isolate-package 1.29.0 → 1.30.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.
- package/dist/index.d.mts +7 -1
- package/dist/index.mjs +2 -3
- package/dist/index.mjs.map +1 -1
- package/dist/{isolate-3GcdAuUK.mjs → isolate-CJy3YyKG.mjs} +261 -64
- package/dist/isolate-CJy3YyKG.mjs.map +1 -0
- package/dist/isolate-bin.mjs +3 -5
- package/dist/isolate-bin.mjs.map +1 -1
- package/package.json +21 -20
- package/src/get-internal-package-names.test.ts +0 -10
- package/src/index.ts +6 -0
- package/src/isolate.ts +38 -8
- package/src/lib/lockfile/helpers/generate-bun-lockfile.test.ts +619 -0
- package/src/lib/lockfile/helpers/generate-bun-lockfile.ts +354 -0
- package/src/lib/lockfile/helpers/generate-pnpm-lockfile.test.ts +387 -0
- package/src/lib/lockfile/helpers/index.ts +1 -0
- package/src/lib/lockfile/helpers/pnpm-map-importer.test.ts +183 -0
- package/src/lib/lockfile/process-lockfile.test.ts +238 -0
- package/src/lib/lockfile/process-lockfile.ts +6 -6
- package/src/lib/manifest/adapt-target-package-manifest.ts +6 -4
- package/src/lib/manifest/helpers/adapt-internal-package-manifests.test.ts +49 -0
- package/src/lib/manifest/helpers/adapt-internal-package-manifests.ts +15 -3
- package/src/lib/manifest/helpers/adopt-pnpm-fields-from-root.test.ts +61 -0
- package/src/lib/manifest/helpers/adopt-pnpm-fields-from-root.ts +42 -3
- package/src/lib/patches/copy-patches.test.ts +49 -11
- package/src/lib/patches/copy-patches.ts +38 -17
- package/src/lib/types.ts +5 -0
- package/src/lib/utils/filter-patched-dependencies.test.ts +1 -11
- package/src/testing/setup.ts +13 -0
- package/dist/isolate-3GcdAuUK.mjs.map +0 -1
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
|
|
2
|
+
import { generatePnpmLockfile } from "./generate-pnpm-lockfile";
|
|
3
|
+
|
|
4
|
+
/** Mock utils */
|
|
5
|
+
vi.mock("~/lib/utils", () => ({
|
|
6
|
+
getErrorMessage: vi.fn((err: Error) => err.message),
|
|
7
|
+
isRushWorkspace: vi.fn(() => false),
|
|
8
|
+
}));
|
|
9
|
+
|
|
10
|
+
/** Mock pnpm v8 lockfile functions */
|
|
11
|
+
vi.mock("pnpm_lockfile_file_v8", () => ({
|
|
12
|
+
readWantedLockfile: vi.fn(),
|
|
13
|
+
writeWantedLockfile: vi.fn(),
|
|
14
|
+
getLockfileImporterId: vi.fn((_root: string, pkgDir: string) =>
|
|
15
|
+
pkgDir.replace(/.*\//, "").replace(/\\/g, "/"),
|
|
16
|
+
),
|
|
17
|
+
}));
|
|
18
|
+
|
|
19
|
+
/** Mock pnpm v9 lockfile functions */
|
|
20
|
+
vi.mock("pnpm_lockfile_file_v9", () => ({
|
|
21
|
+
readWantedLockfile: vi.fn(),
|
|
22
|
+
writeWantedLockfile: vi.fn(),
|
|
23
|
+
getLockfileImporterId: vi.fn((_root: string, pkgDir: string) =>
|
|
24
|
+
pkgDir.replace(/.*\//, "").replace(/\\/g, "/"),
|
|
25
|
+
),
|
|
26
|
+
}));
|
|
27
|
+
|
|
28
|
+
/** Mock pnpm prune functions */
|
|
29
|
+
vi.mock("pnpm_prune_lockfile_v8", () => ({
|
|
30
|
+
pruneLockfile: vi.fn((lockfile: Record<string, unknown>) => ({
|
|
31
|
+
...lockfile,
|
|
32
|
+
})),
|
|
33
|
+
}));
|
|
34
|
+
|
|
35
|
+
vi.mock("pnpm_prune_lockfile_v9", () => ({
|
|
36
|
+
pruneLockfile: vi.fn((lockfile: Record<string, unknown>) => ({
|
|
37
|
+
...lockfile,
|
|
38
|
+
})),
|
|
39
|
+
}));
|
|
40
|
+
|
|
41
|
+
const {
|
|
42
|
+
readWantedLockfile: readWantedLockfile_v8,
|
|
43
|
+
writeWantedLockfile: writeWantedLockfile_v8,
|
|
44
|
+
getLockfileImporterId: getLockfileImporterId_v8,
|
|
45
|
+
} = vi.mocked(await import("pnpm_lockfile_file_v8"));
|
|
46
|
+
|
|
47
|
+
const {
|
|
48
|
+
readWantedLockfile: readWantedLockfile_v9,
|
|
49
|
+
writeWantedLockfile: writeWantedLockfile_v9,
|
|
50
|
+
getLockfileImporterId: getLockfileImporterId_v9,
|
|
51
|
+
} = vi.mocked(await import("pnpm_lockfile_file_v9"));
|
|
52
|
+
|
|
53
|
+
const { pruneLockfile: pruneLockfile_v8 } = vi.mocked(
|
|
54
|
+
await import("pnpm_prune_lockfile_v8"),
|
|
55
|
+
);
|
|
56
|
+
const { pruneLockfile: pruneLockfile_v9 } = vi.mocked(
|
|
57
|
+
await import("pnpm_prune_lockfile_v9"),
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
const { isRushWorkspace } = vi.mocked(await import("~/lib/utils"));
|
|
61
|
+
|
|
62
|
+
/** Reusable lockfile fixture */
|
|
63
|
+
function createMockLockfile() {
|
|
64
|
+
return {
|
|
65
|
+
lockfileVersion: "9.0",
|
|
66
|
+
importers: {
|
|
67
|
+
"apps/my-app": {
|
|
68
|
+
specifiers: { shared: "workspace:*", lodash: "^4.17.21" },
|
|
69
|
+
dependencies: {
|
|
70
|
+
shared: "link:../../packages/shared",
|
|
71
|
+
lodash: "4.17.21",
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
"packages/shared": {
|
|
75
|
+
specifiers: { lodash: "^4.17.21" },
|
|
76
|
+
dependencies: {
|
|
77
|
+
lodash: "4.17.21",
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
"packages/other": {
|
|
81
|
+
specifiers: {},
|
|
82
|
+
dependencies: {},
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
packages: {},
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
describe("generatePnpmLockfile", () => {
|
|
90
|
+
beforeEach(() => {
|
|
91
|
+
vi.clearAllMocks();
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
afterEach(() => {
|
|
95
|
+
vi.restoreAllMocks();
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it("should use v9 API when majorVersion >= 9", async () => {
|
|
99
|
+
const lockfile = createMockLockfile();
|
|
100
|
+
readWantedLockfile_v9.mockResolvedValue(lockfile as never);
|
|
101
|
+
getLockfileImporterId_v9.mockReturnValue("apps/my-app");
|
|
102
|
+
|
|
103
|
+
pruneLockfile_v9.mockReturnValue(lockfile as never);
|
|
104
|
+
|
|
105
|
+
await generatePnpmLockfile({
|
|
106
|
+
workspaceRootDir: "/workspace",
|
|
107
|
+
targetPackageDir: "/workspace/apps/my-app",
|
|
108
|
+
isolateDir: "/workspace/apps/my-app/isolate",
|
|
109
|
+
internalDepPackageNames: ["shared"],
|
|
110
|
+
packagesRegistry: {
|
|
111
|
+
shared: {
|
|
112
|
+
absoluteDir: "/workspace/packages/shared",
|
|
113
|
+
rootRelativeDir: "packages/shared",
|
|
114
|
+
manifest: { name: "shared", version: "1.0.0" },
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
targetPackageManifest: { name: "my-app", version: "1.0.0" },
|
|
118
|
+
majorVersion: 9,
|
|
119
|
+
includeDevDependencies: false,
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
expect(readWantedLockfile_v9).toHaveBeenCalled();
|
|
123
|
+
expect(writeWantedLockfile_v9).toHaveBeenCalled();
|
|
124
|
+
expect(readWantedLockfile_v8).not.toHaveBeenCalled();
|
|
125
|
+
expect(writeWantedLockfile_v8).not.toHaveBeenCalled();
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it("should use v8 API when majorVersion < 9", async () => {
|
|
129
|
+
const lockfile = createMockLockfile();
|
|
130
|
+
readWantedLockfile_v8.mockResolvedValue(lockfile as never);
|
|
131
|
+
getLockfileImporterId_v8.mockReturnValue("apps/my-app");
|
|
132
|
+
|
|
133
|
+
pruneLockfile_v8.mockReturnValue(lockfile as never);
|
|
134
|
+
|
|
135
|
+
await generatePnpmLockfile({
|
|
136
|
+
workspaceRootDir: "/workspace",
|
|
137
|
+
targetPackageDir: "/workspace/apps/my-app",
|
|
138
|
+
isolateDir: "/workspace/apps/my-app/isolate",
|
|
139
|
+
internalDepPackageNames: ["shared"],
|
|
140
|
+
packagesRegistry: {
|
|
141
|
+
shared: {
|
|
142
|
+
absoluteDir: "/workspace/packages/shared",
|
|
143
|
+
rootRelativeDir: "packages/shared",
|
|
144
|
+
manifest: { name: "shared", version: "1.0.0" },
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
targetPackageManifest: { name: "my-app", version: "1.0.0" },
|
|
148
|
+
majorVersion: 8,
|
|
149
|
+
includeDevDependencies: false,
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
expect(readWantedLockfile_v8).toHaveBeenCalled();
|
|
153
|
+
expect(writeWantedLockfile_v8).toHaveBeenCalled();
|
|
154
|
+
expect(readWantedLockfile_v9).not.toHaveBeenCalled();
|
|
155
|
+
expect(writeWantedLockfile_v9).not.toHaveBeenCalled();
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it("should remap target importer to root (.)", async () => {
|
|
159
|
+
const lockfile = createMockLockfile();
|
|
160
|
+
readWantedLockfile_v9.mockResolvedValue(lockfile as never);
|
|
161
|
+
getLockfileImporterId_v9.mockReturnValue("apps/my-app");
|
|
162
|
+
|
|
163
|
+
pruneLockfile_v9.mockImplementation((lf) => lf as never);
|
|
164
|
+
|
|
165
|
+
await generatePnpmLockfile({
|
|
166
|
+
workspaceRootDir: "/workspace",
|
|
167
|
+
targetPackageDir: "/workspace/apps/my-app",
|
|
168
|
+
isolateDir: "/workspace/apps/my-app/isolate",
|
|
169
|
+
internalDepPackageNames: ["shared"],
|
|
170
|
+
packagesRegistry: {
|
|
171
|
+
shared: {
|
|
172
|
+
absoluteDir: "/workspace/packages/shared",
|
|
173
|
+
rootRelativeDir: "packages/shared",
|
|
174
|
+
manifest: { name: "shared", version: "1.0.0" },
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
targetPackageManifest: { name: "my-app", version: "1.0.0" },
|
|
178
|
+
majorVersion: 9,
|
|
179
|
+
includeDevDependencies: false,
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
/** The lockfile passed to prune should have importers with "." as the target */
|
|
183
|
+
const pruneCall = pruneLockfile_v9.mock.calls[0]!;
|
|
184
|
+
const prunedLockfile = pruneCall[0] as {
|
|
185
|
+
importers: Record<string, unknown>;
|
|
186
|
+
};
|
|
187
|
+
expect(prunedLockfile.importers["."]).toBeDefined();
|
|
188
|
+
expect(prunedLockfile.importers["apps/my-app"]).toBeUndefined();
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it("should filter importers to only relevant packages", async () => {
|
|
192
|
+
const lockfile = createMockLockfile();
|
|
193
|
+
readWantedLockfile_v9.mockResolvedValue(lockfile as never);
|
|
194
|
+
getLockfileImporterId_v9.mockReturnValue("apps/my-app");
|
|
195
|
+
|
|
196
|
+
pruneLockfile_v9.mockImplementation((lf) => lf as never);
|
|
197
|
+
|
|
198
|
+
await generatePnpmLockfile({
|
|
199
|
+
workspaceRootDir: "/workspace",
|
|
200
|
+
targetPackageDir: "/workspace/apps/my-app",
|
|
201
|
+
isolateDir: "/workspace/apps/my-app/isolate",
|
|
202
|
+
internalDepPackageNames: ["shared"],
|
|
203
|
+
packagesRegistry: {
|
|
204
|
+
shared: {
|
|
205
|
+
absoluteDir: "/workspace/packages/shared",
|
|
206
|
+
rootRelativeDir: "packages/shared",
|
|
207
|
+
manifest: { name: "shared", version: "1.0.0" },
|
|
208
|
+
},
|
|
209
|
+
},
|
|
210
|
+
targetPackageManifest: { name: "my-app", version: "1.0.0" },
|
|
211
|
+
majorVersion: 9,
|
|
212
|
+
includeDevDependencies: false,
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
const pruneCall = pruneLockfile_v9.mock.calls[0]!;
|
|
216
|
+
const prunedLockfile = pruneCall[0] as {
|
|
217
|
+
importers: Record<string, unknown>;
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
/** Only the target (remapped to ".") and internal dep "packages/shared" should be present */
|
|
221
|
+
expect(Object.keys(prunedLockfile.importers)).toEqual(
|
|
222
|
+
expect.arrayContaining([".", "packages/shared"]),
|
|
223
|
+
);
|
|
224
|
+
/** "packages/other" should be excluded */
|
|
225
|
+
expect(prunedLockfile.importers["packages/other"]).toBeUndefined();
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
it("should preserve overrides after pruning", async () => {
|
|
229
|
+
const lockfile = {
|
|
230
|
+
...createMockLockfile(),
|
|
231
|
+
overrides: { lodash: "4.17.21" },
|
|
232
|
+
};
|
|
233
|
+
readWantedLockfile_v9.mockResolvedValue(lockfile as never);
|
|
234
|
+
getLockfileImporterId_v9.mockReturnValue("apps/my-app");
|
|
235
|
+
|
|
236
|
+
/** Simulate prune removing overrides */
|
|
237
|
+
pruneLockfile_v9.mockImplementation((lf) => {
|
|
238
|
+
const result = { ...(lf as unknown as Record<string, unknown>) };
|
|
239
|
+
delete result.overrides;
|
|
240
|
+
return result as never;
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
await generatePnpmLockfile({
|
|
244
|
+
workspaceRootDir: "/workspace",
|
|
245
|
+
targetPackageDir: "/workspace/apps/my-app",
|
|
246
|
+
isolateDir: "/workspace/apps/my-app/isolate",
|
|
247
|
+
internalDepPackageNames: ["shared"],
|
|
248
|
+
packagesRegistry: {
|
|
249
|
+
shared: {
|
|
250
|
+
absoluteDir: "/workspace/packages/shared",
|
|
251
|
+
rootRelativeDir: "packages/shared",
|
|
252
|
+
manifest: { name: "shared", version: "1.0.0" },
|
|
253
|
+
},
|
|
254
|
+
},
|
|
255
|
+
targetPackageManifest: { name: "my-app", version: "1.0.0" },
|
|
256
|
+
majorVersion: 9,
|
|
257
|
+
includeDevDependencies: false,
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
const writeCall = writeWantedLockfile_v9.mock.calls[0]!;
|
|
261
|
+
const writtenLockfile = writeCall[1] as {
|
|
262
|
+
overrides?: Record<string, string>;
|
|
263
|
+
};
|
|
264
|
+
expect(writtenLockfile.overrides).toEqual({ lodash: "4.17.21" });
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
it("should preserve packageExtensionsChecksum after pruning", async () => {
|
|
268
|
+
const lockfile = {
|
|
269
|
+
...createMockLockfile(),
|
|
270
|
+
packageExtensionsChecksum: "abc123",
|
|
271
|
+
};
|
|
272
|
+
readWantedLockfile_v9.mockResolvedValue(lockfile as never);
|
|
273
|
+
getLockfileImporterId_v9.mockReturnValue("apps/my-app");
|
|
274
|
+
|
|
275
|
+
/** Simulate prune removing packageExtensionsChecksum */
|
|
276
|
+
pruneLockfile_v9.mockImplementation((lf) => {
|
|
277
|
+
const result = { ...(lf as unknown as Record<string, unknown>) };
|
|
278
|
+
delete result.packageExtensionsChecksum;
|
|
279
|
+
return result as never;
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
await generatePnpmLockfile({
|
|
283
|
+
workspaceRootDir: "/workspace",
|
|
284
|
+
targetPackageDir: "/workspace/apps/my-app",
|
|
285
|
+
isolateDir: "/workspace/apps/my-app/isolate",
|
|
286
|
+
internalDepPackageNames: ["shared"],
|
|
287
|
+
packagesRegistry: {
|
|
288
|
+
shared: {
|
|
289
|
+
absoluteDir: "/workspace/packages/shared",
|
|
290
|
+
rootRelativeDir: "packages/shared",
|
|
291
|
+
manifest: { name: "shared", version: "1.0.0" },
|
|
292
|
+
},
|
|
293
|
+
},
|
|
294
|
+
targetPackageManifest: { name: "my-app", version: "1.0.0" },
|
|
295
|
+
majorVersion: 9,
|
|
296
|
+
includeDevDependencies: false,
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
const writeCall = writeWantedLockfile_v9.mock.calls[0]!;
|
|
300
|
+
const writtenLockfile = writeCall[1] as {
|
|
301
|
+
packageExtensionsChecksum?: string;
|
|
302
|
+
};
|
|
303
|
+
expect(writtenLockfile.packageExtensionsChecksum).toBe("abc123");
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
it("should include patchedDependencies in written lockfile", async () => {
|
|
307
|
+
const lockfile = createMockLockfile();
|
|
308
|
+
readWantedLockfile_v9.mockResolvedValue(lockfile as never);
|
|
309
|
+
getLockfileImporterId_v9.mockReturnValue("apps/my-app");
|
|
310
|
+
pruneLockfile_v9.mockImplementation((lf) => lf as never);
|
|
311
|
+
|
|
312
|
+
const patchedDependencies = {
|
|
313
|
+
"lodash@4.17.21": { path: "patches/lodash.patch", hash: "abc123" },
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
await generatePnpmLockfile({
|
|
317
|
+
workspaceRootDir: "/workspace",
|
|
318
|
+
targetPackageDir: "/workspace/apps/my-app",
|
|
319
|
+
isolateDir: "/workspace/apps/my-app/isolate",
|
|
320
|
+
internalDepPackageNames: ["shared"],
|
|
321
|
+
packagesRegistry: {
|
|
322
|
+
shared: {
|
|
323
|
+
absoluteDir: "/workspace/packages/shared",
|
|
324
|
+
rootRelativeDir: "packages/shared",
|
|
325
|
+
manifest: { name: "shared", version: "1.0.0" },
|
|
326
|
+
},
|
|
327
|
+
},
|
|
328
|
+
targetPackageManifest: { name: "my-app", version: "1.0.0" },
|
|
329
|
+
majorVersion: 9,
|
|
330
|
+
includeDevDependencies: false,
|
|
331
|
+
patchedDependencies,
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
const writeCall = writeWantedLockfile_v9.mock.calls[0]!;
|
|
335
|
+
const writtenLockfile = writeCall[1] as {
|
|
336
|
+
patchedDependencies?: Record<string, unknown>;
|
|
337
|
+
};
|
|
338
|
+
expect(writtenLockfile.patchedDependencies).toEqual(patchedDependencies);
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
it("should throw when lockfile is not found", async () => {
|
|
342
|
+
readWantedLockfile_v9.mockResolvedValue(null as never);
|
|
343
|
+
|
|
344
|
+
await expect(
|
|
345
|
+
generatePnpmLockfile({
|
|
346
|
+
workspaceRootDir: "/workspace",
|
|
347
|
+
targetPackageDir: "/workspace/apps/my-app",
|
|
348
|
+
isolateDir: "/workspace/apps/my-app/isolate",
|
|
349
|
+
internalDepPackageNames: [],
|
|
350
|
+
packagesRegistry: {},
|
|
351
|
+
targetPackageManifest: { name: "my-app", version: "1.0.0" },
|
|
352
|
+
majorVersion: 9,
|
|
353
|
+
includeDevDependencies: false,
|
|
354
|
+
}),
|
|
355
|
+
).rejects.toThrow();
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
it("should use Rush lockfile path when in a Rush workspace", async () => {
|
|
359
|
+
isRushWorkspace.mockReturnValue(true);
|
|
360
|
+
const lockfile = createMockLockfile();
|
|
361
|
+
readWantedLockfile_v9.mockResolvedValue(lockfile as never);
|
|
362
|
+
getLockfileImporterId_v9.mockReturnValue("apps/my-app");
|
|
363
|
+
pruneLockfile_v9.mockImplementation((lf) => lf as never);
|
|
364
|
+
|
|
365
|
+
await generatePnpmLockfile({
|
|
366
|
+
workspaceRootDir: "/workspace",
|
|
367
|
+
targetPackageDir: "/workspace/apps/my-app",
|
|
368
|
+
isolateDir: "/workspace/apps/my-app/isolate",
|
|
369
|
+
internalDepPackageNames: ["shared"],
|
|
370
|
+
packagesRegistry: {
|
|
371
|
+
shared: {
|
|
372
|
+
absoluteDir: "/workspace/packages/shared",
|
|
373
|
+
rootRelativeDir: "packages/shared",
|
|
374
|
+
manifest: { name: "shared", version: "1.0.0" },
|
|
375
|
+
},
|
|
376
|
+
},
|
|
377
|
+
targetPackageManifest: { name: "my-app", version: "1.0.0" },
|
|
378
|
+
majorVersion: 9,
|
|
379
|
+
includeDevDependencies: false,
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
expect(readWantedLockfile_v9).toHaveBeenCalledWith(
|
|
383
|
+
"/workspace/common/config/rush",
|
|
384
|
+
expect.any(Object),
|
|
385
|
+
);
|
|
386
|
+
});
|
|
387
|
+
});
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import type { ProjectSnapshot } from "pnpm_lockfile_file_v8";
|
|
3
|
+
import { pnpmMapImporter } from "./pnpm-map-importer";
|
|
4
|
+
|
|
5
|
+
describe("pnpmMapImporter", () => {
|
|
6
|
+
const directoryByPackageName: Record<string, string> = {
|
|
7
|
+
shared: "packages/shared",
|
|
8
|
+
utils: "packages/utils",
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
it("should remap link: dependencies to correct relative paths", () => {
|
|
12
|
+
const importer: ProjectSnapshot = {
|
|
13
|
+
specifiers: { shared: "workspace:*" },
|
|
14
|
+
dependencies: {
|
|
15
|
+
shared: "link:../shared",
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const result = pnpmMapImporter("packages/my-app", importer, {
|
|
20
|
+
includeDevDependencies: false,
|
|
21
|
+
directoryByPackageName,
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
expect(result.dependencies?.["shared"]).toBe("link:../shared");
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("should preserve non-link dependencies unchanged", () => {
|
|
28
|
+
const importer: ProjectSnapshot = {
|
|
29
|
+
specifiers: { lodash: "^4.17.21", shared: "workspace:*" },
|
|
30
|
+
dependencies: {
|
|
31
|
+
lodash: "4.17.21",
|
|
32
|
+
shared: "link:../shared",
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const result = pnpmMapImporter("packages/my-app", importer, {
|
|
37
|
+
includeDevDependencies: false,
|
|
38
|
+
directoryByPackageName,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
expect(result.dependencies?.["lodash"]).toBe("4.17.21");
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("should remove link: entries for non-internal packages", () => {
|
|
45
|
+
const importer: ProjectSnapshot = {
|
|
46
|
+
specifiers: { shared: "workspace:*", "not-internal": "workspace:*" },
|
|
47
|
+
dependencies: {
|
|
48
|
+
shared: "link:../shared",
|
|
49
|
+
"not-internal": "link:../not-internal",
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const result = pnpmMapImporter("packages/my-app", importer, {
|
|
54
|
+
includeDevDependencies: false,
|
|
55
|
+
directoryByPackageName,
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
expect(result.dependencies?.["shared"]).toBeDefined();
|
|
59
|
+
expect(result.dependencies?.["not-internal"]).toBeUndefined();
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("should exclude devDependencies when includeDevDependencies is false", () => {
|
|
63
|
+
const importer: ProjectSnapshot = {
|
|
64
|
+
specifiers: { shared: "workspace:*", vitest: "^1.0.0" },
|
|
65
|
+
dependencies: {
|
|
66
|
+
shared: "link:../shared",
|
|
67
|
+
},
|
|
68
|
+
devDependencies: {
|
|
69
|
+
vitest: "1.0.0",
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const result = pnpmMapImporter("packages/my-app", importer, {
|
|
74
|
+
includeDevDependencies: false,
|
|
75
|
+
directoryByPackageName,
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
expect(result.devDependencies).toBeUndefined();
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it("should include devDependencies when includeDevDependencies is true", () => {
|
|
82
|
+
const importer: ProjectSnapshot = {
|
|
83
|
+
specifiers: {
|
|
84
|
+
shared: "workspace:*",
|
|
85
|
+
vitest: "^1.0.0",
|
|
86
|
+
utils: "workspace:*",
|
|
87
|
+
},
|
|
88
|
+
dependencies: {
|
|
89
|
+
shared: "link:../shared",
|
|
90
|
+
},
|
|
91
|
+
devDependencies: {
|
|
92
|
+
vitest: "1.0.0",
|
|
93
|
+
utils: "link:../utils",
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const result = pnpmMapImporter("packages/my-app", importer, {
|
|
98
|
+
includeDevDependencies: true,
|
|
99
|
+
directoryByPackageName,
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
expect(result.devDependencies?.["vitest"]).toBe("1.0.0");
|
|
103
|
+
expect(result.devDependencies?.["utils"]).toBeDefined();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it("should handle root importer path correctly", () => {
|
|
107
|
+
const importer: ProjectSnapshot = {
|
|
108
|
+
specifiers: { shared: "workspace:*" },
|
|
109
|
+
dependencies: {
|
|
110
|
+
shared: "link:packages/shared",
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const result = pnpmMapImporter(".", importer, {
|
|
115
|
+
includeDevDependencies: false,
|
|
116
|
+
directoryByPackageName,
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
expect(result.dependencies?.["shared"]).toBe("link:./packages/shared");
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it("should handle nested importer paths producing correct relative paths", () => {
|
|
123
|
+
const importer: ProjectSnapshot = {
|
|
124
|
+
specifiers: { utils: "workspace:*" },
|
|
125
|
+
dependencies: {
|
|
126
|
+
utils: "link:../utils",
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
const result = pnpmMapImporter("packages/shared", importer, {
|
|
131
|
+
includeDevDependencies: false,
|
|
132
|
+
directoryByPackageName,
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
expect(result.dependencies?.["utils"]).toBe("link:../utils");
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it("should pass through other ProjectSnapshot fields via rest", () => {
|
|
139
|
+
const importer: ProjectSnapshot = {
|
|
140
|
+
specifiers: { lodash: "^4.17.21" },
|
|
141
|
+
dependencies: {
|
|
142
|
+
lodash: "4.17.21",
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
const result = pnpmMapImporter(".", importer, {
|
|
147
|
+
includeDevDependencies: false,
|
|
148
|
+
directoryByPackageName,
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
expect(result.specifiers).toEqual({ lodash: "^4.17.21" });
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it("should handle undefined dependencies gracefully", () => {
|
|
155
|
+
const importer: ProjectSnapshot = {
|
|
156
|
+
specifiers: {},
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
const result = pnpmMapImporter(".", importer, {
|
|
160
|
+
includeDevDependencies: true,
|
|
161
|
+
directoryByPackageName,
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
expect(result.dependencies).toBeUndefined();
|
|
165
|
+
expect(result.devDependencies).toBeUndefined();
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
it("should add ./ prefix for relative paths that don't start with .", () => {
|
|
169
|
+
const importer: ProjectSnapshot = {
|
|
170
|
+
specifiers: { shared: "workspace:*" },
|
|
171
|
+
dependencies: {
|
|
172
|
+
shared: "link:packages/shared",
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
const result = pnpmMapImporter(".", importer, {
|
|
177
|
+
includeDevDependencies: false,
|
|
178
|
+
directoryByPackageName,
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
expect(result.dependencies?.["shared"]).toMatch(/^link:\.\//);
|
|
182
|
+
});
|
|
183
|
+
});
|