Skip to content

Commit cd74ea2

Browse files
authored
feat: support replace method (#203)
1 parent 62d6e85 commit cd74ea2

4 files changed

Lines changed: 100 additions & 0 deletions

File tree

README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,24 @@ Same as `s.appendLeft(...)`, except that the inserted content will go *before* a
161161

162162
Same as `s.appendRight(...)`, except that the inserted content will go *before* any previous appends or prepends at `index`
163163

164+
### s.replace( regexp, substitution )
165+
166+
String replacement with RegExp or string, a replacer function is also supported. Returns `this`.
167+
168+
```ts
169+
import MagicString from 'magic-string'
170+
171+
const s = new MagicString(source)
172+
173+
s.replace(foo, 'bar')
174+
s.replace(/foo/g, 'bar')
175+
s.replace(/(\w)(\d+)/g, (_, $1, $2) => $1.toUpperCase() + $2)
176+
```
177+
178+
The differences from [`String.replace`]((https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace)):
179+
- It will always match against the **original string**
180+
- It mutates the magic string state (use `.clone()` to be immutable)
181+
164182
### s.remove( start, end )
165183

166184
Removes the characters from `start` to `end` (of the original string, **not** the generated string). Removing the same content twice, or making removals that partially overlap, will cause an error. Returns `this`.

index.d.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,10 @@ export default class MagicString {
204204
* Removes empty lines from the start and end.
205205
*/
206206
trimLines(): MagicString;
207+
/**
208+
* String replacement with RegExp or string.
209+
*/
210+
replace(regex: RegExp | string, replacement: string | ((substring: string, ...args: any[]) => string)): MagicString;
207211

208212
lastChar(): string;
209213
lastLine(): string;

src/MagicString.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -712,4 +712,46 @@ export default class MagicString {
712712
this.trimStartAborted(charType);
713713
return this;
714714
}
715+
716+
replace(searchValue, replacement) {
717+
function getReplacement(match) {
718+
if (typeof replacement === 'string') {
719+
return replacement.replace(/\$(\$|&|\d+)/g, (_, i) => {
720+
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace#specifying_a_string_as_a_parameter
721+
if (i === '$')
722+
return '$';
723+
if (i === '&')
724+
return match[0];
725+
const num = +i;
726+
if (num < match.length)
727+
return match[+i];
728+
return `$${i}`;
729+
});
730+
}
731+
else {
732+
return replacement(...match);
733+
}
734+
}
735+
function matchAll(re, str) {
736+
let match;
737+
const matches = [];
738+
while (match = re.exec(str)) {
739+
matches.push(match);
740+
}
741+
return matches;
742+
}
743+
if (typeof searchValue !== 'string' && searchValue.global) {
744+
const matches = matchAll(searchValue, this.original);
745+
matches.forEach((match) => {
746+
if (match.index != null)
747+
this.overwrite(match.index, match.index + match[0].length, getReplacement(match));
748+
});
749+
}
750+
else {
751+
const match = this.original.match(searchValue);
752+
if (match && match.index != null)
753+
this.overwrite(match.index, match.index + match[0].length, getReplacement(match));
754+
}
755+
return this;
756+
}
715757
}

test/MagicString.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1277,4 +1277,40 @@ describe('MagicString', () => {
12771277
assert.equal(s.lastLine(), '//lastline');
12781278
});
12791279
});
1280+
1281+
describe('replace', () => {
1282+
it('works with string replace', () => {
1283+
const code = '1 2 1 2';
1284+
const s = new MagicString(code);
1285+
1286+
s.replace('2', '3');
1287+
1288+
assert.strictEqual(s.toString(), '1 3 1 2');
1289+
});
1290+
1291+
it('works with global regex replace', () => {
1292+
const s = new MagicString('1 2 3 4 a b c');
1293+
1294+
s.replace(/(\d)/g, 'xx$1$10');
1295+
1296+
assert.strictEqual(s.toString(), 'xx1$10 xx2$10 xx3$10 xx4$10 a b c');
1297+
});
1298+
1299+
it('works with global regex replace $$', () => {
1300+
const s = new MagicString('1 2 3 4 a b c');
1301+
1302+
s.replace(/(\d)/g, '$$');
1303+
1304+
assert.strictEqual(s.toString(),'$ $ $ $ a b c');
1305+
});
1306+
1307+
it('works with global regex replace function', () => {
1308+
const code = 'hey this is magic';
1309+
const s = new MagicString(code);
1310+
1311+
s.replace(/(\w)(\w+)/g, (_, $1, $2) => `${$1.toUpperCase()}${$2}`);
1312+
1313+
assert.strictEqual(s.toString(),'Hey This Is Magic');
1314+
});
1315+
});
12801316
});

0 commit comments

Comments
 (0)