Skip to content

Commit

Permalink
feat: support replace method (#203)
Browse files Browse the repository at this point in the history
  • Loading branch information
antfu authored Mar 3, 2022
1 parent 62d6e85 commit cd74ea2
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 0 deletions.
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,24 @@ Same as `s.appendLeft(...)`, except that the inserted content will go *before* a

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

### s.replace( regexp, substitution )

String replacement with RegExp or string, a replacer function is also supported. Returns `this`.

```ts
import MagicString from 'magic-string'

const s = new MagicString(source)

s.replace(foo, 'bar')
s.replace(/foo/g, 'bar')
s.replace(/(\w)(\d+)/g, (_, $1, $2) => $1.toUpperCase() + $2)
```

The differences from [`String.replace`]((https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace)):
- It will always match against the **original string**
- It mutates the magic string state (use `.clone()` to be immutable)

### s.remove( start, end )

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`.
Expand Down
4 changes: 4 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,10 @@ export default class MagicString {
* Removes empty lines from the start and end.
*/
trimLines(): MagicString;
/**
* String replacement with RegExp or string.
*/
replace(regex: RegExp | string, replacement: string | ((substring: string, ...args: any[]) => string)): MagicString;

lastChar(): string;
lastLine(): string;
Expand Down
42 changes: 42 additions & 0 deletions src/MagicString.js
Original file line number Diff line number Diff line change
Expand Up @@ -712,4 +712,46 @@ export default class MagicString {
this.trimStartAborted(charType);
return this;
}

replace(searchValue, replacement) {
function getReplacement(match) {
if (typeof replacement === 'string') {
return replacement.replace(/\$(\$|&|\d+)/g, (_, i) => {
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace#specifying_a_string_as_a_parameter
if (i === '$')
return '$';
if (i === '&')
return match[0];
const num = +i;
if (num < match.length)
return match[+i];
return `$${i}`;
});
}
else {
return replacement(...match);
}
}
function matchAll(re, str) {
let match;
const matches = [];
while (match = re.exec(str)) {
matches.push(match);
}
return matches;
}
if (typeof searchValue !== 'string' && searchValue.global) {
const matches = matchAll(searchValue, this.original);
matches.forEach((match) => {
if (match.index != null)
this.overwrite(match.index, match.index + match[0].length, getReplacement(match));
});
}
else {
const match = this.original.match(searchValue);
if (match && match.index != null)
this.overwrite(match.index, match.index + match[0].length, getReplacement(match));
}
return this;
}
}
36 changes: 36 additions & 0 deletions test/MagicString.js
Original file line number Diff line number Diff line change
Expand Up @@ -1277,4 +1277,40 @@ describe('MagicString', () => {
assert.equal(s.lastLine(), '//lastline');
});
});

describe('replace', () => {
it('works with string replace', () => {
const code = '1 2 1 2';
const s = new MagicString(code);

s.replace('2', '3');

assert.strictEqual(s.toString(), '1 3 1 2');
});

it('works with global regex replace', () => {
const s = new MagicString('1 2 3 4 a b c');

s.replace(/(\d)/g, 'xx$1$10');

assert.strictEqual(s.toString(), 'xx1$10 xx2$10 xx3$10 xx4$10 a b c');
});

it('works with global regex replace $$', () => {
const s = new MagicString('1 2 3 4 a b c');

s.replace(/(\d)/g, '$$');

assert.strictEqual(s.toString(),'$ $ $ $ a b c');
});

it('works with global regex replace function', () => {
const code = 'hey this is magic';
const s = new MagicString(code);

s.replace(/(\w)(\w+)/g, (_, $1, $2) => `${$1.toUpperCase()}${$2}`);

assert.strictEqual(s.toString(),'Hey This Is Magic');
});
});
});

0 comments on commit cd74ea2

Please sign in to comment.