v1
This commit is contained in:
parent
d8c1dc196d
commit
9a7411420a
95
parser.js
95
parser.js
@ -29,6 +29,7 @@ const ATTR_TYPE = {
|
|||||||
POSITIONAL: "positional",
|
POSITIONAL: "positional",
|
||||||
OPTION: "option",
|
OPTION: "option",
|
||||||
FLAG: "flag",
|
FLAG: "flag",
|
||||||
|
REST: "rest",
|
||||||
};
|
};
|
||||||
const CONTEXT = {
|
const CONTEXT = {
|
||||||
POS_COUNT: "pos_count",
|
POS_COUNT: "pos_count",
|
||||||
@ -98,6 +99,11 @@ function parse_spec_entry(raw_entry, context) {
|
|||||||
},
|
},
|
||||||
})[attribute](attribute_value);
|
})[attribute](attribute_value);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Set default values
|
||||||
|
if (!attributes[ATTR.MAP]) {
|
||||||
|
attributes[ATTR.MAP] = entry.aliases[0]; // alias 0 is always the larger format
|
||||||
|
}
|
||||||
return attributes;
|
return attributes;
|
||||||
},
|
},
|
||||||
}[entry.type]();
|
}[entry.type]();
|
||||||
@ -126,12 +132,11 @@ function parse_spec(spec, command = null) {
|
|||||||
const context = {
|
const context = {
|
||||||
...ctx_defaults,
|
...ctx_defaults,
|
||||||
reset() {
|
reset() {
|
||||||
Object.assing(this, defaults);
|
Object.assign(this, ctx_defaults);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
for (const raw_entry of spec) {
|
for (const raw_entry of spec) {
|
||||||
const entry = parse_spec_entry(raw_entry, context);
|
const entry = parse_spec_entry(raw_entry, context);
|
||||||
console.log(entry.type);
|
|
||||||
const exit = {
|
const exit = {
|
||||||
[ENTRY.COMMAND]: () => {
|
[ENTRY.COMMAND]: () => {
|
||||||
// Previous command was populated
|
// Previous command was populated
|
||||||
@ -164,26 +169,90 @@ function parse_spec(spec, command = null) {
|
|||||||
spec_data[`${cmd_id}.${entry.id}`] = entry;
|
spec_data[`${cmd_id}.${entry.id}`] = entry;
|
||||||
entry.aliases.forEach((alias) => {
|
entry.aliases.forEach((alias) => {
|
||||||
if (entry.attr.type === ATTR_TYPE.POSITIONAL) {
|
if (entry.attr.type === ATTR_TYPE.POSITIONAL) {
|
||||||
spec_aliases[`${cmd_id}.${entry.attr[ATTR.POSITION]}`] = entry.id;
|
const alias_id = `${cmd_id}.${entry.attr[ATTR.POSITION]}`;
|
||||||
} else {
|
spec_aliases[alias_id] = `${cmd_id}.${entry.id}`;
|
||||||
spec_aliases[`${cmd_id}.${alias}`] = entry.id;
|
} else if (
|
||||||
|
entry.attr.type === ATTR_TYPE.OPTION ||
|
||||||
|
entry.attr.type === ATTR_TYPE.FLAG
|
||||||
|
) {
|
||||||
|
const alias_id = `${cmd_id}.${alias}`;
|
||||||
|
spec_aliases[alias_id] = `${cmd_id}.${entry.id}`;
|
||||||
|
} else if (entry.attr.type === ATTR_TYPE.REST) {
|
||||||
|
const alias_id = `${cmd_id}._rest`;
|
||||||
|
spec_aliases[alias_id] = `${cmd_id}.${entry.id}`;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
}[entry.type]();
|
}[entry.type]();
|
||||||
|
context.reset();
|
||||||
if (exit) break;
|
if (exit) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return { spec_data, spec_aliases };
|
if (command && cmd_id === null) {
|
||||||
|
throw new Error(`Invalid command: ${command}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
data: spec_data,
|
||||||
|
aliases: spec_aliases,
|
||||||
|
cmd_id: command ? cmd_id : null,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const r = parse_spec(SPEC, "build");
|
const r = parse_spec(SPEC);
|
||||||
console.log(JSON.stringify(r, null, 2));
|
// console.log(JSON.stringify(r, null, 2));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* INPUT: build -i tm0:node mybox
|
* @return {<variable_name>:<value>}
|
||||||
*
|
|
||||||
* spec_aliases[build] -> "0"
|
|
||||||
* -i -> option/flag short -> spec_aliases["0.i"] -> "1"
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
const inspect = (v) => console.log(JSON.stringify(v, null, 2));
|
||||||
|
function parse_args(spec, args_raw) {
|
||||||
|
const vars = {};
|
||||||
|
const args = args_raw.split(" ");
|
||||||
|
args.shift(); // script name
|
||||||
|
const cmd = args.shift();
|
||||||
|
|
||||||
|
const get_next = () => args[0];
|
||||||
|
const consume = () => args.shift();
|
||||||
|
const consume_all = () => args.splice(0);
|
||||||
|
|
||||||
|
const cmd_spec = parse_spec(spec, cmd);
|
||||||
|
const cmd_info = cmd_spec.data[cmd_spec.cmd_id];
|
||||||
|
let positional_count = 0;
|
||||||
|
while (args.length > 0) {
|
||||||
|
const next = get_next();
|
||||||
|
const [type, next_arg] = (() => {
|
||||||
|
if (next === "--") {
|
||||||
|
return [ATTR_TYPE.REST, "_rest"]; // check if spec if expecing a rest arg
|
||||||
|
} else if (next.startsWith("--")) {
|
||||||
|
return [ATTR_TYPE.OPTION, next.slice(2)]; // invalid type. use only to know if to search per key or whole string
|
||||||
|
} else if (next.startsWith("-")) {
|
||||||
|
return [ATTR_TYPE.FLAG, next.slice(1)]; // same
|
||||||
|
} else {
|
||||||
|
return [ATTR_TYPE.POSITIONAL, positional_count++];
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
const alias_id = `${cmd_info.id}.${next_arg}`;
|
||||||
|
const next_arg_id = cmd_spec.aliases[alias_id];
|
||||||
|
if (typeof next_arg_id !== "undefined") {
|
||||||
|
consume();
|
||||||
|
const next_arg_info = cmd_spec.data[next_arg_id];
|
||||||
|
if (next_arg_info.attr.type === ATTR_TYPE.OPTION) {
|
||||||
|
vars[next_arg_info.attr.map] = consume();
|
||||||
|
} else if (next_arg_info.attr.type === ATTR_TYPE.FLAG) {
|
||||||
|
vars[next_arg_info.attr.map] = true;
|
||||||
|
} else if (next_arg_info.attr.type === ATTR_TYPE.REST) {
|
||||||
|
vars[next_arg_info.attr.map] = consume_all();
|
||||||
|
} else if (next_arg_info.attr.type === ATTR_TYPE.POSITIONAL) {
|
||||||
|
vars[next_arg_info.attr.map] = next;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
inspect(vars);
|
||||||
|
throw new Error(`Invalid argument: '${next_arg}'`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return vars;
|
||||||
|
}
|
||||||
|
|
||||||
|
const args = "dev build -q -v --image tm0:node mybox -v -- bla1 bla2";
|
||||||
|
inspect(parse_args(SPEC, args));
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user