diff --git a/src/commands/commands.js b/src/commands/commands.js index 6d15a78..31bfe1c 100644 --- a/src/commands/commands.js +++ b/src/commands/commands.js @@ -4,5 +4,65 @@ export default { }, wine: function(ctx) { return `${ctx.streamInput + " " ?? ""}:wine_glass:`; + }, + slot: function(ctx) { + const template = ctx.argv.join(" "); + const slot = ctx.streamInput ?? ""; + return template.replace("%%", slot); + }, + times: function(ctx) { + const times = parseInt(ctx.argv[0]); + const text = ctx.streamInput; + if (!times) { + return "times: expected first argument to be the number of times to repeat text"; + } + if (!text) { + return "times: expected stream input"; + } + + let out = ""; + for (let i = 0; i < times; i++) { + out += text; + } + return out; + }, + djson: function(ctx) { + if (ctx.argc > 24) { + return "djson: arbitrary nesting limit of 24 reached" + } + + if (ctx.argc < 1) { + return "djson: expected one or more arguments"; + } + + if (!ctx.streamInput) { + return "djson: expected stream input"; + } + + let json; + try { + json = JSON.parse(ctx.streamInput); + } catch (e) { + return "djson: failed to parse json, is it malformed?"; + } + const fields = ctx.argv; + + let val = json; + for (let i = 0; i < fields.length; i++) { + const field = fields[i]; + + if (field.includes("__")) { + return "djson: security violation - field names that contain __ are disallowed"; + } + + if (typeof val !== "object") { + return "null"; + } + val = val[field]; + } + + val ??= "null"; + + return typeof val === "string" ? val : JSON.stringify(val); } } diff --git a/src/commands/interperter.js b/src/commands/interperter.js index 36dc3ca..83c0476 100644 --- a/src/commands/interperter.js +++ b/src/commands/interperter.js @@ -164,13 +164,20 @@ function interpretInstructions(instructions, displayFunc) { if (inst.inStream) { streamInput = streams.get(inst.inStream); } - let streamOutput = commandFunc({ - argv: inst.args, - argc: inst.args.length, - streamInput - }); - if (inst.outStream) { - streams.set(inst.outStream, streamOutput); + try { + let streamOutput = commandFunc({ + argv: inst.args, + argc: inst.args.length, + streamInput + }); + if (inst.outStream) { + streams.set(inst.outStream, streamOutput); + } + } catch(e) { + console.error("unhandled exception while running command", e); + if (inst.outStream) { + streams.set(inst.outStream, "error: unhandled internal exception"); + } } break; }