aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lua/mason-core/installer/managers/npm.lua24
-rw-r--r--lua/mason-core/semver.lua9
-rw-r--r--lua/mason-vendor/semver.lua11
-rw-r--r--tests/mason-core/installer/managers/npm_spec.lua30
4 files changed, 69 insertions, 5 deletions
diff --git a/lua/mason-core/installer/managers/npm.lua b/lua/mason-core/installer/managers/npm.lua
index 61cf3a38..f8312829 100644
--- a/lua/mason-core/installer/managers/npm.lua
+++ b/lua/mason-core/installer/managers/npm.lua
@@ -4,10 +4,26 @@ local installer = require "mason-core.installer"
local log = require "mason-core.log"
local path = require "mason-core.path"
local platform = require "mason-core.platform"
+local semver = require "mason-core.semver"
+local spawn = require "mason-core.spawn"
local M = {}
---@async
+---@param predicate fun(npm_version: Semver): boolean
+---@return boolean
+local function npm_version_satisfies(predicate)
+ return Result.try(function(try)
+ local npm_versions = try(spawn.npm { "version", "--json" }).stdout
+ ---@type { npm: string }
+ local versions = try(Result.pcall(vim.json.decode, npm_versions))
+ ---@type Semver
+ local npm_version = try(semver.parse(versions.npm))
+ return predicate(npm_version)
+ end):get_or_else(false)
+end
+
+---@async
function M.init()
log.debug "npm: init"
local ctx = installer.context()
@@ -18,7 +34,7 @@ function M.init()
"--scope=mason",
})
- -- Use global-style. The reasons for this are:
+ -- Use shallow install-strategy. The reasons for this are:
-- a) To avoid polluting the executables (aka bin-links) that npm creates.
-- b) The installation is, after all, more similar to a "global" installation. We don't really gain
-- any of the benefits of not using global style (e.g., deduping the dependency tree).
@@ -27,7 +43,11 @@ function M.init()
-- is a bit unreliable across npm versions (especially <7), so we take extra measures to avoid
-- inadvertently polluting global npm config.
try(Result.pcall(function()
- ctx.fs:append_file(".npmrc", "global-style=true")
+ if npm_version_satisfies(_.gte(semver.new "9.0.0")) then
+ ctx.fs:append_file(".npmrc", "\ninstall-strategy=shallow")
+ else
+ ctx.fs:append_file(".npmrc", "\nglobal-style=true")
+ end
end))
ctx.stdio_sink.stdout "Initialized npm root\n"
diff --git a/lua/mason-core/semver.lua b/lua/mason-core/semver.lua
index e10f006b..635b7e36 100644
--- a/lua/mason-core/semver.lua
+++ b/lua/mason-core/semver.lua
@@ -4,9 +4,14 @@ local semver = require "mason-vendor.semver"
local M = {}
---@param version string
-function M.parse(version)
+function M.new(version)
version = version:gsub("^v", "")
- return Result.pcall(semver, version)
+ return semver(version)
+end
+
+---@param version string
+function M.parse(version)
+ return Result.pcall(M.new, version)
end
return M
diff --git a/lua/mason-vendor/semver.lua b/lua/mason-vendor/semver.lua
index b61e3b40..189515df 100644
--- a/lua/mason-vendor/semver.lua
+++ b/lua/mason-vendor/semver.lua
@@ -144,18 +144,28 @@ local function smallerPrerelease(mine, other)
return smallerIdList(splitByDot(mine), splitByDot(other))
end
+---@class ISemver
local methods = {}
+---@return Semver
function methods:nextMajor()
return semver(self.major + 1, 0, 0)
end
+---@return Semver
function methods:nextMinor()
return semver(self.major, self.minor + 1, 0)
end
+---@return Semver
function methods:nextPatch()
return semver(self.major, self.minor, self.patch + 1)
end
+---@class Semver : ISemver
+---@field major integer
+---@field minor integer
+---@field patch integer
+---@field prerelease? string
+---@field build? string
local mt = { __index = methods }
function mt:__eq(other)
return self.major == other.major and
@@ -188,6 +198,7 @@ function mt:__tostring()
return table.concat(buffer)
end
+---@return Semver
local function new(major, minor, patch, prerelease, build)
assert(major, "At least one parameter is needed")
diff --git a/tests/mason-core/installer/managers/npm_spec.lua b/tests/mason-core/installer/managers/npm_spec.lua
index 1555b37d..4f81132b 100644
--- a/tests/mason-core/installer/managers/npm_spec.lua
+++ b/tests/mason-core/installer/managers/npm_spec.lua
@@ -1,12 +1,19 @@
+local Result = require "mason-core.result"
local installer = require "mason-core.installer"
local match = require "luassert.match"
local npm = require "mason-core.installer.managers.npm"
+local spawn = require "mason-core.spawn"
local stub = require "luassert.stub"
describe("npm manager", function()
it("should init package.json", function()
local ctx = create_dummy_context()
stub(ctx.fs, "append_file")
+ stub(spawn, "npm")
+ spawn.npm.returns(Result.success {})
+ spawn.npm.on_call_with({ "version", "--json" }).returns(Result.success {
+ stdout = [[ { "npm": "8.1.0" } ]],
+ })
installer.exec_in_context(ctx, function()
npm.init()
end)
@@ -18,7 +25,28 @@ describe("npm manager", function()
"--scope=mason",
}
assert.spy(ctx.fs.append_file).was_called(1)
- assert.spy(ctx.fs.append_file).was_called_with(match.is_ref(ctx.fs), ".npmrc", "global-style=true")
+ assert.spy(ctx.fs.append_file).was_called_with(match.is_ref(ctx.fs), ".npmrc", "\nglobal-style=true")
+ end)
+
+ it("should use install-strategy on npm >= 9", function()
+ local ctx = create_dummy_context()
+ stub(ctx.fs, "append_file")
+ stub(spawn, "npm")
+ spawn.npm.returns(Result.success {})
+ spawn.npm.on_call_with({ "version", "--json" }).returns(Result.success {
+ stdout = [[ { "npm": "9.1.0" } ]],
+ })
+ installer.exec_in_context(ctx, function()
+ npm.init()
+ end)
+
+ assert.spy(ctx.spawn.npm).was_called(1)
+ assert.spy(ctx.spawn.npm).was_called_with {
+ "init",
+ "--yes",
+ "--scope=mason",
+ }
+ assert.spy(ctx.fs.append_file).was_called_with(match.is_ref(ctx.fs), ".npmrc", "\ninstall-strategy=shallow")
end)
it("should install", function()