UNPKG

@fedify/markdown-it-mention

Version:

A markdown-it plugin that parses and renders Mastodon-style @mentions.

111 lines (110 loc) 3.94 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.mention = void 0; const html_js_1 = require("./html.js"); const label_js_1 = require("./label.js"); /** * A markdown-it plugin to parse and render Mastodon-style mentions. */ const mention = (md, options) => { md.core.ruler.after("inline", "mention", (state) => parseMention(state, options)); md.renderer.rules.mention = renderMention; }; exports.mention = mention; function parseMention(state, options) { for (const blockToken of state.tokens) { if (blockToken.type !== "inline") continue; if (blockToken.children == null) continue; let linkDepth = 0; let htmlLinkDepth = 0; blockToken.children = blockToken.children.flatMap((token) => { if (token.type === "link_open") { linkDepth++; } else if (token.type === "link_close") { linkDepth--; } else if (token.type === "html_inline") { if ((0, html_js_1.isLinkOpen)(token.content)) { htmlLinkDepth++; } else if ((0, html_js_1.isLinkClose)(token.content)) { htmlLinkDepth--; } } if (linkDepth > 0 || htmlLinkDepth > 0 || token.type !== "text") { return [token]; } return splitTokens(token, state, options); }); } } const MENTION_PATTERN = /@[\p{L}\p{N}._-]+(@(?:[\p{L}\p{N}][\p{L}\p{N}_-]*\.)+[\p{L}\p{N}]{2,})?/giu; function splitTokens(token, state, options) { const { content, level } = token; const tokens = []; let pos = 0; for (const match of content.matchAll(MENTION_PATTERN)) { if (match.index == null) continue; let handle = match[0]; if (match[1] == null) { const localDomain = options?.localDomain == null ? null : options.localDomain(handle, state.env); if (localDomain == null) continue; handle += `@${localDomain}`; } if (match.index > pos) { const token = new state.Token("text", "", 0); token.content = content.substring(pos, match.index); token.level = level; tokens.push(token); } const href = options?.link?.(handle, state.env); if (href == null && options?.link != null) { const token = new state.Token("text", "", 0); token.content = match[0]; token.level = level; tokens.push(token); pos = match.index + match[0].length; continue; } const token = new state.Token("mention", "", 0); token.content = options?.label?.(handle, state.env) ?? (0, label_js_1.toBareHandle)(handle, state.env); token.level = level; const attrs = options?.linkAttributes?.(handle, state.env) ?? {}; attrs.href = href ?? `acct:${handle}`; token.attrs = Object.entries(attrs); token.info = handle; tokens.push(token); pos = match.index + match[0].length; } if (pos < content.length) { const token = new state.Token("text", "", 0); token.content = content.substring(pos); token.level = level; tokens.push(token); } return tokens; } function renderMention(tokens, idx, opts, // deno-lint-ignore no-explicit-any env, self) { if (tokens.length <= idx) return ""; const token = tokens[idx]; if (token.type !== "mention") return self.renderToken(tokens, idx, opts); if (typeof env === "object" && env !== null) { if (!("mentions" in env)) { env.mentions = []; } env.mentions.push(token.info); } return `<a ${self.renderAttrs(token)}>${token.content}</a>`; }