@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.js CHANGED
@@ -1,93 +1,3 @@
1
- var __defProp = Object.defineProperty;
2
- var __defProps = Object.defineProperties;
3
- var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
- var __getOwnPropSymbols = Object.getOwnPropertySymbols;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __propIsEnum = Object.prototype.propertyIsEnumerable;
7
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
- var __spreadValues = (a, b) => {
9
- for (var prop in b || (b = {}))
10
- if (__hasOwnProp.call(b, prop))
11
- __defNormalProp(a, prop, b[prop]);
12
- if (__getOwnPropSymbols)
13
- for (var prop of __getOwnPropSymbols(b)) {
14
- if (__propIsEnum.call(b, prop))
15
- __defNormalProp(a, prop, b[prop]);
16
- }
17
- return a;
18
- };
19
- var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
-
21
- // src/_shared/scenario.ts
22
- import { assertNever } from "assert-never";
23
- function positionSetting(inputVarId, position) {
24
- return {
25
- kind: "position",
26
- inputVarId,
27
- position
28
- };
29
- }
30
- function valueSetting(inputVarId, value) {
31
- return {
32
- kind: "value",
33
- inputVarId,
34
- value
35
- };
36
- }
37
- function settingsScenario(key, groupKey, settings) {
38
- return {
39
- kind: "settings",
40
- key,
41
- groupKey,
42
- settings
43
- };
44
- }
45
- function inputAtPositionScenario(inputVarId, groupKey, position) {
46
- const key = keyForInputAtPosition(`input${inputVarId}`, position);
47
- return settingsScenario(key, groupKey, [positionSetting(inputVarId, position)]);
48
- }
49
- function inputAtValueScenario(inputVarId, groupKey, value) {
50
- const key = keyForInputAtValue(`input${inputVarId}`, value);
51
- return settingsScenario(key, groupKey, [valueSetting(inputVarId, value)]);
52
- }
53
- function allInputsAtPositionScenario(position) {
54
- return {
55
- kind: "all-inputs",
56
- key: keyForInputAtPosition("all_inputs", position),
57
- groupKey: "all_inputs",
58
- position
59
- };
60
- }
61
- function matrixScenarios(inputVarIds) {
62
- const scenarios = [];
63
- scenarios.push(allInputsAtPositionScenario("at-default"));
64
- scenarios.push(allInputsAtPositionScenario("at-minimum"));
65
- scenarios.push(allInputsAtPositionScenario("at-maximum"));
66
- for (const inputVarId of inputVarIds) {
67
- scenarios.push(inputAtPositionScenario(inputVarId, inputVarId, "at-minimum"));
68
- scenarios.push(inputAtPositionScenario(inputVarId, inputVarId, "at-maximum"));
69
- }
70
- return scenarios;
71
- }
72
- function keyForInputPosition(position) {
73
- switch (position) {
74
- case "at-default":
75
- return "default";
76
- case "at-minimum":
77
- return "min";
78
- case "at-maximum":
79
- return "max";
80
- default:
81
- assertNever(position);
82
- }
83
- }
84
- function keyForInputAtPosition(inputKey, position) {
85
- return `${inputKey}_at_${keyForInputPosition(position)}`;
86
- }
87
- function keyForInputAtValue(inputKey, value) {
88
- return `${inputKey}_at_${value}`;
89
- }
90
-
91
1
  // src/_shared/task-queue.ts
92
2
  var TaskQueue = class {
93
3
  constructor(processor) {
@@ -174,7 +84,7 @@ var CheckDataCoordinator = class {
174
84
  this.bundleModel = bundleModel;
175
85
  this.taskQueue = new TaskQueue({
176
86
  process: async (request) => {
177
- const result = await this.bundleModel.getDatasetsForScenario(request.scenario, [request.datasetKey]);
87
+ const result = await this.bundleModel.getDatasetsForScenario(request.scenarioSpec, [request.datasetKey]);
178
88
  const dataset = result.datasetMap.get(request.datasetKey);
179
89
  return {
180
90
  dataset
@@ -182,9 +92,9 @@ var CheckDataCoordinator = class {
182
92
  }
183
93
  });
184
94
  }
185
- requestDataset(requestKey, scenario, datasetKey, onResponse) {
95
+ requestDataset(requestKey, scenarioSpec, datasetKey, onResponse) {
186
96
  const request = {
187
- scenario,
97
+ scenarioSpec,
188
98
  datasetKey
189
99
  };
190
100
  this.taskQueue.addTask(requestKey, request, (response) => {
@@ -197,10 +107,10 @@ var CheckDataCoordinator = class {
197
107
  };
198
108
 
199
109
  // src/check/check-report.ts
200
- import assertNever3 from "assert-never";
110
+ import assertNever2 from "assert-never";
201
111
 
202
112
  // src/check/check-predicate.ts
203
- import assertNever2 from "assert-never";
113
+ import assertNever from "assert-never";
204
114
  function symbolForPredicateOp(op) {
205
115
  switch (op) {
206
116
  case "gt":
@@ -216,7 +126,7 @@ function symbolForPredicateOp(op) {
216
126
  case "approx":
217
127
  return "\u2248";
218
128
  default:
219
- assertNever2(op);
129
+ assertNever(op);
220
130
  }
221
131
  }
222
132
 
@@ -230,7 +140,7 @@ function buildCheckReport(checkPlan, checkResults) {
230
140
  const scenarioReports = [];
231
141
  for (const scenarioPlan of testPlan.scenarios) {
232
142
  let scenarioStatus = "passed";
233
- if (scenarioPlan.checkScenario.scenario === void 0) {
143
+ if (scenarioPlan.checkScenario.spec === void 0) {
234
144
  testStatus = "error";
235
145
  scenarioStatus = "error";
236
146
  }
@@ -327,14 +237,14 @@ function predicateReport(predicatePlan, checkKey, result) {
327
237
  };
328
238
  opRef = opDataRef;
329
239
  opValue = `${sym} '${dataRef.dataset.name}'`;
330
- const refScenario = (_b = dataRef.scenario) == null ? void 0 : _b.scenario;
331
- if (!refScenario) {
240
+ const refScenarioSpec = (_b = dataRef.scenario) == null ? void 0 : _b.spec;
241
+ if (!refScenarioSpec) {
332
242
  return;
333
243
  }
334
244
  if (predOp.scenario === "inherit") {
335
245
  opValue += ` (w/ same scenario)`;
336
246
  } else {
337
- if (refScenario.kind === "all-inputs" && refScenario.position === "at-default") {
247
+ if (refScenarioSpec.kind === "all-inputs" && refScenarioSpec.position === "at-default") {
338
248
  opValue += ` (w/ default scenario)`;
339
249
  } else {
340
250
  opValue += ` (w/ configured scenario)`;
@@ -369,7 +279,7 @@ function predicateReport(predicatePlan, checkKey, result) {
369
279
  }
370
280
  function scenarioMessage(scenario, bold) {
371
281
  const checkScenario = scenario.checkScenario;
372
- if (checkScenario.scenario === void 0) {
282
+ if (checkScenario.spec === void 0) {
373
283
  if (checkScenario.error) {
374
284
  switch (checkScenario.error.kind) {
375
285
  case "unknown-input-group":
@@ -377,7 +287,7 @@ function scenarioMessage(scenario, bold) {
377
287
  case "empty-input-group":
378
288
  return `error: input group ${bold(checkScenario.error.name)} is empty`;
379
289
  default:
380
- assertNever3(checkScenario.error.kind);
290
+ assertNever2(checkScenario.error.kind);
381
291
  }
382
292
  } else {
383
293
  const badInputNames = checkScenario.inputDescs.filter((d) => d.inputVar === void 0).map((d) => bold(d.name));
@@ -394,7 +304,7 @@ function scenarioMessage(scenario, bold) {
394
304
  case "at-maximum":
395
305
  return "maximum";
396
306
  default:
397
- assertNever3(position);
307
+ assertNever2(position);
398
308
  }
399
309
  }
400
310
  function inputMessage(inputDesc) {
@@ -409,13 +319,13 @@ function scenarioMessage(scenario, bold) {
409
319
  }
410
320
  return msg;
411
321
  }
412
- if (checkScenario.scenario.kind === "all-inputs") {
413
- const position = checkScenario.scenario.position;
322
+ if (checkScenario.spec.kind === "all-inputs") {
323
+ const position = checkScenario.spec.position;
414
324
  return `when ${bold("all inputs")} are at ${bold(positionName(position))}...`;
415
325
  } else if (checkScenario.inputGroupName) {
416
326
  let position = "at-default";
417
- if (checkScenario.scenario.settings[0].kind === "position") {
418
- position = checkScenario.scenario.settings[0].position;
327
+ if (checkScenario.spec.settings[0].kind === "position") {
328
+ position = checkScenario.spec.settings[0].position;
419
329
  }
420
330
  const groupName = checkScenario.inputGroupName;
421
331
  return `when all inputs in ${bold(groupName)} are at ${bold(positionName(position))}...`;
@@ -448,7 +358,7 @@ function predicateMessage(predicate, bold) {
448
358
  case "empty-input-group":
449
359
  return `error: referenced input group ${bold(result.errorInfo.name)} is empty`;
450
360
  default:
451
- assertNever3(result.errorInfo.kind);
361
+ assertNever2(result.errorInfo.kind);
452
362
  }
453
363
  } else {
454
364
  return `unknown error`;
@@ -1019,7 +929,7 @@ function parseTestYaml(yamlStrings) {
1019
929
  groups.push(group);
1020
930
  }
1021
931
  } else {
1022
- let msg = "Failed to parse YAML tests";
932
+ let msg = "Failed to parse YAML check definitions";
1023
933
  for (const error of validate.errors || []) {
1024
934
  if (error.message) {
1025
935
  msg += `
@@ -1193,9 +1103,12 @@ function actionForPredicate(predicateSpec) {
1193
1103
 
1194
1104
  // src/_shared/combo.ts
1195
1105
  function cartesianProductOf(arr) {
1196
- return arr.reduce((a, b) => {
1197
- return a.map((x) => b.map((y) => x.concat([y]))).reduce((v, w) => v.concat(w), []);
1198
- }, [[]]);
1106
+ return arr.reduce(
1107
+ (a, b) => {
1108
+ return a.map((x) => b.map((y) => x.concat([y]))).reduce((v, w) => v.concat(w), []);
1109
+ },
1110
+ [[]]
1111
+ );
1199
1112
  }
1200
1113
 
1201
1114
  // src/check/check-dataset.ts
@@ -1286,14 +1199,16 @@ function matchByName(modelSpec, datasetName, datasetSource) {
1286
1199
  };
1287
1200
  }
1288
1201
  function matchByGroup(modelSpec, groupName) {
1289
- const groupToMatch = groupName.toLowerCase();
1290
1202
  let matchedGroupName;
1291
1203
  let matchedGroupDatasetKeys;
1292
- for (const [group, datasetKeys] of modelSpec.datasetGroups) {
1293
- if (group.toLowerCase() === groupToMatch) {
1294
- matchedGroupName = group;
1295
- matchedGroupDatasetKeys = datasetKeys;
1296
- break;
1204
+ if (modelSpec.datasetGroups) {
1205
+ const groupToMatch = groupName.toLowerCase();
1206
+ for (const [group, datasetKeys] of modelSpec.datasetGroups) {
1207
+ if (group.toLowerCase() === groupToMatch) {
1208
+ matchedGroupName = group;
1209
+ matchedGroupDatasetKeys = datasetKeys;
1210
+ break;
1211
+ }
1297
1212
  }
1298
1213
  }
1299
1214
  if (matchedGroupName === void 0) {
@@ -1370,6 +1285,65 @@ function matchByType(modelSpec, varTypeToMatch) {
1370
1285
 
1371
1286
  // src/check/check-scenario.ts
1372
1287
  import assertNever4 from "assert-never";
1288
+
1289
+ // src/_shared/scenario-specs.ts
1290
+ import { assertNever as assertNever3 } from "assert-never";
1291
+ function positionSetting(inputVarId, position) {
1292
+ return {
1293
+ kind: "position",
1294
+ inputVarId,
1295
+ position
1296
+ };
1297
+ }
1298
+ function valueSetting(inputVarId, value) {
1299
+ return {
1300
+ kind: "value",
1301
+ inputVarId,
1302
+ value
1303
+ };
1304
+ }
1305
+ function inputSettingsSpec(settings) {
1306
+ const uidParts = settings.map((setting) => {
1307
+ switch (setting.kind) {
1308
+ case "position":
1309
+ return `${setting.inputVarId}_at_${keyForInputPosition(setting.position)}`;
1310
+ case "value":
1311
+ return `${setting.inputVarId}_at_${setting.value}`;
1312
+ default:
1313
+ assertNever3(setting);
1314
+ }
1315
+ });
1316
+ const uid = `inputs_${uidParts.sort().join("_")}`;
1317
+ return {
1318
+ kind: "input-settings",
1319
+ uid,
1320
+ settings
1321
+ };
1322
+ }
1323
+ function inputAtPositionSpec(inputVarId, position) {
1324
+ return inputSettingsSpec([positionSetting(inputVarId, position)]);
1325
+ }
1326
+ function allInputsAtPositionSpec(position) {
1327
+ return {
1328
+ kind: "all-inputs",
1329
+ uid: `all_inputs_at_${keyForInputPosition(position)}`,
1330
+ position
1331
+ };
1332
+ }
1333
+ function keyForInputPosition(position) {
1334
+ switch (position) {
1335
+ case "at-default":
1336
+ return "default";
1337
+ case "at-minimum":
1338
+ return "min";
1339
+ case "at-maximum":
1340
+ return "max";
1341
+ default:
1342
+ assertNever3(position);
1343
+ }
1344
+ }
1345
+
1346
+ // src/check/check-scenario.ts
1373
1347
  function expandScenarios(modelSpec, scenarioSpecs, simplify) {
1374
1348
  if (scenarioSpecs.length === 0) {
1375
1349
  const scenarioSpec = {
@@ -1446,10 +1420,12 @@ function inputDescForName(modelSpec, inputName, at) {
1446
1420
  }
1447
1421
  }
1448
1422
  function groupForName(modelSpec, groupName) {
1449
- const groupToMatch = groupName.toLowerCase();
1450
- for (const [group, inputVars] of modelSpec.inputGroups) {
1451
- if (group.toLowerCase() === groupToMatch) {
1452
- return [group, inputVars];
1423
+ if (modelSpec.inputGroups) {
1424
+ const groupToMatch = groupName.toLowerCase();
1425
+ for (const [group, inputVars] of modelSpec.inputGroups) {
1426
+ if (group.toLowerCase() === groupToMatch) {
1427
+ return [group, inputVars];
1428
+ }
1453
1429
  }
1454
1430
  }
1455
1431
  return void 0;
@@ -1464,56 +1440,35 @@ function errorScenarioForInputGroup(kind, groupName) {
1464
1440
  };
1465
1441
  }
1466
1442
  function checkScenarioWithAllInputsAtPosition(position) {
1467
- const scenario = allInputsAtPositionScenario(position);
1468
1443
  return {
1469
- scenario,
1444
+ spec: allInputsAtPositionSpec(position),
1470
1445
  inputDescs: []
1471
1446
  };
1472
1447
  }
1473
1448
  function checkScenarioWithInputAtPosition(inputVar, position) {
1474
1449
  const varId = inputVar.varId;
1475
- const scenario = inputAtPositionScenario(varId, varId, position);
1476
1450
  return {
1477
- scenario,
1451
+ spec: inputAtPositionSpec(varId, position),
1478
1452
  inputDescs: [inputDescAtPosition(inputVar, position)]
1479
1453
  };
1480
1454
  }
1481
1455
  function checkScenarioForInputDescs(groupName, inputDescs) {
1482
- let scenario;
1456
+ let spec;
1483
1457
  if (inputDescs.every((desc) => desc.inputVar !== void 0)) {
1484
- const settings = [];
1485
- const keyParts = [];
1486
- for (const inputDesc of inputDescs) {
1458
+ const settings = inputDescs.map((inputDesc) => {
1487
1459
  const varId = inputDesc.inputVar.varId;
1488
1460
  if (inputDesc.position) {
1489
- settings.push(positionSetting(varId, inputDesc.position));
1490
- keyParts.push(keyForInputAtPosition(varId, inputDesc.position));
1491
- } else {
1492
- settings.push(valueSetting(varId, inputDesc.value));
1493
- keyParts.push(keyForInputAtValue(varId, inputDesc.value));
1494
- }
1495
- }
1496
- if (settings.length === 1) {
1497
- const scenarioKey = `input${keyParts[0]}`;
1498
- const groupKey = settings[0].inputVarId;
1499
- scenario = settingsScenario(scenarioKey, groupKey, settings);
1500
- } else if (settings.length > 1) {
1501
- let scenarioKey;
1502
- let groupKey;
1503
- if (groupName) {
1504
- scenarioKey = `group_${groupName.toLowerCase().replace(/ /g, "_")}`;
1505
- groupKey = scenarioKey;
1461
+ return positionSetting(varId, inputDesc.position);
1506
1462
  } else {
1507
- scenarioKey = "multi" + keyParts.join("_");
1508
- groupKey = scenarioKey;
1463
+ return valueSetting(varId, inputDesc.value);
1509
1464
  }
1510
- scenario = settingsScenario(scenarioKey, groupKey, settings);
1511
- }
1465
+ });
1466
+ spec = inputSettingsSpec(settings);
1512
1467
  } else {
1513
- scenario = void 0;
1468
+ spec = void 0;
1514
1469
  }
1515
1470
  return {
1516
- scenario,
1471
+ spec,
1517
1472
  inputGroupName: groupName,
1518
1473
  inputDescs
1519
1474
  };
@@ -1627,7 +1582,7 @@ var CheckPlanner = class {
1627
1582
  }
1628
1583
  const planScenarios = [];
1629
1584
  for (const checkScenario of checkScenarios) {
1630
- if (checkScenario.scenario === void 0) {
1585
+ if (checkScenario.spec === void 0) {
1631
1586
  planScenarios.push({
1632
1587
  checkScenario,
1633
1588
  datasets: []
@@ -1736,8 +1691,8 @@ var CheckPlanner = class {
1736
1691
  }
1737
1692
  }
1738
1693
  let dataRefKey;
1739
- if (refScenario.scenario && refDataset.datasetKey) {
1740
- dataRefKey = `${refScenario.scenario.key}::${refDataset.datasetKey}`;
1694
+ if (refScenario.spec && refDataset.datasetKey) {
1695
+ dataRefKey = `${refScenario.spec.uid}::${refDataset.datasetKey}`;
1741
1696
  }
1742
1697
  const dataRef = {
1743
1698
  key: dataRefKey,
@@ -1792,14 +1747,14 @@ function checkSummaryFromReport(checkReport) {
1792
1747
  predicateSummaries
1793
1748
  };
1794
1749
  }
1795
- function checkReportFromSummary(checkConfig, checkSummary, simplifyScenarios) {
1750
+ function checkReportFromSummary(checkConfig, checkSummary) {
1796
1751
  const checkSpecResult = parseTestYaml(checkConfig.tests);
1797
1752
  if (checkSpecResult.isErr()) {
1798
1753
  return void 0;
1799
1754
  }
1800
1755
  const checkSpec = checkSpecResult.value;
1801
1756
  const checkPlanner = new CheckPlanner(checkConfig.bundle.model.modelSpec);
1802
- checkPlanner.addAllChecks(checkSpec, simplifyScenarios);
1757
+ checkPlanner.addAllChecks(checkSpec, false);
1803
1758
  const checkPlan = checkPlanner.buildPlan();
1804
1759
  const checkResults = /* @__PURE__ */ new Map();
1805
1760
  for (const predicateSummary of checkSummary.predicateSummaries) {
@@ -1808,44 +1763,66 @@ function checkReportFromSummary(checkConfig, checkSummary, simplifyScenarios) {
1808
1763
  return buildCheckReport(checkPlan, checkResults);
1809
1764
  }
1810
1765
 
1811
- // src/compare/compare-data-coordinator.ts
1766
+ // src/comparison/run/comparison-data-coordinator.ts
1812
1767
  import { assertNever as assertNever7 } from "assert-never";
1813
- var CompareDataCoordinator = class {
1768
+ var ComparisonDataCoordinator = class {
1814
1769
  constructor(bundleModelL, bundleModelR) {
1815
1770
  this.bundleModelL = bundleModelL;
1816
1771
  this.bundleModelR = bundleModelR;
1817
1772
  this.taskQueue = new TaskQueue({
1818
1773
  process: async (request) => {
1819
1774
  switch (request.kind) {
1820
- case "dataset": {
1821
- const [resultL, resultR] = await Promise.all([
1822
- this.bundleModelL.getDatasetsForScenario(request.scenario, request.datasetKeys),
1823
- this.bundleModelR.getDatasetsForScenario(request.scenario, request.datasetKeys)
1824
- ]);
1825
- return {
1826
- kind: "dataset",
1827
- datasetMapL: resultL.datasetMap,
1828
- datasetMapR: resultR.datasetMap
1829
- };
1830
- }
1831
- case "graph-data": {
1832
- const bundleModel = request.bundle === "right" ? this.bundleModelR : this.bundleModelL;
1833
- const graphData = await bundleModel.getGraphDataForScenario(request.scenario, request.graphId);
1834
- return {
1835
- kind: "graph-data",
1836
- graphData
1837
- };
1838
- }
1775
+ case "dataset":
1776
+ return this.processDatasetRequest(request);
1777
+ case "graph-data":
1778
+ return this.processGraphDataRequest(request);
1839
1779
  default:
1840
1780
  assertNever7(request);
1841
1781
  }
1842
1782
  }
1843
1783
  });
1844
1784
  }
1845
- requestDatasetMaps(requestKey, scenario, datasetKeys, onResponse) {
1785
+ async processDatasetRequest(request) {
1786
+ async function fetchDatasets(bundleModel, scenarioSpec) {
1787
+ if (scenarioSpec) {
1788
+ return bundleModel.getDatasetsForScenario(scenarioSpec, request.datasetKeys);
1789
+ } else {
1790
+ return void 0;
1791
+ }
1792
+ }
1793
+ const [resultL, resultR] = await Promise.all([
1794
+ fetchDatasets(this.bundleModelL, request.scenarioSpecL),
1795
+ fetchDatasets(this.bundleModelR, request.scenarioSpecR)
1796
+ ]);
1797
+ return {
1798
+ kind: "dataset",
1799
+ datasetMapL: resultL == null ? void 0 : resultL.datasetMap,
1800
+ datasetMapR: resultR == null ? void 0 : resultR.datasetMap
1801
+ };
1802
+ }
1803
+ async processGraphDataRequest(request) {
1804
+ async function fetchGraphData(bundleModel, scenarioSpec) {
1805
+ if (scenarioSpec) {
1806
+ return bundleModel.getGraphDataForScenario(scenarioSpec, request.graphId);
1807
+ } else {
1808
+ return void 0;
1809
+ }
1810
+ }
1811
+ const [graphDataL, graphDataR] = await Promise.all([
1812
+ fetchGraphData(this.bundleModelL, request.scenarioSpecL),
1813
+ fetchGraphData(this.bundleModelR, request.scenarioSpecR)
1814
+ ]);
1815
+ return {
1816
+ kind: "graph-data",
1817
+ graphDataL,
1818
+ graphDataR
1819
+ };
1820
+ }
1821
+ requestDatasetMaps(requestKey, scenarioSpecL, scenarioSpecR, datasetKeys, onResponse) {
1846
1822
  const request = {
1847
1823
  kind: "dataset",
1848
- scenario,
1824
+ scenarioSpecL,
1825
+ scenarioSpecR,
1849
1826
  datasetKeys
1850
1827
  };
1851
1828
  this.taskQueue.addTask(requestKey, request, (response) => {
@@ -1854,16 +1831,16 @@ var CompareDataCoordinator = class {
1854
1831
  }
1855
1832
  });
1856
1833
  }
1857
- requestGraphData(requestKey, bundle, scenario, graphId, onResponse) {
1834
+ requestGraphData(requestKey, scenarioSpecL, scenarioSpecR, graphId, onResponse) {
1858
1835
  const request = {
1859
1836
  kind: "graph-data",
1860
- bundle,
1861
- scenario,
1837
+ scenarioSpecL,
1838
+ scenarioSpecR,
1862
1839
  graphId
1863
1840
  };
1864
1841
  this.taskQueue.addTask(requestKey, request, (response) => {
1865
1842
  if (response.kind === "graph-data") {
1866
- onResponse(response.graphData);
1843
+ onResponse(response.graphDataL, response.graphDataR);
1867
1844
  }
1868
1845
  });
1869
1846
  }
@@ -1872,7 +1849,7 @@ var CompareDataCoordinator = class {
1872
1849
  }
1873
1850
  };
1874
1851
 
1875
- // src/compare/compare-datasets.ts
1852
+ // src/comparison/diff-datasets/diff-datasets.ts
1876
1853
  function diffDatasets(datasetL, datasetR) {
1877
1854
  let minValueL = Number.MAX_VALUE;
1878
1855
  let maxValueL = Number.MIN_VALUE;
@@ -1967,19 +1944,9 @@ function diffDatasets(datasetL, datasetR) {
1967
1944
  maxDiffPoint
1968
1945
  };
1969
1946
  }
1970
- function compareDatasets(scenarioKey, datasetKey, datasetMapL, datasetMapR) {
1971
- const datasetL = datasetMapL.get(datasetKey);
1972
- const datasetR = datasetMapR.get(datasetKey);
1973
- const diffReport = diffDatasets(datasetL, datasetR);
1974
- return {
1975
- scenarioKey,
1976
- datasetKey,
1977
- diffReport
1978
- };
1979
- }
1980
1947
 
1981
- // src/compare/compare-graphs.ts
1982
- function diffGraphs(graphL, graphR, scenarioKey, datasetSummaries) {
1948
+ // src/comparison/diff-graphs/diff-graphs.ts
1949
+ function diffGraphs(graphL, graphR, scenarioKey, testSummaries) {
1983
1950
  let inclusion;
1984
1951
  if (graphL && graphR) {
1985
1952
  inclusion = "both";
@@ -2021,8 +1988,8 @@ function diffGraphs(graphL, graphR, scenarioKey, datasetSummaries) {
2021
1988
  datasetKeys.add(dataset.datasetKey);
2022
1989
  }
2023
1990
  for (const datasetKey of datasetKeys) {
2024
- const summary = datasetSummaries.find((summary2) => summary2.d === datasetKey && summary2.s === scenarioKey);
2025
- const maxDiff = summary !== void 0 ? summary.md : void 0;
1991
+ const testSummary = testSummaries.find((summary) => summary.d === datasetKey && summary.s === scenarioKey);
1992
+ const maxDiff = testSummary == null ? void 0 : testSummary.md;
2026
1993
  datasetReports.push({
2027
1994
  datasetKey,
2028
1995
  maxDiff
@@ -2036,12 +2003,12 @@ function diffGraphs(graphL, graphR, scenarioKey, datasetSummaries) {
2036
2003
  };
2037
2004
  }
2038
2005
 
2039
- // src/compare/compare-summary.ts
2040
- function compareSummaryFromReport(compareReport) {
2041
- const datasetSummaries = [];
2042
- for (const r of compareReport.datasetReports) {
2006
+ // src/comparison/report/comparison-reporting.ts
2007
+ function comparisonSummaryFromReport(comparisonReport) {
2008
+ const terseSummaries = [];
2009
+ for (const r of comparisonReport.testReports) {
2043
2010
  if (r.diffReport.validity === "both" && r.diffReport.maxDiff > 0) {
2044
- datasetSummaries.push({
2011
+ terseSummaries.push({
2045
2012
  s: r.scenarioKey,
2046
2013
  d: r.datasetKey,
2047
2014
  md: r.diffReport.maxDiff
@@ -2049,154 +2016,1319 @@ function compareSummaryFromReport(compareReport) {
2049
2016
  }
2050
2017
  }
2051
2018
  return {
2052
- datasetSummaries,
2053
- perfReportL: compareReport.perfReportL,
2054
- perfReportR: compareReport.perfReportR
2019
+ testSummaries: terseSummaries,
2020
+ perfReportL: comparisonReport.perfReportL,
2021
+ perfReportR: comparisonReport.perfReportR
2055
2022
  };
2056
2023
  }
2024
+ function restoreFromTerseSummaries(comparisonConfig, terseSummaries) {
2025
+ const existingSummaries = /* @__PURE__ */ new Map();
2026
+ for (const summary of terseSummaries) {
2027
+ const key = `${summary.s}::${summary.d}`;
2028
+ existingSummaries.set(key, summary);
2029
+ }
2030
+ const allTestSummaries = [];
2031
+ for (const scenario of comparisonConfig.scenarios.getAllScenarios()) {
2032
+ const datasetKeys = comparisonConfig.datasets.getDatasetKeysForScenario(scenario);
2033
+ for (const datasetKey of datasetKeys) {
2034
+ const key = `${scenario.key}::${datasetKey}`;
2035
+ const existingSummary = existingSummaries.get(key);
2036
+ const maxDiff = (existingSummary == null ? void 0 : existingSummary.md) || 0;
2037
+ allTestSummaries.push({
2038
+ s: scenario.key,
2039
+ d: datasetKey,
2040
+ md: maxDiff
2041
+ });
2042
+ }
2043
+ }
2044
+ return allTestSummaries;
2045
+ }
2057
2046
 
2058
- // src/config/synchronized-model.ts
2059
- function synchronizedBundleModel(sourceModel) {
2060
- var _a;
2061
- const promiseQueue = new PromiseQueue();
2047
+ // src/comparison/report/comparison-grouping.ts
2048
+ import { assertNever as assertNever8 } from "assert-never";
2049
+
2050
+ // src/comparison/report/buckets.ts
2051
+ function getBucketIndex(diffPct, thresholds) {
2052
+ if (diffPct === 0) {
2053
+ return 0;
2054
+ }
2055
+ for (let i = 0; i < thresholds.length; i++) {
2056
+ if (diffPct < thresholds[i]) {
2057
+ return i + 1;
2058
+ }
2059
+ }
2060
+ return thresholds.length + 1;
2061
+ }
2062
+
2063
+ // src/comparison/report/comparison-grouping.ts
2064
+ function categorizeComparisonTestSummaries(comparisonConfig, terseSummaries) {
2065
+ const allTestSummaries = restoreFromTerseSummaries(comparisonConfig, terseSummaries);
2066
+ const groupsByScenario = groupComparisonTestSummaries(allTestSummaries, "by-scenario");
2067
+ const byScenario = categorizeComparisonGroups(comparisonConfig, [...groupsByScenario.values()]);
2068
+ const groupsByDataset = groupComparisonTestSummaries(allTestSummaries, "by-dataset");
2069
+ const byDataset = categorizeComparisonGroups(comparisonConfig, [...groupsByDataset.values()]);
2062
2070
  return {
2063
- modelSpec: sourceModel.modelSpec,
2064
- getDatasetsForScenario: (scenario, datasetKeys) => {
2065
- return promiseQueue.add(() => sourceModel.getDatasetsForScenario(scenario, datasetKeys));
2066
- },
2067
- getGraphsForDataset: (_a = sourceModel.getGraphsForDataset) == null ? void 0 : _a.bind(sourceModel),
2068
- getGraphDataForScenario: (scenario, graphId) => {
2069
- return promiseQueue.add(() => sourceModel.getGraphDataForScenario(scenario, graphId));
2070
- },
2071
- getGraphLinksForScenario: sourceModel.getGraphLinksForScenario.bind(sourceModel)
2071
+ byScenario,
2072
+ byDataset
2072
2073
  };
2073
2074
  }
2074
- var PromiseQueue = class {
2075
- constructor() {
2076
- this.tasks = [];
2077
- this.runningCount = 0;
2075
+ function groupComparisonTestSummaries(testSummaries, groupKind) {
2076
+ const groups = /* @__PURE__ */ new Map();
2077
+ for (const testSummary of testSummaries) {
2078
+ let groupKey;
2079
+ switch (groupKind) {
2080
+ case "by-dataset":
2081
+ groupKey = testSummary.d;
2082
+ break;
2083
+ case "by-scenario":
2084
+ groupKey = testSummary.s;
2085
+ break;
2086
+ default:
2087
+ assertNever8(groupKind);
2088
+ }
2089
+ const group = groups.get(groupKey);
2090
+ if (group) {
2091
+ group.testSummaries.push(testSummary);
2092
+ } else {
2093
+ groups.set(groupKey, {
2094
+ kind: groupKind,
2095
+ key: groupKey,
2096
+ testSummaries: [testSummary]
2097
+ });
2098
+ }
2078
2099
  }
2079
- add(f) {
2080
- return new Promise((resolve, reject) => {
2081
- const run = async () => {
2082
- this.runningCount++;
2083
- const promise = f();
2084
- try {
2085
- const result = await promise;
2086
- resolve(result);
2087
- } catch (e) {
2088
- reject(e);
2089
- } finally {
2090
- this.runningCount--;
2091
- this.runNext();
2092
- }
2093
- };
2094
- if (this.runningCount < 1) {
2095
- run();
2100
+ return groups;
2101
+ }
2102
+ function categorizeComparisonGroups(comparisonConfig, allGroups) {
2103
+ const allGroupSummaries = /* @__PURE__ */ new Map();
2104
+ const withErrors = [];
2105
+ const onlyInLeft = [];
2106
+ const onlyInRight = [];
2107
+ let withDiffs = [];
2108
+ const withoutDiffs = [];
2109
+ function addSummaryForGroup(group, root, validInL, validInR) {
2110
+ let scores;
2111
+ if (validInL && validInR) {
2112
+ scores = getScoresForGroup(group, comparisonConfig.thresholds);
2113
+ }
2114
+ const groupSummary = {
2115
+ root,
2116
+ group,
2117
+ scores
2118
+ };
2119
+ allGroupSummaries.set(group.key, groupSummary);
2120
+ if (validInL && validInR) {
2121
+ if (scores.totalDiffCount !== scores.diffCountByBucket[0]) {
2122
+ withDiffs.push(groupSummary);
2096
2123
  } else {
2097
- this.tasks.push(run);
2124
+ withoutDiffs.push(groupSummary);
2098
2125
  }
2099
- });
2126
+ } else if (validInL) {
2127
+ onlyInLeft.push(groupSummary);
2128
+ } else if (validInR) {
2129
+ onlyInRight.push(groupSummary);
2130
+ } else {
2131
+ withErrors.push(groupSummary);
2132
+ }
2100
2133
  }
2101
- runNext() {
2102
- if (this.tasks.length > 0) {
2103
- const task = this.tasks.shift();
2104
- if (task) {
2105
- task();
2134
+ for (const group of allGroups.values()) {
2135
+ switch (group.kind) {
2136
+ case "by-dataset": {
2137
+ const dataset = comparisonConfig.datasets.getDataset(group.key);
2138
+ const validInL = (dataset == null ? void 0 : dataset.outputVarL) !== void 0;
2139
+ const validInR = (dataset == null ? void 0 : dataset.outputVarR) !== void 0;
2140
+ addSummaryForGroup(group, dataset, validInL, validInR);
2141
+ break;
2142
+ }
2143
+ case "by-scenario": {
2144
+ const scenario = comparisonConfig.scenarios.getScenario(group.key);
2145
+ const validInL = (scenario == null ? void 0 : scenario.specL) !== void 0;
2146
+ const validInR = (scenario == null ? void 0 : scenario.specR) !== void 0;
2147
+ addSummaryForGroup(group, scenario, validInL, validInR);
2148
+ break;
2106
2149
  }
2150
+ default:
2151
+ assertNever8(group.kind);
2107
2152
  }
2108
2153
  }
2109
- };
2110
-
2111
- // src/config/config.ts
2112
- async function createConfig(options) {
2113
- var _a;
2114
- const origCurrentBundle = await loadSynchronized(options.current);
2115
- let currentBundle;
2116
- let compareConfig;
2117
- if (options.compare === void 0) {
2118
- currentBundle = origCurrentBundle;
2119
- } else {
2120
- const baselineBundle = await loadSynchronized(options.compare.baseline);
2121
- const renamedDatasetKeys = options.compare.datasets.renamedDatasetKeys;
2122
- const invertedRenamedKeys = /* @__PURE__ */ new Map();
2123
- renamedDatasetKeys == null ? void 0 : renamedDatasetKeys.forEach((newKey, oldKey) => {
2124
- invertedRenamedKeys.set(newKey, oldKey);
2125
- });
2126
- const rightKeyForLeftKey = (leftKey) => {
2127
- return (renamedDatasetKeys == null ? void 0 : renamedDatasetKeys.get(leftKey)) || leftKey;
2128
- };
2129
- const leftKeyForRightKey = (rightKey) => {
2130
- return invertedRenamedKeys.get(rightKey) || rightKey;
2131
- };
2132
- const origBundleModelR = origCurrentBundle.model;
2133
- const adjBundleModelR = {
2134
- modelSpec: origBundleModelR.modelSpec,
2135
- getDatasetsForScenario: async (scenario, datasetKeys) => {
2136
- const rightKeys = datasetKeys.map(rightKeyForLeftKey);
2137
- const result = await origBundleModelR.getDatasetsForScenario(scenario, rightKeys);
2138
- const mapWithRightKeys = result.datasetMap;
2139
- const mapWithLeftKeys = /* @__PURE__ */ new Map();
2140
- for (const [rightKey, dataset] of mapWithRightKeys.entries()) {
2141
- const leftKey = leftKeyForRightKey(rightKey);
2142
- mapWithLeftKeys.set(leftKey, dataset);
2143
- }
2144
- return {
2145
- datasetMap: mapWithLeftKeys,
2146
- modelRunTime: result.modelRunTime
2147
- };
2148
- },
2149
- getGraphsForDataset: (_a = origBundleModelR.getGraphsForDataset) == null ? void 0 : _a.bind(origBundleModelR),
2150
- getGraphDataForScenario: origBundleModelR.getGraphDataForScenario.bind(origBundleModelR),
2151
- getGraphLinksForScenario: origBundleModelR.getGraphLinksForScenario.bind(origBundleModelR)
2152
- };
2153
- currentBundle = __spreadProps(__spreadValues({}, origCurrentBundle), {
2154
- model: adjBundleModelR
2155
- });
2156
- compareConfig = {
2157
- bundleL: baselineBundle,
2158
- bundleR: currentBundle,
2159
- thresholds: options.compare.thresholds,
2160
- scenarios: options.compare.scenarios,
2161
- datasets: options.compare.datasets
2162
- };
2154
+ if (withDiffs.length > 1) {
2155
+ if (withDiffs[0].group.kind === "by-dataset") {
2156
+ withDiffs = sortDatasetGroupSummaries(withDiffs);
2157
+ } else if (withDiffs[0].group.kind === "by-scenario") {
2158
+ withDiffs = sortScenarioGroupSummaries(withDiffs);
2159
+ }
2163
2160
  }
2164
- const checkConfig = {
2165
- bundle: currentBundle,
2166
- tests: options.check.tests
2167
- };
2168
2161
  return {
2169
- check: checkConfig,
2170
- compare: compareConfig
2162
+ allGroupSummaries,
2163
+ withErrors,
2164
+ onlyInLeft,
2165
+ onlyInRight,
2166
+ withDiffs,
2167
+ withoutDiffs
2171
2168
  };
2172
2169
  }
2173
- async function loadSynchronized(sourceBundle) {
2174
- const sourceModel = await sourceBundle.bundle.initModel();
2175
- const synchronizedModel = synchronizedBundleModel(sourceModel);
2170
+ function getScoresForGroup(group, thresholds) {
2171
+ const diffCountByBucket = Array(thresholds.length + 2).fill(0);
2172
+ const totalMaxDiffByBucket = Array(thresholds.length + 2).fill(0);
2173
+ let totalDiffCount = 0;
2174
+ for (const testSummary of group.testSummaries) {
2175
+ const bucketIndex = getBucketIndex(testSummary.md, thresholds);
2176
+ diffCountByBucket[bucketIndex]++;
2177
+ totalMaxDiffByBucket[bucketIndex] += testSummary.md;
2178
+ totalDiffCount++;
2179
+ }
2180
+ let diffPercentByBucket;
2181
+ if (totalDiffCount > 0) {
2182
+ diffPercentByBucket = diffCountByBucket.map((count) => count / totalDiffCount * 100);
2183
+ } else {
2184
+ diffPercentByBucket = [];
2185
+ }
2176
2186
  return {
2177
- name: sourceBundle.name,
2178
- version: sourceBundle.bundle.version,
2179
- model: synchronizedModel
2187
+ totalDiffCount,
2188
+ totalMaxDiffByBucket,
2189
+ diffCountByBucket,
2190
+ diffPercentByBucket
2180
2191
  };
2181
2192
  }
2182
-
2183
- // src/config/dataset-manager.ts
2184
- var DatasetManager = class {
2185
- constructor(bundleL, bundleR, renamedDatasetKeys) {
2186
- this.bundleL = bundleL;
2187
- this.bundleR = bundleR;
2188
- this.renamedDatasetKeys = renamedDatasetKeys;
2189
- const invertedRenamedKeys = /* @__PURE__ */ new Map();
2190
- renamedDatasetKeys == null ? void 0 : renamedDatasetKeys.forEach((newKey, oldKey) => {
2191
- invertedRenamedKeys.set(newKey, oldKey);
2192
- });
2193
- function leftKeyForRightKey(rightKey) {
2194
- return invertedRenamedKeys.get(rightKey) || rightKey;
2193
+ function sortDatasetGroupSummaries(summaries) {
2194
+ return summaries.sort((a, b) => {
2195
+ var _a, _b;
2196
+ const scoreResult = compareScores(a.scores, b.scores);
2197
+ if (scoreResult !== 0) {
2198
+ return -scoreResult;
2199
+ } else {
2200
+ const aVar = a.root.outputVarL;
2201
+ const bVar = b.root.outputVarR;
2202
+ const aSource = ((_a = aVar.sourceName) == null ? void 0 : _a.toLowerCase()) || "";
2203
+ const bSource = ((_b = bVar.sourceName) == null ? void 0 : _b.toLowerCase()) || "";
2204
+ if (aSource !== bSource) {
2205
+ return aSource.localeCompare(bSource);
2206
+ } else {
2207
+ const aName = aVar.varName.toLowerCase();
2208
+ const bName = bVar.varName.toLowerCase();
2209
+ return aName.localeCompare(bName);
2210
+ }
2195
2211
  }
2196
- const allOutputVarKeysSet = /* @__PURE__ */ new Set();
2197
- const modelOutputVarKeysSet = /* @__PURE__ */ new Set();
2198
- function addOutputVars(outputVars, handleRenames) {
2199
- outputVars.forEach((outputVar, key) => {
2212
+ });
2213
+ }
2214
+ function sortScenarioGroupSummaries(summaries) {
2215
+ return summaries.sort((a, b) => {
2216
+ var _a, _b;
2217
+ const scoreResult = compareScores(a.scores, b.scores);
2218
+ if (scoreResult !== 0) {
2219
+ return -scoreResult;
2220
+ } else {
2221
+ const aScenario = a.root;
2222
+ const bScenario = b.root;
2223
+ const aTitle = aScenario.title.toLowerCase();
2224
+ const bTitle = bScenario.title.toLowerCase();
2225
+ if (aTitle !== bTitle) {
2226
+ return aTitle.localeCompare(bTitle);
2227
+ } else {
2228
+ const aSubtitle = ((_a = aScenario.subtitle) == null ? void 0 : _a.toLowerCase()) || "";
2229
+ const bSubtitle = ((_b = bScenario.subtitle) == null ? void 0 : _b.toLowerCase()) || "";
2230
+ return aSubtitle.localeCompare(bSubtitle);
2231
+ }
2232
+ }
2233
+ });
2234
+ }
2235
+ function compareScores(a, b) {
2236
+ if (a.totalMaxDiffByBucket.length !== b.totalMaxDiffByBucket.length) {
2237
+ return 0;
2238
+ }
2239
+ const len = a.totalMaxDiffByBucket.length;
2240
+ for (let i = len - 1; i >= 0; i--) {
2241
+ const aTotal = a.totalMaxDiffByBucket[i];
2242
+ const bTotal = b.totalMaxDiffByBucket[i];
2243
+ if (aTotal > bTotal) {
2244
+ return 1;
2245
+ } else if (aTotal < bTotal) {
2246
+ return -1;
2247
+ }
2248
+ }
2249
+ return 0;
2250
+ }
2251
+
2252
+ // src/bundle/model-inputs.ts
2253
+ var ModelInputs = class {
2254
+ constructor(modelSpec) {
2255
+ this.inputsByLookupName = /* @__PURE__ */ new Map();
2256
+ this.inputIdAliases = /* @__PURE__ */ new Set();
2257
+ for (const inputVar of modelSpec.inputVars.values()) {
2258
+ const varNameKey = inputVar.varName.toLowerCase();
2259
+ this.inputsByLookupName.set(varNameKey, inputVar);
2260
+ if (inputVar.inputId) {
2261
+ const idAlias = `id ${inputVar.inputId}`;
2262
+ this.inputIdAliases.add(idAlias);
2263
+ const idKey = idAlias.toLowerCase();
2264
+ this.inputsByLookupName.set(idKey, inputVar);
2265
+ }
2266
+ }
2267
+ if (modelSpec.inputAliases) {
2268
+ for (const [alias, varId] of modelSpec.inputAliases.entries()) {
2269
+ const aliasKey = alias.toLowerCase();
2270
+ if (this.inputsByLookupName.has(aliasKey)) {
2271
+ console.warn(
2272
+ `WARNING: Input variable already defined with a name that collides with alias '${alias}', skipping`
2273
+ );
2274
+ continue;
2275
+ }
2276
+ const inputVar = modelSpec.inputVars.get(varId);
2277
+ if (inputVar === void 0) {
2278
+ console.warn(`WARNING: No input variable found for '${varId}' associated with alias '${alias}', skipping`);
2279
+ continue;
2280
+ }
2281
+ this.inputsByLookupName.set(aliasKey, inputVar);
2282
+ }
2283
+ }
2284
+ }
2285
+ getAllInputIdAliases() {
2286
+ return [...this.inputIdAliases];
2287
+ }
2288
+ getInputVarForName(name) {
2289
+ return this.inputsByLookupName.get(name.toLowerCase());
2290
+ }
2291
+ };
2292
+
2293
+ // src/comparison/config/parse/comparison-parser.ts
2294
+ import Ajv2 from "ajv";
2295
+ import assertNever9 from "assert-never";
2296
+ import { err as err2, ok as ok2 } from "neverthrow";
2297
+ import yaml2 from "yaml";
2298
+
2299
+ // src/comparison/config/parse/comparison.schema.js
2300
+ var comparison_schema_default = {
2301
+ $schema: "http://json-schema.org/draft-07/schema#",
2302
+ title: "Model Comparison Test",
2303
+ type: "array",
2304
+ description: "A group of model comparison scenarios and views.",
2305
+ items: {
2306
+ $ref: "#/$defs/top_level_array_item"
2307
+ },
2308
+ $defs: {
2309
+ top_level_array_item: {
2310
+ oneOf: [
2311
+ { $ref: "#/$defs/scenario_array_item" },
2312
+ { $ref: "#/$defs/scenario_group_array_item" },
2313
+ { $ref: "#/$defs/view_group_array_item" }
2314
+ ]
2315
+ },
2316
+ scenario_array_item: {
2317
+ type: "object",
2318
+ additionalProperties: false,
2319
+ properties: {
2320
+ scenario: {
2321
+ $ref: "#/$defs/scenario"
2322
+ }
2323
+ },
2324
+ required: ["scenario"]
2325
+ },
2326
+ scenario: {
2327
+ oneOf: [
2328
+ { $ref: "#/$defs/scenario_with_input_at_position" },
2329
+ { $ref: "#/$defs/scenario_with_input_at_value" },
2330
+ { $ref: "#/$defs/scenario_with_multiple_input_settings" },
2331
+ { $ref: "#/$defs/scenario_with_inputs_in_preset_at_position" },
2332
+ { $ref: "#/$defs/scenario_preset" }
2333
+ ]
2334
+ },
2335
+ scenario_position: {
2336
+ type: "string",
2337
+ enum: ["min", "max", "default"]
2338
+ },
2339
+ scenario_with_input_at_position: {
2340
+ type: "object",
2341
+ additionalProperties: false,
2342
+ properties: {
2343
+ id: {
2344
+ type: "string"
2345
+ },
2346
+ title: {
2347
+ type: "string"
2348
+ },
2349
+ subtitle: {
2350
+ type: "string"
2351
+ },
2352
+ with: {
2353
+ type: "string"
2354
+ },
2355
+ at: {
2356
+ $ref: "#/$defs/scenario_position"
2357
+ }
2358
+ },
2359
+ required: ["with", "at"]
2360
+ },
2361
+ scenario_with_input_at_value: {
2362
+ type: "object",
2363
+ additionalProperties: false,
2364
+ properties: {
2365
+ id: {
2366
+ type: "string"
2367
+ },
2368
+ title: {
2369
+ type: "string"
2370
+ },
2371
+ subtitle: {
2372
+ type: "string"
2373
+ },
2374
+ with: {
2375
+ type: "string"
2376
+ },
2377
+ at: {
2378
+ type: "number"
2379
+ }
2380
+ },
2381
+ required: ["with", "at"]
2382
+ },
2383
+ scenario_input_at_position: {
2384
+ type: "object",
2385
+ additionalProperties: false,
2386
+ properties: {
2387
+ input: {
2388
+ type: "string"
2389
+ },
2390
+ at: {
2391
+ $ref: "#/$defs/scenario_position"
2392
+ }
2393
+ },
2394
+ required: ["input", "at"]
2395
+ },
2396
+ scenario_input_at_value: {
2397
+ type: "object",
2398
+ additionalProperties: false,
2399
+ properties: {
2400
+ input: {
2401
+ type: "string"
2402
+ },
2403
+ at: {
2404
+ type: "number"
2405
+ }
2406
+ },
2407
+ required: ["input", "at"]
2408
+ },
2409
+ scenario_input_setting: {
2410
+ oneOf: [{ $ref: "#/$defs/scenario_input_at_position" }, { $ref: "#/$defs/scenario_input_at_value" }]
2411
+ },
2412
+ scenario_input_setting_array: {
2413
+ type: "array",
2414
+ items: {
2415
+ $ref: "#/$defs/scenario_input_setting"
2416
+ },
2417
+ minItems: 1
2418
+ },
2419
+ scenario_with_multiple_input_settings: {
2420
+ type: "object",
2421
+ additionalProperties: false,
2422
+ properties: {
2423
+ id: {
2424
+ type: "string"
2425
+ },
2426
+ title: {
2427
+ type: "string"
2428
+ },
2429
+ subtitle: {
2430
+ type: "string"
2431
+ },
2432
+ with: {
2433
+ $ref: "#/$defs/scenario_input_setting_array"
2434
+ }
2435
+ },
2436
+ required: ["with"]
2437
+ },
2438
+ scenario_with_inputs_in_preset_at_position: {
2439
+ type: "object",
2440
+ additionalProperties: false,
2441
+ properties: {
2442
+ id: {
2443
+ type: "string"
2444
+ },
2445
+ title: {
2446
+ type: "string"
2447
+ },
2448
+ subtitle: {
2449
+ type: "string"
2450
+ },
2451
+ with_inputs: {
2452
+ type: "string",
2453
+ enum: ["all"]
2454
+ },
2455
+ at: {
2456
+ $ref: "#/$defs/scenario_position"
2457
+ }
2458
+ },
2459
+ required: ["with_inputs", "at"]
2460
+ },
2461
+ scenario_preset: {
2462
+ type: "object",
2463
+ additionalProperties: false,
2464
+ properties: {
2465
+ preset: {
2466
+ type: "string",
2467
+ enum: ["matrix"]
2468
+ }
2469
+ },
2470
+ required: ["preset"]
2471
+ },
2472
+ scenario_group_array_item: {
2473
+ type: "object",
2474
+ additionalProperties: false,
2475
+ properties: {
2476
+ scenario_group: {
2477
+ $ref: "#/$defs/scenario_group"
2478
+ }
2479
+ },
2480
+ required: ["scenario_group"]
2481
+ },
2482
+ scenario_group: {
2483
+ type: "object",
2484
+ additionalProperties: false,
2485
+ properties: {
2486
+ id: {
2487
+ type: "string"
2488
+ },
2489
+ title: {
2490
+ type: "string"
2491
+ },
2492
+ scenarios: {
2493
+ type: "array",
2494
+ items: {
2495
+ $ref: "#/$defs/scenario_group_scenarios_array_item"
2496
+ },
2497
+ minItems: 1
2498
+ }
2499
+ },
2500
+ required: ["title", "scenarios"]
2501
+ },
2502
+ scenario_group_scenarios_array_item: {
2503
+ oneOf: [{ $ref: "#/$defs/scenario_array_item" }, { $ref: "#/$defs/scenario_ref_array_item" }]
2504
+ },
2505
+ scenario_ref_id: {
2506
+ type: "string"
2507
+ },
2508
+ scenario_ref_object: {
2509
+ type: "object",
2510
+ additionalProperties: false,
2511
+ properties: {
2512
+ id: {
2513
+ type: "string"
2514
+ },
2515
+ title: {
2516
+ type: "string"
2517
+ },
2518
+ subtitle: {
2519
+ type: "string"
2520
+ }
2521
+ },
2522
+ required: ["id"]
2523
+ },
2524
+ scenario_ref: {
2525
+ oneOf: [{ $ref: "#/$defs/scenario_ref_id" }, { $ref: "#/$defs/scenario_ref_object" }]
2526
+ },
2527
+ scenario_ref_array_item: {
2528
+ type: "object",
2529
+ additionalProperties: false,
2530
+ properties: {
2531
+ scenario_ref: {
2532
+ $ref: "#/$defs/scenario_ref"
2533
+ }
2534
+ },
2535
+ required: ["scenario_ref"]
2536
+ },
2537
+ scenario_group_ref: {
2538
+ type: "object",
2539
+ additionalProperties: false,
2540
+ properties: {
2541
+ scenario_group_ref: {
2542
+ type: "string"
2543
+ }
2544
+ },
2545
+ required: ["scenario_group_ref"]
2546
+ },
2547
+ view: {
2548
+ type: "object",
2549
+ additionalProperties: false,
2550
+ properties: {
2551
+ title: {
2552
+ type: "string"
2553
+ },
2554
+ subtitle: {
2555
+ type: "string"
2556
+ },
2557
+ scenario_ref: {
2558
+ type: "string"
2559
+ },
2560
+ graphs: {
2561
+ $ref: "#/$defs/view_graphs"
2562
+ }
2563
+ },
2564
+ required: ["scenario_ref", "graphs"]
2565
+ },
2566
+ view_graphs: {
2567
+ oneOf: [{ $ref: "#/$defs/view_graphs_preset" }, { $ref: "#/$defs/view_graphs_array" }]
2568
+ },
2569
+ view_graphs_preset: {
2570
+ type: "string",
2571
+ enum: ["all"]
2572
+ },
2573
+ view_graphs_array: {
2574
+ type: "array",
2575
+ items: {
2576
+ type: "string"
2577
+ },
2578
+ minItems: 1
2579
+ },
2580
+ view_group_array_item: {
2581
+ type: "object",
2582
+ additionalProperties: false,
2583
+ properties: {
2584
+ view_group: {
2585
+ $ref: "#/$defs/view_group"
2586
+ }
2587
+ },
2588
+ required: ["view_group"]
2589
+ },
2590
+ view_group: {
2591
+ oneOf: [
2592
+ { $ref: "#/$defs/view_group_with_views_array" },
2593
+ { $ref: "#/$defs/view_group_shorthand_with_scenarios_array" }
2594
+ ]
2595
+ },
2596
+ view_group_with_views_array: {
2597
+ type: "object",
2598
+ additionalProperties: false,
2599
+ properties: {
2600
+ title: {
2601
+ type: "string"
2602
+ },
2603
+ views: {
2604
+ type: "array",
2605
+ items: {
2606
+ $ref: "#/$defs/view_group_views_array_item"
2607
+ },
2608
+ minItems: 1
2609
+ }
2610
+ },
2611
+ required: ["title", "views"]
2612
+ },
2613
+ view_group_views_array_item: {
2614
+ type: "object",
2615
+ additionalProperties: false,
2616
+ properties: {
2617
+ view: {
2618
+ $ref: "#/$defs/view"
2619
+ }
2620
+ }
2621
+ },
2622
+ view_group_shorthand_with_scenarios_array: {
2623
+ type: "object",
2624
+ additionalProperties: false,
2625
+ properties: {
2626
+ title: {
2627
+ type: "string"
2628
+ },
2629
+ scenarios: {
2630
+ type: "array",
2631
+ items: {
2632
+ $ref: "#/$defs/view_group_scenarios_array_item"
2633
+ },
2634
+ minItems: 1
2635
+ },
2636
+ graphs: {
2637
+ $ref: "#/$defs/view_graphs"
2638
+ }
2639
+ },
2640
+ required: ["title", "scenarios", "graphs"]
2641
+ },
2642
+ view_group_scenarios_array_item: {
2643
+ oneOf: [{ $ref: "#/$defs/scenario_ref_array_item" }, { $ref: "#/$defs/scenario_group_ref" }]
2644
+ }
2645
+ }
2646
+ };
2647
+
2648
+ // src/comparison/config/parse/comparison-parser.ts
2649
+ function parseComparisonSpecs(specSource) {
2650
+ const scenarios = [];
2651
+ const scenarioGroups = [];
2652
+ const viewGroups = [];
2653
+ const ajv = new Ajv2();
2654
+ const validate = ajv.compile(comparison_schema_default);
2655
+ let parsed;
2656
+ switch (specSource.kind) {
2657
+ case "json":
2658
+ parsed = JSON.parse(specSource.content);
2659
+ break;
2660
+ case "yaml":
2661
+ parsed = yaml2.parse(specSource.content);
2662
+ break;
2663
+ default:
2664
+ assertNever9(specSource.kind);
2665
+ }
2666
+ if (validate(parsed)) {
2667
+ for (const specItem of parsed) {
2668
+ if ("scenario" in specItem) {
2669
+ scenarios.push(scenarioSpecFromParsed(specItem.scenario));
2670
+ } else if ("scenario_group" in specItem) {
2671
+ scenarioGroups.push(scenarioGroupSpecFromParsed(specItem.scenario_group));
2672
+ } else if ("view_group" in specItem) {
2673
+ viewGroups.push(viewGroupSpecFromParsed(specItem.view_group));
2674
+ }
2675
+ }
2676
+ } else {
2677
+ let msg = "Failed to parse YAML comparison definitions";
2678
+ for (const error of validate.errors || []) {
2679
+ if (error.message) {
2680
+ msg += `
2681
+ ${error.message}`;
2682
+ }
2683
+ }
2684
+ return err2(new Error(msg));
2685
+ }
2686
+ return ok2({
2687
+ scenarios,
2688
+ scenarioGroups,
2689
+ viewGroups
2690
+ });
2691
+ }
2692
+ function scenarioSpecFromParsed(parsedScenario) {
2693
+ if (parsedScenario.preset === "matrix") {
2694
+ return {
2695
+ kind: "scenario-matrix"
2696
+ };
2697
+ }
2698
+ if (parsedScenario.with !== void 0) {
2699
+ let inputSpecs;
2700
+ if (Array.isArray(parsedScenario.with)) {
2701
+ const parsedInputs = parsedScenario.with;
2702
+ inputSpecs = parsedInputs.map(inputSpecFromParsed);
2703
+ } else {
2704
+ inputSpecs = [
2705
+ inputSpecFromParsed({
2706
+ input: parsedScenario.with,
2707
+ at: parsedScenario.at
2708
+ })
2709
+ ];
2710
+ }
2711
+ return {
2712
+ kind: "scenario-with-inputs",
2713
+ id: parsedScenario.id,
2714
+ title: parsedScenario.title,
2715
+ subtitle: parsedScenario.subtitle,
2716
+ inputs: inputSpecs
2717
+ };
2718
+ }
2719
+ if (parsedScenario.with_inputs === "all") {
2720
+ return {
2721
+ kind: "scenario-with-all-inputs",
2722
+ id: parsedScenario.id,
2723
+ title: parsedScenario.title,
2724
+ subtitle: parsedScenario.subtitle,
2725
+ position: parsedScenario.at
2726
+ };
2727
+ }
2728
+ throw new Error(`Unable to convert parsed scenario: ${JSON.stringify(parsedScenario)}`);
2729
+ }
2730
+ function inputSpecFromParsed(parsedInput) {
2731
+ if (typeof parsedInput.at === "number") {
2732
+ const value = parsedInput.at;
2733
+ return {
2734
+ kind: "input-at-value",
2735
+ inputName: parsedInput.input,
2736
+ value
2737
+ };
2738
+ } else {
2739
+ return {
2740
+ kind: "input-at-position",
2741
+ inputName: parsedInput.input,
2742
+ position: parsedInput.at
2743
+ };
2744
+ }
2745
+ }
2746
+ function scenarioGroupSpecFromParsed(parsedScenarioGroup) {
2747
+ const scenarioSpecs = parsedScenarioGroup.scenarios.map(
2748
+ (parsedScenarioOrRef) => {
2749
+ if ("scenario_ref" in parsedScenarioOrRef) {
2750
+ return scenarioRefSpecFromParsed(parsedScenarioOrRef);
2751
+ } else {
2752
+ return scenarioSpecFromParsed(parsedScenarioOrRef.scenario);
2753
+ }
2754
+ }
2755
+ );
2756
+ return {
2757
+ kind: "scenario-group",
2758
+ id: parsedScenarioGroup.id,
2759
+ title: parsedScenarioGroup.title,
2760
+ scenarios: scenarioSpecs
2761
+ };
2762
+ }
2763
+ function scenarioRefSpecFromParsed(parsedScenarioRef) {
2764
+ if (typeof parsedScenarioRef.scenario_ref === "string") {
2765
+ return {
2766
+ kind: "scenario-ref",
2767
+ scenarioId: parsedScenarioRef.scenario_ref
2768
+ };
2769
+ } else {
2770
+ return {
2771
+ kind: "scenario-ref",
2772
+ scenarioId: parsedScenarioRef.scenario_ref.id,
2773
+ title: parsedScenarioRef.scenario_ref.title,
2774
+ subtitle: parsedScenarioRef.scenario_ref.subtitle
2775
+ };
2776
+ }
2777
+ }
2778
+ function scenarioGroupRefSpecFromParsed(parsedGroupRef) {
2779
+ return {
2780
+ kind: "scenario-group-ref",
2781
+ groupId: parsedGroupRef.scenario_group_ref
2782
+ };
2783
+ }
2784
+ function viewSpecFromParsed(parsedView) {
2785
+ return {
2786
+ kind: "view",
2787
+ title: parsedView.title,
2788
+ subtitle: parsedView.subtitle,
2789
+ scenarioId: parsedView.scenario_ref,
2790
+ graphs: viewGraphsSpecFromParsed(parsedView.graphs)
2791
+ };
2792
+ }
2793
+ function viewGraphsSpecFromParsed(parsedGraphs) {
2794
+ if (parsedGraphs === "all") {
2795
+ return {
2796
+ kind: "graphs-preset",
2797
+ preset: "all"
2798
+ };
2799
+ } else {
2800
+ return {
2801
+ kind: "graphs-array",
2802
+ graphIds: parsedGraphs
2803
+ };
2804
+ }
2805
+ }
2806
+ function viewGroupSpecFromParsed(parsedViewGroup) {
2807
+ if (parsedViewGroup.views !== void 0) {
2808
+ return {
2809
+ kind: "view-group-with-views",
2810
+ title: parsedViewGroup.title,
2811
+ views: parsedViewGroup.views.map((item) => viewSpecFromParsed(item.view))
2812
+ };
2813
+ } else if (parsedViewGroup.scenarios !== void 0) {
2814
+ const scenarios = parsedViewGroup.scenarios.map(
2815
+ (parsedScenarioOrGroupRef) => {
2816
+ if ("scenario_ref" in parsedScenarioOrGroupRef) {
2817
+ return scenarioRefSpecFromParsed(parsedScenarioOrGroupRef);
2818
+ } else if ("scenario_group_ref" in parsedScenarioOrGroupRef) {
2819
+ return scenarioGroupRefSpecFromParsed(parsedScenarioOrGroupRef);
2820
+ } else {
2821
+ throw new Error("Invalid view group");
2822
+ }
2823
+ }
2824
+ );
2825
+ return {
2826
+ kind: "view-group-with-scenarios",
2827
+ title: parsedViewGroup.title,
2828
+ scenarios,
2829
+ graphs: viewGraphsSpecFromParsed(parsedViewGroup.graphs)
2830
+ };
2831
+ } else {
2832
+ throw new Error("Invalid view group");
2833
+ }
2834
+ }
2835
+
2836
+ // src/comparison/config/resolve/comparison-resolver.ts
2837
+ import { assertNever as assertNever11 } from "assert-never";
2838
+
2839
+ // src/comparison/config/resolve/comparison-scenario-specs.ts
2840
+ import { assertNever as assertNever10 } from "assert-never";
2841
+ function scenarioSpecsFromSettings(settings) {
2842
+ switch (settings.kind) {
2843
+ case "all-inputs-settings": {
2844
+ const scenario = allInputsAtPositionSpec(settings.position);
2845
+ return [scenario, scenario];
2846
+ }
2847
+ case "input-settings": {
2848
+ const specL = scenarioSpecFromInputs(settings.inputs, "left");
2849
+ const specR = scenarioSpecFromInputs(settings.inputs, "right");
2850
+ return [specL, specR];
2851
+ }
2852
+ default:
2853
+ assertNever10(settings);
2854
+ }
2855
+ }
2856
+ function scenarioSpecFromInputs(inputs, side) {
2857
+ const settings = [];
2858
+ for (const input of inputs) {
2859
+ const state = side === "left" ? input.stateL : input.stateR;
2860
+ if (state.inputVar === void 0) {
2861
+ return void 0;
2862
+ }
2863
+ const varId = state.inputVar.varId;
2864
+ if (state.position) {
2865
+ settings.push(positionSetting(varId, state.position));
2866
+ } else {
2867
+ settings.push(valueSetting(varId, state.value));
2868
+ }
2869
+ }
2870
+ return inputSettingsSpec(settings);
2871
+ }
2872
+
2873
+ // src/comparison/config/resolve/comparison-resolver.ts
2874
+ function resolveComparisonSpecs(modelInputsL, modelInputsR, specs) {
2875
+ let key = 1;
2876
+ const genKey = () => {
2877
+ return `${key++}`;
2878
+ };
2879
+ const resolvedScenarios = new ResolvedScenarios();
2880
+ for (const scenarioSpec of specs.scenarios) {
2881
+ resolvedScenarios.add(resolveScenariosFromSpec(modelInputsL, modelInputsR, scenarioSpec, genKey));
2882
+ }
2883
+ const partiallyResolvedScenarioGroups = [];
2884
+ for (const scenarioGroupSpec of specs.scenarioGroups) {
2885
+ const scenariosForGroup = [];
2886
+ for (const scenarioItem of scenarioGroupSpec.scenarios) {
2887
+ if (scenarioItem.kind === "scenario-ref") {
2888
+ scenariosForGroup.push(scenarioItem);
2889
+ } else {
2890
+ const scenarios = resolveScenariosFromSpec(modelInputsL, modelInputsR, scenarioItem, genKey);
2891
+ resolvedScenarios.add(scenarios);
2892
+ scenariosForGroup.push(...scenarios);
2893
+ }
2894
+ }
2895
+ partiallyResolvedScenarioGroups.push({
2896
+ spec: scenarioGroupSpec,
2897
+ scenarios: scenariosForGroup
2898
+ });
2899
+ }
2900
+ const resolvedScenarioGroups = new ResolvedScenarioGroups();
2901
+ for (const partiallyResolvedGroup of partiallyResolvedScenarioGroups) {
2902
+ const scenariosForGroup = [];
2903
+ for (const scenarioItem of partiallyResolvedGroup.scenarios) {
2904
+ if (scenarioItem.kind === "scenario-ref") {
2905
+ const referencedScenario = resolvedScenarios.getScenarioForId(scenarioItem.scenarioId);
2906
+ if (referencedScenario) {
2907
+ const resolvedScenario = { ...referencedScenario };
2908
+ if (scenarioItem.title) {
2909
+ resolvedScenario.title = scenarioItem.title;
2910
+ }
2911
+ if (scenarioItem.subtitle) {
2912
+ resolvedScenario.subtitle = scenarioItem.subtitle;
2913
+ }
2914
+ scenariosForGroup.push(resolvedScenario);
2915
+ } else {
2916
+ scenariosForGroup.push({
2917
+ kind: "unresolved-scenario-ref",
2918
+ scenarioId: scenarioItem.scenarioId
2919
+ });
2920
+ }
2921
+ } else {
2922
+ scenariosForGroup.push(scenarioItem);
2923
+ }
2924
+ }
2925
+ resolvedScenarioGroups.add({
2926
+ kind: "scenario-group",
2927
+ id: partiallyResolvedGroup.spec.id,
2928
+ title: partiallyResolvedGroup.spec.title,
2929
+ scenarios: scenariosForGroup
2930
+ });
2931
+ }
2932
+ const resolvedViewGroups = [];
2933
+ for (const viewGroupSpec of specs.viewGroups) {
2934
+ const resolvedViewGroup = resolveViewGroupFromSpec(resolvedScenarios, resolvedScenarioGroups, viewGroupSpec);
2935
+ resolvedViewGroups.push(resolvedViewGroup);
2936
+ }
2937
+ return {
2938
+ scenarios: resolvedScenarios.getAll(),
2939
+ scenarioGroups: resolvedScenarioGroups.getAll(),
2940
+ viewGroups: resolvedViewGroups
2941
+ };
2942
+ }
2943
+ var ResolvedScenarios = class {
2944
+ constructor() {
2945
+ this.resolvedScenarios = [];
2946
+ this.resolvedScenariosById = /* @__PURE__ */ new Map();
2947
+ }
2948
+ add(scenarios) {
2949
+ for (const resolvedScenario of scenarios) {
2950
+ this.resolvedScenarios.push(resolvedScenario);
2951
+ if (resolvedScenario.id !== void 0) {
2952
+ if (this.resolvedScenariosById.has(resolvedScenario.id)) {
2953
+ throw new Error(`Multiple scenarios defined with the same id (${resolvedScenario.id})`);
2954
+ }
2955
+ this.resolvedScenariosById.set(resolvedScenario.id, resolvedScenario);
2956
+ }
2957
+ }
2958
+ }
2959
+ getAll() {
2960
+ return this.resolvedScenarios;
2961
+ }
2962
+ getScenarioForId(id) {
2963
+ return this.resolvedScenariosById.get(id);
2964
+ }
2965
+ };
2966
+ function resolveScenariosFromSpec(modelInputsL, modelInputsR, scenarioSpec, genKey) {
2967
+ switch (scenarioSpec.kind) {
2968
+ case "scenario-matrix":
2969
+ return resolveScenarioMatrix(modelInputsL, modelInputsR, genKey);
2970
+ case "scenario-with-all-inputs": {
2971
+ const position = inputPosition2(scenarioSpec.position);
2972
+ return [
2973
+ resolveScenarioWithAllInputsAtPosition(
2974
+ genKey(),
2975
+ scenarioSpec.id,
2976
+ scenarioSpec.title,
2977
+ scenarioSpec.subtitle,
2978
+ position
2979
+ )
2980
+ ];
2981
+ }
2982
+ case "scenario-with-inputs": {
2983
+ return [
2984
+ resolveScenarioForInputSpecs(
2985
+ modelInputsL,
2986
+ modelInputsR,
2987
+ genKey(),
2988
+ scenarioSpec.id,
2989
+ scenarioSpec.title,
2990
+ scenarioSpec.subtitle,
2991
+ scenarioSpec.inputs
2992
+ )
2993
+ ];
2994
+ }
2995
+ default:
2996
+ assertNever11(scenarioSpec);
2997
+ }
2998
+ }
2999
+ function resolveScenarioMatrix(modelInputsL, modelInputsR, genKey) {
3000
+ const resolvedScenarios = [];
3001
+ resolvedScenarios.push(
3002
+ resolveScenarioWithAllInputsAtPosition(genKey(), void 0, void 0, void 0, "at-default")
3003
+ );
3004
+ const inputIdAliases = /* @__PURE__ */ new Set();
3005
+ modelInputsL.getAllInputIdAliases().forEach((alias) => inputIdAliases.add(alias));
3006
+ modelInputsR.getAllInputIdAliases().forEach((alias) => inputIdAliases.add(alias));
3007
+ for (const inputIdAlias of inputIdAliases) {
3008
+ const inputAtMin = {
3009
+ kind: "input-at-position",
3010
+ inputName: inputIdAlias,
3011
+ position: "min"
3012
+ };
3013
+ const inputAtMax = {
3014
+ kind: "input-at-position",
3015
+ inputName: inputIdAlias,
3016
+ position: "max"
3017
+ };
3018
+ resolvedScenarios.push(
3019
+ resolveScenarioForInputSpecs(modelInputsL, modelInputsR, genKey(), void 0, void 0, void 0, [inputAtMin])
3020
+ );
3021
+ resolvedScenarios.push(
3022
+ resolveScenarioForInputSpecs(modelInputsL, modelInputsR, genKey(), void 0, void 0, void 0, [inputAtMax])
3023
+ );
3024
+ }
3025
+ return resolvedScenarios;
3026
+ }
3027
+ function resolveScenarioWithAllInputsAtPosition(key, id, title, subtitle, position) {
3028
+ const settings = {
3029
+ kind: "all-inputs-settings",
3030
+ position
3031
+ };
3032
+ const [specL, specR] = scenarioSpecsFromSettings(settings);
3033
+ return {
3034
+ kind: "scenario",
3035
+ key,
3036
+ id,
3037
+ title,
3038
+ subtitle,
3039
+ settings,
3040
+ specL,
3041
+ specR
3042
+ };
3043
+ }
3044
+ function resolveScenarioForInputSpecs(modelInputsL, modelInputsR, key, id, title, subtitle, inputSpecs) {
3045
+ const resolvedInputs = inputSpecs.map((inputSpec) => {
3046
+ switch (inputSpec.kind) {
3047
+ case "input-at-position":
3048
+ return resolveInputForName(modelInputsL, modelInputsR, inputSpec.inputName, inputSpec.position);
3049
+ case "input-at-value":
3050
+ return resolveInputForName(modelInputsL, modelInputsR, inputSpec.inputName, inputSpec.value);
3051
+ default:
3052
+ assertNever11(inputSpec);
3053
+ }
3054
+ });
3055
+ const settings = {
3056
+ kind: "input-settings",
3057
+ inputs: resolvedInputs
3058
+ };
3059
+ const [specL, specR] = scenarioSpecsFromSettings(settings);
3060
+ return {
3061
+ kind: "scenario",
3062
+ key,
3063
+ id,
3064
+ title,
3065
+ subtitle,
3066
+ settings,
3067
+ specL,
3068
+ specR
3069
+ };
3070
+ }
3071
+ function resolveInputForName(modelInputsL, modelInputsR, inputName, at) {
3072
+ return {
3073
+ requestedName: inputName,
3074
+ stateL: resolveInputForNameInModel(modelInputsL, inputName, at),
3075
+ stateR: resolveInputForNameInModel(modelInputsR, inputName, at)
3076
+ };
3077
+ }
3078
+ function resolveInputForNameInModel(modelInputs, inputName, at) {
3079
+ const inputVar = modelInputs.getInputVarForName(inputName);
3080
+ if (inputVar) {
3081
+ return resolveInputVar(inputVar, at);
3082
+ } else {
3083
+ return {
3084
+ error: {
3085
+ kind: "unknown-input"
3086
+ }
3087
+ };
3088
+ }
3089
+ }
3090
+ function resolveInputVar(inputVar, at) {
3091
+ if (typeof at === "number") {
3092
+ const value = at;
3093
+ return resolveInputVarAtValue(inputVar, value);
3094
+ } else {
3095
+ const position = inputPosition2(at);
3096
+ return resolveInputVarAtPosition(inputVar, position);
3097
+ }
3098
+ }
3099
+ function resolveInputVarAtPosition(inputVar, position) {
3100
+ return {
3101
+ inputVar,
3102
+ position,
3103
+ value: inputValueAtPosition2(inputVar, position)
3104
+ };
3105
+ }
3106
+ function resolveInputVarAtValue(inputVar, value) {
3107
+ if (value >= inputVar.minValue && value <= inputVar.maxValue) {
3108
+ return {
3109
+ inputVar,
3110
+ value
3111
+ };
3112
+ } else {
3113
+ return {
3114
+ error: {
3115
+ kind: "invalid-value"
3116
+ }
3117
+ };
3118
+ }
3119
+ }
3120
+ function inputPosition2(position) {
3121
+ switch (position) {
3122
+ case "default":
3123
+ return "at-default";
3124
+ case "min":
3125
+ return "at-minimum";
3126
+ case "max":
3127
+ return "at-maximum";
3128
+ default:
3129
+ return void 0;
3130
+ }
3131
+ }
3132
+ function inputValueAtPosition2(inputVar, position) {
3133
+ switch (position) {
3134
+ case "at-default":
3135
+ return inputVar.defaultValue;
3136
+ case "at-minimum":
3137
+ return inputVar.minValue;
3138
+ case "at-maximum":
3139
+ return inputVar.maxValue;
3140
+ default:
3141
+ assertNever11(position);
3142
+ }
3143
+ }
3144
+ var ResolvedScenarioGroups = class {
3145
+ constructor() {
3146
+ this.resolvedGroups = [];
3147
+ this.resolvedGroupsById = /* @__PURE__ */ new Map();
3148
+ }
3149
+ add(group) {
3150
+ this.resolvedGroups.push(group);
3151
+ if (group.id !== void 0) {
3152
+ if (this.resolvedGroupsById.has(group.id)) {
3153
+ throw new Error(`Multiple scenario groups defined with the same id (${group.id})`);
3154
+ }
3155
+ this.resolvedGroupsById.set(group.id, group);
3156
+ }
3157
+ }
3158
+ getAll() {
3159
+ return this.resolvedGroups;
3160
+ }
3161
+ getGroupForId(id) {
3162
+ return this.resolvedGroupsById.get(id);
3163
+ }
3164
+ };
3165
+ function resolveGraphsFromSpec(graphsSpec) {
3166
+ switch (graphsSpec.kind) {
3167
+ case "graphs-preset":
3168
+ return "all";
3169
+ case "graphs-array":
3170
+ return graphsSpec.graphIds;
3171
+ default:
3172
+ assertNever11(graphsSpec);
3173
+ }
3174
+ }
3175
+ function resolveViewForScenarioId(resolvedScenarios, viewTitle, viewSubtitle, scenarioId, graphs) {
3176
+ const resolvedScenario = resolvedScenarios.getScenarioForId(scenarioId);
3177
+ if (resolvedScenario) {
3178
+ return resolveViewForScenario(viewTitle, viewSubtitle, resolvedScenario, graphs);
3179
+ } else {
3180
+ return unresolvedViewForScenarioId(viewTitle, viewSubtitle, scenarioId);
3181
+ }
3182
+ }
3183
+ function resolveViewForScenarioRefSpec(resolvedScenarios, refSpec, graphs) {
3184
+ const resolvedScenario = resolvedScenarios.getScenarioForId(refSpec.scenarioId);
3185
+ if (resolvedScenario) {
3186
+ return resolveViewForScenario(refSpec.title, refSpec.subtitle, resolvedScenario, graphs);
3187
+ } else {
3188
+ return unresolvedViewForScenarioId(void 0, void 0, refSpec.scenarioId);
3189
+ }
3190
+ }
3191
+ function resolveViewForScenario(viewTitle, viewSubtitle, resolvedScenario, graphs) {
3192
+ if (viewTitle === void 0) {
3193
+ viewTitle = resolvedScenario.title;
3194
+ if (viewTitle === void 0) {
3195
+ viewTitle = "Untitled view";
3196
+ }
3197
+ if (viewSubtitle === void 0) {
3198
+ viewSubtitle = resolvedScenario.subtitle;
3199
+ }
3200
+ }
3201
+ return {
3202
+ kind: "view",
3203
+ title: viewTitle,
3204
+ subtitle: viewSubtitle,
3205
+ scenario: resolvedScenario,
3206
+ graphs
3207
+ };
3208
+ }
3209
+ function unresolvedViewForScenarioId(viewTitle, viewSubtitle, scenarioId) {
3210
+ return {
3211
+ kind: "unresolved-view",
3212
+ title: viewTitle,
3213
+ subtitle: viewSubtitle,
3214
+ scenarioId
3215
+ };
3216
+ }
3217
+ function unresolvedViewForScenarioGroupId(viewTitle, viewSubtitle, scenarioGroupId) {
3218
+ return {
3219
+ kind: "unresolved-view",
3220
+ title: viewTitle,
3221
+ subtitle: viewSubtitle,
3222
+ scenarioGroupId
3223
+ };
3224
+ }
3225
+ function resolveViewGroupFromSpec(resolvedScenarios, resolvedScenarioGroups, viewGroupSpec) {
3226
+ let views;
3227
+ switch (viewGroupSpec.kind) {
3228
+ case "view-group-with-views": {
3229
+ views = viewGroupSpec.views.map((viewSpec) => {
3230
+ const graphs = resolveGraphsFromSpec(viewSpec.graphs);
3231
+ return resolveViewForScenarioId(
3232
+ resolvedScenarios,
3233
+ viewSpec.title,
3234
+ viewSpec.subtitle,
3235
+ viewSpec.scenarioId,
3236
+ graphs
3237
+ );
3238
+ });
3239
+ break;
3240
+ }
3241
+ case "view-group-with-scenarios": {
3242
+ const graphs = resolveGraphsFromSpec(viewGroupSpec.graphs);
3243
+ views = [];
3244
+ for (const refSpec of viewGroupSpec.scenarios) {
3245
+ switch (refSpec.kind) {
3246
+ case "scenario-ref":
3247
+ views.push(resolveViewForScenarioRefSpec(resolvedScenarios, refSpec, graphs));
3248
+ break;
3249
+ case "scenario-group-ref": {
3250
+ const resolvedGroup = resolvedScenarioGroups.getGroupForId(refSpec.groupId);
3251
+ if (resolvedGroup) {
3252
+ for (const scenario of resolvedGroup.scenarios) {
3253
+ switch (scenario.kind) {
3254
+ case "unresolved-scenario-ref":
3255
+ views.push(unresolvedViewForScenarioId(void 0, void 0, scenario.scenarioId));
3256
+ break;
3257
+ case "scenario":
3258
+ views.push(resolveViewForScenario(void 0, void 0, scenario, graphs));
3259
+ break;
3260
+ default:
3261
+ assertNever11(scenario);
3262
+ }
3263
+ }
3264
+ } else {
3265
+ views.push(unresolvedViewForScenarioGroupId(void 0, void 0, refSpec.groupId));
3266
+ }
3267
+ break;
3268
+ }
3269
+ default:
3270
+ assertNever11(refSpec);
3271
+ }
3272
+ }
3273
+ break;
3274
+ }
3275
+ default:
3276
+ assertNever11(viewGroupSpec);
3277
+ }
3278
+ return {
3279
+ kind: "view-group",
3280
+ title: viewGroupSpec.title,
3281
+ views
3282
+ };
3283
+ }
3284
+
3285
+ // src/comparison/config/comparison-config.ts
3286
+ function resolveComparisonSpecsFromSources(modelInputsL, modelInputsR, specSources) {
3287
+ const combinedSpecs = {
3288
+ scenarios: [],
3289
+ scenarioGroups: [],
3290
+ viewGroups: []
3291
+ };
3292
+ for (const specSource of specSources) {
3293
+ let specs;
3294
+ if ("kind" in specSource) {
3295
+ const parseResult = parseComparisonSpecs(specSource);
3296
+ if (parseResult.isOk()) {
3297
+ specs = parseResult.value;
3298
+ } else {
3299
+ const filenamePart = specSource.filename ? ` in ${specSource.filename}` : "";
3300
+ console.error(`ERROR: Failed to parse comparison spec${filenamePart}, skipping`);
3301
+ continue;
3302
+ }
3303
+ } else {
3304
+ specs = specSource;
3305
+ }
3306
+ combinedSpecs.scenarios.push(...specs.scenarios);
3307
+ combinedSpecs.scenarioGroups.push(...specs.scenarioGroups);
3308
+ combinedSpecs.viewGroups.push(...specs.viewGroups);
3309
+ }
3310
+ return resolveComparisonSpecs(modelInputsL, modelInputsR, combinedSpecs);
3311
+ }
3312
+
3313
+ // src/comparison/config/comparison-datasets.ts
3314
+ function getComparisonDatasets(modelSpecL, modelSpecR, datasetOptions) {
3315
+ return new ComparisonDatasetsImpl(modelSpecL, modelSpecR, datasetOptions);
3316
+ }
3317
+ var ComparisonDatasetsImpl = class {
3318
+ constructor(modelSpecL, modelSpecR, datasetOptions) {
3319
+ this.datasetOptions = datasetOptions;
3320
+ const renamedDatasetKeys = datasetOptions == null ? void 0 : datasetOptions.renamedDatasetKeys;
3321
+ const invertedRenamedKeys = /* @__PURE__ */ new Map();
3322
+ renamedDatasetKeys == null ? void 0 : renamedDatasetKeys.forEach((newKey, oldKey) => {
3323
+ invertedRenamedKeys.set(newKey, oldKey);
3324
+ });
3325
+ function leftKeyForRightKey(rightKey) {
3326
+ return invertedRenamedKeys.get(rightKey) || rightKey;
3327
+ }
3328
+ const allOutputVarKeysSet = /* @__PURE__ */ new Set();
3329
+ const modelOutputVarKeysSet = /* @__PURE__ */ new Set();
3330
+ function addOutputVars(outputVars, handleRenames) {
3331
+ outputVars.forEach((outputVar, key) => {
2200
3332
  const remappedKey = handleRenames ? leftKeyForRightKey(key) : key;
2201
3333
  allOutputVarKeysSet.add(remappedKey);
2202
3334
  if (outputVar.sourceName === void 0) {
@@ -2204,239 +3336,193 @@ var DatasetManager = class {
2204
3336
  }
2205
3337
  });
2206
3338
  }
2207
- addOutputVars(bundleL.modelSpec.outputVars, false);
2208
- addOutputVars(bundleR.modelSpec.outputVars, true);
3339
+ addOutputVars(modelSpecL.outputVars, false);
3340
+ addOutputVars(modelSpecR.outputVars, true);
2209
3341
  this.allOutputVarKeys = Array.from(allOutputVarKeysSet);
2210
3342
  this.modelOutputVarKeys = Array.from(modelOutputVarKeysSet);
2211
- }
2212
- getDatasetKeysForScenario(scenario) {
2213
- if (scenario.kind === "all-inputs" && scenario.position === "at-default") {
2214
- return this.allOutputVarKeys;
2215
- } else {
2216
- return this.modelOutputVarKeys;
3343
+ this.allDatasets = /* @__PURE__ */ new Map();
3344
+ for (const datasetKeyL of this.allOutputVarKeys) {
3345
+ const datasetKeyR = (renamedDatasetKeys == null ? void 0 : renamedDatasetKeys.get(datasetKeyL)) || datasetKeyL;
3346
+ const outputVarL = modelSpecL.outputVars.get(datasetKeyL);
3347
+ const outputVarR = modelSpecR.outputVars.get(datasetKeyR);
3348
+ this.allDatasets.set(datasetKeyL, {
3349
+ kind: "dataset",
3350
+ key: datasetKeyL,
3351
+ outputVarL,
3352
+ outputVarR
3353
+ });
2217
3354
  }
2218
3355
  }
2219
- getDatasetInfo(datasetKey) {
3356
+ getAllDatasets() {
3357
+ return this.allDatasets.values();
3358
+ }
3359
+ getDataset(datasetKey) {
3360
+ return this.allDatasets.get(datasetKey);
3361
+ }
3362
+ getDatasetKeysForScenario(scenario) {
2220
3363
  var _a;
2221
- const modelSpecL = this.bundleL.modelSpec;
2222
- const modelSpecR = this.bundleR.modelSpec;
2223
- const datasetKeyL = datasetKey;
2224
- const datasetKeyR = ((_a = this.renamedDatasetKeys) == null ? void 0 : _a.get(datasetKeyL)) || datasetKeyL;
2225
- const outputVarL = modelSpecL.outputVars.get(datasetKeyL);
2226
- const outputVarR = modelSpecR.outputVars.get(datasetKeyR);
2227
- let varName;
2228
- let newVarName;
2229
- let sourceName;
2230
- let newSourceName;
2231
- if (outputVarL && outputVarR && outputVarL.varName != outputVarR.varName) {
2232
- varName = outputVarL.varName;
2233
- newVarName = outputVarR.varName;
2234
- } else {
2235
- const outputVar = outputVarR || outputVarL;
2236
- varName = (outputVar == null ? void 0 : outputVar.varName) || "Unknown";
2237
- }
2238
- if (outputVarL && outputVarR && outputVarL.sourceName != outputVarR.sourceName) {
2239
- sourceName = outputVarL.sourceName;
2240
- newSourceName = outputVarR.sourceName;
3364
+ if (((_a = this.datasetOptions) == null ? void 0 : _a.datasetKeysForScenario) !== void 0) {
3365
+ return this.datasetOptions.datasetKeysForScenario(this.allOutputVarKeys, scenario);
2241
3366
  } else {
2242
- const outputVar = outputVarR || outputVarL;
2243
- sourceName = outputVar == null ? void 0 : outputVar.sourceName;
3367
+ if (scenario.settings.kind === "all-inputs-settings" && scenario.settings.position === "at-default") {
3368
+ return this.allOutputVarKeys;
3369
+ } else {
3370
+ return this.modelOutputVarKeys;
3371
+ }
2244
3372
  }
2245
- return {
2246
- varName,
2247
- newVarName,
2248
- sourceName,
2249
- newSourceName,
2250
- relatedItems: (outputVarR == null ? void 0 : outputVarR.relatedItems) || []
2251
- };
2252
3373
  }
2253
3374
  };
2254
3375
 
2255
- // src/config/scenario-manager.ts
2256
- import { assertNever as assertNever8 } from "assert-never";
2257
- var ScenarioManager = class {
2258
- constructor(bundleL, bundleR) {
2259
- this.bundleL = bundleL;
2260
- this.bundleR = bundleR;
2261
- this.scenarios = /* @__PURE__ */ new Map();
2262
- this.scenarioInfo = /* @__PURE__ */ new Map();
2263
- this.defaultInfoForGroup = /* @__PURE__ */ new Map();
2264
- this.groupInfo = /* @__PURE__ */ new Map();
2265
- }
2266
- getScenarios() {
2267
- return [...this.scenarios.values()];
2268
- }
2269
- getScenario(scenarioKey) {
2270
- return this.scenarios.get(scenarioKey);
2271
- }
2272
- getScenarioGroupInfo(groupKey) {
2273
- return this.groupInfo.get(groupKey);
2274
- }
2275
- getScenarioInfo(scenario, groupKey) {
2276
- if (scenario.key === "all_inputs_at_default") {
2277
- const defaultInfo = this.defaultInfoForGroup.get(groupKey);
2278
- if (defaultInfo) {
2279
- return defaultInfo;
2280
- }
2281
- }
2282
- return this.scenarioInfo.get(scenario.key);
2283
- }
2284
- setDefaultScenarioInfoForGroup(groupKey, scenarioInfo) {
2285
- this.defaultInfoForGroup.set(groupKey, scenarioInfo);
2286
- }
2287
- addScenario(scenario, scenarioInfo, groupInfo) {
2288
- this.scenarios.set(scenario.key, scenario);
2289
- if (!scenarioInfo) {
2290
- scenarioInfo = this.getInfoForScenario(scenario);
2291
- }
2292
- this.scenarioInfo.set(scenario.key, scenarioInfo);
2293
- if (!groupInfo) {
2294
- groupInfo = this.getGroupInfoForScenario(scenario);
2295
- }
2296
- this.groupInfo.set(scenario.groupKey, groupInfo);
2297
- }
2298
- addScenarioMatrix() {
2299
- const inputVarIdsL = Array.from(this.bundleL.modelSpec.inputVars.keys());
2300
- const inputVarIdsR = Array.from(this.bundleR.modelSpec.inputVars.keys());
2301
- const inputVarIds = /* @__PURE__ */ new Set([...inputVarIdsL, ...inputVarIdsR]);
2302
- this.addScenario(allInputsAtPositionScenario("at-default"));
2303
- this.addScenario(allInputsAtPositionScenario("at-minimum"));
2304
- this.addScenario(allInputsAtPositionScenario("at-maximum"));
2305
- for (const inputVarId of inputVarIds) {
2306
- this.addScenario(inputAtPositionScenario(inputVarId, inputVarId, "at-minimum"));
2307
- this.addScenario(inputAtPositionScenario(inputVarId, inputVarId, "at-maximum"));
2308
- }
2309
- }
2310
- getGroupInfoForScenario(scenario) {
2311
- switch (scenario.kind) {
2312
- case "all-inputs":
2313
- return {
2314
- title: "All Inputs",
2315
- relatedItems: []
2316
- };
2317
- case "settings":
2318
- if (scenario.settings.length === 1) {
2319
- const inputVar = this.getInputVarForSetting(scenario.settings[0]);
2320
- let relatedItems;
2321
- let subtitle;
2322
- if (inputVar == null ? void 0 : inputVar.relatedItem) {
2323
- relatedItems = [inputVar.relatedItem];
2324
- subtitle = inputVar.relatedItem.locationPath.join('&nbsp;<span class="related-sep">&gt;</span>&nbsp;');
2325
- } else {
2326
- relatedItems = [];
2327
- subtitle = void 0;
2328
- }
2329
- return {
2330
- title: (inputVar == null ? void 0 : inputVar.varName) || "Unknown Input",
2331
- subtitle,
2332
- relatedItems
2333
- };
2334
- } else {
2335
- return {
2336
- title: "Multiple Inputs",
2337
- relatedItems: this.getRelatedItemsForSettings(scenario.settings)
2338
- };
2339
- }
2340
- default:
2341
- assertNever8(scenario);
3376
+ // src/comparison/config/comparison-scenarios.ts
3377
+ function getComparisonScenarios(scenarios) {
3378
+ return new ComparisonScenariosImpl(scenarios);
3379
+ }
3380
+ var ComparisonScenariosImpl = class {
3381
+ constructor(scenarios) {
3382
+ this.scenarioDefs = /* @__PURE__ */ new Map();
3383
+ for (const scenario of scenarios) {
3384
+ this.scenarioDefs.set(scenario.key, scenario);
2342
3385
  }
2343
3386
  }
2344
- getInfoForScenario(scenario) {
2345
- switch (scenario.kind) {
2346
- case "all-inputs":
2347
- return this.getInfoForPositionSetting(void 0, scenario.position);
2348
- case "settings":
2349
- if (scenario.settings.length === 1 && scenario.settings[0].kind === "position") {
2350
- const setting = scenario.settings[0];
2351
- return this.getInfoForPositionSetting(setting.inputVarId, setting.position);
2352
- } else {
2353
- return {
2354
- title: `PLACEHOLDER (scenario info not provided)`,
2355
- position: 1
2356
- };
2357
- }
2358
- default:
2359
- assertNever8(scenario);
2360
- }
3387
+ getAllScenarios() {
3388
+ return this.scenarioDefs.values();
2361
3389
  }
2362
- getInfoForPositionSetting(inputVarId, inputPosition2) {
2363
- const title = inputPosition2.replace("-", " ");
2364
- let subtitle;
2365
- if (inputVarId) {
2366
- const inputVarL = this.bundleL.modelSpec.inputVars.get(inputVarId);
2367
- const inputVarR = this.bundleR.modelSpec.inputVars.get(inputVarId);
2368
- const valueL = inputValue(inputVarL, inputPosition2);
2369
- const valueR = inputValue(inputVarR, inputPosition2);
2370
- if (valueL !== valueR) {
2371
- let values = "";
2372
- values += "(";
2373
- values += `<span class='dataset-color-0'>${valueL}</span>`;
2374
- values += "&nbsp;|&nbsp;";
2375
- values += `<span class='dataset-color-1'>${valueR}</span>`;
2376
- values += ")";
2377
- subtitle = values;
3390
+ getScenario(key) {
3391
+ return this.scenarioDefs.get(key);
3392
+ }
3393
+ };
3394
+
3395
+ // src/config/synchronized-model.ts
3396
+ function synchronizedBundleModel(sourceModel) {
3397
+ const promiseQueue = new PromiseQueue();
3398
+ return {
3399
+ modelSpec: sourceModel.modelSpec,
3400
+ getDatasetsForScenario: (scenarioSpec, datasetKeys) => {
3401
+ return promiseQueue.add(() => sourceModel.getDatasetsForScenario(scenarioSpec, datasetKeys));
3402
+ },
3403
+ getGraphDataForScenario: (scenarioSpec, graphId) => {
3404
+ return promiseQueue.add(() => sourceModel.getGraphDataForScenario(scenarioSpec, graphId));
3405
+ },
3406
+ getGraphLinksForScenario: sourceModel.getGraphLinksForScenario.bind(sourceModel)
3407
+ };
3408
+ }
3409
+ var PromiseQueue = class {
3410
+ constructor() {
3411
+ this.tasks = [];
3412
+ this.runningCount = 0;
3413
+ }
3414
+ add(f) {
3415
+ return new Promise((resolve, reject) => {
3416
+ const run = async () => {
3417
+ this.runningCount++;
3418
+ const promise = f();
3419
+ try {
3420
+ const result = await promise;
3421
+ resolve(result);
3422
+ } catch (e) {
3423
+ reject(e);
3424
+ } finally {
3425
+ this.runningCount--;
3426
+ this.runNext();
3427
+ }
3428
+ };
3429
+ if (this.runningCount < 1) {
3430
+ run();
2378
3431
  } else {
2379
- subtitle = `(${valueL})`;
3432
+ this.tasks.push(run);
2380
3433
  }
2381
- } else {
2382
- subtitle = void 0;
2383
- }
2384
- let position;
2385
- switch (inputPosition2) {
2386
- case "at-default":
2387
- position = 0;
2388
- break;
2389
- case "at-minimum":
2390
- position = 1;
2391
- break;
2392
- case "at-maximum":
2393
- position = 2;
2394
- break;
2395
- default:
2396
- assertNever8(inputPosition2);
2397
- }
2398
- return {
2399
- title,
2400
- subtitle,
2401
- position
2402
- };
3434
+ });
2403
3435
  }
2404
- getRelatedItemsForSettings(settings) {
2405
- const relatedItems = [];
2406
- for (const setting of settings) {
2407
- const inputVar = this.getInputVarForSetting(setting);
2408
- if (inputVar == null ? void 0 : inputVar.relatedItem) {
2409
- relatedItems.push(inputVar.relatedItem);
3436
+ runNext() {
3437
+ if (this.tasks.length > 0) {
3438
+ const task = this.tasks.shift();
3439
+ if (task) {
3440
+ task();
2410
3441
  }
2411
3442
  }
2412
- return relatedItems;
2413
- }
2414
- getInputVarForSetting(setting) {
2415
- const inputVarId = setting.inputVarId;
2416
- const inputVarL = this.bundleL.modelSpec.inputVars.get(inputVarId);
2417
- const inputVarR = this.bundleR.modelSpec.inputVars.get(inputVarId);
2418
- return inputVarR || inputVarL;
2419
3443
  }
2420
3444
  };
2421
- function inputValue(inputVar, position) {
2422
- if (inputVar) {
2423
- switch (position) {
2424
- case "at-default":
2425
- return inputVar.defaultValue.toString();
2426
- case "at-minimum":
2427
- return inputVar.minValue.toString();
2428
- case "at-maximum":
2429
- return inputVar.maxValue.toString();
2430
- default:
2431
- assertNever8(position);
2432
- }
3445
+
3446
+ // src/config/config.ts
3447
+ async function createConfig(options) {
3448
+ var _a;
3449
+ const origCurrentBundle = await loadSynchronized(options.current);
3450
+ let currentBundle;
3451
+ let comparisonConfig;
3452
+ if (options.comparison === void 0) {
3453
+ currentBundle = origCurrentBundle;
2433
3454
  } else {
2434
- return "n/a";
3455
+ const baselineBundle = await loadSynchronized(options.comparison.baseline);
3456
+ const renamedDatasetKeys = (_a = options.comparison.datasets) == null ? void 0 : _a.renamedDatasetKeys;
3457
+ const invertedRenamedKeys = /* @__PURE__ */ new Map();
3458
+ renamedDatasetKeys == null ? void 0 : renamedDatasetKeys.forEach((newKey, oldKey) => {
3459
+ invertedRenamedKeys.set(newKey, oldKey);
3460
+ });
3461
+ const rightKeyForLeftKey = (leftKey) => {
3462
+ return (renamedDatasetKeys == null ? void 0 : renamedDatasetKeys.get(leftKey)) || leftKey;
3463
+ };
3464
+ const leftKeyForRightKey = (rightKey) => {
3465
+ return invertedRenamedKeys.get(rightKey) || rightKey;
3466
+ };
3467
+ const origBundleModelR = origCurrentBundle.model;
3468
+ const adjBundleModelR = {
3469
+ modelSpec: origBundleModelR.modelSpec,
3470
+ getDatasetsForScenario: async (scenarioSpec, datasetKeys) => {
3471
+ const rightKeys = datasetKeys.map(rightKeyForLeftKey);
3472
+ const result = await origBundleModelR.getDatasetsForScenario(scenarioSpec, rightKeys);
3473
+ const mapWithRightKeys = result.datasetMap;
3474
+ const mapWithLeftKeys = /* @__PURE__ */ new Map();
3475
+ for (const [rightKey, dataset] of mapWithRightKeys.entries()) {
3476
+ const leftKey = leftKeyForRightKey(rightKey);
3477
+ mapWithLeftKeys.set(leftKey, dataset);
3478
+ }
3479
+ return {
3480
+ datasetMap: mapWithLeftKeys,
3481
+ modelRunTime: result.modelRunTime
3482
+ };
3483
+ },
3484
+ getGraphDataForScenario: origBundleModelR.getGraphDataForScenario.bind(origBundleModelR),
3485
+ getGraphLinksForScenario: origBundleModelR.getGraphLinksForScenario.bind(origBundleModelR)
3486
+ };
3487
+ currentBundle = {
3488
+ ...origCurrentBundle,
3489
+ model: adjBundleModelR
3490
+ };
3491
+ const modelSpecL = baselineBundle.model.modelSpec;
3492
+ const modelSpecR = currentBundle.model.modelSpec;
3493
+ const modelInputsL = new ModelInputs(modelSpecL);
3494
+ const modelInputsR = new ModelInputs(modelSpecR);
3495
+ const comparisonDefs = resolveComparisonSpecsFromSources(modelInputsL, modelInputsR, options.comparison.specs);
3496
+ comparisonConfig = {
3497
+ bundleL: baselineBundle,
3498
+ bundleR: currentBundle,
3499
+ thresholds: options.comparison.thresholds,
3500
+ scenarios: getComparisonScenarios(comparisonDefs.scenarios),
3501
+ datasets: getComparisonDatasets(modelSpecL, modelSpecR, options.comparison.datasets),
3502
+ viewGroups: comparisonDefs.viewGroups
3503
+ };
2435
3504
  }
3505
+ const checkConfig = {
3506
+ bundle: currentBundle,
3507
+ tests: options.check.tests
3508
+ };
3509
+ return {
3510
+ check: checkConfig,
3511
+ comparison: comparisonConfig
3512
+ };
3513
+ }
3514
+ async function loadSynchronized(sourceBundle) {
3515
+ const sourceModel = await sourceBundle.bundle.initModel();
3516
+ const synchronizedModel = synchronizedBundleModel(sourceModel);
3517
+ return {
3518
+ name: sourceBundle.name,
3519
+ version: sourceBundle.bundle.version,
3520
+ model: synchronizedModel
3521
+ };
2436
3522
  }
2437
3523
 
2438
3524
  // src/perf/perf-runner.ts
2439
- import { assertNever as assertNever9 } from "assert-never";
3525
+ import { assertNever as assertNever12 } from "assert-never";
2440
3526
 
2441
3527
  // src/perf/perf-stats.ts
2442
3528
  var PerfStats = class {
@@ -2480,26 +3566,26 @@ var PerfRunner = class {
2480
3566
  this.bundleModelL = bundleModelL;
2481
3567
  this.bundleModelR = bundleModelR;
2482
3568
  this.mode = mode;
2483
- const scenario = allInputsAtPositionScenario("at-default");
3569
+ const scenarioSpec = allInputsAtPositionSpec("at-default");
2484
3570
  this.taskQueue = new TaskQueue({
2485
3571
  process: async (request) => {
2486
3572
  switch (request.kind) {
2487
3573
  case "left": {
2488
- const result = await bundleModelL.getDatasetsForScenario(scenario, []);
3574
+ const result = await bundleModelL.getDatasetsForScenario(scenarioSpec, []);
2489
3575
  return {
2490
3576
  runTimeL: result.modelRunTime
2491
3577
  };
2492
3578
  }
2493
3579
  case "right": {
2494
- const result = await bundleModelR.getDatasetsForScenario(scenario, []);
3580
+ const result = await bundleModelR.getDatasetsForScenario(scenarioSpec, []);
2495
3581
  return {
2496
3582
  runTimeR: result.modelRunTime
2497
3583
  };
2498
3584
  }
2499
3585
  case "both": {
2500
3586
  const [resultL, resultR] = await Promise.all([
2501
- bundleModelL.getDatasetsForScenario(scenario, []),
2502
- bundleModelR.getDatasetsForScenario(scenario, [])
3587
+ bundleModelL.getDatasetsForScenario(scenarioSpec, []),
3588
+ bundleModelR.getDatasetsForScenario(scenarioSpec, [])
2503
3589
  ]);
2504
3590
  return {
2505
3591
  runTimeL: resultL.modelRunTime,
@@ -2507,7 +3593,7 @@ var PerfRunner = class {
2507
3593
  };
2508
3594
  }
2509
3595
  default:
2510
- assertNever9(request.kind);
3596
+ assertNever12(request.kind);
2511
3597
  }
2512
3598
  }
2513
3599
  });
@@ -2555,46 +3641,126 @@ var PerfRunner = class {
2555
3641
  }
2556
3642
  };
2557
3643
 
2558
- // src/suite/suite-runner.ts
2559
- import assertNever10 from "assert-never";
2560
-
2561
3644
  // src/data/data-planner.ts
2562
- var ScenarioTaskSet = class {
2563
- constructor(scenario) {
2564
- this.scenario = scenario;
2565
- this.modelTasks = /* @__PURE__ */ new Map();
2566
- this.modelImplTasks = /* @__PURE__ */ new Map();
2567
- this.requestKind = "check";
2568
- }
2569
- addTask(kind, datasetKey, dataFunc) {
2570
- if (kind === "compare") {
2571
- this.requestKind = "compare";
3645
+ var DataPlanner = class {
3646
+ constructor(batchSize) {
3647
+ this.batchSize = batchSize;
3648
+ this.taskSetsLR = /* @__PURE__ */ new Map();
3649
+ this.taskSetsL = /* @__PURE__ */ new Map();
3650
+ this.taskSetsR = /* @__PURE__ */ new Map();
3651
+ this.complete = false;
3652
+ }
3653
+ addRequest(scenarioSpecL, scenarioSpecR, datasetKey, dataAction) {
3654
+ if (scenarioSpecL === void 0 && scenarioSpecR === void 0) {
3655
+ console.warn("WARNING: Both scenario specs are undefined for DataPlanner request, skipping");
3656
+ return;
3657
+ }
3658
+ let taskSetsMap;
3659
+ let uid;
3660
+ if (scenarioSpecL && scenarioSpecR) {
3661
+ taskSetsMap = this.taskSetsLR;
3662
+ uid = scenarioPairUid(scenarioSpecL, scenarioSpecR);
3663
+ } else if (scenarioSpecR) {
3664
+ taskSetsMap = this.taskSetsR;
3665
+ uid = scenarioSpecR.uid;
3666
+ } else {
3667
+ taskSetsMap = this.taskSetsL;
3668
+ uid = scenarioSpecL.uid;
3669
+ }
3670
+ let taskSet = taskSetsMap.get(uid);
3671
+ if (!taskSet) {
3672
+ taskSet = new DataTaskSet(scenarioSpecL, scenarioSpecR);
3673
+ taskSetsMap.set(uid, taskSet);
2572
3674
  }
2573
- const dataTask = {
3675
+ taskSet.addTask({
2574
3676
  datasetKey,
2575
- dataFunc
3677
+ dataAction
3678
+ });
3679
+ }
3680
+ buildPlan() {
3681
+ if (this.complete) {
3682
+ throw new Error("DataPlanner.buildPlan() can only be called once");
3683
+ }
3684
+ this.complete = true;
3685
+ const lKeyMappings = /* @__PURE__ */ new Map();
3686
+ const rKeyMappings = /* @__PURE__ */ new Map();
3687
+ for (const lrUid of this.taskSetsLR.keys()) {
3688
+ const [lUid, rUid] = lrUid.split("::");
3689
+ if (!lKeyMappings.has(lUid)) {
3690
+ lKeyMappings.set(lUid, lrUid);
3691
+ }
3692
+ if (!rKeyMappings.has(rUid)) {
3693
+ rKeyMappings.set(rUid, lrUid);
3694
+ }
3695
+ }
3696
+ function merge(taskSetsLR, taskSetsForSide, keyMappingsForSide) {
3697
+ for (const [keyForSide, taskSetForSide] of taskSetsForSide.entries()) {
3698
+ const lrKey = keyMappingsForSide.get(keyForSide);
3699
+ if (lrKey) {
3700
+ const taskSetLR = taskSetsLR.get(lrKey);
3701
+ taskSetLR.merge(taskSetForSide);
3702
+ taskSetsForSide.delete(keyForSide);
3703
+ }
3704
+ }
3705
+ }
3706
+ merge(this.taskSetsLR, this.taskSetsL, lKeyMappings);
3707
+ merge(this.taskSetsLR, this.taskSetsR, rKeyMappings);
3708
+ const requests = [];
3709
+ const batchSize = this.batchSize;
3710
+ function addRequests(taskSets) {
3711
+ for (const taskSet of taskSets) {
3712
+ requests.push(...taskSet.buildRequests(batchSize));
3713
+ }
3714
+ }
3715
+ addRequests(this.taskSetsLR.values());
3716
+ addRequests(this.taskSetsL.values());
3717
+ addRequests(this.taskSetsR.values());
3718
+ return {
3719
+ requests
2576
3720
  };
3721
+ }
3722
+ };
3723
+ var DataTaskSet = class {
3724
+ constructor(scenarioSpecL, scenarioSpecR) {
3725
+ this.scenarioSpecL = scenarioSpecL;
3726
+ this.scenarioSpecR = scenarioSpecR;
3727
+ this.modelTasks = /* @__PURE__ */ new Map();
3728
+ this.modelImplTasks = /* @__PURE__ */ new Map();
3729
+ }
3730
+ addTask(dataTask) {
2577
3731
  let taskMap;
2578
- if (datasetKey.startsWith("ModelImpl")) {
3732
+ if (dataTask.datasetKey.startsWith("ModelImpl")) {
2579
3733
  taskMap = this.modelImplTasks;
2580
3734
  } else {
2581
3735
  taskMap = this.modelTasks;
2582
3736
  }
2583
- let tasks = taskMap.get(datasetKey);
3737
+ let tasks = taskMap.get(dataTask.datasetKey);
2584
3738
  if (!tasks) {
2585
3739
  tasks = [];
2586
- taskMap.set(datasetKey, tasks);
3740
+ taskMap.set(dataTask.datasetKey, tasks);
2587
3741
  }
2588
3742
  tasks.push(dataTask);
2589
3743
  }
3744
+ merge(otherTaskSet) {
3745
+ for (const tasks of otherTaskSet.modelTasks.values()) {
3746
+ for (const task of tasks) {
3747
+ this.addTask(task);
3748
+ }
3749
+ }
3750
+ for (const tasks of otherTaskSet.modelImplTasks.values()) {
3751
+ for (const task of tasks) {
3752
+ this.addTask(task);
3753
+ }
3754
+ }
3755
+ }
2590
3756
  buildRequests(batchSize) {
2591
3757
  const dataRequests = [];
2592
3758
  if (this.modelTasks.size > 0) {
2593
3759
  const dataTasks = [];
2594
3760
  this.modelTasks.forEach((tasks) => dataTasks.push(...tasks));
2595
3761
  dataRequests.push({
2596
- kind: this.requestKind,
2597
- scenario: this.scenario,
3762
+ scenarioSpecL: this.scenarioSpecL,
3763
+ scenarioSpecR: this.scenarioSpecR,
2598
3764
  dataTasks
2599
3765
  });
2600
3766
  }
@@ -2607,8 +3773,8 @@ var ScenarioTaskSet = class {
2607
3773
  dataTasks.push(...this.modelImplTasks.get(datasetKey));
2608
3774
  }
2609
3775
  dataRequests.push({
2610
- kind: this.requestKind,
2611
- scenario: this.scenario,
3776
+ scenarioSpecL: this.scenarioSpecL,
3777
+ scenarioSpecR: this.scenarioSpecR,
2612
3778
  dataTasks
2613
3779
  });
2614
3780
  }
@@ -2616,29 +3782,11 @@ var ScenarioTaskSet = class {
2616
3782
  return dataRequests;
2617
3783
  }
2618
3784
  };
2619
- var DataPlanner = class {
2620
- constructor(batchSize) {
2621
- this.batchSize = batchSize;
2622
- this.scenarioTaskSets = /* @__PURE__ */ new Map();
2623
- }
2624
- addRequest(kind, scenario, datasetKey, dataFunc) {
2625
- let scenarioTaskSet = this.scenarioTaskSets.get(scenario.key);
2626
- if (!scenarioTaskSet) {
2627
- scenarioTaskSet = new ScenarioTaskSet(scenario);
2628
- this.scenarioTaskSets.set(scenario.key, scenarioTaskSet);
2629
- }
2630
- scenarioTaskSet.addTask(kind, datasetKey, dataFunc);
2631
- }
2632
- buildPlan() {
2633
- const requests = [];
2634
- for (const taskSet of this.scenarioTaskSets.values()) {
2635
- requests.push(...taskSet.buildRequests(this.batchSize));
2636
- }
2637
- return {
2638
- requests
2639
- };
2640
- }
2641
- };
3785
+ function scenarioPairUid(scenarioSpecL, scenarioSpecR) {
3786
+ const uidL = (scenarioSpecL == null ? void 0 : scenarioSpecL.uid) || "";
3787
+ const uidR = (scenarioSpecR == null ? void 0 : scenarioSpecR.uid) || "";
3788
+ return `${uidL}::${uidR}`;
3789
+ }
2642
3790
 
2643
3791
  // src/check/check-runner.ts
2644
3792
  function runChecks(checkConfig, checkSpec, dataPlanner, refDataPlanner, simplifyScenarios) {
@@ -2648,7 +3796,7 @@ function runChecks(checkConfig, checkSpec, dataPlanner, refDataPlanner, simplify
2648
3796
  const checkPlan = checkPlanner.buildPlan();
2649
3797
  const refDatasets = /* @__PURE__ */ new Map();
2650
3798
  for (const [dataRefKey, dataRef] of checkPlan.dataRefs.entries()) {
2651
- refDataPlanner.addRequest("check", dataRef.scenario.scenario, dataRef.dataset.datasetKey, (datasets) => {
3799
+ refDataPlanner.addRequest(void 0, dataRef.scenario.spec, dataRef.dataset.datasetKey, (datasets) => {
2652
3800
  const dataset = datasets.datasetR;
2653
3801
  if (dataset) {
2654
3802
  refDatasets.set(dataRefKey, dataset);
@@ -2657,7 +3805,7 @@ function runChecks(checkConfig, checkSpec, dataPlanner, refDataPlanner, simplify
2657
3805
  }
2658
3806
  const checkResults = /* @__PURE__ */ new Map();
2659
3807
  for (const [checkKey, checkTask] of checkPlan.tasks.entries()) {
2660
- dataPlanner.addRequest("check", checkTask.scenario.scenario, checkTask.dataset.datasetKey, (datasets) => {
3808
+ dataPlanner.addRequest(void 0, checkTask.scenario.spec, checkTask.dataset.datasetKey, (datasets) => {
2661
3809
  const dataset = datasets.datasetR;
2662
3810
  const checkResult = runCheck(checkTask, dataset, refDatasets);
2663
3811
  checkResults.set(checkKey, checkResult);
@@ -2688,7 +3836,7 @@ function runCheck(checkTask, dataset, refDatasets) {
2688
3836
  name: dataRef.dataset.name
2689
3837
  }
2690
3838
  };
2691
- } else if (dataRef.scenario.scenario === void 0) {
3839
+ } else if (dataRef.scenario.spec === void 0) {
2692
3840
  if (dataRef.scenario.error) {
2693
3841
  return {
2694
3842
  status: "error",
@@ -2725,16 +3873,15 @@ function runCheck(checkTask, dataset, refDatasets) {
2725
3873
  return checkTask.action.run(dataset, opRefDatasets);
2726
3874
  }
2727
3875
 
2728
- // src/compare/compare-runner.ts
2729
- function runCompare(compareConfig, dataPlanner, simplifyScenarios) {
2730
- const scenarios = simplifyScenarios ? [allInputsAtPositionScenario("at-default")] : compareConfig.scenarios.getScenarios();
2731
- const datasetReports = [];
2732
- for (const scenario of scenarios) {
2733
- const datasetKeys = compareConfig.datasets.getDatasetKeysForScenario(scenario);
3876
+ // src/comparison/run/comparison-runner.ts
3877
+ function runComparisons(comparisonConfig, dataPlanner) {
3878
+ const testReports = [];
3879
+ for (const scenario of comparisonConfig.scenarios.getAllScenarios()) {
3880
+ const datasetKeys = comparisonConfig.datasets.getDatasetKeysForScenario(scenario);
2734
3881
  for (const datasetKey of datasetKeys) {
2735
- dataPlanner.addRequest("compare", scenario, datasetKey, (datasets) => {
3882
+ dataPlanner.addRequest(scenario.specL, scenario.specR, datasetKey, (datasets) => {
2736
3883
  const diffReport = diffDatasets(datasets.datasetL, datasets.datasetR);
2737
- datasetReports.push({
3884
+ testReports.push({
2738
3885
  scenarioKey: scenario.key,
2739
3886
  datasetKey,
2740
3887
  diffReport
@@ -2743,7 +3890,7 @@ function runCompare(compareConfig, dataPlanner, simplifyScenarios) {
2743
3890
  }
2744
3891
  }
2745
3892
  return () => {
2746
- return datasetReports;
3893
+ return testReports;
2747
3894
  };
2748
3895
  }
2749
3896
 
@@ -2781,9 +3928,9 @@ var SuiteRunner = class {
2781
3928
  const checkSpec = checkSpecResult.value;
2782
3929
  const simplifyScenarios = (options == null ? void 0 : options.simplifyScenarios) === true;
2783
3930
  const buildCheckReport2 = runChecks(this.config.check, checkSpec, dataPlanner, refDataPlanner, simplifyScenarios);
2784
- let buildCompareDatasetReports;
2785
- if (this.config.compare) {
2786
- buildCompareDatasetReports = runCompare(this.config.compare, dataPlanner, simplifyScenarios);
3931
+ let buildComparisonTestReports;
3932
+ if (this.config.comparison) {
3933
+ buildComparisonTestReports = runComparisons(this.config.comparison, dataPlanner);
2787
3934
  }
2788
3935
  this.taskQueue.onIdle = (error) => {
2789
3936
  var _a2, _b2, _c2, _d2;
@@ -2794,17 +3941,17 @@ var SuiteRunner = class {
2794
3941
  (_b2 = (_a2 = this.callbacks).onError) == null ? void 0 : _b2.call(_a2, error);
2795
3942
  } else {
2796
3943
  const checkReport = buildCheckReport2();
2797
- let compareReport;
2798
- if (this.config.compare) {
2799
- compareReport = {
2800
- datasetReports: buildCompareDatasetReports(),
3944
+ let comparisonReport;
3945
+ if (this.config.comparison) {
3946
+ comparisonReport = {
3947
+ testReports: buildComparisonTestReports(),
2801
3948
  perfReportL: this.perfStatsL.toReport(),
2802
3949
  perfReportR: this.perfStatsR.toReport()
2803
3950
  };
2804
3951
  }
2805
3952
  (_d2 = (_c2 = this.callbacks).onComplete) == null ? void 0 : _d2.call(_c2, {
2806
3953
  checkReport,
2807
- compareReport
3954
+ comparisonReport
2808
3955
  });
2809
3956
  }
2810
3957
  };
@@ -2813,10 +3960,10 @@ var SuiteRunner = class {
2813
3960
  const dataRequests = [...refDataPlan.requests, ...dataPlan.requests];
2814
3961
  const taskCount = dataRequests.length;
2815
3962
  if (taskCount === 0) {
2816
- let compareReport;
2817
- if (this.config.compare) {
2818
- compareReport = {
2819
- datasetReports: [],
3963
+ let comparisonReport;
3964
+ if (this.config.comparison) {
3965
+ comparisonReport = {
3966
+ testReports: [],
2820
3967
  perfReportL: this.perfStatsL.toReport(),
2821
3968
  perfReportR: this.perfStatsR.toReport()
2822
3969
  };
@@ -2827,7 +3974,7 @@ var SuiteRunner = class {
2827
3974
  checkReport: {
2828
3975
  groups: []
2829
3976
  },
2830
- compareReport
3977
+ comparisonReport
2831
3978
  });
2832
3979
  return;
2833
3980
  }
@@ -2842,34 +3989,25 @@ var SuiteRunner = class {
2842
3989
  }
2843
3990
  }
2844
3991
  async processRequest(request) {
3992
+ var _a, _b;
2845
3993
  const datasetKeySet = /* @__PURE__ */ new Set();
2846
3994
  for (const dataTask of request.dataTasks) {
2847
3995
  datasetKeySet.add(dataTask.datasetKey);
2848
3996
  }
2849
3997
  const datasetKeys = [...datasetKeySet];
2850
- const scenario = request.scenario;
2851
- let datasetsResultL;
2852
- let datasetsResultR;
2853
- switch (request.kind) {
2854
- case "check": {
2855
- const bundleModel = this.config.check.bundle.model;
2856
- datasetsResultR = await bundleModel.getDatasetsForScenario(scenario, datasetKeys);
2857
- break;
2858
- }
2859
- case "compare": {
2860
- const bundleModelL = this.config.compare.bundleL.model;
2861
- const bundleModelR = this.config.compare.bundleR.model;
2862
- const [resultL, resultR] = await Promise.all([
2863
- bundleModelL.getDatasetsForScenario(scenario, datasetKeys),
2864
- bundleModelR.getDatasetsForScenario(scenario, datasetKeys)
2865
- ]);
2866
- datasetsResultL = resultL;
2867
- datasetsResultR = resultR;
2868
- break;
3998
+ async function getDatasets(bundleModel, scenarioSpec) {
3999
+ if (bundleModel && scenarioSpec) {
4000
+ return bundleModel.getDatasetsForScenario(scenarioSpec, datasetKeys);
4001
+ } else {
4002
+ return void 0;
2869
4003
  }
2870
- default:
2871
- assertNever10(request.kind);
2872
4004
  }
4005
+ const bundleModelL = (_a = this.config.comparison) == null ? void 0 : _a.bundleL.model;
4006
+ const bundleModelR = ((_b = this.config.comparison) == null ? void 0 : _b.bundleR.model) || this.config.check.bundle.model;
4007
+ const [datasetsResultL, datasetsResultR] = await Promise.all([
4008
+ getDatasets(bundleModelL, request.scenarioSpecL),
4009
+ getDatasets(bundleModelR, request.scenarioSpecR)
4010
+ ]);
2873
4011
  if (datasetsResultL == null ? void 0 : datasetsResultL.modelRunTime) {
2874
4012
  this.perfStatsL.addRun(datasetsResultL == null ? void 0 : datasetsResultL.modelRunTime);
2875
4013
  }
@@ -2881,7 +4019,7 @@ var SuiteRunner = class {
2881
4019
  for (const dataTask of request.dataTasks) {
2882
4020
  const datasetL = datasetMapL == null ? void 0 : datasetMapL.get(dataTask.datasetKey);
2883
4021
  const datasetR = datasetMapR == null ? void 0 : datasetMapR.get(dataTask.datasetKey);
2884
- dataTask.dataFunc({
4022
+ dataTask.dataAction({
2885
4023
  datasetL,
2886
4024
  datasetR
2887
4025
  });
@@ -2896,43 +4034,34 @@ function runSuite(config, callbacks, options) {
2896
4034
  };
2897
4035
  }
2898
4036
 
2899
- // src/suite/suite-summary.ts
4037
+ // src/suite/suite-reporting.ts
2900
4038
  function suiteSummaryFromReport(suiteReport) {
2901
4039
  const checkSummary = checkSummaryFromReport(suiteReport.checkReport);
2902
- let compareSummary;
2903
- if (suiteReport.compareReport) {
2904
- compareSummary = compareSummaryFromReport(suiteReport.compareReport);
4040
+ let comparisonSummary;
4041
+ if (suiteReport.comparisonReport) {
4042
+ comparisonSummary = comparisonSummaryFromReport(suiteReport.comparisonReport);
2905
4043
  }
2906
4044
  return {
2907
4045
  checkSummary,
2908
- compareSummary
4046
+ comparisonSummary
2909
4047
  };
2910
4048
  }
2911
4049
  export {
2912
4050
  CheckDataCoordinator,
2913
- CompareDataCoordinator,
2914
- DatasetManager,
4051
+ ComparisonDataCoordinator,
2915
4052
  PerfRunner,
2916
4053
  PerfStats,
2917
- ScenarioManager,
2918
- allInputsAtPositionScenario,
4054
+ categorizeComparisonTestSummaries,
2919
4055
  checkReportFromSummary,
2920
4056
  checkSummaryFromReport,
2921
- compareDatasets,
2922
- compareSummaryFromReport,
4057
+ comparisonSummaryFromReport,
2923
4058
  createConfig,
2924
4059
  datasetMessage,
2925
4060
  diffDatasets,
2926
4061
  diffGraphs,
2927
- inputAtPositionScenario,
2928
- inputAtValueScenario,
2929
- matrixScenarios,
2930
- positionSetting,
2931
4062
  predicateMessage,
2932
4063
  runSuite,
2933
4064
  scenarioMessage,
2934
- settingsScenario,
2935
- suiteSummaryFromReport,
2936
- valueSetting
4065
+ suiteSummaryFromReport
2937
4066
  };
2938
4067
  //# sourceMappingURL=index.js.map