app-builder-lib 27.0.0-alpha.2 → 27.0.0-alpha.3
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/Framework.d.ts +2 -0
- package/dist/Framework.d.ts.map +1 -1
- package/dist/Framework.js.map +1 -1
- package/dist/asar/asarFileChecker.d.ts +4 -2
- package/dist/asar/asarFileChecker.d.ts.map +1 -1
- package/dist/asar/asarFileChecker.js +2 -3
- package/dist/asar/asarFileChecker.js.map +1 -1
- package/dist/codeSign/certInfo.d.ts +14 -0
- package/dist/codeSign/certInfo.d.ts.map +1 -1
- package/dist/codeSign/certInfo.js +49 -0
- package/dist/codeSign/certInfo.js.map +1 -1
- package/dist/codeSign/mac/macCodeSign.d.ts +3 -3
- package/dist/codeSign/mac/macCodeSign.d.ts.map +1 -1
- package/dist/codeSign/mac/macCodeSign.js +40 -14
- package/dist/codeSign/mac/macCodeSign.js.map +1 -1
- package/dist/codeSign/win/hsmSignManager.d.ts +10 -0
- package/dist/codeSign/win/hsmSignManager.d.ts.map +1 -0
- package/dist/codeSign/win/hsmSignManager.js +50 -0
- package/dist/codeSign/win/hsmSignManager.js.map +1 -0
- package/dist/codeSign/win/pkcs11SignManager.d.ts +14 -0
- package/dist/codeSign/win/pkcs11SignManager.d.ts.map +1 -0
- package/dist/codeSign/win/pkcs11SignManager.js +82 -0
- package/dist/codeSign/win/pkcs11SignManager.js.map +1 -0
- package/dist/codeSign/{signManager.d.ts → win/signManager.d.ts} +8 -6
- package/dist/codeSign/win/signManager.d.ts.map +1 -0
- package/dist/codeSign/win/signManager.js +19 -0
- package/dist/codeSign/win/signManager.js.map +1 -0
- package/dist/codeSign/win/signtoolBaseSignManager.d.ts +71 -0
- package/dist/codeSign/win/signtoolBaseSignManager.d.ts.map +1 -0
- package/dist/codeSign/win/signtoolBaseSignManager.js +407 -0
- package/dist/codeSign/win/signtoolBaseSignManager.js.map +1 -0
- package/dist/codeSign/win/windowsCodeSign.d.ts.map +1 -1
- package/dist/codeSign/win/windowsCodeSign.js +9 -4
- package/dist/codeSign/win/windowsCodeSign.js.map +1 -1
- package/dist/codeSign/win/windowsSignAzureManager.d.ts +9 -3
- package/dist/codeSign/win/windowsSignAzureManager.d.ts.map +1 -1
- package/dist/codeSign/win/windowsSignAzureManager.js +130 -36
- package/dist/codeSign/win/windowsSignAzureManager.js.map +1 -1
- package/dist/codeSign/win/windowsSignToolManager.d.ts +1 -58
- package/dist/codeSign/win/windowsSignToolManager.d.ts.map +1 -1
- package/dist/codeSign/win/windowsSignToolManager.js +3 -363
- package/dist/codeSign/win/windowsSignToolManager.js.map +1 -1
- package/dist/configuration.d.ts +19 -120
- package/dist/configuration.d.ts.map +1 -1
- package/dist/configuration.js.map +1 -1
- package/dist/electron/ElectronFramework.d.ts +0 -2
- package/dist/electron/ElectronFramework.d.ts.map +1 -1
- package/dist/electron/ElectronFramework.js +15 -27
- package/dist/electron/ElectronFramework.js.map +1 -1
- package/dist/electron/injectFFMPEG.js +2 -2
- package/dist/electron/injectFFMPEG.js.map +1 -1
- package/dist/electron/mac/electronMac.js +10 -8
- package/dist/electron/mac/electronMac.js.map +1 -1
- package/dist/electron/win/electronWin.js +1 -2
- package/dist/electron/win/electronWin.js.map +1 -1
- package/dist/index.d.ts +8 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/indexInternal.d.ts +2 -2
- package/dist/indexInternal.d.ts.map +1 -1
- package/dist/indexInternal.js +1 -1
- package/dist/indexInternal.js.map +1 -1
- package/dist/macPackager.d.ts +14 -10
- package/dist/macPackager.d.ts.map +1 -1
- package/dist/macPackager.js +114 -121
- package/dist/macPackager.js.map +1 -1
- package/dist/node-module-collector/moduleManager.d.ts +7 -1
- package/dist/node-module-collector/moduleManager.d.ts.map +1 -1
- package/dist/node-module-collector/moduleManager.js +2 -2
- package/dist/node-module-collector/moduleManager.js.map +1 -1
- package/dist/node-module-collector/nodeModulesCollector.js +1 -1
- package/dist/node-module-collector/nodeModulesCollector.js.map +1 -1
- package/dist/node-module-collector/pnpmNodeModulesCollector.d.ts +48 -1
- package/dist/node-module-collector/pnpmNodeModulesCollector.d.ts.map +1 -1
- package/dist/node-module-collector/pnpmNodeModulesCollector.js +216 -17
- package/dist/node-module-collector/pnpmNodeModulesCollector.js.map +1 -1
- package/dist/options/FuseOptionsV1.d.ts +137 -0
- package/dist/options/FuseOptionsV1.d.ts.map +1 -0
- package/dist/options/FuseOptionsV1.js +2 -0
- package/dist/options/FuseOptionsV1.js.map +1 -0
- package/dist/options/PlatformSpecificBuildOptions.d.ts +1 -1
- package/dist/options/PlatformSpecificBuildOptions.d.ts.map +1 -1
- package/dist/options/PlatformSpecificBuildOptions.js.map +1 -1
- package/dist/options/macOptions.d.ts +93 -126
- package/dist/options/macOptions.d.ts.map +1 -1
- package/dist/options/macOptions.js.map +1 -1
- package/dist/options/winOptions.d.ts +137 -63
- package/dist/options/winOptions.d.ts.map +1 -1
- package/dist/options/winOptions.js +12 -1
- package/dist/options/winOptions.js.map +1 -1
- package/dist/platformPackager.d.ts +4 -2
- package/dist/platformPackager.d.ts.map +1 -1
- package/dist/platformPackager.js +11 -7
- package/dist/platformPackager.js.map +1 -1
- package/dist/targets/ArchiveTarget.js +2 -2
- package/dist/targets/ArchiveTarget.js.map +1 -1
- package/dist/targets/archive.d.ts +10 -2
- package/dist/targets/archive.d.ts.map +1 -1
- package/dist/targets/archive.js +25 -6
- package/dist/targets/archive.js.map +1 -1
- package/dist/targets/linux/snap/core24.d.ts +2 -0
- package/dist/targets/linux/snap/core24.d.ts.map +1 -1
- package/dist/targets/linux/snap/core24.js +48 -8
- package/dist/targets/linux/snap/core24.js.map +1 -1
- package/dist/targets/linux/snap/coreLegacy.d.ts +2 -2
- package/dist/targets/linux/snap/coreLegacy.d.ts.map +1 -1
- package/dist/targets/linux/snap/coreLegacy.js +3 -4
- package/dist/targets/linux/snap/coreLegacy.js.map +1 -1
- package/dist/targets/linux/snap/snapCommand.d.ts +13 -0
- package/dist/targets/linux/snap/snapCommand.d.ts.map +1 -0
- package/dist/targets/linux/snap/snapCommand.js +27 -0
- package/dist/targets/linux/snap/snapCommand.js.map +1 -0
- package/dist/targets/mac/MacTargetHelper.d.ts +12 -12
- package/dist/targets/mac/MacTargetHelper.d.ts.map +1 -1
- package/dist/targets/mac/MacTargetHelper.js +72 -67
- package/dist/targets/mac/MacTargetHelper.js.map +1 -1
- package/dist/targets/mac/pkg.d.ts.map +1 -1
- package/dist/targets/mac/pkg.js +4 -4
- package/dist/targets/mac/pkg.js.map +1 -1
- package/dist/targets/win/AppxTarget.d.ts.map +1 -1
- package/dist/targets/win/AppxTarget.js +4 -4
- package/dist/targets/win/AppxTarget.js.map +1 -1
- package/dist/targets/win/nsis/NsisTarget.js +2 -2
- package/dist/targets/win/nsis/NsisTarget.js.map +1 -1
- package/dist/targets/win/nsis/nsisScriptGenerator.js +1 -1
- package/dist/targets/win/nsis/nsisScriptGenerator.js.map +1 -1
- package/dist/targets/win/nsis/nsisUtil.d.ts.map +1 -1
- package/dist/targets/win/nsis/nsisUtil.js +2 -2
- package/dist/targets/win/nsis/nsisUtil.js.map +1 -1
- package/dist/toolsets/custom.d.ts +1 -0
- package/dist/toolsets/custom.d.ts.map +1 -1
- package/dist/toolsets/custom.js +19 -8
- package/dist/toolsets/custom.js.map +1 -1
- package/dist/toolsets/icons.js +1 -1
- package/dist/toolsets/icons.js.map +1 -1
- package/dist/toolsets/winCodeSign.d.ts +36 -0
- package/dist/toolsets/winCodeSign.d.ts.map +1 -1
- package/dist/toolsets/winCodeSign.js +84 -30
- package/dist/toolsets/winCodeSign.js.map +1 -1
- package/dist/toolsets/wine.d.ts.map +1 -1
- package/dist/toolsets/wine.js +20 -12
- package/dist/toolsets/wine.js.map +1 -1
- package/dist/util/config/schemaValidator.d.ts.map +1 -1
- package/dist/util/config/schemaValidator.js +1 -1
- package/dist/util/config/schemaValidator.js.map +1 -1
- package/dist/util/electronGet.d.ts +8 -25
- package/dist/util/electronGet.d.ts.map +1 -1
- package/dist/util/electronGet.js +107 -87
- package/dist/util/electronGet.js.map +1 -1
- package/dist/util/flags.d.ts +0 -3
- package/dist/util/flags.d.ts.map +1 -1
- package/dist/util/flags.js +0 -9
- package/dist/util/flags.js.map +1 -1
- package/dist/util/license.d.ts.map +1 -1
- package/dist/util/license.js +4 -1
- package/dist/util/license.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/dist/vm/ParallelsVm.d.ts.map +1 -1
- package/dist/vm/ParallelsVm.js +13 -2
- package/dist/vm/ParallelsVm.js.map +1 -1
- package/dist/vm/vm.d.ts.map +1 -1
- package/dist/vm/vm.js +4 -1
- package/dist/vm/vm.js.map +1 -1
- package/dist/winPackager.d.ts +1 -2
- package/dist/winPackager.d.ts.map +1 -1
- package/dist/winPackager.js +17 -22
- package/dist/winPackager.js.map +1 -1
- package/package.json +15 -14
- package/scheme.json +484 -432
- package/dist/codeSign/signManager.d.ts.map +0 -1
- package/dist/codeSign/signManager.js +0 -2
- package/dist/codeSign/signManager.js.map +0 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { Lazy } from "lazy-val";
|
|
1
2
|
import { NodeModulesCollector } from "./nodeModulesCollector.js";
|
|
2
3
|
import { PM } from "./packageManager.js";
|
|
3
|
-
import { PnpmDependency } from "./types.js";
|
|
4
|
+
import type { PnpmDependency } from "./types.js";
|
|
4
5
|
export declare class PnpmNodeModulesCollector extends NodeModulesCollector<PnpmDependency, PnpmDependency> {
|
|
5
6
|
readonly installOptions: {
|
|
6
7
|
manager: PM;
|
|
@@ -9,6 +10,21 @@ export declare class PnpmNodeModulesCollector extends NodeModulesCollector<PnpmD
|
|
|
9
10
|
private _allWorkspacePackages;
|
|
10
11
|
private _pnpmMajorVersion;
|
|
11
12
|
private readonly pnpmVersion;
|
|
13
|
+
/**
|
|
14
|
+
* Detect pnpm's installed layout from the on-disk structure rather than `pnpm config list`.
|
|
15
|
+
* pnpm 11 no longer echoes `node-linker` (from `.npmrc`) in `config list`, so the base-class
|
|
16
|
+
* config-parsing detection silently reports "not hoisted" for a hoisted install, which would
|
|
17
|
+
* disable the downward search needed to find version-conflicted nested deps.
|
|
18
|
+
*
|
|
19
|
+
* In the default isolated store every regular top-level package resolves — through a symlink
|
|
20
|
+
* on POSIX, a junction on Windows — into `node_modules/.pnpm/<name>@<ver>/node_modules/<name>`.
|
|
21
|
+
* In a hoisted layout the same package is a real directory directly under `node_modules`.
|
|
22
|
+
* `realpath` transparently follows both symlinks and junctions, so a layout is isolated iff
|
|
23
|
+
* *any* top-level package's real path routes through `.pnpm`. We scan rather than sample the
|
|
24
|
+
* first entry because `link:` packages resolve to their source (never under `.pnpm`) and could
|
|
25
|
+
* otherwise mask an isolated store.
|
|
26
|
+
*/
|
|
27
|
+
protected isHoisted: Lazy<boolean>;
|
|
12
28
|
/**
|
|
13
29
|
* Memo for `locateFromDepOrRoot`, keyed by `name@version`. pnpm's content-addressed virtual
|
|
14
30
|
* store guarantees that any given `name@version` resolves to a single location on disk, so
|
|
@@ -22,6 +38,9 @@ export declare class PnpmNodeModulesCollector extends NodeModulesCollector<PnpmD
|
|
|
22
38
|
* every shared subtree of the pnpm list output, exploding work in deep workspaces.
|
|
23
39
|
*/
|
|
24
40
|
private readonly collectedDeps;
|
|
41
|
+
/** Reverse index of `allDependencies` keyed by package name (without version). Built once on
|
|
42
|
+
* first access inside `extractProductionDependencyGraph`, after `allDependencies` is settled. */
|
|
43
|
+
private _allDepsByName;
|
|
25
44
|
/**
|
|
26
45
|
* Returns the workspace packages to iterate over, gated by detected pnpm version:
|
|
27
46
|
* - pnpm v11+: multi-entry workspace output → return the full parsed array
|
|
@@ -29,6 +48,7 @@ export declare class PnpmNodeModulesCollector extends NodeModulesCollector<PnpmD
|
|
|
29
48
|
*/
|
|
30
49
|
private get allWorkspacePackages();
|
|
31
50
|
protected getArgs(): string[];
|
|
51
|
+
private getAllDepsByName;
|
|
32
52
|
/**
|
|
33
53
|
* Locate a package version, preferring the dep's own reported path before falling back to rootDir.
|
|
34
54
|
* This is critical for pnpm non-hoisted (virtual store) setups where each package has its own
|
|
@@ -38,7 +58,34 @@ export declare class PnpmNodeModulesCollector extends NodeModulesCollector<PnpmD
|
|
|
38
58
|
private locateFromDepOrRoot;
|
|
39
59
|
protected extractProductionDependencyGraph(tree: PnpmDependency, dependencyId: string): Promise<void>;
|
|
40
60
|
protected collectAllDependencies(_tree: PnpmDependency, _appPackageName: string): Promise<void>;
|
|
61
|
+
/**
|
|
62
|
+
* Resolve a `link:` dependency to its real on-disk source directory — never the `node_modules`
|
|
63
|
+
* junction pnpm creates for it. Returns null for non-link deps.
|
|
64
|
+
*
|
|
65
|
+
* Why this matters: resolving a link: dep through `node_modules` (locateFromDepOrRoot) yields the
|
|
66
|
+
* junction, which CI cannot read across drives. CI checks out the repo on `D:` but installs the
|
|
67
|
+
* app under `C:\…\Temp`, so the junction is a cross-volume link that `realpath`/`stat` fail on,
|
|
68
|
+
* silently dropping the package from the asar. The link target is a plain directory that reads
|
|
69
|
+
* fine from any drive, so we resolve straight to it.
|
|
70
|
+
*/
|
|
71
|
+
private resolveLinkTarget;
|
|
72
|
+
private readPackageJsonAt;
|
|
73
|
+
/**
|
|
74
|
+
* Visit a single dependency node, adding it and its transitive deps to allDependencies.
|
|
75
|
+
*
|
|
76
|
+
* For packages that pnpm list did NOT expand (link: packages and the synthetic entries
|
|
77
|
+
* derived from them), the tree has empty dependencies/optionalDependencies. In that case
|
|
78
|
+
* we fall back to the on-disk package.json to discover transitive deps, resolving each one
|
|
79
|
+
* from the package's own node_modules first (where pnpm placed them).
|
|
80
|
+
*/
|
|
81
|
+
private visitDep;
|
|
41
82
|
private collectDepsRecursively;
|
|
83
|
+
/**
|
|
84
|
+
* pnpm excludes link: packages from `pnpm list --prod` output. Read the app's package.json
|
|
85
|
+
* directly to find any link: deps that were silently omitted and visit them so their
|
|
86
|
+
* transitive deps end up in allDependencies.
|
|
87
|
+
*/
|
|
88
|
+
private collectOmittedLinkPackages;
|
|
42
89
|
protected getTreeFromWorkspaces(tree: PnpmDependency, packageName: string): PnpmDependency;
|
|
43
90
|
protected parseDependenciesTree(jsonBlob: string): Promise<PnpmDependency>;
|
|
44
91
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pnpmNodeModulesCollector.d.ts","sourceRoot":"","sources":["../../src/node-module-collector/pnpmNodeModulesCollector.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"pnpmNodeModulesCollector.d.ts","sourceRoot":"","sources":["../../src/node-module-collector/pnpmNodeModulesCollector.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAA;AAG/B,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAA;AAChE,OAAO,EAA4B,EAAE,EAAE,MAAM,qBAAqB,CAAA;AAClE,OAAO,KAAK,EAAe,cAAc,EAAE,MAAM,YAAY,CAAA;AAG7D,qBAAa,wBAAyB,SAAQ,oBAAoB,CAAC,cAAc,EAAE,cAAc,CAAC;IAChG,SAAgB,cAAc;;;MAG7B;IAGD,OAAO,CAAC,qBAAqB,CAAuB;IAEpD,OAAO,CAAC,iBAAiB,CAAI;IAE7B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAI1B;IAEF;;;;;;;;;;;;;OAaG;IACH,UAAmB,SAAS,gBAwB1B;IAEF;;;;;;OAMG;IACH,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAkD;IAE7E;;;OAGG;IACH,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAyB;IAEvD;sGACkG;IAClG,OAAO,CAAC,cAAc,CAA2C;IAEjE;;;;OAIG;IACH,OAAO,KAAK,oBAAoB,GAK/B;IAED,SAAS,CAAC,OAAO,IAAI,MAAM,EAAE;IAI7B,OAAO,CAAC,gBAAgB;IAaxB;;;;;OAKG;YACW,mBAAmB;cAwDjB,gCAAgC,CAAC,IAAI,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM;cAyE3E,sBAAsB,CAAC,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASrG;;;;;;;;;OASG;IACH,OAAO,CAAC,iBAAiB;YAkBX,iBAAiB;IAK/B;;;;;;;OAOG;YACW,QAAQ;YA+CR,sBAAsB;IASpC;;;;OAIG;YACW,0BAA0B;cA+BrB,qBAAqB,CAAC,IAAI,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,GAAG,cAAc;cAYnF,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;CAMjF"}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import _fsExtra from "fs-extra";
|
|
1
2
|
import { Lazy } from "lazy-val";
|
|
3
|
+
import * as path from "path";
|
|
2
4
|
import { LogMessageByKey } from "./moduleManager.js";
|
|
3
5
|
import { NodeModulesCollector } from "./nodeModulesCollector.js";
|
|
4
6
|
import { getPackageManagerCommand, PM } from "./packageManager.js";
|
|
7
|
+
import { isValidKey } from "builder-util";
|
|
5
8
|
export class PnpmNodeModulesCollector extends NodeModulesCollector {
|
|
6
9
|
constructor() {
|
|
7
10
|
super(...arguments);
|
|
@@ -19,6 +22,45 @@ export class PnpmNodeModulesCollector extends NodeModulesCollector {
|
|
|
19
22
|
const major = parseInt((result.stdout ?? "0").split(".")[0], 10);
|
|
20
23
|
return isNaN(major) ? 0 : major;
|
|
21
24
|
});
|
|
25
|
+
/**
|
|
26
|
+
* Detect pnpm's installed layout from the on-disk structure rather than `pnpm config list`.
|
|
27
|
+
* pnpm 11 no longer echoes `node-linker` (from `.npmrc`) in `config list`, so the base-class
|
|
28
|
+
* config-parsing detection silently reports "not hoisted" for a hoisted install, which would
|
|
29
|
+
* disable the downward search needed to find version-conflicted nested deps.
|
|
30
|
+
*
|
|
31
|
+
* In the default isolated store every regular top-level package resolves — through a symlink
|
|
32
|
+
* on POSIX, a junction on Windows — into `node_modules/.pnpm/<name>@<ver>/node_modules/<name>`.
|
|
33
|
+
* In a hoisted layout the same package is a real directory directly under `node_modules`.
|
|
34
|
+
* `realpath` transparently follows both symlinks and junctions, so a layout is isolated iff
|
|
35
|
+
* *any* top-level package's real path routes through `.pnpm`. We scan rather than sample the
|
|
36
|
+
* first entry because `link:` packages resolve to their source (never under `.pnpm`) and could
|
|
37
|
+
* otherwise mask an isolated store.
|
|
38
|
+
*/
|
|
39
|
+
this.isHoisted = new Lazy(async () => {
|
|
40
|
+
const nmDir = path.join(this.rootDir, "node_modules");
|
|
41
|
+
const entries = await _fsExtra.readdir(nmDir).catch(() => []);
|
|
42
|
+
let sawPackage = false;
|
|
43
|
+
for (const name of entries) {
|
|
44
|
+
if (name.startsWith(".")) {
|
|
45
|
+
continue; // .pnpm, .bin, .modules.yaml
|
|
46
|
+
}
|
|
47
|
+
const entryPath = path.join(nmDir, name);
|
|
48
|
+
// A scoped dir (@scope) is not a package itself; descend to its packages.
|
|
49
|
+
const candidates = name.startsWith("@") ? (await _fsExtra.readdir(entryPath).catch(() => [])).map(s => path.join(entryPath, s)) : [entryPath];
|
|
50
|
+
for (const candidate of candidates) {
|
|
51
|
+
const real = await _fsExtra.realpath(candidate).catch(() => null);
|
|
52
|
+
if (real == null) {
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
sawPackage = true;
|
|
56
|
+
if (real.split(path.sep).includes(".pnpm")) {
|
|
57
|
+
return false; // isolated store: a package routes through the virtual store
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// Packages exist and none route through `.pnpm` → hoisted. No packages → flat default.
|
|
62
|
+
return sawPackage;
|
|
63
|
+
});
|
|
22
64
|
/**
|
|
23
65
|
* Memo for `locateFromDepOrRoot`, keyed by `name@version`. pnpm's content-addressed virtual
|
|
24
66
|
* store guarantees that any given `name@version` resolves to a single location on disk, so
|
|
@@ -32,6 +74,9 @@ export class PnpmNodeModulesCollector extends NodeModulesCollector {
|
|
|
32
74
|
* every shared subtree of the pnpm list output, exploding work in deep workspaces.
|
|
33
75
|
*/
|
|
34
76
|
this.collectedDeps = new Set();
|
|
77
|
+
/** Reverse index of `allDependencies` keyed by package name (without version). Built once on
|
|
78
|
+
* first access inside `extractProductionDependencyGraph`, after `allDependencies` is settled. */
|
|
79
|
+
this._allDepsByName = null;
|
|
35
80
|
}
|
|
36
81
|
/**
|
|
37
82
|
* Returns the workspace packages to iterate over, gated by detected pnpm version:
|
|
@@ -47,6 +92,18 @@ export class PnpmNodeModulesCollector extends NodeModulesCollector {
|
|
|
47
92
|
getArgs() {
|
|
48
93
|
return ["list", "--prod", "--json", "--depth", "Infinity", "--silent", "--loglevel=error"];
|
|
49
94
|
}
|
|
95
|
+
getAllDepsByName() {
|
|
96
|
+
if (!this._allDepsByName) {
|
|
97
|
+
this._allDepsByName = new Map();
|
|
98
|
+
for (const [id, dep] of this.allDependencies.entries()) {
|
|
99
|
+
const { name } = this.parseNameVersion(id);
|
|
100
|
+
if (!this._allDepsByName.has(name)) {
|
|
101
|
+
this._allDepsByName.set(name, dep);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return this._allDepsByName;
|
|
106
|
+
}
|
|
50
107
|
/**
|
|
51
108
|
* Locate a package version, preferring the dep's own reported path before falling back to rootDir.
|
|
52
109
|
* This is critical for pnpm non-hoisted (virtual store) setups where each package has its own
|
|
@@ -72,6 +129,24 @@ export class PnpmNodeModulesCollector extends NodeModulesCollector {
|
|
|
72
129
|
// land at `<root>/node_modules/A/node_modules/B` — downward BFS is needed to find them.
|
|
73
130
|
const skipDownwardSearch = !(await this.isHoisted.value);
|
|
74
131
|
const promise = (async () => {
|
|
132
|
+
// Phase 1: find a version that SATISFIES requiredRange, trying the dep's own location
|
|
133
|
+
// first, then the workspace root. Crucially, neither pass accepts an out-of-range override
|
|
134
|
+
// here — so a wrong-version copy reachable via upward search from `parentPath` (e.g. a
|
|
135
|
+
// hoisted top-level dep) can't shadow the correct nested copy under root. Without this, a
|
|
136
|
+
// package that pnpm deduped to a peer's node_modules resolves its transitive deps to the
|
|
137
|
+
// wrong hoisted version (see jsonfile under two fs-extra majors). The root pass uses the
|
|
138
|
+
// same `skipDownwardSearch` as everywhere else: in a hoisted layout it is already false, so
|
|
139
|
+
// the nested `<root>/node_modules/A/node_modules/B` copy is found via BFS; in the flat
|
|
140
|
+
// `.pnpm` virtual store it stays true (forcing it on there would burn thousands of
|
|
141
|
+
// readdir/lstat calls — and on Windows, where pnpm uses junctions that `lstat` reports as
|
|
142
|
+
// directories, the BFS walks the entire store and resolves the wrong paths).
|
|
143
|
+
const satisfying = (parentPath ? await this.cache.locatePackageVersion({ pkgName, parentDir: parentPath, requiredRange, skipDownwardSearch, skipOverrideFallback: true }) : null) ??
|
|
144
|
+
(await this.cache.locatePackageVersion({ pkgName, parentDir: this.rootDir, requiredRange, skipDownwardSearch, skipOverrideFallback: true }));
|
|
145
|
+
if (satisfying) {
|
|
146
|
+
return satisfying;
|
|
147
|
+
}
|
|
148
|
+
// Phase 2: no version satisfies requiredRange (package-manager override, or no range
|
|
149
|
+
// given). Fall back to the original dep-then-root order, now allowing override versions.
|
|
75
150
|
const fromDep = parentPath ? await this.cache.locatePackageVersion({ pkgName, parentDir: parentPath, requiredRange, skipDownwardSearch }) : null;
|
|
76
151
|
if (fromDep) {
|
|
77
152
|
return fromDep;
|
|
@@ -104,10 +179,27 @@ export class PnpmNodeModulesCollector extends NodeModulesCollector {
|
|
|
104
179
|
}
|
|
105
180
|
}
|
|
106
181
|
const packageName = tree.name || tree.from;
|
|
107
|
-
const { packageJson } = (await this.locateFromDepOrRoot(packageName, tree.path, tree.version)) || {};
|
|
182
|
+
const { packageJson: locatedJson } = (await this.locateFromDepOrRoot(packageName, tree.path, tree.version)) || {};
|
|
183
|
+
// Fallback: the app root package is never installed inside a node_modules directory, so
|
|
184
|
+
// the name-based lookup above returns null. Reading directly from tree.path ensures that
|
|
185
|
+
// link: dependencies — which some pnpm versions omit from `pnpm list --prod` output —
|
|
186
|
+
// still appear in `all` and therefore reach the production graph.
|
|
187
|
+
const packageJson = locatedJson ?? (tree.path ? (await _fsExtra.readJson(path.join(tree.path, "package.json")).catch(() => null)) : null);
|
|
108
188
|
const all = packageJson ? { ...packageJson.dependencies, ...packageJson.optionalDependencies } : { ...tree.dependencies, ...tree.optionalDependencies };
|
|
109
189
|
const optional = packageJson ? { ...packageJson.optionalDependencies } : {};
|
|
110
190
|
const deps = { ...(tree.dependencies || {}), ...(tree.optionalDependencies || {}) };
|
|
191
|
+
// pnpm --prod omits sub-deps for link: packages (and synthetic entries derived from them).
|
|
192
|
+
// For any dep declared in the package.json (all) that pnpm left out of the tree, recover
|
|
193
|
+
// the resolved entry from allDependencies so it lands in the production graph.
|
|
194
|
+
const byName = this.getAllDepsByName();
|
|
195
|
+
for (const depName of Object.keys(all)) {
|
|
196
|
+
if (!deps[depName]) {
|
|
197
|
+
const dep = byName.get(depName);
|
|
198
|
+
if (dep && isValidKey(depName)) {
|
|
199
|
+
deps[depName] = dep;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
111
203
|
this.productionGraph[dependencyId] = { dependencies: [] };
|
|
112
204
|
const depPromises = Object.entries(deps).map(async ([packageName, dependency]) => {
|
|
113
205
|
// First check if it's in production dependencies
|
|
@@ -139,28 +231,135 @@ export class PnpmNodeModulesCollector extends NodeModulesCollector {
|
|
|
139
231
|
for (const root of this.allWorkspacePackages) {
|
|
140
232
|
await this.collectDepsRecursively(root);
|
|
141
233
|
}
|
|
234
|
+
// pnpm --prod omits link: packages from its JSON output entirely; pick them up from the
|
|
235
|
+
// app's package.json so their transitive deps are included in allDependencies.
|
|
236
|
+
await this.collectOmittedLinkPackages();
|
|
142
237
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
238
|
+
/**
|
|
239
|
+
* Resolve a `link:` dependency to its real on-disk source directory — never the `node_modules`
|
|
240
|
+
* junction pnpm creates for it. Returns null for non-link deps.
|
|
241
|
+
*
|
|
242
|
+
* Why this matters: resolving a link: dep through `node_modules` (locateFromDepOrRoot) yields the
|
|
243
|
+
* junction, which CI cannot read across drives. CI checks out the repo on `D:` but installs the
|
|
244
|
+
* app under `C:\…\Temp`, so the junction is a cross-volume link that `realpath`/`stat` fail on,
|
|
245
|
+
* silently dropping the package from the asar. The link target is a plain directory that reads
|
|
246
|
+
* fine from any drive, so we resolve straight to it.
|
|
247
|
+
*/
|
|
248
|
+
resolveLinkTarget(value) {
|
|
249
|
+
const version = value.version;
|
|
250
|
+
if (typeof version !== "string" || !version.startsWith("link:")) {
|
|
251
|
+
return null;
|
|
252
|
+
}
|
|
253
|
+
const spec = version.slice("link:".length);
|
|
254
|
+
// A cross-drive link cannot be expressed relative, so pnpm reports it as an absolute path —
|
|
255
|
+
// use it directly. Otherwise prefer pnpm's already-resolved absolute `path` (the source dir,
|
|
256
|
+
// never the junction), falling back to resolving the relative spec against the workspace root.
|
|
257
|
+
if (path.isAbsolute(spec)) {
|
|
258
|
+
return path.normalize(spec);
|
|
259
|
+
}
|
|
260
|
+
if (value.path && path.isAbsolute(value.path)) {
|
|
261
|
+
return path.normalize(value.path);
|
|
262
|
+
}
|
|
263
|
+
return path.resolve(this.rootDir, spec);
|
|
264
|
+
}
|
|
265
|
+
async readPackageJsonAt(dir) {
|
|
266
|
+
const packageJson = (await _fsExtra.readJson(path.join(dir, "package.json")).catch(() => null));
|
|
267
|
+
return packageJson ? { packageDir: dir, packageJson } : null;
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Visit a single dependency node, adding it and its transitive deps to allDependencies.
|
|
271
|
+
*
|
|
272
|
+
* For packages that pnpm list did NOT expand (link: packages and the synthetic entries
|
|
273
|
+
* derived from them), the tree has empty dependencies/optionalDependencies. In that case
|
|
274
|
+
* we fall back to the on-disk package.json to discover transitive deps, resolving each one
|
|
275
|
+
* from the package's own node_modules first (where pnpm placed them).
|
|
276
|
+
*/
|
|
277
|
+
async visitDep(key, value) {
|
|
278
|
+
const id = `${key}@${value.version}`;
|
|
279
|
+
// The pnpm list output can include the same `name@version` thousands of times across a
|
|
280
|
+
// deep workspace; without this guard we re-resolve and re-recurse each occurrence.
|
|
281
|
+
if (this.collectedDeps.has(id)) {
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
this.collectedDeps.add(id);
|
|
285
|
+
const located = await this.locateFromDepOrRoot(key, value.path, value.version);
|
|
286
|
+
// For a link: dep, store the real source dir (the link target) rather than the located path,
|
|
287
|
+
// which is the node_modules junction. Across drives that junction is unreadable (see
|
|
288
|
+
// resolveLinkTarget), so storing it makes the package vanish from the asar.
|
|
289
|
+
const linkTarget = this.resolveLinkTarget(value);
|
|
290
|
+
const resolvedPath = linkTarget ?? located?.packageDir ?? value.path;
|
|
291
|
+
this.allDependencies.set(id, { ...value, path: resolvedPath });
|
|
292
|
+
// For transitive-dep discovery of entries pnpm did not expand (link: packages), use the
|
|
293
|
+
// located package.json; fall back to the link target's own package.json when the junction
|
|
294
|
+
// could not be resolved (again, the cross-drive case).
|
|
295
|
+
const pkg = located ?? (linkTarget != null ? await this.readPackageJsonAt(linkTarget) : null);
|
|
296
|
+
const hasTreeDeps = Object.keys(value.dependencies ?? {}).length > 0 || Object.keys(value.optionalDependencies ?? {}).length > 0;
|
|
297
|
+
if (!hasTreeDeps && pkg?.packageJson) {
|
|
298
|
+
// pnpm list omits sub-deps for link: packages and for entries where the reported path
|
|
299
|
+
// doesn't expand transitive deps (e.g. a link: package's nested dep). Use the on-disk
|
|
300
|
+
// package.json to discover what to include, and pass the declared version range so that
|
|
301
|
+
// resolution skips wrong-version hoisted packages and finds the correct nested copy.
|
|
302
|
+
const pkgDepsDecl = { ...(pkg.packageJson.dependencies || {}), ...(pkg.packageJson.optionalDependencies || {}) };
|
|
303
|
+
for (const [depName, depRange] of Object.entries(pkgDepsDecl)) {
|
|
304
|
+
const resolved = await this.locateFromDepOrRoot(depName, pkg.packageDir, typeof depRange === "string" ? depRange : undefined);
|
|
305
|
+
if (!resolved) {
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
await this.visitDep(depName, {
|
|
309
|
+
from: depName,
|
|
310
|
+
name: depName,
|
|
311
|
+
version: resolved.packageJson.version,
|
|
312
|
+
path: resolved.packageDir,
|
|
313
|
+
dependencies: {},
|
|
314
|
+
optionalDependencies: {},
|
|
315
|
+
});
|
|
153
316
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
this.allDependencies.set(id, { ...value, path: pkg?.packageDir ?? value.path });
|
|
317
|
+
}
|
|
318
|
+
else {
|
|
157
319
|
await this.collectDepsRecursively(value);
|
|
158
|
-
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
async collectDepsRecursively(tree) {
|
|
159
323
|
for (const [key, value] of Object.entries(tree.dependencies || {})) {
|
|
160
|
-
await
|
|
324
|
+
await this.visitDep(key, value);
|
|
161
325
|
}
|
|
162
326
|
for (const [key, value] of Object.entries(tree.optionalDependencies || {})) {
|
|
163
|
-
await
|
|
327
|
+
await this.visitDep(key, value);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* pnpm excludes link: packages from `pnpm list --prod` output. Read the app's package.json
|
|
332
|
+
* directly to find any link: deps that were silently omitted and visit them so their
|
|
333
|
+
* transitive deps end up in allDependencies.
|
|
334
|
+
*/
|
|
335
|
+
async collectOmittedLinkPackages() {
|
|
336
|
+
const appPkgJson = (await _fsExtra.readJson(path.join(this.rootDir, "package.json")).catch(() => null));
|
|
337
|
+
if (!appPkgJson) {
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
const allDeps = { ...(appPkgJson.dependencies || {}), ...(appPkgJson.optionalDependencies || {}) };
|
|
341
|
+
for (const [name, version] of Object.entries(allDeps)) {
|
|
342
|
+
if (typeof version !== "string" || !version.startsWith("link:")) {
|
|
343
|
+
continue;
|
|
344
|
+
}
|
|
345
|
+
// Resolve the link: target path directly — bypasses potentially broken cross-drive
|
|
346
|
+
// Windows junctions (C:→D:) that locateFromDepOrRoot would traverse through
|
|
347
|
+
// node_modules and silently fail on (readJson returns null via .catch).
|
|
348
|
+
const linkRelPath = version.slice("link:".length);
|
|
349
|
+
const linkTarget = path.isAbsolute(linkRelPath) ? linkRelPath : path.resolve(this.rootDir, linkRelPath);
|
|
350
|
+
const directPkg = (await _fsExtra.readJson(path.join(linkTarget, "package.json")).catch(() => null));
|
|
351
|
+
const resolved = directPkg ? { packageDir: linkTarget, packageJson: directPkg } : await this.locateFromDepOrRoot(name, this.rootDir, undefined);
|
|
352
|
+
if (!resolved) {
|
|
353
|
+
continue;
|
|
354
|
+
}
|
|
355
|
+
await this.visitDep(name, {
|
|
356
|
+
from: name,
|
|
357
|
+
name,
|
|
358
|
+
version: resolved.packageJson.version,
|
|
359
|
+
path: resolved.packageDir,
|
|
360
|
+
dependencies: {},
|
|
361
|
+
optionalDependencies: {},
|
|
362
|
+
});
|
|
164
363
|
}
|
|
165
364
|
}
|
|
166
365
|
getTreeFromWorkspaces(tree, packageName) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pnpmNodeModulesCollector.js","sourceRoot":"","sources":["../../src/node-module-collector/pnpmNodeModulesCollector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAA;AAC/B,OAAO,EAAE,eAAe,EAAgB,MAAM,oBAAoB,CAAA;AAClE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAA;AAChE,OAAO,EAAE,wBAAwB,EAAE,EAAE,EAAE,MAAM,qBAAqB,CAAA;AAGlE,MAAM,OAAO,wBAAyB,SAAQ,oBAAoD;IAAlG;;QACkB,mBAAc,GAAG;YAC/B,OAAO,EAAE,EAAE,CAAC,IAAI;YAChB,QAAQ,EAAE,gBAAgB;SAC3B,CAAA;QAED,0DAA0D;QAClD,0BAAqB,GAAqB,EAAE,CAAA;QACpD,4FAA4F;QACpF,sBAAiB,GAAG,CAAC,CAAA;QAC7B,iEAAiE;QAChD,gBAAW,GAAG,IAAI,IAAI,CAAS,KAAK,IAAI,EAAE;YACzD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,wBAAwB,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAA;YACrF,MAAM,KAAK,GAAG,QAAQ,CAAC,CAAC,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;YAChE,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAA;QACjC,CAAC,CAAC,CAAA;QAEF;;;;;;WAMG;QACc,eAAU,GAAyC,IAAI,GAAG,EAAE,CAAA;QAE7E;;;WAGG;QACc,kBAAa,GAAgB,IAAI,GAAG,EAAE,CAAA;IAoKzD,CAAC;IAlKC;;;;OAIG;IACH,IAAY,oBAAoB;QAC9B,IAAI,IAAI,CAAC,iBAAiB,IAAI,EAAE,EAAE,CAAC;YACjC,OAAO,IAAI,CAAC,qBAAqB,CAAA;QACnC,CAAC;QACD,OAAO,IAAI,CAAC,qBAAqB,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;IAC/C,CAAC;IAES,OAAO;QACf,OAAO,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,kBAAkB,CAAC,CAAA;IAC5F,CAAC;IAED;;;;;OAKG;IACK,KAAK,CAAC,mBAAmB,CAAC,OAAe,EAAE,UAA8B,EAAE,aAAsB;QACvG,2FAA2F;QAC3F,4FAA4F;QAC5F,yFAAyF;QACzF,yFAAyF;QACzF,sFAAsF;QACtF,MAAM,OAAO,GAAG,aAAa,IAAI,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,IAAI,aAAa,EAAE,CAAC,CAAC,CAAC,IAAI,CAAA;QACjG,IAAI,OAAO,IAAI,IAAI,EAAE,CAAC;YACpB,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;YAC3C,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;gBACnB,OAAO,MAAM,CAAA;YACf,CAAC;QACH,CAAC;QAED,yFAAyF;QACzF,uFAAuF;QACvF,uFAAuF;QACvF,wFAAwF;QACxF,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAA;QACxD,MAAM,OAAO,GAAG,CAAC,KAAK,IAA6B,EAAE;YACnD,MAAM,OAAO,GAAG,UAAU,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,oBAAoB,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,aAAa,EAAE,kBAAkB,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;YAChJ,IAAI,OAAO,EAAE,CAAC;gBACZ,OAAO,OAAO,CAAA;YAChB,CAAC;YACD,OAAO,IAAI,CAAC,KAAK,CAAC,oBAAoB,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,CAAC,CAAA;QACjH,CAAC,CAAC,EAAE,CAAA;QAEJ,IAAI,OAAO,IAAI,IAAI,EAAE,CAAC;YACpB,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;QACvC,CAAC;QACD,OAAO,OAAO,CAAA;IAChB,CAAC;IAED,iFAAiF;IACjF,+EAA+E;IAC/E,6EAA6E;IAC7E,mEAAmE;IACzD,KAAK,CAAC,gCAAgC,CAAC,IAAoB,EAAE,YAAoB;QACzF,IAAI,IAAI,CAAC,eAAe,CAAC,YAAY,CAAC,EAAE,CAAC;YACvC,OAAM;QACR,CAAC;QACD,IAAI,CAAC,eAAe,CAAC,YAAY,CAAC,GAAG,EAAE,YAAY,EAAE,EAAE,EAAE,CAAA;QAEzD,IAAI,CAAC,IAAI,CAAC,wBAAwB,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;YAC7C,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,YAAY,CAAC,CAAA;YACtD,IAAI,OAAO,EAAE,CAAC;gBACZ,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,eAAe,CAAC,iBAAiB,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAA;gBAC3E,IAAI,GAAG,OAAO,CAAA;YAChB,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,eAAe,CAAC,4BAA4B,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAA;gBACtF,OAAM;YACR,CAAC;QACH,CAAC;QAED,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,CAAA;QAC1C,MAAM,EAAE,WAAW,EAAE,GAAG,CAAC,MAAM,IAAI,CAAC,mBAAmB,CAAC,WAAW,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAA;QAEpG,MAAM,GAAG,GAAG,WAAW,CAAC,CAAC,CAAC,EAAE,GAAG,WAAW,CAAC,YAAY,EAAE,GAAG,WAAW,CAAC,oBAAoB,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,YAAY,EAAE,GAAG,IAAI,CAAC,oBAAoB,EAAE,CAAA;QACvJ,MAAM,QAAQ,GAAG,WAAW,CAAC,CAAC,CAAC,EAAE,GAAG,WAAW,CAAC,oBAAoB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;QAE3E,MAAM,IAAI,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,YAAY,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC,oBAAoB,IAAI,EAAE,CAAC,EAAE,CAAA;QACnF,IAAI,CAAC,eAAe,CAAC,YAAY,CAAC,GAAG,EAAE,YAAY,EAAE,EAAE,EAAE,CAAA;QACzD,MAAM,WAAW,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,WAAW,EAAE,UAAU,CAAC,EAAE,EAAE;YAC/E,iDAAiD;YACjD,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;gBACtB,OAAO,SAAS,CAAA;YAClB,CAAC;YAED,6EAA6E;YAC7E,IAAI,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;gBAC1B,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAAC,WAAW,EAAE,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,OAAO,CAAC,CAAA;gBACtF,IAAI,CAAC,GAAG,EAAE,CAAC;oBACT,IAAI,CAAC,oBAAoB,CAAC,GAAG,WAAW,IAAI,UAAU,CAAC,OAAO,EAAE,CAAC,CAAA;oBACjE,OAAO,SAAS,CAAA;gBAClB,CAAC;YACH,CAAC;YACD,MAAM,EAAE,EAAE,EAAE,iBAAiB,EAAE,WAAW,EAAE,GAAG,IAAI,CAAC,uBAAuB,CAAC,WAAW,EAAE,UAAU,CAAC,CAAA;YACpG,MAAM,IAAI,CAAC,gCAAgC,CAAC,WAAW,EAAE,iBAAiB,CAAC,CAAA;YAC3E,OAAO,iBAAiB,CAAA;QAC1B,CAAC,CAAC,CAAA;QAEF,MAAM,qBAAqB,GAAa,EAAE,CAAA;QAC1C,KAAK,MAAM,GAAG,IAAI,WAAW,EAAE,CAAC;YAC9B,MAAM,MAAM,GAAG,MAAM,GAAG,CAAA;YACxB,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;gBACzB,qBAAqB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;YACpC,CAAC;QACH,CAAC;QACD,IAAI,CAAC,eAAe,CAAC,YAAY,CAAC,GAAG,EAAE,YAAY,EAAE,qBAAqB,EAAE,CAAA;IAC9E,CAAC;IAES,KAAK,CAAC,sBAAsB,CAAC,KAAqB,EAAE,eAAuB;QACnF,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,oBAAoB,EAAE,CAAC;YAC7C,MAAM,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,CAAA;QACzC,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,sBAAsB,CAAC,IAAoB;QACvD,MAAM,KAAK,GAAG,KAAK,EAAE,GAAW,EAAE,KAAqB,EAAE,EAAE;YACzD,IAAI,CAAC,KAAK,EAAE,wBAAwB,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC/C,OAAM;YACR,CAAC;YACD,MAAM,EAAE,GAAG,GAAG,GAAG,IAAI,KAAK,CAAC,OAAO,EAAE,CAAA;YACpC,uFAAuF;YACvF,mFAAmF;YACnF,IAAI,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;gBAC/B,OAAM;YACR,CAAC;YACD,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;YAC1B,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,CAAA;YAC1E,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,GAAG,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,UAAU,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,CAAA;YAC/E,MAAM,IAAI,CAAC,sBAAsB,CAAC,KAAK,CAAC,CAAA;QAC1C,CAAC,CAAA;QAED,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,YAAY,IAAI,EAAE,CAAC,EAAE,CAAC;YACnE,MAAM,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;QACzB,CAAC;QACD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,oBAAoB,IAAI,EAAE,CAAC,EAAE,CAAC;YAC3E,MAAM,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;QACzB,CAAC;IACH,CAAC;IAEkB,qBAAqB,CAAC,IAAoB,EAAE,WAAmB;QAChF,oFAAoF;QACpF,MAAM,MAAM,GAAG,KAAK,CAAC,qBAAqB,CAAC,IAAI,EAAE,WAAW,CAAC,CAAA;QAC7D,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YACpB,OAAO,MAAM,CAAA;QACf,CAAC;QACD,kFAAkF;QAClF,4FAA4F;QAC5F,MAAM,KAAK,GAAG,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,KAAK,WAAW,IAAI,GAAG,CAAC,IAAI,KAAK,WAAW,CAAC,CAAA;QACzG,OAAO,KAAK,IAAI,IAAI,CAAA;IACtB,CAAC;IAES,KAAK,CAAC,qBAAqB,CAAC,QAAgB;QACpD,MAAM,cAAc,GAAG,IAAI,CAAC,6BAA6B,CAAmB,QAAQ,CAAC,CAAA;QACrF,IAAI,CAAC,qBAAqB,GAAG,cAAc,CAAA;QAC3C,IAAI,CAAC,iBAAiB,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,KAAK,CAAA;QACrD,OAAO,cAAc,CAAC,CAAC,CAAC,CAAA;IAC1B,CAAC;CACF","sourcesContent":["import { Lazy } from \"lazy-val\"\nimport { LogMessageByKey, type Package } from \"./moduleManager.js\"\nimport { NodeModulesCollector } from \"./nodeModulesCollector.js\"\nimport { getPackageManagerCommand, PM } from \"./packageManager.js\"\nimport { PnpmDependency } from \"./types.js\"\n\nexport class PnpmNodeModulesCollector extends NodeModulesCollector<PnpmDependency, PnpmDependency> {\n public readonly installOptions = {\n manager: PM.PNPM,\n lockfile: \"pnpm-lock.yaml\",\n }\n\n // Raw backing field — all entries from `pnpm list --json`\n private _allWorkspacePackages: PnpmDependency[] = []\n // Cached after parseDependenciesTree resolves the Lazy; 0 = safe default (treated as < v11)\n private _pnpmMajorVersion = 0\n // Runs `pnpm --version` once and caches the major version number\n private readonly pnpmVersion = new Lazy<number>(async () => {\n const result = await this.asyncExec(getPackageManagerCommand(PM.PNPM), [\"--version\"])\n const major = parseInt((result.stdout ?? \"0\").split(\".\")[0], 10)\n return isNaN(major) ? 0 : major\n })\n\n /**\n * Memo for `locateFromDepOrRoot`, keyed by `name@version`. pnpm's content-addressed virtual\n * store guarantees that any given `name@version` resolves to a single location on disk, so\n * once we've resolved a package we can short-circuit every subsequent lookup. This is the\n * dominant speedup for large workspaces where the `pnpm list --json` tree contains the same\n * `name@version` thousands of times (one entry per dependent).\n */\n private readonly locateMemo: Map<string, Promise<Package | null>> = new Map()\n\n /**\n * Visited set for `collectDepsRecursively`, keyed by `name@version`. Without this we re-walk\n * every shared subtree of the pnpm list output, exploding work in deep workspaces.\n */\n private readonly collectedDeps: Set<string> = new Set()\n\n /**\n * Returns the workspace packages to iterate over, gated by detected pnpm version:\n * - pnpm v11+: multi-entry workspace output → return the full parsed array\n * - pnpm < v11 / non-workspace / detection failure: single-tree behavior → return only [0]\n */\n private get allWorkspacePackages(): PnpmDependency[] {\n if (this._pnpmMajorVersion >= 11) {\n return this._allWorkspacePackages\n }\n return this._allWorkspacePackages.slice(0, 1)\n }\n\n protected getArgs(): string[] {\n return [\"list\", \"--prod\", \"--json\", \"--depth\", \"Infinity\", \"--silent\", \"--loglevel=error\"]\n }\n\n /**\n * Locate a package version, preferring the dep's own reported path before falling back to rootDir.\n * This is critical for pnpm non-hoisted (virtual store) setups where each package has its own\n * nested node_modules. Searching only from rootDir can resolve the wrong version when multiple\n * versions of a dep exist in the workspace.\n */\n private async locateFromDepOrRoot(pkgName: string, parentPath: string | undefined, requiredRange?: string) {\n // pnpm's virtual store is content-addressed: every `name@version` lookup is deterministic,\n // so memoize on the exact version. `requiredRange` is normally an exact version coming from\n // the pnpm list output (e.g. `value.version`), which makes this cache hit on duplicates.\n // Only memoize when we have a concrete version — semver ranges could resolve differently\n // depending on what's installed at `parentPath` vs root, so skip the cache for those.\n const memoKey = requiredRange && /^\\d/.test(requiredRange) ? `${pkgName}@${requiredRange}` : null\n if (memoKey != null) {\n const cached = this.locateMemo.get(memoKey)\n if (cached != null) {\n return cached\n }\n }\n\n // pnpm's default `.pnpm` virtual store is flat, so `downwardSearch` would burn thousands\n // of `readdir`/`lstat` calls finding nothing. With `nodeLinker: hoisted`, however, the\n // layout is a traditional nested `node_modules` tree where version-conflicted packages\n // land at `<root>/node_modules/A/node_modules/B` — downward BFS is needed to find them.\n const skipDownwardSearch = !(await this.isHoisted.value)\n const promise = (async (): Promise<Package | null> => {\n const fromDep = parentPath ? await this.cache.locatePackageVersion({ pkgName, parentDir: parentPath, requiredRange, skipDownwardSearch }) : null\n if (fromDep) {\n return fromDep\n }\n return this.cache.locatePackageVersion({ pkgName, parentDir: this.rootDir, requiredRange, skipDownwardSearch })\n })()\n\n if (memoKey != null) {\n this.locateMemo.set(memoKey, promise)\n }\n return promise\n }\n\n // pnpm 10+ does not automatically preserve transitive optional platform-specific\n // packages (e.g. sass-embedded-linux-x64) across lock file regeneration. Users\n // must list them as direct optionalDependencies. Missing ones are emitted as\n // PKG_OPTIONAL_PLATFORM_NOT_INSTALLED warnings in the log summary.\n protected async extractProductionDependencyGraph(tree: PnpmDependency, dependencyId: string) {\n if (this.productionGraph[dependencyId]) {\n return\n }\n this.productionGraph[dependencyId] = { dependencies: [] }\n\n if ((tree.dedupedDependenciesCount ?? 0) > 0) {\n const realDep = this.allDependencies.get(dependencyId)\n if (realDep) {\n this.cache.logSummary[LogMessageByKey.PKG_DUPLICATE_REF].push(dependencyId)\n tree = realDep\n } else {\n this.cache.logSummary[LogMessageByKey.PKG_DUPLICATE_REF_UNRESOLVED].push(dependencyId)\n return\n }\n }\n\n const packageName = tree.name || tree.from\n const { packageJson } = (await this.locateFromDepOrRoot(packageName, tree.path, tree.version)) || {}\n\n const all = packageJson ? { ...packageJson.dependencies, ...packageJson.optionalDependencies } : { ...tree.dependencies, ...tree.optionalDependencies }\n const optional = packageJson ? { ...packageJson.optionalDependencies } : {}\n\n const deps = { ...(tree.dependencies || {}), ...(tree.optionalDependencies || {}) }\n this.productionGraph[dependencyId] = { dependencies: [] }\n const depPromises = Object.entries(deps).map(async ([packageName, dependency]) => {\n // First check if it's in production dependencies\n if (!all[packageName]) {\n return undefined\n }\n\n // Then check if optional dependency path exists (using actual resolved path)\n if (optional[packageName]) {\n const pkg = await this.locateFromDepOrRoot(packageName, tree.path, dependency.version)\n if (!pkg) {\n this.logMissingDependency(`${packageName}@${dependency.version}`)\n return undefined\n }\n }\n const { id: childDependencyId, pkgOverride } = this.normalizePackageVersion(packageName, dependency)\n await this.extractProductionDependencyGraph(pkgOverride, childDependencyId)\n return childDependencyId\n })\n\n const collectedDependencies: string[] = []\n for (const dep of depPromises) {\n const result = await dep\n if (result !== undefined) {\n collectedDependencies.push(result)\n }\n }\n this.productionGraph[dependencyId] = { dependencies: collectedDependencies }\n }\n\n protected async collectAllDependencies(_tree: PnpmDependency, _appPackageName: string): Promise<void> {\n for (const root of this.allWorkspacePackages) {\n await this.collectDepsRecursively(root)\n }\n }\n\n private async collectDepsRecursively(tree: PnpmDependency): Promise<void> {\n const visit = async (key: string, value: PnpmDependency) => {\n if ((value?.dedupedDependenciesCount ?? 0) > 0) {\n return\n }\n const id = `${key}@${value.version}`\n // The pnpm list output can include the same `name@version` thousands of times across a\n // deep workspace; without this guard we re-resolve and re-recurse each occurrence.\n if (this.collectedDeps.has(id)) {\n return\n }\n this.collectedDeps.add(id)\n const pkg = await this.locateFromDepOrRoot(key, value.path, value.version)\n this.allDependencies.set(id, { ...value, path: pkg?.packageDir ?? value.path })\n await this.collectDepsRecursively(value)\n }\n\n for (const [key, value] of Object.entries(tree.dependencies || {})) {\n await visit(key, value)\n }\n for (const [key, value] of Object.entries(tree.optionalDependencies || {})) {\n await visit(key, value)\n }\n }\n\n protected override getTreeFromWorkspaces(tree: PnpmDependency, packageName: string): PnpmDependency {\n // pnpm v10 workspace: app is nested as a dependency of root — handled by base class\n const result = super.getTreeFromWorkspaces(tree, packageName)\n if (result !== tree) {\n return result\n }\n // pnpm v11 workspace: each workspace package is a separate top-level array entry;\n // non-workspace (single-tree): find returns the one entry or undefined → falls back to tree\n const match = this.allWorkspacePackages.find(pkg => pkg.name === packageName || pkg.from === packageName)\n return match ?? tree\n }\n\n protected async parseDependenciesTree(jsonBlob: string): Promise<PnpmDependency> {\n const dependencyTree = this.extractJsonFromPollutedOutput<PnpmDependency[]>(jsonBlob)\n this._allWorkspacePackages = dependencyTree\n this._pnpmMajorVersion = await this.pnpmVersion.value\n return dependencyTree[0]\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"pnpmNodeModulesCollector.js","sourceRoot":"","sources":["../../src/node-module-collector/pnpmNodeModulesCollector.ts"],"names":[],"mappings":"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","sourcesContent":["import _fsExtra from \"fs-extra\"\nimport { Lazy } from \"lazy-val\"\nimport * as path from \"path\"\nimport { LogMessageByKey, type Package } from \"./moduleManager.js\"\nimport { NodeModulesCollector } from \"./nodeModulesCollector.js\"\nimport { getPackageManagerCommand, PM } from \"./packageManager.js\"\nimport type { PackageJson, PnpmDependency } from \"./types.js\"\nimport { isValidKey } from \"builder-util\"\n\nexport class PnpmNodeModulesCollector extends NodeModulesCollector<PnpmDependency, PnpmDependency> {\n public readonly installOptions = {\n manager: PM.PNPM,\n lockfile: \"pnpm-lock.yaml\",\n }\n\n // Raw backing field — all entries from `pnpm list --json`\n private _allWorkspacePackages: PnpmDependency[] = []\n // Cached after parseDependenciesTree resolves the Lazy; 0 = safe default (treated as < v11)\n private _pnpmMajorVersion = 0\n // Runs `pnpm --version` once and caches the major version number\n private readonly pnpmVersion = new Lazy<number>(async () => {\n const result = await this.asyncExec(getPackageManagerCommand(PM.PNPM), [\"--version\"])\n const major = parseInt((result.stdout ?? \"0\").split(\".\")[0], 10)\n return isNaN(major) ? 0 : major\n })\n\n /**\n * Detect pnpm's installed layout from the on-disk structure rather than `pnpm config list`.\n * pnpm 11 no longer echoes `node-linker` (from `.npmrc`) in `config list`, so the base-class\n * config-parsing detection silently reports \"not hoisted\" for a hoisted install, which would\n * disable the downward search needed to find version-conflicted nested deps.\n *\n * In the default isolated store every regular top-level package resolves — through a symlink\n * on POSIX, a junction on Windows — into `node_modules/.pnpm/<name>@<ver>/node_modules/<name>`.\n * In a hoisted layout the same package is a real directory directly under `node_modules`.\n * `realpath` transparently follows both symlinks and junctions, so a layout is isolated iff\n * *any* top-level package's real path routes through `.pnpm`. We scan rather than sample the\n * first entry because `link:` packages resolve to their source (never under `.pnpm`) and could\n * otherwise mask an isolated store.\n */\n protected override isHoisted = new Lazy<boolean>(async () => {\n const nmDir = path.join(this.rootDir, \"node_modules\")\n const entries = await _fsExtra.readdir(nmDir).catch(() => [] as string[])\n let sawPackage = false\n for (const name of entries) {\n if (name.startsWith(\".\")) {\n continue // .pnpm, .bin, .modules.yaml\n }\n const entryPath = path.join(nmDir, name)\n // A scoped dir (@scope) is not a package itself; descend to its packages.\n const candidates = name.startsWith(\"@\") ? (await _fsExtra.readdir(entryPath).catch(() => [] as string[])).map(s => path.join(entryPath, s)) : [entryPath]\n for (const candidate of candidates) {\n const real = await _fsExtra.realpath(candidate).catch(() => null)\n if (real == null) {\n continue\n }\n sawPackage = true\n if (real.split(path.sep).includes(\".pnpm\")) {\n return false // isolated store: a package routes through the virtual store\n }\n }\n }\n // Packages exist and none route through `.pnpm` → hoisted. No packages → flat default.\n return sawPackage\n })\n\n /**\n * Memo for `locateFromDepOrRoot`, keyed by `name@version`. pnpm's content-addressed virtual\n * store guarantees that any given `name@version` resolves to a single location on disk, so\n * once we've resolved a package we can short-circuit every subsequent lookup. This is the\n * dominant speedup for large workspaces where the `pnpm list --json` tree contains the same\n * `name@version` thousands of times (one entry per dependent).\n */\n private readonly locateMemo: Map<string, Promise<Package | null>> = new Map()\n\n /**\n * Visited set for `collectDepsRecursively`, keyed by `name@version`. Without this we re-walk\n * every shared subtree of the pnpm list output, exploding work in deep workspaces.\n */\n private readonly collectedDeps: Set<string> = new Set()\n\n /** Reverse index of `allDependencies` keyed by package name (without version). Built once on\n * first access inside `extractProductionDependencyGraph`, after `allDependencies` is settled. */\n private _allDepsByName: Map<string, PnpmDependency> | null = null\n\n /**\n * Returns the workspace packages to iterate over, gated by detected pnpm version:\n * - pnpm v11+: multi-entry workspace output → return the full parsed array\n * - pnpm < v11 / non-workspace / detection failure: single-tree behavior → return only [0]\n */\n private get allWorkspacePackages(): PnpmDependency[] {\n if (this._pnpmMajorVersion >= 11) {\n return this._allWorkspacePackages\n }\n return this._allWorkspacePackages.slice(0, 1)\n }\n\n protected getArgs(): string[] {\n return [\"list\", \"--prod\", \"--json\", \"--depth\", \"Infinity\", \"--silent\", \"--loglevel=error\"]\n }\n\n private getAllDepsByName(): Map<string, PnpmDependency> {\n if (!this._allDepsByName) {\n this._allDepsByName = new Map()\n for (const [id, dep] of this.allDependencies.entries()) {\n const { name } = this.parseNameVersion(id)\n if (!this._allDepsByName.has(name)) {\n this._allDepsByName.set(name, dep)\n }\n }\n }\n return this._allDepsByName\n }\n\n /**\n * Locate a package version, preferring the dep's own reported path before falling back to rootDir.\n * This is critical for pnpm non-hoisted (virtual store) setups where each package has its own\n * nested node_modules. Searching only from rootDir can resolve the wrong version when multiple\n * versions of a dep exist in the workspace.\n */\n private async locateFromDepOrRoot(pkgName: string, parentPath: string | undefined, requiredRange?: string) {\n // pnpm's virtual store is content-addressed: every `name@version` lookup is deterministic,\n // so memoize on the exact version. `requiredRange` is normally an exact version coming from\n // the pnpm list output (e.g. `value.version`), which makes this cache hit on duplicates.\n // Only memoize when we have a concrete version — semver ranges could resolve differently\n // depending on what's installed at `parentPath` vs root, so skip the cache for those.\n const memoKey = requiredRange && /^\\d/.test(requiredRange) ? `${pkgName}@${requiredRange}` : null\n if (memoKey != null) {\n const cached = this.locateMemo.get(memoKey)\n if (cached != null) {\n return cached\n }\n }\n\n // pnpm's default `.pnpm` virtual store is flat, so `downwardSearch` would burn thousands\n // of `readdir`/`lstat` calls finding nothing. With `nodeLinker: hoisted`, however, the\n // layout is a traditional nested `node_modules` tree where version-conflicted packages\n // land at `<root>/node_modules/A/node_modules/B` — downward BFS is needed to find them.\n const skipDownwardSearch = !(await this.isHoisted.value)\n const promise = (async (): Promise<Package | null> => {\n // Phase 1: find a version that SATISFIES requiredRange, trying the dep's own location\n // first, then the workspace root. Crucially, neither pass accepts an out-of-range override\n // here — so a wrong-version copy reachable via upward search from `parentPath` (e.g. a\n // hoisted top-level dep) can't shadow the correct nested copy under root. Without this, a\n // package that pnpm deduped to a peer's node_modules resolves its transitive deps to the\n // wrong hoisted version (see jsonfile under two fs-extra majors). The root pass uses the\n // same `skipDownwardSearch` as everywhere else: in a hoisted layout it is already false, so\n // the nested `<root>/node_modules/A/node_modules/B` copy is found via BFS; in the flat\n // `.pnpm` virtual store it stays true (forcing it on there would burn thousands of\n // readdir/lstat calls — and on Windows, where pnpm uses junctions that `lstat` reports as\n // directories, the BFS walks the entire store and resolves the wrong paths).\n const satisfying =\n (parentPath ? await this.cache.locatePackageVersion({ pkgName, parentDir: parentPath, requiredRange, skipDownwardSearch, skipOverrideFallback: true }) : null) ??\n (await this.cache.locatePackageVersion({ pkgName, parentDir: this.rootDir, requiredRange, skipDownwardSearch, skipOverrideFallback: true }))\n if (satisfying) {\n return satisfying\n }\n // Phase 2: no version satisfies requiredRange (package-manager override, or no range\n // given). Fall back to the original dep-then-root order, now allowing override versions.\n const fromDep = parentPath ? await this.cache.locatePackageVersion({ pkgName, parentDir: parentPath, requiredRange, skipDownwardSearch }) : null\n if (fromDep) {\n return fromDep\n }\n return this.cache.locatePackageVersion({ pkgName, parentDir: this.rootDir, requiredRange, skipDownwardSearch })\n })()\n\n if (memoKey != null) {\n this.locateMemo.set(memoKey, promise)\n }\n return promise\n }\n\n // pnpm 10+ does not automatically preserve transitive optional platform-specific\n // packages (e.g. sass-embedded-linux-x64) across lock file regeneration. Users\n // must list them as direct optionalDependencies. Missing ones are emitted as\n // PKG_OPTIONAL_PLATFORM_NOT_INSTALLED warnings in the log summary.\n protected async extractProductionDependencyGraph(tree: PnpmDependency, dependencyId: string) {\n if (this.productionGraph[dependencyId]) {\n return\n }\n this.productionGraph[dependencyId] = { dependencies: [] }\n\n if ((tree.dedupedDependenciesCount ?? 0) > 0) {\n const realDep = this.allDependencies.get(dependencyId)\n if (realDep) {\n this.cache.logSummary[LogMessageByKey.PKG_DUPLICATE_REF].push(dependencyId)\n tree = realDep\n } else {\n this.cache.logSummary[LogMessageByKey.PKG_DUPLICATE_REF_UNRESOLVED].push(dependencyId)\n return\n }\n }\n\n const packageName = tree.name || tree.from\n const { packageJson: locatedJson } = (await this.locateFromDepOrRoot(packageName, tree.path, tree.version)) || {}\n // Fallback: the app root package is never installed inside a node_modules directory, so\n // the name-based lookup above returns null. Reading directly from tree.path ensures that\n // link: dependencies — which some pnpm versions omit from `pnpm list --prod` output —\n // still appear in `all` and therefore reach the production graph.\n const packageJson = locatedJson ?? (tree.path ? ((await _fsExtra.readJson(path.join(tree.path, \"package.json\")).catch(() => null)) as PackageJson | null) : null)\n\n const all = packageJson ? { ...packageJson.dependencies, ...packageJson.optionalDependencies } : { ...tree.dependencies, ...tree.optionalDependencies }\n const optional = packageJson ? { ...packageJson.optionalDependencies } : {}\n\n const deps: Record<string, PnpmDependency> = { ...(tree.dependencies || {}), ...(tree.optionalDependencies || {}) }\n\n // pnpm --prod omits sub-deps for link: packages (and synthetic entries derived from them).\n // For any dep declared in the package.json (all) that pnpm left out of the tree, recover\n // the resolved entry from allDependencies so it lands in the production graph.\n const byName = this.getAllDepsByName()\n for (const depName of Object.keys(all)) {\n if (!deps[depName]) {\n const dep = byName.get(depName)\n if (dep && isValidKey(depName)) {\n deps[depName] = dep\n }\n }\n }\n\n this.productionGraph[dependencyId] = { dependencies: [] }\n const depPromises = Object.entries(deps).map(async ([packageName, dependency]) => {\n // First check if it's in production dependencies\n if (!all[packageName]) {\n return undefined\n }\n\n // Then check if optional dependency path exists (using actual resolved path)\n if (optional[packageName]) {\n const pkg = await this.locateFromDepOrRoot(packageName, tree.path, dependency.version)\n if (!pkg) {\n this.logMissingDependency(`${packageName}@${dependency.version}`)\n return undefined\n }\n }\n const { id: childDependencyId, pkgOverride } = this.normalizePackageVersion(packageName, dependency)\n await this.extractProductionDependencyGraph(pkgOverride, childDependencyId)\n return childDependencyId\n })\n\n const collectedDependencies: string[] = []\n for (const dep of depPromises) {\n const result = await dep\n if (result !== undefined) {\n collectedDependencies.push(result)\n }\n }\n this.productionGraph[dependencyId] = { dependencies: collectedDependencies }\n }\n\n protected async collectAllDependencies(_tree: PnpmDependency, _appPackageName: string): Promise<void> {\n for (const root of this.allWorkspacePackages) {\n await this.collectDepsRecursively(root)\n }\n // pnpm --prod omits link: packages from its JSON output entirely; pick them up from the\n // app's package.json so their transitive deps are included in allDependencies.\n await this.collectOmittedLinkPackages()\n }\n\n /**\n * Resolve a `link:` dependency to its real on-disk source directory — never the `node_modules`\n * junction pnpm creates for it. Returns null for non-link deps.\n *\n * Why this matters: resolving a link: dep through `node_modules` (locateFromDepOrRoot) yields the\n * junction, which CI cannot read across drives. CI checks out the repo on `D:` but installs the\n * app under `C:\\…\\Temp`, so the junction is a cross-volume link that `realpath`/`stat` fail on,\n * silently dropping the package from the asar. The link target is a plain directory that reads\n * fine from any drive, so we resolve straight to it.\n */\n private resolveLinkTarget(value: PnpmDependency): string | null {\n const version = value.version\n if (typeof version !== \"string\" || !version.startsWith(\"link:\")) {\n return null\n }\n const spec = version.slice(\"link:\".length)\n // A cross-drive link cannot be expressed relative, so pnpm reports it as an absolute path —\n // use it directly. Otherwise prefer pnpm's already-resolved absolute `path` (the source dir,\n // never the junction), falling back to resolving the relative spec against the workspace root.\n if (path.isAbsolute(spec)) {\n return path.normalize(spec)\n }\n if (value.path && path.isAbsolute(value.path)) {\n return path.normalize(value.path)\n }\n return path.resolve(this.rootDir, spec)\n }\n\n private async readPackageJsonAt(dir: string): Promise<Package | null> {\n const packageJson = (await _fsExtra.readJson(path.join(dir, \"package.json\")).catch(() => null)) as PackageJson | null\n return packageJson ? { packageDir: dir, packageJson } : null\n }\n\n /**\n * Visit a single dependency node, adding it and its transitive deps to allDependencies.\n *\n * For packages that pnpm list did NOT expand (link: packages and the synthetic entries\n * derived from them), the tree has empty dependencies/optionalDependencies. In that case\n * we fall back to the on-disk package.json to discover transitive deps, resolving each one\n * from the package's own node_modules first (where pnpm placed them).\n */\n private async visitDep(key: string, value: PnpmDependency): Promise<void> {\n const id = `${key}@${value.version}`\n // The pnpm list output can include the same `name@version` thousands of times across a\n // deep workspace; without this guard we re-resolve and re-recurse each occurrence.\n if (this.collectedDeps.has(id)) {\n return\n }\n this.collectedDeps.add(id)\n\n const located = await this.locateFromDepOrRoot(key, value.path, value.version)\n // For a link: dep, store the real source dir (the link target) rather than the located path,\n // which is the node_modules junction. Across drives that junction is unreadable (see\n // resolveLinkTarget), so storing it makes the package vanish from the asar.\n const linkTarget = this.resolveLinkTarget(value)\n const resolvedPath = linkTarget ?? located?.packageDir ?? value.path\n this.allDependencies.set(id, { ...value, path: resolvedPath })\n\n // For transitive-dep discovery of entries pnpm did not expand (link: packages), use the\n // located package.json; fall back to the link target's own package.json when the junction\n // could not be resolved (again, the cross-drive case).\n const pkg = located ?? (linkTarget != null ? await this.readPackageJsonAt(linkTarget) : null)\n const hasTreeDeps = Object.keys(value.dependencies ?? {}).length > 0 || Object.keys(value.optionalDependencies ?? {}).length > 0\n if (!hasTreeDeps && pkg?.packageJson) {\n // pnpm list omits sub-deps for link: packages and for entries where the reported path\n // doesn't expand transitive deps (e.g. a link: package's nested dep). Use the on-disk\n // package.json to discover what to include, and pass the declared version range so that\n // resolution skips wrong-version hoisted packages and finds the correct nested copy.\n const pkgDepsDecl = { ...(pkg.packageJson.dependencies || {}), ...(pkg.packageJson.optionalDependencies || {}) }\n for (const [depName, depRange] of Object.entries(pkgDepsDecl)) {\n const resolved = await this.locateFromDepOrRoot(depName, pkg.packageDir, typeof depRange === \"string\" ? depRange : undefined)\n if (!resolved) {\n continue\n }\n await this.visitDep(depName, {\n from: depName,\n name: depName,\n version: resolved.packageJson.version,\n path: resolved.packageDir,\n dependencies: {},\n optionalDependencies: {},\n } as unknown as PnpmDependency)\n }\n } else {\n await this.collectDepsRecursively(value)\n }\n }\n\n private async collectDepsRecursively(tree: PnpmDependency): Promise<void> {\n for (const [key, value] of Object.entries(tree.dependencies || {})) {\n await this.visitDep(key, value)\n }\n for (const [key, value] of Object.entries(tree.optionalDependencies || {})) {\n await this.visitDep(key, value)\n }\n }\n\n /**\n * pnpm excludes link: packages from `pnpm list --prod` output. Read the app's package.json\n * directly to find any link: deps that were silently omitted and visit them so their\n * transitive deps end up in allDependencies.\n */\n private async collectOmittedLinkPackages(): Promise<void> {\n const appPkgJson = (await _fsExtra.readJson(path.join(this.rootDir, \"package.json\")).catch(() => null)) as PackageJson | null\n if (!appPkgJson) {\n return\n }\n const allDeps = { ...(appPkgJson.dependencies || {}), ...(appPkgJson.optionalDependencies || {}) }\n for (const [name, version] of Object.entries(allDeps)) {\n if (typeof version !== \"string\" || !version.startsWith(\"link:\")) {\n continue\n }\n // Resolve the link: target path directly — bypasses potentially broken cross-drive\n // Windows junctions (C:→D:) that locateFromDepOrRoot would traverse through\n // node_modules and silently fail on (readJson returns null via .catch).\n const linkRelPath = version.slice(\"link:\".length)\n const linkTarget = path.isAbsolute(linkRelPath) ? linkRelPath : path.resolve(this.rootDir, linkRelPath)\n const directPkg = (await _fsExtra.readJson(path.join(linkTarget, \"package.json\")).catch(() => null)) as PackageJson | null\n const resolved = directPkg ? { packageDir: linkTarget, packageJson: directPkg } : await this.locateFromDepOrRoot(name, this.rootDir, undefined)\n if (!resolved) {\n continue\n }\n await this.visitDep(name, {\n from: name,\n name,\n version: resolved.packageJson.version,\n path: resolved.packageDir,\n dependencies: {},\n optionalDependencies: {},\n } as unknown as PnpmDependency)\n }\n }\n\n protected override getTreeFromWorkspaces(tree: PnpmDependency, packageName: string): PnpmDependency {\n // pnpm v10 workspace: app is nested as a dependency of root — handled by base class\n const result = super.getTreeFromWorkspaces(tree, packageName)\n if (result !== tree) {\n return result\n }\n // pnpm v11 workspace: each workspace package is a separate top-level array entry;\n // non-workspace (single-tree): find returns the one entry or undefined → falls back to tree\n const match = this.allWorkspacePackages.find(pkg => pkg.name === packageName || pkg.from === packageName)\n return match ?? tree\n }\n\n protected async parseDependenciesTree(jsonBlob: string): Promise<PnpmDependency> {\n const dependencyTree = this.extractJsonFromPollutedOutput<PnpmDependency[]>(jsonBlob)\n this._allWorkspacePackages = dependencyTree\n this._pnpmMajorVersion = await this.pnpmVersion.value\n return dependencyTree[0]\n }\n}\n"]}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import type { FuseV1Options } from "@electron/fuses";
|
|
2
|
+
/**
|
|
3
|
+
* Feature flags ("fuses") baked into the Electron binary at build time.
|
|
4
|
+
*
|
|
5
|
+
* All options map 1:1 to the flags documented by
|
|
6
|
+
* [`@electron/fuses`](https://github.com/electron/fuses) and the upstream
|
|
7
|
+
* [Electron fuses guide](https://www.electronjs.org/docs/latest/tutorial/fuses).
|
|
8
|
+
*
|
|
9
|
+
* electron-builder flips fuses after packaging and **before** signing so that the final
|
|
10
|
+
* code signature covers the modified binary. On Apple Silicon, the ad-hoc signature is
|
|
11
|
+
* re-applied automatically after flipping fuses.
|
|
12
|
+
*/
|
|
13
|
+
export interface FuseOptionsV1 extends Partial<Record<Uncapitalize<keyof typeof FuseV1Options>, boolean>> {
|
|
14
|
+
/**
|
|
15
|
+
* Controls whether the `ELECTRON_RUN_AS_NODE` environment variable is respected.
|
|
16
|
+
*
|
|
17
|
+
* When `true` (the Electron default), setting `ELECTRON_RUN_AS_NODE=1` in the environment
|
|
18
|
+
* makes Electron behave like a plain Node.js process, bypassing the app entirely. Disable
|
|
19
|
+
* this fuse in production apps to prevent that escape path.
|
|
20
|
+
*
|
|
21
|
+
* **Note:** Disabling this fuse also breaks `process.fork()` in the main process because
|
|
22
|
+
* it relies on `ELECTRON_RUN_AS_NODE` internally. Use
|
|
23
|
+
* [Utility Processes](https://www.electronjs.org/docs/latest/api/utility-process) as a
|
|
24
|
+
* replacement.
|
|
25
|
+
*
|
|
26
|
+
* @see https://github.com/electron/fuses
|
|
27
|
+
*/
|
|
28
|
+
runAsNode?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Controls whether the Chromium cookie store is encrypted using OS-level cryptography keys.
|
|
31
|
+
*
|
|
32
|
+
* When enabled, cookies are stored encrypted on disk (the same mechanism Chrome uses).
|
|
33
|
+
* **This is a one-way transition**: existing unencrypted cookies are re-encrypted on write, but
|
|
34
|
+
* disabling the fuse afterwards will leave the cookie database unreadable.
|
|
35
|
+
*
|
|
36
|
+
* Most production apps can safely enable this fuse.
|
|
37
|
+
*
|
|
38
|
+
* @see https://github.com/electron/fuses
|
|
39
|
+
*/
|
|
40
|
+
enableCookieEncryption?: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Controls whether the [`NODE_OPTIONS`](https://nodejs.org/api/cli.html#node_optionsoptions)
|
|
43
|
+
* and `NODE_EXTRA_CA_CERTS` environment variables are respected.
|
|
44
|
+
*
|
|
45
|
+
* `NODE_OPTIONS` allows injecting arbitrary Node.js runtime flags (e.g. `--require`) and is
|
|
46
|
+
* rarely needed in production. Most apps can safely disable this fuse.
|
|
47
|
+
*
|
|
48
|
+
* @see https://github.com/electron/fuses
|
|
49
|
+
*/
|
|
50
|
+
enableNodeOptionsEnvironmentVariable?: boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Controls whether the `--inspect`, `--inspect-brk`, and related Node.js debugger flags are
|
|
53
|
+
* honoured.
|
|
54
|
+
*
|
|
55
|
+
* When disabled, `SIGUSR1` no longer opens the V8 inspector in the main process either.
|
|
56
|
+
* Most production apps can safely disable this fuse.
|
|
57
|
+
*
|
|
58
|
+
* @see https://github.com/electron/fuses
|
|
59
|
+
*/
|
|
60
|
+
enableNodeCliInspectArguments?: boolean;
|
|
61
|
+
/**
|
|
62
|
+
* Enables ASAR integrity validation — Electron verifies the embedded SHA-256 hash of
|
|
63
|
+
* `app.asar` before loading it.
|
|
64
|
+
*
|
|
65
|
+
* Platform support:
|
|
66
|
+
* - macOS: Electron ≥ 16.0.0
|
|
67
|
+
* - Windows: Electron ≥ 30.0.0
|
|
68
|
+
*
|
|
69
|
+
* For this fuse to be meaningful, `asar.disableIntegrity` must **not** be
|
|
70
|
+
* `true` (otherwise the hash is not embedded).
|
|
71
|
+
*
|
|
72
|
+
* @see https://www.electronjs.org/docs/latest/tutorial/asar-integrity
|
|
73
|
+
*/
|
|
74
|
+
enableEmbeddedAsarIntegrityValidation?: boolean;
|
|
75
|
+
/**
|
|
76
|
+
* When enabled, Electron searches for the app exclusively in `app.asar`, skipping the `app`
|
|
77
|
+
* directory and `default_app.asar` fallbacks.
|
|
78
|
+
*
|
|
79
|
+
* Combined with `enableEmbeddedAsarIntegrityValidation`, this makes it impossible to side-load
|
|
80
|
+
* unverified code by replacing `app.asar` with an unarchived `app/` directory.
|
|
81
|
+
*
|
|
82
|
+
* @see https://github.com/electron/fuses
|
|
83
|
+
*/
|
|
84
|
+
onlyLoadAppFromAsar?: boolean;
|
|
85
|
+
/**
|
|
86
|
+
* When enabled, the browser (main) process uses a separate V8 snapshot file
|
|
87
|
+
* (`browser_v8_context_snapshot.bin`) instead of the shared one.
|
|
88
|
+
*
|
|
89
|
+
* This is only useful when you ship a custom V8 snapshot for the main process that differs
|
|
90
|
+
* from the renderer snapshot. Standard apps do not need this.
|
|
91
|
+
*
|
|
92
|
+
* @see https://github.com/electron/fuses
|
|
93
|
+
*/
|
|
94
|
+
loadBrowserProcessSpecificV8Snapshot?: boolean;
|
|
95
|
+
/**
|
|
96
|
+
* Controls whether pages loaded from the `file://` protocol receive elevated privileges
|
|
97
|
+
* beyond what a standard web browser would grant.
|
|
98
|
+
*
|
|
99
|
+
* These extra privileges include `fetch` to other `file://` URLs, service workers, and
|
|
100
|
+
* universal frame access for child frames also on `file://`. This behaviour pre-dates modern
|
|
101
|
+
* Electron security best practices.
|
|
102
|
+
*
|
|
103
|
+
* Disable this fuse if your app does not load content directly from `file://` (i.e. you use
|
|
104
|
+
* a [custom protocol](https://www.electronjs.org/docs/latest/tutorial/security#18-avoid-usage-of-the-file-protocol-and-prefer-usage-of-custom-protocols)).
|
|
105
|
+
*
|
|
106
|
+
* @see https://github.com/electron/fuses
|
|
107
|
+
*/
|
|
108
|
+
grantFileProtocolExtraPrivileges?: boolean;
|
|
109
|
+
/**
|
|
110
|
+
* Enables V8 signal-based trap handlers for out-of-bounds WebAssembly memory accesses.
|
|
111
|
+
*
|
|
112
|
+
* When enabled, Electron uses OS signals (e.g. `SIGSEGV` on Linux/macOS) to catch Wasm
|
|
113
|
+
* OOB accesses at the hardware level rather than inserting explicit bounds checks in JIT'd
|
|
114
|
+
* code. This improves Wasm performance and is enabled by default in Electron.
|
|
115
|
+
*
|
|
116
|
+
* Disable only if the host environment restricts signal handlers (e.g. certain sandboxing
|
|
117
|
+
* configurations) and you observe crashes in Wasm-heavy workloads.
|
|
118
|
+
*
|
|
119
|
+
* @see https://github.com/electron/fuses
|
|
120
|
+
*/
|
|
121
|
+
wasmTrapHandlers?: boolean;
|
|
122
|
+
/**
|
|
123
|
+
* Re-applies the ad-hoc codesignature on macOS after fuses are flipped.
|
|
124
|
+
*
|
|
125
|
+
* electron-builder already re-signs the app after flipping fuses, so this flag is
|
|
126
|
+
* generally not needed and exists only as a compatibility shim for edge cases.
|
|
127
|
+
*
|
|
128
|
+
* @see https://github.com/electron/fuses?tab=readme-ov-file#apple-silicon
|
|
129
|
+
*/
|
|
130
|
+
resetAdHocDarwinSignature?: boolean;
|
|
131
|
+
}
|
|
132
|
+
type _AssertTrue<T extends true> = T;
|
|
133
|
+
export type _FuseOptionsV1Exhaustive = _AssertTrue<[
|
|
134
|
+
Exclude<Uncapitalize<keyof typeof FuseV1Options>, keyof FuseOptionsV1>
|
|
135
|
+
] extends [never] ? true : ["FuseOptionsV1 is missing documented key(s) — add them with JSDoc above", Exclude<Uncapitalize<keyof typeof FuseV1Options>, keyof FuseOptionsV1>]>;
|
|
136
|
+
export {};
|
|
137
|
+
//# sourceMappingURL=FuseOptionsV1.d.ts.map
|