Skip to content

Commit 57a244e

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

File tree

8 files changed

+114
-85
lines changed

8 files changed

+114
-85
lines changed

bin/commands/generate.mjs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ const { runGenerators } = createGenerator();
2121
* @property {string} index
2222
* @property {boolean} minify
2323
* @property {string} typeMap
24+
* @property {boolean} progress
2425
*/
2526

2627
export default new Command('generate')
@@ -58,6 +59,7 @@ export default new Command('generate')
5859
.addOption(new Option('--index <url>', 'index.md URL or path'))
5960
.addOption(new Option('--minify', 'Minify?'))
6061
.addOption(new Option('--type-map <url>', 'Type map URL or path'))
62+
.addOption(new Option('--no-progress', 'Disable the progress bar'))
6163

6264
.action(
6365
errorWrap(async opts => {

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: 13 additions & 6 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,7 +93,7 @@ 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
9697
* @returns {Promise<unknown[]>} Results of all requested generators
9798
*/
9899
const runGenerators = async configuration => {
@@ -111,6 +112,9 @@ const createGenerator = () => {
111112
await scheduleGenerator(name, configuration);
112113
}
113114

115+
const progress = createProgressBar({ enabled: configuration.progress });
116+
progress?.start(generators.length, 0, { phase: 'Starting...' });
117+
114118
// Start all collections in parallel (don't await sequentially)
115119
const resultPromises = generators.map(async name => {
116120
let result = await cachedGenerators[name];
@@ -119,14 +123,17 @@ const createGenerator = () => {
119123
result = await streamingCache.getOrCollect(name, result);
120124
}
121125

126+
progress?.increment({ phase: name });
122127
return result;
123128
});
124129

125-
const results = await Promise.all(resultPromises);
126-
127-
await pool.destroy();
128-
129-
return results;
130+
try {
131+
const results = await Promise.all(resultPromises);
132+
return results;
133+
} finally {
134+
await pool.destroy();
135+
progress?.stop();
136+
}
130137
};
131138

132139
return { runGenerators };

src/utils/configuration/__tests__/index.test.mjs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ describe('config.mjs', () => {
9393
target: 'json',
9494
threads: 4,
9595
chunkSize: 5,
96+
progress: true,
9697
};
9798

9899
const config = createConfigFromCLIOptions(options);
@@ -112,6 +113,7 @@ describe('config.mjs', () => {
112113
target: 'json',
113114
threads: 4,
114115
chunkSize: 5,
116+
progress: true,
115117
});
116118
});
117119

src/utils/configuration/index.mjs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export const getDefaultConfig = lazy(() =>
3535

3636
threads: cpus().length,
3737
chunkSize: 10,
38+
progress: true,
3839
})
3940
)
4041
);
@@ -96,6 +97,7 @@ export const createConfigFromCLIOptions = options => ({
9697
target: options.target,
9798
threads: options.threads,
9899
chunkSize: options.chunkSize,
100+
progress: options.progress,
99101
});
100102

101103
/**

src/utils/configuration/types.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export type Configuration = {
1515

1616
// Number of items to process per worker thread
1717
chunkSize: number;
18+
progress: boolean;
1819
} & {
1920
[K in keyof AllGenerators]: GlobalConfiguration &
2021
AllGenerators[K]['defaultConfiguration'];

src/utils/progressBar.mjs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
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 {SingleBar | null}
13+
*/
14+
const createProgressBar = ({ enabled = true } = {}) => {
15+
if (!enabled || !process.stderr.isTTY) {
16+
return null;
17+
}
18+
19+
return new SingleBar(
20+
{
21+
stream: process.stderr,
22+
format: ' {phase} [{bar}] {percentage}% | {value}/{total}',
23+
hideCursor: true,
24+
clearOnComplete: false,
25+
},
26+
Presets.shades_grey
27+
);
28+
};
29+
30+
export default createProgressBar;

0 commit comments

Comments
 (0)