modestbench 0.9.0 → 0.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (224) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/cli/builder.cjs +259 -0
  3. package/dist/cli/builder.cjs.map +1 -0
  4. package/dist/cli/builder.d.cts +37 -0
  5. package/dist/cli/builder.d.cts.map +1 -0
  6. package/dist/cli/builder.d.ts +37 -0
  7. package/dist/cli/builder.d.ts.map +1 -0
  8. package/dist/cli/builder.js +255 -0
  9. package/dist/cli/builder.js.map +1 -0
  10. package/dist/cli/commands/baseline.cjs +4 -33
  11. package/dist/cli/commands/baseline.cjs.map +1 -1
  12. package/dist/cli/commands/baseline.d.cts.map +1 -1
  13. package/dist/cli/commands/baseline.d.ts.map +1 -1
  14. package/dist/cli/commands/baseline.js +2 -31
  15. package/dist/cli/commands/baseline.js.map +1 -1
  16. package/dist/cli/commands/history.cjs +2 -14
  17. package/dist/cli/commands/history.cjs.map +1 -1
  18. package/dist/cli/commands/history.d.cts.map +1 -1
  19. package/dist/cli/commands/history.d.ts.map +1 -1
  20. package/dist/cli/commands/history.js +1 -13
  21. package/dist/cli/commands/history.js.map +1 -1
  22. package/dist/cli/commands/init.cjs +2 -2
  23. package/dist/cli/commands/init.cjs.map +1 -1
  24. package/dist/cli/commands/init.js +2 -2
  25. package/dist/cli/commands/init.js.map +1 -1
  26. package/dist/cli/commands/run.cjs +3 -3
  27. package/dist/cli/commands/run.cjs.map +1 -1
  28. package/dist/cli/commands/run.d.cts +0 -13
  29. package/dist/cli/commands/run.d.cts.map +1 -1
  30. package/dist/cli/commands/run.d.ts +0 -13
  31. package/dist/cli/commands/run.d.ts.map +1 -1
  32. package/dist/cli/commands/run.js +1 -1
  33. package/dist/cli/commands/run.js.map +1 -1
  34. package/dist/cli/commands/test.cjs +1 -1
  35. package/dist/cli/commands/test.cjs.map +1 -1
  36. package/dist/cli/commands/test.js +1 -1
  37. package/dist/cli/commands/test.js.map +1 -1
  38. package/dist/cli/context.cjs +60 -0
  39. package/dist/cli/context.cjs.map +1 -0
  40. package/dist/cli/context.d.cts +28 -0
  41. package/dist/cli/context.d.cts.map +1 -0
  42. package/dist/cli/context.d.ts +28 -0
  43. package/dist/cli/context.d.ts.map +1 -0
  44. package/dist/cli/context.js +56 -0
  45. package/dist/cli/context.js.map +1 -0
  46. package/dist/cli/handlers.cjs +74 -0
  47. package/dist/cli/handlers.cjs.map +1 -0
  48. package/dist/cli/handlers.d.cts +13 -0
  49. package/dist/cli/handlers.d.cts.map +1 -0
  50. package/dist/cli/handlers.d.ts +13 -0
  51. package/dist/cli/handlers.d.ts.map +1 -0
  52. package/dist/cli/handlers.js +70 -0
  53. package/dist/cli/handlers.js.map +1 -0
  54. package/dist/cli/index.cjs +45 -978
  55. package/dist/cli/index.cjs.map +1 -1
  56. package/dist/cli/index.d.cts +6 -31
  57. package/dist/cli/index.d.cts.map +1 -1
  58. package/dist/cli/index.d.ts +6 -31
  59. package/dist/cli/index.d.ts.map +1 -1
  60. package/dist/cli/index.js +43 -974
  61. package/dist/cli/index.js.map +1 -1
  62. package/dist/cli/parsers/analyze.cjs +54 -0
  63. package/dist/cli/parsers/analyze.cjs.map +1 -0
  64. package/dist/cli/parsers/analyze.d.cts +37 -0
  65. package/dist/cli/parsers/analyze.d.cts.map +1 -0
  66. package/dist/cli/parsers/analyze.d.ts +37 -0
  67. package/dist/cli/parsers/analyze.d.ts.map +1 -0
  68. package/dist/cli/parsers/analyze.js +51 -0
  69. package/dist/cli/parsers/analyze.js.map +1 -0
  70. package/dist/cli/parsers/baseline.cjs +75 -0
  71. package/dist/cli/parsers/baseline.cjs.map +1 -0
  72. package/dist/cli/parsers/baseline.d.cts +59 -0
  73. package/dist/cli/parsers/baseline.d.cts.map +1 -0
  74. package/dist/cli/parsers/baseline.d.ts +59 -0
  75. package/dist/cli/parsers/baseline.d.ts.map +1 -0
  76. package/dist/cli/parsers/baseline.js +72 -0
  77. package/dist/cli/parsers/baseline.js.map +1 -0
  78. package/dist/cli/parsers/global.cjs +49 -0
  79. package/dist/cli/parsers/global.cjs.map +1 -0
  80. package/dist/cli/parsers/global.d.cts +45 -0
  81. package/dist/cli/parsers/global.d.cts.map +1 -0
  82. package/dist/cli/parsers/global.d.ts +45 -0
  83. package/dist/cli/parsers/global.d.ts.map +1 -0
  84. package/dist/cli/parsers/global.js +46 -0
  85. package/dist/cli/parsers/global.js.map +1 -0
  86. package/dist/cli/parsers/history.cjs +138 -0
  87. package/dist/cli/parsers/history.cjs.map +1 -0
  88. package/dist/cli/parsers/history.d.cts +108 -0
  89. package/dist/cli/parsers/history.d.cts.map +1 -0
  90. package/dist/cli/parsers/history.d.ts +108 -0
  91. package/dist/cli/parsers/history.d.ts.map +1 -0
  92. package/dist/cli/parsers/history.js +135 -0
  93. package/dist/cli/parsers/history.js.map +1 -0
  94. package/dist/cli/parsers/index.cjs +35 -0
  95. package/dist/cli/parsers/index.cjs.map +1 -0
  96. package/dist/cli/parsers/index.d.cts +15 -0
  97. package/dist/cli/parsers/index.d.cts.map +1 -0
  98. package/dist/cli/parsers/index.d.ts +15 -0
  99. package/dist/cli/parsers/index.d.ts.map +1 -0
  100. package/dist/cli/parsers/index.js +15 -0
  101. package/dist/cli/parsers/index.js.map +1 -0
  102. package/dist/cli/parsers/init.cjs +39 -0
  103. package/dist/cli/parsers/init.cjs.map +1 -0
  104. package/dist/cli/parsers/init.d.cts +32 -0
  105. package/dist/cli/parsers/init.d.cts.map +1 -0
  106. package/dist/cli/parsers/init.d.ts +32 -0
  107. package/dist/cli/parsers/init.d.ts.map +1 -0
  108. package/dist/cli/parsers/init.js +36 -0
  109. package/dist/cli/parsers/init.js.map +1 -0
  110. package/dist/cli/parsers/run.cjs +99 -0
  111. package/dist/cli/parsers/run.cjs.map +1 -0
  112. package/dist/cli/parsers/run.d.cts +62 -0
  113. package/dist/cli/parsers/run.d.cts.map +1 -0
  114. package/dist/cli/parsers/run.d.ts +62 -0
  115. package/dist/cli/parsers/run.d.ts.map +1 -0
  116. package/dist/cli/parsers/run.js +96 -0
  117. package/dist/cli/parsers/run.js.map +1 -0
  118. package/dist/cli/parsers/test.cjs +42 -0
  119. package/dist/cli/parsers/test.cjs.map +1 -0
  120. package/dist/cli/parsers/test.d.cts +31 -0
  121. package/dist/cli/parsers/test.d.cts.map +1 -0
  122. package/dist/cli/parsers/test.d.ts +31 -0
  123. package/dist/cli/parsers/test.d.ts.map +1 -0
  124. package/dist/cli/parsers/test.js +39 -0
  125. package/dist/cli/parsers/test.js.map +1 -0
  126. package/dist/cli/theme.cjs +35 -0
  127. package/dist/cli/theme.cjs.map +1 -0
  128. package/dist/cli/theme.d.cts +31 -0
  129. package/dist/cli/theme.d.cts.map +1 -0
  130. package/dist/cli/theme.d.ts +31 -0
  131. package/dist/cli/theme.d.ts.map +1 -0
  132. package/dist/cli/theme.js +32 -0
  133. package/dist/cli/theme.js.map +1 -0
  134. package/dist/config/budget-schema.cjs +1 -1
  135. package/dist/config/budget-schema.cjs.map +1 -1
  136. package/dist/config/budget-schema.js +1 -1
  137. package/dist/config/budget-schema.js.map +1 -1
  138. package/dist/core/engines/accurate-engine.cjs +1 -1
  139. package/dist/core/engines/accurate-engine.cjs.map +1 -1
  140. package/dist/core/engines/accurate-engine.d.cts.map +1 -1
  141. package/dist/core/engines/accurate-engine.d.ts.map +1 -1
  142. package/dist/core/engines/accurate-engine.js +1 -1
  143. package/dist/core/engines/accurate-engine.js.map +1 -1
  144. package/dist/errors/base.cjs +3 -12
  145. package/dist/errors/base.cjs.map +1 -1
  146. package/dist/errors/base.d.cts +0 -7
  147. package/dist/errors/base.d.cts.map +1 -1
  148. package/dist/errors/base.d.ts +0 -7
  149. package/dist/errors/base.d.ts.map +1 -1
  150. package/dist/errors/base.js +1 -9
  151. package/dist/errors/base.js.map +1 -1
  152. package/dist/formatters/history/compare.cjs +6 -6
  153. package/dist/formatters/history/compare.cjs.map +1 -1
  154. package/dist/formatters/history/compare.js +6 -6
  155. package/dist/formatters/history/compare.js.map +1 -1
  156. package/dist/formatters/history/show.cjs +2 -2
  157. package/dist/formatters/history/show.cjs.map +1 -1
  158. package/dist/formatters/history/show.js +2 -2
  159. package/dist/formatters/history/show.js.map +1 -1
  160. package/dist/formatters/history/trends.cjs +1 -1
  161. package/dist/formatters/history/trends.cjs.map +1 -1
  162. package/dist/formatters/history/trends.js +1 -1
  163. package/dist/formatters/history/trends.js.map +1 -1
  164. package/dist/reporters/human.cjs +3 -3
  165. package/dist/reporters/human.cjs.map +1 -1
  166. package/dist/reporters/human.d.cts.map +1 -1
  167. package/dist/reporters/human.d.ts.map +1 -1
  168. package/dist/reporters/human.js +3 -3
  169. package/dist/reporters/human.js.map +1 -1
  170. package/dist/reporters/nyan.cjs +1 -1
  171. package/dist/reporters/nyan.cjs.map +1 -1
  172. package/dist/reporters/nyan.js +1 -1
  173. package/dist/reporters/nyan.js.map +1 -1
  174. package/dist/services/budget-evaluator.cjs +2 -2
  175. package/dist/services/budget-evaluator.cjs.map +1 -1
  176. package/dist/services/budget-evaluator.js +2 -2
  177. package/dist/services/budget-evaluator.js.map +1 -1
  178. package/dist/services/config-manager.cjs +2 -2
  179. package/dist/services/config-manager.cjs.map +1 -1
  180. package/dist/services/config-manager.js +2 -2
  181. package/dist/services/config-manager.js.map +1 -1
  182. package/dist/services/profiler/profile-runner.cjs +11 -0
  183. package/dist/services/profiler/profile-runner.cjs.map +1 -1
  184. package/dist/services/profiler/profile-runner.d.cts +2 -0
  185. package/dist/services/profiler/profile-runner.d.cts.map +1 -1
  186. package/dist/services/profiler/profile-runner.d.ts +2 -0
  187. package/dist/services/profiler/profile-runner.d.ts.map +1 -1
  188. package/dist/services/profiler/profile-runner.js +11 -0
  189. package/dist/services/profiler/profile-runner.js.map +1 -1
  190. package/dist/services/reporter-registry.cjs +8 -8
  191. package/dist/services/reporter-registry.cjs.map +1 -1
  192. package/dist/services/reporter-registry.js +8 -8
  193. package/dist/services/reporter-registry.js.map +1 -1
  194. package/package.json +7 -9
  195. package/src/cli/builder.ts +387 -0
  196. package/src/cli/commands/baseline.ts +7 -33
  197. package/src/cli/commands/history.ts +1 -16
  198. package/src/cli/commands/init.ts +2 -2
  199. package/src/cli/commands/run.ts +1 -1
  200. package/src/cli/commands/test.ts +1 -1
  201. package/src/cli/context.ts +117 -0
  202. package/src/cli/handlers.ts +76 -0
  203. package/src/cli/index.ts +49 -1194
  204. package/src/cli/parsers/analyze.ts +61 -0
  205. package/src/cli/parsers/baseline.ts +92 -0
  206. package/src/cli/parsers/global.ts +51 -0
  207. package/src/cli/parsers/history.ts +168 -0
  208. package/src/cli/parsers/index.ts +28 -0
  209. package/src/cli/parsers/init.ts +45 -0
  210. package/src/cli/parsers/run.ts +118 -0
  211. package/src/cli/parsers/test.ts +46 -0
  212. package/src/cli/theme.ts +33 -0
  213. package/src/config/budget-schema.ts +1 -1
  214. package/src/core/engines/accurate-engine.ts +1 -1
  215. package/src/errors/base.ts +1 -10
  216. package/src/formatters/history/compare.ts +6 -6
  217. package/src/formatters/history/show.ts +2 -2
  218. package/src/formatters/history/trends.ts +1 -1
  219. package/src/reporters/human.ts +5 -3
  220. package/src/reporters/nyan.ts +1 -1
  221. package/src/services/budget-evaluator.ts +2 -2
  222. package/src/services/config-manager.ts +2 -2
  223. package/src/services/profiler/profile-runner.ts +15 -0
  224. package/src/services/reporter-registry.ts +8 -8
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Analyze Command Parser
3
+ *
4
+ * Parser for the `analyze` command (aliased as `profile`) which profiles code
5
+ * execution to identify benchmark candidates.
6
+ *
7
+ * @packageDocumentation
8
+ */
9
+
10
+ import { camelCaseValues, map, merge, opt, pos } from '@boneskull/bargs';
11
+
12
+ /**
13
+ * Base parser for `analyze` command options and positionals
14
+ */
15
+ const analyzeParserBase = merge(
16
+ opt.options({
17
+ 'filter-file': opt.string({
18
+ description: 'Filter functions by file glob pattern',
19
+ }),
20
+ 'group-by-file': opt.boolean({
21
+ description: 'Group results by file',
22
+ }),
23
+ input: opt.string({
24
+ aliases: ['i'],
25
+ description: 'Path to existing *.cpuprofile file',
26
+ }),
27
+ 'min-percent': opt.number({
28
+ aliases: ['m', 'min'],
29
+ default: 0.5,
30
+ description: 'Minimum execution percentage to show',
31
+ }),
32
+ top: opt.number({
33
+ aliases: ['n'],
34
+ default: 25,
35
+ description: 'Number of top functions to show',
36
+ }),
37
+ }),
38
+ pos.positionals(
39
+ pos.string({
40
+ description: 'Command to analyze (e.g., "npm test")',
41
+ name: 'command',
42
+ }),
43
+ ),
44
+ );
45
+
46
+ /**
47
+ * Parser for `analyze` command with validation and camelCase values
48
+ *
49
+ * Validates that either a command or --input is provided. Uses camelCaseValues
50
+ * transform for cleaner property access.
51
+ */
52
+ export const analyzeParser = map(
53
+ map(analyzeParserBase, ({ positionals, values }) => {
54
+ const [command] = positionals;
55
+ if (!command && !values.input) {
56
+ throw new Error('Either [command] or --input must be provided');
57
+ }
58
+ return { positionals, values };
59
+ }),
60
+ camelCaseValues,
61
+ );
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Baseline Command Parsers
3
+ *
4
+ * Parsers for the `baseline` command and its subcommands: set, list, show,
5
+ * delete, and analyze.
6
+ *
7
+ * @packageDocumentation
8
+ */
9
+
10
+ import { camelCaseValues, map, merge, opt, pos } from '@boneskull/bargs';
11
+
12
+ /**
13
+ * Parser for `baseline set` command
14
+ *
15
+ * Uses camelCaseValues transform for cleaner property access.
16
+ */
17
+ export const baselineSetParser = map(
18
+ merge(
19
+ opt.options({
20
+ branch: opt.string({
21
+ description: 'Git branch name',
22
+ }),
23
+ commit: opt.string({
24
+ description: 'Git commit SHA (40 characters)',
25
+ }),
26
+ default: opt.boolean({
27
+ description: 'Set as default baseline',
28
+ }),
29
+ 'run-id': opt.string({
30
+ description: 'Specific run ID to save (default: most recent)',
31
+ }),
32
+ }),
33
+ pos.positionals(
34
+ pos.string({
35
+ description: 'Name for the baseline',
36
+ name: 'name',
37
+ required: true,
38
+ }),
39
+ ),
40
+ ),
41
+ camelCaseValues,
42
+ );
43
+
44
+ /**
45
+ * Parser for `baseline list` command
46
+ */
47
+ export const baselineListParser = opt.options({
48
+ format: opt.enum(['human', 'json'] as const, {
49
+ description: 'Output format',
50
+ }),
51
+ });
52
+
53
+ /**
54
+ * Parser for `baseline show` command
55
+ */
56
+ export const baselineShowParser = merge(
57
+ opt.options({
58
+ format: opt.enum(['human', 'json'] as const, {
59
+ description: 'Output format',
60
+ }),
61
+ }),
62
+ pos.positionals(
63
+ pos.string({
64
+ description: 'Baseline name to show',
65
+ name: 'name',
66
+ required: true,
67
+ }),
68
+ ),
69
+ );
70
+
71
+ /**
72
+ * Parser for `baseline delete` command
73
+ */
74
+ export const baselineDeleteParser = pos.positionals(
75
+ pos.string({
76
+ description: 'Baseline name to delete',
77
+ name: 'name',
78
+ required: true,
79
+ }),
80
+ );
81
+
82
+ /**
83
+ * Parser for `baseline analyze` command
84
+ */
85
+ export const baselineAnalyzeParser = opt.options({
86
+ confidence: opt.number({
87
+ description: 'Confidence level (0.5-0.999, default 0.95)',
88
+ }),
89
+ runs: opt.number({
90
+ description: 'Number of recent runs to analyze',
91
+ }),
92
+ });
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Global CLI Options
3
+ *
4
+ * Options shared across all commands (verbose, config, cwd, etc.) and common
5
+ * option fragments used by subcommands.
6
+ *
7
+ * @packageDocumentation
8
+ */
9
+
10
+ import { camelCaseValues, map, opt } from '@boneskull/bargs';
11
+
12
+ /**
13
+ * Global options available to all commands
14
+ *
15
+ * Uses camelCaseValues transform so handlers can use `values.noColor` instead
16
+ * of `values['no-color']`.
17
+ */
18
+ export const globalOptions = map(
19
+ opt.options({
20
+ config: opt.string({
21
+ aliases: ['c'],
22
+ description: 'Path to configuration file',
23
+ }),
24
+ cwd: opt.string({
25
+ description: 'Working directory',
26
+ }),
27
+ json: opt.boolean({
28
+ description: 'Output results in JSON format',
29
+ }),
30
+ 'no-color': opt.boolean({
31
+ description: 'Disable colored output',
32
+ }),
33
+ progress: opt.boolean({
34
+ description: 'Show animated progress bar',
35
+ }),
36
+ verbose: opt.boolean({
37
+ aliases: ['v'],
38
+ description: 'Enable verbose output',
39
+ }),
40
+ }),
41
+ camelCaseValues,
42
+ );
43
+
44
+ /**
45
+ * Additional global options for history and baseline subcommands
46
+ */
47
+ export const quietOption = opt.options({
48
+ quiet: opt.boolean({
49
+ description: 'Minimal output',
50
+ }),
51
+ });
@@ -0,0 +1,168 @@
1
+ /**
2
+ * History Command Parsers
3
+ *
4
+ * Parsers for the `history` command and its subcommands: list, show, compare,
5
+ * trends, clean, and export.
6
+ *
7
+ * @packageDocumentation
8
+ */
9
+
10
+ import { camelCaseValues, map, merge, opt, pos } from '@boneskull/bargs';
11
+
12
+ /**
13
+ * Parser for `history list` command
14
+ */
15
+ export const historyListParser = opt.options({
16
+ format: opt.enum(['human', 'json', 'csv'] as const, {
17
+ description: 'Output format',
18
+ }),
19
+ limit: opt.number({
20
+ description: 'Maximum number of results',
21
+ }),
22
+ pattern: opt.string({
23
+ description: 'Filter by benchmark name pattern',
24
+ }),
25
+ since: opt.string({
26
+ description:
27
+ 'Show runs since date (ISO 8601 or relative like "1 week ago")',
28
+ }),
29
+ tag: opt.array('string', {
30
+ aliases: ['t'],
31
+ description: 'Filter by tags',
32
+ }),
33
+ until: opt.string({
34
+ description: 'Show runs until date (ISO 8601 or relative like "1 day ago")',
35
+ }),
36
+ });
37
+
38
+ /**
39
+ * Parser for `history show` command
40
+ */
41
+ export const historyShowParser = merge(
42
+ opt.options({
43
+ format: opt.enum(['human', 'json', 'csv'] as const, {
44
+ description: 'Output format',
45
+ }),
46
+ }),
47
+ pos.positionals(
48
+ pos.string({
49
+ description: 'ID of the benchmark run to show',
50
+ name: 'run-id',
51
+ required: true,
52
+ }),
53
+ ),
54
+ );
55
+
56
+ /**
57
+ * Parser for `history compare` command
58
+ */
59
+ export const historyCompareParser = merge(
60
+ opt.options({
61
+ format: opt.enum(['human', 'json'] as const, {
62
+ description: 'Output format',
63
+ }),
64
+ }),
65
+ pos.positionals(
66
+ pos.string({
67
+ description: 'ID of the first benchmark run',
68
+ name: 'run-id1',
69
+ required: true,
70
+ }),
71
+ pos.string({
72
+ description: 'ID of the second benchmark run',
73
+ name: 'run-id2',
74
+ required: true,
75
+ }),
76
+ ),
77
+ );
78
+
79
+ /**
80
+ * Parser for `history trends` command
81
+ */
82
+ export const historyTrendsParser = merge(
83
+ opt.options({
84
+ all: opt.boolean({
85
+ aliases: ['a'],
86
+ description: 'Analyze all runs (ignore limit)',
87
+ }),
88
+ format: opt.enum(['human', 'json'] as const, {
89
+ description: 'Output format',
90
+ }),
91
+ limit: opt.number({
92
+ description: 'Maximum number of runs to analyze',
93
+ }),
94
+ since: opt.string({
95
+ description:
96
+ 'Show trends since date (ISO 8601 or relative like "1 week ago")',
97
+ }),
98
+ tag: opt.array('string', {
99
+ aliases: ['t'],
100
+ description: 'Filter by tags',
101
+ }),
102
+ until: opt.string({
103
+ description:
104
+ 'Show trends until date (ISO 8601 or relative like "1 day ago")',
105
+ }),
106
+ }),
107
+ pos.positionals(
108
+ pos.string({
109
+ description: 'Filter by benchmark name pattern',
110
+ name: 'pattern',
111
+ }),
112
+ ),
113
+ );
114
+
115
+ /**
116
+ * Parser for `history clean` command
117
+ *
118
+ * Includes validation requiring at least one cleanup criterion. Uses
119
+ * camelCaseValues transform for cleaner property access.
120
+ */
121
+ export const historyCleanParser = map(
122
+ map(
123
+ opt.options({
124
+ 'max-age': opt.number({
125
+ description: 'Remove runs older than this many days',
126
+ }),
127
+ 'max-runs': opt.number({
128
+ description: 'Keep only this many most recent runs',
129
+ }),
130
+ 'max-size': opt.number({
131
+ description: 'Keep history under this size in bytes',
132
+ }),
133
+ yes: opt.boolean({
134
+ aliases: ['y'],
135
+ description: 'Confirm cleanup without prompting',
136
+ }),
137
+ }),
138
+ ({ positionals, values }) => {
139
+ if (!values['max-age'] && !values['max-runs'] && !values['max-size']) {
140
+ throw new Error(
141
+ 'At least one cleanup criterion must be specified (--max-age, --max-runs, or --max-size)',
142
+ );
143
+ }
144
+ return { positionals, values };
145
+ },
146
+ ),
147
+ camelCaseValues,
148
+ );
149
+
150
+ /**
151
+ * Parser for `history export` command
152
+ */
153
+ export const historyExportParser = opt.options({
154
+ format: opt.enum(['json', 'csv'] as const, {
155
+ description: 'Export format',
156
+ }),
157
+ output: opt.string({
158
+ aliases: ['o'],
159
+ description: 'Output file path',
160
+ required: true,
161
+ }),
162
+ since: opt.string({
163
+ description: 'Export runs since date',
164
+ }),
165
+ until: opt.string({
166
+ description: 'Export runs until date',
167
+ }),
168
+ });
@@ -0,0 +1,28 @@
1
+ /**
2
+ * CLI Parsers
3
+ *
4
+ * Re-exports all bargs parser definitions for CLI commands.
5
+ *
6
+ * @packageDocumentation
7
+ */
8
+
9
+ export { analyzeParser } from './analyze.js';
10
+ export {
11
+ baselineAnalyzeParser,
12
+ baselineDeleteParser,
13
+ baselineListParser,
14
+ baselineSetParser,
15
+ baselineShowParser,
16
+ } from './baseline.js';
17
+ export { globalOptions, quietOption } from './global.js';
18
+ export {
19
+ historyCleanParser,
20
+ historyCompareParser,
21
+ historyExportParser,
22
+ historyListParser,
23
+ historyShowParser,
24
+ historyTrendsParser,
25
+ } from './history.js';
26
+ export { initParser } from './init.js';
27
+ export { runParser } from './run.js';
28
+ export { testParser } from './test.js';
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Init Command Parser
3
+ *
4
+ * Parser for the `init` command which initializes a new benchmark project.
5
+ *
6
+ * @packageDocumentation
7
+ */
8
+
9
+ import { camelCaseValues, map, merge, opt, pos } from '@boneskull/bargs';
10
+
11
+ /**
12
+ * Parser for `init` command
13
+ *
14
+ * Uses camelCaseValues transform for cleaner property access.
15
+ */
16
+ export const initParser = map(
17
+ merge(
18
+ opt.options({
19
+ 'config-type': opt.enum(['json', 'yaml', 'js', 'ts'] as const, {
20
+ description: 'Configuration file format',
21
+ }),
22
+ examples: opt.boolean({
23
+ description: 'Include example benchmark files',
24
+ }),
25
+ force: opt.boolean({
26
+ description: 'Overwrite existing files',
27
+ }),
28
+ quiet: opt.boolean({
29
+ aliases: ['q'],
30
+ description: 'Minimal output',
31
+ }),
32
+ yes: opt.boolean({
33
+ aliases: ['y'],
34
+ description: 'Accept all prompts automatically',
35
+ }),
36
+ }),
37
+ pos.positionals(
38
+ pos.enum(['basic', 'advanced', 'library'] as const, {
39
+ description: 'Type of project to initialize',
40
+ name: 'type',
41
+ }),
42
+ ),
43
+ ),
44
+ camelCaseValues,
45
+ );
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Run Command Parser
3
+ *
4
+ * Parser for the `run` command which executes benchmark files.
5
+ *
6
+ * @packageDocumentation
7
+ */
8
+
9
+ import { camelCaseValues, map, merge, opt, pos } from '@boneskull/bargs';
10
+
11
+ import { DEFAULT_REPORTER, Engines, Reporters } from '../../constants.js';
12
+
13
+ /**
14
+ * Base parser for `run` command options and positionals
15
+ */
16
+ const runParserBase = merge(
17
+ opt.options({
18
+ bail: opt.boolean({
19
+ aliases: ['b'],
20
+ description: 'Stop on first failure',
21
+ }),
22
+ engine: opt.enum([Engines.TINYBENCH, Engines.ACCURATE] as const, {
23
+ aliases: ['e'],
24
+ description:
25
+ 'Benchmark engine: tinybench (default) or accurate (requires --allow-natives-syntax)',
26
+ }),
27
+ exclude: opt.array('string', {
28
+ aliases: ['X'],
29
+ description: 'Exclude patterns',
30
+ }),
31
+ 'exclude-tag': opt.array('string', {
32
+ aliases: ['T'],
33
+ description: 'Exclude benchmarks with any of these tags',
34
+ }),
35
+ iterations: opt.number({
36
+ aliases: ['i'],
37
+ description: 'Number of iterations per benchmark',
38
+ }),
39
+ 'json-pretty': opt.boolean({
40
+ description: 'Pretty-print JSON output (only affects json reporter)',
41
+ }),
42
+ 'limit-by': opt.enum(['time', 'iterations', 'any', 'all'] as const, {
43
+ aliases: ['l', 'limit'],
44
+ description:
45
+ 'How to limit benchmarks: time (time budget), iterations (sample count), any (either threshold), all (both thresholds)',
46
+ }),
47
+ output: opt.string({
48
+ aliases: ['o'],
49
+ description: 'Output directory for reports',
50
+ }),
51
+ 'output-file': opt.string({
52
+ aliases: ['of', 'file'],
53
+ description:
54
+ 'Custom filename for reporter output (use with single reporter only)',
55
+ }),
56
+ quiet: opt.boolean({
57
+ aliases: ['q'],
58
+ description: 'Minimal output',
59
+ }),
60
+ reporter: opt.array(
61
+ [
62
+ Reporters.HUMAN,
63
+ Reporters.JSON,
64
+ Reporters.CSV,
65
+ Reporters.NYAN,
66
+ Reporters.SIMPLE,
67
+ ] as const,
68
+ {
69
+ aliases: ['r'],
70
+ default: [DEFAULT_REPORTER],
71
+ description: 'Output reporters to use (human,json,csv)',
72
+ },
73
+ ),
74
+ tag: opt.array('string', {
75
+ description: 'Include only benchmarks with any of these tags',
76
+ }),
77
+ time: opt.number({
78
+ aliases: ['t'],
79
+ description: 'Time budget per benchmark in milliseconds',
80
+ }),
81
+ timeout: opt.number({
82
+ description: 'Timeout per benchmark in milliseconds',
83
+ }),
84
+ warmup: opt.number({
85
+ aliases: ['w', 'warm'],
86
+ description: 'Number of warmup iterations',
87
+ }),
88
+ }),
89
+ pos.positionals(
90
+ pos.variadic('string', {
91
+ description:
92
+ 'File paths, directory paths, or glob patterns for benchmark files',
93
+ name: 'pattern',
94
+ }),
95
+ ),
96
+ );
97
+
98
+ /**
99
+ * Parser for `run` command with validation and camelCase values
100
+ *
101
+ * Validates that --output-file is only used with a single reporter. Uses
102
+ * camelCaseValues transform for cleaner property access.
103
+ */
104
+ export const runParser = map(
105
+ map(runParserBase, ({ positionals, values }) => {
106
+ if (
107
+ values.reporter &&
108
+ values.reporter.length > 1 &&
109
+ values['output-file']
110
+ ) {
111
+ throw new Error(
112
+ '--output-file can only be used with a single reporter. Use --output <dir> for multiple reporters.',
113
+ );
114
+ }
115
+ return { positionals, values };
116
+ }),
117
+ camelCaseValues,
118
+ );
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Test Command Parser
3
+ *
4
+ * Parser for the `test` command which runs test files as benchmarks.
5
+ *
6
+ * @packageDocumentation
7
+ */
8
+
9
+ import { merge, opt, pos } from '@boneskull/bargs';
10
+
11
+ /**
12
+ * Parser for `test` command
13
+ */
14
+ export const testParser = merge(
15
+ opt.options({
16
+ bail: opt.boolean({
17
+ aliases: ['b'],
18
+ description: 'Stop on first failure',
19
+ }),
20
+ iterations: opt.number({
21
+ aliases: ['i'],
22
+ default: 100,
23
+ description: 'Number of iterations per test',
24
+ }),
25
+ quiet: opt.boolean({
26
+ aliases: ['q'],
27
+ description: 'Minimal output',
28
+ }),
29
+ warmup: opt.number({
30
+ aliases: ['w'],
31
+ default: 5,
32
+ description: 'Number of warmup iterations',
33
+ }),
34
+ }),
35
+ pos.positionals(
36
+ pos.enum(['ava', 'jest', 'mocha', 'node-test'] as const, {
37
+ description: 'Test framework to use',
38
+ name: 'framework',
39
+ required: true,
40
+ }),
41
+ pos.variadic('string', {
42
+ description: 'Test file paths or glob patterns',
43
+ name: 'files',
44
+ }),
45
+ ),
46
+ );
@@ -0,0 +1,33 @@
1
+ /**
2
+ * CLI Theme Configuration
3
+ *
4
+ * Synthwave-inspired color theme for bargs help output, matching the retro
5
+ * aesthetic used throughout modestbench reporters.
6
+ *
7
+ * @packageDocumentation
8
+ */
9
+
10
+ import { ansi } from '@boneskull/bargs';
11
+
12
+ /**
13
+ * Synthwave-inspired theme for CLI help output
14
+ *
15
+ * Matches the retro aesthetic used in modestbench reporters
16
+ */
17
+ export const synthwaveTheme = {
18
+ colors: {
19
+ command: ansi.brightMagenta,
20
+ defaultText: ansi.dim,
21
+ defaultValue: ansi.brightYellow,
22
+ description: ansi.brightWhite,
23
+ epilog: ansi.brightWhite,
24
+ example: ansi.cyan,
25
+ flag: ansi.brightCyan,
26
+ positional: ansi.brightMagenta,
27
+ scriptName: ansi.brightCyan + ansi.bold,
28
+ sectionHeader: ansi.magenta + ansi.bold,
29
+ type: ansi.brightWhite + ansi.dim,
30
+ url: ansi.brightCyan + ansi.underline,
31
+ usage: ansi.white,
32
+ },
33
+ };
@@ -26,7 +26,7 @@ export const parseTimeString = (value: string): number => {
26
26
  ms: 1_000_000,
27
27
  ns: 1,
28
28
  s: 1_000_000_000,
29
- us: 1_000,
29
+ us: 1000,
30
30
  };
31
31
 
32
32
  return num * multipliers[unit as keyof typeof multipliers];
@@ -38,7 +38,7 @@ export class AccurateEngine extends ModestBenchEngine {
38
38
  * Maximum iterations per round to prevent overwhelming Node.js test runner
39
39
  * and excessive memory usage
40
40
  */
41
- private static readonly MAX_ITERATIONS_PER_ROUND = 10000;
41
+ private static readonly MAX_ITERATIONS_PER_ROUND = 10_000;
42
42
 
43
43
  /**
44
44
  * Maximum iterations per round for async functions (much lower due to
@@ -6,6 +6,7 @@
6
6
  */
7
7
 
8
8
  import { SITE_URL } from '../constants.js';
9
+ import { isError } from '../utils/type-guards.js';
9
10
 
10
11
  /**
11
12
  * Base URL for error documentation
@@ -150,13 +151,3 @@ export const isModestBenchError = (
150
151
  (error as { code: string }).code.startsWith('ERR_MB_')
151
152
  );
152
153
  };
153
-
154
- /**
155
- * Type guard to check if an error is a standard Error
156
- *
157
- * @param error - The error to check
158
- * @returns `true` if the error is an `Error`
159
- */
160
- export const isError = (error: unknown): error is Error => {
161
- return error instanceof Error;
162
- };