@dudousxd/nestjs-codegen 0.29.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 +8 -0
- 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 +690 -414
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +848 -567
- 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 +1 -1
- package/skills/codegen-setup/SKILL.md +5 -1
package/dist/index.js
CHANGED
|
@@ -252,7 +252,7 @@ async function discoverPages(opts) {
|
|
|
252
252
|
const rel = relative2(opts.cwd, file);
|
|
253
253
|
const nameRel = relative2(pagesBase, file).split(sep2).join("/");
|
|
254
254
|
const name = `${prefix}${computeName(nameRel, opts.componentNameStrategy)}`;
|
|
255
|
-
const source = await readFile(file, "utf8");
|
|
255
|
+
const source = await (opts.read ? opts.read(file) : readFile(file, "utf8"));
|
|
256
256
|
const propsSource = extractPropsSource(source, opts.propsExport);
|
|
257
257
|
out.push({ name, absolutePath: file, relativePath: rel, propsSource, scope });
|
|
258
258
|
}
|
|
@@ -260,10 +260,14 @@ async function discoverPages(opts) {
|
|
|
260
260
|
assertUniqueNames(out);
|
|
261
261
|
return out;
|
|
262
262
|
}
|
|
263
|
-
async function discoverPageScopes(config) {
|
|
263
|
+
async function discoverPageScopes(config, read) {
|
|
264
264
|
const pages = config.pages;
|
|
265
265
|
if (!pages) return [];
|
|
266
|
-
const common = {
|
|
266
|
+
const common = {
|
|
267
|
+
cwd: config.codegen.cwd,
|
|
268
|
+
propsExport: pages.propsExport,
|
|
269
|
+
...read ? { read } : {}
|
|
270
|
+
};
|
|
267
271
|
const out = await discoverPages({
|
|
268
272
|
...common,
|
|
269
273
|
glob: pages.glob,
|
|
@@ -334,305 +338,69 @@ function extractPropsSource(source, exportName) {
|
|
|
334
338
|
}
|
|
335
339
|
|
|
336
340
|
// src/discovery/shared-props.ts
|
|
337
|
-
import {
|
|
338
|
-
import {
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
341
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
342
|
+
import { join as join4 } from "path";
|
|
343
|
+
import { Node as Node11, Project as Project4, SyntaxKind as SyntaxKind4 } from "ts-morph";
|
|
344
|
+
|
|
345
|
+
// src/discovery/contracts-fast.ts
|
|
346
|
+
import { existsSync } from "fs";
|
|
347
|
+
import { dirname as dirname2, join as join3, resolve as resolve3 } from "path";
|
|
348
|
+
import fg2 from "fast-glob";
|
|
349
|
+
import {
|
|
350
|
+
FileSystemRefreshResult as FileSystemRefreshResult3,
|
|
351
|
+
Node as Node10,
|
|
352
|
+
Project as Project3,
|
|
353
|
+
ts as ts4
|
|
354
|
+
} from "ts-morph";
|
|
355
|
+
|
|
356
|
+
// src/discovery/disk-fingerprints.ts
|
|
357
|
+
import { readFileSync, statSync } from "fs";
|
|
358
|
+
var DiskFingerprints = class {
|
|
359
|
+
stats = /* @__PURE__ */ new Map();
|
|
360
|
+
/** The paths whose disk content differs from `text`, or that no longer exist. */
|
|
361
|
+
changed(files) {
|
|
362
|
+
const changed = [];
|
|
363
|
+
for (const { path, text } of files) {
|
|
364
|
+
let key;
|
|
343
365
|
try {
|
|
344
|
-
|
|
366
|
+
const stat2 = statSync(path);
|
|
367
|
+
key = `${stat2.mtimeMs}:${stat2.size}`;
|
|
345
368
|
} catch {
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
const forRootCall = findForRootCall(sourceFile);
|
|
350
|
-
if (!forRootCall) return null;
|
|
351
|
-
const initializer = findShareInitializer(forRootCall);
|
|
352
|
-
if (!initializer) return null;
|
|
353
|
-
return extractShareType(initializer, sourceFile, project);
|
|
354
|
-
} catch {
|
|
355
|
-
return null;
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
function discoverSharedPropsFromConfig(config) {
|
|
359
|
-
if (!config.app?.moduleEntry) return null;
|
|
360
|
-
try {
|
|
361
|
-
const tsconfigPath = config.app.tsconfig ?? join3(config.codegen.cwd, "tsconfig.json");
|
|
362
|
-
let project;
|
|
363
|
-
try {
|
|
364
|
-
project = new Project({
|
|
365
|
-
tsConfigFilePath: tsconfigPath,
|
|
366
|
-
skipAddingFilesFromTsConfig: true,
|
|
367
|
-
skipLoadingLibFiles: true,
|
|
368
|
-
skipFileDependencyResolution: true
|
|
369
|
-
});
|
|
370
|
-
} catch {
|
|
371
|
-
project = new Project({
|
|
372
|
-
skipAddingFilesFromTsConfig: true,
|
|
373
|
-
skipLoadingLibFiles: true,
|
|
374
|
-
skipFileDependencyResolution: true,
|
|
375
|
-
compilerOptions: { allowJs: true, strict: false }
|
|
376
|
-
});
|
|
377
|
-
}
|
|
378
|
-
return discoverSharedProps(project, config.app.moduleEntry);
|
|
379
|
-
} catch {
|
|
380
|
-
return null;
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
function findForRootCall(sourceFile) {
|
|
384
|
-
const callExpressions = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression);
|
|
385
|
-
for (const call of callExpressions) {
|
|
386
|
-
const expr = call.getExpression();
|
|
387
|
-
if (!Node.isPropertyAccessExpression(expr)) continue;
|
|
388
|
-
const methodName = expr.getName();
|
|
389
|
-
const objectExpr = expr.getExpression();
|
|
390
|
-
if (methodName === "forRoot" && Node.isIdentifier(objectExpr)) {
|
|
391
|
-
const name = objectExpr.getText();
|
|
392
|
-
if (name === "InertiaModule") {
|
|
393
|
-
return call;
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
return null;
|
|
398
|
-
}
|
|
399
|
-
function findShareInitializer(forRootCall) {
|
|
400
|
-
if (!Node.isCallExpression(forRootCall)) return null;
|
|
401
|
-
const args = forRootCall.getArguments();
|
|
402
|
-
const firstArg2 = args[0];
|
|
403
|
-
if (!firstArg2 || !Node.isObjectLiteralExpression(firstArg2)) return null;
|
|
404
|
-
for (const prop of firstArg2.getProperties()) {
|
|
405
|
-
if (Node.isPropertyAssignment(prop) && prop.getName() === "share") {
|
|
406
|
-
return prop.getInitializer() ?? null;
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
return null;
|
|
410
|
-
}
|
|
411
|
-
function extractShareType(node, sourceFile, project) {
|
|
412
|
-
if (Node.isIdentifier(node)) {
|
|
413
|
-
const ref = resolveIdentifierToImportRef(node, sourceFile, project);
|
|
414
|
-
if (ref) {
|
|
415
|
-
return {
|
|
416
|
-
typeString: `Awaited<ReturnType<typeof import('${ref.importPath}').${ref.exportName}>>`,
|
|
417
|
-
properties: null,
|
|
418
|
-
isImportRef: true
|
|
419
|
-
};
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
if (Node.isArrowFunction(node)) {
|
|
423
|
-
const result = extractFromFunctionLike(node, sourceFile);
|
|
424
|
-
return result ? { ...result, isImportRef: false } : null;
|
|
425
|
-
}
|
|
426
|
-
if (Node.isFunctionExpression(node)) {
|
|
427
|
-
const result = extractFromFunctionLike(node, sourceFile);
|
|
428
|
-
return result ? { ...result, isImportRef: false } : null;
|
|
429
|
-
}
|
|
430
|
-
if (Node.isObjectLiteralExpression(node)) {
|
|
431
|
-
const result = extractFromObjectLiteral(node);
|
|
432
|
-
return result ? { ...result, isImportRef: false } : null;
|
|
433
|
-
}
|
|
434
|
-
return null;
|
|
435
|
-
}
|
|
436
|
-
function resolveIdentifierToImportRef(id, sourceFile, project) {
|
|
437
|
-
if (!Node.isIdentifier(id)) return null;
|
|
438
|
-
const name = id.getText();
|
|
439
|
-
const localFunc = sourceFile.getFunction(name);
|
|
440
|
-
if (localFunc?.isExported()) {
|
|
441
|
-
const filePath = sourceFile.getFilePath().replace(/\.ts$/, "");
|
|
442
|
-
return { importPath: filePath, exportName: name };
|
|
443
|
-
}
|
|
444
|
-
const localVar = sourceFile.getVariableDeclaration(name);
|
|
445
|
-
if (localVar?.isExported()) {
|
|
446
|
-
const filePath = sourceFile.getFilePath().replace(/\.ts$/, "");
|
|
447
|
-
return { importPath: filePath, exportName: name };
|
|
448
|
-
}
|
|
449
|
-
for (const imp of sourceFile.getImportDeclarations()) {
|
|
450
|
-
for (const named of imp.getNamedImports()) {
|
|
451
|
-
const importedName = named.getAliasNode()?.getText() ?? named.getName();
|
|
452
|
-
if (importedName !== name) continue;
|
|
453
|
-
const resolvedSource = imp.getModuleSpecifierSourceFile();
|
|
454
|
-
if (!resolvedSource) continue;
|
|
455
|
-
const originalName = named.getName();
|
|
456
|
-
const fn = resolvedSource.getFunction(originalName);
|
|
457
|
-
if (fn?.isExported()) {
|
|
458
|
-
const filePath = resolvedSource.getFilePath().replace(/\.ts$/, "");
|
|
459
|
-
return { importPath: filePath, exportName: originalName };
|
|
460
|
-
}
|
|
461
|
-
const v = resolvedSource.getVariableDeclaration(originalName);
|
|
462
|
-
if (v?.isExported()) {
|
|
463
|
-
const filePath = resolvedSource.getFilePath().replace(/\.ts$/, "");
|
|
464
|
-
return { importPath: filePath, exportName: originalName };
|
|
465
|
-
}
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
return null;
|
|
469
|
-
}
|
|
470
|
-
function extractFromFunctionLike(node, _sourceFile) {
|
|
471
|
-
const returnTypeNode = Node.isArrowFunction(node) || Node.isFunctionExpression(node) ? node.getReturnTypeNode() : null;
|
|
472
|
-
if (returnTypeNode) {
|
|
473
|
-
return extractFromReturnTypeAnnotation(returnTypeNode);
|
|
474
|
-
}
|
|
475
|
-
if (Node.isArrowFunction(node)) {
|
|
476
|
-
const body = node.getBody();
|
|
477
|
-
if (Node.isParenthesizedExpression(body)) {
|
|
478
|
-
const inner = body.getExpression();
|
|
479
|
-
if (Node.isObjectLiteralExpression(inner)) {
|
|
480
|
-
return extractFromObjectLiteral(inner);
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
if (Node.isObjectLiteralExpression(body)) {
|
|
484
|
-
return extractFromObjectLiteral(body);
|
|
485
|
-
}
|
|
486
|
-
if (Node.isBlock(body)) {
|
|
487
|
-
return extractFromBlockReturn(body);
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
if (Node.isFunctionExpression(node)) {
|
|
491
|
-
const body = node.getBody();
|
|
492
|
-
if (Node.isBlock(body)) {
|
|
493
|
-
return extractFromBlockReturn(body);
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
return null;
|
|
497
|
-
}
|
|
498
|
-
function extractFromReturnTypeAnnotation(typeNode) {
|
|
499
|
-
if (Node.isTypeReference(typeNode)) {
|
|
500
|
-
const typeName = typeNode.getTypeName();
|
|
501
|
-
if (Node.isIdentifier(typeName) && typeName.getText() === "Promise") {
|
|
502
|
-
const typeArgs = typeNode.getTypeArguments();
|
|
503
|
-
const firstArg2 = typeArgs[0];
|
|
504
|
-
if (firstArg2) {
|
|
505
|
-
return extractFromReturnTypeAnnotation(firstArg2);
|
|
369
|
+
this.stats.delete(path);
|
|
370
|
+
changed.push(path);
|
|
371
|
+
continue;
|
|
506
372
|
}
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
if (Node.isPropertySignature(member)) {
|
|
514
|
-
const name = member.getName();
|
|
515
|
-
const memberTypeNode = member.getTypeNode();
|
|
516
|
-
const type = memberTypeNode ? memberTypeNode.getText() : "unknown";
|
|
517
|
-
properties.push({ name, type });
|
|
373
|
+
if (this.stats.get(path) === key) continue;
|
|
374
|
+
let disk;
|
|
375
|
+
try {
|
|
376
|
+
disk = readFileSync(path, "utf-8");
|
|
377
|
+
} catch {
|
|
378
|
+
disk = void 0;
|
|
518
379
|
}
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
return null;
|
|
525
|
-
}
|
|
526
|
-
function extractFromBlockReturn(block) {
|
|
527
|
-
if (!Node.isBlock(block)) return null;
|
|
528
|
-
const statements = block.getStatements();
|
|
529
|
-
for (let i = statements.length - 1; i >= 0; i--) {
|
|
530
|
-
const stmt = statements[i];
|
|
531
|
-
if (!Node.isReturnStatement(stmt)) continue;
|
|
532
|
-
const expr = stmt.getExpression();
|
|
533
|
-
if (!expr) continue;
|
|
534
|
-
if (Node.isObjectLiteralExpression(expr)) {
|
|
535
|
-
return extractFromObjectLiteral(expr);
|
|
536
|
-
}
|
|
537
|
-
if (Node.isParenthesizedExpression(expr)) {
|
|
538
|
-
const inner = expr.getExpression();
|
|
539
|
-
if (Node.isObjectLiteralExpression(inner)) {
|
|
540
|
-
return extractFromObjectLiteral(inner);
|
|
380
|
+
if (disk === text) {
|
|
381
|
+
this.stats.set(path, key);
|
|
382
|
+
} else {
|
|
383
|
+
this.stats.delete(path);
|
|
384
|
+
changed.push(path);
|
|
541
385
|
}
|
|
542
386
|
}
|
|
543
|
-
|
|
387
|
+
return changed;
|
|
544
388
|
}
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
if (!Node.isObjectLiteralExpression(objLiteral)) return null;
|
|
549
|
-
const properties = [];
|
|
550
|
-
for (const prop of objLiteral.getProperties()) {
|
|
551
|
-
if (!Node.isPropertyAssignment(prop)) continue;
|
|
552
|
-
const name = prop.getName();
|
|
553
|
-
const initializer = prop.getInitializer();
|
|
554
|
-
if (!initializer) continue;
|
|
555
|
-
const type = inferExpressionType(initializer);
|
|
556
|
-
properties.push({ name, type });
|
|
557
|
-
}
|
|
558
|
-
if (properties.length === 0) return null;
|
|
559
|
-
const typeString = `{ ${properties.map((p) => `${p.name}: ${p.type}`).join("; ")} }`;
|
|
560
|
-
return { typeString, properties, isImportRef: false };
|
|
561
|
-
}
|
|
562
|
-
function inferExpressionType(node) {
|
|
563
|
-
if (Node.isStringLiteral(node)) return "string";
|
|
564
|
-
if (Node.isTemplateExpression(node) || Node.isNoSubstitutionTemplateLiteral(node))
|
|
565
|
-
return "string";
|
|
566
|
-
if (Node.isNumericLiteral(node)) return "number";
|
|
567
|
-
if (node.getKind() === SyntaxKind.TrueKeyword || node.getKind() === SyntaxKind.FalseKeyword) {
|
|
568
|
-
return "boolean";
|
|
569
|
-
}
|
|
570
|
-
if (node.getKind() === SyntaxKind.NullKeyword) return "null";
|
|
571
|
-
if (Node.isIdentifier(node) && node.getText() === "undefined") return "undefined";
|
|
572
|
-
if (Node.isObjectLiteralExpression(node)) {
|
|
573
|
-
const props = node.getProperties();
|
|
574
|
-
if (props.length === 0) return "Record<string, unknown>";
|
|
575
|
-
const entries = [];
|
|
576
|
-
for (const prop of props) {
|
|
577
|
-
if (!Node.isPropertyAssignment(prop)) continue;
|
|
578
|
-
const key = prop.getName();
|
|
579
|
-
const init = prop.getInitializer();
|
|
580
|
-
if (!init) continue;
|
|
581
|
-
entries.push(`${key}: ${inferExpressionType(init)}`);
|
|
582
|
-
}
|
|
583
|
-
if (entries.length === 0) return "Record<string, unknown>";
|
|
584
|
-
return `{ ${entries.join("; ")} }`;
|
|
585
|
-
}
|
|
586
|
-
if (Node.isArrayLiteralExpression(node)) {
|
|
587
|
-
const elements = node.getElements();
|
|
588
|
-
if (elements.length === 0) return "Array<unknown>";
|
|
589
|
-
const first = elements[0];
|
|
590
|
-
if (first) return `Array<${inferExpressionType(first)}>`;
|
|
591
|
-
return "Array<unknown>";
|
|
592
|
-
}
|
|
593
|
-
if (Node.isConditionalExpression(node)) {
|
|
594
|
-
const whenTrue = inferExpressionType(node.getWhenTrue());
|
|
595
|
-
const whenFalse = inferExpressionType(node.getWhenFalse());
|
|
596
|
-
if (whenTrue === whenFalse) return whenTrue;
|
|
597
|
-
return `${whenTrue} | ${whenFalse}`;
|
|
598
|
-
}
|
|
599
|
-
if (Node.isParenthesizedExpression(node)) {
|
|
600
|
-
return inferExpressionType(node.getExpression());
|
|
601
|
-
}
|
|
602
|
-
if (Node.isAsExpression(node)) {
|
|
603
|
-
const typeNode = node.getTypeNode();
|
|
604
|
-
if (typeNode) return typeNode.getText();
|
|
389
|
+
/** Forget `path`, so its next check compares content again. */
|
|
390
|
+
forget(path) {
|
|
391
|
+
this.stats.delete(path);
|
|
605
392
|
}
|
|
606
|
-
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
// src/emit/emit-api.ts
|
|
610
|
-
import { mkdir, writeFile } from "fs/promises";
|
|
611
|
-
import { isAbsolute as isAbsolute2, join as join5, relative as relative4 } from "path";
|
|
612
|
-
|
|
613
|
-
// src/extension/registry.ts
|
|
614
|
-
import { relative as relative3, resolve as resolve4 } from "path";
|
|
615
|
-
import { Project as Project5 } from "ts-morph";
|
|
616
|
-
|
|
617
|
-
// src/discovery/contracts-fast.ts
|
|
618
|
-
import { existsSync } from "fs";
|
|
619
|
-
import { dirname as dirname2, join as join4, resolve as resolve3 } from "path";
|
|
620
|
-
import fg2 from "fast-glob";
|
|
621
|
-
import {
|
|
622
|
-
Node as Node11,
|
|
623
|
-
Project as Project4,
|
|
624
|
-
ts as ts3
|
|
625
|
-
} from "ts-morph";
|
|
393
|
+
};
|
|
626
394
|
|
|
627
395
|
// src/discovery/dto-type-resolver.ts
|
|
628
396
|
import {
|
|
629
|
-
Node as
|
|
630
|
-
SyntaxKind as
|
|
397
|
+
Node as Node9,
|
|
398
|
+
SyntaxKind as SyntaxKind3
|
|
631
399
|
} from "ts-morph";
|
|
632
400
|
|
|
633
401
|
// src/discovery/dto-to-ir.ts
|
|
634
402
|
import {
|
|
635
|
-
Node as
|
|
403
|
+
Node as Node2
|
|
636
404
|
} from "ts-morph";
|
|
637
405
|
|
|
638
406
|
// src/util/debug-log.ts
|
|
@@ -647,7 +415,7 @@ function debugWarn(message) {
|
|
|
647
415
|
// src/discovery/type-ref-resolution.ts
|
|
648
416
|
import { dirname, resolve as resolve2 } from "path";
|
|
649
417
|
import {
|
|
650
|
-
Node
|
|
418
|
+
Node
|
|
651
419
|
} from "ts-morph";
|
|
652
420
|
var _EMPTY_CTX = { projectRoot: "", tsconfigPaths: null };
|
|
653
421
|
var _ctxByProject = /* @__PURE__ */ new WeakMap();
|
|
@@ -913,13 +681,13 @@ function resolveTypeRef(nodeOrName, sourceFile, project, opts) {
|
|
|
913
681
|
name = nodeOrName;
|
|
914
682
|
} else {
|
|
915
683
|
const typeNode = nodeOrName;
|
|
916
|
-
if (opts.unwrapContainers &&
|
|
684
|
+
if (opts.unwrapContainers && Node.isArrayTypeNode(typeNode)) {
|
|
917
685
|
const inner = resolveTypeRef(typeNode.getElementTypeNode(), sourceFile, project, opts);
|
|
918
686
|
return inner ? { ...inner, isArray: true } : null;
|
|
919
687
|
}
|
|
920
|
-
if (!
|
|
688
|
+
if (!Node.isTypeReference(typeNode)) return null;
|
|
921
689
|
const typeName = typeNode.getTypeName();
|
|
922
|
-
const refName =
|
|
690
|
+
const refName = Node.isIdentifier(typeName) ? typeName.getText() : null;
|
|
923
691
|
if (!refName) return null;
|
|
924
692
|
if (opts.unwrapContainers && refName === "Promise") {
|
|
925
693
|
const first = typeNode.getTypeArguments()[0];
|
|
@@ -1053,7 +821,7 @@ function buildProperty(prop, classFile, ctx) {
|
|
|
1053
821
|
const dec = (n) => decorators.get(n);
|
|
1054
822
|
const typeNode = prop.getTypeNode();
|
|
1055
823
|
const typeText = typeNode?.getText() ?? "unknown";
|
|
1056
|
-
const isArrayType = !!typeNode &&
|
|
824
|
+
const isArrayType = !!typeNode && Node2.isArrayTypeNode(typeNode);
|
|
1057
825
|
const asField = (child) => applyPresence(
|
|
1058
826
|
has("IsArray") || isArrayType ? { kind: "array", element: child } : child,
|
|
1059
827
|
decorators
|
|
@@ -1267,22 +1035,22 @@ function firstArgText(decorator) {
|
|
|
1267
1035
|
}
|
|
1268
1036
|
function numericArg(decorator) {
|
|
1269
1037
|
const arg = firstArg(decorator);
|
|
1270
|
-
if (arg &&
|
|
1038
|
+
if (arg && Node2.isNumericLiteral(arg)) return arg.getText();
|
|
1271
1039
|
return null;
|
|
1272
1040
|
}
|
|
1273
1041
|
function numericArgs(decorator) {
|
|
1274
1042
|
const args = decorator?.getArguments() ?? [];
|
|
1275
|
-
const num = (n) => n &&
|
|
1043
|
+
const num = (n) => n && Node2.isNumericLiteral(n) ? n.getText() : null;
|
|
1276
1044
|
return [num(args[0]), num(args[1])];
|
|
1277
1045
|
}
|
|
1278
1046
|
function messageRaw(decorator) {
|
|
1279
1047
|
const args = decorator?.getArguments() ?? [];
|
|
1280
1048
|
for (const arg of args) {
|
|
1281
|
-
if (
|
|
1049
|
+
if (Node2.isObjectLiteralExpression(arg)) {
|
|
1282
1050
|
for (const prop of arg.getProperties()) {
|
|
1283
|
-
if (
|
|
1051
|
+
if (Node2.isPropertyAssignment(prop) && prop.getName() === "message") {
|
|
1284
1052
|
const init = prop.getInitializer();
|
|
1285
|
-
if (init &&
|
|
1053
|
+
if (init && Node2.isStringLiteral(init)) return init.getText();
|
|
1286
1054
|
}
|
|
1287
1055
|
}
|
|
1288
1056
|
}
|
|
@@ -1291,30 +1059,30 @@ function messageRaw(decorator) {
|
|
|
1291
1059
|
}
|
|
1292
1060
|
function resolveDiscriminator(decorator) {
|
|
1293
1061
|
const optsArg = decorator?.getArguments()[1];
|
|
1294
|
-
if (!optsArg || !
|
|
1062
|
+
if (!optsArg || !Node2.isObjectLiteralExpression(optsArg)) return null;
|
|
1295
1063
|
let discProp;
|
|
1296
1064
|
for (const prop of optsArg.getProperties()) {
|
|
1297
|
-
if (
|
|
1065
|
+
if (Node2.isPropertyAssignment(prop) && prop.getName() === "discriminator") {
|
|
1298
1066
|
discProp = prop.getInitializer();
|
|
1299
1067
|
}
|
|
1300
1068
|
}
|
|
1301
|
-
if (!discProp || !
|
|
1069
|
+
if (!discProp || !Node2.isObjectLiteralExpression(discProp)) return null;
|
|
1302
1070
|
let property = null;
|
|
1303
1071
|
const subTypes = [];
|
|
1304
1072
|
for (const prop of discProp.getProperties()) {
|
|
1305
|
-
if (!
|
|
1073
|
+
if (!Node2.isPropertyAssignment(prop)) continue;
|
|
1306
1074
|
const name = prop.getName();
|
|
1307
1075
|
const init = prop.getInitializer();
|
|
1308
1076
|
if (!init) continue;
|
|
1309
|
-
if (name === "property" &&
|
|
1077
|
+
if (name === "property" && Node2.isStringLiteral(init)) {
|
|
1310
1078
|
property = init.getLiteralValue();
|
|
1311
|
-
} else if (name === "subTypes" &&
|
|
1079
|
+
} else if (name === "subTypes" && Node2.isArrayLiteralExpression(init)) {
|
|
1312
1080
|
for (const el of init.getElements()) {
|
|
1313
|
-
if (!
|
|
1081
|
+
if (!Node2.isObjectLiteralExpression(el)) continue;
|
|
1314
1082
|
for (const p of el.getProperties()) {
|
|
1315
|
-
if (!
|
|
1083
|
+
if (!Node2.isPropertyAssignment(p) || p.getName() !== "name") continue;
|
|
1316
1084
|
const nameInit = p.getInitializer();
|
|
1317
|
-
if (nameInit &&
|
|
1085
|
+
if (nameInit && Node2.isIdentifier(nameInit)) subTypes.push(nameInit.getText());
|
|
1318
1086
|
}
|
|
1319
1087
|
}
|
|
1320
1088
|
}
|
|
@@ -1325,9 +1093,9 @@ function resolveDiscriminator(decorator) {
|
|
|
1325
1093
|
function resolveTypeFactoryName(decorator) {
|
|
1326
1094
|
const arg = firstArg(decorator);
|
|
1327
1095
|
if (!arg) return null;
|
|
1328
|
-
if (
|
|
1096
|
+
if (Node2.isArrowFunction(arg)) {
|
|
1329
1097
|
const body = arg.getBody();
|
|
1330
|
-
if (
|
|
1098
|
+
if (Node2.isIdentifier(body)) return body.getText();
|
|
1331
1099
|
}
|
|
1332
1100
|
return null;
|
|
1333
1101
|
}
|
|
@@ -1336,12 +1104,12 @@ function singularClassName(typeText) {
|
|
|
1336
1104
|
return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(inner) ? inner : null;
|
|
1337
1105
|
}
|
|
1338
1106
|
function genericTypeArgNames(typeNode) {
|
|
1339
|
-
if (!typeNode || !
|
|
1107
|
+
if (!typeNode || !Node2.isTypeReference(typeNode)) return [];
|
|
1340
1108
|
const names = [];
|
|
1341
1109
|
for (const arg of typeNode.getTypeArguments()) {
|
|
1342
|
-
if (!
|
|
1110
|
+
if (!Node2.isTypeReference(arg)) return [];
|
|
1343
1111
|
const tn = arg.getTypeName();
|
|
1344
|
-
if (!
|
|
1112
|
+
if (!Node2.isIdentifier(tn)) return [];
|
|
1345
1113
|
names.push(tn.getText());
|
|
1346
1114
|
}
|
|
1347
1115
|
return names;
|
|
@@ -1349,7 +1117,7 @@ function genericTypeArgNames(typeNode) {
|
|
|
1349
1117
|
function enumSchemaFromDecorator(decorator, classFile, ctx) {
|
|
1350
1118
|
const arg = firstArg(decorator);
|
|
1351
1119
|
if (!arg) return null;
|
|
1352
|
-
if (
|
|
1120
|
+
if (Node2.isIdentifier(arg)) {
|
|
1353
1121
|
const name = arg.getText();
|
|
1354
1122
|
const resolved = findType(name, classFile, ctx.project);
|
|
1355
1123
|
if (resolved && resolved.kind === "enum") {
|
|
@@ -1363,12 +1131,12 @@ function enumSchemaFromDecorator(decorator, classFile, ctx) {
|
|
|
1363
1131
|
}
|
|
1364
1132
|
return { kind: "unknown", note: `@IsEnum(${name}): enum not resolvable to literals` };
|
|
1365
1133
|
}
|
|
1366
|
-
if (
|
|
1134
|
+
if (Node2.isObjectLiteralExpression(arg)) {
|
|
1367
1135
|
const values = [];
|
|
1368
1136
|
for (const p of arg.getProperties()) {
|
|
1369
|
-
if (!
|
|
1137
|
+
if (!Node2.isPropertyAssignment(p)) continue;
|
|
1370
1138
|
const init = p.getInitializer();
|
|
1371
|
-
if (init &&
|
|
1139
|
+
if (init && Node2.isStringLiteral(init)) values.push(init.getText());
|
|
1372
1140
|
}
|
|
1373
1141
|
if (values.length > 0) return { kind: "enum", literals: values };
|
|
1374
1142
|
}
|
|
@@ -1376,9 +1144,9 @@ function enumSchemaFromDecorator(decorator, classFile, ctx) {
|
|
|
1376
1144
|
}
|
|
1377
1145
|
function inSchemaFromDecorator(decorator) {
|
|
1378
1146
|
const arg = firstArg(decorator);
|
|
1379
|
-
if (arg &&
|
|
1147
|
+
if (arg && Node2.isArrayLiteralExpression(arg)) {
|
|
1380
1148
|
const elements = arg.getElements();
|
|
1381
|
-
const allStrings = elements.every((e) =>
|
|
1149
|
+
const allStrings = elements.every((e) => Node2.isStringLiteral(e));
|
|
1382
1150
|
if (allStrings && elements.length > 0) {
|
|
1383
1151
|
return { kind: "enum", literals: elements.map((e) => e.getText()) };
|
|
1384
1152
|
}
|
|
@@ -1394,13 +1162,13 @@ function inSchemaFromDecorator(decorator) {
|
|
|
1394
1162
|
|
|
1395
1163
|
// src/discovery/filter-for.ts
|
|
1396
1164
|
import {
|
|
1397
|
-
Node as
|
|
1165
|
+
Node as Node5
|
|
1398
1166
|
} from "ts-morph";
|
|
1399
1167
|
|
|
1400
1168
|
// src/discovery/filter-field-types.ts
|
|
1401
1169
|
import {
|
|
1402
|
-
Node as
|
|
1403
|
-
SyntaxKind
|
|
1170
|
+
Node as Node3,
|
|
1171
|
+
SyntaxKind
|
|
1404
1172
|
} from "ts-morph";
|
|
1405
1173
|
|
|
1406
1174
|
// src/discovery/enum-resolution.ts
|
|
@@ -1454,28 +1222,28 @@ function markNullable(r, nullable) {
|
|
|
1454
1222
|
}
|
|
1455
1223
|
var TRANSPARENT_TYPE_BRANDS = /* @__PURE__ */ new Set(["Opt", "Hidden"]);
|
|
1456
1224
|
function classifyTypeNode(typeNode, sourceFile, project, opts) {
|
|
1457
|
-
if (
|
|
1225
|
+
if (Node3.isUnionTypeNode(typeNode)) {
|
|
1458
1226
|
let nullable = false;
|
|
1459
1227
|
const stringLits = [];
|
|
1460
1228
|
const numberLits = [];
|
|
1461
1229
|
const others = [];
|
|
1462
1230
|
for (const member of typeNode.getTypeNodes()) {
|
|
1463
1231
|
const kind = member.getKind();
|
|
1464
|
-
if (kind ===
|
|
1232
|
+
if (kind === SyntaxKind.NullKeyword || kind === SyntaxKind.UndefinedKeyword) {
|
|
1465
1233
|
nullable = true;
|
|
1466
1234
|
continue;
|
|
1467
1235
|
}
|
|
1468
|
-
if (
|
|
1236
|
+
if (Node3.isLiteralTypeNode(member)) {
|
|
1469
1237
|
const lit = member.getLiteral();
|
|
1470
|
-
if (
|
|
1238
|
+
if (Node3.isStringLiteral(lit)) {
|
|
1471
1239
|
stringLits.push(lit.getLiteralValue());
|
|
1472
1240
|
continue;
|
|
1473
1241
|
}
|
|
1474
|
-
if (
|
|
1242
|
+
if (Node3.isNumericLiteral(lit)) {
|
|
1475
1243
|
numberLits.push(lit.getText());
|
|
1476
1244
|
continue;
|
|
1477
1245
|
}
|
|
1478
|
-
if (lit.getKind() ===
|
|
1246
|
+
if (lit.getKind() === SyntaxKind.NullKeyword) {
|
|
1479
1247
|
nullable = true;
|
|
1480
1248
|
continue;
|
|
1481
1249
|
}
|
|
@@ -1495,19 +1263,19 @@ function classifyTypeNode(typeNode, sourceFile, project, opts) {
|
|
|
1495
1263
|
return markNullable({ kind: "unknown" }, nullable);
|
|
1496
1264
|
}
|
|
1497
1265
|
switch (typeNode.getKind()) {
|
|
1498
|
-
case
|
|
1266
|
+
case SyntaxKind.StringKeyword:
|
|
1499
1267
|
return { kind: "string" };
|
|
1500
|
-
case
|
|
1268
|
+
case SyntaxKind.NumberKeyword:
|
|
1501
1269
|
return { kind: "number" };
|
|
1502
|
-
case
|
|
1270
|
+
case SyntaxKind.BooleanKeyword:
|
|
1503
1271
|
return { kind: "boolean" };
|
|
1504
|
-
case
|
|
1505
|
-
case
|
|
1272
|
+
case SyntaxKind.AnyKeyword:
|
|
1273
|
+
case SyntaxKind.UnknownKeyword:
|
|
1506
1274
|
return { kind: "unknown" };
|
|
1507
1275
|
default:
|
|
1508
1276
|
break;
|
|
1509
1277
|
}
|
|
1510
|
-
if (
|
|
1278
|
+
if (Node3.isTypeReference(typeNode)) {
|
|
1511
1279
|
const refName = typeNode.getTypeName().getText();
|
|
1512
1280
|
if (refName === "Date") return { kind: "date" };
|
|
1513
1281
|
if (refName === "Record" || refName === "Object") return { kind: "json" };
|
|
@@ -1525,25 +1293,25 @@ function classifyTypeNode(typeNode, sourceFile, project, opts) {
|
|
|
1525
1293
|
if (typeRef) return { kind: "unknown", typeRef };
|
|
1526
1294
|
return { kind: "unknown" };
|
|
1527
1295
|
}
|
|
1528
|
-
if (
|
|
1296
|
+
if (Node3.isTypeLiteral(typeNode)) return { kind: "json" };
|
|
1529
1297
|
return { kind: "unknown" };
|
|
1530
1298
|
}
|
|
1531
1299
|
function enumFromDecoratorArgs(args, sourceFile, project) {
|
|
1532
1300
|
for (const arg of args) {
|
|
1533
|
-
if (
|
|
1301
|
+
if (Node3.isArrowFunction(arg)) {
|
|
1534
1302
|
const body = arg.getBody();
|
|
1535
|
-
if (
|
|
1303
|
+
if (Node3.isIdentifier(body)) {
|
|
1536
1304
|
const en = resolveEnumValues(body.getText(), sourceFile, project);
|
|
1537
1305
|
if (en) return en;
|
|
1538
1306
|
}
|
|
1539
1307
|
}
|
|
1540
|
-
if (
|
|
1308
|
+
if (Node3.isObjectLiteralExpression(arg)) {
|
|
1541
1309
|
const itemsProp = arg.getProperty("items");
|
|
1542
|
-
if (itemsProp &&
|
|
1310
|
+
if (itemsProp && Node3.isPropertyAssignment(itemsProp)) {
|
|
1543
1311
|
const init = itemsProp.getInitializer();
|
|
1544
|
-
if (init &&
|
|
1312
|
+
if (init && Node3.isArrowFunction(init)) {
|
|
1545
1313
|
const body = init.getBody();
|
|
1546
|
-
if (
|
|
1314
|
+
if (Node3.isIdentifier(body)) {
|
|
1547
1315
|
const en = resolveEnumValues(body.getText(), sourceFile, project);
|
|
1548
1316
|
if (en) return en;
|
|
1549
1317
|
}
|
|
@@ -1566,7 +1334,7 @@ function classifyFromColumnDecorator(prop, sourceFile, project) {
|
|
|
1566
1334
|
return { kind: "string" };
|
|
1567
1335
|
}
|
|
1568
1336
|
for (const arg of args) {
|
|
1569
|
-
if (
|
|
1337
|
+
if (Node3.isStringLiteral(arg)) {
|
|
1570
1338
|
const raw = arg.getLiteralValue();
|
|
1571
1339
|
const kind = classifyTypeKeyword(raw);
|
|
1572
1340
|
if (kind) {
|
|
@@ -1574,11 +1342,11 @@ function classifyFromColumnDecorator(prop, sourceFile, project) {
|
|
|
1574
1342
|
return { kind };
|
|
1575
1343
|
}
|
|
1576
1344
|
}
|
|
1577
|
-
if (
|
|
1345
|
+
if (Node3.isObjectLiteralExpression(arg)) {
|
|
1578
1346
|
const enumProp = arg.getProperty("enum");
|
|
1579
|
-
if (enumProp &&
|
|
1347
|
+
if (enumProp && Node3.isPropertyAssignment(enumProp)) {
|
|
1580
1348
|
const init = enumProp.getInitializer();
|
|
1581
|
-
if (init &&
|
|
1349
|
+
if (init && Node3.isIdentifier(init)) {
|
|
1582
1350
|
const en = resolveEnumValues(init.getText(), sourceFile, project);
|
|
1583
1351
|
if (en) {
|
|
1584
1352
|
return en.numeric ? { kind: "number", enumValues: en.values, numericEnum: true } : { kind: "string", enumValues: en.values };
|
|
@@ -1588,15 +1356,15 @@ function classifyFromColumnDecorator(prop, sourceFile, project) {
|
|
|
1588
1356
|
}
|
|
1589
1357
|
for (const key of ["columnType", "type"]) {
|
|
1590
1358
|
const typeProp = arg.getProperty(key);
|
|
1591
|
-
if (!typeProp || !
|
|
1359
|
+
if (!typeProp || !Node3.isPropertyAssignment(typeProp)) continue;
|
|
1592
1360
|
const init = typeProp.getInitializer();
|
|
1593
1361
|
if (!init) continue;
|
|
1594
|
-
if (
|
|
1362
|
+
if (Node3.isStringLiteral(init)) {
|
|
1595
1363
|
const kind = classifyTypeKeyword(init.getLiteralValue());
|
|
1596
1364
|
if (kind) return { kind };
|
|
1597
1365
|
continue;
|
|
1598
1366
|
}
|
|
1599
|
-
if (
|
|
1367
|
+
if (Node3.isIdentifier(init)) {
|
|
1600
1368
|
const kind = classifyTypeKeyword(init.getText());
|
|
1601
1369
|
if (kind) return { kind };
|
|
1602
1370
|
}
|
|
@@ -1638,23 +1406,70 @@ function toFilterFieldType(name, r) {
|
|
|
1638
1406
|
}
|
|
1639
1407
|
|
|
1640
1408
|
// src/discovery/heritage.ts
|
|
1641
|
-
import {
|
|
1409
|
+
import {
|
|
1410
|
+
FileSystemRefreshResult,
|
|
1411
|
+
Node as Node4,
|
|
1412
|
+
Project
|
|
1413
|
+
} from "ts-morph";
|
|
1414
|
+
|
|
1415
|
+
// src/discovery/unresolved-imports.ts
|
|
1416
|
+
import { ts } from "ts-morph";
|
|
1417
|
+
var UnresolvedImports = class {
|
|
1418
|
+
read;
|
|
1419
|
+
/**
|
|
1420
|
+
* The files with an import that failed to resolve in `program` and now resolves
|
|
1421
|
+
* to a TypeScript file the program does not hold.
|
|
1422
|
+
*/
|
|
1423
|
+
nowResolving(program) {
|
|
1424
|
+
if (this.read?.program !== program) {
|
|
1425
|
+
this.read = { program, imports: failedImports(program) };
|
|
1426
|
+
}
|
|
1427
|
+
const options = program.getCompilerOptions();
|
|
1428
|
+
const files = /* @__PURE__ */ new Set();
|
|
1429
|
+
for (const { specifier, from } of this.read.imports) {
|
|
1430
|
+
const file = ts.resolveModuleName(specifier, from, options, ts.sys).resolvedModule?.resolvedFileName;
|
|
1431
|
+
if (file !== void 0 && /\.(m|c)?tsx?$/.test(file) && !program.getSourceFile(file)) {
|
|
1432
|
+
files.add(from);
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
return [...files];
|
|
1436
|
+
}
|
|
1437
|
+
};
|
|
1438
|
+
function failedImports(program) {
|
|
1439
|
+
const checker = program.getTypeChecker();
|
|
1440
|
+
const imports = [];
|
|
1441
|
+
for (const file of program.getSourceFiles()) {
|
|
1442
|
+
if (program.isSourceFileDefaultLibrary(file) || file.isDeclarationFile) continue;
|
|
1443
|
+
if (program.isSourceFileFromExternalLibrary(file)) continue;
|
|
1444
|
+
for (const statement of file.statements) {
|
|
1445
|
+
if (!ts.isImportDeclaration(statement) && !ts.isExportDeclaration(statement)) continue;
|
|
1446
|
+
const specifier = statement.moduleSpecifier;
|
|
1447
|
+
if (!specifier || !ts.isStringLiteral(specifier)) continue;
|
|
1448
|
+
if (!checker.getSymbolAtLocation(specifier)) {
|
|
1449
|
+
imports.push({ specifier: specifier.text, from: file.fileName });
|
|
1450
|
+
}
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1453
|
+
return imports;
|
|
1454
|
+
}
|
|
1455
|
+
|
|
1456
|
+
// src/discovery/heritage.ts
|
|
1642
1457
|
function resolveHeritageCall(node) {
|
|
1643
1458
|
if (!node) return void 0;
|
|
1644
1459
|
const expr = unwrapExpression(node);
|
|
1645
|
-
if (
|
|
1646
|
-
if (!
|
|
1460
|
+
if (Node4.isCallExpression(expr)) return expr;
|
|
1461
|
+
if (!Node4.isIdentifier(expr)) return void 0;
|
|
1647
1462
|
const decl = expr.getDefinitions().map((d) => d.getDeclarationNode()).find(
|
|
1648
|
-
(n) => n !== void 0 &&
|
|
1463
|
+
(n) => n !== void 0 && Node4.isVariableDeclaration(n)
|
|
1649
1464
|
);
|
|
1650
1465
|
const init = decl?.getInitializer();
|
|
1651
1466
|
if (!init) return void 0;
|
|
1652
1467
|
const unwrapped = unwrapExpression(init);
|
|
1653
|
-
return
|
|
1468
|
+
return Node4.isCallExpression(unwrapped) ? unwrapped : void 0;
|
|
1654
1469
|
}
|
|
1655
1470
|
function unwrapExpression(node) {
|
|
1656
1471
|
let current = node;
|
|
1657
|
-
while (
|
|
1472
|
+
while (Node4.isAsExpression(current) || Node4.isSatisfiesExpression(current) || Node4.isParenthesizedExpression(current) || Node4.isTypeAssertion(current)) {
|
|
1658
1473
|
current = current.getExpression();
|
|
1659
1474
|
}
|
|
1660
1475
|
return current;
|
|
@@ -1662,17 +1477,17 @@ function unwrapExpression(node) {
|
|
|
1662
1477
|
function resolveReturnedClass(factoryDecl) {
|
|
1663
1478
|
const body = factoryDecl.getBody();
|
|
1664
1479
|
if (!body) return void 0;
|
|
1665
|
-
const returns = body.getDescendants().filter((n) =>
|
|
1480
|
+
const returns = body.getDescendants().filter((n) => Node4.isReturnStatement(n));
|
|
1666
1481
|
for (const ret of returns) {
|
|
1667
1482
|
const expr = ret.getExpression();
|
|
1668
1483
|
if (!expr) continue;
|
|
1669
1484
|
const inner = unwrapExpression(expr);
|
|
1670
|
-
if (
|
|
1485
|
+
if (Node4.isClassExpression(inner)) {
|
|
1671
1486
|
return inner;
|
|
1672
1487
|
}
|
|
1673
|
-
if (
|
|
1488
|
+
if (Node4.isIdentifier(inner)) {
|
|
1674
1489
|
const name = inner.getText();
|
|
1675
|
-
const decl = body.getDescendants().find((n) =>
|
|
1490
|
+
const decl = body.getDescendants().find((n) => Node4.isClassDeclaration(n) && n.getName() === name);
|
|
1676
1491
|
if (decl) return decl;
|
|
1677
1492
|
}
|
|
1678
1493
|
}
|
|
@@ -1680,10 +1495,10 @@ function resolveReturnedClass(factoryDecl) {
|
|
|
1680
1495
|
}
|
|
1681
1496
|
function factoryCalleeName(call) {
|
|
1682
1497
|
const callee = unwrapExpression(call.getExpression());
|
|
1683
|
-
if (
|
|
1684
|
-
if (
|
|
1498
|
+
if (Node4.isIdentifier(callee)) return callee;
|
|
1499
|
+
if (Node4.isPropertyAccessExpression(callee)) {
|
|
1685
1500
|
const name = callee.getNameNode();
|
|
1686
|
-
return
|
|
1501
|
+
return Node4.isIdentifier(name) ? name : void 0;
|
|
1687
1502
|
}
|
|
1688
1503
|
return void 0;
|
|
1689
1504
|
}
|
|
@@ -1696,19 +1511,19 @@ function resolveFactoryFromName(name, seen) {
|
|
|
1696
1511
|
seen.add(name);
|
|
1697
1512
|
const decls = name.getDefinitions().map((d) => d.getDeclarationNode()).filter((n) => n !== void 0);
|
|
1698
1513
|
for (const decl of decls) {
|
|
1699
|
-
if (
|
|
1700
|
-
if (
|
|
1514
|
+
if (Node4.isFunctionDeclaration(decl) || Node4.isMethodDeclaration(decl)) return decl;
|
|
1515
|
+
if (Node4.isPropertyAssignment(decl)) {
|
|
1701
1516
|
const init = decl.getInitializer();
|
|
1702
1517
|
const inner = init ? unwrapExpression(init) : void 0;
|
|
1703
|
-
if (inner &&
|
|
1518
|
+
if (inner && Node4.isIdentifier(inner)) {
|
|
1704
1519
|
const resolved = resolveFactoryFromName(inner, seen);
|
|
1705
1520
|
if (resolved) return resolved;
|
|
1706
1521
|
}
|
|
1707
1522
|
continue;
|
|
1708
1523
|
}
|
|
1709
|
-
if (
|
|
1524
|
+
if (Node4.isShorthandPropertyAssignment(decl)) {
|
|
1710
1525
|
const nameNode = decl.getNameNode();
|
|
1711
|
-
const resolved =
|
|
1526
|
+
const resolved = Node4.isIdentifier(nameNode) ? resolveFactoryFromName(nameNode, seen) : void 0;
|
|
1712
1527
|
if (resolved) return resolved;
|
|
1713
1528
|
}
|
|
1714
1529
|
}
|
|
@@ -1720,7 +1535,7 @@ function warnUnresolvedFactory(cls, calleeText, reason) {
|
|
|
1720
1535
|
);
|
|
1721
1536
|
}
|
|
1722
1537
|
function resolveFactoryStaticClass(node) {
|
|
1723
|
-
if (!
|
|
1538
|
+
if (!Node4.isPropertyAccessExpression(node)) return void 0;
|
|
1724
1539
|
const call = resolveHeritageCall(node.getExpression());
|
|
1725
1540
|
if (!call) return void 0;
|
|
1726
1541
|
const factoryDecl = resolveFactoryDeclaration(call);
|
|
@@ -1728,13 +1543,13 @@ function resolveFactoryStaticClass(node) {
|
|
|
1728
1543
|
const returnedClass = resolveReturnedClass(factoryDecl);
|
|
1729
1544
|
if (!returnedClass) return void 0;
|
|
1730
1545
|
const staticProp = returnedClass.getStaticProperties().find((p) => p.getName() === node.getName());
|
|
1731
|
-
if (!staticProp || !
|
|
1546
|
+
if (!staticProp || !Node4.isPropertyDeclaration(staticProp)) return void 0;
|
|
1732
1547
|
const init = staticProp.getInitializer();
|
|
1733
1548
|
if (!init) return void 0;
|
|
1734
1549
|
const inner = unwrapExpression(init);
|
|
1735
|
-
if (
|
|
1736
|
-
if (!
|
|
1737
|
-
return inner.getDefinitions().map((d) => d.getDeclarationNode()).find((n) => n !== void 0 &&
|
|
1550
|
+
if (Node4.isClassExpression(inner)) return inner;
|
|
1551
|
+
if (!Node4.isIdentifier(inner)) return void 0;
|
|
1552
|
+
return inner.getDefinitions().map((d) => d.getDeclarationNode()).find((n) => n !== void 0 && Node4.isClassDeclaration(n));
|
|
1738
1553
|
}
|
|
1739
1554
|
function resolveBaseClass(cls) {
|
|
1740
1555
|
const heritage = cls.getExtends()?.getExpression();
|
|
@@ -1745,8 +1560,8 @@ function resolveBaseClass(cls) {
|
|
|
1745
1560
|
return factoryDecl ? resolveReturnedClass(factoryDecl) : void 0;
|
|
1746
1561
|
}
|
|
1747
1562
|
const expr = unwrapExpression(heritage);
|
|
1748
|
-
if (!
|
|
1749
|
-
return expr.getDefinitions().map((d) => d.getDeclarationNode()).find((n) => n !== void 0 &&
|
|
1563
|
+
if (!Node4.isIdentifier(expr)) return void 0;
|
|
1564
|
+
return expr.getDefinitions().map((d) => d.getDeclarationNode()).find((n) => n !== void 0 && Node4.isClassDeclaration(n));
|
|
1750
1565
|
}
|
|
1751
1566
|
function collectMethodsThroughChain(returnedClass) {
|
|
1752
1567
|
const byName = /* @__PURE__ */ new Map();
|
|
@@ -1793,7 +1608,7 @@ function resolveInheritedMethods(cls) {
|
|
|
1793
1608
|
classArgs.push(positional);
|
|
1794
1609
|
continue;
|
|
1795
1610
|
}
|
|
1796
|
-
if (!
|
|
1611
|
+
if (!Node4.isObjectLiteralExpression(arg)) continue;
|
|
1797
1612
|
for (const prop of arg.getProperties()) {
|
|
1798
1613
|
const named = resolvePropertyClassReference(prop);
|
|
1799
1614
|
if (!named) continue;
|
|
@@ -1815,8 +1630,8 @@ function resolveInheritedMethods(cls) {
|
|
|
1815
1630
|
}
|
|
1816
1631
|
function resolveClassReference(node) {
|
|
1817
1632
|
const expr = unwrapExpression(node);
|
|
1818
|
-
if (!
|
|
1819
|
-
const decl = expr.getDefinitions().map((d) => d.getDeclarationNode()).find((n) => n !== void 0 &&
|
|
1633
|
+
if (!Node4.isIdentifier(expr)) return void 0;
|
|
1634
|
+
const decl = expr.getDefinitions().map((d) => d.getDeclarationNode()).find((n) => n !== void 0 && Node4.isClassDeclaration(n));
|
|
1820
1635
|
if (!decl) return void 0;
|
|
1821
1636
|
return {
|
|
1822
1637
|
name: decl.getName() ?? expr.getText(),
|
|
@@ -1824,29 +1639,56 @@ function resolveClassReference(node) {
|
|
|
1824
1639
|
};
|
|
1825
1640
|
}
|
|
1826
1641
|
function resolvePropertyClassReference(prop) {
|
|
1827
|
-
if (
|
|
1642
|
+
if (Node4.isShorthandPropertyAssignment(prop)) {
|
|
1828
1643
|
const ref2 = resolveClassReference(prop.getNameNode());
|
|
1829
1644
|
return ref2 ? { key: prop.getName(), ref: ref2 } : void 0;
|
|
1830
1645
|
}
|
|
1831
|
-
if (!
|
|
1646
|
+
if (!Node4.isPropertyAssignment(prop)) return void 0;
|
|
1832
1647
|
const init = prop.getInitializer();
|
|
1833
1648
|
if (!init) return void 0;
|
|
1834
1649
|
const ref = resolveClassReference(init);
|
|
1835
1650
|
if (!ref) return void 0;
|
|
1836
1651
|
const nameNode = prop.getNameNode();
|
|
1837
|
-
const key =
|
|
1652
|
+
const key = Node4.isStringLiteral(nameNode) ? nameNode.getLiteralValue() : prop.getName();
|
|
1838
1653
|
return { key, ref };
|
|
1839
1654
|
}
|
|
1840
1655
|
var mixinTypeProject;
|
|
1656
|
+
var mixinFiles = new DiskFingerprints();
|
|
1657
|
+
var mixinStale = false;
|
|
1658
|
+
var mixinUnresolved = new UnresolvedImports();
|
|
1841
1659
|
function getMixinTypeProject() {
|
|
1842
|
-
mixinTypeProject
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1660
|
+
if (mixinTypeProject && mixinStale && !refreshMixinTypeProject(mixinTypeProject)) {
|
|
1661
|
+
mixinTypeProject = void 0;
|
|
1662
|
+
}
|
|
1663
|
+
mixinStale = false;
|
|
1664
|
+
if (!mixinTypeProject) {
|
|
1665
|
+
mixinTypeProject = new Project({
|
|
1666
|
+
skipAddingFilesFromTsConfig: true,
|
|
1667
|
+
compilerOptions: { strict: true }
|
|
1668
|
+
});
|
|
1669
|
+
mixinFiles = new DiskFingerprints();
|
|
1670
|
+
mixinUnresolved = new UnresolvedImports();
|
|
1671
|
+
}
|
|
1846
1672
|
return mixinTypeProject;
|
|
1847
1673
|
}
|
|
1848
1674
|
function clearMixinTypeProject() {
|
|
1849
1675
|
mixinTypeProject = void 0;
|
|
1676
|
+
mixinStale = false;
|
|
1677
|
+
}
|
|
1678
|
+
function invalidateMixinTypeProject() {
|
|
1679
|
+
mixinStale = true;
|
|
1680
|
+
}
|
|
1681
|
+
function refreshMixinTypeProject(project) {
|
|
1682
|
+
const program = project.getProgram().compilerObject;
|
|
1683
|
+
const files = program.getSourceFiles().filter((file) => !program.isSourceFileDefaultLibrary(file)).map((file) => ({ path: file.fileName, text: file.text }));
|
|
1684
|
+
const changed = mixinFiles.changed(files);
|
|
1685
|
+
if (changed.length === 0) return mixinUnresolved.nowResolving(program).length === 0;
|
|
1686
|
+
for (const path of changed) {
|
|
1687
|
+
const sf = project.getSourceFile(path);
|
|
1688
|
+
if (sf?.refreshFromFileSystemSync() !== FileSystemRefreshResult.Updated) return false;
|
|
1689
|
+
}
|
|
1690
|
+
project.resolveSourceFileDependencies();
|
|
1691
|
+
return true;
|
|
1850
1692
|
}
|
|
1851
1693
|
function resolveInstantiatedReturnType(cls, methodName) {
|
|
1852
1694
|
const filePath = cls.getSourceFile().getFilePath();
|
|
@@ -1877,7 +1719,7 @@ function resolveClassRef(ref, project) {
|
|
|
1877
1719
|
return file?.getClass(ref.name);
|
|
1878
1720
|
}
|
|
1879
1721
|
function classifyFilterForHint(typeInit) {
|
|
1880
|
-
if (
|
|
1722
|
+
if (Node5.isStringLiteral(typeInit)) {
|
|
1881
1723
|
switch (typeInit.getLiteralValue()) {
|
|
1882
1724
|
case "string":
|
|
1883
1725
|
return { kind: "string" };
|
|
@@ -1891,10 +1733,10 @@ function classifyFilterForHint(typeInit) {
|
|
|
1891
1733
|
return null;
|
|
1892
1734
|
}
|
|
1893
1735
|
}
|
|
1894
|
-
if (
|
|
1736
|
+
if (Node5.isArrayLiteralExpression(typeInit)) {
|
|
1895
1737
|
const values = [];
|
|
1896
1738
|
for (const el of typeInit.getElements()) {
|
|
1897
|
-
if (!
|
|
1739
|
+
if (!Node5.isStringLiteral(el)) return null;
|
|
1898
1740
|
values.push(el.getLiteralValue());
|
|
1899
1741
|
}
|
|
1900
1742
|
if (values.length === 0) return null;
|
|
@@ -1929,11 +1771,11 @@ function extractFilterForHints(classDecl, project) {
|
|
|
1929
1771
|
if (!filterForDec) continue;
|
|
1930
1772
|
const args = filterForDec.getArguments();
|
|
1931
1773
|
const keyArg = args[0];
|
|
1932
|
-
const inputKey = keyArg &&
|
|
1774
|
+
const inputKey = keyArg && Node5.isStringLiteral(keyArg) ? keyArg.getLiteralValue() : method.getName();
|
|
1933
1775
|
const optsArg = args[1];
|
|
1934
|
-
if (optsArg &&
|
|
1776
|
+
if (optsArg && Node5.isObjectLiteralExpression(optsArg)) {
|
|
1935
1777
|
const typeProp = optsArg.getProperty("type");
|
|
1936
|
-
if (typeProp &&
|
|
1778
|
+
if (typeProp && Node5.isPropertyAssignment(typeProp)) {
|
|
1937
1779
|
const typeInit = typeProp.getInitializer();
|
|
1938
1780
|
if (typeInit) {
|
|
1939
1781
|
const classified = classifyFilterForHint(typeInit);
|
|
@@ -1960,14 +1802,14 @@ function extractApplyFilterInfo(method, sourceFile, project, mixin, controllerCl
|
|
|
1960
1802
|
const filterClassArg = args[0];
|
|
1961
1803
|
if (!filterClassArg) continue;
|
|
1962
1804
|
const factoryStaticClass = resolveFactoryStaticClass(filterClassArg);
|
|
1963
|
-
if (!factoryStaticClass && !
|
|
1805
|
+
if (!factoryStaticClass && !Node5.isIdentifier(filterClassArg)) continue;
|
|
1964
1806
|
let source = "query";
|
|
1965
1807
|
const optionsArg = args[1];
|
|
1966
|
-
if (optionsArg &&
|
|
1808
|
+
if (optionsArg && Node5.isObjectLiteralExpression(optionsArg)) {
|
|
1967
1809
|
const sourceProp = optionsArg.getProperty("source");
|
|
1968
|
-
if (sourceProp &&
|
|
1810
|
+
if (sourceProp && Node5.isPropertyAssignment(sourceProp)) {
|
|
1969
1811
|
const init = sourceProp.getInitializer();
|
|
1970
|
-
if (init &&
|
|
1812
|
+
if (init && Node5.isStringLiteral(init) && init.getLiteralValue() === "body") {
|
|
1971
1813
|
source = "body";
|
|
1972
1814
|
}
|
|
1973
1815
|
}
|
|
@@ -1976,7 +1818,7 @@ function extractApplyFilterInfo(method, sourceFile, project, mixin, controllerCl
|
|
|
1976
1818
|
const resolved = factoryStaticClass ? void 0 : findType(filterClassName, declFile, project);
|
|
1977
1819
|
const declaredClass = factoryStaticClass ?? (resolved?.kind === "class" ? resolved.decl : resolveLocalClassDeclaration(filterClassArg));
|
|
1978
1820
|
const ownRoute = !mixin || (controllerClass ? method.getParent() === controllerClass : declFile.getFilePath() !== mixin.factoryFilePath);
|
|
1979
|
-
const namedByRoute = ownRoute &&
|
|
1821
|
+
const namedByRoute = ownRoute && Node5.isIdentifier(filterClassArg) ? declaredClass : void 0;
|
|
1980
1822
|
for (const candidate of orderFilterCandidates({
|
|
1981
1823
|
namedByRoute,
|
|
1982
1824
|
supplied: resolveMixinFilterClass(mixin, project),
|
|
@@ -2054,22 +1896,22 @@ function resolveRelationEntity(prop, sourceFile, project) {
|
|
|
2054
1896
|
const args = dec.getArguments();
|
|
2055
1897
|
if (args.length === 0) continue;
|
|
2056
1898
|
const arg = args[0];
|
|
2057
|
-
if (
|
|
1899
|
+
if (Node5.isObjectLiteralExpression(arg)) {
|
|
2058
1900
|
const entityProp = arg.getProperty("entity");
|
|
2059
|
-
if (entityProp &&
|
|
1901
|
+
if (entityProp && Node5.isPropertyAssignment(entityProp)) {
|
|
2060
1902
|
const init = entityProp.getInitializer();
|
|
2061
|
-
if (init &&
|
|
1903
|
+
if (init && Node5.isArrowFunction(init)) {
|
|
2062
1904
|
const body = init.getBody();
|
|
2063
|
-
if (
|
|
1905
|
+
if (Node5.isIdentifier(body)) {
|
|
2064
1906
|
const resolved = findType(body.getText(), prop.getSourceFile(), project);
|
|
2065
1907
|
if (resolved?.kind === "class") return resolved.decl;
|
|
2066
1908
|
}
|
|
2067
1909
|
}
|
|
2068
1910
|
}
|
|
2069
1911
|
}
|
|
2070
|
-
if (
|
|
1912
|
+
if (Node5.isArrowFunction(arg)) {
|
|
2071
1913
|
const body = arg.getBody();
|
|
2072
|
-
if (
|
|
1914
|
+
if (Node5.isIdentifier(body)) {
|
|
2073
1915
|
const resolved = findType(body.getText(), prop.getSourceFile(), project);
|
|
2074
1916
|
if (resolved?.kind === "class") return resolved.decl;
|
|
2075
1917
|
}
|
|
@@ -2088,36 +1930,36 @@ function extractClassPropertyTypes(classDecl, project) {
|
|
|
2088
1930
|
return fields;
|
|
2089
1931
|
}
|
|
2090
1932
|
function resolveLocalClassDeclaration(identifier) {
|
|
2091
|
-
if (!
|
|
2092
|
-
return identifier.getDefinitions().map((d) => d.getDeclarationNode()).find((n) => n !== void 0 &&
|
|
1933
|
+
if (!Node5.isIdentifier(identifier)) return void 0;
|
|
1934
|
+
return identifier.getDefinitions().map((d) => d.getDeclarationNode()).find((n) => n !== void 0 && Node5.isClassDeclaration(n));
|
|
2093
1935
|
}
|
|
2094
1936
|
function resolveDeclaredEntity(optionsArg, filterClass, project) {
|
|
2095
|
-
if (!
|
|
1937
|
+
if (!Node5.isObjectLiteralExpression(optionsArg)) return void 0;
|
|
2096
1938
|
const entityProp = optionsArg.getProperty("entity");
|
|
2097
|
-
if (!entityProp || !
|
|
1939
|
+
if (!entityProp || !Node5.isPropertyAssignment(entityProp)) return void 0;
|
|
2098
1940
|
const entityInit = entityProp.getInitializer();
|
|
2099
|
-
if (!entityInit || !
|
|
1941
|
+
if (!entityInit || !Node5.isIdentifier(entityInit)) return void 0;
|
|
2100
1942
|
const resolved = findType(entityInit.getText(), filterClass.getSourceFile(), project);
|
|
2101
1943
|
if (!resolved || resolved.kind !== "class") return void 0;
|
|
2102
1944
|
return resolved.decl;
|
|
2103
1945
|
}
|
|
2104
1946
|
function readFieldNameList(optionsArg, key) {
|
|
2105
|
-
if (!
|
|
1947
|
+
if (!Node5.isObjectLiteralExpression(optionsArg)) return void 0;
|
|
2106
1948
|
const prop = optionsArg.getProperty(key);
|
|
2107
|
-
if (!prop || !
|
|
1949
|
+
if (!prop || !Node5.isPropertyAssignment(prop)) return void 0;
|
|
2108
1950
|
const init = prop.getInitializer();
|
|
2109
|
-
if (!init || !
|
|
1951
|
+
if (!init || !Node5.isArrayLiteralExpression(init)) return void 0;
|
|
2110
1952
|
const names = /* @__PURE__ */ new Set();
|
|
2111
1953
|
for (const el of init.getElements()) {
|
|
2112
|
-
if (
|
|
1954
|
+
if (Node5.isStringLiteral(el)) {
|
|
2113
1955
|
names.add(el.getLiteralValue());
|
|
2114
1956
|
continue;
|
|
2115
1957
|
}
|
|
2116
|
-
if (
|
|
1958
|
+
if (Node5.isObjectLiteralExpression(el)) {
|
|
2117
1959
|
const fieldProp = el.getProperty("field");
|
|
2118
|
-
if (fieldProp &&
|
|
1960
|
+
if (fieldProp && Node5.isPropertyAssignment(fieldProp)) {
|
|
2119
1961
|
const fieldInit = fieldProp.getInitializer();
|
|
2120
|
-
if (fieldInit &&
|
|
1962
|
+
if (fieldInit && Node5.isStringLiteral(fieldInit)) {
|
|
2121
1963
|
names.add(fieldInit.getLiteralValue());
|
|
2122
1964
|
continue;
|
|
2123
1965
|
}
|
|
@@ -2141,7 +1983,7 @@ function extractFilterableEntityFields(filterClass, project, entityOverride, pre
|
|
|
2141
1983
|
const args = filterableDecorator.getArguments();
|
|
2142
1984
|
if (args.length === 0) return [];
|
|
2143
1985
|
const optionsArg = args[0];
|
|
2144
|
-
if (!
|
|
1986
|
+
if (!Node5.isObjectLiteralExpression(optionsArg)) return [];
|
|
2145
1987
|
const declaredEntity = resolveDeclaredEntity(optionsArg, filterClass, project);
|
|
2146
1988
|
const entityDecl = preferDeclaredEntity ? declaredEntity ?? entityOverride : entityOverride ?? declaredEntity;
|
|
2147
1989
|
if (!entityDecl) return [];
|
|
@@ -2152,17 +1994,17 @@ function extractFilterableEntityFields(filterClass, project, entityOverride, pre
|
|
|
2152
1994
|
const relationsDecorator = filterClass.getDecorators().find((d) => d.getName() === "Relations");
|
|
2153
1995
|
if (relationsDecorator) {
|
|
2154
1996
|
const relArgs = relationsDecorator.getArguments();
|
|
2155
|
-
if (relArgs.length > 0 &&
|
|
1997
|
+
if (relArgs.length > 0 && Node5.isObjectLiteralExpression(relArgs[0])) {
|
|
2156
1998
|
for (const relProp of relArgs[0].getProperties()) {
|
|
2157
|
-
if (!
|
|
1999
|
+
if (!Node5.isPropertyAssignment(relProp)) continue;
|
|
2158
2000
|
const relInit = relProp.getInitializer();
|
|
2159
|
-
if (!relInit || !
|
|
2001
|
+
if (!relInit || !Node5.isObjectLiteralExpression(relInit)) continue;
|
|
2160
2002
|
const keysProp = relInit.getProperty("keys");
|
|
2161
|
-
if (!keysProp || !
|
|
2003
|
+
if (!keysProp || !Node5.isPropertyAssignment(keysProp)) continue;
|
|
2162
2004
|
const keysInit = keysProp.getInitializer();
|
|
2163
|
-
if (!keysInit || !
|
|
2005
|
+
if (!keysInit || !Node5.isArrayLiteralExpression(keysInit)) continue;
|
|
2164
2006
|
for (const el of keysInit.getElements()) {
|
|
2165
|
-
if (
|
|
2007
|
+
if (Node5.isStringLiteral(el)) {
|
|
2166
2008
|
fields.push(toFilterFieldType(el.getLiteralValue(), { kind: "unknown" }));
|
|
2167
2009
|
}
|
|
2168
2010
|
}
|
|
@@ -2173,15 +2015,15 @@ function extractFilterableEntityFields(filterClass, project, entityOverride, pre
|
|
|
2173
2015
|
}
|
|
2174
2016
|
|
|
2175
2017
|
// src/discovery/pipe-schema.ts
|
|
2176
|
-
import { Node as
|
|
2018
|
+
import { Node as Node8 } from "ts-morph";
|
|
2177
2019
|
|
|
2178
2020
|
// src/discovery/schema-type-inference.ts
|
|
2179
2021
|
import {
|
|
2180
|
-
ts as
|
|
2022
|
+
ts as ts3
|
|
2181
2023
|
} from "ts-morph";
|
|
2182
2024
|
|
|
2183
2025
|
// src/discovery/schema-type-program.ts
|
|
2184
|
-
import { Node as
|
|
2026
|
+
import { FileSystemRefreshResult as FileSystemRefreshResult2, Node as Node6, Project as Project2, ts as ts2 } from "ts-morph";
|
|
2185
2027
|
var PARAM_DECORATORS = /* @__PURE__ */ new Set(["Body", "Query", "Param"]);
|
|
2186
2028
|
var SchemaTypeProgram = class {
|
|
2187
2029
|
constructor(discovery) {
|
|
@@ -2191,10 +2033,10 @@ var SchemaTypeProgram = class {
|
|
|
2191
2033
|
...base,
|
|
2192
2034
|
// A tsconfig-less consumer gets ES5 by default, whose lib has no `Map`/`Set`/
|
|
2193
2035
|
// `Promise` for the schema libraries' declarations to lean on.
|
|
2194
|
-
target: base.target ??
|
|
2036
|
+
target: base.target ?? ts2.ScriptTarget.ES2022,
|
|
2195
2037
|
// With neither set, resolve the way a bundler does: package `exports`
|
|
2196
2038
|
// (`zod/v4`) and extensionless or `.js` relative imports all resolve.
|
|
2197
|
-
...base.module === void 0 && base.moduleResolution === void 0 ? { module:
|
|
2039
|
+
...base.module === void 0 && base.moduleResolution === void 0 ? { module: ts2.ModuleKind.ESNext, moduleResolution: ts2.ModuleResolutionKind.Bundler } : {},
|
|
2198
2040
|
// Without it `.nullable()` and `.optional()` would erase to the bare type.
|
|
2199
2041
|
strictNullChecks: true,
|
|
2200
2042
|
// No ambient `@types/*` (a tsconfig's `types: ['node']`): a schema does not
|
|
@@ -2202,17 +2044,16 @@ var SchemaTypeProgram = class {
|
|
|
2202
2044
|
types: [],
|
|
2203
2045
|
noEmit: true
|
|
2204
2046
|
};
|
|
2205
|
-
this.project = new
|
|
2047
|
+
this.project = new Project2({
|
|
2206
2048
|
skipAddingFilesFromTsConfig: true,
|
|
2207
2049
|
compilerOptions: this.options
|
|
2208
2050
|
});
|
|
2209
|
-
|
|
2210
|
-
this.flush();
|
|
2051
|
+
this.requestDiscoveryFiles();
|
|
2211
2052
|
}
|
|
2212
2053
|
project;
|
|
2213
2054
|
options;
|
|
2214
2055
|
/** Parses a file that is not in discovery's Project, without adding it there. */
|
|
2215
|
-
scratch = new
|
|
2056
|
+
scratch = new Project2({
|
|
2216
2057
|
skipAddingFilesFromTsConfig: true,
|
|
2217
2058
|
skipLoadingLibFiles: true,
|
|
2218
2059
|
skipFileDependencyResolution: true
|
|
@@ -2220,6 +2061,53 @@ var SchemaTypeProgram = class {
|
|
|
2220
2061
|
needs = /* @__PURE__ */ new Map();
|
|
2221
2062
|
/** Pruned text per file, as last written into {@link project}. */
|
|
2222
2063
|
written = /* @__PURE__ */ new Map();
|
|
2064
|
+
/** What {@link project} read from disk unpruned (packages, declaration files). */
|
|
2065
|
+
externalFiles = new DiskFingerprints();
|
|
2066
|
+
scratchFiles = new DiskFingerprints();
|
|
2067
|
+
/** The last pruning of each file, with the source text and needs it was pruned for. */
|
|
2068
|
+
pruned = /* @__PURE__ */ new Map();
|
|
2069
|
+
/**
|
|
2070
|
+
* Bring the program up to date with discovery's files and the disk, keeping the
|
|
2071
|
+
* lib and package declarations it has already parsed and checked. Leaves it
|
|
2072
|
+
* holding exactly the files a new program built now would hold, with the same
|
|
2073
|
+
* text. Returns false when a file the program read unpruned has changed on disk
|
|
2074
|
+
* (a package was reinstalled, a `.d.ts` was edited): the caller builds a new
|
|
2075
|
+
* program instead.
|
|
2076
|
+
*/
|
|
2077
|
+
refresh() {
|
|
2078
|
+
const program = this.project.getProgram().compilerObject;
|
|
2079
|
+
const external = program.getSourceFiles().filter(
|
|
2080
|
+
(file) => !program.isSourceFileDefaultLibrary(file) && !this.written.has(file.fileName)
|
|
2081
|
+
).map((file) => ({ path: file.fileName, text: file.text }));
|
|
2082
|
+
if (this.externalFiles.changed(external).length > 0) return false;
|
|
2083
|
+
const scratch = this.scratch.getSourceFiles().map((sf) => ({ path: sf.getFilePath(), text: sf.getFullText() }));
|
|
2084
|
+
for (const path of this.scratchFiles.changed(scratch)) {
|
|
2085
|
+
const sf = this.scratch.getSourceFile(path);
|
|
2086
|
+
if (sf?.refreshFromFileSystemSync() === FileSystemRefreshResult2.Deleted) {
|
|
2087
|
+
this.scratchFiles.forget(path);
|
|
2088
|
+
}
|
|
2089
|
+
}
|
|
2090
|
+
this.needs.clear();
|
|
2091
|
+
this.requestDiscoveryFiles();
|
|
2092
|
+
for (const path of [...this.written.keys()]) {
|
|
2093
|
+
if (this.needs.has(path)) continue;
|
|
2094
|
+
const sf = this.project.getSourceFile(path);
|
|
2095
|
+
if (sf) this.project.removeSourceFile(sf);
|
|
2096
|
+
this.written.delete(path);
|
|
2097
|
+
}
|
|
2098
|
+
return true;
|
|
2099
|
+
}
|
|
2100
|
+
/**
|
|
2101
|
+
* Everything discovery holds now (the controllers) goes in before the first
|
|
2102
|
+
* query: a file added afterwards discards the program and its checker, and
|
|
2103
|
+
* rebuilding them once per controller is exactly the cost this avoids.
|
|
2104
|
+
*/
|
|
2105
|
+
requestDiscoveryFiles() {
|
|
2106
|
+
for (const sf of this.discovery.getSourceFiles()) {
|
|
2107
|
+
this.request(sf.getFilePath(), { schema: true });
|
|
2108
|
+
}
|
|
2109
|
+
this.flush();
|
|
2110
|
+
}
|
|
2223
2111
|
/**
|
|
2224
2112
|
* The typed copy of a discovery file, with its schema positions kept. Adding one
|
|
2225
2113
|
* that was not there yet (a contract file discovery reached lazily) rebuilds the
|
|
@@ -2260,12 +2148,21 @@ var SchemaTypeProgram = class {
|
|
|
2260
2148
|
while (this.queue.length > 0) {
|
|
2261
2149
|
const path = this.queue.pop();
|
|
2262
2150
|
const original = this.original(path);
|
|
2263
|
-
if (!original)
|
|
2264
|
-
|
|
2265
|
-
|
|
2151
|
+
if (!original) {
|
|
2152
|
+
if (this.written.has(path)) changed.set(path, void 0);
|
|
2153
|
+
continue;
|
|
2154
|
+
}
|
|
2155
|
+
const { text, requests } = this.pruneCached(path, original, this.needs.get(path));
|
|
2156
|
+
for (const { path: target, want } of requests) this.request(target, want);
|
|
2266
2157
|
if (this.written.get(path) !== text) changed.set(path, text);
|
|
2267
2158
|
}
|
|
2268
2159
|
for (const [path, text] of changed) {
|
|
2160
|
+
if (text === void 0) {
|
|
2161
|
+
const sf = this.project.getSourceFile(path);
|
|
2162
|
+
if (sf) this.project.removeSourceFile(sf);
|
|
2163
|
+
this.written.delete(path);
|
|
2164
|
+
continue;
|
|
2165
|
+
}
|
|
2269
2166
|
this.project.createSourceFile(path, text, { overwrite: true });
|
|
2270
2167
|
this.written.set(path, text);
|
|
2271
2168
|
}
|
|
@@ -2274,11 +2171,29 @@ var SchemaTypeProgram = class {
|
|
|
2274
2171
|
original(path) {
|
|
2275
2172
|
return this.discovery.getSourceFile(path) ?? this.scratch.getSourceFile(path) ?? this.scratch.addSourceFileAtPathIfExists(path);
|
|
2276
2173
|
}
|
|
2174
|
+
/** {@link prune}, reusing the last result while the file's text and needs are the same. */
|
|
2175
|
+
pruneCached(path, sf, needs) {
|
|
2176
|
+
const source = sf.getFullText();
|
|
2177
|
+
const key = `${needs.schema}:${needs.all}:${[...needs.names].sort().join(",")}`;
|
|
2178
|
+
const last = this.pruned.get(path);
|
|
2179
|
+
if (last && last.source === source && last.needs === key) return last;
|
|
2180
|
+
const result = this.prune(sf, needs);
|
|
2181
|
+
if (result.resolved) this.pruned.set(path, { ...result, source, needs: key });
|
|
2182
|
+
else this.pruned.delete(path);
|
|
2183
|
+
return result;
|
|
2184
|
+
}
|
|
2277
2185
|
/**
|
|
2278
2186
|
* `sf`'s text with every import/re-export nothing in `needs` references blanked,
|
|
2279
|
-
*
|
|
2187
|
+
* and the names each kept one brings in from its target.
|
|
2280
2188
|
*/
|
|
2281
2189
|
prune(sf, needs) {
|
|
2190
|
+
const requests = [];
|
|
2191
|
+
let resolved = true;
|
|
2192
|
+
const resolveFrom = (specifier) => {
|
|
2193
|
+
const target = this.resolve(specifier, sf);
|
|
2194
|
+
if (target === null) resolved = false;
|
|
2195
|
+
return target ?? void 0;
|
|
2196
|
+
};
|
|
2282
2197
|
const locals = topLevelDeclarations(sf);
|
|
2283
2198
|
const roots = [];
|
|
2284
2199
|
if (needs.all) roots.push(...sf.getStatements());
|
|
@@ -2312,7 +2227,7 @@ var SchemaTypeProgram = class {
|
|
|
2312
2227
|
const seen = new Set(queue);
|
|
2313
2228
|
while (queue.length > 0) {
|
|
2314
2229
|
const node = queue.pop();
|
|
2315
|
-
const ids =
|
|
2230
|
+
const ids = Node6.isIdentifier(node) ? [node] : node.getDescendantsOfKind(ts2.SyntaxKind.Identifier);
|
|
2316
2231
|
for (const id of ids) {
|
|
2317
2232
|
const name = id.getText();
|
|
2318
2233
|
if (referenced.has(name)) continue;
|
|
@@ -2331,7 +2246,7 @@ var SchemaTypeProgram = class {
|
|
|
2331
2246
|
}
|
|
2332
2247
|
};
|
|
2333
2248
|
for (const decl of sf.getImportDeclarations()) {
|
|
2334
|
-
const target =
|
|
2249
|
+
const target = resolveFrom(decl.getModuleSpecifierValue());
|
|
2335
2250
|
const namespace = decl.getNamespaceImport()?.getText();
|
|
2336
2251
|
const def = decl.getDefaultImport()?.getText();
|
|
2337
2252
|
const named = decl.getNamedImports().map((n) => ({
|
|
@@ -2345,21 +2260,24 @@ var SchemaTypeProgram = class {
|
|
|
2345
2260
|
continue;
|
|
2346
2261
|
}
|
|
2347
2262
|
if (target) {
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2263
|
+
requests.push({
|
|
2264
|
+
path: target,
|
|
2265
|
+
want: {
|
|
2266
|
+
all: wantsNamespace,
|
|
2267
|
+
names: [...wantsDefault ? ["default"] : [], ...named.map((n) => n.imported)]
|
|
2268
|
+
}
|
|
2351
2269
|
});
|
|
2352
2270
|
}
|
|
2353
2271
|
}
|
|
2354
2272
|
for (const exp of sf.getExportDeclarations()) {
|
|
2355
2273
|
const spec = exp.getModuleSpecifierValue();
|
|
2356
2274
|
if (spec === void 0) continue;
|
|
2357
|
-
const target =
|
|
2275
|
+
const target = resolveFrom(spec);
|
|
2358
2276
|
if (exp.isNamespaceExport() || exp.getNamedExports().length === 0) {
|
|
2359
2277
|
if (!needs.all && unresolvedNames.length === 0) {
|
|
2360
2278
|
blank(exp);
|
|
2361
2279
|
} else if (target) {
|
|
2362
|
-
|
|
2280
|
+
requests.push({ path: target, want: { all: needs.all, names: unresolvedNames } });
|
|
2363
2281
|
}
|
|
2364
2282
|
continue;
|
|
2365
2283
|
}
|
|
@@ -2367,22 +2285,24 @@ var SchemaTypeProgram = class {
|
|
|
2367
2285
|
(n) => needs.all || needs.names.has((n.getAliasNode() ?? n.getNameNode()).getText())
|
|
2368
2286
|
).map((n) => n.getNameNode().getText());
|
|
2369
2287
|
if (wanted.length === 0) blank(exp);
|
|
2370
|
-
else if (target)
|
|
2288
|
+
else if (target) requests.push({ path: target, want: { names: wanted } });
|
|
2371
2289
|
}
|
|
2372
|
-
return chars.join("");
|
|
2290
|
+
return { text: chars.join(""), requests, resolved };
|
|
2373
2291
|
}
|
|
2374
2292
|
/**
|
|
2375
|
-
* The project source file a module specifier resolves to
|
|
2376
|
-
* package (read unpruned by the program itself)
|
|
2293
|
+
* The project source file a module specifier resolves to; undefined for a
|
|
2294
|
+
* package or a declaration file (read unpruned by the program itself), null for
|
|
2295
|
+
* one that does not resolve.
|
|
2377
2296
|
*/
|
|
2378
2297
|
resolve(specifier, from) {
|
|
2379
|
-
const resolved =
|
|
2298
|
+
const resolved = ts2.resolveModuleName(
|
|
2380
2299
|
specifier,
|
|
2381
2300
|
from.getFilePath(),
|
|
2382
2301
|
this.options,
|
|
2383
|
-
|
|
2302
|
+
ts2.sys
|
|
2384
2303
|
).resolvedModule;
|
|
2385
|
-
if (!resolved
|
|
2304
|
+
if (!resolved) return null;
|
|
2305
|
+
if (resolved.isExternalLibraryImport) return void 0;
|
|
2386
2306
|
const file = resolved.resolvedFileName;
|
|
2387
2307
|
if (file.endsWith(".d.ts") || !/\.(m|c)?tsx?$/.test(file)) return void 0;
|
|
2388
2308
|
return file;
|
|
@@ -2391,20 +2311,20 @@ var SchemaTypeProgram = class {
|
|
|
2391
2311
|
function schemaPositions(sf) {
|
|
2392
2312
|
const roots = [];
|
|
2393
2313
|
sf.forEachDescendant((node) => {
|
|
2394
|
-
if (
|
|
2314
|
+
if (Node6.isDecorator(node)) {
|
|
2395
2315
|
const name = node.getName();
|
|
2396
2316
|
if (name === "ApplyContract") {
|
|
2397
2317
|
roots.push(...node.getArguments());
|
|
2398
2318
|
} else if (PARAM_DECORATORS.has(name)) {
|
|
2399
2319
|
for (const arg of node.getArguments()) {
|
|
2400
|
-
if (
|
|
2320
|
+
if (Node6.isNewExpression(arg) || Node6.isCallExpression(arg)) {
|
|
2401
2321
|
roots.push(...arg.getArguments());
|
|
2402
2322
|
}
|
|
2403
2323
|
}
|
|
2404
2324
|
}
|
|
2405
|
-
} else if (
|
|
2325
|
+
} else if (Node6.isCallExpression(node)) {
|
|
2406
2326
|
const callee = node.getExpression();
|
|
2407
|
-
const name =
|
|
2327
|
+
const name = Node6.isIdentifier(callee) ? callee.getText() : Node6.isPropertyAccessExpression(callee) ? callee.getName() : void 0;
|
|
2408
2328
|
if (name === "defineContract") roots.push(...node.getArguments());
|
|
2409
2329
|
}
|
|
2410
2330
|
});
|
|
@@ -2437,8 +2357,13 @@ function defaultExport(sf) {
|
|
|
2437
2357
|
|
|
2438
2358
|
// src/discovery/schema-type-inference.ts
|
|
2439
2359
|
var programs = /* @__PURE__ */ new WeakMap();
|
|
2360
|
+
var stale = /* @__PURE__ */ new WeakSet();
|
|
2440
2361
|
function programFor(discovery) {
|
|
2441
2362
|
let program = programs.get(discovery);
|
|
2363
|
+
if (program && stale.has(discovery)) {
|
|
2364
|
+
stale.delete(discovery);
|
|
2365
|
+
if (!program.refresh()) program = void 0;
|
|
2366
|
+
}
|
|
2442
2367
|
if (!program) {
|
|
2443
2368
|
program = new SchemaTypeProgram(discovery);
|
|
2444
2369
|
programs.set(discovery, program);
|
|
@@ -2447,6 +2372,10 @@ function programFor(discovery) {
|
|
|
2447
2372
|
}
|
|
2448
2373
|
function clearSchemaTypeProject(discovery) {
|
|
2449
2374
|
programs.delete(discovery);
|
|
2375
|
+
stale.delete(discovery);
|
|
2376
|
+
}
|
|
2377
|
+
function invalidateSchemaTypeProject(discovery) {
|
|
2378
|
+
if (programs.has(discovery)) stale.add(discovery);
|
|
2450
2379
|
}
|
|
2451
2380
|
function counterpart(typedSf, node) {
|
|
2452
2381
|
const start = node.getStart();
|
|
@@ -2510,7 +2439,7 @@ function objectKey(name) {
|
|
|
2510
2439
|
return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name) ? name : JSON.stringify(name);
|
|
2511
2440
|
}
|
|
2512
2441
|
function isOptionalSymbol(sym) {
|
|
2513
|
-
return (sym.getFlags() &
|
|
2442
|
+
return (sym.getFlags() & ts3.SymbolFlags.Optional) !== 0;
|
|
2514
2443
|
}
|
|
2515
2444
|
function isSymbolKeyed(sym) {
|
|
2516
2445
|
return sym.getName().startsWith("__@");
|
|
@@ -2671,11 +2600,11 @@ function acceptsUndefined(types) {
|
|
|
2671
2600
|
}
|
|
2672
2601
|
|
|
2673
2602
|
// src/discovery/zod-ast-to-ts.ts
|
|
2674
|
-
import { Node as
|
|
2603
|
+
import { Node as Node7, SyntaxKind as SyntaxKind2 } from "ts-morph";
|
|
2675
2604
|
function zodAstToTs(node) {
|
|
2676
|
-
if (!
|
|
2605
|
+
if (!Node7.isCallExpression(node)) return "unknown";
|
|
2677
2606
|
const expr = node.getExpression();
|
|
2678
|
-
if (
|
|
2607
|
+
if (Node7.isPropertyAccessExpression(expr)) {
|
|
2679
2608
|
const methodName = expr.getName();
|
|
2680
2609
|
const receiver = expr.getExpression();
|
|
2681
2610
|
if (methodName === "optional") {
|
|
@@ -2699,17 +2628,17 @@ function zodAstToTs(node) {
|
|
|
2699
2628
|
case "literal": {
|
|
2700
2629
|
const lit = args[0];
|
|
2701
2630
|
if (!lit) return "unknown";
|
|
2702
|
-
if (
|
|
2703
|
-
if (
|
|
2704
|
-
if (lit.getKind() ===
|
|
2705
|
-
if (lit.getKind() ===
|
|
2631
|
+
if (Node7.isStringLiteral(lit)) return JSON.stringify(lit.getLiteralValue());
|
|
2632
|
+
if (Node7.isNumericLiteral(lit)) return lit.getLiteralValue().toString();
|
|
2633
|
+
if (lit.getKind() === SyntaxKind2.TrueKeyword) return "true";
|
|
2634
|
+
if (lit.getKind() === SyntaxKind2.FalseKeyword) return "false";
|
|
2706
2635
|
return "unknown";
|
|
2707
2636
|
}
|
|
2708
2637
|
case "enum": {
|
|
2709
2638
|
const arrArg = args[0];
|
|
2710
|
-
if (!arrArg || !
|
|
2639
|
+
if (!arrArg || !Node7.isArrayLiteralExpression(arrArg)) return "unknown";
|
|
2711
2640
|
const members = arrArg.getElements().map(
|
|
2712
|
-
(el) =>
|
|
2641
|
+
(el) => Node7.isStringLiteral(el) ? JSON.stringify(el.getLiteralValue()) : "unknown"
|
|
2713
2642
|
);
|
|
2714
2643
|
return members.join(" | ");
|
|
2715
2644
|
}
|
|
@@ -2720,10 +2649,10 @@ function zodAstToTs(node) {
|
|
|
2720
2649
|
}
|
|
2721
2650
|
case "object": {
|
|
2722
2651
|
const objArg = args[0];
|
|
2723
|
-
if (!objArg || !
|
|
2652
|
+
if (!objArg || !Node7.isObjectLiteralExpression(objArg)) return "unknown";
|
|
2724
2653
|
const lines = [];
|
|
2725
2654
|
for (const prop of objArg.getProperties()) {
|
|
2726
|
-
if (!
|
|
2655
|
+
if (!Node7.isPropertyAssignment(prop)) continue;
|
|
2727
2656
|
const key = prop.getName();
|
|
2728
2657
|
const valNode = prop.getInitializer();
|
|
2729
2658
|
if (!valNode) continue;
|
|
@@ -2735,7 +2664,7 @@ function zodAstToTs(node) {
|
|
|
2735
2664
|
}
|
|
2736
2665
|
case "union": {
|
|
2737
2666
|
const arrArg = args[0];
|
|
2738
|
-
if (!arrArg || !
|
|
2667
|
+
if (!arrArg || !Node7.isArrayLiteralExpression(arrArg)) return "unknown";
|
|
2739
2668
|
return arrArg.getElements().map(zodAstToTs).join(" | ");
|
|
2740
2669
|
}
|
|
2741
2670
|
case "record": {
|
|
@@ -2745,7 +2674,7 @@ function zodAstToTs(node) {
|
|
|
2745
2674
|
}
|
|
2746
2675
|
case "tuple": {
|
|
2747
2676
|
const arrArg = args[0];
|
|
2748
|
-
if (!arrArg || !
|
|
2677
|
+
if (!arrArg || !Node7.isArrayLiteralExpression(arrArg)) return "unknown";
|
|
2749
2678
|
return `[${arrArg.getElements().map(zodAstToTs).join(", ")}]`;
|
|
2750
2679
|
}
|
|
2751
2680
|
default:
|
|
@@ -2755,9 +2684,9 @@ function zodAstToTs(node) {
|
|
|
2755
2684
|
return "unknown";
|
|
2756
2685
|
}
|
|
2757
2686
|
function isOptionalChain(node) {
|
|
2758
|
-
if (!
|
|
2687
|
+
if (!Node7.isCallExpression(node)) return false;
|
|
2759
2688
|
const expr = node.getExpression();
|
|
2760
|
-
return
|
|
2689
|
+
return Node7.isPropertyAccessExpression(expr) && expr.getName() === "optional";
|
|
2761
2690
|
}
|
|
2762
2691
|
function memberType(val, position, project) {
|
|
2763
2692
|
if (project) {
|
|
@@ -2769,13 +2698,13 @@ function memberType(val, position, project) {
|
|
|
2769
2698
|
return zodAstToTs(val);
|
|
2770
2699
|
}
|
|
2771
2700
|
function parseDefineContractCall(callExpr, project) {
|
|
2772
|
-
if (!
|
|
2701
|
+
if (!Node7.isCallExpression(callExpr)) return null;
|
|
2773
2702
|
const callee = callExpr.getExpression();
|
|
2774
|
-
const calleeName =
|
|
2703
|
+
const calleeName = Node7.isIdentifier(callee) ? callee.getText() : Node7.isPropertyAccessExpression(callee) ? callee.getName() : "";
|
|
2775
2704
|
if (calleeName !== "defineContract") return null;
|
|
2776
2705
|
const args = callExpr.getArguments();
|
|
2777
2706
|
const optsArg = args[0];
|
|
2778
|
-
if (!optsArg || !
|
|
2707
|
+
if (!optsArg || !Node7.isObjectLiteralExpression(optsArg)) return null;
|
|
2779
2708
|
let query = null;
|
|
2780
2709
|
let body = null;
|
|
2781
2710
|
let response = "unknown";
|
|
@@ -2783,7 +2712,7 @@ function parseDefineContractCall(callExpr, project) {
|
|
|
2783
2712
|
let bodyZodText = null;
|
|
2784
2713
|
let queryZodText = null;
|
|
2785
2714
|
for (const prop of optsArg.getProperties()) {
|
|
2786
|
-
if (!
|
|
2715
|
+
if (!Node7.isPropertyAssignment(prop)) continue;
|
|
2787
2716
|
const propName = prop.getName();
|
|
2788
2717
|
const val = prop.getInitializer();
|
|
2789
2718
|
if (!val) continue;
|
|
@@ -2805,7 +2734,7 @@ function parseDefineContractCall(callExpr, project) {
|
|
|
2805
2734
|
// src/discovery/pipe-schema.ts
|
|
2806
2735
|
function pipeSchemaOf(decorator, project) {
|
|
2807
2736
|
for (const pipe of decorator.getArguments()) {
|
|
2808
|
-
if (!
|
|
2737
|
+
if (!Node8.isNewExpression(pipe) && !Node8.isCallExpression(pipe)) continue;
|
|
2809
2738
|
for (const arg of pipe.getArguments()) {
|
|
2810
2739
|
if (!couldBeSchema(arg)) continue;
|
|
2811
2740
|
const inferred = inferSchema(arg, project);
|
|
@@ -2827,15 +2756,15 @@ function pipeSchemaOf(decorator, project) {
|
|
|
2827
2756
|
return null;
|
|
2828
2757
|
}
|
|
2829
2758
|
function couldBeSchema(arg) {
|
|
2830
|
-
return
|
|
2759
|
+
return Node8.isIdentifier(arg) || Node8.isPropertyAccessExpression(arg) || Node8.isCallExpression(arg) || Node8.isAsExpression(arg) || Node8.isSatisfiesExpression(arg) || Node8.isParenthesizedExpression(arg);
|
|
2831
2760
|
}
|
|
2832
2761
|
function syntacticZodType(arg, project) {
|
|
2833
2762
|
let expr = arg;
|
|
2834
|
-
if (
|
|
2763
|
+
if (Node8.isIdentifier(arg)) {
|
|
2835
2764
|
const resolved = resolveImportedVariable(arg.getText(), arg.getSourceFile(), project);
|
|
2836
2765
|
expr = resolved?.decl.getInitializer();
|
|
2837
2766
|
}
|
|
2838
|
-
if (!expr || !
|
|
2767
|
+
if (!expr || !Node8.isCallExpression(expr)) return null;
|
|
2839
2768
|
const type = zodAstToTs(expr);
|
|
2840
2769
|
return type === "unknown" ? null : type;
|
|
2841
2770
|
}
|
|
@@ -2871,22 +2800,22 @@ var PASSTHROUGH_UTILITY = /* @__PURE__ */ new Set([
|
|
|
2871
2800
|
]);
|
|
2872
2801
|
function resolveTypeNodeToString(typeNode, sourceFile, project, depth, subst = /* @__PURE__ */ new Map()) {
|
|
2873
2802
|
if (depth <= 0) return "unknown";
|
|
2874
|
-
if (
|
|
2803
|
+
if (Node9.isArrayTypeNode(typeNode)) {
|
|
2875
2804
|
const elementType = typeNode.getElementTypeNode();
|
|
2876
2805
|
return `Array<${resolveTypeNodeToString(elementType, sourceFile, project, depth, subst)}>`;
|
|
2877
2806
|
}
|
|
2878
|
-
if (
|
|
2807
|
+
if (Node9.isUnionTypeNode(typeNode)) {
|
|
2879
2808
|
return typeNode.getTypeNodes().map((t) => resolveTypeNodeToString(t, sourceFile, project, depth, subst)).join(" | ");
|
|
2880
2809
|
}
|
|
2881
|
-
if (
|
|
2810
|
+
if (Node9.isIntersectionTypeNode(typeNode)) {
|
|
2882
2811
|
return typeNode.getTypeNodes().map((t) => resolveTypeNodeToString(t, sourceFile, project, depth, subst)).join(" & ");
|
|
2883
2812
|
}
|
|
2884
|
-
if (
|
|
2813
|
+
if (Node9.isParenthesizedTypeNode(typeNode)) {
|
|
2885
2814
|
return `(${resolveTypeNodeToString(typeNode.getTypeNode(), sourceFile, project, depth, subst)})`;
|
|
2886
2815
|
}
|
|
2887
|
-
if (
|
|
2816
|
+
if (Node9.isTypeReference(typeNode)) {
|
|
2888
2817
|
const typeName = typeNode.getTypeName();
|
|
2889
|
-
const name =
|
|
2818
|
+
const name = Node9.isIdentifier(typeName) ? typeName.getText() : typeNode.getText();
|
|
2890
2819
|
const bound = subst.get(name);
|
|
2891
2820
|
if (bound !== void 0) return bound;
|
|
2892
2821
|
if (name === "string" || name === "number" || name === "boolean") return name;
|
|
@@ -2909,10 +2838,10 @@ function resolveTypeNodeToString(typeNode, sourceFile, project, depth, subst = /
|
|
|
2909
2838
|
dbg("unresolvable type:", name, "in", sourceFile.getFilePath());
|
|
2910
2839
|
return "unknown";
|
|
2911
2840
|
}
|
|
2912
|
-
if (
|
|
2841
|
+
if (Node9.isTypeLiteral(typeNode)) {
|
|
2913
2842
|
const members = [];
|
|
2914
2843
|
for (const member of typeNode.getMembers()) {
|
|
2915
|
-
if (
|
|
2844
|
+
if (Node9.isPropertySignature(member)) {
|
|
2916
2845
|
const memberTypeNode = member.getTypeNode();
|
|
2917
2846
|
const memberType2 = memberTypeNode ? resolveTypeNodeToString(memberTypeNode, sourceFile, project, depth, subst) : "unknown";
|
|
2918
2847
|
members.push(`${member.getName()}${member.hasQuestionToken() ? "?" : ""}: ${memberType2}`);
|
|
@@ -2923,11 +2852,11 @@ function resolveTypeNodeToString(typeNode, sourceFile, project, depth, subst = /
|
|
|
2923
2852
|
return members.length > 0 ? `{ ${members.join("; ")} }` : "{}";
|
|
2924
2853
|
}
|
|
2925
2854
|
const kind = typeNode.getKind();
|
|
2926
|
-
if (kind ===
|
|
2927
|
-
if (kind ===
|
|
2928
|
-
if (kind ===
|
|
2929
|
-
if (kind ===
|
|
2930
|
-
if (kind ===
|
|
2855
|
+
if (kind === SyntaxKind3.StringKeyword) return "string";
|
|
2856
|
+
if (kind === SyntaxKind3.NumberKeyword) return "number";
|
|
2857
|
+
if (kind === SyntaxKind3.BooleanKeyword) return "boolean";
|
|
2858
|
+
if (kind === SyntaxKind3.UnknownKeyword) return "unknown";
|
|
2859
|
+
if (kind === SyntaxKind3.AnyKeyword) return "unknown";
|
|
2931
2860
|
return typeNode.getText();
|
|
2932
2861
|
}
|
|
2933
2862
|
function unwrapFirstTypeArg(typeNode, sourceFile, project, depth, mode, subst = /* @__PURE__ */ new Map()) {
|
|
@@ -2985,7 +2914,7 @@ function resolvePropertied(decl, sourceFile, project, depth, subst = /* @__PURE_
|
|
|
2985
2914
|
}
|
|
2986
2915
|
function namedField(decorator) {
|
|
2987
2916
|
const first = decorator.getArguments()[0];
|
|
2988
|
-
return first &&
|
|
2917
|
+
return first && Node9.isStringLiteral(first) ? first.getLiteralValue() : null;
|
|
2989
2918
|
}
|
|
2990
2919
|
function extractBodyType(method, sourceFile, project) {
|
|
2991
2920
|
for (const param of method.getParameters()) {
|
|
@@ -3035,8 +2964,8 @@ function extractQueryType(method, sourceFile, project) {
|
|
|
3035
2964
|
function isParamOptional(param) {
|
|
3036
2965
|
if (param.hasQuestionToken() || param.hasInitializer()) return true;
|
|
3037
2966
|
const typeNode = param.getTypeNode();
|
|
3038
|
-
if (typeNode &&
|
|
3039
|
-
return typeNode.getTypeNodes().some((t) => t.getKind() ===
|
|
2967
|
+
if (typeNode && Node9.isUnionTypeNode(typeNode)) {
|
|
2968
|
+
return typeNode.getTypeNodes().some((t) => t.getKind() === SyntaxKind3.UndefinedKeyword);
|
|
3040
2969
|
}
|
|
3041
2970
|
return false;
|
|
3042
2971
|
}
|
|
@@ -3048,7 +2977,7 @@ function extractParamsType(method, sourceFile, project) {
|
|
|
3048
2977
|
const paramArgs = paramDecorator.getArguments();
|
|
3049
2978
|
if (paramArgs.length === 0) continue;
|
|
3050
2979
|
const nameArg = paramArgs[0];
|
|
3051
|
-
if (!
|
|
2980
|
+
if (!Node9.isStringLiteral(nameArg)) continue;
|
|
3052
2981
|
const paramName = nameArg.getLiteralValue();
|
|
3053
2982
|
const typeNode = param.getTypeNode();
|
|
3054
2983
|
const paramType = typeNode ? resolveTypeNodeToString(typeNode, sourceFile, project, 3) : "string";
|
|
@@ -3085,28 +3014,28 @@ function extractUploadedFiles(method) {
|
|
|
3085
3014
|
for (const decorator of method.getDecorators()) {
|
|
3086
3015
|
if (decorator.getName() !== "UseInterceptors") continue;
|
|
3087
3016
|
for (const arg of decorator.getArguments()) {
|
|
3088
|
-
if (!
|
|
3017
|
+
if (!Node9.isCallExpression(arg)) continue;
|
|
3089
3018
|
const interceptor = arg.getExpression().getText();
|
|
3090
3019
|
const callArgs = arg.getArguments();
|
|
3091
3020
|
const firstArg2 = callArgs[0];
|
|
3092
3021
|
if (interceptor === "FileInterceptor") {
|
|
3093
|
-
if (firstArg2 &&
|
|
3022
|
+
if (firstArg2 && Node9.isStringLiteral(firstArg2)) {
|
|
3094
3023
|
entries.push(`${firstArg2.getLiteralValue()}: ${FILE}`);
|
|
3095
3024
|
multipart = true;
|
|
3096
3025
|
}
|
|
3097
3026
|
} else if (interceptor === "FilesInterceptor") {
|
|
3098
|
-
if (firstArg2 &&
|
|
3027
|
+
if (firstArg2 && Node9.isStringLiteral(firstArg2)) {
|
|
3099
3028
|
entries.push(`${firstArg2.getLiteralValue()}: Array<${FILE}>`);
|
|
3100
3029
|
multipart = true;
|
|
3101
3030
|
}
|
|
3102
3031
|
} else if (interceptor === "FileFieldsInterceptor") {
|
|
3103
|
-
if (firstArg2 &&
|
|
3032
|
+
if (firstArg2 && Node9.isArrayLiteralExpression(firstArg2)) {
|
|
3104
3033
|
for (const el of firstArg2.getElements()) {
|
|
3105
|
-
if (!
|
|
3034
|
+
if (!Node9.isObjectLiteralExpression(el)) continue;
|
|
3106
3035
|
const nameProp = el.getProperty("name");
|
|
3107
|
-
if (nameProp &&
|
|
3036
|
+
if (nameProp && Node9.isPropertyAssignment(nameProp)) {
|
|
3108
3037
|
const init = nameProp.getInitializer();
|
|
3109
|
-
if (init &&
|
|
3038
|
+
if (init && Node9.isStringLiteral(init)) {
|
|
3110
3039
|
entries.push(`${init.getLiteralValue()}: Array<${FILE}>`);
|
|
3111
3040
|
}
|
|
3112
3041
|
}
|
|
@@ -3126,13 +3055,13 @@ function extractResponseType(method, sourceFile, project) {
|
|
|
3126
3055
|
if (apiResponseDecorator) {
|
|
3127
3056
|
const args = apiResponseDecorator.getArguments();
|
|
3128
3057
|
const optsArg = args[0];
|
|
3129
|
-
if (optsArg &&
|
|
3058
|
+
if (optsArg && Node9.isObjectLiteralExpression(optsArg)) {
|
|
3130
3059
|
for (const prop of optsArg.getProperties()) {
|
|
3131
|
-
if (!
|
|
3060
|
+
if (!Node9.isPropertyAssignment(prop)) continue;
|
|
3132
3061
|
if (prop.getName() !== "type") continue;
|
|
3133
3062
|
const val = prop.getInitializer();
|
|
3134
3063
|
if (!val) continue;
|
|
3135
|
-
if (
|
|
3064
|
+
if (Node9.isArrayLiteralExpression(val)) {
|
|
3136
3065
|
const elements = val.getElements();
|
|
3137
3066
|
const firstEl = elements[0];
|
|
3138
3067
|
if (elements.length > 0 && firstEl !== void 0) {
|
|
@@ -3153,24 +3082,24 @@ function extractResponseType(method, sourceFile, project) {
|
|
|
3153
3082
|
}
|
|
3154
3083
|
function apiResponseStatus(decorator) {
|
|
3155
3084
|
const optsArg = decorator.getArguments()[0];
|
|
3156
|
-
if (!optsArg || !
|
|
3085
|
+
if (!optsArg || !Node9.isObjectLiteralExpression(optsArg)) return null;
|
|
3157
3086
|
for (const prop of optsArg.getProperties()) {
|
|
3158
|
-
if (!
|
|
3087
|
+
if (!Node9.isPropertyAssignment(prop)) continue;
|
|
3159
3088
|
if (prop.getName() !== "status") continue;
|
|
3160
3089
|
const val = prop.getInitializer();
|
|
3161
|
-
if (val &&
|
|
3090
|
+
if (val && Node9.isNumericLiteral(val)) return Number(val.getLiteralValue());
|
|
3162
3091
|
}
|
|
3163
3092
|
return null;
|
|
3164
3093
|
}
|
|
3165
3094
|
function apiResponseTypeNode(decorator) {
|
|
3166
3095
|
const optsArg = decorator.getArguments()[0];
|
|
3167
|
-
if (!optsArg || !
|
|
3096
|
+
if (!optsArg || !Node9.isObjectLiteralExpression(optsArg)) return null;
|
|
3168
3097
|
for (const prop of optsArg.getProperties()) {
|
|
3169
|
-
if (!
|
|
3098
|
+
if (!Node9.isPropertyAssignment(prop)) continue;
|
|
3170
3099
|
if (prop.getName() !== "type") continue;
|
|
3171
3100
|
const val = prop.getInitializer();
|
|
3172
3101
|
if (!val) return null;
|
|
3173
|
-
if (
|
|
3102
|
+
if (Node9.isArrayLiteralExpression(val)) {
|
|
3174
3103
|
const first = val.getElements()[0];
|
|
3175
3104
|
return first ? { node: first, isArray: true } : null;
|
|
3176
3105
|
}
|
|
@@ -3188,7 +3117,7 @@ function extractErrorType(method, sourceFile, project) {
|
|
|
3188
3117
|
const inner = resolveIdentifierToClassType(typeInfo.node, sourceFile, project, 3);
|
|
3189
3118
|
const type = typeInfo.isArray ? `Array<${inner}>` : inner;
|
|
3190
3119
|
let ref = null;
|
|
3191
|
-
if (
|
|
3120
|
+
if (Node9.isIdentifier(typeInfo.node)) {
|
|
3192
3121
|
const name = typeInfo.node.getText();
|
|
3193
3122
|
const localDecl = sourceFile.getInterface(name) || sourceFile.getClass(name) || sourceFile.getTypeAlias(name);
|
|
3194
3123
|
if (localDecl?.isExported()) {
|
|
@@ -3205,7 +3134,7 @@ function extractErrorType(method, sourceFile, project) {
|
|
|
3205
3134
|
return null;
|
|
3206
3135
|
}
|
|
3207
3136
|
function resolveIdentifierToClassType(node, sourceFile, project, depth) {
|
|
3208
|
-
if (!
|
|
3137
|
+
if (!Node9.isIdentifier(node)) return "unknown";
|
|
3209
3138
|
const name = node.getText();
|
|
3210
3139
|
const resolved = findType(name, sourceFile, project);
|
|
3211
3140
|
if (resolved) {
|
|
@@ -3225,9 +3154,9 @@ var STREAM_ENVELOPES = /* @__PURE__ */ new Set(["MessageEvent", "MessageEventLik
|
|
|
3225
3154
|
var BINARY_RESPONSE_TYPES = /* @__PURE__ */ new Set(["StreamableFile", "Buffer"]);
|
|
3226
3155
|
function detectBinaryResponse(method) {
|
|
3227
3156
|
const node = unwrapNamedContainer(method.getReturnTypeNode(), /* @__PURE__ */ new Set(["Promise"]));
|
|
3228
|
-
if (!node || !
|
|
3157
|
+
if (!node || !Node9.isTypeReference(node)) return false;
|
|
3229
3158
|
const typeName = node.getTypeName();
|
|
3230
|
-
const name =
|
|
3159
|
+
const name = Node9.isIdentifier(typeName) ? typeName.getText() : "";
|
|
3231
3160
|
return BINARY_RESPONSE_TYPES.has(name);
|
|
3232
3161
|
}
|
|
3233
3162
|
function detectStreamElement(method) {
|
|
@@ -3242,9 +3171,9 @@ function detectStreamElement(method) {
|
|
|
3242
3171
|
return null;
|
|
3243
3172
|
}
|
|
3244
3173
|
function streamContainerElement(node) {
|
|
3245
|
-
if (!node || !
|
|
3174
|
+
if (!node || !Node9.isTypeReference(node)) return null;
|
|
3246
3175
|
const typeName = node.getTypeName();
|
|
3247
|
-
const name =
|
|
3176
|
+
const name = Node9.isIdentifier(typeName) ? typeName.getText() : "";
|
|
3248
3177
|
if (STREAM_CONTAINERS.has(name) || STREAM_CONTAINERS_GENERATOR.has(name)) {
|
|
3249
3178
|
return node.getTypeArguments()[0] ?? null;
|
|
3250
3179
|
}
|
|
@@ -3254,9 +3183,9 @@ function hasAsQueryDecorator(method) {
|
|
|
3254
3183
|
return method.getDecorators().some((d) => d.getName() === "AsQuery");
|
|
3255
3184
|
}
|
|
3256
3185
|
function unwrapNamedContainer(node, names) {
|
|
3257
|
-
if (!node || !
|
|
3186
|
+
if (!node || !Node9.isTypeReference(node)) return node;
|
|
3258
3187
|
const typeName = node.getTypeName();
|
|
3259
|
-
const name =
|
|
3188
|
+
const name = Node9.isIdentifier(typeName) ? typeName.getText() : "";
|
|
3260
3189
|
if (names.has(name)) {
|
|
3261
3190
|
return node.getTypeArguments()[0] ?? node;
|
|
3262
3191
|
}
|
|
@@ -3303,11 +3232,11 @@ function extractDtoContract(method, sourceFile, project, mixin, controllerClass)
|
|
|
3303
3232
|
if (apiResp) {
|
|
3304
3233
|
const args = apiResp.getArguments();
|
|
3305
3234
|
const optsArg = args[0];
|
|
3306
|
-
if (optsArg &&
|
|
3235
|
+
if (optsArg && Node9.isObjectLiteralExpression(optsArg)) {
|
|
3307
3236
|
for (const prop of optsArg.getProperties()) {
|
|
3308
|
-
if (
|
|
3237
|
+
if (Node9.isPropertyAssignment(prop) && prop.getName() === "type") {
|
|
3309
3238
|
const val = prop.getInitializer();
|
|
3310
|
-
if (val &&
|
|
3239
|
+
if (val && Node9.isIdentifier(val)) {
|
|
3311
3240
|
const name = val.getText();
|
|
3312
3241
|
const localDecl = sourceFile.getInterface(name) || sourceFile.getClass(name) || sourceFile.getTypeAlias(name);
|
|
3313
3242
|
if (localDecl?.isExported()) {
|
|
@@ -3394,7 +3323,7 @@ async function discoverContractsFast(opts) {
|
|
|
3394
3323
|
return routes;
|
|
3395
3324
|
}
|
|
3396
3325
|
function resolveTsconfigPath(cwd, tsconfig) {
|
|
3397
|
-
return tsconfig ? resolve3(tsconfig) :
|
|
3326
|
+
return tsconfig ? resolve3(tsconfig) : join3(cwd, "tsconfig.json");
|
|
3398
3327
|
}
|
|
3399
3328
|
var NO_TSCONFIG_OPTIONS = {
|
|
3400
3329
|
allowJs: true,
|
|
@@ -3403,25 +3332,25 @@ var NO_TSCONFIG_OPTIONS = {
|
|
|
3403
3332
|
};
|
|
3404
3333
|
function loadDiscoveryTsconfig(tsconfigPath) {
|
|
3405
3334
|
if (!existsSync(tsconfigPath)) return { options: null, files: [] };
|
|
3406
|
-
const read =
|
|
3335
|
+
const read = ts4.readConfigFile(tsconfigPath, (path) => ts4.sys.readFile(path));
|
|
3407
3336
|
if (read.error) {
|
|
3408
3337
|
return {
|
|
3409
3338
|
options: null,
|
|
3410
3339
|
files: [tsconfigPath],
|
|
3411
|
-
error:
|
|
3340
|
+
error: ts4.flattenDiagnosticMessageText(read.error.messageText, " ")
|
|
3412
3341
|
};
|
|
3413
3342
|
}
|
|
3414
3343
|
const host = {
|
|
3415
|
-
useCaseSensitiveFileNames:
|
|
3344
|
+
useCaseSensitiveFileNames: ts4.sys.useCaseSensitiveFileNames,
|
|
3416
3345
|
// The one line that keeps a tsconfig from being a filesystem walk.
|
|
3417
3346
|
readDirectory: () => [],
|
|
3418
|
-
fileExists: (path) =>
|
|
3347
|
+
fileExists: (path) => ts4.sys.fileExists(path),
|
|
3419
3348
|
// `extends` is resolved through the host, so a consumer whose `paths` live
|
|
3420
3349
|
// in a base tsconfig keeps working.
|
|
3421
|
-
readFile: (path) =>
|
|
3350
|
+
readFile: (path) => ts4.sys.readFile(path)
|
|
3422
3351
|
};
|
|
3423
|
-
const sourceFile =
|
|
3424
|
-
const parsed =
|
|
3352
|
+
const sourceFile = ts4.readJsonConfigFile(tsconfigPath, (path) => ts4.sys.readFile(path));
|
|
3353
|
+
const parsed = ts4.parseJsonSourceFileConfigFileContent(
|
|
3425
3354
|
sourceFile,
|
|
3426
3355
|
host,
|
|
3427
3356
|
dirname2(tsconfigPath),
|
|
@@ -3444,7 +3373,7 @@ function createDiscoveryProject(tsconfigPath, tsconfig = loadDiscoveryTsconfig(t
|
|
|
3444
3373
|
`[nestjs-codegen/fast] Could not load ${tsconfigPath}: ${tsconfig.error} \u2014 continuing WITHOUT its compiler options, so path alias imports (e.g. '@/...') will not resolve and controllers extending an alias-imported factory will contribute NO routes to the generated client.`
|
|
3445
3374
|
);
|
|
3446
3375
|
}
|
|
3447
|
-
return new
|
|
3376
|
+
return new Project3({
|
|
3448
3377
|
compilerOptions: tsconfig.options ?? { ...NO_TSCONFIG_OPTIONS },
|
|
3449
3378
|
skipAddingFilesFromTsConfig: true,
|
|
3450
3379
|
skipLoadingLibFiles: true,
|
|
@@ -3486,6 +3415,9 @@ var PersistentDiscovery = class _PersistentDiscovery {
|
|
|
3486
3415
|
glob;
|
|
3487
3416
|
/** Absolute paths of the controllers currently loaded as extraction roots. */
|
|
3488
3417
|
controllerPaths = /* @__PURE__ */ new Set();
|
|
3418
|
+
/** Every file in {@link project}, as last read from disk. */
|
|
3419
|
+
files = new DiskFingerprints();
|
|
3420
|
+
unresolved = new UnresolvedImports();
|
|
3489
3421
|
constructor(project, cwd, glob) {
|
|
3490
3422
|
this.project = project;
|
|
3491
3423
|
this.cwd = cwd;
|
|
@@ -3511,6 +3443,8 @@ var PersistentDiscovery = class _PersistentDiscovery {
|
|
|
3511
3443
|
}
|
|
3512
3444
|
/** Run the initial extraction (equivalent to a first `discoverContractsFast`). */
|
|
3513
3445
|
discover() {
|
|
3446
|
+
clearMixinTypeProject();
|
|
3447
|
+
clearSchemaTypeProject(this.project);
|
|
3514
3448
|
return this.runExtraction();
|
|
3515
3449
|
}
|
|
3516
3450
|
/**
|
|
@@ -3518,26 +3452,39 @@ var PersistentDiscovery = class _PersistentDiscovery {
|
|
|
3518
3452
|
* from disk (controllers AND any lazily-loaded DTO/imported files), re-globs
|
|
3519
3453
|
* to pick up added/removed controllers, clears the per-Project caches, then
|
|
3520
3454
|
* re-extracts. `changedPaths` is a hint; correctness does not depend on it
|
|
3521
|
-
* being exhaustive because re-globbing +
|
|
3455
|
+
* being exhaustive because re-globbing + comparing every loaded file with the
|
|
3456
|
+
* disk covers the set.
|
|
3522
3457
|
*/
|
|
3523
|
-
async rediscover(changedPaths) {
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
|
|
3458
|
+
async rediscover(changedPaths, options = {}) {
|
|
3459
|
+
const hinted = new Set([...changedPaths ?? []].map((p) => resolve3(p)));
|
|
3460
|
+
const program = this.project.getProgram().compilerObject;
|
|
3461
|
+
const sources = program.getSourceFiles().filter(
|
|
3462
|
+
(file) => !program.isSourceFileDefaultLibrary(file) && !program.isSourceFileFromExternalLibrary(file)
|
|
3463
|
+
).map((file) => ({ path: file.fileName, text: file.text }));
|
|
3464
|
+
for (const path of /* @__PURE__ */ new Set([...hinted, ...this.files.changed(sources)])) {
|
|
3465
|
+
const sf = this.project.getSourceFile(path);
|
|
3466
|
+
if (sf && await sf.refreshFromFileSystem() === FileSystemRefreshResult3.Deleted) {
|
|
3467
|
+
this.files.forget(path);
|
|
3531
3468
|
}
|
|
3532
3469
|
}
|
|
3470
|
+
const inProject = new Set(this.project.getSourceFiles().map((sf) => sf.getFilePath()));
|
|
3471
|
+
const definitions = this.project.getLanguageService().compilerObject.getProgram();
|
|
3472
|
+
for (const path of definitions ? this.unresolved.nowResolving(definitions) : []) {
|
|
3473
|
+
const sf = this.project.getSourceFile(path);
|
|
3474
|
+
if (!sf) continue;
|
|
3475
|
+
this.project.removeSourceFile(sf);
|
|
3476
|
+
if (inProject.has(path)) this.project.addSourceFileAtPathIfExists(path);
|
|
3477
|
+
}
|
|
3533
3478
|
const globbed = new Set(
|
|
3534
3479
|
await fg2(this.glob, { cwd: this.cwd, absolute: true, onlyFiles: true })
|
|
3535
3480
|
);
|
|
3481
|
+
let controllersChanged = false;
|
|
3536
3482
|
for (const f of globbed) {
|
|
3537
3483
|
if (!this.controllerPaths.has(f)) {
|
|
3538
3484
|
try {
|
|
3539
3485
|
this.project.addSourceFileAtPath(f);
|
|
3540
3486
|
this.controllerPaths.add(f);
|
|
3487
|
+
controllersChanged = true;
|
|
3541
3488
|
} catch {
|
|
3542
3489
|
}
|
|
3543
3490
|
}
|
|
@@ -3547,25 +3494,31 @@ var PersistentDiscovery = class _PersistentDiscovery {
|
|
|
3547
3494
|
const sf = this.project.getSourceFile(f);
|
|
3548
3495
|
if (sf) this.project.removeSourceFile(sf);
|
|
3549
3496
|
this.controllerPaths.delete(f);
|
|
3497
|
+
controllersChanged = true;
|
|
3550
3498
|
}
|
|
3551
3499
|
}
|
|
3500
|
+
if (controllersChanged || options.filesAddedOrRemoved) {
|
|
3501
|
+
clearMixinTypeProject();
|
|
3502
|
+
clearSchemaTypeProject(this.project);
|
|
3503
|
+
} else {
|
|
3504
|
+
invalidateMixinTypeProject();
|
|
3505
|
+
invalidateSchemaTypeProject(this.project);
|
|
3506
|
+
}
|
|
3552
3507
|
return this.runExtraction();
|
|
3553
3508
|
}
|
|
3554
3509
|
/** Clear stale per-Project caches, then extract over the controller set. */
|
|
3555
3510
|
runExtraction() {
|
|
3556
3511
|
clearTypeResolutionCaches(this.project);
|
|
3557
3512
|
clearEnumCache(this.project);
|
|
3558
|
-
clearMixinTypeProject();
|
|
3559
|
-
clearSchemaTypeProject(this.project);
|
|
3560
3513
|
return extractRoutesFrom(this.project, this.controllerPaths);
|
|
3561
3514
|
}
|
|
3562
3515
|
};
|
|
3563
3516
|
function decoratorStringArg(decoratorExpr) {
|
|
3564
3517
|
if (!decoratorExpr) return void 0;
|
|
3565
|
-
if (
|
|
3566
|
-
if (
|
|
3518
|
+
if (Node10.isStringLiteral(decoratorExpr)) return decoratorExpr.getLiteralValue();
|
|
3519
|
+
if (Node10.isArrayLiteralExpression(decoratorExpr)) {
|
|
3567
3520
|
const first = decoratorExpr.getElements()[0];
|
|
3568
|
-
if (first &&
|
|
3521
|
+
if (first && Node10.isStringLiteral(first)) return first.getLiteralValue();
|
|
3569
3522
|
}
|
|
3570
3523
|
return void 0;
|
|
3571
3524
|
}
|
|
@@ -3686,9 +3639,9 @@ function extractContractRoute(args) {
|
|
|
3686
3639
|
let contractDef = null;
|
|
3687
3640
|
let bodyZodRef = null;
|
|
3688
3641
|
let queryZodRef = null;
|
|
3689
|
-
if (
|
|
3642
|
+
if (Node10.isCallExpression(firstDecoratorArg)) {
|
|
3690
3643
|
contractDef = parseDefineContractCall(firstDecoratorArg, project);
|
|
3691
|
-
} else if (
|
|
3644
|
+
} else if (Node10.isIdentifier(firstDecoratorArg)) {
|
|
3692
3645
|
const identName = firstDecoratorArg.getText();
|
|
3693
3646
|
const resolvedVar = resolveImportedVariable(identName, sourceFile, project);
|
|
3694
3647
|
if (!resolvedVar) {
|
|
@@ -3843,7 +3796,300 @@ function extractFromSourceFile(sourceFile, project) {
|
|
|
3843
3796
|
return routes;
|
|
3844
3797
|
}
|
|
3845
3798
|
|
|
3799
|
+
// src/discovery/shared-props.ts
|
|
3800
|
+
function discoverSharedProps(project, moduleEntry) {
|
|
3801
|
+
try {
|
|
3802
|
+
let sourceFile = project.getSourceFile(moduleEntry);
|
|
3803
|
+
if (!sourceFile) {
|
|
3804
|
+
try {
|
|
3805
|
+
sourceFile = project.addSourceFileAtPath(moduleEntry);
|
|
3806
|
+
} catch {
|
|
3807
|
+
return null;
|
|
3808
|
+
}
|
|
3809
|
+
}
|
|
3810
|
+
const forRootCall = findForRootCall(sourceFile);
|
|
3811
|
+
if (!forRootCall) return null;
|
|
3812
|
+
const initializer = findShareInitializer(forRootCall);
|
|
3813
|
+
if (!initializer) return null;
|
|
3814
|
+
return extractShareType(initializer, sourceFile, project);
|
|
3815
|
+
} catch {
|
|
3816
|
+
return null;
|
|
3817
|
+
}
|
|
3818
|
+
}
|
|
3819
|
+
function discoverSharedPropsFromConfig(config) {
|
|
3820
|
+
if (!config.app?.moduleEntry) return null;
|
|
3821
|
+
try {
|
|
3822
|
+
const tsconfigPath = config.app.tsconfig ?? join4(config.codegen.cwd, "tsconfig.json");
|
|
3823
|
+
let project;
|
|
3824
|
+
try {
|
|
3825
|
+
project = sharedPropsProject(tsconfigPath);
|
|
3826
|
+
} catch {
|
|
3827
|
+
project = new Project4({
|
|
3828
|
+
skipAddingFilesFromTsConfig: true,
|
|
3829
|
+
skipLoadingLibFiles: true,
|
|
3830
|
+
skipFileDependencyResolution: true,
|
|
3831
|
+
compilerOptions: { allowJs: true, strict: false }
|
|
3832
|
+
});
|
|
3833
|
+
}
|
|
3834
|
+
return discoverSharedProps(project, config.app.moduleEntry);
|
|
3835
|
+
} catch {
|
|
3836
|
+
return null;
|
|
3837
|
+
}
|
|
3838
|
+
}
|
|
3839
|
+
var parsedTsconfigs = /* @__PURE__ */ new Map();
|
|
3840
|
+
function readText(file) {
|
|
3841
|
+
try {
|
|
3842
|
+
return readFileSync2(file, "utf8");
|
|
3843
|
+
} catch {
|
|
3844
|
+
return "\0missing";
|
|
3845
|
+
}
|
|
3846
|
+
}
|
|
3847
|
+
function sharedPropsProject(tsconfigPath) {
|
|
3848
|
+
const text = loadDiscoveryTsconfig(tsconfigPath).files.map((file) => `${file}\0${readText(file)}`).join("\0");
|
|
3849
|
+
const flags = {
|
|
3850
|
+
skipAddingFilesFromTsConfig: true,
|
|
3851
|
+
skipLoadingLibFiles: true,
|
|
3852
|
+
skipFileDependencyResolution: true
|
|
3853
|
+
};
|
|
3854
|
+
const parsed = parsedTsconfigs.get(tsconfigPath);
|
|
3855
|
+
if (parsed?.text === text) return new Project4({ ...flags, compilerOptions: parsed.options });
|
|
3856
|
+
const project = new Project4({ ...flags, tsConfigFilePath: tsconfigPath });
|
|
3857
|
+
parsedTsconfigs.set(tsconfigPath, { text, options: project.getCompilerOptions() });
|
|
3858
|
+
return project;
|
|
3859
|
+
}
|
|
3860
|
+
function findForRootCall(sourceFile) {
|
|
3861
|
+
const callExpressions = sourceFile.getDescendantsOfKind(SyntaxKind4.CallExpression);
|
|
3862
|
+
for (const call of callExpressions) {
|
|
3863
|
+
const expr = call.getExpression();
|
|
3864
|
+
if (!Node11.isPropertyAccessExpression(expr)) continue;
|
|
3865
|
+
const methodName = expr.getName();
|
|
3866
|
+
const objectExpr = expr.getExpression();
|
|
3867
|
+
if (methodName === "forRoot" && Node11.isIdentifier(objectExpr)) {
|
|
3868
|
+
const name = objectExpr.getText();
|
|
3869
|
+
if (name === "InertiaModule") {
|
|
3870
|
+
return call;
|
|
3871
|
+
}
|
|
3872
|
+
}
|
|
3873
|
+
}
|
|
3874
|
+
return null;
|
|
3875
|
+
}
|
|
3876
|
+
function findShareInitializer(forRootCall) {
|
|
3877
|
+
if (!Node11.isCallExpression(forRootCall)) return null;
|
|
3878
|
+
const args = forRootCall.getArguments();
|
|
3879
|
+
const firstArg2 = args[0];
|
|
3880
|
+
if (!firstArg2 || !Node11.isObjectLiteralExpression(firstArg2)) return null;
|
|
3881
|
+
for (const prop of firstArg2.getProperties()) {
|
|
3882
|
+
if (Node11.isPropertyAssignment(prop) && prop.getName() === "share") {
|
|
3883
|
+
return prop.getInitializer() ?? null;
|
|
3884
|
+
}
|
|
3885
|
+
}
|
|
3886
|
+
return null;
|
|
3887
|
+
}
|
|
3888
|
+
function extractShareType(node, sourceFile, project) {
|
|
3889
|
+
if (Node11.isIdentifier(node)) {
|
|
3890
|
+
const ref = resolveIdentifierToImportRef(node, sourceFile, project);
|
|
3891
|
+
if (ref) {
|
|
3892
|
+
return {
|
|
3893
|
+
typeString: `Awaited<ReturnType<typeof import('${ref.importPath}').${ref.exportName}>>`,
|
|
3894
|
+
properties: null,
|
|
3895
|
+
isImportRef: true
|
|
3896
|
+
};
|
|
3897
|
+
}
|
|
3898
|
+
}
|
|
3899
|
+
if (Node11.isArrowFunction(node)) {
|
|
3900
|
+
const result = extractFromFunctionLike(node, sourceFile);
|
|
3901
|
+
return result ? { ...result, isImportRef: false } : null;
|
|
3902
|
+
}
|
|
3903
|
+
if (Node11.isFunctionExpression(node)) {
|
|
3904
|
+
const result = extractFromFunctionLike(node, sourceFile);
|
|
3905
|
+
return result ? { ...result, isImportRef: false } : null;
|
|
3906
|
+
}
|
|
3907
|
+
if (Node11.isObjectLiteralExpression(node)) {
|
|
3908
|
+
const result = extractFromObjectLiteral(node);
|
|
3909
|
+
return result ? { ...result, isImportRef: false } : null;
|
|
3910
|
+
}
|
|
3911
|
+
return null;
|
|
3912
|
+
}
|
|
3913
|
+
function resolveIdentifierToImportRef(id, sourceFile, project) {
|
|
3914
|
+
if (!Node11.isIdentifier(id)) return null;
|
|
3915
|
+
const name = id.getText();
|
|
3916
|
+
const localFunc = sourceFile.getFunction(name);
|
|
3917
|
+
if (localFunc?.isExported()) {
|
|
3918
|
+
const filePath = sourceFile.getFilePath().replace(/\.ts$/, "");
|
|
3919
|
+
return { importPath: filePath, exportName: name };
|
|
3920
|
+
}
|
|
3921
|
+
const localVar = sourceFile.getVariableDeclaration(name);
|
|
3922
|
+
if (localVar?.isExported()) {
|
|
3923
|
+
const filePath = sourceFile.getFilePath().replace(/\.ts$/, "");
|
|
3924
|
+
return { importPath: filePath, exportName: name };
|
|
3925
|
+
}
|
|
3926
|
+
for (const imp of sourceFile.getImportDeclarations()) {
|
|
3927
|
+
for (const named of imp.getNamedImports()) {
|
|
3928
|
+
const importedName = named.getAliasNode()?.getText() ?? named.getName();
|
|
3929
|
+
if (importedName !== name) continue;
|
|
3930
|
+
const resolvedSource = imp.getModuleSpecifierSourceFile();
|
|
3931
|
+
if (!resolvedSource) continue;
|
|
3932
|
+
const originalName = named.getName();
|
|
3933
|
+
const fn = resolvedSource.getFunction(originalName);
|
|
3934
|
+
if (fn?.isExported()) {
|
|
3935
|
+
const filePath = resolvedSource.getFilePath().replace(/\.ts$/, "");
|
|
3936
|
+
return { importPath: filePath, exportName: originalName };
|
|
3937
|
+
}
|
|
3938
|
+
const v = resolvedSource.getVariableDeclaration(originalName);
|
|
3939
|
+
if (v?.isExported()) {
|
|
3940
|
+
const filePath = resolvedSource.getFilePath().replace(/\.ts$/, "");
|
|
3941
|
+
return { importPath: filePath, exportName: originalName };
|
|
3942
|
+
}
|
|
3943
|
+
}
|
|
3944
|
+
}
|
|
3945
|
+
return null;
|
|
3946
|
+
}
|
|
3947
|
+
function extractFromFunctionLike(node, _sourceFile) {
|
|
3948
|
+
const returnTypeNode = Node11.isArrowFunction(node) || Node11.isFunctionExpression(node) ? node.getReturnTypeNode() : null;
|
|
3949
|
+
if (returnTypeNode) {
|
|
3950
|
+
return extractFromReturnTypeAnnotation(returnTypeNode);
|
|
3951
|
+
}
|
|
3952
|
+
if (Node11.isArrowFunction(node)) {
|
|
3953
|
+
const body = node.getBody();
|
|
3954
|
+
if (Node11.isParenthesizedExpression(body)) {
|
|
3955
|
+
const inner = body.getExpression();
|
|
3956
|
+
if (Node11.isObjectLiteralExpression(inner)) {
|
|
3957
|
+
return extractFromObjectLiteral(inner);
|
|
3958
|
+
}
|
|
3959
|
+
}
|
|
3960
|
+
if (Node11.isObjectLiteralExpression(body)) {
|
|
3961
|
+
return extractFromObjectLiteral(body);
|
|
3962
|
+
}
|
|
3963
|
+
if (Node11.isBlock(body)) {
|
|
3964
|
+
return extractFromBlockReturn(body);
|
|
3965
|
+
}
|
|
3966
|
+
}
|
|
3967
|
+
if (Node11.isFunctionExpression(node)) {
|
|
3968
|
+
const body = node.getBody();
|
|
3969
|
+
if (Node11.isBlock(body)) {
|
|
3970
|
+
return extractFromBlockReturn(body);
|
|
3971
|
+
}
|
|
3972
|
+
}
|
|
3973
|
+
return null;
|
|
3974
|
+
}
|
|
3975
|
+
function extractFromReturnTypeAnnotation(typeNode) {
|
|
3976
|
+
if (Node11.isTypeReference(typeNode)) {
|
|
3977
|
+
const typeName = typeNode.getTypeName();
|
|
3978
|
+
if (Node11.isIdentifier(typeName) && typeName.getText() === "Promise") {
|
|
3979
|
+
const typeArgs = typeNode.getTypeArguments();
|
|
3980
|
+
const firstArg2 = typeArgs[0];
|
|
3981
|
+
if (firstArg2) {
|
|
3982
|
+
return extractFromReturnTypeAnnotation(firstArg2);
|
|
3983
|
+
}
|
|
3984
|
+
return null;
|
|
3985
|
+
}
|
|
3986
|
+
}
|
|
3987
|
+
if (Node11.isTypeLiteral(typeNode)) {
|
|
3988
|
+
const properties = [];
|
|
3989
|
+
for (const member of typeNode.getMembers()) {
|
|
3990
|
+
if (Node11.isPropertySignature(member)) {
|
|
3991
|
+
const name = member.getName();
|
|
3992
|
+
const memberTypeNode = member.getTypeNode();
|
|
3993
|
+
const type = memberTypeNode ? memberTypeNode.getText() : "unknown";
|
|
3994
|
+
properties.push({ name, type });
|
|
3995
|
+
}
|
|
3996
|
+
}
|
|
3997
|
+
if (properties.length === 0) return null;
|
|
3998
|
+
const typeString = `{ ${properties.map((p) => `${p.name}: ${p.type}`).join("; ")} }`;
|
|
3999
|
+
return { typeString, properties, isImportRef: false };
|
|
4000
|
+
}
|
|
4001
|
+
return null;
|
|
4002
|
+
}
|
|
4003
|
+
function extractFromBlockReturn(block) {
|
|
4004
|
+
if (!Node11.isBlock(block)) return null;
|
|
4005
|
+
const statements = block.getStatements();
|
|
4006
|
+
for (let i = statements.length - 1; i >= 0; i--) {
|
|
4007
|
+
const stmt = statements[i];
|
|
4008
|
+
if (!Node11.isReturnStatement(stmt)) continue;
|
|
4009
|
+
const expr = stmt.getExpression();
|
|
4010
|
+
if (!expr) continue;
|
|
4011
|
+
if (Node11.isObjectLiteralExpression(expr)) {
|
|
4012
|
+
return extractFromObjectLiteral(expr);
|
|
4013
|
+
}
|
|
4014
|
+
if (Node11.isParenthesizedExpression(expr)) {
|
|
4015
|
+
const inner = expr.getExpression();
|
|
4016
|
+
if (Node11.isObjectLiteralExpression(inner)) {
|
|
4017
|
+
return extractFromObjectLiteral(inner);
|
|
4018
|
+
}
|
|
4019
|
+
}
|
|
4020
|
+
break;
|
|
4021
|
+
}
|
|
4022
|
+
return null;
|
|
4023
|
+
}
|
|
4024
|
+
function extractFromObjectLiteral(objLiteral) {
|
|
4025
|
+
if (!Node11.isObjectLiteralExpression(objLiteral)) return null;
|
|
4026
|
+
const properties = [];
|
|
4027
|
+
for (const prop of objLiteral.getProperties()) {
|
|
4028
|
+
if (!Node11.isPropertyAssignment(prop)) continue;
|
|
4029
|
+
const name = prop.getName();
|
|
4030
|
+
const initializer = prop.getInitializer();
|
|
4031
|
+
if (!initializer) continue;
|
|
4032
|
+
const type = inferExpressionType(initializer);
|
|
4033
|
+
properties.push({ name, type });
|
|
4034
|
+
}
|
|
4035
|
+
if (properties.length === 0) return null;
|
|
4036
|
+
const typeString = `{ ${properties.map((p) => `${p.name}: ${p.type}`).join("; ")} }`;
|
|
4037
|
+
return { typeString, properties, isImportRef: false };
|
|
4038
|
+
}
|
|
4039
|
+
function inferExpressionType(node) {
|
|
4040
|
+
if (Node11.isStringLiteral(node)) return "string";
|
|
4041
|
+
if (Node11.isTemplateExpression(node) || Node11.isNoSubstitutionTemplateLiteral(node))
|
|
4042
|
+
return "string";
|
|
4043
|
+
if (Node11.isNumericLiteral(node)) return "number";
|
|
4044
|
+
if (node.getKind() === SyntaxKind4.TrueKeyword || node.getKind() === SyntaxKind4.FalseKeyword) {
|
|
4045
|
+
return "boolean";
|
|
4046
|
+
}
|
|
4047
|
+
if (node.getKind() === SyntaxKind4.NullKeyword) return "null";
|
|
4048
|
+
if (Node11.isIdentifier(node) && node.getText() === "undefined") return "undefined";
|
|
4049
|
+
if (Node11.isObjectLiteralExpression(node)) {
|
|
4050
|
+
const props = node.getProperties();
|
|
4051
|
+
if (props.length === 0) return "Record<string, unknown>";
|
|
4052
|
+
const entries = [];
|
|
4053
|
+
for (const prop of props) {
|
|
4054
|
+
if (!Node11.isPropertyAssignment(prop)) continue;
|
|
4055
|
+
const key = prop.getName();
|
|
4056
|
+
const init = prop.getInitializer();
|
|
4057
|
+
if (!init) continue;
|
|
4058
|
+
entries.push(`${key}: ${inferExpressionType(init)}`);
|
|
4059
|
+
}
|
|
4060
|
+
if (entries.length === 0) return "Record<string, unknown>";
|
|
4061
|
+
return `{ ${entries.join("; ")} }`;
|
|
4062
|
+
}
|
|
4063
|
+
if (Node11.isArrayLiteralExpression(node)) {
|
|
4064
|
+
const elements = node.getElements();
|
|
4065
|
+
if (elements.length === 0) return "Array<unknown>";
|
|
4066
|
+
const first = elements[0];
|
|
4067
|
+
if (first) return `Array<${inferExpressionType(first)}>`;
|
|
4068
|
+
return "Array<unknown>";
|
|
4069
|
+
}
|
|
4070
|
+
if (Node11.isConditionalExpression(node)) {
|
|
4071
|
+
const whenTrue = inferExpressionType(node.getWhenTrue());
|
|
4072
|
+
const whenFalse = inferExpressionType(node.getWhenFalse());
|
|
4073
|
+
if (whenTrue === whenFalse) return whenTrue;
|
|
4074
|
+
return `${whenTrue} | ${whenFalse}`;
|
|
4075
|
+
}
|
|
4076
|
+
if (Node11.isParenthesizedExpression(node)) {
|
|
4077
|
+
return inferExpressionType(node.getExpression());
|
|
4078
|
+
}
|
|
4079
|
+
if (Node11.isAsExpression(node)) {
|
|
4080
|
+
const typeNode = node.getTypeNode();
|
|
4081
|
+
if (typeNode) return typeNode.getText();
|
|
4082
|
+
}
|
|
4083
|
+
return "unknown";
|
|
4084
|
+
}
|
|
4085
|
+
|
|
4086
|
+
// src/emit/emit-api.ts
|
|
4087
|
+
import { mkdir, writeFile } from "fs/promises";
|
|
4088
|
+
import { isAbsolute as isAbsolute2, join as join5, relative as relative4 } from "path";
|
|
4089
|
+
|
|
3846
4090
|
// src/extension/registry.ts
|
|
4091
|
+
import { relative as relative3, resolve as resolve4 } from "path";
|
|
4092
|
+
import { Project as Project5 } from "ts-morph";
|
|
3847
4093
|
function resolveApiSlots(extensions) {
|
|
3848
4094
|
let layer;
|
|
3849
4095
|
let layerOwner;
|
|
@@ -5628,36 +5874,64 @@ async function discoverInputFiles(config) {
|
|
|
5628
5874
|
const matched = await fg3(globs, { cwd, absolute: true, onlyFiles: true });
|
|
5629
5875
|
return [...new Set(matched)].sort();
|
|
5630
5876
|
}
|
|
5631
|
-
|
|
5877
|
+
var READ_CONCURRENCY = 64;
|
|
5878
|
+
async function readAll(paths, read) {
|
|
5879
|
+
const out = /* @__PURE__ */ new Map();
|
|
5880
|
+
for (let i = 0; i < paths.length; i += READ_CONCURRENCY) {
|
|
5881
|
+
const batch = paths.slice(i, i + READ_CONCURRENCY);
|
|
5882
|
+
const texts = await Promise.all(batch.map(read));
|
|
5883
|
+
batch.forEach((path, j) => out.set(path, texts[j]));
|
|
5884
|
+
}
|
|
5885
|
+
return out;
|
|
5886
|
+
}
|
|
5887
|
+
async function readInputs(config) {
|
|
5888
|
+
const cwd = config.codegen.cwd;
|
|
5889
|
+
const tsconfigPath = resolveTsconfigPath(cwd, config.app?.tsconfig ?? void 0);
|
|
5890
|
+
const extended = loadDiscoveryTsconfig(tsconfigPath).files;
|
|
5891
|
+
const tsconfigFiles = extended.length > 0 ? extended : [tsconfigPath];
|
|
5892
|
+
const files = await discoverInputFiles(config);
|
|
5893
|
+
const contents = /* @__PURE__ */ new Map();
|
|
5894
|
+
const tsconfigs = await readAll(
|
|
5895
|
+
tsconfigFiles,
|
|
5896
|
+
(file) => readFile2(file, "utf8").catch(() => null)
|
|
5897
|
+
);
|
|
5898
|
+
for (const [file, text] of tsconfigs) contents.set(file, text);
|
|
5899
|
+
for (const [file, text] of await readAll(files, (file2) => readFile2(file2, "utf8"))) {
|
|
5900
|
+
contents.set(file, text);
|
|
5901
|
+
}
|
|
5902
|
+
return { tsconfigFiles, files, contents, tracked: /* @__PURE__ */ new Map() };
|
|
5903
|
+
}
|
|
5904
|
+
async function readInput(snapshot, path) {
|
|
5905
|
+
return snapshot.contents.get(path) ?? readFile2(path, "utf8");
|
|
5906
|
+
}
|
|
5907
|
+
async function computeInputsHash(config, extraInputs = [], snapshot) {
|
|
5908
|
+
const inputs = snapshot ?? await readInputs(config);
|
|
5632
5909
|
const hash = createHash("sha256");
|
|
5633
5910
|
hash.update(`version:${VERSION}
|
|
5634
5911
|
`);
|
|
5635
5912
|
hash.update(`config:${serializeConfig(config)}
|
|
5636
5913
|
`);
|
|
5637
5914
|
const cwd = config.codegen.cwd;
|
|
5638
|
-
const
|
|
5639
|
-
const tsconfigFiles = loadDiscoveryTsconfig(tsconfigPath).files;
|
|
5640
|
-
for (const file of tsconfigFiles.length > 0 ? tsconfigFiles : [tsconfigPath]) {
|
|
5641
|
-
const contents = await readFile2(file, "utf8").catch(() => null);
|
|
5915
|
+
for (const file of inputs.tsconfigFiles) {
|
|
5642
5916
|
hash.update(`tsconfig:${relative7(cwd, file)}
|
|
5643
5917
|
`);
|
|
5644
|
-
hash.update(contents ?? " missing");
|
|
5918
|
+
hash.update(inputs.contents.get(file) ?? " missing");
|
|
5645
5919
|
hash.update("\n");
|
|
5646
5920
|
}
|
|
5647
|
-
const
|
|
5648
|
-
const globbedRelative = new Set(globbed.map((file) => relative7(cwd, file)));
|
|
5921
|
+
const globbedRelative = new Set(inputs.files.map((file) => relative7(cwd, file)));
|
|
5649
5922
|
const extra = [...new Set(extraInputs)].filter((file) => !globbedRelative.has(file)).sort();
|
|
5650
|
-
for (const file of
|
|
5651
|
-
const contents = await readFile2(file, "utf8");
|
|
5923
|
+
for (const file of inputs.files) {
|
|
5652
5924
|
hash.update(`file:${relative7(cwd, file)}
|
|
5653
5925
|
`);
|
|
5654
|
-
hash.update(contents);
|
|
5926
|
+
hash.update(inputs.contents.get(file));
|
|
5655
5927
|
hash.update("\n");
|
|
5656
5928
|
}
|
|
5929
|
+
const unread = extra.map((file) => join13(cwd, file)).filter((abs) => !inputs.tracked.has(abs));
|
|
5930
|
+
for (const [abs, text] of await readAll(unread, readTrackedInput)) inputs.tracked.set(abs, text);
|
|
5657
5931
|
for (const file of extra) {
|
|
5658
5932
|
hash.update(`extra:${file}
|
|
5659
5933
|
`);
|
|
5660
|
-
hash.update(
|
|
5934
|
+
hash.update(inputs.tracked.get(join13(cwd, file)));
|
|
5661
5935
|
hash.update("\n");
|
|
5662
5936
|
}
|
|
5663
5937
|
return hash.digest("hex");
|
|
@@ -5738,7 +6012,8 @@ function driftGuardMessage(outDir, previousEntryPoint, currentEntryPoint, differ
|
|
|
5738
6012
|
async function generate(config, inputRoutes = [], entryPoint = "cli") {
|
|
5739
6013
|
setCodegenDebug(config.debug);
|
|
5740
6014
|
const manifest = await readManifest(config.codegen.outDir);
|
|
5741
|
-
const
|
|
6015
|
+
const inputs = await readInputs(config);
|
|
6016
|
+
const inputsHash = await computeInputsHash(config, manifest?.extraInputs ?? [], inputs);
|
|
5742
6017
|
if (await isManifestFresh(config.codegen.outDir, manifest, inputsHash)) {
|
|
5743
6018
|
console.log(`[nestjs-codegen] ${config.codegen.outDir} up to date, skipped`);
|
|
5744
6019
|
return;
|
|
@@ -5766,7 +6041,7 @@ async function generate(config, inputRoutes = [], entryPoint = "cli") {
|
|
|
5766
6041
|
}
|
|
5767
6042
|
if (config.pages) {
|
|
5768
6043
|
const pagesConfig = config.pages;
|
|
5769
|
-
const pages = await discoverPageScopes(config);
|
|
6044
|
+
const pages = await discoverPageScopes(config, (path) => readInput(inputs, path));
|
|
5770
6045
|
const sharedProps = discoverSharedPropsFromConfig(config);
|
|
5771
6046
|
await emitPages(pages, config.codegen.outDir, {
|
|
5772
6047
|
propsExport: pagesConfig.propsExport,
|
|
@@ -5816,7 +6091,7 @@ async function generate(config, inputRoutes = [], entryPoint = "cli") {
|
|
|
5816
6091
|
}
|
|
5817
6092
|
const outputFiles = await listOutputFiles(config.codegen.outDir);
|
|
5818
6093
|
const extraInputs = [...trackedInputs].sort();
|
|
5819
|
-
const recordedHash = extraInputs.length > 0 ? await computeInputsHash(config, extraInputs) : inputsHash;
|
|
6094
|
+
const recordedHash = extraInputs.length > 0 ? await computeInputsHash(config, extraInputs, inputs) : inputsHash;
|
|
5820
6095
|
await writeManifest(config.codegen.outDir, {
|
|
5821
6096
|
version: VERSION,
|
|
5822
6097
|
hash: recordedHash,
|
|
@@ -5999,13 +6274,15 @@ async function watch(config, onChange, options = {}) {
|
|
|
5999
6274
|
pagesWatcher.on("unlink", schedulePagesRegenerate);
|
|
6000
6275
|
let contractsDebounceTimer;
|
|
6001
6276
|
const pendingChangedPaths = /* @__PURE__ */ new Set();
|
|
6277
|
+
let pendingAddedOrRemoved = false;
|
|
6002
6278
|
const contractsWatcher = chokidar.watch(join16(config.codegen.cwd, config.contracts.glob), {
|
|
6003
6279
|
ignoreInitial: true,
|
|
6004
6280
|
persistent: true,
|
|
6005
6281
|
awaitWriteFinish: { stabilityThreshold: 80, pollInterval: 20 }
|
|
6006
6282
|
});
|
|
6007
|
-
function scheduleContractsRegenerate(changedPath) {
|
|
6283
|
+
function scheduleContractsRegenerate(changedPath, addedOrRemoved = false) {
|
|
6008
6284
|
if (typeof changedPath === "string") pendingChangedPaths.add(changedPath);
|
|
6285
|
+
if (addedOrRemoved) pendingAddedOrRemoved = true;
|
|
6009
6286
|
if (contractsDebounceTimer !== void 0) {
|
|
6010
6287
|
clearTimeout(contractsDebounceTimer);
|
|
6011
6288
|
}
|
|
@@ -6013,8 +6290,12 @@ async function watch(config, onChange, options = {}) {
|
|
|
6013
6290
|
contractsDebounceTimer = void 0;
|
|
6014
6291
|
const changed = [...pendingChangedPaths];
|
|
6015
6292
|
pendingChangedPaths.clear();
|
|
6293
|
+
const filesAddedOrRemoved = pendingAddedOrRemoved;
|
|
6294
|
+
pendingAddedOrRemoved = false;
|
|
6016
6295
|
try {
|
|
6017
|
-
const routes = await (await getDiscovery()).rediscover(changed
|
|
6296
|
+
const routes = await (await getDiscovery()).rediscover(changed, {
|
|
6297
|
+
filesAddedOrRemoved
|
|
6298
|
+
});
|
|
6018
6299
|
lastRoutes = routes;
|
|
6019
6300
|
await generateAndTrack(routes);
|
|
6020
6301
|
} catch (err) {
|
|
@@ -6026,20 +6307,20 @@ async function watch(config, onChange, options = {}) {
|
|
|
6026
6307
|
onChange?.();
|
|
6027
6308
|
}, config.contracts.debounceMs);
|
|
6028
6309
|
}
|
|
6029
|
-
contractsWatcher.on("add", (p) => scheduleContractsRegenerate(p));
|
|
6310
|
+
contractsWatcher.on("add", (p) => scheduleContractsRegenerate(p, true));
|
|
6030
6311
|
contractsWatcher.on("change", (p) => scheduleContractsRegenerate(p));
|
|
6031
|
-
contractsWatcher.on("unlink", (p) => scheduleContractsRegenerate(p));
|
|
6312
|
+
contractsWatcher.on("unlink", (p) => scheduleContractsRegenerate(p, true));
|
|
6032
6313
|
const formsWatcher = chokidar.watch(join16(config.codegen.cwd, config.forms.watch), {
|
|
6033
6314
|
ignoreInitial: true,
|
|
6034
6315
|
persistent: true,
|
|
6035
6316
|
awaitWriteFinish: { stabilityThreshold: 80, pollInterval: 20 }
|
|
6036
6317
|
});
|
|
6037
|
-
formsWatcher.on("add", (p) => scheduleContractsRegenerate(p));
|
|
6318
|
+
formsWatcher.on("add", (p) => scheduleContractsRegenerate(p, true));
|
|
6038
6319
|
formsWatcher.on("change", (p) => scheduleContractsRegenerate(p));
|
|
6039
|
-
formsWatcher.on("unlink", (p) => scheduleContractsRegenerate(p));
|
|
6040
|
-
trackedWatcher.on("add", (p) => scheduleContractsRegenerate(p));
|
|
6320
|
+
formsWatcher.on("unlink", (p) => scheduleContractsRegenerate(p, true));
|
|
6321
|
+
trackedWatcher.on("add", (p) => scheduleContractsRegenerate(p, true));
|
|
6041
6322
|
trackedWatcher.on("change", (p) => scheduleContractsRegenerate(p));
|
|
6042
|
-
trackedWatcher.on("unlink", (p) => scheduleContractsRegenerate(p));
|
|
6323
|
+
trackedWatcher.on("unlink", (p) => scheduleContractsRegenerate(p, true));
|
|
6043
6324
|
return {
|
|
6044
6325
|
close: async () => {
|
|
6045
6326
|
if (pagesDebounceTimer !== void 0) {
|
|
@@ -6143,7 +6424,7 @@ function createChainModuleRenderer(opts) {
|
|
|
6143
6424
|
}
|
|
6144
6425
|
|
|
6145
6426
|
// src/extension/genui-sandbox-kit.ts
|
|
6146
|
-
import { existsSync as existsSync2, statSync } from "fs";
|
|
6427
|
+
import { existsSync as existsSync2, statSync as statSync2 } from "fs";
|
|
6147
6428
|
import { dirname as dirname5, isAbsolute as isAbsolute3, resolve as resolve6 } from "path";
|
|
6148
6429
|
import fg4 from "fast-glob";
|
|
6149
6430
|
var GENUI_KIT_MODULE = "@dudousxd/nestjs-agent-core/genui/kit";
|
|
@@ -6210,7 +6491,7 @@ function resolveKitFilesLocally(root, options) {
|
|
|
6210
6491
|
continue;
|
|
6211
6492
|
}
|
|
6212
6493
|
const path = isAbsolute3(spec) ? spec : resolve6(root, spec);
|
|
6213
|
-
if (existsSync2(path) &&
|
|
6494
|
+
if (existsSync2(path) && statSync2(path).isDirectory()) {
|
|
6214
6495
|
files.push(...fg4.sync("*.{tsx,jsx,ts,js}", { cwd: path, absolute: true, onlyFiles: true }));
|
|
6215
6496
|
dirs.add(path);
|
|
6216
6497
|
} else if (existsSync2(path)) {
|
|
@@ -6295,7 +6576,7 @@ function genuiSandboxKit(options = {}) {
|
|
|
6295
6576
|
}
|
|
6296
6577
|
|
|
6297
6578
|
// src/index.ts
|
|
6298
|
-
var VERSION = "0.29.
|
|
6579
|
+
var VERSION = "0.29.1";
|
|
6299
6580
|
export {
|
|
6300
6581
|
CodegenError,
|
|
6301
6582
|
ConfigError,
|