-
Notifications
You must be signed in to change notification settings - Fork 67
/
errors.ts
112 lines (93 loc) · 3.57 KB
/
errors.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import {CLIError} from '../errors'
import Deps from './deps'
import * as Help from './help'
import * as List from './list'
import * as chalk from 'chalk'
import {ParserArg, CLIParseErrorOptions, OptionFlag, Flag} from '../interfaces'
import {uniq} from '../config/util'
export {CLIError} from '../errors'
// eslint-disable-next-line new-cap
const m = Deps()
// eslint-disable-next-line node/no-missing-require
.add('help', () => require('./help') as typeof Help)
// eslint-disable-next-line node/no-missing-require
.add('list', () => require('./list') as typeof List)
.add('chalk', () => require('chalk') as typeof chalk)
export type Validation = {
name: string;
status: 'success' | 'failed';
validationFn: string;
reason?: string;
}
export class CLIParseError extends CLIError {
public parse: CLIParseErrorOptions['parse']
constructor(options: CLIParseErrorOptions & { message: string }) {
options.message += '\nSee more help with --help'
super(options.message)
this.parse = options.parse
}
}
export class InvalidArgsSpecError extends CLIParseError {
public args: ParserArg<any>[]
constructor({args, parse}: CLIParseErrorOptions & { args: ParserArg<any>[] }) {
let message = 'Invalid argument spec'
const namedArgs = args.filter(a => a.name)
if (namedArgs.length > 0) {
const list = m.list.renderList(namedArgs.map(a => [`${a.name} (${a.required ? 'required' : 'optional'})`, a.description] as [string, string]))
message += `:\n${list}`
}
super({parse, message})
this.args = args
}
}
export class RequiredArgsError extends CLIParseError {
public args: ParserArg<any>[]
constructor({args, parse}: CLIParseErrorOptions & { args: ParserArg<any>[] }) {
let message = `Missing ${args.length} required arg${args.length === 1 ? '' : 's'}`
const namedArgs = args.filter(a => a.name)
if (namedArgs.length > 0) {
const list = m.list.renderList(namedArgs.map(a => [a.name, a.description] as [string, string]))
message += `:\n${list}`
}
super({parse, message})
this.args = args
}
}
export class RequiredFlagError extends CLIParseError {
public flag: Flag<any>
constructor({flag, parse}: CLIParseErrorOptions & { flag: Flag<any> }) {
const usage = m.list.renderList(m.help.flagUsages([flag], {displayRequired: false}))
const message = `Missing required flag:\n${usage}`
super({parse, message})
this.flag = flag
}
}
export class UnexpectedArgsError extends CLIParseError {
public args: string[]
constructor({parse, args}: CLIParseErrorOptions & { args: string[] }) {
const message = `Unexpected argument${args.length === 1 ? '' : 's'}: ${args.join(', ')}`
super({parse, message})
this.args = args
}
}
export class FlagInvalidOptionError extends CLIParseError {
constructor(flag: OptionFlag<any>, input: string) {
const message = `Expected --${flag.name}=${input} to be one of: ${flag.options!.join(', ')}`
super({parse: {}, message})
}
}
export class ArgInvalidOptionError extends CLIParseError {
constructor(arg: ParserArg<any>, input: string) {
const message = `Expected ${input} to be one of: ${arg.options!.join(', ')}`
super({parse: {}, message})
}
}
export class FailedFlagValidationError extends CLIParseError {
constructor({parse, failed}: CLIParseErrorOptions & { failed: Validation[] }) {
const reasons = failed.map(r => r.reason)
const deduped = uniq(reasons)
const errString = deduped.length === 1 ? 'error' : 'errors'
const message = `The following ${errString} occurred:\n ${m.chalk.dim(deduped.join('\n '))}`
super({parse, message})
}
}