@pnpm/lockfile.filtering 1100.1.13 → 1100.2.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/CHANGELOG.md +32 -0
- package/lib/filterImporter.d.ts +7 -0
- package/lib/filterImporter.js +23 -0
- package/lib/filterLockfile.d.ts +9 -0
- package/lib/filterLockfile.js +8 -0
- package/lib/filterLockfileByImporters.d.ts +10 -0
- package/lib/filterLockfileByImporters.js +36 -0
- package/lib/filterLockfileByImportersAndEngine.d.ts +35 -0
- package/lib/filterLockfileByImportersAndEngine.js +266 -0
- package/lib/index.d.ts +3 -0
- package/package.json +11 -11
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,37 @@
|
|
|
1
1
|
# @pnpm/filter-lockfile
|
|
2
2
|
|
|
3
|
+
## 1100.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Fixed an installed optional dependency being left without one of its own required dependencies. When a package reached through `optionalDependencies` is installable on the current system but one of its regular `dependencies` is not, a lockfile-based install skipped that dependency and installed the parent anyway, so importing the parent failed with `MODULE_NOT_FOUND`. The dependency is now installed, and an install-check warning reports the incompatibility. A dependency is still only skipped when every path to it is optional, or when the package that pulls it in was itself skipped [#13286](https://github.com/pnpm/pnpm/issues/13286).
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- Updated dependencies:
|
|
12
|
+
- @pnpm/config.package-is-installable@1100.1.0
|
|
13
|
+
- @pnpm/deps.path@1100.0.12
|
|
14
|
+
- @pnpm/lockfile.types@1100.0.17
|
|
15
|
+
- @pnpm/lockfile.utils@1100.1.6
|
|
16
|
+
- @pnpm/lockfile.walker@1100.0.17
|
|
17
|
+
- @pnpm/types@1101.7.0
|
|
18
|
+
|
|
19
|
+
## 1100.1.14
|
|
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/config.package-is-installable@1100.0.16
|
|
27
|
+
- @pnpm/constants@1100.0.1
|
|
28
|
+
- @pnpm/deps.path@1100.0.11
|
|
29
|
+
- @pnpm/error@1100.1.0
|
|
30
|
+
- @pnpm/lockfile.types@1100.0.16
|
|
31
|
+
- @pnpm/lockfile.utils@1100.1.5
|
|
32
|
+
- @pnpm/lockfile.walker@1100.0.16
|
|
33
|
+
- @pnpm/types@1101.6.0
|
|
34
|
+
|
|
3
35
|
## 1100.1.13
|
|
4
36
|
|
|
5
37
|
### Patch Changes
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ProjectSnapshot } from '@pnpm/lockfile.types';
|
|
2
|
+
import type { DependenciesField } from '@pnpm/types';
|
|
3
|
+
export declare function filterImporter(importer: ProjectSnapshot, include: {
|
|
4
|
+
[dependenciesField in DependenciesField]: boolean;
|
|
5
|
+
}, opts?: {
|
|
6
|
+
skipRuntimes?: boolean;
|
|
7
|
+
}): ProjectSnapshot;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export function filterImporter(importer, include, opts) {
|
|
2
|
+
const skipRuntimes = opts?.skipRuntimes === true;
|
|
3
|
+
return {
|
|
4
|
+
dependencies: !include.dependencies ? {} : pickNonRuntime(importer.dependencies, skipRuntimes),
|
|
5
|
+
devDependencies: !include.devDependencies ? {} : pickNonRuntime(importer.devDependencies, skipRuntimes),
|
|
6
|
+
optionalDependencies: !include.optionalDependencies ? {} : pickNonRuntime(importer.optionalDependencies, skipRuntimes),
|
|
7
|
+
specifiers: pickNonRuntime(importer.specifiers, skipRuntimes),
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
function pickNonRuntime(deps, skipRuntimes) {
|
|
11
|
+
if (!deps)
|
|
12
|
+
return {};
|
|
13
|
+
if (!skipRuntimes)
|
|
14
|
+
return deps;
|
|
15
|
+
const result = {};
|
|
16
|
+
for (const [name, ref] of Object.entries(deps)) {
|
|
17
|
+
if (!ref.startsWith('runtime:')) {
|
|
18
|
+
result[name] = ref;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return result;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=filterImporter.js.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { LockfileObject } from '@pnpm/lockfile.types';
|
|
2
|
+
import type { DependenciesField, DepPath } from '@pnpm/types';
|
|
3
|
+
export declare function filterLockfile(lockfile: LockfileObject, opts: {
|
|
4
|
+
include: {
|
|
5
|
+
[dependenciesField in DependenciesField]: boolean;
|
|
6
|
+
};
|
|
7
|
+
skipped: Set<DepPath>;
|
|
8
|
+
skipRuntimes?: boolean;
|
|
9
|
+
}): LockfileObject;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { filterLockfileByImporters } from './filterLockfileByImporters.js';
|
|
2
|
+
export function filterLockfile(lockfile, opts) {
|
|
3
|
+
return filterLockfileByImporters(lockfile, Object.keys(lockfile.importers), {
|
|
4
|
+
...opts,
|
|
5
|
+
failOnMissingDependencies: false,
|
|
6
|
+
});
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=filterLockfile.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { LockfileObject } from '@pnpm/lockfile.types';
|
|
2
|
+
import type { DependenciesField, DepPath, ProjectId } from '@pnpm/types';
|
|
3
|
+
export declare function filterLockfileByImporters(lockfile: LockfileObject, importerIds: ProjectId[], opts: {
|
|
4
|
+
include: {
|
|
5
|
+
[dependenciesField in DependenciesField]: boolean;
|
|
6
|
+
};
|
|
7
|
+
skipped: Set<DepPath>;
|
|
8
|
+
skipRuntimes?: boolean;
|
|
9
|
+
failOnMissingDependencies: boolean;
|
|
10
|
+
}): LockfileObject;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { WANTED_LOCKFILE } from '@pnpm/constants';
|
|
2
|
+
import { LockfileMissingDependencyError } from '@pnpm/error';
|
|
3
|
+
import { lockfileWalker } from '@pnpm/lockfile.walker';
|
|
4
|
+
import { logger } from '@pnpm/logger';
|
|
5
|
+
import { filterImporter } from './filterImporter.js';
|
|
6
|
+
const lockfileLogger = logger('lockfile');
|
|
7
|
+
export function filterLockfileByImporters(lockfile, importerIds, opts) {
|
|
8
|
+
const importers = { ...lockfile.importers };
|
|
9
|
+
for (const importerId of importerIds) {
|
|
10
|
+
importers[importerId] = filterImporter(lockfile.importers[importerId], opts.include, { skipRuntimes: opts.skipRuntimes });
|
|
11
|
+
}
|
|
12
|
+
const packages = {};
|
|
13
|
+
if (lockfile.packages != null) {
|
|
14
|
+
pkgAllDeps(lockfileWalker({ ...lockfile, importers }, importerIds, { include: opts.include, skipped: opts.skipped }).step, packages, {
|
|
15
|
+
failOnMissingDependencies: opts.failOnMissingDependencies,
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
return {
|
|
19
|
+
...lockfile,
|
|
20
|
+
importers,
|
|
21
|
+
packages,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function pkgAllDeps(step, pickedPackages, opts) {
|
|
25
|
+
for (const { pkgSnapshot, depPath, next } of step.dependencies) {
|
|
26
|
+
pickedPackages[depPath] = pkgSnapshot;
|
|
27
|
+
pkgAllDeps(next(), pickedPackages, opts);
|
|
28
|
+
}
|
|
29
|
+
for (const depPath of step.missing) {
|
|
30
|
+
if (opts.failOnMissingDependencies) {
|
|
31
|
+
throw new LockfileMissingDependencyError(depPath);
|
|
32
|
+
}
|
|
33
|
+
lockfileLogger.debug(`No entry for "${depPath}" in ${WANTED_LOCKFILE}`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=filterLockfileByImporters.js.map
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { LockfileObject } from '@pnpm/lockfile.types';
|
|
2
|
+
import type { DependenciesField, DepPath, ProjectId, SupportedArchitectures } from '@pnpm/types';
|
|
3
|
+
export interface FilterLockfileResult {
|
|
4
|
+
lockfile: LockfileObject;
|
|
5
|
+
selectedImporterIds: ProjectId[];
|
|
6
|
+
/**
|
|
7
|
+
* Dep paths reached by a non-optional edge from an importer or from a
|
|
8
|
+
* package that is itself part of the install. Their installability is
|
|
9
|
+
* evaluated as non-optional — an incompatible one fails the install under
|
|
10
|
+
* `engineStrict` instead of being skipped — even when the lockfile marks
|
|
11
|
+
* the snapshot `optional: true` because the subtree happens to hang off an
|
|
12
|
+
* optional dependency. Downstream consumers must classify by this set
|
|
13
|
+
* rather than by `pkgSnapshot.optional` so every stage of a headless
|
|
14
|
+
* install agrees with the resolver, which classifies by edge too.
|
|
15
|
+
*/
|
|
16
|
+
requiredDepPaths: Set<DepPath>;
|
|
17
|
+
}
|
|
18
|
+
export declare function filterLockfileByEngine(lockfile: LockfileObject, opts: FilterLockfileOptions): FilterLockfileResult;
|
|
19
|
+
export interface FilterLockfileOptions {
|
|
20
|
+
currentEngine: {
|
|
21
|
+
nodeVersion?: string;
|
|
22
|
+
pnpmVersion: string;
|
|
23
|
+
};
|
|
24
|
+
engineStrict: boolean;
|
|
25
|
+
include: {
|
|
26
|
+
[dependenciesField in DependenciesField]: boolean;
|
|
27
|
+
};
|
|
28
|
+
includeIncompatiblePackages?: boolean;
|
|
29
|
+
failOnMissingDependencies: boolean;
|
|
30
|
+
lockfileDir: string;
|
|
31
|
+
skipped: Set<string>;
|
|
32
|
+
skipRuntimes?: boolean;
|
|
33
|
+
supportedArchitectures?: SupportedArchitectures;
|
|
34
|
+
}
|
|
35
|
+
export declare function filterLockfileByImportersAndEngine(lockfile: LockfileObject, importerIds: ProjectId[], opts: FilterLockfileOptions): FilterLockfileResult;
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import { checkPackageInstallability, packageIsInstallable, } from '@pnpm/config.package-is-installable';
|
|
2
|
+
import { WANTED_LOCKFILE } from '@pnpm/constants';
|
|
3
|
+
import * as dp from '@pnpm/deps.path';
|
|
4
|
+
import { LockfileMissingDependencyError } from '@pnpm/error';
|
|
5
|
+
import { nameVerFromPkgSnapshot } from '@pnpm/lockfile.utils';
|
|
6
|
+
import { logger } from '@pnpm/logger';
|
|
7
|
+
import { map as mapValues, pickBy, unnest } from 'ramda';
|
|
8
|
+
import { filterImporter } from './filterImporter.js';
|
|
9
|
+
const lockfileLogger = logger('lockfile');
|
|
10
|
+
export function filterLockfileByEngine(lockfile, opts) {
|
|
11
|
+
const importerIds = Object.keys(lockfile.importers);
|
|
12
|
+
return filterLockfileByImportersAndEngine(lockfile, importerIds, opts);
|
|
13
|
+
}
|
|
14
|
+
export function filterLockfileByImportersAndEngine(lockfile, importerIds, opts) {
|
|
15
|
+
const importerIdSet = new Set(importerIds);
|
|
16
|
+
const directDepEdges = toImporterDepPaths(lockfile, importerIds, {
|
|
17
|
+
include: opts.include,
|
|
18
|
+
importerIdSet,
|
|
19
|
+
skipRuntimes: opts.skipRuntimes,
|
|
20
|
+
});
|
|
21
|
+
const { packages, requiredDepPaths } = lockfile.packages != null
|
|
22
|
+
? pickPkgsWithAllDeps(lockfile, directDepEdges, importerIdSet, {
|
|
23
|
+
currentEngine: opts.currentEngine,
|
|
24
|
+
engineStrict: opts.engineStrict,
|
|
25
|
+
failOnMissingDependencies: opts.failOnMissingDependencies,
|
|
26
|
+
include: opts.include,
|
|
27
|
+
includeIncompatiblePackages: opts.includeIncompatiblePackages === true,
|
|
28
|
+
lockfileDir: opts.lockfileDir,
|
|
29
|
+
skipped: opts.skipped,
|
|
30
|
+
skipRuntimes: opts.skipRuntimes,
|
|
31
|
+
supportedArchitectures: opts.supportedArchitectures,
|
|
32
|
+
})
|
|
33
|
+
: { packages: {}, requiredDepPaths: new Set() };
|
|
34
|
+
const importers = mapValues((importer) => {
|
|
35
|
+
const newImporter = filterImporter(importer, opts.include, { skipRuntimes: opts.skipRuntimes });
|
|
36
|
+
if (newImporter.optionalDependencies != null) {
|
|
37
|
+
newImporter.optionalDependencies = pickBy((ref, depName) => {
|
|
38
|
+
const depPath = dp.refToRelative(ref, depName);
|
|
39
|
+
return !depPath || packages[depPath] != null;
|
|
40
|
+
}, newImporter.optionalDependencies);
|
|
41
|
+
}
|
|
42
|
+
return newImporter;
|
|
43
|
+
}, lockfile.importers);
|
|
44
|
+
return {
|
|
45
|
+
lockfile: {
|
|
46
|
+
...lockfile,
|
|
47
|
+
importers,
|
|
48
|
+
packages,
|
|
49
|
+
},
|
|
50
|
+
selectedImporterIds: Array.from(importerIdSet),
|
|
51
|
+
requiredDepPaths,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function pickPkgsWithAllDeps(lockfile, depEdges, importerIdSet, opts) {
|
|
55
|
+
const ctx = {
|
|
56
|
+
lockfile,
|
|
57
|
+
pickedPackages: {},
|
|
58
|
+
importerIdSet,
|
|
59
|
+
installed: new Set(),
|
|
60
|
+
requiredDepPaths: new Set(),
|
|
61
|
+
evaluated: [],
|
|
62
|
+
edgesByDepPath: new Map(),
|
|
63
|
+
};
|
|
64
|
+
classifyDeps(ctx, depEdges, opts);
|
|
65
|
+
reportInstallability(ctx, opts);
|
|
66
|
+
pickSkippedDeps(ctx, depEdges, opts);
|
|
67
|
+
return { packages: ctx.pickedPackages, requiredDepPaths: ctx.requiredDepPaths };
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Work out which packages the install actually reaches, and over which kind
|
|
71
|
+
* of edge.
|
|
72
|
+
*
|
|
73
|
+
* An edge is only expanded once its source is known to be part of the
|
|
74
|
+
* install, so the optionality of the edge — not the `optional` flag the
|
|
75
|
+
* resolver propagated onto the snapshot — decides whether an incompatible
|
|
76
|
+
* package is skipped: only a package whose every inbound edge is optional
|
|
77
|
+
* stays out of the install.
|
|
78
|
+
*
|
|
79
|
+
* Traversal is breadth-first over edges rather than depth-first over
|
|
80
|
+
* packages so the verdict does not depend on which edge happens to reach a
|
|
81
|
+
* package first: a package left out on an optional edge is reconsidered when
|
|
82
|
+
* a non-optional one arrives later. Nothing is reported from here — a
|
|
83
|
+
* package can be visited once per inbound edge, and its installability must
|
|
84
|
+
* be reported exactly once, which [reportInstallability] does afterwards.
|
|
85
|
+
*/
|
|
86
|
+
function classifyDeps(ctx, depEdges, opts) {
|
|
87
|
+
const incompatible = new Map();
|
|
88
|
+
// Walked with a cursor rather than `shift()`, which is O(n) per dequeue on
|
|
89
|
+
// a JS array and would make the walk quadratic on a large lockfile.
|
|
90
|
+
const queue = [...depEdges];
|
|
91
|
+
for (let next = 0; next < queue.length; next++) {
|
|
92
|
+
const { depPath, optional } = queue[next];
|
|
93
|
+
if (!optional)
|
|
94
|
+
ctx.requiredDepPaths.add(depPath);
|
|
95
|
+
if (ctx.installed.has(depPath))
|
|
96
|
+
continue;
|
|
97
|
+
const pkgSnapshot = ctx.lockfile.packages[depPath];
|
|
98
|
+
// Missing entries are reported by the closure pass, which reaches every
|
|
99
|
+
// dep path this one does.
|
|
100
|
+
if (!pkgSnapshot)
|
|
101
|
+
continue;
|
|
102
|
+
if (!incompatible.has(depPath)) {
|
|
103
|
+
ctx.evaluated.push(depPath);
|
|
104
|
+
// TODO: depPath is not the package ID. Should be fixed
|
|
105
|
+
incompatible.set(depPath, !opts.includeIncompatiblePackages && checkPackageInstallability(pkgSnapshot.id ?? depPath, toInstallabilityManifest(depPath, pkgSnapshot), {
|
|
106
|
+
nodeVersion: opts.currentEngine.nodeVersion,
|
|
107
|
+
optional: true,
|
|
108
|
+
supportedArchitectures: opts.supportedArchitectures,
|
|
109
|
+
}) != null);
|
|
110
|
+
}
|
|
111
|
+
if (optional && incompatible.get(depPath))
|
|
112
|
+
continue;
|
|
113
|
+
ctx.installed.add(depPath);
|
|
114
|
+
ctx.pickedPackages[depPath] = pkgSnapshot;
|
|
115
|
+
const edges = nextDepEdges(ctx, pkgSnapshot, opts);
|
|
116
|
+
ctx.edgesByDepPath.set(depPath, edges);
|
|
117
|
+
// Appended one by one: `push(...edges)` passes each edge as its own
|
|
118
|
+
// argument and overflows the engine's argument limit on a wide enough
|
|
119
|
+
// dependency list.
|
|
120
|
+
for (const edge of edges) {
|
|
121
|
+
queue.push(edge);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Report each reached package once, against the edge kind it was classified
|
|
127
|
+
* by. This is where an incompatible package that a non-optional edge reaches
|
|
128
|
+
* fails the install under `engineStrict`, and where a skipped optional gets
|
|
129
|
+
* its `skippedOptionalDependencyLogger` entry.
|
|
130
|
+
*/
|
|
131
|
+
function reportInstallability(ctx, opts) {
|
|
132
|
+
for (const depPath of ctx.evaluated) {
|
|
133
|
+
const pkgSnapshot = ctx.lockfile.packages[depPath];
|
|
134
|
+
const installable = opts.includeIncompatiblePackages ||
|
|
135
|
+
packageIsInstallable(pkgSnapshot.id ?? depPath, toInstallabilityManifest(depPath, pkgSnapshot), {
|
|
136
|
+
// A subtree hanging off an `optionalDependencies` entry stays
|
|
137
|
+
// best-effort: the dependency is installed so its dependent is not
|
|
138
|
+
// left broken, but an incompatibility inside it does not fail the
|
|
139
|
+
// install. Only a package no optional path reaches is fatal here.
|
|
140
|
+
engineStrict: opts.engineStrict && pkgSnapshot.optional !== true,
|
|
141
|
+
lockfileDir: opts.lockfileDir,
|
|
142
|
+
nodeVersion: opts.currentEngine.nodeVersion,
|
|
143
|
+
optional: !ctx.installed.has(depPath) || !ctx.requiredDepPaths.has(depPath),
|
|
144
|
+
supportedArchitectures: opts.supportedArchitectures,
|
|
145
|
+
}) !== false;
|
|
146
|
+
if (installable) {
|
|
147
|
+
opts.skipped.delete(depPath);
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
opts.skipped.add(depPath);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
function toInstallabilityManifest(depPath, pkgSnapshot) {
|
|
155
|
+
return {
|
|
156
|
+
...nameVerFromPkgSnapshot(depPath, pkgSnapshot),
|
|
157
|
+
cpu: pkgSnapshot.cpu,
|
|
158
|
+
engines: pkgSnapshot.engines,
|
|
159
|
+
os: pkgSnapshot.os,
|
|
160
|
+
libc: pkgSnapshot.libc,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Extend the picked set over the packages that are reachable but not part of
|
|
165
|
+
* the install — an incompatible optional and everything below it. They stay
|
|
166
|
+
* in the filtered lockfile and are recorded as skipped, so a later install on
|
|
167
|
+
* a host that does support them can pick them up without a re-resolution.
|
|
168
|
+
*/
|
|
169
|
+
function pickSkippedDeps(ctx, depEdges, opts) {
|
|
170
|
+
const queue = depEdges.map(({ depPath }) => depPath);
|
|
171
|
+
const visited = new Set();
|
|
172
|
+
for (let next = 0; next < queue.length; next++) {
|
|
173
|
+
const depPath = queue[next];
|
|
174
|
+
if (visited.has(depPath))
|
|
175
|
+
continue;
|
|
176
|
+
visited.add(depPath);
|
|
177
|
+
const pkgSnapshot = ctx.lockfile.packages[depPath];
|
|
178
|
+
if (!pkgSnapshot && !depPath.startsWith('link:')) {
|
|
179
|
+
if (opts.failOnMissingDependencies) {
|
|
180
|
+
throw new LockfileMissingDependencyError(depPath);
|
|
181
|
+
}
|
|
182
|
+
lockfileLogger.debug(`No entry for "${depPath}" in ${WANTED_LOCKFILE}`);
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
if (!ctx.installed.has(depPath)) {
|
|
186
|
+
if (!ctx.pickedPackages[depPath] && pkgSnapshot.optional === true) {
|
|
187
|
+
opts.skipped.add(depPath);
|
|
188
|
+
}
|
|
189
|
+
ctx.pickedPackages[depPath] = pkgSnapshot;
|
|
190
|
+
}
|
|
191
|
+
// `visited` guarantees one pass per dep path, so a cached entry is
|
|
192
|
+
// released as soon as it is consumed rather than being retained until the
|
|
193
|
+
// whole walk ends.
|
|
194
|
+
const edges = ctx.edgesByDepPath.get(depPath) ?? nextDepEdges(ctx, pkgSnapshot, opts);
|
|
195
|
+
ctx.edgesByDepPath.delete(depPath);
|
|
196
|
+
for (const edge of edges) {
|
|
197
|
+
queue.push(edge.depPath);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
/** The outbound edges of a package, tagged with the optionality of each. */
|
|
202
|
+
function nextDepEdges(ctx, pkgSnapshot, opts) {
|
|
203
|
+
const { depEdges, importerIds } = parseDepRefs([
|
|
204
|
+
...toDepRefs(pkgSnapshot.dependencies, false),
|
|
205
|
+
...(opts.include.optionalDependencies ? toDepRefs(pkgSnapshot.optionalDependencies, true) : []),
|
|
206
|
+
], ctx.lockfile);
|
|
207
|
+
for (const importerId of importerIds) {
|
|
208
|
+
ctx.importerIdSet.add(importerId);
|
|
209
|
+
}
|
|
210
|
+
return [
|
|
211
|
+
...depEdges,
|
|
212
|
+
...toImporterDepPaths(ctx.lockfile, importerIds, {
|
|
213
|
+
include: opts.include,
|
|
214
|
+
importerIdSet: ctx.importerIdSet,
|
|
215
|
+
skipRuntimes: opts.skipRuntimes,
|
|
216
|
+
}),
|
|
217
|
+
];
|
|
218
|
+
}
|
|
219
|
+
function toImporterDepPaths(lockfile, importerIds, opts) {
|
|
220
|
+
const importerDeps = importerIds
|
|
221
|
+
.map(importerId => lockfile.importers[importerId])
|
|
222
|
+
.map(importer => [
|
|
223
|
+
...(opts.include.dependencies ? toDepRefs(importer.dependencies, false) : []),
|
|
224
|
+
...(opts.include.devDependencies ? toDepRefs(importer.devDependencies, false) : []),
|
|
225
|
+
...(opts.include.optionalDependencies ? toDepRefs(importer.optionalDependencies, true) : []),
|
|
226
|
+
])
|
|
227
|
+
.map(refs => opts.skipRuntimes ? refs.filter(({ ref }) => !ref.startsWith('runtime:')) : refs);
|
|
228
|
+
let { depEdges, importerIds: nextImporterIds } = parseDepRefs(unnest(importerDeps), lockfile);
|
|
229
|
+
if (!nextImporterIds.length) {
|
|
230
|
+
return depEdges;
|
|
231
|
+
}
|
|
232
|
+
nextImporterIds = nextImporterIds.filter(importerId => !opts.importerIdSet.has(importerId));
|
|
233
|
+
for (const importerId of nextImporterIds) {
|
|
234
|
+
opts.importerIdSet.add(importerId);
|
|
235
|
+
}
|
|
236
|
+
return [
|
|
237
|
+
...depEdges,
|
|
238
|
+
...toImporterDepPaths(lockfile, nextImporterIds, opts),
|
|
239
|
+
];
|
|
240
|
+
}
|
|
241
|
+
function toDepRefs(refsByPkgNames, optional) {
|
|
242
|
+
if (refsByPkgNames == null)
|
|
243
|
+
return [];
|
|
244
|
+
return Object.entries(refsByPkgNames).map(([pkgName, ref]) => ({ pkgName, ref, optional }));
|
|
245
|
+
}
|
|
246
|
+
function parseDepRefs(depRefs, lockfile) {
|
|
247
|
+
const acc = {
|
|
248
|
+
depEdges: [],
|
|
249
|
+
importerIds: [],
|
|
250
|
+
};
|
|
251
|
+
for (const { pkgName, ref, optional } of depRefs) {
|
|
252
|
+
if (ref.startsWith('link:')) {
|
|
253
|
+
const importerId = ref.substring(5);
|
|
254
|
+
if (lockfile.importers[importerId]) {
|
|
255
|
+
acc.importerIds.push(importerId);
|
|
256
|
+
}
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
259
|
+
const depPath = dp.refToRelative(ref, pkgName);
|
|
260
|
+
if (depPath == null)
|
|
261
|
+
continue;
|
|
262
|
+
acc.depEdges.push({ depPath, optional });
|
|
263
|
+
}
|
|
264
|
+
return acc;
|
|
265
|
+
}
|
|
266
|
+
//# sourceMappingURL=filterLockfileByImportersAndEngine.js.map
|
package/lib/index.d.ts
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pnpm/lockfile.filtering",
|
|
3
|
-
"version": "1100.
|
|
3
|
+
"version": "1100.2.0",
|
|
4
4
|
"description": "Filters a lockfile",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pnpm",
|
|
@@ -29,14 +29,14 @@
|
|
|
29
29
|
"!*.map"
|
|
30
30
|
],
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@pnpm/config.package-is-installable": "1100.0
|
|
33
|
-
"@pnpm/constants": "1100.0.
|
|
34
|
-
"@pnpm/deps.path": "1100.0.
|
|
35
|
-
"@pnpm/error": "1100.0
|
|
36
|
-
"@pnpm/lockfile.types": "1100.0.
|
|
37
|
-
"@pnpm/lockfile.utils": "1100.1.
|
|
38
|
-
"@pnpm/lockfile.walker": "1100.0.
|
|
39
|
-
"@pnpm/types": "1101.
|
|
32
|
+
"@pnpm/config.package-is-installable": "1100.1.0",
|
|
33
|
+
"@pnpm/constants": "1100.0.1",
|
|
34
|
+
"@pnpm/deps.path": "1100.0.12",
|
|
35
|
+
"@pnpm/error": "1100.1.0",
|
|
36
|
+
"@pnpm/lockfile.types": "1100.0.17",
|
|
37
|
+
"@pnpm/lockfile.utils": "1100.1.6",
|
|
38
|
+
"@pnpm/lockfile.walker": "1100.0.17",
|
|
39
|
+
"@pnpm/types": "1101.7.0",
|
|
40
40
|
"ramda": "npm:@pnpm/ramda@0.28.1"
|
|
41
41
|
},
|
|
42
42
|
"peerDependencies": {
|
|
@@ -44,9 +44,9 @@
|
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@jest/globals": "30.4.1",
|
|
47
|
-
"@pnpm/lockfile.filtering": "1100.
|
|
47
|
+
"@pnpm/lockfile.filtering": "1100.2.0",
|
|
48
48
|
"@pnpm/logger": "1100.0.0",
|
|
49
|
-
"@types/ramda": "0.
|
|
49
|
+
"@types/ramda": "0.32.0",
|
|
50
50
|
"detect-libc": "^2.1.2",
|
|
51
51
|
"tempy": "3.0.0",
|
|
52
52
|
"write-yaml-file": "^6.0.0",
|