supercov 4.24.7 → 4.24.8

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "supercov",
3
- "version": "4.24.7",
3
+ "version": "4.24.8",
4
4
  "description": "Coverage, security and code quality for coding agents",
5
5
  "keywords": [
6
6
  "coverage",
@@ -123,14 +123,14 @@
123
123
  "test:windows-tls": "node scripts/windows-tls-test.mjs"
124
124
  },
125
125
  "optionalDependencies": {
126
- "@supercov/cli-darwin-arm64": "4.24.7",
127
- "@supercov/cli-darwin-x64": "4.24.7",
128
- "@supercov/cli-linux-arm64-gnu": "4.24.7",
129
- "@supercov/cli-linux-arm64-musl": "4.24.7",
130
- "@supercov/cli-linux-x64-gnu": "4.24.7",
131
- "@supercov/cli-linux-x64-musl": "4.24.7",
132
- "@supercov/cli-win32-arm64": "4.24.7",
133
- "@supercov/cli-win32-x64": "4.24.7"
126
+ "@supercov/cli-darwin-arm64": "4.24.8",
127
+ "@supercov/cli-darwin-x64": "4.24.8",
128
+ "@supercov/cli-linux-arm64-gnu": "4.24.8",
129
+ "@supercov/cli-linux-arm64-musl": "4.24.8",
130
+ "@supercov/cli-linux-x64-gnu": "4.24.8",
131
+ "@supercov/cli-linux-x64-musl": "4.24.8",
132
+ "@supercov/cli-win32-arm64": "4.24.8",
133
+ "@supercov/cli-win32-x64": "4.24.8"
134
134
  },
135
135
  "peerDependencies": {
136
136
  "@playwright/test": ">=1.55.0",
@@ -1,6 +1,8 @@
1
- import { appendFileSync, chmodSync, existsSync, mkdirSync, openSync, closeSync, fsyncSync, renameSync, rmSync, statSync, writeFileSync, } from "node:fs";
1
+ import fs, { appendFileSync, chmodSync, existsSync, mkdirSync, openSync, closeSync, fsyncSync, renameSync, rmSync, statSync, writeFileSync, } from "node:fs";
2
2
  import { randomUUID } from "node:crypto";
3
- import { dirname, resolve } from "node:path";
3
+ import { syncBuiltinESMExports } from "node:module";
4
+ import { threadId } from "node:worker_threads";
5
+ import { dirname, resolve, sep } from "node:path";
4
6
  import { Buffer } from "node:buffer";
5
7
 
6
8
  // In a container Supercov's `docker` launcher mounts the run's directory
@@ -146,3 +148,41 @@ export function appendEvidenceRecord(directory, prefix, payload) {
146
148
  append(journal.path, line);
147
149
  journal.size += Buffer.byteLength(line);
148
150
  }
151
+
152
+ // Playwright 1.59 writes each file it compiles into its cache in place and
153
+ // reads it back unchecked: a process that read one while another wrote it
154
+ // ran an empty module -- a config of no `default` failed at "Cannot add
155
+ // property metadata, object is not extensible", a test file at "does not
156
+ // provide an export named". The cache a run gives it starts empty and is
157
+ // shared by every Playwright of the run, the containers a sealed suite execs
158
+ // into among them, so every first compile raced; there each file is written
159
+ // whole, or is not there yet and is compiled again. A file written beside the
160
+ // cache's folders, not in one, is never taken for an old entry and removed.
161
+ //
162
+ // Playwright compiles in two threads: the config and CommonJS files in the
163
+ // process's own, ES modules in the thread its loader hooks run in, which has
164
+ // its own `fs` and does not run `--import`. Each calls this. The partial
165
+ // file's name is unique to the write: a process ID repeats across containers
166
+ // and both threads of one process count from zero.
167
+ let cacheWritesWhole = false;
168
+ export function writePlaywrightCacheWhole() {
169
+ const transformCache = process.env.PWTEST_CACHE_DIR;
170
+ if (!transformCache || cacheWritesWhole)
171
+ return;
172
+ cacheWritesWhole = true;
173
+ const cacheFolder = resolve(transformCache) + sep;
174
+ const writeFileSync = fs.writeFileSync;
175
+ fs.writeFileSync = function (file, ...rest) {
176
+ if (typeof file !== "string" || !resolve(file).startsWith(cacheFolder))
177
+ return writeFileSync.call(this, file, ...rest);
178
+ const partial = resolve(transformCache, `.writing-${process.pid}-${threadId}-${randomUUID()}`);
179
+ try {
180
+ writeFileSync.call(this, partial, ...rest);
181
+ fs.renameSync(partial, file);
182
+ }
183
+ finally {
184
+ fs.rmSync(partial, { force: true });
185
+ }
186
+ };
187
+ syncBuiltinESMExports();
188
+ }
@@ -13,28 +13,10 @@ import { fileURLToPath } from "node:url";
13
13
  import { installLaunchSupervisor, wrapImportedCapability } from "./launchSupervisor.mjs";
14
14
  import { __supercovBindCapabilityWrapper } from "./capability.mjs";
15
15
  import { adaptRunnerEntry, noteSkippedCoverageThresholds } from "./runnerEntry.mjs";
16
+ import { writePlaywrightCacheWhole } from "./atomic.mjs";
16
17
  installLaunchSupervisor();
17
- // Playwright 1.59 writes each file it compiles into its cache in place and
18
- // reads it back unchecked: a process that read one while another wrote it
19
- // ran an empty module, and a config of no `default` failed at "Cannot add
20
- // property metadata, object is not extensible". The cache a run gives it
21
- // starts empty, so every run compiled; there each file is written whole, or
22
- // is not there yet and is compiled again. A file written beside the cache's
23
- // folders, not in one, is never taken for an old entry and removed.
24
- const transformCache = process.env.PWTEST_CACHE_DIR;
25
- if (transformCache) {
26
- const cacheFolder = resolve(transformCache) + sep;
27
- const writeFileSync = fs.writeFileSync;
28
- let written = 0;
29
- fs.writeFileSync = function (file, ...rest) {
30
- if (typeof file !== "string" || !resolve(file).startsWith(cacheFolder))
31
- return writeFileSync.call(this, file, ...rest);
32
- const partial = resolve(transformCache, `.writing-${process.pid}-${written++}`);
33
- writeFileSync.call(this, partial, ...rest);
34
- fs.renameSync(partial, file);
35
- };
36
- syncBuiltinESMExports();
37
- }
18
+ // Playwright's compile cache, written whole (atomic.mjs says why).
19
+ writePlaywrightCacheWhole();
38
20
  // Instrumented sources import the browser-safe capability seam; bind the
39
21
  // real supervisor implementation before any user module evaluates.
40
22
  __supercovBindCapabilityWrapper(wrapImportedCapability);
@@ -1,6 +1,10 @@
1
1
  import { appendFileSync, readFileSync } from "node:fs";
2
2
  import { dirname, resolve as resolvePath } from "node:path";
3
3
  import { fileURLToPath, pathToFileURL } from "node:url";
4
+ import { writePlaywrightCacheWhole } from "./atomic.mjs";
5
+ // This thread is where Playwright compiles ES modules and writes them into
6
+ // its cache: written whole here too (atomic.mjs says why).
7
+ writePlaywrightCacheWhole();
4
8
  const GENERATED_TARGET = "__SUPERCOV_PLAYWRIGHT_MODULE__";
5
9
  const TARGET = process.env.SUPERCOV_PLAYWRIGHT_MODULE ??
6
10
  (GENERATED_TARGET.startsWith("__") ? "@playwright/test" : GENERATED_TARGET);