0

i am trying to make a CLIish server in node.js. but I need a way to parse a string and run a function from an object. what I mean is... I don't want to nest a million switch statements just to have the commands I need. using 2 other StackOverflow answers, I got 1 part done. inputs.

now i just need to figure out how to figure ou where the command stops and the input begins. example:

inputting do say user:Yimmee msg:"well hello" "something random":yes I need to separate do say and the inputs. this is what i started with, but I do not know how to finish it.

function command(command, usable){
  //usable is the object holding the commands that can be used.
  //here I set commandMain to the part of command that is the command
  /*and where commandInput is too. and I'm not forcing you,
  but is preferably to be converted to an object.*/
  var commandSplit = [];
  do{
    var match = (/[^ "]+|"([^"]*)"/gim).exec(commandMain);
    if(match != null){
      commandSplit.push(match[1] ? match[1] : match[0]);
    }
  }while (match != null);
  var reach = `usable`;
  commandSplit.forEach((to, nu)=>{
    if(nu === commandSplit.length - 1){
      reach += `["_${to}"]`;
    }else{
      reach += `["${to}"]`;
    }
  });
  console.log(reach);
  try{
    return eval(reach)(commandInputs);
  }catch(error){
    return false;
  }
}

Note I gave up a little, there will be some ridiculous errors.

big fat edit::::::::::::::::::::::L::::::: idk how in the world process.argv works, and looking in one of the answers, i know how to set it. but i am using a live websocket for this.

2 Answers2

0

Unless this is an exercise, I'd strongly recommend not to implement your own command and argument parser. Use one of the existing libraries. A quick web search for "node cli library" yields a lot of results, including comparisons.

The libraries range from tiny and simple like minimist, very popular ones like yargs or commander, to heavier ones like oclif.

I'd also recommend checking the Command-line utilities section of Sindre Sorhus' Awesome Node.js list.

rsmeral
  • 518
  • 3
  • 8
0

What you are doing is passing options and arguments to a program. You can use process.argv to get these.

It's always good to have useful error messages and command line documentation. Hence, if you're distributing to users, a more robust library for this purpose is worth an extra dependency. Widely used is yargs, see their website at https://www.npmjs.com/package/yargs for some examples.

If you want to do it using the basic process.argv, here's a solution:

This is your command in a format most people are used to: node some.js --user Yimmee --msg "well hello" --random

And the implementation

let arguments = process.argv.slice(2); // this removes `node` and the filename from arguments list
console.log(arguments)
switch (arguments[0]) { // check that `say` is the first "command"
    case 'say':
        let options = process.argv.slice(3); // get the stuff after `say`
        let optionsObject = {} // key-value representation
        if (options.indexOf("--user") != -1) { // if it exists
            optionsObject.user = options[options.indexOf("--user")+1]
        }
        else {
            // you can throw an error here
        }
        if (options.indexOf("--msg") != -1) { // if it exists
            optionsObject.msg = options[options.indexOf("--msg")+1]
        }
        if (options.indexOf("--random") != -1) { // if it exists
            optionsObject.random = true
        }
        console.log(optionsObject) // you can use optionsObject for your program
        break;
    default:
        console.log("Invalid command");
}

EDIT: If this is happening inside the code as a function call, you can adapt above code:

function test(argsString) {
    let arguments = argsString.split(/ (?=(?:(?:[^"]*"){2})*[^"]*$)/); // split the string into an array at the spaces
    // ^ regex from https://stackoverflow.com/questions/23582276/
    console.log(arguments)
    switch (arguments[0]) { // check that `say` is the first "command"
        case 'say':
            let options = arguments.slice(1); // get the stuff after `say`
            let optionsObject = {} // key-value representation
            if (options.indexOf("--user") != -1) { // if it exists
                optionsObject.user = options[options.indexOf("--user") + 1]
            }
            else {
                // you can throw an error here
            }
            if (options.indexOf("--msg") != -1) { // if it exists
                optionsObject.msg = options[options.indexOf("--msg") + 1]
            }
            if (options.indexOf("--random") != -1) { // if it exists
                optionsObject.random = true
            }
            console.log(optionsObject) // you can use optionsObject for your program
            break;
        default:
            console.log("Invalid command");
    }
}
atultw
  • 921
  • 7
  • 15
  • For more info about the standard options format, see here: https://softwareengineering.stackexchange.com/questions/70357/command-line-options-style-posix-or-what – atultw May 29 '21 at 23:06
  • @Yimmee I updated the answer with a function version – atultw May 29 '21 at 23:21