qunitx-cli 0.23.3 → 0.23.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -306,10 +306,11 @@ Don't forget to add the plugin's file extension(s) to `qunitx.extensions` so dir
306
306
 
307
307
  ### Environment variables
308
308
 
309
- | Variable | Description |
310
- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
311
- | `CHROME_BIN` | Path to the Chrome/Chromium executable. Required on systems where Chrome is not on `PATH` (e.g. many CI environments). Set automatically when using `browser-actions/setup-chrome` in GitHub Actions. |
312
- | `QUNITX_BROWSER` | Browser engine to use (`chromium`, `firefox`, `webkit`). Equivalent to `--browser` on the CLI. Useful in CI matrix jobs. |
309
+ | Variable | Description |
310
+ | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
311
+ | `CHROME_BIN` | Path to the Chrome/Chromium executable. Required on systems where Chrome is not on `PATH` (e.g. many CI environments). Set automatically when using `browser-actions/setup-chrome` in GitHub Actions. |
312
+ | `QUNITX_BROWSER` | Browser engine to use (`chromium`, `firefox`, `webkit`). Equivalent to `--browser` on the CLI. Useful in CI matrix jobs. |
313
+ | `NODE_COMPILE_CACHE` | Standard Node env, auto-enabled by qunitx. Stores V8 bytecode for the CLI + its dep graph on disk so the second and subsequent `qunitx` runs skip the parser pass — measured ~8% faster end-to-end (more on slow CI disks). Defaults to `${TMPDIR}/node-compile-cache`; set to a path to relocate (handy for a CI cache key) or `""` to disable. |
313
314
 
314
315
  If you do not provide any HTML template, qunitx falls back to its built-in `test/tests.html` boilerplate internally, so `qunitx init` is optional.
315
316
 
package/bin/qunitx.js CHANGED
@@ -3,12 +3,22 @@
3
3
  // Prefers a pre-built SEA binary from the matching optional platform package
4
4
  // (qunitx-cli-linux-x64, qunitx-cli-darwin-arm64, etc.) when available.
5
5
  // Falls back to the bundled JS CLI (dist/cli.js) which requires Node.js + node_modules.
6
+ import nodeModule, { createRequire } from 'node:module';
6
7
  import { spawn } from 'node:child_process';
7
8
  import { access, constants, readFile } from 'node:fs/promises';
8
- import { createRequire } from 'node:module';
9
9
  import { fileURLToPath } from 'node:url';
10
10
  import { dirname, join } from 'node:path';
11
11
 
12
+ // Turn on V8's on-disk compile cache before importing dist/cli.js — caches
13
+ // the bundle + its external deps (esbuild, playwright-core, ws) across cold
14
+ // invocations. The active dir is written back to process.env so any child
15
+ // spawn (SEA binary below, daemon auto-spawn from cli.ts) inherits and also
16
+ // auto-enables from boot. `in` check preserves a user-set empty string.
17
+ const cacheResult = nodeModule.enableCompileCache?.();
18
+ if (cacheResult?.directory && !('NODE_COMPILE_CACHE' in process.env)) {
19
+ process.env.NODE_COMPILE_CACHE = cacheResult.directory;
20
+ }
21
+
12
22
  const __dirname = dirname(fileURLToPath(import.meta.url));
13
23
  const require = createRequire(import.meta.url);
14
24
 
package/dist/cli.js CHANGED
@@ -374,7 +374,7 @@ var init_package = __esm({
374
374
  package_default = {
375
375
  name: "qunitx-cli",
376
376
  type: "module",
377
- version: "0.23.3",
377
+ version: "0.23.5",
378
378
  description: "Browser runner for QUnitx: run your qunitx tests in google-chrome",
379
379
  author: "Izel Nakri",
380
380
  license: "MIT",
@@ -397,7 +397,7 @@ var init_package = __esm({
397
397
  prepublishOnly: "npm run build",
398
398
  format: 'prettier --check "lib/**/*.ts" "test/**/*.ts" "scripts/**/*.js" "bin/**/*.js" "*.ts" "package.json" ".github/**/*.yml"',
399
399
  "format:fix": 'prettier --write "lib/**/*.ts" "test/**/*.ts" "scripts/**/*.js" "bin/**/*.js" "*.ts" "package.json" ".github/**/*.yml"',
400
- lint: "deno lint lib/ bin/ cli.ts",
400
+ lint: "deno lint lib/ bin/ test/ scripts/ cli.ts",
401
401
  "lint:docs": "node scripts/lint-docs.js",
402
402
  docs: `deno doc --html --name="qunitx-cli" --output=docs/lib 'lib/**/*.ts' README.md`,
403
403
  "changelog:unreleased": "git-cliff --unreleased --strip all",
@@ -519,6 +519,7 @@ ${color("--browser")} : browser engine to run tests in: chromium, firefox, webki
519
519
  ${color("--before")} : run a script before the tests(i.e start a new web server before tests)
520
520
  ${color("--after")} : run a script after the tests(i.e save test results to a file)
521
521
  ${color("--no-daemon")} : don't use the daemon for this run \u2014 skips a running daemon and prevents ${color("QUNITX_DAEMON")} auto-spawn
522
+ ${color("--trace-perf")} : write timestamped startup-perf trace lines to stderr (Chrome pre-launch, module load, browser bind)
522
523
 
523
524
  ${highlight("Example:")} $ ${color("qunitx test/foo.ts app/e2e --debug --watch --before=scripts/start-new-webserver.js --after=scripts/write-test-results.js")}
524
525
 
@@ -530,6 +531,8 @@ ${color("$ qunitx daemon <start|stop|status>")} # Optional persistent daemo
530
531
  ${highlight("Environment:")}
531
532
  ${color("QUNITX_DAEMON=1")} : auto-spawn the daemon on the first qunitx run; reuse it on every run after (overrides the CI=1 bypass)
532
533
  ${color("QUNITX_NO_DAEMON=1")} : never use the daemon for this run
534
+ ${color("QUNITX_BROWSER=...")} : default browser engine when ${color("--browser")} is not passed (chromium, firefox, webkit)
535
+ ${color("QUNITX_DEBUG=1")} : enables ${color("--debug")} for every run; per-invocation ${color("--debug=false")} still wins
533
536
  `);
534
537
  }
535
538
  var highlight, color;
@@ -877,7 +880,7 @@ function awaitClose(socket) {
877
880
  async function pingDaemon() {
878
881
  const socket = await tryConnect();
879
882
  if (!socket) return null;
880
- const result = new Promise((resolve) => {
883
+ const result2 = new Promise((resolve) => {
881
884
  attachLineParser(socket, (chunk) => {
882
885
  if (chunk.type === "pong") resolve(chunk);
883
886
  });
@@ -885,7 +888,7 @@ async function pingDaemon() {
885
888
  socket.once("error", () => resolve(null));
886
889
  });
887
890
  send(socket, { type: "ping" });
888
- const pong = await result;
891
+ const pong = await result2;
889
892
  socket.end();
890
893
  return pong;
891
894
  }
@@ -1085,32 +1088,32 @@ var init_test_file_paths = __esm({
1085
1088
  import path5 from "node:path";
1086
1089
  function parseCliFlags(projectRoot) {
1087
1090
  const providedFlags = process.argv.slice(2).reduce(
1088
- (result, arg) => {
1091
+ (result2, arg) => {
1089
1092
  if (arg.startsWith("--debug")) {
1090
- return Object.assign(result, { debug: parseBoolean(arg.split("=")[1]) });
1093
+ return Object.assign(result2, { debug: parseBoolean(arg.split("=")[1]) });
1091
1094
  } else if (arg.startsWith("--watch")) {
1092
- return Object.assign(result, { watch: parseBoolean(arg.split("=")[1]) });
1095
+ return Object.assign(result2, { watch: parseBoolean(arg.split("=")[1]) });
1093
1096
  } else if (arg === "-o" || arg.startsWith("-o=") || arg.startsWith("--open")) {
1094
1097
  const value = arg.split("=")[1];
1095
1098
  const open = value === void 0 || value === "true" ? true : value === "false" ? false : value;
1096
- return Object.assign(result, { open });
1099
+ return Object.assign(result2, { open });
1097
1100
  } else if (arg.startsWith("--failfast") || arg.startsWith("--failFast")) {
1098
- return Object.assign(result, { failFast: parseBoolean(arg.split("=")[1]) });
1101
+ return Object.assign(result2, { failFast: parseBoolean(arg.split("=")[1]) });
1099
1102
  } else if (arg.startsWith("--timeout")) {
1100
- return Object.assign(result, { timeout: Number(arg.split("=")[1]) || FALLBACK_TIMEOUT_MS });
1103
+ return Object.assign(result2, { timeout: Number(arg.split("=")[1]) || FALLBACK_TIMEOUT_MS });
1101
1104
  } else if (arg.startsWith("--output")) {
1102
- return Object.assign(result, { output: arg.split("=")[1] });
1105
+ return Object.assign(result2, { output: arg.split("=")[1] });
1103
1106
  } else if (arg.endsWith(".html")) {
1104
- if (result.htmlPaths) {
1105
- result.htmlPaths.push(arg);
1107
+ if (result2.htmlPaths) {
1108
+ result2.htmlPaths.push(arg);
1106
1109
  } else {
1107
- result.htmlPaths = [arg];
1110
+ result2.htmlPaths = [arg];
1108
1111
  }
1109
- return result;
1112
+ return result2;
1110
1113
  } else if (arg.startsWith("--port")) {
1111
- return Object.assign(result, { port: Number(arg.split("=")[1]), portExplicit: true });
1114
+ return Object.assign(result2, { port: Number(arg.split("=")[1]), portExplicit: true });
1112
1115
  } else if (arg.startsWith("--extensions")) {
1113
- return Object.assign(result, {
1116
+ return Object.assign(result2, {
1114
1117
  extensions: arg.split("=")[1].split(",").map((extension) => extension.trim())
1115
1118
  });
1116
1119
  } else if (arg.startsWith("--browser")) {
@@ -1121,22 +1124,22 @@ function parseCliFlags(projectRoot) {
1121
1124
  );
1122
1125
  process.exit(1);
1123
1126
  }
1124
- return Object.assign(result, { browser: value });
1127
+ return Object.assign(result2, { browser: value });
1125
1128
  } else if (arg.startsWith("--before")) {
1126
- return Object.assign(result, { before: parseModule(arg.split("=")[1]) });
1129
+ return Object.assign(result2, { before: parseModule(arg.split("=")[1]) });
1127
1130
  } else if (arg.startsWith("--after")) {
1128
- return Object.assign(result, { after: parseModule(arg.split("=")[1]) });
1131
+ return Object.assign(result2, { after: parseModule(arg.split("=")[1]) });
1129
1132
  } else if (arg === "--trace-perf") {
1130
- return result;
1133
+ return result2;
1131
1134
  }
1132
1135
  if (arg.startsWith("-")) {
1133
1136
  console.warn(`# Warning: Unknown flag "${arg}" \u2014 ignored`);
1134
- return result;
1137
+ return result2;
1135
1138
  }
1136
- result.inputs.add(
1139
+ result2.inputs.add(
1137
1140
  arg.startsWith(projectRoot) || arg.startsWith("/") ? arg : path5.join(process.cwd(), arg)
1138
1141
  );
1139
- return result;
1142
+ return result2;
1140
1143
  },
1141
1144
  { inputs: /* @__PURE__ */ new Set([]) }
1142
1145
  );
@@ -1150,12 +1153,15 @@ function parseCliFlags(projectRoot) {
1150
1153
  }
1151
1154
  providedFlags.browser = envBrowser;
1152
1155
  }
1156
+ if (providedFlags.debug === void 0 && process.env.QUNITX_DEBUG) {
1157
+ providedFlags.debug = true;
1158
+ }
1153
1159
  return { ...providedFlags, inputs: Array.from(providedFlags.inputs) };
1154
1160
  }
1155
- function parseBoolean(result, defaultValue = true) {
1156
- if (result === "true") {
1161
+ function parseBoolean(result2, defaultValue = true) {
1162
+ if (result2 === "true") {
1157
1163
  return true;
1158
- } else if (result === "false") {
1164
+ } else if (result2 === "false") {
1159
1165
  return false;
1160
1166
  }
1161
1167
  return defaultValue;
@@ -1375,7 +1381,7 @@ var init_indent_string = __esm({
1375
1381
 
1376
1382
  // lib/utils/source-map-decoder.ts
1377
1383
  function decodeMappings(mappings) {
1378
- const result = [];
1384
+ const result2 = [];
1379
1385
  const cursor = { position: 0 };
1380
1386
  const mappingsLength = mappings.length;
1381
1387
  let segments = [];
@@ -1395,14 +1401,14 @@ function decodeMappings(mappings) {
1395
1401
  } else if (charCode === COMMA) {
1396
1402
  cursor.position++;
1397
1403
  } else {
1398
- result.push(segments);
1404
+ result2.push(segments);
1399
1405
  segments = [];
1400
1406
  generatedCol = 0;
1401
1407
  cursor.position++;
1402
1408
  }
1403
1409
  }
1404
- result.push(segments);
1405
- return result;
1410
+ result2.push(segments);
1411
+ return result2;
1406
1412
  }
1407
1413
  function parseSourceMap(json, outDir) {
1408
1414
  const map = JSON.parse(json);
@@ -2517,9 +2523,9 @@ function registerSharedStaticHandler(server, groupConfigs) {
2517
2523
  function replaceAssetPaths(html, htmlPath, projectRoot) {
2518
2524
  const assetPaths = findInternalAssetsFromHTML(html);
2519
2525
  const htmlDirectory = htmlPath.split("/").slice(0, -1).join("/");
2520
- return assetPaths.reduce((result, assetPath) => {
2526
+ return assetPaths.reduce((result2, assetPath) => {
2521
2527
  const normalizedFullAbsolutePath = path6.normalize(`${htmlDirectory}/${assetPath}`);
2522
- return result.replace(assetPath, normalizedFullAbsolutePath.replace(projectRoot, "."));
2528
+ return result2.replace(assetPath, normalizedFullAbsolutePath.replace(projectRoot, "."));
2523
2529
  }, html);
2524
2530
  }
2525
2531
  function testRuntimeToInject(config, groupId) {
@@ -3197,19 +3203,19 @@ async function buildAllGroupBundles(groupConfigs, groupCachedContents) {
3197
3203
  jsx: "automatic",
3198
3204
  footer: { js: 'window.dispatchEvent(new CustomEvent("qunitx:tests-ready"));' }
3199
3205
  };
3200
- const hasSmallOutput = (result) => (result.outputFiles ?? []).some(
3206
+ const hasSmallOutput = (result2) => (result2.outputFiles ?? []).some(
3201
3207
  (outputFile) => GROUP_OUTPUT_REGEX.test(outputFile.path) && !outputFile.path.endsWith(".map") && outputFile.contents.length < EMPTY_BUNDLE_THRESHOLD
3202
3208
  );
3203
3209
  const buildWithRetry = async (retriesLeft) => {
3204
- const result = await esbuild.build(buildOptions);
3205
- if (!hasSmallOutput(result) || retriesLeft === 0) return result;
3210
+ const result2 = await esbuild.build(buildOptions);
3211
+ if (!hasSmallOutput(result2) || retriesLeft === 0) return result2;
3206
3212
  await new Promise((resolve) => setTimeout(resolve, RETRY_DELAY_MS));
3207
3213
  return buildWithRetry(retriesLeft - 1);
3208
3214
  };
3209
3215
  try {
3210
- const result = await buildWithRetry(MAX_RETRIES);
3216
+ const result2 = await buildWithRetry(MAX_RETRIES);
3211
3217
  await Promise.all(
3212
- (result.outputFiles ?? []).map((outputFile) => {
3218
+ (result2.outputFiles ?? []).map((outputFile) => {
3213
3219
  const match = GROUP_OUTPUT_REGEX.exec(outputFile.path);
3214
3220
  if (!match) return Promise.resolve();
3215
3221
  const slotIndex = parseInt(match[1]);
@@ -3271,12 +3277,12 @@ function buildFilteredTests(filteredTests, outputPath, config) {
3271
3277
  );
3272
3278
  }
3273
3279
  async function runWithOverlayfsRetry(getContents, needsDisk) {
3274
- let { result, js } = await getContents();
3280
+ let { result: result2, js } = await getContents();
3275
3281
  const initialSize = js.length;
3276
3282
  for (let retry = 1; retry <= MAX_RETRIES; retry++) {
3277
3283
  if (js.length >= EMPTY_BUNDLE_THRESHOLD) break;
3278
3284
  await new Promise((resolve) => setTimeout(resolve, RETRY_DELAY_MS));
3279
- ({ result, js } = await getContents());
3285
+ ({ result: result2, js } = await getContents());
3280
3286
  }
3281
3287
  if (js.length < EMPTY_BUNDLE_THRESHOLD && js.length !== initialSize) {
3282
3288
  console.log(
@@ -3285,7 +3291,7 @@ async function runWithOverlayfsRetry(getContents, needsDisk) {
3285
3291
  }
3286
3292
  if (needsDisk) {
3287
3293
  await Promise.all(
3288
- result.outputFiles.map((outputFile) => fs10.writeFile(outputFile.path, outputFile.contents))
3294
+ result2.outputFiles.map((outputFile) => fs10.writeFile(outputFile.path, outputFile.contents))
3289
3295
  );
3290
3296
  }
3291
3297
  return js;
@@ -3293,9 +3299,9 @@ async function runWithOverlayfsRetry(getContents, needsDisk) {
3293
3299
  function buildWithOverlayfsRetry(options, needsDisk) {
3294
3300
  const buildOpts = { ...options, write: false };
3295
3301
  return runWithOverlayfsRetry(async () => {
3296
- const result = await esbuild.build(buildOpts);
3297
- const jsFile = result.outputFiles.find((f) => !f.path.endsWith(".map"));
3298
- return { result, js: Buffer.from(jsFile.contents) };
3302
+ const result2 = await esbuild.build(buildOpts);
3303
+ const jsFile = result2.outputFiles.find((f) => !f.path.endsWith(".map"));
3304
+ return { result: result2, js: Buffer.from(jsFile.contents) };
3299
3305
  }, needsDisk);
3300
3306
  }
3301
3307
  async function buildIncrementally(options, fileKey, cache, needsDisk) {
@@ -3308,9 +3314,9 @@ async function buildIncrementally(options, fileKey, cache, needsDisk) {
3308
3314
  }
3309
3315
  const ctx = cache._esbuildContext;
3310
3316
  return runWithOverlayfsRetry(async () => {
3311
- const result = await ctx.rebuild();
3312
- const jsFile = result.outputFiles.find((f) => !f.path.endsWith(".map"));
3313
- return { result, js: Buffer.from(jsFile.contents) };
3317
+ const result2 = await ctx.rebuild();
3318
+ const jsFile = result2.outputFiles.find((f) => !f.path.endsWith(".map"));
3319
+ return { result: result2, js: Buffer.from(jsFile.contents) };
3314
3320
  }, needsDisk);
3315
3321
  }
3316
3322
  function esbuildTarget(browser) {
@@ -3513,6 +3519,11 @@ var init_open_output_in_browser = __esm({
3513
3519
  import fs11 from "node:fs";
3514
3520
  import { readdir, stat, lstat } from "node:fs/promises";
3515
3521
  import path9 from "node:path";
3522
+ function recordJustAdded(config, filePath) {
3523
+ let map = justAddedAt.get(config);
3524
+ if (!map) justAddedAt.set(config, map = /* @__PURE__ */ new Map());
3525
+ map.set(filePath, Date.now());
3526
+ }
3516
3527
  function setupFileWatchers(testFileLookupPaths, config, onEventFunc, onFinishFunc) {
3517
3528
  const extensions = config.extensions || defaultProjectConfigValues.extensions;
3518
3529
  config._lastBuildEndMs ??= Date.now();
@@ -3679,6 +3690,11 @@ function handleWatchEvent(config, extensions, event, filePath, onEventFunc, onFi
3679
3690
  return Promise.resolve();
3680
3691
  if (event === "change" && config._building && config._justAddedFiles?.has(filePath))
3681
3692
  return Promise.resolve();
3693
+ if (event === "change") {
3694
+ const addedAt = justAddedAt.get(config)?.get(filePath);
3695
+ if (addedAt !== void 0 && Date.now() - addedAt < ADD_SUPPRESS_WINDOW_MS)
3696
+ return Promise.resolve();
3697
+ }
3682
3698
  mutateFSTree(config.fsTree, event, filePath);
3683
3699
  console.log(
3684
3700
  "#",
@@ -3690,6 +3706,7 @@ function handleWatchEvent(config, extensions, event, filePath, onEventFunc, onFi
3690
3706
  "#",
3691
3707
  magenta().bold("==================================================================")
3692
3708
  );
3709
+ if (event === "add") recordJustAdded(config, filePath);
3693
3710
  if (config._building) {
3694
3711
  if (event === "add") config._justAddedFiles?.add(filePath);
3695
3712
  config._pendingBuildTrigger = () => handleWatchEvent(config, extensions, event, filePath, onEventFunc, onFinishFunc);
@@ -3697,12 +3714,12 @@ function handleWatchEvent(config, extensions, event, filePath, onEventFunc, onFi
3697
3714
  }
3698
3715
  config._building = true;
3699
3716
  config._justAddedFiles = event === "add" ? /* @__PURE__ */ new Set([filePath]) : /* @__PURE__ */ new Set();
3700
- const result = onEventFunc(event, filePath);
3701
- if (!(result instanceof Promise)) {
3717
+ const result2 = onEventFunc(event, filePath);
3718
+ if (!(result2 instanceof Promise)) {
3702
3719
  config._building = false;
3703
3720
  return Promise.resolve();
3704
3721
  }
3705
- return result.then(() => onFinishFunc?.(filePath, event)).catch((error) => console.error("#", red("Build error:"), error.message || error)).finally(() => {
3722
+ return result2.then(() => onFinishFunc?.(filePath, event)).catch((error) => console.error("#", red("Build error:"), error.message || error)).finally(() => {
3706
3723
  config._building = false;
3707
3724
  config._lastBuildEndMs = Date.now();
3708
3725
  if (config._pendingBuildTrigger) {
@@ -3798,7 +3815,7 @@ function colorEvent(event) {
3798
3815
  if (event === "add" || event === "addDir") return green("ADDED:");
3799
3816
  return red("REMOVED:");
3800
3817
  }
3801
- var CHANGE_DEDUPE_MS, SYMLINK_POLL_INTERVAL_MS, OVERLAYFS_RENAME_RETRY_MS, RESCAN_INTERVAL_MS;
3818
+ var CHANGE_DEDUPE_MS, SYMLINK_POLL_INTERVAL_MS, OVERLAYFS_RENAME_RETRY_MS, RESCAN_INTERVAL_MS, ADD_SUPPRESS_WINDOW_MS, justAddedAt;
3802
3819
  var init_file_watcher = __esm({
3803
3820
  "lib/setup/file-watcher.ts"() {
3804
3821
  init_color();
@@ -3807,6 +3824,8 @@ var init_file_watcher = __esm({
3807
3824
  SYMLINK_POLL_INTERVAL_MS = 500;
3808
3825
  OVERLAYFS_RENAME_RETRY_MS = 50;
3809
3826
  RESCAN_INTERVAL_MS = 1e3;
3827
+ ADD_SUPPRESS_WINDOW_MS = 1e3;
3828
+ justAddedAt = /* @__PURE__ */ new WeakMap();
3810
3829
  }
3811
3830
  });
3812
3831
 
@@ -4211,14 +4230,14 @@ async function buildCachedContent(config, htmlPaths) {
4211
4230
  config.htmlPaths.map((htmlPath) => fs14.readFile(htmlPath).catch(() => null))
4212
4231
  );
4213
4232
  const cachedContent = htmlPaths.reduce(
4214
- (result, _htmlPath, index) => {
4233
+ (result2, _htmlPath, index) => {
4215
4234
  const buffer = htmlBuffers[index];
4216
- if (buffer === null) return result;
4235
+ if (buffer === null) return result2;
4217
4236
  const filePath = config.htmlPaths[index];
4218
4237
  const html = buffer.toString();
4219
4238
  if (isCustomTemplate(html)) {
4220
- result.dynamicContentHTMLs[filePath] = html;
4221
- result.htmlPathsToRunTests.push(filePath.replace(config.projectRoot, ""));
4239
+ result2.dynamicContentHTMLs[filePath] = html;
4240
+ result2.htmlPathsToRunTests.push(filePath.replace(config.projectRoot, ""));
4222
4241
  } else {
4223
4242
  console.log(
4224
4243
  "#",
@@ -4226,12 +4245,12 @@ async function buildCachedContent(config, htmlPaths) {
4226
4245
  `WARNING: Static html file with no {{qunitxScript}} or handlebars-style tokens detected. Therefore ignoring ${filePath}`
4227
4246
  )
4228
4247
  );
4229
- result.staticHTMLs[filePath] = html;
4248
+ result2.staticHTMLs[filePath] = html;
4230
4249
  }
4231
4250
  findInternalAssetsFromHTML(html).forEach((key) => {
4232
- result.assets.add(normalizeInternalAssetPathFromHTML(config.projectRoot, key, filePath));
4251
+ result2.assets.add(normalizeInternalAssetPathFromHTML(config.projectRoot, key, filePath));
4233
4252
  });
4234
- return result;
4253
+ return result2;
4235
4254
  },
4236
4255
  {
4237
4256
  allTestCode: null,
@@ -4270,16 +4289,16 @@ async function readTimingCache(projectRoot) {
4270
4289
  }
4271
4290
  }
4272
4291
  function computeFileTimes(groups, weights, wallTimes) {
4273
- const result = /* @__PURE__ */ new Map();
4292
+ const result2 = /* @__PURE__ */ new Map();
4274
4293
  groups.forEach((group, i) => {
4275
4294
  const wallMs = wallTimes.get(i);
4276
4295
  if (wallMs === void 0) return;
4277
4296
  const total = group.reduce((sum, f) => sum + (weights.get(f) ?? 0), 0);
4278
4297
  group.forEach(
4279
- (f) => result.set(f, total > 0 ? wallMs * ((weights.get(f) ?? 0) / total) : wallMs / group.length)
4298
+ (f) => result2.set(f, total > 0 ? wallMs * ((weights.get(f) ?? 0) / total) : wallMs / group.length)
4280
4299
  );
4281
4300
  });
4282
- return result;
4301
+ return result2;
4283
4302
  }
4284
4303
  async function persistTimings(fileTimes, projectRoot) {
4285
4304
  await fs14.writeFile(
@@ -4744,9 +4763,9 @@ async function startDaemon() {
4744
4763
  `);
4745
4764
  return 0;
4746
4765
  }
4747
- const result = await spawnAndWaitForDaemon();
4748
- if (result) {
4749
- process.stdout.write(`Daemon started (pid ${result.pid})
4766
+ const result2 = await spawnAndWaitForDaemon();
4767
+ if (result2) {
4768
+ process.stdout.write(`Daemon started (pid ${result2.pid})
4750
4769
  `);
4751
4770
  return 0;
4752
4771
  }
@@ -4806,6 +4825,13 @@ ${highlight2("Tip:")} set ${color2("QUNITX_DAEMON=1")} to auto-spawn the daemon
4806
4825
  }
4807
4826
  });
4808
4827
 
4828
+ // lib/utils/enable-compile-cache.ts
4829
+ import module from "node:module";
4830
+ var result = module.enableCompileCache?.();
4831
+ if (result?.directory && !("NODE_COMPILE_CACHE" in process.env)) {
4832
+ process.env.NODE_COMPILE_CACHE = result.directory;
4833
+ }
4834
+
4809
4835
  // cli.ts
4810
4836
  init_chrome_prelaunch();
4811
4837
  init_package();
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "qunitx-cli",
3
3
  "type": "module",
4
- "version": "0.23.3",
4
+ "version": "0.23.5",
5
5
  "description": "Browser runner for QUnitx: run your qunitx tests in google-chrome",
6
6
  "author": "Izel Nakri",
7
7
  "license": "MIT",
@@ -24,7 +24,7 @@
24
24
  "prepublishOnly": "npm run build",
25
25
  "format": "prettier --check \"lib/**/*.ts\" \"test/**/*.ts\" \"scripts/**/*.js\" \"bin/**/*.js\" \"*.ts\" \"package.json\" \".github/**/*.yml\"",
26
26
  "format:fix": "prettier --write \"lib/**/*.ts\" \"test/**/*.ts\" \"scripts/**/*.js\" \"bin/**/*.js\" \"*.ts\" \"package.json\" \".github/**/*.yml\"",
27
- "lint": "deno lint lib/ bin/ cli.ts",
27
+ "lint": "deno lint lib/ bin/ test/ scripts/ cli.ts",
28
28
  "lint:docs": "node scripts/lint-docs.js",
29
29
  "docs": "deno doc --html --name=\"qunitx-cli\" --output=docs/lib 'lib/**/*.ts' README.md",
30
30
  "changelog:unreleased": "git-cliff --unreleased --strip all",