├── asset └── logo.png ├── content ├── index.js ├── promptUi.js └── promptHandler.js ├── manifest.json ├── background ├── menus.js ├── contextMenuManager.js └── index.js ├── README.md ├── popup ├── popup.js └── index.html └── lib └── marked.min.js /asset/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hasan-py/Ai-Assistant-Chrome-Extension/HEAD/asset/logo.png -------------------------------------------------------------------------------- /content/index.js: -------------------------------------------------------------------------------- 1 | // Listener that listen message from content.js 2 | chrome.runtime.onMessage.addListener(function (message) { 3 | chrome.storage.local.get(["MENUS", "DATA"], (result) => { 4 | const promptHandler = new PromptHandler(result, message); 5 | promptHandler.handle(); 6 | }); 7 | }); 8 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 3, 3 | "name": "Ai Assistant", 4 | "version": "1.0", 5 | "description": "Ai in your daily life", 6 | "permissions": [ 7 | "activeTab", 8 | "scripting", 9 | "contextMenus", 10 | "tabs", 11 | "storage", 12 | "declarativeNetRequest" 13 | ], 14 | "host_permissions": ["http://127.0.0.1:11434/*"], 15 | "content_scripts": [ 16 | { 17 | "matches": [""], 18 | "js": [ 19 | "lib/marked.min.js", 20 | "content/promptUi.js", 21 | "content/promptHandler.js", 22 | "content/index.js" 23 | ] 24 | } 25 | ], 26 | "background": { 27 | "service_worker": "background/index.js" 28 | }, 29 | "action": { 30 | "default_popup": "popup/index.html" 31 | }, 32 | "icons": { 33 | "16": "asset/logo.png", 34 | "48": "asset/logo.png", 35 | "128": "asset/logo.png" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /background/menus.js: -------------------------------------------------------------------------------- 1 | // Menus configuration 2 | const MENUS = { 3 | correctGrammar: { 4 | key: "correctGrammar", 5 | title: "Correct Grammar", 6 | }, 7 | codeReview: { 8 | key: "codeReview", 9 | title: "Code Review", 10 | }, 11 | summarize: { 12 | key: "summarize", 13 | title: "Summarize", 14 | }, 15 | generatePost: { 16 | key: "generatePost", 17 | title: "Generate Post", 18 | }, 19 | askAnything: { 20 | key: "askAnything", 21 | title: "Ask Anything", 22 | }, 23 | generateReply: { 24 | key: "generateReply", 25 | title: "Generate Reply", 26 | subMenus: [ 27 | { 28 | key: "positiveReply", 29 | title: "Positive Reply", 30 | }, 31 | { 32 | key: "negativeReply", 33 | title: "Negative Reply", 34 | }, 35 | { 36 | key: "humoristicReply", 37 | title: "Humoristic Reply", 38 | }, 39 | { 40 | key: "engagementReply", 41 | title: "Engagement Reply", 42 | }, 43 | { 44 | key: "acknowledgmentReply", 45 | title: "Acknowledgment Reply", 46 | }, 47 | ], 48 | }, 49 | }; 50 | -------------------------------------------------------------------------------- /background/contextMenuManager.js: -------------------------------------------------------------------------------- 1 | // Menu handler 2 | class ContextMenuManager { 3 | constructor(menus) { 4 | this.menus = menus; // Store menu configuration 5 | } 6 | 7 | // Initialize context menus 8 | initializeMenus() { 9 | Object.keys(this.menus).forEach((parentKey) => { 10 | const parentMenu = this.menus[parentKey]; 11 | 12 | // Create the top-level context menu item 13 | chrome.contextMenus.create({ 14 | id: parentMenu.key, 15 | title: parentMenu.title, 16 | contexts: ["all"], 17 | }); 18 | 19 | // Create nested menu items (if any) 20 | if (parentMenu.subMenus) { 21 | parentMenu.subMenus.forEach((subMenu) => { 22 | chrome.contextMenus.create({ 23 | id: subMenu.key, 24 | title: subMenu.title, 25 | parentId: parentMenu.key, 26 | contexts: ["all"], 27 | }); 28 | }); 29 | } 30 | }); 31 | } 32 | 33 | handleMenuClick(info) { 34 | const handleSubMenus = (menuItem, menu) => { 35 | // Check if the clicked item matches the current menu 36 | if (menuItem === menu.key) { 37 | this.sendMessageToActiveTab({ ...menu }); 38 | return true; // Return true to stop further recursion if the item is found 39 | } 40 | 41 | // If the menu has submenus, iterate through them recursively 42 | if (menu.subMenus) { 43 | for (const subMenu of menu.subMenus) { 44 | if (handleSubMenus(menuItem, subMenu)) { 45 | return true; // Return true once the action is taken for any submenu 46 | } 47 | } 48 | } 49 | 50 | return false; // Return false if the item is not found in this level 51 | }; 52 | 53 | Object.keys(this.menus).forEach((parentKey) => { 54 | const parentMenu = this.menus[parentKey]; 55 | 56 | // Start the recursive search from the main menu or submenus 57 | handleSubMenus(info.menuItemId, parentMenu); 58 | }); 59 | } 60 | 61 | // Send message to active tab 62 | sendMessageToActiveTab(message) { 63 | chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) { 64 | if (tabs.length > 0) { 65 | chrome.tabs.sendMessage(tabs[0].id, message, function (response) { 66 | if (chrome.runtime.lastError) { 67 | // console.error("Error sending message:", chrome.runtime.lastError.message); 68 | } else { 69 | // console.log("Message sent to content script:", response); 70 | } 71 | }); 72 | } else { 73 | // console.error("No active tab found."); 74 | } 75 | }); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Watch the full tutorial video from YouTube: 2 | 3 | [![Alt text](https://img.youtube.com/vi/troznI6r17I/hqdefault.jpg)](https://youtu.be/troznI6r17I?si=jvxJS16LaGASb9FW) 4 | 5 | 6 | ## How to install this chrome extension locally 7 | Follow these steps to install the Chrome extension on your browser: 8 | 9 | ### Step 1: Download the Extension Files 10 | - Download the extension files as a folder or a .zip file. 11 | - If it's a `.zip` file, extract it to get the folder containing the extension files. 12 | 13 | 14 | ### Step 2: Open the Chrome Extensions Page 15 | - Open Google Chrome. 16 | - Type the following URL in the address bar and press Enter: 17 | ``` 18 | chrome://extensions/ 19 | ``` 20 | 21 | ### Step 3: Enable Developer Mode 22 | - At the top-right corner of the Extensions page, toggle the Developer mode switch to turn it on. 23 | 24 | 25 | ### Step 4: Load the Extension 26 | - Click the "Load unpacked" button. 27 | - In the file browser, navigate to the folder where you have saved the extension files. 28 | - Select the folder and click "Open" or "Select Folder". 29 | 30 | ### Step 5: Verify Installation 31 | ![Screenshot from 2025-01-12 17-23-32](https://github.com/user-attachments/assets/d1b47664-a853-43c7-83c0-72f568c8f354) 32 | - Once loaded, the extension will appear in the list of installed extensions on the Extensions page. 33 | - If there are any errors, Chrome will show a warning. Make sure your files (especially manifest.json) are configured correctly. 34 | 35 | ## How to use this chrome extension? 36 | Follow these steps to use the Chrome extension on your browser: 37 | 38 | ### Step 1: Please collect your api key from: GPT or Gemini or Grok 39 | - Goto the tools website's dashboard and generate api key 40 | - Note your api key and api endpoint 41 | 42 | ### Step 2: Open the extension popup from extension icon from the extension list 43 | - Add the api endpoint 44 | - Add api key 45 | - Fillup other input field with any text to pass validations 46 | - Select which tool you want to use 47 | 48 | ![Screenshot from 2025-01-12 19-32-26](https://github.com/user-attachments/assets/f0eecb25-6c1d-484d-9cf1-699a30afed5a) 49 | 50 | ### Step 3: Copy any text from any website 51 | - Right click from the mouse 52 | - Choose the desire menu and clicked 53 | ![Screenshot from 2025-01-12 19-32-06](https://github.com/user-attachments/assets/fc52f860-e3c0-4538-a4a3-ff2c8ad2c47a) 54 | 55 | ### Step 4: After the loading complete you will result like this 56 | - Click copy button to copy ta raw text 57 | ![Screenshot from 2025-01-12 19-32-56](https://github.com/user-attachments/assets/5d3969f8-f9e5-4ba8-bbaf-748abefe3c4f) 58 | 59 | 60 | ### Troubleshoot?  61 | - Please reach out to me on 62 | X: https://x.com/hasan_py or 63 | Linkedin: https://www.linkedin.com/in/hasan-py 64 | 65 | 66 | ----- 67 | Build with ❤️ by Hasan 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /background/index.js: -------------------------------------------------------------------------------- 1 | // This import only work for service worker and web work. If script have dom dependency it will not work 2 | importScripts("menus.js"); 3 | importScripts("contextMenuManager.js"); 4 | 5 | // Instantiate and initialize context menus 6 | const menuManager = new ContextMenuManager(MENUS); 7 | 8 | // When the Chrome extension is installed 9 | chrome.runtime.onInstalled.addListener(() => { 10 | // Dynamically generate a unique rule ID 11 | const uniqueRuleId = Math.floor(Date.now() % 1000000); 12 | 13 | /* 14 | * Chrome sends its origin with a chrome ID in any POST API call, but it was not accepted by Ollama. 15 | * Therefore, this code will forcefully add the origin of the Ollama default port! 16 | */ 17 | chrome.declarativeNetRequest.updateDynamicRules({ 18 | addRules: [ 19 | { 20 | id: uniqueRuleId, 21 | priority: 1, 22 | action: { 23 | type: "modifyHeaders", 24 | requestHeaders: [ 25 | { 26 | header: "Origin", 27 | operation: "set", // Use 'set' operation to replace the value 28 | value: "http://127.0.0.1", // The new origin value 29 | }, 30 | ], 31 | }, 32 | condition: { 33 | urlFilter: "http://127.0.0.1:11434/*", // The API URL you want to target 34 | resourceTypes: ["main_frame", "xmlhttprequest"], // You can target specific types of requests 35 | }, 36 | }, 37 | ], 38 | removeRuleIds: [], // No rules to remove initially 39 | }); 40 | 41 | // Set all the menus in the storage 42 | chrome.storage.local.set({ MENUS: MENUS }, function () {}); 43 | 44 | // Initialize menus when the extension is installed or updated 45 | menuManager.initializeMenus(); 46 | }); 47 | 48 | // Listen for messages from the content script 49 | chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { 50 | if (request.action === "callOllamaApi") { 51 | callOllamaApi(request.payload, request.tags) 52 | .then((data) => { 53 | sendResponse({ success: true, data }); // Send success response 54 | }) 55 | .catch((error) => { 56 | sendResponse({ 57 | success: false, 58 | error: error.message || "Unknown error", 59 | }); // Send error response 60 | }); 61 | 62 | return true; // Indicates that the response will be sent asynchronously 63 | } 64 | }); 65 | 66 | // Function to call the Ollama API 67 | function callOllamaApi(payload, tags) { 68 | // This will look into all the models 69 | if (tags) { 70 | return fetch("http://127.0.0.1:11434/api/tags", { 71 | method: "GET", 72 | headers: { 73 | "Content-Type": "application/json", 74 | }, 75 | }) 76 | .then((response) => { 77 | if (!response.ok) { 78 | // Handle HTTP errors (e.g., 4xx, 5xx) 79 | throw new Error(`HTTP error! Status: ${response.status}`); 80 | } 81 | return response.json(); 82 | }) 83 | .catch((error) => { 84 | // Handle network errors (e.g., CORS, server unreachable) 85 | throw new Error(`Network error: ${error.message}`); 86 | }); 87 | } 88 | 89 | // This is for generate chat 90 | return fetch("http://127.0.0.1:11434/api/chat", { 91 | method: "POST", 92 | headers: { 93 | "Content-Type": "application/json", 94 | }, 95 | body: JSON.stringify(payload), 96 | }) 97 | .then((response) => { 98 | if (!response.ok) { 99 | // Handle HTTP errors (e.g., 4xx, 5xx) 100 | throw new Error(`HTTP error! Status: ${response.status}`); 101 | } 102 | return response.json(); 103 | }) 104 | .catch((error) => { 105 | // Handle network errors (e.g., CORS, server unreachable) 106 | throw new Error(`Network error: ${error.message}`); 107 | }); 108 | } 109 | 110 | // Listen for clicks on the context menu item 111 | chrome.contextMenus.onClicked.addListener((info, tab) => { 112 | menuManager.handleMenuClick(info); 113 | }); 114 | -------------------------------------------------------------------------------- /popup/popup.js: -------------------------------------------------------------------------------- 1 | const DEFAULT_KEY = "**********"; 2 | const GPT_ENDPOINT = "https://api.openai.com/v1/chat/completions"; 3 | const GEMINI_ENDPOINT = 4 | "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash-exp:generateContent"; 5 | const GROK_ENDPOINT = "https://api.x.ai/v1/chat/completions"; 6 | 7 | // Load the stored theme preference 8 | chrome.storage.local.get("darkMode", (data) => { 9 | if (data.darkMode) { 10 | document.documentElement.classList.add("dark"); 11 | toggleModeBtn.querySelector("span").innerHTML = "☀"; 12 | } else { 13 | document.documentElement.classList.remove("dark"); 14 | toggleModeBtn.querySelector("span").innerHTML = "☾"; 15 | } 16 | }); 17 | 18 | const toggleModeBtn = document.getElementById("toggleMode"); 19 | toggleModeBtn.addEventListener("click", () => { 20 | const darkModeEnabled = document.documentElement.classList.toggle("dark"); 21 | const toggleSpan = toggleModeBtn.querySelector("span"); 22 | 23 | // Change icon to corresponding mode 24 | toggleSpan.innerHTML = darkModeEnabled ? "☀" : "☾"; 25 | chrome.storage.local.set({ darkMode: darkModeEnabled }); 26 | }); 27 | 28 | document.getElementById("saveButton").addEventListener("click", () => { 29 | const gptKey = document.getElementById("gptKey").value; 30 | const geminiKey = document.getElementById("geminiKey").value; 31 | const grokKey = document.getElementById("grokKey").value; 32 | 33 | const gptEndpoint = 34 | document.getElementById("gptEndpoint").value || GPT_ENDPOINT; 35 | const geminiEndpoint = 36 | document.getElementById("geminiEndpoint").value || GEMINI_ENDPOINT; 37 | const grokEndpoint = 38 | document.getElementById("grokEndpoint").value || GROK_ENDPOINT; 39 | 40 | const selectedAI = document.getElementById("toggle").value; 41 | 42 | chrome.storage.local.get("DATA", ({ DATA }) => { 43 | const newData = { 44 | gptKey: gptKey !== DEFAULT_KEY ? gptKey : DATA.gptKey, 45 | geminiKey: geminiKey !== DEFAULT_KEY ? geminiKey : DATA.geminiKey, 46 | grokKey: grokKey !== DEFAULT_KEY ? grokKey : DATA.grokKey, 47 | gptEndpoint, 48 | geminiEndpoint, 49 | grokEndpoint, 50 | selectedAI, 51 | }; 52 | chrome.storage.local.set( 53 | { 54 | DATA: newData, 55 | }, 56 | () => { 57 | alert("Configuration saved successfully."); 58 | } 59 | ); 60 | }); 61 | }); 62 | 63 | document.addEventListener("DOMContentLoaded", () => { 64 | const gptKey = document.getElementById("gptKey"); 65 | const geminiKey = document.getElementById("geminiKey"); 66 | const grokKey = document.getElementById("grokKey"); 67 | 68 | const gptEndpoint = document.getElementById("gptEndpoint"); 69 | const geminiEndpoint = document.getElementById("geminiEndpoint"); 70 | const grokEndpoint = document.getElementById("grokEndpoint"); 71 | 72 | const selectedAI = document.getElementById("toggle"); 73 | 74 | chrome.storage.local.get("DATA", (result) => { 75 | const info = result.DATA; 76 | 77 | if (!info) { 78 | getOllamaModels("gemini"); 79 | return; 80 | } 81 | 82 | if (info.gptKey) { 83 | gptKey.value = DEFAULT_KEY; 84 | gptKey.type = "password"; 85 | } 86 | if (info.geminiKey) { 87 | geminiKey.value = DEFAULT_KEY; 88 | geminiKey.type = "password"; 89 | } 90 | if (info.grokKey) { 91 | grokKey.value = DEFAULT_KEY; 92 | grokKey.type = "password"; 93 | } 94 | 95 | if (info.gptEndpoint) gptEndpoint.value = info.gptEndpoint; 96 | if (info.geminiEndpoint) geminiEndpoint.value = info.geminiEndpoint; 97 | if (info.grokEndpoint) grokEndpoint.value = info.grokEndpoint; 98 | 99 | if (info.selectedAI) selectedAI.value = info.selectedAI; 100 | 101 | getOllamaModels(info.selectedAI); 102 | }); 103 | }); 104 | 105 | const getOllamaModels = (selectedModel) => { 106 | chrome.runtime.sendMessage( 107 | { action: "callOllamaApi", tags: true }, 108 | (response) => { 109 | const selectedAI = document.getElementById("toggle"); 110 | if (!response.success) { 111 | const optgroup = document.createElement("optgroup"); 112 | optgroup.label = "No Ollama Models Found"; 113 | selectedAI.appendChild(optgroup); 114 | } else { 115 | const models = response.data.models; 116 | const optgroup = document.createElement("optgroup"); 117 | optgroup.label = "Ollama Local Models"; 118 | models.forEach((model) => { 119 | const option = document.createElement("option"); 120 | option.value = model.model; 121 | option.text = model.name; 122 | optgroup.appendChild(option); 123 | }); 124 | 125 | selectedAI.appendChild(optgroup); 126 | if (selectedModel) { 127 | selectedAI.value = selectedModel; 128 | } 129 | } 130 | } 131 | ); 132 | }; 133 | -------------------------------------------------------------------------------- /content/promptUi.js: -------------------------------------------------------------------------------- 1 | class PromptUi { 2 | constructor(modalTitle) { 3 | this.modalHTML = ` 4 | 16 | `; 17 | 18 | this.modalCSS = ` 19 | .modal-overlay { 20 | display: none; 21 | position: fixed; 22 | top: 0; 23 | left: 0; 24 | width: 100%; 25 | height: 100%; 26 | background-color: rgba(0, 0, 0, 0.5); 27 | display: flex; 28 | align-items: center; 29 | justify-content: center; 30 | z-index: 10000; 31 | } 32 | 33 | .custom-modal { 34 | background-color: #fff; 35 | padding: 20px; 36 | width: 50%; 37 | max-width: 600px; 38 | min-height: 100px; 39 | max-height: 500px; 40 | color: black; 41 | border-radius: 8px; 42 | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); 43 | border: 1px solid rgb(170, 170, 170); 44 | } 45 | 46 | .modal-content { 47 | overflow-y: auto; 48 | max-height: 360px; 49 | } 50 | 51 | .modal-header { 52 | font-size: 24px; 53 | font-weight: bold; 54 | color: rgb(69, 69, 69); 55 | padding-bottom: 16px; 56 | } 57 | 58 | .buttons-container { 59 | display: flex; 60 | justify-content: flex-end; 61 | margin-top: 20px; 62 | gap: 8px; 63 | } 64 | 65 | .buttons-container button { 66 | padding: 10px 20px; 67 | border: none; 68 | border-radius: 4px; 69 | cursor: pointer; 70 | background-color: #dc3545; 71 | color: #fff; 72 | } 73 | 74 | #replace-button { 75 | background-color: #2a8ffb; 76 | color: #fff; 77 | font-weight: bold; 78 | } 79 | 80 | #copy-button { 81 | background-color: #33dd5a; 82 | color: #fff; 83 | font-weight: bold; 84 | } 85 | 86 | #cancel-button { 87 | background-color: #e34353; 88 | color: #fff; 89 | font-weight: bold; 90 | } 91 | `; 92 | 93 | this.loadingSvg = ``; 94 | } 95 | 96 | initialize(_textResult) { 97 | // Create real DOM element 98 | this.modal = document.createElement("div"); 99 | const style = document.createElement("style"); 100 | style.textContent = this.modalCSS; 101 | 102 | // Create shadow DOM 103 | this.shadowRoot = this.modal.attachShadow({ mode: "open" }); 104 | 105 | // Append HTML and CSS to shadow DOM 106 | this.shadowRoot.innerHTML = this.modalHTML; 107 | this.shadowRoot.appendChild(style); 108 | 109 | // Get modal elements 110 | this.modalContent = this.shadowRoot.querySelector(".modal-content"); 111 | this.copyButton = this.shadowRoot.querySelector("#copy-button"); 112 | this.cancelButton = this.shadowRoot.querySelector("#cancel-button"); 113 | 114 | // Copy button functionality 115 | this.copyButton.onclick = () => { 116 | const textResult = _textResult || ""; 117 | navigator.clipboard.writeText(textResult); 118 | this.hideModal(); 119 | }; 120 | 121 | // Cancel Button functionality 122 | this.cancelButton.onclick = () => this.hideModal(); 123 | 124 | // Attach modal to the main DOM document body 125 | document.body.appendChild(this.modal); 126 | } 127 | 128 | showModal(content, textResult) { 129 | // Initialize the modal with creating shadow DOM 130 | this.initialize(textResult); 131 | 132 | // Parse markdown content setting options for code highlighting 133 | marked.setOptions({ 134 | highlight: function (code, language) { 135 | const validLanguage = hljs.getLanguage(language) 136 | ? language 137 | : "plaintext"; 138 | return hljs.highlight(code, { language: validLanguage }).value; 139 | }, 140 | }); 141 | 142 | // Set the modal content 143 | this.modalContent.innerHTML = marked.parse(content); 144 | // Show the modal 145 | this.shadowRoot.querySelector("#modal-overlay").style.display = "flex"; 146 | } 147 | 148 | hideModal() { 149 | this.shadowRoot.querySelector("#modal-overlay").style.display = "none"; 150 | this.modalContent.innerHTML = ""; 151 | // Remove the modal from the DOM 152 | this.modal.remove(); 153 | } 154 | 155 | showLoading() { 156 | if (document.getElementById("loading-indicator")) return; 157 | 158 | const loadingIndicator = document.createElement("div"); 159 | Object.assign(loadingIndicator, { 160 | id: "loading-indicator", 161 | innerHTML: this.loadingSvg, 162 | }); 163 | 164 | Object.assign(loadingIndicator.style, { 165 | position: "fixed", 166 | bottom: "10px", 167 | right: "10px", 168 | width: "50px", 169 | height: "50px", 170 | zIndex: "1000", 171 | borderRadius: "10px", 172 | padding: "8px", 173 | background: "whitesmoke", 174 | }); 175 | 176 | document.body.appendChild(loadingIndicator); 177 | } 178 | 179 | hideLoading() { 180 | const loadingIndicator = document.getElementById("loading-indicator"); 181 | if (loadingIndicator) { 182 | document.body.removeChild(loadingIndicator); 183 | } 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /popup/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | AI Config 5 | 9 | 18 | 19 | 20 |
23 | 24 |
25 |
26 |

29 | AI Assistant 32 | 33 | Configuration 34 |

35 | 41 |
42 |

43 | Configure your ChatGPT, Gemini, and Grok endpoints and keys, then 44 | select any tool you want 45 |

46 |
47 | 48 | 49 |
50 | 51 |
52 |
53 | 58 | 64 |
65 | 66 |
67 | 72 | 78 |
79 |
80 | 81 | 82 |
83 |
84 | 89 | 95 |
96 | 97 |
98 | 103 | 104 | 110 |
111 |
112 | 113 | 114 |
115 |
116 | 121 | 127 |
128 | 129 |
130 | 135 | 136 | 142 |
143 |
144 | 145 | 146 |
147 |
148 | 153 | 163 |
164 | 165 |
166 | 173 |
174 |
175 |
176 | 177 | 178 |
181 | Build with :heart: by Hasan 184 |
185 |
186 | 187 | 188 | 189 | 190 | -------------------------------------------------------------------------------- /content/promptHandler.js: -------------------------------------------------------------------------------- 1 | class PromptHandler { 2 | constructor(result, message) { 3 | this.initializeApiInfo(result.DATA); 4 | this.menus = result.MENUS; 5 | this.message = message; 6 | this.selectedText = window.getSelection().toString(); 7 | this.promptUi = new PromptUi(message.title); 8 | } 9 | 10 | initializeApiInfo({ 11 | gptEndpoint, 12 | geminiEndpoint, 13 | gptKey, 14 | geminiKey, 15 | selectedAI, 16 | grokEndpoint, 17 | grokKey, 18 | }) { 19 | this.openAiEndPoint = gptEndpoint; 20 | this.geminiEndPoint = geminiEndpoint; 21 | this.grokEndPoint = grokEndpoint; 22 | 23 | this.openAPIKey = gptKey; 24 | this.geminiAPIKey = geminiKey; 25 | this.grokAPIKey = grokKey; 26 | 27 | this.selectedAI = selectedAI; 28 | } 29 | 30 | // Method to create the API payload based on the selected menu 31 | createGptPayload() { 32 | const content = this.getUserContent(this.message); 33 | 34 | if (!content) return ""; 35 | 36 | const payload = { 37 | messages: [ 38 | { role: "system", content: "You are a helpful assistant." }, 39 | { role: "user", content }, 40 | ], 41 | model: "gpt-4o-mini", 42 | }; 43 | 44 | return payload; 45 | } 46 | 47 | createGeminiPayload() { 48 | const text = this.getUserContent(this.message); 49 | 50 | if (!text) return ""; 51 | 52 | return { 53 | contents: [ 54 | { 55 | parts: [{ text }], 56 | }, 57 | ], 58 | }; 59 | } 60 | 61 | createGrokPayload() { 62 | const content = this.getUserContent(this.message); 63 | 64 | if (!content) return ""; 65 | 66 | return { 67 | messages: [ 68 | { role: "system", content: "You are a helpful assistant." }, 69 | { role: "user", content }, 70 | ], 71 | model: "grok-beta", 72 | stream: false, 73 | temperature: 0, 74 | }; 75 | } 76 | 77 | createOllamaPayload() { 78 | const content = this.getUserContent(this.message); 79 | 80 | if (!content) return ""; 81 | 82 | return { 83 | model: this.selectedAI, 84 | messages: [ 85 | { role: "system", content: "You are a helpful assistant." }, 86 | { role: "user", content }, 87 | ], 88 | stream: false, 89 | }; 90 | } 91 | 92 | // Helper method to generate user content based on the selected menu 93 | getUserContent(menu) { 94 | const { correctGrammar, codeReview, generatePost, summarize, askAnything } = 95 | this.menus; 96 | 97 | if (menu.key === correctGrammar.key) { 98 | return `Correct this text grammatically and give me only the corrected text not any other explanation: ${this.selectedText}`; 99 | } 100 | 101 | if (menu.key === generatePost.key) { 102 | return `Generate a new post based on the following content: ${this.selectedText}`; 103 | } 104 | 105 | if (menu.key === summarize.key) { 106 | return `Summarize the following text: ${this.selectedText}`; 107 | } 108 | 109 | if (menu.key === codeReview.key) { 110 | const reviewPrompt = ` 111 | Please review the following code for the following aspects: 112 | 1. Proper variable naming conventions (e.g., meaningful and descriptive variable names). 113 | 2. Consistency in code formatting (e.g., indentation, spacing, brace placement). 114 | 3. Presence of meaningful comments and documentation explaining non-obvious code. 115 | 4. Efficiency and readability (e.g., avoid unnecessary loops, complex conditionals, or redundant code). 116 | 5. Avoidance of hardcoded values where possible. 117 | 6. Proper error handling and edge case consideration. 118 | 7. Ensure that boundary conditions (e.g., null/undefined checks, empty values) are properly handled. 119 | 8. Redundant code detection (e.g., duplicated logic, unnecessary calculations, or unreachable code). 120 | 121 | Here is the code to review: 122 | \`\`\` 123 | ${this.selectedText} 124 | \`\`\` 125 | 126 | Please provide a code review based on these criteria. And don't just always give review. If its seems like okay then don't need. If its no then just give me the improved code and the area you improved! not long explanation 127 | `; 128 | 129 | return reviewPrompt; 130 | } 131 | 132 | if (menu.key === askAnything.key) { 133 | return `Tell me about this: ${this.selectedText}`; 134 | } 135 | 136 | if (menu.key) { 137 | return `Generate a ${menu.title.toLowerCase()} for social media post which can fit into any of this platform like: X, LinkedIn, Reedit etc: ${ 138 | this.selectedText 139 | }`; 140 | } 141 | 142 | return ""; 143 | } 144 | 145 | // Methods to handle the API call 146 | callGptApi(payload) { 147 | this.promptUi.showLoading(); 148 | return fetch(this.openAiEndPoint, { 149 | method: "POST", 150 | headers: { 151 | "Content-Type": "application/json", 152 | Authorization: `Bearer ${this.openAPIKey}`, 153 | }, 154 | body: JSON.stringify(payload), 155 | }) 156 | .then((response) => response.json()) 157 | .then((data) => { 158 | const result = data.choices[0]?.message?.content || "No response"; 159 | this.promptUi.showModal(`

${result}

`, result); 160 | }) 161 | .catch((error) => { 162 | this.promptUi.showModal(`

Error: ${error.message}

`); 163 | }) 164 | .finally(() => { 165 | this.promptUi.hideLoading(); 166 | }); 167 | } 168 | 169 | callGeminiAPI(payload) { 170 | this.promptUi.showLoading(); 171 | return fetch(`${this.geminiEndPoint}?key=${this.geminiAPIKey}`, { 172 | method: "POST", 173 | headers: { 174 | "Content-Type": "application/json", 175 | }, 176 | body: JSON.stringify(payload), 177 | }) 178 | .then((response) => { 179 | if (!response.ok) { 180 | throw new Error(`Error: ${response.status} ${response.statusText}`); 181 | } 182 | return response.json(); 183 | }) 184 | .then((data) => { 185 | const result = 186 | data?.candidates?.[0]?.content?.parts?.[0]?.text || 187 | "No response from the API."; 188 | this.promptUi.showModal(`

${result}

`, result); 189 | }) 190 | .catch((error) => { 191 | this.promptUi.showModal(`

Error: ${error.message}

`); 192 | }) 193 | .finally(() => { 194 | this.promptUi.hideLoading(); 195 | }); 196 | } 197 | 198 | callGrokAPI(payload) { 199 | this.promptUi.showLoading(); 200 | return fetch(this.grokEndPoint, { 201 | method: "POST", 202 | headers: { 203 | "Content-Type": "application/json", 204 | Authorization: `Bearer ${this.grokAPIKey}`, 205 | }, 206 | body: JSON.stringify(payload), 207 | }) 208 | .then((response) => { 209 | if (!response.ok) { 210 | throw new Error(`Error: ${response.status} ${response.statusText}`); 211 | } 212 | return response.json(); 213 | }) 214 | .then((data) => { 215 | const result = 216 | data?.choices?.[0]?.message?.content || "No response from the API."; 217 | this.promptUi.showModal(`

${result}

`, result); 218 | }) 219 | .catch((error) => { 220 | this.promptUi.showModal(`

Error: ${error.message}

`); 221 | }) 222 | .finally(() => { 223 | this.promptUi.hideLoading(); 224 | }); 225 | } 226 | 227 | /* 228 | * Some models provide Markdown formatted data, but it doesn't parse properly, hence removing that part here. 229 | */ 230 | removeMarkdownMarkers(markdownText) { 231 | const regex = /```markdown\n([\s\S]*?)\n```/g; 232 | return markdownText.replace(regex, "$1"); // $1 refers to the captured group 233 | } 234 | 235 | /* 236 | * Called the API through `background.js` because of Chrome's CORS policy. 237 | */ 238 | callOllamaApi(payload) { 239 | this.promptUi.showLoading(); 240 | chrome.runtime.sendMessage( 241 | { action: "callOllamaApi", payload }, 242 | (response) => { 243 | if (!response.success) { 244 | this.promptUi.showModal(`

Error: ${response.error}

`); 245 | this.promptUi.hideLoading(); 246 | } else { 247 | const res = response.data.message.content.replace( 248 | /[\s\S]*?<\/think>/g, // It will remove the reasoning portion 249 | "" 250 | ); 251 | const result = this.removeMarkdownMarkers(res) || "No response"; 252 | this.promptUi.showModal(`

${result}

`, result); 253 | this.promptUi.hideLoading(); 254 | } 255 | } 256 | ); 257 | } 258 | 259 | // Main method to handle the menu action and call the API 260 | handle() { 261 | try { 262 | if (!this.selectedText) { 263 | this.promptUi.showModal(`

Please select something

`); 264 | return; 265 | } 266 | 267 | const actionMap = { 268 | gpt: { 269 | createPayload: () => this.createGptPayload(), 270 | callApi: (payload) => this.callGptApi(payload), 271 | }, 272 | grok: { 273 | createPayload: () => this.createGrokPayload(), 274 | callApi: (payload) => this.callGrokAPI(payload), 275 | }, 276 | gemini: { 277 | createPayload: () => this.createGeminiPayload(), 278 | callApi: (payload) => this.callGeminiAPI(payload), 279 | }, 280 | ollama: { 281 | createPayload: () => this.createOllamaPayload(), 282 | callApi: (payload) => this.callOllamaApi(payload), 283 | }, 284 | }; 285 | 286 | const { createPayload, callApi } = 287 | actionMap[ 288 | ["gpt", "grok", "gemini"].includes(this.selectedAI) 289 | ? this.selectedAI 290 | : "ollama" 291 | ] || actionMap.gemini; 292 | 293 | const payload = createPayload(); 294 | 295 | callApi(payload); 296 | } catch (error) { 297 | this.promptUi.showModal(`

Error: ${error.message}

`); 298 | } 299 | } 300 | } 301 | -------------------------------------------------------------------------------- /lib/marked.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * marked v15.0.4 - a markdown parser 3 | * Copyright (c) 2011-2024, Christopher Jeffrey. (MIT Licensed) 4 | * https://github.com/markedjs/marked 5 | */ 6 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).marked={})}(this,(function(e){"use strict";function t(){return{async:!1,breaks:!1,extensions:null,gfm:!0,hooks:null,pedantic:!1,renderer:null,silent:!1,tokenizer:null,walkTokens:null}}function n(t){e.defaults=t}e.defaults={async:!1,breaks:!1,extensions:null,gfm:!0,hooks:null,pedantic:!1,renderer:null,silent:!1,tokenizer:null,walkTokens:null};const s={exec:()=>null};function r(e,t=""){let n="string"==typeof e?e:e.source;const s={replace:(e,t)=>{let r="string"==typeof t?t:t.source;return r=r.replace(i.caret,"$1"),n=n.replace(e,r),s},getRegex:()=>new RegExp(n,t)};return s}const i={codeRemoveIndent:/^(?: {1,4}| {0,3}\t)/gm,outputLinkReplace:/\\([\[\]])/g,indentCodeCompensation:/^(\s+)(?:```)/,beginningSpace:/^\s+/,endingHash:/#$/,startingSpaceChar:/^ /,endingSpaceChar:/ $/,nonSpaceChar:/[^ ]/,newLineCharGlobal:/\n/g,tabCharGlobal:/\t/g,multipleSpaceGlobal:/\s+/g,blankLine:/^[ \t]*$/,doubleBlankLine:/\n[ \t]*\n[ \t]*$/,blockquoteStart:/^ {0,3}>/,blockquoteSetextReplace:/\n {0,3}((?:=+|-+) *)(?=\n|$)/g,blockquoteSetextReplace2:/^ {0,3}>[ \t]?/gm,listReplaceTabs:/^\t+/,listReplaceNesting:/^ {1,4}(?=( {4})*[^ ])/g,listIsTask:/^\[[ xX]\] /,listReplaceTask:/^\[[ xX]\] +/,anyLine:/\n.*\n/,hrefBrackets:/^<(.*)>$/,tableDelimiter:/[:|]/,tableAlignChars:/^\||\| *$/g,tableRowBlankLine:/\n[ \t]*$/,tableAlignRight:/^ *-+: *$/,tableAlignCenter:/^ *:-+: *$/,tableAlignLeft:/^ *:-+ *$/,startATag:/^/i,startPreScriptTag:/^<(pre|code|kbd|script)(\s|>)/i,endPreScriptTag:/^<\/(pre|code|kbd|script)(\s|>)/i,startAngleBracket:/^$/,pedanticHrefTitle:/^([^'"]*[^\s])\s+(['"])(.*)\2/,unicodeAlphaNumeric:/[\p{L}\p{N}]/u,escapeTest:/[&<>"']/,escapeReplace:/[&<>"']/g,escapeTestNoEncode:/[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/,escapeReplaceNoEncode:/[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/g,unescapeTest:/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/gi,caret:/(^|[^\[])\^/g,percentDecode:/%25/g,findPipe:/\|/g,splitPipe:/ \|/,slashPipe:/\\\|/g,carriageReturn:/\r\n|\r/g,spaceLine:/^ +$/gm,notSpaceStart:/^\S*/,endingNewline:/\n$/,listItemRegex:e=>new RegExp(`^( {0,3}${e})((?:[\t ][^\\n]*)?(?:\\n|$))`),nextBulletRegex:e=>new RegExp(`^ {0,${Math.min(3,e-1)}}(?:[*+-]|\\d{1,9}[.)])((?:[ \t][^\\n]*)?(?:\\n|$))`),hrRegex:e=>new RegExp(`^ {0,${Math.min(3,e-1)}}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)`),fencesBeginRegex:e=>new RegExp(`^ {0,${Math.min(3,e-1)}}(?:\`\`\`|~~~)`),headingBeginRegex:e=>new RegExp(`^ {0,${Math.min(3,e-1)}}#`),htmlBeginRegex:e=>new RegExp(`^ {0,${Math.min(3,e-1)}}<(?:[a-z].*>|!--)`,"i")},l=/^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/,o=/(?:[*+-]|\d{1,9}[.)])/,a=r(/^(?!bull |blockCode|fences|blockquote|heading|html)((?:.|\n(?!\s*?\n|bull |blockCode|fences|blockquote|heading|html))+?)\n {0,3}(=+|-+) *(?:\n+|$)/).replace(/bull/g,o).replace(/blockCode/g,/(?: {4}| {0,3}\t)/).replace(/fences/g,/ {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g,/ {0,3}>/).replace(/heading/g,/ {0,3}#{1,6}/).replace(/html/g,/ {0,3}<[^\n>]+>\n/).getRegex(),c=/^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/,h=/(?!\s*\])(?:\\.|[^\[\]\\])+/,p=r(/^ {0,3}\[(label)\]: *(?:\n[ \t]*)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n[ \t]*)?| *\n[ \t]*)(title))? *(?:\n+|$)/).replace("label",h).replace("title",/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/).getRegex(),u=r(/^( {0,3}bull)([ \t][^\n]+?)?(?:\n|$)/).replace(/bull/g,o).getRegex(),g="address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|search|section|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul",k=/|$))/,f=r("^ {0,3}(?:<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?(?:\\?>\\n*|$)|\\n*|$)|\\n*|$)|)[\\s\\S]*?(?:(?:\\n[ \t]*)+\\n|$)|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ \t]*)+\\n|$)|(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ \t]*)+\\n|$))","i").replace("comment",k).replace("tag",g).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),d=r(c).replace("hr",l).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("|lheading","").replace("|table","").replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|textarea|!--)").replace("tag",g).getRegex(),x={blockquote:r(/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/).replace("paragraph",d).getRegex(),code:/^((?: {4}| {0,3}\t)[^\n]+(?:\n(?:[ \t]*(?:\n|$))*)?)+/,def:p,fences:/^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/,heading:/^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,hr:l,html:f,lheading:a,list:u,newline:/^(?:[ \t]*(?:\n|$))+/,paragraph:d,table:s,text:/^[^\n]+/},b=r("^ *([^\\n ].*)\\n {0,3}((?:\\| *)?:?-+:? *(?:\\| *:?-+:? *)*(?:\\| *)?)(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)").replace("hr",l).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("blockquote"," {0,3}>").replace("code","(?: {4}| {0,3}\t)[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|textarea|!--)").replace("tag",g).getRegex(),w={...x,table:b,paragraph:r(c).replace("hr",l).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("|lheading","").replace("table",b).replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|textarea|!--)").replace("tag",g).getRegex()},m={...x,html:r("^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+? *(?:\\n{2,}|\\s*$)|\\s]*)*?/?> *(?:\\n{2,}|\\s*$))").replace("comment",k).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,heading:/^(#{1,6})(.*)(?:\n+|$)/,fences:s,lheading:/^(.+?)\n {0,3}(=+|-+) *(?:\n+|$)/,paragraph:r(c).replace("hr",l).replace("heading"," *#{1,6} *[^\n]").replace("lheading",a).replace("|table","").replace("blockquote"," {0,3}>").replace("|fences","").replace("|list","").replace("|html","").replace("|tag","").getRegex()},y=/^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,$=/^( {2,}|\\)\n(?!\s*$)/,R=/[\p{P}\p{S}]/u,S=/[\s\p{P}\p{S}]/u,T=/[^\s\p{P}\p{S}]/u,z=r(/^((?![*_])punctSpace)/,"u").replace(/punctSpace/g,S).getRegex(),A=r(/^(?:\*+(?:((?!\*)punct)|[^\s*]))|^_+(?:((?!_)punct)|([^\s_]))/,"u").replace(/punct/g,R).getRegex(),_=r("^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\*)punct(\\*+)(?=[\\s]|$)|notPunctSpace(\\*+)(?!\\*)(?=punctSpace|$)|(?!\\*)punctSpace(\\*+)(?=notPunctSpace)|[\\s](\\*+)(?!\\*)(?=punct)|(?!\\*)punct(\\*+)(?!\\*)(?=punct)|notPunctSpace(\\*+)(?=notPunctSpace)","gu").replace(/notPunctSpace/g,T).replace(/punctSpace/g,S).replace(/punct/g,R).getRegex(),P=r("^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)punct(_+)(?=[\\s]|$)|notPunctSpace(_+)(?!_)(?=punctSpace|$)|(?!_)punctSpace(_+)(?=notPunctSpace)|[\\s](_+)(?!_)(?=punct)|(?!_)punct(_+)(?!_)(?=punct)","gu").replace(/notPunctSpace/g,T).replace(/punctSpace/g,S).replace(/punct/g,R).getRegex(),I=r(/\\(punct)/,"gu").replace(/punct/g,R).getRegex(),L=r(/^<(scheme:[^\s\x00-\x1f<>]*|email)>/).replace("scheme",/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/).replace("email",/[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/).getRegex(),B=r(k).replace("(?:--\x3e|$)","--\x3e").getRegex(),C=r("^comment|^|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^|^").replace("comment",B).replace("attribute",/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/).getRegex(),E=/(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/,q=r(/^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/).replace("label",E).replace("href",/<(?:\\.|[^\n<>\\])+>|[^\s\x00-\x1f]*/).replace("title",/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/).getRegex(),Z=r(/^!?\[(label)\]\[(ref)\]/).replace("label",E).replace("ref",h).getRegex(),v=r(/^!?\[(ref)\](?:\[\])?/).replace("ref",h).getRegex(),D={_backpedal:s,anyPunctuation:I,autolink:L,blockSkip:/\[[^[\]]*?\]\((?:\\.|[^\\\(\)]|\((?:\\.|[^\\\(\)])*\))*\)|`[^`]*?`|<[^<>]*?>/g,br:$,code:/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,del:s,emStrongLDelim:A,emStrongRDelimAst:_,emStrongRDelimUnd:P,escape:y,link:q,nolink:v,punctuation:z,reflink:Z,reflinkSearch:r("reflink|nolink(?!\\()","g").replace("reflink",Z).replace("nolink",v).getRegex(),tag:C,text:/^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\":">",'"':""","'":"'"},H=e=>G[e];function X(e,t){if(t){if(i.escapeTest.test(e))return e.replace(i.escapeReplace,H)}else if(i.escapeTestNoEncode.test(e))return e.replace(i.escapeReplaceNoEncode,H);return e}function F(e){try{e=encodeURI(e).replace(i.percentDecode,"%")}catch{return null}return e}function U(e,t){const n=e.replace(i.findPipe,((e,t,n)=>{let s=!1,r=t;for(;--r>=0&&"\\"===n[r];)s=!s;return s?"|":" |"})).split(i.splitPipe);let s=0;if(n[0].trim()||n.shift(),n.length>0&&!n.at(-1)?.trim()&&n.pop(),t)if(n.length>t)n.splice(t);else for(;n.length0)return{type:"space",raw:t[0]}}code(e){const t=this.rules.block.code.exec(e);if(t){const e=t[0].replace(this.rules.other.codeRemoveIndent,"");return{type:"code",raw:t[0],codeBlockStyle:"indented",text:this.options.pedantic?e:J(e,"\n")}}}fences(e){const t=this.rules.block.fences.exec(e);if(t){const e=t[0],n=function(e,t,n){const s=e.match(n.other.indentCodeCompensation);if(null===s)return t;const r=s[1];return t.split("\n").map((e=>{const t=e.match(n.other.beginningSpace);if(null===t)return e;const[s]=t;return s.length>=r.length?e.slice(r.length):e})).join("\n")}(e,t[3]||"",this.rules);return{type:"code",raw:e,lang:t[2]?t[2].trim().replace(this.rules.inline.anyPunctuation,"$1"):t[2],text:n}}}heading(e){const t=this.rules.block.heading.exec(e);if(t){let e=t[2].trim();if(this.rules.other.endingHash.test(e)){const t=J(e,"#");this.options.pedantic?e=t.trim():t&&!this.rules.other.endingSpaceChar.test(t)||(e=t.trim())}return{type:"heading",raw:t[0],depth:t[1].length,text:e,tokens:this.lexer.inline(e)}}}hr(e){const t=this.rules.block.hr.exec(e);if(t)return{type:"hr",raw:J(t[0],"\n")}}blockquote(e){const t=this.rules.block.blockquote.exec(e);if(t){let e=J(t[0],"\n").split("\n"),n="",s="";const r=[];for(;e.length>0;){let t=!1;const i=[];let l;for(l=0;l1,r={type:"list",raw:"",ordered:s,start:s?+n.slice(0,-1):"",loose:!1,items:[]};n=s?`\\d{1,9}\\${n.slice(-1)}`:`\\${n}`,this.options.pedantic&&(n=s?n:"[*+-]");const i=this.rules.other.listItemRegex(n);let l=!1;for(;e;){let n=!1,s="",o="";if(!(t=i.exec(e)))break;if(this.rules.block.hr.test(e))break;s=t[0],e=e.substring(s.length);let a=t[2].split("\n",1)[0].replace(this.rules.other.listReplaceTabs,(e=>" ".repeat(3*e.length))),c=e.split("\n",1)[0],h=!a.trim(),p=0;if(this.options.pedantic?(p=2,o=a.trimStart()):h?p=t[1].length+1:(p=t[2].search(this.rules.other.nonSpaceChar),p=p>4?1:p,o=a.slice(p),p+=t[1].length),h&&this.rules.other.blankLine.test(c)&&(s+=c+"\n",e=e.substring(c.length+1),n=!0),!n){const t=this.rules.other.nextBulletRegex(p),n=this.rules.other.hrRegex(p),r=this.rules.other.fencesBeginRegex(p),i=this.rules.other.headingBeginRegex(p),l=this.rules.other.htmlBeginRegex(p);for(;e;){const u=e.split("\n",1)[0];let g;if(c=u,this.options.pedantic?(c=c.replace(this.rules.other.listReplaceNesting," "),g=c):g=c.replace(this.rules.other.tabCharGlobal," "),r.test(c))break;if(i.test(c))break;if(l.test(c))break;if(t.test(c))break;if(n.test(c))break;if(g.search(this.rules.other.nonSpaceChar)>=p||!c.trim())o+="\n"+g.slice(p);else{if(h)break;if(a.replace(this.rules.other.tabCharGlobal," ").search(this.rules.other.nonSpaceChar)>=4)break;if(r.test(a))break;if(i.test(a))break;if(n.test(a))break;o+="\n"+c}h||c.trim()||(h=!0),s+=u+"\n",e=e.substring(u.length+1),a=g.slice(p)}}r.loose||(l?r.loose=!0:this.rules.other.doubleBlankLine.test(s)&&(l=!0));let u,g=null;this.options.gfm&&(g=this.rules.other.listIsTask.exec(o),g&&(u="[ ] "!==g[0],o=o.replace(this.rules.other.listReplaceTask,""))),r.items.push({type:"list_item",raw:s,task:!!g,checked:u,loose:!1,text:o,tokens:[]}),r.raw+=s}const o=r.items.at(-1);if(!o)return;o.raw=o.raw.trimEnd(),o.text=o.text.trimEnd(),r.raw=r.raw.trimEnd();for(let e=0;e"space"===e.type)),n=t.length>0&&t.some((e=>this.rules.other.anyLine.test(e.raw)));r.loose=n}if(r.loose)for(let e=0;e({text:e,tokens:this.lexer.inline(e),header:!1,align:i.align[t]}))));return i}}lheading(e){const t=this.rules.block.lheading.exec(e);if(t)return{type:"heading",raw:t[0],depth:"="===t[2].charAt(0)?1:2,text:t[1],tokens:this.lexer.inline(t[1])}}paragraph(e){const t=this.rules.block.paragraph.exec(e);if(t){const e="\n"===t[1].charAt(t[1].length-1)?t[1].slice(0,-1):t[1];return{type:"paragraph",raw:t[0],text:e,tokens:this.lexer.inline(e)}}}text(e){const t=this.rules.block.text.exec(e);if(t)return{type:"text",raw:t[0],text:t[0],tokens:this.lexer.inline(t[0])}}escape(e){const t=this.rules.inline.escape.exec(e);if(t)return{type:"escape",raw:t[0],text:t[1]}}tag(e){const t=this.rules.inline.tag.exec(e);if(t)return!this.lexer.state.inLink&&this.rules.other.startATag.test(t[0])?this.lexer.state.inLink=!0:this.lexer.state.inLink&&this.rules.other.endATag.test(t[0])&&(this.lexer.state.inLink=!1),!this.lexer.state.inRawBlock&&this.rules.other.startPreScriptTag.test(t[0])?this.lexer.state.inRawBlock=!0:this.lexer.state.inRawBlock&&this.rules.other.endPreScriptTag.test(t[0])&&(this.lexer.state.inRawBlock=!1),{type:"html",raw:t[0],inLink:this.lexer.state.inLink,inRawBlock:this.lexer.state.inRawBlock,block:!1,text:t[0]}}link(e){const t=this.rules.inline.link.exec(e);if(t){const e=t[2].trim();if(!this.options.pedantic&&this.rules.other.startAngleBracket.test(e)){if(!this.rules.other.endAngleBracket.test(e))return;const t=J(e.slice(0,-1),"\\");if((e.length-t.length)%2==0)return}else{const e=function(e,t){if(-1===e.indexOf(t[1]))return-1;let n=0;for(let s=0;s-1){const n=(0===t[0].indexOf("!")?5:4)+t[1].length+e;t[2]=t[2].substring(0,e),t[0]=t[0].substring(0,n).trim(),t[3]=""}}let n=t[2],s="";if(this.options.pedantic){const e=this.rules.other.pedanticHrefTitle.exec(n);e&&(n=e[1],s=e[3])}else s=t[3]?t[3].slice(1,-1):"";return n=n.trim(),this.rules.other.startAngleBracket.test(n)&&(n=this.options.pedantic&&!this.rules.other.endAngleBracket.test(e)?n.slice(1):n.slice(1,-1)),K(t,{href:n?n.replace(this.rules.inline.anyPunctuation,"$1"):n,title:s?s.replace(this.rules.inline.anyPunctuation,"$1"):s},t[0],this.lexer,this.rules)}}reflink(e,t){let n;if((n=this.rules.inline.reflink.exec(e))||(n=this.rules.inline.nolink.exec(e))){const e=t[(n[2]||n[1]).replace(this.rules.other.multipleSpaceGlobal," ").toLowerCase()];if(!e){const e=n[0].charAt(0);return{type:"text",raw:e,text:e}}return K(n,e,n[0],this.lexer,this.rules)}}emStrong(e,t,n=""){let s=this.rules.inline.emStrongLDelim.exec(e);if(!s)return;if(s[3]&&n.match(this.rules.other.unicodeAlphaNumeric))return;if(!(s[1]||s[2]||"")||!n||this.rules.inline.punctuation.exec(n)){const n=[...s[0]].length-1;let r,i,l=n,o=0;const a="*"===s[0][0]?this.rules.inline.emStrongRDelimAst:this.rules.inline.emStrongRDelimUnd;for(a.lastIndex=0,t=t.slice(-1*e.length+n);null!=(s=a.exec(t));){if(r=s[1]||s[2]||s[3]||s[4]||s[5]||s[6],!r)continue;if(i=[...r].length,s[3]||s[4]){l+=i;continue}if((s[5]||s[6])&&n%3&&!((n+i)%3)){o+=i;continue}if(l-=i,l>0)continue;i=Math.min(i,i+l+o);const t=[...s[0]][0].length,a=e.slice(0,n+s.index+t+i);if(Math.min(n,i)%2){const e=a.slice(1,-1);return{type:"em",raw:a,text:e,tokens:this.lexer.inlineTokens(e)}}const c=a.slice(2,-2);return{type:"strong",raw:a,text:c,tokens:this.lexer.inlineTokens(c)}}}}codespan(e){const t=this.rules.inline.code.exec(e);if(t){let e=t[2].replace(this.rules.other.newLineCharGlobal," ");const n=this.rules.other.nonSpaceChar.test(e),s=this.rules.other.startingSpaceChar.test(e)&&this.rules.other.endingSpaceChar.test(e);return n&&s&&(e=e.substring(1,e.length-1)),{type:"codespan",raw:t[0],text:e}}}br(e){const t=this.rules.inline.br.exec(e);if(t)return{type:"br",raw:t[0]}}del(e){const t=this.rules.inline.del.exec(e);if(t)return{type:"del",raw:t[0],text:t[2],tokens:this.lexer.inlineTokens(t[2])}}autolink(e){const t=this.rules.inline.autolink.exec(e);if(t){let e,n;return"@"===t[2]?(e=t[1],n="mailto:"+e):(e=t[1],n=e),{type:"link",raw:t[0],text:e,href:n,tokens:[{type:"text",raw:e,text:e}]}}}url(e){let t;if(t=this.rules.inline.url.exec(e)){let e,n;if("@"===t[2])e=t[0],n="mailto:"+e;else{let s;do{s=t[0],t[0]=this.rules.inline._backpedal.exec(t[0])?.[0]??""}while(s!==t[0]);e=t[0],n="www."===t[1]?"http://"+t[0]:t[0]}return{type:"link",raw:t[0],text:e,href:n,tokens:[{type:"text",raw:e,text:e}]}}}inlineText(e){const t=this.rules.inline.text.exec(e);if(t){const e=this.lexer.state.inRawBlock;return{type:"text",raw:t[0],text:t[0],escaped:e}}}}class W{tokens;options;state;tokenizer;inlineQueue;constructor(t){this.tokens=[],this.tokens.links=Object.create(null),this.options=t||e.defaults,this.options.tokenizer=this.options.tokenizer||new V,this.tokenizer=this.options.tokenizer,this.tokenizer.options=this.options,this.tokenizer.lexer=this,this.inlineQueue=[],this.state={inLink:!1,inRawBlock:!1,top:!0};const n={other:i,block:j.normal,inline:N.normal};this.options.pedantic?(n.block=j.pedantic,n.inline=N.pedantic):this.options.gfm&&(n.block=j.gfm,this.options.breaks?n.inline=N.breaks:n.inline=N.gfm),this.tokenizer.rules=n}static get rules(){return{block:j,inline:N}}static lex(e,t){return new W(t).lex(e)}static lexInline(e,t){return new W(t).inlineTokens(e)}lex(e){e=e.replace(i.carriageReturn,"\n"),this.blockTokens(e,this.tokens);for(let e=0;e!!(s=n.call({lexer:this},e,t))&&(e=e.substring(s.raw.length),t.push(s),!0))))continue;if(s=this.tokenizer.space(e)){e=e.substring(s.raw.length);const n=t.at(-1);1===s.raw.length&&void 0!==n?n.raw+="\n":t.push(s);continue}if(s=this.tokenizer.code(e)){e=e.substring(s.raw.length);const n=t.at(-1);"paragraph"===n?.type||"text"===n?.type?(n.raw+="\n"+s.raw,n.text+="\n"+s.text,this.inlineQueue.at(-1).src=n.text):t.push(s);continue}if(s=this.tokenizer.fences(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.heading(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.hr(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.blockquote(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.list(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.html(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.def(e)){e=e.substring(s.raw.length);const n=t.at(-1);"paragraph"===n?.type||"text"===n?.type?(n.raw+="\n"+s.raw,n.text+="\n"+s.raw,this.inlineQueue.at(-1).src=n.text):this.tokens.links[s.tag]||(this.tokens.links[s.tag]={href:s.href,title:s.title});continue}if(s=this.tokenizer.table(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.lheading(e)){e=e.substring(s.raw.length),t.push(s);continue}let r=e;if(this.options.extensions?.startBlock){let t=1/0;const n=e.slice(1);let s;this.options.extensions.startBlock.forEach((e=>{s=e.call({lexer:this},n),"number"==typeof s&&s>=0&&(t=Math.min(t,s))})),t<1/0&&t>=0&&(r=e.substring(0,t+1))}if(this.state.top&&(s=this.tokenizer.paragraph(r))){const i=t.at(-1);n&&"paragraph"===i?.type?(i.raw+="\n"+s.raw,i.text+="\n"+s.text,this.inlineQueue.pop(),this.inlineQueue.at(-1).src=i.text):t.push(s),n=r.length!==e.length,e=e.substring(s.raw.length)}else if(s=this.tokenizer.text(e)){e=e.substring(s.raw.length);const n=t.at(-1);"text"===n?.type?(n.raw+="\n"+s.raw,n.text+="\n"+s.text,this.inlineQueue.pop(),this.inlineQueue.at(-1).src=n.text):t.push(s)}else if(e){const t="Infinite loop on byte: "+e.charCodeAt(0);if(this.options.silent){console.error(t);break}throw new Error(t)}}return this.state.top=!0,t}inline(e,t=[]){return this.inlineQueue.push({src:e,tokens:t}),t}inlineTokens(e,t=[]){let n=e,s=null;if(this.tokens.links){const e=Object.keys(this.tokens.links);if(e.length>0)for(;null!=(s=this.tokenizer.rules.inline.reflinkSearch.exec(n));)e.includes(s[0].slice(s[0].lastIndexOf("[")+1,-1))&&(n=n.slice(0,s.index)+"["+"a".repeat(s[0].length-2)+"]"+n.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex))}for(;null!=(s=this.tokenizer.rules.inline.blockSkip.exec(n));)n=n.slice(0,s.index)+"["+"a".repeat(s[0].length-2)+"]"+n.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);for(;null!=(s=this.tokenizer.rules.inline.anyPunctuation.exec(n));)n=n.slice(0,s.index)+"++"+n.slice(this.tokenizer.rules.inline.anyPunctuation.lastIndex);let r=!1,i="";for(;e;){let s;if(r||(i=""),r=!1,this.options.extensions?.inline?.some((n=>!!(s=n.call({lexer:this},e,t))&&(e=e.substring(s.raw.length),t.push(s),!0))))continue;if(s=this.tokenizer.escape(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.tag(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.link(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.reflink(e,this.tokens.links)){e=e.substring(s.raw.length);const n=t.at(-1);"text"===s.type&&"text"===n?.type?(n.raw+=s.raw,n.text+=s.text):t.push(s);continue}if(s=this.tokenizer.emStrong(e,n,i)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.codespan(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.br(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.del(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.autolink(e)){e=e.substring(s.raw.length),t.push(s);continue}if(!this.state.inLink&&(s=this.tokenizer.url(e))){e=e.substring(s.raw.length),t.push(s);continue}let l=e;if(this.options.extensions?.startInline){let t=1/0;const n=e.slice(1);let s;this.options.extensions.startInline.forEach((e=>{s=e.call({lexer:this},n),"number"==typeof s&&s>=0&&(t=Math.min(t,s))})),t<1/0&&t>=0&&(l=e.substring(0,t+1))}if(s=this.tokenizer.inlineText(l)){e=e.substring(s.raw.length),"_"!==s.raw.slice(-1)&&(i=s.raw.slice(-1)),r=!0;const n=t.at(-1);"text"===n?.type?(n.raw+=s.raw,n.text+=s.text):t.push(s)}else if(e){const t="Infinite loop on byte: "+e.charCodeAt(0);if(this.options.silent){console.error(t);break}throw new Error(t)}}return t}}class Y{options;parser;constructor(t){this.options=t||e.defaults}space(e){return""}code({text:e,lang:t,escaped:n}){const s=(t||"").match(i.notSpaceStart)?.[0],r=e.replace(i.endingNewline,"")+"\n";return s?'
'+(n?r:X(r,!0))+"
\n":"
"+(n?r:X(r,!0))+"
\n"}blockquote({tokens:e}){return`
\n${this.parser.parse(e)}
\n`}html({text:e}){return e}heading({tokens:e,depth:t}){return`${this.parser.parseInline(e)}\n`}hr(e){return"
\n"}list(e){const t=e.ordered,n=e.start;let s="";for(let t=0;t\n"+s+"\n"}listitem(e){let t="";if(e.task){const n=this.checkbox({checked:!!e.checked});e.loose?"paragraph"===e.tokens[0]?.type?(e.tokens[0].text=n+" "+e.tokens[0].text,e.tokens[0].tokens&&e.tokens[0].tokens.length>0&&"text"===e.tokens[0].tokens[0].type&&(e.tokens[0].tokens[0].text=n+" "+X(e.tokens[0].tokens[0].text),e.tokens[0].tokens[0].escaped=!0)):e.tokens.unshift({type:"text",raw:n+" ",text:n+" ",escaped:!0}):t+=n+" "}return t+=this.parser.parse(e.tokens,!!e.loose),`
  • ${t}
  • \n`}checkbox({checked:e}){return"'}paragraph({tokens:e}){return`

    ${this.parser.parseInline(e)}

    \n`}table(e){let t="",n="";for(let t=0;t${s}`),"\n\n"+t+"\n"+s+"
    \n"}tablerow({text:e}){return`\n${e}\n`}tablecell(e){const t=this.parser.parseInline(e.tokens),n=e.header?"th":"td";return(e.align?`<${n} align="${e.align}">`:`<${n}>`)+t+`\n`}strong({tokens:e}){return`${this.parser.parseInline(e)}`}em({tokens:e}){return`${this.parser.parseInline(e)}`}codespan({text:e}){return`${X(e,!0)}`}br(e){return"
    "}del({tokens:e}){return`${this.parser.parseInline(e)}`}link({href:e,title:t,tokens:n}){const s=this.parser.parseInline(n),r=F(e);if(null===r)return s;let i='
    ",i}image({href:e,title:t,text:n}){const s=F(e);if(null===s)return X(n);let r=`${n}{const r=e[s].flat(1/0);n=n.concat(this.walkTokens(r,t))})):e.tokens&&(n=n.concat(this.walkTokens(e.tokens,t)))}}return n}use(...e){const t=this.defaults.extensions||{renderers:{},childTokens:{}};return e.forEach((e=>{const n={...e};if(n.async=this.defaults.async||n.async||!1,e.extensions&&(e.extensions.forEach((e=>{if(!e.name)throw new Error("extension name required");if("renderer"in e){const n=t.renderers[e.name];t.renderers[e.name]=n?function(...t){let s=e.renderer.apply(this,t);return!1===s&&(s=n.apply(this,t)),s}:e.renderer}if("tokenizer"in e){if(!e.level||"block"!==e.level&&"inline"!==e.level)throw new Error("extension level must be 'block' or 'inline'");const n=t[e.level];n?n.unshift(e.tokenizer):t[e.level]=[e.tokenizer],e.start&&("block"===e.level?t.startBlock?t.startBlock.push(e.start):t.startBlock=[e.start]:"inline"===e.level&&(t.startInline?t.startInline.push(e.start):t.startInline=[e.start]))}"childTokens"in e&&e.childTokens&&(t.childTokens[e.name]=e.childTokens)})),n.extensions=t),e.renderer){const t=this.defaults.renderer||new Y(this.defaults);for(const n in e.renderer){if(!(n in t))throw new Error(`renderer '${n}' does not exist`);if(["options","parser"].includes(n))continue;const s=n,r=e.renderer[s],i=t[s];t[s]=(...e)=>{let n=r.apply(t,e);return!1===n&&(n=i.apply(t,e)),n||""}}n.renderer=t}if(e.tokenizer){const t=this.defaults.tokenizer||new V(this.defaults);for(const n in e.tokenizer){if(!(n in t))throw new Error(`tokenizer '${n}' does not exist`);if(["options","rules","lexer"].includes(n))continue;const s=n,r=e.tokenizer[s],i=t[s];t[s]=(...e)=>{let n=r.apply(t,e);return!1===n&&(n=i.apply(t,e)),n}}n.tokenizer=t}if(e.hooks){const t=this.defaults.hooks||new ne;for(const n in e.hooks){if(!(n in t))throw new Error(`hook '${n}' does not exist`);if(["options","block"].includes(n))continue;const s=n,r=e.hooks[s],i=t[s];ne.passThroughHooks.has(n)?t[s]=e=>{if(this.defaults.async)return Promise.resolve(r.call(t,e)).then((e=>i.call(t,e)));const n=r.call(t,e);return i.call(t,n)}:t[s]=(...e)=>{let n=r.apply(t,e);return!1===n&&(n=i.apply(t,e)),n}}n.hooks=t}if(e.walkTokens){const t=this.defaults.walkTokens,s=e.walkTokens;n.walkTokens=function(e){let n=[];return n.push(s.call(this,e)),t&&(n=n.concat(t.call(this,e))),n}}this.defaults={...this.defaults,...n}})),this}setOptions(e){return this.defaults={...this.defaults,...e},this}lexer(e,t){return W.lex(e,t??this.defaults)}parser(e,t){return te.parse(e,t??this.defaults)}parseMarkdown(e){return(t,n)=>{const s={...n},r={...this.defaults,...s},i=this.onError(!!r.silent,!!r.async);if(!0===this.defaults.async&&!1===s.async)return i(new Error("marked(): The async option was set to true by an extension. Remove async: false from the parse options object to return a Promise."));if(null==t)return i(new Error("marked(): input parameter is undefined or null"));if("string"!=typeof t)return i(new Error("marked(): input parameter is of type "+Object.prototype.toString.call(t)+", string expected"));r.hooks&&(r.hooks.options=r,r.hooks.block=e);const l=r.hooks?r.hooks.provideLexer():e?W.lex:W.lexInline,o=r.hooks?r.hooks.provideParser():e?te.parse:te.parseInline;if(r.async)return Promise.resolve(r.hooks?r.hooks.preprocess(t):t).then((e=>l(e,r))).then((e=>r.hooks?r.hooks.processAllTokens(e):e)).then((e=>r.walkTokens?Promise.all(this.walkTokens(e,r.walkTokens)).then((()=>e)):e)).then((e=>o(e,r))).then((e=>r.hooks?r.hooks.postprocess(e):e)).catch(i);try{r.hooks&&(t=r.hooks.preprocess(t));let e=l(t,r);r.hooks&&(e=r.hooks.processAllTokens(e)),r.walkTokens&&this.walkTokens(e,r.walkTokens);let n=o(e,r);return r.hooks&&(n=r.hooks.postprocess(n)),n}catch(e){return i(e)}}}onError(e,t){return n=>{if(n.message+="\nPlease report this to https://github.com/markedjs/marked.",e){const e="

    An error occurred:

    "+X(n.message+"",!0)+"
    ";return t?Promise.resolve(e):e}if(t)return Promise.reject(n);throw n}}}const re=new se;function ie(e,t){return re.parse(e,t)}ie.options=ie.setOptions=function(e){return re.setOptions(e),ie.defaults=re.defaults,n(ie.defaults),ie},ie.getDefaults=t,ie.defaults=e.defaults,ie.use=function(...e){return re.use(...e),ie.defaults=re.defaults,n(ie.defaults),ie},ie.walkTokens=function(e,t){return re.walkTokens(e,t)},ie.parseInline=re.parseInline,ie.Parser=te,ie.parser=te.parse,ie.Renderer=Y,ie.TextRenderer=ee,ie.Lexer=W,ie.lexer=W.lex,ie.Tokenizer=V,ie.Hooks=ne,ie.parse=ie;const le=ie.options,oe=ie.setOptions,ae=ie.use,ce=ie.walkTokens,he=ie.parseInline,pe=ie,ue=te.parse,ge=W.lex;e.Hooks=ne,e.Lexer=W,e.Marked=se,e.Parser=te,e.Renderer=Y,e.TextRenderer=ee,e.Tokenizer=V,e.getDefaults=t,e.lexer=ge,e.marked=ie,e.options=le,e.parse=pe,e.parseInline=he,e.parser=ue,e.setOptions=oe,e.use=ae,e.walkTokens=ce})); 7 | --------------------------------------------------------------------------------