import type { BetterLinkDocumentModDecoration } from 'botframework-webchat-component/internal.js'; import { onErrorResumeNext } from 'botframework-webchat-core'; import { sanitizeUri } from 'micromark-util-sanitize-uri'; import type { MarkdownLinkDefinition } from './extractDefinitionsFromEvents'; export const ALLOWED_SCHEMES = ['data', 'http', 'https', 'ftp', 'mailto', 'sip', 'tel']; export function createDecorate( definitions: readonly MarkdownLinkDefinition[], externalLinkAlt: string ): (href: string, textContent: string) => BetterLinkDocumentModDecoration { const linkDefinitions = definitions.map(definition => Object.freeze({ ...definition, markupUrl: sanitizeUri(definition.url), parsedUrl: onErrorResumeNext(() => new URL(definition.url)) }) ); const allowedSchemas = ALLOWED_SCHEMES.map(scheme => `${scheme}:`); return (href: string, textContent: string): BetterLinkDocumentModDecoration => { const decoration: BetterLinkDocumentModDecoration = { rel: 'noopener noreferrer', target: '_blank', wrapZeroWidthSpace: true }; const ariaLabelSegments: string[] = [textContent]; const classes: Set = new Set(); const linkDefinition = linkDefinitions.find(({ url, markupUrl }) => url === href || (href && markupUrl === href)); const protocol = onErrorResumeNext(() => new URL(href).protocol); if (linkDefinition) { ariaLabelSegments.push(linkDefinition.title || linkDefinition?.parsedUrl?.host || linkDefinition.url); // linkDefinition.identifier is uppercase, while linkDefinition.label is as-is. linkDefinition.label === textContent && classes.add('render-markdown__pure-identifier'); } // Let javascript: fell through. Our sanitizer will catch and remove it from . // Otherwise, it will be turn into