Skip to content

Commit ea1b576

Browse files
author
Michael Smith
committed
fix: emit valid JSON from approve-scripts/deny-scripts --json
1 parent fc6268a commit ea1b576

3 files changed

Lines changed: 90 additions & 0 deletions

File tree

lib/utils/allow-scripts-cmd.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ class AllowScriptsCmd extends BaseCommand {
7979
}
8080

8181
runPending (unreviewed) {
82+
if (this.npm.flatOptions.json) {
83+
output.buffer({ allowScripts: this.pendingSummary(unreviewed) })
84+
return
85+
}
8286
if (unreviewed.length === 0) {
8387
output.standard('No packages with unreviewed install scripts.')
8488
return
@@ -105,8 +109,30 @@ class AllowScriptsCmd extends BaseCommand {
105109
)
106110
}
107111

112+
// Build the same `{ name, changes }` shape printSummary uses for writes,
113+
// but tag every entry as `pending` since nothing is written. Names and
114+
// versions are derived exactly like the text listing above.
115+
pendingSummary (unreviewed) {
116+
const groups = new Map()
117+
for (const { node } of unreviewed) {
118+
const { name, version } = trustedDisplay(node)
119+
/* istanbul ignore next: every test node has a name */
120+
const display = name || '<unknown>'
121+
const key = version ? `${display}@${version}` : display
122+
if (!groups.has(display)) {
123+
groups.set(display, [])
124+
}
125+
groups.get(display).push({ key, change: 'pending' })
126+
}
127+
return [...groups].map(([name, changes]) => ({ name, changes }))
128+
}
129+
108130
async runAll (unreviewed) {
109131
if (unreviewed.length === 0) {
132+
if (this.npm.flatOptions.json) {
133+
output.buffer({ allowScripts: [] })
134+
return
135+
}
110136
output.standard('No packages with unreviewed install scripts.')
111137
return
112138
}

test/lib/commands/approve-scripts.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,51 @@ t.test('approve-scripts --json outputs structured summary', async t => {
178178
})
179179
})
180180

181+
t.test('approve-scripts --pending --json lists unreviewed packages as JSON', async t => {
182+
const { npm, joinedOutput } = await mockNpm(t, {
183+
prefixDir: setupProject({ withScripts: ['canvas', 'sharp'] }),
184+
config: { 'allow-scripts-pending': true, json: true },
185+
})
186+
await npm.exec('approve-scripts', [])
187+
const parsed = JSON.parse(joinedOutput())
188+
const byName = Object.fromEntries(parsed.allowScripts.map((e) => [e.name, e.changes]))
189+
t.strictSame(byName, {
190+
canvas: [{ key: 'canvas@1.0.0', change: 'pending' }],
191+
sharp: [{ key: 'sharp@1.0.0', change: 'pending' }],
192+
})
193+
})
194+
195+
t.test('approve-scripts --pending --json with no unreviewed emits empty list', async t => {
196+
const { npm, joinedOutput } = await mockNpm(t, {
197+
prefixDir: setupProject({
198+
allowScripts: { canvas: true },
199+
withScripts: ['canvas'],
200+
}),
201+
config: { 'allow-scripts-pending': true, json: true },
202+
})
203+
await npm.exec('approve-scripts', [])
204+
t.strictSame(JSON.parse(joinedOutput()), { allowScripts: [] })
205+
})
206+
207+
t.test('approve-scripts --all --json with no unreviewed emits empty list', async t => {
208+
const { npm, joinedOutput } = await _mockNpm(t, {
209+
prefixDir: {
210+
'package.json': JSON.stringify({ name: 'host', version: '1.0.0' }),
211+
'package-lock.json': JSON.stringify({
212+
name: 'host',
213+
version: '1.0.0',
214+
lockfileVersion: 3,
215+
requires: true,
216+
packages: { '': { name: 'host', version: '1.0.0' } },
217+
}),
218+
node_modules: {},
219+
},
220+
config: { all: true, json: true },
221+
})
222+
await npm.exec('approve-scripts', [])
223+
t.strictSame(JSON.parse(joinedOutput()), { allowScripts: [] })
224+
})
225+
181226
t.test('approve-scripts --all with no unreviewed packages prints message', async t => {
182227
const { npm, joinedOutput } = await _mockNpm(t, {
183228
prefixDir: {

test/lib/commands/deny-scripts.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,25 @@ t.test('deny-scripts --all with no unreviewed packages prints message', async t
130130
t.match(joinedOutput(), /No packages with unreviewed install scripts/)
131131
})
132132

133+
t.test('deny-scripts --all --json with no unreviewed emits empty list', async t => {
134+
const { npm, joinedOutput } = await _mockNpm(t, {
135+
prefixDir: {
136+
'package.json': JSON.stringify({ name: 'host', version: '1.0.0' }),
137+
'package-lock.json': JSON.stringify({
138+
name: 'host',
139+
version: '1.0.0',
140+
lockfileVersion: 3,
141+
requires: true,
142+
packages: { '': { name: 'host', version: '1.0.0' } },
143+
}),
144+
node_modules: {},
145+
},
146+
config: { all: true, json: true },
147+
})
148+
await npm.exec('deny-scripts', [])
149+
t.strictSame(JSON.parse(joinedOutput()), { allowScripts: [] })
150+
})
151+
133152
t.test('deny-scripts fails on global', async t => {
134153
const { npm } = await _mockNpm(t, {
135154
config: { global: true },

0 commit comments

Comments
 (0)