From 44fd3452be9cceae7a39b6efd46c8580c31ae69e Mon Sep 17 00:00:00 2001 From: "yuxuan.weng" Date: Mon, 26 Oct 2026 09:37:30 +0800 Subject: [PATCH] fix: isolate options between parse calls ref:0 --- deno/mod.js | 4 ++-- src/index.js | 8 ++++++-- test/index.js | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 4 deletions(-) diff --git a/deno/mod.js b/deno/mod.js index 1a20977..c8c0620 100644 --- a/deno/mod.js +++ b/deno/mod.js @@ -177,8 +177,8 @@ class Sade { const all = this.tree[ALL]; // merge all objects :: params > command > all - opts.alias = Object.assign(all.alias, cmd.alias, opts.alias); - opts.default = Object.assign(all.default, cmd.default, opts.default); + opts.alias = Object.assign({}, all.alias, cmd.alias, opts.alias); + opts.default = Object.assign({}, all.default, cmd.default, opts.default); tmp = name.split(" "); idx = arr.indexOf(tmp[0], 2); diff --git a/src/index.js b/src/index.js index b11735a..f445f98 100644 --- a/src/index.js +++ b/src/index.js @@ -157,8 +157,12 @@ class Sade { let all = this.tree[ALL]; // merge all objects :: params > command > all - opts.alias = Object.assign(all.alias, cmd.alias, opts.alias); - opts.default = Object.assign(all.default, cmd.default, opts.default); + opts.alias = Object.assign({}, all.alias, cmd.alias, opts.alias); + opts.default = Object.assign({}, all.default, cmd.default, opts.default); + // mri consumes alias arrays while populating the result. + for (let key in opts.alias) { + if (Array.isArray(opts.alias[key])) opts.alias[key] = opts.alias[key].slice(); + } tmp = name.split(' '); idx = arr.indexOf(tmp[0], 2); diff --git a/test/index.js b/test/index.js index 30349e7..a586b05 100644 --- a/test/index.js +++ b/test/index.js @@ -341,3 +341,36 @@ test('prog.parse :: lazy :: single', t => { bar.handler.apply(null, bar.args); // manual bcuz lazy; +2 tests }); + + +test('prog.parse :: command options stay local', t => { + let ctx = sade('foo') + .option('--mode', 'Global mode', 'global') + .command('build').option('-o, --output', 'Output', 'dist').action(() => {}) + .command('serve').action(() => {}); + + let build = ctx.parse(['', '', 'build'], { lazy:true }); + t.is(build.args[0].output, 'dist', 'uses the command default'); + t.is(build.args[0].o, 'dist', 'uses the command alias'); + + let serve = ctx.parse(['', '', 'serve', '-o', 'public'], { lazy:true }); + t.same(serve.args, [{ _:[], o:'public', mode:'global' }], 'does not inherit another command alias or default'); + + ctx.parse(['', '', 'serve'], { lazy:true, default:{ mode:'temporary' }, alias:{ m:'mode' } }); + serve = ctx.parse(['', '', 'serve', '-m', 'local'], { lazy:true }); + t.same(serve.args, [{ _:[], m:'local', mode:'global' }], 'does not retain per-call defaults or aliases'); + t.end(); +}); + + +test('prog.parse :: reusable short aliases', t => { + let ctx = sade('foo') + .option('-g, --global') + .command('build').option('-o, --output').action(() => {}); + for (let value of ['first', 'second']) { + let result = ctx.parse(['', '', 'build', '-g', value, '-o', value], { lazy:true }); + t.is(result.args[0].global, value, 'retains global alias'); + t.is(result.args[0].output, value, 'retains command alias'); + } + t.end(); +});