UNPKG

expressive-code-twoslash

Version:

Add Twoslash support to your Expressive Code TypeScript code blocks.

1,186 lines 95.5 kB
import path from "node:path"; import { ExpressiveCodeAnnotation, PluginStyleSettings, definePlugin, lighten, toHexColor } from "@expressive-code/core"; import { ExpressiveCode } from "expressive-code"; import ts from "typescript"; import { h } from "@expressive-code/core/hast"; import { fromMarkdown } from "mdast-util-from-markdown"; import { gfmFromMarkdown } from "mdast-util-gfm"; import { toHast } from "mdast-util-to-hast"; import fs from "node:fs"; import tsParser from "@typescript-eslint/parser"; import { css, stylesheet } from "css-js-gen"; //#region src/helpers/comparisons.ts /** * Checks if the given node is of type `NodeCompletion`. * * @param node - The node to check. * @returns True if the node is of type `NodeCompletion`, otherwise false. */ function isNodeCompletion(node) { return node.type === "completion"; } /** * Compares two TwoslashNode objects based on specified criteria. * * @param node1 - The first TwoslashNode to compare. * @param node2 - The second TwoslashNode to compare. * @param checks - An object specifying which properties to check for equality. * @param checks.line - If true, compares the line property of the nodes. * @param checks.start - If true, compares the start property of the nodes. * @param checks.character - If true, compares the character property of the nodes. * @param checks.length - If true, compares the length property of the nodes. * @param checks.text - If true, compares the text property of the nodes. * @returns A boolean indicating whether the nodes are considered equal based on the specified criteria. */ function compareNodes(node1, node2, checks) { if (checks.line && node1.line !== node2.line) return false; if (checks.start && node1.start !== node2.start) return false; if (checks.character && node1.character !== node2.character) return false; if (checks.length && node1.length !== node2.length) return false; if (!isNodeCompletion(node1) && !isNodeCompletion(node2) && checks.text && node1.text !== node2.text) return false; return true; } //#endregion //#region src/helpers/ec-config.ts /** * Generates an ExpressiveCodeConfig object based on the provided ResolvedExpressiveCodeEngineConfig. * * @param config - The resolved configuration object for the Expressive Code Engine. * @returns An ExpressiveCodeConfig object with properties derived from the input config. */ const ecConfig = (config) => { return { cascadeLayer: config.cascadeLayer, customizeTheme: config.customizeTheme, defaultLocale: config.defaultLocale, defaultProps: config.defaultProps, logger: config.logger, minSyntaxHighlightingColorContrast: config.minSyntaxHighlightingColorContrast, styleOverrides: config.styleOverrides, themeCssRoot: config.themeCssRoot, themeCssSelector: config.themeCssSelector, themes: config.themes, useDarkModeMediaQuery: config.useDarkModeMediaQuery, useStyleReset: config.useStyleReset, useThemedScrollbars: config.useThemedScrollbars, useThemedSelectionColors: config.useThemedSelectionColors, frames: { showCopyToClipboardButton: false, extractFileNameFromCode: false } }; }; //#endregion //#region src/helpers/includes.ts var TwoslashIncludesManager = class { constructor(map = /* @__PURE__ */ new Map()) { this.map = map; } add(name, code) { const lines = []; code.split("\n").forEach((l, _i) => { const trimmed = l.trim(); if (trimmed.startsWith("// - ")) { const key = trimmed.split("// - ")[1].split(" ")[0]; this.map.set(`${name}-${key}`, lines.join("\n")); } else lines.push(l); }); this.map.set(name, lines.join("\n")); } applyInclude(code) { const reMarker = /\/\/ @include: (.*)$/gm; const toReplace = []; for (const match of code.matchAll(reMarker)) { const key = match[1]; const replaceWith = this.map.get(key); if (!replaceWith) { const msg = `Could not find an include with the key: '${key}'.\nThere is: ${Array.from(this.map.keys())}.`; throw new Error(msg); } toReplace.push([ match.index, match[0].length, replaceWith ]); } let newCode = code.toString(); for (const [index, length, replacementCode] of toReplace.reverse()) newCode = newCode.slice(0, index) + replacementCode + newCode.slice(index + length); return newCode; } }; /** * An "include [name]" segment in a raw meta string has a "name" that is a sequence of word * characters, possibly connected by dashes, that ends at a word boundary. */ const INCLUDE_META_REGEX = /include\s+([\w-]+)\b.*/; /** * @param meta The raw meta string of a code block, e.g. 'twoslash include main-hello-world meta=miscellaneous'. * @returns The name of the reusable code block, e.g. "main-hello-world", if it exists. */ function parseIncludeMeta(meta) { if (!meta) return null; return meta.match(INCLUDE_META_REGEX)?.[1] ?? null; } //#endregion //#region src/icons/completionIcons.ts const completionIcons = { module: h("svg", { viewBox: "0 0 32 32", width: "1rem", height: "auto" }, [ h("path", { fill: "currentColor", d: "M11 2H2v9h2V4h7V2z" }, []), h("path", { fill: "currentColor", d: "M2 21v9h9v-2H4v-7H2z" }, []), h("path", { fill: "currentColor", d: "M30 11V2h-9v2h7v7h2z" }, []), h("path", { fill: "currentColor", d: "M21 30h9v-9h-2v7h-7v2z" }, []), h("path", { fill: "currentColor", d: "M25.49 10.13l-9-5a1 1 0 0 0-1 0l-9 5A1 1 0 0 0 6 11v10a1 1 0 0 0 .51.87l9 5a1 1 0 0 0 1 0l9-5A1 1 0 0 0 26 21V11a1 1 0 0 0-.51-.87zM16 7.14L22.94 11L16 14.86L9.06 11zM8 12.7l7 3.89v7.71l-7-3.89zm9 11.6v-7.71l7-3.89v7.71z" }, []) ]), class: h("svg", { viewBox: "0 0 32 32", width: "1rem", height: "auto" }, [h("path", { fill: "currentColor", d: "M26 16a3.961 3.961 0 0 0-2.02.566l-2.859-2.859l2.293-2.293a2 2 0 0 0 0-2.828l-6-6a2 2 0 0 0-2.828 0l-6 6a2 2 0 0 0 0 2.828l2.293 2.293l-2.859 2.859a4.043 4.043 0 1 0 1.414 1.414l2.859-2.859l2.293 2.293a1.977 1.977 0 0 0 .414.31V22h-3v8h8v-8h-3v-4.277a1.977 1.977 0 0 0 .414-.309l2.293-2.293l2.859 2.859A3.989 3.989 0 1 0 26 16M8 20a2 2 0 1 1-2-2a2.002 2.002 0 0 1 2 2m10 4v4h-4v-4zm-2-8l-6-6l6-6l6 6Zm10 6a2 2 0 1 1 2-2a2.002 2.002 0 0 1-2 2" }, [])]), method: h("svg", { viewBox: "0 0 32 32", width: "1rem", height: "auto" }, [ h("path", { fill: "currentColor", d: "m19.626 29.526l-.516-1.933a12.004 12.004 0 0 0 6.121-19.26l1.538-1.28a14.003 14.003 0 0 1-7.143 22.473" }, []), h("path", { fill: "currentColor", d: "M10 29H8v-3.82l.804-.16C10.262 24.727 12 23.62 12 20v-1.382l-4-2v-2.236l4-2V12c0-5.467 3.925-9 10-9h2v3.82l-.804.16C21.738 7.273 20 8.38 20 12v.382l4 2v2.236l-4 2V20c0 5.467-3.925 9-10 9m0-2c4.935 0 8-2.682 8-7v-2.618l3.764-1.882L18 13.618V12c0-4.578 2.385-6.192 4-6.76V5c-4.935 0-8 2.682-8 7v1.618L10.236 15.5L14 17.382V20c0 4.578-2.385 6.192-4 6.76Z" }, []), h("path", { fill: "currentColor", d: "M5.231 24.947a14.003 14.003 0 0 1 7.147-22.474l.516 1.932a12.004 12.004 0 0 0-6.125 19.263Z" }, []) ]), property: h("svg", { viewBox: "0 0 32 32", width: "1rem", height: "auto" }, [h("path", { fill: "currentColor", d: "M12.1 2a9.8 9.8 0 0 0-5.4 1.6l6.4 6.4a2.1 2.1 0 0 1 .2 3a2.1 2.1 0 0 1-3-.2L3.7 6.4A9.84 9.84 0 0 0 2 12.1a10.14 10.14 0 0 0 10.1 10.1a10.9 10.9 0 0 0 2.6-.3l6.7 6.7a5 5 0 0 0 7.1-7.1l-6.7-6.7a10.9 10.9 0 0 0 .3-2.6A10 10 0 0 0 12.1 2m8 10.1a7.61 7.61 0 0 1-.3 2.1l-.3 1.1l.8.8l6.7 6.7a2.88 2.88 0 0 1 .9 2.1A2.72 2.72 0 0 1 27 27a2.9 2.9 0 0 1-4.2 0l-6.7-6.7l-.8-.8l-1.1.3a7.61 7.61 0 0 1-2.1.3a8.27 8.27 0 0 1-5.7-2.3A7.63 7.63 0 0 1 4 12.1a8.33 8.33 0 0 1 .3-2.2l4.4 4.4a4.14 4.14 0 0 0 5.9.2a4.14 4.14 0 0 0-.2-5.9L10 4.2a6.45 6.45 0 0 1 2-.3a8.27 8.27 0 0 1 5.7 2.3a8.49 8.49 0 0 1 2.4 5.9" }, [])]), constructor: h("svg", { viewBox: "0 0 32 32", width: "1rem", height: "auto" }, [h("path", { fill: "currentColor", d: "M21.49 13.115l-9-5a1 1 0 0 0-1 0l-9 5A1.008 1.008 0 0 0 2 14v9.995a1 1 0 0 0 .52.87l9 5A1.004 1.004 0 0 0 12 30a1.056 1.056 0 0 0 .49-.135l9-5A.992.992 0 0 0 22 24V14a1.008 1.008 0 0 0-.51-.885zM11 27.295l-7-3.89v-7.72l7 3.89zm1-9.45L5.06 14L12 10.135l6.94 3.86zm8 5.56l-7 3.89v-7.72l7-3.89z" }, []), h("path", { fill: "currentColor", d: "M30 6h-4V2h-2v4h-4v2h4v4h2V8h4V6z" }, [])]), interface: h("svg", { viewBox: "0 0 32 32", width: "1rem", height: "auto" }, [h("path", { fill: "currentColor", d: "M23 16.01a7 7 0 0 0-4.18 1.39l-4.22-4.22A6.86 6.86 0 0 0 16 9.01a7 7 0 1 0-2.81 5.59l4.21 4.22a7 7 0 1 0 5.6-2.81m-19-7a5 5 0 1 1 5 5a5 5 0 0 1-5-5" }, [])]), function: h("svg", { viewBox: "0 0 32 32", width: "1rem", height: "auto" }, [ h("path", { fill: "currentColor", d: "m19.626 29.526l-.516-1.933a12.004 12.004 0 0 0 6.121-19.26l1.538-1.28a14.003 14.003 0 0 1-7.143 22.473" }, []), h("path", { fill: "currentColor", d: "M10 29H8v-3.82l.804-.16C10.262 24.727 12 23.62 12 20v-1.382l-4-2v-2.236l4-2V12c0-5.467 3.925-9 10-9h2v3.82l-.804.16C21.738 7.273 20 8.38 20 12v.382l4 2v2.236l-4 2V20c0 5.467-3.925 9-10 9m0-2c4.935 0 8-2.682 8-7v-2.618l3.764-1.882L18 13.618V12c0-4.578 2.385-6.192 4-6.76V5c-4.935 0-8 2.682-8 7v1.618L10.236 15.5L14 17.382V20c0 4.578-2.385 6.192-4 6.76Z" }, []), h("path", { fill: "currentColor", d: "M5.231 24.947a14.003 14.003 0 0 1 7.147-22.474l.516 1.932a12.004 12.004 0 0 0-6.125 19.263Z" }, []) ]), string: h("svg", { viewBox: "0 0 32 32", width: "1rem", height: "auto" }, [h("path", { fill: "currentColor", d: "M29 22h-5a2.003 2.003 0 0 1-2-2v-6a2.002 2.002 0 0 1 2-2h5v2h-5v6h5zM18 12h-4V8h-2v14h6a2.003 2.003 0 0 0 2-2v-6a2.002 2.002 0 0 0-2-2m-4 8v-6h4v6zm-6-8H3v2h5v2H4a2 2 0 0 0-2 2v2a2 2 0 0 0 2 2h6v-8a2.002 2.002 0 0 0-2-2m0 8H4v-2h4z" }, [])]) }; //#endregion //#region src/helpers/processors.ts /** * Splits the given code string into an array of objects, each containing the line index and the line content. * * @param code - The code string to be split into lines. * @returns An array of objects, each with an `index` representing the line number and a `line` containing the line content. */ function splitCodeToLines(code) { return code.split("\n").map((line, index) => ({ index, line })); } /** * Processes a code block by replacing its content with the provided Twoslash code block. * * @param codeBlock - The ExpressiveCodeBlock instance representing the code block to be processed. * @param codeWithIncludes - The original code block content including any includes. * @param twoslashCode - The Twoslash code block to replace the original content with. */ function processTwoslashCodeBlock(codeBlock, codeWithIncludes, twoslashCode) { const ecCodeBlock = splitCodeToLines(codeWithIncludes); const twoslashCodeBlock = splitCodeToLines(twoslashCode); for (const line of twoslashCodeBlock) { const ln = codeBlock.getLine(line.index); if (ln) ln.editText(0, ln.text.length, line.line); } if (twoslashCodeBlock.length < ecCodeBlock.length) { for (let i = ecCodeBlock.length - 1; i >= twoslashCodeBlock.length; i--) if (codeBlock.getLine(i)) codeBlock.deleteLine(i); } } /** * Processes a NodeCompletion object and returns a CompletionItem. * * @param completion - The NodeCompletion object to process. * @returns A CompletionItem containing the processed completion data. */ function processCompletion(completion) { const items = completion.completions.map((c) => { const kind = c.kind || "property"; const isDeprecated = "kindModifiers" in c && typeof c.kindModifiers === "string" && c.kindModifiers.split(",").includes("deprecated"); const icon = completionIcons[kind]; return { name: c.name, kind, icon, isDeprecated }; }).slice(0, 5); const { character, start, completionsPrefix } = completion; return { startCharacter: character, completionsPrefix, start, length: start - character, items }; } //#endregion //#region src/helpers/regex.ts /** * Default tags used in the twoslash plugin. * * @constant * @default ["annotate", "log", "warn", "error"] */ const twoslashDefaultTags = [ "annotate", "log", "warn", "error" ]; /** * Regular expression to match the word "twoslash" as a whole word. * * @constant {RegExp} reTrigger - The regular expression pattern. * @type {RegExp} */ const reTrigger = /\btwoslash\b/; /** * A regular expression to match and clean up type annotations. * * This regular expression matches strings that start with an uppercase letter, * followed by any word characters, and optionally a generic type parameter enclosed in angle brackets. * The matched string ends with a colon. * * Example matches: * - `TypeName:` * - `GenericType<T>:` * * @constant {RegExp} reTypeCleanup - The regular expression pattern. * @type {RegExp} */ const reTypeCleanup = /^[A-Z]\w*(<[^>]*>)?:/; /** * Regular expression to match the beginning of a function call. * It matches any word characters followed by an opening parenthesis. * * @constant {RegExp} reFunctionCleanup - The regular expression pattern. * @type {RegExp} */ const reFunctionCleanup = /^\w*\(/; /** * Regular expression to match leading property method annotations. * * This regex matches lines that start with an optional whitespace, followed by an opening parenthesis, * and then any word characters or hyphens. The matched string ends with a closing parenthesis and optional whitespace. * * Example matches: * - `(property) ` * - `(method) ` * * @constant {RegExp} reLeadingPropertyMethod - The regular expression pattern. * @type {RegExp} */ const reLeadingPropertyMethod = /^\(([\w-]+)\)\s+/gm; /** * Regular expression to match import statements. * * This regex matches lines that start with `import` followed by any characters until the end of the line. * * @constant {RegExp} reImportStatement - The regular expression pattern. * @type {RegExp} */ const reImportStatement = /\nimport .*$/; /** * Regular expression to match interface or namespace declarations. * * This regex matches lines that start with `interface` or `namespace` followed by a space and any word characters. * * @constant {RegExp} reInterfaceOrNamespace - The regular expression pattern. * @type {RegExp} */ const reInterfaceOrNamespace = /^(interface|namespace) \w+$/gm; /** * Regular expression to match JSDoc links. * * This regex matches `{@link ...}` patterns in a string. * * @constant {RegExp} reJsDocLink - The regular expression pattern. * @type {RegExp} */ const reJsDocLink = /\{@link ([^}]*)\}/g; /** * Regular expression to match JSDoc tag filters. * * @constant {RegExp} reJsDocTagFilter - The regular expression pattern. * @type {RegExp} */ const reJsDocTagFilter = /\b(example|description)\b/; const jsdocTags = [ "abstract", "access", "alias", "async", "augments", "author", "borrows", "callback", "class", "classdesc", "constant", "constructs", "copyright", "default", "deprecated", "description", "enum", "event", "example", "exports", "external", "file", "fires", "function", "generator", "global", "hideconstructor", "ignore", "implements", "inheritdoc", "inner", "instance", "interface", "kind", "lends", "license", "listens", "member", "memberof", "mixes", "mixin", "module", "name", "namespace", "override", "package", "param", "private", "property", "protected", "public", "readonly", "requires", "returns", "see", "since", "static", "summary", "this", "throws", "todo", "tutorial", "type", "typedef", "variation", "version", "yields" ]; //#endregion //#region src/helpers/rendering.ts /** * Renders markdown content with code blocks using ExpressiveCode. * * This function processes the given markdown string, converts it to an MDAST (Markdown Abstract Syntax Tree), * and then transforms it into HAST (Hypertext Abstract Syntax Tree) with custom handlers for code blocks. * It then uses ExpressiveCode to render the code blocks with syntax highlighting and other features. * * @param md - The markdown string to be processed. * @param ec - An instance of ExpressiveCode used to render the code blocks. * @returns A promise that resolves to an array of HAST nodes representing the processed markdown content. */ async function renderMarkdownWithCodeBlocks(md, ec) { const nodes = toHast(fromMarkdown(md.replace(reJsDocLink, "$1"), { mdastExtensions: [gfmFromMarkdown()] }), { handlers: { code: (_, node) => { const lang = node.lang || "plaintext"; return { type: "element", tagName: "div", properties: { class: "expressive-code", "data-lang": lang }, children: [{ type: "text", value: node.value }] }; } } }); const codeBlocks = nodes.children ? nodes.children.filter((node) => node.type === "element" && node.tagName === "div" && node.properties.class === "expressive-code") : []; for (const codeBlock of codeBlocks) if (codeBlock.type === "element") codeBlock.children = codeBlock.type === "element" && codeBlock.children[0].type === "text" ? (await ec.render({ code: codeBlock.children[0].value, language: codeBlock.properties["data-lang"] }).then((res) => { codeBlock.properties["data-lang"] = null; return res; })).renderedGroupAst.children : []; return nodes.children; } /** * Renders the given markdown string inline using the ExpressiveCode instance. * * This function processes the markdown string and returns the rendered children. * If the rendered children contain a single paragraph element, it returns the children of that paragraph. * Otherwise, it returns the entire rendered children array. * * @param md - The markdown string to be rendered. * @param ec - The ExpressiveCode instance used for rendering. * @returns A promise that resolves to the rendered children. */ async function renderMDInline(md, ec) { const children = await renderMarkdownWithCodeBlocks(md, ec); if (children.length === 1 && children[0].type === "element" && children[0].tagName === "p") return children[0].children; return children; } /** * Checks if the given markdown string consists of a single paragraph element. * * @param md - The markdown string to check. * @param filterTags - A boolean indicating whether to filter tags. * @returns A boolean indicating if the markdown string is a single paragraph element. */ async function checkIfSingleParagraph(md, filterTags, ec) { const children = await renderMDInline(md, ec); if (filterTags) return !(children.length === 1 && children[0].type === "element" && children[0].tagName === "p"); return false; } /** * The default hover info processor, which will do some basic cleanup */ function defaultHoverInfoProcessor(type) { let content = type.replace(reLeadingPropertyMethod, "").replace(reImportStatement, "").replace(reInterfaceOrNamespace, "").trim(); if (content.match(reTypeCleanup)) content = `type ${content}`; else if (content.match(reFunctionCleanup)) content = `function ${content}`; if (content.length === 0) return false; return content; } /** * Filters tags based on specific keywords. * * @param tag - The tag string to be checked. * @returns A boolean indicating whether the tag includes any of the specified keywords */ function filterTags(tag) { return !reJsDocTagFilter.test(tag); } /** * Renders the type information for the given text using the provided ExpressiveCode instance. * * @param text - The text to be processed and rendered. * @param ec - An instance of ExpressiveCode used for rendering the text. * @returns A promise that resolves to the rendered group AST. */ async function renderType(text, ec) { const info = defaultHoverInfoProcessor(text); if (typeof info === "string") { const { renderedGroupAst } = await ec.render({ code: info, language: "ts", meta: "" }); return renderedGroupAst; } const { renderedGroupAst } = await ec.render({ code: text, language: "ts", meta: "" }); return renderedGroupAst; } /** * Renders JSDoc comments for a given hover node. * * @param hover - The hover node containing documentation and tags. * @param includeJsDoc - A boolean indicating whether to include JSDoc comments. * @param ec - The ExpressiveCode instance used for rendering. * @returns A promise that resolves to an object containing rendered documentation and tags. */ async function renderJSDocs(hover, includeJsDoc, ec, allowNonStandardJsDocTags) { if (!includeJsDoc) return { docs: [], tags: [] }; return { docs: hover.docs ? h("div.twoslash-popup-docs", [h("p", hover.docs ? await renderMarkdownWithCodeBlocks(hover.docs, ec) : [])]) : [], tags: hover.tags ? h("div.twoslash-popup-docs.twoslash-popup-docs-tags", [...await Promise.all(hover.tags ? hover.tags.map(async (tag) => (allowNonStandardJsDocTags ? true : jsdocTags.includes(tag[0])) ? h("p.twoslash-popup-docs-tagline", [h("span.twoslash-popup-docs-tag-name", `@${tag[0]}`), tag[1] ? [await checkIfSingleParagraph(tag[1], filterTags(tag[0]), ec) ? " ― " : " ", h("span.twoslash-popup-docs-tag-value", await renderMDInline(tag[1], ec))] : []]) : []) : [])]) : [] }; } //#endregion //#region src/helpers/string-gen.ts /** * Returns a string representation of a custom tag. * * @param tag - The custom tag to convert to a string. Can be one of "warn", "annotate", or "log". * @returns A string that represents the custom tag. Returns "Warning" for "warn", "Message" for "annotate", * "Log" for "log", and "Error" for any other value. */ function getCustomTagString(tag) { switch (tag) { case "warn": return "Warning"; case "annotate": return "Message"; case "log": return "Log"; default: return "Error"; } } /** * Returns a custom CSS class name based on the provided TwoslashTag. * * @param tag - The TwoslashTag to get the custom class for. Possible values are "warn", "annotate", "log", or any other string. * @returns The corresponding CSS class name as a string. * - "twoslash-custom-level-warning" for "warn" * - "twoslash-custom-level-suggestion" for "annotate" * - "twoslash-custom-level-message" for "log" * - "twoslash-custom-level-error" for any other value */ function getCustomTagClass(tag) { switch (tag) { case "warn": return "twoslash-custom-level-warning"; case "annotate": return "twoslash-custom-level-suggestion"; case "log": return "twoslash-custom-level-message"; default: return "twoslash-custom-level-error"; } } /** * Returns a CSS class name based on the error level of the provided NodeError. * * @param error - The NodeError object containing the error level. * @returns A string representing the CSS class name corresponding to the error level. * * The possible error levels and their corresponding CSS class names are: * - "warning" -> "twoslash-error-level-warning" * - "suggestion" -> "twoslash-error-level-suggestion" * - "message" -> "twoslash-error-level-message" * - Any other value -> "twoslash-error-level-error" */ function getErrorLevelClass(error) { switch (error.level) { case "warning": return "twoslash-error-level-warning"; case "suggestion": return "twoslash-error-level-suggestion"; case "message": return "twoslash-error-level-message"; default: return "twoslash-error-level-error"; } } /** * Returns a string representation of the error level. * * @param error - The error object containing the level property. * @returns A string that represents the error level. Possible values are: * - "Warning" for level "warning" * - "Suggestion" for level "suggestion" * - "Message" for level "message" * - "Error" for any other level */ function getErrorLevelString(error) { switch (error.level) { case "warning": return "Warning"; case "suggestion": return "Suggestion"; case "message": return "Message"; default: return "Error"; } } //#endregion //#region src/helpers/utils.ts /** * Calculates the width of a given text in pixels based on the character location, font size, and character width. * * @param textLoc - The location of the text (number of characters). * @param fontSize - The font size in pixels. Defaults to 16. * @param charWidth - The width of a single character in pixels. Defaults to 8. * @returns The width of the text in pixels. */ function getTextWidthInPixels(textLoc, fontSize = 16, charWidth = 8) { return textLoc * charWidth * (fontSize / 16); } /** * Merges custom tags from the provided `twoslashOptions` with the default tags. * Ensures that there are no duplicate tags in the final list. * * @param twoslashOptions - The options object containing custom tags to be merged. * @returns A new `TwoslashOptions` object with merged custom tags. */ function checkForCustomTagsAndMerge(twoslashOptions) { const customTags = twoslashOptions?.customTags ?? []; const allTags = [...twoslashDefaultTags]; for (const tag of customTags) if (!allTags.includes(tag)) allTags.push(tag); return { ...twoslashOptions, customTags: allTags }; } const BuiltInTwoslashers = ["twoslash", "eslint"]; /** * Retrieves or creates a base Twoslash instance and caches it in the `TwoslasherMap` for future use. If an instance already exists for the "twoslash" key, it returns the cached instance; otherwise, it creates a new one using the provided options and stores it in the map before returning it. */ const getBaseTwoslasher = (opts, TwoslasherMap) => { const key = "twoslash"; const twoslasher = TwoslasherMap.get(key); if (!twoslasher) { const instance = async () => (await import("@ec-ts/twoslash")).createTwoslasher(opts); TwoslasherMap.set(key, instance); return instance; } return twoslasher; }; /** * Retrieves or creates a Twoslash instance specific to Vue and caches it in the `TwoslasherMap` for future use. If an instance already exists for the "twoslash-vue" key, it returns the cached instance; otherwise, it attempts to create a new one using the provided options and stores it in the map before returning it. If the module fails to load, it logs an error and throws a new error with a user-friendly message. */ const getVueTwoslasher = (opts, TwoslasherMap) => { const key = "twoslash-vue"; const twoslasher = TwoslasherMap.get(key); if (!twoslasher) try { const instance = async () => (await import("@ec-ts/twoslash-vue")).createTwoslasher(opts); TwoslasherMap.set(key, instance); return instance; } catch (error) { console.error("Failed to load twoslash-vue:", error); throw new Error("Failed to load twoslash-vue. Please ensure vue is installed and try again."); } return twoslasher; }; /** * Retrieves or creates a Twoslash instance specific to ESLint and caches it in the `TwoslasherMap` for future use. If an instance already exists for the "eslint" key, it returns the cached instance; otherwise, it attempts to create a new one using the provided options and stores it in the map before returning it. If the module fails to load, it logs an error and throws a new error with a user-friendly message. */ const getEslintTwoslasher = (opts, TwoslasherMap) => { const key = "eslint"; const twoslasher = TwoslasherMap.get(key); if (!twoslasher) try { const instance = async () => (await import("twoslash-eslint")).createTwoslasher(opts); TwoslasherMap.set(key, instance); return instance; } catch (error) { console.error("Failed to load twoslash-eslint:", error); throw new Error("Failed to load twoslash-eslint. Please ensure eslint is installed and try again."); } return twoslasher; }; /** * A map that holds the configuration for built-in twoslash instances, including their trigger patterns, supported languages, and the corresponding twoslasher functions. */ const TwoslashInstanceMap = (TwoslasherMap) => new Map([["twoslash", { trigger: reTrigger, languages: [ "ts", "tsx", "vue" ], twoslashers: (options) => ({ default: getBaseTwoslasher(options, TwoslasherMap), vue: getVueTwoslasher(options, TwoslasherMap) }) }], ["eslint", { trigger: /\beslint\b/, languages: ["ts", "tsx"], twoslashers: (options) => ({ default: getEslintTwoslasher(options, TwoslasherMap) }) }]]); /** * Retrieves a twoslasher instance configuration and applies optional overrides from plugin options. * * @param key - The built-in twoslasher type identifier to retrieve from the instance map * @param opts - Optional plugin configuration containing instance-specific overrides * * @returns An object containing the twoslasher instances, trigger pattern, and supported languages * * @throws {Error} When no twoslash instance is found for the provided key * * @internal */ const __getTwoslasherAndOverride = (key, opts, TwoslasherMap) => { const data = TwoslashInstanceMap(TwoslasherMap).get(key); if (!data) throw new Error(`No twoslash instance found for key: ${key}`); const { trigger, languages, twoslashers } = data; const triggerOverride = opts?.[key]?.explicitTrigger; const languagesOverride = opts?.[key]?.languages; return { twoslashers, trigger: triggerOverride instanceof RegExp ? triggerOverride : trigger, languages: languagesOverride ?? languages }; }; /** * Creates a function that applies Twoslash transformations to code blocks. * * @param opts - Plugin configuration options for Twoslash instances * @param options - Twoslash processing options * @returns A function that processes a code block and applies the appropriate Twoslash transformer based on language and metadata triggers * * @template A - The return type of the transformation function * * @example * ```ts * const transformer = getTwoslasher(config, options); * const result = await transformer(codeBlock, (twoslash) => twoslash.transform()); * ``` */ const getTwoslasher = (opts, options, TwoslasherMap) => { const twoslashersMap = BuiltInTwoslashers.reduce((acc, key) => { acc[key] = __getTwoslasherAndOverride(key, opts, TwoslasherMap); return acc; }, {}); return async (codeBlock, fn) => { for (const key in twoslashersMap) { const { trigger, languages, twoslashers } = twoslashersMap[key]; if (languages.includes(codeBlock.language) && trigger.test(codeBlock.meta)) return fn(await (twoslashers(options)[codeBlock.language] ?? twoslashers(options).default)(), key); } return null; }; }; const resolveTsconfigPath = (paths, overridePath) => { if (overridePath === void 0) return path.join(paths, "tsconfig.json"); if (path.isAbsolute(overridePath) === true) return overridePath; return path.resolve(paths, overridePath); }; const parseSnippetTsconfig = (tsconfigPath) => { if (fs.existsSync(tsconfigPath) === false) throw new Error(`tsconfig not found at ${tsconfigPath}`); const source = fs.readFileSync(tsconfigPath, "utf8"); const configFile = ts.readConfigFile(tsconfigPath, ts.sys.readFile); if (configFile.error !== void 0) { const message = ts.flattenDiagnosticMessageText(configFile.error.messageText, "\n"); throw new Error(`Unable to read ${tsconfigPath}: ${message}`); } return { source, options: ts.parseJsonConfigFileContent(configFile.config, ts.sys, path.dirname(tsconfigPath), void 0, tsconfigPath).options }; }; //#endregion //#region src/annotations/completion.ts /** * Represents a completion annotation for Twoslash. * Extends the `ExpressiveCodeAnnotation` class. */ var TwoslashCompletionAnnotation = class extends ExpressiveCodeAnnotation { name = "twoslash-completion-annotation"; /** * Creates an instance of TwoslashCompletionAnnotation. * * @param completion - The completion item to be annotated. * @param query - The node completion query. */ constructor(completion, query, line) { super({ inlineRange: { columnStart: completion.startCharacter, columnEnd: completion.startCharacter + line.text.length } }); this.completion = completion; this.query = query; this.line = line; } /** * Renders the completion annotation. * @param nodesToTransform - The nodes to transform with the error box annotation. * @returns An array of transformed nodes with the error box annotation. */ render({ nodesToTransform }) { return nodesToTransform.map((node) => { return h("span.twoslash-noline", [ h("span.twoslash-cursor", [" "]), node, h("div.twoslash-completion", { style: { "margin-left": `${getTextWidthInPixels(this.completion.startCharacter)}px` } }, [h("div.twoslash-completion-container", [...this.completion.items.map((item, index) => { return h("div.twoslash-completion-item", { class: ` ${item.isDeprecated ? "twoslash-completion-item-deprecated" : ""} ${index === 0 ? "" : "twoslash-completion-item-separator"}` }, [h("span.twoslash-completion-icon", { class: item.kind }, item.icon), h("span.twoslash-completion-name", [h("span.twoslash-completion-name-matched", [item.name.startsWith(this.query.completionsPrefix) ? this.query.completionsPrefix : ""]), h("span.twoslash-completion-name-unmatched", [item.name.startsWith(this.query.completionsPrefix) ? item.name.slice(this.query.completionsPrefix.length || 0) : item.name])])]); })])]) ]); }); } }; //#endregion //#region src/icons/customTagsIcons.ts const customTagsIcons = { log: h("svg", { viewBox: "0 0 32 32", width: "1rem", height: "auto" }, [h("path", { fill: "currentColor", d: "M17 22v-8h-4v2h2v6h-3v2h8v-2zM16 8a1.5 1.5 0 1 0 1.5 1.5A1.5 1.5 0 0 0 16 8" }, []), h("path", { fill: "currentColor", d: "M26 28H6a2.002 2.002 0 0 1-2-2V6a2.002 2.002 0 0 1 2-2h20a2.002 2.002 0 0 1 2 2v20a2.002 2.002 0 0 1-2 2M6 6v20h20V6Z" }, [])]), warn: h("svg", { viewBox: "0 0 32 32", width: "1rem", height: "auto" }, [h("path", { fill: "currentColor", d: "M16 23a1.5 1.5 0 1 0 1.5 1.5A1.5 1.5 0 0 0 16 23m-1-11h2v9h-2z" }, []), h("path", { fill: "currentColor", d: "M29 30H3a1 1 0 0 1-.887-1.461l13-25a1 1 0 0 1 1.774 0l13 25A1 1 0 0 1 29 30M4.65 28h22.7l.001-.003L16.002 6.17h-.004L4.648 27.997Z" }, [])]), error: h("svg", { viewBox: "0 0 32 32", width: "1rem", height: "auto" }, [h("path", { fill: "currentColor", d: "M16 2a14 14 0 1 0 14 14A14 14 0 0 0 16 2m0 26a12 12 0 1 1 12-12a12 12 0 0 1-12 12" }, []), h("path", { fill: "currentColor", d: "M15 8h2v11h-2zm1 14a1.5 1.5 0 1 0 1.5 1.5A1.5 1.5 0 0 0 16 22" }, [])]), annotate: h("svg", { viewBox: "0 0 32 32", width: "1rem", height: "auto" }, [h("path", { fill: "currentColor", d: "M11 24h10v2H11zm2 4h6v2h-6zm3-26A10 10 0 0 0 6 12a9.19 9.19 0 0 0 3.46 7.62c1 .93 1.54 1.46 1.54 2.38h2c0-1.84-1.11-2.87-2.19-3.86A7.2 7.2 0 0 1 8 12a8 8 0 0 1 16 0a7.2 7.2 0 0 1-2.82 6.14c-1.07 1-2.18 2-2.18 3.86h2c0-.92.53-1.45 1.54-2.39A9.18 9.18 0 0 0 26 12A10 10 0 0 0 16 2" }, [])]) }; //#endregion //#region src/annotations/customTags.ts /** * Represents a custom annotation for Twoslash tags. * Extends the `ExpressiveCodeAnnotation` class to provide custom rendering for Twoslash tags. */ var TwoslashCustomTagsAnnotation = class extends ExpressiveCodeAnnotation { name = "twoslash-custom-tags"; /** * Creates an instance of TwoslashCustomTagsAnnotation. * @param tag - The NodeTag object representing the Twoslash tag. */ constructor(tag, line) { super({ inlineRange: { columnStart: 0, columnEnd: line.text.length } }); this.tag = tag; this.line = line; } render({ nodesToTransform }) { const tag = this.tag; const customTagClass = getCustomTagClass(tag.name); return nodesToTransform.map((node) => { return h("span.twoslash.twocustom", [h("div.twoslash-custom-box", { class: customTagClass }, [h("span.twoslash-custom-box-icon", [customTagsIcons[tag.name]]), h("span.twoslash-custom-box-content", [h("span.twoslash-custom-box-content-title", [`${getCustomTagString(tag.name)}:`]), h("span.twoslash-custom-box-content-message", [` ${tag.text}`])])]), node]); }); } }; //#endregion //#region src/annotations/errors.ts var TwoslashErrorUnderlineAnnotation = class extends ExpressiveCodeAnnotation { name = "twoslash-error-underline"; constructor(error) { super({ inlineRange: { columnStart: error.character, columnEnd: error.character + error.length } }); this.error = error; } render({ nodesToTransform }) { return nodesToTransform.map((node) => { return h("span.twoslash.twoslash-error-underline", [node]); }); } }; /** * Represents an annotation for displaying error boxes in Twoslash. * Extends the `ExpressiveCodeAnnotation` class. */ var TwoslashErrorBoxAnnotation = class extends ExpressiveCodeAnnotation { name = "twoslash-error-box"; /** * Creates an instance of `TwoslashErrorBoxAnnotation`. * * @param error - The error object containing error details. * @param line - The line of code where the error occurred. */ constructor(error, line) { super({ inlineRange: { columnStart: line.text.length, columnEnd: line.text.length + error.length } }); this.error = error; this.line = line; } /** * Renders the error box annotation. * * @param nodesToTransform - The nodes to transform with the error box annotation. * @returns An array of transformed nodes with the error box annotation. */ render({ nodesToTransform }) { const error = this.error; const errorLevelClass = getErrorLevelClass(error); return nodesToTransform.map((node) => { return h("span.twoslash.twoerror", [node, h("div.twoslash-error-box", { class: errorLevelClass }, [h("span.twoslash-error-box-icon"), h("span.twoslash-error-box-content", [h("span.twoslash-error-box-content-title", [`${getErrorLevelString(error)} ${error.code && `ts(${error.code}) `} ― `]), h("span.twoslash-error-box-content-message", [error.text])])])]); }); } }; //#endregion //#region src/annotations/highlight.ts /** * Represents a highlight annotation for Twoslash. * Extends the `ExpressiveCodeAnnotation` class. */ var TwoslashHighlightAnnotation = class extends ExpressiveCodeAnnotation { name = "twoslash-highlight-annotation"; /** * Creates an instance of `TwoslashHighlightAnnotation`. * @param highlight - The highlight details including start position and length. */ constructor(highlight) { super({ inlineRange: { columnStart: highlight.start, columnEnd: highlight.start + highlight.length } }); this.highlight = highlight; } /** * Renders the highlight annotation. * @param nodesToTransform - The nodes to be transformed. * @returns An array of transformed nodes wrapped in a span with the class `twoslash-highlighted`. */ render({ nodesToTransform }) { return nodesToTransform.map((node) => { return h("span.twoslash-highlighted", [node]); }); } }; //#endregion //#region src/annotations/hover.ts /** * Represents a hover annotation for Twoslash. * Extends the `ExpressiveCodeAnnotation` class to provide hover functionality. */ var TwoslashHoverAnnotation = class extends ExpressiveCodeAnnotation { name = "twoslash-hover-annotation"; /** * Creates an instance of `TwoslashHoverAnnotation`. * @param hover - The hover information including character position and text. */ constructor(hover, codeType, renderedDocs) { super({ inlineRange: { columnStart: hover.character, columnEnd: hover.character + hover.length } }); this.hover = hover; this.codeType = codeType; this.renderedDocs = renderedDocs; } /** * Renders the hover annotation. * @param nodesToTransform - The nodes to be transformed with hover annotations. * @returns The transformed nodes with hover annotations. */ render({ nodesToTransform }) { return nodesToTransform.map((node) => { if (node.type === "element") return h("span.twoslash", node.properties, [h("span.twoslash-hover", [h("div.twoslash-popup-container.not-content", [ h("code.twoslash-popup-code", [h("span.twoslash-popup-code-type", this.codeType)]), this.renderedDocs.docs, this.renderedDocs.tags ]), node])]); return node; }); } }; //#endregion //#region src/annotations/static.ts /** * Represents a static annotation for Twoslash. * Extends the ExpressiveCodeAnnotation class. */ var TwoslashStaticAnnotation = class extends ExpressiveCodeAnnotation { name = "twoslash-static-annotation"; /** * Creates an instance of TwoslashStaticAnnotation. * * @param hover - The hover information for the node. * @param line - The line of code associated with the annotation. * @param includeJsDoc - A flag indicating whether to include JSDoc comments. * @param query - The query information for the node. */ constructor(query, line, codeType, renderedDocs) { super({ inlineRange: { columnStart: line.text.length, columnEnd: line.text.length + query.length } }); this.query = query; this.line = line; this.codeType = codeType; this.renderedDocs = renderedDocs; } /** * Renders the static annotation. * @param nodesToTransform - The nodes to transform with the error box annotation. * @returns An array of transformed nodes with the error box annotation. */ render({ nodesToTransform }) { return nodesToTransform.map((node) => { return h("span.twoslash-noline", [node, h("div.twoslash-static", { style: { "margin-left": `${getTextWidthInPixels(this.query.character)}px` } }, [h("div.twoslash-static-container.not-content", [ h("code.twoslash-popup-code", [h("span.twoslash-popup-code-type", this.codeType)]), this.renderedDocs.docs, this.renderedDocs.tags ])])]); }); } }; //#endregion //#region src/consts.ts const instanceConfigsDefaults = { twoslash: { explicitTrigger: true, languages: [ "ts", "tsx", "vue" ] }, eslint: { explicitTrigger: true, languages: ["ts", "tsx"] } }; const twoslashEslintDefaults = { eslintConfig: [{ files: ["**"], rules: { "constructor-super": ["error"], "for-direction": ["error"], "getter-return": ["error"], "no-async-promise-executor": ["error"], "no-case-declarations": ["error"], "no-class-assign": ["error"], "no-compare-neg-zero": ["error"], "no-cond-assign": ["error"], "no-const-assign": ["error"], "no-constant-binary-expression": ["error"], "no-constant-condition": ["error"], "no-control-regex": ["error"], "no-debugger": ["error"], "no-delete-var": ["error"], "no-dupe-args": ["error"], "no-dupe-class-members": ["error"], "no-dupe-else-if": ["error"], "no-dupe-keys": ["error"], "no-duplicate-case": ["error"], "no-empty": ["error"], "no-empty-character-class": ["error"], "no-empty-pattern": ["error"], "no-empty-static-block": ["error"], "no-ex-assign": ["error"], "no-extra-boolean-cast": ["error"], "no-fallthrough": ["error"], "no-func-assign": ["error"], "no-global-assign": ["error"], "no-import-assign": ["error"], "no-invalid-regexp": ["error"], "no-irregular-whitespace": ["error"], "no-loss-of-precision": ["error"], "no-misleading-character-class": ["error"], "no-new-native-nonconstructor": ["error"], "no-nonoctal-decimal-escape": ["error"], "no-obj-calls": ["error"], "no-octal": ["error"], "no-prototype-builtins": ["error"], "no-redeclare": ["error"], "no-regex-spaces": ["error"], "no-self-assign": ["error"], "no-setter-return": ["error"], "no-shadow-restricted-names": ["error"], "no-sparse-arrays": ["error"], "no-this-before-super": ["error"], "no-unassigned-vars": ["error"], "no-undef": ["error"], "no-unexpected-multiline": ["error"], "no-unreachable": ["error"], "no-unsafe-finally": ["error"], "no-unsafe-negation": ["error"], "no-unsafe-optional-chaining": ["error"], "no-unused-labels": ["error"], "no-unused-private-class-members": ["error"], "no-unused-vars": ["error"], "no-useless-assignment": ["error"], "no-useless-backreference": ["error"], "no-useless-catch": ["error"], "no-useless-escape": ["error"], "no-with": ["error"], "preserve-caught-error": ["error"], "require-yield": ["error"], "use-isnan": ["error"], "valid-typeof": ["error"] }, languageOptions: { parserOptions: { ecmaFeatures: { jsx: true }, sourceType: "module" }, ecmaVersion: "latest", parser: tsParser } }] }; //#endregion //#region src/module-code/floating-ui-core.min.ts var floating_ui_core_min_default = "!function(t,e){\"object\"==typeof exports&&\"undefined\"!=typeof module?e(exports):\"function\"==typeof define&&define.amd?define([\"exports\"],e):e((t=\"undefined\"!=typeof globalThis?globalThis:t||self).FloatingUICore={})}(this,(function(t){\"use strict\";const e=[\"top\",\"right\",\"bottom\",\"left\"],n=[\"start\",\"end\"],i=e.reduce(((t,e)=>t.concat(e,e+\"-\"+n[0],e+\"-\"+n[1])),[]),o=Math.min,r=Math.max,a={left:\"right\",right:\"left\",bottom:\"top\",top:\"bottom\"},l={start:\"end\",end:\"start\"};function s(t,e,n){return r(t,o(e,n))}function f(t,e){return\"function\"==typeof t?t(e):t}function c(t){return t.split(\"-\")[0]}function u(t){return t.split(\"-\")[1]}function m(t){return\"x\"===t?\"y\":\"x\"}function d(t){return\"y\"===t?\"height\":\"width\"}function g(t){return[\"top\",\"bottom\"].includes(c(t))?\"y\":\"x\"}function p(t){return m(g(t))}function h(t,e,n){void 0===n&&(n=!1);const i=u(t),o=p(t),r=d(o);let a=\"x\"===o?i===(n?\"end\":\"start\")?\"right\":\"left\":\"start\"===i?\"bottom\":\"top\";return e.reference[r]>e.floating[r]&&(a=w(a)),[a,w(a)]}function y(t){return t.replace(/start|end/g,(t=>l[t]))}function w(t){return t.replace(/left|right|bottom|top/g,(t=>a[t]))}function x(t){return\"number\"!=typeof t?function(t){return{top:0,right:0,bottom:0,left:0,...t}}(t):{top:t,right:t,bottom:t,left:t}}function v(t){const{x:e,y:n,width:i,height:o}=t;return{width:i,height:o,top:n,left:e,right:e+i,bottom:n+o,x:e,y:n}}function b(t,e,n){let{reference:i,floating:o}=t;const r=g(e),a=p(e),l=d(a),s=c(e),f=\"y\"===r,m=i.x+i.width/2-o.width/2,h=i.y+i.height/2-o.height/2,y=i[l]/2-o[l]/2;let w;switch(s){case\"top\":w={x:m,y:i.y-o.height};break;case\"bottom\":w={x:m,y:i.y+i.height};break;case\"right\":w={x:i.x+i.width,y:h};break;case\"left\":w={x:i.x-o.width,y:h};break;default:w={x:i.x,y:i.y}}switch(u(e)){case\"start\":w[a]-=y*(n&&f?-1:1);break;case\"end\":w[a]+=y*(n&&f?-1:1)}return w}async function A(t,e){var n;void 0===e&&(e={});const{x:i,y:o,platform:r,rects:a,elements:l,strategy:s}=t,{boundary:c=\"clippingAncestors\",rootBoundary:u=\"viewport\",elementContext:m=\"floating\",altBoundary:d=!1,padding:g=0}=f(e,t),p=x(g),h=l[d?\"floating\"===m?\"reference\":\"floating\":m],y=v(await r.getClippingRect({element:null==(n=await(null==r.isElement?void 0:r.isElement(h)))||n?h:h.contextElement||await(null==r.getDocumentElement?void 0:r.getDocumentElement(l.floating)),boundary:c,rootBoundary:u,strategy:s})),w=\"floating\"===m?{x:i,y:o,width:a.floating.width,height:a.floating.height}:a.reference,b=await(null==r.getOffsetParent?void 0:r.getOffsetParent(l.floating)),A=await(null==r.isElement?void 0:r.isElement(b))&&await(null==r.getScale?void 0:r.getScale(b))||{x:1,y:1},R=v(r.convertOffsetParentRelativeRectToViewportRelativeRect?await r.convertOffsetParentRelativeRectToViewportRelativeRect({elements:l,rect:w,offsetParent:b,strategy:s}):w);return{top:(y.top-R.top+p.top)/A.y,bottom:(R.bottom-y.bottom+p.bottom)/A.y,left:(y.left-R.left+p.left)/A.x,right:(R.right-y.right+p.right)/A.x}}function R(t,e){return{top:t.top-e.height,right:t.right-e.width,bottom:t.bottom-e.height,left:t.left-e.width}}function P(t){return e.some((e=>t[e]>=0))}function D(t){const e=o(...t.map((t=>t.left))),n=o(...t.map((t=>t.top)));return{x:e,y:n,width:r(...t.map((t=>t.right)))-e,height:r(...t.map((t=>t.bottom)))-n}}t.arrow=t=>({name:\"arrow\",options:t,async fn(e){const{x:n,y:i,placement:r,rects:a,platform:l,elements:c,middlewareData:m}=e,{element:g,padding:h=0}=f(t,e)||{};if(null==g)return{};const y=x(h),w={x:n,y:i},v=p(r),b=d(v),A=await l.getDimensions(g),R=\"y\"===v,P=R?\"top\":\"left\",D=R?\"bottom\":\"right\",T=R?\"clientHeight\":\"clientWidth\",O=a.reference[b]+a.reference[v]-w[v]-a.floating[b],E=w[v]-a.reference[v],L=await(null==l.getOffsetParent?void 0:l.getOffsetParent(g));let k=L?L[T]:0;k&&await(null==l.isElement?void 0:l.isElement(L))||(k=c.floating[T]||a.floating[b]);const C=O/2-E/2,B=k/2-A[b]/2-1,H=o(y[P],B),S=o(y[D],B),F=H,j=k-A[b]-S,z=k/2-A[b]/2+C,M=s(F,z,j),V=!m.arrow&&null!=u(r)&&z!==M&&a.reference[b]/2-(z<F?H:S)-A[b]/2<0,W=V?z<F?z-F:z-j:0;return{[v]:w[v]+W,data:{[v]:M,centerOffset:z-M-W,...V&&{alignmentOffset:W}},reset:V}}}),t.autoPlacement=function(t){return void 0===t&&(t={}),{name:\"autoPlacement\",options:t,async fn(e){var n,o,r;const{rects:a,middlewareData:l,placement:s,platform:m,elements:d}=e,{crossAxis:g=!1,alignment:p,allowedPlacements:w=i,autoAlignment:x=!0,...v}=f(t,e),b=void 0!==p||w===i?function(t,e,n){return(t?[...n.filter((e=>u(e)===t)),...n.filter((e=>u(e)!==t))]:n.filter((t=>c(t)===t))).filter((n=>!t||u(n)===t||!!e&&y(n)!==n))}(p||null,x,w):w,R=await A(e,v),P=(null==(n=l.autoPlacement)?void 0:n.index)||0,D=b[P];if(null==D)return{};const T=h(D,a,await(null==m.isRTL?void 0:m.isRTL(d.floating)));if(s!==D)return{reset:{placement:b[0]}};const O=[R[c(D)],R[T[0]],R[T[1]]],E=[...(null==(o=l.autoPlacement)?void 0:o.overflows)||[],{placement:D,overflows:O}],L=b[P+1];if(L)return{data:{index:P+1,overflows:E},reset:{placement:L}};const k=E.map((t=>{const e=u(t.placement);return[t.placement,e&&g?t.overflows.slice(0,2).reduce(((t,e)=>t+e),0):t.overflows[0],t.overflows]})).sort(((t,e)=>t[1]-e[1])),C=(null==(r=k.filter((t=>t[2].slice(0,u(t[0])?2:3).every((t=>t<=0))))[0])?void 0:r[0])||k[0][0];return C!==s?{data:{index:P+1,overflows:E},reset:{placement:C}}:{}}}},t.computePosition=async(t,e,n)=>{const{placement:i=\"bottom\",strategy:o=\"absolute\",middleware:r=[],platform:a}=n,l=r.filter(Boolean),s=await(null==a.isRTL?void 0:a.isRTL(e));let f=await a.getElementRects({reference:t,floating:e,strategy:o}),{x:c,y:u}=b(f,i,s),m=i,d={},g=0;for(let n=0;n<l.length;n++){const{name:r,fn:p}=l[n],{x:h,y:y,data:w,reset:x}=await p({x:c,y:u,initialPlacement:i,placement:m,strategy:o,middlewareData:d,rects:f,platform:a,elements:{reference:t,floating:e}});c=null!=h?h:c,u=null!=y?y:u,d={...d,[r]:{...d[r],...w}},x&&g<=50&&(g++,\"object\"==typeof x&&(x.placement&&(m=x.placement),x.rects&&(f=!0===x.rects?await a.getElementRects({reference:t,floating:e,strategy:o}):x.rects),({x:c,y:u}=b(f,m,s))),n=-1)}return{x:c,y:u,placement:m,strategy:o,middlewareData:d}},t.detectOverflow=A,t.flip=function(t){return void 0===t&&(t={}),{name:\"flip\",options:t,async fn(e){var n,i;const{placement:o,middlewareData:r,rects:a,initialPlacement:l,platform:s,elements:m}=e,{mainAxis:d=!0,crossAxis:p=!0,fallbackPlacements:x,fallbackStrategy:v=\"bestFit