@sdeverywhere/check-core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +12 -0
- package/dist/index.cjs +2988 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +907 -0
- package/dist/index.js +2938 -0
- package/dist/index.js.map +1 -0
- package/package.json +51 -0
- package/schema/check.schema.json +756 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,2988 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __defProps = Object.defineProperties;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
8
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
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));
|
|
24
|
+
var __export = (target, all) => {
|
|
25
|
+
for (var name in all)
|
|
26
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
27
|
+
};
|
|
28
|
+
var __copyProps = (to, from, except, desc) => {
|
|
29
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
30
|
+
for (let key of __getOwnPropNames(from))
|
|
31
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
32
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
33
|
+
}
|
|
34
|
+
return to;
|
|
35
|
+
};
|
|
36
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod));
|
|
37
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
38
|
+
|
|
39
|
+
// src/index.ts
|
|
40
|
+
var src_exports = {};
|
|
41
|
+
__export(src_exports, {
|
|
42
|
+
CheckDataCoordinator: () => CheckDataCoordinator,
|
|
43
|
+
CompareDataCoordinator: () => CompareDataCoordinator,
|
|
44
|
+
DatasetManager: () => DatasetManager,
|
|
45
|
+
PerfRunner: () => PerfRunner,
|
|
46
|
+
PerfStats: () => PerfStats,
|
|
47
|
+
ScenarioManager: () => ScenarioManager,
|
|
48
|
+
allInputsAtPositionScenario: () => allInputsAtPositionScenario,
|
|
49
|
+
checkReportFromSummary: () => checkReportFromSummary,
|
|
50
|
+
checkSummaryFromReport: () => checkSummaryFromReport,
|
|
51
|
+
compareDatasets: () => compareDatasets,
|
|
52
|
+
compareSummaryFromReport: () => compareSummaryFromReport,
|
|
53
|
+
createConfig: () => createConfig,
|
|
54
|
+
datasetMessage: () => datasetMessage,
|
|
55
|
+
diffDatasets: () => diffDatasets,
|
|
56
|
+
diffGraphs: () => diffGraphs,
|
|
57
|
+
inputAtPositionScenario: () => inputAtPositionScenario,
|
|
58
|
+
inputAtValueScenario: () => inputAtValueScenario,
|
|
59
|
+
matrixScenarios: () => matrixScenarios,
|
|
60
|
+
positionSetting: () => positionSetting,
|
|
61
|
+
predicateMessage: () => predicateMessage,
|
|
62
|
+
runSuite: () => runSuite,
|
|
63
|
+
scenarioMessage: () => scenarioMessage,
|
|
64
|
+
settingsScenario: () => settingsScenario,
|
|
65
|
+
suiteSummaryFromReport: () => suiteSummaryFromReport,
|
|
66
|
+
valueSetting: () => valueSetting
|
|
67
|
+
});
|
|
68
|
+
module.exports = __toCommonJS(src_exports);
|
|
69
|
+
|
|
70
|
+
// src/_shared/scenario.ts
|
|
71
|
+
var import_assert_never = require("assert-never");
|
|
72
|
+
function positionSetting(inputVarId, position) {
|
|
73
|
+
return {
|
|
74
|
+
kind: "position",
|
|
75
|
+
inputVarId,
|
|
76
|
+
position
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
function valueSetting(inputVarId, value) {
|
|
80
|
+
return {
|
|
81
|
+
kind: "value",
|
|
82
|
+
inputVarId,
|
|
83
|
+
value
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function settingsScenario(key, groupKey, settings) {
|
|
87
|
+
return {
|
|
88
|
+
kind: "settings",
|
|
89
|
+
key,
|
|
90
|
+
groupKey,
|
|
91
|
+
settings
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
function inputAtPositionScenario(inputVarId, groupKey, position) {
|
|
95
|
+
const key = keyForInputAtPosition(`input${inputVarId}`, position);
|
|
96
|
+
return settingsScenario(key, groupKey, [positionSetting(inputVarId, position)]);
|
|
97
|
+
}
|
|
98
|
+
function inputAtValueScenario(inputVarId, groupKey, value) {
|
|
99
|
+
const key = keyForInputAtValue(`input${inputVarId}`, value);
|
|
100
|
+
return settingsScenario(key, groupKey, [valueSetting(inputVarId, value)]);
|
|
101
|
+
}
|
|
102
|
+
function allInputsAtPositionScenario(position) {
|
|
103
|
+
return {
|
|
104
|
+
kind: "all-inputs",
|
|
105
|
+
key: keyForInputAtPosition("all_inputs", position),
|
|
106
|
+
groupKey: "all_inputs",
|
|
107
|
+
position
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
function matrixScenarios(inputVarIds) {
|
|
111
|
+
const scenarios = [];
|
|
112
|
+
scenarios.push(allInputsAtPositionScenario("at-default"));
|
|
113
|
+
scenarios.push(allInputsAtPositionScenario("at-minimum"));
|
|
114
|
+
scenarios.push(allInputsAtPositionScenario("at-maximum"));
|
|
115
|
+
for (const inputVarId of inputVarIds) {
|
|
116
|
+
scenarios.push(inputAtPositionScenario(inputVarId, inputVarId, "at-minimum"));
|
|
117
|
+
scenarios.push(inputAtPositionScenario(inputVarId, inputVarId, "at-maximum"));
|
|
118
|
+
}
|
|
119
|
+
return scenarios;
|
|
120
|
+
}
|
|
121
|
+
function keyForInputPosition(position) {
|
|
122
|
+
switch (position) {
|
|
123
|
+
case "at-default":
|
|
124
|
+
return "default";
|
|
125
|
+
case "at-minimum":
|
|
126
|
+
return "min";
|
|
127
|
+
case "at-maximum":
|
|
128
|
+
return "max";
|
|
129
|
+
default:
|
|
130
|
+
(0, import_assert_never.assertNever)(position);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
function keyForInputAtPosition(inputKey, position) {
|
|
134
|
+
return `${inputKey}_at_${keyForInputPosition(position)}`;
|
|
135
|
+
}
|
|
136
|
+
function keyForInputAtValue(inputKey, value) {
|
|
137
|
+
return `${inputKey}_at_${value}`;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// src/_shared/task-queue.ts
|
|
141
|
+
var TaskQueue = class {
|
|
142
|
+
constructor(processor) {
|
|
143
|
+
this.processor = processor;
|
|
144
|
+
this.taskKeyQueue = [];
|
|
145
|
+
this.taskMap = /* @__PURE__ */ new Map();
|
|
146
|
+
this.processing = false;
|
|
147
|
+
this.stopped = false;
|
|
148
|
+
}
|
|
149
|
+
addTask(key, input, onComplete) {
|
|
150
|
+
if (this.stopped) {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
if (this.taskMap.has(key)) {
|
|
154
|
+
throw new Error(`Task already added for key ${key}`);
|
|
155
|
+
}
|
|
156
|
+
this.taskKeyQueue.push(key);
|
|
157
|
+
this.taskMap.set(key, {
|
|
158
|
+
input,
|
|
159
|
+
onComplete
|
|
160
|
+
});
|
|
161
|
+
this.processTasksIfNeeded();
|
|
162
|
+
}
|
|
163
|
+
cancelTask(taskKey) {
|
|
164
|
+
const index = this.taskKeyQueue.indexOf(taskKey);
|
|
165
|
+
if (index >= 0) {
|
|
166
|
+
this.taskKeyQueue.splice(index, 1);
|
|
167
|
+
}
|
|
168
|
+
this.taskMap.delete(taskKey);
|
|
169
|
+
}
|
|
170
|
+
shutdown() {
|
|
171
|
+
this.stopped = true;
|
|
172
|
+
this.processing = false;
|
|
173
|
+
this.taskKeyQueue.length = 0;
|
|
174
|
+
this.taskMap.clear();
|
|
175
|
+
}
|
|
176
|
+
processTasksIfNeeded() {
|
|
177
|
+
if (!this.stopped && !this.processing) {
|
|
178
|
+
this.processing = true;
|
|
179
|
+
setTimeout(() => {
|
|
180
|
+
this.processNextTask();
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
async processNextTask() {
|
|
185
|
+
var _a, _b;
|
|
186
|
+
const taskKey = this.taskKeyQueue.shift();
|
|
187
|
+
if (!taskKey) {
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
const task = this.taskMap.get(taskKey);
|
|
191
|
+
if (task) {
|
|
192
|
+
this.taskMap.delete(taskKey);
|
|
193
|
+
} else {
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
let output;
|
|
197
|
+
try {
|
|
198
|
+
output = await this.processor.process(task.input);
|
|
199
|
+
} catch (e) {
|
|
200
|
+
if (!this.stopped) {
|
|
201
|
+
this.shutdown();
|
|
202
|
+
(_a = this.onIdle) == null ? void 0 : _a.call(this, e);
|
|
203
|
+
}
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
task.onComplete(output);
|
|
207
|
+
if (this.taskKeyQueue.length > 0) {
|
|
208
|
+
setTimeout(() => {
|
|
209
|
+
this.processNextTask();
|
|
210
|
+
});
|
|
211
|
+
} else {
|
|
212
|
+
this.processing = false;
|
|
213
|
+
if (!this.stopped) {
|
|
214
|
+
(_b = this.onIdle) == null ? void 0 : _b.call(this);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
// src/check/check-data-coordinator.ts
|
|
221
|
+
var CheckDataCoordinator = class {
|
|
222
|
+
constructor(bundleModel) {
|
|
223
|
+
this.bundleModel = bundleModel;
|
|
224
|
+
this.taskQueue = new TaskQueue({
|
|
225
|
+
process: async (request) => {
|
|
226
|
+
const result = await this.bundleModel.getDatasetsForScenario(request.scenario, [request.datasetKey]);
|
|
227
|
+
const dataset = result.datasetMap.get(request.datasetKey);
|
|
228
|
+
return {
|
|
229
|
+
dataset
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
requestDataset(requestKey, scenario, datasetKey, onResponse) {
|
|
235
|
+
const request = {
|
|
236
|
+
scenario,
|
|
237
|
+
datasetKey
|
|
238
|
+
};
|
|
239
|
+
this.taskQueue.addTask(requestKey, request, (response) => {
|
|
240
|
+
onResponse(response.dataset);
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
cancelRequest(key) {
|
|
244
|
+
this.taskQueue.cancelTask(key);
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
// src/check/check-report.ts
|
|
249
|
+
var import_assert_never3 = __toESM(require("assert-never"), 1);
|
|
250
|
+
|
|
251
|
+
// src/check/check-predicate.ts
|
|
252
|
+
var import_assert_never2 = __toESM(require("assert-never"), 1);
|
|
253
|
+
function symbolForPredicateOp(op) {
|
|
254
|
+
switch (op) {
|
|
255
|
+
case "gt":
|
|
256
|
+
return ">";
|
|
257
|
+
case "gte":
|
|
258
|
+
return ">=";
|
|
259
|
+
case "lt":
|
|
260
|
+
return "<";
|
|
261
|
+
case "lte":
|
|
262
|
+
return "<=";
|
|
263
|
+
case "eq":
|
|
264
|
+
return "==";
|
|
265
|
+
case "approx":
|
|
266
|
+
return "\u2248";
|
|
267
|
+
default:
|
|
268
|
+
(0, import_assert_never2.default)(op);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// src/check/check-report.ts
|
|
273
|
+
function buildCheckReport(checkPlan, checkResults) {
|
|
274
|
+
const groupReports = [];
|
|
275
|
+
for (const groupPlan of checkPlan.groups) {
|
|
276
|
+
const testReports = [];
|
|
277
|
+
for (const testPlan of groupPlan.tests) {
|
|
278
|
+
let testStatus = "passed";
|
|
279
|
+
const scenarioReports = [];
|
|
280
|
+
for (const scenarioPlan of testPlan.scenarios) {
|
|
281
|
+
let scenarioStatus = "passed";
|
|
282
|
+
if (scenarioPlan.checkScenario.scenario === void 0) {
|
|
283
|
+
testStatus = "error";
|
|
284
|
+
scenarioStatus = "error";
|
|
285
|
+
}
|
|
286
|
+
const datasetReports = [];
|
|
287
|
+
for (const datasetPlan of scenarioPlan.datasets) {
|
|
288
|
+
let datasetStatus = "passed";
|
|
289
|
+
if (datasetPlan.checkDataset.datasetKey === void 0) {
|
|
290
|
+
testStatus = "error";
|
|
291
|
+
scenarioStatus = "error";
|
|
292
|
+
datasetStatus = "error";
|
|
293
|
+
}
|
|
294
|
+
const predicateReports = [];
|
|
295
|
+
for (const predicatePlan of datasetPlan.predicates) {
|
|
296
|
+
const checkKey = predicatePlan.checkKey;
|
|
297
|
+
const checkResult = checkResults.get(checkKey);
|
|
298
|
+
if (checkResult) {
|
|
299
|
+
if (checkResult.status !== "passed") {
|
|
300
|
+
if (checkResult.status === "error") {
|
|
301
|
+
testStatus = "error";
|
|
302
|
+
scenarioStatus = "error";
|
|
303
|
+
datasetStatus = "error";
|
|
304
|
+
} else if (checkResult.status === "failed" && testStatus !== "error") {
|
|
305
|
+
testStatus = "failed";
|
|
306
|
+
scenarioStatus = "failed";
|
|
307
|
+
datasetStatus = "failed";
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
predicateReports.push(predicateReport(predicatePlan, checkKey, checkResult));
|
|
311
|
+
} else {
|
|
312
|
+
predicateReports.push(predicateReport(predicatePlan, checkKey, { status: "passed" }));
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
datasetReports.push({
|
|
316
|
+
checkDataset: datasetPlan.checkDataset,
|
|
317
|
+
status: datasetStatus,
|
|
318
|
+
predicates: predicateReports
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
scenarioReports.push({
|
|
322
|
+
checkScenario: scenarioPlan.checkScenario,
|
|
323
|
+
status: scenarioStatus,
|
|
324
|
+
datasets: datasetReports
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
testReports.push({
|
|
328
|
+
name: testPlan.name,
|
|
329
|
+
status: testStatus,
|
|
330
|
+
scenarios: scenarioReports
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
groupReports.push({
|
|
334
|
+
name: groupPlan.name,
|
|
335
|
+
tests: testReports
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
return {
|
|
339
|
+
groups: groupReports
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
function predicateReport(predicatePlan, checkKey, result) {
|
|
343
|
+
if (result.status === "error") {
|
|
344
|
+
return {
|
|
345
|
+
checkKey,
|
|
346
|
+
result,
|
|
347
|
+
opRefs: /* @__PURE__ */ new Map(),
|
|
348
|
+
opValues: []
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
const predicateSpec = predicatePlan.action.predicateSpec;
|
|
352
|
+
const opRefs = /* @__PURE__ */ new Map();
|
|
353
|
+
const opValues = [];
|
|
354
|
+
function addOp(op) {
|
|
355
|
+
var _a, _b;
|
|
356
|
+
const sym = symbolForPredicateOp(op);
|
|
357
|
+
const predOp = predicateSpec[op];
|
|
358
|
+
if (predOp !== void 0) {
|
|
359
|
+
let opRef;
|
|
360
|
+
let opValue;
|
|
361
|
+
if (typeof predOp === "number") {
|
|
362
|
+
const opConstantRef = {
|
|
363
|
+
kind: "constant",
|
|
364
|
+
value: predOp
|
|
365
|
+
};
|
|
366
|
+
opRef = opConstantRef;
|
|
367
|
+
opValue = `${sym} ${predOp}`;
|
|
368
|
+
} else {
|
|
369
|
+
const dataRef = (_a = predicatePlan.dataRefs) == null ? void 0 : _a.get(op);
|
|
370
|
+
if (!dataRef) {
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
const opDataRef = {
|
|
374
|
+
kind: "data",
|
|
375
|
+
dataRef
|
|
376
|
+
};
|
|
377
|
+
opRef = opDataRef;
|
|
378
|
+
opValue = `${sym} '${dataRef.dataset.name}'`;
|
|
379
|
+
const refScenario = (_b = dataRef.scenario) == null ? void 0 : _b.scenario;
|
|
380
|
+
if (!refScenario) {
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
if (predOp.scenario === "inherit") {
|
|
384
|
+
opValue += ` (w/ same scenario)`;
|
|
385
|
+
} else {
|
|
386
|
+
if (refScenario.kind === "all-inputs" && refScenario.position === "at-default") {
|
|
387
|
+
opValue += ` (w/ default scenario)`;
|
|
388
|
+
} else {
|
|
389
|
+
opValue += ` (w/ configured scenario)`;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
if (op === "approx") {
|
|
394
|
+
const tolerance = predicateSpec.tolerance || 0.1;
|
|
395
|
+
opValue += ` \xB1${tolerance}`;
|
|
396
|
+
}
|
|
397
|
+
opRefs.set(op, opRef);
|
|
398
|
+
opValues.push(opValue);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
addOp("gt");
|
|
402
|
+
addOp("gte");
|
|
403
|
+
addOp("lt");
|
|
404
|
+
addOp("lte");
|
|
405
|
+
addOp("eq");
|
|
406
|
+
addOp("approx");
|
|
407
|
+
if (opValues.length === 0) {
|
|
408
|
+
opValues.push("INVALID PREDICATE");
|
|
409
|
+
}
|
|
410
|
+
return {
|
|
411
|
+
checkKey,
|
|
412
|
+
result,
|
|
413
|
+
opRefs,
|
|
414
|
+
opValues,
|
|
415
|
+
time: predicateSpec.time,
|
|
416
|
+
tolerance: predicateSpec.tolerance
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
function scenarioMessage(scenario, bold) {
|
|
420
|
+
const checkScenario = scenario.checkScenario;
|
|
421
|
+
if (checkScenario.scenario === void 0) {
|
|
422
|
+
if (checkScenario.error) {
|
|
423
|
+
switch (checkScenario.error.kind) {
|
|
424
|
+
case "unknown-input-group":
|
|
425
|
+
return `error: input group ${bold(checkScenario.error.name)} is unknown`;
|
|
426
|
+
case "empty-input-group":
|
|
427
|
+
return `error: input group ${bold(checkScenario.error.name)} is empty`;
|
|
428
|
+
default:
|
|
429
|
+
(0, import_assert_never3.default)(checkScenario.error.kind);
|
|
430
|
+
}
|
|
431
|
+
} else {
|
|
432
|
+
const badInputNames = checkScenario.inputDescs.filter((d) => d.inputVar === void 0).map((d) => bold(d.name));
|
|
433
|
+
const label = badInputNames.length === 1 ? "input" : "inputs";
|
|
434
|
+
return `error: unknown ${label} ${badInputNames.join(", ")}`;
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
function positionName(position) {
|
|
438
|
+
switch (position) {
|
|
439
|
+
case "at-default":
|
|
440
|
+
return "default";
|
|
441
|
+
case "at-minimum":
|
|
442
|
+
return "minimum";
|
|
443
|
+
case "at-maximum":
|
|
444
|
+
return "maximum";
|
|
445
|
+
default:
|
|
446
|
+
(0, import_assert_never3.default)(position);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
function inputMessage(inputDesc) {
|
|
450
|
+
let msg = bold(inputDesc.name);
|
|
451
|
+
if (inputDesc.position) {
|
|
452
|
+
msg += ` is at ${bold(positionName(inputDesc.position))}`;
|
|
453
|
+
if (inputDesc.value !== void 0) {
|
|
454
|
+
msg += ` (${inputDesc.value})`;
|
|
455
|
+
}
|
|
456
|
+
} else if (inputDesc.value !== void 0) {
|
|
457
|
+
msg += ` is ${bold(inputDesc.value.toString())}`;
|
|
458
|
+
}
|
|
459
|
+
return msg;
|
|
460
|
+
}
|
|
461
|
+
if (checkScenario.scenario.kind === "all-inputs") {
|
|
462
|
+
const position = checkScenario.scenario.position;
|
|
463
|
+
return `when ${bold("all inputs")} are at ${bold(positionName(position))}...`;
|
|
464
|
+
} else if (checkScenario.inputGroupName) {
|
|
465
|
+
let position = "at-default";
|
|
466
|
+
if (checkScenario.scenario.settings[0].kind === "position") {
|
|
467
|
+
position = checkScenario.scenario.settings[0].position;
|
|
468
|
+
}
|
|
469
|
+
const groupName = checkScenario.inputGroupName;
|
|
470
|
+
return `when all inputs in ${bold(groupName)} are at ${bold(positionName(position))}...`;
|
|
471
|
+
} else {
|
|
472
|
+
const inputMessages = checkScenario.inputDescs.map(inputMessage).join(" and ");
|
|
473
|
+
return `when ${inputMessages}...`;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
function datasetMessage(dataset, bold) {
|
|
477
|
+
const checkDataset = dataset.checkDataset;
|
|
478
|
+
if (checkDataset.datasetKey === void 0) {
|
|
479
|
+
return `error: ${bold(checkDataset.name)} did not match any datasets`;
|
|
480
|
+
} else {
|
|
481
|
+
return `then ${bold(checkDataset.name)}...`;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
function predicateMessage(predicate, bold) {
|
|
485
|
+
const result = predicate.result;
|
|
486
|
+
if (result.status === "error") {
|
|
487
|
+
if (result.message) {
|
|
488
|
+
return `error: ${predicate.result.message}`;
|
|
489
|
+
} else if (result.errorInfo) {
|
|
490
|
+
switch (result.errorInfo.kind) {
|
|
491
|
+
case "unknown-dataset":
|
|
492
|
+
return `error: referenced dataset ${bold(result.errorInfo.name)} is unknown`;
|
|
493
|
+
case "unknown-input":
|
|
494
|
+
return `error: referenced input ${bold(result.errorInfo.name)} is unknown`;
|
|
495
|
+
case "unknown-input-group":
|
|
496
|
+
return `error: referenced input group ${bold(result.errorInfo.name)} is unknown`;
|
|
497
|
+
case "empty-input-group":
|
|
498
|
+
return `error: referenced input group ${bold(result.errorInfo.name)} is empty`;
|
|
499
|
+
default:
|
|
500
|
+
(0, import_assert_never3.default)(result.errorInfo.kind);
|
|
501
|
+
}
|
|
502
|
+
} else {
|
|
503
|
+
return `unknown error`;
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
const predicateParts = predicate.opValues.map(bold).join(" and ");
|
|
507
|
+
let msg = `should be ${predicateParts}`;
|
|
508
|
+
if (predicate.time !== void 0) {
|
|
509
|
+
if (typeof predicate.time === "number") {
|
|
510
|
+
msg += ` in ${bold(predicate.time.toString())}`;
|
|
511
|
+
} else {
|
|
512
|
+
let minTime;
|
|
513
|
+
let maxTime;
|
|
514
|
+
let minIncl;
|
|
515
|
+
let maxIncl;
|
|
516
|
+
if (Array.isArray(predicate.time)) {
|
|
517
|
+
const timeSpec = predicate.time;
|
|
518
|
+
minTime = timeSpec[0];
|
|
519
|
+
maxTime = timeSpec[1];
|
|
520
|
+
minIncl = true;
|
|
521
|
+
maxIncl = true;
|
|
522
|
+
} else {
|
|
523
|
+
const timeSpec = predicate.time;
|
|
524
|
+
if (timeSpec.after_excl !== void 0) {
|
|
525
|
+
minTime = timeSpec.after_excl;
|
|
526
|
+
minIncl = false;
|
|
527
|
+
} else if (timeSpec.after_incl !== void 0) {
|
|
528
|
+
minTime = timeSpec.after_incl;
|
|
529
|
+
minIncl = true;
|
|
530
|
+
}
|
|
531
|
+
if (timeSpec.before_excl !== void 0) {
|
|
532
|
+
maxTime = timeSpec.before_excl;
|
|
533
|
+
maxIncl = false;
|
|
534
|
+
} else if (timeSpec.before_incl !== void 0) {
|
|
535
|
+
maxTime = timeSpec.before_incl;
|
|
536
|
+
maxIncl = true;
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
if (minTime !== void 0 && maxTime !== void 0) {
|
|
540
|
+
const prefix = minIncl ? "[" : "(";
|
|
541
|
+
const suffix = maxIncl ? "]" : ")";
|
|
542
|
+
const range = `${prefix}${minTime}, ${maxTime}${suffix}`;
|
|
543
|
+
msg += ` in ${bold(range)}`;
|
|
544
|
+
} else if (minTime !== void 0) {
|
|
545
|
+
const prefix = minIncl ? "in/after" : "after";
|
|
546
|
+
msg += ` ${prefix} ${bold(minTime.toString())}`;
|
|
547
|
+
} else if (maxTime !== void 0) {
|
|
548
|
+
const prefix = maxIncl ? "in/before" : "before";
|
|
549
|
+
msg += ` ${prefix} ${bold(maxTime.toString())}`;
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
if (predicate.result.status === "failed") {
|
|
554
|
+
if (predicate.result.failValue !== void 0) {
|
|
555
|
+
msg += ` but got ${bold(predicate.result.failValue.toString())}`;
|
|
556
|
+
if (predicate.result.failRefValue !== void 0) {
|
|
557
|
+
const failSym = symbolForPredicateOp(predicate.result.failOp);
|
|
558
|
+
const refValue = `${failSym} ${predicate.result.failRefValue.toString()}`;
|
|
559
|
+
msg += ` (expected ${bold(refValue)})`;
|
|
560
|
+
}
|
|
561
|
+
} else if (predicate.result.message) {
|
|
562
|
+
msg += ` but got ${bold(predicate.result.message)}`;
|
|
563
|
+
}
|
|
564
|
+
if (predicate.result.failTime !== void 0) {
|
|
565
|
+
msg += ` in ${bold(predicate.result.failTime.toString())}`;
|
|
566
|
+
}
|
|
567
|
+
} else if (predicate.result.status === "error" && predicate.result.message) {
|
|
568
|
+
msg += ` but got error: ${bold(predicate.result.message)}`;
|
|
569
|
+
}
|
|
570
|
+
return msg;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
// src/check/check-summary.ts
|
|
574
|
+
var import_assert_never6 = require("assert-never");
|
|
575
|
+
|
|
576
|
+
// src/check/check-parser.ts
|
|
577
|
+
var import_ajv = __toESM(require("ajv"), 1);
|
|
578
|
+
var import_neverthrow = require("neverthrow");
|
|
579
|
+
var import_yaml = __toESM(require("yaml"), 1);
|
|
580
|
+
|
|
581
|
+
// src/check/check.schema.js
|
|
582
|
+
var check_schema_default = {
|
|
583
|
+
$schema: "http://json-schema.org/draft-07/schema#",
|
|
584
|
+
title: "Model Check Test",
|
|
585
|
+
type: "array",
|
|
586
|
+
description: "A group of tests.",
|
|
587
|
+
items: {
|
|
588
|
+
$ref: "#/$defs/group"
|
|
589
|
+
},
|
|
590
|
+
$defs: {
|
|
591
|
+
group: {
|
|
592
|
+
type: "object",
|
|
593
|
+
additionalProperties: false,
|
|
594
|
+
properties: {
|
|
595
|
+
describe: {
|
|
596
|
+
type: "string"
|
|
597
|
+
},
|
|
598
|
+
tests: {
|
|
599
|
+
type: "array",
|
|
600
|
+
items: {
|
|
601
|
+
$ref: "#/$defs/test"
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
},
|
|
605
|
+
required: ["describe", "tests"]
|
|
606
|
+
},
|
|
607
|
+
test: {
|
|
608
|
+
type: "object",
|
|
609
|
+
additionalProperties: false,
|
|
610
|
+
properties: {
|
|
611
|
+
it: {
|
|
612
|
+
type: "string"
|
|
613
|
+
},
|
|
614
|
+
scenarios: {
|
|
615
|
+
type: "array",
|
|
616
|
+
items: {
|
|
617
|
+
$ref: "#/$defs/scenario"
|
|
618
|
+
},
|
|
619
|
+
minItems: 1
|
|
620
|
+
},
|
|
621
|
+
datasets: {
|
|
622
|
+
type: "array",
|
|
623
|
+
items: {
|
|
624
|
+
$ref: "#/$defs/dataset"
|
|
625
|
+
},
|
|
626
|
+
minItems: 1
|
|
627
|
+
},
|
|
628
|
+
predicates: {
|
|
629
|
+
type: "array",
|
|
630
|
+
items: {
|
|
631
|
+
$ref: "#/$defs/predicate"
|
|
632
|
+
},
|
|
633
|
+
minItems: 1
|
|
634
|
+
}
|
|
635
|
+
},
|
|
636
|
+
required: ["it", "datasets", "predicates"]
|
|
637
|
+
},
|
|
638
|
+
scenario: {
|
|
639
|
+
oneOf: [
|
|
640
|
+
{ $ref: "#/$defs/scenario_with_input_at_position" },
|
|
641
|
+
{ $ref: "#/$defs/scenario_with_input_at_value" },
|
|
642
|
+
{ $ref: "#/$defs/scenario_with_multiple_input_settings" },
|
|
643
|
+
{ $ref: "#/$defs/scenario_with_inputs_in_preset_at_position" },
|
|
644
|
+
{ $ref: "#/$defs/scenario_with_inputs_in_group_at_position" },
|
|
645
|
+
{ $ref: "#/$defs/scenario_preset" },
|
|
646
|
+
{ $ref: "#/$defs/scenario_expand_for_each_input_in_group" }
|
|
647
|
+
]
|
|
648
|
+
},
|
|
649
|
+
scenario_position: {
|
|
650
|
+
type: "string",
|
|
651
|
+
enum: ["min", "max", "default"]
|
|
652
|
+
},
|
|
653
|
+
scenario_with_input_at_position: {
|
|
654
|
+
type: "object",
|
|
655
|
+
additionalProperties: false,
|
|
656
|
+
properties: {
|
|
657
|
+
with: {
|
|
658
|
+
type: "string"
|
|
659
|
+
},
|
|
660
|
+
at: {
|
|
661
|
+
$ref: "#/$defs/scenario_position"
|
|
662
|
+
}
|
|
663
|
+
},
|
|
664
|
+
required: ["with", "at"]
|
|
665
|
+
},
|
|
666
|
+
scenario_with_input_at_value: {
|
|
667
|
+
type: "object",
|
|
668
|
+
additionalProperties: false,
|
|
669
|
+
properties: {
|
|
670
|
+
with: {
|
|
671
|
+
type: "string"
|
|
672
|
+
},
|
|
673
|
+
at: {
|
|
674
|
+
type: "number"
|
|
675
|
+
}
|
|
676
|
+
},
|
|
677
|
+
required: ["with", "at"]
|
|
678
|
+
},
|
|
679
|
+
scenario_input_at_position: {
|
|
680
|
+
type: "object",
|
|
681
|
+
additionalProperties: false,
|
|
682
|
+
properties: {
|
|
683
|
+
input: {
|
|
684
|
+
type: "string"
|
|
685
|
+
},
|
|
686
|
+
at: {
|
|
687
|
+
$ref: "#/$defs/scenario_position"
|
|
688
|
+
}
|
|
689
|
+
},
|
|
690
|
+
required: ["input", "at"]
|
|
691
|
+
},
|
|
692
|
+
scenario_input_at_value: {
|
|
693
|
+
type: "object",
|
|
694
|
+
additionalProperties: false,
|
|
695
|
+
properties: {
|
|
696
|
+
input: {
|
|
697
|
+
type: "string"
|
|
698
|
+
},
|
|
699
|
+
at: {
|
|
700
|
+
type: "number"
|
|
701
|
+
}
|
|
702
|
+
},
|
|
703
|
+
required: ["input", "at"]
|
|
704
|
+
},
|
|
705
|
+
scenario_input_setting: {
|
|
706
|
+
oneOf: [{ $ref: "#/$defs/scenario_input_at_position" }, { $ref: "#/$defs/scenario_input_at_value" }]
|
|
707
|
+
},
|
|
708
|
+
scenario_input_setting_array: {
|
|
709
|
+
type: "array",
|
|
710
|
+
items: {
|
|
711
|
+
$ref: "#/$defs/scenario_input_setting"
|
|
712
|
+
},
|
|
713
|
+
minItems: 1
|
|
714
|
+
},
|
|
715
|
+
scenario_with_multiple_input_settings: {
|
|
716
|
+
type: "object",
|
|
717
|
+
additionalProperties: false,
|
|
718
|
+
properties: {
|
|
719
|
+
with: {
|
|
720
|
+
$ref: "#/$defs/scenario_input_setting_array"
|
|
721
|
+
}
|
|
722
|
+
},
|
|
723
|
+
required: ["with"]
|
|
724
|
+
},
|
|
725
|
+
scenario_with_inputs_in_preset_at_position: {
|
|
726
|
+
type: "object",
|
|
727
|
+
additionalProperties: false,
|
|
728
|
+
properties: {
|
|
729
|
+
with_inputs: {
|
|
730
|
+
type: "string",
|
|
731
|
+
enum: ["all"]
|
|
732
|
+
},
|
|
733
|
+
at: {
|
|
734
|
+
$ref: "#/$defs/scenario_position"
|
|
735
|
+
}
|
|
736
|
+
},
|
|
737
|
+
required: ["with_inputs", "at"]
|
|
738
|
+
},
|
|
739
|
+
scenario_with_inputs_in_group_at_position: {
|
|
740
|
+
type: "object",
|
|
741
|
+
additionalProperties: false,
|
|
742
|
+
properties: {
|
|
743
|
+
with_inputs_in: {
|
|
744
|
+
type: "string"
|
|
745
|
+
},
|
|
746
|
+
at: {
|
|
747
|
+
$ref: "#/$defs/scenario_position"
|
|
748
|
+
}
|
|
749
|
+
},
|
|
750
|
+
required: ["with_inputs_in", "at"]
|
|
751
|
+
},
|
|
752
|
+
scenario_preset: {
|
|
753
|
+
type: "object",
|
|
754
|
+
additionalProperties: false,
|
|
755
|
+
properties: {
|
|
756
|
+
preset: {
|
|
757
|
+
type: "string",
|
|
758
|
+
enum: ["matrix"]
|
|
759
|
+
}
|
|
760
|
+
},
|
|
761
|
+
required: ["preset"]
|
|
762
|
+
},
|
|
763
|
+
scenario_expand_for_each_input_in_group: {
|
|
764
|
+
type: "object",
|
|
765
|
+
additionalProperties: false,
|
|
766
|
+
properties: {
|
|
767
|
+
scenarios_for_each_input_in: {
|
|
768
|
+
type: "string"
|
|
769
|
+
},
|
|
770
|
+
at: {
|
|
771
|
+
$ref: "#/$defs/scenario_position"
|
|
772
|
+
}
|
|
773
|
+
},
|
|
774
|
+
required: ["scenarios_for_each_input_in", "at"]
|
|
775
|
+
},
|
|
776
|
+
dataset: {
|
|
777
|
+
oneOf: [{ $ref: "#/$defs/dataset_name" }, { $ref: "#/$defs/dataset_group" }, { $ref: "#/$defs/dataset_matching" }]
|
|
778
|
+
},
|
|
779
|
+
dataset_name: {
|
|
780
|
+
type: "object",
|
|
781
|
+
additionalProperties: false,
|
|
782
|
+
properties: {
|
|
783
|
+
name: {
|
|
784
|
+
type: "string"
|
|
785
|
+
},
|
|
786
|
+
source: {
|
|
787
|
+
type: "string"
|
|
788
|
+
}
|
|
789
|
+
},
|
|
790
|
+
required: ["name"]
|
|
791
|
+
},
|
|
792
|
+
dataset_group: {
|
|
793
|
+
type: "object",
|
|
794
|
+
additionalProperties: false,
|
|
795
|
+
properties: {
|
|
796
|
+
group: {
|
|
797
|
+
type: "string"
|
|
798
|
+
}
|
|
799
|
+
},
|
|
800
|
+
required: ["group"]
|
|
801
|
+
},
|
|
802
|
+
dataset_matching: {
|
|
803
|
+
type: "object",
|
|
804
|
+
additionalProperties: false,
|
|
805
|
+
properties: {
|
|
806
|
+
matching: {
|
|
807
|
+
type: "object",
|
|
808
|
+
additionalProperties: false,
|
|
809
|
+
properties: {
|
|
810
|
+
type: {
|
|
811
|
+
type: "string"
|
|
812
|
+
}
|
|
813
|
+
},
|
|
814
|
+
required: ["type"]
|
|
815
|
+
}
|
|
816
|
+
},
|
|
817
|
+
required: ["matching"]
|
|
818
|
+
},
|
|
819
|
+
predicate: {
|
|
820
|
+
type: "object",
|
|
821
|
+
oneOf: [
|
|
822
|
+
{ $ref: "#/$defs/predicate_gt" },
|
|
823
|
+
{ $ref: "#/$defs/predicate_gte" },
|
|
824
|
+
{ $ref: "#/$defs/predicate_lt" },
|
|
825
|
+
{ $ref: "#/$defs/predicate_lte" },
|
|
826
|
+
{ $ref: "#/$defs/predicate_gt_lt" },
|
|
827
|
+
{ $ref: "#/$defs/predicate_gt_lte" },
|
|
828
|
+
{ $ref: "#/$defs/predicate_gte_lt" },
|
|
829
|
+
{ $ref: "#/$defs/predicate_gte_lte" },
|
|
830
|
+
{ $ref: "#/$defs/predicate_eq" },
|
|
831
|
+
{ $ref: "#/$defs/predicate_approx" }
|
|
832
|
+
]
|
|
833
|
+
},
|
|
834
|
+
predicate_gt: {
|
|
835
|
+
type: "object",
|
|
836
|
+
additionalProperties: false,
|
|
837
|
+
properties: {
|
|
838
|
+
gt: { $ref: "#/$defs/predicate_ref" },
|
|
839
|
+
time: { $ref: "#/$defs/predicate_time" }
|
|
840
|
+
},
|
|
841
|
+
required: ["gt"]
|
|
842
|
+
},
|
|
843
|
+
predicate_gte: {
|
|
844
|
+
type: "object",
|
|
845
|
+
additionalProperties: false,
|
|
846
|
+
properties: {
|
|
847
|
+
gte: { $ref: "#/$defs/predicate_ref" },
|
|
848
|
+
time: { $ref: "#/$defs/predicate_time" }
|
|
849
|
+
},
|
|
850
|
+
required: ["gte"]
|
|
851
|
+
},
|
|
852
|
+
predicate_lt: {
|
|
853
|
+
type: "object",
|
|
854
|
+
additionalProperties: false,
|
|
855
|
+
properties: {
|
|
856
|
+
lt: { $ref: "#/$defs/predicate_ref" },
|
|
857
|
+
time: { $ref: "#/$defs/predicate_time" }
|
|
858
|
+
},
|
|
859
|
+
required: ["lt"]
|
|
860
|
+
},
|
|
861
|
+
predicate_lte: {
|
|
862
|
+
type: "object",
|
|
863
|
+
additionalProperties: false,
|
|
864
|
+
properties: {
|
|
865
|
+
lte: { $ref: "#/$defs/predicate_ref" },
|
|
866
|
+
time: { $ref: "#/$defs/predicate_time" }
|
|
867
|
+
},
|
|
868
|
+
required: ["lte"]
|
|
869
|
+
},
|
|
870
|
+
predicate_gt_lt: {
|
|
871
|
+
type: "object",
|
|
872
|
+
additionalProperties: false,
|
|
873
|
+
properties: {
|
|
874
|
+
gt: { $ref: "#/$defs/predicate_ref" },
|
|
875
|
+
lt: { $ref: "#/$defs/predicate_ref" },
|
|
876
|
+
time: { $ref: "#/$defs/predicate_time" }
|
|
877
|
+
},
|
|
878
|
+
required: ["gt", "lt"]
|
|
879
|
+
},
|
|
880
|
+
predicate_gt_lte: {
|
|
881
|
+
type: "object",
|
|
882
|
+
additionalProperties: false,
|
|
883
|
+
properties: {
|
|
884
|
+
gt: { $ref: "#/$defs/predicate_ref" },
|
|
885
|
+
lte: { $ref: "#/$defs/predicate_ref" },
|
|
886
|
+
time: { $ref: "#/$defs/predicate_time" }
|
|
887
|
+
},
|
|
888
|
+
required: ["gt", "lte"]
|
|
889
|
+
},
|
|
890
|
+
predicate_gte_lt: {
|
|
891
|
+
type: "object",
|
|
892
|
+
additionalProperties: false,
|
|
893
|
+
properties: {
|
|
894
|
+
gte: { $ref: "#/$defs/predicate_ref" },
|
|
895
|
+
lt: { $ref: "#/$defs/predicate_ref" },
|
|
896
|
+
time: { $ref: "#/$defs/predicate_time" }
|
|
897
|
+
},
|
|
898
|
+
required: ["gte", "lt"]
|
|
899
|
+
},
|
|
900
|
+
predicate_gte_lte: {
|
|
901
|
+
type: "object",
|
|
902
|
+
additionalProperties: false,
|
|
903
|
+
properties: {
|
|
904
|
+
gte: { $ref: "#/$defs/predicate_ref" },
|
|
905
|
+
lte: { $ref: "#/$defs/predicate_ref" },
|
|
906
|
+
time: { $ref: "#/$defs/predicate_time" }
|
|
907
|
+
},
|
|
908
|
+
required: ["gte", "lte"]
|
|
909
|
+
},
|
|
910
|
+
predicate_eq: {
|
|
911
|
+
type: "object",
|
|
912
|
+
additionalProperties: false,
|
|
913
|
+
properties: {
|
|
914
|
+
eq: { $ref: "#/$defs/predicate_ref" },
|
|
915
|
+
time: { $ref: "#/$defs/predicate_time" }
|
|
916
|
+
},
|
|
917
|
+
required: ["eq"]
|
|
918
|
+
},
|
|
919
|
+
predicate_approx: {
|
|
920
|
+
type: "object",
|
|
921
|
+
additionalProperties: false,
|
|
922
|
+
properties: {
|
|
923
|
+
approx: { $ref: "#/$defs/predicate_ref" },
|
|
924
|
+
tolerance: { type: "number" },
|
|
925
|
+
time: { $ref: "#/$defs/predicate_time" }
|
|
926
|
+
},
|
|
927
|
+
required: ["approx"]
|
|
928
|
+
},
|
|
929
|
+
predicate_ref: {
|
|
930
|
+
oneOf: [{ $ref: "#/$defs/predicate_ref_constant" }, { $ref: "#/$defs/predicate_ref_data" }]
|
|
931
|
+
},
|
|
932
|
+
predicate_ref_constant: {
|
|
933
|
+
type: "number"
|
|
934
|
+
},
|
|
935
|
+
predicate_ref_data: {
|
|
936
|
+
type: "object",
|
|
937
|
+
additionalProperties: false,
|
|
938
|
+
properties: {
|
|
939
|
+
dataset: { $ref: "#/$defs/predicate_ref_data_dataset" },
|
|
940
|
+
scenario: { $ref: "#/$defs/predicate_ref_data_scenario" }
|
|
941
|
+
},
|
|
942
|
+
required: ["dataset"]
|
|
943
|
+
},
|
|
944
|
+
predicate_ref_data_dataset: {
|
|
945
|
+
oneOf: [{ $ref: "#/$defs/dataset_name" }, { $ref: "#/$defs/predicate_ref_data_dataset_special" }]
|
|
946
|
+
},
|
|
947
|
+
predicate_ref_data_dataset_special: {
|
|
948
|
+
type: "string",
|
|
949
|
+
enum: ["inherit"]
|
|
950
|
+
},
|
|
951
|
+
predicate_ref_data_scenario: {
|
|
952
|
+
oneOf: [
|
|
953
|
+
{ $ref: "#/$defs/scenario_with_input_at_position" },
|
|
954
|
+
{ $ref: "#/$defs/scenario_with_input_at_value" },
|
|
955
|
+
{ $ref: "#/$defs/scenario_with_multiple_input_settings" },
|
|
956
|
+
{ $ref: "#/$defs/scenario_with_inputs_in_preset_at_position" },
|
|
957
|
+
{ $ref: "#/$defs/scenario_with_inputs_in_group_at_position" },
|
|
958
|
+
{ $ref: "#/$defs/predicate_ref_data_scenario_special" }
|
|
959
|
+
]
|
|
960
|
+
},
|
|
961
|
+
predicate_ref_data_scenario_special: {
|
|
962
|
+
type: "string",
|
|
963
|
+
enum: ["inherit"]
|
|
964
|
+
},
|
|
965
|
+
predicate_time: {
|
|
966
|
+
oneOf: [
|
|
967
|
+
{ $ref: "#/$defs/predicate_time_single" },
|
|
968
|
+
{ $ref: "#/$defs/predicate_time_pair" },
|
|
969
|
+
{ $ref: "#/$defs/predicate_time_gt" },
|
|
970
|
+
{ $ref: "#/$defs/predicate_time_gte" },
|
|
971
|
+
{ $ref: "#/$defs/predicate_time_lt" },
|
|
972
|
+
{ $ref: "#/$defs/predicate_time_lte" },
|
|
973
|
+
{ $ref: "#/$defs/predicate_time_gt_lt" },
|
|
974
|
+
{ $ref: "#/$defs/predicate_time_gt_lte" },
|
|
975
|
+
{ $ref: "#/$defs/predicate_time_gte_lt" },
|
|
976
|
+
{ $ref: "#/$defs/predicate_time_gte_lte" }
|
|
977
|
+
]
|
|
978
|
+
},
|
|
979
|
+
predicate_time_single: {
|
|
980
|
+
type: "number"
|
|
981
|
+
},
|
|
982
|
+
predicate_time_pair: {
|
|
983
|
+
type: "array",
|
|
984
|
+
items: [{ type: "number" }, { type: "number" }],
|
|
985
|
+
minItems: 2,
|
|
986
|
+
maxItems: 2
|
|
987
|
+
},
|
|
988
|
+
predicate_time_gt: {
|
|
989
|
+
type: "object",
|
|
990
|
+
additionalProperties: false,
|
|
991
|
+
properties: {
|
|
992
|
+
after_excl: { type: "number" }
|
|
993
|
+
},
|
|
994
|
+
required: ["after_excl"]
|
|
995
|
+
},
|
|
996
|
+
predicate_time_gte: {
|
|
997
|
+
type: "object",
|
|
998
|
+
additionalProperties: false,
|
|
999
|
+
properties: {
|
|
1000
|
+
after_incl: { type: "number" }
|
|
1001
|
+
},
|
|
1002
|
+
required: ["after_incl"]
|
|
1003
|
+
},
|
|
1004
|
+
predicate_time_lt: {
|
|
1005
|
+
type: "object",
|
|
1006
|
+
additionalProperties: false,
|
|
1007
|
+
properties: {
|
|
1008
|
+
before_excl: { type: "number" }
|
|
1009
|
+
},
|
|
1010
|
+
required: ["before_excl"]
|
|
1011
|
+
},
|
|
1012
|
+
predicate_time_lte: {
|
|
1013
|
+
type: "object",
|
|
1014
|
+
additionalProperties: false,
|
|
1015
|
+
properties: {
|
|
1016
|
+
before_incl: { type: "number" }
|
|
1017
|
+
},
|
|
1018
|
+
required: ["before_incl"]
|
|
1019
|
+
},
|
|
1020
|
+
predicate_time_gt_lt: {
|
|
1021
|
+
type: "object",
|
|
1022
|
+
additionalProperties: false,
|
|
1023
|
+
properties: {
|
|
1024
|
+
after_excl: { type: "number" },
|
|
1025
|
+
before_excl: { type: "number" }
|
|
1026
|
+
},
|
|
1027
|
+
required: ["after_excl", "before_excl"]
|
|
1028
|
+
},
|
|
1029
|
+
predicate_time_gt_lte: {
|
|
1030
|
+
type: "object",
|
|
1031
|
+
additionalProperties: false,
|
|
1032
|
+
properties: {
|
|
1033
|
+
after_excl: { type: "number" },
|
|
1034
|
+
before_incl: { type: "number" }
|
|
1035
|
+
},
|
|
1036
|
+
required: ["after_excl", "before_incl"]
|
|
1037
|
+
},
|
|
1038
|
+
predicate_time_gte_lt: {
|
|
1039
|
+
type: "object",
|
|
1040
|
+
additionalProperties: false,
|
|
1041
|
+
properties: {
|
|
1042
|
+
after_incl: { type: "number" },
|
|
1043
|
+
before_excl: { type: "number" }
|
|
1044
|
+
},
|
|
1045
|
+
required: ["after_incl", "before_excl"]
|
|
1046
|
+
},
|
|
1047
|
+
predicate_time_gte_lte: {
|
|
1048
|
+
type: "object",
|
|
1049
|
+
additionalProperties: false,
|
|
1050
|
+
properties: {
|
|
1051
|
+
after_incl: { type: "number" },
|
|
1052
|
+
before_incl: { type: "number" }
|
|
1053
|
+
},
|
|
1054
|
+
required: ["after_incl", "before_incl"]
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
};
|
|
1058
|
+
|
|
1059
|
+
// src/check/check-parser.ts
|
|
1060
|
+
function parseTestYaml(yamlStrings) {
|
|
1061
|
+
const groups = [];
|
|
1062
|
+
const ajv = new import_ajv.default();
|
|
1063
|
+
const validate = ajv.compile(check_schema_default);
|
|
1064
|
+
for (const yamlString of yamlStrings) {
|
|
1065
|
+
const parsed = import_yaml.default.parse(yamlString);
|
|
1066
|
+
if (validate(parsed)) {
|
|
1067
|
+
for (const group of parsed) {
|
|
1068
|
+
groups.push(group);
|
|
1069
|
+
}
|
|
1070
|
+
} else {
|
|
1071
|
+
let msg = "Failed to parse YAML tests";
|
|
1072
|
+
for (const error of validate.errors || []) {
|
|
1073
|
+
if (error.message) {
|
|
1074
|
+
msg += `
|
|
1075
|
+
${error.message}`;
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
return (0, import_neverthrow.err)(new Error(msg));
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
const checkSpec = {
|
|
1082
|
+
groups
|
|
1083
|
+
};
|
|
1084
|
+
return (0, import_neverthrow.ok)(checkSpec);
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
// src/check/check-planner.ts
|
|
1088
|
+
var import_assert_never5 = __toESM(require("assert-never"), 1);
|
|
1089
|
+
|
|
1090
|
+
// src/check/check-func.ts
|
|
1091
|
+
var passed = {
|
|
1092
|
+
status: "passed"
|
|
1093
|
+
};
|
|
1094
|
+
var gt = (a, b) => a > b;
|
|
1095
|
+
var gte = (a, b) => a >= b;
|
|
1096
|
+
var lt = (a, b) => a < b;
|
|
1097
|
+
var lte = (a, b) => a <= b;
|
|
1098
|
+
var eq = (a, b) => a === b;
|
|
1099
|
+
var approx = (tolerance) => {
|
|
1100
|
+
const f = (a, b) => {
|
|
1101
|
+
return a >= b - tolerance && a <= b + tolerance;
|
|
1102
|
+
};
|
|
1103
|
+
return f;
|
|
1104
|
+
};
|
|
1105
|
+
function checkFunc(spec) {
|
|
1106
|
+
function addCheckValueFunc(op, compareFunc) {
|
|
1107
|
+
const refSpec = spec[op];
|
|
1108
|
+
if (refSpec === void 0) {
|
|
1109
|
+
return;
|
|
1110
|
+
}
|
|
1111
|
+
if (typeof refSpec === "number") {
|
|
1112
|
+
checkValueFuncs.push((value, time) => {
|
|
1113
|
+
if (compareFunc(value, refSpec)) {
|
|
1114
|
+
return passed;
|
|
1115
|
+
} else {
|
|
1116
|
+
return {
|
|
1117
|
+
status: "failed",
|
|
1118
|
+
failValue: value,
|
|
1119
|
+
failTime: time
|
|
1120
|
+
};
|
|
1121
|
+
}
|
|
1122
|
+
});
|
|
1123
|
+
} else {
|
|
1124
|
+
checkValueFuncs.push((value, time, refDatasets) => {
|
|
1125
|
+
const refDataset = refDatasets == null ? void 0 : refDatasets.get(op);
|
|
1126
|
+
if (refDataset === void 0) {
|
|
1127
|
+
return {
|
|
1128
|
+
status: "error",
|
|
1129
|
+
message: "unhandled data reference"
|
|
1130
|
+
};
|
|
1131
|
+
}
|
|
1132
|
+
const refValue = refDataset.get(time);
|
|
1133
|
+
if (refValue !== void 0) {
|
|
1134
|
+
if (compareFunc(value, refValue)) {
|
|
1135
|
+
return passed;
|
|
1136
|
+
} else {
|
|
1137
|
+
return {
|
|
1138
|
+
status: "failed",
|
|
1139
|
+
failValue: value,
|
|
1140
|
+
failOp: op,
|
|
1141
|
+
failRefValue: refValue,
|
|
1142
|
+
failTime: time
|
|
1143
|
+
};
|
|
1144
|
+
}
|
|
1145
|
+
} else {
|
|
1146
|
+
return {
|
|
1147
|
+
status: "failed",
|
|
1148
|
+
message: "no reference value",
|
|
1149
|
+
failTime: time
|
|
1150
|
+
};
|
|
1151
|
+
}
|
|
1152
|
+
});
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
const checkValueFuncs = [];
|
|
1156
|
+
addCheckValueFunc("gt", gt);
|
|
1157
|
+
addCheckValueFunc("gte", gte);
|
|
1158
|
+
addCheckValueFunc("lt", lt);
|
|
1159
|
+
addCheckValueFunc("lte", lte);
|
|
1160
|
+
addCheckValueFunc("eq", eq);
|
|
1161
|
+
if (spec.approx !== void 0) {
|
|
1162
|
+
const tolerance = spec.tolerance || 0.1;
|
|
1163
|
+
addCheckValueFunc("approx", approx(tolerance));
|
|
1164
|
+
}
|
|
1165
|
+
const checkValue = (value, time, refDatasets) => {
|
|
1166
|
+
for (const f of checkValueFuncs) {
|
|
1167
|
+
const result = f(value, time, refDatasets);
|
|
1168
|
+
if (result.status !== "passed") {
|
|
1169
|
+
return result;
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
return passed;
|
|
1173
|
+
};
|
|
1174
|
+
if (spec.time !== void 0 && typeof spec.time === "number") {
|
|
1175
|
+
const time = spec.time;
|
|
1176
|
+
return (dataset, refDatasets) => {
|
|
1177
|
+
const value = dataset.get(time);
|
|
1178
|
+
if (value !== void 0) {
|
|
1179
|
+
return checkValue(value, time, refDatasets);
|
|
1180
|
+
} else {
|
|
1181
|
+
return {
|
|
1182
|
+
status: "failed",
|
|
1183
|
+
message: "no value",
|
|
1184
|
+
failTime: time
|
|
1185
|
+
};
|
|
1186
|
+
}
|
|
1187
|
+
};
|
|
1188
|
+
} else {
|
|
1189
|
+
let checkTime;
|
|
1190
|
+
if (spec.time !== void 0) {
|
|
1191
|
+
if (Array.isArray(spec.time)) {
|
|
1192
|
+
const timeSpec = spec.time;
|
|
1193
|
+
checkTime = (time) => time >= timeSpec[0] && time <= timeSpec[1];
|
|
1194
|
+
} else {
|
|
1195
|
+
const checkTimeFuncs = [];
|
|
1196
|
+
const timeSpec = spec.time;
|
|
1197
|
+
if (timeSpec.after_excl !== void 0) {
|
|
1198
|
+
checkTimeFuncs.push((time) => time > timeSpec.after_excl);
|
|
1199
|
+
}
|
|
1200
|
+
if (timeSpec.after_incl !== void 0) {
|
|
1201
|
+
checkTimeFuncs.push((time) => time >= timeSpec.after_incl);
|
|
1202
|
+
}
|
|
1203
|
+
if (timeSpec.before_excl !== void 0) {
|
|
1204
|
+
checkTimeFuncs.push((time) => time < timeSpec.before_excl);
|
|
1205
|
+
}
|
|
1206
|
+
if (timeSpec.before_incl !== void 0) {
|
|
1207
|
+
checkTimeFuncs.push((time) => time <= timeSpec.before_incl);
|
|
1208
|
+
}
|
|
1209
|
+
checkTime = (time) => {
|
|
1210
|
+
for (const f of checkTimeFuncs) {
|
|
1211
|
+
if (!f(time)) {
|
|
1212
|
+
return false;
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
return true;
|
|
1216
|
+
};
|
|
1217
|
+
}
|
|
1218
|
+
} else {
|
|
1219
|
+
checkTime = () => true;
|
|
1220
|
+
}
|
|
1221
|
+
return (dataset, refDatasets) => {
|
|
1222
|
+
for (const [time, value] of dataset) {
|
|
1223
|
+
if (checkTime(time)) {
|
|
1224
|
+
const result = checkValue(value, time, refDatasets);
|
|
1225
|
+
if (result.status !== "passed") {
|
|
1226
|
+
return result;
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
return passed;
|
|
1231
|
+
};
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
// src/check/check-action.ts
|
|
1236
|
+
function actionForPredicate(predicateSpec) {
|
|
1237
|
+
return {
|
|
1238
|
+
predicateSpec,
|
|
1239
|
+
run: checkFunc(predicateSpec)
|
|
1240
|
+
};
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
// src/_shared/combo.ts
|
|
1244
|
+
function cartesianProductOf(arr) {
|
|
1245
|
+
return arr.reduce((a, b) => {
|
|
1246
|
+
return a.map((x) => b.map((y) => x.concat([y]))).reduce((v, w) => v.concat(w), []);
|
|
1247
|
+
}, [[]]);
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
// src/check/check-dataset.ts
|
|
1251
|
+
function expandDatasets(modelSpec, datasetSpec) {
|
|
1252
|
+
var _a;
|
|
1253
|
+
let result;
|
|
1254
|
+
if (datasetSpec.name) {
|
|
1255
|
+
result = matchByName(modelSpec, datasetSpec.name, datasetSpec.source);
|
|
1256
|
+
} else if (datasetSpec.group) {
|
|
1257
|
+
result = matchByGroup(modelSpec, datasetSpec.group);
|
|
1258
|
+
} else if ((_a = datasetSpec.matching) == null ? void 0 : _a.type) {
|
|
1259
|
+
result = matchByType(modelSpec, datasetSpec.matching.type);
|
|
1260
|
+
}
|
|
1261
|
+
if (result.error) {
|
|
1262
|
+
return [
|
|
1263
|
+
{
|
|
1264
|
+
name: result.error.name,
|
|
1265
|
+
error: result.error.kind
|
|
1266
|
+
}
|
|
1267
|
+
];
|
|
1268
|
+
}
|
|
1269
|
+
const matches = result.matches;
|
|
1270
|
+
const checkDatasets = [];
|
|
1271
|
+
for (const match of matches) {
|
|
1272
|
+
if (match.outputVar) {
|
|
1273
|
+
checkDatasets.push({
|
|
1274
|
+
datasetKey: match.datasetKey,
|
|
1275
|
+
name: match.outputVar.varName
|
|
1276
|
+
});
|
|
1277
|
+
} else if (match.implVar) {
|
|
1278
|
+
const implVar = match.implVar;
|
|
1279
|
+
if (implVar.dimensions.length > 0) {
|
|
1280
|
+
const baseDatasetKey = match.datasetKey;
|
|
1281
|
+
const subscripts = [...implVar.dimensions.map((dim) => dim.subscripts)];
|
|
1282
|
+
const subscriptCombos = cartesianProductOf(subscripts);
|
|
1283
|
+
for (const subscriptCombo of subscriptCombos) {
|
|
1284
|
+
const subIdParts = subscriptCombo.map((sub) => `[${sub.id}]`).join("");
|
|
1285
|
+
const subNameParts = subscriptCombo.map((sub) => sub.name).join(",");
|
|
1286
|
+
checkDatasets.push({
|
|
1287
|
+
datasetKey: `${baseDatasetKey}${subIdParts}`,
|
|
1288
|
+
name: `${implVar.varName}[${subNameParts}]`
|
|
1289
|
+
});
|
|
1290
|
+
}
|
|
1291
|
+
} else {
|
|
1292
|
+
checkDatasets.push({
|
|
1293
|
+
datasetKey: match.datasetKey,
|
|
1294
|
+
name: implVar.varName
|
|
1295
|
+
});
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
return checkDatasets;
|
|
1300
|
+
}
|
|
1301
|
+
function matchByName(modelSpec, datasetName, datasetSource) {
|
|
1302
|
+
var _a;
|
|
1303
|
+
const varNameToMatch = datasetName.toLowerCase();
|
|
1304
|
+
const sourceToMatch = datasetSource == null ? void 0 : datasetSource.toLowerCase();
|
|
1305
|
+
for (const [datasetKey, outputVar] of modelSpec.outputVars) {
|
|
1306
|
+
if (((_a = outputVar.sourceName) == null ? void 0 : _a.toLowerCase()) === sourceToMatch && outputVar.varName.toLowerCase() === varNameToMatch) {
|
|
1307
|
+
return {
|
|
1308
|
+
matches: [
|
|
1309
|
+
{
|
|
1310
|
+
datasetKey,
|
|
1311
|
+
outputVar
|
|
1312
|
+
}
|
|
1313
|
+
]
|
|
1314
|
+
};
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
for (const [datasetKey, implVar] of modelSpec.implVars) {
|
|
1318
|
+
if (implVar.varName.toLowerCase() === varNameToMatch) {
|
|
1319
|
+
return {
|
|
1320
|
+
matches: [
|
|
1321
|
+
{
|
|
1322
|
+
datasetKey,
|
|
1323
|
+
implVar
|
|
1324
|
+
}
|
|
1325
|
+
]
|
|
1326
|
+
};
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
return {
|
|
1330
|
+
matches: [],
|
|
1331
|
+
error: {
|
|
1332
|
+
kind: "no-matches-for-dataset",
|
|
1333
|
+
name: datasetName
|
|
1334
|
+
}
|
|
1335
|
+
};
|
|
1336
|
+
}
|
|
1337
|
+
function matchByGroup(modelSpec, groupName) {
|
|
1338
|
+
const groupToMatch = groupName.toLowerCase();
|
|
1339
|
+
let matchedGroupName;
|
|
1340
|
+
let matchedGroupDatasetKeys;
|
|
1341
|
+
for (const [group, datasetKeys] of modelSpec.datasetGroups) {
|
|
1342
|
+
if (group.toLowerCase() === groupToMatch) {
|
|
1343
|
+
matchedGroupName = group;
|
|
1344
|
+
matchedGroupDatasetKeys = datasetKeys;
|
|
1345
|
+
break;
|
|
1346
|
+
}
|
|
1347
|
+
}
|
|
1348
|
+
if (matchedGroupName === void 0) {
|
|
1349
|
+
return {
|
|
1350
|
+
matches: [],
|
|
1351
|
+
error: {
|
|
1352
|
+
kind: "no-matches-for-group",
|
|
1353
|
+
name: groupName
|
|
1354
|
+
}
|
|
1355
|
+
};
|
|
1356
|
+
}
|
|
1357
|
+
const matches = [];
|
|
1358
|
+
for (const datasetKey of matchedGroupDatasetKeys) {
|
|
1359
|
+
const outputVar = modelSpec.outputVars.get(datasetKey);
|
|
1360
|
+
if (outputVar) {
|
|
1361
|
+
matches.push({
|
|
1362
|
+
datasetKey,
|
|
1363
|
+
outputVar
|
|
1364
|
+
});
|
|
1365
|
+
continue;
|
|
1366
|
+
}
|
|
1367
|
+
const implVar = modelSpec.implVars.get(datasetKey);
|
|
1368
|
+
if (implVar) {
|
|
1369
|
+
matches.push({
|
|
1370
|
+
datasetKey,
|
|
1371
|
+
implVar
|
|
1372
|
+
});
|
|
1373
|
+
continue;
|
|
1374
|
+
}
|
|
1375
|
+
return {
|
|
1376
|
+
matches: [],
|
|
1377
|
+
error: {
|
|
1378
|
+
kind: "no-matches-for-dataset",
|
|
1379
|
+
name: datasetKey
|
|
1380
|
+
}
|
|
1381
|
+
};
|
|
1382
|
+
}
|
|
1383
|
+
if (matches.length === 0) {
|
|
1384
|
+
return {
|
|
1385
|
+
matches: [],
|
|
1386
|
+
error: {
|
|
1387
|
+
kind: "no-matches-for-group",
|
|
1388
|
+
name: matchedGroupName
|
|
1389
|
+
}
|
|
1390
|
+
};
|
|
1391
|
+
}
|
|
1392
|
+
return {
|
|
1393
|
+
matches
|
|
1394
|
+
};
|
|
1395
|
+
}
|
|
1396
|
+
function matchByType(modelSpec, varTypeToMatch) {
|
|
1397
|
+
const matches = [];
|
|
1398
|
+
for (const [datasetKey, implVar] of modelSpec.implVars) {
|
|
1399
|
+
if (implVar.varType === varTypeToMatch) {
|
|
1400
|
+
matches.push({
|
|
1401
|
+
datasetKey,
|
|
1402
|
+
implVar
|
|
1403
|
+
});
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
if (matches.length === 0) {
|
|
1407
|
+
return {
|
|
1408
|
+
matches: [],
|
|
1409
|
+
error: {
|
|
1410
|
+
kind: "no-matches-for-type",
|
|
1411
|
+
name: varTypeToMatch
|
|
1412
|
+
}
|
|
1413
|
+
};
|
|
1414
|
+
}
|
|
1415
|
+
return {
|
|
1416
|
+
matches
|
|
1417
|
+
};
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1420
|
+
// src/check/check-scenario.ts
|
|
1421
|
+
var import_assert_never4 = __toESM(require("assert-never"), 1);
|
|
1422
|
+
function expandScenarios(modelSpec, scenarioSpecs, simplify) {
|
|
1423
|
+
if (scenarioSpecs.length === 0) {
|
|
1424
|
+
const scenarioSpec = {
|
|
1425
|
+
with_inputs: "all",
|
|
1426
|
+
at: "default"
|
|
1427
|
+
};
|
|
1428
|
+
return checkScenariosFromSpec(modelSpec, scenarioSpec, simplify);
|
|
1429
|
+
}
|
|
1430
|
+
const checkScenarios = [];
|
|
1431
|
+
for (const scenarioSpec of scenarioSpecs) {
|
|
1432
|
+
checkScenarios.push(...checkScenariosFromSpec(modelSpec, scenarioSpec, simplify));
|
|
1433
|
+
}
|
|
1434
|
+
return checkScenarios;
|
|
1435
|
+
}
|
|
1436
|
+
function inputPosition(position) {
|
|
1437
|
+
switch (position) {
|
|
1438
|
+
case "default":
|
|
1439
|
+
return "at-default";
|
|
1440
|
+
case "min":
|
|
1441
|
+
return "at-minimum";
|
|
1442
|
+
case "max":
|
|
1443
|
+
return "at-maximum";
|
|
1444
|
+
default:
|
|
1445
|
+
return void 0;
|
|
1446
|
+
}
|
|
1447
|
+
}
|
|
1448
|
+
function inputValueAtPosition(inputVar, position) {
|
|
1449
|
+
switch (position) {
|
|
1450
|
+
case "at-default":
|
|
1451
|
+
return inputVar.defaultValue;
|
|
1452
|
+
case "at-minimum":
|
|
1453
|
+
return inputVar.minValue;
|
|
1454
|
+
case "at-maximum":
|
|
1455
|
+
return inputVar.maxValue;
|
|
1456
|
+
default:
|
|
1457
|
+
(0, import_assert_never4.default)(position);
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
function inputDescAtPosition(inputVar, position) {
|
|
1461
|
+
return {
|
|
1462
|
+
name: inputVar.varName,
|
|
1463
|
+
inputVar,
|
|
1464
|
+
position,
|
|
1465
|
+
value: inputValueAtPosition(inputVar, position)
|
|
1466
|
+
};
|
|
1467
|
+
}
|
|
1468
|
+
function inputDescAtValue(inputVar, value) {
|
|
1469
|
+
return {
|
|
1470
|
+
name: inputVar.varName,
|
|
1471
|
+
inputVar,
|
|
1472
|
+
value
|
|
1473
|
+
};
|
|
1474
|
+
}
|
|
1475
|
+
function inputDescForVar(inputVar, at) {
|
|
1476
|
+
if (typeof at === "number") {
|
|
1477
|
+
const value = at;
|
|
1478
|
+
return inputDescAtValue(inputVar, value);
|
|
1479
|
+
} else {
|
|
1480
|
+
const position = inputPosition(at);
|
|
1481
|
+
return inputDescAtPosition(inputVar, position);
|
|
1482
|
+
}
|
|
1483
|
+
}
|
|
1484
|
+
function inputDescForName(modelSpec, inputName, at) {
|
|
1485
|
+
const inputNameToMatch = inputName.toLowerCase();
|
|
1486
|
+
const inputVar = [...modelSpec.inputVars.values()].find((inputVar2) => {
|
|
1487
|
+
return inputVar2.varName.toLowerCase() === inputNameToMatch;
|
|
1488
|
+
});
|
|
1489
|
+
if (inputVar) {
|
|
1490
|
+
return inputDescForVar(inputVar, at);
|
|
1491
|
+
} else {
|
|
1492
|
+
return {
|
|
1493
|
+
name: inputName
|
|
1494
|
+
};
|
|
1495
|
+
}
|
|
1496
|
+
}
|
|
1497
|
+
function groupForName(modelSpec, groupName) {
|
|
1498
|
+
const groupToMatch = groupName.toLowerCase();
|
|
1499
|
+
for (const [group, inputVars] of modelSpec.inputGroups) {
|
|
1500
|
+
if (group.toLowerCase() === groupToMatch) {
|
|
1501
|
+
return [group, inputVars];
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1504
|
+
return void 0;
|
|
1505
|
+
}
|
|
1506
|
+
function errorScenarioForInputGroup(kind, groupName) {
|
|
1507
|
+
return {
|
|
1508
|
+
inputDescs: [],
|
|
1509
|
+
error: {
|
|
1510
|
+
kind,
|
|
1511
|
+
name: groupName
|
|
1512
|
+
}
|
|
1513
|
+
};
|
|
1514
|
+
}
|
|
1515
|
+
function checkScenarioWithAllInputsAtPosition(position) {
|
|
1516
|
+
const scenario = allInputsAtPositionScenario(position);
|
|
1517
|
+
return {
|
|
1518
|
+
scenario,
|
|
1519
|
+
inputDescs: []
|
|
1520
|
+
};
|
|
1521
|
+
}
|
|
1522
|
+
function checkScenarioWithInputAtPosition(inputVar, position) {
|
|
1523
|
+
const varId = inputVar.varId;
|
|
1524
|
+
const scenario = inputAtPositionScenario(varId, varId, position);
|
|
1525
|
+
return {
|
|
1526
|
+
scenario,
|
|
1527
|
+
inputDescs: [inputDescAtPosition(inputVar, position)]
|
|
1528
|
+
};
|
|
1529
|
+
}
|
|
1530
|
+
function checkScenarioForInputDescs(groupName, inputDescs) {
|
|
1531
|
+
let scenario;
|
|
1532
|
+
if (inputDescs.every((desc) => desc.inputVar !== void 0)) {
|
|
1533
|
+
const settings = [];
|
|
1534
|
+
const keyParts = [];
|
|
1535
|
+
for (const inputDesc of inputDescs) {
|
|
1536
|
+
const varId = inputDesc.inputVar.varId;
|
|
1537
|
+
if (inputDesc.position) {
|
|
1538
|
+
settings.push(positionSetting(varId, inputDesc.position));
|
|
1539
|
+
keyParts.push(keyForInputAtPosition(varId, inputDesc.position));
|
|
1540
|
+
} else {
|
|
1541
|
+
settings.push(valueSetting(varId, inputDesc.value));
|
|
1542
|
+
keyParts.push(keyForInputAtValue(varId, inputDesc.value));
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1545
|
+
if (settings.length === 1) {
|
|
1546
|
+
const scenarioKey = `input${keyParts[0]}`;
|
|
1547
|
+
const groupKey = settings[0].inputVarId;
|
|
1548
|
+
scenario = settingsScenario(scenarioKey, groupKey, settings);
|
|
1549
|
+
} else if (settings.length > 1) {
|
|
1550
|
+
let scenarioKey;
|
|
1551
|
+
let groupKey;
|
|
1552
|
+
if (groupName) {
|
|
1553
|
+
scenarioKey = `group_${groupName.toLowerCase().replace(/ /g, "_")}`;
|
|
1554
|
+
groupKey = scenarioKey;
|
|
1555
|
+
} else {
|
|
1556
|
+
scenarioKey = "multi" + keyParts.join("_");
|
|
1557
|
+
groupKey = scenarioKey;
|
|
1558
|
+
}
|
|
1559
|
+
scenario = settingsScenario(scenarioKey, groupKey, settings);
|
|
1560
|
+
}
|
|
1561
|
+
} else {
|
|
1562
|
+
scenario = void 0;
|
|
1563
|
+
}
|
|
1564
|
+
return {
|
|
1565
|
+
scenario,
|
|
1566
|
+
inputGroupName: groupName,
|
|
1567
|
+
inputDescs
|
|
1568
|
+
};
|
|
1569
|
+
}
|
|
1570
|
+
function checkScenarioForInputSpecs(modelSpec, inputSpecs) {
|
|
1571
|
+
const inputDescs = inputSpecs.map((inputSpec) => {
|
|
1572
|
+
return inputDescForName(modelSpec, inputSpec.input, inputSpec.at);
|
|
1573
|
+
});
|
|
1574
|
+
return checkScenarioForInputDescs(void 0, inputDescs);
|
|
1575
|
+
}
|
|
1576
|
+
function checkScenarioMatrix(modelSpec, simplify) {
|
|
1577
|
+
const checkScenarios = [];
|
|
1578
|
+
checkScenarios.push(checkScenarioWithAllInputsAtPosition("at-default"));
|
|
1579
|
+
if (!simplify) {
|
|
1580
|
+
checkScenarios.push(checkScenarioWithAllInputsAtPosition("at-minimum"));
|
|
1581
|
+
checkScenarios.push(checkScenarioWithAllInputsAtPosition("at-maximum"));
|
|
1582
|
+
for (const inputVar of modelSpec.inputVars.values()) {
|
|
1583
|
+
checkScenarios.push(checkScenarioWithInputAtPosition(inputVar, "at-minimum"));
|
|
1584
|
+
checkScenarios.push(checkScenarioWithInputAtPosition(inputVar, "at-maximum"));
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1587
|
+
return checkScenarios;
|
|
1588
|
+
}
|
|
1589
|
+
function checkScenarioWithAllInputsInGroupAtPosition(modelSpec, groupName, position) {
|
|
1590
|
+
const result = groupForName(modelSpec, groupName);
|
|
1591
|
+
if (result === void 0) {
|
|
1592
|
+
return errorScenarioForInputGroup("unknown-input-group", groupName);
|
|
1593
|
+
}
|
|
1594
|
+
const [matchedGroupName, inputVars] = result;
|
|
1595
|
+
if (inputVars.length === 0) {
|
|
1596
|
+
return errorScenarioForInputGroup("empty-input-group", matchedGroupName);
|
|
1597
|
+
}
|
|
1598
|
+
const inputDescs = [];
|
|
1599
|
+
for (const inputVar of inputVars) {
|
|
1600
|
+
inputDescs.push(inputDescForVar(inputVar, position));
|
|
1601
|
+
}
|
|
1602
|
+
return checkScenarioForInputDescs(matchedGroupName, inputDescs);
|
|
1603
|
+
}
|
|
1604
|
+
function checkScenariosForEachInputInGroup(modelSpec, groupName, position) {
|
|
1605
|
+
const result = groupForName(modelSpec, groupName);
|
|
1606
|
+
if (result === void 0) {
|
|
1607
|
+
return [errorScenarioForInputGroup("unknown-input-group", groupName)];
|
|
1608
|
+
}
|
|
1609
|
+
const [matchedGroupName, inputVars] = result;
|
|
1610
|
+
if (inputVars.length === 0) {
|
|
1611
|
+
return [errorScenarioForInputGroup("empty-input-group", matchedGroupName)];
|
|
1612
|
+
}
|
|
1613
|
+
const checkScenarios = [];
|
|
1614
|
+
for (const inputVar of inputVars) {
|
|
1615
|
+
const inputDesc = inputDescForVar(inputVar, position);
|
|
1616
|
+
checkScenarios.push(checkScenarioForInputDescs(void 0, [inputDesc]));
|
|
1617
|
+
}
|
|
1618
|
+
return checkScenarios;
|
|
1619
|
+
}
|
|
1620
|
+
function checkScenariosFromSpec(modelSpec, scenarioSpec, simplify) {
|
|
1621
|
+
if (scenarioSpec.preset === "matrix") {
|
|
1622
|
+
return checkScenarioMatrix(modelSpec, simplify);
|
|
1623
|
+
}
|
|
1624
|
+
if (scenarioSpec.scenarios_for_each_input_in !== void 0) {
|
|
1625
|
+
const groupName = scenarioSpec.scenarios_for_each_input_in;
|
|
1626
|
+
const position = scenarioSpec.at;
|
|
1627
|
+
return checkScenariosForEachInputInGroup(modelSpec, groupName, position);
|
|
1628
|
+
}
|
|
1629
|
+
if (scenarioSpec.with !== void 0) {
|
|
1630
|
+
if (Array.isArray(scenarioSpec.with)) {
|
|
1631
|
+
const inputSpecs = scenarioSpec.with;
|
|
1632
|
+
return [checkScenarioForInputSpecs(modelSpec, inputSpecs)];
|
|
1633
|
+
} else {
|
|
1634
|
+
const inputSpec = {
|
|
1635
|
+
input: scenarioSpec.with,
|
|
1636
|
+
at: scenarioSpec.at
|
|
1637
|
+
};
|
|
1638
|
+
return [checkScenarioForInputSpecs(modelSpec, [inputSpec])];
|
|
1639
|
+
}
|
|
1640
|
+
}
|
|
1641
|
+
if (scenarioSpec.with_inputs === "all") {
|
|
1642
|
+
const position = inputPosition(scenarioSpec.at);
|
|
1643
|
+
return [checkScenarioWithAllInputsAtPosition(position)];
|
|
1644
|
+
}
|
|
1645
|
+
if (scenarioSpec.with_inputs_in !== void 0) {
|
|
1646
|
+
const groupName = scenarioSpec.with_inputs_in;
|
|
1647
|
+
const position = scenarioSpec.at;
|
|
1648
|
+
return [checkScenarioWithAllInputsInGroupAtPosition(modelSpec, groupName, position)];
|
|
1649
|
+
}
|
|
1650
|
+
throw new Error(`Unhandled scenario spec: ${JSON.stringify(scenarioSpec)}`);
|
|
1651
|
+
}
|
|
1652
|
+
|
|
1653
|
+
// src/check/check-planner.ts
|
|
1654
|
+
var CheckPlanner = class {
|
|
1655
|
+
constructor(modelSpec) {
|
|
1656
|
+
this.modelSpec = modelSpec;
|
|
1657
|
+
this.groups = [];
|
|
1658
|
+
this.tasks = /* @__PURE__ */ new Map();
|
|
1659
|
+
this.dataRefs = /* @__PURE__ */ new Map();
|
|
1660
|
+
this.checkKey = 1;
|
|
1661
|
+
}
|
|
1662
|
+
addAllChecks(checkSpec, simplifyScenarios) {
|
|
1663
|
+
for (const groupSpec of checkSpec.groups) {
|
|
1664
|
+
const groupName = groupSpec.describe;
|
|
1665
|
+
const planTests = [];
|
|
1666
|
+
for (const testSpec of groupSpec.tests) {
|
|
1667
|
+
const testName = testSpec.it;
|
|
1668
|
+
const checkScenarios = expandScenarios(this.modelSpec, testSpec.scenarios || [], simplifyScenarios);
|
|
1669
|
+
const checkDatasets = [];
|
|
1670
|
+
for (const datasetSpec of testSpec.datasets) {
|
|
1671
|
+
checkDatasets.push(...expandDatasets(this.modelSpec, datasetSpec));
|
|
1672
|
+
}
|
|
1673
|
+
const checkActions = [];
|
|
1674
|
+
for (const predicateSpec of testSpec.predicates) {
|
|
1675
|
+
checkActions.push(actionForPredicate(predicateSpec));
|
|
1676
|
+
}
|
|
1677
|
+
const planScenarios = [];
|
|
1678
|
+
for (const checkScenario of checkScenarios) {
|
|
1679
|
+
if (checkScenario.scenario === void 0) {
|
|
1680
|
+
planScenarios.push({
|
|
1681
|
+
checkScenario,
|
|
1682
|
+
datasets: []
|
|
1683
|
+
});
|
|
1684
|
+
continue;
|
|
1685
|
+
}
|
|
1686
|
+
const planDatasets = [];
|
|
1687
|
+
for (const checkDataset of checkDatasets) {
|
|
1688
|
+
if (checkDataset.datasetKey === void 0) {
|
|
1689
|
+
planDatasets.push({
|
|
1690
|
+
checkDataset,
|
|
1691
|
+
predicates: []
|
|
1692
|
+
});
|
|
1693
|
+
continue;
|
|
1694
|
+
}
|
|
1695
|
+
const planPredicates = [];
|
|
1696
|
+
for (const checkAction of checkActions) {
|
|
1697
|
+
const dataRefs = this.addDataRefs(checkAction.predicateSpec, checkScenario, checkDataset);
|
|
1698
|
+
const key = this.checkKey++;
|
|
1699
|
+
planPredicates.push({
|
|
1700
|
+
checkKey: key,
|
|
1701
|
+
action: checkAction,
|
|
1702
|
+
dataRefs
|
|
1703
|
+
});
|
|
1704
|
+
this.tasks.set(key, {
|
|
1705
|
+
scenario: checkScenario,
|
|
1706
|
+
dataset: checkDataset,
|
|
1707
|
+
action: checkAction,
|
|
1708
|
+
dataRefs
|
|
1709
|
+
});
|
|
1710
|
+
}
|
|
1711
|
+
planDatasets.push({
|
|
1712
|
+
checkDataset,
|
|
1713
|
+
predicates: planPredicates
|
|
1714
|
+
});
|
|
1715
|
+
}
|
|
1716
|
+
planScenarios.push({
|
|
1717
|
+
checkScenario,
|
|
1718
|
+
datasets: planDatasets
|
|
1719
|
+
});
|
|
1720
|
+
}
|
|
1721
|
+
planTests.push({
|
|
1722
|
+
name: testName,
|
|
1723
|
+
scenarios: planScenarios
|
|
1724
|
+
});
|
|
1725
|
+
}
|
|
1726
|
+
this.groups.push({
|
|
1727
|
+
name: groupName,
|
|
1728
|
+
tests: planTests
|
|
1729
|
+
});
|
|
1730
|
+
}
|
|
1731
|
+
}
|
|
1732
|
+
buildPlan() {
|
|
1733
|
+
return {
|
|
1734
|
+
groups: this.groups,
|
|
1735
|
+
tasks: this.tasks,
|
|
1736
|
+
dataRefs: this.dataRefs
|
|
1737
|
+
};
|
|
1738
|
+
}
|
|
1739
|
+
addDataRefs(predicateSpec, checkScenario, checkDataset) {
|
|
1740
|
+
let dataRefs;
|
|
1741
|
+
const addDataRef = (op) => {
|
|
1742
|
+
const predOp = predicateSpec[op];
|
|
1743
|
+
if (predOp === void 0 || typeof predOp === "number") {
|
|
1744
|
+
return;
|
|
1745
|
+
}
|
|
1746
|
+
let refDataset;
|
|
1747
|
+
if (typeof predOp.dataset === "string") {
|
|
1748
|
+
switch (predOp.dataset) {
|
|
1749
|
+
case "inherit":
|
|
1750
|
+
refDataset = checkDataset;
|
|
1751
|
+
break;
|
|
1752
|
+
default:
|
|
1753
|
+
(0, import_assert_never5.default)(predOp.dataset);
|
|
1754
|
+
}
|
|
1755
|
+
} else {
|
|
1756
|
+
const refDatasetSpec = { name: predOp.dataset.name };
|
|
1757
|
+
const matchedRefDatasets = expandDatasets(this.modelSpec, refDatasetSpec);
|
|
1758
|
+
if (matchedRefDatasets.length === 1) {
|
|
1759
|
+
refDataset = matchedRefDatasets[0];
|
|
1760
|
+
} else {
|
|
1761
|
+
refDataset = {
|
|
1762
|
+
name: predOp.dataset.name
|
|
1763
|
+
};
|
|
1764
|
+
}
|
|
1765
|
+
}
|
|
1766
|
+
let refScenario;
|
|
1767
|
+
if (typeof predOp.scenario === "string") {
|
|
1768
|
+
switch (predOp.scenario) {
|
|
1769
|
+
case "inherit":
|
|
1770
|
+
refScenario = checkScenario;
|
|
1771
|
+
break;
|
|
1772
|
+
default:
|
|
1773
|
+
(0, import_assert_never5.default)(predOp.scenario);
|
|
1774
|
+
}
|
|
1775
|
+
} else {
|
|
1776
|
+
const refScenarioSpecs = predOp.scenario ? [predOp.scenario] : [];
|
|
1777
|
+
const matchedRefScenarios = expandScenarios(this.modelSpec, refScenarioSpecs, true);
|
|
1778
|
+
if (matchedRefScenarios.length === 1) {
|
|
1779
|
+
refScenario = matchedRefScenarios[0];
|
|
1780
|
+
}
|
|
1781
|
+
if (refScenario === void 0) {
|
|
1782
|
+
refScenario = {
|
|
1783
|
+
inputDescs: []
|
|
1784
|
+
};
|
|
1785
|
+
}
|
|
1786
|
+
}
|
|
1787
|
+
let dataRefKey;
|
|
1788
|
+
if (refScenario.scenario && refDataset.datasetKey) {
|
|
1789
|
+
dataRefKey = `${refScenario.scenario.key}::${refDataset.datasetKey}`;
|
|
1790
|
+
}
|
|
1791
|
+
const dataRef = {
|
|
1792
|
+
key: dataRefKey,
|
|
1793
|
+
dataset: refDataset,
|
|
1794
|
+
scenario: refScenario
|
|
1795
|
+
};
|
|
1796
|
+
if (dataRefKey) {
|
|
1797
|
+
this.dataRefs.set(dataRefKey, dataRef);
|
|
1798
|
+
}
|
|
1799
|
+
if (dataRefs === void 0) {
|
|
1800
|
+
dataRefs = /* @__PURE__ */ new Map();
|
|
1801
|
+
}
|
|
1802
|
+
dataRefs.set(op, dataRef);
|
|
1803
|
+
};
|
|
1804
|
+
addDataRef("gt");
|
|
1805
|
+
addDataRef("gte");
|
|
1806
|
+
addDataRef("lt");
|
|
1807
|
+
addDataRef("lte");
|
|
1808
|
+
addDataRef("eq");
|
|
1809
|
+
addDataRef("approx");
|
|
1810
|
+
return dataRefs;
|
|
1811
|
+
}
|
|
1812
|
+
};
|
|
1813
|
+
|
|
1814
|
+
// src/check/check-summary.ts
|
|
1815
|
+
function checkSummaryFromReport(checkReport) {
|
|
1816
|
+
const predicateSummaries = [];
|
|
1817
|
+
for (const group of checkReport.groups) {
|
|
1818
|
+
for (const test of group.tests) {
|
|
1819
|
+
for (const scenario of test.scenarios) {
|
|
1820
|
+
for (const dataset of scenario.datasets) {
|
|
1821
|
+
for (const predicate of dataset.predicates) {
|
|
1822
|
+
switch (predicate.result.status) {
|
|
1823
|
+
case "passed":
|
|
1824
|
+
break;
|
|
1825
|
+
case "failed":
|
|
1826
|
+
case "error":
|
|
1827
|
+
predicateSummaries.push({
|
|
1828
|
+
checkKey: predicate.checkKey,
|
|
1829
|
+
result: predicate.result
|
|
1830
|
+
});
|
|
1831
|
+
break;
|
|
1832
|
+
default:
|
|
1833
|
+
(0, import_assert_never6.assertNever)(predicate.result.status);
|
|
1834
|
+
}
|
|
1835
|
+
}
|
|
1836
|
+
}
|
|
1837
|
+
}
|
|
1838
|
+
}
|
|
1839
|
+
}
|
|
1840
|
+
return {
|
|
1841
|
+
predicateSummaries
|
|
1842
|
+
};
|
|
1843
|
+
}
|
|
1844
|
+
function checkReportFromSummary(checkConfig, checkSummary, simplifyScenarios) {
|
|
1845
|
+
const checkSpecResult = parseTestYaml(checkConfig.tests);
|
|
1846
|
+
if (checkSpecResult.isErr()) {
|
|
1847
|
+
return void 0;
|
|
1848
|
+
}
|
|
1849
|
+
const checkSpec = checkSpecResult.value;
|
|
1850
|
+
const checkPlanner = new CheckPlanner(checkConfig.bundle.model.modelSpec);
|
|
1851
|
+
checkPlanner.addAllChecks(checkSpec, simplifyScenarios);
|
|
1852
|
+
const checkPlan = checkPlanner.buildPlan();
|
|
1853
|
+
const checkResults = /* @__PURE__ */ new Map();
|
|
1854
|
+
for (const predicateSummary of checkSummary.predicateSummaries) {
|
|
1855
|
+
checkResults.set(predicateSummary.checkKey, predicateSummary.result);
|
|
1856
|
+
}
|
|
1857
|
+
return buildCheckReport(checkPlan, checkResults);
|
|
1858
|
+
}
|
|
1859
|
+
|
|
1860
|
+
// src/compare/compare-data-coordinator.ts
|
|
1861
|
+
var import_assert_never7 = require("assert-never");
|
|
1862
|
+
var CompareDataCoordinator = class {
|
|
1863
|
+
constructor(bundleModelL, bundleModelR) {
|
|
1864
|
+
this.bundleModelL = bundleModelL;
|
|
1865
|
+
this.bundleModelR = bundleModelR;
|
|
1866
|
+
this.taskQueue = new TaskQueue({
|
|
1867
|
+
process: async (request) => {
|
|
1868
|
+
switch (request.kind) {
|
|
1869
|
+
case "dataset": {
|
|
1870
|
+
const [resultL, resultR] = await Promise.all([
|
|
1871
|
+
this.bundleModelL.getDatasetsForScenario(request.scenario, request.datasetKeys),
|
|
1872
|
+
this.bundleModelR.getDatasetsForScenario(request.scenario, request.datasetKeys)
|
|
1873
|
+
]);
|
|
1874
|
+
return {
|
|
1875
|
+
kind: "dataset",
|
|
1876
|
+
datasetMapL: resultL.datasetMap,
|
|
1877
|
+
datasetMapR: resultR.datasetMap
|
|
1878
|
+
};
|
|
1879
|
+
}
|
|
1880
|
+
case "graph-data": {
|
|
1881
|
+
const bundleModel = request.bundle === "right" ? this.bundleModelR : this.bundleModelL;
|
|
1882
|
+
const graphData = await bundleModel.getGraphDataForScenario(request.scenario, request.graphId);
|
|
1883
|
+
return {
|
|
1884
|
+
kind: "graph-data",
|
|
1885
|
+
graphData
|
|
1886
|
+
};
|
|
1887
|
+
}
|
|
1888
|
+
default:
|
|
1889
|
+
(0, import_assert_never7.assertNever)(request);
|
|
1890
|
+
}
|
|
1891
|
+
}
|
|
1892
|
+
});
|
|
1893
|
+
}
|
|
1894
|
+
requestDatasetMaps(requestKey, scenario, datasetKeys, onResponse) {
|
|
1895
|
+
const request = {
|
|
1896
|
+
kind: "dataset",
|
|
1897
|
+
scenario,
|
|
1898
|
+
datasetKeys
|
|
1899
|
+
};
|
|
1900
|
+
this.taskQueue.addTask(requestKey, request, (response) => {
|
|
1901
|
+
if (response.kind === "dataset") {
|
|
1902
|
+
onResponse(response.datasetMapL, response.datasetMapR);
|
|
1903
|
+
}
|
|
1904
|
+
});
|
|
1905
|
+
}
|
|
1906
|
+
requestGraphData(requestKey, bundle, scenario, graphId, onResponse) {
|
|
1907
|
+
const request = {
|
|
1908
|
+
kind: "graph-data",
|
|
1909
|
+
bundle,
|
|
1910
|
+
scenario,
|
|
1911
|
+
graphId
|
|
1912
|
+
};
|
|
1913
|
+
this.taskQueue.addTask(requestKey, request, (response) => {
|
|
1914
|
+
if (response.kind === "graph-data") {
|
|
1915
|
+
onResponse(response.graphData);
|
|
1916
|
+
}
|
|
1917
|
+
});
|
|
1918
|
+
}
|
|
1919
|
+
cancelRequest(key) {
|
|
1920
|
+
this.taskQueue.cancelTask(key);
|
|
1921
|
+
}
|
|
1922
|
+
};
|
|
1923
|
+
|
|
1924
|
+
// src/compare/compare-datasets.ts
|
|
1925
|
+
function diffDatasets(datasetL, datasetR) {
|
|
1926
|
+
let minValueL = Number.MAX_VALUE;
|
|
1927
|
+
let maxValueL = Number.MIN_VALUE;
|
|
1928
|
+
let minValueR = Number.MAX_VALUE;
|
|
1929
|
+
let maxValueR = Number.MIN_VALUE;
|
|
1930
|
+
let minValue = Number.MAX_VALUE;
|
|
1931
|
+
let maxValue = Number.MIN_VALUE;
|
|
1932
|
+
let minRawDiff = Number.MAX_VALUE;
|
|
1933
|
+
let maxRawDiff = -1;
|
|
1934
|
+
let maxDiffPoint;
|
|
1935
|
+
let diffCount = 0;
|
|
1936
|
+
let totalRawDiff = 0;
|
|
1937
|
+
if (datasetL && datasetR) {
|
|
1938
|
+
const times = /* @__PURE__ */ new Set([...datasetL.keys(), ...datasetR.keys()]);
|
|
1939
|
+
for (const t of times) {
|
|
1940
|
+
const valueL = datasetL.get(t);
|
|
1941
|
+
if (valueL !== void 0) {
|
|
1942
|
+
if (valueL < minValueL)
|
|
1943
|
+
minValueL = valueL;
|
|
1944
|
+
if (valueL > maxValueL)
|
|
1945
|
+
maxValueL = valueL;
|
|
1946
|
+
if (valueL < minValue)
|
|
1947
|
+
minValue = valueL;
|
|
1948
|
+
if (valueL > maxValue)
|
|
1949
|
+
maxValue = valueL;
|
|
1950
|
+
}
|
|
1951
|
+
const valueR = datasetR.get(t);
|
|
1952
|
+
if (valueR !== void 0) {
|
|
1953
|
+
if (valueR < minValueR)
|
|
1954
|
+
minValueR = valueR;
|
|
1955
|
+
if (valueR > maxValueR)
|
|
1956
|
+
maxValueR = valueR;
|
|
1957
|
+
if (valueR < minValue)
|
|
1958
|
+
minValue = valueR;
|
|
1959
|
+
if (valueR > maxValue)
|
|
1960
|
+
maxValue = valueR;
|
|
1961
|
+
}
|
|
1962
|
+
if (valueL === void 0 || valueR === void 0) {
|
|
1963
|
+
continue;
|
|
1964
|
+
}
|
|
1965
|
+
const rawDiff = Math.abs(valueR - valueL);
|
|
1966
|
+
if (rawDiff < minRawDiff) {
|
|
1967
|
+
minRawDiff = rawDiff;
|
|
1968
|
+
}
|
|
1969
|
+
if (rawDiff > maxRawDiff) {
|
|
1970
|
+
maxRawDiff = rawDiff;
|
|
1971
|
+
maxDiffPoint = {
|
|
1972
|
+
time: t,
|
|
1973
|
+
valueL,
|
|
1974
|
+
valueR
|
|
1975
|
+
};
|
|
1976
|
+
}
|
|
1977
|
+
diffCount++;
|
|
1978
|
+
totalRawDiff += rawDiff;
|
|
1979
|
+
}
|
|
1980
|
+
}
|
|
1981
|
+
function pct(x) {
|
|
1982
|
+
return x * 100;
|
|
1983
|
+
}
|
|
1984
|
+
let minDiff;
|
|
1985
|
+
let maxDiff;
|
|
1986
|
+
let avgDiff;
|
|
1987
|
+
if (minValueL === maxValueL && minValueR === maxValueR) {
|
|
1988
|
+
const diff = pct(maxValueL !== 0 ? Math.abs((maxValueR - maxValueL) / maxValueL) : 1);
|
|
1989
|
+
minDiff = diff;
|
|
1990
|
+
maxDiff = diff;
|
|
1991
|
+
avgDiff = diff;
|
|
1992
|
+
} else {
|
|
1993
|
+
const spread = maxValue - minValue;
|
|
1994
|
+
minDiff = pct(spread > 0 ? minRawDiff / spread : 0);
|
|
1995
|
+
maxDiff = pct(spread > 0 ? maxRawDiff / spread : 0);
|
|
1996
|
+
const avgRawDiff = totalRawDiff / diffCount;
|
|
1997
|
+
avgDiff = pct(spread > 0 ? avgRawDiff / spread : 0);
|
|
1998
|
+
}
|
|
1999
|
+
let validity;
|
|
2000
|
+
if (datasetL && datasetR) {
|
|
2001
|
+
validity = "both";
|
|
2002
|
+
} else if (datasetL) {
|
|
2003
|
+
validity = "left-only";
|
|
2004
|
+
} else if (datasetR) {
|
|
2005
|
+
validity = "right-only";
|
|
2006
|
+
} else {
|
|
2007
|
+
validity = "neither";
|
|
2008
|
+
}
|
|
2009
|
+
return {
|
|
2010
|
+
validity,
|
|
2011
|
+
minValue,
|
|
2012
|
+
maxValue,
|
|
2013
|
+
avgDiff,
|
|
2014
|
+
minDiff,
|
|
2015
|
+
maxDiff,
|
|
2016
|
+
maxDiffPoint
|
|
2017
|
+
};
|
|
2018
|
+
}
|
|
2019
|
+
function compareDatasets(scenarioKey, datasetKey, datasetMapL, datasetMapR) {
|
|
2020
|
+
const datasetL = datasetMapL.get(datasetKey);
|
|
2021
|
+
const datasetR = datasetMapR.get(datasetKey);
|
|
2022
|
+
const diffReport = diffDatasets(datasetL, datasetR);
|
|
2023
|
+
return {
|
|
2024
|
+
scenarioKey,
|
|
2025
|
+
datasetKey,
|
|
2026
|
+
diffReport
|
|
2027
|
+
};
|
|
2028
|
+
}
|
|
2029
|
+
|
|
2030
|
+
// src/compare/compare-graphs.ts
|
|
2031
|
+
function diffGraphs(graphL, graphR, scenarioKey, datasetSummaries) {
|
|
2032
|
+
let inclusion;
|
|
2033
|
+
if (graphL && graphR) {
|
|
2034
|
+
inclusion = "both";
|
|
2035
|
+
} else if (graphL) {
|
|
2036
|
+
inclusion = "left-only";
|
|
2037
|
+
} else if (graphR) {
|
|
2038
|
+
inclusion = "right-only";
|
|
2039
|
+
} else {
|
|
2040
|
+
inclusion = "neither";
|
|
2041
|
+
}
|
|
2042
|
+
const metadataReports = [];
|
|
2043
|
+
if ((graphL == null ? void 0 : graphL.metadata) && (graphR == null ? void 0 : graphR.metadata)) {
|
|
2044
|
+
const metaKeys = /* @__PURE__ */ new Set();
|
|
2045
|
+
for (const key of graphL.metadata.keys()) {
|
|
2046
|
+
metaKeys.add(key);
|
|
2047
|
+
}
|
|
2048
|
+
for (const key of graphR.metadata.keys()) {
|
|
2049
|
+
metaKeys.add(key);
|
|
2050
|
+
}
|
|
2051
|
+
for (const key of metaKeys) {
|
|
2052
|
+
const valueL = graphL.metadata.get(key);
|
|
2053
|
+
const valueR = graphR.metadata.get(key);
|
|
2054
|
+
if (valueL !== valueR) {
|
|
2055
|
+
metadataReports.push({
|
|
2056
|
+
key,
|
|
2057
|
+
valueL,
|
|
2058
|
+
valueR
|
|
2059
|
+
});
|
|
2060
|
+
}
|
|
2061
|
+
}
|
|
2062
|
+
}
|
|
2063
|
+
const datasetReports = [];
|
|
2064
|
+
if (graphL && graphR) {
|
|
2065
|
+
const datasetKeys = /* @__PURE__ */ new Set();
|
|
2066
|
+
for (const dataset of graphL.datasets) {
|
|
2067
|
+
datasetKeys.add(dataset.datasetKey);
|
|
2068
|
+
}
|
|
2069
|
+
for (const dataset of graphR.datasets) {
|
|
2070
|
+
datasetKeys.add(dataset.datasetKey);
|
|
2071
|
+
}
|
|
2072
|
+
for (const datasetKey of datasetKeys) {
|
|
2073
|
+
const summary = datasetSummaries.find((summary2) => summary2.d === datasetKey && summary2.s === scenarioKey);
|
|
2074
|
+
const maxDiff = summary !== void 0 ? summary.md : void 0;
|
|
2075
|
+
datasetReports.push({
|
|
2076
|
+
datasetKey,
|
|
2077
|
+
maxDiff
|
|
2078
|
+
});
|
|
2079
|
+
}
|
|
2080
|
+
}
|
|
2081
|
+
return {
|
|
2082
|
+
inclusion,
|
|
2083
|
+
metadataReports,
|
|
2084
|
+
datasetReports
|
|
2085
|
+
};
|
|
2086
|
+
}
|
|
2087
|
+
|
|
2088
|
+
// src/compare/compare-summary.ts
|
|
2089
|
+
function compareSummaryFromReport(compareReport) {
|
|
2090
|
+
const datasetSummaries = [];
|
|
2091
|
+
for (const r of compareReport.datasetReports) {
|
|
2092
|
+
if (r.diffReport.validity === "both" && r.diffReport.maxDiff > 0) {
|
|
2093
|
+
datasetSummaries.push({
|
|
2094
|
+
s: r.scenarioKey,
|
|
2095
|
+
d: r.datasetKey,
|
|
2096
|
+
md: r.diffReport.maxDiff
|
|
2097
|
+
});
|
|
2098
|
+
}
|
|
2099
|
+
}
|
|
2100
|
+
return {
|
|
2101
|
+
datasetSummaries,
|
|
2102
|
+
perfReportL: compareReport.perfReportL,
|
|
2103
|
+
perfReportR: compareReport.perfReportR
|
|
2104
|
+
};
|
|
2105
|
+
}
|
|
2106
|
+
|
|
2107
|
+
// src/config/synchronized-model.ts
|
|
2108
|
+
function synchronizedBundleModel(sourceModel) {
|
|
2109
|
+
var _a;
|
|
2110
|
+
const promiseQueue = new PromiseQueue();
|
|
2111
|
+
return {
|
|
2112
|
+
modelSpec: sourceModel.modelSpec,
|
|
2113
|
+
getDatasetsForScenario: (scenario, datasetKeys) => {
|
|
2114
|
+
return promiseQueue.add(() => sourceModel.getDatasetsForScenario(scenario, datasetKeys));
|
|
2115
|
+
},
|
|
2116
|
+
getGraphsForDataset: (_a = sourceModel.getGraphsForDataset) == null ? void 0 : _a.bind(sourceModel),
|
|
2117
|
+
getGraphDataForScenario: (scenario, graphId) => {
|
|
2118
|
+
return promiseQueue.add(() => sourceModel.getGraphDataForScenario(scenario, graphId));
|
|
2119
|
+
},
|
|
2120
|
+
getGraphLinksForScenario: sourceModel.getGraphLinksForScenario.bind(sourceModel)
|
|
2121
|
+
};
|
|
2122
|
+
}
|
|
2123
|
+
var PromiseQueue = class {
|
|
2124
|
+
constructor() {
|
|
2125
|
+
this.tasks = [];
|
|
2126
|
+
this.runningCount = 0;
|
|
2127
|
+
}
|
|
2128
|
+
add(f) {
|
|
2129
|
+
return new Promise((resolve, reject) => {
|
|
2130
|
+
const run = async () => {
|
|
2131
|
+
this.runningCount++;
|
|
2132
|
+
const promise = f();
|
|
2133
|
+
try {
|
|
2134
|
+
const result = await promise;
|
|
2135
|
+
resolve(result);
|
|
2136
|
+
} catch (e) {
|
|
2137
|
+
reject(e);
|
|
2138
|
+
} finally {
|
|
2139
|
+
this.runningCount--;
|
|
2140
|
+
this.runNext();
|
|
2141
|
+
}
|
|
2142
|
+
};
|
|
2143
|
+
if (this.runningCount < 1) {
|
|
2144
|
+
run();
|
|
2145
|
+
} else {
|
|
2146
|
+
this.tasks.push(run);
|
|
2147
|
+
}
|
|
2148
|
+
});
|
|
2149
|
+
}
|
|
2150
|
+
runNext() {
|
|
2151
|
+
if (this.tasks.length > 0) {
|
|
2152
|
+
const task = this.tasks.shift();
|
|
2153
|
+
if (task) {
|
|
2154
|
+
task();
|
|
2155
|
+
}
|
|
2156
|
+
}
|
|
2157
|
+
}
|
|
2158
|
+
};
|
|
2159
|
+
|
|
2160
|
+
// src/config/config.ts
|
|
2161
|
+
async function createConfig(options) {
|
|
2162
|
+
var _a;
|
|
2163
|
+
const origCurrentBundle = await loadSynchronized(options.current);
|
|
2164
|
+
let currentBundle;
|
|
2165
|
+
let compareConfig;
|
|
2166
|
+
if (options.compare === void 0) {
|
|
2167
|
+
currentBundle = origCurrentBundle;
|
|
2168
|
+
} else {
|
|
2169
|
+
const baselineBundle = await loadSynchronized(options.compare.baseline);
|
|
2170
|
+
const renamedDatasetKeys = options.compare.datasets.renamedDatasetKeys;
|
|
2171
|
+
const invertedRenamedKeys = /* @__PURE__ */ new Map();
|
|
2172
|
+
renamedDatasetKeys == null ? void 0 : renamedDatasetKeys.forEach((newKey, oldKey) => {
|
|
2173
|
+
invertedRenamedKeys.set(newKey, oldKey);
|
|
2174
|
+
});
|
|
2175
|
+
const rightKeyForLeftKey = (leftKey) => {
|
|
2176
|
+
return (renamedDatasetKeys == null ? void 0 : renamedDatasetKeys.get(leftKey)) || leftKey;
|
|
2177
|
+
};
|
|
2178
|
+
const leftKeyForRightKey = (rightKey) => {
|
|
2179
|
+
return invertedRenamedKeys.get(rightKey) || rightKey;
|
|
2180
|
+
};
|
|
2181
|
+
const origBundleModelR = origCurrentBundle.model;
|
|
2182
|
+
const adjBundleModelR = {
|
|
2183
|
+
modelSpec: origBundleModelR.modelSpec,
|
|
2184
|
+
getDatasetsForScenario: async (scenario, datasetKeys) => {
|
|
2185
|
+
const rightKeys = datasetKeys.map(rightKeyForLeftKey);
|
|
2186
|
+
const result = await origBundleModelR.getDatasetsForScenario(scenario, rightKeys);
|
|
2187
|
+
const mapWithRightKeys = result.datasetMap;
|
|
2188
|
+
const mapWithLeftKeys = /* @__PURE__ */ new Map();
|
|
2189
|
+
for (const [rightKey, dataset] of mapWithRightKeys.entries()) {
|
|
2190
|
+
const leftKey = leftKeyForRightKey(rightKey);
|
|
2191
|
+
mapWithLeftKeys.set(leftKey, dataset);
|
|
2192
|
+
}
|
|
2193
|
+
return {
|
|
2194
|
+
datasetMap: mapWithLeftKeys,
|
|
2195
|
+
modelRunTime: result.modelRunTime
|
|
2196
|
+
};
|
|
2197
|
+
},
|
|
2198
|
+
getGraphsForDataset: (_a = origBundleModelR.getGraphsForDataset) == null ? void 0 : _a.bind(origBundleModelR),
|
|
2199
|
+
getGraphDataForScenario: origBundleModelR.getGraphDataForScenario.bind(origBundleModelR),
|
|
2200
|
+
getGraphLinksForScenario: origBundleModelR.getGraphLinksForScenario.bind(origBundleModelR)
|
|
2201
|
+
};
|
|
2202
|
+
currentBundle = __spreadProps(__spreadValues({}, origCurrentBundle), {
|
|
2203
|
+
model: adjBundleModelR
|
|
2204
|
+
});
|
|
2205
|
+
compareConfig = {
|
|
2206
|
+
bundleL: baselineBundle,
|
|
2207
|
+
bundleR: currentBundle,
|
|
2208
|
+
thresholds: options.compare.thresholds,
|
|
2209
|
+
scenarios: options.compare.scenarios,
|
|
2210
|
+
datasets: options.compare.datasets
|
|
2211
|
+
};
|
|
2212
|
+
}
|
|
2213
|
+
const checkConfig = {
|
|
2214
|
+
bundle: currentBundle,
|
|
2215
|
+
tests: options.check.tests
|
|
2216
|
+
};
|
|
2217
|
+
return {
|
|
2218
|
+
check: checkConfig,
|
|
2219
|
+
compare: compareConfig
|
|
2220
|
+
};
|
|
2221
|
+
}
|
|
2222
|
+
async function loadSynchronized(sourceBundle) {
|
|
2223
|
+
const sourceModel = await sourceBundle.bundle.initModel();
|
|
2224
|
+
const synchronizedModel = synchronizedBundleModel(sourceModel);
|
|
2225
|
+
return {
|
|
2226
|
+
name: sourceBundle.name,
|
|
2227
|
+
version: sourceBundle.bundle.version,
|
|
2228
|
+
model: synchronizedModel
|
|
2229
|
+
};
|
|
2230
|
+
}
|
|
2231
|
+
|
|
2232
|
+
// src/config/dataset-manager.ts
|
|
2233
|
+
var DatasetManager = class {
|
|
2234
|
+
constructor(bundleL, bundleR, renamedDatasetKeys) {
|
|
2235
|
+
this.bundleL = bundleL;
|
|
2236
|
+
this.bundleR = bundleR;
|
|
2237
|
+
this.renamedDatasetKeys = renamedDatasetKeys;
|
|
2238
|
+
const invertedRenamedKeys = /* @__PURE__ */ new Map();
|
|
2239
|
+
renamedDatasetKeys == null ? void 0 : renamedDatasetKeys.forEach((newKey, oldKey) => {
|
|
2240
|
+
invertedRenamedKeys.set(newKey, oldKey);
|
|
2241
|
+
});
|
|
2242
|
+
function leftKeyForRightKey(rightKey) {
|
|
2243
|
+
return invertedRenamedKeys.get(rightKey) || rightKey;
|
|
2244
|
+
}
|
|
2245
|
+
const allOutputVarKeysSet = /* @__PURE__ */ new Set();
|
|
2246
|
+
const modelOutputVarKeysSet = /* @__PURE__ */ new Set();
|
|
2247
|
+
function addOutputVars(outputVars, handleRenames) {
|
|
2248
|
+
outputVars.forEach((outputVar, key) => {
|
|
2249
|
+
const remappedKey = handleRenames ? leftKeyForRightKey(key) : key;
|
|
2250
|
+
allOutputVarKeysSet.add(remappedKey);
|
|
2251
|
+
if (outputVar.sourceName === void 0) {
|
|
2252
|
+
modelOutputVarKeysSet.add(remappedKey);
|
|
2253
|
+
}
|
|
2254
|
+
});
|
|
2255
|
+
}
|
|
2256
|
+
addOutputVars(bundleL.modelSpec.outputVars, false);
|
|
2257
|
+
addOutputVars(bundleR.modelSpec.outputVars, true);
|
|
2258
|
+
this.allOutputVarKeys = Array.from(allOutputVarKeysSet);
|
|
2259
|
+
this.modelOutputVarKeys = Array.from(modelOutputVarKeysSet);
|
|
2260
|
+
}
|
|
2261
|
+
getDatasetKeysForScenario(scenario) {
|
|
2262
|
+
if (scenario.kind === "all-inputs" && scenario.position === "at-default") {
|
|
2263
|
+
return this.allOutputVarKeys;
|
|
2264
|
+
} else {
|
|
2265
|
+
return this.modelOutputVarKeys;
|
|
2266
|
+
}
|
|
2267
|
+
}
|
|
2268
|
+
getDatasetInfo(datasetKey) {
|
|
2269
|
+
var _a;
|
|
2270
|
+
const modelSpecL = this.bundleL.modelSpec;
|
|
2271
|
+
const modelSpecR = this.bundleR.modelSpec;
|
|
2272
|
+
const datasetKeyL = datasetKey;
|
|
2273
|
+
const datasetKeyR = ((_a = this.renamedDatasetKeys) == null ? void 0 : _a.get(datasetKeyL)) || datasetKeyL;
|
|
2274
|
+
const outputVarL = modelSpecL.outputVars.get(datasetKeyL);
|
|
2275
|
+
const outputVarR = modelSpecR.outputVars.get(datasetKeyR);
|
|
2276
|
+
let varName;
|
|
2277
|
+
let newVarName;
|
|
2278
|
+
let sourceName;
|
|
2279
|
+
let newSourceName;
|
|
2280
|
+
if (outputVarL && outputVarR && outputVarL.varName != outputVarR.varName) {
|
|
2281
|
+
varName = outputVarL.varName;
|
|
2282
|
+
newVarName = outputVarR.varName;
|
|
2283
|
+
} else {
|
|
2284
|
+
const outputVar = outputVarR || outputVarL;
|
|
2285
|
+
varName = (outputVar == null ? void 0 : outputVar.varName) || "Unknown";
|
|
2286
|
+
}
|
|
2287
|
+
if (outputVarL && outputVarR && outputVarL.sourceName != outputVarR.sourceName) {
|
|
2288
|
+
sourceName = outputVarL.sourceName;
|
|
2289
|
+
newSourceName = outputVarR.sourceName;
|
|
2290
|
+
} else {
|
|
2291
|
+
const outputVar = outputVarR || outputVarL;
|
|
2292
|
+
sourceName = outputVar == null ? void 0 : outputVar.sourceName;
|
|
2293
|
+
}
|
|
2294
|
+
return {
|
|
2295
|
+
varName,
|
|
2296
|
+
newVarName,
|
|
2297
|
+
sourceName,
|
|
2298
|
+
newSourceName,
|
|
2299
|
+
relatedItems: (outputVarR == null ? void 0 : outputVarR.relatedItems) || []
|
|
2300
|
+
};
|
|
2301
|
+
}
|
|
2302
|
+
};
|
|
2303
|
+
|
|
2304
|
+
// src/config/scenario-manager.ts
|
|
2305
|
+
var import_assert_never8 = require("assert-never");
|
|
2306
|
+
var ScenarioManager = class {
|
|
2307
|
+
constructor(bundleL, bundleR) {
|
|
2308
|
+
this.bundleL = bundleL;
|
|
2309
|
+
this.bundleR = bundleR;
|
|
2310
|
+
this.scenarios = /* @__PURE__ */ new Map();
|
|
2311
|
+
this.scenarioInfo = /* @__PURE__ */ new Map();
|
|
2312
|
+
this.defaultInfoForGroup = /* @__PURE__ */ new Map();
|
|
2313
|
+
this.groupInfo = /* @__PURE__ */ new Map();
|
|
2314
|
+
}
|
|
2315
|
+
getScenarios() {
|
|
2316
|
+
return [...this.scenarios.values()];
|
|
2317
|
+
}
|
|
2318
|
+
getScenario(scenarioKey) {
|
|
2319
|
+
return this.scenarios.get(scenarioKey);
|
|
2320
|
+
}
|
|
2321
|
+
getScenarioGroupInfo(groupKey) {
|
|
2322
|
+
return this.groupInfo.get(groupKey);
|
|
2323
|
+
}
|
|
2324
|
+
getScenarioInfo(scenario, groupKey) {
|
|
2325
|
+
if (scenario.key === "all_inputs_at_default") {
|
|
2326
|
+
const defaultInfo = this.defaultInfoForGroup.get(groupKey);
|
|
2327
|
+
if (defaultInfo) {
|
|
2328
|
+
return defaultInfo;
|
|
2329
|
+
}
|
|
2330
|
+
}
|
|
2331
|
+
return this.scenarioInfo.get(scenario.key);
|
|
2332
|
+
}
|
|
2333
|
+
setDefaultScenarioInfoForGroup(groupKey, scenarioInfo) {
|
|
2334
|
+
this.defaultInfoForGroup.set(groupKey, scenarioInfo);
|
|
2335
|
+
}
|
|
2336
|
+
addScenario(scenario, scenarioInfo, groupInfo) {
|
|
2337
|
+
this.scenarios.set(scenario.key, scenario);
|
|
2338
|
+
if (!scenarioInfo) {
|
|
2339
|
+
scenarioInfo = this.getInfoForScenario(scenario);
|
|
2340
|
+
}
|
|
2341
|
+
this.scenarioInfo.set(scenario.key, scenarioInfo);
|
|
2342
|
+
if (!groupInfo) {
|
|
2343
|
+
groupInfo = this.getGroupInfoForScenario(scenario);
|
|
2344
|
+
}
|
|
2345
|
+
this.groupInfo.set(scenario.groupKey, groupInfo);
|
|
2346
|
+
}
|
|
2347
|
+
addScenarioMatrix() {
|
|
2348
|
+
const inputVarIdsL = Array.from(this.bundleL.modelSpec.inputVars.keys());
|
|
2349
|
+
const inputVarIdsR = Array.from(this.bundleR.modelSpec.inputVars.keys());
|
|
2350
|
+
const inputVarIds = /* @__PURE__ */ new Set([...inputVarIdsL, ...inputVarIdsR]);
|
|
2351
|
+
this.addScenario(allInputsAtPositionScenario("at-default"));
|
|
2352
|
+
this.addScenario(allInputsAtPositionScenario("at-minimum"));
|
|
2353
|
+
this.addScenario(allInputsAtPositionScenario("at-maximum"));
|
|
2354
|
+
for (const inputVarId of inputVarIds) {
|
|
2355
|
+
this.addScenario(inputAtPositionScenario(inputVarId, inputVarId, "at-minimum"));
|
|
2356
|
+
this.addScenario(inputAtPositionScenario(inputVarId, inputVarId, "at-maximum"));
|
|
2357
|
+
}
|
|
2358
|
+
}
|
|
2359
|
+
getGroupInfoForScenario(scenario) {
|
|
2360
|
+
switch (scenario.kind) {
|
|
2361
|
+
case "all-inputs":
|
|
2362
|
+
return {
|
|
2363
|
+
title: "All Inputs",
|
|
2364
|
+
relatedItems: []
|
|
2365
|
+
};
|
|
2366
|
+
case "settings":
|
|
2367
|
+
if (scenario.settings.length === 1) {
|
|
2368
|
+
const inputVar = this.getInputVarForSetting(scenario.settings[0]);
|
|
2369
|
+
let relatedItems;
|
|
2370
|
+
let subtitle;
|
|
2371
|
+
if (inputVar == null ? void 0 : inputVar.relatedItem) {
|
|
2372
|
+
relatedItems = [inputVar.relatedItem];
|
|
2373
|
+
subtitle = inputVar.relatedItem.locationPath.join(' <span class="related-sep">></span> ');
|
|
2374
|
+
} else {
|
|
2375
|
+
relatedItems = [];
|
|
2376
|
+
subtitle = void 0;
|
|
2377
|
+
}
|
|
2378
|
+
return {
|
|
2379
|
+
title: (inputVar == null ? void 0 : inputVar.varName) || "Unknown Input",
|
|
2380
|
+
subtitle,
|
|
2381
|
+
relatedItems
|
|
2382
|
+
};
|
|
2383
|
+
} else {
|
|
2384
|
+
return {
|
|
2385
|
+
title: "Multiple Inputs",
|
|
2386
|
+
relatedItems: this.getRelatedItemsForSettings(scenario.settings)
|
|
2387
|
+
};
|
|
2388
|
+
}
|
|
2389
|
+
default:
|
|
2390
|
+
(0, import_assert_never8.assertNever)(scenario);
|
|
2391
|
+
}
|
|
2392
|
+
}
|
|
2393
|
+
getInfoForScenario(scenario) {
|
|
2394
|
+
switch (scenario.kind) {
|
|
2395
|
+
case "all-inputs":
|
|
2396
|
+
return this.getInfoForPositionSetting(void 0, scenario.position);
|
|
2397
|
+
case "settings":
|
|
2398
|
+
if (scenario.settings.length === 1 && scenario.settings[0].kind === "position") {
|
|
2399
|
+
const setting = scenario.settings[0];
|
|
2400
|
+
return this.getInfoForPositionSetting(setting.inputVarId, setting.position);
|
|
2401
|
+
} else {
|
|
2402
|
+
return {
|
|
2403
|
+
title: `PLACEHOLDER (scenario info not provided)`,
|
|
2404
|
+
position: 1
|
|
2405
|
+
};
|
|
2406
|
+
}
|
|
2407
|
+
default:
|
|
2408
|
+
(0, import_assert_never8.assertNever)(scenario);
|
|
2409
|
+
}
|
|
2410
|
+
}
|
|
2411
|
+
getInfoForPositionSetting(inputVarId, inputPosition2) {
|
|
2412
|
+
const title = inputPosition2.replace("-", " ");
|
|
2413
|
+
let subtitle;
|
|
2414
|
+
if (inputVarId) {
|
|
2415
|
+
const inputVarL = this.bundleL.modelSpec.inputVars.get(inputVarId);
|
|
2416
|
+
const inputVarR = this.bundleR.modelSpec.inputVars.get(inputVarId);
|
|
2417
|
+
const valueL = inputValue(inputVarL, inputPosition2);
|
|
2418
|
+
const valueR = inputValue(inputVarR, inputPosition2);
|
|
2419
|
+
if (valueL !== valueR) {
|
|
2420
|
+
let values = "";
|
|
2421
|
+
values += "(";
|
|
2422
|
+
values += `<span class='dataset-color-0'>${valueL}</span>`;
|
|
2423
|
+
values += " | ";
|
|
2424
|
+
values += `<span class='dataset-color-1'>${valueR}</span>`;
|
|
2425
|
+
values += ")";
|
|
2426
|
+
subtitle = values;
|
|
2427
|
+
} else {
|
|
2428
|
+
subtitle = `(${valueL})`;
|
|
2429
|
+
}
|
|
2430
|
+
} else {
|
|
2431
|
+
subtitle = void 0;
|
|
2432
|
+
}
|
|
2433
|
+
let position;
|
|
2434
|
+
switch (inputPosition2) {
|
|
2435
|
+
case "at-default":
|
|
2436
|
+
position = 0;
|
|
2437
|
+
break;
|
|
2438
|
+
case "at-minimum":
|
|
2439
|
+
position = 1;
|
|
2440
|
+
break;
|
|
2441
|
+
case "at-maximum":
|
|
2442
|
+
position = 2;
|
|
2443
|
+
break;
|
|
2444
|
+
default:
|
|
2445
|
+
(0, import_assert_never8.assertNever)(inputPosition2);
|
|
2446
|
+
}
|
|
2447
|
+
return {
|
|
2448
|
+
title,
|
|
2449
|
+
subtitle,
|
|
2450
|
+
position
|
|
2451
|
+
};
|
|
2452
|
+
}
|
|
2453
|
+
getRelatedItemsForSettings(settings) {
|
|
2454
|
+
const relatedItems = [];
|
|
2455
|
+
for (const setting of settings) {
|
|
2456
|
+
const inputVar = this.getInputVarForSetting(setting);
|
|
2457
|
+
if (inputVar == null ? void 0 : inputVar.relatedItem) {
|
|
2458
|
+
relatedItems.push(inputVar.relatedItem);
|
|
2459
|
+
}
|
|
2460
|
+
}
|
|
2461
|
+
return relatedItems;
|
|
2462
|
+
}
|
|
2463
|
+
getInputVarForSetting(setting) {
|
|
2464
|
+
const inputVarId = setting.inputVarId;
|
|
2465
|
+
const inputVarL = this.bundleL.modelSpec.inputVars.get(inputVarId);
|
|
2466
|
+
const inputVarR = this.bundleR.modelSpec.inputVars.get(inputVarId);
|
|
2467
|
+
return inputVarR || inputVarL;
|
|
2468
|
+
}
|
|
2469
|
+
};
|
|
2470
|
+
function inputValue(inputVar, position) {
|
|
2471
|
+
if (inputVar) {
|
|
2472
|
+
switch (position) {
|
|
2473
|
+
case "at-default":
|
|
2474
|
+
return inputVar.defaultValue.toString();
|
|
2475
|
+
case "at-minimum":
|
|
2476
|
+
return inputVar.minValue.toString();
|
|
2477
|
+
case "at-maximum":
|
|
2478
|
+
return inputVar.maxValue.toString();
|
|
2479
|
+
default:
|
|
2480
|
+
(0, import_assert_never8.assertNever)(position);
|
|
2481
|
+
}
|
|
2482
|
+
} else {
|
|
2483
|
+
return "n/a";
|
|
2484
|
+
}
|
|
2485
|
+
}
|
|
2486
|
+
|
|
2487
|
+
// src/perf/perf-runner.ts
|
|
2488
|
+
var import_assert_never9 = require("assert-never");
|
|
2489
|
+
|
|
2490
|
+
// src/perf/perf-stats.ts
|
|
2491
|
+
var PerfStats = class {
|
|
2492
|
+
constructor() {
|
|
2493
|
+
this.times = [];
|
|
2494
|
+
}
|
|
2495
|
+
addRun(timeInMillis) {
|
|
2496
|
+
this.times.push(timeInMillis);
|
|
2497
|
+
}
|
|
2498
|
+
toReport() {
|
|
2499
|
+
if (this.times.length === 0) {
|
|
2500
|
+
return {
|
|
2501
|
+
minTime: 0,
|
|
2502
|
+
maxTime: 0,
|
|
2503
|
+
avgTime: 0,
|
|
2504
|
+
allTimes: []
|
|
2505
|
+
};
|
|
2506
|
+
}
|
|
2507
|
+
const minTime = Math.min(...this.times);
|
|
2508
|
+
const maxTime = Math.max(...this.times);
|
|
2509
|
+
const sortedTimes = this.times.sort();
|
|
2510
|
+
const minIndex = Math.floor(sortedTimes.length / 4);
|
|
2511
|
+
const maxIndex = minIndex + Math.ceil(sortedTimes.length / 2);
|
|
2512
|
+
const middleTimes = sortedTimes.slice(minIndex, maxIndex);
|
|
2513
|
+
const totalTime = middleTimes.reduce((a, b) => a + b, 0);
|
|
2514
|
+
const avgTime = totalTime / middleTimes.length;
|
|
2515
|
+
return {
|
|
2516
|
+
minTime,
|
|
2517
|
+
maxTime,
|
|
2518
|
+
avgTime,
|
|
2519
|
+
allTimes: sortedTimes
|
|
2520
|
+
};
|
|
2521
|
+
}
|
|
2522
|
+
};
|
|
2523
|
+
|
|
2524
|
+
// src/perf/perf-runner.ts
|
|
2525
|
+
var warmupCount = 5;
|
|
2526
|
+
var runCount = 100;
|
|
2527
|
+
var PerfRunner = class {
|
|
2528
|
+
constructor(bundleModelL, bundleModelR, mode = "serial") {
|
|
2529
|
+
this.bundleModelL = bundleModelL;
|
|
2530
|
+
this.bundleModelR = bundleModelR;
|
|
2531
|
+
this.mode = mode;
|
|
2532
|
+
const scenario = allInputsAtPositionScenario("at-default");
|
|
2533
|
+
this.taskQueue = new TaskQueue({
|
|
2534
|
+
process: async (request) => {
|
|
2535
|
+
switch (request.kind) {
|
|
2536
|
+
case "left": {
|
|
2537
|
+
const result = await bundleModelL.getDatasetsForScenario(scenario, []);
|
|
2538
|
+
return {
|
|
2539
|
+
runTimeL: result.modelRunTime
|
|
2540
|
+
};
|
|
2541
|
+
}
|
|
2542
|
+
case "right": {
|
|
2543
|
+
const result = await bundleModelR.getDatasetsForScenario(scenario, []);
|
|
2544
|
+
return {
|
|
2545
|
+
runTimeR: result.modelRunTime
|
|
2546
|
+
};
|
|
2547
|
+
}
|
|
2548
|
+
case "both": {
|
|
2549
|
+
const [resultL, resultR] = await Promise.all([
|
|
2550
|
+
bundleModelL.getDatasetsForScenario(scenario, []),
|
|
2551
|
+
bundleModelR.getDatasetsForScenario(scenario, [])
|
|
2552
|
+
]);
|
|
2553
|
+
return {
|
|
2554
|
+
runTimeL: resultL.modelRunTime,
|
|
2555
|
+
runTimeR: resultR.modelRunTime
|
|
2556
|
+
};
|
|
2557
|
+
}
|
|
2558
|
+
default:
|
|
2559
|
+
(0, import_assert_never9.assertNever)(request.kind);
|
|
2560
|
+
}
|
|
2561
|
+
}
|
|
2562
|
+
});
|
|
2563
|
+
}
|
|
2564
|
+
start() {
|
|
2565
|
+
const statsL = new PerfStats();
|
|
2566
|
+
const statsR = new PerfStats();
|
|
2567
|
+
this.taskQueue.onIdle = (error) => {
|
|
2568
|
+
var _a;
|
|
2569
|
+
if (error) {
|
|
2570
|
+
this.onError(error);
|
|
2571
|
+
} else {
|
|
2572
|
+
(_a = this.onComplete) == null ? void 0 : _a.call(this, statsL.toReport(), statsR.toReport());
|
|
2573
|
+
}
|
|
2574
|
+
};
|
|
2575
|
+
const taskQueue = this.taskQueue;
|
|
2576
|
+
function addTask(index, warmup, kind) {
|
|
2577
|
+
const key = `${warmup ? "warmup-" : ""}${kind}-${index}`;
|
|
2578
|
+
const request = {
|
|
2579
|
+
kind
|
|
2580
|
+
};
|
|
2581
|
+
taskQueue.addTask(key, request, (response) => {
|
|
2582
|
+
if (!warmup && response.runTimeL !== void 0) {
|
|
2583
|
+
statsL.addRun(response.runTimeL);
|
|
2584
|
+
}
|
|
2585
|
+
if (!warmup && response.runTimeR !== void 0) {
|
|
2586
|
+
statsR.addRun(response.runTimeR);
|
|
2587
|
+
}
|
|
2588
|
+
});
|
|
2589
|
+
}
|
|
2590
|
+
function addTasks(kind) {
|
|
2591
|
+
for (let i = 0; i < warmupCount; i++) {
|
|
2592
|
+
addTask(i, true, kind);
|
|
2593
|
+
}
|
|
2594
|
+
for (let i = 0; i < runCount; i++) {
|
|
2595
|
+
addTask(i, false, kind);
|
|
2596
|
+
}
|
|
2597
|
+
}
|
|
2598
|
+
if (this.mode === "parallel") {
|
|
2599
|
+
addTasks("both");
|
|
2600
|
+
} else {
|
|
2601
|
+
addTasks("left");
|
|
2602
|
+
addTasks("right");
|
|
2603
|
+
}
|
|
2604
|
+
}
|
|
2605
|
+
};
|
|
2606
|
+
|
|
2607
|
+
// src/suite/suite-runner.ts
|
|
2608
|
+
var import_assert_never10 = __toESM(require("assert-never"), 1);
|
|
2609
|
+
|
|
2610
|
+
// src/data/data-planner.ts
|
|
2611
|
+
var ScenarioTaskSet = class {
|
|
2612
|
+
constructor(scenario) {
|
|
2613
|
+
this.scenario = scenario;
|
|
2614
|
+
this.modelTasks = /* @__PURE__ */ new Map();
|
|
2615
|
+
this.modelImplTasks = /* @__PURE__ */ new Map();
|
|
2616
|
+
this.requestKind = "check";
|
|
2617
|
+
}
|
|
2618
|
+
addTask(kind, datasetKey, dataFunc) {
|
|
2619
|
+
if (kind === "compare") {
|
|
2620
|
+
this.requestKind = "compare";
|
|
2621
|
+
}
|
|
2622
|
+
const dataTask = {
|
|
2623
|
+
datasetKey,
|
|
2624
|
+
dataFunc
|
|
2625
|
+
};
|
|
2626
|
+
let taskMap;
|
|
2627
|
+
if (datasetKey.startsWith("ModelImpl")) {
|
|
2628
|
+
taskMap = this.modelImplTasks;
|
|
2629
|
+
} else {
|
|
2630
|
+
taskMap = this.modelTasks;
|
|
2631
|
+
}
|
|
2632
|
+
let tasks = taskMap.get(datasetKey);
|
|
2633
|
+
if (!tasks) {
|
|
2634
|
+
tasks = [];
|
|
2635
|
+
taskMap.set(datasetKey, tasks);
|
|
2636
|
+
}
|
|
2637
|
+
tasks.push(dataTask);
|
|
2638
|
+
}
|
|
2639
|
+
buildRequests(batchSize) {
|
|
2640
|
+
const dataRequests = [];
|
|
2641
|
+
if (this.modelTasks.size > 0) {
|
|
2642
|
+
const dataTasks = [];
|
|
2643
|
+
this.modelTasks.forEach((tasks) => dataTasks.push(...tasks));
|
|
2644
|
+
dataRequests.push({
|
|
2645
|
+
kind: this.requestKind,
|
|
2646
|
+
scenario: this.scenario,
|
|
2647
|
+
dataTasks
|
|
2648
|
+
});
|
|
2649
|
+
}
|
|
2650
|
+
if (this.modelImplTasks.size > 0) {
|
|
2651
|
+
const allKeys = [...this.modelImplTasks.keys()];
|
|
2652
|
+
for (let i = 0; i < allKeys.length; i += batchSize) {
|
|
2653
|
+
const batchKeys = allKeys.slice(i, i + batchSize);
|
|
2654
|
+
const dataTasks = [];
|
|
2655
|
+
for (const datasetKey of batchKeys) {
|
|
2656
|
+
dataTasks.push(...this.modelImplTasks.get(datasetKey));
|
|
2657
|
+
}
|
|
2658
|
+
dataRequests.push({
|
|
2659
|
+
kind: this.requestKind,
|
|
2660
|
+
scenario: this.scenario,
|
|
2661
|
+
dataTasks
|
|
2662
|
+
});
|
|
2663
|
+
}
|
|
2664
|
+
}
|
|
2665
|
+
return dataRequests;
|
|
2666
|
+
}
|
|
2667
|
+
};
|
|
2668
|
+
var DataPlanner = class {
|
|
2669
|
+
constructor(batchSize) {
|
|
2670
|
+
this.batchSize = batchSize;
|
|
2671
|
+
this.scenarioTaskSets = /* @__PURE__ */ new Map();
|
|
2672
|
+
}
|
|
2673
|
+
addRequest(kind, scenario, datasetKey, dataFunc) {
|
|
2674
|
+
let scenarioTaskSet = this.scenarioTaskSets.get(scenario.key);
|
|
2675
|
+
if (!scenarioTaskSet) {
|
|
2676
|
+
scenarioTaskSet = new ScenarioTaskSet(scenario);
|
|
2677
|
+
this.scenarioTaskSets.set(scenario.key, scenarioTaskSet);
|
|
2678
|
+
}
|
|
2679
|
+
scenarioTaskSet.addTask(kind, datasetKey, dataFunc);
|
|
2680
|
+
}
|
|
2681
|
+
buildPlan() {
|
|
2682
|
+
const requests = [];
|
|
2683
|
+
for (const taskSet of this.scenarioTaskSets.values()) {
|
|
2684
|
+
requests.push(...taskSet.buildRequests(this.batchSize));
|
|
2685
|
+
}
|
|
2686
|
+
return {
|
|
2687
|
+
requests
|
|
2688
|
+
};
|
|
2689
|
+
}
|
|
2690
|
+
};
|
|
2691
|
+
|
|
2692
|
+
// src/check/check-runner.ts
|
|
2693
|
+
function runChecks(checkConfig, checkSpec, dataPlanner, refDataPlanner, simplifyScenarios) {
|
|
2694
|
+
const modelSpec = checkConfig.bundle.model.modelSpec;
|
|
2695
|
+
const checkPlanner = new CheckPlanner(modelSpec);
|
|
2696
|
+
checkPlanner.addAllChecks(checkSpec, simplifyScenarios);
|
|
2697
|
+
const checkPlan = checkPlanner.buildPlan();
|
|
2698
|
+
const refDatasets = /* @__PURE__ */ new Map();
|
|
2699
|
+
for (const [dataRefKey, dataRef] of checkPlan.dataRefs.entries()) {
|
|
2700
|
+
refDataPlanner.addRequest("check", dataRef.scenario.scenario, dataRef.dataset.datasetKey, (datasets) => {
|
|
2701
|
+
const dataset = datasets.datasetR;
|
|
2702
|
+
if (dataset) {
|
|
2703
|
+
refDatasets.set(dataRefKey, dataset);
|
|
2704
|
+
}
|
|
2705
|
+
});
|
|
2706
|
+
}
|
|
2707
|
+
const checkResults = /* @__PURE__ */ new Map();
|
|
2708
|
+
for (const [checkKey, checkTask] of checkPlan.tasks.entries()) {
|
|
2709
|
+
dataPlanner.addRequest("check", checkTask.scenario.scenario, checkTask.dataset.datasetKey, (datasets) => {
|
|
2710
|
+
const dataset = datasets.datasetR;
|
|
2711
|
+
const checkResult = runCheck(checkTask, dataset, refDatasets);
|
|
2712
|
+
checkResults.set(checkKey, checkResult);
|
|
2713
|
+
});
|
|
2714
|
+
}
|
|
2715
|
+
return () => {
|
|
2716
|
+
return buildCheckReport(checkPlan, checkResults);
|
|
2717
|
+
};
|
|
2718
|
+
}
|
|
2719
|
+
function runCheck(checkTask, dataset, refDatasets) {
|
|
2720
|
+
if (dataset === void 0) {
|
|
2721
|
+
return {
|
|
2722
|
+
status: "error",
|
|
2723
|
+
message: "no data available"
|
|
2724
|
+
};
|
|
2725
|
+
}
|
|
2726
|
+
let opRefDatasets;
|
|
2727
|
+
if (checkTask.dataRefs) {
|
|
2728
|
+
opRefDatasets = /* @__PURE__ */ new Map();
|
|
2729
|
+
for (const [op, dataRef] of checkTask.dataRefs.entries()) {
|
|
2730
|
+
const refDataset = refDatasets == null ? void 0 : refDatasets.get(dataRef.key);
|
|
2731
|
+
if (refDataset === void 0) {
|
|
2732
|
+
if (dataRef.dataset.datasetKey === void 0) {
|
|
2733
|
+
return {
|
|
2734
|
+
status: "error",
|
|
2735
|
+
errorInfo: {
|
|
2736
|
+
kind: "unknown-dataset",
|
|
2737
|
+
name: dataRef.dataset.name
|
|
2738
|
+
}
|
|
2739
|
+
};
|
|
2740
|
+
} else if (dataRef.scenario.scenario === void 0) {
|
|
2741
|
+
if (dataRef.scenario.error) {
|
|
2742
|
+
return {
|
|
2743
|
+
status: "error",
|
|
2744
|
+
errorInfo: {
|
|
2745
|
+
kind: dataRef.scenario.error.kind,
|
|
2746
|
+
name: dataRef.scenario.error.name
|
|
2747
|
+
}
|
|
2748
|
+
};
|
|
2749
|
+
} else {
|
|
2750
|
+
let inputName;
|
|
2751
|
+
if (dataRef.scenario.inputDescs.length > 0) {
|
|
2752
|
+
inputName = dataRef.scenario.inputDescs[0].name;
|
|
2753
|
+
} else {
|
|
2754
|
+
inputName = "unknown";
|
|
2755
|
+
}
|
|
2756
|
+
return {
|
|
2757
|
+
status: "error",
|
|
2758
|
+
errorInfo: {
|
|
2759
|
+
kind: "unknown-input",
|
|
2760
|
+
name: inputName
|
|
2761
|
+
}
|
|
2762
|
+
};
|
|
2763
|
+
}
|
|
2764
|
+
} else {
|
|
2765
|
+
return {
|
|
2766
|
+
status: "error",
|
|
2767
|
+
message: "unresolved data reference"
|
|
2768
|
+
};
|
|
2769
|
+
}
|
|
2770
|
+
}
|
|
2771
|
+
opRefDatasets.set(op, refDataset);
|
|
2772
|
+
}
|
|
2773
|
+
}
|
|
2774
|
+
return checkTask.action.run(dataset, opRefDatasets);
|
|
2775
|
+
}
|
|
2776
|
+
|
|
2777
|
+
// src/compare/compare-runner.ts
|
|
2778
|
+
function runCompare(compareConfig, dataPlanner, simplifyScenarios) {
|
|
2779
|
+
const scenarios = simplifyScenarios ? [allInputsAtPositionScenario("at-default")] : compareConfig.scenarios.getScenarios();
|
|
2780
|
+
const datasetReports = [];
|
|
2781
|
+
for (const scenario of scenarios) {
|
|
2782
|
+
const datasetKeys = compareConfig.datasets.getDatasetKeysForScenario(scenario);
|
|
2783
|
+
for (const datasetKey of datasetKeys) {
|
|
2784
|
+
dataPlanner.addRequest("compare", scenario, datasetKey, (datasets) => {
|
|
2785
|
+
const diffReport = diffDatasets(datasets.datasetL, datasets.datasetR);
|
|
2786
|
+
datasetReports.push({
|
|
2787
|
+
scenarioKey: scenario.key,
|
|
2788
|
+
datasetKey,
|
|
2789
|
+
diffReport
|
|
2790
|
+
});
|
|
2791
|
+
});
|
|
2792
|
+
}
|
|
2793
|
+
}
|
|
2794
|
+
return () => {
|
|
2795
|
+
return datasetReports;
|
|
2796
|
+
};
|
|
2797
|
+
}
|
|
2798
|
+
|
|
2799
|
+
// src/suite/suite-runner.ts
|
|
2800
|
+
var SuiteRunner = class {
|
|
2801
|
+
constructor(config, callbacks) {
|
|
2802
|
+
this.config = config;
|
|
2803
|
+
this.callbacks = callbacks;
|
|
2804
|
+
this.perfStatsL = new PerfStats();
|
|
2805
|
+
this.perfStatsR = new PerfStats();
|
|
2806
|
+
this.stopped = false;
|
|
2807
|
+
this.taskQueue = new TaskQueue({
|
|
2808
|
+
process: (request) => {
|
|
2809
|
+
return this.processRequest(request);
|
|
2810
|
+
}
|
|
2811
|
+
});
|
|
2812
|
+
}
|
|
2813
|
+
cancel() {
|
|
2814
|
+
if (!this.stopped) {
|
|
2815
|
+
this.stopped = true;
|
|
2816
|
+
this.taskQueue.shutdown();
|
|
2817
|
+
}
|
|
2818
|
+
}
|
|
2819
|
+
start(options) {
|
|
2820
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
2821
|
+
(_b = (_a = this.callbacks).onProgress) == null ? void 0 : _b.call(_a, 0);
|
|
2822
|
+
const modelSpec = this.config.check.bundle.model.modelSpec;
|
|
2823
|
+
const dataPlanner = new DataPlanner(modelSpec.outputVars.size);
|
|
2824
|
+
const refDataPlanner = new DataPlanner(modelSpec.outputVars.size);
|
|
2825
|
+
const checkSpecResult = parseTestYaml(this.config.check.tests);
|
|
2826
|
+
if (checkSpecResult.isErr()) {
|
|
2827
|
+
(_d = (_c = this.callbacks).onError) == null ? void 0 : _d.call(_c, checkSpecResult.error);
|
|
2828
|
+
return;
|
|
2829
|
+
}
|
|
2830
|
+
const checkSpec = checkSpecResult.value;
|
|
2831
|
+
const simplifyScenarios = (options == null ? void 0 : options.simplifyScenarios) === true;
|
|
2832
|
+
const buildCheckReport2 = runChecks(this.config.check, checkSpec, dataPlanner, refDataPlanner, simplifyScenarios);
|
|
2833
|
+
let buildCompareDatasetReports;
|
|
2834
|
+
if (this.config.compare) {
|
|
2835
|
+
buildCompareDatasetReports = runCompare(this.config.compare, dataPlanner, simplifyScenarios);
|
|
2836
|
+
}
|
|
2837
|
+
this.taskQueue.onIdle = (error) => {
|
|
2838
|
+
var _a2, _b2, _c2, _d2;
|
|
2839
|
+
if (this.stopped) {
|
|
2840
|
+
return;
|
|
2841
|
+
}
|
|
2842
|
+
if (error) {
|
|
2843
|
+
(_b2 = (_a2 = this.callbacks).onError) == null ? void 0 : _b2.call(_a2, error);
|
|
2844
|
+
} else {
|
|
2845
|
+
const checkReport = buildCheckReport2();
|
|
2846
|
+
let compareReport;
|
|
2847
|
+
if (this.config.compare) {
|
|
2848
|
+
compareReport = {
|
|
2849
|
+
datasetReports: buildCompareDatasetReports(),
|
|
2850
|
+
perfReportL: this.perfStatsL.toReport(),
|
|
2851
|
+
perfReportR: this.perfStatsR.toReport()
|
|
2852
|
+
};
|
|
2853
|
+
}
|
|
2854
|
+
(_d2 = (_c2 = this.callbacks).onComplete) == null ? void 0 : _d2.call(_c2, {
|
|
2855
|
+
checkReport,
|
|
2856
|
+
compareReport
|
|
2857
|
+
});
|
|
2858
|
+
}
|
|
2859
|
+
};
|
|
2860
|
+
const refDataPlan = refDataPlanner.buildPlan();
|
|
2861
|
+
const dataPlan = dataPlanner.buildPlan();
|
|
2862
|
+
const dataRequests = [...refDataPlan.requests, ...dataPlan.requests];
|
|
2863
|
+
const taskCount = dataRequests.length;
|
|
2864
|
+
if (taskCount === 0) {
|
|
2865
|
+
let compareReport;
|
|
2866
|
+
if (this.config.compare) {
|
|
2867
|
+
compareReport = {
|
|
2868
|
+
datasetReports: [],
|
|
2869
|
+
perfReportL: this.perfStatsL.toReport(),
|
|
2870
|
+
perfReportR: this.perfStatsR.toReport()
|
|
2871
|
+
};
|
|
2872
|
+
}
|
|
2873
|
+
this.cancel();
|
|
2874
|
+
(_f = (_e = this.callbacks).onProgress) == null ? void 0 : _f.call(_e, 1);
|
|
2875
|
+
(_h = (_g = this.callbacks).onComplete) == null ? void 0 : _h.call(_g, {
|
|
2876
|
+
checkReport: {
|
|
2877
|
+
groups: []
|
|
2878
|
+
},
|
|
2879
|
+
compareReport
|
|
2880
|
+
});
|
|
2881
|
+
return;
|
|
2882
|
+
}
|
|
2883
|
+
let tasksCompleted = 0;
|
|
2884
|
+
let dataTaskId = 1;
|
|
2885
|
+
for (const dataRequest of dataRequests) {
|
|
2886
|
+
this.taskQueue.addTask(`data${dataTaskId++}`, dataRequest, () => {
|
|
2887
|
+
var _a2, _b2;
|
|
2888
|
+
tasksCompleted++;
|
|
2889
|
+
(_b2 = (_a2 = this.callbacks).onProgress) == null ? void 0 : _b2.call(_a2, tasksCompleted / taskCount);
|
|
2890
|
+
});
|
|
2891
|
+
}
|
|
2892
|
+
}
|
|
2893
|
+
async processRequest(request) {
|
|
2894
|
+
const datasetKeySet = /* @__PURE__ */ new Set();
|
|
2895
|
+
for (const dataTask of request.dataTasks) {
|
|
2896
|
+
datasetKeySet.add(dataTask.datasetKey);
|
|
2897
|
+
}
|
|
2898
|
+
const datasetKeys = [...datasetKeySet];
|
|
2899
|
+
const scenario = request.scenario;
|
|
2900
|
+
let datasetsResultL;
|
|
2901
|
+
let datasetsResultR;
|
|
2902
|
+
switch (request.kind) {
|
|
2903
|
+
case "check": {
|
|
2904
|
+
const bundleModel = this.config.check.bundle.model;
|
|
2905
|
+
datasetsResultR = await bundleModel.getDatasetsForScenario(scenario, datasetKeys);
|
|
2906
|
+
break;
|
|
2907
|
+
}
|
|
2908
|
+
case "compare": {
|
|
2909
|
+
const bundleModelL = this.config.compare.bundleL.model;
|
|
2910
|
+
const bundleModelR = this.config.compare.bundleR.model;
|
|
2911
|
+
const [resultL, resultR] = await Promise.all([
|
|
2912
|
+
bundleModelL.getDatasetsForScenario(scenario, datasetKeys),
|
|
2913
|
+
bundleModelR.getDatasetsForScenario(scenario, datasetKeys)
|
|
2914
|
+
]);
|
|
2915
|
+
datasetsResultL = resultL;
|
|
2916
|
+
datasetsResultR = resultR;
|
|
2917
|
+
break;
|
|
2918
|
+
}
|
|
2919
|
+
default:
|
|
2920
|
+
(0, import_assert_never10.default)(request.kind);
|
|
2921
|
+
}
|
|
2922
|
+
if (datasetsResultL == null ? void 0 : datasetsResultL.modelRunTime) {
|
|
2923
|
+
this.perfStatsL.addRun(datasetsResultL == null ? void 0 : datasetsResultL.modelRunTime);
|
|
2924
|
+
}
|
|
2925
|
+
if (datasetsResultR == null ? void 0 : datasetsResultR.modelRunTime) {
|
|
2926
|
+
this.perfStatsR.addRun(datasetsResultR == null ? void 0 : datasetsResultR.modelRunTime);
|
|
2927
|
+
}
|
|
2928
|
+
const datasetMapL = datasetsResultL == null ? void 0 : datasetsResultL.datasetMap;
|
|
2929
|
+
const datasetMapR = datasetsResultR == null ? void 0 : datasetsResultR.datasetMap;
|
|
2930
|
+
for (const dataTask of request.dataTasks) {
|
|
2931
|
+
const datasetL = datasetMapL == null ? void 0 : datasetMapL.get(dataTask.datasetKey);
|
|
2932
|
+
const datasetR = datasetMapR == null ? void 0 : datasetMapR.get(dataTask.datasetKey);
|
|
2933
|
+
dataTask.dataFunc({
|
|
2934
|
+
datasetL,
|
|
2935
|
+
datasetR
|
|
2936
|
+
});
|
|
2937
|
+
}
|
|
2938
|
+
}
|
|
2939
|
+
};
|
|
2940
|
+
function runSuite(config, callbacks, options) {
|
|
2941
|
+
const suiteRunner = new SuiteRunner(config, callbacks);
|
|
2942
|
+
suiteRunner.start(options);
|
|
2943
|
+
return () => {
|
|
2944
|
+
suiteRunner.cancel();
|
|
2945
|
+
};
|
|
2946
|
+
}
|
|
2947
|
+
|
|
2948
|
+
// src/suite/suite-summary.ts
|
|
2949
|
+
function suiteSummaryFromReport(suiteReport) {
|
|
2950
|
+
const checkSummary = checkSummaryFromReport(suiteReport.checkReport);
|
|
2951
|
+
let compareSummary;
|
|
2952
|
+
if (suiteReport.compareReport) {
|
|
2953
|
+
compareSummary = compareSummaryFromReport(suiteReport.compareReport);
|
|
2954
|
+
}
|
|
2955
|
+
return {
|
|
2956
|
+
checkSummary,
|
|
2957
|
+
compareSummary
|
|
2958
|
+
};
|
|
2959
|
+
}
|
|
2960
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
2961
|
+
0 && (module.exports = {
|
|
2962
|
+
CheckDataCoordinator,
|
|
2963
|
+
CompareDataCoordinator,
|
|
2964
|
+
DatasetManager,
|
|
2965
|
+
PerfRunner,
|
|
2966
|
+
PerfStats,
|
|
2967
|
+
ScenarioManager,
|
|
2968
|
+
allInputsAtPositionScenario,
|
|
2969
|
+
checkReportFromSummary,
|
|
2970
|
+
checkSummaryFromReport,
|
|
2971
|
+
compareDatasets,
|
|
2972
|
+
compareSummaryFromReport,
|
|
2973
|
+
createConfig,
|
|
2974
|
+
datasetMessage,
|
|
2975
|
+
diffDatasets,
|
|
2976
|
+
diffGraphs,
|
|
2977
|
+
inputAtPositionScenario,
|
|
2978
|
+
inputAtValueScenario,
|
|
2979
|
+
matrixScenarios,
|
|
2980
|
+
positionSetting,
|
|
2981
|
+
predicateMessage,
|
|
2982
|
+
runSuite,
|
|
2983
|
+
scenarioMessage,
|
|
2984
|
+
settingsScenario,
|
|
2985
|
+
suiteSummaryFromReport,
|
|
2986
|
+
valueSetting
|
|
2987
|
+
});
|
|
2988
|
+
//# sourceMappingURL=index.cjs.map
|