@dudousxd/nestjs-codegen 0.6.1 → 0.7.1
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 +18 -0
- package/dist/cli/main.cjs +31 -16
- package/dist/cli/main.cjs.map +1 -1
- package/dist/cli/main.js +31 -16
- 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 +31 -16
- 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 +31 -16
- package/dist/index.js.map +1 -1
- package/dist/nest/index.cjs +15 -5
- 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 +15 -5
- package/dist/nest/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# @dudousxd/nestjs-codegen
|
|
2
2
|
|
|
3
|
+
## 0.7.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- b8a8ce4: fix(core): load the TypeScript config via Node's native type-stripping first, falling back to tsx — unblocks the codegen CLI on Node 25 where tsx 4.22.4's resolver appends a `?namespace=<ts>` query that Node 25's stricter `finalizeResolution` rejects with `ERR_MODULE_NOT_FOUND`. tsx remains the fallback for older Node versions without native type stripping.
|
|
8
|
+
|
|
9
|
+
## 0.7.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- ff8ad8b: Jsonify-by-default serialized response types, with an opt-out `serialization` config option.
|
|
14
|
+
|
|
15
|
+
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.
|
|
16
|
+
|
|
17
|
+
- **`@dudousxd/nestjs-client`** exports the new `Jsonify<T>` type.
|
|
18
|
+
- **`@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`.
|
|
19
|
+
- 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.
|
|
20
|
+
|
|
3
21
|
## 0.6.1
|
|
4
22
|
|
|
5
23
|
### Patch Changes
|
package/dist/cli/main.cjs
CHANGED
|
@@ -78,18 +78,23 @@ async function fileExists(filePath) {
|
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
80
|
async function importTs(filePath) {
|
|
81
|
-
|
|
81
|
+
const fileUrl = (0, import_node_url.pathToFileURL)(filePath).href;
|
|
82
82
|
try {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
83
|
+
return await import(fileUrl);
|
|
84
|
+
} catch (nativeError) {
|
|
85
|
+
let tsImport;
|
|
86
|
+
try {
|
|
87
|
+
const tsxEsm = await import("tsx/esm/api");
|
|
88
|
+
tsImport = tsxEsm.tsImport;
|
|
89
|
+
} catch {
|
|
90
|
+
throw new ConfigError(
|
|
91
|
+
"Failed to load config: `tsx` is required for loading TypeScript config files. Install it as a dev dependency: pnpm add -D tsx",
|
|
92
|
+
{ cause: nativeError }
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
const parentURL = (0, import_node_url.pathToFileURL)(`${filePath}__parent__`).href;
|
|
96
|
+
return tsImport(fileUrl, { parentURL });
|
|
89
97
|
}
|
|
90
|
-
const parentURL = (0, import_node_url.pathToFileURL)(`${filePath}__parent__`).href;
|
|
91
|
-
const fileUrl = (0, import_node_url.pathToFileURL)(filePath).href;
|
|
92
|
-
return tsImport(fileUrl, { parentURL });
|
|
93
98
|
}
|
|
94
99
|
function resolveAbsolute(cwd, p) {
|
|
95
100
|
if ((0, import_node_path.isAbsolute)(p)) return p;
|
|
@@ -156,6 +161,7 @@ function applyDefaults(userConfig, cwd) {
|
|
|
156
161
|
},
|
|
157
162
|
app,
|
|
158
163
|
fetcher: userConfig.fetcher ?? null,
|
|
164
|
+
serialization: userConfig.serialization ?? "json",
|
|
159
165
|
forms: {
|
|
160
166
|
enabled: userConfig.forms?.enabled ?? true,
|
|
161
167
|
watch: userConfig.forms?.watch ?? "src/**/*.dto.ts",
|
|
@@ -739,7 +745,11 @@ function emitFilterQueryTypeArgs(c) {
|
|
|
739
745
|
function emitFilterQueryType(c) {
|
|
740
746
|
return `import('@dudousxd/nestjs-filter-client').TypedFilterQuery<${emitFilterQueryTypeArgs(c)}>`;
|
|
741
747
|
}
|
|
742
|
-
function buildResponseType(c, outDir) {
|
|
748
|
+
function buildResponseType(c, outDir, serialization) {
|
|
749
|
+
const raw = rawResponseType(c, outDir);
|
|
750
|
+
return serialization === "json" ? `Jsonify<${raw}>` : raw;
|
|
751
|
+
}
|
|
752
|
+
function rawResponseType(c, outDir) {
|
|
743
753
|
const respRef = c.contractSource.responseRef;
|
|
744
754
|
if (c.contractSource.stream) {
|
|
745
755
|
if (respRef) return respRef.isArray ? `Array<${respRef.name}>` : respRef.name;
|
|
@@ -762,7 +772,7 @@ function buildErrorType(c) {
|
|
|
762
772
|
}
|
|
763
773
|
return c.contractSource.error ?? "unknown";
|
|
764
774
|
}
|
|
765
|
-
function emitRouterTypeBlock(tree, indent, outDir) {
|
|
775
|
+
function emitRouterTypeBlock(tree, indent, outDir, serialization) {
|
|
766
776
|
const pad = " ".repeat(indent);
|
|
767
777
|
const lines = [];
|
|
768
778
|
for (const [key, node] of tree) {
|
|
@@ -775,7 +785,7 @@ function emitRouterTypeBlock(tree, indent, outDir) {
|
|
|
775
785
|
const query = queryRef ? queryRef.isArray ? `Array<${queryRef.name}>` : queryRef.name : isFilterQuery ? emitFilterQueryType(c) : c.contractSource.query ?? "never";
|
|
776
786
|
const bodyRef = c.contractSource.bodyRef;
|
|
777
787
|
const body = method === "GET" ? "never" : bodyRef ? bodyRef.isArray ? `Array<${bodyRef.name}>` : bodyRef.name : c.contractSource.body ?? "never";
|
|
778
|
-
const response = buildResponseType(c, outDir);
|
|
788
|
+
const response = buildResponseType(c, outDir, serialization);
|
|
779
789
|
const error = buildErrorType(c);
|
|
780
790
|
const params = buildParamsType(c.params);
|
|
781
791
|
const safeMethod = JSON.stringify(method);
|
|
@@ -787,7 +797,7 @@ function emitRouterTypeBlock(tree, indent, outDir) {
|
|
|
787
797
|
);
|
|
788
798
|
} else {
|
|
789
799
|
lines.push(`${pad}${objKey}: {`);
|
|
790
|
-
lines.push(...emitRouterTypeBlock(node.children, indent + 2, outDir));
|
|
800
|
+
lines.push(...emitRouterTypeBlock(node.children, indent + 2, outDir, serialization));
|
|
791
801
|
lines.push(`${pad}};`);
|
|
792
802
|
}
|
|
793
803
|
}
|
|
@@ -992,6 +1002,7 @@ var EMPTY_PATH_NAMESPACE = [
|
|
|
992
1002
|
];
|
|
993
1003
|
function buildApiFile(routes, outDir, opts = {}) {
|
|
994
1004
|
const fetcherImportPath = opts.fetcherImportPath;
|
|
1005
|
+
const serialization = opts.serialization ?? "json";
|
|
995
1006
|
const extensions = opts.extensions ?? [];
|
|
996
1007
|
const { layer } = resolveApiSlots(extensions);
|
|
997
1008
|
const memberExts = extensions.filter((e) => e.apiMembers);
|
|
@@ -1048,6 +1059,9 @@ function buildApiFile(routes, outDir, opts = {}) {
|
|
|
1048
1059
|
);
|
|
1049
1060
|
const runtimeImport = fetcherImportPath ?? "@dudousxd/nestjs-client";
|
|
1050
1061
|
lines.push(`import type { Fetcher } from '${runtimeImport}';`);
|
|
1062
|
+
if (serialization === "json" && contracted.length > 0) {
|
|
1063
|
+
lines.push(`import type { Jsonify } from '${runtimeImport}';`);
|
|
1064
|
+
}
|
|
1051
1065
|
if (importsByFile.size > 0 && outDir) {
|
|
1052
1066
|
lines.push("");
|
|
1053
1067
|
const emittedNames = /* @__PURE__ */ new Set();
|
|
@@ -1107,7 +1121,7 @@ function buildApiFile(routes, outDir, opts = {}) {
|
|
|
1107
1121
|
insertIntoTree(tree, segments, leaf, name);
|
|
1108
1122
|
}
|
|
1109
1123
|
lines.push("export type ApiRouter = {");
|
|
1110
|
-
lines.push(...emitRouterTypeBlock(tree, 2, outDir ?? ""));
|
|
1124
|
+
lines.push(...emitRouterTypeBlock(tree, 2, outDir ?? "", serialization));
|
|
1111
1125
|
lines.push("};");
|
|
1112
1126
|
lines.push("");
|
|
1113
1127
|
lines.push(...emitReqHelper());
|
|
@@ -2125,6 +2139,7 @@ async function generate(config, inputRoutes = []) {
|
|
|
2125
2139
|
if (hasContracts) {
|
|
2126
2140
|
await emitApi(routes, config.codegen.outDir, {
|
|
2127
2141
|
...config.fetcher?.importPath ? { fetcherImportPath: config.fetcher.importPath } : {},
|
|
2142
|
+
serialization: config.serialization,
|
|
2128
2143
|
extensions,
|
|
2129
2144
|
ctx
|
|
2130
2145
|
});
|
|
@@ -4466,7 +4481,7 @@ async function watch(config, onChange) {
|
|
|
4466
4481
|
}
|
|
4467
4482
|
|
|
4468
4483
|
// src/index.ts
|
|
4469
|
-
var VERSION = "0.
|
|
4484
|
+
var VERSION = "0.7.1";
|
|
4470
4485
|
|
|
4471
4486
|
// src/cli/codegen.ts
|
|
4472
4487
|
async function runCodegen(opts = {}) {
|