Skip to content

Commit a74cfc8

Browse files
committed
chore: finish implementing :: in #committish
This iterates on the spec outlined by @coreyfarrel in #46. For each :: separated item: * If the item has no : then it is a commit-ish * If the item has : then split into name and value. * If the name is semver then do semver lookup of ref or tag * If the name is path then use the value as the subdir to install from. * If the name is unknown then warn that the name-value pair is being ignored. This loop errors if duplicate values are found. Unknown values log a warning instead of erroring.
1 parent 5d9c044 commit a74cfc8

File tree

3 files changed

+96
-9
lines changed

3 files changed

+96
-9
lines changed

lib/npa.js

+40-9
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const semver = require('semver')
99
const path = global.FAKE_WINDOWS ? require('path').win32 : require('path')
1010
const validatePackageName = require('validate-npm-package-name')
1111
const { homedir } = require('os')
12+
const log = require('proc-log')
1213

1314
const isWindows = process.platform === 'win32' || global.FAKE_WINDOWS
1415
const hasSlashes = isWindows ? /\\|[/]/ : /[/]/
@@ -120,6 +121,7 @@ function Result (opts) {
120121
}
121122
this.gitRange = opts.gitRange
122123
this.gitCommittish = opts.gitCommittish
124+
this.gitSubdir = opts.gitSubdir
123125
this.hosted = opts.hosted
124126
}
125127

@@ -155,16 +157,45 @@ Result.prototype.toJSON = function () {
155157
}
156158

157159
function setGitCommittish (res, committish) {
158-
if (committish != null && committish.includes('::')) {
159-
const parts = committish.split('::')
160-
committish = parts[0]
161-
res.gitSubdir = `/${parts[1]}`
162-
}
163-
if (committish != null && committish.length >= 7 && committish.slice(0, 7) === 'semver:') {
164-
res.gitRange = decodeURIComponent(committish.slice(7))
160+
if (!committish) {
165161
res.gitCommittish = null
166-
} else {
167-
res.gitCommittish = committish === '' ? null : committish
162+
return res
163+
}
164+
165+
// for each :: separated item:
166+
for (const part of committish.split('::')) {
167+
// if the item has no : the n it is a commit-ish
168+
if (!part.includes(':')) {
169+
if (res.gitRange) {
170+
throw new Error('cannot override existing semver range with a committish')
171+
}
172+
if (res.gitCommittish) {
173+
throw new Error('cannot override existing committish with a second committish')
174+
}
175+
res.gitCommittish = part
176+
continue
177+
}
178+
// split on name:value
179+
const [name, value] = part.split(':')
180+
// if name is semver do semver lookup of ref or tag
181+
if (name === 'semver') {
182+
if (res.gitCommittish) {
183+
throw new Error('cannot override existing committish with a semver range')
184+
}
185+
if (res.gitRange) {
186+
throw new Error('cannot override existing semver range with a second semver range')
187+
}
188+
res.gitRange = decodeURIComponent(value)
189+
continue
190+
}
191+
if (name === 'path') {
192+
if (res.gitSubdir) {
193+
throw new Error('cannot override existing path with a second path')
194+
}
195+
res.gitSubdir = `/${value}`
196+
continue
197+
}
198+
log.warn('npm-package-arg', `ignoring unknown key "${name}"`)
168199
}
169200

170201
return res

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
],
1313
"dependencies": {
1414
"hosted-git-info": "^5.0.0",
15+
"proc-log": "^2.0.1",
1516
"semver": "^7.3.5",
1617
"validate-npm-package-name": "^4.0.0"
1718
},

test/basic.js

+55
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,41 @@ t.test('basic', function (t) {
298298
raw: 'user/foo#semver:^1.2.3',
299299
},
300300

301+
'user/foo#path:dist': {
302+
name: null,
303+
escapedName: null,
304+
type: 'git',
305+
saveSpec: 'github:user/foo#path:dist',
306+
fetchSpec: null,
307+
gitCommittish: null,
308+
gitSubdir: '/dist',
309+
raw: 'user/foo#path:dist',
310+
},
311+
312+
'user/foo#1234::path:dist': {
313+
name: null,
314+
escapedName: null,
315+
type: 'git',
316+
saveSpec: 'github:user/foo#1234::path:dist',
317+
fetchSpec: null,
318+
gitCommittish: '1234',
319+
gitRange: null,
320+
gitSubdir: '/dist',
321+
raw: 'user/foo#1234::path:dist',
322+
},
323+
324+
'user/foo#notimplemented:value': {
325+
name: null,
326+
escapedName: null,
327+
type: 'git',
328+
saveSpec: 'github:user/foo#notimplemented:value',
329+
fetchSpec: null,
330+
gitCommittish: null,
331+
gitRange: null,
332+
gitSubdir: null,
333+
raw: 'user/foo#notimplemented:value',
334+
},
335+
301336
'git+file://path/to/repo#1.2.3': {
302337
name: null,
303338
escapedName: null,
@@ -705,5 +740,25 @@ t.test('error message', t => {
705740
message: 'Invalid package name "lodash.has " of package "lodash.has @^4": name cannot contain leading or trailing spaces; name can only contain URL-friendly characters.',
706741
})
707742

743+
t.throws(() => npa('user/foo#1234::semver:^1.2.3'), {
744+
message: 'cannot override existing committish with a semver range',
745+
})
746+
747+
t.throws(() => npa('user/foo#semver:^1.2.3::1234'), {
748+
message: 'cannot override existing semver range with a committish',
749+
})
750+
751+
t.throws(() => npa('user/foo#path:skipped::path:dist'), {
752+
message: 'cannot override existing path with a second path',
753+
})
754+
755+
t.throws(() => npa('user/foo#1234::5678'), {
756+
message: 'cannot override existing committish with a second committish',
757+
})
758+
759+
t.throws(() => npa('user/foo#semver:^1.0.0::semver:^2.0.0'), {
760+
message: 'cannot override existing semver range with a second semver range',
761+
})
762+
708763
t.end()
709764
})

0 commit comments

Comments
 (0)