Skip to content

Commit 65cfad2

Browse files
committed
fix(pkg): output like npm view does, do not force json output
BREAKING CHANGE: The `npm pkg` output is no longer forced to json. This means you can get single values without having to worry about wrapping of the values. It also outputs non-json content more similarly to `npm view`. Fixes npm/statusboard#1080
1 parent d24fdd8 commit 65cfad2

4 files changed

Lines changed: 465 additions & 391 deletions

File tree

lib/commands/pkg.js

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
const { inspect } = require('node:util')
12
const { output } = require('proc-log')
23
const PackageJson = require('@npmcli/package-json')
34
const BaseCommand = require('../base-cmd.js')
@@ -56,25 +57,40 @@ class Pkg extends BaseCommand {
5657
}
5758

5859
async get (args, { path, workspace }) {
59-
this.npm.config.set('json', true)
6060
const pkgJson = await PackageJson.load(path)
61+
const json = this.npm.config.get('json')
6162

62-
let result = pkgJson.content
63+
// filter out the newline/indent symbols from the package-json object
64+
let result = JSON.parse(JSON.stringify(pkgJson.content))
6365

6466
if (args.length) {
65-
result = new Queryable(result).query(args)
66-
// in case there's only a single argument and a single result from the query just prints that one element to stdout.
67-
// TODO(BREAKING_CHANGE): much like other places where we unwrap single item arrays this should go away.
68-
// it makes the behavior unknown for users who don't already know the shape of the data.
69-
if (Object.keys(result).length === 1 && args.length === 1) {
70-
result = result[args]
67+
result = new Queryable(result).query(args, { unwrapSingleItemArrays: false })
68+
if (args.length === 1 && !json) {
69+
if (workspace) {
70+
return output.standard(`${workspace} ${result[args[0]]}`)
71+
}
72+
return output.standard(result[args[0]])
7173
}
7274
}
7375

74-
// The display layer is responsible for calling JSON.stringify on the result
75-
// TODO: https://github.com/npm/cli/issues/5508 a raw mode has been requested similar to jq -r.
76-
// If that was added then this method should no longer set `json:true` all the time
77-
output.buffer(workspace ? { [workspace]: result } : result)
76+
if (json) {
77+
output.buffer(workspace ? { [workspace]: result } : result)
78+
} else {
79+
for (let [f, d] of Object.entries(result)) {
80+
d = inspect(d, {
81+
showHidden: false,
82+
depth: 5,
83+
colors: this.npm.color,
84+
maxArrayLength: null,
85+
})
86+
87+
if (workspace) {
88+
output.standard(`${workspace} ${f} = ${d}`)
89+
} else {
90+
output.standard(`${f} = ${d}`)
91+
}
92+
}
93+
}
7894
}
7995

8096
async set (args, { path }) {

lib/commands/view.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ class View extends BaseCommand {
204204
const includeVersions = versions.length > 1
205205

206206
let includeFields
207+
// TODO if we ask for two fields but only one existed we treat it as if we only asked for one field, this needs to be fixed
207208
const res = versions.flatMap((v) => {
208209
const fields = Object.entries(data[v])
209210

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

Lines changed: 41 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@
55
* Make sure to inspect the output below. Do not ignore changes!
66
*/
77
'use strict'
8-
exports[`test/lib/commands/pkg.js TAP delete multiple field > should delete multiple fields from package.json 1`] = `
8+
exports[`test/lib/commands/pkg.js TAP delete delete multiple field > should delete multiple fields from package.json 1`] = `
99
Object {
1010
"name": "foo",
1111
}
1212
`
1313

14-
exports[`test/lib/commands/pkg.js TAP delete nested field > should delete nested fields from package.json 1`] = `
14+
exports[`test/lib/commands/pkg.js TAP delete delete nested field > should delete nested fields from package.json 1`] = `
1515
Object {
1616
"info": Object {
1717
"foo": Object {
@@ -25,7 +25,7 @@ Object {
2525
}
2626
`
2727

28-
exports[`test/lib/commands/pkg.js TAP delete single field > should delete single field from package.json 1`] = `
28+
exports[`test/lib/commands/pkg.js TAP delete delete single field > should delete single field from package.json 1`] = `
2929
Object {
3030
"name": "foo",
3131
}
@@ -39,59 +39,58 @@ Object {
3939
`
4040

4141
exports[`test/lib/commands/pkg.js TAP get array field > should print retrieved array field 1`] = `
42-
[
43-
"index.js",
44-
"cli.js"
45-
]
42+
[ 'index.js', 'cli.js' ]
4643
`
4744

4845
exports[`test/lib/commands/pkg.js TAP get array item > should print retrieved array field 1`] = `
49-
46+
index.js
5047
`
5148

52-
exports[`test/lib/commands/pkg.js TAP get array nested items notation > should print json result containing matching results 1`] = `
49+
exports[`test/lib/commands/pkg.js TAP get json no args > should print package.json content 1`] = `
5350
{
54-
"contributors[0].name": "Ruy",
55-
"contributors[1].name": "Gar"
51+
"name": "foo",
52+
"version": "1.1.1"
5653
}
5754
`
5855

59-
exports[`test/lib/commands/pkg.js TAP get multiple arg > should print retrieved package.json fields 1`] = `
56+
exports[`test/lib/commands/pkg.js TAP get json with args > should print package.json content 1`] = `
6057
{
61-
"name": "foo",
62-
"version": "1.1.1"
58+
"name": "foo"
6359
}
6460
`
6561

62+
exports[`test/lib/commands/pkg.js TAP get multiple arg > should print retrieved package.json fields 1`] = `
63+
name = 'foo'
64+
version = '1.1.1'
65+
`
66+
6667
exports[`test/lib/commands/pkg.js TAP get multiple arg with empty value > should print retrieved package.json field regardless of empty value 1`] = `
67-
{
68-
"name": "foo",
69-
"author": ""
70-
}
68+
name = 'foo'
69+
author = ''
7170
`
7271

7372
exports[`test/lib/commands/pkg.js TAP get multiple arg with only one arg existing > should print retrieved package.json field 1`] = `
74-
{
75-
"name": "foo"
76-
}
73+
name = 'foo'
7774
`
7875

7976
exports[`test/lib/commands/pkg.js TAP get nested arg > node test.js 1`] = `
80-
"node test.js"
77+
node test.js
8178
`
8279

8380
exports[`test/lib/commands/pkg.js TAP get no args > should print package.json content 1`] = `
84-
{
85-
"name": "foo",
86-
"version": "1.1.1"
87-
}
81+
name = 'foo'
82+
version = '1.1.1'
83+
`
84+
85+
exports[`test/lib/commands/pkg.js TAP get non string > should print retrieved package.json field 1`] = `
86+
{ '@npmcli/test': '*' }
8887
`
8988

9089
exports[`test/lib/commands/pkg.js TAP get single arg > should print retrieved package.json field 1`] = `
91-
"1.1.1"
90+
1.1.1
9291
`
9392

94-
exports[`test/lib/commands/pkg.js TAP push to array syntax > should append to arrays using empty bracket syntax 1`] = `
93+
exports[`test/lib/commands/pkg.js TAP set push to array syntax > should append to arrays using empty bracket syntax 1`] = `
9594
Object {
9695
"keywords": Array [
9796
"foo",
@@ -103,7 +102,7 @@ Object {
103102
}
104103
`
105104

106-
exports[`test/lib/commands/pkg.js TAP set --json > should add fields to package.json 1`] = `
105+
exports[`test/lib/commands/pkg.js TAP set set --json > should add fields to package.json 1`] = `
107106
Object {
108107
"description": "awesome",
109108
"foo": Object {
@@ -123,7 +122,7 @@ Object {
123122
}
124123
`
125124

126-
exports[`test/lib/commands/pkg.js TAP set = separate value > should add single field to package.json 1`] = `
125+
exports[`test/lib/commands/pkg.js TAP set set = separate value > should add single field to package.json 1`] = `
127126
Object {
128127
"name": "foo",
129128
"tap": Object {
@@ -135,7 +134,7 @@ Object {
135134
}
136135
`
137136

138-
exports[`test/lib/commands/pkg.js TAP set multiple fields > should add single field to package.json 1`] = `
137+
exports[`test/lib/commands/pkg.js TAP set set multiple fields > should add single field to package.json 1`] = `
139138
Object {
140139
"bin": Object {
141140
"foo": "foo.js",
@@ -148,7 +147,7 @@ Object {
148147
}
149148
`
150149

151-
exports[`test/lib/commands/pkg.js TAP set single field > should add single field to package.json 1`] = `
150+
exports[`test/lib/commands/pkg.js TAP set set single field > should add single field to package.json 1`] = `
152151
Object {
153152
"description": "Awesome stuff",
154153
"name": "foo",
@@ -157,21 +156,22 @@ Object {
157156
`
158157

159158
exports[`test/lib/commands/pkg.js TAP single workspace multiple args > should only return info for one workspace 1`] = `
160-
{
161-
"a": {
162-
"name": "a",
163-
"version": "1.0.0"
164-
}
165-
}
159+
a name = 'a'
160+
a version = '1.0.0'
166161
`
167162

168163
exports[`test/lib/commands/pkg.js TAP single workspace single arg > should only return info for one workspace 1`] = `
169-
{
170-
"a": "1.0.0"
171-
}
164+
a 1.0.0
172165
`
173166

174167
exports[`test/lib/commands/pkg.js TAP workspaces get > should return expected result for configured workspaces 1`] = `
168+
a name = 'a'
169+
a version = '1.0.0'
170+
b name = 'b'
171+
b version = '1.2.3'
172+
`
173+
174+
exports[`test/lib/commands/pkg.js TAP workspaces get json > should return expected json result for configured workspaces 1`] = `
175175
{
176176
"a": {
177177
"name": "a",

0 commit comments

Comments
 (0)