@dudousxd/nestjs-codegen 0.22.1 → 0.24.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 +32 -0
- package/dist/cli/main.cjs +27 -7
- package/dist/cli/main.cjs.map +1 -1
- package/dist/cli/main.js +27 -7
- 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 +27 -7
- 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 +27 -7
- package/dist/index.js.map +1 -1
- package/dist/nest/index.cjs +27 -7
- 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 +27 -7
- package/dist/nest/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,37 @@
|
|
|
1
1
|
# @dudousxd/nestjs-codegen
|
|
2
2
|
|
|
3
|
+
## 0.24.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- c8d7eec: A mapped column's two declared types can disagree, so both are now emitted.
|
|
8
|
+
|
|
9
|
+
**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.
|
|
10
|
+
|
|
11
|
+
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.
|
|
12
|
+
|
|
13
|
+
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'`.
|
|
14
|
+
|
|
15
|
+
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.
|
|
16
|
+
|
|
17
|
+
`valueKind` is absent when the two agree, which is the overwhelming majority of columns, so nothing changes for them.
|
|
18
|
+
|
|
19
|
+
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.
|
|
20
|
+
|
|
21
|
+
## 0.23.0
|
|
22
|
+
|
|
23
|
+
### Minor Changes
|
|
24
|
+
|
|
25
|
+
- 4b13eef: Classify through transparent type brands, so a MikroORM entity's columns stop coming back `unknown`.
|
|
26
|
+
|
|
27
|
+
`Opt<T>` is how MikroORM marks a column optional on insert, and it is how nearly every nullable column in a MikroORM entity is written. It is a compile-time marker with no runtime shape of its own — an `Opt<string>` column holds a string — but the classifier saw a type reference it did not recognise and answered `unknown`. On a real entity that meant 31 of 35 fields unclassified, including plain `Opt<string>` names; the four that worked were the two written as bare primitives and the two written `Date & Opt<Date>`, where the intersection happens to expose a type the classifier already knew.
|
|
28
|
+
|
|
29
|
+
That is not a cosmetic gap. `unknown` is indistinguishable from "the classifier could not tell", so every consumer that reads a kind — operator sets, a number/date gate, a UI picking a filter control from the column's type — has to fall back to permissive for an entity that had in fact declared its types perfectly well.
|
|
30
|
+
|
|
31
|
+
`Opt<T>` and `Hidden<T>` are now unwrapped to their argument, recursively, so `Opt<Hidden<number>>` is a number.
|
|
32
|
+
|
|
33
|
+
Deliberately a short allowlist rather than "unwrap any single-argument reference". `Ref<T>`, `Rel<T>`, `Collection<T>` and `IdentifiedReference<T>` are **not** transparent: their runtime value is a reference or a collection, not a `T`. Unwrapping those would classify a relation as whatever its target's shape happens to be — silently, and only visibly far downstream.
|
|
34
|
+
|
|
3
35
|
## 0.22.1
|
|
4
36
|
|
|
5
37
|
### Patch Changes
|
package/dist/cli/main.cjs
CHANGED
|
@@ -1369,6 +1369,7 @@ function classifyTypeKeyword(raw) {
|
|
|
1369
1369
|
function markNullable(r, nullable) {
|
|
1370
1370
|
return nullable ? { ...r, nullable: true } : r;
|
|
1371
1371
|
}
|
|
1372
|
+
var TRANSPARENT_TYPE_BRANDS = /* @__PURE__ */ new Set(["Opt", "Hidden"]);
|
|
1372
1373
|
function classifyTypeNode(typeNode, sourceFile, project, opts) {
|
|
1373
1374
|
if (import_ts_morph4.Node.isUnionTypeNode(typeNode)) {
|
|
1374
1375
|
let nullable = false;
|
|
@@ -1427,6 +1428,11 @@ function classifyTypeNode(typeNode, sourceFile, project, opts) {
|
|
|
1427
1428
|
const refName = typeNode.getTypeName().getText();
|
|
1428
1429
|
if (refName === "Date") return { kind: "date" };
|
|
1429
1430
|
if (refName === "Record" || refName === "Object") return { kind: "json" };
|
|
1431
|
+
const unwrapped = TRANSPARENT_TYPE_BRANDS.has(refName) ? typeNode.getTypeArguments()[0] : void 0;
|
|
1432
|
+
if (unwrapped) {
|
|
1433
|
+
const inner = classifyTypeNode(unwrapped, sourceFile, project, opts);
|
|
1434
|
+
return inner;
|
|
1435
|
+
}
|
|
1430
1436
|
const typeRef = opts?.resolveRef?.(refName) ?? null;
|
|
1431
1437
|
const en = resolveEnumValues(refName, sourceFile, project);
|
|
1432
1438
|
if (en) {
|
|
@@ -1497,12 +1503,19 @@ function classifyFromColumnDecorator(prop, sourceFile, project) {
|
|
|
1497
1503
|
return { kind: "string" };
|
|
1498
1504
|
}
|
|
1499
1505
|
}
|
|
1500
|
-
const
|
|
1501
|
-
|
|
1506
|
+
for (const key of ["columnType", "type"]) {
|
|
1507
|
+
const typeProp = arg.getProperty(key);
|
|
1508
|
+
if (!typeProp || !import_ts_morph4.Node.isPropertyAssignment(typeProp)) continue;
|
|
1502
1509
|
const init = typeProp.getInitializer();
|
|
1503
|
-
if (init
|
|
1510
|
+
if (!init) continue;
|
|
1511
|
+
if (import_ts_morph4.Node.isStringLiteral(init)) {
|
|
1504
1512
|
const kind = classifyTypeKeyword(init.getLiteralValue());
|
|
1505
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 };
|
|
1506
1519
|
}
|
|
1507
1520
|
}
|
|
1508
1521
|
}
|
|
@@ -1514,12 +1527,18 @@ function classifyFromColumnDecorator(prop, sourceFile, project) {
|
|
|
1514
1527
|
function classifyFieldType(prop, sourceFile, project) {
|
|
1515
1528
|
let nullable = prop.hasQuestionToken();
|
|
1516
1529
|
const typeNode = prop.getTypeNode();
|
|
1530
|
+
const fromDecorator = classifyFromColumnDecorator(prop, sourceFile, project);
|
|
1517
1531
|
if (typeNode) {
|
|
1518
1532
|
const r = classifyTypeNode(typeNode, sourceFile, project);
|
|
1519
1533
|
if (r.nullable) nullable = true;
|
|
1520
|
-
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
|
+
}
|
|
1521
1541
|
}
|
|
1522
|
-
const fromDecorator = classifyFromColumnDecorator(prop, sourceFile, project);
|
|
1523
1542
|
if (fromDecorator) {
|
|
1524
1543
|
return markNullable(fromDecorator, nullable || fromDecorator.nullable === true);
|
|
1525
1544
|
}
|
|
@@ -1527,6 +1546,7 @@ function classifyFieldType(prop, sourceFile, project) {
|
|
|
1527
1546
|
}
|
|
1528
1547
|
function toFilterFieldType(name, r) {
|
|
1529
1548
|
const ft = { name, kind: r.kind };
|
|
1549
|
+
if (r.valueKind && r.valueKind !== r.kind) ft.valueKind = r.valueKind;
|
|
1530
1550
|
if (r.enumValues && r.enumValues.length > 0) ft.enumValues = r.enumValues;
|
|
1531
1551
|
if (r.nullable) ft.nullable = true;
|
|
1532
1552
|
if (r.numericEnum) ft.numericEnum = true;
|
|
@@ -3332,7 +3352,7 @@ function kindToTs(kind, enumValues, numericEnum) {
|
|
|
3332
3352
|
}
|
|
3333
3353
|
function emitFieldTypesLiteral(fts) {
|
|
3334
3354
|
const entries = fts.map((f) => {
|
|
3335
|
-
let t = f.typeRef ? f.typeRef.name : kindToTs(f.kind, f.enumValues, f.numericEnum);
|
|
3355
|
+
let t = f.typeRef ? f.typeRef.name : kindToTs(f.valueKind ?? f.kind, f.enumValues, f.numericEnum);
|
|
3336
3356
|
if (f.nullable) t = `${t} | null`;
|
|
3337
3357
|
return `${JSON.stringify(f.name)}: ${t}`;
|
|
3338
3358
|
});
|
|
@@ -5253,7 +5273,7 @@ async function watch(config, onChange, options = {}) {
|
|
|
5253
5273
|
}
|
|
5254
5274
|
|
|
5255
5275
|
// src/index.ts
|
|
5256
|
-
var VERSION = "0.
|
|
5276
|
+
var VERSION = "0.24.0";
|
|
5257
5277
|
|
|
5258
5278
|
// src/cli/codegen.ts
|
|
5259
5279
|
async function runCodegen(opts = {}) {
|