app-builder-lib 27.0.0-alpha.2 → 27.0.0-alpha.4
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 +414 -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 +22 -123
- 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 +3 -3
- package/dist/indexInternal.d.ts.map +1 -1
- package/dist/indexInternal.js +2 -2
- package/dist/indexInternal.js.map +1 -1
- package/dist/macPackager.d.ts +19 -10
- package/dist/macPackager.d.ts.map +1 -1
- package/dist/macPackager.js +149 -121
- package/dist/macPackager.js.map +1 -1
- package/dist/node-module-collector/moduleManager.d.ts +9 -2
- package/dist/node-module-collector/moduleManager.d.ts.map +1 -1
- package/dist/node-module-collector/moduleManager.js +4 -2
- package/dist/node-module-collector/moduleManager.js.map +1 -1
- package/dist/node-module-collector/nodeModulesCollector.d.ts +13 -23
- package/dist/node-module-collector/nodeModulesCollector.d.ts.map +1 -1
- package/dist/node-module-collector/nodeModulesCollector.js +52 -122
- 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/node-module-collector/types.d.ts +2 -0
- package/dist/node-module-collector/types.d.ts.map +1 -1
- package/dist/node-module-collector/types.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/linuxOptions.d.ts +0 -10
- package/dist/options/linuxOptions.d.ts.map +1 -1
- package/dist/options/linuxOptions.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/packager.js +1 -1
- package/dist/packager.js.map +1 -1
- package/dist/platformPackager.d.ts +5 -2
- package/dist/platformPackager.d.ts.map +1 -1
- package/dist/platformPackager.js +16 -13
- 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/FlatpakTarget.d.ts.map +1 -1
- package/dist/targets/linux/FlatpakTarget.js +4 -1
- package/dist/targets/linux/FlatpakTarget.js.map +1 -1
- package/dist/targets/linux/FpmTarget.d.ts +6 -0
- package/dist/targets/linux/FpmTarget.d.ts.map +1 -1
- package/dist/targets/linux/FpmTarget.js +25 -3
- package/dist/targets/linux/FpmTarget.js.map +1 -1
- package/dist/targets/linux/LinuxTargetHelper.d.ts +14 -0
- package/dist/targets/linux/LinuxTargetHelper.d.ts.map +1 -1
- package/dist/targets/linux/LinuxTargetHelper.js +38 -59
- package/dist/targets/linux/LinuxTargetHelper.js.map +1 -1
- package/dist/targets/linux/appimage/AppImageTarget.d.ts +1 -0
- package/dist/targets/linux/appimage/AppImageTarget.d.ts.map +1 -1
- package/dist/targets/linux/appimage/AppImageTarget.js +8 -9
- package/dist/targets/linux/appimage/AppImageTarget.js.map +1 -1
- package/dist/targets/linux/appimage/appImageUtil.d.ts +4 -0
- package/dist/targets/linux/appimage/appImageUtil.d.ts.map +1 -1
- package/dist/targets/linux/appimage/appImageUtil.js +11 -4
- package/dist/targets/linux/appimage/appImageUtil.js.map +1 -1
- package/dist/targets/linux/appimage/appLauncher.d.ts.map +1 -1
- package/dist/targets/linux/appimage/appLauncher.js +5 -11
- package/dist/targets/linux/appimage/appLauncher.js.map +1 -1
- package/dist/targets/linux/launcherScript.d.ts +32 -0
- package/dist/targets/linux/launcherScript.d.ts.map +1 -0
- package/dist/targets/linux/launcherScript.js +24 -0
- package/dist/targets/linux/launcherScript.js.map +1 -0
- 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 +9 -10
- 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 +21 -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 +9 -9
- package/dist/targets/win/AppxTarget.js.map +1 -1
- package/dist/targets/win/MsiTarget.d.ts.map +1 -1
- package/dist/targets/win/MsiTarget.js +8 -11
- package/dist/targets/win/MsiTarget.js.map +1 -1
- package/dist/targets/win/nsis/NsisTarget.js +5 -5
- package/dist/targets/win/nsis/NsisTarget.js.map +1 -1
- package/dist/targets/win/nsis/nsisScriptGenerator.js +2 -2
- 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.d.ts.map +1 -1
- package/dist/toolsets/icons.js +11 -3
- 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/appFileCopier.d.ts.map +1 -1
- package/dist/util/appFileCopier.js +9 -4
- package/dist/util/appFileCopier.js.map +1 -1
- package/dist/util/archCompatibility.d.ts +42 -0
- package/dist/util/archCompatibility.d.ts.map +1 -0
- package/dist/util/archCompatibility.js +202 -0
- package/dist/util/archCompatibility.js.map +1 -0
- 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/installOrRebuild.d.ts +38 -0
- package/dist/util/installOrRebuild.d.ts.map +1 -0
- package/dist/util/{yarn.js → installOrRebuild.js} +65 -14
- package/dist/util/installOrRebuild.js.map +1 -0
- package/dist/util/langs.d.ts.map +1 -1
- package/dist/util/langs.js +1 -0
- package/dist/util/langs.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/util/mac/macosIconComposer.d.ts +2 -1
- package/dist/util/mac/macosIconComposer.d.ts.map +1 -1
- package/dist/util/mac/macosIconComposer.js +40 -58
- package/dist/util/mac/macosIconComposer.js.map +1 -1
- package/dist/util/streamSpawnToFile.d.ts +47 -0
- package/dist/util/streamSpawnToFile.d.ts.map +1 -0
- package/dist/util/streamSpawnToFile.js +110 -0
- package/dist/util/streamSpawnToFile.js.map +1 -0
- package/dist/util/toolsetLock.d.ts +2 -0
- package/dist/util/toolsetLock.d.ts.map +1 -1
- package/dist/util/toolsetLock.js +31 -5
- package/dist/util/toolsetLock.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 +486 -439
- package/templates/appx/appxmanifest.xml +1 -2
- package/templates/nsis/assistedMessages.yml +17 -0
- package/templates/nsis/messages.yml +5 -0
- package/dist/codeSign/signManager.d.ts.map +0 -1
- package/dist/codeSign/signManager.js +0 -2
- package/dist/codeSign/signManager.js.map +0 -1
- package/dist/util/yarn.d.ts +0 -23
- package/dist/util/yarn.d.ts.map +0 -1
- package/dist/util/yarn.js.map +0 -1
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { exists, log, retry, stripSensitiveEnvVars } from "builder-util";
|
|
2
|
-
import * as childProcess from "child_process";
|
|
3
|
-
import { createWriteStream } from "node:fs";
|
|
4
2
|
import _fsExtra from "fs-extra";
|
|
5
3
|
import { Lazy } from "lazy-val";
|
|
6
4
|
import * as path from "path";
|
|
7
5
|
import { hoist } from "./hoist.js";
|
|
8
6
|
import { LogMessageByKey, ModuleManager } from "./moduleManager.js";
|
|
9
7
|
import { getPackageManagerCommand } from "./packageManager.js";
|
|
8
|
+
import { streamSpawnToFile } from "../util/streamSpawnToFile.js";
|
|
9
|
+
import { isPackageCompatible } from "../util/archCompatibility.js";
|
|
10
10
|
export class NodeModulesCollector {
|
|
11
11
|
constructor(rootDir, tempDirManager) {
|
|
12
12
|
this.rootDir = rootDir;
|
|
@@ -42,7 +42,7 @@ export class NodeModulesCollector {
|
|
|
42
42
|
* 5. Hoisting the dependencies to their final locations
|
|
43
43
|
* 6. Resolving and returning module information
|
|
44
44
|
*/
|
|
45
|
-
async getNodeModules({ packageName }) {
|
|
45
|
+
async getNodeModules({ packageName, archFilter }) {
|
|
46
46
|
const tree = await this.getDependenciesTree(this.installOptions.manager);
|
|
47
47
|
await this.collectAllDependencies(tree, packageName);
|
|
48
48
|
const realTree = this.getTreeFromWorkspaces(tree, packageName);
|
|
@@ -50,7 +50,7 @@ export class NodeModulesCollector {
|
|
|
50
50
|
const hoisterResult = hoist(this.transformToHoisterTree(this.productionGraph, packageName), {
|
|
51
51
|
check: log.isDebugEnabled,
|
|
52
52
|
});
|
|
53
|
-
await this._getNodeModules(hoisterResult.dependencies, this.nodeModules);
|
|
53
|
+
await this._getNodeModules(hoisterResult.dependencies, this.nodeModules, archFilter);
|
|
54
54
|
log.debug({ packageName, depCount: this.nodeModules.length }, "node modules collection complete");
|
|
55
55
|
return { nodeModules: this.nodeModules, logSummary: this.cache.logSummary };
|
|
56
56
|
}
|
|
@@ -238,7 +238,7 @@ export class NodeModulesCollector {
|
|
|
238
238
|
}
|
|
239
239
|
return node;
|
|
240
240
|
}
|
|
241
|
-
async _getNodeModules(dependencies, result) {
|
|
241
|
+
async _getNodeModules(dependencies, result, archFilter) {
|
|
242
242
|
if (dependencies.size === 0) {
|
|
243
243
|
return;
|
|
244
244
|
}
|
|
@@ -258,15 +258,28 @@ export class NodeModulesCollector {
|
|
|
258
258
|
this.logMissingDependency(key);
|
|
259
259
|
continue;
|
|
260
260
|
}
|
|
261
|
+
const dir = await this.cache.realPath[p];
|
|
262
|
+
// Drop packages whose declared `cpu`/`os` is incompatible with the target arch/platform (and their
|
|
263
|
+
// subtree). npm/pnpm install only the host's platform-specific optional packages, so without this an
|
|
264
|
+
// arm64-only binary (e.g. `@esbuild/darwin-arm64`) would be bundled into the x64 build too — and into
|
|
265
|
+
// both slices of a universal build, which `@electron/universal` then refuses to merge. Reuses the
|
|
266
|
+
// memoized `package.json` cache populated during collection.
|
|
267
|
+
if (archFilter != null) {
|
|
268
|
+
const pkgJson = await this.cache.json[path.join(dir, "package.json")];
|
|
269
|
+
if (pkgJson != null && !isPackageCompatible(pkgJson, archFilter.cpu, archFilter.os)) {
|
|
270
|
+
this.cache.logSummary[LogMessageByKey.PKG_INCOMPATIBLE_PLATFORM].push(key);
|
|
271
|
+
continue;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
261
274
|
const node = {
|
|
262
275
|
name: d.name,
|
|
263
276
|
version: reference,
|
|
264
|
-
dir
|
|
277
|
+
dir,
|
|
265
278
|
};
|
|
266
279
|
result.push(node);
|
|
267
280
|
if (d.dependencies.size > 0) {
|
|
268
281
|
node.dependencies = [];
|
|
269
|
-
await this._getNodeModules(d.dependencies, node.dependencies);
|
|
282
|
+
await this._getNodeModules(d.dependencies, node.dependencies, archFilter);
|
|
270
283
|
}
|
|
271
284
|
}
|
|
272
285
|
result.sort((a, b) => a.name.localeCompare(b.name));
|
|
@@ -289,133 +302,50 @@ export class NodeModulesCollector {
|
|
|
289
302
|
}
|
|
290
303
|
}
|
|
291
304
|
/**
|
|
292
|
-
* Executes a command and streams its
|
|
293
|
-
*
|
|
294
|
-
* Spawns a child process to execute the specified command with arguments, capturing stdout
|
|
295
|
-
* to a file. On Windows, wraps the invocation in `powershell.exe -EncodedCommand` (UTF-16LE
|
|
296
|
-
* base64) to avoid spawning `.cmd` shims directly and to eliminate shell-injection surface area.
|
|
297
|
-
* Enables corepack strict mode by default but allows process.env overrides.
|
|
305
|
+
* Executes a package-manager command and streams its stdout to a file.
|
|
298
306
|
*
|
|
299
|
-
*
|
|
307
|
+
* Delegates the spawn/stream/flush mechanics (including the Windows `powershell.exe -EncodedCommand`
|
|
308
|
+
* wrapping) to {@link streamSpawnToFile}, and layers on the collector-specific interpretation of the
|
|
309
|
+
* result: corepack is silenced for these invocations, `npm list` exit code 1 is tolerated, and any
|
|
310
|
+
* stderr is surfaced as a collector warning only when the exit code is genuinely unexpected.
|
|
300
311
|
*
|
|
301
312
|
* @param command - The command to execute
|
|
302
313
|
* @param args - Array of command-line arguments
|
|
303
314
|
* @param cwd - The working directory to execute the command in
|
|
304
315
|
* @param tempOutputFile - The path to the temporary file where stdout will be written
|
|
305
316
|
* @returns Promise that resolves when the command completes successfully or rejects if it fails
|
|
306
|
-
* @throws {Error} If the child process spawn fails or exits with a non-zero code
|
|
317
|
+
* @throws {Error} If the child process spawn fails or exits with a non-zero, unexpected code
|
|
307
318
|
*/
|
|
308
319
|
async streamCollectorCommandToFile(command, args, cwd, tempOutputFile) {
|
|
309
320
|
// Derive execName from the original command so the npm-list shouldIgnore check below keys off the
|
|
310
|
-
// real invocation (e.g. "npm"), not the "powershell" wrapper
|
|
321
|
+
// real invocation (e.g. "npm"), not the "powershell" wrapper streamSpawnToFile uses on Windows.
|
|
311
322
|
const execName = path.basename(command, path.extname(command));
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
await new Promise((resolve, reject) => {
|
|
320
|
-
const outStream = createWriteStream(tempOutputFile);
|
|
321
|
-
const child = childProcess.spawn(spawnCommand, spawnArgs, {
|
|
322
|
-
cwd,
|
|
323
|
-
// Package manager invocations do not need signing/publishing credentials.
|
|
324
|
-
env: { COREPACK_ENABLE_STRICT: "0", ...stripSensitiveEnvVars(process.env) },
|
|
325
|
-
});
|
|
326
|
-
let stderr = "";
|
|
327
|
-
// The process can close before all piped stdout has been flushed to disk. Resolving on the
|
|
328
|
-
// child's "close" alone races the write stream and lets the caller read a TRUNCATED file
|
|
329
|
-
// (manifesting as "No JSON content found in output"). Gate the settle on BOTH the child exit
|
|
330
|
-
// (for the code/stderr) and the write stream's "finish" (all bytes flushed).
|
|
331
|
-
let exitCode = null;
|
|
332
|
-
let childClosed = false;
|
|
333
|
-
let streamFinished = false;
|
|
334
|
-
let settled = false;
|
|
335
|
-
// `pipe` ends `outStream` when stdout EOFs, which triggers its "finish" once flushed.
|
|
336
|
-
child.stdout.pipe(outStream);
|
|
337
|
-
child.stderr.on("data", chunk => {
|
|
338
|
-
stderr += chunk.toString();
|
|
339
|
-
});
|
|
340
|
-
const fail = (err) => {
|
|
341
|
-
if (settled) {
|
|
342
|
-
return;
|
|
343
|
-
}
|
|
344
|
-
settled = true;
|
|
345
|
-
// Best-effort cleanup: stop the child and close the stream so we don't
|
|
346
|
-
// waste CPU writing to a broken fd after rejection.
|
|
347
|
-
try {
|
|
348
|
-
child.kill();
|
|
349
|
-
}
|
|
350
|
-
catch {
|
|
351
|
-
// ignore
|
|
352
|
-
}
|
|
353
|
-
try {
|
|
354
|
-
outStream.destroy();
|
|
355
|
-
}
|
|
356
|
-
catch {
|
|
357
|
-
// ignore
|
|
358
|
-
}
|
|
359
|
-
reject(err);
|
|
360
|
-
};
|
|
361
|
-
const settle = () => {
|
|
362
|
-
if (settled || !childClosed || !streamFinished) {
|
|
363
|
-
return;
|
|
364
|
-
}
|
|
365
|
-
const code = exitCode;
|
|
366
|
-
// https://github.com/npm/npm/issues/17624
|
|
367
|
-
const shouldIgnore = code === 1 && "npm" === execName.toLowerCase() && args.includes("list");
|
|
368
|
-
if (shouldIgnore) {
|
|
369
|
-
log.debug(null, "`npm list` returned non-zero exit code, but it MIGHT be expected (https://github.com/npm/npm/issues/17624). Check stderr for details.");
|
|
370
|
-
}
|
|
371
|
-
if (stderr.length > 0) {
|
|
372
|
-
log.debug({ stderr }, "note: there was node module collector output on stderr");
|
|
373
|
-
// Only surface stderr as a user-visible warning when the exit code itself is unexpected.
|
|
374
|
-
// When shouldIgnore is true (npm list exit code 1) the stderr is an anticipated side
|
|
375
|
-
// effect of package-manager features like yarn resolutions or npm overrides that cause
|
|
376
|
-
// npm to report ELSPROBLEMS for aliased packages it considers "invalid".
|
|
377
|
-
if (!shouldIgnore) {
|
|
378
|
-
this.cache.logSummary[LogMessageByKey.PKG_COLLECTOR_OUTPUT].push(stderr);
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
settled = true;
|
|
382
|
-
const shouldResolve = code === 0 || shouldIgnore;
|
|
383
|
-
return shouldResolve ? resolve() : reject(new Error(`Node module collector process exited with code ${code}:\n${stderr}`));
|
|
384
|
-
};
|
|
385
|
-
outStream.on("error", err => fail(new Error(`Node module collector failed writing output (${command}): ${err.message}`)));
|
|
386
|
-
outStream.on("finish", () => {
|
|
387
|
-
streamFinished = true;
|
|
388
|
-
settle();
|
|
389
|
-
});
|
|
390
|
-
child.on("error", err => {
|
|
391
|
-
fail(new Error(`Node module collector spawn (${command} ${JSON.stringify(args)}) failed: ${err.message}`));
|
|
392
|
-
});
|
|
393
|
-
child.on("close", code => {
|
|
394
|
-
exitCode = code;
|
|
395
|
-
childClosed = true;
|
|
396
|
-
settle();
|
|
397
|
-
});
|
|
323
|
+
const { code, stderr } = await streamSpawnToFile(command, args, cwd, tempOutputFile, {
|
|
324
|
+
// Package manager invocations do not need signing/publishing credentials. Silence corepack:
|
|
325
|
+
// strict=0 so a project's `packageManager` pin can't abort our read-only queries, and the
|
|
326
|
+
// download prompt/notice off so corepack doesn't flood stdout/stderr with activation chatter.
|
|
327
|
+
...stripSensitiveEnvVars(process.env),
|
|
328
|
+
COREPACK_ENABLE_STRICT: "0",
|
|
329
|
+
COREPACK_ENABLE_DOWNLOAD_PROMPT: "0",
|
|
398
330
|
});
|
|
331
|
+
// https://github.com/npm/npm/issues/17624
|
|
332
|
+
const shouldIgnore = code === 1 && "npm" === execName.toLowerCase() && args.includes("list");
|
|
333
|
+
if (shouldIgnore) {
|
|
334
|
+
log.debug(null, "`npm list` returned non-zero exit code, but it MIGHT be expected (https://github.com/npm/npm/issues/17624). Check stderr for details.");
|
|
335
|
+
}
|
|
336
|
+
if (stderr.length > 0) {
|
|
337
|
+
log.debug({ stderr }, "note: there was node module collector output on stderr");
|
|
338
|
+
// Only surface stderr as a user-visible warning when the exit code itself is unexpected.
|
|
339
|
+
// When shouldIgnore is true (npm list exit code 1) the stderr is an anticipated side
|
|
340
|
+
// effect of package-manager features like yarn resolutions or npm overrides that cause
|
|
341
|
+
// npm to report ELSPROBLEMS for aliased packages it considers "invalid".
|
|
342
|
+
if (!shouldIgnore) {
|
|
343
|
+
this.cache.logSummary[LogMessageByKey.PKG_COLLECTOR_OUTPUT].push(stderr);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
if (code !== 0 && !shouldIgnore) {
|
|
347
|
+
throw new Error(`Node module collector process exited with code ${code}:\n${stderr}`);
|
|
348
|
+
}
|
|
399
349
|
}
|
|
400
350
|
}
|
|
401
|
-
/**
|
|
402
|
-
* Build the argv for invoking a Windows command through `powershell.exe -EncodedCommand`.
|
|
403
|
-
*
|
|
404
|
-
* Each token is wrapped in a PowerShell single-quoted string (with embedded single quotes doubled),
|
|
405
|
-
* so no character is interpreted by a shell. The script:
|
|
406
|
-
* - pins `[Console]::OutputEncoding` to UTF-8 *without* a BOM so the JSON dependency tree is not
|
|
407
|
-
* corrupted by the console's OEM code page (and no BOM is prepended to break `JSON.parse`),
|
|
408
|
-
* - invokes the command via the call operator `&`,
|
|
409
|
-
* - re-emits the command's own exit code via `exit $LASTEXITCODE` (e.g. `npm list` returns 1 in
|
|
410
|
-
* expected scenarios, which the caller's shouldIgnore logic relies on).
|
|
411
|
-
*
|
|
412
|
-
* The whole script is base64-encoded as UTF-16LE per PowerShell's `-EncodedCommand` contract.
|
|
413
|
-
*/
|
|
414
|
-
export function buildPowerShellEncodedArgs(command, args) {
|
|
415
|
-
const psQuote = (value) => `'${value.replace(/'/g, "''")}'`;
|
|
416
|
-
const invocation = ["&", psQuote(command), ...args.map(psQuote)].join(" ");
|
|
417
|
-
const script = `[Console]::OutputEncoding=[System.Text.UTF8Encoding]::new($false); ${invocation}; exit $LASTEXITCODE`;
|
|
418
|
-
const encoded = Buffer.from(script, "utf16le").toString("base64");
|
|
419
|
-
return ["-NoProfile", "-NonInteractive", "-EncodedCommand", encoded];
|
|
420
|
-
}
|
|
421
351
|
//# sourceMappingURL=nodeModulesCollector.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nodeModulesCollector.js","sourceRoot":"","sources":["../../src/node-module-collector/nodeModulesCollector.ts"],"names":[],"mappings":"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","sourcesContent":["import { exists, log, retry, stripSensitiveEnvVars, TmpDir } from \"builder-util\"\nimport * as childProcess from \"child_process\"\nimport { createWriteStream } from \"node:fs\"\nimport _fsExtra from \"fs-extra\"\nimport { Lazy } from \"lazy-val\"\nimport * as path from \"path\"\nimport { hoist, type HoisterResult, type HoisterTree } from \"./hoist.js\"\nimport { LogMessageByKey, ModuleManager } from \"./moduleManager.js\"\nimport { getPackageManagerCommand, PM } from \"./packageManager.js\"\nimport type { Dependency, DependencyGraph, NodeModuleInfo, PackageJson } from \"./types.js\"\n\nexport abstract class NodeModulesCollector<ProdDepType extends Dependency<ProdDepType, OptionalDepType>, OptionalDepType> {\n private readonly nodeModules: NodeModuleInfo[] = []\n protected readonly allDependencies: Map<string, ProdDepType> = new Map()\n protected readonly productionGraph: DependencyGraph = {}\n protected readonly cache: ModuleManager = new ModuleManager()\n\n protected isHoisted = new Lazy<boolean>(async () => {\n const { manager } = this.installOptions\n const command = getPackageManagerCommand(manager)\n const config = (await this.asyncExec(command, [\"config\", \"list\"])).stdout\n if (config == null) {\n log.debug({ manager }, \"unable to determine node-linker setting; assuming non-hoisted (virtual store) layout\")\n return false\n }\n const lines = Object.fromEntries(config.split(\"\\n\").map(line => line.split(\"=\").map(s => s.trim())))\n if (lines[\"node-linker\"] === \"hoisted\") {\n log.debug({ manager }, \"node_modules are hoisted\")\n return true\n }\n return false\n })\n\n constructor(\n protected readonly rootDir: string,\n private readonly tempDirManager: TmpDir\n ) {}\n\n /**\n * Retrieves and collects all Node.js modules for a given package.\n *\n * This method orchestrates the entire module collection process by:\n * 1. Fetching the dependency tree from the package manager\n * 2. Collecting all dependencies recursively\n * 3. Extracting workspace references if applicable\n * 4. Building a production dependency graph\n * 5. Hoisting the dependencies to their final locations\n * 6. Resolving and returning module information\n */\n public async getNodeModules({ packageName }: { packageName: string }): Promise<{\n nodeModules: NodeModuleInfo[]\n logSummary: ModuleManager[\"logSummary\"]\n }> {\n const tree: ProdDepType = await this.getDependenciesTree(this.installOptions.manager)\n\n await this.collectAllDependencies(tree, packageName)\n const realTree: ProdDepType = this.getTreeFromWorkspaces(tree, packageName)\n await this.extractProductionDependencyGraph(realTree, packageName)\n\n const hoisterResult: HoisterResult = hoist(this.transformToHoisterTree(this.productionGraph, packageName), {\n check: log.isDebugEnabled,\n })\n\n await this._getNodeModules(hoisterResult.dependencies, this.nodeModules)\n\n log.debug({ packageName, depCount: this.nodeModules.length }, \"node modules collection complete\")\n\n return { nodeModules: this.nodeModules, logSummary: this.cache.logSummary }\n }\n\n public abstract readonly installOptions: {\n manager: PM\n lockfile: string\n }\n\n protected abstract getArgs(): string[]\n protected abstract extractProductionDependencyGraph(tree: Dependency<ProdDepType, OptionalDepType>, dependencyId: string): Promise<void>\n protected abstract collectAllDependencies(tree: Dependency<ProdDepType, OptionalDepType>, appPackageName: string): Promise<void>\n\n /**\n * Retrieves the dependency tree from the package manager.\n *\n * Executes the appropriate package manager command to fetch the dependency tree and writes\n * the output to a temporary file. Includes retry logic to handle transient failures such as\n * incomplete JSON output or missing files. Will retry up to 1 time with exponential backoff.\n */\n protected async getDependenciesTree(pm: PM): Promise<ProdDepType> {\n const command = getPackageManagerCommand(pm)\n const args = this.getArgs()\n\n const tempOutputFile = await this.tempDirManager.getTempFile({\n prefix: path.basename(command, path.extname(command)),\n suffix: \"output.json\",\n })\n\n return retry(\n async () => {\n await this.streamCollectorCommandToFile(command, args, this.rootDir, tempOutputFile)\n const shellOutput = await _fsExtra.readFile(tempOutputFile, { encoding: \"utf8\" })\n const result = await Promise.resolve(this.parseDependenciesTree(shellOutput))\n return result\n },\n {\n retries: 1,\n interval: 2000,\n backoff: 2000,\n shouldRetry: async (error: any) => {\n const fields: Record<string, string> = { error: error.message, tempOutputFile, cwd: this.rootDir, packageManager: pm }\n\n if (!(await exists(tempOutputFile))) {\n log.debug(fields, \"dependency tree output file missing, retrying\")\n return true\n }\n\n const fileContent = await _fsExtra.readFile(tempOutputFile, { encoding: \"utf8\" })\n fields.fileContentLength = fileContent.length.toString()\n\n if (fileContent.trim().length === 0) {\n log.debug(fields, \"dependency tree output file empty, retrying\")\n return true\n }\n\n // extract small start/end sample for debugging purposes (e.g. polluted console output)\n const lines = fileContent.split(\"\\n\")\n const lineSampleSize = Math.min(5, lines.length / 2)\n if (2 * lineSampleSize > 5) {\n fields.sampleStart = lines.slice(0, lineSampleSize).join(\"\\n\")\n fields.sampleEnd = lines.slice(-lineSampleSize).join(\"\\n\")\n } else {\n fields.content = fileContent\n }\n\n // Both indicate truncated/polluted PM output (a transient that re-running the command clears).\n if (error.message?.includes(\"Unexpected end of JSON input\") || error.message?.includes(\"No JSON content found in output\")) {\n log.debug(fields, \"JSON parse error in dependency tree, retrying\")\n return true\n }\n\n log.error(fields, \"error parsing dependencies tree\")\n return false\n },\n }\n )\n }\n\n /**\n * Parses the dependencies tree from shell command output.\n *\n **/\n protected parseDependenciesTree(shellOutput: string): ProdDepType | Promise<ProdDepType> {\n return this.extractJsonFromPollutedOutput<ProdDepType>(shellOutput)\n }\n\n protected extractJsonFromPollutedOutput<T>(shellOutput: string): T {\n const consoleOutput = shellOutput.trim()\n try {\n // Please for the love of all that is holy, this should cover 99% of cases where npm/pnpm/yarn output is clean JSON\n return JSON.parse(consoleOutput)\n } catch {\n // ignore\n }\n\n // DEDICATED FALLBACK FOR POLLUTED OUTPUT, non-trivial to implement correctly, not needed in most cases, and highly inefficient\n\n // Find the first index that starts with { or [\n const bracketOpen = Math.max(consoleOutput.indexOf(\"{\"), 0)\n const bracketOpenSquare = Math.max(consoleOutput.indexOf(\"[\"), 0)\n const start = Math.min(bracketOpen, bracketOpenSquare) // always non-negative due to Math.max above\n\n for (let i = start; i < consoleOutput.length; i++) {\n const slice = consoleOutput.slice(start, i + 1)\n try {\n return JSON.parse(slice)\n } catch {\n // ignore, try next\n }\n }\n throw new Error(\"No JSON content found in output\")\n }\n\n protected cacheKey(pkg: Pick<ProdDepType, \"name\" | \"version\" | \"path\">): string {\n const rel = path.relative(this.rootDir, pkg.path)\n return `${pkg.name}::${pkg.version}::${rel ?? \".\"}`\n }\n\n // We use the key (alias name) instead of value.name for npm aliased packages\n // e.g., { \"foo\": { name: \"@scope/bar\", ... } } should be stored as \"foo@version\"\n protected normalizePackageVersion(key: string, pkg: ProdDepType) {\n return { id: `${key}@${pkg.version}`, pkgOverride: { ...pkg, name: key } }\n }\n\n /**\n * Determines if a given dependency is a production dependency of a package.\n *\n * Checks both the dependencies and optionalDependencies of a package to see if\n * the specified dependency name is listed.\n *\n * @param depName - The name of the dependency to check\n * @param pkg - The package to search for the dependency in\n * @returns True if the dependency is found in either dependencies or optionalDependencies, false otherwise\n */\n protected isProdDependency(depName: string, pkg: ProdDepType): boolean {\n const prodDeps = { ...pkg.dependencies, ...pkg.optionalDependencies }\n return prodDeps[depName] != null\n }\n\n protected async locatePackageWithVersion(depTree: Pick<ProdDepType, \"name\" | \"version\" | \"path\">): Promise<{ packageDir: string; packageJson: PackageJson } | null> {\n const result = await this.cache.locatePackageVersion({\n parentDir: depTree.path,\n pkgName: depTree.name,\n requiredRange: depTree.version,\n })\n return result\n }\n /**\n * Parses a dependency identifier string into name and version components.\n *\n * Handles both scoped packages (e.g., \"@scope/pkg@1.2.3\") and regular packages (e.g., \"pkg@1.2.3\").\n * If the identifier is malformed or cannot be parsed, defaults to treating the entire string as\n * the package name with an \"unknown\" version.\n */\n protected parseNameVersion(identifier: string): { name: string; version: string } {\n let at: number\n if (identifier.startsWith(\"@\")) {\n // Scoped package: find the version separator after the scope (e.g. \"@scope/pkg@1.2.3\")\n const slashIndex = identifier.indexOf(\"/\")\n if (slashIndex === -1) {\n return { name: identifier, version: \"unknown\" }\n }\n at = identifier.indexOf(\"@\", slashIndex + 1)\n } else {\n at = identifier.indexOf(\"@\")\n }\n if (at <= 0) {\n return { name: identifier, version: \"unknown\" }\n }\n return { name: identifier.slice(0, at), version: identifier.slice(at + 1) }\n }\n\n /**\n * Retrieves the dependency tree and handles workspace package self-references.\n *\n * If the project is a workspace project, this method removes the root package's self-reference\n * from the dependency tree to avoid circular dependencies. It promotes the root package's\n * direct dependencies to the top level of the tree.\n *\n * @param tree - The original dependency tree\n * @param packageName - The name of the package to check for and remove from the tree\n * @returns The extracted dependency subtree\n */\n protected getTreeFromWorkspaces(tree: ProdDepType, packageName: string): ProdDepType {\n if (tree.workspaces && tree.dependencies) {\n for (const [key, value] of Object.entries(tree.dependencies)) {\n if (key === packageName) {\n return value\n }\n }\n }\n\n return tree\n }\n\n private transformToHoisterTree(obj: DependencyGraph, key: string, nodes: Map<string, HoisterTree> = new Map()): HoisterTree {\n let node = nodes.get(key)\n const { name, version } = this.parseNameVersion(key)\n\n if (!node) {\n node = {\n name,\n identName: name,\n reference: version,\n dependencies: new Set<HoisterTree>(),\n peerNames: new Set<string>(),\n }\n\n nodes.set(key, node)\n\n const deps = (obj[key] || {}).dependencies || []\n for (const dep of deps) {\n const child = this.transformToHoisterTree(obj, dep, nodes)\n node.dependencies.add(child)\n }\n }\n\n return node\n }\n\n private async _getNodeModules(dependencies: Set<HoisterResult>, result: NodeModuleInfo[]) {\n if (dependencies.size === 0) {\n return\n }\n\n for (const d of dependencies.values()) {\n const reference = [...d.references][0]\n const key = `${d.name}@${reference}`\n // Normalize the path to handle mixed separators from pnpm JSON output on Windows\n const rawPath = this.allDependencies.get(key)?.path\n const p = rawPath != null ? path.normalize(rawPath) : undefined\n if (p === undefined) {\n this.cache.logSummary[LogMessageByKey.PKG_NOT_FOUND].push(key)\n continue\n }\n\n // fix npm list issue\n // https://github.com/npm/cli/issues/8535\n if (!(await this.cache.exists[p])) {\n this.logMissingDependency(key)\n continue\n }\n\n const node: NodeModuleInfo = {\n name: d.name,\n version: reference,\n dir: await this.cache.realPath[p],\n }\n result.push(node)\n if (d.dependencies.size > 0) {\n node.dependencies = []\n await this._getNodeModules(d.dependencies, node.dependencies)\n }\n }\n result.sort((a, b) => a.name.localeCompare(b.name))\n }\n\n protected logMissingDependency(pkgName: string) {\n const PLATFORM_PACKAGE_RE = /(linux|win32|darwin|freebsd|android)[-_](x64|arm64|ia32|arm|ppc64|s390x|loong64|riscv64|universal)/\n const diskLogKey = PLATFORM_PACKAGE_RE.test(pkgName) ? LogMessageByKey.PKG_OPTIONAL_PLATFORM_NOT_INSTALLED : LogMessageByKey.PKG_NOT_ON_DISK\n this.cache.logSummary[diskLogKey].push(pkgName)\n }\n\n protected async asyncExec(command: string, args: string[], cwd: string = this.rootDir): Promise<{ stdout: string | undefined; stderr: string | undefined }> {\n const file = await this.tempDirManager.getTempFile({ prefix: \"exec-\", suffix: \".txt\" })\n try {\n await this.streamCollectorCommandToFile(command, args, cwd, file)\n const result = await _fsExtra.readFile(file, { encoding: \"utf8\" })\n return { stdout: result?.trim(), stderr: undefined }\n } catch (error: any) {\n log.debug({ error: error.message }, \"failed to execute command\")\n return { stdout: undefined, stderr: error.message }\n }\n }\n\n /**\n * Executes a command and streams its output to a file.\n *\n * Spawns a child process to execute the specified command with arguments, capturing stdout\n * to a file. On Windows, wraps the invocation in `powershell.exe -EncodedCommand` (UTF-16LE\n * base64) to avoid spawning `.cmd` shims directly and to eliminate shell-injection surface area.\n * Enables corepack strict mode by default but allows process.env overrides.\n *\n * Special handling for `npm list` exit code 1, which is expected in certain scenarios.\n *\n * @param command - The command to execute\n * @param args - Array of command-line arguments\n * @param cwd - The working directory to execute the command in\n * @param tempOutputFile - The path to the temporary file where stdout will be written\n * @returns Promise that resolves when the command completes successfully or rejects if it fails\n * @throws {Error} If the child process spawn fails or exits with a non-zero code\n */\n protected async streamCollectorCommandToFile(command: string, args: string[], cwd: string, tempOutputFile: string) {\n // Derive execName from the original command so the npm-list shouldIgnore check below keys off the\n // real invocation (e.g. \"npm\"), not the \"powershell\" wrapper we spawn on Windows.\n const execName = path.basename(command, path.extname(command))\n\n // On Windows the package-manager command is typically a `.cmd` shim (npm.cmd/pnpm.cmd/yarn.cmd),\n // which Node can no longer spawn directly (CVE-2024-27980). Rather than spawn with `shell: true` —\n // which emits the DEP0190 \"args with shell\" deprecation warning and forces manual metacharacter\n // escaping — wrap the invocation in a single PowerShell `-EncodedCommand`. The base64 (UTF-16LE)\n // payload sidesteps every shell-quoting layer, and `powershell.exe` is a real executable we spawn\n // directly with no shell. See buildPowerShellEncodedArgs for the UTF-8 / exit-code handling.\n const [spawnCommand, spawnArgs] = process.platform === \"win32\" ? ([\"powershell.exe\", buildPowerShellEncodedArgs(command, args)] as const) : ([command, args] as const)\n\n await new Promise<void>((resolve, reject) => {\n const outStream = createWriteStream(tempOutputFile)\n\n const child = childProcess.spawn(spawnCommand, spawnArgs, {\n cwd,\n // Package manager invocations do not need signing/publishing credentials.\n env: { COREPACK_ENABLE_STRICT: \"0\", ...stripSensitiveEnvVars(process.env) },\n })\n\n let stderr = \"\"\n // The process can close before all piped stdout has been flushed to disk. Resolving on the\n // child's \"close\" alone races the write stream and lets the caller read a TRUNCATED file\n // (manifesting as \"No JSON content found in output\"). Gate the settle on BOTH the child exit\n // (for the code/stderr) and the write stream's \"finish\" (all bytes flushed).\n let exitCode: number | null = null\n let childClosed = false\n let streamFinished = false\n let settled = false\n\n // `pipe` ends `outStream` when stdout EOFs, which triggers its \"finish\" once flushed.\n child.stdout.pipe(outStream)\n child.stderr.on(\"data\", chunk => {\n stderr += chunk.toString()\n })\n\n const fail = (err: Error) => {\n if (settled) {\n return\n }\n settled = true\n // Best-effort cleanup: stop the child and close the stream so we don't\n // waste CPU writing to a broken fd after rejection.\n try {\n child.kill()\n } catch {\n // ignore\n }\n try {\n outStream.destroy()\n } catch {\n // ignore\n }\n reject(err)\n }\n\n const settle = () => {\n if (settled || !childClosed || !streamFinished) {\n return\n }\n const code = exitCode\n // https://github.com/npm/npm/issues/17624\n const shouldIgnore = code === 1 && \"npm\" === execName.toLowerCase() && args.includes(\"list\")\n if (shouldIgnore) {\n log.debug(null, \"`npm list` returned non-zero exit code, but it MIGHT be expected (https://github.com/npm/npm/issues/17624). Check stderr for details.\")\n }\n if (stderr.length > 0) {\n log.debug({ stderr }, \"note: there was node module collector output on stderr\")\n // Only surface stderr as a user-visible warning when the exit code itself is unexpected.\n // When shouldIgnore is true (npm list exit code 1) the stderr is an anticipated side\n // effect of package-manager features like yarn resolutions or npm overrides that cause\n // npm to report ELSPROBLEMS for aliased packages it considers \"invalid\".\n if (!shouldIgnore) {\n this.cache.logSummary[LogMessageByKey.PKG_COLLECTOR_OUTPUT].push(stderr)\n }\n }\n settled = true\n const shouldResolve = code === 0 || shouldIgnore\n return shouldResolve ? resolve() : reject(new Error(`Node module collector process exited with code ${code}:\\n${stderr}`))\n }\n\n outStream.on(\"error\", err => fail(new Error(`Node module collector failed writing output (${command}): ${err.message}`)))\n outStream.on(\"finish\", () => {\n streamFinished = true\n settle()\n })\n child.on(\"error\", err => {\n fail(new Error(`Node module collector spawn (${command} ${JSON.stringify(args)}) failed: ${err.message}`))\n })\n child.on(\"close\", code => {\n exitCode = code\n childClosed = true\n settle()\n })\n })\n }\n}\n\n/**\n * Build the argv for invoking a Windows command through `powershell.exe -EncodedCommand`.\n *\n * Each token is wrapped in a PowerShell single-quoted string (with embedded single quotes doubled),\n * so no character is interpreted by a shell. The script:\n * - pins `[Console]::OutputEncoding` to UTF-8 *without* a BOM so the JSON dependency tree is not\n * corrupted by the console's OEM code page (and no BOM is prepended to break `JSON.parse`),\n * - invokes the command via the call operator `&`,\n * - re-emits the command's own exit code via `exit $LASTEXITCODE` (e.g. `npm list` returns 1 in\n * expected scenarios, which the caller's shouldIgnore logic relies on).\n *\n * The whole script is base64-encoded as UTF-16LE per PowerShell's `-EncodedCommand` contract.\n */\nexport function buildPowerShellEncodedArgs(command: string, args: string[]): string[] {\n const psQuote = (value: string) => `'${value.replace(/'/g, \"''\")}'`\n const invocation = [\"&\", psQuote(command), ...args.map(psQuote)].join(\" \")\n const script = `[Console]::OutputEncoding=[System.Text.UTF8Encoding]::new($false); ${invocation}; exit $LASTEXITCODE`\n const encoded = Buffer.from(script, \"utf16le\").toString(\"base64\")\n return [\"-NoProfile\", \"-NonInteractive\", \"-EncodedCommand\", encoded]\n}\n"]}
|
|
1
|
+
{"version":3,"file":"nodeModulesCollector.js","sourceRoot":"","sources":["../../src/node-module-collector/nodeModulesCollector.ts"],"names":[],"mappings":"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","sourcesContent":["import { exists, log, retry, stripSensitiveEnvVars, TmpDir } from \"builder-util\"\nimport _fsExtra from \"fs-extra\"\nimport { Lazy } from \"lazy-val\"\nimport * as path from \"path\"\nimport { hoist, type HoisterResult, type HoisterTree } from \"./hoist.js\"\nimport { LogMessageByKey, ModuleManager } from \"./moduleManager.js\"\nimport { getPackageManagerCommand, PM } from \"./packageManager.js\"\nimport { streamSpawnToFile } from \"../util/streamSpawnToFile.js\"\nimport type { Dependency, DependencyGraph, NodeModuleInfo, PackageJson } from \"./types.js\"\nimport { isPackageCompatible } from \"../util/archCompatibility.js\"\n\n/** Target arch/platform used to drop `cpu`/`os`-incompatible packages while collecting. */\nexport interface ArchFilter {\n cpu: string | null\n os: string\n}\n\nexport abstract class NodeModulesCollector<ProdDepType extends Dependency<ProdDepType, OptionalDepType>, OptionalDepType> {\n private readonly nodeModules: NodeModuleInfo[] = []\n protected readonly allDependencies: Map<string, ProdDepType> = new Map()\n protected readonly productionGraph: DependencyGraph = {}\n protected readonly cache: ModuleManager = new ModuleManager()\n\n protected isHoisted = new Lazy<boolean>(async () => {\n const { manager } = this.installOptions\n const command = getPackageManagerCommand(manager)\n const config = (await this.asyncExec(command, [\"config\", \"list\"])).stdout\n if (config == null) {\n log.debug({ manager }, \"unable to determine node-linker setting; assuming non-hoisted (virtual store) layout\")\n return false\n }\n const lines = Object.fromEntries(config.split(\"\\n\").map(line => line.split(\"=\").map(s => s.trim())))\n if (lines[\"node-linker\"] === \"hoisted\") {\n log.debug({ manager }, \"node_modules are hoisted\")\n return true\n }\n return false\n })\n\n constructor(\n protected readonly rootDir: string,\n private readonly tempDirManager: TmpDir\n ) {}\n\n /**\n * Retrieves and collects all Node.js modules for a given package.\n *\n * This method orchestrates the entire module collection process by:\n * 1. Fetching the dependency tree from the package manager\n * 2. Collecting all dependencies recursively\n * 3. Extracting workspace references if applicable\n * 4. Building a production dependency graph\n * 5. Hoisting the dependencies to their final locations\n * 6. Resolving and returning module information\n */\n public async getNodeModules({ packageName, archFilter }: { packageName: string; archFilter?: ArchFilter }): Promise<{\n nodeModules: NodeModuleInfo[]\n logSummary: ModuleManager[\"logSummary\"]\n }> {\n const tree: ProdDepType = await this.getDependenciesTree(this.installOptions.manager)\n\n await this.collectAllDependencies(tree, packageName)\n const realTree: ProdDepType = this.getTreeFromWorkspaces(tree, packageName)\n await this.extractProductionDependencyGraph(realTree, packageName)\n\n const hoisterResult: HoisterResult = hoist(this.transformToHoisterTree(this.productionGraph, packageName), {\n check: log.isDebugEnabled,\n })\n\n await this._getNodeModules(hoisterResult.dependencies, this.nodeModules, archFilter)\n\n log.debug({ packageName, depCount: this.nodeModules.length }, \"node modules collection complete\")\n\n return { nodeModules: this.nodeModules, logSummary: this.cache.logSummary }\n }\n\n public abstract readonly installOptions: {\n manager: PM\n lockfile: string\n }\n\n protected abstract getArgs(): string[]\n protected abstract extractProductionDependencyGraph(tree: Dependency<ProdDepType, OptionalDepType>, dependencyId: string): Promise<void>\n protected abstract collectAllDependencies(tree: Dependency<ProdDepType, OptionalDepType>, appPackageName: string): Promise<void>\n\n /**\n * Retrieves the dependency tree from the package manager.\n *\n * Executes the appropriate package manager command to fetch the dependency tree and writes\n * the output to a temporary file. Includes retry logic to handle transient failures such as\n * incomplete JSON output or missing files. Will retry up to 1 time with exponential backoff.\n */\n protected async getDependenciesTree(pm: PM): Promise<ProdDepType> {\n const command = getPackageManagerCommand(pm)\n const args = this.getArgs()\n\n const tempOutputFile = await this.tempDirManager.getTempFile({\n prefix: path.basename(command, path.extname(command)),\n suffix: \"output.json\",\n })\n\n return retry(\n async () => {\n await this.streamCollectorCommandToFile(command, args, this.rootDir, tempOutputFile)\n const shellOutput = await _fsExtra.readFile(tempOutputFile, { encoding: \"utf8\" })\n const result = await Promise.resolve(this.parseDependenciesTree(shellOutput))\n return result\n },\n {\n retries: 1,\n interval: 2000,\n backoff: 2000,\n shouldRetry: async (error: any) => {\n const fields: Record<string, string> = { error: error.message, tempOutputFile, cwd: this.rootDir, packageManager: pm }\n\n if (!(await exists(tempOutputFile))) {\n log.debug(fields, \"dependency tree output file missing, retrying\")\n return true\n }\n\n const fileContent = await _fsExtra.readFile(tempOutputFile, { encoding: \"utf8\" })\n fields.fileContentLength = fileContent.length.toString()\n\n if (fileContent.trim().length === 0) {\n log.debug(fields, \"dependency tree output file empty, retrying\")\n return true\n }\n\n // extract small start/end sample for debugging purposes (e.g. polluted console output)\n const lines = fileContent.split(\"\\n\")\n const lineSampleSize = Math.min(5, lines.length / 2)\n if (2 * lineSampleSize > 5) {\n fields.sampleStart = lines.slice(0, lineSampleSize).join(\"\\n\")\n fields.sampleEnd = lines.slice(-lineSampleSize).join(\"\\n\")\n } else {\n fields.content = fileContent\n }\n\n // Both indicate truncated/polluted PM output (a transient that re-running the command clears).\n if (error.message?.includes(\"Unexpected end of JSON input\") || error.message?.includes(\"No JSON content found in output\")) {\n log.debug(fields, \"JSON parse error in dependency tree, retrying\")\n return true\n }\n\n log.error(fields, \"error parsing dependencies tree\")\n return false\n },\n }\n )\n }\n\n /**\n * Parses the dependencies tree from shell command output.\n *\n **/\n protected parseDependenciesTree(shellOutput: string): ProdDepType | Promise<ProdDepType> {\n return this.extractJsonFromPollutedOutput<ProdDepType>(shellOutput)\n }\n\n protected extractJsonFromPollutedOutput<T>(shellOutput: string): T {\n const consoleOutput = shellOutput.trim()\n try {\n // Please for the love of all that is holy, this should cover 99% of cases where npm/pnpm/yarn output is clean JSON\n return JSON.parse(consoleOutput)\n } catch {\n // ignore\n }\n\n // DEDICATED FALLBACK FOR POLLUTED OUTPUT, non-trivial to implement correctly, not needed in most cases, and highly inefficient\n\n // Find the first index that starts with { or [\n const bracketOpen = Math.max(consoleOutput.indexOf(\"{\"), 0)\n const bracketOpenSquare = Math.max(consoleOutput.indexOf(\"[\"), 0)\n const start = Math.min(bracketOpen, bracketOpenSquare) // always non-negative due to Math.max above\n\n for (let i = start; i < consoleOutput.length; i++) {\n const slice = consoleOutput.slice(start, i + 1)\n try {\n return JSON.parse(slice)\n } catch {\n // ignore, try next\n }\n }\n throw new Error(\"No JSON content found in output\")\n }\n\n protected cacheKey(pkg: Pick<ProdDepType, \"name\" | \"version\" | \"path\">): string {\n const rel = path.relative(this.rootDir, pkg.path)\n return `${pkg.name}::${pkg.version}::${rel ?? \".\"}`\n }\n\n // We use the key (alias name) instead of value.name for npm aliased packages\n // e.g., { \"foo\": { name: \"@scope/bar\", ... } } should be stored as \"foo@version\"\n protected normalizePackageVersion(key: string, pkg: ProdDepType) {\n return { id: `${key}@${pkg.version}`, pkgOverride: { ...pkg, name: key } }\n }\n\n /**\n * Determines if a given dependency is a production dependency of a package.\n *\n * Checks both the dependencies and optionalDependencies of a package to see if\n * the specified dependency name is listed.\n *\n * @param depName - The name of the dependency to check\n * @param pkg - The package to search for the dependency in\n * @returns True if the dependency is found in either dependencies or optionalDependencies, false otherwise\n */\n protected isProdDependency(depName: string, pkg: ProdDepType): boolean {\n const prodDeps = { ...pkg.dependencies, ...pkg.optionalDependencies }\n return prodDeps[depName] != null\n }\n\n protected async locatePackageWithVersion(depTree: Pick<ProdDepType, \"name\" | \"version\" | \"path\">): Promise<{ packageDir: string; packageJson: PackageJson } | null> {\n const result = await this.cache.locatePackageVersion({\n parentDir: depTree.path,\n pkgName: depTree.name,\n requiredRange: depTree.version,\n })\n return result\n }\n /**\n * Parses a dependency identifier string into name and version components.\n *\n * Handles both scoped packages (e.g., \"@scope/pkg@1.2.3\") and regular packages (e.g., \"pkg@1.2.3\").\n * If the identifier is malformed or cannot be parsed, defaults to treating the entire string as\n * the package name with an \"unknown\" version.\n */\n protected parseNameVersion(identifier: string): { name: string; version: string } {\n let at: number\n if (identifier.startsWith(\"@\")) {\n // Scoped package: find the version separator after the scope (e.g. \"@scope/pkg@1.2.3\")\n const slashIndex = identifier.indexOf(\"/\")\n if (slashIndex === -1) {\n return { name: identifier, version: \"unknown\" }\n }\n at = identifier.indexOf(\"@\", slashIndex + 1)\n } else {\n at = identifier.indexOf(\"@\")\n }\n if (at <= 0) {\n return { name: identifier, version: \"unknown\" }\n }\n return { name: identifier.slice(0, at), version: identifier.slice(at + 1) }\n }\n\n /**\n * Retrieves the dependency tree and handles workspace package self-references.\n *\n * If the project is a workspace project, this method removes the root package's self-reference\n * from the dependency tree to avoid circular dependencies. It promotes the root package's\n * direct dependencies to the top level of the tree.\n *\n * @param tree - The original dependency tree\n * @param packageName - The name of the package to check for and remove from the tree\n * @returns The extracted dependency subtree\n */\n protected getTreeFromWorkspaces(tree: ProdDepType, packageName: string): ProdDepType {\n if (tree.workspaces && tree.dependencies) {\n for (const [key, value] of Object.entries(tree.dependencies)) {\n if (key === packageName) {\n return value\n }\n }\n }\n\n return tree\n }\n\n private transformToHoisterTree(obj: DependencyGraph, key: string, nodes: Map<string, HoisterTree> = new Map()): HoisterTree {\n let node = nodes.get(key)\n const { name, version } = this.parseNameVersion(key)\n\n if (!node) {\n node = {\n name,\n identName: name,\n reference: version,\n dependencies: new Set<HoisterTree>(),\n peerNames: new Set<string>(),\n }\n\n nodes.set(key, node)\n\n const deps = (obj[key] || {}).dependencies || []\n for (const dep of deps) {\n const child = this.transformToHoisterTree(obj, dep, nodes)\n node.dependencies.add(child)\n }\n }\n\n return node\n }\n\n private async _getNodeModules(dependencies: Set<HoisterResult>, result: NodeModuleInfo[], archFilter?: ArchFilter) {\n if (dependencies.size === 0) {\n return\n }\n\n for (const d of dependencies.values()) {\n const reference = [...d.references][0]\n const key = `${d.name}@${reference}`\n // Normalize the path to handle mixed separators from pnpm JSON output on Windows\n const rawPath = this.allDependencies.get(key)?.path\n const p = rawPath != null ? path.normalize(rawPath) : undefined\n if (p === undefined) {\n this.cache.logSummary[LogMessageByKey.PKG_NOT_FOUND].push(key)\n continue\n }\n\n // fix npm list issue\n // https://github.com/npm/cli/issues/8535\n if (!(await this.cache.exists[p])) {\n this.logMissingDependency(key)\n continue\n }\n\n const dir = await this.cache.realPath[p]\n\n // Drop packages whose declared `cpu`/`os` is incompatible with the target arch/platform (and their\n // subtree). npm/pnpm install only the host's platform-specific optional packages, so without this an\n // arm64-only binary (e.g. `@esbuild/darwin-arm64`) would be bundled into the x64 build too — and into\n // both slices of a universal build, which `@electron/universal` then refuses to merge. Reuses the\n // memoized `package.json` cache populated during collection.\n if (archFilter != null) {\n const pkgJson = await this.cache.json[path.join(dir, \"package.json\")]\n if (pkgJson != null && !isPackageCompatible(pkgJson, archFilter.cpu, archFilter.os)) {\n this.cache.logSummary[LogMessageByKey.PKG_INCOMPATIBLE_PLATFORM].push(key)\n continue\n }\n }\n\n const node: NodeModuleInfo = {\n name: d.name,\n version: reference,\n dir,\n }\n result.push(node)\n if (d.dependencies.size > 0) {\n node.dependencies = []\n await this._getNodeModules(d.dependencies, node.dependencies, archFilter)\n }\n }\n result.sort((a, b) => a.name.localeCompare(b.name))\n }\n\n protected logMissingDependency(pkgName: string) {\n const PLATFORM_PACKAGE_RE = /(linux|win32|darwin|freebsd|android)[-_](x64|arm64|ia32|arm|ppc64|s390x|loong64|riscv64|universal)/\n const diskLogKey = PLATFORM_PACKAGE_RE.test(pkgName) ? LogMessageByKey.PKG_OPTIONAL_PLATFORM_NOT_INSTALLED : LogMessageByKey.PKG_NOT_ON_DISK\n this.cache.logSummary[diskLogKey].push(pkgName)\n }\n\n protected async asyncExec(command: string, args: string[], cwd: string = this.rootDir): Promise<{ stdout: string | undefined; stderr: string | undefined }> {\n const file = await this.tempDirManager.getTempFile({ prefix: \"exec-\", suffix: \".txt\" })\n try {\n await this.streamCollectorCommandToFile(command, args, cwd, file)\n const result = await _fsExtra.readFile(file, { encoding: \"utf8\" })\n return { stdout: result?.trim(), stderr: undefined }\n } catch (error: any) {\n log.debug({ error: error.message }, \"failed to execute command\")\n return { stdout: undefined, stderr: error.message }\n }\n }\n\n /**\n * Executes a package-manager command and streams its stdout to a file.\n *\n * Delegates the spawn/stream/flush mechanics (including the Windows `powershell.exe -EncodedCommand`\n * wrapping) to {@link streamSpawnToFile}, and layers on the collector-specific interpretation of the\n * result: corepack is silenced for these invocations, `npm list` exit code 1 is tolerated, and any\n * stderr is surfaced as a collector warning only when the exit code is genuinely unexpected.\n *\n * @param command - The command to execute\n * @param args - Array of command-line arguments\n * @param cwd - The working directory to execute the command in\n * @param tempOutputFile - The path to the temporary file where stdout will be written\n * @returns Promise that resolves when the command completes successfully or rejects if it fails\n * @throws {Error} If the child process spawn fails or exits with a non-zero, unexpected code\n */\n protected async streamCollectorCommandToFile(command: string, args: string[], cwd: string, tempOutputFile: string) {\n // Derive execName from the original command so the npm-list shouldIgnore check below keys off the\n // real invocation (e.g. \"npm\"), not the \"powershell\" wrapper streamSpawnToFile uses on Windows.\n const execName = path.basename(command, path.extname(command))\n\n const { code, stderr } = await streamSpawnToFile(command, args, cwd, tempOutputFile, {\n // Package manager invocations do not need signing/publishing credentials. Silence corepack:\n // strict=0 so a project's `packageManager` pin can't abort our read-only queries, and the\n // download prompt/notice off so corepack doesn't flood stdout/stderr with activation chatter.\n ...stripSensitiveEnvVars(process.env),\n COREPACK_ENABLE_STRICT: \"0\",\n COREPACK_ENABLE_DOWNLOAD_PROMPT: \"0\",\n })\n\n // https://github.com/npm/npm/issues/17624\n const shouldIgnore = code === 1 && \"npm\" === execName.toLowerCase() && args.includes(\"list\")\n if (shouldIgnore) {\n log.debug(null, \"`npm list` returned non-zero exit code, but it MIGHT be expected (https://github.com/npm/npm/issues/17624). Check stderr for details.\")\n }\n if (stderr.length > 0) {\n log.debug({ stderr }, \"note: there was node module collector output on stderr\")\n // Only surface stderr as a user-visible warning when the exit code itself is unexpected.\n // When shouldIgnore is true (npm list exit code 1) the stderr is an anticipated side\n // effect of package-manager features like yarn resolutions or npm overrides that cause\n // npm to report ELSPROBLEMS for aliased packages it considers \"invalid\".\n if (!shouldIgnore) {\n this.cache.logSummary[LogMessageByKey.PKG_COLLECTOR_OUTPUT].push(stderr)\n }\n }\n if (code !== 0 && !shouldIgnore) {\n throw new Error(`Node module collector process exited with code ${code}:\\n${stderr}`)\n }\n }\n}\n"]}
|
|
@@ -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"}
|