diff options
| -rw-r--r-- | lua/mason-core/installer/managers/npm.lua | 24 | ||||
| -rw-r--r-- | lua/mason-core/semver.lua | 9 | ||||
| -rw-r--r-- | lua/mason-vendor/semver.lua | 11 | ||||
| -rw-r--r-- | tests/mason-core/installer/managers/npm_spec.lua | 30 |
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() |
