-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathparse.ts
56 lines (50 loc) · 1.55 KB
/
parse.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
import typeDetect from 'https://deno.land/x/[email protected]/index.js'
import type { Option, ParsedOptions } from './types.ts'
import { parseArgs, type ParseArgsConfig } from 'node:util'
export const handleArgParsing = <
T extends readonly Option[] = readonly Option[],
>(
{ options }: { options: T },
args: string[],
parseOptions?: ParseArgsConfig,
): {
positionals: (string | number)[]
parsed: ParsedOptions<typeof options>
} => {
const { positionals, values: parsed } = parseArgs({
...parseOptions,
args,
options: options.reduce((acc, curr) => {
acc[curr.name] = {
type: curr.type,
...(curr.short ? { short: curr.short } : {}),
}
return acc
}, {} as NonNullable<ParseArgsConfig['options']>),
allowPositionals: true,
strict: false,
})
const requiredOptions = options.filter((opt) => opt.required)
const parsedArgs = Object.entries(parsed)
for (const opt of requiredOptions) {
if (
!parsedArgs.find((arg) => arg[0] === opt.name || arg[0] === opt.short)
) {
throw new Error(`Argument ${opt.name} is required`)
}
}
for (const [arg, value] of parsedArgs) {
const opt = options.find((x) => x.name === arg || x.short === arg)
const actualType = typeDetect(value)
if (!opt) throw new Error(`Unknown argument: ${arg}`)
if (actualType !== opt.type) {
throw new Error(
`Invalid argument type for ${arg}: expected ${opt.type}, got ${actualType}`,
)
}
}
return {
positionals,
parsed: parsed as ParsedOptions<typeof options>,
}
}