lake-html 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +11 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +11 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -63,6 +63,14 @@ function getBoxRenderers() {
|
|
|
63
63
|
}),
|
|
64
64
|
isVoid: true
|
|
65
65
|
}),
|
|
66
|
+
media: (boxValue) => ({
|
|
67
|
+
tagName: "video",
|
|
68
|
+
attributes: __spreadProps(__spreadValues(__spreadValues({
|
|
69
|
+
src: boxValue.url
|
|
70
|
+
}, boxValue.width && { width: boxValue.width.replace(/px$/i, "") }), boxValue.height && { height: boxValue.height.replace(/px$/i, "") }), {
|
|
71
|
+
controls: "true"
|
|
72
|
+
})
|
|
73
|
+
}),
|
|
66
74
|
file: (boxValue, encode) => ({
|
|
67
75
|
tagName: "a",
|
|
68
76
|
attributes: {
|
|
@@ -106,12 +114,13 @@ function getBoxRenderers() {
|
|
|
106
114
|
video: (boxValue) => ({
|
|
107
115
|
tagName: "iframe",
|
|
108
116
|
attributes: __spreadProps(__spreadValues({}, boxValue.url && { src: `https://www.youtube.com/embed/${extractIdFromUrl(boxValue.url)}` }), {
|
|
117
|
+
width: boxValue.width ? boxValue.width.replace(/px$/i, "") : "560",
|
|
118
|
+
height: boxValue.height ? boxValue.height.replace(/px$/i, "") : "315",
|
|
109
119
|
title: "YouTube video player",
|
|
110
120
|
frameborder: "0",
|
|
111
121
|
allow: "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share",
|
|
112
122
|
referrerpolicy: "strict-origin-when-cross-origin",
|
|
113
|
-
allowfullscreen: "true"
|
|
114
|
-
style: "width: 560px; height: 315px;"
|
|
123
|
+
allowfullscreen: "true"
|
|
115
124
|
})
|
|
116
125
|
}),
|
|
117
126
|
twitter: (boxValue) => ({
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["// Define a generic type for HTML attributes (key-value pairs)\ntype AttributeMap = Record<string, string>;\n\n// Structure representing the output HTML node\ninterface BoxHTMLNode {\n tagName: string;\n attributes?: AttributeMap;\n isVoid?: boolean; // True for self-closing tags like <img />, <hr />\n innerHTML?: string;\n}\n\n// Function signature for encoding HTML entities\ntype EncodeHTMLEntities = (value: string) => string;\n\n// Function signature for encoding HTML entities\ntype RenderBox = (boxValue: AttributeMap, encode: EncodeHTMLEntities) => BoxHTMLNode;\n\n// Registry of renderers for different box types\ntype BoxRenderers = Record<string, RenderBox>;\n\n/**\n * Extracts the ID from a URL.\n * Useful for extracting YouTube or Twitter IDs from clean URLs.\n */\nfunction extractIdFromUrl(url: string): string {\n const result = /[\\w\\-]+$/.exec(url);\n return result ? result[0] : '';\n}\n\n/**\n * Returns the default configuration for rendering various Lake attributes.\n */\nexport function getBoxRenderers(): BoxRenderers {\n return {\n hr: () => ({\n tagName: 'div',\n attributes: {\n class: 'lake-box-block lake-hr',\n },\n innerHTML: '<hr />',\n }),\n\n image: boxValue => ({\n tagName: 'img',\n attributes: {\n src: boxValue.url,\n ...(boxValue.width && { width: boxValue.width }),\n ...(boxValue.height && { height: boxValue.height }),\n ...(boxValue.caption && { alt: boxValue.caption }),\n border: '0',\n },\n isVoid: true,\n }),\n\n file: (boxValue, encode) => ({\n tagName: 'a',\n attributes: {\n href: boxValue.url,\n target: '_blank',\n },\n innerHTML: encode(boxValue.name),\n }),\n\n codeBlock: (boxValue, encode) => ({\n tagName: 'pre',\n attributes: {\n class: `lang-${boxValue.lang}`,\n },\n innerHTML: `<code>${encode(boxValue.code)}</code>`,\n }),\n\n emoji: boxValue => ({\n tagName: 'img',\n attributes: {\n src: boxValue.url,\n width: '32',\n height: '32',\n border: '0',\n },\n isVoid: true,\n }),\n\n equation: boxValue => ({\n tagName: 'code',\n innerHTML: boxValue.code,\n }),\n\n mention: (boxValue, encode) => ({\n tagName: 'a',\n attributes: {\n href: `/${boxValue.name}`,\n target: '_blank',\n },\n innerHTML: encode(boxValue.nickname ?? boxValue.name),\n }),\n\n video: boxValue => ({\n tagName: 'iframe',\n attributes: {\n ...(boxValue.url && { src: `https://www.youtube.com/embed/${extractIdFromUrl(boxValue.url)}` }),\n title: 'YouTube video player',\n frameborder: '0',\n allow: 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share',\n referrerpolicy: 'strict-origin-when-cross-origin',\n allowfullscreen: 'true',\n style: 'width: 560px; height: 315px;',\n },\n }),\n\n twitter: boxValue => ({\n tagName: 'iframe',\n attributes: {\n ...(boxValue.url && { src: `https://platform.twitter.com/embed/Tweet.html?id=${extractIdFromUrl(boxValue.url)}` }),\n title: 'Twitter tweet',\n scrolling: 'no',\n frameborder: '0',\n allowtransparency: 'true',\n allowfullscreen: 'true',\n style: 'width: 550px; height: 300px;',\n },\n }),\n };\n}\n\n// Map for reserved HTML characters\nconst htmlEntityMap = new Map([\n ['&', '&'],\n ['<', '<'],\n ['>', '>'],\n ['\"', '"'],\n ['\\xA0', ' '],\n]);\n\n/**\n * Escapes reserved HTML characters to prevent XSS and rendering issues.\n */\nfunction encodeHTMLEntities(value: string): string {\n return value.replace(/[&<>\"\\xA0]/g, match => htmlEntityMap.get(match)!);\n}\n\n/**\n * Decodes a Base64 encoded string with UTF-8 support.\n */\nfunction decodeBase64(value: string): string {\n const binaryString = atob(value);\n const byteArray = new Uint8Array(binaryString.length);\n for (let i = 0; i < binaryString.length; i++) {\n byteArray[i] = binaryString.charCodeAt(i);\n }\n const decoder = new TextDecoder();\n return decoder.decode(byteArray);\n}\n\n/**\n * Parses HTML tag attributes from a string into a key-value object.\n */\nfunction parseAttributes(tag: string): AttributeMap {\n const attributes: AttributeMap = {};\n // Regex breakdown:\n // Group 1/2: Key=Value (unquoted)\n // Group 3/4: Key=\"Value\" (double quoted)\n // Group 5/6: Key='Value' (single quoted)\n const reg = /\\s+(?:([\\w\\-:]+)=([^\\s\"'<>]+)|([\\w\\-:\"]+)=\"([^\"]*)\"|([\\w\\-:\"]+)='([^']*)')(?=[\\s/>])/g;\n let match: RegExpExecArray | null;\n while ((match = reg.exec(tag))) {\n const key = (match[1] || match[3] || match[5]).toLowerCase();\n const value = match[1] ? match[2] : (match[3] ? match[4] : match[6]);\n attributes[key] = value;\n }\n return attributes;\n}\n\n/**\n * Serializes an attribute map into an HTML attribute string.\n */\nfunction serializeAttributes(attrs: AttributeMap): string {\n const result: string[] = [];\n for (const key of Object.keys(attrs)) {\n const value = String(attrs[key]);\n result.push(`${key}=\"${encodeHTMLEntities(value)}\"`);\n }\n return result.join(' ');\n}\n\n/**\n * Serializes a BoxHTMLNode object into a standard HTML string.\n */\nfunction toBoxHTML(node: BoxHTMLNode): string {\n let result = `<${node.tagName}`;\n if (node.attributes) {\n result += ` ${serializeAttributes(node.attributes)}`;\n }\n if (node.isVoid === true) {\n result += ' />';\n } else {\n result += `>${node.innerHTML ?? ''}</${node.tagName}>`;\n }\n return result;\n}\n\n/**\n * Main function to convert Lake Markup Language (LML) to standard HTML.\n * It processes custom <lake-box> tags and removes internal anchors.\n */\nexport function toHTML(value: string, renderers?: BoxRenderers): string {\n renderers = renderers ?? getBoxRenderers();\n // Regex to match <lake-box>, <anchor>, and <focus> tags\n const combinedRegex = /(<lake-box[^>]+>)[\\s\\S]*?(?:<\\/lake-box>|$)|(<anchor\\s*\\/>)|(<focus\\s*\\/>)/gi;\n return value.replace(combinedRegex, (match, boxOpen) => {\n // Handle lake-box conversion\n if (boxOpen) {\n const attributes = parseAttributes(boxOpen);\n const render = renderers[attributes.name];\n if (render) {\n try {\n const boxValue = attributes.value ? JSON.parse(decodeBase64(attributes.value)) : {};\n const node = render(boxValue, encodeHTMLEntities);\n return toBoxHTML(node);\n } catch (e) {\n console.error('Failed to parse lake-box value:', e);\n }\n }\n }\n // Remove internal selection markers (<anchor /> and <focus />)\n return '';\n });\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["// Define a generic type for HTML attributes (key-value pairs)\ntype AttributeMap = Record<string, string>;\n\n// Structure representing the output HTML node\ninterface BoxHTMLNode {\n tagName: string;\n attributes?: AttributeMap;\n isVoid?: boolean; // True for self-closing tags like <img />, <hr />\n innerHTML?: string;\n}\n\n// Function signature for encoding HTML entities\ntype EncodeHTMLEntities = (value: string) => string;\n\n// Function signature for encoding HTML entities\ntype RenderBox = (boxValue: AttributeMap, encode: EncodeHTMLEntities) => BoxHTMLNode;\n\n// Registry of renderers for different box types\ntype BoxRenderers = Record<string, RenderBox>;\n\n/**\n * Extracts the ID from a URL.\n * Useful for extracting YouTube or Twitter IDs from clean URLs.\n */\nfunction extractIdFromUrl(url: string): string {\n const result = /[\\w\\-]+$/.exec(url);\n return result ? result[0] : '';\n}\n\n/**\n * Returns the default configuration for rendering various Lake attributes.\n */\nexport function getBoxRenderers(): BoxRenderers {\n return {\n hr: () => ({\n tagName: 'div',\n attributes: {\n class: 'lake-box-block lake-hr',\n },\n innerHTML: '<hr />',\n }),\n\n image: boxValue => ({\n tagName: 'img',\n attributes: {\n src: boxValue.url,\n ...(boxValue.width && { width: boxValue.width }),\n ...(boxValue.height && { height: boxValue.height }),\n ...(boxValue.caption && { alt: boxValue.caption }),\n border: '0',\n },\n isVoid: true,\n }),\n\n media: boxValue => ({\n tagName: 'video',\n attributes: {\n src: boxValue.url,\n ...(boxValue.width && { width: boxValue.width.replace(/px$/i, '') }),\n ...(boxValue.height && { height: boxValue.height.replace(/px$/i, '') }),\n controls: 'true',\n },\n }),\n\n file: (boxValue, encode) => ({\n tagName: 'a',\n attributes: {\n href: boxValue.url,\n target: '_blank',\n },\n innerHTML: encode(boxValue.name),\n }),\n\n codeBlock: (boxValue, encode) => ({\n tagName: 'pre',\n attributes: {\n class: `lang-${boxValue.lang}`,\n },\n innerHTML: `<code>${encode(boxValue.code)}</code>`,\n }),\n\n emoji: boxValue => ({\n tagName: 'img',\n attributes: {\n src: boxValue.url,\n width: '32',\n height: '32',\n border: '0',\n },\n isVoid: true,\n }),\n\n equation: boxValue => ({\n tagName: 'code',\n innerHTML: boxValue.code,\n }),\n\n mention: (boxValue, encode) => ({\n tagName: 'a',\n attributes: {\n href: `/${boxValue.name}`,\n target: '_blank',\n },\n innerHTML: encode(boxValue.nickname ?? boxValue.name),\n }),\n\n video: boxValue => ({\n tagName: 'iframe',\n attributes: {\n ...(boxValue.url && { src: `https://www.youtube.com/embed/${extractIdFromUrl(boxValue.url)}` }),\n width: boxValue.width ? boxValue.width.replace(/px$/i, '') : '560',\n height: boxValue.height ? boxValue.height.replace(/px$/i, '') : '315',\n title: 'YouTube video player',\n frameborder: '0',\n allow: 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share',\n referrerpolicy: 'strict-origin-when-cross-origin',\n allowfullscreen: 'true',\n },\n }),\n\n twitter: boxValue => ({\n tagName: 'iframe',\n attributes: {\n ...(boxValue.url && { src: `https://platform.twitter.com/embed/Tweet.html?id=${extractIdFromUrl(boxValue.url)}` }),\n title: 'Twitter tweet',\n scrolling: 'no',\n frameborder: '0',\n allowtransparency: 'true',\n allowfullscreen: 'true',\n style: 'width: 550px; height: 300px;',\n },\n }),\n };\n}\n\n// Map for reserved HTML characters\nconst htmlEntityMap = new Map([\n ['&', '&'],\n ['<', '<'],\n ['>', '>'],\n ['\"', '"'],\n ['\\xA0', ' '],\n]);\n\n/**\n * Escapes reserved HTML characters to prevent XSS and rendering issues.\n */\nfunction encodeHTMLEntities(value: string): string {\n return value.replace(/[&<>\"\\xA0]/g, match => htmlEntityMap.get(match)!);\n}\n\n/**\n * Decodes a Base64 encoded string with UTF-8 support.\n */\nfunction decodeBase64(value: string): string {\n const binaryString = atob(value);\n const byteArray = new Uint8Array(binaryString.length);\n for (let i = 0; i < binaryString.length; i++) {\n byteArray[i] = binaryString.charCodeAt(i);\n }\n const decoder = new TextDecoder();\n return decoder.decode(byteArray);\n}\n\n/**\n * Parses HTML tag attributes from a string into a key-value object.\n */\nfunction parseAttributes(tag: string): AttributeMap {\n const attributes: AttributeMap = {};\n // Regex breakdown:\n // Group 1/2: Key=Value (unquoted)\n // Group 3/4: Key=\"Value\" (double quoted)\n // Group 5/6: Key='Value' (single quoted)\n const reg = /\\s+(?:([\\w\\-:]+)=([^\\s\"'<>]+)|([\\w\\-:\"]+)=\"([^\"]*)\"|([\\w\\-:\"]+)='([^']*)')(?=[\\s/>])/g;\n let match: RegExpExecArray | null;\n while ((match = reg.exec(tag))) {\n const key = (match[1] || match[3] || match[5]).toLowerCase();\n const value = match[1] ? match[2] : (match[3] ? match[4] : match[6]);\n attributes[key] = value;\n }\n return attributes;\n}\n\n/**\n * Serializes an attribute map into an HTML attribute string.\n */\nfunction serializeAttributes(attrs: AttributeMap): string {\n const result: string[] = [];\n for (const key of Object.keys(attrs)) {\n const value = String(attrs[key]);\n result.push(`${key}=\"${encodeHTMLEntities(value)}\"`);\n }\n return result.join(' ');\n}\n\n/**\n * Serializes a BoxHTMLNode object into a standard HTML string.\n */\nfunction toBoxHTML(node: BoxHTMLNode): string {\n let result = `<${node.tagName}`;\n if (node.attributes) {\n result += ` ${serializeAttributes(node.attributes)}`;\n }\n if (node.isVoid === true) {\n result += ' />';\n } else {\n result += `>${node.innerHTML ?? ''}</${node.tagName}>`;\n }\n return result;\n}\n\n/**\n * Main function to convert Lake Markup Language (LML) to standard HTML.\n * It processes custom <lake-box> tags and removes internal anchors.\n */\nexport function toHTML(value: string, renderers?: BoxRenderers): string {\n renderers = renderers ?? getBoxRenderers();\n // Regex to match <lake-box>, <anchor>, and <focus> tags\n const combinedRegex = /(<lake-box[^>]+>)[\\s\\S]*?(?:<\\/lake-box>|$)|(<anchor\\s*\\/>)|(<focus\\s*\\/>)/gi;\n return value.replace(combinedRegex, (match, boxOpen) => {\n // Handle lake-box conversion\n if (boxOpen) {\n const attributes = parseAttributes(boxOpen);\n const render = renderers[attributes.name];\n if (render) {\n try {\n const boxValue = attributes.value ? JSON.parse(decodeBase64(attributes.value)) : {};\n const node = render(boxValue, encodeHTMLEntities);\n return toBoxHTML(node);\n } catch (e) {\n console.error('Failed to parse lake-box value:', e);\n }\n }\n }\n // Remove internal selection markers (<anchor /> and <focus />)\n return '';\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwBA,SAAS,iBAAiB,KAAqB;AAC7C,QAAM,SAAS,WAAW,KAAK,GAAG;AAClC,SAAO,SAAS,OAAO,CAAC,IAAI;AAC9B;AAKO,SAAS,kBAAgC;AAC9C,SAAO;AAAA,IACL,IAAI,OAAO;AAAA,MACT,SAAS;AAAA,MACT,YAAY;AAAA,QACV,OAAO;AAAA,MACT;AAAA,MACA,WAAW;AAAA,IACb;AAAA,IAEA,OAAO,eAAa;AAAA,MAClB,SAAS;AAAA,MACT,YAAY;AAAA,QACV,KAAK,SAAS;AAAA,SACV,SAAS,SAAS,EAAE,OAAO,SAAS,MAAM,IAC1C,SAAS,UAAU,EAAE,QAAQ,SAAS,OAAO,IAC7C,SAAS,WAAW,EAAE,KAAK,SAAS,QAAQ,IAJtC;AAAA,QAKV,QAAQ;AAAA,MACV;AAAA,MACA,QAAQ;AAAA,IACV;AAAA,IAEA,OAAO,eAAa;AAAA,MAClB,SAAS;AAAA,MACT,YAAY;AAAA,QACV,KAAK,SAAS;AAAA,SACV,SAAS,SAAS,EAAE,OAAO,SAAS,MAAM,QAAQ,QAAQ,EAAE,EAAE,IAC9D,SAAS,UAAU,EAAE,QAAQ,SAAS,OAAO,QAAQ,QAAQ,EAAE,EAAE,IAH3D;AAAA,QAIV,UAAU;AAAA,MACZ;AAAA,IACF;AAAA,IAEA,MAAM,CAAC,UAAU,YAAY;AAAA,MAC3B,SAAS;AAAA,MACT,YAAY;AAAA,QACV,MAAM,SAAS;AAAA,QACf,QAAQ;AAAA,MACV;AAAA,MACA,WAAW,OAAO,SAAS,IAAI;AAAA,IACjC;AAAA,IAEA,WAAW,CAAC,UAAU,YAAY;AAAA,MAChC,SAAS;AAAA,MACT,YAAY;AAAA,QACV,OAAO,QAAQ,SAAS,IAAI;AAAA,MAC9B;AAAA,MACA,WAAW,SAAS,OAAO,SAAS,IAAI,CAAC;AAAA,IAC3C;AAAA,IAEA,OAAO,eAAa;AAAA,MAClB,SAAS;AAAA,MACT,YAAY;AAAA,QACV,KAAK,SAAS;AAAA,QACd,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,QAAQ;AAAA,MACV;AAAA,MACA,QAAQ;AAAA,IACV;AAAA,IAEA,UAAU,eAAa;AAAA,MACrB,SAAS;AAAA,MACT,WAAW,SAAS;AAAA,IACtB;AAAA,IAEA,SAAS,CAAC,UAAU,WAAQ;AAjGhC;AAiGoC;AAAA,QAC9B,SAAS;AAAA,QACT,YAAY;AAAA,UACV,MAAM,IAAI,SAAS,IAAI;AAAA,UACvB,QAAQ;AAAA,QACV;AAAA,QACA,WAAW,QAAO,cAAS,aAAT,YAAqB,SAAS,IAAI;AAAA,MACtD;AAAA;AAAA,IAEA,OAAO,eAAa;AAAA,MAClB,SAAS;AAAA,MACT,YAAY,iCACN,SAAS,OAAO,EAAE,KAAK,iCAAiC,iBAAiB,SAAS,GAAG,CAAC,GAAG,IADnF;AAAA,QAEV,OAAO,SAAS,QAAQ,SAAS,MAAM,QAAQ,QAAQ,EAAE,IAAI;AAAA,QAC7D,QAAQ,SAAS,SAAS,SAAS,OAAO,QAAQ,QAAQ,EAAE,IAAI;AAAA,QAChE,OAAO;AAAA,QACP,aAAa;AAAA,QACb,OAAO;AAAA,QACP,gBAAgB;AAAA,QAChB,iBAAiB;AAAA,MACnB;AAAA,IACF;AAAA,IAEA,SAAS,eAAa;AAAA,MACpB,SAAS;AAAA,MACT,YAAY,iCACN,SAAS,OAAO,EAAE,KAAK,oDAAoD,iBAAiB,SAAS,GAAG,CAAC,GAAG,IADtG;AAAA,QAEV,OAAO;AAAA,QACP,WAAW;AAAA,QACX,aAAa;AAAA,QACb,mBAAmB;AAAA,QACnB,iBAAiB;AAAA,QACjB,OAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AACF;AAGA,IAAM,gBAAgB,oBAAI,IAAI;AAAA,EAC5B,CAAC,KAAK,OAAO;AAAA,EACb,CAAC,KAAK,MAAM;AAAA,EACZ,CAAC,KAAK,MAAM;AAAA,EACZ,CAAC,KAAK,QAAQ;AAAA,EACd,CAAC,QAAQ,QAAQ;AACnB,CAAC;AAKD,SAAS,mBAAmB,OAAuB;AACjD,SAAO,MAAM,QAAQ,eAAe,WAAS,cAAc,IAAI,KAAK,CAAE;AACxE;AAKA,SAAS,aAAa,OAAuB;AAC3C,QAAM,eAAe,KAAK,KAAK;AAC/B,QAAM,YAAY,IAAI,WAAW,aAAa,MAAM;AACpD,WAAS,IAAI,GAAG,IAAI,aAAa,QAAQ,KAAK;AAC5C,cAAU,CAAC,IAAI,aAAa,WAAW,CAAC;AAAA,EAC1C;AACA,QAAM,UAAU,IAAI,YAAY;AAChC,SAAO,QAAQ,OAAO,SAAS;AACjC;AAKA,SAAS,gBAAgB,KAA2B;AAClD,QAAM,aAA2B,CAAC;AAKlC,QAAM,MAAM;AACZ,MAAI;AACJ,SAAQ,QAAQ,IAAI,KAAK,GAAG,GAAI;AAC9B,UAAM,OAAO,MAAM,CAAC,KAAK,MAAM,CAAC,KAAK,MAAM,CAAC,GAAG,YAAY;AAC3D,UAAM,QAAQ,MAAM,CAAC,IAAI,MAAM,CAAC,IAAK,MAAM,CAAC,IAAI,MAAM,CAAC,IAAI,MAAM,CAAC;AAClE,eAAW,GAAG,IAAI;AAAA,EACpB;AACA,SAAO;AACT;AAKA,SAAS,oBAAoB,OAA6B;AACxD,QAAM,SAAmB,CAAC;AAC1B,aAAW,OAAO,OAAO,KAAK,KAAK,GAAG;AACpC,UAAM,QAAQ,OAAO,MAAM,GAAG,CAAC;AAC/B,WAAO,KAAK,GAAG,GAAG,KAAK,mBAAmB,KAAK,CAAC,GAAG;AAAA,EACrD;AACA,SAAO,OAAO,KAAK,GAAG;AACxB;AAKA,SAAS,UAAU,MAA2B;AAtM9C;AAuME,MAAI,SAAS,IAAI,KAAK,OAAO;AAC7B,MAAI,KAAK,YAAY;AACnB,cAAU,IAAI,oBAAoB,KAAK,UAAU,CAAC;AAAA,EACpD;AACA,MAAI,KAAK,WAAW,MAAM;AACxB,cAAU;AAAA,EACZ,OAAO;AACL,cAAU,KAAI,UAAK,cAAL,YAAkB,EAAE,KAAK,KAAK,OAAO;AAAA,EACrD;AACA,SAAO;AACT;AAMO,SAAS,OAAO,OAAe,WAAkC;AACtE,cAAY,gCAAa,gBAAgB;AAEzC,QAAM,gBAAgB;AACtB,SAAO,MAAM,QAAQ,eAAe,CAAC,OAAO,YAAY;AAEtD,QAAI,SAAS;AACX,YAAM,aAAa,gBAAgB,OAAO;AAC1C,YAAM,SAAS,UAAU,WAAW,IAAI;AACxC,UAAI,QAAQ;AACV,YAAI;AACF,gBAAM,WAAW,WAAW,QAAQ,KAAK,MAAM,aAAa,WAAW,KAAK,CAAC,IAAI,CAAC;AAClF,gBAAM,OAAO,OAAO,UAAU,kBAAkB;AAChD,iBAAO,UAAU,IAAI;AAAA,QACvB,SAAS,GAAG;AACV,kBAAQ,MAAM,mCAAmC,CAAC;AAAA,QACpD;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT,CAAC;AACH;","names":[]}
|
package/dist/index.mjs
CHANGED
|
@@ -41,6 +41,14 @@ function getBoxRenderers() {
|
|
|
41
41
|
}),
|
|
42
42
|
isVoid: true
|
|
43
43
|
}),
|
|
44
|
+
media: (boxValue) => ({
|
|
45
|
+
tagName: "video",
|
|
46
|
+
attributes: __spreadProps(__spreadValues(__spreadValues({
|
|
47
|
+
src: boxValue.url
|
|
48
|
+
}, boxValue.width && { width: boxValue.width.replace(/px$/i, "") }), boxValue.height && { height: boxValue.height.replace(/px$/i, "") }), {
|
|
49
|
+
controls: "true"
|
|
50
|
+
})
|
|
51
|
+
}),
|
|
44
52
|
file: (boxValue, encode) => ({
|
|
45
53
|
tagName: "a",
|
|
46
54
|
attributes: {
|
|
@@ -84,12 +92,13 @@ function getBoxRenderers() {
|
|
|
84
92
|
video: (boxValue) => ({
|
|
85
93
|
tagName: "iframe",
|
|
86
94
|
attributes: __spreadProps(__spreadValues({}, boxValue.url && { src: `https://www.youtube.com/embed/${extractIdFromUrl(boxValue.url)}` }), {
|
|
95
|
+
width: boxValue.width ? boxValue.width.replace(/px$/i, "") : "560",
|
|
96
|
+
height: boxValue.height ? boxValue.height.replace(/px$/i, "") : "315",
|
|
87
97
|
title: "YouTube video player",
|
|
88
98
|
frameborder: "0",
|
|
89
99
|
allow: "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share",
|
|
90
100
|
referrerpolicy: "strict-origin-when-cross-origin",
|
|
91
|
-
allowfullscreen: "true"
|
|
92
|
-
style: "width: 560px; height: 315px;"
|
|
101
|
+
allowfullscreen: "true"
|
|
93
102
|
})
|
|
94
103
|
}),
|
|
95
104
|
twitter: (boxValue) => ({
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["// Define a generic type for HTML attributes (key-value pairs)\ntype AttributeMap = Record<string, string>;\n\n// Structure representing the output HTML node\ninterface BoxHTMLNode {\n tagName: string;\n attributes?: AttributeMap;\n isVoid?: boolean; // True for self-closing tags like <img />, <hr />\n innerHTML?: string;\n}\n\n// Function signature for encoding HTML entities\ntype EncodeHTMLEntities = (value: string) => string;\n\n// Function signature for encoding HTML entities\ntype RenderBox = (boxValue: AttributeMap, encode: EncodeHTMLEntities) => BoxHTMLNode;\n\n// Registry of renderers for different box types\ntype BoxRenderers = Record<string, RenderBox>;\n\n/**\n * Extracts the ID from a URL.\n * Useful for extracting YouTube or Twitter IDs from clean URLs.\n */\nfunction extractIdFromUrl(url: string): string {\n const result = /[\\w\\-]+$/.exec(url);\n return result ? result[0] : '';\n}\n\n/**\n * Returns the default configuration for rendering various Lake attributes.\n */\nexport function getBoxRenderers(): BoxRenderers {\n return {\n hr: () => ({\n tagName: 'div',\n attributes: {\n class: 'lake-box-block lake-hr',\n },\n innerHTML: '<hr />',\n }),\n\n image: boxValue => ({\n tagName: 'img',\n attributes: {\n src: boxValue.url,\n ...(boxValue.width && { width: boxValue.width }),\n ...(boxValue.height && { height: boxValue.height }),\n ...(boxValue.caption && { alt: boxValue.caption }),\n border: '0',\n },\n isVoid: true,\n }),\n\n file: (boxValue, encode) => ({\n tagName: 'a',\n attributes: {\n href: boxValue.url,\n target: '_blank',\n },\n innerHTML: encode(boxValue.name),\n }),\n\n codeBlock: (boxValue, encode) => ({\n tagName: 'pre',\n attributes: {\n class: `lang-${boxValue.lang}`,\n },\n innerHTML: `<code>${encode(boxValue.code)}</code>`,\n }),\n\n emoji: boxValue => ({\n tagName: 'img',\n attributes: {\n src: boxValue.url,\n width: '32',\n height: '32',\n border: '0',\n },\n isVoid: true,\n }),\n\n equation: boxValue => ({\n tagName: 'code',\n innerHTML: boxValue.code,\n }),\n\n mention: (boxValue, encode) => ({\n tagName: 'a',\n attributes: {\n href: `/${boxValue.name}`,\n target: '_blank',\n },\n innerHTML: encode(boxValue.nickname ?? boxValue.name),\n }),\n\n video: boxValue => ({\n tagName: 'iframe',\n attributes: {\n ...(boxValue.url && { src: `https://www.youtube.com/embed/${extractIdFromUrl(boxValue.url)}` }),\n title: 'YouTube video player',\n frameborder: '0',\n allow: 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share',\n referrerpolicy: 'strict-origin-when-cross-origin',\n allowfullscreen: 'true',\n style: 'width: 560px; height: 315px;',\n },\n }),\n\n twitter: boxValue => ({\n tagName: 'iframe',\n attributes: {\n ...(boxValue.url && { src: `https://platform.twitter.com/embed/Tweet.html?id=${extractIdFromUrl(boxValue.url)}` }),\n title: 'Twitter tweet',\n scrolling: 'no',\n frameborder: '0',\n allowtransparency: 'true',\n allowfullscreen: 'true',\n style: 'width: 550px; height: 300px;',\n },\n }),\n };\n}\n\n// Map for reserved HTML characters\nconst htmlEntityMap = new Map([\n ['&', '&'],\n ['<', '<'],\n ['>', '>'],\n ['\"', '"'],\n ['\\xA0', ' '],\n]);\n\n/**\n * Escapes reserved HTML characters to prevent XSS and rendering issues.\n */\nfunction encodeHTMLEntities(value: string): string {\n return value.replace(/[&<>\"\\xA0]/g, match => htmlEntityMap.get(match)!);\n}\n\n/**\n * Decodes a Base64 encoded string with UTF-8 support.\n */\nfunction decodeBase64(value: string): string {\n const binaryString = atob(value);\n const byteArray = new Uint8Array(binaryString.length);\n for (let i = 0; i < binaryString.length; i++) {\n byteArray[i] = binaryString.charCodeAt(i);\n }\n const decoder = new TextDecoder();\n return decoder.decode(byteArray);\n}\n\n/**\n * Parses HTML tag attributes from a string into a key-value object.\n */\nfunction parseAttributes(tag: string): AttributeMap {\n const attributes: AttributeMap = {};\n // Regex breakdown:\n // Group 1/2: Key=Value (unquoted)\n // Group 3/4: Key=\"Value\" (double quoted)\n // Group 5/6: Key='Value' (single quoted)\n const reg = /\\s+(?:([\\w\\-:]+)=([^\\s\"'<>]+)|([\\w\\-:\"]+)=\"([^\"]*)\"|([\\w\\-:\"]+)='([^']*)')(?=[\\s/>])/g;\n let match: RegExpExecArray | null;\n while ((match = reg.exec(tag))) {\n const key = (match[1] || match[3] || match[5]).toLowerCase();\n const value = match[1] ? match[2] : (match[3] ? match[4] : match[6]);\n attributes[key] = value;\n }\n return attributes;\n}\n\n/**\n * Serializes an attribute map into an HTML attribute string.\n */\nfunction serializeAttributes(attrs: AttributeMap): string {\n const result: string[] = [];\n for (const key of Object.keys(attrs)) {\n const value = String(attrs[key]);\n result.push(`${key}=\"${encodeHTMLEntities(value)}\"`);\n }\n return result.join(' ');\n}\n\n/**\n * Serializes a BoxHTMLNode object into a standard HTML string.\n */\nfunction toBoxHTML(node: BoxHTMLNode): string {\n let result = `<${node.tagName}`;\n if (node.attributes) {\n result += ` ${serializeAttributes(node.attributes)}`;\n }\n if (node.isVoid === true) {\n result += ' />';\n } else {\n result += `>${node.innerHTML ?? ''}</${node.tagName}>`;\n }\n return result;\n}\n\n/**\n * Main function to convert Lake Markup Language (LML) to standard HTML.\n * It processes custom <lake-box> tags and removes internal anchors.\n */\nexport function toHTML(value: string, renderers?: BoxRenderers): string {\n renderers = renderers ?? getBoxRenderers();\n // Regex to match <lake-box>, <anchor>, and <focus> tags\n const combinedRegex = /(<lake-box[^>]+>)[\\s\\S]*?(?:<\\/lake-box>|$)|(<anchor\\s*\\/>)|(<focus\\s*\\/>)/gi;\n return value.replace(combinedRegex, (match, boxOpen) => {\n // Handle lake-box conversion\n if (boxOpen) {\n const attributes = parseAttributes(boxOpen);\n const render = renderers[attributes.name];\n if (render) {\n try {\n const boxValue = attributes.value ? JSON.parse(decodeBase64(attributes.value)) : {};\n const node = render(boxValue, encodeHTMLEntities);\n return toBoxHTML(node);\n } catch (e) {\n console.error('Failed to parse lake-box value:', e);\n }\n }\n }\n // Remove internal selection markers (<anchor /> and <focus />)\n return '';\n });\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["// Define a generic type for HTML attributes (key-value pairs)\ntype AttributeMap = Record<string, string>;\n\n// Structure representing the output HTML node\ninterface BoxHTMLNode {\n tagName: string;\n attributes?: AttributeMap;\n isVoid?: boolean; // True for self-closing tags like <img />, <hr />\n innerHTML?: string;\n}\n\n// Function signature for encoding HTML entities\ntype EncodeHTMLEntities = (value: string) => string;\n\n// Function signature for encoding HTML entities\ntype RenderBox = (boxValue: AttributeMap, encode: EncodeHTMLEntities) => BoxHTMLNode;\n\n// Registry of renderers for different box types\ntype BoxRenderers = Record<string, RenderBox>;\n\n/**\n * Extracts the ID from a URL.\n * Useful for extracting YouTube or Twitter IDs from clean URLs.\n */\nfunction extractIdFromUrl(url: string): string {\n const result = /[\\w\\-]+$/.exec(url);\n return result ? result[0] : '';\n}\n\n/**\n * Returns the default configuration for rendering various Lake attributes.\n */\nexport function getBoxRenderers(): BoxRenderers {\n return {\n hr: () => ({\n tagName: 'div',\n attributes: {\n class: 'lake-box-block lake-hr',\n },\n innerHTML: '<hr />',\n }),\n\n image: boxValue => ({\n tagName: 'img',\n attributes: {\n src: boxValue.url,\n ...(boxValue.width && { width: boxValue.width }),\n ...(boxValue.height && { height: boxValue.height }),\n ...(boxValue.caption && { alt: boxValue.caption }),\n border: '0',\n },\n isVoid: true,\n }),\n\n media: boxValue => ({\n tagName: 'video',\n attributes: {\n src: boxValue.url,\n ...(boxValue.width && { width: boxValue.width.replace(/px$/i, '') }),\n ...(boxValue.height && { height: boxValue.height.replace(/px$/i, '') }),\n controls: 'true',\n },\n }),\n\n file: (boxValue, encode) => ({\n tagName: 'a',\n attributes: {\n href: boxValue.url,\n target: '_blank',\n },\n innerHTML: encode(boxValue.name),\n }),\n\n codeBlock: (boxValue, encode) => ({\n tagName: 'pre',\n attributes: {\n class: `lang-${boxValue.lang}`,\n },\n innerHTML: `<code>${encode(boxValue.code)}</code>`,\n }),\n\n emoji: boxValue => ({\n tagName: 'img',\n attributes: {\n src: boxValue.url,\n width: '32',\n height: '32',\n border: '0',\n },\n isVoid: true,\n }),\n\n equation: boxValue => ({\n tagName: 'code',\n innerHTML: boxValue.code,\n }),\n\n mention: (boxValue, encode) => ({\n tagName: 'a',\n attributes: {\n href: `/${boxValue.name}`,\n target: '_blank',\n },\n innerHTML: encode(boxValue.nickname ?? boxValue.name),\n }),\n\n video: boxValue => ({\n tagName: 'iframe',\n attributes: {\n ...(boxValue.url && { src: `https://www.youtube.com/embed/${extractIdFromUrl(boxValue.url)}` }),\n width: boxValue.width ? boxValue.width.replace(/px$/i, '') : '560',\n height: boxValue.height ? boxValue.height.replace(/px$/i, '') : '315',\n title: 'YouTube video player',\n frameborder: '0',\n allow: 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share',\n referrerpolicy: 'strict-origin-when-cross-origin',\n allowfullscreen: 'true',\n },\n }),\n\n twitter: boxValue => ({\n tagName: 'iframe',\n attributes: {\n ...(boxValue.url && { src: `https://platform.twitter.com/embed/Tweet.html?id=${extractIdFromUrl(boxValue.url)}` }),\n title: 'Twitter tweet',\n scrolling: 'no',\n frameborder: '0',\n allowtransparency: 'true',\n allowfullscreen: 'true',\n style: 'width: 550px; height: 300px;',\n },\n }),\n };\n}\n\n// Map for reserved HTML characters\nconst htmlEntityMap = new Map([\n ['&', '&'],\n ['<', '<'],\n ['>', '>'],\n ['\"', '"'],\n ['\\xA0', ' '],\n]);\n\n/**\n * Escapes reserved HTML characters to prevent XSS and rendering issues.\n */\nfunction encodeHTMLEntities(value: string): string {\n return value.replace(/[&<>\"\\xA0]/g, match => htmlEntityMap.get(match)!);\n}\n\n/**\n * Decodes a Base64 encoded string with UTF-8 support.\n */\nfunction decodeBase64(value: string): string {\n const binaryString = atob(value);\n const byteArray = new Uint8Array(binaryString.length);\n for (let i = 0; i < binaryString.length; i++) {\n byteArray[i] = binaryString.charCodeAt(i);\n }\n const decoder = new TextDecoder();\n return decoder.decode(byteArray);\n}\n\n/**\n * Parses HTML tag attributes from a string into a key-value object.\n */\nfunction parseAttributes(tag: string): AttributeMap {\n const attributes: AttributeMap = {};\n // Regex breakdown:\n // Group 1/2: Key=Value (unquoted)\n // Group 3/4: Key=\"Value\" (double quoted)\n // Group 5/6: Key='Value' (single quoted)\n const reg = /\\s+(?:([\\w\\-:]+)=([^\\s\"'<>]+)|([\\w\\-:\"]+)=\"([^\"]*)\"|([\\w\\-:\"]+)='([^']*)')(?=[\\s/>])/g;\n let match: RegExpExecArray | null;\n while ((match = reg.exec(tag))) {\n const key = (match[1] || match[3] || match[5]).toLowerCase();\n const value = match[1] ? match[2] : (match[3] ? match[4] : match[6]);\n attributes[key] = value;\n }\n return attributes;\n}\n\n/**\n * Serializes an attribute map into an HTML attribute string.\n */\nfunction serializeAttributes(attrs: AttributeMap): string {\n const result: string[] = [];\n for (const key of Object.keys(attrs)) {\n const value = String(attrs[key]);\n result.push(`${key}=\"${encodeHTMLEntities(value)}\"`);\n }\n return result.join(' ');\n}\n\n/**\n * Serializes a BoxHTMLNode object into a standard HTML string.\n */\nfunction toBoxHTML(node: BoxHTMLNode): string {\n let result = `<${node.tagName}`;\n if (node.attributes) {\n result += ` ${serializeAttributes(node.attributes)}`;\n }\n if (node.isVoid === true) {\n result += ' />';\n } else {\n result += `>${node.innerHTML ?? ''}</${node.tagName}>`;\n }\n return result;\n}\n\n/**\n * Main function to convert Lake Markup Language (LML) to standard HTML.\n * It processes custom <lake-box> tags and removes internal anchors.\n */\nexport function toHTML(value: string, renderers?: BoxRenderers): string {\n renderers = renderers ?? getBoxRenderers();\n // Regex to match <lake-box>, <anchor>, and <focus> tags\n const combinedRegex = /(<lake-box[^>]+>)[\\s\\S]*?(?:<\\/lake-box>|$)|(<anchor\\s*\\/>)|(<focus\\s*\\/>)/gi;\n return value.replace(combinedRegex, (match, boxOpen) => {\n // Handle lake-box conversion\n if (boxOpen) {\n const attributes = parseAttributes(boxOpen);\n const render = renderers[attributes.name];\n if (render) {\n try {\n const boxValue = attributes.value ? JSON.parse(decodeBase64(attributes.value)) : {};\n const node = render(boxValue, encodeHTMLEntities);\n return toBoxHTML(node);\n } catch (e) {\n console.error('Failed to parse lake-box value:', e);\n }\n }\n }\n // Remove internal selection markers (<anchor /> and <focus />)\n return '';\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAwBA,SAAS,iBAAiB,KAAqB;AAC7C,QAAM,SAAS,WAAW,KAAK,GAAG;AAClC,SAAO,SAAS,OAAO,CAAC,IAAI;AAC9B;AAKO,SAAS,kBAAgC;AAC9C,SAAO;AAAA,IACL,IAAI,OAAO;AAAA,MACT,SAAS;AAAA,MACT,YAAY;AAAA,QACV,OAAO;AAAA,MACT;AAAA,MACA,WAAW;AAAA,IACb;AAAA,IAEA,OAAO,eAAa;AAAA,MAClB,SAAS;AAAA,MACT,YAAY;AAAA,QACV,KAAK,SAAS;AAAA,SACV,SAAS,SAAS,EAAE,OAAO,SAAS,MAAM,IAC1C,SAAS,UAAU,EAAE,QAAQ,SAAS,OAAO,IAC7C,SAAS,WAAW,EAAE,KAAK,SAAS,QAAQ,IAJtC;AAAA,QAKV,QAAQ;AAAA,MACV;AAAA,MACA,QAAQ;AAAA,IACV;AAAA,IAEA,OAAO,eAAa;AAAA,MAClB,SAAS;AAAA,MACT,YAAY;AAAA,QACV,KAAK,SAAS;AAAA,SACV,SAAS,SAAS,EAAE,OAAO,SAAS,MAAM,QAAQ,QAAQ,EAAE,EAAE,IAC9D,SAAS,UAAU,EAAE,QAAQ,SAAS,OAAO,QAAQ,QAAQ,EAAE,EAAE,IAH3D;AAAA,QAIV,UAAU;AAAA,MACZ;AAAA,IACF;AAAA,IAEA,MAAM,CAAC,UAAU,YAAY;AAAA,MAC3B,SAAS;AAAA,MACT,YAAY;AAAA,QACV,MAAM,SAAS;AAAA,QACf,QAAQ;AAAA,MACV;AAAA,MACA,WAAW,OAAO,SAAS,IAAI;AAAA,IACjC;AAAA,IAEA,WAAW,CAAC,UAAU,YAAY;AAAA,MAChC,SAAS;AAAA,MACT,YAAY;AAAA,QACV,OAAO,QAAQ,SAAS,IAAI;AAAA,MAC9B;AAAA,MACA,WAAW,SAAS,OAAO,SAAS,IAAI,CAAC;AAAA,IAC3C;AAAA,IAEA,OAAO,eAAa;AAAA,MAClB,SAAS;AAAA,MACT,YAAY;AAAA,QACV,KAAK,SAAS;AAAA,QACd,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,QAAQ;AAAA,MACV;AAAA,MACA,QAAQ;AAAA,IACV;AAAA,IAEA,UAAU,eAAa;AAAA,MACrB,SAAS;AAAA,MACT,WAAW,SAAS;AAAA,IACtB;AAAA,IAEA,SAAS,CAAC,UAAU,WAAQ;AAjGhC;AAiGoC;AAAA,QAC9B,SAAS;AAAA,QACT,YAAY;AAAA,UACV,MAAM,IAAI,SAAS,IAAI;AAAA,UACvB,QAAQ;AAAA,QACV;AAAA,QACA,WAAW,QAAO,cAAS,aAAT,YAAqB,SAAS,IAAI;AAAA,MACtD;AAAA;AAAA,IAEA,OAAO,eAAa;AAAA,MAClB,SAAS;AAAA,MACT,YAAY,iCACN,SAAS,OAAO,EAAE,KAAK,iCAAiC,iBAAiB,SAAS,GAAG,CAAC,GAAG,IADnF;AAAA,QAEV,OAAO,SAAS,QAAQ,SAAS,MAAM,QAAQ,QAAQ,EAAE,IAAI;AAAA,QAC7D,QAAQ,SAAS,SAAS,SAAS,OAAO,QAAQ,QAAQ,EAAE,IAAI;AAAA,QAChE,OAAO;AAAA,QACP,aAAa;AAAA,QACb,OAAO;AAAA,QACP,gBAAgB;AAAA,QAChB,iBAAiB;AAAA,MACnB;AAAA,IACF;AAAA,IAEA,SAAS,eAAa;AAAA,MACpB,SAAS;AAAA,MACT,YAAY,iCACN,SAAS,OAAO,EAAE,KAAK,oDAAoD,iBAAiB,SAAS,GAAG,CAAC,GAAG,IADtG;AAAA,QAEV,OAAO;AAAA,QACP,WAAW;AAAA,QACX,aAAa;AAAA,QACb,mBAAmB;AAAA,QACnB,iBAAiB;AAAA,QACjB,OAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AACF;AAGA,IAAM,gBAAgB,oBAAI,IAAI;AAAA,EAC5B,CAAC,KAAK,OAAO;AAAA,EACb,CAAC,KAAK,MAAM;AAAA,EACZ,CAAC,KAAK,MAAM;AAAA,EACZ,CAAC,KAAK,QAAQ;AAAA,EACd,CAAC,QAAQ,QAAQ;AACnB,CAAC;AAKD,SAAS,mBAAmB,OAAuB;AACjD,SAAO,MAAM,QAAQ,eAAe,WAAS,cAAc,IAAI,KAAK,CAAE;AACxE;AAKA,SAAS,aAAa,OAAuB;AAC3C,QAAM,eAAe,KAAK,KAAK;AAC/B,QAAM,YAAY,IAAI,WAAW,aAAa,MAAM;AACpD,WAAS,IAAI,GAAG,IAAI,aAAa,QAAQ,KAAK;AAC5C,cAAU,CAAC,IAAI,aAAa,WAAW,CAAC;AAAA,EAC1C;AACA,QAAM,UAAU,IAAI,YAAY;AAChC,SAAO,QAAQ,OAAO,SAAS;AACjC;AAKA,SAAS,gBAAgB,KAA2B;AAClD,QAAM,aAA2B,CAAC;AAKlC,QAAM,MAAM;AACZ,MAAI;AACJ,SAAQ,QAAQ,IAAI,KAAK,GAAG,GAAI;AAC9B,UAAM,OAAO,MAAM,CAAC,KAAK,MAAM,CAAC,KAAK,MAAM,CAAC,GAAG,YAAY;AAC3D,UAAM,QAAQ,MAAM,CAAC,IAAI,MAAM,CAAC,IAAK,MAAM,CAAC,IAAI,MAAM,CAAC,IAAI,MAAM,CAAC;AAClE,eAAW,GAAG,IAAI;AAAA,EACpB;AACA,SAAO;AACT;AAKA,SAAS,oBAAoB,OAA6B;AACxD,QAAM,SAAmB,CAAC;AAC1B,aAAW,OAAO,OAAO,KAAK,KAAK,GAAG;AACpC,UAAM,QAAQ,OAAO,MAAM,GAAG,CAAC;AAC/B,WAAO,KAAK,GAAG,GAAG,KAAK,mBAAmB,KAAK,CAAC,GAAG;AAAA,EACrD;AACA,SAAO,OAAO,KAAK,GAAG;AACxB;AAKA,SAAS,UAAU,MAA2B;AAtM9C;AAuME,MAAI,SAAS,IAAI,KAAK,OAAO;AAC7B,MAAI,KAAK,YAAY;AACnB,cAAU,IAAI,oBAAoB,KAAK,UAAU,CAAC;AAAA,EACpD;AACA,MAAI,KAAK,WAAW,MAAM;AACxB,cAAU;AAAA,EACZ,OAAO;AACL,cAAU,KAAI,UAAK,cAAL,YAAkB,EAAE,KAAK,KAAK,OAAO;AAAA,EACrD;AACA,SAAO;AACT;AAMO,SAAS,OAAO,OAAe,WAAkC;AACtE,cAAY,gCAAa,gBAAgB;AAEzC,QAAM,gBAAgB;AACtB,SAAO,MAAM,QAAQ,eAAe,CAAC,OAAO,YAAY;AAEtD,QAAI,SAAS;AACX,YAAM,aAAa,gBAAgB,OAAO;AAC1C,YAAM,SAAS,UAAU,WAAW,IAAI;AACxC,UAAI,QAAQ;AACV,YAAI;AACF,gBAAM,WAAW,WAAW,QAAQ,KAAK,MAAM,aAAa,WAAW,KAAK,CAAC,IAAI,CAAC;AAClF,gBAAM,OAAO,OAAO,UAAU,kBAAkB;AAChD,iBAAO,UAAU,IAAI;AAAA,QACvB,SAAS,GAAG;AACV,kBAAQ,MAAM,mCAAmC,CAAC;AAAA,QACpD;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT,CAAC;AACH;","names":[]}
|