@nestia/sdk
Version:
Nestia SDK and Swagger generator
323 lines (315 loc) • 10.9 kB
text/typescript
import {
type Expression,
type ExpressionStatement,
type Node,
NodeFlags,
type ParameterDeclaration,
type Statement,
SyntaxKind,
type TypeNode,
factory,
} from "@ttsc/factory";
import { ExpressionFactory } from "../../factories/ExpressionFactory";
import { IdentifierFactory } from "../../factories/IdentifierFactory";
import { LiteralFactory } from "../../factories/LiteralFactory";
import { StatementFactory } from "../../factories/StatementFactory";
import { TypeFactory } from "../../factories/TypeFactory";
import { sizeOf } from "../../internal/legacy";
import { INestiaProject } from "../../structures/INestiaProject";
import { ITypedHttpRoute } from "../../structures/ITypedHttpRoute";
import { ImportDictionary } from "./ImportDictionary";
import { SdkAliasCollection } from "./SdkAliasCollection";
import { SdkHttpParameterProgrammer } from "./SdkHttpParameterProgrammer";
import { SdkImportWizard } from "./SdkImportWizard";
export namespace SdkHttpSimulationProgrammer {
export const random =
(project: INestiaProject) =>
(importer: ImportDictionary) =>
(route: ITypedHttpRoute): Node => {
const output: TypeNode = SdkAliasCollection.responseBody(project)(
importer,
)(route) as TypeNode;
return constant("random")(
factory.createArrowFunction(
undefined,
undefined,
[],
project.config.primitive === false || route.success.binary === true
? output
: factory.createTypeReferenceNode(
SdkImportWizard.Resolved(importer),
[output],
),
undefined,
route.success.binary === true
? factory.createNewExpression(
factory.createIdentifier("ReadableStream"),
[SdkAliasCollection.binaryChunk() as TypeNode],
[],
)
: factory.createCallExpression(
IdentifierFactory.access(
factory.createIdentifier(SdkImportWizard.typia(importer)),
"random",
),
[output],
undefined,
),
),
);
};
export const simulate =
(project: INestiaProject) =>
(importer: ImportDictionary) =>
(route: ITypedHttpRoute): Node => {
const output: boolean =
project.config.propagate === true ||
route.success.binary === true ||
sizeOf(route.success.metadata) !== 0;
const caller = () =>
factory.createCallExpression(
factory.createIdentifier("random"),
undefined,
undefined,
);
return constant("simulate")(
factory.createArrowFunction(
undefined,
undefined,
[
IdentifierFactory.parameter(
SdkHttpParameterProgrammer.getSignificant(route, true).length !==
0
? "connection"
: "_connection",
factory.createTypeReferenceNode(
SdkImportWizard.IConnection(importer),
route.headerObject
? [factory.createTypeReferenceNode(`${route.name}.Headers`)]
: [],
),
),
...(SdkHttpParameterProgrammer.getParameterDeclarations({
project,
importer,
route,
body: true,
prefix: false,
}) as ParameterDeclaration[]),
],
factory.createTypeReferenceNode(output ? "Output" : "void"),
undefined,
factory.createBlock(
[
...assert(project)(importer)(route),
factory.createReturnStatement(
project.config.propagate
? factory.createAsExpression(
factory.createObjectLiteralExpression(
[
factory.createPropertyAssignment(
"success",
factory.createTrue(),
),
factory.createPropertyAssignment(
"status",
ExpressionFactory.number(
route.success.status ??
(route.method === "POST" ? 201 : 200),
),
),
factory.createPropertyAssignment(
"headers",
LiteralFactory.write({
"Content-Type": route.success.contentType,
}),
),
factory.createPropertyAssignment("data", caller()),
],
true,
),
factory.createTypeReferenceNode("Output"),
)
: caller(),
),
],
true,
),
),
);
};
const assert =
(project: INestiaProject) =>
(importer: ImportDictionary) =>
(route: ITypedHttpRoute): Statement[] => {
const parameters = SdkHttpParameterProgrammer.getSignificant(route, true);
if (parameters.length === 0) return [];
const typia = SdkImportWizard.typia(importer);
const validator = StatementFactory.constant({
name: "assert",
value: factory.createCallExpression(
IdentifierFactory.access(
factory.createIdentifier(
importer.external({
file: `@nestia/fetcher`,
declaration: false,
type: "element",
name: "NestiaSimulator",
}),
),
"assert",
),
undefined,
[
factory.createObjectLiteralExpression(
[
factory.createPropertyAssignment(
"method",
factory.createIdentifier("METADATA.method"),
),
factory.createPropertyAssignment(
"host",
factory.createIdentifier("connection.host"),
),
factory.createPropertyAssignment(
"path",
factory.createCallExpression(
factory.createIdentifier("path"),
undefined,
SdkHttpParameterProgrammer.getArguments({
project,
route,
body: false,
}) as Expression[],
),
),
factory.createPropertyAssignment(
"contentType",
factory.createIdentifier(
JSON.stringify(route.success.contentType),
),
),
],
true,
),
],
),
});
const individual: ExpressionStatement[] = parameters
.map((p) =>
factory.createCallExpression(
(() => {
const base = IdentifierFactory.access(
factory.createIdentifier("assert"),
p.category,
);
if (p.category !== "param") return base;
return factory.createCallExpression(base, undefined, [
factory.createStringLiteral(p.name),
]);
})(),
undefined,
[
factory.createArrowFunction(
undefined,
undefined,
[],
undefined,
undefined,
factory.createCallExpression(
IdentifierFactory.access(
factory.createIdentifier(typia),
"assert",
),
undefined,
[
project.config.keyword === true
? factory.createIdentifier(`props.${p.name}`)
: factory.createIdentifier(p.name),
],
),
),
],
),
)
.map(factory.createExpressionStatement);
return [
validator,
...(project.config.propagate !== true
? individual
: [tryAndCatch(importer)(individual)]),
];
};
const tryAndCatch =
(importer: ImportDictionary) => (individual: Statement[]) =>
factory.createTryStatement(
factory.createBlock(individual, true),
factory.createCatchClause(
"exp",
factory.createBlock(
[
factory.createIfStatement(
factory.createLogicalNot(
factory.createCallExpression(
IdentifierFactory.access(
factory.createIdentifier(SdkImportWizard.typia(importer)),
"is",
),
[
factory.createTypeReferenceNode(
SdkImportWizard.HttpError(importer),
),
],
[factory.createIdentifier("exp")],
),
),
factory.createThrowStatement(factory.createIdentifier("exp")),
),
factory.createReturnStatement(
factory.createAsExpression(
factory.createObjectLiteralExpression(
[
factory.createPropertyAssignment(
"success",
factory.createFalse(),
),
factory.createPropertyAssignment(
"status",
factory.createIdentifier("exp.status"),
),
factory.createPropertyAssignment(
"headers",
factory.createIdentifier("exp.headers"),
),
factory.createPropertyAssignment(
"data",
factory.createIdentifier("exp.toJSON().message"),
),
],
true,
),
TypeFactory.keyword("any"),
),
),
],
true,
),
),
undefined,
);
}
const constant = (name: string) => (expression: Expression) =>
factory.createVariableStatement(
[factory.createModifier(SyntaxKind.ExportKeyword)],
factory.createVariableDeclarationList(
[
factory.createVariableDeclaration(
factory.createIdentifier(name),
undefined,
undefined,
expression,
),
],
NodeFlags.Const,
),
);