Skip to content

Commit c8553db

Browse files
committed
refactor(core): load generators by import specifier
1 parent 70b7526 commit c8553db

52 files changed

Lines changed: 689 additions & 459 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
'@node-core/doc-kit': minor
3+
---
4+
5+
Generators are now loaded dynamically by import specifier instead of a static
6+
registry. `--target` accepts either a built-in shorthand name (`web`,
7+
`legacy-html`, …) or any import specifier resolving to a generator module
8+
(e.g. `some-package/generator` or `./my-generator.mjs`), and a generator's
9+
`dependsOn` is now a full import specifier. This lays the groundwork for
10+
splitting the built-in generators into separate packages and enables
11+
third-party generator packages.

docs/configuration.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@ uses the `doc-kit` property:
3636

3737
```javascript
3838
export default {
39-
// targets, alternatively supplied by command line flags
39+
// Targets, alternatively supplied by command line flags. Each entry is
40+
// either a built-in shorthand name or an import specifier resolving to a
41+
// generator module (e.g. '@my-scope/my-package/my-generator').
4042
target: ['orama-db', 'web'],
4143
global: {
4244
version: '20.0.0',

docs/generators.md

Lines changed: 67 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -69,24 +69,26 @@ export type Generator = GeneratorMetadata<
6969

7070
### Step 3: Define Generator Metadata
7171

72-
Create the generator metadata in `index.mjs` using `createLazyGenerator`:
72+
A generator module's default export is a plain object with its metadata and
73+
implementation. Create it in `index.mjs`:
7374

7475
```javascript
7576
// packages/core/src/generators/my-format/index.mjs
76-
import { createLazyGenerator } from '../../utils/generators.mjs';
77+
import { generate } from './generate.mjs';
7778

7879
/**
7980
* Generates output in MyFormat.
8081
*
8182
* @type {import('./types').Generator}
8283
*/
83-
export default createLazyGenerator({
84+
export default {
8485
name: 'my-format',
8586

8687
description: 'Generates documentation in MyFormat',
8788

88-
// This generator depends on the metadata generator
89-
dependsOn: 'metadata',
89+
// This generator depends on the metadata generator. Dependencies are
90+
// declared as import specifiers, so they can live in any package.
91+
dependsOn: '@node-core/doc-kit/metadata',
9092

9193
defaultConfiguration: {
9294
// If your generator supports a custom configuration, define the defaults here
@@ -96,7 +98,9 @@ export default createLazyGenerator({
9698
// To override the defaults, they can be specified here
9799
ref: 'overriddenRef',
98100
},
99-
});
101+
102+
generate,
103+
};
100104
```
101105

102106
### Step 4: Implement the Generator Logic
@@ -147,28 +151,34 @@ function transformToMyFormat(entries, version) {
147151
}
148152
```
149153

150-
### Step 5: Register the Generator
154+
### Step 5: Make the Generator Loadable
151155

152-
Add your generator to the exports in `packages/core/src/generators/index.mjs`:
156+
Generators are loaded dynamically by import specifier. Anything that resolves
157+
to a module whose default export is a generator works as a `--target`:
153158

154-
```javascript
155-
// For public generators (available via CLI)
156-
import myFormat from './my-format/index.mjs';
159+
```bash
160+
# A package (subpath) export
161+
doc-kit generate -t @my-scope/my-package/my-format ...
162+
163+
# A local file
164+
doc-kit generate -t ./generators/my-format/index.mjs ...
165+
```
166+
167+
Built-in generators additionally get a shorthand alias in
168+
`packages/core/src/generators/index.mjs`, which maps the name users type to
169+
the import specifier it resolves to:
157170

171+
```javascript
158172
export const publicGenerators = {
159-
'json-simple': jsonSimple,
160-
'my-format': myFormat, // Add this
173+
'json-simple': '@node-core/doc-kit/json-simple',
174+
'my-format': '@node-core/doc-kit/my-format', // Add this
161175
// ... other generators
162176
};
163-
164-
// For internal generators (used only as dependencies)
165-
const internalGenerators = {
166-
ast,
167-
metadata,
168-
// ... internal generators
169-
};
170177
```
171178

179+
If the generator lives in this repository, also add a matching subpath to the
180+
`exports` map of its package's `package.json`.
181+
172182
## Parallel Processing with Workers
173183

174184
For generators processing large datasets, implement parallel processing using worker threads.
@@ -179,21 +189,24 @@ First, define the generator metadata in `index.mjs`:
179189

180190
```javascript
181191
// packages/core/src/generators/parallel-generator/index.mjs
182-
import { createLazyGenerator } from '../../utils/generators.mjs';
192+
import { generate, processChunk } from './generate.mjs';
183193

184194
/**
185195
* @type {import('./types').Generator}
186196
*/
187-
export default createLazyGenerator({
197+
export default {
188198
name: 'parallel-generator',
189199

190200
description: 'Processes data in parallel',
191201

192-
dependsOn: 'metadata',
202+
dependsOn: '@node-core/doc-kit/metadata',
193203

194204
// Indicates this generator has a processChunk implementation
195205
hasParallelProcessor: true,
196-
});
206+
207+
generate,
208+
processChunk,
209+
};
197210
```
198211

199212
Then, implement both `processChunk` and `generate` in `generate.mjs`:
@@ -273,20 +286,23 @@ Define the generator metadata in `index.mjs`:
273286

274287
```javascript
275288
// packages/core/src/generators/streaming-generator/index.mjs
276-
import { createLazyGenerator } from '../../utils/generators.mjs';
289+
import { generate, processChunk } from './generate.mjs';
277290

278291
/**
279292
* @type {import('./types').Generator}
280293
*/
281-
export default createLazyGenerator({
294+
export default {
282295
name: 'streaming-generator',
283296

284297
description: 'Streams results as they are ready',
285298

286-
dependsOn: 'metadata',
299+
dependsOn: '@node-core/doc-kit/metadata',
287300

288301
hasParallelProcessor: true,
289-
});
302+
303+
generate,
304+
processChunk,
305+
};
290306
```
291307

292308
Implement the generator in `generate.mjs`:
@@ -331,18 +347,20 @@ Generator metadata in `index.mjs`:
331347

332348
```javascript
333349
// packages/core/src/generators/batch-generator/index.mjs
334-
import { createLazyGenerator } from '../../utils/generators.mjs';
350+
import { generate } from './generate.mjs';
335351

336352
/**
337353
* @type {import('./types').Generator}
338354
*/
339-
export default createLazyGenerator({
355+
export default {
340356
name: 'batch-generator',
341357

342358
description: 'Requires all input at once',
343359

344-
dependsOn: 'jsx-ast',
345-
});
360+
dependsOn: '@node-core/doc-kit/jsx-ast',
361+
362+
generate,
363+
};
346364
```
347365

348366
Implementation in `generate.mjs`:
@@ -378,15 +396,19 @@ Use non-streaming when:
378396
In `index.mjs`:
379397

380398
```javascript
381-
import { createLazyGenerator } from '../../utils/generators.mjs';
399+
import { generate } from './generate.mjs';
382400

383-
export default createLazyGenerator({
401+
export default {
384402
name: 'my-generator',
385403

386-
dependsOn: 'metadata', // This generator requires metadata output
404+
// This generator requires the metadata generator's output. The dependency
405+
// is an import specifier, so it may point at any installed package.
406+
dependsOn: '@node-core/doc-kit/metadata',
387407

388408
// ... other metadata
389-
});
409+
410+
generate,
411+
};
390412
```
391413

392414
In `generate.mjs`:
@@ -402,27 +424,27 @@ export async function generate(input, worker) {
402424
```javascript
403425
// Step 1: Parse markdown to AST
404426
// packages/core/src/generators/ast/index.mjs
405-
export default createLazyGenerator({
427+
export default {
406428
name: 'ast',
407-
dependsOn: undefined, // No dependency
429+
dependsOn: undefined, // No dependency
408430
// Processes raw markdown files
409-
});
431+
};
410432

411433
// Step 2: Extract metadata from AST
412434
// packages/core/src/generators/metadata/index.mjs
413-
export default createLazyGenerator({
435+
export default {
414436
name: 'metadata',
415-
dependsOn: 'ast', // Depends on AST
437+
dependsOn: '@node-core/doc-kit/ast', // Depends on AST
416438
// Processes AST output
417-
});
439+
};
418440

419441
// Step 3: Generate HTML from metadata
420442
// packages/core/src/generators/html-generator/index.mjs
421-
export default createLazyGenerator({
443+
export default {
422444
name: 'html-generator',
423-
dependsOn: 'metadata', // Depends on metadata
445+
dependsOn: '@node-core/doc-kit/metadata', // Depends on metadata
424446
// Processes metadata output
425-
});
447+
};
426448
```
427449

428450
### Multiple Consumers

packages/core/bin/commands/generate.mjs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,11 @@ export default new Command('generate')
3636
new Option('-i, --input <patterns...>', 'Input file patterns (glob)')
3737
)
3838
.addOption(
39-
new Option('-t, --target <generator...>', 'Target generator(s)').choices(
40-
Object.keys(publicGenerators)
39+
new Option(
40+
'-t, --target <generator...>',
41+
'Target generator(s): a built-in name ' +
42+
`(${Object.keys(publicGenerators).join(', ')}) ` +
43+
'or an import specifier for a custom generator'
4144
)
4245
)
4346
.addOption(

packages/core/package.json

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,29 @@
1616
"watch": "node --watch bin/cli.mjs"
1717
},
1818
"main": "./src/generators.mjs",
19+
"exports": {
20+
".": "./src/generators.mjs",
21+
"./addon-verify": "./src/generators/addon-verify/index.mjs",
22+
"./api-links": "./src/generators/api-links/index.mjs",
23+
"./ast": "./src/generators/ast/index.mjs",
24+
"./ast-js": "./src/generators/ast-js/index.mjs",
25+
"./json-simple": "./src/generators/json-simple/index.mjs",
26+
"./jsx-ast": "./src/generators/jsx-ast/index.mjs",
27+
"./legacy-html": "./src/generators/legacy-html/index.mjs",
28+
"./legacy-html-all": "./src/generators/legacy-html-all/index.mjs",
29+
"./legacy-json": "./src/generators/legacy-json/index.mjs",
30+
"./legacy-json-all": "./src/generators/legacy-json-all/index.mjs",
31+
"./llms-txt": "./src/generators/llms-txt/index.mjs",
32+
"./man-page": "./src/generators/man-page/index.mjs",
33+
"./metadata": "./src/generators/metadata/index.mjs",
34+
"./orama-db": "./src/generators/orama-db/index.mjs",
35+
"./sitemap": "./src/generators/sitemap/index.mjs",
36+
"./web": "./src/generators/web/index.mjs",
37+
"./package.json": "./package.json",
38+
"./shiki.config.mjs": "./shiki.config.mjs",
39+
"./src/*": "./src/*",
40+
"./*": "./src/*"
41+
},
1942
"bin": {
2043
"doc-kit": "./bin/cli.mjs"
2144
},

0 commit comments

Comments
 (0)