@dudousxd/nestjs-inertia-codegen 1.2.0 → 1.4.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 +22 -0
- package/dist/cli/main.cjs +467 -104
- package/dist/cli/main.cjs.map +1 -1
- package/dist/cli/main.js +458 -95
- package/dist/cli/main.js.map +1 -1
- package/dist/index.cjs +259 -68
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -1
- package/dist/index.d.ts +10 -1
- package/dist/index.js +257 -66
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.cjs
CHANGED
|
@@ -269,16 +269,6 @@ function validateNameSegment(seg, fullName) {
|
|
|
269
269
|
}
|
|
270
270
|
}
|
|
271
271
|
__name(validateNameSegment, "validateNameSegment");
|
|
272
|
-
function detectCollisions(tree, name) {
|
|
273
|
-
for (const [key, node] of tree) {
|
|
274
|
-
if (node.kind === "leaf") {
|
|
275
|
-
} else {
|
|
276
|
-
void key;
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
void name;
|
|
280
|
-
}
|
|
281
|
-
__name(detectCollisions, "detectCollisions");
|
|
282
272
|
function insertIntoTree(tree, segments, leaf, fullName) {
|
|
283
273
|
const head = segments[0];
|
|
284
274
|
const rest = segments.slice(1);
|
|
@@ -308,7 +298,30 @@ function insertIntoTree(tree, segments, leaf, fullName) {
|
|
|
308
298
|
}
|
|
309
299
|
}
|
|
310
300
|
__name(insertIntoTree, "insertIntoTree");
|
|
311
|
-
function
|
|
301
|
+
function buildParamsType(params) {
|
|
302
|
+
const pathParams = params.filter((p) => p.source === "path");
|
|
303
|
+
if (pathParams.length === 0) return "never";
|
|
304
|
+
return `{ ${pathParams.map((p) => `${p.name}: string`).join("; ")} }`;
|
|
305
|
+
}
|
|
306
|
+
__name(buildParamsType, "buildParamsType");
|
|
307
|
+
function hasPathParams(params) {
|
|
308
|
+
return params.some((p) => p.source === "path");
|
|
309
|
+
}
|
|
310
|
+
__name(hasPathParams, "hasPathParams");
|
|
311
|
+
function buildResponseType(c, outDir) {
|
|
312
|
+
if (c.controllerRef) {
|
|
313
|
+
let relPath = (0, import_node_path3.relative)(outDir, c.controllerRef.filePath).replace(/\.ts$/, "");
|
|
314
|
+
if (!relPath.startsWith(".")) relPath = `./${relPath}`;
|
|
315
|
+
return `Awaited<ReturnType<import('${relPath}').${c.controllerRef.className}['${c.controllerRef.methodName}']>>`;
|
|
316
|
+
}
|
|
317
|
+
const respRef = c.contractSource.responseRef;
|
|
318
|
+
if (respRef) {
|
|
319
|
+
return respRef.isArray ? `Array<${respRef.name}>` : respRef.name;
|
|
320
|
+
}
|
|
321
|
+
return c.contractSource.response;
|
|
322
|
+
}
|
|
323
|
+
__name(buildResponseType, "buildResponseType");
|
|
324
|
+
function emitRouterTypeBlock(tree, indent, outDir) {
|
|
312
325
|
const pad = " ".repeat(indent);
|
|
313
326
|
const lines = [];
|
|
314
327
|
for (const [key, node] of tree) {
|
|
@@ -320,14 +333,14 @@ function emitRouterTypeBlock(tree, indent) {
|
|
|
320
333
|
const query = queryRef ? queryRef.isArray ? `Array<${queryRef.name}>` : queryRef.name : c.contractSource.query ?? "never";
|
|
321
334
|
const bodyRef = c.contractSource.bodyRef;
|
|
322
335
|
const body = method === "GET" ? "never" : bodyRef ? bodyRef.isArray ? `Array<${bodyRef.name}>` : bodyRef.name : c.contractSource.body ?? "never";
|
|
323
|
-
const
|
|
324
|
-
const
|
|
336
|
+
const response = buildResponseType(c, outDir);
|
|
337
|
+
const params = buildParamsType(c.params);
|
|
325
338
|
const safeMethod = JSON.stringify(method);
|
|
326
339
|
const safeUrl = JSON.stringify(c.path);
|
|
327
|
-
lines.push(`${pad}${objKey}: { method: ${safeMethod}; url: ${safeUrl}; query: ${query}; body: ${body}; response: ${response} };`);
|
|
340
|
+
lines.push(`${pad}${objKey}: { method: ${safeMethod}; url: ${safeUrl}; params: ${params}; query: ${query}; body: ${body}; response: ${response} };`);
|
|
328
341
|
} else {
|
|
329
342
|
lines.push(`${pad}${objKey}: {`);
|
|
330
|
-
lines.push(...emitRouterTypeBlock(node.children, indent + 2));
|
|
343
|
+
lines.push(...emitRouterTypeBlock(node.children, indent + 2, outDir));
|
|
331
344
|
lines.push(`${pad}};`);
|
|
332
345
|
}
|
|
333
346
|
}
|
|
@@ -347,20 +360,61 @@ function emitApiObjectBlock(tree, indent) {
|
|
|
347
360
|
const fetcherMethod = method.toLowerCase();
|
|
348
361
|
if (method === "GET") {
|
|
349
362
|
const typeAccess = buildRouterTypeAccess(c.name);
|
|
363
|
+
const withParams = hasPathParams(c.params);
|
|
350
364
|
lines.push(`${pad}${objKey}: {`);
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
365
|
+
if (withParams) {
|
|
366
|
+
lines.push(`${pad} queryKey: (params: ${typeAccess}['params'], query?: ${typeAccess}['query']) => query !== undefined ? [${flatName}, params, query] as const : [${flatName}, params] as const,`);
|
|
367
|
+
lines.push(`${pad} queryOptions: (params: ${typeAccess}['params'], query?: ${typeAccess}['query']) =>`);
|
|
368
|
+
lines.push(`${pad} _queryOptions({`);
|
|
369
|
+
lines.push(`${pad} queryKey: query !== undefined ? [${flatName}, params, query] as const : [${flatName}, params] as const,`);
|
|
370
|
+
lines.push(`${pad} queryFn: () => fetcher.get<${typeAccess}['response']>(route(${flatName} as never, params as never) || ${safePath}, { query }),`);
|
|
371
|
+
lines.push(`${pad} }),`);
|
|
372
|
+
lines.push(`${pad} infiniteQueryOptions: (params: ${typeAccess}['params'], query?: ${typeAccess}['query']) => ({`);
|
|
373
|
+
lines.push(`${pad} queryKey: query !== undefined ? [${flatName}, params, query] as const : [${flatName}, params] as const,`);
|
|
374
|
+
lines.push(`${pad} queryFn: ({ pageParam }: { pageParam: number }) => fetcher.get<${typeAccess}['response']>(route(${flatName} as never, params as never) || ${safePath}, { query: { ...query, page: pageParam } }),`);
|
|
375
|
+
lines.push(`${pad} initialPageParam: 1,`);
|
|
376
|
+
lines.push(`${pad} getNextPageParam: (lastPage: ${typeAccess}['response']) => {`);
|
|
377
|
+
lines.push(`${pad} const meta = (lastPage as any)?.meta;`);
|
|
378
|
+
lines.push(`${pad} if (meta?.page != null && meta?.lastPage != null) {`);
|
|
379
|
+
lines.push(`${pad} return meta.page < meta.lastPage ? meta.page + 1 : undefined;`);
|
|
380
|
+
lines.push(`${pad} }`);
|
|
381
|
+
lines.push(`${pad} return undefined;`);
|
|
382
|
+
lines.push(`${pad} },`);
|
|
383
|
+
lines.push(`${pad} }),`);
|
|
384
|
+
} else {
|
|
385
|
+
lines.push(`${pad} queryKey: (query?: ${typeAccess}['query']) => query !== undefined ? [${flatName}, query] as const : [${flatName}] as const,`);
|
|
386
|
+
lines.push(`${pad} queryOptions: (query?: ${typeAccess}['query']) =>`);
|
|
387
|
+
lines.push(`${pad} _queryOptions({`);
|
|
388
|
+
lines.push(`${pad} queryKey: query !== undefined ? [${flatName}, query] as const : [${flatName}] as const,`);
|
|
389
|
+
lines.push(`${pad} queryFn: () => fetcher.get<${typeAccess}['response']>(route(${flatName} as never) || ${safePath}, { query }),`);
|
|
390
|
+
lines.push(`${pad} }),`);
|
|
391
|
+
lines.push(`${pad} infiniteQueryOptions: (query?: ${typeAccess}['query']) => ({`);
|
|
392
|
+
lines.push(`${pad} queryKey: query !== undefined ? [${flatName}, query] as const : [${flatName}] as const,`);
|
|
393
|
+
lines.push(`${pad} queryFn: ({ pageParam }: { pageParam: number }) => fetcher.get<${typeAccess}['response']>(route(${flatName} as never) || ${safePath}, { query: { ...query, page: pageParam } }),`);
|
|
394
|
+
lines.push(`${pad} initialPageParam: 1,`);
|
|
395
|
+
lines.push(`${pad} getNextPageParam: (lastPage: ${typeAccess}['response']) => {`);
|
|
396
|
+
lines.push(`${pad} const meta = (lastPage as any)?.meta;`);
|
|
397
|
+
lines.push(`${pad} if (meta?.page != null && meta?.lastPage != null) {`);
|
|
398
|
+
lines.push(`${pad} return meta.page < meta.lastPage ? meta.page + 1 : undefined;`);
|
|
399
|
+
lines.push(`${pad} }`);
|
|
400
|
+
lines.push(`${pad} return undefined;`);
|
|
401
|
+
lines.push(`${pad} },`);
|
|
402
|
+
lines.push(`${pad} }),`);
|
|
403
|
+
}
|
|
356
404
|
lines.push(`${pad}},`);
|
|
357
405
|
} else {
|
|
358
406
|
const typeAccess = buildRouterTypeAccess(c.name);
|
|
407
|
+
const withParams = hasPathParams(c.params);
|
|
359
408
|
lines.push(`${pad}${objKey}: {`);
|
|
360
409
|
lines.push(`${pad} queryKey: () => [${flatName}] as const,`);
|
|
361
|
-
lines.push(`${pad} mutationOptions: ()
|
|
362
|
-
lines.push(`${pad}
|
|
363
|
-
|
|
410
|
+
lines.push(`${pad} mutationOptions: () =>`);
|
|
411
|
+
lines.push(`${pad} _mutationOptions({`);
|
|
412
|
+
if (withParams) {
|
|
413
|
+
lines.push(`${pad} mutationFn: (input: { params: ${typeAccess}['params']; body: ${typeAccess}['body'] }) => fetcher.${fetcherMethod}<${typeAccess}['response']>(route(${flatName} as never, input.params as never) || ${safePath}, { body: input.body }),`);
|
|
414
|
+
} else {
|
|
415
|
+
lines.push(`${pad} mutationFn: (body: ${typeAccess}['body']) => fetcher.${fetcherMethod}<${typeAccess}['response']>(route(${flatName} as never) || ${safePath}, { body }),`);
|
|
416
|
+
}
|
|
417
|
+
lines.push(`${pad} }),`);
|
|
364
418
|
lines.push(`${pad}},`);
|
|
365
419
|
}
|
|
366
420
|
} else {
|
|
@@ -383,11 +437,15 @@ function buildApiFile(routes, outDir) {
|
|
|
383
437
|
for (const r of contracted) {
|
|
384
438
|
const cs = r.contract?.contractSource;
|
|
385
439
|
if (!cs) continue;
|
|
386
|
-
|
|
440
|
+
const refs = r.controllerRef ? [
|
|
441
|
+
cs.queryRef,
|
|
442
|
+
cs.bodyRef
|
|
443
|
+
] : [
|
|
387
444
|
cs.queryRef,
|
|
388
445
|
cs.bodyRef,
|
|
389
446
|
cs.responseRef
|
|
390
|
-
]
|
|
447
|
+
];
|
|
448
|
+
for (const ref of refs) {
|
|
391
449
|
if (!ref) continue;
|
|
392
450
|
let names = importsByFile.get(ref.filePath);
|
|
393
451
|
if (!names) {
|
|
@@ -397,10 +455,18 @@ function buildApiFile(routes, outDir) {
|
|
|
397
455
|
names.add(ref.name);
|
|
398
456
|
}
|
|
399
457
|
}
|
|
458
|
+
const hasGetRoutes = contracted.some((r) => r.method === "GET");
|
|
459
|
+
const hasMutationRoutes = contracted.some((r) => r.method !== "GET");
|
|
400
460
|
const lines = [
|
|
401
461
|
"// Generated by @dudousxd/nestjs-inertia-codegen. Do not edit.",
|
|
402
462
|
""
|
|
403
463
|
];
|
|
464
|
+
const tqImports = [];
|
|
465
|
+
if (hasGetRoutes) tqImports.push("queryOptions as _queryOptions");
|
|
466
|
+
if (hasMutationRoutes) tqImports.push("mutationOptions as _mutationOptions");
|
|
467
|
+
if (tqImports.length > 0) {
|
|
468
|
+
lines.push(`import { ${tqImports.join(", ")} } from '@tanstack/react-query';`);
|
|
469
|
+
}
|
|
404
470
|
lines.push("import { route } from './routes.js';");
|
|
405
471
|
lines.push("import { createFetcher } from '@dudousxd/nestjs-inertia-client';");
|
|
406
472
|
if (importsByFile.size > 0 && outDir) {
|
|
@@ -454,13 +520,14 @@ function buildApiFile(routes, outDir) {
|
|
|
454
520
|
method: r.method,
|
|
455
521
|
name,
|
|
456
522
|
path: r.path,
|
|
523
|
+
params: r.params,
|
|
524
|
+
controllerRef: r.controllerRef,
|
|
457
525
|
contractSource: c.contractSource
|
|
458
526
|
};
|
|
459
527
|
insertIntoTree(tree, segments, leaf, name);
|
|
460
528
|
}
|
|
461
|
-
void detectCollisions;
|
|
462
529
|
lines.push("export type ApiRouter = {");
|
|
463
|
-
lines.push(...emitRouterTypeBlock(tree, 2));
|
|
530
|
+
lines.push(...emitRouterTypeBlock(tree, 2, outDir ?? ""));
|
|
464
531
|
lines.push("};");
|
|
465
532
|
lines.push("");
|
|
466
533
|
lines.push("export const api = {");
|
|
@@ -557,7 +624,8 @@ __name(emitIndex, "emitIndex");
|
|
|
557
624
|
// src/emit/emit-pages.ts
|
|
558
625
|
var import_promises6 = require("fs/promises");
|
|
559
626
|
var import_node_path6 = require("path");
|
|
560
|
-
async function emitPages(pages, outDir) {
|
|
627
|
+
async function emitPages(pages, outDir, options = {}) {
|
|
628
|
+
const propsExport = options.propsExport ?? "ComponentProps";
|
|
561
629
|
await (0, import_promises6.mkdir)(outDir, {
|
|
562
630
|
recursive: true
|
|
563
631
|
});
|
|
@@ -566,14 +634,40 @@ async function emitPages(pages, outDir) {
|
|
|
566
634
|
const key = needsQuotes(p.name) ? JSON.stringify(p.name) : p.name;
|
|
567
635
|
return ` ${key}: ${propType};`;
|
|
568
636
|
}).join("\n");
|
|
637
|
+
const pageNameUnion = pages.length > 0 ? pages.map((p) => JSON.stringify(p.name)).join(" | ") : "never";
|
|
638
|
+
const augBody = pages.map((p) => {
|
|
639
|
+
const key = needsQuotes(p.name) ? JSON.stringify(p.name) : p.name;
|
|
640
|
+
const valueType = buildAugmentationType(p, outDir, propsExport);
|
|
641
|
+
return ` ${key}: ${valueType};`;
|
|
642
|
+
}).join("\n");
|
|
643
|
+
const propsHelper = "\nexport type InertiaProps<K extends InertiaPageName> = import('@dudousxd/nestjs-inertia').InertiaPages[K];\n";
|
|
569
644
|
const content = `// Generated by @dudousxd/nestjs-inertia-codegen. Do not edit.
|
|
570
645
|
export interface InertiaPages {
|
|
571
646
|
${body}
|
|
572
647
|
}
|
|
648
|
+
|
|
649
|
+
export type InertiaPageName = ${pageNameUnion};
|
|
650
|
+
` + propsHelper + `
|
|
651
|
+
declare module '@dudousxd/nestjs-inertia' {
|
|
652
|
+
interface InertiaPages {
|
|
653
|
+
${augBody}
|
|
654
|
+
}
|
|
655
|
+
}
|
|
573
656
|
`;
|
|
574
657
|
await (0, import_promises6.writeFile)((0, import_node_path6.join)(outDir, "pages.d.ts"), content, "utf8");
|
|
575
658
|
}
|
|
576
659
|
__name(emitPages, "emitPages");
|
|
660
|
+
function buildAugmentationType(page, outDir, propsExport) {
|
|
661
|
+
if (!page.propsSource) {
|
|
662
|
+
return "Record<string, unknown>";
|
|
663
|
+
}
|
|
664
|
+
let importPath = (0, import_node_path6.relative)(outDir, page.absolutePath).replace(/\.(tsx?|vue|svelte)$/, "");
|
|
665
|
+
if (!importPath.startsWith(".")) {
|
|
666
|
+
importPath = `./${importPath}`;
|
|
667
|
+
}
|
|
668
|
+
return `import('${importPath}').${propsExport}`;
|
|
669
|
+
}
|
|
670
|
+
__name(buildAugmentationType, "buildAugmentationType");
|
|
577
671
|
function needsQuotes(name) {
|
|
578
672
|
return !/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name);
|
|
579
673
|
}
|
|
@@ -710,7 +804,9 @@ async function generate(config, routes = []) {
|
|
|
710
804
|
propsExport: config.pages.propsExport,
|
|
711
805
|
componentNameStrategy: config.pages.componentNameStrategy
|
|
712
806
|
});
|
|
713
|
-
await emitPages(pages, config.codegen.outDir
|
|
807
|
+
await emitPages(pages, config.codegen.outDir, {
|
|
808
|
+
propsExport: config.pages.propsExport
|
|
809
|
+
});
|
|
714
810
|
await emitCache(pages, config.codegen.outDir);
|
|
715
811
|
const hasRoutes = routes.length > 0;
|
|
716
812
|
const hasContracts = routes.some((r) => r.contract);
|
|
@@ -725,14 +821,43 @@ async function generate(config, routes = []) {
|
|
|
725
821
|
__name(generate, "generate");
|
|
726
822
|
|
|
727
823
|
// src/watch/watcher.ts
|
|
728
|
-
var
|
|
824
|
+
var import_promises10 = require("fs/promises");
|
|
729
825
|
var import_node_path10 = require("path");
|
|
730
826
|
var import_chokidar = __toESM(require("chokidar"), 1);
|
|
731
827
|
|
|
732
828
|
// src/discovery/contracts-fast.ts
|
|
829
|
+
var import_node_fs = require("fs");
|
|
733
830
|
var import_node_path8 = require("path");
|
|
734
831
|
var import_fast_glob2 = __toESM(require("fast-glob"), 1);
|
|
735
832
|
var import_ts_morph = require("ts-morph");
|
|
833
|
+
var _ctx = {
|
|
834
|
+
projectRoot: "",
|
|
835
|
+
tsconfigPaths: null
|
|
836
|
+
};
|
|
837
|
+
function _projectRoot() {
|
|
838
|
+
return _ctx.projectRoot;
|
|
839
|
+
}
|
|
840
|
+
__name(_projectRoot, "_projectRoot");
|
|
841
|
+
function _tsconfigPaths() {
|
|
842
|
+
return _ctx.tsconfigPaths;
|
|
843
|
+
}
|
|
844
|
+
__name(_tsconfigPaths, "_tsconfigPaths");
|
|
845
|
+
var _debug = process.env.NESTJS_INERTIA_DEBUG === "1";
|
|
846
|
+
function dbg(...args) {
|
|
847
|
+
if (_debug) console.log("[codegen:debug]", ...args);
|
|
848
|
+
}
|
|
849
|
+
__name(dbg, "dbg");
|
|
850
|
+
function loadTsconfigPaths(tsconfigPath) {
|
|
851
|
+
try {
|
|
852
|
+
const raw = (0, import_node_fs.readFileSync)(tsconfigPath, "utf8");
|
|
853
|
+
const stripped = raw.replace(/\/\/.*$/gm, "");
|
|
854
|
+
const parsed = JSON.parse(stripped);
|
|
855
|
+
return parsed.compilerOptions?.paths ?? null;
|
|
856
|
+
} catch {
|
|
857
|
+
return null;
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
__name(loadTsconfigPaths, "loadTsconfigPaths");
|
|
736
861
|
async function discoverContractsFast(opts) {
|
|
737
862
|
const { cwd, glob, tsconfig } = opts;
|
|
738
863
|
const tsconfigPath = tsconfig ? (0, import_node_path8.resolve)(tsconfig) : (0, import_node_path8.join)(cwd, "tsconfig.json");
|
|
@@ -765,8 +890,17 @@ async function discoverContractsFast(opts) {
|
|
|
765
890
|
project.addSourceFileAtPath(f);
|
|
766
891
|
}
|
|
767
892
|
const routes = [];
|
|
768
|
-
|
|
769
|
-
|
|
893
|
+
const prevCtx = _ctx;
|
|
894
|
+
_ctx = {
|
|
895
|
+
projectRoot: cwd,
|
|
896
|
+
tsconfigPaths: loadTsconfigPaths(tsconfigPath)
|
|
897
|
+
};
|
|
898
|
+
try {
|
|
899
|
+
for (const sourceFile of project.getSourceFiles()) {
|
|
900
|
+
routes.push(...extractFromSourceFile(sourceFile, project));
|
|
901
|
+
}
|
|
902
|
+
} finally {
|
|
903
|
+
_ctx = prevCtx;
|
|
770
904
|
}
|
|
771
905
|
return routes;
|
|
772
906
|
}
|
|
@@ -966,17 +1100,42 @@ function findTypeInFile(name, file) {
|
|
|
966
1100
|
return null;
|
|
967
1101
|
}
|
|
968
1102
|
__name(findTypeInFile, "findTypeInFile");
|
|
1103
|
+
function resolveModuleSpecifier(moduleSpecifier, sourceFile, project) {
|
|
1104
|
+
if (moduleSpecifier.startsWith(".")) {
|
|
1105
|
+
const dir = (0, import_node_path8.dirname)(sourceFile.getFilePath());
|
|
1106
|
+
return [
|
|
1107
|
+
(0, import_node_path8.resolve)(dir, `${moduleSpecifier}.ts`),
|
|
1108
|
+
(0, import_node_path8.resolve)(dir, moduleSpecifier, "index.ts")
|
|
1109
|
+
];
|
|
1110
|
+
}
|
|
1111
|
+
const baseUrl = _projectRoot();
|
|
1112
|
+
const tsconfigPaths = _tsconfigPaths();
|
|
1113
|
+
dbg("resolveModuleSpecifier", moduleSpecifier, "paths:", JSON.stringify(tsconfigPaths), "baseUrl:", baseUrl);
|
|
1114
|
+
if (tsconfigPaths) {
|
|
1115
|
+
for (const [pattern, mappings] of Object.entries(tsconfigPaths)) {
|
|
1116
|
+
const prefix = pattern.replace("*", "");
|
|
1117
|
+
if (moduleSpecifier.startsWith(prefix)) {
|
|
1118
|
+
const rest = moduleSpecifier.slice(prefix.length);
|
|
1119
|
+
const candidates = [];
|
|
1120
|
+
for (const mapping of mappings) {
|
|
1121
|
+
const resolved = (0, import_node_path8.resolve)(baseUrl, mapping.replace("*", rest));
|
|
1122
|
+
candidates.push(`${resolved}.ts`, (0, import_node_path8.resolve)(resolved, "index.ts"));
|
|
1123
|
+
}
|
|
1124
|
+
dbg(" resolved candidates:", candidates);
|
|
1125
|
+
return candidates;
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
return [];
|
|
1130
|
+
}
|
|
1131
|
+
__name(resolveModuleSpecifier, "resolveModuleSpecifier");
|
|
969
1132
|
function resolveImportedType(name, sourceFile, project) {
|
|
970
1133
|
for (const importDecl of sourceFile.getImportDeclarations()) {
|
|
971
1134
|
const namedImport = importDecl.getNamedImports().find((n) => n.getName() === name);
|
|
972
1135
|
if (!namedImport) continue;
|
|
973
1136
|
const moduleSpecifier = importDecl.getModuleSpecifierValue();
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
const candidates = [
|
|
977
|
-
(0, import_node_path8.resolve)(dir, `${moduleSpecifier}.ts`),
|
|
978
|
-
(0, import_node_path8.resolve)(dir, moduleSpecifier, "index.ts")
|
|
979
|
-
];
|
|
1137
|
+
const candidates = resolveModuleSpecifier(moduleSpecifier, sourceFile, project);
|
|
1138
|
+
if (candidates.length === 0) continue;
|
|
980
1139
|
for (const candidate of candidates) {
|
|
981
1140
|
let importedFile = project.getSourceFile(candidate);
|
|
982
1141
|
if (!importedFile) {
|
|
@@ -1020,6 +1179,18 @@ function resolveTypeNodeToString(typeNode, sourceFile, project, depth) {
|
|
|
1020
1179
|
}
|
|
1021
1180
|
return "Array<unknown>";
|
|
1022
1181
|
}
|
|
1182
|
+
if ([
|
|
1183
|
+
"Record",
|
|
1184
|
+
"Omit",
|
|
1185
|
+
"Pick",
|
|
1186
|
+
"Partial",
|
|
1187
|
+
"Required",
|
|
1188
|
+
"Readonly",
|
|
1189
|
+
"Map",
|
|
1190
|
+
"Set"
|
|
1191
|
+
].includes(name)) {
|
|
1192
|
+
return typeNode.getText();
|
|
1193
|
+
}
|
|
1023
1194
|
if (name === "Promise") {
|
|
1024
1195
|
const typeArgs = typeNode.getTypeArguments();
|
|
1025
1196
|
const firstTypeArg = typeArgs[0];
|
|
@@ -1032,7 +1203,8 @@ function resolveTypeNodeToString(typeNode, sourceFile, project, depth) {
|
|
|
1032
1203
|
if (resolved) {
|
|
1033
1204
|
return expandTypeDecl(resolved, project, depth - 1);
|
|
1034
1205
|
}
|
|
1035
|
-
|
|
1206
|
+
dbg("unresolvable type:", name, "in", sourceFile.getFilePath());
|
|
1207
|
+
return "unknown";
|
|
1036
1208
|
}
|
|
1037
1209
|
const kind = typeNode.getKind();
|
|
1038
1210
|
if (kind === import_ts_morph.SyntaxKind.StringKeyword) return "string";
|
|
@@ -1194,7 +1366,7 @@ function tryResolveTypeRef(typeNode, sourceFile, project) {
|
|
|
1194
1366
|
return null;
|
|
1195
1367
|
}
|
|
1196
1368
|
const localDecl = sourceFile.getInterface(name) || sourceFile.getClass(name) || sourceFile.getTypeAlias(name);
|
|
1197
|
-
if (localDecl
|
|
1369
|
+
if (localDecl?.isExported()) {
|
|
1198
1370
|
return {
|
|
1199
1371
|
name,
|
|
1200
1372
|
filePath: sourceFile.getFilePath()
|
|
@@ -1256,7 +1428,7 @@ function extractDtoContract(method, sourceFile, project) {
|
|
|
1256
1428
|
if (val && import_ts_morph.Node.isIdentifier(val)) {
|
|
1257
1429
|
const name = val.getText();
|
|
1258
1430
|
const localDecl = sourceFile.getInterface(name) || sourceFile.getClass(name) || sourceFile.getTypeAlias(name);
|
|
1259
|
-
if (localDecl
|
|
1431
|
+
if (localDecl?.isExported()) {
|
|
1260
1432
|
responseRef = {
|
|
1261
1433
|
name,
|
|
1262
1434
|
filePath: sourceFile.getFilePath()
|
|
@@ -1382,6 +1554,11 @@ function extractFromSourceFile(sourceFile, project) {
|
|
|
1382
1554
|
path: combined,
|
|
1383
1555
|
name: routeName,
|
|
1384
1556
|
params,
|
|
1557
|
+
controllerRef: {
|
|
1558
|
+
className,
|
|
1559
|
+
methodName,
|
|
1560
|
+
filePath: sourceFile.getFilePath()
|
|
1561
|
+
},
|
|
1385
1562
|
contract: {
|
|
1386
1563
|
contractSource: {
|
|
1387
1564
|
query: contractDef.query,
|
|
@@ -1416,19 +1593,21 @@ function extractFromSourceFile(sourceFile, project) {
|
|
|
1416
1593
|
path: combined,
|
|
1417
1594
|
name: routeName,
|
|
1418
1595
|
params,
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1596
|
+
controllerRef: {
|
|
1597
|
+
className,
|
|
1598
|
+
methodName,
|
|
1599
|
+
filePath: sourceFile.getFilePath()
|
|
1600
|
+
},
|
|
1601
|
+
contract: {
|
|
1602
|
+
contractSource: {
|
|
1603
|
+
query: dtoContract?.query ?? null,
|
|
1604
|
+
body: dtoContract?.body ?? null,
|
|
1605
|
+
response: dtoContract?.response ?? "unknown",
|
|
1606
|
+
queryRef: dtoContract?.queryRef,
|
|
1607
|
+
bodyRef: dtoContract?.bodyRef,
|
|
1608
|
+
responseRef: dtoContract?.responseRef
|
|
1430
1609
|
}
|
|
1431
|
-
}
|
|
1610
|
+
}
|
|
1432
1611
|
});
|
|
1433
1612
|
}
|
|
1434
1613
|
}
|
|
@@ -1439,6 +1618,7 @@ __name(extractFromSourceFile, "extractFromSourceFile");
|
|
|
1439
1618
|
|
|
1440
1619
|
// src/watch/lock-file.ts
|
|
1441
1620
|
var import_promises8 = require("fs/promises");
|
|
1621
|
+
var import_promises9 = require("fs/promises");
|
|
1442
1622
|
var import_node_path9 = require("path");
|
|
1443
1623
|
var LOCK_FILE = ".watcher.lock";
|
|
1444
1624
|
function isProcessAlive(pid) {
|
|
@@ -1451,28 +1631,37 @@ function isProcessAlive(pid) {
|
|
|
1451
1631
|
}
|
|
1452
1632
|
__name(isProcessAlive, "isProcessAlive");
|
|
1453
1633
|
async function acquireLock(outDir) {
|
|
1454
|
-
await (0,
|
|
1634
|
+
await (0, import_promises9.mkdir)(outDir, {
|
|
1455
1635
|
recursive: true
|
|
1456
1636
|
});
|
|
1457
1637
|
const lockPath = (0, import_node_path9.join)(outDir, LOCK_FILE);
|
|
1458
|
-
try {
|
|
1459
|
-
const raw = await (0, import_promises8.readFile)(lockPath, "utf8");
|
|
1460
|
-
const existing = JSON.parse(raw);
|
|
1461
|
-
if (isProcessAlive(existing.pid)) {
|
|
1462
|
-
return null;
|
|
1463
|
-
}
|
|
1464
|
-
} catch {
|
|
1465
|
-
}
|
|
1466
1638
|
const lockData = {
|
|
1467
1639
|
pid: process.pid,
|
|
1468
1640
|
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1469
1641
|
};
|
|
1470
|
-
|
|
1642
|
+
try {
|
|
1643
|
+
const fd = await (0, import_promises8.open)(lockPath, "wx");
|
|
1644
|
+
await fd.writeFile(`${JSON.stringify(lockData, null, 2)}
|
|
1471
1645
|
`, "utf8");
|
|
1646
|
+
await fd.close();
|
|
1647
|
+
} catch (err) {
|
|
1648
|
+
if (err.code === "EEXIST") {
|
|
1649
|
+
try {
|
|
1650
|
+
const raw = await (0, import_promises9.readFile)(lockPath, "utf8");
|
|
1651
|
+
const existing = JSON.parse(raw);
|
|
1652
|
+
if (isProcessAlive(existing.pid)) return null;
|
|
1653
|
+
await (0, import_promises9.unlink)(lockPath);
|
|
1654
|
+
return acquireLock(outDir);
|
|
1655
|
+
} catch {
|
|
1656
|
+
return null;
|
|
1657
|
+
}
|
|
1658
|
+
}
|
|
1659
|
+
return null;
|
|
1660
|
+
}
|
|
1472
1661
|
return {
|
|
1473
1662
|
release: /* @__PURE__ */ __name(async () => {
|
|
1474
1663
|
try {
|
|
1475
|
-
await (0,
|
|
1664
|
+
await (0, import_promises9.unlink)(lockPath);
|
|
1476
1665
|
} catch {
|
|
1477
1666
|
}
|
|
1478
1667
|
}, "release")
|
|
@@ -1491,7 +1680,7 @@ async function watch(config, onChange) {
|
|
|
1491
1680
|
if (lock === null) {
|
|
1492
1681
|
let holderPid = "unknown";
|
|
1493
1682
|
try {
|
|
1494
|
-
const raw = await (0,
|
|
1683
|
+
const raw = await (0, import_promises10.readFile)((0, import_node_path10.join)(config.codegen.outDir, ".watcher.lock"), "utf8");
|
|
1495
1684
|
const data = JSON.parse(raw);
|
|
1496
1685
|
if (data.pid !== void 0) holderPid = String(data.pid);
|
|
1497
1686
|
} catch {
|
|
@@ -1532,7 +1721,8 @@ async function watch(config, onChange) {
|
|
|
1532
1721
|
pagesDebounceTimer = void 0;
|
|
1533
1722
|
try {
|
|
1534
1723
|
await generate(config);
|
|
1535
|
-
} catch {
|
|
1724
|
+
} catch (err) {
|
|
1725
|
+
console.error("[nestjs-inertia-codegen] Pages generation failed:", err instanceof Error ? err.message : err);
|
|
1536
1726
|
}
|
|
1537
1727
|
onChange?.();
|
|
1538
1728
|
}, PAGES_DEBOUNCE_MS);
|
|
@@ -1570,7 +1760,8 @@ async function watch(config, onChange) {
|
|
|
1570
1760
|
if (hasContracts) {
|
|
1571
1761
|
await emitApi(routes, config.codegen.outDir);
|
|
1572
1762
|
}
|
|
1573
|
-
} catch {
|
|
1763
|
+
} catch (err) {
|
|
1764
|
+
console.error("[nestjs-inertia-codegen] Contracts generation failed:", err instanceof Error ? err.message : err);
|
|
1574
1765
|
}
|
|
1575
1766
|
onChange?.();
|
|
1576
1767
|
}, config.contracts.debounceMs);
|
|
@@ -1598,7 +1789,7 @@ async function watch(config, onChange) {
|
|
|
1598
1789
|
__name(watch, "watch");
|
|
1599
1790
|
|
|
1600
1791
|
// src/index.ts
|
|
1601
|
-
var VERSION = "1.
|
|
1792
|
+
var VERSION = "1.4.0";
|
|
1602
1793
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1603
1794
|
0 && (module.exports = {
|
|
1604
1795
|
CodegenError,
|