Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .size-limit
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
[
{
"path": "dist/index.cjs",
"limit": "765 B"
"limit": "780 B"
},
{
"path": "dist/index.js",
"limit": "610 B"
"limit": "620 B"
}
]
14 changes: 7 additions & 7 deletions src/args.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {
ArgRef,
PrimitiveConstructor,
OptionsReaderState,
OptionsReaderNext,
OptionsReaderRead,
OptionResult
} from './types'
import { matchArgName } from './utils'
Expand All @@ -30,12 +30,12 @@ export function alias<T extends string>(name: T, alias: string, ...restAliases:
*/
export function option<T extends string, K extends PrimitiveConstructor>(argRef: ArgRef<T>, type: K) {
if (type === String) {
return (option: string, next: OptionsReaderNext) => {
return (option: string, read: OptionsReaderRead) => {
const argName = matchArgName(argRef, option)

if (argName) {
return {
[argName]: next(true)
[argName]: read()
} as OptionResult<T, K>
}

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

if (type === Number) {
return (option: string, next: OptionsReaderNext) => {
return (option: string, read: OptionsReaderRead) => {
const argName = matchArgName(argRef, option)

if (argName) {
return {
[argName]: parseFloat(next(true))
[argName]: parseFloat(read())
} as OptionResult<T, K>
}

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

if (type === Array) {
return (option: string, next: OptionsReaderNext, options: OptionsReaderState) => {
return (option: string, read: OptionsReaderRead, options: OptionsReaderState) => {
const argName = matchArgName(argRef, option)

if (argName) {
const prevValues = options[argName]
const values = next(true).split(',')
const values = read().split(',')

return {
[argName]: Array.isArray(prevValues)
Expand Down
5 changes: 4 additions & 1 deletion src/options.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { setArgs } from './argv'
import { setArgs, argv } from './argv'
import { option } from './args'
import { readOptions } from './options'

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

expect(readOptions()).toEqual({})
expect(argv).toEqual(['--verbose'])
})

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

expect(readOptions(option('verbose', Boolean))).toEqual({})
expect(argv).toEqual(['--debug'])
})

it('should return options with values', () => {
Expand All @@ -42,6 +44,7 @@ describe('options', () => {
'c'
]
})
expect(argv).toEqual(['compile', '--unknown'])
})

it('should throw error on unexpected end', () => {
Expand Down
30 changes: 24 additions & 6 deletions src/options.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { argv } from './argv'
import { OptionReader } from './types'
import { OptionReader, OptionResult } from './types'
import { Merge, ReturnTypes, UnionMerge } from './utils'

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

return (option, next, options) => readOption(option, next, options) ?? readNextOption(option, next, options)
return (option, read, options) => readOption(option, read, options) ?? readNextOption(option, read, options)
},
null
)
Expand All @@ -31,18 +31,31 @@ function createOptionReader<T extends OptionReader[]>(optionReaders: [...T]) {
* @returns Options with values.
*/
export function readOptions<T extends OptionReader[]>(...optionReaders: [...T]): Partial<Merge<ReturnTypes<T>>> {
if (!argv.length || !optionReaders.length) {
if (!argv.length) {
return {}
}

const readOption = createOptionReader(optionReaders)

if (!readOption) {
return {}
}

const options = {}
let i = 0
let arg = argv[i]
const next = (required = false) => {
let optionResult: OptionResult | null
const next = () => {
arg = argv[++i]
}
const remove = () => {
argv.splice(i--, 1)
}
const read = () => {
next()
remove()

if (required && !arg) {
if (!arg) {
throw new Error('Unexpected end of arguments')
}

Expand All @@ -52,7 +65,12 @@ export function readOptions<T extends OptionReader[]>(...optionReaders: [...T]):
// eslint-disable-next-line no-unmodified-loop-condition
while (arg) {
if (isOption(arg)) {
Object.assign(options, readOption?.(removePrefix(arg), next, options))
optionResult = readOption(removePrefix(arg), read, options)

if (optionResult) {
remove()
Object.assign(options, optionResult)
}
}

next()
Expand Down
13 changes: 4 additions & 9 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,7 @@ export type ArgRefName<T extends ArgRef<string>> =

export type OptionsReaderState = Record<string, unknown>

export type OptionsReaderNext =
<T extends boolean>(required?: T) => (
T extends true
? string
: string | undefined
)
export type OptionsReaderRead = () => string

export type PrimitiveConstructor = StringConstructor | NumberConstructor | ArrayConstructor | BooleanConstructor

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

export type OptionResult<T extends string, K extends PrimitiveConstructor> = Record<T, OptionValueType<K>>
export type OptionResult<T extends string = string, K extends PrimitiveConstructor = PrimitiveConstructor> = Record<T, OptionValueType<K>>

export type OptionReader<T extends OptionResult<string, PrimitiveConstructor> = OptionResult<string, PrimitiveConstructor>> =
export type OptionReader<T extends OptionResult = OptionResult> =
(
option: string,
next: OptionsReaderNext,
read: OptionsReaderRead,
options: OptionsReaderState
) => T | null