@dudousxd/nestjs-inertia-codegen 2.0.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/dist/cli/main.cjs +141 -17
- package/dist/cli/main.cjs.map +1 -1
- package/dist/cli/main.js +142 -18
- package/dist/cli/main.js.map +1 -1
- package/dist/index.cjs +141 -17
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -1
- package/dist/index.d.ts +8 -1
- package/dist/index.js +142 -18
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/cli/main.js
CHANGED
|
@@ -185,12 +185,12 @@ __name(extractPropsSource, "extractPropsSource");
|
|
|
185
185
|
|
|
186
186
|
// src/emit/emit-api.ts
|
|
187
187
|
import { mkdir, writeFile } from "fs/promises";
|
|
188
|
-
import { join as join2 } from "path";
|
|
188
|
+
import { join as join2, relative as relative3 } from "path";
|
|
189
189
|
async function emitApi(routes, outDir) {
|
|
190
190
|
await mkdir(outDir, {
|
|
191
191
|
recursive: true
|
|
192
192
|
});
|
|
193
|
-
const content = buildApiFile(routes);
|
|
193
|
+
const content = buildApiFile(routes, outDir);
|
|
194
194
|
await writeFile(join2(outDir, "api.ts"), content, "utf8");
|
|
195
195
|
}
|
|
196
196
|
__name(emitApi, "emitApi");
|
|
@@ -263,9 +263,9 @@ function emitRouterTypeBlock(tree, indent) {
|
|
|
263
263
|
if (node.kind === "leaf") {
|
|
264
264
|
const c = node;
|
|
265
265
|
const method = c.method.toUpperCase();
|
|
266
|
-
const query = c.contractSource.query ?? "never";
|
|
267
|
-
const body = method === "GET" ? "never" : c.contractSource.body ?? "never";
|
|
268
|
-
const response = c.contractSource.response;
|
|
266
|
+
const query = c.contractSource.queryRef ? c.contractSource.queryRef.name : c.contractSource.query ?? "never";
|
|
267
|
+
const body = method === "GET" ? "never" : c.contractSource.bodyRef ? c.contractSource.bodyRef.name : c.contractSource.body ?? "never";
|
|
268
|
+
const response = c.contractSource.responseRef ? c.contractSource.responseRef.name : c.contractSource.response;
|
|
269
269
|
const safeMethod = JSON.stringify(method);
|
|
270
270
|
const safeUrl = JSON.stringify(c.path);
|
|
271
271
|
lines.push(`${pad}${objKey}: { method: ${safeMethod}; url: ${safeUrl}; query: ${query}; body: ${body}; response: ${response} };`);
|
|
@@ -293,11 +293,10 @@ function emitApiObjectBlock(tree, indent) {
|
|
|
293
293
|
const typeAccess = buildRouterTypeAccess(c.name);
|
|
294
294
|
lines.push(`${pad}${objKey}: {`);
|
|
295
295
|
lines.push(`${pad} queryKey: (query?: ${typeAccess}['query']) => query !== undefined ? [${flatName}, query] as const : [${flatName}] as const,`);
|
|
296
|
-
lines.push(`${pad} queryOptions: (query?: ${typeAccess}['query'])
|
|
297
|
-
lines.push(`${pad}
|
|
298
|
-
lines.push(`${pad}
|
|
299
|
-
lines.push(`${pad}
|
|
300
|
-
lines.push(`${pad} }),`);
|
|
296
|
+
lines.push(`${pad} queryOptions: (query?: ${typeAccess}['query']) => ({`);
|
|
297
|
+
lines.push(`${pad} queryKey: query !== undefined ? [${flatName}, query] as const : [${flatName}] as const,`);
|
|
298
|
+
lines.push(`${pad} queryFn: () => fetcher.get<${typeAccess}['response']>(route(${flatName} as never) || ${safePath}, { query }),`);
|
|
299
|
+
lines.push(`${pad} }),`);
|
|
301
300
|
lines.push(`${pad}},`);
|
|
302
301
|
} else {
|
|
303
302
|
const typeAccess = buildRouterTypeAccess(c.name);
|
|
@@ -322,18 +321,43 @@ function buildRouterTypeAccess(name) {
|
|
|
322
321
|
return `ApiRouter${segments.map((s) => `[${JSON.stringify(s)}]`).join("")}`;
|
|
323
322
|
}
|
|
324
323
|
__name(buildRouterTypeAccess, "buildRouterTypeAccess");
|
|
325
|
-
function buildApiFile(routes) {
|
|
324
|
+
function buildApiFile(routes, outDir) {
|
|
326
325
|
const contracted = routes.filter((r) => r.contract);
|
|
327
|
-
const
|
|
326
|
+
const importsByFile = /* @__PURE__ */ new Map();
|
|
327
|
+
for (const r of contracted) {
|
|
328
|
+
const cs = r.contract?.contractSource;
|
|
329
|
+
if (!cs) continue;
|
|
330
|
+
for (const ref of [
|
|
331
|
+
cs.queryRef,
|
|
332
|
+
cs.bodyRef,
|
|
333
|
+
cs.responseRef
|
|
334
|
+
]) {
|
|
335
|
+
if (!ref) continue;
|
|
336
|
+
let names = importsByFile.get(ref.filePath);
|
|
337
|
+
if (!names) {
|
|
338
|
+
names = /* @__PURE__ */ new Set();
|
|
339
|
+
importsByFile.set(ref.filePath, names);
|
|
340
|
+
}
|
|
341
|
+
names.add(ref.name);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
328
344
|
const lines = [
|
|
329
345
|
"// Generated by @dudousxd/nestjs-inertia-codegen. Do not edit.",
|
|
330
346
|
""
|
|
331
347
|
];
|
|
332
|
-
if (hasGetRoutes) {
|
|
333
|
-
lines.push("import { queryOptions } from '@tanstack/query-core';");
|
|
334
|
-
}
|
|
335
348
|
lines.push("import { route } from './routes.js';");
|
|
336
349
|
lines.push("import { createFetcher } from '@dudousxd/nestjs-inertia-client';");
|
|
350
|
+
if (importsByFile.size > 0 && outDir) {
|
|
351
|
+
lines.push("");
|
|
352
|
+
for (const [filePath, names] of importsByFile) {
|
|
353
|
+
let relPath = relative3(outDir, filePath).replace(/\.ts$/, "");
|
|
354
|
+
if (!relPath.startsWith(".")) relPath = `./${relPath}`;
|
|
355
|
+
const sortedNames = [
|
|
356
|
+
...names
|
|
357
|
+
].sort();
|
|
358
|
+
lines.push(`import type { ${sortedNames.join(", ")} } from '${relPath}';`);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
337
361
|
lines.push("");
|
|
338
362
|
lines.push("export const fetcher = createFetcher();");
|
|
339
363
|
lines.push("");
|
|
@@ -1078,6 +1102,53 @@ function resolveIdentifierToClassType(node, sourceFile, project, depth) {
|
|
|
1078
1102
|
return name;
|
|
1079
1103
|
}
|
|
1080
1104
|
__name(resolveIdentifierToClassType, "resolveIdentifierToClassType");
|
|
1105
|
+
function tryResolveTypeRef(typeNode, sourceFile, project) {
|
|
1106
|
+
if (Node.isTypeReference(typeNode)) {
|
|
1107
|
+
const typeName = typeNode.getTypeName();
|
|
1108
|
+
const name = Node.isIdentifier(typeName) ? typeName.getText() : null;
|
|
1109
|
+
if (!name) return null;
|
|
1110
|
+
if (name === "Promise") {
|
|
1111
|
+
const typeArgs = typeNode.getTypeArguments();
|
|
1112
|
+
const first = typeArgs[0];
|
|
1113
|
+
if (first) return tryResolveTypeRef(first, sourceFile, project);
|
|
1114
|
+
return null;
|
|
1115
|
+
}
|
|
1116
|
+
if ([
|
|
1117
|
+
"string",
|
|
1118
|
+
"number",
|
|
1119
|
+
"boolean",
|
|
1120
|
+
"void",
|
|
1121
|
+
"unknown",
|
|
1122
|
+
"any",
|
|
1123
|
+
"Date",
|
|
1124
|
+
"Array"
|
|
1125
|
+
].includes(name)) {
|
|
1126
|
+
return null;
|
|
1127
|
+
}
|
|
1128
|
+
const localDecl = sourceFile.getInterface(name) || sourceFile.getClass(name) || sourceFile.getTypeAlias(name);
|
|
1129
|
+
if (localDecl && localDecl.isExported()) {
|
|
1130
|
+
return {
|
|
1131
|
+
name,
|
|
1132
|
+
filePath: sourceFile.getFilePath()
|
|
1133
|
+
};
|
|
1134
|
+
}
|
|
1135
|
+
const resolved = resolveImportedType(name, sourceFile, project);
|
|
1136
|
+
if (resolved && (resolved.kind === "class" || resolved.kind === "interface")) {
|
|
1137
|
+
const decl = resolved.decl;
|
|
1138
|
+
if (decl.isExported()) {
|
|
1139
|
+
return {
|
|
1140
|
+
name,
|
|
1141
|
+
filePath: resolved.file.getFilePath()
|
|
1142
|
+
};
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
if (Node.isArrayTypeNode(typeNode)) {
|
|
1147
|
+
return tryResolveTypeRef(typeNode.getElementTypeNode(), sourceFile, project);
|
|
1148
|
+
}
|
|
1149
|
+
return null;
|
|
1150
|
+
}
|
|
1151
|
+
__name(tryResolveTypeRef, "tryResolveTypeRef");
|
|
1081
1152
|
function extractDtoContract(method, sourceFile, project) {
|
|
1082
1153
|
const body = extractBodyType(method, sourceFile, project);
|
|
1083
1154
|
const query = extractQueryType(method, sourceFile, project);
|
|
@@ -1086,11 +1157,61 @@ function extractDtoContract(method, sourceFile, project) {
|
|
|
1086
1157
|
if (body === null && query === null && paramsType === null && response === "unknown") {
|
|
1087
1158
|
return null;
|
|
1088
1159
|
}
|
|
1160
|
+
let bodyRef = null;
|
|
1161
|
+
let queryRef = null;
|
|
1162
|
+
let responseRef = null;
|
|
1163
|
+
for (const param of method.getParameters()) {
|
|
1164
|
+
if (param.getDecorators().some((d) => d.getName() === "Body") && param.getTypeNode()) {
|
|
1165
|
+
bodyRef = tryResolveTypeRef(param.getTypeNode(), sourceFile, project);
|
|
1166
|
+
}
|
|
1167
|
+
if (param.getDecorators().some((d) => d.getName() === "Query") && param.getTypeNode()) {
|
|
1168
|
+
queryRef = tryResolveTypeRef(param.getTypeNode(), sourceFile, project);
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
const returnTypeNode = method.getReturnTypeNode();
|
|
1172
|
+
if (returnTypeNode) {
|
|
1173
|
+
responseRef = tryResolveTypeRef(returnTypeNode, sourceFile, project);
|
|
1174
|
+
}
|
|
1175
|
+
if (!responseRef) {
|
|
1176
|
+
const apiResp = method.getDecorator("ApiResponse");
|
|
1177
|
+
if (apiResp) {
|
|
1178
|
+
const args = apiResp.getArguments();
|
|
1179
|
+
const optsArg = args[0];
|
|
1180
|
+
if (optsArg && Node.isObjectLiteralExpression(optsArg)) {
|
|
1181
|
+
for (const prop of optsArg.getProperties()) {
|
|
1182
|
+
if (Node.isPropertyAssignment(prop) && prop.getName() === "type") {
|
|
1183
|
+
const val = prop.getInitializer();
|
|
1184
|
+
if (val && Node.isIdentifier(val)) {
|
|
1185
|
+
const name = val.getText();
|
|
1186
|
+
const localDecl = sourceFile.getInterface(name) || sourceFile.getClass(name) || sourceFile.getTypeAlias(name);
|
|
1187
|
+
if (localDecl && localDecl.isExported()) {
|
|
1188
|
+
responseRef = {
|
|
1189
|
+
name,
|
|
1190
|
+
filePath: sourceFile.getFilePath()
|
|
1191
|
+
};
|
|
1192
|
+
} else {
|
|
1193
|
+
const resolved = resolveImportedType(name, sourceFile, project);
|
|
1194
|
+
if (resolved && (resolved.kind === "class" || resolved.kind === "interface") && resolved.decl.isExported()) {
|
|
1195
|
+
responseRef = {
|
|
1196
|
+
name,
|
|
1197
|
+
filePath: resolved.file.getFilePath()
|
|
1198
|
+
};
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1089
1207
|
return {
|
|
1090
1208
|
query,
|
|
1091
1209
|
body,
|
|
1092
1210
|
response,
|
|
1093
|
-
params: paramsType
|
|
1211
|
+
params: paramsType,
|
|
1212
|
+
queryRef,
|
|
1213
|
+
bodyRef,
|
|
1214
|
+
responseRef
|
|
1094
1215
|
};
|
|
1095
1216
|
}
|
|
1096
1217
|
__name(extractDtoContract, "extractDtoContract");
|
|
@@ -1229,7 +1350,10 @@ function extractFromSourceFile(sourceFile, project) {
|
|
|
1229
1350
|
contractSource: {
|
|
1230
1351
|
query: dtoContract.query,
|
|
1231
1352
|
body: dtoContract.body,
|
|
1232
|
-
response: dtoContract.response
|
|
1353
|
+
response: dtoContract.response,
|
|
1354
|
+
queryRef: dtoContract.queryRef,
|
|
1355
|
+
bodyRef: dtoContract.bodyRef,
|
|
1356
|
+
responseRef: dtoContract.responseRef
|
|
1233
1357
|
}
|
|
1234
1358
|
}
|
|
1235
1359
|
} : {}
|
|
@@ -1402,7 +1526,7 @@ async function watch(config, onChange) {
|
|
|
1402
1526
|
__name(watch, "watch");
|
|
1403
1527
|
|
|
1404
1528
|
// src/index.ts
|
|
1405
|
-
var VERSION = "
|
|
1529
|
+
var VERSION = "3.0.0";
|
|
1406
1530
|
|
|
1407
1531
|
// src/cli/codegen.ts
|
|
1408
1532
|
async function runCodegen(opts = {}) {
|