Skip to content

Commit e906abe

Browse files
committed
refactor: split into multiple files
1 parent c2a0140 commit e906abe

File tree

3 files changed

+427
-454
lines changed

3 files changed

+427
-454
lines changed
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import {
2+
type SourceFile,
3+
StructureKind,
4+
SyntaxKind,
5+
VariableDeclarationKind,
6+
} from "ts-morph"
7+
import type {IROperation} from "../../../core/openapi-types-normalized"
8+
import {type HttpMethod, isDefined, isHttpMethod} from "../../../core/utils"
9+
import {CompilationUnit, type ICompilable} from "../../common/compilation-units"
10+
import type {ImportBuilder} from "../../common/import-builder"
11+
import {requestBodyAsParameter} from "../../common/typescript-common"
12+
13+
export class TypescriptNextjsAppRouterBuilder implements ICompilable {
14+
constructor(
15+
public readonly filename: string,
16+
private readonly imports: ImportBuilder,
17+
private readonly companionFilename: string,
18+
private readonly sourceFile: SourceFile,
19+
) {}
20+
21+
private readonly httpMethodsUsed = new Set<HttpMethod>()
22+
23+
add(operation: IROperation): void {
24+
const sourceFile = this.sourceFile
25+
26+
const hasPathParam =
27+
operation.parameters.filter((it) => it.in === "path").length > 0
28+
const hasQueryParam =
29+
operation.parameters.filter((it) => it.in === "query").length > 0
30+
const hasBodyParam = Boolean(
31+
requestBodyAsParameter(operation).requestBodyParameter,
32+
)
33+
34+
const wrappingMethod = `_${operation.method.toUpperCase()}`
35+
36+
this.httpMethodsUsed.add(operation.method)
37+
38+
// Get the existing function, or create a new default one
39+
const variableDeclaration =
40+
sourceFile
41+
.getVariableDeclaration(operation.method.toUpperCase())
42+
?.getVariableStatement() ||
43+
sourceFile.addVariableStatement({
44+
isExported: true,
45+
declarationKind: VariableDeclarationKind.Const,
46+
declarations: [
47+
{
48+
name: operation.method.toUpperCase(),
49+
kind: StructureKind.VariableDeclaration,
50+
initializer: `${wrappingMethod}(async (input, respond, context) => {
51+
// TODO: implementation
52+
return respond.withStatus(501).body({message: "not implemented"} as any)
53+
})`,
54+
},
55+
],
56+
})
57+
58+
// Replace the params based on what inputs we have
59+
// biome-ignore lint/style/noNonNullAssertion: <explanation>
60+
const declarations = variableDeclaration.getDeclarations()[0]!
61+
// biome-ignore lint/style/noNonNullAssertion: <explanation>
62+
const innerFunction = declarations
63+
.getInitializerIfKindOrThrow(SyntaxKind.CallExpression)
64+
.getArguments()[0]!
65+
.asKind(SyntaxKind.ArrowFunction)!
66+
67+
// biome-ignore lint/complexity/noForEach: <explanation>
68+
innerFunction?.getParameters().forEach((parameter) => {
69+
parameter.remove()
70+
})
71+
72+
innerFunction?.addParameter({
73+
name: `{${[
74+
hasPathParam ? "params" : undefined,
75+
hasQueryParam ? "query" : undefined,
76+
hasBodyParam ? "body" : undefined,
77+
]
78+
.filter(isDefined)
79+
.join(",")}}`,
80+
})
81+
82+
innerFunction?.addParameter({name: "respond"})
83+
innerFunction?.addParameter({name: "context"})
84+
}
85+
86+
toString(): string {
87+
return this.sourceFile.getFullText()
88+
}
89+
90+
toCompilationUnit(): CompilationUnit {
91+
// Reconcile imports - attempt to find an existing one and replace it with correct one
92+
const imports = this.sourceFile.getImportDeclarations()
93+
const from = this.imports.normalizeFrom(
94+
`./${this.companionFilename}`,
95+
`./${this.filename}`,
96+
)
97+
// biome-ignore lint/complexity/noForEach: <explanation>
98+
imports
99+
.filter((it) => it.getModuleSpecifierValue().includes(from))
100+
.forEach((it) => it.remove())
101+
102+
this.sourceFile.addImportDeclaration({
103+
namedImports: Array.from(this.httpMethodsUsed).map((it) => `_${it}`),
104+
moduleSpecifier: from,
105+
})
106+
107+
// Remove any methods that were removed from the spec
108+
// biome-ignore lint/complexity/noForEach: <explanation>
109+
this.sourceFile
110+
.getVariableDeclarations()
111+
.filter((it) => {
112+
const name = it.getName()
113+
return isHttpMethod(name) && !this.httpMethodsUsed.has(name)
114+
})
115+
.forEach((it) => it.remove())
116+
117+
return new CompilationUnit(
118+
this.filename,
119+
this.imports,
120+
this.toString(),
121+
false,
122+
)
123+
}
124+
}

0 commit comments

Comments
 (0)