@pnpm/deps.graph-hasher 1100.2.11 → 1100.2.13

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,36 @@
1
1
  # @pnpm/calc-dep-state
2
2
 
3
+ ## 1100.2.13
4
+
5
+ ### Patch Changes
6
+
7
+ - Installing a local `file:` directory dependency with the global virtual store enabled no longer fails with `TypeError: Cannot read properties of undefined (reading 'split')` [#13335](https://github.com/pnpm/pnpm/issues/13335).
8
+
9
+ Local directory dependencies — `file:` directories and injected workspace packages — now get a global-virtual-store slot of their own per project. They used to share one slot across every project that depended on a directory of the same name, so a project could end up linked to another project's copy of the dependency.
10
+
11
+ - Updated dependencies:
12
+ - @pnpm/deps.path@1100.0.12
13
+ - @pnpm/engine.runtime.system-version@1100.0.7
14
+ - @pnpm/lockfile.types@1100.0.17
15
+ - @pnpm/lockfile.utils@1100.1.6
16
+ - @pnpm/resolving.resolver-base@1100.5.5
17
+ - @pnpm/types@1101.7.0
18
+
19
+ ## 1100.2.12
20
+
21
+ ### Patch Changes
22
+
23
+ - Republished every package: the tarballs published by the v11.13.1 through v11.16.0 releases were missing most of their compiled files due to a packing bug [#13164](https://github.com/pnpm/pnpm/issues/13164).
24
+
25
+ - Updated dependencies:
26
+ - @pnpm/crypto.object-hasher@1100.0.1
27
+ - @pnpm/deps.path@1100.0.11
28
+ - @pnpm/engine.runtime.system-version@1100.0.6
29
+ - @pnpm/lockfile.types@1100.0.16
30
+ - @pnpm/lockfile.utils@1100.1.5
31
+ - @pnpm/resolving.resolver-base@1100.5.4
32
+ - @pnpm/types@1101.6.0
33
+
3
34
  ## 1100.2.11
4
35
 
5
36
  ### Patch Changes
package/lib/index.d.ts ADDED
@@ -0,0 +1,131 @@
1
+ import type { LockfileObject, LockfileResolution, PackageSnapshot } from '@pnpm/lockfile.types';
2
+ import type { AllowBuild, DepPath, PkgIdWithPatchHash, SupportedArchitectures } from '@pnpm/types';
3
+ /**
4
+ * Scan an iterable of lockfile snapshot keys for the resolved
5
+ * `engines.runtime` / `devEngines.runtime` Node version and return
6
+ * its bare version string (e.g. `"22.11.0"`), or `undefined` when
7
+ * no snapshot pins a runtime.
8
+ *
9
+ * Pnpm's runtime resolver writes the pinned Node into the lockfile as
10
+ * a snapshot with key `node@runtime:<version>[(<peers>)]`
11
+ * (see [`engine/runtime/node-resolver/src/index.ts`](https://github.com/pnpm/pnpm/blob/29a42efc3b/engine/runtime/node-resolver/src/index.ts)).
12
+ * The first such key found is treated as authoritative. This is fine
13
+ * as an install-wide fallback (project-pin in the typical case), but
14
+ * snapshots that pin their own Node still need
15
+ * {@link readSnapshotRuntimePin} to get a per-snapshot result.
16
+ *
17
+ * Callers typically pass `Object.keys(lockfile.packages ?? {})` — the
18
+ * in-memory `LockfileObject` merges the on-disk `packages:` and
19
+ * `snapshots:` sections under a single `packages` field, so its keys
20
+ * include every snapshot key the install will hash.
21
+ */
22
+ export declare function findRuntimeNodeVersion(snapshotKeys: Iterable<string>): string | undefined;
23
+ /**
24
+ * Read a single graph node's own `engines.runtime` Node pin from its
25
+ * `children` map. The resolver desugars `engines.runtime` declared on
26
+ * a dependency's manifest into `dependencies.node: 'runtime:<version>'`
27
+ * (see [`installing/deps-resolver/src/resolveDependencies.ts`](https://github.com/pnpm/pnpm/blob/29a42efc3b/installing/deps-resolver/src/resolveDependencies.ts)),
28
+ * which then becomes a `children.node` entry pointing at the
29
+ * `node@runtime:<version>[(peers)]` snapshot key.
30
+ *
31
+ * Returns the bare version (e.g. `"22.11.0"`) when this snapshot pins
32
+ * its own Node — or `undefined` when it doesn't and the caller should
33
+ * fall back to the install-wide pin / host probe.
34
+ *
35
+ * Per-snapshot resolution matters because the bin linker routes
36
+ * lifecycle-script spawns for a pinning package through *that
37
+ * package's* downloaded Node — anchoring the snapshot's GVS engine
38
+ * hash to an install-wide value would produce the wrong
39
+ * side-effects-cache key for cross-pinning installs.
40
+ */
41
+ export declare function readSnapshotRuntimePin(children: Record<string, string> | undefined): string | undefined;
42
+ export type DepsGraph<T extends string> = Record<T, DepsGraphNode<T>>;
43
+ export interface DepsGraphNode<T extends string> {
44
+ children: {
45
+ [alias: string]: T;
46
+ };
47
+ pkgIdWithPatchHash?: PkgIdWithPatchHash;
48
+ resolution?: LockfileResolution;
49
+ fullPkgId?: string;
50
+ }
51
+ export interface DepsStateCache {
52
+ [depPath: string]: string;
53
+ }
54
+ export declare function calcDepState<T extends string>(depsGraph: DepsGraph<T>, cache: DepsStateCache, depPath: string, opts: {
55
+ patchFileHash?: string;
56
+ includeDepGraphHash: boolean;
57
+ supportedArchitectures?: SupportedArchitectures;
58
+ /**
59
+ * Install-wide fallback `engines.runtime` / `devEngines.runtime`
60
+ * Node version (e.g. `"22.11.0"`). Used only when the snapshot at
61
+ * `depPath` doesn't itself pin a Node: per-snapshot pins take
62
+ * precedence so the side-effects-cache key reflects the actual
63
+ * script-runner Node the bin linker would spawn for the package
64
+ * (see {@link readSnapshotRuntimePin}). Typically computed once
65
+ * per install via {@link findRuntimeNodeVersion} over the
66
+ * lockfile's snapshot keys.
67
+ */
68
+ nodeVersion?: string;
69
+ }): string;
70
+ export interface PkgMeta {
71
+ depPath: DepPath;
72
+ name: string;
73
+ version: string;
74
+ }
75
+ export type PkgMetaIterator<T extends PkgMeta> = IterableIterator<T>;
76
+ export interface HashedDepPath<T extends PkgMeta> {
77
+ pkgMeta: T;
78
+ hash: string;
79
+ }
80
+ export interface GraphNodeHashOptions {
81
+ allowBuild?: AllowBuild;
82
+ supportedArchitectures?: SupportedArchitectures;
83
+ /**
84
+ * Install-wide fallback `engines.runtime` / `devEngines.runtime`
85
+ * Node version. Used only for snapshots that don't pin their own
86
+ * Node; pinning snapshots get resolved per-snapshot via
87
+ * {@link readSnapshotRuntimePin} so the GVS engine hash matches
88
+ * the Node the bin linker would actually spawn for each package
89
+ * (see [`bins/linker/src/index.ts`](https://github.com/pnpm/pnpm/blob/29a42efc3b/bins/linker/src/index.ts)).
90
+ * Typically obtained via {@link findRuntimeNodeVersion} over the
91
+ * lockfile's snapshot keys. `undefined` falls back to
92
+ * {@link engineName}'s default (system `node --version`, with
93
+ * `process.version` as a last resort).
94
+ */
95
+ nodeVersion?: string;
96
+ /**
97
+ * Directory the lockfile lives in. Scopes the slots of local directory
98
+ * dependencies to the project that owns them — see
99
+ * {@link isLocalDirectoryResolution}. Omitting it leaves those packages on a
100
+ * shared slot, which is only safe for a lockfile known to have no directory
101
+ * dependencies.
102
+ */
103
+ lockfileDir?: string;
104
+ }
105
+ export declare function iterateHashedGraphNodes<T extends PkgMeta>(graph: DepsGraph<DepPath>, pkgMetaIterator: PkgMetaIterator<T>, opts?: GraphNodeHashOptions): IterableIterator<HashedDepPath<T>>;
106
+ export declare function calcGraphNodeHash<T extends PkgMeta>({ graph, cache, builtDepPaths, buildRequiredCache, supportedArchitectures, nodeVersion, lockfileDir }: {
107
+ graph: DepsGraph<DepPath>;
108
+ cache: DepsStateCache;
109
+ builtDepPaths?: Set<DepPath>;
110
+ buildRequiredCache?: Record<string, boolean>;
111
+ supportedArchitectures?: SupportedArchitectures;
112
+ /** See {@link GraphNodeHashOptions.nodeVersion}. */
113
+ nodeVersion?: string;
114
+ /** See {@link GraphNodeHashOptions.lockfileDir}. */
115
+ lockfileDir?: string;
116
+ }, pkgMeta: T): string;
117
+ export declare function calcLeafGlobalVirtualStorePath(fullPkgId: string, name: string, version: string): string;
118
+ /**
119
+ * `subdepIds` maps each direct child's alias to its full pkg id
120
+ * (`${name}@${version}:${integrity}`). Each child contributes a leaf hash
121
+ * (no transitive walk) to the parent's hash, so the resulting path differs
122
+ * whenever the set or versions of children change. One level deep only —
123
+ * use {@link calcGraphNodeHash} when full graph traversal is needed.
124
+ */
125
+ export declare function calcGlobalVirtualStorePathWithSubdeps(fullPkgId: string, name: string, version: string, subdepIds: Record<string, string>): string;
126
+ export interface PkgMetaAndSnapshot extends PkgMeta {
127
+ pkgSnapshot: PackageSnapshot;
128
+ pkgIdWithPatchHash: PkgIdWithPatchHash;
129
+ }
130
+ export declare function iteratePkgMeta(lockfile: LockfileObject, graph: DepsGraph<DepPath>): PkgMetaIterator<PkgMetaAndSnapshot>;
131
+ export declare function lockfileToDepGraph(lockfile: LockfileObject, supportedArchitectures?: SupportedArchitectures): DepsGraph<DepPath>;
package/lib/index.js CHANGED
@@ -113,25 +113,12 @@ function calcDepGraphHash(depsGraph, cache, parents, depPath, supportedArchitect
113
113
  });
114
114
  return cache[depPath];
115
115
  }
116
- export function* iterateHashedGraphNodes(graph, pkgMetaIterator, allowBuild, supportedArchitectures,
117
- /**
118
- * Install-wide fallback `engines.runtime` / `devEngines.runtime`
119
- * Node version. Used only for snapshots that don't pin their own
120
- * Node; pinning snapshots get resolved per-snapshot via
121
- * {@link readSnapshotRuntimePin} so the GVS engine hash matches
122
- * the Node the bin linker would actually spawn for each package
123
- * (see [`bins/linker/src/index.ts`](https://github.com/pnpm/pnpm/blob/29a42efc3b/bins/linker/src/index.ts)).
124
- * Typically obtained via {@link findRuntimeNodeVersion} over the
125
- * lockfile's snapshot keys. `undefined` falls back to
126
- * {@link engineName}'s default (system `node --version`, with
127
- * `process.version` as a last resort).
128
- */
129
- nodeVersion) {
116
+ export function* iterateHashedGraphNodes(graph, pkgMetaIterator, opts = {}) {
130
117
  let builtDepPaths;
131
118
  let entries;
132
- if (allowBuild != null) {
119
+ if (opts.allowBuild != null) {
133
120
  const pkgMetaList = Array.from(pkgMetaIterator);
134
- builtDepPaths = computeBuiltDepPaths(pkgMetaList, allowBuild);
121
+ builtDepPaths = computeBuiltDepPaths(pkgMetaList, opts.allowBuild);
135
122
  entries = pkgMetaList;
136
123
  }
137
124
  else {
@@ -142,8 +129,9 @@ nodeVersion) {
142
129
  cache: {},
143
130
  builtDepPaths,
144
131
  buildRequiredCache: builtDepPaths !== undefined ? {} : undefined,
145
- supportedArchitectures,
146
- nodeVersion,
132
+ supportedArchitectures: opts.supportedArchitectures,
133
+ nodeVersion: opts.nodeVersion,
134
+ lockfileDir: opts.lockfileDir,
147
135
  };
148
136
  for (const pkgMeta of entries) {
149
137
  yield {
@@ -152,7 +140,7 @@ nodeVersion) {
152
140
  };
153
141
  }
154
142
  }
155
- export function calcGraphNodeHash({ graph, cache, builtDepPaths, buildRequiredCache, supportedArchitectures, nodeVersion }, pkgMeta) {
143
+ export function calcGraphNodeHash({ graph, cache, builtDepPaths, buildRequiredCache, supportedArchitectures, nodeVersion, lockfileDir }, pkgMeta) {
156
144
  const { name, version, depPath } = pkgMeta;
157
145
  // When builtDepPaths is provided (derived from the allowBuilds config),
158
146
  // we only include the engine name for packages that are allowed to build
@@ -169,8 +157,39 @@ export function calcGraphNodeHash({ graph, cache, builtDepPaths, buildRequiredCa
169
157
  const ownPin = readSnapshotRuntimePin(graph[depPath]?.children);
170
158
  const engine = includeEngine ? engineName(ownPin ?? nodeVersion) : null;
171
159
  const deps = calcDepGraphHash(graph, cache, new Set(), depPath, supportedArchitectures);
172
- const hexDigest = hashObjectWithoutSorting({ engine, deps }, { encoding: 'hex' });
173
- return formatGlobalVirtualStorePath(name, version, hexDigest);
160
+ const isLocalDirectory = isLocalDirectoryResolution(graph[depPath]?.resolution);
161
+ // Scoping the slot needs the project's identity; the segment only needs to
162
+ // know that the package is a local directory, so a caller that leaves
163
+ // `lockfileDir` out still gets a well-formed path.
164
+ const project = isLocalDirectory ? lockfileDir : undefined;
165
+ const hexDigest = project == null
166
+ ? hashObjectWithoutSorting({ engine, deps }, { encoding: 'hex' })
167
+ : hashObjectWithoutSorting({ engine, deps, project }, { encoding: 'hex' });
168
+ return formatGlobalVirtualStorePath(name, isLocalDirectory ? LOCAL_DIRECTORY_SEGMENT : version, hexDigest);
169
+ }
170
+ /**
171
+ * Slot segment that stands in for the version of a package resolved from a
172
+ * local directory. pnpm omits the version from a directory snapshot, so the
173
+ * lockfile has none to offer — and the resolver, which does know it from the
174
+ * manifest, must agree with the lockfile or a re-install would relocate the
175
+ * package. The segment is decoration in a store listing; the digest that
176
+ * follows it is what identifies the slot.
177
+ */
178
+ const LOCAL_DIRECTORY_SEGMENT = 'directory';
179
+ /**
180
+ * Whether the package came from a local directory — a `file:` directory
181
+ * dependency or an injected workspace package.
182
+ *
183
+ * Such a package needs a slot of its own per project. A directory resolution is
184
+ * the one resolution with no integrity: it is a path relative to the lockfile,
185
+ * so `file:dep` hashes identically in every project that happens to depend on a
186
+ * directory of that name. Sharing the slot would hand one project the files of
187
+ * whichever project installed first, and because the source directory is
188
+ * mutable pnpm re-imports it on every install — so the projects would go on
189
+ * overwriting each other's dependency.
190
+ */
191
+ function isLocalDirectoryResolution(resolution) {
192
+ return resolution != null && 'type' in resolution && resolution.type === 'directory';
174
193
  }
175
194
  export function calcLeafGlobalVirtualStorePath(fullPkgId, name, version) {
176
195
  const depsHash = hashObject({ id: fullPkgId, deps: {} });
@@ -244,6 +263,7 @@ export function lockfileToDepGraph(lockfile, supportedArchitectures) {
244
263
  });
245
264
  graph[depPath] = {
246
265
  children,
266
+ resolution: pkgSnapshot.resolution,
247
267
  fullPkgId: createFullPkgId(getPkgIdWithPatchHash(depPath), pkgSnapshot.resolution, supportedArchitectures),
248
268
  };
249
269
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pnpm/deps.graph-hasher",
3
- "version": "1100.2.11",
3
+ "version": "1100.2.13",
4
4
  "description": "Calculates the state of a dependency",
5
5
  "keywords": [
6
6
  "pnpm",
@@ -27,18 +27,18 @@
27
27
  "!*.map"
28
28
  ],
29
29
  "dependencies": {
30
- "@pnpm/crypto.object-hasher": "1100.0.0",
31
- "@pnpm/deps.path": "1100.0.10",
32
- "@pnpm/engine.runtime.system-version": "1100.0.5",
33
- "@pnpm/lockfile.types": "1100.0.15",
34
- "@pnpm/lockfile.utils": "1100.1.4",
35
- "@pnpm/resolving.resolver-base": "1100.5.3",
36
- "@pnpm/types": "1101.5.0",
30
+ "@pnpm/crypto.object-hasher": "1100.0.1",
31
+ "@pnpm/deps.path": "1100.0.12",
32
+ "@pnpm/engine.runtime.system-version": "1100.0.7",
33
+ "@pnpm/lockfile.types": "1100.0.17",
34
+ "@pnpm/lockfile.utils": "1100.1.6",
35
+ "@pnpm/resolving.resolver-base": "1100.5.5",
36
+ "@pnpm/types": "1101.7.0",
37
37
  "detect-libc": "^2.1.2"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@jest/globals": "30.4.1",
41
- "@pnpm/deps.graph-hasher": "1100.2.11"
41
+ "@pnpm/deps.graph-hasher": "1100.2.13"
42
42
  },
43
43
  "engines": {
44
44
  "node": ">=22.13"