nestgen-cli 0.2.3 → 0.2.4
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.
|
@@ -52,6 +52,16 @@ export function loadGenerationManifest(projectRoot) {
|
|
|
52
52
|
const generations = value.generations;
|
|
53
53
|
if (!generations || typeof generations !== 'object' || Array.isArray(generations))
|
|
54
54
|
throw new Error('Le manifeste de génération est invalide.');
|
|
55
|
+
for (const entry of Object.values(generations)) {
|
|
56
|
+
if (!entry || typeof entry !== 'object')
|
|
57
|
+
throw new Error('Le manifeste de génération est invalide.');
|
|
58
|
+
const files = entry.files;
|
|
59
|
+
if (!files || typeof files !== 'object' || Array.isArray(files))
|
|
60
|
+
throw new Error('Le manifeste de génération est invalide.');
|
|
61
|
+
for (const fingerprint of Object.values(files))
|
|
62
|
+
if (typeof fingerprint !== 'string' || !/^[a-f0-9]{64}$/.test(fingerprint))
|
|
63
|
+
throw new Error('Empreinte invalide dans le manifeste de génération.');
|
|
64
|
+
}
|
|
55
65
|
return normalizeManifest(value);
|
|
56
66
|
}
|
|
57
67
|
function resourceDefinition(name, orm, sourceRoot, route, table, profile, fields, indexes, relations, list) {
|
|
@@ -83,10 +93,19 @@ export function withGenerationManifest(projectRoot, changes, definition) {
|
|
|
83
93
|
const files = Object.fromEntries(changes
|
|
84
94
|
.map((change) => [change.path, sha256(change.content)])
|
|
85
95
|
.sort(([left], [right]) => left.localeCompare(right)));
|
|
96
|
+
// A later generation can legitimately rewrite shared files (AppModule, Prisma schema,
|
|
97
|
+
// test support). Keep every owner aligned with the content committed by this transaction.
|
|
98
|
+
const generations = Object.fromEntries(Object.entries(existing.generations).map(([key, entry]) => [
|
|
99
|
+
key,
|
|
100
|
+
{
|
|
101
|
+
...entry,
|
|
102
|
+
files: Object.fromEntries(Object.entries(entry.files).map(([file, fingerprint]) => [file, files[file] ?? fingerprint])),
|
|
103
|
+
},
|
|
104
|
+
]));
|
|
86
105
|
const manifest = normalizeManifest({
|
|
87
106
|
...existing,
|
|
88
107
|
generations: {
|
|
89
|
-
...
|
|
108
|
+
...generations,
|
|
90
109
|
[generationKey(definition)]: {
|
|
91
110
|
definition,
|
|
92
111
|
files,
|
|
@@ -106,6 +125,34 @@ export function withGenerationManifest(projectRoot, changes, definition) {
|
|
|
106
125
|
},
|
|
107
126
|
];
|
|
108
127
|
}
|
|
128
|
+
/** Check all recorded paths once. Older manifests may hold historical hashes for shared files. */
|
|
129
|
+
export function checkGeneratedFiles(projectRoot) {
|
|
130
|
+
const manifest = loadGenerationManifest(projectRoot);
|
|
131
|
+
if (!manifest)
|
|
132
|
+
throw new Error('Manifeste de génération introuvable. Générez d’abord une ressource ou un module.');
|
|
133
|
+
const expected = new Map();
|
|
134
|
+
for (const entry of Object.values(manifest.generations)) {
|
|
135
|
+
for (const [file, fingerprint] of Object.entries(entry.files)) {
|
|
136
|
+
projectPath(projectRoot, file);
|
|
137
|
+
const hashes = expected.get(file) ?? new Set();
|
|
138
|
+
hashes.add(fingerprint);
|
|
139
|
+
expected.set(file, hashes);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
if (expected.size === 0)
|
|
143
|
+
throw new Error('Le manifeste de génération ne contient aucun fichier à vérifier.');
|
|
144
|
+
const missing = [];
|
|
145
|
+
const modified = [];
|
|
146
|
+
for (const [file, fingerprints] of [...expected].sort(([left], [right]) => left.localeCompare(right))) {
|
|
147
|
+
const target = projectPath(projectRoot, file);
|
|
148
|
+
const stat = fs.lstatSync(target, { throwIfNoEntry: false });
|
|
149
|
+
if (!stat)
|
|
150
|
+
missing.push(file);
|
|
151
|
+
else if (!stat.isFile() || !fingerprints.has(sha256(fs.readFileSync(target, 'utf8'))))
|
|
152
|
+
modified.push(file);
|
|
153
|
+
}
|
|
154
|
+
return { checkedFiles: expected.size, missing, modified };
|
|
155
|
+
}
|
|
109
156
|
/** Report generated files changed after their recorded successful generation. */
|
|
110
157
|
export function modifiedGeneratedFiles(projectRoot, entry) {
|
|
111
158
|
return Object.entries(entry.files)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# Exemple Store API — NestGen CLI 0.2.
|
|
1
|
+
# Exemple Store API — NestGen CLI 0.2.4
|
|
2
2
|
|
|
3
|
-
Cette application exemple décrit une API de vente avec des clients, produits, commandes et lignes de commande. Elle est validée avec `nestgen-cli@0.2.
|
|
3
|
+
Cette application exemple décrit une API de vente avec des clients, produits, commandes et lignes de commande. Elle est validée avec `nestgen-cli@0.2.4` et TypeORM, avec le profil d’architecture `advanced`.
|
|
4
4
|
|
|
5
5
|
Les fichiers de `definitions/` sont la source de vérité. Ils restent volontairement déclaratifs : l’application est reconstruite par le CLI au lieu de conserver une copie de fichiers générés qui pourrait diverger du produit.
|
|
6
6
|
|
|
@@ -11,7 +11,7 @@ Créez un dossier de travail, installez la version exacte du CLI puis générez
|
|
|
11
11
|
```bash
|
|
12
12
|
mkdir nestgen-store-api && cd nestgen-store-api
|
|
13
13
|
npm init --yes
|
|
14
|
-
npm install nestgen-cli@0.2.
|
|
14
|
+
npm install nestgen-cli@0.2.4
|
|
15
15
|
|
|
16
16
|
./node_modules/.bin/nestgen init store-api \
|
|
17
17
|
--no-interactive \
|
package/nestgen.js
CHANGED
|
@@ -30,6 +30,7 @@ import {
|
|
|
30
30
|
formatMigration,
|
|
31
31
|
formatHelp,
|
|
32
32
|
} from './dist/cli/output.js';
|
|
33
|
+
import { checkGeneratedFiles } from './dist/engine/generation-manifest.js';
|
|
33
34
|
|
|
34
35
|
// ────── Resolve __dirname compatible ES Modules
|
|
35
36
|
const __filename = fileURLToPath(import.meta.url);
|
|
@@ -549,6 +550,7 @@ function printUsage() {
|
|
|
549
550
|
console.log(
|
|
550
551
|
formatHelp(`Usage: nestgen <commande> [options]\n\nCommandes:\n init [nom] Génère un projet NestJS\n module <nom> [--orm <orm>] Génère un module\n resource <nom> --fields ... Génère un CRUD TypeORM ou Prisma
|
|
551
552
|
config init|show Gère nestgen.config.json
|
|
553
|
+
check Vérifie les fichiers générés sans les modifier
|
|
552
554
|
doctor Vérifie l'installation\n\nOptions:\n -h, --help Affiche cette aide\n -V, --version Affiche la version\n --no-interactive Refuse les prompts\n --quiet Supprime les sorties non essentielles\n --verbose Active les diagnostics\n --no-color Désactive les couleurs\n --profile <simple|advanced> Choisit le profil d'architecture
|
|
553
555
|
--package-manager <pm> Définit npm, pnpm ou yarn
|
|
554
556
|
--project-path <chemin> Définit le dossier parent du projet init
|
|
@@ -714,14 +716,15 @@ function runDoctor(options = {}) {
|
|
|
714
716
|
}
|
|
715
717
|
|
|
716
718
|
function machineResult(command, result) {
|
|
717
|
-
return { version: 1, ok:
|
|
719
|
+
return { version: 1, ok: command !== 'check' || result.ok, command, result };
|
|
718
720
|
}
|
|
719
721
|
|
|
720
722
|
function errorCode(error) {
|
|
721
723
|
const message = error instanceof Error ? error.message : String(error);
|
|
722
724
|
if (/^(Option inconnue|Commande inconnue|.* requiert |Route ou table invalide|Nom de )/.test(message))
|
|
723
725
|
return 'USAGE';
|
|
724
|
-
if (message.startsWith('Préflight échoué'))
|
|
726
|
+
if (message.startsWith('Préflight échoué') || message.toLowerCase().includes('manifeste de génération'))
|
|
727
|
+
return 'PROJECT_INVALID';
|
|
725
728
|
if (/(existe déjà|Destination |Conflit |Transaction interrompue)/.test(message)) return 'CONFLICT';
|
|
726
729
|
return 'INTERNAL';
|
|
727
730
|
}
|
|
@@ -745,7 +748,9 @@ export async function main(args = process.argv.slice(2)) {
|
|
|
745
748
|
if (parsed.options.help || !parsed.command) {
|
|
746
749
|
if (machine)
|
|
747
750
|
console.log(
|
|
748
|
-
JSON.stringify(
|
|
751
|
+
JSON.stringify(
|
|
752
|
+
machineResult('help', { commands: ['init', 'module', 'resource', 'config', 'check', 'doctor'] }),
|
|
753
|
+
),
|
|
749
754
|
);
|
|
750
755
|
else printUsage();
|
|
751
756
|
return;
|
|
@@ -807,6 +812,21 @@ export async function main(args = process.argv.slice(2)) {
|
|
|
807
812
|
result = runDoctor(parsed.options);
|
|
808
813
|
break;
|
|
809
814
|
|
|
815
|
+
case 'check': {
|
|
816
|
+
if (parsed.positionals.length) throw new Error('check ne prend aucun argument.');
|
|
817
|
+
const report = checkGeneratedFiles(process.cwd());
|
|
818
|
+
result = { ok: report.missing.length === 0 && report.modified.length === 0, ...report };
|
|
819
|
+
if (!machine) {
|
|
820
|
+
if (result.ok) console.log(`${report.checkedFiles} fichiers générés vérifiés.`);
|
|
821
|
+
else {
|
|
822
|
+
for (const file of report.missing) console.log(`MANQUANT ${file}`);
|
|
823
|
+
for (const file of report.modified) console.log(`MODIFIÉ ${file}`);
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
if (!result.ok) process.exitCode = 1;
|
|
827
|
+
break;
|
|
828
|
+
}
|
|
829
|
+
|
|
810
830
|
default:
|
|
811
831
|
throw new Error(`Commande inconnue : ${parsed.command}. Utilise --help.`);
|
|
812
832
|
}
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -6,18 +6,19 @@
|
|
|
6
6
|
|
|
7
7
|
NestGen CLI generates NestJS project scaffolding and TypeORM or Prisma resources. The canonical package is [`nestgen-cli`](https://www.npmjs.com/package/nestgen-cli); the canonical repository is [`el-hack/nestgen-cli`](https://github.com/el-hack/nestgen-cli).
|
|
8
8
|
|
|
9
|
-
## Published in 0.2.
|
|
9
|
+
## Published in 0.2.4 / Disponible dans 0.2.4
|
|
10
10
|
|
|
11
11
|
| Available now / Disponible maintenant | Evidence / Preuve |
|
|
12
12
|
| ---------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
|
|
13
|
-
| Nest project, module and TypeORM or Prisma resource generation | The commands are shipped by `nestgen-cli@0.2.
|
|
13
|
+
| Nest project, module and TypeORM or Prisma resource generation | The commands are shipped by `nestgen-cli@0.2.4` and covered by the CLI contract tests. |
|
|
14
14
|
| Declarative resource relations, safe updates and migration plans | The generated manifest protects manual edits; migrations remain explicitly reviewed and applied by the developer. |
|
|
15
|
+
| Read-only generation drift check | `nestgen check` compares recorded file fingerprints and returns a nonzero status for missing or modified generated files. |
|
|
15
16
|
| Operational foundation and authorization metadata | Both are optional extension points; NestGen does not configure an identity provider, a global guard or an external monitoring service. |
|
|
16
17
|
| Store API example | The package ships the [version-pinned example](examples/store-api/README.md), which CI reconstructs from its resource definitions. |
|
|
17
18
|
|
|
18
19
|
## Planned (not released) / Prévu (non publié)
|
|
19
20
|
|
|
20
|
-
The [roadmap](roadmap.md) contains topics under consideration after 0.2.
|
|
21
|
+
The [roadmap](roadmap.md) contains topics under consideration after 0.2.4. They have no release date and are not part of the npm contract until they appear in a versioned guide and `CHANGELOG.md`. La roadmap recense des pistes après 0.2.4 ; elles n’ont ni date de sortie ni engagement de compatibilité avant leur publication dans un guide versionné et le changelog.
|
|
21
22
|
|
|
22
23
|
## Supported contract
|
|
23
24
|
|
|
@@ -52,11 +53,11 @@ For Prisma, run `npx prisma generate` and apply the schema with `npx prisma db p
|
|
|
52
53
|
Install the announced release and verify the exact binary before generating anything. Installez la version annoncée et vérifiez le binaire exact avant toute génération.
|
|
53
54
|
|
|
54
55
|
```bash
|
|
55
|
-
npm install --global nestgen-cli@0.2.
|
|
56
|
-
nestgen --version # 0.2.
|
|
56
|
+
npm install --global nestgen-cli@0.2.4
|
|
57
|
+
nestgen --version # 0.2.4
|
|
57
58
|
```
|
|
58
59
|
|
|
59
|
-
Then follow the [Store API example](examples/store-api/README.md): it generates customers, products, orders and order items; starts PostgreSQL; creates an explicit migration; and runs generated tests. The versioned [guide](docs/versions/0.2.
|
|
60
|
+
Then follow the [Store API example](examples/store-api/README.md): it generates customers, products, orders and order items; starts PostgreSQL; creates an explicit migration; and runs generated tests. The versioned [guide](docs/versions/0.2.4.md) documents the commands and constraints used by the demo. Ensuite, suivez l’exemple Store API : il couvre la génération, PostgreSQL, une migration explicite, les tests générés et la documentation de la version.
|
|
60
61
|
|
|
61
62
|
The CI verifies the public commands against the announced package version, reconstructs the example and installs the npm tarball in a clean consumer. It validates reproducibility of these flows, not a production certification / pas une certification de production.
|
|
62
63
|
|
|
@@ -65,7 +66,7 @@ The CI verifies the public commands against the announced package version, recon
|
|
|
65
66
|
The following flow is the supported end-to-end TypeORM path. Prerequisites: Node.js `>=24.15.0 <27`, npm 11 and Docker with Compose. It uses Docker for PostgreSQL and creates an explicit migration.
|
|
66
67
|
|
|
67
68
|
```bash
|
|
68
|
-
npm install --global nestgen-cli@0.2.
|
|
69
|
+
npm install --global nestgen-cli@0.2.4
|
|
69
70
|
nestgen --version
|
|
70
71
|
nestgen init
|
|
71
72
|
```
|
|
@@ -131,9 +132,12 @@ nestgen module <name> [--orm typeorm|prisma] [--application name] [--dry-run]
|
|
|
131
132
|
nestgen resource <name> --fields name:type[,name:type] [--route route] [--table table] [--profile simple|advanced] [--application name]
|
|
132
133
|
nestgen config init [--orm typeorm|prisma] [--profile simple|advanced] [--package-manager npm|pnpm|yarn]
|
|
133
134
|
nestgen config show
|
|
135
|
+
nestgen check
|
|
134
136
|
nestgen doctor
|
|
135
137
|
```
|
|
136
138
|
|
|
139
|
+
`nestgen check` compares the files recorded in `.nestgen/generation-manifest.json` with their current contents. It is read-only, exits with status `1` when a recorded file is missing or modified, and supports `--json` for CI. Run it from the generated Nest project. It reports generated-file drift; it does not validate runtime behavior or database migrations. New generations update recorded fingerprints for shared files such as `app.module.ts` across all affected resources.
|
|
140
|
+
|
|
137
141
|
Pour la CI, `init` accepte toutes les réponses interactives sous forme d’options :
|
|
138
142
|
|
|
139
143
|
```bash
|