Skip to content

Commit 2f715f0

Browse files
authored
feat(fmt): display millisecond durations (#439)
1 parent 2e80114 commit 2f715f0

4 files changed

Lines changed: 69 additions & 40 deletions

File tree

packages/rstack/src/fmt/cli.ts

Lines changed: 12 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { ensureProjectCacheDir } from '../projectCache.ts';
88
import { fmtCacheFileName } from './cacheStore.ts';
99
import { resolveFmtConfig } from './config.ts';
1010
import { discoverFmtFiles } from './discovery.ts';
11+
import { formatDuration } from './duration.ts';
1112
import { createRelativePathResolver, toPosixPath } from './pathHelpers.ts';
1213
import { runFmtFiles } from './runner.ts';
1314
import type { FmtMode, FmtRunResult, ResolvedFmtConfig } from './types.ts';
@@ -157,35 +158,6 @@ const createDisplayPathResolver = (
157158
return (filePath) => toPosixPath(resolveRelativePath(filePath));
158159
};
159160

160-
const prettyTime = (seconds: number): string => {
161-
const format = (time: string, unit: 'm' | 's') =>
162-
color.bold(`${time}${unit}`);
163-
164-
if (seconds < 10) {
165-
const digits = seconds >= 0.01 ? 2 : 3;
166-
return format(seconds.toFixed(digits), 's');
167-
}
168-
169-
if (seconds < 60) {
170-
return format(seconds.toFixed(1), 's');
171-
}
172-
173-
const minutes = Math.floor(seconds / 60);
174-
const minutesLabel = format(minutes.toFixed(0), 'm');
175-
const remainingSeconds = seconds % 60;
176-
177-
if (remainingSeconds === 0) {
178-
return minutesLabel;
179-
}
180-
181-
const secondsLabel = format(
182-
remainingSeconds.toFixed(remainingSeconds % 1 === 0 ? 0 : 1),
183-
's',
184-
);
185-
186-
return `${minutesLabel} ${secondsLabel}`;
187-
};
188-
189161
const formatCount = (count: number): string => color.bold(count);
190162
const formatFileCount = (count: number, isError = false): string => {
191163
const formattedCount = formatCount(count);
@@ -207,7 +179,7 @@ const logFmtResult = (
207179
mode: FmtMode,
208180
cwd: string,
209181
processedFileCount: number,
210-
durationSeconds: number,
182+
durationMilliseconds: number,
211183
fixCommand?: string,
212184
): void => {
213185
let writtenCount = 0;
@@ -229,13 +201,18 @@ const logFmtResult = (
229201
}
230202
}
231203

204+
if (mode === 'list-different') {
205+
return;
206+
}
207+
208+
const time = color.bold(formatDuration(durationMilliseconds));
209+
232210
if (mode === 'write') {
233211
if (writtenCount === 0 && result.exitCode !== 0) {
234212
return;
235213
}
236214

237215
const processedFiles = formatFileCount(processedFileCount);
238-
const time = prettyTime(durationSeconds);
239216
const message =
240217
writtenCount > 0
241218
? `Formatted ${formatCount(writtenCount)} of ${processedFiles} in ${time}.`
@@ -244,21 +221,17 @@ const logFmtResult = (
244221
return;
245222
}
246223

247-
if (mode !== 'check') {
248-
return;
249-
}
250-
251224
if (differentCount > 0) {
252225
const differentFiles = formatFileCount(differentCount, true);
253226
const processedFiles = formatFileCount(processedFileCount);
254227
const fixHint = fixCommand
255228
? `Run ${color.cyan(fixCommand)} to fix.`
256229
: `Rerun this command without ${color.cyan('--check')} to fix.`;
257230
logger.error(`Formatting issues found in ${differentFiles}. ${fixHint}`);
258-
logger.info(`Checked ${processedFiles} in ${prettyTime(durationSeconds)}.`);
231+
logger.info(`Checked ${processedFiles} in ${time}.`);
259232
} else if (result.exitCode === 0) {
260233
logger.success(
261-
`Checked ${formatFileCount(processedFileCount)} in ${prettyTime(durationSeconds)}. No issues found.`,
234+
`Checked ${formatFileCount(processedFileCount)} in ${time}. No issues found.`,
262235
);
263236
}
264237
};
@@ -415,13 +388,13 @@ const runFmtCLI = async (
415388
return;
416389
}
417390

418-
const durationSeconds = (performance.now() - startTime) / 1000;
391+
const durationMilliseconds = performance.now() - startTime;
419392
logFmtResult(
420393
result,
421394
mode,
422395
cwd,
423396
result.processedFileCount,
424-
durationSeconds,
397+
durationMilliseconds,
425398
fixCommand,
426399
);
427400
process.exitCode = result.exitCode;
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/** Formats sub-second durations in milliseconds and preserves the existing longer-duration format. */
2+
const formatDuration = (milliseconds: number): string => {
3+
if (milliseconds < 1) {
4+
return '<1ms';
5+
}
6+
7+
const roundedMilliseconds = Math.round(milliseconds);
8+
if (roundedMilliseconds < 1000) {
9+
return `${roundedMilliseconds}ms`;
10+
}
11+
12+
const seconds = milliseconds / 1000;
13+
if (seconds < 10) {
14+
return `${seconds.toFixed(2)}s`;
15+
}
16+
17+
if (seconds < 60) {
18+
return `${seconds.toFixed(1)}s`;
19+
}
20+
21+
const minutes = Math.floor(seconds / 60);
22+
const remainingSeconds = seconds % 60;
23+
24+
if (remainingSeconds === 0) {
25+
return `${minutes}m`;
26+
}
27+
28+
const secondsLabel = remainingSeconds.toFixed(
29+
remainingSeconds % 1 === 0 ? 0 : 1,
30+
);
31+
return `${minutes}m ${secondsLabel}s`;
32+
};
33+
34+
export { formatDuration };

packages/rstack/tests/cli/fmt/helpers.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,10 @@ export const createCliEnv = (): NodeJS.ProcessEnv => {
4242
};
4343

4444
export const normalizeDuration = (output: string): string =>
45-
output.replace(/\d+m(?: \d+(?:\.\d+)?s)?|\d+(?:\.\d+)?s/g, '<duration>');
45+
output.replace(
46+
/<1ms|\d+ms|\d+m(?: \d+(?:\.\d+)?s)?|\d+(?:\.\d+)?s/g,
47+
'<duration>',
48+
);
4649

4750
export const expectWriteSummary = (
4851
output: string,
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { expect, test } from 'rstack/test';
2+
import { formatDuration } from '../../src/fmt/duration.ts';
3+
4+
test.each([
5+
[0, '<1ms'],
6+
[0.999, '<1ms'],
7+
[1, '1ms'],
8+
[29.6, '30ms'],
9+
[999.4, '999ms'],
10+
[999.6, '1.00s'],
11+
[1_390, '1.39s'],
12+
[1_234, '1.23s'],
13+
[12_340, '12.3s'],
14+
[60_000, '1m'],
15+
[60_123, '1m 0.1s'],
16+
[3_661_234, '61m 1.2s'],
17+
] as const)('formats %sms as %s', (milliseconds, expected) => {
18+
expect(formatDuration(milliseconds)).toBe(expected);
19+
});

0 commit comments

Comments
 (0)