@dudousxd/nestjs-codegen 0.26.0 → 0.27.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,6 +1,6 @@
1
1
  import * as _nestjs_common from '@nestjs/common';
2
2
  import { DynamicModule, OnApplicationBootstrap, OnModuleDestroy, ExecutionContext } from '@nestjs/common';
3
- import { U as UserConfig } from '../index-Bbw73Kkb.cjs';
3
+ import { U as UserConfig } from '../index-Dc4s883u.cjs';
4
4
  import 'ts-morph';
5
5
 
6
6
  /**
@@ -1,6 +1,6 @@
1
1
  import * as _nestjs_common from '@nestjs/common';
2
2
  import { DynamicModule, OnApplicationBootstrap, OnModuleDestroy, ExecutionContext } from '@nestjs/common';
3
- import { U as UserConfig } from '../index-Bbw73Kkb.js';
3
+ import { U as UserConfig } from '../index-Dc4s883u.js';
4
4
  import 'ts-morph';
5
5
 
6
6
  /**
@@ -70,11 +70,32 @@ function validateUserConfig(userConfig) {
70
70
  "validation adapter is required \u2014 install @dudousxd/nestjs-codegen-zod and pass zodAdapter, or use @dudousxd/nestjs-codegen-valibot / -arktype"
71
71
  );
72
72
  }
73
- if (userConfig.pages && typeof userConfig.pages.glob !== "string") {
73
+ if (userConfig.pages && !isGlobInput(userConfig.pages.glob)) {
74
74
  throw new ConfigError(
75
- "Config validation failed: `pages.glob` must be a string when `pages` is set"
75
+ "Config validation failed: `pages.glob` must be a string or a non-empty array of strings when `pages` is set"
76
76
  );
77
77
  }
78
+ for (const [scope, scopeConfig] of Object.entries(userConfig.pages?.scopes ?? {})) {
79
+ if (scope === "default") {
80
+ throw new ConfigError(
81
+ 'Config validation failed: `pages.scopes` cannot declare "default" \u2014 the default app is `pages.glob` (InertiaModule.forRoot).'
82
+ );
83
+ }
84
+ if (!isGlobInput(scopeConfig?.glob)) {
85
+ throw new ConfigError(
86
+ `Config validation failed: \`pages.scopes.${scope}.glob\` must be a string or a non-empty array of strings`
87
+ );
88
+ }
89
+ }
90
+ if (userConfig.scopes && Object.keys(userConfig.scopes).length > 0) {
91
+ console.warn(
92
+ "[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)."
93
+ );
94
+ }
95
+ }
96
+ function isGlobInput(value) {
97
+ if (typeof value === "string") return true;
98
+ return Array.isArray(value) && value.length > 0 && value.every((glob) => typeof glob === "string");
78
99
  }
79
100
  function applyDefaults(userConfig, cwd) {
80
101
  validateUserConfig(userConfig);
@@ -102,7 +123,17 @@ function applyDefaults(userConfig, cwd) {
102
123
  pages: userConfig.pages ? {
103
124
  glob: userConfig.pages.glob,
104
125
  propsExport: userConfig.pages.propsExport ?? "ComponentProps",
105
- componentNameStrategy: userConfig.pages.componentNameStrategy ?? "relative-no-ext"
126
+ componentNameStrategy: userConfig.pages.componentNameStrategy ?? "relative-no-ext",
127
+ scopes: Object.fromEntries(
128
+ Object.entries(userConfig.pages.scopes ?? {}).map(([scope, scopeConfig]) => [
129
+ scope,
130
+ {
131
+ glob: scopeConfig.glob,
132
+ prefix: scopeConfig.prefix ?? `${scope}/`,
133
+ componentNameStrategy: scopeConfig.componentNameStrategy ?? userConfig.pages?.componentNameStrategy ?? "relative-no-ext"
134
+ }
135
+ ])
136
+ )
106
137
  } : null,
107
138
  contracts: {
108
139
  glob: userConfig.contracts?.glob ?? "src/**/*.controller.ts",
@@ -255,10 +286,11 @@ function resolveModuleSpecifier(moduleSpecifier, sourceFile, project) {
255
286
  }
256
287
  return [];
257
288
  }
258
- function resolveImportedType(name, sourceFile, project) {
289
+ function resolveImportedType(name, sourceFile, project, seen = /* @__PURE__ */ new Set()) {
259
290
  for (const importDecl of sourceFile.getImportDeclarations()) {
260
- const namedImport = importDecl.getNamedImports().find((n) => n.getName() === name);
291
+ const namedImport = importDecl.getNamedImports().find((n) => (n.getAliasNode()?.getText() ?? n.getName()) === name);
261
292
  if (!namedImport) continue;
293
+ const sourceName = namedImport.getName();
262
294
  const moduleSpecifier = importDecl.getModuleSpecifierValue();
263
295
  const candidates = resolveModuleSpecifier(moduleSpecifier, sourceFile, project);
264
296
  for (const candidate of candidates) {
@@ -270,17 +302,17 @@ function resolveImportedType(name, sourceFile, project) {
270
302
  continue;
271
303
  }
272
304
  }
273
- const result = findTypeInFile(name, importedFile);
305
+ const result = findTypeInFile(sourceName, importedFile);
274
306
  if (result) return result;
275
- const viaReExport = resolveReExportedType(name, importedFile, project, /* @__PURE__ */ new Set());
307
+ const viaReExport = resolveReExportedType(sourceName, importedFile, project, /* @__PURE__ */ new Set());
276
308
  if (viaReExport) return viaReExport;
277
309
  }
278
310
  if (candidates.length === 0) {
279
- const viaCompiler = resolveBareSpecifierType(name, importDecl, project);
311
+ const viaCompiler = resolveBareSpecifierType(sourceName, importDecl, project);
280
312
  if (viaCompiler) return viaCompiler;
281
313
  }
282
314
  }
283
- return resolveReExportedType(name, sourceFile, project, /* @__PURE__ */ new Set());
315
+ return resolveReExportedType(name, sourceFile, project, seen);
284
316
  }
285
317
  function resolveBareSpecifierType(name, importDecl, project) {
286
318
  let target;
@@ -295,9 +327,9 @@ function resolveBareSpecifierType(name, importDecl, project) {
295
327
  return resolveReExportedType(name, target, project, /* @__PURE__ */ new Set());
296
328
  }
297
329
  function resolveReExportedType(name, file, project, seen) {
298
- const filePath = file.getFilePath();
299
- if (seen.has(filePath)) return null;
300
- seen.add(filePath);
330
+ const visit = `${file.getFilePath()}#${name}`;
331
+ if (seen.has(visit)) return null;
332
+ seen.add(visit);
301
333
  for (const exportDecl of file.getExportDeclarations()) {
302
334
  const moduleSpecifier = exportDecl.getModuleSpecifierValue();
303
335
  const namedExports = exportDecl.getNamedExports();
@@ -319,7 +351,7 @@ function resolveReExportedType(name, file, project, seen) {
319
351
  const sourceName = namedExports.find((n) => (n.getAliasNode()?.getText() ?? n.getName()) === name)?.getName() ?? name;
320
352
  const local = findTypeInFile(sourceName, file);
321
353
  if (local) return local;
322
- const imported = resolveImportedType(sourceName, file, project);
354
+ const imported = resolveImportedType(sourceName, file, project, seen);
323
355
  if (imported) return imported;
324
356
  }
325
357
  return null;
@@ -3344,32 +3376,86 @@ function extractFromSourceFile(sourceFile, project) {
3344
3376
  return routes;
3345
3377
  }
3346
3378
 
3347
- // src/generate.ts
3348
- import { mkdir as mkdir9, writeFile as writeFile9 } from "fs/promises";
3349
- import { dirname as dirname4, join as join13 } from "path";
3350
-
3351
3379
  // src/discovery/pages.ts
3352
3380
  import { readFile } from "fs/promises";
3353
- import { join as join3, relative as relative2 } from "path";
3381
+ import { join as join3, relative as relative2, sep as sep2 } from "path";
3354
3382
  import fg2 from "fast-glob";
3355
3383
  var NON_PAGE_FILE_RE = /\.(?:test|spec|stories|story)\.(?:tsx?|jsx?|vue|svelte)$/i;
3384
+ var MAGIC_SEGMENT_RE = /[*?{}[\]()!]/;
3385
+ function globStaticBase(glob) {
3386
+ const segments = glob.split("/");
3387
+ const staticSegments = [];
3388
+ for (const segment of segments.slice(0, -1)) {
3389
+ if (MAGIC_SEGMENT_RE.test(segment)) break;
3390
+ staticSegments.push(segment);
3391
+ }
3392
+ return staticSegments.join("/");
3393
+ }
3356
3394
  async function discoverPages(opts) {
3357
- const allFiles = await fg2(opts.glob, { cwd: opts.cwd, absolute: true });
3358
- const files = allFiles.filter((f) => !NON_PAGE_FILE_RE.test(f));
3359
- files.sort();
3360
- const globStatic = opts.glob.split("*")[0]?.replace(/\/$/, "") ?? "";
3361
- const pagesBase = join3(opts.cwd, globStatic);
3395
+ const globs = typeof opts.glob === "string" ? [opts.glob] : opts.glob;
3396
+ const prefix = opts.prefix ?? "";
3397
+ const scope = opts.scope ?? "default";
3398
+ const seenFiles = /* @__PURE__ */ new Set();
3362
3399
  const out = [];
3363
- for (const file of files) {
3364
- const rel = relative2(opts.cwd, file);
3365
- const nameRel = relative2(pagesBase, file);
3366
- const name = computeName(nameRel, opts.componentNameStrategy);
3367
- const source = await readFile(file, "utf8");
3368
- const propsSource = extractPropsSource(source, opts.propsExport);
3369
- out.push({ name, absolutePath: file, relativePath: rel, propsSource });
3400
+ for (const glob of globs) {
3401
+ const files = (await fg2(glob, { cwd: opts.cwd, absolute: true })).filter((f) => !NON_PAGE_FILE_RE.test(f) && !seenFiles.has(f)).sort();
3402
+ const pagesBase = join3(opts.cwd, globStaticBase(glob));
3403
+ for (const file of files) {
3404
+ seenFiles.add(file);
3405
+ const rel = relative2(opts.cwd, file);
3406
+ const nameRel = relative2(pagesBase, file).split(sep2).join("/");
3407
+ const name = `${prefix}${computeName(nameRel, opts.componentNameStrategy)}`;
3408
+ const source = await readFile(file, "utf8");
3409
+ const propsSource = extractPropsSource(source, opts.propsExport);
3410
+ out.push({ name, absolutePath: file, relativePath: rel, propsSource, scope });
3411
+ }
3412
+ }
3413
+ assertUniqueNames(out);
3414
+ return out;
3415
+ }
3416
+ async function discoverPageScopes(config) {
3417
+ const pages = config.pages;
3418
+ if (!pages) return [];
3419
+ const common = { cwd: config.codegen.cwd, propsExport: pages.propsExport };
3420
+ const out = await discoverPages({
3421
+ ...common,
3422
+ glob: pages.glob,
3423
+ componentNameStrategy: pages.componentNameStrategy
3424
+ });
3425
+ for (const [scope, scopeConfig] of Object.entries(pages.scopes ?? {})) {
3426
+ out.push(
3427
+ ...await discoverPages({
3428
+ ...common,
3429
+ glob: scopeConfig.glob,
3430
+ componentNameStrategy: scopeConfig.componentNameStrategy,
3431
+ prefix: scopeConfig.prefix,
3432
+ scope
3433
+ })
3434
+ );
3370
3435
  }
3436
+ assertUniqueNames(out);
3371
3437
  return out;
3372
3438
  }
3439
+ function allPageGlobs(config) {
3440
+ if (!config.pages) return [];
3441
+ const asList = (glob) => typeof glob === "string" ? [glob] : glob;
3442
+ return [
3443
+ ...asList(config.pages.glob),
3444
+ ...Object.values(config.pages.scopes ?? {}).flatMap((scope) => asList(scope.glob))
3445
+ ];
3446
+ }
3447
+ function assertUniqueNames(pages) {
3448
+ const byName = /* @__PURE__ */ new Map();
3449
+ for (const page of pages) {
3450
+ const previous = byName.get(page.name);
3451
+ if (previous) {
3452
+ throw new Error(
3453
+ `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.`
3454
+ );
3455
+ }
3456
+ byName.set(page.name, page);
3457
+ }
3458
+ }
3373
3459
  function computeName(rel, strat) {
3374
3460
  if (typeof strat === "function") return strat(rel);
3375
3461
  const noExt = rel.replace(/\.(tsx?|vue|svelte)$/, "");
@@ -3400,6 +3486,10 @@ function extractPropsSource(source, exportName) {
3400
3486
  return source.slice(start);
3401
3487
  }
3402
3488
 
3489
+ // src/generate.ts
3490
+ import { mkdir as mkdir9, writeFile as writeFile9 } from "fs/promises";
3491
+ import { dirname as dirname4, join as join13 } from "path";
3492
+
3403
3493
  // src/discovery/shared-props.ts
3404
3494
  import { join as join4 } from "path";
3405
3495
  import { Node as Node11, Project as Project4, SyntaxKind as SyntaxKind4 } from "ts-morph";
@@ -4034,28 +4124,28 @@ function renderFetcherRequest(req, binaryResponse) {
4034
4124
  }
4035
4125
  function emitReqHelper() {
4036
4126
  return [
4037
- "/** Awaitable request handle. `await api.x.y({...})` runs the fetch; extensions add query/mutation helpers. */",
4038
- "type __Req<R> = {",
4039
- " then<T1 = R, T2 = never>(",
4127
+ "/** An awaitable request handle: a lazy, memoized `Promise` that also carries `fetch()` and the members extensions add. */",
4128
+ "export type RequestHandle<R, M = {}> = Promise<R> & { fetch(): Promise<R> } & M;",
4129
+ "class __Request<R> extends Promise<R> {",
4130
+ " static override get [Symbol.species](): PromiseConstructor {",
4131
+ " return Promise;",
4132
+ " }",
4133
+ " private __run: () => Promise<R>;",
4134
+ " private __p: Promise<R> | undefined;",
4135
+ " constructor(run: () => Promise<R>) {",
4136
+ " super(() => {});",
4137
+ " this.__run = run;",
4138
+ " }",
4139
+ " override then<T1 = R, T2 = never>(",
4040
4140
  " onfulfilled?: ((value: R) => T1 | PromiseLike<T1>) | null,",
4041
4141
  " onrejected?: ((reason: unknown) => T2 | PromiseLike<T2>) | null,",
4042
- " ): Promise<T1 | T2>;",
4043
- " catch<T = never>(onrejected?: ((reason: unknown) => T | PromiseLike<T>) | null): Promise<R | T>;",
4044
- " finally(onfinally?: (() => void) | null): Promise<R>;",
4045
- " fetch(): Promise<R>;",
4046
- "};",
4047
- "function __req<R>(run: () => Promise<R>): __Req<R> {",
4048
- " let __p: Promise<R> | undefined;",
4049
- " const __promise = () => {",
4050
- " __p ??= run();",
4051
- " return __p;",
4052
- " };",
4053
- " return {",
4054
- " then: (onfulfilled, onrejected) => __promise().then(onfulfilled, onrejected),",
4055
- " catch: (onrejected) => __promise().catch(onrejected),",
4056
- " finally: (onfinally) => __promise().finally(onfinally),",
4057
- " fetch: run,",
4058
- " };",
4142
+ " ): Promise<T1 | T2> {",
4143
+ " this.__p ??= this.__run();",
4144
+ " return this.__p.then(onfulfilled, onrejected);",
4145
+ " }",
4146
+ "}",
4147
+ "function __req<R, M extends object = {}>(run: () => Promise<R>, members?: M): RequestHandle<R, M> {",
4148
+ " return Object.assign(new __Request<R>(run), { fetch: run }, members) as RequestHandle<R, M>;",
4059
4149
  "}",
4060
4150
  ""
4061
4151
  ];
@@ -4073,18 +4163,26 @@ function emitFilterFieldGuard() {
4073
4163
  ];
4074
4164
  }
4075
4165
  function renderLeaf(pad, objKey, req, requestExpr, members, streamExpr) {
4076
- const lines = [`${pad}${objKey}: (input?: ${req.inputType}) => ({`];
4077
- lines.push(`${pad} ...__req<${req.responseType}>(() => ${requestExpr}),`);
4166
+ const memberLines = [];
4078
4167
  if (req.filterFieldsExpr) {
4079
- lines.push(`${pad} filterFields: ${req.filterFieldsExpr},`);
4168
+ memberLines.push(`${pad} filterFields: ${req.filterFieldsExpr},`);
4080
4169
  }
4081
4170
  if (streamExpr) {
4082
- lines.push(`${pad} stream: () => ${streamExpr},`);
4171
+ memberLines.push(`${pad} stream: () => ${streamExpr},`);
4083
4172
  }
4084
4173
  for (const [name, value] of Object.entries(members)) {
4085
- lines.push(`${pad} ${name}: ${value},`);
4086
- }
4087
- lines.push(`${pad}}),`);
4174
+ memberLines.push(`${pad} ${name}: ${value},`);
4175
+ }
4176
+ const body = [requestExpr, ...memberLines].join("\n");
4177
+ const param = /\binput\b/.test(body) ? `input?: ${req.inputType}` : "";
4178
+ const lines = [`${pad}${objKey}: (${param}) =>`];
4179
+ if (memberLines.length === 0) {
4180
+ lines.push(`${pad} __req<${req.responseType}>(() => ${requestExpr}),`);
4181
+ return lines;
4182
+ }
4183
+ lines.push(`${pad} __req(() => ${requestExpr}, {`);
4184
+ lines.push(...memberLines);
4185
+ lines.push(`${pad} }),`);
4088
4186
  return lines;
4089
4187
  }
4090
4188
  function renderStreamExpr(req) {
@@ -4218,6 +4316,23 @@ var EMPTY_PATH_NAMESPACE = [
4218
4316
  function isClientCallable(route) {
4219
4317
  return route.method.toUpperCase() !== "ALL";
4220
4318
  }
4319
+ var ROUTES_IMPORT_PLACEHOLDER = "/* @@routes-import@@ */";
4320
+ var ROUTES_EXPORTS = [
4321
+ // Called, never mentioned in prose: match the call so a comment saying "route" doesn't count.
4322
+ { name: "route", typeOnly: false },
4323
+ { name: "ROUTES", typeOnly: false },
4324
+ { name: "RouteName", typeOnly: true },
4325
+ { name: "ExtractParams", typeOnly: true },
4326
+ { name: "RouteParams", typeOnly: true }
4327
+ ];
4328
+ function finishRoutesImport(lines) {
4329
+ const body = lines.filter((l) => l !== ROUTES_IMPORT_PLACEHOLDER).join("\n");
4330
+ const used = ROUTES_EXPORTS.filter(
4331
+ ({ name }) => new RegExp(name === "route" ? "\\broute\\(" : `\\b${name}\\b`).test(body)
4332
+ ).map(({ name, typeOnly }) => typeOnly ? `type ${name}` : name);
4333
+ const importLine = used.length ? `import { ${used.join(", ")} } from './routes.js';` : null;
4334
+ return lines.flatMap((l) => l === ROUTES_IMPORT_PLACEHOLDER ? importLine ? [importLine] : [] : [l]).join("\n");
4335
+ }
4221
4336
  function buildApiFile(routes, outDir, opts = {}) {
4222
4337
  const fetcherImportPath = opts.fetcherImportPath;
4223
4338
  const serialization = opts.serialization ?? "json";
@@ -4277,9 +4392,7 @@ function buildApiFile(routes, outDir, opts = {}) {
4277
4392
  for (const imp of ext.apiHeader?.(ctx)?.imports ?? []) pushImport(imp);
4278
4393
  }
4279
4394
  lines.push(...extImports);
4280
- lines.push(
4281
- "import { route, ROUTES, type RouteName, type ExtractParams, type RouteParams } from './routes.js';"
4282
- );
4395
+ lines.push(ROUTES_IMPORT_PLACEHOLDER);
4283
4396
  const runtimeImport = fetcherImportPath ?? "@dudousxd/nestjs-client";
4284
4397
  lines.push(`import type { Fetcher } from '${runtimeImport}';`);
4285
4398
  if (serialization === "json" && contracted.length > 0) {
@@ -4330,7 +4443,7 @@ function buildApiFile(routes, outDir, opts = {}) {
4330
4443
  lines.push(...statements, "");
4331
4444
  }
4332
4445
  }
4333
- return lines.join("\n");
4446
+ return finishRoutesImport(lines);
4334
4447
  }
4335
4448
  const tree = /* @__PURE__ */ new Map();
4336
4449
  for (const r of contracted) {
@@ -4383,7 +4496,7 @@ function buildApiFile(routes, outDir, opts = {}) {
4383
4496
  lines.push(...statements, "");
4384
4497
  }
4385
4498
  }
4386
- return lines.join("\n");
4499
+ return finishRoutesImport(lines);
4387
4500
  }
4388
4501
 
4389
4502
  // src/emit/emit-cache.ts
@@ -4396,6 +4509,7 @@ async function emitCache(pages, outDir) {
4396
4509
  const s = await stat(p.absolutePath);
4397
4510
  return {
4398
4511
  name: p.name,
4512
+ scope: p.scope ?? "default",
4399
4513
  relativePath: p.relativePath,
4400
4514
  mtime: s.mtime.toISOString()
4401
4515
  };
@@ -5187,10 +5301,11 @@ async function emitPages(pages, outDir, _options = {}) {
5187
5301
  }).join("\n");
5188
5302
  const propsHelper = "\nexport type InertiaProps<K extends InertiaPageName> = import('@dudousxd/nestjs-inertia').InertiaPages[K];\n";
5189
5303
  const sharedPropsBlock = buildSharedPropsBlock(_options.sharedProps ?? null);
5304
+ const scopesBlock = buildScopesBlock(pages);
5190
5305
  const content = `// Generated by @dudousxd/nestjs-codegen. Do not edit.
5191
5306
 
5192
5307
  export type InertiaPageName = ${pageNameUnion};
5193
- ${propsHelper}
5308
+ ${propsHelper}${scopesBlock}
5194
5309
  declare module '@dudousxd/nestjs-inertia' {
5195
5310
  interface InertiaPages {
5196
5311
  ${augBody}
@@ -5199,6 +5314,31 @@ ${sharedPropsBlock}}
5199
5314
  `;
5200
5315
  await writeFile7(join11(outDir, "pages.d.ts"), content, "utf8");
5201
5316
  }
5317
+ function buildScopesBlock(pages) {
5318
+ const byScope = /* @__PURE__ */ new Map();
5319
+ for (const page of pages) {
5320
+ const scope = page.scope ?? "default";
5321
+ const names = byScope.get(scope) ?? [];
5322
+ names.push(JSON.stringify(page.name));
5323
+ byScope.set(scope, names);
5324
+ }
5325
+ if (![...byScope.keys()].some((scope) => scope !== "default")) return "";
5326
+ if (!byScope.has("default")) byScope.set("default", []);
5327
+ const scopes = ["default", ...[...byScope.keys()].filter((s) => s !== "default")];
5328
+ const body = scopes.map((scope) => {
5329
+ const key = needsQuotes(scope) ? JSON.stringify(scope) : scope;
5330
+ const names = byScope.get(scope) ?? [];
5331
+ return ` ${key}: ${names.length ? names.join(" | ") : "never"};`;
5332
+ }).join("\n");
5333
+ return `
5334
+ /** The page names of each Inertia app: \`default\` (forRoot) and every \`pages.scopes\` entry. */
5335
+ export interface InertiaScopePages {
5336
+ ${body}
5337
+ }
5338
+
5339
+ export type InertiaScopePageName<S extends keyof InertiaScopePages> = InertiaScopePages[S];
5340
+ `;
5341
+ }
5202
5342
  function buildSharedPropsBlock(sharedProps) {
5203
5343
  if (!sharedProps) return "";
5204
5344
  if (sharedProps.isImportRef) {
@@ -5380,12 +5520,7 @@ async function generate(config, inputRoutes = [], entryPoint = "cli") {
5380
5520
  }
5381
5521
  if (config.pages) {
5382
5522
  const pagesConfig = config.pages;
5383
- const pages = await discoverPages({
5384
- glob: pagesConfig.glob,
5385
- cwd: config.codegen.cwd,
5386
- propsExport: pagesConfig.propsExport,
5387
- componentNameStrategy: pagesConfig.componentNameStrategy
5388
- });
5523
+ const pages = await discoverPageScopes(config);
5389
5524
  const sharedProps = discoverSharedPropsFromConfig(config);
5390
5525
  await emitPages(pages, config.codegen.outDir, {
5391
5526
  propsExport: pagesConfig.propsExport,
@@ -5560,12 +5695,17 @@ async function watch(config, onChange, options = {}) {
5560
5695
  await runInitialPass();
5561
5696
  }
5562
5697
  let pagesDebounceTimer;
5563
- const pagesGlob = config.pages?.glob ?? ".nestjs-codegen-no-pages";
5564
- const pagesWatcher = chokidar.watch(join15(config.codegen.cwd, pagesGlob), {
5565
- ignoreInitial: true,
5566
- persistent: true,
5567
- awaitWriteFinish: { stabilityThreshold: 80, pollInterval: 20 }
5568
- });
5698
+ const pageGlobs = allPageGlobs(config);
5699
+ const pagesWatcher = chokidar.watch(
5700
+ (pageGlobs.length ? pageGlobs : [".nestjs-codegen-no-pages"]).map(
5701
+ (glob) => join15(config.codegen.cwd, glob)
5702
+ ),
5703
+ {
5704
+ ignoreInitial: true,
5705
+ persistent: true,
5706
+ awaitWriteFinish: { stabilityThreshold: 80, pollInterval: 20 }
5707
+ }
5708
+ );
5569
5709
  function schedulePagesRegenerate() {
5570
5710
  if (pagesDebounceTimer !== void 0) {
5571
5711
  clearTimeout(pagesDebounceTimer);
@@ -5645,7 +5785,7 @@ async function watch(config, onChange, options = {}) {
5645
5785
  }
5646
5786
 
5647
5787
  // src/index.ts
5648
- var VERSION = "0.26.0";
5788
+ var VERSION = "0.27.1";
5649
5789
 
5650
5790
  // src/generate-manifest.ts
5651
5791
  var MANIFEST_FILE = ".codegen-manifest.json";
@@ -5705,8 +5845,7 @@ function diffConfigKeyHashes(previous, current) {
5705
5845
  return [...keys].filter((key) => previous[key] !== current[key]).sort();
5706
5846
  }
5707
5847
  async function discoverInputFiles(config) {
5708
- const globs = [config.contracts.glob, config.forms.watch];
5709
- if (config.pages) globs.push(config.pages.glob);
5848
+ const globs = [config.contracts.glob, config.forms.watch, ...allPageGlobs(config)];
5710
5849
  const cwd = config.codegen.cwd;
5711
5850
  const matched = await fg3(globs, { cwd, absolute: true, onlyFiles: true });
5712
5851
  return [...new Set(matched)].sort();