@sdeverywhere/check-core 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,9 +1,26 @@
1
1
  var __create = Object.create;
2
2
  var __defProp = Object.defineProperty;
3
+ var __defProps = Object.defineProperties;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
5
8
  var __getProtoOf = Object.getPrototypeOf;
6
9
  var __hasOwnProp = Object.prototype.hasOwnProperty;
10
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
11
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
12
+ var __spreadValues = (a, b) => {
13
+ for (var prop in b || (b = {}))
14
+ if (__hasOwnProp.call(b, prop))
15
+ __defNormalProp(a, prop, b[prop]);
16
+ if (__getOwnPropSymbols)
17
+ for (var prop of __getOwnPropSymbols(b)) {
18
+ if (__propIsEnum.call(b, prop))
19
+ __defNormalProp(a, prop, b[prop]);
20
+ }
21
+ return a;
22
+ };
23
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
7
24
  var __export = (target, all) => {
8
25
  for (var name in all)
9
26
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -17,10 +34,34 @@ var __copyProps = (to, from, except, desc) => {
17
34
  return to;
18
35
  };
19
36
  var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
37
+ // If the importer is in node compatibility mode or this is not an ESM
38
+ // file that has been converted to a CommonJS file using a Babel-
39
+ // compatible transform (i.e. "__esModule" has not been set), then set
40
+ // "default" to the CommonJS "module.exports" for node compatibility.
20
41
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
21
42
  mod
22
43
  ));
23
44
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
45
+ var __async = (__this, __arguments, generator) => {
46
+ return new Promise((resolve, reject) => {
47
+ var fulfilled = (value) => {
48
+ try {
49
+ step(generator.next(value));
50
+ } catch (e) {
51
+ reject(e);
52
+ }
53
+ };
54
+ var rejected = (value) => {
55
+ try {
56
+ step(generator.throw(value));
57
+ } catch (e) {
58
+ reject(e);
59
+ }
60
+ };
61
+ var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
62
+ step((generator = generator.apply(__this, __arguments)).next());
63
+ });
64
+ };
24
65
 
25
66
  // src/index.ts
26
67
  var src_exports = {};
@@ -37,6 +78,7 @@ __export(src_exports, {
37
78
  datasetMessage: () => datasetMessage,
38
79
  diffDatasets: () => diffDatasets,
39
80
  diffGraphs: () => diffGraphs,
81
+ getScoresForTestSummaries: () => getScoresForTestSummaries,
40
82
  predicateMessage: () => predicateMessage,
41
83
  runSuite: () => runSuite,
42
84
  scenarioMessage: () => scenarioMessage,
@@ -48,9 +90,13 @@ module.exports = __toCommonJS(src_exports);
48
90
  var TaskQueue = class {
49
91
  constructor(processor) {
50
92
  this.processor = processor;
93
+ /** The queue of task keys, most recent at front. */
51
94
  this.taskKeyQueue = [];
95
+ /** The map of tasks. */
52
96
  this.taskMap = /* @__PURE__ */ new Map();
97
+ /** Whether tasks are being processed. */
53
98
  this.processing = false;
99
+ /** Whether `shutdown` has been called. */
54
100
  this.stopped = false;
55
101
  }
56
102
  addTask(key, input, onComplete) {
@@ -88,39 +134,41 @@ var TaskQueue = class {
88
134
  });
89
135
  }
90
136
  }
91
- async processNextTask() {
92
- var _a, _b;
93
- const taskKey = this.taskKeyQueue.shift();
94
- if (!taskKey) {
95
- return;
96
- }
97
- const task = this.taskMap.get(taskKey);
98
- if (task) {
99
- this.taskMap.delete(taskKey);
100
- } else {
101
- return;
102
- }
103
- let output;
104
- try {
105
- output = await this.processor.process(task.input);
106
- } catch (e) {
107
- if (!this.stopped) {
108
- this.shutdown();
109
- (_a = this.onIdle) == null ? void 0 : _a.call(this, e);
137
+ processNextTask() {
138
+ return __async(this, null, function* () {
139
+ var _a, _b;
140
+ const taskKey = this.taskKeyQueue.shift();
141
+ if (!taskKey) {
142
+ return;
110
143
  }
111
- return;
112
- }
113
- task.onComplete(output);
114
- if (this.taskKeyQueue.length > 0) {
115
- setTimeout(() => {
116
- this.processNextTask();
117
- });
118
- } else {
119
- this.processing = false;
120
- if (!this.stopped) {
121
- (_b = this.onIdle) == null ? void 0 : _b.call(this);
144
+ const task = this.taskMap.get(taskKey);
145
+ if (task) {
146
+ this.taskMap.delete(taskKey);
147
+ } else {
148
+ return;
122
149
  }
123
- }
150
+ let output;
151
+ try {
152
+ output = yield this.processor.process(task.input);
153
+ } catch (e) {
154
+ if (!this.stopped) {
155
+ this.shutdown();
156
+ (_a = this.onIdle) == null ? void 0 : _a.call(this, e);
157
+ }
158
+ return;
159
+ }
160
+ task.onComplete(output);
161
+ if (this.taskKeyQueue.length > 0) {
162
+ setTimeout(() => {
163
+ this.processNextTask();
164
+ });
165
+ } else {
166
+ this.processing = false;
167
+ if (!this.stopped) {
168
+ (_b = this.onIdle) == null ? void 0 : _b.call(this);
169
+ }
170
+ }
171
+ });
124
172
  }
125
173
  };
126
174
 
@@ -129,13 +177,13 @@ var CheckDataCoordinator = class {
129
177
  constructor(bundleModel) {
130
178
  this.bundleModel = bundleModel;
131
179
  this.taskQueue = new TaskQueue({
132
- process: async (request) => {
133
- const result = await this.bundleModel.getDatasetsForScenario(request.scenarioSpec, [request.datasetKey]);
180
+ process: (request) => __async(this, null, function* () {
181
+ const result = yield this.bundleModel.getDatasetsForScenario(request.scenarioSpec, [request.datasetKey]);
134
182
  const dataset = result.datasetMap.get(request.datasetKey);
135
183
  return {
136
184
  dataset
137
185
  };
138
- }
186
+ })
139
187
  });
140
188
  }
141
189
  requestDataset(requestKey, scenarioSpec, datasetKey, onResponse) {
@@ -1688,6 +1736,24 @@ var CheckPlanner = class {
1688
1736
  dataRefs: this.dataRefs
1689
1737
  };
1690
1738
  }
1739
+ /**
1740
+ * Record any references to additional datasets contained in the given predicate.
1741
+ * For example, if the predicate is:
1742
+ * ```
1743
+ * gt:
1744
+ * dataset:
1745
+ * name: 'XYZ'
1746
+ * scenario:
1747
+ * inputs: all
1748
+ * at: default
1749
+ * ```
1750
+ * this will add a reference to the scenario/dataset pair so that the data can
1751
+ * be fetched in a later stage.
1752
+ *
1753
+ * @param predicateSpec The predicate spec.
1754
+ * @param checkScenario The scenario in which the dataset is being checked.
1755
+ * @param checkDataset The dataset that is being checked.
1756
+ */
1691
1757
  addDataRefs(predicateSpec, checkScenario, checkDataset) {
1692
1758
  let dataRefs;
1693
1759
  const addDataRef = (op) => {
@@ -1816,7 +1882,7 @@ var ComparisonDataCoordinator = class {
1816
1882
  this.bundleModelL = bundleModelL;
1817
1883
  this.bundleModelR = bundleModelR;
1818
1884
  this.taskQueue = new TaskQueue({
1819
- process: async (request) => {
1885
+ process: (request) => __async(this, null, function* () {
1820
1886
  switch (request.kind) {
1821
1887
  case "dataset":
1822
1888
  return this.processDatasetRequest(request);
@@ -1825,44 +1891,52 @@ var ComparisonDataCoordinator = class {
1825
1891
  default:
1826
1892
  (0, import_assert_never7.assertNever)(request);
1827
1893
  }
1828
- }
1894
+ })
1829
1895
  });
1830
1896
  }
1831
- async processDatasetRequest(request) {
1832
- async function fetchDatasets(bundleModel, scenarioSpec) {
1833
- if (scenarioSpec) {
1834
- return bundleModel.getDatasetsForScenario(scenarioSpec, request.datasetKeys);
1835
- } else {
1836
- return void 0;
1897
+ processDatasetRequest(request) {
1898
+ return __async(this, null, function* () {
1899
+ function fetchDatasets(bundleModel, scenarioSpec) {
1900
+ return __async(this, null, function* () {
1901
+ if (scenarioSpec) {
1902
+ return bundleModel.getDatasetsForScenario(scenarioSpec, request.datasetKeys);
1903
+ } else {
1904
+ return void 0;
1905
+ }
1906
+ });
1837
1907
  }
1838
- }
1839
- const [resultL, resultR] = await Promise.all([
1840
- fetchDatasets(this.bundleModelL, request.scenarioSpecL),
1841
- fetchDatasets(this.bundleModelR, request.scenarioSpecR)
1842
- ]);
1843
- return {
1844
- kind: "dataset",
1845
- datasetMapL: resultL == null ? void 0 : resultL.datasetMap,
1846
- datasetMapR: resultR == null ? void 0 : resultR.datasetMap
1847
- };
1908
+ const [resultL, resultR] = yield Promise.all([
1909
+ fetchDatasets(this.bundleModelL, request.scenarioSpecL),
1910
+ fetchDatasets(this.bundleModelR, request.scenarioSpecR)
1911
+ ]);
1912
+ return {
1913
+ kind: "dataset",
1914
+ datasetMapL: resultL == null ? void 0 : resultL.datasetMap,
1915
+ datasetMapR: resultR == null ? void 0 : resultR.datasetMap
1916
+ };
1917
+ });
1848
1918
  }
1849
- async processGraphDataRequest(request) {
1850
- async function fetchGraphData(bundleModel, scenarioSpec) {
1851
- if (scenarioSpec) {
1852
- return bundleModel.getGraphDataForScenario(scenarioSpec, request.graphId);
1853
- } else {
1854
- return void 0;
1919
+ processGraphDataRequest(request) {
1920
+ return __async(this, null, function* () {
1921
+ function fetchGraphData(bundleModel, scenarioSpec) {
1922
+ return __async(this, null, function* () {
1923
+ if (scenarioSpec) {
1924
+ return bundleModel.getGraphDataForScenario(scenarioSpec, request.graphId);
1925
+ } else {
1926
+ return void 0;
1927
+ }
1928
+ });
1855
1929
  }
1856
- }
1857
- const [graphDataL, graphDataR] = await Promise.all([
1858
- fetchGraphData(this.bundleModelL, request.scenarioSpecL),
1859
- fetchGraphData(this.bundleModelR, request.scenarioSpecR)
1860
- ]);
1861
- return {
1862
- kind: "graph-data",
1863
- graphDataL,
1864
- graphDataR
1865
- };
1930
+ const [graphDataL, graphDataR] = yield Promise.all([
1931
+ fetchGraphData(this.bundleModelL, request.scenarioSpecL),
1932
+ fetchGraphData(this.bundleModelR, request.scenarioSpecR)
1933
+ ]);
1934
+ return {
1935
+ kind: "graph-data",
1936
+ graphDataL,
1937
+ graphDataR
1938
+ };
1939
+ });
1866
1940
  }
1867
1941
  requestDatasetMaps(requestKey, scenarioSpecL, scenarioSpecR, datasetKeys, onResponse) {
1868
1942
  const request = {
@@ -1913,25 +1987,17 @@ function diffDatasets(datasetL, datasetR) {
1913
1987
  for (const t of times) {
1914
1988
  const valueL = datasetL.get(t);
1915
1989
  if (valueL !== void 0) {
1916
- if (valueL < minValueL)
1917
- minValueL = valueL;
1918
- if (valueL > maxValueL)
1919
- maxValueL = valueL;
1920
- if (valueL < minValue)
1921
- minValue = valueL;
1922
- if (valueL > maxValue)
1923
- maxValue = valueL;
1990
+ if (valueL < minValueL) minValueL = valueL;
1991
+ if (valueL > maxValueL) maxValueL = valueL;
1992
+ if (valueL < minValue) minValue = valueL;
1993
+ if (valueL > maxValue) maxValue = valueL;
1924
1994
  }
1925
1995
  const valueR = datasetR.get(t);
1926
1996
  if (valueR !== void 0) {
1927
- if (valueR < minValueR)
1928
- minValueR = valueR;
1929
- if (valueR > maxValueR)
1930
- maxValueR = valueR;
1931
- if (valueR < minValue)
1932
- minValue = valueR;
1933
- if (valueR > maxValue)
1934
- maxValue = valueR;
1997
+ if (valueR < minValueR) minValueR = valueR;
1998
+ if (valueR > maxValueR) maxValueR = valueR;
1999
+ if (valueR < minValue) minValue = valueR;
2000
+ if (valueR > maxValue) maxValue = valueR;
1935
2001
  }
1936
2002
  if (valueL === void 0 || valueR === void 0) {
1937
2003
  continue;
@@ -2090,9 +2156,6 @@ function restoreFromTerseSummaries(comparisonConfig, terseSummaries) {
2090
2156
  return allTestSummaries;
2091
2157
  }
2092
2158
 
2093
- // src/comparison/report/comparison-grouping.ts
2094
- var import_assert_never8 = require("assert-never");
2095
-
2096
2159
  // src/comparison/report/buckets.ts
2097
2160
  function getBucketIndex(diffPct, thresholds) {
2098
2161
  if (diffPct === 0) {
@@ -2106,7 +2169,33 @@ function getBucketIndex(diffPct, thresholds) {
2106
2169
  return thresholds.length + 1;
2107
2170
  }
2108
2171
 
2172
+ // src/comparison/report/comparison-group-scores.ts
2173
+ function getScoresForTestSummaries(testSummaries, thresholds) {
2174
+ const diffCountByBucket = Array(thresholds.length + 2).fill(0);
2175
+ const totalMaxDiffByBucket = Array(thresholds.length + 2).fill(0);
2176
+ let totalDiffCount = 0;
2177
+ for (const testSummary of testSummaries) {
2178
+ const bucketIndex = getBucketIndex(testSummary.md, thresholds);
2179
+ diffCountByBucket[bucketIndex]++;
2180
+ totalMaxDiffByBucket[bucketIndex] += testSummary.md;
2181
+ totalDiffCount++;
2182
+ }
2183
+ let diffPercentByBucket;
2184
+ if (totalDiffCount > 0) {
2185
+ diffPercentByBucket = diffCountByBucket.map((count) => count / totalDiffCount * 100);
2186
+ } else {
2187
+ diffPercentByBucket = [];
2188
+ }
2189
+ return {
2190
+ totalDiffCount,
2191
+ totalMaxDiffByBucket,
2192
+ diffCountByBucket,
2193
+ diffPercentByBucket
2194
+ };
2195
+ }
2196
+
2109
2197
  // src/comparison/report/comparison-grouping.ts
2198
+ var import_assert_never8 = require("assert-never");
2110
2199
  function categorizeComparisonTestSummaries(comparisonConfig, terseSummaries) {
2111
2200
  const allTestSummaries = restoreFromTerseSummaries(comparisonConfig, terseSummaries);
2112
2201
  const groupsByScenario = groupComparisonTestSummaries(allTestSummaries, "by-scenario");
@@ -2114,6 +2203,7 @@ function categorizeComparisonTestSummaries(comparisonConfig, terseSummaries) {
2114
2203
  const groupsByDataset = groupComparisonTestSummaries(allTestSummaries, "by-dataset");
2115
2204
  const byDataset = categorizeComparisonGroups(comparisonConfig, [...groupsByDataset.values()]);
2116
2205
  return {
2206
+ allTestSummaries,
2117
2207
  byScenario,
2118
2208
  byDataset
2119
2209
  };
@@ -2155,7 +2245,7 @@ function categorizeComparisonGroups(comparisonConfig, allGroups) {
2155
2245
  function addSummaryForGroup(group, root, validInL, validInR) {
2156
2246
  let scores;
2157
2247
  if (validInL && validInR) {
2158
- scores = getScoresForGroup(group, comparisonConfig.thresholds);
2248
+ scores = getScoresForTestSummaries(group.testSummaries, comparisonConfig.thresholds);
2159
2249
  }
2160
2250
  const groupSummary = {
2161
2251
  root,
@@ -2213,29 +2303,6 @@ function categorizeComparisonGroups(comparisonConfig, allGroups) {
2213
2303
  withoutDiffs
2214
2304
  };
2215
2305
  }
2216
- function getScoresForGroup(group, thresholds) {
2217
- const diffCountByBucket = Array(thresholds.length + 2).fill(0);
2218
- const totalMaxDiffByBucket = Array(thresholds.length + 2).fill(0);
2219
- let totalDiffCount = 0;
2220
- for (const testSummary of group.testSummaries) {
2221
- const bucketIndex = getBucketIndex(testSummary.md, thresholds);
2222
- diffCountByBucket[bucketIndex]++;
2223
- totalMaxDiffByBucket[bucketIndex] += testSummary.md;
2224
- totalDiffCount++;
2225
- }
2226
- let diffPercentByBucket;
2227
- if (totalDiffCount > 0) {
2228
- diffPercentByBucket = diffCountByBucket.map((count) => count / totalDiffCount * 100);
2229
- } else {
2230
- diffPercentByBucket = [];
2231
- }
2232
- return {
2233
- totalDiffCount,
2234
- totalMaxDiffByBucket,
2235
- diffCountByBucket,
2236
- diffPercentByBucket
2237
- };
2238
- }
2239
2306
  function sortDatasetGroupSummaries(summaries) {
2240
2307
  return summaries.sort((a, b) => {
2241
2308
  var _a, _b;
@@ -2295,47 +2362,6 @@ function compareScores(a, b) {
2295
2362
  return 0;
2296
2363
  }
2297
2364
 
2298
- // src/bundle/model-inputs.ts
2299
- var ModelInputs = class {
2300
- constructor(modelSpec) {
2301
- this.inputsByLookupName = /* @__PURE__ */ new Map();
2302
- this.inputIdAliases = /* @__PURE__ */ new Set();
2303
- for (const inputVar of modelSpec.inputVars.values()) {
2304
- const varNameKey = inputVar.varName.toLowerCase();
2305
- this.inputsByLookupName.set(varNameKey, inputVar);
2306
- if (inputVar.inputId) {
2307
- const idAlias = `id ${inputVar.inputId}`;
2308
- this.inputIdAliases.add(idAlias);
2309
- const idKey = idAlias.toLowerCase();
2310
- this.inputsByLookupName.set(idKey, inputVar);
2311
- }
2312
- }
2313
- if (modelSpec.inputAliases) {
2314
- for (const [alias, varId] of modelSpec.inputAliases.entries()) {
2315
- const aliasKey = alias.toLowerCase();
2316
- if (this.inputsByLookupName.has(aliasKey)) {
2317
- console.warn(
2318
- `WARNING: Input variable already defined with a name that collides with alias '${alias}', skipping`
2319
- );
2320
- continue;
2321
- }
2322
- const inputVar = modelSpec.inputVars.get(varId);
2323
- if (inputVar === void 0) {
2324
- console.warn(`WARNING: No input variable found for '${varId}' associated with alias '${alias}', skipping`);
2325
- continue;
2326
- }
2327
- this.inputsByLookupName.set(aliasKey, inputVar);
2328
- }
2329
- }
2330
- }
2331
- getAllInputIdAliases() {
2332
- return [...this.inputIdAliases];
2333
- }
2334
- getInputVarForName(name) {
2335
- return this.inputsByLookupName.get(name.toLowerCase());
2336
- }
2337
- };
2338
-
2339
2365
  // src/comparison/config/parse/comparison-parser.ts
2340
2366
  var import_ajv2 = __toESM(require("ajv"), 1);
2341
2367
  var import_assert_never9 = __toESM(require("assert-never"), 1);
@@ -2352,13 +2378,36 @@ var comparison_schema_default = {
2352
2378
  $ref: "#/$defs/top_level_array_item"
2353
2379
  },
2354
2380
  $defs: {
2381
+ //
2382
+ // TOP-LEVEL
2383
+ //
2355
2384
  top_level_array_item: {
2356
2385
  oneOf: [
2357
2386
  { $ref: "#/$defs/scenario_array_item" },
2358
2387
  { $ref: "#/$defs/scenario_group_array_item" },
2388
+ { $ref: "#/$defs/graph_group_array_item" },
2359
2389
  { $ref: "#/$defs/view_group_array_item" }
2360
2390
  ]
2361
2391
  },
2392
+ //
2393
+ // DATASETS
2394
+ //
2395
+ dataset: {
2396
+ type: "object",
2397
+ additionalProperties: false,
2398
+ properties: {
2399
+ name: {
2400
+ type: "string"
2401
+ },
2402
+ source: {
2403
+ type: "string"
2404
+ }
2405
+ },
2406
+ required: ["name"]
2407
+ },
2408
+ //
2409
+ // SCENARIOS
2410
+ //
2362
2411
  scenario_array_item: {
2363
2412
  type: "object",
2364
2413
  additionalProperties: false,
@@ -2375,7 +2424,9 @@ var comparison_schema_default = {
2375
2424
  { $ref: "#/$defs/scenario_with_input_at_value" },
2376
2425
  { $ref: "#/$defs/scenario_with_multiple_input_settings" },
2377
2426
  { $ref: "#/$defs/scenario_with_inputs_in_preset_at_position" },
2427
+ // { $ref: '#/$defs/scenario_with_inputs_in_group_at_position' }
2378
2428
  { $ref: "#/$defs/scenario_preset" }
2429
+ // { $ref: '#/$defs/scenario_expand_for_each_input_in_group' }
2379
2430
  ]
2380
2431
  },
2381
2432
  scenario_position: {
@@ -2515,6 +2566,9 @@ var comparison_schema_default = {
2515
2566
  },
2516
2567
  required: ["preset"]
2517
2568
  },
2569
+ //
2570
+ // SCENARIO GROUPS
2571
+ //
2518
2572
  scenario_group_array_item: {
2519
2573
  type: "object",
2520
2574
  additionalProperties: false,
@@ -2590,7 +2644,63 @@ var comparison_schema_default = {
2590
2644
  },
2591
2645
  required: ["scenario_group_ref"]
2592
2646
  },
2647
+ //
2648
+ // GRAPHS
2649
+ //
2650
+ graphs_preset: {
2651
+ type: "string",
2652
+ enum: ["all"]
2653
+ },
2654
+ graphs_array: {
2655
+ type: "array",
2656
+ items: {
2657
+ type: "string"
2658
+ },
2659
+ minItems: 1
2660
+ },
2661
+ graph_group_ref: {
2662
+ type: "object",
2663
+ additionalProperties: false,
2664
+ properties: {
2665
+ graph_group_ref: {
2666
+ type: "string"
2667
+ }
2668
+ },
2669
+ required: ["graph_group_ref"]
2670
+ },
2671
+ //
2672
+ // GRAPH GROUPS
2673
+ //
2674
+ graph_group_array_item: {
2675
+ type: "object",
2676
+ additionalProperties: false,
2677
+ properties: {
2678
+ graph_group: {
2679
+ $ref: "#/$defs/graph_group"
2680
+ }
2681
+ },
2682
+ required: ["graph_group"]
2683
+ },
2684
+ graph_group: {
2685
+ type: "object",
2686
+ additionalProperties: false,
2687
+ properties: {
2688
+ id: {
2689
+ type: "string"
2690
+ },
2691
+ graphs: {
2692
+ $ref: "#/$defs/graphs_array"
2693
+ }
2694
+ },
2695
+ required: ["id", "graphs"]
2696
+ },
2697
+ //
2698
+ // VIEWS
2699
+ //
2593
2700
  view: {
2701
+ oneOf: [{ $ref: "#/$defs/view_with_scenario" }, { $ref: "#/$defs/view_with_rows" }]
2702
+ },
2703
+ view_with_scenario: {
2594
2704
  type: "object",
2595
2705
  additionalProperties: false,
2596
2706
  properties: {
@@ -2605,24 +2715,106 @@ var comparison_schema_default = {
2605
2715
  },
2606
2716
  graphs: {
2607
2717
  $ref: "#/$defs/view_graphs"
2718
+ },
2719
+ graph_order: {
2720
+ $ref: "#/$defs/view_graph_order"
2608
2721
  }
2609
2722
  },
2610
- required: ["scenario_ref", "graphs"]
2723
+ required: ["scenario_ref"]
2611
2724
  },
2612
- view_graphs: {
2613
- oneOf: [{ $ref: "#/$defs/view_graphs_preset" }, { $ref: "#/$defs/view_graphs_array" }]
2725
+ view_with_rows: {
2726
+ type: "object",
2727
+ additionalProperties: false,
2728
+ properties: {
2729
+ title: {
2730
+ type: "string"
2731
+ },
2732
+ subtitle: {
2733
+ type: "string"
2734
+ },
2735
+ rows: {
2736
+ $ref: "#/$defs/view_rows_array"
2737
+ }
2738
+ },
2739
+ required: ["title", "rows"]
2614
2740
  },
2615
- view_graphs_preset: {
2616
- type: "string",
2617
- enum: ["all"]
2741
+ view_rows_array: {
2742
+ type: "array",
2743
+ items: {
2744
+ $ref: "#/$defs/view_rows_array_item"
2745
+ },
2746
+ minItems: 1
2618
2747
  },
2619
- view_graphs_array: {
2748
+ view_rows_array_item: {
2749
+ type: "object",
2750
+ additionalProperties: false,
2751
+ properties: {
2752
+ row: {
2753
+ $ref: "#/$defs/view_row"
2754
+ }
2755
+ }
2756
+ },
2757
+ view_row: {
2758
+ type: "object",
2759
+ additionalProperties: false,
2760
+ properties: {
2761
+ title: {
2762
+ type: "string"
2763
+ },
2764
+ subtitle: {
2765
+ type: "string"
2766
+ },
2767
+ boxes: {
2768
+ $ref: "#/$defs/view_boxes_array"
2769
+ }
2770
+ },
2771
+ required: ["title", "boxes"]
2772
+ },
2773
+ view_boxes_array: {
2620
2774
  type: "array",
2621
2775
  items: {
2622
- type: "string"
2776
+ $ref: "#/$defs/view_boxes_array_item"
2623
2777
  },
2624
2778
  minItems: 1
2625
2779
  },
2780
+ view_boxes_array_item: {
2781
+ type: "object",
2782
+ additionalProperties: false,
2783
+ properties: {
2784
+ box: {
2785
+ $ref: "#/$defs/view_box"
2786
+ }
2787
+ }
2788
+ },
2789
+ view_box: {
2790
+ type: "object",
2791
+ additionalProperties: false,
2792
+ properties: {
2793
+ title: {
2794
+ type: "string"
2795
+ },
2796
+ subtitle: {
2797
+ type: "string"
2798
+ },
2799
+ dataset: {
2800
+ $ref: "#/$defs/dataset"
2801
+ },
2802
+ scenario_ref: {
2803
+ $ref: "#/$defs/scenario_ref_id"
2804
+ }
2805
+ },
2806
+ required: ["title", "dataset", "scenario_ref"]
2807
+ },
2808
+ view_graphs: {
2809
+ oneOf: [{ $ref: "#/$defs/graphs_preset" }, { $ref: "#/$defs/graphs_array" }, { $ref: "#/$defs/graph_group_ref" }]
2810
+ },
2811
+ view_graph_order: {
2812
+ type: "string",
2813
+ enum: ["default", "grouped-by-diffs"]
2814
+ },
2815
+ //
2816
+ // VIEW GROUPS
2817
+ //
2626
2818
  view_group_array_item: {
2627
2819
  type: "object",
2628
2820
  additionalProperties: false,
@@ -2695,6 +2887,7 @@ var comparison_schema_default = {
2695
2887
  function parseComparisonSpecs(specSource) {
2696
2888
  const scenarios = [];
2697
2889
  const scenarioGroups = [];
2890
+ const graphGroups = [];
2698
2891
  const viewGroups = [];
2699
2892
  const ajv = new import_ajv2.default();
2700
2893
  const validate = ajv.compile(comparison_schema_default);
@@ -2715,6 +2908,8 @@ function parseComparisonSpecs(specSource) {
2715
2908
  scenarios.push(scenarioSpecFromParsed(specItem.scenario));
2716
2909
  } else if ("scenario_group" in specItem) {
2717
2910
  scenarioGroups.push(scenarioGroupSpecFromParsed(specItem.scenario_group));
2911
+ } else if ("graph_group" in specItem) {
2912
+ graphGroups.push(graphGroupSpecFromParsed(specItem.graph_group));
2718
2913
  } else if ("view_group" in specItem) {
2719
2914
  viewGroups.push(viewGroupSpecFromParsed(specItem.view_group));
2720
2915
  }
@@ -2732,9 +2927,17 @@ ${error.message}`;
2732
2927
  return (0, import_neverthrow2.ok)({
2733
2928
  scenarios,
2734
2929
  scenarioGroups,
2930
+ graphGroups,
2735
2931
  viewGroups
2736
2932
  });
2737
2933
  }
2934
+ function datasetSpecFromParsed(parsedDataset) {
2935
+ return {
2936
+ kind: "dataset",
2937
+ name: parsedDataset.name,
2938
+ source: parsedDataset.source
2939
+ };
2940
+ }
2738
2941
  function scenarioSpecFromParsed(parsedScenario) {
2739
2942
  if (parsedScenario.preset === "matrix") {
2740
2943
  return {
@@ -2827,13 +3030,50 @@ function scenarioGroupRefSpecFromParsed(parsedGroupRef) {
2827
3030
  groupId: parsedGroupRef.scenario_group_ref
2828
3031
  };
2829
3032
  }
3033
+ function graphGroupSpecFromParsed(parsedGraphGroup) {
3034
+ return {
3035
+ kind: "graph-group",
3036
+ id: parsedGraphGroup.id,
3037
+ graphIds: parsedGraphGroup.graphs
3038
+ };
3039
+ }
2830
3040
  function viewSpecFromParsed(parsedView) {
3041
+ let scenarioId;
3042
+ let rows;
3043
+ if (parsedView.scenario_ref !== void 0) {
3044
+ scenarioId = parsedView.scenario_ref;
3045
+ } else if (parsedView.rows !== void 0) {
3046
+ rows = parsedView.rows.map((item) => viewRowSpecFromParsed(item.row));
3047
+ }
3048
+ let graphs;
3049
+ if (parsedView.graphs !== void 0) {
3050
+ graphs = viewGraphsSpecFromParsed(parsedView.graphs);
3051
+ }
2831
3052
  return {
2832
3053
  kind: "view",
2833
3054
  title: parsedView.title,
2834
3055
  subtitle: parsedView.subtitle,
2835
- scenarioId: parsedView.scenario_ref,
2836
- graphs: viewGraphsSpecFromParsed(parsedView.graphs)
3056
+ scenarioId,
3057
+ rows,
3058
+ graphs,
3059
+ graphOrder: parsedView.graph_order
3060
+ };
3061
+ }
3062
+ function viewRowSpecFromParsed(parsedRow) {
3063
+ return {
3064
+ kind: "view-row",
3065
+ title: parsedRow.title,
3066
+ subtitle: parsedRow.subtitle,
3067
+ boxes: parsedRow.boxes.map((item) => viewBoxSpecFromParsed(item.box))
3068
+ };
3069
+ }
3070
+ function viewBoxSpecFromParsed(parsedBox) {
3071
+ return {
3072
+ kind: "view-box",
3073
+ title: parsedBox.title,
3074
+ subtitle: parsedBox.subtitle,
3075
+ dataset: datasetSpecFromParsed(parsedBox.dataset),
3076
+ scenarioId: parsedBox.scenario_ref
2837
3077
  };
2838
3078
  }
2839
3079
  function viewGraphsSpecFromParsed(parsedGraphs) {
@@ -2842,11 +3082,18 @@ function viewGraphsSpecFromParsed(parsedGraphs) {
2842
3082
  kind: "graphs-preset",
2843
3083
  preset: "all"
2844
3084
  };
2845
- } else {
3085
+ } else if (Array.isArray(parsedGraphs)) {
2846
3086
  return {
2847
3087
  kind: "graphs-array",
2848
3088
  graphIds: parsedGraphs
2849
3089
  };
3090
+ } else if ("graph_group_ref" in parsedGraphs) {
3091
+ return {
3092
+ kind: "graph-group-ref",
3093
+ groupId: parsedGraphs.graph_group_ref
3094
+ };
3095
+ } else {
3096
+ throw new Error("Invalid graphs spec in comparison view");
2850
3097
  }
2851
3098
  }
2852
3099
  function viewGroupSpecFromParsed(parsedViewGroup) {
@@ -2882,6 +3129,57 @@ function viewGroupSpecFromParsed(parsedViewGroup) {
2882
3129
  // src/comparison/config/resolve/comparison-resolver.ts
2883
3130
  var import_assert_never11 = require("assert-never");
2884
3131
 
3132
+ // src/bundle/model-inputs.ts
3133
+ var ModelInputs = class {
3134
+ constructor(modelSpec) {
3135
+ /** All inputs keyed by lookup name (lowercase variable name or alias). */
3136
+ this.inputsByLookupName = /* @__PURE__ */ new Map();
3137
+ /** All input ID aliases. */
3138
+ this.inputIdAliases = /* @__PURE__ */ new Set();
3139
+ for (const inputVar of modelSpec.inputVars.values()) {
3140
+ const varNameKey = inputVar.varName.toLowerCase();
3141
+ this.inputsByLookupName.set(varNameKey, inputVar);
3142
+ if (inputVar.inputId) {
3143
+ const idAlias = `id ${inputVar.inputId}`;
3144
+ this.inputIdAliases.add(idAlias);
3145
+ const idKey = idAlias.toLowerCase();
3146
+ this.inputsByLookupName.set(idKey, inputVar);
3147
+ }
3148
+ }
3149
+ if (modelSpec.inputAliases) {
3150
+ for (const [alias, varId] of modelSpec.inputAliases.entries()) {
3151
+ const aliasKey = alias.toLowerCase();
3152
+ if (this.inputsByLookupName.has(aliasKey)) {
3153
+ console.warn(
3154
+ `WARNING: Input variable already defined with a name that collides with alias '${alias}', skipping`
3155
+ );
3156
+ continue;
3157
+ }
3158
+ const inputVar = modelSpec.inputVars.get(varId);
3159
+ if (inputVar === void 0) {
3160
+ console.warn(`WARNING: No input variable found for '${varId}' associated with alias '${alias}', skipping`);
3161
+ continue;
3162
+ }
3163
+ this.inputsByLookupName.set(aliasKey, inputVar);
3164
+ }
3165
+ }
3166
+ }
3167
+ /**
3168
+ * Return the set of `id XYZ` aliases for all input variables.
3169
+ */
3170
+ getAllInputIdAliases() {
3171
+ return [...this.inputIdAliases];
3172
+ }
3173
+ /**
3174
+ * Return the `InputVar` that matches the requested name (either by variable name or alias).
3175
+ *
3176
+ * @param name The variable name or alias to match.
3177
+ */
3178
+ getInputVarForName(name) {
3179
+ return this.inputsByLookupName.get(name.toLowerCase());
3180
+ }
3181
+ };
3182
+
2885
3183
  // src/comparison/config/resolve/comparison-scenario-specs.ts
2886
3184
  var import_assert_never10 = require("assert-never");
2887
3185
  function scenarioSpecsFromSettings(settings) {
@@ -2906,28 +3204,34 @@ function scenarioSpecFromInputs(inputs, side) {
2906
3204
  if (state.inputVar === void 0) {
2907
3205
  return void 0;
2908
3206
  }
2909
- const varId = state.inputVar.varId;
2910
- if (state.position) {
2911
- settings.push(positionSetting(varId, state.position));
2912
- } else {
2913
- settings.push(valueSetting(varId, state.value));
2914
- }
3207
+ settings.push(inputSettingFromResolvedInputState(state));
2915
3208
  }
2916
3209
  return inputSettingsSpec(settings);
2917
3210
  }
3211
+ function inputSettingFromResolvedInputState(state) {
3212
+ const varId = state.inputVar.varId;
3213
+ if (state.position) {
3214
+ return positionSetting(varId, state.position);
3215
+ } else {
3216
+ return valueSetting(varId, state.value);
3217
+ }
3218
+ }
2918
3219
 
2919
3220
  // src/comparison/config/resolve/comparison-resolver.ts
2920
- function resolveComparisonSpecs(modelInputsL, modelInputsR, specs) {
3221
+ function resolveComparisonSpecs(modelSpecL, modelSpecR, specs) {
2921
3222
  let key = 1;
2922
3223
  const genKey = () => {
2923
3224
  return `${key++}`;
2924
3225
  };
3226
+ const modelInputsL = new ModelInputs(modelSpecL);
3227
+ const modelInputsR = new ModelInputs(modelSpecR);
3228
+ const modelOutputs = new ModelOutputs(modelSpecL, modelSpecR);
2925
3229
  const resolvedScenarios = new ResolvedScenarios();
2926
- for (const scenarioSpec of specs.scenarios) {
3230
+ for (const scenarioSpec of specs.scenarios || []) {
2927
3231
  resolvedScenarios.add(resolveScenariosFromSpec(modelInputsL, modelInputsR, scenarioSpec, genKey));
2928
3232
  }
2929
3233
  const partiallyResolvedScenarioGroups = [];
2930
- for (const scenarioGroupSpec of specs.scenarioGroups) {
3234
+ for (const scenarioGroupSpec of specs.scenarioGroups || []) {
2931
3235
  const scenariosForGroup = [];
2932
3236
  for (const scenarioItem of scenarioGroupSpec.scenarios) {
2933
3237
  if (scenarioItem.kind === "scenario-ref") {
@@ -2950,7 +3254,7 @@ function resolveComparisonSpecs(modelInputsL, modelInputsR, specs) {
2950
3254
  if (scenarioItem.kind === "scenario-ref") {
2951
3255
  const referencedScenario = resolvedScenarios.getScenarioForId(scenarioItem.scenarioId);
2952
3256
  if (referencedScenario) {
2953
- const resolvedScenario = { ...referencedScenario };
3257
+ const resolvedScenario = __spreadValues({}, referencedScenario);
2954
3258
  if (scenarioItem.title) {
2955
3259
  resolvedScenario.title = scenarioItem.title;
2956
3260
  }
@@ -2975,9 +3279,21 @@ function resolveComparisonSpecs(modelInputsL, modelInputsR, specs) {
2975
3279
  scenarios: scenariosForGroup
2976
3280
  });
2977
3281
  }
3282
+ const resolvedGraphGroups = new ResolvedGraphGroups();
3283
+ for (const graphGroupSpec of specs.graphGroups || []) {
3284
+ resolvedGraphGroups.add(graphGroupSpec);
3285
+ }
2978
3286
  const resolvedViewGroups = [];
2979
- for (const viewGroupSpec of specs.viewGroups) {
2980
- const resolvedViewGroup = resolveViewGroupFromSpec(resolvedScenarios, resolvedScenarioGroups, viewGroupSpec);
3287
+ for (const viewGroupSpec of specs.viewGroups || []) {
3288
+ const resolvedViewGroup = resolveViewGroupFromSpec(
3289
+ modelSpecL,
3290
+ modelSpecR,
3291
+ modelOutputs,
3292
+ resolvedScenarios,
3293
+ resolvedScenarioGroups,
3294
+ resolvedGraphGroups,
3295
+ viewGroupSpec
3296
+ );
2981
3297
  resolvedViewGroups.push(resolvedViewGroup);
2982
3298
  }
2983
3299
  return {
@@ -2986,9 +3302,40 @@ function resolveComparisonSpecs(modelInputsL, modelInputsR, specs) {
2986
3302
  viewGroups: resolvedViewGroups
2987
3303
  };
2988
3304
  }
3305
+ var ModelOutputs = class {
3306
+ constructor(modelSpecL, modelSpecR) {
3307
+ this.modelSpecL = modelSpecL;
3308
+ this.modelSpecR = modelSpecR;
3309
+ }
3310
+ getDatasetForName(name, source) {
3311
+ function findOutputVar(modelSpec) {
3312
+ for (const outputVar of modelSpec.outputVars.values()) {
3313
+ if (outputVar.varName === name && outputVar.sourceName === source) {
3314
+ return outputVar;
3315
+ }
3316
+ }
3317
+ return void 0;
3318
+ }
3319
+ const outputVarR = findOutputVar(this.modelSpecR);
3320
+ if (outputVarR) {
3321
+ const datasetKey = outputVarR.datasetKey;
3322
+ const outputVarL = this.modelSpecL.outputVars.get(datasetKey);
3323
+ return {
3324
+ kind: "dataset",
3325
+ key: datasetKey,
3326
+ outputVarL,
3327
+ outputVarR
3328
+ };
3329
+ } else {
3330
+ return void 0;
3331
+ }
3332
+ }
3333
+ };
2989
3334
  var ResolvedScenarios = class {
2990
3335
  constructor() {
3336
+ /** The array of all resolved scenarios. */
2991
3337
  this.resolvedScenarios = [];
3338
+ /** The set of resolved scenarios that include an ID, keyed by ID. */
2992
3339
  this.resolvedScenariosById = /* @__PURE__ */ new Map();
2993
3340
  }
2994
3341
  add(scenarios) {
@@ -3038,6 +3385,20 @@ function resolveScenariosFromSpec(modelInputsL, modelInputsR, scenarioSpec, genK
3038
3385
  )
3039
3386
  ];
3040
3387
  }
3388
+ case "scenario-with-distinct-inputs": {
3389
+ return [
3390
+ resolveScenarioForDistinctInputSpecs(
3391
+ modelInputsL,
3392
+ modelInputsR,
3393
+ genKey(),
3394
+ scenarioSpec.id,
3395
+ scenarioSpec.title,
3396
+ scenarioSpec.subtitle,
3397
+ scenarioSpec.inputsL,
3398
+ scenarioSpec.inputsR
3399
+ )
3400
+ ];
3401
+ }
3041
3402
  default:
3042
3403
  (0, import_assert_never11.assertNever)(scenarioSpec);
3043
3404
  }
@@ -3114,6 +3475,59 @@ function resolveScenarioForInputSpecs(modelInputsL, modelInputsR, key, id, title
3114
3475
  specR
3115
3476
  };
3116
3477
  }
3478
+ function resolveScenarioForDistinctInputSpecs(modelInputsL, modelInputsR, key, id, title, subtitle, inputSpecsL, inputSpecsR) {
3479
+ const inputsWithErrors = [];
3480
+ const settingsL = [];
3481
+ const settingsR = [];
3482
+ function resolveInputSpec(side, modelInputs, inputSpec) {
3483
+ let inputState;
3484
+ switch (inputSpec.kind) {
3485
+ case "input-at-position":
3486
+ inputState = resolveInputForNameInModel(modelInputs, inputSpec.inputName, inputSpec.position);
3487
+ break;
3488
+ case "input-at-value":
3489
+ inputState = resolveInputForNameInModel(modelInputs, inputSpec.inputName, inputSpec.value);
3490
+ break;
3491
+ default:
3492
+ (0, import_assert_never11.assertNever)(inputSpec);
3493
+ }
3494
+ if (inputState.error !== void 0) {
3495
+ inputsWithErrors.push({
3496
+ requestedName: inputSpec.inputName,
3497
+ stateL: side === "left" ? inputState : {},
3498
+ stateR: side === "right" ? inputState : {}
3499
+ });
3500
+ } else {
3501
+ const inputSetting = inputSettingFromResolvedInputState(inputState);
3502
+ if (side === "left") {
3503
+ settingsL.push(inputSetting);
3504
+ } else {
3505
+ settingsR.push(inputSetting);
3506
+ }
3507
+ }
3508
+ }
3509
+ inputSpecsL.forEach((inputSpec) => resolveInputSpec("left", modelInputsL, inputSpec));
3510
+ inputSpecsR.forEach((inputSpec) => resolveInputSpec("right", modelInputsR, inputSpec));
3511
+ let specL;
3512
+ let specR;
3513
+ if (inputsWithErrors.length === 0) {
3514
+ specL = inputSettingsSpec(settingsL);
3515
+ specR = inputSettingsSpec(settingsR);
3516
+ }
3517
+ return {
3518
+ kind: "scenario",
3519
+ key,
3520
+ id,
3521
+ title,
3522
+ subtitle,
3523
+ settings: {
3524
+ kind: "input-settings",
3525
+ inputs: inputsWithErrors
3526
+ },
3527
+ specL,
3528
+ specR
3529
+ };
3530
+ }
3117
3531
  function resolveInputForName(modelInputsL, modelInputsR, inputName, at) {
3118
3532
  return {
3119
3533
  requestedName: inputName,
@@ -3189,7 +3603,9 @@ function inputValueAtPosition2(inputVar, position) {
3189
3603
  }
3190
3604
  var ResolvedScenarioGroups = class {
3191
3605
  constructor() {
3606
+ /** The array of all resolved scenario groups. */
3192
3607
  this.resolvedGroups = [];
3608
+ /** The set of resolved scenario groups that include an ID, keyed by ID. */
3193
3609
  this.resolvedGroupsById = /* @__PURE__ */ new Map();
3194
3610
  }
3195
3611
  add(group) {
@@ -3208,33 +3624,73 @@ var ResolvedScenarioGroups = class {
3208
3624
  return this.resolvedGroupsById.get(id);
3209
3625
  }
3210
3626
  };
3211
- function resolveGraphsFromSpec(graphsSpec) {
3627
+ var ResolvedGraphGroups = class {
3628
+ constructor() {
3629
+ /** The set of resolved graph groups, keyed by ID. */
3630
+ this.resolvedGroupsById = /* @__PURE__ */ new Map();
3631
+ }
3632
+ add(group) {
3633
+ if (this.resolvedGroupsById.has(group.id)) {
3634
+ throw new Error(`Multiple graph groups defined with the same id (${group.id})`);
3635
+ }
3636
+ this.resolvedGroupsById.set(group.id, group);
3637
+ }
3638
+ getGroupForId(id) {
3639
+ return this.resolvedGroupsById.get(id);
3640
+ }
3641
+ };
3642
+ function resolveGraphsFromSpec(modelSpecL, modelSpecR, resolvedGraphGroups, graphsSpec) {
3212
3643
  switch (graphsSpec.kind) {
3213
- case "graphs-preset":
3214
- return "all";
3644
+ case "graphs-preset": {
3645
+ switch (graphsSpec.preset) {
3646
+ case "all": {
3647
+ const graphIds = /* @__PURE__ */ new Set();
3648
+ const addGraphIds = (modelSpec) => {
3649
+ if (modelSpec.graphSpecs) {
3650
+ for (const graphSpec of modelSpec.graphSpecs) {
3651
+ graphIds.add(graphSpec.id);
3652
+ }
3653
+ }
3654
+ };
3655
+ addGraphIds(modelSpecL);
3656
+ addGraphIds(modelSpecR);
3657
+ return [...graphIds];
3658
+ }
3659
+ default:
3660
+ (0, import_assert_never11.assertNever)(graphsSpec.preset);
3661
+ }
3662
+ }
3663
+ // eslint-disable-next-line no-fallthrough
3215
3664
  case "graphs-array":
3216
3665
  return graphsSpec.graphIds;
3666
+ case "graph-group-ref": {
3667
+ const groupSpec = resolvedGraphGroups.getGroupForId(graphsSpec.groupId);
3668
+ if (groupSpec === void 0) {
3669
+ throw new Error(`No graph group found for id ${graphsSpec.groupId}`);
3670
+ }
3671
+ return groupSpec.graphIds;
3672
+ }
3217
3673
  default:
3218
3674
  (0, import_assert_never11.assertNever)(graphsSpec);
3219
3675
  }
3220
3676
  }
3221
- function resolveViewForScenarioId(resolvedScenarios, viewTitle, viewSubtitle, scenarioId, graphs) {
3677
+ function resolveViewForScenarioId(resolvedScenarios, viewTitle, viewSubtitle, scenarioId, graphIds, graphOrder) {
3222
3678
  const resolvedScenario = resolvedScenarios.getScenarioForId(scenarioId);
3223
3679
  if (resolvedScenario) {
3224
- return resolveViewForScenario(viewTitle, viewSubtitle, resolvedScenario, graphs);
3680
+ return resolveViewForScenario(viewTitle, viewSubtitle, resolvedScenario, graphIds, graphOrder);
3225
3681
  } else {
3226
3682
  return unresolvedViewForScenarioId(viewTitle, viewSubtitle, scenarioId);
3227
3683
  }
3228
3684
  }
3229
- function resolveViewForScenarioRefSpec(resolvedScenarios, refSpec, graphs) {
3685
+ function resolveViewForScenarioRefSpec(resolvedScenarios, refSpec, graphIds, graphOrder) {
3230
3686
  const resolvedScenario = resolvedScenarios.getScenarioForId(refSpec.scenarioId);
3231
3687
  if (resolvedScenario) {
3232
- return resolveViewForScenario(refSpec.title, refSpec.subtitle, resolvedScenario, graphs);
3688
+ return resolveViewForScenario(refSpec.title, refSpec.subtitle, resolvedScenario, graphIds, graphOrder);
3233
3689
  } else {
3234
3690
  return unresolvedViewForScenarioId(void 0, void 0, refSpec.scenarioId);
3235
3691
  }
3236
3692
  }
3237
- function resolveViewForScenario(viewTitle, viewSubtitle, resolvedScenario, graphs) {
3693
+ function resolveViewForScenario(viewTitle, viewSubtitle, resolvedScenario, graphIds, graphOrder) {
3238
3694
  if (viewTitle === void 0) {
3239
3695
  viewTitle = resolvedScenario.title;
3240
3696
  if (viewTitle === void 0) {
@@ -3249,15 +3705,83 @@ function resolveViewForScenario(viewTitle, viewSubtitle, resolvedScenario, graph
3249
3705
  title: viewTitle,
3250
3706
  subtitle: viewSubtitle,
3251
3707
  scenario: resolvedScenario,
3252
- graphs
3708
+ graphIds,
3709
+ graphOrder
3710
+ };
3711
+ }
3712
+ function resolveViewBoxForSpec(modelOutputs, resolvedScenarios, boxSpec) {
3713
+ const resolvedDataset = modelOutputs.getDatasetForName(boxSpec.dataset.name, boxSpec.dataset.source);
3714
+ if (resolvedDataset === void 0) {
3715
+ return {
3716
+ kind: "unresolved-view-box",
3717
+ datasetName: boxSpec.dataset.name,
3718
+ datasetSource: boxSpec.dataset.source
3719
+ };
3720
+ }
3721
+ const resolvedScenario = resolvedScenarios.getScenarioForId(boxSpec.scenarioId);
3722
+ if (resolvedScenario === void 0) {
3723
+ return {
3724
+ kind: "unresolved-view-box",
3725
+ scenarioId: boxSpec.scenarioId
3726
+ };
3727
+ }
3728
+ return {
3729
+ kind: "view-box",
3730
+ title: boxSpec.title,
3731
+ subtitle: boxSpec.subtitle,
3732
+ dataset: resolvedDataset,
3733
+ scenario: resolvedScenario
3734
+ };
3735
+ }
3736
+ function resolveViewRowForSpec(modelOutputs, resolvedScenarios, rowSpec) {
3737
+ const resolvedBoxes = [];
3738
+ for (const boxSpec of rowSpec.boxes) {
3739
+ const box = resolveViewBoxForSpec(modelOutputs, resolvedScenarios, boxSpec);
3740
+ if (box.kind === "view-box") {
3741
+ resolvedBoxes.push(box);
3742
+ } else {
3743
+ return box;
3744
+ }
3745
+ }
3746
+ return {
3747
+ kind: "view-row",
3748
+ title: rowSpec.title,
3749
+ subtitle: rowSpec.subtitle,
3750
+ boxes: resolvedBoxes
3751
+ };
3752
+ }
3753
+ function resolveViewWithRowSpecs(modelOutputs, resolvedScenarios, viewTitle, viewSubtitle, rowSpecs) {
3754
+ const resolvedRows = [];
3755
+ for (const rowSpec of rowSpecs) {
3756
+ const row = resolveViewRowForSpec(modelOutputs, resolvedScenarios, rowSpec);
3757
+ if (row.kind === "view-row") {
3758
+ resolvedRows.push(row);
3759
+ } else {
3760
+ return unresolvedViewForScenarioId(viewTitle, viewSubtitle, row.scenarioId, row.datasetName, row.datasetSource);
3761
+ }
3762
+ }
3763
+ if (viewTitle === void 0) {
3764
+ viewTitle = "Untitled view";
3765
+ }
3766
+ return {
3767
+ kind: "view",
3768
+ title: viewTitle,
3769
+ subtitle: viewSubtitle,
3770
+ rows: resolvedRows,
3771
+ // TODO: The schema doesn't currently allow for graphs in a view that is defined
3772
+ // with rows. Probably we should have different view types to make this more clear.
3773
+ graphIds: [],
3774
+ graphOrder: "default"
3253
3775
  };
3254
3776
  }
3255
- function unresolvedViewForScenarioId(viewTitle, viewSubtitle, scenarioId) {
3777
+ function unresolvedViewForScenarioId(viewTitle, viewSubtitle, scenarioId, datasetName, datasetSource) {
3256
3778
  return {
3257
3779
  kind: "unresolved-view",
3258
3780
  title: viewTitle,
3259
3781
  subtitle: viewSubtitle,
3260
- scenarioId
3782
+ scenarioId,
3783
+ datasetName,
3784
+ datasetSource
3261
3785
  };
3262
3786
  }
3263
3787
  function unresolvedViewForScenarioGroupId(viewTitle, viewSubtitle, scenarioGroupId) {
@@ -3268,29 +3792,46 @@ function unresolvedViewForScenarioGroupId(viewTitle, viewSubtitle, scenarioGroup
3268
3792
  scenarioGroupId
3269
3793
  };
3270
3794
  }
3271
- function resolveViewGroupFromSpec(resolvedScenarios, resolvedScenarioGroups, viewGroupSpec) {
3795
+ function resolveViewGroupFromSpec(modelSpecL, modelSpecR, modelOutputs, resolvedScenarios, resolvedScenarioGroups, resolvedGraphGroups, viewGroupSpec) {
3272
3796
  let views;
3273
3797
  switch (viewGroupSpec.kind) {
3274
3798
  case "view-group-with-views": {
3275
3799
  views = viewGroupSpec.views.map((viewSpec) => {
3276
- const graphs = resolveGraphsFromSpec(viewSpec.graphs);
3277
- return resolveViewForScenarioId(
3278
- resolvedScenarios,
3279
- viewSpec.title,
3280
- viewSpec.subtitle,
3281
- viewSpec.scenarioId,
3282
- graphs
3283
- );
3800
+ if (viewSpec.scenarioId) {
3801
+ let graphIds;
3802
+ if (viewSpec.graphs) {
3803
+ graphIds = resolveGraphsFromSpec(modelSpecL, modelSpecR, resolvedGraphGroups, viewSpec.graphs);
3804
+ } else {
3805
+ graphIds = [];
3806
+ }
3807
+ return resolveViewForScenarioId(
3808
+ resolvedScenarios,
3809
+ viewSpec.title,
3810
+ viewSpec.subtitle,
3811
+ viewSpec.scenarioId,
3812
+ graphIds,
3813
+ viewSpec.graphOrder || "default"
3814
+ );
3815
+ } else {
3816
+ return resolveViewWithRowSpecs(
3817
+ modelOutputs,
3818
+ resolvedScenarios,
3819
+ viewSpec.title,
3820
+ viewSpec.subtitle,
3821
+ viewSpec.rows
3822
+ );
3823
+ }
3284
3824
  });
3285
3825
  break;
3286
3826
  }
3287
3827
  case "view-group-with-scenarios": {
3288
- const graphs = resolveGraphsFromSpec(viewGroupSpec.graphs);
3828
+ const graphIds = resolveGraphsFromSpec(modelSpecL, modelSpecR, resolvedGraphGroups, viewGroupSpec.graphs);
3829
+ const graphOrder = viewGroupSpec.graphOrder || "default";
3289
3830
  views = [];
3290
3831
  for (const refSpec of viewGroupSpec.scenarios) {
3291
3832
  switch (refSpec.kind) {
3292
3833
  case "scenario-ref":
3293
- views.push(resolveViewForScenarioRefSpec(resolvedScenarios, refSpec, graphs));
3834
+ views.push(resolveViewForScenarioRefSpec(resolvedScenarios, refSpec, graphIds, graphOrder));
3294
3835
  break;
3295
3836
  case "scenario-group-ref": {
3296
3837
  const resolvedGroup = resolvedScenarioGroups.getGroupForId(refSpec.groupId);
@@ -3301,7 +3842,7 @@ function resolveViewGroupFromSpec(resolvedScenarios, resolvedScenarioGroups, vie
3301
3842
  views.push(unresolvedViewForScenarioId(void 0, void 0, scenario.scenarioId));
3302
3843
  break;
3303
3844
  case "scenario":
3304
- views.push(resolveViewForScenario(void 0, void 0, scenario, graphs));
3845
+ views.push(resolveViewForScenario(void 0, void 0, scenario, graphIds, graphOrder));
3305
3846
  break;
3306
3847
  default:
3307
3848
  (0, import_assert_never11.assertNever)(scenario);
@@ -3329,10 +3870,11 @@ function resolveViewGroupFromSpec(resolvedScenarios, resolvedScenarioGroups, vie
3329
3870
  }
3330
3871
 
3331
3872
  // src/comparison/config/comparison-config.ts
3332
- function resolveComparisonSpecsFromSources(modelInputsL, modelInputsR, specSources) {
3873
+ function resolveComparisonSpecsFromSources(modelSpecL, modelSpecR, specSources) {
3333
3874
  const combinedSpecs = {
3334
3875
  scenarios: [],
3335
3876
  scenarioGroups: [],
3877
+ graphGroups: [],
3336
3878
  viewGroups: []
3337
3879
  };
3338
3880
  for (const specSource of specSources) {
@@ -3349,11 +3891,12 @@ function resolveComparisonSpecsFromSources(modelInputsL, modelInputsR, specSourc
3349
3891
  } else {
3350
3892
  specs = specSource;
3351
3893
  }
3352
- combinedSpecs.scenarios.push(...specs.scenarios);
3353
- combinedSpecs.scenarioGroups.push(...specs.scenarioGroups);
3354
- combinedSpecs.viewGroups.push(...specs.viewGroups);
3894
+ combinedSpecs.scenarios.push(...specs.scenarios || []);
3895
+ combinedSpecs.scenarioGroups.push(...specs.scenarioGroups || []);
3896
+ combinedSpecs.graphGroups.push(...specs.graphGroups || []);
3897
+ combinedSpecs.viewGroups.push(...specs.viewGroups || []);
3355
3898
  }
3356
- return resolveComparisonSpecs(modelInputsL, modelInputsR, combinedSpecs);
3899
+ return resolveComparisonSpecs(modelSpecL, modelSpecR, combinedSpecs);
3357
3900
  }
3358
3901
 
3359
3902
  // src/comparison/config/comparison-datasets.ts
@@ -3361,7 +3904,14 @@ function getComparisonDatasets(modelSpecL, modelSpecR, datasetOptions) {
3361
3904
  return new ComparisonDatasetsImpl(modelSpecL, modelSpecR, datasetOptions);
3362
3905
  }
3363
3906
  var ComparisonDatasetsImpl = class {
3907
+ /**
3908
+ * @param modelSpecL The model spec for the "left" bundle being compared.
3909
+ * @param modelSpecR The model spec for the "right" bundle being compared.
3910
+ * @param datasetOptions The custom configuration for the datasets to be compared.
3911
+ */
3364
3912
  constructor(modelSpecL, modelSpecR, datasetOptions) {
3913
+ this.modelSpecL = modelSpecL;
3914
+ this.modelSpecR = modelSpecR;
3365
3915
  this.datasetOptions = datasetOptions;
3366
3916
  const renamedDatasetKeys = datasetOptions == null ? void 0 : datasetOptions.renamedDatasetKeys;
3367
3917
  const invertedRenamedKeys = /* @__PURE__ */ new Map();
@@ -3399,12 +3949,15 @@ var ComparisonDatasetsImpl = class {
3399
3949
  });
3400
3950
  }
3401
3951
  }
3952
+ // from ComparisonDatasets interface
3402
3953
  getAllDatasets() {
3403
3954
  return this.allDatasets.values();
3404
3955
  }
3956
+ // from ComparisonDatasets interface
3405
3957
  getDataset(datasetKey) {
3406
3958
  return this.allDatasets.get(datasetKey);
3407
3959
  }
3960
+ // from ComparisonDatasets interface
3408
3961
  getDatasetKeysForScenario(scenario) {
3409
3962
  var _a;
3410
3963
  if (((_a = this.datasetOptions) == null ? void 0 : _a.datasetKeysForScenario) !== void 0) {
@@ -3417,7 +3970,47 @@ var ComparisonDatasetsImpl = class {
3417
3970
  }
3418
3971
  }
3419
3972
  }
3973
+ // from ComparisonDatasets interface
3974
+ getReferencePlotsForDataset(datasetKey, scenario) {
3975
+ var _a;
3976
+ if (((_a = this.datasetOptions) == null ? void 0 : _a.referencePlotsForDataset) !== void 0) {
3977
+ const dataset = this.getDataset(datasetKey);
3978
+ if (dataset !== void 0) {
3979
+ return this.datasetOptions.referencePlotsForDataset(dataset, scenario);
3980
+ }
3981
+ }
3982
+ return [];
3983
+ }
3984
+ // from ComparisonDatasets interface
3985
+ getContextGraphIdsForDataset(datasetKey, scenario) {
3986
+ var _a;
3987
+ const dataset = this.getDataset(datasetKey);
3988
+ if (dataset === void 0) {
3989
+ return [];
3990
+ }
3991
+ if (((_a = this.datasetOptions) == null ? void 0 : _a.contextGraphIdsForDataset) !== void 0) {
3992
+ return this.datasetOptions.contextGraphIdsForDataset(dataset, scenario);
3993
+ } else {
3994
+ return getContextGraphIdsForDataset(this.modelSpecL, this.modelSpecR, dataset);
3995
+ }
3996
+ }
3420
3997
  };
3998
+ function getContextGraphIdsForDataset(modelSpecL, modelSpecR, dataset) {
3999
+ const contextGraphIds = /* @__PURE__ */ new Set();
4000
+ function addGraphs(modelSpec, outputVar) {
4001
+ for (const graphSpec of modelSpec.graphSpecs || []) {
4002
+ for (const graphDatasetSpec of graphSpec.datasets) {
4003
+ if (graphDatasetSpec.datasetKey === (outputVar == null ? void 0 : outputVar.datasetKey)) {
4004
+ contextGraphIds.add(graphSpec.id);
4005
+ break;
4006
+ }
4007
+ }
4008
+ }
4009
+ }
4010
+ addGraphs(modelSpecL, dataset.outputVarL);
4011
+ addGraphs(modelSpecR, dataset.outputVarR);
4012
+ return [...contextGraphIds];
4013
+ }
3421
4014
 
3422
4015
  // src/comparison/config/comparison-scenarios.ts
3423
4016
  function getComparisonScenarios(scenarios) {
@@ -3430,9 +4023,17 @@ var ComparisonScenariosImpl = class {
3430
4023
  this.scenarioDefs.set(scenario.key, scenario);
3431
4024
  }
3432
4025
  }
4026
+ /**
4027
+ * Return all `ComparisonScenario` instances that are available for comparisons.
4028
+ */
3433
4029
  getAllScenarios() {
3434
4030
  return this.scenarioDefs.values();
3435
4031
  }
4032
+ /**
4033
+ * Return the scenario definition for the given key.
4034
+ *
4035
+ * @param key The key for the scenario.
4036
+ */
3436
4037
  getScenario(key) {
3437
4038
  return this.scenarioDefs.get(key);
3438
4039
  }
@@ -3459,11 +4060,11 @@ var PromiseQueue = class {
3459
4060
  }
3460
4061
  add(f) {
3461
4062
  return new Promise((resolve, reject) => {
3462
- const run = async () => {
4063
+ const run = () => __async(this, null, function* () {
3463
4064
  this.runningCount++;
3464
4065
  const promise = f();
3465
4066
  try {
3466
- const result = await promise;
4067
+ const result = yield promise;
3467
4068
  resolve(result);
3468
4069
  } catch (e) {
3469
4070
  reject(e);
@@ -3471,7 +4072,7 @@ var PromiseQueue = class {
3471
4072
  this.runningCount--;
3472
4073
  this.runNext();
3473
4074
  }
3474
- };
4075
+ });
3475
4076
  if (this.runningCount < 1) {
3476
4077
  run();
3477
4078
  } else {
@@ -3490,81 +4091,82 @@ var PromiseQueue = class {
3490
4091
  };
3491
4092
 
3492
4093
  // src/config/config.ts
3493
- async function createConfig(options) {
3494
- var _a;
3495
- const origCurrentBundle = await loadSynchronized(options.current);
3496
- let currentBundle;
3497
- let comparisonConfig;
3498
- if (options.comparison === void 0) {
3499
- currentBundle = origCurrentBundle;
3500
- } else {
3501
- const baselineBundle = await loadSynchronized(options.comparison.baseline);
3502
- const renamedDatasetKeys = (_a = options.comparison.datasets) == null ? void 0 : _a.renamedDatasetKeys;
3503
- const invertedRenamedKeys = /* @__PURE__ */ new Map();
3504
- renamedDatasetKeys == null ? void 0 : renamedDatasetKeys.forEach((newKey, oldKey) => {
3505
- invertedRenamedKeys.set(newKey, oldKey);
3506
- });
3507
- const rightKeyForLeftKey = (leftKey) => {
3508
- return (renamedDatasetKeys == null ? void 0 : renamedDatasetKeys.get(leftKey)) || leftKey;
3509
- };
3510
- const leftKeyForRightKey = (rightKey) => {
3511
- return invertedRenamedKeys.get(rightKey) || rightKey;
3512
- };
3513
- const origBundleModelR = origCurrentBundle.model;
3514
- const adjBundleModelR = {
3515
- modelSpec: origBundleModelR.modelSpec,
3516
- getDatasetsForScenario: async (scenarioSpec, datasetKeys) => {
3517
- const rightKeys = datasetKeys.map(rightKeyForLeftKey);
3518
- const result = await origBundleModelR.getDatasetsForScenario(scenarioSpec, rightKeys);
3519
- const mapWithRightKeys = result.datasetMap;
3520
- const mapWithLeftKeys = /* @__PURE__ */ new Map();
3521
- for (const [rightKey, dataset] of mapWithRightKeys.entries()) {
3522
- const leftKey = leftKeyForRightKey(rightKey);
3523
- mapWithLeftKeys.set(leftKey, dataset);
3524
- }
3525
- return {
3526
- datasetMap: mapWithLeftKeys,
3527
- modelRunTime: result.modelRunTime
3528
- };
3529
- },
3530
- getGraphDataForScenario: origBundleModelR.getGraphDataForScenario.bind(origBundleModelR),
3531
- getGraphLinksForScenario: origBundleModelR.getGraphLinksForScenario.bind(origBundleModelR)
3532
- };
3533
- currentBundle = {
3534
- ...origCurrentBundle,
3535
- model: adjBundleModelR
4094
+ function createConfig(options) {
4095
+ return __async(this, null, function* () {
4096
+ var _a;
4097
+ const origCurrentBundle = yield loadSynchronized(options.current);
4098
+ let currentBundle;
4099
+ let comparisonConfig;
4100
+ if (options.comparison === void 0) {
4101
+ currentBundle = origCurrentBundle;
4102
+ } else {
4103
+ const baselineBundle = yield loadSynchronized(options.comparison.baseline);
4104
+ const renamedDatasetKeys = (_a = options.comparison.datasets) == null ? void 0 : _a.renamedDatasetKeys;
4105
+ const invertedRenamedKeys = /* @__PURE__ */ new Map();
4106
+ renamedDatasetKeys == null ? void 0 : renamedDatasetKeys.forEach((newKey, oldKey) => {
4107
+ invertedRenamedKeys.set(newKey, oldKey);
4108
+ });
4109
+ const rightKeyForLeftKey = (leftKey) => {
4110
+ return (renamedDatasetKeys == null ? void 0 : renamedDatasetKeys.get(leftKey)) || leftKey;
4111
+ };
4112
+ const leftKeyForRightKey = (rightKey) => {
4113
+ return invertedRenamedKeys.get(rightKey) || rightKey;
4114
+ };
4115
+ const origBundleModelR = origCurrentBundle.model;
4116
+ const adjBundleModelR = {
4117
+ modelSpec: origBundleModelR.modelSpec,
4118
+ getDatasetsForScenario: (scenarioSpec, datasetKeys) => __async(this, null, function* () {
4119
+ const rightKeys = datasetKeys.map(rightKeyForLeftKey);
4120
+ const result = yield origBundleModelR.getDatasetsForScenario(scenarioSpec, rightKeys);
4121
+ const mapWithRightKeys = result.datasetMap;
4122
+ const mapWithLeftKeys = /* @__PURE__ */ new Map();
4123
+ for (const [rightKey, dataset] of mapWithRightKeys.entries()) {
4124
+ const leftKey = leftKeyForRightKey(rightKey);
4125
+ mapWithLeftKeys.set(leftKey, dataset);
4126
+ }
4127
+ return {
4128
+ datasetMap: mapWithLeftKeys,
4129
+ modelRunTime: result.modelRunTime
4130
+ };
4131
+ }),
4132
+ getGraphDataForScenario: origBundleModelR.getGraphDataForScenario.bind(origBundleModelR),
4133
+ getGraphLinksForScenario: origBundleModelR.getGraphLinksForScenario.bind(origBundleModelR)
4134
+ };
4135
+ currentBundle = __spreadProps(__spreadValues({}, origCurrentBundle), {
4136
+ model: adjBundleModelR
4137
+ });
4138
+ const modelSpecL = baselineBundle.model.modelSpec;
4139
+ const modelSpecR = currentBundle.model.modelSpec;
4140
+ const comparisonDefs = resolveComparisonSpecsFromSources(modelSpecL, modelSpecR, options.comparison.specs);
4141
+ comparisonConfig = {
4142
+ bundleL: baselineBundle,
4143
+ bundleR: currentBundle,
4144
+ thresholds: options.comparison.thresholds,
4145
+ scenarios: getComparisonScenarios(comparisonDefs.scenarios),
4146
+ datasets: getComparisonDatasets(modelSpecL, modelSpecR, options.comparison.datasets),
4147
+ viewGroups: comparisonDefs.viewGroups
4148
+ };
4149
+ }
4150
+ const checkConfig = {
4151
+ bundle: currentBundle,
4152
+ tests: options.check.tests
3536
4153
  };
3537
- const modelSpecL = baselineBundle.model.modelSpec;
3538
- const modelSpecR = currentBundle.model.modelSpec;
3539
- const modelInputsL = new ModelInputs(modelSpecL);
3540
- const modelInputsR = new ModelInputs(modelSpecR);
3541
- const comparisonDefs = resolveComparisonSpecsFromSources(modelInputsL, modelInputsR, options.comparison.specs);
3542
- comparisonConfig = {
3543
- bundleL: baselineBundle,
3544
- bundleR: currentBundle,
3545
- thresholds: options.comparison.thresholds,
3546
- scenarios: getComparisonScenarios(comparisonDefs.scenarios),
3547
- datasets: getComparisonDatasets(modelSpecL, modelSpecR, options.comparison.datasets),
3548
- viewGroups: comparisonDefs.viewGroups
4154
+ return {
4155
+ check: checkConfig,
4156
+ comparison: comparisonConfig
3549
4157
  };
3550
- }
3551
- const checkConfig = {
3552
- bundle: currentBundle,
3553
- tests: options.check.tests
3554
- };
3555
- return {
3556
- check: checkConfig,
3557
- comparison: comparisonConfig
3558
- };
4158
+ });
3559
4159
  }
3560
- async function loadSynchronized(sourceBundle) {
3561
- const sourceModel = await sourceBundle.bundle.initModel();
3562
- const synchronizedModel = synchronizedBundleModel(sourceModel);
3563
- return {
3564
- name: sourceBundle.name,
3565
- version: sourceBundle.bundle.version,
3566
- model: synchronizedModel
3567
- };
4160
+ function loadSynchronized(sourceBundle) {
4161
+ return __async(this, null, function* () {
4162
+ const sourceModel = yield sourceBundle.bundle.initModel();
4163
+ const synchronizedModel = synchronizedBundleModel(sourceModel);
4164
+ return {
4165
+ name: sourceBundle.name,
4166
+ version: sourceBundle.bundle.version,
4167
+ model: synchronizedModel
4168
+ };
4169
+ });
3568
4170
  }
3569
4171
 
3570
4172
  // src/perf/perf-runner.ts
@@ -3614,22 +4216,22 @@ var PerfRunner = class {
3614
4216
  this.mode = mode;
3615
4217
  const scenarioSpec = allInputsAtPositionSpec("at-default");
3616
4218
  this.taskQueue = new TaskQueue({
3617
- process: async (request) => {
4219
+ process: (request) => __async(this, null, function* () {
3618
4220
  switch (request.kind) {
3619
4221
  case "left": {
3620
- const result = await bundleModelL.getDatasetsForScenario(scenarioSpec, []);
4222
+ const result = yield bundleModelL.getDatasetsForScenario(scenarioSpec, []);
3621
4223
  return {
3622
4224
  runTimeL: result.modelRunTime
3623
4225
  };
3624
4226
  }
3625
4227
  case "right": {
3626
- const result = await bundleModelR.getDatasetsForScenario(scenarioSpec, []);
4228
+ const result = yield bundleModelR.getDatasetsForScenario(scenarioSpec, []);
3627
4229
  return {
3628
4230
  runTimeR: result.modelRunTime
3629
4231
  };
3630
4232
  }
3631
4233
  case "both": {
3632
- const [resultL, resultR] = await Promise.all([
4234
+ const [resultL, resultR] = yield Promise.all([
3633
4235
  bundleModelL.getDatasetsForScenario(scenarioSpec, []),
3634
4236
  bundleModelR.getDatasetsForScenario(scenarioSpec, [])
3635
4237
  ]);
@@ -3641,7 +4243,7 @@ var PerfRunner = class {
3641
4243
  default:
3642
4244
  (0, import_assert_never12.assertNever)(request.kind);
3643
4245
  }
3644
- }
4246
+ })
3645
4247
  });
3646
4248
  }
3647
4249
  start() {
@@ -3689,13 +4291,31 @@ var PerfRunner = class {
3689
4291
 
3690
4292
  // src/data/data-planner.ts
3691
4293
  var DataPlanner = class {
4294
+ /**
4295
+ * @param batchSize The maximum number of impl vars that can be fetched
4296
+ * with a single request; this is usually the same as the number of
4297
+ * normal model outputs.
4298
+ */
3692
4299
  constructor(batchSize) {
3693
4300
  this.batchSize = batchSize;
4301
+ /** Tasks that need to access both "left" and "right" models in parallel. */
3694
4302
  this.taskSetsLR = /* @__PURE__ */ new Map();
4303
+ /** Tasks that only need to access the "left" model. */
3695
4304
  this.taskSetsL = /* @__PURE__ */ new Map();
4305
+ /** Tasks that only need to access the "right" model. */
3696
4306
  this.taskSetsR = /* @__PURE__ */ new Map();
3697
4307
  this.complete = false;
3698
4308
  }
4309
+ /**
4310
+ * Add a request to the plan for the given scenario(s) and data task.
4311
+ *
4312
+ * @param scenarioSpecL The input scenario used to configure the "left" model, or undefined if no data
4313
+ * is needed from the left model.
4314
+ * @param scenarioSpecR The input scenario used to configure the "right" model, or undefined if no data
4315
+ * is needed from the right model.
4316
+ * @param datasetKey The key for the dataset to be fetched from each model for the given scenario.
4317
+ * @param dataAction The action to be performed with the fetched datasets.
4318
+ */
3699
4319
  addRequest(scenarioSpecL, scenarioSpecR, datasetKey, dataAction) {
3700
4320
  if (scenarioSpecL === void 0 && scenarioSpecR === void 0) {
3701
4321
  console.warn("WARNING: Both scenario specs are undefined for DataPlanner request, skipping");
@@ -3723,6 +4343,9 @@ var DataPlanner = class {
3723
4343
  dataAction
3724
4344
  });
3725
4345
  }
4346
+ /**
4347
+ * Build a plan that minimizes the number of data fetches needed.
4348
+ */
3726
4349
  buildPlan() {
3727
4350
  if (this.complete) {
3728
4351
  throw new Error("DataPlanner.buildPlan() can only be called once");
@@ -3773,6 +4396,12 @@ var DataTaskSet = class {
3773
4396
  this.modelTasks = /* @__PURE__ */ new Map();
3774
4397
  this.modelImplTasks = /* @__PURE__ */ new Map();
3775
4398
  }
4399
+ /**
4400
+ * Add a task that will be performed when the data is fetched for the scenario(s)
4401
+ * associated with this task set.
4402
+ *
4403
+ * @param dataTask A task that performs an action using the fetched dataset(s).
4404
+ */
3776
4405
  addTask(dataTask) {
3777
4406
  let taskMap;
3778
4407
  if (dataTask.datasetKey.startsWith("ModelImpl")) {
@@ -3787,6 +4416,11 @@ var DataTaskSet = class {
3787
4416
  }
3788
4417
  tasks.push(dataTask);
3789
4418
  }
4419
+ /**
4420
+ * Add all tasks from the given set into this set.
4421
+ *
4422
+ * @param otherTaskSet The other task set that will be merged into this one.
4423
+ */
3790
4424
  merge(otherTaskSet) {
3791
4425
  for (const tasks of otherTaskSet.modelTasks.values()) {
3792
4426
  for (const task of tasks) {
@@ -3799,6 +4433,12 @@ var DataTaskSet = class {
3799
4433
  }
3800
4434
  }
3801
4435
  }
4436
+ /**
4437
+ * Create one or more data requests that can be used to fetch data for the configured scenario(s).
4438
+ *
4439
+ * @param batchSize The maximum number of impl vars that can be fetched with a single request.
4440
+ * This is usually the same as the number of normal model outputs.
4441
+ */
3802
4442
  buildRequests(batchSize) {
3803
4443
  const dataRequests = [];
3804
4444
  if (this.modelTasks.size > 0) {
@@ -4034,42 +4674,46 @@ var SuiteRunner = class {
4034
4674
  });
4035
4675
  }
4036
4676
  }
4037
- async processRequest(request) {
4038
- var _a, _b;
4039
- const datasetKeySet = /* @__PURE__ */ new Set();
4040
- for (const dataTask of request.dataTasks) {
4041
- datasetKeySet.add(dataTask.datasetKey);
4042
- }
4043
- const datasetKeys = [...datasetKeySet];
4044
- async function getDatasets(bundleModel, scenarioSpec) {
4045
- if (bundleModel && scenarioSpec) {
4046
- return bundleModel.getDatasetsForScenario(scenarioSpec, datasetKeys);
4047
- } else {
4048
- return void 0;
4677
+ processRequest(request) {
4678
+ return __async(this, null, function* () {
4679
+ var _a, _b;
4680
+ const datasetKeySet = /* @__PURE__ */ new Set();
4681
+ for (const dataTask of request.dataTasks) {
4682
+ datasetKeySet.add(dataTask.datasetKey);
4049
4683
  }
4050
- }
4051
- const bundleModelL = (_a = this.config.comparison) == null ? void 0 : _a.bundleL.model;
4052
- const bundleModelR = ((_b = this.config.comparison) == null ? void 0 : _b.bundleR.model) || this.config.check.bundle.model;
4053
- const [datasetsResultL, datasetsResultR] = await Promise.all([
4054
- getDatasets(bundleModelL, request.scenarioSpecL),
4055
- getDatasets(bundleModelR, request.scenarioSpecR)
4056
- ]);
4057
- if (datasetsResultL == null ? void 0 : datasetsResultL.modelRunTime) {
4058
- this.perfStatsL.addRun(datasetsResultL == null ? void 0 : datasetsResultL.modelRunTime);
4059
- }
4060
- if (datasetsResultR == null ? void 0 : datasetsResultR.modelRunTime) {
4061
- this.perfStatsR.addRun(datasetsResultR == null ? void 0 : datasetsResultR.modelRunTime);
4062
- }
4063
- const datasetMapL = datasetsResultL == null ? void 0 : datasetsResultL.datasetMap;
4064
- const datasetMapR = datasetsResultR == null ? void 0 : datasetsResultR.datasetMap;
4065
- for (const dataTask of request.dataTasks) {
4066
- const datasetL = datasetMapL == null ? void 0 : datasetMapL.get(dataTask.datasetKey);
4067
- const datasetR = datasetMapR == null ? void 0 : datasetMapR.get(dataTask.datasetKey);
4068
- dataTask.dataAction({
4069
- datasetL,
4070
- datasetR
4071
- });
4072
- }
4684
+ const datasetKeys = [...datasetKeySet];
4685
+ function getDatasets(bundleModel, scenarioSpec) {
4686
+ return __async(this, null, function* () {
4687
+ if (bundleModel && scenarioSpec) {
4688
+ return bundleModel.getDatasetsForScenario(scenarioSpec, datasetKeys);
4689
+ } else {
4690
+ return void 0;
4691
+ }
4692
+ });
4693
+ }
4694
+ const bundleModelL = (_a = this.config.comparison) == null ? void 0 : _a.bundleL.model;
4695
+ const bundleModelR = ((_b = this.config.comparison) == null ? void 0 : _b.bundleR.model) || this.config.check.bundle.model;
4696
+ const [datasetsResultL, datasetsResultR] = yield Promise.all([
4697
+ getDatasets(bundleModelL, request.scenarioSpecL),
4698
+ getDatasets(bundleModelR, request.scenarioSpecR)
4699
+ ]);
4700
+ if (datasetsResultL == null ? void 0 : datasetsResultL.modelRunTime) {
4701
+ this.perfStatsL.addRun(datasetsResultL == null ? void 0 : datasetsResultL.modelRunTime);
4702
+ }
4703
+ if (datasetsResultR == null ? void 0 : datasetsResultR.modelRunTime) {
4704
+ this.perfStatsR.addRun(datasetsResultR == null ? void 0 : datasetsResultR.modelRunTime);
4705
+ }
4706
+ const datasetMapL = datasetsResultL == null ? void 0 : datasetsResultL.datasetMap;
4707
+ const datasetMapR = datasetsResultR == null ? void 0 : datasetsResultR.datasetMap;
4708
+ for (const dataTask of request.dataTasks) {
4709
+ const datasetL = datasetMapL == null ? void 0 : datasetMapL.get(dataTask.datasetKey);
4710
+ const datasetR = datasetMapR == null ? void 0 : datasetMapR.get(dataTask.datasetKey);
4711
+ dataTask.dataAction({
4712
+ datasetL,
4713
+ datasetR
4714
+ });
4715
+ }
4716
+ });
4073
4717
  }
4074
4718
  };
4075
4719
  function runSuite(config, callbacks, options) {
@@ -4106,6 +4750,7 @@ function suiteSummaryFromReport(suiteReport) {
4106
4750
  datasetMessage,
4107
4751
  diffDatasets,
4108
4752
  diffGraphs,
4753
+ getScoresForTestSummaries,
4109
4754
  predicateMessage,
4110
4755
  runSuite,
4111
4756
  scenarioMessage,