module.exports = function (RED) { "use strict"; function format_usage(usage, prefix) { if (!prefix) { prefix = []; } let out = ""; for (let k in usage) { if (!usage.hasOwnProperty(k)) continue; if(typeof usage[k] == "object"){ out += format_usage(usage[k], prefix.concat([k])); } else { let ext = k != "" ? [k] : []; out += prefix.concat(ext).join(" ") + ": " + usage[k] + "\n"; } } return out; } function depth_first(n, path) { if (!path) { path = [n.id]; } if (!n) { return null; } let usage = {}; if (n.type == 'parser-consume') { for (let r_idx in n.rules) { let r = n.rules[r_idx]; let key; if (r.t == "regex") { if (r.match_name){ key = `[${r.match_name}]`; } else { key = `[espressione]`; } } else { key = r.v; } if (r.help) { usage[key] = r.help; } else { let sub_usage = {}; for (let wire of n.wires[r_idx]) { if (path.indexOf(wire) === -1) { let sub_n = RED.nodes.getNode(wire); let tmp_sub_usage = depth_first(sub_n, path + [wire]); if (tmp_sub_usage !== null) { Object.assign(sub_usage, tmp_sub_usage); } } } usage[key] = sub_usage; } } } return usage; } function ParserEntryPoint(n) { RED.nodes.createNode(this, n); this.property = n.property; this.help_text = n.help_text; this.help_keyword = n.help_keyword; this.genera_errore = function(msg) { let out = ""; if (msg && msg.token_parser && msg.token_parser.consumed_tokens.length > 0) { let offending_token = msg.token_parser.consumed_tokens[msg.token_parser.consumed_tokens.length - 1]; if (offending_token == "") { offending_token = "(vuoto)"; } out += msg.token_parser.consumed_tokens.slice(0, -1).join(" ") +`: comando non riconosciuto: ${offending_token}.\n`; if (this.help_keyword) { let help_command = msg.token_parser.consumed_tokens.slice(0, -1).concat([this.help_keyword]).join(" "); out += `Usa '${help_command}' per la guida.\n`; } } return out; } this.genera_help = function (root, msg) { let usages = {}; if (!root) { for (let wire of root.wires[0]) { Object.assign(usages, depth_first(RED.nodes.getNode(wire))); } } else { usages = depth_first(root); } return format_usage(usages, msg.token_parser.consumed_tokens.slice(0,-1)); }; this.on("input", msg => { RED.util.evaluateNodeProperty(this.property, "msg", this, msg, (err, value) => { if (err) { this.error(`Can't evaluate msg.${this.property}`); } else { let tokens = value.trim().toLowerCase().split(" "); msg.regex_matches = {}; msg.token_parser = { new_tokens: tokens, consumed_tokens: [], help_keyword: this.help_keyword, on_error: (msg, maybe_error) => { let err = maybe_error ? maybe_error : this.genera_errore(msg); this.send([undefined, err]); }, on_help: (help_node, msg) => { let err = this.genera_help(help_node, msg); this.send([undefined, err]); } }; this.send([msg, undefined]); }; }); }); } RED.nodes.registerType("parser-entry-point", ParserEntryPoint); function ConsumaToken(n) { RED.nodes.createNode(this, n); this.rules = n.rules; this.behavior = n.behavior; this.checkall = n.checkall; function check_rule(r, token) { switch (r.t) { case "eq": return token == r.v.toLowerCase(); case "regex": let reg = new RegExp(r.v); return token.match(reg); } } this.on("input", msg => { let token = msg.token_parser.new_tokens.shift() || ""; msg.token_parser.consumed_tokens.push(token); if(token == msg.token_parser.help_keyword) { msg.token_parser.on_help(this, msg); return; } let out = []; let n_matches = 0; for (let r of this.rules) { let matches = check_rule(r, token); if (matches === true || (matches != null && matches.length && matches.length > 0)) { if (matches.length > 0) { msg.regex_matches[r.match_name] = matches; } out.push(msg); n_matches += 1; if (!this.checkall) { break; } } else { out.push(undefined); } } if (n_matches == 0) { msg.token_parser.on_error(msg); return; } this.send(out); }); } RED.nodes.registerType("parser-consume", ConsumaToken); }