FIX: Escape regex symbols when replaceText is called for ProseMirror (#32280)

When we do replaceText in the ProseMirror TextManipulation lib,
we are creating a regex for the provided markdown. However this markdown
can have things like * (which is valid for a markdown list), which also
doubles as a regex symbol. We can escape the markdown provided to
the regex first to fix the issue.
This commit is contained in:
Martin Brennan
2025-04-15 14:04:33 +10:00
committed by GitHub
parent 077649fafd
commit 7a6006f7aa
2 changed files with 34 additions and 1 deletions
@@ -7,6 +7,7 @@ import { Slice } from "prosemirror-model";
import { liftListItem, sinkListItem } from "prosemirror-schema-list";
import { TextSelection } from "prosemirror-state";
import { bind } from "discourse/lib/decorators";
import escapeRegExp from "discourse/lib/escape-regexp";
import { i18n } from "discourse-i18n";
/**
@@ -278,7 +279,7 @@ export default class ProsemirrorTextManipulation {
const markdown = this.convertToMarkdown(this.view.state.doc);
const regex = opts.regex || new RegExp(oldValue, "g");
const regex = opts.regex || new RegExp(escapeRegExp(oldValue), "g");
const index = opts.index || 0;
let matchCount = 0;
@@ -1314,3 +1314,35 @@ third line`
}
})();
});
module("Integration | Component | d-editor | rich editor", function (hooks) {
setupRenderingTest(hooks);
test("replaceText escapes markdown symbols that could be regexp symbols", async function (assert) {
this.siteSettings.rich_editor = true;
const initialValue = "Hello\n\n* world\n* am am here $";
withPluginApi("2.1.0", (api) => {
api.onToolbarCreate((toolbar) => {
toolbar.addButton({
id: "replace-text",
icon: "xmark",
group: "extras",
action: () => {
toolbar.context
.newToolbarEvent()
.replaceText(initialValue, "goodbye");
},
condition: () => true,
});
});
});
await render(<template><DEditor @value={{initialValue}} /></template>);
await click(".composer-toggle-switch");
await click("button.replace-text");
assert.dom(".ProseMirror p").hasText("goodbye");
});
});