Skip to content

Commit 398763f

Browse files
authored
feat: add new options (#2)
1 parent 749ff8a commit 398763f

10 files changed

Lines changed: 262 additions & 81 deletions

README.md

Lines changed: 65 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ A fast and ultra lightweight CLI argument parser.
55
<sub><a href="https://github.com/hypernym-studio/args">Repository</a> | <a href="https://www.npmjs.com/package/@hypernym/args">Package</a> | <a href="https://github.com/hypernym-studio/args/releases">Releases</a> | <a href="https://github.com/hypernym-studio/args/discussions">Discussions</a></sub>
66

77
```sh
8-
npm i @hypernym/args
8+
pnpm add @hypernym/args
99
```
1010

1111
## Features
@@ -50,6 +50,12 @@ $ --flag value
5050
# => { _: [], flag: 'value', }
5151
```
5252

53+
```sh
54+
$ --flag=value
55+
56+
# => { _: [], flag: 'value', }
57+
```
58+
5359
### Aliases
5460

5561
Inputs with `-` prefix are parsed as _aliases_.
@@ -68,13 +74,19 @@ $ -alias value
6874
# => { _: [], alias: 'value', }
6975
```
7076

77+
```sh
78+
$ -alias=value
79+
80+
# => { _: [], alias: 'value', }
81+
```
82+
7183
### Ignores
7284

7385
- Ignores standalone inputs `--` and `-`
74-
- Ignores all inputs that include `=`
86+
- Ignores argument inputs that include `=`
7587

7688
```sh
77-
$ --flag=value -- arg=value - -alias=value
89+
$ arg=value -- arg-b=value -
7890

7991
# => { _: [] }
8092
```
@@ -99,7 +111,7 @@ const args = createArgs<Args>()
99111

100112
console.log(args)
101113

102-
/* Output:
114+
/*
103115
{
104116
_: ['hello', 'world'],
105117
foo: 'bar',
@@ -114,37 +126,78 @@ console.log(args)
114126

115127
### argv
116128

117-
- Type: `string[]`
129+
Specifies an array of values to parse as arguments.
130+
131+
- Type: `string[] | undefined`
118132
- Default: `process.argv.slice(2)`
119133

120134
```ts
121-
const args = createArgs({
135+
import { createArgs } from '@hypernym/args'
136+
137+
createArgs({
122138
argv: process.argv.slice(2),
123139
})
124140
```
125141

126142
### alias
127143

128-
- Type: `object`
144+
Specifies an object of `alias` that will be added to the parsed output with matching values.
145+
146+
- Type: `Record<string, string | string[]> | undefined`
129147
- Default: `undefined`
130148

131149
```ts
132-
const args = createArgs({
150+
import { createArgs } from '@hypernym/args'
151+
152+
createArgs({
133153
alias: {
134154
config: ['conf', 'c'],
135155
help: 'h',
136156
},
137157
})
138158
```
139159

160+
### defaults
161+
162+
Specifies an object of `defaults` that will be added to the parsed output regardless of `CLI` inputs.
163+
164+
- Type: `(Record<string, unknown> & { _?: string[] }) | undefined`
165+
- Default: `undefined`
166+
167+
```ts
168+
import { createArgs } from '@hypernym/args'
169+
170+
createArgs({
171+
defaults: {
172+
_: ['value'],
173+
a: true,
174+
},
175+
})
176+
```
177+
178+
### exclude
179+
180+
Specifies an array of values that will be skipped when parsing arguments.
181+
182+
- Type: `string[] | undefined`
183+
- Default: `undefined`
184+
185+
```ts
186+
import { createArgs } from '@hypernym/args'
187+
188+
createArgs({
189+
exclude: ['arg', '--flag', '-alias'],
190+
})
191+
```
192+
140193
## Community
141194

142-
Feel free to use the official [discussions](https://github.com/hypernym-studio/args/discussions) for any additional questions.
195+
Feel free to ask questions or share new ideas.
196+
197+
Use the official [discussions](https://github.com/hypernym-studio/args/discussions) to get involved.
143198

144199
## License
145200

146-
Developed in 🇭🇷 Croatia
201+
Developed in 🇭🇷 Croatia, © Hypernym Studio.
147202

148203
Released under the [MIT](LICENSE.txt) license.
149-
150-
© Hypernym Studio

src/index.ts

Lines changed: 49 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
// Inspired by mri, https://github.com/lukeed/mri 1.2.0 MIT
2-
// Rewritten in TypeScript by Ivo Dolenc, Hypernym Studio
1+
// Inspired by mri, 1.2.0, MIT License, https://github.com/lukeed/mri
2+
// Rewritten and adapted to @hypernym/args, 0.3.0, MIT License, https://github.com/hypernym-studio/args
33

4-
import { isString, isArray, isFlag, isAlias } from './utils.js'
5-
import type { Defaults, Args, Options } from './types/index.js'
4+
import { isString, isArray, isFlag, isAlias } from './utils'
5+
import type { Defaults, Args, Options } from './types'
66

77
/**
8-
* Creates a command-line argument parser for the Node process.
8+
* Creates a command-line argument parser.
99
*
1010
* @example
1111
*
@@ -24,53 +24,70 @@ import type { Defaults, Args, Options } from './types/index.js'
2424
export function createArgs<T = Defaults>({
2525
argv = process.argv.slice(2),
2626
alias,
27+
defaults,
28+
exclude,
2729
}: Options = {}): Args<T> {
2830
const args: Args = {
2931
_: [],
3032
}
3133

32-
function _setArg(arg: string, index: number) {
34+
const excludes = ['--', '-', ...(exclude || [])]
35+
argv = argv.filter((arg) => !excludes.includes(arg))
36+
37+
function setArg(arg: string, index: number) {
3338
let value: boolean | string = true
34-
const argKey = isFlag(arg) ? arg.slice(2) : arg.slice(1)
35-
const argValue = argv[index + 1]
39+
let argKey: string = isFlag(arg) ? arg.slice(2) : arg.slice(1)
40+
let argValue: string
41+
42+
if (arg.includes('=')) {
43+
const split = argKey.split('=')
44+
argKey = split[0]
45+
argValue = split[1]
46+
} else {
47+
argValue = argv[index + 1]
48+
}
3649

3750
if (argValue && !argValue.startsWith('-')) value = argValue
3851

39-
if (argKey && !argKey.includes('=')) {
40-
if (alias) {
41-
for (const [aliasKey, aliasValue] of Object.entries(alias)) {
42-
if (aliasKey.includes(argKey) || aliasValue.includes(argKey)) {
43-
args[aliasKey] = value
44-
if (isString(aliasValue)) args[aliasValue] = value
45-
if (isArray(aliasValue)) for (const v of aliasValue) args[v] = value
46-
}
52+
if (alias) {
53+
for (const [aliasKey, aliasValue] of Object.entries(alias)) {
54+
if (aliasKey.includes(argKey) || aliasValue.includes(argKey)) {
55+
args[aliasKey] = value
56+
if (isString(aliasValue)) args[aliasValue] = value
57+
if (isArray(aliasValue)) for (const v of aliasValue) args[v] = value
58+
return
4759
}
4860
}
49-
50-
args[argKey] = value
5161
}
62+
63+
args[argKey] = value
5264
}
5365

54-
for (const [index, arg] of argv.entries()) {
55-
// flags '--'
56-
if (isFlag(arg)) _setArg(arg, index)
57-
// aliases '-'
58-
else if (isAlias(arg)) _setArg(arg, index)
59-
// unprefixed values
66+
for (let i = 0, l = argv.length; i < l; i++) {
67+
const arg = argv[i]
68+
69+
// '--flags' and '-alias'
70+
if (isFlag(arg) || isAlias(arg)) setArg(arg, i)
71+
// 'arguments' (unprefixed)
6072
else {
61-
const _arg = argv[index - 1]
73+
const prevArg: string | undefined = argv[i - 1]
6274

63-
if (!_arg) {
64-
if (!arg.startsWith('-') && !arg.includes('=')) {
65-
args._.push(arg)
75+
if (!prevArg) {
76+
if (!arg.includes('=')) args._.push(arg)
77+
} else if (prevArg) {
78+
if (!prevArg.startsWith('-') || prevArg.includes('=')) {
79+
if (!arg.includes('=')) args._.push(arg)
6680
}
67-
} else if (!_arg.startsWith('-') && !arg.includes('=')) {
68-
args._.push(arg)
69-
} else if ((_arg === '-' || _arg === '--') && !arg.includes('=')) {
70-
args._.push(arg)
7181
}
7282
}
7383
}
7484

85+
if (defaults) {
86+
if (defaults._) args._ = [...defaults._, ...args._]
87+
for (const [dKey, dValue] of Object.entries(defaults)) {
88+
if (dKey !== '_') args[dKey] = dValue
89+
}
90+
}
91+
7592
return args as Args<T>
7693
}

src/types/index.ts

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,78 @@ export type Args<T = Defaults> = T & {
55
}
66

77
export interface Options {
8+
/**
9+
* Specifies an array of values to parse as arguments.
10+
*
11+
* @default process.argv.slice(2)
12+
*
13+
* @example
14+
*
15+
* ```ts
16+
* import { createArgs } from '@hypernym/args'
17+
*
18+
* createArgs({
19+
* argv: process.argv.slice(2),
20+
* })
21+
* ```
22+
*/
823
argv?: string[]
24+
/**
25+
* Specifies an `alias` object that will be added to the parsed output with matching values.
26+
*
27+
* @default undefined
28+
*
29+
* @example
30+
*
31+
* ```ts
32+
* import { createArgs } from '@hypernym/args'
33+
*
34+
* createArgs({
35+
* alias: {
36+
* config: ['conf', 'c'],
37+
* help: 'h',
38+
* },
39+
* })
40+
* ```
41+
*/
942
alias?: Record<string, string | string[]>
43+
/**
44+
* Specifies an `defaults` object that will be added to the parsed output regardless of `CLI` inputs.
45+
*
46+
* @default undefined
47+
*
48+
* @example
49+
*
50+
* ```ts
51+
* import { createArgs } from '@hypernym/args'
52+
*
53+
* createArgs({
54+
* defaults: {
55+
* _: ['value'],
56+
* a: true,
57+
* }
58+
* })
59+
* ```
60+
*/
61+
defaults?: Defaults & {
62+
_?: string[]
63+
}
64+
/**
65+
* Specifies an array of values that will be skipped when parsing arguments.
66+
*
67+
* @default undefined
68+
*
69+
* @example
70+
*
71+
* ```ts
72+
* import { createArgs } from '@hypernym/args'
73+
*
74+
* createArgs({
75+
* exclude: ['arg', '--flag', '-alias'],
76+
* })
77+
* ```
78+
*/
79+
exclude?: string[]
1080
}
1181

12-
// Auto-generated
13-
export * from '../index.js'
82+
export * from '@'

test/alias.test.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { test, expect } from 'vitest'
2+
import { createArgs } from '@'
3+
4+
test('args-alias', () => {
5+
interface ArgsAlias {
6+
a?: string
7+
b?: string
8+
c?: boolean
9+
d?: boolean
10+
}
11+
12+
const argsAlias = createArgs<ArgsAlias>({
13+
argv: ['-a=value', '-b', 'value', '-c', '-d'],
14+
})
15+
16+
expect(argsAlias).toStrictEqual({
17+
_: [],
18+
a: 'value',
19+
b: 'value',
20+
c: true,
21+
d: true,
22+
})
23+
})

test/aliases.test.ts

Lines changed: 0 additions & 24 deletions
This file was deleted.

0 commit comments

Comments
 (0)