@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.
@@ -1,2 +1,2 @@
1
- export { l as ApiClientLayer, m as ApiHeaderContribution, n as ApiModuleDeps, C as CodegenExtension, o as EmittedFile, E as ExtensionContext, L as LeafModel, p as RequestModel, q as RequestShape, s as defineExtension, t as requestShape } from '../index-_qRai4M3.cjs';
1
+ export { m as ApiClientLayer, n as ApiHeaderContribution, o as ApiModuleDeps, C as CodegenExtension, p as EmittedFile, E as ExtensionContext, L as LeafModel, q as RequestModel, s as RequestShape, t as defineExtension, u as requestShape } from '../index-DgIAN5k5.cjs';
2
2
  import 'ts-morph';
@@ -1,2 +1,2 @@
1
- export { l as ApiClientLayer, m as ApiHeaderContribution, n as ApiModuleDeps, C as CodegenExtension, o as EmittedFile, E as ExtensionContext, L as LeafModel, p as RequestModel, q as RequestShape, s as defineExtension, t as requestShape } from '../index-_qRai4M3.js';
1
+ export { m as ApiClientLayer, n as ApiHeaderContribution, o as ApiModuleDeps, C as CodegenExtension, p as EmittedFile, E as ExtensionContext, L as LeafModel, q as RequestModel, s as RequestShape, t as defineExtension, u as requestShape } from '../index-DgIAN5k5.js';
2
2
  import 'ts-morph';
@@ -254,6 +254,18 @@ interface UserConfig {
254
254
  fetcher?: {
255
255
  importPath: string;
256
256
  };
257
+ /**
258
+ * How response payloads are deserialized on the client, which determines the
259
+ * generated `response` type shape.
260
+ *
261
+ * - `'json'` (default): responses cross the wire as plain JSON, so the
262
+ * generated type is wrapped in `Jsonify<...>` (e.g. `Date` → `string`).
263
+ * - `'superjson'`: responses are revived (Dates/Maps/Sets restored), so the
264
+ * raw controller return type is emitted unchanged.
265
+ *
266
+ * @default 'json'
267
+ */
268
+ serialization?: 'json' | 'superjson';
257
269
  /**
258
270
  * Typed-form schema emit (`forms.ts`). Re-exports / translates contract and
259
271
  * class-validator-decorated DTO schemas into zod schemas for client-side
@@ -319,6 +331,8 @@ interface ResolvedCodegenConfig {
319
331
  outDir: string;
320
332
  cwd: string;
321
333
  }
334
+ /** How response payloads are deserialized on the client. */
335
+ type SerializationMode = 'json' | 'superjson';
322
336
  interface ResolvedAppConfig {
323
337
  moduleEntry: string;
324
338
  tsconfig: string | null;
@@ -352,6 +366,7 @@ interface ResolvedConfig {
352
366
  fetcher: {
353
367
  importPath: string;
354
368
  } | null;
369
+ serialization: SerializationMode;
355
370
  forms: ResolvedFormsConfig;
356
371
  openapi: ResolvedOpenApiConfig;
357
372
  mocks: ResolvedMocksConfig;
@@ -631,4 +646,4 @@ declare function requestShape(route: RouteDescriptor): RequestShape;
631
646
  /** Identity helper for authoring extensions with full type inference. */
632
647
  declare function defineExtension(ext: CodegenExtension): CodegenExtension;
633
648
 
634
- export { type AdapterUsage as A, type CodegenExtension as C, type ExtensionContext as E, type LeafModel as L, type NumberCheck as N, type ResolvedConfig as R, type SchemaNode as S, type TypeRef as T, type UserConfig as U, type ValidationAdapter as V, type RouteDescriptor as a, type RenderContext as b, type SchemaModule as c, type RenderedModule as d, type ResolvedFormsConfig as e, type ContractDescriptor as f, type ContractSource as g, type ControllerRef as h, type ScopeConfig as i, type StringCheck as j, type ValidationOption as k, type ApiClientLayer as l, type ApiHeaderContribution as m, type ApiModuleDeps as n, type EmittedFile as o, type RequestModel as p, type RequestShape as q, resolveAdapter as r, defineExtension as s, requestShape as t };
649
+ export { type AdapterUsage as A, type CodegenExtension as C, type ExtensionContext as E, type LeafModel as L, type NumberCheck as N, type ResolvedConfig as R, type SchemaNode as S, type TypeRef as T, type UserConfig as U, type ValidationAdapter as V, type RouteDescriptor as a, type RenderContext as b, type SchemaModule as c, type RenderedModule as d, type ResolvedFormsConfig as e, type SerializationMode as f, type ContractDescriptor as g, type ContractSource as h, type ControllerRef as i, type ScopeConfig as j, type StringCheck as k, type ValidationOption as l, type ApiClientLayer as m, type ApiHeaderContribution as n, type ApiModuleDeps as o, type EmittedFile as p, type RequestModel as q, resolveAdapter as r, type RequestShape as s, defineExtension as t, requestShape as u };
@@ -254,6 +254,18 @@ interface UserConfig {
254
254
  fetcher?: {
255
255
  importPath: string;
256
256
  };
257
+ /**
258
+ * How response payloads are deserialized on the client, which determines the
259
+ * generated `response` type shape.
260
+ *
261
+ * - `'json'` (default): responses cross the wire as plain JSON, so the
262
+ * generated type is wrapped in `Jsonify<...>` (e.g. `Date` → `string`).
263
+ * - `'superjson'`: responses are revived (Dates/Maps/Sets restored), so the
264
+ * raw controller return type is emitted unchanged.
265
+ *
266
+ * @default 'json'
267
+ */
268
+ serialization?: 'json' | 'superjson';
257
269
  /**
258
270
  * Typed-form schema emit (`forms.ts`). Re-exports / translates contract and
259
271
  * class-validator-decorated DTO schemas into zod schemas for client-side
@@ -319,6 +331,8 @@ interface ResolvedCodegenConfig {
319
331
  outDir: string;
320
332
  cwd: string;
321
333
  }
334
+ /** How response payloads are deserialized on the client. */
335
+ type SerializationMode = 'json' | 'superjson';
322
336
  interface ResolvedAppConfig {
323
337
  moduleEntry: string;
324
338
  tsconfig: string | null;
@@ -352,6 +366,7 @@ interface ResolvedConfig {
352
366
  fetcher: {
353
367
  importPath: string;
354
368
  } | null;
369
+ serialization: SerializationMode;
355
370
  forms: ResolvedFormsConfig;
356
371
  openapi: ResolvedOpenApiConfig;
357
372
  mocks: ResolvedMocksConfig;
@@ -631,4 +646,4 @@ declare function requestShape(route: RouteDescriptor): RequestShape;
631
646
  /** Identity helper for authoring extensions with full type inference. */
632
647
  declare function defineExtension(ext: CodegenExtension): CodegenExtension;
633
648
 
634
- export { type AdapterUsage as A, type CodegenExtension as C, type ExtensionContext as E, type LeafModel as L, type NumberCheck as N, type ResolvedConfig as R, type SchemaNode as S, type TypeRef as T, type UserConfig as U, type ValidationAdapter as V, type RouteDescriptor as a, type RenderContext as b, type SchemaModule as c, type RenderedModule as d, type ResolvedFormsConfig as e, type ContractDescriptor as f, type ContractSource as g, type ControllerRef as h, type ScopeConfig as i, type StringCheck as j, type ValidationOption as k, type ApiClientLayer as l, type ApiHeaderContribution as m, type ApiModuleDeps as n, type EmittedFile as o, type RequestModel as p, type RequestShape as q, resolveAdapter as r, defineExtension as s, requestShape as t };
649
+ export { type AdapterUsage as A, type CodegenExtension as C, type ExtensionContext as E, type LeafModel as L, type NumberCheck as N, type ResolvedConfig as R, type SchemaNode as S, type TypeRef as T, type UserConfig as U, type ValidationAdapter as V, type RouteDescriptor as a, type RenderContext as b, type SchemaModule as c, type RenderedModule as d, type ResolvedFormsConfig as e, type SerializationMode as f, type ContractDescriptor as g, type ContractSource as h, type ControllerRef as i, type ScopeConfig as j, type StringCheck as k, type ValidationOption as l, type ApiClientLayer as m, type ApiHeaderContribution as n, type ApiModuleDeps as o, type EmittedFile as p, type RequestModel as q, resolveAdapter as r, type RequestShape as s, defineExtension as t, requestShape as u };
package/dist/index.cjs CHANGED
@@ -106,18 +106,23 @@ async function fileExists(filePath) {
106
106
  }
107
107
  }
108
108
  async function importTs(filePath) {
109
- let tsImport;
109
+ const fileUrl = (0, import_node_url.pathToFileURL)(filePath).href;
110
110
  try {
111
- const tsxEsm = await import("tsx/esm/api");
112
- tsImport = tsxEsm.tsImport;
113
- } catch {
114
- throw new ConfigError(
115
- "Failed to load config: `tsx` is required for loading TypeScript config files. Install it as a dev dependency: pnpm add -D tsx"
116
- );
111
+ return await import(fileUrl);
112
+ } catch (nativeError) {
113
+ let tsImport;
114
+ try {
115
+ const tsxEsm = await import("tsx/esm/api");
116
+ tsImport = tsxEsm.tsImport;
117
+ } catch {
118
+ throw new ConfigError(
119
+ "Failed to load config: `tsx` is required for loading TypeScript config files. Install it as a dev dependency: pnpm add -D tsx",
120
+ { cause: nativeError }
121
+ );
122
+ }
123
+ const parentURL = (0, import_node_url.pathToFileURL)(`${filePath}__parent__`).href;
124
+ return tsImport(fileUrl, { parentURL });
117
125
  }
118
- const parentURL = (0, import_node_url.pathToFileURL)(`${filePath}__parent__`).href;
119
- const fileUrl = (0, import_node_url.pathToFileURL)(filePath).href;
120
- return tsImport(fileUrl, { parentURL });
121
126
  }
122
127
  function resolveAbsolute(cwd, p) {
123
128
  if ((0, import_node_path.isAbsolute)(p)) return p;
@@ -187,6 +192,7 @@ function applyDefaults(userConfig, cwd) {
187
192
  },
188
193
  app,
189
194
  fetcher: userConfig.fetcher ?? null,
195
+ serialization: userConfig.serialization ?? "json",
190
196
  forms: {
191
197
  enabled: userConfig.forms?.enabled ?? true,
192
198
  watch: userConfig.forms?.watch ?? "src/**/*.dto.ts",
@@ -770,7 +776,11 @@ function emitFilterQueryTypeArgs(c) {
770
776
  function emitFilterQueryType(c) {
771
777
  return `import('@dudousxd/nestjs-filter-client').TypedFilterQuery<${emitFilterQueryTypeArgs(c)}>`;
772
778
  }
773
- function buildResponseType(c, outDir) {
779
+ function buildResponseType(c, outDir, serialization) {
780
+ const raw = rawResponseType(c, outDir);
781
+ return serialization === "json" ? `Jsonify<${raw}>` : raw;
782
+ }
783
+ function rawResponseType(c, outDir) {
774
784
  const respRef = c.contractSource.responseRef;
775
785
  if (c.contractSource.stream) {
776
786
  if (respRef) return respRef.isArray ? `Array<${respRef.name}>` : respRef.name;
@@ -793,7 +803,7 @@ function buildErrorType(c) {
793
803
  }
794
804
  return c.contractSource.error ?? "unknown";
795
805
  }
796
- function emitRouterTypeBlock(tree, indent, outDir) {
806
+ function emitRouterTypeBlock(tree, indent, outDir, serialization) {
797
807
  const pad = " ".repeat(indent);
798
808
  const lines = [];
799
809
  for (const [key, node] of tree) {
@@ -806,7 +816,7 @@ function emitRouterTypeBlock(tree, indent, outDir) {
806
816
  const query = queryRef ? queryRef.isArray ? `Array<${queryRef.name}>` : queryRef.name : isFilterQuery ? emitFilterQueryType(c) : c.contractSource.query ?? "never";
807
817
  const bodyRef = c.contractSource.bodyRef;
808
818
  const body = method === "GET" ? "never" : bodyRef ? bodyRef.isArray ? `Array<${bodyRef.name}>` : bodyRef.name : c.contractSource.body ?? "never";
809
- const response = buildResponseType(c, outDir);
819
+ const response = buildResponseType(c, outDir, serialization);
810
820
  const error = buildErrorType(c);
811
821
  const params = buildParamsType(c.params);
812
822
  const safeMethod = JSON.stringify(method);
@@ -818,7 +828,7 @@ function emitRouterTypeBlock(tree, indent, outDir) {
818
828
  );
819
829
  } else {
820
830
  lines.push(`${pad}${objKey}: {`);
821
- lines.push(...emitRouterTypeBlock(node.children, indent + 2, outDir));
831
+ lines.push(...emitRouterTypeBlock(node.children, indent + 2, outDir, serialization));
822
832
  lines.push(`${pad}};`);
823
833
  }
824
834
  }
@@ -1023,6 +1033,7 @@ var EMPTY_PATH_NAMESPACE = [
1023
1033
  ];
1024
1034
  function buildApiFile(routes, outDir, opts = {}) {
1025
1035
  const fetcherImportPath = opts.fetcherImportPath;
1036
+ const serialization = opts.serialization ?? "json";
1026
1037
  const extensions = opts.extensions ?? [];
1027
1038
  const { layer } = resolveApiSlots(extensions);
1028
1039
  const memberExts = extensions.filter((e) => e.apiMembers);
@@ -1079,6 +1090,9 @@ function buildApiFile(routes, outDir, opts = {}) {
1079
1090
  );
1080
1091
  const runtimeImport = fetcherImportPath ?? "@dudousxd/nestjs-client";
1081
1092
  lines.push(`import type { Fetcher } from '${runtimeImport}';`);
1093
+ if (serialization === "json" && contracted.length > 0) {
1094
+ lines.push(`import type { Jsonify } from '${runtimeImport}';`);
1095
+ }
1082
1096
  if (importsByFile.size > 0 && outDir) {
1083
1097
  lines.push("");
1084
1098
  const emittedNames = /* @__PURE__ */ new Set();
@@ -1138,7 +1152,7 @@ function buildApiFile(routes, outDir, opts = {}) {
1138
1152
  insertIntoTree(tree, segments, leaf, name);
1139
1153
  }
1140
1154
  lines.push("export type ApiRouter = {");
1141
- lines.push(...emitRouterTypeBlock(tree, 2, outDir ?? ""));
1155
+ lines.push(...emitRouterTypeBlock(tree, 2, outDir ?? "", serialization));
1142
1156
  lines.push("};");
1143
1157
  lines.push("");
1144
1158
  lines.push(...emitReqHelper());
@@ -2159,6 +2173,7 @@ async function generate(config, inputRoutes = []) {
2159
2173
  if (hasContracts) {
2160
2174
  await emitApi(routes, config.codegen.outDir, {
2161
2175
  ...config.fetcher?.importPath ? { fetcherImportPath: config.fetcher.importPath } : {},
2176
+ serialization: config.serialization,
2162
2177
  extensions,
2163
2178
  ctx
2164
2179
  });
@@ -4583,7 +4598,7 @@ function createChainModuleRenderer(opts) {
4583
4598
  }
4584
4599
 
4585
4600
  // src/index.ts
4586
- var VERSION = "0.6.1";
4601
+ var VERSION = "0.7.1";
4587
4602
  // Annotate the CommonJS export names for ESM import in node:
4588
4603
  0 && (module.exports = {
4589
4604
  CodegenError,