@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.
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/index.ts","../../../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","../src/plugin.ts","../src/bundle-file-ops.ts","../src/run-suite.ts","../src/vite-config-for-bundle.ts","../src/vite-config-for-report.ts","../src/vite-local-bundles-plugin.ts","../src/vite-config-for-tests.ts"],"sourcesContent":["// Copyright (c) 2022 Climate Interactive / New Venture Fund\n\nexport type { CheckBundle, CheckPluginOptions } from './options'\nexport { checkPlugin } from './plugin'\n","// Shim globals in cjs bundle\n// There's a weird bug that esbuild will always inject importMetaUrl\n// if we export it as `const importMetaUrl = ... __filename ...`\n// But using a function will not cause this issue\n\nconst getImportMetaUrl = () => \n typeof document === \"undefined\" \n ? new URL(`file:${__filename}`).href \n : (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') \n ? document.currentScript.src \n : new URL(\"main.js\", document.baseURI).href;\n\nexport const importMetaUrl = /* @__PURE__ */ getImportMetaUrl()\n","// Copyright (c) 2022 Climate Interactive / New Venture Fund\n\nimport { existsSync } from 'node:fs'\nimport { copyFile, mkdir } from 'node:fs/promises'\nimport { dirname, join as joinPath, relative } from 'node:path'\nimport { fileURLToPath } from 'url'\n\nimport type { InlineConfig, ViteDevServer } from 'vite'\nimport { build, createServer } from 'vite'\n\nimport type { BuildContext, Plugin, ResolvedConfig, ResolvedModelSpec } from '@sdeverywhere/build'\n\nimport type { Bundle, ConfigInitOptions, SuiteSummary } from '@sdeverywhere/check-core'\nimport { createConfig } from '@sdeverywhere/check-core'\n\nimport { downloadBundle } from './bundle-file-ops'\nimport type { LocalBundleSpec } from './bundle-spec'\nimport type { CheckBundle, CheckPluginOptions } from './options'\nimport { runTestSuite } from './run-suite'\nimport { createViteConfigForBundle } from './vite-config-for-bundle'\nimport { createViteConfigForReport } from './vite-config-for-report'\nimport { createViteConfigForTests } from './vite-config-for-tests'\n\nexport function checkPlugin(options?: CheckPluginOptions): Plugin {\n return new CheckPlugin(options)\n}\n\ninterface TestOptions {\n currentBundleSpec: LocalBundleSpec\n baselineBundleSpec: LocalBundleSpec | undefined\n testConfigPath: string\n}\n\nclass CheckPlugin implements Plugin {\n private firstBuild = true\n\n constructor(private readonly options?: CheckPluginOptions) {}\n\n async watch(config: ResolvedConfig): Promise<void> {\n if (this.options?.testConfigPath === undefined) {\n // Test config was not provided, so generate a default config in watch mode.\n // The test template uses import.meta.glob so that checks are re-run\n // automatically when the `{checks/comparisons}/*.yaml` files are changed.\n await this.genTestConfig('watch', config)\n }\n\n // For development mode, run Vite in dev mode so that it serves the\n // model-check report locally (with live reload enabled). When a model\n // test file is changed, the tests will be re-run in the browser.\n const testOptions = await this.resolveTestOptions('watch', config)\n const viteConfig = await this.createViteConfigForReport('watch', config, testOptions, undefined)\n const server: ViteDevServer = await createServer(viteConfig)\n await server.listen()\n }\n\n // TODO: Note that this plugin runs as a `postBuild` step because it currently\n // needs to run after other plugins, and those plugins need to run after the\n // staged files are copied to their final destination(s). We should probably\n // make it configurable so that it can either be run as a `postGenerate` or a\n // `postBuild` step.\n async postBuild(context: BuildContext, modelSpec: ResolvedModelSpec): Promise<boolean> {\n const firstBuild = this.firstBuild\n this.firstBuild = false\n\n // For both production builds and local development, generate a default bundle\n // in this post-build step each time a source file is changed\n // TODO: We could potentially use watch mode for the bundle similar to\n // what we do for the test config, but the bundle depends on the ModelSpec,\n // which currently isn't made available to the `watch` function\n if (this.options?.current?.path === undefined && this.options?.current?.url === undefined) {\n // Path to current bundle was not provided, so generate a default bundle\n if (context.config.mode === 'development') {\n // Copy the previous bundle to the `bundles` directory so that\n // we automatically have it available as a baseline for comparison\n await this.copyPreviousBundle(context.config)\n }\n context.log('info', 'Generating model check bundle...')\n await this.genCurrentBundle(context, modelSpec)\n }\n\n // For production builds (and for the initial build in local development mode),\n // generate default test config in this post-build step\n if (this.options?.testConfigPath === undefined) {\n if (context.config.mode === 'production' || firstBuild) {\n // Test config was not provided, so generate a default config\n context.log('info', 'Generating model check test configuration...')\n await this.genTestConfig('bundle', context.config)\n }\n }\n\n if (context.config.mode === 'production') {\n // For production builds, run the model checks/comparisons, and then\n // inject the results into the generated report\n const testOptions = await this.resolveTestOptions('bundle', context.config)\n return this.runChecks(context, testOptions)\n } else {\n // Nothing to do here in dev mode; the dev server will refresh and\n // re-run the tests in the browser when changes are detected\n return true\n }\n }\n\n private async copyPreviousBundle(config: ResolvedConfig): Promise<void> {\n // Only copy if the current bundle exists\n const currentBundleFile = joinPath(config.prepDir, 'check-bundle.js')\n if (existsSync(currentBundleFile)) {\n // TODO: Use the bundles directory from the config (not yet available)\n const bundlesDir = joinPath(config.rootDir, 'bundles')\n if (!existsSync(bundlesDir)) {\n await mkdir(bundlesDir, { recursive: true })\n }\n const previousBundleFile = joinPath(bundlesDir, 'previous.js')\n await copyFile(currentBundleFile, previousBundleFile)\n }\n }\n\n private async genCurrentBundle(context: BuildContext, modelSpec: ResolvedModelSpec): Promise<void> {\n const viteConfig = await createViteConfigForBundle(context, modelSpec)\n await build(viteConfig)\n }\n\n private async genTestConfig(mode: 'bundle' | 'watch', config: ResolvedConfig): Promise<void> {\n const rootDir = config.rootDir\n const prepDir = config.prepDir\n const viteConfig = createViteConfigForTests(mode, rootDir, prepDir)\n await build(viteConfig)\n }\n\n private async runChecks(context: BuildContext, testOptions: TestOptions): Promise<boolean> {\n context.log('info', 'Running model checks...')\n\n type BundleModule = { createBundle(): Bundle }\n async function importBundleModule(bundleSpec: LocalBundleSpec): Promise<BundleModule> {\n return import(relativeToSourcePath(bundleSpec.path))\n }\n\n // Load the bundles used by the model check/compare configuration. We\n // always initialize the \"current\" bundle.\n const moduleR = await importBundleModule(testOptions.currentBundleSpec)\n const bundleR = moduleR.createBundle() as Bundle\n const bundleNameR = testOptions.currentBundleSpec.name\n\n // Only initialize the \"baseline\" bundle if it is defined and the version\n // is the same as the \"current\" one. If the baseline bundle has a different\n // version, we will skip the comparison tests and only run the checks on the\n // current bundle.\n let bundleL: Bundle\n let bundleNameL: string\n if (testOptions.baselineBundleSpec !== undefined) {\n const moduleL = await importBundleModule(testOptions.baselineBundleSpec)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const rawBundleL: any = moduleL.createBundle() as any\n if (rawBundleL.version === bundleR.version) {\n bundleL = rawBundleL as Bundle\n bundleNameL = testOptions.baselineBundleSpec.name || 'base'\n } else {\n console.warn(\n 'WARNING: Bundle version mismatch ' +\n `(baseline=${rawBundleL.version} current=${bundleR.version}); ` +\n 'check tests will be run but comparisons will be skipped'\n )\n }\n }\n\n // Get the model check/comparison configuration\n const testConfigModule = await import(relativeToSourcePath(testOptions.testConfigPath))\n const configInitOptions: ConfigInitOptions = {\n bundleNameL,\n bundleNameR\n }\n const configOptions = await testConfigModule.getConfigOptions(bundleL, bundleR, configInitOptions)\n\n // Run the suite of checks and comparisons\n const checkConfig = await createConfig(configOptions)\n const result = await runTestSuite(context, checkConfig, /*verbose=*/ false)\n\n // Build the report (using Vite)\n context.log('info', 'Building model check report')\n const viteConfig = await this.createViteConfigForReport('bundle', context.config, testOptions, result.suiteSummary)\n await build(viteConfig)\n\n // context.log('info', 'Done!')\n\n return result.allChecksPassed\n }\n\n private async resolveTestOptions(mode: 'bundle' | 'watch', config: ResolvedConfig): Promise<TestOptions> {\n // Helper function that resolves the bundle, downloading it to the local `bundles` directory\n // first if necessary.\n const fetchRemoteBundle = this.options?.fetchRemoteBundle\n async function resolveBundle(bundle: CheckBundle | undefined): Promise<LocalBundleSpec> {\n // Note that Node.js currently only supports importing bundles from a local file.\n // If `bundle` points to a remote bundle, we need to first download it to the\n // local bundles directory.\n // TODO: We don't technically need to download the bundle to disk. We could instead\n // fetch the bundle from the remote URL and then dynamically import it as a blob,\n // similar to how we load bundles via the Vite dev server in local development mode.\n if (bundle?.url !== undefined) {\n // The bundle is remote, so download it to the local `bundles` directory\n const localBundlePath = await downloadBundle(\n bundle.url,\n bundle.name,\n // TODO: We don't know the last modified time of the remote bundle here, so we use\n // undefined (which means the local file will be created with the current timestamp)\n undefined,\n joinPath(config.rootDir, 'bundles'),\n fetchRemoteBundle\n )\n return {\n name: bundle.name,\n path: localBundlePath\n }\n } else if (bundle?.path !== undefined) {\n // Use the provided local bundle path\n // TODO: Fail fast if the bundle path does not exist?\n return {\n name: bundle.name,\n path: bundle.path\n }\n } else {\n // No bundle spec was provided, so use the generated \"current\" bundle\n return {\n name: bundle?.name || 'current',\n path: joinPath(config.prepDir, 'check-bundle.js')\n }\n }\n }\n\n // Resolve the current bundle. Note that if this step fails, an error will be thrown and\n // the build will fail, since this is a required step for creating the model-check report.\n const currentBundleSpec = await resolveBundle(this.options?.current)\n\n // Only resolve the baseline bundle if we are building the production report and the\n // baseline bundle is defined in the plugin options. If it is undefined, we will\n // only run check tests (no comparisons will be run).\n let baselineBundleSpec: LocalBundleSpec | undefined\n if (mode === 'bundle' && this.options?.baseline) {\n // Note that this step is allowed to fail, since the first time we create the report,\n // the baseline bundle may not already exist on the remote server. If downloading\n // fails, log it as a warning and continue with the build; the report will contain\n // check tests but no comparison tests will be included.\n try {\n baselineBundleSpec = await resolveBundle(this.options.baseline)\n } catch (e) {\n const name = this.options.baseline.name\n const loc = this.options.baseline.url || this.options.baseline.path\n // TODO: Use `context.log('warning')` here (if context is available)?\n console.warn(\n `WARNING: Failed to load '${name}' bundle from '${loc}'; ` +\n 'check tests will be run but comparisons will be skipped. ' +\n 'Cause:',\n e\n )\n }\n }\n\n let testConfigPath: string\n if (this.options?.testConfigPath === undefined) {\n // Test config was not provided, so use a generated config\n testConfigPath = joinPath(config.prepDir, 'check-tests.js')\n } else {\n // Use the provided test config\n testConfigPath = this.options.testConfigPath\n }\n\n return {\n currentBundleSpec,\n baselineBundleSpec,\n testConfigPath\n }\n }\n\n private async createViteConfigForReport(\n mode: 'bundle' | 'watch',\n config: ResolvedConfig,\n testOptions: TestOptions,\n suiteSummary: SuiteSummary | undefined\n ): Promise<InlineConfig> {\n return createViteConfigForReport(\n mode,\n this.options,\n config.rootDir,\n config.prepDir,\n testOptions.currentBundleSpec,\n testOptions.baselineBundleSpec,\n testOptions.testConfigPath,\n suiteSummary\n )\n }\n}\n\n/**\n * Return a Unix-style path (e.g. '../../foo.js') that is relative to the directory of\n * the current source file. This can be used to construct a path that is safe for\n * dynamic import on either Unix or Windows.\n *\n * @param filePath The path to make relative.\n */\nfunction relativeToSourcePath(filePath: string): string {\n const srcDir = dirname(fileURLToPath(import.meta.url))\n const relPath = relative(srcDir, filePath)\n return relPath.replaceAll('\\\\', '/')\n}\n","// Copyright (c) 2025 Climate Interactive / New Venture Fund\n\nimport { mkdir, readFile, stat, utimes, writeFile } from 'node:fs/promises'\nimport { dirname, join as joinPath } from 'node:path'\n\n/**\n * Download a bundle from a remote URL and save it to the local bundles directory.\n *\n * @param url The remote URL to download the bundle from.\n * @param name The bundle name (may contain slashes for subdirectories).\n * @param lastModified The last modified timestamp from the remote bundle.\n * @param bundlesDir The bundles directory path.\n * @param fetchRemoteBundle Optional custom function for fetching remote bundle files.\n * @returns The file path where the bundle was saved.\n */\nexport async function downloadBundle(\n url: string,\n name: string,\n lastModified: string | undefined,\n bundlesDir: string,\n fetchRemoteBundle?: (url: string) => Promise<string>\n): Promise<string> {\n // Add cache busting parameter to avoid issues with servers that aggressively cache files\n const fullUrl = `${url}?cb=${Date.now()}`\n\n // Fetch the bundle source code from the remote URL\n let bundleContent: string\n if (fetchRemoteBundle) {\n // Use the custom loader function\n bundleContent = await fetchRemoteBundle(fullUrl)\n } else {\n // Use the default fetch implementation\n const response = await fetch(fullUrl)\n if (!response.ok) {\n throw new Error(`Failed to fetch bundle: HTTP ${response.status} ${response.statusText}`)\n }\n bundleContent = await response.text()\n }\n\n // Preserve slashes in the bundle name (create subdirectories as needed)\n const nameParts = name.split('/')\n const filePath = joinPath(bundlesDir, ...nameParts) + '.js'\n\n // Create parent directories if they don't exist\n await mkdir(dirname(filePath), { recursive: true })\n\n // Write the bundle to the local directory\n await writeFile(filePath, bundleContent, 'utf8')\n\n // Preserve the last modified time from the remote bundle\n if (lastModified) {\n const mtime = new Date(lastModified)\n await utimes(filePath, mtime, mtime)\n }\n\n return filePath\n}\n\n/**\n * Copy a bundle from a source URL and save it with a new name to the local bundles directory.\n *\n * @param url The source URL to copy the bundle from (can be 'current' or file:// URLs).\n * @param newName The new bundle name (may contain slashes for subdirectories).\n * @param bundlesDir The bundles directory path.\n * @returns The file path where the bundle was saved.\n */\nexport async function copyBundle(url: string, newName: string, bundlesDir: string): Promise<string> {\n let srcPath: string\n if (url === 'current') {\n // The \"current\" bundle is in the sde-prep directory (check-bundle.js)\n const sdePrepDir = joinPath(bundlesDir, '..', 'sde-prep')\n srcPath = joinPath(sdePrepDir, 'check-bundle.js')\n } else if (url.startsWith('file://')) {\n // For file:// URLs, extract the file path\n srcPath = new URL(url).pathname\n } else {\n throw new Error(`Cannot copy bundle with URL: ${url}`)\n }\n\n // Read the source file\n const bundleContent = await readFile(srcPath, 'utf8')\n\n // Get the last modified time of the source file\n const stats = await stat(srcPath)\n const sourceLastModified = stats.mtime\n\n // Preserve slashes in the bundle name (create subdirectories)\n const nameParts = newName.split('/')\n const filePath = joinPath(bundlesDir, ...nameParts) + '.js'\n\n // Create parent directories if they don't exist\n await mkdir(dirname(filePath), { recursive: true })\n\n // Write the bundle to the local directory with the new name\n await writeFile(filePath, bundleContent, 'utf8')\n\n // Preserve the last modified time from the source bundle\n if (sourceLastModified) {\n await utimes(filePath, sourceLastModified, sourceLastModified)\n }\n\n return filePath\n}\n","// Copyright (c) 2021-2022 Climate Interactive / New Venture Fund\n\nimport { performance } from 'perf_hooks'\n\nimport pico from 'picocolors'\n\nimport type { BuildContext } from '@sdeverywhere/build'\n\nimport type {\n Config,\n ComparisonReport,\n PerfReport,\n RunSuiteCallbacks,\n CheckReport,\n CheckStatus,\n ComparisonConfig,\n CheckTestReport,\n SuiteSummary\n} from '@sdeverywhere/check-core'\nimport {\n datasetMessage,\n predicateMessage,\n runSuite,\n scenarioMessage,\n suiteSummaryFromReport\n} from '@sdeverywhere/check-core'\n\nexport interface RunTestSuiteResult {\n allChecksPassed: boolean\n suiteSummary: SuiteSummary\n}\n\n/**\n * Runs the test suite.\n */\nexport async function runTestSuite(\n context: BuildContext,\n config: Config,\n verbose: boolean\n): Promise<RunTestSuiteResult> {\n return new Promise((resolve, reject) => {\n const t0 = performance.now()\n let lastPctByInc: number\n const callbacks: RunSuiteCallbacks = {\n onProgress: progress => {\n const pct = Math.round(progress * 100)\n const pctByInc = Math.floor(pct / 5) * 5\n if (lastPctByInc === undefined || pctByInc > lastPctByInc) {\n lastPctByInc = pctByInc\n context.log('info', `${pctByInc}%`)\n }\n },\n onComplete: report => {\n try {\n const t1 = performance.now()\n const elapsedMillis = t1 - t0\n const elapsedSeconds = (elapsedMillis / 1000).toFixed(1)\n context.log('info', `\\nTest suite completed in ${elapsedSeconds}s`)\n\n // Print check summary to the console\n const allChecksPassed = printCheckSummary(context, report.checkReport, verbose)\n\n if (report.comparisonReport) {\n // Print the perf stats to the console\n printPerfStats(context, config.comparison, report.comparisonReport)\n }\n\n // Convert check and compare reports to terse form that only includes\n // failed/errored checks or comparisons with differences\n // TODO: The terse form was originally used when we had to write the\n // results to a JSON file and then read them back in when building\n // the report, but we no longer use that intermediate file, so there's\n // less reason to use the terse form (since it requires the web app\n // code to reconstruct the results). But for now, we will continue\n // to use the terse form, and later we can update the app code.\n const suiteSummary = suiteSummaryFromReport(report, elapsedMillis)\n\n resolve({\n allChecksPassed,\n suiteSummary\n })\n } catch (e) {\n reject(e)\n }\n },\n onError: error => {\n reject(error)\n }\n }\n runSuite(config, callbacks)\n })\n}\n\nfunction printCheckSummary(context: BuildContext, checkReport: CheckReport, verbose: boolean): boolean {\n function printResult(indent: number, status: CheckStatus, text: string): void {\n if (!verbose && status === 'passed' && indent > 1) {\n return\n }\n let statusChar: string\n switch (status) {\n case 'passed':\n statusChar = '✓'\n break\n case 'failed':\n statusChar = '✗'\n break\n case 'error':\n statusChar = '‼'\n break\n case 'skipped':\n statusChar = '–'\n break\n default:\n statusChar = ''\n break\n }\n const msg = `${' '.repeat(indent)}${statusChar} ${text}`\n context.log('info', status === 'passed' ? pico.green(msg) : pico.red(msg))\n }\n\n function bold(s: string): string {\n return pico.bold(s)\n }\n\n function printTest(test: CheckTestReport): void {\n const msg = `${test.name}${verbose || test.status !== 'passed' ? ':' : ''}`\n printResult(1, test.status, msg)\n }\n\n let allPassed = true\n context.log('info', '\\nCheck results:')\n for (const group of checkReport.groups) {\n context.log('info', `\\n${group.name}`)\n\n for (const test of group.tests) {\n if (test.status !== 'passed') {\n allPassed = false\n }\n printTest(test)\n\n for (const scenario of test.scenarios) {\n printResult(3, scenario.status, scenarioMessage(scenario, bold))\n\n for (const dataset of scenario.datasets) {\n printResult(5, dataset.status, datasetMessage(dataset, bold))\n\n for (const predicate of dataset.predicates) {\n printResult(7, predicate.result.status, predicateMessage(predicate, bold))\n }\n }\n }\n }\n }\n context.log('info', '')\n\n return allPassed\n}\n\nfunction stat(label: string, n: number): string {\n return `${label}=${n.toFixed(1)}ms`\n}\n\nfunction printPerfReportLine(context: BuildContext, perfReport: PerfReport): void {\n const avg = stat('avg', perfReport.avgTime)\n const min = stat('min', perfReport.minTime)\n const max = stat('max', perfReport.maxTime)\n context.log('info', ` ${avg} ${min} ${max}`)\n}\n\nfunction printPerfStats(context: BuildContext, comparisonConfig: ComparisonConfig, report: ComparisonReport): void {\n context.log('info', '\\nPerformance stats:')\n context.log('info', ` ${comparisonConfig.bundleL.name}:`)\n printPerfReportLine(context, report.perfReportL)\n context.log('info', ` ${comparisonConfig.bundleR.name}:`)\n printPerfReportLine(context, report.perfReportR)\n context.log('info', '')\n}\n","// Copyright (c) 2022 Climate Interactive / New Venture Fund\n\nimport { existsSync, readFileSync, statSync } from 'fs'\nimport { basename, dirname, join as joinPath, relative, resolve as resolvePath } from 'path'\nimport { fileURLToPath } from 'url'\n\nimport type { InlineConfig, ResolvedConfig, Plugin as VitePlugin } from 'vite'\nimport { nodeResolve } from '@rollup/plugin-node-resolve'\n\nimport type { BuildContext, ResolvedModelSpec } from '@sdeverywhere/build'\nimport { encodeImplVars } from '@sdeverywhere/check-core'\n\nconst __filename = fileURLToPath(import.meta.url)\nconst __dirname = dirname(__filename)\n\n/**\n * This is a virtual module plugin used to inject model-specific configuration\n * values into the generated worker bundle.\n *\n * This follows the \"Virtual Modules Convention\" described here:\n * https://vitejs.dev/guide/api-plugin.html#virtual-modules-convention\n *\n * TODO: This could be simplified by using `vite-plugin-virtual` but that\n * doesn't seem to be working correctly in an ESM setting\n */\nfunction injectModelSpec(context: BuildContext, modelSpec: ResolvedModelSpec): VitePlugin {\n const prepDir = context.config.prepDir\n\n // Include the SDE variable ID with each spec\n const inputSpecs = []\n for (const modelInputSpec of modelSpec.inputs) {\n // Note that the `InputSpec` interface in the `@sdeverywhere/build` package\n // allows the default/min/max values to be undefined, which can be the case\n // if the user doesn't return full `InputSpec` instances in the `ModelSpec`.\n // We will log a warning and skip the input if these values are not defined.\n if (\n modelInputSpec.defaultValue === undefined ||\n modelInputSpec.minValue === undefined ||\n modelInputSpec.maxValue === undefined\n ) {\n let msg = ''\n msg += `WARNING: The {defaultValue,minValue,maxValue} properties are required by plugin-check, `\n msg += `but are undefined in the InputSpec for '${modelInputSpec.varName}'. `\n msg += `This input variable will be excluded from the model-check bundle until those properties `\n msg += `are defined.`\n console.warn(msg)\n continue\n }\n\n // Use the `inputId` if defined for the `InputSpec`, otherwise use `varId`. The\n // latter is less resilient if the variable is renamed between two versions of\n // the model, but will be sufficient for now. Note that `plugin-config` defines\n // a stable `inputId` for each row in the `inputs.csv`, and that is the most\n // common way to configure a `ModelSpec`, so it will be uncommon for `inputId`\n // to be undefined here.\n const varId = context.canonicalVarId(modelInputSpec.varName)\n const inputId = modelInputSpec.inputId || varId\n inputSpecs.push({\n inputId,\n varId,\n ...modelInputSpec\n })\n }\n\n // Include the SDE variable ID with each output variable spec\n const outputSpecs = modelSpec.outputs.map(o => {\n return {\n varId: context.canonicalVarId(o.varName),\n ...o\n }\n })\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n function readJsonListing(): any {\n const path = joinPath(prepDir, 'build', 'processed.json')\n if (existsSync(path)) {\n const json = readFileSync(path, 'utf8')\n return JSON.parse(json)\n } else {\n return {}\n }\n }\n\n // Read the JSON model listing\n const listing = readJsonListing()\n\n // Extract the `varInstances` object from the model listing\n const varInstances = listing.varInstances || {}\n\n // Encode the `varInstances` object into a more efficient format to reduce the bundle size\n const encodedImplVars = encodeImplVars(varInstances)\n\n function stagedFileSize(filename: string): number {\n const path = joinPath(prepDir, 'staged', 'model', filename)\n if (existsSync(path)) {\n return statSync(path).size\n } else {\n return 0\n }\n }\n\n // The size (in bytes) of the `generated-model.js` file\n // TODO: Ideally we would measure the size of the raw Wasm binary, but currently\n // we inline it as a base64 blob inside the JS file, so we take the size of the\n // whole JS file as the second best option\n const modelSizeInBytes = stagedFileSize('generated-model.js')\n\n // The size (in bytes) of the `static-data.ts` file\n // TODO: Ideally we would measure the size of the minified JS file here, or\n // at least ignore things like whitespace\n const dataSizeInBytes = stagedFileSize('static-data.ts')\n\n const moduleSrc = `\nexport const inputSpecs = ${JSON.stringify(inputSpecs)};\nexport const outputSpecs = ${JSON.stringify(outputSpecs)};\nexport const encodedImplVars = ${JSON.stringify(encodedImplVars)};\nexport const modelSizeInBytes = ${modelSizeInBytes};\nexport const dataSizeInBytes = ${dataSizeInBytes};\n`\n\n const virtualModuleId = 'virtual:model-spec'\n const resolvedVirtualModuleId = '\\0' + virtualModuleId\n\n return {\n name: 'vite-plugin-virtual-custom',\n resolveId(id: string) {\n if (id === virtualModuleId) {\n return resolvedVirtualModuleId\n }\n },\n load(id: string) {\n if (id === resolvedVirtualModuleId) {\n return moduleSrc\n }\n }\n }\n}\n\n/**\n * XXX: This overrides the built-in `vite:resolve` plugin so that we can intercept `resolveId`\n * calls for the threads package.\n */\nfunction overrideViteResolvePlugin(viteConfig: ResolvedConfig) {\n const resolvePlugin = viteConfig.plugins.find(p => p.name === 'vite:resolve')\n if (resolvePlugin === undefined) {\n throw new Error('Failed to locate the built-in vite:resolve plugin')\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const originalResolveId = resolvePlugin.resolveId as any\n resolvePlugin.resolveId = async function resolveId(id, importer, options) {\n if (id.startsWith('./implementation') && importer.includes('threads/dist-esm')) {\n // XXX: The default resolver behavior will look at the `browser` mappings in\n // `threads/package.json` and try to resolve `implementation.js` to\n // `implementation.browser.js` because it thinks we're in a browser-only context.\n // We don't want that. Instead we want to keep the generic implementation from\n // threads that chooses between the Node and browser implementations at runtime.\n //\n // If we get here, importer will be something like:\n // /.../node_modules/.pnpm/threads@1.7.0/node_modules/threads/dist-esm/{worker,master}/index.js\n // And id will be:\n // ./implementation\n // So resolve the ID to:\n // /.../node_modules/.pnpm/threads@1.7.0/node_modules/threads/dist-esm/{worker,master}/implementation.js\n //\n // Or, importer will be:\n // /.../node_modules/.pnpm/threads@1.7.0/node_modules/threads/dist-esm/{worker,master}/implementation.js\n // And id will be one of:\n // ./implementation.browser\n // ./implementation.node\n // ./implementation.worker_threads\n // So resolve the ID to:\n // /.../node_modules/.pnpm/threads@1.7.0/node_modules/threads/dist-esm/{worker,master}/implementation.{...}.js\n const idFileName = id.replace('./', '')\n const importerFileName = basename(importer)\n const resolvedId = importer.replace(importerFileName, `${idFileName}.js`)\n return {\n id: resolvedId,\n moduleSideEffects: false\n }\n }\n\n // For all other cases, fall back on the default resolver\n return await originalResolveId.handler.call(this, id, importer, options)\n }\n}\n\nexport async function createViteConfigForBundle(\n context: BuildContext,\n modelSpec: ResolvedModelSpec\n): Promise<InlineConfig> {\n // Use `template-bundle` as the root directory for the bundle project\n const root = resolvePath(__dirname, '..', 'template-bundle')\n\n // Calculate output directory relative to the template root\n // TODO: For now we write it to `prepDir`; make this configurable?\n const prepDir = context.config.prepDir\n const outDir = relative(root, prepDir)\n\n // Use the model worker from the staged directory\n // TODO: Make this configurable?\n const modelWorkerPath = joinPath(prepDir, 'staged', 'model', 'worker.js?raw')\n\n return {\n // Don't use an external config file\n configFile: false,\n\n // Use the root directory configured above\n root,\n\n // Don't clear the screen in dev mode so that we can see builder output\n clearScreen: false,\n\n // TODO: Disable vite output by default?\n // logLevel: 'silent',\n\n // Configure path aliases\n resolve: {\n alias: [\n // Inject the configured model worker\n {\n find: '@_model_worker_',\n replacement: modelWorkerPath\n },\n\n // XXX: Prevent Vite from using the `browser` section of `threads/package.json`\n // since we want to force the use of the general module (under dist-esm) that chooses\n // the correct implementation (Web Worker vs worker_threads) at runtime. Currently\n // Vite's library mode is browser focused and generally chooses the right imports,\n // except in the case of the threads package where we want to use the generic\n // `implementation.js` that chooses between Web Worker and worker_threads at runtime.\n // Note that we could in theory set `resolve.browserField` to false, but that would\n // make Vite not use the browser field for all other packages, and there is not\n // currently a way to tell Vite to use the browser field on a case-by-case basis.\n // So for now we need this workaround here to make it resolve to `dist-esm`, and then\n // a second workaround in `overrideViteResolvePlugin` to prevent the resolver from\n // using the browser field when resolving the threads package.\n {\n find: 'threads',\n replacement: 'threads',\n customResolver: async function (source, importer, options) {\n // Note that we need to use `resolveId.call` here in order to provide the\n // right `this` context, which provides Rollup plugin functionality\n const customResolver = nodeResolve({ browser: false })\n // In Rollup 4, resolveId can either be a function or an object with a `handler` property\n const resolveIdHook = customResolver.resolveId\n const resolveIdFn = typeof resolveIdHook === 'function' ? resolveIdHook : resolveIdHook.handler\n const resolved = await resolveIdFn.call(this, source, importer, options)\n // Force the use of the `dist-esm` variant of the threads.js package\n if (source === 'threads/worker') {\n return resolved.id.replace('worker.mjs', 'dist-esm/worker/index.js')\n } else {\n return resolved.id.replace('index.mjs', 'dist-esm/index.js')\n }\n }\n }\n ]\n },\n\n plugins: [\n // Use a virtual module plugin to inject the model spec values\n injectModelSpec(context, modelSpec),\n\n // XXX: Install a wrapper around the built-in `vite:resolve` plugin so that we can\n // override the default resolver behavior that tries to resolve the `browser` section\n // of the `package.json` for the threads package.\n {\n name: 'vite-plugin-override-resolve',\n configResolved(viteConfig) {\n overrideViteResolvePlugin(viteConfig)\n }\n }\n ],\n\n build: {\n // Write output files to the configured directory (instead of the default `dist`);\n // note that this must be relative to the project `root`\n outDir,\n emptyOutDir: false,\n\n // Uncomment for debugging purposes\n // minify: false,\n\n lib: {\n entry: './src/index.ts',\n formats: ['es'],\n fileName: () => 'check-bundle.js'\n },\n\n rollupOptions: {\n // Don't transform Node imports used by threads.js\n external: ['events', 'os', 'path', 'url'],\n\n // XXX: Insert custom code at the top of the generated bundle that defines\n // the special `__non_webpack_require__` function that is used by threads.js\n // in its Node implementation. This import ensures that threads.js uses\n // the native `worker_threads` implementation when using the bundle in a\n // Node environment. When importing the bundle for use in the browser,\n // Vite will transform this import into an empty module due to the empty\n // polyfill that is configured in `vite-config-for-report.ts`.\n output: {\n banner: `\nimport * as worker_threads from 'worker_threads'\nlet __non_webpack_require__ = () => {\n return worker_threads;\n};\n`\n },\n\n onwarn: (warning, warn) => {\n // XXX: Suppress \"Use of eval is strongly discouraged\" warnings that are\n // triggered by use of the following pattern in threads.js:\n // eval(\"require\")(\"worker_threads\")\n // It would be nice to avoid use of `eval` there, but it's not critical for\n // our use case so we will suppress the warnings for now\n if (warning.code !== 'EVAL') {\n warn(warning)\n }\n }\n }\n }\n }\n}\n","// Copyright (c) 2022 Climate Interactive / New Venture Fund\n\nimport { existsSync, mkdirSync } from 'node:fs'\nimport { dirname, relative, join as joinPath, resolve as resolvePath } from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nimport type { Alias, InlineConfig, PluginOption } from 'vite'\nimport replace from '@rollup/plugin-replace'\n\nimport type { SuiteSummary } from '@sdeverywhere/check-core'\n\nimport type { LocalBundleSpec } from './bundle-spec'\nimport type { CheckPluginOptions } from './options'\nimport { localBundlesPlugin } from './vite-local-bundles-plugin'\n\nconst __filename = fileURLToPath(import.meta.url)\nconst __dirname = dirname(__filename)\n\n/**\n * NOTE: This function currently only supports creating a Vite config for the\n * model-check report when the current/baseline bundles are local files. If\n * you want to use remote bundles, you must first download them to the local\n * `bundles` directory and then pass `LocalBundleSpec` instances that include\n * the local bundle file paths.\n */\nexport function createViteConfigForReport(\n mode: 'bundle' | 'watch',\n options: CheckPluginOptions | undefined,\n projDir: string,\n prepDir: string,\n currentBundleSpec: LocalBundleSpec,\n baselineBundleSpec: LocalBundleSpec | undefined,\n testConfigPath: string,\n suiteSummary: SuiteSummary | undefined\n): InlineConfig {\n // Use `template-report` as the root directory for the report project\n const root = resolvePath(__dirname, '..', 'template-report')\n\n // Make sure the `bundles` directory exists, otherwise Vite's dependency scanner\n // may report errors when processing the `import.meta.glob` call\n const bundlesDir = resolvePath(projDir, 'bundles')\n if (!existsSync(bundlesDir)) {\n mkdirSync(bundlesDir, { recursive: true })\n }\n\n // Include `bundles/**/*.js` files under the configured project root directory. This\n // glob path apparently must be a relative path (relative to the `template-report/src`\n // directory where the glob is used).\n const templateSrcDir = resolvePath(root, 'src')\n const relProjDir = relative(templateSrcDir, projDir)\n // XXX: The glob pattern must use forward slashes only, so on Windows we need to\n // convert backslashes to slashes\n const relProjDirPath = relProjDir.replaceAll('\\\\', '/')\n // TODO: Use localBundlesPath from options\n const bundlesPath = `${relProjDirPath}/bundles/**/*.js`\n\n // Calculate output directory relative to the template root\n let reportPath: string\n if (options?.reportPath) {\n reportPath = options.reportPath\n } else {\n reportPath = joinPath(prepDir, 'check-report')\n }\n const outDir = relative(root, reportPath)\n\n // Convert the suite summary to JSON, which is what the app currently expects\n const suiteSummaryJson = suiteSummary ? JSON.stringify(suiteSummary) : ''\n\n const alias = (find: string, replacement: string) => {\n return {\n find,\n replacement\n } as Alias\n }\n\n // XXX: This provides custom handling for Node built-ins such as 'events' that are\n // referenced by the check bundle (specifically in the Node implementation of\n // threads.js). These are not actually used in the browser, so we just need\n // to provide no-op polyfills for these.\n const noopPolyfillAlias = (find: string) => {\n return {\n find,\n replacement: '/polyfills/noop-polyfills.ts'\n } as Alias\n }\n\n return {\n // Don't use an external config file\n configFile: false,\n\n // Use the root directory configured above\n root,\n\n // Use `.` as the base directory (instead of the default `/`); this controls\n // how the path to the js/css files are generated in `index.html`\n base: '',\n\n // Use a custom cache directory under `prepDir`, as otherwise Vite will use\n // `packages/plugin-check/template-report/node_modules/.vite`, and we want to\n // avoid generating files in `template-report` (which should be read-only)\n cacheDir: joinPath(prepDir, '.vite-check-report'),\n\n // Load static files from `static` (instead of the default `public`)\n // publicDir: 'static',\n\n // Don't clear the screen in dev mode so that we can see builder output\n clearScreen: false,\n\n // TODO\n // logLevel: 'silent',\n\n optimizeDeps: {\n // Prevent Vite from examining other html files when scanning entrypoints\n // for dependency optimization\n entries: ['index.html'],\n\n // XXX: When plugin-check is installed via pnpm, the Vite dev server seems\n // to have no trouble resolving other dependencies using the optimizeDeps\n // mechanism. However, this fails when the package is installed via yarn\n // or npm (probably due to the fact that the `template-report` directory\n // is located under the top-level `node_modules` directory); in the browser,\n // there will be \"import not found\" errors for the packages referenced below.\n // As a terrible workaround, explicitly include the direct dependencies so\n // that Vite optimizes them; this works for pnpm, yarn, and npm. We should\n // find a less fragile solution.\n include: [\n // from check-core\n '@sdeverywhere/check-core > assert-never',\n '@sdeverywhere/check-core > ajv',\n '@sdeverywhere/check-core > neverthrow',\n '@sdeverywhere/check-core > yaml',\n // from check-ui-shell\n '@sdeverywhere/check-ui-shell > fontfaceobserver',\n '@sdeverywhere/check-ui-shell > copy-text-to-clipboard',\n '@sdeverywhere/check-ui-shell > chart.js'\n ],\n\n exclude: [\n // XXX: The threads.js implementation references `tiny-worker` as an optional\n // dependency, but it doesn't get used at runtime, so we can just exclude it\n // so that Vite doesn't complain in dev mode\n 'tiny-worker'\n\n // XXX: Similarly, chart.js treats `moment` as an optional dependency, but we\n // don't use it at runtime; we need to exclude it here, otherwise Vite will\n // complain about missing dependencies in dev mode\n // 'moment'\n ]\n },\n\n // Configure path aliases\n resolve: {\n alias: [\n // Use the configured \"baseline\" bundle if defined, otherwise use the \"empty\" bundle\n // (which will cause comparison tests to be skipped)\n alias('@_baseline_bundle_', baselineBundleSpec?.path || '/src/empty-bundle.ts'),\n\n // Use the configured \"current\" bundle\n alias('@_current_bundle_', currentBundleSpec.path),\n\n // Use the configured test config file\n alias('@_test_config_', testConfigPath),\n\n // Make the overlay use the `messages.html` file that is written to the prep directory\n alias('@_prep_', prepDir),\n\n // XXX: Include no-op polyfills for these modules that are used in the Node-specific\n // implementation of threads.js; this allows us to use one bundle that works in both\n // Node and browser environments\n noopPolyfillAlias('events'),\n noopPolyfillAlias('fs'),\n noopPolyfillAlias('os'),\n noopPolyfillAlias('path'),\n noopPolyfillAlias('url'),\n noopPolyfillAlias('worker_threads')\n ]\n },\n\n // Inject special values into the generated JS\n define: {\n // Inject the summary JSON into the build\n __SUITE_SUMMARY_JSON__: JSON.stringify(suiteSummaryJson),\n\n // Inject the baseline bundle name\n __BASELINE_NAME__: JSON.stringify(baselineBundleSpec?.name || ''),\n\n // Inject the current bundle name\n __CURRENT_NAME__: JSON.stringify(currentBundleSpec.name),\n\n // Inject the remote bundles URL\n __REMOTE_BUNDLES_URL__: JSON.stringify(options?.remoteBundlesUrl || '')\n },\n\n plugins: [\n // Inject special values into the generated JS\n // TODO: We currently have to use `@rollup/plugin-replace` instead of Vite's\n // built-in `define` feature because the latter does not seem to run before\n // the glob handler (which requires the glob to be injected as a literal)\n replace({\n preventAssignment: true,\n delimiters: ['', ''],\n values: {\n // Inject the path for baseline bundles\n // XXX: Note that we use './bundles/**/*.txt' instead of something special\n // like './__BASELINE_BUNDLES_PATH__' because sometimes Vite's dependency\n // scanner sees the latter (instead of the injected path) and reports\n // an error since the path does not exist. As a workaround, we use\n // './bundles/**/*.txt', which gets interpreted as the valid path\n // '.../template-report/src/bundles/**/*.txt' (see `bundles/unused.txt`).\n './bundles/**/*.txt': bundlesPath\n }\n }) as unknown as PluginOption,\n\n // When local development mode is active, enable the local bundles plugin that\n // allows the report app to access the local bundles directory\n ...(mode === 'watch' ? [localBundlesPlugin(bundlesDir, currentBundleSpec.path, options?.fetchRemoteBundle)] : [])\n ],\n\n build: {\n // Write output files to the configured directory (instead of the default `dist`);\n // note that this must be relative to the project `root`\n outDir,\n\n // Write js/css files to `public` (instead of the default `<outDir>/assets`)\n assetsDir: '',\n\n rollupOptions: {\n output: {\n // XXX: Prevent vite from creating a separate `vendor.js` file\n manualChunks: undefined\n },\n\n onwarn: (warning, warn) => {\n // XXX: Suppress \"Use of eval is strongly discouraged\" warnings that are\n // triggered by use of the following pattern in threads.js:\n // eval(\"require\")(\"worker_threads\")\n // It would be nice to avoid use of `eval` there, but it's not critical for\n // our use case so we will suppress the warnings for now\n if (warning.code !== 'EVAL') {\n warn(warning)\n }\n }\n }\n },\n\n server: {\n // Run the dev server at `localhost:8081` by default\n port: options?.serverPort || 8081,\n\n // Open the app in the browser by default\n open: '/index.html',\n\n // XXX: Add a small delay, otherwise on macOS we sometimes get multiple\n // change events when a file is saved just once. That is a relatively\n // harmless issue except that it causes redundant messages in the console\n // and can cause extra churn when refreshing the app.\n watch: {\n awaitWriteFinish: {\n stabilityThreshold: 100\n }\n }\n }\n }\n}\n","// Copyright (c) 2025 Climate Interactive / New Venture Fund\n\nimport { readdir, readFile, stat } from 'node:fs/promises'\nimport { join as joinPath, relative, sep } from 'node:path'\nimport { fileURLToPath, pathToFileURL } from 'node:url'\n\nimport chokidar from 'chokidar'\nimport type { Plugin } from 'vite'\n\nimport type { BundleLocation } from '@sdeverywhere/check-ui-shell'\nimport { copyBundle, downloadBundle } from './bundle-file-ops'\n\n/**\n * Vite plugin that provides a bridge to the model-check report app to allow access\n * to the local bundles directory when running in local development mode.\n *\n * This plugin adds an HMR (Hot Module Replacement) event handler that listens for\n * 'list-bundles' and 'download-bundle' events from the client.\n *\n * @param bundlesDir The absolute path to the bundles directory.\n * @param currentBundlePath The absolute path to the current bundle file.\n * @param fetchRemoteBundle Optional function for fetching remote bundle files.\n */\nexport function localBundlesPlugin(\n bundlesDir: string,\n currentBundlePath: string,\n fetchRemoteBundle?: (url: string) => Promise<string>\n): Plugin {\n return {\n name: 'sde-local-bundles',\n\n configureServer(server) {\n // Watch the bundles directory for changes and notify clients\n const watcher = chokidar.watch(bundlesDir, {\n // Don't send initial \"file added\" events\n ignoreInitial: true,\n // XXX: Include a delay, otherwise on macOS we sometimes get multiple\n // change events when a file is saved just once\n awaitWriteFinish: {\n stabilityThreshold: 200\n },\n // Watch up to 10 levels deep\n depth: 10\n })\n\n watcher.on('all', (event /*, path*/) => {\n if (event === 'add' || event === 'unlink') {\n // Notify all clients that the bundles list has changed\n // console.log(`[sde-local-bundles] Detected ${event} in bundles directory: ${path}`)\n server.ws.send('bundles-changed', {})\n }\n })\n\n // Clean up the file watcher when the vite server is closed\n server.httpServer?.on('close', () => {\n watcher.close()\n })\n\n // Handle requests to list the available local bundles\n server.ws.on('list-bundles', async (_, client) => {\n try {\n // Find all bundles in the local bundles directory\n const bundles = await scanBundlesRecursively(bundlesDir, bundlesDir)\n\n // Add the special \"current\" bundle with its up-to-date last modified time\n const currentBundleStats = await stat(currentBundlePath)\n bundles.push({\n name: 'current',\n url: 'current',\n lastModified: currentBundleStats.mtime.toISOString()\n })\n\n // Send success message back to client\n client.send('list-bundles-success', { bundles })\n } catch (error) {\n // Send error message back to client\n console.error(`[sde-local-bundles] Failed to list bundles:`, error)\n client.send('list-bundles-error', { error: error.message })\n }\n })\n\n // Handle requests to load a local or remote bundle\n server.ws.on('load-bundle', async (data, client) => {\n const { url, name } = data\n try {\n let sourceCode: string\n\n if (url.startsWith('file://')) {\n // Local bundle: read from file system\n // console.log(`[sde-local-bundles] Loading local bundle: name=${name} url=${url}`)\n const filePath = fileURLToPath(url)\n sourceCode = await readFile(filePath, 'utf-8')\n } else if (url.startsWith('https://') || url.startsWith('http://')) {\n // Remote bundle: fetch from remote URL\n // console.log(`[sde-local-bundles] Loading remote bundle: name=${name} url=${url}`)\n // Add cache busting parameter to avoid issues with servers that aggressively cache files\n const fullUrl = `${url}?cb=${Date.now()}`\n if (fetchRemoteBundle) {\n // Use the custom fetch function\n sourceCode = await fetchRemoteBundle(fullUrl)\n } else {\n // Use the default fetch implementation\n const response = await fetch(fullUrl)\n if (!response.ok) {\n throw new Error(`Failed to fetch bundle: ${response.status} ${response.statusText}`)\n }\n sourceCode = await response.text()\n }\n } else {\n throw new Error(`Unsupported URL scheme: ${url}`)\n }\n\n // Send the source code back to client\n client.send('load-bundle-success', { name, url, sourceCode })\n } catch (error) {\n // Send error message back to client\n console.error(`[sde-local-bundles] Failed to load bundle:`, error)\n client.send('load-bundle-error', { name, url, error: error.message })\n }\n })\n\n // Handle requests to download a bundle to the local bundles directory\n server.ws.on('download-bundle', async (data, client) => {\n const { url, name, lastModified } = data\n try {\n // Download the bundle to the local bundles directory\n console.log(`[sde-local-bundles] Downloading bundle: name=${name} url=${url}`)\n const filePath = await downloadBundle(url, name, lastModified, bundlesDir, fetchRemoteBundle)\n\n // Send success message back to client\n console.log(`[sde-local-bundles] Downloaded bundle to ${filePath}`)\n client.send('download-bundle-success', { name, filePath: `${name}.js` })\n } catch (error) {\n // Send error message back to client\n console.error(`[sde-local-bundles] Failed to download bundle:`, error)\n client.send('download-bundle-error', { name, error: error.message })\n }\n })\n\n // Handle requests to copy a bundle to a new name\n server.ws.on('copy-bundle', async (data, client) => {\n const { url, name, newName } = data\n try {\n // Copy the bundle with a new name\n console.log(`[sde-local-bundles] Copying bundle: src=${name} dst=${newName}`)\n const filePath = await copyBundle(url, newName, bundlesDir)\n\n // Send success message back to client\n console.log(`[sde-local-bundles] Copied bundle to ${filePath}`)\n client.send('copy-bundle-success', { name: newName, filePath: `${newName}.js` })\n } catch (error) {\n // Send error message back to client\n console.error(`[sde-local-bundles] Failed to copy bundle:`, error)\n client.send('copy-bundle-error', { name, error: error.message })\n }\n })\n }\n }\n}\n\n/**\n * Recursively scan a directory for .js files.\n *\n * @param dir The directory to scan.\n * @param baseDir The base directory (used for calculating relative paths).\n * @returns An array of bundle information.\n */\nasync function scanBundlesRecursively(dir: string, baseDir: string): Promise<BundleLocation[]> {\n const bundles: BundleLocation[] = []\n const entries = await readdir(dir, { withFileTypes: true })\n\n for (const entry of entries) {\n const fullPath = joinPath(dir, entry.name)\n if (entry.isDirectory()) {\n // Recursively scan subdirectories\n const subBundles = await scanBundlesRecursively(fullPath, baseDir)\n bundles.push(...subBundles)\n } else if (entry.isFile() && entry.name.endsWith('.js')) {\n const stats = await stat(fullPath)\n // Get the relative path from baseDir and remove the .js extension\n const relativePath = relative(baseDir, fullPath)\n const name = relativePath.replace(/\\.js$/, '').split(sep).join('/')\n bundles.push({\n name,\n url: pathToFileURL(fullPath).toString(),\n lastModified: stats.mtime.toISOString()\n })\n }\n }\n\n return bundles\n}\n","// Copyright (c) 2022 Climate Interactive / New Venture Fund\n\nimport { dirname, relative, resolve as resolvePath } from 'path'\nimport { fileURLToPath } from 'url'\n\nimport type { InlineConfig, PluginOption } from 'vite'\nimport replace from '@rollup/plugin-replace'\n\nconst __filename = fileURLToPath(import.meta.url)\nconst __dirname = dirname(__filename)\n\nexport function createViteConfigForTests(mode: 'bundle' | 'watch', projDir: string, prepDir: string): InlineConfig {\n // Use `template-tests` as the root directory for the tests project\n const root = resolvePath(__dirname, '..', 'template-tests')\n\n // Get the base glob path; apparently this must be a relative path (relative to\n // the `template-tests/src` directory where the glob is used)\n const templateSrcDir = resolvePath(root, 'src')\n const relProjDir = relative(templateSrcDir, projDir)\n // XXX: The glob pattern must use forward slashes only, so on Windows we need to\n // convert backslashes to slashes\n const relProjDirPath = relProjDir.replaceAll('\\\\', '/')\n\n // Include check test definitions in files matching `checks/*.yaml` under\n // the configured project root directory. We also include `*.check.yaml`,\n // which was the naming used in earlier versions of the create package and\n // related examples.\n // TODO: Use yaml path/pattern from options\n const yamlCheckGlobPatterns = `['${relProjDirPath}/**/checks/*.yaml', '${relProjDirPath}/**/*.check.yaml']`\n\n // Include comparison test definitions in files matching `comparisons/*.yaml`\n // under the configured project root directory\n // TODO: Use yaml path/pattern from options\n const yamlComparisonGlobPatterns = `['${relProjDirPath}/**/comparisons/*.yaml']`\n\n // Calculate output directory relative to the template root\n // TODO: For now we write it to `prepDir`; make this configurable?\n const outDir = relative(root, prepDir)\n\n return {\n // Don't use an external config file\n configFile: false,\n\n // Use the root directory configured above\n root,\n\n // Don't clear the screen in dev mode so that we can see builder output\n clearScreen: false,\n\n // TODO: Disable vite output by default?\n // logLevel: 'silent',\n\n plugins: [\n // Inject special values into the generated JS\n // TODO: We currently have to use `@rollup/plugin-replace` instead of Vite's\n // built-in `define` feature because the latter does not seem to run before\n // the glob handler (which requires the glob to be injected as a literal)\n replace({\n preventAssignment: true,\n delimiters: ['', ''],\n values: {\n // Inject the glob patterns for matching model check yaml files\n '\"./__YAML_CHECK_GLOB_PATTERNS__\"': yamlCheckGlobPatterns,\n // Inject the glob patterns for matching model comparison yaml files\n '\"./__YAML_COMPARISON_GLOB_PATTERNS__\"': yamlComparisonGlobPatterns\n }\n }) as unknown as PluginOption\n ],\n\n build: {\n // Write output files to the configured directory (instead of the default `dist`);\n // note that this must be relative to the project `root`\n outDir,\n emptyOutDir: false,\n\n lib: {\n entry: './src/index.ts',\n formats: ['es'],\n fileName: () => 'check-tests.js'\n },\n\n // Enable watch mode if requested\n watch: mode === 'watch' && {},\n\n rollupOptions: {\n // Prevent dependencies from being included in packaged library\n // TODO: For now we include check-core in the packaged library so that its\n // dependencies are correctly resolved at runtime. Ideally this would only\n // include a couple functions that are used for defining tests, but Vite 2.x\n // does not implement tree shaking for ES libraries, which means the generated\n // library is much larger than it needs to be. Once we upgrade to Vite 3.x,\n // the generated library should be smaller; see related fix:\n // https://github.com/vitejs/vite/pull/8737\n // external: Object.keys(pkg.dependencies)\n }\n }\n }\n}\n"],"mappings":"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","names":["import_node_fs","import_promises","import_node_path","import_url","import_check_core","joinPath","pico","stat","import_check_core","__filename","joinPath","resolvePath","import_node_path","import_node_url","import_promises","import_node_path","chokidar","joinPath","__filename","__dirname","resolvePath","joinPath","replace","import_path","import_url","import_plugin_replace","__filename","__dirname","resolvePath","replace","joinPath"]}
package/dist/index.d.cts DELETED
@@ -1,83 +0,0 @@
1
- import { Plugin } from '@sdeverywhere/build';
2
-
3
- /**
4
- * Describes a bundle used by model-check.
5
- *
6
- * If `path` is defined, model-check will load that local JS bundle file.
7
- *
8
- * If `path` is undefined, but `url` is defined, model-check will load the
9
- * remote bundle file at that URL.
10
- *
11
- * If both `path` and `url` are undefined, model-check will load the latest
12
- * `check-bundle.js` generated by the build process.
13
- */
14
- interface CheckBundle {
15
- /** The name of the bundle as displayed in the report (this is typically a branch name). */
16
- name: string;
17
- /** The absolute path to the local JS bundle file. */
18
- path?: string;
19
- /** The URL of the remote bundle file. */
20
- url?: string;
21
- }
22
- /**
23
- * The options that control how the model-check report is generated or served.
24
- */
25
- interface CheckPluginOptions {
26
- /**
27
- * The baseline bundle, i.e., the "left" bundle used in comparisons.
28
- *
29
- * If `baseline` is undefined, no comparison tests will be run.
30
- */
31
- baseline?: CheckBundle;
32
- /**
33
- * The current bundle, i.e., the bundle that is being developed and checked.
34
- *
35
- * This will be the "right" bundle that is compared to the "left" (baseline)
36
- * bundle, if `baseline` is defined. If `baseline` is undefined, no
37
- * comparison tests will be run, but check tests will still be run using
38
- * the `current` bundle.
39
- *
40
- * If `current` is undefined, the latest `check-bundle.js` generated by
41
- * the build process will be used as the default `current` bundle, with
42
- * `name` set to "current".
43
- */
44
- current?: CheckBundle;
45
- /**
46
- * The URL to a JSON file containing the list of remote bundles that will be available
47
- * in local development mode. The JSON file is expected to contain an array of
48
- * `BundleLocation` objects. If undefined, only local bundles will be available.
49
- *
50
- * This value is only used in "development" mode and is ignored in "production"
51
- * mode (since only the configured `baseline` and `current` bundles are used
52
- * in that case).
53
- */
54
- remoteBundlesUrl?: string;
55
- /**
56
- * A custom function for fetching remote bundle files. This allows for customizing
57
- * the fetch operation, such as adding authentication headers or other custom logic.
58
- *
59
- * If undefined, a default fetch implementation will be used.
60
- *
61
- * @param url The URL of the remote bundle file to fetch.
62
- * @returns The bundle source code as a string.
63
- */
64
- fetchRemoteBundle?: (url: string) => Promise<string>;
65
- /**
66
- * The absolute path to the JS file containing the test configuration. If undefined,
67
- * a default test configuration will be used.
68
- */
69
- testConfigPath?: string;
70
- /**
71
- * The absolute path to the directory where the report will be written. If undefined,
72
- * the report will be written to the configured `prepDir`.
73
- */
74
- reportPath?: string;
75
- /**
76
- * The port used for the local dev server (defaults to 8081).
77
- */
78
- serverPort?: number;
79
- }
80
-
81
- declare function checkPlugin(options?: CheckPluginOptions): Plugin;
82
-
83
- export { type CheckBundle, type CheckPluginOptions, checkPlugin };
@@ -1,2 +0,0 @@
1
- This file is not used but must remain present to ensure that the `template-report/src/bundles`
2
- directory exists. See `vite-config-for-report.ts` for details.