mirror of
https://github.com/discourse/discourse.git
synced 2025-05-23 17:01:09 +08:00
PERF: Avoid excessive object creations in watched words (#27354)
Inline the helper functions, avoid creating and then immediately destructuring arrays, use complete strings instead of string interpolation, Map instead of a pojo.
This commit is contained in:
@ -1,9 +1,5 @@
|
|||||||
import Component from "@glimmer/component";
|
import Component from "@glimmer/component";
|
||||||
import { tracked } from "@glimmer/tracking";
|
import { tracked } from "@glimmer/tracking";
|
||||||
import {
|
|
||||||
createWatchedWordRegExp,
|
|
||||||
toWatchedWord,
|
|
||||||
} from "discourse-common/utils/watched-words";
|
|
||||||
|
|
||||||
export default class WatchedWordTest extends Component {
|
export default class WatchedWordTest extends Component {
|
||||||
@tracked value;
|
@tracked value;
|
||||||
@ -31,7 +27,10 @@ export default class WatchedWordTest extends Component {
|
|||||||
if (this.isReplace || this.isLink) {
|
if (this.isReplace || this.isLink) {
|
||||||
const matches = [];
|
const matches = [];
|
||||||
this.args.model.watchedWord.words.forEach((word) => {
|
this.args.model.watchedWord.words.forEach((word) => {
|
||||||
const regexp = createWatchedWordRegExp(word);
|
const regexp = new RegExp(
|
||||||
|
word.regexp,
|
||||||
|
word.case_sensitive ? "gu" : "gui"
|
||||||
|
);
|
||||||
let match;
|
let match;
|
||||||
|
|
||||||
while ((match = regexp.exec(this.value)) !== null) {
|
while ((match = regexp.exec(this.value)) !== null) {
|
||||||
@ -42,38 +41,44 @@ export default class WatchedWordTest extends Component {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
return matches;
|
return matches;
|
||||||
} else if (this.isTag) {
|
}
|
||||||
const matches = {};
|
|
||||||
|
if (this.isTag) {
|
||||||
|
const matches = new Map();
|
||||||
this.args.model.watchedWord.words.forEach((word) => {
|
this.args.model.watchedWord.words.forEach((word) => {
|
||||||
const regexp = createWatchedWordRegExp(word);
|
const regexp = new RegExp(
|
||||||
|
word.regexp,
|
||||||
|
word.case_sensitive ? "gu" : "gui"
|
||||||
|
);
|
||||||
let match;
|
let match;
|
||||||
|
|
||||||
while ((match = regexp.exec(this.value)) !== null) {
|
while ((match = regexp.exec(this.value)) !== null) {
|
||||||
if (!matches[match[1]]) {
|
if (!matches.has(match[1])) {
|
||||||
matches[match[1]] = new Set();
|
matches.set(match[1], new Set());
|
||||||
}
|
}
|
||||||
|
|
||||||
let tags = matches[match[1]];
|
const tags = matches.get(match[1]);
|
||||||
word.replacement.split(",").forEach((tag) => {
|
word.replacement.split(",").forEach((tag) => tags.add(tag));
|
||||||
tags.add(tag);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return Object.entries(matches).map((entry) => ({
|
return Array.from(matches, ([match, tagsSet]) => ({
|
||||||
match: entry[0],
|
match,
|
||||||
tags: Array.from(entry[1]),
|
tags: Array.from(tagsSet),
|
||||||
}));
|
}));
|
||||||
} else {
|
}
|
||||||
let matches = [];
|
|
||||||
this.args.model.watchedWord.compiledRegularExpression.forEach(
|
let matches = [];
|
||||||
(regexp) => {
|
this.args.model.watchedWord.compiledRegularExpression.forEach((entry) => {
|
||||||
const wordRegexp = createWatchedWordRegExp(toWatchedWord(regexp));
|
const [regexp, options] = Object.entries(entry)[0];
|
||||||
matches.push(...(this.value.match(wordRegexp) || []));
|
const wordRegexp = new RegExp(
|
||||||
}
|
regexp,
|
||||||
|
options.case_sensitive ? "gu" : "gui"
|
||||||
);
|
);
|
||||||
|
|
||||||
return matches;
|
matches.push(...(this.value.match(wordRegexp) || []));
|
||||||
}
|
});
|
||||||
|
|
||||||
|
return matches;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
export function createWatchedWordRegExp(word) {
|
|
||||||
const caseFlag = word.case_sensitive ? "" : "i";
|
|
||||||
return new RegExp(word.regexp, `${caseFlag}gu`);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function toWatchedWord(regexp) {
|
|
||||||
const [[regexpString, options]] = Object.entries(regexp);
|
|
||||||
return { ...options, regexp: regexpString };
|
|
||||||
}
|
|
@ -196,7 +196,7 @@ function applyEmoji(
|
|||||||
enableShortcuts,
|
enableShortcuts,
|
||||||
inlineEmoji,
|
inlineEmoji,
|
||||||
customEmojiTranslation,
|
customEmojiTranslation,
|
||||||
watchedWordsReplacer,
|
watchedWordsReplace,
|
||||||
emojiDenyList
|
emojiDenyList
|
||||||
) {
|
) {
|
||||||
let result = null;
|
let result = null;
|
||||||
@ -206,19 +206,16 @@ function applyEmoji(
|
|||||||
content = emojiUnicodeReplacer(content);
|
content = emojiUnicodeReplacer(content);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (watchedWordsReplacer) {
|
if (content && watchedWordsReplace) {
|
||||||
const watchedWordRegex = Object.keys(watchedWordsReplacer);
|
Object.entries(watchedWordsReplace).forEach(([regexpString, options]) => {
|
||||||
|
if (content.match(regexpString)) {
|
||||||
watchedWordRegex.forEach((watchedWord) => {
|
const regex = new RegExp(regexpString, "g");
|
||||||
if (content?.match(watchedWord)) {
|
|
||||||
const regex = new RegExp(watchedWord, "g");
|
|
||||||
const matches = content.match(regex);
|
const matches = content.match(regex);
|
||||||
const replacement = watchedWordsReplacer[watchedWord].replacement;
|
|
||||||
|
|
||||||
matches.forEach(() => {
|
matches.forEach(() => {
|
||||||
const matchingRegex = regex.exec(content);
|
const matchingRegex = regex.exec(content);
|
||||||
if (matchingRegex) {
|
if (matchingRegex) {
|
||||||
content = content.replace(matchingRegex[1], replacement);
|
content = content.replace(matchingRegex[1], options.replacement);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -226,9 +223,9 @@ function applyEmoji(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// prevent denied emoji and aliases from being rendered
|
// prevent denied emoji and aliases from being rendered
|
||||||
if (emojiDenyList?.length > 0) {
|
if (content && emojiDenyList?.length > 0) {
|
||||||
emojiDenyList.forEach((emoji) => {
|
emojiDenyList.forEach((emoji) => {
|
||||||
if (content?.match(emoji)) {
|
if (content.match(emoji)) {
|
||||||
const regex = new RegExp(`:${emoji}:`, "g");
|
const regex = new RegExp(`:${emoji}:`, "g");
|
||||||
content = content.replace(regex, "");
|
content = content.replace(regex, "");
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,3 @@
|
|||||||
import {
|
|
||||||
createWatchedWordRegExp,
|
|
||||||
toWatchedWord,
|
|
||||||
} from "discourse-common/utils/watched-words";
|
|
||||||
|
|
||||||
const MAX_MATCHES = 100;
|
const MAX_MATCHES = 100;
|
||||||
|
|
||||||
function isLinkOpen(str) {
|
function isLinkOpen(str) {
|
||||||
@ -59,11 +54,12 @@ export function setup(helper) {
|
|||||||
if (md.options.discourse.watchedWordsReplace) {
|
if (md.options.discourse.watchedWordsReplace) {
|
||||||
Object.entries(md.options.discourse.watchedWordsReplace).forEach(
|
Object.entries(md.options.discourse.watchedWordsReplace).forEach(
|
||||||
([regexpString, options]) => {
|
([regexpString, options]) => {
|
||||||
const word = toWatchedWord({ [regexpString]: options });
|
|
||||||
|
|
||||||
matchers.push({
|
matchers.push({
|
||||||
word: new RegExp(options.regexp, options.case_sensitive ? "" : "i"),
|
word: new RegExp(options.regexp, options.case_sensitive ? "" : "i"),
|
||||||
pattern: createWatchedWordRegExp(word),
|
pattern: new RegExp(
|
||||||
|
regexpString,
|
||||||
|
options.case_sensitive ? "gu" : "gui"
|
||||||
|
),
|
||||||
replacement: options.replacement,
|
replacement: options.replacement,
|
||||||
link: false,
|
link: false,
|
||||||
html: options.html,
|
html: options.html,
|
||||||
@ -75,11 +71,12 @@ export function setup(helper) {
|
|||||||
if (md.options.discourse.watchedWordsLink) {
|
if (md.options.discourse.watchedWordsLink) {
|
||||||
Object.entries(md.options.discourse.watchedWordsLink).forEach(
|
Object.entries(md.options.discourse.watchedWordsLink).forEach(
|
||||||
([regexpString, options]) => {
|
([regexpString, options]) => {
|
||||||
const word = toWatchedWord({ [regexpString]: options });
|
|
||||||
|
|
||||||
matchers.push({
|
matchers.push({
|
||||||
word: new RegExp(options.regexp, options.case_sensitive ? "" : "i"),
|
word: new RegExp(options.regexp, options.case_sensitive ? "" : "i"),
|
||||||
pattern: createWatchedWordRegExp(word),
|
pattern: new RegExp(
|
||||||
|
regexpString,
|
||||||
|
options.case_sensitive ? "gu" : "gui"
|
||||||
|
),
|
||||||
replacement: options.replacement,
|
replacement: options.replacement,
|
||||||
link: true,
|
link: true,
|
||||||
});
|
});
|
||||||
|
@ -1,13 +1,8 @@
|
|||||||
import {
|
export function censorFn(regexpList, replacementLetter = "■") {
|
||||||
createWatchedWordRegExp,
|
|
||||||
toWatchedWord,
|
|
||||||
} from "discourse-common/utils/watched-words";
|
|
||||||
|
|
||||||
export function censorFn(regexpList, replacementLetter) {
|
|
||||||
if (regexpList?.length) {
|
if (regexpList?.length) {
|
||||||
replacementLetter = replacementLetter || "■";
|
const censorRegexps = regexpList.map((entry) => {
|
||||||
let censorRegexps = regexpList.map((regexp) => {
|
const [regexp, options] = Object.entries(entry)[0];
|
||||||
return createWatchedWordRegExp(toWatchedWord(regexp));
|
return new RegExp(regexp, options.case_sensitive ? "gu" : "gui");
|
||||||
});
|
});
|
||||||
|
|
||||||
return function (text) {
|
return function (text) {
|
||||||
|
@ -91,7 +91,6 @@ module PrettyText
|
|||||||
discourse-common/addon/lib/deprecated
|
discourse-common/addon/lib/deprecated
|
||||||
discourse-common/addon/lib/escape
|
discourse-common/addon/lib/escape
|
||||||
discourse-common/addon/lib/avatar-utils
|
discourse-common/addon/lib/avatar-utils
|
||||||
discourse-common/addon/utils/watched-words
|
|
||||||
discourse/app/lib/to-markdown
|
discourse/app/lib/to-markdown
|
||||||
discourse/app/static/markdown-it/features
|
discourse/app/static/markdown-it/features
|
||||||
].each do |f|
|
].each do |f|
|
||||||
|
Reference in New Issue
Block a user