I'm using commander.js command like this ./index.js --project mono --type item --title newInvoice --comments 'Creates an invoice' --write, Now I'm using the command through npm run item newInvoice by setting some options in package.json file like this
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"snapshot": "node --max-old-space-size=10240 ./scripts/snapshot.js",
"item": "./index.js --project mono --type item --title",
"config": "./index.js --project mono --type config --title"
}
But whenever I'm trying to get the --write option with npm using npm run item newInvoice --write it's showing undefined for --write
Source Code:
#!/usr/bin/env node
const fs = require('fs');
const program = require('commander');
require('colors');
program
.version('0.1.0')
.option('--project [project]', 'Specifies the project name', 'mono')
.option('--type [type]', 'Type of code to generate, either "item" or "config"', /^(config|item)$/, 'config')
.option('--title [title]', 'Title of the item or config', 'untitled')
.option('--comments [comments]', 'Configs: describe the config', '#todo description/comments')
.option('--write', 'Write the source code to a new file in the expected path')
.option('--read', 'To see what would be written the source code to a new file in the expected path')
.parse(process.argv);
console.log(program.write, program.read); //=> undefined undefined
Can anyone help me how to use commander js command with npm?
When you run your npm run command you need to utilize the special -- option to demarcate the end of any option(s) that may belong to the npm run command itself (e.g. --silent), and the beginning of the argument(s) that are to be passed to the end of the npm script.
Run the following command instead:
npm run item -- newInvoice --write
Given the aforementioned command and the command currently defined your npm script named item they essentially form the following compound command prior to execution:
./index.js --project mono --type item --title newInvoice --write
^ ^
The npm run documentation states the following:
As of npm#2.0.0, you can use custom arguments when executing scripts. The special option -- is used by getopt to delimit the end of the options. npm will pass all the arguments after the -- directly to your script.
and it's usage syntax is defined in the Synopsis section as:
npm run-script <command> [--silent] [-- <args>...]
^^
Note: It's not possible to add the -- option to the npm script itself.
Related
I tried various solutions for this question but not able to pass 2 test cases amongst 4. Please help me crackdown this problem
Perform the below mentioned steps by creating package.json file named npm_commands in the maxbot directory
Create a file named index.js.
Write a js code in index.js file to create a string named myVar and value as node package manager
and convert it into uppercase.
NOTE: Please use console.log to display the output of myVar in index.js file
Configure scripts in package.json
(a) to check the versions of npm and node by using npm run release | tee output1.txt
(b) to execute index.js by using npm run build | tee output.txt
npm init - to initialize new package
give npm_commands as package name
give index.js as start file
Create new file named as index.js
declare : let myVar = "node package manager"
print var in uppercase: console.log(myVar.toUpperCase());
Add these scripts in package.json
to check npm and node version: "release": "npm -v && node -v",
to execute index.js file: "build": "node index.js"
Save and then run these commands to get the results:
npm run release | tee output1.txt
npm run build | tee output.txt
Step 1: run the command to initialize new package
npm init
Step 2: Command will start package initialization process
Set the package name:
package name: (challange) npm_commands
Step3: Press enter till time it ask for "entry point", by default it set to index.js verify and press enter key. Until the initialization process ends.
Step 4: Go to editor project explorer add create new file index.js, and add following code in it.
let myVar = 'node package manager';
console.log(myVar.toUpperCase());
Step 5: Add following lines into script block of package.json file
"release" : "npm -v && node -v",
"build" : "node index.js",
Script block looks like as below after adding above lines
"scripts": {
"release" : "npm -v && node -v",
"build" : "node index.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
Step 6: Now open the command prompt and run the following commands
npm run release | tee output1.txt
npm run build | tee output.txt
Above commands create the output1.txt, and output.txt files in project explorer containing respective commands output.
Step 7: That's it! now run the test and check your FS_SCORE for 100% and submit the test.
In an NPM project, I'd like to have a commit for each build version. This will allow me to go back to the current build version, fix a bug, without having to go through all the QA of a new version.
We can commit using npm scripts like this (see this answer):
package.json
"scripts": {
"git": "git add . && git commit -m",
}
Then invoke the script by running:
npm run git -- "Message of the commit"
I'd like to automate it to run after npm run build. For this purpose we can create a new command.
package.json
"scripts": {
"buildAndCommit": "npm run build && git add . && git commit -m",
}
This could be run using npm run buildAndCommit -- "commit for a new build"
The only thing left is that I'd like to identify this commit as one that could be linked to a commit. Is it possible to start the message automatically with "BUILD -" and to add to that the unique message which is passed in the command line? Something like:
package.json
"scripts": {
"buildAndCommit": "npm run build && git add . && git commit -'Build' + $uniqueMessageFromTheCommandLine`",
}
If it is not possible to template the string in package.json, how could I achieve it using a command line script? (Powershell is my command line tool).
Running on *nix platforms
On a *nix platform npm utilizes sh by default to execute the npm script(s). In this scenario you can simply use a shell function and reference the git message argument passed via the CLI using the $1 positional parameter.
Your npm script would be redefined like this:
"scripts": {
"build": "...",
"buildAndCommit": "func() { npm run build && git add . && git commit -m \"BUILD - $1\"; }; func"
}
Cross platform
Unfortunately, via Windows Powershell the solution is not quite as simple and terse.
When using Powershell npm utilizes cmd by default to execute npm script(s). Likewise npm utilizes cmd by default via other Windows consoles too, such as Command Prompt.
One way to achieve your requirement is to invoke a node.js via your npm script. The following provides two different methods that are essentially the same. Either will run successfully cross-platform (in your case via Powershell).
Method A - Using a separate node.js script
Create the following node.js script. Let's name the file script.js and save it in the root of the project directory, i.e. in the same directory where package.json resides.
script.js
const execSync = require('child_process').execSync;
const mssg = 'BUILD - ' + process.argv[2];
execSync('npm run build && git add . && git commit -m \"' + mssg + '\"', { stdio:[0, 1, 2] });
Explanation
The node.js builtin process.argv captures the argument at index two, i.e. the git commit message, that was provided via the CLI. The git commit message is concatenated with with the substring BUILD - to form the desired commit message. The resultant string is assigned to the variable mssg.
We then utilize the node.js builtin execSync() to execute your given npm script. As you can see, the value of the mssg variable is used as the git commit message.
The stdio option is utilized to ensure the correct configuration of the pipes, i.e. stdin, stdout, 'stderr', are established between the parent and child process.
Define your npm script named buildAndCommit as follows:
package.json
"scripts": {
"build": "...",
"buildAndCommit": "node script"
}
Above node invokes script.js.
Method B - Inline the node.js script in npm script
Alternatively, the aforementioned node.js script (i.e. script.js) can be provided inline in your npm script instead - therefore negating the use of a separate .js file.
package.json
"scripts": {
"build": "...",
"buildAndCommit": "node -e \"const mssg = 'BUILD - ' + process.argv[1]; require('child_process').execSync('npm run build && git add . && git commit -m \\\"' + mssg + '\\\"', { stdio:[0, 1, 2] })\""
}
This utilizes the same code from Method A albeit it slightly refactored. The notable differences are:
The nodejs command line option -e is utilized to evaluate the inline JavaScript.
process.argv this time will capture the argument, i.e. the git commit message, at index one in the array of arguments.
Additional escaping of the double quotes is necessary, i.e. \\\"
Running the npm script
Using either Method A or Method B run the command via your CLI as desired: For instance:
$ npm run buildAndCommit -- "commit for a new build"
This will produce the following git commit message:
BUILD - commit for a new build
I have some npm scripts that look like this:
"scripts": {
"exec:dev": "export NODE_ENV=development && npm run exec",
"exec:stage": "export NODE_ENV=stage && npm run exec",
"exec:prod": "export NODE_ENV=production && npm run exec",
"exec": "node myapp.js"
}
I'd like to pass some command line arguments to myapp.js but this does not work:
npm run exec:prod -- -a 123 -b 456
This is apparently due to the fact that the exec:prod script is calling the exec script and apparently not passing along the command line parameters. Is there any way to achieve this while keeping the nested script calls?
To explicitly tell the exec script to pass along the arguments it gets, include another --.
Instead of:
npm run exec:prod -- -a 123 -b 456
try:
npm run exec:prod -- -- -a 123 -b 456
The first double dash tells the exec:dev script, "these args
aren't for you, pass them along to the exec script".
The second double dash tells the exec script, "these args aren't
for you, pass them along to node myapp.js".
If you want to keep the npm run command that you enter via the CLI the same as per your question. (i.e. avoid adding yet another npm special option (--) to it, as per #MikePatrick 's answer).
Change your npm-scripts to the following instead:
"scripts": {
"exec:dev": "export NODE_ENV=development && npm run exec --",
"exec:stage": "export NODE_ENV=stage && npm run exec --",
"exec:prod": "export NODE_ENV=production && npm run exec --",
"exec": "node myapp.js"
}
Note: the npm special option (--) added to the end of the first three scripts.
Demo
For demonstration purposes, lets say myapp.js is as follows:
myapp.js
const args = (process.argv.slice(2));
const nodeEnv = process.env.NODE_ENV;
console.log(nodeEnv);
console.log(args);
Testing:
Running npm run exec:dev -- -a 123 -b 456 prints:
development
[ '-a', '123', '-b', '456' ]
Running npm run exec:stage -- -a 123 -b 456 prints:
stage
[ '-a', '123', '-b', '456' ]
Running npm run exec:prod -- -a 123 -b 456 prints:
production
[ '-a', '123', '-b', '456' ]
Further info
The docs for npm-run-script describe the npm special option (--) as follows:
... The special option -- is used by getopt to delimit the end of the options. npm will pass all the arguments after the -- directly to your script ... The arguments will only be passed to the script specified after npm run and not to any pre or post script.
I'm using npm to run a build and I'm trying to override my .npmrc config options using cmd line flags. However npm insists on passing these flags directly to my script rather than reading them as config options as described in the docs. What am I doing wrong?
From the cmd line I try to build a Tizen pacakge like so:
npm run package --tizen_profile myprofile
inside my package.json I have:
"package": "tizen package -t wgt --sign $npm_package_config_tizen_profile -- .buildResult/wgt -o .buildResult/wgt"
The result from running the command is:
package: `tizen package -t wgt --sign $npm_package_config_tizen_profile -- .buildResult/wgt -o .buildResult/wgt "myprofile"`
Where it should be:
package: `tizen package -t wgt --sign "myprofile"_tizen_profile -- .buildResult/wgt -o .buildResult/wgt`
It's like npm is merely appending the cmd line argument to the script command instead of plugging it in like a variable as described in the docs: https://docs.npmjs.com/misc/config
Has there been a recent update to npm which deprecates and removes this ability? I just updated to npm 6.x but it was working this way on 5.x as well.
you can try to rewrite your script within package.json without --sign flag like:
"package": "tizen package -t wgt -- .buildResult/wgt -o .buildResult/wgt"
and then pass it when you run npm command:
npm run package -- --sign myprofile
I assume that you can change the order of arguments, because --sign myprofile now will be at the very end of your command
UPDATE
here is another way to pass variables and place them in any place in your CLI command (without using npm config set). In my package.json:
"aaa": "ls $myoptionalflag && $mycmd"
this way I can pass any flag to la command (or not to pass at all) and I can pass any CLI command as mycmd variable. So, now I can run:
myoptionalflag=-la mycmd=pwd npm run aaa
which will execute
ls -la && pwd
or
mycmd=pwd npm run aaa
which will execute
ls && pwd
I FIGURED IT OUT!
The documentation is flawed as it doesn't tell you the correct syntax for passing npm config properties. I had to use:
npm run package --mypackagename:tizen_profile="myprofile"
where mypackagename is the name property used in package.json. Also note the key value syntax is --key=value and not --key value as described in the docs. Again, --key would be packagename:key using the name specified at the top level of your package.json.
I want to to define a scripts entry in my package.json to simplify building for several environments.
In the script execution I need to replace $1 (or whatever syntax I need for a placeholder) by a parameter I would pass to npm run build-script like for example --env=prod or even simpler, --prod. How can I do that? Other questions and answers I found here didn't help me solve the problem.
"scripts": {
"build-for": "ng build --output-path=../../web/admin-v2 --env=$1 --base-href=\"/admin-v2/\""
}
I often resort to creating a utility node script for this kind of scenario and invoke it via the scripts section of package.json.
build-for.js
var nodeCLI = require('shelljs-nodecli');
var env = '--env=foo'; // <-- Default env flag/value when no arg provided.
if (process.argv.indexOf('--prod') !== -1) {
env = '--env=prod';
}
// Check for other possible env values
if (process.argv.indexOf('--quux') !== -1) {
env = '--env=quux';
}
// Run the ng build command
nodeCLI.exec('ng', 'build', '--output-path=../../web/admin-v2', env, '--base-href=\"/admin-v2/\"');
build-for.js utilizes nodes process.argv to ascertain the argument/flag passed via the CLI and then invokes the ng command (the one currently defined in your package.json) using shelljs-nodecli.
npm i -D shelljs-nodecli
Lets assume that build-for.js is saved to a hidden folder named .scripts in your projects root directory; then your scripts section of package.json will be defined as follows:
package.json
{
...
"scripts": {
"build-for": "node ./.scripts/build-for"
},
...
}
Running the script
Invoke the npm script by running:
npm run build-for -- --prod
Note the special -- before the argument --prod must be included as explained here
As of npm#2.0.0, you can use custom arguments when executing scripts. The special option -- is used by getopt to delimit the end of the options. npm will pass all the arguments after the -- directly to your script:
Given the logic curently in the build-for.js - when no arguments are passed, for example:
npm run build-for
...the env flag will be set to --env=foo
Running the following:
npm run build-for -- --quux
...will result in the env flag will be set to --env=quux
Caveat
I haven't fully tested build-for.js, so you may find that you don't need to escape the double-quotes in this part '--base-href=\"/admin-v2/\"' of the following command (nodeCLI may handle that for you.):
// Run the ng build command
nodeCLI.exec('ng', 'build', '--output-path=../../web/admin-v2', env, '--base-href=\"/admin-v2/\"');
Not exactly what you're looking for but you can use environment variables & provide them inline:
package.json script:
"<script>": "echo ${ENV1} ${ENV2}"
run like so:
ENV1=a ENV2=b npm run <script>
$ npm run <script>
a b