@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 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} queryOptions({`);
330
- lines.push(`${pad} queryKey: query !== undefined ? [${flatName}, query] : [${flatName}],`);
331
- lines.push(`${pad} queryFn: () => fetcher.get<${typeAccess}['response']>(route(${flatName} as never) || ${safePath}, { query }),`);
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 hasGetRoutes = contracted.some((r) => r.method === "GET");
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 = "2.0.0";
1561
+ var VERSION = "3.0.0";
1438
1562
 
1439
1563
  // src/cli/codegen.ts
1440
1564
  async function runCodegen(opts = {}) {