Single npm package with two commands - node.js

I have a node.js package described by this JSON :
"name": "mycommand",
"main": "index.js",
"bin": {
"mycommand": "./index.js",
The index.js file contains this code :
#!/usr/bin/env node
const app = require('./src/app.js')
const { Logger } = require('./utils/Logger')
app.init()
And the app.js contains the code of a command line tool based on yargs.
Now, I would like to add a 2nd command in this package, but I don't know how should I proceed since there can be only one "main".
Anybody has an example somewhere ?

Maybe you are looking for scripts instead of bin?
Now, I would like to add a 2nd command in this package, but I don't know how should I proceed since there can be only one "main".
The bin mapping has nothing to do with your main file.
Your command is getting symlinked, you can simply add more:
"bin": {
"mycommand": "./index.js",
"my-other-command": "./other-command.js",
Or you can use your mycommand and parse the arguments in the script app.js using process.argv:
https://nodejs.org/en/knowledge/command-line/how-to-parse-command-line-arguments/

Related

pass command line argument in vscode test runner script (index.ts)

Scenario:
script in package.json file looks like:
"test": "node ./out/test/runTest.js"
this runTest.js then calls test runner script src/test/suite/index.ts . Source of this file is : https://code.visualstudio.com/api/working-with-extensions/testing-extension
In the index.ts, it uses source like:
return new Promise((c, e) => {
glob('**/**.test.js', { cwd: testsRoot }, (err, files) => {
Here, glob is pointing to the src files to consider for test run.
Question:
For specific reason, I don't want to test all files using regex like: glob('**/**.test.js'
I want to test specific file and I want to pass it by my test script in package.json file.
For ex: I want
"test": "node ./out/test/runTest.js Filename"
And glob() in index.ts file will consider only this Filename for execution.
I need some help in this regards.
Thanks again
The way to pass arguments from npm scripts inside package.json is via environment variables. The syntax is slightly different depending on the platform. The example below is for Windows.
"test": "set FileName=foo.js&node ./out/test/runTest.js"
The argument and the value is now awailable inside runTest.js in process.env
console.log(process.env.FileName); //foo.js
In the src/test/suite/index.ts open your package.json file and search for the "test" script line and parse it for the arguments.
Edit
I needed something similar and added a file: test-arguments.txt next to index.js or maybe in .vscode folder if you use typescript.
Inside index.js I open the file and parse the arguments. I allow lines to be commented with #.
By adding this test-arguments.txt file to .gitignore I don't have to modify package.json and my team members can have different arguments.

How to prepend text to a file as an npm script command

I'm writing a bookmarklet. I need to prepend "javascript:" to the compiled, minified JavaScript. I'm looking for a way to accomplish this using an NPM package.json script.
{
"scripts": {
"oar:transpile-typescript": "tsc --target es6 --lib dom,es6 ./OarBookmarklet/Oar.ts",
"oar:minify-javascript": "jsmin -o ./OarBookmarklet/oar.min.js ./OarBookmarklet/oar.js",
"oar:prepend-javascript": "[??? prepend `javascript:` to minified JavaScript ???]",
"oar": "run-s oar:transpile-typescript oar:minify-javascript oar:prepend-javascript",
"build": "run-s oar"
}
}
For a cross-platform solution utilize node.js and it's builtin fs.readFileSync(...) and fs.writeFileSync(...). This way it doesn't matter which shell your npm script runs in (sh, cmd.exe, bash, bash.exe, pwsh, ... )
To achieve this consider either of the following two solutions - they're essentially the same just different methods of application.
Solution A. Using a separate node.js script
Create the following script, lets save it as prepend.js in the root of the project directory, i.e. at the same level as where package.json resides.
prepend.js
const fs = require('fs');
const filepath = './OarBookmarklet/oar.min.js';
const data = fs.readFileSync(filepath);
fs.writeFileSync(filepath, 'javascript:' + data);
package.json
Define the oar:prepend-javascript npm script in package.json as follows::
"scripts": {
...
"oar:prepend-javascript": "node prepend",
...
},
Note: Above node.js invokes the script and performs the required task. If you choose to save prepend.js in a different directory than the aforementioned then ensure you define the correct path to it, i.e. "oar:prepend-javascript": "node ./some/other/path/to/prepend.js"
Solution B. Inline the node.js script in package.json
Alternatively, you can inline the content of prepend.js in your npm script, therefore negating the use of a separate .js file.
package.json
Define the oar:prepend-javascript script in package.json as follows:
"scripts": {
...
"oar:prepend-javascript": "node -e \"const fs = require('fs'); const fp = './OarBookmarklet/oar.min.js'; const d = fs.readFileSync(fp); fs.writeFileSync(fp, 'javascript:' + d);\""
...
},
Note: Here the nodejs command line option -e is utilized to evaluate the inline JavaScript.
If this is running on something Unix-like then:
(printf 'javascript:' ; cat ./OarBookmarklet/oar.min.js) > ./OarBookmarklet/oar.bm.min.js
should do the job.
Edit in response to OP's comment:
My execution environment is Windows, ...
In that case you should be able to use:
(set /p junk="javascript:" <nul & type ./OarBookmarklet/oar.min.js) > ./OarBookmarklet/oar.bm.min.js
The set /p ... <nul weirdness is a way to get some text sent to stdout without a newline being appended to it.

NPM CLI application relative path doesn't work

I'm creating a CLI application in NodeJS and the package is going to be published on NPM. The application is very simple as it has only two files. Here is the structure of application:
package.json
{
"name": "mycliapp",
"version": "1.0.0",
"description": "Some description",
"main": "./bin/cli.js",
"preferGlobal": true,
"bin": {
"mycliapp": "bin/cli.js"
},
}
bin/cli.js
const nodePlop = require('node-plop');
const configPath = './bin/config.js';
const plop = nodePlop(configPath, {
force: argv.force || argv.f
});
bin/config.js
{
// some configuration
}
Now if I create symlink with npm install -g from this directory and run the command mycliapp from the same development directory, it works absolutely fine but if I run this mycliapp command from any other directory in my computer, the const configPath = './bin/config.js' is tried to be taken from the current working directory not from the actual npm package and hence the config file is not found.
How can I solve this issue? I tried using __dirname and __filename with path.join but nothing seems to be working.
I also published this package on npm and installed from there, the same issue is occurring.
The JSON in your package.json is malformed -- you should remove the trailing comma after you set the bin parameter.
Also, if your configuration file is in the same directory as your script, you should reference it within your script as ./config.js.
Finally, you need to include a shebang (#!/usr/bin/env node) at the top of your cli.js file or any file you intend to use as your point of entry into the app so that your system knows what interpreter to use to execute the file.
See this post on the npm blog for more information.

node.js Command Line Interface app on windows

I am creating a simple CLI (Command line interface) application using NodeJs, involving two files:
package.json:
index.js
I want to print "hello world" to STDOUT and it is working when running command $ node index.js
But I want to use it globally via command test. So, I put a bin entry in package.json. Then build the application using npm link .. But then when I run "test" command, Windows shows me the following error:
How can I use console.log in separate app?
Thank you!
In package.json file, you need to write the code as follows:
"name" : "test",
"version": "1.0.0",
"scripts": {
"start": "node index.js",
"build": "webpack",
},
...
...
after this, use the command npm start to run the application.
1- Create bin folder in root folder and place your index.js inside the bin.
type the shebang code on the first line of index.js:
bin/index.js
#!/usr/bin/env node
console.log("hello world");
2- Add below code into the package.json file.
"bin": {
"test": "./bin/index.js" //this is relative path
}
3-finally run this code on command line
npm link
now you run "test" in your command line, it will log "hello world"
note:pay attention to the relative path that i mentioned above.

Is it possible to run an npm script in the current context using the source operator?

I'm trying to write a simple Node.js CLI to more easily navigate directories. For the sake of simplicity, let's say this is the CLI I'm trying to make:
test.js
#!/usr/bin/env node
console.log('hey there');
var exec = require('child_process').exec;
exec('cd ~/code/');
package.json
{
"name": "example",
"version": "0.1.0",
"description": "Example CLI that needs to run in current context",
"bin": {
"myScript": "test.js"
},
"engines": {
"node": "0.10.*",
"npm": "1.2.*"
}
}
With both of those in the same folder, running npm link will create the CLI. After that, if I run myScript, it outputs "hey there" but doesn't change directories. I know that this is because myScript is run in it's own subshell, which is subsequently terminated. I've read here about the source operator and found that it's used like such:
. filename [arguments]
I've tried doing . myScript to force my code to run in the current context. However, by using the source operator, the code is interpreted as bash instead of js. Here's the error I get:
-bash: /Users/dallinosmun/.nvm/v0.10.21/bin/myScript: line 3: syntax error near unexpected token `('
-bash: /Users/dallinosmun/.nvm/v0.10.21/bin/myScript: line 3: `var exec = require('child_process').exec;'
So, any ideas on how to get a Node.js CLI to run in the current context?
It is not possible since the exec command starts a new process.
But this is a link on a way to bypass the problem:
how do I make node child_process exec continuously

Resources