@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
package/README.md
CHANGED
|
@@ -1,11 +1,32 @@
|
|
|
1
1
|
# @sdeverywhere/plugin-check
|
|
2
2
|
|
|
3
|
-
This package provides a plugin that runs model checks and comparison tests for a
|
|
4
|
-
|
|
3
|
+
This package provides a plugin that runs model checks and comparison tests for a given System Dynamics model generated by [SDEverywhere](https://github.com/climateinteractive/SDEverywhere).
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
The best way to get started with SDEverywhere is to follow the [Quick Start](https://github.com/climateinteractive/SDEverywhere#quick-start) instructions.
|
|
8
|
+
If you follow those instructions, the `@sdeverywhere/plugin-check` package will be added to your project automatically, in which case you can skip the next section and jump straight to the ["Usage"](#usage) section below.
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
```sh
|
|
13
|
+
# npm
|
|
14
|
+
npm install --save-dev @sdeverywhere/plugin-check
|
|
15
|
+
|
|
16
|
+
# pnpm
|
|
17
|
+
pnpm add -D @sdeverywhere/plugin-check
|
|
18
|
+
|
|
19
|
+
# yarn
|
|
20
|
+
yarn add -D @sdeverywhere/plugin-check
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
_TODO: This section needs to be fleshed out. In the meantime, you can refer to the API documentation below for the options used to configure this plugin._
|
|
5
26
|
|
|
6
27
|
## Documentation
|
|
7
28
|
|
|
8
|
-
|
|
29
|
+
API documentation (for plugin configuration options) is available in the [`docs`](./docs/index.md) directory.
|
|
9
30
|
|
|
10
31
|
## License
|
|
11
32
|
|
package/dist/index.cjs
CHANGED
|
@@ -17,6 +17,10 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
17
17
|
return to;
|
|
18
18
|
};
|
|
19
19
|
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
20
24
|
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
21
25
|
mod
|
|
22
26
|
));
|
|
@@ -29,6 +33,10 @@ __export(src_exports, {
|
|
|
29
33
|
});
|
|
30
34
|
module.exports = __toCommonJS(src_exports);
|
|
31
35
|
|
|
36
|
+
// ../../node_modules/.pnpm/tsup@7.2.0_typescript@5.2.2/node_modules/tsup/assets/cjs_shims.js
|
|
37
|
+
var getImportMetaUrl = () => typeof document === "undefined" ? new URL("file:" + __filename).href : document.currentScript && document.currentScript.src || new URL("main.js", document.baseURI).href;
|
|
38
|
+
var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
|
|
39
|
+
|
|
32
40
|
// src/plugin.ts
|
|
33
41
|
var import_fs2 = require("fs");
|
|
34
42
|
var import_promises = require("fs/promises");
|
|
@@ -62,8 +70,8 @@ async function runTestSuite(context, config, verbose) {
|
|
|
62
70
|
context.log("info", `
|
|
63
71
|
Test suite completed in ${elapsed}s`);
|
|
64
72
|
const allChecksPassed = printCheckSummary(context, report.checkReport, verbose);
|
|
65
|
-
if (report.
|
|
66
|
-
printPerfStats(context, config.
|
|
73
|
+
if (report.comparisonReport) {
|
|
74
|
+
printPerfStats(context, config.comparison, report.comparisonReport);
|
|
67
75
|
}
|
|
68
76
|
const suiteSummary = (0, import_check_core.suiteSummaryFromReport)(report);
|
|
69
77
|
resolve({
|
|
@@ -144,11 +152,11 @@ function printPerfReportLine(context, perfReport) {
|
|
|
144
152
|
const max = stat("max", perfReport.maxTime);
|
|
145
153
|
context.log("info", ` ${avg} ${min} ${max}`);
|
|
146
154
|
}
|
|
147
|
-
function printPerfStats(context,
|
|
155
|
+
function printPerfStats(context, comparisonConfig, report) {
|
|
148
156
|
context.log("info", "\nPerformance stats:");
|
|
149
|
-
context.log("info", ` ${
|
|
157
|
+
context.log("info", ` ${comparisonConfig.bundleL.name}:`);
|
|
150
158
|
printPerfReportLine(context, report.perfReportL);
|
|
151
|
-
context.log("info", ` ${
|
|
159
|
+
context.log("info", ` ${comparisonConfig.bundleR.name}:`);
|
|
152
160
|
printPerfReportLine(context, report.perfReportR);
|
|
153
161
|
context.log("info", "");
|
|
154
162
|
}
|
|
@@ -177,13 +185,15 @@ function sdeNameForVensimVarName(varName) {
|
|
|
177
185
|
}
|
|
178
186
|
|
|
179
187
|
// src/vite-config-for-bundle.ts
|
|
180
|
-
var
|
|
181
|
-
var
|
|
182
|
-
var __dirname = (0, import_path.dirname)(__filename);
|
|
188
|
+
var __filename2 = (0, import_url.fileURLToPath)(importMetaUrl);
|
|
189
|
+
var __dirname = (0, import_path.dirname)(__filename2);
|
|
183
190
|
function injectModelSpec(prepDir, modelSpec) {
|
|
184
191
|
const inputSpecs = modelSpec.inputs.map((i) => {
|
|
192
|
+
const varId = sdeNameForVensimVarName(i.varName);
|
|
193
|
+
const inputId = i.inputId || varId;
|
|
185
194
|
return {
|
|
186
|
-
|
|
195
|
+
inputId,
|
|
196
|
+
varId,
|
|
187
197
|
...i
|
|
188
198
|
};
|
|
189
199
|
});
|
|
@@ -225,20 +235,58 @@ export const dataSizeInBytes = ${dataSizeInBytes};
|
|
|
225
235
|
}
|
|
226
236
|
};
|
|
227
237
|
}
|
|
238
|
+
function overrideViteResolvePlugin(viteConfig) {
|
|
239
|
+
const resolvePlugin = viteConfig.plugins.find((p) => p.name === "vite:resolve");
|
|
240
|
+
if (resolvePlugin === void 0) {
|
|
241
|
+
throw new Error("Failed to locate the built-in vite:resolve plugin");
|
|
242
|
+
}
|
|
243
|
+
const originalResolveId = resolvePlugin.resolveId;
|
|
244
|
+
resolvePlugin.resolveId = async function resolveId(id, importer, options) {
|
|
245
|
+
if (id.startsWith("./implementation") && importer.includes("threads/dist-esm")) {
|
|
246
|
+
const idFileName = id.replace("./", "");
|
|
247
|
+
const importerFileName = (0, import_path.basename)(importer);
|
|
248
|
+
const resolvedId = importer.replace(importerFileName, `${idFileName}.js`);
|
|
249
|
+
return {
|
|
250
|
+
id: resolvedId,
|
|
251
|
+
moduleSideEffects: false
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
return originalResolveId.call(this, id, importer, options);
|
|
255
|
+
};
|
|
256
|
+
}
|
|
228
257
|
async function createViteConfigForBundle(prepDir, modelSpec) {
|
|
229
258
|
const root = (0, import_path.resolve)(__dirname, "..", "template-bundle");
|
|
230
259
|
const outDir = (0, import_path.relative)(root, prepDir);
|
|
231
260
|
const modelWorkerPath = (0, import_path.join)(prepDir, "staged", "model", "worker.js?raw");
|
|
232
261
|
return {
|
|
262
|
+
// Don't use an external config file
|
|
233
263
|
configFile: false,
|
|
264
|
+
// Use the root directory configured above
|
|
234
265
|
root,
|
|
266
|
+
// Don't clear the screen in dev mode so that we can see builder output
|
|
235
267
|
clearScreen: false,
|
|
268
|
+
// TODO: Disable vite output by default?
|
|
269
|
+
// logLevel: 'silent',
|
|
270
|
+
// Configure path aliases
|
|
236
271
|
resolve: {
|
|
237
272
|
alias: [
|
|
273
|
+
// Inject the configured model worker
|
|
238
274
|
{
|
|
239
275
|
find: "@_model_worker_",
|
|
240
276
|
replacement: modelWorkerPath
|
|
241
277
|
},
|
|
278
|
+
// XXX: Prevent Vite from using the `browser` section of `threads/package.json`
|
|
279
|
+
// since we want to force the use of the general module (under dist-esm) that chooses
|
|
280
|
+
// the correct implementation (Web Worker vs worker_threads) at runtime. Currently
|
|
281
|
+
// Vite's library mode is browser focused and generally chooses the right imports,
|
|
282
|
+
// except in the case of the threads package where we want to use the generic
|
|
283
|
+
// `implementation.js` that chooses between Web Worker and worker_threads at runtime.
|
|
284
|
+
// Note that we could in theory set `resolve.browserField` to false, but that would
|
|
285
|
+
// make Vite not use the browser field for all other packages, and there is not
|
|
286
|
+
// currently a way to tell Vite to use the browser field on a case-by-case basis.
|
|
287
|
+
// So for now we need this workaround here to make it resolve to `dist-esm`, and then
|
|
288
|
+
// a second workaround in `overrideViteResolvePlugin` to prevent the resolver from
|
|
289
|
+
// using the browser field when resolving the threads package.
|
|
242
290
|
{
|
|
243
291
|
find: "threads",
|
|
244
292
|
replacement: "threads",
|
|
@@ -255,18 +303,40 @@ async function createViteConfigForBundle(prepDir, modelSpec) {
|
|
|
255
303
|
]
|
|
256
304
|
},
|
|
257
305
|
plugins: [
|
|
258
|
-
|
|
306
|
+
// Use a virtual module plugin to inject the model spec values
|
|
307
|
+
injectModelSpec(prepDir, modelSpec),
|
|
308
|
+
// XXX: Install a wrapper around the built-in `vite:resolve` plugin so that we can
|
|
309
|
+
// override the default resolver behavior that tries to resolve the `browser` section
|
|
310
|
+
// of the `package.json` for the threads package.
|
|
311
|
+
{
|
|
312
|
+
name: "vite-plugin-override-resolve",
|
|
313
|
+
configResolved(viteConfig) {
|
|
314
|
+
overrideViteResolvePlugin(viteConfig);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
259
317
|
],
|
|
260
318
|
build: {
|
|
319
|
+
// Write output files to the configured directory (instead of the default `dist`);
|
|
320
|
+
// note that this must be relative to the project `root`
|
|
261
321
|
outDir,
|
|
262
322
|
emptyOutDir: false,
|
|
323
|
+
// Uncomment for debugging purposes
|
|
324
|
+
// minify: false,
|
|
263
325
|
lib: {
|
|
264
326
|
entry: "./src/index.ts",
|
|
265
327
|
formats: ["es"],
|
|
266
328
|
fileName: () => "check-bundle.js"
|
|
267
329
|
},
|
|
268
330
|
rollupOptions: {
|
|
331
|
+
// Don't transform Node imports used by threads.js
|
|
269
332
|
external: ["events", "os", "path", "url"],
|
|
333
|
+
// XXX: Insert custom code at the top of the generated bundle that defines
|
|
334
|
+
// the special `__non_webpack_require__` function that is used by threads.js
|
|
335
|
+
// in its Node implementation. This import ensures that threads.js uses
|
|
336
|
+
// the native `worker_threads` implementation when using the bundle in a
|
|
337
|
+
// Node environment. When importing the bundle for use in the browser,
|
|
338
|
+
// Vite will transform this import into an empty module due to the empty
|
|
339
|
+
// polyfill that is configured in `vite-config-for-report.ts`.
|
|
270
340
|
output: {
|
|
271
341
|
banner: `
|
|
272
342
|
import * as worker_threads from 'worker_threads'
|
|
@@ -289,18 +359,16 @@ let __non_webpack_require__ = () => {
|
|
|
289
359
|
var import_path2 = require("path");
|
|
290
360
|
var import_url2 = require("url");
|
|
291
361
|
var import_plugin_replace = __toESM(require("@rollup/plugin-replace"), 1);
|
|
292
|
-
var
|
|
293
|
-
var
|
|
294
|
-
var __dirname2 = (0, import_path2.dirname)(__filename2);
|
|
362
|
+
var __filename3 = (0, import_url2.fileURLToPath)(importMetaUrl);
|
|
363
|
+
var __dirname2 = (0, import_path2.dirname)(__filename3);
|
|
295
364
|
function createViteConfigForReport(options, projDir, prepDir, currentBundleName, currentBundlePath, testConfigPath, suiteSummary) {
|
|
296
|
-
var _a;
|
|
297
365
|
const root = (0, import_path2.resolve)(__dirname2, "..", "template-report");
|
|
298
366
|
const templateSrcDir = (0, import_path2.resolve)(root, "src");
|
|
299
367
|
const relProjDir = (0, import_path2.relative)(templateSrcDir, projDir);
|
|
300
368
|
const relProjDirPath = relProjDir.replaceAll("\\", "/");
|
|
301
369
|
const baselinesPath = `${relProjDirPath}/baselines/*.js`;
|
|
302
370
|
let reportPath;
|
|
303
|
-
if (options
|
|
371
|
+
if (options?.reportPath) {
|
|
304
372
|
reportPath = options.reportPath;
|
|
305
373
|
} else {
|
|
306
374
|
reportPath = (0, import_path2.join)(prepDir, "check-report");
|
|
@@ -320,57 +388,113 @@ function createViteConfigForReport(options, projDir, prepDir, currentBundleName,
|
|
|
320
388
|
};
|
|
321
389
|
};
|
|
322
390
|
return {
|
|
391
|
+
// Don't use an external config file
|
|
323
392
|
configFile: false,
|
|
393
|
+
// Use the root directory configured above
|
|
324
394
|
root,
|
|
395
|
+
// Use `.` as the base directory (instead of the default `/`); this controls
|
|
396
|
+
// how the path to the js/css files are generated in `index.html`
|
|
325
397
|
base: "",
|
|
398
|
+
// Use a custom cache directory under `prepDir`, as otherwise Vite will use
|
|
399
|
+
// `packages/plugin-check/template-report/node_modules/.vite`, and we want to
|
|
400
|
+
// avoid generating files in `template-report` (which should be read-only)
|
|
326
401
|
cacheDir: (0, import_path2.join)(prepDir, ".vite-check-report"),
|
|
402
|
+
// Load static files from `static` (instead of the default `public`)
|
|
403
|
+
// publicDir: 'static',
|
|
404
|
+
// Don't clear the screen in dev mode so that we can see builder output
|
|
327
405
|
clearScreen: false,
|
|
406
|
+
// TODO
|
|
407
|
+
// logLevel: 'silent',
|
|
328
408
|
optimizeDeps: {
|
|
409
|
+
// Prevent Vite from examining other html files when scanning entrypoints
|
|
410
|
+
// for dependency optimization
|
|
329
411
|
entries: ["index.html"],
|
|
412
|
+
// XXX: When plugin-check is installed via pnpm, the Vite dev server seems
|
|
413
|
+
// to have no trouble resolving other dependencies using the optimizeDeps
|
|
414
|
+
// mechanism. However, this fails when the package is installed via yarn
|
|
415
|
+
// or npm (probably due to the fact that the `template-report` directory
|
|
416
|
+
// is located under the top-level `node_modules` directory); in the browser,
|
|
417
|
+
// there will be "import not found" errors for the packages referenced below.
|
|
418
|
+
// As a terrible workaround, explicitly include the direct dependencies so
|
|
419
|
+
// that Vite optimizes them; this works for pnpm, yarn, and npm. We should
|
|
420
|
+
// find a less fragile solution.
|
|
330
421
|
include: [
|
|
331
|
-
|
|
332
|
-
"
|
|
333
|
-
"
|
|
334
|
-
"
|
|
335
|
-
"
|
|
336
|
-
|
|
337
|
-
"
|
|
422
|
+
// from check-core
|
|
423
|
+
"@sdeverywhere/check-core > assert-never",
|
|
424
|
+
"@sdeverywhere/check-core > ajv",
|
|
425
|
+
"@sdeverywhere/check-core > neverthrow",
|
|
426
|
+
"@sdeverywhere/check-core > yaml",
|
|
427
|
+
// from check-ui-shell
|
|
428
|
+
"@sdeverywhere/check-ui-shell > fontfaceobserver",
|
|
429
|
+
"@sdeverywhere/check-ui-shell > copy-text-to-clipboard",
|
|
430
|
+
"@sdeverywhere/check-ui-shell > chart.js"
|
|
338
431
|
],
|
|
339
432
|
exclude: [
|
|
340
|
-
|
|
341
|
-
|
|
433
|
+
// XXX: The threads.js implementation references `tiny-worker` as an optional
|
|
434
|
+
// dependency, but it doesn't get used at runtime, so we can just exclude it
|
|
435
|
+
// so that Vite doesn't complain in dev mode
|
|
436
|
+
"tiny-worker"
|
|
437
|
+
// XXX: Similarly, chart.js treats `moment` as an optional dependency, but we
|
|
438
|
+
// don't use it at runtime; we need to exclude it here, otherwise Vite will
|
|
439
|
+
// complain about missing dependencies in dev mode
|
|
440
|
+
// 'moment'
|
|
342
441
|
]
|
|
343
442
|
},
|
|
443
|
+
// Configure path aliases
|
|
344
444
|
resolve: {
|
|
345
445
|
alias: [
|
|
346
|
-
|
|
446
|
+
// Use the configured "baseline" bundle if defined, otherwise use the "empty" bundle
|
|
447
|
+
// (which will cause comparison tests to be skipped)
|
|
448
|
+
alias("@_baseline_bundle_", options?.baseline ? options.baseline.path : "/src/empty-bundle.ts"),
|
|
449
|
+
// Use the configured "current" bundle
|
|
347
450
|
alias("@_current_bundle_", currentBundlePath),
|
|
451
|
+
// Use the configured test config file
|
|
348
452
|
alias("@_test_config_", testConfigPath),
|
|
453
|
+
// Make the overlay use the `messages.html` file that is written to the prep directory
|
|
349
454
|
alias("@_prep_", prepDir),
|
|
455
|
+
// XXX: Include no-op polyfills for these modules that are used in the Node-specific
|
|
456
|
+
// implementation of threads.js; this allows us to use one bundle that works in both
|
|
457
|
+
// Node and browser environments
|
|
350
458
|
noopPolyfillAlias("events"),
|
|
459
|
+
noopPolyfillAlias("fs"),
|
|
351
460
|
noopPolyfillAlias("os"),
|
|
352
461
|
noopPolyfillAlias("path"),
|
|
353
|
-
noopPolyfillAlias("url")
|
|
462
|
+
noopPolyfillAlias("url"),
|
|
463
|
+
noopPolyfillAlias("worker_threads")
|
|
354
464
|
]
|
|
355
465
|
},
|
|
466
|
+
// Inject special values into the generated JS
|
|
356
467
|
define: {
|
|
468
|
+
// Inject the summary JSON into the build
|
|
357
469
|
__SUITE_SUMMARY_JSON__: JSON.stringify(suiteSummaryJson),
|
|
358
|
-
|
|
470
|
+
// Inject the baseline branch name
|
|
471
|
+
__BASELINE_NAME__: JSON.stringify(options?.baseline?.name || ""),
|
|
472
|
+
// Inject the current branch name
|
|
359
473
|
__CURRENT_NAME__: JSON.stringify(currentBundleName)
|
|
360
474
|
},
|
|
361
475
|
plugins: [
|
|
476
|
+
// Inject special values into the generated JS
|
|
477
|
+
// TODO: We currently have to use `@rollup/plugin-replace` instead of Vite's
|
|
478
|
+
// built-in `define` feature because the latter does not seem to run before
|
|
479
|
+
// the glob handler (which requires the glob to be injected as a literal)
|
|
362
480
|
(0, import_plugin_replace.default)({
|
|
363
481
|
preventAssignment: true,
|
|
482
|
+
delimiters: ["", ""],
|
|
364
483
|
values: {
|
|
365
|
-
|
|
484
|
+
// Inject the path for baseline bundles
|
|
485
|
+
"./__BASELINE_BUNDLES_PATH__": baselinesPath
|
|
366
486
|
}
|
|
367
487
|
})
|
|
368
488
|
],
|
|
369
489
|
build: {
|
|
490
|
+
// Write output files to the configured directory (instead of the default `dist`);
|
|
491
|
+
// note that this must be relative to the project `root`
|
|
370
492
|
outDir,
|
|
493
|
+
// Write js/css files to `public` (instead of the default `<outDir>/assets`)
|
|
371
494
|
assetsDir: "",
|
|
372
495
|
rollupOptions: {
|
|
373
496
|
output: {
|
|
497
|
+
// XXX: Prevent vite from creating a separate `vendor.js` file
|
|
374
498
|
manualChunks: void 0
|
|
375
499
|
},
|
|
376
500
|
onwarn: (warning, warn) => {
|
|
@@ -381,8 +505,14 @@ function createViteConfigForReport(options, projDir, prepDir, currentBundleName,
|
|
|
381
505
|
}
|
|
382
506
|
},
|
|
383
507
|
server: {
|
|
384
|
-
|
|
508
|
+
// Run the dev server at `localhost:8081` by default
|
|
509
|
+
port: options?.serverPort || 8081,
|
|
510
|
+
// Open the app in the browser by default
|
|
385
511
|
open: "/index.html",
|
|
512
|
+
// XXX: Add a small delay, otherwise on macOS we sometimes get multiple
|
|
513
|
+
// change events when a file is saved just once. That is a relatively
|
|
514
|
+
// harmless issue except that it causes redundant messages in the console
|
|
515
|
+
// and can cause extra churn when refreshing the app.
|
|
386
516
|
watch: {
|
|
387
517
|
awaitWriteFinish: {
|
|
388
518
|
stabilityThreshold: 100
|
|
@@ -395,9 +525,9 @@ function createViteConfigForReport(options, projDir, prepDir, currentBundleName,
|
|
|
395
525
|
// src/vite-config-for-tests.ts
|
|
396
526
|
var import_path3 = require("path");
|
|
397
527
|
var import_url3 = require("url");
|
|
398
|
-
var
|
|
399
|
-
var
|
|
400
|
-
var __dirname3 = (0, import_path3.dirname)(
|
|
528
|
+
var import_plugin_replace2 = __toESM(require("@rollup/plugin-replace"), 1);
|
|
529
|
+
var __filename4 = (0, import_url3.fileURLToPath)(importMetaUrl);
|
|
530
|
+
var __dirname3 = (0, import_path3.dirname)(__filename4);
|
|
401
531
|
function createViteConfigForTests(projDir, prepDir, mode) {
|
|
402
532
|
const root = (0, import_path3.resolve)(__dirname3, "..", "template-tests");
|
|
403
533
|
const templateSrcDir = (0, import_path3.resolve)(root, "src");
|
|
@@ -406,13 +536,31 @@ function createViteConfigForTests(projDir, prepDir, mode) {
|
|
|
406
536
|
const yamlPath = `${relProjDirPath}/**/*.check.yaml`;
|
|
407
537
|
const outDir = (0, import_path3.relative)(root, prepDir);
|
|
408
538
|
return {
|
|
539
|
+
// Don't use an external config file
|
|
409
540
|
configFile: false,
|
|
541
|
+
// Use the root directory configured above
|
|
410
542
|
root,
|
|
543
|
+
// Don't clear the screen in dev mode so that we can see builder output
|
|
411
544
|
clearScreen: false,
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
545
|
+
// TODO: Disable vite output by default?
|
|
546
|
+
// logLevel: 'silent',
|
|
547
|
+
plugins: [
|
|
548
|
+
// Inject special values into the generated JS
|
|
549
|
+
// TODO: We currently have to use `@rollup/plugin-replace` instead of Vite's
|
|
550
|
+
// built-in `define` feature because the latter does not seem to run before
|
|
551
|
+
// the glob handler (which requires the glob to be injected as a literal)
|
|
552
|
+
(0, import_plugin_replace2.default)({
|
|
553
|
+
preventAssignment: true,
|
|
554
|
+
delimiters: ["", ""],
|
|
555
|
+
values: {
|
|
556
|
+
// Inject the glob pattern for matching check yaml files
|
|
557
|
+
"./__YAML_PATH__": yamlPath
|
|
558
|
+
}
|
|
559
|
+
})
|
|
560
|
+
],
|
|
415
561
|
build: {
|
|
562
|
+
// Write output files to the configured directory (instead of the default `dist`);
|
|
563
|
+
// note that this must be relative to the project `root`
|
|
416
564
|
outDir,
|
|
417
565
|
emptyOutDir: false,
|
|
418
566
|
lib: {
|
|
@@ -420,14 +568,24 @@ function createViteConfigForTests(projDir, prepDir, mode) {
|
|
|
420
568
|
formats: ["es"],
|
|
421
569
|
fileName: () => "check-tests.js"
|
|
422
570
|
},
|
|
571
|
+
// Enable watch mode if requested
|
|
423
572
|
watch: mode === "watch" && {},
|
|
424
|
-
rollupOptions: {
|
|
573
|
+
rollupOptions: {
|
|
574
|
+
// Prevent dependencies from being included in packaged library
|
|
575
|
+
// TODO: For now we include check-core in the packaged library so that its
|
|
576
|
+
// dependencies are correctly resolved at runtime. Ideally this would only
|
|
577
|
+
// include a couple functions that are used for defining tests, but Vite 2.x
|
|
578
|
+
// does not implement tree shaking for ES libraries, which means the generated
|
|
579
|
+
// library is much larger than it needs to be. Once we upgrade to Vite 3.x,
|
|
580
|
+
// the generated library should be smaller; see related fix:
|
|
581
|
+
// https://github.com/vitejs/vite/pull/8737
|
|
582
|
+
// external: Object.keys(pkg.dependencies)
|
|
583
|
+
}
|
|
425
584
|
}
|
|
426
585
|
};
|
|
427
586
|
}
|
|
428
587
|
|
|
429
588
|
// src/plugin.ts
|
|
430
|
-
var import_meta4 = {};
|
|
431
589
|
function checkPlugin(options) {
|
|
432
590
|
return new CheckPlugin(options);
|
|
433
591
|
}
|
|
@@ -437,8 +595,7 @@ var CheckPlugin = class {
|
|
|
437
595
|
this.firstBuild = true;
|
|
438
596
|
}
|
|
439
597
|
async watch(config) {
|
|
440
|
-
|
|
441
|
-
if (((_a = this.options) == null ? void 0 : _a.testConfigPath) === void 0) {
|
|
598
|
+
if (this.options?.testConfigPath === void 0) {
|
|
442
599
|
await this.genTestConfig(config, "watch");
|
|
443
600
|
}
|
|
444
601
|
const testOptions = this.resolveTestOptions(config);
|
|
@@ -447,8 +604,12 @@ var CheckPlugin = class {
|
|
|
447
604
|
await server.listen();
|
|
448
605
|
const baselinesDir = "baselines";
|
|
449
606
|
const watcher = import_chokidar.default.watch(baselinesDir, {
|
|
607
|
+
// Watch paths are resolved relative to the project root directory
|
|
450
608
|
cwd: config.rootDir,
|
|
609
|
+
// Don't send initial "file added" events
|
|
451
610
|
ignoreInitial: true,
|
|
611
|
+
// XXX: Include a delay, otherwise on macOS we sometimes get multiple
|
|
612
|
+
// change events when a file is saved just once
|
|
452
613
|
awaitWriteFinish: {
|
|
453
614
|
stabilityThreshold: 200
|
|
454
615
|
}
|
|
@@ -456,18 +617,22 @@ var CheckPlugin = class {
|
|
|
456
617
|
watcher.on("add", () => server.restart());
|
|
457
618
|
watcher.on("unlink", () => server.restart());
|
|
458
619
|
}
|
|
620
|
+
// TODO: Note that this plugin runs as a `postBuild` step because it currently
|
|
621
|
+
// needs to run after other plugins, and those plugins need to run after the
|
|
622
|
+
// staged files are copied to their final destination(s). We should probably
|
|
623
|
+
// make it configurable so that it can either be run as a `postGenerate` or a
|
|
624
|
+
// `postBuild` step.
|
|
459
625
|
async postBuild(context, modelSpec) {
|
|
460
|
-
var _a, _b;
|
|
461
626
|
const firstBuild = this.firstBuild;
|
|
462
627
|
this.firstBuild = false;
|
|
463
|
-
if (
|
|
628
|
+
if (this.options?.current === void 0) {
|
|
464
629
|
if (context.config.mode === "development") {
|
|
465
630
|
await this.copyPreviousBundle(context.config);
|
|
466
631
|
}
|
|
467
632
|
context.log("info", "Generating model check bundle...");
|
|
468
633
|
await this.genCurrentBundle(context.config, modelSpec);
|
|
469
634
|
}
|
|
470
|
-
if (
|
|
635
|
+
if (this.options?.testConfigPath === void 0) {
|
|
471
636
|
if (context.config.mode === "production" || firstBuild) {
|
|
472
637
|
context.log("info", "Generating model check test configuration...");
|
|
473
638
|
await this.genTestConfig(context.config, "build");
|
|
@@ -503,38 +668,42 @@ var CheckPlugin = class {
|
|
|
503
668
|
await (0, import_vite.build)(viteConfig);
|
|
504
669
|
}
|
|
505
670
|
async runChecks(context, testOptions) {
|
|
506
|
-
var _a;
|
|
507
671
|
context.log("info", "Running model checks...");
|
|
508
672
|
const moduleR = await import(relativeToSourcePath(testOptions.currentBundlePath));
|
|
509
673
|
const bundleR = moduleR.createBundle();
|
|
510
|
-
const
|
|
674
|
+
const bundleNameR = testOptions.currentBundleName;
|
|
511
675
|
let bundleL;
|
|
512
|
-
let
|
|
513
|
-
if (
|
|
676
|
+
let bundleNameL;
|
|
677
|
+
if (this.options?.baseline) {
|
|
514
678
|
const moduleL = await import(relativeToSourcePath(this.options.baseline.path));
|
|
515
679
|
const rawBundleL = moduleL.createBundle();
|
|
516
680
|
if (rawBundleL.version === bundleR.version) {
|
|
517
681
|
bundleL = rawBundleL;
|
|
518
|
-
|
|
682
|
+
bundleNameL = this.options.baseline.name;
|
|
519
683
|
}
|
|
520
684
|
}
|
|
521
685
|
const testConfigModule = await import(relativeToSourcePath(testOptions.testConfigPath));
|
|
522
|
-
const
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
}
|
|
526
|
-
const
|
|
527
|
-
const
|
|
686
|
+
const configInitOptions = {
|
|
687
|
+
bundleNameL,
|
|
688
|
+
bundleNameR
|
|
689
|
+
};
|
|
690
|
+
const configOptions = await testConfigModule.getConfigOptions(bundleL, bundleR, configInitOptions);
|
|
691
|
+
const checkConfig = await (0, import_check_core2.createConfig)(configOptions);
|
|
692
|
+
const result = await runTestSuite(
|
|
693
|
+
context,
|
|
694
|
+
checkConfig,
|
|
695
|
+
/*verbose=*/
|
|
696
|
+
false
|
|
697
|
+
);
|
|
528
698
|
context.log("info", "Building model check report");
|
|
529
699
|
const viteConfig = this.createViteConfigForReport(context.config, testOptions, result.suiteSummary);
|
|
530
700
|
await (0, import_vite.build)(viteConfig);
|
|
531
701
|
return result.allChecksPassed;
|
|
532
702
|
}
|
|
533
703
|
resolveTestOptions(config) {
|
|
534
|
-
var _a, _b;
|
|
535
704
|
let currentBundleName;
|
|
536
705
|
let currentBundlePath;
|
|
537
|
-
if (
|
|
706
|
+
if (this.options?.current === void 0) {
|
|
538
707
|
currentBundleName = "current";
|
|
539
708
|
currentBundlePath = (0, import_path4.join)(config.prepDir, "check-bundle.js");
|
|
540
709
|
} else {
|
|
@@ -542,7 +711,7 @@ var CheckPlugin = class {
|
|
|
542
711
|
currentBundlePath = this.options.current.path;
|
|
543
712
|
}
|
|
544
713
|
let testConfigPath;
|
|
545
|
-
if (
|
|
714
|
+
if (this.options?.testConfigPath === void 0) {
|
|
546
715
|
testConfigPath = (0, import_path4.join)(config.prepDir, "check-tests.js");
|
|
547
716
|
} else {
|
|
548
717
|
testConfigPath = this.options.testConfigPath;
|
|
@@ -566,7 +735,7 @@ var CheckPlugin = class {
|
|
|
566
735
|
}
|
|
567
736
|
};
|
|
568
737
|
function relativeToSourcePath(filePath) {
|
|
569
|
-
const srcDir = (0, import_path4.dirname)((0, import_url4.fileURLToPath)(
|
|
738
|
+
const srcDir = (0, import_path4.dirname)((0, import_url4.fileURLToPath)(importMetaUrl));
|
|
570
739
|
const relPath = (0, import_path4.relative)(srcDir, filePath);
|
|
571
740
|
return relPath.replaceAll("\\", "/");
|
|
572
741
|
}
|