@dudousxd/nestjs-codegen 0.29.0 → 0.30.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 +24 -0
- package/dist/cli/main.cjs +711 -436
- package/dist/cli/main.cjs.map +1 -1
- package/dist/cli/main.js +862 -582
- package/dist/cli/main.js.map +1 -1
- package/dist/extension/index.d.cts +1 -1
- package/dist/extension/index.d.ts +1 -1
- package/dist/{index-Dc4s883u.d.cts → index-D4Blt-RT.d.cts} +1 -13
- package/dist/{index-Dc4s883u.d.ts → index-D4Blt-RT.d.ts} +1 -13
- package/dist/index.cjs +696 -434
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +854 -587
- package/dist/index.js.map +1 -1
- package/dist/nest/index.cjs +559 -284
- package/dist/nest/index.cjs.map +1 -1
- package/dist/nest/index.d.cts +1 -1
- package/dist/nest/index.d.ts +1 -1
- package/dist/nest/index.js +369 -89
- package/dist/nest/index.js.map +1 -1
- package/package.json +9 -9
- package/skills/codegen-setup/SKILL.md +5 -1
package/dist/index.cjs
CHANGED
|
@@ -168,11 +168,6 @@ function validateUserConfig(userConfig) {
|
|
|
168
168
|
);
|
|
169
169
|
}
|
|
170
170
|
}
|
|
171
|
-
if (userConfig.scopes && Object.keys(userConfig.scopes).length > 0) {
|
|
172
|
-
console.warn(
|
|
173
|
-
"[nestjs-codegen] The top-level `scopes` option has no effect and is deprecated. For several Inertia apps use `pages.scopes` (one entry per InertiaModule.forFeature scope); for several controller sets use one `contracts.glob` (e.g. a brace glob)."
|
|
174
|
-
);
|
|
175
|
-
}
|
|
176
171
|
}
|
|
177
172
|
function isGlobInput(value) {
|
|
178
173
|
if (typeof value === "string") return true;
|
|
@@ -220,7 +215,6 @@ function applyDefaults(userConfig, cwd) {
|
|
|
220
215
|
glob: userConfig.contracts?.glob ?? "src/**/*.controller.ts",
|
|
221
216
|
debounceMs: userConfig.contracts?.debounceMs ?? 500
|
|
222
217
|
},
|
|
223
|
-
scopes: userConfig.scopes ?? {},
|
|
224
218
|
codegen: {
|
|
225
219
|
outDir,
|
|
226
220
|
cwd: resolvedCwd
|
|
@@ -315,7 +309,7 @@ async function discoverPages(opts) {
|
|
|
315
309
|
const rel = (0, import_node_path2.relative)(opts.cwd, file);
|
|
316
310
|
const nameRel = (0, import_node_path2.relative)(pagesBase, file).split(import_node_path2.sep).join("/");
|
|
317
311
|
const name = `${prefix}${computeName(nameRel, opts.componentNameStrategy)}`;
|
|
318
|
-
const source = await (0, import_promises2.readFile)(file, "utf8");
|
|
312
|
+
const source = await (opts.read ? opts.read(file) : (0, import_promises2.readFile)(file, "utf8"));
|
|
319
313
|
const propsSource = extractPropsSource(source, opts.propsExport);
|
|
320
314
|
out.push({ name, absolutePath: file, relativePath: rel, propsSource, scope });
|
|
321
315
|
}
|
|
@@ -323,10 +317,14 @@ async function discoverPages(opts) {
|
|
|
323
317
|
assertUniqueNames(out);
|
|
324
318
|
return out;
|
|
325
319
|
}
|
|
326
|
-
async function discoverPageScopes(config) {
|
|
320
|
+
async function discoverPageScopes(config, read) {
|
|
327
321
|
const pages = config.pages;
|
|
328
322
|
if (!pages) return [];
|
|
329
|
-
const common = {
|
|
323
|
+
const common = {
|
|
324
|
+
cwd: config.codegen.cwd,
|
|
325
|
+
propsExport: pages.propsExport,
|
|
326
|
+
...read ? { read } : {}
|
|
327
|
+
};
|
|
330
328
|
const out = await discoverPages({
|
|
331
329
|
...common,
|
|
332
330
|
glob: pages.glob,
|
|
@@ -397,297 +395,60 @@ function extractPropsSource(source, exportName) {
|
|
|
397
395
|
}
|
|
398
396
|
|
|
399
397
|
// src/discovery/shared-props.ts
|
|
400
|
-
var
|
|
401
|
-
var
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
398
|
+
var import_node_fs3 = require("fs");
|
|
399
|
+
var import_node_path5 = require("path");
|
|
400
|
+
var import_ts_morph13 = require("ts-morph");
|
|
401
|
+
|
|
402
|
+
// src/discovery/contracts-fast.ts
|
|
403
|
+
var import_node_fs2 = require("fs");
|
|
404
|
+
var import_node_path4 = require("path");
|
|
405
|
+
var import_fast_glob2 = __toESM(require("fast-glob"), 1);
|
|
406
|
+
var import_ts_morph12 = require("ts-morph");
|
|
407
|
+
|
|
408
|
+
// src/discovery/disk-fingerprints.ts
|
|
409
|
+
var import_node_fs = require("fs");
|
|
410
|
+
var DiskFingerprints = class {
|
|
411
|
+
stats = /* @__PURE__ */ new Map();
|
|
412
|
+
/** The paths whose disk content differs from `text`, or that no longer exist. */
|
|
413
|
+
changed(files) {
|
|
414
|
+
const changed = [];
|
|
415
|
+
for (const { path, text } of files) {
|
|
416
|
+
let key;
|
|
406
417
|
try {
|
|
407
|
-
|
|
418
|
+
const stat2 = (0, import_node_fs.statSync)(path);
|
|
419
|
+
key = `${stat2.mtimeMs}:${stat2.size}`;
|
|
408
420
|
} catch {
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
const forRootCall = findForRootCall(sourceFile);
|
|
413
|
-
if (!forRootCall) return null;
|
|
414
|
-
const initializer = findShareInitializer(forRootCall);
|
|
415
|
-
if (!initializer) return null;
|
|
416
|
-
return extractShareType(initializer, sourceFile, project);
|
|
417
|
-
} catch {
|
|
418
|
-
return null;
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
function discoverSharedPropsFromConfig(config) {
|
|
422
|
-
if (!config.app?.moduleEntry) return null;
|
|
423
|
-
try {
|
|
424
|
-
const tsconfigPath = config.app.tsconfig ?? (0, import_node_path3.join)(config.codegen.cwd, "tsconfig.json");
|
|
425
|
-
let project;
|
|
426
|
-
try {
|
|
427
|
-
project = new import_ts_morph.Project({
|
|
428
|
-
tsConfigFilePath: tsconfigPath,
|
|
429
|
-
skipAddingFilesFromTsConfig: true,
|
|
430
|
-
skipLoadingLibFiles: true,
|
|
431
|
-
skipFileDependencyResolution: true
|
|
432
|
-
});
|
|
433
|
-
} catch {
|
|
434
|
-
project = new import_ts_morph.Project({
|
|
435
|
-
skipAddingFilesFromTsConfig: true,
|
|
436
|
-
skipLoadingLibFiles: true,
|
|
437
|
-
skipFileDependencyResolution: true,
|
|
438
|
-
compilerOptions: { allowJs: true, strict: false }
|
|
439
|
-
});
|
|
440
|
-
}
|
|
441
|
-
return discoverSharedProps(project, config.app.moduleEntry);
|
|
442
|
-
} catch {
|
|
443
|
-
return null;
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
function findForRootCall(sourceFile) {
|
|
447
|
-
const callExpressions = sourceFile.getDescendantsOfKind(import_ts_morph.SyntaxKind.CallExpression);
|
|
448
|
-
for (const call of callExpressions) {
|
|
449
|
-
const expr = call.getExpression();
|
|
450
|
-
if (!import_ts_morph.Node.isPropertyAccessExpression(expr)) continue;
|
|
451
|
-
const methodName = expr.getName();
|
|
452
|
-
const objectExpr = expr.getExpression();
|
|
453
|
-
if (methodName === "forRoot" && import_ts_morph.Node.isIdentifier(objectExpr)) {
|
|
454
|
-
const name = objectExpr.getText();
|
|
455
|
-
if (name === "InertiaModule") {
|
|
456
|
-
return call;
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
return null;
|
|
461
|
-
}
|
|
462
|
-
function findShareInitializer(forRootCall) {
|
|
463
|
-
if (!import_ts_morph.Node.isCallExpression(forRootCall)) return null;
|
|
464
|
-
const args = forRootCall.getArguments();
|
|
465
|
-
const firstArg2 = args[0];
|
|
466
|
-
if (!firstArg2 || !import_ts_morph.Node.isObjectLiteralExpression(firstArg2)) return null;
|
|
467
|
-
for (const prop of firstArg2.getProperties()) {
|
|
468
|
-
if (import_ts_morph.Node.isPropertyAssignment(prop) && prop.getName() === "share") {
|
|
469
|
-
return prop.getInitializer() ?? null;
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
return null;
|
|
473
|
-
}
|
|
474
|
-
function extractShareType(node, sourceFile, project) {
|
|
475
|
-
if (import_ts_morph.Node.isIdentifier(node)) {
|
|
476
|
-
const ref = resolveIdentifierToImportRef(node, sourceFile, project);
|
|
477
|
-
if (ref) {
|
|
478
|
-
return {
|
|
479
|
-
typeString: `Awaited<ReturnType<typeof import('${ref.importPath}').${ref.exportName}>>`,
|
|
480
|
-
properties: null,
|
|
481
|
-
isImportRef: true
|
|
482
|
-
};
|
|
483
|
-
}
|
|
484
|
-
}
|
|
485
|
-
if (import_ts_morph.Node.isArrowFunction(node)) {
|
|
486
|
-
const result = extractFromFunctionLike(node, sourceFile);
|
|
487
|
-
return result ? { ...result, isImportRef: false } : null;
|
|
488
|
-
}
|
|
489
|
-
if (import_ts_morph.Node.isFunctionExpression(node)) {
|
|
490
|
-
const result = extractFromFunctionLike(node, sourceFile);
|
|
491
|
-
return result ? { ...result, isImportRef: false } : null;
|
|
492
|
-
}
|
|
493
|
-
if (import_ts_morph.Node.isObjectLiteralExpression(node)) {
|
|
494
|
-
const result = extractFromObjectLiteral(node);
|
|
495
|
-
return result ? { ...result, isImportRef: false } : null;
|
|
496
|
-
}
|
|
497
|
-
return null;
|
|
498
|
-
}
|
|
499
|
-
function resolveIdentifierToImportRef(id, sourceFile, project) {
|
|
500
|
-
if (!import_ts_morph.Node.isIdentifier(id)) return null;
|
|
501
|
-
const name = id.getText();
|
|
502
|
-
const localFunc = sourceFile.getFunction(name);
|
|
503
|
-
if (localFunc?.isExported()) {
|
|
504
|
-
const filePath = sourceFile.getFilePath().replace(/\.ts$/, "");
|
|
505
|
-
return { importPath: filePath, exportName: name };
|
|
506
|
-
}
|
|
507
|
-
const localVar = sourceFile.getVariableDeclaration(name);
|
|
508
|
-
if (localVar?.isExported()) {
|
|
509
|
-
const filePath = sourceFile.getFilePath().replace(/\.ts$/, "");
|
|
510
|
-
return { importPath: filePath, exportName: name };
|
|
511
|
-
}
|
|
512
|
-
for (const imp of sourceFile.getImportDeclarations()) {
|
|
513
|
-
for (const named of imp.getNamedImports()) {
|
|
514
|
-
const importedName = named.getAliasNode()?.getText() ?? named.getName();
|
|
515
|
-
if (importedName !== name) continue;
|
|
516
|
-
const resolvedSource = imp.getModuleSpecifierSourceFile();
|
|
517
|
-
if (!resolvedSource) continue;
|
|
518
|
-
const originalName = named.getName();
|
|
519
|
-
const fn = resolvedSource.getFunction(originalName);
|
|
520
|
-
if (fn?.isExported()) {
|
|
521
|
-
const filePath = resolvedSource.getFilePath().replace(/\.ts$/, "");
|
|
522
|
-
return { importPath: filePath, exportName: originalName };
|
|
523
|
-
}
|
|
524
|
-
const v = resolvedSource.getVariableDeclaration(originalName);
|
|
525
|
-
if (v?.isExported()) {
|
|
526
|
-
const filePath = resolvedSource.getFilePath().replace(/\.ts$/, "");
|
|
527
|
-
return { importPath: filePath, exportName: originalName };
|
|
528
|
-
}
|
|
529
|
-
}
|
|
530
|
-
}
|
|
531
|
-
return null;
|
|
532
|
-
}
|
|
533
|
-
function extractFromFunctionLike(node, _sourceFile) {
|
|
534
|
-
const returnTypeNode = import_ts_morph.Node.isArrowFunction(node) || import_ts_morph.Node.isFunctionExpression(node) ? node.getReturnTypeNode() : null;
|
|
535
|
-
if (returnTypeNode) {
|
|
536
|
-
return extractFromReturnTypeAnnotation(returnTypeNode);
|
|
537
|
-
}
|
|
538
|
-
if (import_ts_morph.Node.isArrowFunction(node)) {
|
|
539
|
-
const body = node.getBody();
|
|
540
|
-
if (import_ts_morph.Node.isParenthesizedExpression(body)) {
|
|
541
|
-
const inner = body.getExpression();
|
|
542
|
-
if (import_ts_morph.Node.isObjectLiteralExpression(inner)) {
|
|
543
|
-
return extractFromObjectLiteral(inner);
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
|
-
if (import_ts_morph.Node.isObjectLiteralExpression(body)) {
|
|
547
|
-
return extractFromObjectLiteral(body);
|
|
548
|
-
}
|
|
549
|
-
if (import_ts_morph.Node.isBlock(body)) {
|
|
550
|
-
return extractFromBlockReturn(body);
|
|
551
|
-
}
|
|
552
|
-
}
|
|
553
|
-
if (import_ts_morph.Node.isFunctionExpression(node)) {
|
|
554
|
-
const body = node.getBody();
|
|
555
|
-
if (import_ts_morph.Node.isBlock(body)) {
|
|
556
|
-
return extractFromBlockReturn(body);
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
return null;
|
|
560
|
-
}
|
|
561
|
-
function extractFromReturnTypeAnnotation(typeNode) {
|
|
562
|
-
if (import_ts_morph.Node.isTypeReference(typeNode)) {
|
|
563
|
-
const typeName = typeNode.getTypeName();
|
|
564
|
-
if (import_ts_morph.Node.isIdentifier(typeName) && typeName.getText() === "Promise") {
|
|
565
|
-
const typeArgs = typeNode.getTypeArguments();
|
|
566
|
-
const firstArg2 = typeArgs[0];
|
|
567
|
-
if (firstArg2) {
|
|
568
|
-
return extractFromReturnTypeAnnotation(firstArg2);
|
|
421
|
+
this.stats.delete(path);
|
|
422
|
+
changed.push(path);
|
|
423
|
+
continue;
|
|
569
424
|
}
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
if (import_ts_morph.Node.isPropertySignature(member)) {
|
|
577
|
-
const name = member.getName();
|
|
578
|
-
const memberTypeNode = member.getTypeNode();
|
|
579
|
-
const type = memberTypeNode ? memberTypeNode.getText() : "unknown";
|
|
580
|
-
properties.push({ name, type });
|
|
425
|
+
if (this.stats.get(path) === key) continue;
|
|
426
|
+
let disk;
|
|
427
|
+
try {
|
|
428
|
+
disk = (0, import_node_fs.readFileSync)(path, "utf-8");
|
|
429
|
+
} catch {
|
|
430
|
+
disk = void 0;
|
|
581
431
|
}
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
return null;
|
|
588
|
-
}
|
|
589
|
-
function extractFromBlockReturn(block) {
|
|
590
|
-
if (!import_ts_morph.Node.isBlock(block)) return null;
|
|
591
|
-
const statements = block.getStatements();
|
|
592
|
-
for (let i = statements.length - 1; i >= 0; i--) {
|
|
593
|
-
const stmt = statements[i];
|
|
594
|
-
if (!import_ts_morph.Node.isReturnStatement(stmt)) continue;
|
|
595
|
-
const expr = stmt.getExpression();
|
|
596
|
-
if (!expr) continue;
|
|
597
|
-
if (import_ts_morph.Node.isObjectLiteralExpression(expr)) {
|
|
598
|
-
return extractFromObjectLiteral(expr);
|
|
599
|
-
}
|
|
600
|
-
if (import_ts_morph.Node.isParenthesizedExpression(expr)) {
|
|
601
|
-
const inner = expr.getExpression();
|
|
602
|
-
if (import_ts_morph.Node.isObjectLiteralExpression(inner)) {
|
|
603
|
-
return extractFromObjectLiteral(inner);
|
|
432
|
+
if (disk === text) {
|
|
433
|
+
this.stats.set(path, key);
|
|
434
|
+
} else {
|
|
435
|
+
this.stats.delete(path);
|
|
436
|
+
changed.push(path);
|
|
604
437
|
}
|
|
605
438
|
}
|
|
606
|
-
|
|
607
|
-
}
|
|
608
|
-
return null;
|
|
609
|
-
}
|
|
610
|
-
function extractFromObjectLiteral(objLiteral) {
|
|
611
|
-
if (!import_ts_morph.Node.isObjectLiteralExpression(objLiteral)) return null;
|
|
612
|
-
const properties = [];
|
|
613
|
-
for (const prop of objLiteral.getProperties()) {
|
|
614
|
-
if (!import_ts_morph.Node.isPropertyAssignment(prop)) continue;
|
|
615
|
-
const name = prop.getName();
|
|
616
|
-
const initializer = prop.getInitializer();
|
|
617
|
-
if (!initializer) continue;
|
|
618
|
-
const type = inferExpressionType(initializer);
|
|
619
|
-
properties.push({ name, type });
|
|
620
|
-
}
|
|
621
|
-
if (properties.length === 0) return null;
|
|
622
|
-
const typeString = `{ ${properties.map((p) => `${p.name}: ${p.type}`).join("; ")} }`;
|
|
623
|
-
return { typeString, properties, isImportRef: false };
|
|
624
|
-
}
|
|
625
|
-
function inferExpressionType(node) {
|
|
626
|
-
if (import_ts_morph.Node.isStringLiteral(node)) return "string";
|
|
627
|
-
if (import_ts_morph.Node.isTemplateExpression(node) || import_ts_morph.Node.isNoSubstitutionTemplateLiteral(node))
|
|
628
|
-
return "string";
|
|
629
|
-
if (import_ts_morph.Node.isNumericLiteral(node)) return "number";
|
|
630
|
-
if (node.getKind() === import_ts_morph.SyntaxKind.TrueKeyword || node.getKind() === import_ts_morph.SyntaxKind.FalseKeyword) {
|
|
631
|
-
return "boolean";
|
|
632
|
-
}
|
|
633
|
-
if (node.getKind() === import_ts_morph.SyntaxKind.NullKeyword) return "null";
|
|
634
|
-
if (import_ts_morph.Node.isIdentifier(node) && node.getText() === "undefined") return "undefined";
|
|
635
|
-
if (import_ts_morph.Node.isObjectLiteralExpression(node)) {
|
|
636
|
-
const props = node.getProperties();
|
|
637
|
-
if (props.length === 0) return "Record<string, unknown>";
|
|
638
|
-
const entries = [];
|
|
639
|
-
for (const prop of props) {
|
|
640
|
-
if (!import_ts_morph.Node.isPropertyAssignment(prop)) continue;
|
|
641
|
-
const key = prop.getName();
|
|
642
|
-
const init = prop.getInitializer();
|
|
643
|
-
if (!init) continue;
|
|
644
|
-
entries.push(`${key}: ${inferExpressionType(init)}`);
|
|
645
|
-
}
|
|
646
|
-
if (entries.length === 0) return "Record<string, unknown>";
|
|
647
|
-
return `{ ${entries.join("; ")} }`;
|
|
439
|
+
return changed;
|
|
648
440
|
}
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
const first = elements[0];
|
|
653
|
-
if (first) return `Array<${inferExpressionType(first)}>`;
|
|
654
|
-
return "Array<unknown>";
|
|
441
|
+
/** Forget `path`, so its next check compares content again. */
|
|
442
|
+
forget(path) {
|
|
443
|
+
this.stats.delete(path);
|
|
655
444
|
}
|
|
656
|
-
|
|
657
|
-
const whenTrue = inferExpressionType(node.getWhenTrue());
|
|
658
|
-
const whenFalse = inferExpressionType(node.getWhenFalse());
|
|
659
|
-
if (whenTrue === whenFalse) return whenTrue;
|
|
660
|
-
return `${whenTrue} | ${whenFalse}`;
|
|
661
|
-
}
|
|
662
|
-
if (import_ts_morph.Node.isParenthesizedExpression(node)) {
|
|
663
|
-
return inferExpressionType(node.getExpression());
|
|
664
|
-
}
|
|
665
|
-
if (import_ts_morph.Node.isAsExpression(node)) {
|
|
666
|
-
const typeNode = node.getTypeNode();
|
|
667
|
-
if (typeNode) return typeNode.getText();
|
|
668
|
-
}
|
|
669
|
-
return "unknown";
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
// src/emit/emit-api.ts
|
|
673
|
-
var import_promises3 = require("fs/promises");
|
|
674
|
-
var import_node_path7 = require("path");
|
|
675
|
-
|
|
676
|
-
// src/extension/registry.ts
|
|
677
|
-
var import_node_path6 = require("path");
|
|
678
|
-
var import_ts_morph13 = require("ts-morph");
|
|
679
|
-
|
|
680
|
-
// src/discovery/contracts-fast.ts
|
|
681
|
-
var import_node_fs = require("fs");
|
|
682
|
-
var import_node_path5 = require("path");
|
|
683
|
-
var import_fast_glob2 = __toESM(require("fast-glob"), 1);
|
|
684
|
-
var import_ts_morph12 = require("ts-morph");
|
|
445
|
+
};
|
|
685
446
|
|
|
686
447
|
// src/discovery/dto-type-resolver.ts
|
|
687
448
|
var import_ts_morph11 = require("ts-morph");
|
|
688
449
|
|
|
689
450
|
// src/discovery/dto-to-ir.ts
|
|
690
|
-
var
|
|
451
|
+
var import_ts_morph2 = require("ts-morph");
|
|
691
452
|
|
|
692
453
|
// src/util/debug-log.ts
|
|
693
454
|
var debugEnabled = false;
|
|
@@ -699,8 +460,8 @@ function debugWarn(message) {
|
|
|
699
460
|
}
|
|
700
461
|
|
|
701
462
|
// src/discovery/type-ref-resolution.ts
|
|
702
|
-
var
|
|
703
|
-
var
|
|
463
|
+
var import_node_path3 = require("path");
|
|
464
|
+
var import_ts_morph = require("ts-morph");
|
|
704
465
|
var _EMPTY_CTX = { projectRoot: "", tsconfigPaths: null };
|
|
705
466
|
var _ctxByProject = /* @__PURE__ */ new WeakMap();
|
|
706
467
|
function setDiscoveryContext(project, ctx) {
|
|
@@ -741,17 +502,17 @@ function findTypeInFile(name, file) {
|
|
|
741
502
|
}
|
|
742
503
|
function resolveModuleSpecifier(moduleSpecifier, sourceFile, project) {
|
|
743
504
|
if (moduleSpecifier.startsWith(".")) {
|
|
744
|
-
const dir = (0,
|
|
505
|
+
const dir = (0, import_node_path3.dirname)(sourceFile.getFilePath());
|
|
745
506
|
const ext = /\.(c|m)?(j|t)sx?$/.exec(moduleSpecifier)?.[0];
|
|
746
507
|
const base = ext ? moduleSpecifier.slice(0, -ext.length) : moduleSpecifier;
|
|
747
508
|
const flavour = ext?.startsWith(".c") ? "c" : ext?.startsWith(".m") ? "m" : "";
|
|
748
509
|
const candidates = [
|
|
749
|
-
(0,
|
|
750
|
-
...flavour === "" ? [(0,
|
|
751
|
-
(0,
|
|
752
|
-
(0,
|
|
753
|
-
(0,
|
|
754
|
-
...ext === void 0 ? [(0,
|
|
510
|
+
(0, import_node_path3.resolve)(dir, `${base}.${flavour}ts`),
|
|
511
|
+
...flavour === "" ? [(0, import_node_path3.resolve)(dir, `${base}.tsx`)] : [],
|
|
512
|
+
(0, import_node_path3.resolve)(dir, `${moduleSpecifier}.ts`),
|
|
513
|
+
(0, import_node_path3.resolve)(dir, moduleSpecifier, "index.ts"),
|
|
514
|
+
(0, import_node_path3.resolve)(dir, `${base}.d.${flavour}ts`),
|
|
515
|
+
...ext === void 0 ? [(0, import_node_path3.resolve)(dir, moduleSpecifier, "index.d.ts")] : []
|
|
755
516
|
];
|
|
756
517
|
return [...new Set(candidates)];
|
|
757
518
|
}
|
|
@@ -773,8 +534,8 @@ function resolveModuleSpecifier(moduleSpecifier, sourceFile, project) {
|
|
|
773
534
|
const rest = moduleSpecifier.slice(prefix.length);
|
|
774
535
|
const candidates = [];
|
|
775
536
|
for (const mapping of mappings) {
|
|
776
|
-
const resolved = (0,
|
|
777
|
-
candidates.push(`${resolved}.ts`, (0,
|
|
537
|
+
const resolved = (0, import_node_path3.resolve)(baseUrl, mapping.replace("*", rest));
|
|
538
|
+
candidates.push(`${resolved}.ts`, (0, import_node_path3.resolve)(resolved, "index.ts"));
|
|
778
539
|
}
|
|
779
540
|
dbg(" resolved candidates:", candidates);
|
|
780
541
|
return candidates;
|
|
@@ -965,13 +726,13 @@ function resolveTypeRef(nodeOrName, sourceFile, project, opts) {
|
|
|
965
726
|
name = nodeOrName;
|
|
966
727
|
} else {
|
|
967
728
|
const typeNode = nodeOrName;
|
|
968
|
-
if (opts.unwrapContainers &&
|
|
729
|
+
if (opts.unwrapContainers && import_ts_morph.Node.isArrayTypeNode(typeNode)) {
|
|
969
730
|
const inner = resolveTypeRef(typeNode.getElementTypeNode(), sourceFile, project, opts);
|
|
970
731
|
return inner ? { ...inner, isArray: true } : null;
|
|
971
732
|
}
|
|
972
|
-
if (!
|
|
733
|
+
if (!import_ts_morph.Node.isTypeReference(typeNode)) return null;
|
|
973
734
|
const typeName = typeNode.getTypeName();
|
|
974
|
-
const refName =
|
|
735
|
+
const refName = import_ts_morph.Node.isIdentifier(typeName) ? typeName.getText() : null;
|
|
975
736
|
if (!refName) return null;
|
|
976
737
|
if (opts.unwrapContainers && refName === "Promise") {
|
|
977
738
|
const first = typeNode.getTypeArguments()[0];
|
|
@@ -1105,7 +866,7 @@ function buildProperty(prop, classFile, ctx) {
|
|
|
1105
866
|
const dec = (n) => decorators.get(n);
|
|
1106
867
|
const typeNode = prop.getTypeNode();
|
|
1107
868
|
const typeText = typeNode?.getText() ?? "unknown";
|
|
1108
|
-
const isArrayType = !!typeNode &&
|
|
869
|
+
const isArrayType = !!typeNode && import_ts_morph2.Node.isArrayTypeNode(typeNode);
|
|
1109
870
|
const asField = (child) => applyPresence(
|
|
1110
871
|
has("IsArray") || isArrayType ? { kind: "array", element: child } : child,
|
|
1111
872
|
decorators
|
|
@@ -1319,22 +1080,22 @@ function firstArgText(decorator) {
|
|
|
1319
1080
|
}
|
|
1320
1081
|
function numericArg(decorator) {
|
|
1321
1082
|
const arg = firstArg(decorator);
|
|
1322
|
-
if (arg &&
|
|
1083
|
+
if (arg && import_ts_morph2.Node.isNumericLiteral(arg)) return arg.getText();
|
|
1323
1084
|
return null;
|
|
1324
1085
|
}
|
|
1325
1086
|
function numericArgs(decorator) {
|
|
1326
1087
|
const args = decorator?.getArguments() ?? [];
|
|
1327
|
-
const num = (n) => n &&
|
|
1088
|
+
const num = (n) => n && import_ts_morph2.Node.isNumericLiteral(n) ? n.getText() : null;
|
|
1328
1089
|
return [num(args[0]), num(args[1])];
|
|
1329
1090
|
}
|
|
1330
1091
|
function messageRaw(decorator) {
|
|
1331
1092
|
const args = decorator?.getArguments() ?? [];
|
|
1332
1093
|
for (const arg of args) {
|
|
1333
|
-
if (
|
|
1094
|
+
if (import_ts_morph2.Node.isObjectLiteralExpression(arg)) {
|
|
1334
1095
|
for (const prop of arg.getProperties()) {
|
|
1335
|
-
if (
|
|
1096
|
+
if (import_ts_morph2.Node.isPropertyAssignment(prop) && prop.getName() === "message") {
|
|
1336
1097
|
const init = prop.getInitializer();
|
|
1337
|
-
if (init &&
|
|
1098
|
+
if (init && import_ts_morph2.Node.isStringLiteral(init)) return init.getText();
|
|
1338
1099
|
}
|
|
1339
1100
|
}
|
|
1340
1101
|
}
|
|
@@ -1343,30 +1104,30 @@ function messageRaw(decorator) {
|
|
|
1343
1104
|
}
|
|
1344
1105
|
function resolveDiscriminator(decorator) {
|
|
1345
1106
|
const optsArg = decorator?.getArguments()[1];
|
|
1346
|
-
if (!optsArg || !
|
|
1107
|
+
if (!optsArg || !import_ts_morph2.Node.isObjectLiteralExpression(optsArg)) return null;
|
|
1347
1108
|
let discProp;
|
|
1348
1109
|
for (const prop of optsArg.getProperties()) {
|
|
1349
|
-
if (
|
|
1110
|
+
if (import_ts_morph2.Node.isPropertyAssignment(prop) && prop.getName() === "discriminator") {
|
|
1350
1111
|
discProp = prop.getInitializer();
|
|
1351
1112
|
}
|
|
1352
1113
|
}
|
|
1353
|
-
if (!discProp || !
|
|
1114
|
+
if (!discProp || !import_ts_morph2.Node.isObjectLiteralExpression(discProp)) return null;
|
|
1354
1115
|
let property = null;
|
|
1355
1116
|
const subTypes = [];
|
|
1356
1117
|
for (const prop of discProp.getProperties()) {
|
|
1357
|
-
if (!
|
|
1118
|
+
if (!import_ts_morph2.Node.isPropertyAssignment(prop)) continue;
|
|
1358
1119
|
const name = prop.getName();
|
|
1359
1120
|
const init = prop.getInitializer();
|
|
1360
1121
|
if (!init) continue;
|
|
1361
|
-
if (name === "property" &&
|
|
1122
|
+
if (name === "property" && import_ts_morph2.Node.isStringLiteral(init)) {
|
|
1362
1123
|
property = init.getLiteralValue();
|
|
1363
|
-
} else if (name === "subTypes" &&
|
|
1124
|
+
} else if (name === "subTypes" && import_ts_morph2.Node.isArrayLiteralExpression(init)) {
|
|
1364
1125
|
for (const el of init.getElements()) {
|
|
1365
|
-
if (!
|
|
1126
|
+
if (!import_ts_morph2.Node.isObjectLiteralExpression(el)) continue;
|
|
1366
1127
|
for (const p of el.getProperties()) {
|
|
1367
|
-
if (!
|
|
1128
|
+
if (!import_ts_morph2.Node.isPropertyAssignment(p) || p.getName() !== "name") continue;
|
|
1368
1129
|
const nameInit = p.getInitializer();
|
|
1369
|
-
if (nameInit &&
|
|
1130
|
+
if (nameInit && import_ts_morph2.Node.isIdentifier(nameInit)) subTypes.push(nameInit.getText());
|
|
1370
1131
|
}
|
|
1371
1132
|
}
|
|
1372
1133
|
}
|
|
@@ -1377,9 +1138,9 @@ function resolveDiscriminator(decorator) {
|
|
|
1377
1138
|
function resolveTypeFactoryName(decorator) {
|
|
1378
1139
|
const arg = firstArg(decorator);
|
|
1379
1140
|
if (!arg) return null;
|
|
1380
|
-
if (
|
|
1141
|
+
if (import_ts_morph2.Node.isArrowFunction(arg)) {
|
|
1381
1142
|
const body = arg.getBody();
|
|
1382
|
-
if (
|
|
1143
|
+
if (import_ts_morph2.Node.isIdentifier(body)) return body.getText();
|
|
1383
1144
|
}
|
|
1384
1145
|
return null;
|
|
1385
1146
|
}
|
|
@@ -1388,12 +1149,12 @@ function singularClassName(typeText) {
|
|
|
1388
1149
|
return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(inner) ? inner : null;
|
|
1389
1150
|
}
|
|
1390
1151
|
function genericTypeArgNames(typeNode) {
|
|
1391
|
-
if (!typeNode || !
|
|
1152
|
+
if (!typeNode || !import_ts_morph2.Node.isTypeReference(typeNode)) return [];
|
|
1392
1153
|
const names = [];
|
|
1393
1154
|
for (const arg of typeNode.getTypeArguments()) {
|
|
1394
|
-
if (!
|
|
1155
|
+
if (!import_ts_morph2.Node.isTypeReference(arg)) return [];
|
|
1395
1156
|
const tn = arg.getTypeName();
|
|
1396
|
-
if (!
|
|
1157
|
+
if (!import_ts_morph2.Node.isIdentifier(tn)) return [];
|
|
1397
1158
|
names.push(tn.getText());
|
|
1398
1159
|
}
|
|
1399
1160
|
return names;
|
|
@@ -1401,7 +1162,7 @@ function genericTypeArgNames(typeNode) {
|
|
|
1401
1162
|
function enumSchemaFromDecorator(decorator, classFile, ctx) {
|
|
1402
1163
|
const arg = firstArg(decorator);
|
|
1403
1164
|
if (!arg) return null;
|
|
1404
|
-
if (
|
|
1165
|
+
if (import_ts_morph2.Node.isIdentifier(arg)) {
|
|
1405
1166
|
const name = arg.getText();
|
|
1406
1167
|
const resolved = findType(name, classFile, ctx.project);
|
|
1407
1168
|
if (resolved && resolved.kind === "enum") {
|
|
@@ -1415,12 +1176,12 @@ function enumSchemaFromDecorator(decorator, classFile, ctx) {
|
|
|
1415
1176
|
}
|
|
1416
1177
|
return { kind: "unknown", note: `@IsEnum(${name}): enum not resolvable to literals` };
|
|
1417
1178
|
}
|
|
1418
|
-
if (
|
|
1179
|
+
if (import_ts_morph2.Node.isObjectLiteralExpression(arg)) {
|
|
1419
1180
|
const values = [];
|
|
1420
1181
|
for (const p of arg.getProperties()) {
|
|
1421
|
-
if (!
|
|
1182
|
+
if (!import_ts_morph2.Node.isPropertyAssignment(p)) continue;
|
|
1422
1183
|
const init = p.getInitializer();
|
|
1423
|
-
if (init &&
|
|
1184
|
+
if (init && import_ts_morph2.Node.isStringLiteral(init)) values.push(init.getText());
|
|
1424
1185
|
}
|
|
1425
1186
|
if (values.length > 0) return { kind: "enum", literals: values };
|
|
1426
1187
|
}
|
|
@@ -1428,9 +1189,9 @@ function enumSchemaFromDecorator(decorator, classFile, ctx) {
|
|
|
1428
1189
|
}
|
|
1429
1190
|
function inSchemaFromDecorator(decorator) {
|
|
1430
1191
|
const arg = firstArg(decorator);
|
|
1431
|
-
if (arg &&
|
|
1192
|
+
if (arg && import_ts_morph2.Node.isArrayLiteralExpression(arg)) {
|
|
1432
1193
|
const elements = arg.getElements();
|
|
1433
|
-
const allStrings = elements.every((e) =>
|
|
1194
|
+
const allStrings = elements.every((e) => import_ts_morph2.Node.isStringLiteral(e));
|
|
1434
1195
|
if (allStrings && elements.length > 0) {
|
|
1435
1196
|
return { kind: "enum", literals: elements.map((e) => e.getText()) };
|
|
1436
1197
|
}
|
|
@@ -1448,7 +1209,7 @@ function inSchemaFromDecorator(decorator) {
|
|
|
1448
1209
|
var import_ts_morph6 = require("ts-morph");
|
|
1449
1210
|
|
|
1450
1211
|
// src/discovery/filter-field-types.ts
|
|
1451
|
-
var
|
|
1212
|
+
var import_ts_morph3 = require("ts-morph");
|
|
1452
1213
|
|
|
1453
1214
|
// src/discovery/enum-resolution.ts
|
|
1454
1215
|
var _enumCache = /* @__PURE__ */ new WeakMap();
|
|
@@ -1501,28 +1262,28 @@ function markNullable(r, nullable) {
|
|
|
1501
1262
|
}
|
|
1502
1263
|
var TRANSPARENT_TYPE_BRANDS = /* @__PURE__ */ new Set(["Opt", "Hidden"]);
|
|
1503
1264
|
function classifyTypeNode(typeNode, sourceFile, project, opts) {
|
|
1504
|
-
if (
|
|
1265
|
+
if (import_ts_morph3.Node.isUnionTypeNode(typeNode)) {
|
|
1505
1266
|
let nullable = false;
|
|
1506
1267
|
const stringLits = [];
|
|
1507
1268
|
const numberLits = [];
|
|
1508
1269
|
const others = [];
|
|
1509
1270
|
for (const member of typeNode.getTypeNodes()) {
|
|
1510
1271
|
const kind = member.getKind();
|
|
1511
|
-
if (kind ===
|
|
1272
|
+
if (kind === import_ts_morph3.SyntaxKind.NullKeyword || kind === import_ts_morph3.SyntaxKind.UndefinedKeyword) {
|
|
1512
1273
|
nullable = true;
|
|
1513
1274
|
continue;
|
|
1514
1275
|
}
|
|
1515
|
-
if (
|
|
1276
|
+
if (import_ts_morph3.Node.isLiteralTypeNode(member)) {
|
|
1516
1277
|
const lit = member.getLiteral();
|
|
1517
|
-
if (
|
|
1278
|
+
if (import_ts_morph3.Node.isStringLiteral(lit)) {
|
|
1518
1279
|
stringLits.push(lit.getLiteralValue());
|
|
1519
1280
|
continue;
|
|
1520
1281
|
}
|
|
1521
|
-
if (
|
|
1282
|
+
if (import_ts_morph3.Node.isNumericLiteral(lit)) {
|
|
1522
1283
|
numberLits.push(lit.getText());
|
|
1523
1284
|
continue;
|
|
1524
1285
|
}
|
|
1525
|
-
if (lit.getKind() ===
|
|
1286
|
+
if (lit.getKind() === import_ts_morph3.SyntaxKind.NullKeyword) {
|
|
1526
1287
|
nullable = true;
|
|
1527
1288
|
continue;
|
|
1528
1289
|
}
|
|
@@ -1542,19 +1303,19 @@ function classifyTypeNode(typeNode, sourceFile, project, opts) {
|
|
|
1542
1303
|
return markNullable({ kind: "unknown" }, nullable);
|
|
1543
1304
|
}
|
|
1544
1305
|
switch (typeNode.getKind()) {
|
|
1545
|
-
case
|
|
1306
|
+
case import_ts_morph3.SyntaxKind.StringKeyword:
|
|
1546
1307
|
return { kind: "string" };
|
|
1547
|
-
case
|
|
1308
|
+
case import_ts_morph3.SyntaxKind.NumberKeyword:
|
|
1548
1309
|
return { kind: "number" };
|
|
1549
|
-
case
|
|
1310
|
+
case import_ts_morph3.SyntaxKind.BooleanKeyword:
|
|
1550
1311
|
return { kind: "boolean" };
|
|
1551
|
-
case
|
|
1552
|
-
case
|
|
1312
|
+
case import_ts_morph3.SyntaxKind.AnyKeyword:
|
|
1313
|
+
case import_ts_morph3.SyntaxKind.UnknownKeyword:
|
|
1553
1314
|
return { kind: "unknown" };
|
|
1554
1315
|
default:
|
|
1555
1316
|
break;
|
|
1556
1317
|
}
|
|
1557
|
-
if (
|
|
1318
|
+
if (import_ts_morph3.Node.isTypeReference(typeNode)) {
|
|
1558
1319
|
const refName = typeNode.getTypeName().getText();
|
|
1559
1320
|
if (refName === "Date") return { kind: "date" };
|
|
1560
1321
|
if (refName === "Record" || refName === "Object") return { kind: "json" };
|
|
@@ -1572,25 +1333,25 @@ function classifyTypeNode(typeNode, sourceFile, project, opts) {
|
|
|
1572
1333
|
if (typeRef) return { kind: "unknown", typeRef };
|
|
1573
1334
|
return { kind: "unknown" };
|
|
1574
1335
|
}
|
|
1575
|
-
if (
|
|
1336
|
+
if (import_ts_morph3.Node.isTypeLiteral(typeNode)) return { kind: "json" };
|
|
1576
1337
|
return { kind: "unknown" };
|
|
1577
1338
|
}
|
|
1578
1339
|
function enumFromDecoratorArgs(args, sourceFile, project) {
|
|
1579
1340
|
for (const arg of args) {
|
|
1580
|
-
if (
|
|
1341
|
+
if (import_ts_morph3.Node.isArrowFunction(arg)) {
|
|
1581
1342
|
const body = arg.getBody();
|
|
1582
|
-
if (
|
|
1343
|
+
if (import_ts_morph3.Node.isIdentifier(body)) {
|
|
1583
1344
|
const en = resolveEnumValues(body.getText(), sourceFile, project);
|
|
1584
1345
|
if (en) return en;
|
|
1585
1346
|
}
|
|
1586
1347
|
}
|
|
1587
|
-
if (
|
|
1348
|
+
if (import_ts_morph3.Node.isObjectLiteralExpression(arg)) {
|
|
1588
1349
|
const itemsProp = arg.getProperty("items");
|
|
1589
|
-
if (itemsProp &&
|
|
1350
|
+
if (itemsProp && import_ts_morph3.Node.isPropertyAssignment(itemsProp)) {
|
|
1590
1351
|
const init = itemsProp.getInitializer();
|
|
1591
|
-
if (init &&
|
|
1352
|
+
if (init && import_ts_morph3.Node.isArrowFunction(init)) {
|
|
1592
1353
|
const body = init.getBody();
|
|
1593
|
-
if (
|
|
1354
|
+
if (import_ts_morph3.Node.isIdentifier(body)) {
|
|
1594
1355
|
const en = resolveEnumValues(body.getText(), sourceFile, project);
|
|
1595
1356
|
if (en) return en;
|
|
1596
1357
|
}
|
|
@@ -1613,7 +1374,7 @@ function classifyFromColumnDecorator(prop, sourceFile, project) {
|
|
|
1613
1374
|
return { kind: "string" };
|
|
1614
1375
|
}
|
|
1615
1376
|
for (const arg of args) {
|
|
1616
|
-
if (
|
|
1377
|
+
if (import_ts_morph3.Node.isStringLiteral(arg)) {
|
|
1617
1378
|
const raw = arg.getLiteralValue();
|
|
1618
1379
|
const kind = classifyTypeKeyword(raw);
|
|
1619
1380
|
if (kind) {
|
|
@@ -1621,11 +1382,11 @@ function classifyFromColumnDecorator(prop, sourceFile, project) {
|
|
|
1621
1382
|
return { kind };
|
|
1622
1383
|
}
|
|
1623
1384
|
}
|
|
1624
|
-
if (
|
|
1385
|
+
if (import_ts_morph3.Node.isObjectLiteralExpression(arg)) {
|
|
1625
1386
|
const enumProp = arg.getProperty("enum");
|
|
1626
|
-
if (enumProp &&
|
|
1387
|
+
if (enumProp && import_ts_morph3.Node.isPropertyAssignment(enumProp)) {
|
|
1627
1388
|
const init = enumProp.getInitializer();
|
|
1628
|
-
if (init &&
|
|
1389
|
+
if (init && import_ts_morph3.Node.isIdentifier(init)) {
|
|
1629
1390
|
const en = resolveEnumValues(init.getText(), sourceFile, project);
|
|
1630
1391
|
if (en) {
|
|
1631
1392
|
return en.numeric ? { kind: "number", enumValues: en.values, numericEnum: true } : { kind: "string", enumValues: en.values };
|
|
@@ -1635,15 +1396,15 @@ function classifyFromColumnDecorator(prop, sourceFile, project) {
|
|
|
1635
1396
|
}
|
|
1636
1397
|
for (const key of ["columnType", "type"]) {
|
|
1637
1398
|
const typeProp = arg.getProperty(key);
|
|
1638
|
-
if (!typeProp || !
|
|
1399
|
+
if (!typeProp || !import_ts_morph3.Node.isPropertyAssignment(typeProp)) continue;
|
|
1639
1400
|
const init = typeProp.getInitializer();
|
|
1640
1401
|
if (!init) continue;
|
|
1641
|
-
if (
|
|
1402
|
+
if (import_ts_morph3.Node.isStringLiteral(init)) {
|
|
1642
1403
|
const kind = classifyTypeKeyword(init.getLiteralValue());
|
|
1643
1404
|
if (kind) return { kind };
|
|
1644
1405
|
continue;
|
|
1645
1406
|
}
|
|
1646
|
-
if (
|
|
1407
|
+
if (import_ts_morph3.Node.isIdentifier(init)) {
|
|
1647
1408
|
const kind = classifyTypeKeyword(init.getText());
|
|
1648
1409
|
if (kind) return { kind };
|
|
1649
1410
|
}
|
|
@@ -1686,6 +1447,49 @@ function toFilterFieldType(name, r) {
|
|
|
1686
1447
|
|
|
1687
1448
|
// src/discovery/heritage.ts
|
|
1688
1449
|
var import_ts_morph5 = require("ts-morph");
|
|
1450
|
+
|
|
1451
|
+
// src/discovery/unresolved-imports.ts
|
|
1452
|
+
var import_ts_morph4 = require("ts-morph");
|
|
1453
|
+
var UnresolvedImports = class {
|
|
1454
|
+
read;
|
|
1455
|
+
/**
|
|
1456
|
+
* The files with an import that failed to resolve in `program` and now resolves
|
|
1457
|
+
* to a TypeScript file the program does not hold.
|
|
1458
|
+
*/
|
|
1459
|
+
nowResolving(program) {
|
|
1460
|
+
if (this.read?.program !== program) {
|
|
1461
|
+
this.read = { program, imports: failedImports(program) };
|
|
1462
|
+
}
|
|
1463
|
+
const options = program.getCompilerOptions();
|
|
1464
|
+
const files = /* @__PURE__ */ new Set();
|
|
1465
|
+
for (const { specifier, from } of this.read.imports) {
|
|
1466
|
+
const file = import_ts_morph4.ts.resolveModuleName(specifier, from, options, import_ts_morph4.ts.sys).resolvedModule?.resolvedFileName;
|
|
1467
|
+
if (file !== void 0 && /\.(m|c)?tsx?$/.test(file) && !program.getSourceFile(file)) {
|
|
1468
|
+
files.add(from);
|
|
1469
|
+
}
|
|
1470
|
+
}
|
|
1471
|
+
return [...files];
|
|
1472
|
+
}
|
|
1473
|
+
};
|
|
1474
|
+
function failedImports(program) {
|
|
1475
|
+
const checker = program.getTypeChecker();
|
|
1476
|
+
const imports = [];
|
|
1477
|
+
for (const file of program.getSourceFiles()) {
|
|
1478
|
+
if (program.isSourceFileDefaultLibrary(file) || file.isDeclarationFile) continue;
|
|
1479
|
+
if (program.isSourceFileFromExternalLibrary(file)) continue;
|
|
1480
|
+
for (const statement of file.statements) {
|
|
1481
|
+
if (!import_ts_morph4.ts.isImportDeclaration(statement) && !import_ts_morph4.ts.isExportDeclaration(statement)) continue;
|
|
1482
|
+
const specifier = statement.moduleSpecifier;
|
|
1483
|
+
if (!specifier || !import_ts_morph4.ts.isStringLiteral(specifier)) continue;
|
|
1484
|
+
if (!checker.getSymbolAtLocation(specifier)) {
|
|
1485
|
+
imports.push({ specifier: specifier.text, from: file.fileName });
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1489
|
+
return imports;
|
|
1490
|
+
}
|
|
1491
|
+
|
|
1492
|
+
// src/discovery/heritage.ts
|
|
1689
1493
|
function resolveHeritageCall(node) {
|
|
1690
1494
|
if (!node) return void 0;
|
|
1691
1495
|
const expr = unwrapExpression(node);
|
|
@@ -1885,15 +1689,42 @@ function resolvePropertyClassReference(prop) {
|
|
|
1885
1689
|
return { key, ref };
|
|
1886
1690
|
}
|
|
1887
1691
|
var mixinTypeProject;
|
|
1692
|
+
var mixinFiles = new DiskFingerprints();
|
|
1693
|
+
var mixinStale = false;
|
|
1694
|
+
var mixinUnresolved = new UnresolvedImports();
|
|
1888
1695
|
function getMixinTypeProject() {
|
|
1889
|
-
mixinTypeProject
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1696
|
+
if (mixinTypeProject && mixinStale && !refreshMixinTypeProject(mixinTypeProject)) {
|
|
1697
|
+
mixinTypeProject = void 0;
|
|
1698
|
+
}
|
|
1699
|
+
mixinStale = false;
|
|
1700
|
+
if (!mixinTypeProject) {
|
|
1701
|
+
mixinTypeProject = new import_ts_morph5.Project({
|
|
1702
|
+
skipAddingFilesFromTsConfig: true,
|
|
1703
|
+
compilerOptions: { strict: true }
|
|
1704
|
+
});
|
|
1705
|
+
mixinFiles = new DiskFingerprints();
|
|
1706
|
+
mixinUnresolved = new UnresolvedImports();
|
|
1707
|
+
}
|
|
1893
1708
|
return mixinTypeProject;
|
|
1894
1709
|
}
|
|
1895
1710
|
function clearMixinTypeProject() {
|
|
1896
1711
|
mixinTypeProject = void 0;
|
|
1712
|
+
mixinStale = false;
|
|
1713
|
+
}
|
|
1714
|
+
function invalidateMixinTypeProject() {
|
|
1715
|
+
mixinStale = true;
|
|
1716
|
+
}
|
|
1717
|
+
function refreshMixinTypeProject(project) {
|
|
1718
|
+
const program = project.getProgram().compilerObject;
|
|
1719
|
+
const files = program.getSourceFiles().filter((file) => !program.isSourceFileDefaultLibrary(file)).map((file) => ({ path: file.fileName, text: file.text }));
|
|
1720
|
+
const changed = mixinFiles.changed(files);
|
|
1721
|
+
if (changed.length === 0) return mixinUnresolved.nowResolving(program).length === 0;
|
|
1722
|
+
for (const path of changed) {
|
|
1723
|
+
const sf = project.getSourceFile(path);
|
|
1724
|
+
if (sf?.refreshFromFileSystemSync() !== import_ts_morph5.FileSystemRefreshResult.Updated) return false;
|
|
1725
|
+
}
|
|
1726
|
+
project.resolveSourceFileDependencies();
|
|
1727
|
+
return true;
|
|
1897
1728
|
}
|
|
1898
1729
|
function resolveInstantiatedReturnType(cls, methodName) {
|
|
1899
1730
|
const filePath = cls.getSourceFile().getFilePath();
|
|
@@ -2251,8 +2082,7 @@ var SchemaTypeProgram = class {
|
|
|
2251
2082
|
skipAddingFilesFromTsConfig: true,
|
|
2252
2083
|
compilerOptions: this.options
|
|
2253
2084
|
});
|
|
2254
|
-
|
|
2255
|
-
this.flush();
|
|
2085
|
+
this.requestDiscoveryFiles();
|
|
2256
2086
|
}
|
|
2257
2087
|
project;
|
|
2258
2088
|
options;
|
|
@@ -2265,6 +2095,53 @@ var SchemaTypeProgram = class {
|
|
|
2265
2095
|
needs = /* @__PURE__ */ new Map();
|
|
2266
2096
|
/** Pruned text per file, as last written into {@link project}. */
|
|
2267
2097
|
written = /* @__PURE__ */ new Map();
|
|
2098
|
+
/** What {@link project} read from disk unpruned (packages, declaration files). */
|
|
2099
|
+
externalFiles = new DiskFingerprints();
|
|
2100
|
+
scratchFiles = new DiskFingerprints();
|
|
2101
|
+
/** The last pruning of each file, with the source text and needs it was pruned for. */
|
|
2102
|
+
pruned = /* @__PURE__ */ new Map();
|
|
2103
|
+
/**
|
|
2104
|
+
* Bring the program up to date with discovery's files and the disk, keeping the
|
|
2105
|
+
* lib and package declarations it has already parsed and checked. Leaves it
|
|
2106
|
+
* holding exactly the files a new program built now would hold, with the same
|
|
2107
|
+
* text. Returns false when a file the program read unpruned has changed on disk
|
|
2108
|
+
* (a package was reinstalled, a `.d.ts` was edited): the caller builds a new
|
|
2109
|
+
* program instead.
|
|
2110
|
+
*/
|
|
2111
|
+
refresh() {
|
|
2112
|
+
const program = this.project.getProgram().compilerObject;
|
|
2113
|
+
const external = program.getSourceFiles().filter(
|
|
2114
|
+
(file) => !program.isSourceFileDefaultLibrary(file) && !this.written.has(file.fileName)
|
|
2115
|
+
).map((file) => ({ path: file.fileName, text: file.text }));
|
|
2116
|
+
if (this.externalFiles.changed(external).length > 0) return false;
|
|
2117
|
+
const scratch = this.scratch.getSourceFiles().map((sf) => ({ path: sf.getFilePath(), text: sf.getFullText() }));
|
|
2118
|
+
for (const path of this.scratchFiles.changed(scratch)) {
|
|
2119
|
+
const sf = this.scratch.getSourceFile(path);
|
|
2120
|
+
if (sf?.refreshFromFileSystemSync() === import_ts_morph7.FileSystemRefreshResult.Deleted) {
|
|
2121
|
+
this.scratchFiles.forget(path);
|
|
2122
|
+
}
|
|
2123
|
+
}
|
|
2124
|
+
this.needs.clear();
|
|
2125
|
+
this.requestDiscoveryFiles();
|
|
2126
|
+
for (const path of [...this.written.keys()]) {
|
|
2127
|
+
if (this.needs.has(path)) continue;
|
|
2128
|
+
const sf = this.project.getSourceFile(path);
|
|
2129
|
+
if (sf) this.project.removeSourceFile(sf);
|
|
2130
|
+
this.written.delete(path);
|
|
2131
|
+
}
|
|
2132
|
+
return true;
|
|
2133
|
+
}
|
|
2134
|
+
/**
|
|
2135
|
+
* Everything discovery holds now (the controllers) goes in before the first
|
|
2136
|
+
* query: a file added afterwards discards the program and its checker, and
|
|
2137
|
+
* rebuilding them once per controller is exactly the cost this avoids.
|
|
2138
|
+
*/
|
|
2139
|
+
requestDiscoveryFiles() {
|
|
2140
|
+
for (const sf of this.discovery.getSourceFiles()) {
|
|
2141
|
+
this.request(sf.getFilePath(), { schema: true });
|
|
2142
|
+
}
|
|
2143
|
+
this.flush();
|
|
2144
|
+
}
|
|
2268
2145
|
/**
|
|
2269
2146
|
* The typed copy of a discovery file, with its schema positions kept. Adding one
|
|
2270
2147
|
* that was not there yet (a contract file discovery reached lazily) rebuilds the
|
|
@@ -2305,12 +2182,21 @@ var SchemaTypeProgram = class {
|
|
|
2305
2182
|
while (this.queue.length > 0) {
|
|
2306
2183
|
const path = this.queue.pop();
|
|
2307
2184
|
const original = this.original(path);
|
|
2308
|
-
if (!original)
|
|
2309
|
-
|
|
2310
|
-
|
|
2185
|
+
if (!original) {
|
|
2186
|
+
if (this.written.has(path)) changed.set(path, void 0);
|
|
2187
|
+
continue;
|
|
2188
|
+
}
|
|
2189
|
+
const { text, requests } = this.pruneCached(path, original, this.needs.get(path));
|
|
2190
|
+
for (const { path: target, want } of requests) this.request(target, want);
|
|
2311
2191
|
if (this.written.get(path) !== text) changed.set(path, text);
|
|
2312
2192
|
}
|
|
2313
2193
|
for (const [path, text] of changed) {
|
|
2194
|
+
if (text === void 0) {
|
|
2195
|
+
const sf = this.project.getSourceFile(path);
|
|
2196
|
+
if (sf) this.project.removeSourceFile(sf);
|
|
2197
|
+
this.written.delete(path);
|
|
2198
|
+
continue;
|
|
2199
|
+
}
|
|
2314
2200
|
this.project.createSourceFile(path, text, { overwrite: true });
|
|
2315
2201
|
this.written.set(path, text);
|
|
2316
2202
|
}
|
|
@@ -2319,11 +2205,29 @@ var SchemaTypeProgram = class {
|
|
|
2319
2205
|
original(path) {
|
|
2320
2206
|
return this.discovery.getSourceFile(path) ?? this.scratch.getSourceFile(path) ?? this.scratch.addSourceFileAtPathIfExists(path);
|
|
2321
2207
|
}
|
|
2208
|
+
/** {@link prune}, reusing the last result while the file's text and needs are the same. */
|
|
2209
|
+
pruneCached(path, sf, needs) {
|
|
2210
|
+
const source = sf.getFullText();
|
|
2211
|
+
const key = `${needs.schema}:${needs.all}:${[...needs.names].sort().join(",")}`;
|
|
2212
|
+
const last = this.pruned.get(path);
|
|
2213
|
+
if (last && last.source === source && last.needs === key) return last;
|
|
2214
|
+
const result = this.prune(sf, needs);
|
|
2215
|
+
if (result.resolved) this.pruned.set(path, { ...result, source, needs: key });
|
|
2216
|
+
else this.pruned.delete(path);
|
|
2217
|
+
return result;
|
|
2218
|
+
}
|
|
2322
2219
|
/**
|
|
2323
2220
|
* `sf`'s text with every import/re-export nothing in `needs` references blanked,
|
|
2324
|
-
*
|
|
2221
|
+
* and the names each kept one brings in from its target.
|
|
2325
2222
|
*/
|
|
2326
2223
|
prune(sf, needs) {
|
|
2224
|
+
const requests = [];
|
|
2225
|
+
let resolved = true;
|
|
2226
|
+
const resolveFrom = (specifier) => {
|
|
2227
|
+
const target = this.resolve(specifier, sf);
|
|
2228
|
+
if (target === null) resolved = false;
|
|
2229
|
+
return target ?? void 0;
|
|
2230
|
+
};
|
|
2327
2231
|
const locals = topLevelDeclarations(sf);
|
|
2328
2232
|
const roots = [];
|
|
2329
2233
|
if (needs.all) roots.push(...sf.getStatements());
|
|
@@ -2376,7 +2280,7 @@ var SchemaTypeProgram = class {
|
|
|
2376
2280
|
}
|
|
2377
2281
|
};
|
|
2378
2282
|
for (const decl of sf.getImportDeclarations()) {
|
|
2379
|
-
const target =
|
|
2283
|
+
const target = resolveFrom(decl.getModuleSpecifierValue());
|
|
2380
2284
|
const namespace = decl.getNamespaceImport()?.getText();
|
|
2381
2285
|
const def = decl.getDefaultImport()?.getText();
|
|
2382
2286
|
const named = decl.getNamedImports().map((n) => ({
|
|
@@ -2390,21 +2294,24 @@ var SchemaTypeProgram = class {
|
|
|
2390
2294
|
continue;
|
|
2391
2295
|
}
|
|
2392
2296
|
if (target) {
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2297
|
+
requests.push({
|
|
2298
|
+
path: target,
|
|
2299
|
+
want: {
|
|
2300
|
+
all: wantsNamespace,
|
|
2301
|
+
names: [...wantsDefault ? ["default"] : [], ...named.map((n) => n.imported)]
|
|
2302
|
+
}
|
|
2396
2303
|
});
|
|
2397
2304
|
}
|
|
2398
2305
|
}
|
|
2399
2306
|
for (const exp of sf.getExportDeclarations()) {
|
|
2400
2307
|
const spec = exp.getModuleSpecifierValue();
|
|
2401
2308
|
if (spec === void 0) continue;
|
|
2402
|
-
const target =
|
|
2309
|
+
const target = resolveFrom(spec);
|
|
2403
2310
|
if (exp.isNamespaceExport() || exp.getNamedExports().length === 0) {
|
|
2404
2311
|
if (!needs.all && unresolvedNames.length === 0) {
|
|
2405
2312
|
blank(exp);
|
|
2406
2313
|
} else if (target) {
|
|
2407
|
-
|
|
2314
|
+
requests.push({ path: target, want: { all: needs.all, names: unresolvedNames } });
|
|
2408
2315
|
}
|
|
2409
2316
|
continue;
|
|
2410
2317
|
}
|
|
@@ -2412,13 +2319,14 @@ var SchemaTypeProgram = class {
|
|
|
2412
2319
|
(n) => needs.all || needs.names.has((n.getAliasNode() ?? n.getNameNode()).getText())
|
|
2413
2320
|
).map((n) => n.getNameNode().getText());
|
|
2414
2321
|
if (wanted.length === 0) blank(exp);
|
|
2415
|
-
else if (target)
|
|
2322
|
+
else if (target) requests.push({ path: target, want: { names: wanted } });
|
|
2416
2323
|
}
|
|
2417
|
-
return chars.join("");
|
|
2324
|
+
return { text: chars.join(""), requests, resolved };
|
|
2418
2325
|
}
|
|
2419
2326
|
/**
|
|
2420
|
-
* The project source file a module specifier resolves to
|
|
2421
|
-
* package (read unpruned by the program itself)
|
|
2327
|
+
* The project source file a module specifier resolves to; undefined for a
|
|
2328
|
+
* package or a declaration file (read unpruned by the program itself), null for
|
|
2329
|
+
* one that does not resolve.
|
|
2422
2330
|
*/
|
|
2423
2331
|
resolve(specifier, from) {
|
|
2424
2332
|
const resolved = import_ts_morph7.ts.resolveModuleName(
|
|
@@ -2427,7 +2335,8 @@ var SchemaTypeProgram = class {
|
|
|
2427
2335
|
this.options,
|
|
2428
2336
|
import_ts_morph7.ts.sys
|
|
2429
2337
|
).resolvedModule;
|
|
2430
|
-
if (!resolved
|
|
2338
|
+
if (!resolved) return null;
|
|
2339
|
+
if (resolved.isExternalLibraryImport) return void 0;
|
|
2431
2340
|
const file = resolved.resolvedFileName;
|
|
2432
2341
|
if (file.endsWith(".d.ts") || !/\.(m|c)?tsx?$/.test(file)) return void 0;
|
|
2433
2342
|
return file;
|
|
@@ -2482,8 +2391,13 @@ function defaultExport(sf) {
|
|
|
2482
2391
|
|
|
2483
2392
|
// src/discovery/schema-type-inference.ts
|
|
2484
2393
|
var programs = /* @__PURE__ */ new WeakMap();
|
|
2394
|
+
var stale = /* @__PURE__ */ new WeakSet();
|
|
2485
2395
|
function programFor(discovery) {
|
|
2486
2396
|
let program = programs.get(discovery);
|
|
2397
|
+
if (program && stale.has(discovery)) {
|
|
2398
|
+
stale.delete(discovery);
|
|
2399
|
+
if (!program.refresh()) program = void 0;
|
|
2400
|
+
}
|
|
2487
2401
|
if (!program) {
|
|
2488
2402
|
program = new SchemaTypeProgram(discovery);
|
|
2489
2403
|
programs.set(discovery, program);
|
|
@@ -2492,6 +2406,10 @@ function programFor(discovery) {
|
|
|
2492
2406
|
}
|
|
2493
2407
|
function clearSchemaTypeProject(discovery) {
|
|
2494
2408
|
programs.delete(discovery);
|
|
2409
|
+
stale.delete(discovery);
|
|
2410
|
+
}
|
|
2411
|
+
function invalidateSchemaTypeProject(discovery) {
|
|
2412
|
+
if (programs.has(discovery)) stale.add(discovery);
|
|
2495
2413
|
}
|
|
2496
2414
|
function counterpart(typedSf, node) {
|
|
2497
2415
|
const start = node.getStart();
|
|
@@ -3439,7 +3357,7 @@ async function discoverContractsFast(opts) {
|
|
|
3439
3357
|
return routes;
|
|
3440
3358
|
}
|
|
3441
3359
|
function resolveTsconfigPath(cwd, tsconfig) {
|
|
3442
|
-
return tsconfig ? (0,
|
|
3360
|
+
return tsconfig ? (0, import_node_path4.resolve)(tsconfig) : (0, import_node_path4.join)(cwd, "tsconfig.json");
|
|
3443
3361
|
}
|
|
3444
3362
|
var NO_TSCONFIG_OPTIONS = {
|
|
3445
3363
|
allowJs: true,
|
|
@@ -3447,7 +3365,7 @@ var NO_TSCONFIG_OPTIONS = {
|
|
|
3447
3365
|
strict: false
|
|
3448
3366
|
};
|
|
3449
3367
|
function loadDiscoveryTsconfig(tsconfigPath) {
|
|
3450
|
-
if (!(0,
|
|
3368
|
+
if (!(0, import_node_fs2.existsSync)(tsconfigPath)) return { options: null, files: [] };
|
|
3451
3369
|
const read = import_ts_morph12.ts.readConfigFile(tsconfigPath, (path) => import_ts_morph12.ts.sys.readFile(path));
|
|
3452
3370
|
if (read.error) {
|
|
3453
3371
|
return {
|
|
@@ -3469,7 +3387,7 @@ function loadDiscoveryTsconfig(tsconfigPath) {
|
|
|
3469
3387
|
const parsed = import_ts_morph12.ts.parseJsonSourceFileConfigFileContent(
|
|
3470
3388
|
sourceFile,
|
|
3471
3389
|
host,
|
|
3472
|
-
(0,
|
|
3390
|
+
(0, import_node_path4.dirname)(tsconfigPath),
|
|
3473
3391
|
void 0,
|
|
3474
3392
|
tsconfigPath
|
|
3475
3393
|
);
|
|
@@ -3531,6 +3449,9 @@ var PersistentDiscovery = class _PersistentDiscovery {
|
|
|
3531
3449
|
glob;
|
|
3532
3450
|
/** Absolute paths of the controllers currently loaded as extraction roots. */
|
|
3533
3451
|
controllerPaths = /* @__PURE__ */ new Set();
|
|
3452
|
+
/** Every file in {@link project}, as last read from disk. */
|
|
3453
|
+
files = new DiskFingerprints();
|
|
3454
|
+
unresolved = new UnresolvedImports();
|
|
3534
3455
|
constructor(project, cwd, glob) {
|
|
3535
3456
|
this.project = project;
|
|
3536
3457
|
this.cwd = cwd;
|
|
@@ -3556,6 +3477,8 @@ var PersistentDiscovery = class _PersistentDiscovery {
|
|
|
3556
3477
|
}
|
|
3557
3478
|
/** Run the initial extraction (equivalent to a first `discoverContractsFast`). */
|
|
3558
3479
|
discover() {
|
|
3480
|
+
clearMixinTypeProject();
|
|
3481
|
+
clearSchemaTypeProject(this.project);
|
|
3559
3482
|
return this.runExtraction();
|
|
3560
3483
|
}
|
|
3561
3484
|
/**
|
|
@@ -3563,26 +3486,39 @@ var PersistentDiscovery = class _PersistentDiscovery {
|
|
|
3563
3486
|
* from disk (controllers AND any lazily-loaded DTO/imported files), re-globs
|
|
3564
3487
|
* to pick up added/removed controllers, clears the per-Project caches, then
|
|
3565
3488
|
* re-extracts. `changedPaths` is a hint; correctness does not depend on it
|
|
3566
|
-
* being exhaustive because re-globbing +
|
|
3489
|
+
* being exhaustive because re-globbing + comparing every loaded file with the
|
|
3490
|
+
* disk covers the set.
|
|
3567
3491
|
*/
|
|
3568
|
-
async rediscover(changedPaths) {
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
3574
|
-
|
|
3575
|
-
|
|
3492
|
+
async rediscover(changedPaths, options = {}) {
|
|
3493
|
+
const hinted = new Set([...changedPaths ?? []].map((p) => (0, import_node_path4.resolve)(p)));
|
|
3494
|
+
const program = this.project.getProgram().compilerObject;
|
|
3495
|
+
const sources = program.getSourceFiles().filter(
|
|
3496
|
+
(file) => !program.isSourceFileDefaultLibrary(file) && !program.isSourceFileFromExternalLibrary(file)
|
|
3497
|
+
).map((file) => ({ path: file.fileName, text: file.text }));
|
|
3498
|
+
for (const path of /* @__PURE__ */ new Set([...hinted, ...this.files.changed(sources)])) {
|
|
3499
|
+
const sf = this.project.getSourceFile(path);
|
|
3500
|
+
if (sf && await sf.refreshFromFileSystem() === import_ts_morph12.FileSystemRefreshResult.Deleted) {
|
|
3501
|
+
this.files.forget(path);
|
|
3576
3502
|
}
|
|
3577
3503
|
}
|
|
3504
|
+
const inProject = new Set(this.project.getSourceFiles().map((sf) => sf.getFilePath()));
|
|
3505
|
+
const definitions = this.project.getLanguageService().compilerObject.getProgram();
|
|
3506
|
+
for (const path of definitions ? this.unresolved.nowResolving(definitions) : []) {
|
|
3507
|
+
const sf = this.project.getSourceFile(path);
|
|
3508
|
+
if (!sf) continue;
|
|
3509
|
+
this.project.removeSourceFile(sf);
|
|
3510
|
+
if (inProject.has(path)) this.project.addSourceFileAtPathIfExists(path);
|
|
3511
|
+
}
|
|
3578
3512
|
const globbed = new Set(
|
|
3579
3513
|
await (0, import_fast_glob2.default)(this.glob, { cwd: this.cwd, absolute: true, onlyFiles: true })
|
|
3580
3514
|
);
|
|
3515
|
+
let controllersChanged = false;
|
|
3581
3516
|
for (const f of globbed) {
|
|
3582
3517
|
if (!this.controllerPaths.has(f)) {
|
|
3583
3518
|
try {
|
|
3584
3519
|
this.project.addSourceFileAtPath(f);
|
|
3585
3520
|
this.controllerPaths.add(f);
|
|
3521
|
+
controllersChanged = true;
|
|
3586
3522
|
} catch {
|
|
3587
3523
|
}
|
|
3588
3524
|
}
|
|
@@ -3592,16 +3528,22 @@ var PersistentDiscovery = class _PersistentDiscovery {
|
|
|
3592
3528
|
const sf = this.project.getSourceFile(f);
|
|
3593
3529
|
if (sf) this.project.removeSourceFile(sf);
|
|
3594
3530
|
this.controllerPaths.delete(f);
|
|
3531
|
+
controllersChanged = true;
|
|
3595
3532
|
}
|
|
3596
3533
|
}
|
|
3534
|
+
if (controllersChanged || options.filesAddedOrRemoved) {
|
|
3535
|
+
clearMixinTypeProject();
|
|
3536
|
+
clearSchemaTypeProject(this.project);
|
|
3537
|
+
} else {
|
|
3538
|
+
invalidateMixinTypeProject();
|
|
3539
|
+
invalidateSchemaTypeProject(this.project);
|
|
3540
|
+
}
|
|
3597
3541
|
return this.runExtraction();
|
|
3598
3542
|
}
|
|
3599
3543
|
/** Clear stale per-Project caches, then extract over the controller set. */
|
|
3600
3544
|
runExtraction() {
|
|
3601
3545
|
clearTypeResolutionCaches(this.project);
|
|
3602
3546
|
clearEnumCache(this.project);
|
|
3603
|
-
clearMixinTypeProject();
|
|
3604
|
-
clearSchemaTypeProject(this.project);
|
|
3605
3547
|
return extractRoutesFrom(this.project, this.controllerPaths);
|
|
3606
3548
|
}
|
|
3607
3549
|
};
|
|
@@ -3888,7 +3830,300 @@ function extractFromSourceFile(sourceFile, project) {
|
|
|
3888
3830
|
return routes;
|
|
3889
3831
|
}
|
|
3890
3832
|
|
|
3833
|
+
// src/discovery/shared-props.ts
|
|
3834
|
+
function discoverSharedProps(project, moduleEntry) {
|
|
3835
|
+
try {
|
|
3836
|
+
let sourceFile = project.getSourceFile(moduleEntry);
|
|
3837
|
+
if (!sourceFile) {
|
|
3838
|
+
try {
|
|
3839
|
+
sourceFile = project.addSourceFileAtPath(moduleEntry);
|
|
3840
|
+
} catch {
|
|
3841
|
+
return null;
|
|
3842
|
+
}
|
|
3843
|
+
}
|
|
3844
|
+
const forRootCall = findForRootCall(sourceFile);
|
|
3845
|
+
if (!forRootCall) return null;
|
|
3846
|
+
const initializer = findShareInitializer(forRootCall);
|
|
3847
|
+
if (!initializer) return null;
|
|
3848
|
+
return extractShareType(initializer, sourceFile, project);
|
|
3849
|
+
} catch {
|
|
3850
|
+
return null;
|
|
3851
|
+
}
|
|
3852
|
+
}
|
|
3853
|
+
function discoverSharedPropsFromConfig(config) {
|
|
3854
|
+
if (!config.app?.moduleEntry) return null;
|
|
3855
|
+
try {
|
|
3856
|
+
const tsconfigPath = config.app.tsconfig ?? (0, import_node_path5.join)(config.codegen.cwd, "tsconfig.json");
|
|
3857
|
+
let project;
|
|
3858
|
+
try {
|
|
3859
|
+
project = sharedPropsProject(tsconfigPath);
|
|
3860
|
+
} catch {
|
|
3861
|
+
project = new import_ts_morph13.Project({
|
|
3862
|
+
skipAddingFilesFromTsConfig: true,
|
|
3863
|
+
skipLoadingLibFiles: true,
|
|
3864
|
+
skipFileDependencyResolution: true,
|
|
3865
|
+
compilerOptions: { allowJs: true, strict: false }
|
|
3866
|
+
});
|
|
3867
|
+
}
|
|
3868
|
+
return discoverSharedProps(project, config.app.moduleEntry);
|
|
3869
|
+
} catch {
|
|
3870
|
+
return null;
|
|
3871
|
+
}
|
|
3872
|
+
}
|
|
3873
|
+
var parsedTsconfigs = /* @__PURE__ */ new Map();
|
|
3874
|
+
function readText(file) {
|
|
3875
|
+
try {
|
|
3876
|
+
return (0, import_node_fs3.readFileSync)(file, "utf8");
|
|
3877
|
+
} catch {
|
|
3878
|
+
return "\0missing";
|
|
3879
|
+
}
|
|
3880
|
+
}
|
|
3881
|
+
function sharedPropsProject(tsconfigPath) {
|
|
3882
|
+
const text = loadDiscoveryTsconfig(tsconfigPath).files.map((file) => `${file}\0${readText(file)}`).join("\0");
|
|
3883
|
+
const flags = {
|
|
3884
|
+
skipAddingFilesFromTsConfig: true,
|
|
3885
|
+
skipLoadingLibFiles: true,
|
|
3886
|
+
skipFileDependencyResolution: true
|
|
3887
|
+
};
|
|
3888
|
+
const parsed = parsedTsconfigs.get(tsconfigPath);
|
|
3889
|
+
if (parsed?.text === text) return new import_ts_morph13.Project({ ...flags, compilerOptions: parsed.options });
|
|
3890
|
+
const project = new import_ts_morph13.Project({ ...flags, tsConfigFilePath: tsconfigPath });
|
|
3891
|
+
parsedTsconfigs.set(tsconfigPath, { text, options: project.getCompilerOptions() });
|
|
3892
|
+
return project;
|
|
3893
|
+
}
|
|
3894
|
+
function findForRootCall(sourceFile) {
|
|
3895
|
+
const callExpressions = sourceFile.getDescendantsOfKind(import_ts_morph13.SyntaxKind.CallExpression);
|
|
3896
|
+
for (const call of callExpressions) {
|
|
3897
|
+
const expr = call.getExpression();
|
|
3898
|
+
if (!import_ts_morph13.Node.isPropertyAccessExpression(expr)) continue;
|
|
3899
|
+
const methodName = expr.getName();
|
|
3900
|
+
const objectExpr = expr.getExpression();
|
|
3901
|
+
if (methodName === "forRoot" && import_ts_morph13.Node.isIdentifier(objectExpr)) {
|
|
3902
|
+
const name = objectExpr.getText();
|
|
3903
|
+
if (name === "InertiaModule") {
|
|
3904
|
+
return call;
|
|
3905
|
+
}
|
|
3906
|
+
}
|
|
3907
|
+
}
|
|
3908
|
+
return null;
|
|
3909
|
+
}
|
|
3910
|
+
function findShareInitializer(forRootCall) {
|
|
3911
|
+
if (!import_ts_morph13.Node.isCallExpression(forRootCall)) return null;
|
|
3912
|
+
const args = forRootCall.getArguments();
|
|
3913
|
+
const firstArg2 = args[0];
|
|
3914
|
+
if (!firstArg2 || !import_ts_morph13.Node.isObjectLiteralExpression(firstArg2)) return null;
|
|
3915
|
+
for (const prop of firstArg2.getProperties()) {
|
|
3916
|
+
if (import_ts_morph13.Node.isPropertyAssignment(prop) && prop.getName() === "share") {
|
|
3917
|
+
return prop.getInitializer() ?? null;
|
|
3918
|
+
}
|
|
3919
|
+
}
|
|
3920
|
+
return null;
|
|
3921
|
+
}
|
|
3922
|
+
function extractShareType(node, sourceFile, project) {
|
|
3923
|
+
if (import_ts_morph13.Node.isIdentifier(node)) {
|
|
3924
|
+
const ref = resolveIdentifierToImportRef(node, sourceFile, project);
|
|
3925
|
+
if (ref) {
|
|
3926
|
+
return {
|
|
3927
|
+
typeString: `Awaited<ReturnType<typeof import('${ref.importPath}').${ref.exportName}>>`,
|
|
3928
|
+
properties: null,
|
|
3929
|
+
isImportRef: true
|
|
3930
|
+
};
|
|
3931
|
+
}
|
|
3932
|
+
}
|
|
3933
|
+
if (import_ts_morph13.Node.isArrowFunction(node)) {
|
|
3934
|
+
const result = extractFromFunctionLike(node, sourceFile);
|
|
3935
|
+
return result ? { ...result, isImportRef: false } : null;
|
|
3936
|
+
}
|
|
3937
|
+
if (import_ts_morph13.Node.isFunctionExpression(node)) {
|
|
3938
|
+
const result = extractFromFunctionLike(node, sourceFile);
|
|
3939
|
+
return result ? { ...result, isImportRef: false } : null;
|
|
3940
|
+
}
|
|
3941
|
+
if (import_ts_morph13.Node.isObjectLiteralExpression(node)) {
|
|
3942
|
+
const result = extractFromObjectLiteral(node);
|
|
3943
|
+
return result ? { ...result, isImportRef: false } : null;
|
|
3944
|
+
}
|
|
3945
|
+
return null;
|
|
3946
|
+
}
|
|
3947
|
+
function resolveIdentifierToImportRef(id, sourceFile, project) {
|
|
3948
|
+
if (!import_ts_morph13.Node.isIdentifier(id)) return null;
|
|
3949
|
+
const name = id.getText();
|
|
3950
|
+
const localFunc = sourceFile.getFunction(name);
|
|
3951
|
+
if (localFunc?.isExported()) {
|
|
3952
|
+
const filePath = sourceFile.getFilePath().replace(/\.ts$/, "");
|
|
3953
|
+
return { importPath: filePath, exportName: name };
|
|
3954
|
+
}
|
|
3955
|
+
const localVar = sourceFile.getVariableDeclaration(name);
|
|
3956
|
+
if (localVar?.isExported()) {
|
|
3957
|
+
const filePath = sourceFile.getFilePath().replace(/\.ts$/, "");
|
|
3958
|
+
return { importPath: filePath, exportName: name };
|
|
3959
|
+
}
|
|
3960
|
+
for (const imp of sourceFile.getImportDeclarations()) {
|
|
3961
|
+
for (const named of imp.getNamedImports()) {
|
|
3962
|
+
const importedName = named.getAliasNode()?.getText() ?? named.getName();
|
|
3963
|
+
if (importedName !== name) continue;
|
|
3964
|
+
const resolvedSource = imp.getModuleSpecifierSourceFile();
|
|
3965
|
+
if (!resolvedSource) continue;
|
|
3966
|
+
const originalName = named.getName();
|
|
3967
|
+
const fn = resolvedSource.getFunction(originalName);
|
|
3968
|
+
if (fn?.isExported()) {
|
|
3969
|
+
const filePath = resolvedSource.getFilePath().replace(/\.ts$/, "");
|
|
3970
|
+
return { importPath: filePath, exportName: originalName };
|
|
3971
|
+
}
|
|
3972
|
+
const v = resolvedSource.getVariableDeclaration(originalName);
|
|
3973
|
+
if (v?.isExported()) {
|
|
3974
|
+
const filePath = resolvedSource.getFilePath().replace(/\.ts$/, "");
|
|
3975
|
+
return { importPath: filePath, exportName: originalName };
|
|
3976
|
+
}
|
|
3977
|
+
}
|
|
3978
|
+
}
|
|
3979
|
+
return null;
|
|
3980
|
+
}
|
|
3981
|
+
function extractFromFunctionLike(node, _sourceFile) {
|
|
3982
|
+
const returnTypeNode = import_ts_morph13.Node.isArrowFunction(node) || import_ts_morph13.Node.isFunctionExpression(node) ? node.getReturnTypeNode() : null;
|
|
3983
|
+
if (returnTypeNode) {
|
|
3984
|
+
return extractFromReturnTypeAnnotation(returnTypeNode);
|
|
3985
|
+
}
|
|
3986
|
+
if (import_ts_morph13.Node.isArrowFunction(node)) {
|
|
3987
|
+
const body = node.getBody();
|
|
3988
|
+
if (import_ts_morph13.Node.isParenthesizedExpression(body)) {
|
|
3989
|
+
const inner = body.getExpression();
|
|
3990
|
+
if (import_ts_morph13.Node.isObjectLiteralExpression(inner)) {
|
|
3991
|
+
return extractFromObjectLiteral(inner);
|
|
3992
|
+
}
|
|
3993
|
+
}
|
|
3994
|
+
if (import_ts_morph13.Node.isObjectLiteralExpression(body)) {
|
|
3995
|
+
return extractFromObjectLiteral(body);
|
|
3996
|
+
}
|
|
3997
|
+
if (import_ts_morph13.Node.isBlock(body)) {
|
|
3998
|
+
return extractFromBlockReturn(body);
|
|
3999
|
+
}
|
|
4000
|
+
}
|
|
4001
|
+
if (import_ts_morph13.Node.isFunctionExpression(node)) {
|
|
4002
|
+
const body = node.getBody();
|
|
4003
|
+
if (import_ts_morph13.Node.isBlock(body)) {
|
|
4004
|
+
return extractFromBlockReturn(body);
|
|
4005
|
+
}
|
|
4006
|
+
}
|
|
4007
|
+
return null;
|
|
4008
|
+
}
|
|
4009
|
+
function extractFromReturnTypeAnnotation(typeNode) {
|
|
4010
|
+
if (import_ts_morph13.Node.isTypeReference(typeNode)) {
|
|
4011
|
+
const typeName = typeNode.getTypeName();
|
|
4012
|
+
if (import_ts_morph13.Node.isIdentifier(typeName) && typeName.getText() === "Promise") {
|
|
4013
|
+
const typeArgs = typeNode.getTypeArguments();
|
|
4014
|
+
const firstArg2 = typeArgs[0];
|
|
4015
|
+
if (firstArg2) {
|
|
4016
|
+
return extractFromReturnTypeAnnotation(firstArg2);
|
|
4017
|
+
}
|
|
4018
|
+
return null;
|
|
4019
|
+
}
|
|
4020
|
+
}
|
|
4021
|
+
if (import_ts_morph13.Node.isTypeLiteral(typeNode)) {
|
|
4022
|
+
const properties = [];
|
|
4023
|
+
for (const member of typeNode.getMembers()) {
|
|
4024
|
+
if (import_ts_morph13.Node.isPropertySignature(member)) {
|
|
4025
|
+
const name = member.getName();
|
|
4026
|
+
const memberTypeNode = member.getTypeNode();
|
|
4027
|
+
const type = memberTypeNode ? memberTypeNode.getText() : "unknown";
|
|
4028
|
+
properties.push({ name, type });
|
|
4029
|
+
}
|
|
4030
|
+
}
|
|
4031
|
+
if (properties.length === 0) return null;
|
|
4032
|
+
const typeString = `{ ${properties.map((p) => `${p.name}: ${p.type}`).join("; ")} }`;
|
|
4033
|
+
return { typeString, properties, isImportRef: false };
|
|
4034
|
+
}
|
|
4035
|
+
return null;
|
|
4036
|
+
}
|
|
4037
|
+
function extractFromBlockReturn(block) {
|
|
4038
|
+
if (!import_ts_morph13.Node.isBlock(block)) return null;
|
|
4039
|
+
const statements = block.getStatements();
|
|
4040
|
+
for (let i = statements.length - 1; i >= 0; i--) {
|
|
4041
|
+
const stmt = statements[i];
|
|
4042
|
+
if (!import_ts_morph13.Node.isReturnStatement(stmt)) continue;
|
|
4043
|
+
const expr = stmt.getExpression();
|
|
4044
|
+
if (!expr) continue;
|
|
4045
|
+
if (import_ts_morph13.Node.isObjectLiteralExpression(expr)) {
|
|
4046
|
+
return extractFromObjectLiteral(expr);
|
|
4047
|
+
}
|
|
4048
|
+
if (import_ts_morph13.Node.isParenthesizedExpression(expr)) {
|
|
4049
|
+
const inner = expr.getExpression();
|
|
4050
|
+
if (import_ts_morph13.Node.isObjectLiteralExpression(inner)) {
|
|
4051
|
+
return extractFromObjectLiteral(inner);
|
|
4052
|
+
}
|
|
4053
|
+
}
|
|
4054
|
+
break;
|
|
4055
|
+
}
|
|
4056
|
+
return null;
|
|
4057
|
+
}
|
|
4058
|
+
function extractFromObjectLiteral(objLiteral) {
|
|
4059
|
+
if (!import_ts_morph13.Node.isObjectLiteralExpression(objLiteral)) return null;
|
|
4060
|
+
const properties = [];
|
|
4061
|
+
for (const prop of objLiteral.getProperties()) {
|
|
4062
|
+
if (!import_ts_morph13.Node.isPropertyAssignment(prop)) continue;
|
|
4063
|
+
const name = prop.getName();
|
|
4064
|
+
const initializer = prop.getInitializer();
|
|
4065
|
+
if (!initializer) continue;
|
|
4066
|
+
const type = inferExpressionType(initializer);
|
|
4067
|
+
properties.push({ name, type });
|
|
4068
|
+
}
|
|
4069
|
+
if (properties.length === 0) return null;
|
|
4070
|
+
const typeString = `{ ${properties.map((p) => `${p.name}: ${p.type}`).join("; ")} }`;
|
|
4071
|
+
return { typeString, properties, isImportRef: false };
|
|
4072
|
+
}
|
|
4073
|
+
function inferExpressionType(node) {
|
|
4074
|
+
if (import_ts_morph13.Node.isStringLiteral(node)) return "string";
|
|
4075
|
+
if (import_ts_morph13.Node.isTemplateExpression(node) || import_ts_morph13.Node.isNoSubstitutionTemplateLiteral(node))
|
|
4076
|
+
return "string";
|
|
4077
|
+
if (import_ts_morph13.Node.isNumericLiteral(node)) return "number";
|
|
4078
|
+
if (node.getKind() === import_ts_morph13.SyntaxKind.TrueKeyword || node.getKind() === import_ts_morph13.SyntaxKind.FalseKeyword) {
|
|
4079
|
+
return "boolean";
|
|
4080
|
+
}
|
|
4081
|
+
if (node.getKind() === import_ts_morph13.SyntaxKind.NullKeyword) return "null";
|
|
4082
|
+
if (import_ts_morph13.Node.isIdentifier(node) && node.getText() === "undefined") return "undefined";
|
|
4083
|
+
if (import_ts_morph13.Node.isObjectLiteralExpression(node)) {
|
|
4084
|
+
const props = node.getProperties();
|
|
4085
|
+
if (props.length === 0) return "Record<string, unknown>";
|
|
4086
|
+
const entries = [];
|
|
4087
|
+
for (const prop of props) {
|
|
4088
|
+
if (!import_ts_morph13.Node.isPropertyAssignment(prop)) continue;
|
|
4089
|
+
const key = prop.getName();
|
|
4090
|
+
const init = prop.getInitializer();
|
|
4091
|
+
if (!init) continue;
|
|
4092
|
+
entries.push(`${key}: ${inferExpressionType(init)}`);
|
|
4093
|
+
}
|
|
4094
|
+
if (entries.length === 0) return "Record<string, unknown>";
|
|
4095
|
+
return `{ ${entries.join("; ")} }`;
|
|
4096
|
+
}
|
|
4097
|
+
if (import_ts_morph13.Node.isArrayLiteralExpression(node)) {
|
|
4098
|
+
const elements = node.getElements();
|
|
4099
|
+
if (elements.length === 0) return "Array<unknown>";
|
|
4100
|
+
const first = elements[0];
|
|
4101
|
+
if (first) return `Array<${inferExpressionType(first)}>`;
|
|
4102
|
+
return "Array<unknown>";
|
|
4103
|
+
}
|
|
4104
|
+
if (import_ts_morph13.Node.isConditionalExpression(node)) {
|
|
4105
|
+
const whenTrue = inferExpressionType(node.getWhenTrue());
|
|
4106
|
+
const whenFalse = inferExpressionType(node.getWhenFalse());
|
|
4107
|
+
if (whenTrue === whenFalse) return whenTrue;
|
|
4108
|
+
return `${whenTrue} | ${whenFalse}`;
|
|
4109
|
+
}
|
|
4110
|
+
if (import_ts_morph13.Node.isParenthesizedExpression(node)) {
|
|
4111
|
+
return inferExpressionType(node.getExpression());
|
|
4112
|
+
}
|
|
4113
|
+
if (import_ts_morph13.Node.isAsExpression(node)) {
|
|
4114
|
+
const typeNode = node.getTypeNode();
|
|
4115
|
+
if (typeNode) return typeNode.getText();
|
|
4116
|
+
}
|
|
4117
|
+
return "unknown";
|
|
4118
|
+
}
|
|
4119
|
+
|
|
4120
|
+
// src/emit/emit-api.ts
|
|
4121
|
+
var import_promises3 = require("fs/promises");
|
|
4122
|
+
var import_node_path7 = require("path");
|
|
4123
|
+
|
|
3891
4124
|
// src/extension/registry.ts
|
|
4125
|
+
var import_node_path6 = require("path");
|
|
4126
|
+
var import_ts_morph14 = require("ts-morph");
|
|
3892
4127
|
function resolveApiSlots(extensions) {
|
|
3893
4128
|
let layer;
|
|
3894
4129
|
let layerOwner;
|
|
@@ -3939,7 +4174,7 @@ function createExtensionContext(config, getRoutes, trackedInputs) {
|
|
|
3939
4174
|
},
|
|
3940
4175
|
project() {
|
|
3941
4176
|
if (!project) {
|
|
3942
|
-
project = new
|
|
4177
|
+
project = new import_ts_morph14.Project({
|
|
3943
4178
|
skipAddingFilesFromTsConfig: true,
|
|
3944
4179
|
skipLoadingLibFiles: true,
|
|
3945
4180
|
skipFileDependencyResolution: true,
|
|
@@ -5673,36 +5908,64 @@ async function discoverInputFiles(config) {
|
|
|
5673
5908
|
const matched = await (0, import_fast_glob3.default)(globs, { cwd, absolute: true, onlyFiles: true });
|
|
5674
5909
|
return [...new Set(matched)].sort();
|
|
5675
5910
|
}
|
|
5676
|
-
|
|
5911
|
+
var READ_CONCURRENCY = 64;
|
|
5912
|
+
async function readAll(paths, read) {
|
|
5913
|
+
const out = /* @__PURE__ */ new Map();
|
|
5914
|
+
for (let i = 0; i < paths.length; i += READ_CONCURRENCY) {
|
|
5915
|
+
const batch = paths.slice(i, i + READ_CONCURRENCY);
|
|
5916
|
+
const texts = await Promise.all(batch.map(read));
|
|
5917
|
+
batch.forEach((path, j) => out.set(path, texts[j]));
|
|
5918
|
+
}
|
|
5919
|
+
return out;
|
|
5920
|
+
}
|
|
5921
|
+
async function readInputs(config) {
|
|
5922
|
+
const cwd = config.codegen.cwd;
|
|
5923
|
+
const tsconfigPath = resolveTsconfigPath(cwd, config.app?.tsconfig ?? void 0);
|
|
5924
|
+
const extended = loadDiscoveryTsconfig(tsconfigPath).files;
|
|
5925
|
+
const tsconfigFiles = extended.length > 0 ? extended : [tsconfigPath];
|
|
5926
|
+
const files = await discoverInputFiles(config);
|
|
5927
|
+
const contents = /* @__PURE__ */ new Map();
|
|
5928
|
+
const tsconfigs = await readAll(
|
|
5929
|
+
tsconfigFiles,
|
|
5930
|
+
(file) => (0, import_promises11.readFile)(file, "utf8").catch(() => null)
|
|
5931
|
+
);
|
|
5932
|
+
for (const [file, text] of tsconfigs) contents.set(file, text);
|
|
5933
|
+
for (const [file, text] of await readAll(files, (file2) => (0, import_promises11.readFile)(file2, "utf8"))) {
|
|
5934
|
+
contents.set(file, text);
|
|
5935
|
+
}
|
|
5936
|
+
return { tsconfigFiles, files, contents, tracked: /* @__PURE__ */ new Map() };
|
|
5937
|
+
}
|
|
5938
|
+
async function readInput(snapshot, path) {
|
|
5939
|
+
return snapshot.contents.get(path) ?? (0, import_promises11.readFile)(path, "utf8");
|
|
5940
|
+
}
|
|
5941
|
+
async function computeInputsHash(config, extraInputs = [], snapshot) {
|
|
5942
|
+
const inputs = snapshot ?? await readInputs(config);
|
|
5677
5943
|
const hash = (0, import_node_crypto.createHash)("sha256");
|
|
5678
5944
|
hash.update(`version:${VERSION}
|
|
5679
5945
|
`);
|
|
5680
5946
|
hash.update(`config:${serializeConfig(config)}
|
|
5681
5947
|
`);
|
|
5682
5948
|
const cwd = config.codegen.cwd;
|
|
5683
|
-
const
|
|
5684
|
-
const tsconfigFiles = loadDiscoveryTsconfig(tsconfigPath).files;
|
|
5685
|
-
for (const file of tsconfigFiles.length > 0 ? tsconfigFiles : [tsconfigPath]) {
|
|
5686
|
-
const contents = await (0, import_promises11.readFile)(file, "utf8").catch(() => null);
|
|
5949
|
+
for (const file of inputs.tsconfigFiles) {
|
|
5687
5950
|
hash.update(`tsconfig:${(0, import_node_path15.relative)(cwd, file)}
|
|
5688
5951
|
`);
|
|
5689
|
-
hash.update(contents ?? " missing");
|
|
5952
|
+
hash.update(inputs.contents.get(file) ?? " missing");
|
|
5690
5953
|
hash.update("\n");
|
|
5691
5954
|
}
|
|
5692
|
-
const
|
|
5693
|
-
const globbedRelative = new Set(globbed.map((file) => (0, import_node_path15.relative)(cwd, file)));
|
|
5955
|
+
const globbedRelative = new Set(inputs.files.map((file) => (0, import_node_path15.relative)(cwd, file)));
|
|
5694
5956
|
const extra = [...new Set(extraInputs)].filter((file) => !globbedRelative.has(file)).sort();
|
|
5695
|
-
for (const file of
|
|
5696
|
-
const contents = await (0, import_promises11.readFile)(file, "utf8");
|
|
5957
|
+
for (const file of inputs.files) {
|
|
5697
5958
|
hash.update(`file:${(0, import_node_path15.relative)(cwd, file)}
|
|
5698
5959
|
`);
|
|
5699
|
-
hash.update(contents);
|
|
5960
|
+
hash.update(inputs.contents.get(file));
|
|
5700
5961
|
hash.update("\n");
|
|
5701
5962
|
}
|
|
5963
|
+
const unread = extra.map((file) => (0, import_node_path15.join)(cwd, file)).filter((abs) => !inputs.tracked.has(abs));
|
|
5964
|
+
for (const [abs, text] of await readAll(unread, readTrackedInput)) inputs.tracked.set(abs, text);
|
|
5702
5965
|
for (const file of extra) {
|
|
5703
5966
|
hash.update(`extra:${file}
|
|
5704
5967
|
`);
|
|
5705
|
-
hash.update(
|
|
5968
|
+
hash.update(inputs.tracked.get((0, import_node_path15.join)(cwd, file)));
|
|
5706
5969
|
hash.update("\n");
|
|
5707
5970
|
}
|
|
5708
5971
|
return hash.digest("hex");
|
|
@@ -5783,14 +6046,15 @@ function driftGuardMessage(outDir, previousEntryPoint, currentEntryPoint, differ
|
|
|
5783
6046
|
async function generate(config, inputRoutes = [], entryPoint = "cli") {
|
|
5784
6047
|
setCodegenDebug(config.debug);
|
|
5785
6048
|
const manifest = await readManifest(config.codegen.outDir);
|
|
5786
|
-
const
|
|
6049
|
+
const inputs = await readInputs(config);
|
|
6050
|
+
const inputsHash = await computeInputsHash(config, manifest?.extraInputs ?? [], inputs);
|
|
5787
6051
|
if (await isManifestFresh(config.codegen.outDir, manifest, inputsHash)) {
|
|
5788
6052
|
console.log(`[nestjs-codegen] ${config.codegen.outDir} up to date, skipped`);
|
|
5789
6053
|
return;
|
|
5790
6054
|
}
|
|
5791
6055
|
const configHash = computeConfigHash(config);
|
|
5792
6056
|
const configKeyHashes = computeConfigKeyHashes(config);
|
|
5793
|
-
if (config.driftGuard && manifest?.entryPoint && manifest.entryPoint !== entryPoint && manifest.configHash && manifest.configHash !== configHash) {
|
|
6057
|
+
if (config.driftGuard && manifest?.version === VERSION && manifest?.entryPoint && manifest.entryPoint !== entryPoint && manifest.configHash && manifest.configHash !== configHash) {
|
|
5794
6058
|
throw new DriftGuardError(
|
|
5795
6059
|
driftGuardMessage(
|
|
5796
6060
|
config.codegen.outDir,
|
|
@@ -5811,7 +6075,7 @@ async function generate(config, inputRoutes = [], entryPoint = "cli") {
|
|
|
5811
6075
|
}
|
|
5812
6076
|
if (config.pages) {
|
|
5813
6077
|
const pagesConfig = config.pages;
|
|
5814
|
-
const pages = await discoverPageScopes(config);
|
|
6078
|
+
const pages = await discoverPageScopes(config, (path) => readInput(inputs, path));
|
|
5815
6079
|
const sharedProps = discoverSharedPropsFromConfig(config);
|
|
5816
6080
|
await emitPages(pages, config.codegen.outDir, {
|
|
5817
6081
|
propsExport: pagesConfig.propsExport,
|
|
@@ -5861,7 +6125,7 @@ async function generate(config, inputRoutes = [], entryPoint = "cli") {
|
|
|
5861
6125
|
}
|
|
5862
6126
|
const outputFiles = await listOutputFiles(config.codegen.outDir);
|
|
5863
6127
|
const extraInputs = [...trackedInputs].sort();
|
|
5864
|
-
const recordedHash = extraInputs.length > 0 ? await computeInputsHash(config, extraInputs) : inputsHash;
|
|
6128
|
+
const recordedHash = extraInputs.length > 0 ? await computeInputsHash(config, extraInputs, inputs) : inputsHash;
|
|
5865
6129
|
await writeManifest(config.codegen.outDir, {
|
|
5866
6130
|
version: VERSION,
|
|
5867
6131
|
hash: recordedHash,
|
|
@@ -6044,13 +6308,15 @@ async function watch(config, onChange, options = {}) {
|
|
|
6044
6308
|
pagesWatcher.on("unlink", schedulePagesRegenerate);
|
|
6045
6309
|
let contractsDebounceTimer;
|
|
6046
6310
|
const pendingChangedPaths = /* @__PURE__ */ new Set();
|
|
6311
|
+
let pendingAddedOrRemoved = false;
|
|
6047
6312
|
const contractsWatcher = import_chokidar.default.watch((0, import_node_path18.join)(config.codegen.cwd, config.contracts.glob), {
|
|
6048
6313
|
ignoreInitial: true,
|
|
6049
6314
|
persistent: true,
|
|
6050
6315
|
awaitWriteFinish: { stabilityThreshold: 80, pollInterval: 20 }
|
|
6051
6316
|
});
|
|
6052
|
-
function scheduleContractsRegenerate(changedPath) {
|
|
6317
|
+
function scheduleContractsRegenerate(changedPath, addedOrRemoved = false) {
|
|
6053
6318
|
if (typeof changedPath === "string") pendingChangedPaths.add(changedPath);
|
|
6319
|
+
if (addedOrRemoved) pendingAddedOrRemoved = true;
|
|
6054
6320
|
if (contractsDebounceTimer !== void 0) {
|
|
6055
6321
|
clearTimeout(contractsDebounceTimer);
|
|
6056
6322
|
}
|
|
@@ -6058,8 +6324,12 @@ async function watch(config, onChange, options = {}) {
|
|
|
6058
6324
|
contractsDebounceTimer = void 0;
|
|
6059
6325
|
const changed = [...pendingChangedPaths];
|
|
6060
6326
|
pendingChangedPaths.clear();
|
|
6327
|
+
const filesAddedOrRemoved = pendingAddedOrRemoved;
|
|
6328
|
+
pendingAddedOrRemoved = false;
|
|
6061
6329
|
try {
|
|
6062
|
-
const routes = await (await getDiscovery()).rediscover(changed
|
|
6330
|
+
const routes = await (await getDiscovery()).rediscover(changed, {
|
|
6331
|
+
filesAddedOrRemoved
|
|
6332
|
+
});
|
|
6063
6333
|
lastRoutes = routes;
|
|
6064
6334
|
await generateAndTrack(routes);
|
|
6065
6335
|
} catch (err) {
|
|
@@ -6071,20 +6341,25 @@ async function watch(config, onChange, options = {}) {
|
|
|
6071
6341
|
onChange?.();
|
|
6072
6342
|
}, config.contracts.debounceMs);
|
|
6073
6343
|
}
|
|
6074
|
-
contractsWatcher.on("add", (p) => scheduleContractsRegenerate(p));
|
|
6344
|
+
contractsWatcher.on("add", (p) => scheduleContractsRegenerate(p, true));
|
|
6075
6345
|
contractsWatcher.on("change", (p) => scheduleContractsRegenerate(p));
|
|
6076
|
-
contractsWatcher.on("unlink", (p) => scheduleContractsRegenerate(p));
|
|
6346
|
+
contractsWatcher.on("unlink", (p) => scheduleContractsRegenerate(p, true));
|
|
6077
6347
|
const formsWatcher = import_chokidar.default.watch((0, import_node_path18.join)(config.codegen.cwd, config.forms.watch), {
|
|
6078
6348
|
ignoreInitial: true,
|
|
6079
6349
|
persistent: true,
|
|
6080
6350
|
awaitWriteFinish: { stabilityThreshold: 80, pollInterval: 20 }
|
|
6081
6351
|
});
|
|
6082
|
-
formsWatcher.on("add", (p) => scheduleContractsRegenerate(p));
|
|
6352
|
+
formsWatcher.on("add", (p) => scheduleContractsRegenerate(p, true));
|
|
6083
6353
|
formsWatcher.on("change", (p) => scheduleContractsRegenerate(p));
|
|
6084
|
-
formsWatcher.on("unlink", (p) => scheduleContractsRegenerate(p));
|
|
6085
|
-
trackedWatcher.on("add", (p) => scheduleContractsRegenerate(p));
|
|
6354
|
+
formsWatcher.on("unlink", (p) => scheduleContractsRegenerate(p, true));
|
|
6355
|
+
trackedWatcher.on("add", (p) => scheduleContractsRegenerate(p, true));
|
|
6086
6356
|
trackedWatcher.on("change", (p) => scheduleContractsRegenerate(p));
|
|
6087
|
-
trackedWatcher.on("unlink", (p) => scheduleContractsRegenerate(p));
|
|
6357
|
+
trackedWatcher.on("unlink", (p) => scheduleContractsRegenerate(p, true));
|
|
6358
|
+
await Promise.all(
|
|
6359
|
+
[pagesWatcher, contractsWatcher, formsWatcher].map(
|
|
6360
|
+
(w) => new Promise((resolveReady) => w.once("ready", () => resolveReady()))
|
|
6361
|
+
)
|
|
6362
|
+
);
|
|
6088
6363
|
return {
|
|
6089
6364
|
close: async () => {
|
|
6090
6365
|
if (pagesDebounceTimer !== void 0) {
|
|
@@ -6188,7 +6463,7 @@ function createChainModuleRenderer(opts) {
|
|
|
6188
6463
|
}
|
|
6189
6464
|
|
|
6190
6465
|
// src/extension/genui-sandbox-kit.ts
|
|
6191
|
-
var
|
|
6466
|
+
var import_node_fs4 = require("fs");
|
|
6192
6467
|
var import_node_path19 = require("path");
|
|
6193
6468
|
var import_fast_glob4 = __toESM(require("fast-glob"), 1);
|
|
6194
6469
|
var GENUI_KIT_MODULE = "@dudousxd/nestjs-agent-core/genui/kit";
|
|
@@ -6200,11 +6475,6 @@ var DEFAULT_KIT_DIRS = [
|
|
|
6200
6475
|
"app/components/ui",
|
|
6201
6476
|
"components/ui"
|
|
6202
6477
|
];
|
|
6203
|
-
var LEGACY_OPTIONS = {
|
|
6204
|
-
entry: "`entry: X` is now `components: X`",
|
|
6205
|
-
include: "`include: G` is now `components: G` (globs, files, directories or packages)",
|
|
6206
|
-
css: "`css: G` is now `styles: G` (the app's style entry files)"
|
|
6207
|
-
};
|
|
6208
6478
|
var MIN_CORE = "0.53.0";
|
|
6209
6479
|
async function loadKitModule(specifier = GENUI_KIT_MODULE) {
|
|
6210
6480
|
let mod;
|
|
@@ -6245,7 +6515,7 @@ function globBase(glob) {
|
|
|
6245
6515
|
return base.join("/");
|
|
6246
6516
|
}
|
|
6247
6517
|
function resolveKitFilesLocally(root, options) {
|
|
6248
|
-
const specs = options.components === void 0 ? DEFAULT_KIT_DIRS.filter((dir) => (0,
|
|
6518
|
+
const specs = options.components === void 0 ? DEFAULT_KIT_DIRS.filter((dir) => (0, import_node_fs4.existsSync)((0, import_node_path19.resolve)(root, dir))).slice(0, 1) : typeof options.components === "string" ? [options.components] : [...options.components];
|
|
6249
6519
|
const files = [];
|
|
6250
6520
|
const dirs = /* @__PURE__ */ new Set();
|
|
6251
6521
|
for (const spec of specs) {
|
|
@@ -6255,30 +6525,22 @@ function resolveKitFilesLocally(root, options) {
|
|
|
6255
6525
|
continue;
|
|
6256
6526
|
}
|
|
6257
6527
|
const path = (0, import_node_path19.isAbsolute)(spec) ? spec : (0, import_node_path19.resolve)(root, spec);
|
|
6258
|
-
if ((0,
|
|
6528
|
+
if ((0, import_node_fs4.existsSync)(path) && (0, import_node_fs4.statSync)(path).isDirectory()) {
|
|
6259
6529
|
files.push(...import_fast_glob4.default.sync("*.{tsx,jsx,ts,js}", { cwd: path, absolute: true, onlyFiles: true }));
|
|
6260
6530
|
dirs.add(path);
|
|
6261
|
-
} else if ((0,
|
|
6531
|
+
} else if ((0, import_node_fs4.existsSync)(path)) {
|
|
6262
6532
|
files.push(path);
|
|
6263
6533
|
dirs.add((0, import_node_path19.dirname)(path));
|
|
6264
6534
|
}
|
|
6265
6535
|
}
|
|
6266
6536
|
if (options.wrapper !== void 0) {
|
|
6267
6537
|
const wrapper = (0, import_node_path19.isAbsolute)(options.wrapper) ? options.wrapper : (0, import_node_path19.resolve)(root, options.wrapper);
|
|
6268
|
-
if ((0,
|
|
6538
|
+
if ((0, import_node_fs4.existsSync)(wrapper)) files.push(wrapper);
|
|
6269
6539
|
}
|
|
6270
6540
|
if (files.length === 0 && dirs.size === 0) return null;
|
|
6271
6541
|
return { files: [...new Set(files)].sort(), dirs: [...dirs] };
|
|
6272
6542
|
}
|
|
6273
6543
|
function genuiSandboxKit(options = {}) {
|
|
6274
|
-
const legacy = Object.keys(LEGACY_OPTIONS).filter(
|
|
6275
|
-
(key) => options[key] !== void 0
|
|
6276
|
-
);
|
|
6277
|
-
if (legacy.length > 0) {
|
|
6278
|
-
throw new CodegenError(
|
|
6279
|
-
`genuiSandboxKit(): ${legacy.map((key) => `\`${key}\``).join(", ")} ${legacy.length > 1 ? "were" : "was"} removed \u2014 ${legacy.map((key) => LEGACY_OPTIONS[key]).join("; ")}. The options are now the agent's Vite plugin's: components, styles, wrapper, stylesDocs.`
|
|
6280
|
-
);
|
|
6281
|
-
}
|
|
6282
6544
|
const output = options.output ?? DEFAULT_SANDBOX_KIT_OUTPUT;
|
|
6283
6545
|
const source = {
|
|
6284
6546
|
...options.components !== void 0 ? { components: options.components } : {},
|
|
@@ -6322,7 +6584,7 @@ function genuiSandboxKit(options = {}) {
|
|
|
6322
6584
|
}
|
|
6323
6585
|
if (options.stylesDocs !== void 0 && !options.stylesDocs.includes("\n")) {
|
|
6324
6586
|
const guide = (0, import_node_path19.isAbsolute)(options.stylesDocs) ? options.stylesDocs : (0, import_node_path19.resolve)(root, options.stylesDocs);
|
|
6325
|
-
if ((0,
|
|
6587
|
+
if ((0, import_node_fs4.existsSync)(guide)) ctx.trackInput(guide);
|
|
6326
6588
|
}
|
|
6327
6589
|
ctx.trackInput((0, import_node_path19.isAbsolute)(output) ? output : (0, import_node_path19.resolve)(root, output));
|
|
6328
6590
|
await generate2({
|
|
@@ -6340,7 +6602,7 @@ function genuiSandboxKit(options = {}) {
|
|
|
6340
6602
|
}
|
|
6341
6603
|
|
|
6342
6604
|
// src/index.ts
|
|
6343
|
-
var VERSION = "0.
|
|
6605
|
+
var VERSION = "0.30.0";
|
|
6344
6606
|
// Annotate the CommonJS export names for ESM import in node:
|
|
6345
6607
|
0 && (module.exports = {
|
|
6346
6608
|
CodegenError,
|