diff --git a/packages/ast/src/state/index.ts b/packages/ast/src/state/index.ts index 0dd2cb576d..c5ba20e448 100644 --- a/packages/ast/src/state/index.ts +++ b/packages/ast/src/state/index.ts @@ -1 +1,2 @@ -export * from './react-query'; \ No newline at end of file +export * from './react-query'; +export * from './mobx'; \ No newline at end of file diff --git a/packages/ast/src/state/mobx/__snapshots__/mobx.scoped.test.ts.snap b/packages/ast/src/state/mobx/__snapshots__/mobx.scoped.test.ts.snap new file mode 100644 index 0000000000..01ae7d22a8 --- /dev/null +++ b/packages/ast/src/state/mobx/__snapshots__/mobx.scoped.test.ts.snap @@ -0,0 +1,28 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`builds stores. 1`] = ` +"import * as _ProtoCosmosBankV1beta1A from "./proto/cosmos/bank/v1beta1/a.lcd"; +import * as _ProtoCosmosBankV1beta1B from "./proto/cosmos/bank/v1beta1/b.lcd"; +import * as _ProtoCosmosBankV1beta1C from "./proto/cosmos/bank/v1beta1/c.lcd"; +export const createRpcStores = ({ + rpc +}: { + rpc: ProtobufRpcClient | undefined; +}) => { + return { + cosmos: { + bank: { + v1beta1: _ProtoCosmosBankV1beta1A.createRpcStores(rpc) + }, + gov: { + v1beta1: _ProtoCosmosBankV1beta1B.createRpcStores(rpc) + } + }, + osmosis: { + gamm: { + v1beta1: _ProtoCosmosBankV1beta1C.createRpcStores(rpc) + } + } + }; +};" +`; diff --git a/packages/ast/src/state/mobx/index.ts b/packages/ast/src/state/mobx/index.ts new file mode 100644 index 0000000000..8004f21a10 --- /dev/null +++ b/packages/ast/src/state/mobx/index.ts @@ -0,0 +1 @@ +export * from './mobx'; \ No newline at end of file diff --git a/packages/ast/src/state/mobx/mobx.scoped.test.ts b/packages/ast/src/state/mobx/mobx.scoped.test.ts new file mode 100644 index 0000000000..fe5e224a2d --- /dev/null +++ b/packages/ast/src/state/mobx/mobx.scoped.test.ts @@ -0,0 +1,33 @@ +import { + expectCode, + getGenericParseContext, + getTestProtoStore +} from '../../../test-utils'; +import * as t from '@babel/types'; +import { build } from './scoped-bundle'; + +const store = getTestProtoStore(); +store.traverseAll(); + +it('builds stores.', async () => { + const context = getGenericParseContext(); + expectCode( + t.program( + build(context, { + cosmos: { + bank: { + v1beta1: './proto/cosmos/bank/v1beta1/a.lcd' + }, + gov: { + v1beta1: './proto/cosmos/bank/v1beta1/b.lcd' + } + }, + osmosis: { + gamm: { + v1beta1: './proto/cosmos/bank/v1beta1/c.lcd' + } + } + }) as t.Statement[] + ) + ); +}); diff --git a/packages/ast/src/state/mobx/mobx.ts b/packages/ast/src/state/mobx/mobx.ts new file mode 100644 index 0000000000..2b142ff119 --- /dev/null +++ b/packages/ast/src/state/mobx/mobx.ts @@ -0,0 +1,23 @@ +import * as t from '@babel/types'; +import { ProtoService, ProtoServiceMethod } from '@osmonauts/types'; +import { getNestedProto, isRefIncluded } from '@osmonauts/proto-parser'; +import { GenericParseContext } from '../../encoding'; +import { objectPattern } from '../../utils'; +import { variableSlug } from '@osmonauts/utils'; + +/** + * Entry for building stores. + */ +export const build = ( + context: GenericParseContext, + name: string, + svc: ProtoServiceMethod +) => { + const isIncluding = + context.pluginValue('mobx.enabled') && + isRefIncluded(context.ref, context.pluginValue('mobx.include')); + + if (isIncluding) { + + } +}; diff --git a/packages/ast/src/state/mobx/scoped-bundle.ts b/packages/ast/src/state/mobx/scoped-bundle.ts new file mode 100644 index 0000000000..0d2ae28779 --- /dev/null +++ b/packages/ast/src/state/mobx/scoped-bundle.ts @@ -0,0 +1,14 @@ +import { GenericParseContext } from '../../encoding'; +import { buildExportCreators } from '../../utils'; + +const CREATOR_NAME = 'createRpcStores'; + +export const build = (context: GenericParseContext, obj: object) => { + return buildExportCreators( + context, + obj, + CREATOR_NAME, + ['ProtobufRpcClient'], + CREATOR_NAME + ); +}; diff --git a/packages/ast/src/state/react-query/scoped-bundle.ts b/packages/ast/src/state/react-query/scoped-bundle.ts index 6751bd3160..cf7cc07b01 100644 --- a/packages/ast/src/state/react-query/scoped-bundle.ts +++ b/packages/ast/src/state/react-query/scoped-bundle.ts @@ -2,49 +2,30 @@ import * as t from '@babel/types'; import { GenericParseContext } from '../../encoding'; import { objectPattern } from '../../utils'; import { variableSlug } from '@osmonauts/utils'; +import { buildExportCreators } from '../../utils'; export const rpcHookFuncArguments = (): t.ObjectPattern[] => { - return [ - objectPattern( - [ - t.objectProperty( - t.identifier('rpc'), - t.identifier('rpc'), - false, - true - ) - ], - t.tsTypeAnnotation( - t.tsTypeLiteral( - [ - t.tsPropertySignature( - t.identifier('rpc'), - t.tsTypeAnnotation( - t.tsTypeReference( - t.identifier('Rpc') - ) - ) - ) - ] - ) - ) - ) - ]; + return [ + objectPattern( + [t.objectProperty(t.identifier('rpc'), t.identifier('rpc'), false, true)], + t.tsTypeAnnotation( + t.tsTypeLiteral([ + t.tsPropertySignature( + t.identifier('rpc'), + t.tsTypeAnnotation(t.tsTypeReference(t.identifier('Rpc'))) + ) + ]) + ) + ) + ]; }; export const rpcHookClassArguments = (): t.ObjectExpression[] => { - return [ - t.objectExpression( - [ - t.objectProperty( - t.identifier('rpc'), - t.identifier('rpc'), - false, - true - ) - ] - ) - ]; + return [ + t.objectExpression([ + t.objectProperty(t.identifier('rpc'), t.identifier('rpc'), false, true) + ]) + ]; }; /** @@ -57,47 +38,37 @@ export const rpcHookClassArguments = (): t.ObjectExpression[] => { * @returns {ParseResult} created AST */ export const rpcHookNewTmRequire = ( - imports: HookImport[], - path: string, - methodName: string + imports: HookImport[], + path: string, + methodName: string ) => { + imports.push({ + as: variableSlug(path), + path + }); + + return t.callExpression( + t.memberExpression( + t.identifier(variableSlug(path)), + t.identifier(methodName) + ), + [t.identifier('rpc')] + ); +}; - imports.push({ - as: variableSlug(path), - path - }); - - return t.callExpression( - t.memberExpression( - t.identifier(variableSlug(path)), - t.identifier(methodName) - ), - [ - t.identifier('rpc') - ] - ) - -} +export const rpcHookRecursiveObjectProps = (names: string[], leaf?: any) => { + const [name, ...rest] = names; -export const rpcHookRecursiveObjectProps = ( - names: string[], - leaf?: any -) => { - const [name, ...rest] = names; + let baseComponent; + if (names.length === 1) { + baseComponent = leaf ? leaf : t.identifier(name); + } else { + baseComponent = rpcHookRecursiveObjectProps(rest, leaf); + } - let baseComponent; - if (names.length === 1) { - baseComponent = leaf ? leaf : t.identifier(name) - } else { - baseComponent = rpcHookRecursiveObjectProps(rest, leaf) - } - - return t.objectExpression([ - t.objectProperty( - t.identifier(name), - baseComponent - ) - ]) + return t.objectExpression([ + t.objectProperty(t.identifier(name), baseComponent) + ]); }; /** @@ -110,30 +81,31 @@ export const rpcHookRecursiveObjectProps = ( * @returns {ParseResult} created AST */ export const rpcHookTmNestedImportObject = ( - imports: HookImport[], - obj: object, - methodName: string + imports: HookImport[], + obj: object, + methodName: string ) => { - - //if obj is a path, end recursion and get the mapping. - if (typeof obj === 'string') { - return rpcHookNewTmRequire(imports, obj, methodName); - } - - const keys = Object.keys(obj); - - // get hooks for keys of the obj. - return t.objectExpression(keys.map(name => { - return t.objectProperty( - t.identifier(name), - rpcHookTmNestedImportObject(imports, obj[name], methodName) - ) - })) + //if obj is a path, end recursion and get the mapping. + if (typeof obj === 'string') { + return rpcHookNewTmRequire(imports, obj, methodName); + } + + const keys = Object.keys(obj); + + // get hooks for keys of the obj. + return t.objectExpression( + keys.map((name) => { + return t.objectProperty( + t.identifier(name), + rpcHookTmNestedImportObject(imports, obj[name], methodName) + ); + }) + ); }; interface HookImport { - as: string; - path: string; + as: string; + path: string; } /** @@ -147,86 +119,9 @@ interface HookImport { * @returns {ParseResult} created AST */ export const createScopedRpcHookFactory = ( - context: GenericParseContext, - obj: object, - identifier: string + context: GenericParseContext, + obj: object, + identifier: string ) => { - - // add imports - context.addUtil('ProtobufRpcClient'); - - const hookImports: HookImport[] = []; - - const ast = t.exportNamedDeclaration( - t.variableDeclaration( - 'const', - [ - t.variableDeclarator( - // createRPCQueryHooks - t.identifier(identifier), - t.arrowFunctionExpression( - [ - objectPattern([ - t.objectProperty( - t.identifier('rpc'), - t.identifier('rpc'), - false, - true - ) - ], t.tsTypeAnnotation( - t.tsTypeLiteral([ - t.tsPropertySignature( - t.identifier('rpc'), - t.tsTypeAnnotation( - t.tsUnionType([ - t.tsTypeReference( - t.identifier('ProtobufRpcClient') - ), - t.tsUndefinedKeyword() - ]) - ) - ) - ]) - )) - ], - t.blockStatement([ - - t.returnStatement( - rpcHookTmNestedImportObject( - hookImports, - obj, - 'createRpcQueryHooks' - ) - ) - - ]), - false - ) - ) - ] - ) - ); - - // generate imports for packages. - const imports = hookImports.map(hookport => { - return { - "type": "ImportDeclaration", - "importKind": "value", - "specifiers": [ - { - "type": "ImportNamespaceSpecifier", - "local": { - "type": "Identifier", - "name": hookport.as - } - } - ], - "source": { - "type": "StringLiteral", - "value": hookport.path - } - }; - }); - - return [...imports, ast]; + return buildExportCreators(context, obj, identifier, ['ProtobufRpcClient']); }; diff --git a/packages/ast/src/utils/index.ts b/packages/ast/src/utils/index.ts index 5ec079e6e2..6ab63964ce 100644 --- a/packages/ast/src/utils/index.ts +++ b/packages/ast/src/utils/index.ts @@ -1,2 +1,3 @@ export * from './babel'; -export * from './utils'; \ No newline at end of file +export * from './utils'; +export * from './scoped-bundle-builder'; diff --git a/packages/ast/src/utils/scoped-bundle-builder.ts b/packages/ast/src/utils/scoped-bundle-builder.ts new file mode 100644 index 0000000000..00d6d3d049 --- /dev/null +++ b/packages/ast/src/utils/scoped-bundle-builder.ts @@ -0,0 +1,159 @@ +import * as t from '@babel/types'; +import { GenericParseContext } from '../encoding'; +import { objectPattern } from '.'; +import { variableSlug } from '@osmonauts/utils'; + +const DEFAULT_RPC_PARAM_NAME = 'rpc'; + +/** + * Create an AST for a certain key and method. + * eg: __fixtures__/output1/hooks.ts + * v1beta2: _AkashAuditV1beta2Queryrpc.createRpcQueryHooks(rpc) + * @param {Object=} imports - imports array reference for generating imports. + * @param {Object=} path - filename of a package. + * @param {string} methodName - hook method name of packages + * @returns {ParseResult} created AST + */ +export const buildSingleCreator = ( + imports: HookImport[], + path: string, + methodName: string +) => { + imports.push({ + as: variableSlug(path), + path + }); + + return t.callExpression( + t.memberExpression( + t.identifier(variableSlug(path)), + t.identifier(methodName) + ), + [t.identifier(DEFAULT_RPC_PARAM_NAME)] + ); +}; + +/** + * Create an ASTs for method creators of packages recursively, and get imports of packages. + * eg: __fixtures__/output1/hooks.ts + * export const createRpcQueryHooks = ... + * @param {Object=} imports - imports array reference for generating imports. + * @param {Object=} obj - mapping of packages and rpc query filenames + * @param {string} methodName - hook method name of packages + * @returns {ParseResult} created AST + */ +export const buildNestedCreator = ( + imports: HookImport[], + obj: object, + methodName: string +) => { + //if obj is a path, end recursion and get the mapping. + if (typeof obj === 'string') { + return buildSingleCreator(imports, obj, methodName); + } + + const keys = Object.keys(obj); + + // get hooks for keys of the obj. + return t.objectExpression( + keys.map((name) => { + return t.objectProperty( + t.identifier(name), + buildNestedCreator(imports, obj[name], methodName) + ); + }) + ); +}; + +interface HookImport { + as: string; + path: string; +} + +/** + * Create an ASTs for export creators. + * Generating files like: + * __fixtures__/output1/hooks.ts + * @param {Object=} context - context of generating the file + * @param {Object=} obj - mapping of packages and rpc query filenames + * @param {string} identifier - name of function creating hooks. eg: createRpcQueryHooks + * @param {string[]} utils - name of imported utils. + * @returns {ParseResult} created AST + */ +export const buildExportCreators = ( + context: GenericParseContext, + obj: object, + identifier: string, + utils: string[], + methodName: string = 'createRpcQueryHooks' +) => { + // add imports + utils.forEach((util) => { + context.addUtil(util); + }); + + const hookImports: HookImport[] = []; + + const ast = t.exportNamedDeclaration( + t.variableDeclaration('const', [ + t.variableDeclarator( + // eg: createRPCQueryHooks + t.identifier(identifier), + t.arrowFunctionExpression( + [ + objectPattern( + [ + t.objectProperty( + t.identifier(DEFAULT_RPC_PARAM_NAME), + t.identifier(DEFAULT_RPC_PARAM_NAME), + false, + true + ) + ], + t.tsTypeAnnotation( + t.tsTypeLiteral([ + t.tsPropertySignature( + t.identifier(DEFAULT_RPC_PARAM_NAME), + t.tsTypeAnnotation( + t.tsUnionType([ + t.tsTypeReference(t.identifier('ProtobufRpcClient')), + t.tsUndefinedKeyword() + ]) + ) + ) + ]) + ) + ) + ], + t.blockStatement([ + t.returnStatement(buildNestedCreator(hookImports, obj, methodName)) + ]), + false + ) + ) + ]) + ); + + // generate imports for packages. + const imports = hookImports.map((hookport) => { + return { + type: 'ImportDeclaration', + importKind: 'value', + specifiers: [ + { + type: 'ImportNamespaceSpecifier', + local: { + type: 'Identifier', + name: hookport.as + } + } + ], + source: { + type: 'StringLiteral', + value: hookport.path + } + }; + }); + + return [...imports, ast]; +};