@nestia/sdk
Version:
Nestia SDK and Swagger generator
280 lines (274 loc) • 10.5 kB
text/typescript
import ts from "typescript";
import { IdentifierFactory } from "typia/lib/factories/IdentifierFactory";
import { TypeFactory } from "typia/lib/factories/TypeFactory";
import { INestiaProject } from "../../structures/INestiaProject";
import { ITypedHttpRoute } from "../../structures/ITypedHttpRoute";
import { StringUtil } from "../../utils/StringUtil";
import { ImportDictionary } from "./ImportDictionary";
import { SdkAliasCollection } from "./SdkAliasCollection";
import { SdkHttpParameterProgrammer } from "./SdkHttpParameterProgrammer";
import { SdkImportWizard } from "./SdkImportWizard";
export namespace SdkHttpFunctionProgrammer {
export const write =
(project: INestiaProject) =>
(importer: ImportDictionary) =>
(route: ITypedHttpRoute): ts.FunctionDeclaration => {
return ts.factory.createFunctionDeclaration(
[
ts.factory.createModifier(ts.SyntaxKind.ExportKeyword),
ts.factory.createModifier(ts.SyntaxKind.AsyncKeyword),
],
undefined,
route.name,
undefined,
[
IdentifierFactory.parameter(
"connection",
ts.factory.createTypeReferenceNode(
SdkImportWizard.IConnection(importer),
route.headerObject !== null
? [ts.factory.createTypeReferenceNode(`${route.name}.Headers`)]
: undefined,
),
),
...SdkHttpParameterProgrammer.getParameterDeclarations({
project,
importer,
route,
body: true,
prefix: true,
}),
],
ts.factory.createTypeReferenceNode("Promise", [
project.config.propagate === true ||
route.success.metadata.size() !== 0
? ts.factory.createTypeReferenceNode(`${route.name}.Output`)
: ts.factory.createTypeReferenceNode("void"),
]),
ts.factory.createBlock(writeBody(project)(importer)(route), true),
);
};
const writeBody =
(project: INestiaProject) =>
(importer: ImportDictionary) =>
(route: ITypedHttpRoute): ts.Statement[] => {
const access = (name: string): ts.Expression =>
project.config.keyword === true
? IdentifierFactory.access(ts.factory.createIdentifier("props"), name)
: ts.factory.createIdentifier(name);
const fetch = () =>
ts.factory.createCallExpression(
IdentifierFactory.access(
ts.factory.createIdentifier(
SdkImportWizard.Fetcher(
!!route.body?.encrypted || route.success.encrypted,
)(importer),
),
project.config.propagate ? "propagate" : "fetch",
),
project.config.propagate
? route.method.toLowerCase() === "get" ||
route.method.toLowerCase() === "head"
? [TypeFactory.keyword("any")]
: [TypeFactory.keyword("any"), TypeFactory.keyword("any")]
: undefined,
[
route.body && route.body.contentType !== "multipart/form-data"
? ts.factory.createObjectLiteralExpression(
[
ts.factory.createSpreadAssignment(
ts.factory.createIdentifier("connection"),
),
ts.factory.createPropertyAssignment(
"headers",
ts.factory.createObjectLiteralExpression(
[
ts.factory.createSpreadAssignment(
IdentifierFactory.access(
ts.factory.createIdentifier("connection"),
"headers",
),
),
ts.factory.createPropertyAssignment(
ts.factory.createStringLiteral("Content-Type"),
ts.factory.createStringLiteral(
route.body?.contentType ?? "application/json",
),
),
],
true,
),
),
],
true,
)
: ts.factory.createIdentifier("connection"),
ts.factory.createObjectLiteralExpression(
[
ts.factory.createSpreadAssignment(
IdentifierFactory.access(
ts.factory.createIdentifier(route.name),
"METADATA",
),
),
ts.factory.createPropertyAssignment(
"template",
IdentifierFactory.access(
IdentifierFactory.access(
ts.factory.createIdentifier(route.name),
"METADATA",
),
"path",
),
),
ts.factory.createPropertyAssignment(
"path",
ts.factory.createCallExpression(
IdentifierFactory.access(
ts.factory.createIdentifier(route.name),
"path",
),
undefined,
SdkHttpParameterProgrammer.getArguments({
project,
route,
body: false,
}),
),
),
],
true,
),
...(route.body ? [access(route.body.name)] : []),
...(project.config.json &&
route.body !== null &&
(route.body.contentType === "application/json" ||
route.body.encrypted === true)
? [ts.factory.createIdentifier(`${route.name}.stringify`)]
: []),
],
);
const output = (awaiter: boolean) =>
project.config.simulate
? ts.factory.createConditionalExpression(
ts.factory.createStrictEquality(
ts.factory.createTrue(),
ts.factory.createIdentifier("connection.simulate"),
),
undefined,
ts.factory.createCallExpression(
ts.factory.createIdentifier(`${route.name}.simulate`),
[],
[
ts.factory.createIdentifier("connection"),
...SdkHttpParameterProgrammer.getArguments({
project,
route,
body: true,
}),
],
),
undefined,
awaiter ? ts.factory.createAwaitExpression(fetch()) : fetch(),
)
: awaiter
? ts.factory.createAwaitExpression(fetch())
: fetch();
return [
...(project.config.assert
? SdkHttpParameterProgrammer.getSignificant(route, true).map((p) =>
ts.factory.createExpressionStatement(
ts.factory.createCallExpression(
IdentifierFactory.access(
ts.factory.createIdentifier(
SdkImportWizard.typia(importer),
),
"assert",
),
[
ts.factory.createTypeQueryNode(
ts.factory.createIdentifier(p.name),
),
],
[ts.factory.createIdentifier(p.name)],
),
),
)
: []),
...(route.success.setHeaders.length === 0
? [ts.factory.createReturnStatement(output(false))]
: writeSetHeaders(project)(importer)(route)(output(true))),
];
};
const writeSetHeaders =
(project: INestiaProject) =>
(importer: ImportDictionary) =>
(route: ITypedHttpRoute) =>
(condition: ts.Expression): ts.Statement[] => {
const accessor = (x: string) => (y: string) =>
x[0] === "[" ? `${x}${y}` : `${x}.${y}`;
const output: string = StringUtil.escapeDuplicate([
"connection",
...SdkHttpParameterProgrammer.getSignificant(route, true).map(
(p) => p.name,
),
])("output");
const headers: string = accessor("connection")("headers");
const data: string = project.config.propagate
? accessor(output)("data")
: output;
const assigners: ts.ExpressionStatement[] = [
ts.factory.createBinaryExpression(
ts.factory.createIdentifier(headers),
ts.factory.createToken(ts.SyntaxKind.QuestionQuestionEqualsToken),
ts.factory.createObjectLiteralExpression([]),
),
...route.success.setHeaders.map((tuple) =>
tuple.type === "assigner"
? ts.factory.createCallExpression(
ts.factory.createIdentifier("Object.assign"),
[],
[
ts.factory.createIdentifier(headers),
ts.factory.createIdentifier(accessor(data)(tuple.source)),
],
)
: ts.factory.createBinaryExpression(
ts.factory.createIdentifier(
accessor(headers)(tuple.target ?? tuple.source),
),
ts.factory.createToken(ts.SyntaxKind.EqualsToken),
ts.factory.createIdentifier(accessor(data)(tuple.source)),
),
),
].map(ts.factory.createExpressionStatement);
return [
ts.factory.createVariableStatement(
[],
ts.factory.createVariableDeclarationList(
[
ts.factory.createVariableDeclaration(
output,
undefined,
SdkAliasCollection.response(project)(importer)(route),
condition,
),
],
ts.NodeFlags.Const,
),
),
...(project.config.propagate
? [
ts.factory.createIfStatement(
ts.factory.createIdentifier(accessor(output)("success")),
assigners.length === 1
? assigners[0]
: ts.factory.createBlock(assigners, true),
undefined,
),
]
: assigners),
ts.factory.createReturnStatement(ts.factory.createIdentifier(output)),
];
};
}