Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/npm/cli.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/commands/ls.js2
-rw-r--r--lib/npm.js32
-rw-r--r--lib/utils/exit-handler.js8
-rw-r--r--test/fixtures/mock-npm.js9
-rw-r--r--test/lib/utils/exit-handler.js48
5 files changed, 94 insertions, 5 deletions
diff --git a/lib/commands/ls.js b/lib/commands/ls.js
index 6812c3923..7eebdf691 100644
--- a/lib/commands/ls.js
+++ b/lib/commands/ls.js
@@ -177,7 +177,7 @@ class LS extends ArboristWorkspaceCmd {
const [rootError] = tree.errors.filter(e =>
e.code === 'EJSONPARSE' && e.path === resolve(path, 'package.json'))
- this.npm.output(
+ this.npm.outputBuffer(
json
? jsonOutput({ path, problems, result, rootError, seenItems })
: parseable
diff --git a/lib/npm.js b/lib/npm.js
index 763c9b7a3..9fbda9073 100644
--- a/lib/npm.js
+++ b/lib/npm.js
@@ -40,6 +40,7 @@ class Npm extends EventEmitter {
#argvClean = []
#chalk = null
+ #outputBuffer = []
#logFile = new LogFile()
#display = new Display()
#timers = new Timers({
@@ -466,6 +467,37 @@ class Npm extends EventEmitter {
log.showProgress()
}
+ outputBuffer (item) {
+ this.#outputBuffer.push(item)
+ }
+
+ flushOutput (jsonError) {
+ if (!jsonError && !this.#outputBuffer.length) {
+ return
+ }
+
+ if (this.config.get('json')) {
+ const jsonOutput = this.#outputBuffer.reduce((acc, item) => {
+ if (typeof item === 'string') {
+ // try to parse it as json in case its a string
+ try {
+ item = JSON.parse(item)
+ } catch {
+ return acc
+ }
+ }
+ return { ...acc, ...item }
+ }, {})
+ this.output(JSON.stringify({ ...jsonOutput, ...jsonError }, null, 2))
+ } else {
+ for (const item of this.#outputBuffer) {
+ this.output(item)
+ }
+ }
+
+ this.#outputBuffer.length = 0
+ }
+
outputError (...msg) {
log.clearProgress()
// eslint-disable-next-line no-console
diff --git a/lib/utils/exit-handler.js b/lib/utils/exit-handler.js
index 2574a83fc..a9e061de7 100644
--- a/lib/utils/exit-handler.js
+++ b/lib/utils/exit-handler.js
@@ -136,6 +136,7 @@ const exitHandler = err => {
let exitCode
let noLogMessage
+ let jsonError
if (err) {
exitCode = 1
@@ -198,14 +199,13 @@ const exitHandler = err => {
}
if (hasLoadedNpm && npm.config.get('json')) {
- const error = {
+ jsonError = {
error: {
code: err.code,
summary: messageText(summary),
detail: messageText(detail),
},
}
- npm.outputError(JSON.stringify(error, null, 2))
}
if (typeof err.errno === 'number') {
@@ -216,6 +216,10 @@ const exitHandler = err => {
}
}
+ if (hasLoadedNpm) {
+ npm.flushOutput(jsonError)
+ }
+
log.verbose('exit', exitCode || 0)
showLogFileError = (hasLoadedNpm && npm.silent) || noLogMessage
diff --git a/test/fixtures/mock-npm.js b/test/fixtures/mock-npm.js
index 0318eadeb..8a744cd55 100644
--- a/test/fixtures/mock-npm.js
+++ b/test/fixtures/mock-npm.js
@@ -238,6 +238,15 @@ class MockNpm {
}
this._mockOutputs.push(msg)
}
+
+ // with the older fake mock npm there is no
+ // difference between output and outputBuffer
+ // since it just collects the output and never
+ // calls the exit handler, so we just mock the
+ // method the same as output.
+ outputBuffer (...msg) {
+ this.output(...msg)
+ }
}
const FakeMockNpm = (base = {}, t) => {
diff --git a/test/lib/utils/exit-handler.js b/test/lib/utils/exit-handler.js
index 7e3137013..d22ec4dd1 100644
--- a/test/lib/utils/exit-handler.js
+++ b/test/lib/utils/exit-handler.js
@@ -208,7 +208,7 @@ t.test('exit handler called - no npm with error without stack', async (t) => {
})
t.test('console.log output using --json', async (t) => {
- const { exitHandler, outputErrors } = await mockExitHandler(t, {
+ const { exitHandler, outputs } = await mockExitHandler(t, {
config: { json: true },
})
@@ -216,7 +216,7 @@ t.test('console.log output using --json', async (t) => {
t.equal(process.exitCode, 1)
t.same(
- JSON.parse(outputErrors[0]),
+ JSON.parse(outputs[0]),
{
error: {
code: 'EBADTHING', // should default error code to E[A-Z]+
@@ -228,6 +228,50 @@ t.test('console.log output using --json', async (t) => {
)
})
+t.test('merges output buffers errors with --json', async (t) => {
+ const { exitHandler, outputs, npm } = await mockExitHandler(t, {
+ config: { json: true },
+ })
+
+ npm.outputBuffer({ output_data: 1 })
+ npm.outputBuffer(JSON.stringify({ more_data: 2 }))
+ npm.outputBuffer('not json, will be ignored')
+
+ await exitHandler(err('Error: EBADTHING Something happened'))
+
+ t.equal(process.exitCode, 1)
+ t.same(
+ JSON.parse(outputs[0]),
+ {
+ output_data: 1,
+ more_data: 2,
+ error: {
+ code: 'EBADTHING', // should default error code to E[A-Z]+
+ summary: 'Error: EBADTHING Something happened',
+ detail: 'Error: EBADTHING Something happened',
+ },
+ },
+ 'should output expected json output'
+ )
+})
+
+t.test('output buffer without json', async (t) => {
+ const { exitHandler, outputs, npm, logs } = await mockExitHandler(t)
+
+ npm.outputBuffer('output_data')
+ npm.outputBuffer('more_data')
+
+ await exitHandler(err('Error: EBADTHING Something happened'))
+
+ t.equal(process.exitCode, 1)
+ t.same(
+ outputs,
+ [['output_data'], ['more_data']],
+ 'should output expected output'
+ )
+ t.match(logs.error, [['code', 'EBADTHING']])
+})
+
t.test('throw a non-error obj', async (t) => {
const { exitHandler, logs } = await mockExitHandler(t)