diff --git a/src/plugins.ts b/src/plugins.ts index 79efe041..8bcfd7d2 100644 --- a/src/plugins.ts +++ b/src/plugins.ts @@ -81,6 +81,22 @@ function notifyUser(plugin: Config, output: Output): void { } } +export function normaliseTag(jitPlugins: Record, modifiedPlugins: Plugin[], p: Interfaces.UserPlugin) { + // a not valid tag indicates that it's a dist-tag like 'latest' + if (!valid(p.tag)) return `${p.name}@${p.tag}` + + if (p.tag && valid(p.tag) && jitPlugins[p.name] && valid(jitPlugins[p.name]) && gt(p.tag, jitPlugins[p.name])) { + // The user has installed a version of the JIT plugin that is newer than the one + // specified by the root plugin's JIT configuration. In this case, we want to + // keep the version installed by the user. + return `${p.name}@${p.tag}` + } + + const tag = jitPlugins[p.name] ?? p.tag + modifiedPlugins.push({...p, tag}) + return `${p.name}@${tag}` +} + export default class Plugins { public config: Interfaces.Config public readonly npm: NPM @@ -379,21 +395,7 @@ export default class Plugins { const modifiedPlugins: Plugin[] = [] if (npmPlugins.length > 0) { await this.npm.install( - npmPlugins.map((p) => { - // a not valid tag indicates that it's a dist-tag like 'latest' - if (!valid(p.tag)) return `${p.name}@${p.tag}` - - if (p.tag && valid(p.tag) && jitPlugins[p.name] && gt(p.tag, jitPlugins[p.name])) { - // The user has installed a version of the JIT plugin that is newer than the one - // specified by the root plugin's JIT configuration. In this case, we want to - // keep the version installed by the user. - return `${p.name}@${p.tag}` - } - - const tag = jitPlugins[p.name] ?? p.tag - modifiedPlugins.push({...p, tag}) - return `${p.name}@${tag}` - }), + npmPlugins.map((p) => normaliseTag(jitPlugins, modifiedPlugins, p)), {cwd: this.config.dataDir, logLevel: this.logLevel, prod: true}, ) } diff --git a/test/plugins.test.ts b/test/plugins.test.ts index 60c9a323..f853053f 100644 --- a/test/plugins.test.ts +++ b/test/plugins.test.ts @@ -3,7 +3,7 @@ import {expect} from 'chai' import {join} from 'node:path' import {createSandbox, SinonSandbox, SinonSpy} from 'sinon' -import Plugins from '../src/plugins.js' +import Plugins, {normaliseTag} from '../src/plugins.js' describe('Plugins', () => { let sandbox: SinonSandbox @@ -189,4 +189,65 @@ describe('Plugins', () => { expect(saveStub.calledWithExactly(userPJSON)).to.be.true }) }) + + describe('normaliseTag', () => { + it('should keep invalid semver tag', async () => { + const cases: { + expected: string + expectedModifiedPluginsLength?: number + jitPlugins: Record + modifiedPlugins: (Interfaces.LinkedPlugin | Interfaces.UserPlugin)[] + tag: string + }[] = [ + { + expected: 'latest', + jitPlugins: {}, + modifiedPlugins: [], + tag: 'latest', + }, + { + expected: 'latest', + jitPlugins: {'@oclif/plugin-user': '*'}, + modifiedPlugins: [], + tag: 'latest', + }, + { + expected: '0.0.2', + jitPlugins: {'@oclif/plugin-user': '0.0.1'}, + modifiedPlugins: [], + tag: '0.0.2', + }, + { + expected: '0.0.2', + expectedModifiedPluginsLength: 1, + jitPlugins: {'@oclif/plugin-user': '0.0.2'}, + modifiedPlugins: [], + tag: '0.0.1', + }, + { + expected: '0.0.1', + expectedModifiedPluginsLength: 1, + jitPlugins: {'@oclif/plugin-user': '0.0.1'}, + modifiedPlugins: [], + tag: '0.0.1', + }, + { + expected: 'latest', + expectedModifiedPluginsLength: 1, + jitPlugins: {'@oclif/plugin-user': 'latest'}, + modifiedPlugins: [], + tag: '0.0.1', + }, + ] + for (const c of cases) { + const actual = normaliseTag(c.jitPlugins, c.modifiedPlugins, { + name: '@oclif/plugin-user', + tag: c.tag, + type: 'user', + }) + expect(actual).to.equal(`@oclif/plugin-user@${c.expected}`) + expect(c.modifiedPlugins).to.lengthOf(c.expectedModifiedPluginsLength || 0) + } + }) + }) })