@conformetry/generation 0.0.39 → 0.0.41
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 +28 -0
- package/README.md +148 -23
- package/dist/src/index.d.ts +9 -1
- package/dist/src/index.js +2 -0
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,31 @@
|
|
|
1
|
+
## 0.0.41 (2026-10-18)
|
|
2
|
+
|
|
3
|
+
### 🧱 Updated Dependencies
|
|
4
|
+
|
|
5
|
+
- Updated conformetry-configuration to 0.0.41
|
|
6
|
+
- Updated conformetry-core to 0.0.40
|
|
7
|
+
|
|
8
|
+
## 0.0.40 (2026-10-18)
|
|
9
|
+
|
|
10
|
+
### 🚀 Features
|
|
11
|
+
|
|
12
|
+
- ⚠️ **conformetry:** ✨ expose the filesystem and configuration directory to hooks ([#1695](https://github.com/organizzolini/codebase/pull/1695), [#1679](https://github.com/organizzolini/codebase/issues/1679))
|
|
13
|
+
|
|
14
|
+
### ⚠️ Breaking Changes
|
|
15
|
+
|
|
16
|
+
- **conformetry:** ✨ expose the filesystem and configuration directory to hooks ([#1695](https://github.com/organizzolini/codebase/pull/1695), [#1679](https://github.com/organizzolini/codebase/issues/1679))
|
|
17
|
+
`GenerationService.runGenerator` in the published
|
|
18
|
+
`@conformetry/generation` now requires `configurationDirectoryPath`, so
|
|
19
|
+
an embedder calling it must pass the absolute directory of its
|
|
20
|
+
configuration file; the title carries `!` so the squash releases it as
|
|
21
|
+
such.
|
|
22
|
+
- This is stacked on #1693.
|
|
23
|
+
|
|
24
|
+
### 🧱 Updated Dependencies
|
|
25
|
+
|
|
26
|
+
- Updated conformetry-configuration to 0.0.40
|
|
27
|
+
- Updated conformetry-core to 0.0.39
|
|
28
|
+
|
|
1
29
|
## 0.0.39 (2026-10-18)
|
|
2
30
|
|
|
3
31
|
### 💅 Refactors
|
package/README.md
CHANGED
|
@@ -16,6 +16,7 @@ npm install --save-dev @conformetry/generation
|
|
|
16
16
|
import { GenerationService } from "@conformetry/generation";
|
|
17
17
|
|
|
18
18
|
const result = await generationService.runGenerator({
|
|
19
|
+
configurationDirectoryPath: "/workspace/configuration",
|
|
19
20
|
definition: {
|
|
20
21
|
name: "nestjs-service-module",
|
|
21
22
|
templateDirectoryPath: "templates/nestjs-service-module",
|
|
@@ -27,7 +28,131 @@ const result = await generationService.runGenerator({
|
|
|
27
28
|
```
|
|
28
29
|
|
|
29
30
|
The lifecycle is `preGenerate` → render → `postGenerate` → format, and the
|
|
30
|
-
|
|
31
|
+
rendered file paths are sorted. A path a hook pushes onto the list is appended
|
|
32
|
+
after the sort.
|
|
33
|
+
|
|
34
|
+
## Hooks
|
|
35
|
+
|
|
36
|
+
A generator may declare two functions that run around generation. The
|
|
37
|
+
[hooks example](../conformetry-examples/examples/hooks/README.md) runs both.
|
|
38
|
+
|
|
39
|
+
| Hook | Runs | `generatedFilePaths` holds |
|
|
40
|
+
| -------------- | ------------------------------------------------- | ----------------------------- |
|
|
41
|
+
| `preGenerate` | Before anything is written | Nothing: it is an empty array |
|
|
42
|
+
| `postGenerate` | After the template is rendered, before formatting | Every rendered path, sorted |
|
|
43
|
+
|
|
44
|
+
Each hook receives one `GeneratorHookContext`, may be sync or async, and is
|
|
45
|
+
awaited. Hooks are plain functions, so a configuration cannot declare them in
|
|
46
|
+
JSON, which cannot carry a function; any JavaScript or TypeScript configuration
|
|
47
|
+
can. Import the types from
|
|
48
|
+
`@conformetry/configuration`, which re-exports `GeneratorHook`,
|
|
49
|
+
`GeneratorHookContext`, and `GeneratorHooks` from `@conformetry/core`; a
|
|
50
|
+
configuration needs no other dependency to type its hooks.
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
import path from "node:path";
|
|
54
|
+
|
|
55
|
+
import type {
|
|
56
|
+
ConformetryConfiguration,
|
|
57
|
+
GeneratorHookContext,
|
|
58
|
+
} from "@conformetry/configuration";
|
|
59
|
+
|
|
60
|
+
const configuration: ConformetryConfiguration = [
|
|
61
|
+
{
|
|
62
|
+
hooks: {
|
|
63
|
+
postGenerate: async (context: GeneratorHookContext): Promise<void> => {
|
|
64
|
+
const receiptPath = path.join(
|
|
65
|
+
context.configurationDirectoryPath,
|
|
66
|
+
"receipts",
|
|
67
|
+
`${context.substitutions["nameKebabCase"] ?? ""}.log`,
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
await context.filesystem.writeFile(receiptPath, "generated\n");
|
|
71
|
+
context.generatedFilePaths.push(receiptPath);
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
name: "receipt",
|
|
75
|
+
templatePath: "templates/receipt",
|
|
76
|
+
},
|
|
77
|
+
];
|
|
78
|
+
|
|
79
|
+
export default configuration;
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### The context
|
|
83
|
+
|
|
84
|
+
| Field | What it holds |
|
|
85
|
+
| ---------------------------- | ---------------------------------------------------------------------------- |
|
|
86
|
+
| `definition` | The generator's runtime definition: `name`, `templateDirectoryPath`, `hooks` |
|
|
87
|
+
| `input` | The input values the run was given, by input name |
|
|
88
|
+
| `substitutions` | What the template renders with: the name variants, then inputs over them |
|
|
89
|
+
| `outputDirectoryPath` | Where the run writes, exactly as the host passed it |
|
|
90
|
+
| `generatedFilePaths` | The list described above. It is mutable, and what the formatter receives |
|
|
91
|
+
| `filesystem` | The adapter the run itself reads and writes through |
|
|
92
|
+
| `configurationDirectoryPath` | Absolute directory of the configuration file that declared the generator |
|
|
93
|
+
|
|
94
|
+
Paths differ by host:
|
|
95
|
+
|
|
96
|
+
- **`outputDirectoryPath` and `generatedFilePaths`** are whatever the host
|
|
97
|
+
passed. Under the command line that is the form `--directory` was given in,
|
|
98
|
+
so possibly relative. Under Nx they are absolute.
|
|
99
|
+
- **`filesystem` takes absolute paths only.** Build them from
|
|
100
|
+
`configurationDirectoryPath`, never from the working directory, so a hook
|
|
101
|
+
behaves the same however the command was started.
|
|
102
|
+
- **`configurationDirectoryPath` is absolute under both hosts**, taken from
|
|
103
|
+
the file that was actually loaded.
|
|
104
|
+
- **`definition.templateDirectoryPath`** is the configuration's `templatePath`
|
|
105
|
+
as written, so workspace-relative, under the command line. Under Nx it is
|
|
106
|
+
resolved against the workspace root, so absolute.
|
|
107
|
+
|
|
108
|
+
There is no `replaceInFile` helper. A hook that edits a rendered file reads it
|
|
109
|
+
with `filesystem.readFile`, changes the text, and writes it back.
|
|
110
|
+
|
|
111
|
+
### Writing from a hook
|
|
112
|
+
|
|
113
|
+
Write through `context.filesystem`, not `node:fs`. Under the command line the
|
|
114
|
+
adapter writes to disk. Under Nx it writes to the generator's virtual tree, so
|
|
115
|
+
the write appears in the change list, `--dry-run` previews it, and nothing
|
|
116
|
+
reaches disk until Nx flushes. A write made with `node:fs` skips the tree: it
|
|
117
|
+
lands immediately, even under `--dry-run`, and stays when the run later fails.
|
|
118
|
+
|
|
119
|
+
**Write only inside the workspace.** The Nx adapter maps an absolute path
|
|
120
|
+
inside the workspace to a tree path. It cannot do that for a path outside, so
|
|
121
|
+
the write is silently re-rooted inside the workspace instead, while a read of
|
|
122
|
+
the same path falls back to disk. Build every path from
|
|
123
|
+
`configurationDirectoryPath`.
|
|
124
|
+
|
|
125
|
+
`makeDirectory` does nothing under Nx; writing a file creates its directories.
|
|
126
|
+
Reads through the Nx adapter look in the tree first, so a hook sees files
|
|
127
|
+
rendered earlier in the same run.
|
|
128
|
+
|
|
129
|
+
### The format list
|
|
130
|
+
|
|
131
|
+
The formatter receives `context.generatedFilePaths` after `postGenerate`. A
|
|
132
|
+
file the hook wrote is not on that list, so push its path to have it formatted:
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
context.generatedFilePaths.push(receiptPath);
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
The command-line host formats nothing by default, so the list there only
|
|
139
|
+
decides what the run reports. The Nx host formats every file changed in the
|
|
140
|
+
tree, hook writes included, whether or not it was pushed; push it anyway so
|
|
141
|
+
both hosts report the same files.
|
|
142
|
+
|
|
143
|
+
### When a hook throws
|
|
144
|
+
|
|
145
|
+
The run stops at the throw and the error propagates.
|
|
146
|
+
|
|
147
|
+
| Host | `preGenerate` throws | `postGenerate` throws |
|
|
148
|
+
| ------------ | --------------------- | --------------------------------------------------------------------------- |
|
|
149
|
+
| Command line | Nothing was written | The rendered files **stay on disk**; the formatter does not run |
|
|
150
|
+
| Nx | The tree is untouched | Rendered files sit in the tree, and `nx g` flushes nothing for a failed run |
|
|
151
|
+
|
|
152
|
+
The command line prints a hook's error with its stack trace and exits non-zero.
|
|
153
|
+
It does not say which hook threw, so put the generator and hook name in the
|
|
154
|
+
message. Under Nx the run is atomic on disk for both hooks, but only for writes
|
|
155
|
+
made through `context.filesystem`.
|
|
31
156
|
|
|
32
157
|
## Rendering
|
|
33
158
|
|
|
@@ -74,9 +199,9 @@ the reason above.
|
|
|
74
199
|
|
|
75
200
|
## Exports
|
|
76
201
|
|
|
77
|
-
`GenerationService`, `
|
|
78
|
-
`FileSystemAdapter`, `FormatterAdapter`, `GeneratorDefinition
|
|
79
|
-
|
|
202
|
+
`GenerationService`, `GenerationModule`, and the `DirectoryEntry`,
|
|
203
|
+
`FileSystemAdapter`, `FormatterAdapter`, and `GeneratorDefinition` types. The
|
|
204
|
+
hook types are re-exported for configurations from `@conformetry/configuration`.
|
|
80
205
|
|
|
81
206
|
## Test
|
|
82
207
|
|
|
@@ -130,7 +255,7 @@ What this project is judged against, as declared in its own `callidescope.config
|
|
|
130
255
|
|
|
131
256
|
| Callable | Breadth | Calls directly | Location |
|
|
132
257
|
| --- | --- | --- | --- |
|
|
133
|
-
| `GenerationService.runGenerator` | 4 | `GenerationService.resolveAdapters`, `GenerationService.normalizeInputs`, `GenerationService.buildSubstitutions`, `GenerationService.renderDirectory` | `projects/ic-suite/conformetry/conformetry-generation/src/modules/generation/generation.service.ts:
|
|
258
|
+
| `GenerationService.runGenerator` | 4 | `GenerationService.resolveAdapters`, `GenerationService.normalizeInputs`, `GenerationService.buildSubstitutions`, `GenerationService.renderDirectory` | `projects/ic-suite/conformetry/conformetry-generation/src/modules/generation/generation.service.ts:193` |
|
|
134
259
|
| `GenerationService.renderDirectory` | 2 | `ConfigurationService.renderPath`, `GenerationService.renderFile` | `projects/ic-suite/conformetry/conformetry-generation/src/modules/generation/generation.service.ts:106` |
|
|
135
260
|
| `GenerationService.listDirectory` | 1 | `GenerationService.map(…)` | `projects/ic-suite/conformetry/conformetry-generation/src/modules/generation/generation.service.ts:40` |
|
|
136
261
|
|
|
@@ -229,14 +354,14 @@ graph LR
|
|
|
229
354
|
|
|
230
355
|
### Project
|
|
231
356
|
|
|
232
|
-

|
|
358
|
+

|
|
234
359
|

|
|
235
360
|

|
|
236
361
|
|
|
237
362
|
### Measured Targets
|
|
238
363
|
|
|
239
|
-

|
|
240
365
|
|
|
241
366
|
### TypeScript
|
|
242
367
|
|
|
@@ -245,7 +370,7 @@ graph LR
|
|
|
245
370
|

|
|
246
371
|

|
|
247
372
|

|
|
248
|
-

|
|
249
374
|

|
|
250
375
|
|
|
251
376
|
### JavaScript
|
|
@@ -254,15 +379,15 @@ graph LR
|
|
|
254
379
|

|
|
255
380
|

|
|
256
381
|

|
|
257
|
-

|
|
258
383
|

|
|
259
|
-

|
|
385
|
+

|
|
386
|
+

|
|
262
387
|

|
|
263
388
|

|
|
264
|
-

|
|
390
|
+

|
|
266
391
|

|
|
267
392
|
|
|
268
393
|
### Python
|
|
@@ -418,23 +543,23 @@ graph LR
|
|
|
418
543
|
### Markdown
|
|
419
544
|
|
|
420
545
|

|
|
421
|
-

|
|
422
547
|

|
|
423
|
-

|
|
549
|
+

|
|
425
550
|

|
|
426
551
|

|
|
427
552
|

|
|
428
|
-

|
|
554
|
+

|
|
555
|
+

|
|
431
556
|

|
|
432
557
|

|
|
433
558
|

|
|
434
|
-

|
|
435
560
|

|
|
436
561
|

|
|
437
|
-

|
|
438
563
|

|
|
439
564
|

|
|
440
565
|
<!-- codometer:end -->
|
package/dist/src/index.d.ts
CHANGED
|
@@ -58,7 +58,8 @@ export declare class GenerationService {
|
|
|
58
58
|
private resolveAdapters;
|
|
59
59
|
/**
|
|
60
60
|
* Runs the generator lifecycle — `preGenerate`, render, `postGenerate`,
|
|
61
|
-
* format — and returns the
|
|
61
|
+
* format — and returns the generated file paths: the rendered paths sorted,
|
|
62
|
+
* then any path a `postGenerate` hook pushed, appended after the sort.
|
|
62
63
|
*/
|
|
63
64
|
runGenerator(args: RunGeneratorArguments): Promise<RunGeneratorResult>;
|
|
64
65
|
}
|
|
@@ -69,6 +70,13 @@ export { GeneratorDefinition }
|
|
|
69
70
|
* Arguments accepted by the runtime runner.
|
|
70
71
|
*/
|
|
71
72
|
declare interface RunGeneratorArguments {
|
|
73
|
+
/**
|
|
74
|
+
* Absolute directory of the configuration file that declared the generator.
|
|
75
|
+
*
|
|
76
|
+
* Handed to the hooks unchanged: the runtime derives nothing from it, since
|
|
77
|
+
* which file declared the generator is the host's knowledge.
|
|
78
|
+
*/
|
|
79
|
+
configurationDirectoryPath: string;
|
|
72
80
|
definition: GeneratorDefinition;
|
|
73
81
|
filesystem?: FileSystemAdapter;
|
|
74
82
|
formatter?: FormatterAdapter;
|
package/dist/src/index.js
CHANGED
|
@@ -90,7 +90,9 @@ var l = class GenerationService {
|
|
|
90
90
|
definitionName: e.definition.name,
|
|
91
91
|
inputs: r
|
|
92
92
|
}), a = {
|
|
93
|
+
configurationDirectoryPath: e.configurationDirectoryPath,
|
|
93
94
|
definition: e.definition,
|
|
95
|
+
filesystem: t,
|
|
94
96
|
generatedFilePaths: [],
|
|
95
97
|
input: r,
|
|
96
98
|
outputDirectoryPath: e.instancePath,
|
package/package.json
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
"url": "https://github.com/organizzolini/codebase/issues"
|
|
5
5
|
},
|
|
6
6
|
"dependencies": {
|
|
7
|
-
"@conformetry/configuration": "0.0.
|
|
8
|
-
"@conformetry/core": "0.0.
|
|
7
|
+
"@conformetry/configuration": "0.0.41",
|
|
8
|
+
"@conformetry/core": "0.0.40",
|
|
9
9
|
"@nestjs/common": "^11.1.21 || ^12.0.1",
|
|
10
10
|
"reflect-metadata": "^0.2.2"
|
|
11
11
|
},
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"devDependencies": {
|
|
14
14
|
"@golevelup/ts-vitest": "^4.0.0",
|
|
15
15
|
"@nestjs/testing": "^12.0.1",
|
|
16
|
-
"@nx/eslint-plugin": "^23.
|
|
16
|
+
"@nx/eslint-plugin": "^23.3.0",
|
|
17
17
|
"@swc/helpers": "^0.5.21",
|
|
18
18
|
"@types/node": "^26.5.1",
|
|
19
19
|
"@vitest/coverage-v8": "^5.0.0",
|
|
@@ -59,5 +59,5 @@
|
|
|
59
59
|
"strict": true
|
|
60
60
|
},
|
|
61
61
|
"types": "./dist/src/index.d.ts",
|
|
62
|
-
"version": "0.0.
|
|
62
|
+
"version": "0.0.41"
|
|
63
63
|
}
|