@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
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**:
|
|
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 &&
|
|
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
|
|
231
|
-
const
|
|
232
|
-
|
|
233
|
-
const
|
|
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
|
|
237
|
-
const
|
|
238
|
-
const
|
|
239
|
-
const
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
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
|
-
"/**
|
|
4117
|
-
"type
|
|
4118
|
-
"
|
|
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
|
-
"
|
|
4123
|
-
"
|
|
4124
|
-
"
|
|
4125
|
-
"}
|
|
4126
|
-
"function __req<R>(run: () => Promise<R
|
|
4127
|
-
"
|
|
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
|
|
4156
|
-
lines.push(`${pad} ...__req<${req.responseType}>(() => ${requestExpr}),`);
|
|
4244
|
+
const memberLines = [];
|
|
4157
4245
|
if (req.filterFieldsExpr) {
|
|
4158
|
-
|
|
4246
|
+
memberLines.push(`${pad} filterFields: ${req.filterFieldsExpr},`);
|
|
4159
4247
|
}
|
|
4160
4248
|
if (streamExpr) {
|
|
4161
|
-
|
|
4249
|
+
memberLines.push(`${pad} stream: () => ${streamExpr},`);
|
|
4162
4250
|
}
|
|
4163
4251
|
for (const [name, value] of Object.entries(members)) {
|
|
4164
|
-
|
|
4165
|
-
}
|
|
4166
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
5801
|
-
const pagesWatcher = import_chokidar.default.watch(
|
|
5802
|
-
|
|
5803
|
-
|
|
5804
|
-
|
|
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.
|
|
6023
|
+
var VERSION = "0.27.0";
|
|
5886
6024
|
|
|
5887
6025
|
// src/cli/codegen.ts
|
|
5888
6026
|
async function runCodegen(opts = {}) {
|