Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: adamreisnz/replace-in-file
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 40a3b59894e87a74182903259029366ab55a99b4
Choose a base ref
...
head repository: adamreisnz/replace-in-file
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 2bec5b78f83848c318741f2bae4bc8f22fe25ca5
Choose a head ref
  • 4 commits
  • 10 files changed
  • 3 contributors

Commits on Oct 27, 2023

  1. Update README.md

    adamreisnz committed Oct 27, 2023

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    dac85a2 View commit details

Commits on Dec 27, 2023

  1. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    c899277 View commit details
  2. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    0299d17 View commit details
  3. Update package.json

    adamreisnz committed Dec 27, 2023

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    2bec5b7 View commit details
33 changes: 31 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -35,6 +35,7 @@ A simple utility to quickly replace text in one or more files or globs. Works sy
- [Making replacements on network drives](#making-replacements-on-network-drives)
- [Specify character encoding](#specify-character-encoding)
- [Dry run](#dry-run)
- [File system](#file-system)
- [CLI usage](#cli-usage)
- [A note on using globs with the CLI](#a-note-on-using-globs-with-the-cli)
- [Version information](#version-information)
@@ -383,8 +384,10 @@ Specify configuration passed to the [glob](https://www.npmjs.com/package/glob) c
```js
const options = {
glob: {
//Glob settings here
dot: true, //E.g. to include file names starting with a dot

//Glob settings here (examples given below)
dot: true, //To include file names starting with a dot
windowsPathsNoEscape: true, //To fix paths on Windows OS when path.join() is used to create paths
},
};
```
@@ -412,6 +415,32 @@ const options = {
};
```

### File system
`replace-in-file` defaults to using `require('fs')` to provide file reading and write APIs.
You can provide an `fs` object of your own to switch to a different file system, such as a mock file system for unit tests.

* If using asynchronous APIs, the provided `fs` must provide `readFile` and `writeFile` methods
* If using synchronous APIs, the provided `fs` must provide `readFileSync` and `writeFileSync` methods

Custom `fs` methods should have the same parameters and returned values as their [built-in Node `fs`](https://nodejs.org/api/fs.html) equivalents.

```js
replaceInFile({
from: 'a',
fs: {
readFile: (file, encoding, callback) => {
console.log(`Reading ${file} with encoding ${encoding}...`);
callback(null, 'fake file contents');
},
writeFile: (file, newContents, encoding, callback) => {
console.log(`Writing ${file} with encoding ${encoding}: ${newContents}`);
callback(null);
},
},
to: 'b',
})
```

## CLI usage

```sh
4 changes: 2 additions & 2 deletions lib/helpers/parse-config.js
Original file line number Diff line number Diff line change
@@ -14,6 +14,7 @@ const defaults = {
dry: false,
glob: {},
cwd: null,
fs: require('fs'),
};

/**
@@ -31,10 +32,9 @@ module.exports = function parseConfig(config) {

//Extract data
const {files, from, to, processor, ignore, encoding} = config;

if (typeof processor !== 'undefined') {
if (typeof processor !== 'function' && !Array.isArray(processor)) {
throw new Error('Processor should be either a function or an array of functions');
throw new Error(`Processor should be either a function or an array of functions`);
}
}
else {
3 changes: 1 addition & 2 deletions lib/helpers/process-async.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@

const fs = require('fs');
const runProcessors = require('./run-processors');

/**
@@ -8,7 +7,7 @@ const runProcessors = require('./run-processors');
module.exports = function processAsync(file, processor, config) {

//Extract relevant config
const {encoding, dry} = config;
const {encoding, dry, fs} = config;

//Wrap in promise
return new Promise((resolve, reject) => {
3 changes: 1 addition & 2 deletions lib/helpers/process-sync.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@

const fs = require('fs');
const runProcessors = require('./run-processors');

/**
@@ -8,7 +7,7 @@ const runProcessors = require('./run-processors');
module.exports = function processSync(file, processor, config) {

//Extract relevant config and read file contents
const {encoding, dry} = config;
const {encoding, dry, fs} = config;
const contents = fs.readFileSync(file, encoding);

//Process contents and check if anything changed
3 changes: 1 addition & 2 deletions lib/helpers/replace-async.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@

const fs = require('fs');
const makeReplacements = require('./make-replacements');

/**
@@ -8,7 +7,7 @@ const makeReplacements = require('./make-replacements');
module.exports = function replaceAsync(file, from, to, config) {

//Extract relevant config
const {encoding, dry, countMatches} = config;
const {encoding, dry, countMatches, fs} = config;

//Wrap in promise
return new Promise((resolve, reject) => {
3 changes: 1 addition & 2 deletions lib/helpers/replace-sync.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@

const fs = require('fs');
const makeReplacements = require('./make-replacements');

/**
@@ -8,7 +7,7 @@ const makeReplacements = require('./make-replacements');
module.exports = function replaceSync(file, from, to, config) {

//Extract relevant config and read file contents
const {encoding, dry, countMatches} = config;
const {encoding, dry, countMatches, fs} = config;
const contents = fs.readFileSync(file, encoding);

//Replace contents and check if anything changed
6 changes: 2 additions & 4 deletions lib/helpers/run-processors.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
/**
* Run processors
*/
module.exports = function runProcessors(contents, processor, file, count) {

module.exports = function runProcessors(contents, processor, file) {
const processors = Array.isArray(processor) ? processor : [processor];
const result = {file};

const newContents = processors.reduce((contents, processor, i) => {
const newContents = processors.reduce((contents, processor) => {
return processor(contents);
}, contents);

result.hasChanged = (newContents !== contents);

return [result, newContents];
};
57 changes: 57 additions & 0 deletions lib/process-file.spec.js
Original file line number Diff line number Diff line change
@@ -297,6 +297,34 @@ describe('Process a file', () => {
done();
});
});

describe('fs', () => {
it('reads and writes using a custom fs when provided', done => {
const before = 'abc';
let written;

const fs = {
readFile: (_fileName, _encoding, callback) => {
callback(null, before);
},
writeFile: (_fileName, data, _encoding, callback) => {
written = data;
callback(null);
},
};

transform({
files: 'test1',
fs,
processor: (input) => {
return input.replace(/b/, 'z');
},
}).then(() => {
expect(written).to.equal('azc');
done();
});
});
});
});

/**
@@ -725,6 +753,35 @@ describe('Process a file', () => {
expect(results[2].file).to.equal('test3');
expect(results[2].hasChanged).to.equal(false);
});

describe('fs', () => {
it('reads and writes using a custom fs when provided', done => {
const before = 'a';
let written;

const fs = {
readFileSync: () => {
return before;
},
writeFileSync: (_fileName, data) => {
written = data;
return data;
},
};

const results = transform.sync({
files: 'test1',
fs,
processor: (input) => {
return input.replace(/a/, 'z');
},
});

expect(results[0].file).to.equal('test1');
expect(written).to.equal('z');
done();
});
});
});

describe('module export', () => {
86 changes: 86 additions & 0 deletions lib/replace-in-file.spec.js
Original file line number Diff line number Diff line change
@@ -67,6 +67,13 @@ describe('Replace in file', () => {
})).to.eventually.be.rejectedWith(Error);
});

it('should throw an error if invalid `processor` supplied', () => {
return expect(replace({
files: 'test1',
processor: 42,
})).to.eventually.be.rejectedWith(Error);
});

it('should replace contents in a single file with regex', done => {
replace({
files: 'test1',
@@ -416,6 +423,33 @@ describe('Replace in file', () => {
done();
});
});

describe('fs', () => {
it('reads and writes using a custom fs when provided', done => {
const before = 'a';
let written;

const fs = {
readFile: (_fileName, _encoding, callback) => {
callback(null, before);
},
writeFile: (_fileName, data, _encoding, callback) => {
written = data;
callback(null);
},
};

replace({
files: 'test1',
from: /a/,
fs,
to: 'z',
}).then(() => {
expect(written).to.equal('z');
done();
});
});
});
});

/**
@@ -1149,6 +1183,58 @@ describe('Replace in file', () => {
expect(results[0].numMatches).to.equal(0);
expect(results[0].numReplacements).to.equal(0);
});

describe('fs', () => {
it('reads and writes using a custom fs when provided', () => {
const before = 'a';
let written;

const fs = {
readFileSync: () => {
return before;
},
writeFileSync: (_fileName, data) => {
written = data;
return data;
},
};

const results = replace.sync({
files: 'test1',
from: /a/,
fs,
to: 'z',
});

expect(results[0].file).to.equal('test1');
expect(written).to.equal('z');
});
});

//Processors
describe('processors', () => {
it('uses custom processor', () => {
replace.sync({
files: 'test1',
fs,
processor: input => input.replace(/place/, 'plop'),
});
const test1 = fs.readFileSync('test1', 'utf8');
expect(test1).to.equal('a re plop c');
});
it('uses array of custom processors', () => {
replace.sync({
files: 'test1',
fs,
processor: [
input => input.replace(/place/, 'plop'),
input => input.replace(/plop/, 'bloop'),
],
});
const test1 = fs.readFileSync('test1', 'utf8');
expect(test1).to.equal('a re bloop c');
});
});
});

describe('module export', () => {
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "replace-in-file",
"version": "7.0.2",
"version": "7.1.0",
"description": "A simple utility to quickly replace text in one or more files.",
"homepage": "https://github.com/adamreisnz/replace-in-file#readme",
"author": {