@pnpm/deps.inspection.tree-builder 1101.0.8 → 1101.0.10
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 +28 -0
- package/lib/buildDependenciesTree.d.ts +1 -0
- package/lib/buildDependenciesTree.js +5 -6
- package/lib/buildDependentsTree.d.ts +1 -0
- package/lib/buildDependentsTree.js +8 -6
- package/lib/getPkgInfo.d.ts +3 -0
- package/lib/getPkgInfo.js +5 -0
- package/lib/getTree.d.ts +2 -0
- package/lib/getTree.js +0 -7
- package/lib/resolvePackagePath.d.ts +10 -2
- package/lib/resolvePackagePath.js +115 -7
- package/package.json +15 -15
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# @pnpm/reviewing.dependencies-hierarchy
|
|
2
2
|
|
|
3
|
+
## 1101.0.10
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- `pnpm list` now reports the correct package paths when `nodeLinker` is `hoisted` [#9593](https://github.com/pnpm/pnpm/issues/9593).
|
|
8
|
+
|
|
9
|
+
- Updated dependencies:
|
|
10
|
+
- @pnpm/config.normalize-registries@1101.0.3
|
|
11
|
+
- @pnpm/deps.path@1101.0.6
|
|
12
|
+
- @pnpm/fs.read-modules-dir@1100.0.4
|
|
13
|
+
- @pnpm/installing.modules-yaml@1101.0.6
|
|
14
|
+
- @pnpm/lockfile.detect-dep-types@1100.0.27
|
|
15
|
+
- @pnpm/lockfile.fs@1100.2.13
|
|
16
|
+
- @pnpm/lockfile.peer-edges@1100.0.2
|
|
17
|
+
- @pnpm/lockfile.utils@1102.1.6
|
|
18
|
+
- @pnpm/pkg-manifest.reader@1100.0.22
|
|
19
|
+
- @pnpm/store.cafs@1100.3.7
|
|
20
|
+
- @pnpm/store.index@1101.0.1
|
|
21
|
+
|
|
22
|
+
## 1101.0.9
|
|
23
|
+
|
|
24
|
+
### Patch Changes
|
|
25
|
+
|
|
26
|
+
- Updated dependencies:
|
|
27
|
+
- @pnpm/config.matcher@1100.0.3
|
|
28
|
+
- @pnpm/lockfile.fs@1100.2.12
|
|
29
|
+
- @pnpm/store.cafs@1100.3.6
|
|
30
|
+
|
|
3
31
|
## 1101.0.8
|
|
4
32
|
|
|
5
33
|
### Patch Changes
|
|
@@ -32,6 +32,7 @@ export interface BuildDependenciesTreeOptions {
|
|
|
32
32
|
modulesDir?: string;
|
|
33
33
|
resolvePeersFromWorkspaceRoot?: boolean;
|
|
34
34
|
virtualStoreDirMaxLength: number;
|
|
35
|
+
nodeLinker?: 'hoisted' | 'isolated' | 'pnp';
|
|
35
36
|
}
|
|
36
37
|
export declare function buildDependenciesTree(projectPaths: string[] | undefined, maybeOpts: BuildDependenciesTreeOptions): Promise<{
|
|
37
38
|
[projectDir: string]: DependenciesTree;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { normalizeRegistriesByScope } from '@pnpm/config.normalize-registries';
|
|
3
|
+
import { withCollapsedVariants } from '@pnpm/deps.path';
|
|
3
4
|
import { readModulesDir } from '@pnpm/fs.read-modules-dir';
|
|
4
5
|
import { readModulesManifest } from '@pnpm/installing.modules-yaml';
|
|
5
6
|
import { detectDepTypes } from '@pnpm/lockfile.detect-dep-types';
|
|
@@ -69,8 +70,8 @@ async function buildProjectsTrees(projectPaths, maybeOpts, linkedWalk) {
|
|
|
69
70
|
return Object.fromEntries(pairs);
|
|
70
71
|
}
|
|
71
72
|
async function readLockfiles(modulesDir, lockfileDir) {
|
|
72
|
-
const
|
|
73
|
-
const currentLockfile = await readCurrentLockfile(
|
|
73
|
+
const installStateDir = path.join(modulesDir, '.pnpm');
|
|
74
|
+
const currentLockfile = await readCurrentLockfile(installStateDir, { ignoreIncompatible: false });
|
|
74
75
|
const wantedLockfile = await readWantedLockfile(lockfileDir, { ignoreIncompatible: false });
|
|
75
76
|
return { currentLockfile, wantedLockfile };
|
|
76
77
|
}
|
|
@@ -134,6 +135,8 @@ function createTreeOptions({ treeOpts, modules, modulesDir, registriesByScope, s
|
|
|
134
135
|
modulesDir,
|
|
135
136
|
virtualStoreDir: modules?.virtualStoreDir,
|
|
136
137
|
virtualStoreDirMaxLength: modules?.virtualStoreDirMaxLength ?? treeOpts.virtualStoreDirMaxLength,
|
|
138
|
+
nodeLinker: modules?.nodeLinker ?? treeOpts.nodeLinker,
|
|
139
|
+
hoistedLocations: modules?.hoistedLocations && withCollapsedVariants(modules.hoistedLocations),
|
|
137
140
|
};
|
|
138
141
|
}
|
|
139
142
|
async function expandLinkedProjectsOfEach(pairs, opts) {
|
|
@@ -238,8 +241,6 @@ async function dependenciesHierarchyForPackage(opts, projectPath) {
|
|
|
238
241
|
? opts.modulesDir
|
|
239
242
|
: path.join(projectPath, opts.modulesDir ?? 'node_modules');
|
|
240
243
|
const { result, fieldMap } = initDependencyFields(projectSnapshot, opts.include);
|
|
241
|
-
// Materialize the tree rooted at this importer in a single getTree call.
|
|
242
|
-
// materializeChildren handles all dedup, search, and circular detection.
|
|
243
244
|
// The depth is incremented by 1 because the importer itself is one level;
|
|
244
245
|
// opts.depth controls how deep *below* the direct dependencies we go.
|
|
245
246
|
const nodes = getTree({
|
|
@@ -251,7 +252,6 @@ async function dependenciesHierarchyForPackage(opts, projectPath) {
|
|
|
251
252
|
wantedPackages: wantedLockfile?.packages ?? {},
|
|
252
253
|
modulesDir,
|
|
253
254
|
}, { type: 'importer', importerId });
|
|
254
|
-
// Categorize the materialized nodes into their dependency fields.
|
|
255
255
|
for (const node of nodes) {
|
|
256
256
|
const field = fieldMap.get(node.alias);
|
|
257
257
|
if (field != null) {
|
|
@@ -268,7 +268,6 @@ async function dependenciesHierarchyForPackage(opts, projectPath) {
|
|
|
268
268
|
return result;
|
|
269
269
|
}
|
|
270
270
|
function initDependencyFields(projectSnapshot, include) {
|
|
271
|
-
// Build a map from alias → dependency field for post-categorization.
|
|
272
271
|
const result = {};
|
|
273
272
|
const fieldMap = new Map();
|
|
274
273
|
for (const field of DEPENDENCIES_FIELDS.sort().filter(f => include[f])) {
|
|
@@ -46,6 +46,7 @@ interface BuildDependentsTreeOptions {
|
|
|
46
46
|
lockfile: LockfileObject;
|
|
47
47
|
nameFormatter?: NameFormatter;
|
|
48
48
|
resolvePeersFromWorkspaceRoot?: boolean;
|
|
49
|
+
nodeLinker?: 'hoisted' | 'isolated' | 'pnp';
|
|
49
50
|
}
|
|
50
51
|
export declare function buildDependentsTree(packages: string[], projectPaths: string[], opts: BuildDependentsTreeOptions): Promise<DependentsTree[]>;
|
|
51
52
|
export {};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { normalizeRegistriesByScope } from '@pnpm/config.normalize-registries';
|
|
3
|
+
import { withCollapsedVariants } from '@pnpm/deps.path';
|
|
3
4
|
import { readModulesManifest } from '@pnpm/installing.modules-yaml';
|
|
4
5
|
import { getLockfileImporterId, } from '@pnpm/lockfile.fs';
|
|
5
6
|
import { getPeerSatisfactionEdgesToSkip } from '@pnpm/lockfile.peer-edges';
|
|
@@ -34,6 +35,9 @@ export async function buildDependentsTree(packages, projectPaths, opts) {
|
|
|
34
35
|
wantedPackages: currentPackages,
|
|
35
36
|
storeDir,
|
|
36
37
|
storeIndex,
|
|
38
|
+
nodeLinker: modules?.nodeLinker ?? opts.nodeLinker,
|
|
39
|
+
hoistedLocations: modules?.hoistedLocations && withCollapsedVariants(modules.hoistedLocations),
|
|
40
|
+
lockfileDir: opts.lockfileDir,
|
|
37
41
|
});
|
|
38
42
|
const trees = collectMatchedTrees(search, {
|
|
39
43
|
reverseMap,
|
|
@@ -56,7 +60,6 @@ function buildSelectedProjectsGraph(projectPaths, opts) {
|
|
|
56
60
|
devDependencies: true,
|
|
57
61
|
optionalDependencies: true,
|
|
58
62
|
};
|
|
59
|
-
// Build root IDs from the selected project paths (respects --filter / --recursive)
|
|
60
63
|
const allRootIds = [];
|
|
61
64
|
for (const projectPath of projectPaths) {
|
|
62
65
|
const importerId = getLockfileImporterId(opts.lockfileDir, projectPath);
|
|
@@ -125,7 +128,6 @@ function buildTreeIfMatched(search, { serialized, depPath }, ctx) {
|
|
|
125
128
|
}
|
|
126
129
|
function searchPackage(search, pkg, ctx) {
|
|
127
130
|
const { name, version, readManifest } = pkg;
|
|
128
|
-
// Check canonical name first
|
|
129
131
|
const matched = search({ alias: name, name, version, readManifest });
|
|
130
132
|
if (matched)
|
|
131
133
|
return matched;
|
|
@@ -179,7 +181,7 @@ function invertGraph(graph) {
|
|
|
179
181
|
*/
|
|
180
182
|
function resolvePackageNodes(graph, currentPackages, opts) {
|
|
181
183
|
const resolved = new Map();
|
|
182
|
-
function walk(serialized, parentDir) {
|
|
184
|
+
function walk(serialized, parentDir, importerDir) {
|
|
183
185
|
const node = graph.nodes.get(serialized);
|
|
184
186
|
if (!node)
|
|
185
187
|
return;
|
|
@@ -196,18 +198,18 @@ function resolvePackageNodes(graph, currentPackages, opts) {
|
|
|
196
198
|
alias: edge.alias,
|
|
197
199
|
currentPackages,
|
|
198
200
|
depTypes: {},
|
|
199
|
-
linkedPathBaseDir:
|
|
201
|
+
linkedPathBaseDir: importerDir,
|
|
200
202
|
parentDir,
|
|
201
203
|
ref: edge.target.nodeId.depPath,
|
|
202
204
|
skipped: new Set(),
|
|
203
205
|
});
|
|
204
206
|
resolved.set(childSerialized, { path: pkgInfo.path, readManifest });
|
|
205
|
-
walk(childSerialized, pkgInfo.path);
|
|
207
|
+
walk(childSerialized, pkgInfo.path, importerDir);
|
|
206
208
|
}
|
|
207
209
|
}
|
|
208
210
|
for (const [serialized, node] of graph.nodes) {
|
|
209
211
|
if (node.nodeId.type === 'importer') {
|
|
210
|
-
walk(serialized, undefined);
|
|
212
|
+
walk(serialized, undefined, path.join(opts.lockfileDir, node.nodeId.importerId));
|
|
211
213
|
}
|
|
212
214
|
}
|
|
213
215
|
return resolved;
|
package/lib/getPkgInfo.d.ts
CHANGED
|
@@ -41,6 +41,9 @@ export interface GetPkgInfoOpts {
|
|
|
41
41
|
* This is needed for subdependencies when using global virtual store.
|
|
42
42
|
*/
|
|
43
43
|
readonly parentDir?: string;
|
|
44
|
+
readonly nodeLinker?: 'hoisted' | 'isolated' | 'pnp';
|
|
45
|
+
readonly hoistedLocations?: Record<string, string[]>;
|
|
46
|
+
readonly lockfileDir?: string;
|
|
44
47
|
}
|
|
45
48
|
export declare function getPkgInfo(opts: GetPkgInfoOpts): {
|
|
46
49
|
pkgInfo: PackageInfo;
|
package/lib/getPkgInfo.js
CHANGED
|
@@ -21,6 +21,11 @@ export function getPkgInfo(opts) {
|
|
|
21
21
|
virtualStoreDirMaxLength: opts.virtualStoreDirMaxLength,
|
|
22
22
|
modulesDir: opts.modulesDir,
|
|
23
23
|
parentDir: opts.parentDir,
|
|
24
|
+
nodeLinker: opts.nodeLinker,
|
|
25
|
+
hoistedLocations: opts.hoistedLocations,
|
|
26
|
+
lockfileDir: opts.lockfileDir,
|
|
27
|
+
projectDir: opts.linkedPathBaseDir,
|
|
28
|
+
version: lockedInfo.version,
|
|
24
29
|
})
|
|
25
30
|
: resolveLinkedPath(opts);
|
|
26
31
|
const version = rewriteLinkVersion(lockedInfo.version || opts.ref, fullPackagePath, opts.rewriteLinkVersionDir);
|
package/lib/getTree.d.ts
CHANGED
|
@@ -27,6 +27,8 @@ export interface BaseTreeOpts {
|
|
|
27
27
|
showDedupedSearchMatches?: boolean;
|
|
28
28
|
graph: DependencyGraph;
|
|
29
29
|
materializationCache: MaterializationCache;
|
|
30
|
+
nodeLinker?: 'hoisted' | 'isolated' | 'pnp';
|
|
31
|
+
hoistedLocations?: Record<string, string[]>;
|
|
30
32
|
}
|
|
31
33
|
interface GetTreeOpts extends BaseTreeOpts {
|
|
32
34
|
maxDepth: number;
|
package/lib/getTree.js
CHANGED
|
@@ -12,11 +12,6 @@ export function getTree(opts, parentId) {
|
|
|
12
12
|
ancestors,
|
|
13
13
|
};
|
|
14
14
|
const result = materializeChildren(ctx, parentId, opts.maxDepth, opts.parentDir);
|
|
15
|
-
// Mark circular back-edges. materializeChildren truncates dependencies
|
|
16
|
-
// at cycle boundaries but does not set the `circular` flag, so that cached
|
|
17
|
-
// subtrees stay context-independent. fixCircularRefs walks the final tree
|
|
18
|
-
// and adds `circular: true` wherever a node's path matches an ancestor.
|
|
19
|
-
//
|
|
20
15
|
// Seed the ancestors with parentDir (the filesystem path of parentId) so
|
|
21
16
|
// that back-edges to the root of this subtree are detected — the root
|
|
22
17
|
// itself does not appear as a node in the tree, only its children do.
|
|
@@ -154,7 +149,6 @@ function materializeTarget(ctx, { target, maxDepth, dir }) {
|
|
|
154
149
|
ctx.ancestors.add(target.id);
|
|
155
150
|
const childResult = materializeChildren(ctx, target.nodeId, maxDepth, dir);
|
|
156
151
|
ctx.ancestors.delete(target.id);
|
|
157
|
-
// Always cache — even results with circular truncations.
|
|
158
152
|
ctx.materializationCache.set(cacheKey, {
|
|
159
153
|
count: childResult.count,
|
|
160
154
|
hasSearchMatch: childResult.hasSearchMatch,
|
|
@@ -228,7 +222,6 @@ function markSearchMatch(newEntry, { searchMatch, subtree, result }) {
|
|
|
228
222
|
function fixCircularRefs(nodes, ancestors) {
|
|
229
223
|
let changed = false;
|
|
230
224
|
const result = nodes.map(node => {
|
|
231
|
-
// A node whose path matches an ancestor is a circular back-edge.
|
|
232
225
|
if (node.path && ancestors.has(node.path)) {
|
|
233
226
|
changed = true;
|
|
234
227
|
const { dependencies: _, deduped: _d, dedupedDependenciesCount: _c, ...rest } = node;
|
|
@@ -4,8 +4,10 @@
|
|
|
4
4
|
* For local virtual stores, the path is constructed directly.
|
|
5
5
|
* For global virtual stores (where virtualStoreDir is outside modulesDir),
|
|
6
6
|
* symlinks are resolved to find the actual store location.
|
|
7
|
+
* For hoisted linker (where virtual store is empty), packages live where the
|
|
8
|
+
* hoisted linker placed them, recorded in hoistedLocations.
|
|
7
9
|
*/
|
|
8
|
-
export
|
|
10
|
+
export interface ResolvePackagePathOptions {
|
|
9
11
|
depPath: string;
|
|
10
12
|
name: string;
|
|
11
13
|
alias: string;
|
|
@@ -13,4 +15,10 @@ export declare function resolvePackagePath(opts: {
|
|
|
13
15
|
virtualStoreDirMaxLength: number;
|
|
14
16
|
modulesDir?: string;
|
|
15
17
|
parentDir?: string;
|
|
16
|
-
|
|
18
|
+
nodeLinker?: 'hoisted' | 'isolated' | 'pnp';
|
|
19
|
+
hoistedLocations?: Record<string, string[]>;
|
|
20
|
+
lockfileDir?: string;
|
|
21
|
+
projectDir?: string;
|
|
22
|
+
version?: string;
|
|
23
|
+
}
|
|
24
|
+
export declare function resolvePackagePath(opts: ResolvePackagePathOptions): string;
|
|
@@ -1,14 +1,105 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import { depPathToFilename } from '@pnpm/deps.path';
|
|
3
|
+
import { depPathToFilename, findHoistedPackageDirs } from '@pnpm/deps.path';
|
|
4
|
+
import { readPackageJsonFromDirSync } from '@pnpm/pkg-manifest.reader';
|
|
5
|
+
export function resolvePackagePath(opts) {
|
|
6
|
+
if (isUnsafePathComponent(opts.name)) {
|
|
7
|
+
return opts.virtualStoreDir;
|
|
8
|
+
}
|
|
9
|
+
if (opts.nodeLinker === 'hoisted') {
|
|
10
|
+
const hoistedPath = resolveHoistedPackagePath(opts);
|
|
11
|
+
if (hoistedPath != null)
|
|
12
|
+
return hoistedPath;
|
|
13
|
+
}
|
|
14
|
+
return resolveVirtualStorePackagePath(opts);
|
|
15
|
+
}
|
|
16
|
+
function resolveHoistedPackagePath(opts) {
|
|
17
|
+
const lockfileDir = opts.lockfileDir ?? opts.projectDir;
|
|
18
|
+
if (!lockfileDir)
|
|
19
|
+
return undefined;
|
|
20
|
+
const hoistedPaths = findHoistedPackageDirs(opts.hoistedLocations, opts.depPath, lockfileDir);
|
|
21
|
+
if (hoistedPaths.length)
|
|
22
|
+
return pickHoistedDir(hoistedPaths, { ...opts, lockfileDir });
|
|
23
|
+
return findHoistedByAlias(opts, lockfileDir);
|
|
24
|
+
}
|
|
4
25
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
26
|
+
* Picks the copy that Node.js resolves from the parent package, or from the
|
|
27
|
+
* project for a direct dependency: the one in the closest modules directory
|
|
28
|
+
* above it. Copies on disk under the edge's alias are preferred, since one
|
|
29
|
+
* depPath gets a directory per alias it is installed under. Falls back to any
|
|
30
|
+
* copy on disk, then to the recorded one under the alias, then to the first
|
|
31
|
+
* recorded one.
|
|
10
32
|
*/
|
|
11
|
-
|
|
33
|
+
function pickHoistedDir(recordedDirs, opts) {
|
|
34
|
+
const existing = recordedDirs.filter((dir) => fs.existsSync(dir));
|
|
35
|
+
const existingUnderAlias = existing.filter((dir) => isInstalledUnder(dir, opts.alias));
|
|
36
|
+
const candidates = existingUnderAlias.length ? existingUnderAlias : existing;
|
|
37
|
+
const resolveFrom = opts.parentDir ?? opts.projectDir;
|
|
38
|
+
if (resolveFrom) {
|
|
39
|
+
const relativeModulesDir = getRelativeModulesDir(opts.lockfileDir, opts.modulesDir);
|
|
40
|
+
const closest = candidates
|
|
41
|
+
.map((dir) => ({ dir, ownerDir: getOwnerDir(dir, relativeModulesDir) }))
|
|
42
|
+
.filter(({ ownerDir }) => isSameOrSubdir(ownerDir, resolveFrom))
|
|
43
|
+
.sort((a, b) => b.ownerDir.length - a.ownerDir.length)[0];
|
|
44
|
+
if (closest)
|
|
45
|
+
return closest.dir;
|
|
46
|
+
}
|
|
47
|
+
return candidates[0] ??
|
|
48
|
+
recordedDirs.find((dir) => isInstalledUnder(dir, opts.alias)) ??
|
|
49
|
+
recordedDirs[0];
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Whether `pkgDir` is `<modules dir>/<alias>`: its trailing segments spell the
|
|
53
|
+
* whole alias, not just the name of a scoped package.
|
|
54
|
+
*/
|
|
55
|
+
function isInstalledUnder(pkgDir, alias) {
|
|
56
|
+
const aliasSuffix = path.join(path.sep, alias);
|
|
57
|
+
return pkgDir.endsWith(aliasSuffix) &&
|
|
58
|
+
!path.basename(pkgDir.slice(0, -aliasSuffix.length)).startsWith('@');
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* The directory whose modules directory holds `pkgDir`.
|
|
62
|
+
*/
|
|
63
|
+
function getOwnerDir(pkgDir, relativeModulesDir) {
|
|
64
|
+
let modulesDir = path.dirname(pkgDir);
|
|
65
|
+
if (path.basename(modulesDir).startsWith('@'))
|
|
66
|
+
modulesDir = path.dirname(modulesDir);
|
|
67
|
+
const rootModulesDirSuffix = path.sep + relativeModulesDir;
|
|
68
|
+
return modulesDir.endsWith(rootModulesDirSuffix)
|
|
69
|
+
? modulesDir.slice(0, -rootModulesDirSuffix.length)
|
|
70
|
+
: path.dirname(modulesDir);
|
|
71
|
+
}
|
|
72
|
+
function isSameOrSubdir(parent, dir) {
|
|
73
|
+
return dir === parent || dir.startsWith(parent.endsWith(path.sep) ? parent : parent + path.sep);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Probes `<alias>` in the modules directory of the project and of the root,
|
|
77
|
+
* because the hoisted linker places a dependency under its alias.
|
|
78
|
+
*/
|
|
79
|
+
function findHoistedByAlias(opts, lockfileDir) {
|
|
80
|
+
if (isUnsafePathComponent(opts.alias))
|
|
81
|
+
return undefined;
|
|
82
|
+
const relativeModulesDir = getRelativeModulesDir(lockfileDir, opts.modulesDir);
|
|
83
|
+
const rootModulesDir = opts.modulesDir ?? path.join(lockfileDir, 'node_modules');
|
|
84
|
+
const candidates = opts.projectDir ? [path.resolve(opts.projectDir, relativeModulesDir, opts.alias)] : [];
|
|
85
|
+
candidates.push(path.join(rootModulesDir, opts.alias));
|
|
86
|
+
return candidates.find((candidate) => candidateMatchesVersion(candidate, opts.version));
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* The modules directory relative to the lockfile directory, such as
|
|
90
|
+
* `node_modules` or `www/modules`. Falls back to its last segment when it
|
|
91
|
+
* lies outside the lockfile directory.
|
|
92
|
+
*/
|
|
93
|
+
function getRelativeModulesDir(lockfileDir, modulesDir) {
|
|
94
|
+
if (!modulesDir)
|
|
95
|
+
return 'node_modules';
|
|
96
|
+
const relative = path.relative(lockfileDir, modulesDir);
|
|
97
|
+
if (!relative || relative === '..' || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) {
|
|
98
|
+
return path.basename(modulesDir);
|
|
99
|
+
}
|
|
100
|
+
return relative;
|
|
101
|
+
}
|
|
102
|
+
function resolveVirtualStorePackagePath(opts) {
|
|
12
103
|
const fullPackagePath = path.join(opts.virtualStoreDir, depPathToFilename(opts.depPath, opts.virtualStoreDirMaxLength), 'node_modules', opts.name);
|
|
13
104
|
// Resolve symlink for global virtual store.
|
|
14
105
|
if (!isGlobalVirtualStore(opts.virtualStoreDir, opts.modulesDir))
|
|
@@ -46,4 +137,21 @@ function getSymlinkNodeModulesDir(opts) {
|
|
|
46
137
|
? path.dirname(nodeModulesDir)
|
|
47
138
|
: nodeModulesDir;
|
|
48
139
|
}
|
|
140
|
+
function candidateMatchesVersion(candidate, expectedVersion) {
|
|
141
|
+
if (!expectedVersion)
|
|
142
|
+
return fs.existsSync(candidate);
|
|
143
|
+
try {
|
|
144
|
+
const manifest = readPackageJsonFromDirSync(candidate);
|
|
145
|
+
return manifest.version === expectedVersion;
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
function isUnsafePathComponent(component) {
|
|
152
|
+
return (path.isAbsolute(component) ||
|
|
153
|
+
component.startsWith('\\') ||
|
|
154
|
+
component.includes(':') ||
|
|
155
|
+
component.split(/[/\\]/).some((part) => part === '..' || part === '.'));
|
|
156
|
+
}
|
|
49
157
|
//# sourceMappingURL=resolvePackagePath.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pnpm/deps.inspection.tree-builder",
|
|
3
|
-
"version": "1101.0.
|
|
3
|
+
"version": "1101.0.10",
|
|
4
4
|
"description": "Creates a dependencies hierarchy for a symlinked `node_modules`",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pnpm",
|
|
@@ -30,19 +30,19 @@
|
|
|
30
30
|
"!*.map"
|
|
31
31
|
],
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@pnpm/config.matcher": "1100.0.
|
|
34
|
-
"@pnpm/config.normalize-registries": "1101.0.
|
|
35
|
-
"@pnpm/deps.path": "1101.0.
|
|
36
|
-
"@pnpm/fs.read-modules-dir": "1100.0.
|
|
37
|
-
"@pnpm/installing.modules-yaml": "1101.0.
|
|
38
|
-
"@pnpm/lockfile.detect-dep-types": "1100.0.
|
|
39
|
-
"@pnpm/lockfile.fs": "1100.2.
|
|
40
|
-
"@pnpm/lockfile.peer-edges": "1100.0.
|
|
41
|
-
"@pnpm/lockfile.utils": "1102.1.
|
|
33
|
+
"@pnpm/config.matcher": "1100.0.3",
|
|
34
|
+
"@pnpm/config.normalize-registries": "1101.0.3",
|
|
35
|
+
"@pnpm/deps.path": "1101.0.6",
|
|
36
|
+
"@pnpm/fs.read-modules-dir": "1100.0.4",
|
|
37
|
+
"@pnpm/installing.modules-yaml": "1101.0.6",
|
|
38
|
+
"@pnpm/lockfile.detect-dep-types": "1100.0.27",
|
|
39
|
+
"@pnpm/lockfile.fs": "1100.2.13",
|
|
40
|
+
"@pnpm/lockfile.peer-edges": "1100.0.2",
|
|
41
|
+
"@pnpm/lockfile.utils": "1102.1.6",
|
|
42
42
|
"@pnpm/npm-package-arg": "^2.0.0",
|
|
43
|
-
"@pnpm/pkg-manifest.reader": "1100.0.
|
|
44
|
-
"@pnpm/store.cafs": "1100.3.
|
|
45
|
-
"@pnpm/store.index": "1101.0.
|
|
43
|
+
"@pnpm/pkg-manifest.reader": "1100.0.22",
|
|
44
|
+
"@pnpm/store.cafs": "1100.3.7",
|
|
45
|
+
"@pnpm/store.index": "1101.0.1",
|
|
46
46
|
"@pnpm/text.ordinal-comparator": "1100.0.0",
|
|
47
47
|
"@pnpm/types": "1102.1.1",
|
|
48
48
|
"load-json-file": "^7.0.1",
|
|
@@ -55,8 +55,8 @@
|
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
57
|
"@jest/globals": "30.4.1",
|
|
58
|
-
"@pnpm/constants": "1102.0.
|
|
59
|
-
"@pnpm/deps.inspection.tree-builder": "1101.0.
|
|
58
|
+
"@pnpm/constants": "1102.0.1",
|
|
59
|
+
"@pnpm/deps.inspection.tree-builder": "1101.0.10",
|
|
60
60
|
"@pnpm/test-fixtures": "1100.0.1",
|
|
61
61
|
"@types/normalize-path": "^3.0.2",
|
|
62
62
|
"@types/semver": "7.8.0"
|