@dudousxd/nestjs-codegen 0.28.0 → 0.29.1
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 +16 -0
- package/README.md +10 -8
- package/dist/cli/main.cjs +705 -429
- package/dist/cli/main.cjs.map +1 -1
- package/dist/cli/main.js +856 -575
- package/dist/cli/main.js.map +1 -1
- package/dist/index.cjs +889 -562
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +27 -14
- package/dist/index.d.ts +27 -14
- package/dist/index.js +1057 -725
- package/dist/index.js.map +1 -1
- package/dist/nest/index.cjs +553 -277
- package/dist/nest/index.cjs.map +1 -1
- package/dist/nest/index.js +363 -82
- package/dist/nest/index.js.map +1 -1
- package/package.json +4 -3
- package/skills/codegen-setup/SKILL.md +5 -1
package/dist/cli/main.cjs
CHANGED
|
@@ -281,7 +281,7 @@ async function discoverPages(opts) {
|
|
|
281
281
|
const rel = (0, import_node_path2.relative)(opts.cwd, file);
|
|
282
282
|
const nameRel = (0, import_node_path2.relative)(pagesBase, file).split(import_node_path2.sep).join("/");
|
|
283
283
|
const name = `${prefix}${computeName(nameRel, opts.componentNameStrategy)}`;
|
|
284
|
-
const source = await (0, import_promises2.readFile)(file, "utf8");
|
|
284
|
+
const source = await (opts.read ? opts.read(file) : (0, import_promises2.readFile)(file, "utf8"));
|
|
285
285
|
const propsSource = extractPropsSource(source, opts.propsExport);
|
|
286
286
|
out.push({ name, absolutePath: file, relativePath: rel, propsSource, scope });
|
|
287
287
|
}
|
|
@@ -289,10 +289,14 @@ async function discoverPages(opts) {
|
|
|
289
289
|
assertUniqueNames(out);
|
|
290
290
|
return out;
|
|
291
291
|
}
|
|
292
|
-
async function discoverPageScopes(config) {
|
|
292
|
+
async function discoverPageScopes(config, read) {
|
|
293
293
|
const pages = config.pages;
|
|
294
294
|
if (!pages) return [];
|
|
295
|
-
const common = {
|
|
295
|
+
const common = {
|
|
296
|
+
cwd: config.codegen.cwd,
|
|
297
|
+
propsExport: pages.propsExport,
|
|
298
|
+
...read ? { read } : {}
|
|
299
|
+
};
|
|
296
300
|
const out = await discoverPages({
|
|
297
301
|
...common,
|
|
298
302
|
glob: pages.glob,
|
|
@@ -363,297 +367,60 @@ function extractPropsSource(source, exportName) {
|
|
|
363
367
|
}
|
|
364
368
|
|
|
365
369
|
// src/discovery/shared-props.ts
|
|
366
|
-
var
|
|
367
|
-
var
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
370
|
+
var import_node_fs3 = require("fs");
|
|
371
|
+
var import_node_path5 = require("path");
|
|
372
|
+
var import_ts_morph13 = require("ts-morph");
|
|
373
|
+
|
|
374
|
+
// src/discovery/contracts-fast.ts
|
|
375
|
+
var import_node_fs2 = require("fs");
|
|
376
|
+
var import_node_path4 = require("path");
|
|
377
|
+
var import_fast_glob2 = __toESM(require("fast-glob"), 1);
|
|
378
|
+
var import_ts_morph12 = require("ts-morph");
|
|
379
|
+
|
|
380
|
+
// src/discovery/disk-fingerprints.ts
|
|
381
|
+
var import_node_fs = require("fs");
|
|
382
|
+
var DiskFingerprints = class {
|
|
383
|
+
stats = /* @__PURE__ */ new Map();
|
|
384
|
+
/** The paths whose disk content differs from `text`, or that no longer exist. */
|
|
385
|
+
changed(files) {
|
|
386
|
+
const changed = [];
|
|
387
|
+
for (const { path, text } of files) {
|
|
388
|
+
let key;
|
|
372
389
|
try {
|
|
373
|
-
|
|
390
|
+
const stat2 = (0, import_node_fs.statSync)(path);
|
|
391
|
+
key = `${stat2.mtimeMs}:${stat2.size}`;
|
|
374
392
|
} catch {
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
const forRootCall = findForRootCall(sourceFile);
|
|
379
|
-
if (!forRootCall) return null;
|
|
380
|
-
const initializer = findShareInitializer(forRootCall);
|
|
381
|
-
if (!initializer) return null;
|
|
382
|
-
return extractShareType(initializer, sourceFile, project);
|
|
383
|
-
} catch {
|
|
384
|
-
return null;
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
function discoverSharedPropsFromConfig(config) {
|
|
388
|
-
if (!config.app?.moduleEntry) return null;
|
|
389
|
-
try {
|
|
390
|
-
const tsconfigPath = config.app.tsconfig ?? (0, import_node_path3.join)(config.codegen.cwd, "tsconfig.json");
|
|
391
|
-
let project;
|
|
392
|
-
try {
|
|
393
|
-
project = new import_ts_morph.Project({
|
|
394
|
-
tsConfigFilePath: tsconfigPath,
|
|
395
|
-
skipAddingFilesFromTsConfig: true,
|
|
396
|
-
skipLoadingLibFiles: true,
|
|
397
|
-
skipFileDependencyResolution: true
|
|
398
|
-
});
|
|
399
|
-
} catch {
|
|
400
|
-
project = new import_ts_morph.Project({
|
|
401
|
-
skipAddingFilesFromTsConfig: true,
|
|
402
|
-
skipLoadingLibFiles: true,
|
|
403
|
-
skipFileDependencyResolution: true,
|
|
404
|
-
compilerOptions: { allowJs: true, strict: false }
|
|
405
|
-
});
|
|
406
|
-
}
|
|
407
|
-
return discoverSharedProps(project, config.app.moduleEntry);
|
|
408
|
-
} catch {
|
|
409
|
-
return null;
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
function findForRootCall(sourceFile) {
|
|
413
|
-
const callExpressions = sourceFile.getDescendantsOfKind(import_ts_morph.SyntaxKind.CallExpression);
|
|
414
|
-
for (const call of callExpressions) {
|
|
415
|
-
const expr = call.getExpression();
|
|
416
|
-
if (!import_ts_morph.Node.isPropertyAccessExpression(expr)) continue;
|
|
417
|
-
const methodName = expr.getName();
|
|
418
|
-
const objectExpr = expr.getExpression();
|
|
419
|
-
if (methodName === "forRoot" && import_ts_morph.Node.isIdentifier(objectExpr)) {
|
|
420
|
-
const name = objectExpr.getText();
|
|
421
|
-
if (name === "InertiaModule") {
|
|
422
|
-
return call;
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
return null;
|
|
427
|
-
}
|
|
428
|
-
function findShareInitializer(forRootCall) {
|
|
429
|
-
if (!import_ts_morph.Node.isCallExpression(forRootCall)) return null;
|
|
430
|
-
const args = forRootCall.getArguments();
|
|
431
|
-
const firstArg2 = args[0];
|
|
432
|
-
if (!firstArg2 || !import_ts_morph.Node.isObjectLiteralExpression(firstArg2)) return null;
|
|
433
|
-
for (const prop of firstArg2.getProperties()) {
|
|
434
|
-
if (import_ts_morph.Node.isPropertyAssignment(prop) && prop.getName() === "share") {
|
|
435
|
-
return prop.getInitializer() ?? null;
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
return null;
|
|
439
|
-
}
|
|
440
|
-
function extractShareType(node, sourceFile, project) {
|
|
441
|
-
if (import_ts_morph.Node.isIdentifier(node)) {
|
|
442
|
-
const ref = resolveIdentifierToImportRef(node, sourceFile, project);
|
|
443
|
-
if (ref) {
|
|
444
|
-
return {
|
|
445
|
-
typeString: `Awaited<ReturnType<typeof import('${ref.importPath}').${ref.exportName}>>`,
|
|
446
|
-
properties: null,
|
|
447
|
-
isImportRef: true
|
|
448
|
-
};
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
if (import_ts_morph.Node.isArrowFunction(node)) {
|
|
452
|
-
const result = extractFromFunctionLike(node, sourceFile);
|
|
453
|
-
return result ? { ...result, isImportRef: false } : null;
|
|
454
|
-
}
|
|
455
|
-
if (import_ts_morph.Node.isFunctionExpression(node)) {
|
|
456
|
-
const result = extractFromFunctionLike(node, sourceFile);
|
|
457
|
-
return result ? { ...result, isImportRef: false } : null;
|
|
458
|
-
}
|
|
459
|
-
if (import_ts_morph.Node.isObjectLiteralExpression(node)) {
|
|
460
|
-
const result = extractFromObjectLiteral(node);
|
|
461
|
-
return result ? { ...result, isImportRef: false } : null;
|
|
462
|
-
}
|
|
463
|
-
return null;
|
|
464
|
-
}
|
|
465
|
-
function resolveIdentifierToImportRef(id, sourceFile, project) {
|
|
466
|
-
if (!import_ts_morph.Node.isIdentifier(id)) return null;
|
|
467
|
-
const name = id.getText();
|
|
468
|
-
const localFunc = sourceFile.getFunction(name);
|
|
469
|
-
if (localFunc?.isExported()) {
|
|
470
|
-
const filePath = sourceFile.getFilePath().replace(/\.ts$/, "");
|
|
471
|
-
return { importPath: filePath, exportName: name };
|
|
472
|
-
}
|
|
473
|
-
const localVar = sourceFile.getVariableDeclaration(name);
|
|
474
|
-
if (localVar?.isExported()) {
|
|
475
|
-
const filePath = sourceFile.getFilePath().replace(/\.ts$/, "");
|
|
476
|
-
return { importPath: filePath, exportName: name };
|
|
477
|
-
}
|
|
478
|
-
for (const imp of sourceFile.getImportDeclarations()) {
|
|
479
|
-
for (const named of imp.getNamedImports()) {
|
|
480
|
-
const importedName = named.getAliasNode()?.getText() ?? named.getName();
|
|
481
|
-
if (importedName !== name) continue;
|
|
482
|
-
const resolvedSource = imp.getModuleSpecifierSourceFile();
|
|
483
|
-
if (!resolvedSource) continue;
|
|
484
|
-
const originalName = named.getName();
|
|
485
|
-
const fn = resolvedSource.getFunction(originalName);
|
|
486
|
-
if (fn?.isExported()) {
|
|
487
|
-
const filePath = resolvedSource.getFilePath().replace(/\.ts$/, "");
|
|
488
|
-
return { importPath: filePath, exportName: originalName };
|
|
489
|
-
}
|
|
490
|
-
const v = resolvedSource.getVariableDeclaration(originalName);
|
|
491
|
-
if (v?.isExported()) {
|
|
492
|
-
const filePath = resolvedSource.getFilePath().replace(/\.ts$/, "");
|
|
493
|
-
return { importPath: filePath, exportName: originalName };
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
return null;
|
|
498
|
-
}
|
|
499
|
-
function extractFromFunctionLike(node, _sourceFile) {
|
|
500
|
-
const returnTypeNode = import_ts_morph.Node.isArrowFunction(node) || import_ts_morph.Node.isFunctionExpression(node) ? node.getReturnTypeNode() : null;
|
|
501
|
-
if (returnTypeNode) {
|
|
502
|
-
return extractFromReturnTypeAnnotation(returnTypeNode);
|
|
503
|
-
}
|
|
504
|
-
if (import_ts_morph.Node.isArrowFunction(node)) {
|
|
505
|
-
const body = node.getBody();
|
|
506
|
-
if (import_ts_morph.Node.isParenthesizedExpression(body)) {
|
|
507
|
-
const inner = body.getExpression();
|
|
508
|
-
if (import_ts_morph.Node.isObjectLiteralExpression(inner)) {
|
|
509
|
-
return extractFromObjectLiteral(inner);
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
if (import_ts_morph.Node.isObjectLiteralExpression(body)) {
|
|
513
|
-
return extractFromObjectLiteral(body);
|
|
514
|
-
}
|
|
515
|
-
if (import_ts_morph.Node.isBlock(body)) {
|
|
516
|
-
return extractFromBlockReturn(body);
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
if (import_ts_morph.Node.isFunctionExpression(node)) {
|
|
520
|
-
const body = node.getBody();
|
|
521
|
-
if (import_ts_morph.Node.isBlock(body)) {
|
|
522
|
-
return extractFromBlockReturn(body);
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
return null;
|
|
526
|
-
}
|
|
527
|
-
function extractFromReturnTypeAnnotation(typeNode) {
|
|
528
|
-
if (import_ts_morph.Node.isTypeReference(typeNode)) {
|
|
529
|
-
const typeName = typeNode.getTypeName();
|
|
530
|
-
if (import_ts_morph.Node.isIdentifier(typeName) && typeName.getText() === "Promise") {
|
|
531
|
-
const typeArgs = typeNode.getTypeArguments();
|
|
532
|
-
const firstArg2 = typeArgs[0];
|
|
533
|
-
if (firstArg2) {
|
|
534
|
-
return extractFromReturnTypeAnnotation(firstArg2);
|
|
393
|
+
this.stats.delete(path);
|
|
394
|
+
changed.push(path);
|
|
395
|
+
continue;
|
|
535
396
|
}
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
if (import_ts_morph.Node.isPropertySignature(member)) {
|
|
543
|
-
const name = member.getName();
|
|
544
|
-
const memberTypeNode = member.getTypeNode();
|
|
545
|
-
const type = memberTypeNode ? memberTypeNode.getText() : "unknown";
|
|
546
|
-
properties.push({ name, type });
|
|
397
|
+
if (this.stats.get(path) === key) continue;
|
|
398
|
+
let disk;
|
|
399
|
+
try {
|
|
400
|
+
disk = (0, import_node_fs.readFileSync)(path, "utf-8");
|
|
401
|
+
} catch {
|
|
402
|
+
disk = void 0;
|
|
547
403
|
}
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
return null;
|
|
554
|
-
}
|
|
555
|
-
function extractFromBlockReturn(block) {
|
|
556
|
-
if (!import_ts_morph.Node.isBlock(block)) return null;
|
|
557
|
-
const statements = block.getStatements();
|
|
558
|
-
for (let i = statements.length - 1; i >= 0; i--) {
|
|
559
|
-
const stmt = statements[i];
|
|
560
|
-
if (!import_ts_morph.Node.isReturnStatement(stmt)) continue;
|
|
561
|
-
const expr = stmt.getExpression();
|
|
562
|
-
if (!expr) continue;
|
|
563
|
-
if (import_ts_morph.Node.isObjectLiteralExpression(expr)) {
|
|
564
|
-
return extractFromObjectLiteral(expr);
|
|
565
|
-
}
|
|
566
|
-
if (import_ts_morph.Node.isParenthesizedExpression(expr)) {
|
|
567
|
-
const inner = expr.getExpression();
|
|
568
|
-
if (import_ts_morph.Node.isObjectLiteralExpression(inner)) {
|
|
569
|
-
return extractFromObjectLiteral(inner);
|
|
404
|
+
if (disk === text) {
|
|
405
|
+
this.stats.set(path, key);
|
|
406
|
+
} else {
|
|
407
|
+
this.stats.delete(path);
|
|
408
|
+
changed.push(path);
|
|
570
409
|
}
|
|
571
410
|
}
|
|
572
|
-
|
|
411
|
+
return changed;
|
|
573
412
|
}
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
if (!import_ts_morph.Node.isObjectLiteralExpression(objLiteral)) return null;
|
|
578
|
-
const properties = [];
|
|
579
|
-
for (const prop of objLiteral.getProperties()) {
|
|
580
|
-
if (!import_ts_morph.Node.isPropertyAssignment(prop)) continue;
|
|
581
|
-
const name = prop.getName();
|
|
582
|
-
const initializer = prop.getInitializer();
|
|
583
|
-
if (!initializer) continue;
|
|
584
|
-
const type = inferExpressionType(initializer);
|
|
585
|
-
properties.push({ name, type });
|
|
586
|
-
}
|
|
587
|
-
if (properties.length === 0) return null;
|
|
588
|
-
const typeString = `{ ${properties.map((p) => `${p.name}: ${p.type}`).join("; ")} }`;
|
|
589
|
-
return { typeString, properties, isImportRef: false };
|
|
590
|
-
}
|
|
591
|
-
function inferExpressionType(node) {
|
|
592
|
-
if (import_ts_morph.Node.isStringLiteral(node)) return "string";
|
|
593
|
-
if (import_ts_morph.Node.isTemplateExpression(node) || import_ts_morph.Node.isNoSubstitutionTemplateLiteral(node))
|
|
594
|
-
return "string";
|
|
595
|
-
if (import_ts_morph.Node.isNumericLiteral(node)) return "number";
|
|
596
|
-
if (node.getKind() === import_ts_morph.SyntaxKind.TrueKeyword || node.getKind() === import_ts_morph.SyntaxKind.FalseKeyword) {
|
|
597
|
-
return "boolean";
|
|
598
|
-
}
|
|
599
|
-
if (node.getKind() === import_ts_morph.SyntaxKind.NullKeyword) return "null";
|
|
600
|
-
if (import_ts_morph.Node.isIdentifier(node) && node.getText() === "undefined") return "undefined";
|
|
601
|
-
if (import_ts_morph.Node.isObjectLiteralExpression(node)) {
|
|
602
|
-
const props = node.getProperties();
|
|
603
|
-
if (props.length === 0) return "Record<string, unknown>";
|
|
604
|
-
const entries = [];
|
|
605
|
-
for (const prop of props) {
|
|
606
|
-
if (!import_ts_morph.Node.isPropertyAssignment(prop)) continue;
|
|
607
|
-
const key = prop.getName();
|
|
608
|
-
const init = prop.getInitializer();
|
|
609
|
-
if (!init) continue;
|
|
610
|
-
entries.push(`${key}: ${inferExpressionType(init)}`);
|
|
611
|
-
}
|
|
612
|
-
if (entries.length === 0) return "Record<string, unknown>";
|
|
613
|
-
return `{ ${entries.join("; ")} }`;
|
|
614
|
-
}
|
|
615
|
-
if (import_ts_morph.Node.isArrayLiteralExpression(node)) {
|
|
616
|
-
const elements = node.getElements();
|
|
617
|
-
if (elements.length === 0) return "Array<unknown>";
|
|
618
|
-
const first = elements[0];
|
|
619
|
-
if (first) return `Array<${inferExpressionType(first)}>`;
|
|
620
|
-
return "Array<unknown>";
|
|
621
|
-
}
|
|
622
|
-
if (import_ts_morph.Node.isConditionalExpression(node)) {
|
|
623
|
-
const whenTrue = inferExpressionType(node.getWhenTrue());
|
|
624
|
-
const whenFalse = inferExpressionType(node.getWhenFalse());
|
|
625
|
-
if (whenTrue === whenFalse) return whenTrue;
|
|
626
|
-
return `${whenTrue} | ${whenFalse}`;
|
|
627
|
-
}
|
|
628
|
-
if (import_ts_morph.Node.isParenthesizedExpression(node)) {
|
|
629
|
-
return inferExpressionType(node.getExpression());
|
|
630
|
-
}
|
|
631
|
-
if (import_ts_morph.Node.isAsExpression(node)) {
|
|
632
|
-
const typeNode = node.getTypeNode();
|
|
633
|
-
if (typeNode) return typeNode.getText();
|
|
413
|
+
/** Forget `path`, so its next check compares content again. */
|
|
414
|
+
forget(path) {
|
|
415
|
+
this.stats.delete(path);
|
|
634
416
|
}
|
|
635
|
-
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
// src/emit/emit-api.ts
|
|
639
|
-
var import_promises3 = require("fs/promises");
|
|
640
|
-
var import_node_path7 = require("path");
|
|
641
|
-
|
|
642
|
-
// src/extension/registry.ts
|
|
643
|
-
var import_node_path6 = require("path");
|
|
644
|
-
var import_ts_morph13 = require("ts-morph");
|
|
645
|
-
|
|
646
|
-
// src/discovery/contracts-fast.ts
|
|
647
|
-
var import_node_fs = require("fs");
|
|
648
|
-
var import_node_path5 = require("path");
|
|
649
|
-
var import_fast_glob2 = __toESM(require("fast-glob"), 1);
|
|
650
|
-
var import_ts_morph12 = require("ts-morph");
|
|
417
|
+
};
|
|
651
418
|
|
|
652
419
|
// src/discovery/dto-type-resolver.ts
|
|
653
420
|
var import_ts_morph11 = require("ts-morph");
|
|
654
421
|
|
|
655
422
|
// src/discovery/dto-to-ir.ts
|
|
656
|
-
var
|
|
423
|
+
var import_ts_morph2 = require("ts-morph");
|
|
657
424
|
|
|
658
425
|
// src/util/debug-log.ts
|
|
659
426
|
var debugEnabled = false;
|
|
@@ -665,8 +432,8 @@ function debugWarn(message) {
|
|
|
665
432
|
}
|
|
666
433
|
|
|
667
434
|
// src/discovery/type-ref-resolution.ts
|
|
668
|
-
var
|
|
669
|
-
var
|
|
435
|
+
var import_node_path3 = require("path");
|
|
436
|
+
var import_ts_morph = require("ts-morph");
|
|
670
437
|
var _EMPTY_CTX = { projectRoot: "", tsconfigPaths: null };
|
|
671
438
|
var _ctxByProject = /* @__PURE__ */ new WeakMap();
|
|
672
439
|
function setDiscoveryContext(project, ctx) {
|
|
@@ -707,17 +474,17 @@ function findTypeInFile(name, file) {
|
|
|
707
474
|
}
|
|
708
475
|
function resolveModuleSpecifier(moduleSpecifier, sourceFile, project) {
|
|
709
476
|
if (moduleSpecifier.startsWith(".")) {
|
|
710
|
-
const dir = (0,
|
|
477
|
+
const dir = (0, import_node_path3.dirname)(sourceFile.getFilePath());
|
|
711
478
|
const ext = /\.(c|m)?(j|t)sx?$/.exec(moduleSpecifier)?.[0];
|
|
712
479
|
const base = ext ? moduleSpecifier.slice(0, -ext.length) : moduleSpecifier;
|
|
713
480
|
const flavour = ext?.startsWith(".c") ? "c" : ext?.startsWith(".m") ? "m" : "";
|
|
714
481
|
const candidates = [
|
|
715
|
-
(0,
|
|
716
|
-
...flavour === "" ? [(0,
|
|
717
|
-
(0,
|
|
718
|
-
(0,
|
|
719
|
-
(0,
|
|
720
|
-
...ext === void 0 ? [(0,
|
|
482
|
+
(0, import_node_path3.resolve)(dir, `${base}.${flavour}ts`),
|
|
483
|
+
...flavour === "" ? [(0, import_node_path3.resolve)(dir, `${base}.tsx`)] : [],
|
|
484
|
+
(0, import_node_path3.resolve)(dir, `${moduleSpecifier}.ts`),
|
|
485
|
+
(0, import_node_path3.resolve)(dir, moduleSpecifier, "index.ts"),
|
|
486
|
+
(0, import_node_path3.resolve)(dir, `${base}.d.${flavour}ts`),
|
|
487
|
+
...ext === void 0 ? [(0, import_node_path3.resolve)(dir, moduleSpecifier, "index.d.ts")] : []
|
|
721
488
|
];
|
|
722
489
|
return [...new Set(candidates)];
|
|
723
490
|
}
|
|
@@ -739,8 +506,8 @@ function resolveModuleSpecifier(moduleSpecifier, sourceFile, project) {
|
|
|
739
506
|
const rest = moduleSpecifier.slice(prefix.length);
|
|
740
507
|
const candidates = [];
|
|
741
508
|
for (const mapping of mappings) {
|
|
742
|
-
const resolved = (0,
|
|
743
|
-
candidates.push(`${resolved}.ts`, (0,
|
|
509
|
+
const resolved = (0, import_node_path3.resolve)(baseUrl, mapping.replace("*", rest));
|
|
510
|
+
candidates.push(`${resolved}.ts`, (0, import_node_path3.resolve)(resolved, "index.ts"));
|
|
744
511
|
}
|
|
745
512
|
dbg(" resolved candidates:", candidates);
|
|
746
513
|
return candidates;
|
|
@@ -931,13 +698,13 @@ function resolveTypeRef(nodeOrName, sourceFile, project, opts) {
|
|
|
931
698
|
name = nodeOrName;
|
|
932
699
|
} else {
|
|
933
700
|
const typeNode = nodeOrName;
|
|
934
|
-
if (opts.unwrapContainers &&
|
|
701
|
+
if (opts.unwrapContainers && import_ts_morph.Node.isArrayTypeNode(typeNode)) {
|
|
935
702
|
const inner = resolveTypeRef(typeNode.getElementTypeNode(), sourceFile, project, opts);
|
|
936
703
|
return inner ? { ...inner, isArray: true } : null;
|
|
937
704
|
}
|
|
938
|
-
if (!
|
|
705
|
+
if (!import_ts_morph.Node.isTypeReference(typeNode)) return null;
|
|
939
706
|
const typeName = typeNode.getTypeName();
|
|
940
|
-
const refName =
|
|
707
|
+
const refName = import_ts_morph.Node.isIdentifier(typeName) ? typeName.getText() : null;
|
|
941
708
|
if (!refName) return null;
|
|
942
709
|
if (opts.unwrapContainers && refName === "Promise") {
|
|
943
710
|
const first = typeNode.getTypeArguments()[0];
|
|
@@ -1071,7 +838,7 @@ function buildProperty(prop, classFile, ctx) {
|
|
|
1071
838
|
const dec = (n) => decorators.get(n);
|
|
1072
839
|
const typeNode = prop.getTypeNode();
|
|
1073
840
|
const typeText = typeNode?.getText() ?? "unknown";
|
|
1074
|
-
const isArrayType = !!typeNode &&
|
|
841
|
+
const isArrayType = !!typeNode && import_ts_morph2.Node.isArrayTypeNode(typeNode);
|
|
1075
842
|
const asField = (child) => applyPresence(
|
|
1076
843
|
has("IsArray") || isArrayType ? { kind: "array", element: child } : child,
|
|
1077
844
|
decorators
|
|
@@ -1285,22 +1052,22 @@ function firstArgText(decorator) {
|
|
|
1285
1052
|
}
|
|
1286
1053
|
function numericArg(decorator) {
|
|
1287
1054
|
const arg = firstArg(decorator);
|
|
1288
|
-
if (arg &&
|
|
1055
|
+
if (arg && import_ts_morph2.Node.isNumericLiteral(arg)) return arg.getText();
|
|
1289
1056
|
return null;
|
|
1290
1057
|
}
|
|
1291
1058
|
function numericArgs(decorator) {
|
|
1292
1059
|
const args = decorator?.getArguments() ?? [];
|
|
1293
|
-
const num = (n) => n &&
|
|
1060
|
+
const num = (n) => n && import_ts_morph2.Node.isNumericLiteral(n) ? n.getText() : null;
|
|
1294
1061
|
return [num(args[0]), num(args[1])];
|
|
1295
1062
|
}
|
|
1296
1063
|
function messageRaw(decorator) {
|
|
1297
1064
|
const args = decorator?.getArguments() ?? [];
|
|
1298
1065
|
for (const arg of args) {
|
|
1299
|
-
if (
|
|
1066
|
+
if (import_ts_morph2.Node.isObjectLiteralExpression(arg)) {
|
|
1300
1067
|
for (const prop of arg.getProperties()) {
|
|
1301
|
-
if (
|
|
1068
|
+
if (import_ts_morph2.Node.isPropertyAssignment(prop) && prop.getName() === "message") {
|
|
1302
1069
|
const init = prop.getInitializer();
|
|
1303
|
-
if (init &&
|
|
1070
|
+
if (init && import_ts_morph2.Node.isStringLiteral(init)) return init.getText();
|
|
1304
1071
|
}
|
|
1305
1072
|
}
|
|
1306
1073
|
}
|
|
@@ -1309,30 +1076,30 @@ function messageRaw(decorator) {
|
|
|
1309
1076
|
}
|
|
1310
1077
|
function resolveDiscriminator(decorator) {
|
|
1311
1078
|
const optsArg = decorator?.getArguments()[1];
|
|
1312
|
-
if (!optsArg || !
|
|
1079
|
+
if (!optsArg || !import_ts_morph2.Node.isObjectLiteralExpression(optsArg)) return null;
|
|
1313
1080
|
let discProp;
|
|
1314
1081
|
for (const prop of optsArg.getProperties()) {
|
|
1315
|
-
if (
|
|
1082
|
+
if (import_ts_morph2.Node.isPropertyAssignment(prop) && prop.getName() === "discriminator") {
|
|
1316
1083
|
discProp = prop.getInitializer();
|
|
1317
1084
|
}
|
|
1318
1085
|
}
|
|
1319
|
-
if (!discProp || !
|
|
1086
|
+
if (!discProp || !import_ts_morph2.Node.isObjectLiteralExpression(discProp)) return null;
|
|
1320
1087
|
let property = null;
|
|
1321
1088
|
const subTypes = [];
|
|
1322
1089
|
for (const prop of discProp.getProperties()) {
|
|
1323
|
-
if (!
|
|
1090
|
+
if (!import_ts_morph2.Node.isPropertyAssignment(prop)) continue;
|
|
1324
1091
|
const name = prop.getName();
|
|
1325
1092
|
const init = prop.getInitializer();
|
|
1326
1093
|
if (!init) continue;
|
|
1327
|
-
if (name === "property" &&
|
|
1094
|
+
if (name === "property" && import_ts_morph2.Node.isStringLiteral(init)) {
|
|
1328
1095
|
property = init.getLiteralValue();
|
|
1329
|
-
} else if (name === "subTypes" &&
|
|
1096
|
+
} else if (name === "subTypes" && import_ts_morph2.Node.isArrayLiteralExpression(init)) {
|
|
1330
1097
|
for (const el of init.getElements()) {
|
|
1331
|
-
if (!
|
|
1098
|
+
if (!import_ts_morph2.Node.isObjectLiteralExpression(el)) continue;
|
|
1332
1099
|
for (const p of el.getProperties()) {
|
|
1333
|
-
if (!
|
|
1100
|
+
if (!import_ts_morph2.Node.isPropertyAssignment(p) || p.getName() !== "name") continue;
|
|
1334
1101
|
const nameInit = p.getInitializer();
|
|
1335
|
-
if (nameInit &&
|
|
1102
|
+
if (nameInit && import_ts_morph2.Node.isIdentifier(nameInit)) subTypes.push(nameInit.getText());
|
|
1336
1103
|
}
|
|
1337
1104
|
}
|
|
1338
1105
|
}
|
|
@@ -1343,9 +1110,9 @@ function resolveDiscriminator(decorator) {
|
|
|
1343
1110
|
function resolveTypeFactoryName(decorator) {
|
|
1344
1111
|
const arg = firstArg(decorator);
|
|
1345
1112
|
if (!arg) return null;
|
|
1346
|
-
if (
|
|
1113
|
+
if (import_ts_morph2.Node.isArrowFunction(arg)) {
|
|
1347
1114
|
const body = arg.getBody();
|
|
1348
|
-
if (
|
|
1115
|
+
if (import_ts_morph2.Node.isIdentifier(body)) return body.getText();
|
|
1349
1116
|
}
|
|
1350
1117
|
return null;
|
|
1351
1118
|
}
|
|
@@ -1354,12 +1121,12 @@ function singularClassName(typeText) {
|
|
|
1354
1121
|
return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(inner) ? inner : null;
|
|
1355
1122
|
}
|
|
1356
1123
|
function genericTypeArgNames(typeNode) {
|
|
1357
|
-
if (!typeNode || !
|
|
1124
|
+
if (!typeNode || !import_ts_morph2.Node.isTypeReference(typeNode)) return [];
|
|
1358
1125
|
const names = [];
|
|
1359
1126
|
for (const arg of typeNode.getTypeArguments()) {
|
|
1360
|
-
if (!
|
|
1127
|
+
if (!import_ts_morph2.Node.isTypeReference(arg)) return [];
|
|
1361
1128
|
const tn = arg.getTypeName();
|
|
1362
|
-
if (!
|
|
1129
|
+
if (!import_ts_morph2.Node.isIdentifier(tn)) return [];
|
|
1363
1130
|
names.push(tn.getText());
|
|
1364
1131
|
}
|
|
1365
1132
|
return names;
|
|
@@ -1367,7 +1134,7 @@ function genericTypeArgNames(typeNode) {
|
|
|
1367
1134
|
function enumSchemaFromDecorator(decorator, classFile, ctx) {
|
|
1368
1135
|
const arg = firstArg(decorator);
|
|
1369
1136
|
if (!arg) return null;
|
|
1370
|
-
if (
|
|
1137
|
+
if (import_ts_morph2.Node.isIdentifier(arg)) {
|
|
1371
1138
|
const name = arg.getText();
|
|
1372
1139
|
const resolved = findType(name, classFile, ctx.project);
|
|
1373
1140
|
if (resolved && resolved.kind === "enum") {
|
|
@@ -1381,12 +1148,12 @@ function enumSchemaFromDecorator(decorator, classFile, ctx) {
|
|
|
1381
1148
|
}
|
|
1382
1149
|
return { kind: "unknown", note: `@IsEnum(${name}): enum not resolvable to literals` };
|
|
1383
1150
|
}
|
|
1384
|
-
if (
|
|
1151
|
+
if (import_ts_morph2.Node.isObjectLiteralExpression(arg)) {
|
|
1385
1152
|
const values = [];
|
|
1386
1153
|
for (const p of arg.getProperties()) {
|
|
1387
|
-
if (!
|
|
1154
|
+
if (!import_ts_morph2.Node.isPropertyAssignment(p)) continue;
|
|
1388
1155
|
const init = p.getInitializer();
|
|
1389
|
-
if (init &&
|
|
1156
|
+
if (init && import_ts_morph2.Node.isStringLiteral(init)) values.push(init.getText());
|
|
1390
1157
|
}
|
|
1391
1158
|
if (values.length > 0) return { kind: "enum", literals: values };
|
|
1392
1159
|
}
|
|
@@ -1394,9 +1161,9 @@ function enumSchemaFromDecorator(decorator, classFile, ctx) {
|
|
|
1394
1161
|
}
|
|
1395
1162
|
function inSchemaFromDecorator(decorator) {
|
|
1396
1163
|
const arg = firstArg(decorator);
|
|
1397
|
-
if (arg &&
|
|
1164
|
+
if (arg && import_ts_morph2.Node.isArrayLiteralExpression(arg)) {
|
|
1398
1165
|
const elements = arg.getElements();
|
|
1399
|
-
const allStrings = elements.every((e) =>
|
|
1166
|
+
const allStrings = elements.every((e) => import_ts_morph2.Node.isStringLiteral(e));
|
|
1400
1167
|
if (allStrings && elements.length > 0) {
|
|
1401
1168
|
return { kind: "enum", literals: elements.map((e) => e.getText()) };
|
|
1402
1169
|
}
|
|
@@ -1414,7 +1181,7 @@ function inSchemaFromDecorator(decorator) {
|
|
|
1414
1181
|
var import_ts_morph6 = require("ts-morph");
|
|
1415
1182
|
|
|
1416
1183
|
// src/discovery/filter-field-types.ts
|
|
1417
|
-
var
|
|
1184
|
+
var import_ts_morph3 = require("ts-morph");
|
|
1418
1185
|
|
|
1419
1186
|
// src/discovery/enum-resolution.ts
|
|
1420
1187
|
var _enumCache = /* @__PURE__ */ new WeakMap();
|
|
@@ -1467,28 +1234,28 @@ function markNullable(r, nullable) {
|
|
|
1467
1234
|
}
|
|
1468
1235
|
var TRANSPARENT_TYPE_BRANDS = /* @__PURE__ */ new Set(["Opt", "Hidden"]);
|
|
1469
1236
|
function classifyTypeNode(typeNode, sourceFile, project, opts) {
|
|
1470
|
-
if (
|
|
1237
|
+
if (import_ts_morph3.Node.isUnionTypeNode(typeNode)) {
|
|
1471
1238
|
let nullable = false;
|
|
1472
1239
|
const stringLits = [];
|
|
1473
1240
|
const numberLits = [];
|
|
1474
1241
|
const others = [];
|
|
1475
1242
|
for (const member of typeNode.getTypeNodes()) {
|
|
1476
1243
|
const kind = member.getKind();
|
|
1477
|
-
if (kind ===
|
|
1244
|
+
if (kind === import_ts_morph3.SyntaxKind.NullKeyword || kind === import_ts_morph3.SyntaxKind.UndefinedKeyword) {
|
|
1478
1245
|
nullable = true;
|
|
1479
1246
|
continue;
|
|
1480
1247
|
}
|
|
1481
|
-
if (
|
|
1248
|
+
if (import_ts_morph3.Node.isLiteralTypeNode(member)) {
|
|
1482
1249
|
const lit = member.getLiteral();
|
|
1483
|
-
if (
|
|
1250
|
+
if (import_ts_morph3.Node.isStringLiteral(lit)) {
|
|
1484
1251
|
stringLits.push(lit.getLiteralValue());
|
|
1485
1252
|
continue;
|
|
1486
1253
|
}
|
|
1487
|
-
if (
|
|
1254
|
+
if (import_ts_morph3.Node.isNumericLiteral(lit)) {
|
|
1488
1255
|
numberLits.push(lit.getText());
|
|
1489
1256
|
continue;
|
|
1490
1257
|
}
|
|
1491
|
-
if (lit.getKind() ===
|
|
1258
|
+
if (lit.getKind() === import_ts_morph3.SyntaxKind.NullKeyword) {
|
|
1492
1259
|
nullable = true;
|
|
1493
1260
|
continue;
|
|
1494
1261
|
}
|
|
@@ -1508,19 +1275,19 @@ function classifyTypeNode(typeNode, sourceFile, project, opts) {
|
|
|
1508
1275
|
return markNullable({ kind: "unknown" }, nullable);
|
|
1509
1276
|
}
|
|
1510
1277
|
switch (typeNode.getKind()) {
|
|
1511
|
-
case
|
|
1278
|
+
case import_ts_morph3.SyntaxKind.StringKeyword:
|
|
1512
1279
|
return { kind: "string" };
|
|
1513
|
-
case
|
|
1280
|
+
case import_ts_morph3.SyntaxKind.NumberKeyword:
|
|
1514
1281
|
return { kind: "number" };
|
|
1515
|
-
case
|
|
1282
|
+
case import_ts_morph3.SyntaxKind.BooleanKeyword:
|
|
1516
1283
|
return { kind: "boolean" };
|
|
1517
|
-
case
|
|
1518
|
-
case
|
|
1284
|
+
case import_ts_morph3.SyntaxKind.AnyKeyword:
|
|
1285
|
+
case import_ts_morph3.SyntaxKind.UnknownKeyword:
|
|
1519
1286
|
return { kind: "unknown" };
|
|
1520
1287
|
default:
|
|
1521
1288
|
break;
|
|
1522
1289
|
}
|
|
1523
|
-
if (
|
|
1290
|
+
if (import_ts_morph3.Node.isTypeReference(typeNode)) {
|
|
1524
1291
|
const refName = typeNode.getTypeName().getText();
|
|
1525
1292
|
if (refName === "Date") return { kind: "date" };
|
|
1526
1293
|
if (refName === "Record" || refName === "Object") return { kind: "json" };
|
|
@@ -1538,25 +1305,25 @@ function classifyTypeNode(typeNode, sourceFile, project, opts) {
|
|
|
1538
1305
|
if (typeRef) return { kind: "unknown", typeRef };
|
|
1539
1306
|
return { kind: "unknown" };
|
|
1540
1307
|
}
|
|
1541
|
-
if (
|
|
1308
|
+
if (import_ts_morph3.Node.isTypeLiteral(typeNode)) return { kind: "json" };
|
|
1542
1309
|
return { kind: "unknown" };
|
|
1543
1310
|
}
|
|
1544
1311
|
function enumFromDecoratorArgs(args, sourceFile, project) {
|
|
1545
1312
|
for (const arg of args) {
|
|
1546
|
-
if (
|
|
1313
|
+
if (import_ts_morph3.Node.isArrowFunction(arg)) {
|
|
1547
1314
|
const body = arg.getBody();
|
|
1548
|
-
if (
|
|
1315
|
+
if (import_ts_morph3.Node.isIdentifier(body)) {
|
|
1549
1316
|
const en = resolveEnumValues(body.getText(), sourceFile, project);
|
|
1550
1317
|
if (en) return en;
|
|
1551
1318
|
}
|
|
1552
1319
|
}
|
|
1553
|
-
if (
|
|
1320
|
+
if (import_ts_morph3.Node.isObjectLiteralExpression(arg)) {
|
|
1554
1321
|
const itemsProp = arg.getProperty("items");
|
|
1555
|
-
if (itemsProp &&
|
|
1322
|
+
if (itemsProp && import_ts_morph3.Node.isPropertyAssignment(itemsProp)) {
|
|
1556
1323
|
const init = itemsProp.getInitializer();
|
|
1557
|
-
if (init &&
|
|
1324
|
+
if (init && import_ts_morph3.Node.isArrowFunction(init)) {
|
|
1558
1325
|
const body = init.getBody();
|
|
1559
|
-
if (
|
|
1326
|
+
if (import_ts_morph3.Node.isIdentifier(body)) {
|
|
1560
1327
|
const en = resolveEnumValues(body.getText(), sourceFile, project);
|
|
1561
1328
|
if (en) return en;
|
|
1562
1329
|
}
|
|
@@ -1579,7 +1346,7 @@ function classifyFromColumnDecorator(prop, sourceFile, project) {
|
|
|
1579
1346
|
return { kind: "string" };
|
|
1580
1347
|
}
|
|
1581
1348
|
for (const arg of args) {
|
|
1582
|
-
if (
|
|
1349
|
+
if (import_ts_morph3.Node.isStringLiteral(arg)) {
|
|
1583
1350
|
const raw = arg.getLiteralValue();
|
|
1584
1351
|
const kind = classifyTypeKeyword(raw);
|
|
1585
1352
|
if (kind) {
|
|
@@ -1587,11 +1354,11 @@ function classifyFromColumnDecorator(prop, sourceFile, project) {
|
|
|
1587
1354
|
return { kind };
|
|
1588
1355
|
}
|
|
1589
1356
|
}
|
|
1590
|
-
if (
|
|
1357
|
+
if (import_ts_morph3.Node.isObjectLiteralExpression(arg)) {
|
|
1591
1358
|
const enumProp = arg.getProperty("enum");
|
|
1592
|
-
if (enumProp &&
|
|
1359
|
+
if (enumProp && import_ts_morph3.Node.isPropertyAssignment(enumProp)) {
|
|
1593
1360
|
const init = enumProp.getInitializer();
|
|
1594
|
-
if (init &&
|
|
1361
|
+
if (init && import_ts_morph3.Node.isIdentifier(init)) {
|
|
1595
1362
|
const en = resolveEnumValues(init.getText(), sourceFile, project);
|
|
1596
1363
|
if (en) {
|
|
1597
1364
|
return en.numeric ? { kind: "number", enumValues: en.values, numericEnum: true } : { kind: "string", enumValues: en.values };
|
|
@@ -1601,15 +1368,15 @@ function classifyFromColumnDecorator(prop, sourceFile, project) {
|
|
|
1601
1368
|
}
|
|
1602
1369
|
for (const key of ["columnType", "type"]) {
|
|
1603
1370
|
const typeProp = arg.getProperty(key);
|
|
1604
|
-
if (!typeProp || !
|
|
1371
|
+
if (!typeProp || !import_ts_morph3.Node.isPropertyAssignment(typeProp)) continue;
|
|
1605
1372
|
const init = typeProp.getInitializer();
|
|
1606
1373
|
if (!init) continue;
|
|
1607
|
-
if (
|
|
1374
|
+
if (import_ts_morph3.Node.isStringLiteral(init)) {
|
|
1608
1375
|
const kind = classifyTypeKeyword(init.getLiteralValue());
|
|
1609
1376
|
if (kind) return { kind };
|
|
1610
1377
|
continue;
|
|
1611
1378
|
}
|
|
1612
|
-
if (
|
|
1379
|
+
if (import_ts_morph3.Node.isIdentifier(init)) {
|
|
1613
1380
|
const kind = classifyTypeKeyword(init.getText());
|
|
1614
1381
|
if (kind) return { kind };
|
|
1615
1382
|
}
|
|
@@ -1652,6 +1419,49 @@ function toFilterFieldType(name, r) {
|
|
|
1652
1419
|
|
|
1653
1420
|
// src/discovery/heritage.ts
|
|
1654
1421
|
var import_ts_morph5 = require("ts-morph");
|
|
1422
|
+
|
|
1423
|
+
// src/discovery/unresolved-imports.ts
|
|
1424
|
+
var import_ts_morph4 = require("ts-morph");
|
|
1425
|
+
var UnresolvedImports = class {
|
|
1426
|
+
read;
|
|
1427
|
+
/**
|
|
1428
|
+
* The files with an import that failed to resolve in `program` and now resolves
|
|
1429
|
+
* to a TypeScript file the program does not hold.
|
|
1430
|
+
*/
|
|
1431
|
+
nowResolving(program) {
|
|
1432
|
+
if (this.read?.program !== program) {
|
|
1433
|
+
this.read = { program, imports: failedImports(program) };
|
|
1434
|
+
}
|
|
1435
|
+
const options = program.getCompilerOptions();
|
|
1436
|
+
const files = /* @__PURE__ */ new Set();
|
|
1437
|
+
for (const { specifier, from } of this.read.imports) {
|
|
1438
|
+
const file = import_ts_morph4.ts.resolveModuleName(specifier, from, options, import_ts_morph4.ts.sys).resolvedModule?.resolvedFileName;
|
|
1439
|
+
if (file !== void 0 && /\.(m|c)?tsx?$/.test(file) && !program.getSourceFile(file)) {
|
|
1440
|
+
files.add(from);
|
|
1441
|
+
}
|
|
1442
|
+
}
|
|
1443
|
+
return [...files];
|
|
1444
|
+
}
|
|
1445
|
+
};
|
|
1446
|
+
function failedImports(program) {
|
|
1447
|
+
const checker = program.getTypeChecker();
|
|
1448
|
+
const imports = [];
|
|
1449
|
+
for (const file of program.getSourceFiles()) {
|
|
1450
|
+
if (program.isSourceFileDefaultLibrary(file) || file.isDeclarationFile) continue;
|
|
1451
|
+
if (program.isSourceFileFromExternalLibrary(file)) continue;
|
|
1452
|
+
for (const statement of file.statements) {
|
|
1453
|
+
if (!import_ts_morph4.ts.isImportDeclaration(statement) && !import_ts_morph4.ts.isExportDeclaration(statement)) continue;
|
|
1454
|
+
const specifier = statement.moduleSpecifier;
|
|
1455
|
+
if (!specifier || !import_ts_morph4.ts.isStringLiteral(specifier)) continue;
|
|
1456
|
+
if (!checker.getSymbolAtLocation(specifier)) {
|
|
1457
|
+
imports.push({ specifier: specifier.text, from: file.fileName });
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
|
+
return imports;
|
|
1462
|
+
}
|
|
1463
|
+
|
|
1464
|
+
// src/discovery/heritage.ts
|
|
1655
1465
|
function resolveHeritageCall(node) {
|
|
1656
1466
|
if (!node) return void 0;
|
|
1657
1467
|
const expr = unwrapExpression(node);
|
|
@@ -1851,15 +1661,42 @@ function resolvePropertyClassReference(prop) {
|
|
|
1851
1661
|
return { key, ref };
|
|
1852
1662
|
}
|
|
1853
1663
|
var mixinTypeProject;
|
|
1664
|
+
var mixinFiles = new DiskFingerprints();
|
|
1665
|
+
var mixinStale = false;
|
|
1666
|
+
var mixinUnresolved = new UnresolvedImports();
|
|
1854
1667
|
function getMixinTypeProject() {
|
|
1855
|
-
mixinTypeProject
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1668
|
+
if (mixinTypeProject && mixinStale && !refreshMixinTypeProject(mixinTypeProject)) {
|
|
1669
|
+
mixinTypeProject = void 0;
|
|
1670
|
+
}
|
|
1671
|
+
mixinStale = false;
|
|
1672
|
+
if (!mixinTypeProject) {
|
|
1673
|
+
mixinTypeProject = new import_ts_morph5.Project({
|
|
1674
|
+
skipAddingFilesFromTsConfig: true,
|
|
1675
|
+
compilerOptions: { strict: true }
|
|
1676
|
+
});
|
|
1677
|
+
mixinFiles = new DiskFingerprints();
|
|
1678
|
+
mixinUnresolved = new UnresolvedImports();
|
|
1679
|
+
}
|
|
1859
1680
|
return mixinTypeProject;
|
|
1860
1681
|
}
|
|
1861
1682
|
function clearMixinTypeProject() {
|
|
1862
1683
|
mixinTypeProject = void 0;
|
|
1684
|
+
mixinStale = false;
|
|
1685
|
+
}
|
|
1686
|
+
function invalidateMixinTypeProject() {
|
|
1687
|
+
mixinStale = true;
|
|
1688
|
+
}
|
|
1689
|
+
function refreshMixinTypeProject(project) {
|
|
1690
|
+
const program = project.getProgram().compilerObject;
|
|
1691
|
+
const files = program.getSourceFiles().filter((file) => !program.isSourceFileDefaultLibrary(file)).map((file) => ({ path: file.fileName, text: file.text }));
|
|
1692
|
+
const changed = mixinFiles.changed(files);
|
|
1693
|
+
if (changed.length === 0) return mixinUnresolved.nowResolving(program).length === 0;
|
|
1694
|
+
for (const path of changed) {
|
|
1695
|
+
const sf = project.getSourceFile(path);
|
|
1696
|
+
if (sf?.refreshFromFileSystemSync() !== import_ts_morph5.FileSystemRefreshResult.Updated) return false;
|
|
1697
|
+
}
|
|
1698
|
+
project.resolveSourceFileDependencies();
|
|
1699
|
+
return true;
|
|
1863
1700
|
}
|
|
1864
1701
|
function resolveInstantiatedReturnType(cls, methodName) {
|
|
1865
1702
|
const filePath = cls.getSourceFile().getFilePath();
|
|
@@ -2217,8 +2054,7 @@ var SchemaTypeProgram = class {
|
|
|
2217
2054
|
skipAddingFilesFromTsConfig: true,
|
|
2218
2055
|
compilerOptions: this.options
|
|
2219
2056
|
});
|
|
2220
|
-
|
|
2221
|
-
this.flush();
|
|
2057
|
+
this.requestDiscoveryFiles();
|
|
2222
2058
|
}
|
|
2223
2059
|
project;
|
|
2224
2060
|
options;
|
|
@@ -2231,6 +2067,53 @@ var SchemaTypeProgram = class {
|
|
|
2231
2067
|
needs = /* @__PURE__ */ new Map();
|
|
2232
2068
|
/** Pruned text per file, as last written into {@link project}. */
|
|
2233
2069
|
written = /* @__PURE__ */ new Map();
|
|
2070
|
+
/** What {@link project} read from disk unpruned (packages, declaration files). */
|
|
2071
|
+
externalFiles = new DiskFingerprints();
|
|
2072
|
+
scratchFiles = new DiskFingerprints();
|
|
2073
|
+
/** The last pruning of each file, with the source text and needs it was pruned for. */
|
|
2074
|
+
pruned = /* @__PURE__ */ new Map();
|
|
2075
|
+
/**
|
|
2076
|
+
* Bring the program up to date with discovery's files and the disk, keeping the
|
|
2077
|
+
* lib and package declarations it has already parsed and checked. Leaves it
|
|
2078
|
+
* holding exactly the files a new program built now would hold, with the same
|
|
2079
|
+
* text. Returns false when a file the program read unpruned has changed on disk
|
|
2080
|
+
* (a package was reinstalled, a `.d.ts` was edited): the caller builds a new
|
|
2081
|
+
* program instead.
|
|
2082
|
+
*/
|
|
2083
|
+
refresh() {
|
|
2084
|
+
const program = this.project.getProgram().compilerObject;
|
|
2085
|
+
const external = program.getSourceFiles().filter(
|
|
2086
|
+
(file) => !program.isSourceFileDefaultLibrary(file) && !this.written.has(file.fileName)
|
|
2087
|
+
).map((file) => ({ path: file.fileName, text: file.text }));
|
|
2088
|
+
if (this.externalFiles.changed(external).length > 0) return false;
|
|
2089
|
+
const scratch = this.scratch.getSourceFiles().map((sf) => ({ path: sf.getFilePath(), text: sf.getFullText() }));
|
|
2090
|
+
for (const path of this.scratchFiles.changed(scratch)) {
|
|
2091
|
+
const sf = this.scratch.getSourceFile(path);
|
|
2092
|
+
if (sf?.refreshFromFileSystemSync() === import_ts_morph7.FileSystemRefreshResult.Deleted) {
|
|
2093
|
+
this.scratchFiles.forget(path);
|
|
2094
|
+
}
|
|
2095
|
+
}
|
|
2096
|
+
this.needs.clear();
|
|
2097
|
+
this.requestDiscoveryFiles();
|
|
2098
|
+
for (const path of [...this.written.keys()]) {
|
|
2099
|
+
if (this.needs.has(path)) continue;
|
|
2100
|
+
const sf = this.project.getSourceFile(path);
|
|
2101
|
+
if (sf) this.project.removeSourceFile(sf);
|
|
2102
|
+
this.written.delete(path);
|
|
2103
|
+
}
|
|
2104
|
+
return true;
|
|
2105
|
+
}
|
|
2106
|
+
/**
|
|
2107
|
+
* Everything discovery holds now (the controllers) goes in before the first
|
|
2108
|
+
* query: a file added afterwards discards the program and its checker, and
|
|
2109
|
+
* rebuilding them once per controller is exactly the cost this avoids.
|
|
2110
|
+
*/
|
|
2111
|
+
requestDiscoveryFiles() {
|
|
2112
|
+
for (const sf of this.discovery.getSourceFiles()) {
|
|
2113
|
+
this.request(sf.getFilePath(), { schema: true });
|
|
2114
|
+
}
|
|
2115
|
+
this.flush();
|
|
2116
|
+
}
|
|
2234
2117
|
/**
|
|
2235
2118
|
* The typed copy of a discovery file, with its schema positions kept. Adding one
|
|
2236
2119
|
* that was not there yet (a contract file discovery reached lazily) rebuilds the
|
|
@@ -2271,12 +2154,21 @@ var SchemaTypeProgram = class {
|
|
|
2271
2154
|
while (this.queue.length > 0) {
|
|
2272
2155
|
const path = this.queue.pop();
|
|
2273
2156
|
const original = this.original(path);
|
|
2274
|
-
if (!original)
|
|
2275
|
-
|
|
2276
|
-
|
|
2157
|
+
if (!original) {
|
|
2158
|
+
if (this.written.has(path)) changed.set(path, void 0);
|
|
2159
|
+
continue;
|
|
2160
|
+
}
|
|
2161
|
+
const { text, requests } = this.pruneCached(path, original, this.needs.get(path));
|
|
2162
|
+
for (const { path: target, want } of requests) this.request(target, want);
|
|
2277
2163
|
if (this.written.get(path) !== text) changed.set(path, text);
|
|
2278
2164
|
}
|
|
2279
2165
|
for (const [path, text] of changed) {
|
|
2166
|
+
if (text === void 0) {
|
|
2167
|
+
const sf = this.project.getSourceFile(path);
|
|
2168
|
+
if (sf) this.project.removeSourceFile(sf);
|
|
2169
|
+
this.written.delete(path);
|
|
2170
|
+
continue;
|
|
2171
|
+
}
|
|
2280
2172
|
this.project.createSourceFile(path, text, { overwrite: true });
|
|
2281
2173
|
this.written.set(path, text);
|
|
2282
2174
|
}
|
|
@@ -2285,11 +2177,29 @@ var SchemaTypeProgram = class {
|
|
|
2285
2177
|
original(path) {
|
|
2286
2178
|
return this.discovery.getSourceFile(path) ?? this.scratch.getSourceFile(path) ?? this.scratch.addSourceFileAtPathIfExists(path);
|
|
2287
2179
|
}
|
|
2180
|
+
/** {@link prune}, reusing the last result while the file's text and needs are the same. */
|
|
2181
|
+
pruneCached(path, sf, needs) {
|
|
2182
|
+
const source = sf.getFullText();
|
|
2183
|
+
const key = `${needs.schema}:${needs.all}:${[...needs.names].sort().join(",")}`;
|
|
2184
|
+
const last = this.pruned.get(path);
|
|
2185
|
+
if (last && last.source === source && last.needs === key) return last;
|
|
2186
|
+
const result = this.prune(sf, needs);
|
|
2187
|
+
if (result.resolved) this.pruned.set(path, { ...result, source, needs: key });
|
|
2188
|
+
else this.pruned.delete(path);
|
|
2189
|
+
return result;
|
|
2190
|
+
}
|
|
2288
2191
|
/**
|
|
2289
2192
|
* `sf`'s text with every import/re-export nothing in `needs` references blanked,
|
|
2290
|
-
*
|
|
2193
|
+
* and the names each kept one brings in from its target.
|
|
2291
2194
|
*/
|
|
2292
2195
|
prune(sf, needs) {
|
|
2196
|
+
const requests = [];
|
|
2197
|
+
let resolved = true;
|
|
2198
|
+
const resolveFrom = (specifier) => {
|
|
2199
|
+
const target = this.resolve(specifier, sf);
|
|
2200
|
+
if (target === null) resolved = false;
|
|
2201
|
+
return target ?? void 0;
|
|
2202
|
+
};
|
|
2293
2203
|
const locals = topLevelDeclarations(sf);
|
|
2294
2204
|
const roots = [];
|
|
2295
2205
|
if (needs.all) roots.push(...sf.getStatements());
|
|
@@ -2342,7 +2252,7 @@ var SchemaTypeProgram = class {
|
|
|
2342
2252
|
}
|
|
2343
2253
|
};
|
|
2344
2254
|
for (const decl of sf.getImportDeclarations()) {
|
|
2345
|
-
const target =
|
|
2255
|
+
const target = resolveFrom(decl.getModuleSpecifierValue());
|
|
2346
2256
|
const namespace = decl.getNamespaceImport()?.getText();
|
|
2347
2257
|
const def = decl.getDefaultImport()?.getText();
|
|
2348
2258
|
const named = decl.getNamedImports().map((n) => ({
|
|
@@ -2356,21 +2266,24 @@ var SchemaTypeProgram = class {
|
|
|
2356
2266
|
continue;
|
|
2357
2267
|
}
|
|
2358
2268
|
if (target) {
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2269
|
+
requests.push({
|
|
2270
|
+
path: target,
|
|
2271
|
+
want: {
|
|
2272
|
+
all: wantsNamespace,
|
|
2273
|
+
names: [...wantsDefault ? ["default"] : [], ...named.map((n) => n.imported)]
|
|
2274
|
+
}
|
|
2362
2275
|
});
|
|
2363
2276
|
}
|
|
2364
2277
|
}
|
|
2365
2278
|
for (const exp of sf.getExportDeclarations()) {
|
|
2366
2279
|
const spec = exp.getModuleSpecifierValue();
|
|
2367
2280
|
if (spec === void 0) continue;
|
|
2368
|
-
const target =
|
|
2281
|
+
const target = resolveFrom(spec);
|
|
2369
2282
|
if (exp.isNamespaceExport() || exp.getNamedExports().length === 0) {
|
|
2370
2283
|
if (!needs.all && unresolvedNames.length === 0) {
|
|
2371
2284
|
blank(exp);
|
|
2372
2285
|
} else if (target) {
|
|
2373
|
-
|
|
2286
|
+
requests.push({ path: target, want: { all: needs.all, names: unresolvedNames } });
|
|
2374
2287
|
}
|
|
2375
2288
|
continue;
|
|
2376
2289
|
}
|
|
@@ -2378,13 +2291,14 @@ var SchemaTypeProgram = class {
|
|
|
2378
2291
|
(n) => needs.all || needs.names.has((n.getAliasNode() ?? n.getNameNode()).getText())
|
|
2379
2292
|
).map((n) => n.getNameNode().getText());
|
|
2380
2293
|
if (wanted.length === 0) blank(exp);
|
|
2381
|
-
else if (target)
|
|
2294
|
+
else if (target) requests.push({ path: target, want: { names: wanted } });
|
|
2382
2295
|
}
|
|
2383
|
-
return chars.join("");
|
|
2296
|
+
return { text: chars.join(""), requests, resolved };
|
|
2384
2297
|
}
|
|
2385
2298
|
/**
|
|
2386
|
-
* The project source file a module specifier resolves to
|
|
2387
|
-
* package (read unpruned by the program itself)
|
|
2299
|
+
* The project source file a module specifier resolves to; undefined for a
|
|
2300
|
+
* package or a declaration file (read unpruned by the program itself), null for
|
|
2301
|
+
* one that does not resolve.
|
|
2388
2302
|
*/
|
|
2389
2303
|
resolve(specifier, from) {
|
|
2390
2304
|
const resolved = import_ts_morph7.ts.resolveModuleName(
|
|
@@ -2393,7 +2307,8 @@ var SchemaTypeProgram = class {
|
|
|
2393
2307
|
this.options,
|
|
2394
2308
|
import_ts_morph7.ts.sys
|
|
2395
2309
|
).resolvedModule;
|
|
2396
|
-
if (!resolved
|
|
2310
|
+
if (!resolved) return null;
|
|
2311
|
+
if (resolved.isExternalLibraryImport) return void 0;
|
|
2397
2312
|
const file = resolved.resolvedFileName;
|
|
2398
2313
|
if (file.endsWith(".d.ts") || !/\.(m|c)?tsx?$/.test(file)) return void 0;
|
|
2399
2314
|
return file;
|
|
@@ -2448,8 +2363,13 @@ function defaultExport(sf) {
|
|
|
2448
2363
|
|
|
2449
2364
|
// src/discovery/schema-type-inference.ts
|
|
2450
2365
|
var programs = /* @__PURE__ */ new WeakMap();
|
|
2366
|
+
var stale = /* @__PURE__ */ new WeakSet();
|
|
2451
2367
|
function programFor(discovery) {
|
|
2452
2368
|
let program = programs.get(discovery);
|
|
2369
|
+
if (program && stale.has(discovery)) {
|
|
2370
|
+
stale.delete(discovery);
|
|
2371
|
+
if (!program.refresh()) program = void 0;
|
|
2372
|
+
}
|
|
2453
2373
|
if (!program) {
|
|
2454
2374
|
program = new SchemaTypeProgram(discovery);
|
|
2455
2375
|
programs.set(discovery, program);
|
|
@@ -2458,6 +2378,10 @@ function programFor(discovery) {
|
|
|
2458
2378
|
}
|
|
2459
2379
|
function clearSchemaTypeProject(discovery) {
|
|
2460
2380
|
programs.delete(discovery);
|
|
2381
|
+
stale.delete(discovery);
|
|
2382
|
+
}
|
|
2383
|
+
function invalidateSchemaTypeProject(discovery) {
|
|
2384
|
+
if (programs.has(discovery)) stale.add(discovery);
|
|
2461
2385
|
}
|
|
2462
2386
|
function counterpart(typedSf, node) {
|
|
2463
2387
|
const start = node.getStart();
|
|
@@ -3405,7 +3329,7 @@ async function discoverContractsFast(opts) {
|
|
|
3405
3329
|
return routes;
|
|
3406
3330
|
}
|
|
3407
3331
|
function resolveTsconfigPath(cwd, tsconfig) {
|
|
3408
|
-
return tsconfig ? (0,
|
|
3332
|
+
return tsconfig ? (0, import_node_path4.resolve)(tsconfig) : (0, import_node_path4.join)(cwd, "tsconfig.json");
|
|
3409
3333
|
}
|
|
3410
3334
|
var NO_TSCONFIG_OPTIONS = {
|
|
3411
3335
|
allowJs: true,
|
|
@@ -3413,7 +3337,7 @@ var NO_TSCONFIG_OPTIONS = {
|
|
|
3413
3337
|
strict: false
|
|
3414
3338
|
};
|
|
3415
3339
|
function loadDiscoveryTsconfig(tsconfigPath) {
|
|
3416
|
-
if (!(0,
|
|
3340
|
+
if (!(0, import_node_fs2.existsSync)(tsconfigPath)) return { options: null, files: [] };
|
|
3417
3341
|
const read = import_ts_morph12.ts.readConfigFile(tsconfigPath, (path) => import_ts_morph12.ts.sys.readFile(path));
|
|
3418
3342
|
if (read.error) {
|
|
3419
3343
|
return {
|
|
@@ -3435,7 +3359,7 @@ function loadDiscoveryTsconfig(tsconfigPath) {
|
|
|
3435
3359
|
const parsed = import_ts_morph12.ts.parseJsonSourceFileConfigFileContent(
|
|
3436
3360
|
sourceFile,
|
|
3437
3361
|
host,
|
|
3438
|
-
(0,
|
|
3362
|
+
(0, import_node_path4.dirname)(tsconfigPath),
|
|
3439
3363
|
void 0,
|
|
3440
3364
|
tsconfigPath
|
|
3441
3365
|
);
|
|
@@ -3497,6 +3421,9 @@ var PersistentDiscovery = class _PersistentDiscovery {
|
|
|
3497
3421
|
glob;
|
|
3498
3422
|
/** Absolute paths of the controllers currently loaded as extraction roots. */
|
|
3499
3423
|
controllerPaths = /* @__PURE__ */ new Set();
|
|
3424
|
+
/** Every file in {@link project}, as last read from disk. */
|
|
3425
|
+
files = new DiskFingerprints();
|
|
3426
|
+
unresolved = new UnresolvedImports();
|
|
3500
3427
|
constructor(project, cwd, glob) {
|
|
3501
3428
|
this.project = project;
|
|
3502
3429
|
this.cwd = cwd;
|
|
@@ -3522,6 +3449,8 @@ var PersistentDiscovery = class _PersistentDiscovery {
|
|
|
3522
3449
|
}
|
|
3523
3450
|
/** Run the initial extraction (equivalent to a first `discoverContractsFast`). */
|
|
3524
3451
|
discover() {
|
|
3452
|
+
clearMixinTypeProject();
|
|
3453
|
+
clearSchemaTypeProject(this.project);
|
|
3525
3454
|
return this.runExtraction();
|
|
3526
3455
|
}
|
|
3527
3456
|
/**
|
|
@@ -3529,26 +3458,39 @@ var PersistentDiscovery = class _PersistentDiscovery {
|
|
|
3529
3458
|
* from disk (controllers AND any lazily-loaded DTO/imported files), re-globs
|
|
3530
3459
|
* to pick up added/removed controllers, clears the per-Project caches, then
|
|
3531
3460
|
* re-extracts. `changedPaths` is a hint; correctness does not depend on it
|
|
3532
|
-
* being exhaustive because re-globbing +
|
|
3461
|
+
* being exhaustive because re-globbing + comparing every loaded file with the
|
|
3462
|
+
* disk covers the set.
|
|
3533
3463
|
*/
|
|
3534
|
-
async rediscover(changedPaths) {
|
|
3535
|
-
|
|
3536
|
-
|
|
3537
|
-
|
|
3538
|
-
|
|
3539
|
-
|
|
3540
|
-
|
|
3541
|
-
|
|
3464
|
+
async rediscover(changedPaths, options = {}) {
|
|
3465
|
+
const hinted = new Set([...changedPaths ?? []].map((p) => (0, import_node_path4.resolve)(p)));
|
|
3466
|
+
const program = this.project.getProgram().compilerObject;
|
|
3467
|
+
const sources = program.getSourceFiles().filter(
|
|
3468
|
+
(file) => !program.isSourceFileDefaultLibrary(file) && !program.isSourceFileFromExternalLibrary(file)
|
|
3469
|
+
).map((file) => ({ path: file.fileName, text: file.text }));
|
|
3470
|
+
for (const path of /* @__PURE__ */ new Set([...hinted, ...this.files.changed(sources)])) {
|
|
3471
|
+
const sf = this.project.getSourceFile(path);
|
|
3472
|
+
if (sf && await sf.refreshFromFileSystem() === import_ts_morph12.FileSystemRefreshResult.Deleted) {
|
|
3473
|
+
this.files.forget(path);
|
|
3542
3474
|
}
|
|
3543
3475
|
}
|
|
3476
|
+
const inProject = new Set(this.project.getSourceFiles().map((sf) => sf.getFilePath()));
|
|
3477
|
+
const definitions = this.project.getLanguageService().compilerObject.getProgram();
|
|
3478
|
+
for (const path of definitions ? this.unresolved.nowResolving(definitions) : []) {
|
|
3479
|
+
const sf = this.project.getSourceFile(path);
|
|
3480
|
+
if (!sf) continue;
|
|
3481
|
+
this.project.removeSourceFile(sf);
|
|
3482
|
+
if (inProject.has(path)) this.project.addSourceFileAtPathIfExists(path);
|
|
3483
|
+
}
|
|
3544
3484
|
const globbed = new Set(
|
|
3545
3485
|
await (0, import_fast_glob2.default)(this.glob, { cwd: this.cwd, absolute: true, onlyFiles: true })
|
|
3546
3486
|
);
|
|
3487
|
+
let controllersChanged = false;
|
|
3547
3488
|
for (const f of globbed) {
|
|
3548
3489
|
if (!this.controllerPaths.has(f)) {
|
|
3549
3490
|
try {
|
|
3550
3491
|
this.project.addSourceFileAtPath(f);
|
|
3551
3492
|
this.controllerPaths.add(f);
|
|
3493
|
+
controllersChanged = true;
|
|
3552
3494
|
} catch {
|
|
3553
3495
|
}
|
|
3554
3496
|
}
|
|
@@ -3558,16 +3500,22 @@ var PersistentDiscovery = class _PersistentDiscovery {
|
|
|
3558
3500
|
const sf = this.project.getSourceFile(f);
|
|
3559
3501
|
if (sf) this.project.removeSourceFile(sf);
|
|
3560
3502
|
this.controllerPaths.delete(f);
|
|
3503
|
+
controllersChanged = true;
|
|
3561
3504
|
}
|
|
3562
3505
|
}
|
|
3506
|
+
if (controllersChanged || options.filesAddedOrRemoved) {
|
|
3507
|
+
clearMixinTypeProject();
|
|
3508
|
+
clearSchemaTypeProject(this.project);
|
|
3509
|
+
} else {
|
|
3510
|
+
invalidateMixinTypeProject();
|
|
3511
|
+
invalidateSchemaTypeProject(this.project);
|
|
3512
|
+
}
|
|
3563
3513
|
return this.runExtraction();
|
|
3564
3514
|
}
|
|
3565
3515
|
/** Clear stale per-Project caches, then extract over the controller set. */
|
|
3566
3516
|
runExtraction() {
|
|
3567
3517
|
clearTypeResolutionCaches(this.project);
|
|
3568
3518
|
clearEnumCache(this.project);
|
|
3569
|
-
clearMixinTypeProject();
|
|
3570
|
-
clearSchemaTypeProject(this.project);
|
|
3571
3519
|
return extractRoutesFrom(this.project, this.controllerPaths);
|
|
3572
3520
|
}
|
|
3573
3521
|
};
|
|
@@ -3854,7 +3802,300 @@ function extractFromSourceFile(sourceFile, project) {
|
|
|
3854
3802
|
return routes;
|
|
3855
3803
|
}
|
|
3856
3804
|
|
|
3805
|
+
// src/discovery/shared-props.ts
|
|
3806
|
+
function discoverSharedProps(project, moduleEntry) {
|
|
3807
|
+
try {
|
|
3808
|
+
let sourceFile = project.getSourceFile(moduleEntry);
|
|
3809
|
+
if (!sourceFile) {
|
|
3810
|
+
try {
|
|
3811
|
+
sourceFile = project.addSourceFileAtPath(moduleEntry);
|
|
3812
|
+
} catch {
|
|
3813
|
+
return null;
|
|
3814
|
+
}
|
|
3815
|
+
}
|
|
3816
|
+
const forRootCall = findForRootCall(sourceFile);
|
|
3817
|
+
if (!forRootCall) return null;
|
|
3818
|
+
const initializer = findShareInitializer(forRootCall);
|
|
3819
|
+
if (!initializer) return null;
|
|
3820
|
+
return extractShareType(initializer, sourceFile, project);
|
|
3821
|
+
} catch {
|
|
3822
|
+
return null;
|
|
3823
|
+
}
|
|
3824
|
+
}
|
|
3825
|
+
function discoverSharedPropsFromConfig(config) {
|
|
3826
|
+
if (!config.app?.moduleEntry) return null;
|
|
3827
|
+
try {
|
|
3828
|
+
const tsconfigPath = config.app.tsconfig ?? (0, import_node_path5.join)(config.codegen.cwd, "tsconfig.json");
|
|
3829
|
+
let project;
|
|
3830
|
+
try {
|
|
3831
|
+
project = sharedPropsProject(tsconfigPath);
|
|
3832
|
+
} catch {
|
|
3833
|
+
project = new import_ts_morph13.Project({
|
|
3834
|
+
skipAddingFilesFromTsConfig: true,
|
|
3835
|
+
skipLoadingLibFiles: true,
|
|
3836
|
+
skipFileDependencyResolution: true,
|
|
3837
|
+
compilerOptions: { allowJs: true, strict: false }
|
|
3838
|
+
});
|
|
3839
|
+
}
|
|
3840
|
+
return discoverSharedProps(project, config.app.moduleEntry);
|
|
3841
|
+
} catch {
|
|
3842
|
+
return null;
|
|
3843
|
+
}
|
|
3844
|
+
}
|
|
3845
|
+
var parsedTsconfigs = /* @__PURE__ */ new Map();
|
|
3846
|
+
function readText(file) {
|
|
3847
|
+
try {
|
|
3848
|
+
return (0, import_node_fs3.readFileSync)(file, "utf8");
|
|
3849
|
+
} catch {
|
|
3850
|
+
return "\0missing";
|
|
3851
|
+
}
|
|
3852
|
+
}
|
|
3853
|
+
function sharedPropsProject(tsconfigPath) {
|
|
3854
|
+
const text = loadDiscoveryTsconfig(tsconfigPath).files.map((file) => `${file}\0${readText(file)}`).join("\0");
|
|
3855
|
+
const flags = {
|
|
3856
|
+
skipAddingFilesFromTsConfig: true,
|
|
3857
|
+
skipLoadingLibFiles: true,
|
|
3858
|
+
skipFileDependencyResolution: true
|
|
3859
|
+
};
|
|
3860
|
+
const parsed = parsedTsconfigs.get(tsconfigPath);
|
|
3861
|
+
if (parsed?.text === text) return new import_ts_morph13.Project({ ...flags, compilerOptions: parsed.options });
|
|
3862
|
+
const project = new import_ts_morph13.Project({ ...flags, tsConfigFilePath: tsconfigPath });
|
|
3863
|
+
parsedTsconfigs.set(tsconfigPath, { text, options: project.getCompilerOptions() });
|
|
3864
|
+
return project;
|
|
3865
|
+
}
|
|
3866
|
+
function findForRootCall(sourceFile) {
|
|
3867
|
+
const callExpressions = sourceFile.getDescendantsOfKind(import_ts_morph13.SyntaxKind.CallExpression);
|
|
3868
|
+
for (const call of callExpressions) {
|
|
3869
|
+
const expr = call.getExpression();
|
|
3870
|
+
if (!import_ts_morph13.Node.isPropertyAccessExpression(expr)) continue;
|
|
3871
|
+
const methodName = expr.getName();
|
|
3872
|
+
const objectExpr = expr.getExpression();
|
|
3873
|
+
if (methodName === "forRoot" && import_ts_morph13.Node.isIdentifier(objectExpr)) {
|
|
3874
|
+
const name = objectExpr.getText();
|
|
3875
|
+
if (name === "InertiaModule") {
|
|
3876
|
+
return call;
|
|
3877
|
+
}
|
|
3878
|
+
}
|
|
3879
|
+
}
|
|
3880
|
+
return null;
|
|
3881
|
+
}
|
|
3882
|
+
function findShareInitializer(forRootCall) {
|
|
3883
|
+
if (!import_ts_morph13.Node.isCallExpression(forRootCall)) return null;
|
|
3884
|
+
const args = forRootCall.getArguments();
|
|
3885
|
+
const firstArg2 = args[0];
|
|
3886
|
+
if (!firstArg2 || !import_ts_morph13.Node.isObjectLiteralExpression(firstArg2)) return null;
|
|
3887
|
+
for (const prop of firstArg2.getProperties()) {
|
|
3888
|
+
if (import_ts_morph13.Node.isPropertyAssignment(prop) && prop.getName() === "share") {
|
|
3889
|
+
return prop.getInitializer() ?? null;
|
|
3890
|
+
}
|
|
3891
|
+
}
|
|
3892
|
+
return null;
|
|
3893
|
+
}
|
|
3894
|
+
function extractShareType(node, sourceFile, project) {
|
|
3895
|
+
if (import_ts_morph13.Node.isIdentifier(node)) {
|
|
3896
|
+
const ref = resolveIdentifierToImportRef(node, sourceFile, project);
|
|
3897
|
+
if (ref) {
|
|
3898
|
+
return {
|
|
3899
|
+
typeString: `Awaited<ReturnType<typeof import('${ref.importPath}').${ref.exportName}>>`,
|
|
3900
|
+
properties: null,
|
|
3901
|
+
isImportRef: true
|
|
3902
|
+
};
|
|
3903
|
+
}
|
|
3904
|
+
}
|
|
3905
|
+
if (import_ts_morph13.Node.isArrowFunction(node)) {
|
|
3906
|
+
const result = extractFromFunctionLike(node, sourceFile);
|
|
3907
|
+
return result ? { ...result, isImportRef: false } : null;
|
|
3908
|
+
}
|
|
3909
|
+
if (import_ts_morph13.Node.isFunctionExpression(node)) {
|
|
3910
|
+
const result = extractFromFunctionLike(node, sourceFile);
|
|
3911
|
+
return result ? { ...result, isImportRef: false } : null;
|
|
3912
|
+
}
|
|
3913
|
+
if (import_ts_morph13.Node.isObjectLiteralExpression(node)) {
|
|
3914
|
+
const result = extractFromObjectLiteral(node);
|
|
3915
|
+
return result ? { ...result, isImportRef: false } : null;
|
|
3916
|
+
}
|
|
3917
|
+
return null;
|
|
3918
|
+
}
|
|
3919
|
+
function resolveIdentifierToImportRef(id, sourceFile, project) {
|
|
3920
|
+
if (!import_ts_morph13.Node.isIdentifier(id)) return null;
|
|
3921
|
+
const name = id.getText();
|
|
3922
|
+
const localFunc = sourceFile.getFunction(name);
|
|
3923
|
+
if (localFunc?.isExported()) {
|
|
3924
|
+
const filePath = sourceFile.getFilePath().replace(/\.ts$/, "");
|
|
3925
|
+
return { importPath: filePath, exportName: name };
|
|
3926
|
+
}
|
|
3927
|
+
const localVar = sourceFile.getVariableDeclaration(name);
|
|
3928
|
+
if (localVar?.isExported()) {
|
|
3929
|
+
const filePath = sourceFile.getFilePath().replace(/\.ts$/, "");
|
|
3930
|
+
return { importPath: filePath, exportName: name };
|
|
3931
|
+
}
|
|
3932
|
+
for (const imp of sourceFile.getImportDeclarations()) {
|
|
3933
|
+
for (const named of imp.getNamedImports()) {
|
|
3934
|
+
const importedName = named.getAliasNode()?.getText() ?? named.getName();
|
|
3935
|
+
if (importedName !== name) continue;
|
|
3936
|
+
const resolvedSource = imp.getModuleSpecifierSourceFile();
|
|
3937
|
+
if (!resolvedSource) continue;
|
|
3938
|
+
const originalName = named.getName();
|
|
3939
|
+
const fn = resolvedSource.getFunction(originalName);
|
|
3940
|
+
if (fn?.isExported()) {
|
|
3941
|
+
const filePath = resolvedSource.getFilePath().replace(/\.ts$/, "");
|
|
3942
|
+
return { importPath: filePath, exportName: originalName };
|
|
3943
|
+
}
|
|
3944
|
+
const v = resolvedSource.getVariableDeclaration(originalName);
|
|
3945
|
+
if (v?.isExported()) {
|
|
3946
|
+
const filePath = resolvedSource.getFilePath().replace(/\.ts$/, "");
|
|
3947
|
+
return { importPath: filePath, exportName: originalName };
|
|
3948
|
+
}
|
|
3949
|
+
}
|
|
3950
|
+
}
|
|
3951
|
+
return null;
|
|
3952
|
+
}
|
|
3953
|
+
function extractFromFunctionLike(node, _sourceFile) {
|
|
3954
|
+
const returnTypeNode = import_ts_morph13.Node.isArrowFunction(node) || import_ts_morph13.Node.isFunctionExpression(node) ? node.getReturnTypeNode() : null;
|
|
3955
|
+
if (returnTypeNode) {
|
|
3956
|
+
return extractFromReturnTypeAnnotation(returnTypeNode);
|
|
3957
|
+
}
|
|
3958
|
+
if (import_ts_morph13.Node.isArrowFunction(node)) {
|
|
3959
|
+
const body = node.getBody();
|
|
3960
|
+
if (import_ts_morph13.Node.isParenthesizedExpression(body)) {
|
|
3961
|
+
const inner = body.getExpression();
|
|
3962
|
+
if (import_ts_morph13.Node.isObjectLiteralExpression(inner)) {
|
|
3963
|
+
return extractFromObjectLiteral(inner);
|
|
3964
|
+
}
|
|
3965
|
+
}
|
|
3966
|
+
if (import_ts_morph13.Node.isObjectLiteralExpression(body)) {
|
|
3967
|
+
return extractFromObjectLiteral(body);
|
|
3968
|
+
}
|
|
3969
|
+
if (import_ts_morph13.Node.isBlock(body)) {
|
|
3970
|
+
return extractFromBlockReturn(body);
|
|
3971
|
+
}
|
|
3972
|
+
}
|
|
3973
|
+
if (import_ts_morph13.Node.isFunctionExpression(node)) {
|
|
3974
|
+
const body = node.getBody();
|
|
3975
|
+
if (import_ts_morph13.Node.isBlock(body)) {
|
|
3976
|
+
return extractFromBlockReturn(body);
|
|
3977
|
+
}
|
|
3978
|
+
}
|
|
3979
|
+
return null;
|
|
3980
|
+
}
|
|
3981
|
+
function extractFromReturnTypeAnnotation(typeNode) {
|
|
3982
|
+
if (import_ts_morph13.Node.isTypeReference(typeNode)) {
|
|
3983
|
+
const typeName = typeNode.getTypeName();
|
|
3984
|
+
if (import_ts_morph13.Node.isIdentifier(typeName) && typeName.getText() === "Promise") {
|
|
3985
|
+
const typeArgs = typeNode.getTypeArguments();
|
|
3986
|
+
const firstArg2 = typeArgs[0];
|
|
3987
|
+
if (firstArg2) {
|
|
3988
|
+
return extractFromReturnTypeAnnotation(firstArg2);
|
|
3989
|
+
}
|
|
3990
|
+
return null;
|
|
3991
|
+
}
|
|
3992
|
+
}
|
|
3993
|
+
if (import_ts_morph13.Node.isTypeLiteral(typeNode)) {
|
|
3994
|
+
const properties = [];
|
|
3995
|
+
for (const member of typeNode.getMembers()) {
|
|
3996
|
+
if (import_ts_morph13.Node.isPropertySignature(member)) {
|
|
3997
|
+
const name = member.getName();
|
|
3998
|
+
const memberTypeNode = member.getTypeNode();
|
|
3999
|
+
const type = memberTypeNode ? memberTypeNode.getText() : "unknown";
|
|
4000
|
+
properties.push({ name, type });
|
|
4001
|
+
}
|
|
4002
|
+
}
|
|
4003
|
+
if (properties.length === 0) return null;
|
|
4004
|
+
const typeString = `{ ${properties.map((p) => `${p.name}: ${p.type}`).join("; ")} }`;
|
|
4005
|
+
return { typeString, properties, isImportRef: false };
|
|
4006
|
+
}
|
|
4007
|
+
return null;
|
|
4008
|
+
}
|
|
4009
|
+
function extractFromBlockReturn(block) {
|
|
4010
|
+
if (!import_ts_morph13.Node.isBlock(block)) return null;
|
|
4011
|
+
const statements = block.getStatements();
|
|
4012
|
+
for (let i = statements.length - 1; i >= 0; i--) {
|
|
4013
|
+
const stmt = statements[i];
|
|
4014
|
+
if (!import_ts_morph13.Node.isReturnStatement(stmt)) continue;
|
|
4015
|
+
const expr = stmt.getExpression();
|
|
4016
|
+
if (!expr) continue;
|
|
4017
|
+
if (import_ts_morph13.Node.isObjectLiteralExpression(expr)) {
|
|
4018
|
+
return extractFromObjectLiteral(expr);
|
|
4019
|
+
}
|
|
4020
|
+
if (import_ts_morph13.Node.isParenthesizedExpression(expr)) {
|
|
4021
|
+
const inner = expr.getExpression();
|
|
4022
|
+
if (import_ts_morph13.Node.isObjectLiteralExpression(inner)) {
|
|
4023
|
+
return extractFromObjectLiteral(inner);
|
|
4024
|
+
}
|
|
4025
|
+
}
|
|
4026
|
+
break;
|
|
4027
|
+
}
|
|
4028
|
+
return null;
|
|
4029
|
+
}
|
|
4030
|
+
function extractFromObjectLiteral(objLiteral) {
|
|
4031
|
+
if (!import_ts_morph13.Node.isObjectLiteralExpression(objLiteral)) return null;
|
|
4032
|
+
const properties = [];
|
|
4033
|
+
for (const prop of objLiteral.getProperties()) {
|
|
4034
|
+
if (!import_ts_morph13.Node.isPropertyAssignment(prop)) continue;
|
|
4035
|
+
const name = prop.getName();
|
|
4036
|
+
const initializer = prop.getInitializer();
|
|
4037
|
+
if (!initializer) continue;
|
|
4038
|
+
const type = inferExpressionType(initializer);
|
|
4039
|
+
properties.push({ name, type });
|
|
4040
|
+
}
|
|
4041
|
+
if (properties.length === 0) return null;
|
|
4042
|
+
const typeString = `{ ${properties.map((p) => `${p.name}: ${p.type}`).join("; ")} }`;
|
|
4043
|
+
return { typeString, properties, isImportRef: false };
|
|
4044
|
+
}
|
|
4045
|
+
function inferExpressionType(node) {
|
|
4046
|
+
if (import_ts_morph13.Node.isStringLiteral(node)) return "string";
|
|
4047
|
+
if (import_ts_morph13.Node.isTemplateExpression(node) || import_ts_morph13.Node.isNoSubstitutionTemplateLiteral(node))
|
|
4048
|
+
return "string";
|
|
4049
|
+
if (import_ts_morph13.Node.isNumericLiteral(node)) return "number";
|
|
4050
|
+
if (node.getKind() === import_ts_morph13.SyntaxKind.TrueKeyword || node.getKind() === import_ts_morph13.SyntaxKind.FalseKeyword) {
|
|
4051
|
+
return "boolean";
|
|
4052
|
+
}
|
|
4053
|
+
if (node.getKind() === import_ts_morph13.SyntaxKind.NullKeyword) return "null";
|
|
4054
|
+
if (import_ts_morph13.Node.isIdentifier(node) && node.getText() === "undefined") return "undefined";
|
|
4055
|
+
if (import_ts_morph13.Node.isObjectLiteralExpression(node)) {
|
|
4056
|
+
const props = node.getProperties();
|
|
4057
|
+
if (props.length === 0) return "Record<string, unknown>";
|
|
4058
|
+
const entries = [];
|
|
4059
|
+
for (const prop of props) {
|
|
4060
|
+
if (!import_ts_morph13.Node.isPropertyAssignment(prop)) continue;
|
|
4061
|
+
const key = prop.getName();
|
|
4062
|
+
const init = prop.getInitializer();
|
|
4063
|
+
if (!init) continue;
|
|
4064
|
+
entries.push(`${key}: ${inferExpressionType(init)}`);
|
|
4065
|
+
}
|
|
4066
|
+
if (entries.length === 0) return "Record<string, unknown>";
|
|
4067
|
+
return `{ ${entries.join("; ")} }`;
|
|
4068
|
+
}
|
|
4069
|
+
if (import_ts_morph13.Node.isArrayLiteralExpression(node)) {
|
|
4070
|
+
const elements = node.getElements();
|
|
4071
|
+
if (elements.length === 0) return "Array<unknown>";
|
|
4072
|
+
const first = elements[0];
|
|
4073
|
+
if (first) return `Array<${inferExpressionType(first)}>`;
|
|
4074
|
+
return "Array<unknown>";
|
|
4075
|
+
}
|
|
4076
|
+
if (import_ts_morph13.Node.isConditionalExpression(node)) {
|
|
4077
|
+
const whenTrue = inferExpressionType(node.getWhenTrue());
|
|
4078
|
+
const whenFalse = inferExpressionType(node.getWhenFalse());
|
|
4079
|
+
if (whenTrue === whenFalse) return whenTrue;
|
|
4080
|
+
return `${whenTrue} | ${whenFalse}`;
|
|
4081
|
+
}
|
|
4082
|
+
if (import_ts_morph13.Node.isParenthesizedExpression(node)) {
|
|
4083
|
+
return inferExpressionType(node.getExpression());
|
|
4084
|
+
}
|
|
4085
|
+
if (import_ts_morph13.Node.isAsExpression(node)) {
|
|
4086
|
+
const typeNode = node.getTypeNode();
|
|
4087
|
+
if (typeNode) return typeNode.getText();
|
|
4088
|
+
}
|
|
4089
|
+
return "unknown";
|
|
4090
|
+
}
|
|
4091
|
+
|
|
4092
|
+
// src/emit/emit-api.ts
|
|
4093
|
+
var import_promises3 = require("fs/promises");
|
|
4094
|
+
var import_node_path7 = require("path");
|
|
4095
|
+
|
|
3857
4096
|
// src/extension/registry.ts
|
|
4097
|
+
var import_node_path6 = require("path");
|
|
4098
|
+
var import_ts_morph14 = require("ts-morph");
|
|
3858
4099
|
function resolveApiSlots(extensions) {
|
|
3859
4100
|
let layer;
|
|
3860
4101
|
let layerOwner;
|
|
@@ -3905,7 +4146,7 @@ function createExtensionContext(config, getRoutes, trackedInputs) {
|
|
|
3905
4146
|
},
|
|
3906
4147
|
project() {
|
|
3907
4148
|
if (!project) {
|
|
3908
|
-
project = new
|
|
4149
|
+
project = new import_ts_morph14.Project({
|
|
3909
4150
|
skipAddingFilesFromTsConfig: true,
|
|
3910
4151
|
skipLoadingLibFiles: true,
|
|
3911
4152
|
skipFileDependencyResolution: true,
|
|
@@ -5636,36 +5877,64 @@ async function discoverInputFiles(config) {
|
|
|
5636
5877
|
const matched = await (0, import_fast_glob3.default)(globs, { cwd, absolute: true, onlyFiles: true });
|
|
5637
5878
|
return [...new Set(matched)].sort();
|
|
5638
5879
|
}
|
|
5639
|
-
|
|
5880
|
+
var READ_CONCURRENCY = 64;
|
|
5881
|
+
async function readAll(paths, read) {
|
|
5882
|
+
const out = /* @__PURE__ */ new Map();
|
|
5883
|
+
for (let i = 0; i < paths.length; i += READ_CONCURRENCY) {
|
|
5884
|
+
const batch = paths.slice(i, i + READ_CONCURRENCY);
|
|
5885
|
+
const texts = await Promise.all(batch.map(read));
|
|
5886
|
+
batch.forEach((path, j) => out.set(path, texts[j]));
|
|
5887
|
+
}
|
|
5888
|
+
return out;
|
|
5889
|
+
}
|
|
5890
|
+
async function readInputs(config) {
|
|
5891
|
+
const cwd = config.codegen.cwd;
|
|
5892
|
+
const tsconfigPath = resolveTsconfigPath(cwd, config.app?.tsconfig ?? void 0);
|
|
5893
|
+
const extended = loadDiscoveryTsconfig(tsconfigPath).files;
|
|
5894
|
+
const tsconfigFiles = extended.length > 0 ? extended : [tsconfigPath];
|
|
5895
|
+
const files = await discoverInputFiles(config);
|
|
5896
|
+
const contents = /* @__PURE__ */ new Map();
|
|
5897
|
+
const tsconfigs = await readAll(
|
|
5898
|
+
tsconfigFiles,
|
|
5899
|
+
(file) => (0, import_promises11.readFile)(file, "utf8").catch(() => null)
|
|
5900
|
+
);
|
|
5901
|
+
for (const [file, text] of tsconfigs) contents.set(file, text);
|
|
5902
|
+
for (const [file, text] of await readAll(files, (file2) => (0, import_promises11.readFile)(file2, "utf8"))) {
|
|
5903
|
+
contents.set(file, text);
|
|
5904
|
+
}
|
|
5905
|
+
return { tsconfigFiles, files, contents, tracked: /* @__PURE__ */ new Map() };
|
|
5906
|
+
}
|
|
5907
|
+
async function readInput(snapshot, path) {
|
|
5908
|
+
return snapshot.contents.get(path) ?? (0, import_promises11.readFile)(path, "utf8");
|
|
5909
|
+
}
|
|
5910
|
+
async function computeInputsHash(config, extraInputs = [], snapshot) {
|
|
5911
|
+
const inputs = snapshot ?? await readInputs(config);
|
|
5640
5912
|
const hash = (0, import_node_crypto.createHash)("sha256");
|
|
5641
5913
|
hash.update(`version:${VERSION}
|
|
5642
5914
|
`);
|
|
5643
5915
|
hash.update(`config:${serializeConfig(config)}
|
|
5644
5916
|
`);
|
|
5645
5917
|
const cwd = config.codegen.cwd;
|
|
5646
|
-
const
|
|
5647
|
-
const tsconfigFiles = loadDiscoveryTsconfig(tsconfigPath).files;
|
|
5648
|
-
for (const file of tsconfigFiles.length > 0 ? tsconfigFiles : [tsconfigPath]) {
|
|
5649
|
-
const contents = await (0, import_promises11.readFile)(file, "utf8").catch(() => null);
|
|
5918
|
+
for (const file of inputs.tsconfigFiles) {
|
|
5650
5919
|
hash.update(`tsconfig:${(0, import_node_path15.relative)(cwd, file)}
|
|
5651
5920
|
`);
|
|
5652
|
-
hash.update(contents ?? " missing");
|
|
5921
|
+
hash.update(inputs.contents.get(file) ?? " missing");
|
|
5653
5922
|
hash.update("\n");
|
|
5654
5923
|
}
|
|
5655
|
-
const
|
|
5656
|
-
const globbedRelative = new Set(globbed.map((file) => (0, import_node_path15.relative)(cwd, file)));
|
|
5924
|
+
const globbedRelative = new Set(inputs.files.map((file) => (0, import_node_path15.relative)(cwd, file)));
|
|
5657
5925
|
const extra = [...new Set(extraInputs)].filter((file) => !globbedRelative.has(file)).sort();
|
|
5658
|
-
for (const file of
|
|
5659
|
-
const contents = await (0, import_promises11.readFile)(file, "utf8");
|
|
5926
|
+
for (const file of inputs.files) {
|
|
5660
5927
|
hash.update(`file:${(0, import_node_path15.relative)(cwd, file)}
|
|
5661
5928
|
`);
|
|
5662
|
-
hash.update(contents);
|
|
5929
|
+
hash.update(inputs.contents.get(file));
|
|
5663
5930
|
hash.update("\n");
|
|
5664
5931
|
}
|
|
5932
|
+
const unread = extra.map((file) => (0, import_node_path15.join)(cwd, file)).filter((abs) => !inputs.tracked.has(abs));
|
|
5933
|
+
for (const [abs, text] of await readAll(unread, readTrackedInput)) inputs.tracked.set(abs, text);
|
|
5665
5934
|
for (const file of extra) {
|
|
5666
5935
|
hash.update(`extra:${file}
|
|
5667
5936
|
`);
|
|
5668
|
-
hash.update(
|
|
5937
|
+
hash.update(inputs.tracked.get((0, import_node_path15.join)(cwd, file)));
|
|
5669
5938
|
hash.update("\n");
|
|
5670
5939
|
}
|
|
5671
5940
|
return hash.digest("hex");
|
|
@@ -5746,7 +6015,8 @@ function driftGuardMessage(outDir, previousEntryPoint, currentEntryPoint, differ
|
|
|
5746
6015
|
async function generate(config, inputRoutes = [], entryPoint = "cli") {
|
|
5747
6016
|
setCodegenDebug(config.debug);
|
|
5748
6017
|
const manifest = await readManifest(config.codegen.outDir);
|
|
5749
|
-
const
|
|
6018
|
+
const inputs = await readInputs(config);
|
|
6019
|
+
const inputsHash = await computeInputsHash(config, manifest?.extraInputs ?? [], inputs);
|
|
5750
6020
|
if (await isManifestFresh(config.codegen.outDir, manifest, inputsHash)) {
|
|
5751
6021
|
console.log(`[nestjs-codegen] ${config.codegen.outDir} up to date, skipped`);
|
|
5752
6022
|
return;
|
|
@@ -5774,7 +6044,7 @@ async function generate(config, inputRoutes = [], entryPoint = "cli") {
|
|
|
5774
6044
|
}
|
|
5775
6045
|
if (config.pages) {
|
|
5776
6046
|
const pagesConfig = config.pages;
|
|
5777
|
-
const pages = await discoverPageScopes(config);
|
|
6047
|
+
const pages = await discoverPageScopes(config, (path) => readInput(inputs, path));
|
|
5778
6048
|
const sharedProps = discoverSharedPropsFromConfig(config);
|
|
5779
6049
|
await emitPages(pages, config.codegen.outDir, {
|
|
5780
6050
|
propsExport: pagesConfig.propsExport,
|
|
@@ -5824,7 +6094,7 @@ async function generate(config, inputRoutes = [], entryPoint = "cli") {
|
|
|
5824
6094
|
}
|
|
5825
6095
|
const outputFiles = await listOutputFiles(config.codegen.outDir);
|
|
5826
6096
|
const extraInputs = [...trackedInputs].sort();
|
|
5827
|
-
const recordedHash = extraInputs.length > 0 ? await computeInputsHash(config, extraInputs) : inputsHash;
|
|
6097
|
+
const recordedHash = extraInputs.length > 0 ? await computeInputsHash(config, extraInputs, inputs) : inputsHash;
|
|
5828
6098
|
await writeManifest(config.codegen.outDir, {
|
|
5829
6099
|
version: VERSION,
|
|
5830
6100
|
hash: recordedHash,
|
|
@@ -6007,13 +6277,15 @@ async function watch(config, onChange, options = {}) {
|
|
|
6007
6277
|
pagesWatcher.on("unlink", schedulePagesRegenerate);
|
|
6008
6278
|
let contractsDebounceTimer;
|
|
6009
6279
|
const pendingChangedPaths = /* @__PURE__ */ new Set();
|
|
6280
|
+
let pendingAddedOrRemoved = false;
|
|
6010
6281
|
const contractsWatcher = import_chokidar.default.watch((0, import_node_path18.join)(config.codegen.cwd, config.contracts.glob), {
|
|
6011
6282
|
ignoreInitial: true,
|
|
6012
6283
|
persistent: true,
|
|
6013
6284
|
awaitWriteFinish: { stabilityThreshold: 80, pollInterval: 20 }
|
|
6014
6285
|
});
|
|
6015
|
-
function scheduleContractsRegenerate(changedPath) {
|
|
6286
|
+
function scheduleContractsRegenerate(changedPath, addedOrRemoved = false) {
|
|
6016
6287
|
if (typeof changedPath === "string") pendingChangedPaths.add(changedPath);
|
|
6288
|
+
if (addedOrRemoved) pendingAddedOrRemoved = true;
|
|
6017
6289
|
if (contractsDebounceTimer !== void 0) {
|
|
6018
6290
|
clearTimeout(contractsDebounceTimer);
|
|
6019
6291
|
}
|
|
@@ -6021,8 +6293,12 @@ async function watch(config, onChange, options = {}) {
|
|
|
6021
6293
|
contractsDebounceTimer = void 0;
|
|
6022
6294
|
const changed = [...pendingChangedPaths];
|
|
6023
6295
|
pendingChangedPaths.clear();
|
|
6296
|
+
const filesAddedOrRemoved = pendingAddedOrRemoved;
|
|
6297
|
+
pendingAddedOrRemoved = false;
|
|
6024
6298
|
try {
|
|
6025
|
-
const routes = await (await getDiscovery()).rediscover(changed
|
|
6299
|
+
const routes = await (await getDiscovery()).rediscover(changed, {
|
|
6300
|
+
filesAddedOrRemoved
|
|
6301
|
+
});
|
|
6026
6302
|
lastRoutes = routes;
|
|
6027
6303
|
await generateAndTrack(routes);
|
|
6028
6304
|
} catch (err) {
|
|
@@ -6034,20 +6310,20 @@ async function watch(config, onChange, options = {}) {
|
|
|
6034
6310
|
onChange?.();
|
|
6035
6311
|
}, config.contracts.debounceMs);
|
|
6036
6312
|
}
|
|
6037
|
-
contractsWatcher.on("add", (p) => scheduleContractsRegenerate(p));
|
|
6313
|
+
contractsWatcher.on("add", (p) => scheduleContractsRegenerate(p, true));
|
|
6038
6314
|
contractsWatcher.on("change", (p) => scheduleContractsRegenerate(p));
|
|
6039
|
-
contractsWatcher.on("unlink", (p) => scheduleContractsRegenerate(p));
|
|
6315
|
+
contractsWatcher.on("unlink", (p) => scheduleContractsRegenerate(p, true));
|
|
6040
6316
|
const formsWatcher = import_chokidar.default.watch((0, import_node_path18.join)(config.codegen.cwd, config.forms.watch), {
|
|
6041
6317
|
ignoreInitial: true,
|
|
6042
6318
|
persistent: true,
|
|
6043
6319
|
awaitWriteFinish: { stabilityThreshold: 80, pollInterval: 20 }
|
|
6044
6320
|
});
|
|
6045
|
-
formsWatcher.on("add", (p) => scheduleContractsRegenerate(p));
|
|
6321
|
+
formsWatcher.on("add", (p) => scheduleContractsRegenerate(p, true));
|
|
6046
6322
|
formsWatcher.on("change", (p) => scheduleContractsRegenerate(p));
|
|
6047
|
-
formsWatcher.on("unlink", (p) => scheduleContractsRegenerate(p));
|
|
6048
|
-
trackedWatcher.on("add", (p) => scheduleContractsRegenerate(p));
|
|
6323
|
+
formsWatcher.on("unlink", (p) => scheduleContractsRegenerate(p, true));
|
|
6324
|
+
trackedWatcher.on("add", (p) => scheduleContractsRegenerate(p, true));
|
|
6049
6325
|
trackedWatcher.on("change", (p) => scheduleContractsRegenerate(p));
|
|
6050
|
-
trackedWatcher.on("unlink", (p) => scheduleContractsRegenerate(p));
|
|
6326
|
+
trackedWatcher.on("unlink", (p) => scheduleContractsRegenerate(p, true));
|
|
6051
6327
|
return {
|
|
6052
6328
|
close: async () => {
|
|
6053
6329
|
if (pagesDebounceTimer !== void 0) {
|
|
@@ -6068,7 +6344,7 @@ async function watch(config, onChange, options = {}) {
|
|
|
6068
6344
|
}
|
|
6069
6345
|
|
|
6070
6346
|
// src/index.ts
|
|
6071
|
-
var VERSION = "0.
|
|
6347
|
+
var VERSION = "0.29.1";
|
|
6072
6348
|
|
|
6073
6349
|
// src/cli/codegen.ts
|
|
6074
6350
|
async function runCodegen(opts = {}) {
|
|
@@ -6096,28 +6372,28 @@ async function runCodegen(opts = {}) {
|
|
|
6096
6372
|
|
|
6097
6373
|
// src/cli/doctor.ts
|
|
6098
6374
|
var import_node_child_process2 = require("child_process");
|
|
6099
|
-
var
|
|
6375
|
+
var import_node_fs6 = require("fs");
|
|
6100
6376
|
var import_node_path20 = require("path");
|
|
6101
6377
|
|
|
6102
6378
|
// src/cli/init.ts
|
|
6103
6379
|
var import_node_child_process = require("child_process");
|
|
6104
|
-
var
|
|
6380
|
+
var import_node_fs5 = require("fs");
|
|
6105
6381
|
var import_promises16 = require("fs/promises");
|
|
6106
6382
|
var import_node_path19 = require("path");
|
|
6107
6383
|
var import_node_readline = require("readline");
|
|
6108
6384
|
|
|
6109
6385
|
// src/cli/patch-utils.ts
|
|
6110
|
-
var
|
|
6386
|
+
var import_node_fs4 = require("fs");
|
|
6111
6387
|
function patchJsonFile(filePath, mutator, parse = (raw) => raw) {
|
|
6112
6388
|
let raw;
|
|
6113
6389
|
try {
|
|
6114
|
-
raw = (0,
|
|
6390
|
+
raw = (0, import_node_fs4.readFileSync)(filePath, "utf8");
|
|
6115
6391
|
} catch {
|
|
6116
6392
|
return "skipped";
|
|
6117
6393
|
}
|
|
6118
6394
|
const json = JSON.parse(parse(raw));
|
|
6119
6395
|
if (!mutator(json)) return "already";
|
|
6120
|
-
(0,
|
|
6396
|
+
(0, import_node_fs4.writeFileSync)(filePath, `${JSON.stringify(json, null, 2)}
|
|
6121
6397
|
`, "utf8");
|
|
6122
6398
|
return "patched";
|
|
6123
6399
|
}
|
|
@@ -6329,7 +6605,7 @@ async function patchPackageJsonScripts(cwd, scripts) {
|
|
|
6329
6605
|
function patchAppModule(filePath, rootView) {
|
|
6330
6606
|
let content;
|
|
6331
6607
|
try {
|
|
6332
|
-
content = (0,
|
|
6608
|
+
content = (0, import_node_fs5.readFileSync)(filePath, "utf8");
|
|
6333
6609
|
} catch {
|
|
6334
6610
|
return "skipped";
|
|
6335
6611
|
}
|
|
@@ -6364,13 +6640,13 @@ ${indent}HomeController,${content.slice(bracketPos)}`;
|
|
|
6364
6640
|
}
|
|
6365
6641
|
}
|
|
6366
6642
|
if (!changed) return "already";
|
|
6367
|
-
(0,
|
|
6643
|
+
(0, import_node_fs5.writeFileSync)(filePath, content, "utf8");
|
|
6368
6644
|
return "patched";
|
|
6369
6645
|
}
|
|
6370
6646
|
function patchMainTs(filePath) {
|
|
6371
6647
|
let content;
|
|
6372
6648
|
try {
|
|
6373
|
-
content = (0,
|
|
6649
|
+
content = (0, import_node_fs5.readFileSync)(filePath, "utf8");
|
|
6374
6650
|
} catch {
|
|
6375
6651
|
return "skipped";
|
|
6376
6652
|
}
|
|
@@ -6395,7 +6671,7 @@ function patchMainTs(filePath) {
|
|
|
6395
6671
|
});`;
|
|
6396
6672
|
content = `${content.slice(0, insertAfterPos)}
|
|
6397
6673
|
${viteSetup}${content.slice(insertAfterPos)}`;
|
|
6398
|
-
(0,
|
|
6674
|
+
(0, import_node_fs5.writeFileSync)(filePath, content, "utf8");
|
|
6399
6675
|
return "patched";
|
|
6400
6676
|
}
|
|
6401
6677
|
function configTemplate(framework) {
|
|
@@ -6850,18 +7126,18 @@ ${green("\u2713")} Setup complete! Run: ${bold("nest start --watch")}
|
|
|
6850
7126
|
|
|
6851
7127
|
// src/cli/doctor.ts
|
|
6852
7128
|
function checkFileExists(cwd, file) {
|
|
6853
|
-
return (0,
|
|
7129
|
+
return (0, import_node_fs6.existsSync)((0, import_node_path20.join)(cwd, file));
|
|
6854
7130
|
}
|
|
6855
7131
|
function readJson(path) {
|
|
6856
7132
|
try {
|
|
6857
|
-
const raw = (0,
|
|
7133
|
+
const raw = (0, import_node_fs6.readFileSync)(path, "utf8").replace(/\/\/.*$/gm, "");
|
|
6858
7134
|
return JSON.parse(raw);
|
|
6859
7135
|
} catch {
|
|
6860
7136
|
return null;
|
|
6861
7137
|
}
|
|
6862
7138
|
}
|
|
6863
7139
|
function writeJsonField(filePath, dotPath, value) {
|
|
6864
|
-
const raw = (0,
|
|
7140
|
+
const raw = (0, import_node_fs6.readFileSync)(filePath, "utf8");
|
|
6865
7141
|
const stripped = raw.replace(/\/\/.*$/gm, "");
|
|
6866
7142
|
const obj = JSON.parse(stripped);
|
|
6867
7143
|
let target = obj;
|
|
@@ -6881,7 +7157,7 @@ function writeJsonField(filePath, dotPath, value) {
|
|
|
6881
7157
|
} else {
|
|
6882
7158
|
target[lastKey] = value;
|
|
6883
7159
|
}
|
|
6884
|
-
(0,
|
|
7160
|
+
(0, import_node_fs6.writeFileSync)(filePath, `${JSON.stringify(obj, null, 2)}
|
|
6885
7161
|
`, "utf8");
|
|
6886
7162
|
}
|
|
6887
7163
|
function getPackageVersion(cwd, pkg) {
|
|
@@ -6893,8 +7169,8 @@ function getPackageVersion(cwd, pkg) {
|
|
|
6893
7169
|
}
|
|
6894
7170
|
}
|
|
6895
7171
|
function detectPkgManager(cwd) {
|
|
6896
|
-
if ((0,
|
|
6897
|
-
if ((0,
|
|
7172
|
+
if ((0, import_node_fs6.existsSync)((0, import_node_path20.join)(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
7173
|
+
if ((0, import_node_fs6.existsSync)((0, import_node_path20.join)(cwd, "yarn.lock"))) return "yarn";
|
|
6898
7174
|
return "npm";
|
|
6899
7175
|
}
|
|
6900
7176
|
async function runDoctor(opts) {
|
|
@@ -7015,7 +7291,7 @@ async function runDoctor(opts) {
|
|
|
7015
7291
|
pass: !!inertiaTsconfig,
|
|
7016
7292
|
fix: "Create tsconfig.inertia.json (typechecks inertia/ + .nestjs-inertia/)",
|
|
7017
7293
|
autoFix: () => {
|
|
7018
|
-
(0,
|
|
7294
|
+
(0, import_node_fs6.writeFileSync)(inertiaTsconfigPath, TSCONFIG_INERTIA_TEMPLATE, "utf8");
|
|
7019
7295
|
}
|
|
7020
7296
|
});
|
|
7021
7297
|
if (inertiaTsconfig) {
|
|
@@ -7063,14 +7339,14 @@ async function runDoctor(opts) {
|
|
|
7063
7339
|
const innerTsconfigPath = (0, import_node_path20.join)(cwd, "inertia", "tsconfig.json");
|
|
7064
7340
|
checks.push({
|
|
7065
7341
|
name: "inertia/tsconfig.json exists (VSCode picks up ~codegen alias)",
|
|
7066
|
-
pass: (0,
|
|
7342
|
+
pass: (0, import_node_fs6.existsSync)(innerTsconfigPath),
|
|
7067
7343
|
fix: "Create inertia/tsconfig.json that extends ../tsconfig.inertia.json",
|
|
7068
7344
|
autoFix: () => {
|
|
7069
|
-
(0,
|
|
7345
|
+
(0, import_node_fs6.writeFileSync)(innerTsconfigPath, INERTIA_TSCONFIG_TEMPLATE, "utf8");
|
|
7070
7346
|
}
|
|
7071
7347
|
});
|
|
7072
7348
|
if (checkFileExists(cwd, "vite.config.ts")) {
|
|
7073
|
-
const viteContent = (0,
|
|
7349
|
+
const viteContent = (0, import_node_fs6.readFileSync)((0, import_node_path20.join)(cwd, "vite.config.ts"), "utf8");
|
|
7074
7350
|
checks.push({
|
|
7075
7351
|
name: "vite.config.ts has resolve.alias",
|
|
7076
7352
|
pass: viteContent.includes("resolve") && viteContent.includes("alias"),
|
|
@@ -7136,12 +7412,12 @@ async function runDoctor(opts) {
|
|
|
7136
7412
|
}
|
|
7137
7413
|
if (checkFileExists(cwd, ".gitignore")) {
|
|
7138
7414
|
const gitignorePath = (0, import_node_path20.join)(cwd, ".gitignore");
|
|
7139
|
-
const gitignore = (0,
|
|
7415
|
+
const gitignore = (0, import_node_fs6.readFileSync)(gitignorePath, "utf8");
|
|
7140
7416
|
checks.push({
|
|
7141
7417
|
name: ".gitignore includes .nestjs-inertia/",
|
|
7142
7418
|
pass: gitignore.includes(".nestjs-inertia"),
|
|
7143
7419
|
fix: "Add .nestjs-inertia/ to .gitignore",
|
|
7144
|
-
autoFix: () => (0,
|
|
7420
|
+
autoFix: () => (0, import_node_fs6.appendFileSync)(gitignorePath, "\n.nestjs-inertia/\n")
|
|
7145
7421
|
});
|
|
7146
7422
|
}
|
|
7147
7423
|
const pkgJsonPath = (0, import_node_path20.join)(cwd, "package.json");
|