@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/index.d.cts
CHANGED
|
@@ -382,6 +382,6 @@ interface FastDiscoveryOptions {
|
|
|
382
382
|
}
|
|
383
383
|
declare function discoverContractsFast(opts: FastDiscoveryOptions): Promise<RouteDescriptor[]>;
|
|
384
384
|
|
|
385
|
-
declare const VERSION = "0.
|
|
385
|
+
declare const VERSION = "0.20.0";
|
|
386
386
|
|
|
387
387
|
export { type ChainModuleRendererOptions, CodegenError, type CodegenManifest, ConfigError, DriftGuardError, type EntryPoint, type FastDiscoveryOptions, type JsonSchema, type MocksEmitOptions, type OpenApiDocument, type OpenApiEmitOptions, type OpenApiInfo, RenderContext, RenderedModule, ResolvedConfig, RouteDescriptor, SchemaModule, SchemaNode, type TsTypeContext, UserConfig, VERSION, ValidationAdapter, type WatchOptions, type Watcher, acquireLock, buildMocksFile, buildOpenApiSpec, createChainModuleRenderer, defineConfig, discoverContractsFast, emitApi, emitForms, emitMocks, emitOpenApi, emitRoutes, extractSchemaFromDto, generate, loadConfig, renderTsType, resolveConfig, schemaModuleToJsonSchema, schemaNodeToJsonSchema, toObjectKey, typeNameFor, watch };
|
package/dist/index.d.ts
CHANGED
|
@@ -382,6 +382,6 @@ interface FastDiscoveryOptions {
|
|
|
382
382
|
}
|
|
383
383
|
declare function discoverContractsFast(opts: FastDiscoveryOptions): Promise<RouteDescriptor[]>;
|
|
384
384
|
|
|
385
|
-
declare const VERSION = "0.
|
|
385
|
+
declare const VERSION = "0.20.0";
|
|
386
386
|
|
|
387
387
|
export { type ChainModuleRendererOptions, CodegenError, type CodegenManifest, ConfigError, DriftGuardError, type EntryPoint, type FastDiscoveryOptions, type JsonSchema, type MocksEmitOptions, type OpenApiDocument, type OpenApiEmitOptions, type OpenApiInfo, RenderContext, RenderedModule, ResolvedConfig, RouteDescriptor, SchemaModule, SchemaNode, type TsTypeContext, UserConfig, VERSION, ValidationAdapter, type WatchOptions, type Watcher, acquireLock, buildMocksFile, buildOpenApiSpec, createChainModuleRenderer, defineConfig, discoverContractsFast, emitApi, emitForms, emitMocks, emitOpenApi, emitRoutes, extractSchemaFromDto, generate, loadConfig, renderTsType, resolveConfig, schemaModuleToJsonSchema, schemaNodeToJsonSchema, toObjectKey, typeNameFor, watch };
|
package/dist/index.js
CHANGED
|
@@ -3480,10 +3480,46 @@ function resolveReturnedClass(factoryDecl) {
|
|
|
3480
3480
|
}
|
|
3481
3481
|
return void 0;
|
|
3482
3482
|
}
|
|
3483
|
+
function factoryCalleeName(call) {
|
|
3484
|
+
const callee = unwrapExpression(call.getExpression());
|
|
3485
|
+
if (Node5.isIdentifier(callee)) return callee;
|
|
3486
|
+
if (Node5.isPropertyAccessExpression(callee)) {
|
|
3487
|
+
const name = callee.getNameNode();
|
|
3488
|
+
return Node5.isIdentifier(name) ? name : void 0;
|
|
3489
|
+
}
|
|
3490
|
+
return void 0;
|
|
3491
|
+
}
|
|
3483
3492
|
function resolveFactoryDeclaration(call) {
|
|
3484
|
-
const
|
|
3485
|
-
|
|
3486
|
-
|
|
3493
|
+
const name = factoryCalleeName(call);
|
|
3494
|
+
return name ? resolveFactoryFromName(name, /* @__PURE__ */ new Set()) : void 0;
|
|
3495
|
+
}
|
|
3496
|
+
function resolveFactoryFromName(name, seen) {
|
|
3497
|
+
if (seen.has(name)) return void 0;
|
|
3498
|
+
seen.add(name);
|
|
3499
|
+
const decls = name.getDefinitions().map((d) => d.getDeclarationNode()).filter((n) => n !== void 0);
|
|
3500
|
+
for (const decl of decls) {
|
|
3501
|
+
if (Node5.isFunctionDeclaration(decl) || Node5.isMethodDeclaration(decl)) return decl;
|
|
3502
|
+
if (Node5.isPropertyAssignment(decl)) {
|
|
3503
|
+
const init = decl.getInitializer();
|
|
3504
|
+
const inner = init ? unwrapExpression(init) : void 0;
|
|
3505
|
+
if (inner && Node5.isIdentifier(inner)) {
|
|
3506
|
+
const resolved = resolveFactoryFromName(inner, seen);
|
|
3507
|
+
if (resolved) return resolved;
|
|
3508
|
+
}
|
|
3509
|
+
continue;
|
|
3510
|
+
}
|
|
3511
|
+
if (Node5.isShorthandPropertyAssignment(decl)) {
|
|
3512
|
+
const nameNode = decl.getNameNode();
|
|
3513
|
+
const resolved = Node5.isIdentifier(nameNode) ? resolveFactoryFromName(nameNode, seen) : void 0;
|
|
3514
|
+
if (resolved) return resolved;
|
|
3515
|
+
}
|
|
3516
|
+
}
|
|
3517
|
+
return void 0;
|
|
3518
|
+
}
|
|
3519
|
+
function warnUnresolvedFactory(cls, calleeText, reason) {
|
|
3520
|
+
console.warn(
|
|
3521
|
+
`[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.`
|
|
3522
|
+
);
|
|
3487
3523
|
}
|
|
3488
3524
|
function resolveFactoryStaticClass(node) {
|
|
3489
3525
|
if (!Node5.isPropertyAccessExpression(node)) return void 0;
|
|
@@ -3505,12 +3541,26 @@ function resolveFactoryStaticClass(node) {
|
|
|
3505
3541
|
function resolveInheritedMethods(cls) {
|
|
3506
3542
|
const expr = resolveHeritageCall(cls.getExtends()?.getExpression());
|
|
3507
3543
|
if (!expr) return void 0;
|
|
3508
|
-
const
|
|
3509
|
-
|
|
3544
|
+
const isController = cls.getDecorator("Controller") !== void 0;
|
|
3545
|
+
const calleeText = expr.getExpression().getText();
|
|
3510
3546
|
const factoryDecl = resolveFactoryDeclaration(expr);
|
|
3511
|
-
if (!factoryDecl)
|
|
3547
|
+
if (!factoryDecl) {
|
|
3548
|
+
if (isController) {
|
|
3549
|
+
warnUnresolvedFactory(
|
|
3550
|
+
cls,
|
|
3551
|
+
calleeText,
|
|
3552
|
+
factoryCalleeName(expr) ? "its callee does not resolve to a function or method declaration" : "its callee is not a name that can be resolved statically"
|
|
3553
|
+
);
|
|
3554
|
+
}
|
|
3555
|
+
return void 0;
|
|
3556
|
+
}
|
|
3512
3557
|
const returnedClass = resolveReturnedClass(factoryDecl);
|
|
3513
|
-
if (!returnedClass)
|
|
3558
|
+
if (!returnedClass) {
|
|
3559
|
+
if (isController) {
|
|
3560
|
+
warnUnresolvedFactory(cls, calleeText, "that factory does not return a class declaration");
|
|
3561
|
+
}
|
|
3562
|
+
return void 0;
|
|
3563
|
+
}
|
|
3514
3564
|
const classArgs = [];
|
|
3515
3565
|
const namedClassArgs = {};
|
|
3516
3566
|
for (const arg of expr.getArguments()) {
|
|
@@ -3528,7 +3578,12 @@ function resolveInheritedMethods(cls) {
|
|
|
3528
3578
|
}
|
|
3529
3579
|
return {
|
|
3530
3580
|
methods: returnedClass.getMethods(),
|
|
3531
|
-
|
|
3581
|
+
// The DECLARATION's name, not the call-site text: consumers look the factory
|
|
3582
|
+
// back up by name inside `factoryFilePath`, which a qualified
|
|
3583
|
+
// `tables.createTableController` would never match. For a bare identifier
|
|
3584
|
+
// the two coincide (bar an import alias, where the declaration name is the
|
|
3585
|
+
// one that resolves anyway).
|
|
3586
|
+
factoryName: factoryDecl.getName() ?? calleeText,
|
|
3532
3587
|
factoryFilePath: factoryDecl.getSourceFile().getFilePath(),
|
|
3533
3588
|
classArgs,
|
|
3534
3589
|
namedClassArgs
|
|
@@ -3587,10 +3642,15 @@ function resolveInstantiatedReturnType(cls, methodName) {
|
|
|
3587
3642
|
|
|
3588
3643
|
// src/discovery/filter-for.ts
|
|
3589
3644
|
function resolveMixinEntityClass(mixin, project) {
|
|
3590
|
-
|
|
3591
|
-
|
|
3592
|
-
|
|
3593
|
-
return
|
|
3645
|
+
return resolveClassRef(mixin?.namedClassArgs?.entity ?? mixin?.classArgs[0], project);
|
|
3646
|
+
}
|
|
3647
|
+
function resolveMixinFilterClass(mixin, project) {
|
|
3648
|
+
return resolveClassRef(mixin?.namedClassArgs?.filter, project);
|
|
3649
|
+
}
|
|
3650
|
+
function resolveClassRef(ref, project) {
|
|
3651
|
+
if (!ref) return void 0;
|
|
3652
|
+
const file = project.getSourceFile(ref.filePath) ?? project.addSourceFileAtPathIfExists(ref.filePath);
|
|
3653
|
+
return file?.getClass(ref.name);
|
|
3594
3654
|
}
|
|
3595
3655
|
function classifyFilterForHint(typeInit) {
|
|
3596
3656
|
if (Node6.isStringLiteral(typeInit)) {
|
|
@@ -3690,31 +3750,55 @@ function extractApplyFilterInfo(method, sourceFile, project, mixin) {
|
|
|
3690
3750
|
}
|
|
3691
3751
|
const filterClassName = filterClassArg.getText();
|
|
3692
3752
|
const resolved = factoryStaticClass ? void 0 : findType(filterClassName, declFile, project);
|
|
3693
|
-
const
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
3700
|
-
|
|
3701
|
-
|
|
3702
|
-
|
|
3703
|
-
byName.set(key, toFilterFieldType(key, classified));
|
|
3704
|
-
}
|
|
3705
|
-
fieldTypes = [...byName.values()];
|
|
3706
|
-
}
|
|
3707
|
-
if (fieldTypes.length === 0) return null;
|
|
3708
|
-
const fieldNames = fieldTypes.map((f) => f.name);
|
|
3753
|
+
const declaredClass = factoryStaticClass ?? (resolved?.kind === "class" ? resolved.decl : resolveLocalClassDeclaration(filterClassArg));
|
|
3754
|
+
const ownRoute = !mixin || declFile.getFilePath() !== mixin.factoryFilePath;
|
|
3755
|
+
const namedByRoute = ownRoute && Node6.isIdentifier(filterClassArg) ? declaredClass : void 0;
|
|
3756
|
+
for (const candidate of orderFilterCandidates({
|
|
3757
|
+
namedByRoute,
|
|
3758
|
+
supplied: resolveMixinFilterClass(mixin, project),
|
|
3759
|
+
declared: declaredClass
|
|
3760
|
+
})) {
|
|
3761
|
+
const fieldTypes = collectFilterFields(candidate, project, mixinEntity);
|
|
3762
|
+
if (fieldTypes.length === 0) continue;
|
|
3709
3763
|
return {
|
|
3710
|
-
fieldNames,
|
|
3764
|
+
fieldNames: fieldTypes.map((f) => f.name),
|
|
3711
3765
|
fieldTypes,
|
|
3712
3766
|
source
|
|
3713
3767
|
};
|
|
3714
3768
|
}
|
|
3769
|
+
if (declaredClass) return null;
|
|
3715
3770
|
}
|
|
3716
3771
|
return null;
|
|
3717
3772
|
}
|
|
3773
|
+
function orderFilterCandidates(sources) {
|
|
3774
|
+
const ordered = [];
|
|
3775
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3776
|
+
const push = (decl, preferDeclaredEntity) => {
|
|
3777
|
+
if (!decl || seen.has(decl)) return;
|
|
3778
|
+
seen.add(decl);
|
|
3779
|
+
ordered.push({ decl, preferDeclaredEntity });
|
|
3780
|
+
};
|
|
3781
|
+
push(sources.namedByRoute, true);
|
|
3782
|
+
push(sources.supplied, true);
|
|
3783
|
+
push(sources.declared, false);
|
|
3784
|
+
return ordered;
|
|
3785
|
+
}
|
|
3786
|
+
function collectFilterFields(candidate, project, mixinEntity) {
|
|
3787
|
+
const { decl, preferDeclaredEntity } = candidate;
|
|
3788
|
+
let fieldTypes = extractClassPropertyTypes(decl, project);
|
|
3789
|
+
if (fieldTypes.length === 0) {
|
|
3790
|
+
fieldTypes = extractFilterableEntityFields(decl, project, mixinEntity, preferDeclaredEntity);
|
|
3791
|
+
}
|
|
3792
|
+
const filterForHints = extractFilterForHints(decl, project);
|
|
3793
|
+
if (filterForHints.size > 0) {
|
|
3794
|
+
const byName = new Map(fieldTypes.map((f) => [f.name, f]));
|
|
3795
|
+
for (const [key, classified] of filterForHints) {
|
|
3796
|
+
byName.set(key, toFilterFieldType(key, classified));
|
|
3797
|
+
}
|
|
3798
|
+
fieldTypes = [...byName.values()];
|
|
3799
|
+
}
|
|
3800
|
+
return fieldTypes;
|
|
3801
|
+
}
|
|
3718
3802
|
var RELATION_DECORATORS = /* @__PURE__ */ new Set(["OneToMany", "ManyToOne", "ManyToMany", "OneToOne"]);
|
|
3719
3803
|
function collectEntityFields(entityDecl, sourceFile, project, prefix, visited) {
|
|
3720
3804
|
const entityName = entityDecl.getName() ?? "";
|
|
@@ -3793,21 +3877,53 @@ function resolveDeclaredEntity(optionsArg, filterClass, project) {
|
|
|
3793
3877
|
if (!resolved || resolved.kind !== "class") return void 0;
|
|
3794
3878
|
return resolved.decl;
|
|
3795
3879
|
}
|
|
3796
|
-
function
|
|
3880
|
+
function readFieldNameList(optionsArg, key) {
|
|
3881
|
+
if (!Node6.isObjectLiteralExpression(optionsArg)) return void 0;
|
|
3882
|
+
const prop = optionsArg.getProperty(key);
|
|
3883
|
+
if (!prop || !Node6.isPropertyAssignment(prop)) return void 0;
|
|
3884
|
+
const init = prop.getInitializer();
|
|
3885
|
+
if (!init || !Node6.isArrayLiteralExpression(init)) return void 0;
|
|
3886
|
+
const names = /* @__PURE__ */ new Set();
|
|
3887
|
+
for (const el of init.getElements()) {
|
|
3888
|
+
if (Node6.isStringLiteral(el)) {
|
|
3889
|
+
names.add(el.getLiteralValue());
|
|
3890
|
+
continue;
|
|
3891
|
+
}
|
|
3892
|
+
if (Node6.isObjectLiteralExpression(el)) {
|
|
3893
|
+
const fieldProp = el.getProperty("field");
|
|
3894
|
+
if (fieldProp && Node6.isPropertyAssignment(fieldProp)) {
|
|
3895
|
+
const fieldInit = fieldProp.getInitializer();
|
|
3896
|
+
if (fieldInit && Node6.isStringLiteral(fieldInit)) {
|
|
3897
|
+
names.add(fieldInit.getLiteralValue());
|
|
3898
|
+
continue;
|
|
3899
|
+
}
|
|
3900
|
+
}
|
|
3901
|
+
}
|
|
3902
|
+
return void 0;
|
|
3903
|
+
}
|
|
3904
|
+
return names;
|
|
3905
|
+
}
|
|
3906
|
+
function narrowToDeclaredFields(fields, optionsArg) {
|
|
3907
|
+
const allowed = readFieldNameList(optionsArg, "allowed");
|
|
3908
|
+
const blocked = readFieldNameList(optionsArg, "blocked");
|
|
3909
|
+
if (!allowed && !blocked) return fields;
|
|
3910
|
+
return fields.filter(
|
|
3911
|
+
(f) => (!allowed || allowed.has(f.name)) && !(blocked?.has(f.name) ?? false)
|
|
3912
|
+
);
|
|
3913
|
+
}
|
|
3914
|
+
function extractFilterableEntityFields(filterClass, project, entityOverride, preferDeclaredEntity = false) {
|
|
3797
3915
|
const filterableDecorator = filterClass.getDecorators().find((d) => d.getName() === "Filterable");
|
|
3798
3916
|
if (!filterableDecorator) return [];
|
|
3799
3917
|
const args = filterableDecorator.getArguments();
|
|
3800
3918
|
if (args.length === 0) return [];
|
|
3801
3919
|
const optionsArg = args[0];
|
|
3802
3920
|
if (!Node6.isObjectLiteralExpression(optionsArg)) return [];
|
|
3803
|
-
const
|
|
3921
|
+
const declaredEntity = resolveDeclaredEntity(optionsArg, filterClass, project);
|
|
3922
|
+
const entityDecl = preferDeclaredEntity ? declaredEntity ?? entityOverride : entityOverride ?? declaredEntity;
|
|
3804
3923
|
if (!entityDecl) return [];
|
|
3805
|
-
const fields =
|
|
3806
|
-
entityDecl,
|
|
3807
|
-
|
|
3808
|
-
project,
|
|
3809
|
-
"",
|
|
3810
|
-
/* @__PURE__ */ new Set()
|
|
3924
|
+
const fields = narrowToDeclaredFields(
|
|
3925
|
+
collectEntityFields(entityDecl, entityDecl.getSourceFile(), project, "", /* @__PURE__ */ new Set()),
|
|
3926
|
+
optionsArg
|
|
3811
3927
|
);
|
|
3812
3928
|
const relationsDecorator = filterClass.getDecorators().find((d) => d.getName() === "Relations");
|
|
3813
3929
|
if (relationsDecorator) {
|
|
@@ -5155,7 +5271,7 @@ function createChainModuleRenderer(opts) {
|
|
|
5155
5271
|
}
|
|
5156
5272
|
|
|
5157
5273
|
// src/index.ts
|
|
5158
|
-
var VERSION = "0.
|
|
5274
|
+
var VERSION = "0.20.0";
|
|
5159
5275
|
export {
|
|
5160
5276
|
CodegenError,
|
|
5161
5277
|
ConfigError,
|