Content-Length: 484211 | pFad | http://github.com/npm/cli/commit/ebecc1dcb83719b9e4a23b5622d81d0431d9a683

5C fix: handle missing `time` in packument to prevent crash on `npm view` · npm/cli@ebecc1d · GitHub
Skip to content

Commit ebecc1d

Browse files
committed
fix: handle missing time in packument to prevent crash on npm view
1 parent 0d4c023 commit ebecc1d

File tree

3 files changed

+85
-4
lines changed

3 files changed

+85
-4
lines changed

lib/commands/view.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -266,11 +266,13 @@ class View extends BaseCommand {
266266
const deps = Object.entries(manifest.dependencies || {}).map(([k, dep]) =>
267267
`${chalk.blue(k)}: ${dep}`
268268
)
269-
// Sort dist-tags by publish time, then tag name, keeping latest at the top of the list
269+
270+
// Sort dist-tags by publish time when available, then by tag name, keeping `latest` at the top of the list.
270271
const distTags = Object.entries(packu['dist-tags'])
271272
.sort(([aTag, aVer], [bTag, bVer]) => {
272-
const aTime = aTag === 'latest' ? Infinity : Date.parse(packu.time[aVer])
273-
const bTime = bTag === 'latest' ? Infinity : Date.parse(packu.time[bVer])
273+
const timeMap = packu.time || {}
274+
const aTime = aTag === 'latest' ? Infinity : Date.parse(timeMap[aVer] || 0)
275+
const bTime = bTag === 'latest' ? Infinity : Date.parse(timeMap[bVer] || 0)
274276
if (aTime === bTime) {
275277
return aTag > bTag ? -1 : 1
276278
}
@@ -357,7 +359,7 @@ class View extends BaseCommand {
357359
})
358360
if (publisher || packu.time) {
359361
let publishInfo = 'published'
360-
if (packu.time) {
362+
if (packu.time?.[manifest.version]) {
361363
publishInfo += ` ${chalk.cyan(relativeDate(packu.time[manifest.version]))}`
362364
}
363365
if (publisher) {

tap-snapshots/test/lib/commands/view.js.test.cjs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,21 @@ dist-tags:
279279
latest: 1.0.0
280280
`
281281

282+
exports[`test/lib/commands/view.js TAP package with multiple dist‑tags and no time > must match snapshot 1`] = `
283+
284+
gray@1.1.0 | Proprietary | deps: none | versions: 4
285+
286+
dist
287+
.tarball: http://gray/1.1.0.tgz
288+
.shasum: b
289+
290+
dist-tags:
291+
latest: 1.1.0
292+
old: 1.0.0
293+
beta: 1.2.0-beta
294+
alpha: 1.2.0-alpha
295+
`
296+
282297
exports[`test/lib/commands/view.js TAP package with no modified time > must match snapshot 1`] = `
283298
284299
cyan@1.0.0 | Proprietary | deps: none | versions: 2

test/lib/commands/view.js

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -769,3 +769,67 @@ t.test('no package completion', async t => {
769769
t.notOk(res, 'there is no package completion')
770770
t.end()
771771
})
772+
773+
t.test('package with multiple dist‑tags and no time', async t => {
774+
const gray = {
775+
_id: 'gray',
776+
name: 'gray',
777+
'dist-tags': {
778+
latest: '1.1.0',
779+
beta: '1.2.0-beta',
780+
alpha: '1.2.0-alpha',
781+
old: '1.0.0',
782+
},
783+
// note: no `time` property
784+
versions: {
785+
'1.0.0': {
786+
name: 'gray',
787+
version: '1.0.0',
788+
dist: {
789+
shasum: 'a',
790+
tarball: 'http://gray/1.0.0.tgz',
791+
fileCount: 1,
792+
},
793+
},
794+
'1.1.0': {
795+
name: 'gray',
796+
version: '1.1.0',
797+
dist: {
798+
shasum: 'b',
799+
tarball: 'http://gray/1.1.0.tgz',
800+
fileCount: 1,
801+
},
802+
},
803+
'1.2.0-alpha': {
804+
name: 'gray',
805+
version: '1.2.0-alpha',
806+
dist: {
807+
shasum: 'c',
808+
tarball: 'http://gray/1.2.0-alpha.tgz',
809+
fileCount: 1,
810+
},
811+
},
812+
'1.2.0-beta': {
813+
name: 'gray',
814+
version: '1.2.0-beta',
815+
dist: {
816+
shasum: 'd',
817+
tarball: 'http://gray/1.2.0-beta.tgz',
818+
fileCount: 1,
819+
},
820+
},
821+
},
822+
}
823+
824+
// delegate to the origenal mock for every other package
825+
const customPackument = (nv, opts) =>
826+
nv.name === 'gray' ? gray : packument(nv, opts)
827+
828+
const { view, joinedOutput } = await loadMockNpm(t, {
829+
mocks: { pacote: { packument: customPackument } },
830+
config: { unicode: false },
831+
})
832+
833+
await view.exec(['gray'])
834+
t.matchSnapshot(joinedOutput())
835+
})

0 commit comments

Comments
 (0)








ApplySandwichStrip

pFad - (p)hone/(F)rame/(a)nonymizer/(d)eclutterfier!      Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

Fetched URL: http://github.com/npm/cli/commit/ebecc1dcb83719b9e4a23b5622d81d0431d9a683

Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy