Skip to content

Commit c4d1efe

Browse files
committed
fix: readOptions should remove args from internal state
1 parent 9206316 commit c4d1efe

4 files changed

Lines changed: 39 additions & 23 deletions

File tree

src/args.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {
33
ArgRef,
44
PrimitiveConstructor,
55
OptionsReaderState,
6-
OptionsReaderNext,
6+
OptionsReaderRead,
77
OptionResult
88
} from './types'
99
import { matchArgName } from './utils'
@@ -30,12 +30,12 @@ export function alias<T extends string>(name: T, alias: string, ...restAliases:
3030
*/
3131
export function option<T extends string, K extends PrimitiveConstructor>(argRef: ArgRef<T>, type: K) {
3232
if (type === String) {
33-
return (option: string, next: OptionsReaderNext) => {
33+
return (option: string, read: OptionsReaderRead) => {
3434
const argName = matchArgName(argRef, option)
3535

3636
if (argName) {
3737
return {
38-
[argName]: next(true)
38+
[argName]: read()
3939
} as OptionResult<T, K>
4040
}
4141

@@ -44,12 +44,12 @@ export function option<T extends string, K extends PrimitiveConstructor>(argRef:
4444
}
4545

4646
if (type === Number) {
47-
return (option: string, next: OptionsReaderNext) => {
47+
return (option: string, read: OptionsReaderRead) => {
4848
const argName = matchArgName(argRef, option)
4949

5050
if (argName) {
5151
return {
52-
[argName]: parseFloat(next(true))
52+
[argName]: parseFloat(read())
5353
} as OptionResult<T, K>
5454
}
5555

@@ -58,12 +58,12 @@ export function option<T extends string, K extends PrimitiveConstructor>(argRef:
5858
}
5959

6060
if (type === Array) {
61-
return (option: string, next: OptionsReaderNext, options: OptionsReaderState) => {
61+
return (option: string, read: OptionsReaderRead, options: OptionsReaderState) => {
6262
const argName = matchArgName(argRef, option)
6363

6464
if (argName) {
6565
const prevValues = options[argName]
66-
const values = next(true).split(',')
66+
const values = read().split(',')
6767

6868
return {
6969
[argName]: Array.isArray(prevValues)

src/options.spec.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { setArgs } from './argv'
1+
import { setArgs, argv } from './argv'
22
import { option } from './args'
33
import { readOptions } from './options'
44

@@ -14,12 +14,14 @@ describe('options', () => {
1414
setArgs('--verbose')
1515

1616
expect(readOptions()).toEqual({})
17+
expect(argv).toEqual(['--verbose'])
1718
})
1819

1920
it('should return empty object if no options in args', () => {
2021
setArgs('--debug')
2122

2223
expect(readOptions(option('verbose', Boolean))).toEqual({})
24+
expect(argv).toEqual(['--debug'])
2325
})
2426

2527
it('should return options with values', () => {
@@ -42,6 +44,7 @@ describe('options', () => {
4244
'c'
4345
]
4446
})
47+
expect(argv).toEqual(['compile', '--unknown'])
4548
})
4649

4750
it('should throw error on unexpected end', () => {

src/options.ts

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { argv } from './argv'
2-
import { OptionReader } from './types'
2+
import { OptionReader, OptionResult } from './types'
33
import { Merge, ReturnTypes, UnionMerge } from './utils'
44

55
function isOption(arg: string) {
@@ -17,7 +17,7 @@ function createOptionReader<T extends OptionReader[]>(optionReaders: [...T]) {
1717
return readOption
1818
}
1919

20-
return (option, next, options) => readOption(option, next, options) ?? readNextOption(option, next, options)
20+
return (option, read, options) => readOption(option, read, options) ?? readNextOption(option, read, options)
2121
},
2222
null
2323
)
@@ -31,18 +31,31 @@ function createOptionReader<T extends OptionReader[]>(optionReaders: [...T]) {
3131
* @returns Options with values.
3232
*/
3333
export function readOptions<T extends OptionReader[]>(...optionReaders: [...T]): Partial<Merge<ReturnTypes<T>>> {
34-
if (!argv.length || !optionReaders.length) {
34+
if (!argv.length) {
3535
return {}
3636
}
3737

3838
const readOption = createOptionReader(optionReaders)
39+
40+
if (!readOption) {
41+
return {}
42+
}
43+
3944
const options = {}
4045
let i = 0
4146
let arg = argv[i]
42-
const next = (required = false) => {
47+
let optionResult: OptionResult | null
48+
const next = () => {
4349
arg = argv[++i]
50+
}
51+
const remove = () => {
52+
argv.splice(i--, 1)
53+
}
54+
const read = () => {
55+
next()
56+
remove()
4457

45-
if (required && !arg) {
58+
if (!arg) {
4659
throw new Error('Unexpected end of arguments')
4760
}
4861

@@ -52,7 +65,12 @@ export function readOptions<T extends OptionReader[]>(...optionReaders: [...T]):
5265
// eslint-disable-next-line no-unmodified-loop-condition
5366
while (arg) {
5467
if (isOption(arg)) {
55-
Object.assign(options, readOption?.(removePrefix(arg), next, options))
68+
optionResult = readOption(removePrefix(arg), read, options)
69+
70+
if (optionResult) {
71+
remove()
72+
Object.assign(options, optionResult)
73+
}
5674
}
5775

5876
next()

src/types.ts

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,7 @@ export type ArgRefName<T extends ArgRef<string>> =
1414

1515
export type OptionsReaderState = Record<string, unknown>
1616

17-
export type OptionsReaderNext =
18-
<T extends boolean>(required?: T) => (
19-
T extends true
20-
? string
21-
: string | undefined
22-
)
17+
export type OptionsReaderRead = () => string
2318

2419
export type PrimitiveConstructor = StringConstructor | NumberConstructor | ArrayConstructor | BooleanConstructor
2520

@@ -32,11 +27,11 @@ export type OptionValueType<T extends PrimitiveConstructor> =
3227
? string[]
3328
: boolean
3429

35-
export type OptionResult<T extends string, K extends PrimitiveConstructor> = Record<T, OptionValueType<K>>
30+
export type OptionResult<T extends string = string, K extends PrimitiveConstructor = PrimitiveConstructor> = Record<T, OptionValueType<K>>
3631

37-
export type OptionReader<T extends OptionResult<string, PrimitiveConstructor> = OptionResult<string, PrimitiveConstructor>> =
32+
export type OptionReader<T extends OptionResult = OptionResult> =
3833
(
3934
option: string,
40-
next: OptionsReaderNext,
35+
read: OptionsReaderRead,
4136
options: OptionsReaderState
4237
) => T | null

0 commit comments

Comments
 (0)