This repository was archived by the owner on Nov 21, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathparser.ts
107 lines (90 loc) · 2.99 KB
/
parser.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
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
import { ParsedArgument, Command } from './models/command.model';
import normalize, { normalizeWithoutLowercase } from './normalize';
import findCommand from './command/find-command';
import findArgument from './argument/find-argument';
import validateArgument from './argument/validate-argument';
import validateCommandValue from './command/validate-command-value';
/**
* Parse user-input, find the command and extract arguments. Test the validity
* of arguments and of the command value. Return the command found, parsed
* arguments and validity of the input.
*
* @param input user-input terminal command
* @param commands an array of commands with a type that extends `Command`
*/
function parse<C extends Command>(
input: string,
commands: C[],
): {
command: C | undefined;
parsedArgs: ParsedArgument[];
valid: boolean;
} {
const originalsSplitted = normalizeWithoutLowercase(input).split(' ');
const splitted = normalize(input).split(' ');
const command = findCommand<C>(splitted[0], commands);
const originalArgs = originalsSplitted.splice(1, originalsSplitted.length);
const args = splitted.splice(1, splitted.length);
const parsedArgs: ParsedArgument[] = [];
let valid = false;
if (command) {
valid = !command.requireValue;
for (let i = 0; i < args.length; i += 1) {
const arg = args[i];
const originalArg = originalArgs[i];
// Try to detect an argument (and its value if it have one)
if (arg.startsWith('-')) {
const parsedArg = findArgument(command, arg);
// If the argument have been found
if (parsedArg) {
parsedArgs.push({
type: 'ARG_NAME',
reflect: parsedArg,
value: originalArg,
isValid: true,
});
// If the parsed argument require a value, make sure the value is
// valid (and increase our loop index)
if (parsedArg.requireValue) {
const nextArgValue = args[i + 1];
const nextArgValid = validateArgument(parsedArg, nextArgValue);
parsedArgs.push({
type: 'ARG_VALUE',
reflect: parsedArg,
value: nextArgValue,
isValid: nextArgValid,
});
i = i + 1;
}
}
// Unable to find a valid argument name
else {
parsedArgs.push({
type: 'ARG_NAME',
value: originalArg,
isValid: false,
});
}
}
// If not an argument, fallback on the command value and end the loop
else {
const commandValueValid = validateCommandValue(command, arg);
parsedArgs.push({
type: 'CMD_VALUE',
reflect: command,
value: originalArg,
isValid: commandValueValid,
});
valid = commandValueValid;
i = args.length;
}
}
}
valid = valid ? parsedArgs.every((arg) => arg.isValid) : valid;
return {
command,
parsedArgs,
valid,
};
}
export default parse;