turnish 1.1.0 → 1.2.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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.iife.js","sources":["../src/node.ts","../src/utilities.ts","../src/default-rules.ts","../src/rules.ts","../src/collapse-whitespace.ts","../src/html-parser.ts","../src/root-node.ts","../src/index.ts"],"sourcesContent":["import { isBlock, isVoid, hasVoid, isMeaningfulWhenBlank, hasMeaningfulWhenBlank } from '@/utilities'\n\ninterface Options {\n preformattedCode?: boolean;\n}\n\ninterface FlankingWhitespace {\n leading: string;\n trailing: string;\n}\n\ninterface EdgeWhitespace extends FlankingWhitespace {\n leadingAscii: string;\n leadingNonAscii: string;\n trailingNonAscii: string;\n trailingAscii: string;\n}\n\nexport interface ExtendedNode extends Element {\n isBlock: boolean;\n isCode: boolean;\n isBlank: boolean;\n flankingWhitespace: FlankingWhitespace;\n}\n\nexport function ExtendedNode(node: Node, options: Options): ExtendedNode {\n const extended = node as ExtendedNode;\n extended.isBlock = isBlock(extended);\n extended.isCode = extended.nodeName === 'CODE' || (extended.parentNode as ExtendedNode)?.isCode;\n extended.isBlank = isBlank(extended);\n extended.flankingWhitespace = flankingWhitespace(extended, options);\n return extended;\n}\n\nfunction isBlank(node: ExtendedNode): boolean {\n return (\n !isVoid(node) &&\n !isMeaningfulWhenBlank(node) &&\n /^\\s*$/i.test(node.textContent || '') &&\n !hasVoid(node) &&\n !hasMeaningfulWhenBlank(node)\n )\n}\n\nfunction flankingWhitespace(node: ExtendedNode, options: Options): FlankingWhitespace {\n const extendedNode = node as ExtendedNode;\n\n if (extendedNode.isBlock || (options.preformattedCode && extendedNode.isCode)) {\n return { leading: '', trailing: '' };\n }\n\n const edges = edgeWhitespace(node.textContent || '');\n\n // abandon leading ASCII WS if left-flanked by ASCII WS\n if (edges.leadingAscii && isFlankedByWhitespace('left', node, options)) {\n edges.leading = edges.leadingNonAscii;\n }\n\n // abandon trailing ASCII WS if right-flanked by ASCII WS\n if (edges.trailingAscii && isFlankedByWhitespace('right', node, options)) {\n edges.trailing = edges.trailingNonAscii;\n }\n\n return { leading: edges.leading, trailing: edges.trailing };\n}\n\nfunction edgeWhitespace(string: string): EdgeWhitespace {\n const m = string.match(/^(([ \\t\\r\\n]*)(\\s*))(?:(?=\\S)[\\s\\S]*\\S)?((\\s*?)([ \\t\\r\\n]*))$/);\n\n if (!m) {\n return {\n leading: '',\n leadingAscii: '',\n leadingNonAscii: '',\n trailing: '',\n trailingNonAscii: '',\n trailingAscii: ''\n };\n }\n\n return {\n leading: m[1], // whole string for whitespace-only strings\n leadingAscii: m[2],\n leadingNonAscii: m[3],\n trailing: m[4], // empty for whitespace-only strings\n trailingNonAscii: m[5],\n trailingAscii: m[6]\n };\n}\n\nfunction isFlankedByWhitespace(side: 'left' | 'right', node: Element, options: Options): boolean {\n let sibling: Element | null;\n let regExp: RegExp;\n let isFlanked: boolean | undefined;\n\n if (side === 'left') {\n sibling = node.previousElementSibling;\n regExp = / $/;\n } else {\n sibling = node.nextElementSibling;\n regExp = /^ /;\n }\n\n if (sibling) {\n if (sibling.nodeType === 3) {\n isFlanked = regExp.test(sibling.nodeValue || '');\n } else if (options.preformattedCode && sibling.nodeName === 'CODE') {\n isFlanked = false;\n } else if (sibling.nodeType === 1 && !isBlock(sibling)) {\n isFlanked = regExp.test(sibling.textContent || '');\n }\n }\n\n return isFlanked || false;\n}\n\nexport const NodeTypes = {\n Element: 1,\n Text: 3,\n CDATASection: 4,\n Comment: 8\n} as const;\n\nexport type NodeType = typeof NodeTypes[keyof typeof NodeTypes];\n","import { ExtendedNode, NodeTypes } from \"./node\";\n\nexport function repeat(character: string, count: number) {\n return Array(count + 1).join(character)\n}\n\nexport function trimLeadingNewlines(string: string) {\n return string.replace(/^\\n*/, '')\n}\n\nexport function trimTrailingNewlines(string: string) {\n // avoid match-at-end regexp bottleneck, see #370\n let indexEnd = string.length\n while (indexEnd > 0 && string[indexEnd - 1] === '\\n') indexEnd--\n return string.substring(0, indexEnd)\n}\n\nexport function trimNewlines(string: string) {\n return trimTrailingNewlines(trimLeadingNewlines(string))\n}\n\nexport const blockElements = [\n 'ADDRESS', 'ARTICLE', 'ASIDE', 'AUDIO', 'BLOCKQUOTE', 'BODY', 'CANVAS',\n 'CENTER', 'DD', 'DIR', 'DIV', 'DL', 'DT', 'FIELDSET', 'FIGCAPTION', 'FIGURE',\n 'FOOTER', 'FORM', 'FRAMESET', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'HEADER',\n 'HGROUP', 'HR', 'HTML', 'ISINDEX', 'LI', 'MAIN', 'MENU', 'NAV', 'NOFRAMES',\n 'NOSCRIPT', 'OL', 'OUTPUT', 'P', 'PRE', 'SECTION', 'TABLE', 'TBODY', 'TD',\n 'TFOOT', 'TH', 'THEAD', 'TR', 'UL'\n]\n\nexport function isBlock(node: Node) {\n return is(node, blockElements)\n}\n\nexport const voidElements = [\n 'AREA', 'BASE', 'BR', 'COL', 'COMMAND', 'EMBED', 'HR', 'IMG', 'INPUT',\n 'KEYGEN', 'LINK', 'META', 'PARAM', 'SOURCE', 'TRACK', 'WBR'\n]\n\nexport function isVoid(node: Node) {\n return is(node, voidElements)\n}\n\nexport function hasVoid(node: Node) {\n return has(node, voidElements)\n}\n\nconst meaningfulWhenBlankElements = [\n 'A', 'TABLE', 'THEAD', 'TBODY', 'TFOOT', 'TH', 'TD', 'IFRAME', 'SCRIPT',\n 'AUDIO', 'VIDEO'\n]\n\nexport const standardMarkdownElements = [\n 'P', 'BR', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'BLOCKQUOTE',\n 'UL', 'OL', 'LI', 'PRE', 'CODE', 'HR', 'A', 'EM', 'I', 'STRONG',\n 'B', 'IMG', 'DIV', 'SPAN', 'TABLE', 'THEAD', 'TBODY', 'TR', 'TH', 'TD'\n]\n\nexport function isMeaningfulWhenBlank(node: Node) {\n return is(node, meaningfulWhenBlankElements)\n}\n\nexport function hasMeaningfulWhenBlank(node: Node) {\n return has(node, meaningfulWhenBlankElements)\n}\n\nfunction is(node: Node, tagNames: string[]) {\n return tagNames.indexOf(node.nodeName) >= 0\n}\n\nfunction has(node: Node, tagNames: string[]) {\n return (\n tagNames.some(function (tagName) {\n if (node.nodeType !== NodeTypes.Element) {\n return false;\n }\n return (node as Element).getElementsByTagName(tagName).length\n })\n )\n}\n\nexport function sanitizeWhitespace(string: string): string {\n return string ? string.replace(/(\\n+\\s*)+/g, '\\n') : '';\n}\n\nexport function sanitizedLinkContent(content: string): string {\n const sanitized = sanitizeWhitespace(content);\n return sanitized\n .replace(/[\\t\\r\\n]+/g, ' ')\n .replace(/ {2,}/g, ' ')\n .replace(/([()])/g, '\\\\$1')\n .trim();\n}\n\nexport function sanitizedLinkTitle(content: string): string {\n const sanitized = sanitizeWhitespace(content);\n return sanitized\n .replace(/[\\t\\r\\n]+/g, ' ');\n}\n\nexport type RequireOnly<T, K extends keyof T> =\n T & Required<Pick<T, K>>;\n","\nimport { Rule } from '@/rules';\nimport { TurnishOptions } from '@/index';\nimport { repeat, RequireOnly, sanitizedLinkContent, sanitizedLinkTitle, trimNewlines } from '@/utilities';\nimport { NodeTypes } from './node';\n\nexport const defaultRules: { [key: string]: Rule } = {}\n\ndefaultRules.paragraph = {\n filter: 'p',\n replacement: function (content: string): string {\n return '\\n\\n' + content + '\\n\\n';\n }\n};\n\ndefaultRules.lineBreak = {\n filter: 'br',\n replacement: function (_content: string, _node: Node, options: TurnishOptions): string {\n return options.br + '\\n';\n }\n};\n\ndefaultRules.heading = {\n filter: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'],\n replacement: function (content: string, node: Node, options: TurnishOptions): string {\n const hLevel = Number(node.nodeName.charAt(1));\n if (options.headingStyle === 'setext' && hLevel < 3) {\n const underline = repeat((hLevel === 1 ? '=' : '-'), content.length);\n return (\n '\\n\\n' + content + '\\n' + underline + '\\n\\n'\n );\n } else {\n return '\\n\\n' + repeat('#', hLevel) + ' ' + content + '\\n\\n';\n }\n }\n};\n\ndefaultRules.blockquote = {\n filter: 'blockquote',\n replacement: function (content: string): string {\n content = trimNewlines(content).replace(/^/gm, '> ');\n return '\\n\\n' + content + '\\n\\n';\n }\n};\n\ndefaultRules.list = {\n filter: ['ul', 'ol'],\n replacement: function (content: string, node: Node): string {\n const parent = node.parentNode as Element;\n if (parent.nodeName === 'LI' && parent.lastElementChild === node) {\n return '\\n' + content;\n } else {\n return '\\n\\n' + content + '\\n\\n';\n }\n }\n};\n\ndefaultRules.listItem = {\n filter: 'li',\n replacement: function (content: string, node: Node, options: TurnishOptions): string {\n let prefix = options.bulletListMarker + ' '.repeat(options.listMarkerSpaceCount);\n const parent = node.parentNode as Element;\n if (parent.nodeName === 'OL') {\n const start = parent.getAttribute('start');\n const index = Array.prototype.indexOf.call(parent.children, node);\n prefix = (start ? Number(start) + index : index + 1) + '.' + ' '.repeat(options.listMarkerSpaceCount);\n }\n const isParagraph = /\\n$/.test(content);\n content = trimNewlines(content) + (isParagraph ? '\\n' : '');\n\n const hasOnlyNestedList = node.childNodes.length > 0 &&\n Array.from(node.childNodes).every((child: Node) => {\n return (child.nodeType === NodeTypes.Text && /^\\s*$/.test(child.nodeValue || ''))\n || (child.nodeType === NodeTypes.Element && ['UL', 'OL'].includes(child.nodeName));\n });\n if (hasOnlyNestedList && content.trim() !== '') {\n // This list item only contains a nested list, don't duplicate marker\n return content + (node.nextSibling ? '\\n' : '');\n }\n\n let nestingLevel = 0;\n let currentNode: Node | null = parent;\n while (currentNode) {\n if (currentNode.nodeName === 'UL' || currentNode.nodeName === 'OL') {\n const grandparent = currentNode.parentNode as Element | null;\n if (grandparent && grandparent.nodeName === 'LI') {\n nestingLevel++;\n }\n }\n currentNode = currentNode.parentNode;\n }\n\n let oneIndent = options.listItemIndent === 'tab' ? '\\t' : ' '.repeat(options.listItemIndentSpaceCount);\n let indent = oneIndent.repeat(nestingLevel);\n const listMarkerRegex = /\\n(?!\\s*(?:\\d+\\.\\s|[-+*]\\s))/gm;\n content = content.replace(listMarkerRegex, '\\n' + oneIndent);\n return indent + prefix + content + (node.nextSibling ? '\\n' : '');\n }\n};\n\ndefaultRules.indentedCodeBlock = {\n filter: function (node: Node, options: TurnishOptions): boolean {\n return !!(\n options &&\n options.codeBlockStyle === 'indented' &&\n node.nodeName === 'PRE' &&\n node.firstChild &&\n (node.firstChild as Element).nodeName === 'CODE'\n );\n },\n replacement: function (_content: string, node: Node): string {\n if (!node || !node.firstChild) return '';\n return (\n '\\n\\n ' +\n (node.firstChild as Element).textContent!.replace(/\\n/g, '\\n ') +\n '\\n\\n'\n );\n }\n};\n\ndefaultRules.fencedCodeBlock = {\n filter: function (node: Node, options: TurnishOptions): boolean {\n return !!(\n options &&\n options.codeBlockStyle === 'fenced' &&\n node.nodeName === 'PRE' &&\n node.firstChild &&\n (node.firstChild as Element).nodeName === 'CODE'\n );\n },\n replacement: function (_content: string, node: Node, options: TurnishOptions): string {\n if (!node.firstChild) {\n return '';\n }\n const codeElem = node.firstChild as Element;\n const className = codeElem.getAttribute('class') || '';\n const language = (className.match(/language-(\\S+)/) || [null, ''])[1];\n const code = codeElem.textContent || '';\n const fenceChar = options.fence?.charAt(0) || '`';\n let fenceSize = 3;\n const fenceInCodeRegex = new RegExp('^' + fenceChar + '{3,}', 'gm');\n let match;\n while ((match = fenceInCodeRegex.exec(code))) {\n if (match[0].length >= fenceSize) {\n fenceSize = match[0].length + 1;\n }\n }\n const fence = repeat(fenceChar, fenceSize);\n return (\n '\\n\\n' + fence + language + '\\n' +\n code.replace(/\\n$/, '') +\n '\\n' + fence + '\\n\\n'\n );\n }\n};\n\ndefaultRules.horizontalRule = {\n filter: 'hr',\n replacement: function (_content: string, _node: Node, options: TurnishOptions): string {\n return '\\n\\n' + options.hr + '\\n\\n';\n }\n};\n\ndefaultRules.inlineLink = {\n filter: function (node: Node, options: TurnishOptions): boolean {\n return !!(\n options?.linkStyle === 'inlined' &&\n node.nodeName === 'A' &&\n (node as Element).getAttribute('href')\n );\n },\n replacement: function (content: string, node: Node): string {\n const sanitizedContent = sanitizedLinkContent(content);\n let href = (node as Element)\n .getAttribute('href')\n ?.replace(/([()])/g, '\\\\$1');\n let title: string;\n const titleAttr = (node as Element).getAttribute('title');\n if (titleAttr) {\n const sanitizedTitle = sanitizedLinkTitle(titleAttr);\n title = ' \"' + sanitizedTitle.replace(/\"/g, '\\\\\"') + '\"';\n } else {\n title = '';\n }\n return '[' + sanitizedContent + '](' + href + title + ')';\n }\n};\n\nconst referenceLinkRule: RequireOnly<Rule, \"urlReferenceIdMap\" | \"references\"> = {\n filter: function (node: Node, options: TurnishOptions): boolean {\n return !!(\n options &&\n options.linkStyle === 'referenced' &&\n node.nodeName === 'A' &&\n (node as Element).getAttribute('href')\n );\n },\n replacement: function (content: string, node: Node, options: TurnishOptions): string {\n const self = referenceLinkRule;\n\n const href = (node as Element).getAttribute('href');\n let title: string;\n const titleAttr = (node as Element).getAttribute('title');\n if (titleAttr) {\n const sanitizedTitle = sanitizedLinkTitle(titleAttr);\n title = ' \"' + sanitizedTitle + '\"';\n } else {\n title = '';\n }\n const referenceKey = href + title;\n\n let replacement: string;\n let reference: string;\n switch (options.linkReferenceStyle) {\n case 'collapsed':\n replacement = '[' + content + '][]';\n reference = '[' + content + ']: ' + referenceKey;\n break;\n case 'shortcut':\n replacement = '[' + content + ']';\n reference = '[' + content + ']: ' + referenceKey;\n break;\n default: {\n let id: number;\n const existingKey = self.urlReferenceIdMap.get(referenceKey);\n if (options.linkReferenceDeduplication === 'full' && existingKey) {\n id = existingKey;\n reference = '[' + id + ']: ' + href + title;\n } else {\n id = self.references.length + 1;\n self.urlReferenceIdMap.set(referenceKey, id);\n reference = '[' + id + ']: ' + href + title;\n self.references.push(reference);\n }\n replacement = '[' + content + '][' + id + ']';\n break;\n }\n }\n\n if (options.linkReferenceStyle !== 'full') {\n // Check if we should deduplicate\n if (options.linkReferenceDeduplication === 'full') {\n if (!self.urlReferenceIdMap.has(referenceKey)) {\n self.urlReferenceIdMap.set(referenceKey, 1);\n self.references.push(reference);\n }\n } else {\n self.references.push(reference);\n }\n }\n return replacement;\n },\n references: [],\n urlReferenceIdMap: new Map<string, number>(),\n append: (): string => {\n const self = referenceLinkRule;\n let references = '';\n if (self.references && self.references.length) {\n references = '\\n\\n' + self.references.join('\\n') + '\\n\\n';\n self.references = [];\n self.urlReferenceIdMap = new Map();\n }\n return references;\n }\n};\n\ndefaultRules.referenceLink = referenceLinkRule;\n\ndefaultRules.emphasis = {\n filter: ['em', 'i'],\n replacement: (content: string, _node: Node, options: TurnishOptions): string => {\n content = content.trim();\n if (!content) { return ''; }\n return options.emDelimiter + content + options.emDelimiter;\n }\n};\n\ndefaultRules.strong = {\n filter: ['strong', 'b'],\n replacement: (content: string, _node: Node, options: TurnishOptions): string => {\n content = content.trim();\n if (!content) { return ''; }\n return options.strongDelimiter + content + options.strongDelimiter;\n }\n};\n\ndefaultRules.code = {\n filter: (node: Node): boolean => {\n const hasSiblings = node.previousSibling || node.nextSibling;\n const parent = node.parentNode as Element;\n const isCodeBlock = parent.nodeName === 'PRE' && !hasSiblings;\n return node.nodeName === 'CODE' && !isCodeBlock;\n },\n replacement: (content: string): string => {\n const trimmed = content.replace(/\\r?\\n|\\r/g, ' ');\n const extraSpace = /^`|^ .*?[^ ].* $|`$/.test(trimmed) ? ' ' : '';\n let delimiter = '`';\n const matches: string[] = trimmed.match(/`+/gm) || [];\n while (matches.includes(delimiter)) delimiter = delimiter + '`';\n return delimiter + extraSpace + trimmed + extraSpace + delimiter;\n }\n};\n\ndefaultRules.image = {\n filter: 'img',\n replacement: function (_content: string, node: Node): string {\n const altAttr = (node as Element).getAttribute('alt');\n const alt = altAttr ? sanitizedLinkTitle(altAttr) : '';\n const src = (node as Element).getAttribute('src') || '';\n const titleAttr = (node as Element).getAttribute('title');\n const title = titleAttr ? sanitizedLinkTitle(titleAttr) : '';\n const titlePart = title ? ' \"' + title + '\"' : '';\n return src ? '![' + alt + ']' + '(' + src + titlePart + ')' : '';\n }\n};\n","/**\n * Manages a collection of rules used to convert HTML to Markdown\n */\nimport { ExtendedNode } from \"./node\";\nimport { TurnishOptions } from \"@/index\";\nimport { standardMarkdownElements } from \"./utilities\";\n\nexport type RuleFilterFunction = (node: ExtendedNode, options: TurnishOptions) => boolean;\nexport type RuleFilter = string | string[] | RuleFilterFunction;\n\ntype RuleReplacementFunction = (...args: any[]) => string;\n\nexport interface Rule {\n filter?: RuleFilter;\n replacement: RuleReplacementFunction | ((content: string, node: any, options: TurnishOptions, previousNode?: any) => string);\n references?: string[];\n /// Map of URL+title combinations to their reference IDs, used for link reference deduplication.\n /// When linkReferenceDeduplication is 'full', this tracks which URLs have already been assigned a reference number to avoid creating duplicate references.\n urlReferenceIdMap?: Map<string, number>;\n append?: (options: TurnishOptions) => string;\n}\n\nexport class Rules {\n options: TurnishOptions;\n private _keep: Rule[];\n private _remove: Rule[];\n blankRule: Rule;\n keepReplacement: RuleReplacementFunction;\n markdownIncludingHtmlReplacement: RuleReplacementFunction;\n defaultRule: Rule;\n array: Rule[];\n\n constructor(options: TurnishOptions) {\n this.options = options;\n this._keep = [];\n this._remove = [];\n\n this.blankRule = {\n replacement: options.blankReplacement\n };\n\n this.keepReplacement = options.keepReplacement;\n this.markdownIncludingHtmlReplacement = options.markdownIncludingHtmlReplacement;\n\n this.defaultRule = {\n replacement: options.defaultReplacement\n };\n\n this.array = [];\n for (const key in options.rules) {\n this.array.push(options.rules[key]);\n }\n }\n\n add(key: string, rule: Rule): void {\n this.array.unshift(rule);\n }\n\n keep(filter: RuleFilter): void {\n this._keep.unshift({\n filter: filter,\n replacement: this.keepReplacement\n });\n }\n\n remove(filter: RuleFilter): void {\n this._remove.unshift({\n filter: filter,\n replacement: function () {\n return '';\n }\n });\n }\n\n forNode(node: ExtendedNode): Rule {\n if (node.isBlank) {\n return this.blankRule;\n }\n if (this.options.htmlRetentionMode === 'preserveAll' && this.isUnsupportedElement(node)) {\n return {\n replacement: this.keepReplacement\n };\n }\n if (this.options.htmlRetentionMode === 'markdownIncludingHtml' && this.isUnsupportedElement(node)) {\n return {\n replacement: this.markdownIncludingHtmlReplacement\n };\n }\n\n let rule: Rule | undefined;\n if ((rule = findRule(this.array, node, this.options))) {\n return rule;\n }\n if ((rule = findRule(this._keep, node, this.options))) {\n return rule;\n }\n if ((rule = findRule(this._remove, node, this.options))) {\n return rule;\n }\n return this.defaultRule;\n }\n\n /// Check if an element is unsupported for Markdown conversion.\n private isUnsupportedElement(node: ExtendedNode): boolean {\n const nodeName = node.nodeName;\n\n if (nodeName === 'PRE' && node.firstChild && (node.firstChild as Element).nodeName === 'CODE') {\n const codeElem = node.firstChild as Element;\n if (codeElem.attributes && codeElem.attributes.length > 0) {\n for (let i = 0; i < codeElem.attributes.length; i++) {\n const attrName = codeElem.attributes[i].name.toLowerCase();\n if (attrName !== 'class') {\n return true;\n }\n }\n }\n }\n\n if (node.attributes && node.attributes.length > 0) {\n switch (nodeName) {\n case 'IMG':\n for (let i = 0; i < node.attributes.length; i++) {\n const attrName = node.attributes[i].name.toLowerCase();\n if (attrName !== 'src' && attrName !== 'alt' && attrName !== 'title') {\n return true;\n }\n }\n return false;\n case 'A':\n for (let i = 0; i < node.attributes.length; i++) {\n const attrName = node.attributes[i].name.toLowerCase();\n if (attrName !== 'href' && attrName !== 'title') {\n return true;\n }\n }\n return false;\n case 'CODE':\n const parent = node.parentNode as Element;\n if (parent && parent.nodeName === 'PRE') {\n for (let i = 0; i < node.attributes.length; i++) {\n const attrName = node.attributes[i].name.toLowerCase();\n if (attrName !== 'class') {\n return true;\n }\n }\n return false;\n }\n default:\n return true;\n }\n }\n // Elements that are not standard HTML elements are unsupported\n if (standardMarkdownElements.indexOf(nodeName) === -1) {\n return true;\n }\n return false;\n }\n\n forEach(fn: (rule: Rule, index: number) => void): void {\n for (let i = 0; i < this.array.length; i++) {\n fn(this.array[i], i);\n }\n }\n}\n\nfunction findRule(rules: Rule[], node: ExtendedNode, options: TurnishOptions): Rule | undefined {\n for (let i = 0; i < rules.length; i++) {\n const rule = rules[i];\n if (filterValue(rule, node, options)) return rule;\n }\n return undefined;\n}\n\nfunction filterValue(rule: Rule, node: ExtendedNode, options: TurnishOptions): boolean {\n const filter = rule.filter;\n if (typeof filter === 'string') {\n if (filter === node.nodeName.toLowerCase()) {\n return true;\n }\n } else if (Array.isArray(filter)) {\n if (filter.indexOf(node.nodeName.toLowerCase()) > -1) {\n return true;\n }\n } else if (typeof filter === 'function') {\n if (filter(node, options)) {\n return true;\n }\n } else {\n throw new TypeError('`filter` needs to be a string, array, or function');\n }\n return false;\n}\n","/**\n * The collapseWhitespace function is adapted from collapse-whitespace\n * by Luc Thevenard.\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2014 Luc Thevenard <lucthevenard@gmail.com>\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\nimport { NodeTypes } from \"./node\";\n\n/**\n * collapseWhitespace(options) removes extraneous whitespace from an the given element.\n *\n * @param {Object} options\n */\ninterface CollapseWhitespaceOptions {\n element: Node;\n isBlock: (node: Node) => boolean;\n isVoid: (node: Node) => boolean;\n isPre?: (node: Node) => boolean;\n}\n\nfunction collapseWhitespace(options: CollapseWhitespaceOptions): void {\n const element = options.element\n const isBlock = options.isBlock\n const isVoid = options.isVoid\n const isPre = options.isPre || function (node: Node): boolean {\n return node.nodeName === 'PRE';\n };\n\n if (!element.firstChild || isPre(element)) return\n\n let prevText: Text | null = null;\n let keepLeadingWs = false\n\n let prev: Node | null = null;\n let node: Node = next(prev, element, isPre);\n\n while (node !== element) {\n if (node.nodeType === NodeTypes.Text || node.nodeType === NodeTypes.CDATASection) {\n const textNode = node as Text;\n let text = textNode.data.replace(/[ \\r\\n\\t]+/g, ' ');\n\n if ((!prevText || / $/.test(prevText.data)) &&\n !keepLeadingWs && text[0] === ' ') {\n text = text.substr(1);\n }\n\n // `text` might be empty at this point.\n if (!text) {\n node = remove(node);\n continue;\n }\n\n textNode.data = text;\n\n prevText = textNode;\n } else if (node.nodeType === NodeTypes.Element) {\n if (isBlock(node) || node.nodeName === 'BR') {\n if (prevText) {\n prevText.data = prevText.data.replace(/ $/, '');\n }\n\n prevText = null;\n keepLeadingWs = false;\n } else if (isVoid(node) || isPre(node)) {\n // Avoid trimming space around non-block, non-BR void elements and inline PRE.\n prevText = null;\n keepLeadingWs = true;\n } else if (prevText) {\n // Drop protection if set previously.\n keepLeadingWs = false;\n }\n } else {\n node = remove(node);\n continue;\n }\n\n const nextNode = next(prev, node, isPre);\n prev = node;\n node = nextNode;\n }\n\n if (prevText) {\n prevText.data = prevText.data.replace(/ $/, '');\n if (!prevText.data) {\n remove(prevText);\n }\n }\n}\n\n/**\n * remove(node) removes the given node from the DOM and returns the\n * next node in the sequence.\n *\n * @param {Node} node\n * @return {Node} node\n */\nfunction remove(node: Node): Node {\n const nextNode: Node | null = node.nextSibling ?? node.parentNode;\n if (node.parentNode) {\n node.parentNode.removeChild(node);\n }\n return nextNode as Node;\n}\n\n/**\n * next(prev, current, isPre) returns the next node in the sequence, given the\n * current and previous nodes.\n *\n * @param {Node} prev\n * @param {Node} current\n * @param {Function} isPre\n * @return {Node}\n */\nfunction next(prev: Node | null, current: Node, isPre: (node: Node) => boolean): Node {\n if ((prev && prev.parentNode === current) || isPre(current)) {\n const nextNode: Node | null = current.nextSibling ?? current.parentNode;\n return nextNode as Node;\n }\n const nextNode: Node | null = current.firstChild ?? current.nextSibling ?? current.parentNode;\n return nextNode as Node;\n}\n\nexport default collapseWhitespace\n","/*\n * Set up window for Node.js\n */\n\nconst root: typeof globalThis = typeof window !== 'undefined' ? window : (typeof globalThis !== 'undefined' ? globalThis : {} as any)\n\n/*\n * Parsing HTML strings\n */\n\nfunction canParseHTMLNatively() {\n const Parser = typeof root.DOMParser !== 'undefined' ? root.DOMParser : undefined;\n let canParse = false;\n if (!Parser) return false;\n // Adapted from https://gist.github.com/1129031\n // Firefox/Opera/IE throw errors on unsupported types\n try {\n // WebKit returns null on unsupported types\n if (new Parser().parseFromString('', 'text/html')) {\n canParse = true;\n }\n } catch (e) { }\n return canParse;\n}\n\nexport class HTMLParser {\n // This will be assigned per environment below\n parseFromString(_input: string, _type?: string): Document {\n throw new Error('Not implemented')\n }\n}\n\nfunction createParser(): HTMLParser {\n const isBrowser =\n typeof window !== 'undefined' &&\n typeof document !== 'undefined' &&\n (typeof process === 'undefined' || (process as any).browser === true)\n\n if (typeof window !== 'undefined') {\n // Browser environment: use DOM API\n class HTMLParserBrowser extends HTMLParser {\n parseFromString(input: string, _type?: string): Document {\n const doc = document.implementation.createHTMLDocument('')\n doc.open()\n doc.write(input)\n doc.close()\n return doc\n }\n }\n return new HTMLParserBrowser()\n } else {\n const domino = require('@mixmark-io/domino') as {\n createDocument: (html: string) => Document\n }\n class HTMLParserNode extends HTMLParser {\n parseFromString(input: string, _type?: string): Document {\n return domino.createDocument(input);\n }\n }\n return new HTMLParserNode()\n }\n}\n\nexport const createHTMLParser = (): HTMLParser =>\n canParseHTMLNatively()\n ? new root.DOMParser()\n : createParser()\n","import collapseWhitespace from '@/collapse-whitespace'\nimport { createHTMLParser, HTMLParser } from '@/html-parser'\nimport { isBlock, isVoid } from '@/utilities'\n\ninterface RootNodeOptions {\n preformattedCode?: boolean\n}\n\nexport default function RootNode(\n input: string | Node,\n { preformattedCode }: RootNodeOptions\n): Element {\n let root: Element\n if (typeof input === 'string') {\n const doc = htmlParser().parseFromString(\n // DOM parsers arrange elements in the <head> and <body>.\n // Wrapping in a custom element ensures elements are reliably arranged in\n // a single element.\n '<x-turnish id=\"turnish-root\">' + input + '</x-turnish>',\n 'text/html'\n )\n root = doc.getElementById('turnish-root') as Element\n } else {\n root = input.cloneNode(true) as Element\n }\n collapseWhitespace({\n element: root,\n isBlock: isBlock,\n isVoid: isVoid,\n isPre: preformattedCode ? isPreOrCode : undefined\n })\n\n return root\n}\n\nlet _htmlParser: HTMLParser | undefined\nfunction htmlParser(): HTMLParser {\n return (_htmlParser ??= createHTMLParser())\n}\n\nfunction isPreOrCode(node: Node): boolean {\n return node.nodeName === 'PRE' || node.nodeName === 'CODE';\n}\n","import { defaultRules } from '@/default-rules'\nimport { Rules, Rule, RuleFilter } from '@/rules'\nimport { trimLeadingNewlines, trimTrailingNewlines } from '@/utilities'\nimport RootNode from '@/root-node'\nimport { ExtendedNode, NodeTypes } from '@/node';\nconst reduce = Array.prototype.reduce\n\ntype EscapeRule = [RegExp, string];\n\nconst escapes: EscapeRule[] = [\n [/\\\\/g, '\\\\\\\\'],\n [/\\*/g, '\\\\*'],\n [/_/g, '\\\\_'],\n [/^-/g, '\\\\-'],\n [/^\\+ /g, '\\\\+ '],\n [/^(=+)/g, '\\\\$1'],\n [/^(#{1,6}) /g, '\\\\$1 '],\n [/`/g, '\\\\`'],\n [/^~~~/g, '\\\\~~~'],\n [/\\[/g, '\\\\['],\n [/\\]/g, '\\\\]'],\n [/<([^>]*)>/g, '\\\\<$1\\\\>'],\n [/^>/g, '\\\\>'],\n [/^(\\d+)\\. /g, '$1\\\\. ']\n];\n\ntype Plugin = (service: Turnish) => void;\n\nexport interface TurnishOptions {\n rules: { [key: string]: Rule };\n headingStyle: 'setext' | 'atx';\n hr: string;\n bulletListMarker: '*' | '-' | '+';\n listMarkerSpaceCount: 1 | 2 | 3 | 4;\n listItemIndent: 'tab' | 'space';\n listItemIndentSpaceCount: 1 | 2 | 3 | 4;\n codeBlockStyle: 'indented' | 'fenced';\n fence: string;\n emDelimiter: '_' | '*';\n strongDelimiter: '**' | '__';\n linkStyle: 'inlined' | 'referenced';\n linkReferenceStyle: 'full' | 'collapsed' | 'shortcut';\n linkReferenceDeduplication: 'none' | 'full';\n br: string;\n preformattedCode: boolean;\n htmlRetentionMode: 'standard' | 'preserveAll' | 'markdownIncludingHtml';\n blankReplacement: (content: string, node: ExtendedNode) => string;\n keepReplacement: (content: string, node: ExtendedNode) => string;\n markdownIncludingHtmlReplacement: (content: string, node: ExtendedNode) => string;\n defaultReplacement: (content: string, node: ExtendedNode) => string;\n [key: string]: any;\n}\n\n\nconst defaultOptions: TurnishOptions = {\n rules: defaultRules,\n headingStyle: 'atx',\n hr: '---',\n bulletListMarker: '-',\n listMarkerSpaceCount: 1,\n listItemIndent: 'space',\n listItemIndentSpaceCount: 4,\n codeBlockStyle: 'fenced',\n fence: '```',\n emDelimiter: '*',\n strongDelimiter: '**',\n linkStyle: 'inlined',\n linkReferenceStyle: 'full',\n linkReferenceDeduplication: 'full',\n br: ' ',\n preformattedCode: false,\n htmlRetentionMode: 'standard',\n blankReplacement: (content: string, node: ExtendedNode): string => {\n return node.isBlock ? '\\n\\n' : '';\n },\n keepReplacement: (content: string, node: ExtendedNode): string => {\n return node.isBlock ? '\\n\\n' + node.outerHTML + '\\n\\n' : node.outerHTML;\n },\n markdownIncludingHtmlReplacement: (content: string, node: ExtendedNode): string => {\n const tagName = node.nodeName.toLowerCase();\n\n let attributes = '';\n if (node.attributes && node.attributes.length > 0) {\n const attrs: string[] = [];\n for (let i = 0; i < node.attributes.length; i++) {\n const attr = node.attributes[i];\n attrs.push(`${attr.name}=\"${attr.value}\"`);\n }\n attributes = ' ' + attrs.join(' ');\n }\n\n attributes += ' markdown=\"1\"';\n\n const openTag = `<${tagName}${attributes}>`;\n const closeTag = `</${tagName}>`;\n\n const trimmedContent = content.trim();\n const html = openTag + '\\n' + trimmedContent + '\\n' + closeTag;\n\n return node.isBlock ? '\\n\\n' + html + '\\n\\n' : html;\n },\n defaultReplacement: function (content: string, node: ExtendedNode): string {\n return node.isBlock ? '\\n\\n' + content + '\\n\\n' : content;\n }\n};\n\nexport default class Turnish {\n options: TurnishOptions;\n rules: Rules;\n\n constructor(options?: Partial<TurnishOptions>) {\n this.options = Object.assign({}, defaultOptions, options);\n this.rules = new Rules(this.options);\n }\n\n /**\n * The entry point for converting a string or DOM node to Markdown\n * @public\n * @param {InputType} input The string or DOM node to convert\n * @returns A Markdown representation of the input\n * @type string\n */\n render(input: InputType): string {\n if (!canConvert(input)) {\n throw new TypeError(\n input + ' is not a string, or an element/document/fragment node.'\n );\n }\n if (input === '') {\n return '';\n }\n const output = this.process(RootNode(input, this.options));\n return this.postProcess(output);\n }\n\n /**\n * Add one or more plugins\n * @public\n * @param {Plugin|Plugin[]} plugin The plugin or array of plugins to add\n * @returns The Turnish instance for chaining\n * @type Object\n */\n use(plugin: Plugin | Plugin[]): Turnish {\n if (Array.isArray(plugin)) {\n for (let i = 0; i < plugin.length; i++) this.use(plugin[i]);\n } else if (typeof plugin === 'function') {\n plugin(this);\n } else {\n throw new TypeError('plugin must be a Function or an Array of Functions');\n }\n return this;\n }\n\n /**\n * Adds a rule\n * @public\n * @param {string} key The unique key of the rule\n * @param {Object} rule The rule\n * @returns The Turnish instance for chaining\n * @type Object\n */\n addRule(key: string, rule: Rule): Turnish {\n this.rules.add(key, rule);\n return this;\n }\n\n /**\n * Keep a node (as HTML) that matches the filter\n * @public\n * @param {RuleFilter} filter The unique key of the rule\n * @returns The Turnish instance for chaining\n * @type Object\n */\n keep(filter: RuleFilter): Turnish {\n this.rules.keep(filter);\n return this;\n }\n\n /**\n * Remove a node that matches the filter\n * @public\n * @param {string|Array|Function} filter The unique key of the rule\n * @returns The Turnish instance for chaining\n * @type Object\n */\n remove(filter: RuleFilter): Turnish {\n this.rules.remove(filter);\n return this;\n }\n\n /**\n * Escapes Markdown syntax\n * @public\n * @param {string} string The string to escape\n * @returns A string with Markdown syntax escaped\n * @type string\n */\n escape(string: string): string {\n return escapes.reduce(function (accumulator: string, escape: EscapeRule) {\n return accumulator.replace(escape[0], escape[1]);\n }, string);\n }\n\n\n /**\n * Reduces a DOM node down to its Markdown string equivalent\n * @private\n * @param {HTMLElement} parentNode The node to convert\n * @returns A Markdown representation of the node\n * @type string\n */\n process(this: Turnish, parentNode: Node): string {\n return Array.from(parentNode.childNodes).reduce((output, node) => {\n const extended = ExtendedNode(node, this.options);\n let replacement = '';\n if (extended.nodeType === NodeTypes.Text) {\n const value = extended.nodeValue ?? ''; // ensure a string\n replacement = extended.isCode ? value : this.escape(value);\n } else if (extended.nodeType === NodeTypes.Element) {\n replacement = this.replacementForNode(extended);\n }\n return join(output, replacement);\n }, '');\n }\n\n /**\n * Appends strings as each rule requires and trims the output\n * @private\n * @param {string} output The conversion output\n * @returns A trimmed version of the ouput\n * @type string\n */\n postProcess(output: string): string {\n for (const rule of this.rules.array) {\n if (rule.append) {\n output = join(output, rule.append(this.options))\n }\n }\n return output\n .replace(/^[\\t\\r\\n]+/, '')\n .replace(/[\\t\\r\\n\\s]+$/, '')\n }\n\n\n /**\n * Converts an element node to its Markdown equivalent\n * @private\n * @param {ExtendedNode} node The node to convert\n * @returns A Markdown representation of the node\n * @type string\n */\n replacementForNode(node: ExtendedNode) {\n const rule = this.rules.forNode(node)\n let content = this.process(node)\n const whitespace = node.flankingWhitespace\n if (whitespace.leading || whitespace.trailing) {\n content = content.trim()\n }\n return (\n whitespace.leading +\n rule.replacement(content, node, this.options) +\n whitespace.trailing\n )\n }\n}\n\n/**\n * Joins replacement to the current output with appropriate number of new lines\n * @private\n * @param {string} output The current conversion output\n * @param {string} replacement The string to append to the output\n * @returns Joined output\n * @type string\n */\nfunction join(output: string, replacement: string): string {\n const s1 = trimTrailingNewlines(output)\n const s2 = trimLeadingNewlines(replacement)\n const nls = Math.max(output.length - s1.length, replacement.length - s2.length)\n const separator = '\\n\\n'.substring(0, nls)\n\n return s1 + separator + s2\n}\n\n/**\n * Determines whether an input can be converted\n * @private\n * @param {string|HTMLElement} input Describe this parameter\n * @returns Describe what it returns\n * @type string|Object|Array|Boolean|Number\n */\ntype InputType = string | HTMLElement | Document | DocumentFragment;\nfunction canConvert(input: any): input is InputType {\n return (\n input != null && (\n typeof input === 'string' ||\n (input.nodeType && (\n input.nodeType === 1 || input.nodeType === 9 || input.nodeType === 11\n ))\n )\n );\n}\n"],"names":["ExtendedNode","node","options","extended","isBlock","isBlank","flankingWhitespace","isVoid","isMeaningfulWhenBlank","hasVoid","hasMeaningfulWhenBlank","extendedNode","edges","edgeWhitespace","isFlankedByWhitespace","string","m","side","sibling","regExp","isFlanked","NodeTypes","repeat","character","count","trimLeadingNewlines","trimTrailingNewlines","indexEnd","trimNewlines","blockElements","is","voidElements","has","meaningfulWhenBlankElements","standardMarkdownElements","tagNames","tagName","sanitizeWhitespace","sanitizedLinkContent","content","sanitizedLinkTitle","defaultRules","_content","_node","hLevel","underline","parent","prefix","start","index","isParagraph","child","nestingLevel","currentNode","grandparent","oneIndent","indent","listMarkerRegex","codeElem","language","code","fenceChar","fenceSize","fenceInCodeRegex","match","fence","sanitizedContent","href","title","titleAttr","referenceLinkRule","self","referenceKey","replacement","reference","id","existingKey","references","hasSiblings","isCodeBlock","trimmed","extraSpace","delimiter","matches","altAttr","alt","src","titlePart","Rules","key","rule","filter","findRule","nodeName","attrName","fn","i","rules","filterValue","collapseWhitespace","element","isPre","prevText","keepLeadingWs","prev","next","textNode","text","remove","nextNode","current","root","canParseHTMLNatively","Parser","canParse","HTMLParser","_input","_type","createParser","HTMLParserBrowser","input","doc","domino","HTMLParserNode","createHTMLParser","RootNode","preformattedCode","htmlParser","isPreOrCode","_htmlParser","escapes","defaultOptions","attributes","attrs","attr","openTag","closeTag","trimmedContent","html","Turnish","canConvert","output","plugin","accumulator","escape","parentNode","value","join","whitespace","s1","s2","nls","separator"],"mappings":"qCAyBO,SAASA,EAAaC,EAAYC,EAAgC,CACvE,MAAMC,EAAWF,EACjB,OAAAE,EAAS,QAAUC,EAAQD,CAAQ,EACnCA,EAAS,OAASA,EAAS,WAAa,QAAWA,EAAS,YAA6B,OACzFA,EAAS,QAAUE,EAAQF,CAAQ,EACnCA,EAAS,mBAAqBG,EAAmBH,EAAUD,CAAO,EAC3DC,CACT,CAEA,SAASE,EAAQJ,EAA6B,CAC5C,MACE,CAACM,EAAON,CAAI,GACZ,CAACO,EAAsBP,CAAI,GAC3B,SAAS,KAAKA,EAAK,aAAe,EAAE,GACpC,CAACQ,EAAQR,CAAI,GACb,CAACS,EAAuBT,CAAI,CAEhC,CAEA,SAASK,EAAmBL,EAAoBC,EAAsC,CACpF,MAAMS,EAAeV,EAErB,GAAIU,EAAa,SAAYT,EAAQ,kBAAoBS,EAAa,OACpE,MAAO,CAAE,QAAS,GAAI,SAAU,EAAA,EAGlC,MAAMC,EAAQC,EAAeZ,EAAK,aAAe,EAAE,EAGnD,OAAIW,EAAM,cAAgBE,EAAsB,OAAQb,EAAMC,CAAO,IACnEU,EAAM,QAAUA,EAAM,iBAIpBA,EAAM,eAAiBE,EAAsB,QAASb,EAAMC,CAAO,IACrEU,EAAM,SAAWA,EAAM,kBAGlB,CAAE,QAASA,EAAM,QAAS,SAAUA,EAAM,QAAA,CACnD,CAEA,SAASC,EAAeE,EAAgC,CACtD,MAAMC,EAAID,EAAO,MAAM,+DAA+D,EAEtF,OAAKC,EAWE,CACL,QAASA,EAAE,CAAC,EACZ,aAAcA,EAAE,CAAC,EACjB,gBAAiBA,EAAE,CAAC,EACpB,SAAUA,EAAE,CAAC,EACb,iBAAkBA,EAAE,CAAC,EACrB,cAAeA,EAAE,CAAC,CAAA,EAhBX,CACL,QAAS,GACT,aAAc,GACd,gBAAiB,GACjB,SAAU,GACV,iBAAkB,GAClB,cAAe,EAAA,CAYrB,CAEA,SAASF,EAAsBG,EAAwBhB,EAAeC,EAA2B,CAC/F,IAAIgB,EACAC,EACAC,EAEJ,OAAIH,IAAS,QACXC,EAAUjB,EAAK,uBACfkB,EAAS,OAETD,EAAUjB,EAAK,mBACfkB,EAAS,MAGPD,IACEA,EAAQ,WAAa,EACvBE,EAAYD,EAAO,KAAKD,EAAQ,WAAa,EAAE,EACtChB,EAAQ,kBAAoBgB,EAAQ,WAAa,OAC1DE,EAAY,GACHF,EAAQ,WAAa,GAAK,CAACd,EAAQc,CAAO,IACnDE,EAAYD,EAAO,KAAKD,EAAQ,aAAe,EAAE,IAI9CE,GAAa,EACtB,CAEO,MAAMC,EAAY,CACvB,QAAS,EACT,KAAM,EACN,aAAc,CAEhB,ECvHO,SAASC,EAAOC,EAAmBC,EAAe,CACvD,OAAO,MAAMA,EAAQ,CAAC,EAAE,KAAKD,CAAS,CACxC,CAEO,SAASE,EAAoBV,EAAgB,CAClD,OAAOA,EAAO,QAAQ,OAAQ,EAAE,CAClC,CAEO,SAASW,EAAqBX,EAAgB,CAEnD,IAAIY,EAAWZ,EAAO,OACtB,KAAOY,EAAW,GAAKZ,EAAOY,EAAW,CAAC,IAAM;AAAA,GAAMA,IACtD,OAAOZ,EAAO,UAAU,EAAGY,CAAQ,CACrC,CAEO,SAASC,EAAab,EAAgB,CAC3C,OAAOW,EAAqBD,EAAoBV,CAAM,CAAC,CACzD,CAEO,MAAMc,EAAgB,CAC3B,UAAW,UAAW,QAAS,QAAS,aAAc,OAAQ,SAC9D,SAAU,KAAM,MAAO,MAAO,KAAM,KAAM,WAAY,aAAc,SACpE,SAAU,OAAQ,WAAY,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,SAClE,SAAU,KAAM,OAAQ,UAAW,KAAM,OAAQ,OAAQ,MAAO,WAChE,WAAY,KAAM,SAAU,IAAK,MAAO,UAAW,QAAS,QAAS,KACrE,QAAS,KAAM,QAAS,KAAM,IAChC,EAEO,SAASzB,EAAQH,EAAY,CAClC,OAAO6B,EAAG7B,EAAM4B,CAAa,CAC/B,CAEO,MAAME,EAAe,CAC1B,OAAQ,OAAQ,KAAM,MAAO,UAAW,QAAS,KAAM,MAAO,QAC9D,SAAU,OAAQ,OAAQ,QAAS,SAAU,QAAS,KACxD,EAEO,SAASxB,EAAON,EAAY,CACjC,OAAO6B,EAAG7B,EAAM8B,CAAY,CAC9B,CAEO,SAAStB,EAAQR,EAAY,CAClC,OAAO+B,EAAI/B,EAAM8B,CAAY,CAC/B,CAEA,MAAME,EAA8B,CAClC,IAAK,QAAS,QAAS,QAAS,QAAS,KAAM,KAAM,SAAU,SAC/D,QAAS,OACX,EAEaC,EAA2B,CACtC,IAAK,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,aAC/C,KAAM,KAAM,KAAM,MAAO,OAAQ,KAAM,IAAK,KAAM,IAAK,SACvD,IAAK,MAAO,MAAO,OAAQ,QAAS,QAAS,QAAS,KAAM,KAAM,IACpE,EAEO,SAAS1B,EAAsBP,EAAY,CAChD,OAAO6B,EAAG7B,EAAMgC,CAA2B,CAC7C,CAEO,SAASvB,EAAuBT,EAAY,CACjD,OAAO+B,EAAI/B,EAAMgC,CAA2B,CAC9C,CAEA,SAASH,EAAG7B,EAAYkC,EAAoB,CAC1C,OAAOA,EAAS,QAAQlC,EAAK,QAAQ,GAAK,CAC5C,CAEA,SAAS+B,EAAI/B,EAAYkC,EAAoB,CAC3C,OACEA,EAAS,KAAK,SAAUC,EAAS,CAC/B,OAAInC,EAAK,WAAaoB,EAAU,QACvB,GAEDpB,EAAiB,qBAAqBmC,CAAO,EAAE,MACzD,CAAC,CAEL,CAEO,SAASC,EAAmBtB,EAAwB,CACzD,OAAOA,EAASA,EAAO,QAAQ,aAAc;AAAA,CAAI,EAAI,EACvD,CAEO,SAASuB,EAAqBC,EAAyB,CAE5D,OADkBF,EAAmBE,CAAO,EAEzC,QAAQ,aAAc,GAAG,EACzB,QAAQ,SAAU,GAAG,EACrB,QAAQ,UAAW,MAAM,EACzB,KAAA,CACL,CAEO,SAASC,EAAmBD,EAAyB,CAE1D,OADkBF,EAAmBE,CAAO,EAEzC,QAAQ,aAAc,GAAG,CAC9B,CC5FO,MAAME,EAAwC,CAAA,EAErDA,EAAa,UAAY,CACvB,OAAQ,IACR,YAAa,SAAUF,EAAyB,CAC9C,MAAO;AAAA;AAAA,EAASA,EAAU;AAAA;AAAA,CAC5B,CACF,EAEAE,EAAa,UAAY,CACvB,OAAQ,KACR,YAAa,SAAUC,EAAkBC,EAAazC,EAAiC,CACrF,OAAOA,EAAQ,GAAK;AAAA,CACtB,CACF,EAEAuC,EAAa,QAAU,CACrB,OAAQ,CAAC,KAAM,KAAM,KAAM,KAAM,KAAM,IAAI,EAC3C,YAAa,SAAUF,EAAiBtC,EAAYC,EAAiC,CACnF,MAAM0C,EAAS,OAAO3C,EAAK,SAAS,OAAO,CAAC,CAAC,EAC7C,GAAIC,EAAQ,eAAiB,UAAY0C,EAAS,EAAG,CACnD,MAAMC,EAAYvB,EAAQsB,IAAW,EAAI,IAAM,IAAML,EAAQ,MAAM,EACnE,MACE;AAAA;AAAA,EAASA,EAAU;AAAA,EAAOM,EAAY;AAAA;AAAA,CAE1C,KACE,OAAO;AAAA;AAAA,EAASvB,EAAO,IAAKsB,CAAM,EAAI,IAAML,EAAU;AAAA;AAAA,CAE1D,CACF,EAEAE,EAAa,WAAa,CACxB,OAAQ,aACR,YAAa,SAAUF,EAAyB,CAC9C,OAAAA,EAAUX,EAAaW,CAAO,EAAE,QAAQ,MAAO,IAAI,EAC5C;AAAA;AAAA,EAASA,EAAU;AAAA;AAAA,CAC5B,CACF,EAEAE,EAAa,KAAO,CAClB,OAAQ,CAAC,KAAM,IAAI,EACnB,YAAa,SAAUF,EAAiBtC,EAAoB,CAC1D,MAAM6C,EAAS7C,EAAK,WACpB,OAAI6C,EAAO,WAAa,MAAQA,EAAO,mBAAqB7C,EACnD;AAAA,EAAOsC,EAEP;AAAA;AAAA,EAASA,EAAU;AAAA;AAAA,CAE9B,CACF,EAEAE,EAAa,SAAW,CACtB,OAAQ,KACR,YAAa,SAAUF,EAAiBtC,EAAYC,EAAiC,CACnF,IAAI6C,EAAS7C,EAAQ,iBAAmB,IAAI,OAAOA,EAAQ,oBAAoB,EAC/E,MAAM4C,EAAS7C,EAAK,WACpB,GAAI6C,EAAO,WAAa,KAAM,CAC5B,MAAME,EAAQF,EAAO,aAAa,OAAO,EACnCG,EAAQ,MAAM,UAAU,QAAQ,KAAKH,EAAO,SAAU7C,CAAI,EAChE8C,GAAUC,EAAQ,OAAOA,CAAK,EAAIC,EAAQA,EAAQ,GAAK,IAAM,IAAI,OAAO/C,EAAQ,oBAAoB,CACtG,CACA,MAAMgD,EAAc,MAAM,KAAKX,CAAO,EAQtC,GAPAA,EAAUX,EAAaW,CAAO,GAAKW,EAAc;AAAA,EAAO,IAE9BjD,EAAK,WAAW,OAAS,GACjD,MAAM,KAAKA,EAAK,UAAU,EAAE,MAAOkD,GACzBA,EAAM,WAAa9B,EAAU,MAAQ,QAAQ,KAAK8B,EAAM,WAAa,EAAE,GACzEA,EAAM,WAAa9B,EAAU,SAAW,CAAC,KAAM,IAAI,EAAE,SAAS8B,EAAM,QAAQ,CACnF,GACsBZ,EAAQ,KAAA,IAAW,GAE1C,OAAOA,GAAWtC,EAAK,YAAc;AAAA,EAAO,IAG9C,IAAImD,EAAe,EACfC,EAA2BP,EAC/B,KAAOO,GAAa,CAClB,GAAIA,EAAY,WAAa,MAAQA,EAAY,WAAa,KAAM,CAClE,MAAMC,EAAcD,EAAY,WAC5BC,GAAeA,EAAY,WAAa,MAC1CF,GAEJ,CACAC,EAAcA,EAAY,UAC5B,CAEA,IAAIE,EAAYrD,EAAQ,iBAAmB,MAAQ,IAAO,IAAI,OAAOA,EAAQ,wBAAwB,EACjGsD,EAASD,EAAU,OAAOH,CAAY,EAC1C,MAAMK,EAAkB,iCACxB,OAAAlB,EAAUA,EAAQ,QAAQkB,EAAiB;AAAA,EAAOF,CAAS,EACpDC,EAAST,EAASR,GAAWtC,EAAK,YAAc;AAAA,EAAO,GAChE,CACF,EAEAwC,EAAa,kBAAoB,CAC/B,OAAQ,SAAUxC,EAAYC,EAAkC,CAC9D,MAAO,CAAC,EACNA,GACAA,EAAQ,iBAAmB,YAC3BD,EAAK,WAAa,OAClBA,EAAK,YACJA,EAAK,WAAuB,WAAa,OAE9C,EACA,YAAa,SAAUyC,EAAkBzC,EAAoB,CAC3D,MAAI,CAACA,GAAQ,CAACA,EAAK,WAAmB,GAEpC;AAAA;AAAA,MACCA,EAAK,WAAuB,YAAa,QAAQ,MAAO;AAAA,KAAQ,EACjE;AAAA;AAAA,CAEJ,CACF,EAEAwC,EAAa,gBAAkB,CAC7B,OAAQ,SAAUxC,EAAYC,EAAkC,CAC9D,MAAO,CAAC,EACNA,GACAA,EAAQ,iBAAmB,UAC3BD,EAAK,WAAa,OAClBA,EAAK,YACJA,EAAK,WAAuB,WAAa,OAE9C,EACA,YAAa,SAAUyC,EAAkBzC,EAAYC,EAAiC,CACpF,GAAI,CAACD,EAAK,WACR,MAAO,GAET,MAAMyD,EAAWzD,EAAK,WAEhB0D,IADYD,EAAS,aAAa,OAAO,GAAK,IACxB,MAAM,gBAAgB,GAAK,CAAC,KAAM,EAAE,GAAG,CAAC,EAC9DE,EAAOF,EAAS,aAAe,GAC/BG,EAAY3D,EAAQ,OAAO,OAAO,CAAC,GAAK,IAC9C,IAAI4D,EAAY,EAChB,MAAMC,EAAmB,IAAI,OAAO,IAAMF,EAAY,OAAQ,IAAI,EAClE,IAAIG,EACJ,KAAQA,EAAQD,EAAiB,KAAKH,CAAI,GACpCI,EAAM,CAAC,EAAE,QAAUF,IACrBA,EAAYE,EAAM,CAAC,EAAE,OAAS,GAGlC,MAAMC,EAAQ3C,EAAOuC,EAAWC,CAAS,EACzC,MACE;AAAA;AAAA,EAASG,EAAQN,EAAW;AAAA,EAC5BC,EAAK,QAAQ,MAAO,EAAE,EACtB;AAAA,EAAOK,EAAQ;AAAA;AAAA,CAEnB,CACF,EAEAxB,EAAa,eAAiB,CAC5B,OAAQ,KACR,YAAa,SAAUC,EAAkBC,EAAazC,EAAiC,CACrF,MAAO;AAAA;AAAA,EAASA,EAAQ,GAAK;AAAA;AAAA,CAC/B,CACF,EAEAuC,EAAa,WAAa,CACxB,OAAQ,SAAUxC,EAAYC,EAAkC,CAC9D,MAAO,CAAC,EACNA,GAAS,YAAc,WACvBD,EAAK,WAAa,KACjBA,EAAiB,aAAa,MAAM,EAEzC,EACA,YAAa,SAAUsC,EAAiBtC,EAAoB,CAC1D,MAAMiE,EAAmB5B,EAAqBC,CAAO,EACrD,IAAI4B,EAAQlE,EACT,aAAa,MAAM,GAClB,QAAQ,UAAW,MAAM,EACzBmE,EACJ,MAAMC,EAAapE,EAAiB,aAAa,OAAO,EACxD,OAAIoE,EAEFD,EAAQ,KADe5B,EAAmB6B,CAAS,EACrB,QAAQ,KAAM,KAAK,EAAI,IAErDD,EAAQ,GAEH,IAAMF,EAAmB,KAAOC,EAAOC,EAAQ,GACxD,CACF,EAEA,MAAME,EAA2E,CAC/E,OAAQ,SAAUrE,EAAYC,EAAkC,CAC9D,MAAO,CAAC,EACNA,GACAA,EAAQ,YAAc,cACtBD,EAAK,WAAa,KACjBA,EAAiB,aAAa,MAAM,EAEzC,EACA,YAAa,SAAUsC,EAAiBtC,EAAYC,EAAiC,CACnF,MAAMqE,EAAOD,EAEPH,EAAQlE,EAAiB,aAAa,MAAM,EAClD,IAAImE,EACJ,MAAMC,EAAapE,EAAiB,aAAa,OAAO,EACpDoE,EAEFD,EAAQ,KADe5B,EAAmB6B,CAAS,EACnB,IAEhCD,EAAQ,GAEV,MAAMI,EAAeL,EAAOC,EAE5B,IAAIK,EACAC,EACJ,OAAQxE,EAAQ,mBAAA,CACd,IAAK,YACHuE,EAAc,IAAMlC,EAAU,MAC9BmC,EAAY,IAAMnC,EAAU,MAAQiC,EACpC,MACF,IAAK,WACHC,EAAc,IAAMlC,EAAU,IAC9BmC,EAAY,IAAMnC,EAAU,MAAQiC,EACpC,MACF,QAAS,CACP,IAAIG,EACJ,MAAMC,EAAcL,EAAK,kBAAkB,IAAIC,CAAY,EACvDtE,EAAQ,6BAA+B,QAAU0E,GACnDD,EAAKC,EACLF,EAAY,IAAMC,EAAK,MAAQR,EAAOC,IAEtCO,EAAKJ,EAAK,WAAW,OAAS,EAC9BA,EAAK,kBAAkB,IAAIC,EAAcG,CAAE,EAC3CD,EAAY,IAAMC,EAAK,MAAQR,EAAOC,EACtCG,EAAK,WAAW,KAAKG,CAAS,GAEhCD,EAAc,IAAMlC,EAAU,KAAOoC,EAAK,IAC1C,KACF,CAAA,CAGF,OAAIzE,EAAQ,qBAAuB,SAE7BA,EAAQ,6BAA+B,OACpCqE,EAAK,kBAAkB,IAAIC,CAAY,IAC1CD,EAAK,kBAAkB,IAAIC,EAAc,CAAC,EAC1CD,EAAK,WAAW,KAAKG,CAAS,GAGhCH,EAAK,WAAW,KAAKG,CAAS,GAG3BD,CACT,EACA,WAAY,CAAA,EACZ,sBAAuB,IACvB,OAAQ,IAAc,CACpB,MAAMF,EAAOD,EACb,IAAIO,EAAa,GACjB,OAAIN,EAAK,YAAcA,EAAK,WAAW,SACrCM,EAAa;AAAA;AAAA,EAASN,EAAK,WAAW,KAAK;AAAA,CAAI,EAAI;AAAA;AAAA,EACnDA,EAAK,WAAa,CAAA,EAClBA,EAAK,sBAAwB,KAExBM,CACT,CACF,EAEApC,EAAa,cAAgB6B,EAE7B7B,EAAa,SAAW,CACtB,OAAQ,CAAC,KAAM,GAAG,EAClB,YAAa,CAACF,EAAiBI,EAAazC,KAC1CqC,EAAUA,EAAQ,KAAA,EACbA,EACErC,EAAQ,YAAcqC,EAAUrC,EAAQ,YADxB,GAG3B,EAEAuC,EAAa,OAAS,CACpB,OAAQ,CAAC,SAAU,GAAG,EACtB,YAAa,CAACF,EAAiBI,EAAazC,KAC1CqC,EAAUA,EAAQ,KAAA,EACbA,EACErC,EAAQ,gBAAkBqC,EAAUrC,EAAQ,gBAD5B,GAG3B,EAEAuC,EAAa,KAAO,CAClB,OAASxC,GAAwB,CAC/B,MAAM6E,EAAc7E,EAAK,iBAAmBA,EAAK,YAE3C8E,EADS9E,EAAK,WACO,WAAa,OAAS,CAAC6E,EAClD,OAAO7E,EAAK,WAAa,QAAU,CAAC8E,CACtC,EACA,YAAcxC,GAA4B,CACxC,MAAMyC,EAAUzC,EAAQ,QAAQ,YAAa,GAAG,EAC1C0C,EAAa,sBAAsB,KAAKD,CAAO,EAAI,IAAM,GAC/D,IAAIE,EAAY,IAChB,MAAMC,EAAoBH,EAAQ,MAAM,MAAM,GAAK,CAAA,EACnD,KAAOG,EAAQ,SAASD,CAAS,KAAeA,EAAY,IAC5D,OAAOA,EAAYD,EAAaD,EAAUC,EAAaC,CACzD,CACF,EAEAzC,EAAa,MAAQ,CACnB,OAAQ,MACR,YAAa,SAAUC,EAAkBzC,EAAoB,CAC3D,MAAMmF,EAAWnF,EAAiB,aAAa,KAAK,EAC9CoF,EAAMD,EAAU5C,EAAmB4C,CAAO,EAAI,GAC9CE,EAAOrF,EAAiB,aAAa,KAAK,GAAK,GAC/CoE,EAAapE,EAAiB,aAAa,OAAO,EAClDmE,EAAQC,EAAY7B,EAAmB6B,CAAS,EAAI,GACpDkB,EAAYnB,EAAQ,KAAOA,EAAQ,IAAM,GAC/C,OAAOkB,EAAM,KAAOD,EAAM,KAAYC,EAAMC,EAAY,IAAM,EAChE,CACF,ECpSO,MAAMC,CAAM,CACjB,QACQ,MACA,QACR,UACA,gBACA,iCACA,YACA,MAEA,YAAYtF,EAAyB,CACnC,KAAK,QAAUA,EACf,KAAK,MAAQ,CAAA,EACb,KAAK,QAAU,CAAA,EAEf,KAAK,UAAY,CACf,YAAaA,EAAQ,gBAAA,EAGvB,KAAK,gBAAkBA,EAAQ,gBAC/B,KAAK,iCAAmCA,EAAQ,iCAEhD,KAAK,YAAc,CACjB,YAAaA,EAAQ,kBAAA,EAGvB,KAAK,MAAQ,CAAA,EACb,UAAWuF,KAAOvF,EAAQ,MACxB,KAAK,MAAM,KAAKA,EAAQ,MAAMuF,CAAG,CAAC,CAEtC,CAEA,IAAIA,EAAaC,EAAkB,CACjC,KAAK,MAAM,QAAQA,CAAI,CACzB,CAEA,KAAKC,EAA0B,CAC7B,KAAK,MAAM,QAAQ,CACjB,OAAAA,EACA,YAAa,KAAK,eAAA,CACnB,CACH,CAEA,OAAOA,EAA0B,CAC/B,KAAK,QAAQ,QAAQ,CACnB,OAAAA,EACA,YAAa,UAAY,CACvB,MAAO,EACT,CAAA,CACD,CACH,CAEA,QAAQ1F,EAA0B,CAChC,GAAIA,EAAK,QACP,OAAO,KAAK,UAEd,GAAI,KAAK,QAAQ,oBAAsB,eAAiB,KAAK,qBAAqBA,CAAI,EACpF,MAAO,CACL,YAAa,KAAK,eAAA,EAGtB,GAAI,KAAK,QAAQ,oBAAsB,yBAA2B,KAAK,qBAAqBA,CAAI,EAC9F,MAAO,CACL,YAAa,KAAK,gCAAA,EAItB,IAAIyF,EAOJ,OANKA,EAAOE,EAAS,KAAK,MAAO3F,EAAM,KAAK,OAAO,KAG9CyF,EAAOE,EAAS,KAAK,MAAO3F,EAAM,KAAK,OAAO,KAG9CyF,EAAOE,EAAS,KAAK,QAAS3F,EAAM,KAAK,OAAO,GAC5CyF,EAEF,KAAK,WACd,CAGQ,qBAAqBzF,EAA6B,CACxD,MAAM4F,EAAW5F,EAAK,SAEtB,GAAI4F,IAAa,OAAS5F,EAAK,YAAeA,EAAK,WAAuB,WAAa,OAAQ,CAC7F,MAAMyD,EAAWzD,EAAK,WACtB,GAAIyD,EAAS,YAAcA,EAAS,WAAW,OAAS,GACtD,QAAS,EAAI,EAAG,EAAIA,EAAS,WAAW,OAAQ,IAE9C,GADiBA,EAAS,WAAW,CAAC,EAAE,KAAK,YAAA,IAC5B,QACf,MAAO,GAIf,CAEA,GAAIzD,EAAK,YAAcA,EAAK,WAAW,OAAS,EAC9C,OAAQ4F,EAAA,CACN,IAAK,MACH,QAAS,EAAI,EAAG,EAAI5F,EAAK,WAAW,OAAQ,IAAK,CAC/C,MAAM6F,EAAW7F,EAAK,WAAW,CAAC,EAAE,KAAK,YAAA,EACzC,GAAI6F,IAAa,OAASA,IAAa,OAASA,IAAa,QAC3D,MAAO,EAEX,CACA,MAAO,GACT,IAAK,IACH,QAAS,EAAI,EAAG,EAAI7F,EAAK,WAAW,OAAQ,IAAK,CAC/C,MAAM6F,EAAW7F,EAAK,WAAW,CAAC,EAAE,KAAK,YAAA,EACzC,GAAI6F,IAAa,QAAUA,IAAa,QACtC,MAAO,EAEX,CACA,MAAO,GACT,IAAK,OACH,MAAMhD,EAAS7C,EAAK,WACpB,GAAI6C,GAAUA,EAAO,WAAa,MAAO,CACvC,QAAS,EAAI,EAAG,EAAI7C,EAAK,WAAW,OAAQ,IAE1C,GADiBA,EAAK,WAAW,CAAC,EAAE,KAAK,YAAA,IACxB,QACf,MAAO,GAGX,MAAO,EACT,CACF,QACE,MAAO,EAAA,CAIb,OAAIiC,EAAyB,QAAQ2D,CAAQ,IAAM,EAIrD,CAEA,QAAQE,EAA+C,CACrD,QAASC,EAAI,EAAGA,EAAI,KAAK,MAAM,OAAQA,IACrCD,EAAG,KAAK,MAAMC,CAAC,EAAGA,CAAC,CAEvB,CACF,CAEA,SAASJ,EAASK,EAAehG,EAAoBC,EAA2C,CAC9F,QAAS8F,EAAI,EAAGA,EAAIC,EAAM,OAAQD,IAAK,CACrC,MAAMN,EAAOO,EAAMD,CAAC,EACpB,GAAIE,EAAYR,EAAMzF,EAAMC,CAAO,EAAG,OAAOwF,CAC/C,CAEF,CAEA,SAASQ,EAAYR,EAAYzF,EAAoBC,EAAkC,CACrF,MAAMyF,EAASD,EAAK,OACpB,GAAI,OAAOC,GAAW,UACpB,GAAIA,IAAW1F,EAAK,SAAS,YAAA,EAC3B,MAAO,WAEA,MAAM,QAAQ0F,CAAM,GAC7B,GAAIA,EAAO,QAAQ1F,EAAK,SAAS,YAAA,CAAa,EAAI,GAChD,MAAO,WAEA,OAAO0F,GAAW,YAC3B,GAAIA,EAAO1F,EAAMC,CAAO,EACtB,MAAO,OAGT,OAAM,IAAI,UAAU,mDAAmD,EAEzE,MAAO,EACT,CCtJA,SAASiG,EAAmBjG,EAA0C,CACpE,MAAMkG,EAAUlG,EAAQ,QAClBE,EAAUF,EAAQ,QAClBK,EAASL,EAAQ,OACjBmG,EAAQnG,EAAQ,OAAS,SAAUD,EAAqB,CAC5D,OAAOA,EAAK,WAAa,KAC3B,EAEA,GAAI,CAACmG,EAAQ,YAAcC,EAAMD,CAAO,EAAG,OAE3C,IAAIE,EAAwB,KACxBC,EAAgB,GAEhBC,EAAoB,KACpBvG,EAAawG,EAAKD,EAAMJ,EAASC,CAAK,EAE1C,KAAOpG,IAASmG,GAAS,CACvB,GAAInG,EAAK,WAAaoB,EAAU,MAAQpB,EAAK,WAAaoB,EAAU,aAAc,CAChF,MAAMqF,EAAWzG,EACjB,IAAI0G,EAAOD,EAAS,KAAK,QAAQ,cAAe,GAAG,EAQnD,IANK,CAACJ,GAAY,KAAK,KAAKA,EAAS,IAAI,IACvC,CAACC,GAAiBI,EAAK,CAAC,IAAM,MAC9BA,EAAOA,EAAK,OAAO,CAAC,GAIlB,CAACA,EAAM,CACT1G,EAAO2G,EAAO3G,CAAI,EAClB,QACF,CAEAyG,EAAS,KAAOC,EAEhBL,EAAWI,CACb,SAAWzG,EAAK,WAAaoB,EAAU,QACjCjB,EAAQH,CAAI,GAAKA,EAAK,WAAa,MACjCqG,IACFA,EAAS,KAAOA,EAAS,KAAK,QAAQ,KAAM,EAAE,GAGhDA,EAAW,KACXC,EAAgB,IACPhG,EAAON,CAAI,GAAKoG,EAAMpG,CAAI,GAEnCqG,EAAW,KACXC,EAAgB,IACPD,IAETC,EAAgB,QAEb,CACLtG,EAAO2G,EAAO3G,CAAI,EAClB,QACF,CAEA,MAAM4G,EAAWJ,EAAKD,EAAMvG,EAAMoG,CAAK,EACvCG,EAAOvG,EACPA,EAAO4G,CACT,CAEIP,IACFA,EAAS,KAAOA,EAAS,KAAK,QAAQ,KAAM,EAAE,EACzCA,EAAS,MACZM,EAAON,CAAQ,EAGrB,CASA,SAASM,EAAO3G,EAAkB,CAChC,MAAM4G,EAAwB5G,EAAK,aAAeA,EAAK,WACvD,OAAIA,EAAK,YACPA,EAAK,WAAW,YAAYA,CAAI,EAE3B4G,CACT,CAWA,SAASJ,EAAKD,EAAmBM,EAAeT,EAAsC,CACpF,OAAKG,GAAQA,EAAK,aAAeM,GAAYT,EAAMS,CAAO,EAC1BA,EAAQ,aAAeA,EAAQ,WAGjCA,EAAQ,YAAcA,EAAQ,aAAeA,EAAQ,UAErF,CCzIA,MAAMC,EAA0B,OAAO,OAAW,IAAc,OAAU,OAAO,WAAe,IAAc,WAAa,CAAA,EAM3H,SAASC,GAAuB,CAC9B,MAAMC,EAAS,OAAOF,EAAK,UAAc,IAAcA,EAAK,UAAY,OACxE,IAAIG,EAAW,GACf,GAAI,CAACD,EAAQ,MAAO,GAGpB,GAAI,CAEE,IAAIA,EAAA,EAAS,gBAAgB,GAAI,WAAW,IAC9CC,EAAW,GAEf,MAAY,CAAE,CACd,OAAOA,CACT,CAEO,MAAMC,CAAW,CAEtB,gBAAgBC,EAAgBC,EAA0B,CACxD,MAAM,IAAI,MAAM,iBAAiB,CACnC,CACF,CAEA,SAASC,GAA2B,CAMlC,GAJE,OAAO,OAAW,KAClB,OAAO,SAAa,MACnB,OAAO,QAAY,KAAgB,QAAgB,SAElD,OAAO,OAAW,IAAa,CAEjC,MAAMC,UAA0BJ,CAAW,CACzC,gBAAgBK,EAAeH,EAA0B,CACvD,MAAMI,EAAM,SAAS,eAAe,mBAAmB,EAAE,EACzD,OAAAA,EAAI,KAAA,EACJA,EAAI,MAAMD,CAAK,EACfC,EAAI,MAAA,EACGA,CACT,CAAA,CAEF,OAAO,IAAIF,CACb,KAAO,CACL,MAAMG,EAAS,QAAQ,oBAAoB,EAG3C,MAAMC,UAAuBR,CAAW,CACtC,gBAAgBK,EAAeH,EAA0B,CACvD,OAAOK,EAAO,eAAeF,CAAK,CACpC,CAAA,CAEF,OAAO,IAAIG,CACb,CACF,CAEO,MAAMC,EAAmB,IAC9BZ,EAAA,EACI,IAAID,EAAK,UACTO,EAAA,EC1DN,SAAwBO,EACtBL,EACA,CAAE,iBAAAM,GACO,CACT,IAAIf,EACJ,OAAI,OAAOS,GAAU,SAQnBT,EAPYgB,KAAa,gBAIvB,gCAAkCP,EAAQ,eAC1C,WAAA,EAES,eAAe,cAAc,EAExCT,EAAOS,EAAM,UAAU,EAAI,EAE7BrB,EAAmB,CACjB,QAASY,EACT,QAAA3G,EACA,OAAAG,EACA,MAAOuH,EAAmBE,GAAc,MAAA,CACzC,EAEMjB,CACT,CAEA,IAAIkB,EACJ,SAASF,IAAyB,CAChC,OAAQE,IAAgBL,EAAA,CAC1B,CAEA,SAASI,GAAY/H,EAAqB,CACxC,OAAOA,EAAK,WAAa,OAASA,EAAK,WAAa,MACtD,CCjCA,MAAMiI,GAAwB,CAC5B,CAAC,MAAO,MAAM,EACd,CAAC,MAAO,KAAK,EACb,CAAC,KAAM,KAAK,EACZ,CAAC,MAAO,KAAK,EACb,CAAC,QAAS,MAAM,EAChB,CAAC,SAAU,MAAM,EACjB,CAAC,cAAe,OAAO,EACvB,CAAC,KAAM,KAAK,EACZ,CAAC,QAAS,OAAO,EACjB,CAAC,MAAO,KAAK,EACb,CAAC,MAAO,KAAK,EACb,CAAC,aAAc,UAAU,EACzB,CAAC,MAAO,KAAK,EACb,CAAC,aAAc,QAAQ,CACzB,EA8BMC,GAAiC,CACrC,MAAO1F,EACP,aAAc,MACd,GAAI,MACJ,iBAAkB,IAClB,qBAAsB,EACtB,eAAgB,QAChB,yBAA0B,EAC1B,eAAgB,SAChB,MAAO,MACP,YAAa,IACb,gBAAiB,KACjB,UAAW,UACX,mBAAoB,OACpB,2BAA4B,OAC5B,GAAI,KACJ,iBAAkB,GAClB,kBAAmB,WACnB,iBAAkB,CAACF,EAAiBtC,IAC3BA,EAAK,QAAU;AAAA;AAAA,EAAS,GAEjC,gBAAiB,CAACsC,EAAiBtC,IAC1BA,EAAK,QAAU;AAAA;AAAA,EAASA,EAAK,UAAY;AAAA;AAAA,EAASA,EAAK,UAEhE,iCAAkC,CAACsC,EAAiBtC,IAA+B,CACjF,MAAMmC,EAAUnC,EAAK,SAAS,YAAA,EAE9B,IAAImI,EAAa,GACjB,GAAInI,EAAK,YAAcA,EAAK,WAAW,OAAS,EAAG,CACjD,MAAMoI,EAAkB,CAAA,EACxB,QAASrC,EAAI,EAAGA,EAAI/F,EAAK,WAAW,OAAQ+F,IAAK,CAC/C,MAAMsC,EAAOrI,EAAK,WAAW+F,CAAC,EAC9BqC,EAAM,KAAK,GAAGC,EAAK,IAAI,KAAKA,EAAK,KAAK,GAAG,CAC3C,CACAF,EAAa,IAAMC,EAAM,KAAK,GAAG,CACnC,CAEAD,GAAc,gBAEd,MAAMG,EAAU,IAAInG,CAAO,GAAGgG,CAAU,IAClCI,EAAW,KAAKpG,CAAO,IAEvBqG,EAAiBlG,EAAQ,KAAA,EACzBmG,EAAOH,EAAU;AAAA,EAAOE,EAAiB;AAAA,EAAOD,EAEtD,OAAOvI,EAAK,QAAU;AAAA;AAAA,EAASyI,EAAO;AAAA;AAAA,EAASA,CACjD,EACA,mBAAoB,SAAUnG,EAAiBtC,EAA4B,CACzE,OAAOA,EAAK,QAAU;AAAA;AAAA,EAASsC,EAAU;AAAA;AAAA,EAASA,CACpD,CACF,EAEA,MAAqBoG,EAAQ,CAC3B,QACA,MAEA,YAAYzI,EAAmC,CAC7C,KAAK,QAAU,OAAO,OAAO,CAAA,EAAIiI,GAAgBjI,CAAO,EACxD,KAAK,MAAQ,IAAIsF,EAAM,KAAK,OAAO,CACrC,CASA,OAAOgC,EAA0B,CAC/B,GAAI,CAACoB,GAAWpB,CAAK,EACnB,MAAM,IAAI,UACRA,EAAQ,yDAAA,EAGZ,GAAIA,IAAU,GACZ,MAAO,GAET,MAAMqB,EAAS,KAAK,QAAQhB,EAASL,EAAO,KAAK,OAAO,CAAC,EACzD,OAAO,KAAK,YAAYqB,CAAM,CAChC,CASA,IAAIC,EAAoC,CACtC,GAAI,MAAM,QAAQA,CAAM,EACtB,QAAS9C,EAAI,EAAGA,EAAI8C,EAAO,OAAQ9C,IAAK,KAAK,IAAI8C,EAAO9C,CAAC,CAAC,UACjD,OAAO8C,GAAW,WAC3BA,EAAO,IAAI,MAEX,OAAM,IAAI,UAAU,oDAAoD,EAE1E,OAAO,IACT,CAUA,QAAQrD,EAAaC,EAAqB,CACxC,YAAK,MAAM,IAAID,EAAKC,CAAI,EACjB,IACT,CASA,KAAKC,EAA6B,CAChC,YAAK,MAAM,KAAKA,CAAM,EACf,IACT,CASA,OAAOA,EAA6B,CAClC,YAAK,MAAM,OAAOA,CAAM,EACjB,IACT,CASA,OAAO5E,EAAwB,CAC7B,OAAOmH,GAAQ,OAAO,SAAUa,EAAqBC,EAAoB,CACvE,OAAOD,EAAY,QAAQC,EAAO,CAAC,EAAGA,EAAO,CAAC,CAAC,CACjD,EAAGjI,CAAM,CACX,CAUA,QAAuBkI,EAA0B,CAC/C,OAAO,MAAM,KAAKA,EAAW,UAAU,EAAE,OAAO,CAACJ,EAAQ5I,IAAS,CAChE,MAAME,EAAWH,EAAaC,EAAM,KAAK,OAAO,EAChD,IAAIwE,EAAc,GAClB,GAAItE,EAAS,WAAakB,EAAU,KAAM,CACxC,MAAM6H,EAAQ/I,EAAS,WAAa,GACpCsE,EAActE,EAAS,OAAS+I,EAAQ,KAAK,OAAOA,CAAK,CAC3D,MAAW/I,EAAS,WAAakB,EAAU,UACzCoD,EAAc,KAAK,mBAAmBtE,CAAQ,GAEhD,OAAOgJ,EAAKN,EAAQpE,CAAW,CACjC,EAAG,EAAE,CACP,CASA,YAAYoE,EAAwB,CAClC,UAAWnD,KAAQ,KAAK,MAAM,MACxBA,EAAK,SACPmD,EAASM,EAAKN,EAAQnD,EAAK,OAAO,KAAK,OAAO,CAAC,GAGnD,OAAOmD,EACJ,QAAQ,aAAc,EAAE,EACxB,QAAQ,eAAgB,EAAE,CAC/B,CAUA,mBAAmB5I,EAAoB,CACrC,MAAMyF,EAAO,KAAK,MAAM,QAAQzF,CAAI,EACpC,IAAIsC,EAAU,KAAK,QAAQtC,CAAI,EAC/B,MAAMmJ,EAAanJ,EAAK,mBACxB,OAAImJ,EAAW,SAAWA,EAAW,YACnC7G,EAAUA,EAAQ,KAAA,GAGlB6G,EAAW,QACX1D,EAAK,YAAYnD,EAAStC,EAAM,KAAK,OAAO,EAC5CmJ,EAAW,QAEf,CACF,CAUA,SAASD,EAAKN,EAAgBpE,EAA6B,CACzD,MAAM4E,EAAK3H,EAAqBmH,CAAM,EAChCS,EAAK7H,EAAoBgD,CAAW,EACpC8E,EAAM,KAAK,IAAIV,EAAO,OAASQ,EAAG,OAAQ5E,EAAY,OAAS6E,EAAG,MAAM,EACxEE,EAAY;AAAA;AAAA,EAAO,UAAU,EAAGD,CAAG,EAEzC,OAAOF,EAAKG,EAAYF,CAC1B,CAUA,SAASV,GAAWpB,EAAgC,CAClD,OACEA,GAAS,OACP,OAAOA,GAAU,UAChBA,EAAM,WACLA,EAAM,WAAa,GAAKA,EAAM,WAAa,GAAKA,EAAM,WAAa,IAI3E"}
1
+ {"version":3,"file":"index.iife.js","sources":["../src/node.ts","../src/utilities.ts","../src/default-rules.ts","../src/rules.ts","../src/collapse-whitespace.ts","../src/html-parser.ts","../src/root-node.ts","../src/index.ts"],"sourcesContent":["import { isBlock, isVoid, hasVoid, isMeaningfulWhenBlank, hasMeaningfulWhenBlank } from '@/utilities'\n\ninterface Options {\n preformattedCode?: boolean;\n}\n\ninterface FlankingWhitespace {\n leading: string;\n trailing: string;\n}\n\ninterface EdgeWhitespace extends FlankingWhitespace {\n leadingAscii: string;\n leadingNonAscii: string;\n trailingNonAscii: string;\n trailingAscii: string;\n}\n\nexport interface ExtendedNode extends Element {\n isBlock: boolean;\n isCode: boolean;\n isBlank: boolean;\n flankingWhitespace: FlankingWhitespace;\n}\n\nexport function ExtendedNode(node: Node, options: Options): ExtendedNode {\n const extended = node as ExtendedNode;\n extended.isBlock = isBlock(extended);\n extended.isCode = extended.nodeName === 'CODE' || (extended.parentNode as ExtendedNode)?.isCode;\n extended.isBlank = isBlank(extended);\n extended.flankingWhitespace = flankingWhitespace(extended, options);\n return extended;\n}\n\nfunction isBlank(node: ExtendedNode): boolean {\n return (\n !isVoid(node) &&\n !isMeaningfulWhenBlank(node) &&\n /^\\s*$/i.test(node.textContent || '') &&\n !hasVoid(node) &&\n !hasMeaningfulWhenBlank(node)\n )\n}\n\nfunction flankingWhitespace(node: ExtendedNode, options: Options): FlankingWhitespace {\n const extendedNode = node as ExtendedNode;\n\n if (extendedNode.isBlock || (options.preformattedCode && extendedNode.isCode)) {\n return { leading: '', trailing: '' };\n }\n\n const edges = edgeWhitespace(node.textContent || '');\n\n // abandon leading ASCII WS if left-flanked by ASCII WS\n if (edges.leadingAscii && isFlankedByWhitespace('left', node, options)) {\n edges.leading = edges.leadingNonAscii;\n }\n\n // abandon trailing ASCII WS if right-flanked by ASCII WS\n if (edges.trailingAscii && isFlankedByWhitespace('right', node, options)) {\n edges.trailing = edges.trailingNonAscii;\n }\n\n return { leading: edges.leading, trailing: edges.trailing };\n}\n\nfunction edgeWhitespace(string: string): EdgeWhitespace {\n const m = string.match(/^(([ \\t\\r\\n]*)(\\s*))(?:(?=\\S)[\\s\\S]*\\S)?((\\s*?)([ \\t\\r\\n]*))$/);\n\n if (!m) {\n return {\n leading: '',\n leadingAscii: '',\n leadingNonAscii: '',\n trailing: '',\n trailingNonAscii: '',\n trailingAscii: ''\n };\n }\n\n return {\n leading: m[1], // whole string for whitespace-only strings\n leadingAscii: m[2],\n leadingNonAscii: m[3],\n trailing: m[4], // empty for whitespace-only strings\n trailingNonAscii: m[5],\n trailingAscii: m[6]\n };\n}\n\nfunction isFlankedByWhitespace(side: 'left' | 'right', node: Element, options: Options): boolean {\n let sibling: Node | null;\n let regExp: RegExp;\n let isFlanked: boolean | undefined;\n\n if (side === 'left') {\n sibling = node.previousSibling;\n regExp = / $/;\n } else {\n sibling = node.nextSibling;\n regExp = /^ /;\n }\n\n if (sibling) {\n if (sibling.nodeType === 3) {\n isFlanked = regExp.test(sibling.nodeValue || '');\n } else if (options.preformattedCode && sibling.nodeName === 'CODE') {\n isFlanked = false;\n } else if (sibling.nodeType === 1 && !isBlock(sibling)) {\n isFlanked = regExp.test(sibling.textContent || '');\n }\n }\n\n return isFlanked || false;\n}\n\nexport const NodeTypes = {\n Element: 1,\n Text: 3,\n CDATASection: 4,\n Comment: 8\n} as const;\n\nexport type NodeType = typeof NodeTypes[keyof typeof NodeTypes];\n","import { ExtendedNode, NodeTypes } from \"./node\";\n\nexport function repeat(character: string, count: number) {\n return Array(count + 1).join(character)\n}\n\nexport function trimLeadingNewlines(string: string) {\n return string.replace(/^\\n*/, '')\n}\n\nexport function trimTrailingNewlines(string: string) {\n // avoid match-at-end regexp bottleneck, see #370\n let indexEnd = string.length\n while (indexEnd > 0 && string[indexEnd - 1] === '\\n') indexEnd--\n return string.substring(0, indexEnd)\n}\n\nexport function trimNewlines(string: string) {\n return trimTrailingNewlines(trimLeadingNewlines(string))\n}\n\nexport const blockElements = [\n 'ADDRESS', 'ARTICLE', 'ASIDE', 'AUDIO', 'BLOCKQUOTE', 'BODY', 'CANVAS',\n 'CENTER', 'DD', 'DIR', 'DIV', 'DL', 'DT', 'FIELDSET', 'FIGCAPTION', 'FIGURE',\n 'FOOTER', 'FORM', 'FRAMESET', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'HEADER',\n 'HGROUP', 'HR', 'HTML', 'ISINDEX', 'LI', 'MAIN', 'MENU', 'NAV', 'NOFRAMES',\n 'NOSCRIPT', 'OL', 'OUTPUT', 'P', 'PRE', 'SECTION', 'TABLE', 'TBODY', 'TD',\n 'TFOOT', 'TH', 'THEAD', 'TR', 'UL'\n]\n\nexport function isBlock(node: Node) {\n return is(node, blockElements)\n}\n\nexport const voidElements = [\n 'AREA', 'BASE', 'BR', 'COL', 'COMMAND', 'EMBED', 'HR', 'IMG', 'INPUT',\n 'KEYGEN', 'LINK', 'META', 'PARAM', 'SOURCE', 'TRACK', 'WBR'\n]\n\nexport function isVoid(node: Node) {\n return is(node, voidElements)\n}\n\nexport function hasVoid(node: Node) {\n return has(node, voidElements)\n}\n\nconst meaningfulWhenBlankElements = [\n 'A', 'TABLE', 'THEAD', 'TBODY', 'TFOOT', 'TH', 'TD', 'IFRAME', 'SCRIPT',\n 'AUDIO', 'VIDEO'\n]\n\nexport const standardMarkdownElements = [\n 'P', 'BR', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'BLOCKQUOTE',\n 'UL', 'OL', 'LI', 'PRE', 'CODE', 'HR', 'A', 'EM', 'I', 'STRONG',\n 'B', 'IMG', 'DIV', 'SPAN', 'TABLE', 'THEAD', 'TBODY', 'TR', 'TH', 'TD'\n]\n\nexport function isMeaningfulWhenBlank(node: Node) {\n return is(node, meaningfulWhenBlankElements)\n}\n\nexport function hasMeaningfulWhenBlank(node: Node) {\n return has(node, meaningfulWhenBlankElements)\n}\n\nfunction is(node: Node, tagNames: string[]) {\n return tagNames.indexOf(node.nodeName) >= 0\n}\n\nfunction has(node: Node, tagNames: string[]) {\n return (\n tagNames.some(function (tagName) {\n if (node.nodeType !== NodeTypes.Element) {\n return false;\n }\n return (node as Element).getElementsByTagName(tagName).length\n })\n )\n}\n\nexport function sanitizeWhitespace(string: string): string {\n return string ? string.replace(/(\\n+\\s*)+/g, '\\n') : '';\n}\n\nexport function sanitizedLinkContent(content: string): string {\n const sanitized = sanitizeWhitespace(content);\n return sanitized\n .replace(/[\\t\\r\\n]+/g, ' ')\n .replace(/ {2,}/g, ' ')\n .replace(/([()])/g, '\\\\$1')\n .trim();\n}\n\nexport function sanitizedLinkTitle(content: string): string {\n const sanitized = sanitizeWhitespace(content);\n return sanitized\n .replace(/[\\t\\r\\n]+/g, ' ');\n}\n\nexport type RequireOnly<T, K extends keyof T> =\n T & Required<Pick<T, K>>;\n","\nimport { Rule } from '@/rules';\nimport { TurnishOptions } from '@/index';\nimport { repeat, RequireOnly, sanitizedLinkContent, sanitizedLinkTitle, trimNewlines } from '@/utilities';\nimport { NodeTypes } from './node';\n\nexport const defaultRules: { [key: string]: Rule } = {}\n\ndefaultRules.paragraph = {\n filter: 'p',\n replacement: function (content: string): string {\n return '\\n\\n' + content + '\\n\\n';\n }\n};\n\ndefaultRules.lineBreak = {\n filter: 'br',\n replacement: function (_content: string, _node: Node, options: TurnishOptions): string {\n return options.br + '\\n';\n }\n};\n\ndefaultRules.heading = {\n filter: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'],\n replacement: function (content: string, node: Node, options: TurnishOptions): string {\n const hLevel = Number(node.nodeName.charAt(1));\n if (options.headingStyle === 'setext' && hLevel < 3) {\n const underline = repeat((hLevel === 1 ? '=' : '-'), content.length);\n return (\n '\\n\\n' + content + '\\n' + underline + '\\n\\n'\n );\n } else {\n return '\\n\\n' + repeat('#', hLevel) + ' ' + content + '\\n\\n';\n }\n }\n};\n\ndefaultRules.blockquote = {\n filter: 'blockquote',\n replacement: function (content: string): string {\n content = trimNewlines(content).replace(/^/gm, '> ');\n return '\\n\\n' + content + '\\n\\n';\n }\n};\n\ndefaultRules.list = {\n filter: ['ul', 'ol'],\n replacement: function (content: string, node: Node): string {\n const parent = node.parentNode as Element;\n if (parent.nodeName === 'LI' && parent.lastElementChild === node) {\n return '\\n' + content;\n } else {\n return '\\n\\n' + content + '\\n\\n';\n }\n }\n};\n\ndefaultRules.listItem = {\n filter: 'li',\n replacement: function (content: string, node: Node, options: TurnishOptions): string {\n let prefix = options.bulletListMarker + ' '.repeat(options.listMarkerSpaceCount);\n const parent = node.parentNode as Element;\n if (parent.nodeName === 'OL') {\n const start = parent.getAttribute('start');\n const index = Array.prototype.indexOf.call(parent.children, node);\n prefix = (start ? Number(start) + index : index + 1) + '.' + ' '.repeat(options.listMarkerSpaceCount);\n }\n const isParagraph = /\\n$/.test(content);\n content = trimNewlines(content) + (isParagraph ? '\\n' : '');\n\n const hasOnlyNestedList = node.childNodes.length > 0 &&\n Array.from(node.childNodes).every((child: Node) => {\n return (child.nodeType === NodeTypes.Text && /^\\s*$/.test(child.nodeValue || ''))\n || (child.nodeType === NodeTypes.Element && ['UL', 'OL'].includes(child.nodeName));\n });\n if (hasOnlyNestedList && content.trim() !== '') {\n // This list item only contains a nested list, don't duplicate marker\n return content + (node.nextSibling ? '\\n' : '');\n }\n\n let nestingLevel = 0;\n let currentNode: Node | null = parent;\n while (currentNode) {\n if (currentNode.nodeName === 'UL' || currentNode.nodeName === 'OL') {\n const grandparent = currentNode.parentNode as Element | null;\n if (grandparent && grandparent.nodeName === 'LI') {\n nestingLevel++;\n }\n }\n currentNode = currentNode.parentNode;\n }\n\n let oneIndent = options.listItemIndent === 'tab' ? '\\t' : ' '.repeat(options.listItemIndentSpaceCount);\n let indent = oneIndent.repeat(nestingLevel);\n const listMarkerRegex = /\\n(?!\\s*(?:\\d+\\.\\s|[-+*]\\s))/gm;\n content = content.replace(listMarkerRegex, '\\n' + oneIndent);\n return indent + prefix + content + (node.nextSibling ? '\\n' : '');\n }\n};\n\ndefaultRules.indentedCodeBlock = {\n filter: function (node: Node, options: TurnishOptions): boolean {\n return !!(\n options &&\n options.codeBlockStyle === 'indented' &&\n node.nodeName === 'PRE' &&\n node.firstChild &&\n (node.firstChild as Element).nodeName === 'CODE'\n );\n },\n replacement: function (_content: string, node: Node): string {\n if (!node || !node.firstChild) return '';\n return (\n '\\n\\n ' +\n (node.firstChild as Element).textContent!.replace(/\\n/g, '\\n ') +\n '\\n\\n'\n );\n }\n};\n\ndefaultRules.fencedCodeBlock = {\n filter: function (node: Node, options: TurnishOptions): boolean {\n return !!(\n options &&\n options.codeBlockStyle === 'fenced' &&\n node.nodeName === 'PRE' &&\n node.firstChild &&\n (node.firstChild as Element).nodeName === 'CODE'\n );\n },\n replacement: function (_content: string, node: Node, options: TurnishOptions): string {\n if (!node.firstChild) {\n return '';\n }\n const codeElem = node.firstChild as Element;\n const className = codeElem.getAttribute('class') || '';\n const language = (className.match(/language-(\\S+)/) || [null, ''])[1];\n const code = codeElem.textContent || '';\n const fenceChar = options.fence?.charAt(0) || '`';\n let fenceSize = 3;\n const fenceInCodeRegex = new RegExp('^' + fenceChar + '{3,}', 'gm');\n let match;\n while ((match = fenceInCodeRegex.exec(code))) {\n if (match[0].length >= fenceSize) {\n fenceSize = match[0].length + 1;\n }\n }\n const fence = repeat(fenceChar, fenceSize);\n return (\n '\\n\\n' + fence + language + '\\n' +\n code.replace(/\\n$/, '') +\n '\\n' + fence + '\\n\\n'\n );\n }\n};\n\ndefaultRules.horizontalRule = {\n filter: 'hr',\n replacement: function (_content: string, _node: Node, options: TurnishOptions): string {\n return '\\n\\n' + options.hr + '\\n\\n';\n }\n};\n\ndefaultRules.inlineLink = {\n filter: function (node: Node, options: TurnishOptions): boolean {\n return !!(\n options?.linkStyle === 'inlined' &&\n node.nodeName === 'A' &&\n (node as Element).getAttribute('href')\n );\n },\n replacement: function (content: string, node: Node): string {\n const sanitizedContent = sanitizedLinkContent(content);\n let href = (node as Element)\n .getAttribute('href')\n ?.replace(/([()])/g, '\\\\$1');\n let title: string;\n const titleAttr = (node as Element).getAttribute('title');\n if (titleAttr) {\n const sanitizedTitle = sanitizedLinkTitle(titleAttr);\n title = ' \"' + sanitizedTitle.replace(/\"/g, '\\\\\"') + '\"';\n } else {\n title = '';\n }\n return '[' + sanitizedContent + '](' + href + title + ')';\n }\n};\n\nconst referenceLinkRule: RequireOnly<Rule, \"urlReferenceIdMap\" | \"references\"> = {\n filter: function (node: Node, options: TurnishOptions): boolean {\n return !!(\n options &&\n options.linkStyle === 'referenced' &&\n node.nodeName === 'A' &&\n (node as Element).getAttribute('href')\n );\n },\n replacement: function (content: string, node: Node, options: TurnishOptions): string {\n const self = referenceLinkRule;\n\n const href = (node as Element).getAttribute('href');\n let title: string;\n const titleAttr = (node as Element).getAttribute('title');\n if (titleAttr) {\n const sanitizedTitle = sanitizedLinkTitle(titleAttr);\n title = ' \"' + sanitizedTitle + '\"';\n } else {\n title = '';\n }\n const referenceKey = href + title;\n\n let replacement: string;\n let reference: string;\n switch (options.linkReferenceStyle) {\n case 'collapsed':\n replacement = '[' + content + '][]';\n reference = '[' + content + ']: ' + referenceKey;\n break;\n case 'shortcut':\n replacement = '[' + content + ']';\n reference = '[' + content + ']: ' + referenceKey;\n break;\n default: {\n let id: number;\n const existingKey = self.urlReferenceIdMap.get(referenceKey);\n if (options.linkReferenceDeduplication === 'full' && existingKey) {\n id = existingKey;\n reference = '[' + id + ']: ' + href + title;\n } else {\n id = self.references.length + 1;\n self.urlReferenceIdMap.set(referenceKey, id);\n reference = '[' + id + ']: ' + href + title;\n self.references.push(reference);\n }\n replacement = '[' + content + '][' + id + ']';\n break;\n }\n }\n\n if (options.linkReferenceStyle !== 'full') {\n // Check if we should deduplicate\n if (options.linkReferenceDeduplication === 'full') {\n if (!self.urlReferenceIdMap.has(referenceKey)) {\n self.urlReferenceIdMap.set(referenceKey, 1);\n self.references.push(reference);\n }\n } else {\n self.references.push(reference);\n }\n }\n return replacement;\n },\n references: [],\n urlReferenceIdMap: new Map<string, number>(),\n append: (): string => {\n const self = referenceLinkRule;\n let references = '';\n if (self.references && self.references.length) {\n references = '\\n\\n' + self.references.join('\\n') + '\\n\\n';\n self.references = [];\n self.urlReferenceIdMap = new Map();\n }\n return references;\n }\n};\n\ndefaultRules.referenceLink = referenceLinkRule;\n\ndefaultRules.emphasis = {\n filter: ['em', 'i'],\n replacement: (content: string, _node: Node, options: TurnishOptions): string => {\n content = content.trim();\n if (!content) { return ''; }\n return options.emDelimiter + content + options.emDelimiter;\n }\n};\n\ndefaultRules.strong = {\n filter: ['strong', 'b'],\n replacement: (content: string, _node: Node, options: TurnishOptions): string => {\n content = content.trim();\n if (!content) { return ''; }\n return options.strongDelimiter + content + options.strongDelimiter;\n }\n};\n\ndefaultRules.code = {\n filter: (node: Node): boolean => {\n const hasSiblings = node.previousSibling || node.nextSibling;\n const parent = node.parentNode as Element;\n const isCodeBlock = parent.nodeName === 'PRE' && !hasSiblings;\n return node.nodeName === 'CODE' && !isCodeBlock;\n },\n replacement: (content: string): string => {\n const trimmed = content.replace(/\\r?\\n|\\r/g, ' ');\n const extraSpace = /^`|^ .*?[^ ].* $|`$/.test(trimmed) ? ' ' : '';\n let delimiter = '`';\n const matches: string[] = trimmed.match(/`+/gm) || [];\n while (matches.includes(delimiter)) delimiter = delimiter + '`';\n return delimiter + extraSpace + trimmed + extraSpace + delimiter;\n }\n};\n\ndefaultRules.image = {\n filter: 'img',\n replacement: function (_content: string, node: Node): string {\n const altAttr = (node as Element).getAttribute('alt');\n const alt = altAttr ? sanitizedLinkTitle(altAttr) : '';\n const src = (node as Element).getAttribute('src') || '';\n const titleAttr = (node as Element).getAttribute('title');\n const title = titleAttr ? sanitizedLinkTitle(titleAttr) : '';\n const titlePart = title ? ' \"' + title + '\"' : '';\n return src ? '![' + alt + ']' + '(' + src + titlePart + ')' : '';\n }\n};\n","/**\n * Manages a collection of rules used to convert HTML to Markdown\n */\nimport { ExtendedNode } from \"./node\";\nimport { TurnishOptions } from \"@/index\";\nimport { standardMarkdownElements } from \"./utilities\";\n\nexport type RuleFilterFunction = (node: ExtendedNode, options: TurnishOptions) => boolean;\nexport type RuleFilter = string | string[] | RuleFilterFunction;\n\ntype RuleReplacementFunction = (...args: any[]) => string;\n\nexport interface Rule {\n filter?: RuleFilter;\n replacement: RuleReplacementFunction | ((content: string, node: any, options: TurnishOptions, previousNode?: any) => string);\n references?: string[];\n /// Map of URL+title combinations to their reference IDs, used for link reference deduplication.\n /// When linkReferenceDeduplication is 'full', this tracks which URLs have already been assigned a reference number to avoid creating duplicate references.\n urlReferenceIdMap?: Map<string, number>;\n append?: (options: TurnishOptions) => string;\n}\n\nexport class Rules {\n options: TurnishOptions;\n private _keep: Rule[];\n private _remove: Rule[];\n blankRule: Rule;\n keepReplacement: RuleReplacementFunction;\n markdownIncludingHtmlReplacement: RuleReplacementFunction;\n defaultRule: Rule;\n array: Rule[];\n\n constructor(options: TurnishOptions) {\n this.options = options;\n this._keep = [];\n this._remove = [];\n\n this.blankRule = {\n replacement: options.blankReplacement\n };\n\n this.keepReplacement = options.keepReplacement;\n this.markdownIncludingHtmlReplacement = options.markdownIncludingHtmlReplacement;\n\n this.defaultRule = {\n replacement: options.defaultReplacement\n };\n\n this.array = [];\n for (const key in options.rules) {\n this.array.push(options.rules[key]);\n }\n }\n\n add(key: string, rule: Rule): void {\n this.array.unshift(rule);\n }\n\n keep(filter: RuleFilter): void {\n this._keep.unshift({\n filter: filter,\n replacement: this.keepReplacement\n });\n }\n\n remove(filter: RuleFilter): void {\n this._remove.unshift({\n filter: filter,\n replacement: function () {\n return '';\n }\n });\n }\n\n forNode(node: ExtendedNode): Rule {\n if (node.isBlank) {\n return this.blankRule;\n }\n if (this.options.htmlRetentionMode === 'preserveAll' && this.isUnsupportedElement(node)) {\n return {\n replacement: this.keepReplacement\n };\n }\n if (this.options.htmlRetentionMode === 'markdownIncludingHtml' && this.isUnsupportedElement(node)) {\n return {\n replacement: this.markdownIncludingHtmlReplacement\n };\n }\n\n let rule: Rule | undefined;\n if ((rule = findRule(this.array, node, this.options))) {\n return rule;\n }\n if ((rule = findRule(this._keep, node, this.options))) {\n return rule;\n }\n if ((rule = findRule(this._remove, node, this.options))) {\n return rule;\n }\n return this.defaultRule;\n }\n\n /// Check if an element is unsupported for Markdown conversion.\n private isUnsupportedElement(node: ExtendedNode): boolean {\n const nodeName = node.nodeName;\n\n if (nodeName === 'PRE' && node.firstChild && (node.firstChild as Element).nodeName === 'CODE') {\n const codeElem = node.firstChild as Element;\n if (codeElem.attributes && codeElem.attributes.length > 0) {\n for (let i = 0; i < codeElem.attributes.length; i++) {\n const attrName = codeElem.attributes[i].name.toLowerCase();\n if (attrName !== 'class') {\n return true;\n }\n }\n }\n }\n\n if (node.attributes && node.attributes.length > 0) {\n switch (nodeName) {\n case 'IMG':\n for (let i = 0; i < node.attributes.length; i++) {\n const attrName = node.attributes[i].name.toLowerCase();\n if (attrName !== 'src' && attrName !== 'alt' && attrName !== 'title') {\n return true;\n }\n }\n return false;\n case 'A':\n for (let i = 0; i < node.attributes.length; i++) {\n const attrName = node.attributes[i].name.toLowerCase();\n if (attrName !== 'href' && attrName !== 'title') {\n return true;\n }\n }\n return false;\n case 'CODE':\n const parent = node.parentNode as Element;\n if (parent && parent.nodeName === 'PRE') {\n for (let i = 0; i < node.attributes.length; i++) {\n const attrName = node.attributes[i].name.toLowerCase();\n if (attrName !== 'class') {\n return true;\n }\n }\n return false;\n }\n default:\n return true;\n }\n }\n // Elements that are not standard HTML elements are unsupported\n if (standardMarkdownElements.indexOf(nodeName) === -1) {\n return true;\n }\n return false;\n }\n\n forEach(fn: (rule: Rule, index: number) => void): void {\n for (let i = 0; i < this.array.length; i++) {\n fn(this.array[i], i);\n }\n }\n}\n\nfunction findRule(rules: Rule[], node: ExtendedNode, options: TurnishOptions): Rule | undefined {\n for (let i = 0; i < rules.length; i++) {\n const rule = rules[i];\n if (filterValue(rule, node, options)) return rule;\n }\n return undefined;\n}\n\nfunction filterValue(rule: Rule, node: ExtendedNode, options: TurnishOptions): boolean {\n const filter = rule.filter;\n if (typeof filter === 'string') {\n if (filter === node.nodeName.toLowerCase()) {\n return true;\n }\n } else if (Array.isArray(filter)) {\n if (filter.indexOf(node.nodeName.toLowerCase()) > -1) {\n return true;\n }\n } else if (typeof filter === 'function') {\n if (filter(node, options)) {\n return true;\n }\n } else {\n throw new TypeError('`filter` needs to be a string, array, or function');\n }\n return false;\n}\n","/**\n * The collapseWhitespace function is adapted from collapse-whitespace\n * by Luc Thevenard.\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2014 Luc Thevenard <lucthevenard@gmail.com>\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\nimport { NodeTypes } from \"./node\";\n\n/**\n * collapseWhitespace(options) removes extraneous whitespace from an the given element.\n *\n * @param {Object} options\n */\ninterface CollapseWhitespaceOptions {\n element: Node;\n isBlock: (node: Node) => boolean;\n isVoid: (node: Node) => boolean;\n isPre?: (node: Node) => boolean;\n}\n\nfunction collapseWhitespace(options: CollapseWhitespaceOptions): void {\n const element = options.element\n const isBlock = options.isBlock\n const isVoid = options.isVoid\n const isPre = options.isPre || function (node: Node): boolean {\n return node.nodeName === 'PRE';\n };\n\n if (!element.firstChild || isPre(element)) return\n\n let prevText: Text | null = null;\n let keepLeadingWs = false\n\n let prev: Node | null = null;\n let node: Node = next(prev, element, isPre);\n\n while (node !== element) {\n if (node.nodeType === NodeTypes.Text || node.nodeType === NodeTypes.CDATASection) {\n const textNode = node as Text;\n let text = textNode.data.replace(/[ \\r\\n\\t]+/g, ' ');\n\n if ((!prevText || / $/.test(prevText.data)) &&\n !keepLeadingWs && text[0] === ' ') {\n text = text.substr(1);\n }\n\n // `text` might be empty at this point.\n if (!text) {\n node = remove(node);\n continue;\n }\n\n textNode.data = text;\n\n prevText = textNode;\n } else if (node.nodeType === NodeTypes.Element) {\n if (isBlock(node) || node.nodeName === 'BR') {\n if (prevText) {\n prevText.data = prevText.data.replace(/ $/, '');\n }\n\n prevText = null;\n keepLeadingWs = false;\n } else if (isVoid(node) || isPre(node)) {\n // Avoid trimming space around non-block, non-BR void elements and inline PRE.\n prevText = null;\n keepLeadingWs = true;\n } else if (prevText) {\n // Drop protection if set previously.\n keepLeadingWs = false;\n }\n } else {\n node = remove(node);\n continue;\n }\n\n const nextNode = next(prev, node, isPre);\n prev = node;\n node = nextNode;\n }\n\n if (prevText) {\n prevText.data = prevText.data.replace(/ $/, '');\n if (!prevText.data) {\n remove(prevText);\n }\n }\n}\n\n/**\n * remove(node) removes the given node from the DOM and returns the\n * next node in the sequence.\n *\n * @param {Node} node\n * @return {Node} node\n */\nfunction remove(node: Node): Node {\n const nextNode: Node | null = node.nextSibling ?? node.parentNode;\n if (node.parentNode) {\n node.parentNode.removeChild(node);\n }\n return nextNode as Node;\n}\n\n/**\n * next(prev, current, isPre) returns the next node in the sequence, given the\n * current and previous nodes.\n *\n * @param {Node} prev\n * @param {Node} current\n * @param {Function} isPre\n * @return {Node}\n */\nfunction next(prev: Node | null, current: Node, isPre: (node: Node) => boolean): Node {\n if ((prev && prev.parentNode === current) || isPre(current)) {\n const nextNode: Node | null = current.nextSibling ?? current.parentNode;\n return nextNode as Node;\n }\n const nextNode: Node | null = current.firstChild ?? current.nextSibling ?? current.parentNode;\n return nextNode as Node;\n}\n\nexport default collapseWhitespace\n","/*\n * Set up window for Node.js\n */\n\nconst root: typeof globalThis = typeof window !== 'undefined' ? window : (typeof globalThis !== 'undefined' ? globalThis : {} as any)\n\n/*\n * Parsing HTML strings\n */\n\nfunction canParseHTMLNatively() {\n const Parser = typeof root.DOMParser !== 'undefined' ? root.DOMParser : undefined;\n let canParse = false;\n if (!Parser) return false;\n // Adapted from https://gist.github.com/1129031\n // Firefox/Opera/IE throw errors on unsupported types\n try {\n // WebKit returns null on unsupported types\n if (new Parser().parseFromString('', 'text/html')) {\n canParse = true;\n }\n } catch (e) { }\n return canParse;\n}\n\nexport class HTMLParser {\n // This will be assigned per environment below\n parseFromString(_input: string, _type?: string): Document {\n throw new Error('Not implemented')\n }\n}\n\nfunction createParser(): HTMLParser {\n const isBrowser =\n typeof window !== 'undefined' &&\n typeof document !== 'undefined' &&\n (typeof process === 'undefined' || (process as any).browser === true)\n\n if (typeof window !== 'undefined') {\n // Browser environment: use DOM API\n class HTMLParserBrowser extends HTMLParser {\n parseFromString(input: string, _type?: string): Document {\n const doc = document.implementation.createHTMLDocument('')\n doc.open()\n doc.write(input)\n doc.close()\n return doc\n }\n }\n return new HTMLParserBrowser()\n } else {\n // Node environment: use domino\n const domino = require('@mixmark-io/domino') as {\n createDocument: (html: string) => Document\n }\n class HTMLParserNode extends HTMLParser {\n parseFromString(input: string, _type?: string): Document {\n return domino.createDocument(input);\n }\n }\n return new HTMLParserNode()\n }\n}\n\nexport const createHTMLParser = (): HTMLParser =>\n canParseHTMLNatively()\n ? new root.DOMParser()\n : createParser()\n","import collapseWhitespace from '@/collapse-whitespace'\nimport { createHTMLParser, HTMLParser } from '@/html-parser'\nimport { isBlock, isVoid } from '@/utilities'\n\ninterface RootNodeOptions {\n preformattedCode?: boolean\n}\n\nexport default function RootNode(\n input: string | Node,\n { preformattedCode }: RootNodeOptions\n): Element {\n let root: Element\n if (typeof input === 'string') {\n const doc = htmlParser().parseFromString(\n // DOM parsers arrange elements in the <head> and <body>.\n // Wrapping in a custom element ensures elements are reliably arranged in\n // a single element.\n '<x-turnish id=\"turnish-root\">' + input + '</x-turnish>',\n 'text/html'\n )\n root = doc.getElementById('turnish-root') as Element\n } else {\n root = input.cloneNode(true) as Element\n }\n collapseWhitespace({\n element: root,\n isBlock: isBlock,\n isVoid: isVoid,\n isPre: preformattedCode ? isPreOrCode : undefined\n })\n\n return root\n}\n\nlet _htmlParser: HTMLParser | undefined\nfunction htmlParser(): HTMLParser {\n return (_htmlParser ??= createHTMLParser())\n}\n\nfunction isPreOrCode(node: Node): boolean {\n return node.nodeName === 'PRE' || node.nodeName === 'CODE';\n}\n","import { defaultRules } from '@/default-rules'\nimport { Rules, Rule, RuleFilter } from '@/rules'\nimport { trimLeadingNewlines, trimTrailingNewlines } from '@/utilities'\nimport RootNode from '@/root-node'\nimport { ExtendedNode, NodeTypes } from '@/node';\nconst reduce = Array.prototype.reduce\n\ntype EscapeRule = [RegExp, string];\n\nconst escapes: EscapeRule[] = [\n [/\\\\/g, '\\\\\\\\'],\n [/\\*/g, '\\\\*'],\n [/_/g, '\\\\_'],\n [/^-/g, '\\\\-'],\n [/^\\+ /g, '\\\\+ '],\n [/^(=+)/g, '\\\\$1'],\n [/^(#{1,6}) /g, '\\\\$1 '],\n [/`/g, '\\\\`'],\n [/^~~~/g, '\\\\~~~'],\n [/\\[/g, '\\\\['],\n [/\\]/g, '\\\\]'],\n [/<([^>]*)>/g, '\\\\<$1\\\\>'],\n [/^>/g, '\\\\>'],\n [/^(\\d+)\\. /g, '$1\\\\. ']\n];\n\ntype Plugin = (service: Turnish) => void;\n\nexport interface TurnishOptions {\n rules: { [key: string]: Rule };\n headingStyle: 'setext' | 'atx';\n hr: string;\n bulletListMarker: '*' | '-' | '+';\n listMarkerSpaceCount: 1 | 2 | 3 | 4;\n listItemIndent: 'tab' | 'space';\n listItemIndentSpaceCount: 1 | 2 | 3 | 4;\n codeBlockStyle: 'indented' | 'fenced';\n fence: string;\n emDelimiter: '_' | '*';\n strongDelimiter: '**' | '__';\n linkStyle: 'inlined' | 'referenced';\n linkReferenceStyle: 'full' | 'collapsed' | 'shortcut';\n linkReferenceDeduplication: 'none' | 'full';\n br: string;\n preformattedCode: boolean;\n htmlRetentionMode: 'standard' | 'preserveAll' | 'markdownIncludingHtml';\n blankReplacement: (content: string, node: ExtendedNode) => string;\n keepReplacement: (content: string, node: ExtendedNode) => string;\n markdownIncludingHtmlReplacement: (content: string, node: ExtendedNode) => string;\n defaultReplacement: (content: string, node: ExtendedNode) => string;\n [key: string]: any;\n}\n\n\nconst defaultOptions: TurnishOptions = {\n rules: defaultRules,\n headingStyle: 'atx',\n hr: '---',\n bulletListMarker: '-',\n listMarkerSpaceCount: 1,\n listItemIndent: 'space',\n listItemIndentSpaceCount: 4,\n codeBlockStyle: 'fenced',\n fence: '```',\n emDelimiter: '*',\n strongDelimiter: '**',\n linkStyle: 'inlined',\n linkReferenceStyle: 'full',\n linkReferenceDeduplication: 'full',\n br: ' ',\n preformattedCode: false,\n htmlRetentionMode: 'standard',\n blankReplacement: (content: string, node: ExtendedNode): string => {\n return node.isBlock ? '\\n\\n' : '';\n },\n keepReplacement: (content: string, node: ExtendedNode): string => {\n return node.isBlock ? '\\n\\n' + node.outerHTML + '\\n\\n' : node.outerHTML;\n },\n markdownIncludingHtmlReplacement: (content: string, node: ExtendedNode): string => {\n const tagName = node.nodeName.toLowerCase();\n\n let attributes = '';\n if (node.attributes && node.attributes.length > 0) {\n const attrs: string[] = [];\n for (let i = 0; i < node.attributes.length; i++) {\n const attr = node.attributes[i];\n attrs.push(`${attr.name}=\"${attr.value}\"`);\n }\n attributes = ' ' + attrs.join(' ');\n }\n\n attributes += ' markdown=\"1\"';\n\n const openTag = `<${tagName}${attributes}>`;\n const closeTag = `</${tagName}>`;\n\n const trimmedContent = content.trim();\n const html = openTag + '\\n' + trimmedContent + '\\n' + closeTag;\n\n return node.isBlock ? '\\n\\n' + html + '\\n\\n' : html;\n },\n defaultReplacement: function (content: string, node: ExtendedNode): string {\n return node.isBlock ? '\\n\\n' + content + '\\n\\n' : content;\n }\n};\n\nexport default class Turnish {\n options: TurnishOptions;\n rules: Rules;\n\n constructor(options?: Partial<TurnishOptions>) {\n this.options = Object.assign({}, defaultOptions, options);\n this.rules = new Rules(this.options);\n }\n\n /**\n * The entry point for converting a string or DOM node to Markdown\n * @public\n * @param {InputType} input The string or DOM node to convert\n * @returns A Markdown representation of the input\n * @type string\n */\n render(input: InputType): string {\n if (!canConvert(input)) {\n throw new TypeError(\n input + ' is not a string, or an element/document/fragment node.'\n );\n }\n if (input === '') {\n return '';\n }\n const output = this.process(RootNode(input, this.options));\n return this.postProcess(output);\n }\n\n /**\n * Add one or more plugins\n * @public\n * @param {Plugin|Plugin[]} plugin The plugin or array of plugins to add\n * @returns The Turnish instance for chaining\n * @type Object\n */\n use(plugin: Plugin | Plugin[]): Turnish {\n if (Array.isArray(plugin)) {\n for (let i = 0; i < plugin.length; i++) this.use(plugin[i]);\n } else if (typeof plugin === 'function') {\n plugin(this);\n } else {\n throw new TypeError('plugin must be a Function or an Array of Functions');\n }\n return this;\n }\n\n /**\n * Adds a rule\n * @public\n * @param {string} key The unique key of the rule\n * @param {Object} rule The rule\n * @returns The Turnish instance for chaining\n * @type Object\n */\n addRule(key: string, rule: Rule): Turnish {\n this.rules.add(key, rule);\n return this;\n }\n\n /**\n * Keep a node (as HTML) that matches the filter\n * @public\n * @param {RuleFilter} filter The unique key of the rule\n * @returns The Turnish instance for chaining\n * @type Object\n */\n keep(filter: RuleFilter): Turnish {\n this.rules.keep(filter);\n return this;\n }\n\n /**\n * Remove a node that matches the filter\n * @public\n * @param {string|Array|Function} filter The unique key of the rule\n * @returns The Turnish instance for chaining\n * @type Object\n */\n remove(filter: RuleFilter): Turnish {\n this.rules.remove(filter);\n return this;\n }\n\n /**\n * Escapes Markdown syntax\n * @public\n * @param {string} string The string to escape\n * @returns A string with Markdown syntax escaped\n * @type string\n */\n escape(string: string): string {\n return escapes.reduce(function (accumulator: string, escape: EscapeRule) {\n return accumulator.replace(escape[0], escape[1]);\n }, string);\n }\n\n\n /**\n * Reduces a DOM node down to its Markdown string equivalent\n * @private\n * @param {HTMLElement} parentNode The node to convert\n * @returns A Markdown representation of the node\n * @type string\n */\n process(this: Turnish, parentNode: Node): string {\n return Array.from(parentNode.childNodes).reduce((output, node) => {\n const extended = ExtendedNode(node, this.options);\n let replacement = '';\n if (extended.nodeType === NodeTypes.Text) {\n let value = extended.nodeValue ?? '';\n // Special handling for text nodes following void elements. Void element replacements (e.g., from GFM plugin for checkboxes) may add trailing whitespace, so we should remove leading whitespace from the following text node.\n if (node.previousSibling && node.previousSibling.nodeType === NodeTypes.Element) {\n const prevElement = node.previousSibling as Element;\n if (prevElement.nodeName === 'INPUT' && prevElement.getAttribute('type') === 'checkbox') {\n value = value.replace(/^\\s+/, '');\n }\n }\n replacement = extended.isCode ? value : this.escape(value);\n } else if (extended.nodeType === NodeTypes.Element) {\n replacement = this.replacementForNode(extended);\n }\n return join(output, replacement);\n }, '');\n }\n\n /**\n * Appends strings as each rule requires and trims the output\n * @private\n * @param {string} output The conversion output\n * @returns A trimmed version of the ouput\n * @type string\n */\n postProcess(output: string): string {\n for (const rule of this.rules.array) {\n if (rule.append) {\n output = join(output, rule.append(this.options))\n }\n }\n return output\n .replace(/^[\\t\\r\\n]+/, '')\n .replace(/[\\t\\r\\n\\s]+$/, '')\n }\n\n\n /**\n * Converts an element node to its Markdown equivalent\n * @private\n * @param {ExtendedNode} node The node to convert\n * @returns A Markdown representation of the node\n * @type string\n */\n replacementForNode(node: ExtendedNode) {\n const rule = this.rules.forNode(node)\n let content = this.process(node)\n const whitespace = node.flankingWhitespace\n if (whitespace.leading || whitespace.trailing) {\n content = content.trim()\n }\n return (\n whitespace.leading +\n rule.replacement(content, node, this.options) +\n whitespace.trailing\n )\n }\n}\n\n/**\n * Joins replacement to the current output with appropriate number of new lines\n * @private\n * @param {string} output The current conversion output\n * @param {string} replacement The string to append to the output\n * @returns Joined output\n * @type string\n */\nfunction join(output: string, replacement: string): string {\n const s1 = trimTrailingNewlines(output)\n const s2 = trimLeadingNewlines(replacement)\n const nls = Math.max(output.length - s1.length, replacement.length - s2.length)\n const separator = '\\n\\n'.substring(0, nls)\n\n return s1 + separator + s2\n}\n\n/**\n * Determines whether an input can be converted\n * @private\n * @param {string|HTMLElement} input Describe this parameter\n * @returns Describe what it returns\n * @type string|Object|Array|Boolean|Number\n */\ntype InputType = string | HTMLElement | Document | DocumentFragment;\nfunction canConvert(input: any): input is InputType {\n return (\n input != null && (\n typeof input === 'string' ||\n (input.nodeType && (\n input.nodeType === 1 || input.nodeType === 9 || input.nodeType === 11\n ))\n )\n );\n}\n"],"names":["ExtendedNode","node","options","extended","isBlock","isBlank","flankingWhitespace","isVoid","isMeaningfulWhenBlank","hasVoid","hasMeaningfulWhenBlank","extendedNode","edges","edgeWhitespace","isFlankedByWhitespace","string","m","side","sibling","regExp","isFlanked","NodeTypes","repeat","character","count","trimLeadingNewlines","trimTrailingNewlines","indexEnd","trimNewlines","blockElements","is","voidElements","has","meaningfulWhenBlankElements","standardMarkdownElements","tagNames","tagName","sanitizeWhitespace","sanitizedLinkContent","content","sanitizedLinkTitle","defaultRules","_content","_node","hLevel","underline","parent","prefix","start","index","isParagraph","child","nestingLevel","currentNode","grandparent","oneIndent","indent","listMarkerRegex","codeElem","language","code","fenceChar","fenceSize","fenceInCodeRegex","match","fence","sanitizedContent","href","title","titleAttr","referenceLinkRule","self","referenceKey","replacement","reference","id","existingKey","references","hasSiblings","isCodeBlock","trimmed","extraSpace","delimiter","matches","altAttr","alt","src","titlePart","Rules","key","rule","filter","findRule","nodeName","attrName","fn","i","rules","filterValue","collapseWhitespace","element","isPre","prevText","keepLeadingWs","prev","next","textNode","text","remove","nextNode","current","root","canParseHTMLNatively","Parser","canParse","HTMLParser","_input","_type","createParser","HTMLParserBrowser","input","doc","domino","HTMLParserNode","createHTMLParser","RootNode","preformattedCode","htmlParser","isPreOrCode","_htmlParser","escapes","defaultOptions","attributes","attrs","attr","openTag","closeTag","trimmedContent","html","Turnish","canConvert","output","plugin","accumulator","escape","parentNode","value","prevElement","join","whitespace","s1","s2","nls","separator"],"mappings":"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"}
package/dist/index.mjs CHANGED
@@ -10,7 +10,7 @@ function _(t, e) {
10
10
  if (n.isBlock || e.preformattedCode && n.isCode)
11
11
  return { leading: "", trailing: "" };
12
12
  const r = $(t.textContent || "");
13
- return r.leadingAscii && C("left", t, e) && (r.leading = r.leadingNonAscii), r.trailingAscii && C("right", t, e) && (r.trailing = r.trailingNonAscii), { leading: r.leading, trailing: r.trailing };
13
+ return r.leadingAscii && b("left", t, e) && (r.leading = r.leadingNonAscii), r.trailingAscii && b("right", t, e) && (r.trailing = r.trailingNonAscii), { leading: r.leading, trailing: r.trailing };
14
14
  }
15
15
  function $(t) {
16
16
  const e = t.match(/^(([ \t\r\n]*)(\s*))(?:(?=\S)[\s\S]*\S)?((\s*?)([ \t\r\n]*))$/);
@@ -32,9 +32,9 @@ function $(t) {
32
32
  trailingAscii: ""
33
33
  };
34
34
  }
35
- function C(t, e, n) {
35
+ function b(t, e, n) {
36
36
  let r, i, l;
37
- return t === "left" ? (r = e.previousElementSibling, i = / $/) : (r = e.nextElementSibling, i = /^ /), r && (r.nodeType === 3 ? l = i.test(r.nodeValue || "") : n.preformattedCode && r.nodeName === "CODE" ? l = !1 : r.nodeType === 1 && !E(r) && (l = i.test(r.textContent || ""))), l || !1;
37
+ return t === "left" ? (r = e.previousSibling, i = / $/) : (r = e.nextSibling, i = /^ /), r && (r.nodeType === 3 ? l = i.test(r.nodeValue || "") : n.preformattedCode && r.nodeName === "CODE" ? l = !1 : r.nodeType === 1 && !E(r) && (l = i.test(r.textContent || ""))), l || !1;
38
38
  }
39
39
  const p = {
40
40
  Element: 1,
@@ -44,17 +44,17 @@ const p = {
44
44
  function T(t, e) {
45
45
  return Array(e + 1).join(t);
46
46
  }
47
- function S(t) {
47
+ function I(t) {
48
48
  return t.replace(/^\n*/, "");
49
49
  }
50
- function w(t) {
50
+ function O(t) {
51
51
  let e = t.length;
52
52
  for (; e > 0 && t[e - 1] === `
53
53
  `; ) e--;
54
54
  return t.substring(0, e);
55
55
  }
56
- function D(t) {
57
- return w(S(t));
56
+ function w(t) {
57
+ return O(I(t));
58
58
  }
59
59
  const F = [
60
60
  "ADDRESS",
@@ -110,7 +110,7 @@ const F = [
110
110
  function E(t) {
111
111
  return A(t, F);
112
112
  }
113
- const I = [
113
+ const D = [
114
114
  "AREA",
115
115
  "BASE",
116
116
  "BR",
@@ -129,10 +129,10 @@ const I = [
129
129
  "WBR"
130
130
  ];
131
131
  function L(t) {
132
- return A(t, I);
132
+ return A(t, D);
133
133
  }
134
134
  function U(t) {
135
- return B(t, I);
135
+ return B(t, D);
136
136
  }
137
137
  const M = [
138
138
  "A",
@@ -242,7 +242,7 @@ f.heading = {
242
242
  f.blockquote = {
243
243
  filter: "blockquote",
244
244
  replacement: function(t) {
245
- return t = D(t).replace(/^/gm, "> "), `
245
+ return t = w(t).replace(/^/gm, "> "), `
246
246
 
247
247
  ` + t + `
248
248
 
@@ -271,7 +271,7 @@ f.listItem = {
271
271
  r = (m ? Number(m) + y : y + 1) + "." + " ".repeat(n.listMarkerSpaceCount);
272
272
  }
273
273
  const l = /\n$/.test(t);
274
- if (t = D(t) + (l ? `
274
+ if (t = w(t) + (l ? `
275
275
  ` : ""), e.childNodes.length > 0 && Array.from(e.childNodes).every((m) => m.nodeType === p.Text && /^\s*$/.test(m.nodeValue || "") || m.nodeType === p.Element && ["UL", "OL"].includes(m.nodeName)) && t.trim() !== "")
276
276
  return t + (e.nextSibling ? `
277
277
  ` : "");
@@ -347,12 +347,12 @@ f.inlineLink = {
347
347
  return l ? i = ' "' + h(l).replace(/"/g, '\\"') + '"' : i = "", "[" + n + "](" + r + i + ")";
348
348
  }
349
349
  };
350
- const R = {
350
+ const k = {
351
351
  filter: function(t, e) {
352
352
  return !!(e && e.linkStyle === "referenced" && t.nodeName === "A" && t.getAttribute("href"));
353
353
  },
354
354
  replacement: function(t, e, n) {
355
- const r = R, i = e.getAttribute("href");
355
+ const r = k, i = e.getAttribute("href");
356
356
  let l;
357
357
  const o = e.getAttribute("title");
358
358
  o ? l = ' "' + h(o) + '"' : l = "";
@@ -377,7 +377,7 @@ const R = {
377
377
  references: [],
378
378
  urlReferenceIdMap: /* @__PURE__ */ new Map(),
379
379
  append: () => {
380
- const t = R;
380
+ const t = k;
381
381
  let e = "";
382
382
  return t.references && t.references.length && (e = `
383
383
 
@@ -387,7 +387,7 @@ const R = {
387
387
  `, t.references = [], t.urlReferenceIdMap = /* @__PURE__ */ new Map()), e;
388
388
  }
389
389
  };
390
- f.referenceLink = R;
390
+ f.referenceLink = k;
391
391
  f.emphasis = {
392
392
  filter: ["em", "i"],
393
393
  replacement: (t, e, n) => (t = t.trim(), t ? n.emDelimiter + t + n.emDelimiter : "")
@@ -536,7 +536,7 @@ function Y(t) {
536
536
  return c.nodeName === "PRE";
537
537
  };
538
538
  if (!e.firstChild || i(e)) return;
539
- let l = null, o = !1, a = null, s = b(a, e, i);
539
+ let l = null, o = !1, a = null, s = C(a, e, i);
540
540
  for (; s !== e; ) {
541
541
  if (s.nodeType === p.Text || s.nodeType === p.CDATASection) {
542
542
  const u = s;
@@ -552,7 +552,7 @@ function Y(t) {
552
552
  s = N(s);
553
553
  continue;
554
554
  }
555
- const c = b(a, s, i);
555
+ const c = C(a, s, i);
556
556
  a = s, s = c;
557
557
  }
558
558
  l && (l.data = l.data.replace(/ $/, ""), l.data || N(l));
@@ -561,12 +561,12 @@ function N(t) {
561
561
  const e = t.nextSibling ?? t.parentNode;
562
562
  return t.parentNode && t.parentNode.removeChild(t), e;
563
563
  }
564
- function b(t, e, n) {
564
+ function C(t, e, n) {
565
565
  return t && t.parentNode === e || n(e) ? e.nextSibling ?? e.parentNode : e.firstChild ?? e.nextSibling ?? e.parentNode;
566
566
  }
567
- const k = typeof window < "u" ? window : typeof globalThis < "u" ? globalThis : {};
567
+ const R = typeof window < "u" ? window : typeof globalThis < "u" ? globalThis : {};
568
568
  function q() {
569
- const t = typeof k.DOMParser < "u" ? k.DOMParser : void 0;
569
+ const t = typeof R.DOMParser < "u" ? R.DOMParser : void 0;
570
570
  let e = !1;
571
571
  if (!t) return !1;
572
572
  try {
@@ -575,7 +575,7 @@ function q() {
575
575
  }
576
576
  return e;
577
577
  }
578
- class x {
578
+ class S {
579
579
  // This will be assigned per environment below
580
580
  parseFromString(e, n) {
581
581
  throw new Error("Not implemented");
@@ -583,7 +583,7 @@ class x {
583
583
  }
584
584
  function Q() {
585
585
  if (typeof window < "u" && typeof document < "u" && (typeof process > "u" || process.browser), typeof window < "u") {
586
- class t extends x {
586
+ class t extends S {
587
587
  parseFromString(n, r) {
588
588
  const i = document.implementation.createHTMLDocument("");
589
589
  return i.open(), i.write(n), i.close(), i;
@@ -592,7 +592,7 @@ function Q() {
592
592
  return new t();
593
593
  } else {
594
594
  const t = require("@mixmark-io/domino");
595
- class e extends x {
595
+ class e extends S {
596
596
  parseFromString(r, i) {
597
597
  return t.createDocument(r);
598
598
  }
@@ -600,7 +600,7 @@ function Q() {
600
600
  return new e();
601
601
  }
602
602
  }
603
- const X = () => q() ? new k.DOMParser() : Q();
603
+ const X = () => q() ? new R.DOMParser() : Q();
604
604
  function J(t, { preformattedCode: e }) {
605
605
  let n;
606
606
  return typeof t == "string" ? n = ee().parseFromString(
@@ -787,10 +787,14 @@ class le {
787
787
  const i = H(r, this.options);
788
788
  let l = "";
789
789
  if (i.nodeType === p.Text) {
790
- const o = i.nodeValue ?? "";
790
+ let o = i.nodeValue ?? "";
791
+ if (r.previousSibling && r.previousSibling.nodeType === p.Element) {
792
+ const a = r.previousSibling;
793
+ a.nodeName === "INPUT" && a.getAttribute("type") === "checkbox" && (o = o.replace(/^\s+/, ""));
794
+ }
791
795
  l = i.isCode ? o : this.escape(o);
792
796
  } else i.nodeType === p.Element && (l = this.replacementForNode(i));
793
- return O(n, l);
797
+ return x(n, l);
794
798
  }, "");
795
799
  }
796
800
  /**
@@ -802,7 +806,7 @@ class le {
802
806
  */
803
807
  postProcess(e) {
804
808
  for (const n of this.rules.array)
805
- n.append && (e = O(e, n.append(this.options)));
809
+ n.append && (e = x(e, n.append(this.options)));
806
810
  return e.replace(/^[\t\r\n]+/, "").replace(/[\t\r\n\s]+$/, "");
807
811
  }
808
812
  /**
@@ -819,8 +823,8 @@ class le {
819
823
  return (i.leading || i.trailing) && (r = r.trim()), i.leading + n.replacement(r, e, this.options) + i.trailing;
820
824
  }
821
825
  }
822
- function O(t, e) {
823
- const n = w(t), r = S(e), i = Math.max(t.length - n.length, e.length - r.length), l = `
826
+ function x(t, e) {
827
+ const n = O(t), r = I(e), i = Math.max(t.length - n.length, e.length - r.length), l = `
824
828
 
825
829
  `.substring(0, i);
826
830
  return n + l + r;