Socket
Socket
Sign inDemoInstall

replace-in-file

Package Overview
Dependencies
Maintainers
0
Versions
79
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

replace-in-file - npm Package Compare versions

Comparing version 7.2.0 to 8.0.0

.c8rc

38

bin/cli.js
#!/usr/bin/env node
const {argv} = require('yargs');
const replace = require('../lib/replace-in-file');
const loadConfig = require('../lib/helpers/load-config');
const combineConfig = require('../lib/helpers/combine-config');
const errorHandler = require('../lib/helpers/error-handler');
const successHandler = require('../lib/helpers/success-handler');
import {argv} from 'yargs'
import replace from '../src/replace-in-file.js'
import {loadConfig, combineConfig} from '../src/helpers/config.js'
import {errorHandler, successHandler} from '../src/helpers/handlers.js'

@@ -16,26 +14,26 @@ /**

//Extract parameters
const {configFile} = argv;
const {configFile} = argv
//Verify arguments
if (argv._.length < 3 && !configFile) {
throw new Error('Replace in file needs at least 3 arguments');
throw new Error('Replace in file needs at least 3 arguments')
}
//Load config and combine with passed arguments
const config = await loadConfig(configFile);
const options = combineConfig(config, argv);
const config = configFile ? await loadConfig(configFile) : {}
const options = combineConfig(config, argv)
//Extract settings
const {from, to, files, isRegex, verbose, quiet} = 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) => {
return files.concat(file.split(','));
}, []);
return files.concat(file.split(','))
}, [])
//If the isRegex flag is passed, convert the from parameter to a RegExp object
if (isRegex) {
const flags = from.replace(/.*\/([gimyus]*)$/, '$1');
const pattern = from.replace(new RegExp(`^/(.*?)/${flags}$`), '$1');
options.from = new RegExp(pattern, flags);
const flags = from.replace(/.*\/([gimyus]*)$/, '$1')
const pattern = from.replace(new RegExp(`^/(.*?)/${flags}$`), '$1')
options.from = new RegExp(pattern, flags)
}

@@ -45,9 +43,9 @@

if (!quiet) {
console.log(`Replacing '${from}' with '${to}'`);
console.log(`Replacing '${from}' with '${to}'`)
}
//Replace
const results = replace.sync(options);
const results = replace.sync(options)
if (!quiet) {
successHandler(results, verbose);
successHandler(results, verbose)
}

@@ -57,2 +55,2 @@ }

//Call main routine
main().catch(error => errorHandler(error));
main().catch(error => errorHandler(error))

@@ -0,1 +1,25 @@

## 8.0.0
The package has been converted to an ES module and now requires Node 18 or higher. If you need support for Node 16 or below, please use version 7.x.x.
### Breaking changes
- Package has been converted to an ES module
- No longer providing a default export. Use the named exports `replaceInFile` or `replaceInFileSync` instead.
- The `replace.sync` syntax is no longer available. Use the named export `replaceInFileSync` instead.
- The callback API has been removed for asynchronous replacements. Please use promises or `async/await` instead.
- Configuration files provided to the CLI using the `--configFile` flag can now only be JSON.
- To use a custom `fs` implementation, you must now specify `fs` config parameter for the async API, and `fsSync` for the sync API. For the asynchronous APIs, the provided `fs` must provide the `readFile` and `writeFile` methods. For the synchronous APIs, the provided `fsSync` must provide the `readFileSync` and `writeFileSync` methods.
- If a `cwd` parameter is provided, it will no longer be prefixed to each path using basic string concatenation, but rather uses `path.join()` to ensure correct path concatenation.
### New features
You can now specify a `getTargetFile` config param to modify the target file for saving the new file contents to. For example:
```js
const options = {
files: 'path/to/files/*.html',
getTargetFile: source => `new/path/${source}`,
from: 'foo',
to: 'bar',
}
```
## 7.0.0

@@ -2,0 +26,0 @@ Strings provided to the `from` value are now escaped for regex matching when counting of matches is enabled. This is unlikely to result in any breaking changes, but as a precaution the major version has been bumped.

@@ -1,1 +0,5 @@

module.exports = require('./lib/replace-in-file');
import {replaceInFile, replaceInFileSync} from './src/replace-in-file.js'
import {processFile, processFileSync} from './src/process-file.js'
//Export
export {replaceInFile, replaceInFileSync, processFile, processFileSync}
{
"name": "replace-in-file",
"version": "7.2.0",
"type": "module",
"version": "8.0.0",
"description": "A simple utility to quickly replace text in one or more files.",

@@ -28,39 +29,23 @@ "homepage": "https://github.com/adamreisnz/replace-in-file#readme",

"engines": {
"node": ">=10"
"node": ">=18"
},
"scripts": {
"test": "nyc mocha 'lib/**/*.spec.js'",
"postversion": "git push && git push --tags && npm publish",
"coverage": "open -a \"Google Chrome\" ./coverage/lcov-report/index.html"
"test": "mocha 'src/**/*.spec.js'",
"coverage": "c8 npm run test",
"postcoverage": "open -a \"Google Chrome\" ./coverage/lcov-report/index.html",
"postversion": "git push && git push --tags && npm publish"
},
"dependencies": {
"chalk": "^4.1.2",
"glob": "^8.1.0",
"chalk": "^5.3.0",
"glob": "^10.4.2",
"yargs": "^17.7.2"
},
"devDependencies": {
"@babel/core": "^7.23.6",
"@babel/cli": "^7.23.4",
"@babel/preset-env": "^7.23.6",
"@babel/register": "^7.22.15",
"babel-plugin-istanbul": "^6.1.1",
"bluebird": "^3.7.2",
"chai": "^4.3.10",
"chai-as-promised": "^7.1.1",
"dirty-chai": "^2.0.1",
"mocha": "^10.2.0",
"nyc": "^15.0.1"
},
"browserify": {
"transform": [
[
"babelify",
{
"presets": [
"es2015"
]
}
]
]
"@eslint/js": "^9.2.0",
"c8": "^10.1.2",
"chai": "^5.1.1",
"chai-as-promised": "^8.0.0",
"eslint": "^9.2.0",
"mocha": "^10.4.0"
}
}
# Replace in file
[![npm version](https://img.shields.io/npm/v/replace-in-file.svg)](https://www.npmjs.com/package/replace-in-file)
[![build status](https://travis-ci.org/adamreisnz/replace-in-file.svg?branch=master)](https://travis-ci.org/adamreisnz/replace-in-file)
[![coverage status](https://coveralls.io/repos/github/adamreisnz/replace-in-file/badge.svg?branch=master)](https://coveralls.io/github/adamreisnz/replace-in-file?branch=master)

@@ -10,12 +9,9 @@ [![github issues](https://img.shields.io/github/issues/adamreisnz/replace-in-file.svg)](https://github.com/adamreisnz/replace-in-file/issues)

# Index
## Index
- [Installation](#installation)
- [Basic usage](#basic-usage)
- [Asynchronous replacement with `async`/`await`](#asynchronous-replacement-with-asyncawait)
- [Asynchronous replacement with promises](asynchronous-replacement-with-promises)
- [Asynchronous replacement with callback](#asynchronous-replacement-with-callback)
- [Asynchronous replacement](#asynchronous-replacement)
- [Synchronous replacement](#synchronous-replacement)
- [Return value](#return-value)
- [Counting matches and replacements](#counting-matches-and-replacements)
- [Custom processor](#custom-processor)
- [Advanced usage](#advanced-usage)

@@ -29,4 +25,6 @@ - [Replace a single file or glob](#replace-a-single-file-or-glob)

- [Multiple values with different replacements](#multiple-values-with-different-replacements)
- [Multiple replacements with different options](#multiple-replacements-with-different-options)
- [Using callbacks for `from`](#using-callbacks-for-from)
- [Using callbacks for `to`](#using-callbacks-for-to)
- [Saving to a different file](#saving-to-a-different-file)
- [Ignore a single file or glob](#ignore-a-single-file-or-glob)

@@ -40,3 +38,4 @@ - [Ignore multiple files or globs](#ignore-multiple-files-or-globs)

- [Dry run](#dry-run)
- [File system](#file-system)
- [Using custom processors](#using-custom-processors)
- [Using a custom file system API](#using-a-custom-file-system-api)
- [CLI usage](#cli-usage)

@@ -49,8 +48,5 @@ - [A note on using globs with the CLI](#a-note-on-using-globs-with-the-cli)

```shell
# Using npm, installing to local project
npm i --save replace-in-file
# Using npm
npm i replace-in-file
# Using npm, installing globally for global cli usage
npm i -g replace-in-file
# Using yarn

@@ -60,7 +56,7 @@ yarn add replace-in-file

## Basic usage
### Asynchronous replacement
```js
//Load the library and specify options
const replace = require('replace-in-file');
import {replaceInFile} from 'replace-in-file'
const options = {

@@ -70,49 +66,30 @@ files: 'path/to/file',

to: 'bar',
};
```
}
### Asynchronous replacement with `async`/`await`
```js
try {
const results = await replace(options)
console.log('Replacement results:', results);
const results = await replaceInFile(options)
console.log('Replacement results:', results)
}
catch (error) {
console.error('Error occurred:', error);
console.error('Error occurred:', error)
}
```
### Asynchronous replacement with promises
### Synchronous replacement
```js
replace(options)
.then(results => {
console.log('Replacement results:', results);
})
.catch(error => {
console.error('Error occurred:', error);
});
```
import {replaceInFileSync} from 'replace-in-file'
### Asynchronous replacement with callback
const options = {
files: 'path/to/file',
from: /foo/g,
to: 'bar',
}
```js
replace(options, (error, results) => {
if (error) {
return console.error('Error occurred:', error);
}
console.log('Replacement results:', results);
});
```
### Synchronous replacement
```js
try {
const results = replace.sync(options);
console.log('Replacement results:', results);
const results = replaceInFileSync(options)
console.log('Replacement results:', results)
}
catch (error) {
console.error('Error occurred:', error);
console.error('Error occurred:', error)
}

@@ -131,9 +108,9 @@ ```

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

@@ -162,3 +139,3 @@ // [

.filter(result => result.hasChanged)
.map(result => result.file);
.map(result => result.file)
```

@@ -175,3 +152,3 @@

```js
const results = replace.sync({
const results = replaceInFileSync({
files: 'path/to/files/*.html',

@@ -181,5 +158,5 @@ from: /foo/g,

countMatches: true,
});
})
console.log(results);
console.log(results)

@@ -208,42 +185,2 @@ // [

### Custom processor
For advanced usage where complex processing is needed it's possible to use a callback that will receive content as an argument and should return it processed.
```js
const results = replace.sync({
files: 'path/to/files/*.html',
processor: (input) => input.replace(/foo/g, 'bar'),
});
```
The custom processor will receive the path of the file being processed as a second parameter:
```js
const results = replace.sync({
files: 'path/to/files/*.html',
processor: (input, file) => input.replace(/foo/g, file),
});
```
### Array of custom processors
Passing processor function also supports passing an array of functions that will be executed sequentially
```js
function someProcessingA(input) {
const chapters = input.split('###')
chapters[1] = chapters[1].replace(/foo/g, 'bar')
return chapters.join('###')
}
function someProcessingB(input) {
return input.replace(/foo/g, 'bar')
}
const results = replace.sync({
files: 'path/to/files/*.html',
processor: [someProcessingA, someProcessingB],
});
```
## Advanced usage

@@ -255,3 +192,3 @@

files: 'path/to/file',
};
}
```

@@ -269,3 +206,3 @@

],
};
}
```

@@ -279,3 +216,3 @@

to: 'bar',
};
}
```

@@ -292,3 +229,3 @@

to: 'bar',
};
}
```

@@ -304,3 +241,3 @@

to: 'bar',
};
}
```

@@ -316,5 +253,28 @@

to: ['bar', 'bax'],
};
}
```
### Multiple replacements with different options
There is no direct API in this package to make multiple replacements on different files with different options. However, you can easily accomplish this in your scripts as follows:
```js
const replacements = [
{
files: 'path/to/file1',
from: /foo/g,
to: 'bar',
},
{
files: 'path/to/file2',
from: /bar/g,
to: 'foo',
}
]
await Promise.all(
replacements.map(options => replaceInFile(options))
)
```
### Custom regular expressions

@@ -325,8 +285,8 @@

```js
const str = 'foo';
const regex = new RegExp('^' + str + 'bar', 'i');
const str = 'foo'
const regex = new RegExp('^' + str + 'bar', 'i')
const options = {
from: regex,
to: 'bar',
};
}
```

@@ -342,3 +302,3 @@

to: 'bar',
};
}
```

@@ -354,3 +314,3 @@

to: (match) => match.toLowerCase(),
};
}
```

@@ -365,5 +325,17 @@

to: (...args) => args.pop(),
};
}
```
### Saving to a different file
You can specify a `getTargetFile` config param to modify the target file for saving the new file contents to. For example:
```js
const options = {
files: 'path/to/files/*.html',
getTargetFile: source => `new/path/${source}`,
from: 'foo',
to: 'bar',
}
```
### Ignore a single file or glob

@@ -374,3 +346,3 @@

ignore: 'path/to/ignored/file',
};
}
```

@@ -388,3 +360,3 @@

],
};
}
```

@@ -400,3 +372,3 @@

allowEmptyPaths: true,
};
}
```

@@ -410,3 +382,3 @@

disableGlobs: true,
};
}
```

@@ -425,3 +397,3 @@

},
};
}
```

@@ -440,3 +412,3 @@

encoding: 'utf8',
};
}
```

@@ -450,25 +422,62 @@

dry: true,
};
}
```
### 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.
### Using custom processors
* 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
For advanced usage where complex processing is needed it's possible to use a callback that will receive content as an argument and should return it processed.
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
const results = await replaceInFile({
files: 'path/to/files/*.html',
processor: (input) => input.replace(/foo/g, 'bar'),
})
```
The custom processor will receive the path of the file being processed as a second parameter:
```js
const results = await replaceInFile({
files: 'path/to/files/*.html',
processor: (input, file) => input.replace(/foo/g, file),
})
```
This also supports passing an array of functions that will be executed sequentially
```js
function someProcessingA(input) {
const chapters = input.split('###')
chapters[1] = chapters[1].replace(/foo/g, 'bar')
return chapters.join('###')
}
function someProcessingB(input) {
return input.replace(/foo/g, 'bar')
}
const results = replaceInFileSync({
files: 'path/to/files/*.html',
processor: [someProcessingA, someProcessingB],
})
```
### Using a custom file system API
`replace-in-file` defaults to using `'node:fs/promises'` and `'node:fs'` to provide file reading and write APIs.
You can provide an `fs` or `fsSync` object of your own to switch to a different file system, such as a mock file system for unit tests.
* For the asynchronous APIs, the provided `fs` must provide the `readFile` and `writeFile` methods.
* For the synchronous APIs, the provided `fsSync` must provide the `readFileSync` and `writeFileSync` methods.
Custom `fs` and `fsSync` implementations 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');
readFile: async (file, encoding) => {
console.log(`Reading ${file} with encoding ${encoding}...`)
return 'fake file contents'
},
writeFile: (file, newContents, encoding, callback) => {
console.log(`Writing ${file} with encoding ${encoding}: ${newContents}`);
callback(null);
writeFile: async (file, newContents, encoding) => {
console.log(`Writing ${file} with encoding ${encoding}: ${newContents}`)
},

@@ -480,2 +489,20 @@ },

Or for the sync API:
```js
replaceInFileSync({
from: 'a',
fsSync: {
readFileSync: (file, encoding) => {
console.log(`Reading ${file} with encoding ${encoding}...`)
return 'fake file contents'
},
writeFileSync: (file, newContents, encoding) => {
console.log(`Writing ${file} with encoding ${encoding}: ${newContents}`)
},
},
to: 'b',
})
```
## CLI usage

@@ -485,3 +512,3 @@

replace-in-file from to some/file.js,some/**/glob.js
[--configFile=replace-config.js]
[--configFile=config.json]
[--ignore=ignore/files.js,ignore/**/glob.js]

@@ -510,6 +537,17 @@ [--encoding=utf-8]

The `from` and `to` parameters, as well as the files list, can be omitted if you provide this
information in a configuration file. You can provide a path to a configuration file
(either Javascript or JSON) with the `--configFile` flag. This path will be resolved using
information in a configuration file.
You can provide a path to a configuration file
(JSON) with the `--configFile` flag. This path will be resolved using
Node’s built in `path.resolve()`, so you can pass in an absolute or relative path.
If you are using a configuration file, and you want to use a regular expression for the `from` value, ensure that it starts with a `/`, for example:
```json
{
"from": "/cat/g",
"to": "dog",
}
```
## A note on using globs with the CLI

@@ -520,12 +558,11 @@ When using the CLI, the glob pattern is handled by the operating system. But if you specify the glob pattern in the configuration file, the package will use the glob module from the Node modules, and this can lead to different behaviour despite using the same pattern.

```js
//config.js
module.exports = {
from: /cat/g,
to: 'dog',
};
```json
{
"from": "cat",
"to": "dog",
}
```
```sh
replace-in-file ** --configFile=config.js
replace-in-file ** --configFile=config.json
```

@@ -535,13 +572,12 @@

```js
//config.js
module.exports = {
files: '**',
from: /cat/g,
to: 'dog',
};
```json
{
"files": "**",
"from": "cat",
"to": "dog",
}
```
```sh
replace-in-file --configFile=config.js
replace-in-file --configFile=config.json
```

@@ -552,10 +588,8 @@

```sh
replace-in-file $(ls l {,**/}*) --configFile=config.js
replace-in-file $(ls l {,**/}*) --configFile=config.json
```
## 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.
From version 8.0.0 onwards, this package requires Node 18 or higher. If you need support for older versions of Node, please use a previous version of this package.
From version 5.0.0 onwards, replace in file requires Node 8 or higher. If you need support for Node 6, please use version 4.x.x.
See the [Changelog](CHANGELOG.md) for more information.

@@ -566,2 +600,2 @@

Copyright 2015-2023, Adam Reis, Co-founder at [Hello Club](https://helloclub.com/?source=npm) and [Frello](https://getfrello.com/?source=npm)
Copyright 2015-2024, Adam Reis
declare module 'replace-in-file' {
export function replaceInFile(config: ReplaceInFileConfig & { from?: never, to?: never, processor: ReplaceInFileConfig["processor"] }): Promise<ReplaceResult[]>;
export function replaceInFile(config: ReplaceInFileConfig & { from?: never, to?: never, processor: ReplaceInFileConfig["processor"] }, cb: (error: Error, results: ReplaceResult[]) => void): void;
export function replaceInFile(config: ReplaceInFileConfig & { from: ReplaceInFileConfig["from"], to: ReplaceInFileConfig["to"], processor?: never }): Promise<ReplaceResult[]>;
export function replaceInFile(config: ReplaceInFileConfig & { from: ReplaceInFileConfig["from"], to: ReplaceInFileConfig["to"], processor?: never }, cb: (error: Error, results: ReplaceResult[]) => void): void;

@@ -12,9 +10,6 @@ export default replaceInFile;

export namespace replaceInFile {
export function sync(config: ReplaceInFileConfig): ReplaceResult[];
export function replaceInFileSync(config: ReplaceInFileConfig): ReplaceResult[];
export function replaceInFile(config: ReplaceInFileConfig): Promise<ReplaceResult[]>;
export function replaceInFile(config: ReplaceInFileConfig, cb: (error: Error, results: ReplaceResult[]) => void): void;
}
export function sync(config: ReplaceInFileConfig): ReplaceResult[];
export function replaceInFileSync(config: ReplaceInFileConfig): ReplaceResult[];

@@ -21,0 +16,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc