@dudousxd/nestjs-codegen 0.18.0 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +102 -0
- package/dist/cli/main.cjs +154 -38
- package/dist/cli/main.cjs.map +1 -1
- package/dist/cli/main.js +154 -38
- package/dist/cli/main.js.map +1 -1
- package/dist/index.cjs +154 -38
- 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 +154 -38
- package/dist/index.js.map +1 -1
- package/dist/nest/index.cjs +154 -38
- package/dist/nest/index.cjs.map +1 -1
- package/dist/nest/index.js +154 -38
- package/dist/nest/index.js.map +1 -1
- package/package.json +1 -1
package/dist/nest/index.js
CHANGED
|
@@ -3284,10 +3284,46 @@ function resolveReturnedClass(factoryDecl) {
|
|
|
3284
3284
|
}
|
|
3285
3285
|
return void 0;
|
|
3286
3286
|
}
|
|
3287
|
+
function factoryCalleeName(call) {
|
|
3288
|
+
const callee = unwrapExpression(call.getExpression());
|
|
3289
|
+
if (Node5.isIdentifier(callee)) return callee;
|
|
3290
|
+
if (Node5.isPropertyAccessExpression(callee)) {
|
|
3291
|
+
const name = callee.getNameNode();
|
|
3292
|
+
return Node5.isIdentifier(name) ? name : void 0;
|
|
3293
|
+
}
|
|
3294
|
+
return void 0;
|
|
3295
|
+
}
|
|
3287
3296
|
function resolveFactoryDeclaration(call) {
|
|
3288
|
-
const
|
|
3289
|
-
|
|
3290
|
-
|
|
3297
|
+
const name = factoryCalleeName(call);
|
|
3298
|
+
return name ? resolveFactoryFromName(name, /* @__PURE__ */ new Set()) : void 0;
|
|
3299
|
+
}
|
|
3300
|
+
function resolveFactoryFromName(name, seen) {
|
|
3301
|
+
if (seen.has(name)) return void 0;
|
|
3302
|
+
seen.add(name);
|
|
3303
|
+
const decls = name.getDefinitions().map((d) => d.getDeclarationNode()).filter((n) => n !== void 0);
|
|
3304
|
+
for (const decl of decls) {
|
|
3305
|
+
if (Node5.isFunctionDeclaration(decl) || Node5.isMethodDeclaration(decl)) return decl;
|
|
3306
|
+
if (Node5.isPropertyAssignment(decl)) {
|
|
3307
|
+
const init = decl.getInitializer();
|
|
3308
|
+
const inner = init ? unwrapExpression(init) : void 0;
|
|
3309
|
+
if (inner && Node5.isIdentifier(inner)) {
|
|
3310
|
+
const resolved = resolveFactoryFromName(inner, seen);
|
|
3311
|
+
if (resolved) return resolved;
|
|
3312
|
+
}
|
|
3313
|
+
continue;
|
|
3314
|
+
}
|
|
3315
|
+
if (Node5.isShorthandPropertyAssignment(decl)) {
|
|
3316
|
+
const nameNode = decl.getNameNode();
|
|
3317
|
+
const resolved = Node5.isIdentifier(nameNode) ? resolveFactoryFromName(nameNode, seen) : void 0;
|
|
3318
|
+
if (resolved) return resolved;
|
|
3319
|
+
}
|
|
3320
|
+
}
|
|
3321
|
+
return void 0;
|
|
3322
|
+
}
|
|
3323
|
+
function warnUnresolvedFactory(cls, calleeText, reason) {
|
|
3324
|
+
console.warn(
|
|
3325
|
+
`[nestjs-codegen/fast] ${cls.getName() ?? "<anonymous class>"} in ${cls.getSourceFile().getFilePath()} extends ${calleeText}(...) but ${reason} \u2014 it contributes NO routes to the generated client. Resolvable factory callees: a name (\`factory(...)\`), a namespace or object property (\`ns.factory(...)\`), or a static method (\`Factory.create(...)\`), each resolving to a function or method declaration that returns a class.`
|
|
3326
|
+
);
|
|
3291
3327
|
}
|
|
3292
3328
|
function resolveFactoryStaticClass(node) {
|
|
3293
3329
|
if (!Node5.isPropertyAccessExpression(node)) return void 0;
|
|
@@ -3309,12 +3345,26 @@ function resolveFactoryStaticClass(node) {
|
|
|
3309
3345
|
function resolveInheritedMethods(cls) {
|
|
3310
3346
|
const expr = resolveHeritageCall(cls.getExtends()?.getExpression());
|
|
3311
3347
|
if (!expr) return void 0;
|
|
3312
|
-
const
|
|
3313
|
-
|
|
3348
|
+
const isController = cls.getDecorator("Controller") !== void 0;
|
|
3349
|
+
const calleeText = expr.getExpression().getText();
|
|
3314
3350
|
const factoryDecl = resolveFactoryDeclaration(expr);
|
|
3315
|
-
if (!factoryDecl)
|
|
3351
|
+
if (!factoryDecl) {
|
|
3352
|
+
if (isController) {
|
|
3353
|
+
warnUnresolvedFactory(
|
|
3354
|
+
cls,
|
|
3355
|
+
calleeText,
|
|
3356
|
+
factoryCalleeName(expr) ? "its callee does not resolve to a function or method declaration" : "its callee is not a name that can be resolved statically"
|
|
3357
|
+
);
|
|
3358
|
+
}
|
|
3359
|
+
return void 0;
|
|
3360
|
+
}
|
|
3316
3361
|
const returnedClass = resolveReturnedClass(factoryDecl);
|
|
3317
|
-
if (!returnedClass)
|
|
3362
|
+
if (!returnedClass) {
|
|
3363
|
+
if (isController) {
|
|
3364
|
+
warnUnresolvedFactory(cls, calleeText, "that factory does not return a class declaration");
|
|
3365
|
+
}
|
|
3366
|
+
return void 0;
|
|
3367
|
+
}
|
|
3318
3368
|
const classArgs = [];
|
|
3319
3369
|
const namedClassArgs = {};
|
|
3320
3370
|
for (const arg of expr.getArguments()) {
|
|
@@ -3332,7 +3382,12 @@ function resolveInheritedMethods(cls) {
|
|
|
3332
3382
|
}
|
|
3333
3383
|
return {
|
|
3334
3384
|
methods: returnedClass.getMethods(),
|
|
3335
|
-
|
|
3385
|
+
// The DECLARATION's name, not the call-site text: consumers look the factory
|
|
3386
|
+
// back up by name inside `factoryFilePath`, which a qualified
|
|
3387
|
+
// `tables.createTableController` would never match. For a bare identifier
|
|
3388
|
+
// the two coincide (bar an import alias, where the declaration name is the
|
|
3389
|
+
// one that resolves anyway).
|
|
3390
|
+
factoryName: factoryDecl.getName() ?? calleeText,
|
|
3336
3391
|
factoryFilePath: factoryDecl.getSourceFile().getFilePath(),
|
|
3337
3392
|
classArgs,
|
|
3338
3393
|
namedClassArgs
|
|
@@ -3391,10 +3446,15 @@ function resolveInstantiatedReturnType(cls, methodName) {
|
|
|
3391
3446
|
|
|
3392
3447
|
// src/discovery/filter-for.ts
|
|
3393
3448
|
function resolveMixinEntityClass(mixin, project) {
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
return
|
|
3449
|
+
return resolveClassRef(mixin?.namedClassArgs?.entity ?? mixin?.classArgs[0], project);
|
|
3450
|
+
}
|
|
3451
|
+
function resolveMixinFilterClass(mixin, project) {
|
|
3452
|
+
return resolveClassRef(mixin?.namedClassArgs?.filter, project);
|
|
3453
|
+
}
|
|
3454
|
+
function resolveClassRef(ref, project) {
|
|
3455
|
+
if (!ref) return void 0;
|
|
3456
|
+
const file = project.getSourceFile(ref.filePath) ?? project.addSourceFileAtPathIfExists(ref.filePath);
|
|
3457
|
+
return file?.getClass(ref.name);
|
|
3398
3458
|
}
|
|
3399
3459
|
function classifyFilterForHint(typeInit) {
|
|
3400
3460
|
if (Node6.isStringLiteral(typeInit)) {
|
|
@@ -3494,31 +3554,55 @@ function extractApplyFilterInfo(method, sourceFile, project, mixin) {
|
|
|
3494
3554
|
}
|
|
3495
3555
|
const filterClassName = filterClassArg.getText();
|
|
3496
3556
|
const resolved = factoryStaticClass ? void 0 : findType(filterClassName, declFile, project);
|
|
3497
|
-
const
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
|
|
3506
|
-
|
|
3507
|
-
byName.set(key, toFilterFieldType(key, classified));
|
|
3508
|
-
}
|
|
3509
|
-
fieldTypes = [...byName.values()];
|
|
3510
|
-
}
|
|
3511
|
-
if (fieldTypes.length === 0) return null;
|
|
3512
|
-
const fieldNames = fieldTypes.map((f) => f.name);
|
|
3557
|
+
const declaredClass = factoryStaticClass ?? (resolved?.kind === "class" ? resolved.decl : resolveLocalClassDeclaration(filterClassArg));
|
|
3558
|
+
const ownRoute = !mixin || declFile.getFilePath() !== mixin.factoryFilePath;
|
|
3559
|
+
const namedByRoute = ownRoute && Node6.isIdentifier(filterClassArg) ? declaredClass : void 0;
|
|
3560
|
+
for (const candidate of orderFilterCandidates({
|
|
3561
|
+
namedByRoute,
|
|
3562
|
+
supplied: resolveMixinFilterClass(mixin, project),
|
|
3563
|
+
declared: declaredClass
|
|
3564
|
+
})) {
|
|
3565
|
+
const fieldTypes = collectFilterFields(candidate, project, mixinEntity);
|
|
3566
|
+
if (fieldTypes.length === 0) continue;
|
|
3513
3567
|
return {
|
|
3514
|
-
fieldNames,
|
|
3568
|
+
fieldNames: fieldTypes.map((f) => f.name),
|
|
3515
3569
|
fieldTypes,
|
|
3516
3570
|
source
|
|
3517
3571
|
};
|
|
3518
3572
|
}
|
|
3573
|
+
if (declaredClass) return null;
|
|
3519
3574
|
}
|
|
3520
3575
|
return null;
|
|
3521
3576
|
}
|
|
3577
|
+
function orderFilterCandidates(sources) {
|
|
3578
|
+
const ordered = [];
|
|
3579
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3580
|
+
const push = (decl, preferDeclaredEntity) => {
|
|
3581
|
+
if (!decl || seen.has(decl)) return;
|
|
3582
|
+
seen.add(decl);
|
|
3583
|
+
ordered.push({ decl, preferDeclaredEntity });
|
|
3584
|
+
};
|
|
3585
|
+
push(sources.namedByRoute, true);
|
|
3586
|
+
push(sources.supplied, true);
|
|
3587
|
+
push(sources.declared, false);
|
|
3588
|
+
return ordered;
|
|
3589
|
+
}
|
|
3590
|
+
function collectFilterFields(candidate, project, mixinEntity) {
|
|
3591
|
+
const { decl, preferDeclaredEntity } = candidate;
|
|
3592
|
+
let fieldTypes = extractClassPropertyTypes(decl, project);
|
|
3593
|
+
if (fieldTypes.length === 0) {
|
|
3594
|
+
fieldTypes = extractFilterableEntityFields(decl, project, mixinEntity, preferDeclaredEntity);
|
|
3595
|
+
}
|
|
3596
|
+
const filterForHints = extractFilterForHints(decl, project);
|
|
3597
|
+
if (filterForHints.size > 0) {
|
|
3598
|
+
const byName = new Map(fieldTypes.map((f) => [f.name, f]));
|
|
3599
|
+
for (const [key, classified] of filterForHints) {
|
|
3600
|
+
byName.set(key, toFilterFieldType(key, classified));
|
|
3601
|
+
}
|
|
3602
|
+
fieldTypes = [...byName.values()];
|
|
3603
|
+
}
|
|
3604
|
+
return fieldTypes;
|
|
3605
|
+
}
|
|
3522
3606
|
var RELATION_DECORATORS = /* @__PURE__ */ new Set(["OneToMany", "ManyToOne", "ManyToMany", "OneToOne"]);
|
|
3523
3607
|
function collectEntityFields(entityDecl, sourceFile, project, prefix, visited) {
|
|
3524
3608
|
const entityName = entityDecl.getName() ?? "";
|
|
@@ -3597,21 +3681,53 @@ function resolveDeclaredEntity(optionsArg, filterClass, project) {
|
|
|
3597
3681
|
if (!resolved || resolved.kind !== "class") return void 0;
|
|
3598
3682
|
return resolved.decl;
|
|
3599
3683
|
}
|
|
3600
|
-
function
|
|
3684
|
+
function readFieldNameList(optionsArg, key) {
|
|
3685
|
+
if (!Node6.isObjectLiteralExpression(optionsArg)) return void 0;
|
|
3686
|
+
const prop = optionsArg.getProperty(key);
|
|
3687
|
+
if (!prop || !Node6.isPropertyAssignment(prop)) return void 0;
|
|
3688
|
+
const init = prop.getInitializer();
|
|
3689
|
+
if (!init || !Node6.isArrayLiteralExpression(init)) return void 0;
|
|
3690
|
+
const names = /* @__PURE__ */ new Set();
|
|
3691
|
+
for (const el of init.getElements()) {
|
|
3692
|
+
if (Node6.isStringLiteral(el)) {
|
|
3693
|
+
names.add(el.getLiteralValue());
|
|
3694
|
+
continue;
|
|
3695
|
+
}
|
|
3696
|
+
if (Node6.isObjectLiteralExpression(el)) {
|
|
3697
|
+
const fieldProp = el.getProperty("field");
|
|
3698
|
+
if (fieldProp && Node6.isPropertyAssignment(fieldProp)) {
|
|
3699
|
+
const fieldInit = fieldProp.getInitializer();
|
|
3700
|
+
if (fieldInit && Node6.isStringLiteral(fieldInit)) {
|
|
3701
|
+
names.add(fieldInit.getLiteralValue());
|
|
3702
|
+
continue;
|
|
3703
|
+
}
|
|
3704
|
+
}
|
|
3705
|
+
}
|
|
3706
|
+
return void 0;
|
|
3707
|
+
}
|
|
3708
|
+
return names;
|
|
3709
|
+
}
|
|
3710
|
+
function narrowToDeclaredFields(fields, optionsArg) {
|
|
3711
|
+
const allowed = readFieldNameList(optionsArg, "allowed");
|
|
3712
|
+
const blocked = readFieldNameList(optionsArg, "blocked");
|
|
3713
|
+
if (!allowed && !blocked) return fields;
|
|
3714
|
+
return fields.filter(
|
|
3715
|
+
(f) => (!allowed || allowed.has(f.name)) && !(blocked?.has(f.name) ?? false)
|
|
3716
|
+
);
|
|
3717
|
+
}
|
|
3718
|
+
function extractFilterableEntityFields(filterClass, project, entityOverride, preferDeclaredEntity = false) {
|
|
3601
3719
|
const filterableDecorator = filterClass.getDecorators().find((d) => d.getName() === "Filterable");
|
|
3602
3720
|
if (!filterableDecorator) return [];
|
|
3603
3721
|
const args = filterableDecorator.getArguments();
|
|
3604
3722
|
if (args.length === 0) return [];
|
|
3605
3723
|
const optionsArg = args[0];
|
|
3606
3724
|
if (!Node6.isObjectLiteralExpression(optionsArg)) return [];
|
|
3607
|
-
const
|
|
3725
|
+
const declaredEntity = resolveDeclaredEntity(optionsArg, filterClass, project);
|
|
3726
|
+
const entityDecl = preferDeclaredEntity ? declaredEntity ?? entityOverride : entityOverride ?? declaredEntity;
|
|
3608
3727
|
if (!entityDecl) return [];
|
|
3609
|
-
const fields =
|
|
3610
|
-
entityDecl,
|
|
3611
|
-
|
|
3612
|
-
project,
|
|
3613
|
-
"",
|
|
3614
|
-
/* @__PURE__ */ new Set()
|
|
3728
|
+
const fields = narrowToDeclaredFields(
|
|
3729
|
+
collectEntityFields(entityDecl, entityDecl.getSourceFile(), project, "", /* @__PURE__ */ new Set()),
|
|
3730
|
+
optionsArg
|
|
3615
3731
|
);
|
|
3616
3732
|
const relationsDecorator = filterClass.getDecorators().find((d) => d.getName() === "Relations");
|
|
3617
3733
|
if (relationsDecorator) {
|
|
@@ -4857,7 +4973,7 @@ async function watch(config, onChange, options = {}) {
|
|
|
4857
4973
|
}
|
|
4858
4974
|
|
|
4859
4975
|
// src/index.ts
|
|
4860
|
-
var VERSION = "0.
|
|
4976
|
+
var VERSION = "0.20.0";
|
|
4861
4977
|
|
|
4862
4978
|
// src/generate-manifest.ts
|
|
4863
4979
|
var MANIFEST_FILE = ".codegen-manifest.json";
|