@sdeverywhere/plugin-check 0.3.37 → 0.3.38
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +67 -65
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +660 -899
- package/dist/index.js.map +1 -1
- package/package.json +13 -26
- package/template-report/index.html +7 -5
- package/template-report/polyfills/noop-polyfills.ts +8 -5
- package/template-report/src/bundle-metadata.spec.ts +81 -0
- package/template-report/src/bundle-metadata.ts +66 -0
- package/template-report/src/index.ts +17 -78
- package/template-report/src/load-bundle.ts +1 -4
- package/template-report/src/resolve-bundle.spec.ts +109 -0
- package/template-report/src/resolve-bundle.ts +64 -0
- package/dist/index.cjs +0 -972
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -83
- package/template-report/src/bundles/unused.txt +0 -2
package/dist/index.cjs
DELETED
|
@@ -1,972 +0,0 @@
|
|
|
1
|
-
var __create = Object.create;
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
-
var __export = (target, all) => {
|
|
8
|
-
for (var name in all)
|
|
9
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
-
};
|
|
11
|
-
var __copyProps = (to, from, except, desc) => {
|
|
12
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
-
for (let key of __getOwnPropNames(from))
|
|
14
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
-
}
|
|
17
|
-
return to;
|
|
18
|
-
};
|
|
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.
|
|
24
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
-
mod
|
|
26
|
-
));
|
|
27
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
|
-
|
|
29
|
-
// src/index.ts
|
|
30
|
-
var index_exports = {};
|
|
31
|
-
__export(index_exports, {
|
|
32
|
-
checkPlugin: () => checkPlugin
|
|
33
|
-
});
|
|
34
|
-
module.exports = __toCommonJS(index_exports);
|
|
35
|
-
|
|
36
|
-
// ../../node_modules/.pnpm/tsup@8.5.1_postcss@8.5.26_typescript@5.2.2_yaml@2.9.0/node_modules/tsup/assets/cjs_shims.js
|
|
37
|
-
var getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.tagName.toUpperCase() === "SCRIPT" ? document.currentScript.src : new URL("main.js", document.baseURI).href;
|
|
38
|
-
var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
|
|
39
|
-
|
|
40
|
-
// src/plugin.ts
|
|
41
|
-
var import_node_fs2 = require("fs");
|
|
42
|
-
var import_promises3 = require("fs/promises");
|
|
43
|
-
var import_node_path4 = require("path");
|
|
44
|
-
var import_url3 = require("url");
|
|
45
|
-
var import_vite = require("vite");
|
|
46
|
-
var import_check_core3 = require("@sdeverywhere/check-core");
|
|
47
|
-
|
|
48
|
-
// src/bundle-file-ops.ts
|
|
49
|
-
var import_promises = require("fs/promises");
|
|
50
|
-
var import_node_path = require("path");
|
|
51
|
-
async function downloadBundle(url, name, lastModified, bundlesDir, fetchRemoteBundle) {
|
|
52
|
-
const fullUrl = `${url}?cb=${Date.now()}`;
|
|
53
|
-
let bundleContent;
|
|
54
|
-
if (fetchRemoteBundle) {
|
|
55
|
-
bundleContent = await fetchRemoteBundle(fullUrl);
|
|
56
|
-
} else {
|
|
57
|
-
const response = await fetch(fullUrl);
|
|
58
|
-
if (!response.ok) {
|
|
59
|
-
throw new Error(`Failed to fetch bundle: HTTP ${response.status} ${response.statusText}`);
|
|
60
|
-
}
|
|
61
|
-
bundleContent = await response.text();
|
|
62
|
-
}
|
|
63
|
-
const nameParts = name.split("/");
|
|
64
|
-
const filePath = (0, import_node_path.join)(bundlesDir, ...nameParts) + ".js";
|
|
65
|
-
await (0, import_promises.mkdir)((0, import_node_path.dirname)(filePath), { recursive: true });
|
|
66
|
-
await (0, import_promises.writeFile)(filePath, bundleContent, "utf8");
|
|
67
|
-
if (lastModified) {
|
|
68
|
-
const mtime = new Date(lastModified);
|
|
69
|
-
await (0, import_promises.utimes)(filePath, mtime, mtime);
|
|
70
|
-
}
|
|
71
|
-
return filePath;
|
|
72
|
-
}
|
|
73
|
-
async function copyBundle(url, newName, bundlesDir) {
|
|
74
|
-
let srcPath;
|
|
75
|
-
if (url === "current") {
|
|
76
|
-
const sdePrepDir = (0, import_node_path.join)(bundlesDir, "..", "sde-prep");
|
|
77
|
-
srcPath = (0, import_node_path.join)(sdePrepDir, "check-bundle.js");
|
|
78
|
-
} else if (url.startsWith("file://")) {
|
|
79
|
-
srcPath = new URL(url).pathname;
|
|
80
|
-
} else {
|
|
81
|
-
throw new Error(`Cannot copy bundle with URL: ${url}`);
|
|
82
|
-
}
|
|
83
|
-
const bundleContent = await (0, import_promises.readFile)(srcPath, "utf8");
|
|
84
|
-
const stats = await (0, import_promises.stat)(srcPath);
|
|
85
|
-
const sourceLastModified = stats.mtime;
|
|
86
|
-
const nameParts = newName.split("/");
|
|
87
|
-
const filePath = (0, import_node_path.join)(bundlesDir, ...nameParts) + ".js";
|
|
88
|
-
await (0, import_promises.mkdir)((0, import_node_path.dirname)(filePath), { recursive: true });
|
|
89
|
-
await (0, import_promises.writeFile)(filePath, bundleContent, "utf8");
|
|
90
|
-
if (sourceLastModified) {
|
|
91
|
-
await (0, import_promises.utimes)(filePath, sourceLastModified, sourceLastModified);
|
|
92
|
-
}
|
|
93
|
-
return filePath;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// src/run-suite.ts
|
|
97
|
-
var import_perf_hooks = require("perf_hooks");
|
|
98
|
-
var import_picocolors = __toESM(require("picocolors"), 1);
|
|
99
|
-
var import_check_core = require("@sdeverywhere/check-core");
|
|
100
|
-
async function runTestSuite(context, config, verbose) {
|
|
101
|
-
return new Promise((resolve, reject) => {
|
|
102
|
-
const t0 = import_perf_hooks.performance.now();
|
|
103
|
-
let lastPctByInc;
|
|
104
|
-
const callbacks = {
|
|
105
|
-
onProgress: (progress) => {
|
|
106
|
-
const pct = Math.round(progress * 100);
|
|
107
|
-
const pctByInc = Math.floor(pct / 5) * 5;
|
|
108
|
-
if (lastPctByInc === void 0 || pctByInc > lastPctByInc) {
|
|
109
|
-
lastPctByInc = pctByInc;
|
|
110
|
-
context.log("info", `${pctByInc}%`);
|
|
111
|
-
}
|
|
112
|
-
},
|
|
113
|
-
onComplete: (report) => {
|
|
114
|
-
try {
|
|
115
|
-
const t1 = import_perf_hooks.performance.now();
|
|
116
|
-
const elapsedMillis = t1 - t0;
|
|
117
|
-
const elapsedSeconds = (elapsedMillis / 1e3).toFixed(1);
|
|
118
|
-
context.log("info", `
|
|
119
|
-
Test suite completed in ${elapsedSeconds}s`);
|
|
120
|
-
const allChecksPassed = printCheckSummary(context, report.checkReport, verbose);
|
|
121
|
-
if (report.comparisonReport) {
|
|
122
|
-
printPerfStats(context, config.comparison, report.comparisonReport);
|
|
123
|
-
}
|
|
124
|
-
const suiteSummary = (0, import_check_core.suiteSummaryFromReport)(report, elapsedMillis);
|
|
125
|
-
resolve({
|
|
126
|
-
allChecksPassed,
|
|
127
|
-
suiteSummary
|
|
128
|
-
});
|
|
129
|
-
} catch (e) {
|
|
130
|
-
reject(e);
|
|
131
|
-
}
|
|
132
|
-
},
|
|
133
|
-
onError: (error) => {
|
|
134
|
-
reject(error);
|
|
135
|
-
}
|
|
136
|
-
};
|
|
137
|
-
(0, import_check_core.runSuite)(config, callbacks);
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
function printCheckSummary(context, checkReport, verbose) {
|
|
141
|
-
function printResult(indent, status, text) {
|
|
142
|
-
if (!verbose && status === "passed" && indent > 1) {
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
let statusChar;
|
|
146
|
-
switch (status) {
|
|
147
|
-
case "passed":
|
|
148
|
-
statusChar = "\u2713";
|
|
149
|
-
break;
|
|
150
|
-
case "failed":
|
|
151
|
-
statusChar = "\u2717";
|
|
152
|
-
break;
|
|
153
|
-
case "error":
|
|
154
|
-
statusChar = "\u203C";
|
|
155
|
-
break;
|
|
156
|
-
case "skipped":
|
|
157
|
-
statusChar = "\u2013";
|
|
158
|
-
break;
|
|
159
|
-
default:
|
|
160
|
-
statusChar = "";
|
|
161
|
-
break;
|
|
162
|
-
}
|
|
163
|
-
const msg = `${" ".repeat(indent)}${statusChar} ${text}`;
|
|
164
|
-
context.log("info", status === "passed" ? import_picocolors.default.green(msg) : import_picocolors.default.red(msg));
|
|
165
|
-
}
|
|
166
|
-
function bold(s) {
|
|
167
|
-
return import_picocolors.default.bold(s);
|
|
168
|
-
}
|
|
169
|
-
function printTest(test) {
|
|
170
|
-
const msg = `${test.name}${verbose || test.status !== "passed" ? ":" : ""}`;
|
|
171
|
-
printResult(1, test.status, msg);
|
|
172
|
-
}
|
|
173
|
-
let allPassed = true;
|
|
174
|
-
context.log("info", "\nCheck results:");
|
|
175
|
-
for (const group of checkReport.groups) {
|
|
176
|
-
context.log("info", `
|
|
177
|
-
${group.name}`);
|
|
178
|
-
for (const test of group.tests) {
|
|
179
|
-
if (test.status !== "passed") {
|
|
180
|
-
allPassed = false;
|
|
181
|
-
}
|
|
182
|
-
printTest(test);
|
|
183
|
-
for (const scenario of test.scenarios) {
|
|
184
|
-
printResult(3, scenario.status, (0, import_check_core.scenarioMessage)(scenario, bold));
|
|
185
|
-
for (const dataset of scenario.datasets) {
|
|
186
|
-
printResult(5, dataset.status, (0, import_check_core.datasetMessage)(dataset, bold));
|
|
187
|
-
for (const predicate of dataset.predicates) {
|
|
188
|
-
printResult(7, predicate.result.status, (0, import_check_core.predicateMessage)(predicate, bold));
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
context.log("info", "");
|
|
195
|
-
return allPassed;
|
|
196
|
-
}
|
|
197
|
-
function stat2(label, n) {
|
|
198
|
-
return `${label}=${n.toFixed(1)}ms`;
|
|
199
|
-
}
|
|
200
|
-
function printPerfReportLine(context, perfReport) {
|
|
201
|
-
const avg = stat2("avg", perfReport.avgTime);
|
|
202
|
-
const min = stat2("min", perfReport.minTime);
|
|
203
|
-
const max = stat2("max", perfReport.maxTime);
|
|
204
|
-
context.log("info", ` ${avg} ${min} ${max}`);
|
|
205
|
-
}
|
|
206
|
-
function printPerfStats(context, comparisonConfig, report) {
|
|
207
|
-
context.log("info", "\nPerformance stats:");
|
|
208
|
-
context.log("info", ` ${comparisonConfig.bundleL.name}:`);
|
|
209
|
-
printPerfReportLine(context, report.perfReportL);
|
|
210
|
-
context.log("info", ` ${comparisonConfig.bundleR.name}:`);
|
|
211
|
-
printPerfReportLine(context, report.perfReportR);
|
|
212
|
-
context.log("info", "");
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
// src/vite-config-for-bundle.ts
|
|
216
|
-
var import_fs = require("fs");
|
|
217
|
-
var import_path = require("path");
|
|
218
|
-
var import_url = require("url");
|
|
219
|
-
var import_plugin_node_resolve = require("@rollup/plugin-node-resolve");
|
|
220
|
-
var import_check_core2 = require("@sdeverywhere/check-core");
|
|
221
|
-
var __filename2 = (0, import_url.fileURLToPath)(importMetaUrl);
|
|
222
|
-
var __dirname = (0, import_path.dirname)(__filename2);
|
|
223
|
-
function injectModelSpec(context, modelSpec) {
|
|
224
|
-
const prepDir = context.config.prepDir;
|
|
225
|
-
const inputSpecs = [];
|
|
226
|
-
for (const modelInputSpec of modelSpec.inputs) {
|
|
227
|
-
if (modelInputSpec.defaultValue === void 0 || modelInputSpec.minValue === void 0 || modelInputSpec.maxValue === void 0) {
|
|
228
|
-
let msg = "";
|
|
229
|
-
msg += `WARNING: The {defaultValue,minValue,maxValue} properties are required by plugin-check, `;
|
|
230
|
-
msg += `but are undefined in the InputSpec for '${modelInputSpec.varName}'. `;
|
|
231
|
-
msg += `This input variable will be excluded from the model-check bundle until those properties `;
|
|
232
|
-
msg += `are defined.`;
|
|
233
|
-
console.warn(msg);
|
|
234
|
-
continue;
|
|
235
|
-
}
|
|
236
|
-
const varId = context.canonicalVarId(modelInputSpec.varName);
|
|
237
|
-
const inputId = modelInputSpec.inputId || varId;
|
|
238
|
-
inputSpecs.push({
|
|
239
|
-
inputId,
|
|
240
|
-
varId,
|
|
241
|
-
...modelInputSpec
|
|
242
|
-
});
|
|
243
|
-
}
|
|
244
|
-
const outputSpecs = modelSpec.outputs.map((o) => {
|
|
245
|
-
return {
|
|
246
|
-
varId: context.canonicalVarId(o.varName),
|
|
247
|
-
...o
|
|
248
|
-
};
|
|
249
|
-
});
|
|
250
|
-
function readJsonListing() {
|
|
251
|
-
const path = (0, import_path.join)(prepDir, "build", "processed.json");
|
|
252
|
-
if ((0, import_fs.existsSync)(path)) {
|
|
253
|
-
const json = (0, import_fs.readFileSync)(path, "utf8");
|
|
254
|
-
return JSON.parse(json);
|
|
255
|
-
} else {
|
|
256
|
-
return {};
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
const listing = readJsonListing();
|
|
260
|
-
const varInstances = listing.varInstances || {};
|
|
261
|
-
const encodedImplVars = (0, import_check_core2.encodeImplVars)(varInstances);
|
|
262
|
-
function stagedFileSize(filename) {
|
|
263
|
-
const path = (0, import_path.join)(prepDir, "staged", "model", filename);
|
|
264
|
-
if ((0, import_fs.existsSync)(path)) {
|
|
265
|
-
return (0, import_fs.statSync)(path).size;
|
|
266
|
-
} else {
|
|
267
|
-
return 0;
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
const modelSizeInBytes = stagedFileSize("generated-model.js");
|
|
271
|
-
const dataSizeInBytes = stagedFileSize("static-data.ts");
|
|
272
|
-
const moduleSrc = `
|
|
273
|
-
export const inputSpecs = ${JSON.stringify(inputSpecs)};
|
|
274
|
-
export const outputSpecs = ${JSON.stringify(outputSpecs)};
|
|
275
|
-
export const encodedImplVars = ${JSON.stringify(encodedImplVars)};
|
|
276
|
-
export const modelSizeInBytes = ${modelSizeInBytes};
|
|
277
|
-
export const dataSizeInBytes = ${dataSizeInBytes};
|
|
278
|
-
`;
|
|
279
|
-
const virtualModuleId = "virtual:model-spec";
|
|
280
|
-
const resolvedVirtualModuleId = "\0" + virtualModuleId;
|
|
281
|
-
return {
|
|
282
|
-
name: "vite-plugin-virtual-custom",
|
|
283
|
-
resolveId(id) {
|
|
284
|
-
if (id === virtualModuleId) {
|
|
285
|
-
return resolvedVirtualModuleId;
|
|
286
|
-
}
|
|
287
|
-
},
|
|
288
|
-
load(id) {
|
|
289
|
-
if (id === resolvedVirtualModuleId) {
|
|
290
|
-
return moduleSrc;
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
};
|
|
294
|
-
}
|
|
295
|
-
function overrideViteResolvePlugin(viteConfig) {
|
|
296
|
-
const resolvePlugin = viteConfig.plugins.find((p) => p.name === "vite:resolve");
|
|
297
|
-
if (resolvePlugin === void 0) {
|
|
298
|
-
throw new Error("Failed to locate the built-in vite:resolve plugin");
|
|
299
|
-
}
|
|
300
|
-
const originalResolveId = resolvePlugin.resolveId;
|
|
301
|
-
resolvePlugin.resolveId = async function resolveId(id, importer, options) {
|
|
302
|
-
if (id.startsWith("./implementation") && importer.includes("threads/dist-esm")) {
|
|
303
|
-
const idFileName = id.replace("./", "");
|
|
304
|
-
const importerFileName = (0, import_path.basename)(importer);
|
|
305
|
-
const resolvedId = importer.replace(importerFileName, `${idFileName}.js`);
|
|
306
|
-
return {
|
|
307
|
-
id: resolvedId,
|
|
308
|
-
moduleSideEffects: false
|
|
309
|
-
};
|
|
310
|
-
}
|
|
311
|
-
return await originalResolveId.handler.call(this, id, importer, options);
|
|
312
|
-
};
|
|
313
|
-
}
|
|
314
|
-
async function createViteConfigForBundle(context, modelSpec) {
|
|
315
|
-
const root = (0, import_path.resolve)(__dirname, "..", "template-bundle");
|
|
316
|
-
const prepDir = context.config.prepDir;
|
|
317
|
-
const outDir = (0, import_path.relative)(root, prepDir);
|
|
318
|
-
const modelWorkerPath = (0, import_path.join)(prepDir, "staged", "model", "worker.js?raw");
|
|
319
|
-
return {
|
|
320
|
-
// Don't use an external config file
|
|
321
|
-
configFile: false,
|
|
322
|
-
// Use the root directory configured above
|
|
323
|
-
root,
|
|
324
|
-
// Don't clear the screen in dev mode so that we can see builder output
|
|
325
|
-
clearScreen: false,
|
|
326
|
-
// TODO: Disable vite output by default?
|
|
327
|
-
// logLevel: 'silent',
|
|
328
|
-
// Configure path aliases
|
|
329
|
-
resolve: {
|
|
330
|
-
alias: [
|
|
331
|
-
// Inject the configured model worker
|
|
332
|
-
{
|
|
333
|
-
find: "@_model_worker_",
|
|
334
|
-
replacement: modelWorkerPath
|
|
335
|
-
},
|
|
336
|
-
// XXX: Prevent Vite from using the `browser` section of `threads/package.json`
|
|
337
|
-
// since we want to force the use of the general module (under dist-esm) that chooses
|
|
338
|
-
// the correct implementation (Web Worker vs worker_threads) at runtime. Currently
|
|
339
|
-
// Vite's library mode is browser focused and generally chooses the right imports,
|
|
340
|
-
// except in the case of the threads package where we want to use the generic
|
|
341
|
-
// `implementation.js` that chooses between Web Worker and worker_threads at runtime.
|
|
342
|
-
// Note that we could in theory set `resolve.browserField` to false, but that would
|
|
343
|
-
// make Vite not use the browser field for all other packages, and there is not
|
|
344
|
-
// currently a way to tell Vite to use the browser field on a case-by-case basis.
|
|
345
|
-
// So for now we need this workaround here to make it resolve to `dist-esm`, and then
|
|
346
|
-
// a second workaround in `overrideViteResolvePlugin` to prevent the resolver from
|
|
347
|
-
// using the browser field when resolving the threads package.
|
|
348
|
-
{
|
|
349
|
-
find: "threads",
|
|
350
|
-
replacement: "threads",
|
|
351
|
-
customResolver: async function(source, importer, options) {
|
|
352
|
-
const customResolver = (0, import_plugin_node_resolve.nodeResolve)({ browser: false });
|
|
353
|
-
const resolveIdHook = customResolver.resolveId;
|
|
354
|
-
const resolveIdFn = typeof resolveIdHook === "function" ? resolveIdHook : resolveIdHook.handler;
|
|
355
|
-
const resolved = await resolveIdFn.call(this, source, importer, options);
|
|
356
|
-
if (source === "threads/worker") {
|
|
357
|
-
return resolved.id.replace("worker.mjs", "dist-esm/worker/index.js");
|
|
358
|
-
} else {
|
|
359
|
-
return resolved.id.replace("index.mjs", "dist-esm/index.js");
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
]
|
|
364
|
-
},
|
|
365
|
-
plugins: [
|
|
366
|
-
// Use a virtual module plugin to inject the model spec values
|
|
367
|
-
injectModelSpec(context, modelSpec),
|
|
368
|
-
// XXX: Install a wrapper around the built-in `vite:resolve` plugin so that we can
|
|
369
|
-
// override the default resolver behavior that tries to resolve the `browser` section
|
|
370
|
-
// of the `package.json` for the threads package.
|
|
371
|
-
{
|
|
372
|
-
name: "vite-plugin-override-resolve",
|
|
373
|
-
configResolved(viteConfig) {
|
|
374
|
-
overrideViteResolvePlugin(viteConfig);
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
],
|
|
378
|
-
build: {
|
|
379
|
-
// Write output files to the configured directory (instead of the default `dist`);
|
|
380
|
-
// note that this must be relative to the project `root`
|
|
381
|
-
outDir,
|
|
382
|
-
emptyOutDir: false,
|
|
383
|
-
// Uncomment for debugging purposes
|
|
384
|
-
// minify: false,
|
|
385
|
-
lib: {
|
|
386
|
-
entry: "./src/index.ts",
|
|
387
|
-
formats: ["es"],
|
|
388
|
-
fileName: () => "check-bundle.js"
|
|
389
|
-
},
|
|
390
|
-
rollupOptions: {
|
|
391
|
-
// Don't transform Node imports used by threads.js
|
|
392
|
-
external: ["events", "os", "path", "url"],
|
|
393
|
-
// XXX: Insert custom code at the top of the generated bundle that defines
|
|
394
|
-
// the special `__non_webpack_require__` function that is used by threads.js
|
|
395
|
-
// in its Node implementation. This import ensures that threads.js uses
|
|
396
|
-
// the native `worker_threads` implementation when using the bundle in a
|
|
397
|
-
// Node environment. When importing the bundle for use in the browser,
|
|
398
|
-
// Vite will transform this import into an empty module due to the empty
|
|
399
|
-
// polyfill that is configured in `vite-config-for-report.ts`.
|
|
400
|
-
output: {
|
|
401
|
-
banner: `
|
|
402
|
-
import * as worker_threads from 'worker_threads'
|
|
403
|
-
let __non_webpack_require__ = () => {
|
|
404
|
-
return worker_threads;
|
|
405
|
-
};
|
|
406
|
-
`
|
|
407
|
-
},
|
|
408
|
-
onwarn: (warning, warn) => {
|
|
409
|
-
if (warning.code !== "EVAL") {
|
|
410
|
-
warn(warning);
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
};
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
// src/vite-config-for-report.ts
|
|
419
|
-
var import_node_fs = require("fs");
|
|
420
|
-
var import_node_path3 = require("path");
|
|
421
|
-
var import_node_url2 = require("url");
|
|
422
|
-
var import_plugin_replace = __toESM(require("@rollup/plugin-replace"), 1);
|
|
423
|
-
|
|
424
|
-
// src/vite-local-bundles-plugin.ts
|
|
425
|
-
var import_promises2 = require("fs/promises");
|
|
426
|
-
var import_node_path2 = require("path");
|
|
427
|
-
var import_node_url = require("url");
|
|
428
|
-
var import_chokidar = __toESM(require("chokidar"), 1);
|
|
429
|
-
function localBundlesPlugin(bundlesDir, currentBundlePath, fetchRemoteBundle) {
|
|
430
|
-
return {
|
|
431
|
-
name: "sde-local-bundles",
|
|
432
|
-
configureServer(server) {
|
|
433
|
-
const watcher = import_chokidar.default.watch(bundlesDir, {
|
|
434
|
-
// Don't send initial "file added" events
|
|
435
|
-
ignoreInitial: true,
|
|
436
|
-
// XXX: Include a delay, otherwise on macOS we sometimes get multiple
|
|
437
|
-
// change events when a file is saved just once
|
|
438
|
-
awaitWriteFinish: {
|
|
439
|
-
stabilityThreshold: 200
|
|
440
|
-
},
|
|
441
|
-
// Watch up to 10 levels deep
|
|
442
|
-
depth: 10
|
|
443
|
-
});
|
|
444
|
-
watcher.on("all", (event) => {
|
|
445
|
-
if (event === "add" || event === "unlink") {
|
|
446
|
-
server.ws.send("bundles-changed", {});
|
|
447
|
-
}
|
|
448
|
-
});
|
|
449
|
-
server.httpServer?.on("close", () => {
|
|
450
|
-
watcher.close();
|
|
451
|
-
});
|
|
452
|
-
server.ws.on("list-bundles", async (_, client) => {
|
|
453
|
-
try {
|
|
454
|
-
const bundles = await scanBundlesRecursively(bundlesDir, bundlesDir);
|
|
455
|
-
const currentBundleStats = await (0, import_promises2.stat)(currentBundlePath);
|
|
456
|
-
bundles.push({
|
|
457
|
-
name: "current",
|
|
458
|
-
url: "current",
|
|
459
|
-
lastModified: currentBundleStats.mtime.toISOString()
|
|
460
|
-
});
|
|
461
|
-
client.send("list-bundles-success", { bundles });
|
|
462
|
-
} catch (error) {
|
|
463
|
-
console.error(`[sde-local-bundles] Failed to list bundles:`, error);
|
|
464
|
-
client.send("list-bundles-error", { error: error.message });
|
|
465
|
-
}
|
|
466
|
-
});
|
|
467
|
-
server.ws.on("load-bundle", async (data, client) => {
|
|
468
|
-
const { url, name } = data;
|
|
469
|
-
try {
|
|
470
|
-
let sourceCode;
|
|
471
|
-
if (url.startsWith("file://")) {
|
|
472
|
-
const filePath = (0, import_node_url.fileURLToPath)(url);
|
|
473
|
-
sourceCode = await (0, import_promises2.readFile)(filePath, "utf-8");
|
|
474
|
-
} else if (url.startsWith("https://") || url.startsWith("http://")) {
|
|
475
|
-
const fullUrl = `${url}?cb=${Date.now()}`;
|
|
476
|
-
if (fetchRemoteBundle) {
|
|
477
|
-
sourceCode = await fetchRemoteBundle(fullUrl);
|
|
478
|
-
} else {
|
|
479
|
-
const response = await fetch(fullUrl);
|
|
480
|
-
if (!response.ok) {
|
|
481
|
-
throw new Error(`Failed to fetch bundle: ${response.status} ${response.statusText}`);
|
|
482
|
-
}
|
|
483
|
-
sourceCode = await response.text();
|
|
484
|
-
}
|
|
485
|
-
} else {
|
|
486
|
-
throw new Error(`Unsupported URL scheme: ${url}`);
|
|
487
|
-
}
|
|
488
|
-
client.send("load-bundle-success", { name, url, sourceCode });
|
|
489
|
-
} catch (error) {
|
|
490
|
-
console.error(`[sde-local-bundles] Failed to load bundle:`, error);
|
|
491
|
-
client.send("load-bundle-error", { name, url, error: error.message });
|
|
492
|
-
}
|
|
493
|
-
});
|
|
494
|
-
server.ws.on("download-bundle", async (data, client) => {
|
|
495
|
-
const { url, name, lastModified } = data;
|
|
496
|
-
try {
|
|
497
|
-
console.log(`[sde-local-bundles] Downloading bundle: name=${name} url=${url}`);
|
|
498
|
-
const filePath = await downloadBundle(url, name, lastModified, bundlesDir, fetchRemoteBundle);
|
|
499
|
-
console.log(`[sde-local-bundles] Downloaded bundle to ${filePath}`);
|
|
500
|
-
client.send("download-bundle-success", { name, filePath: `${name}.js` });
|
|
501
|
-
} catch (error) {
|
|
502
|
-
console.error(`[sde-local-bundles] Failed to download bundle:`, error);
|
|
503
|
-
client.send("download-bundle-error", { name, error: error.message });
|
|
504
|
-
}
|
|
505
|
-
});
|
|
506
|
-
server.ws.on("copy-bundle", async (data, client) => {
|
|
507
|
-
const { url, name, newName } = data;
|
|
508
|
-
try {
|
|
509
|
-
console.log(`[sde-local-bundles] Copying bundle: src=${name} dst=${newName}`);
|
|
510
|
-
const filePath = await copyBundle(url, newName, bundlesDir);
|
|
511
|
-
console.log(`[sde-local-bundles] Copied bundle to ${filePath}`);
|
|
512
|
-
client.send("copy-bundle-success", { name: newName, filePath: `${newName}.js` });
|
|
513
|
-
} catch (error) {
|
|
514
|
-
console.error(`[sde-local-bundles] Failed to copy bundle:`, error);
|
|
515
|
-
client.send("copy-bundle-error", { name, error: error.message });
|
|
516
|
-
}
|
|
517
|
-
});
|
|
518
|
-
}
|
|
519
|
-
};
|
|
520
|
-
}
|
|
521
|
-
async function scanBundlesRecursively(dir, baseDir) {
|
|
522
|
-
const bundles = [];
|
|
523
|
-
const entries = await (0, import_promises2.readdir)(dir, { withFileTypes: true });
|
|
524
|
-
for (const entry of entries) {
|
|
525
|
-
const fullPath = (0, import_node_path2.join)(dir, entry.name);
|
|
526
|
-
if (entry.isDirectory()) {
|
|
527
|
-
const subBundles = await scanBundlesRecursively(fullPath, baseDir);
|
|
528
|
-
bundles.push(...subBundles);
|
|
529
|
-
} else if (entry.isFile() && entry.name.endsWith(".js")) {
|
|
530
|
-
const stats = await (0, import_promises2.stat)(fullPath);
|
|
531
|
-
const relativePath = (0, import_node_path2.relative)(baseDir, fullPath);
|
|
532
|
-
const name = relativePath.replace(/\.js$/, "").split(import_node_path2.sep).join("/");
|
|
533
|
-
bundles.push({
|
|
534
|
-
name,
|
|
535
|
-
url: (0, import_node_url.pathToFileURL)(fullPath).toString(),
|
|
536
|
-
lastModified: stats.mtime.toISOString()
|
|
537
|
-
});
|
|
538
|
-
}
|
|
539
|
-
}
|
|
540
|
-
return bundles;
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
// src/vite-config-for-report.ts
|
|
544
|
-
var __filename3 = (0, import_node_url2.fileURLToPath)(importMetaUrl);
|
|
545
|
-
var __dirname2 = (0, import_node_path3.dirname)(__filename3);
|
|
546
|
-
function createViteConfigForReport(mode, options, projDir, prepDir, currentBundleSpec, baselineBundleSpec, testConfigPath, suiteSummary) {
|
|
547
|
-
const root = (0, import_node_path3.resolve)(__dirname2, "..", "template-report");
|
|
548
|
-
const bundlesDir = (0, import_node_path3.resolve)(projDir, "bundles");
|
|
549
|
-
if (!(0, import_node_fs.existsSync)(bundlesDir)) {
|
|
550
|
-
(0, import_node_fs.mkdirSync)(bundlesDir, { recursive: true });
|
|
551
|
-
}
|
|
552
|
-
const templateSrcDir = (0, import_node_path3.resolve)(root, "src");
|
|
553
|
-
const relProjDir = (0, import_node_path3.relative)(templateSrcDir, projDir);
|
|
554
|
-
const relProjDirPath = relProjDir.replaceAll("\\", "/");
|
|
555
|
-
const bundlesPath = `${relProjDirPath}/bundles/**/*.js`;
|
|
556
|
-
let reportPath;
|
|
557
|
-
if (options?.reportPath) {
|
|
558
|
-
reportPath = options.reportPath;
|
|
559
|
-
} else {
|
|
560
|
-
reportPath = (0, import_node_path3.join)(prepDir, "check-report");
|
|
561
|
-
}
|
|
562
|
-
const outDir = (0, import_node_path3.relative)(root, reportPath);
|
|
563
|
-
const suiteSummaryJson = suiteSummary ? JSON.stringify(suiteSummary) : "";
|
|
564
|
-
const alias = (find, replacement) => {
|
|
565
|
-
return {
|
|
566
|
-
find,
|
|
567
|
-
replacement
|
|
568
|
-
};
|
|
569
|
-
};
|
|
570
|
-
const noopPolyfillAlias = (find) => {
|
|
571
|
-
return {
|
|
572
|
-
find,
|
|
573
|
-
replacement: "/polyfills/noop-polyfills.ts"
|
|
574
|
-
};
|
|
575
|
-
};
|
|
576
|
-
return {
|
|
577
|
-
// Don't use an external config file
|
|
578
|
-
configFile: false,
|
|
579
|
-
// Use the root directory configured above
|
|
580
|
-
root,
|
|
581
|
-
// Use `.` as the base directory (instead of the default `/`); this controls
|
|
582
|
-
// how the path to the js/css files are generated in `index.html`
|
|
583
|
-
base: "",
|
|
584
|
-
// Use a custom cache directory under `prepDir`, as otherwise Vite will use
|
|
585
|
-
// `packages/plugin-check/template-report/node_modules/.vite`, and we want to
|
|
586
|
-
// avoid generating files in `template-report` (which should be read-only)
|
|
587
|
-
cacheDir: (0, import_node_path3.join)(prepDir, ".vite-check-report"),
|
|
588
|
-
// Load static files from `static` (instead of the default `public`)
|
|
589
|
-
// publicDir: 'static',
|
|
590
|
-
// Don't clear the screen in dev mode so that we can see builder output
|
|
591
|
-
clearScreen: false,
|
|
592
|
-
// TODO
|
|
593
|
-
// logLevel: 'silent',
|
|
594
|
-
optimizeDeps: {
|
|
595
|
-
// Prevent Vite from examining other html files when scanning entrypoints
|
|
596
|
-
// for dependency optimization
|
|
597
|
-
entries: ["index.html"],
|
|
598
|
-
// XXX: When plugin-check is installed via pnpm, the Vite dev server seems
|
|
599
|
-
// to have no trouble resolving other dependencies using the optimizeDeps
|
|
600
|
-
// mechanism. However, this fails when the package is installed via yarn
|
|
601
|
-
// or npm (probably due to the fact that the `template-report` directory
|
|
602
|
-
// is located under the top-level `node_modules` directory); in the browser,
|
|
603
|
-
// there will be "import not found" errors for the packages referenced below.
|
|
604
|
-
// As a terrible workaround, explicitly include the direct dependencies so
|
|
605
|
-
// that Vite optimizes them; this works for pnpm, yarn, and npm. We should
|
|
606
|
-
// find a less fragile solution.
|
|
607
|
-
include: [
|
|
608
|
-
// from check-core
|
|
609
|
-
"@sdeverywhere/check-core > assert-never",
|
|
610
|
-
"@sdeverywhere/check-core > ajv",
|
|
611
|
-
"@sdeverywhere/check-core > neverthrow",
|
|
612
|
-
"@sdeverywhere/check-core > yaml",
|
|
613
|
-
// from check-ui-shell
|
|
614
|
-
"@sdeverywhere/check-ui-shell > fontfaceobserver",
|
|
615
|
-
"@sdeverywhere/check-ui-shell > copy-text-to-clipboard",
|
|
616
|
-
"@sdeverywhere/check-ui-shell > chart.js"
|
|
617
|
-
],
|
|
618
|
-
exclude: [
|
|
619
|
-
// XXX: The threads.js implementation references `tiny-worker` as an optional
|
|
620
|
-
// dependency, but it doesn't get used at runtime, so we can just exclude it
|
|
621
|
-
// so that Vite doesn't complain in dev mode
|
|
622
|
-
"tiny-worker"
|
|
623
|
-
// XXX: Similarly, chart.js treats `moment` as an optional dependency, but we
|
|
624
|
-
// don't use it at runtime; we need to exclude it here, otherwise Vite will
|
|
625
|
-
// complain about missing dependencies in dev mode
|
|
626
|
-
// 'moment'
|
|
627
|
-
]
|
|
628
|
-
},
|
|
629
|
-
// Configure path aliases
|
|
630
|
-
resolve: {
|
|
631
|
-
alias: [
|
|
632
|
-
// Use the configured "baseline" bundle if defined, otherwise use the "empty" bundle
|
|
633
|
-
// (which will cause comparison tests to be skipped)
|
|
634
|
-
alias("@_baseline_bundle_", baselineBundleSpec?.path || "/src/empty-bundle.ts"),
|
|
635
|
-
// Use the configured "current" bundle
|
|
636
|
-
alias("@_current_bundle_", currentBundleSpec.path),
|
|
637
|
-
// Use the configured test config file
|
|
638
|
-
alias("@_test_config_", testConfigPath),
|
|
639
|
-
// Make the overlay use the `messages.html` file that is written to the prep directory
|
|
640
|
-
alias("@_prep_", prepDir),
|
|
641
|
-
// XXX: Include no-op polyfills for these modules that are used in the Node-specific
|
|
642
|
-
// implementation of threads.js; this allows us to use one bundle that works in both
|
|
643
|
-
// Node and browser environments
|
|
644
|
-
noopPolyfillAlias("events"),
|
|
645
|
-
noopPolyfillAlias("fs"),
|
|
646
|
-
noopPolyfillAlias("os"),
|
|
647
|
-
noopPolyfillAlias("path"),
|
|
648
|
-
noopPolyfillAlias("url"),
|
|
649
|
-
noopPolyfillAlias("worker_threads")
|
|
650
|
-
]
|
|
651
|
-
},
|
|
652
|
-
// Inject special values into the generated JS
|
|
653
|
-
define: {
|
|
654
|
-
// Inject the summary JSON into the build
|
|
655
|
-
__SUITE_SUMMARY_JSON__: JSON.stringify(suiteSummaryJson),
|
|
656
|
-
// Inject the baseline bundle name
|
|
657
|
-
__BASELINE_NAME__: JSON.stringify(baselineBundleSpec?.name || ""),
|
|
658
|
-
// Inject the current bundle name
|
|
659
|
-
__CURRENT_NAME__: JSON.stringify(currentBundleSpec.name),
|
|
660
|
-
// Inject the remote bundles URL
|
|
661
|
-
__REMOTE_BUNDLES_URL__: JSON.stringify(options?.remoteBundlesUrl || "")
|
|
662
|
-
},
|
|
663
|
-
plugins: [
|
|
664
|
-
// Inject special values into the generated JS
|
|
665
|
-
// TODO: We currently have to use `@rollup/plugin-replace` instead of Vite's
|
|
666
|
-
// built-in `define` feature because the latter does not seem to run before
|
|
667
|
-
// the glob handler (which requires the glob to be injected as a literal)
|
|
668
|
-
(0, import_plugin_replace.default)({
|
|
669
|
-
preventAssignment: true,
|
|
670
|
-
delimiters: ["", ""],
|
|
671
|
-
values: {
|
|
672
|
-
// Inject the path for baseline bundles
|
|
673
|
-
// XXX: Note that we use './bundles/**/*.txt' instead of something special
|
|
674
|
-
// like './__BASELINE_BUNDLES_PATH__' because sometimes Vite's dependency
|
|
675
|
-
// scanner sees the latter (instead of the injected path) and reports
|
|
676
|
-
// an error since the path does not exist. As a workaround, we use
|
|
677
|
-
// './bundles/**/*.txt', which gets interpreted as the valid path
|
|
678
|
-
// '.../template-report/src/bundles/**/*.txt' (see `bundles/unused.txt`).
|
|
679
|
-
"./bundles/**/*.txt": bundlesPath
|
|
680
|
-
}
|
|
681
|
-
}),
|
|
682
|
-
// When local development mode is active, enable the local bundles plugin that
|
|
683
|
-
// allows the report app to access the local bundles directory
|
|
684
|
-
...mode === "watch" ? [localBundlesPlugin(bundlesDir, currentBundleSpec.path, options?.fetchRemoteBundle)] : []
|
|
685
|
-
],
|
|
686
|
-
build: {
|
|
687
|
-
// Write output files to the configured directory (instead of the default `dist`);
|
|
688
|
-
// note that this must be relative to the project `root`
|
|
689
|
-
outDir,
|
|
690
|
-
// Write js/css files to `public` (instead of the default `<outDir>/assets`)
|
|
691
|
-
assetsDir: "",
|
|
692
|
-
rollupOptions: {
|
|
693
|
-
output: {
|
|
694
|
-
// XXX: Prevent vite from creating a separate `vendor.js` file
|
|
695
|
-
manualChunks: void 0
|
|
696
|
-
},
|
|
697
|
-
onwarn: (warning, warn) => {
|
|
698
|
-
if (warning.code !== "EVAL") {
|
|
699
|
-
warn(warning);
|
|
700
|
-
}
|
|
701
|
-
}
|
|
702
|
-
}
|
|
703
|
-
},
|
|
704
|
-
server: {
|
|
705
|
-
// Run the dev server at `localhost:8081` by default
|
|
706
|
-
port: options?.serverPort || 8081,
|
|
707
|
-
// Open the app in the browser by default
|
|
708
|
-
open: "/index.html",
|
|
709
|
-
// XXX: Add a small delay, otherwise on macOS we sometimes get multiple
|
|
710
|
-
// change events when a file is saved just once. That is a relatively
|
|
711
|
-
// harmless issue except that it causes redundant messages in the console
|
|
712
|
-
// and can cause extra churn when refreshing the app.
|
|
713
|
-
watch: {
|
|
714
|
-
awaitWriteFinish: {
|
|
715
|
-
stabilityThreshold: 100
|
|
716
|
-
}
|
|
717
|
-
}
|
|
718
|
-
}
|
|
719
|
-
};
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
// src/vite-config-for-tests.ts
|
|
723
|
-
var import_path2 = require("path");
|
|
724
|
-
var import_url2 = require("url");
|
|
725
|
-
var import_plugin_replace2 = __toESM(require("@rollup/plugin-replace"), 1);
|
|
726
|
-
var __filename4 = (0, import_url2.fileURLToPath)(importMetaUrl);
|
|
727
|
-
var __dirname3 = (0, import_path2.dirname)(__filename4);
|
|
728
|
-
function createViteConfigForTests(mode, projDir, prepDir) {
|
|
729
|
-
const root = (0, import_path2.resolve)(__dirname3, "..", "template-tests");
|
|
730
|
-
const templateSrcDir = (0, import_path2.resolve)(root, "src");
|
|
731
|
-
const relProjDir = (0, import_path2.relative)(templateSrcDir, projDir);
|
|
732
|
-
const relProjDirPath = relProjDir.replaceAll("\\", "/");
|
|
733
|
-
const yamlCheckGlobPatterns = `['${relProjDirPath}/**/checks/*.yaml', '${relProjDirPath}/**/*.check.yaml']`;
|
|
734
|
-
const yamlComparisonGlobPatterns = `['${relProjDirPath}/**/comparisons/*.yaml']`;
|
|
735
|
-
const outDir = (0, import_path2.relative)(root, prepDir);
|
|
736
|
-
return {
|
|
737
|
-
// Don't use an external config file
|
|
738
|
-
configFile: false,
|
|
739
|
-
// Use the root directory configured above
|
|
740
|
-
root,
|
|
741
|
-
// Don't clear the screen in dev mode so that we can see builder output
|
|
742
|
-
clearScreen: false,
|
|
743
|
-
// TODO: Disable vite output by default?
|
|
744
|
-
// logLevel: 'silent',
|
|
745
|
-
plugins: [
|
|
746
|
-
// Inject special values into the generated JS
|
|
747
|
-
// TODO: We currently have to use `@rollup/plugin-replace` instead of Vite's
|
|
748
|
-
// built-in `define` feature because the latter does not seem to run before
|
|
749
|
-
// the glob handler (which requires the glob to be injected as a literal)
|
|
750
|
-
(0, import_plugin_replace2.default)({
|
|
751
|
-
preventAssignment: true,
|
|
752
|
-
delimiters: ["", ""],
|
|
753
|
-
values: {
|
|
754
|
-
// Inject the glob patterns for matching model check yaml files
|
|
755
|
-
'"./__YAML_CHECK_GLOB_PATTERNS__"': yamlCheckGlobPatterns,
|
|
756
|
-
// Inject the glob patterns for matching model comparison yaml files
|
|
757
|
-
'"./__YAML_COMPARISON_GLOB_PATTERNS__"': yamlComparisonGlobPatterns
|
|
758
|
-
}
|
|
759
|
-
})
|
|
760
|
-
],
|
|
761
|
-
build: {
|
|
762
|
-
// Write output files to the configured directory (instead of the default `dist`);
|
|
763
|
-
// note that this must be relative to the project `root`
|
|
764
|
-
outDir,
|
|
765
|
-
emptyOutDir: false,
|
|
766
|
-
lib: {
|
|
767
|
-
entry: "./src/index.ts",
|
|
768
|
-
formats: ["es"],
|
|
769
|
-
fileName: () => "check-tests.js"
|
|
770
|
-
},
|
|
771
|
-
// Enable watch mode if requested
|
|
772
|
-
watch: mode === "watch" && {},
|
|
773
|
-
rollupOptions: {
|
|
774
|
-
// Prevent dependencies from being included in packaged library
|
|
775
|
-
// TODO: For now we include check-core in the packaged library so that its
|
|
776
|
-
// dependencies are correctly resolved at runtime. Ideally this would only
|
|
777
|
-
// include a couple functions that are used for defining tests, but Vite 2.x
|
|
778
|
-
// does not implement tree shaking for ES libraries, which means the generated
|
|
779
|
-
// library is much larger than it needs to be. Once we upgrade to Vite 3.x,
|
|
780
|
-
// the generated library should be smaller; see related fix:
|
|
781
|
-
// https://github.com/vitejs/vite/pull/8737
|
|
782
|
-
// external: Object.keys(pkg.dependencies)
|
|
783
|
-
}
|
|
784
|
-
}
|
|
785
|
-
};
|
|
786
|
-
}
|
|
787
|
-
|
|
788
|
-
// src/plugin.ts
|
|
789
|
-
function checkPlugin(options) {
|
|
790
|
-
return new CheckPlugin(options);
|
|
791
|
-
}
|
|
792
|
-
var CheckPlugin = class {
|
|
793
|
-
constructor(options) {
|
|
794
|
-
this.options = options;
|
|
795
|
-
this.firstBuild = true;
|
|
796
|
-
}
|
|
797
|
-
async watch(config) {
|
|
798
|
-
if (this.options?.testConfigPath === void 0) {
|
|
799
|
-
await this.genTestConfig("watch", config);
|
|
800
|
-
}
|
|
801
|
-
const testOptions = await this.resolveTestOptions("watch", config);
|
|
802
|
-
const viteConfig = await this.createViteConfigForReport("watch", config, testOptions, void 0);
|
|
803
|
-
const server = await (0, import_vite.createServer)(viteConfig);
|
|
804
|
-
await server.listen();
|
|
805
|
-
}
|
|
806
|
-
// TODO: Note that this plugin runs as a `postBuild` step because it currently
|
|
807
|
-
// needs to run after other plugins, and those plugins need to run after the
|
|
808
|
-
// staged files are copied to their final destination(s). We should probably
|
|
809
|
-
// make it configurable so that it can either be run as a `postGenerate` or a
|
|
810
|
-
// `postBuild` step.
|
|
811
|
-
async postBuild(context, modelSpec) {
|
|
812
|
-
const firstBuild = this.firstBuild;
|
|
813
|
-
this.firstBuild = false;
|
|
814
|
-
if (this.options?.current?.path === void 0 && this.options?.current?.url === void 0) {
|
|
815
|
-
if (context.config.mode === "development") {
|
|
816
|
-
await this.copyPreviousBundle(context.config);
|
|
817
|
-
}
|
|
818
|
-
context.log("info", "Generating model check bundle...");
|
|
819
|
-
await this.genCurrentBundle(context, modelSpec);
|
|
820
|
-
}
|
|
821
|
-
if (this.options?.testConfigPath === void 0) {
|
|
822
|
-
if (context.config.mode === "production" || firstBuild) {
|
|
823
|
-
context.log("info", "Generating model check test configuration...");
|
|
824
|
-
await this.genTestConfig("bundle", context.config);
|
|
825
|
-
}
|
|
826
|
-
}
|
|
827
|
-
if (context.config.mode === "production") {
|
|
828
|
-
const testOptions = await this.resolveTestOptions("bundle", context.config);
|
|
829
|
-
return this.runChecks(context, testOptions);
|
|
830
|
-
} else {
|
|
831
|
-
return true;
|
|
832
|
-
}
|
|
833
|
-
}
|
|
834
|
-
async copyPreviousBundle(config) {
|
|
835
|
-
const currentBundleFile = (0, import_node_path4.join)(config.prepDir, "check-bundle.js");
|
|
836
|
-
if ((0, import_node_fs2.existsSync)(currentBundleFile)) {
|
|
837
|
-
const bundlesDir = (0, import_node_path4.join)(config.rootDir, "bundles");
|
|
838
|
-
if (!(0, import_node_fs2.existsSync)(bundlesDir)) {
|
|
839
|
-
await (0, import_promises3.mkdir)(bundlesDir, { recursive: true });
|
|
840
|
-
}
|
|
841
|
-
const previousBundleFile = (0, import_node_path4.join)(bundlesDir, "previous.js");
|
|
842
|
-
await (0, import_promises3.copyFile)(currentBundleFile, previousBundleFile);
|
|
843
|
-
}
|
|
844
|
-
}
|
|
845
|
-
async genCurrentBundle(context, modelSpec) {
|
|
846
|
-
const viteConfig = await createViteConfigForBundle(context, modelSpec);
|
|
847
|
-
await (0, import_vite.build)(viteConfig);
|
|
848
|
-
}
|
|
849
|
-
async genTestConfig(mode, config) {
|
|
850
|
-
const rootDir = config.rootDir;
|
|
851
|
-
const prepDir = config.prepDir;
|
|
852
|
-
const viteConfig = createViteConfigForTests(mode, rootDir, prepDir);
|
|
853
|
-
await (0, import_vite.build)(viteConfig);
|
|
854
|
-
}
|
|
855
|
-
async runChecks(context, testOptions) {
|
|
856
|
-
context.log("info", "Running model checks...");
|
|
857
|
-
async function importBundleModule(bundleSpec) {
|
|
858
|
-
return import(relativeToSourcePath(bundleSpec.path));
|
|
859
|
-
}
|
|
860
|
-
const moduleR = await importBundleModule(testOptions.currentBundleSpec);
|
|
861
|
-
const bundleR = moduleR.createBundle();
|
|
862
|
-
const bundleNameR = testOptions.currentBundleSpec.name;
|
|
863
|
-
let bundleL;
|
|
864
|
-
let bundleNameL;
|
|
865
|
-
if (testOptions.baselineBundleSpec !== void 0) {
|
|
866
|
-
const moduleL = await importBundleModule(testOptions.baselineBundleSpec);
|
|
867
|
-
const rawBundleL = moduleL.createBundle();
|
|
868
|
-
if (rawBundleL.version === bundleR.version) {
|
|
869
|
-
bundleL = rawBundleL;
|
|
870
|
-
bundleNameL = testOptions.baselineBundleSpec.name || "base";
|
|
871
|
-
} else {
|
|
872
|
-
console.warn(
|
|
873
|
-
`WARNING: Bundle version mismatch (baseline=${rawBundleL.version} current=${bundleR.version}); check tests will be run but comparisons will be skipped`
|
|
874
|
-
);
|
|
875
|
-
}
|
|
876
|
-
}
|
|
877
|
-
const testConfigModule = await import(relativeToSourcePath(testOptions.testConfigPath));
|
|
878
|
-
const configInitOptions = {
|
|
879
|
-
bundleNameL,
|
|
880
|
-
bundleNameR
|
|
881
|
-
};
|
|
882
|
-
const configOptions = await testConfigModule.getConfigOptions(bundleL, bundleR, configInitOptions);
|
|
883
|
-
const checkConfig = await (0, import_check_core3.createConfig)(configOptions);
|
|
884
|
-
const result = await runTestSuite(
|
|
885
|
-
context,
|
|
886
|
-
checkConfig,
|
|
887
|
-
/*verbose=*/
|
|
888
|
-
false
|
|
889
|
-
);
|
|
890
|
-
context.log("info", "Building model check report");
|
|
891
|
-
const viteConfig = await this.createViteConfigForReport("bundle", context.config, testOptions, result.suiteSummary);
|
|
892
|
-
await (0, import_vite.build)(viteConfig);
|
|
893
|
-
return result.allChecksPassed;
|
|
894
|
-
}
|
|
895
|
-
async resolveTestOptions(mode, config) {
|
|
896
|
-
const fetchRemoteBundle = this.options?.fetchRemoteBundle;
|
|
897
|
-
async function resolveBundle(bundle) {
|
|
898
|
-
if (bundle?.url !== void 0) {
|
|
899
|
-
const localBundlePath = await downloadBundle(
|
|
900
|
-
bundle.url,
|
|
901
|
-
bundle.name,
|
|
902
|
-
// TODO: We don't know the last modified time of the remote bundle here, so we use
|
|
903
|
-
// undefined (which means the local file will be created with the current timestamp)
|
|
904
|
-
void 0,
|
|
905
|
-
(0, import_node_path4.join)(config.rootDir, "bundles"),
|
|
906
|
-
fetchRemoteBundle
|
|
907
|
-
);
|
|
908
|
-
return {
|
|
909
|
-
name: bundle.name,
|
|
910
|
-
path: localBundlePath
|
|
911
|
-
};
|
|
912
|
-
} else if (bundle?.path !== void 0) {
|
|
913
|
-
return {
|
|
914
|
-
name: bundle.name,
|
|
915
|
-
path: bundle.path
|
|
916
|
-
};
|
|
917
|
-
} else {
|
|
918
|
-
return {
|
|
919
|
-
name: bundle?.name || "current",
|
|
920
|
-
path: (0, import_node_path4.join)(config.prepDir, "check-bundle.js")
|
|
921
|
-
};
|
|
922
|
-
}
|
|
923
|
-
}
|
|
924
|
-
const currentBundleSpec = await resolveBundle(this.options?.current);
|
|
925
|
-
let baselineBundleSpec;
|
|
926
|
-
if (mode === "bundle" && this.options?.baseline) {
|
|
927
|
-
try {
|
|
928
|
-
baselineBundleSpec = await resolveBundle(this.options.baseline);
|
|
929
|
-
} catch (e) {
|
|
930
|
-
const name = this.options.baseline.name;
|
|
931
|
-
const loc = this.options.baseline.url || this.options.baseline.path;
|
|
932
|
-
console.warn(
|
|
933
|
-
`WARNING: Failed to load '${name}' bundle from '${loc}'; check tests will be run but comparisons will be skipped. Cause:`,
|
|
934
|
-
e
|
|
935
|
-
);
|
|
936
|
-
}
|
|
937
|
-
}
|
|
938
|
-
let testConfigPath;
|
|
939
|
-
if (this.options?.testConfigPath === void 0) {
|
|
940
|
-
testConfigPath = (0, import_node_path4.join)(config.prepDir, "check-tests.js");
|
|
941
|
-
} else {
|
|
942
|
-
testConfigPath = this.options.testConfigPath;
|
|
943
|
-
}
|
|
944
|
-
return {
|
|
945
|
-
currentBundleSpec,
|
|
946
|
-
baselineBundleSpec,
|
|
947
|
-
testConfigPath
|
|
948
|
-
};
|
|
949
|
-
}
|
|
950
|
-
async createViteConfigForReport(mode, config, testOptions, suiteSummary) {
|
|
951
|
-
return createViteConfigForReport(
|
|
952
|
-
mode,
|
|
953
|
-
this.options,
|
|
954
|
-
config.rootDir,
|
|
955
|
-
config.prepDir,
|
|
956
|
-
testOptions.currentBundleSpec,
|
|
957
|
-
testOptions.baselineBundleSpec,
|
|
958
|
-
testOptions.testConfigPath,
|
|
959
|
-
suiteSummary
|
|
960
|
-
);
|
|
961
|
-
}
|
|
962
|
-
};
|
|
963
|
-
function relativeToSourcePath(filePath) {
|
|
964
|
-
const srcDir = (0, import_node_path4.dirname)((0, import_url3.fileURLToPath)(importMetaUrl));
|
|
965
|
-
const relPath = (0, import_node_path4.relative)(srcDir, filePath);
|
|
966
|
-
return relPath.replaceAll("\\", "/");
|
|
967
|
-
}
|
|
968
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
969
|
-
0 && (module.exports = {
|
|
970
|
-
checkPlugin
|
|
971
|
-
});
|
|
972
|
-
//# sourceMappingURL=index.cjs.map
|