Skip to content

Commit

Permalink
fix(view): output full json object with errors with workspaces
Browse files Browse the repository at this point in the history
Fixes: #5444
  • Loading branch information
lukekarrys committed May 11, 2024
1 parent 461a6fb commit aaff460
Show file tree
Hide file tree
Showing 10 changed files with 326 additions and 280 deletions.
12 changes: 7 additions & 5 deletions lib/commands/run-script.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,13 @@ class RunScript extends BaseCommand {
return
}

const didYouMean = require('../utils/did-you-mean.js')
const suggestions = await didYouMean(path, event)
throw new Error(
`Missing script: "${event}"${suggestions}\n\nTo see a list of scripts, run:\n npm run`
)
const suggestions = require('../utils/did-you-mean.js')(pkg, event)
throw new Error([
`Missing script: "${event}"`,
...suggestions ? ['', ...suggestions] : [],
'To see a list of scripts, run:',
' npm run',
].join('\n'))
}

// positional args only added to the main event, not pre/post
Expand Down
171 changes: 89 additions & 82 deletions lib/commands/view.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const { inspect } = require('util')
const { packument } = require('pacote')
const Queryable = require('../utils/queryable.js')
const BaseCommand = require('../base-cmd.js')
const { getError, jsonError, outputError } = require('../utils/error-message.js')

const readJson = async file => jsonParse(await readFile(file, 'utf8'))

Expand Down Expand Up @@ -77,11 +78,7 @@ class View extends BaseCommand {
}

async exec (args) {
if (!args.length) {
args = ['.']
}
let pkg = args.shift()
const local = /^\.@/.test(pkg) || pkg === '.'
let { pkg, local, rest } = parseArgs(args)

if (local) {
if (this.npm.global) {
Expand All @@ -96,92 +93,88 @@ class View extends BaseCommand {
pkg = `${manifest.name}${pkg.slice(1)}`
}

let wholePackument = false
if (!args.length) {
args = ['']
wholePackument = true
}
const [pckmnt, data] = await this.getData(pkg, args)

if (!this.npm.config.get('json') && wholePackument) {
// pretty view (entire packument)
data.map((v) => this.prettyView(pckmnt, v[Object.keys(v)[0]]['']))
} else {
// JSON formatted output (JSON or specific attributes from packument)
let reducedData = data.reduce(reducer, {})
if (wholePackument) {
// No attributes
reducedData = cleanBlanks(reducedData)
log.silly('view', reducedData)
}

const msg = await this.jsonData(reducedData, pckmnt._id)
if (msg !== '') {
output.standard(msg)
}
}
await this.#viewPackage(pkg, rest)
}

async execWorkspaces (args) {
if (!args.length) {
args = ['.']
}

const pkg = args.shift()
const { pkg, local, rest } = parseArgs(args)

const local = /^\.@/.test(pkg) || pkg === '.'
if (!local) {
log.warn('Ignoring workspaces for specified package(s)')
return this.exec([pkg, ...args])
return this.exec([pkg, ...rest])
}
let wholePackument = false
if (!args.length) {
wholePackument = true
args = [''] // getData relies on this
}
const results = {}

const json = this.npm.config.get('json')
await this.setWorkspaces()
for (const name of this.workspaceNames) {
const wsPkg = `${name}${pkg.slice(1)}`
const [pckmnt, data] = await this.getData(wsPkg, args)

let reducedData = data.reduce(reducer, {})
if (wholePackument) {
// No attributes
reducedData = cleanBlanks(reducedData)
log.silly('view', reducedData)
}

if (!this.npm.config.get('json')) {
if (wholePackument) {
data.map((v) => this.prettyView(pckmnt, v[Object.keys(v)[0]]['']))
let hasError = false
for (const name of this.workspaceNames) {
try {
await this.#viewPackage(
`${name}${pkg.slice(1)}`,
rest,
{ multiple: !!this.workspaceNames.length }
)
} catch (e) {
hasError = true
const err = getError(e, { npm: this.npm, command: this })
if (json) {
output.buffer({ [name]: jsonError(err, this.npm) })
} else {
output.standard(`${name}:`)
const msg = await this.jsonData(reducedData, pckmnt._id)
if (msg !== '') {
output.standard(msg)
}
}
} else {
const msg = await this.jsonData(reducedData, pckmnt._id)
if (msg !== '') {
results[name] = JSON.parse(msg)
outputError(err)
}
}
}
if (Object.keys(results).length > 0) {
output.standard(JSON.stringify(results, null, 2))

if (hasError) {
process.exitCode = 1
}
}

async getData (pkg, args) {
async #viewPackage (name, args, { multiple = false } = {}) {
const wholePackument = !args.length
const json = this.npm.config.get('json')
const opts = {
...this.npm.flatOptions,
preferOnline: true,
fullMetadata: true,

// If we are viewing many packages output the name before doing
// any async activity
if (!json && !wholePackument && multiple) {
output.standard(`${name}:`)
}

const [pckmnt, data, version] = await this.#getData(name, wholePackument ? [''] : args)
if (wholePackument) {
pckmnt.version = version
}

// This already outputs to the terminal
if (!json && wholePackument) {
// pretty view (entire packument)
for (const v of data) {
this.#prettyView(pckmnt, v[Object.keys(v)[0]][''])
}
return
}

// JSON formatted output (JSON or specific attributes from packument)
let reducedData = data.reduce(reducer, {})
if (wholePackument) {
// No attributes
reducedData = cleanBlanks(reducedData)
log.silly('view', reducedData)
}

const msg = this.#packageOutput(reducedData, pckmnt._id)
if (msg !== '') {
if (json && multiple) {
output.buffer({ [name]: JSON.parse(msg) })
} else {
output.standard(msg)
}
}
}

async #getData (pkg, args = []) {
const json = this.npm.config.get('json')
const spec = npa(pkg)

// get the data about this package
Expand All @@ -191,13 +184,17 @@ class View extends BaseCommand {
version = spec.rawSpec
}

const pckmnt = await packument(spec, opts)
const pckmnt = await packument(spec, {
...this.npm.flatOptions,
preferOnline: true,
fullMetadata: true,
})

if (pckmnt['dist-tags']?.[version]) {
version = pckmnt['dist-tags'][version]
}

if (pckmnt.time && pckmnt.time.unpublished) {
if (pckmnt.time?.unpublished) {
const u = pckmnt.time.unpublished
const er = new Error(`Unpublished on ${u.time}`)
er.statusCode = 404
Expand Down Expand Up @@ -240,22 +237,18 @@ class View extends BaseCommand {
})

// No data has been pushed because no data is matching the specified version
if (data.length === 0 && version !== 'latest') {
if (!data.length && version !== 'latest') {
const er = new Error(`No match found for version ${version}`)
er.statusCode = 404
er.code = 'E404'
er.pkgid = `${pckmnt._id}@${version}`
throw er
}

if (!json && args.length === 1 && args[0] === '') {
pckmnt.version = version
}

return [pckmnt, data]
return [pckmnt, data, version]
}

async jsonData (data, name) {
#packageOutput (data, name) {
const versions = Object.keys(data)
let msg = ''
let msgJson = []
Expand Down Expand Up @@ -315,7 +308,7 @@ class View extends BaseCommand {
return msg.trim()
}

prettyView (packu, manifest) {
#prettyView (packu, manifest) {
// More modern, pretty printing of default view
const unicode = this.npm.config.get('unicode')
const chalk = this.npm.chalk
Expand Down Expand Up @@ -411,6 +404,20 @@ class View extends BaseCommand {

module.exports = View

function parseArgs (args) {
if (!args.length) {
args = ['.']
}

const pkg = args.shift()

return {
pkg,
local: /^\.@/.test(pkg) || pkg === '.',
rest: args,
}
}

function cleanBlanks (obj) {
const clean = {}
Object.keys(obj).forEach((version) => {
Expand Down
Loading

0 comments on commit aaff460

Please sign in to comment.