Skip to content

Commit

Permalink
4.0.0 (#74)
Browse files Browse the repository at this point in the history
* Bump dependencies

* [feature] #38 Count number of matches

* Update make-replacements.js

* [feature] #42 Differentiate number of matches and number of replacements

* [enhance] #56 Support for CWD parameter

* Default config value

* [enhance] #63 Add --quiet flag to supress console output in CLI

* Update success-handler.js

* Update readme and add change log
  • Loading branch information
adamreisnz authored Apr 21, 2019
1 parent d607529 commit 27f5572
Show file tree
Hide file tree
Showing 14 changed files with 485 additions and 890 deletions.
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# 4.0.0

## Breaking changes
The return value is now a results array instead of an array with changed files. The new results array includes each file that was processed, with a flag to indicate whether or not the file was changed, and optionally information about the number of matches and replacements that were made. See the readme for more details.

To update existing code and obtain an array of changed files again, simply convert the results array as follows:

```js
const results = await replace(options);
const changedFiles = results
.filter(result => result.hasChanged)
.map(result => result.file);
```

## New features
- Added `countMatches` flag to count the number of matches and replacements per file [#38](https://github.com/adamreisnz/replace-in-file/issues/38), [#42](https://github.com/adamreisnz/replace-in-file/issues/42), [#61](https://github.com/adamreisnz/replace-in-file/issues/61)
- Added `--quiet` flag for CLI to suppress success output [#63](https://github.com/adamreisnz/replace-in-file/issues/63)
- Added `cwd` configuration parameter for network drive replacements [#56](https://github.com/adamreisnz/replace-in-file/issues/56)

# 3.0.0

## Breaking changes
From version 3.0.0 onwards, replace in file requires Node 6 or higher. If you need support for Node 4 or 5, please use version 2.x.x.
110 changes: 91 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ A simple utility to quickly replace text in one or more files or globs. Works sy
- [Asynchronous replacement with callback](#asynchronous-replacement-with-callback)
- [Synchronous replacement](#synchronous-replacement)
- [Return value](#return-value)
- [Counting matches and replacements](#counting-matches-and-replacements)
- [Advanced usage](#advanced-usage)
- [Replace a single file or glob](#replace-a-single-file-or-glob)
- [Replace multiple files or globs](#replace-multiple-files-or-globs)
Expand All @@ -30,7 +31,8 @@ A simple utility to quickly replace text in one or more files or globs. Works sy
- [Ignore multiple files or globs](#ignore-multiple-files-or-globs)
- [Allow empty/invalid paths](#allow-emptyinvalid-paths)
- [Disable globs](#disable-globs)
- [Specify glob configuration](#glob-configuration)
- [Specify glob configuration](#specify-glob-configuration)
- [Making replacements on network drives](#making-replacements-on-network-drives)
- [Specify character encoding](#specify-character-encoding)
- [Dry run](#dry-run)
- [CLI usage](#cli-usage)
Expand Down Expand Up @@ -65,8 +67,8 @@ const options = {

```js
try {
const changes = await replace(options)
console.log('Modified files:', changes.join(', '));
const results = await replace(options)
console.log('Replacement results:', results);
}
catch (error) {
console.error('Error occurred:', error);
Expand All @@ -77,8 +79,8 @@ catch (error) {

```js
replace(options)
.then(changes => {
console.log('Modified files:', changes.join(', '));
.then(results => {
console.log('Replacement results:', results);
})
.catch(error => {
console.error('Error occurred:', error);
Expand All @@ -88,20 +90,20 @@ replace(options)
### Asynchronous replacement with callback

```js
replace(options, (error, changes) => {
replace(options, (error, results) => {
if (error) {
return console.error('Error occurred:', error);
}
console.log('Modified files:', changes.join(', '));
console.log('Replacement results:', results);
});
```

### Synchronous replacement

```js
try {
const changes = replace.sync(options);
console.log('Modified files:', changes.join(', '));
const results = replace.sync(options);
console.log('Replacement results:', results);
}
catch (error) {
console.error('Error occurred:', error);
Expand All @@ -110,22 +112,84 @@ catch (error) {

### Return value

The return value of the library is an array of file names of files that were modified (e.g.
had some of the contents replaced). If no replacements were made, the return array will be empty.
The return value of the library is an array of replacement results against each file that was processed. This includes files in which no replacements were made.

Each result contains the following values:

- `file`: The path to the file that was processed
- `hasChanged`: Flag to indicate if the file was changed or not

```js
const changes = replace.sync({
const results = replace.sync({
files: 'path/to/files/*.html',
from: 'foo',
from: /foo/g,
to: 'bar',
});

console.log(results);

// [
// {
// file: 'path/to/files/file1.html',
// hasChanged: true,
// },
// {
// file: 'path/to/files/file2.html',
// hasChanged: true,
// },
// {
// file: 'path/to/files/file3.html',
// hasChanged: false,
// },
// ]

```

To get an array of changed files, simply map the results as follows:

```js
const changedFiles = results
.filter(result => result.hasChanged)
.map(result => result.file);
```

### Counting matches and replacements
By setting the `countMatches` configuration flag to `true`, the number of matches and replacements per file will be counted and present in the results array.

- `numMatches`: Indicates the number of times a match was found in the file
- `numReplacements`: Indicates the number of times a replacement was made in the file

Note that the number of matches can be higher than the number of replacements if a match and replacement are the same string.

```js
const results = replace.sync({
files: 'path/to/files/*.html',
from: /foo/g,
to: 'bar',
countMatches: true,
});

console.log(changes);
console.log(results);

// [
// 'path/to/files/file1.html',
// 'path/to/files/file3.html',
// 'path/to/files/file5.html',
// {
// file: 'path/to/files/file1.html',
// hasChanged: true,
// numMatches: 3,
// numReplacements: 3,
// },
// {
// file: 'path/to/files/file2.html',
// hasChanged: true,
// numMatches: 1,
// numReplacements: 1,
// },
// {
// file: 'path/to/files/file3.html',
// hasChanged: false,
// numMatches: 0,
// numReplacements: 0,
// },
// ]
```

Expand Down Expand Up @@ -293,6 +357,9 @@ const options = {

Please note that the setting `nodir` will always be passed as `false`.

### Making replacements on network drives
To make replacements in files on network drives, you may need to specify the UNC path as the `cwd` config option. This will then be passed to glob and prefixed to your paths accordingly. See [#56](https://github.com/adamreisnz/replace-in-file/issues/56) for more details.

### Specify character encoding
Use a different character encoding for reading/writing files. Defaults to `utf-8`.

Expand Down Expand Up @@ -321,6 +388,7 @@ replace-in-file from to some/file.js,some/**/glob.js
[--disableGlobs]
[--isRegex]
[--verbose]
[--quiet]
[--dry]
```

Expand All @@ -331,7 +399,9 @@ The flags `--disableGlobs`, `--ignore` and `--encoding` are supported in the CLI
The setting `allowEmptyPaths` is not supported in the CLI as the replacement is
synchronous, and this setting is only relevant for asynchronous replacement.

To list the changed files, use the `--verbose` flag. To do a dry run, use `--dry`.
To list the changed files, use the `--verbose` flag. Success output can be suppressed by using the `--quiet` flag.

To do a dry run without making any actual changes, use `--dry`.

A regular expression may be used for the `from` parameter by specifying the `--isRegex` flag.

Expand All @@ -343,7 +413,9 @@ Node’s built in `path.resolve()`, so you can pass in an absolute or relative p
## Version information
From version 3.0.0 onwards, replace in file requires Node 6 or higher. If you need support for Node 4 or 5, please use version 2.x.x.

See the [Changelog](CHANGELOG.md) for more information.

## License
(MIT License)

Copyright 2015-2018, [Adam Reis](https://adam.reis.nz), co-founder at [Hello Club](https://helloclub.com/?source=npm)
Copyright 2015-2019, [Adam Reis](https://adam.reis.nz), Co-founder at [Hello Club](https://helloclub.com/?source=npm)
12 changes: 8 additions & 4 deletions bin/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const config = loadConfig(configFile);
const options = combineConfig(config, argv);

//Extract settings
const {from, to, files, isRegex, verbose} = options;
const {from, to, files, isRegex, verbose, quiet} = options;

//Single star globs already get expanded in the command line
options.files = files.reduce((files, file) => {
Expand All @@ -44,12 +44,16 @@ if (isRegex) {
}

//Log
console.log(`Replacing '${from}' with '${to}'`);
if (!quiet) {
console.log(`Replacing '${from}' with '${to}'`);
}

//Replace
try {
const changes = replace.sync(options);
successHandler(changes, verbose);
const results = replace.sync(options);
if (!quiet) {
successHandler(results, verbose);
}
}
catch (error) {
errorHandler(error);
Expand Down
7 changes: 4 additions & 3 deletions lib/helpers/get-paths-async.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ const globAsync = require('./glob-async');
/**
* Get paths asynchrously
*/
module.exports = function getPathsAsync(
patterns, ignore, disableGlobs, allowEmptyPaths, cfg
) {
module.exports = function getPathsAsync(patterns, config) {

//Extract relevant config
const {ignore, disableGlobs, allowEmptyPaths, glob: cfg} = config;

//Not using globs?
if (disableGlobs) {
Expand Down
25 changes: 20 additions & 5 deletions lib/helpers/get-paths-sync.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,35 @@ const glob = require('glob');
/**
* Get paths (sync)
*/
module.exports = function getPathsSync(patterns, ignore, disableGlobs, cfg) {
module.exports = function getPathsSync(patterns, config) {

//Extract relevant config
const {ignore, disableGlobs, glob: globConfig, cwd} = config;

//Not using globs?
if (disableGlobs) {
return patterns;
}

//Prepare glob config
cfg = Object.assign({ignore}, cfg, {nodir: true});
const cfg = Object.assign({ignore}, globConfig, {nodir: true});

//Append CWD configuration if given (#56)
//istanbul ignore if
if (cwd) {
cfg.cwd = cwd;
}

//Get paths
const paths = patterns
.map(pattern => glob.sync(pattern, cfg));
const paths = patterns.map(pattern => glob.sync(pattern, cfg));
const flattened = [].concat.apply([], paths);

//Prefix each path with CWD if given (#56)
//istanbul ignore if
if (cwd) {
return flattened.map(path => `${cwd}${path}`);
}

//Return flattened
return [].concat.apply([], paths);
return flattened;
};
38 changes: 29 additions & 9 deletions lib/helpers/make-replacements.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,28 +16,35 @@ function getReplacement(replace, isArray, i) {
/**
* Helper to make replacements
*/
module.exports = function makeReplacements(contents, from, to, file) {
module.exports = function makeReplacements(contents, from, to, file, count) {

//Turn into array
if (!Array.isArray(from)) {
from = [from];
}

//Check if replace value is an array
//Check if replace value is an array and prepare result
const isArray = Array.isArray(to);
const result = {file};

//Counting? Initialize number of matches
if (count) {
result.numMatches = 0;
result.numReplacements = 0;
}

//Make replacements
from.forEach((item, i) => {
const newContents = from.reduce((contents, item, i) => {

//Call function if given, passing the filename
//Call function if given, passing in the filename
if (typeof item === 'function') {
item = item(file);
}

//Get replacement value
let replacement = getReplacement(to, isArray, i);
if (replacement === null) {
return;
return contents;
}

//Call function if given, appending the filename
Expand All @@ -46,10 +53,23 @@ module.exports = function makeReplacements(contents, from, to, file) {
replacement = (...args) => original(...args, file);
}

//Count matches
if (count) {
const matches = contents.match(item);
if (matches) {
const replacements = matches.filter(match => match !== replacement);
result.numMatches += matches.length;
result.numReplacements += replacements.length;
}
}

//Make replacement
contents = contents.replace(item, replacement);
});
return contents.replace(item, replacement);
}, contents);

//Check if changed
result.hasChanged = (newContents !== contents);

//Return modified contents
return contents;
//Return result and new contents
return [result, newContents];
};
Loading

0 comments on commit 27f5572

Please sign in to comment.