-
-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathargs.ts
More file actions
113 lines (106 loc) · 2.78 KB
/
args.ts
File metadata and controls
113 lines (106 loc) · 2.78 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
/**
* Utility functions for parsing and processing command-line arguments.
* @module
*/
/**
* Parse command line arguments respecting quotes and escapes.
*
* This function properly handles:
* - Double quotes (`"`)
* - Single quotes (`'`)
* - Escape sequences (`\`)
* - Nested quotes of different types
*
* Note on edge cases:
* - Unclosed quotes: treated as part of the argument value
* - Trailing backslash: ignored (escape with no following character)
* - Empty string or only spaces: returns empty array
*
* @param cmdline - The command line string to parse
* @returns Array of parsed arguments
*
* @example
* ```ts
* parseArgs('file -input="Hello world"')
* // => ['file', '-input=Hello world']
*
* parseArgs("file -input='test'")
* // => ['file', '-input=test']
*
* parseArgs('file -input="He said \\"hello\\""')
* // => ['file', '-input=He said "hello"']
*
* parseArgs('file -input="unclosed')
* // => ['file', '-input=unclosed'] (unclosed quote)
* ```
*/
export function parseArgs(cmdline: string): string[] {
const args: string[] = [];
let current = "";
let inQuote: string | null = null;
let escaped = false;
for (const char of cmdline) {
if (escaped) {
current += char;
escaped = false;
} else if (char === "\\") {
escaped = true;
} else if (char === '"' || char === "'") {
if (inQuote === char) {
inQuote = null;
} else if (inQuote === null) {
inQuote = char;
} else {
current += char;
}
} else if (char === " " && inQuote === null) {
if (current) {
args.push(current);
current = "";
}
} else {
current += char;
}
}
if (current) {
args.push(current);
}
return args;
}
/**
* Extract option arguments from argument list.
*
* All arguments with the matching prefix are extracted and returned as an array.
* The caller can decide whether to use the first, last, or all values.
*
* @param args - Array of arguments to search
* @param prefix - Option prefix to extract (e.g., '-input=')
* @returns Tuple of [array of extracted values, remaining arguments]
*
* @example
* ```ts
* extractOption(['-input=Hello', 'file', '/path'], '-input=')
* // => [['Hello'], ['file', '/path']]
*
* extractOption(['file', '/path'], '-input=')
* // => [[], ['file', '/path']]
*
* extractOption(['-input=first', 'file', '-input=second'], '-input=')
* // => [['first', 'second'], ['file']]
* ```
*/
export function extractOption(
args: readonly string[],
prefix: string,
): [string[], string[]] {
const values: string[] = [];
const remaining: string[] = [];
for (const arg of args) {
if (arg.startsWith(prefix)) {
values.push(arg.slice(prefix.length));
} else {
remaining.push(arg);
}
}
return [values, remaining];
}