diff --git a/src/client.ts b/src/client.ts index 61828a44b..475ee77f0 100644 --- a/src/client.ts +++ b/src/client.ts @@ -1234,7 +1234,7 @@ export class MatrixClient extends TypedEventEmitter(); // The pushprocessor caches useful things, so keep one and re-use it - protected pushProcessor = new PushProcessor(this); + public readonly pushProcessor = new PushProcessor(this); // Promise to a response of the server's /versions response // TODO: This should expire: https://github.com/matrix-org/matrix-js-sdk/issues/1020 diff --git a/src/pushprocessor.ts b/src/pushprocessor.ts index 87e8b0ae7..c0cdb3182 100644 --- a/src/pushprocessor.ts +++ b/src/pushprocessor.ts @@ -308,6 +308,26 @@ export class PushProcessor { return newRules; } + /** + * Create a RegExp object for the given glob pattern with a single capture group around the pattern itself, caching the result. + * No cache invalidation is present currently, + * as this will be inherently bounded to the size of the user's own push rules. + * @param pattern - the glob pattern to convert to a RegExp + * @param alignToWordBoundary - whether to align the pattern to word boundaries, as specified for `content.body` matches + * @param flags - the flags to pass to the RegExp constructor, defaults to case-insensitive + */ + public static getPushRuleGlobRegex(pattern: string, alignToWordBoundary = false, flags = "i"): RegExp { + const [prefix, suffix] = alignToWordBoundary ? ["(^|\\W)", "(\\W|$)"] : ["^", "$"]; + + if (!PushProcessor.cachedGlobToRegex[pattern]) { + PushProcessor.cachedGlobToRegex[pattern] = new RegExp( + prefix + "(" + globToRegexp(pattern) + ")" + suffix, + flags, + ); + } + return PushProcessor.cachedGlobToRegex[pattern]; + } + /** * Pre-caches the parsed keys for push rules and cleans out any obsolete cache * entries. Should be called after push rules are updated. @@ -567,11 +587,9 @@ export class PushProcessor { return false; } - const regex = - cond.key === "content.body" - ? this.createCachedRegex("(^|\\W)", cond.pattern, "(\\W|$)") - : this.createCachedRegex("^", cond.pattern, "$"); - + // Align to word boundary on `content.body` matches, whole string otherwise + // https://spec.matrix.org/v1.13/client-server-api/#conditions-1 + const regex = PushProcessor.getPushRuleGlobRegex(cond.pattern, cond.key === "content.body"); return !!val.match(regex); } @@ -621,17 +639,6 @@ export class PushProcessor { ); } - private createCachedRegex(prefix: string, glob: string, suffix: string): RegExp { - if (PushProcessor.cachedGlobToRegex[glob]) { - return PushProcessor.cachedGlobToRegex[glob]; - } - PushProcessor.cachedGlobToRegex[glob] = new RegExp( - prefix + globToRegexp(glob) + suffix, - "i", // Case insensitive - ); - return PushProcessor.cachedGlobToRegex[glob]; - } - /** * Parse the key into the separate fields to search by splitting on * unescaped ".", and then removing any escape characters.