@dudousxd/nestjs-codegen 0.6.0 → 0.7.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 +23 -0
- package/dist/cli/main.cjs +21 -8
- package/dist/cli/main.cjs.map +1 -1
- package/dist/cli/main.js +21 -8
- 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-_qRai4M3.d.cts → index-DgIAN5k5.d.cts} +16 -1
- package/dist/{index-_qRai4M3.d.ts → index-DgIAN5k5.d.ts} +16 -1
- package/dist/index.cjs +21 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -6
- package/dist/index.d.ts +13 -6
- package/dist/index.js +21 -8
- package/dist/index.js.map +1 -1
- package/dist/nest/index.cjs +20 -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 +20 -7
- package/dist/nest/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# @dudousxd/nestjs-codegen
|
|
2
2
|
|
|
3
|
+
## 0.7.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- ff8ad8b: Jsonify-by-default serialized response types, with an opt-out `serialization` config option.
|
|
8
|
+
|
|
9
|
+
The generated `api.ts` now reflects the **JSON wire shape** of each route's response rather than the in-process server return type. A controller returning `{ createdAt: Date }` now generates `response: Jsonify<{ createdAt: string }>` — because `Date.prototype.toJSON()` emits an ISO string. `Jsonify<T>` recurses arrays/objects, follows any `toJSON()` holder to its returned shape, drops non-serializable properties (functions/symbols), keeps optional properties optional, and passes `any`/`unknown` through untouched. It is a hand-rolled, type-only utility with no runtime footprint.
|
|
10
|
+
|
|
11
|
+
- **`@dudousxd/nestjs-client`** exports the new `Jsonify<T>` type.
|
|
12
|
+
- **`@dudousxd/nestjs-codegen`** wraps each route `response` field in `Jsonify<...>` by default and emits `import type { Jsonify } from '<runtime>'` (tracking `fetcher.importPath`) when at least one route is wrapped. Only the `response` field is wrapped — never `error`, `body`, or `query`.
|
|
13
|
+
- New config option `serialization?: 'json' | 'superjson'` (default `'json'`). In `'superjson'` mode the raw controller return type is emitted unchanged (Dates/Maps/Sets are revived on the client), and no `Jsonify` import is emitted.
|
|
14
|
+
|
|
15
|
+
## 0.6.1
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- 95c744f: Fix watcher clobbering `api.ts` with an extension-only stub on page edits. The
|
|
20
|
+
pages fast path called `generate(config)` with no routes, so a route-injecting
|
|
21
|
+
extension (e.g. the notifications codegen) still emitted — overwriting the full
|
|
22
|
+
`api.ts` with just the injected namespace and dropping every contract-derived
|
|
23
|
+
route. The watcher now caches the last discovered routes (from the initial pass
|
|
24
|
+
and each contracts rediscovery) and reuses them for pages-only regenerations.
|
|
25
|
+
|
|
3
26
|
## 0.6.0
|
|
4
27
|
|
|
5
28
|
### Minor Changes
|
package/dist/cli/main.cjs
CHANGED
|
@@ -156,6 +156,7 @@ function applyDefaults(userConfig, cwd) {
|
|
|
156
156
|
},
|
|
157
157
|
app,
|
|
158
158
|
fetcher: userConfig.fetcher ?? null,
|
|
159
|
+
serialization: userConfig.serialization ?? "json",
|
|
159
160
|
forms: {
|
|
160
161
|
enabled: userConfig.forms?.enabled ?? true,
|
|
161
162
|
watch: userConfig.forms?.watch ?? "src/**/*.dto.ts",
|
|
@@ -739,7 +740,11 @@ function emitFilterQueryTypeArgs(c) {
|
|
|
739
740
|
function emitFilterQueryType(c) {
|
|
740
741
|
return `import('@dudousxd/nestjs-filter-client').TypedFilterQuery<${emitFilterQueryTypeArgs(c)}>`;
|
|
741
742
|
}
|
|
742
|
-
function buildResponseType(c, outDir) {
|
|
743
|
+
function buildResponseType(c, outDir, serialization) {
|
|
744
|
+
const raw = rawResponseType(c, outDir);
|
|
745
|
+
return serialization === "json" ? `Jsonify<${raw}>` : raw;
|
|
746
|
+
}
|
|
747
|
+
function rawResponseType(c, outDir) {
|
|
743
748
|
const respRef = c.contractSource.responseRef;
|
|
744
749
|
if (c.contractSource.stream) {
|
|
745
750
|
if (respRef) return respRef.isArray ? `Array<${respRef.name}>` : respRef.name;
|
|
@@ -762,7 +767,7 @@ function buildErrorType(c) {
|
|
|
762
767
|
}
|
|
763
768
|
return c.contractSource.error ?? "unknown";
|
|
764
769
|
}
|
|
765
|
-
function emitRouterTypeBlock(tree, indent, outDir) {
|
|
770
|
+
function emitRouterTypeBlock(tree, indent, outDir, serialization) {
|
|
766
771
|
const pad = " ".repeat(indent);
|
|
767
772
|
const lines = [];
|
|
768
773
|
for (const [key, node] of tree) {
|
|
@@ -775,7 +780,7 @@ function emitRouterTypeBlock(tree, indent, outDir) {
|
|
|
775
780
|
const query = queryRef ? queryRef.isArray ? `Array<${queryRef.name}>` : queryRef.name : isFilterQuery ? emitFilterQueryType(c) : c.contractSource.query ?? "never";
|
|
776
781
|
const bodyRef = c.contractSource.bodyRef;
|
|
777
782
|
const body = method === "GET" ? "never" : bodyRef ? bodyRef.isArray ? `Array<${bodyRef.name}>` : bodyRef.name : c.contractSource.body ?? "never";
|
|
778
|
-
const response = buildResponseType(c, outDir);
|
|
783
|
+
const response = buildResponseType(c, outDir, serialization);
|
|
779
784
|
const error = buildErrorType(c);
|
|
780
785
|
const params = buildParamsType(c.params);
|
|
781
786
|
const safeMethod = JSON.stringify(method);
|
|
@@ -787,7 +792,7 @@ function emitRouterTypeBlock(tree, indent, outDir) {
|
|
|
787
792
|
);
|
|
788
793
|
} else {
|
|
789
794
|
lines.push(`${pad}${objKey}: {`);
|
|
790
|
-
lines.push(...emitRouterTypeBlock(node.children, indent + 2, outDir));
|
|
795
|
+
lines.push(...emitRouterTypeBlock(node.children, indent + 2, outDir, serialization));
|
|
791
796
|
lines.push(`${pad}};`);
|
|
792
797
|
}
|
|
793
798
|
}
|
|
@@ -992,6 +997,7 @@ var EMPTY_PATH_NAMESPACE = [
|
|
|
992
997
|
];
|
|
993
998
|
function buildApiFile(routes, outDir, opts = {}) {
|
|
994
999
|
const fetcherImportPath = opts.fetcherImportPath;
|
|
1000
|
+
const serialization = opts.serialization ?? "json";
|
|
995
1001
|
const extensions = opts.extensions ?? [];
|
|
996
1002
|
const { layer } = resolveApiSlots(extensions);
|
|
997
1003
|
const memberExts = extensions.filter((e) => e.apiMembers);
|
|
@@ -1048,6 +1054,9 @@ function buildApiFile(routes, outDir, opts = {}) {
|
|
|
1048
1054
|
);
|
|
1049
1055
|
const runtimeImport = fetcherImportPath ?? "@dudousxd/nestjs-client";
|
|
1050
1056
|
lines.push(`import type { Fetcher } from '${runtimeImport}';`);
|
|
1057
|
+
if (serialization === "json" && contracted.length > 0) {
|
|
1058
|
+
lines.push(`import type { Jsonify } from '${runtimeImport}';`);
|
|
1059
|
+
}
|
|
1051
1060
|
if (importsByFile.size > 0 && outDir) {
|
|
1052
1061
|
lines.push("");
|
|
1053
1062
|
const emittedNames = /* @__PURE__ */ new Set();
|
|
@@ -1107,7 +1116,7 @@ function buildApiFile(routes, outDir, opts = {}) {
|
|
|
1107
1116
|
insertIntoTree(tree, segments, leaf, name);
|
|
1108
1117
|
}
|
|
1109
1118
|
lines.push("export type ApiRouter = {");
|
|
1110
|
-
lines.push(...emitRouterTypeBlock(tree, 2, outDir ?? ""));
|
|
1119
|
+
lines.push(...emitRouterTypeBlock(tree, 2, outDir ?? "", serialization));
|
|
1111
1120
|
lines.push("};");
|
|
1112
1121
|
lines.push("");
|
|
1113
1122
|
lines.push(...emitReqHelper());
|
|
@@ -2125,6 +2134,7 @@ async function generate(config, inputRoutes = []) {
|
|
|
2125
2134
|
if (hasContracts) {
|
|
2126
2135
|
await emitApi(routes, config.codegen.outDir, {
|
|
2127
2136
|
...config.fetcher?.importPath ? { fetcherImportPath: config.fetcher.importPath } : {},
|
|
2137
|
+
serialization: config.serialization,
|
|
2128
2138
|
extensions,
|
|
2129
2139
|
ctx
|
|
2130
2140
|
});
|
|
@@ -4355,6 +4365,7 @@ async function watch(config, onChange) {
|
|
|
4355
4365
|
return NO_OP_WATCHER;
|
|
4356
4366
|
}
|
|
4357
4367
|
let discovery = null;
|
|
4368
|
+
let lastRoutes = [];
|
|
4358
4369
|
async function getDiscovery() {
|
|
4359
4370
|
if (discovery === null) {
|
|
4360
4371
|
discovery = await PersistentDiscovery.create({
|
|
@@ -4368,13 +4379,14 @@ async function watch(config, onChange) {
|
|
|
4368
4379
|
}
|
|
4369
4380
|
try {
|
|
4370
4381
|
const initialRoutes = (await getDiscovery()).discover();
|
|
4382
|
+
lastRoutes = initialRoutes;
|
|
4371
4383
|
await generate(config, initialRoutes);
|
|
4372
4384
|
} catch (err) {
|
|
4373
4385
|
console.warn(
|
|
4374
4386
|
`[nestjs-codegen] Initial route discovery failed, falling back to pages-only: ${err instanceof Error ? err.message : String(err)}`
|
|
4375
4387
|
);
|
|
4376
4388
|
try {
|
|
4377
|
-
await generate(config);
|
|
4389
|
+
await generate(config, lastRoutes);
|
|
4378
4390
|
} catch {
|
|
4379
4391
|
}
|
|
4380
4392
|
}
|
|
@@ -4392,7 +4404,7 @@ async function watch(config, onChange) {
|
|
|
4392
4404
|
pagesDebounceTimer = setTimeout(async () => {
|
|
4393
4405
|
pagesDebounceTimer = void 0;
|
|
4394
4406
|
try {
|
|
4395
|
-
await generate(config);
|
|
4407
|
+
await generate(config, lastRoutes);
|
|
4396
4408
|
} catch (err) {
|
|
4397
4409
|
console.error(
|
|
4398
4410
|
"[nestjs-codegen] Pages generation failed:",
|
|
@@ -4423,6 +4435,7 @@ async function watch(config, onChange) {
|
|
|
4423
4435
|
pendingChangedPaths.clear();
|
|
4424
4436
|
try {
|
|
4425
4437
|
const routes = await (await getDiscovery()).rediscover(changed);
|
|
4438
|
+
lastRoutes = routes;
|
|
4426
4439
|
await generate(config, routes);
|
|
4427
4440
|
} catch (err) {
|
|
4428
4441
|
console.error(
|
|
@@ -4463,7 +4476,7 @@ async function watch(config, onChange) {
|
|
|
4463
4476
|
}
|
|
4464
4477
|
|
|
4465
4478
|
// src/index.ts
|
|
4466
|
-
var VERSION = "0.
|
|
4479
|
+
var VERSION = "0.7.0";
|
|
4467
4480
|
|
|
4468
4481
|
// src/cli/codegen.ts
|
|
4469
4482
|
async function runCodegen(opts = {}) {
|