Skip to content

Commit 606ec44

Browse files
committed
refactor: migrate code generation to a ts-morph pipeline
1 parent f6fc823 commit 606ec44

30 files changed

+2861
-2066
lines changed

src/common.mts

Lines changed: 6 additions & 195 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,17 @@
11
import type { PathLike } from "node:fs";
22
import { stat } from "node:fs/promises";
33
import path from "node:path";
4-
import type {
5-
ClassDeclaration,
6-
ParameterDeclaration,
7-
SourceFile,
8-
Type,
9-
VariableDeclaration,
4+
import {
5+
ArrowFunction,
6+
type ClassDeclaration,
7+
type ParameterDeclaration,
8+
type SourceFile,
9+
type VariableDeclaration,
1010
} from "ts-morph";
11-
import { ArrowFunction } from "ts-morph";
1211
import ts from "typescript";
1312
import type { LimitedUserConfig } from "./cli.mjs";
1413
import { queriesOutputPath, requestsOutputPath } from "./constants.mjs";
1514

16-
export const TData = ts.factory.createIdentifier("TData");
17-
export const TError = ts.factory.createIdentifier("TError");
18-
export const TContext = ts.factory.createIdentifier("TContext");
19-
20-
export const EqualsOrGreaterThanToken = ts.factory.createToken(
21-
ts.SyntaxKind.EqualsGreaterThanToken,
22-
);
23-
24-
export const QuestionToken = ts.factory.createToken(
25-
ts.SyntaxKind.QuestionToken,
26-
);
27-
28-
export const queryKeyGenericType =
29-
ts.factory.createTypeReferenceNode("TQueryKey");
30-
export const queryKeyConstraint = ts.factory.createTypeReferenceNode("Array", [
31-
ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword),
32-
]);
33-
3415
export const capitalizeFirstLetter = (str: string) => {
3516
return str.charAt(0).toUpperCase() + str.slice(1);
3617
};
@@ -63,7 +44,6 @@ export const getNameFromVariable = (variable: VariableDeclaration) => {
6344
export type FunctionDescription = {
6445
node: SourceFile;
6546
method: VariableDeclaration;
66-
methodBlock: ts.Block;
6747
httpMethodName: string;
6848
jsDoc: string;
6949
isDeprecated: boolean;
@@ -200,172 +180,3 @@ export function buildRequestsOutputPath(outputPath: string) {
200180
export function buildQueriesOutputPath(outputPath: string) {
201181
return path.join(outputPath, queriesOutputPath);
202182
}
203-
204-
export function getQueryKeyFnName(queryKey: string) {
205-
return `${capitalizeFirstLetter(queryKey)}Fn`;
206-
}
207-
208-
/**
209-
* Create QueryKey/MutationKey exports
210-
*/
211-
export function createQueryKeyExport({
212-
methodName,
213-
queryKey,
214-
}: {
215-
methodName: string;
216-
queryKey: string;
217-
}) {
218-
return ts.factory.createVariableStatement(
219-
[ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)],
220-
ts.factory.createVariableDeclarationList(
221-
[
222-
ts.factory.createVariableDeclaration(
223-
ts.factory.createIdentifier(queryKey),
224-
undefined,
225-
undefined,
226-
ts.factory.createStringLiteral(
227-
`${capitalizeFirstLetter(methodName)}`,
228-
),
229-
),
230-
],
231-
ts.NodeFlags.Const,
232-
),
233-
);
234-
}
235-
236-
export function createQueryKeyFnExport(
237-
queryKey: string,
238-
method: VariableDeclaration,
239-
type: "query" | "mutation" = "query",
240-
modelNames: string[] = [],
241-
) {
242-
// Mutation keys don't require clientOptions
243-
const params =
244-
type === "query"
245-
? getRequestParamFromMethod(method, undefined, modelNames)
246-
: null;
247-
248-
// override key is used to allow the user to override the the queryKey values
249-
const overrideKey = ts.factory.createParameterDeclaration(
250-
undefined,
251-
undefined,
252-
ts.factory.createIdentifier(type === "query" ? "queryKey" : "mutationKey"),
253-
QuestionToken,
254-
ts.factory.createTypeReferenceNode("Array<unknown>", []),
255-
);
256-
257-
return ts.factory.createVariableStatement(
258-
[ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)],
259-
ts.factory.createVariableDeclarationList(
260-
[
261-
ts.factory.createVariableDeclaration(
262-
ts.factory.createIdentifier(getQueryKeyFnName(queryKey)),
263-
undefined,
264-
undefined,
265-
ts.factory.createArrowFunction(
266-
undefined,
267-
undefined,
268-
params ? [params, overrideKey] : [overrideKey],
269-
undefined,
270-
EqualsOrGreaterThanToken,
271-
type === "query"
272-
? queryKeyFn(queryKey, method)
273-
: mutationKeyFn(queryKey),
274-
),
275-
),
276-
],
277-
ts.NodeFlags.Const,
278-
),
279-
);
280-
}
281-
282-
function queryKeyFn(
283-
queryKey: string,
284-
method: VariableDeclaration,
285-
): ts.Expression {
286-
return ts.factory.createArrayLiteralExpression(
287-
[
288-
ts.factory.createIdentifier(queryKey),
289-
ts.factory.createSpreadElement(
290-
ts.factory.createParenthesizedExpression(
291-
ts.factory.createBinaryExpression(
292-
ts.factory.createIdentifier("queryKey"),
293-
ts.factory.createToken(ts.SyntaxKind.QuestionQuestionToken),
294-
getVariableArrowFunctionParameters(method)
295-
? // [...clientOptions]
296-
ts.factory.createArrayLiteralExpression([
297-
ts.factory.createIdentifier("clientOptions"),
298-
])
299-
: // []
300-
ts.factory.createArrayLiteralExpression(),
301-
),
302-
),
303-
),
304-
],
305-
false,
306-
);
307-
}
308-
309-
function mutationKeyFn(mutationKey: string): ts.Expression {
310-
return ts.factory.createArrayLiteralExpression(
311-
[
312-
ts.factory.createIdentifier(mutationKey),
313-
ts.factory.createSpreadElement(
314-
ts.factory.createParenthesizedExpression(
315-
ts.factory.createBinaryExpression(
316-
ts.factory.createIdentifier("mutationKey"),
317-
ts.factory.createToken(ts.SyntaxKind.QuestionQuestionToken),
318-
ts.factory.createArrayLiteralExpression(),
319-
),
320-
),
321-
),
322-
],
323-
false,
324-
);
325-
}
326-
327-
export function getRequestParamFromMethod(
328-
method: VariableDeclaration,
329-
pageParam?: string,
330-
modelNames: string[] = [],
331-
) {
332-
if (!getVariableArrowFunctionParameters(method).length) {
333-
return null;
334-
}
335-
const methodName = getNameFromVariable(method);
336-
337-
const params = getVariableArrowFunctionParameters(method).flatMap((param) => {
338-
const paramNodes = extractPropertiesFromObjectParam(param);
339-
340-
return paramNodes
341-
.filter((p) => p.name !== pageParam)
342-
.map((refParam) => ({
343-
name: refParam.name,
344-
// TODO: Client<Request, Response, unknown, RequestOptions> -> Client<Request, Response, unknown>
345-
typeName: getShortType(refParam.type?.getText() ?? ""),
346-
optional: refParam.optional,
347-
}));
348-
});
349-
350-
const areAllPropertiesOptional = params.every((param) => param.optional);
351-
352-
return ts.factory.createParameterDeclaration(
353-
undefined,
354-
undefined,
355-
ts.factory.createIdentifier("clientOptions"),
356-
undefined,
357-
ts.factory.createTypeReferenceNode(ts.factory.createIdentifier("Options"), [
358-
ts.factory.createTypeReferenceNode(
359-
modelNames.includes(`${capitalizeFirstLetter(methodName)}Data`)
360-
? `${capitalizeFirstLetter(methodName)}Data`
361-
: "unknown",
362-
),
363-
ts.factory.createTypeReferenceNode(ts.factory.createIdentifier("true")),
364-
]),
365-
// if all params are optional, we create an empty object literal
366-
// so the hook can be called without any parameters
367-
areAllPropertiesOptional
368-
? ts.factory.createObjectLiteralExpression()
369-
: undefined,
370-
);
371-
}

0 commit comments

Comments
 (0)