@dudousxd/nestjs-codegen 0.27.1 → 0.28.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 +14 -0
- package/README.md +23 -0
- package/dist/cli/main.cjs +64 -17
- package/dist/cli/main.cjs.map +1 -1
- package/dist/cli/main.js +65 -18
- package/dist/cli/main.js.map +1 -1
- package/dist/index.cjs +163 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +56 -3
- package/dist/index.d.ts +56 -3
- package/dist/index.js +162 -12
- package/dist/index.js.map +1 -1
- package/dist/nest/index.cjs +58 -11
- package/dist/nest/index.cjs.map +1 -1
- package/dist/nest/index.js +59 -12
- package/dist/nest/index.js.map +1 -1
- package/package.json +6 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @dudousxd/nestjs-codegen
|
|
2
2
|
|
|
3
|
+
## 0.28.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#111](https://github.com/DavideCarvalho/nestjs-codegen/pull/111) [`26529df`](https://github.com/DavideCarvalho/nestjs-codegen/commit/26529df5f6fd1f91148217f9149da41de49fc8ca) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - New built-in `genuiSandboxKit()` extension: writes the generative-UI sandbox-kit docs (`.genui/sandbox-kit.json`, the component names and props of your shadcn `components/ui` read from their TypeScript types) for `@dudousxd/nestjs-agent`, on every generate and in watch mode. It calls `writeSandboxKitDocs` from the optional peer `@dudousxd/nestjs-agent-core/genui/kit` (>=0.52.0), or a `generate` function you pass.
|
|
8
|
+
|
|
9
|
+
Watch mode now also watches the files extensions declare with `ctx.trackInput` (so editing an extension's out-of-glob dependency, such as a filter class or a kit component, regenerates without waiting for an unrelated change), and a tracked directory hashes as its file listing, so adding a file to it invalidates the skip-when-unchanged check.
|
|
10
|
+
|
|
11
|
+
## 0.27.2
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- [#105](https://github.com/DavideCarvalho/nestjs-codegen/pull/105) [`12be710`](https://github.com/DavideCarvalho/nestjs-codegen/commit/12be710f3c21ccc2e058d901a9921a72587ad939) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - Follow relative imports inside declaration files to their declarations: `./chunk.cjs` resolves to `chunk.d.cts` (and `.cts`), `./chunk.mjs` to `chunk.d.mts`, `./chunk.js` to `chunk.d.ts` — after the source candidates, as before. A package's bundled `index.d.cts` imports its chunks by runtime name, and those types came out `unknown`.
|
|
16
|
+
|
|
3
17
|
## 0.27.1
|
|
4
18
|
|
|
5
19
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -116,6 +116,29 @@ const create = useMutation(api.users.create().mutationOptions());
|
|
|
116
116
|
| [`@dudousxd/nestjs-filter-codegen`](https://www.npmjs.com/package/@dudousxd/nestjs-filter-codegen) | Extension — typed `filterQuery` helpers from the [nestjs-filter](https://github.com/DavideCarvalho/nestjs-filter) repo. |
|
|
117
117
|
| [`@dudousxd/nestjs-inertia-codegen-extension`](https://www.npmjs.com/package/@dudousxd/nestjs-inertia-codegen-extension) | Extension — Inertia `router` / navigate output from the nestjs-inertia repo. |
|
|
118
118
|
|
|
119
|
+
### Generative-UI sandbox kit (built in)
|
|
120
|
+
|
|
121
|
+
`genuiSandboxKit()` writes the sandbox-kit docs that
|
|
122
|
+
[`@dudousxd/nestjs-agent`](https://github.com/DavideCarvalho/nestjs-agent) uses to render
|
|
123
|
+
generative UI with your design-system components: the names and props of your shadcn
|
|
124
|
+
`components/ui` (read from their TypeScript types) go to `.genui/sandbox-kit.json`, on every
|
|
125
|
+
generate and in watch mode. It needs the optional peer `@dudousxd/nestjs-agent-core`
|
|
126
|
+
(>=0.52.0).
|
|
127
|
+
|
|
128
|
+
```ts
|
|
129
|
+
import { defineConfig, genuiSandboxKit } from '@dudousxd/nestjs-codegen';
|
|
130
|
+
|
|
131
|
+
export default defineConfig({
|
|
132
|
+
contracts: { glob: 'src/**/*.controller.ts' },
|
|
133
|
+
codegen: { outDir: 'src/generated' },
|
|
134
|
+
extensions: [genuiSandboxKit({ include: 'web/components/ui/*.tsx', css: 'web/styles/globals.css' })],
|
|
135
|
+
});
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Options: `entry`, `include` (default: the first shadcn `components/ui` dir found), `css`,
|
|
139
|
+
`tsconfig`, `output` (default `.genui/sandbox-kit.json`, relative to the app cwd), and
|
|
140
|
+
`generate` to inject the docs writer.
|
|
141
|
+
|
|
119
142
|
Write your own against the `@dudousxd/nestjs-codegen/extension` contract:
|
|
120
143
|
|
|
121
144
|
```ts
|
package/dist/cli/main.cjs
CHANGED
|
@@ -708,12 +708,18 @@ function findTypeInFile(name, file) {
|
|
|
708
708
|
function resolveModuleSpecifier(moduleSpecifier, sourceFile, project) {
|
|
709
709
|
if (moduleSpecifier.startsWith(".")) {
|
|
710
710
|
const dir = (0, import_node_path4.dirname)(sourceFile.getFilePath());
|
|
711
|
-
const
|
|
712
|
-
|
|
713
|
-
|
|
711
|
+
const ext = /\.(c|m)?(j|t)sx?$/.exec(moduleSpecifier)?.[0];
|
|
712
|
+
const base = ext ? moduleSpecifier.slice(0, -ext.length) : moduleSpecifier;
|
|
713
|
+
const flavour = ext?.startsWith(".c") ? "c" : ext?.startsWith(".m") ? "m" : "";
|
|
714
|
+
const candidates = [
|
|
715
|
+
(0, import_node_path4.resolve)(dir, `${base}.${flavour}ts`),
|
|
716
|
+
...flavour === "" ? [(0, import_node_path4.resolve)(dir, `${base}.tsx`)] : [],
|
|
714
717
|
(0, import_node_path4.resolve)(dir, `${moduleSpecifier}.ts`),
|
|
715
|
-
(0, import_node_path4.resolve)(dir, moduleSpecifier, "index.ts")
|
|
718
|
+
(0, import_node_path4.resolve)(dir, moduleSpecifier, "index.ts"),
|
|
719
|
+
(0, import_node_path4.resolve)(dir, `${base}.d.${flavour}ts`),
|
|
720
|
+
...ext === void 0 ? [(0, import_node_path4.resolve)(dir, moduleSpecifier, "index.d.ts")] : []
|
|
716
721
|
];
|
|
722
|
+
return [...new Set(candidates)];
|
|
717
723
|
}
|
|
718
724
|
const ctx = _ctxFor(project);
|
|
719
725
|
const baseUrl = ctx.pathsBase ?? ctx.projectRoot;
|
|
@@ -5657,14 +5663,26 @@ async function computeInputsHash(config, extraInputs = []) {
|
|
|
5657
5663
|
hash.update("\n");
|
|
5658
5664
|
}
|
|
5659
5665
|
for (const file of extra) {
|
|
5660
|
-
const contents = await (0, import_promises11.readFile)((0, import_node_path15.join)(cwd, file), "utf8").catch(() => null);
|
|
5661
5666
|
hash.update(`extra:${file}
|
|
5662
5667
|
`);
|
|
5663
|
-
hash.update(
|
|
5668
|
+
hash.update(await readTrackedInput((0, import_node_path15.join)(cwd, file)));
|
|
5664
5669
|
hash.update("\n");
|
|
5665
5670
|
}
|
|
5666
5671
|
return hash.digest("hex");
|
|
5667
5672
|
}
|
|
5673
|
+
async function readTrackedInput(path) {
|
|
5674
|
+
try {
|
|
5675
|
+
return await (0, import_promises11.readFile)(path, "utf8");
|
|
5676
|
+
} catch (err) {
|
|
5677
|
+
if (err.code !== "EISDIR") return "\0missing";
|
|
5678
|
+
}
|
|
5679
|
+
try {
|
|
5680
|
+
const entries = await (0, import_promises11.readdir)(path);
|
|
5681
|
+
return `\0dir:${entries.sort().join("\n")}`;
|
|
5682
|
+
} catch {
|
|
5683
|
+
return "\0missing";
|
|
5684
|
+
}
|
|
5685
|
+
}
|
|
5668
5686
|
async function readManifest(outDir) {
|
|
5669
5687
|
try {
|
|
5670
5688
|
const raw = await (0, import_promises11.readFile)((0, import_node_path15.join)(outDir, MANIFEST_FILE), "utf8");
|
|
@@ -5902,11 +5920,36 @@ async function watch(config, onChange, options = {}) {
|
|
|
5902
5920
|
}
|
|
5903
5921
|
return discovery;
|
|
5904
5922
|
}
|
|
5923
|
+
const trackedWatcher = import_chokidar.default.watch([], {
|
|
5924
|
+
ignoreInitial: true,
|
|
5925
|
+
persistent: true,
|
|
5926
|
+
awaitWriteFinish: { stabilityThreshold: 80, pollInterval: 20 }
|
|
5927
|
+
});
|
|
5928
|
+
const trackedPaths = /* @__PURE__ */ new Set();
|
|
5929
|
+
async function syncTrackedInputs() {
|
|
5930
|
+
const manifest = await readManifest(config.codegen.outDir);
|
|
5931
|
+
const fresh = [];
|
|
5932
|
+
for (const path of manifest?.extraInputs ?? []) {
|
|
5933
|
+
const abs = (0, import_node_path18.resolve)(config.codegen.cwd, path);
|
|
5934
|
+
if (trackedPaths.has(abs)) continue;
|
|
5935
|
+
trackedPaths.add(abs);
|
|
5936
|
+
fresh.push(abs);
|
|
5937
|
+
}
|
|
5938
|
+
if (fresh.length > 0) trackedWatcher.add(fresh);
|
|
5939
|
+
}
|
|
5940
|
+
async function generateAndTrack(routes) {
|
|
5941
|
+
try {
|
|
5942
|
+
await generate(config, routes, entryPoint);
|
|
5943
|
+
} finally {
|
|
5944
|
+
await syncTrackedInputs().catch(() => {
|
|
5945
|
+
});
|
|
5946
|
+
}
|
|
5947
|
+
}
|
|
5905
5948
|
async function runInitialPass() {
|
|
5906
5949
|
try {
|
|
5907
5950
|
const initialRoutes = (await getDiscovery()).discover();
|
|
5908
5951
|
lastRoutes = initialRoutes;
|
|
5909
|
-
await
|
|
5952
|
+
await generateAndTrack(initialRoutes);
|
|
5910
5953
|
} catch (err) {
|
|
5911
5954
|
if (err instanceof DriftGuardError) {
|
|
5912
5955
|
console.error(err.message);
|
|
@@ -5916,7 +5959,7 @@ async function watch(config, onChange, options = {}) {
|
|
|
5916
5959
|
`[nestjs-codegen] Initial route discovery failed, falling back to pages-only: ${err instanceof Error ? err.message : String(err)}`
|
|
5917
5960
|
);
|
|
5918
5961
|
try {
|
|
5919
|
-
await
|
|
5962
|
+
await generateAndTrack(lastRoutes);
|
|
5920
5963
|
} catch {
|
|
5921
5964
|
}
|
|
5922
5965
|
}
|
|
@@ -5949,7 +5992,7 @@ async function watch(config, onChange, options = {}) {
|
|
|
5949
5992
|
pagesDebounceTimer = setTimeout(async () => {
|
|
5950
5993
|
pagesDebounceTimer = void 0;
|
|
5951
5994
|
try {
|
|
5952
|
-
await
|
|
5995
|
+
await generateAndTrack(lastRoutes);
|
|
5953
5996
|
} catch (err) {
|
|
5954
5997
|
console.error(
|
|
5955
5998
|
"[nestjs-codegen] Pages generation failed:",
|
|
@@ -5981,7 +6024,7 @@ async function watch(config, onChange, options = {}) {
|
|
|
5981
6024
|
try {
|
|
5982
6025
|
const routes = await (await getDiscovery()).rediscover(changed);
|
|
5983
6026
|
lastRoutes = routes;
|
|
5984
|
-
await
|
|
6027
|
+
await generateAndTrack(routes);
|
|
5985
6028
|
} catch (err) {
|
|
5986
6029
|
console.error(
|
|
5987
6030
|
"[nestjs-codegen] Contracts generation failed:",
|
|
@@ -6002,6 +6045,9 @@ async function watch(config, onChange, options = {}) {
|
|
|
6002
6045
|
formsWatcher.on("add", (p) => scheduleContractsRegenerate(p));
|
|
6003
6046
|
formsWatcher.on("change", (p) => scheduleContractsRegenerate(p));
|
|
6004
6047
|
formsWatcher.on("unlink", (p) => scheduleContractsRegenerate(p));
|
|
6048
|
+
trackedWatcher.on("add", (p) => scheduleContractsRegenerate(p));
|
|
6049
|
+
trackedWatcher.on("change", (p) => scheduleContractsRegenerate(p));
|
|
6050
|
+
trackedWatcher.on("unlink", (p) => scheduleContractsRegenerate(p));
|
|
6005
6051
|
return {
|
|
6006
6052
|
close: async () => {
|
|
6007
6053
|
if (pagesDebounceTimer !== void 0) {
|
|
@@ -6015,13 +6061,14 @@ async function watch(config, onChange, options = {}) {
|
|
|
6015
6061
|
await pagesWatcher.close();
|
|
6016
6062
|
await contractsWatcher.close();
|
|
6017
6063
|
await formsWatcher.close();
|
|
6064
|
+
await trackedWatcher.close();
|
|
6018
6065
|
await lock.release();
|
|
6019
6066
|
}
|
|
6020
6067
|
};
|
|
6021
6068
|
}
|
|
6022
6069
|
|
|
6023
6070
|
// src/index.ts
|
|
6024
|
-
var VERSION = "0.
|
|
6071
|
+
var VERSION = "0.28.0";
|
|
6025
6072
|
|
|
6026
6073
|
// src/cli/codegen.ts
|
|
6027
6074
|
async function runCodegen(opts = {}) {
|
|
@@ -6029,9 +6076,9 @@ async function runCodegen(opts = {}) {
|
|
|
6029
6076
|
const config = await loadConfig(cwd);
|
|
6030
6077
|
if (opts.watch) {
|
|
6031
6078
|
const watcher = await watch(config, void 0, { entryPoint: "cli" });
|
|
6032
|
-
await new Promise((
|
|
6079
|
+
await new Promise((resolve6) => {
|
|
6033
6080
|
function onSignal() {
|
|
6034
|
-
watcher.close().then(
|
|
6081
|
+
watcher.close().then(resolve6).catch(resolve6);
|
|
6035
6082
|
}
|
|
6036
6083
|
process.once("SIGINT", onSignal);
|
|
6037
6084
|
process.once("SIGTERM", onSignal);
|
|
@@ -6161,16 +6208,16 @@ async function detectPackageManager(cwd) {
|
|
|
6161
6208
|
}
|
|
6162
6209
|
async function promptFramework() {
|
|
6163
6210
|
if (!process.stdin.isTTY) return "react";
|
|
6164
|
-
return new Promise((
|
|
6211
|
+
return new Promise((resolve6) => {
|
|
6165
6212
|
const rl = (0, import_node_readline.createInterface)({ input: process.stdin, output: process.stdout });
|
|
6166
6213
|
rl.question(
|
|
6167
6214
|
"[nestjs-codegen] Which frontend framework? (react/vue/svelte) [react]: ",
|
|
6168
6215
|
(answer) => {
|
|
6169
6216
|
rl.close();
|
|
6170
6217
|
const trimmed = answer.trim().toLowerCase();
|
|
6171
|
-
if (trimmed === "vue")
|
|
6172
|
-
else if (trimmed === "svelte")
|
|
6173
|
-
else
|
|
6218
|
+
if (trimmed === "vue") resolve6("vue");
|
|
6219
|
+
else if (trimmed === "svelte") resolve6("svelte");
|
|
6220
|
+
else resolve6("react");
|
|
6174
6221
|
}
|
|
6175
6222
|
);
|
|
6176
6223
|
});
|