/
githubmirror
/
zulip
Обзор
Документация
Войти
/
githubmirror
/
zulip
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
10.4
web/src/linkifiers.ts
110 строк
4 KB
Abhay Upadhyay
settings: Validate candidate linkifier before sending to server.
13 фев 2025, 21:07
13 фев 2025, 21:07
51a4ed6
Код
Авторство
О чём код?
import * as url_template_lib from "url-template"; import type {z} from "zod"; import * as blueslip from "./blueslip.ts"; import type {realm_linkifier_schema} from "./state_data.ts"; type LinkifierMap = Map< RegExp, {url_template: url_template_lib.Template; group_number_to_name: Record<number, string>} >; const linkifier_map: LinkifierMap = new Map(); type Linkifier = z.output<typeof realm_linkifier_schema>; export function get_linkifier_map(): LinkifierMap { return linkifier_map; } export function python_to_js_linkifier( pattern: string, url: string, ): [RegExp | null, url_template_lib.Template, Record<number, string>] { // Converts a python named-group regex to a javascript-compatible numbered // group regex... with a regex! const named_group_re = /\(?P<([^>]+?)>/g; let match = named_group_re.exec(pattern); let current_group = 1; const group_number_to_name: Record<number, string> = {}; while (match) { const name = match[1]!; // Replace named group with regular matching group pattern = pattern.replace("(?P<" + name + ">", "("); // Map numbered reference to named reference for template expansion group_number_to_name[current_group] = name; // Reset the RegExp state named_group_re.lastIndex = 0; match = named_group_re.exec(pattern); current_group += 1; } // Convert any python in-regex flags to RegExp flags let js_flags = "g"; const inline_flag_re = /\(\?([Limsux]+)\)/; match = inline_flag_re.exec(pattern); // JS regexes only support i (case insensitivity) and m (multiline) // flags, so keep those and ignore the rest if (match) { const py_flags = match[1]!; for (const flag of py_flags) { if ("im".includes(flag)) { js_flags += flag; } } pattern = pattern.replace(inline_flag_re, ""); } // Ideally we should have been checking that linkifiers // begin with certain characters but since there is no // support for negative lookbehind in javascript, we check // for this condition in `contains_backend_only_syntax()` // function. If the condition is satisfied then the message // is rendered locally, otherwise, we return false there and // message is rendered on the backend which has proper support // for negative lookbehind. pattern = pattern + /(?!\w)/.source; let final_regex = null; try { final_regex = new RegExp(pattern, js_flags); } catch (error) { // We have an error computing the generated regex syntax. // We'll ignore this linkifier for now, but log this // failure for debugging later. if (error instanceof SyntaxError) { blueslip.error("python_to_js_linkifier failure!", {pattern}, error); } else { // Don't swallow any other (unexpected) exceptions. /* istanbul ignore next */ throw error; } } const url_template = url_template_lib.parseTemplate(url); return [final_regex, url_template, group_number_to_name]; } export function update_linkifier_rules(linkifiers: Linkifier[]): void { linkifier_map.clear(); for (const linkifier of linkifiers) { const [regex, url_template, group_number_to_name] = python_to_js_linkifier( linkifier.pattern, linkifier.url_template, ); if (!regex) { // Skip any linkifiers that could not be converted continue; } linkifier_map.set(regex, { url_template, group_number_to_name, }); } } export function initialize(linkifiers: Linkifier[]): void { update_linkifier_rules(linkifiers); }