From 4e3fe7b738d1fe042d1082bb50b6a0d2b7918cfd Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Mon, 15 Sep 2025 09:39:41 +0200 Subject: [PATCH] Rely on npm version rather than node version to determine which scanner to use. Fixes #46 --- packages/safe-chain/bin/aikido-npm.js | 13 ++++++- .../npm/createPackageManager.js | 35 ++++++++++--------- .../npx/createPackageManager.js | 1 - .../pnpm/createPackageManager.js | 2 -- .../yarn/createPackageManager.js | 1 - 5 files changed, 30 insertions(+), 22 deletions(-) diff --git a/packages/safe-chain/bin/aikido-npm.js b/packages/safe-chain/bin/aikido-npm.js index db6469f..4176db1 100755 --- a/packages/safe-chain/bin/aikido-npm.js +++ b/packages/safe-chain/bin/aikido-npm.js @@ -1,8 +1,19 @@ #!/usr/bin/env node +import { execSync } from "child_process"; import { main } from "../src/main.js"; import { initializePackageManager } from "../src/packagemanager/currentPackageManager.js"; const packageManagerName = "npm"; -initializePackageManager(packageManagerName, process.versions.node); +initializePackageManager(packageManagerName, getNpmVersion()); await main(process.argv.slice(2)); + +function getNpmVersion() { + try { + return execSync("npm --version").toString().trim(); + } catch { + // Default to 0.0.0 if npm is not found + // That way we don't use any unsupported features + return "0.0.0"; + } +} diff --git a/packages/safe-chain/src/packagemanager/npm/createPackageManager.js b/packages/safe-chain/src/packagemanager/npm/createPackageManager.js index d0a862e..bf38209 100644 --- a/packages/safe-chain/src/packagemanager/npm/createPackageManager.js +++ b/packages/safe-chain/src/packagemanager/npm/createPackageManager.js @@ -14,10 +14,13 @@ import { } from "./utils/npmCommands.js"; export function createNpmPackageManager(version) { - const supportedScanners = - getMajorVersion(version) >= 22 - ? npm22AndAboveSupportedScanners - : npm21AndBelowSupportedScanners; + // From npm v10.4.0 onwards, the npm commands output detailed information + // when using the --dry-run flag. + // We use that information to scan for dependency changes. + // For older versions of npm we have to rely on parsing the command arguments. + const supportedScanners = isPriorToNpm10_4(version) + ? npm10_3AndBelowSupportedScanners + : npm10_4AndAboveSupportedScanners; function isSupportedCommand(args) { const scanner = findDependencyScannerForCommand(supportedScanners, args); @@ -30,14 +33,13 @@ export function createNpmPackageManager(version) { } return { - getWarningMessage: () => warnForLimitedSupport(version), runCommand: runNpm, isSupportedCommand, getDependencyUpdatesForCommand, }; } -const npm22AndAboveSupportedScanners = { +const npm10_4AndAboveSupportedScanners = { [npmInstallCommand]: dryRunScanner(), [npmUpdateCommand]: dryRunScanner(), [npmCiCommand]: dryRunScanner(), @@ -53,23 +55,22 @@ const npm22AndAboveSupportedScanners = { [npmInstallCiTestCommand]: dryRunScanner({ dryRunCommand: npmCiCommand }), }; -const npm21AndBelowSupportedScanners = { +const npm10_3AndBelowSupportedScanners = { [npmInstallCommand]: commandArgumentScanner(), [npmUpdateCommand]: commandArgumentScanner(), [npmExecCommand]: commandArgumentScanner({ ignoreDryRun: true }), // exec command doesn't support dry-run }; -function warnForLimitedSupport(version) { - if (getMajorVersion(version) >= 22) { - return null; +function isPriorToNpm10_4(version) { + try { + const [major, minor] = version.split(".").map(Number); + if (major < 10) return true; + if (major === 10 && minor < 4) return true; + return false; + } catch { + // Default to true: if version parsing fails, assume it's an older version + return true; } - - return `Aikido-npm will only scan the arguments of the install command for Node.js version prior to version 22. -Please update your Node.js version to 22 or higher for full coverage. Current version: v${version}`; -} - -function getMajorVersion(version) { - return parseInt(version.split(".")[0]); } function findDependencyScannerForCommand(scanners, args) { diff --git a/packages/safe-chain/src/packagemanager/npx/createPackageManager.js b/packages/safe-chain/src/packagemanager/npx/createPackageManager.js index 6e7499a..a3319fa 100644 --- a/packages/safe-chain/src/packagemanager/npx/createPackageManager.js +++ b/packages/safe-chain/src/packagemanager/npx/createPackageManager.js @@ -5,7 +5,6 @@ export function createNpxPackageManager() { const scanner = commandArgumentScanner(); return { - getWarningMessage: () => null, runCommand: runNpx, isSupportedCommand: (args) => scanner.shouldScan(args), getDependencyUpdatesForCommand: (args) => scanner.scan(args), diff --git a/packages/safe-chain/src/packagemanager/pnpm/createPackageManager.js b/packages/safe-chain/src/packagemanager/pnpm/createPackageManager.js index 325f1ca..15cb628 100644 --- a/packages/safe-chain/src/packagemanager/pnpm/createPackageManager.js +++ b/packages/safe-chain/src/packagemanager/pnpm/createPackageManager.js @@ -6,7 +6,6 @@ const scanner = commandArgumentScanner(); export function createPnpmPackageManager() { return { - getWarningMessage: () => null, runCommand: (args) => runPnpmCommand(args, "pnpm"), isSupportedCommand: (args) => matchesCommand(args, "add") || @@ -26,7 +25,6 @@ export function createPnpmPackageManager() { export function createPnpxPackageManager() { return { - getWarningMessage: () => null, runCommand: (args) => runPnpmCommand(args, "pnpx"), isSupportedCommand: () => true, getDependencyUpdatesForCommand: (args) => diff --git a/packages/safe-chain/src/packagemanager/yarn/createPackageManager.js b/packages/safe-chain/src/packagemanager/yarn/createPackageManager.js index 37e1971..f49c763 100644 --- a/packages/safe-chain/src/packagemanager/yarn/createPackageManager.js +++ b/packages/safe-chain/src/packagemanager/yarn/createPackageManager.js @@ -5,7 +5,6 @@ const scanner = commandArgumentScanner(); export function createYarnPackageManager() { return { - getWarningMessage: () => null, runCommand: runYarnCommand, isSupportedCommand: (args) => matchesCommand(args, "add") ||