@sdeverywhere/plugin-check 0.3.0 → 0.3.2
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/README.md +24 -3
- package/dist/index.cjs +226 -57
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +30 -0
- package/dist/index.js +221 -56
- package/dist/index.js.map +1 -1
- package/package.json +8 -7
- package/template-bundle/src/bundle.ts +3 -5
- package/template-bundle/src/inputs.ts +14 -4
- package/template-bundle/tsconfig.json +1 -1
- package/template-report/index.html +1 -1
- package/template-report/src/empty-test-config.ts +2 -7
- package/template-report/src/env.d.ts +0 -1
- package/template-report/src/index.ts +47 -26
- package/template-report/tsconfig.json +1 -1
- package/template-tests/src/index.ts +107 -27
- package/template-tests/tsconfig.json +1 -1
- package/template-tests/src/env.d.ts +0 -5
|
@@ -1,11 +1,22 @@
|
|
|
1
1
|
// Copyright (c) 2022 Climate Interactive / New Venture Fund
|
|
2
2
|
|
|
3
|
-
import type {
|
|
3
|
+
import type {
|
|
4
|
+
Bundle,
|
|
5
|
+
ComparisonOptions,
|
|
6
|
+
ComparisonScenarioSpec,
|
|
7
|
+
ComparisonSpecs,
|
|
8
|
+
ConfigInitOptions,
|
|
9
|
+
ConfigOptions,
|
|
10
|
+
DatasetKey,
|
|
11
|
+
InputId,
|
|
12
|
+
InputVar
|
|
13
|
+
} from '@sdeverywhere/check-core'
|
|
4
14
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
//
|
|
8
|
-
|
|
15
|
+
// Load the yaml test files. The `./__YAML_PATH__` part will be replaced by Vite
|
|
16
|
+
// (see `vite-config-for-tests.ts`). Note that we provide a placeholder here that
|
|
17
|
+
// looks like a valid glob pattern, since Vite's dependency resolver will report
|
|
18
|
+
// errors if it is invalid (not a literal).
|
|
19
|
+
const yamlGlob = import.meta.glob('./__YAML_PATH__', {
|
|
9
20
|
eager: true,
|
|
10
21
|
as: 'raw'
|
|
11
22
|
})
|
|
@@ -24,56 +35,125 @@ const renamedDatasetKeys: Map<DatasetKey, DatasetKey> = new Map([
|
|
|
24
35
|
// ['Model_old_name', 'Model_new_name']
|
|
25
36
|
])
|
|
26
37
|
|
|
27
|
-
export interface BundleOptions {
|
|
28
|
-
nameL?: string
|
|
29
|
-
nameR?: string
|
|
30
|
-
}
|
|
31
|
-
|
|
32
38
|
// TODO: Make this pluggable (with default implementation similar to below)
|
|
33
39
|
export async function getConfigOptions(
|
|
34
40
|
bundleL: Bundle | undefined,
|
|
35
41
|
bundleR: Bundle,
|
|
36
|
-
opts
|
|
42
|
+
opts?: ConfigInitOptions
|
|
37
43
|
): Promise<ConfigOptions> {
|
|
38
|
-
// Only include
|
|
44
|
+
// Only include comparison options if the baseline bundle is defined (and
|
|
39
45
|
// has the same version)
|
|
40
|
-
let
|
|
46
|
+
let comparisonOptions: ComparisonOptions
|
|
41
47
|
if (bundleL && bundleL.version === bundleR.version) {
|
|
42
48
|
// Configure the set of input scenarios used for comparisons. This includes
|
|
43
49
|
// the default matrix of scenarios; for any output variable, the model will
|
|
44
50
|
// be run:
|
|
45
51
|
// - once with all inputs at their default
|
|
46
|
-
// - once with all inputs at their minimum
|
|
47
|
-
// - once with all inputs at their maximum
|
|
48
52
|
// - twice for each input
|
|
49
53
|
// - once with single input at its minimum
|
|
50
54
|
// - once with single input at its maximum
|
|
51
|
-
|
|
52
|
-
|
|
55
|
+
// TODO: Also read specs from comparison yaml files
|
|
56
|
+
const baseComparisonSpecs = createBaseComparisonSpecs(bundleL, bundleR)
|
|
53
57
|
|
|
54
|
-
|
|
55
|
-
// in the given bundles) that can be used to compare two versions of the model
|
|
56
|
-
const datasets = new DatasetManager(bundleL, bundleR, renamedDatasetKeys)
|
|
57
|
-
|
|
58
|
-
compareOptions = {
|
|
58
|
+
comparisonOptions = {
|
|
59
59
|
baseline: {
|
|
60
|
-
name: opts?.
|
|
60
|
+
name: opts?.bundleNameL || 'baseline',
|
|
61
61
|
bundle: bundleL
|
|
62
62
|
},
|
|
63
63
|
thresholds: [1, 5, 10],
|
|
64
|
-
|
|
65
|
-
datasets
|
|
64
|
+
specs: [baseComparisonSpecs],
|
|
65
|
+
datasets: {
|
|
66
|
+
renamedDatasetKeys
|
|
67
|
+
}
|
|
66
68
|
}
|
|
67
69
|
}
|
|
68
70
|
|
|
69
71
|
return {
|
|
70
72
|
current: {
|
|
71
|
-
name: opts?.
|
|
73
|
+
name: opts?.bundleNameR || 'current',
|
|
72
74
|
bundle: bundleR
|
|
73
75
|
},
|
|
74
76
|
check: {
|
|
75
77
|
tests
|
|
76
78
|
},
|
|
77
|
-
|
|
79
|
+
comparison: comparisonOptions
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function createBaseComparisonSpecs(bundleL: Bundle, bundleR: Bundle): ComparisonSpecs {
|
|
84
|
+
// Get the union of all input IDs appearing in left and/or right
|
|
85
|
+
const allInputIds: Set<InputId> = new Set()
|
|
86
|
+
const addInputs = (bundle: Bundle, inputsMap: Map<InputId, InputVar>) => {
|
|
87
|
+
for (const inputVar of bundle.modelSpec.inputVars.values()) {
|
|
88
|
+
allInputIds.add(inputVar.inputId)
|
|
89
|
+
inputsMap.set(inputVar.inputId, inputVar)
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
const inputsByIdL: Map<InputId, InputVar> = new Map()
|
|
93
|
+
const inputsByIdR: Map<InputId, InputVar> = new Map()
|
|
94
|
+
addInputs(bundleL, inputsByIdL)
|
|
95
|
+
addInputs(bundleR, inputsByIdR)
|
|
96
|
+
|
|
97
|
+
// Create an "all inputs at default" scenario
|
|
98
|
+
const scenarios: ComparisonScenarioSpec[] = []
|
|
99
|
+
scenarios.push({
|
|
100
|
+
kind: 'scenario-with-all-inputs',
|
|
101
|
+
id: 'all_inputs_at_default',
|
|
102
|
+
title: 'All inputs',
|
|
103
|
+
subtitle: 'at default',
|
|
104
|
+
position: 'default'
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
// Create "input at min/max" scenarios for all inputs (that appear in either "left" or "right")
|
|
108
|
+
const addScenario = (inputId: InputId, position: 'min' | 'max') => {
|
|
109
|
+
const inputL = inputsByIdL.get(inputId)
|
|
110
|
+
const inputR = inputsByIdR.get(inputId)
|
|
111
|
+
if (inputL === undefined || inputR === undefined) {
|
|
112
|
+
return
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Don't add a scenario if the input's min or max is equal to its default (this is already
|
|
116
|
+
// covered by the `all_inputs_at_default` scenario from above)
|
|
117
|
+
if (position === 'min') {
|
|
118
|
+
if (inputL.minValue === inputL.defaultValue && inputR.minValue === inputR.defaultValue) {
|
|
119
|
+
return
|
|
120
|
+
}
|
|
121
|
+
} else {
|
|
122
|
+
if (inputL.maxValue === inputL.defaultValue && inputR.maxValue === inputR.defaultValue) {
|
|
123
|
+
return
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Derive the scenario name from the related slider name (or if not defined, the variable name)
|
|
128
|
+
const input = inputR || inputL
|
|
129
|
+
const path = input.relatedItem?.locationPath
|
|
130
|
+
const title = path ? path[path.length - 1] : input.varName
|
|
131
|
+
|
|
132
|
+
scenarios.push({
|
|
133
|
+
kind: 'scenario-with-inputs',
|
|
134
|
+
id: `id_${inputId}_at_${position}`,
|
|
135
|
+
title,
|
|
136
|
+
subtitle: `at ${position}`,
|
|
137
|
+
inputs: [
|
|
138
|
+
{
|
|
139
|
+
kind: 'input-at-position',
|
|
140
|
+
inputName: `id ${inputId}`,
|
|
141
|
+
position
|
|
142
|
+
}
|
|
143
|
+
]
|
|
144
|
+
})
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Add an "at min" and "at max" scenario for each input
|
|
148
|
+
const inputIds = [...allInputIds]
|
|
149
|
+
for (const inputId of inputIds) {
|
|
150
|
+
addScenario(inputId, 'min')
|
|
151
|
+
addScenario(inputId, 'max')
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return {
|
|
155
|
+
scenarios,
|
|
156
|
+
scenarioGroups: [],
|
|
157
|
+
viewGroups: []
|
|
78
158
|
}
|
|
79
159
|
}
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
// Enable warnings for transpilation-unsafe code
|
|
12
12
|
"isolatedModules": true,
|
|
13
13
|
// Enable strict enforcement of `import type`
|
|
14
|
-
"
|
|
14
|
+
"verbatimModuleSyntax": true,
|
|
15
15
|
"noImplicitAny": true,
|
|
16
16
|
"noUnusedLocals": true,
|
|
17
17
|
"noUnusedParameters": true,
|