isolate-package 1.31.0 → 1.32.1
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/index.mjs +1 -1
- package/dist/{isolate-DtNAHzfa.mjs → isolate-DyRD5Zd_.mjs} +442 -124
- package/dist/isolate-DyRD5Zd_.mjs.map +1 -0
- package/dist/isolate-bin.mjs +1 -1
- package/package.json +1 -1
- package/src/isolate.ts +7 -4
- package/src/lib/lockfile/helpers/__fixtures__/internal-deps/workspace/package-lock.json +82 -0
- package/src/lib/lockfile/helpers/__fixtures__/internal-deps/workspace/package.json +8 -0
- package/src/lib/lockfile/helpers/__fixtures__/internal-deps/workspace/packages/api/package.json +12 -0
- package/src/lib/lockfile/helpers/__fixtures__/internal-deps/workspace/packages/shared/package.json +12 -0
- package/src/lib/lockfile/helpers/__fixtures__/internal-deps/workspace/packages/utils/package.json +11 -0
- package/src/lib/lockfile/helpers/__fixtures__/nested-version-override/workspace/package-lock.json +56 -0
- package/src/lib/lockfile/helpers/__fixtures__/nested-version-override/workspace/package.json +8 -0
- package/src/lib/lockfile/helpers/__fixtures__/nested-version-override/workspace/packages/api/package.json +11 -0
- package/src/lib/lockfile/helpers/__fixtures__/nested-version-override/workspace/packages/other/package.json +11 -0
- package/src/lib/lockfile/helpers/generate-npm-lockfile.integration.test.ts +243 -0
- package/src/lib/lockfile/helpers/generate-npm-lockfile.test.ts +604 -0
- package/src/lib/lockfile/helpers/generate-npm-lockfile.ts +417 -21
- package/src/lib/lockfile/process-lockfile.test.ts +4 -0
- package/src/lib/lockfile/process-lockfile.ts +14 -16
- package/src/lib/patches/copy-patches.test.ts +78 -0
- package/src/lib/patches/copy-patches.ts +22 -1
- package/src/lib/patches/write-isolate-pnpm-workspace.test.ts +189 -0
- package/src/lib/patches/write-isolate-pnpm-workspace.ts +80 -0
- package/src/lib/registry/collect-reachable-package-names.test.ts +239 -0
- package/src/lib/registry/collect-reachable-package-names.ts +60 -0
- package/src/lib/registry/index.ts +1 -0
- package/src/lib/utils/filter-patched-dependencies.test.ts +77 -0
- package/src/lib/utils/filter-patched-dependencies.ts +41 -17
- package/dist/isolate-DtNAHzfa.mjs.map +0 -1
|
@@ -67,6 +67,7 @@ describe("copyPatches", () => {
|
|
|
67
67
|
workspaceRootDir: "/workspace",
|
|
68
68
|
targetPackageManifest: { name: "test", version: "1.0.0" },
|
|
69
69
|
isolateDir: "/workspace/isolate",
|
|
70
|
+
packagesRegistry: {},
|
|
70
71
|
includeDevDependencies: false,
|
|
71
72
|
});
|
|
72
73
|
|
|
@@ -127,6 +128,7 @@ describe("copyPatches", () => {
|
|
|
127
128
|
workspaceRootDir: "/workspace",
|
|
128
129
|
targetPackageManifest: { name: "test", version: "1.0.0" },
|
|
129
130
|
isolateDir: "/workspace/isolate",
|
|
131
|
+
packagesRegistry: {},
|
|
130
132
|
includeDevDependencies: false,
|
|
131
133
|
});
|
|
132
134
|
|
|
@@ -146,6 +148,7 @@ describe("copyPatches", () => {
|
|
|
146
148
|
workspaceRootDir: "/workspace",
|
|
147
149
|
targetPackageManifest: { name: "test", version: "1.0.0" },
|
|
148
150
|
isolateDir: "/workspace/isolate",
|
|
151
|
+
packagesRegistry: {},
|
|
149
152
|
includeDevDependencies: false,
|
|
150
153
|
});
|
|
151
154
|
|
|
@@ -175,6 +178,7 @@ describe("copyPatches", () => {
|
|
|
175
178
|
workspaceRootDir: "/workspace",
|
|
176
179
|
targetPackageManifest: targetManifest,
|
|
177
180
|
isolateDir: "/workspace/isolate",
|
|
181
|
+
packagesRegistry: {},
|
|
178
182
|
includeDevDependencies: false,
|
|
179
183
|
});
|
|
180
184
|
|
|
@@ -212,6 +216,7 @@ describe("copyPatches", () => {
|
|
|
212
216
|
workspaceRootDir: "/workspace",
|
|
213
217
|
targetPackageManifest: targetManifest,
|
|
214
218
|
isolateDir: "/workspace/isolate",
|
|
219
|
+
packagesRegistry: {},
|
|
215
220
|
includeDevDependencies: true,
|
|
216
221
|
});
|
|
217
222
|
|
|
@@ -222,6 +227,7 @@ describe("copyPatches", () => {
|
|
|
222
227
|
patchedDependencies: { "vitest@1.0.0": "patches/vitest.patch" },
|
|
223
228
|
targetPackageManifest: targetManifest,
|
|
224
229
|
includeDevDependencies: true,
|
|
230
|
+
reachableDependencyNames: expect.any(Set),
|
|
225
231
|
});
|
|
226
232
|
expect(fs.copy).toHaveBeenCalledWith(
|
|
227
233
|
"/workspace/patches/vitest.patch",
|
|
@@ -252,6 +258,7 @@ describe("copyPatches", () => {
|
|
|
252
258
|
workspaceRootDir: "/workspace",
|
|
253
259
|
targetPackageManifest: targetManifest,
|
|
254
260
|
isolateDir: "/workspace/isolate",
|
|
261
|
+
packagesRegistry: {},
|
|
255
262
|
includeDevDependencies: false,
|
|
256
263
|
});
|
|
257
264
|
|
|
@@ -282,6 +289,7 @@ describe("copyPatches", () => {
|
|
|
282
289
|
workspaceRootDir: "/workspace",
|
|
283
290
|
targetPackageManifest: targetManifest,
|
|
284
291
|
isolateDir: "/workspace/isolate",
|
|
292
|
+
packagesRegistry: {},
|
|
285
293
|
includeDevDependencies: false,
|
|
286
294
|
});
|
|
287
295
|
|
|
@@ -315,6 +323,7 @@ describe("copyPatches", () => {
|
|
|
315
323
|
workspaceRootDir: "/workspace",
|
|
316
324
|
targetPackageManifest: targetManifest,
|
|
317
325
|
isolateDir: "/workspace/isolate",
|
|
326
|
+
packagesRegistry: {},
|
|
318
327
|
includeDevDependencies: false,
|
|
319
328
|
});
|
|
320
329
|
|
|
@@ -357,6 +366,7 @@ describe("copyPatches", () => {
|
|
|
357
366
|
workspaceRootDir: "/workspace",
|
|
358
367
|
targetPackageManifest: targetManifest,
|
|
359
368
|
isolateDir: "/workspace/isolate",
|
|
369
|
+
packagesRegistry: {},
|
|
360
370
|
includeDevDependencies: false,
|
|
361
371
|
});
|
|
362
372
|
|
|
@@ -401,6 +411,7 @@ describe("copyPatches", () => {
|
|
|
401
411
|
workspaceRootDir: "/workspace",
|
|
402
412
|
targetPackageManifest: targetManifest,
|
|
403
413
|
isolateDir: "/workspace/isolate",
|
|
414
|
+
packagesRegistry: {},
|
|
404
415
|
includeDevDependencies: false,
|
|
405
416
|
});
|
|
406
417
|
|
|
@@ -447,6 +458,7 @@ describe("copyPatches", () => {
|
|
|
447
458
|
workspaceRootDir: "/workspace",
|
|
448
459
|
targetPackageManifest: targetManifest,
|
|
449
460
|
isolateDir: "/workspace/isolate",
|
|
461
|
+
packagesRegistry: {},
|
|
450
462
|
includeDevDependencies: false,
|
|
451
463
|
});
|
|
452
464
|
|
|
@@ -458,4 +470,70 @@ describe("copyPatches", () => {
|
|
|
458
470
|
"/workspace/isolate/patches/lodash.patch",
|
|
459
471
|
);
|
|
460
472
|
});
|
|
473
|
+
|
|
474
|
+
it("should pass reachable transitive dep names from internal packages to the filter (regression: issue #167)", async () => {
|
|
475
|
+
/**
|
|
476
|
+
* Target `consumer` depends on internal `firebase-package`, which in turn
|
|
477
|
+
* depends on `tslib`. A patch for `tslib@2.0.0` declared at the workspace
|
|
478
|
+
* root must reach the filter with `tslib` in `reachableDependencyNames`
|
|
479
|
+
* so it can be preserved even though `consumer` doesn't list it directly.
|
|
480
|
+
*/
|
|
481
|
+
const consumerManifest: PackageManifest = {
|
|
482
|
+
name: "consumer",
|
|
483
|
+
version: "1.0.0",
|
|
484
|
+
dependencies: { "firebase-package": "file:./packages/firebase-package" },
|
|
485
|
+
};
|
|
486
|
+
|
|
487
|
+
readTypedYamlSync.mockReturnValue({
|
|
488
|
+
patchedDependencies: {
|
|
489
|
+
"tslib@2.0.0": "patches/tslib@2.0.0.patch",
|
|
490
|
+
},
|
|
491
|
+
});
|
|
492
|
+
readTypedJson.mockResolvedValue({
|
|
493
|
+
name: "root",
|
|
494
|
+
version: "1.0.0",
|
|
495
|
+
} as PackageManifest);
|
|
496
|
+
|
|
497
|
+
filterPatchedDependencies.mockReturnValue({
|
|
498
|
+
"tslib@2.0.0": "patches/tslib@2.0.0.patch",
|
|
499
|
+
});
|
|
500
|
+
|
|
501
|
+
fs.existsSync.mockReturnValue(true);
|
|
502
|
+
|
|
503
|
+
usePackageManager.mockReturnValue({
|
|
504
|
+
name: "pnpm",
|
|
505
|
+
majorVersion: 9,
|
|
506
|
+
version: "9.0.0",
|
|
507
|
+
packageManagerString: "pnpm@9.0.0",
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
const result = await copyPatches({
|
|
511
|
+
workspaceRootDir: "/workspace",
|
|
512
|
+
targetPackageManifest: consumerManifest,
|
|
513
|
+
isolateDir: "/workspace/isolate",
|
|
514
|
+
packagesRegistry: {
|
|
515
|
+
"firebase-package": {
|
|
516
|
+
absoluteDir: "/workspace/packages/firebase-package",
|
|
517
|
+
rootRelativeDir: "packages/firebase-package",
|
|
518
|
+
manifest: {
|
|
519
|
+
name: "firebase-package",
|
|
520
|
+
version: "1.0.0",
|
|
521
|
+
dependencies: { tslib: "^2.0.0" },
|
|
522
|
+
},
|
|
523
|
+
},
|
|
524
|
+
},
|
|
525
|
+
includeDevDependencies: false,
|
|
526
|
+
});
|
|
527
|
+
|
|
528
|
+
expect(result).toEqual({
|
|
529
|
+
"tslib@2.0.0": { path: "patches/tslib@2.0.0.patch", hash: "" },
|
|
530
|
+
});
|
|
531
|
+
|
|
532
|
+
const filterCall = filterPatchedDependencies.mock.calls[0]?.[0];
|
|
533
|
+
expect(filterCall).toBeDefined();
|
|
534
|
+
const reachable = filterCall!.reachableDependencyNames;
|
|
535
|
+
expect(reachable).toBeInstanceOf(Set);
|
|
536
|
+
expect(reachable!.has("firebase-package")).toBe(true);
|
|
537
|
+
expect(reachable!.has("tslib")).toBe(true);
|
|
538
|
+
});
|
|
461
539
|
});
|
|
@@ -4,7 +4,13 @@ import { readWantedLockfile as readWantedLockfile_v8 } from "pnpm_lockfile_file_
|
|
|
4
4
|
import { readWantedLockfile as readWantedLockfile_v9 } from "pnpm_lockfile_file_v9";
|
|
5
5
|
import { useLogger } from "~/lib/logger";
|
|
6
6
|
import { usePackageManager } from "~/lib/package-manager";
|
|
7
|
-
import
|
|
7
|
+
import { collectReachablePackageNames } from "~/lib/registry";
|
|
8
|
+
import type {
|
|
9
|
+
PackageManifest,
|
|
10
|
+
PackagesRegistry,
|
|
11
|
+
PatchFile,
|
|
12
|
+
PnpmSettings,
|
|
13
|
+
} from "~/lib/types";
|
|
8
14
|
import {
|
|
9
15
|
filterPatchedDependencies,
|
|
10
16
|
getRootRelativeLogPath,
|
|
@@ -16,11 +22,13 @@ import {
|
|
|
16
22
|
export async function copyPatches({
|
|
17
23
|
workspaceRootDir,
|
|
18
24
|
targetPackageManifest,
|
|
25
|
+
packagesRegistry,
|
|
19
26
|
isolateDir,
|
|
20
27
|
includeDevDependencies,
|
|
21
28
|
}: {
|
|
22
29
|
workspaceRootDir: string;
|
|
23
30
|
targetPackageManifest: PackageManifest;
|
|
31
|
+
packagesRegistry: PackagesRegistry;
|
|
24
32
|
isolateDir: string;
|
|
25
33
|
includeDevDependencies: boolean;
|
|
26
34
|
}): Promise<Record<string, PatchFile>> {
|
|
@@ -82,10 +90,23 @@ export async function copyPatches({
|
|
|
82
90
|
`Found ${Object.keys(patchedDependencies).length} patched dependencies in workspace`,
|
|
83
91
|
);
|
|
84
92
|
|
|
93
|
+
/**
|
|
94
|
+
* Collect the set of dependency names reachable from the target (direct deps
|
|
95
|
+
* plus deps introduced by internal workspace packages). Patches for names in
|
|
96
|
+
* this set are preserved even when the target doesn't list them directly —
|
|
97
|
+
* see issue #167.
|
|
98
|
+
*/
|
|
99
|
+
const reachableDependencyNames = collectReachablePackageNames({
|
|
100
|
+
targetPackageManifest,
|
|
101
|
+
packagesRegistry,
|
|
102
|
+
includeDevDependencies,
|
|
103
|
+
});
|
|
104
|
+
|
|
85
105
|
const filteredPatches = filterPatchedDependencies({
|
|
86
106
|
patchedDependencies,
|
|
87
107
|
targetPackageManifest,
|
|
88
108
|
includeDevDependencies,
|
|
109
|
+
reachableDependencyNames,
|
|
89
110
|
});
|
|
90
111
|
|
|
91
112
|
if (!filteredPatches) {
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import type { PatchFile } from "~/lib/types";
|
|
3
|
+
import { writeIsolatePnpmWorkspace } from "./write-isolate-pnpm-workspace";
|
|
4
|
+
|
|
5
|
+
vi.mock("fs-extra", () => ({
|
|
6
|
+
default: {
|
|
7
|
+
copyFileSync: vi.fn(),
|
|
8
|
+
},
|
|
9
|
+
}));
|
|
10
|
+
|
|
11
|
+
vi.mock("~/lib/utils", () => ({
|
|
12
|
+
readTypedYamlSync: vi.fn(),
|
|
13
|
+
writeTypedYamlSync: vi.fn(),
|
|
14
|
+
}));
|
|
15
|
+
|
|
16
|
+
const fs = vi.mocked((await import("fs-extra")).default);
|
|
17
|
+
const { readTypedYamlSync, writeTypedYamlSync } = vi.mocked(
|
|
18
|
+
await import("~/lib/utils"),
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
const workspaceRootDir = "/workspace";
|
|
22
|
+
const isolateDir = "/workspace/isolate";
|
|
23
|
+
|
|
24
|
+
describe("writeIsolatePnpmWorkspace", () => {
|
|
25
|
+
beforeEach(() => {
|
|
26
|
+
vi.clearAllMocks();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
afterEach(() => {
|
|
30
|
+
vi.restoreAllMocks();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("retains only the patches that were copied", () => {
|
|
34
|
+
readTypedYamlSync.mockReturnValue({
|
|
35
|
+
packages: ["packages/*"],
|
|
36
|
+
patchedDependencies: {
|
|
37
|
+
"lodash@4.17.21": "patches/lodash@4.17.21.patch",
|
|
38
|
+
"react@18.2.0": "patches/react@18.2.0.patch",
|
|
39
|
+
"axios@1.6.0": "patches/axios@1.6.0.patch",
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const copiedPatches: Record<string, PatchFile> = {
|
|
44
|
+
"lodash@4.17.21": {
|
|
45
|
+
path: "patches/lodash@4.17.21.patch",
|
|
46
|
+
hash: "abc",
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
writeIsolatePnpmWorkspace({
|
|
51
|
+
workspaceRootDir,
|
|
52
|
+
isolateDir,
|
|
53
|
+
copiedPatches,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
expect(fs.copyFileSync).not.toHaveBeenCalled();
|
|
57
|
+
expect(writeTypedYamlSync).toHaveBeenCalledTimes(1);
|
|
58
|
+
expect(writeTypedYamlSync).toHaveBeenCalledWith(
|
|
59
|
+
"/workspace/isolate/pnpm-workspace.yaml",
|
|
60
|
+
{
|
|
61
|
+
packages: ["packages/*"],
|
|
62
|
+
patchedDependencies: {
|
|
63
|
+
"lodash@4.17.21": "patches/lodash@4.17.21.patch",
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it("removes the patchedDependencies field when no patches were copied", () => {
|
|
70
|
+
readTypedYamlSync.mockReturnValue({
|
|
71
|
+
packages: ["packages/*"],
|
|
72
|
+
patchedDependencies: {
|
|
73
|
+
"lodash@4.17.21": "patches/lodash@4.17.21.patch",
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
writeIsolatePnpmWorkspace({
|
|
78
|
+
workspaceRootDir,
|
|
79
|
+
isolateDir,
|
|
80
|
+
copiedPatches: {},
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
expect(fs.copyFileSync).not.toHaveBeenCalled();
|
|
84
|
+
expect(writeTypedYamlSync).toHaveBeenCalledWith(
|
|
85
|
+
"/workspace/isolate/pnpm-workspace.yaml",
|
|
86
|
+
{ packages: ["packages/*"] },
|
|
87
|
+
);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it("falls back to a verbatim copy when the file has no patchedDependencies field", () => {
|
|
91
|
+
readTypedYamlSync.mockReturnValue({
|
|
92
|
+
packages: ["packages/*"],
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
writeIsolatePnpmWorkspace({
|
|
96
|
+
workspaceRootDir,
|
|
97
|
+
isolateDir,
|
|
98
|
+
copiedPatches: {},
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
expect(writeTypedYamlSync).not.toHaveBeenCalled();
|
|
102
|
+
expect(fs.copyFileSync).toHaveBeenCalledWith(
|
|
103
|
+
"/workspace/pnpm-workspace.yaml",
|
|
104
|
+
"/workspace/isolate/pnpm-workspace.yaml",
|
|
105
|
+
);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it("preserves unrelated top-level fields", () => {
|
|
109
|
+
readTypedYamlSync.mockReturnValue({
|
|
110
|
+
packages: ["packages/*"],
|
|
111
|
+
onlyBuiltDependencies: ["esbuild"],
|
|
112
|
+
overrides: { foo: "1.0.0" },
|
|
113
|
+
patchedDependencies: {
|
|
114
|
+
"lodash@4.17.21": "patches/lodash@4.17.21.patch",
|
|
115
|
+
"react@18.2.0": "patches/react@18.2.0.patch",
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
const copiedPatches: Record<string, PatchFile> = {
|
|
120
|
+
"react@18.2.0": { path: "patches/react@18.2.0.patch", hash: "def" },
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
writeIsolatePnpmWorkspace({
|
|
124
|
+
workspaceRootDir,
|
|
125
|
+
isolateDir,
|
|
126
|
+
copiedPatches,
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
expect(writeTypedYamlSync).toHaveBeenCalledWith(
|
|
130
|
+
"/workspace/isolate/pnpm-workspace.yaml",
|
|
131
|
+
{
|
|
132
|
+
packages: ["packages/*"],
|
|
133
|
+
onlyBuiltDependencies: ["esbuild"],
|
|
134
|
+
overrides: { foo: "1.0.0" },
|
|
135
|
+
patchedDependencies: {
|
|
136
|
+
"react@18.2.0": "patches/react@18.2.0.patch",
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it("copies verbatim when every patch is kept (preserving comments and order)", () => {
|
|
143
|
+
readTypedYamlSync.mockReturnValue({
|
|
144
|
+
packages: ["packages/*"],
|
|
145
|
+
patchedDependencies: {
|
|
146
|
+
"lodash@4.17.21": "patches/lodash@4.17.21.patch",
|
|
147
|
+
"react@18.2.0": "patches/react@18.2.0.patch",
|
|
148
|
+
},
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
const copiedPatches: Record<string, PatchFile> = {
|
|
152
|
+
"lodash@4.17.21": {
|
|
153
|
+
path: "patches/lodash@4.17.21.patch",
|
|
154
|
+
hash: "abc",
|
|
155
|
+
},
|
|
156
|
+
"react@18.2.0": { path: "patches/react@18.2.0.patch", hash: "def" },
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
writeIsolatePnpmWorkspace({
|
|
160
|
+
workspaceRootDir,
|
|
161
|
+
isolateDir,
|
|
162
|
+
copiedPatches,
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
expect(writeTypedYamlSync).not.toHaveBeenCalled();
|
|
166
|
+
expect(fs.copyFileSync).toHaveBeenCalledWith(
|
|
167
|
+
"/workspace/pnpm-workspace.yaml",
|
|
168
|
+
"/workspace/isolate/pnpm-workspace.yaml",
|
|
169
|
+
);
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it("falls back to a verbatim copy when the yaml cannot be parsed", () => {
|
|
173
|
+
readTypedYamlSync.mockImplementation(() => {
|
|
174
|
+
throw new Error("bad yaml");
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
writeIsolatePnpmWorkspace({
|
|
178
|
+
workspaceRootDir,
|
|
179
|
+
isolateDir,
|
|
180
|
+
copiedPatches: {},
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
expect(writeTypedYamlSync).not.toHaveBeenCalled();
|
|
184
|
+
expect(fs.copyFileSync).toHaveBeenCalledWith(
|
|
185
|
+
"/workspace/pnpm-workspace.yaml",
|
|
186
|
+
"/workspace/isolate/pnpm-workspace.yaml",
|
|
187
|
+
);
|
|
188
|
+
});
|
|
189
|
+
});
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import fs from "fs-extra";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { useLogger } from "~/lib/logger";
|
|
4
|
+
import type { PatchFile, PnpmSettings } from "~/lib/types";
|
|
5
|
+
import { readTypedYamlSync, writeTypedYamlSync } from "~/lib/utils";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Copy `pnpm-workspace.yaml` from the workspace root to the isolate directory,
|
|
9
|
+
* filtering its `patchedDependencies` field so it only references patches that
|
|
10
|
+
* were actually copied to the isolate. Without this, `pnpm install` in the
|
|
11
|
+
* isolate fails when patches that don't apply to the target package are
|
|
12
|
+
* declared in the workspace root config (see issue #178).
|
|
13
|
+
*
|
|
14
|
+
* The yaml is only rewritten when filtering is required. The file is copied
|
|
15
|
+
* verbatim — preserving comments, key order, and trailing whitespace — when
|
|
16
|
+
* any of the following hold:
|
|
17
|
+
*
|
|
18
|
+
* - The source yaml cannot be read or parsed.
|
|
19
|
+
* - The parsed settings have no `patchedDependencies` field.
|
|
20
|
+
* - Every entry in `patchedDependencies` is also present in `copiedPatches`
|
|
21
|
+
* (no exclusions, so rewriting would only churn formatting).
|
|
22
|
+
*
|
|
23
|
+
* Otherwise, `patchedDependencies` is rewritten to the entries in
|
|
24
|
+
* `copiedPatches` (or removed entirely when none remain).
|
|
25
|
+
*/
|
|
26
|
+
export function writeIsolatePnpmWorkspace({
|
|
27
|
+
workspaceRootDir,
|
|
28
|
+
isolateDir,
|
|
29
|
+
copiedPatches,
|
|
30
|
+
}: {
|
|
31
|
+
workspaceRootDir: string;
|
|
32
|
+
isolateDir: string;
|
|
33
|
+
copiedPatches: Record<string, PatchFile>;
|
|
34
|
+
}) {
|
|
35
|
+
const log = useLogger();
|
|
36
|
+
const sourcePath = path.join(workspaceRootDir, "pnpm-workspace.yaml");
|
|
37
|
+
const targetPath = path.join(isolateDir, "pnpm-workspace.yaml");
|
|
38
|
+
|
|
39
|
+
let settings: PnpmSettings | undefined;
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
settings = readTypedYamlSync<PnpmSettings>(sourcePath);
|
|
43
|
+
} catch (error) {
|
|
44
|
+
log.warn(
|
|
45
|
+
`Could not read pnpm-workspace.yaml, falling back to verbatim copy: ${error instanceof Error ? error.message : String(error)}`,
|
|
46
|
+
);
|
|
47
|
+
fs.copyFileSync(sourcePath, targetPath);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (!settings || !settings.patchedDependencies) {
|
|
52
|
+
fs.copyFileSync(sourcePath, targetPath);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* If every patch declared in the source yaml was kept, copy verbatim so
|
|
58
|
+
* comments, ordering, and trailing whitespace are preserved.
|
|
59
|
+
*/
|
|
60
|
+
const sourceSpecs = Object.keys(settings.patchedDependencies);
|
|
61
|
+
const copiedSpecs = new Set(Object.keys(copiedPatches));
|
|
62
|
+
const hasExclusions = sourceSpecs.some((spec) => !copiedSpecs.has(spec));
|
|
63
|
+
|
|
64
|
+
if (!hasExclusions) {
|
|
65
|
+
fs.copyFileSync(sourcePath, targetPath);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const filteredEntries = Object.entries(copiedPatches).map(
|
|
70
|
+
([spec, patchFile]) => [spec, patchFile.path] as const,
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
if (filteredEntries.length > 0) {
|
|
74
|
+
settings.patchedDependencies = Object.fromEntries(filteredEntries);
|
|
75
|
+
} else {
|
|
76
|
+
delete settings.patchedDependencies;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
writeTypedYamlSync(targetPath, settings);
|
|
80
|
+
}
|