isolate-package 1.33.0 → 1.35.0

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.
Files changed (68) hide show
  1. package/dist/index.mjs +1 -1
  2. package/dist/index.mjs.map +1 -1
  3. package/dist/isolate-bin.mjs +5 -6
  4. package/dist/isolate-bin.mjs.map +1 -1
  5. package/dist/{isolate-DyRD5Zd_.mjs → isolate-ts-Igq7C.mjs} +888 -271
  6. package/dist/isolate-ts-Igq7C.mjs.map +1 -0
  7. package/package.json +23 -19
  8. package/src/get-internal-package-names.test.ts +1 -1
  9. package/src/get-internal-package-names.ts +2 -2
  10. package/src/isolate-bin.ts +5 -5
  11. package/src/isolate.ts +22 -17
  12. package/src/lib/config.test.ts +1 -1
  13. package/src/lib/config.ts +3 -3
  14. package/src/lib/lockfile/helpers/bun-lockfile.ts +153 -0
  15. package/src/lib/lockfile/helpers/generate-bun-lockfile.test.ts +3 -3
  16. package/src/lib/lockfile/helpers/generate-bun-lockfile.ts +14 -146
  17. package/src/lib/lockfile/helpers/generate-npm-lockfile.integration.test.ts +1 -5
  18. package/src/lib/lockfile/helpers/generate-npm-lockfile.test.ts +311 -16
  19. package/src/lib/lockfile/helpers/generate-npm-lockfile.ts +193 -22
  20. package/src/lib/lockfile/helpers/generate-pnpm-lockfile.test.ts +83 -2
  21. package/src/lib/lockfile/helpers/generate-pnpm-lockfile.ts +33 -6
  22. package/src/lib/lockfile/helpers/generate-yarn-lockfile.ts +5 -5
  23. package/src/lib/lockfile/process-lockfile.test.ts +2 -2
  24. package/src/lib/manifest/adapt-target-package-manifest.ts +22 -13
  25. package/src/lib/manifest/helpers/adapt-internal-package-manifests.test.ts +72 -3
  26. package/src/lib/manifest/helpers/adapt-internal-package-manifests.ts +22 -12
  27. package/src/lib/manifest/helpers/adapt-manifest-internal-deps.ts +1 -1
  28. package/src/lib/manifest/helpers/adopt-pnpm-fields-from-root.test.ts +4 -4
  29. package/src/lib/manifest/helpers/adopt-pnpm-fields-from-root.ts +7 -7
  30. package/src/lib/manifest/helpers/resolve-catalog-dependencies.test.ts +410 -0
  31. package/src/lib/manifest/helpers/resolve-catalog-dependencies.ts +115 -27
  32. package/src/lib/manifest/io.ts +6 -2
  33. package/src/lib/manifest/validate-manifest.ts +2 -2
  34. package/src/lib/output/get-build-output-dir.ts +1 -1
  35. package/src/lib/output/pack-dependencies.ts +1 -1
  36. package/src/lib/output/process-build-output-files.ts +6 -17
  37. package/src/lib/package-manager/helpers/infer-from-files.ts +5 -5
  38. package/src/lib/package-manager/helpers/infer-from-manifest.ts +7 -8
  39. package/src/lib/package-manager/index.ts +1 -1
  40. package/src/lib/package-manager/names.ts +8 -10
  41. package/src/lib/patches/collect-installed-names-bun.test.ts +154 -0
  42. package/src/lib/patches/collect-installed-names-bun.ts +87 -0
  43. package/src/lib/patches/collect-installed-names-pnpm.test.ts +316 -0
  44. package/src/lib/patches/collect-installed-names-pnpm.ts +365 -0
  45. package/src/lib/patches/copy-patches.test.ts +130 -13
  46. package/src/lib/patches/copy-patches.ts +47 -10
  47. package/src/lib/patches/write-isolate-pnpm-workspace.test.ts +83 -3
  48. package/src/lib/patches/write-isolate-pnpm-workspace.ts +4 -4
  49. package/src/lib/registry/collect-reachable-package-names.test.ts +1 -1
  50. package/src/lib/registry/create-packages-registry.ts +34 -31
  51. package/src/lib/registry/helpers/find-packages-globs.ts +23 -19
  52. package/src/lib/registry/list-internal-packages.test.ts +2 -2
  53. package/src/lib/types.ts +2 -2
  54. package/src/lib/utils/filter-patched-dependencies.test.ts +1 -1
  55. package/src/lib/utils/filter-patched-dependencies.ts +2 -2
  56. package/src/lib/utils/get-dirname.ts +1 -1
  57. package/src/lib/utils/index.ts +1 -1
  58. package/src/lib/utils/json.ts +12 -14
  59. package/src/lib/utils/pack.ts +32 -22
  60. package/src/lib/utils/reset-isolate-dir.test.ts +165 -0
  61. package/src/lib/utils/reset-isolate-dir.ts +147 -0
  62. package/src/lib/utils/unpack.test.ts +76 -0
  63. package/src/lib/utils/unpack.ts +16 -10
  64. package/src/lib/utils/wait-for-complete-file.test.ts +105 -0
  65. package/src/lib/utils/wait-for-complete-file.ts +44 -0
  66. package/src/lib/utils/yaml.ts +8 -9
  67. package/src/testing/setup.ts +1 -1
  68. package/dist/isolate-DyRD5Zd_.mjs.map +0 -1
@@ -23,9 +23,9 @@ export async function getInternalPackageNames(
23
23
 
24
24
  detectPackageManager(workspaceRootDir);
25
25
 
26
- const targetPackageManifest = await readTypedJson<PackageManifest>(
26
+ const targetPackageManifest = (await readTypedJson(
27
27
  path.join(targetPackageDir, "package.json"),
28
- );
28
+ )) as PackageManifest;
29
29
 
30
30
  const packagesRegistry = await createPackagesRegistry(
31
31
  workspaceRootDir,
@@ -97,11 +97,11 @@ async function run() {
97
97
  await isolate(mergedConfig);
98
98
  }
99
99
 
100
- run().catch((err) => {
101
- if (err instanceof Error) {
102
- console.error(err.stack);
103
- process.exit(1);
100
+ run().catch((error) => {
101
+ if (error instanceof Error) {
102
+ console.error(error.stack);
104
103
  } else {
105
- console.error(err);
104
+ console.error(error);
106
105
  }
106
+ process.exit(1);
107
107
  });
package/src/isolate.ts CHANGED
@@ -31,29 +31,30 @@ import {
31
31
  getRootRelativeLogPath,
32
32
  isRushWorkspace,
33
33
  readTypedJson,
34
+ resetIsolateDir,
34
35
  writeTypedYamlSync,
35
36
  } from "./lib/utils";
36
37
 
37
38
  const __dirname = getDirname(import.meta.url);
38
39
 
39
- export function createIsolator(config?: IsolateConfig) {
40
- const resolvedConfig = resolveConfig(config);
40
+ export function createIsolator(initialConfig?: IsolateConfig) {
41
+ const resolvedConfig = resolveConfig(initialConfig);
41
42
 
42
- return async function isolate(): Promise<string> {
43
+ return async function runIsolate(): Promise<string> {
43
44
  const config = resolvedConfig;
44
45
  setLogLevel(config.logLevel);
45
46
  const log = useLogger();
46
47
 
47
- const { version: libraryVersion } = await readTypedJson<PackageManifest>(
48
+ const { version: libraryVersion } = (await readTypedJson(
48
49
  path.join(path.join(__dirname, "..", "package.json")),
49
- );
50
+ )) as PackageManifest;
50
51
 
51
52
  log.debug("Using isolate-package version", libraryVersion);
52
53
 
53
54
  const { targetPackageDir, workspaceRootDir } =
54
55
  resolveWorkspacePaths(config);
55
56
 
56
- const buildOutputDir = await getBuildOutputDir({
57
+ const buildOutputDir = getBuildOutputDir({
57
58
  targetPackageDir,
58
59
  buildDirName: config.buildDirName,
59
60
  tsconfigPath: config.tsconfigPath,
@@ -77,19 +78,23 @@ export function createIsolator(config?: IsolateConfig) {
77
78
  getRootRelativeLogPath(isolateDir, workspaceRootDir),
78
79
  );
79
80
 
80
- if (fs.existsSync(isolateDir)) {
81
- await fs.remove(isolateDir);
82
- log.debug("Cleaned the existing isolate output directory");
83
- }
84
-
85
- await fs.ensureDir(isolateDir);
81
+ /**
82
+ * Place the trash sibling outside `targetPackageDir`, since that directory
83
+ * is later packed by `processBuildOutputFiles`. Keeping the trash next to
84
+ * the target package (still on the same filesystem) preserves the atomic
85
+ * rename without risking that the trash gets picked up by `npm pack` or
86
+ * races with that step.
87
+ */
88
+ await resetIsolateDir(isolateDir, {
89
+ trashParentDir: path.dirname(targetPackageDir),
90
+ });
86
91
 
87
92
  const tmpDir = path.join(isolateDir, "__tmp");
88
93
  await fs.ensureDir(tmpDir);
89
94
 
90
- const targetPackageManifest = await readTypedJson<PackageManifest>(
95
+ const targetPackageManifest = (await readTypedJson(
91
96
  path.join(targetPackageDir, "package.json"),
92
- );
97
+ )) as PackageManifest;
93
98
 
94
99
  /** Validate mandatory fields for the target package */
95
100
  validateManifestMandatoryFields(
@@ -233,8 +238,10 @@ export function createIsolator(config?: IsolateConfig) {
233
238
  const copiedPatches = shouldCopyPatches
234
239
  ? await copyPatches({
235
240
  workspaceRootDir,
241
+ targetPackageDir,
236
242
  targetPackageManifest: outputManifest,
237
243
  packagesRegistry,
244
+ internalDepPackageNames: internalPackageNames,
238
245
  isolateDir,
239
246
  includeDevDependencies: config.includeDevDependencies,
240
247
  })
@@ -276,9 +283,7 @@ export function createIsolator(config?: IsolateConfig) {
276
283
  if (packageManager.name === "bun") {
277
284
  manifest.patchedDependencies = patchEntries;
278
285
  } else {
279
- if (!manifest.pnpm) {
280
- manifest.pnpm = {};
281
- }
286
+ manifest.pnpm ??= {};
282
287
  manifest.pnpm.patchedDependencies = patchEntries;
283
288
  }
284
289
 
@@ -12,7 +12,7 @@ const mockLogger = {
12
12
  error: vi.fn(),
13
13
  };
14
14
 
15
- vi.mock("~/lib/logger", () => ({
15
+ vi.mock("#/lib/logger", () => ({
16
16
  useLogger: () => mockLogger,
17
17
  }));
18
18
 
package/src/lib/config.ts CHANGED
@@ -93,7 +93,7 @@ function loadModuleConfig(filePath: string): IsolateConfig {
93
93
  throw new Error("Failed to extract config JSON from subprocess output");
94
94
  }
95
95
 
96
- const parsed = JSON.parse(jsonMatch);
96
+ const parsed = JSON.parse(jsonMatch) as unknown;
97
97
 
98
98
  if (
99
99
  typeof parsed !== "object" ||
@@ -105,7 +105,7 @@ function loadModuleConfig(filePath: string): IsolateConfig {
105
105
  );
106
106
  }
107
107
 
108
- return parsed;
108
+ return parsed as IsolateConfig;
109
109
  } catch (error) {
110
110
  const stderr =
111
111
  error instanceof Error && "stderr" in error
@@ -151,7 +151,7 @@ export function loadConfigFromFile(): IsolateConfig {
151
151
  }
152
152
 
153
153
  if (jsonExists) {
154
- return readTypedJsonSync<IsolateConfig>(jsonConfigPath);
154
+ return readTypedJsonSync(jsonConfigPath) as IsolateConfig;
155
155
  }
156
156
 
157
157
  return {};
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Shared types and walker logic for the Bun workspace lockfile (`bun.lock`).
3
+ *
4
+ * Used both when generating the isolated lockfile and when computing the set
5
+ * of package names that will end up installed in the isolate (so that patches
6
+ * for deep transitive deps are preserved).
7
+ */
8
+
9
+ export type BunWorkspaceEntry = {
10
+ name?: string;
11
+ version?: string;
12
+ dependencies?: Record<string, string>;
13
+ devDependencies?: Record<string, string>;
14
+ optionalDependencies?: Record<string, string>;
15
+ peerDependencies?: Record<string, string>;
16
+ optionalPeers?: string[];
17
+ };
18
+
19
+ export type BunLockfile = {
20
+ lockfileVersion: number;
21
+ workspaces: Record<string, BunWorkspaceEntry>;
22
+ packages: Record<string, unknown[]>;
23
+ trustedDependencies?: string[];
24
+ patchedDependencies?: Record<string, string>;
25
+ overrides?: Record<string, string>;
26
+ };
27
+
28
+ /** Extract dependency names from a workspace entry. */
29
+ export function collectDependencyNames(
30
+ entry: BunWorkspaceEntry,
31
+ includeDevDependencies: boolean,
32
+ ): string[] {
33
+ const names = new Set<string>();
34
+
35
+ for (const name of Object.keys(entry.dependencies ?? {})) {
36
+ names.add(name);
37
+ }
38
+ for (const name of Object.keys(entry.optionalDependencies ?? {})) {
39
+ names.add(name);
40
+ }
41
+ for (const name of Object.keys(entry.peerDependencies ?? {})) {
42
+ names.add(name);
43
+ }
44
+
45
+ if (includeDevDependencies) {
46
+ for (const name of Object.keys(entry.devDependencies ?? {})) {
47
+ names.add(name);
48
+ }
49
+ }
50
+
51
+ return [...names];
52
+ }
53
+
54
+ /**
55
+ * Check whether a package entry represents a workspace package by examining
56
+ * its identifier string (first element in the entry array).
57
+ */
58
+ export function isWorkspacePackageEntry(entry: unknown[]): boolean {
59
+ const ident = entry[0];
60
+ return typeof ident === "string" && ident.includes("@workspace:");
61
+ }
62
+
63
+ /**
64
+ * Extract the info object from a packages entry. The position varies by type:
65
+ * - npm packages: [ident, registry, info, checksum] -> index 2
66
+ * - workspace packages: [ident, info] -> index 1
67
+ * - git/github packages: [ident, info, checksum] -> index 1
68
+ *
69
+ * Detection: if the second element is a string (registry URL or checksum),
70
+ * the info object is deeper. Workspace entries have only 2 elements.
71
+ */
72
+ export function getPackageInfoObject(
73
+ entry: unknown[],
74
+ ): Record<string, unknown> | undefined {
75
+ if (entry.length <= 1) return undefined;
76
+
77
+ /** Workspace entries: [ident, info] */
78
+ if (isWorkspacePackageEntry(entry)) {
79
+ return typeof entry[1] === "object"
80
+ ? (entry[1] as Record<string, unknown>)
81
+ : undefined;
82
+ }
83
+
84
+ /**
85
+ * npm entries with registry URL: [ident, registryUrl, info, checksum]. The
86
+ * second element is a string (the registry URL).
87
+ */
88
+ if (typeof entry[1] === "string") {
89
+ return typeof entry[2] === "object"
90
+ ? (entry[2] as Record<string, unknown>)
91
+ : undefined;
92
+ }
93
+
94
+ /** git/tarball entries: [ident, info, checksum] */
95
+ return typeof entry[1] === "object"
96
+ ? (entry[1] as Record<string, unknown>)
97
+ : undefined;
98
+ }
99
+
100
+ /**
101
+ * Recursively collect all package keys that are required, starting from a set
102
+ * of direct dependency names and walking through their transitive
103
+ * dependencies in the packages section.
104
+ */
105
+ export function collectRequiredPackages(
106
+ directDependencyNames: Set<string>,
107
+ packages: Record<string, unknown[]>,
108
+ ): Set<string> {
109
+ const required = new Set<string>();
110
+ const queue = [...directDependencyNames];
111
+
112
+ let name: string | undefined;
113
+ while ((name = queue.pop()) !== undefined) {
114
+ if (required.has(name)) continue;
115
+
116
+ const entry = packages[name];
117
+ if (!entry) continue;
118
+
119
+ required.add(name);
120
+
121
+ const info = getPackageInfoObject(entry);
122
+ if (!info) continue;
123
+
124
+ /** Walk transitive dependencies from the info object */
125
+ for (const depField of [
126
+ "dependencies",
127
+ "optionalDependencies",
128
+ "peerDependencies",
129
+ ]) {
130
+ enqueueDeps(info[depField], required, queue);
131
+ }
132
+ }
133
+
134
+ return required;
135
+ }
136
+
137
+ /**
138
+ * Push any names from a dependency map onto the BFS queue, skipping anything
139
+ * already marked required so we don't revisit it. `deps` is typed as `unknown`
140
+ * because it comes from a freshly-parsed lockfile entry with no schema.
141
+ */
142
+ function enqueueDeps(
143
+ deps: unknown,
144
+ required: Set<string>,
145
+ queue: string[],
146
+ ): void {
147
+ if (!deps || typeof deps !== "object") return;
148
+ for (const depName of Object.keys(deps as Record<string, unknown>)) {
149
+ if (!required.has(depName)) {
150
+ queue.push(depName);
151
+ }
152
+ }
153
+ }
@@ -13,8 +13,8 @@ vi.mock("fs-extra", () => ({
13
13
  }));
14
14
 
15
15
  /** Mock the utils */
16
- vi.mock("~/lib/utils", async (importOriginal) => {
17
- const actual = await importOriginal<typeof import("~/lib/utils")>();
16
+ vi.mock("#/lib/utils", async (importOriginal) => {
17
+ const actual = await importOriginal<typeof import("#/lib/utils")>();
18
18
  return {
19
19
  getErrorMessage: vi.fn((err: Error) => err.message),
20
20
  getPackageName: actual.getPackageName,
@@ -23,7 +23,7 @@ vi.mock("~/lib/utils", async (importOriginal) => {
23
23
  });
24
24
 
25
25
  const fs = vi.mocked((await import("fs-extra")).default);
26
- const { readTypedJsonSync } = vi.mocked(await import("~/lib/utils"));
26
+ const { readTypedJsonSync } = vi.mocked(await import("#/lib/utils"));
27
27
 
28
28
  /** Reusable packages registry fixture */
29
29
  function createPackagesRegistry() {
@@ -1,32 +1,20 @@
1
1
  import fs from "fs-extra";
2
2
  import { got } from "get-or-throw";
3
3
  import path from "node:path";
4
- import { useLogger } from "~/lib/logger";
5
- import type { PackagesRegistry } from "~/lib/types";
4
+ import { useLogger } from "#/lib/logger";
5
+ import type { PackagesRegistry } from "#/lib/types";
6
6
  import {
7
7
  getErrorMessage,
8
8
  getPackageName,
9
9
  readTypedJsonSync,
10
- } from "~/lib/utils";
11
-
12
- type BunWorkspaceEntry = {
13
- name?: string;
14
- version?: string;
15
- dependencies?: Record<string, string>;
16
- devDependencies?: Record<string, string>;
17
- optionalDependencies?: Record<string, string>;
18
- peerDependencies?: Record<string, string>;
19
- optionalPeers?: string[];
20
- };
21
-
22
- type BunLockfile = {
23
- lockfileVersion: number;
24
- workspaces: Record<string, BunWorkspaceEntry>;
25
- packages: Record<string, unknown[]>;
26
- trustedDependencies?: string[];
27
- patchedDependencies?: Record<string, string>;
28
- overrides?: Record<string, string>;
29
- };
10
+ } from "#/lib/utils";
11
+ import {
12
+ type BunLockfile,
13
+ type BunWorkspaceEntry,
14
+ collectDependencyNames,
15
+ collectRequiredPackages,
16
+ isWorkspacePackageEntry,
17
+ } from "./bun-lockfile";
30
18
 
31
19
  /**
32
20
  * Serialize a value to JSON with trailing commas after every array element and
@@ -54,126 +42,6 @@ export function serializeWithTrailingCommas(
54
42
  return result;
55
43
  }
56
44
 
57
- /**
58
- * Extract dependency names from a workspace entry, optionally including
59
- * devDependencies.
60
- */
61
- function collectDependencyNames(
62
- entry: BunWorkspaceEntry,
63
- includeDevDependencies: boolean,
64
- ): string[] {
65
- const names = new Set<string>();
66
-
67
- for (const name of Object.keys(entry.dependencies ?? {})) {
68
- names.add(name);
69
- }
70
- for (const name of Object.keys(entry.optionalDependencies ?? {})) {
71
- names.add(name);
72
- }
73
- for (const name of Object.keys(entry.peerDependencies ?? {})) {
74
- names.add(name);
75
- }
76
-
77
- if (includeDevDependencies) {
78
- for (const name of Object.keys(entry.devDependencies ?? {})) {
79
- names.add(name);
80
- }
81
- }
82
-
83
- return [...names];
84
- }
85
-
86
- /**
87
- * Check whether a package entry represents a workspace package by examining its
88
- * identifier string (first element in the entry array).
89
- */
90
- function isWorkspacePackageEntry(entry: unknown[]): boolean {
91
- const ident = entry[0];
92
- return typeof ident === "string" && ident.includes("@workspace:");
93
- }
94
-
95
- /**
96
- * Extract the info object from a packages entry. The position varies by type:
97
- * - npm packages: [ident, registry, info, checksum] -> index 2
98
- * - workspace packages: [ident, info] -> index 1
99
- * - git/github packages: [ident, info, checksum] -> index 1
100
- *
101
- * Detection: if the second element is a string (registry URL or checksum), the
102
- * info object is deeper. Workspace entries have only 2 elements.
103
- */
104
- function getPackageInfoObject(
105
- entry: unknown[],
106
- ): Record<string, unknown> | undefined {
107
- if (entry.length <= 1) return undefined;
108
-
109
- /** Workspace entries: [ident, info] */
110
- if (isWorkspacePackageEntry(entry)) {
111
- return typeof entry[1] === "object"
112
- ? (entry[1] as Record<string, unknown>)
113
- : undefined;
114
- }
115
-
116
- /**
117
- * npm entries with registry URL: [ident, registryUrl, info, checksum].
118
- * The second element is a string (the registry URL).
119
- */
120
- if (typeof entry[1] === "string") {
121
- return typeof entry[2] === "object"
122
- ? (entry[2] as Record<string, unknown>)
123
- : undefined;
124
- }
125
-
126
- /** git/tarball entries: [ident, info, checksum] */
127
- return typeof entry[1] === "object"
128
- ? (entry[1] as Record<string, unknown>)
129
- : undefined;
130
- }
131
-
132
- /**
133
- * Recursively collect all package keys that are required, starting from a set
134
- * of direct dependency names and walking through their transitive dependencies
135
- * in the packages section.
136
- */
137
- function collectRequiredPackages(
138
- directDependencyNames: Set<string>,
139
- packages: Record<string, unknown[]>,
140
- ): Set<string> {
141
- const required = new Set<string>();
142
- const queue = [...directDependencyNames];
143
-
144
- while (queue.length > 0) {
145
- const name = queue.pop()!;
146
-
147
- if (required.has(name)) continue;
148
-
149
- const entry = packages[name];
150
- if (!entry) continue;
151
-
152
- required.add(name);
153
-
154
- const info = getPackageInfoObject(entry);
155
- if (!info) continue;
156
-
157
- /** Walk transitive dependencies from the info object */
158
- for (const depField of [
159
- "dependencies",
160
- "optionalDependencies",
161
- "peerDependencies",
162
- ]) {
163
- const deps = info[depField];
164
- if (deps && typeof deps === "object") {
165
- for (const depName of Object.keys(deps as Record<string, unknown>)) {
166
- if (!required.has(depName)) {
167
- queue.push(depName);
168
- }
169
- }
170
- }
171
- }
172
- }
173
-
174
- return required;
175
- }
176
-
177
45
  export async function generateBunLockfile({
178
46
  workspaceRootDir,
179
47
  targetPackageDir,
@@ -200,7 +68,7 @@ export async function generateBunLockfile({
200
68
  throw new Error(`Failed to find bun.lock at ${lockfilePath}`);
201
69
  }
202
70
 
203
- const lockfile = readTypedJsonSync<BunLockfile>(lockfilePath);
71
+ const lockfile = readTypedJsonSync(lockfilePath) as BunLockfile;
204
72
 
205
73
  /** Compute workspace keys for the target and internal deps */
206
74
  const targetWorkspaceKey = path
@@ -347,8 +215,8 @@ export async function generateBunLockfile({
347
215
  );
348
216
 
349
217
  log.debug("Created lockfile at", outputPath);
350
- } catch (err) {
351
- log.error(`Failed to generate lockfile: ${getErrorMessage(err)}`);
352
- throw err;
218
+ } catch (error) {
219
+ log.error(`Failed to generate lockfile: ${getErrorMessage(error)}`);
220
+ throw error;
353
221
  }
354
222
  }
@@ -1,14 +1,10 @@
1
1
  import fs from "fs-extra";
2
2
  import os from "node:os";
3
3
  import path from "node:path";
4
- import { fileURLToPath } from "node:url";
5
4
  import { afterEach, beforeEach, describe, expect, it } from "vitest";
6
5
  import { generateNpmLockfile } from "./generate-npm-lockfile";
7
6
 
8
- const __filename = fileURLToPath(import.meta.url);
9
- const __dirname = path.dirname(__filename);
10
-
11
- const FIXTURES_DIR = path.join(__dirname, "__fixtures__");
7
+ const FIXTURES_DIR = path.join(import.meta.dirname, "__fixtures__");
12
8
 
13
9
  /**
14
10
  * Copy a fixture's `workspace/` tree into a fresh tmp directory so that the