@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 +32 -0
- package/README.md +2 -2
- package/dist/cli/main.cjs +201 -63
- package/dist/cli/main.cjs.map +1 -1
- package/dist/cli/main.js +202 -64
- package/dist/cli/main.js.map +1 -1
- package/dist/extension/index.d.cts +1 -1
- package/dist/extension/index.d.ts +1 -1
- package/dist/{index-Bbw73Kkb.d.cts → index-Dc4s883u.d.cts} +41 -4
- package/dist/{index-Bbw73Kkb.d.ts → index-Dc4s883u.d.ts} +41 -4
- package/dist/index.cjs +201 -63
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +202 -64
- package/dist/index.js.map +1 -1
- package/dist/nest/index.cjs +205 -67
- package/dist/nest/index.cjs.map +1 -1
- package/dist/nest/index.d.cts +1 -1
- package/dist/nest/index.d.ts +1 -1
- package/dist/nest/index.js +206 -68
- package/dist/nest/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,2 +1,2 @@
|
|
|
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-
|
|
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-Dc4s883u.cjs';
|
|
2
2
|
import 'ts-morph';
|
|
@@ -1,2 +1,2 @@
|
|
|
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-
|
|
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-Dc4s883u.js';
|
|
2
2
|
import 'ts-morph';
|
|
@@ -238,9 +238,22 @@ interface UserConfig {
|
|
|
238
238
|
validation: ValidationOption;
|
|
239
239
|
/** Inertia page discovery. Omit when you don't use Inertia. */
|
|
240
240
|
pages?: {
|
|
241
|
-
|
|
241
|
+
/**
|
|
242
|
+
* Page files of the default Inertia app (`InertiaModule.forRoot`), relative to `cwd`. One
|
|
243
|
+
* glob or several; a page is named relative to the static base of the glob that matched it
|
|
244
|
+
* (`inertia/pages/users/Show.tsx` under `inertia/pages/**\/*.tsx` → `users/Show`).
|
|
245
|
+
*/
|
|
246
|
+
glob: string | string[];
|
|
242
247
|
propsExport?: string;
|
|
243
|
-
componentNameStrategy?:
|
|
248
|
+
componentNameStrategy?: PageNameStrategy;
|
|
249
|
+
/**
|
|
250
|
+
* Further Inertia apps, one per `InertiaModule.forFeature({ scope })`, keyed by scope name.
|
|
251
|
+
* Each has its own page glob(s); its page names get a prefix (default `'<scope>/'`, so
|
|
252
|
+
* `minimal/pages/Home.tsx` → `minimal/Home`, the name its `@Inertia('minimal/Home')`
|
|
253
|
+
* handlers render). Every page of every scope lands in `InertiaPages`/`InertiaPageName`;
|
|
254
|
+
* `InertiaScopePages` lists each scope's page names.
|
|
255
|
+
*/
|
|
256
|
+
scopes?: Record<string, PageScopeConfig>;
|
|
244
257
|
};
|
|
245
258
|
contracts?: {
|
|
246
259
|
/** Glob pattern (relative to cwd) for controller files. Default: `'src/**\/\*.controller.ts'` */
|
|
@@ -248,6 +261,11 @@ interface UserConfig {
|
|
|
248
261
|
/** Debounce delay in ms before re-running route discovery. Default: `500` */
|
|
249
262
|
debounceMs?: number;
|
|
250
263
|
};
|
|
264
|
+
/**
|
|
265
|
+
* @deprecated Has no effect: discovery never read it. For several Inertia apps use
|
|
266
|
+
* `pages.scopes`; for several controller sets use one `contracts.glob` (brace/extglob).
|
|
267
|
+
* A config that sets it gets a warning.
|
|
268
|
+
*/
|
|
251
269
|
scopes?: Record<string, ScopeConfig>;
|
|
252
270
|
codegen?: {
|
|
253
271
|
outDir?: string;
|
|
@@ -344,14 +362,33 @@ interface UserConfig {
|
|
|
344
362
|
*/
|
|
345
363
|
driftGuard?: boolean;
|
|
346
364
|
}
|
|
365
|
+
/** @deprecated See `UserConfig.scopes`. */
|
|
347
366
|
interface ScopeConfig {
|
|
348
367
|
glob: string;
|
|
349
368
|
prefix?: string;
|
|
350
369
|
}
|
|
370
|
+
/** How a page file's path (relative to its glob's static base) becomes its component name. */
|
|
371
|
+
type PageNameStrategy = 'relative-no-ext' | 'kebab' | ((path: string) => string);
|
|
372
|
+
/** One more Inertia app (an `InertiaModule.forFeature({ scope })`) — see `pages.scopes`. */
|
|
373
|
+
interface PageScopeConfig {
|
|
374
|
+
/** Page files of this app, relative to `cwd`. */
|
|
375
|
+
glob: string | string[];
|
|
376
|
+
/** Prepended to every page name of this scope. Default `'<scope>/'`; `''` for none. */
|
|
377
|
+
prefix?: string;
|
|
378
|
+
/** Naming strategy for this scope's pages. Default: `pages.componentNameStrategy`. */
|
|
379
|
+
componentNameStrategy?: PageNameStrategy;
|
|
380
|
+
}
|
|
381
|
+
interface ResolvedPageScopeConfig {
|
|
382
|
+
glob: string | string[];
|
|
383
|
+
prefix: string;
|
|
384
|
+
componentNameStrategy: PageNameStrategy;
|
|
385
|
+
}
|
|
351
386
|
interface ResolvedPagesConfig {
|
|
352
|
-
glob: string;
|
|
387
|
+
glob: string | string[];
|
|
353
388
|
propsExport: string;
|
|
354
|
-
componentNameStrategy:
|
|
389
|
+
componentNameStrategy: PageNameStrategy;
|
|
390
|
+
/** Feature scopes (not including the default app), with defaults applied. */
|
|
391
|
+
scopes: Record<string, ResolvedPageScopeConfig>;
|
|
355
392
|
}
|
|
356
393
|
interface ResolvedContractsConfig {
|
|
357
394
|
/** Glob pattern relative to `codegen.cwd` for watching controller files. */
|
|
@@ -238,9 +238,22 @@ interface UserConfig {
|
|
|
238
238
|
validation: ValidationOption;
|
|
239
239
|
/** Inertia page discovery. Omit when you don't use Inertia. */
|
|
240
240
|
pages?: {
|
|
241
|
-
|
|
241
|
+
/**
|
|
242
|
+
* Page files of the default Inertia app (`InertiaModule.forRoot`), relative to `cwd`. One
|
|
243
|
+
* glob or several; a page is named relative to the static base of the glob that matched it
|
|
244
|
+
* (`inertia/pages/users/Show.tsx` under `inertia/pages/**\/*.tsx` → `users/Show`).
|
|
245
|
+
*/
|
|
246
|
+
glob: string | string[];
|
|
242
247
|
propsExport?: string;
|
|
243
|
-
componentNameStrategy?:
|
|
248
|
+
componentNameStrategy?: PageNameStrategy;
|
|
249
|
+
/**
|
|
250
|
+
* Further Inertia apps, one per `InertiaModule.forFeature({ scope })`, keyed by scope name.
|
|
251
|
+
* Each has its own page glob(s); its page names get a prefix (default `'<scope>/'`, so
|
|
252
|
+
* `minimal/pages/Home.tsx` → `minimal/Home`, the name its `@Inertia('minimal/Home')`
|
|
253
|
+
* handlers render). Every page of every scope lands in `InertiaPages`/`InertiaPageName`;
|
|
254
|
+
* `InertiaScopePages` lists each scope's page names.
|
|
255
|
+
*/
|
|
256
|
+
scopes?: Record<string, PageScopeConfig>;
|
|
244
257
|
};
|
|
245
258
|
contracts?: {
|
|
246
259
|
/** Glob pattern (relative to cwd) for controller files. Default: `'src/**\/\*.controller.ts'` */
|
|
@@ -248,6 +261,11 @@ interface UserConfig {
|
|
|
248
261
|
/** Debounce delay in ms before re-running route discovery. Default: `500` */
|
|
249
262
|
debounceMs?: number;
|
|
250
263
|
};
|
|
264
|
+
/**
|
|
265
|
+
* @deprecated Has no effect: discovery never read it. For several Inertia apps use
|
|
266
|
+
* `pages.scopes`; for several controller sets use one `contracts.glob` (brace/extglob).
|
|
267
|
+
* A config that sets it gets a warning.
|
|
268
|
+
*/
|
|
251
269
|
scopes?: Record<string, ScopeConfig>;
|
|
252
270
|
codegen?: {
|
|
253
271
|
outDir?: string;
|
|
@@ -344,14 +362,33 @@ interface UserConfig {
|
|
|
344
362
|
*/
|
|
345
363
|
driftGuard?: boolean;
|
|
346
364
|
}
|
|
365
|
+
/** @deprecated See `UserConfig.scopes`. */
|
|
347
366
|
interface ScopeConfig {
|
|
348
367
|
glob: string;
|
|
349
368
|
prefix?: string;
|
|
350
369
|
}
|
|
370
|
+
/** How a page file's path (relative to its glob's static base) becomes its component name. */
|
|
371
|
+
type PageNameStrategy = 'relative-no-ext' | 'kebab' | ((path: string) => string);
|
|
372
|
+
/** One more Inertia app (an `InertiaModule.forFeature({ scope })`) — see `pages.scopes`. */
|
|
373
|
+
interface PageScopeConfig {
|
|
374
|
+
/** Page files of this app, relative to `cwd`. */
|
|
375
|
+
glob: string | string[];
|
|
376
|
+
/** Prepended to every page name of this scope. Default `'<scope>/'`; `''` for none. */
|
|
377
|
+
prefix?: string;
|
|
378
|
+
/** Naming strategy for this scope's pages. Default: `pages.componentNameStrategy`. */
|
|
379
|
+
componentNameStrategy?: PageNameStrategy;
|
|
380
|
+
}
|
|
381
|
+
interface ResolvedPageScopeConfig {
|
|
382
|
+
glob: string | string[];
|
|
383
|
+
prefix: string;
|
|
384
|
+
componentNameStrategy: PageNameStrategy;
|
|
385
|
+
}
|
|
351
386
|
interface ResolvedPagesConfig {
|
|
352
|
-
glob: string;
|
|
387
|
+
glob: string | string[];
|
|
353
388
|
propsExport: string;
|
|
354
|
-
componentNameStrategy:
|
|
389
|
+
componentNameStrategy: PageNameStrategy;
|
|
390
|
+
/** Feature scopes (not including the default app), with defaults applied. */
|
|
391
|
+
scopes: Record<string, ResolvedPageScopeConfig>;
|
|
355
392
|
}
|
|
356
393
|
interface ResolvedContractsConfig {
|
|
357
394
|
/** Glob pattern relative to `codegen.cwd` for watching controller files. */
|
package/dist/index.cjs
CHANGED
|
@@ -149,11 +149,32 @@ function validateUserConfig(userConfig) {
|
|
|
149
149
|
"validation adapter is required \u2014 install @dudousxd/nestjs-codegen-zod and pass zodAdapter, or use @dudousxd/nestjs-codegen-valibot / -arktype"
|
|
150
150
|
);
|
|
151
151
|
}
|
|
152
|
-
if (userConfig.pages &&
|
|
152
|
+
if (userConfig.pages && !isGlobInput(userConfig.pages.glob)) {
|
|
153
153
|
throw new ConfigError(
|
|
154
|
-
"Config validation failed: `pages.glob` must be a string when `pages` is set"
|
|
154
|
+
"Config validation failed: `pages.glob` must be a string or a non-empty array of strings when `pages` is set"
|
|
155
155
|
);
|
|
156
156
|
}
|
|
157
|
+
for (const [scope, scopeConfig] of Object.entries(userConfig.pages?.scopes ?? {})) {
|
|
158
|
+
if (scope === "default") {
|
|
159
|
+
throw new ConfigError(
|
|
160
|
+
'Config validation failed: `pages.scopes` cannot declare "default" \u2014 the default app is `pages.glob` (InertiaModule.forRoot).'
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
if (!isGlobInput(scopeConfig?.glob)) {
|
|
164
|
+
throw new ConfigError(
|
|
165
|
+
`Config validation failed: \`pages.scopes.${scope}.glob\` must be a string or a non-empty array of strings`
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
if (userConfig.scopes && Object.keys(userConfig.scopes).length > 0) {
|
|
170
|
+
console.warn(
|
|
171
|
+
"[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)."
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
function isGlobInput(value) {
|
|
176
|
+
if (typeof value === "string") return true;
|
|
177
|
+
return Array.isArray(value) && value.length > 0 && value.every((glob) => typeof glob === "string");
|
|
157
178
|
}
|
|
158
179
|
function applyDefaults(userConfig, cwd) {
|
|
159
180
|
validateUserConfig(userConfig);
|
|
@@ -181,7 +202,17 @@ function applyDefaults(userConfig, cwd) {
|
|
|
181
202
|
pages: userConfig.pages ? {
|
|
182
203
|
glob: userConfig.pages.glob,
|
|
183
204
|
propsExport: userConfig.pages.propsExport ?? "ComponentProps",
|
|
184
|
-
componentNameStrategy: userConfig.pages.componentNameStrategy ?? "relative-no-ext"
|
|
205
|
+
componentNameStrategy: userConfig.pages.componentNameStrategy ?? "relative-no-ext",
|
|
206
|
+
scopes: Object.fromEntries(
|
|
207
|
+
Object.entries(userConfig.pages.scopes ?? {}).map(([scope, scopeConfig]) => [
|
|
208
|
+
scope,
|
|
209
|
+
{
|
|
210
|
+
glob: scopeConfig.glob,
|
|
211
|
+
prefix: scopeConfig.prefix ?? `${scope}/`,
|
|
212
|
+
componentNameStrategy: scopeConfig.componentNameStrategy ?? userConfig.pages?.componentNameStrategy ?? "relative-no-ext"
|
|
213
|
+
}
|
|
214
|
+
])
|
|
215
|
+
)
|
|
185
216
|
} : null,
|
|
186
217
|
contracts: {
|
|
187
218
|
glob: userConfig.contracts?.glob ?? "src/**/*.controller.ts",
|
|
@@ -258,23 +289,81 @@ var import_promises2 = require("fs/promises");
|
|
|
258
289
|
var import_node_path2 = require("path");
|
|
259
290
|
var import_fast_glob = __toESM(require("fast-glob"), 1);
|
|
260
291
|
var NON_PAGE_FILE_RE = /\.(?:test|spec|stories|story)\.(?:tsx?|jsx?|vue|svelte)$/i;
|
|
292
|
+
var MAGIC_SEGMENT_RE = /[*?{}[\]()!]/;
|
|
293
|
+
function globStaticBase(glob) {
|
|
294
|
+
const segments = glob.split("/");
|
|
295
|
+
const staticSegments = [];
|
|
296
|
+
for (const segment of segments.slice(0, -1)) {
|
|
297
|
+
if (MAGIC_SEGMENT_RE.test(segment)) break;
|
|
298
|
+
staticSegments.push(segment);
|
|
299
|
+
}
|
|
300
|
+
return staticSegments.join("/");
|
|
301
|
+
}
|
|
261
302
|
async function discoverPages(opts) {
|
|
262
|
-
const
|
|
263
|
-
const
|
|
264
|
-
|
|
265
|
-
const
|
|
266
|
-
const pagesBase = (0, import_node_path2.join)(opts.cwd, globStatic);
|
|
303
|
+
const globs = typeof opts.glob === "string" ? [opts.glob] : opts.glob;
|
|
304
|
+
const prefix = opts.prefix ?? "";
|
|
305
|
+
const scope = opts.scope ?? "default";
|
|
306
|
+
const seenFiles = /* @__PURE__ */ new Set();
|
|
267
307
|
const out = [];
|
|
268
|
-
for (const
|
|
269
|
-
const
|
|
270
|
-
const
|
|
271
|
-
const
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
308
|
+
for (const glob of globs) {
|
|
309
|
+
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();
|
|
310
|
+
const pagesBase = (0, import_node_path2.join)(opts.cwd, globStaticBase(glob));
|
|
311
|
+
for (const file of files) {
|
|
312
|
+
seenFiles.add(file);
|
|
313
|
+
const rel = (0, import_node_path2.relative)(opts.cwd, file);
|
|
314
|
+
const nameRel = (0, import_node_path2.relative)(pagesBase, file).split(import_node_path2.sep).join("/");
|
|
315
|
+
const name = `${prefix}${computeName(nameRel, opts.componentNameStrategy)}`;
|
|
316
|
+
const source = await (0, import_promises2.readFile)(file, "utf8");
|
|
317
|
+
const propsSource = extractPropsSource(source, opts.propsExport);
|
|
318
|
+
out.push({ name, absolutePath: file, relativePath: rel, propsSource, scope });
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
assertUniqueNames(out);
|
|
322
|
+
return out;
|
|
323
|
+
}
|
|
324
|
+
async function discoverPageScopes(config) {
|
|
325
|
+
const pages = config.pages;
|
|
326
|
+
if (!pages) return [];
|
|
327
|
+
const common = { cwd: config.codegen.cwd, propsExport: pages.propsExport };
|
|
328
|
+
const out = await discoverPages({
|
|
329
|
+
...common,
|
|
330
|
+
glob: pages.glob,
|
|
331
|
+
componentNameStrategy: pages.componentNameStrategy
|
|
332
|
+
});
|
|
333
|
+
for (const [scope, scopeConfig] of Object.entries(pages.scopes ?? {})) {
|
|
334
|
+
out.push(
|
|
335
|
+
...await discoverPages({
|
|
336
|
+
...common,
|
|
337
|
+
glob: scopeConfig.glob,
|
|
338
|
+
componentNameStrategy: scopeConfig.componentNameStrategy,
|
|
339
|
+
prefix: scopeConfig.prefix,
|
|
340
|
+
scope
|
|
341
|
+
})
|
|
342
|
+
);
|
|
275
343
|
}
|
|
344
|
+
assertUniqueNames(out);
|
|
276
345
|
return out;
|
|
277
346
|
}
|
|
347
|
+
function allPageGlobs(config) {
|
|
348
|
+
if (!config.pages) return [];
|
|
349
|
+
const asList = (glob) => typeof glob === "string" ? [glob] : glob;
|
|
350
|
+
return [
|
|
351
|
+
...asList(config.pages.glob),
|
|
352
|
+
...Object.values(config.pages.scopes ?? {}).flatMap((scope) => asList(scope.glob))
|
|
353
|
+
];
|
|
354
|
+
}
|
|
355
|
+
function assertUniqueNames(pages) {
|
|
356
|
+
const byName = /* @__PURE__ */ new Map();
|
|
357
|
+
for (const page of pages) {
|
|
358
|
+
const previous = byName.get(page.name);
|
|
359
|
+
if (previous) {
|
|
360
|
+
throw new Error(
|
|
361
|
+
`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.`
|
|
362
|
+
);
|
|
363
|
+
}
|
|
364
|
+
byName.set(page.name, page);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
278
367
|
function computeName(rel, strat) {
|
|
279
368
|
if (typeof strat === "function") return strat(rel);
|
|
280
369
|
const noExt = rel.replace(/\.(tsx?|vue|svelte)$/, "");
|
|
@@ -4145,28 +4234,28 @@ function renderFetcherRequest(req, binaryResponse) {
|
|
|
4145
4234
|
}
|
|
4146
4235
|
function emitReqHelper() {
|
|
4147
4236
|
return [
|
|
4148
|
-
"/**
|
|
4149
|
-
"type
|
|
4150
|
-
"
|
|
4237
|
+
"/** An awaitable request handle: a lazy, memoized `Promise` that also carries `fetch()` and the members extensions add. */",
|
|
4238
|
+
"export type RequestHandle<R, M = {}> = Promise<R> & { fetch(): Promise<R> } & M;",
|
|
4239
|
+
"class __Request<R> extends Promise<R> {",
|
|
4240
|
+
" static override get [Symbol.species](): PromiseConstructor {",
|
|
4241
|
+
" return Promise;",
|
|
4242
|
+
" }",
|
|
4243
|
+
" private __run: () => Promise<R>;",
|
|
4244
|
+
" private __p: Promise<R> | undefined;",
|
|
4245
|
+
" constructor(run: () => Promise<R>) {",
|
|
4246
|
+
" super(() => {});",
|
|
4247
|
+
" this.__run = run;",
|
|
4248
|
+
" }",
|
|
4249
|
+
" override then<T1 = R, T2 = never>(",
|
|
4151
4250
|
" onfulfilled?: ((value: R) => T1 | PromiseLike<T1>) | null,",
|
|
4152
4251
|
" onrejected?: ((reason: unknown) => T2 | PromiseLike<T2>) | null,",
|
|
4153
|
-
" ): Promise<T1 | T2
|
|
4154
|
-
"
|
|
4155
|
-
"
|
|
4156
|
-
"
|
|
4157
|
-
"}
|
|
4158
|
-
"function __req<R>(run: () => Promise<R
|
|
4159
|
-
"
|
|
4160
|
-
" const __promise = () => {",
|
|
4161
|
-
" __p ??= run();",
|
|
4162
|
-
" return __p;",
|
|
4163
|
-
" };",
|
|
4164
|
-
" return {",
|
|
4165
|
-
" then: (onfulfilled, onrejected) => __promise().then(onfulfilled, onrejected),",
|
|
4166
|
-
" catch: (onrejected) => __promise().catch(onrejected),",
|
|
4167
|
-
" finally: (onfinally) => __promise().finally(onfinally),",
|
|
4168
|
-
" fetch: run,",
|
|
4169
|
-
" };",
|
|
4252
|
+
" ): Promise<T1 | T2> {",
|
|
4253
|
+
" this.__p ??= this.__run();",
|
|
4254
|
+
" return this.__p.then(onfulfilled, onrejected);",
|
|
4255
|
+
" }",
|
|
4256
|
+
"}",
|
|
4257
|
+
"function __req<R, M extends object = {}>(run: () => Promise<R>, members?: M): RequestHandle<R, M> {",
|
|
4258
|
+
" return Object.assign(new __Request<R>(run), { fetch: run }, members) as RequestHandle<R, M>;",
|
|
4170
4259
|
"}",
|
|
4171
4260
|
""
|
|
4172
4261
|
];
|
|
@@ -4184,18 +4273,26 @@ function emitFilterFieldGuard() {
|
|
|
4184
4273
|
];
|
|
4185
4274
|
}
|
|
4186
4275
|
function renderLeaf(pad, objKey, req, requestExpr, members, streamExpr) {
|
|
4187
|
-
const
|
|
4188
|
-
lines.push(`${pad} ...__req<${req.responseType}>(() => ${requestExpr}),`);
|
|
4276
|
+
const memberLines = [];
|
|
4189
4277
|
if (req.filterFieldsExpr) {
|
|
4190
|
-
|
|
4278
|
+
memberLines.push(`${pad} filterFields: ${req.filterFieldsExpr},`);
|
|
4191
4279
|
}
|
|
4192
4280
|
if (streamExpr) {
|
|
4193
|
-
|
|
4281
|
+
memberLines.push(`${pad} stream: () => ${streamExpr},`);
|
|
4194
4282
|
}
|
|
4195
4283
|
for (const [name, value] of Object.entries(members)) {
|
|
4196
|
-
|
|
4197
|
-
}
|
|
4198
|
-
|
|
4284
|
+
memberLines.push(`${pad} ${name}: ${value},`);
|
|
4285
|
+
}
|
|
4286
|
+
const body = [requestExpr, ...memberLines].join("\n");
|
|
4287
|
+
const param = /\binput\b/.test(body) ? `input?: ${req.inputType}` : "";
|
|
4288
|
+
const lines = [`${pad}${objKey}: (${param}) =>`];
|
|
4289
|
+
if (memberLines.length === 0) {
|
|
4290
|
+
lines.push(`${pad} __req<${req.responseType}>(() => ${requestExpr}),`);
|
|
4291
|
+
return lines;
|
|
4292
|
+
}
|
|
4293
|
+
lines.push(`${pad} __req(() => ${requestExpr}, {`);
|
|
4294
|
+
lines.push(...memberLines);
|
|
4295
|
+
lines.push(`${pad} }),`);
|
|
4199
4296
|
return lines;
|
|
4200
4297
|
}
|
|
4201
4298
|
function renderStreamExpr(req) {
|
|
@@ -4329,6 +4426,23 @@ var EMPTY_PATH_NAMESPACE = [
|
|
|
4329
4426
|
function isClientCallable(route) {
|
|
4330
4427
|
return route.method.toUpperCase() !== "ALL";
|
|
4331
4428
|
}
|
|
4429
|
+
var ROUTES_IMPORT_PLACEHOLDER = "/* @@routes-import@@ */";
|
|
4430
|
+
var ROUTES_EXPORTS = [
|
|
4431
|
+
// Called, never mentioned in prose: match the call so a comment saying "route" doesn't count.
|
|
4432
|
+
{ name: "route", typeOnly: false },
|
|
4433
|
+
{ name: "ROUTES", typeOnly: false },
|
|
4434
|
+
{ name: "RouteName", typeOnly: true },
|
|
4435
|
+
{ name: "ExtractParams", typeOnly: true },
|
|
4436
|
+
{ name: "RouteParams", typeOnly: true }
|
|
4437
|
+
];
|
|
4438
|
+
function finishRoutesImport(lines) {
|
|
4439
|
+
const body = lines.filter((l) => l !== ROUTES_IMPORT_PLACEHOLDER).join("\n");
|
|
4440
|
+
const used = ROUTES_EXPORTS.filter(
|
|
4441
|
+
({ name }) => new RegExp(name === "route" ? "\\broute\\(" : `\\b${name}\\b`).test(body)
|
|
4442
|
+
).map(({ name, typeOnly }) => typeOnly ? `type ${name}` : name);
|
|
4443
|
+
const importLine = used.length ? `import { ${used.join(", ")} } from './routes.js';` : null;
|
|
4444
|
+
return lines.flatMap((l) => l === ROUTES_IMPORT_PLACEHOLDER ? importLine ? [importLine] : [] : [l]).join("\n");
|
|
4445
|
+
}
|
|
4332
4446
|
function buildApiFile(routes, outDir, opts = {}) {
|
|
4333
4447
|
const fetcherImportPath = opts.fetcherImportPath;
|
|
4334
4448
|
const serialization = opts.serialization ?? "json";
|
|
@@ -4388,9 +4502,7 @@ function buildApiFile(routes, outDir, opts = {}) {
|
|
|
4388
4502
|
for (const imp of ext.apiHeader?.(ctx)?.imports ?? []) pushImport(imp);
|
|
4389
4503
|
}
|
|
4390
4504
|
lines.push(...extImports);
|
|
4391
|
-
lines.push(
|
|
4392
|
-
"import { route, ROUTES, type RouteName, type ExtractParams, type RouteParams } from './routes.js';"
|
|
4393
|
-
);
|
|
4505
|
+
lines.push(ROUTES_IMPORT_PLACEHOLDER);
|
|
4394
4506
|
const runtimeImport = fetcherImportPath ?? "@dudousxd/nestjs-client";
|
|
4395
4507
|
lines.push(`import type { Fetcher } from '${runtimeImport}';`);
|
|
4396
4508
|
if (serialization === "json" && contracted.length > 0) {
|
|
@@ -4441,7 +4553,7 @@ function buildApiFile(routes, outDir, opts = {}) {
|
|
|
4441
4553
|
lines.push(...statements, "");
|
|
4442
4554
|
}
|
|
4443
4555
|
}
|
|
4444
|
-
return lines
|
|
4556
|
+
return finishRoutesImport(lines);
|
|
4445
4557
|
}
|
|
4446
4558
|
const tree = /* @__PURE__ */ new Map();
|
|
4447
4559
|
for (const r of contracted) {
|
|
@@ -4494,7 +4606,7 @@ function buildApiFile(routes, outDir, opts = {}) {
|
|
|
4494
4606
|
lines.push(...statements, "");
|
|
4495
4607
|
}
|
|
4496
4608
|
}
|
|
4497
|
-
return lines
|
|
4609
|
+
return finishRoutesImport(lines);
|
|
4498
4610
|
}
|
|
4499
4611
|
|
|
4500
4612
|
// src/emit/emit-cache.ts
|
|
@@ -4507,6 +4619,7 @@ async function emitCache(pages, outDir) {
|
|
|
4507
4619
|
const s = await (0, import_promises4.stat)(p.absolutePath);
|
|
4508
4620
|
return {
|
|
4509
4621
|
name: p.name,
|
|
4622
|
+
scope: p.scope ?? "default",
|
|
4510
4623
|
relativePath: p.relativePath,
|
|
4511
4624
|
mtime: s.mtime.toISOString()
|
|
4512
4625
|
};
|
|
@@ -5301,10 +5414,11 @@ async function emitPages(pages, outDir, _options = {}) {
|
|
|
5301
5414
|
}).join("\n");
|
|
5302
5415
|
const propsHelper = "\nexport type InertiaProps<K extends InertiaPageName> = import('@dudousxd/nestjs-inertia').InertiaPages[K];\n";
|
|
5303
5416
|
const sharedPropsBlock = buildSharedPropsBlock(_options.sharedProps ?? null);
|
|
5417
|
+
const scopesBlock = buildScopesBlock(pages);
|
|
5304
5418
|
const content = `// Generated by @dudousxd/nestjs-codegen. Do not edit.
|
|
5305
5419
|
|
|
5306
5420
|
export type InertiaPageName = ${pageNameUnion};
|
|
5307
|
-
${propsHelper}
|
|
5421
|
+
${propsHelper}${scopesBlock}
|
|
5308
5422
|
declare module '@dudousxd/nestjs-inertia' {
|
|
5309
5423
|
interface InertiaPages {
|
|
5310
5424
|
${augBody}
|
|
@@ -5313,6 +5427,31 @@ ${sharedPropsBlock}}
|
|
|
5313
5427
|
`;
|
|
5314
5428
|
await (0, import_promises9.writeFile)((0, import_node_path13.join)(outDir, "pages.d.ts"), content, "utf8");
|
|
5315
5429
|
}
|
|
5430
|
+
function buildScopesBlock(pages) {
|
|
5431
|
+
const byScope = /* @__PURE__ */ new Map();
|
|
5432
|
+
for (const page of pages) {
|
|
5433
|
+
const scope = page.scope ?? "default";
|
|
5434
|
+
const names = byScope.get(scope) ?? [];
|
|
5435
|
+
names.push(JSON.stringify(page.name));
|
|
5436
|
+
byScope.set(scope, names);
|
|
5437
|
+
}
|
|
5438
|
+
if (![...byScope.keys()].some((scope) => scope !== "default")) return "";
|
|
5439
|
+
if (!byScope.has("default")) byScope.set("default", []);
|
|
5440
|
+
const scopes = ["default", ...[...byScope.keys()].filter((s) => s !== "default")];
|
|
5441
|
+
const body = scopes.map((scope) => {
|
|
5442
|
+
const key = needsQuotes(scope) ? JSON.stringify(scope) : scope;
|
|
5443
|
+
const names = byScope.get(scope) ?? [];
|
|
5444
|
+
return ` ${key}: ${names.length ? names.join(" | ") : "never"};`;
|
|
5445
|
+
}).join("\n");
|
|
5446
|
+
return `
|
|
5447
|
+
/** The page names of each Inertia app: \`default\` (forRoot) and every \`pages.scopes\` entry. */
|
|
5448
|
+
export interface InertiaScopePages {
|
|
5449
|
+
${body}
|
|
5450
|
+
}
|
|
5451
|
+
|
|
5452
|
+
export type InertiaScopePageName<S extends keyof InertiaScopePages> = InertiaScopePages[S];
|
|
5453
|
+
`;
|
|
5454
|
+
}
|
|
5316
5455
|
function buildSharedPropsBlock(sharedProps) {
|
|
5317
5456
|
if (!sharedProps) return "";
|
|
5318
5457
|
if (sharedProps.isImportRef) {
|
|
@@ -5520,8 +5659,7 @@ function diffConfigKeyHashes(previous, current) {
|
|
|
5520
5659
|
return [...keys].filter((key) => previous[key] !== current[key]).sort();
|
|
5521
5660
|
}
|
|
5522
5661
|
async function discoverInputFiles(config) {
|
|
5523
|
-
const globs = [config.contracts.glob, config.forms.watch];
|
|
5524
|
-
if (config.pages) globs.push(config.pages.glob);
|
|
5662
|
+
const globs = [config.contracts.glob, config.forms.watch, ...allPageGlobs(config)];
|
|
5525
5663
|
const cwd = config.codegen.cwd;
|
|
5526
5664
|
const matched = await (0, import_fast_glob3.default)(globs, { cwd, absolute: true, onlyFiles: true });
|
|
5527
5665
|
return [...new Set(matched)].sort();
|
|
@@ -5652,12 +5790,7 @@ async function generate(config, inputRoutes = [], entryPoint = "cli") {
|
|
|
5652
5790
|
}
|
|
5653
5791
|
if (config.pages) {
|
|
5654
5792
|
const pagesConfig = config.pages;
|
|
5655
|
-
const pages = await
|
|
5656
|
-
glob: pagesConfig.glob,
|
|
5657
|
-
cwd: config.codegen.cwd,
|
|
5658
|
-
propsExport: pagesConfig.propsExport,
|
|
5659
|
-
componentNameStrategy: pagesConfig.componentNameStrategy
|
|
5660
|
-
});
|
|
5793
|
+
const pages = await discoverPageScopes(config);
|
|
5661
5794
|
const sharedProps = discoverSharedPropsFromConfig(config);
|
|
5662
5795
|
await emitPages(pages, config.codegen.outDir, {
|
|
5663
5796
|
propsExport: pagesConfig.propsExport,
|
|
@@ -5832,12 +5965,17 @@ async function watch(config, onChange, options = {}) {
|
|
|
5832
5965
|
await runInitialPass();
|
|
5833
5966
|
}
|
|
5834
5967
|
let pagesDebounceTimer;
|
|
5835
|
-
const
|
|
5836
|
-
const pagesWatcher = import_chokidar.default.watch(
|
|
5837
|
-
|
|
5838
|
-
|
|
5839
|
-
|
|
5840
|
-
|
|
5968
|
+
const pageGlobs = allPageGlobs(config);
|
|
5969
|
+
const pagesWatcher = import_chokidar.default.watch(
|
|
5970
|
+
(pageGlobs.length ? pageGlobs : [".nestjs-codegen-no-pages"]).map(
|
|
5971
|
+
(glob) => (0, import_node_path18.join)(config.codegen.cwd, glob)
|
|
5972
|
+
),
|
|
5973
|
+
{
|
|
5974
|
+
ignoreInitial: true,
|
|
5975
|
+
persistent: true,
|
|
5976
|
+
awaitWriteFinish: { stabilityThreshold: 80, pollInterval: 20 }
|
|
5977
|
+
}
|
|
5978
|
+
);
|
|
5841
5979
|
function schedulePagesRegenerate() {
|
|
5842
5980
|
if (pagesDebounceTimer !== void 0) {
|
|
5843
5981
|
clearTimeout(pagesDebounceTimer);
|
|
@@ -6000,7 +6138,7 @@ function createChainModuleRenderer(opts) {
|
|
|
6000
6138
|
}
|
|
6001
6139
|
|
|
6002
6140
|
// src/index.ts
|
|
6003
|
-
var VERSION = "0.
|
|
6141
|
+
var VERSION = "0.27.0";
|
|
6004
6142
|
// Annotate the CommonJS export names for ESM import in node:
|
|
6005
6143
|
0 && (module.exports = {
|
|
6006
6144
|
CodegenError,
|