modestbench 0.1.0 → 0.3.0
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.
- package/CHANGELOG.md +31 -0
- package/README.md +162 -57
- package/dist/bootstrap.cjs +10 -10
- package/dist/bootstrap.cjs.map +1 -1
- package/dist/bootstrap.d.cts.map +1 -1
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +5 -5
- package/dist/bootstrap.js.map +1 -1
- package/dist/cli/commands/analyze.cjs +60 -0
- package/dist/cli/commands/analyze.cjs.map +1 -0
- package/dist/cli/commands/analyze.d.cts +35 -0
- package/dist/cli/commands/analyze.d.cts.map +1 -0
- package/dist/cli/commands/analyze.d.ts +35 -0
- package/dist/cli/commands/analyze.d.ts.map +1 -0
- package/dist/cli/commands/analyze.js +56 -0
- package/dist/cli/commands/analyze.js.map +1 -0
- package/dist/cli/commands/baseline.cjs +404 -0
- package/dist/cli/commands/baseline.cjs.map +1 -0
- package/dist/cli/commands/baseline.d.cts +72 -0
- package/dist/cli/commands/baseline.d.cts.map +1 -0
- package/dist/cli/commands/baseline.d.ts +72 -0
- package/dist/cli/commands/baseline.d.ts.map +1 -0
- package/dist/cli/commands/baseline.js +396 -0
- package/dist/cli/commands/baseline.js.map +1 -0
- package/dist/cli/commands/history.cjs +108 -266
- package/dist/cli/commands/history.cjs.map +1 -1
- package/dist/cli/commands/history.d.cts +75 -12
- package/dist/cli/commands/history.d.cts.map +1 -1
- package/dist/cli/commands/history.d.ts +75 -12
- package/dist/cli/commands/history.d.ts.map +1 -1
- package/dist/cli/commands/history.js +105 -268
- package/dist/cli/commands/history.js.map +1 -1
- package/dist/cli/commands/init.cjs +88 -155
- package/dist/cli/commands/init.cjs.map +1 -1
- package/dist/cli/commands/init.d.cts +4 -4
- package/dist/cli/commands/init.d.cts.map +1 -1
- package/dist/cli/commands/init.d.ts +4 -4
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +88 -155
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/run.cjs +143 -112
- package/dist/cli/commands/run.cjs.map +1 -1
- package/dist/cli/commands/run.d.cts +17 -3
- package/dist/cli/commands/run.d.cts.map +1 -1
- package/dist/cli/commands/run.d.ts +17 -3
- package/dist/cli/commands/run.d.ts.map +1 -1
- package/dist/cli/commands/run.js +142 -78
- package/dist/cli/commands/run.js.map +1 -1
- package/dist/cli/index.cjs +671 -266
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.d.cts +4 -16
- package/dist/cli/index.d.cts.map +1 -1
- package/dist/cli/index.d.ts +4 -16
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +664 -259
- package/dist/cli/index.js.map +1 -1
- package/dist/config/budget-schema.cjs +172 -0
- package/dist/config/budget-schema.cjs.map +1 -0
- package/dist/config/budget-schema.d.cts +59 -0
- package/dist/config/budget-schema.d.cts.map +1 -0
- package/dist/config/budget-schema.d.ts +59 -0
- package/dist/config/budget-schema.d.ts.map +1 -0
- package/dist/config/budget-schema.js +166 -0
- package/dist/config/budget-schema.js.map +1 -0
- package/dist/config/schema.cjs +182 -2
- package/dist/config/schema.cjs.map +1 -1
- package/dist/config/schema.d.cts +122 -3
- package/dist/config/schema.d.cts.map +1 -1
- package/dist/config/schema.d.ts +122 -3
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +180 -1
- package/dist/config/schema.js.map +1 -1
- package/dist/constants.cjs +45 -2
- package/dist/constants.cjs.map +1 -1
- package/dist/constants.d.cts +41 -0
- package/dist/constants.d.cts.map +1 -1
- package/dist/constants.d.ts +41 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +44 -1
- package/dist/constants.js.map +1 -1
- package/dist/core/engine.cjs +104 -15
- package/dist/core/engine.cjs.map +1 -1
- package/dist/core/engine.d.cts +7 -4
- package/dist/core/engine.d.cts.map +1 -1
- package/dist/core/engine.d.ts +7 -4
- package/dist/core/engine.d.ts.map +1 -1
- package/dist/core/engine.js +105 -16
- package/dist/core/engine.js.map +1 -1
- package/dist/core/output-path-resolver.cjs +41 -0
- package/dist/core/output-path-resolver.cjs.map +1 -0
- package/dist/core/output-path-resolver.d.cts +10 -0
- package/dist/core/output-path-resolver.d.cts.map +1 -0
- package/dist/core/output-path-resolver.d.ts +10 -0
- package/dist/core/output-path-resolver.d.ts.map +1 -0
- package/dist/core/output-path-resolver.js +37 -0
- package/dist/core/output-path-resolver.js.map +1 -0
- package/dist/errors/base.cjs +12 -3
- package/dist/errors/base.cjs.map +1 -1
- package/dist/errors/base.d.cts +7 -0
- package/dist/errors/base.d.cts.map +1 -1
- package/dist/errors/base.d.ts +7 -0
- package/dist/errors/base.d.ts.map +1 -1
- package/dist/errors/base.js +10 -2
- package/dist/errors/base.js.map +1 -1
- package/dist/errors/budget.cjs +37 -0
- package/dist/errors/budget.cjs.map +1 -0
- package/dist/errors/budget.d.cts +31 -0
- package/dist/errors/budget.d.cts.map +1 -0
- package/dist/errors/budget.d.ts +31 -0
- package/dist/errors/budget.d.ts.map +1 -0
- package/dist/errors/budget.js +33 -0
- package/dist/errors/budget.js.map +1 -0
- package/dist/errors/index.cjs +4 -1
- package/dist/errors/index.cjs.map +1 -1
- package/dist/errors/index.d.cts +1 -0
- package/dist/errors/index.d.cts.map +1 -1
- package/dist/errors/index.d.ts +1 -0
- package/dist/errors/index.d.ts.map +1 -1
- package/dist/errors/index.js +2 -0
- package/dist/errors/index.js.map +1 -1
- package/dist/formatters/history/base.cjs +9 -0
- package/dist/formatters/history/base.cjs.map +1 -0
- package/dist/formatters/history/base.d.cts +26 -0
- package/dist/formatters/history/base.d.cts.map +1 -0
- package/dist/formatters/history/base.d.ts +26 -0
- package/dist/formatters/history/base.d.ts.map +1 -0
- package/dist/formatters/history/base.js +8 -0
- package/dist/formatters/history/base.js.map +1 -0
- package/dist/formatters/history/compare.cjs +127 -0
- package/dist/formatters/history/compare.cjs.map +1 -0
- package/dist/formatters/history/compare.d.cts +21 -0
- package/dist/formatters/history/compare.d.cts.map +1 -0
- package/dist/formatters/history/compare.d.ts +21 -0
- package/dist/formatters/history/compare.d.ts.map +1 -0
- package/dist/formatters/history/compare.js +123 -0
- package/dist/formatters/history/compare.js.map +1 -0
- package/dist/formatters/history/list.cjs +74 -0
- package/dist/formatters/history/list.cjs.map +1 -0
- package/dist/formatters/history/list.d.cts +25 -0
- package/dist/formatters/history/list.d.cts.map +1 -0
- package/dist/formatters/history/list.d.ts +25 -0
- package/dist/formatters/history/list.d.ts.map +1 -0
- package/dist/formatters/history/list.js +70 -0
- package/dist/formatters/history/list.js.map +1 -0
- package/dist/formatters/history/show.cjs +98 -0
- package/dist/formatters/history/show.cjs.map +1 -0
- package/dist/formatters/history/show.d.cts +21 -0
- package/dist/formatters/history/show.d.cts.map +1 -0
- package/dist/formatters/history/show.d.ts +21 -0
- package/dist/formatters/history/show.d.ts.map +1 -0
- package/dist/formatters/history/show.js +94 -0
- package/dist/formatters/history/show.js.map +1 -0
- package/dist/formatters/history/trends.cjs +194 -0
- package/dist/formatters/history/trends.cjs.map +1 -0
- package/dist/formatters/history/trends.d.cts +22 -0
- package/dist/formatters/history/trends.d.cts.map +1 -0
- package/dist/formatters/history/trends.d.ts +22 -0
- package/dist/formatters/history/trends.d.ts.map +1 -0
- package/dist/formatters/history/trends.js +190 -0
- package/dist/formatters/history/trends.js.map +1 -0
- package/dist/formatters/history/visualization.cjs +79 -0
- package/dist/formatters/history/visualization.cjs.map +1 -0
- package/dist/formatters/history/visualization.d.cts +24 -0
- package/dist/formatters/history/visualization.d.cts.map +1 -0
- package/dist/formatters/history/visualization.d.ts +24 -0
- package/dist/formatters/history/visualization.d.ts.map +1 -0
- package/dist/formatters/history/visualization.js +74 -0
- package/dist/formatters/history/visualization.js.map +1 -0
- package/dist/index.cjs +27 -17
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -5
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +10 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -9
- package/dist/index.js.map +1 -1
- package/dist/reporters/csv.cjs +39 -19
- package/dist/reporters/csv.cjs.map +1 -1
- package/dist/reporters/csv.d.cts +4 -7
- package/dist/reporters/csv.d.cts.map +1 -1
- package/dist/reporters/csv.d.ts +4 -7
- package/dist/reporters/csv.d.ts.map +1 -1
- package/dist/reporters/csv.js +38 -18
- package/dist/reporters/csv.js.map +1 -1
- package/dist/reporters/human.cjs +87 -99
- package/dist/reporters/human.cjs.map +1 -1
- package/dist/reporters/human.d.cts +15 -14
- package/dist/reporters/human.d.cts.map +1 -1
- package/dist/reporters/human.d.ts +15 -14
- package/dist/reporters/human.d.ts.map +1 -1
- package/dist/reporters/human.js +68 -80
- package/dist/reporters/human.js.map +1 -1
- package/dist/reporters/json.cjs +25 -50
- package/dist/reporters/json.cjs.map +1 -1
- package/dist/reporters/json.d.cts +3 -29
- package/dist/reporters/json.d.cts.map +1 -1
- package/dist/reporters/json.d.ts +3 -29
- package/dist/reporters/json.d.ts.map +1 -1
- package/dist/reporters/json.js +26 -51
- package/dist/reporters/json.js.map +1 -1
- package/dist/reporters/profile-human.cjs +149 -0
- package/dist/reporters/profile-human.cjs.map +1 -0
- package/dist/reporters/profile-human.d.cts +44 -0
- package/dist/reporters/profile-human.d.cts.map +1 -0
- package/dist/reporters/profile-human.d.ts +44 -0
- package/dist/reporters/profile-human.d.ts.map +1 -0
- package/dist/reporters/profile-human.js +142 -0
- package/dist/reporters/profile-human.js.map +1 -0
- package/dist/reporters/simple.cjs +66 -46
- package/dist/reporters/simple.cjs.map +1 -1
- package/dist/reporters/simple.d.cts +15 -15
- package/dist/reporters/simple.d.cts.map +1 -1
- package/dist/reporters/simple.d.ts +15 -15
- package/dist/reporters/simple.d.ts.map +1 -1
- package/dist/reporters/simple.js +65 -45
- package/dist/reporters/simple.js.map +1 -1
- package/dist/schema/modestbench-config.schema.json +153 -0
- package/dist/services/baseline-storage.cjs +151 -0
- package/dist/services/baseline-storage.cjs.map +1 -0
- package/dist/services/baseline-storage.d.cts +55 -0
- package/dist/services/baseline-storage.d.cts.map +1 -0
- package/dist/services/baseline-storage.d.ts +55 -0
- package/dist/services/baseline-storage.d.ts.map +1 -0
- package/dist/services/baseline-storage.js +147 -0
- package/dist/services/baseline-storage.js.map +1 -0
- package/dist/services/budget-evaluator.cjs +146 -0
- package/dist/services/budget-evaluator.cjs.map +1 -0
- package/dist/services/budget-evaluator.d.cts +29 -0
- package/dist/services/budget-evaluator.d.cts.map +1 -0
- package/dist/services/budget-evaluator.d.ts +29 -0
- package/dist/services/budget-evaluator.d.ts.map +1 -0
- package/dist/services/budget-evaluator.js +142 -0
- package/dist/services/budget-evaluator.js.map +1 -0
- package/dist/{config/manager.cjs → services/config-manager.cjs} +25 -11
- package/dist/services/config-manager.cjs.map +1 -0
- package/dist/{config/manager.d.cts → services/config-manager.d.cts} +7 -2
- package/dist/services/config-manager.d.cts.map +1 -0
- package/dist/{config/manager.d.ts → services/config-manager.d.ts} +7 -2
- package/dist/services/config-manager.d.ts.map +1 -0
- package/dist/{config/manager.js → services/config-manager.js} +25 -11
- package/dist/services/config-manager.js.map +1 -0
- package/dist/{core/loader.cjs → services/file-loader.cjs} +5 -8
- package/dist/services/file-loader.cjs.map +1 -0
- package/dist/{core/loader.d.cts → services/file-loader.d.cts} +1 -1
- package/dist/services/file-loader.d.cts.map +1 -0
- package/dist/{core/loader.d.ts → services/file-loader.d.ts} +1 -1
- package/dist/services/file-loader.d.ts.map +1 -0
- package/dist/{core/loader.js → services/file-loader.js} +5 -8
- package/dist/services/file-loader.js.map +1 -0
- package/dist/services/history/comparison.cjs +124 -0
- package/dist/services/history/comparison.cjs.map +1 -0
- package/dist/services/history/comparison.d.cts +18 -0
- package/dist/services/history/comparison.d.cts.map +1 -0
- package/dist/services/history/comparison.d.ts +18 -0
- package/dist/services/history/comparison.d.ts.map +1 -0
- package/dist/services/history/comparison.js +120 -0
- package/dist/services/history/comparison.js.map +1 -0
- package/dist/services/history/models.cjs +9 -0
- package/dist/services/history/models.cjs.map +1 -0
- package/dist/services/history/models.d.cts +139 -0
- package/dist/services/history/models.d.cts.map +1 -0
- package/dist/services/history/models.d.ts +139 -0
- package/dist/services/history/models.d.ts.map +1 -0
- package/dist/services/history/models.js +8 -0
- package/dist/services/history/models.js.map +1 -0
- package/dist/services/history/query.cjs +97 -0
- package/dist/services/history/query.cjs.map +1 -0
- package/dist/services/history/query.d.cts +38 -0
- package/dist/services/history/query.d.cts.map +1 -0
- package/dist/services/history/query.d.ts +38 -0
- package/dist/services/history/query.d.ts.map +1 -0
- package/dist/services/history/query.js +92 -0
- package/dist/services/history/query.js.map +1 -0
- package/dist/services/history/trend-analysis.cjs +187 -0
- package/dist/services/history/trend-analysis.cjs.map +1 -0
- package/dist/services/history/trend-analysis.d.cts +34 -0
- package/dist/services/history/trend-analysis.d.cts.map +1 -0
- package/dist/services/history/trend-analysis.d.ts +34 -0
- package/dist/services/history/trend-analysis.d.ts.map +1 -0
- package/dist/services/history/trend-analysis.js +179 -0
- package/dist/services/history/trend-analysis.js.map +1 -0
- package/dist/{storage/history.cjs → services/history-storage.cjs} +1 -1
- package/dist/services/history-storage.cjs.map +1 -0
- package/dist/{storage/history.d.cts → services/history-storage.d.cts} +1 -1
- package/dist/services/history-storage.d.cts.map +1 -0
- package/dist/{storage/history.d.ts → services/history-storage.d.ts} +1 -1
- package/dist/services/history-storage.d.ts.map +1 -0
- package/dist/{storage/history.js → services/history-storage.js} +1 -1
- package/dist/services/history-storage.js.map +1 -0
- package/dist/services/profiler/profile-filter.cjs +113 -0
- package/dist/services/profiler/profile-filter.cjs.map +1 -0
- package/dist/services/profiler/profile-filter.d.cts +20 -0
- package/dist/services/profiler/profile-filter.d.cts.map +1 -0
- package/dist/services/profiler/profile-filter.d.ts +20 -0
- package/dist/services/profiler/profile-filter.d.ts.map +1 -0
- package/dist/services/profiler/profile-filter.js +109 -0
- package/dist/services/profiler/profile-filter.js.map +1 -0
- package/dist/services/profiler/profile-parser.cjs +139 -0
- package/dist/services/profiler/profile-parser.cjs.map +1 -0
- package/dist/services/profiler/profile-parser.d.cts +18 -0
- package/dist/services/profiler/profile-parser.d.cts.map +1 -0
- package/dist/services/profiler/profile-parser.d.ts +18 -0
- package/dist/services/profiler/profile-parser.d.ts.map +1 -0
- package/dist/services/profiler/profile-parser.js +132 -0
- package/dist/services/profiler/profile-parser.js.map +1 -0
- package/dist/services/profiler/profile-runner.cjs +90 -0
- package/dist/services/profiler/profile-runner.cjs.map +1 -0
- package/dist/services/profiler/profile-runner.d.cts +29 -0
- package/dist/services/profiler/profile-runner.d.cts.map +1 -0
- package/dist/services/profiler/profile-runner.d.ts +29 -0
- package/dist/services/profiler/profile-runner.d.ts.map +1 -0
- package/dist/services/profiler/profile-runner.js +86 -0
- package/dist/services/profiler/profile-runner.js.map +1 -0
- package/dist/{progress/manager.cjs → services/progress-manager.cjs} +1 -1
- package/dist/services/progress-manager.cjs.map +1 -0
- package/dist/{progress/manager.d.cts → services/progress-manager.d.cts} +1 -1
- package/dist/services/progress-manager.d.cts.map +1 -0
- package/dist/{progress/manager.d.ts → services/progress-manager.d.ts} +1 -1
- package/dist/services/progress-manager.d.ts.map +1 -0
- package/dist/{progress/manager.js → services/progress-manager.js} +1 -1
- package/dist/services/progress-manager.js.map +1 -0
- package/dist/{reporters/registry.cjs → services/reporter-registry.cjs} +19 -25
- package/dist/services/reporter-registry.cjs.map +1 -0
- package/dist/{reporters/registry.d.cts → services/reporter-registry.d.cts} +19 -41
- package/dist/services/reporter-registry.d.cts.map +1 -0
- package/dist/{reporters/registry.d.ts → services/reporter-registry.d.ts} +19 -41
- package/dist/services/reporter-registry.d.ts.map +1 -0
- package/dist/{reporters/registry.js → services/reporter-registry.js} +19 -25
- package/dist/services/reporter-registry.js.map +1 -0
- package/dist/types/budgets.cjs +8 -0
- package/dist/types/budgets.cjs.map +1 -0
- package/dist/types/budgets.d.cts +149 -0
- package/dist/types/budgets.d.cts.map +1 -0
- package/dist/types/budgets.d.ts +149 -0
- package/dist/types/budgets.d.ts.map +1 -0
- package/dist/types/budgets.js +7 -0
- package/dist/types/budgets.js.map +1 -0
- package/dist/types/cli.cjs +2 -11
- package/dist/types/cli.cjs.map +1 -1
- package/dist/types/cli.d.cts +3 -224
- package/dist/types/cli.d.cts.map +1 -1
- package/dist/types/cli.d.ts +3 -224
- package/dist/types/cli.d.ts.map +1 -1
- package/dist/types/cli.js +2 -11
- package/dist/types/cli.js.map +1 -1
- package/dist/types/core.cjs +6 -1
- package/dist/types/core.cjs.map +1 -1
- package/dist/types/core.d.cts +13 -2
- package/dist/types/core.d.cts.map +1 -1
- package/dist/types/core.d.ts +13 -2
- package/dist/types/core.d.ts.map +1 -1
- package/dist/types/core.js +2 -1
- package/dist/types/core.js.map +1 -1
- package/dist/types/index.cjs +5 -0
- package/dist/types/index.cjs.map +1 -1
- package/dist/types/index.d.cts +2 -0
- package/dist/types/index.d.cts.map +1 -1
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -1
- package/dist/types/interfaces.d.cts +15 -8
- package/dist/types/interfaces.d.cts.map +1 -1
- package/dist/types/interfaces.d.ts +15 -8
- package/dist/types/interfaces.d.ts.map +1 -1
- package/dist/types/profiler.cjs +11 -0
- package/dist/types/profiler.cjs.map +1 -0
- package/dist/types/profiler.d.cts +100 -0
- package/dist/types/profiler.d.cts.map +1 -0
- package/dist/types/profiler.d.ts +100 -0
- package/dist/types/profiler.d.ts.map +1 -0
- package/dist/types/profiler.js +10 -0
- package/dist/types/profiler.js.map +1 -0
- package/dist/types/utility.cjs.map +1 -1
- package/dist/types/utility.d.cts +0 -8
- package/dist/types/utility.d.cts.map +1 -1
- package/dist/types/utility.d.ts +0 -8
- package/dist/types/utility.d.ts.map +1 -1
- package/dist/types/utility.js.map +1 -1
- package/dist/utils/ansi.cjs +61 -0
- package/dist/utils/ansi.cjs.map +1 -0
- package/dist/utils/ansi.d.cts +53 -0
- package/dist/utils/ansi.d.cts.map +1 -0
- package/dist/utils/ansi.d.ts +53 -0
- package/dist/utils/ansi.d.ts.map +1 -0
- package/dist/utils/ansi.js +57 -0
- package/dist/utils/ansi.js.map +1 -0
- package/dist/utils/identifiers.cjs +32 -0
- package/dist/utils/identifiers.cjs.map +1 -0
- package/dist/utils/identifiers.d.cts +32 -0
- package/dist/utils/identifiers.d.cts.map +1 -0
- package/dist/utils/identifiers.d.ts +32 -0
- package/dist/utils/identifiers.d.ts.map +1 -0
- package/dist/utils/identifiers.js +27 -0
- package/dist/utils/identifiers.js.map +1 -0
- package/dist/utils/package.cjs +40 -0
- package/dist/utils/package.cjs.map +1 -0
- package/dist/utils/package.d.cts +15 -0
- package/dist/utils/package.d.cts.map +1 -0
- package/dist/utils/package.d.ts +15 -0
- package/dist/utils/package.d.ts.map +1 -0
- package/dist/utils/package.js +33 -0
- package/dist/utils/package.js.map +1 -0
- package/dist/utils/type-guards.cjs +48 -0
- package/dist/utils/type-guards.cjs.map +1 -0
- package/dist/utils/type-guards.d.cts +22 -0
- package/dist/utils/type-guards.d.cts.map +1 -0
- package/dist/utils/type-guards.d.ts +22 -0
- package/dist/utils/type-guards.d.ts.map +1 -0
- package/dist/utils/type-guards.js +43 -0
- package/dist/utils/type-guards.js.map +1 -0
- package/package.json +14 -13
- package/src/bootstrap.ts +5 -5
- package/src/cli/commands/analyze.ts +101 -0
- package/src/cli/commands/baseline.ts +577 -0
- package/src/cli/commands/history.ts +194 -342
- package/src/cli/commands/init.ts +105 -183
- package/src/cli/commands/run.ts +186 -88
- package/src/cli/index.ts +731 -234
- package/src/config/budget-schema.ts +189 -0
- package/src/config/schema.ts +260 -1
- package/src/constants.ts +53 -1
- package/src/core/engine.ts +153 -14
- package/src/core/output-path-resolver.ts +46 -0
- package/src/errors/base.ts +11 -2
- package/src/errors/budget.ts +38 -0
- package/src/errors/index.ts +3 -0
- package/src/formatters/history/base.ts +28 -0
- package/src/formatters/history/compare.ts +186 -0
- package/src/formatters/history/list.ts +101 -0
- package/src/formatters/history/show.ts +155 -0
- package/src/formatters/history/trends.ts +281 -0
- package/src/formatters/history/visualization.ts +93 -0
- package/src/index.ts +17 -12
- package/src/reporters/csv.ts +55 -26
- package/src/reporters/human.ts +90 -89
- package/src/reporters/json.ts +27 -72
- package/src/reporters/profile-human.ts +204 -0
- package/src/reporters/simple.ts +85 -54
- package/src/services/baseline-storage.ts +199 -0
- package/src/services/budget-evaluator.ts +182 -0
- package/src/{config/manager.ts → services/config-manager.ts} +24 -9
- package/src/{core/loader.ts → services/file-loader.ts} +4 -7
- package/src/services/history/comparison.ts +130 -0
- package/src/services/history/models.ts +148 -0
- package/src/services/history/query.ts +116 -0
- package/src/services/history/trend-analysis.ts +238 -0
- package/src/services/profiler/profile-filter.ts +143 -0
- package/src/services/profiler/profile-parser.ts +194 -0
- package/src/services/profiler/profile-runner.ts +121 -0
- package/src/{reporters/registry.ts → services/reporter-registry.ts} +46 -81
- package/src/types/budgets.ts +180 -0
- package/src/types/cli.ts +5 -235
- package/src/types/core.ts +50 -10
- package/src/types/index.ts +5 -0
- package/src/types/interfaces.ts +16 -6
- package/src/types/profiler.ts +132 -0
- package/src/types/utility.ts +0 -10
- package/src/utils/ansi.ts +59 -0
- package/src/utils/identifiers.ts +58 -0
- package/src/utils/package.ts +35 -0
- package/src/utils/type-guards.ts +51 -0
- package/dist/config/manager.cjs.map +0 -1
- package/dist/config/manager.d.cts.map +0 -1
- package/dist/config/manager.d.ts.map +0 -1
- package/dist/config/manager.js.map +0 -1
- package/dist/core/loader.cjs.map +0 -1
- package/dist/core/loader.d.cts.map +0 -1
- package/dist/core/loader.d.ts.map +0 -1
- package/dist/core/loader.js.map +0 -1
- package/dist/progress/manager.cjs.map +0 -1
- package/dist/progress/manager.d.cts.map +0 -1
- package/dist/progress/manager.d.ts.map +0 -1
- package/dist/progress/manager.js.map +0 -1
- package/dist/reporters/registry.cjs.map +0 -1
- package/dist/reporters/registry.d.cts.map +0 -1
- package/dist/reporters/registry.d.ts.map +0 -1
- package/dist/reporters/registry.js.map +0 -1
- package/dist/storage/history.cjs.map +0 -1
- package/dist/storage/history.d.cts.map +0 -1
- package/dist/storage/history.d.ts.map +0 -1
- package/dist/storage/history.js.map +0 -1
- /package/src/{storage/history.ts → services/history-storage.ts} +0 -0
- /package/src/{progress/manager.ts → services/progress-manager.ts} +0 -0
package/src/core/engine.ts
CHANGED
|
@@ -6,12 +6,18 @@
|
|
|
6
6
|
* architecture.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
import { randomBytes } from 'node:crypto';
|
|
10
|
+
import { relative as pathRelative } from 'node:path';
|
|
11
|
+
|
|
9
12
|
import type {
|
|
13
|
+
BaselineSummaryData,
|
|
10
14
|
BenchmarkDefinition,
|
|
11
15
|
BenchmarkEngine,
|
|
12
16
|
BenchmarkRun,
|
|
13
17
|
BenchmarkSuite,
|
|
14
18
|
BenchmarkTask,
|
|
19
|
+
Budget,
|
|
20
|
+
BudgetSummary,
|
|
15
21
|
CiInfo,
|
|
16
22
|
ConfigurationManager,
|
|
17
23
|
EnvironmentInfo,
|
|
@@ -24,7 +30,9 @@ import type {
|
|
|
24
30
|
Reporter,
|
|
25
31
|
ReporterRegistry,
|
|
26
32
|
RunConfiguration,
|
|
33
|
+
RunId,
|
|
27
34
|
SuiteResult,
|
|
35
|
+
TaskId,
|
|
28
36
|
TaskResult,
|
|
29
37
|
ValidationError,
|
|
30
38
|
ValidationResult,
|
|
@@ -33,11 +41,15 @@ import type {
|
|
|
33
41
|
|
|
34
42
|
import {
|
|
35
43
|
BenchmarkExecutionError,
|
|
44
|
+
BudgetExceededError,
|
|
36
45
|
FileDiscoveryError,
|
|
37
46
|
SchemaValidationError,
|
|
38
47
|
SetupError,
|
|
39
48
|
StructureValidationError,
|
|
40
49
|
} from '../errors/index.js';
|
|
50
|
+
import { BaselineStorageService } from '../services/baseline-storage.js';
|
|
51
|
+
import { BudgetEvaluator } from '../services/budget-evaluator.js';
|
|
52
|
+
import { createRunId, createTaskId } from '../types/index.js';
|
|
41
53
|
|
|
42
54
|
/**
|
|
43
55
|
* Dependencies required by the BenchmarkEngine
|
|
@@ -76,6 +88,20 @@ export abstract class ModestBenchEngine implements BenchmarkEngine {
|
|
|
76
88
|
this.progressManager = dependencies.progressManager;
|
|
77
89
|
}
|
|
78
90
|
|
|
91
|
+
/**
|
|
92
|
+
* Generate a unique run ID
|
|
93
|
+
*
|
|
94
|
+
* Uses crypto.randomBytes for cryptographically random 7-character IDs.
|
|
95
|
+
* Format: 7 lowercase alphanumeric characters (e.g., "k3m9x2p")
|
|
96
|
+
*/
|
|
97
|
+
private static generateRunId(this: void): RunId {
|
|
98
|
+
// Generate random bytes, convert to hex, then to base36, take first 7 chars
|
|
99
|
+
const hex = randomBytes(4).toString('hex');
|
|
100
|
+
const num = parseInt(hex, 16);
|
|
101
|
+
const id = num.toString(36).padStart(7, '0').substring(0, 7);
|
|
102
|
+
return createRunId(id);
|
|
103
|
+
}
|
|
104
|
+
|
|
79
105
|
/**
|
|
80
106
|
* Discover benchmark files matching the pattern(s)
|
|
81
107
|
*/
|
|
@@ -134,7 +160,7 @@ export abstract class ModestBenchEngine implements BenchmarkEngine {
|
|
|
134
160
|
}
|
|
135
161
|
|
|
136
162
|
// 4. Initialize progress tracking
|
|
137
|
-
const runId =
|
|
163
|
+
const runId = ModestBenchEngine.generateRunId();
|
|
138
164
|
|
|
139
165
|
// Pre-calculate total tasks for progress tracking
|
|
140
166
|
let totalTasks = 0;
|
|
@@ -210,9 +236,9 @@ export abstract class ModestBenchEngine implements BenchmarkEngine {
|
|
|
210
236
|
|
|
211
237
|
// Register progress callbacks with reporters that support them
|
|
212
238
|
for (const reporter of reporters) {
|
|
213
|
-
if (
|
|
239
|
+
if (reporter.onProgress) {
|
|
214
240
|
this.progressManager.onProgress((state) => {
|
|
215
|
-
void reporter.onProgress(state);
|
|
241
|
+
void reporter.onProgress?.(state);
|
|
216
242
|
});
|
|
217
243
|
}
|
|
218
244
|
}
|
|
@@ -225,12 +251,17 @@ export abstract class ModestBenchEngine implements BenchmarkEngine {
|
|
|
225
251
|
|
|
226
252
|
for (const filePath of files) {
|
|
227
253
|
try {
|
|
228
|
-
//
|
|
229
|
-
|
|
254
|
+
// Normalize file path to be relative to cwd
|
|
255
|
+
const cwd = config.cwd || process.cwd();
|
|
256
|
+
const relativePath = pathRelative(cwd, filePath);
|
|
257
|
+
|
|
258
|
+
// Call reporter onFileStart with relative path
|
|
259
|
+
await this.callReporters(reporters, 'onFileStart', relativePath);
|
|
230
260
|
|
|
231
261
|
const fileResult = await this.executeBenchmarkFile(
|
|
232
262
|
filePath,
|
|
233
263
|
mergedConfig,
|
|
264
|
+
cwd,
|
|
234
265
|
reporters,
|
|
235
266
|
signal,
|
|
236
267
|
);
|
|
@@ -244,6 +275,16 @@ export abstract class ModestBenchEngine implements BenchmarkEngine {
|
|
|
244
275
|
currentFile: filePath,
|
|
245
276
|
filesCompleted: fileResults.length,
|
|
246
277
|
});
|
|
278
|
+
|
|
279
|
+
// Check for bail: stop execution if any task failed
|
|
280
|
+
if (mergedConfig.bail) {
|
|
281
|
+
const hasFailedTask = fileResult.suites.some((suite) =>
|
|
282
|
+
suite.tasks.some((task) => task.error),
|
|
283
|
+
);
|
|
284
|
+
if (hasFailedTask) {
|
|
285
|
+
break;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
247
288
|
} catch (error) {
|
|
248
289
|
const fileError =
|
|
249
290
|
error instanceof Error ? error : new Error(String(error));
|
|
@@ -265,6 +306,11 @@ export abstract class ModestBenchEngine implements BenchmarkEngine {
|
|
|
265
306
|
|
|
266
307
|
// Call reporter onFileEnd for error case
|
|
267
308
|
await this.callReporters(reporters, 'onFileEnd', errorResult);
|
|
309
|
+
|
|
310
|
+
// Check bail flag for file-level errors
|
|
311
|
+
if (mergedConfig.bail) {
|
|
312
|
+
break;
|
|
313
|
+
}
|
|
268
314
|
}
|
|
269
315
|
}
|
|
270
316
|
|
|
@@ -300,10 +346,103 @@ export abstract class ModestBenchEngine implements BenchmarkEngine {
|
|
|
300
346
|
}
|
|
301
347
|
|
|
302
348
|
const overallMean = totalOperations > 0 ? totalTime / totalOperations : 0;
|
|
349
|
+
// Evaluate budgets if configured
|
|
350
|
+
let budgetSummary: BudgetSummary | undefined;
|
|
351
|
+
|
|
352
|
+
if (config.budgets && Object.keys(config.budgets).length > 0) {
|
|
353
|
+
const evaluator = new BudgetEvaluator();
|
|
354
|
+
const baselineStorage = new BaselineStorageService(process.cwd());
|
|
355
|
+
|
|
356
|
+
// Collect task results
|
|
357
|
+
const taskResults = new Map<TaskId, TaskResult>();
|
|
358
|
+
|
|
359
|
+
for (const file of fileResults) {
|
|
360
|
+
for (const suite of file.suites) {
|
|
361
|
+
for (const task of suite.tasks) {
|
|
362
|
+
if (!task.error) {
|
|
363
|
+
// file.filePath is already relative to cwd
|
|
364
|
+
const taskId = createTaskId(
|
|
365
|
+
file.filePath,
|
|
366
|
+
suite.name,
|
|
367
|
+
task.name,
|
|
368
|
+
);
|
|
369
|
+
taskResults.set(taskId, task);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// Load baseline data if needed for relative budgets
|
|
376
|
+
let baselineData: Map<TaskId, BaselineSummaryData> | undefined;
|
|
377
|
+
|
|
378
|
+
// Check if any budgets use relative thresholds
|
|
379
|
+
const hasRelativeBudgets = Object.values(config.budgets).some(
|
|
380
|
+
(budget) => (budget as Budget).relative,
|
|
381
|
+
);
|
|
382
|
+
|
|
383
|
+
if (hasRelativeBudgets) {
|
|
384
|
+
const baselineName =
|
|
385
|
+
config.baseline || (await baselineStorage.getDefault());
|
|
386
|
+
|
|
387
|
+
if (baselineName) {
|
|
388
|
+
const baseline = await baselineStorage.getBaseline(baselineName);
|
|
389
|
+
|
|
390
|
+
if (baseline) {
|
|
391
|
+
// Cast keys to TaskId since they come from validated baseline storage
|
|
392
|
+
baselineData = new Map(
|
|
393
|
+
Object.entries(baseline.summary) as [
|
|
394
|
+
TaskId,
|
|
395
|
+
BaselineSummaryData,
|
|
396
|
+
][],
|
|
397
|
+
);
|
|
398
|
+
} else {
|
|
399
|
+
console.warn(
|
|
400
|
+
`Warning: Baseline "${baselineName}" not found. Relative budgets will be skipped.`,
|
|
401
|
+
);
|
|
402
|
+
}
|
|
403
|
+
} else {
|
|
404
|
+
console.warn(
|
|
405
|
+
'Warning: Relative budgets configured but no baseline specified. Relative budgets will be skipped.',
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// Evaluate budgets
|
|
411
|
+
budgetSummary = evaluator.evaluateRun(
|
|
412
|
+
config.budgets as Record<string, Budget>,
|
|
413
|
+
taskResults,
|
|
414
|
+
baselineData,
|
|
415
|
+
);
|
|
416
|
+
|
|
417
|
+
// Notify reporters of budget results
|
|
418
|
+
for (const reporter of reporters) {
|
|
419
|
+
if (reporter.onBudgetResult) {
|
|
420
|
+
await reporter.onBudgetResult(budgetSummary);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// Handle budget failures based on budgetMode
|
|
425
|
+
if (budgetSummary.failed > 0) {
|
|
426
|
+
const mode = config.budgetMode || 'fail';
|
|
427
|
+
|
|
428
|
+
if (mode === 'fail') {
|
|
429
|
+
throw new BudgetExceededError(
|
|
430
|
+
`${budgetSummary.failed} of ${budgetSummary.total} budget(s) exceeded`,
|
|
431
|
+
budgetSummary,
|
|
432
|
+
);
|
|
433
|
+
} else if (mode === 'warn') {
|
|
434
|
+
console.warn(
|
|
435
|
+
`Warning: ${budgetSummary.failed} of ${budgetSummary.total} budget(s) exceeded`,
|
|
436
|
+
);
|
|
437
|
+
}
|
|
438
|
+
// mode === 'report': just include in output, don't fail
|
|
439
|
+
}
|
|
440
|
+
}
|
|
303
441
|
|
|
304
442
|
const endTime = new Date();
|
|
305
443
|
const finalRun: BenchmarkRun = {
|
|
306
444
|
...initialRun,
|
|
445
|
+
budgetSummary,
|
|
307
446
|
duration: endTime.getTime() - startTime.getTime(),
|
|
308
447
|
endTime,
|
|
309
448
|
files: fileResults,
|
|
@@ -487,6 +626,7 @@ export abstract class ModestBenchEngine implements BenchmarkEngine {
|
|
|
487
626
|
private async executeBenchmarkFile(
|
|
488
627
|
filePath: string,
|
|
489
628
|
config: ModestBenchConfig,
|
|
629
|
+
cwd: string,
|
|
490
630
|
reporters: Reporter[] = [],
|
|
491
631
|
signal?: AbortSignal,
|
|
492
632
|
): Promise<FileResult> {
|
|
@@ -541,11 +681,14 @@ export abstract class ModestBenchEngine implements BenchmarkEngine {
|
|
|
541
681
|
|
|
542
682
|
const endTime = new Date();
|
|
543
683
|
|
|
684
|
+
// Normalize file path to be relative to cwd
|
|
685
|
+
const relativePath = pathRelative(cwd, filePath);
|
|
686
|
+
|
|
544
687
|
return {
|
|
545
688
|
config: benchmarkDef.config,
|
|
546
689
|
duration: endTime.getTime() - startTime.getTime(),
|
|
547
690
|
endTime,
|
|
548
|
-
filePath,
|
|
691
|
+
filePath: relativePath,
|
|
549
692
|
startTime,
|
|
550
693
|
suites: suiteResults,
|
|
551
694
|
};
|
|
@@ -554,11 +697,14 @@ export abstract class ModestBenchEngine implements BenchmarkEngine {
|
|
|
554
697
|
const executionError =
|
|
555
698
|
error instanceof Error ? error : new Error(String(error));
|
|
556
699
|
|
|
700
|
+
// Normalize file path to be relative to cwd
|
|
701
|
+
const relativePath = pathRelative(cwd, filePath);
|
|
702
|
+
|
|
557
703
|
return {
|
|
558
704
|
duration: endTime.getTime() - startTime.getTime(),
|
|
559
705
|
endTime,
|
|
560
706
|
error: executionError,
|
|
561
|
-
filePath,
|
|
707
|
+
filePath: relativePath,
|
|
562
708
|
startTime,
|
|
563
709
|
suites: [],
|
|
564
710
|
};
|
|
@@ -695,13 +841,6 @@ export abstract class ModestBenchEngine implements BenchmarkEngine {
|
|
|
695
841
|
}
|
|
696
842
|
}
|
|
697
843
|
|
|
698
|
-
/**
|
|
699
|
-
* Generate a unique run ID
|
|
700
|
-
*/
|
|
701
|
-
private generateRunId(): string {
|
|
702
|
-
return `run-${Date.now()}-${Math.random().toString(36).substring(2, 15)}`;
|
|
703
|
-
}
|
|
704
|
-
|
|
705
844
|
/**
|
|
706
845
|
* Get CI/CD information if available
|
|
707
846
|
*/
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { extname, isAbsolute, join, resolve } from 'node:path';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Resolves the final output path for a reporter
|
|
5
|
+
*
|
|
6
|
+
* @param outputDir - Optional output directory from --output flag
|
|
7
|
+
* @param outputFile - Optional output filename from --output-file flag
|
|
8
|
+
* @param defaultFilename - Default filename to use if none specified
|
|
9
|
+
* @returns Resolved output path, or undefined if no output to file requested
|
|
10
|
+
*/
|
|
11
|
+
export const resolveOutputPath = (
|
|
12
|
+
outputDir?: string,
|
|
13
|
+
outputFile?: string,
|
|
14
|
+
defaultFilename?: string,
|
|
15
|
+
): string | undefined => {
|
|
16
|
+
// If outputFile is provided
|
|
17
|
+
if (outputFile) {
|
|
18
|
+
// If outputFile is absolute, use as-is
|
|
19
|
+
if (isAbsolute(outputFile)) {
|
|
20
|
+
return outputFile;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// If outputDir specified, join them
|
|
24
|
+
if (outputDir) {
|
|
25
|
+
return join(outputDir, outputFile);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Otherwise, resolve relative to cwd
|
|
29
|
+
return resolve(process.cwd(), outputFile);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// If outputDir looks like a file (has extension), treat it as a file path
|
|
33
|
+
// This handles cases like: --output results.csv
|
|
34
|
+
if (outputDir && extname(outputDir)) {
|
|
35
|
+
return isAbsolute(outputDir)
|
|
36
|
+
? outputDir
|
|
37
|
+
: resolve(process.cwd(), outputDir);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Fall back to default behavior (outputDir is a directory)
|
|
41
|
+
if (outputDir && defaultFilename) {
|
|
42
|
+
return join(outputDir, defaultFilename);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return undefined;
|
|
46
|
+
};
|
package/src/errors/base.ts
CHANGED
|
@@ -143,10 +143,19 @@ export const isModestBenchError = (
|
|
|
143
143
|
error: unknown,
|
|
144
144
|
): error is ModestBenchError => {
|
|
145
145
|
return (
|
|
146
|
-
|
|
147
|
-
error !== null &&
|
|
146
|
+
isError(error) &&
|
|
148
147
|
'code' in error &&
|
|
149
148
|
typeof (error as { code: unknown }).code === 'string' &&
|
|
150
149
|
(error as { code: string }).code.startsWith('ERR_MB_')
|
|
151
150
|
);
|
|
152
151
|
};
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Type guard to check if an error is a standard Error
|
|
155
|
+
*
|
|
156
|
+
* @param error - The error to check
|
|
157
|
+
* @returns `true` if the error is an `Error`
|
|
158
|
+
*/
|
|
159
|
+
export const isError = (error: unknown): error is Error => {
|
|
160
|
+
return error instanceof Error;
|
|
161
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Budget-related errors
|
|
3
|
+
*
|
|
4
|
+
* Errors that occur during budget evaluation and enforcement.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { BudgetSummary } from '../types/core.js';
|
|
8
|
+
|
|
9
|
+
import { ModestBenchError } from './base.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Error thrown when performance budgets are exceeded
|
|
13
|
+
*
|
|
14
|
+
* Thrown when budget evaluation fails and budgetMode is set to 'fail'. Contains
|
|
15
|
+
* the full budget summary for detailed reporting.
|
|
16
|
+
*/
|
|
17
|
+
export class BudgetExceededError extends ModestBenchError {
|
|
18
|
+
/**
|
|
19
|
+
* Budget summary containing details of all violations
|
|
20
|
+
*/
|
|
21
|
+
public readonly budgetSummary: BudgetSummary;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Error code for budget exceeded errors
|
|
25
|
+
*/
|
|
26
|
+
readonly code = 'ERR_MB_BUDGET_EXCEEDED';
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Create a new budget exceeded error
|
|
30
|
+
*
|
|
31
|
+
* @param message - Human-readable error message
|
|
32
|
+
* @param budgetSummary - Budget evaluation results
|
|
33
|
+
*/
|
|
34
|
+
constructor(message: string, budgetSummary: BudgetSummary) {
|
|
35
|
+
super(message);
|
|
36
|
+
this.budgetSummary = budgetSummary;
|
|
37
|
+
}
|
|
38
|
+
}
|
package/src/errors/index.ts
CHANGED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base Formatter Interface
|
|
3
|
+
*
|
|
4
|
+
* Defines the contract for history command formatters. Each formatter
|
|
5
|
+
* transforms processed data into human-readable or machine-readable output.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Formatter interface for history command output
|
|
10
|
+
*
|
|
11
|
+
* @template TData - The data type this formatter accepts
|
|
12
|
+
*/
|
|
13
|
+
export interface HistoryFormatter<TData> {
|
|
14
|
+
/**
|
|
15
|
+
* Format data as CSV (optional, not all commands support CSV)
|
|
16
|
+
*/
|
|
17
|
+
formatCsv?(data: TData): string;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Format data for human-readable terminal output
|
|
21
|
+
*/
|
|
22
|
+
formatHuman(data: TData): string;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Format data as JSON
|
|
26
|
+
*/
|
|
27
|
+
formatJson(data: TData): string;
|
|
28
|
+
}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compare Formatter
|
|
3
|
+
*
|
|
4
|
+
* Formats benchmark run comparison results in human and JSON formats.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { CompareResult } from '../../services/history/models.js';
|
|
8
|
+
import type { HistoryFormatter } from './base.js';
|
|
9
|
+
|
|
10
|
+
import { colorize } from '../../utils/ansi.js';
|
|
11
|
+
import { ansiChars } from '../../utils/ansi.js';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Formatter for history compare command
|
|
15
|
+
*/
|
|
16
|
+
export class HistoryCompareFormatter
|
|
17
|
+
implements HistoryFormatter<CompareResult>
|
|
18
|
+
{
|
|
19
|
+
/**
|
|
20
|
+
* Format as human-readable comparison
|
|
21
|
+
*/
|
|
22
|
+
formatHuman(data: CompareResult): string {
|
|
23
|
+
const lines: string[] = [];
|
|
24
|
+
|
|
25
|
+
lines.push(colorize('brightMagenta', colorize('bold', 'Comparing runs:')));
|
|
26
|
+
lines.push(
|
|
27
|
+
` ${colorize('brightCyan', ansiChars.bullet)} ${colorize('brightWhite', colorize('bold', 'Run 1'))} ${colorize('dim', data.run1.id)} (${colorize('white', data.run1.startTime.toLocaleString())})`,
|
|
28
|
+
);
|
|
29
|
+
lines.push(
|
|
30
|
+
` ${colorize('brightCyan', ansiChars.bullet)} ${colorize('brightWhite', colorize('bold', 'Run 2'))} ${colorize('dim', data.run2.id)} (${colorize('white', data.run2.startTime.toLocaleString())})`,
|
|
31
|
+
);
|
|
32
|
+
lines.push('');
|
|
33
|
+
|
|
34
|
+
lines.push(colorize('cyan', 'Summary comparison:'));
|
|
35
|
+
lines.push('');
|
|
36
|
+
lines.push(
|
|
37
|
+
` ${colorize('dim', ansiChars.smallSquare)} Files: ${colorize('brightWhite', String(data.run1.summary.totalFiles))} vs ${colorize('brightWhite', String(data.run2.summary.totalFiles))}`,
|
|
38
|
+
);
|
|
39
|
+
lines.push(
|
|
40
|
+
` ${colorize('dim', ansiChars.smallSquare)} Tasks: ${colorize('brightWhite', String(data.run1.summary.totalTasks))} vs ${colorize('brightWhite', String(data.run2.summary.totalTasks))}`,
|
|
41
|
+
);
|
|
42
|
+
lines.push(
|
|
43
|
+
` ${colorize('dim', ansiChars.smallSquare)} Passed: ${colorize('brightCyan', String(data.run1.summary.passedTasks))} vs ${colorize('brightCyan', String(data.run2.summary.passedTasks))}`,
|
|
44
|
+
);
|
|
45
|
+
lines.push(
|
|
46
|
+
` ${colorize('dim', ansiChars.smallSquare)} Failed: ${colorize('brightRed', colorize('bold', String(data.run1.summary.failedTasks)))} vs ${colorize('brightRed', colorize('bold', String(data.run2.summary.failedTasks)))}`,
|
|
47
|
+
);
|
|
48
|
+
lines.push('');
|
|
49
|
+
|
|
50
|
+
// Detailed task comparison
|
|
51
|
+
if (data.tasksInBoth.length > 0) {
|
|
52
|
+
lines.push(colorize('cyan', 'Task-by-task comparison:'));
|
|
53
|
+
lines.push('');
|
|
54
|
+
|
|
55
|
+
for (const comparison of data.tasksInBoth) {
|
|
56
|
+
const mean1 = comparison.run1!.mean / 1000000; // Convert to ms
|
|
57
|
+
const mean2 = comparison.run2!.mean / 1000000;
|
|
58
|
+
const changeSign = comparison.percentChange >= 0 ? '+' : '';
|
|
59
|
+
const changeStr = `${changeSign}${comparison.percentChange.toFixed(1)}%`;
|
|
60
|
+
|
|
61
|
+
lines.push(
|
|
62
|
+
` ${colorize('brightWhite', `${comparison.suite} › ${comparison.task}`)}`,
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
// Mean - highlight higher (slower/worse) number
|
|
66
|
+
const meanHigher = mean2 > mean1;
|
|
67
|
+
const mean1Str = meanHigher
|
|
68
|
+
? colorize('magenta', `${mean1.toFixed(3)}ms`)
|
|
69
|
+
: colorize('brightMagenta', `${mean1.toFixed(3)}ms`);
|
|
70
|
+
const mean2Str = meanHigher
|
|
71
|
+
? colorize('brightMagenta', `${mean2.toFixed(3)}ms`)
|
|
72
|
+
: colorize('magenta', `${mean2.toFixed(3)}ms`);
|
|
73
|
+
lines.push(
|
|
74
|
+
` ${colorize('dim', ansiChars.bullet)} ${colorize('white', 'Mean:')} ${mean1Str} ${colorize('dim', '→')} ${mean2Str} ${colorize('dim', `(${colorize('white', changeStr)}`)}`,
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
// Min - highlight higher number
|
|
78
|
+
const min1 = comparison.run1!.min / 1000000;
|
|
79
|
+
const min2 = comparison.run2!.min / 1000000;
|
|
80
|
+
const minHigher = min2 > min1;
|
|
81
|
+
const min1Str = minHigher
|
|
82
|
+
? colorize('magenta', `${min1.toFixed(3)}ms`)
|
|
83
|
+
: colorize('brightMagenta', `${min1.toFixed(3)}ms`);
|
|
84
|
+
const min2Str = minHigher
|
|
85
|
+
? colorize('brightMagenta', `${min2.toFixed(3)}ms`)
|
|
86
|
+
: colorize('magenta', `${min2.toFixed(3)}ms`);
|
|
87
|
+
lines.push(
|
|
88
|
+
` ${colorize('dim', ansiChars.bullet)} ${colorize('white', 'Min:')} ${min1Str} ${colorize('dim', '→')} ${min2Str}`,
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
// Max - highlight higher number
|
|
92
|
+
const max1 = comparison.run1!.max / 1000000;
|
|
93
|
+
const max2 = comparison.run2!.max / 1000000;
|
|
94
|
+
const maxHigher = max2 > max1;
|
|
95
|
+
const max1Str = maxHigher
|
|
96
|
+
? colorize('magenta', `${max1.toFixed(3)}ms`)
|
|
97
|
+
: colorize('brightMagenta', `${max1.toFixed(3)}ms`);
|
|
98
|
+
const max2Str = maxHigher
|
|
99
|
+
? colorize('brightMagenta', `${max2.toFixed(3)}ms`)
|
|
100
|
+
: colorize('magenta', `${max2.toFixed(3)}ms`);
|
|
101
|
+
lines.push(
|
|
102
|
+
` ${colorize('dim', ansiChars.bullet)} ${colorize('white', 'Max:')} ${max1Str} ${colorize('dim', '→')} ${max2Str}`,
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
// Iterations - highlight higher number
|
|
106
|
+
const iter1 = comparison.run1!.iterations;
|
|
107
|
+
const iter2 = comparison.run2!.iterations;
|
|
108
|
+
const iterHigher = iter2 > iter1;
|
|
109
|
+
const iter1Str = iterHigher
|
|
110
|
+
? colorize('brightWhite', String(iter1))
|
|
111
|
+
: colorize('bold', colorize('brightWhite', String(iter1)));
|
|
112
|
+
const iter2Str = iterHigher
|
|
113
|
+
? colorize('bold', colorize('brightWhite', String(iter2)))
|
|
114
|
+
: colorize('brightWhite', String(iter2));
|
|
115
|
+
lines.push(
|
|
116
|
+
` ${colorize('dim', ansiChars.bullet)} ${colorize('white', 'Iterations:')} ${iter1Str} ${colorize('dim', 'vs')} ${iter2Str}`,
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
// CV (Coefficient of Variation) - shows measurement consistency
|
|
120
|
+
const cv1 = comparison.run1!.cv * 100;
|
|
121
|
+
const cv2 = comparison.run2!.cv * 100;
|
|
122
|
+
const cvHigher = cv2 > cv1;
|
|
123
|
+
const cv1Str = cvHigher
|
|
124
|
+
? colorize('magenta', `${cv1.toFixed(2)}%`)
|
|
125
|
+
: colorize('brightMagenta', `${cv1.toFixed(2)}%`);
|
|
126
|
+
const cv2Str = cvHigher
|
|
127
|
+
? colorize('brightMagenta', `${cv2.toFixed(2)}%`)
|
|
128
|
+
: colorize('magenta', `${cv2.toFixed(2)}%`);
|
|
129
|
+
lines.push(
|
|
130
|
+
` ${colorize('dim', ansiChars.bullet)} ${colorize('white', 'CV:')} ${cv1Str} ${colorize('dim', '→')} ${cv2Str}`,
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
lines.push('');
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (data.tasksOnlyInRun1.length > 0) {
|
|
138
|
+
lines.push(
|
|
139
|
+
colorize(
|
|
140
|
+
'cyan',
|
|
141
|
+
`Tasks only in run 1 (${data.tasksOnlyInRun1.length}):`,
|
|
142
|
+
),
|
|
143
|
+
);
|
|
144
|
+
for (const task of data.tasksOnlyInRun1) {
|
|
145
|
+
lines.push(
|
|
146
|
+
` ${colorize('dim', ansiChars.bullet)} ${colorize('brightWhite', `${task.suite} › ${task.task}`)}`,
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
lines.push('');
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (data.tasksOnlyInRun2.length > 0) {
|
|
153
|
+
lines.push(
|
|
154
|
+
colorize(
|
|
155
|
+
'cyan',
|
|
156
|
+
`Tasks only in run 2 (${data.tasksOnlyInRun2.length}):`,
|
|
157
|
+
),
|
|
158
|
+
);
|
|
159
|
+
for (const task of data.tasksOnlyInRun2) {
|
|
160
|
+
lines.push(
|
|
161
|
+
` ${colorize('dim', ansiChars.bullet)} ${colorize('brightWhite', `${task.suite} › ${task.task}`)}`,
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
lines.push('');
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return lines.join('\n');
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Format as JSON
|
|
172
|
+
*/
|
|
173
|
+
formatJson(data: CompareResult): string {
|
|
174
|
+
return JSON.stringify(
|
|
175
|
+
{
|
|
176
|
+
run1: data.run1,
|
|
177
|
+
run2: data.run2,
|
|
178
|
+
taskComparisons: data.tasksInBoth,
|
|
179
|
+
tasksOnlyInRun1: data.tasksOnlyInRun1,
|
|
180
|
+
tasksOnlyInRun2: data.tasksOnlyInRun2,
|
|
181
|
+
},
|
|
182
|
+
null,
|
|
183
|
+
2,
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
}
|