|
| 1 | +const { parseCommandLine } = require('./utils.js') |
1 | 2 |
|
2 | 3 | module.exports = async function proc(node, args, ctx) { |
3 | 4 | /* |
@@ -25,113 +26,4 @@ module.exports = async function proc(node, args, ctx) { |
25 | 26 | } |
26 | 27 | } |
27 | 28 |
|
28 | | -// Examples: |
29 | | -// parseCommandLine('command hello world bla bla') |
30 | | -// -> ["command", { text: "hello world bla bla" }] |
31 | | -// |
32 | | -// parseCommandLine('cmd hello=world num=8 text="bla \\"bla"') |
33 | | -// -> ["cmd", { hello: "world", num: 8, text: 'bla "bla' }] |
34 | | -// |
35 | | -// parseCommandLine('cmd') |
36 | | -// -> ["cmd", {}] |
37 | 29 |
|
38 | | -function parseCommandLine(input) { |
39 | | - const s = String(input); |
40 | | - let i = 0, len = s.length; |
41 | | - |
42 | | - function skipWS() { while (i < len && /\s/.test(s[i])) i++; } |
43 | | - |
44 | | - // 1) Parse leading alphanumeric command |
45 | | - skipWS(); |
46 | | - const cmdStart = i; |
47 | | - while (i < len && /[A-Za-z0-9_\-]/.test(s[i])) i++; |
48 | | - const command = s.slice(cmdStart, i); |
49 | | - if (!command) return [null, {}]; |
50 | | - |
51 | | - // 2) Parse the remainder as args |
52 | | - skipWS(); |
53 | | - const r = s.slice(i); |
54 | | - if (!r.trim()) return [command, {}]; |
55 | | - |
56 | | - function parseArgs(str) { |
57 | | - if (!/^\s*[A-Za-z0-9]+=/.test(str)) { |
58 | | - return { text: str.trim() }; |
59 | | - } |
60 | | - |
61 | | - let j = 0; |
62 | | - const L = str.length; |
63 | | - const out = {}; |
64 | | - |
65 | | - function skipW() { while (j < L && /\s/.test(str[j])) j++; } |
66 | | - |
67 | | - function parseKey() { |
68 | | - const start = j; |
69 | | - while (j < L && str[j] !== '=' && !/\s/.test(str[j])) j++; |
70 | | - return str.slice(start, j); |
71 | | - } |
72 | | - |
73 | | - function parseQuotedValue(q) { |
74 | | - j++; // skip opening quote |
75 | | - let val = ''; |
76 | | - while (j < L) { |
77 | | - const ch = str[j++]; |
78 | | - if (ch === '\\') { |
79 | | - if (j >= L) break; |
80 | | - const esc = str[j++]; |
81 | | - if (esc === 'n') val += '\n'; |
82 | | - else if (esc === 't') val += '\t'; |
83 | | - else if (esc === 'r') val += '\r'; |
84 | | - else val += esc; // includes \" \\ \' |
85 | | - } else if (ch === q) { |
86 | | - return val; |
87 | | - } else { |
88 | | - val += ch; |
89 | | - } |
90 | | - } |
91 | | - return val; // best-effort if unclosed |
92 | | - } |
93 | | - |
94 | | - function parseUnquotedValue() { |
95 | | - const start = j; |
96 | | - while (j < L && !/\s/.test(str[j])) j++; |
97 | | - return str.slice(start, j); |
98 | | - } |
99 | | - |
100 | | - function coerce(v) { |
101 | | - if (/^-?\d+(\.\d+)?$/.test(v)) return Number(v); |
102 | | - const low = v.toLowerCase(); |
103 | | - if (low === 'true') return true; |
104 | | - if (low === 'false') return false; |
105 | | - if (low === 'null') return null; |
106 | | - return v; |
107 | | - } |
108 | | - |
109 | | - while (j < L) { |
110 | | - skipW(); |
111 | | - if (j >= L) break; |
112 | | - |
113 | | - const key = parseKey(); |
114 | | - if (!key) return { text: str.trim() }; |
115 | | - |
116 | | - skipW(); |
117 | | - if (j < L && str[j] === '=') { |
118 | | - j++; // skip '=' |
119 | | - skipW(); |
120 | | - let valueStr = ''; |
121 | | - if (j < L && (str[j] === '"' || str[j] === "'")) { |
122 | | - valueStr = parseQuotedValue(str[j]); |
123 | | - } else { |
124 | | - valueStr = parseUnquotedValue(); |
125 | | - } |
126 | | - out[key] = coerce(valueStr); |
127 | | - } else { |
128 | | - // If a non key=value token appears, treat the whole remainder as text |
129 | | - return { text: str.trim() }; |
130 | | - } |
131 | | - } |
132 | | - |
133 | | - return out; |
134 | | - } |
135 | | - |
136 | | - return [command, parseArgs(r)]; |
137 | | -} |
0 commit comments