Skip to content

Commit

Permalink
vue query
Browse files Browse the repository at this point in the history
  • Loading branch information
hu-ke committed Dec 8, 2024
1 parent e0d8431 commit 0ea835e
Show file tree
Hide file tree
Showing 8 changed files with 182 additions and 18 deletions.
43 changes: 43 additions & 0 deletions packages/ast/src/encoding/proto/interface/proto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,49 @@ export const createProtoType = (
return declaration;
};

export const cloneAndWrapFieldsWithComputedRef = (
originalDeclaration: t.ExportNamedDeclaration
): t.ExportNamedDeclaration => {
// Extract the interface declaration
const interfaceDeclaration = originalDeclaration.declaration as t.TSInterfaceDeclaration;
const originalFields = (interfaceDeclaration.body as t.TSInterfaceBody).body;

// Clone and modify each field
const newFields = originalFields.map((field) => {
if (t.isTSPropertySignature(field) && field.typeAnnotation) {
// Get the original field type
const originalType = field.typeAnnotation.typeAnnotation;

// Create the new type: ComputedRef<OriginalType>
const computedRefType = t.tsTypeReference(
t.identifier('ComputedRef'),
t.tsTypeParameterInstantiation([originalType])
);

// Clone the field and replace its type
return tsPropertySignature(
field.key,
t.tsTypeAnnotation(computedRefType),
field.optional
);
}
// Keep the field unchanged if it's not a TSPropertySignature
return field;
});

const newInterfaceId = t.identifier(`Reactive${interfaceDeclaration.id.name}`);
// Create a new interface declaration
const newInterfaceDeclaration = t.tsInterfaceDeclaration(
newInterfaceId,
interfaceDeclaration.typeParameters,
interfaceDeclaration.extends,
t.tsInterfaceBody(newFields)
);

// Wrap it as a new ExportNamedDeclaration
return t.exportNamedDeclaration(newInterfaceDeclaration);
}

export const createProtoTypeType = (
context: ProtoParseContext,
name: string,
Expand Down
85 changes: 79 additions & 6 deletions packages/ast/src/state/vue-query/vue-query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const rpcHookMethod = (
}

// add import
context.addUtil('useQuery');
context.addUtil('useVueQuery');

return t.variableDeclaration('const', [
t.variableDeclarator(
Expand Down Expand Up @@ -205,7 +205,7 @@ const rpcHookMethod = (

}

export const createVueRpcQueryHooks = (
export const createRpcVueQueryHooks = (
context: GenericParseContext,
service: ProtoService
) => {
Expand All @@ -227,8 +227,6 @@ export const createVueRpcQueryHooks = (
)
});

console.log('methods>>', methods.length)

const methodNames = Object.keys(service.methods ?? {})
.map(key => {
const name = camelRpcMethods ? camel(key) : key;
Expand Down Expand Up @@ -292,20 +290,95 @@ export const createVueRpcQueryHooks = (
);
};

const rpcVueHookMethodInterface = (
context: GenericParseContext,
name: string,
svc: ProtoServiceMethod
) => {
const requestType = svc.requestType;
const responseType = svc.responseType;
const fieldNames = Object.keys(svc.fields ?? {})
const hasParams = fieldNames.length > 0;

let optional = false;
// if no params, then let's default to empty object for cleaner API
if (!hasParams) {
optional = true;
} else if (hasParams && fieldNames.length === 1 && fieldNames.includes('pagination')) {
// if only argument "required" is pagination
// also default to empty
optional = true;
}

// import VueQueryParams in the generated file.
context.addUtil('VueQueryParams');

return t.exportNamedDeclaration(t.tsInterfaceDeclaration(
t.identifier(makeUseHookTypeName(name)),
t.tsTypeParameterDeclaration([
t.tsTypeParameter(null, null, 'TData')
]),
[
t.tsExpressionWithTypeArguments(
t.identifier('VueQueryParams'),
t.tsTypeParameterInstantiation([
t.tsTypeReference(t.identifier(responseType)),
t.tsTypeReference(t.identifier('TData'))
])
)
],
t.tsInterfaceBody([
tsPropertySignature(
t.identifier('request'),
t.tsTypeAnnotation(
t.tsTypeReference(
t.identifier(requestType)
)
),
optional
)
])
));
}

/**
* Create ASTs for all the methods of a proto service.
* @param {Object=} context - context of generating the file
* @param {Object=} service - service details
* @returns {ParseResult} created AST
*/
export const createRpcVueQueryHookInterfaces = (
context: GenericParseContext,
service: ProtoService
) => {


const camelRpcMethods = context.pluginValue('rpcClients.camelCase');

const methods = Object.keys(service.methods ?? {})
.map(key => {
const name = camelRpcMethods ? camel(key) : key;
const method = service.methods[key];
return {
name,
method
};
});

return methods.map(method => rpcVueHookMethodInterface(context, method.name, method.method));
};

function astToCodeWithBabel(ast: any): string {
const { code } = generate(ast, { retainLines: true });
console.log('code!~', code)
return code;
}

export const createVueRpcQueryHookClientMap = (
export const createRpcVueQueryHookClientMap = (
context: GenericParseContext,
service: ProtoService
) => {
const name = service.name + 'ClientImpl';
console.log('hahah.')
// const ast = createClientMap(name)
// astToCodeWithBabel(ast[0])

Expand Down
1 change: 1 addition & 0 deletions packages/ast/types/encoding/proto/interface/proto.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { ProtoType } from '@cosmology/types';
import { ProtoParseContext } from '../../context';
import { TelescopeBaseTypes } from '../../types';
export declare const createProtoType: (context: ProtoParseContext, name: string, proto: ProtoType, type?: TelescopeBaseTypes) => t.ExportNamedDeclaration;
export declare const cloneAndWrapFieldsWithComputedRef: (originalDeclaration: t.ExportNamedDeclaration) => t.ExportNamedDeclaration;
export declare const createProtoTypeType: (context: ProtoParseContext, name: string, proto: ProtoType) => t.ExportNamedDeclaration;
export declare const createProtoInterfaceEncodedType: (context: ProtoParseContext, name: string, proto: ProtoType) => t.ExportNamedDeclaration;
export declare const createCreateProtoType: (context: ProtoParseContext, name: string, proto: ProtoType) => t.FunctionDeclaration;
11 changes: 9 additions & 2 deletions packages/ast/types/state/vue-query/vue-query.d.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
import * as t from '@babel/types';
import { ProtoService } from '@cosmology/types';
import { GenericParseContext } from '../../encoding';
export declare const createVueRpcQueryHooks: (context: GenericParseContext, service: ProtoService) => t.ExportNamedDeclaration;
export declare const createVueRpcQueryHookClientMap: (context: GenericParseContext, service: ProtoService) => {
export declare const createRpcVueQueryHooks: (context: GenericParseContext, service: ProtoService) => t.ExportNamedDeclaration;
/**
* Create ASTs for all the methods of a proto service.
* @param {Object=} context - context of generating the file
* @param {Object=} service - service details
* @returns {ParseResult} created AST
*/
export declare const createRpcVueQueryHookInterfaces: (context: GenericParseContext, service: ProtoService) => t.ExportNamedDeclaration[];
export declare const createRpcVueQueryHookClientMap: (context: GenericParseContext, service: ProtoService) => {
type: string;
declarations: {
type: string;
Expand Down
13 changes: 12 additions & 1 deletion packages/telescope/src/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
createProtoEnumToJSON,
createProtoEnumFromJSON,
createProtoType,
cloneAndWrapFieldsWithComputedRef,
createProtoInterfaceEncodedType,
createProtoTypeType,
createSDKType,
Expand Down Expand Up @@ -79,7 +80,17 @@ export const buildBaseTypeScriptInterface = (
obj: any
) => {

context.body.push(createProtoType(context.proto, name, obj));
const protoType = createProtoType(context.proto, name, obj)
context.body.push(protoType);

if (context.options.vueQuery?.enabled) {
// create interfaces with fields of ComputedRef
// eg: interface QueryBalanceRequest {
// address: ComputedRef<string>;
// denom: ComputedRef<string>;
// }
context.body.push(cloneAndWrapFieldsWithComputedRef(protoType))
}

if (context.options.aminoEncoding?.enabled && !context.options.aminoEncoding?.useLegacyInlineEncoding || context.options.prototypes?.methods?.fromProto || context.options.prototypes?.methods?.toProto) {
context.body.push(createProtoTypeType(context.proto, name, obj));
Expand Down
26 changes: 17 additions & 9 deletions packages/telescope/src/generators/create-rpc-query-clients.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ import {
createRpcClientClass,
createRpcClientInterface,
createRpcQueryHookInterfaces,
createRpcVueQueryHookInterfaces,
createRpcQueryHookClientMap,
createVueRpcQueryHookClientMap,
createRpcVueQueryHookClientMap,
createRpcQueryHooks,
createVueRpcQueryHooks,
createRpcVueQueryHooks,
// grpc-gateway:
createGRPCGatewayQueryClass,
createGRPCGatewayWrapperClass,
Expand Down Expand Up @@ -233,21 +234,26 @@ export const plugin = (

if (includeReactQueryHooks) {
[].push.apply(asts, createRpcQueryHookInterfaces(ctx.generic, svc));

}

// enable getQueryService for plugins using it.
if (includeReactQueryHooks || includeMobxHooks) {
// [].push.apply(asts, createRpcQueryHookClientMap(ctx.generic, svc));
[].push.apply(asts, createRpcQueryHookClientMap(ctx.generic, svc));
}

// see if current file has been vueQuery enabled and included
const includeVueQueryHooks = c.proto.pluginValue('vueQuery.enabled') && isRefIncluded(
c.ref,
c.proto.pluginValue('vueQuery.include')
)
// enable vue useQueryService for plugins using it.

if (includeVueQueryHooks) {
[].push.apply(asts, createRpcVueQueryHookInterfaces(ctx.generic, svc));
}

if (includeVueQueryHooks) {
[].push.apply(asts, createVueRpcQueryHookClientMap(ctx.generic, svc));
[].push.apply(asts, createRpcVueQueryHookClientMap(ctx.generic, svc));
}


Expand All @@ -260,15 +266,17 @@ export const plugin = (
// export const createRpcQueryHooks = ...
// TODO use the imports and make separate files
if (includeReactQueryHooks) {
// asts.push(createRpcQueryHooks(ctx.generic, proto[svcKey]));
asts.push(createVueRpcQueryHooks(ctx.generic, proto[svcKey]));

asts.push(createRpcQueryHooks(ctx.generic, proto[svcKey]));

// get all query methods
const patterns = c.proto.pluginValue('reactQuery.instantExport.include.patterns');
bundlerFile.instantExportedMethods = getQueryMethodNames(bundlerFile.package, Object.keys(proto[svcKey].methods ?? {}), patterns).map((key)=> proto[svcKey].methods[key]);
bundlerFile.instantExportedMethods = getQueryMethodNames(bundlerFile.package, Object.keys(proto[svcKey].methods ?? {}), patterns).map((key) => proto[svcKey].methods[key]);

reactQueryBundlerFiles.push(bundlerFile);
}
if (includeVueQueryHooks) {
asts.push(createRpcVueQueryHooks(ctx.generic, proto[svcKey]));
}

// whether mobx plugin is enabled has been dealt with inside createMobxQueryStores
const mobxQueryStoreAst = createMobxQueryStores(
Expand Down
11 changes: 11 additions & 0 deletions packages/telescope/src/generators/create-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,17 @@ export const plugin = (
.concat(importStmts)
;

if (context.proto.pluginValue('vueQuery.enabled')) {
// import { ComputedRef } from 'vue'
const importVueStatement = t.importDeclaration(
[
t.importSpecifier(t.identifier('ComputedRef'), t.identifier('ComputedRef')), // 指定导入的名称
],
t.stringLiteral('vue')
);
prog.push(importVueStatement)
}

// package var
if (context.proto.pluginValue('prototypes.includePackageVar')) {
prog.push(t.exportNamedDeclaration(t.variableDeclaration('const', [
Expand Down
10 changes: 10 additions & 0 deletions packages/telescope/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,20 @@ export const UTILS: { [key: string]: UtilValue } = {
toTimestamp: '__helpers__',
toUtf8: '@cosmjs/encoding',
useQuery: '@tanstack/react-query',
useVueQuery: {
type: 'import',
name: 'useQuery',
path: '@tanstack/vue-query'
},
useRpcEndpoint: '__react-query__',
useRpcClient: '__react-query__',
useTendermintClient: '__react-query__',
ReactQueryParams: '__react-query__',
VueQueryParams: {
type: 'import',
name: 'VueQueryParams',
path: '../../../vue-query'
},
buildUseMutation:'__react-query__',
UseQueryParams:'__react-query__',
buildUseQuery:'__react-query__',
Expand Down

0 comments on commit 0ea835e

Please sign in to comment.