diff --git a/README.md b/README.md index cd124b9c..a230036e 100644 --- a/README.md +++ b/README.md @@ -186,7 +186,7 @@ Let both `"foo 'is' bar"` and `' foo "was" bar'` become `» foo ... bar «` inde | `-E` | **`--engine`** What regex engine to use. `default` is the engine of the runtime: `V8` with Node and `JSC` (JavaScriptCore) with Bun. The engine of the other runtime can not be picked. [choices: "default", "V8", "JSC"] [default: "default"] | | `-q` | **`--quiet`** Only display errors (no other info) [boolean] | | `-Q` | **`--quiet-total`** Never display errors or info [boolean] | -| `-H` | **`--halt`** Halt on first error [boolean] [default: false] | +| `-H` | **`--halt`**, **`--bail`** Halt on first error [boolean] [default: false] | | `-d` | **`--debug`** Print debug info [boolean] | | `-€` | **`--void-euro`** Void having `€` as alias for `$` in the pattern, replacement and --exclude-re parameters (the alias is never used for globs or piped data) [boolean] | | `-§` | **`--void-section`** Void having `§` as alias for `\` in the pattern, replacement and --exclude-re parameters (the alias is never used for globs or piped data) [boolean] | diff --git a/src/cli.ts b/src/cli.ts index 06452bb2..3c92ed4b 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -113,6 +113,7 @@ const yargs = require('yargs') .boolean('H') .describe('H', 'Halt on first error') .alias('H', 'halt') + .alias('H', 'bail') .default('H', false) .boolean('d') diff --git a/test/cli/run.sh b/test/cli/run.sh index afd8a820..18b99269 100644 --- a/test/cli/run.sh +++ b/test/cli/run.sh @@ -96,6 +96,16 @@ assert_success "rexreplace --help" assert_failure "rexreplace o-ho" assert_failure "rexreplace -H" +# -H, --halt, --bail +reset +assert_success "rexreplace --help | grep -F -- '--bail' >/dev/null" +assert_raises "rexreplace o x nope.file --bail" 1 +assert_raises "rexreplace o x nope.file --halt" 1 +assert_raises "rexreplace o x nope.file -H" 1 +# --bail is accepted (not an unknown argument) and leaves files untouched when nothing fails +assert_success "rexreplace o x my.file --bail" +assert "cat my.file" "fxxbar" + # -o reset @@ -374,10 +384,6 @@ assert "cat your.file" 'abc123' # assert "rexreplace ??? ??? my.file -Q" "foobar" # reset -# Todo: test -H -# assert "rexreplace ??? ??? my.file -H" "foobar" -# reset - # Todo: test -d # assert "rexreplace ??? ??? my.file -d" "foobar" # reset diff --git a/test/js/halt.test.js b/test/js/halt.test.js index 2aa66a63..df001713 100644 --- a/test/js/halt.test.js +++ b/test/js/halt.test.js @@ -1,7 +1,20 @@ import {describe, test, expect} from 'bun:test'; +import {spawnSync} from 'child_process'; import fs from 'fs'; +import path from 'path'; import {rr} from './helper.js'; +// --bail is a CLI alias for --halt, so these cases run the CLI itself (like test/js/fix/691.test.js). +const cli = path.join(import.meta.dir, '../../src/cli.ts'); + +function runCli(...args) { + const {stdout, stderr, status} = spawnSync(process.execPath, [cli, ...args], { + input: '', + encoding: 'utf8', + }); + return {out: stdout, err: stderr, exit: status}; +} + describe('--halt', () => { test('stops the process on the first error', () => { const result = rr('o', 'x', {includeGlob: ['nope.file'], halt: true}); @@ -27,6 +40,28 @@ describe('--halt', () => { expect(rr('(', 'x', {pipedData: 'foobar', halt: true}).exit).toBe(1); }); + describe('--bail alias', () => { + test('is listed in --help with --halt', () => { + const result = runCli('--help'); + expect(result.exit).toBe(0); + expect(result.out).toContain('--bail'); + expect(result.out).toMatch(/-H,\s*--halt,\s*--bail/); + }); + + test.each(['--bail', '--halt', '-H'])('%s stops on the first error like --halt', (flag) => { + const result = runCli('o', 'x', 'nope.file', flag); + expect(result.err).toContain('0 files found'); + expect(result.exit).toBe(1); + }); + + test('--bail is accepted and changes nothing when all goes well', () => { + fs.writeFileSync('my.file', 'foobar'); + const result = runCli('o', 'x', 'my.file', '--bail'); + expect(result.exit).toBe(0); + expect(fs.readFileSync('my.file', 'utf8')).toBe('fxxbar'); + }); + }); + describe('combined', () => { test.each(['quiet', 'quietTotal'])('with --%s it still stops', (flag) => { const result = rr('o', 'x', {includeGlob: ['nope.file'], halt: true, [flag]: true});