(text: string)
| 852 | } |
| 853 | |
| 854 | function markdownToHtml(text: string): string { |
| 855 | let result = text; |
| 856 | |
| 857 | const htmlTags: string[] = []; |
| 858 | let tagIndex = 0; |
| 859 | result = result.replace(/<\/?[a-zA-Z][^>]*>/g, (match) => { |
| 860 | htmlTags.push(match); |
| 861 | return `__HTML_TAG_${tagIndex++}__`; |
| 862 | }); |
| 863 | |
| 864 | result = result |
| 865 | .replace(/&/g, "&") |
| 866 | .replace(/</g, "<") |
| 867 | .replace(/>/g, ">"); |
| 868 | |
| 869 | htmlTags.forEach((tag, index) => { |
| 870 | result = result.replace(`__HTML_TAG_${index}__`, tag); |
| 871 | }); |
| 872 | |
| 873 | result = result |
| 874 | .replace(/```(\w+)?\n([\s\S]*?)```/g, (_match, _lang, code) => { |
| 875 | const escapedCode = code.replace(/</g, '<').replace(/>/g, '>').replace(/&/g, '&'); |
| 876 | return `<pre><code>${Utils.escapeHtml(escapedCode)}</code></pre>`; |
| 877 | }) |
| 878 | .replace(/`([^`]+)`/g, (_match, code) => { |
| 879 | const escapedCode = code.replace(/</g, '<').replace(/>/g, '>').replace(/&/g, '&'); |
| 880 | return `<code>${Utils.escapeHtml(escapedCode)}</code>`; |
| 881 | }) |
| 882 | .replace(/\*\*([^*]+)\*\*/g, '<b>$1</b>') |
| 883 | .replace(/\*([^*\n]+)\*/g, '<i>$1</i>') |
| 884 | .replace(/__([^_]+)__/g, '<b>$1</b>') |
| 885 | .replace(/_([^_\n]+)_/g, '<i>$1</i>') |
| 886 | .replace(/~~([^~]+)~~/g, '<s>$1</s>') |
| 887 | .replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2">$1</a>') |
| 888 | .replace(/^### (.+)$/gm, '<b>$1</b>') |
| 889 | .replace(/^## (.+)$/gm, '<b>$1</b>') |
| 890 | .replace(/^# (.+)$/gm, '<b>$1</b>') |
| 891 | .replace(/^> (.+)$/gm, '<blockquote>$1</blockquote>'); |
| 892 | return result; |
| 893 | } |
| 894 | |
| 895 | async function getGeminiClient(): Promise<GeminiClient> { |
| 896 | const apiKey = getConfig(CONFIG_KEYS.GEMINI_API_KEY); |
no test coverage detected