Skip to content

Commit

Permalink
Merge 2ec7e07 into 03e7600
Browse files Browse the repository at this point in the history
  • Loading branch information
FRSgit committed Oct 17, 2018
2 parents 03e7600 + 2ec7e07 commit ad16381
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 7 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@

All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.

<a name="0.1.0"></a>
# [0.1.0](https://github.com/FRSource/FRS-replace/compare/v0.0.6...v0.1.0) (2018-10-17)


### Features

* **cli:** Input & output options ([55555ce](https://github.com/FRSource/FRS-replace/commit/55555ce)), closes [#7](https://github.com/FRSource/FRS-replace/issues/7)



<a name="0.0.6"></a>
## [0.0.6](https://github.com/FRSource/FRS-replace/compare/v0.0.5...v0.0.6) (2018-10-15)

Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,16 @@ FRS-replace <regex> <replacement> [options]
| \<replacement\> | string | String or path to replacement function file (see &#8209;&#8209;replace&#8209;fn switch for details) |

#### Options:
> Note: Every boolean option can be negated with use of `--no-` prefix, e.g. `--stdout` or `--no-stdout` turn stdout output on or off, respectively.
> Note: Object types can be set using [dot notation](https://github.com/yargs/yargs-parser#dot-notation). So, e.g. if you want to pass `utf8` value under in-opts encoding field you should write `--in-opts.encoding utf8`.
| Option | Type | Default | Description |
| --- | --- | --- | --- |
|&#8209;i, &#8209;&#8209;input | string | *-* | File to read & replace from |
| &#8209;&#8209;in-opts | string or object | utf8 | Passed to [readFileSync](https://nodejs.org/api/fs.html#fs_fs_readfilesync_path_options) when reading input file |
| &#8209;o, &#8209;&#8209;output | string | *-* | Output file name/path (replaces the file if it already exists and creates any intermediate directories if they don't already exist) |
| &#8209;&#8209;out-opts | string or object | utf8 | Passed as options argument of [write's .sync](https://www.npmjs.com/package/write#sync) |
| &#8209;f, &#8209;&#8209;flags | combination of *gim* flags | g | [RegExp](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#Syntax) flags |
| &#8209;c, &#8209;&#8209;content | string | *-* | Content to be replaced (takes precedence over stream & file input) |
| &#8209;&#8209;stdout | boolean | true if piped input present, false otherwise | Force sending output on stdout |
Expand Down
12 changes: 8 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "frs-replace",
"version": "0.0.6",
"version": "0.1.0",
"description": "Simple wrapper around javascript replace with CLI usage support!",
"bin": "./src/cli.js",
"main": "index.js",
Expand All @@ -11,15 +11,19 @@
"prerelease": "standard --fix && yarn test",
"release": "standard-version",
"postrelease": "git push --follow-tags origin master && yarn publish",
"pretest": "standard",
"test": "yarn test:unit --100",
"pretest:unit": "standard",
"test:unit": "tap ./src/*.spec.js -J",
"posttest:unit": "tap --coverage-report=html"
"posttest": "tap --coverage-report=html",
"pretest:unit": "standard --fix",
"test:unit": "tap ./src/*.spec.js -J"
},
"nyc": {
"exclude": "**/*.spec.js",
"include": "src/**"
},
"yargs": {
"camel-case-expansion": false
},
"devDependencies": {
"standard": "^12.0.1",
"standard-version": "^4.4.0",
Expand Down
14 changes: 13 additions & 1 deletion src/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,22 @@ require('get-stdin')().then((stdin) => {
.string('i')
.nargs('i', 1)

.option('in-opts')
.describe('in-opts', 'Passed to fs.readFileSync when reading input file')
.default('in-opts', void 0, 'utf8') // will use node's default value
.implies('in-opts', 'i')

.option('o')
.alias('o', 'output')
.describe('o', 'Output file name/path (replaces the file if it already exists and creates any intermediate directories if they don\'t already exist)')
.string('o')
.nargs('o', 1)

.option('out-opts')
.describe('out-opts', 'Passed as options argument of write\'s .sync method')
.default('out-opts', void 0, 'utf8') // will use node's default value
.implies('out-opts', 'o')

.option('f')
.alias('f', 'flags')
.describe('f', 'RegExp flags (supporting gim)')
Expand Down Expand Up @@ -88,9 +98,11 @@ require('get-stdin')().then((stdin) => {
result = require('./replace').sync({
content: argv.c,
input: argv.i,
inputOptions: argv['in-opts'],
regex: new RegExp(argv.regex, argv.f),
replacement: argv.r ? require(argv.replacement) : argv.replacement,
output: argv.o
output: argv.o,
outputOptions: argv['out-opts']
})
} catch (e) /* istanbul ignore next */ {
process.stderr.write(e.toString())
Expand Down
100 changes: 98 additions & 2 deletions src/cli.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const replacement = 'ą|'
const replaceFn = () => replacement
const expectedOutput = content.replace(new RegExp(regex, defaultFlags), replacement)
const defaultEncoding = 'utf8'
let input, output
let output

tap.afterEach((done) => {
fs.existsSync(output) && fs.unlinkSync(output)
Expand Down Expand Up @@ -89,6 +89,8 @@ tap.test('stdout argument', (t) => {
})

tap.test('input argument', async (t) => {
let input

t.beforeEach(
async () => tmp.file({ prefix: tmpPrefix, keep: true }).then(
async f => {
Expand Down Expand Up @@ -122,6 +124,65 @@ tap.test('input argument', async (t) => {
t.end()
})

tap.test('input options argument', async (t) => {
let input

t.beforeEach(
async () => tmp.file({ prefix: tmpPrefix, keep: true }).then(
async f => {
input = f
return new Promise(
(resolve) => fs.appendFile(f.path, content, { encoding: defaultEncoding }, resolve)
)
})
)

t.afterEach(done => {
input.cleanup()
input = void 0
done()
})

t.test('without input argument', async (ct) => {
const result = runCli(
[regex, replacement, '--in-opts.encoding', defaultEncoding, '--stdout'],
{ input: content }
)

ct.is(result.status, 1, 'process should send error status (1)')
ct.is(result.parsedOutput, '', 'stdout should be empty')
ct.is(result.parsedError, 'in-opts -> i', 'stderr contain error about missing in-opts dependency: i argument')

ct.end()
})

t.test('wrong with input argument', async (ct) => {
const result = runCli(
[regex, replacement, '-i', input.path, '--in-opts.encoding', 'incorrect-encoding', '--stdout']
)

ct.is(result.status, 1, 'process should send error status (1)')
ct.is(result.parsedOutput, '', 'stdout should be empty')
ct.is(result.parsedError, 'TypeError [ERR_INVALID_OPT_VALUE_ENCODING]: The value "incorrect-encoding" is invalid for option "encoding"', 'stderr should complain wrong encoding argument')

ct.end()
})

t.test('correct with input argument', async (ct) => {
const result = runCli(
[regex, replacement, '-i', input.path, '--in-opts.encoding', defaultEncoding, '--stdout']
)

ct.is(result.status, 0, 'process should send success status (0)')
ct.is(result.parsedOutput, expectedOutput, 'stdout should contain replaced string')
ct.is(result.parsedError, '', 'stderr should be empty')

ct.end()
})

t.end()
})

tap.test('output argument', async (t) => {
const outputPath = output = tmp.tmpNameSync({ prefix: tmpPrefix })
await checkEachArgCombinations(
Expand All @@ -144,6 +205,41 @@ tap.test('output argument', async (t) => {
t.end()
})

tap.test('input options argument', async (t) => {
const outputPath = output = tmp.tmpNameSync({ prefix: tmpPrefix })

t.test('without output argument', async (ct) => {
const result = runCli(
[regex, replacement, '--out-opts.encoding', defaultEncoding, '--stdout'],
{ input: content }
)

ct.is(result.status, 1, 'process should send error status (1)')
ct.is(result.parsedOutput, '', 'stdout should be empty')
ct.is(result.parsedError, 'out-opts -> o', 'stderr contain error about missing in-opts dependency: i argument')

ct.end()
})

t.test('correct with input argument', async (ct) => {
const result = runCli(
[regex, replacement, '-o', outputPath, '--out-opts.encoding', defaultEncoding, '--no-stdout'],
{ input: content }
)

ct.is(result.status, 0, 'process should send success status (0)')
ct.is(result.parsedOutput, '', 'stdout should be empty')
ct.is(result.parsedError, '', 'stderr should be empty')

const outputFileContent = fs.readFileSync(outputPath).toString()
ct.is(outputFileContent, expectedOutput, 'expected output saved to file')

ct.end()
})

t.end()
})

tap.test('stdin && output argument', async (t) => {
const outputPath = output = tmp.tmpNameSync({ prefix: tmpPrefix })

Expand Down Expand Up @@ -273,7 +369,7 @@ function runCli (_args, _options) {
const result = childProcess.spawnSync('node', ['./src/cli'].concat(_args || []), _options)

result.parsedOutput = result.stdout.toString().trim()
result.parsedError = result.stderr.toString().trim().split('\n').pop()
result.parsedError = result.stderr.toString().trim().split('\n').pop().trim()

return result
}

0 comments on commit ad16381

Please sign in to comment.