Skip to content

Commit ca20ac3

Browse files
committed
feat(cli): add progress bar to generation pipeline
1 parent 38c58bc commit ca20ac3

File tree

5 files changed

+121
-82
lines changed

5 files changed

+121
-82
lines changed

bin/commands/generate.mjs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,11 @@ export default new Command('generate')
5858
.addOption(new Option('--index <url>', 'index.md URL or path'))
5959
.addOption(new Option('--minify', 'Minify?'))
6060
.addOption(new Option('--type-map <url>', 'Type map URL or path'))
61+
.addOption(new Option('--no-progress', 'Disable the progress bar'))
6162

6263
.action(
6364
errorWrap(async opts => {
6465
const config = await setConfig(opts);
65-
await runGenerators(config);
66+
await runGenerators(config, opts.progress);
6667
})
6768
);

package-lock.json

Lines changed: 63 additions & 79 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
"@rollup/plugin-virtual": "^3.0.2",
5353
"@swc/html-wasm": "^1.15.18",
5454
"acorn": "^8.16.0",
55+
"cli-progress": "^3.12.0",
5556
"commander": "^14.0.3",
5657
"dedent": "^1.7.1",
5758
"estree-util-to-js": "^2.0.0",

src/generators.mjs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import logger from './logger/index.mjs';
55
import { isAsyncGenerator, createStreamingCache } from './streaming.mjs';
66
import createWorkerPool from './threading/index.mjs';
77
import createParallelWorker from './threading/parallel.mjs';
8+
import createProgressBar from './utils/progressBar.mjs';
89

910
const generatorsLogger = logger.child('generators');
1011

@@ -92,10 +93,11 @@ const createGenerator = () => {
9293
/**
9394
* Runs all requested generators with their dependencies.
9495
*
95-
* @param {import('./utils/configuration/types').Configuration} options - Runtime options
96+
* @param {import('./utils/configuration/types').Configuration} configuration - Runtime options
97+
* @param {boolean} [showProgress=true] - Whether to render the progress bar
9698
* @returns {Promise<unknown[]>} Results of all requested generators
9799
*/
98-
const runGenerators = async configuration => {
100+
const runGenerators = async (configuration, showProgress = true) => {
99101
const { target: generators, threads } = configuration;
100102

101103
generatorsLogger.debug(`Starting pipeline`, {
@@ -111,6 +113,9 @@ const createGenerator = () => {
111113
await scheduleGenerator(name, configuration);
112114
}
113115

116+
const progress = createProgressBar({ enabled: showProgress });
117+
progress.start(generators.length);
118+
114119
// Start all collections in parallel (don't await sequentially)
115120
const resultPromises = generators.map(async name => {
116121
let result = await cachedGenerators[name];
@@ -119,12 +124,14 @@ const createGenerator = () => {
119124
result = await streamingCache.getOrCollect(name, result);
120125
}
121126

127+
progress.increment(name);
122128
return result;
123129
});
124130

125131
const results = await Promise.all(resultPromises);
126132

127133
await pool.destroy();
134+
progress.stop();
128135

129136
return results;
130137
};

src/utils/progressBar.mjs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
'use strict';
2+
3+
import { SingleBar, Presets } from 'cli-progress';
4+
5+
/**
6+
* Creates a progress bar for the generation pipeline.
7+
* Writes to stderr to avoid conflicts with the logger (stdout).
8+
* Returns a no-op object if disabled or if stderr is not a TTY (e.g. CI).
9+
*
10+
* @param {object} [options]
11+
* @param {boolean} [options.enabled=true] Whether to render the progress bar
12+
* @returns {{ start: (total: number) => void, increment: (phase: string) => void, stop: () => void }}
13+
*/
14+
const createProgressBar = ({ enabled = true } = {}) => {
15+
if (!enabled || !process.stderr.isTTY) {
16+
return {
17+
/** @returns {void} */
18+
start: () => {},
19+
/** @returns {void} */
20+
increment: () => {},
21+
/** @returns {void} */
22+
stop: () => {},
23+
};
24+
}
25+
26+
const bar = new SingleBar(
27+
{
28+
stream: process.stderr,
29+
format: ' {phase} [{bar}] {percentage}% | {value}/{total}',
30+
hideCursor: true,
31+
clearOnComplete: false,
32+
},
33+
Presets.shades_grey
34+
);
35+
36+
return {
37+
/** @param {number} total */
38+
start: total => bar.start(total, 0, { phase: 'Starting...' }),
39+
/** @param {string} phase */
40+
increment: phase => bar.increment({ phase }),
41+
/** @returns {void} */
42+
stop: () => bar.stop(),
43+
};
44+
};
45+
46+
export default createProgressBar;

0 commit comments

Comments
 (0)