@sdeverywhere/check-core 0.1.0 → 0.1.1

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/dist/index.cjs CHANGED
@@ -1,26 +1,9 @@
1
1
  var __create = Object.create;
2
2
  var __defProp = Object.defineProperty;
3
- var __defProps = Object.defineProperties;
4
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
6
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
- var __getOwnPropSymbols = Object.getOwnPropertySymbols;
8
5
  var __getProtoOf = Object.getPrototypeOf;
9
6
  var __hasOwnProp = Object.prototype.hasOwnProperty;
10
- var __propIsEnum = Object.prototype.propertyIsEnumerable;
11
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
12
- var __spreadValues = (a, b) => {
13
- for (var prop in b || (b = {}))
14
- if (__hasOwnProp.call(b, prop))
15
- __defNormalProp(a, prop, b[prop]);
16
- if (__getOwnPropSymbols)
17
- for (var prop of __getOwnPropSymbols(b)) {
18
- if (__propIsEnum.call(b, prop))
19
- __defNormalProp(a, prop, b[prop]);
20
- }
21
- return a;
22
- };
23
- var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
24
7
  var __export = (target, all) => {
25
8
  for (var name in all)
26
9
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -33,110 +16,34 @@ var __copyProps = (to, from, except, desc) => {
33
16
  }
34
17
  return to;
35
18
  };
36
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod));
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
21
+ mod
22
+ ));
37
23
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
38
24
 
39
25
  // src/index.ts
40
26
  var src_exports = {};
41
27
  __export(src_exports, {
42
28
  CheckDataCoordinator: () => CheckDataCoordinator,
43
- CompareDataCoordinator: () => CompareDataCoordinator,
44
- DatasetManager: () => DatasetManager,
29
+ ComparisonDataCoordinator: () => ComparisonDataCoordinator,
45
30
  PerfRunner: () => PerfRunner,
46
31
  PerfStats: () => PerfStats,
47
- ScenarioManager: () => ScenarioManager,
48
- allInputsAtPositionScenario: () => allInputsAtPositionScenario,
32
+ categorizeComparisonTestSummaries: () => categorizeComparisonTestSummaries,
49
33
  checkReportFromSummary: () => checkReportFromSummary,
50
34
  checkSummaryFromReport: () => checkSummaryFromReport,
51
- compareDatasets: () => compareDatasets,
52
- compareSummaryFromReport: () => compareSummaryFromReport,
35
+ comparisonSummaryFromReport: () => comparisonSummaryFromReport,
53
36
  createConfig: () => createConfig,
54
37
  datasetMessage: () => datasetMessage,
55
38
  diffDatasets: () => diffDatasets,
56
39
  diffGraphs: () => diffGraphs,
57
- inputAtPositionScenario: () => inputAtPositionScenario,
58
- inputAtValueScenario: () => inputAtValueScenario,
59
- matrixScenarios: () => matrixScenarios,
60
- positionSetting: () => positionSetting,
61
40
  predicateMessage: () => predicateMessage,
62
41
  runSuite: () => runSuite,
63
42
  scenarioMessage: () => scenarioMessage,
64
- settingsScenario: () => settingsScenario,
65
- suiteSummaryFromReport: () => suiteSummaryFromReport,
66
- valueSetting: () => valueSetting
43
+ suiteSummaryFromReport: () => suiteSummaryFromReport
67
44
  });
68
45
  module.exports = __toCommonJS(src_exports);
69
46
 
70
- // src/_shared/scenario.ts
71
- var import_assert_never = require("assert-never");
72
- function positionSetting(inputVarId, position) {
73
- return {
74
- kind: "position",
75
- inputVarId,
76
- position
77
- };
78
- }
79
- function valueSetting(inputVarId, value) {
80
- return {
81
- kind: "value",
82
- inputVarId,
83
- value
84
- };
85
- }
86
- function settingsScenario(key, groupKey, settings) {
87
- return {
88
- kind: "settings",
89
- key,
90
- groupKey,
91
- settings
92
- };
93
- }
94
- function inputAtPositionScenario(inputVarId, groupKey, position) {
95
- const key = keyForInputAtPosition(`input${inputVarId}`, position);
96
- return settingsScenario(key, groupKey, [positionSetting(inputVarId, position)]);
97
- }
98
- function inputAtValueScenario(inputVarId, groupKey, value) {
99
- const key = keyForInputAtValue(`input${inputVarId}`, value);
100
- return settingsScenario(key, groupKey, [valueSetting(inputVarId, value)]);
101
- }
102
- function allInputsAtPositionScenario(position) {
103
- return {
104
- kind: "all-inputs",
105
- key: keyForInputAtPosition("all_inputs", position),
106
- groupKey: "all_inputs",
107
- position
108
- };
109
- }
110
- function matrixScenarios(inputVarIds) {
111
- const scenarios = [];
112
- scenarios.push(allInputsAtPositionScenario("at-default"));
113
- scenarios.push(allInputsAtPositionScenario("at-minimum"));
114
- scenarios.push(allInputsAtPositionScenario("at-maximum"));
115
- for (const inputVarId of inputVarIds) {
116
- scenarios.push(inputAtPositionScenario(inputVarId, inputVarId, "at-minimum"));
117
- scenarios.push(inputAtPositionScenario(inputVarId, inputVarId, "at-maximum"));
118
- }
119
- return scenarios;
120
- }
121
- function keyForInputPosition(position) {
122
- switch (position) {
123
- case "at-default":
124
- return "default";
125
- case "at-minimum":
126
- return "min";
127
- case "at-maximum":
128
- return "max";
129
- default:
130
- (0, import_assert_never.assertNever)(position);
131
- }
132
- }
133
- function keyForInputAtPosition(inputKey, position) {
134
- return `${inputKey}_at_${keyForInputPosition(position)}`;
135
- }
136
- function keyForInputAtValue(inputKey, value) {
137
- return `${inputKey}_at_${value}`;
138
- }
139
-
140
47
  // src/_shared/task-queue.ts
141
48
  var TaskQueue = class {
142
49
  constructor(processor) {
@@ -223,7 +130,7 @@ var CheckDataCoordinator = class {
223
130
  this.bundleModel = bundleModel;
224
131
  this.taskQueue = new TaskQueue({
225
132
  process: async (request) => {
226
- const result = await this.bundleModel.getDatasetsForScenario(request.scenario, [request.datasetKey]);
133
+ const result = await this.bundleModel.getDatasetsForScenario(request.scenarioSpec, [request.datasetKey]);
227
134
  const dataset = result.datasetMap.get(request.datasetKey);
228
135
  return {
229
136
  dataset
@@ -231,9 +138,9 @@ var CheckDataCoordinator = class {
231
138
  }
232
139
  });
233
140
  }
234
- requestDataset(requestKey, scenario, datasetKey, onResponse) {
141
+ requestDataset(requestKey, scenarioSpec, datasetKey, onResponse) {
235
142
  const request = {
236
- scenario,
143
+ scenarioSpec,
237
144
  datasetKey
238
145
  };
239
146
  this.taskQueue.addTask(requestKey, request, (response) => {
@@ -246,10 +153,10 @@ var CheckDataCoordinator = class {
246
153
  };
247
154
 
248
155
  // src/check/check-report.ts
249
- var import_assert_never3 = __toESM(require("assert-never"), 1);
156
+ var import_assert_never2 = __toESM(require("assert-never"), 1);
250
157
 
251
158
  // src/check/check-predicate.ts
252
- var import_assert_never2 = __toESM(require("assert-never"), 1);
159
+ var import_assert_never = __toESM(require("assert-never"), 1);
253
160
  function symbolForPredicateOp(op) {
254
161
  switch (op) {
255
162
  case "gt":
@@ -265,7 +172,7 @@ function symbolForPredicateOp(op) {
265
172
  case "approx":
266
173
  return "\u2248";
267
174
  default:
268
- (0, import_assert_never2.default)(op);
175
+ (0, import_assert_never.default)(op);
269
176
  }
270
177
  }
271
178
 
@@ -279,7 +186,7 @@ function buildCheckReport(checkPlan, checkResults) {
279
186
  const scenarioReports = [];
280
187
  for (const scenarioPlan of testPlan.scenarios) {
281
188
  let scenarioStatus = "passed";
282
- if (scenarioPlan.checkScenario.scenario === void 0) {
189
+ if (scenarioPlan.checkScenario.spec === void 0) {
283
190
  testStatus = "error";
284
191
  scenarioStatus = "error";
285
192
  }
@@ -376,14 +283,14 @@ function predicateReport(predicatePlan, checkKey, result) {
376
283
  };
377
284
  opRef = opDataRef;
378
285
  opValue = `${sym} '${dataRef.dataset.name}'`;
379
- const refScenario = (_b = dataRef.scenario) == null ? void 0 : _b.scenario;
380
- if (!refScenario) {
286
+ const refScenarioSpec = (_b = dataRef.scenario) == null ? void 0 : _b.spec;
287
+ if (!refScenarioSpec) {
381
288
  return;
382
289
  }
383
290
  if (predOp.scenario === "inherit") {
384
291
  opValue += ` (w/ same scenario)`;
385
292
  } else {
386
- if (refScenario.kind === "all-inputs" && refScenario.position === "at-default") {
293
+ if (refScenarioSpec.kind === "all-inputs" && refScenarioSpec.position === "at-default") {
387
294
  opValue += ` (w/ default scenario)`;
388
295
  } else {
389
296
  opValue += ` (w/ configured scenario)`;
@@ -418,7 +325,7 @@ function predicateReport(predicatePlan, checkKey, result) {
418
325
  }
419
326
  function scenarioMessage(scenario, bold) {
420
327
  const checkScenario = scenario.checkScenario;
421
- if (checkScenario.scenario === void 0) {
328
+ if (checkScenario.spec === void 0) {
422
329
  if (checkScenario.error) {
423
330
  switch (checkScenario.error.kind) {
424
331
  case "unknown-input-group":
@@ -426,7 +333,7 @@ function scenarioMessage(scenario, bold) {
426
333
  case "empty-input-group":
427
334
  return `error: input group ${bold(checkScenario.error.name)} is empty`;
428
335
  default:
429
- (0, import_assert_never3.default)(checkScenario.error.kind);
336
+ (0, import_assert_never2.default)(checkScenario.error.kind);
430
337
  }
431
338
  } else {
432
339
  const badInputNames = checkScenario.inputDescs.filter((d) => d.inputVar === void 0).map((d) => bold(d.name));
@@ -443,7 +350,7 @@ function scenarioMessage(scenario, bold) {
443
350
  case "at-maximum":
444
351
  return "maximum";
445
352
  default:
446
- (0, import_assert_never3.default)(position);
353
+ (0, import_assert_never2.default)(position);
447
354
  }
448
355
  }
449
356
  function inputMessage(inputDesc) {
@@ -458,13 +365,13 @@ function scenarioMessage(scenario, bold) {
458
365
  }
459
366
  return msg;
460
367
  }
461
- if (checkScenario.scenario.kind === "all-inputs") {
462
- const position = checkScenario.scenario.position;
368
+ if (checkScenario.spec.kind === "all-inputs") {
369
+ const position = checkScenario.spec.position;
463
370
  return `when ${bold("all inputs")} are at ${bold(positionName(position))}...`;
464
371
  } else if (checkScenario.inputGroupName) {
465
372
  let position = "at-default";
466
- if (checkScenario.scenario.settings[0].kind === "position") {
467
- position = checkScenario.scenario.settings[0].position;
373
+ if (checkScenario.spec.settings[0].kind === "position") {
374
+ position = checkScenario.spec.settings[0].position;
468
375
  }
469
376
  const groupName = checkScenario.inputGroupName;
470
377
  return `when all inputs in ${bold(groupName)} are at ${bold(positionName(position))}...`;
@@ -497,7 +404,7 @@ function predicateMessage(predicate, bold) {
497
404
  case "empty-input-group":
498
405
  return `error: referenced input group ${bold(result.errorInfo.name)} is empty`;
499
406
  default:
500
- (0, import_assert_never3.default)(result.errorInfo.kind);
407
+ (0, import_assert_never2.default)(result.errorInfo.kind);
501
408
  }
502
409
  } else {
503
410
  return `unknown error`;
@@ -1068,7 +975,7 @@ function parseTestYaml(yamlStrings) {
1068
975
  groups.push(group);
1069
976
  }
1070
977
  } else {
1071
- let msg = "Failed to parse YAML tests";
978
+ let msg = "Failed to parse YAML check definitions";
1072
979
  for (const error of validate.errors || []) {
1073
980
  if (error.message) {
1074
981
  msg += `
@@ -1242,9 +1149,12 @@ function actionForPredicate(predicateSpec) {
1242
1149
 
1243
1150
  // src/_shared/combo.ts
1244
1151
  function cartesianProductOf(arr) {
1245
- return arr.reduce((a, b) => {
1246
- return a.map((x) => b.map((y) => x.concat([y]))).reduce((v, w) => v.concat(w), []);
1247
- }, [[]]);
1152
+ return arr.reduce(
1153
+ (a, b) => {
1154
+ return a.map((x) => b.map((y) => x.concat([y]))).reduce((v, w) => v.concat(w), []);
1155
+ },
1156
+ [[]]
1157
+ );
1248
1158
  }
1249
1159
 
1250
1160
  // src/check/check-dataset.ts
@@ -1335,14 +1245,16 @@ function matchByName(modelSpec, datasetName, datasetSource) {
1335
1245
  };
1336
1246
  }
1337
1247
  function matchByGroup(modelSpec, groupName) {
1338
- const groupToMatch = groupName.toLowerCase();
1339
1248
  let matchedGroupName;
1340
1249
  let matchedGroupDatasetKeys;
1341
- for (const [group, datasetKeys] of modelSpec.datasetGroups) {
1342
- if (group.toLowerCase() === groupToMatch) {
1343
- matchedGroupName = group;
1344
- matchedGroupDatasetKeys = datasetKeys;
1345
- break;
1250
+ if (modelSpec.datasetGroups) {
1251
+ const groupToMatch = groupName.toLowerCase();
1252
+ for (const [group, datasetKeys] of modelSpec.datasetGroups) {
1253
+ if (group.toLowerCase() === groupToMatch) {
1254
+ matchedGroupName = group;
1255
+ matchedGroupDatasetKeys = datasetKeys;
1256
+ break;
1257
+ }
1346
1258
  }
1347
1259
  }
1348
1260
  if (matchedGroupName === void 0) {
@@ -1419,6 +1331,65 @@ function matchByType(modelSpec, varTypeToMatch) {
1419
1331
 
1420
1332
  // src/check/check-scenario.ts
1421
1333
  var import_assert_never4 = __toESM(require("assert-never"), 1);
1334
+
1335
+ // src/_shared/scenario-specs.ts
1336
+ var import_assert_never3 = require("assert-never");
1337
+ function positionSetting(inputVarId, position) {
1338
+ return {
1339
+ kind: "position",
1340
+ inputVarId,
1341
+ position
1342
+ };
1343
+ }
1344
+ function valueSetting(inputVarId, value) {
1345
+ return {
1346
+ kind: "value",
1347
+ inputVarId,
1348
+ value
1349
+ };
1350
+ }
1351
+ function inputSettingsSpec(settings) {
1352
+ const uidParts = settings.map((setting) => {
1353
+ switch (setting.kind) {
1354
+ case "position":
1355
+ return `${setting.inputVarId}_at_${keyForInputPosition(setting.position)}`;
1356
+ case "value":
1357
+ return `${setting.inputVarId}_at_${setting.value}`;
1358
+ default:
1359
+ (0, import_assert_never3.assertNever)(setting);
1360
+ }
1361
+ });
1362
+ const uid = `inputs_${uidParts.sort().join("_")}`;
1363
+ return {
1364
+ kind: "input-settings",
1365
+ uid,
1366
+ settings
1367
+ };
1368
+ }
1369
+ function inputAtPositionSpec(inputVarId, position) {
1370
+ return inputSettingsSpec([positionSetting(inputVarId, position)]);
1371
+ }
1372
+ function allInputsAtPositionSpec(position) {
1373
+ return {
1374
+ kind: "all-inputs",
1375
+ uid: `all_inputs_at_${keyForInputPosition(position)}`,
1376
+ position
1377
+ };
1378
+ }
1379
+ function keyForInputPosition(position) {
1380
+ switch (position) {
1381
+ case "at-default":
1382
+ return "default";
1383
+ case "at-minimum":
1384
+ return "min";
1385
+ case "at-maximum":
1386
+ return "max";
1387
+ default:
1388
+ (0, import_assert_never3.assertNever)(position);
1389
+ }
1390
+ }
1391
+
1392
+ // src/check/check-scenario.ts
1422
1393
  function expandScenarios(modelSpec, scenarioSpecs, simplify) {
1423
1394
  if (scenarioSpecs.length === 0) {
1424
1395
  const scenarioSpec = {
@@ -1495,10 +1466,12 @@ function inputDescForName(modelSpec, inputName, at) {
1495
1466
  }
1496
1467
  }
1497
1468
  function groupForName(modelSpec, groupName) {
1498
- const groupToMatch = groupName.toLowerCase();
1499
- for (const [group, inputVars] of modelSpec.inputGroups) {
1500
- if (group.toLowerCase() === groupToMatch) {
1501
- return [group, inputVars];
1469
+ if (modelSpec.inputGroups) {
1470
+ const groupToMatch = groupName.toLowerCase();
1471
+ for (const [group, inputVars] of modelSpec.inputGroups) {
1472
+ if (group.toLowerCase() === groupToMatch) {
1473
+ return [group, inputVars];
1474
+ }
1502
1475
  }
1503
1476
  }
1504
1477
  return void 0;
@@ -1513,56 +1486,35 @@ function errorScenarioForInputGroup(kind, groupName) {
1513
1486
  };
1514
1487
  }
1515
1488
  function checkScenarioWithAllInputsAtPosition(position) {
1516
- const scenario = allInputsAtPositionScenario(position);
1517
1489
  return {
1518
- scenario,
1490
+ spec: allInputsAtPositionSpec(position),
1519
1491
  inputDescs: []
1520
1492
  };
1521
1493
  }
1522
1494
  function checkScenarioWithInputAtPosition(inputVar, position) {
1523
1495
  const varId = inputVar.varId;
1524
- const scenario = inputAtPositionScenario(varId, varId, position);
1525
1496
  return {
1526
- scenario,
1497
+ spec: inputAtPositionSpec(varId, position),
1527
1498
  inputDescs: [inputDescAtPosition(inputVar, position)]
1528
1499
  };
1529
1500
  }
1530
1501
  function checkScenarioForInputDescs(groupName, inputDescs) {
1531
- let scenario;
1502
+ let spec;
1532
1503
  if (inputDescs.every((desc) => desc.inputVar !== void 0)) {
1533
- const settings = [];
1534
- const keyParts = [];
1535
- for (const inputDesc of inputDescs) {
1504
+ const settings = inputDescs.map((inputDesc) => {
1536
1505
  const varId = inputDesc.inputVar.varId;
1537
1506
  if (inputDesc.position) {
1538
- settings.push(positionSetting(varId, inputDesc.position));
1539
- keyParts.push(keyForInputAtPosition(varId, inputDesc.position));
1507
+ return positionSetting(varId, inputDesc.position);
1540
1508
  } else {
1541
- settings.push(valueSetting(varId, inputDesc.value));
1542
- keyParts.push(keyForInputAtValue(varId, inputDesc.value));
1543
- }
1544
- }
1545
- if (settings.length === 1) {
1546
- const scenarioKey = `input${keyParts[0]}`;
1547
- const groupKey = settings[0].inputVarId;
1548
- scenario = settingsScenario(scenarioKey, groupKey, settings);
1549
- } else if (settings.length > 1) {
1550
- let scenarioKey;
1551
- let groupKey;
1552
- if (groupName) {
1553
- scenarioKey = `group_${groupName.toLowerCase().replace(/ /g, "_")}`;
1554
- groupKey = scenarioKey;
1555
- } else {
1556
- scenarioKey = "multi" + keyParts.join("_");
1557
- groupKey = scenarioKey;
1509
+ return valueSetting(varId, inputDesc.value);
1558
1510
  }
1559
- scenario = settingsScenario(scenarioKey, groupKey, settings);
1560
- }
1511
+ });
1512
+ spec = inputSettingsSpec(settings);
1561
1513
  } else {
1562
- scenario = void 0;
1514
+ spec = void 0;
1563
1515
  }
1564
1516
  return {
1565
- scenario,
1517
+ spec,
1566
1518
  inputGroupName: groupName,
1567
1519
  inputDescs
1568
1520
  };
@@ -1676,7 +1628,7 @@ var CheckPlanner = class {
1676
1628
  }
1677
1629
  const planScenarios = [];
1678
1630
  for (const checkScenario of checkScenarios) {
1679
- if (checkScenario.scenario === void 0) {
1631
+ if (checkScenario.spec === void 0) {
1680
1632
  planScenarios.push({
1681
1633
  checkScenario,
1682
1634
  datasets: []
@@ -1785,8 +1737,8 @@ var CheckPlanner = class {
1785
1737
  }
1786
1738
  }
1787
1739
  let dataRefKey;
1788
- if (refScenario.scenario && refDataset.datasetKey) {
1789
- dataRefKey = `${refScenario.scenario.key}::${refDataset.datasetKey}`;
1740
+ if (refScenario.spec && refDataset.datasetKey) {
1741
+ dataRefKey = `${refScenario.spec.uid}::${refDataset.datasetKey}`;
1790
1742
  }
1791
1743
  const dataRef = {
1792
1744
  key: dataRefKey,
@@ -1841,14 +1793,14 @@ function checkSummaryFromReport(checkReport) {
1841
1793
  predicateSummaries
1842
1794
  };
1843
1795
  }
1844
- function checkReportFromSummary(checkConfig, checkSummary, simplifyScenarios) {
1796
+ function checkReportFromSummary(checkConfig, checkSummary) {
1845
1797
  const checkSpecResult = parseTestYaml(checkConfig.tests);
1846
1798
  if (checkSpecResult.isErr()) {
1847
1799
  return void 0;
1848
1800
  }
1849
1801
  const checkSpec = checkSpecResult.value;
1850
1802
  const checkPlanner = new CheckPlanner(checkConfig.bundle.model.modelSpec);
1851
- checkPlanner.addAllChecks(checkSpec, simplifyScenarios);
1803
+ checkPlanner.addAllChecks(checkSpec, false);
1852
1804
  const checkPlan = checkPlanner.buildPlan();
1853
1805
  const checkResults = /* @__PURE__ */ new Map();
1854
1806
  for (const predicateSummary of checkSummary.predicateSummaries) {
@@ -1857,44 +1809,66 @@ function checkReportFromSummary(checkConfig, checkSummary, simplifyScenarios) {
1857
1809
  return buildCheckReport(checkPlan, checkResults);
1858
1810
  }
1859
1811
 
1860
- // src/compare/compare-data-coordinator.ts
1812
+ // src/comparison/run/comparison-data-coordinator.ts
1861
1813
  var import_assert_never7 = require("assert-never");
1862
- var CompareDataCoordinator = class {
1814
+ var ComparisonDataCoordinator = class {
1863
1815
  constructor(bundleModelL, bundleModelR) {
1864
1816
  this.bundleModelL = bundleModelL;
1865
1817
  this.bundleModelR = bundleModelR;
1866
1818
  this.taskQueue = new TaskQueue({
1867
1819
  process: async (request) => {
1868
1820
  switch (request.kind) {
1869
- case "dataset": {
1870
- const [resultL, resultR] = await Promise.all([
1871
- this.bundleModelL.getDatasetsForScenario(request.scenario, request.datasetKeys),
1872
- this.bundleModelR.getDatasetsForScenario(request.scenario, request.datasetKeys)
1873
- ]);
1874
- return {
1875
- kind: "dataset",
1876
- datasetMapL: resultL.datasetMap,
1877
- datasetMapR: resultR.datasetMap
1878
- };
1879
- }
1880
- case "graph-data": {
1881
- const bundleModel = request.bundle === "right" ? this.bundleModelR : this.bundleModelL;
1882
- const graphData = await bundleModel.getGraphDataForScenario(request.scenario, request.graphId);
1883
- return {
1884
- kind: "graph-data",
1885
- graphData
1886
- };
1887
- }
1821
+ case "dataset":
1822
+ return this.processDatasetRequest(request);
1823
+ case "graph-data":
1824
+ return this.processGraphDataRequest(request);
1888
1825
  default:
1889
1826
  (0, import_assert_never7.assertNever)(request);
1890
1827
  }
1891
1828
  }
1892
1829
  });
1893
1830
  }
1894
- requestDatasetMaps(requestKey, scenario, datasetKeys, onResponse) {
1831
+ async processDatasetRequest(request) {
1832
+ async function fetchDatasets(bundleModel, scenarioSpec) {
1833
+ if (scenarioSpec) {
1834
+ return bundleModel.getDatasetsForScenario(scenarioSpec, request.datasetKeys);
1835
+ } else {
1836
+ return void 0;
1837
+ }
1838
+ }
1839
+ const [resultL, resultR] = await Promise.all([
1840
+ fetchDatasets(this.bundleModelL, request.scenarioSpecL),
1841
+ fetchDatasets(this.bundleModelR, request.scenarioSpecR)
1842
+ ]);
1843
+ return {
1844
+ kind: "dataset",
1845
+ datasetMapL: resultL == null ? void 0 : resultL.datasetMap,
1846
+ datasetMapR: resultR == null ? void 0 : resultR.datasetMap
1847
+ };
1848
+ }
1849
+ async processGraphDataRequest(request) {
1850
+ async function fetchGraphData(bundleModel, scenarioSpec) {
1851
+ if (scenarioSpec) {
1852
+ return bundleModel.getGraphDataForScenario(scenarioSpec, request.graphId);
1853
+ } else {
1854
+ return void 0;
1855
+ }
1856
+ }
1857
+ const [graphDataL, graphDataR] = await Promise.all([
1858
+ fetchGraphData(this.bundleModelL, request.scenarioSpecL),
1859
+ fetchGraphData(this.bundleModelR, request.scenarioSpecR)
1860
+ ]);
1861
+ return {
1862
+ kind: "graph-data",
1863
+ graphDataL,
1864
+ graphDataR
1865
+ };
1866
+ }
1867
+ requestDatasetMaps(requestKey, scenarioSpecL, scenarioSpecR, datasetKeys, onResponse) {
1895
1868
  const request = {
1896
1869
  kind: "dataset",
1897
- scenario,
1870
+ scenarioSpecL,
1871
+ scenarioSpecR,
1898
1872
  datasetKeys
1899
1873
  };
1900
1874
  this.taskQueue.addTask(requestKey, request, (response) => {
@@ -1903,16 +1877,16 @@ var CompareDataCoordinator = class {
1903
1877
  }
1904
1878
  });
1905
1879
  }
1906
- requestGraphData(requestKey, bundle, scenario, graphId, onResponse) {
1880
+ requestGraphData(requestKey, scenarioSpecL, scenarioSpecR, graphId, onResponse) {
1907
1881
  const request = {
1908
1882
  kind: "graph-data",
1909
- bundle,
1910
- scenario,
1883
+ scenarioSpecL,
1884
+ scenarioSpecR,
1911
1885
  graphId
1912
1886
  };
1913
1887
  this.taskQueue.addTask(requestKey, request, (response) => {
1914
1888
  if (response.kind === "graph-data") {
1915
- onResponse(response.graphData);
1889
+ onResponse(response.graphDataL, response.graphDataR);
1916
1890
  }
1917
1891
  });
1918
1892
  }
@@ -1921,7 +1895,7 @@ var CompareDataCoordinator = class {
1921
1895
  }
1922
1896
  };
1923
1897
 
1924
- // src/compare/compare-datasets.ts
1898
+ // src/comparison/diff-datasets/diff-datasets.ts
1925
1899
  function diffDatasets(datasetL, datasetR) {
1926
1900
  let minValueL = Number.MAX_VALUE;
1927
1901
  let maxValueL = Number.MIN_VALUE;
@@ -2016,19 +1990,9 @@ function diffDatasets(datasetL, datasetR) {
2016
1990
  maxDiffPoint
2017
1991
  };
2018
1992
  }
2019
- function compareDatasets(scenarioKey, datasetKey, datasetMapL, datasetMapR) {
2020
- const datasetL = datasetMapL.get(datasetKey);
2021
- const datasetR = datasetMapR.get(datasetKey);
2022
- const diffReport = diffDatasets(datasetL, datasetR);
2023
- return {
2024
- scenarioKey,
2025
- datasetKey,
2026
- diffReport
2027
- };
2028
- }
2029
1993
 
2030
- // src/compare/compare-graphs.ts
2031
- function diffGraphs(graphL, graphR, scenarioKey, datasetSummaries) {
1994
+ // src/comparison/diff-graphs/diff-graphs.ts
1995
+ function diffGraphs(graphL, graphR, scenarioKey, testSummaries) {
2032
1996
  let inclusion;
2033
1997
  if (graphL && graphR) {
2034
1998
  inclusion = "both";
@@ -2070,8 +2034,8 @@ function diffGraphs(graphL, graphR, scenarioKey, datasetSummaries) {
2070
2034
  datasetKeys.add(dataset.datasetKey);
2071
2035
  }
2072
2036
  for (const datasetKey of datasetKeys) {
2073
- const summary = datasetSummaries.find((summary2) => summary2.d === datasetKey && summary2.s === scenarioKey);
2074
- const maxDiff = summary !== void 0 ? summary.md : void 0;
2037
+ const testSummary = testSummaries.find((summary) => summary.d === datasetKey && summary.s === scenarioKey);
2038
+ const maxDiff = testSummary == null ? void 0 : testSummary.md;
2075
2039
  datasetReports.push({
2076
2040
  datasetKey,
2077
2041
  maxDiff
@@ -2085,12 +2049,12 @@ function diffGraphs(graphL, graphR, scenarioKey, datasetSummaries) {
2085
2049
  };
2086
2050
  }
2087
2051
 
2088
- // src/compare/compare-summary.ts
2089
- function compareSummaryFromReport(compareReport) {
2090
- const datasetSummaries = [];
2091
- for (const r of compareReport.datasetReports) {
2052
+ // src/comparison/report/comparison-reporting.ts
2053
+ function comparisonSummaryFromReport(comparisonReport) {
2054
+ const terseSummaries = [];
2055
+ for (const r of comparisonReport.testReports) {
2092
2056
  if (r.diffReport.validity === "both" && r.diffReport.maxDiff > 0) {
2093
- datasetSummaries.push({
2057
+ terseSummaries.push({
2094
2058
  s: r.scenarioKey,
2095
2059
  d: r.datasetKey,
2096
2060
  md: r.diffReport.maxDiff
@@ -2098,152 +2062,1317 @@ function compareSummaryFromReport(compareReport) {
2098
2062
  }
2099
2063
  }
2100
2064
  return {
2101
- datasetSummaries,
2102
- perfReportL: compareReport.perfReportL,
2103
- perfReportR: compareReport.perfReportR
2065
+ testSummaries: terseSummaries,
2066
+ perfReportL: comparisonReport.perfReportL,
2067
+ perfReportR: comparisonReport.perfReportR
2104
2068
  };
2105
2069
  }
2070
+ function restoreFromTerseSummaries(comparisonConfig, terseSummaries) {
2071
+ const existingSummaries = /* @__PURE__ */ new Map();
2072
+ for (const summary of terseSummaries) {
2073
+ const key = `${summary.s}::${summary.d}`;
2074
+ existingSummaries.set(key, summary);
2075
+ }
2076
+ const allTestSummaries = [];
2077
+ for (const scenario of comparisonConfig.scenarios.getAllScenarios()) {
2078
+ const datasetKeys = comparisonConfig.datasets.getDatasetKeysForScenario(scenario);
2079
+ for (const datasetKey of datasetKeys) {
2080
+ const key = `${scenario.key}::${datasetKey}`;
2081
+ const existingSummary = existingSummaries.get(key);
2082
+ const maxDiff = (existingSummary == null ? void 0 : existingSummary.md) || 0;
2083
+ allTestSummaries.push({
2084
+ s: scenario.key,
2085
+ d: datasetKey,
2086
+ md: maxDiff
2087
+ });
2088
+ }
2089
+ }
2090
+ return allTestSummaries;
2091
+ }
2106
2092
 
2107
- // src/config/synchronized-model.ts
2108
- function synchronizedBundleModel(sourceModel) {
2109
- var _a;
2110
- const promiseQueue = new PromiseQueue();
2093
+ // src/comparison/report/comparison-grouping.ts
2094
+ var import_assert_never8 = require("assert-never");
2095
+
2096
+ // src/comparison/report/buckets.ts
2097
+ function getBucketIndex(diffPct, thresholds) {
2098
+ if (diffPct === 0) {
2099
+ return 0;
2100
+ }
2101
+ for (let i = 0; i < thresholds.length; i++) {
2102
+ if (diffPct < thresholds[i]) {
2103
+ return i + 1;
2104
+ }
2105
+ }
2106
+ return thresholds.length + 1;
2107
+ }
2108
+
2109
+ // src/comparison/report/comparison-grouping.ts
2110
+ function categorizeComparisonTestSummaries(comparisonConfig, terseSummaries) {
2111
+ const allTestSummaries = restoreFromTerseSummaries(comparisonConfig, terseSummaries);
2112
+ const groupsByScenario = groupComparisonTestSummaries(allTestSummaries, "by-scenario");
2113
+ const byScenario = categorizeComparisonGroups(comparisonConfig, [...groupsByScenario.values()]);
2114
+ const groupsByDataset = groupComparisonTestSummaries(allTestSummaries, "by-dataset");
2115
+ const byDataset = categorizeComparisonGroups(comparisonConfig, [...groupsByDataset.values()]);
2111
2116
  return {
2112
- modelSpec: sourceModel.modelSpec,
2113
- getDatasetsForScenario: (scenario, datasetKeys) => {
2114
- return promiseQueue.add(() => sourceModel.getDatasetsForScenario(scenario, datasetKeys));
2115
- },
2116
- getGraphsForDataset: (_a = sourceModel.getGraphsForDataset) == null ? void 0 : _a.bind(sourceModel),
2117
- getGraphDataForScenario: (scenario, graphId) => {
2118
- return promiseQueue.add(() => sourceModel.getGraphDataForScenario(scenario, graphId));
2119
- },
2120
- getGraphLinksForScenario: sourceModel.getGraphLinksForScenario.bind(sourceModel)
2117
+ byScenario,
2118
+ byDataset
2121
2119
  };
2122
2120
  }
2123
- var PromiseQueue = class {
2124
- constructor() {
2125
- this.tasks = [];
2126
- this.runningCount = 0;
2121
+ function groupComparisonTestSummaries(testSummaries, groupKind) {
2122
+ const groups = /* @__PURE__ */ new Map();
2123
+ for (const testSummary of testSummaries) {
2124
+ let groupKey;
2125
+ switch (groupKind) {
2126
+ case "by-dataset":
2127
+ groupKey = testSummary.d;
2128
+ break;
2129
+ case "by-scenario":
2130
+ groupKey = testSummary.s;
2131
+ break;
2132
+ default:
2133
+ (0, import_assert_never8.assertNever)(groupKind);
2134
+ }
2135
+ const group = groups.get(groupKey);
2136
+ if (group) {
2137
+ group.testSummaries.push(testSummary);
2138
+ } else {
2139
+ groups.set(groupKey, {
2140
+ kind: groupKind,
2141
+ key: groupKey,
2142
+ testSummaries: [testSummary]
2143
+ });
2144
+ }
2127
2145
  }
2128
- add(f) {
2129
- return new Promise((resolve, reject) => {
2130
- const run = async () => {
2131
- this.runningCount++;
2132
- const promise = f();
2133
- try {
2134
- const result = await promise;
2135
- resolve(result);
2136
- } catch (e) {
2137
- reject(e);
2138
- } finally {
2139
- this.runningCount--;
2140
- this.runNext();
2141
- }
2142
- };
2143
- if (this.runningCount < 1) {
2144
- run();
2146
+ return groups;
2147
+ }
2148
+ function categorizeComparisonGroups(comparisonConfig, allGroups) {
2149
+ const allGroupSummaries = /* @__PURE__ */ new Map();
2150
+ const withErrors = [];
2151
+ const onlyInLeft = [];
2152
+ const onlyInRight = [];
2153
+ let withDiffs = [];
2154
+ const withoutDiffs = [];
2155
+ function addSummaryForGroup(group, root, validInL, validInR) {
2156
+ let scores;
2157
+ if (validInL && validInR) {
2158
+ scores = getScoresForGroup(group, comparisonConfig.thresholds);
2159
+ }
2160
+ const groupSummary = {
2161
+ root,
2162
+ group,
2163
+ scores
2164
+ };
2165
+ allGroupSummaries.set(group.key, groupSummary);
2166
+ if (validInL && validInR) {
2167
+ if (scores.totalDiffCount !== scores.diffCountByBucket[0]) {
2168
+ withDiffs.push(groupSummary);
2145
2169
  } else {
2146
- this.tasks.push(run);
2170
+ withoutDiffs.push(groupSummary);
2147
2171
  }
2148
- });
2172
+ } else if (validInL) {
2173
+ onlyInLeft.push(groupSummary);
2174
+ } else if (validInR) {
2175
+ onlyInRight.push(groupSummary);
2176
+ } else {
2177
+ withErrors.push(groupSummary);
2178
+ }
2149
2179
  }
2150
- runNext() {
2151
- if (this.tasks.length > 0) {
2152
- const task = this.tasks.shift();
2153
- if (task) {
2154
- task();
2180
+ for (const group of allGroups.values()) {
2181
+ switch (group.kind) {
2182
+ case "by-dataset": {
2183
+ const dataset = comparisonConfig.datasets.getDataset(group.key);
2184
+ const validInL = (dataset == null ? void 0 : dataset.outputVarL) !== void 0;
2185
+ const validInR = (dataset == null ? void 0 : dataset.outputVarR) !== void 0;
2186
+ addSummaryForGroup(group, dataset, validInL, validInR);
2187
+ break;
2188
+ }
2189
+ case "by-scenario": {
2190
+ const scenario = comparisonConfig.scenarios.getScenario(group.key);
2191
+ const validInL = (scenario == null ? void 0 : scenario.specL) !== void 0;
2192
+ const validInR = (scenario == null ? void 0 : scenario.specR) !== void 0;
2193
+ addSummaryForGroup(group, scenario, validInL, validInR);
2194
+ break;
2155
2195
  }
2196
+ default:
2197
+ (0, import_assert_never8.assertNever)(group.kind);
2156
2198
  }
2157
2199
  }
2158
- };
2159
-
2160
- // src/config/config.ts
2161
- async function createConfig(options) {
2162
- var _a;
2163
- const origCurrentBundle = await loadSynchronized(options.current);
2164
- let currentBundle;
2165
- let compareConfig;
2166
- if (options.compare === void 0) {
2167
- currentBundle = origCurrentBundle;
2168
- } else {
2169
- const baselineBundle = await loadSynchronized(options.compare.baseline);
2170
- const renamedDatasetKeys = options.compare.datasets.renamedDatasetKeys;
2171
- const invertedRenamedKeys = /* @__PURE__ */ new Map();
2172
- renamedDatasetKeys == null ? void 0 : renamedDatasetKeys.forEach((newKey, oldKey) => {
2173
- invertedRenamedKeys.set(newKey, oldKey);
2174
- });
2175
- const rightKeyForLeftKey = (leftKey) => {
2176
- return (renamedDatasetKeys == null ? void 0 : renamedDatasetKeys.get(leftKey)) || leftKey;
2177
- };
2178
- const leftKeyForRightKey = (rightKey) => {
2179
- return invertedRenamedKeys.get(rightKey) || rightKey;
2180
- };
2181
- const origBundleModelR = origCurrentBundle.model;
2182
- const adjBundleModelR = {
2183
- modelSpec: origBundleModelR.modelSpec,
2184
- getDatasetsForScenario: async (scenario, datasetKeys) => {
2185
- const rightKeys = datasetKeys.map(rightKeyForLeftKey);
2186
- const result = await origBundleModelR.getDatasetsForScenario(scenario, rightKeys);
2187
- const mapWithRightKeys = result.datasetMap;
2188
- const mapWithLeftKeys = /* @__PURE__ */ new Map();
2189
- for (const [rightKey, dataset] of mapWithRightKeys.entries()) {
2190
- const leftKey = leftKeyForRightKey(rightKey);
2191
- mapWithLeftKeys.set(leftKey, dataset);
2192
- }
2193
- return {
2194
- datasetMap: mapWithLeftKeys,
2195
- modelRunTime: result.modelRunTime
2196
- };
2197
- },
2198
- getGraphsForDataset: (_a = origBundleModelR.getGraphsForDataset) == null ? void 0 : _a.bind(origBundleModelR),
2199
- getGraphDataForScenario: origBundleModelR.getGraphDataForScenario.bind(origBundleModelR),
2200
- getGraphLinksForScenario: origBundleModelR.getGraphLinksForScenario.bind(origBundleModelR)
2201
- };
2202
- currentBundle = __spreadProps(__spreadValues({}, origCurrentBundle), {
2203
- model: adjBundleModelR
2204
- });
2205
- compareConfig = {
2206
- bundleL: baselineBundle,
2207
- bundleR: currentBundle,
2208
- thresholds: options.compare.thresholds,
2209
- scenarios: options.compare.scenarios,
2210
- datasets: options.compare.datasets
2211
- };
2200
+ if (withDiffs.length > 1) {
2201
+ if (withDiffs[0].group.kind === "by-dataset") {
2202
+ withDiffs = sortDatasetGroupSummaries(withDiffs);
2203
+ } else if (withDiffs[0].group.kind === "by-scenario") {
2204
+ withDiffs = sortScenarioGroupSummaries(withDiffs);
2205
+ }
2212
2206
  }
2213
- const checkConfig = {
2214
- bundle: currentBundle,
2215
- tests: options.check.tests
2216
- };
2217
2207
  return {
2218
- check: checkConfig,
2219
- compare: compareConfig
2208
+ allGroupSummaries,
2209
+ withErrors,
2210
+ onlyInLeft,
2211
+ onlyInRight,
2212
+ withDiffs,
2213
+ withoutDiffs
2220
2214
  };
2221
2215
  }
2222
- async function loadSynchronized(sourceBundle) {
2223
- const sourceModel = await sourceBundle.bundle.initModel();
2224
- const synchronizedModel = synchronizedBundleModel(sourceModel);
2216
+ function getScoresForGroup(group, thresholds) {
2217
+ const diffCountByBucket = Array(thresholds.length + 2).fill(0);
2218
+ const totalMaxDiffByBucket = Array(thresholds.length + 2).fill(0);
2219
+ let totalDiffCount = 0;
2220
+ for (const testSummary of group.testSummaries) {
2221
+ const bucketIndex = getBucketIndex(testSummary.md, thresholds);
2222
+ diffCountByBucket[bucketIndex]++;
2223
+ totalMaxDiffByBucket[bucketIndex] += testSummary.md;
2224
+ totalDiffCount++;
2225
+ }
2226
+ let diffPercentByBucket;
2227
+ if (totalDiffCount > 0) {
2228
+ diffPercentByBucket = diffCountByBucket.map((count) => count / totalDiffCount * 100);
2229
+ } else {
2230
+ diffPercentByBucket = [];
2231
+ }
2225
2232
  return {
2226
- name: sourceBundle.name,
2227
- version: sourceBundle.bundle.version,
2228
- model: synchronizedModel
2233
+ totalDiffCount,
2234
+ totalMaxDiffByBucket,
2235
+ diffCountByBucket,
2236
+ diffPercentByBucket
2229
2237
  };
2230
2238
  }
2231
-
2232
- // src/config/dataset-manager.ts
2233
- var DatasetManager = class {
2234
- constructor(bundleL, bundleR, renamedDatasetKeys) {
2235
- this.bundleL = bundleL;
2236
- this.bundleR = bundleR;
2237
- this.renamedDatasetKeys = renamedDatasetKeys;
2238
- const invertedRenamedKeys = /* @__PURE__ */ new Map();
2239
- renamedDatasetKeys == null ? void 0 : renamedDatasetKeys.forEach((newKey, oldKey) => {
2240
- invertedRenamedKeys.set(newKey, oldKey);
2241
- });
2242
- function leftKeyForRightKey(rightKey) {
2243
- return invertedRenamedKeys.get(rightKey) || rightKey;
2239
+ function sortDatasetGroupSummaries(summaries) {
2240
+ return summaries.sort((a, b) => {
2241
+ var _a, _b;
2242
+ const scoreResult = compareScores(a.scores, b.scores);
2243
+ if (scoreResult !== 0) {
2244
+ return -scoreResult;
2245
+ } else {
2246
+ const aVar = a.root.outputVarL;
2247
+ const bVar = b.root.outputVarR;
2248
+ const aSource = ((_a = aVar.sourceName) == null ? void 0 : _a.toLowerCase()) || "";
2249
+ const bSource = ((_b = bVar.sourceName) == null ? void 0 : _b.toLowerCase()) || "";
2250
+ if (aSource !== bSource) {
2251
+ return aSource.localeCompare(bSource);
2252
+ } else {
2253
+ const aName = aVar.varName.toLowerCase();
2254
+ const bName = bVar.varName.toLowerCase();
2255
+ return aName.localeCompare(bName);
2256
+ }
2244
2257
  }
2245
- const allOutputVarKeysSet = /* @__PURE__ */ new Set();
2246
- const modelOutputVarKeysSet = /* @__PURE__ */ new Set();
2258
+ });
2259
+ }
2260
+ function sortScenarioGroupSummaries(summaries) {
2261
+ return summaries.sort((a, b) => {
2262
+ var _a, _b;
2263
+ const scoreResult = compareScores(a.scores, b.scores);
2264
+ if (scoreResult !== 0) {
2265
+ return -scoreResult;
2266
+ } else {
2267
+ const aScenario = a.root;
2268
+ const bScenario = b.root;
2269
+ const aTitle = aScenario.title.toLowerCase();
2270
+ const bTitle = bScenario.title.toLowerCase();
2271
+ if (aTitle !== bTitle) {
2272
+ return aTitle.localeCompare(bTitle);
2273
+ } else {
2274
+ const aSubtitle = ((_a = aScenario.subtitle) == null ? void 0 : _a.toLowerCase()) || "";
2275
+ const bSubtitle = ((_b = bScenario.subtitle) == null ? void 0 : _b.toLowerCase()) || "";
2276
+ return aSubtitle.localeCompare(bSubtitle);
2277
+ }
2278
+ }
2279
+ });
2280
+ }
2281
+ function compareScores(a, b) {
2282
+ if (a.totalMaxDiffByBucket.length !== b.totalMaxDiffByBucket.length) {
2283
+ return 0;
2284
+ }
2285
+ const len = a.totalMaxDiffByBucket.length;
2286
+ for (let i = len - 1; i >= 0; i--) {
2287
+ const aTotal = a.totalMaxDiffByBucket[i];
2288
+ const bTotal = b.totalMaxDiffByBucket[i];
2289
+ if (aTotal > bTotal) {
2290
+ return 1;
2291
+ } else if (aTotal < bTotal) {
2292
+ return -1;
2293
+ }
2294
+ }
2295
+ return 0;
2296
+ }
2297
+
2298
+ // src/bundle/model-inputs.ts
2299
+ var ModelInputs = class {
2300
+ constructor(modelSpec) {
2301
+ this.inputsByLookupName = /* @__PURE__ */ new Map();
2302
+ this.inputIdAliases = /* @__PURE__ */ new Set();
2303
+ for (const inputVar of modelSpec.inputVars.values()) {
2304
+ const varNameKey = inputVar.varName.toLowerCase();
2305
+ this.inputsByLookupName.set(varNameKey, inputVar);
2306
+ if (inputVar.inputId) {
2307
+ const idAlias = `id ${inputVar.inputId}`;
2308
+ this.inputIdAliases.add(idAlias);
2309
+ const idKey = idAlias.toLowerCase();
2310
+ this.inputsByLookupName.set(idKey, inputVar);
2311
+ }
2312
+ }
2313
+ if (modelSpec.inputAliases) {
2314
+ for (const [alias, varId] of modelSpec.inputAliases.entries()) {
2315
+ const aliasKey = alias.toLowerCase();
2316
+ if (this.inputsByLookupName.has(aliasKey)) {
2317
+ console.warn(
2318
+ `WARNING: Input variable already defined with a name that collides with alias '${alias}', skipping`
2319
+ );
2320
+ continue;
2321
+ }
2322
+ const inputVar = modelSpec.inputVars.get(varId);
2323
+ if (inputVar === void 0) {
2324
+ console.warn(`WARNING: No input variable found for '${varId}' associated with alias '${alias}', skipping`);
2325
+ continue;
2326
+ }
2327
+ this.inputsByLookupName.set(aliasKey, inputVar);
2328
+ }
2329
+ }
2330
+ }
2331
+ getAllInputIdAliases() {
2332
+ return [...this.inputIdAliases];
2333
+ }
2334
+ getInputVarForName(name) {
2335
+ return this.inputsByLookupName.get(name.toLowerCase());
2336
+ }
2337
+ };
2338
+
2339
+ // src/comparison/config/parse/comparison-parser.ts
2340
+ var import_ajv2 = __toESM(require("ajv"), 1);
2341
+ var import_assert_never9 = __toESM(require("assert-never"), 1);
2342
+ var import_neverthrow2 = require("neverthrow");
2343
+ var import_yaml2 = __toESM(require("yaml"), 1);
2344
+
2345
+ // src/comparison/config/parse/comparison.schema.js
2346
+ var comparison_schema_default = {
2347
+ $schema: "http://json-schema.org/draft-07/schema#",
2348
+ title: "Model Comparison Test",
2349
+ type: "array",
2350
+ description: "A group of model comparison scenarios and views.",
2351
+ items: {
2352
+ $ref: "#/$defs/top_level_array_item"
2353
+ },
2354
+ $defs: {
2355
+ top_level_array_item: {
2356
+ oneOf: [
2357
+ { $ref: "#/$defs/scenario_array_item" },
2358
+ { $ref: "#/$defs/scenario_group_array_item" },
2359
+ { $ref: "#/$defs/view_group_array_item" }
2360
+ ]
2361
+ },
2362
+ scenario_array_item: {
2363
+ type: "object",
2364
+ additionalProperties: false,
2365
+ properties: {
2366
+ scenario: {
2367
+ $ref: "#/$defs/scenario"
2368
+ }
2369
+ },
2370
+ required: ["scenario"]
2371
+ },
2372
+ scenario: {
2373
+ oneOf: [
2374
+ { $ref: "#/$defs/scenario_with_input_at_position" },
2375
+ { $ref: "#/$defs/scenario_with_input_at_value" },
2376
+ { $ref: "#/$defs/scenario_with_multiple_input_settings" },
2377
+ { $ref: "#/$defs/scenario_with_inputs_in_preset_at_position" },
2378
+ { $ref: "#/$defs/scenario_preset" }
2379
+ ]
2380
+ },
2381
+ scenario_position: {
2382
+ type: "string",
2383
+ enum: ["min", "max", "default"]
2384
+ },
2385
+ scenario_with_input_at_position: {
2386
+ type: "object",
2387
+ additionalProperties: false,
2388
+ properties: {
2389
+ id: {
2390
+ type: "string"
2391
+ },
2392
+ title: {
2393
+ type: "string"
2394
+ },
2395
+ subtitle: {
2396
+ type: "string"
2397
+ },
2398
+ with: {
2399
+ type: "string"
2400
+ },
2401
+ at: {
2402
+ $ref: "#/$defs/scenario_position"
2403
+ }
2404
+ },
2405
+ required: ["with", "at"]
2406
+ },
2407
+ scenario_with_input_at_value: {
2408
+ type: "object",
2409
+ additionalProperties: false,
2410
+ properties: {
2411
+ id: {
2412
+ type: "string"
2413
+ },
2414
+ title: {
2415
+ type: "string"
2416
+ },
2417
+ subtitle: {
2418
+ type: "string"
2419
+ },
2420
+ with: {
2421
+ type: "string"
2422
+ },
2423
+ at: {
2424
+ type: "number"
2425
+ }
2426
+ },
2427
+ required: ["with", "at"]
2428
+ },
2429
+ scenario_input_at_position: {
2430
+ type: "object",
2431
+ additionalProperties: false,
2432
+ properties: {
2433
+ input: {
2434
+ type: "string"
2435
+ },
2436
+ at: {
2437
+ $ref: "#/$defs/scenario_position"
2438
+ }
2439
+ },
2440
+ required: ["input", "at"]
2441
+ },
2442
+ scenario_input_at_value: {
2443
+ type: "object",
2444
+ additionalProperties: false,
2445
+ properties: {
2446
+ input: {
2447
+ type: "string"
2448
+ },
2449
+ at: {
2450
+ type: "number"
2451
+ }
2452
+ },
2453
+ required: ["input", "at"]
2454
+ },
2455
+ scenario_input_setting: {
2456
+ oneOf: [{ $ref: "#/$defs/scenario_input_at_position" }, { $ref: "#/$defs/scenario_input_at_value" }]
2457
+ },
2458
+ scenario_input_setting_array: {
2459
+ type: "array",
2460
+ items: {
2461
+ $ref: "#/$defs/scenario_input_setting"
2462
+ },
2463
+ minItems: 1
2464
+ },
2465
+ scenario_with_multiple_input_settings: {
2466
+ type: "object",
2467
+ additionalProperties: false,
2468
+ properties: {
2469
+ id: {
2470
+ type: "string"
2471
+ },
2472
+ title: {
2473
+ type: "string"
2474
+ },
2475
+ subtitle: {
2476
+ type: "string"
2477
+ },
2478
+ with: {
2479
+ $ref: "#/$defs/scenario_input_setting_array"
2480
+ }
2481
+ },
2482
+ required: ["with"]
2483
+ },
2484
+ scenario_with_inputs_in_preset_at_position: {
2485
+ type: "object",
2486
+ additionalProperties: false,
2487
+ properties: {
2488
+ id: {
2489
+ type: "string"
2490
+ },
2491
+ title: {
2492
+ type: "string"
2493
+ },
2494
+ subtitle: {
2495
+ type: "string"
2496
+ },
2497
+ with_inputs: {
2498
+ type: "string",
2499
+ enum: ["all"]
2500
+ },
2501
+ at: {
2502
+ $ref: "#/$defs/scenario_position"
2503
+ }
2504
+ },
2505
+ required: ["with_inputs", "at"]
2506
+ },
2507
+ scenario_preset: {
2508
+ type: "object",
2509
+ additionalProperties: false,
2510
+ properties: {
2511
+ preset: {
2512
+ type: "string",
2513
+ enum: ["matrix"]
2514
+ }
2515
+ },
2516
+ required: ["preset"]
2517
+ },
2518
+ scenario_group_array_item: {
2519
+ type: "object",
2520
+ additionalProperties: false,
2521
+ properties: {
2522
+ scenario_group: {
2523
+ $ref: "#/$defs/scenario_group"
2524
+ }
2525
+ },
2526
+ required: ["scenario_group"]
2527
+ },
2528
+ scenario_group: {
2529
+ type: "object",
2530
+ additionalProperties: false,
2531
+ properties: {
2532
+ id: {
2533
+ type: "string"
2534
+ },
2535
+ title: {
2536
+ type: "string"
2537
+ },
2538
+ scenarios: {
2539
+ type: "array",
2540
+ items: {
2541
+ $ref: "#/$defs/scenario_group_scenarios_array_item"
2542
+ },
2543
+ minItems: 1
2544
+ }
2545
+ },
2546
+ required: ["title", "scenarios"]
2547
+ },
2548
+ scenario_group_scenarios_array_item: {
2549
+ oneOf: [{ $ref: "#/$defs/scenario_array_item" }, { $ref: "#/$defs/scenario_ref_array_item" }]
2550
+ },
2551
+ scenario_ref_id: {
2552
+ type: "string"
2553
+ },
2554
+ scenario_ref_object: {
2555
+ type: "object",
2556
+ additionalProperties: false,
2557
+ properties: {
2558
+ id: {
2559
+ type: "string"
2560
+ },
2561
+ title: {
2562
+ type: "string"
2563
+ },
2564
+ subtitle: {
2565
+ type: "string"
2566
+ }
2567
+ },
2568
+ required: ["id"]
2569
+ },
2570
+ scenario_ref: {
2571
+ oneOf: [{ $ref: "#/$defs/scenario_ref_id" }, { $ref: "#/$defs/scenario_ref_object" }]
2572
+ },
2573
+ scenario_ref_array_item: {
2574
+ type: "object",
2575
+ additionalProperties: false,
2576
+ properties: {
2577
+ scenario_ref: {
2578
+ $ref: "#/$defs/scenario_ref"
2579
+ }
2580
+ },
2581
+ required: ["scenario_ref"]
2582
+ },
2583
+ scenario_group_ref: {
2584
+ type: "object",
2585
+ additionalProperties: false,
2586
+ properties: {
2587
+ scenario_group_ref: {
2588
+ type: "string"
2589
+ }
2590
+ },
2591
+ required: ["scenario_group_ref"]
2592
+ },
2593
+ view: {
2594
+ type: "object",
2595
+ additionalProperties: false,
2596
+ properties: {
2597
+ title: {
2598
+ type: "string"
2599
+ },
2600
+ subtitle: {
2601
+ type: "string"
2602
+ },
2603
+ scenario_ref: {
2604
+ type: "string"
2605
+ },
2606
+ graphs: {
2607
+ $ref: "#/$defs/view_graphs"
2608
+ }
2609
+ },
2610
+ required: ["scenario_ref", "graphs"]
2611
+ },
2612
+ view_graphs: {
2613
+ oneOf: [{ $ref: "#/$defs/view_graphs_preset" }, { $ref: "#/$defs/view_graphs_array" }]
2614
+ },
2615
+ view_graphs_preset: {
2616
+ type: "string",
2617
+ enum: ["all"]
2618
+ },
2619
+ view_graphs_array: {
2620
+ type: "array",
2621
+ items: {
2622
+ type: "string"
2623
+ },
2624
+ minItems: 1
2625
+ },
2626
+ view_group_array_item: {
2627
+ type: "object",
2628
+ additionalProperties: false,
2629
+ properties: {
2630
+ view_group: {
2631
+ $ref: "#/$defs/view_group"
2632
+ }
2633
+ },
2634
+ required: ["view_group"]
2635
+ },
2636
+ view_group: {
2637
+ oneOf: [
2638
+ { $ref: "#/$defs/view_group_with_views_array" },
2639
+ { $ref: "#/$defs/view_group_shorthand_with_scenarios_array" }
2640
+ ]
2641
+ },
2642
+ view_group_with_views_array: {
2643
+ type: "object",
2644
+ additionalProperties: false,
2645
+ properties: {
2646
+ title: {
2647
+ type: "string"
2648
+ },
2649
+ views: {
2650
+ type: "array",
2651
+ items: {
2652
+ $ref: "#/$defs/view_group_views_array_item"
2653
+ },
2654
+ minItems: 1
2655
+ }
2656
+ },
2657
+ required: ["title", "views"]
2658
+ },
2659
+ view_group_views_array_item: {
2660
+ type: "object",
2661
+ additionalProperties: false,
2662
+ properties: {
2663
+ view: {
2664
+ $ref: "#/$defs/view"
2665
+ }
2666
+ }
2667
+ },
2668
+ view_group_shorthand_with_scenarios_array: {
2669
+ type: "object",
2670
+ additionalProperties: false,
2671
+ properties: {
2672
+ title: {
2673
+ type: "string"
2674
+ },
2675
+ scenarios: {
2676
+ type: "array",
2677
+ items: {
2678
+ $ref: "#/$defs/view_group_scenarios_array_item"
2679
+ },
2680
+ minItems: 1
2681
+ },
2682
+ graphs: {
2683
+ $ref: "#/$defs/view_graphs"
2684
+ }
2685
+ },
2686
+ required: ["title", "scenarios", "graphs"]
2687
+ },
2688
+ view_group_scenarios_array_item: {
2689
+ oneOf: [{ $ref: "#/$defs/scenario_ref_array_item" }, { $ref: "#/$defs/scenario_group_ref" }]
2690
+ }
2691
+ }
2692
+ };
2693
+
2694
+ // src/comparison/config/parse/comparison-parser.ts
2695
+ function parseComparisonSpecs(specSource) {
2696
+ const scenarios = [];
2697
+ const scenarioGroups = [];
2698
+ const viewGroups = [];
2699
+ const ajv = new import_ajv2.default();
2700
+ const validate = ajv.compile(comparison_schema_default);
2701
+ let parsed;
2702
+ switch (specSource.kind) {
2703
+ case "json":
2704
+ parsed = JSON.parse(specSource.content);
2705
+ break;
2706
+ case "yaml":
2707
+ parsed = import_yaml2.default.parse(specSource.content);
2708
+ break;
2709
+ default:
2710
+ (0, import_assert_never9.default)(specSource.kind);
2711
+ }
2712
+ if (validate(parsed)) {
2713
+ for (const specItem of parsed) {
2714
+ if ("scenario" in specItem) {
2715
+ scenarios.push(scenarioSpecFromParsed(specItem.scenario));
2716
+ } else if ("scenario_group" in specItem) {
2717
+ scenarioGroups.push(scenarioGroupSpecFromParsed(specItem.scenario_group));
2718
+ } else if ("view_group" in specItem) {
2719
+ viewGroups.push(viewGroupSpecFromParsed(specItem.view_group));
2720
+ }
2721
+ }
2722
+ } else {
2723
+ let msg = "Failed to parse YAML comparison definitions";
2724
+ for (const error of validate.errors || []) {
2725
+ if (error.message) {
2726
+ msg += `
2727
+ ${error.message}`;
2728
+ }
2729
+ }
2730
+ return (0, import_neverthrow2.err)(new Error(msg));
2731
+ }
2732
+ return (0, import_neverthrow2.ok)({
2733
+ scenarios,
2734
+ scenarioGroups,
2735
+ viewGroups
2736
+ });
2737
+ }
2738
+ function scenarioSpecFromParsed(parsedScenario) {
2739
+ if (parsedScenario.preset === "matrix") {
2740
+ return {
2741
+ kind: "scenario-matrix"
2742
+ };
2743
+ }
2744
+ if (parsedScenario.with !== void 0) {
2745
+ let inputSpecs;
2746
+ if (Array.isArray(parsedScenario.with)) {
2747
+ const parsedInputs = parsedScenario.with;
2748
+ inputSpecs = parsedInputs.map(inputSpecFromParsed);
2749
+ } else {
2750
+ inputSpecs = [
2751
+ inputSpecFromParsed({
2752
+ input: parsedScenario.with,
2753
+ at: parsedScenario.at
2754
+ })
2755
+ ];
2756
+ }
2757
+ return {
2758
+ kind: "scenario-with-inputs",
2759
+ id: parsedScenario.id,
2760
+ title: parsedScenario.title,
2761
+ subtitle: parsedScenario.subtitle,
2762
+ inputs: inputSpecs
2763
+ };
2764
+ }
2765
+ if (parsedScenario.with_inputs === "all") {
2766
+ return {
2767
+ kind: "scenario-with-all-inputs",
2768
+ id: parsedScenario.id,
2769
+ title: parsedScenario.title,
2770
+ subtitle: parsedScenario.subtitle,
2771
+ position: parsedScenario.at
2772
+ };
2773
+ }
2774
+ throw new Error(`Unable to convert parsed scenario: ${JSON.stringify(parsedScenario)}`);
2775
+ }
2776
+ function inputSpecFromParsed(parsedInput) {
2777
+ if (typeof parsedInput.at === "number") {
2778
+ const value = parsedInput.at;
2779
+ return {
2780
+ kind: "input-at-value",
2781
+ inputName: parsedInput.input,
2782
+ value
2783
+ };
2784
+ } else {
2785
+ return {
2786
+ kind: "input-at-position",
2787
+ inputName: parsedInput.input,
2788
+ position: parsedInput.at
2789
+ };
2790
+ }
2791
+ }
2792
+ function scenarioGroupSpecFromParsed(parsedScenarioGroup) {
2793
+ const scenarioSpecs = parsedScenarioGroup.scenarios.map(
2794
+ (parsedScenarioOrRef) => {
2795
+ if ("scenario_ref" in parsedScenarioOrRef) {
2796
+ return scenarioRefSpecFromParsed(parsedScenarioOrRef);
2797
+ } else {
2798
+ return scenarioSpecFromParsed(parsedScenarioOrRef.scenario);
2799
+ }
2800
+ }
2801
+ );
2802
+ return {
2803
+ kind: "scenario-group",
2804
+ id: parsedScenarioGroup.id,
2805
+ title: parsedScenarioGroup.title,
2806
+ scenarios: scenarioSpecs
2807
+ };
2808
+ }
2809
+ function scenarioRefSpecFromParsed(parsedScenarioRef) {
2810
+ if (typeof parsedScenarioRef.scenario_ref === "string") {
2811
+ return {
2812
+ kind: "scenario-ref",
2813
+ scenarioId: parsedScenarioRef.scenario_ref
2814
+ };
2815
+ } else {
2816
+ return {
2817
+ kind: "scenario-ref",
2818
+ scenarioId: parsedScenarioRef.scenario_ref.id,
2819
+ title: parsedScenarioRef.scenario_ref.title,
2820
+ subtitle: parsedScenarioRef.scenario_ref.subtitle
2821
+ };
2822
+ }
2823
+ }
2824
+ function scenarioGroupRefSpecFromParsed(parsedGroupRef) {
2825
+ return {
2826
+ kind: "scenario-group-ref",
2827
+ groupId: parsedGroupRef.scenario_group_ref
2828
+ };
2829
+ }
2830
+ function viewSpecFromParsed(parsedView) {
2831
+ return {
2832
+ kind: "view",
2833
+ title: parsedView.title,
2834
+ subtitle: parsedView.subtitle,
2835
+ scenarioId: parsedView.scenario_ref,
2836
+ graphs: viewGraphsSpecFromParsed(parsedView.graphs)
2837
+ };
2838
+ }
2839
+ function viewGraphsSpecFromParsed(parsedGraphs) {
2840
+ if (parsedGraphs === "all") {
2841
+ return {
2842
+ kind: "graphs-preset",
2843
+ preset: "all"
2844
+ };
2845
+ } else {
2846
+ return {
2847
+ kind: "graphs-array",
2848
+ graphIds: parsedGraphs
2849
+ };
2850
+ }
2851
+ }
2852
+ function viewGroupSpecFromParsed(parsedViewGroup) {
2853
+ if (parsedViewGroup.views !== void 0) {
2854
+ return {
2855
+ kind: "view-group-with-views",
2856
+ title: parsedViewGroup.title,
2857
+ views: parsedViewGroup.views.map((item) => viewSpecFromParsed(item.view))
2858
+ };
2859
+ } else if (parsedViewGroup.scenarios !== void 0) {
2860
+ const scenarios = parsedViewGroup.scenarios.map(
2861
+ (parsedScenarioOrGroupRef) => {
2862
+ if ("scenario_ref" in parsedScenarioOrGroupRef) {
2863
+ return scenarioRefSpecFromParsed(parsedScenarioOrGroupRef);
2864
+ } else if ("scenario_group_ref" in parsedScenarioOrGroupRef) {
2865
+ return scenarioGroupRefSpecFromParsed(parsedScenarioOrGroupRef);
2866
+ } else {
2867
+ throw new Error("Invalid view group");
2868
+ }
2869
+ }
2870
+ );
2871
+ return {
2872
+ kind: "view-group-with-scenarios",
2873
+ title: parsedViewGroup.title,
2874
+ scenarios,
2875
+ graphs: viewGraphsSpecFromParsed(parsedViewGroup.graphs)
2876
+ };
2877
+ } else {
2878
+ throw new Error("Invalid view group");
2879
+ }
2880
+ }
2881
+
2882
+ // src/comparison/config/resolve/comparison-resolver.ts
2883
+ var import_assert_never11 = require("assert-never");
2884
+
2885
+ // src/comparison/config/resolve/comparison-scenario-specs.ts
2886
+ var import_assert_never10 = require("assert-never");
2887
+ function scenarioSpecsFromSettings(settings) {
2888
+ switch (settings.kind) {
2889
+ case "all-inputs-settings": {
2890
+ const scenario = allInputsAtPositionSpec(settings.position);
2891
+ return [scenario, scenario];
2892
+ }
2893
+ case "input-settings": {
2894
+ const specL = scenarioSpecFromInputs(settings.inputs, "left");
2895
+ const specR = scenarioSpecFromInputs(settings.inputs, "right");
2896
+ return [specL, specR];
2897
+ }
2898
+ default:
2899
+ (0, import_assert_never10.assertNever)(settings);
2900
+ }
2901
+ }
2902
+ function scenarioSpecFromInputs(inputs, side) {
2903
+ const settings = [];
2904
+ for (const input of inputs) {
2905
+ const state = side === "left" ? input.stateL : input.stateR;
2906
+ if (state.inputVar === void 0) {
2907
+ return void 0;
2908
+ }
2909
+ const varId = state.inputVar.varId;
2910
+ if (state.position) {
2911
+ settings.push(positionSetting(varId, state.position));
2912
+ } else {
2913
+ settings.push(valueSetting(varId, state.value));
2914
+ }
2915
+ }
2916
+ return inputSettingsSpec(settings);
2917
+ }
2918
+
2919
+ // src/comparison/config/resolve/comparison-resolver.ts
2920
+ function resolveComparisonSpecs(modelInputsL, modelInputsR, specs) {
2921
+ let key = 1;
2922
+ const genKey = () => {
2923
+ return `${key++}`;
2924
+ };
2925
+ const resolvedScenarios = new ResolvedScenarios();
2926
+ for (const scenarioSpec of specs.scenarios) {
2927
+ resolvedScenarios.add(resolveScenariosFromSpec(modelInputsL, modelInputsR, scenarioSpec, genKey));
2928
+ }
2929
+ const partiallyResolvedScenarioGroups = [];
2930
+ for (const scenarioGroupSpec of specs.scenarioGroups) {
2931
+ const scenariosForGroup = [];
2932
+ for (const scenarioItem of scenarioGroupSpec.scenarios) {
2933
+ if (scenarioItem.kind === "scenario-ref") {
2934
+ scenariosForGroup.push(scenarioItem);
2935
+ } else {
2936
+ const scenarios = resolveScenariosFromSpec(modelInputsL, modelInputsR, scenarioItem, genKey);
2937
+ resolvedScenarios.add(scenarios);
2938
+ scenariosForGroup.push(...scenarios);
2939
+ }
2940
+ }
2941
+ partiallyResolvedScenarioGroups.push({
2942
+ spec: scenarioGroupSpec,
2943
+ scenarios: scenariosForGroup
2944
+ });
2945
+ }
2946
+ const resolvedScenarioGroups = new ResolvedScenarioGroups();
2947
+ for (const partiallyResolvedGroup of partiallyResolvedScenarioGroups) {
2948
+ const scenariosForGroup = [];
2949
+ for (const scenarioItem of partiallyResolvedGroup.scenarios) {
2950
+ if (scenarioItem.kind === "scenario-ref") {
2951
+ const referencedScenario = resolvedScenarios.getScenarioForId(scenarioItem.scenarioId);
2952
+ if (referencedScenario) {
2953
+ const resolvedScenario = { ...referencedScenario };
2954
+ if (scenarioItem.title) {
2955
+ resolvedScenario.title = scenarioItem.title;
2956
+ }
2957
+ if (scenarioItem.subtitle) {
2958
+ resolvedScenario.subtitle = scenarioItem.subtitle;
2959
+ }
2960
+ scenariosForGroup.push(resolvedScenario);
2961
+ } else {
2962
+ scenariosForGroup.push({
2963
+ kind: "unresolved-scenario-ref",
2964
+ scenarioId: scenarioItem.scenarioId
2965
+ });
2966
+ }
2967
+ } else {
2968
+ scenariosForGroup.push(scenarioItem);
2969
+ }
2970
+ }
2971
+ resolvedScenarioGroups.add({
2972
+ kind: "scenario-group",
2973
+ id: partiallyResolvedGroup.spec.id,
2974
+ title: partiallyResolvedGroup.spec.title,
2975
+ scenarios: scenariosForGroup
2976
+ });
2977
+ }
2978
+ const resolvedViewGroups = [];
2979
+ for (const viewGroupSpec of specs.viewGroups) {
2980
+ const resolvedViewGroup = resolveViewGroupFromSpec(resolvedScenarios, resolvedScenarioGroups, viewGroupSpec);
2981
+ resolvedViewGroups.push(resolvedViewGroup);
2982
+ }
2983
+ return {
2984
+ scenarios: resolvedScenarios.getAll(),
2985
+ scenarioGroups: resolvedScenarioGroups.getAll(),
2986
+ viewGroups: resolvedViewGroups
2987
+ };
2988
+ }
2989
+ var ResolvedScenarios = class {
2990
+ constructor() {
2991
+ this.resolvedScenarios = [];
2992
+ this.resolvedScenariosById = /* @__PURE__ */ new Map();
2993
+ }
2994
+ add(scenarios) {
2995
+ for (const resolvedScenario of scenarios) {
2996
+ this.resolvedScenarios.push(resolvedScenario);
2997
+ if (resolvedScenario.id !== void 0) {
2998
+ if (this.resolvedScenariosById.has(resolvedScenario.id)) {
2999
+ throw new Error(`Multiple scenarios defined with the same id (${resolvedScenario.id})`);
3000
+ }
3001
+ this.resolvedScenariosById.set(resolvedScenario.id, resolvedScenario);
3002
+ }
3003
+ }
3004
+ }
3005
+ getAll() {
3006
+ return this.resolvedScenarios;
3007
+ }
3008
+ getScenarioForId(id) {
3009
+ return this.resolvedScenariosById.get(id);
3010
+ }
3011
+ };
3012
+ function resolveScenariosFromSpec(modelInputsL, modelInputsR, scenarioSpec, genKey) {
3013
+ switch (scenarioSpec.kind) {
3014
+ case "scenario-matrix":
3015
+ return resolveScenarioMatrix(modelInputsL, modelInputsR, genKey);
3016
+ case "scenario-with-all-inputs": {
3017
+ const position = inputPosition2(scenarioSpec.position);
3018
+ return [
3019
+ resolveScenarioWithAllInputsAtPosition(
3020
+ genKey(),
3021
+ scenarioSpec.id,
3022
+ scenarioSpec.title,
3023
+ scenarioSpec.subtitle,
3024
+ position
3025
+ )
3026
+ ];
3027
+ }
3028
+ case "scenario-with-inputs": {
3029
+ return [
3030
+ resolveScenarioForInputSpecs(
3031
+ modelInputsL,
3032
+ modelInputsR,
3033
+ genKey(),
3034
+ scenarioSpec.id,
3035
+ scenarioSpec.title,
3036
+ scenarioSpec.subtitle,
3037
+ scenarioSpec.inputs
3038
+ )
3039
+ ];
3040
+ }
3041
+ default:
3042
+ (0, import_assert_never11.assertNever)(scenarioSpec);
3043
+ }
3044
+ }
3045
+ function resolveScenarioMatrix(modelInputsL, modelInputsR, genKey) {
3046
+ const resolvedScenarios = [];
3047
+ resolvedScenarios.push(
3048
+ resolveScenarioWithAllInputsAtPosition(genKey(), void 0, void 0, void 0, "at-default")
3049
+ );
3050
+ const inputIdAliases = /* @__PURE__ */ new Set();
3051
+ modelInputsL.getAllInputIdAliases().forEach((alias) => inputIdAliases.add(alias));
3052
+ modelInputsR.getAllInputIdAliases().forEach((alias) => inputIdAliases.add(alias));
3053
+ for (const inputIdAlias of inputIdAliases) {
3054
+ const inputAtMin = {
3055
+ kind: "input-at-position",
3056
+ inputName: inputIdAlias,
3057
+ position: "min"
3058
+ };
3059
+ const inputAtMax = {
3060
+ kind: "input-at-position",
3061
+ inputName: inputIdAlias,
3062
+ position: "max"
3063
+ };
3064
+ resolvedScenarios.push(
3065
+ resolveScenarioForInputSpecs(modelInputsL, modelInputsR, genKey(), void 0, void 0, void 0, [inputAtMin])
3066
+ );
3067
+ resolvedScenarios.push(
3068
+ resolveScenarioForInputSpecs(modelInputsL, modelInputsR, genKey(), void 0, void 0, void 0, [inputAtMax])
3069
+ );
3070
+ }
3071
+ return resolvedScenarios;
3072
+ }
3073
+ function resolveScenarioWithAllInputsAtPosition(key, id, title, subtitle, position) {
3074
+ const settings = {
3075
+ kind: "all-inputs-settings",
3076
+ position
3077
+ };
3078
+ const [specL, specR] = scenarioSpecsFromSettings(settings);
3079
+ return {
3080
+ kind: "scenario",
3081
+ key,
3082
+ id,
3083
+ title,
3084
+ subtitle,
3085
+ settings,
3086
+ specL,
3087
+ specR
3088
+ };
3089
+ }
3090
+ function resolveScenarioForInputSpecs(modelInputsL, modelInputsR, key, id, title, subtitle, inputSpecs) {
3091
+ const resolvedInputs = inputSpecs.map((inputSpec) => {
3092
+ switch (inputSpec.kind) {
3093
+ case "input-at-position":
3094
+ return resolveInputForName(modelInputsL, modelInputsR, inputSpec.inputName, inputSpec.position);
3095
+ case "input-at-value":
3096
+ return resolveInputForName(modelInputsL, modelInputsR, inputSpec.inputName, inputSpec.value);
3097
+ default:
3098
+ (0, import_assert_never11.assertNever)(inputSpec);
3099
+ }
3100
+ });
3101
+ const settings = {
3102
+ kind: "input-settings",
3103
+ inputs: resolvedInputs
3104
+ };
3105
+ const [specL, specR] = scenarioSpecsFromSettings(settings);
3106
+ return {
3107
+ kind: "scenario",
3108
+ key,
3109
+ id,
3110
+ title,
3111
+ subtitle,
3112
+ settings,
3113
+ specL,
3114
+ specR
3115
+ };
3116
+ }
3117
+ function resolveInputForName(modelInputsL, modelInputsR, inputName, at) {
3118
+ return {
3119
+ requestedName: inputName,
3120
+ stateL: resolveInputForNameInModel(modelInputsL, inputName, at),
3121
+ stateR: resolveInputForNameInModel(modelInputsR, inputName, at)
3122
+ };
3123
+ }
3124
+ function resolveInputForNameInModel(modelInputs, inputName, at) {
3125
+ const inputVar = modelInputs.getInputVarForName(inputName);
3126
+ if (inputVar) {
3127
+ return resolveInputVar(inputVar, at);
3128
+ } else {
3129
+ return {
3130
+ error: {
3131
+ kind: "unknown-input"
3132
+ }
3133
+ };
3134
+ }
3135
+ }
3136
+ function resolveInputVar(inputVar, at) {
3137
+ if (typeof at === "number") {
3138
+ const value = at;
3139
+ return resolveInputVarAtValue(inputVar, value);
3140
+ } else {
3141
+ const position = inputPosition2(at);
3142
+ return resolveInputVarAtPosition(inputVar, position);
3143
+ }
3144
+ }
3145
+ function resolveInputVarAtPosition(inputVar, position) {
3146
+ return {
3147
+ inputVar,
3148
+ position,
3149
+ value: inputValueAtPosition2(inputVar, position)
3150
+ };
3151
+ }
3152
+ function resolveInputVarAtValue(inputVar, value) {
3153
+ if (value >= inputVar.minValue && value <= inputVar.maxValue) {
3154
+ return {
3155
+ inputVar,
3156
+ value
3157
+ };
3158
+ } else {
3159
+ return {
3160
+ error: {
3161
+ kind: "invalid-value"
3162
+ }
3163
+ };
3164
+ }
3165
+ }
3166
+ function inputPosition2(position) {
3167
+ switch (position) {
3168
+ case "default":
3169
+ return "at-default";
3170
+ case "min":
3171
+ return "at-minimum";
3172
+ case "max":
3173
+ return "at-maximum";
3174
+ default:
3175
+ return void 0;
3176
+ }
3177
+ }
3178
+ function inputValueAtPosition2(inputVar, position) {
3179
+ switch (position) {
3180
+ case "at-default":
3181
+ return inputVar.defaultValue;
3182
+ case "at-minimum":
3183
+ return inputVar.minValue;
3184
+ case "at-maximum":
3185
+ return inputVar.maxValue;
3186
+ default:
3187
+ (0, import_assert_never11.assertNever)(position);
3188
+ }
3189
+ }
3190
+ var ResolvedScenarioGroups = class {
3191
+ constructor() {
3192
+ this.resolvedGroups = [];
3193
+ this.resolvedGroupsById = /* @__PURE__ */ new Map();
3194
+ }
3195
+ add(group) {
3196
+ this.resolvedGroups.push(group);
3197
+ if (group.id !== void 0) {
3198
+ if (this.resolvedGroupsById.has(group.id)) {
3199
+ throw new Error(`Multiple scenario groups defined with the same id (${group.id})`);
3200
+ }
3201
+ this.resolvedGroupsById.set(group.id, group);
3202
+ }
3203
+ }
3204
+ getAll() {
3205
+ return this.resolvedGroups;
3206
+ }
3207
+ getGroupForId(id) {
3208
+ return this.resolvedGroupsById.get(id);
3209
+ }
3210
+ };
3211
+ function resolveGraphsFromSpec(graphsSpec) {
3212
+ switch (graphsSpec.kind) {
3213
+ case "graphs-preset":
3214
+ return "all";
3215
+ case "graphs-array":
3216
+ return graphsSpec.graphIds;
3217
+ default:
3218
+ (0, import_assert_never11.assertNever)(graphsSpec);
3219
+ }
3220
+ }
3221
+ function resolveViewForScenarioId(resolvedScenarios, viewTitle, viewSubtitle, scenarioId, graphs) {
3222
+ const resolvedScenario = resolvedScenarios.getScenarioForId(scenarioId);
3223
+ if (resolvedScenario) {
3224
+ return resolveViewForScenario(viewTitle, viewSubtitle, resolvedScenario, graphs);
3225
+ } else {
3226
+ return unresolvedViewForScenarioId(viewTitle, viewSubtitle, scenarioId);
3227
+ }
3228
+ }
3229
+ function resolveViewForScenarioRefSpec(resolvedScenarios, refSpec, graphs) {
3230
+ const resolvedScenario = resolvedScenarios.getScenarioForId(refSpec.scenarioId);
3231
+ if (resolvedScenario) {
3232
+ return resolveViewForScenario(refSpec.title, refSpec.subtitle, resolvedScenario, graphs);
3233
+ } else {
3234
+ return unresolvedViewForScenarioId(void 0, void 0, refSpec.scenarioId);
3235
+ }
3236
+ }
3237
+ function resolveViewForScenario(viewTitle, viewSubtitle, resolvedScenario, graphs) {
3238
+ if (viewTitle === void 0) {
3239
+ viewTitle = resolvedScenario.title;
3240
+ if (viewTitle === void 0) {
3241
+ viewTitle = "Untitled view";
3242
+ }
3243
+ if (viewSubtitle === void 0) {
3244
+ viewSubtitle = resolvedScenario.subtitle;
3245
+ }
3246
+ }
3247
+ return {
3248
+ kind: "view",
3249
+ title: viewTitle,
3250
+ subtitle: viewSubtitle,
3251
+ scenario: resolvedScenario,
3252
+ graphs
3253
+ };
3254
+ }
3255
+ function unresolvedViewForScenarioId(viewTitle, viewSubtitle, scenarioId) {
3256
+ return {
3257
+ kind: "unresolved-view",
3258
+ title: viewTitle,
3259
+ subtitle: viewSubtitle,
3260
+ scenarioId
3261
+ };
3262
+ }
3263
+ function unresolvedViewForScenarioGroupId(viewTitle, viewSubtitle, scenarioGroupId) {
3264
+ return {
3265
+ kind: "unresolved-view",
3266
+ title: viewTitle,
3267
+ subtitle: viewSubtitle,
3268
+ scenarioGroupId
3269
+ };
3270
+ }
3271
+ function resolveViewGroupFromSpec(resolvedScenarios, resolvedScenarioGroups, viewGroupSpec) {
3272
+ let views;
3273
+ switch (viewGroupSpec.kind) {
3274
+ case "view-group-with-views": {
3275
+ views = viewGroupSpec.views.map((viewSpec) => {
3276
+ const graphs = resolveGraphsFromSpec(viewSpec.graphs);
3277
+ return resolveViewForScenarioId(
3278
+ resolvedScenarios,
3279
+ viewSpec.title,
3280
+ viewSpec.subtitle,
3281
+ viewSpec.scenarioId,
3282
+ graphs
3283
+ );
3284
+ });
3285
+ break;
3286
+ }
3287
+ case "view-group-with-scenarios": {
3288
+ const graphs = resolveGraphsFromSpec(viewGroupSpec.graphs);
3289
+ views = [];
3290
+ for (const refSpec of viewGroupSpec.scenarios) {
3291
+ switch (refSpec.kind) {
3292
+ case "scenario-ref":
3293
+ views.push(resolveViewForScenarioRefSpec(resolvedScenarios, refSpec, graphs));
3294
+ break;
3295
+ case "scenario-group-ref": {
3296
+ const resolvedGroup = resolvedScenarioGroups.getGroupForId(refSpec.groupId);
3297
+ if (resolvedGroup) {
3298
+ for (const scenario of resolvedGroup.scenarios) {
3299
+ switch (scenario.kind) {
3300
+ case "unresolved-scenario-ref":
3301
+ views.push(unresolvedViewForScenarioId(void 0, void 0, scenario.scenarioId));
3302
+ break;
3303
+ case "scenario":
3304
+ views.push(resolveViewForScenario(void 0, void 0, scenario, graphs));
3305
+ break;
3306
+ default:
3307
+ (0, import_assert_never11.assertNever)(scenario);
3308
+ }
3309
+ }
3310
+ } else {
3311
+ views.push(unresolvedViewForScenarioGroupId(void 0, void 0, refSpec.groupId));
3312
+ }
3313
+ break;
3314
+ }
3315
+ default:
3316
+ (0, import_assert_never11.assertNever)(refSpec);
3317
+ }
3318
+ }
3319
+ break;
3320
+ }
3321
+ default:
3322
+ (0, import_assert_never11.assertNever)(viewGroupSpec);
3323
+ }
3324
+ return {
3325
+ kind: "view-group",
3326
+ title: viewGroupSpec.title,
3327
+ views
3328
+ };
3329
+ }
3330
+
3331
+ // src/comparison/config/comparison-config.ts
3332
+ function resolveComparisonSpecsFromSources(modelInputsL, modelInputsR, specSources) {
3333
+ const combinedSpecs = {
3334
+ scenarios: [],
3335
+ scenarioGroups: [],
3336
+ viewGroups: []
3337
+ };
3338
+ for (const specSource of specSources) {
3339
+ let specs;
3340
+ if ("kind" in specSource) {
3341
+ const parseResult = parseComparisonSpecs(specSource);
3342
+ if (parseResult.isOk()) {
3343
+ specs = parseResult.value;
3344
+ } else {
3345
+ const filenamePart = specSource.filename ? ` in ${specSource.filename}` : "";
3346
+ console.error(`ERROR: Failed to parse comparison spec${filenamePart}, skipping`);
3347
+ continue;
3348
+ }
3349
+ } else {
3350
+ specs = specSource;
3351
+ }
3352
+ combinedSpecs.scenarios.push(...specs.scenarios);
3353
+ combinedSpecs.scenarioGroups.push(...specs.scenarioGroups);
3354
+ combinedSpecs.viewGroups.push(...specs.viewGroups);
3355
+ }
3356
+ return resolveComparisonSpecs(modelInputsL, modelInputsR, combinedSpecs);
3357
+ }
3358
+
3359
+ // src/comparison/config/comparison-datasets.ts
3360
+ function getComparisonDatasets(modelSpecL, modelSpecR, datasetOptions) {
3361
+ return new ComparisonDatasetsImpl(modelSpecL, modelSpecR, datasetOptions);
3362
+ }
3363
+ var ComparisonDatasetsImpl = class {
3364
+ constructor(modelSpecL, modelSpecR, datasetOptions) {
3365
+ this.datasetOptions = datasetOptions;
3366
+ const renamedDatasetKeys = datasetOptions == null ? void 0 : datasetOptions.renamedDatasetKeys;
3367
+ const invertedRenamedKeys = /* @__PURE__ */ new Map();
3368
+ renamedDatasetKeys == null ? void 0 : renamedDatasetKeys.forEach((newKey, oldKey) => {
3369
+ invertedRenamedKeys.set(newKey, oldKey);
3370
+ });
3371
+ function leftKeyForRightKey(rightKey) {
3372
+ return invertedRenamedKeys.get(rightKey) || rightKey;
3373
+ }
3374
+ const allOutputVarKeysSet = /* @__PURE__ */ new Set();
3375
+ const modelOutputVarKeysSet = /* @__PURE__ */ new Set();
2247
3376
  function addOutputVars(outputVars, handleRenames) {
2248
3377
  outputVars.forEach((outputVar, key) => {
2249
3378
  const remappedKey = handleRenames ? leftKeyForRightKey(key) : key;
@@ -2253,239 +3382,193 @@ var DatasetManager = class {
2253
3382
  }
2254
3383
  });
2255
3384
  }
2256
- addOutputVars(bundleL.modelSpec.outputVars, false);
2257
- addOutputVars(bundleR.modelSpec.outputVars, true);
3385
+ addOutputVars(modelSpecL.outputVars, false);
3386
+ addOutputVars(modelSpecR.outputVars, true);
2258
3387
  this.allOutputVarKeys = Array.from(allOutputVarKeysSet);
2259
3388
  this.modelOutputVarKeys = Array.from(modelOutputVarKeysSet);
2260
- }
2261
- getDatasetKeysForScenario(scenario) {
2262
- if (scenario.kind === "all-inputs" && scenario.position === "at-default") {
2263
- return this.allOutputVarKeys;
2264
- } else {
2265
- return this.modelOutputVarKeys;
3389
+ this.allDatasets = /* @__PURE__ */ new Map();
3390
+ for (const datasetKeyL of this.allOutputVarKeys) {
3391
+ const datasetKeyR = (renamedDatasetKeys == null ? void 0 : renamedDatasetKeys.get(datasetKeyL)) || datasetKeyL;
3392
+ const outputVarL = modelSpecL.outputVars.get(datasetKeyL);
3393
+ const outputVarR = modelSpecR.outputVars.get(datasetKeyR);
3394
+ this.allDatasets.set(datasetKeyL, {
3395
+ kind: "dataset",
3396
+ key: datasetKeyL,
3397
+ outputVarL,
3398
+ outputVarR
3399
+ });
2266
3400
  }
2267
3401
  }
2268
- getDatasetInfo(datasetKey) {
3402
+ getAllDatasets() {
3403
+ return this.allDatasets.values();
3404
+ }
3405
+ getDataset(datasetKey) {
3406
+ return this.allDatasets.get(datasetKey);
3407
+ }
3408
+ getDatasetKeysForScenario(scenario) {
2269
3409
  var _a;
2270
- const modelSpecL = this.bundleL.modelSpec;
2271
- const modelSpecR = this.bundleR.modelSpec;
2272
- const datasetKeyL = datasetKey;
2273
- const datasetKeyR = ((_a = this.renamedDatasetKeys) == null ? void 0 : _a.get(datasetKeyL)) || datasetKeyL;
2274
- const outputVarL = modelSpecL.outputVars.get(datasetKeyL);
2275
- const outputVarR = modelSpecR.outputVars.get(datasetKeyR);
2276
- let varName;
2277
- let newVarName;
2278
- let sourceName;
2279
- let newSourceName;
2280
- if (outputVarL && outputVarR && outputVarL.varName != outputVarR.varName) {
2281
- varName = outputVarL.varName;
2282
- newVarName = outputVarR.varName;
2283
- } else {
2284
- const outputVar = outputVarR || outputVarL;
2285
- varName = (outputVar == null ? void 0 : outputVar.varName) || "Unknown";
2286
- }
2287
- if (outputVarL && outputVarR && outputVarL.sourceName != outputVarR.sourceName) {
2288
- sourceName = outputVarL.sourceName;
2289
- newSourceName = outputVarR.sourceName;
3410
+ if (((_a = this.datasetOptions) == null ? void 0 : _a.datasetKeysForScenario) !== void 0) {
3411
+ return this.datasetOptions.datasetKeysForScenario(this.allOutputVarKeys, scenario);
2290
3412
  } else {
2291
- const outputVar = outputVarR || outputVarL;
2292
- sourceName = outputVar == null ? void 0 : outputVar.sourceName;
3413
+ if (scenario.settings.kind === "all-inputs-settings" && scenario.settings.position === "at-default") {
3414
+ return this.allOutputVarKeys;
3415
+ } else {
3416
+ return this.modelOutputVarKeys;
3417
+ }
2293
3418
  }
2294
- return {
2295
- varName,
2296
- newVarName,
2297
- sourceName,
2298
- newSourceName,
2299
- relatedItems: (outputVarR == null ? void 0 : outputVarR.relatedItems) || []
2300
- };
2301
3419
  }
2302
3420
  };
2303
3421
 
2304
- // src/config/scenario-manager.ts
2305
- var import_assert_never8 = require("assert-never");
2306
- var ScenarioManager = class {
2307
- constructor(bundleL, bundleR) {
2308
- this.bundleL = bundleL;
2309
- this.bundleR = bundleR;
2310
- this.scenarios = /* @__PURE__ */ new Map();
2311
- this.scenarioInfo = /* @__PURE__ */ new Map();
2312
- this.defaultInfoForGroup = /* @__PURE__ */ new Map();
2313
- this.groupInfo = /* @__PURE__ */ new Map();
2314
- }
2315
- getScenarios() {
2316
- return [...this.scenarios.values()];
2317
- }
2318
- getScenario(scenarioKey) {
2319
- return this.scenarios.get(scenarioKey);
2320
- }
2321
- getScenarioGroupInfo(groupKey) {
2322
- return this.groupInfo.get(groupKey);
2323
- }
2324
- getScenarioInfo(scenario, groupKey) {
2325
- if (scenario.key === "all_inputs_at_default") {
2326
- const defaultInfo = this.defaultInfoForGroup.get(groupKey);
2327
- if (defaultInfo) {
2328
- return defaultInfo;
2329
- }
2330
- }
2331
- return this.scenarioInfo.get(scenario.key);
2332
- }
2333
- setDefaultScenarioInfoForGroup(groupKey, scenarioInfo) {
2334
- this.defaultInfoForGroup.set(groupKey, scenarioInfo);
2335
- }
2336
- addScenario(scenario, scenarioInfo, groupInfo) {
2337
- this.scenarios.set(scenario.key, scenario);
2338
- if (!scenarioInfo) {
2339
- scenarioInfo = this.getInfoForScenario(scenario);
2340
- }
2341
- this.scenarioInfo.set(scenario.key, scenarioInfo);
2342
- if (!groupInfo) {
2343
- groupInfo = this.getGroupInfoForScenario(scenario);
2344
- }
2345
- this.groupInfo.set(scenario.groupKey, groupInfo);
2346
- }
2347
- addScenarioMatrix() {
2348
- const inputVarIdsL = Array.from(this.bundleL.modelSpec.inputVars.keys());
2349
- const inputVarIdsR = Array.from(this.bundleR.modelSpec.inputVars.keys());
2350
- const inputVarIds = /* @__PURE__ */ new Set([...inputVarIdsL, ...inputVarIdsR]);
2351
- this.addScenario(allInputsAtPositionScenario("at-default"));
2352
- this.addScenario(allInputsAtPositionScenario("at-minimum"));
2353
- this.addScenario(allInputsAtPositionScenario("at-maximum"));
2354
- for (const inputVarId of inputVarIds) {
2355
- this.addScenario(inputAtPositionScenario(inputVarId, inputVarId, "at-minimum"));
2356
- this.addScenario(inputAtPositionScenario(inputVarId, inputVarId, "at-maximum"));
2357
- }
2358
- }
2359
- getGroupInfoForScenario(scenario) {
2360
- switch (scenario.kind) {
2361
- case "all-inputs":
2362
- return {
2363
- title: "All Inputs",
2364
- relatedItems: []
2365
- };
2366
- case "settings":
2367
- if (scenario.settings.length === 1) {
2368
- const inputVar = this.getInputVarForSetting(scenario.settings[0]);
2369
- let relatedItems;
2370
- let subtitle;
2371
- if (inputVar == null ? void 0 : inputVar.relatedItem) {
2372
- relatedItems = [inputVar.relatedItem];
2373
- subtitle = inputVar.relatedItem.locationPath.join('&nbsp;<span class="related-sep">&gt;</span>&nbsp;');
2374
- } else {
2375
- relatedItems = [];
2376
- subtitle = void 0;
2377
- }
2378
- return {
2379
- title: (inputVar == null ? void 0 : inputVar.varName) || "Unknown Input",
2380
- subtitle,
2381
- relatedItems
2382
- };
2383
- } else {
2384
- return {
2385
- title: "Multiple Inputs",
2386
- relatedItems: this.getRelatedItemsForSettings(scenario.settings)
2387
- };
2388
- }
2389
- default:
2390
- (0, import_assert_never8.assertNever)(scenario);
3422
+ // src/comparison/config/comparison-scenarios.ts
3423
+ function getComparisonScenarios(scenarios) {
3424
+ return new ComparisonScenariosImpl(scenarios);
3425
+ }
3426
+ var ComparisonScenariosImpl = class {
3427
+ constructor(scenarios) {
3428
+ this.scenarioDefs = /* @__PURE__ */ new Map();
3429
+ for (const scenario of scenarios) {
3430
+ this.scenarioDefs.set(scenario.key, scenario);
2391
3431
  }
2392
3432
  }
2393
- getInfoForScenario(scenario) {
2394
- switch (scenario.kind) {
2395
- case "all-inputs":
2396
- return this.getInfoForPositionSetting(void 0, scenario.position);
2397
- case "settings":
2398
- if (scenario.settings.length === 1 && scenario.settings[0].kind === "position") {
2399
- const setting = scenario.settings[0];
2400
- return this.getInfoForPositionSetting(setting.inputVarId, setting.position);
2401
- } else {
2402
- return {
2403
- title: `PLACEHOLDER (scenario info not provided)`,
2404
- position: 1
2405
- };
2406
- }
2407
- default:
2408
- (0, import_assert_never8.assertNever)(scenario);
2409
- }
3433
+ getAllScenarios() {
3434
+ return this.scenarioDefs.values();
2410
3435
  }
2411
- getInfoForPositionSetting(inputVarId, inputPosition2) {
2412
- const title = inputPosition2.replace("-", " ");
2413
- let subtitle;
2414
- if (inputVarId) {
2415
- const inputVarL = this.bundleL.modelSpec.inputVars.get(inputVarId);
2416
- const inputVarR = this.bundleR.modelSpec.inputVars.get(inputVarId);
2417
- const valueL = inputValue(inputVarL, inputPosition2);
2418
- const valueR = inputValue(inputVarR, inputPosition2);
2419
- if (valueL !== valueR) {
2420
- let values = "";
2421
- values += "(";
2422
- values += `<span class='dataset-color-0'>${valueL}</span>`;
2423
- values += "&nbsp;|&nbsp;";
2424
- values += `<span class='dataset-color-1'>${valueR}</span>`;
2425
- values += ")";
2426
- subtitle = values;
3436
+ getScenario(key) {
3437
+ return this.scenarioDefs.get(key);
3438
+ }
3439
+ };
3440
+
3441
+ // src/config/synchronized-model.ts
3442
+ function synchronizedBundleModel(sourceModel) {
3443
+ const promiseQueue = new PromiseQueue();
3444
+ return {
3445
+ modelSpec: sourceModel.modelSpec,
3446
+ getDatasetsForScenario: (scenarioSpec, datasetKeys) => {
3447
+ return promiseQueue.add(() => sourceModel.getDatasetsForScenario(scenarioSpec, datasetKeys));
3448
+ },
3449
+ getGraphDataForScenario: (scenarioSpec, graphId) => {
3450
+ return promiseQueue.add(() => sourceModel.getGraphDataForScenario(scenarioSpec, graphId));
3451
+ },
3452
+ getGraphLinksForScenario: sourceModel.getGraphLinksForScenario.bind(sourceModel)
3453
+ };
3454
+ }
3455
+ var PromiseQueue = class {
3456
+ constructor() {
3457
+ this.tasks = [];
3458
+ this.runningCount = 0;
3459
+ }
3460
+ add(f) {
3461
+ return new Promise((resolve, reject) => {
3462
+ const run = async () => {
3463
+ this.runningCount++;
3464
+ const promise = f();
3465
+ try {
3466
+ const result = await promise;
3467
+ resolve(result);
3468
+ } catch (e) {
3469
+ reject(e);
3470
+ } finally {
3471
+ this.runningCount--;
3472
+ this.runNext();
3473
+ }
3474
+ };
3475
+ if (this.runningCount < 1) {
3476
+ run();
2427
3477
  } else {
2428
- subtitle = `(${valueL})`;
3478
+ this.tasks.push(run);
2429
3479
  }
2430
- } else {
2431
- subtitle = void 0;
2432
- }
2433
- let position;
2434
- switch (inputPosition2) {
2435
- case "at-default":
2436
- position = 0;
2437
- break;
2438
- case "at-minimum":
2439
- position = 1;
2440
- break;
2441
- case "at-maximum":
2442
- position = 2;
2443
- break;
2444
- default:
2445
- (0, import_assert_never8.assertNever)(inputPosition2);
2446
- }
2447
- return {
2448
- title,
2449
- subtitle,
2450
- position
2451
- };
3480
+ });
2452
3481
  }
2453
- getRelatedItemsForSettings(settings) {
2454
- const relatedItems = [];
2455
- for (const setting of settings) {
2456
- const inputVar = this.getInputVarForSetting(setting);
2457
- if (inputVar == null ? void 0 : inputVar.relatedItem) {
2458
- relatedItems.push(inputVar.relatedItem);
3482
+ runNext() {
3483
+ if (this.tasks.length > 0) {
3484
+ const task = this.tasks.shift();
3485
+ if (task) {
3486
+ task();
2459
3487
  }
2460
3488
  }
2461
- return relatedItems;
2462
- }
2463
- getInputVarForSetting(setting) {
2464
- const inputVarId = setting.inputVarId;
2465
- const inputVarL = this.bundleL.modelSpec.inputVars.get(inputVarId);
2466
- const inputVarR = this.bundleR.modelSpec.inputVars.get(inputVarId);
2467
- return inputVarR || inputVarL;
2468
3489
  }
2469
3490
  };
2470
- function inputValue(inputVar, position) {
2471
- if (inputVar) {
2472
- switch (position) {
2473
- case "at-default":
2474
- return inputVar.defaultValue.toString();
2475
- case "at-minimum":
2476
- return inputVar.minValue.toString();
2477
- case "at-maximum":
2478
- return inputVar.maxValue.toString();
2479
- default:
2480
- (0, import_assert_never8.assertNever)(position);
2481
- }
3491
+
3492
+ // src/config/config.ts
3493
+ async function createConfig(options) {
3494
+ var _a;
3495
+ const origCurrentBundle = await loadSynchronized(options.current);
3496
+ let currentBundle;
3497
+ let comparisonConfig;
3498
+ if (options.comparison === void 0) {
3499
+ currentBundle = origCurrentBundle;
2482
3500
  } else {
2483
- return "n/a";
3501
+ const baselineBundle = await loadSynchronized(options.comparison.baseline);
3502
+ const renamedDatasetKeys = (_a = options.comparison.datasets) == null ? void 0 : _a.renamedDatasetKeys;
3503
+ const invertedRenamedKeys = /* @__PURE__ */ new Map();
3504
+ renamedDatasetKeys == null ? void 0 : renamedDatasetKeys.forEach((newKey, oldKey) => {
3505
+ invertedRenamedKeys.set(newKey, oldKey);
3506
+ });
3507
+ const rightKeyForLeftKey = (leftKey) => {
3508
+ return (renamedDatasetKeys == null ? void 0 : renamedDatasetKeys.get(leftKey)) || leftKey;
3509
+ };
3510
+ const leftKeyForRightKey = (rightKey) => {
3511
+ return invertedRenamedKeys.get(rightKey) || rightKey;
3512
+ };
3513
+ const origBundleModelR = origCurrentBundle.model;
3514
+ const adjBundleModelR = {
3515
+ modelSpec: origBundleModelR.modelSpec,
3516
+ getDatasetsForScenario: async (scenarioSpec, datasetKeys) => {
3517
+ const rightKeys = datasetKeys.map(rightKeyForLeftKey);
3518
+ const result = await origBundleModelR.getDatasetsForScenario(scenarioSpec, rightKeys);
3519
+ const mapWithRightKeys = result.datasetMap;
3520
+ const mapWithLeftKeys = /* @__PURE__ */ new Map();
3521
+ for (const [rightKey, dataset] of mapWithRightKeys.entries()) {
3522
+ const leftKey = leftKeyForRightKey(rightKey);
3523
+ mapWithLeftKeys.set(leftKey, dataset);
3524
+ }
3525
+ return {
3526
+ datasetMap: mapWithLeftKeys,
3527
+ modelRunTime: result.modelRunTime
3528
+ };
3529
+ },
3530
+ getGraphDataForScenario: origBundleModelR.getGraphDataForScenario.bind(origBundleModelR),
3531
+ getGraphLinksForScenario: origBundleModelR.getGraphLinksForScenario.bind(origBundleModelR)
3532
+ };
3533
+ currentBundle = {
3534
+ ...origCurrentBundle,
3535
+ model: adjBundleModelR
3536
+ };
3537
+ const modelSpecL = baselineBundle.model.modelSpec;
3538
+ const modelSpecR = currentBundle.model.modelSpec;
3539
+ const modelInputsL = new ModelInputs(modelSpecL);
3540
+ const modelInputsR = new ModelInputs(modelSpecR);
3541
+ const comparisonDefs = resolveComparisonSpecsFromSources(modelInputsL, modelInputsR, options.comparison.specs);
3542
+ comparisonConfig = {
3543
+ bundleL: baselineBundle,
3544
+ bundleR: currentBundle,
3545
+ thresholds: options.comparison.thresholds,
3546
+ scenarios: getComparisonScenarios(comparisonDefs.scenarios),
3547
+ datasets: getComparisonDatasets(modelSpecL, modelSpecR, options.comparison.datasets),
3548
+ viewGroups: comparisonDefs.viewGroups
3549
+ };
2484
3550
  }
3551
+ const checkConfig = {
3552
+ bundle: currentBundle,
3553
+ tests: options.check.tests
3554
+ };
3555
+ return {
3556
+ check: checkConfig,
3557
+ comparison: comparisonConfig
3558
+ };
3559
+ }
3560
+ async function loadSynchronized(sourceBundle) {
3561
+ const sourceModel = await sourceBundle.bundle.initModel();
3562
+ const synchronizedModel = synchronizedBundleModel(sourceModel);
3563
+ return {
3564
+ name: sourceBundle.name,
3565
+ version: sourceBundle.bundle.version,
3566
+ model: synchronizedModel
3567
+ };
2485
3568
  }
2486
3569
 
2487
3570
  // src/perf/perf-runner.ts
2488
- var import_assert_never9 = require("assert-never");
3571
+ var import_assert_never12 = require("assert-never");
2489
3572
 
2490
3573
  // src/perf/perf-stats.ts
2491
3574
  var PerfStats = class {
@@ -2529,26 +3612,26 @@ var PerfRunner = class {
2529
3612
  this.bundleModelL = bundleModelL;
2530
3613
  this.bundleModelR = bundleModelR;
2531
3614
  this.mode = mode;
2532
- const scenario = allInputsAtPositionScenario("at-default");
3615
+ const scenarioSpec = allInputsAtPositionSpec("at-default");
2533
3616
  this.taskQueue = new TaskQueue({
2534
3617
  process: async (request) => {
2535
3618
  switch (request.kind) {
2536
3619
  case "left": {
2537
- const result = await bundleModelL.getDatasetsForScenario(scenario, []);
3620
+ const result = await bundleModelL.getDatasetsForScenario(scenarioSpec, []);
2538
3621
  return {
2539
3622
  runTimeL: result.modelRunTime
2540
3623
  };
2541
3624
  }
2542
3625
  case "right": {
2543
- const result = await bundleModelR.getDatasetsForScenario(scenario, []);
3626
+ const result = await bundleModelR.getDatasetsForScenario(scenarioSpec, []);
2544
3627
  return {
2545
3628
  runTimeR: result.modelRunTime
2546
3629
  };
2547
3630
  }
2548
3631
  case "both": {
2549
3632
  const [resultL, resultR] = await Promise.all([
2550
- bundleModelL.getDatasetsForScenario(scenario, []),
2551
- bundleModelR.getDatasetsForScenario(scenario, [])
3633
+ bundleModelL.getDatasetsForScenario(scenarioSpec, []),
3634
+ bundleModelR.getDatasetsForScenario(scenarioSpec, [])
2552
3635
  ]);
2553
3636
  return {
2554
3637
  runTimeL: resultL.modelRunTime,
@@ -2556,7 +3639,7 @@ var PerfRunner = class {
2556
3639
  };
2557
3640
  }
2558
3641
  default:
2559
- (0, import_assert_never9.assertNever)(request.kind);
3642
+ (0, import_assert_never12.assertNever)(request.kind);
2560
3643
  }
2561
3644
  }
2562
3645
  });
@@ -2604,46 +3687,126 @@ var PerfRunner = class {
2604
3687
  }
2605
3688
  };
2606
3689
 
2607
- // src/suite/suite-runner.ts
2608
- var import_assert_never10 = __toESM(require("assert-never"), 1);
2609
-
2610
3690
  // src/data/data-planner.ts
2611
- var ScenarioTaskSet = class {
2612
- constructor(scenario) {
2613
- this.scenario = scenario;
2614
- this.modelTasks = /* @__PURE__ */ new Map();
2615
- this.modelImplTasks = /* @__PURE__ */ new Map();
2616
- this.requestKind = "check";
3691
+ var DataPlanner = class {
3692
+ constructor(batchSize) {
3693
+ this.batchSize = batchSize;
3694
+ this.taskSetsLR = /* @__PURE__ */ new Map();
3695
+ this.taskSetsL = /* @__PURE__ */ new Map();
3696
+ this.taskSetsR = /* @__PURE__ */ new Map();
3697
+ this.complete = false;
2617
3698
  }
2618
- addTask(kind, datasetKey, dataFunc) {
2619
- if (kind === "compare") {
2620
- this.requestKind = "compare";
3699
+ addRequest(scenarioSpecL, scenarioSpecR, datasetKey, dataAction) {
3700
+ if (scenarioSpecL === void 0 && scenarioSpecR === void 0) {
3701
+ console.warn("WARNING: Both scenario specs are undefined for DataPlanner request, skipping");
3702
+ return;
3703
+ }
3704
+ let taskSetsMap;
3705
+ let uid;
3706
+ if (scenarioSpecL && scenarioSpecR) {
3707
+ taskSetsMap = this.taskSetsLR;
3708
+ uid = scenarioPairUid(scenarioSpecL, scenarioSpecR);
3709
+ } else if (scenarioSpecR) {
3710
+ taskSetsMap = this.taskSetsR;
3711
+ uid = scenarioSpecR.uid;
3712
+ } else {
3713
+ taskSetsMap = this.taskSetsL;
3714
+ uid = scenarioSpecL.uid;
2621
3715
  }
2622
- const dataTask = {
3716
+ let taskSet = taskSetsMap.get(uid);
3717
+ if (!taskSet) {
3718
+ taskSet = new DataTaskSet(scenarioSpecL, scenarioSpecR);
3719
+ taskSetsMap.set(uid, taskSet);
3720
+ }
3721
+ taskSet.addTask({
2623
3722
  datasetKey,
2624
- dataFunc
3723
+ dataAction
3724
+ });
3725
+ }
3726
+ buildPlan() {
3727
+ if (this.complete) {
3728
+ throw new Error("DataPlanner.buildPlan() can only be called once");
3729
+ }
3730
+ this.complete = true;
3731
+ const lKeyMappings = /* @__PURE__ */ new Map();
3732
+ const rKeyMappings = /* @__PURE__ */ new Map();
3733
+ for (const lrUid of this.taskSetsLR.keys()) {
3734
+ const [lUid, rUid] = lrUid.split("::");
3735
+ if (!lKeyMappings.has(lUid)) {
3736
+ lKeyMappings.set(lUid, lrUid);
3737
+ }
3738
+ if (!rKeyMappings.has(rUid)) {
3739
+ rKeyMappings.set(rUid, lrUid);
3740
+ }
3741
+ }
3742
+ function merge(taskSetsLR, taskSetsForSide, keyMappingsForSide) {
3743
+ for (const [keyForSide, taskSetForSide] of taskSetsForSide.entries()) {
3744
+ const lrKey = keyMappingsForSide.get(keyForSide);
3745
+ if (lrKey) {
3746
+ const taskSetLR = taskSetsLR.get(lrKey);
3747
+ taskSetLR.merge(taskSetForSide);
3748
+ taskSetsForSide.delete(keyForSide);
3749
+ }
3750
+ }
3751
+ }
3752
+ merge(this.taskSetsLR, this.taskSetsL, lKeyMappings);
3753
+ merge(this.taskSetsLR, this.taskSetsR, rKeyMappings);
3754
+ const requests = [];
3755
+ const batchSize = this.batchSize;
3756
+ function addRequests(taskSets) {
3757
+ for (const taskSet of taskSets) {
3758
+ requests.push(...taskSet.buildRequests(batchSize));
3759
+ }
3760
+ }
3761
+ addRequests(this.taskSetsLR.values());
3762
+ addRequests(this.taskSetsL.values());
3763
+ addRequests(this.taskSetsR.values());
3764
+ return {
3765
+ requests
2625
3766
  };
3767
+ }
3768
+ };
3769
+ var DataTaskSet = class {
3770
+ constructor(scenarioSpecL, scenarioSpecR) {
3771
+ this.scenarioSpecL = scenarioSpecL;
3772
+ this.scenarioSpecR = scenarioSpecR;
3773
+ this.modelTasks = /* @__PURE__ */ new Map();
3774
+ this.modelImplTasks = /* @__PURE__ */ new Map();
3775
+ }
3776
+ addTask(dataTask) {
2626
3777
  let taskMap;
2627
- if (datasetKey.startsWith("ModelImpl")) {
3778
+ if (dataTask.datasetKey.startsWith("ModelImpl")) {
2628
3779
  taskMap = this.modelImplTasks;
2629
3780
  } else {
2630
3781
  taskMap = this.modelTasks;
2631
3782
  }
2632
- let tasks = taskMap.get(datasetKey);
3783
+ let tasks = taskMap.get(dataTask.datasetKey);
2633
3784
  if (!tasks) {
2634
3785
  tasks = [];
2635
- taskMap.set(datasetKey, tasks);
3786
+ taskMap.set(dataTask.datasetKey, tasks);
2636
3787
  }
2637
3788
  tasks.push(dataTask);
2638
3789
  }
3790
+ merge(otherTaskSet) {
3791
+ for (const tasks of otherTaskSet.modelTasks.values()) {
3792
+ for (const task of tasks) {
3793
+ this.addTask(task);
3794
+ }
3795
+ }
3796
+ for (const tasks of otherTaskSet.modelImplTasks.values()) {
3797
+ for (const task of tasks) {
3798
+ this.addTask(task);
3799
+ }
3800
+ }
3801
+ }
2639
3802
  buildRequests(batchSize) {
2640
3803
  const dataRequests = [];
2641
3804
  if (this.modelTasks.size > 0) {
2642
3805
  const dataTasks = [];
2643
3806
  this.modelTasks.forEach((tasks) => dataTasks.push(...tasks));
2644
3807
  dataRequests.push({
2645
- kind: this.requestKind,
2646
- scenario: this.scenario,
3808
+ scenarioSpecL: this.scenarioSpecL,
3809
+ scenarioSpecR: this.scenarioSpecR,
2647
3810
  dataTasks
2648
3811
  });
2649
3812
  }
@@ -2656,8 +3819,8 @@ var ScenarioTaskSet = class {
2656
3819
  dataTasks.push(...this.modelImplTasks.get(datasetKey));
2657
3820
  }
2658
3821
  dataRequests.push({
2659
- kind: this.requestKind,
2660
- scenario: this.scenario,
3822
+ scenarioSpecL: this.scenarioSpecL,
3823
+ scenarioSpecR: this.scenarioSpecR,
2661
3824
  dataTasks
2662
3825
  });
2663
3826
  }
@@ -2665,29 +3828,11 @@ var ScenarioTaskSet = class {
2665
3828
  return dataRequests;
2666
3829
  }
2667
3830
  };
2668
- var DataPlanner = class {
2669
- constructor(batchSize) {
2670
- this.batchSize = batchSize;
2671
- this.scenarioTaskSets = /* @__PURE__ */ new Map();
2672
- }
2673
- addRequest(kind, scenario, datasetKey, dataFunc) {
2674
- let scenarioTaskSet = this.scenarioTaskSets.get(scenario.key);
2675
- if (!scenarioTaskSet) {
2676
- scenarioTaskSet = new ScenarioTaskSet(scenario);
2677
- this.scenarioTaskSets.set(scenario.key, scenarioTaskSet);
2678
- }
2679
- scenarioTaskSet.addTask(kind, datasetKey, dataFunc);
2680
- }
2681
- buildPlan() {
2682
- const requests = [];
2683
- for (const taskSet of this.scenarioTaskSets.values()) {
2684
- requests.push(...taskSet.buildRequests(this.batchSize));
2685
- }
2686
- return {
2687
- requests
2688
- };
2689
- }
2690
- };
3831
+ function scenarioPairUid(scenarioSpecL, scenarioSpecR) {
3832
+ const uidL = (scenarioSpecL == null ? void 0 : scenarioSpecL.uid) || "";
3833
+ const uidR = (scenarioSpecR == null ? void 0 : scenarioSpecR.uid) || "";
3834
+ return `${uidL}::${uidR}`;
3835
+ }
2691
3836
 
2692
3837
  // src/check/check-runner.ts
2693
3838
  function runChecks(checkConfig, checkSpec, dataPlanner, refDataPlanner, simplifyScenarios) {
@@ -2697,7 +3842,7 @@ function runChecks(checkConfig, checkSpec, dataPlanner, refDataPlanner, simplify
2697
3842
  const checkPlan = checkPlanner.buildPlan();
2698
3843
  const refDatasets = /* @__PURE__ */ new Map();
2699
3844
  for (const [dataRefKey, dataRef] of checkPlan.dataRefs.entries()) {
2700
- refDataPlanner.addRequest("check", dataRef.scenario.scenario, dataRef.dataset.datasetKey, (datasets) => {
3845
+ refDataPlanner.addRequest(void 0, dataRef.scenario.spec, dataRef.dataset.datasetKey, (datasets) => {
2701
3846
  const dataset = datasets.datasetR;
2702
3847
  if (dataset) {
2703
3848
  refDatasets.set(dataRefKey, dataset);
@@ -2706,7 +3851,7 @@ function runChecks(checkConfig, checkSpec, dataPlanner, refDataPlanner, simplify
2706
3851
  }
2707
3852
  const checkResults = /* @__PURE__ */ new Map();
2708
3853
  for (const [checkKey, checkTask] of checkPlan.tasks.entries()) {
2709
- dataPlanner.addRequest("check", checkTask.scenario.scenario, checkTask.dataset.datasetKey, (datasets) => {
3854
+ dataPlanner.addRequest(void 0, checkTask.scenario.spec, checkTask.dataset.datasetKey, (datasets) => {
2710
3855
  const dataset = datasets.datasetR;
2711
3856
  const checkResult = runCheck(checkTask, dataset, refDatasets);
2712
3857
  checkResults.set(checkKey, checkResult);
@@ -2737,7 +3882,7 @@ function runCheck(checkTask, dataset, refDatasets) {
2737
3882
  name: dataRef.dataset.name
2738
3883
  }
2739
3884
  };
2740
- } else if (dataRef.scenario.scenario === void 0) {
3885
+ } else if (dataRef.scenario.spec === void 0) {
2741
3886
  if (dataRef.scenario.error) {
2742
3887
  return {
2743
3888
  status: "error",
@@ -2774,16 +3919,15 @@ function runCheck(checkTask, dataset, refDatasets) {
2774
3919
  return checkTask.action.run(dataset, opRefDatasets);
2775
3920
  }
2776
3921
 
2777
- // src/compare/compare-runner.ts
2778
- function runCompare(compareConfig, dataPlanner, simplifyScenarios) {
2779
- const scenarios = simplifyScenarios ? [allInputsAtPositionScenario("at-default")] : compareConfig.scenarios.getScenarios();
2780
- const datasetReports = [];
2781
- for (const scenario of scenarios) {
2782
- const datasetKeys = compareConfig.datasets.getDatasetKeysForScenario(scenario);
3922
+ // src/comparison/run/comparison-runner.ts
3923
+ function runComparisons(comparisonConfig, dataPlanner) {
3924
+ const testReports = [];
3925
+ for (const scenario of comparisonConfig.scenarios.getAllScenarios()) {
3926
+ const datasetKeys = comparisonConfig.datasets.getDatasetKeysForScenario(scenario);
2783
3927
  for (const datasetKey of datasetKeys) {
2784
- dataPlanner.addRequest("compare", scenario, datasetKey, (datasets) => {
3928
+ dataPlanner.addRequest(scenario.specL, scenario.specR, datasetKey, (datasets) => {
2785
3929
  const diffReport = diffDatasets(datasets.datasetL, datasets.datasetR);
2786
- datasetReports.push({
3930
+ testReports.push({
2787
3931
  scenarioKey: scenario.key,
2788
3932
  datasetKey,
2789
3933
  diffReport
@@ -2792,7 +3936,7 @@ function runCompare(compareConfig, dataPlanner, simplifyScenarios) {
2792
3936
  }
2793
3937
  }
2794
3938
  return () => {
2795
- return datasetReports;
3939
+ return testReports;
2796
3940
  };
2797
3941
  }
2798
3942
 
@@ -2830,9 +3974,9 @@ var SuiteRunner = class {
2830
3974
  const checkSpec = checkSpecResult.value;
2831
3975
  const simplifyScenarios = (options == null ? void 0 : options.simplifyScenarios) === true;
2832
3976
  const buildCheckReport2 = runChecks(this.config.check, checkSpec, dataPlanner, refDataPlanner, simplifyScenarios);
2833
- let buildCompareDatasetReports;
2834
- if (this.config.compare) {
2835
- buildCompareDatasetReports = runCompare(this.config.compare, dataPlanner, simplifyScenarios);
3977
+ let buildComparisonTestReports;
3978
+ if (this.config.comparison) {
3979
+ buildComparisonTestReports = runComparisons(this.config.comparison, dataPlanner);
2836
3980
  }
2837
3981
  this.taskQueue.onIdle = (error) => {
2838
3982
  var _a2, _b2, _c2, _d2;
@@ -2843,17 +3987,17 @@ var SuiteRunner = class {
2843
3987
  (_b2 = (_a2 = this.callbacks).onError) == null ? void 0 : _b2.call(_a2, error);
2844
3988
  } else {
2845
3989
  const checkReport = buildCheckReport2();
2846
- let compareReport;
2847
- if (this.config.compare) {
2848
- compareReport = {
2849
- datasetReports: buildCompareDatasetReports(),
3990
+ let comparisonReport;
3991
+ if (this.config.comparison) {
3992
+ comparisonReport = {
3993
+ testReports: buildComparisonTestReports(),
2850
3994
  perfReportL: this.perfStatsL.toReport(),
2851
3995
  perfReportR: this.perfStatsR.toReport()
2852
3996
  };
2853
3997
  }
2854
3998
  (_d2 = (_c2 = this.callbacks).onComplete) == null ? void 0 : _d2.call(_c2, {
2855
3999
  checkReport,
2856
- compareReport
4000
+ comparisonReport
2857
4001
  });
2858
4002
  }
2859
4003
  };
@@ -2862,10 +4006,10 @@ var SuiteRunner = class {
2862
4006
  const dataRequests = [...refDataPlan.requests, ...dataPlan.requests];
2863
4007
  const taskCount = dataRequests.length;
2864
4008
  if (taskCount === 0) {
2865
- let compareReport;
2866
- if (this.config.compare) {
2867
- compareReport = {
2868
- datasetReports: [],
4009
+ let comparisonReport;
4010
+ if (this.config.comparison) {
4011
+ comparisonReport = {
4012
+ testReports: [],
2869
4013
  perfReportL: this.perfStatsL.toReport(),
2870
4014
  perfReportR: this.perfStatsR.toReport()
2871
4015
  };
@@ -2876,7 +4020,7 @@ var SuiteRunner = class {
2876
4020
  checkReport: {
2877
4021
  groups: []
2878
4022
  },
2879
- compareReport
4023
+ comparisonReport
2880
4024
  });
2881
4025
  return;
2882
4026
  }
@@ -2891,34 +4035,25 @@ var SuiteRunner = class {
2891
4035
  }
2892
4036
  }
2893
4037
  async processRequest(request) {
4038
+ var _a, _b;
2894
4039
  const datasetKeySet = /* @__PURE__ */ new Set();
2895
4040
  for (const dataTask of request.dataTasks) {
2896
4041
  datasetKeySet.add(dataTask.datasetKey);
2897
4042
  }
2898
4043
  const datasetKeys = [...datasetKeySet];
2899
- const scenario = request.scenario;
2900
- let datasetsResultL;
2901
- let datasetsResultR;
2902
- switch (request.kind) {
2903
- case "check": {
2904
- const bundleModel = this.config.check.bundle.model;
2905
- datasetsResultR = await bundleModel.getDatasetsForScenario(scenario, datasetKeys);
2906
- break;
2907
- }
2908
- case "compare": {
2909
- const bundleModelL = this.config.compare.bundleL.model;
2910
- const bundleModelR = this.config.compare.bundleR.model;
2911
- const [resultL, resultR] = await Promise.all([
2912
- bundleModelL.getDatasetsForScenario(scenario, datasetKeys),
2913
- bundleModelR.getDatasetsForScenario(scenario, datasetKeys)
2914
- ]);
2915
- datasetsResultL = resultL;
2916
- datasetsResultR = resultR;
2917
- break;
4044
+ async function getDatasets(bundleModel, scenarioSpec) {
4045
+ if (bundleModel && scenarioSpec) {
4046
+ return bundleModel.getDatasetsForScenario(scenarioSpec, datasetKeys);
4047
+ } else {
4048
+ return void 0;
2918
4049
  }
2919
- default:
2920
- (0, import_assert_never10.default)(request.kind);
2921
4050
  }
4051
+ const bundleModelL = (_a = this.config.comparison) == null ? void 0 : _a.bundleL.model;
4052
+ const bundleModelR = ((_b = this.config.comparison) == null ? void 0 : _b.bundleR.model) || this.config.check.bundle.model;
4053
+ const [datasetsResultL, datasetsResultR] = await Promise.all([
4054
+ getDatasets(bundleModelL, request.scenarioSpecL),
4055
+ getDatasets(bundleModelR, request.scenarioSpecR)
4056
+ ]);
2922
4057
  if (datasetsResultL == null ? void 0 : datasetsResultL.modelRunTime) {
2923
4058
  this.perfStatsL.addRun(datasetsResultL == null ? void 0 : datasetsResultL.modelRunTime);
2924
4059
  }
@@ -2930,7 +4065,7 @@ var SuiteRunner = class {
2930
4065
  for (const dataTask of request.dataTasks) {
2931
4066
  const datasetL = datasetMapL == null ? void 0 : datasetMapL.get(dataTask.datasetKey);
2932
4067
  const datasetR = datasetMapR == null ? void 0 : datasetMapR.get(dataTask.datasetKey);
2933
- dataTask.dataFunc({
4068
+ dataTask.dataAction({
2934
4069
  datasetL,
2935
4070
  datasetR
2936
4071
  });
@@ -2945,44 +4080,35 @@ function runSuite(config, callbacks, options) {
2945
4080
  };
2946
4081
  }
2947
4082
 
2948
- // src/suite/suite-summary.ts
4083
+ // src/suite/suite-reporting.ts
2949
4084
  function suiteSummaryFromReport(suiteReport) {
2950
4085
  const checkSummary = checkSummaryFromReport(suiteReport.checkReport);
2951
- let compareSummary;
2952
- if (suiteReport.compareReport) {
2953
- compareSummary = compareSummaryFromReport(suiteReport.compareReport);
4086
+ let comparisonSummary;
4087
+ if (suiteReport.comparisonReport) {
4088
+ comparisonSummary = comparisonSummaryFromReport(suiteReport.comparisonReport);
2954
4089
  }
2955
4090
  return {
2956
4091
  checkSummary,
2957
- compareSummary
4092
+ comparisonSummary
2958
4093
  };
2959
4094
  }
2960
4095
  // Annotate the CommonJS export names for ESM import in node:
2961
4096
  0 && (module.exports = {
2962
4097
  CheckDataCoordinator,
2963
- CompareDataCoordinator,
2964
- DatasetManager,
4098
+ ComparisonDataCoordinator,
2965
4099
  PerfRunner,
2966
4100
  PerfStats,
2967
- ScenarioManager,
2968
- allInputsAtPositionScenario,
4101
+ categorizeComparisonTestSummaries,
2969
4102
  checkReportFromSummary,
2970
4103
  checkSummaryFromReport,
2971
- compareDatasets,
2972
- compareSummaryFromReport,
4104
+ comparisonSummaryFromReport,
2973
4105
  createConfig,
2974
4106
  datasetMessage,
2975
4107
  diffDatasets,
2976
4108
  diffGraphs,
2977
- inputAtPositionScenario,
2978
- inputAtValueScenario,
2979
- matrixScenarios,
2980
- positionSetting,
2981
4109
  predicateMessage,
2982
4110
  runSuite,
2983
4111
  scenarioMessage,
2984
- settingsScenario,
2985
- suiteSummaryFromReport,
2986
- valueSetting
4112
+ suiteSummaryFromReport
2987
4113
  });
2988
4114
  //# sourceMappingURL=index.cjs.map