@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/cli/main.cjs
CHANGED
|
@@ -248,16 +248,6 @@ function validateNameSegment(seg, fullName) {
|
|
|
248
248
|
}
|
|
249
249
|
}
|
|
250
250
|
__name(validateNameSegment, "validateNameSegment");
|
|
251
|
-
function detectCollisions(tree, name) {
|
|
252
|
-
for (const [key, node] of tree) {
|
|
253
|
-
if (node.kind === "leaf") {
|
|
254
|
-
} else {
|
|
255
|
-
void key;
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
void name;
|
|
259
|
-
}
|
|
260
|
-
__name(detectCollisions, "detectCollisions");
|
|
261
251
|
function insertIntoTree(tree, segments, leaf, fullName) {
|
|
262
252
|
const head = segments[0];
|
|
263
253
|
const rest = segments.slice(1);
|
|
@@ -287,7 +277,30 @@ function insertIntoTree(tree, segments, leaf, fullName) {
|
|
|
287
277
|
}
|
|
288
278
|
}
|
|
289
279
|
__name(insertIntoTree, "insertIntoTree");
|
|
290
|
-
function
|
|
280
|
+
function buildParamsType(params) {
|
|
281
|
+
const pathParams = params.filter((p) => p.source === "path");
|
|
282
|
+
if (pathParams.length === 0) return "never";
|
|
283
|
+
return `{ ${pathParams.map((p) => `${p.name}: string`).join("; ")} }`;
|
|
284
|
+
}
|
|
285
|
+
__name(buildParamsType, "buildParamsType");
|
|
286
|
+
function hasPathParams(params) {
|
|
287
|
+
return params.some((p) => p.source === "path");
|
|
288
|
+
}
|
|
289
|
+
__name(hasPathParams, "hasPathParams");
|
|
290
|
+
function buildResponseType(c, outDir) {
|
|
291
|
+
if (c.controllerRef) {
|
|
292
|
+
let relPath = (0, import_node_path3.relative)(outDir, c.controllerRef.filePath).replace(/\.ts$/, "");
|
|
293
|
+
if (!relPath.startsWith(".")) relPath = `./${relPath}`;
|
|
294
|
+
return `Awaited<ReturnType<import('${relPath}').${c.controllerRef.className}['${c.controllerRef.methodName}']>>`;
|
|
295
|
+
}
|
|
296
|
+
const respRef = c.contractSource.responseRef;
|
|
297
|
+
if (respRef) {
|
|
298
|
+
return respRef.isArray ? `Array<${respRef.name}>` : respRef.name;
|
|
299
|
+
}
|
|
300
|
+
return c.contractSource.response;
|
|
301
|
+
}
|
|
302
|
+
__name(buildResponseType, "buildResponseType");
|
|
303
|
+
function emitRouterTypeBlock(tree, indent, outDir) {
|
|
291
304
|
const pad = " ".repeat(indent);
|
|
292
305
|
const lines = [];
|
|
293
306
|
for (const [key, node] of tree) {
|
|
@@ -299,14 +312,14 @@ function emitRouterTypeBlock(tree, indent) {
|
|
|
299
312
|
const query = queryRef ? queryRef.isArray ? `Array<${queryRef.name}>` : queryRef.name : c.contractSource.query ?? "never";
|
|
300
313
|
const bodyRef = c.contractSource.bodyRef;
|
|
301
314
|
const body = method === "GET" ? "never" : bodyRef ? bodyRef.isArray ? `Array<${bodyRef.name}>` : bodyRef.name : c.contractSource.body ?? "never";
|
|
302
|
-
const
|
|
303
|
-
const
|
|
315
|
+
const response = buildResponseType(c, outDir);
|
|
316
|
+
const params = buildParamsType(c.params);
|
|
304
317
|
const safeMethod = JSON.stringify(method);
|
|
305
318
|
const safeUrl = JSON.stringify(c.path);
|
|
306
|
-
lines.push(`${pad}${objKey}: { method: ${safeMethod}; url: ${safeUrl}; query: ${query}; body: ${body}; response: ${response} };`);
|
|
319
|
+
lines.push(`${pad}${objKey}: { method: ${safeMethod}; url: ${safeUrl}; params: ${params}; query: ${query}; body: ${body}; response: ${response} };`);
|
|
307
320
|
} else {
|
|
308
321
|
lines.push(`${pad}${objKey}: {`);
|
|
309
|
-
lines.push(...emitRouterTypeBlock(node.children, indent + 2));
|
|
322
|
+
lines.push(...emitRouterTypeBlock(node.children, indent + 2, outDir));
|
|
310
323
|
lines.push(`${pad}};`);
|
|
311
324
|
}
|
|
312
325
|
}
|
|
@@ -326,20 +339,61 @@ function emitApiObjectBlock(tree, indent) {
|
|
|
326
339
|
const fetcherMethod = method.toLowerCase();
|
|
327
340
|
if (method === "GET") {
|
|
328
341
|
const typeAccess = buildRouterTypeAccess(c.name);
|
|
342
|
+
const withParams = hasPathParams(c.params);
|
|
329
343
|
lines.push(`${pad}${objKey}: {`);
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
344
|
+
if (withParams) {
|
|
345
|
+
lines.push(`${pad} queryKey: (params: ${typeAccess}['params'], query?: ${typeAccess}['query']) => query !== undefined ? [${flatName}, params, query] as const : [${flatName}, params] as const,`);
|
|
346
|
+
lines.push(`${pad} queryOptions: (params: ${typeAccess}['params'], query?: ${typeAccess}['query']) =>`);
|
|
347
|
+
lines.push(`${pad} _queryOptions({`);
|
|
348
|
+
lines.push(`${pad} queryKey: query !== undefined ? [${flatName}, params, query] as const : [${flatName}, params] as const,`);
|
|
349
|
+
lines.push(`${pad} queryFn: () => fetcher.get<${typeAccess}['response']>(route(${flatName} as never, params as never) || ${safePath}, { query }),`);
|
|
350
|
+
lines.push(`${pad} }),`);
|
|
351
|
+
lines.push(`${pad} infiniteQueryOptions: (params: ${typeAccess}['params'], query?: ${typeAccess}['query']) => ({`);
|
|
352
|
+
lines.push(`${pad} queryKey: query !== undefined ? [${flatName}, params, query] as const : [${flatName}, params] as const,`);
|
|
353
|
+
lines.push(`${pad} queryFn: ({ pageParam }: { pageParam: number }) => fetcher.get<${typeAccess}['response']>(route(${flatName} as never, params as never) || ${safePath}, { query: { ...query, page: pageParam } }),`);
|
|
354
|
+
lines.push(`${pad} initialPageParam: 1,`);
|
|
355
|
+
lines.push(`${pad} getNextPageParam: (lastPage: ${typeAccess}['response']) => {`);
|
|
356
|
+
lines.push(`${pad} const meta = (lastPage as any)?.meta;`);
|
|
357
|
+
lines.push(`${pad} if (meta?.page != null && meta?.lastPage != null) {`);
|
|
358
|
+
lines.push(`${pad} return meta.page < meta.lastPage ? meta.page + 1 : undefined;`);
|
|
359
|
+
lines.push(`${pad} }`);
|
|
360
|
+
lines.push(`${pad} return undefined;`);
|
|
361
|
+
lines.push(`${pad} },`);
|
|
362
|
+
lines.push(`${pad} }),`);
|
|
363
|
+
} else {
|
|
364
|
+
lines.push(`${pad} queryKey: (query?: ${typeAccess}['query']) => query !== undefined ? [${flatName}, query] as const : [${flatName}] as const,`);
|
|
365
|
+
lines.push(`${pad} queryOptions: (query?: ${typeAccess}['query']) =>`);
|
|
366
|
+
lines.push(`${pad} _queryOptions({`);
|
|
367
|
+
lines.push(`${pad} queryKey: query !== undefined ? [${flatName}, query] as const : [${flatName}] as const,`);
|
|
368
|
+
lines.push(`${pad} queryFn: () => fetcher.get<${typeAccess}['response']>(route(${flatName} as never) || ${safePath}, { query }),`);
|
|
369
|
+
lines.push(`${pad} }),`);
|
|
370
|
+
lines.push(`${pad} infiniteQueryOptions: (query?: ${typeAccess}['query']) => ({`);
|
|
371
|
+
lines.push(`${pad} queryKey: query !== undefined ? [${flatName}, query] as const : [${flatName}] as const,`);
|
|
372
|
+
lines.push(`${pad} queryFn: ({ pageParam }: { pageParam: number }) => fetcher.get<${typeAccess}['response']>(route(${flatName} as never) || ${safePath}, { query: { ...query, page: pageParam } }),`);
|
|
373
|
+
lines.push(`${pad} initialPageParam: 1,`);
|
|
374
|
+
lines.push(`${pad} getNextPageParam: (lastPage: ${typeAccess}['response']) => {`);
|
|
375
|
+
lines.push(`${pad} const meta = (lastPage as any)?.meta;`);
|
|
376
|
+
lines.push(`${pad} if (meta?.page != null && meta?.lastPage != null) {`);
|
|
377
|
+
lines.push(`${pad} return meta.page < meta.lastPage ? meta.page + 1 : undefined;`);
|
|
378
|
+
lines.push(`${pad} }`);
|
|
379
|
+
lines.push(`${pad} return undefined;`);
|
|
380
|
+
lines.push(`${pad} },`);
|
|
381
|
+
lines.push(`${pad} }),`);
|
|
382
|
+
}
|
|
335
383
|
lines.push(`${pad}},`);
|
|
336
384
|
} else {
|
|
337
385
|
const typeAccess = buildRouterTypeAccess(c.name);
|
|
386
|
+
const withParams = hasPathParams(c.params);
|
|
338
387
|
lines.push(`${pad}${objKey}: {`);
|
|
339
388
|
lines.push(`${pad} queryKey: () => [${flatName}] as const,`);
|
|
340
|
-
lines.push(`${pad} mutationOptions: ()
|
|
341
|
-
lines.push(`${pad}
|
|
342
|
-
|
|
389
|
+
lines.push(`${pad} mutationOptions: () =>`);
|
|
390
|
+
lines.push(`${pad} _mutationOptions({`);
|
|
391
|
+
if (withParams) {
|
|
392
|
+
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 }),`);
|
|
393
|
+
} else {
|
|
394
|
+
lines.push(`${pad} mutationFn: (body: ${typeAccess}['body']) => fetcher.${fetcherMethod}<${typeAccess}['response']>(route(${flatName} as never) || ${safePath}, { body }),`);
|
|
395
|
+
}
|
|
396
|
+
lines.push(`${pad} }),`);
|
|
343
397
|
lines.push(`${pad}},`);
|
|
344
398
|
}
|
|
345
399
|
} else {
|
|
@@ -362,11 +416,15 @@ function buildApiFile(routes, outDir) {
|
|
|
362
416
|
for (const r of contracted) {
|
|
363
417
|
const cs = r.contract?.contractSource;
|
|
364
418
|
if (!cs) continue;
|
|
365
|
-
|
|
419
|
+
const refs = r.controllerRef ? [
|
|
420
|
+
cs.queryRef,
|
|
421
|
+
cs.bodyRef
|
|
422
|
+
] : [
|
|
366
423
|
cs.queryRef,
|
|
367
424
|
cs.bodyRef,
|
|
368
425
|
cs.responseRef
|
|
369
|
-
]
|
|
426
|
+
];
|
|
427
|
+
for (const ref of refs) {
|
|
370
428
|
if (!ref) continue;
|
|
371
429
|
let names = importsByFile.get(ref.filePath);
|
|
372
430
|
if (!names) {
|
|
@@ -376,10 +434,18 @@ function buildApiFile(routes, outDir) {
|
|
|
376
434
|
names.add(ref.name);
|
|
377
435
|
}
|
|
378
436
|
}
|
|
437
|
+
const hasGetRoutes = contracted.some((r) => r.method === "GET");
|
|
438
|
+
const hasMutationRoutes = contracted.some((r) => r.method !== "GET");
|
|
379
439
|
const lines = [
|
|
380
440
|
"// Generated by @dudousxd/nestjs-inertia-codegen. Do not edit.",
|
|
381
441
|
""
|
|
382
442
|
];
|
|
443
|
+
const tqImports = [];
|
|
444
|
+
if (hasGetRoutes) tqImports.push("queryOptions as _queryOptions");
|
|
445
|
+
if (hasMutationRoutes) tqImports.push("mutationOptions as _mutationOptions");
|
|
446
|
+
if (tqImports.length > 0) {
|
|
447
|
+
lines.push(`import { ${tqImports.join(", ")} } from '@tanstack/react-query';`);
|
|
448
|
+
}
|
|
383
449
|
lines.push("import { route } from './routes.js';");
|
|
384
450
|
lines.push("import { createFetcher } from '@dudousxd/nestjs-inertia-client';");
|
|
385
451
|
if (importsByFile.size > 0 && outDir) {
|
|
@@ -433,13 +499,14 @@ function buildApiFile(routes, outDir) {
|
|
|
433
499
|
method: r.method,
|
|
434
500
|
name,
|
|
435
501
|
path: r.path,
|
|
502
|
+
params: r.params,
|
|
503
|
+
controllerRef: r.controllerRef,
|
|
436
504
|
contractSource: c.contractSource
|
|
437
505
|
};
|
|
438
506
|
insertIntoTree(tree, segments, leaf, name);
|
|
439
507
|
}
|
|
440
|
-
void detectCollisions;
|
|
441
508
|
lines.push("export type ApiRouter = {");
|
|
442
|
-
lines.push(...emitRouterTypeBlock(tree, 2));
|
|
509
|
+
lines.push(...emitRouterTypeBlock(tree, 2, outDir ?? ""));
|
|
443
510
|
lines.push("};");
|
|
444
511
|
lines.push("");
|
|
445
512
|
lines.push("export const api = {");
|
|
@@ -536,7 +603,8 @@ __name(emitIndex, "emitIndex");
|
|
|
536
603
|
// src/emit/emit-pages.ts
|
|
537
604
|
var import_promises6 = require("fs/promises");
|
|
538
605
|
var import_node_path6 = require("path");
|
|
539
|
-
async function emitPages(pages, outDir) {
|
|
606
|
+
async function emitPages(pages, outDir, options = {}) {
|
|
607
|
+
const propsExport = options.propsExport ?? "ComponentProps";
|
|
540
608
|
await (0, import_promises6.mkdir)(outDir, {
|
|
541
609
|
recursive: true
|
|
542
610
|
});
|
|
@@ -545,14 +613,40 @@ async function emitPages(pages, outDir) {
|
|
|
545
613
|
const key = needsQuotes(p.name) ? JSON.stringify(p.name) : p.name;
|
|
546
614
|
return ` ${key}: ${propType};`;
|
|
547
615
|
}).join("\n");
|
|
616
|
+
const pageNameUnion = pages.length > 0 ? pages.map((p) => JSON.stringify(p.name)).join(" | ") : "never";
|
|
617
|
+
const augBody = pages.map((p) => {
|
|
618
|
+
const key = needsQuotes(p.name) ? JSON.stringify(p.name) : p.name;
|
|
619
|
+
const valueType = buildAugmentationType(p, outDir, propsExport);
|
|
620
|
+
return ` ${key}: ${valueType};`;
|
|
621
|
+
}).join("\n");
|
|
622
|
+
const propsHelper = "\nexport type InertiaProps<K extends InertiaPageName> = import('@dudousxd/nestjs-inertia').InertiaPages[K];\n";
|
|
548
623
|
const content = `// Generated by @dudousxd/nestjs-inertia-codegen. Do not edit.
|
|
549
624
|
export interface InertiaPages {
|
|
550
625
|
${body}
|
|
551
626
|
}
|
|
627
|
+
|
|
628
|
+
export type InertiaPageName = ${pageNameUnion};
|
|
629
|
+
` + propsHelper + `
|
|
630
|
+
declare module '@dudousxd/nestjs-inertia' {
|
|
631
|
+
interface InertiaPages {
|
|
632
|
+
${augBody}
|
|
633
|
+
}
|
|
634
|
+
}
|
|
552
635
|
`;
|
|
553
636
|
await (0, import_promises6.writeFile)((0, import_node_path6.join)(outDir, "pages.d.ts"), content, "utf8");
|
|
554
637
|
}
|
|
555
638
|
__name(emitPages, "emitPages");
|
|
639
|
+
function buildAugmentationType(page, outDir, propsExport) {
|
|
640
|
+
if (!page.propsSource) {
|
|
641
|
+
return "Record<string, unknown>";
|
|
642
|
+
}
|
|
643
|
+
let importPath = (0, import_node_path6.relative)(outDir, page.absolutePath).replace(/\.(tsx?|vue|svelte)$/, "");
|
|
644
|
+
if (!importPath.startsWith(".")) {
|
|
645
|
+
importPath = `./${importPath}`;
|
|
646
|
+
}
|
|
647
|
+
return `import('${importPath}').${propsExport}`;
|
|
648
|
+
}
|
|
649
|
+
__name(buildAugmentationType, "buildAugmentationType");
|
|
556
650
|
function needsQuotes(name) {
|
|
557
651
|
return !/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name);
|
|
558
652
|
}
|
|
@@ -689,7 +783,9 @@ async function generate(config, routes = []) {
|
|
|
689
783
|
propsExport: config.pages.propsExport,
|
|
690
784
|
componentNameStrategy: config.pages.componentNameStrategy
|
|
691
785
|
});
|
|
692
|
-
await emitPages(pages, config.codegen.outDir
|
|
786
|
+
await emitPages(pages, config.codegen.outDir, {
|
|
787
|
+
propsExport: config.pages.propsExport
|
|
788
|
+
});
|
|
693
789
|
await emitCache(pages, config.codegen.outDir);
|
|
694
790
|
const hasRoutes = routes.length > 0;
|
|
695
791
|
const hasContracts = routes.some((r) => r.contract);
|
|
@@ -704,14 +800,43 @@ async function generate(config, routes = []) {
|
|
|
704
800
|
__name(generate, "generate");
|
|
705
801
|
|
|
706
802
|
// src/watch/watcher.ts
|
|
707
|
-
var
|
|
803
|
+
var import_promises10 = require("fs/promises");
|
|
708
804
|
var import_node_path10 = require("path");
|
|
709
805
|
var import_chokidar = __toESM(require("chokidar"), 1);
|
|
710
806
|
|
|
711
807
|
// src/discovery/contracts-fast.ts
|
|
808
|
+
var import_node_fs = require("fs");
|
|
712
809
|
var import_node_path8 = require("path");
|
|
713
810
|
var import_fast_glob2 = __toESM(require("fast-glob"), 1);
|
|
714
811
|
var import_ts_morph = require("ts-morph");
|
|
812
|
+
var _ctx = {
|
|
813
|
+
projectRoot: "",
|
|
814
|
+
tsconfigPaths: null
|
|
815
|
+
};
|
|
816
|
+
function _projectRoot() {
|
|
817
|
+
return _ctx.projectRoot;
|
|
818
|
+
}
|
|
819
|
+
__name(_projectRoot, "_projectRoot");
|
|
820
|
+
function _tsconfigPaths() {
|
|
821
|
+
return _ctx.tsconfigPaths;
|
|
822
|
+
}
|
|
823
|
+
__name(_tsconfigPaths, "_tsconfigPaths");
|
|
824
|
+
var _debug = process.env.NESTJS_INERTIA_DEBUG === "1";
|
|
825
|
+
function dbg(...args) {
|
|
826
|
+
if (_debug) console.log("[codegen:debug]", ...args);
|
|
827
|
+
}
|
|
828
|
+
__name(dbg, "dbg");
|
|
829
|
+
function loadTsconfigPaths(tsconfigPath) {
|
|
830
|
+
try {
|
|
831
|
+
const raw = (0, import_node_fs.readFileSync)(tsconfigPath, "utf8");
|
|
832
|
+
const stripped = raw.replace(/\/\/.*$/gm, "");
|
|
833
|
+
const parsed = JSON.parse(stripped);
|
|
834
|
+
return parsed.compilerOptions?.paths ?? null;
|
|
835
|
+
} catch {
|
|
836
|
+
return null;
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
__name(loadTsconfigPaths, "loadTsconfigPaths");
|
|
715
840
|
async function discoverContractsFast(opts) {
|
|
716
841
|
const { cwd, glob, tsconfig } = opts;
|
|
717
842
|
const tsconfigPath = tsconfig ? (0, import_node_path8.resolve)(tsconfig) : (0, import_node_path8.join)(cwd, "tsconfig.json");
|
|
@@ -744,8 +869,17 @@ async function discoverContractsFast(opts) {
|
|
|
744
869
|
project.addSourceFileAtPath(f);
|
|
745
870
|
}
|
|
746
871
|
const routes = [];
|
|
747
|
-
|
|
748
|
-
|
|
872
|
+
const prevCtx = _ctx;
|
|
873
|
+
_ctx = {
|
|
874
|
+
projectRoot: cwd,
|
|
875
|
+
tsconfigPaths: loadTsconfigPaths(tsconfigPath)
|
|
876
|
+
};
|
|
877
|
+
try {
|
|
878
|
+
for (const sourceFile of project.getSourceFiles()) {
|
|
879
|
+
routes.push(...extractFromSourceFile(sourceFile, project));
|
|
880
|
+
}
|
|
881
|
+
} finally {
|
|
882
|
+
_ctx = prevCtx;
|
|
749
883
|
}
|
|
750
884
|
return routes;
|
|
751
885
|
}
|
|
@@ -945,17 +1079,42 @@ function findTypeInFile(name, file) {
|
|
|
945
1079
|
return null;
|
|
946
1080
|
}
|
|
947
1081
|
__name(findTypeInFile, "findTypeInFile");
|
|
1082
|
+
function resolveModuleSpecifier(moduleSpecifier, sourceFile, project) {
|
|
1083
|
+
if (moduleSpecifier.startsWith(".")) {
|
|
1084
|
+
const dir = (0, import_node_path8.dirname)(sourceFile.getFilePath());
|
|
1085
|
+
return [
|
|
1086
|
+
(0, import_node_path8.resolve)(dir, `${moduleSpecifier}.ts`),
|
|
1087
|
+
(0, import_node_path8.resolve)(dir, moduleSpecifier, "index.ts")
|
|
1088
|
+
];
|
|
1089
|
+
}
|
|
1090
|
+
const baseUrl = _projectRoot();
|
|
1091
|
+
const tsconfigPaths = _tsconfigPaths();
|
|
1092
|
+
dbg("resolveModuleSpecifier", moduleSpecifier, "paths:", JSON.stringify(tsconfigPaths), "baseUrl:", baseUrl);
|
|
1093
|
+
if (tsconfigPaths) {
|
|
1094
|
+
for (const [pattern, mappings] of Object.entries(tsconfigPaths)) {
|
|
1095
|
+
const prefix = pattern.replace("*", "");
|
|
1096
|
+
if (moduleSpecifier.startsWith(prefix)) {
|
|
1097
|
+
const rest = moduleSpecifier.slice(prefix.length);
|
|
1098
|
+
const candidates = [];
|
|
1099
|
+
for (const mapping of mappings) {
|
|
1100
|
+
const resolved = (0, import_node_path8.resolve)(baseUrl, mapping.replace("*", rest));
|
|
1101
|
+
candidates.push(`${resolved}.ts`, (0, import_node_path8.resolve)(resolved, "index.ts"));
|
|
1102
|
+
}
|
|
1103
|
+
dbg(" resolved candidates:", candidates);
|
|
1104
|
+
return candidates;
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
return [];
|
|
1109
|
+
}
|
|
1110
|
+
__name(resolveModuleSpecifier, "resolveModuleSpecifier");
|
|
948
1111
|
function resolveImportedType(name, sourceFile, project) {
|
|
949
1112
|
for (const importDecl of sourceFile.getImportDeclarations()) {
|
|
950
1113
|
const namedImport = importDecl.getNamedImports().find((n) => n.getName() === name);
|
|
951
1114
|
if (!namedImport) continue;
|
|
952
1115
|
const moduleSpecifier = importDecl.getModuleSpecifierValue();
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
const candidates = [
|
|
956
|
-
(0, import_node_path8.resolve)(dir, `${moduleSpecifier}.ts`),
|
|
957
|
-
(0, import_node_path8.resolve)(dir, moduleSpecifier, "index.ts")
|
|
958
|
-
];
|
|
1116
|
+
const candidates = resolveModuleSpecifier(moduleSpecifier, sourceFile, project);
|
|
1117
|
+
if (candidates.length === 0) continue;
|
|
959
1118
|
for (const candidate of candidates) {
|
|
960
1119
|
let importedFile = project.getSourceFile(candidate);
|
|
961
1120
|
if (!importedFile) {
|
|
@@ -999,6 +1158,18 @@ function resolveTypeNodeToString(typeNode, sourceFile, project, depth) {
|
|
|
999
1158
|
}
|
|
1000
1159
|
return "Array<unknown>";
|
|
1001
1160
|
}
|
|
1161
|
+
if ([
|
|
1162
|
+
"Record",
|
|
1163
|
+
"Omit",
|
|
1164
|
+
"Pick",
|
|
1165
|
+
"Partial",
|
|
1166
|
+
"Required",
|
|
1167
|
+
"Readonly",
|
|
1168
|
+
"Map",
|
|
1169
|
+
"Set"
|
|
1170
|
+
].includes(name)) {
|
|
1171
|
+
return typeNode.getText();
|
|
1172
|
+
}
|
|
1002
1173
|
if (name === "Promise") {
|
|
1003
1174
|
const typeArgs = typeNode.getTypeArguments();
|
|
1004
1175
|
const firstTypeArg = typeArgs[0];
|
|
@@ -1011,7 +1182,8 @@ function resolveTypeNodeToString(typeNode, sourceFile, project, depth) {
|
|
|
1011
1182
|
if (resolved) {
|
|
1012
1183
|
return expandTypeDecl(resolved, project, depth - 1);
|
|
1013
1184
|
}
|
|
1014
|
-
|
|
1185
|
+
dbg("unresolvable type:", name, "in", sourceFile.getFilePath());
|
|
1186
|
+
return "unknown";
|
|
1015
1187
|
}
|
|
1016
1188
|
const kind = typeNode.getKind();
|
|
1017
1189
|
if (kind === import_ts_morph.SyntaxKind.StringKeyword) return "string";
|
|
@@ -1173,7 +1345,7 @@ function tryResolveTypeRef(typeNode, sourceFile, project) {
|
|
|
1173
1345
|
return null;
|
|
1174
1346
|
}
|
|
1175
1347
|
const localDecl = sourceFile.getInterface(name) || sourceFile.getClass(name) || sourceFile.getTypeAlias(name);
|
|
1176
|
-
if (localDecl
|
|
1348
|
+
if (localDecl?.isExported()) {
|
|
1177
1349
|
return {
|
|
1178
1350
|
name,
|
|
1179
1351
|
filePath: sourceFile.getFilePath()
|
|
@@ -1235,7 +1407,7 @@ function extractDtoContract(method, sourceFile, project) {
|
|
|
1235
1407
|
if (val && import_ts_morph.Node.isIdentifier(val)) {
|
|
1236
1408
|
const name = val.getText();
|
|
1237
1409
|
const localDecl = sourceFile.getInterface(name) || sourceFile.getClass(name) || sourceFile.getTypeAlias(name);
|
|
1238
|
-
if (localDecl
|
|
1410
|
+
if (localDecl?.isExported()) {
|
|
1239
1411
|
responseRef = {
|
|
1240
1412
|
name,
|
|
1241
1413
|
filePath: sourceFile.getFilePath()
|
|
@@ -1361,6 +1533,11 @@ function extractFromSourceFile(sourceFile, project) {
|
|
|
1361
1533
|
path: combined,
|
|
1362
1534
|
name: routeName,
|
|
1363
1535
|
params,
|
|
1536
|
+
controllerRef: {
|
|
1537
|
+
className,
|
|
1538
|
+
methodName,
|
|
1539
|
+
filePath: sourceFile.getFilePath()
|
|
1540
|
+
},
|
|
1364
1541
|
contract: {
|
|
1365
1542
|
contractSource: {
|
|
1366
1543
|
query: contractDef.query,
|
|
@@ -1395,19 +1572,21 @@ function extractFromSourceFile(sourceFile, project) {
|
|
|
1395
1572
|
path: combined,
|
|
1396
1573
|
name: routeName,
|
|
1397
1574
|
params,
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1575
|
+
controllerRef: {
|
|
1576
|
+
className,
|
|
1577
|
+
methodName,
|
|
1578
|
+
filePath: sourceFile.getFilePath()
|
|
1579
|
+
},
|
|
1580
|
+
contract: {
|
|
1581
|
+
contractSource: {
|
|
1582
|
+
query: dtoContract?.query ?? null,
|
|
1583
|
+
body: dtoContract?.body ?? null,
|
|
1584
|
+
response: dtoContract?.response ?? "unknown",
|
|
1585
|
+
queryRef: dtoContract?.queryRef,
|
|
1586
|
+
bodyRef: dtoContract?.bodyRef,
|
|
1587
|
+
responseRef: dtoContract?.responseRef
|
|
1409
1588
|
}
|
|
1410
|
-
}
|
|
1589
|
+
}
|
|
1411
1590
|
});
|
|
1412
1591
|
}
|
|
1413
1592
|
}
|
|
@@ -1418,6 +1597,7 @@ __name(extractFromSourceFile, "extractFromSourceFile");
|
|
|
1418
1597
|
|
|
1419
1598
|
// src/watch/lock-file.ts
|
|
1420
1599
|
var import_promises8 = require("fs/promises");
|
|
1600
|
+
var import_promises9 = require("fs/promises");
|
|
1421
1601
|
var import_node_path9 = require("path");
|
|
1422
1602
|
var LOCK_FILE = ".watcher.lock";
|
|
1423
1603
|
function isProcessAlive(pid) {
|
|
@@ -1430,28 +1610,37 @@ function isProcessAlive(pid) {
|
|
|
1430
1610
|
}
|
|
1431
1611
|
__name(isProcessAlive, "isProcessAlive");
|
|
1432
1612
|
async function acquireLock(outDir) {
|
|
1433
|
-
await (0,
|
|
1613
|
+
await (0, import_promises9.mkdir)(outDir, {
|
|
1434
1614
|
recursive: true
|
|
1435
1615
|
});
|
|
1436
1616
|
const lockPath = (0, import_node_path9.join)(outDir, LOCK_FILE);
|
|
1437
|
-
try {
|
|
1438
|
-
const raw = await (0, import_promises8.readFile)(lockPath, "utf8");
|
|
1439
|
-
const existing = JSON.parse(raw);
|
|
1440
|
-
if (isProcessAlive(existing.pid)) {
|
|
1441
|
-
return null;
|
|
1442
|
-
}
|
|
1443
|
-
} catch {
|
|
1444
|
-
}
|
|
1445
1617
|
const lockData = {
|
|
1446
1618
|
pid: process.pid,
|
|
1447
1619
|
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1448
1620
|
};
|
|
1449
|
-
|
|
1621
|
+
try {
|
|
1622
|
+
const fd = await (0, import_promises8.open)(lockPath, "wx");
|
|
1623
|
+
await fd.writeFile(`${JSON.stringify(lockData, null, 2)}
|
|
1450
1624
|
`, "utf8");
|
|
1625
|
+
await fd.close();
|
|
1626
|
+
} catch (err) {
|
|
1627
|
+
if (err.code === "EEXIST") {
|
|
1628
|
+
try {
|
|
1629
|
+
const raw = await (0, import_promises9.readFile)(lockPath, "utf8");
|
|
1630
|
+
const existing = JSON.parse(raw);
|
|
1631
|
+
if (isProcessAlive(existing.pid)) return null;
|
|
1632
|
+
await (0, import_promises9.unlink)(lockPath);
|
|
1633
|
+
return acquireLock(outDir);
|
|
1634
|
+
} catch {
|
|
1635
|
+
return null;
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1638
|
+
return null;
|
|
1639
|
+
}
|
|
1451
1640
|
return {
|
|
1452
1641
|
release: /* @__PURE__ */ __name(async () => {
|
|
1453
1642
|
try {
|
|
1454
|
-
await (0,
|
|
1643
|
+
await (0, import_promises9.unlink)(lockPath);
|
|
1455
1644
|
} catch {
|
|
1456
1645
|
}
|
|
1457
1646
|
}, "release")
|
|
@@ -1470,7 +1659,7 @@ async function watch(config, onChange) {
|
|
|
1470
1659
|
if (lock === null) {
|
|
1471
1660
|
let holderPid = "unknown";
|
|
1472
1661
|
try {
|
|
1473
|
-
const raw = await (0,
|
|
1662
|
+
const raw = await (0, import_promises10.readFile)((0, import_node_path10.join)(config.codegen.outDir, ".watcher.lock"), "utf8");
|
|
1474
1663
|
const data = JSON.parse(raw);
|
|
1475
1664
|
if (data.pid !== void 0) holderPid = String(data.pid);
|
|
1476
1665
|
} catch {
|
|
@@ -1511,7 +1700,8 @@ async function watch(config, onChange) {
|
|
|
1511
1700
|
pagesDebounceTimer = void 0;
|
|
1512
1701
|
try {
|
|
1513
1702
|
await generate(config);
|
|
1514
|
-
} catch {
|
|
1703
|
+
} catch (err) {
|
|
1704
|
+
console.error("[nestjs-inertia-codegen] Pages generation failed:", err instanceof Error ? err.message : err);
|
|
1515
1705
|
}
|
|
1516
1706
|
onChange?.();
|
|
1517
1707
|
}, PAGES_DEBOUNCE_MS);
|
|
@@ -1549,7 +1739,8 @@ async function watch(config, onChange) {
|
|
|
1549
1739
|
if (hasContracts) {
|
|
1550
1740
|
await emitApi(routes, config.codegen.outDir);
|
|
1551
1741
|
}
|
|
1552
|
-
} catch {
|
|
1742
|
+
} catch (err) {
|
|
1743
|
+
console.error("[nestjs-inertia-codegen] Contracts generation failed:", err instanceof Error ? err.message : err);
|
|
1553
1744
|
}
|
|
1554
1745
|
onChange?.();
|
|
1555
1746
|
}, config.contracts.debounceMs);
|
|
@@ -1577,7 +1768,7 @@ async function watch(config, onChange) {
|
|
|
1577
1768
|
__name(watch, "watch");
|
|
1578
1769
|
|
|
1579
1770
|
// src/index.ts
|
|
1580
|
-
var VERSION = "1.
|
|
1771
|
+
var VERSION = "1.4.0";
|
|
1581
1772
|
|
|
1582
1773
|
// src/cli/codegen.ts
|
|
1583
1774
|
async function runCodegen(opts = {}) {
|
|
@@ -1607,11 +1798,163 @@ async function runCodegen(opts = {}) {
|
|
|
1607
1798
|
}
|
|
1608
1799
|
__name(runCodegen, "runCodegen");
|
|
1609
1800
|
|
|
1801
|
+
// src/cli/doctor.ts
|
|
1802
|
+
var import_node_fs2 = require("fs");
|
|
1803
|
+
var import_node_path11 = require("path");
|
|
1804
|
+
function checkFileExists(cwd, file) {
|
|
1805
|
+
return (0, import_node_fs2.existsSync)((0, import_node_path11.join)(cwd, file));
|
|
1806
|
+
}
|
|
1807
|
+
__name(checkFileExists, "checkFileExists");
|
|
1808
|
+
function readJson(path) {
|
|
1809
|
+
try {
|
|
1810
|
+
const raw = (0, import_node_fs2.readFileSync)(path, "utf8").replace(/\/\/.*$/gm, "");
|
|
1811
|
+
return JSON.parse(raw);
|
|
1812
|
+
} catch {
|
|
1813
|
+
return null;
|
|
1814
|
+
}
|
|
1815
|
+
}
|
|
1816
|
+
__name(readJson, "readJson");
|
|
1817
|
+
function getPackageVersion(cwd, pkg) {
|
|
1818
|
+
try {
|
|
1819
|
+
const pkgJson = readJson((0, import_node_path11.join)(cwd, "node_modules", pkg, "package.json"));
|
|
1820
|
+
return pkgJson?.version ?? null;
|
|
1821
|
+
} catch {
|
|
1822
|
+
return null;
|
|
1823
|
+
}
|
|
1824
|
+
}
|
|
1825
|
+
__name(getPackageVersion, "getPackageVersion");
|
|
1826
|
+
async function runDoctor(opts) {
|
|
1827
|
+
const { cwd } = opts;
|
|
1828
|
+
const checks = [];
|
|
1829
|
+
checks.push({
|
|
1830
|
+
name: "nestjs-inertia.config.ts exists",
|
|
1831
|
+
pass: checkFileExists(cwd, "nestjs-inertia.config.ts"),
|
|
1832
|
+
fix: "Run: pnpm exec nestjs-inertia init"
|
|
1833
|
+
});
|
|
1834
|
+
const hasApi = checkFileExists(cwd, ".nestjs-inertia/api.ts");
|
|
1835
|
+
const hasRoutes = checkFileExists(cwd, ".nestjs-inertia/routes.ts");
|
|
1836
|
+
const hasPages = checkFileExists(cwd, ".nestjs-inertia/pages.d.ts");
|
|
1837
|
+
checks.push({
|
|
1838
|
+
name: ".nestjs-inertia/ codegen output exists",
|
|
1839
|
+
pass: hasApi && hasRoutes && hasPages,
|
|
1840
|
+
fix: "Run: pnpm exec nestjs-inertia codegen"
|
|
1841
|
+
});
|
|
1842
|
+
const tsconfig = readJson((0, import_node_path11.join)(cwd, "tsconfig.json"));
|
|
1843
|
+
const paths = tsconfig?.compilerOptions?.paths;
|
|
1844
|
+
checks.push({
|
|
1845
|
+
name: "tsconfig.json has @/* path alias",
|
|
1846
|
+
pass: !!paths?.["@/*"],
|
|
1847
|
+
fix: 'Add to tsconfig.json compilerOptions.paths: { "@/*": ["./src/*"] }'
|
|
1848
|
+
});
|
|
1849
|
+
const inertiaTsconfig = readJson((0, import_node_path11.join)(cwd, "tsconfig.inertia.json"));
|
|
1850
|
+
if (inertiaTsconfig) {
|
|
1851
|
+
const inertiaPaths = inertiaTsconfig.compilerOptions?.paths;
|
|
1852
|
+
checks.push({
|
|
1853
|
+
name: "tsconfig.inertia.json has ~/* and ~codegen/* aliases",
|
|
1854
|
+
pass: !!inertiaPaths?.["~/*"] && !!inertiaPaths?.["~codegen/*"],
|
|
1855
|
+
fix: 'Add paths: { "~/*": ["inertia/*"], "~codegen/*": [".nestjs-inertia/*"] }'
|
|
1856
|
+
});
|
|
1857
|
+
}
|
|
1858
|
+
if (checkFileExists(cwd, "vite.config.ts")) {
|
|
1859
|
+
const viteContent = (0, import_node_fs2.readFileSync)((0, import_node_path11.join)(cwd, "vite.config.ts"), "utf8");
|
|
1860
|
+
checks.push({
|
|
1861
|
+
name: "vite.config.ts has resolve.alias",
|
|
1862
|
+
pass: viteContent.includes("resolve") && viteContent.includes("alias"),
|
|
1863
|
+
fix: "Add resolve.alias with @\u2192src, ~\u2192inertia, ~codegen\u2192.nestjs-inertia"
|
|
1864
|
+
});
|
|
1865
|
+
checks.push({
|
|
1866
|
+
name: "vite.config.ts references nestjs-inertia",
|
|
1867
|
+
pass: viteContent.includes("nestInertia") || viteContent.includes("nestjs-inertia") || viteContent.includes("setupInertiaVite"),
|
|
1868
|
+
fix: "Add: import nestInertia from '@dudousxd/nestjs-inertia-vite/plugin'"
|
|
1869
|
+
});
|
|
1870
|
+
}
|
|
1871
|
+
const libPackages = [
|
|
1872
|
+
"@dudousxd/nestjs-inertia",
|
|
1873
|
+
"@dudousxd/nestjs-inertia-codegen",
|
|
1874
|
+
"@dudousxd/nestjs-inertia-client",
|
|
1875
|
+
"@dudousxd/nestjs-inertia-vite",
|
|
1876
|
+
"@dudousxd/nestjs-inertia-testing"
|
|
1877
|
+
];
|
|
1878
|
+
const versions = libPackages.map((pkg) => ({
|
|
1879
|
+
pkg,
|
|
1880
|
+
version: getPackageVersion(cwd, pkg)
|
|
1881
|
+
}));
|
|
1882
|
+
const installed = versions.filter((v) => v.version !== null);
|
|
1883
|
+
const uniqueVersions = new Set(installed.map((v) => v.version));
|
|
1884
|
+
const requiredPkgs = [
|
|
1885
|
+
"@dudousxd/nestjs-inertia",
|
|
1886
|
+
"@dudousxd/nestjs-inertia-codegen",
|
|
1887
|
+
"@dudousxd/nestjs-inertia-client"
|
|
1888
|
+
];
|
|
1889
|
+
const missingRequired = requiredPkgs.filter((pkg) => !getPackageVersion(cwd, pkg));
|
|
1890
|
+
checks.push({
|
|
1891
|
+
name: "Core packages installed (core + codegen + client)",
|
|
1892
|
+
pass: missingRequired.length === 0,
|
|
1893
|
+
fix: missingRequired.length > 0 ? `Missing: ${missingRequired.join(", ")}` : void 0
|
|
1894
|
+
});
|
|
1895
|
+
if (installed.length > 1) {
|
|
1896
|
+
checks.push({
|
|
1897
|
+
name: "All packages on same version",
|
|
1898
|
+
pass: uniqueVersions.size === 1,
|
|
1899
|
+
fix: `Versions: ${installed.map((v) => `${v.pkg.replace("@dudousxd/", "")}@${v.version}`).join(", ")}`
|
|
1900
|
+
});
|
|
1901
|
+
}
|
|
1902
|
+
const inertiaReact = getPackageVersion(cwd, "@inertiajs/react");
|
|
1903
|
+
const inertiaVue = getPackageVersion(cwd, "@inertiajs/vue3");
|
|
1904
|
+
const inertiaSvelte = getPackageVersion(cwd, "@inertiajs/svelte");
|
|
1905
|
+
const inertiaVersion = inertiaReact ?? inertiaVue ?? inertiaSvelte;
|
|
1906
|
+
const inertiaFramework = inertiaReact ? "react" : inertiaVue ? "vue" : inertiaSvelte ? "svelte" : null;
|
|
1907
|
+
if (inertiaVersion) {
|
|
1908
|
+
const majorVersion = Number.parseInt(inertiaVersion.split(".")[0] ?? "0", 10);
|
|
1909
|
+
checks.push({
|
|
1910
|
+
name: `@inertiajs/${inertiaFramework} is v3+`,
|
|
1911
|
+
pass: majorVersion >= 3,
|
|
1912
|
+
fix: `Current: v${inertiaVersion}. Run: pnpm add @inertiajs/${inertiaFramework}@^3.0.0`
|
|
1913
|
+
});
|
|
1914
|
+
}
|
|
1915
|
+
if (checkFileExists(cwd, ".gitignore")) {
|
|
1916
|
+
const gitignore = (0, import_node_fs2.readFileSync)((0, import_node_path11.join)(cwd, ".gitignore"), "utf8");
|
|
1917
|
+
checks.push({
|
|
1918
|
+
name: ".gitignore includes .nestjs-inertia/",
|
|
1919
|
+
pass: gitignore.includes(".nestjs-inertia"),
|
|
1920
|
+
fix: "Add .nestjs-inertia/ to .gitignore"
|
|
1921
|
+
});
|
|
1922
|
+
}
|
|
1923
|
+
const pkgJson = readJson((0, import_node_path11.join)(cwd, "package.json"));
|
|
1924
|
+
const scripts = pkgJson?.scripts ?? {};
|
|
1925
|
+
checks.push({
|
|
1926
|
+
name: "package.json has build:client script",
|
|
1927
|
+
pass: !!scripts["build:client"],
|
|
1928
|
+
fix: 'Add: "build:client": "vite build"'
|
|
1929
|
+
});
|
|
1930
|
+
console.log("");
|
|
1931
|
+
console.log("\x1B[1mnestjs-inertia doctor\x1B[0m");
|
|
1932
|
+
console.log("");
|
|
1933
|
+
let hasFailures = false;
|
|
1934
|
+
for (const check of checks) {
|
|
1935
|
+
const icon = check.pass ? "\x1B[32m\u2713\x1B[0m" : "\x1B[31m\u2717\x1B[0m";
|
|
1936
|
+
console.log(` ${icon} ${check.name}`);
|
|
1937
|
+
if (!check.pass && check.fix) {
|
|
1938
|
+
console.log(` \x1B[2m${check.fix}\x1B[0m`);
|
|
1939
|
+
hasFailures = true;
|
|
1940
|
+
}
|
|
1941
|
+
}
|
|
1942
|
+
console.log("");
|
|
1943
|
+
if (hasFailures) {
|
|
1944
|
+
console.log(`\x1B[33m${checks.filter((c) => !c.pass).length} issue(s) found\x1B[0m`);
|
|
1945
|
+
} else {
|
|
1946
|
+
console.log("\x1B[32mAll checks passed!\x1B[0m");
|
|
1947
|
+
}
|
|
1948
|
+
console.log("");
|
|
1949
|
+
return hasFailures ? 1 : 0;
|
|
1950
|
+
}
|
|
1951
|
+
__name(runDoctor, "runDoctor");
|
|
1952
|
+
|
|
1610
1953
|
// src/cli/init.ts
|
|
1611
1954
|
var import_node_child_process = require("child_process");
|
|
1612
|
-
var
|
|
1613
|
-
var
|
|
1614
|
-
var
|
|
1955
|
+
var import_node_fs3 = require("fs");
|
|
1956
|
+
var import_promises11 = require("fs/promises");
|
|
1957
|
+
var import_node_path12 = require("path");
|
|
1615
1958
|
var import_node_readline = require("readline");
|
|
1616
1959
|
var GITIGNORE_ENTRY = ".nestjs-inertia/";
|
|
1617
1960
|
var green = /* @__PURE__ */ __name((s) => `\x1B[32m${s}\x1B[0m`, "green");
|
|
@@ -1642,7 +1985,7 @@ ${bold(title)}`);
|
|
|
1642
1985
|
__name(logSection, "logSection");
|
|
1643
1986
|
async function readPackageJson(cwd) {
|
|
1644
1987
|
try {
|
|
1645
|
-
const raw = await (0,
|
|
1988
|
+
const raw = await (0, import_promises11.readFile)((0, import_node_path12.join)(cwd, "package.json"), "utf8");
|
|
1646
1989
|
return JSON.parse(raw);
|
|
1647
1990
|
} catch {
|
|
1648
1991
|
return {};
|
|
@@ -1680,7 +2023,7 @@ __name(detectTemplateEngine, "detectTemplateEngine");
|
|
|
1680
2023
|
async function detectPackageManager(cwd) {
|
|
1681
2024
|
async function exists(file) {
|
|
1682
2025
|
try {
|
|
1683
|
-
await (0,
|
|
2026
|
+
await (0, import_promises11.access)((0, import_node_path12.join)(cwd, file));
|
|
1684
2027
|
return true;
|
|
1685
2028
|
} catch {
|
|
1686
2029
|
return false;
|
|
@@ -1711,7 +2054,7 @@ async function promptFramework() {
|
|
|
1711
2054
|
__name(promptFramework, "promptFramework");
|
|
1712
2055
|
async function fileExists2(filePath) {
|
|
1713
2056
|
try {
|
|
1714
|
-
await (0,
|
|
2057
|
+
await (0, import_promises11.access)(filePath);
|
|
1715
2058
|
return true;
|
|
1716
2059
|
} catch {
|
|
1717
2060
|
return false;
|
|
@@ -1725,18 +2068,18 @@ async function writeIfNotExists(filePath, content, label) {
|
|
|
1725
2068
|
}
|
|
1726
2069
|
const dir = filePath.substring(0, filePath.lastIndexOf("/"));
|
|
1727
2070
|
if (dir) {
|
|
1728
|
-
await (0,
|
|
2071
|
+
await (0, import_promises11.mkdir)(dir, {
|
|
1729
2072
|
recursive: true
|
|
1730
2073
|
});
|
|
1731
2074
|
}
|
|
1732
|
-
await (0,
|
|
2075
|
+
await (0, import_promises11.writeFile)(filePath, content, "utf8");
|
|
1733
2076
|
logCreated(label);
|
|
1734
2077
|
}
|
|
1735
2078
|
__name(writeIfNotExists, "writeIfNotExists");
|
|
1736
2079
|
async function handleViteConfig(cwd, framework) {
|
|
1737
|
-
const filePath = (0,
|
|
2080
|
+
const filePath = (0, import_node_path12.join)(cwd, "vite.config.ts");
|
|
1738
2081
|
if (await fileExists2(filePath)) {
|
|
1739
|
-
const existing = await (0,
|
|
2082
|
+
const existing = await (0, import_promises11.readFile)(filePath, "utf8");
|
|
1740
2083
|
const hasPlugin = existing.includes("nestInertia") || existing.includes("nestjs-inertia-vite/plugin");
|
|
1741
2084
|
if (!hasPlugin) {
|
|
1742
2085
|
logSkipped("vite.config.ts");
|
|
@@ -1750,18 +2093,18 @@ async function handleViteConfig(cwd, framework) {
|
|
|
1750
2093
|
}
|
|
1751
2094
|
const dir = filePath.substring(0, filePath.lastIndexOf("/"));
|
|
1752
2095
|
if (dir) {
|
|
1753
|
-
await (0,
|
|
2096
|
+
await (0, import_promises11.mkdir)(dir, {
|
|
1754
2097
|
recursive: true
|
|
1755
2098
|
});
|
|
1756
2099
|
}
|
|
1757
|
-
await (0,
|
|
2100
|
+
await (0, import_promises11.writeFile)(filePath, viteConfigTemplate(framework), "utf8");
|
|
1758
2101
|
logCreated("vite.config.ts");
|
|
1759
2102
|
}
|
|
1760
2103
|
__name(handleViteConfig, "handleViteConfig");
|
|
1761
2104
|
async function patchGitignore(gitignorePath) {
|
|
1762
2105
|
let existing = "";
|
|
1763
2106
|
if (await fileExists2(gitignorePath)) {
|
|
1764
|
-
existing = await (0,
|
|
2107
|
+
existing = await (0, import_promises11.readFile)(gitignorePath, "utf8");
|
|
1765
2108
|
}
|
|
1766
2109
|
if (existing.split("\n").some((line) => line.trim() === GITIGNORE_ENTRY)) {
|
|
1767
2110
|
console.log(` ${cyan("\u2192")} .gitignore ${dim("(already contains .nestjs-inertia/, skipped)")}`);
|
|
@@ -1771,30 +2114,36 @@ async function patchGitignore(gitignorePath) {
|
|
|
1771
2114
|
` : `${existing}
|
|
1772
2115
|
${GITIGNORE_ENTRY}
|
|
1773
2116
|
`;
|
|
1774
|
-
await (0,
|
|
2117
|
+
await (0, import_promises11.writeFile)(gitignorePath, newContent, "utf8");
|
|
1775
2118
|
logPatched(".gitignore", "added .nestjs-inertia/");
|
|
1776
2119
|
}
|
|
1777
2120
|
__name(patchGitignore, "patchGitignore");
|
|
1778
2121
|
function installDeps(pkgManager, deps, dev) {
|
|
1779
2122
|
if (deps.length === 0) return;
|
|
1780
|
-
const
|
|
1781
|
-
|
|
2123
|
+
const args = [];
|
|
2124
|
+
if (pkgManager === "npm") {
|
|
2125
|
+
args.push("install");
|
|
2126
|
+
if (dev) args.push("--save-dev");
|
|
2127
|
+
} else {
|
|
2128
|
+
args.push("add");
|
|
2129
|
+
if (dev) args.push("-D");
|
|
2130
|
+
}
|
|
2131
|
+
args.push(...deps);
|
|
1782
2132
|
logPatched(deps.join(", "), "installed");
|
|
1783
2133
|
try {
|
|
1784
|
-
(0, import_node_child_process.
|
|
2134
|
+
(0, import_node_child_process.execFileSync)(pkgManager, args, {
|
|
1785
2135
|
stdio: "inherit"
|
|
1786
2136
|
});
|
|
1787
2137
|
} catch {
|
|
1788
|
-
logWarning(`Failed to install deps.
|
|
1789
|
-
${cmd}`);
|
|
2138
|
+
logWarning(`Failed to install: ${deps.join(", ")}`);
|
|
1790
2139
|
}
|
|
1791
2140
|
}
|
|
1792
2141
|
__name(installDeps, "installDeps");
|
|
1793
2142
|
async function patchPackageJsonScripts(cwd, scripts) {
|
|
1794
|
-
const pkgPath = (0,
|
|
2143
|
+
const pkgPath = (0, import_node_path12.join)(cwd, "package.json");
|
|
1795
2144
|
let pkg = {};
|
|
1796
2145
|
try {
|
|
1797
|
-
pkg = JSON.parse(await (0,
|
|
2146
|
+
pkg = JSON.parse(await (0, import_promises11.readFile)(pkgPath, "utf8"));
|
|
1798
2147
|
} catch {
|
|
1799
2148
|
return;
|
|
1800
2149
|
}
|
|
@@ -1813,7 +2162,7 @@ async function patchPackageJsonScripts(cwd, scripts) {
|
|
|
1813
2162
|
return;
|
|
1814
2163
|
}
|
|
1815
2164
|
pkg.scripts = existing;
|
|
1816
|
-
await (0,
|
|
2165
|
+
await (0, import_promises11.writeFile)(pkgPath, `${JSON.stringify(pkg, null, 2)}
|
|
1817
2166
|
`, "utf8");
|
|
1818
2167
|
}
|
|
1819
2168
|
__name(patchPackageJsonScripts, "patchPackageJsonScripts");
|
|
@@ -1833,7 +2182,7 @@ __name(findAfterLastImport, "findAfterLastImport");
|
|
|
1833
2182
|
function patchAppModule(filePath, rootView) {
|
|
1834
2183
|
let content;
|
|
1835
2184
|
try {
|
|
1836
|
-
content = (0,
|
|
2185
|
+
content = (0, import_node_fs3.readFileSync)(filePath, "utf8");
|
|
1837
2186
|
} catch {
|
|
1838
2187
|
return "skipped";
|
|
1839
2188
|
}
|
|
@@ -1871,14 +2220,14 @@ ${indent}HomeController,${content.slice(bracketPos)}`;
|
|
|
1871
2220
|
}
|
|
1872
2221
|
}
|
|
1873
2222
|
if (!changed) return "already";
|
|
1874
|
-
(0,
|
|
2223
|
+
(0, import_node_fs3.writeFileSync)(filePath, content, "utf8");
|
|
1875
2224
|
return "patched";
|
|
1876
2225
|
}
|
|
1877
2226
|
__name(patchAppModule, "patchAppModule");
|
|
1878
2227
|
function patchMainTs(filePath) {
|
|
1879
2228
|
let content;
|
|
1880
2229
|
try {
|
|
1881
|
-
content = (0,
|
|
2230
|
+
content = (0, import_node_fs3.readFileSync)(filePath, "utf8");
|
|
1882
2231
|
} catch {
|
|
1883
2232
|
return "skipped";
|
|
1884
2233
|
}
|
|
@@ -1902,7 +2251,7 @@ ${content.slice(insertAt)}`;
|
|
|
1902
2251
|
});`;
|
|
1903
2252
|
content = `${content.slice(0, insertAfterPos)}
|
|
1904
2253
|
${viteSetup}${content.slice(insertAfterPos)}`;
|
|
1905
|
-
(0,
|
|
2254
|
+
(0, import_node_fs3.writeFileSync)(filePath, content, "utf8");
|
|
1906
2255
|
return "patched";
|
|
1907
2256
|
}
|
|
1908
2257
|
__name(patchMainTs, "patchMainTs");
|
|
@@ -1951,11 +2300,19 @@ function htmlShellTemplate(framework, _engine) {
|
|
|
1951
2300
|
__name(htmlShellTemplate, "htmlShellTemplate");
|
|
1952
2301
|
function viteConfigTemplate(framework) {
|
|
1953
2302
|
const pluginOption = `{ ${framework}: true }`;
|
|
1954
|
-
return `import {
|
|
2303
|
+
return `import { resolve } from 'node:path';
|
|
2304
|
+
import { defineConfig } from 'vite';
|
|
1955
2305
|
import nestInertia from '@dudousxd/nestjs-inertia-vite/plugin';
|
|
1956
2306
|
|
|
1957
2307
|
export default defineConfig({
|
|
1958
2308
|
plugins: [nestInertia(${pluginOption})],
|
|
2309
|
+
resolve: {
|
|
2310
|
+
alias: {
|
|
2311
|
+
'@': resolve(__dirname, 'src'),
|
|
2312
|
+
'~': resolve(__dirname, 'inertia'),
|
|
2313
|
+
'~codegen': resolve(__dirname, '.nestjs-inertia'),
|
|
2314
|
+
},
|
|
2315
|
+
},
|
|
1959
2316
|
});
|
|
1960
2317
|
`;
|
|
1961
2318
|
}
|
|
@@ -2075,16 +2432,16 @@ ${bold("nestjs-inertia init")}`);
|
|
|
2075
2432
|
const entryExt = framework === "react" ? "tsx" : "ts";
|
|
2076
2433
|
const pageExt = framework === "react" ? "tsx" : framework === "vue" ? "vue" : "svelte";
|
|
2077
2434
|
logSection("Scaffold files");
|
|
2078
|
-
await writeIfNotExists((0,
|
|
2079
|
-
await writeIfNotExists((0,
|
|
2080
|
-
await writeIfNotExists((0,
|
|
2435
|
+
await writeIfNotExists((0, import_node_path12.join)(cwd, "nestjs-inertia.config.ts"), configTemplate(framework), "nestjs-inertia.config.ts");
|
|
2436
|
+
await writeIfNotExists((0, import_node_path12.join)(cwd, "nestjs-inertia.d.ts"), DTS_TEMPLATE, "nestjs-inertia.d.ts");
|
|
2437
|
+
await writeIfNotExists((0, import_node_path12.join)(cwd, "inertia", shellFileName), htmlShellTemplate(framework, engine), `inertia/${shellFileName}`);
|
|
2081
2438
|
await handleViteConfig(cwd, framework);
|
|
2082
|
-
await writeIfNotExists((0,
|
|
2083
|
-
await writeIfNotExists((0,
|
|
2084
|
-
await writeIfNotExists((0,
|
|
2439
|
+
await writeIfNotExists((0, import_node_path12.join)(cwd, "inertia", `app.${entryExt}`), entryPointTemplate(framework), `inertia/app.${entryExt}`);
|
|
2440
|
+
await writeIfNotExists((0, import_node_path12.join)(cwd, "inertia", "pages", `Home.${pageExt}`), samplePageTemplate(framework), `inertia/pages/Home.${pageExt}`);
|
|
2441
|
+
await writeIfNotExists((0, import_node_path12.join)(cwd, "src", "home.controller.ts"), SAMPLE_CONTROLLER, "src/home.controller.ts");
|
|
2085
2442
|
logSection("Patch existing files");
|
|
2086
2443
|
const rootView = engine === "html" ? "inertia/index.html" : `inertia/index.${engine === "handlebars" ? "hbs" : engine}`;
|
|
2087
|
-
const appModulePath = (0,
|
|
2444
|
+
const appModulePath = (0, import_node_path12.join)(cwd, "src", "app.module.ts");
|
|
2088
2445
|
const appModuleResult = patchAppModule(appModulePath, rootView);
|
|
2089
2446
|
if (appModuleResult === "patched") {
|
|
2090
2447
|
logPatched("src/app.module.ts", "added InertiaModule.forRoot");
|
|
@@ -2094,7 +2451,7 @@ ${bold("nestjs-inertia init")}`);
|
|
|
2094
2451
|
} else {
|
|
2095
2452
|
logWarning("src/app.module.ts not found \u2014 add InertiaModule.forRoot() manually");
|
|
2096
2453
|
}
|
|
2097
|
-
const mainTsPath = (0,
|
|
2454
|
+
const mainTsPath = (0, import_node_path12.join)(cwd, "src", "main.ts");
|
|
2098
2455
|
const mainTsResult = patchMainTs(mainTsPath);
|
|
2099
2456
|
if (mainTsResult === "patched") {
|
|
2100
2457
|
logPatched("src/main.ts", "added setupInertiaVite after NestFactory.create");
|
|
@@ -2103,7 +2460,7 @@ ${bold("nestjs-inertia init")}`);
|
|
|
2103
2460
|
} else {
|
|
2104
2461
|
logWarning("src/main.ts not found \u2014 add setupInertiaVite() manually");
|
|
2105
2462
|
}
|
|
2106
|
-
await patchGitignore((0,
|
|
2463
|
+
await patchGitignore((0, import_node_path12.join)(cwd, ".gitignore"));
|
|
2107
2464
|
await patchPackageJsonScripts(cwd, {
|
|
2108
2465
|
"build:client": "vite build",
|
|
2109
2466
|
"build:ssr": "VITE_SSR=1 vite build --ssr"
|
|
@@ -2180,6 +2537,12 @@ async function run(argv) {
|
|
|
2180
2537
|
cwd: process.cwd()
|
|
2181
2538
|
});
|
|
2182
2539
|
});
|
|
2540
|
+
cli.command("doctor", "Diagnose your nestjs-inertia setup").action(async () => {
|
|
2541
|
+
const code = await runDoctor({
|
|
2542
|
+
cwd: process.cwd()
|
|
2543
|
+
});
|
|
2544
|
+
process.exitCode = code;
|
|
2545
|
+
});
|
|
2183
2546
|
cli.help();
|
|
2184
2547
|
cli.version(VERSION);
|
|
2185
2548
|
try {
|