Skip to content
This repository has been archived by the owner on Aug 22, 2023. It is now read-only.

Commit

Permalink
Allow for multiple suggestions (#42)
Browse files Browse the repository at this point in the history
  • Loading branch information
chadian authored Jun 26, 2020
1 parent 6820d14 commit e0fc392
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 15 deletions.
21 changes: 15 additions & 6 deletions src/errors/pretty-print.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,40 +23,49 @@ export interface PrettyPrintableError {
/**
* a suggestion that may be useful or provide additional context
*/
suggestion?: string;
suggestions?: string[];
}

// These exist for backwards compatibility with CLIError
type CLIErrorDisplayOptions = { name?: string; bang?: string }

export function applyPrettyPrintOptions(error: Error, options: PrettyPrintableError): PrettyPrintableError {
const prettyErrorKeys: (keyof PrettyPrintableError)[] = ['message', 'code', 'ref', 'suggestion']
const prettyErrorKeys: (keyof PrettyPrintableError)[] = ['message', 'code', 'ref', 'suggestions']

prettyErrorKeys.forEach(key => {
const applyOptionsKey = !(key in error) && options[key]
if (applyOptionsKey) {
(error as PrettyPrintableError)[key] = options[key]
(error as any)[key] = options[key]
}
})

return error
}

const formatSuggestions = (suggestions?: string[]): string | undefined => {
const label = 'Try this:'
if (!suggestions || suggestions.length === 0) return undefined
if (suggestions.length === 1) return `${label} ${suggestions[0]}`

const multiple = suggestions.map(suggestion => `* ${suggestion}`).join('\n')
return `${label}\n${indent(multiple, 2)}`
}

export default function prettyPrint(error: Error & PrettyPrintableError & CLIErrorDisplayOptions) {
if (config.debug) {
return error.stack
}

const {message, code, suggestion, ref, name: errorSuffix, bang} = error
const {message, code, suggestions, ref, name: errorSuffix, bang} = error

// errorSuffix is pulled from the 'name' property on CLIError
// and is like either Error or Warning
const formattedHeader = message ? `${errorSuffix || 'Error'}: ${message}` : undefined
const formattedCode = code ? `Code: ${code}` : undefined
const formattedSuggestion = suggestion ? `Suggestion: ${suggestion}` : undefined
const formattedSuggestions = formatSuggestions(suggestions)
const formattedReference = ref ? `Reference: ${ref}` : undefined

const formatted = [formattedHeader, formattedCode, formattedSuggestion, formattedReference]
const formatted = [formattedHeader, formattedCode, formattedSuggestions, formattedReference]
.filter(Boolean)
.join('\n')

Expand Down
14 changes: 7 additions & 7 deletions test/error.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,25 @@ describe('error', () => {

fancy
.do(() => {
error('An error happened!', {code: 'ERR', ref: 'https://oclif.com/error', suggestion: 'rm -rf node_modules'})
error('An error happened!', {code: 'ERR', ref: 'https://oclif.com/error', suggestions: ['rm -rf node_modules']})
})
.catch((error: PrettyPrintableError) => {
expect(error.message).to.equal('An error happened!')
expect(error.code).to.equal('ERR')
expect(error.ref).to.equal('https://oclif.com/error')
expect(error.suggestion).to.equal('rm -rf node_modules')
expect(error.suggestions).to.deep.equal(['rm -rf node_modules'])
})
.it('attaches pretty print properties to a new error from options')

fancy
.do(() => {
error(new Error('An existing error object error!'), {code: 'ERR', ref: 'https://oclif.com/error', suggestion: 'rm -rf node_modules'})
error(new Error('An existing error object error!'), {code: 'ERR', ref: 'https://oclif.com/error', suggestions: ['rm -rf node_modules']})
})
.catch((error: PrettyPrintableError) => {
expect(error.message).to.equal('An existing error object error!')
expect(error.code).to.equal('ERR')
expect(error.ref).to.equal('https://oclif.com/error')
expect(error.suggestion).to.equal('rm -rf node_modules')
expect(error.suggestions).to.deep.equal(['rm -rf node_modules'])
})
.it('attached pretty print properties from options to an existing error object')

Expand All @@ -41,13 +41,13 @@ describe('error', () => {
const e: any = new Error('An existing error object error!')
e.code = 'ORIG_ERR'
e.ref = 'ORIG_REF'
e.suggestion = 'ORIG_SUGGESTION'
error(e, {code: 'ERR', ref: 'https://oclif.com/error', suggestion: 'rm -rf node_modules'})
e.suggestions = ['ORIG_SUGGESTION']
error(e, {code: 'ERR', ref: 'https://oclif.com/error', suggestions: ['rm -rf node_modules']})
})
.catch((error: PrettyPrintableError) => {
expect(error.code).to.equal('ORIG_ERR')
expect(error.ref).to.equal('ORIG_REF')
expect(error.suggestion).to.equal('ORIG_SUGGESTION')
expect(error.suggestions).to.deep.equal(['ORIG_SUGGESTION'])
})
.it('preserves original pretty printable properties and is not overwritten by options')

Expand Down
16 changes: 14 additions & 2 deletions test/pretty-print.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,28 @@ describe('pretty-print', () => {
const sampleError: Error & PrettyPrintableError = new Error('Something very serious has gone wrong with the flags!')
sampleError.ref = 'https://oclif.io/docs/flags'
sampleError.code = 'OCLIF_BAD_FLAG'
sampleError.suggestion = 'Try using using a good flag'
sampleError.suggestions = ['Try using using a good flag']

expect(
stripAnsi(prettyPrint(sampleError)),
).to.equal(` Error: Something very serious has gone wrong with the flags!
Code: OCLIF_BAD_FLAG
Suggestion: Try using using a good flag
Try this: Try using using a good flag
Reference: https://oclif.io/docs/flags`)
})

fancy
.it('pretty prints multiple suggestions', async () => {
const sampleError: Error & PrettyPrintableError = new Error('Something very serious has gone wrong with the flags!')
sampleError.suggestions = ['Use a good flag', 'Use no flags']
expect(
stripAnsi(prettyPrint(sampleError)),
).to.equal(` Error: Something very serious has gone wrong with the flags!
Try this:
* Use a good flag
* Use no flags`)
})

fancy
.it('pretty prints with omitted fields', async () => {
const sampleError = new Error('Something very serious has gone wrong with the flags!')
Expand Down

0 comments on commit e0fc392

Please sign in to comment.