@pnpm/installing.linking.real-hoist 1100.1.13 → 1100.1.15

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/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # @pnpm/real-hoist
2
2
 
3
+ ## 1100.1.15
4
+
5
+ ### Patch Changes
6
+
7
+ - Under `nodeLinker: hoisted`, peer-resolution variants of an injected directory dependency (a `file:` snapshot) are materialized as separate copies again instead of collapsing onto the first-seen variant. Each copy keeps its own peer-resolved dependency set, so a project pinning one peer version no longer resolves another project's variant — Bit root components with conflicting peers across injected copies rely on this.
8
+
9
+ ## 1100.1.14
10
+
11
+ ### Patch Changes
12
+
13
+ - Under `nodeLinker: hoisted`, a dependency declared against a peer-resolution variant of a package version is no longer dropped from the installed layout. All variants of a version share one hoisted copy, and edges pointing at any of them now resolve to it, so the depending project keeps the package in its `.package-map.json` and the depending package keeps it in its `node_modules/.bin`.
14
+
15
+ - Updated dependencies:
16
+ - @pnpm/deps.path@1101.0.0
17
+ - @pnpm/error@1100.1.3
18
+ - @pnpm/lockfile.types@1100.0.20
19
+ - @pnpm/lockfile.utils@1102.0.0
20
+
3
21
  ## 1100.1.13
4
22
 
5
23
  ### Patch Changes
package/lib/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { PackageSnapshot } from '@pnpm/lockfile.types';
1
2
  import { type LockfileObject } from '@pnpm/lockfile.utils';
2
3
  import { type HoisterResult } from '@yarnpkg/nm/hoist';
3
4
  /**
@@ -14,6 +15,34 @@ import { type HoisterResult } from '@yarnpkg/nm/hoist';
14
15
  */
15
16
  export type HoistingLimits = 'none' | 'workspaces' | 'dependencies';
16
17
  export type { HoisterResult };
18
+ /**
19
+ * The identity every peer variant of one package version collapses
20
+ * onto.
21
+ *
22
+ * `toTree` maps the id to the first depPath it sees for it and stamps
23
+ * that depPath on every variant as their shared `reference`, so only
24
+ * that one depPath survives into the result. Anything indexing the
25
+ * hoist result by package therefore has to key *and* look up by this
26
+ * id rather than by the depPath an edge declares — otherwise every
27
+ * edge on a collapsed variant finds nothing and drops out of the
28
+ * layout.
29
+ *
30
+ * One id can still cover several directories: nodes are interned per
31
+ * `(alias, depPath)`, so an alias exposing a package under a second
32
+ * name gets a node, and a directory, of its own. An index over the
33
+ * result holds the list and resolves an edge to its first entry.
34
+ *
35
+ * An injected directory dependency (a `directory` resolution) keeps
36
+ * its peer suffix: every variant of it is a separate on-disk copy of
37
+ * the local package, materialized with its own peer-resolved
38
+ * dependency set, so collapsing the variants would rewire every
39
+ * dependent of the losing one onto the survivor's children (Bit's
40
+ * root components pin conflicting peers across such copies on
41
+ * purpose). The registry collapse exists to stop peer-variant
42
+ * explosion on large lockfiles; directory snapshots are one per
43
+ * injected workspace package and cannot explode that way.
44
+ */
45
+ export declare function getHoisterPkgId(depPath: string, pkgSnapshot: PackageSnapshot): string;
17
46
  /**
18
47
  * Translate the user-facing {@link HoistingLimits} mode into the
19
48
  * `@yarnpkg/nm` hoister's per-locator border map. A name in a
package/lib/index.js CHANGED
@@ -2,6 +2,44 @@ import * as dp from '@pnpm/deps.path';
2
2
  import { LockfileMissingDependencyError } from '@pnpm/error';
3
3
  import { nameVerFromPkgSnapshot, } from '@pnpm/lockfile.utils';
4
4
  import { hoist as _hoist, HoisterDependencyKind } from '@yarnpkg/nm/hoist';
5
+ /**
6
+ * The identity every peer variant of one package version collapses
7
+ * onto.
8
+ *
9
+ * `toTree` maps the id to the first depPath it sees for it and stamps
10
+ * that depPath on every variant as their shared `reference`, so only
11
+ * that one depPath survives into the result. Anything indexing the
12
+ * hoist result by package therefore has to key *and* look up by this
13
+ * id rather than by the depPath an edge declares — otherwise every
14
+ * edge on a collapsed variant finds nothing and drops out of the
15
+ * layout.
16
+ *
17
+ * One id can still cover several directories: nodes are interned per
18
+ * `(alias, depPath)`, so an alias exposing a package under a second
19
+ * name gets a node, and a directory, of its own. An index over the
20
+ * result holds the list and resolves an edge to its first entry.
21
+ *
22
+ * An injected directory dependency (a `directory` resolution) keeps
23
+ * its peer suffix: every variant of it is a separate on-disk copy of
24
+ * the local package, materialized with its own peer-resolved
25
+ * dependency set, so collapsing the variants would rewire every
26
+ * dependent of the losing one onto the survivor's children (Bit's
27
+ * root components pin conflicting peers across such copies on
28
+ * purpose). The registry collapse exists to stop peer-variant
29
+ * explosion on large lockfiles; directory snapshots are one per
30
+ * injected workspace package and cannot explode that way.
31
+ */
32
+ export function getHoisterPkgId(depPath, pkgSnapshot) {
33
+ // `resolution` is typed as required, but the lockfile is parsed from
34
+ // untyped YAML — guard so a malformed snapshot degrades to the
35
+ // collapsed identity instead of a TypeError here.
36
+ const resolution = pkgSnapshot.resolution;
37
+ if (resolution != null && 'directory' in resolution && resolution.directory != null) {
38
+ return depPath;
39
+ }
40
+ const { name, version } = nameVerFromPkgSnapshot(depPath, pkgSnapshot);
41
+ return `${name}@${version}`;
42
+ }
5
43
  /**
6
44
  * Translate the user-facing {@link HoistingLimits} mode into the
7
45
  * `@yarnpkg/nm` hoister's per-locator border map. A name in a
@@ -121,8 +159,8 @@ function toTree({ nodes, lockfile, depPathByPkgId, autoInstallPeers }, deps) {
121
159
  if (!pkgSnapshot) {
122
160
  throw new LockfileMissingDependencyError(depPath);
123
161
  }
124
- const { name: pkgName, version } = nameVerFromPkgSnapshot(depPath, pkgSnapshot);
125
- const id = `${pkgName}@${version}`;
162
+ const { name: pkgName } = nameVerFromPkgSnapshot(depPath, pkgSnapshot);
163
+ const id = getHoisterPkgId(depPath, pkgSnapshot);
126
164
  if (!depPathByPkgId.has(id)) {
127
165
  depPathByPkgId.set(id, depPath);
128
166
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pnpm/installing.linking.real-hoist",
3
- "version": "1100.1.13",
3
+ "version": "1100.1.15",
4
4
  "description": "Hoists dependencies in a node_modules created by pnpm",
5
5
  "keywords": [
6
6
  "pnpm",
@@ -27,17 +27,18 @@
27
27
  "!*.map"
28
28
  ],
29
29
  "dependencies": {
30
- "@pnpm/deps.path": "1100.1.0",
31
- "@pnpm/error": "1100.1.2",
32
- "@pnpm/lockfile.utils": "1101.1.0",
30
+ "@pnpm/deps.path": "1101.0.0",
31
+ "@pnpm/error": "1100.1.3",
32
+ "@pnpm/lockfile.types": "1100.0.20",
33
+ "@pnpm/lockfile.utils": "1102.0.0",
33
34
  "@yarnpkg/nm": "4.1.1"
34
35
  },
35
36
  "devDependencies": {
36
37
  "@jest/globals": "30.4.1",
37
- "@pnpm/installing.linking.real-hoist": "1100.1.13",
38
- "@pnpm/lockfile.fs": "1100.2.2",
38
+ "@pnpm/installing.linking.real-hoist": "1100.1.15",
39
+ "@pnpm/lockfile.fs": "1100.2.4",
39
40
  "@pnpm/test-fixtures": "1100.0.1",
40
- "@pnpm/types": "1101.9.0"
41
+ "@pnpm/types": "1102.0.0"
41
42
  },
42
43
  "engines": {
43
44
  "node": ">=22.13"