@dudousxd/nestjs-codegen 0.26.0 → 0.27.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 CHANGED
@@ -1,5 +1,37 @@
1
1
  # @dudousxd/nestjs-codegen
2
2
 
3
+ ## 0.27.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#101](https://github.com/DavideCarvalho/nestjs-codegen/pull/101) [`eb98ec8`](https://github.com/DavideCarvalho/nestjs-codegen/commit/eb98ec87be042b56a068bff9d4d71c35b6e67283) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - Several page globs and several Inertia apps (scopes).
8
+
9
+ - `pages.glob` takes one glob or an array. Each page is named relative to the static base of
10
+ the glob that matched it (brace globs included: the base stops at the first segment with
11
+ glob syntax), and two files resolving to the same page name are an error.
12
+ - `pages.scopes` declares more Inertia apps, one per `InertiaModule.forFeature({ scope })`:
13
+ `{ glob, prefix?, componentNameStrategy? }`. A scope's page names get the prefix
14
+ `'<scope>/'` by default (`minimal/pages/Home.tsx` → `minimal/Home`). Every page lands in
15
+ `InertiaPages`/`InertiaPageName`; `pages.d.ts` also exports `InertiaScopePages` and
16
+ `InertiaScopePageName<S>`, `components.json` records each page's `scope`, and the watcher and
17
+ the skip-if-unchanged hash cover every scope's pages.
18
+ - The top-level `scopes` option never had an effect; it is deprecated and now warns.
19
+
20
+ - [#100](https://github.com/DavideCarvalho/nestjs-codegen/pull/100) [`1cc8944`](https://github.com/DavideCarvalho/nestjs-codegen/commit/1cc8944126b794cdd5748e2417f448cd1e157395) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - Request handles are real Promises, and `api.ts` compiles under strict compiler flags.
21
+
22
+ - A generated leaf call (`api.users.create({ body })`) now returns a `RequestHandle<R>`: a
23
+ lazy, memoized `Promise<R>` that also carries `fetch()` and the extension members
24
+ (`queryKey`, `queryOptions`, `mutationOptions`, …). It can be returned from a TanStack
25
+ `mutationFn`/`queryFn`, passed to `Promise.all` or assigned to `Promise<T>` without calling
26
+ `.fetch()` first. Nothing is sent until it is awaited, so building `queryOptions()` or
27
+ reading `queryKey()` never fires a request. `.fetch()` keeps working.
28
+ - `api.ts` imports from `routes.ts` only the names it uses (no unused `ROUTES`/`RouteName`/…),
29
+ a leaf with no input to read takes no parameter, and `infiniteQueryOptions()` no longer
30
+ passes `getPreviousPageParam: undefined`. The output is clean under `noUnusedLocals`,
31
+ `noUnusedParameters`, `exactOptionalPropertyTypes`, `noImplicitOverride`,
32
+ `noUncheckedIndexedAccess` and `noPropertyAccessFromIndexSignature`; a fixture test compiles
33
+ it with all of them.
34
+
3
35
  ## 0.26.0
4
36
 
5
37
  ### Minor Changes
package/README.md CHANGED
@@ -53,8 +53,8 @@ export class AppModule {}
53
53
  ```
54
54
 
55
55
  The generated `api.ts` exports a `createApi(fetcher)` factory — create the client once,
56
- injecting your fetcher. Each endpoint is a **unified awaitable handle**: `await` it to run
57
- the request.
56
+ injecting your fetcher. Each endpoint is a **unified awaitable handle**: a lazy, memoized
57
+ `Promise` — `await` it (or return it from a TanStack `mutationFn`) to run the request.
58
58
 
59
59
  ```ts title="src/lib/api.ts"
60
60
  import { createApi } from '../generated/api';
package/dist/cli/main.cjs CHANGED
@@ -117,11 +117,32 @@ function validateUserConfig(userConfig) {
117
117
  "validation adapter is required \u2014 install @dudousxd/nestjs-codegen-zod and pass zodAdapter, or use @dudousxd/nestjs-codegen-valibot / -arktype"
118
118
  );
119
119
  }
120
- if (userConfig.pages && typeof userConfig.pages.glob !== "string") {
120
+ if (userConfig.pages && !isGlobInput(userConfig.pages.glob)) {
121
121
  throw new ConfigError(
122
- "Config validation failed: `pages.glob` must be a string when `pages` is set"
122
+ "Config validation failed: `pages.glob` must be a string or a non-empty array of strings when `pages` is set"
123
123
  );
124
124
  }
125
+ for (const [scope, scopeConfig] of Object.entries(userConfig.pages?.scopes ?? {})) {
126
+ if (scope === "default") {
127
+ throw new ConfigError(
128
+ 'Config validation failed: `pages.scopes` cannot declare "default" \u2014 the default app is `pages.glob` (InertiaModule.forRoot).'
129
+ );
130
+ }
131
+ if (!isGlobInput(scopeConfig?.glob)) {
132
+ throw new ConfigError(
133
+ `Config validation failed: \`pages.scopes.${scope}.glob\` must be a string or a non-empty array of strings`
134
+ );
135
+ }
136
+ }
137
+ if (userConfig.scopes && Object.keys(userConfig.scopes).length > 0) {
138
+ console.warn(
139
+ "[nestjs-codegen] The top-level `scopes` option has no effect and is deprecated. For several Inertia apps use `pages.scopes` (one entry per InertiaModule.forFeature scope); for several controller sets use one `contracts.glob` (e.g. a brace glob)."
140
+ );
141
+ }
142
+ }
143
+ function isGlobInput(value) {
144
+ if (typeof value === "string") return true;
145
+ return Array.isArray(value) && value.length > 0 && value.every((glob) => typeof glob === "string");
125
146
  }
126
147
  function applyDefaults(userConfig, cwd) {
127
148
  validateUserConfig(userConfig);
@@ -149,7 +170,17 @@ function applyDefaults(userConfig, cwd) {
149
170
  pages: userConfig.pages ? {
150
171
  glob: userConfig.pages.glob,
151
172
  propsExport: userConfig.pages.propsExport ?? "ComponentProps",
152
- componentNameStrategy: userConfig.pages.componentNameStrategy ?? "relative-no-ext"
173
+ componentNameStrategy: userConfig.pages.componentNameStrategy ?? "relative-no-ext",
174
+ scopes: Object.fromEntries(
175
+ Object.entries(userConfig.pages.scopes ?? {}).map(([scope, scopeConfig]) => [
176
+ scope,
177
+ {
178
+ glob: scopeConfig.glob,
179
+ prefix: scopeConfig.prefix ?? `${scope}/`,
180
+ componentNameStrategy: scopeConfig.componentNameStrategy ?? userConfig.pages?.componentNameStrategy ?? "relative-no-ext"
181
+ }
182
+ ])
183
+ )
153
184
  } : null,
154
185
  contracts: {
155
186
  glob: userConfig.contracts?.glob ?? "src/**/*.controller.ts",
@@ -226,23 +257,81 @@ var import_promises2 = require("fs/promises");
226
257
  var import_node_path2 = require("path");
227
258
  var import_fast_glob = __toESM(require("fast-glob"), 1);
228
259
  var NON_PAGE_FILE_RE = /\.(?:test|spec|stories|story)\.(?:tsx?|jsx?|vue|svelte)$/i;
260
+ var MAGIC_SEGMENT_RE = /[*?{}[\]()!]/;
261
+ function globStaticBase(glob) {
262
+ const segments = glob.split("/");
263
+ const staticSegments = [];
264
+ for (const segment of segments.slice(0, -1)) {
265
+ if (MAGIC_SEGMENT_RE.test(segment)) break;
266
+ staticSegments.push(segment);
267
+ }
268
+ return staticSegments.join("/");
269
+ }
229
270
  async function discoverPages(opts) {
230
- const allFiles = await (0, import_fast_glob.default)(opts.glob, { cwd: opts.cwd, absolute: true });
231
- const files = allFiles.filter((f) => !NON_PAGE_FILE_RE.test(f));
232
- files.sort();
233
- const globStatic = opts.glob.split("*")[0]?.replace(/\/$/, "") ?? "";
234
- const pagesBase = (0, import_node_path2.join)(opts.cwd, globStatic);
271
+ const globs = typeof opts.glob === "string" ? [opts.glob] : opts.glob;
272
+ const prefix = opts.prefix ?? "";
273
+ const scope = opts.scope ?? "default";
274
+ const seenFiles = /* @__PURE__ */ new Set();
235
275
  const out = [];
236
- for (const file of files) {
237
- const rel = (0, import_node_path2.relative)(opts.cwd, file);
238
- const nameRel = (0, import_node_path2.relative)(pagesBase, file);
239
- const name = computeName(nameRel, opts.componentNameStrategy);
240
- const source = await (0, import_promises2.readFile)(file, "utf8");
241
- const propsSource = extractPropsSource(source, opts.propsExport);
242
- out.push({ name, absolutePath: file, relativePath: rel, propsSource });
276
+ for (const glob of globs) {
277
+ const files = (await (0, import_fast_glob.default)(glob, { cwd: opts.cwd, absolute: true })).filter((f) => !NON_PAGE_FILE_RE.test(f) && !seenFiles.has(f)).sort();
278
+ const pagesBase = (0, import_node_path2.join)(opts.cwd, globStaticBase(glob));
279
+ for (const file of files) {
280
+ seenFiles.add(file);
281
+ const rel = (0, import_node_path2.relative)(opts.cwd, file);
282
+ const nameRel = (0, import_node_path2.relative)(pagesBase, file).split(import_node_path2.sep).join("/");
283
+ const name = `${prefix}${computeName(nameRel, opts.componentNameStrategy)}`;
284
+ const source = await (0, import_promises2.readFile)(file, "utf8");
285
+ const propsSource = extractPropsSource(source, opts.propsExport);
286
+ out.push({ name, absolutePath: file, relativePath: rel, propsSource, scope });
287
+ }
288
+ }
289
+ assertUniqueNames(out);
290
+ return out;
291
+ }
292
+ async function discoverPageScopes(config) {
293
+ const pages = config.pages;
294
+ if (!pages) return [];
295
+ const common = { cwd: config.codegen.cwd, propsExport: pages.propsExport };
296
+ const out = await discoverPages({
297
+ ...common,
298
+ glob: pages.glob,
299
+ componentNameStrategy: pages.componentNameStrategy
300
+ });
301
+ for (const [scope, scopeConfig] of Object.entries(pages.scopes ?? {})) {
302
+ out.push(
303
+ ...await discoverPages({
304
+ ...common,
305
+ glob: scopeConfig.glob,
306
+ componentNameStrategy: scopeConfig.componentNameStrategy,
307
+ prefix: scopeConfig.prefix,
308
+ scope
309
+ })
310
+ );
243
311
  }
312
+ assertUniqueNames(out);
244
313
  return out;
245
314
  }
315
+ function allPageGlobs(config) {
316
+ if (!config.pages) return [];
317
+ const asList = (glob) => typeof glob === "string" ? [glob] : glob;
318
+ return [
319
+ ...asList(config.pages.glob),
320
+ ...Object.values(config.pages.scopes ?? {}).flatMap((scope) => asList(scope.glob))
321
+ ];
322
+ }
323
+ function assertUniqueNames(pages) {
324
+ const byName = /* @__PURE__ */ new Map();
325
+ for (const page of pages) {
326
+ const previous = byName.get(page.name);
327
+ if (previous) {
328
+ throw new Error(
329
+ `Two Inertia pages resolve to the component name "${page.name}": ${previous.relativePath} (scope "${previous.scope}") and ${page.relativePath} (scope "${page.scope}"). Give one of them another name, directory or scope prefix.`
330
+ );
331
+ }
332
+ byName.set(page.name, page);
333
+ }
334
+ }
246
335
  function computeName(rel, strat) {
247
336
  if (typeof strat === "function") return strat(rel);
248
337
  const noExt = rel.replace(/\.(tsx?|vue|svelte)$/, "");
@@ -4113,28 +4202,28 @@ function renderFetcherRequest(req, binaryResponse) {
4113
4202
  }
4114
4203
  function emitReqHelper() {
4115
4204
  return [
4116
- "/** Awaitable request handle. `await api.x.y({...})` runs the fetch; extensions add query/mutation helpers. */",
4117
- "type __Req<R> = {",
4118
- " then<T1 = R, T2 = never>(",
4205
+ "/** An awaitable request handle: a lazy, memoized `Promise` that also carries `fetch()` and the members extensions add. */",
4206
+ "export type RequestHandle<R, M = {}> = Promise<R> & { fetch(): Promise<R> } & M;",
4207
+ "class __Request<R> extends Promise<R> {",
4208
+ " static override get [Symbol.species](): PromiseConstructor {",
4209
+ " return Promise;",
4210
+ " }",
4211
+ " private __run: () => Promise<R>;",
4212
+ " private __p: Promise<R> | undefined;",
4213
+ " constructor(run: () => Promise<R>) {",
4214
+ " super(() => {});",
4215
+ " this.__run = run;",
4216
+ " }",
4217
+ " override then<T1 = R, T2 = never>(",
4119
4218
  " onfulfilled?: ((value: R) => T1 | PromiseLike<T1>) | null,",
4120
4219
  " onrejected?: ((reason: unknown) => T2 | PromiseLike<T2>) | null,",
4121
- " ): Promise<T1 | T2>;",
4122
- " catch<T = never>(onrejected?: ((reason: unknown) => T | PromiseLike<T>) | null): Promise<R | T>;",
4123
- " finally(onfinally?: (() => void) | null): Promise<R>;",
4124
- " fetch(): Promise<R>;",
4125
- "};",
4126
- "function __req<R>(run: () => Promise<R>): __Req<R> {",
4127
- " let __p: Promise<R> | undefined;",
4128
- " const __promise = () => {",
4129
- " __p ??= run();",
4130
- " return __p;",
4131
- " };",
4132
- " return {",
4133
- " then: (onfulfilled, onrejected) => __promise().then(onfulfilled, onrejected),",
4134
- " catch: (onrejected) => __promise().catch(onrejected),",
4135
- " finally: (onfinally) => __promise().finally(onfinally),",
4136
- " fetch: run,",
4137
- " };",
4220
+ " ): Promise<T1 | T2> {",
4221
+ " this.__p ??= this.__run();",
4222
+ " return this.__p.then(onfulfilled, onrejected);",
4223
+ " }",
4224
+ "}",
4225
+ "function __req<R, M extends object = {}>(run: () => Promise<R>, members?: M): RequestHandle<R, M> {",
4226
+ " return Object.assign(new __Request<R>(run), { fetch: run }, members) as RequestHandle<R, M>;",
4138
4227
  "}",
4139
4228
  ""
4140
4229
  ];
@@ -4152,18 +4241,26 @@ function emitFilterFieldGuard() {
4152
4241
  ];
4153
4242
  }
4154
4243
  function renderLeaf(pad, objKey, req, requestExpr, members, streamExpr) {
4155
- const lines = [`${pad}${objKey}: (input?: ${req.inputType}) => ({`];
4156
- lines.push(`${pad} ...__req<${req.responseType}>(() => ${requestExpr}),`);
4244
+ const memberLines = [];
4157
4245
  if (req.filterFieldsExpr) {
4158
- lines.push(`${pad} filterFields: ${req.filterFieldsExpr},`);
4246
+ memberLines.push(`${pad} filterFields: ${req.filterFieldsExpr},`);
4159
4247
  }
4160
4248
  if (streamExpr) {
4161
- lines.push(`${pad} stream: () => ${streamExpr},`);
4249
+ memberLines.push(`${pad} stream: () => ${streamExpr},`);
4162
4250
  }
4163
4251
  for (const [name, value] of Object.entries(members)) {
4164
- lines.push(`${pad} ${name}: ${value},`);
4165
- }
4166
- lines.push(`${pad}}),`);
4252
+ memberLines.push(`${pad} ${name}: ${value},`);
4253
+ }
4254
+ const body = [requestExpr, ...memberLines].join("\n");
4255
+ const param = /\binput\b/.test(body) ? `input?: ${req.inputType}` : "";
4256
+ const lines = [`${pad}${objKey}: (${param}) =>`];
4257
+ if (memberLines.length === 0) {
4258
+ lines.push(`${pad} __req<${req.responseType}>(() => ${requestExpr}),`);
4259
+ return lines;
4260
+ }
4261
+ lines.push(`${pad} __req(() => ${requestExpr}, {`);
4262
+ lines.push(...memberLines);
4263
+ lines.push(`${pad} }),`);
4167
4264
  return lines;
4168
4265
  }
4169
4266
  function renderStreamExpr(req) {
@@ -4297,6 +4394,23 @@ var EMPTY_PATH_NAMESPACE = [
4297
4394
  function isClientCallable(route) {
4298
4395
  return route.method.toUpperCase() !== "ALL";
4299
4396
  }
4397
+ var ROUTES_IMPORT_PLACEHOLDER = "/* @@routes-import@@ */";
4398
+ var ROUTES_EXPORTS = [
4399
+ // Called, never mentioned in prose: match the call so a comment saying "route" doesn't count.
4400
+ { name: "route", typeOnly: false },
4401
+ { name: "ROUTES", typeOnly: false },
4402
+ { name: "RouteName", typeOnly: true },
4403
+ { name: "ExtractParams", typeOnly: true },
4404
+ { name: "RouteParams", typeOnly: true }
4405
+ ];
4406
+ function finishRoutesImport(lines) {
4407
+ const body = lines.filter((l) => l !== ROUTES_IMPORT_PLACEHOLDER).join("\n");
4408
+ const used = ROUTES_EXPORTS.filter(
4409
+ ({ name }) => new RegExp(name === "route" ? "\\broute\\(" : `\\b${name}\\b`).test(body)
4410
+ ).map(({ name, typeOnly }) => typeOnly ? `type ${name}` : name);
4411
+ const importLine = used.length ? `import { ${used.join(", ")} } from './routes.js';` : null;
4412
+ return lines.flatMap((l) => l === ROUTES_IMPORT_PLACEHOLDER ? importLine ? [importLine] : [] : [l]).join("\n");
4413
+ }
4300
4414
  function buildApiFile(routes, outDir, opts = {}) {
4301
4415
  const fetcherImportPath = opts.fetcherImportPath;
4302
4416
  const serialization = opts.serialization ?? "json";
@@ -4356,9 +4470,7 @@ function buildApiFile(routes, outDir, opts = {}) {
4356
4470
  for (const imp of ext.apiHeader?.(ctx)?.imports ?? []) pushImport(imp);
4357
4471
  }
4358
4472
  lines.push(...extImports);
4359
- lines.push(
4360
- "import { route, ROUTES, type RouteName, type ExtractParams, type RouteParams } from './routes.js';"
4361
- );
4473
+ lines.push(ROUTES_IMPORT_PLACEHOLDER);
4362
4474
  const runtimeImport = fetcherImportPath ?? "@dudousxd/nestjs-client";
4363
4475
  lines.push(`import type { Fetcher } from '${runtimeImport}';`);
4364
4476
  if (serialization === "json" && contracted.length > 0) {
@@ -4409,7 +4521,7 @@ function buildApiFile(routes, outDir, opts = {}) {
4409
4521
  lines.push(...statements, "");
4410
4522
  }
4411
4523
  }
4412
- return lines.join("\n");
4524
+ return finishRoutesImport(lines);
4413
4525
  }
4414
4526
  const tree = /* @__PURE__ */ new Map();
4415
4527
  for (const r of contracted) {
@@ -4462,7 +4574,7 @@ function buildApiFile(routes, outDir, opts = {}) {
4462
4574
  lines.push(...statements, "");
4463
4575
  }
4464
4576
  }
4465
- return lines.join("\n");
4577
+ return finishRoutesImport(lines);
4466
4578
  }
4467
4579
 
4468
4580
  // src/emit/emit-cache.ts
@@ -4475,6 +4587,7 @@ async function emitCache(pages, outDir) {
4475
4587
  const s = await (0, import_promises4.stat)(p.absolutePath);
4476
4588
  return {
4477
4589
  name: p.name,
4590
+ scope: p.scope ?? "default",
4478
4591
  relativePath: p.relativePath,
4479
4592
  mtime: s.mtime.toISOString()
4480
4593
  };
@@ -5266,10 +5379,11 @@ async function emitPages(pages, outDir, _options = {}) {
5266
5379
  }).join("\n");
5267
5380
  const propsHelper = "\nexport type InertiaProps<K extends InertiaPageName> = import('@dudousxd/nestjs-inertia').InertiaPages[K];\n";
5268
5381
  const sharedPropsBlock = buildSharedPropsBlock(_options.sharedProps ?? null);
5382
+ const scopesBlock = buildScopesBlock(pages);
5269
5383
  const content = `// Generated by @dudousxd/nestjs-codegen. Do not edit.
5270
5384
 
5271
5385
  export type InertiaPageName = ${pageNameUnion};
5272
- ${propsHelper}
5386
+ ${propsHelper}${scopesBlock}
5273
5387
  declare module '@dudousxd/nestjs-inertia' {
5274
5388
  interface InertiaPages {
5275
5389
  ${augBody}
@@ -5278,6 +5392,31 @@ ${sharedPropsBlock}}
5278
5392
  `;
5279
5393
  await (0, import_promises9.writeFile)((0, import_node_path13.join)(outDir, "pages.d.ts"), content, "utf8");
5280
5394
  }
5395
+ function buildScopesBlock(pages) {
5396
+ const byScope = /* @__PURE__ */ new Map();
5397
+ for (const page of pages) {
5398
+ const scope = page.scope ?? "default";
5399
+ const names = byScope.get(scope) ?? [];
5400
+ names.push(JSON.stringify(page.name));
5401
+ byScope.set(scope, names);
5402
+ }
5403
+ if (![...byScope.keys()].some((scope) => scope !== "default")) return "";
5404
+ if (!byScope.has("default")) byScope.set("default", []);
5405
+ const scopes = ["default", ...[...byScope.keys()].filter((s) => s !== "default")];
5406
+ const body = scopes.map((scope) => {
5407
+ const key = needsQuotes(scope) ? JSON.stringify(scope) : scope;
5408
+ const names = byScope.get(scope) ?? [];
5409
+ return ` ${key}: ${names.length ? names.join(" | ") : "never"};`;
5410
+ }).join("\n");
5411
+ return `
5412
+ /** The page names of each Inertia app: \`default\` (forRoot) and every \`pages.scopes\` entry. */
5413
+ export interface InertiaScopePages {
5414
+ ${body}
5415
+ }
5416
+
5417
+ export type InertiaScopePageName<S extends keyof InertiaScopePages> = InertiaScopePages[S];
5418
+ `;
5419
+ }
5281
5420
  function buildSharedPropsBlock(sharedProps) {
5282
5421
  if (!sharedProps) return "";
5283
5422
  if (sharedProps.isImportRef) {
@@ -5485,8 +5624,7 @@ function diffConfigKeyHashes(previous, current) {
5485
5624
  return [...keys].filter((key) => previous[key] !== current[key]).sort();
5486
5625
  }
5487
5626
  async function discoverInputFiles(config) {
5488
- const globs = [config.contracts.glob, config.forms.watch];
5489
- if (config.pages) globs.push(config.pages.glob);
5627
+ const globs = [config.contracts.glob, config.forms.watch, ...allPageGlobs(config)];
5490
5628
  const cwd = config.codegen.cwd;
5491
5629
  const matched = await (0, import_fast_glob3.default)(globs, { cwd, absolute: true, onlyFiles: true });
5492
5630
  return [...new Set(matched)].sort();
@@ -5617,12 +5755,7 @@ async function generate(config, inputRoutes = [], entryPoint = "cli") {
5617
5755
  }
5618
5756
  if (config.pages) {
5619
5757
  const pagesConfig = config.pages;
5620
- const pages = await discoverPages({
5621
- glob: pagesConfig.glob,
5622
- cwd: config.codegen.cwd,
5623
- propsExport: pagesConfig.propsExport,
5624
- componentNameStrategy: pagesConfig.componentNameStrategy
5625
- });
5758
+ const pages = await discoverPageScopes(config);
5626
5759
  const sharedProps = discoverSharedPropsFromConfig(config);
5627
5760
  await emitPages(pages, config.codegen.outDir, {
5628
5761
  propsExport: pagesConfig.propsExport,
@@ -5797,12 +5930,17 @@ async function watch(config, onChange, options = {}) {
5797
5930
  await runInitialPass();
5798
5931
  }
5799
5932
  let pagesDebounceTimer;
5800
- const pagesGlob = config.pages?.glob ?? ".nestjs-codegen-no-pages";
5801
- const pagesWatcher = import_chokidar.default.watch((0, import_node_path18.join)(config.codegen.cwd, pagesGlob), {
5802
- ignoreInitial: true,
5803
- persistent: true,
5804
- awaitWriteFinish: { stabilityThreshold: 80, pollInterval: 20 }
5805
- });
5933
+ const pageGlobs = allPageGlobs(config);
5934
+ const pagesWatcher = import_chokidar.default.watch(
5935
+ (pageGlobs.length ? pageGlobs : [".nestjs-codegen-no-pages"]).map(
5936
+ (glob) => (0, import_node_path18.join)(config.codegen.cwd, glob)
5937
+ ),
5938
+ {
5939
+ ignoreInitial: true,
5940
+ persistent: true,
5941
+ awaitWriteFinish: { stabilityThreshold: 80, pollInterval: 20 }
5942
+ }
5943
+ );
5806
5944
  function schedulePagesRegenerate() {
5807
5945
  if (pagesDebounceTimer !== void 0) {
5808
5946
  clearTimeout(pagesDebounceTimer);
@@ -5882,7 +6020,7 @@ async function watch(config, onChange, options = {}) {
5882
6020
  }
5883
6021
 
5884
6022
  // src/index.ts
5885
- var VERSION = "0.26.0";
6023
+ var VERSION = "0.27.0";
5886
6024
 
5887
6025
  // src/cli/codegen.ts
5888
6026
  async function runCodegen(opts = {}) {