@dudousxd/nestjs-codegen 0.10.0 → 0.12.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 +47 -0
- package/dist/cli/main.cjs +209 -89
- package/dist/cli/main.cjs.map +1 -1
- package/dist/cli/main.js +193 -73
- package/dist/cli/main.js.map +1 -1
- package/dist/index.cjs +167 -47
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +29 -3
- package/dist/index.d.ts +29 -3
- package/dist/index.js +154 -34
- package/dist/index.js.map +1 -1
- package/dist/nest/index.cjs +212 -73
- package/dist/nest/index.cjs.map +1 -1
- package/dist/nest/index.d.cts +15 -4
- package/dist/nest/index.d.ts +15 -4
- package/dist/nest/index.js +212 -73
- package/dist/nest/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -45,6 +45,18 @@ declare function generate(config: ResolvedConfig, inputRoutes?: RouteDescriptor[
|
|
|
45
45
|
interface Watcher {
|
|
46
46
|
close(): Promise<void>;
|
|
47
47
|
}
|
|
48
|
+
interface WatchOptions {
|
|
49
|
+
/**
|
|
50
|
+
* Run the initial discover + generate as fire-and-forget instead of awaiting it
|
|
51
|
+
* before returning. The lock is still acquired and the chokidar watchers are
|
|
52
|
+
* still set up synchronously; only the initial generate is backgrounded. Used by
|
|
53
|
+
* the Nest `onApplicationBootstrap` hook so codegen never blocks time-to-ready.
|
|
54
|
+
* The one-shot CLI leaves this `false` so the build step stays synchronous.
|
|
55
|
+
*
|
|
56
|
+
* @default false
|
|
57
|
+
*/
|
|
58
|
+
deferInitialGenerate?: boolean;
|
|
59
|
+
}
|
|
48
60
|
/**
|
|
49
61
|
* Start two chokidar watchers:
|
|
50
62
|
*
|
|
@@ -58,7 +70,7 @@ interface Watcher {
|
|
|
58
70
|
* Both watchers share a single lock file in `config.codegen.outDir`. If another live process
|
|
59
71
|
* already holds the lock, logs a warning and returns a no-op watcher.
|
|
60
72
|
*/
|
|
61
|
-
declare function watch(config: ResolvedConfig, onChange?: () => void): Promise<Watcher>;
|
|
73
|
+
declare function watch(config: ResolvedConfig, onChange?: () => void, options?: WatchOptions): Promise<Watcher>;
|
|
62
74
|
|
|
63
75
|
/**
|
|
64
76
|
* Try to acquire an exclusive lock for a watcher in `outDir`.
|
|
@@ -73,6 +85,20 @@ declare function acquireLock(outDir: string): Promise<{
|
|
|
73
85
|
release: () => Promise<void>;
|
|
74
86
|
} | null>;
|
|
75
87
|
|
|
88
|
+
/**
|
|
89
|
+
* Persisted record of the last successful generate, written to
|
|
90
|
+
* `<outDir>/.codegen-manifest.json`. Used to skip regeneration when nothing
|
|
91
|
+
* relevant changed (see {@link isManifestFresh}).
|
|
92
|
+
*/
|
|
93
|
+
interface CodegenManifest {
|
|
94
|
+
/** Lib version that produced the output. A lib upgrade invalidates the manifest. */
|
|
95
|
+
version: string;
|
|
96
|
+
/** Content hash over all generate inputs (source files + resolved config + version). */
|
|
97
|
+
hash: string;
|
|
98
|
+
/** Generated output files, relative to `outDir`, recorded after the last run. */
|
|
99
|
+
files: string[];
|
|
100
|
+
}
|
|
101
|
+
|
|
76
102
|
/**
|
|
77
103
|
* Renders the neutral {@link SchemaNode} IR to a TypeScript *type* expression
|
|
78
104
|
* (not a validation-lib schema). Used to synthesize the hoisted structural type
|
|
@@ -296,6 +322,6 @@ interface FastDiscoveryOptions {
|
|
|
296
322
|
}
|
|
297
323
|
declare function discoverContractsFast(opts: FastDiscoveryOptions): Promise<RouteDescriptor[]>;
|
|
298
324
|
|
|
299
|
-
declare const VERSION = "0.
|
|
325
|
+
declare const VERSION = "0.12.0";
|
|
300
326
|
|
|
301
|
-
export { type ChainModuleRendererOptions, CodegenError, ConfigError, type FastDiscoveryOptions, type JsonSchema, type MocksEmitOptions, type OpenApiDocument, type OpenApiEmitOptions, type OpenApiInfo, RenderContext, RenderedModule, ResolvedConfig, RouteDescriptor, SchemaModule, SchemaNode, type TsTypeContext, UserConfig, VERSION, ValidationAdapter, type Watcher, acquireLock, buildMocksFile, buildOpenApiSpec, createChainModuleRenderer, defineConfig, discoverContractsFast, emitApi, emitForms, emitMocks, emitOpenApi, emitRoutes, extractSchemaFromDto, generate, loadConfig, renderTsType, resolveConfig, schemaModuleToJsonSchema, schemaNodeToJsonSchema, toObjectKey, typeNameFor, watch };
|
|
327
|
+
export { type ChainModuleRendererOptions, CodegenError, type CodegenManifest, ConfigError, 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
|
@@ -45,6 +45,18 @@ declare function generate(config: ResolvedConfig, inputRoutes?: RouteDescriptor[
|
|
|
45
45
|
interface Watcher {
|
|
46
46
|
close(): Promise<void>;
|
|
47
47
|
}
|
|
48
|
+
interface WatchOptions {
|
|
49
|
+
/**
|
|
50
|
+
* Run the initial discover + generate as fire-and-forget instead of awaiting it
|
|
51
|
+
* before returning. The lock is still acquired and the chokidar watchers are
|
|
52
|
+
* still set up synchronously; only the initial generate is backgrounded. Used by
|
|
53
|
+
* the Nest `onApplicationBootstrap` hook so codegen never blocks time-to-ready.
|
|
54
|
+
* The one-shot CLI leaves this `false` so the build step stays synchronous.
|
|
55
|
+
*
|
|
56
|
+
* @default false
|
|
57
|
+
*/
|
|
58
|
+
deferInitialGenerate?: boolean;
|
|
59
|
+
}
|
|
48
60
|
/**
|
|
49
61
|
* Start two chokidar watchers:
|
|
50
62
|
*
|
|
@@ -58,7 +70,7 @@ interface Watcher {
|
|
|
58
70
|
* Both watchers share a single lock file in `config.codegen.outDir`. If another live process
|
|
59
71
|
* already holds the lock, logs a warning and returns a no-op watcher.
|
|
60
72
|
*/
|
|
61
|
-
declare function watch(config: ResolvedConfig, onChange?: () => void): Promise<Watcher>;
|
|
73
|
+
declare function watch(config: ResolvedConfig, onChange?: () => void, options?: WatchOptions): Promise<Watcher>;
|
|
62
74
|
|
|
63
75
|
/**
|
|
64
76
|
* Try to acquire an exclusive lock for a watcher in `outDir`.
|
|
@@ -73,6 +85,20 @@ declare function acquireLock(outDir: string): Promise<{
|
|
|
73
85
|
release: () => Promise<void>;
|
|
74
86
|
} | null>;
|
|
75
87
|
|
|
88
|
+
/**
|
|
89
|
+
* Persisted record of the last successful generate, written to
|
|
90
|
+
* `<outDir>/.codegen-manifest.json`. Used to skip regeneration when nothing
|
|
91
|
+
* relevant changed (see {@link isManifestFresh}).
|
|
92
|
+
*/
|
|
93
|
+
interface CodegenManifest {
|
|
94
|
+
/** Lib version that produced the output. A lib upgrade invalidates the manifest. */
|
|
95
|
+
version: string;
|
|
96
|
+
/** Content hash over all generate inputs (source files + resolved config + version). */
|
|
97
|
+
hash: string;
|
|
98
|
+
/** Generated output files, relative to `outDir`, recorded after the last run. */
|
|
99
|
+
files: string[];
|
|
100
|
+
}
|
|
101
|
+
|
|
76
102
|
/**
|
|
77
103
|
* Renders the neutral {@link SchemaNode} IR to a TypeScript *type* expression
|
|
78
104
|
* (not a validation-lib schema). Used to synthesize the hoisted structural type
|
|
@@ -296,6 +322,6 @@ interface FastDiscoveryOptions {
|
|
|
296
322
|
}
|
|
297
323
|
declare function discoverContractsFast(opts: FastDiscoveryOptions): Promise<RouteDescriptor[]>;
|
|
298
324
|
|
|
299
|
-
declare const VERSION = "0.
|
|
325
|
+
declare const VERSION = "0.12.0";
|
|
300
326
|
|
|
301
|
-
export { type ChainModuleRendererOptions, CodegenError, ConfigError, type FastDiscoveryOptions, type JsonSchema, type MocksEmitOptions, type OpenApiDocument, type OpenApiEmitOptions, type OpenApiInfo, RenderContext, RenderedModule, ResolvedConfig, RouteDescriptor, SchemaModule, SchemaNode, type TsTypeContext, UserConfig, VERSION, ValidationAdapter, type Watcher, acquireLock, buildMocksFile, buildOpenApiSpec, createChainModuleRenderer, defineConfig, discoverContractsFast, emitApi, emitForms, emitMocks, emitOpenApi, emitRoutes, extractSchemaFromDto, generate, loadConfig, renderTsType, resolveConfig, schemaModuleToJsonSchema, schemaNodeToJsonSchema, toObjectKey, typeNameFor, watch };
|
|
327
|
+
export { type ChainModuleRendererOptions, CodegenError, type CodegenManifest, ConfigError, 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
|
@@ -188,8 +188,8 @@ Run \`nestjs-codegen init\` to create a starter config.`
|
|
|
188
188
|
}
|
|
189
189
|
|
|
190
190
|
// src/generate.ts
|
|
191
|
-
import { mkdir as mkdir9, writeFile as
|
|
192
|
-
import { dirname as dirname2, join as
|
|
191
|
+
import { mkdir as mkdir9, writeFile as writeFile10 } from "fs/promises";
|
|
192
|
+
import { dirname as dirname2, join as join13 } from "path";
|
|
193
193
|
|
|
194
194
|
// src/discovery/pages.ts
|
|
195
195
|
import { readFile } from "fs/promises";
|
|
@@ -803,7 +803,11 @@ function buildRequestModel(c) {
|
|
|
803
803
|
urlExpr,
|
|
804
804
|
optsExpr,
|
|
805
805
|
responseType: `${TA}['response']`,
|
|
806
|
-
|
|
806
|
+
// When no input is supplied the key omits the trailing element entirely
|
|
807
|
+
// (`[name]` rather than `[name, undefined]`) so the bare `.queryKey()` is a
|
|
808
|
+
// clean prefix that partial-matches every parametrized variant — making it
|
|
809
|
+
// directly usable for `invalidateQueries`.
|
|
810
|
+
queryKeyExpr: `(input === undefined ? [${flat}] as const : [${flat}, input] as const)`
|
|
807
811
|
};
|
|
808
812
|
}
|
|
809
813
|
function renderFetcherRequest(req) {
|
|
@@ -2083,6 +2087,99 @@ function buildEmpty() {
|
|
|
2083
2087
|
].join("\n");
|
|
2084
2088
|
}
|
|
2085
2089
|
|
|
2090
|
+
// src/generate-manifest.ts
|
|
2091
|
+
import { createHash } from "crypto";
|
|
2092
|
+
import { readFile as readFile2, readdir, writeFile as writeFile9 } from "fs/promises";
|
|
2093
|
+
import { join as join12, relative as relative6 } from "path";
|
|
2094
|
+
import fg2 from "fast-glob";
|
|
2095
|
+
var MANIFEST_FILE = ".codegen-manifest.json";
|
|
2096
|
+
var LOCK_FILE = ".watcher.lock";
|
|
2097
|
+
function isManifestShape(value) {
|
|
2098
|
+
if (typeof value !== "object" || value === null) return false;
|
|
2099
|
+
const candidate = value;
|
|
2100
|
+
if (typeof candidate.version !== "string") return false;
|
|
2101
|
+
if (typeof candidate.hash !== "string") return false;
|
|
2102
|
+
if (!Array.isArray(candidate.files)) return false;
|
|
2103
|
+
return candidate.files.every((entry) => typeof entry === "string");
|
|
2104
|
+
}
|
|
2105
|
+
function serializeConfig(config) {
|
|
2106
|
+
try {
|
|
2107
|
+
return JSON.stringify(config, (_key, value) => {
|
|
2108
|
+
if (typeof value === "function") return `[fn:${value.name}]${value.toString()}`;
|
|
2109
|
+
return value;
|
|
2110
|
+
});
|
|
2111
|
+
} catch {
|
|
2112
|
+
return `unserializable:${config.codegen.outDir}:${config.contracts.glob}`;
|
|
2113
|
+
}
|
|
2114
|
+
}
|
|
2115
|
+
async function discoverInputFiles(config) {
|
|
2116
|
+
const globs = [config.contracts.glob, config.forms.watch];
|
|
2117
|
+
if (config.pages) globs.push(config.pages.glob);
|
|
2118
|
+
const cwd = config.codegen.cwd;
|
|
2119
|
+
const matched = await fg2(globs, { cwd, absolute: true, onlyFiles: true });
|
|
2120
|
+
return [...new Set(matched)].sort();
|
|
2121
|
+
}
|
|
2122
|
+
async function computeInputsHash(config) {
|
|
2123
|
+
const hash = createHash("sha256");
|
|
2124
|
+
hash.update(`version:${VERSION}
|
|
2125
|
+
`);
|
|
2126
|
+
hash.update(`config:${serializeConfig(config)}
|
|
2127
|
+
`);
|
|
2128
|
+
const inputFiles = await discoverInputFiles(config);
|
|
2129
|
+
const cwd = config.codegen.cwd;
|
|
2130
|
+
for (const file of inputFiles) {
|
|
2131
|
+
const contents = await readFile2(file, "utf8");
|
|
2132
|
+
hash.update(`file:${relative6(cwd, file)}
|
|
2133
|
+
`);
|
|
2134
|
+
hash.update(contents);
|
|
2135
|
+
hash.update("\n");
|
|
2136
|
+
}
|
|
2137
|
+
return hash.digest("hex");
|
|
2138
|
+
}
|
|
2139
|
+
async function readManifest(outDir) {
|
|
2140
|
+
try {
|
|
2141
|
+
const raw = await readFile2(join12(outDir, MANIFEST_FILE), "utf8");
|
|
2142
|
+
const parsed = JSON.parse(raw);
|
|
2143
|
+
if (!isManifestShape(parsed)) return null;
|
|
2144
|
+
return { version: parsed.version, hash: parsed.hash, files: parsed.files };
|
|
2145
|
+
} catch {
|
|
2146
|
+
return null;
|
|
2147
|
+
}
|
|
2148
|
+
}
|
|
2149
|
+
async function writeManifest(outDir, manifest) {
|
|
2150
|
+
await writeFile9(join12(outDir, MANIFEST_FILE), `${JSON.stringify(manifest, null, 2)}
|
|
2151
|
+
`, "utf8");
|
|
2152
|
+
}
|
|
2153
|
+
async function listOutputFiles(outDir) {
|
|
2154
|
+
const found = [];
|
|
2155
|
+
async function walk(dir) {
|
|
2156
|
+
const entries = await readdir(dir, { withFileTypes: true }).catch(() => []);
|
|
2157
|
+
for (const entry of entries) {
|
|
2158
|
+
const abs = join12(dir, entry.name);
|
|
2159
|
+
if (entry.isDirectory()) {
|
|
2160
|
+
await walk(abs);
|
|
2161
|
+
} else if (entry.isFile()) {
|
|
2162
|
+
const rel = relative6(outDir, abs);
|
|
2163
|
+
if (rel === MANIFEST_FILE || rel === LOCK_FILE) continue;
|
|
2164
|
+
found.push(rel);
|
|
2165
|
+
}
|
|
2166
|
+
}
|
|
2167
|
+
}
|
|
2168
|
+
await walk(outDir);
|
|
2169
|
+
return found.sort();
|
|
2170
|
+
}
|
|
2171
|
+
async function allOutputsExist(outDir, files) {
|
|
2172
|
+
const present = new Set(await listOutputFiles(outDir));
|
|
2173
|
+
return files.every((file) => present.has(file));
|
|
2174
|
+
}
|
|
2175
|
+
async function isManifestFresh(outDir, manifest, inputsHash) {
|
|
2176
|
+
if (manifest === null) return false;
|
|
2177
|
+
if (manifest.version !== VERSION) return false;
|
|
2178
|
+
if (manifest.hash !== inputsHash) return false;
|
|
2179
|
+
if (manifest.files.length === 0) return false;
|
|
2180
|
+
return allOutputsExist(outDir, manifest.files);
|
|
2181
|
+
}
|
|
2182
|
+
|
|
2086
2183
|
// src/util/debug-log.ts
|
|
2087
2184
|
var debugEnabled = false;
|
|
2088
2185
|
function setCodegenDebug(enabled) {
|
|
@@ -2095,6 +2192,12 @@ function debugWarn(message) {
|
|
|
2095
2192
|
// src/generate.ts
|
|
2096
2193
|
async function generate(config, inputRoutes = []) {
|
|
2097
2194
|
setCodegenDebug(config.debug);
|
|
2195
|
+
const inputsHash = await computeInputsHash(config);
|
|
2196
|
+
const manifest = await readManifest(config.codegen.outDir);
|
|
2197
|
+
if (await isManifestFresh(config.codegen.outDir, manifest, inputsHash)) {
|
|
2198
|
+
console.log(`[nestjs-codegen] ${config.codegen.outDir} up to date, skipped`);
|
|
2199
|
+
return;
|
|
2200
|
+
}
|
|
2098
2201
|
const extensions = config.extensions ?? [];
|
|
2099
2202
|
let routes = inputRoutes;
|
|
2100
2203
|
const ctx = createExtensionContext(config, () => routes);
|
|
@@ -2151,21 +2254,27 @@ async function generate(config, inputRoutes = []) {
|
|
|
2151
2254
|
if (extensions.length > 0) {
|
|
2152
2255
|
const extraFiles = await collectEmittedFiles(extensions, ctx);
|
|
2153
2256
|
for (const file of extraFiles) {
|
|
2154
|
-
const dest =
|
|
2257
|
+
const dest = join13(config.codegen.outDir, file.path);
|
|
2155
2258
|
await mkdir9(dirname2(dest), { recursive: true });
|
|
2156
|
-
await
|
|
2259
|
+
await writeFile10(dest, file.contents, "utf8");
|
|
2157
2260
|
}
|
|
2158
2261
|
}
|
|
2262
|
+
const outputFiles = await listOutputFiles(config.codegen.outDir);
|
|
2263
|
+
await writeManifest(config.codegen.outDir, {
|
|
2264
|
+
version: VERSION,
|
|
2265
|
+
hash: inputsHash,
|
|
2266
|
+
files: outputFiles
|
|
2267
|
+
});
|
|
2159
2268
|
}
|
|
2160
2269
|
|
|
2161
2270
|
// src/watch/watcher.ts
|
|
2162
|
-
import { readFile as
|
|
2163
|
-
import { join as
|
|
2271
|
+
import { readFile as readFile4 } from "fs/promises";
|
|
2272
|
+
import { join as join16 } from "path";
|
|
2164
2273
|
import chokidar from "chokidar";
|
|
2165
2274
|
|
|
2166
2275
|
// src/discovery/contracts-fast.ts
|
|
2167
|
-
import { join as
|
|
2168
|
-
import
|
|
2276
|
+
import { join as join14, resolve as resolve3 } from "path";
|
|
2277
|
+
import fg3 from "fast-glob";
|
|
2169
2278
|
import {
|
|
2170
2279
|
Node as Node8,
|
|
2171
2280
|
Project as Project3
|
|
@@ -3942,7 +4051,7 @@ async function discoverContractsFast(opts) {
|
|
|
3942
4051
|
const { cwd, glob, tsconfig } = opts;
|
|
3943
4052
|
const tsconfigPath = resolveTsconfigPath(cwd, tsconfig);
|
|
3944
4053
|
const project = createDiscoveryProject(tsconfigPath);
|
|
3945
|
-
const files = await
|
|
4054
|
+
const files = await fg3(glob, { cwd, absolute: true, onlyFiles: true });
|
|
3946
4055
|
for (const f of files) {
|
|
3947
4056
|
project.addSourceFileAtPath(f);
|
|
3948
4057
|
}
|
|
@@ -3950,7 +4059,7 @@ async function discoverContractsFast(opts) {
|
|
|
3950
4059
|
return extractAllRoutes(project);
|
|
3951
4060
|
}
|
|
3952
4061
|
function resolveTsconfigPath(cwd, tsconfig) {
|
|
3953
|
-
return tsconfig ? resolve3(tsconfig) :
|
|
4062
|
+
return tsconfig ? resolve3(tsconfig) : join14(cwd, "tsconfig.json");
|
|
3954
4063
|
}
|
|
3955
4064
|
function createDiscoveryProject(tsconfigPath) {
|
|
3956
4065
|
try {
|
|
@@ -4015,7 +4124,7 @@ var PersistentDiscovery = class _PersistentDiscovery {
|
|
|
4015
4124
|
const project = createDiscoveryProject(tsconfigPath);
|
|
4016
4125
|
bindDiscoveryContext(project, cwd, tsconfigPath);
|
|
4017
4126
|
const instance = new _PersistentDiscovery(project, cwd, glob);
|
|
4018
|
-
const files = await
|
|
4127
|
+
const files = await fg3(glob, { cwd, absolute: true, onlyFiles: true });
|
|
4019
4128
|
for (const f of files) {
|
|
4020
4129
|
project.addSourceFileAtPath(f);
|
|
4021
4130
|
instance.controllerPaths.add(f);
|
|
@@ -4044,7 +4153,7 @@ var PersistentDiscovery = class _PersistentDiscovery {
|
|
|
4044
4153
|
}
|
|
4045
4154
|
}
|
|
4046
4155
|
const globbed = new Set(
|
|
4047
|
-
await
|
|
4156
|
+
await fg3(this.glob, { cwd: this.cwd, absolute: true, onlyFiles: true })
|
|
4048
4157
|
);
|
|
4049
4158
|
for (const f of globbed) {
|
|
4050
4159
|
if (!this.controllerPaths.has(f)) {
|
|
@@ -4325,9 +4434,9 @@ function extractFromSourceFile(sourceFile, project) {
|
|
|
4325
4434
|
|
|
4326
4435
|
// src/watch/lock-file.ts
|
|
4327
4436
|
import { open } from "fs/promises";
|
|
4328
|
-
import { mkdir as mkdir10, readFile as
|
|
4329
|
-
import { join as
|
|
4330
|
-
var
|
|
4437
|
+
import { mkdir as mkdir10, readFile as readFile3, unlink } from "fs/promises";
|
|
4438
|
+
import { join as join15 } from "path";
|
|
4439
|
+
var LOCK_FILE2 = ".watcher.lock";
|
|
4331
4440
|
function isProcessAlive(pid) {
|
|
4332
4441
|
try {
|
|
4333
4442
|
process.kill(pid, 0);
|
|
@@ -4338,7 +4447,7 @@ function isProcessAlive(pid) {
|
|
|
4338
4447
|
}
|
|
4339
4448
|
async function acquireLock(outDir) {
|
|
4340
4449
|
await mkdir10(outDir, { recursive: true });
|
|
4341
|
-
const lockPath =
|
|
4450
|
+
const lockPath = join15(outDir, LOCK_FILE2);
|
|
4342
4451
|
const lockData = { pid: process.pid, startedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
4343
4452
|
try {
|
|
4344
4453
|
const fd = await open(lockPath, "wx");
|
|
@@ -4348,7 +4457,7 @@ async function acquireLock(outDir) {
|
|
|
4348
4457
|
} catch (err) {
|
|
4349
4458
|
if (err.code === "EEXIST") {
|
|
4350
4459
|
try {
|
|
4351
|
-
const raw = await
|
|
4460
|
+
const raw = await readFile3(lockPath, "utf8");
|
|
4352
4461
|
const existing = JSON.parse(raw);
|
|
4353
4462
|
if (isProcessAlive(existing.pid)) return null;
|
|
4354
4463
|
await unlink(lockPath);
|
|
@@ -4373,12 +4482,12 @@ async function acquireLock(outDir) {
|
|
|
4373
4482
|
var PAGES_DEBOUNCE_MS = 150;
|
|
4374
4483
|
var NO_OP_WATCHER = { close: async () => {
|
|
4375
4484
|
} };
|
|
4376
|
-
async function watch(config, onChange) {
|
|
4485
|
+
async function watch(config, onChange, options = {}) {
|
|
4377
4486
|
const lock = await acquireLock(config.codegen.outDir);
|
|
4378
4487
|
if (lock === null) {
|
|
4379
4488
|
let holderPid = "unknown";
|
|
4380
4489
|
try {
|
|
4381
|
-
const raw = await
|
|
4490
|
+
const raw = await readFile4(join16(config.codegen.outDir, ".watcher.lock"), "utf8");
|
|
4382
4491
|
const data = JSON.parse(raw);
|
|
4383
4492
|
if (data.pid !== void 0) holderPid = String(data.pid);
|
|
4384
4493
|
} catch {
|
|
@@ -4401,22 +4510,33 @@ async function watch(config, onChange) {
|
|
|
4401
4510
|
}
|
|
4402
4511
|
return discovery;
|
|
4403
4512
|
}
|
|
4404
|
-
|
|
4405
|
-
const initialRoutes = (await getDiscovery()).discover();
|
|
4406
|
-
lastRoutes = initialRoutes;
|
|
4407
|
-
await generate(config, initialRoutes);
|
|
4408
|
-
} catch (err) {
|
|
4409
|
-
console.warn(
|
|
4410
|
-
`[nestjs-codegen] Initial route discovery failed, falling back to pages-only: ${err instanceof Error ? err.message : String(err)}`
|
|
4411
|
-
);
|
|
4513
|
+
async function runInitialPass() {
|
|
4412
4514
|
try {
|
|
4413
|
-
await
|
|
4414
|
-
|
|
4515
|
+
const initialRoutes = (await getDiscovery()).discover();
|
|
4516
|
+
lastRoutes = initialRoutes;
|
|
4517
|
+
await generate(config, initialRoutes);
|
|
4518
|
+
} catch (err) {
|
|
4519
|
+
console.warn(
|
|
4520
|
+
`[nestjs-codegen] Initial route discovery failed, falling back to pages-only: ${err instanceof Error ? err.message : String(err)}`
|
|
4521
|
+
);
|
|
4522
|
+
try {
|
|
4523
|
+
await generate(config, lastRoutes);
|
|
4524
|
+
} catch {
|
|
4525
|
+
}
|
|
4415
4526
|
}
|
|
4416
4527
|
}
|
|
4528
|
+
if (options.deferInitialGenerate) {
|
|
4529
|
+
void runInitialPass().catch((err) => {
|
|
4530
|
+
console.warn(
|
|
4531
|
+
`[nestjs-codegen] Background initial generate failed: ${err instanceof Error ? err.message : String(err)}`
|
|
4532
|
+
);
|
|
4533
|
+
});
|
|
4534
|
+
} else {
|
|
4535
|
+
await runInitialPass();
|
|
4536
|
+
}
|
|
4417
4537
|
let pagesDebounceTimer;
|
|
4418
4538
|
const pagesGlob = config.pages?.glob ?? ".nestjs-codegen-no-pages";
|
|
4419
|
-
const pagesWatcher = chokidar.watch(
|
|
4539
|
+
const pagesWatcher = chokidar.watch(join16(config.codegen.cwd, pagesGlob), {
|
|
4420
4540
|
ignoreInitial: true,
|
|
4421
4541
|
persistent: true,
|
|
4422
4542
|
awaitWriteFinish: { stabilityThreshold: 80, pollInterval: 20 }
|
|
@@ -4443,7 +4563,7 @@ async function watch(config, onChange) {
|
|
|
4443
4563
|
pagesWatcher.on("unlink", schedulePagesRegenerate);
|
|
4444
4564
|
let contractsDebounceTimer;
|
|
4445
4565
|
const pendingChangedPaths = /* @__PURE__ */ new Set();
|
|
4446
|
-
const contractsWatcher = chokidar.watch(
|
|
4566
|
+
const contractsWatcher = chokidar.watch(join16(config.codegen.cwd, config.contracts.glob), {
|
|
4447
4567
|
ignoreInitial: true,
|
|
4448
4568
|
persistent: true,
|
|
4449
4569
|
awaitWriteFinish: { stabilityThreshold: 80, pollInterval: 20 }
|
|
@@ -4473,7 +4593,7 @@ async function watch(config, onChange) {
|
|
|
4473
4593
|
contractsWatcher.on("add", (p) => scheduleContractsRegenerate(p));
|
|
4474
4594
|
contractsWatcher.on("change", (p) => scheduleContractsRegenerate(p));
|
|
4475
4595
|
contractsWatcher.on("unlink", (p) => scheduleContractsRegenerate(p));
|
|
4476
|
-
const formsWatcher = chokidar.watch(
|
|
4596
|
+
const formsWatcher = chokidar.watch(join16(config.codegen.cwd, config.forms.watch), {
|
|
4477
4597
|
ignoreInitial: true,
|
|
4478
4598
|
persistent: true,
|
|
4479
4599
|
awaitWriteFinish: { stabilityThreshold: 80, pollInterval: 20 }
|
|
@@ -4583,7 +4703,7 @@ function createChainModuleRenderer(opts) {
|
|
|
4583
4703
|
}
|
|
4584
4704
|
|
|
4585
4705
|
// src/index.ts
|
|
4586
|
-
var VERSION = "0.
|
|
4706
|
+
var VERSION = "0.12.0";
|
|
4587
4707
|
export {
|
|
4588
4708
|
CodegenError,
|
|
4589
4709
|
ConfigError,
|