@dudousxd/nestjs-codegen 0.14.1 → 0.15.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 +13 -0
- package/dist/cli/main.cjs +71 -10
- package/dist/cli/main.cjs.map +1 -1
- package/dist/cli/main.js +71 -10
- package/dist/cli/main.js.map +1 -1
- package/dist/extension/index.cjs.map +1 -1
- package/dist/extension/index.d.cts +1 -1
- package/dist/extension/index.d.ts +1 -1
- package/dist/extension/index.js.map +1 -1
- package/dist/{index-DT8SgPxp.d.cts → index-CjIDPMsV.d.cts} +7 -0
- package/dist/{index-DT8SgPxp.d.ts → index-CjIDPMsV.d.ts} +7 -0
- package/dist/index.cjs +71 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -3
- package/dist/index.d.ts +9 -3
- package/dist/index.js +71 -10
- package/dist/index.js.map +1 -1
- package/dist/nest/index.cjs +92 -12
- package/dist/nest/index.cjs.map +1 -1
- package/dist/nest/index.d.cts +56 -3
- package/dist/nest/index.d.ts +56 -3
- package/dist/nest/index.js +88 -11
- package/dist/nest/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { U as UserConfig, R as ResolvedConfig, a as RouteDescriptor, S as SchemaNode, b as RenderContext, c as SchemaModule, d as RenderedModule, e as ResolvedFormsConfig, V as ValidationAdapter, C as CodegenExtension, E as ExtensionContext, f as SerializationMode } from './index-
|
|
2
|
-
export { A as AdapterUsage, g as ContractDescriptor, h as ContractSource, i as ControllerRef, N as NumberCheck, j as ScopeConfig, k as StringCheck, T as TypeRef, l as ValidationOption, r as resolveAdapter } from './index-
|
|
1
|
+
import { U as UserConfig, R as ResolvedConfig, a as RouteDescriptor, S as SchemaNode, b as RenderContext, c as SchemaModule, d as RenderedModule, e as ResolvedFormsConfig, V as ValidationAdapter, C as CodegenExtension, E as ExtensionContext, f as SerializationMode } from './index-CjIDPMsV.cjs';
|
|
2
|
+
export { A as AdapterUsage, g as ContractDescriptor, h as ContractSource, i as ControllerRef, N as NumberCheck, j as ScopeConfig, k as StringCheck, T as TypeRef, l as ValidationOption, r as resolveAdapter } from './index-CjIDPMsV.cjs';
|
|
3
3
|
import { ClassDeclaration, SourceFile, Project } from 'ts-morph';
|
|
4
4
|
|
|
5
5
|
declare function defineConfig(c: UserConfig): UserConfig;
|
|
@@ -73,6 +73,12 @@ interface CodegenManifest {
|
|
|
73
73
|
* unrelated source-file changes. Absent on pre-drift-guard manifests.
|
|
74
74
|
*/
|
|
75
75
|
configHash?: string;
|
|
76
|
+
/**
|
|
77
|
+
* Per-top-level-key hashes of the serialized resolved config, so a drift-guard
|
|
78
|
+
* failure can NAME the keys that differ instead of asking the consumer to
|
|
79
|
+
* eyeball two whole configs. Absent on manifests written before this field.
|
|
80
|
+
*/
|
|
81
|
+
configKeyHashes?: Record<string, string>;
|
|
76
82
|
/** Generated output files, relative to `outDir`, recorded after the last run. */
|
|
77
83
|
files: string[];
|
|
78
84
|
}
|
|
@@ -367,6 +373,6 @@ interface FastDiscoveryOptions {
|
|
|
367
373
|
}
|
|
368
374
|
declare function discoverContractsFast(opts: FastDiscoveryOptions): Promise<RouteDescriptor[]>;
|
|
369
375
|
|
|
370
|
-
declare const VERSION = "0.
|
|
376
|
+
declare const VERSION = "0.15.0";
|
|
371
377
|
|
|
372
378
|
export { type ChainModuleRendererOptions, CodegenError, type CodegenManifest, ConfigError, DriftGuardError, type EntryPoint, type FastDiscoveryOptions, type JsonSchema, type MocksEmitOptions, type OpenApiDocument, type OpenApiEmitOptions, type OpenApiInfo, RenderContext, RenderedModule, ResolvedConfig, RouteDescriptor, SchemaModule, SchemaNode, type TsTypeContext, UserConfig, VERSION, ValidationAdapter, type WatchOptions, type Watcher, acquireLock, buildMocksFile, buildOpenApiSpec, createChainModuleRenderer, defineConfig, discoverContractsFast, emitApi, emitForms, emitMocks, emitOpenApi, emitRoutes, extractSchemaFromDto, generate, loadConfig, renderTsType, resolveConfig, schemaModuleToJsonSchema, schemaNodeToJsonSchema, toObjectKey, typeNameFor, watch };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { U as UserConfig, R as ResolvedConfig, a as RouteDescriptor, S as SchemaNode, b as RenderContext, c as SchemaModule, d as RenderedModule, e as ResolvedFormsConfig, V as ValidationAdapter, C as CodegenExtension, E as ExtensionContext, f as SerializationMode } from './index-
|
|
2
|
-
export { A as AdapterUsage, g as ContractDescriptor, h as ContractSource, i as ControllerRef, N as NumberCheck, j as ScopeConfig, k as StringCheck, T as TypeRef, l as ValidationOption, r as resolveAdapter } from './index-
|
|
1
|
+
import { U as UserConfig, R as ResolvedConfig, a as RouteDescriptor, S as SchemaNode, b as RenderContext, c as SchemaModule, d as RenderedModule, e as ResolvedFormsConfig, V as ValidationAdapter, C as CodegenExtension, E as ExtensionContext, f as SerializationMode } from './index-CjIDPMsV.js';
|
|
2
|
+
export { A as AdapterUsage, g as ContractDescriptor, h as ContractSource, i as ControllerRef, N as NumberCheck, j as ScopeConfig, k as StringCheck, T as TypeRef, l as ValidationOption, r as resolveAdapter } from './index-CjIDPMsV.js';
|
|
3
3
|
import { ClassDeclaration, SourceFile, Project } from 'ts-morph';
|
|
4
4
|
|
|
5
5
|
declare function defineConfig(c: UserConfig): UserConfig;
|
|
@@ -73,6 +73,12 @@ interface CodegenManifest {
|
|
|
73
73
|
* unrelated source-file changes. Absent on pre-drift-guard manifests.
|
|
74
74
|
*/
|
|
75
75
|
configHash?: string;
|
|
76
|
+
/**
|
|
77
|
+
* Per-top-level-key hashes of the serialized resolved config, so a drift-guard
|
|
78
|
+
* failure can NAME the keys that differ instead of asking the consumer to
|
|
79
|
+
* eyeball two whole configs. Absent on manifests written before this field.
|
|
80
|
+
*/
|
|
81
|
+
configKeyHashes?: Record<string, string>;
|
|
76
82
|
/** Generated output files, relative to `outDir`, recorded after the last run. */
|
|
77
83
|
files: string[];
|
|
78
84
|
}
|
|
@@ -367,6 +373,6 @@ interface FastDiscoveryOptions {
|
|
|
367
373
|
}
|
|
368
374
|
declare function discoverContractsFast(opts: FastDiscoveryOptions): Promise<RouteDescriptor[]>;
|
|
369
375
|
|
|
370
|
-
declare const VERSION = "0.
|
|
376
|
+
declare const VERSION = "0.15.0";
|
|
371
377
|
|
|
372
378
|
export { type ChainModuleRendererOptions, CodegenError, type CodegenManifest, ConfigError, DriftGuardError, type EntryPoint, type FastDiscoveryOptions, type JsonSchema, type MocksEmitOptions, type OpenApiDocument, type OpenApiEmitOptions, type OpenApiInfo, RenderContext, RenderedModule, ResolvedConfig, RouteDescriptor, SchemaModule, SchemaNode, type TsTypeContext, UserConfig, VERSION, ValidationAdapter, type WatchOptions, type Watcher, acquireLock, buildMocksFile, buildOpenApiSpec, createChainModuleRenderer, defineConfig, discoverContractsFast, emitApi, emitForms, emitMocks, emitOpenApi, emitRoutes, extractSchemaFromDto, generate, loadConfig, renderTsType, resolveConfig, schemaModuleToJsonSchema, schemaNodeToJsonSchema, toObjectKey, typeNameFor, watch };
|
package/dist/index.js
CHANGED
|
@@ -746,6 +746,9 @@ function buildErrorType(c) {
|
|
|
746
746
|
}
|
|
747
747
|
return c.contractSource.error ?? "unknown";
|
|
748
748
|
}
|
|
749
|
+
function filterFieldLiterals(fields) {
|
|
750
|
+
return fields?.length ? fields.map((f) => JSON.stringify(f)) : [];
|
|
751
|
+
}
|
|
749
752
|
function emitRouterTypeBlock(tree, indent, outDir, serialization) {
|
|
750
753
|
const pad = " ".repeat(indent);
|
|
751
754
|
const lines = [];
|
|
@@ -772,7 +775,8 @@ function emitRouterTypeBlock(tree, indent, outDir, serialization) {
|
|
|
772
775
|
const params = buildParamsType(c.params);
|
|
773
776
|
const safeMethod = JSON.stringify(method);
|
|
774
777
|
const safeUrl = JSON.stringify(c.path);
|
|
775
|
-
const
|
|
778
|
+
const filterLiterals = filterFieldLiterals(c.contractSource.filterFields);
|
|
779
|
+
const filterFields = filterLiterals.length ? filterLiterals.join(" | ") : "never";
|
|
776
780
|
const stream = c.contractSource.stream ? "true" : "false";
|
|
777
781
|
const binary = c.contractSource.binaryResponse ? "true" : "false";
|
|
778
782
|
lines.push(
|
|
@@ -812,6 +816,7 @@ function buildRequestModel(c) {
|
|
|
812
816
|
const TA = buildRouterTypeAccess(c.name);
|
|
813
817
|
const withParams = hasPathParams(c.params);
|
|
814
818
|
const { isGet, isQuery, hasBody, hasQuery } = requestShape(c.route);
|
|
819
|
+
const filterLiterals = filterFieldLiterals(c.contractSource.filterFields);
|
|
815
820
|
const fields = [];
|
|
816
821
|
if (withParams) fields.push(`params: ${TA}['params']`);
|
|
817
822
|
if (hasQuery) fields.push(`query?: ${TA}['query']`);
|
|
@@ -841,7 +846,12 @@ function buildRequestModel(c) {
|
|
|
841
846
|
// (`[name]` rather than `[name, undefined]`) so the bare `.queryKey()` is a
|
|
842
847
|
// clean prefix that partial-matches every parametrized variant — making it
|
|
843
848
|
// directly usable for `invalidateQueries`.
|
|
844
|
-
queryKeyExpr: `(input === undefined ? [${flat}] as const : [${flat}, input] as const)
|
|
849
|
+
queryKeyExpr: `(input === undefined ? [${flat}] as const : [${flat}, input] as const)`,
|
|
850
|
+
// Runtime counterpart to the type-level `filterFields` union: the same
|
|
851
|
+
// discovered field list, emitted as a literal `[...] as const` so apps can
|
|
852
|
+
// validate a dynamic/user-supplied field string with `isFilterField(...)`
|
|
853
|
+
// instead of casting. Omitted for routes with no filter.
|
|
854
|
+
...filterLiterals.length ? { filterFieldsExpr: `[${filterLiterals.join(", ")}] as const` } : {}
|
|
845
855
|
};
|
|
846
856
|
}
|
|
847
857
|
function renderFetcherRequest(req, binaryResponse) {
|
|
@@ -876,9 +886,24 @@ function emitReqHelper() {
|
|
|
876
886
|
""
|
|
877
887
|
];
|
|
878
888
|
}
|
|
889
|
+
function emitFilterFieldGuard() {
|
|
890
|
+
return [
|
|
891
|
+
"/** Runtime guard: narrows `value` to one of the leaf's `filterFields` (a `readonly K[] as const`), so a dynamic field string can be passed to `.where()` without a cast. */",
|
|
892
|
+
"export function isFilterField<const K extends string>(",
|
|
893
|
+
" fields: readonly K[],",
|
|
894
|
+
" value: string,",
|
|
895
|
+
"): value is K {",
|
|
896
|
+
" return (fields as readonly string[]).includes(value);",
|
|
897
|
+
"}",
|
|
898
|
+
""
|
|
899
|
+
];
|
|
900
|
+
}
|
|
879
901
|
function renderLeaf(pad, objKey, req, requestExpr, members, streamExpr) {
|
|
880
902
|
const lines = [`${pad}${objKey}: (input?: ${req.inputType}) => ({`];
|
|
881
903
|
lines.push(`${pad} ...__req<${req.responseType}>(() => ${requestExpr}),`);
|
|
904
|
+
if (req.filterFieldsExpr) {
|
|
905
|
+
lines.push(`${pad} filterFields: ${req.filterFieldsExpr},`);
|
|
906
|
+
}
|
|
882
907
|
if (streamExpr) {
|
|
883
908
|
lines.push(`${pad} stream: () => ${streamExpr},`);
|
|
884
909
|
}
|
|
@@ -1150,6 +1175,9 @@ function buildApiFile(routes, outDir, opts = {}) {
|
|
|
1150
1175
|
lines.push("};");
|
|
1151
1176
|
lines.push("");
|
|
1152
1177
|
lines.push(...emitReqHelper());
|
|
1178
|
+
if (contracted.some((r) => r.contract?.contractSource.filterFields?.length)) {
|
|
1179
|
+
lines.push(...emitFilterFieldGuard());
|
|
1180
|
+
}
|
|
1153
1181
|
lines.push("export function createApi(fetcher: Fetcher) {");
|
|
1154
1182
|
lines.push(" return {");
|
|
1155
1183
|
lines.push(
|
|
@@ -2159,19 +2187,41 @@ function isManifestShape(value) {
|
|
|
2159
2187
|
if (typeof candidate.hash !== "string") return false;
|
|
2160
2188
|
if (candidate.entryPoint !== void 0 && !isEntryPoint(candidate.entryPoint)) return false;
|
|
2161
2189
|
if (candidate.configHash !== void 0 && typeof candidate.configHash !== "string") return false;
|
|
2190
|
+
if (candidate.configKeyHashes !== void 0 && !isStringRecord(candidate.configKeyHashes)) {
|
|
2191
|
+
return false;
|
|
2192
|
+
}
|
|
2162
2193
|
if (!Array.isArray(candidate.files)) return false;
|
|
2163
2194
|
return candidate.files.every((entry) => typeof entry === "string");
|
|
2164
2195
|
}
|
|
2196
|
+
function isStringRecord(value) {
|
|
2197
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
2198
|
+
return Object.values(value).every((entry) => typeof entry === "string");
|
|
2199
|
+
}
|
|
2165
2200
|
function serializeConfig(config) {
|
|
2201
|
+
return serializeConfigValue(config, `unserializable:${config.codegen.outDir}`);
|
|
2202
|
+
}
|
|
2203
|
+
function serializeConfigValue(value, unserializableMarker) {
|
|
2166
2204
|
try {
|
|
2167
|
-
return JSON.stringify(
|
|
2168
|
-
if (typeof
|
|
2169
|
-
return
|
|
2205
|
+
return JSON.stringify(value, (_key, entry) => {
|
|
2206
|
+
if (typeof entry === "function") return `[fn:${entry.name}]`;
|
|
2207
|
+
return entry;
|
|
2170
2208
|
});
|
|
2171
2209
|
} catch {
|
|
2172
|
-
return
|
|
2210
|
+
return unserializableMarker;
|
|
2173
2211
|
}
|
|
2174
2212
|
}
|
|
2213
|
+
function computeConfigKeyHashes(config) {
|
|
2214
|
+
const hashes = {};
|
|
2215
|
+
for (const [key, value] of Object.entries(config)) {
|
|
2216
|
+
if (value === void 0) continue;
|
|
2217
|
+
hashes[key] = createHash("sha256").update(serializeConfigValue(value, `unserializable:${key}`)).digest("hex");
|
|
2218
|
+
}
|
|
2219
|
+
return hashes;
|
|
2220
|
+
}
|
|
2221
|
+
function diffConfigKeyHashes(previous, current) {
|
|
2222
|
+
const keys = /* @__PURE__ */ new Set([...Object.keys(previous), ...Object.keys(current)]);
|
|
2223
|
+
return [...keys].filter((key) => previous[key] !== current[key]).sort();
|
|
2224
|
+
}
|
|
2175
2225
|
async function discoverInputFiles(config) {
|
|
2176
2226
|
const globs = [config.contracts.glob, config.forms.watch];
|
|
2177
2227
|
if (config.pages) globs.push(config.pages.glob);
|
|
@@ -2206,6 +2256,7 @@ async function readManifest(outDir) {
|
|
|
2206
2256
|
hash: parsed.hash,
|
|
2207
2257
|
...parsed.entryPoint ? { entryPoint: parsed.entryPoint } : {},
|
|
2208
2258
|
...parsed.configHash ? { configHash: parsed.configHash } : {},
|
|
2259
|
+
...parsed.configKeyHashes ? { configKeyHashes: parsed.configKeyHashes } : {},
|
|
2209
2260
|
files: parsed.files
|
|
2210
2261
|
};
|
|
2211
2262
|
} catch {
|
|
@@ -2259,8 +2310,9 @@ function debugWarn(message) {
|
|
|
2259
2310
|
}
|
|
2260
2311
|
|
|
2261
2312
|
// src/generate.ts
|
|
2262
|
-
function driftGuardMessage(outDir, previousEntryPoint, currentEntryPoint) {
|
|
2263
|
-
|
|
2313
|
+
function driftGuardMessage(outDir, previousEntryPoint, currentEntryPoint, differingKeys) {
|
|
2314
|
+
const differ = differingKeys.length > 0 ? `their resolved configs differ at: ${differingKeys.map((key) => `\`${key}\``).join(", ")}` : "their resolved configs differ (re-run after this generate records per-key hashes to see which keys)";
|
|
2315
|
+
return `[nestjs-codegen] Config drift detected in "${outDir}": the last generate ran from the "${previousEntryPoint}" entry point, this run is from the "${currentEntryPoint}" entry point, and ${differ}. Both entry points must read the SAME config \u2014 export a shared config object (e.g. codegen.config.ts) and import it from BOTH nestjs-codegen.config.ts (CLI) and NestjsCodegenModule.forRoot() (Nest module), or set \`driftGuard: false\` on either config to opt out of this check.`;
|
|
2264
2316
|
}
|
|
2265
2317
|
async function generate(config, inputRoutes = [], entryPoint = "cli") {
|
|
2266
2318
|
setCodegenDebug(config.debug);
|
|
@@ -2271,9 +2323,17 @@ async function generate(config, inputRoutes = [], entryPoint = "cli") {
|
|
|
2271
2323
|
return;
|
|
2272
2324
|
}
|
|
2273
2325
|
const configHash = computeConfigHash(config);
|
|
2326
|
+
const configKeyHashes = computeConfigKeyHashes(config);
|
|
2274
2327
|
if (config.driftGuard && manifest?.entryPoint && manifest.entryPoint !== entryPoint && manifest.configHash && manifest.configHash !== configHash) {
|
|
2275
2328
|
throw new DriftGuardError(
|
|
2276
|
-
driftGuardMessage(
|
|
2329
|
+
driftGuardMessage(
|
|
2330
|
+
config.codegen.outDir,
|
|
2331
|
+
manifest.entryPoint,
|
|
2332
|
+
entryPoint,
|
|
2333
|
+
// A pre-key-hash manifest can't tell us WHICH keys differ — pass none
|
|
2334
|
+
// rather than diffing against {} (which would name every key).
|
|
2335
|
+
manifest.configKeyHashes ? diffConfigKeyHashes(manifest.configKeyHashes, configKeyHashes) : []
|
|
2336
|
+
)
|
|
2277
2337
|
);
|
|
2278
2338
|
}
|
|
2279
2339
|
const extensions = config.extensions ?? [];
|
|
@@ -2343,6 +2403,7 @@ async function generate(config, inputRoutes = [], entryPoint = "cli") {
|
|
|
2343
2403
|
hash: inputsHash,
|
|
2344
2404
|
entryPoint,
|
|
2345
2405
|
configHash,
|
|
2406
|
+
configKeyHashes,
|
|
2346
2407
|
files: outputFiles
|
|
2347
2408
|
});
|
|
2348
2409
|
}
|
|
@@ -4873,7 +4934,7 @@ function createChainModuleRenderer(opts) {
|
|
|
4873
4934
|
}
|
|
4874
4935
|
|
|
4875
4936
|
// src/index.ts
|
|
4876
|
-
var VERSION = "0.
|
|
4937
|
+
var VERSION = "0.15.0";
|
|
4877
4938
|
export {
|
|
4878
4939
|
CodegenError,
|
|
4879
4940
|
ConfigError,
|