@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/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# Changelog — @dudousxd/nestjs-inertia-codegen
|
|
2
2
|
|
|
3
|
+
## 3.0.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- feat(codegen): import type references from source instead of inline expansion — eliminates unknown fields from depth limits
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- Updated dependencies []:
|
|
12
|
+
- @dudousxd/nestjs-inertia@3.0.0
|
|
13
|
+
|
|
14
|
+
## 2.0.1
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- fix(codegen): remove @tanstack/query-core dependency — generated api.ts uses plain object literals
|
|
19
|
+
|
|
20
|
+
- Updated dependencies []:
|
|
21
|
+
- @dudousxd/nestjs-inertia@2.0.1
|
|
22
|
+
|
|
3
23
|
## 2.0.0
|
|
4
24
|
|
|
5
25
|
### Minor Changes
|
package/dist/cli/main.cjs
CHANGED
|
@@ -222,7 +222,7 @@ async function emitApi(routes, outDir) {
|
|
|
222
222
|
await (0, import_promises3.mkdir)(outDir, {
|
|
223
223
|
recursive: true
|
|
224
224
|
});
|
|
225
|
-
const content = buildApiFile(routes);
|
|
225
|
+
const content = buildApiFile(routes, outDir);
|
|
226
226
|
await (0, import_promises3.writeFile)((0, import_node_path3.join)(outDir, "api.ts"), content, "utf8");
|
|
227
227
|
}
|
|
228
228
|
__name(emitApi, "emitApi");
|
|
@@ -295,9 +295,9 @@ function emitRouterTypeBlock(tree, indent) {
|
|
|
295
295
|
if (node.kind === "leaf") {
|
|
296
296
|
const c = node;
|
|
297
297
|
const method = c.method.toUpperCase();
|
|
298
|
-
const query = c.contractSource.query ?? "never";
|
|
299
|
-
const body = method === "GET" ? "never" : c.contractSource.body ?? "never";
|
|
300
|
-
const response = c.contractSource.response;
|
|
298
|
+
const query = c.contractSource.queryRef ? c.contractSource.queryRef.name : c.contractSource.query ?? "never";
|
|
299
|
+
const body = method === "GET" ? "never" : c.contractSource.bodyRef ? c.contractSource.bodyRef.name : c.contractSource.body ?? "never";
|
|
300
|
+
const response = c.contractSource.responseRef ? c.contractSource.responseRef.name : c.contractSource.response;
|
|
301
301
|
const safeMethod = JSON.stringify(method);
|
|
302
302
|
const safeUrl = JSON.stringify(c.path);
|
|
303
303
|
lines.push(`${pad}${objKey}: { method: ${safeMethod}; url: ${safeUrl}; query: ${query}; body: ${body}; response: ${response} };`);
|
|
@@ -325,11 +325,10 @@ function emitApiObjectBlock(tree, indent) {
|
|
|
325
325
|
const typeAccess = buildRouterTypeAccess(c.name);
|
|
326
326
|
lines.push(`${pad}${objKey}: {`);
|
|
327
327
|
lines.push(`${pad} queryKey: (query?: ${typeAccess}['query']) => query !== undefined ? [${flatName}, query] as const : [${flatName}] as const,`);
|
|
328
|
-
lines.push(`${pad} queryOptions: (query?: ${typeAccess}['query'])
|
|
329
|
-
lines.push(`${pad}
|
|
330
|
-
lines.push(`${pad}
|
|
331
|
-
lines.push(`${pad}
|
|
332
|
-
lines.push(`${pad} }),`);
|
|
328
|
+
lines.push(`${pad} queryOptions: (query?: ${typeAccess}['query']) => ({`);
|
|
329
|
+
lines.push(`${pad} queryKey: query !== undefined ? [${flatName}, query] as const : [${flatName}] as const,`);
|
|
330
|
+
lines.push(`${pad} queryFn: () => fetcher.get<${typeAccess}['response']>(route(${flatName} as never) || ${safePath}, { query }),`);
|
|
331
|
+
lines.push(`${pad} }),`);
|
|
333
332
|
lines.push(`${pad}},`);
|
|
334
333
|
} else {
|
|
335
334
|
const typeAccess = buildRouterTypeAccess(c.name);
|
|
@@ -354,18 +353,43 @@ function buildRouterTypeAccess(name) {
|
|
|
354
353
|
return `ApiRouter${segments.map((s) => `[${JSON.stringify(s)}]`).join("")}`;
|
|
355
354
|
}
|
|
356
355
|
__name(buildRouterTypeAccess, "buildRouterTypeAccess");
|
|
357
|
-
function buildApiFile(routes) {
|
|
356
|
+
function buildApiFile(routes, outDir) {
|
|
358
357
|
const contracted = routes.filter((r) => r.contract);
|
|
359
|
-
const
|
|
358
|
+
const importsByFile = /* @__PURE__ */ new Map();
|
|
359
|
+
for (const r of contracted) {
|
|
360
|
+
const cs = r.contract?.contractSource;
|
|
361
|
+
if (!cs) continue;
|
|
362
|
+
for (const ref of [
|
|
363
|
+
cs.queryRef,
|
|
364
|
+
cs.bodyRef,
|
|
365
|
+
cs.responseRef
|
|
366
|
+
]) {
|
|
367
|
+
if (!ref) continue;
|
|
368
|
+
let names = importsByFile.get(ref.filePath);
|
|
369
|
+
if (!names) {
|
|
370
|
+
names = /* @__PURE__ */ new Set();
|
|
371
|
+
importsByFile.set(ref.filePath, names);
|
|
372
|
+
}
|
|
373
|
+
names.add(ref.name);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
360
376
|
const lines = [
|
|
361
377
|
"// Generated by @dudousxd/nestjs-inertia-codegen. Do not edit.",
|
|
362
378
|
""
|
|
363
379
|
];
|
|
364
|
-
if (hasGetRoutes) {
|
|
365
|
-
lines.push("import { queryOptions } from '@tanstack/query-core';");
|
|
366
|
-
}
|
|
367
380
|
lines.push("import { route } from './routes.js';");
|
|
368
381
|
lines.push("import { createFetcher } from '@dudousxd/nestjs-inertia-client';");
|
|
382
|
+
if (importsByFile.size > 0 && outDir) {
|
|
383
|
+
lines.push("");
|
|
384
|
+
for (const [filePath, names] of importsByFile) {
|
|
385
|
+
let relPath = (0, import_node_path3.relative)(outDir, filePath).replace(/\.ts$/, "");
|
|
386
|
+
if (!relPath.startsWith(".")) relPath = `./${relPath}`;
|
|
387
|
+
const sortedNames = [
|
|
388
|
+
...names
|
|
389
|
+
].sort();
|
|
390
|
+
lines.push(`import type { ${sortedNames.join(", ")} } from '${relPath}';`);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
369
393
|
lines.push("");
|
|
370
394
|
lines.push("export const fetcher = createFetcher();");
|
|
371
395
|
lines.push("");
|
|
@@ -1110,6 +1134,53 @@ function resolveIdentifierToClassType(node, sourceFile, project, depth) {
|
|
|
1110
1134
|
return name;
|
|
1111
1135
|
}
|
|
1112
1136
|
__name(resolveIdentifierToClassType, "resolveIdentifierToClassType");
|
|
1137
|
+
function tryResolveTypeRef(typeNode, sourceFile, project) {
|
|
1138
|
+
if (import_ts_morph.Node.isTypeReference(typeNode)) {
|
|
1139
|
+
const typeName = typeNode.getTypeName();
|
|
1140
|
+
const name = import_ts_morph.Node.isIdentifier(typeName) ? typeName.getText() : null;
|
|
1141
|
+
if (!name) return null;
|
|
1142
|
+
if (name === "Promise") {
|
|
1143
|
+
const typeArgs = typeNode.getTypeArguments();
|
|
1144
|
+
const first = typeArgs[0];
|
|
1145
|
+
if (first) return tryResolveTypeRef(first, sourceFile, project);
|
|
1146
|
+
return null;
|
|
1147
|
+
}
|
|
1148
|
+
if ([
|
|
1149
|
+
"string",
|
|
1150
|
+
"number",
|
|
1151
|
+
"boolean",
|
|
1152
|
+
"void",
|
|
1153
|
+
"unknown",
|
|
1154
|
+
"any",
|
|
1155
|
+
"Date",
|
|
1156
|
+
"Array"
|
|
1157
|
+
].includes(name)) {
|
|
1158
|
+
return null;
|
|
1159
|
+
}
|
|
1160
|
+
const localDecl = sourceFile.getInterface(name) || sourceFile.getClass(name) || sourceFile.getTypeAlias(name);
|
|
1161
|
+
if (localDecl && localDecl.isExported()) {
|
|
1162
|
+
return {
|
|
1163
|
+
name,
|
|
1164
|
+
filePath: sourceFile.getFilePath()
|
|
1165
|
+
};
|
|
1166
|
+
}
|
|
1167
|
+
const resolved = resolveImportedType(name, sourceFile, project);
|
|
1168
|
+
if (resolved && (resolved.kind === "class" || resolved.kind === "interface")) {
|
|
1169
|
+
const decl = resolved.decl;
|
|
1170
|
+
if (decl.isExported()) {
|
|
1171
|
+
return {
|
|
1172
|
+
name,
|
|
1173
|
+
filePath: resolved.file.getFilePath()
|
|
1174
|
+
};
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
if (import_ts_morph.Node.isArrayTypeNode(typeNode)) {
|
|
1179
|
+
return tryResolveTypeRef(typeNode.getElementTypeNode(), sourceFile, project);
|
|
1180
|
+
}
|
|
1181
|
+
return null;
|
|
1182
|
+
}
|
|
1183
|
+
__name(tryResolveTypeRef, "tryResolveTypeRef");
|
|
1113
1184
|
function extractDtoContract(method, sourceFile, project) {
|
|
1114
1185
|
const body = extractBodyType(method, sourceFile, project);
|
|
1115
1186
|
const query = extractQueryType(method, sourceFile, project);
|
|
@@ -1118,11 +1189,61 @@ function extractDtoContract(method, sourceFile, project) {
|
|
|
1118
1189
|
if (body === null && query === null && paramsType === null && response === "unknown") {
|
|
1119
1190
|
return null;
|
|
1120
1191
|
}
|
|
1192
|
+
let bodyRef = null;
|
|
1193
|
+
let queryRef = null;
|
|
1194
|
+
let responseRef = null;
|
|
1195
|
+
for (const param of method.getParameters()) {
|
|
1196
|
+
if (param.getDecorators().some((d) => d.getName() === "Body") && param.getTypeNode()) {
|
|
1197
|
+
bodyRef = tryResolveTypeRef(param.getTypeNode(), sourceFile, project);
|
|
1198
|
+
}
|
|
1199
|
+
if (param.getDecorators().some((d) => d.getName() === "Query") && param.getTypeNode()) {
|
|
1200
|
+
queryRef = tryResolveTypeRef(param.getTypeNode(), sourceFile, project);
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
const returnTypeNode = method.getReturnTypeNode();
|
|
1204
|
+
if (returnTypeNode) {
|
|
1205
|
+
responseRef = tryResolveTypeRef(returnTypeNode, sourceFile, project);
|
|
1206
|
+
}
|
|
1207
|
+
if (!responseRef) {
|
|
1208
|
+
const apiResp = method.getDecorator("ApiResponse");
|
|
1209
|
+
if (apiResp) {
|
|
1210
|
+
const args = apiResp.getArguments();
|
|
1211
|
+
const optsArg = args[0];
|
|
1212
|
+
if (optsArg && import_ts_morph.Node.isObjectLiteralExpression(optsArg)) {
|
|
1213
|
+
for (const prop of optsArg.getProperties()) {
|
|
1214
|
+
if (import_ts_morph.Node.isPropertyAssignment(prop) && prop.getName() === "type") {
|
|
1215
|
+
const val = prop.getInitializer();
|
|
1216
|
+
if (val && import_ts_morph.Node.isIdentifier(val)) {
|
|
1217
|
+
const name = val.getText();
|
|
1218
|
+
const localDecl = sourceFile.getInterface(name) || sourceFile.getClass(name) || sourceFile.getTypeAlias(name);
|
|
1219
|
+
if (localDecl && localDecl.isExported()) {
|
|
1220
|
+
responseRef = {
|
|
1221
|
+
name,
|
|
1222
|
+
filePath: sourceFile.getFilePath()
|
|
1223
|
+
};
|
|
1224
|
+
} else {
|
|
1225
|
+
const resolved = resolveImportedType(name, sourceFile, project);
|
|
1226
|
+
if (resolved && (resolved.kind === "class" || resolved.kind === "interface") && resolved.decl.isExported()) {
|
|
1227
|
+
responseRef = {
|
|
1228
|
+
name,
|
|
1229
|
+
filePath: resolved.file.getFilePath()
|
|
1230
|
+
};
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1121
1239
|
return {
|
|
1122
1240
|
query,
|
|
1123
1241
|
body,
|
|
1124
1242
|
response,
|
|
1125
|
-
params: paramsType
|
|
1243
|
+
params: paramsType,
|
|
1244
|
+
queryRef,
|
|
1245
|
+
bodyRef,
|
|
1246
|
+
responseRef
|
|
1126
1247
|
};
|
|
1127
1248
|
}
|
|
1128
1249
|
__name(extractDtoContract, "extractDtoContract");
|
|
@@ -1261,7 +1382,10 @@ function extractFromSourceFile(sourceFile, project) {
|
|
|
1261
1382
|
contractSource: {
|
|
1262
1383
|
query: dtoContract.query,
|
|
1263
1384
|
body: dtoContract.body,
|
|
1264
|
-
response: dtoContract.response
|
|
1385
|
+
response: dtoContract.response,
|
|
1386
|
+
queryRef: dtoContract.queryRef,
|
|
1387
|
+
bodyRef: dtoContract.bodyRef,
|
|
1388
|
+
responseRef: dtoContract.responseRef
|
|
1265
1389
|
}
|
|
1266
1390
|
}
|
|
1267
1391
|
} : {}
|
|
@@ -1434,7 +1558,7 @@ async function watch(config, onChange) {
|
|
|
1434
1558
|
__name(watch, "watch");
|
|
1435
1559
|
|
|
1436
1560
|
// src/index.ts
|
|
1437
|
-
var VERSION = "
|
|
1561
|
+
var VERSION = "3.0.0";
|
|
1438
1562
|
|
|
1439
1563
|
// src/cli/codegen.ts
|
|
1440
1564
|
async function runCodegen(opts = {}) {
|