Lukas
Lukas

Reputation: 10340

Provide part of a pathname (as an argument) to a npm script

Is it possible to read CLI arguments in a scripts entry of a package.json. I am looking for something like this:

{
  "scripts": {
    "example": "ts-node --project tsconfig.json ./examples/${1}/.ts"
  }
}

where ${1} would be replaced by the first argument passed to

npm run example yadda

and eventually run

ts-node --project tsconfig.json ./examples/yadda/.ts

I know I can write a JS file that can be called and run by npm that will read the CLI args, but I am wondering if I can read the args right from the npm script entry.

Upvotes: 0

Views: 420

Answers (3)

RobC
RobC

Reputation: 24962

Unfortunately npm does not, nor intends to, provide a builtin feature which allows arguments to be passed to the middle of a npm script (as stated here). Arguments can only be passed to the end of a script.

Given that in your example you're wanting to pass an argument to the middle of a script, (to essentially create a new pathname), you'll need to utilize a workaround.

On *nix platforms (Linux, macOS, ...) the default shell utilized by npm is sh. Therefore you can utilize a shell function in npm-scripts as a mechanism for handling arguments which are intended to be passed to the middle of a script.

package.json

...
"scripts": {
  "example": "func() { ts-node --project tsconfig.json \"./examples/${1}.ts\"; }; func"
},
...

Explanation:

  • At the end of the script, i.e. the trailing func part, invokes the arbitrarily named shell function; func, which is defined at the beginning of the script. Essentially the argument (e.g. yadda) which is provided via the CLI is passed to it.
  • In the body of the func function we execute the ts-node command. The argument (e.g. yadda) is referenced in the body of the function using $1 (i.e. the first positional parameter/argument).

Running:

Running the following command via your command line;

npm run example yadda

will eventually run as:

ts-node --project tsconfig.json ./examples/yadda.ts

Notes:

  1. Windows, which utilizes cmd.exe as the default shell, will choke at the aforementioned solution.

  2. You may want to consider also utilizing Shell Parameter Expansion to provide a default value when no argument is provided via the CLI. For instance:

    package.json

    ...
    "scripts": {
      "example": "func() { ts-node --project tsconfig.json \"./examples/${1:-foobar}.ts\"; }; func"
                                                                           ^^^^^^^^
    },
    ...
    

    Note the ${1:-foobar} part instead of just ${1}. This means that running the script without providing an argument. For instance:

    npm run example
    

    will eventually run as:

    ts-node --project tsconfig.json ./examples/foobar.ts
                                               ^^^^^^
    

    However, when an argument is provided, such as:

    npm run example yadda
    

    it will still run as before, i.e.

    ts-node --project tsconfig.json ./examples/yadda.ts
    

Cross-platform:

If a cross platform solution, i.e. one that runs with both sh and cmd.exe, is required then you're left with really only one option, which is as you say: "write a JS file that can be called and run by npm that will read the CLI args [ ...using process.argv and shell-out the ts-node command using execSync() or exec() ]

Upvotes: 0

Webber
Webber

Reputation: 5484

You can set your example command to run a script

{
  "scripts": {
    "example": "node --project tsconfig.json ./yourscript.js"
  }
}

Then in your script use the arguments

var args = process.argv.splice(process.execArgv.length + 2);


args.forEach((value, index) => {
  console.log(`Argument ${index} is: ${value}`);
});

You could then call your script running npm run example arg1 arg2 and use one of the arguments to import/require another file or run the specific code conditionally.

Upvotes: 0

Emanuele Scarabattoli
Emanuele Scarabattoli

Reputation: 4469

You can use the following syntax (not specific to npm itself)

$MY_VAR=foo npm run example

and in your scripts section do that

"example": "ts-node --project tsconfig.json ./examples/$MY_VAR/.ts"

Upvotes: 1

Related Questions