lukeed / sade

Smooth (CLI) Operator 🎢

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Parsed args (argv/opts) always to be the 1st param of action

tunnckoCore opened this issue Β· comments

Heya. Currently you always get the argv (what's called "opts" everywhere in readme - i don't like that) from mri as last parameter of the action function. It's pretty much not comfortable in anyway.

It not make sense to be last. It is the only guaranteed param that can exist, so the best position of is to be always first. Working with variable position arguments is not feeling good any way.

Adding option for that would work too.

The changes

args.push(vals); // flags & co are last
let handler = cmd.handler;
return opts.lazy ? { args, name, handler } : handler.apply(null, args);

to this

args.unshift(vals); // flags & co (the parsed argv) are always first
let handler = cmd.handler;
return opts.lazy ? { args, argv: vals, name, handler } : handler.apply(null, args);

Wanna PR? I can add it behind option so we'll don't care about problems.

Nope, sorry. This is exactly as intended.

Okey, consider adding an option? It's really no way to workaround it and I don't see a problem for adding one if check. It's one line change.

if (opts.argvFirst) {
  args.unshift(vals);
} else {
  args.push(vals);
}

Oops, sorry @olstenlarck. That could be interpreted in a tone I did not intend. (I'm a bit stressed out right now 😞)

The positionally-based arguments within action is a pattern I loved & wanted since the beginning. The reason is that required arguments are/should be guaranteed to have values. Therefore, they are passed in the order of their command's definition. Options are a different vocabulary entirely. They are (by definition) optional, and therefore are cared for (and accessed) last.

An easy work-around for your case, since you don't like positional parameters, is define usages with {foo} {bar} and then shift() off values from opts._. It's hacky, but you're intentionally diverting from Sade's design/API anyway.

Another option is to pass all your action handlers through a function that constructs the argument in a way that you like.

function wrap(keys, fn) {
  return function () {
    let vals = [].slice.call(arguments);
    let opts = vals.pop(); // last
    while (keys.length) {
      opts[ keys.shift() ] = vals.shift();
    }
    return fn(opts);
}

let bar = wrap(['src', 'dest'], FUNCTION);
let ctx = sade('foo').command('bar <src> [dest]').action(bar);

Re argvFirst suggestion :: Sorry, I don't even want to allow that to happen. Again, this is by design. The above snippet is probably your best bet.

No problemo πŸ˜†

The point is that it's meant to be exposed to third parties, so i can't know the names of the keys, so such workaround still won't work for me.

Also, they still will be positional arguments and won't loose anything, will just make it easier for both sides. Also, worth nothing for 1-2 lines - the default behavior still will be your opinionated behavior.

Options are a different vocabulary entirely. They are (by definition) optional, and therefore are cared for (and accessed) last.

First, i more like to call them flags, cuz we are in CLI land. And yes, they are optional, but that param always exist as object (the result of mri), so implementer is guaranteed and can be sure that it is an object and can depend on that param and make logic in the action based on them. It is the only guaranteed param in any time. It's not guaranteed that there can be optional or required arguments/sub-commands, but it's guaranteed that there will always be flags object no matter that there may not be passed flags.

If you don't know the required/optional keys ahead of time, then they don't/can't make it into your usage definition. In which case, define nothing & you'll always & only get the argv object first.

I, as exposer of the API to third parties, don't care and can't know what is the command, what keys (required/optional arguments) command have and when implementer want to depend more on flags than on keys/required/optional arguments/sub-commands. :D

Ha! With fresh mind and cup of coffee.. Rethinking it, makes the things easier and no need for any changes. Even the #13 is not needed so much, but still can be good addition for someone else. β˜• πŸ‘Œ

Great! Yeah, I didn't think there was really much of an issue πŸ˜… Seemed like a super weird edge case... or just strong preference.

Going to go ahead & close the other issue too -- I forgot about it. There's no need to expose it because Sade if self-contained. Exposing it is just asking for trouble and weird edge cases. It works and does what it's meant to do πŸ˜‡