@specific.dev/spectest 0.119.5 → 0.119.6

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/next.js CHANGED
@@ -4,36 +4,49 @@ import path from "node:path";
4
4
  * versions that do not apply outputFileTracingIncludes still emit these traces
5
5
  * before runAfterProductionCompile. No source files or generated code change. */
6
6
  async function includeTracedMaps(distDir) {
7
+ const traces = [];
8
+ const serverMaps = [];
7
9
  async function walk(dir) {
8
10
  for (const entry of await fs.readdir(dir, { withFileTypes: true })) {
9
11
  const file = path.join(dir, entry.name);
10
12
  if (entry.isDirectory() && entry.name !== "cache" && entry.name !== "standalone")
11
13
  await walk(file);
12
- else if (entry.isFile() && entry.name.endsWith(".nft.json")) {
13
- const trace = JSON.parse(await fs.readFile(file, "utf8"));
14
- if (!Array.isArray(trace.files))
15
- throw new Error(`Invalid Next trace: ${file}`);
16
- const scripts = [entry.name.slice(0, -".nft.json".length), ...trace.files];
17
- const maps = [];
18
- for (const script of scripts) {
19
- if (typeof script !== "string" || !script.endsWith(".js"))
20
- continue;
21
- const map = script + ".map";
22
- try {
23
- if ((await fs.stat(path.resolve(dir, map))).isFile())
24
- maps.push(map);
25
- }
26
- catch (e) {
27
- if (e.code !== "ENOENT")
28
- throw e;
29
- }
30
- }
31
- trace.files = [...new Set([...trace.files, ...maps])];
32
- await fs.writeFile(file, JSON.stringify(trace));
14
+ else if (entry.isFile()) {
15
+ if (entry.name.endsWith(".nft.json"))
16
+ traces.push(file);
17
+ if (entry.name.endsWith(".js.map") && file.startsWith(path.join(distDir, "server") + path.sep))
18
+ serverMaps.push(file);
33
19
  }
34
20
  }
35
21
  }
36
22
  await walk(distDir);
23
+ for (const file of traces) {
24
+ const dir = path.dirname(file);
25
+ const trace = JSON.parse(await fs.readFile(file, "utf8"));
26
+ if (!Array.isArray(trace.files))
27
+ throw new Error(`Invalid Next trace: ${file}`);
28
+ const scripts = [path.basename(file).slice(0, -".nft.json".length), ...trace.files];
29
+ // Edge bundles are copied through middleware-manifest, not NFT traces.
30
+ // The server trace is always copied into standalone output; retain
31
+ // their maps there without changing the middleware's executable files.
32
+ const maps = file === path.join(distDir, "next-server.js.nft.json")
33
+ ? serverMaps.map(map => path.relative(dir, map)) : [];
34
+ for (const script of scripts) {
35
+ if (typeof script !== "string" || !script.endsWith(".js"))
36
+ continue;
37
+ const map = script + ".map";
38
+ try {
39
+ if ((await fs.stat(path.resolve(dir, map))).isFile())
40
+ maps.push(map);
41
+ }
42
+ catch (e) {
43
+ if (e.code !== "ENOENT")
44
+ throw e;
45
+ }
46
+ }
47
+ trace.files = [...new Set([...trace.files, ...maps])];
48
+ await fs.writeFile(file, JSON.stringify(trace));
49
+ }
37
50
  }
38
51
  /** Build-time companion for coverage.next(). Import this lightweight module in
39
52
  * next.config; it does not load the Spectest harness or require Next at runtime.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@specific.dev/spectest",
3
- "version": "0.119.5",
3
+ "version": "0.119.6",
4
4
  "description": "Spectest SDK for defining test environments in TypeScript.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -92,18 +92,22 @@ describe("Next adapter", () => {
92
92
  loaderHook!(dependency, {resource: "/app/node_modules/next/dist/client/router.js"});
93
93
  expect(dependency.sourceMap).toBe(false);
94
94
  });
95
- test("build hook retains traced maps and composes an existing compiler hook", async () => {
95
+ test("build hook retains traced and untraced Edge maps and composes an existing compiler hook", async () => {
96
96
  const dir=await fs.mkdtemp(path.join(os.tmpdir(),"next-trace-"));
97
97
  try {
98
98
  let called=false;
99
99
  const config=withCoverage({compiler:{runAfterProductionCompile:async()=>{
100
100
  called=true;
101
+ await fs.mkdir(path.join(dir,"server/edge"),{recursive:true});
102
+ await fs.writeFile(path.join(dir,"server/edge/middleware.js.map"),"{}");
103
+ await fs.writeFile(path.join(dir,"next-server.js.nft.json"),JSON.stringify({version:1,files:["runtime.js"]}));
101
104
  await fs.writeFile(path.join(dir,"page.js.map"),"{}");
102
105
  await fs.writeFile(path.join(dir,"chunk.js.map"),"{}");
103
106
  await fs.writeFile(path.join(dir,"page.js.nft.json"),JSON.stringify({version:1,files:["chunk.js","missing.js"]}));
104
107
  }}});
105
108
  await (config.compiler.runAfterProductionCompile as any)({projectDir:dir,distDir:dir});
106
109
  expect(called).toBe(true);
110
+ expect(JSON.parse(await fs.readFile(path.join(dir,"next-server.js.nft.json"),"utf8")).files).toEqual(["runtime.js","server/edge/middleware.js.map"]);
107
111
  expect(JSON.parse(await fs.readFile(path.join(dir,"page.js.nft.json"),"utf8")).files).toEqual(["chunk.js","missing.js","page.js.map","chunk.js.map"]);
108
112
  } finally {await fs.rm(dir,{recursive:true,force:true});}
109
113
  });
package/src/next.ts CHANGED
@@ -5,27 +5,38 @@ import path from "node:path";
5
5
  * versions that do not apply outputFileTracingIncludes still emit these traces
6
6
  * before runAfterProductionCompile. No source files or generated code change. */
7
7
  async function includeTracedMaps(distDir: string): Promise<void> {
8
+ const traces: string[] = [];
9
+ const serverMaps: string[] = [];
8
10
  async function walk(dir: string): Promise<void> {
9
11
  for (const entry of await fs.readdir(dir, { withFileTypes: true })) {
10
12
  const file = path.join(dir, entry.name);
11
13
  if (entry.isDirectory() && entry.name !== "cache" && entry.name !== "standalone") await walk(file);
12
- else if (entry.isFile() && entry.name.endsWith(".nft.json")) {
13
- const trace = JSON.parse(await fs.readFile(file, "utf8"));
14
- if (!Array.isArray(trace.files)) throw new Error(`Invalid Next trace: ${file}`);
15
- const scripts = [entry.name.slice(0, -".nft.json".length), ...trace.files];
16
- const maps: string[] = [];
17
- for (const script of scripts) {
18
- if (typeof script !== "string" || !script.endsWith(".js")) continue;
19
- const map = script + ".map";
20
- try { if ((await fs.stat(path.resolve(dir, map))).isFile()) maps.push(map); }
21
- catch (e) { if ((e as NodeJS.ErrnoException).code !== "ENOENT") throw e; }
22
- }
23
- trace.files = [...new Set([...trace.files, ...maps])];
24
- await fs.writeFile(file, JSON.stringify(trace));
14
+ else if (entry.isFile()) {
15
+ if (entry.name.endsWith(".nft.json")) traces.push(file);
16
+ if (entry.name.endsWith(".js.map") && file.startsWith(path.join(distDir, "server") + path.sep)) serverMaps.push(file);
25
17
  }
26
18
  }
27
19
  }
28
20
  await walk(distDir);
21
+ for (const file of traces) {
22
+ const dir = path.dirname(file);
23
+ const trace = JSON.parse(await fs.readFile(file, "utf8"));
24
+ if (!Array.isArray(trace.files)) throw new Error(`Invalid Next trace: ${file}`);
25
+ const scripts = [path.basename(file).slice(0, -".nft.json".length), ...trace.files];
26
+ // Edge bundles are copied through middleware-manifest, not NFT traces.
27
+ // The server trace is always copied into standalone output; retain
28
+ // their maps there without changing the middleware's executable files.
29
+ const maps = file === path.join(distDir, "next-server.js.nft.json")
30
+ ? serverMaps.map(map => path.relative(dir, map)) : [];
31
+ for (const script of scripts) {
32
+ if (typeof script !== "string" || !script.endsWith(".js")) continue;
33
+ const map = script + ".map";
34
+ try { if ((await fs.stat(path.resolve(dir, map))).isFile()) maps.push(map); }
35
+ catch (e) { if ((e as NodeJS.ErrnoException).code !== "ENOENT") throw e; }
36
+ }
37
+ trace.files = [...new Set([...trace.files, ...maps])];
38
+ await fs.writeFile(file, JSON.stringify(trace));
39
+ }
29
40
  }
30
41
 
31
42
  /** Build-time companion for coverage.next(). Import this lightweight module in