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.
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/isolate-bin.mjs +5 -6
- package/dist/isolate-bin.mjs.map +1 -1
- package/dist/{isolate-DyRD5Zd_.mjs → isolate-ts-Igq7C.mjs} +888 -271
- package/dist/isolate-ts-Igq7C.mjs.map +1 -0
- package/package.json +23 -19
- package/src/get-internal-package-names.test.ts +1 -1
- package/src/get-internal-package-names.ts +2 -2
- package/src/isolate-bin.ts +5 -5
- package/src/isolate.ts +22 -17
- package/src/lib/config.test.ts +1 -1
- package/src/lib/config.ts +3 -3
- package/src/lib/lockfile/helpers/bun-lockfile.ts +153 -0
- package/src/lib/lockfile/helpers/generate-bun-lockfile.test.ts +3 -3
- package/src/lib/lockfile/helpers/generate-bun-lockfile.ts +14 -146
- package/src/lib/lockfile/helpers/generate-npm-lockfile.integration.test.ts +1 -5
- package/src/lib/lockfile/helpers/generate-npm-lockfile.test.ts +311 -16
- package/src/lib/lockfile/helpers/generate-npm-lockfile.ts +193 -22
- package/src/lib/lockfile/helpers/generate-pnpm-lockfile.test.ts +83 -2
- package/src/lib/lockfile/helpers/generate-pnpm-lockfile.ts +33 -6
- package/src/lib/lockfile/helpers/generate-yarn-lockfile.ts +5 -5
- package/src/lib/lockfile/process-lockfile.test.ts +2 -2
- package/src/lib/manifest/adapt-target-package-manifest.ts +22 -13
- package/src/lib/manifest/helpers/adapt-internal-package-manifests.test.ts +72 -3
- package/src/lib/manifest/helpers/adapt-internal-package-manifests.ts +22 -12
- package/src/lib/manifest/helpers/adapt-manifest-internal-deps.ts +1 -1
- package/src/lib/manifest/helpers/adopt-pnpm-fields-from-root.test.ts +4 -4
- package/src/lib/manifest/helpers/adopt-pnpm-fields-from-root.ts +7 -7
- package/src/lib/manifest/helpers/resolve-catalog-dependencies.test.ts +410 -0
- package/src/lib/manifest/helpers/resolve-catalog-dependencies.ts +115 -27
- package/src/lib/manifest/io.ts +6 -2
- package/src/lib/manifest/validate-manifest.ts +2 -2
- package/src/lib/output/get-build-output-dir.ts +1 -1
- package/src/lib/output/pack-dependencies.ts +1 -1
- package/src/lib/output/process-build-output-files.ts +6 -17
- package/src/lib/package-manager/helpers/infer-from-files.ts +5 -5
- package/src/lib/package-manager/helpers/infer-from-manifest.ts +7 -8
- package/src/lib/package-manager/index.ts +1 -1
- package/src/lib/package-manager/names.ts +8 -10
- package/src/lib/patches/collect-installed-names-bun.test.ts +154 -0
- package/src/lib/patches/collect-installed-names-bun.ts +87 -0
- package/src/lib/patches/collect-installed-names-pnpm.test.ts +316 -0
- package/src/lib/patches/collect-installed-names-pnpm.ts +365 -0
- package/src/lib/patches/copy-patches.test.ts +130 -13
- package/src/lib/patches/copy-patches.ts +47 -10
- package/src/lib/patches/write-isolate-pnpm-workspace.test.ts +83 -3
- package/src/lib/patches/write-isolate-pnpm-workspace.ts +4 -4
- package/src/lib/registry/collect-reachable-package-names.test.ts +1 -1
- package/src/lib/registry/create-packages-registry.ts +34 -31
- package/src/lib/registry/helpers/find-packages-globs.ts +23 -19
- package/src/lib/registry/list-internal-packages.test.ts +2 -2
- package/src/lib/types.ts +2 -2
- package/src/lib/utils/filter-patched-dependencies.test.ts +1 -1
- package/src/lib/utils/filter-patched-dependencies.ts +2 -2
- package/src/lib/utils/get-dirname.ts +1 -1
- package/src/lib/utils/index.ts +1 -1
- package/src/lib/utils/json.ts +12 -14
- package/src/lib/utils/pack.ts +32 -22
- package/src/lib/utils/reset-isolate-dir.test.ts +165 -0
- package/src/lib/utils/reset-isolate-dir.ts +147 -0
- package/src/lib/utils/unpack.test.ts +76 -0
- package/src/lib/utils/unpack.ts +16 -10
- package/src/lib/utils/wait-for-complete-file.test.ts +105 -0
- package/src/lib/utils/wait-for-complete-file.ts +44 -0
- package/src/lib/utils/yaml.ts +8 -9
- package/src/testing/setup.ts +1 -1
- package/dist/isolate-DyRD5Zd_.mjs.map +0 -1
|
@@ -2,7 +2,7 @@ import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
|
|
|
2
2
|
import { generatePnpmLockfile } from "./generate-pnpm-lockfile";
|
|
3
3
|
|
|
4
4
|
/** Mock utils */
|
|
5
|
-
vi.mock("
|
|
5
|
+
vi.mock("#/lib/utils", () => ({
|
|
6
6
|
getErrorMessage: vi.fn((err: Error) => err.message),
|
|
7
7
|
isRushWorkspace: vi.fn(() => false),
|
|
8
8
|
}));
|
|
@@ -57,7 +57,7 @@ const { pruneLockfile: pruneLockfile_v9 } = vi.mocked(
|
|
|
57
57
|
await import("pnpm_prune_lockfile_v9"),
|
|
58
58
|
);
|
|
59
59
|
|
|
60
|
-
const { isRushWorkspace } = vi.mocked(await import("
|
|
60
|
+
const { isRushWorkspace } = vi.mocked(await import("#/lib/utils"));
|
|
61
61
|
|
|
62
62
|
/** Reusable lockfile fixture */
|
|
63
63
|
function createMockLockfile() {
|
|
@@ -303,6 +303,87 @@ describe("generatePnpmLockfile", () => {
|
|
|
303
303
|
expect(writtenLockfile.packageExtensionsChecksum).toBe("abc123");
|
|
304
304
|
});
|
|
305
305
|
|
|
306
|
+
it("should restore the catalogs snapshot after pruning (#198)", async () => {
|
|
307
|
+
const catalogs = {
|
|
308
|
+
default: {
|
|
309
|
+
lodash: { specifier: "^4.17.21", version: "4.17.21" },
|
|
310
|
+
},
|
|
311
|
+
utils: {
|
|
312
|
+
ramda: { specifier: "^0.30.0", version: "0.30.0" },
|
|
313
|
+
},
|
|
314
|
+
};
|
|
315
|
+
const lockfile = {
|
|
316
|
+
...createMockLockfile(),
|
|
317
|
+
catalogs,
|
|
318
|
+
};
|
|
319
|
+
readWantedLockfile_v9.mockResolvedValue(lockfile as never);
|
|
320
|
+
getLockfileImporterId_v9.mockReturnValue("apps/my-app");
|
|
321
|
+
|
|
322
|
+
/** Simulate prune dropping the catalogs snapshot */
|
|
323
|
+
pruneLockfile_v9.mockImplementation((lf) => {
|
|
324
|
+
const result = { ...(lf as unknown as Record<string, unknown>) };
|
|
325
|
+
delete result.catalogs;
|
|
326
|
+
return result as never;
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
await generatePnpmLockfile({
|
|
330
|
+
workspaceRootDir: "/workspace",
|
|
331
|
+
targetPackageDir: "/workspace/apps/my-app",
|
|
332
|
+
isolateDir: "/workspace/apps/my-app/isolate",
|
|
333
|
+
internalDepPackageNames: ["shared"],
|
|
334
|
+
packagesRegistry: {
|
|
335
|
+
shared: {
|
|
336
|
+
absoluteDir: "/workspace/packages/shared",
|
|
337
|
+
rootRelativeDir: "packages/shared",
|
|
338
|
+
manifest: { name: "shared", version: "1.0.0" },
|
|
339
|
+
},
|
|
340
|
+
},
|
|
341
|
+
targetPackageManifest: { name: "my-app", version: "1.0.0" },
|
|
342
|
+
majorVersion: 9,
|
|
343
|
+
includeDevDependencies: false,
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
const writeCall = writeWantedLockfile_v9.mock.calls[0]!;
|
|
347
|
+
const writtenLockfile = writeCall[1] as {
|
|
348
|
+
catalogs?: Record<string, Record<string, unknown>>;
|
|
349
|
+
};
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* The catalogs snapshot is restored verbatim (like overrides), so it stays
|
|
353
|
+
* in sync with the importer specifiers and the verbatim pnpm-workspace.yaml
|
|
354
|
+
* copy.
|
|
355
|
+
*/
|
|
356
|
+
expect(writtenLockfile.catalogs).toEqual(catalogs);
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
it("should not set catalogs when the source lockfile has none", async () => {
|
|
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
|
+
const writeCall = writeWantedLockfile_v9.mock.calls[0]!;
|
|
383
|
+
const writtenLockfile = writeCall[1] as { catalogs?: unknown };
|
|
384
|
+
expect(writtenLockfile.catalogs).toBeUndefined();
|
|
385
|
+
});
|
|
386
|
+
|
|
306
387
|
it("should include patchedDependencies in written lockfile", async () => {
|
|
307
388
|
const lockfile = createMockLockfile();
|
|
308
389
|
readWantedLockfile_v9.mockResolvedValue(lockfile as never);
|
|
@@ -13,11 +13,22 @@ import {
|
|
|
13
13
|
import { pruneLockfile as pruneLockfile_v8 } from "pnpm_prune_lockfile_v8";
|
|
14
14
|
import { pruneLockfile as pruneLockfile_v9 } from "pnpm_prune_lockfile_v9";
|
|
15
15
|
import { pick } from "remeda";
|
|
16
|
-
import { useLogger } from "
|
|
17
|
-
import type { PackageManifest, PackagesRegistry, PatchFile } from "
|
|
18
|
-
import { getErrorMessage, isRushWorkspace } from "
|
|
16
|
+
import { useLogger } from "#/lib/logger";
|
|
17
|
+
import type { PackageManifest, PackagesRegistry, PatchFile } from "#/lib/types";
|
|
18
|
+
import { getErrorMessage, isRushWorkspace } from "#/lib/utils";
|
|
19
19
|
import { pnpmMapImporter } from "./pnpm-map-importer";
|
|
20
20
|
|
|
21
|
+
/**
|
|
22
|
+
* A pnpm catalog snapshot as stored in the lockfile: a map of catalog name
|
|
23
|
+
* (e.g. "default") to a map of dependency name to its resolved entry. The
|
|
24
|
+
* pinned `@pnpm/lockfile-file` types predate catalogs, so we model the shape
|
|
25
|
+
* locally for the cast below.
|
|
26
|
+
*/
|
|
27
|
+
type CatalogSnapshots = Record<
|
|
28
|
+
string,
|
|
29
|
+
Record<string, { specifier: string; version: string }>
|
|
30
|
+
>;
|
|
31
|
+
|
|
21
32
|
export async function generatePnpmLockfile({
|
|
22
33
|
workspaceRootDir,
|
|
23
34
|
targetPackageDir,
|
|
@@ -167,6 +178,22 @@ export async function generatePnpmLockfile({
|
|
|
167
178
|
lockfile.packageExtensionsChecksum;
|
|
168
179
|
}
|
|
169
180
|
|
|
181
|
+
/**
|
|
182
|
+
* Pruning drops the catalogs snapshot, but the isolated importers keep
|
|
183
|
+
* their "catalog:" specifiers (for pnpm we don't resolve catalog deps in
|
|
184
|
+
* the manifest, since the output is itself a workspace). Restore it
|
|
185
|
+
* verbatim — like overrides above — so it stays in sync with the importer
|
|
186
|
+
* specifiers and the preserved pnpm-workspace.yaml catalog definitions,
|
|
187
|
+
* which are themselves copied verbatim (see issue #198). pnpm tolerates
|
|
188
|
+
* catalog entries that no retained importer references, so there is no need
|
|
189
|
+
* to narrow the snapshot.
|
|
190
|
+
*/
|
|
191
|
+
const catalogs = (lockfile as { catalogs?: CatalogSnapshots }).catalogs;
|
|
192
|
+
|
|
193
|
+
if (catalogs) {
|
|
194
|
+
(prunedLockfile as { catalogs?: CatalogSnapshots }).catalogs = catalogs;
|
|
195
|
+
}
|
|
196
|
+
|
|
170
197
|
/**
|
|
171
198
|
* Use pre-computed patched dependencies with transformed paths. The paths
|
|
172
199
|
* are already adapted by copyPatches to match the isolated directory
|
|
@@ -185,8 +212,8 @@ export async function generatePnpmLockfile({
|
|
|
185
212
|
}
|
|
186
213
|
|
|
187
214
|
log.debug("Created lockfile at", path.join(isolateDir, "pnpm-lock.yaml"));
|
|
188
|
-
} catch (
|
|
189
|
-
log.error(`Failed to generate lockfile: ${getErrorMessage(
|
|
190
|
-
throw
|
|
215
|
+
} catch (error) {
|
|
216
|
+
log.error(`Failed to generate lockfile: ${getErrorMessage(error)}`);
|
|
217
|
+
throw error;
|
|
191
218
|
}
|
|
192
219
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import fs from "fs-extra";
|
|
2
2
|
import { execSync } from "node:child_process";
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
import { useLogger } from "
|
|
5
|
-
import { getErrorMessage, isRushWorkspace } from "
|
|
4
|
+
import { useLogger } from "#/lib/logger";
|
|
5
|
+
import { getErrorMessage, isRushWorkspace } from "#/lib/utils";
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Generate an isolated / pruned lockfile, based on the existing lockfile from
|
|
@@ -43,8 +43,8 @@ export async function generateYarnLockfile({
|
|
|
43
43
|
execSync(`yarn install --cwd ${isolateDir}`);
|
|
44
44
|
|
|
45
45
|
log.debug("Generated lockfile at", newLockfilePath);
|
|
46
|
-
} catch (
|
|
47
|
-
log.error(`Failed to generate lockfile: ${getErrorMessage(
|
|
48
|
-
throw
|
|
46
|
+
} catch (error) {
|
|
47
|
+
log.error(`Failed to generate lockfile: ${getErrorMessage(error)}`);
|
|
48
|
+
throw error;
|
|
49
49
|
}
|
|
50
50
|
}
|
|
@@ -3,7 +3,7 @@ import { processLockfile } from "./process-lockfile";
|
|
|
3
3
|
import type { IsolateConfigResolved } from "../config";
|
|
4
4
|
|
|
5
5
|
/** Mock the package manager detection */
|
|
6
|
-
vi.mock("
|
|
6
|
+
vi.mock("#/lib/package-manager", () => ({
|
|
7
7
|
usePackageManager: vi.fn(),
|
|
8
8
|
}));
|
|
9
9
|
|
|
@@ -15,7 +15,7 @@ vi.mock("./helpers", () => ({
|
|
|
15
15
|
generateYarnLockfile: vi.fn(),
|
|
16
16
|
}));
|
|
17
17
|
|
|
18
|
-
const { usePackageManager } = vi.mocked(await import("
|
|
18
|
+
const { usePackageManager } = vi.mocked(await import("#/lib/package-manager"));
|
|
19
19
|
const {
|
|
20
20
|
generateBunLockfile,
|
|
21
21
|
generateNpmLockfile,
|
|
@@ -41,14 +41,26 @@ export async function adaptTargetPackageManifest({
|
|
|
41
41
|
? manifest
|
|
42
42
|
: omit(manifest, ["devDependencies"]);
|
|
43
43
|
|
|
44
|
-
/**
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
44
|
+
/**
|
|
45
|
+
* For PNPM (non-forceNpm) the isolated output is itself a pnpm workspace and
|
|
46
|
+
* the `pnpm-workspace.yaml` with its catalog definitions is preserved, so
|
|
47
|
+
* "catalog:" specifiers can be kept verbatim — just like "workspace:*". The
|
|
48
|
+
* lockfile importers also keep their "catalog:" specifiers, so resolving them
|
|
49
|
+
* here would create a mismatch and break `pnpm install --frozen-lockfile`
|
|
50
|
+
* (see issue #198). For other package managers (and forceNpm) the catalog is
|
|
51
|
+
* not available in the output, so we resolve the specifiers to versions.
|
|
52
|
+
*/
|
|
53
|
+
const isPnpmWorkspaceOutput = packageManager.name === "pnpm" && !forceNpm;
|
|
54
|
+
|
|
55
|
+
const preparedManifest = isPnpmWorkspaceOutput
|
|
56
|
+
? inputManifest
|
|
57
|
+
: {
|
|
58
|
+
...inputManifest,
|
|
59
|
+
dependencies: await resolveCatalogDependencies(
|
|
60
|
+
inputManifest.dependencies,
|
|
61
|
+
workspaceRootDir,
|
|
62
|
+
),
|
|
63
|
+
};
|
|
52
64
|
|
|
53
65
|
const adaptedManifest =
|
|
54
66
|
(packageManager.name === "pnpm" || packageManager.name === "bun") &&
|
|
@@ -59,13 +71,10 @@ export async function adaptTargetPackageManifest({
|
|
|
59
71
|
* want to adopt workspace-level fields from the root package.json
|
|
60
72
|
* (pnpm.overrides for PNPM, top-level overrides for Bun).
|
|
61
73
|
*/
|
|
62
|
-
await adoptPnpmFieldsFromRoot(
|
|
63
|
-
manifestWithResolvedCatalogs,
|
|
64
|
-
workspaceRootDir,
|
|
65
|
-
)
|
|
74
|
+
await adoptPnpmFieldsFromRoot(preparedManifest, workspaceRootDir)
|
|
66
75
|
: /** For other package managers we replace the links to internal dependencies */
|
|
67
76
|
adaptManifestInternalDeps({
|
|
68
|
-
manifest:
|
|
77
|
+
manifest: preparedManifest,
|
|
69
78
|
packagesRegistry,
|
|
70
79
|
});
|
|
71
80
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { describe, it, expect, beforeEach, vi } from "vitest";
|
|
2
|
-
import type { PackageManifest, PackagesRegistry } from "
|
|
2
|
+
import type { PackageManifest, PackagesRegistry } from "#/lib/types";
|
|
3
3
|
|
|
4
4
|
/** Mock dependencies */
|
|
5
|
-
vi.mock("
|
|
5
|
+
vi.mock("#/lib/package-manager", () => ({
|
|
6
6
|
usePackageManager: vi.fn(),
|
|
7
7
|
}));
|
|
8
8
|
|
|
@@ -18,7 +18,11 @@ vi.mock("./resolve-catalog-dependencies", () => ({
|
|
|
18
18
|
resolveCatalogDependencies: vi.fn((deps) => Promise.resolve(deps)),
|
|
19
19
|
}));
|
|
20
20
|
|
|
21
|
-
const { usePackageManager } = vi.mocked(await import("
|
|
21
|
+
const { usePackageManager } = vi.mocked(await import("#/lib/package-manager"));
|
|
22
|
+
|
|
23
|
+
const { resolveCatalogDependencies } = vi.mocked(
|
|
24
|
+
await import("./resolve-catalog-dependencies"),
|
|
25
|
+
);
|
|
22
26
|
|
|
23
27
|
const { writeManifest } = vi.mocked(await import("../io"));
|
|
24
28
|
|
|
@@ -178,4 +182,69 @@ describe("adaptInternalPackageManifests", () => {
|
|
|
178
182
|
|
|
179
183
|
expect(writtenManifest.devDependencies).toBeUndefined();
|
|
180
184
|
});
|
|
185
|
+
|
|
186
|
+
it("should preserve catalog: specifiers for pnpm without resolving them (#198)", async () => {
|
|
187
|
+
const manifest: PackageManifest = {
|
|
188
|
+
name: "@repo/shared",
|
|
189
|
+
version: "1.0.0",
|
|
190
|
+
dependencies: {
|
|
191
|
+
"lodash.merge": "catalog:",
|
|
192
|
+
},
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
const packagesRegistry = createRegistry({
|
|
196
|
+
"@repo/shared": {
|
|
197
|
+
rootRelativeDir: "packages/shared",
|
|
198
|
+
manifest,
|
|
199
|
+
},
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
await adaptInternalPackageManifests({
|
|
203
|
+
internalPackageNames: ["@repo/shared"],
|
|
204
|
+
packagesRegistry,
|
|
205
|
+
isolateDir: "/output",
|
|
206
|
+
forceNpm: false,
|
|
207
|
+
workspaceRootDir: "/workspace",
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* For pnpm the isolated output is itself a workspace with its catalog
|
|
212
|
+
* definitions preserved, so the specifier is kept verbatim rather than
|
|
213
|
+
* resolved (which would desync it from the lockfile importers).
|
|
214
|
+
*/
|
|
215
|
+
expect(resolveCatalogDependencies).not.toHaveBeenCalled();
|
|
216
|
+
|
|
217
|
+
const writtenManifest = writeManifest.mock.calls[0]![1];
|
|
218
|
+
expect(writtenManifest.dependencies).toEqual({
|
|
219
|
+
"lodash.merge": "catalog:",
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
it("should resolve catalog dependencies when forceNpm is enabled", async () => {
|
|
224
|
+
const manifest: PackageManifest = {
|
|
225
|
+
name: "@repo/shared",
|
|
226
|
+
version: "1.0.0",
|
|
227
|
+
dependencies: {
|
|
228
|
+
"lodash.merge": "catalog:",
|
|
229
|
+
},
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
const packagesRegistry = createRegistry({
|
|
233
|
+
"@repo/shared": {
|
|
234
|
+
rootRelativeDir: "packages/shared",
|
|
235
|
+
manifest,
|
|
236
|
+
},
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
await adaptInternalPackageManifests({
|
|
240
|
+
internalPackageNames: ["@repo/shared"],
|
|
241
|
+
packagesRegistry,
|
|
242
|
+
isolateDir: "/output",
|
|
243
|
+
forceNpm: true,
|
|
244
|
+
workspaceRootDir: "/workspace",
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
/** With forceNpm the catalog is not available in the output, so resolve. */
|
|
248
|
+
expect(resolveCatalogDependencies).toHaveBeenCalledOnce();
|
|
249
|
+
});
|
|
181
250
|
});
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { got } from "get-or-throw";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { omit } from "remeda";
|
|
4
|
-
import { usePackageManager } from "
|
|
5
|
-
import type { PackagesRegistry } from "
|
|
4
|
+
import { usePackageManager } from "#/lib/package-manager";
|
|
5
|
+
import type { PackagesRegistry } from "#/lib/types";
|
|
6
6
|
import { writeManifest } from "../io";
|
|
7
7
|
import { adaptManifestInternalDeps } from "./adapt-manifest-internal-deps";
|
|
8
8
|
import { resolveCatalogDependencies } from "./resolve-catalog-dependencies";
|
|
@@ -27,6 +27,15 @@ export async function adaptInternalPackageManifests({
|
|
|
27
27
|
}) {
|
|
28
28
|
const packageManager = usePackageManager();
|
|
29
29
|
|
|
30
|
+
/**
|
|
31
|
+
* For PNPM (non-forceNpm) the isolated output is itself a pnpm workspace with
|
|
32
|
+
* its `pnpm-workspace.yaml` catalog definitions preserved, so "catalog:"
|
|
33
|
+
* specifiers are kept verbatim to stay in sync with the lockfile importers
|
|
34
|
+
* (see issue #198). For other package managers the catalog is not available
|
|
35
|
+
* in the output, so we resolve the specifiers to versions.
|
|
36
|
+
*/
|
|
37
|
+
const isPnpmWorkspaceOutput = packageManager.name === "pnpm" && !forceNpm;
|
|
38
|
+
|
|
30
39
|
await Promise.all(
|
|
31
40
|
internalPackageNames.map(async (packageName) => {
|
|
32
41
|
const { manifest, rootRelativeDir } = got(packagesRegistry, packageName);
|
|
@@ -45,14 +54,15 @@ export async function adaptInternalPackageManifests({
|
|
|
45
54
|
strippedManifest.scripts = omit(strippedManifest.scripts, ["prepare"]);
|
|
46
55
|
}
|
|
47
56
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
57
|
+
const preparedManifest = isPnpmWorkspaceOutput
|
|
58
|
+
? strippedManifest
|
|
59
|
+
: {
|
|
60
|
+
...strippedManifest,
|
|
61
|
+
dependencies: await resolveCatalogDependencies(
|
|
62
|
+
strippedManifest.dependencies,
|
|
63
|
+
workspaceRootDir,
|
|
64
|
+
),
|
|
65
|
+
};
|
|
56
66
|
|
|
57
67
|
const outputManifest =
|
|
58
68
|
(packageManager.name === "pnpm" || packageManager.name === "bun") &&
|
|
@@ -61,10 +71,10 @@ export async function adaptInternalPackageManifests({
|
|
|
61
71
|
* For PNPM and Bun the output itself is a workspace so we can preserve
|
|
62
72
|
* the specifiers with "workspace:*" in the output manifest.
|
|
63
73
|
*/
|
|
64
|
-
|
|
74
|
+
preparedManifest
|
|
65
75
|
: /** For other package managers we replace the links to internal dependencies */
|
|
66
76
|
adaptManifestInternalDeps({
|
|
67
|
-
manifest:
|
|
77
|
+
manifest: preparedManifest,
|
|
68
78
|
packagesRegistry,
|
|
69
79
|
parentRootRelativeDir: rootRelativeDir,
|
|
70
80
|
});
|
|
@@ -7,20 +7,20 @@ import type {
|
|
|
7
7
|
import { adoptPnpmFieldsFromRoot } from "./adopt-pnpm-fields-from-root";
|
|
8
8
|
|
|
9
9
|
/** Mock the dependencies */
|
|
10
|
-
vi.mock("
|
|
10
|
+
vi.mock("#/lib/utils", () => ({
|
|
11
11
|
isRushWorkspace: vi.fn(),
|
|
12
12
|
readTypedJson: vi.fn(),
|
|
13
13
|
}));
|
|
14
14
|
|
|
15
|
-
vi.mock("
|
|
15
|
+
vi.mock("#/lib/package-manager", () => ({
|
|
16
16
|
usePackageManager: vi.fn(() => ({ name: "pnpm", majorVersion: 9 })),
|
|
17
17
|
}));
|
|
18
18
|
|
|
19
19
|
const { isRushWorkspace, readTypedJson } = vi.mocked(
|
|
20
|
-
await import("
|
|
20
|
+
await import("#/lib/utils"),
|
|
21
21
|
);
|
|
22
22
|
|
|
23
|
-
const { usePackageManager } = vi.mocked(await import("
|
|
23
|
+
const { usePackageManager } = vi.mocked(await import("#/lib/package-manager"));
|
|
24
24
|
|
|
25
25
|
describe("adoptPnpmFieldsFromRoot", () => {
|
|
26
26
|
beforeEach(() => {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { ProjectManifest, PnpmSettings } from "@pnpm/types";
|
|
2
|
-
import path from "path";
|
|
3
|
-
import { usePackageManager } from "
|
|
4
|
-
import type { PackageManifest } from "
|
|
5
|
-
import { isRushWorkspace, readTypedJson } from "
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { usePackageManager } from "#/lib/package-manager";
|
|
4
|
+
import type { PackageManifest } from "#/lib/types";
|
|
5
|
+
import { isRushWorkspace, readTypedJson } from "#/lib/utils";
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Adopts workspace-level fields from the root package manifest. For pnpm this
|
|
@@ -17,9 +17,9 @@ export async function adoptPnpmFieldsFromRoot(
|
|
|
17
17
|
return targetPackageManifest;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
const rootPackageManifest = await readTypedJson
|
|
20
|
+
const rootPackageManifest = (await readTypedJson(
|
|
21
21
|
path.join(workspaceRootDir, "package.json"),
|
|
22
|
-
);
|
|
22
|
+
)) as ProjectManifest;
|
|
23
23
|
|
|
24
24
|
const packageManager = usePackageManager();
|
|
25
25
|
|
|
@@ -60,7 +60,7 @@ function adoptPnpmFieldsOnly(
|
|
|
60
60
|
rootPackageManifest: ProjectManifest,
|
|
61
61
|
): PackageManifest {
|
|
62
62
|
const { overrides, onlyBuiltDependencies, ignoredBuiltDependencies } =
|
|
63
|
-
rootPackageManifest.pnpm
|
|
63
|
+
rootPackageManifest.pnpm ?? {};
|
|
64
64
|
|
|
65
65
|
/** If no pnpm fields are present, return the original manifest */
|
|
66
66
|
if (!overrides && !onlyBuiltDependencies && !ignoredBuiltDependencies) {
|