Skip to content

Commit a6d3cd6

Browse files
committed
massive sort
1 parent 58fcc48 commit a6d3cd6

File tree

1 file changed

+71
-104
lines changed

1 file changed

+71
-104
lines changed

index.js

Lines changed: 71 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,11 @@ const isA = Array.isArray;
1212
* @property {OptKit} [set] Array of options to set the variable value
1313
* @property {OptKit} [rst] Array of options to reset the variable value
1414
*
15-
* @typedef {OptDef | OptDef[]} HaltKit Halt options, identical to `OptKit`, for now...
16-
* @typedef {{opt: OptStr, key: VarKey}} HaltRes
17-
* @typedef {Record<VarKey, VarKit | HaltKit>} KeyKitMap
15+
* @typedef {OptDef | OptDef[]} ExitKit Exit options, identical to `OptKit` for now
16+
* @typedef {Record<VarKey, VarKit | ExitKit>} KeyKitMap
1817
* @typedef {Record<VarKey, VarVal>} KeyValMap
1918
*
20-
* @callback CanQuit
19+
* @callback IsFatal
2120
* @param {{msg: string, i: number, opt: OptStr, key?: VarKey, val?: VarVal }} err
2221
* @returns {boolean} Whether the parsing should continue (false) or quit (true)
2322
* @typedef {Record<OptStr, VarKey>} OptKeyMap internal type
@@ -26,150 +25,118 @@ const isA = Array.isArray;
2625
const god = ok => typeof ok === 'string' ? [ok] : isA(ok) ? ok : [];
2726
/**
2827
* Command line argument parser function
29-
* @param {string[]} argv Command line arguments array
30-
* @param {number} i Index of current argument being processed
28+
* @param {string[]} argv Command line arguments array, e.g. `process.argv`
29+
* @param {number} i Index of current argument being processed, e.g. `2`
3130
* @param {KeyKitMap} req Options structure definition
3231
* @param {KeyValMap} res Object to store parsed results
33-
* @param {CanQuit} err Error handler function
34-
* @returns {{ i: number, halt?: HaltRes }}
32+
* @param {IsFatal} err Error handler function, return true to quit parsing
33+
* @returns {{ i: number, opt: OptStr, key?: VarKey, exit: boolean }}
3534
* @example
3635
*/
3736
export default function parse(argv, i, req, res, err) {
38-
/** @type {OptKeyMap} options to set var */
39-
const set_ = {};
40-
/** @type {OptKeyMap} options to reset var */
41-
const rst_ = {};
42-
/** @type {OptKeyMap} options to halt parse */
43-
const hlt_ = {};
4437
/** @type {OptStr} option */
4538
let opt = '';
46-
/** @type {OptStr} option of the extension */
47-
let ext = '';
4839
/** @type {VarKey | undefined} key */
4940
let key;
50-
/** @type {VarKey | undefined} key to set the universe variable */
51-
let suv;
52-
/** @type {boolean} set universe variable to halt (?) */
53-
let sun = false;
54-
// methodsze
55-
/** @param {string} msg @param {VarVal} [val] */
56-
const ask = (msg, val) => err({msg, i, opt, key, val});
57-
// below: assert(key != null)
5841
/** @param {VarVal} val */
5942
const set = val => {
6043
const cur = res[key];
6144
if (isA(cur)) cur.push(val); else res[key] = val;
62-
};
63-
const rst = () => {
45+
}, rst = () => {
6446
const def = req[key].def;
6547
res[key] = isA(def) ? def.slice() : def;
66-
};
67-
const noB = () => {
48+
}, noB = () => {
6849
const def = req[key].def;
6950
if (typeof def === 'boolean') {
7051
res[key] = !def;
7152
return false;
7253
} return true;
73-
};
74-
/** @param {string} s */
75-
const one = s => {
76-
if (key = set_[opt = s]) {
77-
if (noB()) ext = opt;
78-
} else if (key = rst_[opt]) rst();
79-
else return ask('invalid option');
80-
return false;
81-
};
54+
}, ask = (msg, val) => err({msg, i, opt, key, val});
8255
// prepare
56+
/** @type {OptKeyMap} */
57+
const set_ = {}, rst_ = {}, exit_ = {};
58+
/** @type {VarKey | undefined} */
59+
let _key, _exit = false;
8360
for (key in req) {
8461
const vk = req[key];
85-
H: { let hk;
62+
H: { let xk; // stricter than god()
8663
switch (typeof vk) {
8764
case 'object':
88-
if (vk == null) hk = [key];
89-
else if (isA(vk)) hk = vk;
65+
if (vk == null) xk = [key];
66+
else if (isA(vk)) xk = vk;
9067
else break H; break;
91-
case 'string': hk = [vk]; break;
68+
case 'string': xk = [vk]; break;
9269
default: continue; }
93-
for (const o of hk) if (o!=='--') hlt_[o||key] = key; else suv = key, sun = true; // lol
70+
for (const o of xk) if (o!=='--') exit_[o||key] = key; else _key = key, _exit = true;
9471
continue; }
9572
const def = vk.def;
96-
res[key] = isA(def) ? def.slice() : def; // just rst() with known `def`
97-
for (const o of god(vk.set)) if (o!=='--') set_[o||key] = key; else suv = key, sun = false;
98-
for (const o of god(vk.rst)) if (o!=='--') rst_[o||key] = key; // ?? wanna reset around?
73+
res[key] = isA(def) ? def.slice() : def;
74+
for (const o of god(vk.set)) if (o!=='--') set_[o||key] = key; else _key = key, _exit = false;
75+
for (const o of god(vk.rst)) if (o!=='--') rst_[o||key] = key;
9976
}
10077
// process
101-
/** @type {HaltRes} */
102-
let halt = null;
78+
let ext = '', exit = '';
10379
I: for (; i < argv.length; ++i) {
10480
const s = argv[i];
105-
// extension ~ Just one more thing
106-
if (ext) { // fact(const val = s)
107-
ext = ''; // assert(opt === ext)
108-
if (key) { // assert(key === set_[opt])
109-
set(s);
110-
continue;
111-
}
81+
// extension ~ ASSERT key = set_[opt = ext]
82+
if (ext) { ext = '';
83+
if (key) { set(s); continue; }
11284
if (ask('invalid option', s)) break;
11385
}
114-
// halt ~ Basic so that `i` is usable for resuming parsing
115-
if (key = hlt_[opt = s]) { ++i; halt = {opt, key}; break; }
116-
// abc
117-
if (s.length < 2 || s[0] !== '-') {
118-
if (key = set_[opt = s]) {
119-
if (noB()) ext = opt;
120-
} else if (key = rst_[opt]) rst();
121-
else if (key = suv) if (sun) { ++i; halt = {opt, key}; break; } else set(s);
86+
if (s.length < 2 || s[0] !== '-') { // abc
87+
if (key = set_[opt = s]) { if (noB()) ext = opt; }
88+
else if (key = rst_[opt]) rst();
89+
else if (key = exit_[opt]) { exit = key; break; }
90+
else if (key = _key) if (_exit) { exit = key; break; } else set(s);
12291
else if (ask('invalid option', s)) break;
123-
continue;
124-
}
125-
// -abc
126-
if (s[1] !== '-') {
127-
// -ab ~ no extension
92+
} else if (s[1] !== '-') { // -abc
12893
const J = s.length - 1;
12994
for (let j = 1; j < J; ++j) {
95+
// -ab ~ no extension, no universe, no exit
13096
opt = '-' + s[j];
131-
if (key = set_[opt]) {
132-
if (noB()) {
133-
set(s.slice(j + 1));
134-
continue I;
135-
}
136-
} else if (key = rst_[opt]) rst();
97+
if (key = set_[opt]) { if (noB()) { set(s.slice(j + 1)); continue I; } }
98+
else if (key = rst_[opt]) rst();
99+
else if (key = exit_[opt]) { if (ask('cannot exit inside an argument')) break I; }
137100
else if (ask('invalid option')) break I;
138101
}
139-
// -c ~ not universe
140-
if (one('-' + s[J])) break;
141-
continue;
142-
}
143-
// --abc
144-
if (s.length > 2) {
102+
// -c ~ no universe, can exit
103+
opt = '-' + s[J];
104+
if (key = set_[opt]) { if (noB()) ext = opt; }
105+
else if (key = rst_[opt]) rst();
106+
else if (key = exit_[opt]) { exit = key; break; }
107+
else if (ask('invalid option')) break;
108+
} else if (s.length > 2) { // --opt
145109
const k = s.indexOf('=');
146-
// --opt ~ not universe
147-
if (k < 0) if (one(s)) break; else continue;
148-
// --opt=val ~ explicit assignment
110+
if (k < 0) {
111+
// --opt ...
112+
if (key = set_[opt = s]) { if (noB()) ext = opt; }
113+
else if (key = rst_[opt]) rst();
114+
else if (key = exit_[opt]) { exit = key; break; }
115+
else if (ask('invalid option')) break;
116+
continue;
117+
}
118+
// --opt=val
149119
opt = s.slice(0, k);
150-
const val = s.slice(k + 1);
151-
if (key = set_[opt]) {
152-
if (typeof res[key] === 'boolean') {
153-
if (ask('Cannot assign a value to a boolean-type option', val)) break;
154-
} else set(val);
155-
} else if (key = rst_[opt]) {
156-
if (ask('Cannot assign a value to a reset-type option', val)) break;
157-
} else {
158-
if (ask('invalid option', val)) break;
120+
const v = s.slice(k + 1); let t;
121+
if (key = set_[opt])
122+
switch (t = typeof res[key]) {
123+
case 'boolean': break;
124+
default: set(v); continue; }
125+
else if (key = rst_[opt]) t = 'reset';
126+
else if (key = exit_[opt]) t = 'exit';
127+
else if (ask('invalid option', v)) break; else continue;
128+
if (ask(`Cannot assign a value to a ${t} option`, v)) break;
129+
} else { opt = '--';
130+
if (key = _key) {
131+
if (_exit) { exit = key; break; }
132+
const a = res[key], l = argv.length; ++i;
133+
if (isA(a)) while (i < l) a.push(argv[i++]);
134+
else if (i < l) res[key] = argv[(i = l) - 1];
135+
break;
159136
}
160-
continue;
161-
}
162-
// -- ~ collect all
163-
opt = '--';
164-
if (key = suv) { ++i;
165-
if (sun) { halt = {opt, key}; break; }
166-
const cur = res[key], len = argv.length;
167-
if (isA(cur)) while (i < len) cur.push(argv[i++]);
168-
else if (i < len) res[key] = argv[(i = len) - 1];
169-
break;
137+
if (ask('unexpected argument')) break;
170138
}
171-
if (ask('unexpected argument')) break;
172139
}
173-
if (ext) ask('This option requires an argument'); // assertion same as above
174-
return {i, halt};
140+
if (ext) ask('This option requires an argument');
141+
return { i, exit };
175142
};

0 commit comments

Comments
 (0)