diff --git a/src/cli/help.ts b/src/cli/help.ts new file mode 100644 index 0000000..fa7e900 --- /dev/null +++ b/src/cli/help.ts @@ -0,0 +1,33 @@ +export const help_text = ` + +pkg-fence + + Reading the NPM lockfile from stdin and filtering pkg name by rules. + Exit code: 0 for empty results, 1 for anything matched. + + + +Usage: + + cat package-lock.json | pkg-fence + + npm shrinkwrap && cat npm-shrinkwrap.json | pkg-fence + + + +Builtin Presets: + + --lodash + + --nolyfill + + + +Options: + + --extra foo --extra bar --extra=abc,def + + --ignore foo --ignore bar --ignore=abc,def + +`; + diff --git a/src/cli/main.ts b/src/cli/main.ts index 4520d11..6909fe6 100644 --- a/src/cli/main.ts +++ b/src/cli/main.ts @@ -4,6 +4,7 @@ import { argv, stdin, exit } from 'node:process'; import type { Fn } from '../common.ts'; import { collect, type Flags } from '../collect.ts'; +import { help_text } from './help.ts'; @@ -52,20 +53,35 @@ export function parse (args: Iterable): Flags { export async function main ({ args = argv.slice(2), - lines = createInterface(stdin), + input = stdin, + lines: optional_lines, print = console.log, quit = exit, }: { args?: Iterable, + input?: NodeJS.ReadableStream, lines?: AsyncIterable, - print?: Fn, + // deno-lint-ignore no-explicit-any + print?: Fn, quit?: Fn, } = {}): Promise { + { // -h, --help + + const [ cmd ] = Array.from(args); + + if (cmd == null || cmd === '-h' || cmd === '--help') { + print(help_text); + return quit(0); + } + + } + const flags = parse(args); + const lines = optional_lines ?? createInterface({ input }); let code = 0; diff --git a/tests/cli/main.test.ts b/tests/cli/main.test.ts index ee63793..28b2e66 100644 --- a/tests/cli/main.test.ts +++ b/tests/cli/main.test.ts @@ -1,6 +1,9 @@ import { describe, it } from '@std/testing/bdd'; +import * as asserts from '@std/assert'; import * as mock from '@std/testing/mock'; +import { Readable } from 'node:stream'; + import { make_lines } from '../utils.ts'; import { @@ -15,6 +18,55 @@ import { describe('main', function () { + for (const cmd of [ null, '-h', '--help' ]) { + + it(`print help message on ${ cmd }`, async function () { + + const args = cmd == null ? [] : [ cmd ]; + + const print = mock.spy(function (help: string) { + asserts.assertMatch(help, /Reading the NPM lockfile/); + }); + + const quit = mock.spy(() => {}); + + await main({ args, print, quit }); + + mock.assertSpyCalls(print, 1); + + mock.assertSpyCallArg(quit, 0, 0, 0); + mock.assertSpyCalls(quit, 1); + + }); + + } + + it('ok in optional lines with input of ReadableStream', async function () { + + const args = [ '--extra', 'acorn-jsx' ]; + + const input = Readable.from(` + "version": "1.2.3", + "lockfileVersion": 2, + "node_modules/lodash.memoize": { + "node_modules/acorn-jsx": { + "node_modules/side-channel": { + `); + + const print = mock.spy(() => {}); + + const quit = mock.spy(() => {}); + + await main({ args, input, print, quit }); + + mock.assertSpyCallArg(print, 0, 0, 'acorn-jsx'); + mock.assertSpyCalls(print, 1); + + mock.assertSpyCallArg(quit, 0, 0, 1); + mock.assertSpyCalls(quit, 1); + + }); + it('exit by 0 with no matches', async function () { const args = [ '--extra', 'wat' ];