diff --git a/src/commands.mjs b/src/commands.mjs index 189dc44..7cacf74 100644 --- a/src/commands.mjs +++ b/src/commands.mjs @@ -36,9 +36,21 @@ async function deliver(type, data) { } export function defaultCommands() { + const expectNoArgs = (name, args) => { + if (args.length > 0) { + throw new Error(`moshscript: ${name}() does not take arguments`); + } + }; + return { - code: (ctx) => ctx.out(" ⌨ code() → compiling features (no bugs)…"), - mosh: (ctx) => ctx.out(" 🤘 mosh() → opening the pit"), + code: (ctx, args) => { + expectNoArgs("code", args); + ctx.out(" ⌨ code() → compiling features (no bugs)…"); + }, + mosh: (ctx, args) => { + expectNoArgs("mosh", args); + ctx.out(" 🤘 mosh() → opening the pit"); + }, notify: async (ctx, args) => { const msg = args.length ? args.join(" ") : "moshcode ping 🤘"; ctx.out(` 🔔 notify() → ${msg}`); @@ -46,10 +58,20 @@ export function defaultCommands() { const res = await deliver("moshscript.notify", { message: msg, iter: ctx.iter }); for (const r of res) if (!r.ok) ctx.out(` ! notify ${r.target} failed (${r.status || r.error})`); }, - repeat: (ctx) => ctx.out(" ↻ repeat() → back to the top"), + repeat: (ctx, args) => { + expectNoArgs("repeat", args); + ctx.out(" ↻ repeat() → back to the top"); + }, // handy extras say: (ctx, args) => ctx.out(` 💬 ${args.join(" ")}`), - sleep: async (_ctx, args) => { const ms = Number(args[0] || 0); if (ms > 0) await new Promise((r) => setTimeout(r, ms)); }, - stop: (ctx) => { ctx.vars.alive = false; ctx.out(" ⏹ stop() → alive = false"); }, + sleep: async (_ctx, args) => { + const ms = Number(args[0] || 0); + if (ms > 0) await new Promise((r) => setTimeout(r, ms)); + }, + stop: (ctx, args) => { + expectNoArgs("stop", args); + ctx.vars.alive = false; + ctx.out(" ⏹ stop() → alive = false"); + }, }; } diff --git a/test/commands.test.mjs b/test/commands.test.mjs new file mode 100644 index 0000000..0ad9f08 --- /dev/null +++ b/test/commands.test.mjs @@ -0,0 +1,36 @@ +import assert from "node:assert/strict"; +import test from "node:test"; + +import { defaultCommands } from "../src/commands.mjs"; + +function createCtx() { + return { + dryRun: true, + iter: 0, + vars: { alive: true }, + lines: [], + out(line) { + this.lines.push(line); + }, + }; +} + +for (const name of ["code", "mosh", "repeat", "stop"]) { + test(`${name}() rejects unexpected arguments`, async () => { + const commands = defaultCommands(); + await assert.rejects( + async () => commands[name](createCtx(), ["extra"]), + new RegExp(`moshscript: ${name}\\(\\) does not take arguments`) + ); + }); +} + +test("notify() still accepts message arguments", async () => { + const commands = defaultCommands(); + const ctx = createCtx(); + + await commands.notify(ctx, ["hello", "there"]); + + assert.equal(ctx.lines.length, 1); + assert.match(ctx.lines[0], /hello there/); +});