Skip to content

Commit 986ac2a

Browse files
committed
fix(view): dont unwrap arrays in json mode
The view command alters the data by default to unwrap single item arrays when in human readable mode (the default). This change makes it so those arrays are not altered when the --json flag is set. Fixes #3611
1 parent 8add914 commit 986ac2a

File tree

4 files changed

+78
-12
lines changed

4 files changed

+78
-12
lines changed

lib/commands/view.js

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ class View extends BaseCommand {
175175
}
176176

177177
async getData (pkg, args) {
178+
const json = this.npm.config.get('json')
178179
const opts = {
179180
...this.npm.flatOptions,
180181
preferOnline: true,
@@ -228,7 +229,12 @@ class View extends BaseCommand {
228229
delete versions[v].readme
229230
}
230231

231-
data.push(showFields(pckmnt, versions[v], arg))
232+
data.push(showFields({
233+
data: pckmnt,
234+
version: versions[v],
235+
fields: arg,
236+
json,
237+
}))
232238
})
233239
}
234240
})
@@ -242,11 +248,7 @@ class View extends BaseCommand {
242248
throw er
243249
}
244250

245-
if (
246-
!this.npm.config.get('json') &&
247-
args.length === 1 &&
248-
args[0] === ''
249-
) {
251+
if (!json && args.length === 1 && args[0] === '') {
250252
pckmnt.version = version
251253
}
252254

@@ -432,7 +434,7 @@ function reducer (acc, cur) {
432434
}
433435

434436
// return whatever was printed
435-
function showFields (data, version, fields) {
437+
function showFields ({ data, version, fields, json }) {
436438
const o = {}
437439
;[data, version].forEach((s) => {
438440
Object.keys(s).forEach((k) => {
@@ -441,7 +443,7 @@ function showFields (data, version, fields) {
441443
})
442444

443445
const queryable = new Queryable(o)
444-
const s = queryable.query(fields)
446+
const s = queryable.query(fields, { unwrapSingleItemArrays: !json })
445447
const res = { [version.version]: s }
446448

447449
if (s) {

lib/utils/queryable.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ const parseKeys = key => {
8383
return res
8484
}
8585

86-
const getter = ({ data, key }) => {
86+
const getter = ({ data, key }, { unwrapSingleItemArrays = true } = {}) => {
8787
// keys are a list in which each entry represents the name of
8888
// a property that should be walked through the object in order to
8989
// return the final found value
@@ -122,7 +122,7 @@ const getter = ({ data, key }) => {
122122

123123
// these are some legacy expectations from
124124
// the old API consumed by lib/view.js
125-
if (Array.isArray(_data) && _data.length <= 1) {
125+
if (unwrapSingleItemArrays && Array.isArray(_data) && _data.length <= 1) {
126126
_data = _data[0]
127127
}
128128

@@ -243,7 +243,7 @@ class Queryable {
243243
this.#data = obj
244244
}
245245

246-
query (queries) {
246+
query (queries, opts) {
247247
// this ugly interface here is meant to be a compatibility layer
248248
// with the legacy API lib/view.js is consuming, if at some point
249249
// we refactor that command then we can revisit making this nicer
@@ -255,7 +255,7 @@ class Queryable {
255255
getter({
256256
data: this.#data,
257257
key: query,
258-
})
258+
}, opts)
259259

260260
if (Array.isArray(queries)) {
261261
let res = {}

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,28 @@ dist-tags:
300300
published over a year from now
301301
`
302302

303+
exports[`test/lib/commands/view.js TAP package with single version full json > must match snapshot 1`] = `
304+
{
305+
"_id": "single-version",
306+
"name": "single-version",
307+
"dist-tags": {
308+
"latest": "1.0.0"
309+
},
310+
"time": {
311+
"1.0.0": "2024-05-07T19:41:40.177Z"
312+
},
313+
"versions": [
314+
"1.0.0"
315+
],
316+
"version": "1.0.0",
317+
"dist": {
318+
"shasum": "123",
319+
"tarball": "http://hm.single-version.com/1.0.0.tgz",
320+
"fileCount": 1
321+
}
322+
}
323+
`
324+
303325
exports[`test/lib/commands/view.js TAP specific field names array field - 1 element > must match snapshot 1`] = `
304326
claudia
305327
`

test/lib/commands/view.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,27 @@ const packument = (nv, opts) => {
252252
},
253253
},
254254
},
255+
'single-version': {
256+
_id: 'single-version',
257+
name: 'single-version',
258+
'dist-tags': {
259+
latest: '1.0.0',
260+
},
261+
time: {
262+
'1.0.0': yesterday,
263+
},
264+
versions: {
265+
'1.0.0': {
266+
name: 'single-version',
267+
version: '1.0.0',
268+
dist: {
269+
shasum: '123',
270+
tarball: 'http://hm.single-version.com/1.0.0.tgz',
271+
fileCount: 1,
272+
},
273+
},
274+
},
275+
},
255276
}
256277
if (nv.type === 'git') {
257278
return mocks[nv.hosted.project]
@@ -357,6 +378,27 @@ t.test('package with --json and no versions', async t => {
357378
t.equal(joinedOutput(), '', 'no info to display')
358379
})
359380

381+
t.test('package with single version', async t => {
382+
t.test('full json', async t => {
383+
const { view, joinedOutput } = await loadMockNpm(t, { config: { json: true } })
384+
await view.exec(['single-version'])
385+
t.matchSnapshot(joinedOutput())
386+
})
387+
388+
t.test('json and versions arg', async t => {
389+
const { view, joinedOutput } = await loadMockNpm(t, { config: { json: true } })
390+
await view.exec(['single-version', 'versions'])
391+
const parsed = JSON.parse(joinedOutput())
392+
t.strictSame(parsed, ['1.0.0'], 'does not unwrap single item arrays in json')
393+
})
394+
395+
t.test('no json and versions arg', async t => {
396+
const { view, joinedOutput } = await loadMockNpm(t, { config: { json: false } })
397+
await view.exec(['single-version', 'versions'])
398+
t.strictSame(joinedOutput(), '1.0.0', 'unwraps single item arrays in basic mode')
399+
})
400+
})
401+
360402
t.test('package in cwd', async t => {
361403
const prefixDir = {
362404
'package.json': JSON.stringify({

0 commit comments

Comments
 (0)