» Make grep CLI App in Node.js » 3. Publish » 3.1 Build

Build

To make your script executable, update your package.json file to include a bin field.

"bin": {
    "grepjs": "dist/bin/cmd.js"
}

This field should map the name of your executable (grepjs) to the entry point script (e.g., dist/bin/cmd.js).

Ensure that the dist/bin/cmd.js file is executable. You can use the chmod command:

chmod +x dist/bin/cmd.js

Run the following command to install your package globally. This will make the grepjs executable available system-wide.

npm install -g

Make sure you run this command from the root of your project, where the package.json file is located.

After installation, you can do this:

grepjs -n line lib/*ts

You should be able to see something similar to this:

3: import * as readline from 'readline'
16: const lines = filePath === '' ? await _readStdinLines() : await _readFileLines(filePath)
21: matchingLines = _filterLines(regex, lines, false)
23: matchingLines = _filterLines(regex, lines, true)
73: (count, lines) => count + lines.length,
78: function _filterLines (regexPattern: RegExp, lines: string[], flag: boolean): MatchItem[] {
79: const candidates: MatchItem[] = lines.map((line, index) => [index + 1, line.trim()])
81: .filter(([_, line]) => regexPattern.test(line) === flag)
100: const rl = readline.createInterface({
107: const lines: string[] = []
108: rl.on('line', (line) => {
113: resolve(lines)

Try the recursive search:

grepjs -nr line lib/ bin/

Result:

lib/grep.ts:
3: import * as readline from 'readline'
16: const lines = filePath === '' ? await _readStdinLines() : await _readFileLines(filePath)
21: matchingLines = _filterLines(regex, lines, false)
23: matchingLines = _filterLines(regex, lines, true)
73: (count, lines) => count + lines.length,
78: function _filterLines (regexPattern: RegExp, lines: string[], flag: boolean): MatchItem[] {
79: const candidates: MatchItem[] = lines.map((line, index) => [index + 1, line.trim()])
81: .filter(([_, line]) => regexPattern.test(line) === flag)
100: const rl = readline.createInterface({
107: const lines: string[] = []
108: rl.on('line', (line) => {
113: resolve(lines)

bin/cmd.ts:
8: // Parse command-line options
14: describe: 'Only a count of selected lines is written to standard output.',
32: alias: 'line-number',
34: 'Each output line is preceded by its relative line number in the file, starting at line 1. The line number counter is reset for each file processed. This option is ignored if -c is specified.',
47: 'Selected lines are those not matching any of the specified patterns.',
75: printResult(result, argv['line-number'] as boolean)
86: for (const [filePath, lines] of Object.entries(result)) {
87: for (const [lineNumber, line] of lines) {
93: console.log(`${lineNumber}: ${line}`)
95: console.log(line)

At this point, you may have too many commands (run, test, local install, build and etc) to remember. Add a Makefile to make it easier.

Makefile:

.PHONY: run test lint build publish clean

run:
	npm start

test:
	npm test

lint:
	npm run lint

install:
	chmod +x dist/bin/cmd.js
	npm install -g

build:
	npm run build

publish: build
	npm publish

clean:
	rm -rf dist

Then you can easily do these operations:

make run
make test
make build
make install
make publish