Skip to content

Commit 50f6fbf

Browse files
authored
feat: chunked processing (streaming) (#509)
1 parent 26d5760 commit 50f6fbf

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+2218
-1040
lines changed

.github/workflows/generate.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ jobs:
5959
sparse-checkout: |
6060
doc/api
6161
lib
62+
.
6263
path: node
6364

6465
- name: Setup Node.js
@@ -79,7 +80,9 @@ jobs:
7980
-t ${{ matrix.target }} \
8081
-i "${{ matrix.input }}" \
8182
-o "out/${{ matrix.target }}" \
82-
--index ./node/doc/api/index.md
83+
-c ./node/CHANGELOG.md \
84+
--index ./node/doc/api/index.md \
85+
--log-level debug
8386
8487
- name: Upload ${{ matrix.target }} artifacts
8588
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0

bin/cli.mjs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,19 @@ import process from 'node:process';
55
import { Command, Option } from 'commander';
66

77
import commands from './commands/index.mjs';
8-
import interactive from './commands/interactive.mjs';
98
import { errorWrap } from './utils.mjs';
9+
import { LogLevel } from '../src/logger/constants.mjs';
10+
import logger from '../src/logger/index.mjs';
11+
12+
const logLevelOption = new Option('--log-level <level>', 'Log level')
13+
.choices(Object.keys(LogLevel))
14+
.default('info');
1015

1116
const program = new Command()
1217
.name('@nodejs/doc-kit')
13-
.description('CLI tool to generate the Node.js API documentation');
18+
.description('CLI tool to generate the Node.js API documentation')
19+
.addOption(logLevelOption)
20+
.hook('preAction', cmd => logger.setLogLevel(cmd.opts().logLevel));
1421

1522
// Registering commands
1623
commands.forEach(({ name, description, options, action }) => {
@@ -37,11 +44,5 @@ commands.forEach(({ name, description, options, action }) => {
3744
cmd.action(errorWrap(action));
3845
});
3946

40-
// Register the interactive command
41-
program
42-
.command('interactive')
43-
.description('Launch guided CLI wizard')
44-
.action(errorWrap(interactive));
45-
4647
// Parse and execute command-line arguments
4748
program.parse(process.argv);

bin/commands/generate.mjs

Lines changed: 29 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -3,38 +3,18 @@ import { resolve } from 'node:path';
33

44
import { coerce } from 'semver';
55

6-
import {
7-
DOC_NODE_CHANGELOG_URL,
8-
DOC_NODE_VERSION,
9-
} from '../../src/constants.mjs';
6+
import { NODE_CHANGELOG_URL, NODE_VERSION } from '../../src/constants.mjs';
107
import { publicGenerators } from '../../src/generators/index.mjs';
118
import createGenerator from '../../src/generators.mjs';
9+
import logger from '../../src/logger/index.mjs';
10+
import { parseTypeMap } from '../../src/parsers/json.mjs';
1211
import { parseChangelog, parseIndex } from '../../src/parsers/markdown.mjs';
1312
import { DEFAULT_TYPE_MAP } from '../../src/utils/parser/constants.mjs';
14-
import { loadFromURL } from '../../src/utils/parser.mjs';
15-
import { loadAndParse } from '../utils.mjs';
1613

1714
const availableGenerators = Object.keys(publicGenerators);
1815

19-
// Half of available logical CPUs guarantees in general all physical CPUs are being used
20-
// which in most scenarios is the best way to maximize performance
21-
const optimalThreads = Math.floor(cpus().length / 2) + 1;
22-
23-
/**
24-
* @typedef {Object} Options
25-
* @property {Array<string>|string} input - Specifies the glob/path for input files.
26-
* @property {Array<string>|string} [ignore] - Specifies the glob/path for ignoring files.
27-
* @property {Array<keyof publicGenerators>} target - Specifies the generator target mode.
28-
* @property {string} version - Specifies the target Node.js version.
29-
* @property {string} changelog - Specifies the path to the Node.js CHANGELOG.md file.
30-
* @property {string} typeMap - Specifies the path to the Node.js Type Map.
31-
* @property {string} [gitRef] - Git ref/commit URL.
32-
* @property {number} [threads] - Number of threads to allow.
33-
* @property {number} [chunkSize] - Number of items to process per worker thread.
34-
*/
35-
3616
/**
37-
* @type {import('../utils.mjs').Command}
17+
* @type {import('./types').Command}
3818
*/
3919
export default {
4020
description: 'Generate API docs',
@@ -66,11 +46,11 @@ export default {
6646
},
6747
threads: {
6848
flags: ['-p', '--threads <number>'],
69-
desc: 'Number of worker threads to use',
49+
desc: 'Number of threads to use (minimum: 1)',
7050
prompt: {
7151
type: 'text',
7252
message: 'How many threads to allow',
73-
initialValue: String(Math.max(optimalThreads, 1)),
53+
initialValue: String(cpus().length),
7454
},
7555
},
7656
chunkSize: {
@@ -88,7 +68,7 @@ export default {
8868
prompt: {
8969
type: 'text',
9070
message: 'Enter Node.js version',
91-
initialValue: DOC_NODE_VERSION,
71+
initialValue: NODE_VERSION,
9272
},
9373
},
9474
changelog: {
@@ -97,7 +77,7 @@ export default {
9777
prompt: {
9878
type: 'text',
9979
message: 'Enter changelog URL',
100-
initialValue: DOC_NODE_CHANGELOG_URL,
80+
initialValue: NODE_CHANGELOG_URL,
10181
},
10282
},
10383
gitRef: {
@@ -140,33 +120,42 @@ export default {
140120
},
141121
},
142122
},
123+
143124
/**
125+
* @typedef {Object} Options
126+
* @property {Array<string>|string} input - Specifies the glob/path for input files.
127+
* @property {Array<string>|string} [ignore] - Specifies the glob/path for ignoring files.
128+
* @property {Array<keyof AvailableGenerators>} target - Specifies the generator target mode.
129+
* @property {string} version - Specifies the target Node.js version.
130+
* @property {string} changelog - Specifies the path to the Node.js CHANGELOG.md file.
131+
* @property {string} typeMap - Specifies the path to the Node.js Type Map.
132+
* @property {string} index - Specifies the path to the index document.
133+
* @property {string} [gitRef] - Git ref/commit URL.
134+
* @property {number} [threads] - Number of threads to allow.
135+
* @property {number} [chunkSize] - Number of items to process per worker thread.
136+
*
144137
* Handles the action for generating API docs
145138
* @param {Options} opts - The options to generate API docs.
146139
* @returns {Promise<void>}
147140
*/
148141
async action(opts) {
149-
const docs = await loadAndParse(opts.input, opts.ignore);
150-
const releases = await parseChangelog(opts.changelog);
151-
152-
const rawTypeMap = await loadFromURL(opts.typeMap);
153-
const typeMap = JSON.parse(rawTypeMap);
142+
logger.debug('Starting doc-kit', opts);
154143

155-
const index = opts.index && (await parseIndex(opts.index));
144+
const { runGenerators } = createGenerator();
156145

157-
const { runGenerators } = createGenerator(docs);
146+
logger.debug('Starting generation', { targets: opts.target });
158147

159148
await runGenerators({
160149
generators: opts.target,
161150
input: opts.input,
162151
output: opts.output && resolve(opts.output),
163152
version: coerce(opts.version),
164-
releases,
153+
releases: await parseChangelog(opts.changelog),
165154
gitRef: opts.gitRef,
166-
threads: parseInt(opts.threads, 10),
167-
chunkSize: parseInt(opts.chunkSize, 10),
168-
index,
169-
typeMap,
155+
threads: Math.max(parseInt(opts.threads, 10), 1),
156+
chunkSize: Math.max(parseInt(opts.chunkSize, 10), 1),
157+
index: await parseIndex(opts.index),
158+
typeMap: await parseTypeMap(opts.typeMap),
170159
});
171160
},
172161
};

bin/commands/index.mjs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
import generate from './generate.mjs';
2+
import interactive from './interactive.mjs';
23

3-
export default [generate];
4+
export default [generate, interactive];

0 commit comments

Comments
 (0)