@neohm/nh-cli 1.4.1 → 2.0.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/README.md CHANGED
@@ -6,7 +6,7 @@ sibling [`@neohm/nestendx`](../nestendx).
6
6
 
7
7
  `nh` generates fully wired modules, entities, controllers, services, DTOs, data
8
8
  processors, migrations and seeds — and keeps your import barrels
9
- (`es6.classes.ts`) and `app.module.ts` registration in sync, so the project
9
+ (`module.registry.ts`) and `app.module.ts` registration in sync, so the project
10
10
  builds without any manual import wiring.
11
11
 
12
12
  ## Two flavours, one CLI
@@ -64,7 +64,7 @@ The project root is auto-detected by walking up from the current directory for a
64
64
  | `nh gen <flag>` | Generate one artifact instead of a whole module — see [Flag generation](#flag-generation). |
65
65
  | `nh migration` | Generate a standalone migration `<timestamp>M-<Name>.ts`. |
66
66
  | `nh seed` | Generate a seed file `<timestamp>S-<Name>.ts`. |
67
- | `nh sync` | Rebuild every `es6.classes.ts` barrel and register modules in `app.module.ts`. |
67
+ | `nh sync` | Rebuild every `module.registry.ts` barrel and register modules in `app.module.ts`. |
68
68
  | `nh check` | Dry-run of `sync` — show what would change without writing. |
69
69
  | `nh list` | List scaffolded modules with their entities and providers. |
70
70
  | `nh remove <name>` | Safely remove a scaffolded module and de-register it (migrations are preserved). |
@@ -83,7 +83,7 @@ $ nh gen
83
83
  ? Create controller (ShapeController)? Yes
84
84
  ? Create DTO (AddShapeDataDto)? Yes
85
85
  ? Create data processor (ShapeDataProcessor)? Yes
86
- ? Create listing processor (ShapeListProcessor)? Yes
86
+ ? Create filter processor (ShapeFilterProcessor)? Yes
87
87
  ? Create migration (M-AddShapeTable)? Yes
88
88
  ```
89
89
 
@@ -92,13 +92,13 @@ Produces, under `src/shape/`:
92
92
  ```text
93
93
  shape/
94
94
  shape.module.ts # ShapeModule (imports CommonModule, QueueModule, ...)
95
- es6.classes.ts # barrel of controllers/services/jobs/subscribers
95
+ module.registry.ts # barrel of controllers/services/jobs/subscribers
96
96
  controllers/shape.controller.ts
97
97
  services/shape.service.ts
98
98
  dtos/add.shape.data.dto.ts
99
99
  entities/shape.entity.ts
100
100
  libraries/shape.data.processor.ts
101
- libraries/shape.list.processor.ts
101
+ libraries/shape.filter.processor.ts
102
102
  enums/ jobs/ subscribers/
103
103
  external/ # optional API-key surface (nh gen -x ...)
104
104
  controllers/ libraries/ services/
@@ -125,11 +125,11 @@ Generated artifacts extend the `@neohm/nestend` base classes:
125
125
  `TenantEntity` relation, and `TenantScopeSubscriber` stamps and guards it),
126
126
  `CommonEntity` under `nhx`; both with an empty `attributes` jsonb column
127
127
  - DTO → `CommonDataDto`
128
- - Data processor → `CommonDataProcessor` (`process()` → `validate()` → `set()`),
128
+ - Data processor → `BaseDataProcessor` (`process()` → `validate()` → `set()`),
129
129
  reached through the service's `upsert()`. It takes the caller and, on edit,
130
130
  loads the row scoped to them — another owner's `id` is a field error, never an
131
131
  update.
132
- - Listing processor → `CommonListProcessor` (column allowlist config, `id` default sort). It takes `CommonListFilterDto` directly — no per-list DTO is generated, since paging, sorting, filters and free-text search all live on the base DTO and the filterable columns are declared in the processor's `columns` config.
132
+ - Filter processor → `BaseFilterProcessor` (column allowlist config, `id` default sort). It takes `CommonListFilterDto` directly — no per-list DTO is generated, since paging, sorting, filters and free-text search all live on the base DTO and the filterable columns are declared in the processor's `columns` config.
133
133
 
134
134
  ### Controller → service → processor
135
135
 
@@ -150,7 +150,7 @@ answers you already gave:
150
150
  | `get(user, id)` | always | `GET /api/v1/shape/:id` |
151
151
  | `remove(user, id)` | always | `DELETE /api/v1/shape/:id` |
152
152
  | `upsert(user, data)` | data processor: Yes | `POST /api/v1/shape` |
153
- | `list(user, data)` | listing processor: Yes | `POST /api/v1/shape/list` |
153
+ | `list(user, data)` | filter processor: Yes | `POST /api/v1/shape/list` |
154
154
 
155
155
  `get()` and `remove()` keep their logic in the service — no processor: `remove()`
156
156
  soft-deletes through the same owner-scoped lookup as `get()`. A module that
@@ -210,14 +210,14 @@ identifiers only: create the `sys_scopes` row and the three `sys_roles` rows
210
210
  Bare `nh gen` scaffolds a whole module. Once that module exists, most work is
211
211
  adding *one* more file to it — which is what the target flags do. Each asks
212
212
  only what it cannot infer, refuses to shadow a name already in the project,
213
- registers the result in `es6.classes.ts`, and formats what it wrote.
213
+ registers the result in `module.registry.ts`, and formats what it wrote.
214
214
 
215
215
  | Command | Generates | Asks |
216
216
  | --- | --- | --- |
217
217
  | `nh gen -c` | `controllers/<name>.controller.ts` | module, name, route path |
218
218
  | `nh gen -s` | `services/<name>.service.ts` | module, name |
219
219
  | `nh gen -dp` | `libraries/<name>.data.processor.ts` + `dtos/add.<name>.data.dto.ts` | module, name |
220
- | `nh gen -lp` | `libraries/<name>.list.processor.ts` | module, name, table name |
220
+ | `nh gen -fp` | `libraries/<name>.filter.processor.ts` | module, name, table name |
221
221
  | `nh gen -e` | `entities/<name>.entity.ts` + `dtos/<name>.attributes.dto.ts` + `jobs/<name>.job.ts` + `subscribers/<name>.subscriber.ts` + a migration | module, name, table name |
222
222
  | `nh gen -j` | `jobs/<name>.job.ts` | module, name |
223
223
 
@@ -230,10 +230,10 @@ entity, `job.constants.ts` / `job.maps.ts` for the job it brought along.
230
230
 
231
231
  The two jobs are deliberately different shapes:
232
232
 
233
- | | Driven by | `handle()` takes |
234
- | --- | --- | --- |
235
- | the job `-e` brings along | the entity's subscriber | `event: DatabaseEventDto<<Name>Entity>` |
236
- | `nh gen -j` | an explicit `dispatch()` | `data: unknown` |
233
+ | | Extends | Driven by | `handle()` takes |
234
+ | --- | --- | --- | --- |
235
+ | the job `-e` brings along | `BaseEntityJob` | the entity's subscriber | `event: DatabaseEventDto<<Name>Entity>` |
236
+ | `nh gen -j` | `BaseJob` | an explicit `dispatch()` | `data: unknown` |
237
237
 
238
238
  So reach for `-j` when you want a queue worker that is not tied to a table's
239
239
  lifecycle.
@@ -250,7 +250,7 @@ Only one target flag per run; the module is created if it does not exist yet.
250
250
  | `nh gen -x -c` | `external/controllers/external.<name>.controller.ts` |
251
251
  | `nh gen -x -s` | `external/services/external.<name>.service.ts` |
252
252
  | `nh gen -x -dp` | `external/libraries/external.<name>.data.processor.ts` |
253
- | `nh gen -x -lp` | `external/libraries/external.<name>.list.processor.ts` |
253
+ | `nh gen -x -fp` | `external/libraries/external.<name>.filter.processor.ts` |
254
254
 
255
255
  External files take an `external.` filename prefix and an `External` class
256
256
  prefix. An external controller differs from an internal one in three ways, all
@@ -262,7 +262,7 @@ than `AuthService`.
262
262
  inward/outward face, so there is nothing to mirror. Both refuse the flag rather
263
263
  than quietly ignoring it.
264
264
 
265
- External providers register into the *same* `es6.classes.ts` categories as
265
+ External providers register into the *same* `module.registry.ts` categories as
266
266
  their internal siblings, listed after them — so `nh sync` and `nh check` see
267
267
  `<module>/external/<folder>` as well as `<module>/<folder>`.
268
268
 
@@ -297,7 +297,7 @@ this keeps that true for entity names long enough to push a line past 80
297
297
  columns. A project without prettier installed still gets its files, just
298
298
  unformatted.
299
299
 
300
- - Migration → `MigrationUtility`
300
+ - Migration → `MigrationHelper`
301
301
  - Seed → `SeederUtility`
302
302
 
303
303
  Re-running `gen` for an existing module reuses it and only adds new files —
@@ -306,7 +306,7 @@ existing files are never overwritten.
306
306
  ## `nh sync` and `nh check`
307
307
 
308
308
  `sync` scans every module under `src/` — including its `external/` mirror —
309
- and regenerates its `es6.classes.ts` barrel from the files actually present in
309
+ and regenerates its `module.registry.ts` barrel from the files actually present in
310
310
  `controllers/`, `services/`, `libraries/`, `dtos/`, `jobs/` and
311
311
  `subscribers/`, then ensures each module is imported and listed in
312
312
  `app.module.ts`. Files are classified by their **folder** and the presence of an
@@ -317,9 +317,9 @@ never silently dropped. The operation is idempotent.
317
317
 
318
318
  ```text
319
319
  $ nh check
320
- es6.classes barrels:
321
- ok src/shape/es6.classes.ts
322
- update src/test/es6.classes.ts
320
+ module registries:
321
+ ok src/shape/module.registry.ts
322
+ update src/test/module.registry.ts
323
323
  + services: TestService
324
324
 
325
325
  app.module.ts:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neohm/nh-cli",
3
- "version": "1.4.1",
3
+ "version": "2.0.0",
4
4
  "description": "nh / nhx — Command Line Interface for neohm. NestJS projects",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -21,8 +21,8 @@ async function check() {
21
21
  const plan = engine.buildPlan(paths, modules);
22
22
  let changes = 0;
23
23
 
24
- console.log(chalk.bold('\nes6.classes barrels:'));
25
- for (const p of plan.es6) {
24
+ console.log(chalk.bold('\nmodule registries:'));
25
+ for (const p of plan.registries) {
26
26
  const rel = path.relative(paths.root, p.path);
27
27
  if (p.changed) {
28
28
  changes++;
@@ -21,7 +21,7 @@ const { registerJob, registerEntity } = require('../lib/registry');
21
21
  const { findConflict, describeConflict } = require('../lib/collision');
22
22
 
23
23
  /**
24
- * Single-artifact generation: `nh gen -c`, `-s`, `-dp`, `-lp`, `-e`, `-j`, and
24
+ * Single-artifact generation: `nh gen -c`, `-s`, `-dp`, `-fp`, `-e`, `-j`, and
25
25
  * the `-x` (external, API-key surface) variants of the first four.
26
26
  *
27
27
  * Bare `nh gen` still runs the full wizard — this path exists for adding one
@@ -34,7 +34,7 @@ const LABELS = {
34
34
  controller: 'controller',
35
35
  service: 'service',
36
36
  dataProcessor: 'data processor',
37
- listProcessor: 'list processor',
37
+ filterProcessor: 'filter processor',
38
38
  entity: 'entity',
39
39
  job: 'job',
40
40
  };
@@ -44,7 +44,7 @@ const DESCRIBES = {
44
44
  controller: 'controller',
45
45
  service: 'service',
46
46
  dataProcessor: 'data processor (+ its payload DTO)',
47
- listProcessor: 'list processor',
47
+ filterProcessor: 'filter processor',
48
48
  entity: 'entity, its job and subscriber, and a migration',
49
49
  job: 'job',
50
50
  };
@@ -55,14 +55,14 @@ const EXTERNAL_CAPABLE = new Set([
55
55
  'controller',
56
56
  'service',
57
57
  'dataProcessor',
58
- 'listProcessor',
58
+ 'filterProcessor',
59
59
  ]);
60
60
 
61
61
  const FLAG = {
62
62
  controller: '-c',
63
63
  service: '-s',
64
64
  dataProcessor: '-dp',
65
- listProcessor: '-lp',
65
+ filterProcessor: '-fp',
66
66
  entity: '-e',
67
67
  job: '-j',
68
68
  };
@@ -103,14 +103,14 @@ function primaryArtifacts(target, moduleDir, n, external) {
103
103
  return external
104
104
  ? one(n.externalProcessorClass, 'libraries', n.externalProcessorFile)
105
105
  : one(n.processorClass, 'libraries', n.processorFile);
106
- case 'listProcessor':
106
+ case 'filterProcessor':
107
107
  return external
108
108
  ? one(
109
- n.externalListProcessorClass,
109
+ n.externalFilterProcessorClass,
110
110
  'libraries',
111
- n.externalListProcessorFile,
111
+ n.externalFilterProcessorFile,
112
112
  )
113
- : one(n.listProcessorClass, 'libraries', n.listProcessorFile);
113
+ : one(n.filterProcessorClass, 'libraries', n.filterProcessorFile);
114
114
  case 'entity':
115
115
  return [
116
116
  {
@@ -151,11 +151,11 @@ function ensureModule(paths, moduleDot, external, report) {
151
151
  }
152
152
 
153
153
  const modulePath = path.join(moduleDir, `${moduleDot}.module.ts`);
154
- const es6Path = path.join(moduleDir, 'es6.classes.ts');
154
+ const registryPath = path.join(moduleDir, 'module.registry.ts');
155
155
  const a = writeFile(modulePath, tpl.moduleFile(moduleDot));
156
- const b = writeFile(es6Path, tpl.emptyEs6Classes());
156
+ const b = writeFile(registryPath, tpl.emptyModuleRegistry());
157
157
  if (a !== 'skipped') report(a, modulePath, paths.root);
158
- if (b !== 'skipped') report(b, es6Path, paths.root);
158
+ if (b !== 'skipped') report(b, registryPath, paths.root);
159
159
 
160
160
  if (!existed) log.info(`Created module "${moduleDot}".`);
161
161
  return moduleDir;
@@ -166,7 +166,7 @@ async function genFlag(target, { external = false } = {}) {
166
166
  if (external && !EXTERNAL_CAPABLE.has(target)) {
167
167
  throw new Error(
168
168
  `-x is not supported for ${LABELS[target]} — external applies to ` +
169
- `-c, -s, -dp and -lp only. Run \`nh gen ${FLAG[target]}\` without -x.`,
169
+ `-c, -s, -dp and -fp only. Run \`nh gen ${FLAG[target]}\` without -x.`,
170
170
  );
171
171
  }
172
172
 
@@ -225,7 +225,7 @@ async function genFlag(target, { external = false } = {}) {
225
225
  }
226
226
 
227
227
  let tableName;
228
- if (target === 'listProcessor' || target === 'entity') {
228
+ if (target === 'filterProcessor' || target === 'entity') {
229
229
  ({ tableName } = await inquirer.prompt([
230
230
  {
231
231
  type: 'input',
@@ -295,8 +295,8 @@ async function genFlag(target, { external = false } = {}) {
295
295
  write(path.join(moduleDir, 'dtos', n.dtoFile), tpl.dto(rawName));
296
296
  break;
297
297
 
298
- case 'listProcessor':
299
- write(dest, tpl.listProcessor(rawName, tableName, { external }));
298
+ case 'filterProcessor':
299
+ write(dest, tpl.filterProcessor(rawName, tableName, { external }));
300
300
  break;
301
301
 
302
302
  case 'entity': {
@@ -25,7 +25,7 @@ async function gen() {
25
25
 
26
26
  // Every file this run writes or rewrites, formatted in one pass at the end.
27
27
  // Each write is announced through report(), so recording paths here catches
28
- // templates, the constant registries, the es6 barrel and app.module alike.
28
+ // templates, the constant registries, the module registry and app.module alike.
29
29
  const touched = [];
30
30
  const report = (result, filePath, root) => {
31
31
  if (result !== "skipped") touched.push(filePath);
@@ -51,7 +51,7 @@ async function gen() {
51
51
  log.info(`Creating module "${moduleDot}".`);
52
52
  }
53
53
 
54
- // Always ensure the module skeleton (folders + module file + es6 barrel).
54
+ // Always ensure the module skeleton (folders + module file + module registry).
55
55
  for (const sub of MODULE_SUBFOLDERS) ensureDir(path.join(moduleDir, sub));
56
56
  report(
57
57
  writeFile(
@@ -61,8 +61,8 @@ async function gen() {
61
61
  path.join(moduleDir, `${moduleDot}.module.ts`),
62
62
  paths.root,
63
63
  );
64
- const es6Path = path.join(moduleDir, "es6.classes.ts");
65
- report(writeFile(es6Path, tpl.emptyEs6Classes()), es6Path, paths.root);
64
+ const registryPath = path.join(moduleDir, "module.registry.ts");
65
+ report(writeFile(registryPath, tpl.emptyModuleRegistry()), registryPath, paths.root);
66
66
 
67
67
  // 2. Entity ---------------------------------------------------------------
68
68
  const { entityName } = await inquirer.prompt([
@@ -125,7 +125,7 @@ async function gen() {
125
125
  // job, subscriber or sibling service goes through, never an opt-in. It is
126
126
  // written after the processor prompts, because those answers decide which
127
127
  // methods it (and the controller) ships with: `get()` always, `upsert()`
128
- // with a data processor, `list()` with a listing processor.
128
+ // with a data processor, `list()` with a filter processor.
129
129
 
130
130
  // 5. Optional: data processor (includes Add*DataDto) ----------------------
131
131
  const { processor } = await inquirer.prompt([
@@ -145,20 +145,20 @@ async function gen() {
145
145
  report(writeFile(procPath, tpl.processor(entityName, { withEntity: true })), procPath, paths.root);
146
146
  }
147
147
 
148
- // 6. Optional: listing processor (takes CommonListFilterDto directly) ------
149
- const { listProcessor } = await inquirer.prompt([
148
+ // 6. Optional: filter processor (takes CommonListFilterDto directly) ------
149
+ const { filterProcessor } = await inquirer.prompt([
150
150
  {
151
151
  type: "confirm",
152
- name: "listProcessor",
153
- message: `Create listing processor (${n.listProcessorClass})?`,
152
+ name: "filterProcessor",
153
+ message: `Create filter processor (${n.filterProcessorClass})?`,
154
154
  default: true,
155
155
  },
156
156
  ]);
157
157
 
158
- if (listProcessor) {
159
- const listProcPath = path.join(moduleDir, "libraries", n.listProcessorFile);
158
+ if (filterProcessor) {
159
+ const listProcPath = path.join(moduleDir, "libraries", n.filterProcessorFile);
160
160
  report(
161
- writeFile(listProcPath, tpl.listProcessor(entityName, tableName)),
161
+ writeFile(listProcPath, tpl.filterProcessor(entityName, tableName)),
162
162
  listProcPath,
163
163
  paths.root,
164
164
  );
@@ -166,7 +166,7 @@ async function gen() {
166
166
 
167
167
  const servicePath = path.join(moduleDir, "services", n.serviceFile);
168
168
  report(
169
- writeFile(servicePath, tpl.service(entityName, { processor, listProcessor })),
169
+ writeFile(servicePath, tpl.service(entityName, { processor, filterProcessor })),
170
170
  servicePath,
171
171
  paths.root,
172
172
  );
@@ -176,7 +176,7 @@ async function gen() {
176
176
  report(
177
177
  writeFile(
178
178
  p,
179
- tpl.controller(entityName, { processor, listProcessor, enums }),
179
+ tpl.controller(entityName, { processor, filterProcessor, enums }),
180
180
  ),
181
181
  p,
182
182
  paths.root,
@@ -19,7 +19,7 @@ async function sync() {
19
19
  const plan = engine.buildPlan(paths, modules);
20
20
  const written = engine.applyPlan(plan);
21
21
 
22
- for (const p of plan.es6) {
22
+ for (const p of plan.registries) {
23
23
  const rel = path.relative(paths.root, p.path);
24
24
  if (p.changed) log.overwritten(rel);
25
25
  else console.log(` ${chalk.dim('ok')} ${rel}`);
package/src/index.js CHANGED
@@ -32,12 +32,12 @@ program
32
32
 
33
33
  // `gen` with no target flag runs the full wizard; a target flag generates just
34
34
  // that one artifact. -x mirrors a target onto the module's external (API-key)
35
- // surface and applies to -c, -s, -dp and -lp only.
35
+ // surface and applies to -c, -s, -dp and -fp only.
36
36
  const GEN_TARGETS = [
37
37
  ['controller', 'controller'],
38
38
  ['service', 'service'],
39
39
  ['dataProcessor', 'dataProcessor'],
40
- ['listProcessor', 'listProcessor'],
40
+ ['filterProcessor', 'filterProcessor'],
41
41
  ['entity', 'entity'],
42
42
  ['job', 'job'],
43
43
  ];
@@ -50,7 +50,7 @@ program
50
50
  .option('-c, --controller', 'generate only a controller')
51
51
  .option('-s, --service', 'generate only a service')
52
52
  .option('-dp, --data-processor', 'generate only a data processor')
53
- .option('-lp, --list-processor', 'generate only a listing processor')
53
+ .option('-fp, --filter-processor', 'generate only a filter processor')
54
54
  .option('-e, --entity', 'generate an entity and its migration')
55
55
  .option('-j, --job', 'generate only a job')
56
56
  .option('-x, --external', 'put it on the external (api/e/v1) surface')
@@ -62,7 +62,7 @@ Examples:
62
62
  ${cli} gen -c controller only (asks module, name, route path)
63
63
  ${cli} gen -s bare injectable service
64
64
  ${cli} gen -dp data processor (+ its Add<Name>DataDto if missing)
65
- ${cli} gen -lp listing processor
65
+ ${cli} gen -fp filter processor
66
66
  ${cli} gen -e entity + migration, registered in the constants/maps
67
67
  ${cli} gen -j job, registered in job.constants/job.maps
68
68
  ${cli} gen -x -c external controller under <module>/external/controllers
@@ -75,12 +75,12 @@ Examples:
75
75
  );
76
76
  if (chosen.length > 1) {
77
77
  throw new Error(
78
- 'Pick one target flag at a time (-c, -s, -dp, -lp, -e or -j).',
78
+ 'Pick one target flag at a time (-c, -s, -dp, -fp, -e or -j).',
79
79
  );
80
80
  }
81
81
  if (!chosen.length) {
82
82
  if (opts.external) {
83
- throw new Error('-x needs a target: -c, -s, -dp or -lp.');
83
+ throw new Error('-x needs a target: -c, -s, -dp or -fp.');
84
84
  }
85
85
  return require('./commands/gen')();
86
86
  }
@@ -102,7 +102,7 @@ program
102
102
 
103
103
  program
104
104
  .command('sync')
105
- .description('rebuild es6.classes barrels and register modules in app.module.ts')
105
+ .description('rebuild module registries and register modules in app.module.ts')
106
106
  .action(run(() => require('./commands/sync')()));
107
107
 
108
108
  program
@@ -7,7 +7,7 @@ const path = require('path');
7
7
  * Which package the generated code is written against.
8
8
  *
9
9
  * The two share every convention this CLI encodes — dot.separated filenames,
10
- * the processor lifecycle, es6.classes barrels, the migration utility — and
10
+ * the processor lifecycle, module registries, the migration utility — and
11
11
  * differ in what a record belongs to. `nestend` is the tenanted model: rows
12
12
  * carry a `tenant_id`, access is a scope *and* a role. `nestendx` is the B2C
13
13
  * one: users register themselves and hold scopes alone, so a row belongs to the
@@ -8,12 +8,12 @@ const scan = require('./source.scan');
8
8
  /**
9
9
  * The sync engine is the single brain behind `nh sync`, `nh check` and the
10
10
  * auto-wiring step of `nh gen`. It scans scaffolded modules, regenerates each
11
- * module's es6.classes.ts barrel from the files actually present on disk, and
11
+ * module's module.registry.ts from the files actually present on disk, and
12
12
  * registers every module in app.module.ts — so the project builds without any
13
13
  * manual import wiring.
14
14
  */
15
15
 
16
- // Provider categories registered through es6.classes.ts. Files are classified
16
+ // Provider categories registered through module.registry.ts. Files are classified
17
17
  // by the folder they live in (not by a fragile filename suffix) so that
18
18
  // non-standard names — e.g. the boilerplate's `test.service..ts` — are still
19
19
  // picked up and never silently dropped from the barrel.
@@ -27,12 +27,12 @@ const CATEGORIES = [
27
27
  ];
28
28
 
29
29
  // Files in a category folder that are not providers themselves.
30
- const NON_PROVIDER_FILES = new Set(['es6.classes.ts', 'index.ts']);
30
+ const NON_PROVIDER_FILES = new Set(['module.registry.ts', 'index.ts']);
31
31
 
32
32
  // A module may expose an API-key surface from `<module>/external/<folder>`
33
33
  // (e.g. external/controllers/external.test.controller.ts). Those classes are
34
34
  // providers of the same categories as their internal siblings and belong in
35
- // the same es6.classes arrays — listed after the internal ones — so the
35
+ // the same module.registry arrays — listed after the internal ones — so the
36
36
  // scanner has to walk both roots or `nh sync` would strip them from the
37
37
  // barrel.
38
38
  const EXTERNAL_DIR = 'external';
@@ -109,7 +109,7 @@ function scanModule(dir, modFile) {
109
109
  moduleFile: modFile,
110
110
  moduleClass: exportedClassName(modFile),
111
111
  moduleImportPath: `./${moduleDot}/${path.basename(modFile, '.ts')}`,
112
- es6Path: path.join(dir, 'es6.classes.ts'),
112
+ registryPath: path.join(dir, 'module.registry.ts'),
113
113
  providers,
114
114
  entities: listTsFiles(path.join(dir, 'entities'), '.entity.ts'),
115
115
  dtos: listTsFiles(path.join(dir, 'dtos'), '.dto.ts'),
@@ -117,7 +117,7 @@ function scanModule(dir, modFile) {
117
117
  }
118
118
 
119
119
  /**
120
- * Render the es6.classes.ts content for a scanned module.
120
+ * Render the module.registry.ts content for a scanned module.
121
121
  *
122
122
  * The array literals are wrapped exactly the way prettier's 80-column printer
123
123
  * would: inline while they fit, one class per line once they don't. `nh gen`
@@ -125,7 +125,7 @@ function scanModule(dir, modFile) {
125
125
  * every later `nh check` would report the barrel as drifted purely because
126
126
  * prettier had reflowed it.
127
127
  */
128
- function buildEs6Content(mod) {
128
+ function buildRegistryContent(mod) {
129
129
  const importLines = [];
130
130
  const arrayLines = [];
131
131
  for (const cat of CATEGORIES) {
@@ -142,19 +142,19 @@ function buildEs6Content(mod) {
142
142
  );
143
143
  }
144
144
  const header = importLines.length ? importLines.join('\n') + '\n\n' : '';
145
- return `${header}export const es6Classes = {\n${arrayLines.join('\n')}\n};\n`;
145
+ return `${header}export const moduleRegistry = {\n${arrayLines.join('\n')}\n};\n`;
146
146
  }
147
147
 
148
- /** Plan the es6.classes.ts rewrite for one module. */
149
- function planEs6(mod) {
150
- const next = buildEs6Content(mod);
151
- const current = fs.existsSync(mod.es6Path)
152
- ? fs.readFileSync(mod.es6Path, 'utf8')
148
+ /** Plan the module.registry.ts rewrite for one module. */
149
+ function planRegistry(mod) {
150
+ const next = buildRegistryContent(mod);
151
+ const current = fs.existsSync(mod.registryPath)
152
+ ? fs.readFileSync(mod.registryPath, 'utf8')
153
153
  : null;
154
154
  return {
155
- type: 'es6',
155
+ type: 'registry',
156
156
  moduleDot: mod.moduleDot,
157
- path: mod.es6Path,
157
+ path: mod.registryPath,
158
158
  current,
159
159
  next,
160
160
  changed: current !== next,
@@ -251,18 +251,18 @@ function planAppModule(paths, modules) {
251
251
  };
252
252
  }
253
253
 
254
- /** Full plan: every module's es6 barrel + app.module registration. */
254
+ /** Full plan: every module's module registry + app.module registration. */
255
255
  function buildPlan(paths, modules = scanModules(paths)) {
256
256
  return {
257
257
  modules,
258
- es6: modules.map(planEs6),
258
+ registries: modules.map(planRegistry),
259
259
  appModule: planAppModule(paths, modules),
260
260
  };
261
261
  }
262
262
 
263
263
  function applyPlan(plan) {
264
264
  const written = [];
265
- for (const p of plan.es6) {
265
+ for (const p of plan.registries) {
266
266
  if (p.changed) {
267
267
  fs.writeFileSync(p.path, p.next);
268
268
  written.push(p.path);
@@ -280,8 +280,8 @@ module.exports = {
280
280
  EXTERNAL_DIR,
281
281
  scanModules,
282
282
  scanModule,
283
- buildEs6Content,
284
- planEs6,
283
+ buildRegistryContent,
284
+ planRegistry,
285
285
  planAppModule,
286
286
  buildPlan,
287
287
  applyPlan,
@@ -15,7 +15,7 @@ const { accessNames } = require('./access');
15
15
  * Code templates. All generated code imports shared base classes from the
16
16
  * package the active flavour names — `@neohm/nestend` under `nh`,
17
17
  * `@neohm/nestendx` under `nhx` (verified exports: CommonEntity, CommonDataDto,
18
- * CommonDataProcessor, MigrationUtility, SeederUtility, etc.) — and matches the
18
+ * BaseDataProcessor, MigrationHelper, SeederUtility, etc.) — and matches the
19
19
  * dot.separated filename / PascalCase class conventions used across the
20
20
  * boilerplates.
21
21
  *
@@ -59,8 +59,8 @@ function names(base) {
59
59
  dtoFile: `add.${dot}.data.dto.ts`,
60
60
  processorClass: `${pascal}DataProcessor`,
61
61
  processorFile: `${dot}.data.processor.ts`,
62
- listProcessorClass: `${pascal}ListProcessor`,
63
- listProcessorFile: `${dot}.list.processor.ts`,
62
+ filterProcessorClass: `${pascal}FilterProcessor`,
63
+ filterProcessorFile: `${dot}.filter.processor.ts`,
64
64
  subscriberClass: `${pascal}Subscriber`,
65
65
  subscriberFile: `${dot}.subscriber.ts`,
66
66
  jobClass: `${pascal}Job`,
@@ -74,8 +74,8 @@ function names(base) {
74
74
  externalServiceFile: `external.${dot}.service.ts`,
75
75
  externalProcessorClass: `External${pascal}DataProcessor`,
76
76
  externalProcessorFile: `external.${dot}.data.processor.ts`,
77
- externalListProcessorClass: `External${pascal}ListProcessor`,
78
- externalListProcessorFile: `external.${dot}.list.processor.ts`,
77
+ externalFilterProcessorClass: `External${pascal}FilterProcessor`,
78
+ externalFilterProcessorFile: `external.${dot}.filter.processor.ts`,
79
79
  // Fed through naming.migrationFileName/migrationClassName so the migration
80
80
  // `nh gen` writes is named exactly like one from `nh migration`.
81
81
  migrationName: `Add${pascal}Table`,
@@ -137,14 +137,14 @@ function attributesDto(base) {
137
137
  */
138
138
  function controller(
139
139
  base,
140
- { processor = false, listProcessor = false, enums = {} } = {},
140
+ { processor = false, filterProcessor = false, enums = {} } = {},
141
141
  ) {
142
142
  const n = names(base);
143
143
  const a = accessNames(base);
144
144
  const scopeEnum = enums.scope || 'ScopeEnum';
145
145
  const roleEnum = enums.role || 'RoleEnum';
146
146
  const svcProp = `${n.camel}Service`;
147
- const hasPost = processor || listProcessor;
147
+ const hasPost = processor || filterProcessor;
148
148
 
149
149
  // @nestjs/common members, alphabetised the way prettier leaves them.
150
150
  const nestCommon = [
@@ -159,7 +159,7 @@ function controller(
159
159
  nestCommon.sort();
160
160
 
161
161
  const nestendImports = ['AuthService'];
162
- if (listProcessor) nestendImports.push('CommonListFilterDto');
162
+ if (filterProcessor) nestendImports.push('CommonListFilterDto');
163
163
  nestendImports.push('StrictValidationPipe');
164
164
 
165
165
  const imports = [
@@ -218,7 +218,7 @@ function controller(
218
218
  }`);
219
219
  }
220
220
 
221
- if (listProcessor) {
221
+ if (filterProcessor) {
222
222
  methods.push(` @Post('list')
223
223
  @ApiOperation({ summary: 'List, search and filter ${n.kebab}.' })
224
224
  async list(@Body() body: CommonListFilterDto) {
@@ -259,14 +259,14 @@ ${methods.join('\n\n')}
259
259
  * controller, so nothing downstream has to know how a record is fetched.
260
260
  *
261
261
  * `get()` is unconditional — it is the one operation that needs no processor.
262
- * `upsert()` appears with a data processor, `list()` with a listing processor.
262
+ * `upsert()` appears with a data processor, `list()` with a filter processor.
263
263
  */
264
- function service(base, { processor = false, listProcessor = false } = {}) {
264
+ function service(base, { processor = false, filterProcessor = false } = {}) {
265
265
  const n = names(base);
266
266
  const label = toWords(base).join(' ');
267
267
 
268
268
  const nestendImports = [];
269
- if (listProcessor) {
269
+ if (filterProcessor) {
270
270
  nestendImports.push('CommonListFilterDto', 'ListFilterService');
271
271
  }
272
272
  nestendImports.push('NotFoundException', 'UserEntity');
@@ -275,9 +275,9 @@ function service(base, { processor = false, listProcessor = false } = {}) {
275
275
  namedImport(nestendImports, pkg()),
276
276
  `import { Injectable } from '@nestjs/common';`,
277
277
  ];
278
- if (listProcessor) {
278
+ if (filterProcessor) {
279
279
  imports.push(
280
- `import { ${n.listProcessorClass} } from '../libraries/${n.dot}.list.processor';`,
280
+ `import { ${n.filterProcessorClass} } from '../libraries/${n.dot}.filter.processor';`,
281
281
  );
282
282
  }
283
283
  if (processor) {
@@ -291,7 +291,7 @@ function service(base, { processor = false, listProcessor = false } = {}) {
291
291
  );
292
292
 
293
293
  const members = [];
294
- if (listProcessor) {
294
+ if (filterProcessor) {
295
295
  members.push(
296
296
  ` constructor(protected readonly listFilterService: ListFilterService) {}`,
297
297
  );
@@ -328,12 +328,12 @@ function service(base, { processor = false, listProcessor = false } = {}) {
328
328
  }`);
329
329
  }
330
330
 
331
- if (listProcessor) {
331
+ if (filterProcessor) {
332
332
  // Emit the call already wrapped the way prettier's 80-column printer
333
333
  // would, so a long entity name doesn't leave the generated file dirty.
334
334
  // Prettier's three tiers: keep the fluent one-liner; else break the
335
335
  // .process() argument; else break the constructor arguments too.
336
- const call = `new ${n.listProcessorClass}(this.listFilterService, user)`;
336
+ const call = `new ${n.filterProcessorClass}(this.listFilterService, user)`;
337
337
  const oneLine = ` return ${call}.process(data);`;
338
338
  const brokenArg = ` return ${call}.process(`;
339
339
  let body;
@@ -342,7 +342,7 @@ function service(base, { processor = false, listProcessor = false } = {}) {
342
342
  } else if (brokenArg.length <= 80) {
343
343
  body = `${brokenArg}\n data,\n );`;
344
344
  } else {
345
- body = ` return new ${n.listProcessorClass}(\n this.listFilterService,\n user,\n ).process(data);`;
345
+ body = ` return new ${n.filterProcessorClass}(\n this.listFilterService,\n user,\n ).process(data);`;
346
346
  }
347
347
  members.push(` async list(user: UserEntity, data: CommonListFilterDto) {
348
348
  ${body}
@@ -424,12 +424,12 @@ export class ${cls} {}
424
424
  */
425
425
  function additionalJob(base) {
426
426
  const n = names(base);
427
- return `import { CommonJob, QueueService } from '${pkg()}';
427
+ return `import { BaseJob, QueueService } from '${pkg()}';
428
428
  import { Injectable } from '@nestjs/common';
429
429
  import { JobConstants } from '../../constants/job.constants';
430
430
 
431
431
  @Injectable()
432
- export class ${n.jobClass} extends CommonJob {
432
+ export class ${n.jobClass} extends BaseJob {
433
433
  constructor(protected readonly queueService: QueueService) {
434
434
  super(JobConstants.${n.camel}Job);
435
435
  }
@@ -458,10 +458,10 @@ function processor(base, { external = false, withEntity = false } = {}) {
458
458
  const up = external ? '../..' : '..';
459
459
  const cls = external ? n.externalProcessorClass : n.processorClass;
460
460
  if (external) {
461
- return `import { CommonDataProcessor } from '${pkg()}';
461
+ return `import { BaseDataProcessor } from '${pkg()}';
462
462
  import { ${n.dtoClass} } from '${up}/dtos/add.${n.dot}.data.dto';
463
463
 
464
- export class ${cls} extends CommonDataProcessor {
464
+ export class ${cls} extends BaseDataProcessor {
465
465
  protected payload: ${n.dtoClass};
466
466
 
467
467
  async process(data: ${n.dtoClass}) {
@@ -518,10 +518,10 @@ export class ${cls} extends CommonDataProcessor {
518
518
  : ` private set(): void {
519
519
  // TODO: persist ${n.pascal} from this.payload, assigning fields explicitly.
520
520
  }`;
521
- return `import { CommonDataProcessor, UserEntity } from '${pkg()}';
521
+ return `import { BaseDataProcessor, UserEntity } from '${pkg()}';
522
522
  import { ${n.dtoClass} } from '${up}/dtos/add.${n.dot}.data.dto';${entityImport}
523
523
 
524
- export class ${cls} extends CommonDataProcessor {
524
+ export class ${cls} extends BaseDataProcessor {
525
525
  protected payload: ${n.dtoClass};${existingField}
526
526
 
527
527
  constructor(private readonly user: UserEntity) {
@@ -558,13 +558,13 @@ ${set}
558
558
  `;
559
559
  }
560
560
 
561
- function listProcessor(base, tableName, { external = false } = {}) {
561
+ function filterProcessor(base, tableName, { external = false } = {}) {
562
562
  const n = names(base);
563
- const cls = external ? n.externalListProcessorClass : n.listProcessorClass;
563
+ const cls = external ? n.externalFilterProcessorClass : n.filterProcessorClass;
564
564
  return `import {
565
565
  CommonListFilterConfig,
566
566
  CommonListFilterDto,
567
- CommonListProcessor,
567
+ BaseFilterProcessor,
568
568
  FilterValueTypeEnum,
569
569
  ListFilterService,
570
570
  SortDirection,
@@ -589,7 +589,7 @@ function listProcessor(base, tableName, { external = false } = {}) {
589
589
  * \`columns\`. Standing literal clauses go in \`predicates\`; anything
590
590
  * carrying a value goes in the method, where add() binds it.
591
591
  */
592
- export class ${cls} extends CommonListProcessor {
592
+ export class ${cls} extends BaseFilterProcessor {
593
593
  protected config: CommonListFilterConfig = {
594
594
  query: '${tableName} a',
595
595
  columns: [
@@ -639,14 +639,14 @@ ${
639
639
 
640
640
  function subscriber(base) {
641
641
  const n = names(base);
642
- return `import { CommonSubscriber } from '${pkg()}';
642
+ return `import { BaseEntitySubscriber } from '${pkg()}';
643
643
  import { EventSubscriber } from 'typeorm';
644
644
  import { ${n.entityClass} } from '../entities/${n.dot}.entity';
645
645
  import { DataSource } from 'typeorm';
646
646
  import { ${n.jobClass} } from '../jobs/${n.dot}.job';
647
647
 
648
648
  @EventSubscriber()
649
- export class ${n.subscriberClass} extends CommonSubscriber<${n.entityClass}> {
649
+ export class ${n.subscriberClass} extends BaseEntitySubscriber<${n.entityClass}> {
650
650
  constructor(
651
651
  protected readonly datasource: DataSource,
652
652
  protected readonly entityJob: ${n.jobClass},
@@ -667,13 +667,13 @@ export class ${n.subscriberClass} extends CommonSubscriber<${n.entityClass}> {
667
667
 
668
668
  function job(base) {
669
669
  const n = names(base);
670
- return `import { CommonJob, QueueService, DatabaseEventDto } from '${pkg()}';
670
+ return `import { BaseEntityJob, QueueService, DatabaseEventDto } from '${pkg()}';
671
671
  import { Injectable } from '@nestjs/common';
672
672
  import { JobConstants } from '../../constants/job.constants';
673
673
  import { ${n.entityClass} } from '../entities/${n.dot}.entity';
674
674
 
675
675
  @Injectable()
676
- export class ${n.jobClass} extends CommonJob {
676
+ export class ${n.jobClass} extends BaseEntityJob {
677
677
  constructor(protected readonly queueService: QueueService) {
678
678
  super(JobConstants.${n.camel}Job);
679
679
  }
@@ -693,9 +693,9 @@ export class ${n.jobClass} extends CommonJob {
693
693
  function genMigration(base, tableName, timestamp) {
694
694
  const n = names(base);
695
695
  const className = migrationClassName(n.migrationName, timestamp);
696
- return `import { MigrationUtility } from '${pkg()}';
696
+ return `import { MigrationHelper } from '${pkg()}';
697
697
 
698
- export class ${className} extends MigrationUtility {
698
+ export class ${className} extends MigrationHelper {
699
699
  constructor() {
700
700
  super('${tableName}');
701
701
  this.process();
@@ -726,9 +726,9 @@ ${current().tenantScoped ? ` this.index('tenant_id');\n` : ''} this.index(
726
726
  /** Standalone migration (`nh migration`). */
727
727
  function migration(migrationName, tableName, timestamp) {
728
728
  const className = migrationClassName(migrationName, timestamp);
729
- return `import { MigrationUtility } from '${pkg()}';
729
+ return `import { MigrationHelper } from '${pkg()}';
730
730
 
731
- export class ${className} extends MigrationUtility {
731
+ export class ${className} extends MigrationHelper {
732
732
  constructor() {
733
733
  super('${tableName}');
734
734
  this.process();
@@ -841,9 +841,9 @@ ${members}
841
841
  `;
842
842
  }
843
843
 
844
- /** A freshly scaffolded module before any es6.classes content exists. */
845
- function emptyEs6Classes() {
846
- return `export const es6Classes = {
844
+ /** A freshly scaffolded module before any module.registry content exists. */
845
+ function emptyModuleRegistry() {
846
+ return `export const moduleRegistry = {
847
847
  controllers: [],
848
848
  services: [],
849
849
  libraries: [],
@@ -863,16 +863,16 @@ import {
863
863
  AuthModule,
864
864
  SystemPropertyModule,
865
865
  } from '${pkg()}';
866
- import { es6Classes } from './es6.classes';
866
+ import { moduleRegistry } from './module.registry';
867
867
 
868
868
  @Module({
869
869
  imports: [CommonModule, QueueModule, AuthModule, SystemPropertyModule],
870
- controllers: [...es6Classes.controllers],
870
+ controllers: [...moduleRegistry.controllers],
871
871
  providers: [
872
- ...es6Classes.services,
873
- ...es6Classes.libraries,
874
- ...es6Classes.jobs,
875
- ...es6Classes.subscribers,
872
+ ...moduleRegistry.services,
873
+ ...moduleRegistry.libraries,
874
+ ...moduleRegistry.jobs,
875
+ ...moduleRegistry.subscribers,
876
876
  ],
877
877
  })
878
878
  export class ${pascal}Module {}
@@ -893,7 +893,7 @@ module.exports = {
893
893
  additionalJob,
894
894
  dto,
895
895
  processor,
896
- listProcessor,
896
+ filterProcessor,
897
897
  subscriber,
898
898
  job,
899
899
  genMigration,
@@ -903,6 +903,6 @@ module.exports = {
903
903
  entityConstantsFile,
904
904
  jobMapsFile,
905
905
  entityMapsFile,
906
- emptyEs6Classes,
906
+ emptyModuleRegistry,
907
907
  moduleFile,
908
908
  };