UNPKG

@nestia/sdk

Version:

Nestia SDK and Swagger generator

363 lines (353 loc) 12.9 kB
import ts from "typescript"; import { ExpressionFactory } from "typia/lib/factories/ExpressionFactory"; import { IdentifierFactory } from "typia/lib/factories/IdentifierFactory"; import { TypeFactory } from "typia/lib/factories/TypeFactory"; import { ITypedWebSocketRoute } from "../../structures/ITypedWebSocketRoute"; import { ITypedWebSocketRouteParameter } from "../../structures/ITypedWebSocketRouteParameter"; import { FilePrinter } from "./FilePrinter"; import { ImportDictionary } from "./ImportDictionary"; import { SdkAliasCollection } from "./SdkAliasCollection"; export namespace SdkWebSocketNamespaceProgrammer { export const write = (importer: ImportDictionary) => (route: ITypedWebSocketRoute): ts.ModuleDeclaration => ts.factory.createModuleDeclaration( [ts.factory.createToken(ts.SyntaxKind.ExportKeyword)], ts.factory.createIdentifier(route.name), ts.factory.createModuleBlock([ ...writeTypes(importer)(route), FilePrinter.enter(), writePath(route), ]), ts.NodeFlags.Namespace, ); const writeTypes = (importer: ImportDictionary) => (route: ITypedWebSocketRoute): ts.TypeAliasDeclaration[] => { const output: ts.TypeAliasDeclaration[] = []; const declare = (name: string, type: ts.TypeNode) => output.push( ts.factory.createTypeAliasDeclaration( [ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)], name, undefined, type, ), ); declare( "Output", ts.factory.createTypeLiteralNode([ ts.factory.createPropertySignature( undefined, "connector", undefined, ts.factory.createTypeReferenceNode( importer.external({ type: false, library: "tgrid", instance: "WebSocketConnector", }), [ ts.factory.createTypeReferenceNode("Header"), ts.factory.createTypeReferenceNode("Provider"), ts.factory.createTypeReferenceNode("Listener"), ], ), ), ts.factory.createPropertySignature( undefined, "driver", undefined, ts.factory.createTypeReferenceNode( importer.external({ type: true, library: "tgrid", instance: "Driver", }), [ts.factory.createTypeReferenceNode("Listener")], ), ), ]), ); const acceptor: ITypedWebSocketRouteParameter.IAcceptor = route.parameters.find((x) => x.category === "acceptor")!; const query: ITypedWebSocketRouteParameter.IQuery | undefined = route.parameters.find((x) => x.category === "query"); const driver: ITypedWebSocketRouteParameter.IDriver | undefined = route.parameters.find((x) => x.category === "driver"); declare( "Header", SdkAliasCollection.name({ type: (route.parameters.find((x) => x.category === "header")?.type ?? acceptor.type.typeArguments?.[0])!, }), ); declare( "Provider", SdkAliasCollection.name({ type: driver?.type.typeArguments?.[0] ?? acceptor.type.typeArguments?.[2]!, }), ); declare( "Listener", SdkAliasCollection.name({ type: acceptor.type.typeArguments?.[1]!, }), ); if (query) declare("Query", SdkAliasCollection.name(query)); return output; }; const writePath = (route: ITypedWebSocketRoute): ts.VariableStatement => { const pathParams: ITypedWebSocketRouteParameter.IParam[] = route.parameters.filter( (p) => p.category === "param", ) as ITypedWebSocketRouteParameter.IParam[]; const query: ITypedWebSocketRouteParameter.IQuery | undefined = route.parameters.find((p) => p.category === "query"); const total: Array< | ITypedWebSocketRouteParameter.IParam | ITypedWebSocketRouteParameter.IQuery > = [...pathParams, ...(query ? [query] : [])]; const out = (body: ts.ConciseBody) => constant("path")( ts.factory.createArrowFunction( [], [], total.map((p) => IdentifierFactory.parameter( p.name, p === query ? ts.factory.createTypeReferenceNode(`${route.name}.Query`) : SdkAliasCollection.name(p), ), ), undefined, undefined, body, ), ); if (total.length === 0) return out(ts.factory.createStringLiteral(route.path)); const template = () => { const split: string[] = route.path.split(":"); if (split.length === 1) return ts.factory.createStringLiteral(route.path); return ts.factory.createTemplateExpression( ts.factory.createTemplateHead(split[0]), split.slice(1).map((s, i, arr) => { const name: string = s.split("/")[0]; return ts.factory.createTemplateSpan( ts.factory.createCallExpression( ts.factory.createIdentifier("encodeURIComponent"), undefined, [ ts.factory.createBinaryExpression( ts.factory.createCallChain( ts.factory.createPropertyAccessChain( ts.factory.createIdentifier( pathParams.find((p) => p.field === name)!.name, ), ts.factory.createToken(ts.SyntaxKind.QuestionDotToken), "toString", ), undefined, undefined, [], ), ts.factory.createToken(ts.SyntaxKind.QuestionQuestionToken), ts.factory.createStringLiteral("null"), ), ], ), (i !== arr.length - 1 ? ts.factory.createTemplateMiddle : ts.factory.createTemplateTail)(s.substring(name.length)), ); }), ); }; if (query === undefined) return out(template()); const block = (expr: ts.Expression) => { const computeName = (str: string): string => total.find((p) => p.name === str) !== undefined ? computeName("_" + str) : str; const variables: string = computeName("variables"); return ts.factory.createBlock( [ local(variables)("URLSearchParams")( ts.factory.createNewExpression( ts.factory.createIdentifier("URLSearchParams"), [], [], ), ), ts.factory.createForOfStatement( undefined, ts.factory.createVariableDeclarationList( [ ts.factory.createVariableDeclaration( ts.factory.createArrayBindingPattern([ ts.factory.createBindingElement( undefined, undefined, ts.factory.createIdentifier("key"), undefined, ), ts.factory.createBindingElement( undefined, undefined, ts.factory.createIdentifier("value"), undefined, ), ]), undefined, undefined, undefined, ), ], ts.NodeFlags.Const, ), ts.factory.createCallExpression( ts.factory.createIdentifier("Object.entries"), undefined, [ts.factory.createAsExpression(expr, TypeFactory.keyword("any"))], ), ts.factory.createIfStatement( ts.factory.createStrictEquality( ts.factory.createIdentifier("undefined"), ts.factory.createIdentifier("value"), ), ts.factory.createContinueStatement(), ts.factory.createIfStatement( ts.factory.createCallExpression( ts.factory.createIdentifier("Array.isArray"), undefined, [ts.factory.createIdentifier("value")], ), ts.factory.createExpressionStatement( ts.factory.createCallExpression( ts.factory.createPropertyAccessExpression( ts.factory.createIdentifier("value"), ts.factory.createIdentifier("forEach"), ), undefined, [ ts.factory.createArrowFunction( undefined, undefined, [IdentifierFactory.parameter("elem")], undefined, undefined, ts.factory.createCallExpression( IdentifierFactory.access( ts.factory.createIdentifier(variables), "append", ), undefined, [ ts.factory.createIdentifier("key"), ts.factory.createCallExpression( ts.factory.createIdentifier("String"), undefined, [ts.factory.createIdentifier("elem")], ), ], ), ), ], ), ), ts.factory.createExpressionStatement( ts.factory.createCallExpression( IdentifierFactory.access( ts.factory.createIdentifier(variables), "set", ), undefined, [ ts.factory.createIdentifier("key"), ts.factory.createCallExpression( ts.factory.createIdentifier("String"), undefined, [ts.factory.createIdentifier("value")], ), ], ), ), ), ), ), local("location")("string")(template()), ts.factory.createReturnStatement( ts.factory.createConditionalExpression( ts.factory.createStrictEquality( ExpressionFactory.number(0), IdentifierFactory.access( ts.factory.createIdentifier(variables), "size", ), ), undefined, ts.factory.createIdentifier("location"), undefined, ts.factory.createTemplateExpression( ts.factory.createTemplateHead(""), [ ts.factory.createTemplateSpan( ts.factory.createIdentifier("location"), ts.factory.createTemplateMiddle("?"), ), ts.factory.createTemplateSpan( ts.factory.createCallExpression( IdentifierFactory.access( ts.factory.createIdentifier(variables), "toString", ), undefined, undefined, ), ts.factory.createTemplateTail(""), ), ], ), ), ), ], true, ); }; return out(block(ts.factory.createIdentifier(query.name))); }; } const local = (name: string) => (type: string) => (expression: ts.Expression) => ts.factory.createVariableStatement( [], ts.factory.createVariableDeclarationList( [ ts.factory.createVariableDeclaration( name, undefined, ts.factory.createTypeReferenceNode(type), expression, ), ], ts.NodeFlags.Const, ), ); const constant = (name: string) => (expression: ts.Expression) => ts.factory.createVariableStatement( [ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)], ts.factory.createVariableDeclarationList( [ ts.factory.createVariableDeclaration( name, undefined, undefined, expression, ), ], ts.NodeFlags.Const, ), );