From a1b857cc5a77af1ffae73355d9c467dce058e427 Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Wed, 3 Apr 2024 23:51:19 +0200 Subject: [PATCH] perf: avoid create uncessary overrides for `replace` --- README.md | 2 +- package-lock.json | 2 +- package.json | 1 + src/MagicString.js | 34 ++++++++++++++++++++++------------ test/MagicString.js | 19 +++++++++++++++++++ 5 files changed, 44 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 995565f..6ef18c5 100644 --- a/README.md +++ b/README.md @@ -193,7 +193,7 @@ The differences from [`String.replace`]((https://developer.mozilla.org/en-US/doc ### s.replaceAll( regexpOrString, substitution ) Same as `s.replace`, but replace all matched strings instead of just one. -If `substitution` is a regex, then it must have the global (`g`) flag set, or a `TypeError` is thrown. Matches the behavior of the bultin [`String.property.replaceAll`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replaceAll). +If `substitution` is a regex, then it must have the global (`g`) flag set, or a `TypeError` is thrown. Matches the behavior of the builtin [`String.property.replaceAll`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replaceAll). ### s.remove( start, end ) diff --git a/package-lock.json b/package-lock.json index f52a3e0..e491793 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,7 @@ "packages": { "": { "name": "magic-string", - "version": "0.30.7", + "version": "0.30.8", "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" diff --git a/package.json b/package.json index f8fc80c..e67fc29 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s", "format": "prettier --single-quote --print-width 100 --use-tabs --write src/*.js src/**/*.js", "lint": "eslint src test && publint", + "lint:fix": "eslint src test --fix", "prepare": "npm run build", "prepublishOnly": "npm run lint && rm -rf dist && npm test", "release": "bumpp -x \"npm run changelog\" --all --commit --tag --push && npm publish", diff --git a/src/MagicString.js b/src/MagicString.js index 7e24e35..49c05cf 100644 --- a/src/MagicString.js +++ b/src/MagicString.js @@ -797,21 +797,29 @@ export default class MagicString { if (searchValue.global) { const matches = matchAll(searchValue, this.original); matches.forEach((match) => { - if (match.index != null) + if (match.index != null) { + const replacement = getReplacement(match, this.original); + if (replacement !== match[0]) { + this.overwrite( + match.index, + match.index + match[0].length, + replacement + ); + } + } + }); + } else { + const match = this.original.match(searchValue); + if (match && match.index != null) { + const replacement = getReplacement(match, this.original); + if (replacement !== match[0]) { this.overwrite( match.index, match.index + match[0].length, - getReplacement(match, this.original), + replacement ); - }); - } else { - const match = this.original.match(searchValue); - if (match && match.index != null) - this.overwrite( - match.index, - match.index + match[0].length, - getReplacement(match, this.original), - ); + } + } } return this; } @@ -843,7 +851,9 @@ export default class MagicString { index !== -1; index = original.indexOf(string, index + stringLength) ) { - this.overwrite(index, index + stringLength, replacement); + const previous = original.slice(index, index + stringLength); + if (previous !== replacement) + this.overwrite(index, index + stringLength, replacement); } return this; diff --git a/test/MagicString.js b/test/MagicString.js index 190cab9..a7d881a 100644 --- a/test/MagicString.js +++ b/test/MagicString.js @@ -1758,6 +1758,25 @@ describe('MagicString', () => { new MagicString(code).replace(regex, replacer).toString() ); }); + + it('should ignore non-changed replacements', () => { + const code = 'a12bc345#$*%'; + const matched = []; + + const s = new MagicString(code); + + assert.strictEqual(s.firstChunk, s.lastChunk); + + s.replace(/(\d)/g, (match, $1) => { + matched.push($1); + return match; + }); + + assert.strictEqual(s.toString(), code); + assert.deepStrictEqual(matched, ['1', '2', '3', '4', '5']); + + assert.strictEqual(s.firstChunk, s.lastChunk); + }); }); describe('replaceAll', () => {