Skip to content

Commit 5369cd7

Browse files
boneskullsindresorhus
authored andcommitted
Add support for globs (#4)
1 parent 89a7fb1 commit 5369cd7

File tree

5 files changed

+44
-4
lines changed

5 files changed

+44
-4
lines changed

api.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@ const fs = require('fs');
55
const writeFileAtomic = require('write-file-atomic');
66
const escapeStringRegexp = require('escape-string-regexp');
77
const arrify = require('arrify');
8+
const globby = require('globby');
89

910
const readFile = promisify(fs.readFile);
1011

1112
// TODO(sindresorhus): I will extract this to a separate module at some point when it's more mature.
1213
// `find` is expected to be `Array<string | RegExp>`
1314
// The `ignoreCase` option overrides the `i` flag for regexes in `find`
14-
module.exports = async (filePaths, {find, replacement, ignoreCase} = {}) => {
15+
module.exports = async (filePaths, {find, replacement, ignoreCase, glob} = {}) => {
1516
filePaths = arrify(filePaths);
1617

1718
if (filePaths.length === 0) {
@@ -32,8 +33,7 @@ module.exports = async (filePaths, {find, replacement, ignoreCase} = {}) => {
3233
.replace(/\\r/g, '\r')
3334
.replace(/\\t/g, '\t');
3435

35-
// Deduplicate
36-
filePaths = [...new Set(filePaths.map(filePath => path.resolve(filePath)))];
36+
filePaths = glob ? await globby(filePaths) : [...new Set(filePaths.map(filePath => path.resolve(filePath)))];
3737

3838
find = find.map(element => {
3939
const iFlag = ignoreCase ? 'i' : '';

cli.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@ const cli = meow(`
1313
--string String to find (Can be set multiple times)
1414
--replacement Replacement string (Required)
1515
--ignore-case Search case-insensitively
16+
--no-glob Disable globbing
1617
1718
Examples
1819
$ replace-in-files --string='horse' --regex='unicorn|rainbow' --replacement='🦄' foo.md
1920
$ replace-in-files --regex='v\\d+\\.\\d+\\.\\d+' --replacement=v$npm_package_version foo.css
21+
$ replace-in-files --string='blob' --replacement='blog' 'some/**/[gb]lob/*' '!some/glob/foo'
2022
2123
You can use the same replacement patterns as with \`String#replace()\`, like \`$&\`.
2224
`, {
@@ -33,6 +35,10 @@ const cli = meow(`
3335
ignoreCase: {
3436
type: 'boolean',
3537
default: false
38+
},
39+
glob: {
40+
type: 'boolean',
41+
default: true
3642
}
3743
}
3844
});
@@ -60,6 +66,7 @@ if (cli.flags.replacement === undefined) {
6066
...arrify(cli.flags.regex).map(regexString => new RegExp(regexString, 'g'))
6167
],
6268
replacement: cli.flags.replacement,
63-
ignoreCase: cli.flags.ignoreCase
69+
ignoreCase: cli.flags.ignoreCase,
70+
glob: cli.flags.glob
6471
});
6572
})();

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
"dependencies": {
4444
"arrify": "^2.0.1",
4545
"escape-string-regexp": "^2.0.0",
46+
"globby": "^10.0.1",
4647
"meow": "^5.0.0",
4748
"write-file-atomic": "^3.0.0"
4849
},

readme.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,12 @@ $ replace-in-files --help
2323
--string String to find (Can be set multiple times)
2424
--replacement Replacement string (Required)
2525
--ignore-case Search case-insensitively
26+
--no-glob Disable globbing
2627
2728
Examples
2829
$ replace-in-files --string='horse' --regex='unicorn|rainbow' --replacement='🦄' foo.md
2930
$ replace-in-files --regex='v\d+\.\d+\.\d+' --replacement=v$npm_package_version foo.css
31+
$ replace-in-files --string='blob' --replacement='blog' 'some/**/[gb]lob/*' '!some/glob/foo'
3032
3133
You can use the same replacement patterns as with `String#replace()`, like `$&`.
3234
```

test.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import fs from 'fs';
2+
import os from 'os';
3+
import path from 'path';
24
import test from 'ava';
35
import execa from 'execa';
46
import tempWrite from 'temp-write';
@@ -34,3 +36,31 @@ test('multiple newlines and tabs', async t => {
3436
await execa('./cli.js', ['--string=,', '--replacement=\\n\\n\\t\\r', filePath]);
3537
t.is(fs.readFileSync(filePath, 'utf8'), 'a\n\n\t\rb\n\n\t\rc');
3638
});
39+
40+
test('globs', async t => {
41+
const filePaths = [await tempWrite('foo bar foo', 'a.glob'), await tempWrite('foo bar foo', 'b.glob')];
42+
const tmpdir = os.tmpdir();
43+
44+
await execa('./cli.js', ['--string=bar', '--replacement=foo', path.join(tmpdir, '*', '*.glob')]);
45+
t.is(fs.readFileSync(filePaths[0], 'utf8'), 'foo foo foo');
46+
t.is(fs.readFileSync(filePaths[1], 'utf8'), 'foo foo foo');
47+
});
48+
49+
test('no globs', async t => {
50+
const filePaths = [await tempWrite('foo bar foo', '*.glob'), await tempWrite('foo bar foo', 'foo.glob')];
51+
const dirnames = filePaths.map(filePath => path.dirname(filePath));
52+
53+
await t.throwsAsync(
54+
execa('./cli.js', [
55+
'--string=bar',
56+
'--replacement=foo',
57+
'--no-glob',
58+
path.join(dirnames[0], '*.glob'),
59+
path.join(dirnames[1], '*.glob')
60+
]),
61+
{
62+
code: 1,
63+
message: /ENOENT/
64+
}
65+
);
66+
});

0 commit comments

Comments
 (0)