@dudousxd/nestjs-codegen 0.23.0 → 0.25.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 +34 -0
- package/dist/cli/main.cjs +49 -9
- package/dist/cli/main.cjs.map +1 -1
- package/dist/cli/main.js +49 -9
- package/dist/cli/main.js.map +1 -1
- package/dist/extension/index.d.cts +1 -1
- package/dist/extension/index.d.ts +1 -1
- package/dist/{index-BsptKWwz.d.cts → index-Ce3YnfwS.d.cts} +19 -0
- package/dist/{index-BsptKWwz.d.ts → index-Ce3YnfwS.d.ts} +19 -0
- package/dist/index.cjs +49 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +49 -9
- package/dist/index.js.map +1 -1
- package/dist/nest/index.cjs +49 -9
- package/dist/nest/index.cjs.map +1 -1
- package/dist/nest/index.d.cts +1 -1
- package/dist/nest/index.d.ts +1 -1
- package/dist/nest/index.js +49 -9
- package/dist/nest/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,39 @@
|
|
|
1
1
|
# @dudousxd/nestjs-codegen
|
|
2
2
|
|
|
3
|
+
## 0.25.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 595c4b1: Follow a factory-produced controller's own heritage chain, so a factory that wraps a factory contributes every level's routes.
|
|
8
|
+
|
|
9
|
+
`class C extends createTableController(...)` was resolved one level deep: discovery found the class the factory returns and read **its own methods only**. A factory whose returned class itself extends something — another factory call, or an ordinary base class — lost everything the inner level declared. The controller was not skipped, which would at least be visible; it was generated with a subset of its routes and no warning anywhere, while Nest served all of them.
|
|
10
|
+
|
|
11
|
+
That gap made the natural way to give SOME controllers an extra route unusable. Wrapping the shared factory in a second one and declaring the extra route as an ordinary `@Post('export')` method is the shape that keeps every route statically visible — the conditionality becomes which factory a controller extends — but the wrapper's own base routes disappeared from the client, so the pattern looked broken and the alternative (declaring the handler undecorated and mounting it imperatively, `Post('export')(proto, 'export', descriptor)`) is invisible to a static scan by construction.
|
|
12
|
+
|
|
13
|
+
Discovery now walks the returned class's chain to any depth, the way Nest walks the prototype chain, resolving each base through the same factory resolution or as a plain class declaration. Nearest declaration wins, so a wrapper overriding an inner route still contributes one route rather than two — matching how a derived controller's own override was already resolved against its base.
|
|
14
|
+
|
|
15
|
+
Also fixes the types of an inherited route. A route's parameter and return annotations were resolved against the CONTROLLER's file, but they are written in the file that declares the handler — the factory's. A `@Body() body: ExportRequestDto` on a factory-declared method resolved against a file that never imports `ExportRequestDto` and silently degraded to `unknown`, so the route reached the client accepting anything. They now resolve in the declaring file, which is what the filter pass already did. For a route declared on the controller itself the two files are the same and nothing changes.
|
|
16
|
+
|
|
17
|
+
Both are additive: routes and types that were missing now appear. Regenerate and expect new entries for any controller extending a wrapping factory, and real body/query/response types where an inherited route previously had `unknown`.
|
|
18
|
+
|
|
19
|
+
## 0.24.0
|
|
20
|
+
|
|
21
|
+
### Minor Changes
|
|
22
|
+
|
|
23
|
+
- c8d7eec: A mapped column's two declared types can disagree, so both are now emitted.
|
|
24
|
+
|
|
25
|
+
**If you upgraded to 0.23.0, you were affected** wherever an entity declares a mapped column — `@Property({ columnType: 'date', type: DateType }) x?: Opt<string>`, or a DECIMAL read back as a string. Those fields kept being emitted, but with the wrong kind, so every union a client derives from it rejected them: `.lt('serviceEndDate', …)` stopped compiling on a column that had been orderable all along.
|
|
26
|
+
|
|
27
|
+
The cause was the brand unwrapping itself. `classifyFieldType` consults the column decorator ONLY when the TS type resolves to `unknown` — so before 0.23.0 an `Opt<string>` fell through to `columnType: 'date'` and classified `date`, correctly and by accident. Making the TS side resolve meant the decorator was never reached.
|
|
28
|
+
|
|
29
|
+
The fix is not to pick a winner, because both are true and each is needed for a different question. `kind` now carries what the COLUMN is — the semantics an operator set derives from — and a new optional `valueKind` carries what the VALUE is, when they differ. A DATE column read back as `'YYYY-MM-DD'` emits `kind: 'date'` and `valueKind: 'string'`.
|
|
30
|
+
|
|
31
|
+
Collapsing them loses one or the other. Answer `string` and the field stops accepting the ordering and range operators the column supports. Answer `date` and the emitted type promises a `Date` the value never holds — which a type-preserving wire format like superjson then contradicts at runtime, since it faithfully transports the string that is actually there. That second failure predates 0.23.0 and is fixed here too: these columns used to emit as `Date` while carrying a string.
|
|
32
|
+
|
|
33
|
+
`valueKind` is absent when the two agree, which is the overwhelming majority of columns, so nothing changes for them.
|
|
34
|
+
|
|
35
|
+
Also teaches the decorator reader `columnType` (MikroORM's raw DDL slot) alongside `type`, and a mapped-type class (`type: DateType`) alongside a keyword string. It read neither, which is why the conflict was invisible from that side.
|
|
36
|
+
|
|
3
37
|
## 0.23.0
|
|
4
38
|
|
|
5
39
|
### Minor Changes
|
package/dist/cli/main.cjs
CHANGED
|
@@ -1503,12 +1503,19 @@ function classifyFromColumnDecorator(prop, sourceFile, project) {
|
|
|
1503
1503
|
return { kind: "string" };
|
|
1504
1504
|
}
|
|
1505
1505
|
}
|
|
1506
|
-
const
|
|
1507
|
-
|
|
1506
|
+
for (const key of ["columnType", "type"]) {
|
|
1507
|
+
const typeProp = arg.getProperty(key);
|
|
1508
|
+
if (!typeProp || !import_ts_morph4.Node.isPropertyAssignment(typeProp)) continue;
|
|
1508
1509
|
const init = typeProp.getInitializer();
|
|
1509
|
-
if (init
|
|
1510
|
+
if (!init) continue;
|
|
1511
|
+
if (import_ts_morph4.Node.isStringLiteral(init)) {
|
|
1510
1512
|
const kind = classifyTypeKeyword(init.getLiteralValue());
|
|
1511
1513
|
if (kind) return { kind };
|
|
1514
|
+
continue;
|
|
1515
|
+
}
|
|
1516
|
+
if (import_ts_morph4.Node.isIdentifier(init)) {
|
|
1517
|
+
const kind = classifyTypeKeyword(init.getText());
|
|
1518
|
+
if (kind) return { kind };
|
|
1512
1519
|
}
|
|
1513
1520
|
}
|
|
1514
1521
|
}
|
|
@@ -1520,12 +1527,18 @@ function classifyFromColumnDecorator(prop, sourceFile, project) {
|
|
|
1520
1527
|
function classifyFieldType(prop, sourceFile, project) {
|
|
1521
1528
|
let nullable = prop.hasQuestionToken();
|
|
1522
1529
|
const typeNode = prop.getTypeNode();
|
|
1530
|
+
const fromDecorator = classifyFromColumnDecorator(prop, sourceFile, project);
|
|
1523
1531
|
if (typeNode) {
|
|
1524
1532
|
const r = classifyTypeNode(typeNode, sourceFile, project);
|
|
1525
1533
|
if (r.nullable) nullable = true;
|
|
1526
|
-
if (r.kind !== "unknown")
|
|
1534
|
+
if (r.kind !== "unknown") {
|
|
1535
|
+
const conflicts = fromDecorator !== null && fromDecorator.kind !== "unknown" && fromDecorator.kind !== r.kind;
|
|
1536
|
+
if (conflicts) {
|
|
1537
|
+
return markNullable({ ...fromDecorator, valueKind: r.kind }, nullable);
|
|
1538
|
+
}
|
|
1539
|
+
return markNullable(r, nullable);
|
|
1540
|
+
}
|
|
1527
1541
|
}
|
|
1528
|
-
const fromDecorator = classifyFromColumnDecorator(prop, sourceFile, project);
|
|
1529
1542
|
if (fromDecorator) {
|
|
1530
1543
|
return markNullable(fromDecorator, nullable || fromDecorator.nullable === true);
|
|
1531
1544
|
}
|
|
@@ -1533,6 +1546,7 @@ function classifyFieldType(prop, sourceFile, project) {
|
|
|
1533
1546
|
}
|
|
1534
1547
|
function toFilterFieldType(name, r) {
|
|
1535
1548
|
const ft = { name, kind: r.kind };
|
|
1549
|
+
if (r.valueKind && r.valueKind !== r.kind) ft.valueKind = r.valueKind;
|
|
1536
1550
|
if (r.enumValues && r.enumValues.length > 0) ft.enumValues = r.enumValues;
|
|
1537
1551
|
if (r.nullable) ft.nullable = true;
|
|
1538
1552
|
if (r.numericEnum) ft.numericEnum = true;
|
|
@@ -1639,6 +1653,32 @@ function resolveFactoryStaticClass(node) {
|
|
|
1639
1653
|
if (!import_ts_morph5.Node.isIdentifier(inner)) return void 0;
|
|
1640
1654
|
return inner.getDefinitions().map((d) => d.getDeclarationNode()).find((n) => n !== void 0 && import_ts_morph5.Node.isClassDeclaration(n));
|
|
1641
1655
|
}
|
|
1656
|
+
function resolveBaseClass(cls) {
|
|
1657
|
+
const heritage = cls.getExtends()?.getExpression();
|
|
1658
|
+
if (!heritage) return void 0;
|
|
1659
|
+
const call = resolveHeritageCall(heritage);
|
|
1660
|
+
if (call) {
|
|
1661
|
+
const factoryDecl = resolveFactoryDeclaration(call);
|
|
1662
|
+
return factoryDecl ? resolveReturnedClass(factoryDecl) : void 0;
|
|
1663
|
+
}
|
|
1664
|
+
const expr = unwrapExpression(heritage);
|
|
1665
|
+
if (!import_ts_morph5.Node.isIdentifier(expr)) return void 0;
|
|
1666
|
+
return expr.getDefinitions().map((d) => d.getDeclarationNode()).find((n) => n !== void 0 && import_ts_morph5.Node.isClassDeclaration(n));
|
|
1667
|
+
}
|
|
1668
|
+
function collectMethodsThroughChain(returnedClass) {
|
|
1669
|
+
const byName = /* @__PURE__ */ new Map();
|
|
1670
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1671
|
+
let current = returnedClass;
|
|
1672
|
+
while (current && !seen.has(current)) {
|
|
1673
|
+
seen.add(current);
|
|
1674
|
+
for (const method of current.getMethods()) {
|
|
1675
|
+
const name = method.getName();
|
|
1676
|
+
if (!byName.has(name)) byName.set(name, method);
|
|
1677
|
+
}
|
|
1678
|
+
current = resolveBaseClass(current);
|
|
1679
|
+
}
|
|
1680
|
+
return [...byName.values()];
|
|
1681
|
+
}
|
|
1642
1682
|
function resolveInheritedMethods(cls) {
|
|
1643
1683
|
const expr = resolveHeritageCall(cls.getExtends()?.getExpression());
|
|
1644
1684
|
if (!expr) return void 0;
|
|
@@ -1678,7 +1718,7 @@ function resolveInheritedMethods(cls) {
|
|
|
1678
1718
|
}
|
|
1679
1719
|
}
|
|
1680
1720
|
return {
|
|
1681
|
-
methods: returnedClass
|
|
1721
|
+
methods: collectMethodsThroughChain(returnedClass),
|
|
1682
1722
|
// The DECLARATION's name, not the call-site text: consumers look the factory
|
|
1683
1723
|
// back up by name inside `factoryFilePath`, which a qualified
|
|
1684
1724
|
// `tables.createTableController` would never match. For a bare identifier
|
|
@@ -3052,7 +3092,7 @@ function extractDtoRoute(args) {
|
|
|
3052
3092
|
const methodName = method.getName();
|
|
3053
3093
|
const classAs = readAsDecorator(cls, `class ${className}`);
|
|
3054
3094
|
const methodAs = readAsDecorator(method, `${className}.${methodName}`);
|
|
3055
|
-
const dtoContract = extractDtoContract(method,
|
|
3095
|
+
const dtoContract = extractDtoContract(method, method.getSourceFile(), project, mixin, cls);
|
|
3056
3096
|
const mixinResponse = mixin ? resolveInstantiatedReturnType(cls, methodName) : void 0;
|
|
3057
3097
|
return buildRoute({
|
|
3058
3098
|
className,
|
|
@@ -3338,7 +3378,7 @@ function kindToTs(kind, enumValues, numericEnum) {
|
|
|
3338
3378
|
}
|
|
3339
3379
|
function emitFieldTypesLiteral(fts) {
|
|
3340
3380
|
const entries = fts.map((f) => {
|
|
3341
|
-
let t = f.typeRef ? f.typeRef.name : kindToTs(f.kind, f.enumValues, f.numericEnum);
|
|
3381
|
+
let t = f.typeRef ? f.typeRef.name : kindToTs(f.valueKind ?? f.kind, f.enumValues, f.numericEnum);
|
|
3342
3382
|
if (f.nullable) t = `${t} | null`;
|
|
3343
3383
|
return `${JSON.stringify(f.name)}: ${t}`;
|
|
3344
3384
|
});
|
|
@@ -5259,7 +5299,7 @@ async function watch(config, onChange, options = {}) {
|
|
|
5259
5299
|
}
|
|
5260
5300
|
|
|
5261
5301
|
// src/index.ts
|
|
5262
|
-
var VERSION = "0.
|
|
5302
|
+
var VERSION = "0.25.0";
|
|
5263
5303
|
|
|
5264
5304
|
// src/cli/codegen.ts
|
|
5265
5305
|
async function runCodegen(opts = {}) {
|