class PackageManager
Detects and invokes npm-compatible package managers without replacing them.
Definitions
def self.detect(configuration, environment: ENV)
Detect the package manager selected by a project.
Signature
-
parameter
configurationConfiguration The project configuration.
-
parameter
environmentHash Environment variables used for explicit selection.
-
returns
PackageManager The selected package-manager wrapper.
-
raises
ConfigurationError If selection is ambiguous or unsupported.
Implementation
def self.detect(configuration, environment: ENV)
if name = environment["NODE_PACKAGE_MANAGER"]
return new(configuration.root, name)
end
if declaration = configuration.package_json["packageManager"]
unless declaration.is_a?(String)
raise ConfigurationError, "packageManager must be a string!"
end
return new(configuration.root, declaration.split("@", 2).first)
end
managers = LOCK_FILES.filter_map do |path, manager|
manager if (configuration.root + path).file?
end.uniq
if managers.size > 1
raise ConfigurationError, "Multiple package manager lock files were found: #{managers.join(', ')}!"
end
new(configuration.root, managers.first || "npm")
end
def initialize(root, name)
Initialize a package-manager wrapper.
Signature
-
parameter
rootString | Pathname The directory in which commands will run.
-
parameter
nameString The package-manager executable name.
-
raises
ConfigurationError If the package manager is unsupported.
Implementation
def initialize(root, name)
unless SUPPORTED.include?(name)
raise ConfigurationError, "Unsupported package manager: #{name.inspect}!"
end
@root = root
@name = name
end
attr :root
Signature
-
attribute
String | Pathname The directory in which commands run.
attr :name
Signature
-
attribute
String The selected package-manager name.
def install(frozen: false)
Install the project's dependencies.
Signature
-
parameter
frozenBoolean Whether the lock file must remain unchanged.
-
raises
Error If the package-manager command fails.
Implementation
def install(frozen: false)
execute(install_command(frozen: frozen))
end
def run(script)
Run a package script.
Signature
-
parameter
scriptString The script name from
package.json.-
raises
ArgumentError If the script name is empty.
-
raises
Error If the package-manager command fails.
Implementation
def run(script)
unless script.is_a?(String) && !script.empty?
raise ArgumentError, "Script must be a non-empty string!"
end
execute([@name, "run", script])
end
def install_command(frozen: false)
Construct the installation command for the selected package manager.
Signature
-
parameter
frozenBoolean Whether the lock file must remain unchanged.
-
returns
Array(String) The command and arguments to execute.
Implementation
def install_command(frozen: false)
command = case @name
when "npm"
frozen ? ["npm", "ci"] : ["npm", "install"]
when "pnpm"
["pnpm", "install"]
when "yarn"
["yarn", "install"]
when "bun"
["bun", "install"]
end
if frozen && @name != "npm"
command << (@name == "yarn" ? "--immutable" : "--frozen-lockfile")
end
command
end