-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathparse_args.test.js
More file actions
203 lines (171 loc) · 6.85 KB
/
Copy pathparse_args.test.js
File metadata and controls
203 lines (171 loc) · 6.85 KB
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
import {describe, test, expect} from 'vitest'
import {parseArgs, formatHelp, CliError} from './parse_args.js'
describe('parseArgs', () => {
test('parses string flags and consumes the next token', () => {
const result = parseArgs(['--out', 'sheet.json'], {
flags: {out: {type: 'string'}}
})
expect(result.out).toBe('sheet.json')
})
test('coerces int flags', () => {
const result = parseArgs(['--cols', '4'], {
flags: {cols: {type: 'int'}}
})
expect(result.cols).toBe(4)
})
test('coerces float flags', () => {
const result = parseArgs(['--tolerance', '0.25'], {
flags: {tolerance: {type: 'float'}}
})
expect(result.tolerance).toBe(0.25)
})
test('bool flags are true when present, do not consume next', () => {
const result = parseArgs(['--json', 'file.psd'], {
flags: {json: {type: 'bool'}},
positionals: ['file']
})
expect(result.json).toBe(true)
expect(result.file).toBe('file.psd')
})
test('applies defaults when a flag is absent', () => {
const result = parseArgs([], {
flags: {
cols: {type: 'int', default: 8},
json: {type: 'bool'},
out: {type: 'string'}
}
})
expect(result).toMatchObject({cols: 8, json: false, out: null})
})
test('maps camelCase keys to kebab-case tokens', () => {
const result = parseArgs(['--keep-key'], {
flags: {keepKey: {type: 'bool'}}
})
expect(result.keepKey).toBe(true)
})
test('supports aliases', () => {
const result = parseArgs(['-w', '256'], {
flags: {width: {type: 'int', alias: '-w'}}
})
expect(result.width).toBe(256)
})
test('supports multiple aliases', () => {
const spec = {flags: {height: {type: 'int', alias: ['-h2', '--ht']}}}
expect(parseArgs(['-h2', '10'], spec).height).toBe(10)
expect(parseArgs(['--ht', '20'], spec).height).toBe(20)
})
test('supports --flag=value inline syntax', () => {
const result = parseArgs(['--cols=12', '--name=hero'], {
flags: {cols: {type: 'int'}, name: {type: 'string'}}
})
expect(result.cols).toBe(12)
expect(result.name).toBe('hero')
})
test('multiple collects values into an array', () => {
const result = parseArgs(['--ignore', 'a', '--ignore', 'b'], {
flags: {ignore: {type: 'string', multiple: true}}
})
expect(result.ignore).toEqual(['a', 'b'])
})
test('multiple defaults to an empty array', () => {
const result = parseArgs([], {flags: {ignore: {type: 'string', multiple: true}}})
expect(result.ignore).toEqual([])
})
test('custom parse hook overrides type coercion', () => {
const parseSize = value => value.split('x').map(Number)
const result = parseArgs(['--frame', '32x48'], {
flags: {frame: {parse: parseSize}}
})
expect(result.frame).toEqual([32, 48])
})
test('collects positionals in order and exposes _', () => {
const result = parseArgs(['extract', 'hero.png', 'extra'], {
positionals: ['command', 'file']
})
expect(result.command).toBe('extract')
expect(result.file).toBe('hero.png')
expect(result._).toEqual(['extract', 'hero.png', 'extra'])
})
test('unset optional positionals are null', () => {
const result = parseArgs(['only'], {positionals: ['command', 'file']})
expect(result.command).toBe('only')
expect(result.file).toBeNull()
})
test('flags and positionals interleave', () => {
const result = parseArgs(['extract', '--cols', '4', 'hero.png', '--json'], {
flags: {cols: {type: 'int'}, json: {type: 'bool'}},
positionals: ['command', 'file']
})
expect(result).toMatchObject({command: 'extract', file: 'hero.png', cols: 4, json: true})
})
test('negative numbers are accepted as flag values', () => {
const result = parseArgs(['--offset', '-5'], {flags: {offset: {type: 'int'}}})
expect(result.offset).toBe(-5)
})
test('throws on unknown flag', () => {
expect(() => parseArgs(['--nope'], {flags: {}})).toThrow(CliError)
})
test('throws when a value flag is missing its value', () => {
expect(() => parseArgs(['--out'], {flags: {out: {type: 'string'}}})).toThrow(/expects a value/)
})
test('throws when an int flag gets a non-integer', () => {
expect(() => parseArgs(['--cols', 'abc'], {flags: {cols: {type: 'int'}}})).toThrow(/integer/)
})
test('throws when a bool flag is given a value', () => {
expect(() => parseArgs(['--json=1'], {flags: {json: {type: 'bool'}}})).toThrow(/does not take a value/)
})
test('throws on a required positional that is missing', () => {
expect(() => parseArgs([], {positionals: [{name: 'file', required: true}]})).toThrow(/Missing required/)
})
test('--help triggers onHelp instead of exiting when provided', () => {
let helped = false
parseArgs(['--help'], {
usage: 'demo',
flags: {json: {type: 'bool'}},
onHelp: () => {
helped = true
}
})
expect(helped).toBe(true)
})
test('spec.help as a function is invoked instead of the generated help', () => {
let printed = null
parseArgs(['-h'], {
help: () => {
printed = 'custom'
},
onHelp: () => {}
})
expect(printed).toBe('custom')
})
test('spec.help as a string is printed verbatim', () => {
const logs = []
const original = console.log
console.log = msg => logs.push(msg)
try {
parseArgs(['--help'], {help: 'VERBATIM HELP', onHelp: () => {}})
} finally {
console.log = original
}
expect(logs).toContain('VERBATIM HELP')
})
})
describe('formatHelp', () => {
test('renders usage, arguments and options', () => {
const help = formatHelp({
usage: 'yarn sprite <command> <file> [options]',
description: 'Asset pipeline tool.',
positionals: [{name: 'command', help: 'What to do'}, {name: 'file', help: 'Input file'}],
flags: {
cols: {type: 'int', alias: '-c', help: 'Number of columns'},
keepKey: {type: 'bool', help: 'Keep the chroma key'}
}
})
expect(help).toContain('Usage: yarn sprite <command> <file> [options]')
expect(help).toContain('Asset pipeline tool.')
expect(help).toContain('<command>')
expect(help).toContain('--cols, -c')
expect(help).toContain('--keep-key')
expect(help).toContain('--help, -h')
})
})