import { cloneElement, createElement } from "react";
import { jsx, jsxs } from "react/jsx-runtime";

//#region src/components/MarkDownRender/processor.tsx
/**
* it's a fork
* [markdown-to-jsx v7.7.14](https://github.com/quantizor/markdown-to-jsx) from quantizor
* [simple-markdown v0.2.2](https://github.com/Khan/simple-markdown) from Khan Academy.
*/
/**
* Analogous to `node.type`. Please note that the values here may change at any time,
* so do not hard code against the value directly.
*/
const RuleType = {
	blockQuote: "0",
	breakLine: "1",
	breakThematic: "2",
	codeBlock: "3",
	codeFenced: "4",
	codeInline: "5",
	footnote: "6",
	footnoteReference: "7",
	gfmTask: "8",
	heading: "9",
	headingSetext: "10",
	htmlBlock: "11",
	htmlComment: "12",
	htmlSelfClosing: "13",
	customComponent: "34",
	image: "14",
	link: "15",
	linkAngleBraceStyleDetector: "16",
	linkBareUrlDetector: "17",
	newlineCoalescer: "19",
	orderedList: "20",
	paragraph: "21",
	ref: "22",
	refImage: "23",
	refLink: "24",
	table: "25",
	tableSeparator: "26",
	text: "27",
	textBolded: "28",
	textEmphasized: "29",
	textEscaped: "30",
	textMarked: "31",
	textStrikethroughed: "32",
	unorderedList: "33"
};
if (process.env.NODE_ENV === "test") Object.keys(RuleType).forEach((key) => {
	RuleType[key] = key;
});
const durationDelayTrigger = 20;
const Priority = {
	MAX: 0,
	HIGH: 1,
	MED: 2,
	LOW: 3,
	MIN: 4
};
/** TODO: Drop for React 16? */
const ATTRIBUTE_TO_JSX_PROP_MAP = [
	"allowFullScreen",
	"allowTransparency",
	"autoComplete",
	"autoFocus",
	"autoPlay",
	"cellPadding",
	"cellSpacing",
	"charSet",
	"classId",
	"colSpan",
	"contentEditable",
	"contextMenu",
	"crossOrigin",
	"encType",
	"formAction",
	"formEncType",
	"formMethod",
	"formNoValidate",
	"formTarget",
	"frameBorder",
	"hrefLang",
	"inputMode",
	"keyParams",
	"keyType",
	"marginHeight",
	"marginWidth",
	"maxLength",
	"mediaGroup",
	"minLength",
	"noValidate",
	"radioGroup",
	"readOnly",
	"rowSpan",
	"spellCheck",
	"srcDoc",
	"srcLang",
	"srcSet",
	"tabIndex",
	"useMap"
].reduce((obj, x) => {
	obj[x.toLowerCase()] = x;
	return obj;
}, {
	class: "className",
	for: "htmlFor"
});
const namedCodesToUnicode = {
	amp: "&",
	apos: "'",
	gt: ">",
	lt: "<",
	nbsp: "\xA0",
	quot: "“"
};
const DO_NOT_PROCESS_HTML_ELEMENTS = [
	"style",
	"script",
	"pre"
];
const ATTRIBUTES_TO_SANITIZE = [
	"src",
	"href",
	"data",
	"formAction",
	"srcDoc",
	"action"
];
/**
* the attribute extractor regex looks for a valid attribute name,
* followed by an equal sign (whitespace around the equal sign is allowed), followed
* by one of the following:
*
* 1. a single quote-bounded string, e.g. 'foo'
* 2. a double quote-bounded string, e.g. "bar"
* 3. an interpolation, e.g. {something}
*
* JSX can be be interpolated into itself and is passed through the compiler using
* the same options and setup as the current run.
*
* <Something children={<SomeOtherThing />} />
*                      ==================
*                              ↳ children: [<SomeOtherThing />]
*
* Otherwise, interpolations are handled as strings or simple booleans
* unless HTML syntax is detected.
*
* <Something color={green} disabled={true} />
*                   =====            ====
*                     ↓                ↳ disabled: true
*                     ↳ color: "green"
*
* Numbers are not parsed at this time due to complexities around int, float,
* and the upcoming bigint functionality that would make handling it unwieldy.
* Parse the string in your component as desired.
*
* <Something someBigNumber={123456789123456789} />
*                           ==================
*                                   ↳ someBigNumber: "123456789123456789"
*/
const ATTR_EXTRACTOR_R = /([-A-Z0-9_:]+)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|(?:\{((?:\\.|{[^}]*?}|[^}])*)\})))?/gi;
/** TODO: Write explainers for each of these */
const BLOCK_END_R = /\n{2,}$/;
const BLOCKQUOTE_R = /^(\s*>[\s\S]*?)(?=\n\n|$)/;
const BLOCKQUOTE_TRIM_LEFT_MULTILINE_R = /^ *> ?/gm;
const BLOCKQUOTE_ALERT_R = /^(?:\[!([^\]]*)\]\n)?([\s\S]*)/;
const BREAK_LINE_R = /^ {2,}\n/;
const BREAK_THEMATIC_R = /^(?:([-*_])( *\1){2,}) *(?:\n *)+\n/;
const CODE_BLOCK_FENCED_R = /^(?: {1,3})?(`{3,}|~{3,}) *(\S+)? *([^\n]*?)?\n([\s\S]*?)(?:\1\n?|$)/;
const CODE_BLOCK_R = /^(?: {4}[^\n]+\n*)+(?:\n *)+\n?/;
const CODE_INLINE_R = /^(`+)((?:\\`|(?!\1)`|[^`])+)\1/;
const CONSECUTIVE_NEWLINE_R = /^(?:\n *)*\n/;
const CR_NEWLINE_R = /\r\n?/g;
/**
* Matches footnotes on the format:
*
* [^key]: value
*
* Matches multiline footnotes
*
* [^key]: row
* row
* row
*
* And empty lines in indented multiline footnotes
*
* [^key]: indented with
*     row
*
*     row
*
* Explanation:
*
* 1. Look for the starting tag, eg: [^key]
*    ^\[\^([^\]]+)]
*
* 2. The first line starts with a colon, and continues for the rest of the line
*   :(.*)
*
* 3. Parse as many additional lines as possible. Matches new non-empty lines that doesn't begin with a new footnote definition.
*    (\n(?!\[\^).+)
*
* 4. ...or allows for repeated newlines if the next line begins with at least four whitespaces.
*    (\n+ {4,}.*)
*/
const FOOTNOTE_R = /^\[\^([^\]]+)](:(.*)((\n+ {4,}.*)|(\n(?!\[\^).+))*)/;
const FOOTNOTE_REFERENCE_R = /^\[\^([^\]]+)]/;
const FORMFEED_R = /\f/g;
const FRONT_MATTER_R = /^---[ \t]*\n(.|\n)*\n---[ \t]*\n/;
const GFM_TASK_R = /^\s*?\[(x|\s)\]/;
const HEADING_R = /^ *(#{1,6}) *([^\n]+?)(?: +#*)?(?:\n *)*(?:\n|$)/;
const HEADING_ATX_COMPLIANT_R = /^ *(#{1,6}) +([^\n]+?)(?: +#*)?(?:\n *)*(?:\n|$)/;
const HEADING_SETEXT_R = /^([^\n]+)\n *(=|-)\2{2,} *\n/;
/**
* Explanation:
*
* 1. Look for a starting tag, preceded by any amount of spaces
*    ^ *<
*
* 2. Capture the tag name (capture 1)
*    ([^ >/]+)
*
* 3. Ignore a space after the starting tag and capture the attribute portion of the tag (capture 2)
*     ?([^>]*)>
*
* 4. Ensure a matching closing tag is present in the rest of the input string
*    (?=[\s\S]*<\/\1>)
*
* 5. Capture everything until the matching closing tag -- this might include additional pairs
*    of the same tag type found in step 2 (capture 3)
*    ((?:[\s\S]*?(?:<\1[^>]*>[\s\S]*?<\/\1>)*[\s\S]*?)*?)<\/\1>
*
* 6. Capture excess newlines afterward
*    \n*
*/
const HTML_BLOCK_ELEMENT_R = /^ *(?!<[a-zA-Z][^ >/]* ?\/>)<([a-zA-Z][^ >/]*) ?((?:[^>]*[^/])?)>\n?(\s*(?:<\1[^>]*?>[\s\S]*?<\/\1>|(?!<\1\b)[\s\S])*?)<\/\1>(?!<\/\1>)\n*/i;
const HTML_CHAR_CODE_R = /&([a-z0-9]+|#[0-9]{1,6}|#x[0-9a-fA-F]{1,6});/gi;
const HTML_COMMENT_R = /^<!--[\s\S]*?(?:-->)/;
/**
* borrowed from React 15(https://github.com/facebook/react/blob/894d20744cba99383ffd847dbd5b6e0800355a5c/src/renderers/dom/shared/HTMLDOMPropertyConfig.js)
*/
const HTML_CUSTOM_ATTR_R = /^(data|aria|x)-[a-z_][a-z\d_.-]*$/;
const HTML_SELF_CLOSING_ELEMENT_R = /^ *<([a-zA-Z][a-zA-Z0-9:]*)(?:\s+((?:<.*?>|[^>])*))?\/?>(?!<\/\1>)(\s*\n)?/i;
const CUSTOM_COMPONENT_R = /^ *<([A-Z][a-zA-Z0-9]*)(?:\s+((?:<.*?>|[^>])*))?>\n?(\s*(?:<\1[^>]*?>[\s\S]*?<\/\1>|(?!<\1\b)[\s\S])*?)<\/\1>(?!<\/\1>)\n*/;
const INTERPOLATION_R = /^\{.*\}$/;
const LINK_AUTOLINK_BARE_URL_R = /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/;
const LINK_AUTOLINK_R = /^<([^ >]+[:@/][^ >]+)>/;
const CAPTURE_LETTER_AFTER_HYPHEN = /-([a-z])?/gi;
const NP_TABLE_R = /^(\|.*)\n(?: *(\|? *[-:]+ *\|[-| :]*)\n((?:.*\|.*\n)*))?\n?/;
const PARAGRAPH_R = /^[^\n]+(?: {2}\n|\n{2,})/;
const REFERENCE_IMAGE_OR_LINK = /^\[([^\]]*)\]:\s+<?([^\s>]+)>?\s*("([^"]*)")?/;
const REFERENCE_IMAGE_R = /^!\[([^\]]*)\] ?\[([^\]]*)\]/;
const REFERENCE_LINK_R = /^\[([^\]]*)\] ?\[([^\]]*)\]/;
const SHOULD_RENDER_AS_BLOCK_R = /(\n|^[-*]\s|^#|^ {2,}|^-{2,}|^>\s)/;
const TAB_R = /\t/g;
const TABLE_TRIM_PIPES = /(^ *\||\| *$)/g;
const TABLE_CENTER_ALIGN = /^ *:-+: *$/;
const TABLE_LEFT_ALIGN = /^ *:-+ *$/;
const TABLE_RIGHT_ALIGN = /^ *-+: *$/;
const some = (regexes, input) => {
	for (let i = 0; i < regexes.length; i++) if (regexes[i].test(input)) return true;
	return false;
};
/**
* Ensure there's at least one more instance of the delimiter later
* in the current sequence.
*/
const LOOKAHEAD = (double) => `(?=[\\s\\S]+?\\1${double ? "\\1" : ""})`;
/**
* For inline formatting, this partial attempts to ignore characters that
* may appear in nested formatting that could prematurely trigger detection
* and therefore miss content that should have been included.
*/
const INLINE_SKIP_R = "((?:\\[.*?\\][([].*?[)\\]]|<.*?>(?:.*?<.*?>)?|`.*?`|\\\\[^\\s]|[\\s\\S])+?)";
/**
* Detect a sequence like **foo** or __foo__. Note that bold has a higher priority
* than emphasized to support nesting of both since they share a delimiter.
*/
const TEXT_BOLD_R = /* @__PURE__ */ new RegExp(`^([*_])\\1${LOOKAHEAD(1)}${INLINE_SKIP_R}\\1\\1(?!\\1)`);
/**
* Detect a sequence like *foo* or _foo_.
*/
const TEXT_EMPHASIZED_R = /* @__PURE__ */ new RegExp(`^([*_])${LOOKAHEAD(0)}${INLINE_SKIP_R}\\1(?!\\1)`);
/**
* Detect a sequence like ==foo==.
*/
const TEXT_MARKED_R = /* @__PURE__ */ new RegExp(`^(==)${LOOKAHEAD(0)}${INLINE_SKIP_R}\\1`);
/**
* Detect a sequence like ~~foo~~.
*/
const TEXT_STRIKETHROUGHED_R = /* @__PURE__ */ new RegExp(`^(~~)${LOOKAHEAD(0)}${INLINE_SKIP_R}\\1`);
/**
* Special case for shortcodes like :big-smile: or :emoji:
*/
const SHORTCODE_R = /^(:[a-zA-Z0-9-_]+:)/;
const TEXT_ESCAPED_R = /^\\([^0-9A-Za-z\s])/;
const UNESCAPE_R = /\\([^0-9A-Za-z\s])/g;
/**
* Always take the first character, then eagerly take text until a double space
* (potential line break) or some markdown-like punctuation is reached.
*/
const TEXT_PLAIN_R = /^[\s\S](?:(?! {2}\n|[0-9]\.|http)[^=*_~\-\n:<`\\[!])*/;
const TRIM_STARTING_NEWLINES = /^\n+/;
const HTML_LEFT_TRIM_AMOUNT_R = /^([ \t]*)/;
const ORDERED = 1;
const UNORDERED = 2;
const LIST_LOOKBEHIND_R = /(?:^|\n)( *)$/;
const ORDERED_LIST_BULLET = "(?:\\d+\\.)";
const UNORDERED_LIST_BULLET = "(?:[*+-])";
const generateListItemPrefix = (type) => {
	return "( *)(" + (type === ORDERED ? ORDERED_LIST_BULLET : UNORDERED_LIST_BULLET) + ") +";
};
const ORDERED_LIST_ITEM_PREFIX = generateListItemPrefix(ORDERED);
const UNORDERED_LIST_ITEM_PREFIX = generateListItemPrefix(UNORDERED);
const generateListItemPrefixRegex = (type) => {
	return /* @__PURE__ */ new RegExp("^" + (type === ORDERED ? ORDERED_LIST_ITEM_PREFIX : UNORDERED_LIST_ITEM_PREFIX));
};
const ORDERED_LIST_ITEM_PREFIX_R = generateListItemPrefixRegex(ORDERED);
const UNORDERED_LIST_ITEM_PREFIX_R = generateListItemPrefixRegex(UNORDERED);
const generateListItemRegex = (type) => {
	return new RegExp("^" + (type === ORDERED ? ORDERED_LIST_ITEM_PREFIX : UNORDERED_LIST_ITEM_PREFIX) + "[^\\n]*(?:\\n(?!\\1" + (type === ORDERED ? ORDERED_LIST_BULLET : UNORDERED_LIST_BULLET) + " )[^\\n]*)*(\\n|$)", "gm");
};
const ORDERED_LIST_ITEM_R = generateListItemRegex(ORDERED);
const UNORDERED_LIST_ITEM_R = generateListItemRegex(UNORDERED);
const generateListRegex = (type) => {
	const bullet = type === ORDERED ? ORDERED_LIST_BULLET : UNORDERED_LIST_BULLET;
	return /* @__PURE__ */ new RegExp("^( *)(" + bullet + ") [\\s\\S]+?(?:\\n{2,}(?! )(?!\\1" + bullet + " (?!" + bullet + " ))\\n*|\\s*\\n*$)");
};
const ORDERED_LIST_R = generateListRegex(ORDERED);
const UNORDERED_LIST_R = generateListRegex(UNORDERED);
const generateListRule = (type, factory) => {
	const ordered = type === ORDERED;
	const LIST_R = ordered ? ORDERED_LIST_R : UNORDERED_LIST_R;
	const LIST_ITEM_R = ordered ? ORDERED_LIST_ITEM_R : UNORDERED_LIST_ITEM_R;
	const LIST_ITEM_PREFIX_R = ordered ? ORDERED_LIST_ITEM_PREFIX_R : UNORDERED_LIST_ITEM_PREFIX_R;
	return {
		_qualify: (source) => LIST_ITEM_PREFIX_R.test(source),
		_match: allowInline((source, state) => {
			const isStartOfLine = LIST_LOOKBEHIND_R.exec(state.prevCapture ?? "");
			const isListAllowed = state.list ?? (!state.inline && !state.simple);
			if (isStartOfLine && isListAllowed) {
				source = isStartOfLine[1] + source;
				return LIST_R.exec(source);
			} else return null;
		}),
		_order: Priority.HIGH,
		_parse(capture, parse, state) {
			const bullet = capture[2];
			const start = ordered ? +bullet : void 0;
			const items = capture[0].replace(BLOCK_END_R, "\n").match(LIST_ITEM_R);
			if (!items) return {
				items: [],
				ordered,
				start
			};
			let lastItemWasAParagraph = false;
			return {
				items: items.map((item, i) => {
					const spaceMatch = LIST_ITEM_PREFIX_R.exec(item);
					if (!spaceMatch) return [];
					const space = spaceMatch[0].length;
					const spaceRegex = new RegExp(`^ {1,${space}}`, "gm");
					const content = item.replace(spaceRegex, "").replace(LIST_ITEM_PREFIX_R, "");
					const isLastItem = i === items.length - 1;
					const thisItemIsAParagraph = content.indexOf("\n\n") !== -1 || isLastItem && lastItemWasAParagraph;
					lastItemWasAParagraph = thisItemIsAParagraph;
					const oldStateInline = state.inline;
					const oldStateList = state.list;
					state.list = true;
					let adjustedContent;
					if (thisItemIsAParagraph) {
						state.inline = false;
						adjustedContent = `${trimEnd(content)}\n\n`;
					} else {
						state.inline = true;
						adjustedContent = trimEnd(content);
					}
					const result = parse(adjustedContent, state);
					state.inline = oldStateInline;
					state.list = oldStateList;
					return result;
				}),
				ordered,
				start
			};
		},
		_render(node, _output, state = {}) {
			const Tag = node.ordered ? "ol" : "ul";
			const props = { key: state.key };
			if (node.ordered && node.start != null) props.start = node.start;
			if (factory) return factory(Tag, props, ...node.items.map((item, i) => factory("li", { key: i }, _output(item, state))));
			return /* @__PURE__ */ jsx(Tag, {
				start: node.type === RuleType.orderedList ? node.start : void 0,
				children: node.items.map((item, i) => {
					return /* @__PURE__ */ jsx("li", { children: _output(item, state) }, `item-${i}-${Math.random()}`);
				})
			}, state.key);
		}
	};
};
const LINK_R = /* @__PURE__ */ new RegExp(`^\\[((?:\\[[^\\[\\]]*(?:\\[[^\\[\\]]*\\][^\\[\\]]*)*\\]|[^\\[\\]])*)\\]\\(\\s*<?((?:\\([^)]*\\)|[^\\s\\\\]|\\\\.)*?)>?(?:\\s+['"]([\\s\\S]*?)['"])?\\s*\\)`);
const IMAGE_R = /^!\[(.*?)\]\( *((?:\([^)]*\)|[^() ])*) *"?([^)"]*)?"?\)/;
const trimEnd = (str) => {
	let end = str.length;
	while (end > 0 && str[end - 1] <= " ") end--;
	return str.slice(0, end);
};
const startsWith = (str, prefix) => {
	return str.startsWith(prefix);
};
const qualifies = (source, state, qualify) => {
	if (Array.isArray(qualify)) {
		for (let i = 0; i < qualify.length; i++) if (startsWith(source, qualify[i])) return true;
		return false;
	}
	return qualify(source, state);
};
/** Remove symmetrical leading and trailing quotes */
const unquote = (str) => {
	const first = str[0];
	if ((first === "\"" || first === "'") && str.length >= 2 && str[str.length - 1] === first) return str.slice(1, -1);
	return str;
};
const slugify = (str) => str.replace(/[ÀÁÂÃÄÅàáâãäåæÆ]/g, "a").replace(/[çÇ]/g, "c").replace(/[ðÐ]/g, "d").replace(/[ÈÉÊËéèêë]/g, "e").replace(/[ÏïÎîÍíÌì]/g, "i").replace(/[Ññ]/g, "n").replace(/[øØœŒÕõÔôÓóÒò]/g, "o").replace(/[ÜüÛûÚúÙù]/g, "u").replace(/[ŸÿÝý]/g, "y").replace(/[^a-z0-9- ]/gi, "").replace(/ /gi, "-").toLowerCase();
const parseTableAlignCapture = (alignCapture) => {
	if (TABLE_RIGHT_ALIGN.test(alignCapture)) return "right";
	else if (TABLE_CENTER_ALIGN.test(alignCapture)) return "center";
	else if (TABLE_LEFT_ALIGN.test(alignCapture)) return "left";
	return "left";
};
const parseTableRow = (source, parse, state, tableOutput) => {
	const start = performance.now();
	const prevInTable = state.inTable;
	state.inTable = true;
	const cells = [[]];
	let acc = "";
	const flush = () => {
		if (!acc) return;
		const cell = cells[cells.length - 1];
		cell.push.apply(cell, parse(acc, state));
		acc = "";
	};
	source.trim().split(/(`[^`]*`|\\\||\|)/).filter(Boolean).forEach((fragment, i, arr) => {
		if (fragment.trim() === "|") {
			flush();
			if (tableOutput) {
				if (i !== 0 && i !== arr.length - 1) cells.push([]);
				return;
			}
		}
		acc += fragment;
	});
	flush();
	state.inTable = prevInTable;
	const duration = performance.now() - start;
	if (duration > durationDelayTrigger) console.log(`parseTableRow: ${duration.toFixed(3)}ms, source length: ${source.length}, cells count: ${cells.length}`);
	return cells;
};
const parseTableAlign = (source) => {
	return source.replace(TABLE_TRIM_PIPES, "").split("|").map(parseTableAlignCapture);
};
const parseTableCells = (source, parse, state) => {
	const start = performance.now();
	const rowsText = source.trim().split("\n");
	const result = rowsText.map((rowText) => parseTableRow(rowText, parse, state, true));
	const duration = performance.now() - start;
	if (duration > durationDelayTrigger) console.log(`parseTableCells: ${duration.toFixed(3)}ms, source length: ${source.length}, rows count: ${rowsText.length}`);
	return result;
};
const parseTable = (capture, parse, state) => {
	/**
	* The table syntax makes some other parsing angry so as a bit of a hack even if alignment and/or cell rows are missing,
	* we'll still run a detected first row through the parser and then just emit a paragraph.
	*/
	state.inline = true;
	const align = capture[2] ? parseTableAlign(capture[2]) : [];
	const cells = capture[3] ? parseTableCells(capture[3], parse, state) : [];
	const header = parseTableRow(capture[1], parse, state, !!cells.length);
	state.inline = false;
	return cells.length ? {
		align,
		cells,
		header,
		type: RuleType.table
	} : {
		children: header.flat(),
		type: RuleType.paragraph
	};
};
const getTableStyle = (node, colIndex) => node.align[colIndex] == null ? {} : { textAlign: node.align[colIndex] };
/** TODO: remove for react 16 */
const normalizeAttributeKey = (key) => {
	if (key.indexOf("-") !== -1 && key.match(HTML_CUSTOM_ATTR_R) === null) key = key.replace(CAPTURE_LETTER_AFTER_HYPHEN, (_, letter) => {
		return letter.toUpperCase();
	});
	return key;
};
const parseStyleAttribute = (styleString) => {
	const start = performance.now();
	const styles = [];
	let buffer = "";
	let inUrl = false;
	let inQuotes = false;
	let quoteChar = "";
	if (!styleString) return styles;
	for (let i = 0; i < styleString.length; i++) {
		const char = styleString[i];
		if ((char === "\"" || char === "'") && !inUrl) {
			if (!inQuotes) {
				inQuotes = true;
				quoteChar = char;
			} else if (char === quoteChar) {
				inQuotes = false;
				quoteChar = "";
			}
		}
		if (char === "(" && buffer.endsWith("url")) inUrl = true;
		else if (char === ")" && inUrl) inUrl = false;
		if (char === ";" && !inQuotes && !inUrl) {
			const declaration$1 = buffer.trim();
			if (declaration$1) {
				const colonIndex = declaration$1.indexOf(":");
				if (colonIndex > 0) {
					const key = declaration$1.slice(0, colonIndex).trim();
					const value = declaration$1.slice(colonIndex + 1).trim();
					styles.push([key, value]);
				}
			}
			buffer = "";
		} else buffer += char;
	}
	const declaration = buffer.trim();
	if (declaration) {
		const colonIndex = declaration.indexOf(":");
		if (colonIndex > 0) {
			const key = declaration.slice(0, colonIndex).trim();
			const value = declaration.slice(colonIndex + 1).trim();
			styles.push([key, value]);
		}
	}
	const duration = performance.now() - start;
	if (duration > durationDelayTrigger) console.log(`parseStyleAttribute: ${duration.toFixed(3)}ms, styleString length: ${styleString.length}, styles count: ${styles.length}`);
	return styles;
};
const trimLeadingWhitespaceOutsideFences = (text, whitespace) => {
	const start = performance.now();
	if (!whitespace) return text;
	const lines = text.split("\n");
	let inFence = false;
	let fenceToken = null;
	const isFenceLine = (line) => line.match(/^\s*(`{3,}|~{3,})/);
	const maybeToggleFence = (line) => {
		const m = isFenceLine(line);
		if (!m) return;
		const token = m[1];
		if (!inFence) {
			inFence = true;
			fenceToken = token;
		} else if (fenceToken && line.includes(fenceToken)) {
			inFence = false;
			fenceToken = null;
		}
	};
	const result = lines.map((line) => {
		if (isFenceLine(line)) {
			const trimmedFenceLine = line.startsWith(whitespace) ? line.slice(whitespace.length) : line;
			maybeToggleFence(line);
			return trimmedFenceLine;
		}
		if (inFence) return line;
		return line.startsWith(whitespace) ? line.slice(whitespace.length) : line;
	}).join("\n");
	const duration = performance.now() - start;
	if (duration > durationDelayTrigger) console.log(`trimLeadingWhitespaceOutsideFences: ${duration.toFixed(3)}ms, text length: ${text.length}, lines count: ${lines.length}`);
	return result;
};
const attributeValueToJSXPropValue = (tag, key, value, sanitizeUrlFn) => {
	if (key === "style") return parseStyleAttribute(value).reduce((styles, [key$1, value$1]) => {
		const camelCasedKey = key$1.replace(/(-[a-z])/g, (substr) => substr[1].toUpperCase());
		styles[camelCasedKey] = sanitizeUrlFn(value$1, tag, key$1);
		return styles;
	}, {});
	else if (ATTRIBUTES_TO_SANITIZE.indexOf(key) !== -1) return sanitizeUrlFn(unescapeString(value), tag, key);
	else if (value.match(INTERPOLATION_R)) value = unescapeString(value.slice(1, value.length - 1));
	if (value === "true") return true;
	else if (value === "false") return false;
	return value;
};
const normalizeWhitespace = (source) => {
	const start = performance.now();
	const result = source.replace(CR_NEWLINE_R, "\n").replace(FORMFEED_R, "").replace(TAB_R, "    ");
	const duration = performance.now() - start;
	if (duration > durationDelayTrigger) console.log(`normalizeWhitespace: ${duration.toFixed(3)}ms, source length: ${source.length}`);
	return result;
};
/**
* Creates a parser for a given set of rules, with the precedence
* specified as a list of rules.
*
* @rules: an object containing
* rule type -> {match, order, parse} objects
* (lower order is higher precedence)
* (Note: `order` is added to defaultRules after creation so that
*  the `order` of defaultRules in the source matches the `order`
*  of defaultRules in terms of `order` fields.)
*
* @returns The resulting parse function, with the following parameters:
*   @source: the input source string to be parsed
*   @state: an optional object to be threaded through parse
*     calls. Allows clients to add stateful operations to
*     parsing, such as keeping track of how many levels deep
*     some nesting is. For an example use-case, see passage-ref
*     parsing in src/widgets/passage/passage-markdown.jsx
*/
const parserFor = (rules) => {
	const start = performance.now();
	var ruleList = Object.keys(rules);
	if (process.env.NODE_ENV !== "production") ruleList.forEach((type) => {
		const order = rules[type]._order;
		if (typeof order !== "number" || !Number.isFinite(order)) console.warn(`intlayer: Invalid order for rule \`${type}\`: ${order}`);
	});
	ruleList.sort((a, b) => {
		return rules[a]._order - rules[b]._order || (a < b ? -1 : 1);
	});
	const nestedParse = (source, state = {}) => {
		const parseStart = performance.now();
		const result = [];
		state.prevCapture = state.prevCapture || "";
		if (source.trim()) while (source) {
			let i = 0;
			while (i < ruleList.length) {
				const ruleType = ruleList[i];
				const rule = rules[ruleType];
				if (rule._qualify && !qualifies(source, state, rule._qualify)) {
					i++;
					continue;
				}
				const matchStart = performance.now();
				const capture = rule._match(source, state);
				const matchDuration = performance.now() - matchStart;
				if (matchDuration > 1) console.log(`${ruleType}._match: ${matchDuration.toFixed(3)}ms, source length: ${source.length}`);
				if (capture?.[0]) {
					source = source.substring(capture[0].length);
					const ruleParseStart = performance.now();
					const parsedAny = rule._parse(capture, nestedParse, state);
					const ruleParseDuration = performance.now() - ruleParseStart;
					if (ruleParseDuration > 1) console.log(`${ruleType}._parse: ${ruleParseDuration.toFixed(3)}ms, capture length: ${capture[0].length}`);
					state.prevCapture += capture[0];
					if (!parsedAny.type) parsedAny.type = ruleType;
					result.push(parsedAny);
					break;
				}
				i++;
			}
		}
		state.prevCapture = "";
		const parseDuration = performance.now() - parseStart;
		if (parseDuration > 1) console.log(`nestedParse: ${parseDuration.toFixed(3)}ms, source length: ${source.length}, result count: ${result.length}`);
		return result;
	};
	const duration = performance.now() - start;
	if (duration > durationDelayTrigger) console.log(`parserFor: ${duration.toFixed(3)}ms, rules count: ${ruleList.length}`);
	return (source, state) => nestedParse(normalizeWhitespace(source), state);
};
/**
* Marks a matcher function as eligible for being run inside an inline context;
* allows us to do a little less work in the nested parser.
*/
const allowInline = (fn) => {
	fn.inline = 1;
	return fn;
};
const inlineRegex = (regex) => allowInline((source, state) => {
	if (state.inline) return regex.exec(source);
	else return null;
});
const simpleInlineRegex = (regex) => allowInline((source, state) => {
	if (state.inline || state.simple) return regex.exec(source);
	else return null;
});
const blockRegex = (regex) => (source, state) => {
	if (state.inline || state.simple) return null;
	else return regex.exec(source);
};
const anyScopeRegex = (regex) => allowInline((source) => regex.exec(source));
const SANITIZE_R = /(javascript|vbscript|data(?!:image)):/i;
const sanitizer = (input) => {
	try {
		const decoded = decodeURIComponent(input).replace(/[^A-Za-z0-9/:]/g, "");
		if (SANITIZE_R.test(decoded)) {
			if (process.env.NODE_ENV !== "production") console.warn("Input contains an unsafe JavaScript/VBScript/data expression, it will not be rendered.", decoded);
			return null;
		}
	} catch (_e) {
		if (process.env.NODE_ENV !== "production") console.warn("Input could not be decoded due to malformed syntax or characters, it will not be rendered.", input);
		return null;
	}
	return input;
};
const unescapeString = (rawString) => rawString ? rawString.replace(UNESCAPE_R, "$1") : rawString;
/**
* Everything inline, including links.
*/
const parseInline = (parse, children, state) => {
	const start = performance.now();
	const isCurrentlyInline = state.inline ?? false;
	const isCurrentlySimple = state.simple ?? false;
	state.inline = true;
	state.simple = true;
	const result = parse(children, state);
	state.inline = isCurrentlyInline;
	state.simple = isCurrentlySimple;
	const duration = performance.now() - start;
	if (duration > durationDelayTrigger) console.log(`parseInline: ${duration.toFixed(3)}ms, children length: ${children.length}, result count: ${result.length}`);
	return result;
};
/**
* Anything inline that isn't a link.
*/
const parseSimpleInline = (parse, children, state) => {
	const start = performance.now();
	const isCurrentlyInline = state.inline ?? false;
	const isCurrentlySimple = state.simple ?? false;
	state.inline = false;
	state.simple = true;
	const result = parse(children, state);
	state.inline = isCurrentlyInline;
	state.simple = isCurrentlySimple;
	const duration = performance.now() - start;
	if (duration > durationDelayTrigger) console.log(`parseSimpleInline: ${duration.toFixed(3)}ms, children length: ${children.length}, result count: ${result.length}`);
	return result;
};
const parseBlock = (parse, children, state = {}) => {
	const start = performance.now();
	const isCurrentlyInline = state.inline || false;
	state.inline = false;
	const normalizedChildren = trimEnd(children);
	const result = parse(/\n\n$/.test(normalizedChildren) === false ? normalizedChildren.endsWith("\n") ? `${normalizedChildren}\n` : `${normalizedChildren}\n\n` : normalizedChildren, state);
	state.inline = isCurrentlyInline;
	const duration = performance.now() - start;
	if (duration > durationDelayTrigger) console.log(`parseBlock: ${duration.toFixed(3)}ms, children length: ${children.length}, result count: ${result.length}`);
	return result;
};
const parseCaptureInline = (capture, parse, state) => {
	return { children: parseInline(parse, capture[2], state) };
};
const captureNothing = () => ({});
const renderNothing = () => null;
const reactFor = (render) => (ast, state = {}) => {
	const start = performance.now();
	const patchedRender = (ast$1, state$1 = {}) => reactFor(render)(ast$1, state$1);
	if (Array.isArray(ast)) {
		const oldKey = state.key;
		const result$1 = [];
		let lastWasString = false;
		for (let i = 0; i < ast.length; i++) {
			state.key = i;
			const nodeOut = patchedRender(ast[i], state);
			const isString = typeof nodeOut === "string";
			if (isString && lastWasString) result$1[result$1.length - 1] = result$1[result$1.length - 1] + nodeOut;
			else if (nodeOut !== null) result$1.push(nodeOut);
			lastWasString = isString;
		}
		state.key = oldKey;
		const duration$1 = performance.now() - start;
		if (duration$1 > durationDelayTrigger) console.log(`reactFor (array): ${duration$1.toFixed(3)}ms, ast length: ${ast.length}`);
		return result$1;
	}
	const result = render(ast, patchedRender, state);
	const duration = performance.now() - start;
	if (duration > durationDelayTrigger) console.log(`reactFor (single): ${duration.toFixed(3)}ms, ast type: ${ast.type}`);
	return result;
};
const createRenderer = (rules, userRender) => (ast, render, state) => {
	const start = performance.now();
	const renderer = rules[ast.type]._render;
	const result = userRender ? userRender(() => renderer?.(ast, render, state), ast, render, state) : renderer?.(ast, render, state);
	const duration = performance.now() - start;
	if (duration > durationDelayTrigger) console.log(`createRenderer: ${duration.toFixed(3)}ms, ast type: ${ast.type}, hasUserRender: ${!!userRender}`);
	return result;
};
const cx = (...args) => args.filter(Boolean).join(" ");
const get = (src, path, fb) => {
	let ptr = src;
	const frags = path.split(".");
	while (frags.length) {
		ptr = ptr[frags[0]];
		if (ptr === void 0) break;
		else frags.shift();
	}
	return ptr ?? fb;
};
const getTag = (tag, overrides) => {
	const override = get(overrides, tag);
	if (!override) return tag;
	return typeof override === "function" || typeof override === "object" && "render" in override ? override : get(overrides, `${tag}.component`, tag);
};
const compiler = (markdown = "", options = {}) => {
	options.overrides = options.overrides ?? {};
	options.namedCodesToUnicode = options.namedCodesToUnicode ? {
		...namedCodesToUnicode,
		...options.namedCodesToUnicode
	} : namedCodesToUnicode;
	const slug = options.slugify ?? slugify;
	const sanitize = options.sanitizer ?? sanitizer;
	const createElementFn = options.createElement ?? createElement;
	const NON_PARAGRAPH_BLOCK_SYNTAXES = [
		BLOCKQUOTE_R,
		CODE_BLOCK_FENCED_R,
		CODE_BLOCK_R,
		options.enforceAtxHeadings ? HEADING_ATX_COMPLIANT_R : HEADING_R,
		HEADING_SETEXT_R,
		NP_TABLE_R,
		ORDERED_LIST_R,
		UNORDERED_LIST_R
	];
	const BLOCK_SYNTAXES = [
		...NON_PARAGRAPH_BLOCK_SYNTAXES,
		PARAGRAPH_R,
		HTML_BLOCK_ELEMENT_R,
		HTML_COMMENT_R,
		HTML_SELF_CLOSING_ELEMENT_R,
		CUSTOM_COMPONENT_R
	];
	const containsBlockSyntax = (input) => {
		const cleaned = input.replace(TRIM_STARTING_NEWLINES, "");
		const slice = cleaned.length > 2048 ? cleaned.slice(0, 2048) : cleaned;
		return some(options.disableParsingRawHTML ? [
			...NON_PARAGRAPH_BLOCK_SYNTAXES,
			PARAGRAPH_R,
			CUSTOM_COMPONENT_R
		] : BLOCK_SYNTAXES, slice);
	};
	const matchParagraph = (source, state) => {
		if (state.inline || state.simple || state.inHTML && source.indexOf("\n\n") === -1 && state.prevCapture?.indexOf("\n\n") === -1) return null;
		let start = 0;
		while (true) {
			const newlineIndex = source.indexOf("\n", start);
			const line = source.slice(start, newlineIndex === -1 ? void 0 : newlineIndex + 1);
			if (some(NON_PARAGRAPH_BLOCK_SYNTAXES, line)) break;
			if (newlineIndex === -1 || !line.trim()) break;
			start = newlineIndex + 1;
		}
		const match = source.slice(0, start);
		const captured = trimEnd(match);
		if (captured === "") return null;
		return [
			match,
			void 0,
			captured
		];
	};
	const h = (tag, props, ...children) => {
		const overrideProps = get(options.overrides ?? {}, `${tag}.props`, {});
		const className = cx(props?.className, overrideProps.className);
		const mergedProps = {
			...props,
			...overrideProps,
			...className && { className }
		};
		return createElementFn(getTag(tag, options.overrides ?? {}), mergedProps, ...children.length === 1 ? [children[0]] : children);
	};
	const compile = (input) => {
		const start = performance.now();
		const result = input.replace(FRONT_MATTER_R, "");
		let inline = false;
		if (options.forceInline) inline = true;
		else if (!options.forceBlock) {
			/**
			* should not contain any block-level markdown like newlines, lists, headings,
			* thematic breaks, blockquotes, tables, etc
			*/
			const leadingNewlinesTrimmed = result.replace(TRIM_STARTING_NEWLINES, "");
			inline = SHOULD_RENDER_AS_BLOCK_R.test(leadingNewlinesTrimmed) === false;
		}
		const arr = emitter(parser(inline ? result : `${trimEnd(result).replace(TRIM_STARTING_NEWLINES, "")}\n\n`, { inline }), { inline });
		while (typeof arr[arr.length - 1] === "string" && !arr[arr.length - 1].trim()) arr.pop();
		if (options.wrapper === null) {
			const duration$1 = performance.now() - start;
			if (duration$1 > durationDelayTrigger) console.log(`compile: ${duration$1.toFixed(3)}ms, input length: ${input.length}, inline: ${inline}`);
			return arr;
		}
		const wrapper = options.wrapper ?? (inline ? "span" : "div");
		let jsx$2;
		if (arr.length > 1 || options.forceWrapper) jsx$2 = arr;
		else if (arr.length === 1) {
			jsx$2 = arr[0];
			if (typeof jsx$2 === "string") {
				const duration$1 = performance.now() - start;
				if (duration$1 > durationDelayTrigger) console.log(`compile: ${duration$1.toFixed(3)}ms, input length: ${input.length}, inline: ${inline}`);
				const spanProps = { key: "outer" };
				if (!inline && options.overrides) {
					const pOverrideProps = get(options.overrides, "p.props", {});
					if (pOverrideProps && typeof pOverrideProps === "object") {
						const mergedClassName = cx(spanProps.className, pOverrideProps.className);
						Object.assign(spanProps, pOverrideProps);
						if (mergedClassName) spanProps.className = mergedClassName;
					}
				}
				return createElementFn("span", spanProps, jsx$2);
			} else {
				const duration$1 = performance.now() - start;
				if (duration$1 > durationDelayTrigger) console.log(`compile: ${duration$1.toFixed(3)}ms, input length: ${input.length}, inline: ${inline}`);
				return jsx$2;
			}
		} else jsx$2 = null;
		const duration = performance.now() - start;
		if (duration > durationDelayTrigger) console.log(`compile: ${duration.toFixed(3)}ms, input length: ${input.length}, inline: ${inline}`);
		return createElementFn(wrapper, { key: "outer" }, jsx$2);
	};
	const attrStringToMap = (tag, str) => {
		const start = performance.now();
		if (!str || !str.trim()) return null;
		const attributes = str.match(ATTR_EXTRACTOR_R);
		if (!attributes) return null;
		const result = attributes.reduce((map, raw) => {
			const delimiterIdx = raw.indexOf("=");
			if (delimiterIdx !== -1) {
				const key = normalizeAttributeKey(raw.slice(0, delimiterIdx)).trim();
				const value = unquote(raw.slice(delimiterIdx + 1).trim());
				const mappedKey = ATTRIBUTE_TO_JSX_PROP_MAP[key] ?? key;
				if (mappedKey === "ref") return map;
				const normalizedValue = attributeValueToJSXPropValue(tag, key, value, sanitize);
				map[mappedKey] = normalizedValue;
				if (typeof normalizedValue === "string" && (HTML_BLOCK_ELEMENT_R.test(normalizedValue) || HTML_SELF_CLOSING_ELEMENT_R.test(normalizedValue))) map[mappedKey] = compile(normalizedValue.trim());
			} else if (raw !== "style") map[ATTRIBUTE_TO_JSX_PROP_MAP[raw] ?? raw] = true;
			return map;
		}, {});
		const duration = performance.now() - start;
		if (duration > durationDelayTrigger) console.log(`attrStringToMap: ${duration.toFixed(3)}ms, str length: ${str.length}, attributes count: ${attributes.length}`);
		return result;
	};
	if (process.env.NODE_ENV !== "production") {
		if (typeof markdown !== "string") throw new Error(`intlayer: the first argument must be
                             a string`);
		if (Object.prototype.toString.call(options.overrides) !== "[object Object]") throw new Error(`intlayer: options.overrides (second argument property) must be
                             undefined or an object literal with shape:
                             {
                                htmltagname: {
                                    component: string|ReactComponent(optional),
                                    props: object(optional)
                                }
                             }`);
	}
	const footnotes = [];
	const refs = {};
	/**
	* each rule's react() output function goes through our custom
	* h() JSX pragma; this allows the override functionality to be
	* automatically applied
	*/
	const rules = {
		[RuleType.blockQuote]: {
			_qualify: [">"],
			_match: blockRegex(BLOCKQUOTE_R),
			_order: Priority.HIGH,
			_parse(capture, parse, state) {
				const start = performance.now();
				const matchAlert = capture[0].replace(BLOCKQUOTE_TRIM_LEFT_MULTILINE_R, "").match(BLOCKQUOTE_ALERT_R);
				const alert = matchAlert?.[1];
				const content = matchAlert?.[2] ?? "";
				const result = {
					alert,
					children: content.indexOf("\n") !== -1 ? parseBlock(parse, content, state) : parseInline(parse, content, state)
				};
				const duration = performance.now() - start;
				if (duration > durationDelayTrigger) console.log(`blockQuote._parse: ${duration.toFixed(3)}ms, capture length: ${capture[0].length}`);
				return result;
			},
			_render(node, _output, state = {}) {
				const start = performance.now();
				const props = { key: state?.key };
				if (node.alert) {
					props.className = `markdown-alert-${slug(node.alert.toLowerCase(), slugify)}`;
					node.children.unshift({
						attrs: {},
						children: [{
							type: RuleType.text,
							text: node.alert
						}],
						noInnerParse: true,
						type: RuleType.htmlBlock,
						tag: "header"
					});
				}
				const result = h("blockquote", props, _output(node.children, state));
				const duration = performance.now() - start;
				if (duration > durationDelayTrigger) console.log(`blockQuote._render: ${duration.toFixed(3)}ms, children count: ${node.children.length}, has alert: ${!!node.alert}`);
				return result;
			}
		},
		[RuleType.breakLine]: {
			_qualify: ["  "],
			_match: anyScopeRegex(BREAK_LINE_R),
			_order: Priority.HIGH,
			_parse: captureNothing,
			_render(_, __, state = {}) {
				return h("br", { key: state.key });
			}
		},
		[RuleType.breakThematic]: {
			_qualify: [
				"--",
				"__",
				"**",
				"- ",
				"* ",
				"_ "
			],
			_match: blockRegex(BREAK_THEMATIC_R),
			_order: Priority.HIGH,
			_parse: captureNothing,
			_render(_, __, state = {}) {
				return h("hr", { key: state.key });
			}
		},
		[RuleType.codeBlock]: {
			_qualify: ["    "],
			_match: blockRegex(CODE_BLOCK_R),
			_order: Priority.MAX,
			_parse(capture) {
				return {
					type: RuleType.codeBlock,
					lang: void 0,
					text: unescapeString(trimEnd(capture[0].replace(/^ {4}/gm, "")))
				};
			},
			_render(node, _output, state = {}) {
				const start = performance.now();
				const attrs = { ...node.attrs ?? {} };
				const langClass = node.lang ? `lang-${node.lang}` : "lang-plaintext";
				attrs.className = attrs.className ? `${attrs.className} ${langClass}` : langClass;
				if (node.lang && !attrs.lang) attrs.lang = node.lang;
				const result = h("pre", { key: state.key }, h("code", attrs, node.text));
				const duration = performance.now() - start;
				if (duration > durationDelayTrigger) console.log(`codeBlock._render: ${duration.toFixed(3)}ms, text length: ${node.text.length}, lang: ${node.lang || "none"}`);
				return result;
			}
		},
		[RuleType.codeFenced]: {
			_qualify: ["```", "~~~"],
			_match: blockRegex(CODE_BLOCK_FENCED_R),
			_order: Priority.MAX,
			_parse(capture) {
				const text = capture[4];
				return {
					attrs: attrStringToMap("code", capture[3] ?? ""),
					lang: capture[2] || void 0,
					text,
					type: RuleType.codeBlock
				};
			}
		},
		[RuleType.codeInline]: {
			_qualify: ["`"],
			_match: simpleInlineRegex(CODE_INLINE_R),
			_order: Priority.LOW,
			_parse(capture) {
				return { text: unescapeString(capture[2]) };
			},
			_render(node, _output, state = {}) {
				const start = performance.now();
				const result = h("code", { key: state.key }, node.text);
				const duration = performance.now() - start;
				if (duration > durationDelayTrigger) console.log(`codeInline._render: ${duration.toFixed(3)}ms, text length: ${node.text.length}`);
				return result;
			}
		},
		[RuleType.footnote]: {
			_qualify: ["[^"],
			_match: blockRegex(FOOTNOTE_R),
			_order: Priority.MAX,
			_parse(capture) {
				footnotes.push({
					footnote: capture[2],
					identifier: capture[1]
				});
				return {};
			},
			_render: renderNothing
		},
		[RuleType.footnoteReference]: {
			_qualify: ["[^"],
			_match: inlineRegex(FOOTNOTE_REFERENCE_R),
			_order: Priority.HIGH,
			_parse(capture) {
				return {
					target: `#${slug(capture[1], slugify)}`,
					text: capture[1]
				};
			},
			_render(node, _output, state = {}) {
				return /* @__PURE__ */ jsx("a", {
					href: sanitize(node.target, "a", "href") ?? void 0,
					children: /* @__PURE__ */ jsx("sup", { children: node.text }, state.key)
				}, state.key);
			}
		},
		[RuleType.gfmTask]: {
			_qualify: ["[ ]", "[x]"],
			_match: inlineRegex(GFM_TASK_R),
			_order: Priority.HIGH,
			_parse(capture) {
				return { completed: capture[1].toLowerCase() === "x" };
			},
			_render(node, _output, state = {}) {
				return h("input", {
					checked: node.completed,
					key: state.key,
					readOnly: true,
					type: "checkbox"
				});
			}
		},
		[RuleType.heading]: {
			_qualify: ["#"],
			_match: blockRegex(options.enforceAtxHeadings ? HEADING_ATX_COMPLIANT_R : HEADING_R),
			_order: Priority.HIGH,
			_parse(capture, parse, state) {
				const start = performance.now();
				const result = {
					children: parseInline(parse, capture[2], state),
					id: slug(capture[2], slugify),
					level: capture[1].length
				};
				const duration = performance.now() - start;
				if (duration > durationDelayTrigger) console.log(`heading._parse: ${duration.toFixed(3)}ms, capture length: ${capture[0].length}, level: ${capture[1].length}`);
				return result;
			},
			_render(node, _output, state = {}) {
				const start = performance.now();
				const result = h(`h${node.level}`, {
					id: node.id,
					key: state.key
				}, _output(node.children, state));
				const duration = performance.now() - start;
				if (duration > durationDelayTrigger) console.log(`heading._render: ${duration.toFixed(3)}ms, level: ${node.level}, children count: ${node.children.length}, id: ${node.id}`);
				return result;
			}
		},
		[RuleType.headingSetext]: {
			_qualify: (source) => {
				const nlIndex = source.indexOf("\n");
				return nlIndex > 0 && nlIndex < source.length - 1 && (source[nlIndex + 1] === "=" || source[nlIndex + 1] === "-");
			},
			_match: blockRegex(HEADING_SETEXT_R),
			_order: Priority.MAX,
			_parse(capture, parse, state) {
				return {
					children: parseInline(parse, capture[1], state),
					level: capture[2] === "=" ? 1 : 2,
					type: RuleType.heading
				};
			}
		},
		[RuleType.htmlBlock]: {
			_qualify: (source) => {
				if (options.disableParsingRawHTML) return false;
				if (source[0] !== "<") return false;
				if (!/^<([a-z][a-z0-9:-]*)\b/.test(source)) return false;
				const tag = source.match(/^<([a-z][a-z0-9:-]*)\b/)?.[1];
				return tag ? source.indexOf(`</${tag}>`) !== -1 : false;
			},
			_match: anyScopeRegex(HTML_BLOCK_ELEMENT_R),
			_order: Priority.HIGH,
			_parse(capture, parse, state) {
				const whitespace = capture[3].match(HTML_LEFT_TRIM_AMOUNT_R)?.[1] ?? "";
				const trimmed = trimLeadingWhitespaceOutsideFences(capture[3], whitespace);
				const parseFunc = containsBlockSyntax(trimmed) ? parseBlock : parseInline;
				const tagName = capture[1].toLowerCase();
				const noInnerParse = DO_NOT_PROCESS_HTML_ELEMENTS.indexOf(tagName) !== -1;
				const tag = (noInnerParse ? tagName : capture[1]).trim();
				const ast = {
					attrs: attrStringToMap(tag, capture[2] ?? ""),
					noInnerParse,
					tag
				};
				state.inAnchor = state.inAnchor || tagName === "a";
				if (noInnerParse) ast.text = capture[3];
				else {
					const prevInHTML = state.inHTML;
					state.inHTML = true;
					ast.children = parseFunc(parse, trimmed, state);
					state.inHTML = prevInHTML;
				}
				/**
				* if another html block is detected within, parse as block,
				* otherwise parse as inline to pick up any further markdown
				*/
				state.inAnchor = false;
				return ast;
			},
			_render(node, _output, state = {}) {
				const start = performance.now();
				const result = h(node.tag, {
					key: state.key,
					...node.attrs ?? {}
				}, node.text ?? (node.children ? _output(node.children, state) : ""));
				const duration = performance.now() - start;
				if (duration > durationDelayTrigger) console.log(`htmlBlock._render: ${duration.toFixed(3)}ms, tag: ${node.tag}, has text: ${!!node.text}, has children: ${!!node.children}`);
				return result;
			}
		},
		[RuleType.htmlSelfClosing]: {
			_qualify: (source) => {
				if (options.disableParsingRawHTML) return false;
				if (source[0] !== "<") return false;
				return /^<([a-zA-Z][a-zA-Z0-9:]*)[\s>/]/.test(source);
			},
			_match: anyScopeRegex(HTML_SELF_CLOSING_ELEMENT_R),
			_order: Priority.HIGH,
			_parse(capture) {
				const tag = capture[1].trim();
				return {
					attrs: attrStringToMap(tag, capture[2] || ""),
					tag
				};
			},
			_render(node, _output, state = {}) {
				const start = performance.now();
				const result = h(node.tag, {
					key: state.key,
					...node.attrs ?? {}
				});
				const duration = performance.now() - start;
				if (duration > durationDelayTrigger) console.log(`htmlSelfClosing._render: ${duration.toFixed(3)}ms, tag: ${node.tag}`);
				return result;
			}
		},
		[RuleType.htmlComment]: {
			_qualify: ["<!--"],
			_match: anyScopeRegex(HTML_COMMENT_R),
			_order: Priority.HIGH,
			_parse() {
				return {};
			},
			_render: renderNothing
		},
		[RuleType.customComponent]: {
			_qualify: (source) => {
				return !!source.match(/^ *<([A-Z][a-zA-Z0-9]*)/);
			},
			_match: blockRegex(CUSTOM_COMPONENT_R),
			_order: Priority.MAX,
			_parse(capture, parse, state) {
				const whitespace = capture[3].match(HTML_LEFT_TRIM_AMOUNT_R)?.[1] ?? "";
				const trimmed = trimLeadingWhitespaceOutsideFences(capture[3], whitespace);
				const parseFunc = containsBlockSyntax(trimmed) ? parseBlock : parseInline;
				const tagName = capture[1];
				const ast = {
					attrs: attrStringToMap(tagName, capture[2] ?? ""),
					noInnerParse: false,
					tag: tagName
				};
				{
					const prevInHTML = state.inHTML;
					state.inHTML = true;
					ast.children = parseFunc(parse, trimmed, state);
					state.inHTML = prevInHTML;
				}
				return ast;
			},
			_render(node, _output, state = {}) {
				const customComponent = getTag(node.tag, options.overrides ?? {});
				if (typeof customComponent === "function") {
					const renderedChildren = node.children ? _output(node.children, state) : null;
					return customComponent({
						key: state.key,
						...node.attrs,
						children: renderedChildren
					});
				}
				return createElementFn(node.tag, {
					key: state.key,
					...node.attrs
				}, node.text ?? (node.children ? _output(node.children, state) : ""));
			}
		},
		[RuleType.image]: {
			_qualify: ["!["],
			_match: simpleInlineRegex(IMAGE_R),
			_order: Priority.HIGH,
			_parse(capture) {
				return {
					alt: unescapeString(capture[1]),
					target: unescapeString(capture[2]),
					title: unescapeString(capture[3])
				};
			},
			_render(node, _output, state = {}) {
				return h("img", {
					key: state.key,
					alt: node.alt ?? void 0,
					title: node.title ?? void 0,
					src: sanitize(node.target, "img", "src") ?? void 0
				});
			}
		},
		[RuleType.link]: {
			_qualify: ["["],
			_match: inlineRegex(LINK_R),
			_order: Priority.LOW,
			_parse(capture, parse, state) {
				return {
					children: parseSimpleInline(parse, capture[1], state),
					target: unescapeString(capture[2]),
					title: unescapeString(capture[3])
				};
			},
			_render(node, output, state = {}) {
				return h("a", {
					key: state.key,
					href: sanitize(node.target, "a", "href") ?? void 0,
					title: node.title
				}, output(node.children, state ?? {}));
			}
		},
		[RuleType.linkAngleBraceStyleDetector]: {
			_qualify: ["<"],
			_match: inlineRegex(LINK_AUTOLINK_R),
			_order: Priority.MAX,
			_parse(capture) {
				let target = capture[1];
				let isEmail = false;
				if (target.indexOf("@") !== -1 && target.indexOf("//") === -1) {
					isEmail = true;
					target = target.replace("mailto:", "");
				}
				return {
					children: [{
						text: target,
						type: RuleType.text
					}],
					target: isEmail ? `mailto:${target}` : target,
					type: RuleType.link
				};
			}
		},
		[RuleType.linkBareUrlDetector]: {
			_qualify: (source, state) => {
				if (state.inAnchor || options.disableAutoLink) return false;
				return startsWith(source, "http://") || startsWith(source, "https://");
			},
			_match: inlineRegex(LINK_AUTOLINK_BARE_URL_R),
			_order: Priority.MAX,
			_parse(capture) {
				return {
					children: [{
						text: capture[1],
						type: RuleType.text
					}],
					target: capture[1],
					title: void 0,
					type: RuleType.link
				};
			}
		},
		[RuleType.orderedList]: generateListRule(ORDERED, (tag, props, ...children) => h(tag, props, ...children)),
		[RuleType.unorderedList]: generateListRule(UNORDERED, (tag, props, ...children) => h(tag, props, ...children)),
		[RuleType.newlineCoalescer]: {
			_qualify: ["\n"],
			_match: blockRegex(CONSECUTIVE_NEWLINE_R),
			_order: Priority.LOW,
			_parse: captureNothing,
			_render() {
				return "\n";
			}
		},
		[RuleType.paragraph]: {
			_match: allowInline(matchParagraph),
			_order: Priority.LOW,
			_parse(capture, parse, state) {
				const start = performance.now();
				const result = parseCaptureInline(capture, parse, state);
				const duration = performance.now() - start;
				if (duration > durationDelayTrigger) console.log(`paragraph._parse: ${duration.toFixed(3)}ms, capture length: ${capture[0].length}`);
				return result;
			},
			_render(node, _output, state = {}) {
				const start = performance.now();
				const result = h("p", { key: state.key }, _output(node.children, state));
				const duration = performance.now() - start;
				if (duration > durationDelayTrigger) console.log(`paragraph._render: ${duration.toFixed(3)}ms, children count: ${node.children.length}`);
				return result;
			}
		},
		[RuleType.ref]: {
			_qualify: ["["],
			_match: inlineRegex(REFERENCE_IMAGE_OR_LINK),
			_order: Priority.MAX,
			_parse(capture) {
				refs[capture[1]] = {
					target: capture[2],
					title: capture[4]
				};
				return {};
			},
			_render: renderNothing
		},
		[RuleType.refImage]: {
			_qualify: ["!["],
			_match: simpleInlineRegex(REFERENCE_IMAGE_R),
			_order: Priority.MAX,
			_parse(capture) {
				return {
					alt: capture[1] ? unescapeString(capture[1]) : void 0,
					ref: capture[2]
				};
			},
			_render(node, _output, state = {}) {
				return refs[node.ref] ? /* @__PURE__ */ jsx("img", {
					alt: node.alt,
					src: sanitize(refs[node.ref].target, "img", "src") ?? void 0,
					title: refs[node.ref].title
				}, state.key) : null;
			}
		},
		[RuleType.refLink]: {
			_qualify: (source) => source[0] === "[" && source.indexOf("](") === -1,
			_match: inlineRegex(REFERENCE_LINK_R),
			_order: Priority.MAX,
			_parse(capture, parse, state) {
				return {
					children: parse(capture[1], state),
					fallbackChildren: capture[0],
					ref: capture[2]
				};
			},
			_render(node, _output, state = {}) {
				return refs[node.ref] ? /* @__PURE__ */ jsx("a", {
					href: sanitize(refs[node.ref].target, "a", "href") ?? void 0,
					title: refs[node.ref].title,
					children: _output(node.children, state)
				}, state.key) : /* @__PURE__ */ jsx("span", { children: node.fallbackChildren }, state.key);
			}
		},
		[RuleType.table]: {
			_qualify: ["|"],
			_match: blockRegex(NP_TABLE_R),
			_order: Priority.HIGH,
			_parse(capture, parse, state) {
				const start = performance.now();
				const result = parseTable(capture, parse, state);
				const duration = performance.now() - start;
				if (duration > durationDelayTrigger) console.log(`table._parse: ${duration.toFixed(3)}ms, capture length: ${capture[0].length}`);
				return result;
			},
			_render(node, _output, state = {}) {
				const start = performance.now();
				const table = node;
				const result = h("table", { key: state.key }, h("thead", {}, h("tr", {}, ...table.header.map((content, i) => h("th", {
					key: i,
					style: getTableStyle(table, i)
				}, _output(content, state))))), h("tbody", {}, ...table.cells.map((row, i) => h("tr", { key: i }, ...row.map((content, c) => h("td", {
					key: c,
					style: getTableStyle(table, c)
				}, _output(content, state)))))));
				const duration = performance.now() - start;
				if (duration > durationDelayTrigger) console.log(`table._render: ${duration.toFixed(3)}ms, header count: ${table.header.length}, rows count: ${table.cells.length}`);
				return result;
			}
		},
		[RuleType.text]: {
			_match: allowInline((source, _state) => {
				if (startsWith(source, ":")) {
					const ret = SHORTCODE_R.exec(source);
					if (ret) return ret;
				}
				return TEXT_PLAIN_R.exec(source);
			}),
			_order: Priority.MIN,
			_parse(capture) {
				const text = capture[0];
				return { text: text.indexOf("&") === -1 ? text : text.replace(HTML_CHAR_CODE_R, (full, inner) => options.namedCodesToUnicode?.[inner] ?? full) };
			},
			_render(node) {
				return node.text;
			}
		},
		[RuleType.textBolded]: {
			_qualify: ["**", "__"],
			_match: simpleInlineRegex(TEXT_BOLD_R),
			_order: Priority.MED,
			_parse(capture, parse, state) {
				return { children: parse(capture[2], state) };
			},
			_render(node, _output, state = {}) {
				const start = performance.now();
				const result = h("strong", { key: state.key }, _output(node.children, state));
				const duration = performance.now() - start;
				if (duration > durationDelayTrigger) console.log(`textBolded._render: ${duration.toFixed(3)}ms, children count: ${node.children.length}`);
				return result;
			}
		},
		[RuleType.textEmphasized]: {
			_qualify: (source) => {
				const char = source[0];
				return (char === "*" || char === "_") && source[1] !== char;
			},
			_match: simpleInlineRegex(TEXT_EMPHASIZED_R),
			_order: Priority.LOW,
			_parse(capture, parse, state) {
				return { children: parse(capture[2], state) };
			},
			_render(node, _output, state = {}) {
				const start = performance.now();
				const result = h("em", { key: state.key }, _output(node.children, state));
				const duration = performance.now() - start;
				if (duration > durationDelayTrigger) console.log(`textEmphasized._render: ${duration.toFixed(3)}ms, children count: ${node.children.length}`);
				return result;
			}
		},
		[RuleType.textEscaped]: {
			_qualify: ["\\"],
			_match: simpleInlineRegex(TEXT_ESCAPED_R),
			_order: Priority.HIGH,
			_parse(capture) {
				return {
					text: capture[1],
					type: RuleType.text
				};
			}
		},
		[RuleType.textMarked]: {
			_qualify: ["=="],
			_match: simpleInlineRegex(TEXT_MARKED_R),
			_order: Priority.LOW,
			_parse: parseCaptureInline,
			_render(node, _output, state = {}) {
				return h("mark", { key: state.key }, _output(node.children, state));
			}
		},
		[RuleType.textStrikethroughed]: {
			_qualify: ["~~"],
			_match: simpleInlineRegex(TEXT_STRIKETHROUGHED_R),
			_order: Priority.LOW,
			_parse: parseCaptureInline,
			_render(node, _output, state = {}) {
				return h("del", { key: state.key }, _output(node.children, state));
			}
		}
	};
	if (options.disableParsingRawHTML === true) {
		delete rules[RuleType.htmlBlock];
		delete rules[RuleType.htmlSelfClosing];
	}
	const parser = parserFor(rules);
	const emitter = reactFor(createRenderer(rules, options.renderRule));
	const jsx$1 = compile(markdown);
	if (footnotes.length) return /* @__PURE__ */ jsxs("div", { children: [jsx$1, /* @__PURE__ */ jsx("footer", { children: footnotes.map((def) => /* @__PURE__ */ jsxs("div", {
		id: slug(def.identifier, slugify),
		children: [def.identifier, emitter(parser(def.footnote, { inline: true }), { inline: true })]
	}, def.identifier)) }, "footer")] });
	return jsx$1;
};
/**
* A simple HOC for easy React use. Feed the markdown content as a direct child
* and the rest is taken care of automatically.
*/
const MarkdownProcessor = ({ children = "", options,...props }) => {
	if (process.env.NODE_ENV !== "production" && typeof children !== "string") console.error("intlayer: <Markdown> component only accepts a single string as a child, received:", children);
	return cloneElement(compiler(children, options), props);
};

//#endregion
export { MarkdownProcessor, RuleType, compiler, sanitizer, slugify };
//# sourceMappingURL=processor.mjs.map