import require$$0 from 'tty'; import require$$1, { inspect } from 'util'; import { webcrypto, createHash } from 'node:crypto'; import { createRequire } from 'node:module'; import path$1, { win32, posix as posix$1, resolve as resolve$2, join, sep as sep$2, normalize as normalize$4 } from 'node:path'; import { fileURLToPath, URL as URL$1, pathToFileURL } from 'node:url'; import process$2, { stdin, stdout } from 'node:process'; import { realpath, readlink, readdir as readdir$1, lstat as lstat$3 } from 'node:fs/promises'; import * as fs$2 from 'node:fs'; import fs__default, { statSync as statSync$1 } from 'node:fs'; import * as nativeFs from 'fs'; import nativeFs__default, { realpathSync as realpathSync$1, readlinkSync, readdirSync as readdirSync$1, readdir as readdir$2, lstatSync, unlinkSync, rmdirSync, chmodSync, statSync, renameSync, rmSync } from 'fs'; import { EventEmitter } from 'node:events'; import Stream, { Transform } from 'node:stream'; import { StringDecoder } from 'node:string_decoder'; import require$$1$1, { resolve as resolve$1, parse as parse$4, basename, sep as sep$1, dirname, normalize as normalize$3, relative, posix as posix$2, join as join$1 } from 'path'; import fsPromises from 'fs/promises'; import { setTimeout as setTimeout$1 } from 'timers/promises'; import { tmpdir } from 'os'; import * as vite from 'vite'; import { normalizePath as normalizePath$1, loadConfigFromFile, createLogger, mergeConfig as mergeConfig$1, searchForWorkspaceRoot, build as build$9, transformWithEsbuild, createServer as createServer$1 } from 'vite'; import k from 'node:readline'; import 'node:child_process'; import require$$1$2 from 'string_decoder'; import zlib from 'node:zlib'; import 'node:stream/promises'; import { isBooleanAttr } from '@vue/shared'; import { isatty } from 'node:tty'; import { inspect as inspect$1, formatWithOptions } from 'node:util'; import http from 'node:http'; import { setImmediate } from 'node:timers'; import * as qs from 'node:querystring'; import require$$0$1 from 'constants'; import require$$0$2 from 'stream'; import require$$5 from 'assert'; import { fileURLToPath as fileURLToPath$1 } from 'url'; import { createRequire as createRequire$1 } from 'module'; import { transformerMetaHighlight, transformerNotationDiff, transformerNotationFocus, transformerNotationHighlight, transformerNotationErrorLevel } from '@shikijs/transformers'; import { createHighlighter, isSpecialLang, guessEmbeddedLanguages } from 'shiki'; import require$$0$3 from 'child_process'; import MiniSearch from 'minisearch'; /** * Default values for dimensions */ const defaultIconDimensions = Object.freeze({ left: 0, top: 0, width: 16, height: 16 }); /** * Default values for transformations */ const defaultIconTransformations = Object.freeze({ rotate: 0, vFlip: false, hFlip: false }); /** * Default values for all optional IconifyIcon properties */ const defaultIconProps = Object.freeze({ ...defaultIconDimensions, ...defaultIconTransformations }); /** * Default values for all properties used in ExtendedIconifyIcon */ const defaultExtendedIconProps = Object.freeze({ ...defaultIconProps, body: "", hidden: false }); /** * Default icon customisations values */ const defaultIconSizeCustomisations = Object.freeze({ width: null, height: null }); const defaultIconCustomisations = Object.freeze({ ...defaultIconSizeCustomisations, ...defaultIconTransformations }); /** * Merge transformations */ function mergeIconTransformations(obj1, obj2) { const result = {}; if (!obj1.hFlip !== !obj2.hFlip) result.hFlip = true; if (!obj1.vFlip !== !obj2.vFlip) result.vFlip = true; const rotate = ((obj1.rotate || 0) + (obj2.rotate || 0)) % 4; if (rotate) result.rotate = rotate; return result; } /** * Merge icon and alias * * Can also be used to merge default values and icon */ function mergeIconData(parent, child) { const result = mergeIconTransformations(parent, child); for (const key in defaultExtendedIconProps) if (key in defaultIconTransformations) { if (key in parent && !(key in result)) result[key] = defaultIconTransformations[key]; } else if (key in child) result[key] = child[key]; else if (key in parent) result[key] = parent[key]; return result; } /** * Make icon square */ /** * Make icon viewBox square */ function makeViewBoxSquare(viewBox) { const [left, top, width, height] = viewBox; if (width !== height) { const max = Math.max(width, height); return [ left - (max - width) / 2, top - (max - height) / 2, max, max ]; } return viewBox; } /** * Resolve icon set icons * * Returns parent icon for each icon */ function getIconsTree(data, names) { const icons = data.icons; const aliases = data.aliases || Object.create(null); const resolved = Object.create(null); function resolve(name) { if (icons[name]) return resolved[name] = []; if (!(name in resolved)) { resolved[name] = null; const parent = aliases[name] && aliases[name].parent; const value = parent && resolve(parent); if (value) resolved[name] = [parent].concat(value); } return resolved[name]; } (names || Object.keys(icons).concat(Object.keys(aliases))).forEach(resolve); return resolved; } /** * Get icon data, using prepared aliases tree */ function internalGetIconData(data, name, tree) { const icons = data.icons; const aliases = data.aliases || Object.create(null); let currentProps = {}; function parse(name$1) { currentProps = mergeIconData(icons[name$1] || aliases[name$1], currentProps); } parse(name); tree.forEach(parse); return mergeIconData(data, currentProps); } /** * Get data for icon */ function getIconData(data, name) { if (data.icons[name]) return internalGetIconData(data, name, []); const tree = getIconsTree(data, [name])[name]; return tree ? internalGetIconData(data, name, tree) : null; } /** * Optional properties */ ({ ...defaultIconDimensions }); /** * Optional properties that must be copied when copying icon set */ Object.keys(defaultIconDimensions).concat(["provider"]); /** * Regular expressions for calculating dimensions */ const unitsSplit = /(-?[0-9.]*[0-9]+[0-9.]*)/g; const unitsTest = /^-?[0-9.]*[0-9]+[0-9.]*$/g; function calculateSize(size, ratio, precision) { if (ratio === 1) return size; precision = precision || 100; if (typeof size === "number") return Math.ceil(size * ratio * precision) / precision; if (typeof size !== "string") return size; const oldParts = size.split(unitsSplit); if (oldParts === null || !oldParts.length) return size; const newParts = []; let code = oldParts.shift(); let isNumber = unitsTest.test(code); while (true) { if (isNumber) { const num = parseFloat(code); if (isNaN(num)) newParts.push(code); else newParts.push(Math.ceil(num * ratio * precision) / precision); } else newParts.push(code); code = oldParts.shift(); if (code === void 0) return newParts.join(""); isNumber = !isNumber; } } function splitSVGDefs(content, tag = "defs") { let defs = ""; const index = content.indexOf("<" + tag); while (index >= 0) { const start = content.indexOf(">", index); const end = content.indexOf("", end); if (endEnd === -1) break; defs += content.slice(start + 1, end).trim(); content = content.slice(0, index).trim() + content.slice(endEnd + 1); } return { defs, content }; } /** * Merge defs and content */ function mergeDefsAndContent(defs, content) { return defs ? "" + defs + "" + content : content; } /** * Wrap SVG content, without wrapping definitions */ function wrapSVGContent(body, start, end) { const split = splitSVGDefs(body); return mergeDefsAndContent(split.defs, start + split.content + end); } /** * Check if value should be unset. Allows multiple keywords */ const isUnsetKeyword = (value) => value === "unset" || value === "undefined" || value === "none"; /** * Get SVG attributes and content from icon + customisations * * Does not generate style to make it compatible with frameworks that use objects for style, such as React. * Instead, it generates 'inline' value. If true, rendering engine should add verticalAlign: -0.125em to icon. * * Customisations should be normalised by platform specific parser. * Result should be converted to by platform specific parser. * Use replaceIDs to generate unique IDs for body. */ function iconToSVG(icon, customisations) { const fullIcon = { ...defaultIconProps, ...icon }; const fullCustomisations = { ...defaultIconCustomisations, ...customisations }; const box = { left: fullIcon.left, top: fullIcon.top, width: fullIcon.width, height: fullIcon.height }; let body = fullIcon.body; [fullIcon, fullCustomisations].forEach((props) => { const transformations = []; const hFlip = props.hFlip; const vFlip = props.vFlip; let rotation = props.rotate; if (hFlip) if (vFlip) rotation += 2; else { transformations.push("translate(" + (box.width + box.left).toString() + " " + (0 - box.top).toString() + ")"); transformations.push("scale(-1 1)"); box.top = box.left = 0; } else if (vFlip) { transformations.push("translate(" + (0 - box.left).toString() + " " + (box.height + box.top).toString() + ")"); transformations.push("scale(1 -1)"); box.top = box.left = 0; } let tempValue; if (rotation < 0) rotation -= Math.floor(rotation / 4) * 4; rotation = rotation % 4; switch (rotation) { case 1: tempValue = box.height / 2 + box.top; transformations.unshift("rotate(90 " + tempValue.toString() + " " + tempValue.toString() + ")"); break; case 2: transformations.unshift("rotate(180 " + (box.width / 2 + box.left).toString() + " " + (box.height / 2 + box.top).toString() + ")"); break; case 3: tempValue = box.width / 2 + box.left; transformations.unshift("rotate(-90 " + tempValue.toString() + " " + tempValue.toString() + ")"); break; } if (rotation % 2 === 1) { if (box.left !== box.top) { tempValue = box.left; box.left = box.top; box.top = tempValue; } if (box.width !== box.height) { tempValue = box.width; box.width = box.height; box.height = tempValue; } } if (transformations.length) body = wrapSVGContent(body, "", ""); }); const customisationsWidth = fullCustomisations.width; const customisationsHeight = fullCustomisations.height; const boxWidth = box.width; const boxHeight = box.height; let width; let height; if (customisationsWidth === null) { height = customisationsHeight === null ? "1em" : customisationsHeight === "auto" ? boxHeight : customisationsHeight; width = calculateSize(height, boxWidth / boxHeight); } else { width = customisationsWidth === "auto" ? boxWidth : customisationsWidth; height = customisationsHeight === null ? calculateSize(width, boxHeight / boxWidth) : customisationsHeight === "auto" ? boxHeight : customisationsHeight; } const attributes = {}; const setAttr = (prop, value) => { if (!isUnsetKeyword(value)) attributes[prop] = value.toString(); }; setAttr("width", width); setAttr("height", height); const viewBox = [ box.left, box.top, boxWidth, boxHeight ]; attributes.viewBox = viewBox.join(" "); return { attributes, viewBox, body }; } /** * IDs usage: * * id="{id}" * xlink:href="#{id}" * url(#{id}) * * From SVG animations: * * begin="0;{id}.end" * begin="{id}.end" * begin="{id}.click" */ /** * Regular expression for finding ids */ /** * New random-ish prefix for ids * * Do not use dash, it cannot be used in SVG 2 animations */ "IconifyId" + Date.now().toString(16) + (Math.random() * 16777216 | 0).toString(16); /** * Encode SVG for use in url() * * Short alternative to encodeURIComponent() that encodes only stuff used in SVG, generating * smaller code. */ function encodeSVGforURL(svg) { return svg.replace(/"/g, "'").replace(/%/g, "%25").replace(/#/g, "%23").replace(//g, "%3E").replace(/\s+/g, " "); } /** * Generate data: URL from SVG */ function svgToData(svg) { return "data:image/svg+xml," + encodeSVGforURL(svg); } /** * Generate url() from SVG */ function svgToURL(svg) { return "url(\"" + svgToData(svg) + "\")"; } /** * Generate */ function iconToHTML(body, attributes) { let renderAttribsHTML = body.indexOf("xlink:") === -1 ? "" : " xmlns:xlink=\"http://www.w3.org/1999/xlink\""; for (const attr in attributes) renderAttribsHTML += " " + attr + "=\"" + attributes[attr] + "\""; return "" + body + ""; } /** * Color keywords */ const colorKeywords = { transparent: { type: "transparent" }, none: { type: "none" }, currentcolor: { type: "current" } }; /** * Add color */ function add(keyword, colors) { const type = "rgb"; const r = colors[0]; const length = colors.length; colorKeywords[keyword] = { type, r, g: length > 1 ? colors[1] : r, b: length > 2 ? colors[2] : r, alpha: length > 3 ? colors[3] : 1 }; } /** * List of base colors. From https://www.w3.org/TR/css3-color/ */ add("silver", [192]); add("gray", [128]); add("white", [255]); add("maroon", [ 128, 0, 0 ]); add("red", [ 255, 0, 0 ]); add("purple", [128, 0]); add("fuchsia", [255, 0]); add("green", [0, 128]); add("lime", [0, 255]); add("olive", [ 128, 128, 0 ]); add("yellow", [ 255, 255, 0 ]); add("navy", [ 0, 0, 128 ]); add("blue", [ 0, 0, 255 ]); add("teal", [ 0, 128, 128 ]); add("aqua", [ 0, 255, 255 ]); /** * List of extended colors. From https://drafts.csswg.org/css-color/ */ add("aliceblue", [ 240, 248, 255 ]); add("antiquewhite", [ 250, 235, 215 ]); add("aqua", [ 0, 255, 255 ]); add("aquamarine", [ 127, 255, 212 ]); add("azure", [ 240, 255, 255 ]); add("beige", [ 245, 245, 220 ]); add("bisque", [ 255, 228, 196 ]); add("black", [0]); add("blanchedalmond", [ 255, 235, 205 ]); add("blue", [ 0, 0, 255 ]); add("blueviolet", [ 138, 43, 226 ]); add("brown", [ 165, 42, 42 ]); add("burlywood", [ 222, 184, 135 ]); add("cadetblue", [ 95, 158, 160 ]); add("chartreuse", [ 127, 255, 0 ]); add("chocolate", [ 210, 105, 30 ]); add("coral", [ 255, 127, 80 ]); add("cornflowerblue", [ 100, 149, 237 ]); add("cornsilk", [ 255, 248, 220 ]); add("crimson", [ 220, 20, 60 ]); add("cyan", [ 0, 255, 255 ]); add("darkblue", [ 0, 0, 139 ]); add("darkcyan", [ 0, 139, 139 ]); add("darkgoldenrod", [ 184, 134, 11 ]); add("darkgray", [169]); add("darkgreen", [0, 100]); add("darkgrey", [169]); add("darkkhaki", [ 189, 183, 107 ]); add("darkmagenta", [139, 0]); add("darkolivegreen", [ 85, 107, 47 ]); add("darkorange", [ 255, 140, 0 ]); add("darkorchid", [ 153, 50, 204 ]); add("darkred", [ 139, 0, 0 ]); add("darksalmon", [ 233, 150, 122 ]); add("darkseagreen", [143, 188]); add("darkslateblue", [ 72, 61, 139 ]); add("darkslategray", [ 47, 79, 79 ]); add("darkslategrey", [ 47, 79, 79 ]); add("darkturquoise", [ 0, 206, 209 ]); add("darkviolet", [ 148, 0, 211 ]); add("deeppink", [ 255, 20, 147 ]); add("deepskyblue", [ 0, 191, 255 ]); add("dimgray", [105]); add("dimgrey", [105]); add("dodgerblue", [ 30, 144, 255 ]); add("firebrick", [ 178, 34, 34 ]); add("floralwhite", [ 255, 250, 240 ]); add("forestgreen", [34, 139]); add("fuchsia", [255, 0]); add("gainsboro", [220]); add("ghostwhite", [ 248, 248, 255 ]); add("gold", [ 255, 215, 0 ]); add("goldenrod", [ 218, 165, 32 ]); add("gray", [128]); add("green", [0, 128]); add("greenyellow", [ 173, 255, 47 ]); add("grey", [128]); add("honeydew", [240, 255]); add("hotpink", [ 255, 105, 180 ]); add("indianred", [ 205, 92, 92 ]); add("indigo", [ 75, 0, 130 ]); add("ivory", [ 255, 255, 240 ]); add("khaki", [ 240, 230, 140 ]); add("lavender", [ 230, 230, 250 ]); add("lavenderblush", [ 255, 240, 245 ]); add("lawngreen", [ 124, 252, 0 ]); add("lemonchiffon", [ 255, 250, 205 ]); add("lightblue", [ 173, 216, 230 ]); add("lightcoral", [ 240, 128, 128 ]); add("lightcyan", [ 224, 255, 255 ]); add("lightgoldenrodyellow", [ 250, 250, 210 ]); add("lightgray", [211]); add("lightgreen", [144, 238]); add("lightgrey", [211]); add("lightpink", [ 255, 182, 193 ]); add("lightsalmon", [ 255, 160, 122 ]); add("lightseagreen", [ 32, 178, 170 ]); add("lightskyblue", [ 135, 206, 250 ]); add("lightslategray", [ 119, 136, 153 ]); add("lightslategrey", [ 119, 136, 153 ]); add("lightsteelblue", [ 176, 196, 222 ]); add("lightyellow", [ 255, 255, 224 ]); add("lime", [0, 255]); add("limegreen", [50, 205]); add("linen", [ 250, 240, 230 ]); add("magenta", [255, 0]); add("maroon", [ 128, 0, 0 ]); add("mediumaquamarine", [ 102, 205, 170 ]); add("mediumblue", [ 0, 0, 205 ]); add("mediumorchid", [ 186, 85, 211 ]); add("mediumpurple", [ 147, 112, 219 ]); add("mediumseagreen", [ 60, 179, 113 ]); add("mediumslateblue", [ 123, 104, 238 ]); add("mediumspringgreen", [ 0, 250, 154 ]); add("mediumturquoise", [ 72, 209, 204 ]); add("mediumvioletred", [ 199, 21, 133 ]); add("midnightblue", [ 25, 25, 112 ]); add("mintcream", [ 245, 255, 250 ]); add("mistyrose", [ 255, 228, 225 ]); add("moccasin", [ 255, 228, 181 ]); add("navajowhite", [ 255, 222, 173 ]); add("navy", [ 0, 0, 128 ]); add("oldlace", [ 253, 245, 230 ]); add("olive", [ 128, 128, 0 ]); add("olivedrab", [ 107, 142, 35 ]); add("orange", [ 255, 165, 0 ]); add("orangered", [ 255, 69, 0 ]); add("orchid", [ 218, 112, 214 ]); add("palegoldenrod", [ 238, 232, 170 ]); add("palegreen", [152, 251]); add("paleturquoise", [ 175, 238, 238 ]); add("palevioletred", [ 219, 112, 147 ]); add("papayawhip", [ 255, 239, 213 ]); add("peachpuff", [ 255, 218, 185 ]); add("peru", [ 205, 133, 63 ]); add("pink", [ 255, 192, 203 ]); add("plum", [221, 160]); add("powderblue", [ 176, 224, 230 ]); add("purple", [128, 0]); add("rebeccapurple", [ 102, 51, 153 ]); add("red", [ 255, 0, 0 ]); add("rosybrown", [ 188, 143, 143 ]); add("royalblue", [ 65, 105, 225 ]); add("saddlebrown", [ 139, 69, 19 ]); add("salmon", [ 250, 128, 114 ]); add("sandybrown", [ 244, 164, 96 ]); add("seagreen", [ 46, 139, 87 ]); add("seashell", [ 255, 245, 238 ]); add("sienna", [ 160, 82, 45 ]); add("silver", [192]); add("skyblue", [ 135, 206, 235 ]); add("slateblue", [ 106, 90, 205 ]); add("slategray", [ 112, 128, 144 ]); add("slategrey", [ 112, 128, 144 ]); add("snow", [ 255, 250, 250 ]); add("springgreen", [ 0, 255, 127 ]); add("steelblue", [ 70, 130, 180 ]); add("tan", [ 210, 180, 140 ]); add("teal", [ 0, 128, 128 ]); add("thistle", [216, 191]); add("tomato", [ 255, 99, 71 ]); add("turquoise", [ 64, 224, 208 ]); add("violet", [238, 130]); add("wheat", [ 245, 222, 179 ]); add("white", [255]); add("whitesmoke", [245]); add("yellow", [ 255, 255, 0 ]); add("yellowgreen", [ 154, 205, 50 ]); /** * Generates common CSS rules for multiple icons, rendered as background/mask */ function getCommonCSSRules(options) { const result = { display: "inline-block", width: "1em", height: "1em" }; const varName = options.varName; if (options.pseudoSelector) result["content"] = "''"; switch (options.mode) { case "background": if (varName) result["background-image"] = "var(--" + varName + ")"; result["background-repeat"] = "no-repeat"; result["background-size"] = "100% 100%"; break; case "mask": result["background-color"] = "currentColor"; if (varName) result["mask-image"] = result["-webkit-mask-image"] = "var(--" + varName + ")"; result["mask-repeat"] = result["-webkit-mask-repeat"] = "no-repeat"; result["mask-size"] = result["-webkit-mask-size"] = "100% 100%"; break; } return result; } /** * Generate CSS rules for one icon, rendered as background/mask * * This function excludes common rules */ function generateItemCSSRules(icon, options) { const result = {}; const varName = options.varName; const buildResult = iconToSVG(icon); let viewBox = buildResult.viewBox; if (viewBox[2] !== viewBox[3]) if (options.forceSquare) viewBox = makeViewBoxSquare(viewBox); else result["width"] = calculateSize("1em", viewBox[2] / viewBox[3]); const svg = iconToHTML(buildResult.body.replace(/currentColor/g, options.color || "black"), { viewBox: `${viewBox[0]} ${viewBox[1]} ${viewBox[2]} ${viewBox[3]}`, width: `${viewBox[2]}`, height: `${viewBox[3]}` }); const url = svgToURL(svg); if (varName) result["--" + varName] = url; else switch (options.mode) { case "background": result["background-image"] = url; break; case "mask": result["mask-image"] = result["-webkit-mask-image"] = url; break; } return result; } const format$1 = { selectorStart: { compressed: "{", compact: " {", expanded: " {" }, selectorEnd: { compressed: "}", compact: "; }\n", expanded: ";\n}\n" }, rule: { compressed: "{key}:", compact: " {key}: ", expanded: "\n {key}: " } }; /** * Format data * * Key is selector, value is list of rules */ function formatCSS(data, mode = "expanded") { const results = []; for (let i = 0; i < data.length; i++) { const { selector, rules } = data[i]; const fullSelector = selector instanceof Array ? selector.join(mode === "compressed" ? "," : ", ") : selector; let entry = fullSelector + format$1.selectorStart[mode]; let firstRule = true; for (const key in rules) { if (!firstRule) entry += ";"; entry += format$1.rule[mode].replace("{key}", key) + rules[key]; firstRule = false; } entry += format$1.selectorEnd[mode]; results.push(entry); } return results.join(mode === "compressed" ? "" : "\n"); } const commonSelector = ".icon--{prefix}"; const iconSelector = ".icon--{prefix}--{name}"; const defaultSelectors = { commonSelector, iconSelector, overrideSelector: commonSelector + iconSelector }; /** * Get data for getIconsCSS() */ function getIconsCSSData(iconSet, names, options = {}) { const css = []; const errors = []; const palette = options.color ? true : void 0; let mode = options.mode || typeof palette === "boolean" && (palette ? "background" : "mask"); if (!mode) { for (let i = 0; i < names.length; i++) { const name = names[i]; const icon = getIconData(iconSet, name); if (icon) { const body = options.customise ? options.customise(icon.body, name) : icon.body; mode = body.includes("currentColor") ? "mask" : "background"; break; } } if (!mode) { mode = "mask"; errors.push("/* cannot detect icon mode: not set in options and icon set is missing info, rendering as " + mode + " */"); } } let varName = options.varName; if (varName === void 0 && mode === "mask") varName = "svg"; const newOptions = { ...options, mode, varName }; const { commonSelector: commonSelector$1, iconSelector: iconSelector$1, overrideSelector } = newOptions.iconSelector ? newOptions : defaultSelectors; const iconSelectorWithPrefix = iconSelector$1.replace(/{prefix}/g, iconSet.prefix); const commonRules = { ...options.rules, ...getCommonCSSRules(newOptions) }; const hasCommonRules = commonSelector$1 && commonSelector$1 !== iconSelector$1; const commonSelectors = /* @__PURE__ */ new Set(); if (hasCommonRules) css.push({ selector: commonSelector$1.replace(/{prefix}/g, iconSet.prefix), rules: commonRules }); for (let i = 0; i < names.length; i++) { const name = names[i]; const iconData = getIconData(iconSet, name); if (!iconData) { errors.push("/* Could not find icon: " + name + " */"); continue; } const body = options.customise ? options.customise(iconData.body, name) : iconData.body; const rules = generateItemCSSRules({ ...defaultIconProps, ...iconData, body }, newOptions); let requiresOverride = false; if (hasCommonRules && overrideSelector) { for (const key in rules) if (key in commonRules) requiresOverride = true; } const selector = (requiresOverride && overrideSelector ? overrideSelector.replace(/{prefix}/g, iconSet.prefix) : iconSelectorWithPrefix).replace(/{name}/g, name); css.push({ selector, rules }); if (!hasCommonRules) commonSelectors.add(selector); } const result = { css, errors }; if (!hasCommonRules && commonSelectors.size) { const selector = Array.from(commonSelectors).join(newOptions.format === "compressed" ? "," : ", "); result.common = { selector, rules: commonRules }; } return result; } /** * Get CSS for icons as background/mask */ function getIconsCSS(iconSet, names, options = {}) { const { css, errors, common } = getIconsCSSData(iconSet, names, options); if (common) if (css.length === 1 && css[0].selector === common.selector) css[0].rules = { ...common.rules, ...css[0].rules }; else css.unshift(common); return formatCSS(css, options.format) + (errors.length ? "\n" + errors.join("\n") + "\n" : ""); } var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; function getDefaultExportFromCjs (x) { return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; } var src$1 = {exports: {}}; var browser = {exports: {}}; /** * Helpers. */ var ms; var hasRequiredMs; function requireMs () { if (hasRequiredMs) return ms; hasRequiredMs = 1; var s = 1000; var m = s * 60; var h = m * 60; var d = h * 24; var w = d * 7; var y = d * 365.25; /** * Parse or format the given `val`. * * Options: * * - `long` verbose formatting [false] * * @param {String|Number} val * @param {Object} [options] * @throws {Error} throw an error if val is not a non-empty string or a number * @return {String|Number} * @api public */ ms = function (val, options) { options = options || {}; var type = typeof val; if (type === 'string' && val.length > 0) { return parse(val); } else if (type === 'number' && isFinite(val)) { return options.long ? fmtLong(val) : fmtShort(val); } throw new Error( 'val is not a non-empty string or a valid number. val=' + JSON.stringify(val) ); }; /** * Parse the given `str` and return milliseconds. * * @param {String} str * @return {Number} * @api private */ function parse(str) { str = String(str); if (str.length > 100) { return; } var match = /^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec( str ); if (!match) { return; } var n = parseFloat(match[1]); var type = (match[2] || 'ms').toLowerCase(); switch (type) { case 'years': case 'year': case 'yrs': case 'yr': case 'y': return n * y; case 'weeks': case 'week': case 'w': return n * w; case 'days': case 'day': case 'd': return n * d; case 'hours': case 'hour': case 'hrs': case 'hr': case 'h': return n * h; case 'minutes': case 'minute': case 'mins': case 'min': case 'm': return n * m; case 'seconds': case 'second': case 'secs': case 'sec': case 's': return n * s; case 'milliseconds': case 'millisecond': case 'msecs': case 'msec': case 'ms': return n; default: return undefined; } } /** * Short format for `ms`. * * @param {Number} ms * @return {String} * @api private */ function fmtShort(ms) { var msAbs = Math.abs(ms); if (msAbs >= d) { return Math.round(ms / d) + 'd'; } if (msAbs >= h) { return Math.round(ms / h) + 'h'; } if (msAbs >= m) { return Math.round(ms / m) + 'm'; } if (msAbs >= s) { return Math.round(ms / s) + 's'; } return ms + 'ms'; } /** * Long format for `ms`. * * @param {Number} ms * @return {String} * @api private */ function fmtLong(ms) { var msAbs = Math.abs(ms); if (msAbs >= d) { return plural(ms, msAbs, d, 'day'); } if (msAbs >= h) { return plural(ms, msAbs, h, 'hour'); } if (msAbs >= m) { return plural(ms, msAbs, m, 'minute'); } if (msAbs >= s) { return plural(ms, msAbs, s, 'second'); } return ms + ' ms'; } /** * Pluralization helper. */ function plural(ms, msAbs, n, name) { var isPlural = msAbs >= n * 1.5; return Math.round(ms / n) + ' ' + name + (isPlural ? 's' : ''); } return ms; } var common$1; var hasRequiredCommon$1; function requireCommon$1 () { if (hasRequiredCommon$1) return common$1; hasRequiredCommon$1 = 1; /** * This is the common logic for both the Node.js and web browser * implementations of `debug()`. */ function setup(env) { createDebug.debug = createDebug; createDebug.default = createDebug; createDebug.coerce = coerce; createDebug.disable = disable; createDebug.enable = enable; createDebug.enabled = enabled; createDebug.humanize = requireMs(); createDebug.destroy = destroy; Object.keys(env).forEach(key => { createDebug[key] = env[key]; }); /** * The currently active debug mode names, and names to skip. */ createDebug.names = []; createDebug.skips = []; /** * Map of special "%n" handling functions, for the debug "format" argument. * * Valid key names are a single, lower or upper-case letter, i.e. "n" and "N". */ createDebug.formatters = {}; /** * Selects a color for a debug namespace * @param {String} namespace The namespace string for the debug instance to be colored * @return {Number|String} An ANSI color code for the given namespace * @api private */ function selectColor(namespace) { let hash = 0; for (let i = 0; i < namespace.length; i++) { hash = ((hash << 5) - hash) + namespace.charCodeAt(i); hash |= 0; // Convert to 32bit integer } return createDebug.colors[Math.abs(hash) % createDebug.colors.length]; } createDebug.selectColor = selectColor; /** * Create a debugger with the given `namespace`. * * @param {String} namespace * @return {Function} * @api public */ function createDebug(namespace) { let prevTime; let enableOverride = null; let namespacesCache; let enabledCache; function debug(...args) { // Disabled? if (!debug.enabled) { return; } const self = debug; // Set `diff` timestamp const curr = Number(new Date()); const ms = curr - (prevTime || curr); self.diff = ms; self.prev = prevTime; self.curr = curr; prevTime = curr; args[0] = createDebug.coerce(args[0]); if (typeof args[0] !== 'string') { // Anything else let's inspect with %O args.unshift('%O'); } // Apply any `formatters` transformations let index = 0; args[0] = args[0].replace(/%([a-zA-Z%])/g, (match, format) => { // If we encounter an escaped % then don't increase the array index if (match === '%%') { return '%'; } index++; const formatter = createDebug.formatters[format]; if (typeof formatter === 'function') { const val = args[index]; match = formatter.call(self, val); // Now we need to remove `args[index]` since it's inlined in the `format` args.splice(index, 1); index--; } return match; }); // Apply env-specific formatting (colors, etc.) createDebug.formatArgs.call(self, args); const logFn = self.log || createDebug.log; logFn.apply(self, args); } debug.namespace = namespace; debug.useColors = createDebug.useColors(); debug.color = createDebug.selectColor(namespace); debug.extend = extend; debug.destroy = createDebug.destroy; // XXX Temporary. Will be removed in the next major release. Object.defineProperty(debug, 'enabled', { enumerable: true, configurable: false, get: () => { if (enableOverride !== null) { return enableOverride; } if (namespacesCache !== createDebug.namespaces) { namespacesCache = createDebug.namespaces; enabledCache = createDebug.enabled(namespace); } return enabledCache; }, set: v => { enableOverride = v; } }); // Env-specific initialization logic for debug instances if (typeof createDebug.init === 'function') { createDebug.init(debug); } return debug; } function extend(namespace, delimiter) { const newDebug = createDebug(this.namespace + (typeof delimiter === 'undefined' ? ':' : delimiter) + namespace); newDebug.log = this.log; return newDebug; } /** * Enables a debug mode by namespaces. This can include modes * separated by a colon and wildcards. * * @param {String} namespaces * @api public */ function enable(namespaces) { createDebug.save(namespaces); createDebug.namespaces = namespaces; createDebug.names = []; createDebug.skips = []; const split = (typeof namespaces === 'string' ? namespaces : '') .trim() .replace(/\s+/g, ',') .split(',') .filter(Boolean); for (const ns of split) { if (ns[0] === '-') { createDebug.skips.push(ns.slice(1)); } else { createDebug.names.push(ns); } } } /** * Checks if the given string matches a namespace template, honoring * asterisks as wildcards. * * @param {String} search * @param {String} template * @return {Boolean} */ function matchesTemplate(search, template) { let searchIndex = 0; let templateIndex = 0; let starIndex = -1; let matchIndex = 0; while (searchIndex < search.length) { if (templateIndex < template.length && (template[templateIndex] === search[searchIndex] || template[templateIndex] === '*')) { // Match character or proceed with wildcard if (template[templateIndex] === '*') { starIndex = templateIndex; matchIndex = searchIndex; templateIndex++; // Skip the '*' } else { searchIndex++; templateIndex++; } } else if (starIndex !== -1) { // eslint-disable-line no-negated-condition // Backtrack to the last '*' and try to match more characters templateIndex = starIndex + 1; matchIndex++; searchIndex = matchIndex; } else { return false; // No match } } // Handle trailing '*' in template while (templateIndex < template.length && template[templateIndex] === '*') { templateIndex++; } return templateIndex === template.length; } /** * Disable debug output. * * @return {String} namespaces * @api public */ function disable() { const namespaces = [ ...createDebug.names, ...createDebug.skips.map(namespace => '-' + namespace) ].join(','); createDebug.enable(''); return namespaces; } /** * Returns true if the given mode name is enabled, false otherwise. * * @param {String} name * @return {Boolean} * @api public */ function enabled(name) { for (const skip of createDebug.skips) { if (matchesTemplate(name, skip)) { return false; } } for (const ns of createDebug.names) { if (matchesTemplate(name, ns)) { return true; } } return false; } /** * Coerce `val`. * * @param {Mixed} val * @return {Mixed} * @api private */ function coerce(val) { if (val instanceof Error) { return val.stack || val.message; } return val; } /** * XXX DO NOT USE. This is a temporary stub function. * XXX It WILL be removed in the next major release. */ function destroy() { console.warn('Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.'); } createDebug.enable(createDebug.load()); return createDebug; } common$1 = setup; return common$1; } /* eslint-env browser */ var hasRequiredBrowser; function requireBrowser () { if (hasRequiredBrowser) return browser.exports; hasRequiredBrowser = 1; (function (module, exports$1) { /** * This is the web browser implementation of `debug()`. */ exports$1.formatArgs = formatArgs; exports$1.save = save; exports$1.load = load; exports$1.useColors = useColors; exports$1.storage = localstorage(); exports$1.destroy = (() => { let warned = false; return () => { if (!warned) { warned = true; console.warn('Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.'); } }; })(); /** * Colors. */ exports$1.colors = [ '#0000CC', '#0000FF', '#0033CC', '#0033FF', '#0066CC', '#0066FF', '#0099CC', '#0099FF', '#00CC00', '#00CC33', '#00CC66', '#00CC99', '#00CCCC', '#00CCFF', '#3300CC', '#3300FF', '#3333CC', '#3333FF', '#3366CC', '#3366FF', '#3399CC', '#3399FF', '#33CC00', '#33CC33', '#33CC66', '#33CC99', '#33CCCC', '#33CCFF', '#6600CC', '#6600FF', '#6633CC', '#6633FF', '#66CC00', '#66CC33', '#9900CC', '#9900FF', '#9933CC', '#9933FF', '#99CC00', '#99CC33', '#CC0000', '#CC0033', '#CC0066', '#CC0099', '#CC00CC', '#CC00FF', '#CC3300', '#CC3333', '#CC3366', '#CC3399', '#CC33CC', '#CC33FF', '#CC6600', '#CC6633', '#CC9900', '#CC9933', '#CCCC00', '#CCCC33', '#FF0000', '#FF0033', '#FF0066', '#FF0099', '#FF00CC', '#FF00FF', '#FF3300', '#FF3333', '#FF3366', '#FF3399', '#FF33CC', '#FF33FF', '#FF6600', '#FF6633', '#FF9900', '#FF9933', '#FFCC00', '#FFCC33' ]; /** * Currently only WebKit-based Web Inspectors, Firefox >= v31, * and the Firebug extension (any Firefox version) are known * to support "%c" CSS customizations. * * TODO: add a `localStorage` variable to explicitly enable/disable colors */ // eslint-disable-next-line complexity function useColors() { // NB: In an Electron preload script, document will be defined but not fully // initialized. Since we know we're in Chrome, we'll just detect this case // explicitly if (typeof window !== 'undefined' && window.process && (window.process.type === 'renderer' || window.process.__nwjs)) { return true; } // Is webkit? http://stackoverflow.com/a/16459606/376773 // document is undefined in react-native: https://github.com/facebook/react-native/pull/1632 // eslint-disable-next-line no-return-assign return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) || // Is firebug? http://stackoverflow.com/a/398120/376773 (typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) || // Is firefox >= v31? // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages (typeof navigator !== 'undefined' && undefined) || // Double check webkit in userAgent just in case we are in a worker (typeof navigator !== 'undefined' && undefined); } /** * Colorize log arguments if enabled. * * @api public */ function formatArgs(args) { args[0] = (this.useColors ? '%c' : '') + this.namespace + (this.useColors ? ' %c' : ' ') + args[0] + (this.useColors ? '%c ' : ' ') + '+' + module.exports.humanize(this.diff); if (!this.useColors) { return; } const c = 'color: ' + this.color; args.splice(1, 0, c, 'color: inherit'); // The final "%c" is somewhat tricky, because there could be other // arguments passed either before or after the %c, so we need to // figure out the correct index to insert the CSS into let index = 0; let lastC = 0; args[0].replace(/%[a-zA-Z%]/g, match => { if (match === '%%') { return; } index++; if (match === '%c') { // We only are interested in the *last* %c // (the user may have provided their own) lastC = index; } }); args.splice(lastC, 0, c); } /** * Invokes `console.debug()` when available. * No-op when `console.debug` is not a "function". * If `console.debug` is not available, falls back * to `console.log`. * * @api public */ exports$1.log = console.debug || console.log || (() => {}); /** * Save `namespaces`. * * @param {String} namespaces * @api private */ function save(namespaces) { try { if (namespaces) { exports$1.storage.setItem('debug', namespaces); } else { exports$1.storage.removeItem('debug'); } } catch (error) { // Swallow // XXX (@Qix-) should we be logging these? } } /** * Load `namespaces`. * * @return {String} returns the previously persisted debug modes * @api private */ function load() { let r; try { r = exports$1.storage.getItem('debug') || exports$1.storage.getItem('DEBUG') ; } catch (error) { // Swallow // XXX (@Qix-) should we be logging these? } // If debug isn't set in LS, and we're in Electron, try to load $DEBUG if (!r && typeof process !== 'undefined' && 'env' in process) { r = process.env.DEBUG; } return r; } /** * Localstorage attempts to return the localstorage. * * This is necessary because safari throws * when a user disables cookies/localstorage * and you attempt to access it. * * @return {LocalStorage} * @api private */ function localstorage() { try { // TVMLKit (Apple TV JS Runtime) does not have a window object, just localStorage in the global context // The Browser also has localStorage in the global context. return localStorage; } catch (error) { // Swallow // XXX (@Qix-) should we be logging these? } } module.exports = requireCommon$1()(exports$1); const {formatters} = module.exports; /** * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default. */ formatters.j = function (v) { try { return JSON.stringify(v); } catch (error) { return '[UnexpectedJSONParseError]: ' + error.message; } }; } (browser, browser.exports)); return browser.exports; } var node$2 = {exports: {}}; /** * Module dependencies. */ var hasRequiredNode$2; function requireNode$2 () { if (hasRequiredNode$2) return node$2.exports; hasRequiredNode$2 = 1; (function (module, exports$1) { const tty = require$$0; const util = require$$1; /** * This is the Node.js implementation of `debug()`. */ exports$1.init = init; exports$1.log = log; exports$1.formatArgs = formatArgs; exports$1.save = save; exports$1.load = load; exports$1.useColors = useColors; exports$1.destroy = util.deprecate( () => {}, 'Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.' ); /** * Colors. */ exports$1.colors = [6, 2, 3, 4, 5, 1]; try { // Optional dependency (as in, doesn't need to be installed, NOT like optionalDependencies in package.json) // eslint-disable-next-line import/no-extraneous-dependencies const supportsColor = require('supports-color'); if (supportsColor && (supportsColor.stderr || supportsColor).level >= 2) { exports$1.colors = [ 20, 21, 26, 27, 32, 33, 38, 39, 40, 41, 42, 43, 44, 45, 56, 57, 62, 63, 68, 69, 74, 75, 76, 77, 78, 79, 80, 81, 92, 93, 98, 99, 112, 113, 128, 129, 134, 135, 148, 149, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 178, 179, 184, 185, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 214, 215, 220, 221 ]; } } catch (error) { // Swallow - we only care if `supports-color` is available; it doesn't have to be. } /** * Build up the default `inspectOpts` object from the environment variables. * * $ DEBUG_COLORS=no DEBUG_DEPTH=10 DEBUG_SHOW_HIDDEN=enabled node script.js */ exports$1.inspectOpts = Object.keys(process.env).filter(key => { return /^debug_/i.test(key); }).reduce((obj, key) => { // Camel-case const prop = key .substring(6) .toLowerCase() .replace(/_([a-z])/g, (_, k) => { return k.toUpperCase(); }); // Coerce string value into JS value let val = process.env[key]; if (/^(yes|on|true|enabled)$/i.test(val)) { val = true; } else if (/^(no|off|false|disabled)$/i.test(val)) { val = false; } else if (val === 'null') { val = null; } else { val = Number(val); } obj[prop] = val; return obj; }, {}); /** * Is stdout a TTY? Colored output is enabled when `true`. */ function useColors() { return 'colors' in exports$1.inspectOpts ? Boolean(exports$1.inspectOpts.colors) : tty.isatty(process.stderr.fd); } /** * Adds ANSI color escape codes if enabled. * * @api public */ function formatArgs(args) { const {namespace: name, useColors} = this; if (useColors) { const c = this.color; const colorCode = '\u001B[3' + (c < 8 ? c : '8;5;' + c); const prefix = ` ${colorCode};1m${name} \u001B[0m`; args[0] = prefix + args[0].split('\n').join('\n' + prefix); args.push(colorCode + 'm+' + module.exports.humanize(this.diff) + '\u001B[0m'); } else { args[0] = getDate() + name + ' ' + args[0]; } } function getDate() { if (exports$1.inspectOpts.hideDate) { return ''; } return new Date().toISOString() + ' '; } /** * Invokes `util.formatWithOptions()` with the specified arguments and writes to stderr. */ function log(...args) { return process.stderr.write(util.formatWithOptions(exports$1.inspectOpts, ...args) + '\n'); } /** * Save `namespaces`. * * @param {String} namespaces * @api private */ function save(namespaces) { if (namespaces) { process.env.DEBUG = namespaces; } else { // If you set a process.env field to null or undefined, it gets cast to the // string 'null' or 'undefined'. Just delete instead. delete process.env.DEBUG; } } /** * Load `namespaces`. * * @return {String} returns the previously persisted debug modes * @api private */ function load() { return process.env.DEBUG; } /** * Init logic for `debug` instances. * * Create a new `inspectOpts` object in case `useColors` is set * differently for a particular `debug` instance. */ function init(debug) { debug.inspectOpts = {}; const keys = Object.keys(exports$1.inspectOpts); for (let i = 0; i < keys.length; i++) { debug.inspectOpts[keys[i]] = exports$1.inspectOpts[keys[i]]; } } module.exports = requireCommon$1()(exports$1); const {formatters} = module.exports; /** * Map %o to `util.inspect()`, all on a single line. */ formatters.o = function (v) { this.inspectOpts.colors = this.useColors; return util.inspect(v, this.inspectOpts) .split('\n') .map(str => str.trim()) .join(' '); }; /** * Map %O to `util.inspect()`, allowing multiple lines if needed. */ formatters.O = function (v) { this.inspectOpts.colors = this.useColors; return util.inspect(v, this.inspectOpts); }; } (node$2, node$2.exports)); return node$2.exports; } /** * Detect Electron renderer / nwjs process, which is node, but we should * treat as a browser. */ var hasRequiredSrc$1; function requireSrc$1 () { if (hasRequiredSrc$1) return src$1.exports; hasRequiredSrc$1 = 1; if (typeof process === 'undefined' || process.type === 'renderer' || process.browser === true || process.__nwjs) { src$1.exports = requireBrowser(); } else { src$1.exports = requireNode$2(); } return src$1.exports; } var srcExports$1 = requireSrc$1(); var createDebugger = /*@__PURE__*/getDefaultExportFromCjs(srcExports$1); createDebugger("@iconify-loader:custom"); createDebugger("@iconify-loader:icon"); var fs$1 = {}; var universalify = {}; var hasRequiredUniversalify; function requireUniversalify () { if (hasRequiredUniversalify) return universalify; hasRequiredUniversalify = 1; universalify.fromCallback = function (fn) { return Object.defineProperty(function (...args) { if (typeof args[args.length - 1] === 'function') fn.apply(this, args); else { return new Promise((resolve, reject) => { args.push((err, res) => (err != null) ? reject(err) : resolve(res)); fn.apply(this, args); }) } }, 'name', { value: fn.name }) }; universalify.fromPromise = function (fn) { return Object.defineProperty(function (...args) { const cb = args[args.length - 1]; if (typeof cb !== 'function') return fn.apply(this, args) else { args.pop(); fn.apply(this, args).then(r => cb(null, r), cb); } }, 'name', { value: fn.name }) }; return universalify; } var polyfills; var hasRequiredPolyfills; function requirePolyfills () { if (hasRequiredPolyfills) return polyfills; hasRequiredPolyfills = 1; var constants = require$$0$1; var origCwd = process.cwd; var cwd = null; var platform = process.env.GRACEFUL_FS_PLATFORM || process.platform; process.cwd = function() { if (!cwd) cwd = origCwd.call(process); return cwd }; try { process.cwd(); } catch (er) {} // This check is needed until node.js 12 is required if (typeof process.chdir === 'function') { var chdir = process.chdir; process.chdir = function (d) { cwd = null; chdir.call(process, d); }; if (Object.setPrototypeOf) Object.setPrototypeOf(process.chdir, chdir); } polyfills = patch; function patch (fs) { // (re-)implement some things that are known busted or missing. // lchmod, broken prior to 0.6.2 // back-port the fix here. if (constants.hasOwnProperty('O_SYMLINK') && process.version.match(/^v0\.6\.[0-2]|^v0\.5\./)) { patchLchmod(fs); } // lutimes implementation, or no-op if (!fs.lutimes) { patchLutimes(fs); } // https://github.com/isaacs/node-graceful-fs/issues/4 // Chown should not fail on einval or eperm if non-root. // It should not fail on enosys ever, as this just indicates // that a fs doesn't support the intended operation. fs.chown = chownFix(fs.chown); fs.fchown = chownFix(fs.fchown); fs.lchown = chownFix(fs.lchown); fs.chmod = chmodFix(fs.chmod); fs.fchmod = chmodFix(fs.fchmod); fs.lchmod = chmodFix(fs.lchmod); fs.chownSync = chownFixSync(fs.chownSync); fs.fchownSync = chownFixSync(fs.fchownSync); fs.lchownSync = chownFixSync(fs.lchownSync); fs.chmodSync = chmodFixSync(fs.chmodSync); fs.fchmodSync = chmodFixSync(fs.fchmodSync); fs.lchmodSync = chmodFixSync(fs.lchmodSync); fs.stat = statFix(fs.stat); fs.fstat = statFix(fs.fstat); fs.lstat = statFix(fs.lstat); fs.statSync = statFixSync(fs.statSync); fs.fstatSync = statFixSync(fs.fstatSync); fs.lstatSync = statFixSync(fs.lstatSync); // if lchmod/lchown do not exist, then make them no-ops if (fs.chmod && !fs.lchmod) { fs.lchmod = function (path, mode, cb) { if (cb) process.nextTick(cb); }; fs.lchmodSync = function () {}; } if (fs.chown && !fs.lchown) { fs.lchown = function (path, uid, gid, cb) { if (cb) process.nextTick(cb); }; fs.lchownSync = function () {}; } // on Windows, A/V software can lock the directory, causing this // to fail with an EACCES or EPERM if the directory contains newly // created files. Try again on failure, for up to 60 seconds. // Set the timeout this long because some Windows Anti-Virus, such as Parity // bit9, may lock files for up to a minute, causing npm package install // failures. Also, take care to yield the scheduler. Windows scheduling gives // CPU to a busy looping process, which can cause the program causing the lock // contention to be starved of CPU by node, so the contention doesn't resolve. if (platform === "win32") { fs.rename = typeof fs.rename !== 'function' ? fs.rename : (function (fs$rename) { function rename (from, to, cb) { var start = Date.now(); var backoff = 0; fs$rename(from, to, function CB (er) { if (er && (er.code === "EACCES" || er.code === "EPERM" || er.code === "EBUSY") && Date.now() - start < 60000) { setTimeout(function() { fs.stat(to, function (stater, st) { if (stater && stater.code === "ENOENT") fs$rename(from, to, CB); else cb(er); }); }, backoff); if (backoff < 100) backoff += 10; return; } if (cb) cb(er); }); } if (Object.setPrototypeOf) Object.setPrototypeOf(rename, fs$rename); return rename })(fs.rename); } // if read() returns EAGAIN, then just try it again. fs.read = typeof fs.read !== 'function' ? fs.read : (function (fs$read) { function read (fd, buffer, offset, length, position, callback_) { var callback; if (callback_ && typeof callback_ === 'function') { var eagCounter = 0; callback = function (er, _, __) { if (er && er.code === 'EAGAIN' && eagCounter < 10) { eagCounter ++; return fs$read.call(fs, fd, buffer, offset, length, position, callback) } callback_.apply(this, arguments); }; } return fs$read.call(fs, fd, buffer, offset, length, position, callback) } // This ensures `util.promisify` works as it does for native `fs.read`. if (Object.setPrototypeOf) Object.setPrototypeOf(read, fs$read); return read })(fs.read); fs.readSync = typeof fs.readSync !== 'function' ? fs.readSync : (function (fs$readSync) { return function (fd, buffer, offset, length, position) { var eagCounter = 0; while (true) { try { return fs$readSync.call(fs, fd, buffer, offset, length, position) } catch (er) { if (er.code === 'EAGAIN' && eagCounter < 10) { eagCounter ++; continue } throw er } } }})(fs.readSync); function patchLchmod (fs) { fs.lchmod = function (path, mode, callback) { fs.open( path , constants.O_WRONLY | constants.O_SYMLINK , mode , function (err, fd) { if (err) { if (callback) callback(err); return } // prefer to return the chmod error, if one occurs, // but still try to close, and report closing errors if they occur. fs.fchmod(fd, mode, function (err) { fs.close(fd, function(err2) { if (callback) callback(err || err2); }); }); }); }; fs.lchmodSync = function (path, mode) { var fd = fs.openSync(path, constants.O_WRONLY | constants.O_SYMLINK, mode); // prefer to return the chmod error, if one occurs, // but still try to close, and report closing errors if they occur. var threw = true; var ret; try { ret = fs.fchmodSync(fd, mode); threw = false; } finally { if (threw) { try { fs.closeSync(fd); } catch (er) {} } else { fs.closeSync(fd); } } return ret }; } function patchLutimes (fs) { if (constants.hasOwnProperty("O_SYMLINK") && fs.futimes) { fs.lutimes = function (path, at, mt, cb) { fs.open(path, constants.O_SYMLINK, function (er, fd) { if (er) { if (cb) cb(er); return } fs.futimes(fd, at, mt, function (er) { fs.close(fd, function (er2) { if (cb) cb(er || er2); }); }); }); }; fs.lutimesSync = function (path, at, mt) { var fd = fs.openSync(path, constants.O_SYMLINK); var ret; var threw = true; try { ret = fs.futimesSync(fd, at, mt); threw = false; } finally { if (threw) { try { fs.closeSync(fd); } catch (er) {} } else { fs.closeSync(fd); } } return ret }; } else if (fs.futimes) { fs.lutimes = function (_a, _b, _c, cb) { if (cb) process.nextTick(cb); }; fs.lutimesSync = function () {}; } } function chmodFix (orig) { if (!orig) return orig return function (target, mode, cb) { return orig.call(fs, target, mode, function (er) { if (chownErOk(er)) er = null; if (cb) cb.apply(this, arguments); }) } } function chmodFixSync (orig) { if (!orig) return orig return function (target, mode) { try { return orig.call(fs, target, mode) } catch (er) { if (!chownErOk(er)) throw er } } } function chownFix (orig) { if (!orig) return orig return function (target, uid, gid, cb) { return orig.call(fs, target, uid, gid, function (er) { if (chownErOk(er)) er = null; if (cb) cb.apply(this, arguments); }) } } function chownFixSync (orig) { if (!orig) return orig return function (target, uid, gid) { try { return orig.call(fs, target, uid, gid) } catch (er) { if (!chownErOk(er)) throw er } } } function statFix (orig) { if (!orig) return orig // Older versions of Node erroneously returned signed integers for // uid + gid. return function (target, options, cb) { if (typeof options === 'function') { cb = options; options = null; } function callback (er, stats) { if (stats) { if (stats.uid < 0) stats.uid += 0x100000000; if (stats.gid < 0) stats.gid += 0x100000000; } if (cb) cb.apply(this, arguments); } return options ? orig.call(fs, target, options, callback) : orig.call(fs, target, callback) } } function statFixSync (orig) { if (!orig) return orig // Older versions of Node erroneously returned signed integers for // uid + gid. return function (target, options) { var stats = options ? orig.call(fs, target, options) : orig.call(fs, target); if (stats) { if (stats.uid < 0) stats.uid += 0x100000000; if (stats.gid < 0) stats.gid += 0x100000000; } return stats; } } // ENOSYS means that the fs doesn't support the op. Just ignore // that, because it doesn't matter. // // if there's no getuid, or if getuid() is something other // than 0, and the error is EINVAL or EPERM, then just ignore // it. // // This specific case is a silent failure in cp, install, tar, // and most other unix tools that manage permissions. // // When running as root, or if other types of errors are // encountered, then it's strict. function chownErOk (er) { if (!er) return true if (er.code === "ENOSYS") return true var nonroot = !process.getuid || process.getuid() !== 0; if (nonroot) { if (er.code === "EINVAL" || er.code === "EPERM") return true } return false } } return polyfills; } var legacyStreams; var hasRequiredLegacyStreams; function requireLegacyStreams () { if (hasRequiredLegacyStreams) return legacyStreams; hasRequiredLegacyStreams = 1; var Stream = require$$0$2.Stream; legacyStreams = legacy; function legacy (fs) { return { ReadStream: ReadStream, WriteStream: WriteStream } function ReadStream (path, options) { if (!(this instanceof ReadStream)) return new ReadStream(path, options); Stream.call(this); var self = this; this.path = path; this.fd = null; this.readable = true; this.paused = false; this.flags = 'r'; this.mode = 438; /*=0666*/ this.bufferSize = 64 * 1024; options = options || {}; // Mixin options into this var keys = Object.keys(options); for (var index = 0, length = keys.length; index < length; index++) { var key = keys[index]; this[key] = options[key]; } if (this.encoding) this.setEncoding(this.encoding); if (this.start !== undefined) { if ('number' !== typeof this.start) { throw TypeError('start must be a Number'); } if (this.end === undefined) { this.end = Infinity; } else if ('number' !== typeof this.end) { throw TypeError('end must be a Number'); } if (this.start > this.end) { throw new Error('start must be <= end'); } this.pos = this.start; } if (this.fd !== null) { process.nextTick(function() { self._read(); }); return; } fs.open(this.path, this.flags, this.mode, function (err, fd) { if (err) { self.emit('error', err); self.readable = false; return; } self.fd = fd; self.emit('open', fd); self._read(); }); } function WriteStream (path, options) { if (!(this instanceof WriteStream)) return new WriteStream(path, options); Stream.call(this); this.path = path; this.fd = null; this.writable = true; this.flags = 'w'; this.encoding = 'binary'; this.mode = 438; /*=0666*/ this.bytesWritten = 0; options = options || {}; // Mixin options into this var keys = Object.keys(options); for (var index = 0, length = keys.length; index < length; index++) { var key = keys[index]; this[key] = options[key]; } if (this.start !== undefined) { if ('number' !== typeof this.start) { throw TypeError('start must be a Number'); } if (this.start < 0) { throw new Error('start must be >= zero'); } this.pos = this.start; } this.busy = false; this._queue = []; if (this.fd === null) { this._open = fs.open; this._queue.push([this._open, this.path, this.flags, this.mode, undefined]); this.flush(); } } } return legacyStreams; } var clone_1; var hasRequiredClone; function requireClone () { if (hasRequiredClone) return clone_1; hasRequiredClone = 1; clone_1 = clone; var getPrototypeOf = Object.getPrototypeOf || function (obj) { return obj.__proto__ }; function clone (obj) { if (obj === null || typeof obj !== 'object') return obj if (obj instanceof Object) var copy = { __proto__: getPrototypeOf(obj) }; else var copy = Object.create(null); Object.getOwnPropertyNames(obj).forEach(function (key) { Object.defineProperty(copy, key, Object.getOwnPropertyDescriptor(obj, key)); }); return copy } return clone_1; } var gracefulFs; var hasRequiredGracefulFs; function requireGracefulFs () { if (hasRequiredGracefulFs) return gracefulFs; hasRequiredGracefulFs = 1; var fs = nativeFs__default; var polyfills = requirePolyfills(); var legacy = requireLegacyStreams(); var clone = requireClone(); var util = require$$1; /* istanbul ignore next - node 0.x polyfill */ var gracefulQueue; var previousSymbol; /* istanbul ignore else - node 0.x polyfill */ if (typeof Symbol === 'function' && typeof Symbol.for === 'function') { gracefulQueue = Symbol.for('graceful-fs.queue'); // This is used in testing by future versions previousSymbol = Symbol.for('graceful-fs.previous'); } else { gracefulQueue = '___graceful-fs.queue'; previousSymbol = '___graceful-fs.previous'; } function noop () {} function publishQueue(context, queue) { Object.defineProperty(context, gracefulQueue, { get: function() { return queue } }); } var debug = noop; if (util.debuglog) debug = util.debuglog('gfs4'); else if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || '')) debug = function() { var m = util.format.apply(util, arguments); m = 'GFS4: ' + m.split(/\n/).join('\nGFS4: '); console.error(m); }; // Once time initialization if (!fs[gracefulQueue]) { // This queue can be shared by multiple loaded instances var queue = commonjsGlobal[gracefulQueue] || []; publishQueue(fs, queue); // Patch fs.close/closeSync to shared queue version, because we need // to retry() whenever a close happens *anywhere* in the program. // This is essential when multiple graceful-fs instances are // in play at the same time. fs.close = (function (fs$close) { function close (fd, cb) { return fs$close.call(fs, fd, function (err) { // This function uses the graceful-fs shared queue if (!err) { resetQueue(); } if (typeof cb === 'function') cb.apply(this, arguments); }) } Object.defineProperty(close, previousSymbol, { value: fs$close }); return close })(fs.close); fs.closeSync = (function (fs$closeSync) { function closeSync (fd) { // This function uses the graceful-fs shared queue fs$closeSync.apply(fs, arguments); resetQueue(); } Object.defineProperty(closeSync, previousSymbol, { value: fs$closeSync }); return closeSync })(fs.closeSync); if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || '')) { process.on('exit', function() { debug(fs[gracefulQueue]); require$$5.equal(fs[gracefulQueue].length, 0); }); } } if (!commonjsGlobal[gracefulQueue]) { publishQueue(commonjsGlobal, fs[gracefulQueue]); } gracefulFs = patch(clone(fs)); if (process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH && !fs.__patched) { gracefulFs = patch(fs); fs.__patched = true; } function patch (fs) { // Everything that references the open() function needs to be in here polyfills(fs); fs.gracefulify = patch; fs.createReadStream = createReadStream; fs.createWriteStream = createWriteStream; var fs$readFile = fs.readFile; fs.readFile = readFile; function readFile (path, options, cb) { if (typeof options === 'function') cb = options, options = null; return go$readFile(path, options, cb) function go$readFile (path, options, cb, startTime) { return fs$readFile(path, options, function (err) { if (err && (err.code === 'EMFILE' || err.code === 'ENFILE')) enqueue([go$readFile, [path, options, cb], err, startTime || Date.now(), Date.now()]); else { if (typeof cb === 'function') cb.apply(this, arguments); } }) } } var fs$writeFile = fs.writeFile; fs.writeFile = writeFile; function writeFile (path, data, options, cb) { if (typeof options === 'function') cb = options, options = null; return go$writeFile(path, data, options, cb) function go$writeFile (path, data, options, cb, startTime) { return fs$writeFile(path, data, options, function (err) { if (err && (err.code === 'EMFILE' || err.code === 'ENFILE')) enqueue([go$writeFile, [path, data, options, cb], err, startTime || Date.now(), Date.now()]); else { if (typeof cb === 'function') cb.apply(this, arguments); } }) } } var fs$appendFile = fs.appendFile; if (fs$appendFile) fs.appendFile = appendFile; function appendFile (path, data, options, cb) { if (typeof options === 'function') cb = options, options = null; return go$appendFile(path, data, options, cb) function go$appendFile (path, data, options, cb, startTime) { return fs$appendFile(path, data, options, function (err) { if (err && (err.code === 'EMFILE' || err.code === 'ENFILE')) enqueue([go$appendFile, [path, data, options, cb], err, startTime || Date.now(), Date.now()]); else { if (typeof cb === 'function') cb.apply(this, arguments); } }) } } var fs$copyFile = fs.copyFile; if (fs$copyFile) fs.copyFile = copyFile; function copyFile (src, dest, flags, cb) { if (typeof flags === 'function') { cb = flags; flags = 0; } return go$copyFile(src, dest, flags, cb) function go$copyFile (src, dest, flags, cb, startTime) { return fs$copyFile(src, dest, flags, function (err) { if (err && (err.code === 'EMFILE' || err.code === 'ENFILE')) enqueue([go$copyFile, [src, dest, flags, cb], err, startTime || Date.now(), Date.now()]); else { if (typeof cb === 'function') cb.apply(this, arguments); } }) } } var fs$readdir = fs.readdir; fs.readdir = readdir; var noReaddirOptionVersions = /^v[0-5]\./; function readdir (path, options, cb) { if (typeof options === 'function') cb = options, options = null; var go$readdir = noReaddirOptionVersions.test(process.version) ? function go$readdir (path, options, cb, startTime) { return fs$readdir(path, fs$readdirCallback( path, options, cb, startTime )) } : function go$readdir (path, options, cb, startTime) { return fs$readdir(path, options, fs$readdirCallback( path, options, cb, startTime )) }; return go$readdir(path, options, cb) function fs$readdirCallback (path, options, cb, startTime) { return function (err, files) { if (err && (err.code === 'EMFILE' || err.code === 'ENFILE')) enqueue([ go$readdir, [path, options, cb], err, startTime || Date.now(), Date.now() ]); else { if (files && files.sort) files.sort(); if (typeof cb === 'function') cb.call(this, err, files); } } } } if (process.version.substr(0, 4) === 'v0.8') { var legStreams = legacy(fs); ReadStream = legStreams.ReadStream; WriteStream = legStreams.WriteStream; } var fs$ReadStream = fs.ReadStream; if (fs$ReadStream) { ReadStream.prototype = Object.create(fs$ReadStream.prototype); ReadStream.prototype.open = ReadStream$open; } var fs$WriteStream = fs.WriteStream; if (fs$WriteStream) { WriteStream.prototype = Object.create(fs$WriteStream.prototype); WriteStream.prototype.open = WriteStream$open; } Object.defineProperty(fs, 'ReadStream', { get: function () { return ReadStream }, set: function (val) { ReadStream = val; }, enumerable: true, configurable: true }); Object.defineProperty(fs, 'WriteStream', { get: function () { return WriteStream }, set: function (val) { WriteStream = val; }, enumerable: true, configurable: true }); // legacy names var FileReadStream = ReadStream; Object.defineProperty(fs, 'FileReadStream', { get: function () { return FileReadStream }, set: function (val) { FileReadStream = val; }, enumerable: true, configurable: true }); var FileWriteStream = WriteStream; Object.defineProperty(fs, 'FileWriteStream', { get: function () { return FileWriteStream }, set: function (val) { FileWriteStream = val; }, enumerable: true, configurable: true }); function ReadStream (path, options) { if (this instanceof ReadStream) return fs$ReadStream.apply(this, arguments), this else return ReadStream.apply(Object.create(ReadStream.prototype), arguments) } function ReadStream$open () { var that = this; open(that.path, that.flags, that.mode, function (err, fd) { if (err) { if (that.autoClose) that.destroy(); that.emit('error', err); } else { that.fd = fd; that.emit('open', fd); that.read(); } }); } function WriteStream (path, options) { if (this instanceof WriteStream) return fs$WriteStream.apply(this, arguments), this else return WriteStream.apply(Object.create(WriteStream.prototype), arguments) } function WriteStream$open () { var that = this; open(that.path, that.flags, that.mode, function (err, fd) { if (err) { that.destroy(); that.emit('error', err); } else { that.fd = fd; that.emit('open', fd); } }); } function createReadStream (path, options) { return new fs.ReadStream(path, options) } function createWriteStream (path, options) { return new fs.WriteStream(path, options) } var fs$open = fs.open; fs.open = open; function open (path, flags, mode, cb) { if (typeof mode === 'function') cb = mode, mode = null; return go$open(path, flags, mode, cb) function go$open (path, flags, mode, cb, startTime) { return fs$open(path, flags, mode, function (err, fd) { if (err && (err.code === 'EMFILE' || err.code === 'ENFILE')) enqueue([go$open, [path, flags, mode, cb], err, startTime || Date.now(), Date.now()]); else { if (typeof cb === 'function') cb.apply(this, arguments); } }) } } return fs } function enqueue (elem) { debug('ENQUEUE', elem[0].name, elem[1]); fs[gracefulQueue].push(elem); retry(); } // keep track of the timeout between retry() calls var retryTimer; // reset the startTime and lastTime to now // this resets the start of the 60 second overall timeout as well as the // delay between attempts so that we'll retry these jobs sooner function resetQueue () { var now = Date.now(); for (var i = 0; i < fs[gracefulQueue].length; ++i) { // entries that are only a length of 2 are from an older version, don't // bother modifying those since they'll be retried anyway. if (fs[gracefulQueue][i].length > 2) { fs[gracefulQueue][i][3] = now; // startTime fs[gracefulQueue][i][4] = now; // lastTime } } // call retry to make sure we're actively processing the queue retry(); } function retry () { // clear the timer and remove it to help prevent unintended concurrency clearTimeout(retryTimer); retryTimer = undefined; if (fs[gracefulQueue].length === 0) return var elem = fs[gracefulQueue].shift(); var fn = elem[0]; var args = elem[1]; // these items may be unset if they were added by an older graceful-fs var err = elem[2]; var startTime = elem[3]; var lastTime = elem[4]; // if we don't have a startTime we have no way of knowing if we've waited // long enough, so go ahead and retry this item now if (startTime === undefined) { debug('RETRY', fn.name, args); fn.apply(null, args); } else if (Date.now() - startTime >= 60000) { // it's been more than 60 seconds total, bail now debug('TIMEOUT', fn.name, args); var cb = args.pop(); if (typeof cb === 'function') cb.call(null, err); } else { // the amount of time between the last attempt and right now var sinceAttempt = Date.now() - lastTime; // the amount of time between when we first tried, and when we last tried // rounded up to at least 1 var sinceStart = Math.max(lastTime - startTime, 1); // backoff. wait longer than the total time we've been retrying, but only // up to a maximum of 100ms var desiredDelay = Math.min(sinceStart * 1.2, 100); // it's been long enough since the last retry, do it again if (sinceAttempt >= desiredDelay) { debug('RETRY', fn.name, args); fn.apply(null, args.concat([startTime])); } else { // if we can't do this job yet, push it to the end of the queue // and let the next iteration check again fs[gracefulQueue].push(elem); } } // schedule our next run if one isn't already scheduled if (retryTimer === undefined) { retryTimer = setTimeout(retry, 0); } } return gracefulFs; } var hasRequiredFs; function requireFs () { if (hasRequiredFs) return fs$1; hasRequiredFs = 1; (function (exports$1) { // This is adapted from https://github.com/normalize/mz // Copyright (c) 2014-2016 Jonathan Ong me@jongleberry.com and Contributors const u = requireUniversalify().fromCallback; const fs = requireGracefulFs(); const api = [ 'access', 'appendFile', 'chmod', 'chown', 'close', 'copyFile', 'cp', 'fchmod', 'fchown', 'fdatasync', 'fstat', 'fsync', 'ftruncate', 'futimes', 'glob', 'lchmod', 'lchown', 'lutimes', 'link', 'lstat', 'mkdir', 'mkdtemp', 'open', 'opendir', 'readdir', 'readFile', 'readlink', 'realpath', 'rename', 'rm', 'rmdir', 'stat', 'statfs', 'symlink', 'truncate', 'unlink', 'utimes', 'writeFile' ].filter(key => { // Some commands are not available on some systems. Ex: // fs.cp was added in Node.js v16.7.0 // fs.statfs was added in Node v19.6.0, v18.15.0 // fs.glob was added in Node.js v22.0.0 // fs.lchown is not available on at least some Linux return typeof fs[key] === 'function' }); // Export cloned fs: Object.assign(exports$1, fs); // Universalify async methods: api.forEach(method => { exports$1[method] = u(fs[method]); }); // We differ from mz/fs in that we still ship the old, broken, fs.exists() // since we are a drop-in replacement for the native module exports$1.exists = function (filename, callback) { if (typeof callback === 'function') { return fs.exists(filename, callback) } return new Promise(resolve => { return fs.exists(filename, resolve) }) }; // fs.read(), fs.write(), fs.readv(), & fs.writev() need special treatment due to multiple callback args exports$1.read = function (fd, buffer, offset, length, position, callback) { if (typeof callback === 'function') { return fs.read(fd, buffer, offset, length, position, callback) } return new Promise((resolve, reject) => { fs.read(fd, buffer, offset, length, position, (err, bytesRead, buffer) => { if (err) return reject(err) resolve({ bytesRead, buffer }); }); }) }; // Function signature can be // fs.write(fd, buffer[, offset[, length[, position]]], callback) // OR // fs.write(fd, string[, position[, encoding]], callback) // We need to handle both cases, so we use ...args exports$1.write = function (fd, buffer, ...args) { if (typeof args[args.length - 1] === 'function') { return fs.write(fd, buffer, ...args) } return new Promise((resolve, reject) => { fs.write(fd, buffer, ...args, (err, bytesWritten, buffer) => { if (err) return reject(err) resolve({ bytesWritten, buffer }); }); }) }; // Function signature is // s.readv(fd, buffers[, position], callback) // We need to handle the optional arg, so we use ...args exports$1.readv = function (fd, buffers, ...args) { if (typeof args[args.length - 1] === 'function') { return fs.readv(fd, buffers, ...args) } return new Promise((resolve, reject) => { fs.readv(fd, buffers, ...args, (err, bytesRead, buffers) => { if (err) return reject(err) resolve({ bytesRead, buffers }); }); }) }; // Function signature is // s.writev(fd, buffers[, position], callback) // We need to handle the optional arg, so we use ...args exports$1.writev = function (fd, buffers, ...args) { if (typeof args[args.length - 1] === 'function') { return fs.writev(fd, buffers, ...args) } return new Promise((resolve, reject) => { fs.writev(fd, buffers, ...args, (err, bytesWritten, buffers) => { if (err) return reject(err) resolve({ bytesWritten, buffers }); }); }) }; // fs.realpath.native sometimes not available if fs is monkey-patched if (typeof fs.realpath.native === 'function') { exports$1.realpath.native = u(fs.realpath.native); } else { process.emitWarning( 'fs.realpath.native is not a function. Is fs being monkey-patched?', 'Warning', 'fs-extra-WARN0003' ); } } (fs$1)); return fs$1; } var makeDir = {}; var utils$5 = {}; var hasRequiredUtils$4; function requireUtils$4 () { if (hasRequiredUtils$4) return utils$5; hasRequiredUtils$4 = 1; const path = require$$1$1; // https://github.com/nodejs/node/issues/8987 // https://github.com/libuv/libuv/pull/1088 utils$5.checkPath = function checkPath (pth) { if (process.platform === 'win32') { const pathHasInvalidWinCharacters = /[<>:"|?*]/.test(pth.replace(path.parse(pth).root, '')); if (pathHasInvalidWinCharacters) { const error = new Error(`Path contains invalid characters: ${pth}`); error.code = 'EINVAL'; throw error } } }; return utils$5; } var hasRequiredMakeDir; function requireMakeDir () { if (hasRequiredMakeDir) return makeDir; hasRequiredMakeDir = 1; const fs = requireFs(); const { checkPath } = requireUtils$4(); const getMode = options => { const defaults = { mode: 0o777 }; if (typeof options === 'number') return options return ({ ...defaults, ...options }).mode }; makeDir.makeDir = async (dir, options) => { checkPath(dir); return fs.mkdir(dir, { mode: getMode(options), recursive: true }) }; makeDir.makeDirSync = (dir, options) => { checkPath(dir); return fs.mkdirSync(dir, { mode: getMode(options), recursive: true }) }; return makeDir; } var mkdirs; var hasRequiredMkdirs; function requireMkdirs () { if (hasRequiredMkdirs) return mkdirs; hasRequiredMkdirs = 1; const u = requireUniversalify().fromPromise; const { makeDir: _makeDir, makeDirSync } = requireMakeDir(); const makeDir = u(_makeDir); mkdirs = { mkdirs: makeDir, mkdirsSync: makeDirSync, // alias mkdirp: makeDir, mkdirpSync: makeDirSync, ensureDir: makeDir, ensureDirSync: makeDirSync }; return mkdirs; } var pathExists_1; var hasRequiredPathExists; function requirePathExists () { if (hasRequiredPathExists) return pathExists_1; hasRequiredPathExists = 1; const u = requireUniversalify().fromPromise; const fs = requireFs(); function pathExists (path) { return fs.access(path).then(() => true).catch(() => false) } pathExists_1 = { pathExists: u(pathExists), pathExistsSync: fs.existsSync }; return pathExists_1; } var utimes; var hasRequiredUtimes; function requireUtimes () { if (hasRequiredUtimes) return utimes; hasRequiredUtimes = 1; const fs = requireFs(); const u = requireUniversalify().fromPromise; async function utimesMillis (path, atime, mtime) { // if (!HAS_MILLIS_RES) return fs.utimes(path, atime, mtime, callback) const fd = await fs.open(path, 'r+'); let closeErr = null; try { await fs.futimes(fd, atime, mtime); } finally { try { await fs.close(fd); } catch (e) { closeErr = e; } } if (closeErr) { throw closeErr } } function utimesMillisSync (path, atime, mtime) { const fd = fs.openSync(path, 'r+'); fs.futimesSync(fd, atime, mtime); return fs.closeSync(fd) } utimes = { utimesMillis: u(utimesMillis), utimesMillisSync }; return utimes; } var stat$1; var hasRequiredStat; function requireStat () { if (hasRequiredStat) return stat$1; hasRequiredStat = 1; const fs = requireFs(); const path = require$$1$1; const u = requireUniversalify().fromPromise; function getStats (src, dest, opts) { const statFunc = opts.dereference ? (file) => fs.stat(file, { bigint: true }) : (file) => fs.lstat(file, { bigint: true }); return Promise.all([ statFunc(src), statFunc(dest).catch(err => { if (err.code === 'ENOENT') return null throw err }) ]).then(([srcStat, destStat]) => ({ srcStat, destStat })) } function getStatsSync (src, dest, opts) { let destStat; const statFunc = opts.dereference ? (file) => fs.statSync(file, { bigint: true }) : (file) => fs.lstatSync(file, { bigint: true }); const srcStat = statFunc(src); try { destStat = statFunc(dest); } catch (err) { if (err.code === 'ENOENT') return { srcStat, destStat: null } throw err } return { srcStat, destStat } } async function checkPaths (src, dest, funcName, opts) { const { srcStat, destStat } = await getStats(src, dest, opts); if (destStat) { if (areIdentical(srcStat, destStat)) { const srcBaseName = path.basename(src); const destBaseName = path.basename(dest); if (funcName === 'move' && srcBaseName !== destBaseName && srcBaseName.toLowerCase() === destBaseName.toLowerCase()) { return { srcStat, destStat, isChangingCase: true } } throw new Error('Source and destination must not be the same.') } if (srcStat.isDirectory() && !destStat.isDirectory()) { throw new Error(`Cannot overwrite non-directory '${dest}' with directory '${src}'.`) } if (!srcStat.isDirectory() && destStat.isDirectory()) { throw new Error(`Cannot overwrite directory '${dest}' with non-directory '${src}'.`) } } if (srcStat.isDirectory() && isSrcSubdir(src, dest)) { throw new Error(errMsg(src, dest, funcName)) } return { srcStat, destStat } } function checkPathsSync (src, dest, funcName, opts) { const { srcStat, destStat } = getStatsSync(src, dest, opts); if (destStat) { if (areIdentical(srcStat, destStat)) { const srcBaseName = path.basename(src); const destBaseName = path.basename(dest); if (funcName === 'move' && srcBaseName !== destBaseName && srcBaseName.toLowerCase() === destBaseName.toLowerCase()) { return { srcStat, destStat, isChangingCase: true } } throw new Error('Source and destination must not be the same.') } if (srcStat.isDirectory() && !destStat.isDirectory()) { throw new Error(`Cannot overwrite non-directory '${dest}' with directory '${src}'.`) } if (!srcStat.isDirectory() && destStat.isDirectory()) { throw new Error(`Cannot overwrite directory '${dest}' with non-directory '${src}'.`) } } if (srcStat.isDirectory() && isSrcSubdir(src, dest)) { throw new Error(errMsg(src, dest, funcName)) } return { srcStat, destStat } } // recursively check if dest parent is a subdirectory of src. // It works for all file types including symlinks since it // checks the src and dest inodes. It starts from the deepest // parent and stops once it reaches the src parent or the root path. async function checkParentPaths (src, srcStat, dest, funcName) { const srcParent = path.resolve(path.dirname(src)); const destParent = path.resolve(path.dirname(dest)); if (destParent === srcParent || destParent === path.parse(destParent).root) return let destStat; try { destStat = await fs.stat(destParent, { bigint: true }); } catch (err) { if (err.code === 'ENOENT') return throw err } if (areIdentical(srcStat, destStat)) { throw new Error(errMsg(src, dest, funcName)) } return checkParentPaths(src, srcStat, destParent, funcName) } function checkParentPathsSync (src, srcStat, dest, funcName) { const srcParent = path.resolve(path.dirname(src)); const destParent = path.resolve(path.dirname(dest)); if (destParent === srcParent || destParent === path.parse(destParent).root) return let destStat; try { destStat = fs.statSync(destParent, { bigint: true }); } catch (err) { if (err.code === 'ENOENT') return throw err } if (areIdentical(srcStat, destStat)) { throw new Error(errMsg(src, dest, funcName)) } return checkParentPathsSync(src, srcStat, destParent, funcName) } function areIdentical (srcStat, destStat) { // stat.dev can be 0n on windows when node version >= 22.x.x return destStat.ino !== undefined && destStat.dev !== undefined && destStat.ino === srcStat.ino && destStat.dev === srcStat.dev } // return true if dest is a subdir of src, otherwise false. // It only checks the path strings. function isSrcSubdir (src, dest) { const srcArr = path.resolve(src).split(path.sep).filter(i => i); const destArr = path.resolve(dest).split(path.sep).filter(i => i); return srcArr.every((cur, i) => destArr[i] === cur) } function errMsg (src, dest, funcName) { return `Cannot ${funcName} '${src}' to a subdirectory of itself, '${dest}'.` } stat$1 = { // checkPaths checkPaths: u(checkPaths), checkPathsSync, // checkParent checkParentPaths: u(checkParentPaths), checkParentPathsSync, // Misc isSrcSubdir, areIdentical }; return stat$1; } var async; var hasRequiredAsync; function requireAsync () { if (hasRequiredAsync) return async; hasRequiredAsync = 1; // https://github.com/jprichardson/node-fs-extra/issues/1056 // Performing parallel operations on each item of an async iterator is // surprisingly hard; you need to have handlers in place to avoid getting an // UnhandledPromiseRejectionWarning. // NOTE: This function does not presently handle return values, only errors async function asyncIteratorConcurrentProcess (iterator, fn) { const promises = []; for await (const item of iterator) { promises.push( fn(item).then( () => null, (err) => err ?? new Error('unknown error') ) ); } await Promise.all( promises.map((promise) => promise.then((possibleErr) => { if (possibleErr !== null) throw possibleErr }) ) ); } async = { asyncIteratorConcurrentProcess }; return async; } var copy_1; var hasRequiredCopy$1; function requireCopy$1 () { if (hasRequiredCopy$1) return copy_1; hasRequiredCopy$1 = 1; const fs = requireFs(); const path = require$$1$1; const { mkdirs } = requireMkdirs(); const { pathExists } = requirePathExists(); const { utimesMillis } = requireUtimes(); const stat = requireStat(); const { asyncIteratorConcurrentProcess } = requireAsync(); async function copy (src, dest, opts = {}) { if (typeof opts === 'function') { opts = { filter: opts }; } opts.clobber = 'clobber' in opts ? !!opts.clobber : true; // default to true for now opts.overwrite = 'overwrite' in opts ? !!opts.overwrite : opts.clobber; // overwrite falls back to clobber // Warn about using preserveTimestamps on 32-bit node if (opts.preserveTimestamps && process.arch === 'ia32') { process.emitWarning( 'Using the preserveTimestamps option in 32-bit node is not recommended;\n\n' + '\tsee https://github.com/jprichardson/node-fs-extra/issues/269', 'Warning', 'fs-extra-WARN0001' ); } const { srcStat, destStat } = await stat.checkPaths(src, dest, 'copy', opts); await stat.checkParentPaths(src, srcStat, dest, 'copy'); const include = await runFilter(src, dest, opts); if (!include) return // check if the parent of dest exists, and create it if it doesn't exist const destParent = path.dirname(dest); const dirExists = await pathExists(destParent); if (!dirExists) { await mkdirs(destParent); } await getStatsAndPerformCopy(destStat, src, dest, opts); } async function runFilter (src, dest, opts) { if (!opts.filter) return true return opts.filter(src, dest) } async function getStatsAndPerformCopy (destStat, src, dest, opts) { const statFn = opts.dereference ? fs.stat : fs.lstat; const srcStat = await statFn(src); if (srcStat.isDirectory()) return onDir(srcStat, destStat, src, dest, opts) if ( srcStat.isFile() || srcStat.isCharacterDevice() || srcStat.isBlockDevice() ) return onFile(srcStat, destStat, src, dest, opts) if (srcStat.isSymbolicLink()) return onLink(destStat, src, dest, opts) if (srcStat.isSocket()) throw new Error(`Cannot copy a socket file: ${src}`) if (srcStat.isFIFO()) throw new Error(`Cannot copy a FIFO pipe: ${src}`) throw new Error(`Unknown file: ${src}`) } async function onFile (srcStat, destStat, src, dest, opts) { if (!destStat) return copyFile(srcStat, src, dest, opts) if (opts.overwrite) { await fs.unlink(dest); return copyFile(srcStat, src, dest, opts) } if (opts.errorOnExist) { throw new Error(`'${dest}' already exists`) } } async function copyFile (srcStat, src, dest, opts) { await fs.copyFile(src, dest); if (opts.preserveTimestamps) { // Make sure the file is writable before setting the timestamp // otherwise open fails with EPERM when invoked with 'r+' // (through utimes call) if (fileIsNotWritable(srcStat.mode)) { await makeFileWritable(dest, srcStat.mode); } // Set timestamps and mode correspondingly // Note that The initial srcStat.atime cannot be trusted // because it is modified by the read(2) system call // (See https://nodejs.org/api/fs.html#fs_stat_time_values) const updatedSrcStat = await fs.stat(src); await utimesMillis(dest, updatedSrcStat.atime, updatedSrcStat.mtime); } return fs.chmod(dest, srcStat.mode) } function fileIsNotWritable (srcMode) { return (srcMode & 0o200) === 0 } function makeFileWritable (dest, srcMode) { return fs.chmod(dest, srcMode | 0o200) } async function onDir (srcStat, destStat, src, dest, opts) { // the dest directory might not exist, create it if (!destStat) { await fs.mkdir(dest); } // iterate through the files in the current directory to copy everything await asyncIteratorConcurrentProcess(await fs.opendir(src), async (item) => { const srcItem = path.join(src, item.name); const destItem = path.join(dest, item.name); const include = await runFilter(srcItem, destItem, opts); // only copy the item if it matches the filter function if (include) { const { destStat } = await stat.checkPaths(srcItem, destItem, 'copy', opts); // If the item is a copyable file, `getStatsAndPerformCopy` will copy it // If the item is a directory, `getStatsAndPerformCopy` will call `onDir` recursively await getStatsAndPerformCopy(destStat, srcItem, destItem, opts); } }); if (!destStat) { await fs.chmod(dest, srcStat.mode); } } async function onLink (destStat, src, dest, opts) { let resolvedSrc = await fs.readlink(src); if (opts.dereference) { resolvedSrc = path.resolve(process.cwd(), resolvedSrc); } if (!destStat) { return fs.symlink(resolvedSrc, dest) } let resolvedDest = null; try { resolvedDest = await fs.readlink(dest); } catch (e) { // dest exists and is a regular file or directory, // Windows may throw UNKNOWN error. If dest already exists, // fs throws error anyway, so no need to guard against it here. if (e.code === 'EINVAL' || e.code === 'UNKNOWN') return fs.symlink(resolvedSrc, dest) throw e } if (opts.dereference) { resolvedDest = path.resolve(process.cwd(), resolvedDest); } if (stat.isSrcSubdir(resolvedSrc, resolvedDest)) { throw new Error(`Cannot copy '${resolvedSrc}' to a subdirectory of itself, '${resolvedDest}'.`) } // do not copy if src is a subdir of dest since unlinking // dest in this case would result in removing src contents // and therefore a broken symlink would be created. if (stat.isSrcSubdir(resolvedDest, resolvedSrc)) { throw new Error(`Cannot overwrite '${resolvedDest}' with '${resolvedSrc}'.`) } // copy the link await fs.unlink(dest); return fs.symlink(resolvedSrc, dest) } copy_1 = copy; return copy_1; } var copySync_1; var hasRequiredCopySync; function requireCopySync () { if (hasRequiredCopySync) return copySync_1; hasRequiredCopySync = 1; const fs = requireGracefulFs(); const path = require$$1$1; const mkdirsSync = requireMkdirs().mkdirsSync; const utimesMillisSync = requireUtimes().utimesMillisSync; const stat = requireStat(); function copySync (src, dest, opts) { if (typeof opts === 'function') { opts = { filter: opts }; } opts = opts || {}; opts.clobber = 'clobber' in opts ? !!opts.clobber : true; // default to true for now opts.overwrite = 'overwrite' in opts ? !!opts.overwrite : opts.clobber; // overwrite falls back to clobber // Warn about using preserveTimestamps on 32-bit node if (opts.preserveTimestamps && process.arch === 'ia32') { process.emitWarning( 'Using the preserveTimestamps option in 32-bit node is not recommended;\n\n' + '\tsee https://github.com/jprichardson/node-fs-extra/issues/269', 'Warning', 'fs-extra-WARN0002' ); } const { srcStat, destStat } = stat.checkPathsSync(src, dest, 'copy', opts); stat.checkParentPathsSync(src, srcStat, dest, 'copy'); if (opts.filter && !opts.filter(src, dest)) return const destParent = path.dirname(dest); if (!fs.existsSync(destParent)) mkdirsSync(destParent); return getStats(destStat, src, dest, opts) } function getStats (destStat, src, dest, opts) { const statSync = opts.dereference ? fs.statSync : fs.lstatSync; const srcStat = statSync(src); if (srcStat.isDirectory()) return onDir(srcStat, destStat, src, dest, opts) else if (srcStat.isFile() || srcStat.isCharacterDevice() || srcStat.isBlockDevice()) return onFile(srcStat, destStat, src, dest, opts) else if (srcStat.isSymbolicLink()) return onLink(destStat, src, dest, opts) else if (srcStat.isSocket()) throw new Error(`Cannot copy a socket file: ${src}`) else if (srcStat.isFIFO()) throw new Error(`Cannot copy a FIFO pipe: ${src}`) throw new Error(`Unknown file: ${src}`) } function onFile (srcStat, destStat, src, dest, opts) { if (!destStat) return copyFile(srcStat, src, dest, opts) return mayCopyFile(srcStat, src, dest, opts) } function mayCopyFile (srcStat, src, dest, opts) { if (opts.overwrite) { fs.unlinkSync(dest); return copyFile(srcStat, src, dest, opts) } else if (opts.errorOnExist) { throw new Error(`'${dest}' already exists`) } } function copyFile (srcStat, src, dest, opts) { fs.copyFileSync(src, dest); if (opts.preserveTimestamps) handleTimestamps(srcStat.mode, src, dest); return setDestMode(dest, srcStat.mode) } function handleTimestamps (srcMode, src, dest) { // Make sure the file is writable before setting the timestamp // otherwise open fails with EPERM when invoked with 'r+' // (through utimes call) if (fileIsNotWritable(srcMode)) makeFileWritable(dest, srcMode); return setDestTimestamps(src, dest) } function fileIsNotWritable (srcMode) { return (srcMode & 0o200) === 0 } function makeFileWritable (dest, srcMode) { return setDestMode(dest, srcMode | 0o200) } function setDestMode (dest, srcMode) { return fs.chmodSync(dest, srcMode) } function setDestTimestamps (src, dest) { // The initial srcStat.atime cannot be trusted // because it is modified by the read(2) system call // (See https://nodejs.org/api/fs.html#fs_stat_time_values) const updatedSrcStat = fs.statSync(src); return utimesMillisSync(dest, updatedSrcStat.atime, updatedSrcStat.mtime) } function onDir (srcStat, destStat, src, dest, opts) { if (!destStat) return mkDirAndCopy(srcStat.mode, src, dest, opts) return copyDir(src, dest, opts) } function mkDirAndCopy (srcMode, src, dest, opts) { fs.mkdirSync(dest); copyDir(src, dest, opts); return setDestMode(dest, srcMode) } function copyDir (src, dest, opts) { const dir = fs.opendirSync(src); try { let dirent; while ((dirent = dir.readSync()) !== null) { copyDirItem(dirent.name, src, dest, opts); } } finally { dir.closeSync(); } } function copyDirItem (item, src, dest, opts) { const srcItem = path.join(src, item); const destItem = path.join(dest, item); if (opts.filter && !opts.filter(srcItem, destItem)) return const { destStat } = stat.checkPathsSync(srcItem, destItem, 'copy', opts); return getStats(destStat, srcItem, destItem, opts) } function onLink (destStat, src, dest, opts) { let resolvedSrc = fs.readlinkSync(src); if (opts.dereference) { resolvedSrc = path.resolve(process.cwd(), resolvedSrc); } if (!destStat) { return fs.symlinkSync(resolvedSrc, dest) } else { let resolvedDest; try { resolvedDest = fs.readlinkSync(dest); } catch (err) { // dest exists and is a regular file or directory, // Windows may throw UNKNOWN error. If dest already exists, // fs throws error anyway, so no need to guard against it here. if (err.code === 'EINVAL' || err.code === 'UNKNOWN') return fs.symlinkSync(resolvedSrc, dest) throw err } if (opts.dereference) { resolvedDest = path.resolve(process.cwd(), resolvedDest); } if (stat.isSrcSubdir(resolvedSrc, resolvedDest)) { throw new Error(`Cannot copy '${resolvedSrc}' to a subdirectory of itself, '${resolvedDest}'.`) } // prevent copy if src is a subdir of dest since unlinking // dest in this case would result in removing src contents // and therefore a broken symlink would be created. if (stat.isSrcSubdir(resolvedDest, resolvedSrc)) { throw new Error(`Cannot overwrite '${resolvedDest}' with '${resolvedSrc}'.`) } return copyLink(resolvedSrc, dest) } } function copyLink (resolvedSrc, dest) { fs.unlinkSync(dest); return fs.symlinkSync(resolvedSrc, dest) } copySync_1 = copySync; return copySync_1; } var copy; var hasRequiredCopy; function requireCopy () { if (hasRequiredCopy) return copy; hasRequiredCopy = 1; const u = requireUniversalify().fromPromise; copy = { copy: u(requireCopy$1()), copySync: requireCopySync() }; return copy; } var remove_1; var hasRequiredRemove; function requireRemove () { if (hasRequiredRemove) return remove_1; hasRequiredRemove = 1; const fs = requireGracefulFs(); const u = requireUniversalify().fromCallback; function remove (path, callback) { fs.rm(path, { recursive: true, force: true }, callback); } function removeSync (path) { fs.rmSync(path, { recursive: true, force: true }); } remove_1 = { remove: u(remove), removeSync }; return remove_1; } var empty$3; var hasRequiredEmpty; function requireEmpty () { if (hasRequiredEmpty) return empty$3; hasRequiredEmpty = 1; const u = requireUniversalify().fromPromise; const fs = requireFs(); const path = require$$1$1; const mkdir = requireMkdirs(); const remove = requireRemove(); const emptyDir = u(async function emptyDir (dir) { let items; try { items = await fs.readdir(dir); } catch { return mkdir.mkdirs(dir) } return Promise.all(items.map(item => remove.remove(path.join(dir, item)))) }); function emptyDirSync (dir) { let items; try { items = fs.readdirSync(dir); } catch { return mkdir.mkdirsSync(dir) } items.forEach(item => { item = path.join(dir, item); remove.removeSync(item); }); } empty$3 = { emptyDirSync, emptydirSync: emptyDirSync, emptyDir, emptydir: emptyDir }; return empty$3; } var file; var hasRequiredFile; function requireFile () { if (hasRequiredFile) return file; hasRequiredFile = 1; const u = requireUniversalify().fromPromise; const path = require$$1$1; const fs = requireFs(); const mkdir = requireMkdirs(); async function createFile (file) { let stats; try { stats = await fs.stat(file); } catch { } if (stats && stats.isFile()) return const dir = path.dirname(file); let dirStats = null; try { dirStats = await fs.stat(dir); } catch (err) { // if the directory doesn't exist, make it if (err.code === 'ENOENT') { await mkdir.mkdirs(dir); await fs.writeFile(file, ''); return } else { throw err } } if (dirStats.isDirectory()) { await fs.writeFile(file, ''); } else { // parent is not a directory // This is just to cause an internal ENOTDIR error to be thrown await fs.readdir(dir); } } function createFileSync (file) { let stats; try { stats = fs.statSync(file); } catch { } if (stats && stats.isFile()) return const dir = path.dirname(file); try { if (!fs.statSync(dir).isDirectory()) { // parent is not a directory // This is just to cause an internal ENOTDIR error to be thrown fs.readdirSync(dir); } } catch (err) { // If the stat call above failed because the directory doesn't exist, create it if (err && err.code === 'ENOENT') mkdir.mkdirsSync(dir); else throw err } fs.writeFileSync(file, ''); } file = { createFile: u(createFile), createFileSync }; return file; } var link$1; var hasRequiredLink; function requireLink () { if (hasRequiredLink) return link$1; hasRequiredLink = 1; const u = requireUniversalify().fromPromise; const path = require$$1$1; const fs = requireFs(); const mkdir = requireMkdirs(); const { pathExists } = requirePathExists(); const { areIdentical } = requireStat(); async function createLink (srcpath, dstpath) { let dstStat; try { dstStat = await fs.lstat(dstpath); } catch { // ignore error } let srcStat; try { srcStat = await fs.lstat(srcpath); } catch (err) { err.message = err.message.replace('lstat', 'ensureLink'); throw err } if (dstStat && areIdentical(srcStat, dstStat)) return const dir = path.dirname(dstpath); const dirExists = await pathExists(dir); if (!dirExists) { await mkdir.mkdirs(dir); } await fs.link(srcpath, dstpath); } function createLinkSync (srcpath, dstpath) { let dstStat; try { dstStat = fs.lstatSync(dstpath); } catch {} try { const srcStat = fs.lstatSync(srcpath); if (dstStat && areIdentical(srcStat, dstStat)) return } catch (err) { err.message = err.message.replace('lstat', 'ensureLink'); throw err } const dir = path.dirname(dstpath); const dirExists = fs.existsSync(dir); if (dirExists) return fs.linkSync(srcpath, dstpath) mkdir.mkdirsSync(dir); return fs.linkSync(srcpath, dstpath) } link$1 = { createLink: u(createLink), createLinkSync }; return link$1; } var symlinkPaths_1; var hasRequiredSymlinkPaths; function requireSymlinkPaths () { if (hasRequiredSymlinkPaths) return symlinkPaths_1; hasRequiredSymlinkPaths = 1; const path = require$$1$1; const fs = requireFs(); const { pathExists } = requirePathExists(); const u = requireUniversalify().fromPromise; /** * Function that returns two types of paths, one relative to symlink, and one * relative to the current working directory. Checks if path is absolute or * relative. If the path is relative, this function checks if the path is * relative to symlink or relative to current working directory. This is an * initiative to find a smarter `srcpath` to supply when building symlinks. * This allows you to determine which path to use out of one of three possible * types of source paths. The first is an absolute path. This is detected by * `path.isAbsolute()`. When an absolute path is provided, it is checked to * see if it exists. If it does it's used, if not an error is returned * (callback)/ thrown (sync). The other two options for `srcpath` are a * relative url. By default Node's `fs.symlink` works by creating a symlink * using `dstpath` and expects the `srcpath` to be relative to the newly * created symlink. If you provide a `srcpath` that does not exist on the file * system it results in a broken symlink. To minimize this, the function * checks to see if the 'relative to symlink' source file exists, and if it * does it will use it. If it does not, it checks if there's a file that * exists that is relative to the current working directory, if does its used. * This preserves the expectations of the original fs.symlink spec and adds * the ability to pass in `relative to current working direcotry` paths. */ async function symlinkPaths (srcpath, dstpath) { if (path.isAbsolute(srcpath)) { try { await fs.lstat(srcpath); } catch (err) { err.message = err.message.replace('lstat', 'ensureSymlink'); throw err } return { toCwd: srcpath, toDst: srcpath } } const dstdir = path.dirname(dstpath); const relativeToDst = path.join(dstdir, srcpath); const exists = await pathExists(relativeToDst); if (exists) { return { toCwd: relativeToDst, toDst: srcpath } } try { await fs.lstat(srcpath); } catch (err) { err.message = err.message.replace('lstat', 'ensureSymlink'); throw err } return { toCwd: srcpath, toDst: path.relative(dstdir, srcpath) } } function symlinkPathsSync (srcpath, dstpath) { if (path.isAbsolute(srcpath)) { const exists = fs.existsSync(srcpath); if (!exists) throw new Error('absolute srcpath does not exist') return { toCwd: srcpath, toDst: srcpath } } const dstdir = path.dirname(dstpath); const relativeToDst = path.join(dstdir, srcpath); const exists = fs.existsSync(relativeToDst); if (exists) { return { toCwd: relativeToDst, toDst: srcpath } } const srcExists = fs.existsSync(srcpath); if (!srcExists) throw new Error('relative srcpath does not exist') return { toCwd: srcpath, toDst: path.relative(dstdir, srcpath) } } symlinkPaths_1 = { symlinkPaths: u(symlinkPaths), symlinkPathsSync }; return symlinkPaths_1; } var symlinkType_1; var hasRequiredSymlinkType; function requireSymlinkType () { if (hasRequiredSymlinkType) return symlinkType_1; hasRequiredSymlinkType = 1; const fs = requireFs(); const u = requireUniversalify().fromPromise; async function symlinkType (srcpath, type) { if (type) return type let stats; try { stats = await fs.lstat(srcpath); } catch { return 'file' } return (stats && stats.isDirectory()) ? 'dir' : 'file' } function symlinkTypeSync (srcpath, type) { if (type) return type let stats; try { stats = fs.lstatSync(srcpath); } catch { return 'file' } return (stats && stats.isDirectory()) ? 'dir' : 'file' } symlinkType_1 = { symlinkType: u(symlinkType), symlinkTypeSync }; return symlinkType_1; } var symlink; var hasRequiredSymlink; function requireSymlink () { if (hasRequiredSymlink) return symlink; hasRequiredSymlink = 1; const u = requireUniversalify().fromPromise; const path = require$$1$1; const fs = requireFs(); const { mkdirs, mkdirsSync } = requireMkdirs(); const { symlinkPaths, symlinkPathsSync } = requireSymlinkPaths(); const { symlinkType, symlinkTypeSync } = requireSymlinkType(); const { pathExists } = requirePathExists(); const { areIdentical } = requireStat(); async function createSymlink (srcpath, dstpath, type) { let stats; try { stats = await fs.lstat(dstpath); } catch { } if (stats && stats.isSymbolicLink()) { const [srcStat, dstStat] = await Promise.all([ fs.stat(srcpath), fs.stat(dstpath) ]); if (areIdentical(srcStat, dstStat)) return } const relative = await symlinkPaths(srcpath, dstpath); srcpath = relative.toDst; const toType = await symlinkType(relative.toCwd, type); const dir = path.dirname(dstpath); if (!(await pathExists(dir))) { await mkdirs(dir); } return fs.symlink(srcpath, dstpath, toType) } function createSymlinkSync (srcpath, dstpath, type) { let stats; try { stats = fs.lstatSync(dstpath); } catch { } if (stats && stats.isSymbolicLink()) { const srcStat = fs.statSync(srcpath); const dstStat = fs.statSync(dstpath); if (areIdentical(srcStat, dstStat)) return } const relative = symlinkPathsSync(srcpath, dstpath); srcpath = relative.toDst; type = symlinkTypeSync(relative.toCwd, type); const dir = path.dirname(dstpath); const exists = fs.existsSync(dir); if (exists) return fs.symlinkSync(srcpath, dstpath, type) mkdirsSync(dir); return fs.symlinkSync(srcpath, dstpath, type) } symlink = { createSymlink: u(createSymlink), createSymlinkSync }; return symlink; } var ensure; var hasRequiredEnsure; function requireEnsure () { if (hasRequiredEnsure) return ensure; hasRequiredEnsure = 1; const { createFile, createFileSync } = requireFile(); const { createLink, createLinkSync } = requireLink(); const { createSymlink, createSymlinkSync } = requireSymlink(); ensure = { // file createFile, createFileSync, ensureFile: createFile, ensureFileSync: createFileSync, // link createLink, createLinkSync, ensureLink: createLink, ensureLinkSync: createLinkSync, // symlink createSymlink, createSymlinkSync, ensureSymlink: createSymlink, ensureSymlinkSync: createSymlinkSync }; return ensure; } var utils$4; var hasRequiredUtils$3; function requireUtils$3 () { if (hasRequiredUtils$3) return utils$4; hasRequiredUtils$3 = 1; function stringify (obj, { EOL = '\n', finalEOL = true, replacer = null, spaces } = {}) { const EOF = finalEOL ? EOL : ''; const str = JSON.stringify(obj, replacer, spaces); return str.replace(/\n/g, EOL) + EOF } function stripBom (content) { // we do this because JSON.parse would convert it to a utf8 string if encoding wasn't specified if (Buffer.isBuffer(content)) content = content.toString('utf8'); return content.replace(/^\uFEFF/, '') } utils$4 = { stringify, stripBom }; return utils$4; } var jsonfile$1; var hasRequiredJsonfile$1; function requireJsonfile$1 () { if (hasRequiredJsonfile$1) return jsonfile$1; hasRequiredJsonfile$1 = 1; let _fs; try { _fs = requireGracefulFs(); } catch (_) { _fs = nativeFs__default; } const universalify = requireUniversalify(); const { stringify, stripBom } = requireUtils$3(); async function _readFile (file, options = {}) { if (typeof options === 'string') { options = { encoding: options }; } const fs = options.fs || _fs; const shouldThrow = 'throws' in options ? options.throws : true; let data = await universalify.fromCallback(fs.readFile)(file, options); data = stripBom(data); let obj; try { obj = JSON.parse(data, options ? options.reviver : null); } catch (err) { if (shouldThrow) { err.message = `${file}: ${err.message}`; throw err } else { return null } } return obj } const readFile = universalify.fromPromise(_readFile); function readFileSync (file, options = {}) { if (typeof options === 'string') { options = { encoding: options }; } const fs = options.fs || _fs; const shouldThrow = 'throws' in options ? options.throws : true; try { let content = fs.readFileSync(file, options); content = stripBom(content); return JSON.parse(content, options.reviver) } catch (err) { if (shouldThrow) { err.message = `${file}: ${err.message}`; throw err } else { return null } } } async function _writeFile (file, obj, options = {}) { const fs = options.fs || _fs; const str = stringify(obj, options); await universalify.fromCallback(fs.writeFile)(file, str, options); } const writeFile = universalify.fromPromise(_writeFile); function writeFileSync (file, obj, options = {}) { const fs = options.fs || _fs; const str = stringify(obj, options); // not sure if fs.writeFileSync returns anything, but just in case return fs.writeFileSync(file, str, options) } // NOTE: do not change this export format; required for ESM compat // see https://github.com/jprichardson/node-jsonfile/pull/162 for details jsonfile$1 = { readFile, readFileSync, writeFile, writeFileSync }; return jsonfile$1; } var jsonfile; var hasRequiredJsonfile; function requireJsonfile () { if (hasRequiredJsonfile) return jsonfile; hasRequiredJsonfile = 1; const jsonFile = requireJsonfile$1(); jsonfile = { // jsonfile exports readJson: jsonFile.readFile, readJsonSync: jsonFile.readFileSync, writeJson: jsonFile.writeFile, writeJsonSync: jsonFile.writeFileSync }; return jsonfile; } var outputFile_1; var hasRequiredOutputFile; function requireOutputFile () { if (hasRequiredOutputFile) return outputFile_1; hasRequiredOutputFile = 1; const u = requireUniversalify().fromPromise; const fs = requireFs(); const path = require$$1$1; const mkdir = requireMkdirs(); const pathExists = requirePathExists().pathExists; async function outputFile (file, data, encoding = 'utf-8') { const dir = path.dirname(file); if (!(await pathExists(dir))) { await mkdir.mkdirs(dir); } return fs.writeFile(file, data, encoding) } function outputFileSync (file, ...args) { const dir = path.dirname(file); if (!fs.existsSync(dir)) { mkdir.mkdirsSync(dir); } fs.writeFileSync(file, ...args); } outputFile_1 = { outputFile: u(outputFile), outputFileSync }; return outputFile_1; } var outputJson_1; var hasRequiredOutputJson; function requireOutputJson () { if (hasRequiredOutputJson) return outputJson_1; hasRequiredOutputJson = 1; const { stringify } = requireUtils$3(); const { outputFile } = requireOutputFile(); async function outputJson (file, data, options = {}) { const str = stringify(data, options); await outputFile(file, str, options); } outputJson_1 = outputJson; return outputJson_1; } var outputJsonSync_1; var hasRequiredOutputJsonSync; function requireOutputJsonSync () { if (hasRequiredOutputJsonSync) return outputJsonSync_1; hasRequiredOutputJsonSync = 1; const { stringify } = requireUtils$3(); const { outputFileSync } = requireOutputFile(); function outputJsonSync (file, data, options) { const str = stringify(data, options); outputFileSync(file, str, options); } outputJsonSync_1 = outputJsonSync; return outputJsonSync_1; } var json$1; var hasRequiredJson$1; function requireJson$1 () { if (hasRequiredJson$1) return json$1; hasRequiredJson$1 = 1; const u = requireUniversalify().fromPromise; const jsonFile = requireJsonfile(); jsonFile.outputJson = u(requireOutputJson()); jsonFile.outputJsonSync = requireOutputJsonSync(); // aliases jsonFile.outputJSON = jsonFile.outputJson; jsonFile.outputJSONSync = jsonFile.outputJsonSync; jsonFile.writeJSON = jsonFile.writeJson; jsonFile.writeJSONSync = jsonFile.writeJsonSync; jsonFile.readJSON = jsonFile.readJson; jsonFile.readJSONSync = jsonFile.readJsonSync; json$1 = jsonFile; return json$1; } var move_1; var hasRequiredMove$1; function requireMove$1 () { if (hasRequiredMove$1) return move_1; hasRequiredMove$1 = 1; const fs = requireFs(); const path = require$$1$1; const { copy } = requireCopy(); const { remove } = requireRemove(); const { mkdirp } = requireMkdirs(); const { pathExists } = requirePathExists(); const stat = requireStat(); async function move (src, dest, opts = {}) { const overwrite = opts.overwrite || opts.clobber || false; const { srcStat, isChangingCase = false } = await stat.checkPaths(src, dest, 'move', opts); await stat.checkParentPaths(src, srcStat, dest, 'move'); // If the parent of dest is not root, make sure it exists before proceeding const destParent = path.dirname(dest); const parsedParentPath = path.parse(destParent); if (parsedParentPath.root !== destParent) { await mkdirp(destParent); } return doRename(src, dest, overwrite, isChangingCase) } async function doRename (src, dest, overwrite, isChangingCase) { if (!isChangingCase) { if (overwrite) { await remove(dest); } else if (await pathExists(dest)) { throw new Error('dest already exists.') } } try { // Try w/ rename first, and try copy + remove if EXDEV await fs.rename(src, dest); } catch (err) { if (err.code !== 'EXDEV') { throw err } await moveAcrossDevice(src, dest, overwrite); } } async function moveAcrossDevice (src, dest, overwrite) { const opts = { overwrite, errorOnExist: true, preserveTimestamps: true }; await copy(src, dest, opts); return remove(src) } move_1 = move; return move_1; } var moveSync_1; var hasRequiredMoveSync; function requireMoveSync () { if (hasRequiredMoveSync) return moveSync_1; hasRequiredMoveSync = 1; const fs = requireGracefulFs(); const path = require$$1$1; const copySync = requireCopy().copySync; const removeSync = requireRemove().removeSync; const mkdirpSync = requireMkdirs().mkdirpSync; const stat = requireStat(); function moveSync (src, dest, opts) { opts = opts || {}; const overwrite = opts.overwrite || opts.clobber || false; const { srcStat, isChangingCase = false } = stat.checkPathsSync(src, dest, 'move', opts); stat.checkParentPathsSync(src, srcStat, dest, 'move'); if (!isParentRoot(dest)) mkdirpSync(path.dirname(dest)); return doRename(src, dest, overwrite, isChangingCase) } function isParentRoot (dest) { const parent = path.dirname(dest); const parsedPath = path.parse(parent); return parsedPath.root === parent } function doRename (src, dest, overwrite, isChangingCase) { if (isChangingCase) return rename(src, dest, overwrite) if (overwrite) { removeSync(dest); return rename(src, dest, overwrite) } if (fs.existsSync(dest)) throw new Error('dest already exists.') return rename(src, dest, overwrite) } function rename (src, dest, overwrite) { try { fs.renameSync(src, dest); } catch (err) { if (err.code !== 'EXDEV') throw err return moveAcrossDevice(src, dest, overwrite) } } function moveAcrossDevice (src, dest, overwrite) { const opts = { overwrite, errorOnExist: true, preserveTimestamps: true }; copySync(src, dest, opts); return removeSync(src) } moveSync_1 = moveSync; return moveSync_1; } var move; var hasRequiredMove; function requireMove () { if (hasRequiredMove) return move; hasRequiredMove = 1; const u = requireUniversalify().fromPromise; move = { move: u(requireMove$1()), moveSync: requireMoveSync() }; return move; } var lib$1; var hasRequiredLib; function requireLib () { if (hasRequiredLib) return lib$1; hasRequiredLib = 1; lib$1 = { // Export promiseified graceful-fs: ...requireFs(), // Export extra methods: ...requireCopy(), ...requireEmpty(), ...requireEnsure(), ...requireJson$1(), ...requireMkdirs(), ...requireMove(), ...requireOutputFile(), ...requirePathExists(), ...requireRemove() }; return lib$1; } var libExports = /*@__PURE__*/ requireLib(); var fs = /*@__PURE__*/getDefaultExportFromCjs(libExports); async function pMap( iterable, mapper, { concurrency = Number.POSITIVE_INFINITY, stopOnError = true, signal, } = {}, ) { return new Promise((resolve_, reject_) => { if (iterable[Symbol.iterator] === undefined && iterable[Symbol.asyncIterator] === undefined) { throw new TypeError(`Expected \`input\` to be either an \`Iterable\` or \`AsyncIterable\`, got (${typeof iterable})`); } if (typeof mapper !== 'function') { throw new TypeError('Mapper function is required'); } if (!((Number.isSafeInteger(concurrency) && concurrency >= 1) || concurrency === Number.POSITIVE_INFINITY)) { throw new TypeError(`Expected \`concurrency\` to be an integer from 1 and up or \`Infinity\`, got \`${concurrency}\` (${typeof concurrency})`); } const result = []; const errors = []; const skippedIndexesMap = new Map(); let isRejected = false; let isResolved = false; let isIterableDone = false; let resolvingCount = 0; let currentIndex = 0; const iterator = iterable[Symbol.iterator] === undefined ? iterable[Symbol.asyncIterator]() : iterable[Symbol.iterator](); const signalListener = () => { reject(signal.reason); }; const cleanup = () => { signal?.removeEventListener('abort', signalListener); }; const resolve = value => { resolve_(value); cleanup(); }; const reject = reason => { isRejected = true; isResolved = true; reject_(reason); cleanup(); }; if (signal) { if (signal.aborted) { reject(signal.reason); } signal.addEventListener('abort', signalListener, {once: true}); } const next = async () => { if (isResolved) { return; } const nextItem = await iterator.next(); const index = currentIndex; currentIndex++; // Note: `iterator.next()` can be called many times in parallel. // This can cause multiple calls to this `next()` function to // receive a `nextItem` with `done === true`. // The shutdown logic that rejects/resolves must be protected // so it runs only one time as the `skippedIndex` logic is // non-idempotent. if (nextItem.done) { isIterableDone = true; if (resolvingCount === 0 && !isResolved) { if (!stopOnError && errors.length > 0) { reject(new AggregateError(errors)); // eslint-disable-line unicorn/error-message return; } isResolved = true; if (skippedIndexesMap.size === 0) { resolve(result); return; } const pureResult = []; // Support multiple `pMapSkip`'s. for (const [index, value] of result.entries()) { if (skippedIndexesMap.get(index) === pMapSkip) { continue; } pureResult.push(value); } resolve(pureResult); } return; } resolvingCount++; // Intentionally detached (async () => { try { const element = await nextItem.value; if (isResolved) { return; } const value = await mapper(element, index); // Use Map to stage the index of the element. if (value === pMapSkip) { skippedIndexesMap.set(index, value); } result[index] = value; resolvingCount--; await next(); } catch (error) { if (stopOnError) { reject(error); } else { errors.push(error); resolvingCount--; // In that case we can't really continue regardless of `stopOnError` state // since an iterable is likely to continue throwing after it throws once. // If we continue calling `next()` indefinitely we will likely end up // in an infinite loop of failed iteration. try { await next(); } catch (error) { reject(error); } } } })(); }; // Create the concurrent runners in a detached (non-awaited) // promise. We need this so we can await the `next()` calls // to stop creating runners before hitting the concurrency limit // if the iterable has already been marked as done. // NOTE: We *must* do this for async iterators otherwise we'll spin up // infinite `next()` calls by default and never start the event loop. (async () => { for (let index = 0; index < concurrency; index++) { try { // eslint-disable-next-line no-await-in-loop await next(); } catch (error) { reject(error); break; } if (isIterableDone || isRejected) { break; } } })(); }); } const pMapSkip = Symbol('skip'); const toPath = urlOrPath => urlOrPath instanceof URL ? fileURLToPath(urlOrPath) : urlOrPath; function findUpSync(name, { cwd = process$2.cwd(), type = 'file', stopAt, } = {}) { let directory = path$1.resolve(toPath(cwd) ?? ''); const {root} = path$1.parse(directory); stopAt = path$1.resolve(directory, toPath(stopAt) ?? root); const isAbsoluteName = path$1.isAbsolute(name); while (directory) { const filePath = isAbsoluteName ? name : path$1.join(directory, name); try { const stats = fs__default.statSync(filePath, {throwIfNoEntry: false}); if ((type === 'file' && stats?.isFile()) || (type === 'directory' && stats?.isDirectory())) { return filePath; } } catch {} if (directory === stopAt || directory === root) { break; } directory = path$1.dirname(directory); } } function packageDirectorySync({cwd} = {}) { const filePath = findUpSync('package.json', {cwd}); return filePath && path$1.dirname(filePath); } const balanced = (a, b, str) => { const ma = a instanceof RegExp ? maybeMatch(a, str) : a; const mb = b instanceof RegExp ? maybeMatch(b, str) : b; const r = ma !== null && mb != null && range(ma, mb, str); return (r && { start: r[0], end: r[1], pre: str.slice(0, r[0]), body: str.slice(r[0] + ma.length, r[1]), post: str.slice(r[1] + mb.length), }); }; const maybeMatch = (reg, str) => { const m = str.match(reg); return m ? m[0] : null; }; const range = (a, b, str) => { let begs, beg, left, right = undefined, result; let ai = str.indexOf(a); let bi = str.indexOf(b, ai + 1); let i = ai; if (ai >= 0 && bi > 0) { if (a === b) { return [ai, bi]; } begs = []; left = str.length; while (i >= 0 && !result) { if (i === ai) { begs.push(i); ai = str.indexOf(a, i + 1); } else if (begs.length === 1) { const r = begs.pop(); if (r !== undefined) result = [r, bi]; } else { beg = begs.pop(); if (beg !== undefined && beg < left) { left = beg; right = bi; } bi = str.indexOf(b, i + 1); } i = ai < bi && ai >= 0 ? ai : bi; } if (begs.length && right !== undefined) { result = [left, right]; } } return result; }; const escSlash = '\0SLASH' + Math.random() + '\0'; const escOpen = '\0OPEN' + Math.random() + '\0'; const escClose = '\0CLOSE' + Math.random() + '\0'; const escComma = '\0COMMA' + Math.random() + '\0'; const escPeriod = '\0PERIOD' + Math.random() + '\0'; const escSlashPattern = new RegExp(escSlash, 'g'); const escOpenPattern = new RegExp(escOpen, 'g'); const escClosePattern = new RegExp(escClose, 'g'); const escCommaPattern = new RegExp(escComma, 'g'); const escPeriodPattern = new RegExp(escPeriod, 'g'); const slashPattern = /\\\\/g; const openPattern = /\\{/g; const closePattern = /\\}/g; const commaPattern = /\\,/g; const periodPattern = /\\./g; function numeric(str) { return !isNaN(str) ? parseInt(str, 10) : str.charCodeAt(0); } function escapeBraces(str) { return str .replace(slashPattern, escSlash) .replace(openPattern, escOpen) .replace(closePattern, escClose) .replace(commaPattern, escComma) .replace(periodPattern, escPeriod); } function unescapeBraces(str) { return str .replace(escSlashPattern, '\\') .replace(escOpenPattern, '{') .replace(escClosePattern, '}') .replace(escCommaPattern, ',') .replace(escPeriodPattern, '.'); } /** * Basically just str.split(","), but handling cases * where we have nested braced sections, which should be * treated as individual members, like {a,{b,c},d} */ function parseCommaParts(str) { if (!str) { return ['']; } const parts = []; const m = balanced('{', '}', str); if (!m) { return str.split(','); } const { pre, body, post } = m; const p = pre.split(','); p[p.length - 1] += '{' + body + '}'; const postParts = parseCommaParts(post); if (post.length) { p[p.length - 1] += postParts.shift(); p.push.apply(p, postParts); } parts.push.apply(parts, p); return parts; } function expand(str) { if (!str) { return []; } // I don't know why Bash 4.3 does this, but it does. // Anything starting with {} will have the first two bytes preserved // but *only* at the top level, so {},a}b will not expand to anything, // but a{},b}c will be expanded to [a}c,abc]. // One could argue that this is a bug in Bash, but since the goal of // this module is to match Bash's rules, we escape a leading {} if (str.slice(0, 2) === '{}') { str = '\\{\\}' + str.slice(2); } return expand_(escapeBraces(str), true).map(unescapeBraces); } function embrace(str) { return '{' + str + '}'; } function isPadded(el) { return /^-?0\d/.test(el); } function lte(i, y) { return i <= y; } function gte(i, y) { return i >= y; } function expand_(str, isTop) { /** @type {string[]} */ const expansions = []; const m = balanced('{', '}', str); if (!m) return [str]; // no need to expand pre, since it is guaranteed to be free of brace-sets const pre = m.pre; const post = m.post.length ? expand_(m.post, false) : ['']; if (/\$$/.test(m.pre)) { for (let k = 0; k < post.length; k++) { const expansion = pre + '{' + m.body + '}' + post[k]; expansions.push(expansion); } } else { const isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m.body); const isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m.body); const isSequence = isNumericSequence || isAlphaSequence; const isOptions = m.body.indexOf(',') >= 0; if (!isSequence && !isOptions) { // {a},b} if (m.post.match(/,(?!,).*\}/)) { str = m.pre + '{' + m.body + escClose + m.post; return expand_(str); } return [str]; } let n; if (isSequence) { n = m.body.split(/\.\./); } else { n = parseCommaParts(m.body); if (n.length === 1 && n[0] !== undefined) { // x{{a,b}}y ==> x{a}y x{b}y n = expand_(n[0], false).map(embrace); //XXX is this necessary? Can't seem to hit it in tests. /* c8 ignore start */ if (n.length === 1) { return post.map(p => m.pre + n[0] + p); } /* c8 ignore stop */ } } // at this point, n is the parts, and we know it's not a comma set // with a single entry. let N; if (isSequence && n[0] !== undefined && n[1] !== undefined) { const x = numeric(n[0]); const y = numeric(n[1]); const width = Math.max(n[0].length, n[1].length); let incr = n.length === 3 && n[2] !== undefined ? Math.abs(numeric(n[2])) : 1; let test = lte; const reverse = y < x; if (reverse) { incr *= -1; test = gte; } const pad = n.some(isPadded); N = []; for (let i = x; test(i, y); i += incr) { let c; if (isAlphaSequence) { c = String.fromCharCode(i); if (c === '\\') { c = ''; } } else { c = String(i); if (pad) { const need = width - c.length; if (need > 0) { const z = new Array(need + 1).join('0'); if (i < 0) { c = '-' + z + c.slice(1); } else { c = z + c; } } } } N.push(c); } } else { N = []; for (let j = 0; j < n.length; j++) { N.push.apply(N, expand_(n[j], false)); } } for (let j = 0; j < N.length; j++) { for (let k = 0; k < post.length; k++) { const expansion = pre + N[j] + post[k]; if (!isTop || isSequence || expansion) { expansions.push(expansion); } } } } return expansions; } const MAX_PATTERN_LENGTH = 1024 * 64; const assertValidPattern = (pattern) => { if (typeof pattern !== 'string') { throw new TypeError('invalid pattern'); } if (pattern.length > MAX_PATTERN_LENGTH) { throw new TypeError('pattern is too long'); } }; // translate the various posix character classes into unicode properties // this works across all unicode locales // { : [, /u flag required, negated] const posixClasses = { '[:alnum:]': ['\\p{L}\\p{Nl}\\p{Nd}', true], '[:alpha:]': ['\\p{L}\\p{Nl}', true], '[:ascii:]': ['\\x' + '00-\\x' + '7f', false], '[:blank:]': ['\\p{Zs}\\t', true], '[:cntrl:]': ['\\p{Cc}', true], '[:digit:]': ['\\p{Nd}', true], '[:graph:]': ['\\p{Z}\\p{C}', true, true], '[:lower:]': ['\\p{Ll}', true], '[:print:]': ['\\p{C}', true], '[:punct:]': ['\\p{P}', true], '[:space:]': ['\\p{Z}\\t\\r\\n\\v\\f', true], '[:upper:]': ['\\p{Lu}', true], '[:word:]': ['\\p{L}\\p{Nl}\\p{Nd}\\p{Pc}', true], '[:xdigit:]': ['A-Fa-f0-9', false], }; // only need to escape a few things inside of brace expressions // escapes: [ \ ] - const braceEscape = (s) => s.replace(/[[\]\\-]/g, '\\$&'); // escape all regexp magic characters const regexpEscape = (s) => s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'); // everything has already been escaped, we just have to join const rangesToString = (ranges) => ranges.join(''); // takes a glob string at a posix brace expression, and returns // an equivalent regular expression source, and boolean indicating // whether the /u flag needs to be applied, and the number of chars // consumed to parse the character class. // This also removes out of order ranges, and returns ($.) if the // entire class just no good. const parseClass = (glob, position) => { const pos = position; /* c8 ignore start */ if (glob.charAt(pos) !== '[') { throw new Error('not in a brace expression'); } /* c8 ignore stop */ const ranges = []; const negs = []; let i = pos + 1; let sawStart = false; let uflag = false; let escaping = false; let negate = false; let endPos = pos; let rangeStart = ''; WHILE: while (i < glob.length) { const c = glob.charAt(i); if ((c === '!' || c === '^') && i === pos + 1) { negate = true; i++; continue; } if (c === ']' && sawStart && !escaping) { endPos = i + 1; break; } sawStart = true; if (c === '\\') { if (!escaping) { escaping = true; i++; continue; } // escaped \ char, fall through and treat like normal char } if (c === '[' && !escaping) { // either a posix class, a collation equivalent, or just a [ for (const [cls, [unip, u, neg]] of Object.entries(posixClasses)) { if (glob.startsWith(cls, i)) { // invalid, [a-[] is fine, but not [a-[:alpha]] if (rangeStart) { return ['$.', false, glob.length - pos, true]; } i += cls.length; if (neg) negs.push(unip); else ranges.push(unip); uflag = uflag || u; continue WHILE; } } } // now it's just a normal character, effectively escaping = false; if (rangeStart) { // throw this range away if it's not valid, but others // can still match. if (c > rangeStart) { ranges.push(braceEscape(rangeStart) + '-' + braceEscape(c)); } else if (c === rangeStart) { ranges.push(braceEscape(c)); } rangeStart = ''; i++; continue; } // now might be the start of a range. // can be either c-d or c-] or c] or c] at this point if (glob.startsWith('-]', i + 1)) { ranges.push(braceEscape(c + '-')); i += 2; continue; } if (glob.startsWith('-', i + 1)) { rangeStart = c; i += 2; continue; } // not the start of a range, just a single character ranges.push(braceEscape(c)); i++; } if (endPos < i) { // didn't see the end of the class, not a valid class, // but might still be valid as a literal match. return ['', false, 0, false]; } // if we got no ranges and no negates, then we have a range that // cannot possibly match anything, and that poisons the whole glob if (!ranges.length && !negs.length) { return ['$.', false, glob.length - pos, true]; } // if we got one positive range, and it's a single character, then that's // not actually a magic pattern, it's just that one literal character. // we should not treat that as "magic", we should just return the literal // character. [_] is a perfectly valid way to escape glob magic chars. if (negs.length === 0 && ranges.length === 1 && /^\\?.$/.test(ranges[0]) && !negate) { const r = ranges[0].length === 2 ? ranges[0].slice(-1) : ranges[0]; return [regexpEscape(r), false, endPos - pos, false]; } const sranges = '[' + (negate ? '^' : '') + rangesToString(ranges) + ']'; const snegs = '[' + (negate ? '' : '^') + rangesToString(negs) + ']'; const comb = ranges.length && negs.length ? '(' + sranges + '|' + snegs + ')' : ranges.length ? sranges : snegs; return [comb, uflag, endPos - pos, true]; }; /** * Un-escape a string that has been escaped with {@link escape}. * * If the {@link MinimatchOptions.windowsPathsNoEscape} option is used, then * square-bracket escapes are removed, but not backslash escapes. * * For example, it will turn the string `'[*]'` into `*`, but it will not * turn `'\\*'` into `'*'`, because `\` is a path separator in * `windowsPathsNoEscape` mode. * * When `windowsPathsNoEscape` is not set, then both square-bracket escapes and * backslash escapes are removed. * * Slashes (and backslashes in `windowsPathsNoEscape` mode) cannot be escaped * or unescaped. * * When `magicalBraces` is not set, escapes of braces (`{` and `}`) will not be * unescaped. */ const unescape = (s, { windowsPathsNoEscape = false, magicalBraces = true, } = {}) => { if (magicalBraces) { return windowsPathsNoEscape ? s.replace(/\[([^\/\\])\]/g, '$1') : s .replace(/((?!\\).|^)\[([^\/\\])\]/g, '$1$2') .replace(/\\([^\/])/g, '$1'); } return windowsPathsNoEscape ? s.replace(/\[([^\/\\{}])\]/g, '$1') : s .replace(/((?!\\).|^)\[([^\/\\{}])\]/g, '$1$2') .replace(/\\([^\/{}])/g, '$1'); }; // parse a single path portion const types$1 = new Set(['!', '?', '+', '*', '@']); const isExtglobType = (c) => types$1.has(c); // Patterns that get prepended to bind to the start of either the // entire string, or just a single path portion, to prevent dots // and/or traversal patterns, when needed. // Exts don't need the ^ or / bit, because the root binds that already. const startNoTraversal = '(?!(?:^|/)\\.\\.?(?:$|/))'; const startNoDot = '(?!\\.)'; // characters that indicate a start of pattern needs the "no dots" bit, // because a dot *might* be matched. ( is not in the list, because in // the case of a child extglob, it will handle the prevention itself. const addPatternStart = new Set(['[', '.']); // cases where traversal is A-OK, no dot prevention needed const justDots = new Set(['..', '.']); const reSpecials = new Set('().*{}+?[]^$\\!'); const regExpEscape$1 = (s) => s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'); // any single thing other than / const qmark$1 = '[^/]'; // * => any number of characters const star$2 = qmark$1 + '*?'; // use + when we need to ensure that *something* matches, because the * is // the only thing in the path portion. const starNoEmpty = qmark$1 + '+?'; // remove the \ chars that we added if we end up doing a nonmagic compare // const deslash = (s: string) => s.replace(/\\(.)/g, '$1') class AST { type; #root; #hasMagic; #uflag = false; #parts = []; #parent; #parentIndex; #negs; #filledNegs = false; #options; #toString; // set to true if it's an extglob with no children // (which really means one child of '') #emptyExt = false; constructor(type, parent, options = {}) { this.type = type; // extglobs are inherently magical if (type) this.#hasMagic = true; this.#parent = parent; this.#root = this.#parent ? this.#parent.#root : this; this.#options = this.#root === this ? options : this.#root.#options; this.#negs = this.#root === this ? [] : this.#root.#negs; if (type === '!' && !this.#root.#filledNegs) this.#negs.push(this); this.#parentIndex = this.#parent ? this.#parent.#parts.length : 0; } get hasMagic() { /* c8 ignore start */ if (this.#hasMagic !== undefined) return this.#hasMagic; /* c8 ignore stop */ for (const p of this.#parts) { if (typeof p === 'string') continue; if (p.type || p.hasMagic) return (this.#hasMagic = true); } // note: will be undefined until we generate the regexp src and find out return this.#hasMagic; } // reconstructs the pattern toString() { if (this.#toString !== undefined) return this.#toString; if (!this.type) { return (this.#toString = this.#parts.map(p => String(p)).join('')); } else { return (this.#toString = this.type + '(' + this.#parts.map(p => String(p)).join('|') + ')'); } } #fillNegs() { /* c8 ignore start */ if (this !== this.#root) throw new Error('should only call on root'); if (this.#filledNegs) return this; /* c8 ignore stop */ // call toString() once to fill this out this.toString(); this.#filledNegs = true; let n; while ((n = this.#negs.pop())) { if (n.type !== '!') continue; // walk up the tree, appending everthing that comes AFTER parentIndex let p = n; let pp = p.#parent; while (pp) { for (let i = p.#parentIndex + 1; !pp.type && i < pp.#parts.length; i++) { for (const part of n.#parts) { /* c8 ignore start */ if (typeof part === 'string') { throw new Error('string part in extglob AST??'); } /* c8 ignore stop */ part.copyIn(pp.#parts[i]); } } p = pp; pp = p.#parent; } } return this; } push(...parts) { for (const p of parts) { if (p === '') continue; /* c8 ignore start */ if (typeof p !== 'string' && !(p instanceof AST && p.#parent === this)) { throw new Error('invalid part: ' + p); } /* c8 ignore stop */ this.#parts.push(p); } } toJSON() { const ret = this.type === null ? this.#parts.slice().map(p => (typeof p === 'string' ? p : p.toJSON())) : [this.type, ...this.#parts.map(p => p.toJSON())]; if (this.isStart() && !this.type) ret.unshift([]); if (this.isEnd() && (this === this.#root || (this.#root.#filledNegs && this.#parent?.type === '!'))) { ret.push({}); } return ret; } isStart() { if (this.#root === this) return true; // if (this.type) return !!this.#parent?.isStart() if (!this.#parent?.isStart()) return false; if (this.#parentIndex === 0) return true; // if everything AHEAD of this is a negation, then it's still the "start" const p = this.#parent; for (let i = 0; i < this.#parentIndex; i++) { const pp = p.#parts[i]; if (!(pp instanceof AST && pp.type === '!')) { return false; } } return true; } isEnd() { if (this.#root === this) return true; if (this.#parent?.type === '!') return true; if (!this.#parent?.isEnd()) return false; if (!this.type) return this.#parent?.isEnd(); // if not root, it'll always have a parent /* c8 ignore start */ const pl = this.#parent ? this.#parent.#parts.length : 0; /* c8 ignore stop */ return this.#parentIndex === pl - 1; } copyIn(part) { if (typeof part === 'string') this.push(part); else this.push(part.clone(this)); } clone(parent) { const c = new AST(this.type, parent); for (const p of this.#parts) { c.copyIn(p); } return c; } static #parseAST(str, ast, pos, opt) { let escaping = false; let inBrace = false; let braceStart = -1; let braceNeg = false; if (ast.type === null) { // outside of a extglob, append until we find a start let i = pos; let acc = ''; while (i < str.length) { const c = str.charAt(i++); // still accumulate escapes at this point, but we do ignore // starts that are escaped if (escaping || c === '\\') { escaping = !escaping; acc += c; continue; } if (inBrace) { if (i === braceStart + 1) { if (c === '^' || c === '!') { braceNeg = true; } } else if (c === ']' && !(i === braceStart + 2 && braceNeg)) { inBrace = false; } acc += c; continue; } else if (c === '[') { inBrace = true; braceStart = i; braceNeg = false; acc += c; continue; } if (!opt.noext && isExtglobType(c) && str.charAt(i) === '(') { ast.push(acc); acc = ''; const ext = new AST(c, ast); i = AST.#parseAST(str, ext, i, opt); ast.push(ext); continue; } acc += c; } ast.push(acc); return i; } // some kind of extglob, pos is at the ( // find the next | or ) let i = pos + 1; let part = new AST(null, ast); const parts = []; let acc = ''; while (i < str.length) { const c = str.charAt(i++); // still accumulate escapes at this point, but we do ignore // starts that are escaped if (escaping || c === '\\') { escaping = !escaping; acc += c; continue; } if (inBrace) { if (i === braceStart + 1) { if (c === '^' || c === '!') { braceNeg = true; } } else if (c === ']' && !(i === braceStart + 2 && braceNeg)) { inBrace = false; } acc += c; continue; } else if (c === '[') { inBrace = true; braceStart = i; braceNeg = false; acc += c; continue; } if (isExtglobType(c) && str.charAt(i) === '(') { part.push(acc); acc = ''; const ext = new AST(c, part); part.push(ext); i = AST.#parseAST(str, ext, i, opt); continue; } if (c === '|') { part.push(acc); acc = ''; parts.push(part); part = new AST(null, ast); continue; } if (c === ')') { if (acc === '' && ast.#parts.length === 0) { ast.#emptyExt = true; } part.push(acc); acc = ''; ast.push(...parts, part); return i; } acc += c; } // unfinished extglob // if we got here, it was a malformed extglob! not an extglob, but // maybe something else in there. ast.type = null; ast.#hasMagic = undefined; ast.#parts = [str.substring(pos - 1)]; return i; } static fromGlob(pattern, options = {}) { const ast = new AST(null, undefined, options); AST.#parseAST(pattern, ast, 0, options); return ast; } // returns the regular expression if there's magic, or the unescaped // string if not. toMMPattern() { // should only be called on root /* c8 ignore start */ if (this !== this.#root) return this.#root.toMMPattern(); /* c8 ignore stop */ const glob = this.toString(); const [re, body, hasMagic, uflag] = this.toRegExpSource(); // if we're in nocase mode, and not nocaseMagicOnly, then we do // still need a regular expression if we have to case-insensitively // match capital/lowercase characters. const anyMagic = hasMagic || this.#hasMagic || (this.#options.nocase && !this.#options.nocaseMagicOnly && glob.toUpperCase() !== glob.toLowerCase()); if (!anyMagic) { return body; } const flags = (this.#options.nocase ? 'i' : '') + (uflag ? 'u' : ''); return Object.assign(new RegExp(`^${re}$`, flags), { _src: re, _glob: glob, }); } get options() { return this.#options; } // returns the string match, the regexp source, whether there's magic // in the regexp (so a regular expression is required) and whether or // not the uflag is needed for the regular expression (for posix classes) // TODO: instead of injecting the start/end at this point, just return // the BODY of the regexp, along with the start/end portions suitable // for binding the start/end in either a joined full-path makeRe context // (where we bind to (^|/), or a standalone matchPart context (where // we bind to ^, and not /). Otherwise slashes get duped! // // In part-matching mode, the start is: // - if not isStart: nothing // - if traversal possible, but not allowed: ^(?!\.\.?$) // - if dots allowed or not possible: ^ // - if dots possible and not allowed: ^(?!\.) // end is: // - if not isEnd(): nothing // - else: $ // // In full-path matching mode, we put the slash at the START of the // pattern, so start is: // - if first pattern: same as part-matching mode // - if not isStart(): nothing // - if traversal possible, but not allowed: /(?!\.\.?(?:$|/)) // - if dots allowed or not possible: / // - if dots possible and not allowed: /(?!\.) // end is: // - if last pattern, same as part-matching mode // - else nothing // // Always put the (?:$|/) on negated tails, though, because that has to be // there to bind the end of the negated pattern portion, and it's easier to // just stick it in now rather than try to inject it later in the middle of // the pattern. // // We can just always return the same end, and leave it up to the caller // to know whether it's going to be used joined or in parts. // And, if the start is adjusted slightly, can do the same there: // - if not isStart: nothing // - if traversal possible, but not allowed: (?:/|^)(?!\.\.?$) // - if dots allowed or not possible: (?:/|^) // - if dots possible and not allowed: (?:/|^)(?!\.) // // But it's better to have a simpler binding without a conditional, for // performance, so probably better to return both start options. // // Then the caller just ignores the end if it's not the first pattern, // and the start always gets applied. // // But that's always going to be $ if it's the ending pattern, or nothing, // so the caller can just attach $ at the end of the pattern when building. // // So the todo is: // - better detect what kind of start is needed // - return both flavors of starting pattern // - attach $ at the end of the pattern when creating the actual RegExp // // Ah, but wait, no, that all only applies to the root when the first pattern // is not an extglob. If the first pattern IS an extglob, then we need all // that dot prevention biz to live in the extglob portions, because eg // +(*|.x*) can match .xy but not .yx. // // So, return the two flavors if it's #root and the first child is not an // AST, otherwise leave it to the child AST to handle it, and there, // use the (?:^|/) style of start binding. // // Even simplified further: // - Since the start for a join is eg /(?!\.) and the start for a part // is ^(?!\.), we can just prepend (?!\.) to the pattern (either root // or start or whatever) and prepend ^ or / at the Regexp construction. toRegExpSource(allowDot) { const dot = allowDot ?? !!this.#options.dot; if (this.#root === this) this.#fillNegs(); if (!this.type) { const noEmpty = this.isStart() && this.isEnd() && !this.#parts.some(s => typeof s !== 'string'); const src = this.#parts .map(p => { const [re, _, hasMagic, uflag] = typeof p === 'string' ? AST.#parseGlob(p, this.#hasMagic, noEmpty) : p.toRegExpSource(allowDot); this.#hasMagic = this.#hasMagic || hasMagic; this.#uflag = this.#uflag || uflag; return re; }) .join(''); let start = ''; if (this.isStart()) { if (typeof this.#parts[0] === 'string') { // this is the string that will match the start of the pattern, // so we need to protect against dots and such. // '.' and '..' cannot match unless the pattern is that exactly, // even if it starts with . or dot:true is set. const dotTravAllowed = this.#parts.length === 1 && justDots.has(this.#parts[0]); if (!dotTravAllowed) { const aps = addPatternStart; // check if we have a possibility of matching . or .., // and prevent that. const needNoTrav = // dots are allowed, and the pattern starts with [ or . (dot && aps.has(src.charAt(0))) || // the pattern starts with \., and then [ or . (src.startsWith('\\.') && aps.has(src.charAt(2))) || // the pattern starts with \.\., and then [ or . (src.startsWith('\\.\\.') && aps.has(src.charAt(4))); // no need to prevent dots if it can't match a dot, or if a // sub-pattern will be preventing it anyway. const needNoDot = !dot && !allowDot && aps.has(src.charAt(0)); start = needNoTrav ? startNoTraversal : needNoDot ? startNoDot : ''; } } } // append the "end of path portion" pattern to negation tails let end = ''; if (this.isEnd() && this.#root.#filledNegs && this.#parent?.type === '!') { end = '(?:$|\\/)'; } const final = start + src + end; return [ final, unescape(src), (this.#hasMagic = !!this.#hasMagic), this.#uflag, ]; } // We need to calculate the body *twice* if it's a repeat pattern // at the start, once in nodot mode, then again in dot mode, so a // pattern like *(?) can match 'x.y' const repeated = this.type === '*' || this.type === '+'; // some kind of extglob const start = this.type === '!' ? '(?:(?!(?:' : '(?:'; let body = this.#partsToRegExp(dot); if (this.isStart() && this.isEnd() && !body && this.type !== '!') { // invalid extglob, has to at least be *something* present, if it's // the entire path portion. const s = this.toString(); this.#parts = [s]; this.type = null; this.#hasMagic = undefined; return [s, unescape(this.toString()), false, false]; } // XXX abstract out this map method let bodyDotAllowed = !repeated || allowDot || dot || !startNoDot ? '' : this.#partsToRegExp(true); if (bodyDotAllowed === body) { bodyDotAllowed = ''; } if (bodyDotAllowed) { body = `(?:${body})(?:${bodyDotAllowed})*?`; } // an empty !() is exactly equivalent to a starNoEmpty let final = ''; if (this.type === '!' && this.#emptyExt) { final = (this.isStart() && !dot ? startNoDot : '') + starNoEmpty; } else { const close = this.type === '!' ? // !() must match something,but !(x) can match '' '))' + (this.isStart() && !dot && !allowDot ? startNoDot : '') + star$2 + ')' : this.type === '@' ? ')' : this.type === '?' ? ')?' : this.type === '+' && bodyDotAllowed ? ')' : this.type === '*' && bodyDotAllowed ? `)?` : `)${this.type}`; final = start + body + close; } return [ final, unescape(body), (this.#hasMagic = !!this.#hasMagic), this.#uflag, ]; } #partsToRegExp(dot) { return this.#parts .map(p => { // extglob ASTs should only contain parent ASTs /* c8 ignore start */ if (typeof p === 'string') { throw new Error('string type in extglob ast??'); } /* c8 ignore stop */ // can ignore hasMagic, because extglobs are already always magic const [re, _, _hasMagic, uflag] = p.toRegExpSource(dot); this.#uflag = this.#uflag || uflag; return re; }) .filter(p => !(this.isStart() && this.isEnd()) || !!p) .join('|'); } static #parseGlob(glob, hasMagic, noEmpty = false) { let escaping = false; let re = ''; let uflag = false; for (let i = 0; i < glob.length; i++) { const c = glob.charAt(i); if (escaping) { escaping = false; re += (reSpecials.has(c) ? '\\' : '') + c; continue; } if (c === '\\') { if (i === glob.length - 1) { re += '\\\\'; } else { escaping = true; } continue; } if (c === '[') { const [src, needUflag, consumed, magic] = parseClass(glob, i); if (consumed) { re += src; uflag = uflag || needUflag; i += consumed - 1; hasMagic = hasMagic || magic; continue; } } if (c === '*') { re += noEmpty && glob === '*' ? starNoEmpty : star$2; hasMagic = true; continue; } if (c === '?') { re += qmark$1; hasMagic = true; continue; } re += regExpEscape$1(c); } return [re, unescape(glob), !!hasMagic, uflag]; } } /** * Escape all magic characters in a glob pattern. * * If the {@link MinimatchOptions.windowsPathsNoEscape} * option is used, then characters are escaped by wrapping in `[]`, because * a magic character wrapped in a character class can only be satisfied by * that exact character. In this mode, `\` is _not_ escaped, because it is * not interpreted as a magic character, but instead as a path separator. * * If the {@link MinimatchOptions.magicalBraces} option is used, * then braces (`{` and `}`) will be escaped. */ const escape$1 = (s, { windowsPathsNoEscape = false, magicalBraces = false, } = {}) => { // don't need to escape +@! because we escape the parens // that make those magic, and escaping ! as [!] isn't valid, // because [!]] is a valid glob class meaning not ']'. if (magicalBraces) { return windowsPathsNoEscape ? s.replace(/[?*()[\]{}]/g, '[$&]') : s.replace(/[?*()[\]\\{}]/g, '\\$&'); } return windowsPathsNoEscape ? s.replace(/[?*()[\]]/g, '[$&]') : s.replace(/[?*()[\]\\]/g, '\\$&'); }; const minimatch = (p, pattern, options = {}) => { assertValidPattern(pattern); // shortcut: comments match nothing. if (!options.nocomment && pattern.charAt(0) === '#') { return false; } return new Minimatch(pattern, options).match(p); }; // Optimized checking for the most common glob patterns. const starDotExtRE = /^\*+([^+@!?\*\[\(]*)$/; const starDotExtTest = (ext) => (f) => !f.startsWith('.') && f.endsWith(ext); const starDotExtTestDot = (ext) => (f) => f.endsWith(ext); const starDotExtTestNocase = (ext) => { ext = ext.toLowerCase(); return (f) => !f.startsWith('.') && f.toLowerCase().endsWith(ext); }; const starDotExtTestNocaseDot = (ext) => { ext = ext.toLowerCase(); return (f) => f.toLowerCase().endsWith(ext); }; const starDotStarRE = /^\*+\.\*+$/; const starDotStarTest = (f) => !f.startsWith('.') && f.includes('.'); const starDotStarTestDot = (f) => f !== '.' && f !== '..' && f.includes('.'); const dotStarRE = /^\.\*+$/; const dotStarTest = (f) => f !== '.' && f !== '..' && f.startsWith('.'); const starRE = /^\*+$/; const starTest = (f) => f.length !== 0 && !f.startsWith('.'); const starTestDot = (f) => f.length !== 0 && f !== '.' && f !== '..'; const qmarksRE = /^\?+([^+@!?\*\[\(]*)?$/; const qmarksTestNocase = ([$0, ext = '']) => { const noext = qmarksTestNoExt([$0]); if (!ext) return noext; ext = ext.toLowerCase(); return (f) => noext(f) && f.toLowerCase().endsWith(ext); }; const qmarksTestNocaseDot = ([$0, ext = '']) => { const noext = qmarksTestNoExtDot([$0]); if (!ext) return noext; ext = ext.toLowerCase(); return (f) => noext(f) && f.toLowerCase().endsWith(ext); }; const qmarksTestDot = ([$0, ext = '']) => { const noext = qmarksTestNoExtDot([$0]); return !ext ? noext : (f) => noext(f) && f.endsWith(ext); }; const qmarksTest = ([$0, ext = '']) => { const noext = qmarksTestNoExt([$0]); return !ext ? noext : (f) => noext(f) && f.endsWith(ext); }; const qmarksTestNoExt = ([$0]) => { const len = $0.length; return (f) => f.length === len && !f.startsWith('.'); }; const qmarksTestNoExtDot = ([$0]) => { const len = $0.length; return (f) => f.length === len && f !== '.' && f !== '..'; }; /* c8 ignore start */ const defaultPlatform$2 = (typeof process === 'object' && process ? (typeof process.env === 'object' && process.env && process.env.__MINIMATCH_TESTING_PLATFORM__) || process.platform : 'posix'); const path = { win32: { sep: '\\' }, posix: { sep: '/' }, }; /* c8 ignore stop */ const sep = defaultPlatform$2 === 'win32' ? path.win32.sep : path.posix.sep; minimatch.sep = sep; const GLOBSTAR = Symbol('globstar **'); minimatch.GLOBSTAR = GLOBSTAR; // any single thing other than / // don't need to escape / when using new RegExp() const qmark = '[^/]'; // * => any number of characters const star$1 = qmark + '*?'; // ** when dots are allowed. Anything goes, except .. and . // not (^ or / followed by one or two dots followed by $ or /), // followed by anything, any number of times. const twoStarDot = '(?:(?!(?:\\/|^)(?:\\.{1,2})($|\\/)).)*?'; // not a ^ or / followed by a dot, // followed by anything, any number of times. const twoStarNoDot = '(?:(?!(?:\\/|^)\\.).)*?'; const filter = (pattern, options = {}) => (p) => minimatch(p, pattern, options); minimatch.filter = filter; const ext = (a, b = {}) => Object.assign({}, a, b); const defaults$1 = (def) => { if (!def || typeof def !== 'object' || !Object.keys(def).length) { return minimatch; } const orig = minimatch; const m = (p, pattern, options = {}) => orig(p, pattern, ext(def, options)); return Object.assign(m, { Minimatch: class Minimatch extends orig.Minimatch { constructor(pattern, options = {}) { super(pattern, ext(def, options)); } static defaults(options) { return orig.defaults(ext(def, options)).Minimatch; } }, AST: class AST extends orig.AST { /* c8 ignore start */ constructor(type, parent, options = {}) { super(type, parent, ext(def, options)); } /* c8 ignore stop */ static fromGlob(pattern, options = {}) { return orig.AST.fromGlob(pattern, ext(def, options)); } }, unescape: (s, options = {}) => orig.unescape(s, ext(def, options)), escape: (s, options = {}) => orig.escape(s, ext(def, options)), filter: (pattern, options = {}) => orig.filter(pattern, ext(def, options)), defaults: (options) => orig.defaults(ext(def, options)), makeRe: (pattern, options = {}) => orig.makeRe(pattern, ext(def, options)), braceExpand: (pattern, options = {}) => orig.braceExpand(pattern, ext(def, options)), match: (list, pattern, options = {}) => orig.match(list, pattern, ext(def, options)), sep: orig.sep, GLOBSTAR: GLOBSTAR, }); }; minimatch.defaults = defaults$1; // Brace expansion: // a{b,c}d -> abd acd // a{b,}c -> abc ac // a{0..3}d -> a0d a1d a2d a3d // a{b,c{d,e}f}g -> abg acdfg acefg // a{b,c}d{e,f}g -> abdeg acdeg abdeg abdfg // // Invalid sets are not expanded. // a{2..}b -> a{2..}b // a{b}c -> a{b}c const braceExpand = (pattern, options = {}) => { assertValidPattern(pattern); // Thanks to Yeting Li for // improving this regexp to avoid a ReDOS vulnerability. if (options.nobrace || !/\{(?:(?!\{).)*\}/.test(pattern)) { // shortcut. no need to expand. return [pattern]; } return expand(pattern); }; minimatch.braceExpand = braceExpand; // parse a component of the expanded set. // At this point, no pattern may contain "/" in it // so we're going to return a 2d array, where each entry is the full // pattern, split on '/', and then turned into a regular expression. // A regexp is made at the end which joins each array with an // escaped /, and another full one which joins each regexp with |. // // Following the lead of Bash 4.1, note that "**" only has special meaning // when it is the *only* thing in a path portion. Otherwise, any series // of * is equivalent to a single *. Globstar behavior is enabled by // default, and can be disabled by setting options.noglobstar. const makeRe = (pattern, options = {}) => new Minimatch(pattern, options).makeRe(); minimatch.makeRe = makeRe; const match$1 = (list, pattern, options = {}) => { const mm = new Minimatch(pattern, options); list = list.filter(f => mm.match(f)); if (mm.options.nonull && !list.length) { list.push(pattern); } return list; }; minimatch.match = match$1; // replace stuff like \* with * const globMagic = /[?*]|[+@!]\(.*?\)|\[|\]/; const regExpEscape = (s) => s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'); class Minimatch { options; set; pattern; windowsPathsNoEscape; nonegate; negate; comment; empty; preserveMultipleSlashes; partial; globSet; globParts; nocase; isWindows; platform; windowsNoMagicRoot; regexp; constructor(pattern, options = {}) { assertValidPattern(pattern); options = options || {}; this.options = options; this.pattern = pattern; this.platform = options.platform || defaultPlatform$2; this.isWindows = this.platform === 'win32'; this.windowsPathsNoEscape = !!options.windowsPathsNoEscape || options.allowWindowsEscape === false; if (this.windowsPathsNoEscape) { this.pattern = this.pattern.replace(/\\/g, '/'); } this.preserveMultipleSlashes = !!options.preserveMultipleSlashes; this.regexp = null; this.negate = false; this.nonegate = !!options.nonegate; this.comment = false; this.empty = false; this.partial = !!options.partial; this.nocase = !!this.options.nocase; this.windowsNoMagicRoot = options.windowsNoMagicRoot !== undefined ? options.windowsNoMagicRoot : !!(this.isWindows && this.nocase); this.globSet = []; this.globParts = []; this.set = []; // make the set of regexps etc. this.make(); } hasMagic() { if (this.options.magicalBraces && this.set.length > 1) { return true; } for (const pattern of this.set) { for (const part of pattern) { if (typeof part !== 'string') return true; } } return false; } debug(..._) { } make() { const pattern = this.pattern; const options = this.options; // empty patterns and comments match nothing. if (!options.nocomment && pattern.charAt(0) === '#') { this.comment = true; return; } if (!pattern) { this.empty = true; return; } // step 1: figure out negation, etc. this.parseNegate(); // step 2: expand braces this.globSet = [...new Set(this.braceExpand())]; if (options.debug) { this.debug = (...args) => console.error(...args); } this.debug(this.pattern, this.globSet); // step 3: now we have a set, so turn each one into a series of // path-portion matching patterns. // These will be regexps, except in the case of "**", which is // set to the GLOBSTAR object for globstar behavior, // and will not contain any / characters // // First, we preprocess to make the glob pattern sets a bit simpler // and deduped. There are some perf-killing patterns that can cause // problems with a glob walk, but we can simplify them down a bit. const rawGlobParts = this.globSet.map(s => this.slashSplit(s)); this.globParts = this.preprocess(rawGlobParts); this.debug(this.pattern, this.globParts); // glob --> regexps let set = this.globParts.map((s, _, __) => { if (this.isWindows && this.windowsNoMagicRoot) { // check if it's a drive or unc path. const isUNC = s[0] === '' && s[1] === '' && (s[2] === '?' || !globMagic.test(s[2])) && !globMagic.test(s[3]); const isDrive = /^[a-z]:/i.test(s[0]); if (isUNC) { return [...s.slice(0, 4), ...s.slice(4).map(ss => this.parse(ss))]; } else if (isDrive) { return [s[0], ...s.slice(1).map(ss => this.parse(ss))]; } } return s.map(ss => this.parse(ss)); }); this.debug(this.pattern, set); // filter out everything that didn't compile properly. this.set = set.filter(s => s.indexOf(false) === -1); // do not treat the ? in UNC paths as magic if (this.isWindows) { for (let i = 0; i < this.set.length; i++) { const p = this.set[i]; if (p[0] === '' && p[1] === '' && this.globParts[i][2] === '?' && typeof p[3] === 'string' && /^[a-z]:$/i.test(p[3])) { p[2] = '?'; } } } this.debug(this.pattern, this.set); } // various transforms to equivalent pattern sets that are // faster to process in a filesystem walk. The goal is to // eliminate what we can, and push all ** patterns as far // to the right as possible, even if it increases the number // of patterns that we have to process. preprocess(globParts) { // if we're not in globstar mode, then turn all ** into * if (this.options.noglobstar) { for (let i = 0; i < globParts.length; i++) { for (let j = 0; j < globParts[i].length; j++) { if (globParts[i][j] === '**') { globParts[i][j] = '*'; } } } } const { optimizationLevel = 1 } = this.options; if (optimizationLevel >= 2) { // aggressive optimization for the purpose of fs walking globParts = this.firstPhasePreProcess(globParts); globParts = this.secondPhasePreProcess(globParts); } else if (optimizationLevel >= 1) { // just basic optimizations to remove some .. parts globParts = this.levelOneOptimize(globParts); } else { // just collapse multiple ** portions into one globParts = this.adjascentGlobstarOptimize(globParts); } return globParts; } // just get rid of adjascent ** portions adjascentGlobstarOptimize(globParts) { return globParts.map(parts => { let gs = -1; while (-1 !== (gs = parts.indexOf('**', gs + 1))) { let i = gs; while (parts[i + 1] === '**') { i++; } if (i !== gs) { parts.splice(gs, i - gs); } } return parts; }); } // get rid of adjascent ** and resolve .. portions levelOneOptimize(globParts) { return globParts.map(parts => { parts = parts.reduce((set, part) => { const prev = set[set.length - 1]; if (part === '**' && prev === '**') { return set; } if (part === '..') { if (prev && prev !== '..' && prev !== '.' && prev !== '**') { set.pop(); return set; } } set.push(part); return set; }, []); return parts.length === 0 ? [''] : parts; }); } levelTwoFileOptimize(parts) { if (!Array.isArray(parts)) { parts = this.slashSplit(parts); } let didSomething = false; do { didSomething = false; //
// -> 
/
            if (!this.preserveMultipleSlashes) {
                for (let i = 1; i < parts.length - 1; i++) {
                    const p = parts[i];
                    // don't squeeze out UNC patterns
                    if (i === 1 && p === '' && parts[0] === '')
                        continue;
                    if (p === '.' || p === '') {
                        didSomething = true;
                        parts.splice(i, 1);
                        i--;
                    }
                }
                if (parts[0] === '.' &&
                    parts.length === 2 &&
                    (parts[1] === '.' || parts[1] === '')) {
                    didSomething = true;
                    parts.pop();
                }
            }
            // 
/

/../ ->

/
            let dd = 0;
            while (-1 !== (dd = parts.indexOf('..', dd + 1))) {
                const p = parts[dd - 1];
                if (p && p !== '.' && p !== '..' && p !== '**') {
                    didSomething = true;
                    parts.splice(dd - 1, 2);
                    dd -= 2;
                }
            }
        } while (didSomething);
        return parts.length === 0 ? [''] : parts;
    }
    // First phase: single-pattern processing
    // 
 is 1 or more portions
    //  is 1 or more portions
    // 

is any portion other than ., .., '', or ** // is . or '' // // **/.. is *brutal* for filesystem walking performance, because // it effectively resets the recursive walk each time it occurs, // and ** cannot be reduced out by a .. pattern part like a regexp // or most strings (other than .., ., and '') can be. // //

/**/../

/

/ -> {

/../

/

/,

/**/

/

/} //

// -> 
/
    // 
/

/../ ->

/
    // **/**/ -> **/
    //
    // **/*/ -> */**/ <== not valid because ** doesn't follow
    // this WOULD be allowed if ** did follow symlinks, or * didn't
    firstPhasePreProcess(globParts) {
        let didSomething = false;
        do {
            didSomething = false;
            // 
/**/../

/

/ -> {

/../

/

/,

/**/

/

/} for (let parts of globParts) { let gs = -1; while (-1 !== (gs = parts.indexOf('**', gs + 1))) { let gss = gs; while (parts[gss + 1] === '**') { //

/**/**/ -> 
/**/
                        gss++;
                    }
                    // eg, if gs is 2 and gss is 4, that means we have 3 **
                    // parts, and can remove 2 of them.
                    if (gss > gs) {
                        parts.splice(gs + 1, gss - gs);
                    }
                    let next = parts[gs + 1];
                    const p = parts[gs + 2];
                    const p2 = parts[gs + 3];
                    if (next !== '..')
                        continue;
                    if (!p ||
                        p === '.' ||
                        p === '..' ||
                        !p2 ||
                        p2 === '.' ||
                        p2 === '..') {
                        continue;
                    }
                    didSomething = true;
                    // edit parts in place, and push the new one
                    parts.splice(gs, 1);
                    const other = parts.slice(0);
                    other[gs] = '**';
                    globParts.push(other);
                    gs--;
                }
                // 
// -> 
/
                if (!this.preserveMultipleSlashes) {
                    for (let i = 1; i < parts.length - 1; i++) {
                        const p = parts[i];
                        // don't squeeze out UNC patterns
                        if (i === 1 && p === '' && parts[0] === '')
                            continue;
                        if (p === '.' || p === '') {
                            didSomething = true;
                            parts.splice(i, 1);
                            i--;
                        }
                    }
                    if (parts[0] === '.' &&
                        parts.length === 2 &&
                        (parts[1] === '.' || parts[1] === '')) {
                        didSomething = true;
                        parts.pop();
                    }
                }
                // 
/

/../ ->

/
                let dd = 0;
                while (-1 !== (dd = parts.indexOf('..', dd + 1))) {
                    const p = parts[dd - 1];
                    if (p && p !== '.' && p !== '..' && p !== '**') {
                        didSomething = true;
                        const needDot = dd === 1 && parts[dd + 1] === '**';
                        const splin = needDot ? ['.'] : [];
                        parts.splice(dd - 1, 2, ...splin);
                        if (parts.length === 0)
                            parts.push('');
                        dd -= 2;
                    }
                }
            }
        } while (didSomething);
        return globParts;
    }
    // second phase: multi-pattern dedupes
    // {
/*/,
/

/} ->

/*/
    // {
/,
/} -> 
/
    // {
/**/,
/} -> 
/**/
    //
    // {
/**/,
/**/

/} ->

/**/
    // ^-- not valid because ** doens't follow symlinks
    secondPhasePreProcess(globParts) {
        for (let i = 0; i < globParts.length - 1; i++) {
            for (let j = i + 1; j < globParts.length; j++) {
                const matched = this.partsMatch(globParts[i], globParts[j], !this.preserveMultipleSlashes);
                if (matched) {
                    globParts[i] = [];
                    globParts[j] = matched;
                    break;
                }
            }
        }
        return globParts.filter(gs => gs.length);
    }
    partsMatch(a, b, emptyGSMatch = false) {
        let ai = 0;
        let bi = 0;
        let result = [];
        let which = '';
        while (ai < a.length && bi < b.length) {
            if (a[ai] === b[bi]) {
                result.push(which === 'b' ? b[bi] : a[ai]);
                ai++;
                bi++;
            }
            else if (emptyGSMatch && a[ai] === '**' && b[bi] === a[ai + 1]) {
                result.push(a[ai]);
                ai++;
            }
            else if (emptyGSMatch && b[bi] === '**' && a[ai] === b[bi + 1]) {
                result.push(b[bi]);
                bi++;
            }
            else if (a[ai] === '*' &&
                b[bi] &&
                (this.options.dot || !b[bi].startsWith('.')) &&
                b[bi] !== '**') {
                if (which === 'b')
                    return false;
                which = 'a';
                result.push(a[ai]);
                ai++;
                bi++;
            }
            else if (b[bi] === '*' &&
                a[ai] &&
                (this.options.dot || !a[ai].startsWith('.')) &&
                a[ai] !== '**') {
                if (which === 'a')
                    return false;
                which = 'b';
                result.push(b[bi]);
                ai++;
                bi++;
            }
            else {
                return false;
            }
        }
        // if we fall out of the loop, it means they two are identical
        // as long as their lengths match
        return a.length === b.length && result;
    }
    parseNegate() {
        if (this.nonegate)
            return;
        const pattern = this.pattern;
        let negate = false;
        let negateOffset = 0;
        for (let i = 0; i < pattern.length && pattern.charAt(i) === '!'; i++) {
            negate = !negate;
            negateOffset++;
        }
        if (negateOffset)
            this.pattern = pattern.slice(negateOffset);
        this.negate = negate;
    }
    // set partial to true to test if, for example,
    // "/a/b" matches the start of "/*/b/*/d"
    // Partial means, if you run out of file before you run
    // out of pattern, then that's fine, as long as all
    // the parts match.
    matchOne(file, pattern, partial = false) {
        const options = this.options;
        // UNC paths like //?/X:/... can match X:/... and vice versa
        // Drive letters in absolute drive or unc paths are always compared
        // case-insensitively.
        if (this.isWindows) {
            const fileDrive = typeof file[0] === 'string' && /^[a-z]:$/i.test(file[0]);
            const fileUNC = !fileDrive &&
                file[0] === '' &&
                file[1] === '' &&
                file[2] === '?' &&
                /^[a-z]:$/i.test(file[3]);
            const patternDrive = typeof pattern[0] === 'string' && /^[a-z]:$/i.test(pattern[0]);
            const patternUNC = !patternDrive &&
                pattern[0] === '' &&
                pattern[1] === '' &&
                pattern[2] === '?' &&
                typeof pattern[3] === 'string' &&
                /^[a-z]:$/i.test(pattern[3]);
            const fdi = fileUNC ? 3 : fileDrive ? 0 : undefined;
            const pdi = patternUNC ? 3 : patternDrive ? 0 : undefined;
            if (typeof fdi === 'number' && typeof pdi === 'number') {
                const [fd, pd] = [file[fdi], pattern[pdi]];
                if (fd.toLowerCase() === pd.toLowerCase()) {
                    pattern[pdi] = fd;
                    if (pdi > fdi) {
                        pattern = pattern.slice(pdi);
                    }
                    else if (fdi > pdi) {
                        file = file.slice(fdi);
                    }
                }
            }
        }
        // resolve and reduce . and .. portions in the file as well.
        // don't need to do the second phase, because it's only one string[]
        const { optimizationLevel = 1 } = this.options;
        if (optimizationLevel >= 2) {
            file = this.levelTwoFileOptimize(file);
        }
        this.debug('matchOne', this, { file, pattern });
        this.debug('matchOne', file.length, pattern.length);
        for (var fi = 0, pi = 0, fl = file.length, pl = pattern.length; fi < fl && pi < pl; fi++, pi++) {
            this.debug('matchOne loop');
            var p = pattern[pi];
            var f = file[fi];
            this.debug(pattern, p, f);
            // should be impossible.
            // some invalid regexp stuff in the set.
            /* c8 ignore start */
            if (p === false) {
                return false;
            }
            /* c8 ignore stop */
            if (p === GLOBSTAR) {
                this.debug('GLOBSTAR', [pattern, p, f]);
                // "**"
                // a/**/b/**/c would match the following:
                // a/b/x/y/z/c
                // a/x/y/z/b/c
                // a/b/x/b/x/c
                // a/b/c
                // To do this, take the rest of the pattern after
                // the **, and see if it would match the file remainder.
                // If so, return success.
                // If not, the ** "swallows" a segment, and try again.
                // This is recursively awful.
                //
                // a/**/b/**/c matching a/b/x/y/z/c
                // - a matches a
                // - doublestar
                //   - matchOne(b/x/y/z/c, b/**/c)
                //     - b matches b
                //     - doublestar
                //       - matchOne(x/y/z/c, c) -> no
                //       - matchOne(y/z/c, c) -> no
                //       - matchOne(z/c, c) -> no
                //       - matchOne(c, c) yes, hit
                var fr = fi;
                var pr = pi + 1;
                if (pr === pl) {
                    this.debug('** at the end');
                    // a ** at the end will just swallow the rest.
                    // We have found a match.
                    // however, it will not swallow /.x, unless
                    // options.dot is set.
                    // . and .. are *never* matched by **, for explosively
                    // exponential reasons.
                    for (; fi < fl; fi++) {
                        if (file[fi] === '.' ||
                            file[fi] === '..' ||
                            (!options.dot && file[fi].charAt(0) === '.'))
                            return false;
                    }
                    return true;
                }
                // ok, let's see if we can swallow whatever we can.
                while (fr < fl) {
                    var swallowee = file[fr];
                    this.debug('\nglobstar while', file, fr, pattern, pr, swallowee);
                    // XXX remove this slice.  Just pass the start index.
                    if (this.matchOne(file.slice(fr), pattern.slice(pr), partial)) {
                        this.debug('globstar found match!', fr, fl, swallowee);
                        // found a match.
                        return true;
                    }
                    else {
                        // can't swallow "." or ".." ever.
                        // can only swallow ".foo" when explicitly asked.
                        if (swallowee === '.' ||
                            swallowee === '..' ||
                            (!options.dot && swallowee.charAt(0) === '.')) {
                            this.debug('dot detected!', file, fr, pattern, pr);
                            break;
                        }
                        // ** swallows a segment, and continue.
                        this.debug('globstar swallow a segment, and continue');
                        fr++;
                    }
                }
                // no match was found.
                // However, in partial mode, we can't say this is necessarily over.
                /* c8 ignore start */
                if (partial) {
                    // ran out of file
                    this.debug('\n>>> no match, partial?', file, fr, pattern, pr);
                    if (fr === fl) {
                        return true;
                    }
                }
                /* c8 ignore stop */
                return false;
            }
            // something other than **
            // non-magic patterns just have to match exactly
            // patterns with magic have been turned into regexps.
            let hit;
            if (typeof p === 'string') {
                hit = f === p;
                this.debug('string match', p, f, hit);
            }
            else {
                hit = p.test(f);
                this.debug('pattern match', p, f, hit);
            }
            if (!hit)
                return false;
        }
        // Note: ending in / means that we'll get a final ""
        // at the end of the pattern.  This can only match a
        // corresponding "" at the end of the file.
        // If the file ends in /, then it can only match a
        // a pattern that ends in /, unless the pattern just
        // doesn't have any more for it. But, a/b/ should *not*
        // match "a/b/*", even though "" matches against the
        // [^/]*? pattern, except in partial mode, where it might
        // simply not be reached yet.
        // However, a/b/ should still satisfy a/*
        // now either we fell off the end of the pattern, or we're done.
        if (fi === fl && pi === pl) {
            // ran out of pattern and filename at the same time.
            // an exact hit!
            return true;
        }
        else if (fi === fl) {
            // ran out of file, but still had pattern left.
            // this is ok if we're doing the match as part of
            // a glob fs traversal.
            return partial;
        }
        else if (pi === pl) {
            // ran out of pattern, still have file left.
            // this is only acceptable if we're on the very last
            // empty segment of a file with a trailing slash.
            // a/* should match a/b/
            return fi === fl - 1 && file[fi] === '';
            /* c8 ignore start */
        }
        else {
            // should be unreachable.
            throw new Error('wtf?');
        }
        /* c8 ignore stop */
    }
    braceExpand() {
        return braceExpand(this.pattern, this.options);
    }
    parse(pattern) {
        assertValidPattern(pattern);
        const options = this.options;
        // shortcuts
        if (pattern === '**')
            return GLOBSTAR;
        if (pattern === '')
            return '';
        // far and away, the most common glob pattern parts are
        // *, *.*, and *.  Add a fast check method for those.
        let m;
        let fastTest = null;
        if ((m = pattern.match(starRE))) {
            fastTest = options.dot ? starTestDot : starTest;
        }
        else if ((m = pattern.match(starDotExtRE))) {
            fastTest = (options.nocase
                ? options.dot
                    ? starDotExtTestNocaseDot
                    : starDotExtTestNocase
                : options.dot
                    ? starDotExtTestDot
                    : starDotExtTest)(m[1]);
        }
        else if ((m = pattern.match(qmarksRE))) {
            fastTest = (options.nocase
                ? options.dot
                    ? qmarksTestNocaseDot
                    : qmarksTestNocase
                : options.dot
                    ? qmarksTestDot
                    : qmarksTest)(m);
        }
        else if ((m = pattern.match(starDotStarRE))) {
            fastTest = options.dot ? starDotStarTestDot : starDotStarTest;
        }
        else if ((m = pattern.match(dotStarRE))) {
            fastTest = dotStarTest;
        }
        const re = AST.fromGlob(pattern, this.options).toMMPattern();
        if (fastTest && typeof re === 'object') {
            // Avoids overriding in frozen environments
            Reflect.defineProperty(re, 'test', { value: fastTest });
        }
        return re;
    }
    makeRe() {
        if (this.regexp || this.regexp === false)
            return this.regexp;
        // at this point, this.set is a 2d array of partial
        // pattern strings, or "**".
        //
        // It's better to use .match().  This function shouldn't
        // be used, really, but it's pretty convenient sometimes,
        // when you just want to work with a regex.
        const set = this.set;
        if (!set.length) {
            this.regexp = false;
            return this.regexp;
        }
        const options = this.options;
        const twoStar = options.noglobstar
            ? star$1
            : options.dot
                ? twoStarDot
                : twoStarNoDot;
        const flags = new Set(options.nocase ? ['i'] : []);
        // regexpify non-globstar patterns
        // if ** is only item, then we just do one twoStar
        // if ** is first, and there are more, prepend (\/|twoStar\/)? to next
        // if ** is last, append (\/twoStar|) to previous
        // if ** is in the middle, append (\/|\/twoStar\/) to previous
        // then filter out GLOBSTAR symbols
        let re = set
            .map(pattern => {
            const pp = pattern.map(p => {
                if (p instanceof RegExp) {
                    for (const f of p.flags.split(''))
                        flags.add(f);
                }
                return typeof p === 'string'
                    ? regExpEscape(p)
                    : p === GLOBSTAR
                        ? GLOBSTAR
                        : p._src;
            });
            pp.forEach((p, i) => {
                const next = pp[i + 1];
                const prev = pp[i - 1];
                if (p !== GLOBSTAR || prev === GLOBSTAR) {
                    return;
                }
                if (prev === undefined) {
                    if (next !== undefined && next !== GLOBSTAR) {
                        pp[i + 1] = '(?:\\/|' + twoStar + '\\/)?' + next;
                    }
                    else {
                        pp[i] = twoStar;
                    }
                }
                else if (next === undefined) {
                    pp[i - 1] = prev + '(?:\\/|\\/' + twoStar + ')?';
                }
                else if (next !== GLOBSTAR) {
                    pp[i - 1] = prev + '(?:\\/|\\/' + twoStar + '\\/)' + next;
                    pp[i + 1] = GLOBSTAR;
                }
            });
            const filtered = pp.filter(p => p !== GLOBSTAR);
            // For partial matches, we need to make the pattern match
            // any prefix of the full path. We do this by generating
            // alternative patterns that match progressively longer prefixes.
            if (this.partial && filtered.length >= 1) {
                const prefixes = [];
                for (let i = 1; i <= filtered.length; i++) {
                    prefixes.push(filtered.slice(0, i).join('/'));
                }
                return '(?:' + prefixes.join('|') + ')';
            }
            return filtered.join('/');
        })
            .join('|');
        // need to wrap in parens if we had more than one thing with |,
        // otherwise only the first will be anchored to ^ and the last to $
        const [open, close] = set.length > 1 ? ['(?:', ')'] : ['', ''];
        // must match entire pattern
        // ending in a * or ** will make it less strict.
        re = '^' + open + re + close + '$';
        // In partial mode, '/' should always match as it's a valid prefix for any pattern
        if (this.partial) {
            re = '^(?:\\/|' + open + re.slice(1, -1) + close + ')$';
        }
        // can match anything, as long as it's not this.
        if (this.negate)
            re = '^(?!' + re + ').+$';
        try {
            this.regexp = new RegExp(re, [...flags].join(''));
            /* c8 ignore start */
        }
        catch (ex) {
            // should be impossible
            this.regexp = false;
        }
        /* c8 ignore stop */
        return this.regexp;
    }
    slashSplit(p) {
        // if p starts with // on windows, we preserve that
        // so that UNC paths aren't broken.  Otherwise, any number of
        // / characters are coalesced into one, unless
        // preserveMultipleSlashes is set to true.
        if (this.preserveMultipleSlashes) {
            return p.split('/');
        }
        else if (this.isWindows && /^\/\/[^\/]+/.test(p)) {
            // add an extra '' for the one we lose
            return ['', ...p.split(/\/+/)];
        }
        else {
            return p.split(/\/+/);
        }
    }
    match(f, partial = this.partial) {
        this.debug('match', f, this.pattern);
        // short-circuit in the case of busted things.
        // comments, etc.
        if (this.comment) {
            return false;
        }
        if (this.empty) {
            return f === '';
        }
        if (f === '/' && partial) {
            return true;
        }
        const options = this.options;
        // windows: need to use /, not \
        if (this.isWindows) {
            f = f.split('\\').join('/');
        }
        // treat the test path as a set of pathparts.
        const ff = this.slashSplit(f);
        this.debug(this.pattern, 'split', ff);
        // just ONE of the pattern sets in this.set needs to match
        // in order for it to be valid.  If negating, then just one
        // match means that we have failed.
        // Either way, return on the first hit.
        const set = this.set;
        this.debug(this.pattern, 'set', set);
        // Find the basename of the path by looking for the last non-empty segment
        let filename = ff[ff.length - 1];
        if (!filename) {
            for (let i = ff.length - 2; !filename && i >= 0; i--) {
                filename = ff[i];
            }
        }
        for (let i = 0; i < set.length; i++) {
            const pattern = set[i];
            let file = ff;
            if (options.matchBase && pattern.length === 1) {
                file = [filename];
            }
            const hit = this.matchOne(file, pattern, partial);
            if (hit) {
                if (options.flipNegate) {
                    return true;
                }
                return !this.negate;
            }
        }
        // didn't get any hits.  this is success if it's a negative
        // pattern, failure otherwise.
        if (options.flipNegate) {
            return false;
        }
        return this.negate;
    }
    static defaults(def) {
        return minimatch.defaults(def).Minimatch;
    }
}
/* c8 ignore stop */
minimatch.AST = AST;
minimatch.Minimatch = Minimatch;
minimatch.escape = escape$1;
minimatch.unescape = unescape;

/**
 * @module LRUCache
 */
const defaultPerf = (typeof performance === 'object' &&
    performance &&
    typeof performance.now === 'function') ?
    performance
    : Date;
const warned = new Set();
/* c8 ignore start */
const PROCESS = (typeof process === 'object' && !!process ?
    process
    : {});
/* c8 ignore start */
const emitWarning = (msg, type, code, fn) => {
    typeof PROCESS.emitWarning === 'function' ?
        PROCESS.emitWarning(msg, type, code, fn)
        : console.error(`[${code}] ${type}: ${msg}`);
};
let AC = globalThis.AbortController;
let AS = globalThis.AbortSignal;
/* c8 ignore start */
if (typeof AC === 'undefined') {
    //@ts-ignore
    AS = class AbortSignal {
        onabort;
        _onabort = [];
        reason;
        aborted = false;
        addEventListener(_, fn) {
            this._onabort.push(fn);
        }
    };
    //@ts-ignore
    AC = class AbortController {
        constructor() {
            warnACPolyfill();
        }
        signal = new AS();
        abort(reason) {
            if (this.signal.aborted)
                return;
            //@ts-ignore
            this.signal.reason = reason;
            //@ts-ignore
            this.signal.aborted = true;
            //@ts-ignore
            for (const fn of this.signal._onabort) {
                fn(reason);
            }
            this.signal.onabort?.(reason);
        }
    };
    let printACPolyfillWarning = PROCESS.env?.LRU_CACHE_IGNORE_AC_WARNING !== '1';
    const warnACPolyfill = () => {
        if (!printACPolyfillWarning)
            return;
        printACPolyfillWarning = false;
        emitWarning('AbortController is not defined. If using lru-cache in ' +
            'node 14, load an AbortController polyfill from the ' +
            '`node-abort-controller` package. A minimal polyfill is ' +
            'provided for use by LRUCache.fetch(), but it should not be ' +
            'relied upon in other contexts (eg, passing it to other APIs that ' +
            'use AbortController/AbortSignal might have undesirable effects). ' +
            'You may disable this with LRU_CACHE_IGNORE_AC_WARNING=1 in the env.', 'NO_ABORT_CONTROLLER', 'ENOTSUP', warnACPolyfill);
    };
}
/* c8 ignore stop */
const shouldWarn = (code) => !warned.has(code);
const isPosInt = (n) => n && n === Math.floor(n) && n > 0 && isFinite(n);
/* c8 ignore start */
// This is a little bit ridiculous, tbh.
// The maximum array length is 2^32-1 or thereabouts on most JS impls.
// And well before that point, you're caching the entire world, I mean,
// that's ~32GB of just integers for the next/prev links, plus whatever
// else to hold that many keys and values.  Just filling the memory with
// zeroes at init time is brutal when you get that big.
// But why not be complete?
// Maybe in the future, these limits will have expanded.
const getUintArray = (max) => !isPosInt(max) ? null
    : max <= Math.pow(2, 8) ? Uint8Array
        : max <= Math.pow(2, 16) ? Uint16Array
            : max <= Math.pow(2, 32) ? Uint32Array
                : max <= Number.MAX_SAFE_INTEGER ? ZeroArray
                    : null;
/* c8 ignore stop */
class ZeroArray extends Array {
    constructor(size) {
        super(size);
        this.fill(0);
    }
}
class Stack {
    heap;
    length;
    // private constructor
    static #constructing = false;
    static create(max) {
        const HeapCls = getUintArray(max);
        if (!HeapCls)
            return [];
        Stack.#constructing = true;
        const s = new Stack(max, HeapCls);
        Stack.#constructing = false;
        return s;
    }
    constructor(max, HeapCls) {
        /* c8 ignore start */
        if (!Stack.#constructing) {
            throw new TypeError('instantiate Stack using Stack.create(n)');
        }
        /* c8 ignore stop */
        this.heap = new HeapCls(max);
        this.length = 0;
    }
    push(n) {
        this.heap[this.length++] = n;
    }
    pop() {
        return this.heap[--this.length];
    }
}
/**
 * Default export, the thing you're using this module to get.
 *
 * The `K` and `V` types define the key and value types, respectively. The
 * optional `FC` type defines the type of the `context` object passed to
 * `cache.fetch()` and `cache.memo()`.
 *
 * Keys and values **must not** be `null` or `undefined`.
 *
 * All properties from the options object (with the exception of `max`,
 * `maxSize`, `fetchMethod`, `memoMethod`, `dispose` and `disposeAfter`) are
 * added as normal public members. (The listed options are read-only getters.)
 *
 * Changing any of these will alter the defaults for subsequent method calls.
 */
class LRUCache {
    // options that cannot be changed without disaster
    #max;
    #maxSize;
    #dispose;
    #onInsert;
    #disposeAfter;
    #fetchMethod;
    #memoMethod;
    #perf;
    /**
     * {@link LRUCache.OptionsBase.perf}
     */
    get perf() {
        return this.#perf;
    }
    /**
     * {@link LRUCache.OptionsBase.ttl}
     */
    ttl;
    /**
     * {@link LRUCache.OptionsBase.ttlResolution}
     */
    ttlResolution;
    /**
     * {@link LRUCache.OptionsBase.ttlAutopurge}
     */
    ttlAutopurge;
    /**
     * {@link LRUCache.OptionsBase.updateAgeOnGet}
     */
    updateAgeOnGet;
    /**
     * {@link LRUCache.OptionsBase.updateAgeOnHas}
     */
    updateAgeOnHas;
    /**
     * {@link LRUCache.OptionsBase.allowStale}
     */
    allowStale;
    /**
     * {@link LRUCache.OptionsBase.noDisposeOnSet}
     */
    noDisposeOnSet;
    /**
     * {@link LRUCache.OptionsBase.noUpdateTTL}
     */
    noUpdateTTL;
    /**
     * {@link LRUCache.OptionsBase.maxEntrySize}
     */
    maxEntrySize;
    /**
     * {@link LRUCache.OptionsBase.sizeCalculation}
     */
    sizeCalculation;
    /**
     * {@link LRUCache.OptionsBase.noDeleteOnFetchRejection}
     */
    noDeleteOnFetchRejection;
    /**
     * {@link LRUCache.OptionsBase.noDeleteOnStaleGet}
     */
    noDeleteOnStaleGet;
    /**
     * {@link LRUCache.OptionsBase.allowStaleOnFetchAbort}
     */
    allowStaleOnFetchAbort;
    /**
     * {@link LRUCache.OptionsBase.allowStaleOnFetchRejection}
     */
    allowStaleOnFetchRejection;
    /**
     * {@link LRUCache.OptionsBase.ignoreFetchAbort}
     */
    ignoreFetchAbort;
    // computed properties
    #size;
    #calculatedSize;
    #keyMap;
    #keyList;
    #valList;
    #next;
    #prev;
    #head;
    #tail;
    #free;
    #disposed;
    #sizes;
    #starts;
    #ttls;
    #hasDispose;
    #hasFetchMethod;
    #hasDisposeAfter;
    #hasOnInsert;
    /**
     * Do not call this method unless you need to inspect the
     * inner workings of the cache.  If anything returned by this
     * object is modified in any way, strange breakage may occur.
     *
     * These fields are private for a reason!
     *
     * @internal
     */
    static unsafeExposeInternals(c) {
        return {
            // properties
            starts: c.#starts,
            ttls: c.#ttls,
            sizes: c.#sizes,
            keyMap: c.#keyMap,
            keyList: c.#keyList,
            valList: c.#valList,
            next: c.#next,
            prev: c.#prev,
            get head() {
                return c.#head;
            },
            get tail() {
                return c.#tail;
            },
            free: c.#free,
            // methods
            isBackgroundFetch: (p) => c.#isBackgroundFetch(p),
            backgroundFetch: (k, index, options, context) => c.#backgroundFetch(k, index, options, context),
            moveToTail: (index) => c.#moveToTail(index),
            indexes: (options) => c.#indexes(options),
            rindexes: (options) => c.#rindexes(options),
            isStale: (index) => c.#isStale(index),
        };
    }
    // Protected read-only members
    /**
     * {@link LRUCache.OptionsBase.max} (read-only)
     */
    get max() {
        return this.#max;
    }
    /**
     * {@link LRUCache.OptionsBase.maxSize} (read-only)
     */
    get maxSize() {
        return this.#maxSize;
    }
    /**
     * The total computed size of items in the cache (read-only)
     */
    get calculatedSize() {
        return this.#calculatedSize;
    }
    /**
     * The number of items stored in the cache (read-only)
     */
    get size() {
        return this.#size;
    }
    /**
     * {@link LRUCache.OptionsBase.fetchMethod} (read-only)
     */
    get fetchMethod() {
        return this.#fetchMethod;
    }
    get memoMethod() {
        return this.#memoMethod;
    }
    /**
     * {@link LRUCache.OptionsBase.dispose} (read-only)
     */
    get dispose() {
        return this.#dispose;
    }
    /**
     * {@link LRUCache.OptionsBase.onInsert} (read-only)
     */
    get onInsert() {
        return this.#onInsert;
    }
    /**
     * {@link LRUCache.OptionsBase.disposeAfter} (read-only)
     */
    get disposeAfter() {
        return this.#disposeAfter;
    }
    constructor(options) {
        const { max = 0, ttl, ttlResolution = 1, ttlAutopurge, updateAgeOnGet, updateAgeOnHas, allowStale, dispose, onInsert, disposeAfter, noDisposeOnSet, noUpdateTTL, maxSize = 0, maxEntrySize = 0, sizeCalculation, fetchMethod, memoMethod, noDeleteOnFetchRejection, noDeleteOnStaleGet, allowStaleOnFetchRejection, allowStaleOnFetchAbort, ignoreFetchAbort, perf, } = options;
        if (perf !== undefined) {
            if (typeof perf?.now !== 'function') {
                throw new TypeError('perf option must have a now() method if specified');
            }
        }
        this.#perf = perf ?? defaultPerf;
        if (max !== 0 && !isPosInt(max)) {
            throw new TypeError('max option must be a nonnegative integer');
        }
        const UintArray = max ? getUintArray(max) : Array;
        if (!UintArray) {
            throw new Error('invalid max value: ' + max);
        }
        this.#max = max;
        this.#maxSize = maxSize;
        this.maxEntrySize = maxEntrySize || this.#maxSize;
        this.sizeCalculation = sizeCalculation;
        if (this.sizeCalculation) {
            if (!this.#maxSize && !this.maxEntrySize) {
                throw new TypeError('cannot set sizeCalculation without setting maxSize or maxEntrySize');
            }
            if (typeof this.sizeCalculation !== 'function') {
                throw new TypeError('sizeCalculation set to non-function');
            }
        }
        if (memoMethod !== undefined &&
            typeof memoMethod !== 'function') {
            throw new TypeError('memoMethod must be a function if defined');
        }
        this.#memoMethod = memoMethod;
        if (fetchMethod !== undefined &&
            typeof fetchMethod !== 'function') {
            throw new TypeError('fetchMethod must be a function if specified');
        }
        this.#fetchMethod = fetchMethod;
        this.#hasFetchMethod = !!fetchMethod;
        this.#keyMap = new Map();
        this.#keyList = new Array(max).fill(undefined);
        this.#valList = new Array(max).fill(undefined);
        this.#next = new UintArray(max);
        this.#prev = new UintArray(max);
        this.#head = 0;
        this.#tail = 0;
        this.#free = Stack.create(max);
        this.#size = 0;
        this.#calculatedSize = 0;
        if (typeof dispose === 'function') {
            this.#dispose = dispose;
        }
        if (typeof onInsert === 'function') {
            this.#onInsert = onInsert;
        }
        if (typeof disposeAfter === 'function') {
            this.#disposeAfter = disposeAfter;
            this.#disposed = [];
        }
        else {
            this.#disposeAfter = undefined;
            this.#disposed = undefined;
        }
        this.#hasDispose = !!this.#dispose;
        this.#hasOnInsert = !!this.#onInsert;
        this.#hasDisposeAfter = !!this.#disposeAfter;
        this.noDisposeOnSet = !!noDisposeOnSet;
        this.noUpdateTTL = !!noUpdateTTL;
        this.noDeleteOnFetchRejection = !!noDeleteOnFetchRejection;
        this.allowStaleOnFetchRejection = !!allowStaleOnFetchRejection;
        this.allowStaleOnFetchAbort = !!allowStaleOnFetchAbort;
        this.ignoreFetchAbort = !!ignoreFetchAbort;
        // NB: maxEntrySize is set to maxSize if it's set
        if (this.maxEntrySize !== 0) {
            if (this.#maxSize !== 0) {
                if (!isPosInt(this.#maxSize)) {
                    throw new TypeError('maxSize must be a positive integer if specified');
                }
            }
            if (!isPosInt(this.maxEntrySize)) {
                throw new TypeError('maxEntrySize must be a positive integer if specified');
            }
            this.#initializeSizeTracking();
        }
        this.allowStale = !!allowStale;
        this.noDeleteOnStaleGet = !!noDeleteOnStaleGet;
        this.updateAgeOnGet = !!updateAgeOnGet;
        this.updateAgeOnHas = !!updateAgeOnHas;
        this.ttlResolution =
            isPosInt(ttlResolution) || ttlResolution === 0 ?
                ttlResolution
                : 1;
        this.ttlAutopurge = !!ttlAutopurge;
        this.ttl = ttl || 0;
        if (this.ttl) {
            if (!isPosInt(this.ttl)) {
                throw new TypeError('ttl must be a positive integer if specified');
            }
            this.#initializeTTLTracking();
        }
        // do not allow completely unbounded caches
        if (this.#max === 0 && this.ttl === 0 && this.#maxSize === 0) {
            throw new TypeError('At least one of max, maxSize, or ttl is required');
        }
        if (!this.ttlAutopurge && !this.#max && !this.#maxSize) {
            const code = 'LRU_CACHE_UNBOUNDED';
            if (shouldWarn(code)) {
                warned.add(code);
                const msg = 'TTL caching without ttlAutopurge, max, or maxSize can ' +
                    'result in unbounded memory consumption.';
                emitWarning(msg, 'UnboundedCacheWarning', code, LRUCache);
            }
        }
    }
    /**
     * Return the number of ms left in the item's TTL. If item is not in cache,
     * returns `0`. Returns `Infinity` if item is in cache without a defined TTL.
     */
    getRemainingTTL(key) {
        return this.#keyMap.has(key) ? Infinity : 0;
    }
    #initializeTTLTracking() {
        const ttls = new ZeroArray(this.#max);
        const starts = new ZeroArray(this.#max);
        this.#ttls = ttls;
        this.#starts = starts;
        this.#setItemTTL = (index, ttl, start = this.#perf.now()) => {
            starts[index] = ttl !== 0 ? start : 0;
            ttls[index] = ttl;
            if (ttl !== 0 && this.ttlAutopurge) {
                const t = setTimeout(() => {
                    if (this.#isStale(index)) {
                        this.#delete(this.#keyList[index], 'expire');
                    }
                }, ttl + 1);
                // unref() not supported on all platforms
                /* c8 ignore start */
                if (t.unref) {
                    t.unref();
                }
                /* c8 ignore stop */
            }
        };
        this.#updateItemAge = index => {
            starts[index] = ttls[index] !== 0 ? this.#perf.now() : 0;
        };
        this.#statusTTL = (status, index) => {
            if (ttls[index]) {
                const ttl = ttls[index];
                const start = starts[index];
                /* c8 ignore next */
                if (!ttl || !start)
                    return;
                status.ttl = ttl;
                status.start = start;
                status.now = cachedNow || getNow();
                const age = status.now - start;
                status.remainingTTL = ttl - age;
            }
        };
        // debounce calls to perf.now() to 1s so we're not hitting
        // that costly call repeatedly.
        let cachedNow = 0;
        const getNow = () => {
            const n = this.#perf.now();
            if (this.ttlResolution > 0) {
                cachedNow = n;
                const t = setTimeout(() => (cachedNow = 0), this.ttlResolution);
                // not available on all platforms
                /* c8 ignore start */
                if (t.unref) {
                    t.unref();
                }
                /* c8 ignore stop */
            }
            return n;
        };
        this.getRemainingTTL = key => {
            const index = this.#keyMap.get(key);
            if (index === undefined) {
                return 0;
            }
            const ttl = ttls[index];
            const start = starts[index];
            if (!ttl || !start) {
                return Infinity;
            }
            const age = (cachedNow || getNow()) - start;
            return ttl - age;
        };
        this.#isStale = index => {
            const s = starts[index];
            const t = ttls[index];
            return !!t && !!s && (cachedNow || getNow()) - s > t;
        };
    }
    // conditionally set private methods related to TTL
    #updateItemAge = () => { };
    #statusTTL = () => { };
    #setItemTTL = () => { };
    /* c8 ignore stop */
    #isStale = () => false;
    #initializeSizeTracking() {
        const sizes = new ZeroArray(this.#max);
        this.#calculatedSize = 0;
        this.#sizes = sizes;
        this.#removeItemSize = index => {
            this.#calculatedSize -= sizes[index];
            sizes[index] = 0;
        };
        this.#requireSize = (k, v, size, sizeCalculation) => {
            // provisionally accept background fetches.
            // actual value size will be checked when they return.
            if (this.#isBackgroundFetch(v)) {
                return 0;
            }
            if (!isPosInt(size)) {
                if (sizeCalculation) {
                    if (typeof sizeCalculation !== 'function') {
                        throw new TypeError('sizeCalculation must be a function');
                    }
                    size = sizeCalculation(v, k);
                    if (!isPosInt(size)) {
                        throw new TypeError('sizeCalculation return invalid (expect positive integer)');
                    }
                }
                else {
                    throw new TypeError('invalid size value (must be positive integer). ' +
                        'When maxSize or maxEntrySize is used, sizeCalculation ' +
                        'or size must be set.');
                }
            }
            return size;
        };
        this.#addItemSize = (index, size, status) => {
            sizes[index] = size;
            if (this.#maxSize) {
                const maxSize = this.#maxSize - sizes[index];
                while (this.#calculatedSize > maxSize) {
                    this.#evict(true);
                }
            }
            this.#calculatedSize += sizes[index];
            if (status) {
                status.entrySize = size;
                status.totalCalculatedSize = this.#calculatedSize;
            }
        };
    }
    #removeItemSize = _i => { };
    #addItemSize = (_i, _s, _st) => { };
    #requireSize = (_k, _v, size, sizeCalculation) => {
        if (size || sizeCalculation) {
            throw new TypeError('cannot set size without setting maxSize or maxEntrySize on cache');
        }
        return 0;
    };
    *#indexes({ allowStale = this.allowStale } = {}) {
        if (this.#size) {
            for (let i = this.#tail; true;) {
                if (!this.#isValidIndex(i)) {
                    break;
                }
                if (allowStale || !this.#isStale(i)) {
                    yield i;
                }
                if (i === this.#head) {
                    break;
                }
                else {
                    i = this.#prev[i];
                }
            }
        }
    }
    *#rindexes({ allowStale = this.allowStale } = {}) {
        if (this.#size) {
            for (let i = this.#head; true;) {
                if (!this.#isValidIndex(i)) {
                    break;
                }
                if (allowStale || !this.#isStale(i)) {
                    yield i;
                }
                if (i === this.#tail) {
                    break;
                }
                else {
                    i = this.#next[i];
                }
            }
        }
    }
    #isValidIndex(index) {
        return (index !== undefined &&
            this.#keyMap.get(this.#keyList[index]) === index);
    }
    /**
     * Return a generator yielding `[key, value]` pairs,
     * in order from most recently used to least recently used.
     */
    *entries() {
        for (const i of this.#indexes()) {
            if (this.#valList[i] !== undefined &&
                this.#keyList[i] !== undefined &&
                !this.#isBackgroundFetch(this.#valList[i])) {
                yield [this.#keyList[i], this.#valList[i]];
            }
        }
    }
    /**
     * Inverse order version of {@link LRUCache.entries}
     *
     * Return a generator yielding `[key, value]` pairs,
     * in order from least recently used to most recently used.
     */
    *rentries() {
        for (const i of this.#rindexes()) {
            if (this.#valList[i] !== undefined &&
                this.#keyList[i] !== undefined &&
                !this.#isBackgroundFetch(this.#valList[i])) {
                yield [this.#keyList[i], this.#valList[i]];
            }
        }
    }
    /**
     * Return a generator yielding the keys in the cache,
     * in order from most recently used to least recently used.
     */
    *keys() {
        for (const i of this.#indexes()) {
            const k = this.#keyList[i];
            if (k !== undefined &&
                !this.#isBackgroundFetch(this.#valList[i])) {
                yield k;
            }
        }
    }
    /**
     * Inverse order version of {@link LRUCache.keys}
     *
     * Return a generator yielding the keys in the cache,
     * in order from least recently used to most recently used.
     */
    *rkeys() {
        for (const i of this.#rindexes()) {
            const k = this.#keyList[i];
            if (k !== undefined &&
                !this.#isBackgroundFetch(this.#valList[i])) {
                yield k;
            }
        }
    }
    /**
     * Return a generator yielding the values in the cache,
     * in order from most recently used to least recently used.
     */
    *values() {
        for (const i of this.#indexes()) {
            const v = this.#valList[i];
            if (v !== undefined &&
                !this.#isBackgroundFetch(this.#valList[i])) {
                yield this.#valList[i];
            }
        }
    }
    /**
     * Inverse order version of {@link LRUCache.values}
     *
     * Return a generator yielding the values in the cache,
     * in order from least recently used to most recently used.
     */
    *rvalues() {
        for (const i of this.#rindexes()) {
            const v = this.#valList[i];
            if (v !== undefined &&
                !this.#isBackgroundFetch(this.#valList[i])) {
                yield this.#valList[i];
            }
        }
    }
    /**
     * Iterating over the cache itself yields the same results as
     * {@link LRUCache.entries}
     */
    [Symbol.iterator]() {
        return this.entries();
    }
    /**
     * A String value that is used in the creation of the default string
     * description of an object. Called by the built-in method
     * `Object.prototype.toString`.
     */
    [Symbol.toStringTag] = 'LRUCache';
    /**
     * Find a value for which the supplied fn method returns a truthy value,
     * similar to `Array.find()`. fn is called as `fn(value, key, cache)`.
     */
    find(fn, getOptions = {}) {
        for (const i of this.#indexes()) {
            const v = this.#valList[i];
            const value = this.#isBackgroundFetch(v) ? v.__staleWhileFetching : v;
            if (value === undefined)
                continue;
            if (fn(value, this.#keyList[i], this)) {
                return this.get(this.#keyList[i], getOptions);
            }
        }
    }
    /**
     * Call the supplied function on each item in the cache, in order from most
     * recently used to least recently used.
     *
     * `fn` is called as `fn(value, key, cache)`.
     *
     * If `thisp` is provided, function will be called in the `this`-context of
     * the provided object, or the cache if no `thisp` object is provided.
     *
     * Does not update age or recenty of use, or iterate over stale values.
     */
    forEach(fn, thisp = this) {
        for (const i of this.#indexes()) {
            const v = this.#valList[i];
            const value = this.#isBackgroundFetch(v) ? v.__staleWhileFetching : v;
            if (value === undefined)
                continue;
            fn.call(thisp, value, this.#keyList[i], this);
        }
    }
    /**
     * The same as {@link LRUCache.forEach} but items are iterated over in
     * reverse order.  (ie, less recently used items are iterated over first.)
     */
    rforEach(fn, thisp = this) {
        for (const i of this.#rindexes()) {
            const v = this.#valList[i];
            const value = this.#isBackgroundFetch(v) ? v.__staleWhileFetching : v;
            if (value === undefined)
                continue;
            fn.call(thisp, value, this.#keyList[i], this);
        }
    }
    /**
     * Delete any stale entries. Returns true if anything was removed,
     * false otherwise.
     */
    purgeStale() {
        let deleted = false;
        for (const i of this.#rindexes({ allowStale: true })) {
            if (this.#isStale(i)) {
                this.#delete(this.#keyList[i], 'expire');
                deleted = true;
            }
        }
        return deleted;
    }
    /**
     * Get the extended info about a given entry, to get its value, size, and
     * TTL info simultaneously. Returns `undefined` if the key is not present.
     *
     * Unlike {@link LRUCache#dump}, which is designed to be portable and survive
     * serialization, the `start` value is always the current timestamp, and the
     * `ttl` is a calculated remaining time to live (negative if expired).
     *
     * Always returns stale values, if their info is found in the cache, so be
     * sure to check for expirations (ie, a negative {@link LRUCache.Entry#ttl})
     * if relevant.
     */
    info(key) {
        const i = this.#keyMap.get(key);
        if (i === undefined)
            return undefined;
        const v = this.#valList[i];
        /* c8 ignore start - this isn't tested for the info function,
         * but it's the same logic as found in other places. */
        const value = this.#isBackgroundFetch(v) ? v.__staleWhileFetching : v;
        if (value === undefined)
            return undefined;
        /* c8 ignore end */
        const entry = { value };
        if (this.#ttls && this.#starts) {
            const ttl = this.#ttls[i];
            const start = this.#starts[i];
            if (ttl && start) {
                const remain = ttl - (this.#perf.now() - start);
                entry.ttl = remain;
                entry.start = Date.now();
            }
        }
        if (this.#sizes) {
            entry.size = this.#sizes[i];
        }
        return entry;
    }
    /**
     * Return an array of [key, {@link LRUCache.Entry}] tuples which can be
     * passed to {@link LRUCache#load}.
     *
     * The `start` fields are calculated relative to a portable `Date.now()`
     * timestamp, even if `performance.now()` is available.
     *
     * Stale entries are always included in the `dump`, even if
     * {@link LRUCache.OptionsBase.allowStale} is false.
     *
     * Note: this returns an actual array, not a generator, so it can be more
     * easily passed around.
     */
    dump() {
        const arr = [];
        for (const i of this.#indexes({ allowStale: true })) {
            const key = this.#keyList[i];
            const v = this.#valList[i];
            const value = this.#isBackgroundFetch(v) ? v.__staleWhileFetching : v;
            if (value === undefined || key === undefined)
                continue;
            const entry = { value };
            if (this.#ttls && this.#starts) {
                entry.ttl = this.#ttls[i];
                // always dump the start relative to a portable timestamp
                // it's ok for this to be a bit slow, it's a rare operation.
                const age = this.#perf.now() - this.#starts[i];
                entry.start = Math.floor(Date.now() - age);
            }
            if (this.#sizes) {
                entry.size = this.#sizes[i];
            }
            arr.unshift([key, entry]);
        }
        return arr;
    }
    /**
     * Reset the cache and load in the items in entries in the order listed.
     *
     * The shape of the resulting cache may be different if the same options are
     * not used in both caches.
     *
     * The `start` fields are assumed to be calculated relative to a portable
     * `Date.now()` timestamp, even if `performance.now()` is available.
     */
    load(arr) {
        this.clear();
        for (const [key, entry] of arr) {
            if (entry.start) {
                // entry.start is a portable timestamp, but we may be using
                // node's performance.now(), so calculate the offset, so that
                // we get the intended remaining TTL, no matter how long it's
                // been on ice.
                //
                // it's ok for this to be a bit slow, it's a rare operation.
                const age = Date.now() - entry.start;
                entry.start = this.#perf.now() - age;
            }
            this.set(key, entry.value, entry);
        }
    }
    /**
     * Add a value to the cache.
     *
     * Note: if `undefined` is specified as a value, this is an alias for
     * {@link LRUCache#delete}
     *
     * Fields on the {@link LRUCache.SetOptions} options param will override
     * their corresponding values in the constructor options for the scope
     * of this single `set()` operation.
     *
     * If `start` is provided, then that will set the effective start
     * time for the TTL calculation. Note that this must be a previous
     * value of `performance.now()` if supported, or a previous value of
     * `Date.now()` if not.
     *
     * Options object may also include `size`, which will prevent
     * calling the `sizeCalculation` function and just use the specified
     * number if it is a positive integer, and `noDisposeOnSet` which
     * will prevent calling a `dispose` function in the case of
     * overwrites.
     *
     * If the `size` (or return value of `sizeCalculation`) for a given
     * entry is greater than `maxEntrySize`, then the item will not be
     * added to the cache.
     *
     * Will update the recency of the entry.
     *
     * If the value is `undefined`, then this is an alias for
     * `cache.delete(key)`. `undefined` is never stored in the cache.
     */
    set(k, v, setOptions = {}) {
        if (v === undefined) {
            this.delete(k);
            return this;
        }
        const { ttl = this.ttl, start, noDisposeOnSet = this.noDisposeOnSet, sizeCalculation = this.sizeCalculation, status, } = setOptions;
        let { noUpdateTTL = this.noUpdateTTL } = setOptions;
        const size = this.#requireSize(k, v, setOptions.size || 0, sizeCalculation);
        // if the item doesn't fit, don't do anything
        // NB: maxEntrySize set to maxSize by default
        if (this.maxEntrySize && size > this.maxEntrySize) {
            if (status) {
                status.set = 'miss';
                status.maxEntrySizeExceeded = true;
            }
            // have to delete, in case something is there already.
            this.#delete(k, 'set');
            return this;
        }
        let index = this.#size === 0 ? undefined : this.#keyMap.get(k);
        if (index === undefined) {
            // addition
            index = (this.#size === 0 ? this.#tail
                : this.#free.length !== 0 ? this.#free.pop()
                    : this.#size === this.#max ? this.#evict(false)
                        : this.#size);
            this.#keyList[index] = k;
            this.#valList[index] = v;
            this.#keyMap.set(k, index);
            this.#next[this.#tail] = index;
            this.#prev[index] = this.#tail;
            this.#tail = index;
            this.#size++;
            this.#addItemSize(index, size, status);
            if (status)
                status.set = 'add';
            noUpdateTTL = false;
            if (this.#hasOnInsert) {
                this.#onInsert?.(v, k, 'add');
            }
        }
        else {
            // update
            this.#moveToTail(index);
            const oldVal = this.#valList[index];
            if (v !== oldVal) {
                if (this.#hasFetchMethod && this.#isBackgroundFetch(oldVal)) {
                    oldVal.__abortController.abort(new Error('replaced'));
                    const { __staleWhileFetching: s } = oldVal;
                    if (s !== undefined && !noDisposeOnSet) {
                        if (this.#hasDispose) {
                            this.#dispose?.(s, k, 'set');
                        }
                        if (this.#hasDisposeAfter) {
                            this.#disposed?.push([s, k, 'set']);
                        }
                    }
                }
                else if (!noDisposeOnSet) {
                    if (this.#hasDispose) {
                        this.#dispose?.(oldVal, k, 'set');
                    }
                    if (this.#hasDisposeAfter) {
                        this.#disposed?.push([oldVal, k, 'set']);
                    }
                }
                this.#removeItemSize(index);
                this.#addItemSize(index, size, status);
                this.#valList[index] = v;
                if (status) {
                    status.set = 'replace';
                    const oldValue = oldVal && this.#isBackgroundFetch(oldVal) ?
                        oldVal.__staleWhileFetching
                        : oldVal;
                    if (oldValue !== undefined)
                        status.oldValue = oldValue;
                }
            }
            else if (status) {
                status.set = 'update';
            }
            if (this.#hasOnInsert) {
                this.onInsert?.(v, k, v === oldVal ? 'update' : 'replace');
            }
        }
        if (ttl !== 0 && !this.#ttls) {
            this.#initializeTTLTracking();
        }
        if (this.#ttls) {
            if (!noUpdateTTL) {
                this.#setItemTTL(index, ttl, start);
            }
            if (status)
                this.#statusTTL(status, index);
        }
        if (!noDisposeOnSet && this.#hasDisposeAfter && this.#disposed) {
            const dt = this.#disposed;
            let task;
            while ((task = dt?.shift())) {
                this.#disposeAfter?.(...task);
            }
        }
        return this;
    }
    /**
     * Evict the least recently used item, returning its value or
     * `undefined` if cache is empty.
     */
    pop() {
        try {
            while (this.#size) {
                const val = this.#valList[this.#head];
                this.#evict(true);
                if (this.#isBackgroundFetch(val)) {
                    if (val.__staleWhileFetching) {
                        return val.__staleWhileFetching;
                    }
                }
                else if (val !== undefined) {
                    return val;
                }
            }
        }
        finally {
            if (this.#hasDisposeAfter && this.#disposed) {
                const dt = this.#disposed;
                let task;
                while ((task = dt?.shift())) {
                    this.#disposeAfter?.(...task);
                }
            }
        }
    }
    #evict(free) {
        const head = this.#head;
        const k = this.#keyList[head];
        const v = this.#valList[head];
        if (this.#hasFetchMethod && this.#isBackgroundFetch(v)) {
            v.__abortController.abort(new Error('evicted'));
        }
        else if (this.#hasDispose || this.#hasDisposeAfter) {
            if (this.#hasDispose) {
                this.#dispose?.(v, k, 'evict');
            }
            if (this.#hasDisposeAfter) {
                this.#disposed?.push([v, k, 'evict']);
            }
        }
        this.#removeItemSize(head);
        // if we aren't about to use the index, then null these out
        if (free) {
            this.#keyList[head] = undefined;
            this.#valList[head] = undefined;
            this.#free.push(head);
        }
        if (this.#size === 1) {
            this.#head = this.#tail = 0;
            this.#free.length = 0;
        }
        else {
            this.#head = this.#next[head];
        }
        this.#keyMap.delete(k);
        this.#size--;
        return head;
    }
    /**
     * Check if a key is in the cache, without updating the recency of use.
     * Will return false if the item is stale, even though it is technically
     * in the cache.
     *
     * Check if a key is in the cache, without updating the recency of
     * use. Age is updated if {@link LRUCache.OptionsBase.updateAgeOnHas} is set
     * to `true` in either the options or the constructor.
     *
     * Will return `false` if the item is stale, even though it is technically in
     * the cache. The difference can be determined (if it matters) by using a
     * `status` argument, and inspecting the `has` field.
     *
     * Will not update item age unless
     * {@link LRUCache.OptionsBase.updateAgeOnHas} is set.
     */
    has(k, hasOptions = {}) {
        const { updateAgeOnHas = this.updateAgeOnHas, status } = hasOptions;
        const index = this.#keyMap.get(k);
        if (index !== undefined) {
            const v = this.#valList[index];
            if (this.#isBackgroundFetch(v) &&
                v.__staleWhileFetching === undefined) {
                return false;
            }
            if (!this.#isStale(index)) {
                if (updateAgeOnHas) {
                    this.#updateItemAge(index);
                }
                if (status) {
                    status.has = 'hit';
                    this.#statusTTL(status, index);
                }
                return true;
            }
            else if (status) {
                status.has = 'stale';
                this.#statusTTL(status, index);
            }
        }
        else if (status) {
            status.has = 'miss';
        }
        return false;
    }
    /**
     * Like {@link LRUCache#get} but doesn't update recency or delete stale
     * items.
     *
     * Returns `undefined` if the item is stale, unless
     * {@link LRUCache.OptionsBase.allowStale} is set.
     */
    peek(k, peekOptions = {}) {
        const { allowStale = this.allowStale } = peekOptions;
        const index = this.#keyMap.get(k);
        if (index === undefined ||
            (!allowStale && this.#isStale(index))) {
            return;
        }
        const v = this.#valList[index];
        // either stale and allowed, or forcing a refresh of non-stale value
        return this.#isBackgroundFetch(v) ? v.__staleWhileFetching : v;
    }
    #backgroundFetch(k, index, options, context) {
        const v = index === undefined ? undefined : this.#valList[index];
        if (this.#isBackgroundFetch(v)) {
            return v;
        }
        const ac = new AC();
        const { signal } = options;
        // when/if our AC signals, then stop listening to theirs.
        signal?.addEventListener('abort', () => ac.abort(signal.reason), {
            signal: ac.signal,
        });
        const fetchOpts = {
            signal: ac.signal,
            options,
            context,
        };
        const cb = (v, updateCache = false) => {
            const { aborted } = ac.signal;
            const ignoreAbort = options.ignoreFetchAbort && v !== undefined;
            if (options.status) {
                if (aborted && !updateCache) {
                    options.status.fetchAborted = true;
                    options.status.fetchError = ac.signal.reason;
                    if (ignoreAbort)
                        options.status.fetchAbortIgnored = true;
                }
                else {
                    options.status.fetchResolved = true;
                }
            }
            if (aborted && !ignoreAbort && !updateCache) {
                return fetchFail(ac.signal.reason);
            }
            // either we didn't abort, and are still here, or we did, and ignored
            const bf = p;
            // if nothing else has been written there but we're set to update the
            // cache and ignore the abort, or if it's still pending on this specific
            // background request, then write it to the cache.
            const vl = this.#valList[index];
            if (vl === p || ignoreAbort && updateCache && vl === undefined) {
                if (v === undefined) {
                    if (bf.__staleWhileFetching !== undefined) {
                        this.#valList[index] = bf.__staleWhileFetching;
                    }
                    else {
                        this.#delete(k, 'fetch');
                    }
                }
                else {
                    if (options.status)
                        options.status.fetchUpdated = true;
                    this.set(k, v, fetchOpts.options);
                }
            }
            return v;
        };
        const eb = (er) => {
            if (options.status) {
                options.status.fetchRejected = true;
                options.status.fetchError = er;
            }
            return fetchFail(er);
        };
        const fetchFail = (er) => {
            const { aborted } = ac.signal;
            const allowStaleAborted = aborted && options.allowStaleOnFetchAbort;
            const allowStale = allowStaleAborted || options.allowStaleOnFetchRejection;
            const noDelete = allowStale || options.noDeleteOnFetchRejection;
            const bf = p;
            if (this.#valList[index] === p) {
                // if we allow stale on fetch rejections, then we need to ensure that
                // the stale value is not removed from the cache when the fetch fails.
                const del = !noDelete || bf.__staleWhileFetching === undefined;
                if (del) {
                    this.#delete(k, 'fetch');
                }
                else if (!allowStaleAborted) {
                    // still replace the *promise* with the stale value,
                    // since we are done with the promise at this point.
                    // leave it untouched if we're still waiting for an
                    // aborted background fetch that hasn't yet returned.
                    this.#valList[index] = bf.__staleWhileFetching;
                }
            }
            if (allowStale) {
                if (options.status && bf.__staleWhileFetching !== undefined) {
                    options.status.returnedStale = true;
                }
                return bf.__staleWhileFetching;
            }
            else if (bf.__returned === bf) {
                throw er;
            }
        };
        const pcall = (res, rej) => {
            const fmp = this.#fetchMethod?.(k, v, fetchOpts);
            if (fmp && fmp instanceof Promise) {
                fmp.then(v => res(v === undefined ? undefined : v), rej);
            }
            // ignored, we go until we finish, regardless.
            // defer check until we are actually aborting,
            // so fetchMethod can override.
            ac.signal.addEventListener('abort', () => {
                if (!options.ignoreFetchAbort ||
                    options.allowStaleOnFetchAbort) {
                    res(undefined);
                    // when it eventually resolves, update the cache.
                    if (options.allowStaleOnFetchAbort) {
                        res = v => cb(v, true);
                    }
                }
            });
        };
        if (options.status)
            options.status.fetchDispatched = true;
        const p = new Promise(pcall).then(cb, eb);
        const bf = Object.assign(p, {
            __abortController: ac,
            __staleWhileFetching: v,
            __returned: undefined,
        });
        if (index === undefined) {
            // internal, don't expose status.
            this.set(k, bf, { ...fetchOpts.options, status: undefined });
            index = this.#keyMap.get(k);
        }
        else {
            this.#valList[index] = bf;
        }
        return bf;
    }
    #isBackgroundFetch(p) {
        if (!this.#hasFetchMethod)
            return false;
        const b = p;
        return (!!b &&
            b instanceof Promise &&
            b.hasOwnProperty('__staleWhileFetching') &&
            b.__abortController instanceof AC);
    }
    async fetch(k, fetchOptions = {}) {
        const { 
        // get options
        allowStale = this.allowStale, updateAgeOnGet = this.updateAgeOnGet, noDeleteOnStaleGet = this.noDeleteOnStaleGet, 
        // set options
        ttl = this.ttl, noDisposeOnSet = this.noDisposeOnSet, size = 0, sizeCalculation = this.sizeCalculation, noUpdateTTL = this.noUpdateTTL, 
        // fetch exclusive options
        noDeleteOnFetchRejection = this.noDeleteOnFetchRejection, allowStaleOnFetchRejection = this.allowStaleOnFetchRejection, ignoreFetchAbort = this.ignoreFetchAbort, allowStaleOnFetchAbort = this.allowStaleOnFetchAbort, context, forceRefresh = false, status, signal, } = fetchOptions;
        if (!this.#hasFetchMethod) {
            if (status)
                status.fetch = 'get';
            return this.get(k, {
                allowStale,
                updateAgeOnGet,
                noDeleteOnStaleGet,
                status,
            });
        }
        const options = {
            allowStale,
            updateAgeOnGet,
            noDeleteOnStaleGet,
            ttl,
            noDisposeOnSet,
            size,
            sizeCalculation,
            noUpdateTTL,
            noDeleteOnFetchRejection,
            allowStaleOnFetchRejection,
            allowStaleOnFetchAbort,
            ignoreFetchAbort,
            status,
            signal,
        };
        let index = this.#keyMap.get(k);
        if (index === undefined) {
            if (status)
                status.fetch = 'miss';
            const p = this.#backgroundFetch(k, index, options, context);
            return (p.__returned = p);
        }
        else {
            // in cache, maybe already fetching
            const v = this.#valList[index];
            if (this.#isBackgroundFetch(v)) {
                const stale = allowStale && v.__staleWhileFetching !== undefined;
                if (status) {
                    status.fetch = 'inflight';
                    if (stale)
                        status.returnedStale = true;
                }
                return stale ? v.__staleWhileFetching : (v.__returned = v);
            }
            // if we force a refresh, that means do NOT serve the cached value,
            // unless we are already in the process of refreshing the cache.
            const isStale = this.#isStale(index);
            if (!forceRefresh && !isStale) {
                if (status)
                    status.fetch = 'hit';
                this.#moveToTail(index);
                if (updateAgeOnGet) {
                    this.#updateItemAge(index);
                }
                if (status)
                    this.#statusTTL(status, index);
                return v;
            }
            // ok, it is stale or a forced refresh, and not already fetching.
            // refresh the cache.
            const p = this.#backgroundFetch(k, index, options, context);
            const hasStale = p.__staleWhileFetching !== undefined;
            const staleVal = hasStale && allowStale;
            if (status) {
                status.fetch = isStale ? 'stale' : 'refresh';
                if (staleVal && isStale)
                    status.returnedStale = true;
            }
            return staleVal ? p.__staleWhileFetching : (p.__returned = p);
        }
    }
    async forceFetch(k, fetchOptions = {}) {
        const v = await this.fetch(k, fetchOptions);
        if (v === undefined)
            throw new Error('fetch() returned undefined');
        return v;
    }
    memo(k, memoOptions = {}) {
        const memoMethod = this.#memoMethod;
        if (!memoMethod) {
            throw new Error('no memoMethod provided to constructor');
        }
        const { context, forceRefresh, ...options } = memoOptions;
        const v = this.get(k, options);
        if (!forceRefresh && v !== undefined)
            return v;
        const vv = memoMethod(k, v, {
            options,
            context,
        });
        this.set(k, vv, options);
        return vv;
    }
    /**
     * Return a value from the cache. Will update the recency of the cache
     * entry found.
     *
     * If the key is not found, get() will return `undefined`.
     */
    get(k, getOptions = {}) {
        const { allowStale = this.allowStale, updateAgeOnGet = this.updateAgeOnGet, noDeleteOnStaleGet = this.noDeleteOnStaleGet, status, } = getOptions;
        const index = this.#keyMap.get(k);
        if (index !== undefined) {
            const value = this.#valList[index];
            const fetching = this.#isBackgroundFetch(value);
            if (status)
                this.#statusTTL(status, index);
            if (this.#isStale(index)) {
                if (status)
                    status.get = 'stale';
                // delete only if not an in-flight background fetch
                if (!fetching) {
                    if (!noDeleteOnStaleGet) {
                        this.#delete(k, 'expire');
                    }
                    if (status && allowStale)
                        status.returnedStale = true;
                    return allowStale ? value : undefined;
                }
                else {
                    if (status &&
                        allowStale &&
                        value.__staleWhileFetching !== undefined) {
                        status.returnedStale = true;
                    }
                    return allowStale ? value.__staleWhileFetching : undefined;
                }
            }
            else {
                if (status)
                    status.get = 'hit';
                // if we're currently fetching it, we don't actually have it yet
                // it's not stale, which means this isn't a staleWhileRefetching.
                // If it's not stale, and fetching, AND has a __staleWhileFetching
                // value, then that means the user fetched with {forceRefresh:true},
                // so it's safe to return that value.
                if (fetching) {
                    return value.__staleWhileFetching;
                }
                this.#moveToTail(index);
                if (updateAgeOnGet) {
                    this.#updateItemAge(index);
                }
                return value;
            }
        }
        else if (status) {
            status.get = 'miss';
        }
    }
    #connect(p, n) {
        this.#prev[n] = p;
        this.#next[p] = n;
    }
    #moveToTail(index) {
        // if tail already, nothing to do
        // if head, move head to next[index]
        // else
        //   move next[prev[index]] to next[index] (head has no prev)
        //   move prev[next[index]] to prev[index]
        // prev[index] = tail
        // next[tail] = index
        // tail = index
        if (index !== this.#tail) {
            if (index === this.#head) {
                this.#head = this.#next[index];
            }
            else {
                this.#connect(this.#prev[index], this.#next[index]);
            }
            this.#connect(this.#tail, index);
            this.#tail = index;
        }
    }
    /**
     * Deletes a key out of the cache.
     *
     * Returns true if the key was deleted, false otherwise.
     */
    delete(k) {
        return this.#delete(k, 'delete');
    }
    #delete(k, reason) {
        let deleted = false;
        if (this.#size !== 0) {
            const index = this.#keyMap.get(k);
            if (index !== undefined) {
                deleted = true;
                if (this.#size === 1) {
                    this.#clear(reason);
                }
                else {
                    this.#removeItemSize(index);
                    const v = this.#valList[index];
                    if (this.#isBackgroundFetch(v)) {
                        v.__abortController.abort(new Error('deleted'));
                    }
                    else if (this.#hasDispose || this.#hasDisposeAfter) {
                        if (this.#hasDispose) {
                            this.#dispose?.(v, k, reason);
                        }
                        if (this.#hasDisposeAfter) {
                            this.#disposed?.push([v, k, reason]);
                        }
                    }
                    this.#keyMap.delete(k);
                    this.#keyList[index] = undefined;
                    this.#valList[index] = undefined;
                    if (index === this.#tail) {
                        this.#tail = this.#prev[index];
                    }
                    else if (index === this.#head) {
                        this.#head = this.#next[index];
                    }
                    else {
                        const pi = this.#prev[index];
                        this.#next[pi] = this.#next[index];
                        const ni = this.#next[index];
                        this.#prev[ni] = this.#prev[index];
                    }
                    this.#size--;
                    this.#free.push(index);
                }
            }
        }
        if (this.#hasDisposeAfter && this.#disposed?.length) {
            const dt = this.#disposed;
            let task;
            while ((task = dt?.shift())) {
                this.#disposeAfter?.(...task);
            }
        }
        return deleted;
    }
    /**
     * Clear the cache entirely, throwing away all values.
     */
    clear() {
        return this.#clear('delete');
    }
    #clear(reason) {
        for (const index of this.#rindexes({ allowStale: true })) {
            const v = this.#valList[index];
            if (this.#isBackgroundFetch(v)) {
                v.__abortController.abort(new Error('deleted'));
            }
            else {
                const k = this.#keyList[index];
                if (this.#hasDispose) {
                    this.#dispose?.(v, k, reason);
                }
                if (this.#hasDisposeAfter) {
                    this.#disposed?.push([v, k, reason]);
                }
            }
        }
        this.#keyMap.clear();
        this.#valList.fill(undefined);
        this.#keyList.fill(undefined);
        if (this.#ttls && this.#starts) {
            this.#ttls.fill(0);
            this.#starts.fill(0);
        }
        if (this.#sizes) {
            this.#sizes.fill(0);
        }
        this.#head = 0;
        this.#tail = 0;
        this.#free.length = 0;
        this.#calculatedSize = 0;
        this.#size = 0;
        if (this.#hasDisposeAfter && this.#disposed) {
            const dt = this.#disposed;
            let task;
            while ((task = dt?.shift())) {
                this.#disposeAfter?.(...task);
            }
        }
    }
}

const proc = typeof process === 'object' && process
    ? process
    : {
        stdout: null,
        stderr: null,
    };
/**
 * Return true if the argument is a Minipass stream, Node stream, or something
 * else that Minipass can interact with.
 */
const isStream = (s) => !!s &&
    typeof s === 'object' &&
    (s instanceof Minipass ||
        s instanceof Stream ||
        isReadable(s) ||
        isWritable(s));
/**
 * Return true if the argument is a valid {@link Minipass.Readable}
 */
const isReadable = (s) => !!s &&
    typeof s === 'object' &&
    s instanceof EventEmitter &&
    typeof s.pipe === 'function' &&
    // node core Writable streams have a pipe() method, but it throws
    s.pipe !== Stream.Writable.prototype.pipe;
/**
 * Return true if the argument is a valid {@link Minipass.Writable}
 */
const isWritable = (s) => !!s &&
    typeof s === 'object' &&
    s instanceof EventEmitter &&
    typeof s.write === 'function' &&
    typeof s.end === 'function';
const EOF = Symbol('EOF');
const MAYBE_EMIT_END = Symbol('maybeEmitEnd');
const EMITTED_END = Symbol('emittedEnd');
const EMITTING_END = Symbol('emittingEnd');
const EMITTED_ERROR = Symbol('emittedError');
const CLOSED = Symbol('closed');
const READ = Symbol('read');
const FLUSH = Symbol('flush');
const FLUSHCHUNK = Symbol('flushChunk');
const ENCODING$1 = Symbol('encoding');
const DECODER = Symbol('decoder');
const FLOWING = Symbol('flowing');
const PAUSED = Symbol('paused');
const RESUME = Symbol('resume');
const BUFFER = Symbol('buffer');
const PIPES = Symbol('pipes');
const BUFFERLENGTH = Symbol('bufferLength');
const BUFFERPUSH = Symbol('bufferPush');
const BUFFERSHIFT = Symbol('bufferShift');
const OBJECTMODE = Symbol('objectMode');
// internal event when stream is destroyed
const DESTROYED = Symbol('destroyed');
// internal event when stream has an error
const ERROR = Symbol('error');
const EMITDATA = Symbol('emitData');
const EMITEND = Symbol('emitEnd');
const EMITEND2 = Symbol('emitEnd2');
const ASYNC = Symbol('async');
const ABORT = Symbol('abort');
const ABORTED = Symbol('aborted');
const SIGNAL = Symbol('signal');
const DATALISTENERS = Symbol('dataListeners');
const DISCARDED = Symbol('discarded');
const defer = (fn) => Promise.resolve().then(fn);
const nodefer = (fn) => fn();
const isEndish = (ev) => ev === 'end' || ev === 'finish' || ev === 'prefinish';
const isArrayBufferLike = (b) => b instanceof ArrayBuffer ||
    (!!b &&
        typeof b === 'object' &&
        b.constructor &&
        b.constructor.name === 'ArrayBuffer' &&
        b.byteLength >= 0);
const isArrayBufferView = (b) => !Buffer.isBuffer(b) && ArrayBuffer.isView(b);
/**
 * Internal class representing a pipe to a destination stream.
 *
 * @internal
 */
class Pipe {
    src;
    dest;
    opts;
    ondrain;
    constructor(src, dest, opts) {
        this.src = src;
        this.dest = dest;
        this.opts = opts;
        this.ondrain = () => src[RESUME]();
        this.dest.on('drain', this.ondrain);
    }
    unpipe() {
        this.dest.removeListener('drain', this.ondrain);
    }
    // only here for the prototype
    /* c8 ignore start */
    proxyErrors(_er) { }
    /* c8 ignore stop */
    end() {
        this.unpipe();
        if (this.opts.end)
            this.dest.end();
    }
}
/**
 * Internal class representing a pipe to a destination stream where
 * errors are proxied.
 *
 * @internal
 */
class PipeProxyErrors extends Pipe {
    unpipe() {
        this.src.removeListener('error', this.proxyErrors);
        super.unpipe();
    }
    constructor(src, dest, opts) {
        super(src, dest, opts);
        this.proxyErrors = er => dest.emit('error', er);
        src.on('error', this.proxyErrors);
    }
}
const isObjectModeOptions = (o) => !!o.objectMode;
const isEncodingOptions = (o) => !o.objectMode && !!o.encoding && o.encoding !== 'buffer';
/**
 * Main export, the Minipass class
 *
 * `RType` is the type of data emitted, defaults to Buffer
 *
 * `WType` is the type of data to be written, if RType is buffer or string,
 * then any {@link Minipass.ContiguousData} is allowed.
 *
 * `Events` is the set of event handler signatures that this object
 * will emit, see {@link Minipass.Events}
 */
class Minipass extends EventEmitter {
    [FLOWING] = false;
    [PAUSED] = false;
    [PIPES] = [];
    [BUFFER] = [];
    [OBJECTMODE];
    [ENCODING$1];
    [ASYNC];
    [DECODER];
    [EOF] = false;
    [EMITTED_END] = false;
    [EMITTING_END] = false;
    [CLOSED] = false;
    [EMITTED_ERROR] = null;
    [BUFFERLENGTH] = 0;
    [DESTROYED] = false;
    [SIGNAL];
    [ABORTED] = false;
    [DATALISTENERS] = 0;
    [DISCARDED] = false;
    /**
     * true if the stream can be written
     */
    writable = true;
    /**
     * true if the stream can be read
     */
    readable = true;
    /**
     * If `RType` is Buffer, then options do not need to be provided.
     * Otherwise, an options object must be provided to specify either
     * {@link Minipass.SharedOptions.objectMode} or
     * {@link Minipass.SharedOptions.encoding}, as appropriate.
     */
    constructor(...args) {
        const options = (args[0] ||
            {});
        super();
        if (options.objectMode && typeof options.encoding === 'string') {
            throw new TypeError('Encoding and objectMode may not be used together');
        }
        if (isObjectModeOptions(options)) {
            this[OBJECTMODE] = true;
            this[ENCODING$1] = null;
        }
        else if (isEncodingOptions(options)) {
            this[ENCODING$1] = options.encoding;
            this[OBJECTMODE] = false;
        }
        else {
            this[OBJECTMODE] = false;
            this[ENCODING$1] = null;
        }
        this[ASYNC] = !!options.async;
        this[DECODER] = this[ENCODING$1]
            ? new StringDecoder(this[ENCODING$1])
            : null;
        //@ts-ignore - private option for debugging and testing
        if (options && options.debugExposeBuffer === true) {
            Object.defineProperty(this, 'buffer', { get: () => this[BUFFER] });
        }
        //@ts-ignore - private option for debugging and testing
        if (options && options.debugExposePipes === true) {
            Object.defineProperty(this, 'pipes', { get: () => this[PIPES] });
        }
        const { signal } = options;
        if (signal) {
            this[SIGNAL] = signal;
            if (signal.aborted) {
                this[ABORT]();
            }
            else {
                signal.addEventListener('abort', () => this[ABORT]());
            }
        }
    }
    /**
     * The amount of data stored in the buffer waiting to be read.
     *
     * For Buffer strings, this will be the total byte length.
     * For string encoding streams, this will be the string character length,
     * according to JavaScript's `string.length` logic.
     * For objectMode streams, this is a count of the items waiting to be
     * emitted.
     */
    get bufferLength() {
        return this[BUFFERLENGTH];
    }
    /**
     * The `BufferEncoding` currently in use, or `null`
     */
    get encoding() {
        return this[ENCODING$1];
    }
    /**
     * @deprecated - This is a read only property
     */
    set encoding(_enc) {
        throw new Error('Encoding must be set at instantiation time');
    }
    /**
     * @deprecated - Encoding may only be set at instantiation time
     */
    setEncoding(_enc) {
        throw new Error('Encoding must be set at instantiation time');
    }
    /**
     * True if this is an objectMode stream
     */
    get objectMode() {
        return this[OBJECTMODE];
    }
    /**
     * @deprecated - This is a read-only property
     */
    set objectMode(_om) {
        throw new Error('objectMode must be set at instantiation time');
    }
    /**
     * true if this is an async stream
     */
    get ['async']() {
        return this[ASYNC];
    }
    /**
     * Set to true to make this stream async.
     *
     * Once set, it cannot be unset, as this would potentially cause incorrect
     * behavior.  Ie, a sync stream can be made async, but an async stream
     * cannot be safely made sync.
     */
    set ['async'](a) {
        this[ASYNC] = this[ASYNC] || !!a;
    }
    // drop everything and get out of the flow completely
    [ABORT]() {
        this[ABORTED] = true;
        this.emit('abort', this[SIGNAL]?.reason);
        this.destroy(this[SIGNAL]?.reason);
    }
    /**
     * True if the stream has been aborted.
     */
    get aborted() {
        return this[ABORTED];
    }
    /**
     * No-op setter. Stream aborted status is set via the AbortSignal provided
     * in the constructor options.
     */
    set aborted(_) { }
    write(chunk, encoding, cb) {
        if (this[ABORTED])
            return false;
        if (this[EOF])
            throw new Error('write after end');
        if (this[DESTROYED]) {
            this.emit('error', Object.assign(new Error('Cannot call write after a stream was destroyed'), { code: 'ERR_STREAM_DESTROYED' }));
            return true;
        }
        if (typeof encoding === 'function') {
            cb = encoding;
            encoding = 'utf8';
        }
        if (!encoding)
            encoding = 'utf8';
        const fn = this[ASYNC] ? defer : nodefer;
        // convert array buffers and typed array views into buffers
        // at some point in the future, we may want to do the opposite!
        // leave strings and buffers as-is
        // anything is only allowed if in object mode, so throw
        if (!this[OBJECTMODE] && !Buffer.isBuffer(chunk)) {
            if (isArrayBufferView(chunk)) {
                //@ts-ignore - sinful unsafe type changing
                chunk = Buffer.from(chunk.buffer, chunk.byteOffset, chunk.byteLength);
            }
            else if (isArrayBufferLike(chunk)) {
                //@ts-ignore - sinful unsafe type changing
                chunk = Buffer.from(chunk);
            }
            else if (typeof chunk !== 'string') {
                throw new Error('Non-contiguous data written to non-objectMode stream');
            }
        }
        // handle object mode up front, since it's simpler
        // this yields better performance, fewer checks later.
        if (this[OBJECTMODE]) {
            // maybe impossible?
            /* c8 ignore start */
            if (this[FLOWING] && this[BUFFERLENGTH] !== 0)
                this[FLUSH](true);
            /* c8 ignore stop */
            if (this[FLOWING])
                this.emit('data', chunk);
            else
                this[BUFFERPUSH](chunk);
            if (this[BUFFERLENGTH] !== 0)
                this.emit('readable');
            if (cb)
                fn(cb);
            return this[FLOWING];
        }
        // at this point the chunk is a buffer or string
        // don't buffer it up or send it to the decoder
        if (!chunk.length) {
            if (this[BUFFERLENGTH] !== 0)
                this.emit('readable');
            if (cb)
                fn(cb);
            return this[FLOWING];
        }
        // fast-path writing strings of same encoding to a stream with
        // an empty buffer, skipping the buffer/decoder dance
        if (typeof chunk === 'string' &&
            // unless it is a string already ready for us to use
            !(encoding === this[ENCODING$1] && !this[DECODER]?.lastNeed)) {
            //@ts-ignore - sinful unsafe type change
            chunk = Buffer.from(chunk, encoding);
        }
        if (Buffer.isBuffer(chunk) && this[ENCODING$1]) {
            //@ts-ignore - sinful unsafe type change
            chunk = this[DECODER].write(chunk);
        }
        // Note: flushing CAN potentially switch us into not-flowing mode
        if (this[FLOWING] && this[BUFFERLENGTH] !== 0)
            this[FLUSH](true);
        if (this[FLOWING])
            this.emit('data', chunk);
        else
            this[BUFFERPUSH](chunk);
        if (this[BUFFERLENGTH] !== 0)
            this.emit('readable');
        if (cb)
            fn(cb);
        return this[FLOWING];
    }
    /**
     * Low-level explicit read method.
     *
     * In objectMode, the argument is ignored, and one item is returned if
     * available.
     *
     * `n` is the number of bytes (or in the case of encoding streams,
     * characters) to consume. If `n` is not provided, then the entire buffer
     * is returned, or `null` is returned if no data is available.
     *
     * If `n` is greater that the amount of data in the internal buffer,
     * then `null` is returned.
     */
    read(n) {
        if (this[DESTROYED])
            return null;
        this[DISCARDED] = false;
        if (this[BUFFERLENGTH] === 0 ||
            n === 0 ||
            (n && n > this[BUFFERLENGTH])) {
            this[MAYBE_EMIT_END]();
            return null;
        }
        if (this[OBJECTMODE])
            n = null;
        if (this[BUFFER].length > 1 && !this[OBJECTMODE]) {
            // not object mode, so if we have an encoding, then RType is string
            // otherwise, must be Buffer
            this[BUFFER] = [
                (this[ENCODING$1]
                    ? this[BUFFER].join('')
                    : Buffer.concat(this[BUFFER], this[BUFFERLENGTH])),
            ];
        }
        const ret = this[READ](n || null, this[BUFFER][0]);
        this[MAYBE_EMIT_END]();
        return ret;
    }
    [READ](n, chunk) {
        if (this[OBJECTMODE])
            this[BUFFERSHIFT]();
        else {
            const c = chunk;
            if (n === c.length || n === null)
                this[BUFFERSHIFT]();
            else if (typeof c === 'string') {
                this[BUFFER][0] = c.slice(n);
                chunk = c.slice(0, n);
                this[BUFFERLENGTH] -= n;
            }
            else {
                this[BUFFER][0] = c.subarray(n);
                chunk = c.subarray(0, n);
                this[BUFFERLENGTH] -= n;
            }
        }
        this.emit('data', chunk);
        if (!this[BUFFER].length && !this[EOF])
            this.emit('drain');
        return chunk;
    }
    end(chunk, encoding, cb) {
        if (typeof chunk === 'function') {
            cb = chunk;
            chunk = undefined;
        }
        if (typeof encoding === 'function') {
            cb = encoding;
            encoding = 'utf8';
        }
        if (chunk !== undefined)
            this.write(chunk, encoding);
        if (cb)
            this.once('end', cb);
        this[EOF] = true;
        this.writable = false;
        // if we haven't written anything, then go ahead and emit,
        // even if we're not reading.
        // we'll re-emit if a new 'end' listener is added anyway.
        // This makes MP more suitable to write-only use cases.
        if (this[FLOWING] || !this[PAUSED])
            this[MAYBE_EMIT_END]();
        return this;
    }
    // don't let the internal resume be overwritten
    [RESUME]() {
        if (this[DESTROYED])
            return;
        if (!this[DATALISTENERS] && !this[PIPES].length) {
            this[DISCARDED] = true;
        }
        this[PAUSED] = false;
        this[FLOWING] = true;
        this.emit('resume');
        if (this[BUFFER].length)
            this[FLUSH]();
        else if (this[EOF])
            this[MAYBE_EMIT_END]();
        else
            this.emit('drain');
    }
    /**
     * Resume the stream if it is currently in a paused state
     *
     * If called when there are no pipe destinations or `data` event listeners,
     * this will place the stream in a "discarded" state, where all data will
     * be thrown away. The discarded state is removed if a pipe destination or
     * data handler is added, if pause() is called, or if any synchronous or
     * asynchronous iteration is started.
     */
    resume() {
        return this[RESUME]();
    }
    /**
     * Pause the stream
     */
    pause() {
        this[FLOWING] = false;
        this[PAUSED] = true;
        this[DISCARDED] = false;
    }
    /**
     * true if the stream has been forcibly destroyed
     */
    get destroyed() {
        return this[DESTROYED];
    }
    /**
     * true if the stream is currently in a flowing state, meaning that
     * any writes will be immediately emitted.
     */
    get flowing() {
        return this[FLOWING];
    }
    /**
     * true if the stream is currently in a paused state
     */
    get paused() {
        return this[PAUSED];
    }
    [BUFFERPUSH](chunk) {
        if (this[OBJECTMODE])
            this[BUFFERLENGTH] += 1;
        else
            this[BUFFERLENGTH] += chunk.length;
        this[BUFFER].push(chunk);
    }
    [BUFFERSHIFT]() {
        if (this[OBJECTMODE])
            this[BUFFERLENGTH] -= 1;
        else
            this[BUFFERLENGTH] -= this[BUFFER][0].length;
        return this[BUFFER].shift();
    }
    [FLUSH](noDrain = false) {
        do { } while (this[FLUSHCHUNK](this[BUFFERSHIFT]()) &&
            this[BUFFER].length);
        if (!noDrain && !this[BUFFER].length && !this[EOF])
            this.emit('drain');
    }
    [FLUSHCHUNK](chunk) {
        this.emit('data', chunk);
        return this[FLOWING];
    }
    /**
     * Pipe all data emitted by this stream into the destination provided.
     *
     * Triggers the flow of data.
     */
    pipe(dest, opts) {
        if (this[DESTROYED])
            return dest;
        this[DISCARDED] = false;
        const ended = this[EMITTED_END];
        opts = opts || {};
        if (dest === proc.stdout || dest === proc.stderr)
            opts.end = false;
        else
            opts.end = opts.end !== false;
        opts.proxyErrors = !!opts.proxyErrors;
        // piping an ended stream ends immediately
        if (ended) {
            if (opts.end)
                dest.end();
        }
        else {
            // "as" here just ignores the WType, which pipes don't care about,
            // since they're only consuming from us, and writing to the dest
            this[PIPES].push(!opts.proxyErrors
                ? new Pipe(this, dest, opts)
                : new PipeProxyErrors(this, dest, opts));
            if (this[ASYNC])
                defer(() => this[RESUME]());
            else
                this[RESUME]();
        }
        return dest;
    }
    /**
     * Fully unhook a piped destination stream.
     *
     * If the destination stream was the only consumer of this stream (ie,
     * there are no other piped destinations or `'data'` event listeners)
     * then the flow of data will stop until there is another consumer or
     * {@link Minipass#resume} is explicitly called.
     */
    unpipe(dest) {
        const p = this[PIPES].find(p => p.dest === dest);
        if (p) {
            if (this[PIPES].length === 1) {
                if (this[FLOWING] && this[DATALISTENERS] === 0) {
                    this[FLOWING] = false;
                }
                this[PIPES] = [];
            }
            else
                this[PIPES].splice(this[PIPES].indexOf(p), 1);
            p.unpipe();
        }
    }
    /**
     * Alias for {@link Minipass#on}
     */
    addListener(ev, handler) {
        return this.on(ev, handler);
    }
    /**
     * Mostly identical to `EventEmitter.on`, with the following
     * behavior differences to prevent data loss and unnecessary hangs:
     *
     * - Adding a 'data' event handler will trigger the flow of data
     *
     * - Adding a 'readable' event handler when there is data waiting to be read
     *   will cause 'readable' to be emitted immediately.
     *
     * - Adding an 'endish' event handler ('end', 'finish', etc.) which has
     *   already passed will cause the event to be emitted immediately and all
     *   handlers removed.
     *
     * - Adding an 'error' event handler after an error has been emitted will
     *   cause the event to be re-emitted immediately with the error previously
     *   raised.
     */
    on(ev, handler) {
        const ret = super.on(ev, handler);
        if (ev === 'data') {
            this[DISCARDED] = false;
            this[DATALISTENERS]++;
            if (!this[PIPES].length && !this[FLOWING]) {
                this[RESUME]();
            }
        }
        else if (ev === 'readable' && this[BUFFERLENGTH] !== 0) {
            super.emit('readable');
        }
        else if (isEndish(ev) && this[EMITTED_END]) {
            super.emit(ev);
            this.removeAllListeners(ev);
        }
        else if (ev === 'error' && this[EMITTED_ERROR]) {
            const h = handler;
            if (this[ASYNC])
                defer(() => h.call(this, this[EMITTED_ERROR]));
            else
                h.call(this, this[EMITTED_ERROR]);
        }
        return ret;
    }
    /**
     * Alias for {@link Minipass#off}
     */
    removeListener(ev, handler) {
        return this.off(ev, handler);
    }
    /**
     * Mostly identical to `EventEmitter.off`
     *
     * If a 'data' event handler is removed, and it was the last consumer
     * (ie, there are no pipe destinations or other 'data' event listeners),
     * then the flow of data will stop until there is another consumer or
     * {@link Minipass#resume} is explicitly called.
     */
    off(ev, handler) {
        const ret = super.off(ev, handler);
        // if we previously had listeners, and now we don't, and we don't
        // have any pipes, then stop the flow, unless it's been explicitly
        // put in a discarded flowing state via stream.resume().
        if (ev === 'data') {
            this[DATALISTENERS] = this.listeners('data').length;
            if (this[DATALISTENERS] === 0 &&
                !this[DISCARDED] &&
                !this[PIPES].length) {
                this[FLOWING] = false;
            }
        }
        return ret;
    }
    /**
     * Mostly identical to `EventEmitter.removeAllListeners`
     *
     * If all 'data' event handlers are removed, and they were the last consumer
     * (ie, there are no pipe destinations), then the flow of data will stop
     * until there is another consumer or {@link Minipass#resume} is explicitly
     * called.
     */
    removeAllListeners(ev) {
        const ret = super.removeAllListeners(ev);
        if (ev === 'data' || ev === undefined) {
            this[DATALISTENERS] = 0;
            if (!this[DISCARDED] && !this[PIPES].length) {
                this[FLOWING] = false;
            }
        }
        return ret;
    }
    /**
     * true if the 'end' event has been emitted
     */
    get emittedEnd() {
        return this[EMITTED_END];
    }
    [MAYBE_EMIT_END]() {
        if (!this[EMITTING_END] &&
            !this[EMITTED_END] &&
            !this[DESTROYED] &&
            this[BUFFER].length === 0 &&
            this[EOF]) {
            this[EMITTING_END] = true;
            this.emit('end');
            this.emit('prefinish');
            this.emit('finish');
            if (this[CLOSED])
                this.emit('close');
            this[EMITTING_END] = false;
        }
    }
    /**
     * Mostly identical to `EventEmitter.emit`, with the following
     * behavior differences to prevent data loss and unnecessary hangs:
     *
     * If the stream has been destroyed, and the event is something other
     * than 'close' or 'error', then `false` is returned and no handlers
     * are called.
     *
     * If the event is 'end', and has already been emitted, then the event
     * is ignored. If the stream is in a paused or non-flowing state, then
     * the event will be deferred until data flow resumes. If the stream is
     * async, then handlers will be called on the next tick rather than
     * immediately.
     *
     * If the event is 'close', and 'end' has not yet been emitted, then
     * the event will be deferred until after 'end' is emitted.
     *
     * If the event is 'error', and an AbortSignal was provided for the stream,
     * and there are no listeners, then the event is ignored, matching the
     * behavior of node core streams in the presense of an AbortSignal.
     *
     * If the event is 'finish' or 'prefinish', then all listeners will be
     * removed after emitting the event, to prevent double-firing.
     */
    emit(ev, ...args) {
        const data = args[0];
        // error and close are only events allowed after calling destroy()
        if (ev !== 'error' &&
            ev !== 'close' &&
            ev !== DESTROYED &&
            this[DESTROYED]) {
            return false;
        }
        else if (ev === 'data') {
            return !this[OBJECTMODE] && !data
                ? false
                : this[ASYNC]
                    ? (defer(() => this[EMITDATA](data)), true)
                    : this[EMITDATA](data);
        }
        else if (ev === 'end') {
            return this[EMITEND]();
        }
        else if (ev === 'close') {
            this[CLOSED] = true;
            // don't emit close before 'end' and 'finish'
            if (!this[EMITTED_END] && !this[DESTROYED])
                return false;
            const ret = super.emit('close');
            this.removeAllListeners('close');
            return ret;
        }
        else if (ev === 'error') {
            this[EMITTED_ERROR] = data;
            super.emit(ERROR, data);
            const ret = !this[SIGNAL] || this.listeners('error').length
                ? super.emit('error', data)
                : false;
            this[MAYBE_EMIT_END]();
            return ret;
        }
        else if (ev === 'resume') {
            const ret = super.emit('resume');
            this[MAYBE_EMIT_END]();
            return ret;
        }
        else if (ev === 'finish' || ev === 'prefinish') {
            const ret = super.emit(ev);
            this.removeAllListeners(ev);
            return ret;
        }
        // Some other unknown event
        const ret = super.emit(ev, ...args);
        this[MAYBE_EMIT_END]();
        return ret;
    }
    [EMITDATA](data) {
        for (const p of this[PIPES]) {
            if (p.dest.write(data) === false)
                this.pause();
        }
        const ret = this[DISCARDED] ? false : super.emit('data', data);
        this[MAYBE_EMIT_END]();
        return ret;
    }
    [EMITEND]() {
        if (this[EMITTED_END])
            return false;
        this[EMITTED_END] = true;
        this.readable = false;
        return this[ASYNC]
            ? (defer(() => this[EMITEND2]()), true)
            : this[EMITEND2]();
    }
    [EMITEND2]() {
        if (this[DECODER]) {
            const data = this[DECODER].end();
            if (data) {
                for (const p of this[PIPES]) {
                    p.dest.write(data);
                }
                if (!this[DISCARDED])
                    super.emit('data', data);
            }
        }
        for (const p of this[PIPES]) {
            p.end();
        }
        const ret = super.emit('end');
        this.removeAllListeners('end');
        return ret;
    }
    /**
     * Return a Promise that resolves to an array of all emitted data once
     * the stream ends.
     */
    async collect() {
        const buf = Object.assign([], {
            dataLength: 0,
        });
        if (!this[OBJECTMODE])
            buf.dataLength = 0;
        // set the promise first, in case an error is raised
        // by triggering the flow here.
        const p = this.promise();
        this.on('data', c => {
            buf.push(c);
            if (!this[OBJECTMODE])
                buf.dataLength += c.length;
        });
        await p;
        return buf;
    }
    /**
     * Return a Promise that resolves to the concatenation of all emitted data
     * once the stream ends.
     *
     * Not allowed on objectMode streams.
     */
    async concat() {
        if (this[OBJECTMODE]) {
            throw new Error('cannot concat in objectMode');
        }
        const buf = await this.collect();
        return (this[ENCODING$1]
            ? buf.join('')
            : Buffer.concat(buf, buf.dataLength));
    }
    /**
     * Return a void Promise that resolves once the stream ends.
     */
    async promise() {
        return new Promise((resolve, reject) => {
            this.on(DESTROYED, () => reject(new Error('stream destroyed')));
            this.on('error', er => reject(er));
            this.on('end', () => resolve());
        });
    }
    /**
     * Asynchronous `for await of` iteration.
     *
     * This will continue emitting all chunks until the stream terminates.
     */
    [Symbol.asyncIterator]() {
        // set this up front, in case the consumer doesn't call next()
        // right away.
        this[DISCARDED] = false;
        let stopped = false;
        const stop = async () => {
            this.pause();
            stopped = true;
            return { value: undefined, done: true };
        };
        const next = () => {
            if (stopped)
                return stop();
            const res = this.read();
            if (res !== null)
                return Promise.resolve({ done: false, value: res });
            if (this[EOF])
                return stop();
            let resolve;
            let reject;
            const onerr = (er) => {
                this.off('data', ondata);
                this.off('end', onend);
                this.off(DESTROYED, ondestroy);
                stop();
                reject(er);
            };
            const ondata = (value) => {
                this.off('error', onerr);
                this.off('end', onend);
                this.off(DESTROYED, ondestroy);
                this.pause();
                resolve({ value, done: !!this[EOF] });
            };
            const onend = () => {
                this.off('error', onerr);
                this.off('data', ondata);
                this.off(DESTROYED, ondestroy);
                stop();
                resolve({ done: true, value: undefined });
            };
            const ondestroy = () => onerr(new Error('stream destroyed'));
            return new Promise((res, rej) => {
                reject = rej;
                resolve = res;
                this.once(DESTROYED, ondestroy);
                this.once('error', onerr);
                this.once('end', onend);
                this.once('data', ondata);
            });
        };
        return {
            next,
            throw: stop,
            return: stop,
            [Symbol.asyncIterator]() {
                return this;
            },
        };
    }
    /**
     * Synchronous `for of` iteration.
     *
     * The iteration will terminate when the internal buffer runs out, even
     * if the stream has not yet terminated.
     */
    [Symbol.iterator]() {
        // set this up front, in case the consumer doesn't call next()
        // right away.
        this[DISCARDED] = false;
        let stopped = false;
        const stop = () => {
            this.pause();
            this.off(ERROR, stop);
            this.off(DESTROYED, stop);
            this.off('end', stop);
            stopped = true;
            return { done: true, value: undefined };
        };
        const next = () => {
            if (stopped)
                return stop();
            const value = this.read();
            return value === null ? stop() : { done: false, value };
        };
        this.once('end', stop);
        this.once(ERROR, stop);
        this.once(DESTROYED, stop);
        return {
            next,
            throw: stop,
            return: stop,
            [Symbol.iterator]() {
                return this;
            },
        };
    }
    /**
     * Destroy a stream, preventing it from being used for any further purpose.
     *
     * If the stream has a `close()` method, then it will be called on
     * destruction.
     *
     * After destruction, any attempt to write data, read data, or emit most
     * events will be ignored.
     *
     * If an error argument is provided, then it will be emitted in an
     * 'error' event.
     */
    destroy(er) {
        if (this[DESTROYED]) {
            if (er)
                this.emit('error', er);
            else
                this.emit(DESTROYED);
            return this;
        }
        this[DESTROYED] = true;
        this[DISCARDED] = true;
        // throw away all buffered data, it's never coming out
        this[BUFFER].length = 0;
        this[BUFFERLENGTH] = 0;
        const wc = this;
        if (typeof wc.close === 'function' && !this[CLOSED])
            wc.close();
        if (er)
            this.emit('error', er);
        // if no error to emit, still reject pending promises
        else
            this.emit(DESTROYED);
        return this;
    }
    /**
     * Alias for {@link isStream}
     *
     * Former export location, maintained for backwards compatibility.
     *
     * @deprecated
     */
    static get isStream() {
        return isStream;
    }
}

const realpathSync = realpathSync$1.native;
const defaultFS = {
    lstatSync,
    readdir: readdir$2,
    readdirSync: readdirSync$1,
    readlinkSync,
    realpathSync,
    promises: {
        lstat: lstat$3,
        readdir: readdir$1,
        readlink,
        realpath,
    },
};
// if they just gave us require('fs') then use our default
const fsFromOption = (fsOption) => !fsOption || fsOption === defaultFS || fsOption === fs$2 ?
    defaultFS
    : {
        ...defaultFS,
        ...fsOption,
        promises: {
            ...defaultFS.promises,
            ...(fsOption.promises || {}),
        },
    };
// turn something like //?/c:/ into c:\
const uncDriveRegexp = /^\\\\\?\\([a-z]:)\\?$/i;
const uncToDrive = (rootPath) => rootPath.replace(/\//g, '\\').replace(uncDriveRegexp, '$1\\');
// windows paths are separated by either / or \
const eitherSep = /[\\\/]/;
const UNKNOWN = 0; // may not even exist, for all we know
const IFIFO = 0b0001;
const IFCHR = 0b0010;
const IFDIR = 0b0100;
const IFBLK = 0b0110;
const IFREG = 0b1000;
const IFLNK = 0b1010;
const IFSOCK = 0b1100;
const IFMT = 0b1111;
// mask to unset low 4 bits
const IFMT_UNKNOWN = ~IFMT;
// set after successfully calling readdir() and getting entries.
const READDIR_CALLED = 0b0000_0001_0000;
// set after a successful lstat()
const LSTAT_CALLED = 0b0000_0010_0000;
// set if an entry (or one of its parents) is definitely not a dir
const ENOTDIR = 0b0000_0100_0000;
// set if an entry (or one of its parents) does not exist
// (can also be set on lstat errors like EACCES or ENAMETOOLONG)
const ENOENT = 0b0000_1000_0000;
// cannot have child entries -- also verify &IFMT is either IFDIR or IFLNK
// set if we fail to readlink
const ENOREADLINK = 0b0001_0000_0000;
// set if we know realpath() will fail
const ENOREALPATH = 0b0010_0000_0000;
const ENOCHILD = ENOTDIR | ENOENT | ENOREALPATH;
const TYPEMASK = 0b0011_1111_1111;
const entToType = (s) => s.isFile() ? IFREG
    : s.isDirectory() ? IFDIR
        : s.isSymbolicLink() ? IFLNK
            : s.isCharacterDevice() ? IFCHR
                : s.isBlockDevice() ? IFBLK
                    : s.isSocket() ? IFSOCK
                        : s.isFIFO() ? IFIFO
                            : UNKNOWN;
// normalize unicode path names
const normalizeCache = new LRUCache({ max: 2 ** 12 });
const normalize$2 = (s) => {
    const c = normalizeCache.get(s);
    if (c)
        return c;
    const n = s.normalize('NFKD');
    normalizeCache.set(s, n);
    return n;
};
const normalizeNocaseCache = new LRUCache({ max: 2 ** 12 });
const normalizeNocase = (s) => {
    const c = normalizeNocaseCache.get(s);
    if (c)
        return c;
    const n = normalize$2(s.toLowerCase());
    normalizeNocaseCache.set(s, n);
    return n;
};
/**
 * An LRUCache for storing resolved path strings or Path objects.
 * @internal
 */
class ResolveCache extends LRUCache {
    constructor() {
        super({ max: 256 });
    }
}
// In order to prevent blowing out the js heap by allocating hundreds of
// thousands of Path entries when walking extremely large trees, the "children"
// in this tree are represented by storing an array of Path entries in an
// LRUCache, indexed by the parent.  At any time, Path.children() may return an
// empty array, indicating that it doesn't know about any of its children, and
// thus has to rebuild that cache.  This is fine, it just means that we don't
// benefit as much from having the cached entries, but huge directory walks
// don't blow out the stack, and smaller ones are still as fast as possible.
//
//It does impose some complexity when building up the readdir data, because we
//need to pass a reference to the children array that we started with.
/**
 * an LRUCache for storing child entries.
 * @internal
 */
class ChildrenCache extends LRUCache {
    constructor(maxSize = 16 * 1024) {
        super({
            maxSize,
            // parent + children
            sizeCalculation: a => a.length + 1,
        });
    }
}
const setAsCwd = Symbol('PathScurry setAsCwd');
/**
 * Path objects are sort of like a super-powered
 * {@link https://nodejs.org/docs/latest/api/fs.html#class-fsdirent fs.Dirent}
 *
 * Each one represents a single filesystem entry on disk, which may or may not
 * exist. It includes methods for reading various types of information via
 * lstat, readlink, and readdir, and caches all information to the greatest
 * degree possible.
 *
 * Note that fs operations that would normally throw will instead return an
 * "empty" value. This is in order to prevent excessive overhead from error
 * stack traces.
 */
class PathBase {
    /**
     * the basename of this path
     *
     * **Important**: *always* test the path name against any test string
     * usingthe {@link isNamed} method, and not by directly comparing this
     * string. Otherwise, unicode path strings that the system sees as identical
     * will not be properly treated as the same path, leading to incorrect
     * behavior and possible security issues.
     */
    name;
    /**
     * the Path entry corresponding to the path root.
     *
     * @internal
     */
    root;
    /**
     * All roots found within the current PathScurry family
     *
     * @internal
     */
    roots;
    /**
     * a reference to the parent path, or undefined in the case of root entries
     *
     * @internal
     */
    parent;
    /**
     * boolean indicating whether paths are compared case-insensitively
     * @internal
     */
    nocase;
    /**
     * boolean indicating that this path is the current working directory
     * of the PathScurry collection that contains it.
     */
    isCWD = false;
    // potential default fs override
    #fs;
    // Stats fields
    #dev;
    get dev() {
        return this.#dev;
    }
    #mode;
    get mode() {
        return this.#mode;
    }
    #nlink;
    get nlink() {
        return this.#nlink;
    }
    #uid;
    get uid() {
        return this.#uid;
    }
    #gid;
    get gid() {
        return this.#gid;
    }
    #rdev;
    get rdev() {
        return this.#rdev;
    }
    #blksize;
    get blksize() {
        return this.#blksize;
    }
    #ino;
    get ino() {
        return this.#ino;
    }
    #size;
    get size() {
        return this.#size;
    }
    #blocks;
    get blocks() {
        return this.#blocks;
    }
    #atimeMs;
    get atimeMs() {
        return this.#atimeMs;
    }
    #mtimeMs;
    get mtimeMs() {
        return this.#mtimeMs;
    }
    #ctimeMs;
    get ctimeMs() {
        return this.#ctimeMs;
    }
    #birthtimeMs;
    get birthtimeMs() {
        return this.#birthtimeMs;
    }
    #atime;
    get atime() {
        return this.#atime;
    }
    #mtime;
    get mtime() {
        return this.#mtime;
    }
    #ctime;
    get ctime() {
        return this.#ctime;
    }
    #birthtime;
    get birthtime() {
        return this.#birthtime;
    }
    #matchName;
    #depth;
    #fullpath;
    #fullpathPosix;
    #relative;
    #relativePosix;
    #type;
    #children;
    #linkTarget;
    #realpath;
    /**
     * This property is for compatibility with the Dirent class as of
     * Node v20, where Dirent['parentPath'] refers to the path of the
     * directory that was passed to readdir. For root entries, it's the path
     * to the entry itself.
     */
    get parentPath() {
        return (this.parent || this).fullpath();
    }
    /* c8 ignore start */
    /**
     * Deprecated alias for Dirent['parentPath'] Somewhat counterintuitively,
     * this property refers to the *parent* path, not the path object itself.
     *
     * @deprecated
     */
    get path() {
        return this.parentPath;
    }
    /* c8 ignore stop */
    /**
     * Do not create new Path objects directly.  They should always be accessed
     * via the PathScurry class or other methods on the Path class.
     *
     * @internal
     */
    constructor(name, type = UNKNOWN, root, roots, nocase, children, opts) {
        this.name = name;
        this.#matchName = nocase ? normalizeNocase(name) : normalize$2(name);
        this.#type = type & TYPEMASK;
        this.nocase = nocase;
        this.roots = roots;
        this.root = root || this;
        this.#children = children;
        this.#fullpath = opts.fullpath;
        this.#relative = opts.relative;
        this.#relativePosix = opts.relativePosix;
        this.parent = opts.parent;
        if (this.parent) {
            this.#fs = this.parent.#fs;
        }
        else {
            this.#fs = fsFromOption(opts.fs);
        }
    }
    /**
     * Returns the depth of the Path object from its root.
     *
     * For example, a path at `/foo/bar` would have a depth of 2.
     */
    depth() {
        if (this.#depth !== undefined)
            return this.#depth;
        if (!this.parent)
            return (this.#depth = 0);
        return (this.#depth = this.parent.depth() + 1);
    }
    /**
     * @internal
     */
    childrenCache() {
        return this.#children;
    }
    /**
     * Get the Path object referenced by the string path, resolved from this Path
     */
    resolve(path) {
        if (!path) {
            return this;
        }
        const rootPath = this.getRootString(path);
        const dir = path.substring(rootPath.length);
        const dirParts = dir.split(this.splitSep);
        const result = rootPath ?
            this.getRoot(rootPath).#resolveParts(dirParts)
            : this.#resolveParts(dirParts);
        return result;
    }
    #resolveParts(dirParts) {
        let p = this;
        for (const part of dirParts) {
            p = p.child(part);
        }
        return p;
    }
    /**
     * Returns the cached children Path objects, if still available.  If they
     * have fallen out of the cache, then returns an empty array, and resets the
     * READDIR_CALLED bit, so that future calls to readdir() will require an fs
     * lookup.
     *
     * @internal
     */
    children() {
        const cached = this.#children.get(this);
        if (cached) {
            return cached;
        }
        const children = Object.assign([], { provisional: 0 });
        this.#children.set(this, children);
        this.#type &= ~READDIR_CALLED;
        return children;
    }
    /**
     * Resolves a path portion and returns or creates the child Path.
     *
     * Returns `this` if pathPart is `''` or `'.'`, or `parent` if pathPart is
     * `'..'`.
     *
     * This should not be called directly.  If `pathPart` contains any path
     * separators, it will lead to unsafe undefined behavior.
     *
     * Use `Path.resolve()` instead.
     *
     * @internal
     */
    child(pathPart, opts) {
        if (pathPart === '' || pathPart === '.') {
            return this;
        }
        if (pathPart === '..') {
            return this.parent || this;
        }
        // find the child
        const children = this.children();
        const name = this.nocase ? normalizeNocase(pathPart) : normalize$2(pathPart);
        for (const p of children) {
            if (p.#matchName === name) {
                return p;
            }
        }
        // didn't find it, create provisional child, since it might not
        // actually exist.  If we know the parent isn't a dir, then
        // in fact it CAN'T exist.
        const s = this.parent ? this.sep : '';
        const fullpath = this.#fullpath ? this.#fullpath + s + pathPart : undefined;
        const pchild = this.newChild(pathPart, UNKNOWN, {
            ...opts,
            parent: this,
            fullpath,
        });
        if (!this.canReaddir()) {
            pchild.#type |= ENOENT;
        }
        // don't have to update provisional, because if we have real children,
        // then provisional is set to children.length, otherwise a lower number
        children.push(pchild);
        return pchild;
    }
    /**
     * The relative path from the cwd. If it does not share an ancestor with
     * the cwd, then this ends up being equivalent to the fullpath()
     */
    relative() {
        if (this.isCWD)
            return '';
        if (this.#relative !== undefined) {
            return this.#relative;
        }
        const name = this.name;
        const p = this.parent;
        if (!p) {
            return (this.#relative = this.name);
        }
        const pv = p.relative();
        return pv + (!pv || !p.parent ? '' : this.sep) + name;
    }
    /**
     * The relative path from the cwd, using / as the path separator.
     * If it does not share an ancestor with
     * the cwd, then this ends up being equivalent to the fullpathPosix()
     * On posix systems, this is identical to relative().
     */
    relativePosix() {
        if (this.sep === '/')
            return this.relative();
        if (this.isCWD)
            return '';
        if (this.#relativePosix !== undefined)
            return this.#relativePosix;
        const name = this.name;
        const p = this.parent;
        if (!p) {
            return (this.#relativePosix = this.fullpathPosix());
        }
        const pv = p.relativePosix();
        return pv + (!pv || !p.parent ? '' : '/') + name;
    }
    /**
     * The fully resolved path string for this Path entry
     */
    fullpath() {
        if (this.#fullpath !== undefined) {
            return this.#fullpath;
        }
        const name = this.name;
        const p = this.parent;
        if (!p) {
            return (this.#fullpath = this.name);
        }
        const pv = p.fullpath();
        const fp = pv + (!p.parent ? '' : this.sep) + name;
        return (this.#fullpath = fp);
    }
    /**
     * On platforms other than windows, this is identical to fullpath.
     *
     * On windows, this is overridden to return the forward-slash form of the
     * full UNC path.
     */
    fullpathPosix() {
        if (this.#fullpathPosix !== undefined)
            return this.#fullpathPosix;
        if (this.sep === '/')
            return (this.#fullpathPosix = this.fullpath());
        if (!this.parent) {
            const p = this.fullpath().replace(/\\/g, '/');
            if (/^[a-z]:\//i.test(p)) {
                return (this.#fullpathPosix = `//?/${p}`);
            }
            else {
                return (this.#fullpathPosix = p);
            }
        }
        const p = this.parent;
        const pfpp = p.fullpathPosix();
        const fpp = pfpp + (!pfpp || !p.parent ? '' : '/') + this.name;
        return (this.#fullpathPosix = fpp);
    }
    /**
     * Is the Path of an unknown type?
     *
     * Note that we might know *something* about it if there has been a previous
     * filesystem operation, for example that it does not exist, or is not a
     * link, or whether it has child entries.
     */
    isUnknown() {
        return (this.#type & IFMT) === UNKNOWN;
    }
    isType(type) {
        return this[`is${type}`]();
    }
    getType() {
        return (this.isUnknown() ? 'Unknown'
            : this.isDirectory() ? 'Directory'
                : this.isFile() ? 'File'
                    : this.isSymbolicLink() ? 'SymbolicLink'
                        : this.isFIFO() ? 'FIFO'
                            : this.isCharacterDevice() ? 'CharacterDevice'
                                : this.isBlockDevice() ? 'BlockDevice'
                                    : /* c8 ignore start */ this.isSocket() ? 'Socket'
                                        : 'Unknown');
        /* c8 ignore stop */
    }
    /**
     * Is the Path a regular file?
     */
    isFile() {
        return (this.#type & IFMT) === IFREG;
    }
    /**
     * Is the Path a directory?
     */
    isDirectory() {
        return (this.#type & IFMT) === IFDIR;
    }
    /**
     * Is the path a character device?
     */
    isCharacterDevice() {
        return (this.#type & IFMT) === IFCHR;
    }
    /**
     * Is the path a block device?
     */
    isBlockDevice() {
        return (this.#type & IFMT) === IFBLK;
    }
    /**
     * Is the path a FIFO pipe?
     */
    isFIFO() {
        return (this.#type & IFMT) === IFIFO;
    }
    /**
     * Is the path a socket?
     */
    isSocket() {
        return (this.#type & IFMT) === IFSOCK;
    }
    /**
     * Is the path a symbolic link?
     */
    isSymbolicLink() {
        return (this.#type & IFLNK) === IFLNK;
    }
    /**
     * Return the entry if it has been subject of a successful lstat, or
     * undefined otherwise.
     *
     * Does not read the filesystem, so an undefined result *could* simply
     * mean that we haven't called lstat on it.
     */
    lstatCached() {
        return this.#type & LSTAT_CALLED ? this : undefined;
    }
    /**
     * Return the cached link target if the entry has been the subject of a
     * successful readlink, or undefined otherwise.
     *
     * Does not read the filesystem, so an undefined result *could* just mean we
     * don't have any cached data. Only use it if you are very sure that a
     * readlink() has been called at some point.
     */
    readlinkCached() {
        return this.#linkTarget;
    }
    /**
     * Returns the cached realpath target if the entry has been the subject
     * of a successful realpath, or undefined otherwise.
     *
     * Does not read the filesystem, so an undefined result *could* just mean we
     * don't have any cached data. Only use it if you are very sure that a
     * realpath() has been called at some point.
     */
    realpathCached() {
        return this.#realpath;
    }
    /**
     * Returns the cached child Path entries array if the entry has been the
     * subject of a successful readdir(), or [] otherwise.
     *
     * Does not read the filesystem, so an empty array *could* just mean we
     * don't have any cached data. Only use it if you are very sure that a
     * readdir() has been called recently enough to still be valid.
     */
    readdirCached() {
        const children = this.children();
        return children.slice(0, children.provisional);
    }
    /**
     * Return true if it's worth trying to readlink.  Ie, we don't (yet) have
     * any indication that readlink will definitely fail.
     *
     * Returns false if the path is known to not be a symlink, if a previous
     * readlink failed, or if the entry does not exist.
     */
    canReadlink() {
        if (this.#linkTarget)
            return true;
        if (!this.parent)
            return false;
        // cases where it cannot possibly succeed
        const ifmt = this.#type & IFMT;
        return !((ifmt !== UNKNOWN && ifmt !== IFLNK) ||
            this.#type & ENOREADLINK ||
            this.#type & ENOENT);
    }
    /**
     * Return true if readdir has previously been successfully called on this
     * path, indicating that cachedReaddir() is likely valid.
     */
    calledReaddir() {
        return !!(this.#type & READDIR_CALLED);
    }
    /**
     * Returns true if the path is known to not exist. That is, a previous lstat
     * or readdir failed to verify its existence when that would have been
     * expected, or a parent entry was marked either enoent or enotdir.
     */
    isENOENT() {
        return !!(this.#type & ENOENT);
    }
    /**
     * Return true if the path is a match for the given path name.  This handles
     * case sensitivity and unicode normalization.
     *
     * Note: even on case-sensitive systems, it is **not** safe to test the
     * equality of the `.name` property to determine whether a given pathname
     * matches, due to unicode normalization mismatches.
     *
     * Always use this method instead of testing the `path.name` property
     * directly.
     */
    isNamed(n) {
        return !this.nocase ?
            this.#matchName === normalize$2(n)
            : this.#matchName === normalizeNocase(n);
    }
    /**
     * Return the Path object corresponding to the target of a symbolic link.
     *
     * If the Path is not a symbolic link, or if the readlink call fails for any
     * reason, `undefined` is returned.
     *
     * Result is cached, and thus may be outdated if the filesystem is mutated.
     */
    async readlink() {
        const target = this.#linkTarget;
        if (target) {
            return target;
        }
        if (!this.canReadlink()) {
            return undefined;
        }
        /* c8 ignore start */
        // already covered by the canReadlink test, here for ts grumples
        if (!this.parent) {
            return undefined;
        }
        /* c8 ignore stop */
        try {
            const read = await this.#fs.promises.readlink(this.fullpath());
            const linkTarget = (await this.parent.realpath())?.resolve(read);
            if (linkTarget) {
                return (this.#linkTarget = linkTarget);
            }
        }
        catch (er) {
            this.#readlinkFail(er.code);
            return undefined;
        }
    }
    /**
     * Synchronous {@link PathBase.readlink}
     */
    readlinkSync() {
        const target = this.#linkTarget;
        if (target) {
            return target;
        }
        if (!this.canReadlink()) {
            return undefined;
        }
        /* c8 ignore start */
        // already covered by the canReadlink test, here for ts grumples
        if (!this.parent) {
            return undefined;
        }
        /* c8 ignore stop */
        try {
            const read = this.#fs.readlinkSync(this.fullpath());
            const linkTarget = this.parent.realpathSync()?.resolve(read);
            if (linkTarget) {
                return (this.#linkTarget = linkTarget);
            }
        }
        catch (er) {
            this.#readlinkFail(er.code);
            return undefined;
        }
    }
    #readdirSuccess(children) {
        // succeeded, mark readdir called bit
        this.#type |= READDIR_CALLED;
        // mark all remaining provisional children as ENOENT
        for (let p = children.provisional; p < children.length; p++) {
            const c = children[p];
            if (c)
                c.#markENOENT();
        }
    }
    #markENOENT() {
        // mark as UNKNOWN and ENOENT
        if (this.#type & ENOENT)
            return;
        this.#type = (this.#type | ENOENT) & IFMT_UNKNOWN;
        this.#markChildrenENOENT();
    }
    #markChildrenENOENT() {
        // all children are provisional and do not exist
        const children = this.children();
        children.provisional = 0;
        for (const p of children) {
            p.#markENOENT();
        }
    }
    #markENOREALPATH() {
        this.#type |= ENOREALPATH;
        this.#markENOTDIR();
    }
    // save the information when we know the entry is not a dir
    #markENOTDIR() {
        // entry is not a directory, so any children can't exist.
        // this *should* be impossible, since any children created
        // after it's been marked ENOTDIR should be marked ENOENT,
        // so it won't even get to this point.
        /* c8 ignore start */
        if (this.#type & ENOTDIR)
            return;
        /* c8 ignore stop */
        let t = this.#type;
        // this could happen if we stat a dir, then delete it,
        // then try to read it or one of its children.
        if ((t & IFMT) === IFDIR)
            t &= IFMT_UNKNOWN;
        this.#type = t | ENOTDIR;
        this.#markChildrenENOENT();
    }
    #readdirFail(code = '') {
        // markENOTDIR and markENOENT also set provisional=0
        if (code === 'ENOTDIR' || code === 'EPERM') {
            this.#markENOTDIR();
        }
        else if (code === 'ENOENT') {
            this.#markENOENT();
        }
        else {
            this.children().provisional = 0;
        }
    }
    #lstatFail(code = '') {
        // Windows just raises ENOENT in this case, disable for win CI
        /* c8 ignore start */
        if (code === 'ENOTDIR') {
            // already know it has a parent by this point
            const p = this.parent;
            p.#markENOTDIR();
        }
        else if (code === 'ENOENT') {
            /* c8 ignore stop */
            this.#markENOENT();
        }
    }
    #readlinkFail(code = '') {
        let ter = this.#type;
        ter |= ENOREADLINK;
        if (code === 'ENOENT')
            ter |= ENOENT;
        // windows gets a weird error when you try to readlink a file
        if (code === 'EINVAL' || code === 'UNKNOWN') {
            // exists, but not a symlink, we don't know WHAT it is, so remove
            // all IFMT bits.
            ter &= IFMT_UNKNOWN;
        }
        this.#type = ter;
        // windows just gets ENOENT in this case.  We do cover the case,
        // just disabled because it's impossible on Windows CI
        /* c8 ignore start */
        if (code === 'ENOTDIR' && this.parent) {
            this.parent.#markENOTDIR();
        }
        /* c8 ignore stop */
    }
    #readdirAddChild(e, c) {
        return (this.#readdirMaybePromoteChild(e, c) ||
            this.#readdirAddNewChild(e, c));
    }
    #readdirAddNewChild(e, c) {
        // alloc new entry at head, so it's never provisional
        const type = entToType(e);
        const child = this.newChild(e.name, type, { parent: this });
        const ifmt = child.#type & IFMT;
        if (ifmt !== IFDIR && ifmt !== IFLNK && ifmt !== UNKNOWN) {
            child.#type |= ENOTDIR;
        }
        c.unshift(child);
        c.provisional++;
        return child;
    }
    #readdirMaybePromoteChild(e, c) {
        for (let p = c.provisional; p < c.length; p++) {
            const pchild = c[p];
            const name = this.nocase ? normalizeNocase(e.name) : normalize$2(e.name);
            if (name !== pchild.#matchName) {
                continue;
            }
            return this.#readdirPromoteChild(e, pchild, p, c);
        }
    }
    #readdirPromoteChild(e, p, index, c) {
        const v = p.name;
        // retain any other flags, but set ifmt from dirent
        p.#type = (p.#type & IFMT_UNKNOWN) | entToType(e);
        // case sensitivity fixing when we learn the true name.
        if (v !== e.name)
            p.name = e.name;
        // just advance provisional index (potentially off the list),
        // otherwise we have to splice/pop it out and re-insert at head
        if (index !== c.provisional) {
            if (index === c.length - 1)
                c.pop();
            else
                c.splice(index, 1);
            c.unshift(p);
        }
        c.provisional++;
        return p;
    }
    /**
     * Call lstat() on this Path, and update all known information that can be
     * determined.
     *
     * Note that unlike `fs.lstat()`, the returned value does not contain some
     * information, such as `mode`, `dev`, `nlink`, and `ino`.  If that
     * information is required, you will need to call `fs.lstat` yourself.
     *
     * If the Path refers to a nonexistent file, or if the lstat call fails for
     * any reason, `undefined` is returned.  Otherwise the updated Path object is
     * returned.
     *
     * Results are cached, and thus may be out of date if the filesystem is
     * mutated.
     */
    async lstat() {
        if ((this.#type & ENOENT) === 0) {
            try {
                this.#applyStat(await this.#fs.promises.lstat(this.fullpath()));
                return this;
            }
            catch (er) {
                this.#lstatFail(er.code);
            }
        }
    }
    /**
     * synchronous {@link PathBase.lstat}
     */
    lstatSync() {
        if ((this.#type & ENOENT) === 0) {
            try {
                this.#applyStat(this.#fs.lstatSync(this.fullpath()));
                return this;
            }
            catch (er) {
                this.#lstatFail(er.code);
            }
        }
    }
    #applyStat(st) {
        const { atime, atimeMs, birthtime, birthtimeMs, blksize, blocks, ctime, ctimeMs, dev, gid, ino, mode, mtime, mtimeMs, nlink, rdev, size, uid, } = st;
        this.#atime = atime;
        this.#atimeMs = atimeMs;
        this.#birthtime = birthtime;
        this.#birthtimeMs = birthtimeMs;
        this.#blksize = blksize;
        this.#blocks = blocks;
        this.#ctime = ctime;
        this.#ctimeMs = ctimeMs;
        this.#dev = dev;
        this.#gid = gid;
        this.#ino = ino;
        this.#mode = mode;
        this.#mtime = mtime;
        this.#mtimeMs = mtimeMs;
        this.#nlink = nlink;
        this.#rdev = rdev;
        this.#size = size;
        this.#uid = uid;
        const ifmt = entToType(st);
        // retain any other flags, but set the ifmt
        this.#type = (this.#type & IFMT_UNKNOWN) | ifmt | LSTAT_CALLED;
        if (ifmt !== UNKNOWN && ifmt !== IFDIR && ifmt !== IFLNK) {
            this.#type |= ENOTDIR;
        }
    }
    #onReaddirCB = [];
    #readdirCBInFlight = false;
    #callOnReaddirCB(children) {
        this.#readdirCBInFlight = false;
        const cbs = this.#onReaddirCB.slice();
        this.#onReaddirCB.length = 0;
        cbs.forEach(cb => cb(null, children));
    }
    /**
     * Standard node-style callback interface to get list of directory entries.
     *
     * If the Path cannot or does not contain any children, then an empty array
     * is returned.
     *
     * Results are cached, and thus may be out of date if the filesystem is
     * mutated.
     *
     * @param cb The callback called with (er, entries).  Note that the `er`
     * param is somewhat extraneous, as all readdir() errors are handled and
     * simply result in an empty set of entries being returned.
     * @param allowZalgo Boolean indicating that immediately known results should
     * *not* be deferred with `queueMicrotask`. Defaults to `false`. Release
     * zalgo at your peril, the dark pony lord is devious and unforgiving.
     */
    readdirCB(cb, allowZalgo = false) {
        if (!this.canReaddir()) {
            if (allowZalgo)
                cb(null, []);
            else
                queueMicrotask(() => cb(null, []));
            return;
        }
        const children = this.children();
        if (this.calledReaddir()) {
            const c = children.slice(0, children.provisional);
            if (allowZalgo)
                cb(null, c);
            else
                queueMicrotask(() => cb(null, c));
            return;
        }
        // don't have to worry about zalgo at this point.
        this.#onReaddirCB.push(cb);
        if (this.#readdirCBInFlight) {
            return;
        }
        this.#readdirCBInFlight = true;
        // else read the directory, fill up children
        // de-provisionalize any provisional children.
        const fullpath = this.fullpath();
        this.#fs.readdir(fullpath, { withFileTypes: true }, (er, entries) => {
            if (er) {
                this.#readdirFail(er.code);
                children.provisional = 0;
            }
            else {
                // if we didn't get an error, we always get entries.
                //@ts-ignore
                for (const e of entries) {
                    this.#readdirAddChild(e, children);
                }
                this.#readdirSuccess(children);
            }
            this.#callOnReaddirCB(children.slice(0, children.provisional));
            return;
        });
    }
    #asyncReaddirInFlight;
    /**
     * Return an array of known child entries.
     *
     * If the Path cannot or does not contain any children, then an empty array
     * is returned.
     *
     * Results are cached, and thus may be out of date if the filesystem is
     * mutated.
     */
    async readdir() {
        if (!this.canReaddir()) {
            return [];
        }
        const children = this.children();
        if (this.calledReaddir()) {
            return children.slice(0, children.provisional);
        }
        // else read the directory, fill up children
        // de-provisionalize any provisional children.
        const fullpath = this.fullpath();
        if (this.#asyncReaddirInFlight) {
            await this.#asyncReaddirInFlight;
        }
        else {
            /* c8 ignore start */
            let resolve = () => { };
            /* c8 ignore stop */
            this.#asyncReaddirInFlight = new Promise(res => (resolve = res));
            try {
                for (const e of await this.#fs.promises.readdir(fullpath, {
                    withFileTypes: true,
                })) {
                    this.#readdirAddChild(e, children);
                }
                this.#readdirSuccess(children);
            }
            catch (er) {
                this.#readdirFail(er.code);
                children.provisional = 0;
            }
            this.#asyncReaddirInFlight = undefined;
            resolve();
        }
        return children.slice(0, children.provisional);
    }
    /**
     * synchronous {@link PathBase.readdir}
     */
    readdirSync() {
        if (!this.canReaddir()) {
            return [];
        }
        const children = this.children();
        if (this.calledReaddir()) {
            return children.slice(0, children.provisional);
        }
        // else read the directory, fill up children
        // de-provisionalize any provisional children.
        const fullpath = this.fullpath();
        try {
            for (const e of this.#fs.readdirSync(fullpath, {
                withFileTypes: true,
            })) {
                this.#readdirAddChild(e, children);
            }
            this.#readdirSuccess(children);
        }
        catch (er) {
            this.#readdirFail(er.code);
            children.provisional = 0;
        }
        return children.slice(0, children.provisional);
    }
    canReaddir() {
        if (this.#type & ENOCHILD)
            return false;
        const ifmt = IFMT & this.#type;
        // we always set ENOTDIR when setting IFMT, so should be impossible
        /* c8 ignore start */
        if (!(ifmt === UNKNOWN || ifmt === IFDIR || ifmt === IFLNK)) {
            return false;
        }
        /* c8 ignore stop */
        return true;
    }
    shouldWalk(dirs, walkFilter) {
        return ((this.#type & IFDIR) === IFDIR &&
            !(this.#type & ENOCHILD) &&
            !dirs.has(this) &&
            (!walkFilter || walkFilter(this)));
    }
    /**
     * Return the Path object corresponding to path as resolved
     * by realpath(3).
     *
     * If the realpath call fails for any reason, `undefined` is returned.
     *
     * Result is cached, and thus may be outdated if the filesystem is mutated.
     * On success, returns a Path object.
     */
    async realpath() {
        if (this.#realpath)
            return this.#realpath;
        if ((ENOREALPATH | ENOREADLINK | ENOENT) & this.#type)
            return undefined;
        try {
            const rp = await this.#fs.promises.realpath(this.fullpath());
            return (this.#realpath = this.resolve(rp));
        }
        catch (_) {
            this.#markENOREALPATH();
        }
    }
    /**
     * Synchronous {@link realpath}
     */
    realpathSync() {
        if (this.#realpath)
            return this.#realpath;
        if ((ENOREALPATH | ENOREADLINK | ENOENT) & this.#type)
            return undefined;
        try {
            const rp = this.#fs.realpathSync(this.fullpath());
            return (this.#realpath = this.resolve(rp));
        }
        catch (_) {
            this.#markENOREALPATH();
        }
    }
    /**
     * Internal method to mark this Path object as the scurry cwd,
     * called by {@link PathScurry#chdir}
     *
     * @internal
     */
    [setAsCwd](oldCwd) {
        if (oldCwd === this)
            return;
        oldCwd.isCWD = false;
        this.isCWD = true;
        const changed = new Set([]);
        let rp = [];
        let p = this;
        while (p && p.parent) {
            changed.add(p);
            p.#relative = rp.join(this.sep);
            p.#relativePosix = rp.join('/');
            p = p.parent;
            rp.push('..');
        }
        // now un-memoize parents of old cwd
        p = oldCwd;
        while (p && p.parent && !changed.has(p)) {
            p.#relative = undefined;
            p.#relativePosix = undefined;
            p = p.parent;
        }
    }
}
/**
 * Path class used on win32 systems
 *
 * Uses `'\\'` as the path separator for returned paths, either `'\\'` or `'/'`
 * as the path separator for parsing paths.
 */
class PathWin32 extends PathBase {
    /**
     * Separator for generating path strings.
     */
    sep = '\\';
    /**
     * Separator for parsing path strings.
     */
    splitSep = eitherSep;
    /**
     * Do not create new Path objects directly.  They should always be accessed
     * via the PathScurry class or other methods on the Path class.
     *
     * @internal
     */
    constructor(name, type = UNKNOWN, root, roots, nocase, children, opts) {
        super(name, type, root, roots, nocase, children, opts);
    }
    /**
     * @internal
     */
    newChild(name, type = UNKNOWN, opts = {}) {
        return new PathWin32(name, type, this.root, this.roots, this.nocase, this.childrenCache(), opts);
    }
    /**
     * @internal
     */
    getRootString(path) {
        return win32.parse(path).root;
    }
    /**
     * @internal
     */
    getRoot(rootPath) {
        rootPath = uncToDrive(rootPath.toUpperCase());
        if (rootPath === this.root.name) {
            return this.root;
        }
        // ok, not that one, check if it matches another we know about
        for (const [compare, root] of Object.entries(this.roots)) {
            if (this.sameRoot(rootPath, compare)) {
                return (this.roots[rootPath] = root);
            }
        }
        // otherwise, have to create a new one.
        return (this.roots[rootPath] = new PathScurryWin32(rootPath, this).root);
    }
    /**
     * @internal
     */
    sameRoot(rootPath, compare = this.root.name) {
        // windows can (rarely) have case-sensitive filesystem, but
        // UNC and drive letters are always case-insensitive, and canonically
        // represented uppercase.
        rootPath = rootPath
            .toUpperCase()
            .replace(/\//g, '\\')
            .replace(uncDriveRegexp, '$1\\');
        return rootPath === compare;
    }
}
/**
 * Path class used on all posix systems.
 *
 * Uses `'/'` as the path separator.
 */
class PathPosix extends PathBase {
    /**
     * separator for parsing path strings
     */
    splitSep = '/';
    /**
     * separator for generating path strings
     */
    sep = '/';
    /**
     * Do not create new Path objects directly.  They should always be accessed
     * via the PathScurry class or other methods on the Path class.
     *
     * @internal
     */
    constructor(name, type = UNKNOWN, root, roots, nocase, children, opts) {
        super(name, type, root, roots, nocase, children, opts);
    }
    /**
     * @internal
     */
    getRootString(path) {
        return path.startsWith('/') ? '/' : '';
    }
    /**
     * @internal
     */
    getRoot(_rootPath) {
        return this.root;
    }
    /**
     * @internal
     */
    newChild(name, type = UNKNOWN, opts = {}) {
        return new PathPosix(name, type, this.root, this.roots, this.nocase, this.childrenCache(), opts);
    }
}
/**
 * The base class for all PathScurry classes, providing the interface for path
 * resolution and filesystem operations.
 *
 * Typically, you should *not* instantiate this class directly, but rather one
 * of the platform-specific classes, or the exported {@link PathScurry} which
 * defaults to the current platform.
 */
class PathScurryBase {
    /**
     * The root Path entry for the current working directory of this Scurry
     */
    root;
    /**
     * The string path for the root of this Scurry's current working directory
     */
    rootPath;
    /**
     * A collection of all roots encountered, referenced by rootPath
     */
    roots;
    /**
     * The Path entry corresponding to this PathScurry's current working directory.
     */
    cwd;
    #resolveCache;
    #resolvePosixCache;
    #children;
    /**
     * Perform path comparisons case-insensitively.
     *
     * Defaults true on Darwin and Windows systems, false elsewhere.
     */
    nocase;
    #fs;
    /**
     * This class should not be instantiated directly.
     *
     * Use PathScurryWin32, PathScurryDarwin, PathScurryPosix, or PathScurry
     *
     * @internal
     */
    constructor(cwd = process.cwd(), pathImpl, sep, { nocase, childrenCacheSize = 16 * 1024, fs = defaultFS, } = {}) {
        this.#fs = fsFromOption(fs);
        if (cwd instanceof URL || cwd.startsWith('file://')) {
            cwd = fileURLToPath(cwd);
        }
        // resolve and split root, and then add to the store.
        // this is the only time we call path.resolve()
        const cwdPath = pathImpl.resolve(cwd);
        this.roots = Object.create(null);
        this.rootPath = this.parseRootPath(cwdPath);
        this.#resolveCache = new ResolveCache();
        this.#resolvePosixCache = new ResolveCache();
        this.#children = new ChildrenCache(childrenCacheSize);
        const split = cwdPath.substring(this.rootPath.length).split(sep);
        // resolve('/') leaves '', splits to [''], we don't want that.
        if (split.length === 1 && !split[0]) {
            split.pop();
        }
        /* c8 ignore start */
        if (nocase === undefined) {
            throw new TypeError('must provide nocase setting to PathScurryBase ctor');
        }
        /* c8 ignore stop */
        this.nocase = nocase;
        this.root = this.newRoot(this.#fs);
        this.roots[this.rootPath] = this.root;
        let prev = this.root;
        let len = split.length - 1;
        const joinSep = pathImpl.sep;
        let abs = this.rootPath;
        let sawFirst = false;
        for (const part of split) {
            const l = len--;
            prev = prev.child(part, {
                relative: new Array(l).fill('..').join(joinSep),
                relativePosix: new Array(l).fill('..').join('/'),
                fullpath: (abs += (sawFirst ? '' : joinSep) + part),
            });
            sawFirst = true;
        }
        this.cwd = prev;
    }
    /**
     * Get the depth of a provided path, string, or the cwd
     */
    depth(path = this.cwd) {
        if (typeof path === 'string') {
            path = this.cwd.resolve(path);
        }
        return path.depth();
    }
    /**
     * Return the cache of child entries.  Exposed so subclasses can create
     * child Path objects in a platform-specific way.
     *
     * @internal
     */
    childrenCache() {
        return this.#children;
    }
    /**
     * Resolve one or more path strings to a resolved string
     *
     * Same interface as require('path').resolve.
     *
     * Much faster than path.resolve() when called multiple times for the same
     * path, because the resolved Path objects are cached.  Much slower
     * otherwise.
     */
    resolve(...paths) {
        // first figure out the minimum number of paths we have to test
        // we always start at cwd, but any absolutes will bump the start
        let r = '';
        for (let i = paths.length - 1; i >= 0; i--) {
            const p = paths[i];
            if (!p || p === '.')
                continue;
            r = r ? `${p}/${r}` : p;
            if (this.isAbsolute(p)) {
                break;
            }
        }
        const cached = this.#resolveCache.get(r);
        if (cached !== undefined) {
            return cached;
        }
        const result = this.cwd.resolve(r).fullpath();
        this.#resolveCache.set(r, result);
        return result;
    }
    /**
     * Resolve one or more path strings to a resolved string, returning
     * the posix path.  Identical to .resolve() on posix systems, but on
     * windows will return a forward-slash separated UNC path.
     *
     * Same interface as require('path').resolve.
     *
     * Much faster than path.resolve() when called multiple times for the same
     * path, because the resolved Path objects are cached.  Much slower
     * otherwise.
     */
    resolvePosix(...paths) {
        // first figure out the minimum number of paths we have to test
        // we always start at cwd, but any absolutes will bump the start
        let r = '';
        for (let i = paths.length - 1; i >= 0; i--) {
            const p = paths[i];
            if (!p || p === '.')
                continue;
            r = r ? `${p}/${r}` : p;
            if (this.isAbsolute(p)) {
                break;
            }
        }
        const cached = this.#resolvePosixCache.get(r);
        if (cached !== undefined) {
            return cached;
        }
        const result = this.cwd.resolve(r).fullpathPosix();
        this.#resolvePosixCache.set(r, result);
        return result;
    }
    /**
     * find the relative path from the cwd to the supplied path string or entry
     */
    relative(entry = this.cwd) {
        if (typeof entry === 'string') {
            entry = this.cwd.resolve(entry);
        }
        return entry.relative();
    }
    /**
     * find the relative path from the cwd to the supplied path string or
     * entry, using / as the path delimiter, even on Windows.
     */
    relativePosix(entry = this.cwd) {
        if (typeof entry === 'string') {
            entry = this.cwd.resolve(entry);
        }
        return entry.relativePosix();
    }
    /**
     * Return the basename for the provided string or Path object
     */
    basename(entry = this.cwd) {
        if (typeof entry === 'string') {
            entry = this.cwd.resolve(entry);
        }
        return entry.name;
    }
    /**
     * Return the dirname for the provided string or Path object
     */
    dirname(entry = this.cwd) {
        if (typeof entry === 'string') {
            entry = this.cwd.resolve(entry);
        }
        return (entry.parent || entry).fullpath();
    }
    async readdir(entry = this.cwd, opts = {
        withFileTypes: true,
    }) {
        if (typeof entry === 'string') {
            entry = this.cwd.resolve(entry);
        }
        else if (!(entry instanceof PathBase)) {
            opts = entry;
            entry = this.cwd;
        }
        const { withFileTypes } = opts;
        if (!entry.canReaddir()) {
            return [];
        }
        else {
            const p = await entry.readdir();
            return withFileTypes ? p : p.map(e => e.name);
        }
    }
    readdirSync(entry = this.cwd, opts = {
        withFileTypes: true,
    }) {
        if (typeof entry === 'string') {
            entry = this.cwd.resolve(entry);
        }
        else if (!(entry instanceof PathBase)) {
            opts = entry;
            entry = this.cwd;
        }
        const { withFileTypes = true } = opts;
        if (!entry.canReaddir()) {
            return [];
        }
        else if (withFileTypes) {
            return entry.readdirSync();
        }
        else {
            return entry.readdirSync().map(e => e.name);
        }
    }
    /**
     * Call lstat() on the string or Path object, and update all known
     * information that can be determined.
     *
     * Note that unlike `fs.lstat()`, the returned value does not contain some
     * information, such as `mode`, `dev`, `nlink`, and `ino`.  If that
     * information is required, you will need to call `fs.lstat` yourself.
     *
     * If the Path refers to a nonexistent file, or if the lstat call fails for
     * any reason, `undefined` is returned.  Otherwise the updated Path object is
     * returned.
     *
     * Results are cached, and thus may be out of date if the filesystem is
     * mutated.
     */
    async lstat(entry = this.cwd) {
        if (typeof entry === 'string') {
            entry = this.cwd.resolve(entry);
        }
        return entry.lstat();
    }
    /**
     * synchronous {@link PathScurryBase.lstat}
     */
    lstatSync(entry = this.cwd) {
        if (typeof entry === 'string') {
            entry = this.cwd.resolve(entry);
        }
        return entry.lstatSync();
    }
    async readlink(entry = this.cwd, { withFileTypes } = {
        withFileTypes: false,
    }) {
        if (typeof entry === 'string') {
            entry = this.cwd.resolve(entry);
        }
        else if (!(entry instanceof PathBase)) {
            withFileTypes = entry.withFileTypes;
            entry = this.cwd;
        }
        const e = await entry.readlink();
        return withFileTypes ? e : e?.fullpath();
    }
    readlinkSync(entry = this.cwd, { withFileTypes } = {
        withFileTypes: false,
    }) {
        if (typeof entry === 'string') {
            entry = this.cwd.resolve(entry);
        }
        else if (!(entry instanceof PathBase)) {
            withFileTypes = entry.withFileTypes;
            entry = this.cwd;
        }
        const e = entry.readlinkSync();
        return withFileTypes ? e : e?.fullpath();
    }
    async realpath(entry = this.cwd, { withFileTypes } = {
        withFileTypes: false,
    }) {
        if (typeof entry === 'string') {
            entry = this.cwd.resolve(entry);
        }
        else if (!(entry instanceof PathBase)) {
            withFileTypes = entry.withFileTypes;
            entry = this.cwd;
        }
        const e = await entry.realpath();
        return withFileTypes ? e : e?.fullpath();
    }
    realpathSync(entry = this.cwd, { withFileTypes } = {
        withFileTypes: false,
    }) {
        if (typeof entry === 'string') {
            entry = this.cwd.resolve(entry);
        }
        else if (!(entry instanceof PathBase)) {
            withFileTypes = entry.withFileTypes;
            entry = this.cwd;
        }
        const e = entry.realpathSync();
        return withFileTypes ? e : e?.fullpath();
    }
    async walk(entry = this.cwd, opts = {}) {
        if (typeof entry === 'string') {
            entry = this.cwd.resolve(entry);
        }
        else if (!(entry instanceof PathBase)) {
            opts = entry;
            entry = this.cwd;
        }
        const { withFileTypes = true, follow = false, filter, walkFilter, } = opts;
        const results = [];
        if (!filter || filter(entry)) {
            results.push(withFileTypes ? entry : entry.fullpath());
        }
        const dirs = new Set();
        const walk = (dir, cb) => {
            dirs.add(dir);
            dir.readdirCB((er, entries) => {
                /* c8 ignore start */
                if (er) {
                    return cb(er);
                }
                /* c8 ignore stop */
                let len = entries.length;
                if (!len)
                    return cb();
                const next = () => {
                    if (--len === 0) {
                        cb();
                    }
                };
                for (const e of entries) {
                    if (!filter || filter(e)) {
                        results.push(withFileTypes ? e : e.fullpath());
                    }
                    if (follow && e.isSymbolicLink()) {
                        e.realpath()
                            .then(r => (r?.isUnknown() ? r.lstat() : r))
                            .then(r => r?.shouldWalk(dirs, walkFilter) ? walk(r, next) : next());
                    }
                    else {
                        if (e.shouldWalk(dirs, walkFilter)) {
                            walk(e, next);
                        }
                        else {
                            next();
                        }
                    }
                }
            }, true); // zalgooooooo
        };
        const start = entry;
        return new Promise((res, rej) => {
            walk(start, er => {
                /* c8 ignore start */
                if (er)
                    return rej(er);
                /* c8 ignore stop */
                res(results);
            });
        });
    }
    walkSync(entry = this.cwd, opts = {}) {
        if (typeof entry === 'string') {
            entry = this.cwd.resolve(entry);
        }
        else if (!(entry instanceof PathBase)) {
            opts = entry;
            entry = this.cwd;
        }
        const { withFileTypes = true, follow = false, filter, walkFilter, } = opts;
        const results = [];
        if (!filter || filter(entry)) {
            results.push(withFileTypes ? entry : entry.fullpath());
        }
        const dirs = new Set([entry]);
        for (const dir of dirs) {
            const entries = dir.readdirSync();
            for (const e of entries) {
                if (!filter || filter(e)) {
                    results.push(withFileTypes ? e : e.fullpath());
                }
                let r = e;
                if (e.isSymbolicLink()) {
                    if (!(follow && (r = e.realpathSync())))
                        continue;
                    if (r.isUnknown())
                        r.lstatSync();
                }
                if (r.shouldWalk(dirs, walkFilter)) {
                    dirs.add(r);
                }
            }
        }
        return results;
    }
    /**
     * Support for `for await`
     *
     * Alias for {@link PathScurryBase.iterate}
     *
     * Note: As of Node 19, this is very slow, compared to other methods of
     * walking.  Consider using {@link PathScurryBase.stream} if memory overhead
     * and backpressure are concerns, or {@link PathScurryBase.walk} if not.
     */
    [Symbol.asyncIterator]() {
        return this.iterate();
    }
    iterate(entry = this.cwd, options = {}) {
        // iterating async over the stream is significantly more performant,
        // especially in the warm-cache scenario, because it buffers up directory
        // entries in the background instead of waiting for a yield for each one.
        if (typeof entry === 'string') {
            entry = this.cwd.resolve(entry);
        }
        else if (!(entry instanceof PathBase)) {
            options = entry;
            entry = this.cwd;
        }
        return this.stream(entry, options)[Symbol.asyncIterator]();
    }
    /**
     * Iterating over a PathScurry performs a synchronous walk.
     *
     * Alias for {@link PathScurryBase.iterateSync}
     */
    [Symbol.iterator]() {
        return this.iterateSync();
    }
    *iterateSync(entry = this.cwd, opts = {}) {
        if (typeof entry === 'string') {
            entry = this.cwd.resolve(entry);
        }
        else if (!(entry instanceof PathBase)) {
            opts = entry;
            entry = this.cwd;
        }
        const { withFileTypes = true, follow = false, filter, walkFilter, } = opts;
        if (!filter || filter(entry)) {
            yield withFileTypes ? entry : entry.fullpath();
        }
        const dirs = new Set([entry]);
        for (const dir of dirs) {
            const entries = dir.readdirSync();
            for (const e of entries) {
                if (!filter || filter(e)) {
                    yield withFileTypes ? e : e.fullpath();
                }
                let r = e;
                if (e.isSymbolicLink()) {
                    if (!(follow && (r = e.realpathSync())))
                        continue;
                    if (r.isUnknown())
                        r.lstatSync();
                }
                if (r.shouldWalk(dirs, walkFilter)) {
                    dirs.add(r);
                }
            }
        }
    }
    stream(entry = this.cwd, opts = {}) {
        if (typeof entry === 'string') {
            entry = this.cwd.resolve(entry);
        }
        else if (!(entry instanceof PathBase)) {
            opts = entry;
            entry = this.cwd;
        }
        const { withFileTypes = true, follow = false, filter, walkFilter, } = opts;
        const results = new Minipass({ objectMode: true });
        if (!filter || filter(entry)) {
            results.write(withFileTypes ? entry : entry.fullpath());
        }
        const dirs = new Set();
        const queue = [entry];
        let processing = 0;
        const process = () => {
            let paused = false;
            while (!paused) {
                const dir = queue.shift();
                if (!dir) {
                    if (processing === 0)
                        results.end();
                    return;
                }
                processing++;
                dirs.add(dir);
                const onReaddir = (er, entries, didRealpaths = false) => {
                    /* c8 ignore start */
                    if (er)
                        return results.emit('error', er);
                    /* c8 ignore stop */
                    if (follow && !didRealpaths) {
                        const promises = [];
                        for (const e of entries) {
                            if (e.isSymbolicLink()) {
                                promises.push(e
                                    .realpath()
                                    .then((r) => r?.isUnknown() ? r.lstat() : r));
                            }
                        }
                        if (promises.length) {
                            Promise.all(promises).then(() => onReaddir(null, entries, true));
                            return;
                        }
                    }
                    for (const e of entries) {
                        if (e && (!filter || filter(e))) {
                            if (!results.write(withFileTypes ? e : e.fullpath())) {
                                paused = true;
                            }
                        }
                    }
                    processing--;
                    for (const e of entries) {
                        const r = e.realpathCached() || e;
                        if (r.shouldWalk(dirs, walkFilter)) {
                            queue.push(r);
                        }
                    }
                    if (paused && !results.flowing) {
                        results.once('drain', process);
                    }
                    else if (!sync) {
                        process();
                    }
                };
                // zalgo containment
                let sync = true;
                dir.readdirCB(onReaddir, true);
                sync = false;
            }
        };
        process();
        return results;
    }
    streamSync(entry = this.cwd, opts = {}) {
        if (typeof entry === 'string') {
            entry = this.cwd.resolve(entry);
        }
        else if (!(entry instanceof PathBase)) {
            opts = entry;
            entry = this.cwd;
        }
        const { withFileTypes = true, follow = false, filter, walkFilter, } = opts;
        const results = new Minipass({ objectMode: true });
        const dirs = new Set();
        if (!filter || filter(entry)) {
            results.write(withFileTypes ? entry : entry.fullpath());
        }
        const queue = [entry];
        let processing = 0;
        const process = () => {
            let paused = false;
            while (!paused) {
                const dir = queue.shift();
                if (!dir) {
                    if (processing === 0)
                        results.end();
                    return;
                }
                processing++;
                dirs.add(dir);
                const entries = dir.readdirSync();
                for (const e of entries) {
                    if (!filter || filter(e)) {
                        if (!results.write(withFileTypes ? e : e.fullpath())) {
                            paused = true;
                        }
                    }
                }
                processing--;
                for (const e of entries) {
                    let r = e;
                    if (e.isSymbolicLink()) {
                        if (!(follow && (r = e.realpathSync())))
                            continue;
                        if (r.isUnknown())
                            r.lstatSync();
                    }
                    if (r.shouldWalk(dirs, walkFilter)) {
                        queue.push(r);
                    }
                }
            }
            if (paused && !results.flowing)
                results.once('drain', process);
        };
        process();
        return results;
    }
    chdir(path = this.cwd) {
        const oldCwd = this.cwd;
        this.cwd = typeof path === 'string' ? this.cwd.resolve(path) : path;
        this.cwd[setAsCwd](oldCwd);
    }
}
/**
 * Windows implementation of {@link PathScurryBase}
 *
 * Defaults to case insensitve, uses `'\\'` to generate path strings.  Uses
 * {@link PathWin32} for Path objects.
 */
class PathScurryWin32 extends PathScurryBase {
    /**
     * separator for generating path strings
     */
    sep = '\\';
    constructor(cwd = process.cwd(), opts = {}) {
        const { nocase = true } = opts;
        super(cwd, win32, '\\', { ...opts, nocase });
        this.nocase = nocase;
        for (let p = this.cwd; p; p = p.parent) {
            p.nocase = this.nocase;
        }
    }
    /**
     * @internal
     */
    parseRootPath(dir) {
        // if the path starts with a single separator, it's not a UNC, and we'll
        // just get separator as the root, and driveFromUNC will return \
        // In that case, mount \ on the root from the cwd.
        return win32.parse(dir).root.toUpperCase();
    }
    /**
     * @internal
     */
    newRoot(fs) {
        return new PathWin32(this.rootPath, IFDIR, undefined, this.roots, this.nocase, this.childrenCache(), { fs });
    }
    /**
     * Return true if the provided path string is an absolute path
     */
    isAbsolute(p) {
        return (p.startsWith('/') || p.startsWith('\\') || /^[a-z]:(\/|\\)/i.test(p));
    }
}
/**
 * {@link PathScurryBase} implementation for all posix systems other than Darwin.
 *
 * Defaults to case-sensitive matching, uses `'/'` to generate path strings.
 *
 * Uses {@link PathPosix} for Path objects.
 */
class PathScurryPosix extends PathScurryBase {
    /**
     * separator for generating path strings
     */
    sep = '/';
    constructor(cwd = process.cwd(), opts = {}) {
        const { nocase = false } = opts;
        super(cwd, posix$1, '/', { ...opts, nocase });
        this.nocase = nocase;
    }
    /**
     * @internal
     */
    parseRootPath(_dir) {
        return '/';
    }
    /**
     * @internal
     */
    newRoot(fs) {
        return new PathPosix(this.rootPath, IFDIR, undefined, this.roots, this.nocase, this.childrenCache(), { fs });
    }
    /**
     * Return true if the provided path string is an absolute path
     */
    isAbsolute(p) {
        return p.startsWith('/');
    }
}
/**
 * {@link PathScurryBase} implementation for Darwin (macOS) systems.
 *
 * Defaults to case-insensitive matching, uses `'/'` for generating path
 * strings.
 *
 * Uses {@link PathPosix} for Path objects.
 */
class PathScurryDarwin extends PathScurryPosix {
    constructor(cwd = process.cwd(), opts = {}) {
        const { nocase = true } = opts;
        super(cwd, { ...opts, nocase });
    }
}
/**
 * Default {@link PathBase} implementation for the current platform.
 *
 * {@link PathWin32} on Windows systems, {@link PathPosix} on all others.
 */
process.platform === 'win32' ? PathWin32 : PathPosix;
/**
 * Default {@link PathScurryBase} implementation for the current platform.
 *
 * {@link PathScurryWin32} on Windows systems, {@link PathScurryDarwin} on
 * Darwin (macOS) systems, {@link PathScurryPosix} on all others.
 */
const PathScurry = process.platform === 'win32' ? PathScurryWin32
    : process.platform === 'darwin' ? PathScurryDarwin
        : PathScurryPosix;

// this is just a very light wrapper around 2 arrays with an offset index
const isPatternList = (pl) => pl.length >= 1;
const isGlobList = (gl) => gl.length >= 1;
/**
 * An immutable-ish view on an array of glob parts and their parsed
 * results
 */
class Pattern {
    #patternList;
    #globList;
    #index;
    length;
    #platform;
    #rest;
    #globString;
    #isDrive;
    #isUNC;
    #isAbsolute;
    #followGlobstar = true;
    constructor(patternList, globList, index, platform) {
        if (!isPatternList(patternList)) {
            throw new TypeError('empty pattern list');
        }
        if (!isGlobList(globList)) {
            throw new TypeError('empty glob list');
        }
        if (globList.length !== patternList.length) {
            throw new TypeError('mismatched pattern list and glob list lengths');
        }
        this.length = patternList.length;
        if (index < 0 || index >= this.length) {
            throw new TypeError('index out of range');
        }
        this.#patternList = patternList;
        this.#globList = globList;
        this.#index = index;
        this.#platform = platform;
        // normalize root entries of absolute patterns on initial creation.
        if (this.#index === 0) {
            // c: => ['c:/']
            // C:/ => ['C:/']
            // C:/x => ['C:/', 'x']
            // //host/share => ['//host/share/']
            // //host/share/ => ['//host/share/']
            // //host/share/x => ['//host/share/', 'x']
            // /etc => ['/', 'etc']
            // / => ['/']
            if (this.isUNC()) {
                // '' / '' / 'host' / 'share'
                const [p0, p1, p2, p3, ...prest] = this.#patternList;
                const [g0, g1, g2, g3, ...grest] = this.#globList;
                if (prest[0] === '') {
                    // ends in /
                    prest.shift();
                    grest.shift();
                }
                const p = [p0, p1, p2, p3, ''].join('/');
                const g = [g0, g1, g2, g3, ''].join('/');
                this.#patternList = [p, ...prest];
                this.#globList = [g, ...grest];
                this.length = this.#patternList.length;
            }
            else if (this.isDrive() || this.isAbsolute()) {
                const [p1, ...prest] = this.#patternList;
                const [g1, ...grest] = this.#globList;
                if (prest[0] === '') {
                    // ends in /
                    prest.shift();
                    grest.shift();
                }
                const p = p1 + '/';
                const g = g1 + '/';
                this.#patternList = [p, ...prest];
                this.#globList = [g, ...grest];
                this.length = this.#patternList.length;
            }
        }
    }
    /**
     * The first entry in the parsed list of patterns
     */
    pattern() {
        return this.#patternList[this.#index];
    }
    /**
     * true of if pattern() returns a string
     */
    isString() {
        return typeof this.#patternList[this.#index] === 'string';
    }
    /**
     * true of if pattern() returns GLOBSTAR
     */
    isGlobstar() {
        return this.#patternList[this.#index] === GLOBSTAR;
    }
    /**
     * true if pattern() returns a regexp
     */
    isRegExp() {
        return this.#patternList[this.#index] instanceof RegExp;
    }
    /**
     * The /-joined set of glob parts that make up this pattern
     */
    globString() {
        return (this.#globString =
            this.#globString ||
                (this.#index === 0 ?
                    this.isAbsolute() ?
                        this.#globList[0] + this.#globList.slice(1).join('/')
                        : this.#globList.join('/')
                    : this.#globList.slice(this.#index).join('/')));
    }
    /**
     * true if there are more pattern parts after this one
     */
    hasMore() {
        return this.length > this.#index + 1;
    }
    /**
     * The rest of the pattern after this part, or null if this is the end
     */
    rest() {
        if (this.#rest !== undefined)
            return this.#rest;
        if (!this.hasMore())
            return (this.#rest = null);
        this.#rest = new Pattern(this.#patternList, this.#globList, this.#index + 1, this.#platform);
        this.#rest.#isAbsolute = this.#isAbsolute;
        this.#rest.#isUNC = this.#isUNC;
        this.#rest.#isDrive = this.#isDrive;
        return this.#rest;
    }
    /**
     * true if the pattern represents a //unc/path/ on windows
     */
    isUNC() {
        const pl = this.#patternList;
        return this.#isUNC !== undefined ?
            this.#isUNC
            : (this.#isUNC =
                this.#platform === 'win32' &&
                    this.#index === 0 &&
                    pl[0] === '' &&
                    pl[1] === '' &&
                    typeof pl[2] === 'string' &&
                    !!pl[2] &&
                    typeof pl[3] === 'string' &&
                    !!pl[3]);
    }
    // pattern like C:/...
    // split = ['C:', ...]
    // XXX: would be nice to handle patterns like `c:*` to test the cwd
    // in c: for *, but I don't know of a way to even figure out what that
    // cwd is without actually chdir'ing into it?
    /**
     * True if the pattern starts with a drive letter on Windows
     */
    isDrive() {
        const pl = this.#patternList;
        return this.#isDrive !== undefined ?
            this.#isDrive
            : (this.#isDrive =
                this.#platform === 'win32' &&
                    this.#index === 0 &&
                    this.length > 1 &&
                    typeof pl[0] === 'string' &&
                    /^[a-z]:$/i.test(pl[0]));
    }
    // pattern = '/' or '/...' or '/x/...'
    // split = ['', ''] or ['', ...] or ['', 'x', ...]
    // Drive and UNC both considered absolute on windows
    /**
     * True if the pattern is rooted on an absolute path
     */
    isAbsolute() {
        const pl = this.#patternList;
        return this.#isAbsolute !== undefined ?
            this.#isAbsolute
            : (this.#isAbsolute =
                (pl[0] === '' && pl.length > 1) ||
                    this.isDrive() ||
                    this.isUNC());
    }
    /**
     * consume the root of the pattern, and return it
     */
    root() {
        const p = this.#patternList[0];
        return (typeof p === 'string' && this.isAbsolute() && this.#index === 0) ?
            p
            : '';
    }
    /**
     * Check to see if the current globstar pattern is allowed to follow
     * a symbolic link.
     */
    checkFollowGlobstar() {
        return !(this.#index === 0 ||
            !this.isGlobstar() ||
            !this.#followGlobstar);
    }
    /**
     * Mark that the current globstar pattern is following a symbolic link
     */
    markFollowGlobstar() {
        if (this.#index === 0 || !this.isGlobstar() || !this.#followGlobstar)
            return false;
        this.#followGlobstar = false;
        return true;
    }
}

// give it a pattern, and it'll be able to tell you if
// a given path should be ignored.
// Ignoring a path ignores its children if the pattern ends in /**
// Ignores are always parsed in dot:true mode
const defaultPlatform$1 = (typeof process === 'object' &&
    process &&
    typeof process.platform === 'string') ?
    process.platform
    : 'linux';
/**
 * Class used to process ignored patterns
 */
class Ignore {
    relative;
    relativeChildren;
    absolute;
    absoluteChildren;
    platform;
    mmopts;
    constructor(ignored, { nobrace, nocase, noext, noglobstar, platform = defaultPlatform$1, }) {
        this.relative = [];
        this.absolute = [];
        this.relativeChildren = [];
        this.absoluteChildren = [];
        this.platform = platform;
        this.mmopts = {
            dot: true,
            nobrace,
            nocase,
            noext,
            noglobstar,
            optimizationLevel: 2,
            platform,
            nocomment: true,
            nonegate: true,
        };
        for (const ign of ignored)
            this.add(ign);
    }
    add(ign) {
        // this is a little weird, but it gives us a clean set of optimized
        // minimatch matchers, without getting tripped up if one of them
        // ends in /** inside a brace section, and it's only inefficient at
        // the start of the walk, not along it.
        // It'd be nice if the Pattern class just had a .test() method, but
        // handling globstars is a bit of a pita, and that code already lives
        // in minimatch anyway.
        // Another way would be if maybe Minimatch could take its set/globParts
        // as an option, and then we could at least just use Pattern to test
        // for absolute-ness.
        // Yet another way, Minimatch could take an array of glob strings, and
        // a cwd option, and do the right thing.
        const mm = new Minimatch(ign, this.mmopts);
        for (let i = 0; i < mm.set.length; i++) {
            const parsed = mm.set[i];
            const globParts = mm.globParts[i];
            /* c8 ignore start */
            if (!parsed || !globParts) {
                throw new Error('invalid pattern object');
            }
            // strip off leading ./ portions
            // https://github.com/isaacs/node-glob/issues/570
            while (parsed[0] === '.' && globParts[0] === '.') {
                parsed.shift();
                globParts.shift();
            }
            /* c8 ignore stop */
            const p = new Pattern(parsed, globParts, 0, this.platform);
            const m = new Minimatch(p.globString(), this.mmopts);
            const children = globParts[globParts.length - 1] === '**';
            const absolute = p.isAbsolute();
            if (absolute)
                this.absolute.push(m);
            else
                this.relative.push(m);
            if (children) {
                if (absolute)
                    this.absoluteChildren.push(m);
                else
                    this.relativeChildren.push(m);
            }
        }
    }
    ignored(p) {
        const fullpath = p.fullpath();
        const fullpaths = `${fullpath}/`;
        const relative = p.relative() || '.';
        const relatives = `${relative}/`;
        for (const m of this.relative) {
            if (m.match(relative) || m.match(relatives))
                return true;
        }
        for (const m of this.absolute) {
            if (m.match(fullpath) || m.match(fullpaths))
                return true;
        }
        return false;
    }
    childrenIgnored(p) {
        const fullpath = p.fullpath() + '/';
        const relative = (p.relative() || '.') + '/';
        for (const m of this.relativeChildren) {
            if (m.match(relative))
                return true;
        }
        for (const m of this.absoluteChildren) {
            if (m.match(fullpath))
                return true;
        }
        return false;
    }
}

// synchronous utility for filtering entries and calculating subwalks
/**
 * A cache of which patterns have been processed for a given Path
 */
class HasWalkedCache {
    store;
    constructor(store = new Map()) {
        this.store = store;
    }
    copy() {
        return new HasWalkedCache(new Map(this.store));
    }
    hasWalked(target, pattern) {
        return this.store.get(target.fullpath())?.has(pattern.globString());
    }
    storeWalked(target, pattern) {
        const fullpath = target.fullpath();
        const cached = this.store.get(fullpath);
        if (cached)
            cached.add(pattern.globString());
        else
            this.store.set(fullpath, new Set([pattern.globString()]));
    }
}
/**
 * A record of which paths have been matched in a given walk step,
 * and whether they only are considered a match if they are a directory,
 * and whether their absolute or relative path should be returned.
 */
class MatchRecord {
    store = new Map();
    add(target, absolute, ifDir) {
        const n = (absolute ? 2 : 0) | (ifDir ? 1 : 0);
        const current = this.store.get(target);
        this.store.set(target, current === undefined ? n : n & current);
    }
    // match, absolute, ifdir
    entries() {
        return [...this.store.entries()].map(([path, n]) => [
            path,
            !!(n & 2),
            !!(n & 1),
        ]);
    }
}
/**
 * A collection of patterns that must be processed in a subsequent step
 * for a given path.
 */
class SubWalks {
    store = new Map();
    add(target, pattern) {
        if (!target.canReaddir()) {
            return;
        }
        const subs = this.store.get(target);
        if (subs) {
            if (!subs.find(p => p.globString() === pattern.globString())) {
                subs.push(pattern);
            }
        }
        else
            this.store.set(target, [pattern]);
    }
    get(target) {
        const subs = this.store.get(target);
        /* c8 ignore start */
        if (!subs) {
            throw new Error('attempting to walk unknown path');
        }
        /* c8 ignore stop */
        return subs;
    }
    entries() {
        return this.keys().map(k => [k, this.store.get(k)]);
    }
    keys() {
        return [...this.store.keys()].filter(t => t.canReaddir());
    }
}
/**
 * The class that processes patterns for a given path.
 *
 * Handles child entry filtering, and determining whether a path's
 * directory contents must be read.
 */
class Processor {
    hasWalkedCache;
    matches = new MatchRecord();
    subwalks = new SubWalks();
    patterns;
    follow;
    dot;
    opts;
    constructor(opts, hasWalkedCache) {
        this.opts = opts;
        this.follow = !!opts.follow;
        this.dot = !!opts.dot;
        this.hasWalkedCache =
            hasWalkedCache ? hasWalkedCache.copy() : new HasWalkedCache();
    }
    processPatterns(target, patterns) {
        this.patterns = patterns;
        const processingSet = patterns.map(p => [target, p]);
        // map of paths to the magic-starting subwalks they need to walk
        // first item in patterns is the filter
        for (let [t, pattern] of processingSet) {
            this.hasWalkedCache.storeWalked(t, pattern);
            const root = pattern.root();
            const absolute = pattern.isAbsolute() && this.opts.absolute !== false;
            // start absolute patterns at root
            if (root) {
                t = t.resolve(root === '/' && this.opts.root !== undefined ?
                    this.opts.root
                    : root);
                const rest = pattern.rest();
                if (!rest) {
                    this.matches.add(t, true, false);
                    continue;
                }
                else {
                    pattern = rest;
                }
            }
            if (t.isENOENT())
                continue;
            let p;
            let rest;
            let changed = false;
            while (typeof (p = pattern.pattern()) === 'string' &&
                (rest = pattern.rest())) {
                const c = t.resolve(p);
                t = c;
                pattern = rest;
                changed = true;
            }
            p = pattern.pattern();
            rest = pattern.rest();
            if (changed) {
                if (this.hasWalkedCache.hasWalked(t, pattern))
                    continue;
                this.hasWalkedCache.storeWalked(t, pattern);
            }
            // now we have either a final string for a known entry,
            // more strings for an unknown entry,
            // or a pattern starting with magic, mounted on t.
            if (typeof p === 'string') {
                // must not be final entry, otherwise we would have
                // concatenated it earlier.
                const ifDir = p === '..' || p === '' || p === '.';
                this.matches.add(t.resolve(p), absolute, ifDir);
                continue;
            }
            else if (p === GLOBSTAR) {
                // if no rest, match and subwalk pattern
                // if rest, process rest and subwalk pattern
                // if it's a symlink, but we didn't get here by way of a
                // globstar match (meaning it's the first time THIS globstar
                // has traversed a symlink), then we follow it. Otherwise, stop.
                if (!t.isSymbolicLink() ||
                    this.follow ||
                    pattern.checkFollowGlobstar()) {
                    this.subwalks.add(t, pattern);
                }
                const rp = rest?.pattern();
                const rrest = rest?.rest();
                if (!rest || ((rp === '' || rp === '.') && !rrest)) {
                    // only HAS to be a dir if it ends in **/ or **/.
                    // but ending in ** will match files as well.
                    this.matches.add(t, absolute, rp === '' || rp === '.');
                }
                else {
                    if (rp === '..') {
                        // this would mean you're matching **/.. at the fs root,
                        // and no thanks, I'm not gonna test that specific case.
                        /* c8 ignore start */
                        const tp = t.parent || t;
                        /* c8 ignore stop */
                        if (!rrest)
                            this.matches.add(tp, absolute, true);
                        else if (!this.hasWalkedCache.hasWalked(tp, rrest)) {
                            this.subwalks.add(tp, rrest);
                        }
                    }
                }
            }
            else if (p instanceof RegExp) {
                this.subwalks.add(t, pattern);
            }
        }
        return this;
    }
    subwalkTargets() {
        return this.subwalks.keys();
    }
    child() {
        return new Processor(this.opts, this.hasWalkedCache);
    }
    // return a new Processor containing the subwalks for each
    // child entry, and a set of matches, and
    // a hasWalkedCache that's a copy of this one
    // then we're going to call
    filterEntries(parent, entries) {
        const patterns = this.subwalks.get(parent);
        // put matches and entry walks into the results processor
        const results = this.child();
        for (const e of entries) {
            for (const pattern of patterns) {
                const absolute = pattern.isAbsolute();
                const p = pattern.pattern();
                const rest = pattern.rest();
                if (p === GLOBSTAR) {
                    results.testGlobstar(e, pattern, rest, absolute);
                }
                else if (p instanceof RegExp) {
                    results.testRegExp(e, p, rest, absolute);
                }
                else {
                    results.testString(e, p, rest, absolute);
                }
            }
        }
        return results;
    }
    testGlobstar(e, pattern, rest, absolute) {
        if (this.dot || !e.name.startsWith('.')) {
            if (!pattern.hasMore()) {
                this.matches.add(e, absolute, false);
            }
            if (e.canReaddir()) {
                // if we're in follow mode or it's not a symlink, just keep
                // testing the same pattern. If there's more after the globstar,
                // then this symlink consumes the globstar. If not, then we can
                // follow at most ONE symlink along the way, so we mark it, which
                // also checks to ensure that it wasn't already marked.
                if (this.follow || !e.isSymbolicLink()) {
                    this.subwalks.add(e, pattern);
                }
                else if (e.isSymbolicLink()) {
                    if (rest && pattern.checkFollowGlobstar()) {
                        this.subwalks.add(e, rest);
                    }
                    else if (pattern.markFollowGlobstar()) {
                        this.subwalks.add(e, pattern);
                    }
                }
            }
        }
        // if the NEXT thing matches this entry, then also add
        // the rest.
        if (rest) {
            const rp = rest.pattern();
            if (typeof rp === 'string' &&
                // dots and empty were handled already
                rp !== '..' &&
                rp !== '' &&
                rp !== '.') {
                this.testString(e, rp, rest.rest(), absolute);
            }
            else if (rp === '..') {
                /* c8 ignore start */
                const ep = e.parent || e;
                /* c8 ignore stop */
                this.subwalks.add(ep, rest);
            }
            else if (rp instanceof RegExp) {
                this.testRegExp(e, rp, rest.rest(), absolute);
            }
        }
    }
    testRegExp(e, p, rest, absolute) {
        if (!p.test(e.name))
            return;
        if (!rest) {
            this.matches.add(e, absolute, false);
        }
        else {
            this.subwalks.add(e, rest);
        }
    }
    testString(e, p, rest, absolute) {
        // should never happen?
        if (!e.isNamed(p))
            return;
        if (!rest) {
            this.matches.add(e, absolute, false);
        }
        else {
            this.subwalks.add(e, rest);
        }
    }
}

/**
 * Single-use utility classes to provide functionality to the {@link Glob}
 * methods.
 *
 * @module
 */
const makeIgnore = (ignore, opts) => typeof ignore === 'string' ? new Ignore([ignore], opts)
    : Array.isArray(ignore) ? new Ignore(ignore, opts)
        : ignore;
/**
 * basic walking utilities that all the glob walker types use
 */
class GlobUtil {
    path;
    patterns;
    opts;
    seen = new Set();
    paused = false;
    aborted = false;
    #onResume = [];
    #ignore;
    #sep;
    signal;
    maxDepth;
    includeChildMatches;
    constructor(patterns, path, opts) {
        this.patterns = patterns;
        this.path = path;
        this.opts = opts;
        this.#sep = !opts.posix && opts.platform === 'win32' ? '\\' : '/';
        this.includeChildMatches = opts.includeChildMatches !== false;
        if (opts.ignore || !this.includeChildMatches) {
            this.#ignore = makeIgnore(opts.ignore ?? [], opts);
            if (!this.includeChildMatches &&
                typeof this.#ignore.add !== 'function') {
                const m = 'cannot ignore child matches, ignore lacks add() method.';
                throw new Error(m);
            }
        }
        // ignore, always set with maxDepth, but it's optional on the
        // GlobOptions type
        /* c8 ignore start */
        this.maxDepth = opts.maxDepth || Infinity;
        /* c8 ignore stop */
        if (opts.signal) {
            this.signal = opts.signal;
            this.signal.addEventListener('abort', () => {
                this.#onResume.length = 0;
            });
        }
    }
    #ignored(path) {
        return this.seen.has(path) || !!this.#ignore?.ignored?.(path);
    }
    #childrenIgnored(path) {
        return !!this.#ignore?.childrenIgnored?.(path);
    }
    // backpressure mechanism
    pause() {
        this.paused = true;
    }
    resume() {
        /* c8 ignore start */
        if (this.signal?.aborted)
            return;
        /* c8 ignore stop */
        this.paused = false;
        let fn = undefined;
        while (!this.paused && (fn = this.#onResume.shift())) {
            fn();
        }
    }
    onResume(fn) {
        if (this.signal?.aborted)
            return;
        /* c8 ignore start */
        if (!this.paused) {
            fn();
        }
        else {
            /* c8 ignore stop */
            this.#onResume.push(fn);
        }
    }
    // do the requisite realpath/stat checking, and return the path
    // to add or undefined to filter it out.
    async matchCheck(e, ifDir) {
        if (ifDir && this.opts.nodir)
            return undefined;
        let rpc;
        if (this.opts.realpath) {
            rpc = e.realpathCached() || (await e.realpath());
            if (!rpc)
                return undefined;
            e = rpc;
        }
        const needStat = e.isUnknown() || this.opts.stat;
        const s = needStat ? await e.lstat() : e;
        if (this.opts.follow && this.opts.nodir && s?.isSymbolicLink()) {
            const target = await s.realpath();
            /* c8 ignore start */
            if (target && (target.isUnknown() || this.opts.stat)) {
                await target.lstat();
            }
            /* c8 ignore stop */
        }
        return this.matchCheckTest(s, ifDir);
    }
    matchCheckTest(e, ifDir) {
        return (e &&
            (this.maxDepth === Infinity || e.depth() <= this.maxDepth) &&
            (!ifDir || e.canReaddir()) &&
            (!this.opts.nodir || !e.isDirectory()) &&
            (!this.opts.nodir ||
                !this.opts.follow ||
                !e.isSymbolicLink() ||
                !e.realpathCached()?.isDirectory()) &&
            !this.#ignored(e)) ?
            e
            : undefined;
    }
    matchCheckSync(e, ifDir) {
        if (ifDir && this.opts.nodir)
            return undefined;
        let rpc;
        if (this.opts.realpath) {
            rpc = e.realpathCached() || e.realpathSync();
            if (!rpc)
                return undefined;
            e = rpc;
        }
        const needStat = e.isUnknown() || this.opts.stat;
        const s = needStat ? e.lstatSync() : e;
        if (this.opts.follow && this.opts.nodir && s?.isSymbolicLink()) {
            const target = s.realpathSync();
            if (target && (target?.isUnknown() || this.opts.stat)) {
                target.lstatSync();
            }
        }
        return this.matchCheckTest(s, ifDir);
    }
    matchFinish(e, absolute) {
        if (this.#ignored(e))
            return;
        // we know we have an ignore if this is false, but TS doesn't
        if (!this.includeChildMatches && this.#ignore?.add) {
            const ign = `${e.relativePosix()}/**`;
            this.#ignore.add(ign);
        }
        const abs = this.opts.absolute === undefined ? absolute : this.opts.absolute;
        this.seen.add(e);
        const mark = this.opts.mark && e.isDirectory() ? this.#sep : '';
        // ok, we have what we need!
        if (this.opts.withFileTypes) {
            this.matchEmit(e);
        }
        else if (abs) {
            const abs = this.opts.posix ? e.fullpathPosix() : e.fullpath();
            this.matchEmit(abs + mark);
        }
        else {
            const rel = this.opts.posix ? e.relativePosix() : e.relative();
            const pre = this.opts.dotRelative && !rel.startsWith('..' + this.#sep) ?
                '.' + this.#sep
                : '';
            this.matchEmit(!rel ? '.' + mark : pre + rel + mark);
        }
    }
    async match(e, absolute, ifDir) {
        const p = await this.matchCheck(e, ifDir);
        if (p)
            this.matchFinish(p, absolute);
    }
    matchSync(e, absolute, ifDir) {
        const p = this.matchCheckSync(e, ifDir);
        if (p)
            this.matchFinish(p, absolute);
    }
    walkCB(target, patterns, cb) {
        /* c8 ignore start */
        if (this.signal?.aborted)
            cb();
        /* c8 ignore stop */
        this.walkCB2(target, patterns, new Processor(this.opts), cb);
    }
    walkCB2(target, patterns, processor, cb) {
        if (this.#childrenIgnored(target))
            return cb();
        if (this.signal?.aborted)
            cb();
        if (this.paused) {
            this.onResume(() => this.walkCB2(target, patterns, processor, cb));
            return;
        }
        processor.processPatterns(target, patterns);
        // done processing.  all of the above is sync, can be abstracted out.
        // subwalks is a map of paths to the entry filters they need
        // matches is a map of paths to [absolute, ifDir] tuples.
        let tasks = 1;
        const next = () => {
            if (--tasks === 0)
                cb();
        };
        for (const [m, absolute, ifDir] of processor.matches.entries()) {
            if (this.#ignored(m))
                continue;
            tasks++;
            this.match(m, absolute, ifDir).then(() => next());
        }
        for (const t of processor.subwalkTargets()) {
            if (this.maxDepth !== Infinity && t.depth() >= this.maxDepth) {
                continue;
            }
            tasks++;
            const childrenCached = t.readdirCached();
            if (t.calledReaddir())
                this.walkCB3(t, childrenCached, processor, next);
            else {
                t.readdirCB((_, entries) => this.walkCB3(t, entries, processor, next), true);
            }
        }
        next();
    }
    walkCB3(target, entries, processor, cb) {
        processor = processor.filterEntries(target, entries);
        let tasks = 1;
        const next = () => {
            if (--tasks === 0)
                cb();
        };
        for (const [m, absolute, ifDir] of processor.matches.entries()) {
            if (this.#ignored(m))
                continue;
            tasks++;
            this.match(m, absolute, ifDir).then(() => next());
        }
        for (const [target, patterns] of processor.subwalks.entries()) {
            tasks++;
            this.walkCB2(target, patterns, processor.child(), next);
        }
        next();
    }
    walkCBSync(target, patterns, cb) {
        /* c8 ignore start */
        if (this.signal?.aborted)
            cb();
        /* c8 ignore stop */
        this.walkCB2Sync(target, patterns, new Processor(this.opts), cb);
    }
    walkCB2Sync(target, patterns, processor, cb) {
        if (this.#childrenIgnored(target))
            return cb();
        if (this.signal?.aborted)
            cb();
        if (this.paused) {
            this.onResume(() => this.walkCB2Sync(target, patterns, processor, cb));
            return;
        }
        processor.processPatterns(target, patterns);
        // done processing.  all of the above is sync, can be abstracted out.
        // subwalks is a map of paths to the entry filters they need
        // matches is a map of paths to [absolute, ifDir] tuples.
        let tasks = 1;
        const next = () => {
            if (--tasks === 0)
                cb();
        };
        for (const [m, absolute, ifDir] of processor.matches.entries()) {
            if (this.#ignored(m))
                continue;
            this.matchSync(m, absolute, ifDir);
        }
        for (const t of processor.subwalkTargets()) {
            if (this.maxDepth !== Infinity && t.depth() >= this.maxDepth) {
                continue;
            }
            tasks++;
            const children = t.readdirSync();
            this.walkCB3Sync(t, children, processor, next);
        }
        next();
    }
    walkCB3Sync(target, entries, processor, cb) {
        processor = processor.filterEntries(target, entries);
        let tasks = 1;
        const next = () => {
            if (--tasks === 0)
                cb();
        };
        for (const [m, absolute, ifDir] of processor.matches.entries()) {
            if (this.#ignored(m))
                continue;
            this.matchSync(m, absolute, ifDir);
        }
        for (const [target, patterns] of processor.subwalks.entries()) {
            tasks++;
            this.walkCB2Sync(target, patterns, processor.child(), next);
        }
        next();
    }
}
class GlobWalker extends GlobUtil {
    matches = new Set();
    constructor(patterns, path, opts) {
        super(patterns, path, opts);
    }
    matchEmit(e) {
        this.matches.add(e);
    }
    async walk() {
        if (this.signal?.aborted)
            throw this.signal.reason;
        if (this.path.isUnknown()) {
            await this.path.lstat();
        }
        await new Promise((res, rej) => {
            this.walkCB(this.path, this.patterns, () => {
                if (this.signal?.aborted) {
                    rej(this.signal.reason);
                }
                else {
                    res(this.matches);
                }
            });
        });
        return this.matches;
    }
    walkSync() {
        if (this.signal?.aborted)
            throw this.signal.reason;
        if (this.path.isUnknown()) {
            this.path.lstatSync();
        }
        // nothing for the callback to do, because this never pauses
        this.walkCBSync(this.path, this.patterns, () => {
            if (this.signal?.aborted)
                throw this.signal.reason;
        });
        return this.matches;
    }
}
class GlobStream extends GlobUtil {
    results;
    constructor(patterns, path, opts) {
        super(patterns, path, opts);
        this.results = new Minipass({
            signal: this.signal,
            objectMode: true,
        });
        this.results.on('drain', () => this.resume());
        this.results.on('resume', () => this.resume());
    }
    matchEmit(e) {
        this.results.write(e);
        if (!this.results.flowing)
            this.pause();
    }
    stream() {
        const target = this.path;
        if (target.isUnknown()) {
            target.lstat().then(() => {
                this.walkCB(target, this.patterns, () => this.results.end());
            });
        }
        else {
            this.walkCB(target, this.patterns, () => this.results.end());
        }
        return this.results;
    }
    streamSync() {
        if (this.path.isUnknown()) {
            this.path.lstatSync();
        }
        this.walkCBSync(this.path, this.patterns, () => this.results.end());
        return this.results;
    }
}

// if no process global, just call it linux.
// so we default to case-sensitive, / separators
const defaultPlatform = (typeof process === 'object' &&
    process &&
    typeof process.platform === 'string') ?
    process.platform
    : 'linux';
/**
 * An object that can perform glob pattern traversals.
 */
class Glob {
    absolute;
    cwd;
    root;
    dot;
    dotRelative;
    follow;
    ignore;
    magicalBraces;
    mark;
    matchBase;
    maxDepth;
    nobrace;
    nocase;
    nodir;
    noext;
    noglobstar;
    pattern;
    platform;
    realpath;
    scurry;
    stat;
    signal;
    windowsPathsNoEscape;
    withFileTypes;
    includeChildMatches;
    /**
     * The options provided to the constructor.
     */
    opts;
    /**
     * An array of parsed immutable {@link Pattern} objects.
     */
    patterns;
    /**
     * All options are stored as properties on the `Glob` object.
     *
     * See {@link GlobOptions} for full options descriptions.
     *
     * Note that a previous `Glob` object can be passed as the
     * `GlobOptions` to another `Glob` instantiation to re-use settings
     * and caches with a new pattern.
     *
     * Traversal functions can be called multiple times to run the walk
     * again.
     */
    constructor(pattern, opts) {
        /* c8 ignore start */
        if (!opts)
            throw new TypeError('glob options required');
        /* c8 ignore stop */
        this.withFileTypes = !!opts.withFileTypes;
        this.signal = opts.signal;
        this.follow = !!opts.follow;
        this.dot = !!opts.dot;
        this.dotRelative = !!opts.dotRelative;
        this.nodir = !!opts.nodir;
        this.mark = !!opts.mark;
        if (!opts.cwd) {
            this.cwd = '';
        }
        else if (opts.cwd instanceof URL || opts.cwd.startsWith('file://')) {
            opts.cwd = fileURLToPath(opts.cwd);
        }
        this.cwd = opts.cwd || '';
        this.root = opts.root;
        this.magicalBraces = !!opts.magicalBraces;
        this.nobrace = !!opts.nobrace;
        this.noext = !!opts.noext;
        this.realpath = !!opts.realpath;
        this.absolute = opts.absolute;
        this.includeChildMatches = opts.includeChildMatches !== false;
        this.noglobstar = !!opts.noglobstar;
        this.matchBase = !!opts.matchBase;
        this.maxDepth =
            typeof opts.maxDepth === 'number' ? opts.maxDepth : Infinity;
        this.stat = !!opts.stat;
        this.ignore = opts.ignore;
        if (this.withFileTypes && this.absolute !== undefined) {
            throw new Error('cannot set absolute and withFileTypes:true');
        }
        if (typeof pattern === 'string') {
            pattern = [pattern];
        }
        this.windowsPathsNoEscape =
            !!opts.windowsPathsNoEscape ||
                opts.allowWindowsEscape ===
                    false;
        if (this.windowsPathsNoEscape) {
            pattern = pattern.map(p => p.replace(/\\/g, '/'));
        }
        if (this.matchBase) {
            if (opts.noglobstar) {
                throw new TypeError('base matching requires globstar');
            }
            pattern = pattern.map(p => (p.includes('/') ? p : `./**/${p}`));
        }
        this.pattern = pattern;
        this.platform = opts.platform || defaultPlatform;
        this.opts = { ...opts, platform: this.platform };
        if (opts.scurry) {
            this.scurry = opts.scurry;
            if (opts.nocase !== undefined &&
                opts.nocase !== opts.scurry.nocase) {
                throw new Error('nocase option contradicts provided scurry option');
            }
        }
        else {
            const Scurry = opts.platform === 'win32' ? PathScurryWin32
                : opts.platform === 'darwin' ? PathScurryDarwin
                    : opts.platform ? PathScurryPosix
                        : PathScurry;
            this.scurry = new Scurry(this.cwd, {
                nocase: opts.nocase,
                fs: opts.fs,
            });
        }
        this.nocase = this.scurry.nocase;
        // If you do nocase:true on a case-sensitive file system, then
        // we need to use regexps instead of strings for non-magic
        // path portions, because statting `aBc` won't return results
        // for the file `AbC` for example.
        const nocaseMagicOnly = this.platform === 'darwin' || this.platform === 'win32';
        const mmo = {
            // default nocase based on platform
            ...opts,
            dot: this.dot,
            matchBase: this.matchBase,
            nobrace: this.nobrace,
            nocase: this.nocase,
            nocaseMagicOnly,
            nocomment: true,
            noext: this.noext,
            nonegate: true,
            optimizationLevel: 2,
            platform: this.platform,
            windowsPathsNoEscape: this.windowsPathsNoEscape,
            debug: !!this.opts.debug,
        };
        const mms = this.pattern.map(p => new Minimatch(p, mmo));
        const [matchSet, globParts] = mms.reduce((set, m) => {
            set[0].push(...m.set);
            set[1].push(...m.globParts);
            return set;
        }, [[], []]);
        this.patterns = matchSet.map((set, i) => {
            const g = globParts[i];
            /* c8 ignore start */
            if (!g)
                throw new Error('invalid pattern object');
            /* c8 ignore stop */
            return new Pattern(set, g, 0, this.platform);
        });
    }
    async walk() {
        // Walkers always return array of Path objects, so we just have to
        // coerce them into the right shape.  It will have already called
        // realpath() if the option was set to do so, so we know that's cached.
        // start out knowing the cwd, at least
        return [
            ...(await new GlobWalker(this.patterns, this.scurry.cwd, {
                ...this.opts,
                maxDepth: this.maxDepth !== Infinity ?
                    this.maxDepth + this.scurry.cwd.depth()
                    : Infinity,
                platform: this.platform,
                nocase: this.nocase,
                includeChildMatches: this.includeChildMatches,
            }).walk()),
        ];
    }
    walkSync() {
        return [
            ...new GlobWalker(this.patterns, this.scurry.cwd, {
                ...this.opts,
                maxDepth: this.maxDepth !== Infinity ?
                    this.maxDepth + this.scurry.cwd.depth()
                    : Infinity,
                platform: this.platform,
                nocase: this.nocase,
                includeChildMatches: this.includeChildMatches,
            }).walkSync(),
        ];
    }
    stream() {
        return new GlobStream(this.patterns, this.scurry.cwd, {
            ...this.opts,
            maxDepth: this.maxDepth !== Infinity ?
                this.maxDepth + this.scurry.cwd.depth()
                : Infinity,
            platform: this.platform,
            nocase: this.nocase,
            includeChildMatches: this.includeChildMatches,
        }).stream();
    }
    streamSync() {
        return new GlobStream(this.patterns, this.scurry.cwd, {
            ...this.opts,
            maxDepth: this.maxDepth !== Infinity ?
                this.maxDepth + this.scurry.cwd.depth()
                : Infinity,
            platform: this.platform,
            nocase: this.nocase,
            includeChildMatches: this.includeChildMatches,
        }).streamSync();
    }
    /**
     * Default sync iteration function. Returns a Generator that
     * iterates over the results.
     */
    iterateSync() {
        return this.streamSync()[Symbol.iterator]();
    }
    [Symbol.iterator]() {
        return this.iterateSync();
    }
    /**
     * Default async iteration function. Returns an AsyncGenerator that
     * iterates over the results.
     */
    iterate() {
        return this.stream()[Symbol.asyncIterator]();
    }
    [Symbol.asyncIterator]() {
        return this.iterate();
    }
}

/**
 * Return true if the patterns provided contain any magic glob characters,
 * given the options provided.
 *
 * Brace expansion is not considered "magic" unless the `magicalBraces` option
 * is set, as brace expansion just turns one string into an array of strings.
 * So a pattern like `'x{a,b}y'` would return `false`, because `'xay'` and
 * `'xby'` both do not contain any magic glob characters, and it's treated the
 * same as if you had called it on `['xay', 'xby']`. When `magicalBraces:true`
 * is in the options, brace expansion _is_ treated as a pattern having magic.
 */
const hasMagic = (pattern, options = {}) => {
    if (!Array.isArray(pattern)) {
        pattern = [pattern];
    }
    for (const p of pattern) {
        if (new Minimatch(p, options).hasMagic())
            return true;
    }
    return false;
};

function globStreamSync(pattern, options = {}) {
    return new Glob(pattern, options).streamSync();
}
function globStream(pattern, options = {}) {
    return new Glob(pattern, options).stream();
}
function globSync(pattern, options = {}) {
    return new Glob(pattern, options).walkSync();
}
async function glob_(pattern, options = {}) {
    return new Glob(pattern, options).walk();
}
function globIterateSync(pattern, options = {}) {
    return new Glob(pattern, options).iterateSync();
}
function globIterate(pattern, options = {}) {
    return new Glob(pattern, options).iterate();
}
// aliases: glob.sync.stream() glob.stream.sync() glob.sync() etc
const streamSync = globStreamSync;
const stream = Object.assign(globStream, { sync: globStreamSync });
const iterateSync = globIterateSync;
const iterate = Object.assign(globIterate, {
    sync: globIterateSync,
});
const sync$1 = Object.assign(globSync, {
    stream: globStreamSync,
    iterate: globIterateSync,
});
const glob$2 = Object.assign(glob_, {
    glob: glob_,
    globSync,
    sync: sync$1,
    globStream,
    stream,
    globStreamSync,
    streamSync,
    globIterate,
    iterate,
    globIterateSync,
    iterateSync,
    Glob,
    hasMagic,
    escape: escape$1,
    unescape,
});
glob$2.glob = glob$2;

const typeOrUndef = (val, t) => typeof val === 'undefined' || typeof val === t;
const isRimrafOptions = (o) => !!o &&
    typeof o === 'object' &&
    typeOrUndef(o.preserveRoot, 'boolean') &&
    typeOrUndef(o.tmp, 'string') &&
    typeOrUndef(o.maxRetries, 'number') &&
    typeOrUndef(o.retryDelay, 'number') &&
    typeOrUndef(o.backoff, 'number') &&
    typeOrUndef(o.maxBackoff, 'number') &&
    (typeOrUndef(o.glob, 'boolean') || (o.glob && typeof o.glob === 'object')) &&
    typeOrUndef(o.filter, 'function');
const assertRimrafOptions = (o) => {
    if (!isRimrafOptions(o)) {
        throw new Error('invalid rimraf options');
    }
};
const optArgT = (opt) => {
    assertRimrafOptions(opt);
    const { glob, ...options } = opt;
    if (!glob) {
        return options;
    }
    const globOpt = glob === true ?
        opt.signal ?
            { signal: opt.signal }
            : {}
        : opt.signal ?
            {
                signal: opt.signal,
                ...glob,
            }
            : glob;
    return {
        ...options,
        glob: {
            ...globOpt,
            // always get absolute paths from glob, to ensure
            // that we are referencing the correct thing.
            absolute: true,
            withFileTypes: false,
        },
    };
};
const optArg = (opt = {}) => optArgT(opt);
const optArgSync = (opt = {}) => optArgT(opt);

const pathArg = (path, opt = {}) => {
    const type = typeof path;
    if (type !== 'string') {
        const ctor = path && type === 'object' && path.constructor;
        const received = ctor && ctor.name ? `an instance of ${ctor.name}`
            : type === 'object' ? inspect(path)
                : `type ${type} ${path}`;
        const msg = 'The "path" argument must be of type string. ' + `Received ${received}`;
        throw Object.assign(new TypeError(msg), {
            path,
            code: 'ERR_INVALID_ARG_TYPE',
        });
    }
    if (/\0/.test(path)) {
        // simulate same failure that node raises
        const msg = 'path must be a string without null bytes';
        throw Object.assign(new TypeError(msg), {
            path,
            code: 'ERR_INVALID_ARG_VALUE',
        });
    }
    path = resolve$1(path);
    const { root } = parse$4(path);
    if (path === root && opt.preserveRoot !== false) {
        const msg = 'refusing to remove root directory without preserveRoot:false';
        throw Object.assign(new Error(msg), {
            path,
            code: 'ERR_PRESERVE_ROOT',
        });
    }
    if (process.platform === 'win32') {
        const badWinChars = /[*|"<>?:]/;
        const { root } = parse$4(path);
        if (badWinChars.test(path.substring(root.length))) {
            throw Object.assign(new Error('Illegal characters in path.'), {
                path,
                code: 'EINVAL',
            });
        }
    }
    return path;
};

const readdirSync = (path) => readdirSync$1(path, { withFileTypes: true });
const promises = {
    chmod: fsPromises.chmod,
    mkdir: fsPromises.mkdir,
    readdir: (path) => fsPromises.readdir(path, { withFileTypes: true }),
    rename: fsPromises.rename,
    rm: fsPromises.rm,
    rmdir: fsPromises.rmdir,
    stat: fsPromises.stat,
    lstat: fsPromises.lstat,
    unlink: fsPromises.unlink,
};

// returns an array of entries if readdir() works,
// or the error that readdir() raised if not.
const { readdir } = promises;
const readdirOrError = (path) => readdir(path).catch(er => er);
const readdirOrErrorSync = (path) => {
    try {
        return readdirSync(path);
    }
    catch (er) {
        return er;
    }
};

const isRecord = (o) => !!o && typeof o === 'object';
const hasString = (o, key) => key in o && typeof o[key] === 'string';
const isFsError = (o) => isRecord(o) && hasString(o, 'code') && hasString(o, 'path');
const errorCode = (er) => isRecord(er) && hasString(er, 'code') ? er.code : null;

const ignoreENOENT = async (p, rethrow) => p.catch(er => {
    if (errorCode(er) === 'ENOENT') {
        return;
    }
    throw rethrow ?? er;
});
const ignoreENOENTSync = (fn, rethrow) => {
    try {
        return fn();
    }
    catch (er) {
        if (errorCode(er) === 'ENOENT') {
            return;
        }
        throw rethrow ?? er;
    }
};

// the simple recursive removal, where unlink and rmdir are atomic
// Note that this approach does NOT work on Windows!
// We stat first and only unlink if the Dirent isn't a directory,
// because sunos will let root unlink a directory, and some
// SUPER weird breakage happens as a result.
const { lstat: lstat$2, rmdir: rmdir$2, unlink: unlink$2 } = promises;
const rimrafPosix = async (path, opt) => {
    opt?.signal?.throwIfAborted();
    return ((await ignoreENOENT(lstat$2(path).then(stat => rimrafPosixDir(path, opt, stat)))) ?? true);
};
const rimrafPosixSync = (path, opt) => {
    opt?.signal?.throwIfAborted();
    return (ignoreENOENTSync(() => rimrafPosixDirSync(path, opt, lstatSync(path))) ??
        true);
};
const rimrafPosixDir = async (path, opt, ent) => {
    opt?.signal?.throwIfAborted();
    const entries = ent.isDirectory() ? await readdirOrError(path) : null;
    if (!Array.isArray(entries)) {
        // this can only happen if lstat/readdir lied, or if the dir was
        // swapped out with a file at just the right moment.
        /* c8 ignore start */
        if (entries) {
            if (errorCode(entries) === 'ENOENT') {
                return true;
            }
            if (errorCode(entries) !== 'ENOTDIR') {
                throw entries;
            }
        }
        /* c8 ignore stop */
        if (opt.filter && !(await opt.filter(path, ent))) {
            return false;
        }
        await ignoreENOENT(unlink$2(path));
        return true;
    }
    const removedAll = (await Promise.all(entries.map(ent => rimrafPosixDir(resolve$1(path, ent.name), opt, ent)))).every(v => v === true);
    if (!removedAll) {
        return false;
    }
    // we don't ever ACTUALLY try to unlink /, because that can never work
    // but when preserveRoot is false, we could be operating on it.
    // No need to check if preserveRoot is not false.
    if (opt.preserveRoot === false && path === parse$4(path).root) {
        return false;
    }
    if (opt.filter && !(await opt.filter(path, ent))) {
        return false;
    }
    await ignoreENOENT(rmdir$2(path));
    return true;
};
const rimrafPosixDirSync = (path, opt, ent) => {
    opt?.signal?.throwIfAborted();
    const entries = ent.isDirectory() ? readdirOrErrorSync(path) : null;
    if (!Array.isArray(entries)) {
        // this can only happen if lstat/readdir lied, or if the dir was
        // swapped out with a file at just the right moment.
        /* c8 ignore start */
        if (entries) {
            if (errorCode(entries) === 'ENOENT') {
                return true;
            }
            if (errorCode(entries) !== 'ENOTDIR') {
                throw entries;
            }
        }
        /* c8 ignore stop */
        if (opt.filter && !opt.filter(path, ent)) {
            return false;
        }
        ignoreENOENTSync(() => unlinkSync(path));
        return true;
    }
    let removedAll = true;
    for (const ent of entries) {
        const p = resolve$1(path, ent.name);
        removedAll = rimrafPosixDirSync(p, opt, ent) && removedAll;
    }
    if (opt.preserveRoot === false && path === parse$4(path).root) {
        return false;
    }
    if (!removedAll) {
        return false;
    }
    if (opt.filter && !opt.filter(path, ent)) {
        return false;
    }
    ignoreENOENTSync(() => rmdirSync(path));
    return true;
};

const { chmod } = promises;
const fixEPERM = (fn) => async (path) => {
    try {
        return void (await ignoreENOENT(fn(path)));
    }
    catch (er) {
        if (errorCode(er) === 'EPERM') {
            if (!(await ignoreENOENT(chmod(path, 0o666).then(() => true), er))) {
                return;
            }
            return void (await fn(path));
        }
        throw er;
    }
};
const fixEPERMSync = (fn) => (path) => {
    try {
        return void ignoreENOENTSync(() => fn(path));
    }
    catch (er) {
        if (errorCode(er) === 'EPERM') {
            if (!ignoreENOENTSync(() => (chmodSync(path, 0o666), true), er)) {
                return;
            }
            return void fn(path);
        }
        throw er;
    }
};

// note: max backoff is the maximum that any *single* backoff will do
const MAXBACKOFF = 200;
const RATE = 1.2;
const MAXRETRIES = 10;
const codes = new Set(['EMFILE', 'ENFILE', 'EBUSY']);
const retryBusy = (fn) => {
    const method = async (path, opt, backoff = 1, total = 0) => {
        const mbo = opt.maxBackoff || MAXBACKOFF;
        const rate = opt.backoff || RATE;
        const max = opt.maxRetries || MAXRETRIES;
        let retries = 0;
        while (true) {
            try {
                return await fn(path);
            }
            catch (er) {
                if (isFsError(er) && er.path === path && codes.has(er.code)) {
                    backoff = Math.ceil(backoff * rate);
                    total = backoff + total;
                    if (total < mbo) {
                        await setTimeout$1(backoff);
                        return method(path, opt, backoff, total);
                    }
                    if (retries < max) {
                        retries++;
                        continue;
                    }
                }
                throw er;
            }
        }
    };
    return method;
};
// just retries, no async so no backoff
const retryBusySync = (fn) => {
    const method = (path, opt) => {
        const max = opt.maxRetries || MAXRETRIES;
        let retries = 0;
        while (true) {
            try {
                return fn(path);
            }
            catch (er) {
                if (isFsError(er) &&
                    er.path === path &&
                    codes.has(er.code) &&
                    retries < max) {
                    retries++;
                    continue;
                }
                throw er;
            }
        }
    };
    return method;
};

// The default temporary folder location for use in the windows algorithm.
// It's TEMPting to use dirname(path), since that's guaranteed to be on the
// same device.  However, this means that:
// rimraf(path).then(() => rimraf(dirname(path)))
// will often fail with EBUSY, because the parent dir contains
// marked-for-deletion directory entries (which do not show up in readdir).
// The approach here is to use os.tmpdir() if it's on the same drive letter,
// or resolve(path, '\\temp') if it exists, or the root of the drive if not.
// On Posix (not that you'd be likely to use the windows algorithm there),
// it uses os.tmpdir() always.
const { stat } = promises;
const isDirSync = (path) => {
    try {
        return statSync(path).isDirectory();
    }
    catch {
        return false;
    }
};
const isDir = (path) => stat(path).then(st => st.isDirectory(), () => false);
const win32DefaultTmp = async (path) => {
    const { root } = parse$4(path);
    const tmp = tmpdir();
    const { root: tmpRoot } = parse$4(tmp);
    if (root.toLowerCase() === tmpRoot.toLowerCase()) {
        return tmp;
    }
    const driveTmp = resolve$1(root, '/temp');
    if (await isDir(driveTmp)) {
        return driveTmp;
    }
    return root;
};
const win32DefaultTmpSync = (path) => {
    const { root } = parse$4(path);
    const tmp = tmpdir();
    const { root: tmpRoot } = parse$4(tmp);
    if (root.toLowerCase() === tmpRoot.toLowerCase()) {
        return tmp;
    }
    const driveTmp = resolve$1(root, '/temp');
    if (isDirSync(driveTmp)) {
        return driveTmp;
    }
    return root;
};
// eslint-disable-next-line @typescript-eslint/require-await
const posixDefaultTmp = async () => tmpdir();
const posixDefaultTmpSync = () => tmpdir();
const defaultTmp = process.platform === 'win32' ? win32DefaultTmp : posixDefaultTmp;
const defaultTmpSync = process.platform === 'win32' ? win32DefaultTmpSync : posixDefaultTmpSync;

// https://youtu.be/uhRWMGBjlO8?t=537
//
// 1. readdir
// 2. for each entry
//   a. if a non-empty directory, recurse
//   b. if an empty directory, move to random hidden file name in $TEMP
//   c. unlink/rmdir $TEMP
//
// This works around the fact that unlink/rmdir is non-atomic and takes
// a non-deterministic amount of time to complete.
//
// However, it is HELLA SLOW, like 2-10x slower than a naive recursive rm.
const { lstat: lstat$1, rename, unlink: unlink$1, rmdir: rmdir$1 } = promises;
// crypto.randomBytes is much slower, and Math.random() is enough here
const uniqueFilename = (path) => `.${basename(path)}.${Math.random()}`;
const unlinkFixEPERM = fixEPERM(unlink$1);
const unlinkFixEPERMSync = fixEPERMSync(unlinkSync);
const rimrafMoveRemove = async (path, opt) => {
    opt?.signal?.throwIfAborted();
    return ((await ignoreENOENT(lstat$1(path).then(stat => rimrafMoveRemoveDir(path, opt, stat)))) ?? true);
};
const rimrafMoveRemoveDir = async (path, opt, ent) => {
    opt?.signal?.throwIfAborted();
    if (!opt.tmp) {
        return rimrafMoveRemoveDir(path, { ...opt, tmp: await defaultTmp(path) }, ent);
    }
    if (path === opt.tmp && parse$4(path).root !== path) {
        throw new Error('cannot delete temp directory used for deletion');
    }
    const entries = ent.isDirectory() ? await readdirOrError(path) : null;
    if (!Array.isArray(entries)) {
        // this can only happen if lstat/readdir lied, or if the dir was
        // swapped out with a file at just the right moment.
        /* c8 ignore start */
        if (entries) {
            if (errorCode(entries) === 'ENOENT') {
                return true;
            }
            if (errorCode(entries) !== 'ENOTDIR') {
                throw entries;
            }
        }
        /* c8 ignore stop */
        if (opt.filter && !(await opt.filter(path, ent))) {
            return false;
        }
        await ignoreENOENT(tmpUnlink(path, opt.tmp, unlinkFixEPERM));
        return true;
    }
    const removedAll = (await Promise.all(entries.map(ent => rimrafMoveRemoveDir(resolve$1(path, ent.name), opt, ent)))).every(v => v === true);
    if (!removedAll) {
        return false;
    }
    // we don't ever ACTUALLY try to unlink /, because that can never work
    // but when preserveRoot is false, we could be operating on it.
    // No need to check if preserveRoot is not false.
    if (opt.preserveRoot === false && path === parse$4(path).root) {
        return false;
    }
    if (opt.filter && !(await opt.filter(path, ent))) {
        return false;
    }
    await ignoreENOENT(tmpUnlink(path, opt.tmp, rmdir$1));
    return true;
};
const tmpUnlink = async (path, tmp, rm) => {
    const tmpFile = resolve$1(tmp, uniqueFilename(path));
    await rename(path, tmpFile);
    return await rm(tmpFile);
};
const rimrafMoveRemoveSync = (path, opt) => {
    opt?.signal?.throwIfAborted();
    return (ignoreENOENTSync(() => rimrafMoveRemoveDirSync(path, opt, lstatSync(path))) ?? true);
};
const rimrafMoveRemoveDirSync = (path, opt, ent) => {
    opt?.signal?.throwIfAborted();
    if (!opt.tmp) {
        return rimrafMoveRemoveDirSync(path, { ...opt, tmp: defaultTmpSync(path) }, ent);
    }
    const tmp = opt.tmp;
    if (path === opt.tmp && parse$4(path).root !== path) {
        throw new Error('cannot delete temp directory used for deletion');
    }
    const entries = ent.isDirectory() ? readdirOrErrorSync(path) : null;
    if (!Array.isArray(entries)) {
        // this can only happen if lstat/readdir lied, or if the dir was
        // swapped out with a file at just the right moment.
        /* c8 ignore start */
        if (entries) {
            if (errorCode(entries) === 'ENOENT') {
                return true;
            }
            if (errorCode(entries) !== 'ENOTDIR') {
                throw entries;
            }
        }
        /* c8 ignore stop */
        if (opt.filter && !opt.filter(path, ent)) {
            return false;
        }
        ignoreENOENTSync(() => tmpUnlinkSync(path, tmp, unlinkFixEPERMSync));
        return true;
    }
    let removedAll = true;
    for (const ent of entries) {
        const p = resolve$1(path, ent.name);
        removedAll = rimrafMoveRemoveDirSync(p, opt, ent) && removedAll;
    }
    if (!removedAll) {
        return false;
    }
    if (opt.preserveRoot === false && path === parse$4(path).root) {
        return false;
    }
    if (opt.filter && !opt.filter(path, ent)) {
        return false;
    }
    ignoreENOENTSync(() => tmpUnlinkSync(path, tmp, rmdirSync));
    return true;
};
const tmpUnlinkSync = (path, tmp, rmSync) => {
    const tmpFile = resolve$1(tmp, uniqueFilename(path));
    renameSync(path, tmpFile);
    return rmSync(tmpFile);
};

// This is the same as rimrafPosix, with the following changes:
//
// 1. EBUSY, ENFILE, EMFILE trigger retries and/or exponential backoff
// 2. All non-directories are removed first and then all directories are
//    removed in a second sweep.
// 3. If we hit ENOTEMPTY in the second sweep, fall back to move-remove on
//    the that folder.
//
// Note: "move then remove" is 2-10 times slower, and just as unreliable.
const { unlink, rmdir, lstat } = promises;
const rimrafWindowsFile = retryBusy(fixEPERM(unlink));
const rimrafWindowsFileSync = retryBusySync(fixEPERMSync(unlinkSync));
const rimrafWindowsDirRetry = retryBusy(fixEPERM(rmdir));
const rimrafWindowsDirRetrySync = retryBusySync(fixEPERMSync(rmdirSync));
const rimrafWindowsDirMoveRemoveFallback = async (path, 
// already filtered, remove from options so we don't call unnecessarily
// eslint-disable-next-line @typescript-eslint/no-unused-vars
{ filter, ...opt }) => {
    /* c8 ignore next */
    opt?.signal?.throwIfAborted();
    try {
        await rimrafWindowsDirRetry(path, opt);
        return true;
    }
    catch (er) {
        if (errorCode(er) === 'ENOTEMPTY') {
            return rimrafMoveRemove(path, opt);
        }
        throw er;
    }
};
const rimrafWindowsDirMoveRemoveFallbackSync = (path, 
// already filtered, remove from options so we don't call unnecessarily
// eslint-disable-next-line @typescript-eslint/no-unused-vars
{ filter, ...opt }) => {
    opt?.signal?.throwIfAborted();
    try {
        rimrafWindowsDirRetrySync(path, opt);
        return true;
    }
    catch (er) {
        if (errorCode(er) === 'ENOTEMPTY') {
            return rimrafMoveRemoveSync(path, opt);
        }
        throw er;
    }
};
const START = Symbol('start');
const CHILD = Symbol('child');
const FINISH = Symbol('finish');
const rimrafWindows = async (path, opt) => {
    opt?.signal?.throwIfAborted();
    return ((await ignoreENOENT(lstat(path).then(stat => rimrafWindowsDir(path, opt, stat, START)))) ?? true);
};
const rimrafWindowsSync = (path, opt) => {
    opt?.signal?.throwIfAborted();
    return (ignoreENOENTSync(() => rimrafWindowsDirSync(path, opt, lstatSync(path), START)) ?? true);
};
const rimrafWindowsDir = async (path, opt, ent, state = START) => {
    opt?.signal?.throwIfAborted();
    const entries = ent.isDirectory() ? await readdirOrError(path) : null;
    if (!Array.isArray(entries)) {
        // this can only happen if lstat/readdir lied, or if the dir was
        // swapped out with a file at just the right moment.
        /* c8 ignore start */
        if (entries) {
            if (errorCode(entries) === 'ENOENT') {
                return true;
            }
            if (errorCode(entries) !== 'ENOTDIR') {
                throw entries;
            }
        }
        /* c8 ignore stop */
        if (opt.filter && !(await opt.filter(path, ent))) {
            return false;
        }
        // is a file
        await ignoreENOENT(rimrafWindowsFile(path, opt));
        return true;
    }
    const s = state === START ? CHILD : state;
    const removedAll = (await Promise.all(entries.map(ent => rimrafWindowsDir(resolve$1(path, ent.name), opt, ent, s)))).every(v => v === true);
    if (state === START) {
        return rimrafWindowsDir(path, opt, ent, FINISH);
    }
    else if (state === FINISH) {
        if (opt.preserveRoot === false && path === parse$4(path).root) {
            return false;
        }
        if (!removedAll) {
            return false;
        }
        if (opt.filter && !(await opt.filter(path, ent))) {
            return false;
        }
        await ignoreENOENT(rimrafWindowsDirMoveRemoveFallback(path, opt));
    }
    return true;
};
const rimrafWindowsDirSync = (path, opt, ent, state = START) => {
    const entries = ent.isDirectory() ? readdirOrErrorSync(path) : null;
    if (!Array.isArray(entries)) {
        // this can only happen if lstat/readdir lied, or if the dir was
        // swapped out with a file at just the right moment.
        /* c8 ignore start */
        if (entries) {
            if (errorCode(entries) === 'ENOENT') {
                return true;
            }
            if (errorCode(entries) !== 'ENOTDIR') {
                throw entries;
            }
        }
        /* c8 ignore stop */
        if (opt.filter && !opt.filter(path, ent)) {
            return false;
        }
        // is a file
        ignoreENOENTSync(() => rimrafWindowsFileSync(path, opt));
        return true;
    }
    let removedAll = true;
    for (const ent of entries) {
        const s = state === START ? CHILD : state;
        const p = resolve$1(path, ent.name);
        removedAll = rimrafWindowsDirSync(p, opt, ent, s) && removedAll;
    }
    if (state === START) {
        return rimrafWindowsDirSync(path, opt, ent, FINISH);
    }
    else if (state === FINISH) {
        if (opt.preserveRoot === false && path === parse$4(path).root) {
            return false;
        }
        if (!removedAll) {
            return false;
        }
        if (opt.filter && !opt.filter(path, ent)) {
            return false;
        }
        ignoreENOENTSync(() => rimrafWindowsDirMoveRemoveFallbackSync(path, opt));
    }
    return true;
};

const rimrafManual = process.platform === 'win32' ? rimrafWindows : rimrafPosix;
const rimrafManualSync = process.platform === 'win32' ? rimrafWindowsSync : rimrafPosixSync;

const { rm } = promises;
const rimrafNative = async (path, opt) => {
    await rm(path, {
        ...opt,
        force: true,
        recursive: true,
    });
    return true;
};
const rimrafNativeSync = (path, opt) => {
    rmSync(path, {
        ...opt,
        force: true,
        recursive: true,
    });
    return true;
};

/* c8 ignore next */
const [major = 0, minor = 0] = process.version
    .replace(/^v/, '')
    .split('.')
    .map(v => parseInt(v, 10));
const hasNative = major > 14 || (major === 14 && minor >= 14);
// we do NOT use native by default on Windows, because Node's native
// rm implementation is less advanced.  Change this code if that changes.
const useNative = !hasNative || process.platform === 'win32' ?
    () => false
    : opt => !opt?.signal && !opt?.filter;
const useNativeSync = !hasNative || process.platform === 'win32' ?
    () => false
    : opt => !opt?.signal && !opt?.filter;

const wrap = (fn) => async (path, opt) => {
    const options = optArg(opt);
    if (options.glob) {
        path = await glob$2(path, options.glob);
    }
    if (Array.isArray(path)) {
        return !!(await Promise.all(path.map(p => fn(pathArg(p, options), options)))).reduce((a, b) => a && b, true);
    }
    else {
        return !!(await fn(pathArg(path, options), options));
    }
};
const wrapSync = (fn) => (path, opt) => {
    const options = optArgSync(opt);
    if (options.glob) {
        path = globSync(path, options.glob);
    }
    if (Array.isArray(path)) {
        return !!path
            .map(p => fn(pathArg(p, options), options))
            .reduce((a, b) => a && b, true);
    }
    else {
        return !!fn(pathArg(path, options), options);
    }
};
const nativeSync = wrapSync(rimrafNativeSync);
const native = Object.assign(wrap(rimrafNative), { sync: nativeSync });
const manualSync = wrapSync(rimrafManualSync);
const manual = Object.assign(wrap(rimrafManual), { sync: manualSync });
const windowsSync = wrapSync(rimrafWindowsSync);
const windows$1 = Object.assign(wrap(rimrafWindows), { sync: windowsSync });
const posixSync = wrapSync(rimrafPosixSync);
const posix = Object.assign(wrap(rimrafPosix), { sync: posixSync });
const moveRemoveSync = wrapSync(rimrafMoveRemoveSync);
const moveRemove = Object.assign(wrap(rimrafMoveRemove), {
    sync: moveRemoveSync,
});
const rimrafSync = wrapSync((path, opt) => useNativeSync(opt) ?
    rimrafNativeSync(path, opt)
    : rimrafManualSync(path, opt));
const rimraf_ = wrap((path, opt) => useNative(opt) ? rimrafNative(path, opt) : rimrafManual(path, opt));
const rimraf = Object.assign(rimraf_, {
    rimraf: rimraf_,
    sync: rimrafSync,
    rimrafSync: rimrafSync,
    manual,
    manualSync,
    native,
    nativeSync,
    posix,
    posixSync,
    windows: windows$1,
    windowsSync,
    moveRemove,
    moveRemoveSync,
});
rimraf.rimraf = rimraf;

function coerce(value) {
	if (value instanceof Error) return value.stack || value.message;
	return value;
}
function selectColor(colors, namespace) {
	let hash = 0;
	for (let i = 0; i < namespace.length; i++) {
		hash = (hash << 5) - hash + namespace.charCodeAt(i);
		hash |= 0;
	}
	return colors[Math.abs(hash) % colors.length];
}
function matchesTemplate(search, template) {
	let searchIndex = 0;
	let templateIndex = 0;
	let starIndex = -1;
	let matchIndex = 0;
	while (searchIndex < search.length) if (templateIndex < template.length && (template[templateIndex] === search[searchIndex] || template[templateIndex] === "*")) if (template[templateIndex] === "*") {
		starIndex = templateIndex;
		matchIndex = searchIndex;
		templateIndex++;
	} else {
		searchIndex++;
		templateIndex++;
	}
	else if (starIndex !== -1) {
		templateIndex = starIndex + 1;
		matchIndex++;
		searchIndex = matchIndex;
	} else return false;
	while (templateIndex < template.length && template[templateIndex] === "*") templateIndex++;
	return templateIndex === template.length;
}
function humanize(value) {
	if (value >= 1e3) return `${(value / 1e3).toFixed(1)}s`;
	return `${value}ms`;
}
let globalNamespaces = "";
function createDebug$1(namespace, options) {
	let prevTime;
	let enableOverride;
	let namespacesCache;
	let enabledCache;
	const debug = (...args) => {
		if (!debug.enabled) return;
		const curr = Date.now();
		const diff = curr - (prevTime || curr);
		prevTime = curr;
		args[0] = coerce(args[0]);
		if (typeof args[0] !== "string") args.unshift("%O");
		let index = 0;
		args[0] = args[0].replace(/%([a-z%])/gi, (match, format) => {
			if (match === "%%") return "%";
			index++;
			const formatter = options.formatters[format];
			if (typeof formatter === "function") {
				const value = args[index];
				match = formatter.call(debug, value);
				args.splice(index, 1);
				index--;
			}
			return match;
		});
		options.formatArgs.call(debug, diff, args);
		debug.log(...args);
	};
	debug.extend = function(namespace$1, delimiter = ":") {
		return createDebug$1(this.namespace + delimiter + namespace$1, {
			useColors: this.useColors,
			color: this.color,
			formatArgs: this.formatArgs,
			formatters: this.formatters,
			inspectOpts: this.inspectOpts,
			log: this.log
		});
	};
	Object.assign(debug, options);
	debug.namespace = namespace;
	Object.defineProperty(debug, "enabled", {
		enumerable: true,
		configurable: false,
		get: () => {
			if (enableOverride != null) return enableOverride;
			if (namespacesCache !== globalNamespaces) {
				namespacesCache = globalNamespaces;
				enabledCache = enabled(namespace);
			}
			return enabledCache;
		},
		set: (v) => {
			enableOverride = v;
		}
	});
	return debug;
}
let names = [];
let skips = [];
function enable(namespaces$1) {
	globalNamespaces = namespaces$1;
	names = [];
	skips = [];
	const split = globalNamespaces.trim().replace(/\s+/g, ",").split(",").filter(Boolean);
	for (const ns of split) if (ns[0] === "-") skips.push(ns.slice(1));
	else names.push(ns);
}
function enabled(name) {
	for (const skip of skips) if (matchesTemplate(name, skip)) return false;
	for (const ns of names) if (matchesTemplate(name, ns)) return true;
	return false;
}

const require$3 = createRequire(import.meta.url);
const colors = process.stderr.getColorDepth && process.stderr.getColorDepth() > 2 ? [
	20,
	21,
	26,
	27,
	32,
	33,
	38,
	39,
	40,
	41,
	42,
	43,
	44,
	45,
	56,
	57,
	62,
	63,
	68,
	69,
	74,
	75,
	76,
	77,
	78,
	79,
	80,
	81,
	92,
	93,
	98,
	99,
	112,
	113,
	128,
	129,
	134,
	135,
	148,
	149,
	160,
	161,
	162,
	163,
	164,
	165,
	166,
	167,
	168,
	169,
	170,
	171,
	172,
	173,
	178,
	179,
	184,
	185,
	196,
	197,
	198,
	199,
	200,
	201,
	202,
	203,
	204,
	205,
	206,
	207,
	208,
	209,
	214,
	215,
	220,
	221
] : [
	6,
	2,
	3,
	4,
	5,
	1
];
const inspectOpts = Object.keys(process.env).filter((key) => /^debug_/i.test(key)).reduce((obj, key) => {
	const prop = key.slice(6).toLowerCase().replace(/_([a-z])/g, (_, k) => k.toUpperCase());
	let value = process.env[key];
	if (value === "null") value = null;
	else if (/^yes|on|true|enabled$/i.test(value)) value = true;
	else if (/^no|off|false|disabled$/i.test(value)) value = false;
	else value = Number(value);
	obj[prop] = value;
	return obj;
}, {});
function useColors() {
	return "colors" in inspectOpts ? Boolean(inspectOpts.colors) : isatty(process.stderr.fd);
}
let humanize$1;
try {
	humanize$1 = require$3("ms");
} catch (_unused) {
	humanize$1 = humanize;
}
function getDate() {
	if (inspectOpts.hideDate) return "";
	return `${(/* @__PURE__ */ new Date()).toISOString()} `;
}
function formatArgs(diff, args) {
	const { namespace: name, useColors: useColors$1 } = this;
	if (useColors$1) {
		const c = this.color;
		const colorCode = `\u001B[3${c < 8 ? c : `8;5;${c}`}`;
		const prefix = `  ${colorCode};1m${name} \u001B[0m`;
		args[0] = prefix + args[0].split("\n").join(`\n${prefix}`);
		args.push(`${colorCode}m+${humanize$1(diff)}\u001B[0m`);
	} else args[0] = `${getDate()}${name} ${args[0]}`;
}
function log$1(...args) {
	process.stderr.write(`${formatWithOptions(this.inspectOpts, ...args)}\n`);
}
const defaultOptions$1 = {
	useColors: useColors(),
	formatArgs,
	formatters: {
		o(v) {
			this.inspectOpts.colors = this.useColors;
			return inspect$1(v, this.inspectOpts).split("\n").map((str) => str.trim()).join(" ");
		},
		O(v) {
			this.inspectOpts.colors = this.useColors;
			return inspect$1(v, this.inspectOpts);
		}
	},
	inspectOpts,
	log: log$1
};
function createDebug(namespace, options) {
	var _ref;
	const color = (_ref = options) !== null && _ref !== void 0 ? _ref : selectColor(colors, namespace);
	return createDebug$1(namespace, Object.assign(defaultOptions$1, { color }, options));
}
enable(process.env.DEBUG || "");

var picocolors = {exports: {}};

var hasRequiredPicocolors;

function requirePicocolors () {
	if (hasRequiredPicocolors) return picocolors.exports;
	hasRequiredPicocolors = 1;
	let p = process || {}, argv = p.argv || [], env = p.env || {};
	let isColorSupported =
		!(!!env.NO_COLOR || argv.includes("--no-color")) &&
		(!!env.FORCE_COLOR || argv.includes("--color") || p.platform === "win32" || ((p.stdout || {}).isTTY && env.TERM !== "dumb") || !!env.CI);

	let formatter = (open, close, replace = open) =>
		input => {
			let string = "" + input, index = string.indexOf(close, open.length);
			return ~index ? open + replaceClose(string, close, replace, index) + close : open + string + close
		};

	let replaceClose = (string, close, replace, index) => {
		let result = "", cursor = 0;
		do {
			result += string.substring(cursor, index) + replace;
			cursor = index + close.length;
			index = string.indexOf(close, cursor);
		} while (~index)
		return result + string.substring(cursor)
	};

	let createColors = (enabled = isColorSupported) => {
		let f = enabled ? formatter : () => String;
		return {
			isColorSupported: enabled,
			reset: f("\x1b[0m", "\x1b[0m"),
			bold: f("\x1b[1m", "\x1b[22m", "\x1b[22m\x1b[1m"),
			dim: f("\x1b[2m", "\x1b[22m", "\x1b[22m\x1b[2m"),
			italic: f("\x1b[3m", "\x1b[23m"),
			underline: f("\x1b[4m", "\x1b[24m"),
			inverse: f("\x1b[7m", "\x1b[27m"),
			hidden: f("\x1b[8m", "\x1b[28m"),
			strikethrough: f("\x1b[9m", "\x1b[29m"),

			black: f("\x1b[30m", "\x1b[39m"),
			red: f("\x1b[31m", "\x1b[39m"),
			green: f("\x1b[32m", "\x1b[39m"),
			yellow: f("\x1b[33m", "\x1b[39m"),
			blue: f("\x1b[34m", "\x1b[39m"),
			magenta: f("\x1b[35m", "\x1b[39m"),
			cyan: f("\x1b[36m", "\x1b[39m"),
			white: f("\x1b[37m", "\x1b[39m"),
			gray: f("\x1b[90m", "\x1b[39m"),

			bgBlack: f("\x1b[40m", "\x1b[49m"),
			bgRed: f("\x1b[41m", "\x1b[49m"),
			bgGreen: f("\x1b[42m", "\x1b[49m"),
			bgYellow: f("\x1b[43m", "\x1b[49m"),
			bgBlue: f("\x1b[44m", "\x1b[49m"),
			bgMagenta: f("\x1b[45m", "\x1b[49m"),
			bgCyan: f("\x1b[46m", "\x1b[49m"),
			bgWhite: f("\x1b[47m", "\x1b[49m"),

			blackBright: f("\x1b[90m", "\x1b[39m"),
			redBright: f("\x1b[91m", "\x1b[39m"),
			greenBright: f("\x1b[92m", "\x1b[39m"),
			yellowBright: f("\x1b[93m", "\x1b[39m"),
			blueBright: f("\x1b[94m", "\x1b[39m"),
			magentaBright: f("\x1b[95m", "\x1b[39m"),
			cyanBright: f("\x1b[96m", "\x1b[39m"),
			whiteBright: f("\x1b[97m", "\x1b[39m"),

			bgBlackBright: f("\x1b[100m", "\x1b[49m"),
			bgRedBright: f("\x1b[101m", "\x1b[49m"),
			bgGreenBright: f("\x1b[102m", "\x1b[49m"),
			bgYellowBright: f("\x1b[103m", "\x1b[49m"),
			bgBlueBright: f("\x1b[104m", "\x1b[49m"),
			bgMagentaBright: f("\x1b[105m", "\x1b[49m"),
			bgCyanBright: f("\x1b[106m", "\x1b[49m"),
			bgWhiteBright: f("\x1b[107m", "\x1b[49m"),
		}
	};

	picocolors.exports = createColors();
	picocolors.exports.createColors = createColors;
	return picocolors.exports;
}

var picocolorsExports = /*@__PURE__*/ requirePicocolors();
var c$1 = /*@__PURE__*/getDefaultExportFromCjs(picocolorsExports);

const require$2 = createRequire(import.meta.url);
const PKG_ROOT = resolve$2(fileURLToPath(import.meta.url), "../..");
const DIST_CLIENT_PATH = resolve$2(PKG_ROOT, "client");
const APP_PATH = join(DIST_CLIENT_PATH, "app");
join(DIST_CLIENT_PATH, "shared");
const DEFAULT_THEME_PATH = join(DIST_CLIENT_PATH, "theme-default");
const SITE_DATA_ID = "@siteData";
const SITE_DATA_REQUEST_PATH = "/" + SITE_DATA_ID;
const vueRuntimePath = "vue/dist/vue.runtime.esm-bundler.js";
function resolveAliases(root, ssr) {
  const aliases = [
    {
      find: /^vitepress$/,
      replacement: join(DIST_CLIENT_PATH, "/index.js")
    },
    {
      find: /^vitepress\/theme$/,
      replacement: join(DIST_CLIENT_PATH, "/theme-default/index.js")
    }
  ];
  if (!ssr) {
    let vuePath;
    try {
      vuePath = require$2.resolve(vueRuntimePath, { paths: [root] });
    } catch (e) {
      vuePath = require$2.resolve(vueRuntimePath);
    }
    aliases.push({
      find: /^vue$/,
      replacement: vuePath
    });
  }
  return aliases;
}

var utils$3 = {};

var constants;
var hasRequiredConstants;

function requireConstants () {
	if (hasRequiredConstants) return constants;
	hasRequiredConstants = 1;

	const WIN_SLASH = '\\\\/';
	const WIN_NO_SLASH = `[^${WIN_SLASH}]`;

	/**
	 * Posix glob regex
	 */

	const DOT_LITERAL = '\\.';
	const PLUS_LITERAL = '\\+';
	const QMARK_LITERAL = '\\?';
	const SLASH_LITERAL = '\\/';
	const ONE_CHAR = '(?=.)';
	const QMARK = '[^/]';
	const END_ANCHOR = `(?:${SLASH_LITERAL}|$)`;
	const START_ANCHOR = `(?:^|${SLASH_LITERAL})`;
	const DOTS_SLASH = `${DOT_LITERAL}{1,2}${END_ANCHOR}`;
	const NO_DOT = `(?!${DOT_LITERAL})`;
	const NO_DOTS = `(?!${START_ANCHOR}${DOTS_SLASH})`;
	const NO_DOT_SLASH = `(?!${DOT_LITERAL}{0,1}${END_ANCHOR})`;
	const NO_DOTS_SLASH = `(?!${DOTS_SLASH})`;
	const QMARK_NO_DOT = `[^.${SLASH_LITERAL}]`;
	const STAR = `${QMARK}*?`;
	const SEP = '/';

	const POSIX_CHARS = {
	  DOT_LITERAL,
	  PLUS_LITERAL,
	  QMARK_LITERAL,
	  SLASH_LITERAL,
	  ONE_CHAR,
	  QMARK,
	  END_ANCHOR,
	  DOTS_SLASH,
	  NO_DOT,
	  NO_DOTS,
	  NO_DOT_SLASH,
	  NO_DOTS_SLASH,
	  QMARK_NO_DOT,
	  STAR,
	  START_ANCHOR,
	  SEP
	};

	/**
	 * Windows glob regex
	 */

	const WINDOWS_CHARS = {
	  ...POSIX_CHARS,

	  SLASH_LITERAL: `[${WIN_SLASH}]`,
	  QMARK: WIN_NO_SLASH,
	  STAR: `${WIN_NO_SLASH}*?`,
	  DOTS_SLASH: `${DOT_LITERAL}{1,2}(?:[${WIN_SLASH}]|$)`,
	  NO_DOT: `(?!${DOT_LITERAL})`,
	  NO_DOTS: `(?!(?:^|[${WIN_SLASH}])${DOT_LITERAL}{1,2}(?:[${WIN_SLASH}]|$))`,
	  NO_DOT_SLASH: `(?!${DOT_LITERAL}{0,1}(?:[${WIN_SLASH}]|$))`,
	  NO_DOTS_SLASH: `(?!${DOT_LITERAL}{1,2}(?:[${WIN_SLASH}]|$))`,
	  QMARK_NO_DOT: `[^.${WIN_SLASH}]`,
	  START_ANCHOR: `(?:^|[${WIN_SLASH}])`,
	  END_ANCHOR: `(?:[${WIN_SLASH}]|$)`,
	  SEP: '\\'
	};

	/**
	 * POSIX Bracket Regex
	 */

	const POSIX_REGEX_SOURCE = {
	  alnum: 'a-zA-Z0-9',
	  alpha: 'a-zA-Z',
	  ascii: '\\x00-\\x7F',
	  blank: ' \\t',
	  cntrl: '\\x00-\\x1F\\x7F',
	  digit: '0-9',
	  graph: '\\x21-\\x7E',
	  lower: 'a-z',
	  print: '\\x20-\\x7E ',
	  punct: '\\-!"#$%&\'()\\*+,./:;<=>?@[\\]^_`{|}~',
	  space: ' \\t\\r\\n\\v\\f',
	  upper: 'A-Z',
	  word: 'A-Za-z0-9_',
	  xdigit: 'A-Fa-f0-9'
	};

	constants = {
	  MAX_LENGTH: 1024 * 64,
	  POSIX_REGEX_SOURCE,

	  // regular expressions
	  REGEX_BACKSLASH: /\\(?![*+?^${}(|)[\]])/g,
	  REGEX_NON_SPECIAL_CHARS: /^[^@![\].,$*+?^{}()|\\/]+/,
	  REGEX_SPECIAL_CHARS: /[-*+?.^${}(|)[\]]/,
	  REGEX_SPECIAL_CHARS_BACKREF: /(\\?)((\W)(\3*))/g,
	  REGEX_SPECIAL_CHARS_GLOBAL: /([-*+?.^${}(|)[\]])/g,
	  REGEX_REMOVE_BACKSLASH: /(?:\[.*?[^\\]\]|\\(?=.))/g,

	  // Replace globs with equivalent patterns to reduce parsing time.
	  REPLACEMENTS: {
	    __proto__: null,
	    '***': '*',
	    '**/**': '**',
	    '**/**/**': '**'
	  },

	  // Digits
	  CHAR_0: 48, /* 0 */
	  CHAR_9: 57, /* 9 */

	  // Alphabet chars.
	  CHAR_UPPERCASE_A: 65, /* A */
	  CHAR_LOWERCASE_A: 97, /* a */
	  CHAR_UPPERCASE_Z: 90, /* Z */
	  CHAR_LOWERCASE_Z: 122, /* z */

	  CHAR_LEFT_PARENTHESES: 40, /* ( */
	  CHAR_RIGHT_PARENTHESES: 41, /* ) */

	  CHAR_ASTERISK: 42, /* * */

	  // Non-alphabetic chars.
	  CHAR_AMPERSAND: 38, /* & */
	  CHAR_AT: 64, /* @ */
	  CHAR_BACKWARD_SLASH: 92, /* \ */
	  CHAR_CARRIAGE_RETURN: 13, /* \r */
	  CHAR_CIRCUMFLEX_ACCENT: 94, /* ^ */
	  CHAR_COLON: 58, /* : */
	  CHAR_COMMA: 44, /* , */
	  CHAR_DOT: 46, /* . */
	  CHAR_DOUBLE_QUOTE: 34, /* " */
	  CHAR_EQUAL: 61, /* = */
	  CHAR_EXCLAMATION_MARK: 33, /* ! */
	  CHAR_FORM_FEED: 12, /* \f */
	  CHAR_FORWARD_SLASH: 47, /* / */
	  CHAR_GRAVE_ACCENT: 96, /* ` */
	  CHAR_HASH: 35, /* # */
	  CHAR_HYPHEN_MINUS: 45, /* - */
	  CHAR_LEFT_ANGLE_BRACKET: 60, /* < */
	  CHAR_LEFT_CURLY_BRACE: 123, /* { */
	  CHAR_LEFT_SQUARE_BRACKET: 91, /* [ */
	  CHAR_LINE_FEED: 10, /* \n */
	  CHAR_NO_BREAK_SPACE: 160, /* \u00A0 */
	  CHAR_PERCENT: 37, /* % */
	  CHAR_PLUS: 43, /* + */
	  CHAR_QUESTION_MARK: 63, /* ? */
	  CHAR_RIGHT_ANGLE_BRACKET: 62, /* > */
	  CHAR_RIGHT_CURLY_BRACE: 125, /* } */
	  CHAR_RIGHT_SQUARE_BRACKET: 93, /* ] */
	  CHAR_SEMICOLON: 59, /* ; */
	  CHAR_SINGLE_QUOTE: 39, /* ' */
	  CHAR_SPACE: 32, /*   */
	  CHAR_TAB: 9, /* \t */
	  CHAR_UNDERSCORE: 95, /* _ */
	  CHAR_VERTICAL_LINE: 124, /* | */
	  CHAR_ZERO_WIDTH_NOBREAK_SPACE: 65279, /* \uFEFF */

	  /**
	   * Create EXTGLOB_CHARS
	   */

	  extglobChars(chars) {
	    return {
	      '!': { type: 'negate', open: '(?:(?!(?:', close: `))${chars.STAR})` },
	      '?': { type: 'qmark', open: '(?:', close: ')?' },
	      '+': { type: 'plus', open: '(?:', close: ')+' },
	      '*': { type: 'star', open: '(?:', close: ')*' },
	      '@': { type: 'at', open: '(?:', close: ')' }
	    };
	  },

	  /**
	   * Create GLOB_CHARS
	   */

	  globChars(win32) {
	    return win32 === true ? WINDOWS_CHARS : POSIX_CHARS;
	  }
	};
	return constants;
}

/*global navigator*/

var hasRequiredUtils$2;

function requireUtils$2 () {
	if (hasRequiredUtils$2) return utils$3;
	hasRequiredUtils$2 = 1;
	(function (exports$1) {

		const {
		  REGEX_BACKSLASH,
		  REGEX_REMOVE_BACKSLASH,
		  REGEX_SPECIAL_CHARS,
		  REGEX_SPECIAL_CHARS_GLOBAL
		} = requireConstants();

		exports$1.isObject = val => val !== null && typeof val === 'object' && !Array.isArray(val);
		exports$1.hasRegexChars = str => REGEX_SPECIAL_CHARS.test(str);
		exports$1.isRegexChar = str => str.length === 1 && exports$1.hasRegexChars(str);
		exports$1.escapeRegex = str => str.replace(REGEX_SPECIAL_CHARS_GLOBAL, '\\$1');
		exports$1.toPosixSlashes = str => str.replace(REGEX_BACKSLASH, '/');

		exports$1.isWindows = () => {
		  if (typeof navigator !== 'undefined' && navigator.platform) {
		    const platform = navigator.platform.toLowerCase();
		    return platform === 'win32' || platform === 'windows';
		  }

		  if (typeof process !== 'undefined' && process.platform) {
		    return process.platform === 'win32';
		  }

		  return false;
		};

		exports$1.removeBackslashes = str => {
		  return str.replace(REGEX_REMOVE_BACKSLASH, match => {
		    return match === '\\' ? '' : match;
		  });
		};

		exports$1.escapeLast = (input, char, lastIdx) => {
		  const idx = input.lastIndexOf(char, lastIdx);
		  if (idx === -1) return input;
		  if (input[idx - 1] === '\\') return exports$1.escapeLast(input, char, idx - 1);
		  return `${input.slice(0, idx)}\\${input.slice(idx)}`;
		};

		exports$1.removePrefix = (input, state = {}) => {
		  let output = input;
		  if (output.startsWith('./')) {
		    output = output.slice(2);
		    state.prefix = './';
		  }
		  return output;
		};

		exports$1.wrapOutput = (input, state = {}, options = {}) => {
		  const prepend = options.contains ? '' : '^';
		  const append = options.contains ? '' : '$';

		  let output = `${prepend}(?:${input})${append}`;
		  if (state.negated === true) {
		    output = `(?:^(?!${output}).*$)`;
		  }
		  return output;
		};

		exports$1.basename = (path, { windows } = {}) => {
		  const segs = path.split(windows ? /[\\/]/ : '/');
		  const last = segs[segs.length - 1];

		  if (last === '') {
		    return segs[segs.length - 2];
		  }

		  return last;
		}; 
	} (utils$3));
	return utils$3;
}

var scan_1;
var hasRequiredScan;

function requireScan () {
	if (hasRequiredScan) return scan_1;
	hasRequiredScan = 1;

	const utils = requireUtils$2();
	const {
	  CHAR_ASTERISK,             /* * */
	  CHAR_AT,                   /* @ */
	  CHAR_BACKWARD_SLASH,       /* \ */
	  CHAR_COMMA,                /* , */
	  CHAR_DOT,                  /* . */
	  CHAR_EXCLAMATION_MARK,     /* ! */
	  CHAR_FORWARD_SLASH,        /* / */
	  CHAR_LEFT_CURLY_BRACE,     /* { */
	  CHAR_LEFT_PARENTHESES,     /* ( */
	  CHAR_LEFT_SQUARE_BRACKET,  /* [ */
	  CHAR_PLUS,                 /* + */
	  CHAR_QUESTION_MARK,        /* ? */
	  CHAR_RIGHT_CURLY_BRACE,    /* } */
	  CHAR_RIGHT_PARENTHESES,    /* ) */
	  CHAR_RIGHT_SQUARE_BRACKET  /* ] */
	} = requireConstants();

	const isPathSeparator = code => {
	  return code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH;
	};

	const depth = token => {
	  if (token.isPrefix !== true) {
	    token.depth = token.isGlobstar ? Infinity : 1;
	  }
	};

	/**
	 * Quickly scans a glob pattern and returns an object with a handful of
	 * useful properties, like `isGlob`, `path` (the leading non-glob, if it exists),
	 * `glob` (the actual pattern), `negated` (true if the path starts with `!` but not
	 * with `!(`) and `negatedExtglob` (true if the path starts with `!(`).
	 *
	 * ```js
	 * const pm = require('picomatch');
	 * console.log(pm.scan('foo/bar/*.js'));
	 * { isGlob: true, input: 'foo/bar/*.js', base: 'foo/bar', glob: '*.js' }
	 * ```
	 * @param {String} `str`
	 * @param {Object} `options`
	 * @return {Object} Returns an object with tokens and regex source string.
	 * @api public
	 */

	const scan = (input, options) => {
	  const opts = options || {};

	  const length = input.length - 1;
	  const scanToEnd = opts.parts === true || opts.scanToEnd === true;
	  const slashes = [];
	  const tokens = [];
	  const parts = [];

	  let str = input;
	  let index = -1;
	  let start = 0;
	  let lastIndex = 0;
	  let isBrace = false;
	  let isBracket = false;
	  let isGlob = false;
	  let isExtglob = false;
	  let isGlobstar = false;
	  let braceEscaped = false;
	  let backslashes = false;
	  let negated = false;
	  let negatedExtglob = false;
	  let finished = false;
	  let braces = 0;
	  let prev;
	  let code;
	  let token = { value: '', depth: 0, isGlob: false };

	  const eos = () => index >= length;
	  const peek = () => str.charCodeAt(index + 1);
	  const advance = () => {
	    prev = code;
	    return str.charCodeAt(++index);
	  };

	  while (index < length) {
	    code = advance();
	    let next;

	    if (code === CHAR_BACKWARD_SLASH) {
	      backslashes = token.backslashes = true;
	      code = advance();

	      if (code === CHAR_LEFT_CURLY_BRACE) {
	        braceEscaped = true;
	      }
	      continue;
	    }

	    if (braceEscaped === true || code === CHAR_LEFT_CURLY_BRACE) {
	      braces++;

	      while (eos() !== true && (code = advance())) {
	        if (code === CHAR_BACKWARD_SLASH) {
	          backslashes = token.backslashes = true;
	          advance();
	          continue;
	        }

	        if (code === CHAR_LEFT_CURLY_BRACE) {
	          braces++;
	          continue;
	        }

	        if (braceEscaped !== true && code === CHAR_DOT && (code = advance()) === CHAR_DOT) {
	          isBrace = token.isBrace = true;
	          isGlob = token.isGlob = true;
	          finished = true;

	          if (scanToEnd === true) {
	            continue;
	          }

	          break;
	        }

	        if (braceEscaped !== true && code === CHAR_COMMA) {
	          isBrace = token.isBrace = true;
	          isGlob = token.isGlob = true;
	          finished = true;

	          if (scanToEnd === true) {
	            continue;
	          }

	          break;
	        }

	        if (code === CHAR_RIGHT_CURLY_BRACE) {
	          braces--;

	          if (braces === 0) {
	            braceEscaped = false;
	            isBrace = token.isBrace = true;
	            finished = true;
	            break;
	          }
	        }
	      }

	      if (scanToEnd === true) {
	        continue;
	      }

	      break;
	    }

	    if (code === CHAR_FORWARD_SLASH) {
	      slashes.push(index);
	      tokens.push(token);
	      token = { value: '', depth: 0, isGlob: false };

	      if (finished === true) continue;
	      if (prev === CHAR_DOT && index === (start + 1)) {
	        start += 2;
	        continue;
	      }

	      lastIndex = index + 1;
	      continue;
	    }

	    if (opts.noext !== true) {
	      const isExtglobChar = code === CHAR_PLUS
	        || code === CHAR_AT
	        || code === CHAR_ASTERISK
	        || code === CHAR_QUESTION_MARK
	        || code === CHAR_EXCLAMATION_MARK;

	      if (isExtglobChar === true && peek() === CHAR_LEFT_PARENTHESES) {
	        isGlob = token.isGlob = true;
	        isExtglob = token.isExtglob = true;
	        finished = true;
	        if (code === CHAR_EXCLAMATION_MARK && index === start) {
	          negatedExtglob = true;
	        }

	        if (scanToEnd === true) {
	          while (eos() !== true && (code = advance())) {
	            if (code === CHAR_BACKWARD_SLASH) {
	              backslashes = token.backslashes = true;
	              code = advance();
	              continue;
	            }

	            if (code === CHAR_RIGHT_PARENTHESES) {
	              isGlob = token.isGlob = true;
	              finished = true;
	              break;
	            }
	          }
	          continue;
	        }
	        break;
	      }
	    }

	    if (code === CHAR_ASTERISK) {
	      if (prev === CHAR_ASTERISK) isGlobstar = token.isGlobstar = true;
	      isGlob = token.isGlob = true;
	      finished = true;

	      if (scanToEnd === true) {
	        continue;
	      }
	      break;
	    }

	    if (code === CHAR_QUESTION_MARK) {
	      isGlob = token.isGlob = true;
	      finished = true;

	      if (scanToEnd === true) {
	        continue;
	      }
	      break;
	    }

	    if (code === CHAR_LEFT_SQUARE_BRACKET) {
	      while (eos() !== true && (next = advance())) {
	        if (next === CHAR_BACKWARD_SLASH) {
	          backslashes = token.backslashes = true;
	          advance();
	          continue;
	        }

	        if (next === CHAR_RIGHT_SQUARE_BRACKET) {
	          isBracket = token.isBracket = true;
	          isGlob = token.isGlob = true;
	          finished = true;
	          break;
	        }
	      }

	      if (scanToEnd === true) {
	        continue;
	      }

	      break;
	    }

	    if (opts.nonegate !== true && code === CHAR_EXCLAMATION_MARK && index === start) {
	      negated = token.negated = true;
	      start++;
	      continue;
	    }

	    if (opts.noparen !== true && code === CHAR_LEFT_PARENTHESES) {
	      isGlob = token.isGlob = true;

	      if (scanToEnd === true) {
	        while (eos() !== true && (code = advance())) {
	          if (code === CHAR_LEFT_PARENTHESES) {
	            backslashes = token.backslashes = true;
	            code = advance();
	            continue;
	          }

	          if (code === CHAR_RIGHT_PARENTHESES) {
	            finished = true;
	            break;
	          }
	        }
	        continue;
	      }
	      break;
	    }

	    if (isGlob === true) {
	      finished = true;

	      if (scanToEnd === true) {
	        continue;
	      }

	      break;
	    }
	  }

	  if (opts.noext === true) {
	    isExtglob = false;
	    isGlob = false;
	  }

	  let base = str;
	  let prefix = '';
	  let glob = '';

	  if (start > 0) {
	    prefix = str.slice(0, start);
	    str = str.slice(start);
	    lastIndex -= start;
	  }

	  if (base && isGlob === true && lastIndex > 0) {
	    base = str.slice(0, lastIndex);
	    glob = str.slice(lastIndex);
	  } else if (isGlob === true) {
	    base = '';
	    glob = str;
	  } else {
	    base = str;
	  }

	  if (base && base !== '' && base !== '/' && base !== str) {
	    if (isPathSeparator(base.charCodeAt(base.length - 1))) {
	      base = base.slice(0, -1);
	    }
	  }

	  if (opts.unescape === true) {
	    if (glob) glob = utils.removeBackslashes(glob);

	    if (base && backslashes === true) {
	      base = utils.removeBackslashes(base);
	    }
	  }

	  const state = {
	    prefix,
	    input,
	    start,
	    base,
	    glob,
	    isBrace,
	    isBracket,
	    isGlob,
	    isExtglob,
	    isGlobstar,
	    negated,
	    negatedExtglob
	  };

	  if (opts.tokens === true) {
	    state.maxDepth = 0;
	    if (!isPathSeparator(code)) {
	      tokens.push(token);
	    }
	    state.tokens = tokens;
	  }

	  if (opts.parts === true || opts.tokens === true) {
	    let prevIndex;

	    for (let idx = 0; idx < slashes.length; idx++) {
	      const n = prevIndex ? prevIndex + 1 : start;
	      const i = slashes[idx];
	      const value = input.slice(n, i);
	      if (opts.tokens) {
	        if (idx === 0 && start !== 0) {
	          tokens[idx].isPrefix = true;
	          tokens[idx].value = prefix;
	        } else {
	          tokens[idx].value = value;
	        }
	        depth(tokens[idx]);
	        state.maxDepth += tokens[idx].depth;
	      }
	      if (idx !== 0 || value !== '') {
	        parts.push(value);
	      }
	      prevIndex = i;
	    }

	    if (prevIndex && prevIndex + 1 < input.length) {
	      const value = input.slice(prevIndex + 1);
	      parts.push(value);

	      if (opts.tokens) {
	        tokens[tokens.length - 1].value = value;
	        depth(tokens[tokens.length - 1]);
	        state.maxDepth += tokens[tokens.length - 1].depth;
	      }
	    }

	    state.slashes = slashes;
	    state.parts = parts;
	  }

	  return state;
	};

	scan_1 = scan;
	return scan_1;
}

var parse_1$1;
var hasRequiredParse$2;

function requireParse$2 () {
	if (hasRequiredParse$2) return parse_1$1;
	hasRequiredParse$2 = 1;

	const constants = requireConstants();
	const utils = requireUtils$2();

	/**
	 * Constants
	 */

	const {
	  MAX_LENGTH,
	  POSIX_REGEX_SOURCE,
	  REGEX_NON_SPECIAL_CHARS,
	  REGEX_SPECIAL_CHARS_BACKREF,
	  REPLACEMENTS
	} = constants;

	/**
	 * Helpers
	 */

	const expandRange = (args, options) => {
	  if (typeof options.expandRange === 'function') {
	    return options.expandRange(...args, options);
	  }

	  args.sort();
	  const value = `[${args.join('-')}]`;

	  try {
	    /* eslint-disable-next-line no-new */
	    new RegExp(value);
	  } catch (ex) {
	    return args.map(v => utils.escapeRegex(v)).join('..');
	  }

	  return value;
	};

	/**
	 * Create the message for a syntax error
	 */

	const syntaxError = (type, char) => {
	  return `Missing ${type}: "${char}" - use "\\\\${char}" to match literal characters`;
	};

	/**
	 * Parse the given input string.
	 * @param {String} input
	 * @param {Object} options
	 * @return {Object}
	 */

	const parse = (input, options) => {
	  if (typeof input !== 'string') {
	    throw new TypeError('Expected a string');
	  }

	  input = REPLACEMENTS[input] || input;

	  const opts = { ...options };
	  const max = typeof opts.maxLength === 'number' ? Math.min(MAX_LENGTH, opts.maxLength) : MAX_LENGTH;

	  let len = input.length;
	  if (len > max) {
	    throw new SyntaxError(`Input length: ${len}, exceeds maximum allowed length: ${max}`);
	  }

	  const bos = { type: 'bos', value: '', output: opts.prepend || '' };
	  const tokens = [bos];

	  const capture = opts.capture ? '' : '?:';

	  // create constants based on platform, for windows or posix
	  const PLATFORM_CHARS = constants.globChars(opts.windows);
	  const EXTGLOB_CHARS = constants.extglobChars(PLATFORM_CHARS);

	  const {
	    DOT_LITERAL,
	    PLUS_LITERAL,
	    SLASH_LITERAL,
	    ONE_CHAR,
	    DOTS_SLASH,
	    NO_DOT,
	    NO_DOT_SLASH,
	    NO_DOTS_SLASH,
	    QMARK,
	    QMARK_NO_DOT,
	    STAR,
	    START_ANCHOR
	  } = PLATFORM_CHARS;

	  const globstar = opts => {
	    return `(${capture}(?:(?!${START_ANCHOR}${opts.dot ? DOTS_SLASH : DOT_LITERAL}).)*?)`;
	  };

	  const nodot = opts.dot ? '' : NO_DOT;
	  const qmarkNoDot = opts.dot ? QMARK : QMARK_NO_DOT;
	  let star = opts.bash === true ? globstar(opts) : STAR;

	  if (opts.capture) {
	    star = `(${star})`;
	  }

	  // minimatch options support
	  if (typeof opts.noext === 'boolean') {
	    opts.noextglob = opts.noext;
	  }

	  const state = {
	    input,
	    index: -1,
	    start: 0,
	    dot: opts.dot === true,
	    consumed: '',
	    output: '',
	    prefix: '',
	    backtrack: false,
	    negated: false,
	    brackets: 0,
	    braces: 0,
	    parens: 0,
	    quotes: 0,
	    globstar: false,
	    tokens
	  };

	  input = utils.removePrefix(input, state);
	  len = input.length;

	  const extglobs = [];
	  const braces = [];
	  const stack = [];
	  let prev = bos;
	  let value;

	  /**
	   * Tokenizing helpers
	   */

	  const eos = () => state.index === len - 1;
	  const peek = state.peek = (n = 1) => input[state.index + n];
	  const advance = state.advance = () => input[++state.index] || '';
	  const remaining = () => input.slice(state.index + 1);
	  const consume = (value = '', num = 0) => {
	    state.consumed += value;
	    state.index += num;
	  };

	  const append = token => {
	    state.output += token.output != null ? token.output : token.value;
	    consume(token.value);
	  };

	  const negate = () => {
	    let count = 1;

	    while (peek() === '!' && (peek(2) !== '(' || peek(3) === '?')) {
	      advance();
	      state.start++;
	      count++;
	    }

	    if (count % 2 === 0) {
	      return false;
	    }

	    state.negated = true;
	    state.start++;
	    return true;
	  };

	  const increment = type => {
	    state[type]++;
	    stack.push(type);
	  };

	  const decrement = type => {
	    state[type]--;
	    stack.pop();
	  };

	  /**
	   * Push tokens onto the tokens array. This helper speeds up
	   * tokenizing by 1) helping us avoid backtracking as much as possible,
	   * and 2) helping us avoid creating extra tokens when consecutive
	   * characters are plain text. This improves performance and simplifies
	   * lookbehinds.
	   */

	  const push = tok => {
	    if (prev.type === 'globstar') {
	      const isBrace = state.braces > 0 && (tok.type === 'comma' || tok.type === 'brace');
	      const isExtglob = tok.extglob === true || (extglobs.length && (tok.type === 'pipe' || tok.type === 'paren'));

	      if (tok.type !== 'slash' && tok.type !== 'paren' && !isBrace && !isExtglob) {
	        state.output = state.output.slice(0, -prev.output.length);
	        prev.type = 'star';
	        prev.value = '*';
	        prev.output = star;
	        state.output += prev.output;
	      }
	    }

	    if (extglobs.length && tok.type !== 'paren') {
	      extglobs[extglobs.length - 1].inner += tok.value;
	    }

	    if (tok.value || tok.output) append(tok);
	    if (prev && prev.type === 'text' && tok.type === 'text') {
	      prev.output = (prev.output || prev.value) + tok.value;
	      prev.value += tok.value;
	      return;
	    }

	    tok.prev = prev;
	    tokens.push(tok);
	    prev = tok;
	  };

	  const extglobOpen = (type, value) => {
	    const token = { ...EXTGLOB_CHARS[value], conditions: 1, inner: '' };

	    token.prev = prev;
	    token.parens = state.parens;
	    token.output = state.output;
	    const output = (opts.capture ? '(' : '') + token.open;

	    increment('parens');
	    push({ type, value, output: state.output ? '' : ONE_CHAR });
	    push({ type: 'paren', extglob: true, value: advance(), output });
	    extglobs.push(token);
	  };

	  const extglobClose = token => {
	    let output = token.close + (opts.capture ? ')' : '');
	    let rest;

	    if (token.type === 'negate') {
	      let extglobStar = star;

	      if (token.inner && token.inner.length > 1 && token.inner.includes('/')) {
	        extglobStar = globstar(opts);
	      }

	      if (extglobStar !== star || eos() || /^\)+$/.test(remaining())) {
	        output = token.close = `)$))${extglobStar}`;
	      }

	      if (token.inner.includes('*') && (rest = remaining()) && /^\.[^\\/.]+$/.test(rest)) {
	        // Any non-magical string (`.ts`) or even nested expression (`.{ts,tsx}`) can follow after the closing parenthesis.
	        // In this case, we need to parse the string and use it in the output of the original pattern.
	        // Suitable patterns: `/!(*.d).ts`, `/!(*.d).{ts,tsx}`, `**/!(*-dbg).@(js)`.
	        //
	        // Disabling the `fastpaths` option due to a problem with parsing strings as `.ts` in the pattern like `**/!(*.d).ts`.
	        const expression = parse(rest, { ...options, fastpaths: false }).output;

	        output = token.close = `)${expression})${extglobStar})`;
	      }

	      if (token.prev.type === 'bos') {
	        state.negatedExtglob = true;
	      }
	    }

	    push({ type: 'paren', extglob: true, value, output });
	    decrement('parens');
	  };

	  /**
	   * Fast paths
	   */

	  if (opts.fastpaths !== false && !/(^[*!]|[/()[\]{}"])/.test(input)) {
	    let backslashes = false;

	    let output = input.replace(REGEX_SPECIAL_CHARS_BACKREF, (m, esc, chars, first, rest, index) => {
	      if (first === '\\') {
	        backslashes = true;
	        return m;
	      }

	      if (first === '?') {
	        if (esc) {
	          return esc + first + (rest ? QMARK.repeat(rest.length) : '');
	        }
	        if (index === 0) {
	          return qmarkNoDot + (rest ? QMARK.repeat(rest.length) : '');
	        }
	        return QMARK.repeat(chars.length);
	      }

	      if (first === '.') {
	        return DOT_LITERAL.repeat(chars.length);
	      }

	      if (first === '*') {
	        if (esc) {
	          return esc + first + (rest ? star : '');
	        }
	        return star;
	      }
	      return esc ? m : `\\${m}`;
	    });

	    if (backslashes === true) {
	      if (opts.unescape === true) {
	        output = output.replace(/\\/g, '');
	      } else {
	        output = output.replace(/\\+/g, m => {
	          return m.length % 2 === 0 ? '\\\\' : (m ? '\\' : '');
	        });
	      }
	    }

	    if (output === input && opts.contains === true) {
	      state.output = input;
	      return state;
	    }

	    state.output = utils.wrapOutput(output, state, options);
	    return state;
	  }

	  /**
	   * Tokenize input until we reach end-of-string
	   */

	  while (!eos()) {
	    value = advance();

	    if (value === '\u0000') {
	      continue;
	    }

	    /**
	     * Escaped characters
	     */

	    if (value === '\\') {
	      const next = peek();

	      if (next === '/' && opts.bash !== true) {
	        continue;
	      }

	      if (next === '.' || next === ';') {
	        continue;
	      }

	      if (!next) {
	        value += '\\';
	        push({ type: 'text', value });
	        continue;
	      }

	      // collapse slashes to reduce potential for exploits
	      const match = /^\\+/.exec(remaining());
	      let slashes = 0;

	      if (match && match[0].length > 2) {
	        slashes = match[0].length;
	        state.index += slashes;
	        if (slashes % 2 !== 0) {
	          value += '\\';
	        }
	      }

	      if (opts.unescape === true) {
	        value = advance();
	      } else {
	        value += advance();
	      }

	      if (state.brackets === 0) {
	        push({ type: 'text', value });
	        continue;
	      }
	    }

	    /**
	     * If we're inside a regex character class, continue
	     * until we reach the closing bracket.
	     */

	    if (state.brackets > 0 && (value !== ']' || prev.value === '[' || prev.value === '[^')) {
	      if (opts.posix !== false && value === ':') {
	        const inner = prev.value.slice(1);
	        if (inner.includes('[')) {
	          prev.posix = true;

	          if (inner.includes(':')) {
	            const idx = prev.value.lastIndexOf('[');
	            const pre = prev.value.slice(0, idx);
	            const rest = prev.value.slice(idx + 2);
	            const posix = POSIX_REGEX_SOURCE[rest];
	            if (posix) {
	              prev.value = pre + posix;
	              state.backtrack = true;
	              advance();

	              if (!bos.output && tokens.indexOf(prev) === 1) {
	                bos.output = ONE_CHAR;
	              }
	              continue;
	            }
	          }
	        }
	      }

	      if ((value === '[' && peek() !== ':') || (value === '-' && peek() === ']')) {
	        value = `\\${value}`;
	      }

	      if (value === ']' && (prev.value === '[' || prev.value === '[^')) {
	        value = `\\${value}`;
	      }

	      if (opts.posix === true && value === '!' && prev.value === '[') {
	        value = '^';
	      }

	      prev.value += value;
	      append({ value });
	      continue;
	    }

	    /**
	     * If we're inside a quoted string, continue
	     * until we reach the closing double quote.
	     */

	    if (state.quotes === 1 && value !== '"') {
	      value = utils.escapeRegex(value);
	      prev.value += value;
	      append({ value });
	      continue;
	    }

	    /**
	     * Double quotes
	     */

	    if (value === '"') {
	      state.quotes = state.quotes === 1 ? 0 : 1;
	      if (opts.keepQuotes === true) {
	        push({ type: 'text', value });
	      }
	      continue;
	    }

	    /**
	     * Parentheses
	     */

	    if (value === '(') {
	      increment('parens');
	      push({ type: 'paren', value });
	      continue;
	    }

	    if (value === ')') {
	      if (state.parens === 0 && opts.strictBrackets === true) {
	        throw new SyntaxError(syntaxError('opening', '('));
	      }

	      const extglob = extglobs[extglobs.length - 1];
	      if (extglob && state.parens === extglob.parens + 1) {
	        extglobClose(extglobs.pop());
	        continue;
	      }

	      push({ type: 'paren', value, output: state.parens ? ')' : '\\)' });
	      decrement('parens');
	      continue;
	    }

	    /**
	     * Square brackets
	     */

	    if (value === '[') {
	      if (opts.nobracket === true || !remaining().includes(']')) {
	        if (opts.nobracket !== true && opts.strictBrackets === true) {
	          throw new SyntaxError(syntaxError('closing', ']'));
	        }

	        value = `\\${value}`;
	      } else {
	        increment('brackets');
	      }

	      push({ type: 'bracket', value });
	      continue;
	    }

	    if (value === ']') {
	      if (opts.nobracket === true || (prev && prev.type === 'bracket' && prev.value.length === 1)) {
	        push({ type: 'text', value, output: `\\${value}` });
	        continue;
	      }

	      if (state.brackets === 0) {
	        if (opts.strictBrackets === true) {
	          throw new SyntaxError(syntaxError('opening', '['));
	        }

	        push({ type: 'text', value, output: `\\${value}` });
	        continue;
	      }

	      decrement('brackets');

	      const prevValue = prev.value.slice(1);
	      if (prev.posix !== true && prevValue[0] === '^' && !prevValue.includes('/')) {
	        value = `/${value}`;
	      }

	      prev.value += value;
	      append({ value });

	      // when literal brackets are explicitly disabled
	      // assume we should match with a regex character class
	      if (opts.literalBrackets === false || utils.hasRegexChars(prevValue)) {
	        continue;
	      }

	      const escaped = utils.escapeRegex(prev.value);
	      state.output = state.output.slice(0, -prev.value.length);

	      // when literal brackets are explicitly enabled
	      // assume we should escape the brackets to match literal characters
	      if (opts.literalBrackets === true) {
	        state.output += escaped;
	        prev.value = escaped;
	        continue;
	      }

	      // when the user specifies nothing, try to match both
	      prev.value = `(${capture}${escaped}|${prev.value})`;
	      state.output += prev.value;
	      continue;
	    }

	    /**
	     * Braces
	     */

	    if (value === '{' && opts.nobrace !== true) {
	      increment('braces');

	      const open = {
	        type: 'brace',
	        value,
	        output: '(',
	        outputIndex: state.output.length,
	        tokensIndex: state.tokens.length
	      };

	      braces.push(open);
	      push(open);
	      continue;
	    }

	    if (value === '}') {
	      const brace = braces[braces.length - 1];

	      if (opts.nobrace === true || !brace) {
	        push({ type: 'text', value, output: value });
	        continue;
	      }

	      let output = ')';

	      if (brace.dots === true) {
	        const arr = tokens.slice();
	        const range = [];

	        for (let i = arr.length - 1; i >= 0; i--) {
	          tokens.pop();
	          if (arr[i].type === 'brace') {
	            break;
	          }
	          if (arr[i].type !== 'dots') {
	            range.unshift(arr[i].value);
	          }
	        }

	        output = expandRange(range, opts);
	        state.backtrack = true;
	      }

	      if (brace.comma !== true && brace.dots !== true) {
	        const out = state.output.slice(0, brace.outputIndex);
	        const toks = state.tokens.slice(brace.tokensIndex);
	        brace.value = brace.output = '\\{';
	        value = output = '\\}';
	        state.output = out;
	        for (const t of toks) {
	          state.output += (t.output || t.value);
	        }
	      }

	      push({ type: 'brace', value, output });
	      decrement('braces');
	      braces.pop();
	      continue;
	    }

	    /**
	     * Pipes
	     */

	    if (value === '|') {
	      if (extglobs.length > 0) {
	        extglobs[extglobs.length - 1].conditions++;
	      }
	      push({ type: 'text', value });
	      continue;
	    }

	    /**
	     * Commas
	     */

	    if (value === ',') {
	      let output = value;

	      const brace = braces[braces.length - 1];
	      if (brace && stack[stack.length - 1] === 'braces') {
	        brace.comma = true;
	        output = '|';
	      }

	      push({ type: 'comma', value, output });
	      continue;
	    }

	    /**
	     * Slashes
	     */

	    if (value === '/') {
	      // if the beginning of the glob is "./", advance the start
	      // to the current index, and don't add the "./" characters
	      // to the state. This greatly simplifies lookbehinds when
	      // checking for BOS characters like "!" and "." (not "./")
	      if (prev.type === 'dot' && state.index === state.start + 1) {
	        state.start = state.index + 1;
	        state.consumed = '';
	        state.output = '';
	        tokens.pop();
	        prev = bos; // reset "prev" to the first token
	        continue;
	      }

	      push({ type: 'slash', value, output: SLASH_LITERAL });
	      continue;
	    }

	    /**
	     * Dots
	     */

	    if (value === '.') {
	      if (state.braces > 0 && prev.type === 'dot') {
	        if (prev.value === '.') prev.output = DOT_LITERAL;
	        const brace = braces[braces.length - 1];
	        prev.type = 'dots';
	        prev.output += value;
	        prev.value += value;
	        brace.dots = true;
	        continue;
	      }

	      if ((state.braces + state.parens) === 0 && prev.type !== 'bos' && prev.type !== 'slash') {
	        push({ type: 'text', value, output: DOT_LITERAL });
	        continue;
	      }

	      push({ type: 'dot', value, output: DOT_LITERAL });
	      continue;
	    }

	    /**
	     * Question marks
	     */

	    if (value === '?') {
	      const isGroup = prev && prev.value === '(';
	      if (!isGroup && opts.noextglob !== true && peek() === '(' && peek(2) !== '?') {
	        extglobOpen('qmark', value);
	        continue;
	      }

	      if (prev && prev.type === 'paren') {
	        const next = peek();
	        let output = value;

	        if ((prev.value === '(' && !/[!=<:]/.test(next)) || (next === '<' && !/<([!=]|\w+>)/.test(remaining()))) {
	          output = `\\${value}`;
	        }

	        push({ type: 'text', value, output });
	        continue;
	      }

	      if (opts.dot !== true && (prev.type === 'slash' || prev.type === 'bos')) {
	        push({ type: 'qmark', value, output: QMARK_NO_DOT });
	        continue;
	      }

	      push({ type: 'qmark', value, output: QMARK });
	      continue;
	    }

	    /**
	     * Exclamation
	     */

	    if (value === '!') {
	      if (opts.noextglob !== true && peek() === '(') {
	        if (peek(2) !== '?' || !/[!=<:]/.test(peek(3))) {
	          extglobOpen('negate', value);
	          continue;
	        }
	      }

	      if (opts.nonegate !== true && state.index === 0) {
	        negate();
	        continue;
	      }
	    }

	    /**
	     * Plus
	     */

	    if (value === '+') {
	      if (opts.noextglob !== true && peek() === '(' && peek(2) !== '?') {
	        extglobOpen('plus', value);
	        continue;
	      }

	      if ((prev && prev.value === '(') || opts.regex === false) {
	        push({ type: 'plus', value, output: PLUS_LITERAL });
	        continue;
	      }

	      if ((prev && (prev.type === 'bracket' || prev.type === 'paren' || prev.type === 'brace')) || state.parens > 0) {
	        push({ type: 'plus', value });
	        continue;
	      }

	      push({ type: 'plus', value: PLUS_LITERAL });
	      continue;
	    }

	    /**
	     * Plain text
	     */

	    if (value === '@') {
	      if (opts.noextglob !== true && peek() === '(' && peek(2) !== '?') {
	        push({ type: 'at', extglob: true, value, output: '' });
	        continue;
	      }

	      push({ type: 'text', value });
	      continue;
	    }

	    /**
	     * Plain text
	     */

	    if (value !== '*') {
	      if (value === '$' || value === '^') {
	        value = `\\${value}`;
	      }

	      const match = REGEX_NON_SPECIAL_CHARS.exec(remaining());
	      if (match) {
	        value += match[0];
	        state.index += match[0].length;
	      }

	      push({ type: 'text', value });
	      continue;
	    }

	    /**
	     * Stars
	     */

	    if (prev && (prev.type === 'globstar' || prev.star === true)) {
	      prev.type = 'star';
	      prev.star = true;
	      prev.value += value;
	      prev.output = star;
	      state.backtrack = true;
	      state.globstar = true;
	      consume(value);
	      continue;
	    }

	    let rest = remaining();
	    if (opts.noextglob !== true && /^\([^?]/.test(rest)) {
	      extglobOpen('star', value);
	      continue;
	    }

	    if (prev.type === 'star') {
	      if (opts.noglobstar === true) {
	        consume(value);
	        continue;
	      }

	      const prior = prev.prev;
	      const before = prior.prev;
	      const isStart = prior.type === 'slash' || prior.type === 'bos';
	      const afterStar = before && (before.type === 'star' || before.type === 'globstar');

	      if (opts.bash === true && (!isStart || (rest[0] && rest[0] !== '/'))) {
	        push({ type: 'star', value, output: '' });
	        continue;
	      }

	      const isBrace = state.braces > 0 && (prior.type === 'comma' || prior.type === 'brace');
	      const isExtglob = extglobs.length && (prior.type === 'pipe' || prior.type === 'paren');
	      if (!isStart && prior.type !== 'paren' && !isBrace && !isExtglob) {
	        push({ type: 'star', value, output: '' });
	        continue;
	      }

	      // strip consecutive `/**/`
	      while (rest.slice(0, 3) === '/**') {
	        const after = input[state.index + 4];
	        if (after && after !== '/') {
	          break;
	        }
	        rest = rest.slice(3);
	        consume('/**', 3);
	      }

	      if (prior.type === 'bos' && eos()) {
	        prev.type = 'globstar';
	        prev.value += value;
	        prev.output = globstar(opts);
	        state.output = prev.output;
	        state.globstar = true;
	        consume(value);
	        continue;
	      }

	      if (prior.type === 'slash' && prior.prev.type !== 'bos' && !afterStar && eos()) {
	        state.output = state.output.slice(0, -(prior.output + prev.output).length);
	        prior.output = `(?:${prior.output}`;

	        prev.type = 'globstar';
	        prev.output = globstar(opts) + (opts.strictSlashes ? ')' : '|$)');
	        prev.value += value;
	        state.globstar = true;
	        state.output += prior.output + prev.output;
	        consume(value);
	        continue;
	      }

	      if (prior.type === 'slash' && prior.prev.type !== 'bos' && rest[0] === '/') {
	        const end = rest[1] !== void 0 ? '|$' : '';

	        state.output = state.output.slice(0, -(prior.output + prev.output).length);
	        prior.output = `(?:${prior.output}`;

	        prev.type = 'globstar';
	        prev.output = `${globstar(opts)}${SLASH_LITERAL}|${SLASH_LITERAL}${end})`;
	        prev.value += value;

	        state.output += prior.output + prev.output;
	        state.globstar = true;

	        consume(value + advance());

	        push({ type: 'slash', value: '/', output: '' });
	        continue;
	      }

	      if (prior.type === 'bos' && rest[0] === '/') {
	        prev.type = 'globstar';
	        prev.value += value;
	        prev.output = `(?:^|${SLASH_LITERAL}|${globstar(opts)}${SLASH_LITERAL})`;
	        state.output = prev.output;
	        state.globstar = true;
	        consume(value + advance());
	        push({ type: 'slash', value: '/', output: '' });
	        continue;
	      }

	      // remove single star from output
	      state.output = state.output.slice(0, -prev.output.length);

	      // reset previous token to globstar
	      prev.type = 'globstar';
	      prev.output = globstar(opts);
	      prev.value += value;

	      // reset output with globstar
	      state.output += prev.output;
	      state.globstar = true;
	      consume(value);
	      continue;
	    }

	    const token = { type: 'star', value, output: star };

	    if (opts.bash === true) {
	      token.output = '.*?';
	      if (prev.type === 'bos' || prev.type === 'slash') {
	        token.output = nodot + token.output;
	      }
	      push(token);
	      continue;
	    }

	    if (prev && (prev.type === 'bracket' || prev.type === 'paren') && opts.regex === true) {
	      token.output = value;
	      push(token);
	      continue;
	    }

	    if (state.index === state.start || prev.type === 'slash' || prev.type === 'dot') {
	      if (prev.type === 'dot') {
	        state.output += NO_DOT_SLASH;
	        prev.output += NO_DOT_SLASH;

	      } else if (opts.dot === true) {
	        state.output += NO_DOTS_SLASH;
	        prev.output += NO_DOTS_SLASH;

	      } else {
	        state.output += nodot;
	        prev.output += nodot;
	      }

	      if (peek() !== '*') {
	        state.output += ONE_CHAR;
	        prev.output += ONE_CHAR;
	      }
	    }

	    push(token);
	  }

	  while (state.brackets > 0) {
	    if (opts.strictBrackets === true) throw new SyntaxError(syntaxError('closing', ']'));
	    state.output = utils.escapeLast(state.output, '[');
	    decrement('brackets');
	  }

	  while (state.parens > 0) {
	    if (opts.strictBrackets === true) throw new SyntaxError(syntaxError('closing', ')'));
	    state.output = utils.escapeLast(state.output, '(');
	    decrement('parens');
	  }

	  while (state.braces > 0) {
	    if (opts.strictBrackets === true) throw new SyntaxError(syntaxError('closing', '}'));
	    state.output = utils.escapeLast(state.output, '{');
	    decrement('braces');
	  }

	  if (opts.strictSlashes !== true && (prev.type === 'star' || prev.type === 'bracket')) {
	    push({ type: 'maybe_slash', value: '', output: `${SLASH_LITERAL}?` });
	  }

	  // rebuild the output if we had to backtrack at any point
	  if (state.backtrack === true) {
	    state.output = '';

	    for (const token of state.tokens) {
	      state.output += token.output != null ? token.output : token.value;

	      if (token.suffix) {
	        state.output += token.suffix;
	      }
	    }
	  }

	  return state;
	};

	/**
	 * Fast paths for creating regular expressions for common glob patterns.
	 * This can significantly speed up processing and has very little downside
	 * impact when none of the fast paths match.
	 */

	parse.fastpaths = (input, options) => {
	  const opts = { ...options };
	  const max = typeof opts.maxLength === 'number' ? Math.min(MAX_LENGTH, opts.maxLength) : MAX_LENGTH;
	  const len = input.length;
	  if (len > max) {
	    throw new SyntaxError(`Input length: ${len}, exceeds maximum allowed length: ${max}`);
	  }

	  input = REPLACEMENTS[input] || input;

	  // create constants based on platform, for windows or posix
	  const {
	    DOT_LITERAL,
	    SLASH_LITERAL,
	    ONE_CHAR,
	    DOTS_SLASH,
	    NO_DOT,
	    NO_DOTS,
	    NO_DOTS_SLASH,
	    STAR,
	    START_ANCHOR
	  } = constants.globChars(opts.windows);

	  const nodot = opts.dot ? NO_DOTS : NO_DOT;
	  const slashDot = opts.dot ? NO_DOTS_SLASH : NO_DOT;
	  const capture = opts.capture ? '' : '?:';
	  const state = { negated: false, prefix: '' };
	  let star = opts.bash === true ? '.*?' : STAR;

	  if (opts.capture) {
	    star = `(${star})`;
	  }

	  const globstar = opts => {
	    if (opts.noglobstar === true) return star;
	    return `(${capture}(?:(?!${START_ANCHOR}${opts.dot ? DOTS_SLASH : DOT_LITERAL}).)*?)`;
	  };

	  const create = str => {
	    switch (str) {
	      case '*':
	        return `${nodot}${ONE_CHAR}${star}`;

	      case '.*':
	        return `${DOT_LITERAL}${ONE_CHAR}${star}`;

	      case '*.*':
	        return `${nodot}${star}${DOT_LITERAL}${ONE_CHAR}${star}`;

	      case '*/*':
	        return `${nodot}${star}${SLASH_LITERAL}${ONE_CHAR}${slashDot}${star}`;

	      case '**':
	        return nodot + globstar(opts);

	      case '**/*':
	        return `(?:${nodot}${globstar(opts)}${SLASH_LITERAL})?${slashDot}${ONE_CHAR}${star}`;

	      case '**/*.*':
	        return `(?:${nodot}${globstar(opts)}${SLASH_LITERAL})?${slashDot}${star}${DOT_LITERAL}${ONE_CHAR}${star}`;

	      case '**/.*':
	        return `(?:${nodot}${globstar(opts)}${SLASH_LITERAL})?${DOT_LITERAL}${ONE_CHAR}${star}`;

	      default: {
	        const match = /^(.*?)\.(\w+)$/.exec(str);
	        if (!match) return;

	        const source = create(match[1]);
	        if (!source) return;

	        return source + DOT_LITERAL + match[2];
	      }
	    }
	  };

	  const output = utils.removePrefix(input, state);
	  let source = create(output);

	  if (source && opts.strictSlashes !== true) {
	    source += `${SLASH_LITERAL}?`;
	  }

	  return source;
	};

	parse_1$1 = parse;
	return parse_1$1;
}

var picomatch_1$1;
var hasRequiredPicomatch$1;

function requirePicomatch$1 () {
	if (hasRequiredPicomatch$1) return picomatch_1$1;
	hasRequiredPicomatch$1 = 1;

	const scan = requireScan();
	const parse = requireParse$2();
	const utils = requireUtils$2();
	const constants = requireConstants();
	const isObject = val => val && typeof val === 'object' && !Array.isArray(val);

	/**
	 * Creates a matcher function from one or more glob patterns. The
	 * returned function takes a string to match as its first argument,
	 * and returns true if the string is a match. The returned matcher
	 * function also takes a boolean as the second argument that, when true,
	 * returns an object with additional information.
	 *
	 * ```js
	 * const picomatch = require('picomatch');
	 * // picomatch(glob[, options]);
	 *
	 * const isMatch = picomatch('*.!(*a)');
	 * console.log(isMatch('a.a')); //=> false
	 * console.log(isMatch('a.b')); //=> true
	 * ```
	 * @name picomatch
	 * @param {String|Array} `globs` One or more glob patterns.
	 * @param {Object=} `options`
	 * @return {Function=} Returns a matcher function.
	 * @api public
	 */

	const picomatch = (glob, options, returnState = false) => {
	  if (Array.isArray(glob)) {
	    const fns = glob.map(input => picomatch(input, options, returnState));
	    const arrayMatcher = str => {
	      for (const isMatch of fns) {
	        const state = isMatch(str);
	        if (state) return state;
	      }
	      return false;
	    };
	    return arrayMatcher;
	  }

	  const isState = isObject(glob) && glob.tokens && glob.input;

	  if (glob === '' || (typeof glob !== 'string' && !isState)) {
	    throw new TypeError('Expected pattern to be a non-empty string');
	  }

	  const opts = options || {};
	  const posix = opts.windows;
	  const regex = isState
	    ? picomatch.compileRe(glob, options)
	    : picomatch.makeRe(glob, options, false, true);

	  const state = regex.state;
	  delete regex.state;

	  let isIgnored = () => false;
	  if (opts.ignore) {
	    const ignoreOpts = { ...options, ignore: null, onMatch: null, onResult: null };
	    isIgnored = picomatch(opts.ignore, ignoreOpts, returnState);
	  }

	  const matcher = (input, returnObject = false) => {
	    const { isMatch, match, output } = picomatch.test(input, regex, options, { glob, posix });
	    const result = { glob, state, regex, posix, input, output, match, isMatch };

	    if (typeof opts.onResult === 'function') {
	      opts.onResult(result);
	    }

	    if (isMatch === false) {
	      result.isMatch = false;
	      return returnObject ? result : false;
	    }

	    if (isIgnored(input)) {
	      if (typeof opts.onIgnore === 'function') {
	        opts.onIgnore(result);
	      }
	      result.isMatch = false;
	      return returnObject ? result : false;
	    }

	    if (typeof opts.onMatch === 'function') {
	      opts.onMatch(result);
	    }
	    return returnObject ? result : true;
	  };

	  if (returnState) {
	    matcher.state = state;
	  }

	  return matcher;
	};

	/**
	 * Test `input` with the given `regex`. This is used by the main
	 * `picomatch()` function to test the input string.
	 *
	 * ```js
	 * const picomatch = require('picomatch');
	 * // picomatch.test(input, regex[, options]);
	 *
	 * console.log(picomatch.test('foo/bar', /^(?:([^/]*?)\/([^/]*?))$/));
	 * // { isMatch: true, match: [ 'foo/', 'foo', 'bar' ], output: 'foo/bar' }
	 * ```
	 * @param {String} `input` String to test.
	 * @param {RegExp} `regex`
	 * @return {Object} Returns an object with matching info.
	 * @api public
	 */

	picomatch.test = (input, regex, options, { glob, posix } = {}) => {
	  if (typeof input !== 'string') {
	    throw new TypeError('Expected input to be a string');
	  }

	  if (input === '') {
	    return { isMatch: false, output: '' };
	  }

	  const opts = options || {};
	  const format = opts.format || (posix ? utils.toPosixSlashes : null);
	  let match = input === glob;
	  let output = (match && format) ? format(input) : input;

	  if (match === false) {
	    output = format ? format(input) : input;
	    match = output === glob;
	  }

	  if (match === false || opts.capture === true) {
	    if (opts.matchBase === true || opts.basename === true) {
	      match = picomatch.matchBase(input, regex, options, posix);
	    } else {
	      match = regex.exec(output);
	    }
	  }

	  return { isMatch: Boolean(match), match, output };
	};

	/**
	 * Match the basename of a filepath.
	 *
	 * ```js
	 * const picomatch = require('picomatch');
	 * // picomatch.matchBase(input, glob[, options]);
	 * console.log(picomatch.matchBase('foo/bar.js', '*.js'); // true
	 * ```
	 * @param {String} `input` String to test.
	 * @param {RegExp|String} `glob` Glob pattern or regex created by [.makeRe](#makeRe).
	 * @return {Boolean}
	 * @api public
	 */

	picomatch.matchBase = (input, glob, options) => {
	  const regex = glob instanceof RegExp ? glob : picomatch.makeRe(glob, options);
	  return regex.test(utils.basename(input));
	};

	/**
	 * Returns true if **any** of the given glob `patterns` match the specified `string`.
	 *
	 * ```js
	 * const picomatch = require('picomatch');
	 * // picomatch.isMatch(string, patterns[, options]);
	 *
	 * console.log(picomatch.isMatch('a.a', ['b.*', '*.a'])); //=> true
	 * console.log(picomatch.isMatch('a.a', 'b.*')); //=> false
	 * ```
	 * @param {String|Array} str The string to test.
	 * @param {String|Array} patterns One or more glob patterns to use for matching.
	 * @param {Object} [options] See available [options](#options).
	 * @return {Boolean} Returns true if any patterns match `str`
	 * @api public
	 */

	picomatch.isMatch = (str, patterns, options) => picomatch(patterns, options)(str);

	/**
	 * Parse a glob pattern to create the source string for a regular
	 * expression.
	 *
	 * ```js
	 * const picomatch = require('picomatch');
	 * const result = picomatch.parse(pattern[, options]);
	 * ```
	 * @param {String} `pattern`
	 * @param {Object} `options`
	 * @return {Object} Returns an object with useful properties and output to be used as a regex source string.
	 * @api public
	 */

	picomatch.parse = (pattern, options) => {
	  if (Array.isArray(pattern)) return pattern.map(p => picomatch.parse(p, options));
	  return parse(pattern, { ...options, fastpaths: false });
	};

	/**
	 * Scan a glob pattern to separate the pattern into segments.
	 *
	 * ```js
	 * const picomatch = require('picomatch');
	 * // picomatch.scan(input[, options]);
	 *
	 * const result = picomatch.scan('!./foo/*.js');
	 * console.log(result);
	 * { prefix: '!./',
	 *   input: '!./foo/*.js',
	 *   start: 3,
	 *   base: 'foo',
	 *   glob: '*.js',
	 *   isBrace: false,
	 *   isBracket: false,
	 *   isGlob: true,
	 *   isExtglob: false,
	 *   isGlobstar: false,
	 *   negated: true }
	 * ```
	 * @param {String} `input` Glob pattern to scan.
	 * @param {Object} `options`
	 * @return {Object} Returns an object with
	 * @api public
	 */

	picomatch.scan = (input, options) => scan(input, options);

	/**
	 * Compile a regular expression from the `state` object returned by the
	 * [parse()](#parse) method.
	 *
	 * @param {Object} `state`
	 * @param {Object} `options`
	 * @param {Boolean} `returnOutput` Intended for implementors, this argument allows you to return the raw output from the parser.
	 * @param {Boolean} `returnState` Adds the state to a `state` property on the returned regex. Useful for implementors and debugging.
	 * @return {RegExp}
	 * @api public
	 */

	picomatch.compileRe = (state, options, returnOutput = false, returnState = false) => {
	  if (returnOutput === true) {
	    return state.output;
	  }

	  const opts = options || {};
	  const prepend = opts.contains ? '' : '^';
	  const append = opts.contains ? '' : '$';

	  let source = `${prepend}(?:${state.output})${append}`;
	  if (state && state.negated === true) {
	    source = `^(?!${source}).*$`;
	  }

	  const regex = picomatch.toRegex(source, options);
	  if (returnState === true) {
	    regex.state = state;
	  }

	  return regex;
	};

	/**
	 * Create a regular expression from a parsed glob pattern.
	 *
	 * ```js
	 * const picomatch = require('picomatch');
	 * const state = picomatch.parse('*.js');
	 * // picomatch.compileRe(state[, options]);
	 *
	 * console.log(picomatch.compileRe(state));
	 * //=> /^(?:(?!\.)(?=.)[^/]*?\.js)$/
	 * ```
	 * @param {String} `state` The object returned from the `.parse` method.
	 * @param {Object} `options`
	 * @param {Boolean} `returnOutput` Implementors may use this argument to return the compiled output, instead of a regular expression. This is not exposed on the options to prevent end-users from mutating the result.
	 * @param {Boolean} `returnState` Implementors may use this argument to return the state from the parsed glob with the returned regular expression.
	 * @return {RegExp} Returns a regex created from the given pattern.
	 * @api public
	 */

	picomatch.makeRe = (input, options = {}, returnOutput = false, returnState = false) => {
	  if (!input || typeof input !== 'string') {
	    throw new TypeError('Expected a non-empty string');
	  }

	  let parsed = { negated: false, fastpaths: true };

	  if (options.fastpaths !== false && (input[0] === '.' || input[0] === '*')) {
	    parsed.output = parse.fastpaths(input, options);
	  }

	  if (!parsed.output) {
	    parsed = parse(input, options);
	  }

	  return picomatch.compileRe(parsed, options, returnOutput, returnState);
	};

	/**
	 * Create a regular expression from the given regex source string.
	 *
	 * ```js
	 * const picomatch = require('picomatch');
	 * // picomatch.toRegex(source[, options]);
	 *
	 * const { output } = picomatch.parse('*.js');
	 * console.log(picomatch.toRegex(output));
	 * //=> /^(?:(?!\.)(?=.)[^/]*?\.js)$/
	 * ```
	 * @param {String} `source` Regular expression source string.
	 * @param {Object} `options`
	 * @return {RegExp}
	 * @api public
	 */

	picomatch.toRegex = (source, options) => {
	  try {
	    const opts = options || {};
	    return new RegExp(source, opts.flags || (opts.nocase ? 'i' : ''));
	  } catch (err) {
	    if (options && options.debug === true) throw err;
	    return /$^/;
	  }
	};

	/**
	 * Picomatch constants.
	 * @return {Object}
	 */

	picomatch.constants = constants;

	/**
	 * Expose "picomatch"
	 */

	picomatch_1$1 = picomatch;
	return picomatch_1$1;
}

var picomatch_1;
var hasRequiredPicomatch;

function requirePicomatch () {
	if (hasRequiredPicomatch) return picomatch_1;
	hasRequiredPicomatch = 1;

	const pico = requirePicomatch$1();
	const utils = requireUtils$2();

	function picomatch(glob, options, returnState = false) {
	  // default to os.platform()
	  if (options && (options.windows === null || options.windows === undefined)) {
	    // don't mutate the original options object
	    options = { ...options, windows: utils.isWindows() };
	  }

	  return pico(glob, options, returnState);
	}

	Object.assign(picomatch, pico);
	picomatch_1 = picomatch;
	return picomatch_1;
}

var picomatchExports = /*@__PURE__*/ requirePicomatch();
var pm$1 = /*@__PURE__*/getDefaultExportFromCjs(picomatchExports);

//#region rolldown:runtime
var __require = /* @__PURE__ */ createRequire$1(import.meta.url);

//#endregion
//#region src/utils.ts
function cleanPath(path) {
	let normalized = normalize$3(path);
	if (normalized.length > 1 && normalized[normalized.length - 1] === sep$1) normalized = normalized.substring(0, normalized.length - 1);
	return normalized;
}
const SLASHES_REGEX = /[\\/]/g;
function convertSlashes(path, separator) {
	return path.replace(SLASHES_REGEX, separator);
}
const WINDOWS_ROOT_DIR_REGEX = /^[a-z]:[\\/]$/i;
function isRootDirectory(path) {
	return path === "/" || WINDOWS_ROOT_DIR_REGEX.test(path);
}
function normalizePath(path, options) {
	const { resolvePaths, normalizePath: normalizePath$1, pathSeparator } = options;
	const pathNeedsCleaning = process.platform === "win32" && path.includes("/") || path.startsWith(".");
	if (resolvePaths) path = resolve$1(path);
	if (normalizePath$1 || pathNeedsCleaning) path = cleanPath(path);
	if (path === ".") return "";
	const needsSeperator = path[path.length - 1] !== pathSeparator;
	return convertSlashes(needsSeperator ? path + pathSeparator : path, pathSeparator);
}

//#endregion
//#region src/api/functions/join-path.ts
function joinPathWithBasePath(filename, directoryPath) {
	return directoryPath + filename;
}
function joinPathWithRelativePath(root, options) {
	return function(filename, directoryPath) {
		const sameRoot = directoryPath.startsWith(root);
		if (sameRoot) return directoryPath.slice(root.length) + filename;
		else return convertSlashes(relative(root, directoryPath), options.pathSeparator) + options.pathSeparator + filename;
	};
}
function joinPath(filename) {
	return filename;
}
function joinDirectoryPath(filename, directoryPath, separator) {
	return directoryPath + filename + separator;
}
function build$7(root, options) {
	const { relativePaths, includeBasePath } = options;
	return relativePaths && root ? joinPathWithRelativePath(root, options) : includeBasePath ? joinPathWithBasePath : joinPath;
}

//#endregion
//#region src/api/functions/push-directory.ts
function pushDirectoryWithRelativePath(root) {
	return function(directoryPath, paths) {
		paths.push(directoryPath.substring(root.length) || ".");
	};
}
function pushDirectoryFilterWithRelativePath(root) {
	return function(directoryPath, paths, filters) {
		const relativePath = directoryPath.substring(root.length) || ".";
		if (filters.every((filter) => filter(relativePath, true))) paths.push(relativePath);
	};
}
const pushDirectory = (directoryPath, paths) => {
	paths.push(directoryPath || ".");
};
const pushDirectoryFilter = (directoryPath, paths, filters) => {
	const path = directoryPath || ".";
	if (filters.every((filter) => filter(path, true))) paths.push(path);
};
const empty$2 = () => {};
function build$6(root, options) {
	const { includeDirs, filters, relativePaths } = options;
	if (!includeDirs) return empty$2;
	if (relativePaths) return filters && filters.length ? pushDirectoryFilterWithRelativePath(root) : pushDirectoryWithRelativePath(root);
	return filters && filters.length ? pushDirectoryFilter : pushDirectory;
}

//#endregion
//#region src/api/functions/push-file.ts
const pushFileFilterAndCount = (filename, _paths, counts, filters) => {
	if (filters.every((filter) => filter(filename, false))) counts.files++;
};
const pushFileFilter = (filename, paths, _counts, filters) => {
	if (filters.every((filter) => filter(filename, false))) paths.push(filename);
};
const pushFileCount = (_filename, _paths, counts, _filters) => {
	counts.files++;
};
const pushFile = (filename, paths) => {
	paths.push(filename);
};
const empty$1 = () => {};
function build$5(options) {
	const { excludeFiles, filters, onlyCounts } = options;
	if (excludeFiles) return empty$1;
	if (filters && filters.length) return onlyCounts ? pushFileFilterAndCount : pushFileFilter;
	else if (onlyCounts) return pushFileCount;
	else return pushFile;
}

//#endregion
//#region src/api/functions/get-array.ts
const getArray = (paths) => {
	return paths;
};
const getArrayGroup = () => {
	return [""].slice(0, 0);
};
function build$4(options) {
	return options.group ? getArrayGroup : getArray;
}

//#endregion
//#region src/api/functions/group-files.ts
const groupFiles = (groups, directory, files) => {
	groups.push({
		directory,
		files,
		dir: directory
	});
};
const empty = () => {};
function build$3(options) {
	return options.group ? groupFiles : empty;
}

//#endregion
//#region src/api/functions/resolve-symlink.ts
const resolveSymlinksAsync = function(path, state, callback$1) {
	const { queue, fs, options: { suppressErrors } } = state;
	queue.enqueue();
	fs.realpath(path, (error, resolvedPath) => {
		if (error) return queue.dequeue(suppressErrors ? null : error, state);
		fs.stat(resolvedPath, (error$1, stat) => {
			if (error$1) return queue.dequeue(suppressErrors ? null : error$1, state);
			if (stat.isDirectory() && isRecursive(path, resolvedPath, state)) return queue.dequeue(null, state);
			callback$1(stat, resolvedPath);
			queue.dequeue(null, state);
		});
	});
};
const resolveSymlinks = function(path, state, callback$1) {
	const { queue, fs, options: { suppressErrors } } = state;
	queue.enqueue();
	try {
		const resolvedPath = fs.realpathSync(path);
		const stat = fs.statSync(resolvedPath);
		if (stat.isDirectory() && isRecursive(path, resolvedPath, state)) return;
		callback$1(stat, resolvedPath);
	} catch (e) {
		if (!suppressErrors) throw e;
	}
};
function build$2(options, isSynchronous) {
	if (!options.resolveSymlinks || options.excludeSymlinks) return null;
	return isSynchronous ? resolveSymlinks : resolveSymlinksAsync;
}
function isRecursive(path, resolved, state) {
	if (state.options.useRealPaths) return isRecursiveUsingRealPaths(resolved, state);
	let parent = dirname(path);
	let depth = 1;
	while (parent !== state.root && depth < 2) {
		const resolvedPath = state.symlinks.get(parent);
		const isSameRoot = !!resolvedPath && (resolvedPath === resolved || resolvedPath.startsWith(resolved) || resolved.startsWith(resolvedPath));
		if (isSameRoot) depth++;
		else parent = dirname(parent);
	}
	state.symlinks.set(path, resolved);
	return depth > 1;
}
function isRecursiveUsingRealPaths(resolved, state) {
	return state.visited.includes(resolved + state.options.pathSeparator);
}

//#endregion
//#region src/api/functions/invoke-callback.ts
const onlyCountsSync = (state) => {
	return state.counts;
};
const groupsSync = (state) => {
	return state.groups;
};
const defaultSync = (state) => {
	return state.paths;
};
const limitFilesSync = (state) => {
	return state.paths.slice(0, state.options.maxFiles);
};
const onlyCountsAsync = (state, error, callback$1) => {
	report(error, callback$1, state.counts, state.options.suppressErrors);
	return null;
};
const defaultAsync = (state, error, callback$1) => {
	report(error, callback$1, state.paths, state.options.suppressErrors);
	return null;
};
const limitFilesAsync = (state, error, callback$1) => {
	report(error, callback$1, state.paths.slice(0, state.options.maxFiles), state.options.suppressErrors);
	return null;
};
const groupsAsync = (state, error, callback$1) => {
	report(error, callback$1, state.groups, state.options.suppressErrors);
	return null;
};
function report(error, callback$1, output, suppressErrors) {
	if (error && !suppressErrors) callback$1(error, output);
	else callback$1(null, output);
}
function build$1(options, isSynchronous) {
	const { onlyCounts, group, maxFiles } = options;
	if (onlyCounts) return isSynchronous ? onlyCountsSync : onlyCountsAsync;
	else if (group) return isSynchronous ? groupsSync : groupsAsync;
	else if (maxFiles) return isSynchronous ? limitFilesSync : limitFilesAsync;
	else return isSynchronous ? defaultSync : defaultAsync;
}

//#endregion
//#region src/api/functions/walk-directory.ts
const readdirOpts = { withFileTypes: true };
const walkAsync = (state, crawlPath, directoryPath, currentDepth, callback$1) => {
	state.queue.enqueue();
	if (currentDepth < 0) return state.queue.dequeue(null, state);
	const { fs } = state;
	state.visited.push(crawlPath);
	state.counts.directories++;
	fs.readdir(crawlPath || ".", readdirOpts, (error, entries = []) => {
		callback$1(entries, directoryPath, currentDepth);
		state.queue.dequeue(state.options.suppressErrors ? null : error, state);
	});
};
const walkSync = (state, crawlPath, directoryPath, currentDepth, callback$1) => {
	const { fs } = state;
	if (currentDepth < 0) return;
	state.visited.push(crawlPath);
	state.counts.directories++;
	let entries = [];
	try {
		entries = fs.readdirSync(crawlPath || ".", readdirOpts);
	} catch (e) {
		if (!state.options.suppressErrors) throw e;
	}
	callback$1(entries, directoryPath, currentDepth);
};
function build$8(isSynchronous) {
	return isSynchronous ? walkSync : walkAsync;
}

//#endregion
//#region src/api/queue.ts
/**
* This is a custom stateless queue to track concurrent async fs calls.
* It increments a counter whenever a call is queued and decrements it
* as soon as it completes. When the counter hits 0, it calls onQueueEmpty.
*/
var Queue = class {
	count = 0;
	constructor(onQueueEmpty) {
		this.onQueueEmpty = onQueueEmpty;
	}
	enqueue() {
		this.count++;
		return this.count;
	}
	dequeue(error, output) {
		if (this.onQueueEmpty && (--this.count <= 0 || error)) {
			this.onQueueEmpty(error, output);
			if (error) {
				output.controller.abort();
				this.onQueueEmpty = void 0;
			}
		}
	}
};

//#endregion
//#region src/api/counter.ts
var Counter = class {
	_files = 0;
	_directories = 0;
	set files(num) {
		this._files = num;
	}
	get files() {
		return this._files;
	}
	set directories(num) {
		this._directories = num;
	}
	get directories() {
		return this._directories;
	}
	/**
	* @deprecated use `directories` instead
	*/
	/* c8 ignore next 3 */
	get dirs() {
		return this._directories;
	}
};

//#endregion
//#region src/api/aborter.ts
/**
* AbortController is not supported on Node 14 so we use this until we can drop
* support for Node 14.
*/
var Aborter = class {
	aborted = false;
	abort() {
		this.aborted = true;
	}
};

//#endregion
//#region src/api/walker.ts
var Walker = class {
	root;
	isSynchronous;
	state;
	joinPath;
	pushDirectory;
	pushFile;
	getArray;
	groupFiles;
	resolveSymlink;
	walkDirectory;
	callbackInvoker;
	constructor(root, options, callback$1) {
		this.isSynchronous = !callback$1;
		this.callbackInvoker = build$1(options, this.isSynchronous);
		this.root = normalizePath(root, options);
		this.state = {
			root: isRootDirectory(this.root) ? this.root : this.root.slice(0, -1),
			paths: [""].slice(0, 0),
			groups: [],
			counts: new Counter(),
			options,
			queue: new Queue((error, state) => this.callbackInvoker(state, error, callback$1)),
			symlinks: /* @__PURE__ */ new Map(),
			visited: [""].slice(0, 0),
			controller: new Aborter(),
			fs: options.fs || nativeFs
		};
		this.joinPath = build$7(this.root, options);
		this.pushDirectory = build$6(this.root, options);
		this.pushFile = build$5(options);
		this.getArray = build$4(options);
		this.groupFiles = build$3(options);
		this.resolveSymlink = build$2(options, this.isSynchronous);
		this.walkDirectory = build$8(this.isSynchronous);
	}
	start() {
		this.pushDirectory(this.root, this.state.paths, this.state.options.filters);
		this.walkDirectory(this.state, this.root, this.root, this.state.options.maxDepth, this.walk);
		return this.isSynchronous ? this.callbackInvoker(this.state, null) : null;
	}
	walk = (entries, directoryPath, depth) => {
		const { paths, options: { filters, resolveSymlinks: resolveSymlinks$1, excludeSymlinks, exclude, maxFiles, signal, useRealPaths, pathSeparator }, controller } = this.state;
		if (controller.aborted || signal && signal.aborted || maxFiles && paths.length > maxFiles) return;
		const files = this.getArray(this.state.paths);
		for (let i = 0; i < entries.length; ++i) {
			const entry = entries[i];
			if (entry.isFile() || entry.isSymbolicLink() && !resolveSymlinks$1 && !excludeSymlinks) {
				const filename = this.joinPath(entry.name, directoryPath);
				this.pushFile(filename, files, this.state.counts, filters);
			} else if (entry.isDirectory()) {
				let path = joinDirectoryPath(entry.name, directoryPath, this.state.options.pathSeparator);
				if (exclude && exclude(entry.name, path)) continue;
				this.pushDirectory(path, paths, filters);
				this.walkDirectory(this.state, path, path, depth - 1, this.walk);
			} else if (this.resolveSymlink && entry.isSymbolicLink()) {
				let path = joinPathWithBasePath(entry.name, directoryPath);
				this.resolveSymlink(path, this.state, (stat, resolvedPath) => {
					if (stat.isDirectory()) {
						resolvedPath = normalizePath(resolvedPath, this.state.options);
						if (exclude && exclude(entry.name, useRealPaths ? resolvedPath : path + pathSeparator)) return;
						this.walkDirectory(this.state, resolvedPath, useRealPaths ? resolvedPath : path + pathSeparator, depth - 1, this.walk);
					} else {
						resolvedPath = useRealPaths ? resolvedPath : path;
						const filename = basename(resolvedPath);
						const directoryPath$1 = normalizePath(dirname(resolvedPath), this.state.options);
						resolvedPath = this.joinPath(filename, directoryPath$1);
						this.pushFile(resolvedPath, files, this.state.counts, filters);
					}
				});
			}
		}
		this.groupFiles(this.state.groups, directoryPath, files);
	};
};

//#endregion
//#region src/api/async.ts
function promise(root, options) {
	return new Promise((resolve$1, reject) => {
		callback(root, options, (err, output) => {
			if (err) return reject(err);
			resolve$1(output);
		});
	});
}
function callback(root, options, callback$1) {
	let walker = new Walker(root, options, callback$1);
	walker.start();
}

//#endregion
//#region src/api/sync.ts
function sync(root, options) {
	const walker = new Walker(root, options);
	return walker.start();
}

//#endregion
//#region src/builder/api-builder.ts
var APIBuilder = class {
	constructor(root, options) {
		this.root = root;
		this.options = options;
	}
	withPromise() {
		return promise(this.root, this.options);
	}
	withCallback(cb) {
		callback(this.root, this.options, cb);
	}
	sync() {
		return sync(this.root, this.options);
	}
};

//#endregion
//#region src/builder/index.ts
let pm = null;
/* c8 ignore next 6 */
try {
	__require.resolve("picomatch");
	pm = __require("picomatch");
} catch {}
var Builder = class {
	globCache = {};
	options = {
		maxDepth: Infinity,
		suppressErrors: true,
		pathSeparator: sep$1,
		filters: []
	};
	globFunction;
	constructor(options) {
		this.options = {
			...this.options,
			...options
		};
		this.globFunction = this.options.globFunction;
	}
	group() {
		this.options.group = true;
		return this;
	}
	withPathSeparator(separator) {
		this.options.pathSeparator = separator;
		return this;
	}
	withBasePath() {
		this.options.includeBasePath = true;
		return this;
	}
	withRelativePaths() {
		this.options.relativePaths = true;
		return this;
	}
	withDirs() {
		this.options.includeDirs = true;
		return this;
	}
	withMaxDepth(depth) {
		this.options.maxDepth = depth;
		return this;
	}
	withMaxFiles(limit) {
		this.options.maxFiles = limit;
		return this;
	}
	withFullPaths() {
		this.options.resolvePaths = true;
		this.options.includeBasePath = true;
		return this;
	}
	withErrors() {
		this.options.suppressErrors = false;
		return this;
	}
	withSymlinks({ resolvePaths = true } = {}) {
		this.options.resolveSymlinks = true;
		this.options.useRealPaths = resolvePaths;
		return this.withFullPaths();
	}
	withAbortSignal(signal) {
		this.options.signal = signal;
		return this;
	}
	normalize() {
		this.options.normalizePath = true;
		return this;
	}
	filter(predicate) {
		this.options.filters.push(predicate);
		return this;
	}
	onlyDirs() {
		this.options.excludeFiles = true;
		this.options.includeDirs = true;
		return this;
	}
	exclude(predicate) {
		this.options.exclude = predicate;
		return this;
	}
	onlyCounts() {
		this.options.onlyCounts = true;
		return this;
	}
	crawl(root) {
		return new APIBuilder(root || ".", this.options);
	}
	withGlobFunction(fn) {
		this.globFunction = fn;
		return this;
	}
	/**
	* @deprecated Pass options using the constructor instead:
	* ```ts
	* new fdir(options).crawl("/path/to/root");
	* ```
	* This method will be removed in v7.0
	*/
	/* c8 ignore next 4 */
	crawlWithOptions(root, options) {
		this.options = {
			...this.options,
			...options
		};
		return new APIBuilder(root || ".", this.options);
	}
	glob(...patterns) {
		if (this.globFunction) return this.globWithOptions(patterns);
		return this.globWithOptions(patterns, ...[{ dot: true }]);
	}
	globWithOptions(patterns, ...options) {
		const globFn = this.globFunction || pm;
		/* c8 ignore next 5 */
		if (!globFn) throw new Error("Please specify a glob function to use glob matching.");
		var isMatch = this.globCache[patterns.join("\0")];
		if (!isMatch) {
			isMatch = globFn(patterns, ...options);
			this.globCache[patterns.join("\0")] = isMatch;
		}
		this.options.filters.push((path) => isMatch(path));
		return this;
	}
};

//#region src/utils.ts
const isReadonlyArray = Array.isArray;
const isWin = process.platform === "win32";
const ONLY_PARENT_DIRECTORIES = /^(\/?\.\.)+$/;
function getPartialMatcher(patterns, options = {}) {
	const patternsCount = patterns.length;
	const patternsParts = Array(patternsCount);
	const matchers = Array(patternsCount);
	const globstarEnabled = !options.noglobstar;
	for (let i = 0; i < patternsCount; i++) {
		const parts = splitPattern(patterns[i]);
		patternsParts[i] = parts;
		const partsCount = parts.length;
		const partMatchers = Array(partsCount);
		for (let j = 0; j < partsCount; j++) partMatchers[j] = pm$1(parts[j], options);
		matchers[i] = partMatchers;
	}
	return (input) => {
		const inputParts = input.split("/");
		if (inputParts[0] === ".." && ONLY_PARENT_DIRECTORIES.test(input)) return true;
		for (let i = 0; i < patterns.length; i++) {
			const patternParts = patternsParts[i];
			const matcher = matchers[i];
			const inputPatternCount = inputParts.length;
			const minParts = Math.min(inputPatternCount, patternParts.length);
			let j = 0;
			while (j < minParts) {
				const part = patternParts[j];
				if (part.includes("/")) return true;
				const match = matcher[j](inputParts[j]);
				if (!match) break;
				if (globstarEnabled && part === "**") return true;
				j++;
			}
			if (j === inputPatternCount) return true;
		}
		return false;
	};
}
/* node:coverage ignore next 2 */
const WIN32_ROOT_DIR = /^[A-Z]:\/$/i;
const isRoot = isWin ? (p) => WIN32_ROOT_DIR.test(p) : (p) => p === "/";
function buildFormat(cwd, root, absolute) {
	if (cwd === root || root.startsWith(`${cwd}/`)) {
		if (absolute) {
			const start = isRoot(cwd) ? cwd.length : cwd.length + 1;
			return (p, isDir) => p.slice(start, isDir ? -1 : void 0) || ".";
		}
		const prefix = root.slice(cwd.length + 1);
		if (prefix) return (p, isDir) => {
			if (p === ".") return prefix;
			const result = `${prefix}/${p}`;
			return isDir ? result.slice(0, -1) : result;
		};
		return (p, isDir) => isDir && p !== "." ? p.slice(0, -1) : p;
	}
	if (absolute) return (p) => posix$2.relative(cwd, p) || ".";
	return (p) => posix$2.relative(cwd, `${root}/${p}`) || ".";
}
function buildRelative(cwd, root) {
	if (root.startsWith(`${cwd}/`)) {
		const prefix = root.slice(cwd.length + 1);
		return (p) => `${prefix}/${p}`;
	}
	return (p) => {
		const result = posix$2.relative(cwd, `${root}/${p}`);
		if (p.endsWith("/") && result !== "") return `${result}/`;
		return result || ".";
	};
}
const splitPatternOptions = { parts: true };
function splitPattern(path$1) {
	var _result$parts;
	const result = pm$1.scan(path$1, splitPatternOptions);
	return ((_result$parts = result.parts) === null || _result$parts === void 0 ? void 0 : _result$parts.length) ? result.parts : [path$1];
}
const POSIX_UNESCAPED_GLOB_SYMBOLS = /(? path$1.replace(POSIX_UNESCAPED_GLOB_SYMBOLS, "\\$&");
const escapeWin32Path = (path$1) => path$1.replace(WIN32_UNESCAPED_GLOB_SYMBOLS, "\\$&");
/**
* Escapes a path's special characters depending on the platform.
* @see {@link https://superchupu.dev/tinyglobby/documentation#escapePath}
*/
/* node:coverage ignore next */
const escapePath = isWin ? escapeWin32Path : escapePosixPath;
/**
* Checks if a pattern has dynamic parts.
*
* Has a few minor differences with [`fast-glob`](https://github.com/mrmlnc/fast-glob) for better accuracy:
*
* - Doesn't necessarily return `false` on patterns that include `\`.
* - Returns `true` if the pattern includes parentheses, regardless of them representing one single pattern or not.
* - Returns `true` for unfinished glob extensions i.e. `(h`, `+(h`.
* - Returns `true` for unfinished brace expansions as long as they include `,` or `..`.
*
* @see {@link https://superchupu.dev/tinyglobby/documentation#isDynamicPattern}
*/
function isDynamicPattern(pattern, options) {
	const scan = pm$1.scan(pattern);
	return scan.isGlob || scan.negated;
}
function log(...tasks) {
	console.log(`[tinyglobby ${(/* @__PURE__ */ new Date()).toLocaleTimeString("es")}]`, ...tasks);
}

//#endregion
//#region src/index.ts
const PARENT_DIRECTORY = /^(\/?\.\.)+/;
const ESCAPING_BACKSLASHES = /\\(?=[()[\]{}!*+?@|])/g;
const BACKSLASHES = /\\/g;
function normalizePattern(pattern, expandDirectories, cwd, props, isIgnore) {
	let result = pattern;
	if (pattern.endsWith("/")) result = pattern.slice(0, -1);
	if (!result.endsWith("*") && expandDirectories) result += "/**";
	const escapedCwd = escapePath(cwd);
	if (require$$1$1.isAbsolute(result.replace(ESCAPING_BACKSLASHES, ""))) result = posix$2.relative(escapedCwd, result);
	else result = posix$2.normalize(result);
	const parentDirectoryMatch = PARENT_DIRECTORY.exec(result);
	const parts = splitPattern(result);
	if (parentDirectoryMatch === null || parentDirectoryMatch === void 0 ? void 0 : parentDirectoryMatch[0]) {
		const n = (parentDirectoryMatch[0].length + 1) / 3;
		let i = 0;
		const cwdParts = escapedCwd.split("/");
		while (i < n && parts[i + n] === cwdParts[cwdParts.length + i - n]) {
			result = result.slice(0, (n - i - 1) * 3) + result.slice((n - i) * 3 + parts[i + n].length + 1) || ".";
			i++;
		}
		const potentialRoot = posix$2.join(cwd, parentDirectoryMatch[0].slice(i * 3));
		if (!potentialRoot.startsWith(".") && props.root.length > potentialRoot.length) {
			props.root = potentialRoot;
			props.depthOffset = -n + i;
		}
	}
	if (!isIgnore && props.depthOffset >= 0) {
		var _props$commonPath;
		(_props$commonPath = props.commonPath) !== null && _props$commonPath !== void 0 || (props.commonPath = parts);
		const newCommonPath = [];
		const length = Math.min(props.commonPath.length, parts.length);
		for (let i = 0; i < length; i++) {
			const part = parts[i];
			if (part === "**" && !parts[i + 1]) {
				newCommonPath.pop();
				break;
			}
			if (part !== props.commonPath[i] || isDynamicPattern(part) || i === parts.length - 1) break;
			newCommonPath.push(part);
		}
		props.depthOffset = newCommonPath.length;
		props.commonPath = newCommonPath;
		props.root = newCommonPath.length > 0 ? posix$2.join(cwd, ...newCommonPath) : cwd;
	}
	return result;
}
function processPatterns({ patterns = ["**/*"], ignore = [], expandDirectories = true }, cwd, props) {
	if (typeof patterns === "string") patterns = [patterns];
	if (typeof ignore === "string") ignore = [ignore];
	const matchPatterns = [];
	const ignorePatterns = [];
	for (const pattern of ignore) {
		if (!pattern) continue;
		if (pattern[0] !== "!" || pattern[1] === "(") ignorePatterns.push(normalizePattern(pattern, expandDirectories, cwd, props, true));
	}
	for (const pattern of patterns) {
		if (!pattern) continue;
		if (pattern[0] !== "!" || pattern[1] === "(") matchPatterns.push(normalizePattern(pattern, expandDirectories, cwd, props, false));
		else if (pattern[1] !== "!" || pattern[2] === "(") ignorePatterns.push(normalizePattern(pattern.slice(1), expandDirectories, cwd, props, true));
	}
	return {
		match: matchPatterns,
		ignore: ignorePatterns
	};
}
function formatPaths(paths, relative) {
	for (let i = paths.length - 1; i >= 0; i--) {
		const path$1 = paths[i];
		paths[i] = relative(path$1);
	}
	return paths;
}
function normalizeCwd(cwd) {
	if (!cwd) return process.cwd().replace(BACKSLASHES, "/");
	if (cwd instanceof URL) return fileURLToPath$1(cwd).replace(BACKSLASHES, "/");
	return require$$1$1.resolve(cwd).replace(BACKSLASHES, "/");
}
function getCrawler(patterns, inputOptions = {}) {
	const options = process.env.TINYGLOBBY_DEBUG ? {
		...inputOptions,
		debug: true
	} : inputOptions;
	const cwd = normalizeCwd(options.cwd);
	if (options.debug) log("globbing with:", {
		patterns,
		options,
		cwd
	});
	if (Array.isArray(patterns) && patterns.length === 0) return [{
		sync: () => [],
		withPromise: async () => []
	}, false];
	const props = {
		root: cwd,
		commonPath: null,
		depthOffset: 0
	};
	const processed = processPatterns({
		...options,
		patterns
	}, cwd, props);
	if (options.debug) log("internal processing patterns:", processed);
	const matchOptions = {
		dot: options.dot,
		nobrace: options.braceExpansion === false,
		nocase: options.caseSensitiveMatch === false,
		noextglob: options.extglob === false,
		noglobstar: options.globstar === false,
		posix: true
	};
	const matcher = pm$1(processed.match, {
		...matchOptions,
		ignore: processed.ignore
	});
	const ignore = pm$1(processed.ignore, matchOptions);
	const partialMatcher = getPartialMatcher(processed.match, matchOptions);
	const format = buildFormat(cwd, props.root, options.absolute);
	const formatExclude = options.absolute ? format : buildFormat(cwd, props.root, true);
	const fdirOptions = {
		filters: [options.debug ? (p, isDirectory) => {
			const path$1 = format(p, isDirectory);
			const matches = matcher(path$1);
			if (matches) log(`matched ${path$1}`);
			return matches;
		} : (p, isDirectory) => matcher(format(p, isDirectory))],
		exclude: options.debug ? (_, p) => {
			const relativePath = formatExclude(p, true);
			const skipped = relativePath !== "." && !partialMatcher(relativePath) || ignore(relativePath);
			if (skipped) log(`skipped ${p}`);
			else log(`crawling ${p}`);
			return skipped;
		} : (_, p) => {
			const relativePath = formatExclude(p, true);
			return relativePath !== "." && !partialMatcher(relativePath) || ignore(relativePath);
		},
		fs: options.fs ? {
			readdir: options.fs.readdir || nativeFs__default.readdir,
			readdirSync: options.fs.readdirSync || nativeFs__default.readdirSync,
			realpath: options.fs.realpath || nativeFs__default.realpath,
			realpathSync: options.fs.realpathSync || nativeFs__default.realpathSync,
			stat: options.fs.stat || nativeFs__default.stat,
			statSync: options.fs.statSync || nativeFs__default.statSync
		} : void 0,
		pathSeparator: "/",
		relativePaths: true,
		resolveSymlinks: true,
		signal: options.signal
	};
	if (options.deep !== void 0) fdirOptions.maxDepth = Math.round(options.deep - props.depthOffset);
	if (options.absolute) {
		fdirOptions.relativePaths = false;
		fdirOptions.resolvePaths = true;
		fdirOptions.includeBasePath = true;
	}
	if (options.followSymbolicLinks === false) {
		fdirOptions.resolveSymlinks = false;
		fdirOptions.excludeSymlinks = true;
	}
	if (options.onlyDirectories) {
		fdirOptions.excludeFiles = true;
		fdirOptions.includeDirs = true;
	} else if (options.onlyFiles === false) fdirOptions.includeDirs = true;
	props.root = props.root.replace(BACKSLASHES, "");
	const root = props.root;
	if (options.debug) log("internal properties:", props);
	const relative = cwd !== root && !options.absolute && buildRelative(cwd, props.root);
	return [new Builder(fdirOptions).crawl(root), relative];
}
async function glob$1(patternsOrOptions, options) {
	if (patternsOrOptions && (options === null || options === void 0 ? void 0 : options.patterns)) throw new Error("Cannot pass patterns as both an argument and an option");
	const isModern = isReadonlyArray(patternsOrOptions) || typeof patternsOrOptions === "string";
	const opts = isModern ? options : patternsOrOptions;
	const patterns = isModern ? patternsOrOptions : patternsOrOptions.patterns;
	const [crawler, relative] = getCrawler(patterns, opts);
	if (!relative) return crawler.withPromise();
	return formatPaths(await crawler.withPromise(), relative);
}

function normalizeGlob(patterns, base) {
  if (!patterns) return [];
  if (typeof patterns === "string") patterns = [patterns];
  return patterns.map(
    (p) => p[0] === "!" ? "!" + normalizePath$1(path$1.resolve(base, p.slice(1))) : normalizePath$1(path$1.resolve(base, p))
  );
}
async function glob(patterns, options) {
  if (!patterns?.length) return [];
  return (await glob$1(patterns, {
    expandDirectories: false,
    ...options,
    ignore: ["**/node_modules/**", "**/dist/**", ...options?.ignore || []]
  })).sort();
}

class ModuleGraph {
  // Each module is tracked with its dependencies and dependents.
  nodes = /* @__PURE__ */ new Map();
  /**
   * Adds or updates a module by merging the provided dependencies
   * with any existing ones.
   *
   * For every new dependency, the module is added to that dependency's
   * 'dependents' set.
   *
   * @param module - The module to add or update.
   * @param dependencies - Array of module names that the module depends on.
   */
  add(module, dependencies) {
    if (!this.nodes.has(module)) {
      this.nodes.set(module, {
        dependencies: /* @__PURE__ */ new Set(),
        dependents: /* @__PURE__ */ new Set()
      });
    }
    const moduleNode = this.nodes.get(module);
    for (const dep of dependencies) {
      if (!moduleNode.dependencies.has(dep) && dep !== module) {
        moduleNode.dependencies.add(dep);
        if (!this.nodes.has(dep)) {
          this.nodes.set(dep, {
            dependencies: /* @__PURE__ */ new Set(),
            dependents: /* @__PURE__ */ new Set()
          });
        }
        this.nodes.get(dep).dependents.add(module);
      }
    }
  }
  /**
   * Deletes a module and all modules that (transitively) depend on it.
   *
   * This method performs a depth-first search from the target module,
   * collects all affected modules, and then removes them from the graph,
   * cleaning up their references from other nodes.
   *
   * @param module - The module to delete.
   * @returns A Set containing the deleted module and all modules that depend on it.
   */
  delete(module) {
    const deleted = /* @__PURE__ */ new Set();
    if (!this.nodes.has(module)) return deleted;
    const stack = [module];
    while (stack.length) {
      const current = stack.pop();
      if (!deleted.has(current)) {
        deleted.add(current);
        const node = this.nodes.get(current);
        if (node) {
          for (const dependent of node.dependents) {
            stack.push(dependent);
          }
        }
      }
    }
    for (const mod of deleted) {
      const node = this.nodes.get(mod);
      if (node) {
        for (const dep of node.dependencies) {
          const depNode = this.nodes.get(dep);
          if (depNode) {
            depNode.dependents.delete(mod);
          }
        }
      }
      this.nodes.delete(mod);
    }
    return deleted;
  }
  /**
   * Clears all modules from the graph.
   */
  clear() {
    this.nodes.clear();
  }
  /**
   * Creates a deep clone of the ModuleGraph instance.
   * This is useful for preserving the state of the graph
   * before making modifications.
   *
   * @returns A new ModuleGraph instance with the same state as the original.
   */
  clone() {
    const clone = new ModuleGraph();
    for (const [module, { dependencies, dependents }] of this.nodes) {
      clone.nodes.set(module, {
        dependencies: new Set(dependencies),
        dependents: new Set(dependents)
      });
    }
    return clone;
  }
}

/**
 * Tokenize input string.
 */
function lexer(str) {
    var tokens = [];
    var i = 0;
    while (i < str.length) {
        var char = str[i];
        if (char === "*" || char === "+" || char === "?") {
            tokens.push({ type: "MODIFIER", index: i, value: str[i++] });
            continue;
        }
        if (char === "\\") {
            tokens.push({ type: "ESCAPED_CHAR", index: i++, value: str[i++] });
            continue;
        }
        if (char === "{") {
            tokens.push({ type: "OPEN", index: i, value: str[i++] });
            continue;
        }
        if (char === "}") {
            tokens.push({ type: "CLOSE", index: i, value: str[i++] });
            continue;
        }
        if (char === ":") {
            var name = "";
            var j = i + 1;
            while (j < str.length) {
                var code = str.charCodeAt(j);
                if (
                // `0-9`
                (code >= 48 && code <= 57) ||
                    // `A-Z`
                    (code >= 65 && code <= 90) ||
                    // `a-z`
                    (code >= 97 && code <= 122) ||
                    // `_`
                    code === 95) {
                    name += str[j++];
                    continue;
                }
                break;
            }
            if (!name)
                throw new TypeError("Missing parameter name at ".concat(i));
            tokens.push({ type: "NAME", index: i, value: name });
            i = j;
            continue;
        }
        if (char === "(") {
            var count = 1;
            var pattern = "";
            var j = i + 1;
            if (str[j] === "?") {
                throw new TypeError("Pattern cannot start with \"?\" at ".concat(j));
            }
            while (j < str.length) {
                if (str[j] === "\\") {
                    pattern += str[j++] + str[j++];
                    continue;
                }
                if (str[j] === ")") {
                    count--;
                    if (count === 0) {
                        j++;
                        break;
                    }
                }
                else if (str[j] === "(") {
                    count++;
                    if (str[j + 1] !== "?") {
                        throw new TypeError("Capturing groups are not allowed at ".concat(j));
                    }
                }
                pattern += str[j++];
            }
            if (count)
                throw new TypeError("Unbalanced pattern at ".concat(i));
            if (!pattern)
                throw new TypeError("Missing pattern at ".concat(i));
            tokens.push({ type: "PATTERN", index: i, value: pattern });
            i = j;
            continue;
        }
        tokens.push({ type: "CHAR", index: i, value: str[i++] });
    }
    tokens.push({ type: "END", index: i, value: "" });
    return tokens;
}
/**
 * Parse a string for the raw tokens.
 */
function parse$3(str, options) {
    if (options === void 0) { options = {}; }
    var tokens = lexer(str);
    var _a = options.prefixes, prefixes = _a === void 0 ? "./" : _a, _b = options.delimiter, delimiter = _b === void 0 ? "/#?" : _b;
    var result = [];
    var key = 0;
    var i = 0;
    var path = "";
    var tryConsume = function (type) {
        if (i < tokens.length && tokens[i].type === type)
            return tokens[i++].value;
    };
    var mustConsume = function (type) {
        var value = tryConsume(type);
        if (value !== undefined)
            return value;
        var _a = tokens[i], nextType = _a.type, index = _a.index;
        throw new TypeError("Unexpected ".concat(nextType, " at ").concat(index, ", expected ").concat(type));
    };
    var consumeText = function () {
        var result = "";
        var value;
        while ((value = tryConsume("CHAR") || tryConsume("ESCAPED_CHAR"))) {
            result += value;
        }
        return result;
    };
    var isSafe = function (value) {
        for (var _i = 0, delimiter_1 = delimiter; _i < delimiter_1.length; _i++) {
            var char = delimiter_1[_i];
            if (value.indexOf(char) > -1)
                return true;
        }
        return false;
    };
    var safePattern = function (prefix) {
        var prev = result[result.length - 1];
        var prevText = prefix || (prev && typeof prev === "string" ? prev : "");
        if (prev && !prevText) {
            throw new TypeError("Must have text between two parameters, missing text after \"".concat(prev.name, "\""));
        }
        if (!prevText || isSafe(prevText))
            return "[^".concat(escapeString(delimiter), "]+?");
        return "(?:(?!".concat(escapeString(prevText), ")[^").concat(escapeString(delimiter), "])+?");
    };
    while (i < tokens.length) {
        var char = tryConsume("CHAR");
        var name = tryConsume("NAME");
        var pattern = tryConsume("PATTERN");
        if (name || pattern) {
            var prefix = char || "";
            if (prefixes.indexOf(prefix) === -1) {
                path += prefix;
                prefix = "";
            }
            if (path) {
                result.push(path);
                path = "";
            }
            result.push({
                name: name || key++,
                prefix: prefix,
                suffix: "",
                pattern: pattern || safePattern(prefix),
                modifier: tryConsume("MODIFIER") || "",
            });
            continue;
        }
        var value = char || tryConsume("ESCAPED_CHAR");
        if (value) {
            path += value;
            continue;
        }
        if (path) {
            result.push(path);
            path = "";
        }
        var open = tryConsume("OPEN");
        if (open) {
            var prefix = consumeText();
            var name_1 = tryConsume("NAME") || "";
            var pattern_1 = tryConsume("PATTERN") || "";
            var suffix = consumeText();
            mustConsume("CLOSE");
            result.push({
                name: name_1 || (pattern_1 ? key++ : ""),
                pattern: name_1 && !pattern_1 ? safePattern(prefix) : pattern_1,
                prefix: prefix,
                suffix: suffix,
                modifier: tryConsume("MODIFIER") || "",
            });
            continue;
        }
        mustConsume("END");
    }
    return result;
}
/**
 * Compile a string to a template function for the path.
 */
function compile$1(str, options) {
    return tokensToFunction(parse$3(str, options), options);
}
/**
 * Expose a method for transforming tokens into the path function.
 */
function tokensToFunction(tokens, options) {
    if (options === void 0) { options = {}; }
    var reFlags = flags(options);
    var _a = options.encode, encode = _a === void 0 ? function (x) { return x; } : _a, _b = options.validate, validate = _b === void 0 ? true : _b;
    // Compile all the tokens into regexps.
    var matches = tokens.map(function (token) {
        if (typeof token === "object") {
            return new RegExp("^(?:".concat(token.pattern, ")$"), reFlags);
        }
    });
    return function (data) {
        var path = "";
        for (var i = 0; i < tokens.length; i++) {
            var token = tokens[i];
            if (typeof token === "string") {
                path += token;
                continue;
            }
            var value = data ? data[token.name] : undefined;
            var optional = token.modifier === "?" || token.modifier === "*";
            var repeat = token.modifier === "*" || token.modifier === "+";
            if (Array.isArray(value)) {
                if (!repeat) {
                    throw new TypeError("Expected \"".concat(token.name, "\" to not repeat, but got an array"));
                }
                if (value.length === 0) {
                    if (optional)
                        continue;
                    throw new TypeError("Expected \"".concat(token.name, "\" to not be empty"));
                }
                for (var j = 0; j < value.length; j++) {
                    var segment = encode(value[j], token);
                    if (validate && !matches[i].test(segment)) {
                        throw new TypeError("Expected all \"".concat(token.name, "\" to match \"").concat(token.pattern, "\", but got \"").concat(segment, "\""));
                    }
                    path += token.prefix + segment + token.suffix;
                }
                continue;
            }
            if (typeof value === "string" || typeof value === "number") {
                var segment = encode(String(value), token);
                if (validate && !matches[i].test(segment)) {
                    throw new TypeError("Expected \"".concat(token.name, "\" to match \"").concat(token.pattern, "\", but got \"").concat(segment, "\""));
                }
                path += token.prefix + segment + token.suffix;
                continue;
            }
            if (optional)
                continue;
            var typeOfMessage = repeat ? "an array" : "a string";
            throw new TypeError("Expected \"".concat(token.name, "\" to be ").concat(typeOfMessage));
        }
        return path;
    };
}
/**
 * Create path match function from `path-to-regexp` spec.
 */
function match(str, options) {
    var keys = [];
    var re = pathToRegexp(str, keys, options);
    return regexpToFunction(re, keys, options);
}
/**
 * Create a path match function from `path-to-regexp` output.
 */
function regexpToFunction(re, keys, options) {
    if (options === void 0) { options = {}; }
    var _a = options.decode, decode = _a === void 0 ? function (x) { return x; } : _a;
    return function (pathname) {
        var m = re.exec(pathname);
        if (!m)
            return false;
        var path = m[0], index = m.index;
        var params = Object.create(null);
        var _loop_1 = function (i) {
            if (m[i] === undefined)
                return "continue";
            var key = keys[i - 1];
            if (key.modifier === "*" || key.modifier === "+") {
                params[key.name] = m[i].split(key.prefix + key.suffix).map(function (value) {
                    return decode(value, key);
                });
            }
            else {
                params[key.name] = decode(m[i], key);
            }
        };
        for (var i = 1; i < m.length; i++) {
            _loop_1(i);
        }
        return { path: path, index: index, params: params };
    };
}
/**
 * Escape a regular expression string.
 */
function escapeString(str) {
    return str.replace(/([.+*?=^!:${}()[\]|/\\])/g, "\\$1");
}
/**
 * Get the flags for a regexp from the options.
 */
function flags(options) {
    return options && options.sensitive ? "" : "i";
}
/**
 * Pull out keys from a regexp.
 */
function regexpToRegexp(path, keys) {
    if (!keys)
        return path;
    var groupsRegex = /\((?:\?<(.*?)>)?(?!\?)/g;
    var index = 0;
    var execResult = groupsRegex.exec(path.source);
    while (execResult) {
        keys.push({
            // Use parenthesized substring match if available, index otherwise
            name: execResult[1] || index++,
            prefix: "",
            suffix: "",
            modifier: "",
            pattern: "",
        });
        execResult = groupsRegex.exec(path.source);
    }
    return path;
}
/**
 * Transform an array into a regexp.
 */
function arrayToRegexp(paths, keys, options) {
    var parts = paths.map(function (path) { return pathToRegexp(path, keys, options).source; });
    return new RegExp("(?:".concat(parts.join("|"), ")"), flags(options));
}
/**
 * Create a path regexp from string input.
 */
function stringToRegexp(path, keys, options) {
    return tokensToRegexp(parse$3(path, options), keys, options);
}
/**
 * Expose a function for taking tokens and returning a RegExp.
 */
function tokensToRegexp(tokens, keys, options) {
    if (options === void 0) { options = {}; }
    var _a = options.strict, strict = _a === void 0 ? false : _a, _b = options.start, start = _b === void 0 ? true : _b, _c = options.end, end = _c === void 0 ? true : _c, _d = options.encode, encode = _d === void 0 ? function (x) { return x; } : _d, _e = options.delimiter, delimiter = _e === void 0 ? "/#?" : _e, _f = options.endsWith, endsWith = _f === void 0 ? "" : _f;
    var endsWithRe = "[".concat(escapeString(endsWith), "]|$");
    var delimiterRe = "[".concat(escapeString(delimiter), "]");
    var route = start ? "^" : "";
    // Iterate over the tokens and create our regexp string.
    for (var _i = 0, tokens_1 = tokens; _i < tokens_1.length; _i++) {
        var token = tokens_1[_i];
        if (typeof token === "string") {
            route += escapeString(encode(token));
        }
        else {
            var prefix = escapeString(encode(token.prefix));
            var suffix = escapeString(encode(token.suffix));
            if (token.pattern) {
                if (keys)
                    keys.push(token);
                if (prefix || suffix) {
                    if (token.modifier === "+" || token.modifier === "*") {
                        var mod = token.modifier === "*" ? "?" : "";
                        route += "(?:".concat(prefix, "((?:").concat(token.pattern, ")(?:").concat(suffix).concat(prefix, "(?:").concat(token.pattern, "))*)").concat(suffix, ")").concat(mod);
                    }
                    else {
                        route += "(?:".concat(prefix, "(").concat(token.pattern, ")").concat(suffix, ")").concat(token.modifier);
                    }
                }
                else {
                    if (token.modifier === "+" || token.modifier === "*") {
                        throw new TypeError("Can not repeat \"".concat(token.name, "\" without a prefix and suffix"));
                    }
                    route += "(".concat(token.pattern, ")").concat(token.modifier);
                }
            }
            else {
                route += "(?:".concat(prefix).concat(suffix, ")").concat(token.modifier);
            }
        }
    }
    if (end) {
        if (!strict)
            route += "".concat(delimiterRe, "?");
        route += !options.endsWith ? "$" : "(?=".concat(endsWithRe, ")");
    }
    else {
        var endToken = tokens[tokens.length - 1];
        var isEndDelimited = typeof endToken === "string"
            ? delimiterRe.indexOf(endToken[endToken.length - 1]) > -1
            : endToken === undefined;
        if (!strict) {
            route += "(?:".concat(delimiterRe, "(?=").concat(endsWithRe, "))?");
        }
        if (!isEndDelimited) {
            route += "(?=".concat(delimiterRe, "|").concat(endsWithRe, ")");
        }
    }
    return new RegExp(route, flags(options));
}
/**
 * Normalize the given path string, returning a regular expression.
 *
 * An empty array can be passed in for the keys, which will hold the
 * placeholder key descriptions. For example, using `/user/:id`, `keys` will
 * contain `[{ name: 'id', delimiter: '/', optional: false, repeat: false }]`.
 */
function pathToRegexp(path, keys, options) {
    if (path instanceof RegExp)
        return regexpToRegexp(path, keys);
    if (Array.isArray(path))
        return arrayToRegexp(path, keys, options);
    return stringToRegexp(path, keys, options);
}

function resolveRewrites(pages, userRewrites) {
  const pageToRewrite = {};
  const rewriteToPage = {};
  if (typeof userRewrites === "function") {
    for (const page of pages) {
      const dest = userRewrites(page);
      if (dest && dest !== page) {
        pageToRewrite[page] = dest;
        rewriteToPage[dest] = page;
      }
    }
  } else if (typeof userRewrites === "object") {
    const rewriteRules = Object.entries(userRewrites || {}).map(
      ([from, to]) => ({
        toPath: compile$1(`/${to}`, { validate: false }),
        matchUrl: match(from.startsWith("^") ? new RegExp(from) : from)
      })
    );
    if (rewriteRules.length) {
      for (const page of pages) {
        for (const { matchUrl, toPath } of rewriteRules) {
          const res = matchUrl(page);
          if (res) {
            const dest = toPath(res.params).slice(1);
            pageToRewrite[page] = dest;
            rewriteToPage[dest] = page;
            break;
          }
        }
      }
    }
  }
  return {
    map: pageToRewrite,
    inv: rewriteToPage
  };
}
const rewritesPlugin = (config) => {
  return {
    name: "vitepress:rewrites",
    configureServer(server) {
      server.middlewares.use((req, _res, next) => {
        if (req.url) {
          const page = decodeURI(req.url).replace(/[?#].*$/, "").slice(config.site.base.length);
          if (config.rewrites.inv[page]) {
            req.url = req.url.replace(
              encodeURI(page),
              encodeURI(config.rewrites.inv[page])
            );
          }
        }
        next();
      });
    }
  };
};

const dynamicRouteRE = /\[(\w+?)\]/g;
const pathLoaderRE = /\.paths\.m?[jt]s$/;
const routeModuleCache = /* @__PURE__ */ new Map();
let moduleGraph = new ModuleGraph();
let discoveredPages = /* @__PURE__ */ new Set();
function defineRoutes(loader) {
  return loader;
}
async function resolvePages(siteConfig, rebuildCache = false) {
  if (rebuildCache) {
    moduleGraph = new ModuleGraph();
    routeModuleCache.clear();
    discoveredPages.clear();
  }
  const allMarkdownFiles = await glob(["**/*.md"], {
    cwd: siteConfig.srcDir,
    ignore: siteConfig.userConfig.srcExclude
  });
  const pages = [];
  const dynamicRouteFiles = [];
  allMarkdownFiles.forEach((file) => {
    dynamicRouteRE.lastIndex = 0;
    (dynamicRouteRE.test(file) ? dynamicRouteFiles : pages).push(file);
  });
  const dynamicRoutes = await resolveDynamicRoutes(
    siteConfig.srcDir,
    dynamicRouteFiles,
    siteConfig.logger
  );
  pages.push(...dynamicRoutes.map((r) => r.path));
  const externalDynamicRoutes = siteConfig.dynamicRoutes?.filter((r) => !discoveredPages.has(r.path)) || [];
  const externalPages = siteConfig.pages?.filter((p) => !discoveredPages.has(p)) || [];
  const finalDynamicRoutes = [...dynamicRoutes, ...externalDynamicRoutes].sort(
    (a, b) => a.path.localeCompare(b.path)
  );
  const finalPages = [...pages, ...externalPages].sort();
  const rewrites = resolveRewrites(pages, siteConfig.userConfig.rewrites);
  Object.assign(siteConfig, {
    pages: finalPages,
    dynamicRoutes: finalDynamicRoutes,
    rewrites,
    // @ts-expect-error internal flag to reload resolution cache in ../markdownToVue.ts
    __dirty: true
  });
  discoveredPages = new Set(pages);
}
const dynamicRoutesPlugin = async (config) => {
  return {
    name: "vitepress:dynamic-routes",
    enforce: "pre",
    resolveId(id) {
      if (!id.endsWith(".md")) return;
      const normalizedId = id.startsWith(config.srcDir) ? id : normalizePath$1(path$1.resolve(config.srcDir, id.replace(/^\//, "")));
      const matched = config.dynamicRoutes.find(
        (r) => r.fullPath === normalizedId
      );
      if (matched) return normalizedId;
    },
    load(id) {
      const matched = config.dynamicRoutes.find((r) => r.fullPath === id);
      if (matched) {
        const { route, params, content } = matched;
        const routeFile = normalizePath$1(path$1.resolve(config.srcDir, route));
        moduleGraph.add(id, [routeFile]);
        moduleGraph.add(routeFile, [matched.loaderPath]);
        let baseContent = fs.readFileSync(routeFile, "utf-8");
        if (content) {
          baseContent = baseContent.replace(
            //,
            content.replace(/\$/g, "$$$")
          );
        }
        return `__VP_PARAMS_START${JSON.stringify(params)}__VP_PARAMS_END__${baseContent}`;
      }
    },
    async hotUpdate({ file, modules: existingMods }) {
      if (this.environment.name !== "client") return;
      const modules = [];
      const normalizedFile = normalizePath$1(file);
      modules.push(...getModules(normalizedFile, this.environment.moduleGraph));
      let watchedFileChanged = false;
      for (const [file2, route] of routeModuleCache) {
        if (route.watch?.length && pm$1(route.watch, route.options.globOptions)(normalizedFile)) {
          route.routes = void 0;
          watchedFileChanged = true;
          modules.push(...getModules(file2, this.environment.moduleGraph, false));
        }
      }
      if (modules.length && !normalizedFile.endsWith(".md") || watchedFileChanged || pathLoaderRE.test(normalizedFile)) {
        await resolvePages(config);
      }
      return modules.length ? [...existingMods, ...modules] : void 0;
    }
  };
};
function getPageDataTransformer(loaderPath) {
  return routeModuleCache.get(loaderPath)?.transformPageData;
}
async function resolveDynamicRoutes(srcDir, routes, logger) {
  const pendingResolveRoutes = [];
  const newModuleGraph = moduleGraph.clone();
  for (const route of routes) {
    const fullPath = normalizePath$1(path$1.resolve(srcDir, route));
    const paths = ["js", "ts", "mjs", "mts"].map(
      (ext) => fullPath.replace(/\.md$/, `.paths.${ext}`)
    );
    const pathsFile = paths.find((p) => fs.existsSync(p));
    if (pathsFile == null) {
      logger.warn(
        c$1.yellow(
          `Missing paths file for dynamic route ${route}: a corresponding ${paths[0]} (or .ts/.mjs/.mts) file is needed.`
        )
      );
      continue;
    }
    let watch;
    let loader;
    let transformPageData;
    let options;
    const loaderPath = normalizePath$1(pathsFile);
    const existing = routeModuleCache.get(loaderPath);
    if (existing) {
      if (existing.routes) {
        pendingResolveRoutes.push(Promise.resolve(existing.routes));
        continue;
      }
      ({ watch, loader, transformPageData, options } = existing);
    } else {
      let mod;
      try {
        mod = await loadConfigFromFile(
          {},
          pathsFile,
          void 0,
          "silent"
        );
      } catch (err) {
        logger.warn(
          `${c$1.yellow(`Failed to load ${pathsFile}:`)}
${err.message}
${err.stack}`
        );
        continue;
      }
      if (!mod) {
        logger.warn(
          c$1.yellow(
            `Invalid paths file export in ${pathsFile}. Missing "default" export.`
          )
        );
        continue;
      }
      const loaderModule = mod.config;
      watch = normalizeGlob(loaderModule.watch, path$1.dirname(pathsFile));
      loader = loaderModule.paths;
      transformPageData = loaderModule.transformPageData;
      options = loaderModule.options || {};
      if (!loader) {
        logger.warn(
          c$1.yellow(
            `Invalid paths file export in ${pathsFile}. Missing "paths" property from default export.`
          )
        );
        continue;
      }
      newModuleGraph.add(
        loaderPath,
        mod.dependencies.map((p) => normalizePath$1(path$1.resolve(p)))
      );
    }
    const resolveRoute = async () => {
      let pathsData;
      if (typeof loader === "function") {
        const watchedFiles = await glob(watch, {
          absolute: true,
          ...options.globOptions
        });
        pathsData = await loader(watchedFiles);
      } else {
        pathsData = loader;
      }
      const routes2 = pathsData.map((userConfig) => {
        const resolvedPath = route.replace(
          dynamicRouteRE,
          (_, key) => userConfig.params[key]
        );
        return {
          path: resolvedPath,
          fullPath: normalizePath$1(path$1.resolve(srcDir, resolvedPath)),
          route,
          loaderPath,
          ...userConfig
        };
      });
      const mod = { watch, routes: routes2, loader, transformPageData, options };
      routeModuleCache.set(loaderPath, mod);
      return routes2;
    };
    pendingResolveRoutes.push(resolveRoute());
  }
  const resolvedRoutes = (await Promise.all(pendingResolveRoutes)).flat();
  moduleGraph = newModuleGraph;
  return resolvedRoutes;
}
function getModules(id, envModuleGraph, deleteFromRouteModuleCache = true) {
  const modules = [];
  for (const file of moduleGraph.delete(id)) {
    deleteFromRouteModuleCache && routeModuleCache.delete(file);
    modules.push(...envModuleGraph.getModulesByFile(file)?.values() ?? []);
  }
  return modules;
}

const EXTERNAL_URL_RE = /^(?:[a-z]+:|\/\/)/i;
const APPEARANCE_KEY = "vitepress-theme-appearance";
const VP_SOURCE_KEY = "[VP_SOURCE]";
const UnpackStackView = Symbol("stack-view:unpack");
const HASH_RE = /#.*$/;
const HASH_OR_QUERY_RE = /[?#].*$/;
const INDEX_OR_EXT_RE = /(?:(^|\/)index)?\.(?:md|html)$/;
const inBrowser = typeof document !== "undefined";
const notFoundPageData = {
  relativePath: "404.md",
  filePath: "",
  title: "404",
  description: "Not Found",
  headers: [],
  frontmatter: { sidebar: false, layout: "page" },
  lastUpdated: 0,
  isNotFound: true
};
function isActive(currentPath, matchPath, asRegex = false) {
  if (matchPath === void 0) {
    return false;
  }
  currentPath = normalize$1(`/${currentPath}`);
  if (asRegex) {
    return new RegExp(matchPath).test(currentPath);
  }
  if (normalize$1(matchPath) !== currentPath) {
    return false;
  }
  const hashMatch = matchPath.match(HASH_RE);
  if (hashMatch) {
    return (inBrowser ? location.hash : "") === hashMatch[0];
  }
  return true;
}
function normalize$1(path) {
  return decodeURI(path).replace(HASH_OR_QUERY_RE, "").replace(INDEX_OR_EXT_RE, "$1");
}
function isExternal(path) {
  return EXTERNAL_URL_RE.test(path);
}
function getLocaleForPath(siteData, relativePath) {
  return Object.keys(siteData?.locales || {}).find(
    (key) => key !== "root" && !isExternal(key) && isActive(relativePath, `^/${key}/`, true)
  ) || "root";
}
function resolveSiteDataByRoute(siteData, relativePath) {
  const localeIndex = getLocaleForPath(siteData, relativePath);
  const { label, link, ...localeConfig } = siteData.locales[localeIndex] ?? {};
  Object.assign(localeConfig, { localeIndex });
  const additionalConfigs = resolveAdditionalConfig(siteData, relativePath);
  if (inBrowser && import.meta.env?.DEV) {
    localeConfig[VP_SOURCE_KEY] = `locale config (${localeIndex})`;
    reportConfigLayers(relativePath, [
      ...additionalConfigs,
      localeConfig,
      siteData
    ]);
  }
  const topLayer = {
    head: mergeHead(
      siteData.head ?? [],
      localeConfig.head ?? [],
      ...additionalConfigs.map((data) => data.head ?? []).reverse()
    )
  };
  return stackView(
    topLayer,
    ...additionalConfigs,
    localeConfig,
    siteData
  );
}
function createTitle(siteData, pageData) {
  const title = pageData.title || siteData.title;
  const template = pageData.titleTemplate ?? siteData.titleTemplate;
  if (typeof template === "string" && template.includes(":title")) {
    return template.replace(/:title/g, title);
  }
  const templateString = createTitleTemplate(siteData.title, template);
  if (title === templateString.slice(3)) {
    return title;
  }
  return `${title}${templateString}`;
}
function createTitleTemplate(siteTitle, template) {
  if (template === false) {
    return "";
  }
  if (template === true || template === void 0) {
    return ` | ${siteTitle}`;
  }
  if (siteTitle === template) {
    return "";
  }
  return ` | ${template}`;
}
function mergeHead(...headArrays) {
  const merged = [];
  const metaKeyMap = /* @__PURE__ */ new Map();
  for (const current of headArrays) {
    for (const tag of current) {
      const [type, attrs] = tag;
      const keyAttr = Object.entries(attrs)[0];
      if (type !== "meta" || !keyAttr) {
        merged.push(tag);
        continue;
      }
      const key = `${keyAttr[0]}=${keyAttr[1]}`;
      const existingIndex = metaKeyMap.get(key);
      if (existingIndex != null) {
        merged[existingIndex] = tag;
      } else {
        metaKeyMap.set(key, merged.length);
        merged.push(tag);
      }
    }
  }
  return merged;
}
const INVALID_CHAR_REGEX = /[\u0000-\u001F"#$&*+,:;<=>?[\]^`{|}\u007F]/g;
const DRIVE_LETTER_REGEX = /^[a-z]:/i;
function sanitizeFileName(name) {
  const match = DRIVE_LETTER_REGEX.exec(name);
  const driveLetter = match ? match[0] : "";
  return driveLetter + name.slice(driveLetter.length).replace(INVALID_CHAR_REGEX, "_").replace(/(^|\/)_+(?=[^/]*$)/, "$1");
}
function slash(p) {
  return p.replace(/\\/g, "/");
}
const KNOWN_EXTENSIONS = /* @__PURE__ */ new Set();
function treatAsHtml(filename) {
  if (KNOWN_EXTENSIONS.size === 0) {
    const extraExts = typeof process === "object" && process.env?.VITE_EXTRA_EXTENSIONS || import.meta.env?.VITE_EXTRA_EXTENSIONS || "";
    ("3g2,3gp,aac,ai,apng,au,avif,bin,bmp,cer,class,conf,crl,css,csv,dll,doc,eps,epub,exe,gif,gz,ics,ief,jar,jpe,jpeg,jpg,js,json,jsonld,m4a,man,mid,midi,mjs,mov,mp2,mp3,mp4,mpe,mpeg,mpg,mpp,oga,ogg,ogv,ogx,opus,otf,p10,p7c,p7m,p7s,pdf,png,ps,qt,roff,rtf,rtx,ser,svg,t,tif,tiff,tr,ts,tsv,ttf,txt,vtt,wav,weba,webm,webp,woff,woff2,xhtml,xml,yaml,yml,zip" + (extraExts && typeof extraExts === "string" ? "," + extraExts : "")).split(",").forEach((ext2) => KNOWN_EXTENSIONS.add(ext2));
  }
  const ext = filename.split(".").pop();
  return ext == null || !KNOWN_EXTENSIONS.has(ext.toLowerCase());
}
function escapeRegExp(str) {
  return str.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&").replace(/-/g, "\\x2d");
}
function escapeHtml$2(str) {
  return str.replace(//g, ">").replace(/"/g, """).replace(/&(?![\w#]+;)/g, "&");
}
function resolveAdditionalConfig({ additionalConfig }, path) {
  if (additionalConfig === void 0) return [];
  if (typeof additionalConfig === "function")
    return additionalConfig(path) ?? [];
  const configs = [];
  const segments = path.split("/").slice(0, -1);
  while (segments.length) {
    const key = `/${segments.join("/")}/`;
    configs.push(additionalConfig[key]);
    segments.pop();
  }
  configs.push(additionalConfig["/"]);
  return configs.filter((config) => config !== void 0);
}
function reportConfigLayers(path, layers) {
  const summaryTitle = `Config Layers for ${path}:`;
  const summary = layers.map((c, i, arr) => {
    const n = i + 1;
    if (n === arr.length) return `${n}. .vitepress/config (root)`;
    return `${n}. ${c?.[VP_SOURCE_KEY] ?? "(Unknown Source)"}`;
  });
  console.debug(
    [summaryTitle, "".padEnd(summaryTitle.length, "="), ...summary].join("\n")
  );
}
function stackView(..._layers) {
  const layers = _layers.filter((layer) => isObject$1(layer));
  if (layers.length <= 1) return _layers[0];
  const allKeys = new Set(layers.flatMap((layer) => Reflect.ownKeys(layer)));
  const allKeysArray = [...allKeys];
  return new Proxy({}, {
    // TODO: optimize for performance, this is a hot path
    get(_, prop) {
      if (prop === UnpackStackView) return layers;
      return stackView(
        ...layers.map((layer) => layer[prop]).filter((v) => v !== void 0)
      );
    },
    set() {
      throw new Error("StackView is read-only and cannot be mutated.");
    },
    has(_, prop) {
      return allKeys.has(prop);
    },
    ownKeys() {
      return allKeysArray;
    },
    getOwnPropertyDescriptor(_, prop) {
      for (const layer of layers) {
        const descriptor = Object.getOwnPropertyDescriptor(layer, prop);
        if (descriptor) return descriptor;
      }
    }
  });
}
stackView.unpack = function(obj) {
  return obj?.[UnpackStackView];
};
function isObject$1(value) {
  return Object.prototype.toString.call(value) === "[object Object]";
}
const shellLangs = ["shellscript", "shell", "bash", "sh", "zsh"];
function isShell(lang) {
  return shellLangs.includes(lang);
}

const debug$3 = createDebug("vitepress:config");
const resolve = (root, file) => normalizePath$1(path$1.resolve(root, `.vitepress`, file));
function defineConfig(config) {
  return config;
}
function defineAdditionalConfig(config) {
  return config;
}
function defineConfigWithTheme(config) {
  return config;
}
async function resolveConfig(root = process.cwd(), command = "serve", mode = "development") {
  root = normalizePath$1(path$1.resolve(root));
  const [userConfig, configPath, configDeps] = await resolveUserConfig(
    root,
    command,
    mode
  );
  const logger = userConfig.vite?.customLogger ?? createLogger(userConfig.vite?.logLevel, {
    prefix: "[vitepress]",
    allowClearScreen: userConfig.vite?.clearScreen
  });
  const site = await resolveSiteData(root, userConfig);
  const srcDir = normalizePath$1(path$1.resolve(root, userConfig.srcDir || "."));
  const assetsDir = userConfig.assetsDir ? slash(userConfig.assetsDir).replace(/^\.?\/|\/$/g, "") : "assets";
  const outDir = userConfig.outDir ? normalizePath$1(path$1.resolve(root, userConfig.outDir)) : resolve(root, "dist");
  const cacheDir = userConfig.cacheDir ? normalizePath$1(path$1.resolve(root, userConfig.cacheDir)) : resolve(root, "cache");
  const resolvedAssetsDir = normalizePath$1(path$1.resolve(outDir, assetsDir));
  if (!resolvedAssetsDir.startsWith(outDir)) {
    throw new Error(
      [
        `assetsDir cannot be set to a location outside of the outDir.`,
        `outDir: ${outDir}`,
        `assetsDir: ${assetsDir}`,
        `resolved: ${resolvedAssetsDir}`
      ].join("\n  ")
    );
  }
  const userThemeDir = resolve(root, "theme");
  const themeDir = await fs.pathExists(userThemeDir) ? userThemeDir : DEFAULT_THEME_PATH;
  const config = {
    root,
    srcDir,
    assetsDir,
    site,
    themeDir,
    configPath,
    configDeps,
    outDir,
    cacheDir,
    logger,
    tempDir: resolve(root, ".temp"),
    markdown: userConfig.markdown,
    lastUpdated: userConfig.lastUpdated ?? !!userConfig.themeConfig?.lastUpdated,
    vue: userConfig.vue,
    vite: userConfig.vite,
    shouldPreload: userConfig.shouldPreload,
    mpa: !!userConfig.mpa,
    metaChunk: !!userConfig.metaChunk,
    ignoreDeadLinks: userConfig.ignoreDeadLinks,
    cleanUrls: !!userConfig.cleanUrls,
    useWebFonts: userConfig.useWebFonts ?? typeof process.versions.webcontainer === "string",
    postRender: userConfig.postRender,
    buildEnd: userConfig.buildEnd,
    transformHead: userConfig.transformHead,
    transformHtml: userConfig.transformHtml,
    transformPageData: userConfig.transformPageData,
    userConfig,
    sitemap: userConfig.sitemap,
    buildConcurrency: userConfig.buildConcurrency ?? 64
  };
  global.VITEPRESS_CONFIG = config;
  await resolvePages(config, true);
  return config;
}
const supportedConfigExtensions = ["js", "ts", "mjs", "mts"];
const additionalConfigRE = /(?:^|\/|\\)config\.m?[jt]s$/;
const additionalConfigGlob = `**/config.{js,mjs,ts,mts}`;
function isAdditionalConfigFile(path2) {
  return additionalConfigRE.test(path2);
}
async function gatherAdditionalConfig(root, command, mode, srcDir = ".", srcExclude = []) {
  const candidates = await glob([additionalConfigGlob], {
    cwd: path$1.resolve(root, srcDir),
    ignore: srcExclude
  });
  const deps = [];
  const exports$1 = await Promise.all(
    candidates.map(async (file) => {
      const id = normalizePath$1(`/${path$1.dirname(file)}/`);
      const configExports = await loadConfigFromFile(
        { command, mode },
        normalizePath$1(path$1.resolve(root, srcDir, file)),
        root
      ).catch(console.error);
      if (!configExports) {
        debug$3(`Failed to load additional config from ${file}`);
        return;
      }
      deps.push(
        configExports.dependencies.map(
          (file2) => normalizePath$1(path$1.resolve(file2))
        )
      );
      if (mode === "development") {
        configExports.config[VP_SOURCE_KEY] = "/" + slash(file);
      }
      return [id, configExports.config];
    })
  );
  return [Object.fromEntries(exports$1.filter((e) => e != null)), deps];
}
async function resolveUserConfig(root, command, mode) {
  const configPath = supportedConfigExtensions.flatMap((ext) => [
    resolve(root, `config/index.${ext}`),
    resolve(root, `config.${ext}`)
  ]).find(fs.pathExistsSync);
  let userConfig = {};
  let configDeps = [];
  if (!configPath) {
    debug$3(`no config file found.`);
  } else {
    const configExports = await loadConfigFromFile(
      { command, mode },
      configPath,
      root
    );
    if (configExports) {
      userConfig = configExports.config;
      configDeps = configExports.dependencies.map(
        (file) => normalizePath$1(path$1.resolve(file))
      );
    }
    debug$3(`loaded config at ${c$1.yellow(configPath)}`);
  }
  if (userConfig.additionalConfig === void 0) {
    const [additionalConfig, additionalDeps] = await gatherAdditionalConfig(
      root,
      command,
      mode,
      userConfig.srcDir,
      userConfig.srcExclude
    );
    userConfig.additionalConfig = additionalConfig;
    configDeps = configDeps.concat(...additionalDeps);
  }
  return [await resolveConfigExtends(userConfig), configPath, configDeps];
}
async function resolveConfigExtends(config) {
  const resolved = await (typeof config === "function" ? config() : config);
  if (resolved.extends) {
    const base = await resolveConfigExtends(resolved.extends);
    return mergeConfig(base, resolved);
  }
  return resolved;
}
function mergeConfig(a, b, isRoot = true) {
  const merged = { ...a };
  for (const key in b) {
    const value = b[key];
    if (value == null) {
      continue;
    }
    const existing = merged[key];
    if (Array.isArray(existing) && Array.isArray(value)) {
      merged[key] = [...existing, ...value];
      continue;
    }
    if (isObject$1(existing) && isObject$1(value)) {
      if (isRoot && key === "vite") {
        merged[key] = mergeConfig$1(existing, value);
      } else {
        merged[key] = mergeConfig(existing, value, false);
      }
      continue;
    }
    merged[key] = value;
  }
  return merged;
}
async function resolveSiteData(root, userConfig, command = "serve", mode = "development") {
  userConfig = userConfig || (await resolveUserConfig(root, command, mode))[0];
  return {
    lang: userConfig.lang || "en-US",
    dir: userConfig.dir || "ltr",
    title: userConfig.title || "VitePress",
    titleTemplate: userConfig.titleTemplate,
    description: userConfig.description || "A VitePress site",
    base: userConfig.base ? userConfig.base.replace(/([^/])$/, "$1/") : "/",
    head: resolveSiteDataHead(userConfig),
    router: {
      prefetchLinks: userConfig.router?.prefetchLinks ?? true
    },
    appearance: userConfig.appearance ?? true,
    themeConfig: userConfig.themeConfig || {},
    locales: userConfig.locales || {},
    scrollOffset: userConfig.scrollOffset ?? 134,
    cleanUrls: !!userConfig.cleanUrls,
    contentProps: userConfig.contentProps,
    additionalConfig: userConfig.additionalConfig
  };
}
function resolveSiteDataHead(userConfig) {
  const head = userConfig?.head ?? [];
  if (userConfig?.mpa) return head;
  if (userConfig?.appearance ?? true) {
    const fallbackPreference = typeof userConfig?.appearance === "string" ? userConfig?.appearance : typeof userConfig?.appearance === "object" ? userConfig.appearance.initialValue ?? "auto" : "auto";
    head.push([
      "script",
      { id: "check-dark-mode" },
      fallbackPreference === "force-dark" ? `document.documentElement.classList.add('dark')` : fallbackPreference === "force-auto" ? `;(() => {
               if (window.matchMedia('(prefers-color-scheme: dark)').matches)
                 document.documentElement.classList.add('dark')
             })()` : `;(() => {
               const preference = localStorage.getItem('${APPEARANCE_KEY}') || '${fallbackPreference}'
               const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches
               if (!preference || preference === 'auto' ? prefersDark : preference === 'dark')
                 document.documentElement.classList.add('dark')
             })()`
    ]);
  }
  head.push([
    "script",
    { id: "check-mac-os" },
    `document.documentElement.classList.toggle('mac', /Mac|iPhone|iPod|iPad/i.test(navigator.platform))`
  ]);
  return head;
}

//#region src/html-escape.ts
const htmlEscapeMap = {
	"&": "&",
	"<": "<",
	">": ">",
	"'": "'",
	"\"": """
};
const htmlEscapeRegexp = /[&<>'"]/g;
/**
* Escape html chars
*/
const htmlEscape = (str) => str.replace(htmlEscapeRegexp, (char) => htmlEscapeMap[char]);

//#endregion
//#region src/resolve-title-from-token.ts
/**
* Resolve header title from markdown-it token
*
* Typically using the next token of `heading_open` token
*/
const resolveTitleFromToken = (token, { shouldAllowHtml, shouldEscapeText }) => {
	const children = token.children ?? [];
	const titleTokenTypes = [
		"text",
		"emoji",
		"code_inline"
	];
	if (shouldAllowHtml) titleTokenTypes.push("html_inline");
	const titleTokens = children.filter((item) => titleTokenTypes.includes(item.type) && !item.meta?.isPermalinkSymbol);
	return titleTokens.reduce((result, item) => {
		if (shouldEscapeText) {
			if (item.type === "code_inline" || item.type === "text") return `${result}${htmlEscape(item.content)}`;
		}
		return `${result}${item.content}`;
	}, "").trim();
};

//#endregion
//#region src/resolve-headers-from-tokens.ts
/**
* Resolve headers from markdown-it tokens
*/
const resolveHeadersFromTokens = (tokens, { level, shouldAllowHtml, shouldAllowNested, shouldEscapeText, slugify: slugify$1, format }) => {
	const headers = [];
	const stack = [];
	const push = (header) => {
		while (stack.length !== 0 && header.level <= stack[0].level) stack.shift();
		if (stack.length === 0) {
			headers.push(header);
			stack.push(header);
		} else {
			stack[0].children.push(header);
			stack.unshift(header);
		}
	};
	for (let i = 0; i < tokens.length; i += 1) {
		const token = tokens[i];
		if (token.type !== "heading_open") continue;
		if (token.level !== 0 && !shouldAllowNested) continue;
		const headerLevel = Number.parseInt(token.tag.slice(1), 10);
		if (!level.includes(headerLevel)) continue;
		const nextToken = tokens[i + 1];
		/* istanbul ignore if -- @preserve */
		if (!nextToken) continue;
		const title = resolveTitleFromToken(nextToken, {
			shouldAllowHtml,
			shouldEscapeText
		});
		const slug = token.attrGet("id") ?? slugify$1(title);
		push({
			level: headerLevel,
			title: format?.(title) ?? title,
			slug,
			link: `#${slug}`,
			children: []
		});
	}
	return headers;
};

//#endregion
//#region src/slugify.ts
const rControl = /[\u0000-\u001f]/g;
const rSpecial = /[\s~`!@#$%^&*()\-_+=[\]{}|\\;:"'“”‘’<>,.?/]+/g;
const rCombining = /[\u0300-\u036F]/g;
/**
* Default slugification function
*/
const slugify = (str) => str.normalize("NFKD").replace(rCombining, "").replace(rControl, "").replace(rSpecial, "-").replace(/-{2,}/g, "-").replace(/^-+|-+$/g, "").replace(/^(\d)/, "_$1").toLowerCase();

//#region src/html-re.ts
const attr_name$1 = "[a-zA-Z_:@][a-zA-Z0-9:._-]*";
const attribute$2 = "(?:\\s+" + attr_name$1 + "(?:\\s*=\\s*(?:[^\"'=<>`\\x00-\\x20]+|'[^']*'|\"[^\"]*\"))?)";
const open_tag$1 = "<[A-Za-z][A-Za-z0-9\\-]*" + attribute$2 + "*\\s*\\/?>";
const HTML_TAG_RE$1 = /* @__PURE__ */ new RegExp("^(?:" + open_tag$1 + "|<\\/[A-Za-z][A-Za-z0-9\\-]*\\s*>|||<[?][\\s\\S]*?[?]>|]*>|)");
const HTML_OPEN_CLOSE_TAG_RE$1 = /* @__PURE__ */ new RegExp("^(?:" + open_tag$1 + "|<\\/[A-Za-z][A-Za-z0-9\\-]*\\s*>)");
const HTML_SELF_CLOSING_TAG_RE = /* @__PURE__ */ new RegExp("^<[A-Za-z][A-Za-z0-9\\-]*" + attribute$2 + "*\\s*\\/>");
const HTML_OPEN_AND_CLOSE_TAG_IN_THE_SAME_LINE_RE = /* @__PURE__ */ new RegExp("^<([A-Za-z][A-Za-z0-9\\-]*)" + attribute$2 + "*\\s*>.*<\\/\\1\\s*>");

//#endregion
//#region src/tags.ts
/**
* List of block tags
*
* @see https://spec.commonmark.org/0.30/#html-blocks
* @see https://github.com/markdown-it/markdown-it/blob/master/lib/common/html_blocks.mjs
*/
const TAGS_BLOCK = [
	"address",
	"article",
	"aside",
	"base",
	"basefont",
	"blockquote",
	"body",
	"caption",
	"center",
	"col",
	"colgroup",
	"dd",
	"details",
	"dialog",
	"dir",
	"div",
	"dl",
	"dt",
	"fieldset",
	"figcaption",
	"figure",
	"footer",
	"form",
	"frame",
	"frameset",
	"h1",
	"h2",
	"h3",
	"h4",
	"h5",
	"h6",
	"head",
	"header",
	"hr",
	"html",
	"iframe",
	"legend",
	"li",
	"link",
	"main",
	"menu",
	"menuitem",
	"nav",
	"noframes",
	"ol",
	"optgroup",
	"option",
	"p",
	"param",
	"search",
	"section",
	"summary",
	"table",
	"tbody",
	"td",
	"tfoot",
	"th",
	"thead",
	"title",
	"tr",
	"track",
	"ul"
];
/**
* According to markdown spec, all non-block html tags are treated as "inline"
* tags (wrapped with 

), including those "unknown" tags * * Therefore, markdown-it processes "inline" tags and "unknown" tags in the same * way, and does not care if a tag is "inline" or "unknown" * * As we want to take those "unknown" tags as custom components, we should * treat them as "block" tags * * So we have to distinguish between "inline" and "unknown" tags ourselves * * The inline tags list comes from MDN * * @see https://spec.commonmark.org/0.30/#raw-html * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Inline_elements */ const TAGS_INLINE = [ "a", "abbr", "acronym", "audio", "b", "bdi", "bdo", "big", "br", "button", "canvas", "cite", "code", "data", "datalist", "del", "dfn", "em", "embed", "i", "iframe", "img", "input", "ins", "kbd", "label", "map", "mark", "meter", "noscript", "object", "output", "picture", "progress", "q", "ruby", "s", "samp", "script", "select", "slot", "small", "span", "strong", "sub", "sup", "svg", "template", "textarea", "time", "u", "tt", "var", "video", "wbr" ]; /** * Tags of Vue built-in components * * @see https://vuejs.org/api/built-in-components.html * @see https://vuejs.org/api/built-in-special-elements.html */ const TAGS_VUE_RESERVED = [ "template", "component", "transition", "transition-group", "keep-alive", "slot", "teleport" ]; //#endregion //#region src/html-block-rule.ts /** * ADDED: wrap the `HTML_SEQUENCES` with a function, because we allow user options * to customize the block tags and inline tags */ const createHtmlSequences = ({ blockTags, inlineTags }) => { const forceBlockTags = [...blockTags, ...TAGS_BLOCK]; const forceInlineTags = [...inlineTags, ...TAGS_INLINE.filter((item) => !TAGS_VUE_RESERVED.includes(item))]; const HTML_SEQUENCES = [ [ /^<(script|pre|style)(?=(\s|>|$))/i, /<\/(script|pre|style)>/i, true ], [ /^/, true ], [ /^<\?/, /\?>/, true ], [ /^/, true ], [ /^/, true ], [ new RegExp("^|$))", "i"), /^$/, true ], [ /* @__PURE__ */ new RegExp("^|$))"), /^$/, true ], [ /* @__PURE__ */ new RegExp(HTML_OPEN_CLOSE_TAG_RE$1.source + "\\s*$"), /^$/, false ] ]; return HTML_SEQUENCES; }; const createHtmlBlockRule = (options) => { const HTML_SEQUENCES = createHtmlSequences(options); return (state, startLine, endLine, silent) => { let i; let nextLine; let lineText; let pos = state.bMarks[startLine] + state.tShift[startLine]; let max = state.eMarks[startLine]; if (state.sCount[startLine] - state.blkIndent >= 4) return false; if (!state.md.options.html) return false; if (state.src.charCodeAt(pos) !== 60) return false; lineText = state.src.slice(pos, max); for (i = 0; i < HTML_SEQUENCES.length; i++) if (HTML_SEQUENCES[i][0].test(lineText)) break; if (i === HTML_SEQUENCES.length) return false; if (silent) return HTML_SEQUENCES[i][2]; if (i === 6) { const match = lineText.match(HTML_SELF_CLOSING_TAG_RE) ?? lineText.match(HTML_OPEN_AND_CLOSE_TAG_IN_THE_SAME_LINE_RE); if (match) { state.line = startLine + 1; let token$1 = state.push("html_inline", "", 0); token$1.content = match[0]; token$1.map = [startLine, state.line]; token$1 = state.push("inline", "", 0); token$1.content = lineText.slice(match[0].length); token$1.map = [startLine, state.line]; token$1.children = []; return true; } } nextLine = startLine + 1; if (!HTML_SEQUENCES[i][1].test(lineText)) for (; nextLine < endLine; nextLine++) { if (state.sCount[nextLine] < state.blkIndent) break; pos = state.bMarks[nextLine] + state.tShift[nextLine]; max = state.eMarks[nextLine]; lineText = state.src.slice(pos, max); if (HTML_SEQUENCES[i][1].test(lineText)) { if (lineText.length !== 0) nextLine++; break; } } state.line = nextLine; const token = state.push("html_block", "", 0); token.map = [startLine, nextLine]; token.content = state.getLines(startLine, nextLine, state.blkIndent, true); return true; }; }; //#endregion //#region src/html-inline-rule.ts const isLetter$1 = (ch) => { const lc = ch | 32; return lc >= 97 && lc <= 122; }; const htmlInlineRule = (state, silent) => { const { pos } = state; if (!state.md.options.html) return false; const max = state.posMax; if (state.src.charCodeAt(pos) !== 60 || pos + 2 >= max) return false; const ch = state.src.charCodeAt(pos + 1); if (ch !== 33 && ch !== 63 && ch !== 47 && !isLetter$1(ch)) return false; const match = state.src.slice(pos).match(HTML_TAG_RE$1); if (!match) return false; if (!silent) { const token = state.push("html_inline", "", 0); token.content = state.src.slice(pos, pos + match[0].length); } state.pos += match[0].length; return true; }; //#endregion //#region src/component-plugin.ts /** * Allows better use of Vue components in Markdown */ const componentPlugin = (md, { blockTags = [], inlineTags = [] } = {}) => { const htmlBlockRule = createHtmlBlockRule({ blockTags, inlineTags }); md.block.ruler.at("html_block", htmlBlockRule, { alt: [ "paragraph", "reference", "blockquote" ] }); md.inline.ruler.at("html_inline", htmlInlineRule); }; var kindOf; var hasRequiredKindOf; function requireKindOf () { if (hasRequiredKindOf) return kindOf; hasRequiredKindOf = 1; var toString = Object.prototype.toString; kindOf = function kindOf(val) { if (val === void 0) return 'undefined'; if (val === null) return 'null'; var type = typeof val; if (type === 'boolean') return 'boolean'; if (type === 'string') return 'string'; if (type === 'number') return 'number'; if (type === 'symbol') return 'symbol'; if (type === 'function') { return isGeneratorFn(val) ? 'generatorfunction' : 'function'; } if (isArray(val)) return 'array'; if (isBuffer(val)) return 'buffer'; if (isArguments(val)) return 'arguments'; if (isDate(val)) return 'date'; if (isError(val)) return 'error'; if (isRegexp(val)) return 'regexp'; switch (ctorName(val)) { case 'Symbol': return 'symbol'; case 'Promise': return 'promise'; // Set, Map, WeakSet, WeakMap case 'WeakMap': return 'weakmap'; case 'WeakSet': return 'weakset'; case 'Map': return 'map'; case 'Set': return 'set'; // 8-bit typed arrays case 'Int8Array': return 'int8array'; case 'Uint8Array': return 'uint8array'; case 'Uint8ClampedArray': return 'uint8clampedarray'; // 16-bit typed arrays case 'Int16Array': return 'int16array'; case 'Uint16Array': return 'uint16array'; // 32-bit typed arrays case 'Int32Array': return 'int32array'; case 'Uint32Array': return 'uint32array'; case 'Float32Array': return 'float32array'; case 'Float64Array': return 'float64array'; } if (isGeneratorObj(val)) { return 'generator'; } // Non-plain objects type = toString.call(val); switch (type) { case '[object Object]': return 'object'; // iterators case '[object Map Iterator]': return 'mapiterator'; case '[object Set Iterator]': return 'setiterator'; case '[object String Iterator]': return 'stringiterator'; case '[object Array Iterator]': return 'arrayiterator'; } // other return type.slice(8, -1).toLowerCase().replace(/\s/g, ''); }; function ctorName(val) { return typeof val.constructor === 'function' ? val.constructor.name : null; } function isArray(val) { if (Array.isArray) return Array.isArray(val); return val instanceof Array; } function isError(val) { return val instanceof Error || (typeof val.message === 'string' && val.constructor && typeof val.constructor.stackTraceLimit === 'number'); } function isDate(val) { if (val instanceof Date) return true; return typeof val.toDateString === 'function' && typeof val.getDate === 'function' && typeof val.setDate === 'function'; } function isRegexp(val) { if (val instanceof RegExp) return true; return typeof val.flags === 'string' && typeof val.ignoreCase === 'boolean' && typeof val.multiline === 'boolean' && typeof val.global === 'boolean'; } function isGeneratorFn(name, val) { return ctorName(name) === 'GeneratorFunction'; } function isGeneratorObj(val) { return typeof val.throw === 'function' && typeof val.return === 'function' && typeof val.next === 'function'; } function isArguments(val) { try { if (typeof val.length === 'number' && typeof val.callee === 'function') { return true; } } catch (err) { if (err.message.indexOf('callee') !== -1) { return true; } } return false; } /** * If you need to support Safari 5-7 (8-10 yr-old browser), * take a look at https://github.com/feross/is-buffer */ function isBuffer(val) { if (val.constructor && typeof val.constructor.isBuffer === 'function') { return val.constructor.isBuffer(val); } return false; } return kindOf; } /*! * is-extendable * * Copyright (c) 2015, Jon Schlinkert. * Licensed under the MIT License. */ var isExtendable; var hasRequiredIsExtendable; function requireIsExtendable () { if (hasRequiredIsExtendable) return isExtendable; hasRequiredIsExtendable = 1; isExtendable = function isExtendable(val) { return typeof val !== 'undefined' && val !== null && (typeof val === 'object' || typeof val === 'function'); }; return isExtendable; } var extendShallow; var hasRequiredExtendShallow; function requireExtendShallow () { if (hasRequiredExtendShallow) return extendShallow; hasRequiredExtendShallow = 1; var isObject = requireIsExtendable(); extendShallow = function extend(o/*, objects*/) { if (!isObject(o)) { o = {}; } var len = arguments.length; for (var i = 1; i < len; i++) { var obj = arguments[i]; if (isObject(obj)) { assign(o, obj); } } return o; }; function assign(a, b) { for (var key in b) { if (hasOwn(b, key)) { a[key] = b[key]; } } } /** * Returns true if the given `key` is an own property of `obj`. */ function hasOwn(obj, key) { return Object.prototype.hasOwnProperty.call(obj, key); } return extendShallow; } var sectionMatter; var hasRequiredSectionMatter; function requireSectionMatter () { if (hasRequiredSectionMatter) return sectionMatter; hasRequiredSectionMatter = 1; var typeOf = requireKindOf(); var extend = requireExtendShallow(); /** * Parse sections in `input` with the given `options`. * * ```js * var sections = require('{%= name %}'); * var result = sections(input, options); * // { content: 'Content before sections', sections: [] } * ``` * @param {String|Buffer|Object} `input` If input is an object, it's `content` property must be a string or buffer. * @param {Object} options * @return {Object} Returns an object with a `content` string and an array of `sections` objects. * @api public */ sectionMatter = function(input, options) { if (typeof options === 'function') { options = { parse: options }; } var file = toObject(input); var defaults = {section_delimiter: '---', parse: identity}; var opts = extend({}, defaults, options); var delim = opts.section_delimiter; var lines = file.content.split(/\r?\n/); var sections = null; var section = createSection(); var content = []; var stack = []; function initSections(val) { file.content = val; sections = []; content = []; } function closeSection(val) { if (stack.length) { section.key = getKey(stack[0], delim); section.content = val; opts.parse(section, sections); sections.push(section); section = createSection(); content = []; stack = []; } } for (var i = 0; i < lines.length; i++) { var line = lines[i]; var len = stack.length; var ln = line.trim(); if (isDelimiter(ln, delim)) { if (ln.length === 3 && i !== 0) { if (len === 0 || len === 2) { content.push(line); continue; } stack.push(ln); section.data = content.join('\n'); content = []; continue; } if (sections === null) { initSections(content.join('\n')); } if (len === 2) { closeSection(content.join('\n')); } stack.push(ln); continue; } content.push(line); } if (sections === null) { initSections(content.join('\n')); } else { closeSection(content.join('\n')); } file.sections = sections; return file; }; function isDelimiter(line, delim) { if (line.slice(0, delim.length) !== delim) { return false; } if (line.charAt(delim.length + 1) === delim.slice(-1)) { return false; } return true; } function toObject(input) { if (typeOf(input) !== 'object') { input = { content: input }; } if (typeof input.content !== 'string' && !isBuffer(input.content)) { throw new TypeError('expected a buffer or string'); } input.content = input.content.toString(); input.sections = []; return input; } function getKey(val, delim) { return val ? val.slice(delim.length).trim() : ''; } function createSection() { return { key: '', data: '', content: '' }; } function identity(val) { return val; } function isBuffer(val) { if (val && val.constructor && typeof val.constructor.isBuffer === 'function') { return val.constructor.isBuffer(val); } return false; } return sectionMatter; } var engines = {exports: {}}; var jsYaml$1 = {}; var loader = {}; var common = {}; var hasRequiredCommon; function requireCommon () { if (hasRequiredCommon) return common; hasRequiredCommon = 1; function isNothing(subject) { return (typeof subject === 'undefined') || (subject === null); } function isObject(subject) { return (typeof subject === 'object') && (subject !== null); } function toArray(sequence) { if (Array.isArray(sequence)) return sequence; else if (isNothing(sequence)) return []; return [ sequence ]; } function extend(target, source) { var index, length, key, sourceKeys; if (source) { sourceKeys = Object.keys(source); for (index = 0, length = sourceKeys.length; index < length; index += 1) { key = sourceKeys[index]; target[key] = source[key]; } } return target; } function repeat(string, count) { var result = '', cycle; for (cycle = 0; cycle < count; cycle += 1) { result += string; } return result; } function isNegativeZero(number) { return (number === 0) && (Number.NEGATIVE_INFINITY === 1 / number); } common.isNothing = isNothing; common.isObject = isObject; common.toArray = toArray; common.repeat = repeat; common.isNegativeZero = isNegativeZero; common.extend = extend; return common; } var exception; var hasRequiredException; function requireException () { if (hasRequiredException) return exception; hasRequiredException = 1; function YAMLException(reason, mark) { // Super constructor Error.call(this); this.name = 'YAMLException'; this.reason = reason; this.mark = mark; this.message = (this.reason || '(unknown reason)') + (this.mark ? ' ' + this.mark.toString() : ''); // Include stack trace in error object if (Error.captureStackTrace) { // Chrome and NodeJS Error.captureStackTrace(this, this.constructor); } else { // FF, IE 10+ and Safari 6+. Fallback for others this.stack = (new Error()).stack || ''; } } // Inherit from Error YAMLException.prototype = Object.create(Error.prototype); YAMLException.prototype.constructor = YAMLException; YAMLException.prototype.toString = function toString(compact) { var result = this.name + ': '; result += this.reason || '(unknown reason)'; if (!compact && this.mark) { result += ' ' + this.mark.toString(); } return result; }; exception = YAMLException; return exception; } var mark; var hasRequiredMark; function requireMark () { if (hasRequiredMark) return mark; hasRequiredMark = 1; var common = requireCommon(); function Mark(name, buffer, position, line, column) { this.name = name; this.buffer = buffer; this.position = position; this.line = line; this.column = column; } Mark.prototype.getSnippet = function getSnippet(indent, maxLength) { var head, start, tail, end, snippet; if (!this.buffer) return null; indent = indent || 4; maxLength = maxLength || 75; head = ''; start = this.position; while (start > 0 && '\x00\r\n\x85\u2028\u2029'.indexOf(this.buffer.charAt(start - 1)) === -1) { start -= 1; if (this.position - start > (maxLength / 2 - 1)) { head = ' ... '; start += 5; break; } } tail = ''; end = this.position; while (end < this.buffer.length && '\x00\r\n\x85\u2028\u2029'.indexOf(this.buffer.charAt(end)) === -1) { end += 1; if (end - this.position > (maxLength / 2 - 1)) { tail = ' ... '; end -= 5; break; } } snippet = this.buffer.slice(start, end); return common.repeat(' ', indent) + head + snippet + tail + '\n' + common.repeat(' ', indent + this.position - start + head.length) + '^'; }; Mark.prototype.toString = function toString(compact) { var snippet, where = ''; if (this.name) { where += 'in "' + this.name + '" '; } where += 'at line ' + (this.line + 1) + ', column ' + (this.column + 1); if (!compact) { snippet = this.getSnippet(); if (snippet) { where += ':\n' + snippet; } } return where; }; mark = Mark; return mark; } var type; var hasRequiredType; function requireType () { if (hasRequiredType) return type; hasRequiredType = 1; var YAMLException = requireException(); var TYPE_CONSTRUCTOR_OPTIONS = [ 'kind', 'resolve', 'construct', 'instanceOf', 'predicate', 'represent', 'defaultStyle', 'styleAliases' ]; var YAML_NODE_KINDS = [ 'scalar', 'sequence', 'mapping' ]; function compileStyleAliases(map) { var result = {}; if (map !== null) { Object.keys(map).forEach(function (style) { map[style].forEach(function (alias) { result[String(alias)] = style; }); }); } return result; } function Type(tag, options) { options = options || {}; Object.keys(options).forEach(function (name) { if (TYPE_CONSTRUCTOR_OPTIONS.indexOf(name) === -1) { throw new YAMLException('Unknown option "' + name + '" is met in definition of "' + tag + '" YAML type.'); } }); // TODO: Add tag format check. this.tag = tag; this.kind = options['kind'] || null; this.resolve = options['resolve'] || function () { return true; }; this.construct = options['construct'] || function (data) { return data; }; this.instanceOf = options['instanceOf'] || null; this.predicate = options['predicate'] || null; this.represent = options['represent'] || null; this.defaultStyle = options['defaultStyle'] || null; this.styleAliases = compileStyleAliases(options['styleAliases'] || null); if (YAML_NODE_KINDS.indexOf(this.kind) === -1) { throw new YAMLException('Unknown kind "' + this.kind + '" is specified for "' + tag + '" YAML type.'); } } type = Type; return type; } var schema; var hasRequiredSchema; function requireSchema () { if (hasRequiredSchema) return schema; hasRequiredSchema = 1; /*eslint-disable max-len*/ var common = requireCommon(); var YAMLException = requireException(); var Type = requireType(); function compileList(schema, name, result) { var exclude = []; schema.include.forEach(function (includedSchema) { result = compileList(includedSchema, name, result); }); schema[name].forEach(function (currentType) { result.forEach(function (previousType, previousIndex) { if (previousType.tag === currentType.tag && previousType.kind === currentType.kind) { exclude.push(previousIndex); } }); result.push(currentType); }); return result.filter(function (type, index) { return exclude.indexOf(index) === -1; }); } function compileMap(/* lists... */) { var result = { scalar: {}, sequence: {}, mapping: {}, fallback: {} }, index, length; function collectType(type) { result[type.kind][type.tag] = result['fallback'][type.tag] = type; } for (index = 0, length = arguments.length; index < length; index += 1) { arguments[index].forEach(collectType); } return result; } function Schema(definition) { this.include = definition.include || []; this.implicit = definition.implicit || []; this.explicit = definition.explicit || []; this.implicit.forEach(function (type) { if (type.loadKind && type.loadKind !== 'scalar') { throw new YAMLException('There is a non-scalar type in the implicit list of a schema. Implicit resolving of such types is not supported.'); } }); this.compiledImplicit = compileList(this, 'implicit', []); this.compiledExplicit = compileList(this, 'explicit', []); this.compiledTypeMap = compileMap(this.compiledImplicit, this.compiledExplicit); } Schema.DEFAULT = null; Schema.create = function createSchema() { var schemas, types; switch (arguments.length) { case 1: schemas = Schema.DEFAULT; types = arguments[0]; break; case 2: schemas = arguments[0]; types = arguments[1]; break; default: throw new YAMLException('Wrong number of arguments for Schema.create function'); } schemas = common.toArray(schemas); types = common.toArray(types); if (!schemas.every(function (schema) { return schema instanceof Schema; })) { throw new YAMLException('Specified list of super schemas (or a single Schema object) contains a non-Schema object.'); } if (!types.every(function (type) { return type instanceof Type; })) { throw new YAMLException('Specified list of YAML types (or a single Type object) contains a non-Type object.'); } return new Schema({ include: schemas, explicit: types }); }; schema = Schema; return schema; } var str; var hasRequiredStr; function requireStr () { if (hasRequiredStr) return str; hasRequiredStr = 1; var Type = requireType(); str = new Type('tag:yaml.org,2002:str', { kind: 'scalar', construct: function (data) { return data !== null ? data : ''; } }); return str; } var seq; var hasRequiredSeq; function requireSeq () { if (hasRequiredSeq) return seq; hasRequiredSeq = 1; var Type = requireType(); seq = new Type('tag:yaml.org,2002:seq', { kind: 'sequence', construct: function (data) { return data !== null ? data : []; } }); return seq; } var map$1; var hasRequiredMap; function requireMap () { if (hasRequiredMap) return map$1; hasRequiredMap = 1; var Type = requireType(); map$1 = new Type('tag:yaml.org,2002:map', { kind: 'mapping', construct: function (data) { return data !== null ? data : {}; } }); return map$1; } var failsafe; var hasRequiredFailsafe; function requireFailsafe () { if (hasRequiredFailsafe) return failsafe; hasRequiredFailsafe = 1; var Schema = requireSchema(); failsafe = new Schema({ explicit: [ requireStr(), requireSeq(), requireMap() ] }); return failsafe; } var _null; var hasRequired_null; function require_null () { if (hasRequired_null) return _null; hasRequired_null = 1; var Type = requireType(); function resolveYamlNull(data) { if (data === null) return true; var max = data.length; return (max === 1 && data === '~') || (max === 4 && (data === 'null' || data === 'Null' || data === 'NULL')); } function constructYamlNull() { return null; } function isNull(object) { return object === null; } _null = new Type('tag:yaml.org,2002:null', { kind: 'scalar', resolve: resolveYamlNull, construct: constructYamlNull, predicate: isNull, represent: { canonical: function () { return '~'; }, lowercase: function () { return 'null'; }, uppercase: function () { return 'NULL'; }, camelcase: function () { return 'Null'; } }, defaultStyle: 'lowercase' }); return _null; } var bool; var hasRequiredBool; function requireBool () { if (hasRequiredBool) return bool; hasRequiredBool = 1; var Type = requireType(); function resolveYamlBoolean(data) { if (data === null) return false; var max = data.length; return (max === 4 && (data === 'true' || data === 'True' || data === 'TRUE')) || (max === 5 && (data === 'false' || data === 'False' || data === 'FALSE')); } function constructYamlBoolean(data) { return data === 'true' || data === 'True' || data === 'TRUE'; } function isBoolean(object) { return Object.prototype.toString.call(object) === '[object Boolean]'; } bool = new Type('tag:yaml.org,2002:bool', { kind: 'scalar', resolve: resolveYamlBoolean, construct: constructYamlBoolean, predicate: isBoolean, represent: { lowercase: function (object) { return object ? 'true' : 'false'; }, uppercase: function (object) { return object ? 'TRUE' : 'FALSE'; }, camelcase: function (object) { return object ? 'True' : 'False'; } }, defaultStyle: 'lowercase' }); return bool; } var int; var hasRequiredInt; function requireInt () { if (hasRequiredInt) return int; hasRequiredInt = 1; var common = requireCommon(); var Type = requireType(); function isHexCode(c) { return ((0x30/* 0 */ <= c) && (c <= 0x39/* 9 */)) || ((0x41/* A */ <= c) && (c <= 0x46/* F */)) || ((0x61/* a */ <= c) && (c <= 0x66/* f */)); } function isOctCode(c) { return ((0x30/* 0 */ <= c) && (c <= 0x37/* 7 */)); } function isDecCode(c) { return ((0x30/* 0 */ <= c) && (c <= 0x39/* 9 */)); } function resolveYamlInteger(data) { if (data === null) return false; var max = data.length, index = 0, hasDigits = false, ch; if (!max) return false; ch = data[index]; // sign if (ch === '-' || ch === '+') { ch = data[++index]; } if (ch === '0') { // 0 if (index + 1 === max) return true; ch = data[++index]; // base 2, base 8, base 16 if (ch === 'b') { // base 2 index++; for (; index < max; index++) { ch = data[index]; if (ch === '_') continue; if (ch !== '0' && ch !== '1') return false; hasDigits = true; } return hasDigits && ch !== '_'; } if (ch === 'x') { // base 16 index++; for (; index < max; index++) { ch = data[index]; if (ch === '_') continue; if (!isHexCode(data.charCodeAt(index))) return false; hasDigits = true; } return hasDigits && ch !== '_'; } // base 8 for (; index < max; index++) { ch = data[index]; if (ch === '_') continue; if (!isOctCode(data.charCodeAt(index))) return false; hasDigits = true; } return hasDigits && ch !== '_'; } // base 10 (except 0) or base 60 // value should not start with `_`; if (ch === '_') return false; for (; index < max; index++) { ch = data[index]; if (ch === '_') continue; if (ch === ':') break; if (!isDecCode(data.charCodeAt(index))) { return false; } hasDigits = true; } // Should have digits and should not end with `_` if (!hasDigits || ch === '_') return false; // if !base60 - done; if (ch !== ':') return true; // base60 almost not used, no needs to optimize return /^(:[0-5]?[0-9])+$/.test(data.slice(index)); } function constructYamlInteger(data) { var value = data, sign = 1, ch, base, digits = []; if (value.indexOf('_') !== -1) { value = value.replace(/_/g, ''); } ch = value[0]; if (ch === '-' || ch === '+') { if (ch === '-') sign = -1; value = value.slice(1); ch = value[0]; } if (value === '0') return 0; if (ch === '0') { if (value[1] === 'b') return sign * parseInt(value.slice(2), 2); if (value[1] === 'x') return sign * parseInt(value, 16); return sign * parseInt(value, 8); } if (value.indexOf(':') !== -1) { value.split(':').forEach(function (v) { digits.unshift(parseInt(v, 10)); }); value = 0; base = 1; digits.forEach(function (d) { value += (d * base); base *= 60; }); return sign * value; } return sign * parseInt(value, 10); } function isInteger(object) { return (Object.prototype.toString.call(object)) === '[object Number]' && (object % 1 === 0 && !common.isNegativeZero(object)); } int = new Type('tag:yaml.org,2002:int', { kind: 'scalar', resolve: resolveYamlInteger, construct: constructYamlInteger, predicate: isInteger, represent: { binary: function (obj) { return obj >= 0 ? '0b' + obj.toString(2) : '-0b' + obj.toString(2).slice(1); }, octal: function (obj) { return obj >= 0 ? '0' + obj.toString(8) : '-0' + obj.toString(8).slice(1); }, decimal: function (obj) { return obj.toString(10); }, /* eslint-disable max-len */ hexadecimal: function (obj) { return obj >= 0 ? '0x' + obj.toString(16).toUpperCase() : '-0x' + obj.toString(16).toUpperCase().slice(1); } }, defaultStyle: 'decimal', styleAliases: { binary: [ 2, 'bin' ], octal: [ 8, 'oct' ], decimal: [ 10, 'dec' ], hexadecimal: [ 16, 'hex' ] } }); return int; } var float; var hasRequiredFloat; function requireFloat () { if (hasRequiredFloat) return float; hasRequiredFloat = 1; var common = requireCommon(); var Type = requireType(); var YAML_FLOAT_PATTERN = new RegExp( // 2.5e4, 2.5 and integers '^(?:[-+]?(?:0|[1-9][0-9_]*)(?:\\.[0-9_]*)?(?:[eE][-+]?[0-9]+)?' + // .2e4, .2 // special case, seems not from spec '|\\.[0-9_]+(?:[eE][-+]?[0-9]+)?' + // 20:59 '|[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*' + // .inf '|[-+]?\\.(?:inf|Inf|INF)' + // .nan '|\\.(?:nan|NaN|NAN))$'); function resolveYamlFloat(data) { if (data === null) return false; if (!YAML_FLOAT_PATTERN.test(data) || // Quick hack to not allow integers end with `_` // Probably should update regexp & check speed data[data.length - 1] === '_') { return false; } return true; } function constructYamlFloat(data) { var value, sign, base, digits; value = data.replace(/_/g, '').toLowerCase(); sign = value[0] === '-' ? -1 : 1; digits = []; if ('+-'.indexOf(value[0]) >= 0) { value = value.slice(1); } if (value === '.inf') { return (sign === 1) ? Number.POSITIVE_INFINITY : Number.NEGATIVE_INFINITY; } else if (value === '.nan') { return NaN; } else if (value.indexOf(':') >= 0) { value.split(':').forEach(function (v) { digits.unshift(parseFloat(v, 10)); }); value = 0.0; base = 1; digits.forEach(function (d) { value += d * base; base *= 60; }); return sign * value; } return sign * parseFloat(value, 10); } var SCIENTIFIC_WITHOUT_DOT = /^[-+]?[0-9]+e/; function representYamlFloat(object, style) { var res; if (isNaN(object)) { switch (style) { case 'lowercase': return '.nan'; case 'uppercase': return '.NAN'; case 'camelcase': return '.NaN'; } } else if (Number.POSITIVE_INFINITY === object) { switch (style) { case 'lowercase': return '.inf'; case 'uppercase': return '.INF'; case 'camelcase': return '.Inf'; } } else if (Number.NEGATIVE_INFINITY === object) { switch (style) { case 'lowercase': return '-.inf'; case 'uppercase': return '-.INF'; case 'camelcase': return '-.Inf'; } } else if (common.isNegativeZero(object)) { return '-0.0'; } res = object.toString(10); // JS stringifier can build scientific format without dots: 5e-100, // while YAML requres dot: 5.e-100. Fix it with simple hack return SCIENTIFIC_WITHOUT_DOT.test(res) ? res.replace('e', '.e') : res; } function isFloat(object) { return (Object.prototype.toString.call(object) === '[object Number]') && (object % 1 !== 0 || common.isNegativeZero(object)); } float = new Type('tag:yaml.org,2002:float', { kind: 'scalar', resolve: resolveYamlFloat, construct: constructYamlFloat, predicate: isFloat, represent: representYamlFloat, defaultStyle: 'lowercase' }); return float; } var json; var hasRequiredJson; function requireJson () { if (hasRequiredJson) return json; hasRequiredJson = 1; var Schema = requireSchema(); json = new Schema({ include: [ requireFailsafe() ], implicit: [ require_null(), requireBool(), requireInt(), requireFloat() ] }); return json; } var core; var hasRequiredCore; function requireCore () { if (hasRequiredCore) return core; hasRequiredCore = 1; var Schema = requireSchema(); core = new Schema({ include: [ requireJson() ] }); return core; } var timestamp; var hasRequiredTimestamp; function requireTimestamp () { if (hasRequiredTimestamp) return timestamp; hasRequiredTimestamp = 1; var Type = requireType(); var YAML_DATE_REGEXP = new RegExp( '^([0-9][0-9][0-9][0-9])' + // [1] year '-([0-9][0-9])' + // [2] month '-([0-9][0-9])$'); // [3] day var YAML_TIMESTAMP_REGEXP = new RegExp( '^([0-9][0-9][0-9][0-9])' + // [1] year '-([0-9][0-9]?)' + // [2] month '-([0-9][0-9]?)' + // [3] day '(?:[Tt]|[ \\t]+)' + // ... '([0-9][0-9]?)' + // [4] hour ':([0-9][0-9])' + // [5] minute ':([0-9][0-9])' + // [6] second '(?:\\.([0-9]*))?' + // [7] fraction '(?:[ \\t]*(Z|([-+])([0-9][0-9]?)' + // [8] tz [9] tz_sign [10] tz_hour '(?::([0-9][0-9]))?))?$'); // [11] tz_minute function resolveYamlTimestamp(data) { if (data === null) return false; if (YAML_DATE_REGEXP.exec(data) !== null) return true; if (YAML_TIMESTAMP_REGEXP.exec(data) !== null) return true; return false; } function constructYamlTimestamp(data) { var match, year, month, day, hour, minute, second, fraction = 0, delta = null, tz_hour, tz_minute, date; match = YAML_DATE_REGEXP.exec(data); if (match === null) match = YAML_TIMESTAMP_REGEXP.exec(data); if (match === null) throw new Error('Date resolve error'); // match: [1] year [2] month [3] day year = +(match[1]); month = +(match[2]) - 1; // JS month starts with 0 day = +(match[3]); if (!match[4]) { // no hour return new Date(Date.UTC(year, month, day)); } // match: [4] hour [5] minute [6] second [7] fraction hour = +(match[4]); minute = +(match[5]); second = +(match[6]); if (match[7]) { fraction = match[7].slice(0, 3); while (fraction.length < 3) { // milli-seconds fraction += '0'; } fraction = +fraction; } // match: [8] tz [9] tz_sign [10] tz_hour [11] tz_minute if (match[9]) { tz_hour = +(match[10]); tz_minute = +(match[11] || 0); delta = (tz_hour * 60 + tz_minute) * 60000; // delta in mili-seconds if (match[9] === '-') delta = -delta; } date = new Date(Date.UTC(year, month, day, hour, minute, second, fraction)); if (delta) date.setTime(date.getTime() - delta); return date; } function representYamlTimestamp(object /*, style*/) { return object.toISOString(); } timestamp = new Type('tag:yaml.org,2002:timestamp', { kind: 'scalar', resolve: resolveYamlTimestamp, construct: constructYamlTimestamp, instanceOf: Date, represent: representYamlTimestamp }); return timestamp; } var merge; var hasRequiredMerge; function requireMerge () { if (hasRequiredMerge) return merge; hasRequiredMerge = 1; var Type = requireType(); function resolveYamlMerge(data) { return data === '<<' || data === null; } merge = new Type('tag:yaml.org,2002:merge', { kind: 'scalar', resolve: resolveYamlMerge }); return merge; } function commonjsRequire(path) { throw new Error('Could not dynamically require "' + path + '". Please configure the dynamicRequireTargets or/and ignoreDynamicRequires option of @rollup/plugin-commonjs appropriately for this require call to work.'); } var binary$1; var hasRequiredBinary; function requireBinary () { if (hasRequiredBinary) return binary$1; hasRequiredBinary = 1; /*eslint-disable no-bitwise*/ var NodeBuffer; try { // A trick for browserified version, to not include `Buffer` shim var _require = commonjsRequire; NodeBuffer = _require('buffer').Buffer; } catch (__) {} var Type = requireType(); // [ 64, 65, 66 ] -> [ padding, CR, LF ] var BASE64_MAP = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n\r'; function resolveYamlBinary(data) { if (data === null) return false; var code, idx, bitlen = 0, max = data.length, map = BASE64_MAP; // Convert one by one. for (idx = 0; idx < max; idx++) { code = map.indexOf(data.charAt(idx)); // Skip CR/LF if (code > 64) continue; // Fail on illegal characters if (code < 0) return false; bitlen += 6; } // If there are any bits left, source was corrupted return (bitlen % 8) === 0; } function constructYamlBinary(data) { var idx, tailbits, input = data.replace(/[\r\n=]/g, ''), // remove CR/LF & padding to simplify scan max = input.length, map = BASE64_MAP, bits = 0, result = []; // Collect by 6*4 bits (3 bytes) for (idx = 0; idx < max; idx++) { if ((idx % 4 === 0) && idx) { result.push((bits >> 16) & 0xFF); result.push((bits >> 8) & 0xFF); result.push(bits & 0xFF); } bits = (bits << 6) | map.indexOf(input.charAt(idx)); } // Dump tail tailbits = (max % 4) * 6; if (tailbits === 0) { result.push((bits >> 16) & 0xFF); result.push((bits >> 8) & 0xFF); result.push(bits & 0xFF); } else if (tailbits === 18) { result.push((bits >> 10) & 0xFF); result.push((bits >> 2) & 0xFF); } else if (tailbits === 12) { result.push((bits >> 4) & 0xFF); } // Wrap into Buffer for NodeJS and leave Array for browser if (NodeBuffer) { // Support node 6.+ Buffer API when available return NodeBuffer.from ? NodeBuffer.from(result) : new NodeBuffer(result); } return result; } function representYamlBinary(object /*, style*/) { var result = '', bits = 0, idx, tail, max = object.length, map = BASE64_MAP; // Convert every three bytes to 4 ASCII characters. for (idx = 0; idx < max; idx++) { if ((idx % 3 === 0) && idx) { result += map[(bits >> 18) & 0x3F]; result += map[(bits >> 12) & 0x3F]; result += map[(bits >> 6) & 0x3F]; result += map[bits & 0x3F]; } bits = (bits << 8) + object[idx]; } // Dump tail tail = max % 3; if (tail === 0) { result += map[(bits >> 18) & 0x3F]; result += map[(bits >> 12) & 0x3F]; result += map[(bits >> 6) & 0x3F]; result += map[bits & 0x3F]; } else if (tail === 2) { result += map[(bits >> 10) & 0x3F]; result += map[(bits >> 4) & 0x3F]; result += map[(bits << 2) & 0x3F]; result += map[64]; } else if (tail === 1) { result += map[(bits >> 2) & 0x3F]; result += map[(bits << 4) & 0x3F]; result += map[64]; result += map[64]; } return result; } function isBinary(object) { return NodeBuffer && NodeBuffer.isBuffer(object); } binary$1 = new Type('tag:yaml.org,2002:binary', { kind: 'scalar', resolve: resolveYamlBinary, construct: constructYamlBinary, predicate: isBinary, represent: representYamlBinary }); return binary$1; } var omap; var hasRequiredOmap; function requireOmap () { if (hasRequiredOmap) return omap; hasRequiredOmap = 1; var Type = requireType(); var _hasOwnProperty = Object.prototype.hasOwnProperty; var _toString = Object.prototype.toString; function resolveYamlOmap(data) { if (data === null) return true; var objectKeys = [], index, length, pair, pairKey, pairHasKey, object = data; for (index = 0, length = object.length; index < length; index += 1) { pair = object[index]; pairHasKey = false; if (_toString.call(pair) !== '[object Object]') return false; for (pairKey in pair) { if (_hasOwnProperty.call(pair, pairKey)) { if (!pairHasKey) pairHasKey = true; else return false; } } if (!pairHasKey) return false; if (objectKeys.indexOf(pairKey) === -1) objectKeys.push(pairKey); else return false; } return true; } function constructYamlOmap(data) { return data !== null ? data : []; } omap = new Type('tag:yaml.org,2002:omap', { kind: 'sequence', resolve: resolveYamlOmap, construct: constructYamlOmap }); return omap; } var pairs; var hasRequiredPairs; function requirePairs () { if (hasRequiredPairs) return pairs; hasRequiredPairs = 1; var Type = requireType(); var _toString = Object.prototype.toString; function resolveYamlPairs(data) { if (data === null) return true; var index, length, pair, keys, result, object = data; result = new Array(object.length); for (index = 0, length = object.length; index < length; index += 1) { pair = object[index]; if (_toString.call(pair) !== '[object Object]') return false; keys = Object.keys(pair); if (keys.length !== 1) return false; result[index] = [ keys[0], pair[keys[0]] ]; } return true; } function constructYamlPairs(data) { if (data === null) return []; var index, length, pair, keys, result, object = data; result = new Array(object.length); for (index = 0, length = object.length; index < length; index += 1) { pair = object[index]; keys = Object.keys(pair); result[index] = [ keys[0], pair[keys[0]] ]; } return result; } pairs = new Type('tag:yaml.org,2002:pairs', { kind: 'sequence', resolve: resolveYamlPairs, construct: constructYamlPairs }); return pairs; } var set; var hasRequiredSet; function requireSet () { if (hasRequiredSet) return set; hasRequiredSet = 1; var Type = requireType(); var _hasOwnProperty = Object.prototype.hasOwnProperty; function resolveYamlSet(data) { if (data === null) return true; var key, object = data; for (key in object) { if (_hasOwnProperty.call(object, key)) { if (object[key] !== null) return false; } } return true; } function constructYamlSet(data) { return data !== null ? data : {}; } set = new Type('tag:yaml.org,2002:set', { kind: 'mapping', resolve: resolveYamlSet, construct: constructYamlSet }); return set; } var default_safe; var hasRequiredDefault_safe; function requireDefault_safe () { if (hasRequiredDefault_safe) return default_safe; hasRequiredDefault_safe = 1; var Schema = requireSchema(); default_safe = new Schema({ include: [ requireCore() ], implicit: [ requireTimestamp(), requireMerge() ], explicit: [ requireBinary(), requireOmap(), requirePairs(), requireSet() ] }); return default_safe; } var _undefined; var hasRequired_undefined; function require_undefined () { if (hasRequired_undefined) return _undefined; hasRequired_undefined = 1; var Type = requireType(); function resolveJavascriptUndefined() { return true; } function constructJavascriptUndefined() { /*eslint-disable no-undefined*/ return undefined; } function representJavascriptUndefined() { return ''; } function isUndefined(object) { return typeof object === 'undefined'; } _undefined = new Type('tag:yaml.org,2002:js/undefined', { kind: 'scalar', resolve: resolveJavascriptUndefined, construct: constructJavascriptUndefined, predicate: isUndefined, represent: representJavascriptUndefined }); return _undefined; } var regexp; var hasRequiredRegexp; function requireRegexp () { if (hasRequiredRegexp) return regexp; hasRequiredRegexp = 1; var Type = requireType(); function resolveJavascriptRegExp(data) { if (data === null) return false; if (data.length === 0) return false; var regexp = data, tail = /\/([gim]*)$/.exec(data), modifiers = ''; // if regexp starts with '/' it can have modifiers and must be properly closed // `/foo/gim` - modifiers tail can be maximum 3 chars if (regexp[0] === '/') { if (tail) modifiers = tail[1]; if (modifiers.length > 3) return false; // if expression starts with /, is should be properly terminated if (regexp[regexp.length - modifiers.length - 1] !== '/') return false; } return true; } function constructJavascriptRegExp(data) { var regexp = data, tail = /\/([gim]*)$/.exec(data), modifiers = ''; // `/foo/gim` - tail can be maximum 4 chars if (regexp[0] === '/') { if (tail) modifiers = tail[1]; regexp = regexp.slice(1, regexp.length - modifiers.length - 1); } return new RegExp(regexp, modifiers); } function representJavascriptRegExp(object /*, style*/) { var result = '/' + object.source + '/'; if (object.global) result += 'g'; if (object.multiline) result += 'm'; if (object.ignoreCase) result += 'i'; return result; } function isRegExp(object) { return Object.prototype.toString.call(object) === '[object RegExp]'; } regexp = new Type('tag:yaml.org,2002:js/regexp', { kind: 'scalar', resolve: resolveJavascriptRegExp, construct: constructJavascriptRegExp, predicate: isRegExp, represent: representJavascriptRegExp }); return regexp; } var _function; var hasRequired_function; function require_function () { if (hasRequired_function) return _function; hasRequired_function = 1; var esprima; // Browserified version does not have esprima // // 1. For node.js just require module as deps // 2. For browser try to require mudule via external AMD system. // If not found - try to fallback to window.esprima. If not // found too - then fail to parse. // try { // workaround to exclude package from browserify list. var _require = commonjsRequire; esprima = _require('esprima'); } catch (_) { /* eslint-disable no-redeclare */ /* global window */ if (typeof window !== 'undefined') esprima = window.esprima; } var Type = requireType(); function resolveJavascriptFunction(data) { if (data === null) return false; try { var source = '(' + data + ')', ast = esprima.parse(source, { range: true }); if (ast.type !== 'Program' || ast.body.length !== 1 || ast.body[0].type !== 'ExpressionStatement' || (ast.body[0].expression.type !== 'ArrowFunctionExpression' && ast.body[0].expression.type !== 'FunctionExpression')) { return false; } return true; } catch (err) { return false; } } function constructJavascriptFunction(data) { /*jslint evil:true*/ var source = '(' + data + ')', ast = esprima.parse(source, { range: true }), params = [], body; if (ast.type !== 'Program' || ast.body.length !== 1 || ast.body[0].type !== 'ExpressionStatement' || (ast.body[0].expression.type !== 'ArrowFunctionExpression' && ast.body[0].expression.type !== 'FunctionExpression')) { throw new Error('Failed to resolve function'); } ast.body[0].expression.params.forEach(function (param) { params.push(param.name); }); body = ast.body[0].expression.body.range; // Esprima's ranges include the first '{' and the last '}' characters on // function expressions. So cut them out. if (ast.body[0].expression.body.type === 'BlockStatement') { /*eslint-disable no-new-func*/ return new Function(params, source.slice(body[0] + 1, body[1] - 1)); } // ES6 arrow functions can omit the BlockStatement. In that case, just return // the body. /*eslint-disable no-new-func*/ return new Function(params, 'return ' + source.slice(body[0], body[1])); } function representJavascriptFunction(object /*, style*/) { return object.toString(); } function isFunction(object) { return Object.prototype.toString.call(object) === '[object Function]'; } _function = new Type('tag:yaml.org,2002:js/function', { kind: 'scalar', resolve: resolveJavascriptFunction, construct: constructJavascriptFunction, predicate: isFunction, represent: representJavascriptFunction }); return _function; } var default_full; var hasRequiredDefault_full; function requireDefault_full () { if (hasRequiredDefault_full) return default_full; hasRequiredDefault_full = 1; var Schema = requireSchema(); default_full = Schema.DEFAULT = new Schema({ include: [ requireDefault_safe() ], explicit: [ require_undefined(), requireRegexp(), require_function() ] }); return default_full; } var hasRequiredLoader; function requireLoader () { if (hasRequiredLoader) return loader; hasRequiredLoader = 1; /*eslint-disable max-len,no-use-before-define*/ var common = requireCommon(); var YAMLException = requireException(); var Mark = requireMark(); var DEFAULT_SAFE_SCHEMA = requireDefault_safe(); var DEFAULT_FULL_SCHEMA = requireDefault_full(); var _hasOwnProperty = Object.prototype.hasOwnProperty; var CONTEXT_FLOW_IN = 1; var CONTEXT_FLOW_OUT = 2; var CONTEXT_BLOCK_IN = 3; var CONTEXT_BLOCK_OUT = 4; var CHOMPING_CLIP = 1; var CHOMPING_STRIP = 2; var CHOMPING_KEEP = 3; var PATTERN_NON_PRINTABLE = /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x84\x86-\x9F\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/; var PATTERN_NON_ASCII_LINE_BREAKS = /[\x85\u2028\u2029]/; var PATTERN_FLOW_INDICATORS = /[,\[\]\{\}]/; var PATTERN_TAG_HANDLE = /^(?:!|!!|![a-z\-]+!)$/i; var PATTERN_TAG_URI = /^(?:!|[^,\[\]\{\}])(?:%[0-9a-f]{2}|[0-9a-z\-#;\/\?:@&=\+\$,_\.!~\*'\(\)\[\]])*$/i; function _class(obj) { return Object.prototype.toString.call(obj); } function is_EOL(c) { return (c === 0x0A/* LF */) || (c === 0x0D/* CR */); } function is_WHITE_SPACE(c) { return (c === 0x09/* Tab */) || (c === 0x20/* Space */); } function is_WS_OR_EOL(c) { return (c === 0x09/* Tab */) || (c === 0x20/* Space */) || (c === 0x0A/* LF */) || (c === 0x0D/* CR */); } function is_FLOW_INDICATOR(c) { return c === 0x2C/* , */ || c === 0x5B/* [ */ || c === 0x5D/* ] */ || c === 0x7B/* { */ || c === 0x7D/* } */; } function fromHexCode(c) { var lc; if ((0x30/* 0 */ <= c) && (c <= 0x39/* 9 */)) { return c - 0x30; } /*eslint-disable no-bitwise*/ lc = c | 0x20; if ((0x61/* a */ <= lc) && (lc <= 0x66/* f */)) { return lc - 0x61 + 10; } return -1; } function escapedHexLen(c) { if (c === 0x78/* x */) { return 2; } if (c === 0x75/* u */) { return 4; } if (c === 0x55/* U */) { return 8; } return 0; } function fromDecimalCode(c) { if ((0x30/* 0 */ <= c) && (c <= 0x39/* 9 */)) { return c - 0x30; } return -1; } function simpleEscapeSequence(c) { /* eslint-disable indent */ return (c === 0x30/* 0 */) ? '\x00' : (c === 0x61/* a */) ? '\x07' : (c === 0x62/* b */) ? '\x08' : (c === 0x74/* t */) ? '\x09' : (c === 0x09/* Tab */) ? '\x09' : (c === 0x6E/* n */) ? '\x0A' : (c === 0x76/* v */) ? '\x0B' : (c === 0x66/* f */) ? '\x0C' : (c === 0x72/* r */) ? '\x0D' : (c === 0x65/* e */) ? '\x1B' : (c === 0x20/* Space */) ? ' ' : (c === 0x22/* " */) ? '\x22' : (c === 0x2F/* / */) ? '/' : (c === 0x5C/* \ */) ? '\x5C' : (c === 0x4E/* N */) ? '\x85' : (c === 0x5F/* _ */) ? '\xA0' : (c === 0x4C/* L */) ? '\u2028' : (c === 0x50/* P */) ? '\u2029' : ''; } function charFromCodepoint(c) { if (c <= 0xFFFF) { return String.fromCharCode(c); } // Encode UTF-16 surrogate pair // https://en.wikipedia.org/wiki/UTF-16#Code_points_U.2B010000_to_U.2B10FFFF return String.fromCharCode( ((c - 0x010000) >> 10) + 0xD800, ((c - 0x010000) & 0x03FF) + 0xDC00 ); } // set a property of a literal object, while protecting against prototype pollution, // see https://github.com/nodeca/js-yaml/issues/164 for more details function setProperty(object, key, value) { // used for this specific key only because Object.defineProperty is slow if (key === '__proto__') { Object.defineProperty(object, key, { configurable: true, enumerable: true, writable: true, value: value }); } else { object[key] = value; } } var simpleEscapeCheck = new Array(256); // integer, for fast access var simpleEscapeMap = new Array(256); for (var i = 0; i < 256; i++) { simpleEscapeCheck[i] = simpleEscapeSequence(i) ? 1 : 0; simpleEscapeMap[i] = simpleEscapeSequence(i); } function State(input, options) { this.input = input; this.filename = options['filename'] || null; this.schema = options['schema'] || DEFAULT_FULL_SCHEMA; this.onWarning = options['onWarning'] || null; this.legacy = options['legacy'] || false; this.json = options['json'] || false; this.listener = options['listener'] || null; this.implicitTypes = this.schema.compiledImplicit; this.typeMap = this.schema.compiledTypeMap; this.length = input.length; this.position = 0; this.line = 0; this.lineStart = 0; this.lineIndent = 0; this.documents = []; /* this.version; this.checkLineBreaks; this.tagMap; this.anchorMap; this.tag; this.anchor; this.kind; this.result;*/ } function generateError(state, message) { return new YAMLException( message, new Mark(state.filename, state.input, state.position, state.line, (state.position - state.lineStart))); } function throwError(state, message) { throw generateError(state, message); } function throwWarning(state, message) { if (state.onWarning) { state.onWarning.call(null, generateError(state, message)); } } var directiveHandlers = { YAML: function handleYamlDirective(state, name, args) { var match, major, minor; if (state.version !== null) { throwError(state, 'duplication of %YAML directive'); } if (args.length !== 1) { throwError(state, 'YAML directive accepts exactly one argument'); } match = /^([0-9]+)\.([0-9]+)$/.exec(args[0]); if (match === null) { throwError(state, 'ill-formed argument of the YAML directive'); } major = parseInt(match[1], 10); minor = parseInt(match[2], 10); if (major !== 1) { throwError(state, 'unacceptable YAML version of the document'); } state.version = args[0]; state.checkLineBreaks = (minor < 2); if (minor !== 1 && minor !== 2) { throwWarning(state, 'unsupported YAML version of the document'); } }, TAG: function handleTagDirective(state, name, args) { var handle, prefix; if (args.length !== 2) { throwError(state, 'TAG directive accepts exactly two arguments'); } handle = args[0]; prefix = args[1]; if (!PATTERN_TAG_HANDLE.test(handle)) { throwError(state, 'ill-formed tag handle (first argument) of the TAG directive'); } if (_hasOwnProperty.call(state.tagMap, handle)) { throwError(state, 'there is a previously declared suffix for "' + handle + '" tag handle'); } if (!PATTERN_TAG_URI.test(prefix)) { throwError(state, 'ill-formed tag prefix (second argument) of the TAG directive'); } state.tagMap[handle] = prefix; } }; function captureSegment(state, start, end, checkJson) { var _position, _length, _character, _result; if (start < end) { _result = state.input.slice(start, end); if (checkJson) { for (_position = 0, _length = _result.length; _position < _length; _position += 1) { _character = _result.charCodeAt(_position); if (!(_character === 0x09 || (0x20 <= _character && _character <= 0x10FFFF))) { throwError(state, 'expected valid JSON character'); } } } else if (PATTERN_NON_PRINTABLE.test(_result)) { throwError(state, 'the stream contains non-printable characters'); } state.result += _result; } } function mergeMappings(state, destination, source, overridableKeys) { var sourceKeys, key, index, quantity; if (!common.isObject(source)) { throwError(state, 'cannot merge mappings; the provided source object is unacceptable'); } sourceKeys = Object.keys(source); for (index = 0, quantity = sourceKeys.length; index < quantity; index += 1) { key = sourceKeys[index]; if (!_hasOwnProperty.call(destination, key)) { setProperty(destination, key, source[key]); overridableKeys[key] = true; } } } function storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode, startLine, startPos) { var index, quantity; // The output is a plain object here, so keys can only be strings. // We need to convert keyNode to a string, but doing so can hang the process // (deeply nested arrays that explode exponentially using aliases). if (Array.isArray(keyNode)) { keyNode = Array.prototype.slice.call(keyNode); for (index = 0, quantity = keyNode.length; index < quantity; index += 1) { if (Array.isArray(keyNode[index])) { throwError(state, 'nested arrays are not supported inside keys'); } if (typeof keyNode === 'object' && _class(keyNode[index]) === '[object Object]') { keyNode[index] = '[object Object]'; } } } // Avoid code execution in load() via toString property // (still use its own toString for arrays, timestamps, // and whatever user schema extensions happen to have @@toStringTag) if (typeof keyNode === 'object' && _class(keyNode) === '[object Object]') { keyNode = '[object Object]'; } keyNode = String(keyNode); if (_result === null) { _result = {}; } if (keyTag === 'tag:yaml.org,2002:merge') { if (Array.isArray(valueNode)) { for (index = 0, quantity = valueNode.length; index < quantity; index += 1) { mergeMappings(state, _result, valueNode[index], overridableKeys); } } else { mergeMappings(state, _result, valueNode, overridableKeys); } } else { if (!state.json && !_hasOwnProperty.call(overridableKeys, keyNode) && _hasOwnProperty.call(_result, keyNode)) { state.line = startLine || state.line; state.position = startPos || state.position; throwError(state, 'duplicated mapping key'); } setProperty(_result, keyNode, valueNode); delete overridableKeys[keyNode]; } return _result; } function readLineBreak(state) { var ch; ch = state.input.charCodeAt(state.position); if (ch === 0x0A/* LF */) { state.position++; } else if (ch === 0x0D/* CR */) { state.position++; if (state.input.charCodeAt(state.position) === 0x0A/* LF */) { state.position++; } } else { throwError(state, 'a line break is expected'); } state.line += 1; state.lineStart = state.position; } function skipSeparationSpace(state, allowComments, checkIndent) { var lineBreaks = 0, ch = state.input.charCodeAt(state.position); while (ch !== 0) { while (is_WHITE_SPACE(ch)) { ch = state.input.charCodeAt(++state.position); } if (allowComments && ch === 0x23/* # */) { do { ch = state.input.charCodeAt(++state.position); } while (ch !== 0x0A/* LF */ && ch !== 0x0D/* CR */ && ch !== 0); } if (is_EOL(ch)) { readLineBreak(state); ch = state.input.charCodeAt(state.position); lineBreaks++; state.lineIndent = 0; while (ch === 0x20/* Space */) { state.lineIndent++; ch = state.input.charCodeAt(++state.position); } } else { break; } } if (checkIndent !== -1 && lineBreaks !== 0 && state.lineIndent < checkIndent) { throwWarning(state, 'deficient indentation'); } return lineBreaks; } function testDocumentSeparator(state) { var _position = state.position, ch; ch = state.input.charCodeAt(_position); // Condition state.position === state.lineStart is tested // in parent on each call, for efficiency. No needs to test here again. if ((ch === 0x2D/* - */ || ch === 0x2E/* . */) && ch === state.input.charCodeAt(_position + 1) && ch === state.input.charCodeAt(_position + 2)) { _position += 3; ch = state.input.charCodeAt(_position); if (ch === 0 || is_WS_OR_EOL(ch)) { return true; } } return false; } function writeFoldedLines(state, count) { if (count === 1) { state.result += ' '; } else if (count > 1) { state.result += common.repeat('\n', count - 1); } } function readPlainScalar(state, nodeIndent, withinFlowCollection) { var preceding, following, captureStart, captureEnd, hasPendingContent, _line, _lineStart, _lineIndent, _kind = state.kind, _result = state.result, ch; ch = state.input.charCodeAt(state.position); if (is_WS_OR_EOL(ch) || is_FLOW_INDICATOR(ch) || ch === 0x23/* # */ || ch === 0x26/* & */ || ch === 0x2A/* * */ || ch === 0x21/* ! */ || ch === 0x7C/* | */ || ch === 0x3E/* > */ || ch === 0x27/* ' */ || ch === 0x22/* " */ || ch === 0x25/* % */ || ch === 0x40/* @ */ || ch === 0x60/* ` */) { return false; } if (ch === 0x3F/* ? */ || ch === 0x2D/* - */) { following = state.input.charCodeAt(state.position + 1); if (is_WS_OR_EOL(following) || withinFlowCollection && is_FLOW_INDICATOR(following)) { return false; } } state.kind = 'scalar'; state.result = ''; captureStart = captureEnd = state.position; hasPendingContent = false; while (ch !== 0) { if (ch === 0x3A/* : */) { following = state.input.charCodeAt(state.position + 1); if (is_WS_OR_EOL(following) || withinFlowCollection && is_FLOW_INDICATOR(following)) { break; } } else if (ch === 0x23/* # */) { preceding = state.input.charCodeAt(state.position - 1); if (is_WS_OR_EOL(preceding)) { break; } } else if ((state.position === state.lineStart && testDocumentSeparator(state)) || withinFlowCollection && is_FLOW_INDICATOR(ch)) { break; } else if (is_EOL(ch)) { _line = state.line; _lineStart = state.lineStart; _lineIndent = state.lineIndent; skipSeparationSpace(state, false, -1); if (state.lineIndent >= nodeIndent) { hasPendingContent = true; ch = state.input.charCodeAt(state.position); continue; } else { state.position = captureEnd; state.line = _line; state.lineStart = _lineStart; state.lineIndent = _lineIndent; break; } } if (hasPendingContent) { captureSegment(state, captureStart, captureEnd, false); writeFoldedLines(state, state.line - _line); captureStart = captureEnd = state.position; hasPendingContent = false; } if (!is_WHITE_SPACE(ch)) { captureEnd = state.position + 1; } ch = state.input.charCodeAt(++state.position); } captureSegment(state, captureStart, captureEnd, false); if (state.result) { return true; } state.kind = _kind; state.result = _result; return false; } function readSingleQuotedScalar(state, nodeIndent) { var ch, captureStart, captureEnd; ch = state.input.charCodeAt(state.position); if (ch !== 0x27/* ' */) { return false; } state.kind = 'scalar'; state.result = ''; state.position++; captureStart = captureEnd = state.position; while ((ch = state.input.charCodeAt(state.position)) !== 0) { if (ch === 0x27/* ' */) { captureSegment(state, captureStart, state.position, true); ch = state.input.charCodeAt(++state.position); if (ch === 0x27/* ' */) { captureStart = state.position; state.position++; captureEnd = state.position; } else { return true; } } else if (is_EOL(ch)) { captureSegment(state, captureStart, captureEnd, true); writeFoldedLines(state, skipSeparationSpace(state, false, nodeIndent)); captureStart = captureEnd = state.position; } else if (state.position === state.lineStart && testDocumentSeparator(state)) { throwError(state, 'unexpected end of the document within a single quoted scalar'); } else { state.position++; captureEnd = state.position; } } throwError(state, 'unexpected end of the stream within a single quoted scalar'); } function readDoubleQuotedScalar(state, nodeIndent) { var captureStart, captureEnd, hexLength, hexResult, tmp, ch; ch = state.input.charCodeAt(state.position); if (ch !== 0x22/* " */) { return false; } state.kind = 'scalar'; state.result = ''; state.position++; captureStart = captureEnd = state.position; while ((ch = state.input.charCodeAt(state.position)) !== 0) { if (ch === 0x22/* " */) { captureSegment(state, captureStart, state.position, true); state.position++; return true; } else if (ch === 0x5C/* \ */) { captureSegment(state, captureStart, state.position, true); ch = state.input.charCodeAt(++state.position); if (is_EOL(ch)) { skipSeparationSpace(state, false, nodeIndent); // TODO: rework to inline fn with no type cast? } else if (ch < 256 && simpleEscapeCheck[ch]) { state.result += simpleEscapeMap[ch]; state.position++; } else if ((tmp = escapedHexLen(ch)) > 0) { hexLength = tmp; hexResult = 0; for (; hexLength > 0; hexLength--) { ch = state.input.charCodeAt(++state.position); if ((tmp = fromHexCode(ch)) >= 0) { hexResult = (hexResult << 4) + tmp; } else { throwError(state, 'expected hexadecimal character'); } } state.result += charFromCodepoint(hexResult); state.position++; } else { throwError(state, 'unknown escape sequence'); } captureStart = captureEnd = state.position; } else if (is_EOL(ch)) { captureSegment(state, captureStart, captureEnd, true); writeFoldedLines(state, skipSeparationSpace(state, false, nodeIndent)); captureStart = captureEnd = state.position; } else if (state.position === state.lineStart && testDocumentSeparator(state)) { throwError(state, 'unexpected end of the document within a double quoted scalar'); } else { state.position++; captureEnd = state.position; } } throwError(state, 'unexpected end of the stream within a double quoted scalar'); } function readFlowCollection(state, nodeIndent) { var readNext = true, _line, _tag = state.tag, _result, _anchor = state.anchor, following, terminator, isPair, isExplicitPair, isMapping, overridableKeys = {}, keyNode, keyTag, valueNode, ch; ch = state.input.charCodeAt(state.position); if (ch === 0x5B/* [ */) { terminator = 0x5D;/* ] */ isMapping = false; _result = []; } else if (ch === 0x7B/* { */) { terminator = 0x7D;/* } */ isMapping = true; _result = {}; } else { return false; } if (state.anchor !== null) { state.anchorMap[state.anchor] = _result; } ch = state.input.charCodeAt(++state.position); while (ch !== 0) { skipSeparationSpace(state, true, nodeIndent); ch = state.input.charCodeAt(state.position); if (ch === terminator) { state.position++; state.tag = _tag; state.anchor = _anchor; state.kind = isMapping ? 'mapping' : 'sequence'; state.result = _result; return true; } else if (!readNext) { throwError(state, 'missed comma between flow collection entries'); } keyTag = keyNode = valueNode = null; isPair = isExplicitPair = false; if (ch === 0x3F/* ? */) { following = state.input.charCodeAt(state.position + 1); if (is_WS_OR_EOL(following)) { isPair = isExplicitPair = true; state.position++; skipSeparationSpace(state, true, nodeIndent); } } _line = state.line; composeNode(state, nodeIndent, CONTEXT_FLOW_IN, false, true); keyTag = state.tag; keyNode = state.result; skipSeparationSpace(state, true, nodeIndent); ch = state.input.charCodeAt(state.position); if ((isExplicitPair || state.line === _line) && ch === 0x3A/* : */) { isPair = true; ch = state.input.charCodeAt(++state.position); skipSeparationSpace(state, true, nodeIndent); composeNode(state, nodeIndent, CONTEXT_FLOW_IN, false, true); valueNode = state.result; } if (isMapping) { storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode); } else if (isPair) { _result.push(storeMappingPair(state, null, overridableKeys, keyTag, keyNode, valueNode)); } else { _result.push(keyNode); } skipSeparationSpace(state, true, nodeIndent); ch = state.input.charCodeAt(state.position); if (ch === 0x2C/* , */) { readNext = true; ch = state.input.charCodeAt(++state.position); } else { readNext = false; } } throwError(state, 'unexpected end of the stream within a flow collection'); } function readBlockScalar(state, nodeIndent) { var captureStart, folding, chomping = CHOMPING_CLIP, didReadContent = false, detectedIndent = false, textIndent = nodeIndent, emptyLines = 0, atMoreIndented = false, tmp, ch; ch = state.input.charCodeAt(state.position); if (ch === 0x7C/* | */) { folding = false; } else if (ch === 0x3E/* > */) { folding = true; } else { return false; } state.kind = 'scalar'; state.result = ''; while (ch !== 0) { ch = state.input.charCodeAt(++state.position); if (ch === 0x2B/* + */ || ch === 0x2D/* - */) { if (CHOMPING_CLIP === chomping) { chomping = (ch === 0x2B/* + */) ? CHOMPING_KEEP : CHOMPING_STRIP; } else { throwError(state, 'repeat of a chomping mode identifier'); } } else if ((tmp = fromDecimalCode(ch)) >= 0) { if (tmp === 0) { throwError(state, 'bad explicit indentation width of a block scalar; it cannot be less than one'); } else if (!detectedIndent) { textIndent = nodeIndent + tmp - 1; detectedIndent = true; } else { throwError(state, 'repeat of an indentation width identifier'); } } else { break; } } if (is_WHITE_SPACE(ch)) { do { ch = state.input.charCodeAt(++state.position); } while (is_WHITE_SPACE(ch)); if (ch === 0x23/* # */) { do { ch = state.input.charCodeAt(++state.position); } while (!is_EOL(ch) && (ch !== 0)); } } while (ch !== 0) { readLineBreak(state); state.lineIndent = 0; ch = state.input.charCodeAt(state.position); while ((!detectedIndent || state.lineIndent < textIndent) && (ch === 0x20/* Space */)) { state.lineIndent++; ch = state.input.charCodeAt(++state.position); } if (!detectedIndent && state.lineIndent > textIndent) { textIndent = state.lineIndent; } if (is_EOL(ch)) { emptyLines++; continue; } // End of the scalar. if (state.lineIndent < textIndent) { // Perform the chomping. if (chomping === CHOMPING_KEEP) { state.result += common.repeat('\n', didReadContent ? 1 + emptyLines : emptyLines); } else if (chomping === CHOMPING_CLIP) { if (didReadContent) { // i.e. only if the scalar is not empty. state.result += '\n'; } } // Break this `while` cycle and go to the funciton's epilogue. break; } // Folded style: use fancy rules to handle line breaks. if (folding) { // Lines starting with white space characters (more-indented lines) are not folded. if (is_WHITE_SPACE(ch)) { atMoreIndented = true; // except for the first content line (cf. Example 8.1) state.result += common.repeat('\n', didReadContent ? 1 + emptyLines : emptyLines); // End of more-indented block. } else if (atMoreIndented) { atMoreIndented = false; state.result += common.repeat('\n', emptyLines + 1); // Just one line break - perceive as the same line. } else if (emptyLines === 0) { if (didReadContent) { // i.e. only if we have already read some scalar content. state.result += ' '; } // Several line breaks - perceive as different lines. } else { state.result += common.repeat('\n', emptyLines); } // Literal style: just add exact number of line breaks between content lines. } else { // Keep all line breaks except the header line break. state.result += common.repeat('\n', didReadContent ? 1 + emptyLines : emptyLines); } didReadContent = true; detectedIndent = true; emptyLines = 0; captureStart = state.position; while (!is_EOL(ch) && (ch !== 0)) { ch = state.input.charCodeAt(++state.position); } captureSegment(state, captureStart, state.position, false); } return true; } function readBlockSequence(state, nodeIndent) { var _line, _tag = state.tag, _anchor = state.anchor, _result = [], following, detected = false, ch; if (state.anchor !== null) { state.anchorMap[state.anchor] = _result; } ch = state.input.charCodeAt(state.position); while (ch !== 0) { if (ch !== 0x2D/* - */) { break; } following = state.input.charCodeAt(state.position + 1); if (!is_WS_OR_EOL(following)) { break; } detected = true; state.position++; if (skipSeparationSpace(state, true, -1)) { if (state.lineIndent <= nodeIndent) { _result.push(null); ch = state.input.charCodeAt(state.position); continue; } } _line = state.line; composeNode(state, nodeIndent, CONTEXT_BLOCK_IN, false, true); _result.push(state.result); skipSeparationSpace(state, true, -1); ch = state.input.charCodeAt(state.position); if ((state.line === _line || state.lineIndent > nodeIndent) && (ch !== 0)) { throwError(state, 'bad indentation of a sequence entry'); } else if (state.lineIndent < nodeIndent) { break; } } if (detected) { state.tag = _tag; state.anchor = _anchor; state.kind = 'sequence'; state.result = _result; return true; } return false; } function readBlockMapping(state, nodeIndent, flowIndent) { var following, allowCompact, _line, _pos, _tag = state.tag, _anchor = state.anchor, _result = {}, overridableKeys = {}, keyTag = null, keyNode = null, valueNode = null, atExplicitKey = false, detected = false, ch; if (state.anchor !== null) { state.anchorMap[state.anchor] = _result; } ch = state.input.charCodeAt(state.position); while (ch !== 0) { following = state.input.charCodeAt(state.position + 1); _line = state.line; // Save the current line. _pos = state.position; // // Explicit notation case. There are two separate blocks: // first for the key (denoted by "?") and second for the value (denoted by ":") // if ((ch === 0x3F/* ? */ || ch === 0x3A/* : */) && is_WS_OR_EOL(following)) { if (ch === 0x3F/* ? */) { if (atExplicitKey) { storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null); keyTag = keyNode = valueNode = null; } detected = true; atExplicitKey = true; allowCompact = true; } else if (atExplicitKey) { // i.e. 0x3A/* : */ === character after the explicit key. atExplicitKey = false; allowCompact = true; } else { throwError(state, 'incomplete explicit mapping pair; a key node is missed; or followed by a non-tabulated empty line'); } state.position += 1; ch = following; // // Implicit notation case. Flow-style node as the key first, then ":", and the value. // } else if (composeNode(state, flowIndent, CONTEXT_FLOW_OUT, false, true)) { if (state.line === _line) { ch = state.input.charCodeAt(state.position); while (is_WHITE_SPACE(ch)) { ch = state.input.charCodeAt(++state.position); } if (ch === 0x3A/* : */) { ch = state.input.charCodeAt(++state.position); if (!is_WS_OR_EOL(ch)) { throwError(state, 'a whitespace character is expected after the key-value separator within a block mapping'); } if (atExplicitKey) { storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null); keyTag = keyNode = valueNode = null; } detected = true; atExplicitKey = false; allowCompact = false; keyTag = state.tag; keyNode = state.result; } else if (detected) { throwError(state, 'can not read an implicit mapping pair; a colon is missed'); } else { state.tag = _tag; state.anchor = _anchor; return true; // Keep the result of `composeNode`. } } else if (detected) { throwError(state, 'can not read a block mapping entry; a multiline key may not be an implicit key'); } else { state.tag = _tag; state.anchor = _anchor; return true; // Keep the result of `composeNode`. } } else { break; // Reading is done. Go to the epilogue. } // // Common reading code for both explicit and implicit notations. // if (state.line === _line || state.lineIndent > nodeIndent) { if (composeNode(state, nodeIndent, CONTEXT_BLOCK_OUT, true, allowCompact)) { if (atExplicitKey) { keyNode = state.result; } else { valueNode = state.result; } } if (!atExplicitKey) { storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode, _line, _pos); keyTag = keyNode = valueNode = null; } skipSeparationSpace(state, true, -1); ch = state.input.charCodeAt(state.position); } if (state.lineIndent > nodeIndent && (ch !== 0)) { throwError(state, 'bad indentation of a mapping entry'); } else if (state.lineIndent < nodeIndent) { break; } } // // Epilogue. // // Special case: last mapping's node contains only the key in explicit notation. if (atExplicitKey) { storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null); } // Expose the resulting mapping. if (detected) { state.tag = _tag; state.anchor = _anchor; state.kind = 'mapping'; state.result = _result; } return detected; } function readTagProperty(state) { var _position, isVerbatim = false, isNamed = false, tagHandle, tagName, ch; ch = state.input.charCodeAt(state.position); if (ch !== 0x21/* ! */) return false; if (state.tag !== null) { throwError(state, 'duplication of a tag property'); } ch = state.input.charCodeAt(++state.position); if (ch === 0x3C/* < */) { isVerbatim = true; ch = state.input.charCodeAt(++state.position); } else if (ch === 0x21/* ! */) { isNamed = true; tagHandle = '!!'; ch = state.input.charCodeAt(++state.position); } else { tagHandle = '!'; } _position = state.position; if (isVerbatim) { do { ch = state.input.charCodeAt(++state.position); } while (ch !== 0 && ch !== 0x3E/* > */); if (state.position < state.length) { tagName = state.input.slice(_position, state.position); ch = state.input.charCodeAt(++state.position); } else { throwError(state, 'unexpected end of the stream within a verbatim tag'); } } else { while (ch !== 0 && !is_WS_OR_EOL(ch)) { if (ch === 0x21/* ! */) { if (!isNamed) { tagHandle = state.input.slice(_position - 1, state.position + 1); if (!PATTERN_TAG_HANDLE.test(tagHandle)) { throwError(state, 'named tag handle cannot contain such characters'); } isNamed = true; _position = state.position + 1; } else { throwError(state, 'tag suffix cannot contain exclamation marks'); } } ch = state.input.charCodeAt(++state.position); } tagName = state.input.slice(_position, state.position); if (PATTERN_FLOW_INDICATORS.test(tagName)) { throwError(state, 'tag suffix cannot contain flow indicator characters'); } } if (tagName && !PATTERN_TAG_URI.test(tagName)) { throwError(state, 'tag name cannot contain such characters: ' + tagName); } if (isVerbatim) { state.tag = tagName; } else if (_hasOwnProperty.call(state.tagMap, tagHandle)) { state.tag = state.tagMap[tagHandle] + tagName; } else if (tagHandle === '!') { state.tag = '!' + tagName; } else if (tagHandle === '!!') { state.tag = 'tag:yaml.org,2002:' + tagName; } else { throwError(state, 'undeclared tag handle "' + tagHandle + '"'); } return true; } function readAnchorProperty(state) { var _position, ch; ch = state.input.charCodeAt(state.position); if (ch !== 0x26/* & */) return false; if (state.anchor !== null) { throwError(state, 'duplication of an anchor property'); } ch = state.input.charCodeAt(++state.position); _position = state.position; while (ch !== 0 && !is_WS_OR_EOL(ch) && !is_FLOW_INDICATOR(ch)) { ch = state.input.charCodeAt(++state.position); } if (state.position === _position) { throwError(state, 'name of an anchor node must contain at least one character'); } state.anchor = state.input.slice(_position, state.position); return true; } function readAlias(state) { var _position, alias, ch; ch = state.input.charCodeAt(state.position); if (ch !== 0x2A/* * */) return false; ch = state.input.charCodeAt(++state.position); _position = state.position; while (ch !== 0 && !is_WS_OR_EOL(ch) && !is_FLOW_INDICATOR(ch)) { ch = state.input.charCodeAt(++state.position); } if (state.position === _position) { throwError(state, 'name of an alias node must contain at least one character'); } alias = state.input.slice(_position, state.position); if (!_hasOwnProperty.call(state.anchorMap, alias)) { throwError(state, 'unidentified alias "' + alias + '"'); } state.result = state.anchorMap[alias]; skipSeparationSpace(state, true, -1); return true; } function composeNode(state, parentIndent, nodeContext, allowToSeek, allowCompact) { var allowBlockStyles, allowBlockScalars, allowBlockCollections, indentStatus = 1, // 1: this>parent, 0: this=parent, -1: this parentIndent) { indentStatus = 1; } else if (state.lineIndent === parentIndent) { indentStatus = 0; } else if (state.lineIndent < parentIndent) { indentStatus = -1; } } } if (indentStatus === 1) { while (readTagProperty(state) || readAnchorProperty(state)) { if (skipSeparationSpace(state, true, -1)) { atNewLine = true; allowBlockCollections = allowBlockStyles; if (state.lineIndent > parentIndent) { indentStatus = 1; } else if (state.lineIndent === parentIndent) { indentStatus = 0; } else if (state.lineIndent < parentIndent) { indentStatus = -1; } } else { allowBlockCollections = false; } } } if (allowBlockCollections) { allowBlockCollections = atNewLine || allowCompact; } if (indentStatus === 1 || CONTEXT_BLOCK_OUT === nodeContext) { if (CONTEXT_FLOW_IN === nodeContext || CONTEXT_FLOW_OUT === nodeContext) { flowIndent = parentIndent; } else { flowIndent = parentIndent + 1; } blockIndent = state.position - state.lineStart; if (indentStatus === 1) { if (allowBlockCollections && (readBlockSequence(state, blockIndent) || readBlockMapping(state, blockIndent, flowIndent)) || readFlowCollection(state, flowIndent)) { hasContent = true; } else { if ((allowBlockScalars && readBlockScalar(state, flowIndent)) || readSingleQuotedScalar(state, flowIndent) || readDoubleQuotedScalar(state, flowIndent)) { hasContent = true; } else if (readAlias(state)) { hasContent = true; if (state.tag !== null || state.anchor !== null) { throwError(state, 'alias node should not have any properties'); } } else if (readPlainScalar(state, flowIndent, CONTEXT_FLOW_IN === nodeContext)) { hasContent = true; if (state.tag === null) { state.tag = '?'; } } if (state.anchor !== null) { state.anchorMap[state.anchor] = state.result; } } } else if (indentStatus === 0) { // Special case: block sequences are allowed to have same indentation level as the parent. // http://www.yaml.org/spec/1.2/spec.html#id2799784 hasContent = allowBlockCollections && readBlockSequence(state, blockIndent); } } if (state.tag !== null && state.tag !== '!') { if (state.tag === '?') { // Implicit resolving is not allowed for non-scalar types, and '?' // non-specific tag is only automatically assigned to plain scalars. // // We only need to check kind conformity in case user explicitly assigns '?' // tag, for example like this: "! [0]" // if (state.result !== null && state.kind !== 'scalar') { throwError(state, 'unacceptable node kind for ! tag; it should be "scalar", not "' + state.kind + '"'); } for (typeIndex = 0, typeQuantity = state.implicitTypes.length; typeIndex < typeQuantity; typeIndex += 1) { type = state.implicitTypes[typeIndex]; if (type.resolve(state.result)) { // `state.result` updated in resolver if matched state.result = type.construct(state.result); state.tag = type.tag; if (state.anchor !== null) { state.anchorMap[state.anchor] = state.result; } break; } } } else if (_hasOwnProperty.call(state.typeMap[state.kind || 'fallback'], state.tag)) { type = state.typeMap[state.kind || 'fallback'][state.tag]; if (state.result !== null && type.kind !== state.kind) { throwError(state, 'unacceptable node kind for !<' + state.tag + '> tag; it should be "' + type.kind + '", not "' + state.kind + '"'); } if (!type.resolve(state.result)) { // `state.result` updated in resolver if matched throwError(state, 'cannot resolve a node with !<' + state.tag + '> explicit tag'); } else { state.result = type.construct(state.result); if (state.anchor !== null) { state.anchorMap[state.anchor] = state.result; } } } else { throwError(state, 'unknown tag !<' + state.tag + '>'); } } if (state.listener !== null) { state.listener('close', state); } return state.tag !== null || state.anchor !== null || hasContent; } function readDocument(state) { var documentStart = state.position, _position, directiveName, directiveArgs, hasDirectives = false, ch; state.version = null; state.checkLineBreaks = state.legacy; state.tagMap = {}; state.anchorMap = {}; while ((ch = state.input.charCodeAt(state.position)) !== 0) { skipSeparationSpace(state, true, -1); ch = state.input.charCodeAt(state.position); if (state.lineIndent > 0 || ch !== 0x25/* % */) { break; } hasDirectives = true; ch = state.input.charCodeAt(++state.position); _position = state.position; while (ch !== 0 && !is_WS_OR_EOL(ch)) { ch = state.input.charCodeAt(++state.position); } directiveName = state.input.slice(_position, state.position); directiveArgs = []; if (directiveName.length < 1) { throwError(state, 'directive name must not be less than one character in length'); } while (ch !== 0) { while (is_WHITE_SPACE(ch)) { ch = state.input.charCodeAt(++state.position); } if (ch === 0x23/* # */) { do { ch = state.input.charCodeAt(++state.position); } while (ch !== 0 && !is_EOL(ch)); break; } if (is_EOL(ch)) break; _position = state.position; while (ch !== 0 && !is_WS_OR_EOL(ch)) { ch = state.input.charCodeAt(++state.position); } directiveArgs.push(state.input.slice(_position, state.position)); } if (ch !== 0) readLineBreak(state); if (_hasOwnProperty.call(directiveHandlers, directiveName)) { directiveHandlers[directiveName](state, directiveName, directiveArgs); } else { throwWarning(state, 'unknown document directive "' + directiveName + '"'); } } skipSeparationSpace(state, true, -1); if (state.lineIndent === 0 && state.input.charCodeAt(state.position) === 0x2D/* - */ && state.input.charCodeAt(state.position + 1) === 0x2D/* - */ && state.input.charCodeAt(state.position + 2) === 0x2D/* - */) { state.position += 3; skipSeparationSpace(state, true, -1); } else if (hasDirectives) { throwError(state, 'directives end mark is expected'); } composeNode(state, state.lineIndent - 1, CONTEXT_BLOCK_OUT, false, true); skipSeparationSpace(state, true, -1); if (state.checkLineBreaks && PATTERN_NON_ASCII_LINE_BREAKS.test(state.input.slice(documentStart, state.position))) { throwWarning(state, 'non-ASCII line breaks are interpreted as content'); } state.documents.push(state.result); if (state.position === state.lineStart && testDocumentSeparator(state)) { if (state.input.charCodeAt(state.position) === 0x2E/* . */) { state.position += 3; skipSeparationSpace(state, true, -1); } return; } if (state.position < (state.length - 1)) { throwError(state, 'end of the stream or a document separator is expected'); } else { return; } } function loadDocuments(input, options) { input = String(input); options = options || {}; if (input.length !== 0) { // Add tailing `\n` if not exists if (input.charCodeAt(input.length - 1) !== 0x0A/* LF */ && input.charCodeAt(input.length - 1) !== 0x0D/* CR */) { input += '\n'; } // Strip BOM if (input.charCodeAt(0) === 0xFEFF) { input = input.slice(1); } } var state = new State(input, options); var nullpos = input.indexOf('\0'); if (nullpos !== -1) { state.position = nullpos; throwError(state, 'null byte is not allowed in input'); } // Use 0 as string terminator. That significantly simplifies bounds check. state.input += '\0'; while (state.input.charCodeAt(state.position) === 0x20/* Space */) { state.lineIndent += 1; state.position += 1; } while (state.position < (state.length - 1)) { readDocument(state); } return state.documents; } function loadAll(input, iterator, options) { if (iterator !== null && typeof iterator === 'object' && typeof options === 'undefined') { options = iterator; iterator = null; } var documents = loadDocuments(input, options); if (typeof iterator !== 'function') { return documents; } for (var index = 0, length = documents.length; index < length; index += 1) { iterator(documents[index]); } } function load(input, options) { var documents = loadDocuments(input, options); if (documents.length === 0) { /*eslint-disable no-undefined*/ return undefined; } else if (documents.length === 1) { return documents[0]; } throw new YAMLException('expected a single document in the stream, but found more'); } function safeLoadAll(input, iterator, options) { if (typeof iterator === 'object' && iterator !== null && typeof options === 'undefined') { options = iterator; iterator = null; } return loadAll(input, iterator, common.extend({ schema: DEFAULT_SAFE_SCHEMA }, options)); } function safeLoad(input, options) { return load(input, common.extend({ schema: DEFAULT_SAFE_SCHEMA }, options)); } loader.loadAll = loadAll; loader.load = load; loader.safeLoadAll = safeLoadAll; loader.safeLoad = safeLoad; return loader; } var dumper = {}; var hasRequiredDumper; function requireDumper () { if (hasRequiredDumper) return dumper; hasRequiredDumper = 1; /*eslint-disable no-use-before-define*/ var common = requireCommon(); var YAMLException = requireException(); var DEFAULT_FULL_SCHEMA = requireDefault_full(); var DEFAULT_SAFE_SCHEMA = requireDefault_safe(); var _toString = Object.prototype.toString; var _hasOwnProperty = Object.prototype.hasOwnProperty; var CHAR_TAB = 0x09; /* Tab */ var CHAR_LINE_FEED = 0x0A; /* LF */ var CHAR_CARRIAGE_RETURN = 0x0D; /* CR */ var CHAR_SPACE = 0x20; /* Space */ var CHAR_EXCLAMATION = 0x21; /* ! */ var CHAR_DOUBLE_QUOTE = 0x22; /* " */ var CHAR_SHARP = 0x23; /* # */ var CHAR_PERCENT = 0x25; /* % */ var CHAR_AMPERSAND = 0x26; /* & */ var CHAR_SINGLE_QUOTE = 0x27; /* ' */ var CHAR_ASTERISK = 0x2A; /* * */ var CHAR_COMMA = 0x2C; /* , */ var CHAR_MINUS = 0x2D; /* - */ var CHAR_COLON = 0x3A; /* : */ var CHAR_EQUALS = 0x3D; /* = */ var CHAR_GREATER_THAN = 0x3E; /* > */ var CHAR_QUESTION = 0x3F; /* ? */ var CHAR_COMMERCIAL_AT = 0x40; /* @ */ var CHAR_LEFT_SQUARE_BRACKET = 0x5B; /* [ */ var CHAR_RIGHT_SQUARE_BRACKET = 0x5D; /* ] */ var CHAR_GRAVE_ACCENT = 0x60; /* ` */ var CHAR_LEFT_CURLY_BRACKET = 0x7B; /* { */ var CHAR_VERTICAL_LINE = 0x7C; /* | */ var CHAR_RIGHT_CURLY_BRACKET = 0x7D; /* } */ var ESCAPE_SEQUENCES = {}; ESCAPE_SEQUENCES[0x00] = '\\0'; ESCAPE_SEQUENCES[0x07] = '\\a'; ESCAPE_SEQUENCES[0x08] = '\\b'; ESCAPE_SEQUENCES[0x09] = '\\t'; ESCAPE_SEQUENCES[0x0A] = '\\n'; ESCAPE_SEQUENCES[0x0B] = '\\v'; ESCAPE_SEQUENCES[0x0C] = '\\f'; ESCAPE_SEQUENCES[0x0D] = '\\r'; ESCAPE_SEQUENCES[0x1B] = '\\e'; ESCAPE_SEQUENCES[0x22] = '\\"'; ESCAPE_SEQUENCES[0x5C] = '\\\\'; ESCAPE_SEQUENCES[0x85] = '\\N'; ESCAPE_SEQUENCES[0xA0] = '\\_'; ESCAPE_SEQUENCES[0x2028] = '\\L'; ESCAPE_SEQUENCES[0x2029] = '\\P'; var DEPRECATED_BOOLEANS_SYNTAX = [ 'y', 'Y', 'yes', 'Yes', 'YES', 'on', 'On', 'ON', 'n', 'N', 'no', 'No', 'NO', 'off', 'Off', 'OFF' ]; function compileStyleMap(schema, map) { var result, keys, index, length, tag, style, type; if (map === null) return {}; result = {}; keys = Object.keys(map); for (index = 0, length = keys.length; index < length; index += 1) { tag = keys[index]; style = String(map[tag]); if (tag.slice(0, 2) === '!!') { tag = 'tag:yaml.org,2002:' + tag.slice(2); } type = schema.compiledTypeMap['fallback'][tag]; if (type && _hasOwnProperty.call(type.styleAliases, style)) { style = type.styleAliases[style]; } result[tag] = style; } return result; } function encodeHex(character) { var string, handle, length; string = character.toString(16).toUpperCase(); if (character <= 0xFF) { handle = 'x'; length = 2; } else if (character <= 0xFFFF) { handle = 'u'; length = 4; } else if (character <= 0xFFFFFFFF) { handle = 'U'; length = 8; } else { throw new YAMLException('code point within a string may not be greater than 0xFFFFFFFF'); } return '\\' + handle + common.repeat('0', length - string.length) + string; } function State(options) { this.schema = options['schema'] || DEFAULT_FULL_SCHEMA; this.indent = Math.max(1, (options['indent'] || 2)); this.noArrayIndent = options['noArrayIndent'] || false; this.skipInvalid = options['skipInvalid'] || false; this.flowLevel = (common.isNothing(options['flowLevel']) ? -1 : options['flowLevel']); this.styleMap = compileStyleMap(this.schema, options['styles'] || null); this.sortKeys = options['sortKeys'] || false; this.lineWidth = options['lineWidth'] || 80; this.noRefs = options['noRefs'] || false; this.noCompatMode = options['noCompatMode'] || false; this.condenseFlow = options['condenseFlow'] || false; this.implicitTypes = this.schema.compiledImplicit; this.explicitTypes = this.schema.compiledExplicit; this.tag = null; this.result = ''; this.duplicates = []; this.usedDuplicates = null; } // Indents every line in a string. Empty lines (\n only) are not indented. function indentString(string, spaces) { var ind = common.repeat(' ', spaces), position = 0, next = -1, result = '', line, length = string.length; while (position < length) { next = string.indexOf('\n', position); if (next === -1) { line = string.slice(position); position = length; } else { line = string.slice(position, next + 1); position = next + 1; } if (line.length && line !== '\n') result += ind; result += line; } return result; } function generateNextLine(state, level) { return '\n' + common.repeat(' ', state.indent * level); } function testImplicitResolving(state, str) { var index, length, type; for (index = 0, length = state.implicitTypes.length; index < length; index += 1) { type = state.implicitTypes[index]; if (type.resolve(str)) { return true; } } return false; } // [33] s-white ::= s-space | s-tab function isWhitespace(c) { return c === CHAR_SPACE || c === CHAR_TAB; } // Returns true if the character can be printed without escaping. // From YAML 1.2: "any allowed characters known to be non-printable // should also be escaped. [However,] This isn’t mandatory" // Derived from nb-char - \t - #x85 - #xA0 - #x2028 - #x2029. function isPrintable(c) { return (0x00020 <= c && c <= 0x00007E) || ((0x000A1 <= c && c <= 0x00D7FF) && c !== 0x2028 && c !== 0x2029) || ((0x0E000 <= c && c <= 0x00FFFD) && c !== 0xFEFF /* BOM */) || (0x10000 <= c && c <= 0x10FFFF); } // [34] ns-char ::= nb-char - s-white // [27] nb-char ::= c-printable - b-char - c-byte-order-mark // [26] b-char ::= b-line-feed | b-carriage-return // [24] b-line-feed ::= #xA /* LF */ // [25] b-carriage-return ::= #xD /* CR */ // [3] c-byte-order-mark ::= #xFEFF function isNsChar(c) { return isPrintable(c) && !isWhitespace(c) // byte-order-mark && c !== 0xFEFF // b-char && c !== CHAR_CARRIAGE_RETURN && c !== CHAR_LINE_FEED; } // Simplified test for values allowed after the first character in plain style. function isPlainSafe(c, prev) { // Uses a subset of nb-char - c-flow-indicator - ":" - "#" // where nb-char ::= c-printable - b-char - c-byte-order-mark. return isPrintable(c) && c !== 0xFEFF // - c-flow-indicator && c !== CHAR_COMMA && c !== CHAR_LEFT_SQUARE_BRACKET && c !== CHAR_RIGHT_SQUARE_BRACKET && c !== CHAR_LEFT_CURLY_BRACKET && c !== CHAR_RIGHT_CURLY_BRACKET // - ":" - "#" // /* An ns-char preceding */ "#" && c !== CHAR_COLON && ((c !== CHAR_SHARP) || (prev && isNsChar(prev))); } // Simplified test for values allowed as the first character in plain style. function isPlainSafeFirst(c) { // Uses a subset of ns-char - c-indicator // where ns-char = nb-char - s-white. return isPrintable(c) && c !== 0xFEFF && !isWhitespace(c) // - s-white // - (c-indicator ::= // “-” | “?” | “:” | “,” | “[” | “]” | “{” | “}” && c !== CHAR_MINUS && c !== CHAR_QUESTION && c !== CHAR_COLON && c !== CHAR_COMMA && c !== CHAR_LEFT_SQUARE_BRACKET && c !== CHAR_RIGHT_SQUARE_BRACKET && c !== CHAR_LEFT_CURLY_BRACKET && c !== CHAR_RIGHT_CURLY_BRACKET // | “#” | “&” | “*” | “!” | “|” | “=” | “>” | “'” | “"” && c !== CHAR_SHARP && c !== CHAR_AMPERSAND && c !== CHAR_ASTERISK && c !== CHAR_EXCLAMATION && c !== CHAR_VERTICAL_LINE && c !== CHAR_EQUALS && c !== CHAR_GREATER_THAN && c !== CHAR_SINGLE_QUOTE && c !== CHAR_DOUBLE_QUOTE // | “%” | “@” | “`”) && c !== CHAR_PERCENT && c !== CHAR_COMMERCIAL_AT && c !== CHAR_GRAVE_ACCENT; } // Determines whether block indentation indicator is required. function needIndentIndicator(string) { var leadingSpaceRe = /^\n* /; return leadingSpaceRe.test(string); } var STYLE_PLAIN = 1, STYLE_SINGLE = 2, STYLE_LITERAL = 3, STYLE_FOLDED = 4, STYLE_DOUBLE = 5; // Determines which scalar styles are possible and returns the preferred style. // lineWidth = -1 => no limit. // Pre-conditions: str.length > 0. // Post-conditions: // STYLE_PLAIN or STYLE_SINGLE => no \n are in the string. // STYLE_LITERAL => no lines are suitable for folding (or lineWidth is -1). // STYLE_FOLDED => a line > lineWidth and can be folded (and lineWidth != -1). function chooseScalarStyle(string, singleLineOnly, indentPerLevel, lineWidth, testAmbiguousType) { var i; var char, prev_char; var hasLineBreak = false; var hasFoldableLine = false; // only checked if shouldTrackWidth var shouldTrackWidth = lineWidth !== -1; var previousLineBreak = -1; // count the first line correctly var plain = isPlainSafeFirst(string.charCodeAt(0)) && !isWhitespace(string.charCodeAt(string.length - 1)); if (singleLineOnly) { // Case: no block styles. // Check for disallowed characters to rule out plain and single. for (i = 0; i < string.length; i++) { char = string.charCodeAt(i); if (!isPrintable(char)) { return STYLE_DOUBLE; } prev_char = i > 0 ? string.charCodeAt(i - 1) : null; plain = plain && isPlainSafe(char, prev_char); } } else { // Case: block styles permitted. for (i = 0; i < string.length; i++) { char = string.charCodeAt(i); if (char === CHAR_LINE_FEED) { hasLineBreak = true; // Check if any line can be folded. if (shouldTrackWidth) { hasFoldableLine = hasFoldableLine || // Foldable line = too long, and not more-indented. (i - previousLineBreak - 1 > lineWidth && string[previousLineBreak + 1] !== ' '); previousLineBreak = i; } } else if (!isPrintable(char)) { return STYLE_DOUBLE; } prev_char = i > 0 ? string.charCodeAt(i - 1) : null; plain = plain && isPlainSafe(char, prev_char); } // in case the end is missing a \n hasFoldableLine = hasFoldableLine || (shouldTrackWidth && (i - previousLineBreak - 1 > lineWidth && string[previousLineBreak + 1] !== ' ')); } // Although every style can represent \n without escaping, prefer block styles // for multiline, since they're more readable and they don't add empty lines. // Also prefer folding a super-long line. if (!hasLineBreak && !hasFoldableLine) { // Strings interpretable as another type have to be quoted; // e.g. the string 'true' vs. the boolean true. return plain && !testAmbiguousType(string) ? STYLE_PLAIN : STYLE_SINGLE; } // Edge case: block indentation indicator can only have one digit. if (indentPerLevel > 9 && needIndentIndicator(string)) { return STYLE_DOUBLE; } // At this point we know block styles are valid. // Prefer literal style unless we want to fold. return hasFoldableLine ? STYLE_FOLDED : STYLE_LITERAL; } // Note: line breaking/folding is implemented for only the folded style. // NB. We drop the last trailing newline (if any) of a returned block scalar // since the dumper adds its own newline. This always works: // • No ending newline => unaffected; already using strip "-" chomping. // • Ending newline => removed then restored. // Importantly, this keeps the "+" chomp indicator from gaining an extra line. function writeScalar(state, string, level, iskey) { state.dump = (function () { if (string.length === 0) { return "''"; } if (!state.noCompatMode && DEPRECATED_BOOLEANS_SYNTAX.indexOf(string) !== -1) { return "'" + string + "'"; } var indent = state.indent * Math.max(1, level); // no 0-indent scalars // As indentation gets deeper, let the width decrease monotonically // to the lower bound min(state.lineWidth, 40). // Note that this implies // state.lineWidth ≤ 40 + state.indent: width is fixed at the lower bound. // state.lineWidth > 40 + state.indent: width decreases until the lower bound. // This behaves better than a constant minimum width which disallows narrower options, // or an indent threshold which causes the width to suddenly increase. var lineWidth = state.lineWidth === -1 ? -1 : Math.max(Math.min(state.lineWidth, 40), state.lineWidth - indent); // Without knowing if keys are implicit/explicit, assume implicit for safety. var singleLineOnly = iskey // No block styles in flow mode. || (state.flowLevel > -1 && level >= state.flowLevel); function testAmbiguity(string) { return testImplicitResolving(state, string); } switch (chooseScalarStyle(string, singleLineOnly, state.indent, lineWidth, testAmbiguity)) { case STYLE_PLAIN: return string; case STYLE_SINGLE: return "'" + string.replace(/'/g, "''") + "'"; case STYLE_LITERAL: return '|' + blockHeader(string, state.indent) + dropEndingNewline(indentString(string, indent)); case STYLE_FOLDED: return '>' + blockHeader(string, state.indent) + dropEndingNewline(indentString(foldString(string, lineWidth), indent)); case STYLE_DOUBLE: return '"' + escapeString(string) + '"'; default: throw new YAMLException('impossible error: invalid scalar style'); } }()); } // Pre-conditions: string is valid for a block scalar, 1 <= indentPerLevel <= 9. function blockHeader(string, indentPerLevel) { var indentIndicator = needIndentIndicator(string) ? String(indentPerLevel) : ''; // note the special case: the string '\n' counts as a "trailing" empty line. var clip = string[string.length - 1] === '\n'; var keep = clip && (string[string.length - 2] === '\n' || string === '\n'); var chomp = keep ? '+' : (clip ? '' : '-'); return indentIndicator + chomp + '\n'; } // (See the note for writeScalar.) function dropEndingNewline(string) { return string[string.length - 1] === '\n' ? string.slice(0, -1) : string; } // Note: a long line without a suitable break point will exceed the width limit. // Pre-conditions: every char in str isPrintable, str.length > 0, width > 0. function foldString(string, width) { // In folded style, $k$ consecutive newlines output as $k+1$ newlines— // unless they're before or after a more-indented line, or at the very // beginning or end, in which case $k$ maps to $k$. // Therefore, parse each chunk as newline(s) followed by a content line. var lineRe = /(\n+)([^\n]*)/g; // first line (possibly an empty line) var result = (function () { var nextLF = string.indexOf('\n'); nextLF = nextLF !== -1 ? nextLF : string.length; lineRe.lastIndex = nextLF; return foldLine(string.slice(0, nextLF), width); }()); // If we haven't reached the first content line yet, don't add an extra \n. var prevMoreIndented = string[0] === '\n' || string[0] === ' '; var moreIndented; // rest of the lines var match; while ((match = lineRe.exec(string))) { var prefix = match[1], line = match[2]; moreIndented = (line[0] === ' '); result += prefix + (!prevMoreIndented && !moreIndented && line !== '' ? '\n' : '') + foldLine(line, width); prevMoreIndented = moreIndented; } return result; } // Greedy line breaking. // Picks the longest line under the limit each time, // otherwise settles for the shortest line over the limit. // NB. More-indented lines *cannot* be folded, as that would add an extra \n. function foldLine(line, width) { if (line === '' || line[0] === ' ') return line; // Since a more-indented line adds a \n, breaks can't be followed by a space. var breakRe = / [^ ]/g; // note: the match index will always be <= length-2. var match; // start is an inclusive index. end, curr, and next are exclusive. var start = 0, end, curr = 0, next = 0; var result = ''; // Invariants: 0 <= start <= length-1. // 0 <= curr <= next <= max(0, length-2). curr - start <= width. // Inside the loop: // A match implies length >= 2, so curr and next are <= length-2. while ((match = breakRe.exec(line))) { next = match.index; // maintain invariant: curr - start <= width if (next - start > width) { end = (curr > start) ? curr : next; // derive end <= length-2 result += '\n' + line.slice(start, end); // skip the space that was output as \n start = end + 1; // derive start <= length-1 } curr = next; } // By the invariants, start <= length-1, so there is something left over. // It is either the whole string or a part starting from non-whitespace. result += '\n'; // Insert a break if the remainder is too long and there is a break available. if (line.length - start > width && curr > start) { result += line.slice(start, curr) + '\n' + line.slice(curr + 1); } else { result += line.slice(start); } return result.slice(1); // drop extra \n joiner } // Escapes a double-quoted string. function escapeString(string) { var result = ''; var char, nextChar; var escapeSeq; for (var i = 0; i < string.length; i++) { char = string.charCodeAt(i); // Check for surrogate pairs (reference Unicode 3.0 section "3.7 Surrogates"). if (char >= 0xD800 && char <= 0xDBFF/* high surrogate */) { nextChar = string.charCodeAt(i + 1); if (nextChar >= 0xDC00 && nextChar <= 0xDFFF/* low surrogate */) { // Combine the surrogate pair and store it escaped. result += encodeHex((char - 0xD800) * 0x400 + nextChar - 0xDC00 + 0x10000); // Advance index one extra since we already used that char here. i++; continue; } } escapeSeq = ESCAPE_SEQUENCES[char]; result += !escapeSeq && isPrintable(char) ? string[i] : escapeSeq || encodeHex(char); } return result; } function writeFlowSequence(state, level, object) { var _result = '', _tag = state.tag, index, length; for (index = 0, length = object.length; index < length; index += 1) { // Write only valid elements. if (writeNode(state, level, object[index], false, false)) { if (index !== 0) _result += ',' + (!state.condenseFlow ? ' ' : ''); _result += state.dump; } } state.tag = _tag; state.dump = '[' + _result + ']'; } function writeBlockSequence(state, level, object, compact) { var _result = '', _tag = state.tag, index, length; for (index = 0, length = object.length; index < length; index += 1) { // Write only valid elements. if (writeNode(state, level + 1, object[index], true, true)) { if (!compact || index !== 0) { _result += generateNextLine(state, level); } if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) { _result += '-'; } else { _result += '- '; } _result += state.dump; } } state.tag = _tag; state.dump = _result || '[]'; // Empty sequence if no valid values. } function writeFlowMapping(state, level, object) { var _result = '', _tag = state.tag, objectKeyList = Object.keys(object), index, length, objectKey, objectValue, pairBuffer; for (index = 0, length = objectKeyList.length; index < length; index += 1) { pairBuffer = ''; if (index !== 0) pairBuffer += ', '; if (state.condenseFlow) pairBuffer += '"'; objectKey = objectKeyList[index]; objectValue = object[objectKey]; if (!writeNode(state, level, objectKey, false, false)) { continue; // Skip this pair because of invalid key; } if (state.dump.length > 1024) pairBuffer += '? '; pairBuffer += state.dump + (state.condenseFlow ? '"' : '') + ':' + (state.condenseFlow ? '' : ' '); if (!writeNode(state, level, objectValue, false, false)) { continue; // Skip this pair because of invalid value. } pairBuffer += state.dump; // Both key and value are valid. _result += pairBuffer; } state.tag = _tag; state.dump = '{' + _result + '}'; } function writeBlockMapping(state, level, object, compact) { var _result = '', _tag = state.tag, objectKeyList = Object.keys(object), index, length, objectKey, objectValue, explicitPair, pairBuffer; // Allow sorting keys so that the output file is deterministic if (state.sortKeys === true) { // Default sorting objectKeyList.sort(); } else if (typeof state.sortKeys === 'function') { // Custom sort function objectKeyList.sort(state.sortKeys); } else if (state.sortKeys) { // Something is wrong throw new YAMLException('sortKeys must be a boolean or a function'); } for (index = 0, length = objectKeyList.length; index < length; index += 1) { pairBuffer = ''; if (!compact || index !== 0) { pairBuffer += generateNextLine(state, level); } objectKey = objectKeyList[index]; objectValue = object[objectKey]; if (!writeNode(state, level + 1, objectKey, true, true, true)) { continue; // Skip this pair because of invalid key. } explicitPair = (state.tag !== null && state.tag !== '?') || (state.dump && state.dump.length > 1024); if (explicitPair) { if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) { pairBuffer += '?'; } else { pairBuffer += '? '; } } pairBuffer += state.dump; if (explicitPair) { pairBuffer += generateNextLine(state, level); } if (!writeNode(state, level + 1, objectValue, true, explicitPair)) { continue; // Skip this pair because of invalid value. } if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) { pairBuffer += ':'; } else { pairBuffer += ': '; } pairBuffer += state.dump; // Both key and value are valid. _result += pairBuffer; } state.tag = _tag; state.dump = _result || '{}'; // Empty mapping if no valid pairs. } function detectType(state, object, explicit) { var _result, typeList, index, length, type, style; typeList = explicit ? state.explicitTypes : state.implicitTypes; for (index = 0, length = typeList.length; index < length; index += 1) { type = typeList[index]; if ((type.instanceOf || type.predicate) && (!type.instanceOf || ((typeof object === 'object') && (object instanceof type.instanceOf))) && (!type.predicate || type.predicate(object))) { state.tag = explicit ? type.tag : '?'; if (type.represent) { style = state.styleMap[type.tag] || type.defaultStyle; if (_toString.call(type.represent) === '[object Function]') { _result = type.represent(object, style); } else if (_hasOwnProperty.call(type.represent, style)) { _result = type.represent[style](object, style); } else { throw new YAMLException('!<' + type.tag + '> tag resolver accepts not "' + style + '" style'); } state.dump = _result; } return true; } } return false; } // Serializes `object` and writes it to global `result`. // Returns true on success, or false on invalid object. // function writeNode(state, level, object, block, compact, iskey) { state.tag = null; state.dump = object; if (!detectType(state, object, false)) { detectType(state, object, true); } var type = _toString.call(state.dump); if (block) { block = (state.flowLevel < 0 || state.flowLevel > level); } var objectOrArray = type === '[object Object]' || type === '[object Array]', duplicateIndex, duplicate; if (objectOrArray) { duplicateIndex = state.duplicates.indexOf(object); duplicate = duplicateIndex !== -1; } if ((state.tag !== null && state.tag !== '?') || duplicate || (state.indent !== 2 && level > 0)) { compact = false; } if (duplicate && state.usedDuplicates[duplicateIndex]) { state.dump = '*ref_' + duplicateIndex; } else { if (objectOrArray && duplicate && !state.usedDuplicates[duplicateIndex]) { state.usedDuplicates[duplicateIndex] = true; } if (type === '[object Object]') { if (block && (Object.keys(state.dump).length !== 0)) { writeBlockMapping(state, level, state.dump, compact); if (duplicate) { state.dump = '&ref_' + duplicateIndex + state.dump; } } else { writeFlowMapping(state, level, state.dump); if (duplicate) { state.dump = '&ref_' + duplicateIndex + ' ' + state.dump; } } } else if (type === '[object Array]') { var arrayLevel = (state.noArrayIndent && (level > 0)) ? level - 1 : level; if (block && (state.dump.length !== 0)) { writeBlockSequence(state, arrayLevel, state.dump, compact); if (duplicate) { state.dump = '&ref_' + duplicateIndex + state.dump; } } else { writeFlowSequence(state, arrayLevel, state.dump); if (duplicate) { state.dump = '&ref_' + duplicateIndex + ' ' + state.dump; } } } else if (type === '[object String]') { if (state.tag !== '?') { writeScalar(state, state.dump, level, iskey); } } else { if (state.skipInvalid) return false; throw new YAMLException('unacceptable kind of an object to dump ' + type); } if (state.tag !== null && state.tag !== '?') { state.dump = '!<' + state.tag + '> ' + state.dump; } } return true; } function getDuplicateReferences(object, state) { var objects = [], duplicatesIndexes = [], index, length; inspectNode(object, objects, duplicatesIndexes); for (index = 0, length = duplicatesIndexes.length; index < length; index += 1) { state.duplicates.push(objects[duplicatesIndexes[index]]); } state.usedDuplicates = new Array(length); } function inspectNode(object, objects, duplicatesIndexes) { var objectKeyList, index, length; if (object !== null && typeof object === 'object') { index = objects.indexOf(object); if (index !== -1) { if (duplicatesIndexes.indexOf(index) === -1) { duplicatesIndexes.push(index); } } else { objects.push(object); if (Array.isArray(object)) { for (index = 0, length = object.length; index < length; index += 1) { inspectNode(object[index], objects, duplicatesIndexes); } } else { objectKeyList = Object.keys(object); for (index = 0, length = objectKeyList.length; index < length; index += 1) { inspectNode(object[objectKeyList[index]], objects, duplicatesIndexes); } } } } } function dump(input, options) { options = options || {}; var state = new State(options); if (!state.noRefs) getDuplicateReferences(input, state); if (writeNode(state, 0, input, true, true)) return state.dump + '\n'; return ''; } function safeDump(input, options) { return dump(input, common.extend({ schema: DEFAULT_SAFE_SCHEMA }, options)); } dumper.dump = dump; dumper.safeDump = safeDump; return dumper; } var hasRequiredJsYaml$1; function requireJsYaml$1 () { if (hasRequiredJsYaml$1) return jsYaml$1; hasRequiredJsYaml$1 = 1; var loader = requireLoader(); var dumper = requireDumper(); function deprecated(name) { return function () { throw new Error('Function ' + name + ' is deprecated and cannot be used.'); }; } jsYaml$1.Type = requireType(); jsYaml$1.Schema = requireSchema(); jsYaml$1.FAILSAFE_SCHEMA = requireFailsafe(); jsYaml$1.JSON_SCHEMA = requireJson(); jsYaml$1.CORE_SCHEMA = requireCore(); jsYaml$1.DEFAULT_SAFE_SCHEMA = requireDefault_safe(); jsYaml$1.DEFAULT_FULL_SCHEMA = requireDefault_full(); jsYaml$1.load = loader.load; jsYaml$1.loadAll = loader.loadAll; jsYaml$1.safeLoad = loader.safeLoad; jsYaml$1.safeLoadAll = loader.safeLoadAll; jsYaml$1.dump = dumper.dump; jsYaml$1.safeDump = dumper.safeDump; jsYaml$1.YAMLException = requireException(); // Deprecated schema names from JS-YAML 2.0.x jsYaml$1.MINIMAL_SCHEMA = requireFailsafe(); jsYaml$1.SAFE_SCHEMA = requireDefault_safe(); jsYaml$1.DEFAULT_SCHEMA = requireDefault_full(); // Deprecated functions from JS-YAML 1.x.x jsYaml$1.scan = deprecated('scan'); jsYaml$1.parse = deprecated('parse'); jsYaml$1.compose = deprecated('compose'); jsYaml$1.addConstructor = deprecated('addConstructor'); return jsYaml$1; } var jsYaml; var hasRequiredJsYaml; function requireJsYaml () { if (hasRequiredJsYaml) return jsYaml; hasRequiredJsYaml = 1; var yaml = requireJsYaml$1(); jsYaml = yaml; return jsYaml; } var hasRequiredEngines; function requireEngines () { if (hasRequiredEngines) return engines.exports; hasRequiredEngines = 1; (function (module, exports$1) { const yaml = requireJsYaml(); /** * Default engines */ const engines = module.exports; /** * YAML */ engines.yaml = { parse: yaml.safeLoad.bind(yaml), stringify: yaml.safeDump.bind(yaml) }; /** * JSON */ engines.json = { parse: JSON.parse.bind(JSON), stringify: function(obj, options) { const opts = Object.assign({replacer: null, space: 2}, options); return JSON.stringify(obj, opts.replacer, opts.space); } }; /** * JavaScript */ engines.javascript = { parse: function parse(str, options, wrap) { /* eslint no-eval: 0 */ try { if (wrap !== false) { str = '(function() {\nreturn ' + str.trim() + ';\n}());'; } return eval(str) || {}; } catch (err) { if (wrap !== false && /(unexpected|identifier)/i.test(err.message)) { return parse(str, options, false); } throw new SyntaxError(err); } }, stringify: function() { throw new Error('stringifying JavaScript is not supported'); } }; } (engines)); return engines.exports; } var utils$2 = {}; /*! * strip-bom-string * * Copyright (c) 2015, 2017, Jon Schlinkert. * Released under the MIT License. */ var stripBomString; var hasRequiredStripBomString; function requireStripBomString () { if (hasRequiredStripBomString) return stripBomString; hasRequiredStripBomString = 1; stripBomString = function(str) { if (typeof str === 'string' && str.charAt(0) === '\ufeff') { return str.slice(1); } return str; }; return stripBomString; } var hasRequiredUtils$1; function requireUtils$1 () { if (hasRequiredUtils$1) return utils$2; hasRequiredUtils$1 = 1; (function (exports$1) { const stripBom = requireStripBomString(); const typeOf = requireKindOf(); exports$1.define = function(obj, key, val) { Reflect.defineProperty(obj, key, { enumerable: false, configurable: true, writable: true, value: val }); }; /** * Returns true if `val` is a buffer */ exports$1.isBuffer = function(val) { return typeOf(val) === 'buffer'; }; /** * Returns true if `val` is an object */ exports$1.isObject = function(val) { return typeOf(val) === 'object'; }; /** * Cast `input` to a buffer */ exports$1.toBuffer = function(input) { return typeof input === 'string' ? Buffer.from(input) : input; }; /** * Cast `val` to a string. */ exports$1.toString = function(input) { if (exports$1.isBuffer(input)) return stripBom(String(input)); if (typeof input !== 'string') { throw new TypeError('expected input to be a string or buffer'); } return stripBom(input); }; /** * Cast `val` to an array. */ exports$1.arrayify = function(val) { return val ? (Array.isArray(val) ? val : [val]) : []; }; /** * Returns true if `str` starts with `substr`. */ exports$1.startsWith = function(str, substr, len) { if (typeof len !== 'number') len = substr.length; return str.slice(0, len) === substr; }; } (utils$2)); return utils$2; } var defaults; var hasRequiredDefaults; function requireDefaults () { if (hasRequiredDefaults) return defaults; hasRequiredDefaults = 1; const engines = requireEngines(); const utils = requireUtils$1(); defaults = function(options) { const opts = Object.assign({}, options); // ensure that delimiters are an array opts.delimiters = utils.arrayify(opts.delims || opts.delimiters || '---'); if (opts.delimiters.length === 1) { opts.delimiters.push(opts.delimiters[0]); } opts.language = (opts.language || opts.lang || 'yaml').toLowerCase(); opts.engines = Object.assign({}, engines, opts.parsers, opts.engines); return opts; }; return defaults; } var engine; var hasRequiredEngine; function requireEngine () { if (hasRequiredEngine) return engine; hasRequiredEngine = 1; engine = function(name, options) { let engine = options.engines[name] || options.engines[aliase(name)]; if (typeof engine === 'undefined') { throw new Error('gray-matter engine "' + name + '" is not registered'); } if (typeof engine === 'function') { engine = { parse: engine }; } return engine; }; function aliase(name) { switch (name.toLowerCase()) { case 'js': case 'javascript': return 'javascript'; case 'coffee': case 'coffeescript': case 'cson': return 'coffee'; case 'yaml': case 'yml': return 'yaml'; default: { return name; } } } return engine; } var stringify; var hasRequiredStringify; function requireStringify () { if (hasRequiredStringify) return stringify; hasRequiredStringify = 1; const typeOf = requireKindOf(); const getEngine = requireEngine(); const defaults = requireDefaults(); stringify = function(file, data, options) { if (data == null && options == null) { switch (typeOf(file)) { case 'object': data = file.data; options = {}; break; case 'string': return file; default: { throw new TypeError('expected file to be a string or object'); } } } const str = file.content; const opts = defaults(options); if (data == null) { if (!opts.data) return file; data = opts.data; } const language = file.language || opts.language; const engine = getEngine(language, opts); if (typeof engine.stringify !== 'function') { throw new TypeError('expected "' + language + '.stringify" to be a function'); } data = Object.assign({}, file.data, data); const open = opts.delimiters[0]; const close = opts.delimiters[1]; const matter = engine.stringify(data, options).trim(); let buf = ''; if (matter !== '{}') { buf = newline(open) + newline(matter) + newline(close); } if (typeof file.excerpt === 'string' && file.excerpt !== '') { if (str.indexOf(file.excerpt.trim()) === -1) { buf += newline(file.excerpt) + newline(close); } } return buf + newline(str); }; function newline(str) { return str.slice(-1) !== '\n' ? str + '\n' : str; } return stringify; } var excerpt; var hasRequiredExcerpt; function requireExcerpt () { if (hasRequiredExcerpt) return excerpt; hasRequiredExcerpt = 1; const defaults = requireDefaults(); excerpt = function(file, options) { const opts = defaults(options); if (file.data == null) { file.data = {}; } if (typeof opts.excerpt === 'function') { return opts.excerpt(file, opts); } const sep = file.data.excerpt_separator || opts.excerpt_separator; if (sep == null && (opts.excerpt === false || opts.excerpt == null)) { return file; } const delimiter = typeof opts.excerpt === 'string' ? opts.excerpt : (sep || opts.delimiters[0]); // if enabled, get the excerpt defined after front-matter const idx = file.content.indexOf(delimiter); if (idx !== -1) { file.excerpt = file.content.slice(0, idx); } return file; }; return excerpt; } var toFile; var hasRequiredToFile; function requireToFile () { if (hasRequiredToFile) return toFile; hasRequiredToFile = 1; const typeOf = requireKindOf(); const stringify = requireStringify(); const utils = requireUtils$1(); /** * Normalize the given value to ensure an object is returned * with the expected properties. */ toFile = function(file) { if (typeOf(file) !== 'object') { file = { content: file }; } if (typeOf(file.data) !== 'object') { file.data = {}; } // if file was passed as an object, ensure that // "file.content" is set if (file.contents && file.content == null) { file.content = file.contents; } // set non-enumerable properties on the file object utils.define(file, 'orig', utils.toBuffer(file.content)); utils.define(file, 'language', file.language || ''); utils.define(file, 'matter', file.matter || ''); utils.define(file, 'stringify', function(data, options) { if (options && options.language) { file.language = options.language; } return stringify(file, data, options); }); // strip BOM and ensure that "file.content" is a string file.content = utils.toString(file.content); file.isEmpty = false; file.excerpt = ''; return file; }; return toFile; } var parse$2; var hasRequiredParse$1; function requireParse$1 () { if (hasRequiredParse$1) return parse$2; hasRequiredParse$1 = 1; const getEngine = requireEngine(); const defaults = requireDefaults(); parse$2 = function(language, str, options) { const opts = defaults(options); const engine = getEngine(language, opts); if (typeof engine.parse !== 'function') { throw new TypeError('expected "' + language + '.parse" to be a function'); } return engine.parse(str, opts); }; return parse$2; } var grayMatter; var hasRequiredGrayMatter; function requireGrayMatter () { if (hasRequiredGrayMatter) return grayMatter; hasRequiredGrayMatter = 1; const fs = nativeFs__default; const sections = requireSectionMatter(); const defaults = requireDefaults(); const stringify = requireStringify(); const excerpt = requireExcerpt(); const engines = requireEngines(); const toFile = requireToFile(); const parse = requireParse$1(); const utils = requireUtils$1(); /** * Takes a string or object with `content` property, extracts * and parses front-matter from the string, then returns an object * with `data`, `content` and other [useful properties](#returned-object). * * ```js * const matter = require('gray-matter'); * console.log(matter('---\ntitle: Home\n---\nOther stuff')); * //=> { data: { title: 'Home'}, content: 'Other stuff' } * ``` * @param {Object|String} `input` String, or object with `content` string * @param {Object} `options` * @return {Object} * @api public */ function matter(input, options) { if (input === '') { return { data: {}, content: input, excerpt: '', orig: input }; } let file = toFile(input); const cached = matter.cache[file.content]; if (!options) { if (cached) { file = Object.assign({}, cached); file.orig = cached.orig; return file; } // only cache if there are no options passed. if we cache when options // are passed, we would need to also cache options values, which would // negate any performance benefits of caching matter.cache[file.content] = file; } return parseMatter(file, options); } /** * Parse front matter */ function parseMatter(file, options) { const opts = defaults(options); const open = opts.delimiters[0]; const close = '\n' + opts.delimiters[1]; let str = file.content; if (opts.language) { file.language = opts.language; } // get the length of the opening delimiter const openLen = open.length; if (!utils.startsWith(str, open, openLen)) { excerpt(file, opts); return file; } // if the next character after the opening delimiter is // a character from the delimiter, then it's not a front- // matter delimiter if (str.charAt(openLen) === open.slice(-1)) { return file; } // strip the opening delimiter str = str.slice(openLen); const len = str.length; // use the language defined after first delimiter, if it exists const language = matter.language(str, opts); if (language.name) { file.language = language.name; str = str.slice(language.raw.length); } // get the index of the closing delimiter let closeIndex = str.indexOf(close); if (closeIndex === -1) { closeIndex = len; } // get the raw front-matter block file.matter = str.slice(0, closeIndex); const block = file.matter.replace(/^\s*#[^\n]+/gm, '').trim(); if (block === '') { file.isEmpty = true; file.empty = file.content; file.data = {}; } else { // create file.data by parsing the raw file.matter block file.data = parse(file.language, file.matter, opts); } // update file.content if (closeIndex === len) { file.content = ''; } else { file.content = str.slice(closeIndex + close.length); if (file.content[0] === '\r') { file.content = file.content.slice(1); } if (file.content[0] === '\n') { file.content = file.content.slice(1); } } excerpt(file, opts); if (opts.sections === true || typeof opts.section === 'function') { sections(file, opts.section); } return file; } /** * Expose engines */ matter.engines = engines; /** * Stringify an object to YAML or the specified language, and * append it to the given string. By default, only YAML and JSON * can be stringified. See the [engines](#engines) section to learn * how to stringify other languages. * * ```js * console.log(matter.stringify('foo bar baz', {title: 'Home'})); * // results in: * // --- * // title: Home * // --- * // foo bar baz * ``` * @param {String|Object} `file` The content string to append to stringified front-matter, or a file object with `file.content` string. * @param {Object} `data` Front matter to stringify. * @param {Object} `options` [Options](#options) to pass to gray-matter and [js-yaml]. * @return {String} Returns a string created by wrapping stringified yaml with delimiters, and appending that to the given string. * @api public */ matter.stringify = function(file, data, options) { if (typeof file === 'string') file = matter(file, options); return stringify(file, data, options); }; /** * Synchronously read a file from the file system and parse * front matter. Returns the same object as the [main function](#matter). * * ```js * const file = matter.read('./content/blog-post.md'); * ``` * @param {String} `filepath` file path of the file to read. * @param {Object} `options` [Options](#options) to pass to gray-matter. * @return {Object} Returns [an object](#returned-object) with `data` and `content` * @api public */ matter.read = function(filepath, options) { const str = fs.readFileSync(filepath, 'utf8'); const file = matter(str, options); file.path = filepath; return file; }; /** * Returns true if the given `string` has front matter. * @param {String} `string` * @param {Object} `options` * @return {Boolean} True if front matter exists. * @api public */ matter.test = function(str, options) { return utils.startsWith(str, defaults(options).delimiters[0]); }; /** * Detect the language to use, if one is defined after the * first front-matter delimiter. * @param {String} `string` * @param {Object} `options` * @return {Object} Object with `raw` (actual language string), and `name`, the language with whitespace trimmed */ matter.language = function(str, options) { const opts = defaults(options); const open = opts.delimiters[0]; if (matter.test(str)) { str = str.slice(open.length); } const language = str.slice(0, str.search(/\r?\n/)); return { raw: language, name: language ? language.trim() : '' }; }; /** * Expose `matter` */ matter.cache = {}; matter.clearCache = function() { matter.cache = {}; }; grayMatter = matter; return grayMatter; } var grayMatterExports = requireGrayMatter(); var matter = /*@__PURE__*/getDefaultExportFromCjs(grayMatterExports); //#region src/frontmatter-plugin.ts /** * Get markdown frontmatter and excerpt * * Extract them into env */ const frontmatterPlugin = (md, { grayMatterOptions, renderExcerpt = true } = {}) => { const parse = md.parse.bind(md); md.parse = (src, env = {}) => { const { data, content, excerpt = "" } = matter(src, grayMatterOptions); env.content = content; env.frontmatter = { ...env.frontmatter, ...data }; env.excerpt = renderExcerpt && excerpt ? md.render(excerpt, { ...env }) : excerpt; return parse(content, env); }; }; //#region src/headers-plugin.ts /** * Get markdown headers info * * Extract them into env */ const headersPlugin = (md, { level = [2, 3], shouldAllowNested = false, slugify: slugify$1 = slugify, format } = {}) => { const render = md.renderer.render.bind(md.renderer); md.renderer.render = (tokens, options, env) => { env.headers = resolveHeadersFromTokens(tokens, { level, shouldAllowHtml: false, shouldAllowNested, shouldEscapeText: false, slugify: slugify$1, format }); return render(tokens, options, env); }; }; //#region src/constants.ts const TAG_NAME_SCRIPT = "script"; const TAG_NAME_STYLE = "style"; const TAG_NAME_TEMPLATE = "template"; //#endregion //#region src/sfc-regexp.ts const SCRIPT_SETUP_TAG_OPEN_REGEXP = /^$/is; /** * Generate RegExp for sfc blocks */ const createSfcRegexp = ({ customBlocks }) => { const sfcTags = Array.from(new Set([ TAG_NAME_SCRIPT, TAG_NAME_STYLE, ...customBlocks ])).join("|"); return new RegExp(`^\\s*(?(?<(?${sfcTags})\\s?.*?>)(?.*)(?<\\/\\k\\s*>))\\s*$`, "is"); }; //#endregion //#region src/sfc-plugin.ts /** * Get Vue SFC blocks * * Extract them into env and avoid rendering them */ const sfcPlugin = (md, { customBlocks = [] } = {}) => { const sfcRegexp = createSfcRegexp({ customBlocks }); const render = md.render.bind(md); md.render = (src, env = {}) => { env.sfcBlocks = { template: null, script: null, scriptSetup: null, scripts: [], styles: [], customBlocks: [] }; const rendered = render(src, env); env.sfcBlocks.template = { type: TAG_NAME_TEMPLATE, content: `<${TAG_NAME_TEMPLATE}>${rendered}`, contentStripped: rendered, tagOpen: `<${TAG_NAME_TEMPLATE}>`, tagClose: `` }; return rendered; }; const htmlBlockRule = md.renderer.rules.html_block; md.renderer.rules.html_block = (tokens, idx, options, env, self) => { /* istanbul ignore if -- @preserve */ if (!env.sfcBlocks) return htmlBlockRule(tokens, idx, options, env, self); const token = tokens[idx]; const content = token.content; const match = content.match(sfcRegexp); if (!match) return htmlBlockRule(tokens, idx, options, env, self); const sfcBlock = match.groups; if (sfcBlock.type === TAG_NAME_SCRIPT) { env.sfcBlocks.scripts.push(sfcBlock); if (SCRIPT_SETUP_TAG_OPEN_REGEXP.test(sfcBlock.tagOpen)) env.sfcBlocks.scriptSetup = sfcBlock; else env.sfcBlocks.script = sfcBlock; } else if (sfcBlock.type === TAG_NAME_STYLE) env.sfcBlocks.styles.push(sfcBlock); else env.sfcBlocks.customBlocks.push(sfcBlock); return ""; }; }; //#region src/title-plugin.ts /** * Get markdown page title info * * Extract it into env */ const titlePlugin = (md) => { const render = md.renderer.render.bind(md.renderer); md.renderer.render = (tokens, options, env) => { const tokenIdx = tokens.findIndex((token) => token.tag === "h1"); env.title = tokenIdx > -1 ? resolveTitleFromToken(tokens[tokenIdx + 1], { shouldAllowHtml: false, shouldEscapeText: false }) : ""; return render(tokens, options, env); }; }; //#region src/create-render-headers.ts const createRenderHeaders = ({ listTag, listClass, itemClass, linkTag, linkClass }) => { const listTagString = htmlEscape(listTag); const listClassString = listClass ? ` class="${htmlEscape(listClass)}"` : ""; const itemTagString = "li"; const itemClassString = itemClass ? ` class="${htmlEscape(itemClass)}"` : ""; const linkTagString = htmlEscape(linkTag); const linkClassString = linkClass ? ` class="${htmlEscape(linkClass)}"` : ""; const linkTo = (link) => linkTag === "router-link" ? ` to="${link}"` : ` href="${link}"`; const renderHeaders = (headers) => `\ <${listTagString}${listClassString}>\ ${headers.map((header) => `\ <${itemTagString}${itemClassString}>\ <${linkTagString}${linkClassString}${linkTo(header.link)}>\ ${header.title}\ \ ${header.children.length > 0 ? renderHeaders(header.children) : ""}\ \ `).join("")}\ `; return renderHeaders; }; //#endregion //#region src/create-toc-block-rule.ts /** * Forked and modified from markdown-it-toc-done-right * * - remove the `inlineOptions` support * - use markdown-it default renderer to render token whenever possible * * @see https://github.com/nagaozen/markdown-it-toc-done-right */ const createTocBlockRule = ({ pattern, containerTag, containerClass }) => (state, startLine, endLine, silent) => { if (state.sCount[startLine] - state.blkIndent >= 4) return false; const pos = state.bMarks[startLine] + state.tShift[startLine]; const max = state.eMarks[startLine]; const lineFirstToken = state.src.slice(pos, max).split(" ")[0]; if (!pattern.test(lineFirstToken)) return false; if (silent) return true; state.line = startLine + 1; const tokenOpen = state.push("toc_open", containerTag, 1); tokenOpen.markup = ""; tokenOpen.map = [startLine, state.line]; if (containerClass) tokenOpen.attrSet("class", containerClass); const tokenBody = state.push("toc_body", "", 0); tokenBody.markup = lineFirstToken; tokenBody.map = [startLine, state.line]; tokenBody.hidden = true; const tokenClose = state.push("toc_close", containerTag, -1); tokenClose.markup = ""; tokenBody.map = [startLine, state.line]; return true; }; //#endregion //#region src/toc-plugin.ts /** * Generate table of contents * * Forked and modified from markdown-it-toc-done-right: * * @see https://github.com/nagaozen/markdown-it-toc-done-right */ const tocPlugin = (md, { pattern = /^\[\[toc\]\]$/i, slugify: slugify$1 = slugify, format, level = [2, 3], shouldAllowNested = false, containerTag = "nav", containerClass = "table-of-contents", listTag = "ul", listClass = "", itemClass = "", linkTag = "a", linkClass = "" } = {}) => { md.block.ruler.before("heading", "toc", createTocBlockRule({ pattern, containerTag, containerClass }), { alt: [ "paragraph", "reference", "blockquote" ] }); const renderHeaders = createRenderHeaders({ listTag, listClass, itemClass, linkTag, linkClass }); md.renderer.rules.toc_body = (tokens) => renderHeaders(resolveHeadersFromTokens(tokens, { level, shouldAllowHtml: true, shouldAllowNested, shouldEscapeText: true, slugify: slugify$1, format })); }; var e=false,n={false:"push",true:"unshift",after:"push",before:"unshift"},t={isPermalinkSymbol:true};function r(r,a,i,l){var o;if(!e){var c="Using deprecated markdown-it-anchor permalink option, see https://github.com/valeriangalliat/markdown-it-anchor#permalinks";"object"==typeof process&&process&&process.emitWarning?process.emitWarning(c):console.warn(c),e=true;}var s=[Object.assign(new i.Token("link_open","a",1),{attrs:[].concat(a.permalinkClass?[["class",a.permalinkClass]]:[],[["href",a.permalinkHref(r,i)]],Object.entries(a.permalinkAttrs(r,i)))}),Object.assign(new i.Token("html_block","",0),{content:a.permalinkSymbol,meta:t}),new i.Token("link_close","a",-1)];a.permalinkSpace&&i.tokens[l+1].children[n[a.permalinkBefore]](Object.assign(new i.Token("text","",0),{content:" "})),(o=i.tokens[l+1].children)[n[a.permalinkBefore]].apply(o,s);}function a(e){return "#"+e}function i(e){return {}}var l={class:"header-anchor",symbol:"#",renderHref:a,renderAttrs:i};function o(e){function n(t){return t=Object.assign({},n.defaults,t),function(n,r,a,i){return e(n,t,r,a,i)}}return n.defaults=Object.assign({},l),n.renderPermalinkImpl=e,n}function c(e){var n=[],t=e.filter(function(e){if("class"!==e[0])return true;n.push(e[1]);});return n.length>0&&t.unshift(["class",n.join(" ")]),t}var s=o(function(e,r,a,i,l){var o,s=[Object.assign(new i.Token("link_open","a",1),{attrs:c([].concat(r.class?[["class",r.class]]:[],[["href",r.renderHref(e,i)]],r.ariaHidden?[["aria-hidden","true"]]:[],Object.entries(r.renderAttrs(e,i))))}),Object.assign(new i.Token("html_inline","",0),{content:r.symbol,meta:t}),new i.Token("link_close","a",-1)];if(r.space){var u="string"==typeof r.space?r.space:" ";i.tokens[l+1].children[n[r.placement]](Object.assign(new i.Token("string"==typeof r.space?"html_inline":"text","",0),{content:u}));}(o=i.tokens[l+1].children)[n[r.placement]].apply(o,s);});Object.assign(s.defaults,{space:true,placement:"after",ariaHidden:false});var u=o(s.renderPermalinkImpl);u.defaults=Object.assign({},s.defaults,{ariaHidden:true});var d$1=o(function(e,n,t,r,a){var i=[Object.assign(new r.Token("link_open","a",1),{attrs:c([].concat(n.class?[["class",n.class]]:[],[["href",n.renderHref(e,r)]],Object.entries(n.renderAttrs(e,r))))})].concat(n.safariReaderFix?[new r.Token("span_open","span",1)]:[],r.tokens[a+1].children,n.safariReaderFix?[new r.Token("span_close","span",-1)]:[],[new r.Token("link_close","a",-1)]);r.tokens[a+1]=Object.assign(new r.Token("inline","",0),{children:i});});Object.assign(d$1.defaults,{safariReaderFix:false});var f=o(function(e,r,a,i,l){var o;if(!["visually-hidden","aria-label","aria-describedby","aria-labelledby"].includes(r.style))throw new Error("`permalink.linkAfterHeader` called with unknown style option `"+r.style+"`");if(!["aria-describedby","aria-labelledby"].includes(r.style)&&!r.assistiveText)throw new Error("`permalink.linkAfterHeader` called without the `assistiveText` option in `"+r.style+"` style");if("visually-hidden"===r.style&&!r.visuallyHiddenClass)throw new Error("`permalink.linkAfterHeader` called without the `visuallyHiddenClass` option in `visually-hidden` style");var s=i.tokens[l+1].children.filter(function(e){return "text"===e.type||"code_inline"===e.type}).reduce(function(e,n){return e+n.content},""),u=[],d=[];if(r.class&&d.push(["class",r.class]),d.push(["href",r.renderHref(e,i)]),d.push.apply(d,Object.entries(r.renderAttrs(e,i))),"visually-hidden"===r.style){if(u.push(Object.assign(new i.Token("span_open","span",1),{attrs:[["class",r.visuallyHiddenClass]]}),Object.assign(new i.Token("text","",0),{content:r.assistiveText(s)}),new i.Token("span_close","span",-1)),r.space){var f="string"==typeof r.space?r.space:" ";u[n[r.placement]](Object.assign(new i.Token("string"==typeof r.space?"html_inline":"text","",0),{content:f}));}u[n[r.placement]](Object.assign(new i.Token("span_open","span",1),{attrs:[["aria-hidden","true"]]}),Object.assign(new i.Token("html_inline","",0),{content:r.symbol,meta:t}),new i.Token("span_close","span",-1));}else u.push(Object.assign(new i.Token("html_inline","",0),{content:r.symbol,meta:t}));"aria-label"===r.style?d.push(["aria-label",r.assistiveText(s)]):["aria-describedby","aria-labelledby"].includes(r.style)&&d.push([r.style,e]);var p=[Object.assign(new i.Token("link_open","a",1),{attrs:c(d)})].concat(u,[new i.Token("link_close","a",-1)]);(o=i.tokens).splice.apply(o,[l+3,0].concat(p)),r.wrapper&&(i.tokens.splice(l,0,Object.assign(new i.Token("html_block","",0),{content:r.wrapper[0]+"\n"})),i.tokens.splice(l+3+p.length+1,0,Object.assign(new i.Token("html_block","",0),{content:r.wrapper[1]+"\n"})));});function p(e,n,t,r){var a=e,i=r;if(t&&Object.prototype.hasOwnProperty.call(n,a))throw new Error("User defined `id` attribute `"+e+"` is not unique. Please fix it in your Markdown to continue.");for(;Object.prototype.hasOwnProperty.call(n,a);)a=e+"-"+i,i+=1;return n[a]=true,a}function b$1(e,n){n=Object.assign({},b$1.defaults,n),e.core.ruler.push("anchor",function(e){for(var t,a={},i=e.tokens,l=Array.isArray(n.level)?(t=n.level,function(e){return t.includes(e)}):function(e){return function(n){return n>=e}}(n.level),o=0;o= 0xD800 && chr <= 0xDFFF)) { result += '\ufffd\ufffd\ufffd'; } else { result += String.fromCharCode(chr); } i += 6; continue } } if ((b1 & 0xF8) === 0xF0 && (i + 9 < l)) { // 111110xx 10xxxxxx 10xxxxxx 10xxxxxx const b2 = parseInt(seq.slice(i + 4, i + 6), 16); const b3 = parseInt(seq.slice(i + 7, i + 9), 16); const b4 = parseInt(seq.slice(i + 10, i + 12), 16); if ((b2 & 0xC0) === 0x80 && (b3 & 0xC0) === 0x80 && (b4 & 0xC0) === 0x80) { let chr = ((b1 << 18) & 0x1C0000) | ((b2 << 12) & 0x3F000) | ((b3 << 6) & 0xFC0) | (b4 & 0x3F); if (chr < 0x10000 || chr > 0x10FFFF) { result += '\ufffd\ufffd\ufffd\ufffd'; } else { chr -= 0x10000; result += String.fromCharCode(0xD800 + (chr >> 10), 0xDC00 + (chr & 0x3FF)); } i += 9; continue } } result += '\ufffd'; } return result }) } decode$1.defaultChars = ';/?:@&=+$,#'; decode$1.componentChars = ''; const encodeCache = {}; // Create a lookup array where anything but characters in `chars` string // and alphanumeric chars is percent-encoded. // function getEncodeCache (exclude) { let cache = encodeCache[exclude]; if (cache) { return cache } cache = encodeCache[exclude] = []; for (let i = 0; i < 128; i++) { const ch = String.fromCharCode(i); if (/^[0-9a-z]$/i.test(ch)) { // always allow unencoded alphanumeric characters cache.push(ch); } else { cache.push('%' + ('0' + i.toString(16).toUpperCase()).slice(-2)); } } for (let i = 0; i < exclude.length; i++) { cache[exclude.charCodeAt(i)] = exclude[i]; } return cache } // Encode unsafe characters with percent-encoding, skipping already // encoded sequences. // // - string - string to encode // - exclude - list of characters to ignore (in addition to a-zA-Z0-9) // - keepEscaped - don't encode '%' in a correct escape sequence (default: true) // function encode$1 (string, exclude, keepEscaped) { if (typeof exclude !== 'string') { // encode(string, keepEscaped) keepEscaped = exclude; exclude = encode$1.defaultChars; } if (typeof keepEscaped === 'undefined') { keepEscaped = true; } const cache = getEncodeCache(exclude); let result = ''; for (let i = 0, l = string.length; i < l; i++) { const code = string.charCodeAt(i); if (keepEscaped && code === 0x25 /* % */ && i + 2 < l) { if (/^[0-9a-f]{2}$/i.test(string.slice(i + 1, i + 3))) { result += string.slice(i, i + 3); i += 2; continue } } if (code < 128) { result += cache[code]; continue } if (code >= 0xD800 && code <= 0xDFFF) { if (code >= 0xD800 && code <= 0xDBFF && i + 1 < l) { const nextCode = string.charCodeAt(i + 1); if (nextCode >= 0xDC00 && nextCode <= 0xDFFF) { result += encodeURIComponent(string[i] + string[i + 1]); i++; continue } } result += '%EF%BF%BD'; continue } result += encodeURIComponent(string[i]); } return result } encode$1.defaultChars = ";/?:@&=+$,-_.!~*'()#"; encode$1.componentChars = "-_.!~*'()"; function format (url) { let result = ''; result += url.protocol || ''; result += url.slashes ? '//' : ''; result += url.auth ? url.auth + '@' : ''; if (url.hostname && url.hostname.indexOf(':') !== -1) { // ipv6 address result += '[' + url.hostname + ']'; } else { result += url.hostname || ''; } result += url.port ? ':' + url.port : ''; result += url.pathname || ''; result += url.search || ''; result += url.hash || ''; return result } // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to permit // persons to whom the Software is furnished to do so, subject to the // following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. // // Changes from joyent/node: // // 1. No leading slash in paths, // e.g. in `url.parse('http://foo?bar')` pathname is ``, not `/` // // 2. Backslashes are not replaced with slashes, // so `http:\\example.org\` is treated like a relative path // // 3. Trailing colon is treated like a part of the path, // i.e. in `http://example.org:foo` pathname is `:foo` // // 4. Nothing is URL-encoded in the resulting object, // (in joyent/node some chars in auth and paths are encoded) // // 5. `url.parse()` does not have `parseQueryString` argument // // 6. Removed extraneous result properties: `host`, `path`, `query`, etc., // which can be constructed using other parts of the url. // function Url () { this.protocol = null; this.slashes = null; this.auth = null; this.port = null; this.hostname = null; this.hash = null; this.search = null; this.pathname = null; } // Reference: RFC 3986, RFC 1808, RFC 2396 // define these here so at least they only have to be // compiled once on the first module load. const protocolPattern = /^([a-z0-9.+-]+:)/i; const portPattern = /:[0-9]*$/; // Special case for a simple path URL /* eslint-disable-next-line no-useless-escape */ const simplePathPattern = /^(\/\/?(?!\/)[^\?\s]*)(\?[^\s]*)?$/; // RFC 2396: characters reserved for delimiting URLs. // We actually just auto-escape these. const delims = ['<', '>', '"', '`', ' ', '\r', '\n', '\t']; // RFC 2396: characters not allowed for various reasons. const unwise = ['{', '}', '|', '\\', '^', '`'].concat(delims); // Allowed by RFCs, but cause of XSS attacks. Always escape these. const autoEscape = ['\''].concat(unwise); // Characters that are never ever allowed in a hostname. // Note that any invalid chars are also handled, but these // are the ones that are *expected* to be seen, so we fast-path // them. const nonHostChars = ['%', '/', '?', ';', '#'].concat(autoEscape); const hostEndingChars = ['/', '?', '#']; const hostnameMaxLen = 255; const hostnamePartPattern = /^[+a-z0-9A-Z_-]{0,63}$/; const hostnamePartStart = /^([+a-z0-9A-Z_-]{0,63})(.*)$/; // protocols that can allow "unsafe" and "unwise" chars. // protocols that never have a hostname. const hostlessProtocol = { javascript: true, 'javascript:': true }; // protocols that always contain a // bit. const slashedProtocol = { http: true, https: true, ftp: true, gopher: true, file: true, 'http:': true, 'https:': true, 'ftp:': true, 'gopher:': true, 'file:': true }; function urlParse (url, slashesDenoteHost) { if (url && url instanceof Url) return url const u = new Url(); u.parse(url, slashesDenoteHost); return u } Url.prototype.parse = function (url, slashesDenoteHost) { let lowerProto, hec, slashes; let rest = url; // trim before proceeding. // This is to support parse stuff like " http://foo.com \n" rest = rest.trim(); if (!slashesDenoteHost && url.split('#').length === 1) { // Try fast path regexp const simplePath = simplePathPattern.exec(rest); if (simplePath) { this.pathname = simplePath[1]; if (simplePath[2]) { this.search = simplePath[2]; } return this } } let proto = protocolPattern.exec(rest); if (proto) { proto = proto[0]; lowerProto = proto.toLowerCase(); this.protocol = proto; rest = rest.substr(proto.length); } // figure out if it's got a host // user@server is *always* interpreted as a hostname, and url // resolution will treat //foo/bar as host=foo,path=bar because that's // how the browser resolves relative URLs. /* eslint-disable-next-line no-useless-escape */ if (slashesDenoteHost || proto || rest.match(/^\/\/[^@\/]+@[^@\/]+/)) { slashes = rest.substr(0, 2) === '//'; if (slashes && !(proto && hostlessProtocol[proto])) { rest = rest.substr(2); this.slashes = true; } } if (!hostlessProtocol[proto] && (slashes || (proto && !slashedProtocol[proto]))) { // there's a hostname. // the first instance of /, ?, ;, or # ends the host. // // If there is an @ in the hostname, then non-host chars *are* allowed // to the left of the last @ sign, unless some host-ending character // comes *before* the @-sign. // URLs are obnoxious. // // ex: // http://a@b@c/ => user:a@b host:c // http://a@b?@c => user:a host:c path:/?@c // v0.12 TODO(isaacs): This is not quite how Chrome does things. // Review our test case against browsers more comprehensively. // find the first instance of any hostEndingChars let hostEnd = -1; for (let i = 0; i < hostEndingChars.length; i++) { hec = rest.indexOf(hostEndingChars[i]); if (hec !== -1 && (hostEnd === -1 || hec < hostEnd)) { hostEnd = hec; } } // at this point, either we have an explicit point where the // auth portion cannot go past, or the last @ char is the decider. let auth, atSign; if (hostEnd === -1) { // atSign can be anywhere. atSign = rest.lastIndexOf('@'); } else { // atSign must be in auth portion. // http://a@b/c@d => host:b auth:a path:/c@d atSign = rest.lastIndexOf('@', hostEnd); } // Now we have a portion which is definitely the auth. // Pull that off. if (atSign !== -1) { auth = rest.slice(0, atSign); rest = rest.slice(atSign + 1); this.auth = auth; } // the host is the remaining to the left of the first non-host char hostEnd = -1; for (let i = 0; i < nonHostChars.length; i++) { hec = rest.indexOf(nonHostChars[i]); if (hec !== -1 && (hostEnd === -1 || hec < hostEnd)) { hostEnd = hec; } } // if we still have not hit it, then the entire thing is a host. if (hostEnd === -1) { hostEnd = rest.length; } if (rest[hostEnd - 1] === ':') { hostEnd--; } const host = rest.slice(0, hostEnd); rest = rest.slice(hostEnd); // pull out port. this.parseHost(host); // we've indicated that there is a hostname, // so even if it's empty, it has to be present. this.hostname = this.hostname || ''; // if hostname begins with [ and ends with ] // assume that it's an IPv6 address. const ipv6Hostname = this.hostname[0] === '[' && this.hostname[this.hostname.length - 1] === ']'; // validate a little. if (!ipv6Hostname) { const hostparts = this.hostname.split(/\./); for (let i = 0, l = hostparts.length; i < l; i++) { const part = hostparts[i]; if (!part) { continue } if (!part.match(hostnamePartPattern)) { let newpart = ''; for (let j = 0, k = part.length; j < k; j++) { if (part.charCodeAt(j) > 127) { // we replace non-ASCII char with a temporary placeholder // we need this to make sure size of hostname is not // broken by replacing non-ASCII by nothing newpart += 'x'; } else { newpart += part[j]; } } // we test again with ASCII char only if (!newpart.match(hostnamePartPattern)) { const validParts = hostparts.slice(0, i); const notHost = hostparts.slice(i + 1); const bit = part.match(hostnamePartStart); if (bit) { validParts.push(bit[1]); notHost.unshift(bit[2]); } if (notHost.length) { rest = notHost.join('.') + rest; } this.hostname = validParts.join('.'); break } } } } if (this.hostname.length > hostnameMaxLen) { this.hostname = ''; } // strip [ and ] from the hostname // the host field still retains them, though if (ipv6Hostname) { this.hostname = this.hostname.substr(1, this.hostname.length - 2); } } // chop off from the tail first. const hash = rest.indexOf('#'); if (hash !== -1) { // got a fragment string. this.hash = rest.substr(hash); rest = rest.slice(0, hash); } const qm = rest.indexOf('?'); if (qm !== -1) { this.search = rest.substr(qm); rest = rest.slice(0, qm); } if (rest) { this.pathname = rest; } if (slashedProtocol[lowerProto] && this.hostname && !this.pathname) { this.pathname = ''; } return this }; Url.prototype.parseHost = function (host) { let port = portPattern.exec(host); if (port) { port = port[0]; if (port !== ':') { this.port = port.substr(1); } host = host.substr(0, host.length - port.length); } if (host) { this.hostname = host; } }; var mdurl = /*#__PURE__*/Object.freeze({ __proto__: null, decode: decode$1, encode: encode$1, format: format, parse: urlParse }); var Any = /[\0-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/; var Cc = /[\0-\x1F\x7F-\x9F]/; var regex$2 = /[\xAD\u0600-\u0605\u061C\u06DD\u070F\u0890\u0891\u08E2\u180E\u200B-\u200F\u202A-\u202E\u2060-\u2064\u2066-\u206F\uFEFF\uFFF9-\uFFFB]|\uD804[\uDCBD\uDCCD]|\uD80D[\uDC30-\uDC3F]|\uD82F[\uDCA0-\uDCA3]|\uD834[\uDD73-\uDD7A]|\uDB40[\uDC01\uDC20-\uDC7F]/; var P$1 = /[!-#%-\*,-\/:;\?@\[-\]_\{\}\xA1\xA7\xAB\xB6\xB7\xBB\xBF\u037E\u0387\u055A-\u055F\u0589\u058A\u05BE\u05C0\u05C3\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061D-\u061F\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E\u085E\u0964\u0965\u0970\u09FD\u0A76\u0AF0\u0C77\u0C84\u0DF4\u0E4F\u0E5A\u0E5B\u0F04-\u0F12\u0F14\u0F3A-\u0F3D\u0F85\u0FD0-\u0FD4\u0FD9\u0FDA\u104A-\u104F\u10FB\u1360-\u1368\u1400\u166E\u169B\u169C\u16EB-\u16ED\u1735\u1736\u17D4-\u17D6\u17D8-\u17DA\u1800-\u180A\u1944\u1945\u1A1E\u1A1F\u1AA0-\u1AA6\u1AA8-\u1AAD\u1B5A-\u1B60\u1B7D\u1B7E\u1BFC-\u1BFF\u1C3B-\u1C3F\u1C7E\u1C7F\u1CC0-\u1CC7\u1CD3\u2010-\u2027\u2030-\u2043\u2045-\u2051\u2053-\u205E\u207D\u207E\u208D\u208E\u2308-\u230B\u2329\u232A\u2768-\u2775\u27C5\u27C6\u27E6-\u27EF\u2983-\u2998\u29D8-\u29DB\u29FC\u29FD\u2CF9-\u2CFC\u2CFE\u2CFF\u2D70\u2E00-\u2E2E\u2E30-\u2E4F\u2E52-\u2E5D\u3001-\u3003\u3008-\u3011\u3014-\u301F\u3030\u303D\u30A0\u30FB\uA4FE\uA4FF\uA60D-\uA60F\uA673\uA67E\uA6F2-\uA6F7\uA874-\uA877\uA8CE\uA8CF\uA8F8-\uA8FA\uA8FC\uA92E\uA92F\uA95F\uA9C1-\uA9CD\uA9DE\uA9DF\uAA5C-\uAA5F\uAADE\uAADF\uAAF0\uAAF1\uABEB\uFD3E\uFD3F\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE61\uFE63\uFE68\uFE6A\uFE6B\uFF01-\uFF03\uFF05-\uFF0A\uFF0C-\uFF0F\uFF1A\uFF1B\uFF1F\uFF20\uFF3B-\uFF3D\uFF3F\uFF5B\uFF5D\uFF5F-\uFF65]|\uD800[\uDD00-\uDD02\uDF9F\uDFD0]|\uD801\uDD6F|\uD802[\uDC57\uDD1F\uDD3F\uDE50-\uDE58\uDE7F\uDEF0-\uDEF6\uDF39-\uDF3F\uDF99-\uDF9C]|\uD803[\uDEAD\uDF55-\uDF59\uDF86-\uDF89]|\uD804[\uDC47-\uDC4D\uDCBB\uDCBC\uDCBE-\uDCC1\uDD40-\uDD43\uDD74\uDD75\uDDC5-\uDDC8\uDDCD\uDDDB\uDDDD-\uDDDF\uDE38-\uDE3D\uDEA9]|\uD805[\uDC4B-\uDC4F\uDC5A\uDC5B\uDC5D\uDCC6\uDDC1-\uDDD7\uDE41-\uDE43\uDE60-\uDE6C\uDEB9\uDF3C-\uDF3E]|\uD806[\uDC3B\uDD44-\uDD46\uDDE2\uDE3F-\uDE46\uDE9A-\uDE9C\uDE9E-\uDEA2\uDF00-\uDF09]|\uD807[\uDC41-\uDC45\uDC70\uDC71\uDEF7\uDEF8\uDF43-\uDF4F\uDFFF]|\uD809[\uDC70-\uDC74]|\uD80B[\uDFF1\uDFF2]|\uD81A[\uDE6E\uDE6F\uDEF5\uDF37-\uDF3B\uDF44]|\uD81B[\uDE97-\uDE9A\uDFE2]|\uD82F\uDC9F|\uD836[\uDE87-\uDE8B]|\uD83A[\uDD5E\uDD5F]/; var regex$1 = /[\$\+<->\^`\|~\xA2-\xA6\xA8\xA9\xAC\xAE-\xB1\xB4\xB8\xD7\xF7\u02C2-\u02C5\u02D2-\u02DF\u02E5-\u02EB\u02ED\u02EF-\u02FF\u0375\u0384\u0385\u03F6\u0482\u058D-\u058F\u0606-\u0608\u060B\u060E\u060F\u06DE\u06E9\u06FD\u06FE\u07F6\u07FE\u07FF\u0888\u09F2\u09F3\u09FA\u09FB\u0AF1\u0B70\u0BF3-\u0BFA\u0C7F\u0D4F\u0D79\u0E3F\u0F01-\u0F03\u0F13\u0F15-\u0F17\u0F1A-\u0F1F\u0F34\u0F36\u0F38\u0FBE-\u0FC5\u0FC7-\u0FCC\u0FCE\u0FCF\u0FD5-\u0FD8\u109E\u109F\u1390-\u1399\u166D\u17DB\u1940\u19DE-\u19FF\u1B61-\u1B6A\u1B74-\u1B7C\u1FBD\u1FBF-\u1FC1\u1FCD-\u1FCF\u1FDD-\u1FDF\u1FED-\u1FEF\u1FFD\u1FFE\u2044\u2052\u207A-\u207C\u208A-\u208C\u20A0-\u20C0\u2100\u2101\u2103-\u2106\u2108\u2109\u2114\u2116-\u2118\u211E-\u2123\u2125\u2127\u2129\u212E\u213A\u213B\u2140-\u2144\u214A-\u214D\u214F\u218A\u218B\u2190-\u2307\u230C-\u2328\u232B-\u2426\u2440-\u244A\u249C-\u24E9\u2500-\u2767\u2794-\u27C4\u27C7-\u27E5\u27F0-\u2982\u2999-\u29D7\u29DC-\u29FB\u29FE-\u2B73\u2B76-\u2B95\u2B97-\u2BFF\u2CE5-\u2CEA\u2E50\u2E51\u2E80-\u2E99\u2E9B-\u2EF3\u2F00-\u2FD5\u2FF0-\u2FFF\u3004\u3012\u3013\u3020\u3036\u3037\u303E\u303F\u309B\u309C\u3190\u3191\u3196-\u319F\u31C0-\u31E3\u31EF\u3200-\u321E\u322A-\u3247\u3250\u3260-\u327F\u328A-\u32B0\u32C0-\u33FF\u4DC0-\u4DFF\uA490-\uA4C6\uA700-\uA716\uA720\uA721\uA789\uA78A\uA828-\uA82B\uA836-\uA839\uAA77-\uAA79\uAB5B\uAB6A\uAB6B\uFB29\uFBB2-\uFBC2\uFD40-\uFD4F\uFDCF\uFDFC-\uFDFF\uFE62\uFE64-\uFE66\uFE69\uFF04\uFF0B\uFF1C-\uFF1E\uFF3E\uFF40\uFF5C\uFF5E\uFFE0-\uFFE6\uFFE8-\uFFEE\uFFFC\uFFFD]|\uD800[\uDD37-\uDD3F\uDD79-\uDD89\uDD8C-\uDD8E\uDD90-\uDD9C\uDDA0\uDDD0-\uDDFC]|\uD802[\uDC77\uDC78\uDEC8]|\uD805\uDF3F|\uD807[\uDFD5-\uDFF1]|\uD81A[\uDF3C-\uDF3F\uDF45]|\uD82F\uDC9C|\uD833[\uDF50-\uDFC3]|\uD834[\uDC00-\uDCF5\uDD00-\uDD26\uDD29-\uDD64\uDD6A-\uDD6C\uDD83\uDD84\uDD8C-\uDDA9\uDDAE-\uDDEA\uDE00-\uDE41\uDE45\uDF00-\uDF56]|\uD835[\uDEC1\uDEDB\uDEFB\uDF15\uDF35\uDF4F\uDF6F\uDF89\uDFA9\uDFC3]|\uD836[\uDC00-\uDDFF\uDE37-\uDE3A\uDE6D-\uDE74\uDE76-\uDE83\uDE85\uDE86]|\uD838[\uDD4F\uDEFF]|\uD83B[\uDCAC\uDCB0\uDD2E\uDEF0\uDEF1]|\uD83C[\uDC00-\uDC2B\uDC30-\uDC93\uDCA0-\uDCAE\uDCB1-\uDCBF\uDCC1-\uDCCF\uDCD1-\uDCF5\uDD0D-\uDDAD\uDDE6-\uDE02\uDE10-\uDE3B\uDE40-\uDE48\uDE50\uDE51\uDE60-\uDE65\uDF00-\uDFFF]|\uD83D[\uDC00-\uDED7\uDEDC-\uDEEC\uDEF0-\uDEFC\uDF00-\uDF76\uDF7B-\uDFD9\uDFE0-\uDFEB\uDFF0]|\uD83E[\uDC00-\uDC0B\uDC10-\uDC47\uDC50-\uDC59\uDC60-\uDC87\uDC90-\uDCAD\uDCB0\uDCB1\uDD00-\uDE53\uDE60-\uDE6D\uDE70-\uDE7C\uDE80-\uDE88\uDE90-\uDEBD\uDEBF-\uDEC5\uDECE-\uDEDB\uDEE0-\uDEE8\uDEF0-\uDEF8\uDF00-\uDF92\uDF94-\uDFCA]/; var Z$1 = /[ \xA0\u1680\u2000-\u200A\u2028\u2029\u202F\u205F\u3000]/; var ucmicro = /*#__PURE__*/Object.freeze({ __proto__: null, Any: Any, Cc: Cc, Cf: regex$2, P: P$1, S: regex$1, Z: Z$1 }); // Generated using scripts/write-decode-map.ts var htmlDecodeTree = new Uint16Array( // prettier-ignore "\u1d41<\xd5\u0131\u028a\u049d\u057b\u05d0\u0675\u06de\u07a2\u07d6\u080f\u0a4a\u0a91\u0da1\u0e6d\u0f09\u0f26\u10ca\u1228\u12e1\u1415\u149d\u14c3\u14df\u1525\0\0\0\0\0\0\u156b\u16cd\u198d\u1c12\u1ddd\u1f7e\u2060\u21b0\u228d\u23c0\u23fb\u2442\u2824\u2912\u2d08\u2e48\u2fce\u3016\u32ba\u3639\u37ac\u38fe\u3a28\u3a71\u3ae0\u3b2e\u0800EMabcfglmnoprstu\\bfms\x7f\x84\x8b\x90\x95\x98\xa6\xb3\xb9\xc8\xcflig\u803b\xc6\u40c6P\u803b&\u4026cute\u803b\xc1\u40c1reve;\u4102\u0100iyx}rc\u803b\xc2\u40c2;\u4410r;\uc000\ud835\udd04rave\u803b\xc0\u40c0pha;\u4391acr;\u4100d;\u6a53\u0100gp\x9d\xa1on;\u4104f;\uc000\ud835\udd38plyFunction;\u6061ing\u803b\xc5\u40c5\u0100cs\xbe\xc3r;\uc000\ud835\udc9cign;\u6254ilde\u803b\xc3\u40c3ml\u803b\xc4\u40c4\u0400aceforsu\xe5\xfb\xfe\u0117\u011c\u0122\u0127\u012a\u0100cr\xea\xf2kslash;\u6216\u0176\xf6\xf8;\u6ae7ed;\u6306y;\u4411\u0180crt\u0105\u010b\u0114ause;\u6235noullis;\u612ca;\u4392r;\uc000\ud835\udd05pf;\uc000\ud835\udd39eve;\u42d8c\xf2\u0113mpeq;\u624e\u0700HOacdefhilorsu\u014d\u0151\u0156\u0180\u019e\u01a2\u01b5\u01b7\u01ba\u01dc\u0215\u0273\u0278\u027ecy;\u4427PY\u803b\xa9\u40a9\u0180cpy\u015d\u0162\u017aute;\u4106\u0100;i\u0167\u0168\u62d2talDifferentialD;\u6145leys;\u612d\u0200aeio\u0189\u018e\u0194\u0198ron;\u410cdil\u803b\xc7\u40c7rc;\u4108nint;\u6230ot;\u410a\u0100dn\u01a7\u01adilla;\u40b8terDot;\u40b7\xf2\u017fi;\u43a7rcle\u0200DMPT\u01c7\u01cb\u01d1\u01d6ot;\u6299inus;\u6296lus;\u6295imes;\u6297o\u0100cs\u01e2\u01f8kwiseContourIntegral;\u6232eCurly\u0100DQ\u0203\u020foubleQuote;\u601duote;\u6019\u0200lnpu\u021e\u0228\u0247\u0255on\u0100;e\u0225\u0226\u6237;\u6a74\u0180git\u022f\u0236\u023aruent;\u6261nt;\u622fourIntegral;\u622e\u0100fr\u024c\u024e;\u6102oduct;\u6210nterClockwiseContourIntegral;\u6233oss;\u6a2fcr;\uc000\ud835\udc9ep\u0100;C\u0284\u0285\u62d3ap;\u624d\u0580DJSZacefios\u02a0\u02ac\u02b0\u02b4\u02b8\u02cb\u02d7\u02e1\u02e6\u0333\u048d\u0100;o\u0179\u02a5trahd;\u6911cy;\u4402cy;\u4405cy;\u440f\u0180grs\u02bf\u02c4\u02c7ger;\u6021r;\u61a1hv;\u6ae4\u0100ay\u02d0\u02d5ron;\u410e;\u4414l\u0100;t\u02dd\u02de\u6207a;\u4394r;\uc000\ud835\udd07\u0100af\u02eb\u0327\u0100cm\u02f0\u0322ritical\u0200ADGT\u0300\u0306\u0316\u031ccute;\u40b4o\u0174\u030b\u030d;\u42d9bleAcute;\u42ddrave;\u4060ilde;\u42dcond;\u62c4ferentialD;\u6146\u0470\u033d\0\0\0\u0342\u0354\0\u0405f;\uc000\ud835\udd3b\u0180;DE\u0348\u0349\u034d\u40a8ot;\u60dcqual;\u6250ble\u0300CDLRUV\u0363\u0372\u0382\u03cf\u03e2\u03f8ontourIntegra\xec\u0239o\u0274\u0379\0\0\u037b\xbb\u0349nArrow;\u61d3\u0100eo\u0387\u03a4ft\u0180ART\u0390\u0396\u03a1rrow;\u61d0ightArrow;\u61d4e\xe5\u02cang\u0100LR\u03ab\u03c4eft\u0100AR\u03b3\u03b9rrow;\u67f8ightArrow;\u67faightArrow;\u67f9ight\u0100AT\u03d8\u03derrow;\u61d2ee;\u62a8p\u0241\u03e9\0\0\u03efrrow;\u61d1ownArrow;\u61d5erticalBar;\u6225n\u0300ABLRTa\u0412\u042a\u0430\u045e\u047f\u037crrow\u0180;BU\u041d\u041e\u0422\u6193ar;\u6913pArrow;\u61f5reve;\u4311eft\u02d2\u043a\0\u0446\0\u0450ightVector;\u6950eeVector;\u695eector\u0100;B\u0459\u045a\u61bdar;\u6956ight\u01d4\u0467\0\u0471eeVector;\u695fector\u0100;B\u047a\u047b\u61c1ar;\u6957ee\u0100;A\u0486\u0487\u62a4rrow;\u61a7\u0100ct\u0492\u0497r;\uc000\ud835\udc9frok;\u4110\u0800NTacdfglmopqstux\u04bd\u04c0\u04c4\u04cb\u04de\u04e2\u04e7\u04ee\u04f5\u0521\u052f\u0536\u0552\u055d\u0560\u0565G;\u414aH\u803b\xd0\u40d0cute\u803b\xc9\u40c9\u0180aiy\u04d2\u04d7\u04dcron;\u411arc\u803b\xca\u40ca;\u442dot;\u4116r;\uc000\ud835\udd08rave\u803b\xc8\u40c8ement;\u6208\u0100ap\u04fa\u04fecr;\u4112ty\u0253\u0506\0\0\u0512mallSquare;\u65fberySmallSquare;\u65ab\u0100gp\u0526\u052aon;\u4118f;\uc000\ud835\udd3csilon;\u4395u\u0100ai\u053c\u0549l\u0100;T\u0542\u0543\u6a75ilde;\u6242librium;\u61cc\u0100ci\u0557\u055ar;\u6130m;\u6a73a;\u4397ml\u803b\xcb\u40cb\u0100ip\u056a\u056fsts;\u6203onentialE;\u6147\u0280cfios\u0585\u0588\u058d\u05b2\u05ccy;\u4424r;\uc000\ud835\udd09lled\u0253\u0597\0\0\u05a3mallSquare;\u65fcerySmallSquare;\u65aa\u0370\u05ba\0\u05bf\0\0\u05c4f;\uc000\ud835\udd3dAll;\u6200riertrf;\u6131c\xf2\u05cb\u0600JTabcdfgorst\u05e8\u05ec\u05ef\u05fa\u0600\u0612\u0616\u061b\u061d\u0623\u066c\u0672cy;\u4403\u803b>\u403emma\u0100;d\u05f7\u05f8\u4393;\u43dcreve;\u411e\u0180eiy\u0607\u060c\u0610dil;\u4122rc;\u411c;\u4413ot;\u4120r;\uc000\ud835\udd0a;\u62d9pf;\uc000\ud835\udd3eeater\u0300EFGLST\u0635\u0644\u064e\u0656\u065b\u0666qual\u0100;L\u063e\u063f\u6265ess;\u62dbullEqual;\u6267reater;\u6aa2ess;\u6277lantEqual;\u6a7eilde;\u6273cr;\uc000\ud835\udca2;\u626b\u0400Aacfiosu\u0685\u068b\u0696\u069b\u069e\u06aa\u06be\u06caRDcy;\u442a\u0100ct\u0690\u0694ek;\u42c7;\u405eirc;\u4124r;\u610clbertSpace;\u610b\u01f0\u06af\0\u06b2f;\u610dizontalLine;\u6500\u0100ct\u06c3\u06c5\xf2\u06a9rok;\u4126mp\u0144\u06d0\u06d8ownHum\xf0\u012fqual;\u624f\u0700EJOacdfgmnostu\u06fa\u06fe\u0703\u0707\u070e\u071a\u071e\u0721\u0728\u0744\u0778\u078b\u078f\u0795cy;\u4415lig;\u4132cy;\u4401cute\u803b\xcd\u40cd\u0100iy\u0713\u0718rc\u803b\xce\u40ce;\u4418ot;\u4130r;\u6111rave\u803b\xcc\u40cc\u0180;ap\u0720\u072f\u073f\u0100cg\u0734\u0737r;\u412ainaryI;\u6148lie\xf3\u03dd\u01f4\u0749\0\u0762\u0100;e\u074d\u074e\u622c\u0100gr\u0753\u0758ral;\u622bsection;\u62c2isible\u0100CT\u076c\u0772omma;\u6063imes;\u6062\u0180gpt\u077f\u0783\u0788on;\u412ef;\uc000\ud835\udd40a;\u4399cr;\u6110ilde;\u4128\u01eb\u079a\0\u079ecy;\u4406l\u803b\xcf\u40cf\u0280cfosu\u07ac\u07b7\u07bc\u07c2\u07d0\u0100iy\u07b1\u07b5rc;\u4134;\u4419r;\uc000\ud835\udd0dpf;\uc000\ud835\udd41\u01e3\u07c7\0\u07ccr;\uc000\ud835\udca5rcy;\u4408kcy;\u4404\u0380HJacfos\u07e4\u07e8\u07ec\u07f1\u07fd\u0802\u0808cy;\u4425cy;\u440cppa;\u439a\u0100ey\u07f6\u07fbdil;\u4136;\u441ar;\uc000\ud835\udd0epf;\uc000\ud835\udd42cr;\uc000\ud835\udca6\u0580JTaceflmost\u0825\u0829\u082c\u0850\u0863\u09b3\u09b8\u09c7\u09cd\u0a37\u0a47cy;\u4409\u803b<\u403c\u0280cmnpr\u0837\u083c\u0841\u0844\u084dute;\u4139bda;\u439bg;\u67ealacetrf;\u6112r;\u619e\u0180aey\u0857\u085c\u0861ron;\u413ddil;\u413b;\u441b\u0100fs\u0868\u0970t\u0500ACDFRTUVar\u087e\u08a9\u08b1\u08e0\u08e6\u08fc\u092f\u095b\u0390\u096a\u0100nr\u0883\u088fgleBracket;\u67e8row\u0180;BR\u0899\u089a\u089e\u6190ar;\u61e4ightArrow;\u61c6eiling;\u6308o\u01f5\u08b7\0\u08c3bleBracket;\u67e6n\u01d4\u08c8\0\u08d2eeVector;\u6961ector\u0100;B\u08db\u08dc\u61c3ar;\u6959loor;\u630aight\u0100AV\u08ef\u08f5rrow;\u6194ector;\u694e\u0100er\u0901\u0917e\u0180;AV\u0909\u090a\u0910\u62a3rrow;\u61a4ector;\u695aiangle\u0180;BE\u0924\u0925\u0929\u62b2ar;\u69cfqual;\u62b4p\u0180DTV\u0937\u0942\u094cownVector;\u6951eeVector;\u6960ector\u0100;B\u0956\u0957\u61bfar;\u6958ector\u0100;B\u0965\u0966\u61bcar;\u6952ight\xe1\u039cs\u0300EFGLST\u097e\u098b\u0995\u099d\u09a2\u09adqualGreater;\u62daullEqual;\u6266reater;\u6276ess;\u6aa1lantEqual;\u6a7dilde;\u6272r;\uc000\ud835\udd0f\u0100;e\u09bd\u09be\u62d8ftarrow;\u61daidot;\u413f\u0180npw\u09d4\u0a16\u0a1bg\u0200LRlr\u09de\u09f7\u0a02\u0a10eft\u0100AR\u09e6\u09ecrrow;\u67f5ightArrow;\u67f7ightArrow;\u67f6eft\u0100ar\u03b3\u0a0aight\xe1\u03bfight\xe1\u03caf;\uc000\ud835\udd43er\u0100LR\u0a22\u0a2ceftArrow;\u6199ightArrow;\u6198\u0180cht\u0a3e\u0a40\u0a42\xf2\u084c;\u61b0rok;\u4141;\u626a\u0400acefiosu\u0a5a\u0a5d\u0a60\u0a77\u0a7c\u0a85\u0a8b\u0a8ep;\u6905y;\u441c\u0100dl\u0a65\u0a6fiumSpace;\u605flintrf;\u6133r;\uc000\ud835\udd10nusPlus;\u6213pf;\uc000\ud835\udd44c\xf2\u0a76;\u439c\u0480Jacefostu\u0aa3\u0aa7\u0aad\u0ac0\u0b14\u0b19\u0d91\u0d97\u0d9ecy;\u440acute;\u4143\u0180aey\u0ab4\u0ab9\u0aberon;\u4147dil;\u4145;\u441d\u0180gsw\u0ac7\u0af0\u0b0eative\u0180MTV\u0ad3\u0adf\u0ae8ediumSpace;\u600bhi\u0100cn\u0ae6\u0ad8\xeb\u0ad9eryThi\xee\u0ad9ted\u0100GL\u0af8\u0b06reaterGreate\xf2\u0673essLes\xf3\u0a48Line;\u400ar;\uc000\ud835\udd11\u0200Bnpt\u0b22\u0b28\u0b37\u0b3areak;\u6060BreakingSpace;\u40a0f;\u6115\u0680;CDEGHLNPRSTV\u0b55\u0b56\u0b6a\u0b7c\u0ba1\u0beb\u0c04\u0c5e\u0c84\u0ca6\u0cd8\u0d61\u0d85\u6aec\u0100ou\u0b5b\u0b64ngruent;\u6262pCap;\u626doubleVerticalBar;\u6226\u0180lqx\u0b83\u0b8a\u0b9bement;\u6209ual\u0100;T\u0b92\u0b93\u6260ilde;\uc000\u2242\u0338ists;\u6204reater\u0380;EFGLST\u0bb6\u0bb7\u0bbd\u0bc9\u0bd3\u0bd8\u0be5\u626fqual;\u6271ullEqual;\uc000\u2267\u0338reater;\uc000\u226b\u0338ess;\u6279lantEqual;\uc000\u2a7e\u0338ilde;\u6275ump\u0144\u0bf2\u0bfdownHump;\uc000\u224e\u0338qual;\uc000\u224f\u0338e\u0100fs\u0c0a\u0c27tTriangle\u0180;BE\u0c1a\u0c1b\u0c21\u62eaar;\uc000\u29cf\u0338qual;\u62ecs\u0300;EGLST\u0c35\u0c36\u0c3c\u0c44\u0c4b\u0c58\u626equal;\u6270reater;\u6278ess;\uc000\u226a\u0338lantEqual;\uc000\u2a7d\u0338ilde;\u6274ested\u0100GL\u0c68\u0c79reaterGreater;\uc000\u2aa2\u0338essLess;\uc000\u2aa1\u0338recedes\u0180;ES\u0c92\u0c93\u0c9b\u6280qual;\uc000\u2aaf\u0338lantEqual;\u62e0\u0100ei\u0cab\u0cb9verseElement;\u620cghtTriangle\u0180;BE\u0ccb\u0ccc\u0cd2\u62ebar;\uc000\u29d0\u0338qual;\u62ed\u0100qu\u0cdd\u0d0cuareSu\u0100bp\u0ce8\u0cf9set\u0100;E\u0cf0\u0cf3\uc000\u228f\u0338qual;\u62e2erset\u0100;E\u0d03\u0d06\uc000\u2290\u0338qual;\u62e3\u0180bcp\u0d13\u0d24\u0d4eset\u0100;E\u0d1b\u0d1e\uc000\u2282\u20d2qual;\u6288ceeds\u0200;EST\u0d32\u0d33\u0d3b\u0d46\u6281qual;\uc000\u2ab0\u0338lantEqual;\u62e1ilde;\uc000\u227f\u0338erset\u0100;E\u0d58\u0d5b\uc000\u2283\u20d2qual;\u6289ilde\u0200;EFT\u0d6e\u0d6f\u0d75\u0d7f\u6241qual;\u6244ullEqual;\u6247ilde;\u6249erticalBar;\u6224cr;\uc000\ud835\udca9ilde\u803b\xd1\u40d1;\u439d\u0700Eacdfgmoprstuv\u0dbd\u0dc2\u0dc9\u0dd5\u0ddb\u0de0\u0de7\u0dfc\u0e02\u0e20\u0e22\u0e32\u0e3f\u0e44lig;\u4152cute\u803b\xd3\u40d3\u0100iy\u0dce\u0dd3rc\u803b\xd4\u40d4;\u441eblac;\u4150r;\uc000\ud835\udd12rave\u803b\xd2\u40d2\u0180aei\u0dee\u0df2\u0df6cr;\u414cga;\u43a9cron;\u439fpf;\uc000\ud835\udd46enCurly\u0100DQ\u0e0e\u0e1aoubleQuote;\u601cuote;\u6018;\u6a54\u0100cl\u0e27\u0e2cr;\uc000\ud835\udcaaash\u803b\xd8\u40d8i\u016c\u0e37\u0e3cde\u803b\xd5\u40d5es;\u6a37ml\u803b\xd6\u40d6er\u0100BP\u0e4b\u0e60\u0100ar\u0e50\u0e53r;\u603eac\u0100ek\u0e5a\u0e5c;\u63deet;\u63b4arenthesis;\u63dc\u0480acfhilors\u0e7f\u0e87\u0e8a\u0e8f\u0e92\u0e94\u0e9d\u0eb0\u0efcrtialD;\u6202y;\u441fr;\uc000\ud835\udd13i;\u43a6;\u43a0usMinus;\u40b1\u0100ip\u0ea2\u0eadncareplan\xe5\u069df;\u6119\u0200;eio\u0eb9\u0eba\u0ee0\u0ee4\u6abbcedes\u0200;EST\u0ec8\u0ec9\u0ecf\u0eda\u627aqual;\u6aaflantEqual;\u627cilde;\u627eme;\u6033\u0100dp\u0ee9\u0eeeuct;\u620fortion\u0100;a\u0225\u0ef9l;\u621d\u0100ci\u0f01\u0f06r;\uc000\ud835\udcab;\u43a8\u0200Ufos\u0f11\u0f16\u0f1b\u0f1fOT\u803b\"\u4022r;\uc000\ud835\udd14pf;\u611acr;\uc000\ud835\udcac\u0600BEacefhiorsu\u0f3e\u0f43\u0f47\u0f60\u0f73\u0fa7\u0faa\u0fad\u1096\u10a9\u10b4\u10bearr;\u6910G\u803b\xae\u40ae\u0180cnr\u0f4e\u0f53\u0f56ute;\u4154g;\u67ebr\u0100;t\u0f5c\u0f5d\u61a0l;\u6916\u0180aey\u0f67\u0f6c\u0f71ron;\u4158dil;\u4156;\u4420\u0100;v\u0f78\u0f79\u611cerse\u0100EU\u0f82\u0f99\u0100lq\u0f87\u0f8eement;\u620builibrium;\u61cbpEquilibrium;\u696fr\xbb\u0f79o;\u43a1ght\u0400ACDFTUVa\u0fc1\u0feb\u0ff3\u1022\u1028\u105b\u1087\u03d8\u0100nr\u0fc6\u0fd2gleBracket;\u67e9row\u0180;BL\u0fdc\u0fdd\u0fe1\u6192ar;\u61e5eftArrow;\u61c4eiling;\u6309o\u01f5\u0ff9\0\u1005bleBracket;\u67e7n\u01d4\u100a\0\u1014eeVector;\u695dector\u0100;B\u101d\u101e\u61c2ar;\u6955loor;\u630b\u0100er\u102d\u1043e\u0180;AV\u1035\u1036\u103c\u62a2rrow;\u61a6ector;\u695biangle\u0180;BE\u1050\u1051\u1055\u62b3ar;\u69d0qual;\u62b5p\u0180DTV\u1063\u106e\u1078ownVector;\u694feeVector;\u695cector\u0100;B\u1082\u1083\u61bear;\u6954ector\u0100;B\u1091\u1092\u61c0ar;\u6953\u0100pu\u109b\u109ef;\u611dndImplies;\u6970ightarrow;\u61db\u0100ch\u10b9\u10bcr;\u611b;\u61b1leDelayed;\u69f4\u0680HOacfhimoqstu\u10e4\u10f1\u10f7\u10fd\u1119\u111e\u1151\u1156\u1161\u1167\u11b5\u11bb\u11bf\u0100Cc\u10e9\u10eeHcy;\u4429y;\u4428FTcy;\u442ccute;\u415a\u0280;aeiy\u1108\u1109\u110e\u1113\u1117\u6abcron;\u4160dil;\u415erc;\u415c;\u4421r;\uc000\ud835\udd16ort\u0200DLRU\u112a\u1134\u113e\u1149ownArrow\xbb\u041eeftArrow\xbb\u089aightArrow\xbb\u0fddpArrow;\u6191gma;\u43a3allCircle;\u6218pf;\uc000\ud835\udd4a\u0272\u116d\0\0\u1170t;\u621aare\u0200;ISU\u117b\u117c\u1189\u11af\u65a1ntersection;\u6293u\u0100bp\u118f\u119eset\u0100;E\u1197\u1198\u628fqual;\u6291erset\u0100;E\u11a8\u11a9\u6290qual;\u6292nion;\u6294cr;\uc000\ud835\udcaear;\u62c6\u0200bcmp\u11c8\u11db\u1209\u120b\u0100;s\u11cd\u11ce\u62d0et\u0100;E\u11cd\u11d5qual;\u6286\u0100ch\u11e0\u1205eeds\u0200;EST\u11ed\u11ee\u11f4\u11ff\u627bqual;\u6ab0lantEqual;\u627dilde;\u627fTh\xe1\u0f8c;\u6211\u0180;es\u1212\u1213\u1223\u62d1rset\u0100;E\u121c\u121d\u6283qual;\u6287et\xbb\u1213\u0580HRSacfhiors\u123e\u1244\u1249\u1255\u125e\u1271\u1276\u129f\u12c2\u12c8\u12d1ORN\u803b\xde\u40deADE;\u6122\u0100Hc\u124e\u1252cy;\u440by;\u4426\u0100bu\u125a\u125c;\u4009;\u43a4\u0180aey\u1265\u126a\u126fron;\u4164dil;\u4162;\u4422r;\uc000\ud835\udd17\u0100ei\u127b\u1289\u01f2\u1280\0\u1287efore;\u6234a;\u4398\u0100cn\u128e\u1298kSpace;\uc000\u205f\u200aSpace;\u6009lde\u0200;EFT\u12ab\u12ac\u12b2\u12bc\u623cqual;\u6243ullEqual;\u6245ilde;\u6248pf;\uc000\ud835\udd4bipleDot;\u60db\u0100ct\u12d6\u12dbr;\uc000\ud835\udcafrok;\u4166\u0ae1\u12f7\u130e\u131a\u1326\0\u132c\u1331\0\0\0\0\0\u1338\u133d\u1377\u1385\0\u13ff\u1404\u140a\u1410\u0100cr\u12fb\u1301ute\u803b\xda\u40dar\u0100;o\u1307\u1308\u619fcir;\u6949r\u01e3\u1313\0\u1316y;\u440eve;\u416c\u0100iy\u131e\u1323rc\u803b\xdb\u40db;\u4423blac;\u4170r;\uc000\ud835\udd18rave\u803b\xd9\u40d9acr;\u416a\u0100di\u1341\u1369er\u0100BP\u1348\u135d\u0100ar\u134d\u1350r;\u405fac\u0100ek\u1357\u1359;\u63dfet;\u63b5arenthesis;\u63ddon\u0100;P\u1370\u1371\u62c3lus;\u628e\u0100gp\u137b\u137fon;\u4172f;\uc000\ud835\udd4c\u0400ADETadps\u1395\u13ae\u13b8\u13c4\u03e8\u13d2\u13d7\u13f3rrow\u0180;BD\u1150\u13a0\u13a4ar;\u6912ownArrow;\u61c5ownArrow;\u6195quilibrium;\u696eee\u0100;A\u13cb\u13cc\u62a5rrow;\u61a5own\xe1\u03f3er\u0100LR\u13de\u13e8eftArrow;\u6196ightArrow;\u6197i\u0100;l\u13f9\u13fa\u43d2on;\u43a5ing;\u416ecr;\uc000\ud835\udcb0ilde;\u4168ml\u803b\xdc\u40dc\u0480Dbcdefosv\u1427\u142c\u1430\u1433\u143e\u1485\u148a\u1490\u1496ash;\u62abar;\u6aeby;\u4412ash\u0100;l\u143b\u143c\u62a9;\u6ae6\u0100er\u1443\u1445;\u62c1\u0180bty\u144c\u1450\u147aar;\u6016\u0100;i\u144f\u1455cal\u0200BLST\u1461\u1465\u146a\u1474ar;\u6223ine;\u407ceparator;\u6758ilde;\u6240ThinSpace;\u600ar;\uc000\ud835\udd19pf;\uc000\ud835\udd4dcr;\uc000\ud835\udcb1dash;\u62aa\u0280cefos\u14a7\u14ac\u14b1\u14b6\u14bcirc;\u4174dge;\u62c0r;\uc000\ud835\udd1apf;\uc000\ud835\udd4ecr;\uc000\ud835\udcb2\u0200fios\u14cb\u14d0\u14d2\u14d8r;\uc000\ud835\udd1b;\u439epf;\uc000\ud835\udd4fcr;\uc000\ud835\udcb3\u0480AIUacfosu\u14f1\u14f5\u14f9\u14fd\u1504\u150f\u1514\u151a\u1520cy;\u442fcy;\u4407cy;\u442ecute\u803b\xdd\u40dd\u0100iy\u1509\u150drc;\u4176;\u442br;\uc000\ud835\udd1cpf;\uc000\ud835\udd50cr;\uc000\ud835\udcb4ml;\u4178\u0400Hacdefos\u1535\u1539\u153f\u154b\u154f\u155d\u1560\u1564cy;\u4416cute;\u4179\u0100ay\u1544\u1549ron;\u417d;\u4417ot;\u417b\u01f2\u1554\0\u155boWidt\xe8\u0ad9a;\u4396r;\u6128pf;\u6124cr;\uc000\ud835\udcb5\u0be1\u1583\u158a\u1590\0\u15b0\u15b6\u15bf\0\0\0\0\u15c6\u15db\u15eb\u165f\u166d\0\u1695\u169b\u16b2\u16b9\0\u16becute\u803b\xe1\u40e1reve;\u4103\u0300;Ediuy\u159c\u159d\u15a1\u15a3\u15a8\u15ad\u623e;\uc000\u223e\u0333;\u623frc\u803b\xe2\u40e2te\u80bb\xb4\u0306;\u4430lig\u803b\xe6\u40e6\u0100;r\xb2\u15ba;\uc000\ud835\udd1erave\u803b\xe0\u40e0\u0100ep\u15ca\u15d6\u0100fp\u15cf\u15d4sym;\u6135\xe8\u15d3ha;\u43b1\u0100ap\u15dfc\u0100cl\u15e4\u15e7r;\u4101g;\u6a3f\u0264\u15f0\0\0\u160a\u0280;adsv\u15fa\u15fb\u15ff\u1601\u1607\u6227nd;\u6a55;\u6a5clope;\u6a58;\u6a5a\u0380;elmrsz\u1618\u1619\u161b\u161e\u163f\u164f\u1659\u6220;\u69a4e\xbb\u1619sd\u0100;a\u1625\u1626\u6221\u0461\u1630\u1632\u1634\u1636\u1638\u163a\u163c\u163e;\u69a8;\u69a9;\u69aa;\u69ab;\u69ac;\u69ad;\u69ae;\u69aft\u0100;v\u1645\u1646\u621fb\u0100;d\u164c\u164d\u62be;\u699d\u0100pt\u1654\u1657h;\u6222\xbb\xb9arr;\u637c\u0100gp\u1663\u1667on;\u4105f;\uc000\ud835\udd52\u0380;Eaeiop\u12c1\u167b\u167d\u1682\u1684\u1687\u168a;\u6a70cir;\u6a6f;\u624ad;\u624bs;\u4027rox\u0100;e\u12c1\u1692\xf1\u1683ing\u803b\xe5\u40e5\u0180cty\u16a1\u16a6\u16a8r;\uc000\ud835\udcb6;\u402amp\u0100;e\u12c1\u16af\xf1\u0288ilde\u803b\xe3\u40e3ml\u803b\xe4\u40e4\u0100ci\u16c2\u16c8onin\xf4\u0272nt;\u6a11\u0800Nabcdefiklnoprsu\u16ed\u16f1\u1730\u173c\u1743\u1748\u1778\u177d\u17e0\u17e6\u1839\u1850\u170d\u193d\u1948\u1970ot;\u6aed\u0100cr\u16f6\u171ek\u0200ceps\u1700\u1705\u170d\u1713ong;\u624cpsilon;\u43f6rime;\u6035im\u0100;e\u171a\u171b\u623dq;\u62cd\u0176\u1722\u1726ee;\u62bded\u0100;g\u172c\u172d\u6305e\xbb\u172drk\u0100;t\u135c\u1737brk;\u63b6\u0100oy\u1701\u1741;\u4431quo;\u601e\u0280cmprt\u1753\u175b\u1761\u1764\u1768aus\u0100;e\u010a\u0109ptyv;\u69b0s\xe9\u170cno\xf5\u0113\u0180ahw\u176f\u1771\u1773;\u43b2;\u6136een;\u626cr;\uc000\ud835\udd1fg\u0380costuvw\u178d\u179d\u17b3\u17c1\u17d5\u17db\u17de\u0180aiu\u1794\u1796\u179a\xf0\u0760rc;\u65efp\xbb\u1371\u0180dpt\u17a4\u17a8\u17adot;\u6a00lus;\u6a01imes;\u6a02\u0271\u17b9\0\0\u17becup;\u6a06ar;\u6605riangle\u0100du\u17cd\u17d2own;\u65bdp;\u65b3plus;\u6a04e\xe5\u1444\xe5\u14adarow;\u690d\u0180ako\u17ed\u1826\u1835\u0100cn\u17f2\u1823k\u0180lst\u17fa\u05ab\u1802ozenge;\u69ebriangle\u0200;dlr\u1812\u1813\u1818\u181d\u65b4own;\u65beeft;\u65c2ight;\u65b8k;\u6423\u01b1\u182b\0\u1833\u01b2\u182f\0\u1831;\u6592;\u65914;\u6593ck;\u6588\u0100eo\u183e\u184d\u0100;q\u1843\u1846\uc000=\u20e5uiv;\uc000\u2261\u20e5t;\u6310\u0200ptwx\u1859\u185e\u1867\u186cf;\uc000\ud835\udd53\u0100;t\u13cb\u1863om\xbb\u13cctie;\u62c8\u0600DHUVbdhmptuv\u1885\u1896\u18aa\u18bb\u18d7\u18db\u18ec\u18ff\u1905\u190a\u1910\u1921\u0200LRlr\u188e\u1890\u1892\u1894;\u6557;\u6554;\u6556;\u6553\u0280;DUdu\u18a1\u18a2\u18a4\u18a6\u18a8\u6550;\u6566;\u6569;\u6564;\u6567\u0200LRlr\u18b3\u18b5\u18b7\u18b9;\u655d;\u655a;\u655c;\u6559\u0380;HLRhlr\u18ca\u18cb\u18cd\u18cf\u18d1\u18d3\u18d5\u6551;\u656c;\u6563;\u6560;\u656b;\u6562;\u655fox;\u69c9\u0200LRlr\u18e4\u18e6\u18e8\u18ea;\u6555;\u6552;\u6510;\u650c\u0280;DUdu\u06bd\u18f7\u18f9\u18fb\u18fd;\u6565;\u6568;\u652c;\u6534inus;\u629flus;\u629eimes;\u62a0\u0200LRlr\u1919\u191b\u191d\u191f;\u655b;\u6558;\u6518;\u6514\u0380;HLRhlr\u1930\u1931\u1933\u1935\u1937\u1939\u193b\u6502;\u656a;\u6561;\u655e;\u653c;\u6524;\u651c\u0100ev\u0123\u1942bar\u803b\xa6\u40a6\u0200ceio\u1951\u1956\u195a\u1960r;\uc000\ud835\udcb7mi;\u604fm\u0100;e\u171a\u171cl\u0180;bh\u1968\u1969\u196b\u405c;\u69c5sub;\u67c8\u016c\u1974\u197el\u0100;e\u1979\u197a\u6022t\xbb\u197ap\u0180;Ee\u012f\u1985\u1987;\u6aae\u0100;q\u06dc\u06db\u0ce1\u19a7\0\u19e8\u1a11\u1a15\u1a32\0\u1a37\u1a50\0\0\u1ab4\0\0\u1ac1\0\0\u1b21\u1b2e\u1b4d\u1b52\0\u1bfd\0\u1c0c\u0180cpr\u19ad\u19b2\u19ddute;\u4107\u0300;abcds\u19bf\u19c0\u19c4\u19ca\u19d5\u19d9\u6229nd;\u6a44rcup;\u6a49\u0100au\u19cf\u19d2p;\u6a4bp;\u6a47ot;\u6a40;\uc000\u2229\ufe00\u0100eo\u19e2\u19e5t;\u6041\xee\u0693\u0200aeiu\u19f0\u19fb\u1a01\u1a05\u01f0\u19f5\0\u19f8s;\u6a4don;\u410ddil\u803b\xe7\u40e7rc;\u4109ps\u0100;s\u1a0c\u1a0d\u6a4cm;\u6a50ot;\u410b\u0180dmn\u1a1b\u1a20\u1a26il\u80bb\xb8\u01adptyv;\u69b2t\u8100\xa2;e\u1a2d\u1a2e\u40a2r\xe4\u01b2r;\uc000\ud835\udd20\u0180cei\u1a3d\u1a40\u1a4dy;\u4447ck\u0100;m\u1a47\u1a48\u6713ark\xbb\u1a48;\u43c7r\u0380;Ecefms\u1a5f\u1a60\u1a62\u1a6b\u1aa4\u1aaa\u1aae\u65cb;\u69c3\u0180;el\u1a69\u1a6a\u1a6d\u42c6q;\u6257e\u0261\u1a74\0\0\u1a88rrow\u0100lr\u1a7c\u1a81eft;\u61baight;\u61bb\u0280RSacd\u1a92\u1a94\u1a96\u1a9a\u1a9f\xbb\u0f47;\u64c8st;\u629birc;\u629aash;\u629dnint;\u6a10id;\u6aefcir;\u69c2ubs\u0100;u\u1abb\u1abc\u6663it\xbb\u1abc\u02ec\u1ac7\u1ad4\u1afa\0\u1b0aon\u0100;e\u1acd\u1ace\u403a\u0100;q\xc7\xc6\u026d\u1ad9\0\0\u1ae2a\u0100;t\u1ade\u1adf\u402c;\u4040\u0180;fl\u1ae8\u1ae9\u1aeb\u6201\xee\u1160e\u0100mx\u1af1\u1af6ent\xbb\u1ae9e\xf3\u024d\u01e7\u1afe\0\u1b07\u0100;d\u12bb\u1b02ot;\u6a6dn\xf4\u0246\u0180fry\u1b10\u1b14\u1b17;\uc000\ud835\udd54o\xe4\u0254\u8100\xa9;s\u0155\u1b1dr;\u6117\u0100ao\u1b25\u1b29rr;\u61b5ss;\u6717\u0100cu\u1b32\u1b37r;\uc000\ud835\udcb8\u0100bp\u1b3c\u1b44\u0100;e\u1b41\u1b42\u6acf;\u6ad1\u0100;e\u1b49\u1b4a\u6ad0;\u6ad2dot;\u62ef\u0380delprvw\u1b60\u1b6c\u1b77\u1b82\u1bac\u1bd4\u1bf9arr\u0100lr\u1b68\u1b6a;\u6938;\u6935\u0270\u1b72\0\0\u1b75r;\u62dec;\u62dfarr\u0100;p\u1b7f\u1b80\u61b6;\u693d\u0300;bcdos\u1b8f\u1b90\u1b96\u1ba1\u1ba5\u1ba8\u622arcap;\u6a48\u0100au\u1b9b\u1b9ep;\u6a46p;\u6a4aot;\u628dr;\u6a45;\uc000\u222a\ufe00\u0200alrv\u1bb5\u1bbf\u1bde\u1be3rr\u0100;m\u1bbc\u1bbd\u61b7;\u693cy\u0180evw\u1bc7\u1bd4\u1bd8q\u0270\u1bce\0\0\u1bd2re\xe3\u1b73u\xe3\u1b75ee;\u62ceedge;\u62cfen\u803b\xa4\u40a4earrow\u0100lr\u1bee\u1bf3eft\xbb\u1b80ight\xbb\u1bbde\xe4\u1bdd\u0100ci\u1c01\u1c07onin\xf4\u01f7nt;\u6231lcty;\u632d\u0980AHabcdefhijlorstuwz\u1c38\u1c3b\u1c3f\u1c5d\u1c69\u1c75\u1c8a\u1c9e\u1cac\u1cb7\u1cfb\u1cff\u1d0d\u1d7b\u1d91\u1dab\u1dbb\u1dc6\u1dcdr\xf2\u0381ar;\u6965\u0200glrs\u1c48\u1c4d\u1c52\u1c54ger;\u6020eth;\u6138\xf2\u1133h\u0100;v\u1c5a\u1c5b\u6010\xbb\u090a\u016b\u1c61\u1c67arow;\u690fa\xe3\u0315\u0100ay\u1c6e\u1c73ron;\u410f;\u4434\u0180;ao\u0332\u1c7c\u1c84\u0100gr\u02bf\u1c81r;\u61catseq;\u6a77\u0180glm\u1c91\u1c94\u1c98\u803b\xb0\u40b0ta;\u43b4ptyv;\u69b1\u0100ir\u1ca3\u1ca8sht;\u697f;\uc000\ud835\udd21ar\u0100lr\u1cb3\u1cb5\xbb\u08dc\xbb\u101e\u0280aegsv\u1cc2\u0378\u1cd6\u1cdc\u1ce0m\u0180;os\u0326\u1cca\u1cd4nd\u0100;s\u0326\u1cd1uit;\u6666amma;\u43ddin;\u62f2\u0180;io\u1ce7\u1ce8\u1cf8\u40f7de\u8100\xf7;o\u1ce7\u1cf0ntimes;\u62c7n\xf8\u1cf7cy;\u4452c\u026f\u1d06\0\0\u1d0arn;\u631eop;\u630d\u0280lptuw\u1d18\u1d1d\u1d22\u1d49\u1d55lar;\u4024f;\uc000\ud835\udd55\u0280;emps\u030b\u1d2d\u1d37\u1d3d\u1d42q\u0100;d\u0352\u1d33ot;\u6251inus;\u6238lus;\u6214quare;\u62a1blebarwedg\xe5\xfan\u0180adh\u112e\u1d5d\u1d67ownarrow\xf3\u1c83arpoon\u0100lr\u1d72\u1d76ef\xf4\u1cb4igh\xf4\u1cb6\u0162\u1d7f\u1d85karo\xf7\u0f42\u026f\u1d8a\0\0\u1d8ern;\u631fop;\u630c\u0180cot\u1d98\u1da3\u1da6\u0100ry\u1d9d\u1da1;\uc000\ud835\udcb9;\u4455l;\u69f6rok;\u4111\u0100dr\u1db0\u1db4ot;\u62f1i\u0100;f\u1dba\u1816\u65bf\u0100ah\u1dc0\u1dc3r\xf2\u0429a\xf2\u0fa6angle;\u69a6\u0100ci\u1dd2\u1dd5y;\u445fgrarr;\u67ff\u0900Dacdefglmnopqrstux\u1e01\u1e09\u1e19\u1e38\u0578\u1e3c\u1e49\u1e61\u1e7e\u1ea5\u1eaf\u1ebd\u1ee1\u1f2a\u1f37\u1f44\u1f4e\u1f5a\u0100Do\u1e06\u1d34o\xf4\u1c89\u0100cs\u1e0e\u1e14ute\u803b\xe9\u40e9ter;\u6a6e\u0200aioy\u1e22\u1e27\u1e31\u1e36ron;\u411br\u0100;c\u1e2d\u1e2e\u6256\u803b\xea\u40ealon;\u6255;\u444dot;\u4117\u0100Dr\u1e41\u1e45ot;\u6252;\uc000\ud835\udd22\u0180;rs\u1e50\u1e51\u1e57\u6a9aave\u803b\xe8\u40e8\u0100;d\u1e5c\u1e5d\u6a96ot;\u6a98\u0200;ils\u1e6a\u1e6b\u1e72\u1e74\u6a99nters;\u63e7;\u6113\u0100;d\u1e79\u1e7a\u6a95ot;\u6a97\u0180aps\u1e85\u1e89\u1e97cr;\u4113ty\u0180;sv\u1e92\u1e93\u1e95\u6205et\xbb\u1e93p\u01001;\u1e9d\u1ea4\u0133\u1ea1\u1ea3;\u6004;\u6005\u6003\u0100gs\u1eaa\u1eac;\u414bp;\u6002\u0100gp\u1eb4\u1eb8on;\u4119f;\uc000\ud835\udd56\u0180als\u1ec4\u1ece\u1ed2r\u0100;s\u1eca\u1ecb\u62d5l;\u69e3us;\u6a71i\u0180;lv\u1eda\u1edb\u1edf\u43b5on\xbb\u1edb;\u43f5\u0200csuv\u1eea\u1ef3\u1f0b\u1f23\u0100io\u1eef\u1e31rc\xbb\u1e2e\u0269\u1ef9\0\0\u1efb\xed\u0548ant\u0100gl\u1f02\u1f06tr\xbb\u1e5dess\xbb\u1e7a\u0180aei\u1f12\u1f16\u1f1als;\u403dst;\u625fv\u0100;D\u0235\u1f20D;\u6a78parsl;\u69e5\u0100Da\u1f2f\u1f33ot;\u6253rr;\u6971\u0180cdi\u1f3e\u1f41\u1ef8r;\u612fo\xf4\u0352\u0100ah\u1f49\u1f4b;\u43b7\u803b\xf0\u40f0\u0100mr\u1f53\u1f57l\u803b\xeb\u40ebo;\u60ac\u0180cip\u1f61\u1f64\u1f67l;\u4021s\xf4\u056e\u0100eo\u1f6c\u1f74ctatio\xee\u0559nential\xe5\u0579\u09e1\u1f92\0\u1f9e\0\u1fa1\u1fa7\0\0\u1fc6\u1fcc\0\u1fd3\0\u1fe6\u1fea\u2000\0\u2008\u205allingdotse\xf1\u1e44y;\u4444male;\u6640\u0180ilr\u1fad\u1fb3\u1fc1lig;\u8000\ufb03\u0269\u1fb9\0\0\u1fbdg;\u8000\ufb00ig;\u8000\ufb04;\uc000\ud835\udd23lig;\u8000\ufb01lig;\uc000fj\u0180alt\u1fd9\u1fdc\u1fe1t;\u666dig;\u8000\ufb02ns;\u65b1of;\u4192\u01f0\u1fee\0\u1ff3f;\uc000\ud835\udd57\u0100ak\u05bf\u1ff7\u0100;v\u1ffc\u1ffd\u62d4;\u6ad9artint;\u6a0d\u0100ao\u200c\u2055\u0100cs\u2011\u2052\u03b1\u201a\u2030\u2038\u2045\u2048\0\u2050\u03b2\u2022\u2025\u2027\u202a\u202c\0\u202e\u803b\xbd\u40bd;\u6153\u803b\xbc\u40bc;\u6155;\u6159;\u615b\u01b3\u2034\0\u2036;\u6154;\u6156\u02b4\u203e\u2041\0\0\u2043\u803b\xbe\u40be;\u6157;\u615c5;\u6158\u01b6\u204c\0\u204e;\u615a;\u615d8;\u615el;\u6044wn;\u6322cr;\uc000\ud835\udcbb\u0880Eabcdefgijlnorstv\u2082\u2089\u209f\u20a5\u20b0\u20b4\u20f0\u20f5\u20fa\u20ff\u2103\u2112\u2138\u0317\u213e\u2152\u219e\u0100;l\u064d\u2087;\u6a8c\u0180cmp\u2090\u2095\u209dute;\u41f5ma\u0100;d\u209c\u1cda\u43b3;\u6a86reve;\u411f\u0100iy\u20aa\u20aerc;\u411d;\u4433ot;\u4121\u0200;lqs\u063e\u0642\u20bd\u20c9\u0180;qs\u063e\u064c\u20c4lan\xf4\u0665\u0200;cdl\u0665\u20d2\u20d5\u20e5c;\u6aa9ot\u0100;o\u20dc\u20dd\u6a80\u0100;l\u20e2\u20e3\u6a82;\u6a84\u0100;e\u20ea\u20ed\uc000\u22db\ufe00s;\u6a94r;\uc000\ud835\udd24\u0100;g\u0673\u061bmel;\u6137cy;\u4453\u0200;Eaj\u065a\u210c\u210e\u2110;\u6a92;\u6aa5;\u6aa4\u0200Eaes\u211b\u211d\u2129\u2134;\u6269p\u0100;p\u2123\u2124\u6a8arox\xbb\u2124\u0100;q\u212e\u212f\u6a88\u0100;q\u212e\u211bim;\u62e7pf;\uc000\ud835\udd58\u0100ci\u2143\u2146r;\u610am\u0180;el\u066b\u214e\u2150;\u6a8e;\u6a90\u8300>;cdlqr\u05ee\u2160\u216a\u216e\u2173\u2179\u0100ci\u2165\u2167;\u6aa7r;\u6a7aot;\u62d7Par;\u6995uest;\u6a7c\u0280adels\u2184\u216a\u2190\u0656\u219b\u01f0\u2189\0\u218epro\xf8\u209er;\u6978q\u0100lq\u063f\u2196les\xf3\u2088i\xed\u066b\u0100en\u21a3\u21adrtneqq;\uc000\u2269\ufe00\xc5\u21aa\u0500Aabcefkosy\u21c4\u21c7\u21f1\u21f5\u21fa\u2218\u221d\u222f\u2268\u227dr\xf2\u03a0\u0200ilmr\u21d0\u21d4\u21d7\u21dbrs\xf0\u1484f\xbb\u2024il\xf4\u06a9\u0100dr\u21e0\u21e4cy;\u444a\u0180;cw\u08f4\u21eb\u21efir;\u6948;\u61adar;\u610firc;\u4125\u0180alr\u2201\u220e\u2213rts\u0100;u\u2209\u220a\u6665it\xbb\u220alip;\u6026con;\u62b9r;\uc000\ud835\udd25s\u0100ew\u2223\u2229arow;\u6925arow;\u6926\u0280amopr\u223a\u223e\u2243\u225e\u2263rr;\u61fftht;\u623bk\u0100lr\u2249\u2253eftarrow;\u61a9ightarrow;\u61aaf;\uc000\ud835\udd59bar;\u6015\u0180clt\u226f\u2274\u2278r;\uc000\ud835\udcbdas\xe8\u21f4rok;\u4127\u0100bp\u2282\u2287ull;\u6043hen\xbb\u1c5b\u0ae1\u22a3\0\u22aa\0\u22b8\u22c5\u22ce\0\u22d5\u22f3\0\0\u22f8\u2322\u2367\u2362\u237f\0\u2386\u23aa\u23b4cute\u803b\xed\u40ed\u0180;iy\u0771\u22b0\u22b5rc\u803b\xee\u40ee;\u4438\u0100cx\u22bc\u22bfy;\u4435cl\u803b\xa1\u40a1\u0100fr\u039f\u22c9;\uc000\ud835\udd26rave\u803b\xec\u40ec\u0200;ino\u073e\u22dd\u22e9\u22ee\u0100in\u22e2\u22e6nt;\u6a0ct;\u622dfin;\u69dcta;\u6129lig;\u4133\u0180aop\u22fe\u231a\u231d\u0180cgt\u2305\u2308\u2317r;\u412b\u0180elp\u071f\u230f\u2313in\xe5\u078ear\xf4\u0720h;\u4131f;\u62b7ed;\u41b5\u0280;cfot\u04f4\u232c\u2331\u233d\u2341are;\u6105in\u0100;t\u2338\u2339\u621eie;\u69dddo\xf4\u2319\u0280;celp\u0757\u234c\u2350\u235b\u2361al;\u62ba\u0100gr\u2355\u2359er\xf3\u1563\xe3\u234darhk;\u6a17rod;\u6a3c\u0200cgpt\u236f\u2372\u2376\u237by;\u4451on;\u412ff;\uc000\ud835\udd5aa;\u43b9uest\u803b\xbf\u40bf\u0100ci\u238a\u238fr;\uc000\ud835\udcben\u0280;Edsv\u04f4\u239b\u239d\u23a1\u04f3;\u62f9ot;\u62f5\u0100;v\u23a6\u23a7\u62f4;\u62f3\u0100;i\u0777\u23aelde;\u4129\u01eb\u23b8\0\u23bccy;\u4456l\u803b\xef\u40ef\u0300cfmosu\u23cc\u23d7\u23dc\u23e1\u23e7\u23f5\u0100iy\u23d1\u23d5rc;\u4135;\u4439r;\uc000\ud835\udd27ath;\u4237pf;\uc000\ud835\udd5b\u01e3\u23ec\0\u23f1r;\uc000\ud835\udcbfrcy;\u4458kcy;\u4454\u0400acfghjos\u240b\u2416\u2422\u2427\u242d\u2431\u2435\u243bppa\u0100;v\u2413\u2414\u43ba;\u43f0\u0100ey\u241b\u2420dil;\u4137;\u443ar;\uc000\ud835\udd28reen;\u4138cy;\u4445cy;\u445cpf;\uc000\ud835\udd5ccr;\uc000\ud835\udcc0\u0b80ABEHabcdefghjlmnoprstuv\u2470\u2481\u2486\u248d\u2491\u250e\u253d\u255a\u2580\u264e\u265e\u2665\u2679\u267d\u269a\u26b2\u26d8\u275d\u2768\u278b\u27c0\u2801\u2812\u0180art\u2477\u247a\u247cr\xf2\u09c6\xf2\u0395ail;\u691barr;\u690e\u0100;g\u0994\u248b;\u6a8bar;\u6962\u0963\u24a5\0\u24aa\0\u24b1\0\0\0\0\0\u24b5\u24ba\0\u24c6\u24c8\u24cd\0\u24f9ute;\u413amptyv;\u69b4ra\xee\u084cbda;\u43bbg\u0180;dl\u088e\u24c1\u24c3;\u6991\xe5\u088e;\u6a85uo\u803b\xab\u40abr\u0400;bfhlpst\u0899\u24de\u24e6\u24e9\u24eb\u24ee\u24f1\u24f5\u0100;f\u089d\u24e3s;\u691fs;\u691d\xeb\u2252p;\u61abl;\u6939im;\u6973l;\u61a2\u0180;ae\u24ff\u2500\u2504\u6aabil;\u6919\u0100;s\u2509\u250a\u6aad;\uc000\u2aad\ufe00\u0180abr\u2515\u2519\u251drr;\u690crk;\u6772\u0100ak\u2522\u252cc\u0100ek\u2528\u252a;\u407b;\u405b\u0100es\u2531\u2533;\u698bl\u0100du\u2539\u253b;\u698f;\u698d\u0200aeuy\u2546\u254b\u2556\u2558ron;\u413e\u0100di\u2550\u2554il;\u413c\xec\u08b0\xe2\u2529;\u443b\u0200cqrs\u2563\u2566\u256d\u257da;\u6936uo\u0100;r\u0e19\u1746\u0100du\u2572\u2577har;\u6967shar;\u694bh;\u61b2\u0280;fgqs\u258b\u258c\u0989\u25f3\u25ff\u6264t\u0280ahlrt\u2598\u25a4\u25b7\u25c2\u25e8rrow\u0100;t\u0899\u25a1a\xe9\u24f6arpoon\u0100du\u25af\u25b4own\xbb\u045ap\xbb\u0966eftarrows;\u61c7ight\u0180ahs\u25cd\u25d6\u25derrow\u0100;s\u08f4\u08a7arpoon\xf3\u0f98quigarro\xf7\u21f0hreetimes;\u62cb\u0180;qs\u258b\u0993\u25falan\xf4\u09ac\u0280;cdgs\u09ac\u260a\u260d\u261d\u2628c;\u6aa8ot\u0100;o\u2614\u2615\u6a7f\u0100;r\u261a\u261b\u6a81;\u6a83\u0100;e\u2622\u2625\uc000\u22da\ufe00s;\u6a93\u0280adegs\u2633\u2639\u263d\u2649\u264bppro\xf8\u24c6ot;\u62d6q\u0100gq\u2643\u2645\xf4\u0989gt\xf2\u248c\xf4\u099bi\xed\u09b2\u0180ilr\u2655\u08e1\u265asht;\u697c;\uc000\ud835\udd29\u0100;E\u099c\u2663;\u6a91\u0161\u2669\u2676r\u0100du\u25b2\u266e\u0100;l\u0965\u2673;\u696alk;\u6584cy;\u4459\u0280;acht\u0a48\u2688\u268b\u2691\u2696r\xf2\u25c1orne\xf2\u1d08ard;\u696bri;\u65fa\u0100io\u269f\u26a4dot;\u4140ust\u0100;a\u26ac\u26ad\u63b0che\xbb\u26ad\u0200Eaes\u26bb\u26bd\u26c9\u26d4;\u6268p\u0100;p\u26c3\u26c4\u6a89rox\xbb\u26c4\u0100;q\u26ce\u26cf\u6a87\u0100;q\u26ce\u26bbim;\u62e6\u0400abnoptwz\u26e9\u26f4\u26f7\u271a\u272f\u2741\u2747\u2750\u0100nr\u26ee\u26f1g;\u67ecr;\u61fdr\xeb\u08c1g\u0180lmr\u26ff\u270d\u2714eft\u0100ar\u09e6\u2707ight\xe1\u09f2apsto;\u67fcight\xe1\u09fdparrow\u0100lr\u2725\u2729ef\xf4\u24edight;\u61ac\u0180afl\u2736\u2739\u273dr;\u6985;\uc000\ud835\udd5dus;\u6a2dimes;\u6a34\u0161\u274b\u274fst;\u6217\xe1\u134e\u0180;ef\u2757\u2758\u1800\u65cange\xbb\u2758ar\u0100;l\u2764\u2765\u4028t;\u6993\u0280achmt\u2773\u2776\u277c\u2785\u2787r\xf2\u08a8orne\xf2\u1d8car\u0100;d\u0f98\u2783;\u696d;\u600eri;\u62bf\u0300achiqt\u2798\u279d\u0a40\u27a2\u27ae\u27bbquo;\u6039r;\uc000\ud835\udcc1m\u0180;eg\u09b2\u27aa\u27ac;\u6a8d;\u6a8f\u0100bu\u252a\u27b3o\u0100;r\u0e1f\u27b9;\u601arok;\u4142\u8400<;cdhilqr\u082b\u27d2\u2639\u27dc\u27e0\u27e5\u27ea\u27f0\u0100ci\u27d7\u27d9;\u6aa6r;\u6a79re\xe5\u25f2mes;\u62c9arr;\u6976uest;\u6a7b\u0100Pi\u27f5\u27f9ar;\u6996\u0180;ef\u2800\u092d\u181b\u65c3r\u0100du\u2807\u280dshar;\u694ahar;\u6966\u0100en\u2817\u2821rtneqq;\uc000\u2268\ufe00\xc5\u281e\u0700Dacdefhilnopsu\u2840\u2845\u2882\u288e\u2893\u28a0\u28a5\u28a8\u28da\u28e2\u28e4\u0a83\u28f3\u2902Dot;\u623a\u0200clpr\u284e\u2852\u2863\u287dr\u803b\xaf\u40af\u0100et\u2857\u2859;\u6642\u0100;e\u285e\u285f\u6720se\xbb\u285f\u0100;s\u103b\u2868to\u0200;dlu\u103b\u2873\u2877\u287bow\xee\u048cef\xf4\u090f\xf0\u13d1ker;\u65ae\u0100oy\u2887\u288cmma;\u6a29;\u443cash;\u6014asuredangle\xbb\u1626r;\uc000\ud835\udd2ao;\u6127\u0180cdn\u28af\u28b4\u28c9ro\u803b\xb5\u40b5\u0200;acd\u1464\u28bd\u28c0\u28c4s\xf4\u16a7ir;\u6af0ot\u80bb\xb7\u01b5us\u0180;bd\u28d2\u1903\u28d3\u6212\u0100;u\u1d3c\u28d8;\u6a2a\u0163\u28de\u28e1p;\u6adb\xf2\u2212\xf0\u0a81\u0100dp\u28e9\u28eeels;\u62a7f;\uc000\ud835\udd5e\u0100ct\u28f8\u28fdr;\uc000\ud835\udcc2pos\xbb\u159d\u0180;lm\u2909\u290a\u290d\u43bctimap;\u62b8\u0c00GLRVabcdefghijlmoprstuvw\u2942\u2953\u297e\u2989\u2998\u29da\u29e9\u2a15\u2a1a\u2a58\u2a5d\u2a83\u2a95\u2aa4\u2aa8\u2b04\u2b07\u2b44\u2b7f\u2bae\u2c34\u2c67\u2c7c\u2ce9\u0100gt\u2947\u294b;\uc000\u22d9\u0338\u0100;v\u2950\u0bcf\uc000\u226b\u20d2\u0180elt\u295a\u2972\u2976ft\u0100ar\u2961\u2967rrow;\u61cdightarrow;\u61ce;\uc000\u22d8\u0338\u0100;v\u297b\u0c47\uc000\u226a\u20d2ightarrow;\u61cf\u0100Dd\u298e\u2993ash;\u62afash;\u62ae\u0280bcnpt\u29a3\u29a7\u29ac\u29b1\u29ccla\xbb\u02deute;\u4144g;\uc000\u2220\u20d2\u0280;Eiop\u0d84\u29bc\u29c0\u29c5\u29c8;\uc000\u2a70\u0338d;\uc000\u224b\u0338s;\u4149ro\xf8\u0d84ur\u0100;a\u29d3\u29d4\u666el\u0100;s\u29d3\u0b38\u01f3\u29df\0\u29e3p\u80bb\xa0\u0b37mp\u0100;e\u0bf9\u0c00\u0280aeouy\u29f4\u29fe\u2a03\u2a10\u2a13\u01f0\u29f9\0\u29fb;\u6a43on;\u4148dil;\u4146ng\u0100;d\u0d7e\u2a0aot;\uc000\u2a6d\u0338p;\u6a42;\u443dash;\u6013\u0380;Aadqsx\u0b92\u2a29\u2a2d\u2a3b\u2a41\u2a45\u2a50rr;\u61d7r\u0100hr\u2a33\u2a36k;\u6924\u0100;o\u13f2\u13f0ot;\uc000\u2250\u0338ui\xf6\u0b63\u0100ei\u2a4a\u2a4ear;\u6928\xed\u0b98ist\u0100;s\u0ba0\u0b9fr;\uc000\ud835\udd2b\u0200Eest\u0bc5\u2a66\u2a79\u2a7c\u0180;qs\u0bbc\u2a6d\u0be1\u0180;qs\u0bbc\u0bc5\u2a74lan\xf4\u0be2i\xed\u0bea\u0100;r\u0bb6\u2a81\xbb\u0bb7\u0180Aap\u2a8a\u2a8d\u2a91r\xf2\u2971rr;\u61aear;\u6af2\u0180;sv\u0f8d\u2a9c\u0f8c\u0100;d\u2aa1\u2aa2\u62fc;\u62facy;\u445a\u0380AEadest\u2ab7\u2aba\u2abe\u2ac2\u2ac5\u2af6\u2af9r\xf2\u2966;\uc000\u2266\u0338rr;\u619ar;\u6025\u0200;fqs\u0c3b\u2ace\u2ae3\u2aeft\u0100ar\u2ad4\u2ad9rro\xf7\u2ac1ightarro\xf7\u2a90\u0180;qs\u0c3b\u2aba\u2aealan\xf4\u0c55\u0100;s\u0c55\u2af4\xbb\u0c36i\xed\u0c5d\u0100;r\u0c35\u2afei\u0100;e\u0c1a\u0c25i\xe4\u0d90\u0100pt\u2b0c\u2b11f;\uc000\ud835\udd5f\u8180\xac;in\u2b19\u2b1a\u2b36\u40acn\u0200;Edv\u0b89\u2b24\u2b28\u2b2e;\uc000\u22f9\u0338ot;\uc000\u22f5\u0338\u01e1\u0b89\u2b33\u2b35;\u62f7;\u62f6i\u0100;v\u0cb8\u2b3c\u01e1\u0cb8\u2b41\u2b43;\u62fe;\u62fd\u0180aor\u2b4b\u2b63\u2b69r\u0200;ast\u0b7b\u2b55\u2b5a\u2b5flle\xec\u0b7bl;\uc000\u2afd\u20e5;\uc000\u2202\u0338lint;\u6a14\u0180;ce\u0c92\u2b70\u2b73u\xe5\u0ca5\u0100;c\u0c98\u2b78\u0100;e\u0c92\u2b7d\xf1\u0c98\u0200Aait\u2b88\u2b8b\u2b9d\u2ba7r\xf2\u2988rr\u0180;cw\u2b94\u2b95\u2b99\u619b;\uc000\u2933\u0338;\uc000\u219d\u0338ghtarrow\xbb\u2b95ri\u0100;e\u0ccb\u0cd6\u0380chimpqu\u2bbd\u2bcd\u2bd9\u2b04\u0b78\u2be4\u2bef\u0200;cer\u0d32\u2bc6\u0d37\u2bc9u\xe5\u0d45;\uc000\ud835\udcc3ort\u026d\u2b05\0\0\u2bd6ar\xe1\u2b56m\u0100;e\u0d6e\u2bdf\u0100;q\u0d74\u0d73su\u0100bp\u2beb\u2bed\xe5\u0cf8\xe5\u0d0b\u0180bcp\u2bf6\u2c11\u2c19\u0200;Ees\u2bff\u2c00\u0d22\u2c04\u6284;\uc000\u2ac5\u0338et\u0100;e\u0d1b\u2c0bq\u0100;q\u0d23\u2c00c\u0100;e\u0d32\u2c17\xf1\u0d38\u0200;Ees\u2c22\u2c23\u0d5f\u2c27\u6285;\uc000\u2ac6\u0338et\u0100;e\u0d58\u2c2eq\u0100;q\u0d60\u2c23\u0200gilr\u2c3d\u2c3f\u2c45\u2c47\xec\u0bd7lde\u803b\xf1\u40f1\xe7\u0c43iangle\u0100lr\u2c52\u2c5ceft\u0100;e\u0c1a\u2c5a\xf1\u0c26ight\u0100;e\u0ccb\u2c65\xf1\u0cd7\u0100;m\u2c6c\u2c6d\u43bd\u0180;es\u2c74\u2c75\u2c79\u4023ro;\u6116p;\u6007\u0480DHadgilrs\u2c8f\u2c94\u2c99\u2c9e\u2ca3\u2cb0\u2cb6\u2cd3\u2ce3ash;\u62adarr;\u6904p;\uc000\u224d\u20d2ash;\u62ac\u0100et\u2ca8\u2cac;\uc000\u2265\u20d2;\uc000>\u20d2nfin;\u69de\u0180Aet\u2cbd\u2cc1\u2cc5rr;\u6902;\uc000\u2264\u20d2\u0100;r\u2cca\u2ccd\uc000<\u20d2ie;\uc000\u22b4\u20d2\u0100At\u2cd8\u2cdcrr;\u6903rie;\uc000\u22b5\u20d2im;\uc000\u223c\u20d2\u0180Aan\u2cf0\u2cf4\u2d02rr;\u61d6r\u0100hr\u2cfa\u2cfdk;\u6923\u0100;o\u13e7\u13e5ear;\u6927\u1253\u1a95\0\0\0\0\0\0\0\0\0\0\0\0\0\u2d2d\0\u2d38\u2d48\u2d60\u2d65\u2d72\u2d84\u1b07\0\0\u2d8d\u2dab\0\u2dc8\u2dce\0\u2ddc\u2e19\u2e2b\u2e3e\u2e43\u0100cs\u2d31\u1a97ute\u803b\xf3\u40f3\u0100iy\u2d3c\u2d45r\u0100;c\u1a9e\u2d42\u803b\xf4\u40f4;\u443e\u0280abios\u1aa0\u2d52\u2d57\u01c8\u2d5alac;\u4151v;\u6a38old;\u69bclig;\u4153\u0100cr\u2d69\u2d6dir;\u69bf;\uc000\ud835\udd2c\u036f\u2d79\0\0\u2d7c\0\u2d82n;\u42dbave\u803b\xf2\u40f2;\u69c1\u0100bm\u2d88\u0df4ar;\u69b5\u0200acit\u2d95\u2d98\u2da5\u2da8r\xf2\u1a80\u0100ir\u2d9d\u2da0r;\u69beoss;\u69bbn\xe5\u0e52;\u69c0\u0180aei\u2db1\u2db5\u2db9cr;\u414dga;\u43c9\u0180cdn\u2dc0\u2dc5\u01cdron;\u43bf;\u69b6pf;\uc000\ud835\udd60\u0180ael\u2dd4\u2dd7\u01d2r;\u69b7rp;\u69b9\u0380;adiosv\u2dea\u2deb\u2dee\u2e08\u2e0d\u2e10\u2e16\u6228r\xf2\u1a86\u0200;efm\u2df7\u2df8\u2e02\u2e05\u6a5dr\u0100;o\u2dfe\u2dff\u6134f\xbb\u2dff\u803b\xaa\u40aa\u803b\xba\u40bagof;\u62b6r;\u6a56lope;\u6a57;\u6a5b\u0180clo\u2e1f\u2e21\u2e27\xf2\u2e01ash\u803b\xf8\u40f8l;\u6298i\u016c\u2e2f\u2e34de\u803b\xf5\u40f5es\u0100;a\u01db\u2e3as;\u6a36ml\u803b\xf6\u40f6bar;\u633d\u0ae1\u2e5e\0\u2e7d\0\u2e80\u2e9d\0\u2ea2\u2eb9\0\0\u2ecb\u0e9c\0\u2f13\0\0\u2f2b\u2fbc\0\u2fc8r\u0200;ast\u0403\u2e67\u2e72\u0e85\u8100\xb6;l\u2e6d\u2e6e\u40b6le\xec\u0403\u0269\u2e78\0\0\u2e7bm;\u6af3;\u6afdy;\u443fr\u0280cimpt\u2e8b\u2e8f\u2e93\u1865\u2e97nt;\u4025od;\u402eil;\u6030enk;\u6031r;\uc000\ud835\udd2d\u0180imo\u2ea8\u2eb0\u2eb4\u0100;v\u2ead\u2eae\u43c6;\u43d5ma\xf4\u0a76ne;\u660e\u0180;tv\u2ebf\u2ec0\u2ec8\u43c0chfork\xbb\u1ffd;\u43d6\u0100au\u2ecf\u2edfn\u0100ck\u2ed5\u2eddk\u0100;h\u21f4\u2edb;\u610e\xf6\u21f4s\u0480;abcdemst\u2ef3\u2ef4\u1908\u2ef9\u2efd\u2f04\u2f06\u2f0a\u2f0e\u402bcir;\u6a23ir;\u6a22\u0100ou\u1d40\u2f02;\u6a25;\u6a72n\u80bb\xb1\u0e9dim;\u6a26wo;\u6a27\u0180ipu\u2f19\u2f20\u2f25ntint;\u6a15f;\uc000\ud835\udd61nd\u803b\xa3\u40a3\u0500;Eaceinosu\u0ec8\u2f3f\u2f41\u2f44\u2f47\u2f81\u2f89\u2f92\u2f7e\u2fb6;\u6ab3p;\u6ab7u\xe5\u0ed9\u0100;c\u0ece\u2f4c\u0300;acens\u0ec8\u2f59\u2f5f\u2f66\u2f68\u2f7eppro\xf8\u2f43urlye\xf1\u0ed9\xf1\u0ece\u0180aes\u2f6f\u2f76\u2f7approx;\u6ab9qq;\u6ab5im;\u62e8i\xed\u0edfme\u0100;s\u2f88\u0eae\u6032\u0180Eas\u2f78\u2f90\u2f7a\xf0\u2f75\u0180dfp\u0eec\u2f99\u2faf\u0180als\u2fa0\u2fa5\u2faalar;\u632eine;\u6312urf;\u6313\u0100;t\u0efb\u2fb4\xef\u0efbrel;\u62b0\u0100ci\u2fc0\u2fc5r;\uc000\ud835\udcc5;\u43c8ncsp;\u6008\u0300fiopsu\u2fda\u22e2\u2fdf\u2fe5\u2feb\u2ff1r;\uc000\ud835\udd2epf;\uc000\ud835\udd62rime;\u6057cr;\uc000\ud835\udcc6\u0180aeo\u2ff8\u3009\u3013t\u0100ei\u2ffe\u3005rnion\xf3\u06b0nt;\u6a16st\u0100;e\u3010\u3011\u403f\xf1\u1f19\xf4\u0f14\u0a80ABHabcdefhilmnoprstux\u3040\u3051\u3055\u3059\u30e0\u310e\u312b\u3147\u3162\u3172\u318e\u3206\u3215\u3224\u3229\u3258\u326e\u3272\u3290\u32b0\u32b7\u0180art\u3047\u304a\u304cr\xf2\u10b3\xf2\u03ddail;\u691car\xf2\u1c65ar;\u6964\u0380cdenqrt\u3068\u3075\u3078\u307f\u308f\u3094\u30cc\u0100eu\u306d\u3071;\uc000\u223d\u0331te;\u4155i\xe3\u116emptyv;\u69b3g\u0200;del\u0fd1\u3089\u308b\u308d;\u6992;\u69a5\xe5\u0fd1uo\u803b\xbb\u40bbr\u0580;abcfhlpstw\u0fdc\u30ac\u30af\u30b7\u30b9\u30bc\u30be\u30c0\u30c3\u30c7\u30cap;\u6975\u0100;f\u0fe0\u30b4s;\u6920;\u6933s;\u691e\xeb\u225d\xf0\u272el;\u6945im;\u6974l;\u61a3;\u619d\u0100ai\u30d1\u30d5il;\u691ao\u0100;n\u30db\u30dc\u6236al\xf3\u0f1e\u0180abr\u30e7\u30ea\u30eer\xf2\u17e5rk;\u6773\u0100ak\u30f3\u30fdc\u0100ek\u30f9\u30fb;\u407d;\u405d\u0100es\u3102\u3104;\u698cl\u0100du\u310a\u310c;\u698e;\u6990\u0200aeuy\u3117\u311c\u3127\u3129ron;\u4159\u0100di\u3121\u3125il;\u4157\xec\u0ff2\xe2\u30fa;\u4440\u0200clqs\u3134\u3137\u313d\u3144a;\u6937dhar;\u6969uo\u0100;r\u020e\u020dh;\u61b3\u0180acg\u314e\u315f\u0f44l\u0200;ips\u0f78\u3158\u315b\u109cn\xe5\u10bbar\xf4\u0fa9t;\u65ad\u0180ilr\u3169\u1023\u316esht;\u697d;\uc000\ud835\udd2f\u0100ao\u3177\u3186r\u0100du\u317d\u317f\xbb\u047b\u0100;l\u1091\u3184;\u696c\u0100;v\u318b\u318c\u43c1;\u43f1\u0180gns\u3195\u31f9\u31fcht\u0300ahlrst\u31a4\u31b0\u31c2\u31d8\u31e4\u31eerrow\u0100;t\u0fdc\u31ada\xe9\u30c8arpoon\u0100du\u31bb\u31bfow\xee\u317ep\xbb\u1092eft\u0100ah\u31ca\u31d0rrow\xf3\u0feaarpoon\xf3\u0551ightarrows;\u61c9quigarro\xf7\u30cbhreetimes;\u62ccg;\u42daingdotse\xf1\u1f32\u0180ahm\u320d\u3210\u3213r\xf2\u0feaa\xf2\u0551;\u600foust\u0100;a\u321e\u321f\u63b1che\xbb\u321fmid;\u6aee\u0200abpt\u3232\u323d\u3240\u3252\u0100nr\u3237\u323ag;\u67edr;\u61fer\xeb\u1003\u0180afl\u3247\u324a\u324er;\u6986;\uc000\ud835\udd63us;\u6a2eimes;\u6a35\u0100ap\u325d\u3267r\u0100;g\u3263\u3264\u4029t;\u6994olint;\u6a12ar\xf2\u31e3\u0200achq\u327b\u3280\u10bc\u3285quo;\u603ar;\uc000\ud835\udcc7\u0100bu\u30fb\u328ao\u0100;r\u0214\u0213\u0180hir\u3297\u329b\u32a0re\xe5\u31f8mes;\u62cai\u0200;efl\u32aa\u1059\u1821\u32ab\u65b9tri;\u69celuhar;\u6968;\u611e\u0d61\u32d5\u32db\u32df\u332c\u3338\u3371\0\u337a\u33a4\0\0\u33ec\u33f0\0\u3428\u3448\u345a\u34ad\u34b1\u34ca\u34f1\0\u3616\0\0\u3633cute;\u415bqu\xef\u27ba\u0500;Eaceinpsy\u11ed\u32f3\u32f5\u32ff\u3302\u330b\u330f\u331f\u3326\u3329;\u6ab4\u01f0\u32fa\0\u32fc;\u6ab8on;\u4161u\xe5\u11fe\u0100;d\u11f3\u3307il;\u415frc;\u415d\u0180Eas\u3316\u3318\u331b;\u6ab6p;\u6abaim;\u62e9olint;\u6a13i\xed\u1204;\u4441ot\u0180;be\u3334\u1d47\u3335\u62c5;\u6a66\u0380Aacmstx\u3346\u334a\u3357\u335b\u335e\u3363\u336drr;\u61d8r\u0100hr\u3350\u3352\xeb\u2228\u0100;o\u0a36\u0a34t\u803b\xa7\u40a7i;\u403bwar;\u6929m\u0100in\u3369\xf0nu\xf3\xf1t;\u6736r\u0100;o\u3376\u2055\uc000\ud835\udd30\u0200acoy\u3382\u3386\u3391\u33a0rp;\u666f\u0100hy\u338b\u338fcy;\u4449;\u4448rt\u026d\u3399\0\0\u339ci\xe4\u1464ara\xec\u2e6f\u803b\xad\u40ad\u0100gm\u33a8\u33b4ma\u0180;fv\u33b1\u33b2\u33b2\u43c3;\u43c2\u0400;deglnpr\u12ab\u33c5\u33c9\u33ce\u33d6\u33de\u33e1\u33e6ot;\u6a6a\u0100;q\u12b1\u12b0\u0100;E\u33d3\u33d4\u6a9e;\u6aa0\u0100;E\u33db\u33dc\u6a9d;\u6a9fe;\u6246lus;\u6a24arr;\u6972ar\xf2\u113d\u0200aeit\u33f8\u3408\u340f\u3417\u0100ls\u33fd\u3404lsetm\xe9\u336ahp;\u6a33parsl;\u69e4\u0100dl\u1463\u3414e;\u6323\u0100;e\u341c\u341d\u6aaa\u0100;s\u3422\u3423\u6aac;\uc000\u2aac\ufe00\u0180flp\u342e\u3433\u3442tcy;\u444c\u0100;b\u3438\u3439\u402f\u0100;a\u343e\u343f\u69c4r;\u633ff;\uc000\ud835\udd64a\u0100dr\u344d\u0402es\u0100;u\u3454\u3455\u6660it\xbb\u3455\u0180csu\u3460\u3479\u349f\u0100au\u3465\u346fp\u0100;s\u1188\u346b;\uc000\u2293\ufe00p\u0100;s\u11b4\u3475;\uc000\u2294\ufe00u\u0100bp\u347f\u348f\u0180;es\u1197\u119c\u3486et\u0100;e\u1197\u348d\xf1\u119d\u0180;es\u11a8\u11ad\u3496et\u0100;e\u11a8\u349d\xf1\u11ae\u0180;af\u117b\u34a6\u05b0r\u0165\u34ab\u05b1\xbb\u117car\xf2\u1148\u0200cemt\u34b9\u34be\u34c2\u34c5r;\uc000\ud835\udcc8tm\xee\xf1i\xec\u3415ar\xe6\u11be\u0100ar\u34ce\u34d5r\u0100;f\u34d4\u17bf\u6606\u0100an\u34da\u34edight\u0100ep\u34e3\u34eapsilo\xee\u1ee0h\xe9\u2eafs\xbb\u2852\u0280bcmnp\u34fb\u355e\u1209\u358b\u358e\u0480;Edemnprs\u350e\u350f\u3511\u3515\u351e\u3523\u352c\u3531\u3536\u6282;\u6ac5ot;\u6abd\u0100;d\u11da\u351aot;\u6ac3ult;\u6ac1\u0100Ee\u3528\u352a;\u6acb;\u628alus;\u6abfarr;\u6979\u0180eiu\u353d\u3552\u3555t\u0180;en\u350e\u3545\u354bq\u0100;q\u11da\u350feq\u0100;q\u352b\u3528m;\u6ac7\u0100bp\u355a\u355c;\u6ad5;\u6ad3c\u0300;acens\u11ed\u356c\u3572\u3579\u357b\u3326ppro\xf8\u32faurlye\xf1\u11fe\xf1\u11f3\u0180aes\u3582\u3588\u331bppro\xf8\u331aq\xf1\u3317g;\u666a\u0680123;Edehlmnps\u35a9\u35ac\u35af\u121c\u35b2\u35b4\u35c0\u35c9\u35d5\u35da\u35df\u35e8\u35ed\u803b\xb9\u40b9\u803b\xb2\u40b2\u803b\xb3\u40b3;\u6ac6\u0100os\u35b9\u35bct;\u6abeub;\u6ad8\u0100;d\u1222\u35c5ot;\u6ac4s\u0100ou\u35cf\u35d2l;\u67c9b;\u6ad7arr;\u697bult;\u6ac2\u0100Ee\u35e4\u35e6;\u6acc;\u628blus;\u6ac0\u0180eiu\u35f4\u3609\u360ct\u0180;en\u121c\u35fc\u3602q\u0100;q\u1222\u35b2eq\u0100;q\u35e7\u35e4m;\u6ac8\u0100bp\u3611\u3613;\u6ad4;\u6ad6\u0180Aan\u361c\u3620\u362drr;\u61d9r\u0100hr\u3626\u3628\xeb\u222e\u0100;o\u0a2b\u0a29war;\u692alig\u803b\xdf\u40df\u0be1\u3651\u365d\u3660\u12ce\u3673\u3679\0\u367e\u36c2\0\0\0\0\0\u36db\u3703\0\u3709\u376c\0\0\0\u3787\u0272\u3656\0\0\u365bget;\u6316;\u43c4r\xeb\u0e5f\u0180aey\u3666\u366b\u3670ron;\u4165dil;\u4163;\u4442lrec;\u6315r;\uc000\ud835\udd31\u0200eiko\u3686\u369d\u36b5\u36bc\u01f2\u368b\0\u3691e\u01004f\u1284\u1281a\u0180;sv\u3698\u3699\u369b\u43b8ym;\u43d1\u0100cn\u36a2\u36b2k\u0100as\u36a8\u36aeppro\xf8\u12c1im\xbb\u12acs\xf0\u129e\u0100as\u36ba\u36ae\xf0\u12c1rn\u803b\xfe\u40fe\u01ec\u031f\u36c6\u22e7es\u8180\xd7;bd\u36cf\u36d0\u36d8\u40d7\u0100;a\u190f\u36d5r;\u6a31;\u6a30\u0180eps\u36e1\u36e3\u3700\xe1\u2a4d\u0200;bcf\u0486\u36ec\u36f0\u36f4ot;\u6336ir;\u6af1\u0100;o\u36f9\u36fc\uc000\ud835\udd65rk;\u6ada\xe1\u3362rime;\u6034\u0180aip\u370f\u3712\u3764d\xe5\u1248\u0380adempst\u3721\u374d\u3740\u3751\u3757\u375c\u375fngle\u0280;dlqr\u3730\u3731\u3736\u3740\u3742\u65b5own\xbb\u1dbbeft\u0100;e\u2800\u373e\xf1\u092e;\u625cight\u0100;e\u32aa\u374b\xf1\u105aot;\u65ecinus;\u6a3alus;\u6a39b;\u69cdime;\u6a3bezium;\u63e2\u0180cht\u3772\u377d\u3781\u0100ry\u3777\u377b;\uc000\ud835\udcc9;\u4446cy;\u445brok;\u4167\u0100io\u378b\u378ex\xf4\u1777head\u0100lr\u3797\u37a0eftarro\xf7\u084fightarrow\xbb\u0f5d\u0900AHabcdfghlmoprstuw\u37d0\u37d3\u37d7\u37e4\u37f0\u37fc\u380e\u381c\u3823\u3834\u3851\u385d\u386b\u38a9\u38cc\u38d2\u38ea\u38f6r\xf2\u03edar;\u6963\u0100cr\u37dc\u37e2ute\u803b\xfa\u40fa\xf2\u1150r\u01e3\u37ea\0\u37edy;\u445eve;\u416d\u0100iy\u37f5\u37farc\u803b\xfb\u40fb;\u4443\u0180abh\u3803\u3806\u380br\xf2\u13adlac;\u4171a\xf2\u13c3\u0100ir\u3813\u3818sht;\u697e;\uc000\ud835\udd32rave\u803b\xf9\u40f9\u0161\u3827\u3831r\u0100lr\u382c\u382e\xbb\u0957\xbb\u1083lk;\u6580\u0100ct\u3839\u384d\u026f\u383f\0\0\u384arn\u0100;e\u3845\u3846\u631cr\xbb\u3846op;\u630fri;\u65f8\u0100al\u3856\u385acr;\u416b\u80bb\xa8\u0349\u0100gp\u3862\u3866on;\u4173f;\uc000\ud835\udd66\u0300adhlsu\u114b\u3878\u387d\u1372\u3891\u38a0own\xe1\u13b3arpoon\u0100lr\u3888\u388cef\xf4\u382digh\xf4\u382fi\u0180;hl\u3899\u389a\u389c\u43c5\xbb\u13faon\xbb\u389aparrows;\u61c8\u0180cit\u38b0\u38c4\u38c8\u026f\u38b6\0\0\u38c1rn\u0100;e\u38bc\u38bd\u631dr\xbb\u38bdop;\u630eng;\u416fri;\u65f9cr;\uc000\ud835\udcca\u0180dir\u38d9\u38dd\u38e2ot;\u62f0lde;\u4169i\u0100;f\u3730\u38e8\xbb\u1813\u0100am\u38ef\u38f2r\xf2\u38a8l\u803b\xfc\u40fcangle;\u69a7\u0780ABDacdeflnoprsz\u391c\u391f\u3929\u392d\u39b5\u39b8\u39bd\u39df\u39e4\u39e8\u39f3\u39f9\u39fd\u3a01\u3a20r\xf2\u03f7ar\u0100;v\u3926\u3927\u6ae8;\u6ae9as\xe8\u03e1\u0100nr\u3932\u3937grt;\u699c\u0380eknprst\u34e3\u3946\u394b\u3952\u395d\u3964\u3996app\xe1\u2415othin\xe7\u1e96\u0180hir\u34eb\u2ec8\u3959op\xf4\u2fb5\u0100;h\u13b7\u3962\xef\u318d\u0100iu\u3969\u396dgm\xe1\u33b3\u0100bp\u3972\u3984setneq\u0100;q\u397d\u3980\uc000\u228a\ufe00;\uc000\u2acb\ufe00setneq\u0100;q\u398f\u3992\uc000\u228b\ufe00;\uc000\u2acc\ufe00\u0100hr\u399b\u399fet\xe1\u369ciangle\u0100lr\u39aa\u39afeft\xbb\u0925ight\xbb\u1051y;\u4432ash\xbb\u1036\u0180elr\u39c4\u39d2\u39d7\u0180;be\u2dea\u39cb\u39cfar;\u62bbq;\u625alip;\u62ee\u0100bt\u39dc\u1468a\xf2\u1469r;\uc000\ud835\udd33tr\xe9\u39aesu\u0100bp\u39ef\u39f1\xbb\u0d1c\xbb\u0d59pf;\uc000\ud835\udd67ro\xf0\u0efbtr\xe9\u39b4\u0100cu\u3a06\u3a0br;\uc000\ud835\udccb\u0100bp\u3a10\u3a18n\u0100Ee\u3980\u3a16\xbb\u397en\u0100Ee\u3992\u3a1e\xbb\u3990igzag;\u699a\u0380cefoprs\u3a36\u3a3b\u3a56\u3a5b\u3a54\u3a61\u3a6airc;\u4175\u0100di\u3a40\u3a51\u0100bg\u3a45\u3a49ar;\u6a5fe\u0100;q\u15fa\u3a4f;\u6259erp;\u6118r;\uc000\ud835\udd34pf;\uc000\ud835\udd68\u0100;e\u1479\u3a66at\xe8\u1479cr;\uc000\ud835\udccc\u0ae3\u178e\u3a87\0\u3a8b\0\u3a90\u3a9b\0\0\u3a9d\u3aa8\u3aab\u3aaf\0\0\u3ac3\u3ace\0\u3ad8\u17dc\u17dftr\xe9\u17d1r;\uc000\ud835\udd35\u0100Aa\u3a94\u3a97r\xf2\u03c3r\xf2\u09f6;\u43be\u0100Aa\u3aa1\u3aa4r\xf2\u03b8r\xf2\u09eba\xf0\u2713is;\u62fb\u0180dpt\u17a4\u3ab5\u3abe\u0100fl\u3aba\u17a9;\uc000\ud835\udd69im\xe5\u17b2\u0100Aa\u3ac7\u3acar\xf2\u03cer\xf2\u0a01\u0100cq\u3ad2\u17b8r;\uc000\ud835\udccd\u0100pt\u17d6\u3adcr\xe9\u17d4\u0400acefiosu\u3af0\u3afd\u3b08\u3b0c\u3b11\u3b15\u3b1b\u3b21c\u0100uy\u3af6\u3afbte\u803b\xfd\u40fd;\u444f\u0100iy\u3b02\u3b06rc;\u4177;\u444bn\u803b\xa5\u40a5r;\uc000\ud835\udd36cy;\u4457pf;\uc000\ud835\udd6acr;\uc000\ud835\udcce\u0100cm\u3b26\u3b29y;\u444el\u803b\xff\u40ff\u0500acdefhiosw\u3b42\u3b48\u3b54\u3b58\u3b64\u3b69\u3b6d\u3b74\u3b7a\u3b80cute;\u417a\u0100ay\u3b4d\u3b52ron;\u417e;\u4437ot;\u417c\u0100et\u3b5d\u3b61tr\xe6\u155fa;\u43b6r;\uc000\ud835\udd37cy;\u4436grarr;\u61ddpf;\uc000\ud835\udd6bcr;\uc000\ud835\udccf\u0100jn\u3b85\u3b87;\u600dj;\u600c" .split("") .map((c) => c.charCodeAt(0))); // Generated using scripts/write-decode-map.ts var xmlDecodeTree = new Uint16Array( // prettier-ignore "\u0200aglq\t\x15\x18\x1b\u026d\x0f\0\0\x12p;\u4026os;\u4027t;\u403et;\u403cuot;\u4022" .split("") .map((c) => c.charCodeAt(0))); // Adapted from https://github.com/mathiasbynens/he/blob/36afe179392226cf1b6ccdb16ebbb7a5a844d93a/src/he.js#L106-L134 var _a; const decodeMap = new Map([ [0, 65533], // C1 Unicode control character reference replacements [128, 8364], [130, 8218], [131, 402], [132, 8222], [133, 8230], [134, 8224], [135, 8225], [136, 710], [137, 8240], [138, 352], [139, 8249], [140, 338], [142, 381], [145, 8216], [146, 8217], [147, 8220], [148, 8221], [149, 8226], [150, 8211], [151, 8212], [152, 732], [153, 8482], [154, 353], [155, 8250], [156, 339], [158, 382], [159, 376], ]); /** * Polyfill for `String.fromCodePoint`. It is used to create a string from a Unicode code point. */ const fromCodePoint$1 = // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition, node/no-unsupported-features/es-builtins (_a = String.fromCodePoint) !== null && _a !== void 0 ? _a : function (codePoint) { let output = ""; if (codePoint > 0xffff) { codePoint -= 0x10000; output += String.fromCharCode(((codePoint >>> 10) & 0x3ff) | 0xd800); codePoint = 0xdc00 | (codePoint & 0x3ff); } output += String.fromCharCode(codePoint); return output; }; /** * Replace the given code point with a replacement character if it is a * surrogate or is outside the valid range. Otherwise return the code * point unchanged. */ function replaceCodePoint(codePoint) { var _a; if ((codePoint >= 0xd800 && codePoint <= 0xdfff) || codePoint > 0x10ffff) { return 0xfffd; } return (_a = decodeMap.get(codePoint)) !== null && _a !== void 0 ? _a : codePoint; } var CharCodes; (function (CharCodes) { CharCodes[CharCodes["NUM"] = 35] = "NUM"; CharCodes[CharCodes["SEMI"] = 59] = "SEMI"; CharCodes[CharCodes["EQUALS"] = 61] = "EQUALS"; CharCodes[CharCodes["ZERO"] = 48] = "ZERO"; CharCodes[CharCodes["NINE"] = 57] = "NINE"; CharCodes[CharCodes["LOWER_A"] = 97] = "LOWER_A"; CharCodes[CharCodes["LOWER_F"] = 102] = "LOWER_F"; CharCodes[CharCodes["LOWER_X"] = 120] = "LOWER_X"; CharCodes[CharCodes["LOWER_Z"] = 122] = "LOWER_Z"; CharCodes[CharCodes["UPPER_A"] = 65] = "UPPER_A"; CharCodes[CharCodes["UPPER_F"] = 70] = "UPPER_F"; CharCodes[CharCodes["UPPER_Z"] = 90] = "UPPER_Z"; })(CharCodes || (CharCodes = {})); /** Bit that needs to be set to convert an upper case ASCII character to lower case */ const TO_LOWER_BIT = 0b100000; var BinTrieFlags; (function (BinTrieFlags) { BinTrieFlags[BinTrieFlags["VALUE_LENGTH"] = 49152] = "VALUE_LENGTH"; BinTrieFlags[BinTrieFlags["BRANCH_LENGTH"] = 16256] = "BRANCH_LENGTH"; BinTrieFlags[BinTrieFlags["JUMP_TABLE"] = 127] = "JUMP_TABLE"; })(BinTrieFlags || (BinTrieFlags = {})); function isNumber(code) { return code >= CharCodes.ZERO && code <= CharCodes.NINE; } function isHexadecimalCharacter(code) { return ((code >= CharCodes.UPPER_A && code <= CharCodes.UPPER_F) || (code >= CharCodes.LOWER_A && code <= CharCodes.LOWER_F)); } function isAsciiAlphaNumeric(code) { return ((code >= CharCodes.UPPER_A && code <= CharCodes.UPPER_Z) || (code >= CharCodes.LOWER_A && code <= CharCodes.LOWER_Z) || isNumber(code)); } /** * Checks if the given character is a valid end character for an entity in an attribute. * * Attribute values that aren't terminated properly aren't parsed, and shouldn't lead to a parser error. * See the example in https://html.spec.whatwg.org/multipage/parsing.html#named-character-reference-state */ function isEntityInAttributeInvalidEnd(code) { return code === CharCodes.EQUALS || isAsciiAlphaNumeric(code); } var EntityDecoderState; (function (EntityDecoderState) { EntityDecoderState[EntityDecoderState["EntityStart"] = 0] = "EntityStart"; EntityDecoderState[EntityDecoderState["NumericStart"] = 1] = "NumericStart"; EntityDecoderState[EntityDecoderState["NumericDecimal"] = 2] = "NumericDecimal"; EntityDecoderState[EntityDecoderState["NumericHex"] = 3] = "NumericHex"; EntityDecoderState[EntityDecoderState["NamedEntity"] = 4] = "NamedEntity"; })(EntityDecoderState || (EntityDecoderState = {})); var DecodingMode; (function (DecodingMode) { /** Entities in text nodes that can end with any character. */ DecodingMode[DecodingMode["Legacy"] = 0] = "Legacy"; /** Only allow entities terminated with a semicolon. */ DecodingMode[DecodingMode["Strict"] = 1] = "Strict"; /** Entities in attributes have limitations on ending characters. */ DecodingMode[DecodingMode["Attribute"] = 2] = "Attribute"; })(DecodingMode || (DecodingMode = {})); /** * Token decoder with support of writing partial entities. */ class EntityDecoder { constructor( /** The tree used to decode entities. */ decodeTree, /** * The function that is called when a codepoint is decoded. * * For multi-byte named entities, this will be called multiple times, * with the second codepoint, and the same `consumed` value. * * @param codepoint The decoded codepoint. * @param consumed The number of bytes consumed by the decoder. */ emitCodePoint, /** An object that is used to produce errors. */ errors) { this.decodeTree = decodeTree; this.emitCodePoint = emitCodePoint; this.errors = errors; /** The current state of the decoder. */ this.state = EntityDecoderState.EntityStart; /** Characters that were consumed while parsing an entity. */ this.consumed = 1; /** * The result of the entity. * * Either the result index of a numeric entity, or the codepoint of a * numeric entity. */ this.result = 0; /** The current index in the decode tree. */ this.treeIndex = 0; /** The number of characters that were consumed in excess. */ this.excess = 1; /** The mode in which the decoder is operating. */ this.decodeMode = DecodingMode.Strict; } /** Resets the instance to make it reusable. */ startEntity(decodeMode) { this.decodeMode = decodeMode; this.state = EntityDecoderState.EntityStart; this.result = 0; this.treeIndex = 0; this.excess = 1; this.consumed = 1; } /** * Write an entity to the decoder. This can be called multiple times with partial entities. * If the entity is incomplete, the decoder will return -1. * * Mirrors the implementation of `getDecoder`, but with the ability to stop decoding if the * entity is incomplete, and resume when the next string is written. * * @param string The string containing the entity (or a continuation of the entity). * @param offset The offset at which the entity begins. Should be 0 if this is not the first call. * @returns The number of characters that were consumed, or -1 if the entity is incomplete. */ write(str, offset) { switch (this.state) { case EntityDecoderState.EntityStart: { if (str.charCodeAt(offset) === CharCodes.NUM) { this.state = EntityDecoderState.NumericStart; this.consumed += 1; return this.stateNumericStart(str, offset + 1); } this.state = EntityDecoderState.NamedEntity; return this.stateNamedEntity(str, offset); } case EntityDecoderState.NumericStart: { return this.stateNumericStart(str, offset); } case EntityDecoderState.NumericDecimal: { return this.stateNumericDecimal(str, offset); } case EntityDecoderState.NumericHex: { return this.stateNumericHex(str, offset); } case EntityDecoderState.NamedEntity: { return this.stateNamedEntity(str, offset); } } } /** * Switches between the numeric decimal and hexadecimal states. * * Equivalent to the `Numeric character reference state` in the HTML spec. * * @param str The string containing the entity (or a continuation of the entity). * @param offset The current offset. * @returns The number of characters that were consumed, or -1 if the entity is incomplete. */ stateNumericStart(str, offset) { if (offset >= str.length) { return -1; } if ((str.charCodeAt(offset) | TO_LOWER_BIT) === CharCodes.LOWER_X) { this.state = EntityDecoderState.NumericHex; this.consumed += 1; return this.stateNumericHex(str, offset + 1); } this.state = EntityDecoderState.NumericDecimal; return this.stateNumericDecimal(str, offset); } addToNumericResult(str, start, end, base) { if (start !== end) { const digitCount = end - start; this.result = this.result * Math.pow(base, digitCount) + parseInt(str.substr(start, digitCount), base); this.consumed += digitCount; } } /** * Parses a hexadecimal numeric entity. * * Equivalent to the `Hexademical character reference state` in the HTML spec. * * @param str The string containing the entity (or a continuation of the entity). * @param offset The current offset. * @returns The number of characters that were consumed, or -1 if the entity is incomplete. */ stateNumericHex(str, offset) { const startIdx = offset; while (offset < str.length) { const char = str.charCodeAt(offset); if (isNumber(char) || isHexadecimalCharacter(char)) { offset += 1; } else { this.addToNumericResult(str, startIdx, offset, 16); return this.emitNumericEntity(char, 3); } } this.addToNumericResult(str, startIdx, offset, 16); return -1; } /** * Parses a decimal numeric entity. * * Equivalent to the `Decimal character reference state` in the HTML spec. * * @param str The string containing the entity (or a continuation of the entity). * @param offset The current offset. * @returns The number of characters that were consumed, or -1 if the entity is incomplete. */ stateNumericDecimal(str, offset) { const startIdx = offset; while (offset < str.length) { const char = str.charCodeAt(offset); if (isNumber(char)) { offset += 1; } else { this.addToNumericResult(str, startIdx, offset, 10); return this.emitNumericEntity(char, 2); } } this.addToNumericResult(str, startIdx, offset, 10); return -1; } /** * Validate and emit a numeric entity. * * Implements the logic from the `Hexademical character reference start * state` and `Numeric character reference end state` in the HTML spec. * * @param lastCp The last code point of the entity. Used to see if the * entity was terminated with a semicolon. * @param expectedLength The minimum number of characters that should be * consumed. Used to validate that at least one digit * was consumed. * @returns The number of characters that were consumed. */ emitNumericEntity(lastCp, expectedLength) { var _a; // Ensure we consumed at least one digit. if (this.consumed <= expectedLength) { (_a = this.errors) === null || _a === void 0 ? void 0 : _a.absenceOfDigitsInNumericCharacterReference(this.consumed); return 0; } // Figure out if this is a legit end of the entity if (lastCp === CharCodes.SEMI) { this.consumed += 1; } else if (this.decodeMode === DecodingMode.Strict) { return 0; } this.emitCodePoint(replaceCodePoint(this.result), this.consumed); if (this.errors) { if (lastCp !== CharCodes.SEMI) { this.errors.missingSemicolonAfterCharacterReference(); } this.errors.validateNumericCharacterReference(this.result); } return this.consumed; } /** * Parses a named entity. * * Equivalent to the `Named character reference state` in the HTML spec. * * @param str The string containing the entity (or a continuation of the entity). * @param offset The current offset. * @returns The number of characters that were consumed, or -1 if the entity is incomplete. */ stateNamedEntity(str, offset) { const { decodeTree } = this; let current = decodeTree[this.treeIndex]; // The mask is the number of bytes of the value, including the current byte. let valueLength = (current & BinTrieFlags.VALUE_LENGTH) >> 14; for (; offset < str.length; offset++, this.excess++) { const char = str.charCodeAt(offset); this.treeIndex = determineBranch(decodeTree, current, this.treeIndex + Math.max(1, valueLength), char); if (this.treeIndex < 0) { return this.result === 0 || // If we are parsing an attribute (this.decodeMode === DecodingMode.Attribute && // We shouldn't have consumed any characters after the entity, (valueLength === 0 || // And there should be no invalid characters. isEntityInAttributeInvalidEnd(char))) ? 0 : this.emitNotTerminatedNamedEntity(); } current = decodeTree[this.treeIndex]; valueLength = (current & BinTrieFlags.VALUE_LENGTH) >> 14; // If the branch is a value, store it and continue if (valueLength !== 0) { // If the entity is terminated by a semicolon, we are done. if (char === CharCodes.SEMI) { return this.emitNamedEntityData(this.treeIndex, valueLength, this.consumed + this.excess); } // If we encounter a non-terminated (legacy) entity while parsing strictly, then ignore it. if (this.decodeMode !== DecodingMode.Strict) { this.result = this.treeIndex; this.consumed += this.excess; this.excess = 0; } } } return -1; } /** * Emit a named entity that was not terminated with a semicolon. * * @returns The number of characters consumed. */ emitNotTerminatedNamedEntity() { var _a; const { result, decodeTree } = this; const valueLength = (decodeTree[result] & BinTrieFlags.VALUE_LENGTH) >> 14; this.emitNamedEntityData(result, valueLength, this.consumed); (_a = this.errors) === null || _a === void 0 ? void 0 : _a.missingSemicolonAfterCharacterReference(); return this.consumed; } /** * Emit a named entity. * * @param result The index of the entity in the decode tree. * @param valueLength The number of bytes in the entity. * @param consumed The number of characters consumed. * * @returns The number of characters consumed. */ emitNamedEntityData(result, valueLength, consumed) { const { decodeTree } = this; this.emitCodePoint(valueLength === 1 ? decodeTree[result] & ~BinTrieFlags.VALUE_LENGTH : decodeTree[result + 1], consumed); if (valueLength === 3) { // For multi-byte values, we need to emit the second byte. this.emitCodePoint(decodeTree[result + 2], consumed); } return consumed; } /** * Signal to the parser that the end of the input was reached. * * Remaining data will be emitted and relevant errors will be produced. * * @returns The number of characters consumed. */ end() { var _a; switch (this.state) { case EntityDecoderState.NamedEntity: { // Emit a named entity if we have one. return this.result !== 0 && (this.decodeMode !== DecodingMode.Attribute || this.result === this.treeIndex) ? this.emitNotTerminatedNamedEntity() : 0; } // Otherwise, emit a numeric entity if we have one. case EntityDecoderState.NumericDecimal: { return this.emitNumericEntity(0, 2); } case EntityDecoderState.NumericHex: { return this.emitNumericEntity(0, 3); } case EntityDecoderState.NumericStart: { (_a = this.errors) === null || _a === void 0 ? void 0 : _a.absenceOfDigitsInNumericCharacterReference(this.consumed); return 0; } case EntityDecoderState.EntityStart: { // Return 0 if we have no entity. return 0; } } } } /** * Creates a function that decodes entities in a string. * * @param decodeTree The decode tree. * @returns A function that decodes entities in a string. */ function getDecoder(decodeTree) { let ret = ""; const decoder = new EntityDecoder(decodeTree, (str) => (ret += fromCodePoint$1(str))); return function decodeWithTrie(str, decodeMode) { let lastIndex = 0; let offset = 0; while ((offset = str.indexOf("&", offset)) >= 0) { ret += str.slice(lastIndex, offset); decoder.startEntity(decodeMode); const len = decoder.write(str, // Skip the "&" offset + 1); if (len < 0) { lastIndex = offset + decoder.end(); break; } lastIndex = offset + len; // If `len` is 0, skip the current `&` and continue. offset = len === 0 ? lastIndex + 1 : lastIndex; } const result = ret + str.slice(lastIndex); // Make sure we don't keep a reference to the final string. ret = ""; return result; }; } /** * Determines the branch of the current node that is taken given the current * character. This function is used to traverse the trie. * * @param decodeTree The trie. * @param current The current node. * @param nodeIdx The index right after the current node and its value. * @param char The current character. * @returns The index of the next node, or -1 if no branch is taken. */ function determineBranch(decodeTree, current, nodeIdx, char) { const branchCount = (current & BinTrieFlags.BRANCH_LENGTH) >> 7; const jumpOffset = current & BinTrieFlags.JUMP_TABLE; // Case 1: Single branch encoded in jump offset if (branchCount === 0) { return jumpOffset !== 0 && char === jumpOffset ? nodeIdx : -1; } // Case 2: Multiple branches encoded in jump table if (jumpOffset) { const value = char - jumpOffset; return value < 0 || value >= branchCount ? -1 : decodeTree[nodeIdx + value] - 1; } // Case 3: Multiple branches encoded in dictionary // Binary search for the character. let lo = nodeIdx; let hi = lo + branchCount - 1; while (lo <= hi) { const mid = (lo + hi) >>> 1; const midVal = decodeTree[mid]; if (midVal < char) { lo = mid + 1; } else if (midVal > char) { hi = mid - 1; } else { return decodeTree[mid + branchCount]; } } return -1; } const htmlDecoder = getDecoder(htmlDecodeTree); getDecoder(xmlDecodeTree); /** * Decodes an HTML string. * * @param str The string to decode. * @param mode The decoding mode. * @returns The decoded string. */ function decodeHTML(str, mode = DecodingMode.Legacy) { return htmlDecoder(str, mode); } // Utilities // function _class$1 (obj) { return Object.prototype.toString.call(obj) } function isString$1 (obj) { return _class$1(obj) === '[object String]' } const _hasOwnProperty = Object.prototype.hasOwnProperty; function has (object, key) { return _hasOwnProperty.call(object, key) } // Merge objects // function assign$1 (obj /* from1, from2, from3, ... */) { const sources = Array.prototype.slice.call(arguments, 1); sources.forEach(function (source) { if (!source) { return } if (typeof source !== 'object') { throw new TypeError(source + 'must be object') } Object.keys(source).forEach(function (key) { obj[key] = source[key]; }); }); return obj } // Remove element from array and put another array at those position. // Useful for some operations with tokens function arrayReplaceAt (src, pos, newElements) { return [].concat(src.slice(0, pos), newElements, src.slice(pos + 1)) } function isValidEntityCode (c) { /* eslint no-bitwise:0 */ // broken sequence if (c >= 0xD800 && c <= 0xDFFF) { return false } // never used if (c >= 0xFDD0 && c <= 0xFDEF) { return false } if ((c & 0xFFFF) === 0xFFFF || (c & 0xFFFF) === 0xFFFE) { return false } // control codes if (c >= 0x00 && c <= 0x08) { return false } if (c === 0x0B) { return false } if (c >= 0x0E && c <= 0x1F) { return false } if (c >= 0x7F && c <= 0x9F) { return false } // out of range if (c > 0x10FFFF) { return false } return true } function fromCodePoint (c) { /* eslint no-bitwise:0 */ if (c > 0xffff) { c -= 0x10000; const surrogate1 = 0xd800 + (c >> 10); const surrogate2 = 0xdc00 + (c & 0x3ff); return String.fromCharCode(surrogate1, surrogate2) } return String.fromCharCode(c) } const UNESCAPE_MD_RE = /\\([!"#$%&'()*+,\-./:;<=>?@[\\\]^_`{|}~])/g; const ENTITY_RE = /&([a-z#][a-z0-9]{1,31});/gi; const UNESCAPE_ALL_RE = new RegExp(UNESCAPE_MD_RE.source + '|' + ENTITY_RE.source, 'gi'); const DIGITAL_ENTITY_TEST_RE = /^#((?:x[a-f0-9]{1,8}|[0-9]{1,8}))$/i; function replaceEntityPattern (match, name) { if (name.charCodeAt(0) === 0x23/* # */ && DIGITAL_ENTITY_TEST_RE.test(name)) { const code = name[1].toLowerCase() === 'x' ? parseInt(name.slice(2), 16) : parseInt(name.slice(1), 10); if (isValidEntityCode(code)) { return fromCodePoint(code) } return match } const decoded = decodeHTML(match); if (decoded !== match) { return decoded } return match } /* function replaceEntities(str) { if (str.indexOf('&') < 0) { return str; } return str.replace(ENTITY_RE, replaceEntityPattern); } */ function unescapeMd (str) { if (str.indexOf('\\') < 0) { return str } return str.replace(UNESCAPE_MD_RE, '$1') } function unescapeAll (str) { if (str.indexOf('\\') < 0 && str.indexOf('&') < 0) { return str } return str.replace(UNESCAPE_ALL_RE, function (match, escaped, entity) { if (escaped) { return escaped } return replaceEntityPattern(match, entity) }) } const HTML_ESCAPE_TEST_RE = /[&<>"]/; const HTML_ESCAPE_REPLACE_RE = /[&<>"]/g; const HTML_REPLACEMENTS = { '&': '&', '<': '<', '>': '>', '"': '"' }; function replaceUnsafeChar (ch) { return HTML_REPLACEMENTS[ch] } function escapeHtml$1 (str) { if (HTML_ESCAPE_TEST_RE.test(str)) { return str.replace(HTML_ESCAPE_REPLACE_RE, replaceUnsafeChar) } return str } const REGEXP_ESCAPE_RE = /[.?*+^$[\]\\(){}|-]/g; function escapeRE$1 (str) { return str.replace(REGEXP_ESCAPE_RE, '\\$&') } function isSpace (code) { switch (code) { case 0x09: case 0x20: return true } return false } // Zs (unicode class) || [\t\f\v\r\n] function isWhiteSpace (code) { if (code >= 0x2000 && code <= 0x200A) { return true } switch (code) { case 0x09: // \t case 0x0A: // \n case 0x0B: // \v case 0x0C: // \f case 0x0D: // \r case 0x20: case 0xA0: case 0x1680: case 0x202F: case 0x205F: case 0x3000: return true } return false } /* eslint-disable max-len */ // Currently without astral characters support. function isPunctChar (ch) { return P$1.test(ch) || regex$1.test(ch) } // Markdown ASCII punctuation characters. // // !, ", #, $, %, &, ', (, ), *, +, ,, -, ., /, :, ;, <, =, >, ?, @, [, \, ], ^, _, `, {, |, }, or ~ // http://spec.commonmark.org/0.15/#ascii-punctuation-character // // Don't confuse with unicode punctuation !!! It lacks some chars in ascii range. // function isMdAsciiPunct (ch) { switch (ch) { case 0x21/* ! */: case 0x22/* " */: case 0x23/* # */: case 0x24/* $ */: case 0x25/* % */: case 0x26/* & */: case 0x27/* ' */: case 0x28/* ( */: case 0x29/* ) */: case 0x2A/* * */: case 0x2B/* + */: case 0x2C/* , */: case 0x2D/* - */: case 0x2E/* . */: case 0x2F/* / */: case 0x3A/* : */: case 0x3B/* ; */: case 0x3C/* < */: case 0x3D/* = */: case 0x3E/* > */: case 0x3F/* ? */: case 0x40/* @ */: case 0x5B/* [ */: case 0x5C/* \ */: case 0x5D/* ] */: case 0x5E/* ^ */: case 0x5F/* _ */: case 0x60/* ` */: case 0x7B/* { */: case 0x7C/* | */: case 0x7D/* } */: case 0x7E/* ~ */: return true default: return false } } // Hepler to unify [reference labels]. // function normalizeReference (str) { // Trim and collapse whitespace // str = str.trim().replace(/\s+/g, ' '); // In node v10 'ẞ'.toLowerCase() === 'Ṿ', which is presumed to be a bug // fixed in v12 (couldn't find any details). // // So treat this one as a special case // (remove this when node v10 is no longer supported). // if ('ẞ'.toLowerCase() === 'Ṿ') { str = str.replace(/ẞ/g, 'ß'); } // .toLowerCase().toUpperCase() should get rid of all differences // between letter variants. // // Simple .toLowerCase() doesn't normalize 125 code points correctly, // and .toUpperCase doesn't normalize 6 of them (list of exceptions: // İ, ϴ, ẞ, Ω, K, Å - those are already uppercased, but have differently // uppercased versions). // // Here's an example showing how it happens. Lets take greek letter omega: // uppercase U+0398 (Θ), U+03f4 (ϴ) and lowercase U+03b8 (θ), U+03d1 (ϑ) // // Unicode entries: // 0398;GREEK CAPITAL LETTER THETA;Lu;0;L;;;;;N;;;;03B8; // 03B8;GREEK SMALL LETTER THETA;Ll;0;L;;;;;N;;;0398;;0398 // 03D1;GREEK THETA SYMBOL;Ll;0;L; 03B8;;;;N;GREEK SMALL LETTER SCRIPT THETA;;0398;;0398 // 03F4;GREEK CAPITAL THETA SYMBOL;Lu;0;L; 0398;;;;N;;;;03B8; // // Case-insensitive comparison should treat all of them as equivalent. // // But .toLowerCase() doesn't change ϑ (it's already lowercase), // and .toUpperCase() doesn't change ϴ (already uppercase). // // Applying first lower then upper case normalizes any character: // '\u0398\u03f4\u03b8\u03d1'.toLowerCase().toUpperCase() === '\u0398\u0398\u0398\u0398' // // Note: this is equivalent to unicode case folding; unicode normalization // is a different step that is not required here. // // Final result should be uppercased, because it's later stored in an object // (this avoid a conflict with Object.prototype members, // most notably, `__proto__`) // return str.toLowerCase().toUpperCase() } // Re-export libraries commonly used in both markdown-it and its plugins, // so plugins won't have to depend on them explicitly, which reduces their // bundled size (e.g. a browser build). // const lib = { mdurl, ucmicro }; var utils$1 = /*#__PURE__*/Object.freeze({ __proto__: null, arrayReplaceAt: arrayReplaceAt, assign: assign$1, escapeHtml: escapeHtml$1, escapeRE: escapeRE$1, fromCodePoint: fromCodePoint, has: has, isMdAsciiPunct: isMdAsciiPunct, isPunctChar: isPunctChar, isSpace: isSpace, isString: isString$1, isValidEntityCode: isValidEntityCode, isWhiteSpace: isWhiteSpace, lib: lib, normalizeReference: normalizeReference, unescapeAll: unescapeAll, unescapeMd: unescapeMd }); // Parse link label // // this function assumes that first character ("[") already matches; // returns the end of the label // function parseLinkLabel (state, start, disableNested) { let level, found, marker, prevPos; const max = state.posMax; const oldPos = state.pos; state.pos = start + 1; level = 1; while (state.pos < max) { marker = state.src.charCodeAt(state.pos); if (marker === 0x5D /* ] */) { level--; if (level === 0) { found = true; break } } prevPos = state.pos; state.md.inline.skipToken(state); if (marker === 0x5B /* [ */) { if (prevPos === state.pos - 1) { // increase level if we find text `[`, which is not a part of any token level++; } else if (disableNested) { state.pos = oldPos; return -1 } } } let labelEnd = -1; if (found) { labelEnd = state.pos; } // restore old state state.pos = oldPos; return labelEnd } // Parse link destination // function parseLinkDestination (str, start, max) { let code; let pos = start; const result = { ok: false, pos: 0, str: '' }; if (str.charCodeAt(pos) === 0x3C /* < */) { pos++; while (pos < max) { code = str.charCodeAt(pos); if (code === 0x0A /* \n */) { return result } if (code === 0x3C /* < */) { return result } if (code === 0x3E /* > */) { result.pos = pos + 1; result.str = unescapeAll(str.slice(start + 1, pos)); result.ok = true; return result } if (code === 0x5C /* \ */ && pos + 1 < max) { pos += 2; continue } pos++; } // no closing '>' return result } // this should be ... } else { ... branch let level = 0; while (pos < max) { code = str.charCodeAt(pos); if (code === 0x20) { break } // ascii control characters if (code < 0x20 || code === 0x7F) { break } if (code === 0x5C /* \ */ && pos + 1 < max) { if (str.charCodeAt(pos + 1) === 0x20) { break } pos += 2; continue } if (code === 0x28 /* ( */) { level++; if (level > 32) { return result } } if (code === 0x29 /* ) */) { if (level === 0) { break } level--; } pos++; } if (start === pos) { return result } if (level !== 0) { return result } result.str = unescapeAll(str.slice(start, pos)); result.pos = pos; result.ok = true; return result } // Parse link title // // Parse link title within `str` in [start, max] range, // or continue previous parsing if `prev_state` is defined (equal to result of last execution). // function parseLinkTitle (str, start, max, prev_state) { let code; let pos = start; const state = { // if `true`, this is a valid link title ok: false, // if `true`, this link can be continued on the next line can_continue: false, // if `ok`, it's the position of the first character after the closing marker pos: 0, // if `ok`, it's the unescaped title str: '', // expected closing marker character code marker: 0 }; if (prev_state) { // this is a continuation of a previous parseLinkTitle call on the next line, // used in reference links only state.str = prev_state.str; state.marker = prev_state.marker; } else { if (pos >= max) { return state } let marker = str.charCodeAt(pos); if (marker !== 0x22 /* " */ && marker !== 0x27 /* ' */ && marker !== 0x28 /* ( */) { return state } start++; pos++; // if opening marker is "(", switch it to closing marker ")" if (marker === 0x28) { marker = 0x29; } state.marker = marker; } while (pos < max) { code = str.charCodeAt(pos); if (code === state.marker) { state.pos = pos + 1; state.str += unescapeAll(str.slice(start, pos)); state.ok = true; return state } else if (code === 0x28 /* ( */ && state.marker === 0x29 /* ) */) { return state } else if (code === 0x5C /* \ */ && pos + 1 < max) { pos++; } pos++; } // no closing marker found, but this link title may continue on the next line (for references) state.can_continue = true; state.str += unescapeAll(str.slice(start, pos)); return state } // Just a shortcut for bulk export var helpers = /*#__PURE__*/Object.freeze({ __proto__: null, parseLinkDestination: parseLinkDestination, parseLinkLabel: parseLinkLabel, parseLinkTitle: parseLinkTitle }); /** * class Renderer * * Generates HTML from parsed token stream. Each instance has independent * copy of rules. Those can be rewritten with ease. Also, you can add new * rules if you create plugin and adds new token types. **/ const default_rules = {}; default_rules.code_inline = function (tokens, idx, options, env, slf) { const token = tokens[idx]; return '' + escapeHtml$1(token.content) + '' }; default_rules.code_block = function (tokens, idx, options, env, slf) { const token = tokens[idx]; return '' + escapeHtml$1(tokens[idx].content) + '
\n' }; default_rules.fence = function (tokens, idx, options, env, slf) { const token = tokens[idx]; const info = token.info ? unescapeAll(token.info).trim() : ''; let langName = ''; let langAttrs = ''; if (info) { const arr = info.split(/(\s+)/g); langName = arr[0]; langAttrs = arr.slice(2).join(''); } let highlighted; if (options.highlight) { highlighted = options.highlight(token.content, langName, langAttrs) || escapeHtml$1(token.content); } else { highlighted = escapeHtml$1(token.content); } if (highlighted.indexOf('${highlighted}
\n` } return `
${highlighted}
\n` }; default_rules.image = function (tokens, idx, options, env, slf) { const token = tokens[idx]; // "alt" attr MUST be set, even if empty. Because it's mandatory and // should be placed on proper position for tests. // // Replace content with actual value token.attrs[token.attrIndex('alt')][1] = slf.renderInlineAsText(token.children, options, env); return slf.renderToken(tokens, idx, options) }; default_rules.hardbreak = function (tokens, idx, options /*, env */) { return options.xhtmlOut ? '
\n' : '
\n' }; default_rules.softbreak = function (tokens, idx, options /*, env */) { return options.breaks ? (options.xhtmlOut ? '
\n' : '
\n') : '\n' }; default_rules.text = function (tokens, idx /*, options, env */) { return escapeHtml$1(tokens[idx].content) }; default_rules.html_block = function (tokens, idx /*, options, env */) { return tokens[idx].content }; default_rules.html_inline = function (tokens, idx /*, options, env */) { return tokens[idx].content }; /** * new Renderer() * * Creates new [[Renderer]] instance and fill [[Renderer#rules]] with defaults. **/ function Renderer () { /** * Renderer#rules -> Object * * Contains render rules for tokens. Can be updated and extended. * * ##### Example * * ```javascript * var md = require('markdown-it')(); * * md.renderer.rules.strong_open = function () { return ''; }; * md.renderer.rules.strong_close = function () { return ''; }; * * var result = md.renderInline(...); * ``` * * Each rule is called as independent static function with fixed signature: * * ```javascript * function my_token_render(tokens, idx, options, env, renderer) { * // ... * return renderedHTML; * } * ``` * * See [source code](https://github.com/markdown-it/markdown-it/blob/master/lib/renderer.mjs) * for more details and examples. **/ this.rules = assign$1({}, default_rules); } /** * Renderer.renderAttrs(token) -> String * * Render token attributes to string. **/ Renderer.prototype.renderAttrs = function renderAttrs (token) { let i, l, result; if (!token.attrs) { return '' } result = ''; for (i = 0, l = token.attrs.length; i < l; i++) { result += ' ' + escapeHtml$1(token.attrs[i][0]) + '="' + escapeHtml$1(token.attrs[i][1]) + '"'; } return result }; /** * Renderer.renderToken(tokens, idx, options) -> String * - tokens (Array): list of tokens * - idx (Numbed): token index to render * - options (Object): params of parser instance * * Default token renderer. Can be overriden by custom function * in [[Renderer#rules]]. **/ Renderer.prototype.renderToken = function renderToken (tokens, idx, options) { const token = tokens[idx]; let result = ''; // Tight list paragraphs if (token.hidden) { return '' } // Insert a newline between hidden paragraph and subsequent opening // block-level tag. // // For example, here we should insert a newline before blockquote: // - a // > // if (token.block && token.nesting !== -1 && idx && tokens[idx - 1].hidden) { result += '\n'; } // Add token name, e.g. ``. // needLf = false; } } } } result += needLf ? '>\n' : '>'; return result }; /** * Renderer.renderInline(tokens, options, env) -> String * - tokens (Array): list on block tokens to render * - options (Object): params of parser instance * - env (Object): additional data from parsed input (references, for example) * * The same as [[Renderer.render]], but for single token of `inline` type. **/ Renderer.prototype.renderInline = function (tokens, options, env) { let result = ''; const rules = this.rules; for (let i = 0, len = tokens.length; i < len; i++) { const type = tokens[i].type; if (typeof rules[type] !== 'undefined') { result += rules[type](tokens, i, options, env, this); } else { result += this.renderToken(tokens, i, options); } } return result }; /** internal * Renderer.renderInlineAsText(tokens, options, env) -> String * - tokens (Array): list on block tokens to render * - options (Object): params of parser instance * - env (Object): additional data from parsed input (references, for example) * * Special kludge for image `alt` attributes to conform CommonMark spec. * Don't try to use it! Spec requires to show `alt` content with stripped markup, * instead of simple escaping. **/ Renderer.prototype.renderInlineAsText = function (tokens, options, env) { let result = ''; for (let i = 0, len = tokens.length; i < len; i++) { switch (tokens[i].type) { case 'text': result += tokens[i].content; break case 'image': result += this.renderInlineAsText(tokens[i].children, options, env); break case 'html_inline': case 'html_block': result += tokens[i].content; break case 'softbreak': case 'hardbreak': result += '\n'; break // all other tokens are skipped } } return result }; /** * Renderer.render(tokens, options, env) -> String * - tokens (Array): list on block tokens to render * - options (Object): params of parser instance * - env (Object): additional data from parsed input (references, for example) * * Takes token stream and generates HTML. Probably, you will never need to call * this method directly. **/ Renderer.prototype.render = function (tokens, options, env) { let result = ''; const rules = this.rules; for (let i = 0, len = tokens.length; i < len; i++) { const type = tokens[i].type; if (type === 'inline') { result += this.renderInline(tokens[i].children, options, env); } else if (typeof rules[type] !== 'undefined') { result += rules[type](tokens, i, options, env, this); } else { result += this.renderToken(tokens, i, options, env); } } return result }; /** * class Ruler * * Helper class, used by [[MarkdownIt#core]], [[MarkdownIt#block]] and * [[MarkdownIt#inline]] to manage sequences of functions (rules): * * - keep rules in defined order * - assign the name to each rule * - enable/disable rules * - add/replace rules * - allow assign rules to additional named chains (in the same) * - cacheing lists of active rules * * You will not need use this class directly until write plugins. For simple * rules control use [[MarkdownIt.disable]], [[MarkdownIt.enable]] and * [[MarkdownIt.use]]. **/ /** * new Ruler() **/ function Ruler () { // List of added rules. Each element is: // // { // name: XXX, // enabled: Boolean, // fn: Function(), // alt: [ name2, name3 ] // } // this.__rules__ = []; // Cached rule chains. // // First level - chain name, '' for default. // Second level - diginal anchor for fast filtering by charcodes. // this.__cache__ = null; } // Helper methods, should not be used directly // Find rule index by name // Ruler.prototype.__find__ = function (name) { for (let i = 0; i < this.__rules__.length; i++) { if (this.__rules__[i].name === name) { return i } } return -1 }; // Build rules lookup cache // Ruler.prototype.__compile__ = function () { const self = this; const chains = ['']; // collect unique names self.__rules__.forEach(function (rule) { if (!rule.enabled) { return } rule.alt.forEach(function (altName) { if (chains.indexOf(altName) < 0) { chains.push(altName); } }); }); self.__cache__ = {}; chains.forEach(function (chain) { self.__cache__[chain] = []; self.__rules__.forEach(function (rule) { if (!rule.enabled) { return } if (chain && rule.alt.indexOf(chain) < 0) { return } self.__cache__[chain].push(rule.fn); }); }); }; /** * Ruler.at(name, fn [, options]) * - name (String): rule name to replace. * - fn (Function): new rule function. * - options (Object): new rule options (not mandatory). * * Replace rule by name with new function & options. Throws error if name not * found. * * ##### Options: * * - __alt__ - array with names of "alternate" chains. * * ##### Example * * Replace existing typographer replacement rule with new one: * * ```javascript * var md = require('markdown-it')(); * * md.core.ruler.at('replacements', function replace(state) { * //... * }); * ``` **/ Ruler.prototype.at = function (name, fn, options) { const index = this.__find__(name); const opt = options || {}; if (index === -1) { throw new Error('Parser rule not found: ' + name) } this.__rules__[index].fn = fn; this.__rules__[index].alt = opt.alt || []; this.__cache__ = null; }; /** * Ruler.before(beforeName, ruleName, fn [, options]) * - beforeName (String): new rule will be added before this one. * - ruleName (String): name of added rule. * - fn (Function): rule function. * - options (Object): rule options (not mandatory). * * Add new rule to chain before one with given name. See also * [[Ruler.after]], [[Ruler.push]]. * * ##### Options: * * - __alt__ - array with names of "alternate" chains. * * ##### Example * * ```javascript * var md = require('markdown-it')(); * * md.block.ruler.before('paragraph', 'my_rule', function replace(state) { * //... * }); * ``` **/ Ruler.prototype.before = function (beforeName, ruleName, fn, options) { const index = this.__find__(beforeName); const opt = options || {}; if (index === -1) { throw new Error('Parser rule not found: ' + beforeName) } this.__rules__.splice(index, 0, { name: ruleName, enabled: true, fn, alt: opt.alt || [] }); this.__cache__ = null; }; /** * Ruler.after(afterName, ruleName, fn [, options]) * - afterName (String): new rule will be added after this one. * - ruleName (String): name of added rule. * - fn (Function): rule function. * - options (Object): rule options (not mandatory). * * Add new rule to chain after one with given name. See also * [[Ruler.before]], [[Ruler.push]]. * * ##### Options: * * - __alt__ - array with names of "alternate" chains. * * ##### Example * * ```javascript * var md = require('markdown-it')(); * * md.inline.ruler.after('text', 'my_rule', function replace(state) { * //... * }); * ``` **/ Ruler.prototype.after = function (afterName, ruleName, fn, options) { const index = this.__find__(afterName); const opt = options || {}; if (index === -1) { throw new Error('Parser rule not found: ' + afterName) } this.__rules__.splice(index + 1, 0, { name: ruleName, enabled: true, fn, alt: opt.alt || [] }); this.__cache__ = null; }; /** * Ruler.push(ruleName, fn [, options]) * - ruleName (String): name of added rule. * - fn (Function): rule function. * - options (Object): rule options (not mandatory). * * Push new rule to the end of chain. See also * [[Ruler.before]], [[Ruler.after]]. * * ##### Options: * * - __alt__ - array with names of "alternate" chains. * * ##### Example * * ```javascript * var md = require('markdown-it')(); * * md.core.ruler.push('my_rule', function replace(state) { * //... * }); * ``` **/ Ruler.prototype.push = function (ruleName, fn, options) { const opt = options || {}; this.__rules__.push({ name: ruleName, enabled: true, fn, alt: opt.alt || [] }); this.__cache__ = null; }; /** * Ruler.enable(list [, ignoreInvalid]) -> Array * - list (String|Array): list of rule names to enable. * - ignoreInvalid (Boolean): set `true` to ignore errors when rule not found. * * Enable rules with given names. If any rule name not found - throw Error. * Errors can be disabled by second param. * * Returns list of found rule names (if no exception happened). * * See also [[Ruler.disable]], [[Ruler.enableOnly]]. **/ Ruler.prototype.enable = function (list, ignoreInvalid) { if (!Array.isArray(list)) { list = [list]; } const result = []; // Search by name and enable list.forEach(function (name) { const idx = this.__find__(name); if (idx < 0) { if (ignoreInvalid) { return } throw new Error('Rules manager: invalid rule name ' + name) } this.__rules__[idx].enabled = true; result.push(name); }, this); this.__cache__ = null; return result }; /** * Ruler.enableOnly(list [, ignoreInvalid]) * - list (String|Array): list of rule names to enable (whitelist). * - ignoreInvalid (Boolean): set `true` to ignore errors when rule not found. * * Enable rules with given names, and disable everything else. If any rule name * not found - throw Error. Errors can be disabled by second param. * * See also [[Ruler.disable]], [[Ruler.enable]]. **/ Ruler.prototype.enableOnly = function (list, ignoreInvalid) { if (!Array.isArray(list)) { list = [list]; } this.__rules__.forEach(function (rule) { rule.enabled = false; }); this.enable(list, ignoreInvalid); }; /** * Ruler.disable(list [, ignoreInvalid]) -> Array * - list (String|Array): list of rule names to disable. * - ignoreInvalid (Boolean): set `true` to ignore errors when rule not found. * * Disable rules with given names. If any rule name not found - throw Error. * Errors can be disabled by second param. * * Returns list of found rule names (if no exception happened). * * See also [[Ruler.enable]], [[Ruler.enableOnly]]. **/ Ruler.prototype.disable = function (list, ignoreInvalid) { if (!Array.isArray(list)) { list = [list]; } const result = []; // Search by name and disable list.forEach(function (name) { const idx = this.__find__(name); if (idx < 0) { if (ignoreInvalid) { return } throw new Error('Rules manager: invalid rule name ' + name) } this.__rules__[idx].enabled = false; result.push(name); }, this); this.__cache__ = null; return result }; /** * Ruler.getRules(chainName) -> Array * * Return array of active functions (rules) for given chain name. It analyzes * rules configuration, compiles caches if not exists and returns result. * * Default chain name is `''` (empty string). It can't be skipped. That's * done intentionally, to keep signature monomorphic for high speed. **/ Ruler.prototype.getRules = function (chainName) { if (this.__cache__ === null) { this.__compile__(); } // Chain can be empty, if rules disabled. But we still have to return Array. return this.__cache__[chainName] || [] }; // Token class /** * class Token **/ /** * new Token(type, tag, nesting) * * Create new token and fill passed properties. **/ function Token (type, tag, nesting) { /** * Token#type -> String * * Type of the token (string, e.g. "paragraph_open") **/ this.type = type; /** * Token#tag -> String * * html tag name, e.g. "p" **/ this.tag = tag; /** * Token#attrs -> Array * * Html attributes. Format: `[ [ name1, value1 ], [ name2, value2 ] ]` **/ this.attrs = null; /** * Token#map -> Array * * Source map info. Format: `[ line_begin, line_end ]` **/ this.map = null; /** * Token#nesting -> Number * * Level change (number in {-1, 0, 1} set), where: * * - `1` means the tag is opening * - `0` means the tag is self-closing * - `-1` means the tag is closing **/ this.nesting = nesting; /** * Token#level -> Number * * nesting level, the same as `state.level` **/ this.level = 0; /** * Token#children -> Array * * An array of child nodes (inline and img tokens) **/ this.children = null; /** * Token#content -> String * * In a case of self-closing tag (code, html, fence, etc.), * it has contents of this tag. **/ this.content = ''; /** * Token#markup -> String * * '*' or '_' for emphasis, fence string for fence, etc. **/ this.markup = ''; /** * Token#info -> String * * Additional information: * * - Info string for "fence" tokens * - The value "auto" for autolink "link_open" and "link_close" tokens * - The string value of the item marker for ordered-list "list_item_open" tokens **/ this.info = ''; /** * Token#meta -> Object * * A place for plugins to store an arbitrary data **/ this.meta = null; /** * Token#block -> Boolean * * True for block-level tokens, false for inline tokens. * Used in renderer to calculate line breaks **/ this.block = false; /** * Token#hidden -> Boolean * * If it's true, ignore this element when rendering. Used for tight lists * to hide paragraphs. **/ this.hidden = false; } /** * Token.attrIndex(name) -> Number * * Search attribute index by name. **/ Token.prototype.attrIndex = function attrIndex (name) { if (!this.attrs) { return -1 } const attrs = this.attrs; for (let i = 0, len = attrs.length; i < len; i++) { if (attrs[i][0] === name) { return i } } return -1 }; /** * Token.attrPush(attrData) * * Add `[ name, value ]` attribute to list. Init attrs if necessary **/ Token.prototype.attrPush = function attrPush (attrData) { if (this.attrs) { this.attrs.push(attrData); } else { this.attrs = [attrData]; } }; /** * Token.attrSet(name, value) * * Set `name` attribute to `value`. Override old value if exists. **/ Token.prototype.attrSet = function attrSet (name, value) { const idx = this.attrIndex(name); const attrData = [name, value]; if (idx < 0) { this.attrPush(attrData); } else { this.attrs[idx] = attrData; } }; /** * Token.attrGet(name) * * Get the value of attribute `name`, or null if it does not exist. **/ Token.prototype.attrGet = function attrGet (name) { const idx = this.attrIndex(name); let value = null; if (idx >= 0) { value = this.attrs[idx][1]; } return value }; /** * Token.attrJoin(name, value) * * Join value to existing attribute via space. Or create new attribute if not * exists. Useful to operate with token classes. **/ Token.prototype.attrJoin = function attrJoin (name, value) { const idx = this.attrIndex(name); if (idx < 0) { this.attrPush([name, value]); } else { this.attrs[idx][1] = this.attrs[idx][1] + ' ' + value; } }; // Core state object // function StateCore (src, md, env) { this.src = src; this.env = env; this.tokens = []; this.inlineMode = false; this.md = md; // link to parser instance } // re-export Token class to use in core rules StateCore.prototype.Token = Token; // Normalize input string // https://spec.commonmark.org/0.29/#line-ending const NEWLINES_RE = /\r\n?|\n/g; const NULL_RE = /\0/g; function normalize (state) { let str; // Normalize newlines str = state.src.replace(NEWLINES_RE, '\n'); // Replace NULL characters str = str.replace(NULL_RE, '\uFFFD'); state.src = str; } function block (state) { let token; if (state.inlineMode) { token = new state.Token('inline', '', 0); token.content = state.src; token.map = [0, 1]; token.children = []; state.tokens.push(token); } else { state.md.block.parse(state.src, state.md, state.env, state.tokens); } } function inline (state) { const tokens = state.tokens; // Parse inlines for (let i = 0, l = tokens.length; i < l; i++) { const tok = tokens[i]; if (tok.type === 'inline') { state.md.inline.parse(tok.content, state.md, state.env, tok.children); } } } // Replace link-like texts with link nodes. // // Currently restricted by `md.validateLink()` to http/https/ftp // function isLinkOpen$1 (str) { return /^\s]/i.test(str) } function isLinkClose$1 (str) { return /^<\/a\s*>/i.test(str) } function linkify$1 (state) { const blockTokens = state.tokens; if (!state.md.options.linkify) { return } for (let j = 0, l = blockTokens.length; j < l; j++) { if (blockTokens[j].type !== 'inline' || !state.md.linkify.pretest(blockTokens[j].content)) { continue } let tokens = blockTokens[j].children; let htmlLinkLevel = 0; // We scan from the end, to keep position when new tags added. // Use reversed logic in links start/end match for (let i = tokens.length - 1; i >= 0; i--) { const currentToken = tokens[i]; // Skip content of markdown links if (currentToken.type === 'link_close') { i--; while (tokens[i].level !== currentToken.level && tokens[i].type !== 'link_open') { i--; } continue } // Skip content of html tag links if (currentToken.type === 'html_inline') { if (isLinkOpen$1(currentToken.content) && htmlLinkLevel > 0) { htmlLinkLevel--; } if (isLinkClose$1(currentToken.content)) { htmlLinkLevel++; } } if (htmlLinkLevel > 0) { continue } if (currentToken.type === 'text' && state.md.linkify.test(currentToken.content)) { const text = currentToken.content; let links = state.md.linkify.match(text); // Now split string to nodes const nodes = []; let level = currentToken.level; let lastPos = 0; // forbid escape sequence at the start of the string, // this avoids http\://example.com/ from being linkified as // http://example.com/ if (links.length > 0 && links[0].index === 0 && i > 0 && tokens[i - 1].type === 'text_special') { links = links.slice(1); } for (let ln = 0; ln < links.length; ln++) { const url = links[ln].url; const fullUrl = state.md.normalizeLink(url); if (!state.md.validateLink(fullUrl)) { continue } let urlText = links[ln].text; // Linkifier might send raw hostnames like "example.com", where url // starts with domain name. So we prepend http:// in those cases, // and remove it afterwards. // if (!links[ln].schema) { urlText = state.md.normalizeLinkText('http://' + urlText).replace(/^http:\/\//, ''); } else if (links[ln].schema === 'mailto:' && !/^mailto:/i.test(urlText)) { urlText = state.md.normalizeLinkText('mailto:' + urlText).replace(/^mailto:/, ''); } else { urlText = state.md.normalizeLinkText(urlText); } const pos = links[ln].index; if (pos > lastPos) { const token = new state.Token('text', '', 0); token.content = text.slice(lastPos, pos); token.level = level; nodes.push(token); } const token_o = new state.Token('link_open', 'a', 1); token_o.attrs = [['href', fullUrl]]; token_o.level = level++; token_o.markup = 'linkify'; token_o.info = 'auto'; nodes.push(token_o); const token_t = new state.Token('text', '', 0); token_t.content = urlText; token_t.level = level; nodes.push(token_t); const token_c = new state.Token('link_close', 'a', -1); token_c.level = --level; token_c.markup = 'linkify'; token_c.info = 'auto'; nodes.push(token_c); lastPos = links[ln].lastIndex; } if (lastPos < text.length) { const token = new state.Token('text', '', 0); token.content = text.slice(lastPos); token.level = level; nodes.push(token); } // replace current node blockTokens[j].children = tokens = arrayReplaceAt(tokens, i, nodes); } } } } // Simple typographic replacements // // (c) (C) → © // (tm) (TM) → ™ // (r) (R) → ® // +- → ± // ... → … (also ?.... → ?.., !.... → !..) // ???????? → ???, !!!!! → !!!, `,,` → `,` // -- → –, --- → — // // TODO: // - fractionals 1/2, 1/4, 3/4 -> ½, ¼, ¾ // - multiplications 2 x 4 -> 2 × 4 const RARE_RE = /\+-|\.\.|\?\?\?\?|!!!!|,,|--/; // Workaround for phantomjs - need regex without /g flag, // or root check will fail every second time const SCOPED_ABBR_TEST_RE = /\((c|tm|r)\)/i; const SCOPED_ABBR_RE = /\((c|tm|r)\)/ig; const SCOPED_ABBR = { c: '©', r: '®', tm: '™' }; function replaceFn (match, name) { return SCOPED_ABBR[name.toLowerCase()] } function replace_scoped (inlineTokens) { let inside_autolink = 0; for (let i = inlineTokens.length - 1; i >= 0; i--) { const token = inlineTokens[i]; if (token.type === 'text' && !inside_autolink) { token.content = token.content.replace(SCOPED_ABBR_RE, replaceFn); } if (token.type === 'link_open' && token.info === 'auto') { inside_autolink--; } if (token.type === 'link_close' && token.info === 'auto') { inside_autolink++; } } } function replace_rare (inlineTokens) { let inside_autolink = 0; for (let i = inlineTokens.length - 1; i >= 0; i--) { const token = inlineTokens[i]; if (token.type === 'text' && !inside_autolink) { if (RARE_RE.test(token.content)) { token.content = token.content .replace(/\+-/g, '±') // .., ..., ....... -> … // but ?..... & !..... -> ?.. & !.. .replace(/\.{2,}/g, '…').replace(/([?!])…/g, '$1..') .replace(/([?!]){4,}/g, '$1$1$1').replace(/,{2,}/g, ',') // em-dash .replace(/(^|[^-])---(?=[^-]|$)/mg, '$1\u2014') // en-dash .replace(/(^|\s)--(?=\s|$)/mg, '$1\u2013') .replace(/(^|[^-\s])--(?=[^-\s]|$)/mg, '$1\u2013'); } } if (token.type === 'link_open' && token.info === 'auto') { inside_autolink--; } if (token.type === 'link_close' && token.info === 'auto') { inside_autolink++; } } } function replace (state) { let blkIdx; if (!state.md.options.typographer) { return } for (blkIdx = state.tokens.length - 1; blkIdx >= 0; blkIdx--) { if (state.tokens[blkIdx].type !== 'inline') { continue } if (SCOPED_ABBR_TEST_RE.test(state.tokens[blkIdx].content)) { replace_scoped(state.tokens[blkIdx].children); } if (RARE_RE.test(state.tokens[blkIdx].content)) { replace_rare(state.tokens[blkIdx].children); } } } // Convert straight quotation marks to typographic ones // const QUOTE_TEST_RE = /['"]/; const QUOTE_RE = /['"]/g; const APOSTROPHE = '\u2019'; /* ’ */ function replaceAt (str, index, ch) { return str.slice(0, index) + ch + str.slice(index + 1) } function process_inlines (tokens, state) { let j; const stack = []; for (let i = 0; i < tokens.length; i++) { const token = tokens[i]; const thisLevel = tokens[i].level; for (j = stack.length - 1; j >= 0; j--) { if (stack[j].level <= thisLevel) { break } } stack.length = j + 1; if (token.type !== 'text') { continue } let text = token.content; let pos = 0; let max = text.length; /* eslint no-labels:0,block-scoped-var:0 */ OUTER: while (pos < max) { QUOTE_RE.lastIndex = pos; const t = QUOTE_RE.exec(text); if (!t) { break } let canOpen = true; let canClose = true; pos = t.index + 1; const isSingle = (t[0] === "'"); // Find previous character, // default to space if it's the beginning of the line // let lastChar = 0x20; if (t.index - 1 >= 0) { lastChar = text.charCodeAt(t.index - 1); } else { for (j = i - 1; j >= 0; j--) { if (tokens[j].type === 'softbreak' || tokens[j].type === 'hardbreak') break // lastChar defaults to 0x20 if (!tokens[j].content) continue // should skip all tokens except 'text', 'html_inline' or 'code_inline' lastChar = tokens[j].content.charCodeAt(tokens[j].content.length - 1); break } } // Find next character, // default to space if it's the end of the line // let nextChar = 0x20; if (pos < max) { nextChar = text.charCodeAt(pos); } else { for (j = i + 1; j < tokens.length; j++) { if (tokens[j].type === 'softbreak' || tokens[j].type === 'hardbreak') break // nextChar defaults to 0x20 if (!tokens[j].content) continue // should skip all tokens except 'text', 'html_inline' or 'code_inline' nextChar = tokens[j].content.charCodeAt(0); break } } const isLastPunctChar = isMdAsciiPunct(lastChar) || isPunctChar(String.fromCharCode(lastChar)); const isNextPunctChar = isMdAsciiPunct(nextChar) || isPunctChar(String.fromCharCode(nextChar)); const isLastWhiteSpace = isWhiteSpace(lastChar); const isNextWhiteSpace = isWhiteSpace(nextChar); if (isNextWhiteSpace) { canOpen = false; } else if (isNextPunctChar) { if (!(isLastWhiteSpace || isLastPunctChar)) { canOpen = false; } } if (isLastWhiteSpace) { canClose = false; } else if (isLastPunctChar) { if (!(isNextWhiteSpace || isNextPunctChar)) { canClose = false; } } if (nextChar === 0x22 /* " */ && t[0] === '"') { if (lastChar >= 0x30 /* 0 */ && lastChar <= 0x39 /* 9 */) { // special case: 1"" - count first quote as an inch canClose = canOpen = false; } } if (canOpen && canClose) { // Replace quotes in the middle of punctuation sequence, but not // in the middle of the words, i.e.: // // 1. foo " bar " baz - not replaced // 2. foo-"-bar-"-baz - replaced // 3. foo"bar"baz - not replaced // canOpen = isLastPunctChar; canClose = isNextPunctChar; } if (!canOpen && !canClose) { // middle of word if (isSingle) { token.content = replaceAt(token.content, t.index, APOSTROPHE); } continue } if (canClose) { // this could be a closing quote, rewind the stack to get a match for (j = stack.length - 1; j >= 0; j--) { let item = stack[j]; if (stack[j].level < thisLevel) { break } if (item.single === isSingle && stack[j].level === thisLevel) { item = stack[j]; let openQuote; let closeQuote; if (isSingle) { openQuote = state.md.options.quotes[2]; closeQuote = state.md.options.quotes[3]; } else { openQuote = state.md.options.quotes[0]; closeQuote = state.md.options.quotes[1]; } // replace token.content *before* tokens[item.token].content, // because, if they are pointing at the same token, replaceAt // could mess up indices when quote length != 1 token.content = replaceAt(token.content, t.index, closeQuote); tokens[item.token].content = replaceAt( tokens[item.token].content, item.pos, openQuote); pos += closeQuote.length - 1; if (item.token === i) { pos += openQuote.length - 1; } text = token.content; max = text.length; stack.length = j; continue OUTER } } } if (canOpen) { stack.push({ token: i, pos: t.index, single: isSingle, level: thisLevel }); } else if (canClose && isSingle) { token.content = replaceAt(token.content, t.index, APOSTROPHE); } } } } function smartquotes (state) { /* eslint max-depth:0 */ if (!state.md.options.typographer) { return } for (let blkIdx = state.tokens.length - 1; blkIdx >= 0; blkIdx--) { if (state.tokens[blkIdx].type !== 'inline' || !QUOTE_TEST_RE.test(state.tokens[blkIdx].content)) { continue } process_inlines(state.tokens[blkIdx].children, state); } } // Join raw text tokens with the rest of the text // // This is set as a separate rule to provide an opportunity for plugins // to run text replacements after text join, but before escape join. // // For example, `\:)` shouldn't be replaced with an emoji. // function text_join$1 (state) { let curr, last; const blockTokens = state.tokens; const l = blockTokens.length; for (let j = 0; j < l; j++) { if (blockTokens[j].type !== 'inline') continue const tokens = blockTokens[j].children; const max = tokens.length; for (curr = 0; curr < max; curr++) { if (tokens[curr].type === 'text_special') { tokens[curr].type = 'text'; } } for (curr = last = 0; curr < max; curr++) { if (tokens[curr].type === 'text' && curr + 1 < max && tokens[curr + 1].type === 'text') { // collapse two adjacent text nodes tokens[curr + 1].content = tokens[curr].content + tokens[curr + 1].content; } else { if (curr !== last) { tokens[last] = tokens[curr]; } last++; } } if (curr !== last) { tokens.length = last; } } } /** internal * class Core * * Top-level rules executor. Glues block/inline parsers and does intermediate * transformations. **/ const _rules$2 = [ ['normalize', normalize], ['block', block], ['inline', inline], ['linkify', linkify$1], ['replacements', replace], ['smartquotes', smartquotes], // `text_join` finds `text_special` tokens (for escape sequences) // and joins them with the rest of the text ['text_join', text_join$1] ]; /** * new Core() **/ function Core () { /** * Core#ruler -> Ruler * * [[Ruler]] instance. Keep configuration of core rules. **/ this.ruler = new Ruler(); for (let i = 0; i < _rules$2.length; i++) { this.ruler.push(_rules$2[i][0], _rules$2[i][1]); } } /** * Core.process(state) * * Executes core chain rules. **/ Core.prototype.process = function (state) { const rules = this.ruler.getRules(''); for (let i = 0, l = rules.length; i < l; i++) { rules[i](state); } }; Core.prototype.State = StateCore; // Parser state class function StateBlock (src, md, env, tokens) { this.src = src; // link to parser instance this.md = md; this.env = env; // // Internal state vartiables // this.tokens = tokens; this.bMarks = []; // line begin offsets for fast jumps this.eMarks = []; // line end offsets for fast jumps this.tShift = []; // offsets of the first non-space characters (tabs not expanded) this.sCount = []; // indents for each line (tabs expanded) // An amount of virtual spaces (tabs expanded) between beginning // of each line (bMarks) and real beginning of that line. // // It exists only as a hack because blockquotes override bMarks // losing information in the process. // // It's used only when expanding tabs, you can think about it as // an initial tab length, e.g. bsCount=21 applied to string `\t123` // means first tab should be expanded to 4-21%4 === 3 spaces. // this.bsCount = []; // block parser variables // required block content indent (for example, if we are // inside a list, it would be positioned after list marker) this.blkIndent = 0; this.line = 0; // line index in src this.lineMax = 0; // lines count this.tight = false; // loose/tight mode for lists this.ddIndent = -1; // indent of the current dd block (-1 if there isn't any) this.listIndent = -1; // indent of the current list block (-1 if there isn't any) // can be 'blockquote', 'list', 'root', 'paragraph' or 'reference' // used in lists to determine if they interrupt a paragraph this.parentType = 'root'; this.level = 0; // Create caches // Generate markers. const s = this.src; for (let start = 0, pos = 0, indent = 0, offset = 0, len = s.length, indent_found = false; pos < len; pos++) { const ch = s.charCodeAt(pos); if (!indent_found) { if (isSpace(ch)) { indent++; if (ch === 0x09) { offset += 4 - offset % 4; } else { offset++; } continue } else { indent_found = true; } } if (ch === 0x0A || pos === len - 1) { if (ch !== 0x0A) { pos++; } this.bMarks.push(start); this.eMarks.push(pos); this.tShift.push(indent); this.sCount.push(offset); this.bsCount.push(0); indent_found = false; indent = 0; offset = 0; start = pos + 1; } } // Push fake entry to simplify cache bounds checks this.bMarks.push(s.length); this.eMarks.push(s.length); this.tShift.push(0); this.sCount.push(0); this.bsCount.push(0); this.lineMax = this.bMarks.length - 1; // don't count last fake line } // Push new token to "stream". // StateBlock.prototype.push = function (type, tag, nesting) { const token = new Token(type, tag, nesting); token.block = true; if (nesting < 0) this.level--; // closing tag token.level = this.level; if (nesting > 0) this.level++; // opening tag this.tokens.push(token); return token }; StateBlock.prototype.isEmpty = function isEmpty (line) { return this.bMarks[line] + this.tShift[line] >= this.eMarks[line] }; StateBlock.prototype.skipEmptyLines = function skipEmptyLines (from) { for (let max = this.lineMax; from < max; from++) { if (this.bMarks[from] + this.tShift[from] < this.eMarks[from]) { break } } return from }; // Skip spaces from given position. StateBlock.prototype.skipSpaces = function skipSpaces (pos) { for (let max = this.src.length; pos < max; pos++) { const ch = this.src.charCodeAt(pos); if (!isSpace(ch)) { break } } return pos }; // Skip spaces from given position in reverse. StateBlock.prototype.skipSpacesBack = function skipSpacesBack (pos, min) { if (pos <= min) { return pos } while (pos > min) { if (!isSpace(this.src.charCodeAt(--pos))) { return pos + 1 } } return pos }; // Skip char codes from given position StateBlock.prototype.skipChars = function skipChars (pos, code) { for (let max = this.src.length; pos < max; pos++) { if (this.src.charCodeAt(pos) !== code) { break } } return pos }; // Skip char codes reverse from given position - 1 StateBlock.prototype.skipCharsBack = function skipCharsBack (pos, code, min) { if (pos <= min) { return pos } while (pos > min) { if (code !== this.src.charCodeAt(--pos)) { return pos + 1 } } return pos }; // cut lines range from source. StateBlock.prototype.getLines = function getLines (begin, end, indent, keepLastLF) { if (begin >= end) { return '' } const queue = new Array(end - begin); for (let i = 0, line = begin; line < end; line++, i++) { let lineIndent = 0; const lineStart = this.bMarks[line]; let first = lineStart; let last; if (line + 1 < end || keepLastLF) { // No need for bounds check because we have fake entry on tail. last = this.eMarks[line] + 1; } else { last = this.eMarks[line]; } while (first < last && lineIndent < indent) { const ch = this.src.charCodeAt(first); if (isSpace(ch)) { if (ch === 0x09) { lineIndent += 4 - (lineIndent + this.bsCount[line]) % 4; } else { lineIndent++; } } else if (first - lineStart < this.tShift[line]) { // patched tShift masked characters to look like spaces (blockquotes, list markers) lineIndent++; } else { break } first++; } if (lineIndent > indent) { // partially expanding tabs in code blocks, e.g '\t\tfoobar' // with indent=2 becomes ' \tfoobar' queue[i] = new Array(lineIndent - indent + 1).join(' ') + this.src.slice(first, last); } else { queue[i] = this.src.slice(first, last); } } return queue.join('') }; // re-export Token class to use in block rules StateBlock.prototype.Token = Token; // GFM table, https://github.github.com/gfm/#tables-extension- // Limit the amount of empty autocompleted cells in a table, // see https://github.com/markdown-it/markdown-it/issues/1000, // // Both pulldown-cmark and commonmark-hs limit the number of cells this way to ~200k. // We set it to 65k, which can expand user input by a factor of x370 // (256x256 square is 1.8kB expanded into 650kB). const MAX_AUTOCOMPLETED_CELLS = 0x10000; function getLine (state, line) { const pos = state.bMarks[line] + state.tShift[line]; const max = state.eMarks[line]; return state.src.slice(pos, max) } function escapedSplit (str) { const result = []; const max = str.length; let pos = 0; let ch = str.charCodeAt(pos); let isEscaped = false; let lastPos = 0; let current = ''; while (pos < max) { if (ch === 0x7c/* | */) { if (!isEscaped) { // pipe separating cells, '|' result.push(current + str.substring(lastPos, pos)); current = ''; lastPos = pos + 1; } else { // escaped pipe, '\|' current += str.substring(lastPos, pos - 1); lastPos = pos; } } isEscaped = (ch === 0x5c/* \ */); pos++; ch = str.charCodeAt(pos); } result.push(current + str.substring(lastPos)); return result } function table (state, startLine, endLine, silent) { // should have at least two lines if (startLine + 2 > endLine) { return false } let nextLine = startLine + 1; if (state.sCount[nextLine] < state.blkIndent) { return false } // if it's indented more than 3 spaces, it should be a code block if (state.sCount[nextLine] - state.blkIndent >= 4) { return false } // first character of the second line should be '|', '-', ':', // and no other characters are allowed but spaces; // basically, this is the equivalent of /^[-:|][-:|\s]*$/ regexp let pos = state.bMarks[nextLine] + state.tShift[nextLine]; if (pos >= state.eMarks[nextLine]) { return false } const firstCh = state.src.charCodeAt(pos++); if (firstCh !== 0x7C/* | */ && firstCh !== 0x2D/* - */ && firstCh !== 0x3A/* : */) { return false } if (pos >= state.eMarks[nextLine]) { return false } const secondCh = state.src.charCodeAt(pos++); if (secondCh !== 0x7C/* | */ && secondCh !== 0x2D/* - */ && secondCh !== 0x3A/* : */ && !isSpace(secondCh)) { return false } // if first character is '-', then second character must not be a space // (due to parsing ambiguity with list) if (firstCh === 0x2D/* - */ && isSpace(secondCh)) { return false } while (pos < state.eMarks[nextLine]) { const ch = state.src.charCodeAt(pos); if (ch !== 0x7C/* | */ && ch !== 0x2D/* - */ && ch !== 0x3A/* : */ && !isSpace(ch)) { return false } pos++; } let lineText = getLine(state, startLine + 1); let columns = lineText.split('|'); const aligns = []; for (let i = 0; i < columns.length; i++) { const t = columns[i].trim(); if (!t) { // allow empty columns before and after table, but not in between columns; // e.g. allow ` |---| `, disallow ` ---||--- ` if (i === 0 || i === columns.length - 1) { continue } else { return false } } if (!/^:?-+:?$/.test(t)) { return false } if (t.charCodeAt(t.length - 1) === 0x3A/* : */) { aligns.push(t.charCodeAt(0) === 0x3A/* : */ ? 'center' : 'right'); } else if (t.charCodeAt(0) === 0x3A/* : */) { aligns.push('left'); } else { aligns.push(''); } } lineText = getLine(state, startLine).trim(); if (lineText.indexOf('|') === -1) { return false } if (state.sCount[startLine] - state.blkIndent >= 4) { return false } columns = escapedSplit(lineText); if (columns.length && columns[0] === '') columns.shift(); if (columns.length && columns[columns.length - 1] === '') columns.pop(); // header row will define an amount of columns in the entire table, // and align row should be exactly the same (the rest of the rows can differ) const columnCount = columns.length; if (columnCount === 0 || columnCount !== aligns.length) { return false } if (silent) { return true } const oldParentType = state.parentType; state.parentType = 'table'; // use 'blockquote' lists for termination because it's // the most similar to tables const terminatorRules = state.md.block.ruler.getRules('blockquote'); const token_to = state.push('table_open', 'table', 1); const tableLines = [startLine, 0]; token_to.map = tableLines; const token_tho = state.push('thead_open', 'thead', 1); token_tho.map = [startLine, startLine + 1]; const token_htro = state.push('tr_open', 'tr', 1); token_htro.map = [startLine, startLine + 1]; for (let i = 0; i < columns.length; i++) { const token_ho = state.push('th_open', 'th', 1); if (aligns[i]) { token_ho.attrs = [['style', 'text-align:' + aligns[i]]]; } const token_il = state.push('inline', '', 0); token_il.content = columns[i].trim(); token_il.children = []; state.push('th_close', 'th', -1); } state.push('tr_close', 'tr', -1); state.push('thead_close', 'thead', -1); let tbodyLines; let autocompletedCells = 0; for (nextLine = startLine + 2; nextLine < endLine; nextLine++) { if (state.sCount[nextLine] < state.blkIndent) { break } let terminate = false; for (let i = 0, l = terminatorRules.length; i < l; i++) { if (terminatorRules[i](state, nextLine, endLine, true)) { terminate = true; break } } if (terminate) { break } lineText = getLine(state, nextLine).trim(); if (!lineText) { break } if (state.sCount[nextLine] - state.blkIndent >= 4) { break } columns = escapedSplit(lineText); if (columns.length && columns[0] === '') columns.shift(); if (columns.length && columns[columns.length - 1] === '') columns.pop(); // note: autocomplete count can be negative if user specifies more columns than header, // but that does not affect intended use (which is limiting expansion) autocompletedCells += columnCount - columns.length; if (autocompletedCells > MAX_AUTOCOMPLETED_CELLS) { break } if (nextLine === startLine + 2) { const token_tbo = state.push('tbody_open', 'tbody', 1); token_tbo.map = tbodyLines = [startLine + 2, 0]; } const token_tro = state.push('tr_open', 'tr', 1); token_tro.map = [nextLine, nextLine + 1]; for (let i = 0; i < columnCount; i++) { const token_tdo = state.push('td_open', 'td', 1); if (aligns[i]) { token_tdo.attrs = [['style', 'text-align:' + aligns[i]]]; } const token_il = state.push('inline', '', 0); token_il.content = columns[i] ? columns[i].trim() : ''; token_il.children = []; state.push('td_close', 'td', -1); } state.push('tr_close', 'tr', -1); } if (tbodyLines) { state.push('tbody_close', 'tbody', -1); tbodyLines[1] = nextLine; } state.push('table_close', 'table', -1); tableLines[1] = nextLine; state.parentType = oldParentType; state.line = nextLine; return true } // Code block (4 spaces padded) function code (state, startLine, endLine/*, silent */) { if (state.sCount[startLine] - state.blkIndent < 4) { return false } let nextLine = startLine + 1; let last = nextLine; while (nextLine < endLine) { if (state.isEmpty(nextLine)) { nextLine++; continue } if (state.sCount[nextLine] - state.blkIndent >= 4) { nextLine++; last = nextLine; continue } break } state.line = last; const token = state.push('code_block', 'code', 0); token.content = state.getLines(startLine, last, 4 + state.blkIndent, false) + '\n'; token.map = [startLine, state.line]; return true } // fences (``` lang, ~~~ lang) function fence (state, startLine, endLine, silent) { let pos = state.bMarks[startLine] + state.tShift[startLine]; let max = state.eMarks[startLine]; // if it's indented more than 3 spaces, it should be a code block if (state.sCount[startLine] - state.blkIndent >= 4) { return false } if (pos + 3 > max) { return false } const marker = state.src.charCodeAt(pos); if (marker !== 0x7E/* ~ */ && marker !== 0x60 /* ` */) { return false } // scan marker length let mem = pos; pos = state.skipChars(pos, marker); let len = pos - mem; if (len < 3) { return false } const markup = state.src.slice(mem, pos); const params = state.src.slice(pos, max); if (marker === 0x60 /* ` */) { if (params.indexOf(String.fromCharCode(marker)) >= 0) { return false } } // Since start is found, we can report success here in validation mode if (silent) { return true } // search end of block let nextLine = startLine; let haveEndMarker = false; for (;;) { nextLine++; if (nextLine >= endLine) { // unclosed block should be autoclosed by end of document. // also block seems to be autoclosed by end of parent break } pos = mem = state.bMarks[nextLine] + state.tShift[nextLine]; max = state.eMarks[nextLine]; if (pos < max && state.sCount[nextLine] < state.blkIndent) { // non-empty line with negative indent should stop the list: // - ``` // test break } if (state.src.charCodeAt(pos) !== marker) { continue } if (state.sCount[nextLine] - state.blkIndent >= 4) { // closing fence should be indented less than 4 spaces continue } pos = state.skipChars(pos, marker); // closing code fence must be at least as long as the opening one if (pos - mem < len) { continue } // make sure tail has spaces only pos = state.skipSpaces(pos); if (pos < max) { continue } haveEndMarker = true; // found! break } // If a fence has heading spaces, they should be removed from its inner block len = state.sCount[startLine]; state.line = nextLine + (haveEndMarker ? 1 : 0); const token = state.push('fence', 'code', 0); token.info = params; token.content = state.getLines(startLine + 1, nextLine, len, true); token.markup = markup; token.map = [startLine, state.line]; return true } // Block quotes function blockquote (state, startLine, endLine, silent) { let pos = state.bMarks[startLine] + state.tShift[startLine]; let max = state.eMarks[startLine]; const oldLineMax = state.lineMax; // if it's indented more than 3 spaces, it should be a code block if (state.sCount[startLine] - state.blkIndent >= 4) { return false } // check the block quote marker if (state.src.charCodeAt(pos) !== 0x3E/* > */) { return false } // we know that it's going to be a valid blockquote, // so no point trying to find the end of it in silent mode if (silent) { return true } const oldBMarks = []; const oldBSCount = []; const oldSCount = []; const oldTShift = []; const terminatorRules = state.md.block.ruler.getRules('blockquote'); const oldParentType = state.parentType; state.parentType = 'blockquote'; let lastLineEmpty = false; let nextLine; // Search the end of the block // // Block ends with either: // 1. an empty line outside: // ``` // > test // // ``` // 2. an empty line inside: // ``` // > // test // ``` // 3. another tag: // ``` // > test // - - - // ``` for (nextLine = startLine; nextLine < endLine; nextLine++) { // check if it's outdented, i.e. it's inside list item and indented // less than said list item: // // ``` // 1. anything // > current blockquote // 2. checking this line // ``` const isOutdented = state.sCount[nextLine] < state.blkIndent; pos = state.bMarks[nextLine] + state.tShift[nextLine]; max = state.eMarks[nextLine]; if (pos >= max) { // Case 1: line is not inside the blockquote, and this line is empty. break } if (state.src.charCodeAt(pos++) === 0x3E/* > */ && !isOutdented) { // This line is inside the blockquote. // set offset past spaces and ">" let initial = state.sCount[nextLine] + 1; let spaceAfterMarker; let adjustTab; // skip one optional space after '>' if (state.src.charCodeAt(pos) === 0x20 /* space */) { // ' > test ' // ^ -- position start of line here: pos++; initial++; adjustTab = false; spaceAfterMarker = true; } else if (state.src.charCodeAt(pos) === 0x09 /* tab */) { spaceAfterMarker = true; if ((state.bsCount[nextLine] + initial) % 4 === 3) { // ' >\t test ' // ^ -- position start of line here (tab has width===1) pos++; initial++; adjustTab = false; } else { // ' >\t test ' // ^ -- position start of line here + shift bsCount slightly // to make extra space appear adjustTab = true; } } else { spaceAfterMarker = false; } let offset = initial; oldBMarks.push(state.bMarks[nextLine]); state.bMarks[nextLine] = pos; while (pos < max) { const ch = state.src.charCodeAt(pos); if (isSpace(ch)) { if (ch === 0x09) { offset += 4 - (offset + state.bsCount[nextLine] + (adjustTab ? 1 : 0)) % 4; } else { offset++; } } else { break } pos++; } lastLineEmpty = pos >= max; oldBSCount.push(state.bsCount[nextLine]); state.bsCount[nextLine] = state.sCount[nextLine] + 1 + (spaceAfterMarker ? 1 : 0); oldSCount.push(state.sCount[nextLine]); state.sCount[nextLine] = offset - initial; oldTShift.push(state.tShift[nextLine]); state.tShift[nextLine] = pos - state.bMarks[nextLine]; continue } // Case 2: line is not inside the blockquote, and the last line was empty. if (lastLineEmpty) { break } // Case 3: another tag found. let terminate = false; for (let i = 0, l = terminatorRules.length; i < l; i++) { if (terminatorRules[i](state, nextLine, endLine, true)) { terminate = true; break } } if (terminate) { // Quirk to enforce "hard termination mode" for paragraphs; // normally if you call `tokenize(state, startLine, nextLine)`, // paragraphs will look below nextLine for paragraph continuation, // but if blockquote is terminated by another tag, they shouldn't state.lineMax = nextLine; if (state.blkIndent !== 0) { // state.blkIndent was non-zero, we now set it to zero, // so we need to re-calculate all offsets to appear as // if indent wasn't changed oldBMarks.push(state.bMarks[nextLine]); oldBSCount.push(state.bsCount[nextLine]); oldTShift.push(state.tShift[nextLine]); oldSCount.push(state.sCount[nextLine]); state.sCount[nextLine] -= state.blkIndent; } break } oldBMarks.push(state.bMarks[nextLine]); oldBSCount.push(state.bsCount[nextLine]); oldTShift.push(state.tShift[nextLine]); oldSCount.push(state.sCount[nextLine]); // A negative indentation means that this is a paragraph continuation // state.sCount[nextLine] = -1; } const oldIndent = state.blkIndent; state.blkIndent = 0; const token_o = state.push('blockquote_open', 'blockquote', 1); token_o.markup = '>'; const lines = [startLine, 0]; token_o.map = lines; state.md.block.tokenize(state, startLine, nextLine); const token_c = state.push('blockquote_close', 'blockquote', -1); token_c.markup = '>'; state.lineMax = oldLineMax; state.parentType = oldParentType; lines[1] = state.line; // Restore original tShift; this might not be necessary since the parser // has already been here, but just to make sure we can do that. for (let i = 0; i < oldTShift.length; i++) { state.bMarks[i + startLine] = oldBMarks[i]; state.tShift[i + startLine] = oldTShift[i]; state.sCount[i + startLine] = oldSCount[i]; state.bsCount[i + startLine] = oldBSCount[i]; } state.blkIndent = oldIndent; return true } // Horizontal rule function hr (state, startLine, endLine, silent) { const max = state.eMarks[startLine]; // if it's indented more than 3 spaces, it should be a code block if (state.sCount[startLine] - state.blkIndent >= 4) { return false } let pos = state.bMarks[startLine] + state.tShift[startLine]; const marker = state.src.charCodeAt(pos++); // Check hr marker if (marker !== 0x2A/* * */ && marker !== 0x2D/* - */ && marker !== 0x5F/* _ */) { return false } // markers can be mixed with spaces, but there should be at least 3 of them let cnt = 1; while (pos < max) { const ch = state.src.charCodeAt(pos++); if (ch !== marker && !isSpace(ch)) { return false } if (ch === marker) { cnt++; } } if (cnt < 3) { return false } if (silent) { return true } state.line = startLine + 1; const token = state.push('hr', 'hr', 0); token.map = [startLine, state.line]; token.markup = Array(cnt + 1).join(String.fromCharCode(marker)); return true } // Lists // Search `[-+*][\n ]`, returns next pos after marker on success // or -1 on fail. function skipBulletListMarker (state, startLine) { const max = state.eMarks[startLine]; let pos = state.bMarks[startLine] + state.tShift[startLine]; const marker = state.src.charCodeAt(pos++); // Check bullet if (marker !== 0x2A/* * */ && marker !== 0x2D/* - */ && marker !== 0x2B/* + */) { return -1 } if (pos < max) { const ch = state.src.charCodeAt(pos); if (!isSpace(ch)) { // " -test " - is not a list item return -1 } } return pos } // Search `\d+[.)][\n ]`, returns next pos after marker on success // or -1 on fail. function skipOrderedListMarker (state, startLine) { const start = state.bMarks[startLine] + state.tShift[startLine]; const max = state.eMarks[startLine]; let pos = start; // List marker should have at least 2 chars (digit + dot) if (pos + 1 >= max) { return -1 } let ch = state.src.charCodeAt(pos++); if (ch < 0x30/* 0 */ || ch > 0x39/* 9 */) { return -1 } for (;;) { // EOL -> fail if (pos >= max) { return -1 } ch = state.src.charCodeAt(pos++); if (ch >= 0x30/* 0 */ && ch <= 0x39/* 9 */) { // List marker should have no more than 9 digits // (prevents integer overflow in browsers) if (pos - start >= 10) { return -1 } continue } // found valid marker if (ch === 0x29/* ) */ || ch === 0x2e/* . */) { break } return -1 } if (pos < max) { ch = state.src.charCodeAt(pos); if (!isSpace(ch)) { // " 1.test " - is not a list item return -1 } } return pos } function markTightParagraphs (state, idx) { const level = state.level + 2; for (let i = idx + 2, l = state.tokens.length - 2; i < l; i++) { if (state.tokens[i].level === level && state.tokens[i].type === 'paragraph_open') { state.tokens[i + 2].hidden = true; state.tokens[i].hidden = true; i += 2; } } } function list (state, startLine, endLine, silent) { let max, pos, start, token; let nextLine = startLine; let tight = true; // if it's indented more than 3 spaces, it should be a code block if (state.sCount[nextLine] - state.blkIndent >= 4) { return false } // Special case: // - item 1 // - item 2 // - item 3 // - item 4 // - this one is a paragraph continuation if (state.listIndent >= 0 && state.sCount[nextLine] - state.listIndent >= 4 && state.sCount[nextLine] < state.blkIndent) { return false } let isTerminatingParagraph = false; // limit conditions when list can interrupt // a paragraph (validation mode only) if (silent && state.parentType === 'paragraph') { // Next list item should still terminate previous list item; // // This code can fail if plugins use blkIndent as well as lists, // but I hope the spec gets fixed long before that happens. // if (state.sCount[nextLine] >= state.blkIndent) { isTerminatingParagraph = true; } } // Detect list type and position after marker let isOrdered; let markerValue; let posAfterMarker; if ((posAfterMarker = skipOrderedListMarker(state, nextLine)) >= 0) { isOrdered = true; start = state.bMarks[nextLine] + state.tShift[nextLine]; markerValue = Number(state.src.slice(start, posAfterMarker - 1)); // If we're starting a new ordered list right after // a paragraph, it should start with 1. if (isTerminatingParagraph && markerValue !== 1) return false } else if ((posAfterMarker = skipBulletListMarker(state, nextLine)) >= 0) { isOrdered = false; } else { return false } // If we're starting a new unordered list right after // a paragraph, first line should not be empty. if (isTerminatingParagraph) { if (state.skipSpaces(posAfterMarker) >= state.eMarks[nextLine]) return false } // For validation mode we can terminate immediately if (silent) { return true } // We should terminate list on style change. Remember first one to compare. const markerCharCode = state.src.charCodeAt(posAfterMarker - 1); // Start list const listTokIdx = state.tokens.length; if (isOrdered) { token = state.push('ordered_list_open', 'ol', 1); if (markerValue !== 1) { token.attrs = [['start', markerValue]]; } } else { token = state.push('bullet_list_open', 'ul', 1); } const listLines = [nextLine, 0]; token.map = listLines; token.markup = String.fromCharCode(markerCharCode); // // Iterate list items // let prevEmptyEnd = false; const terminatorRules = state.md.block.ruler.getRules('list'); const oldParentType = state.parentType; state.parentType = 'list'; while (nextLine < endLine) { pos = posAfterMarker; max = state.eMarks[nextLine]; const initial = state.sCount[nextLine] + posAfterMarker - (state.bMarks[nextLine] + state.tShift[nextLine]); let offset = initial; while (pos < max) { const ch = state.src.charCodeAt(pos); if (ch === 0x09) { offset += 4 - (offset + state.bsCount[nextLine]) % 4; } else if (ch === 0x20) { offset++; } else { break } pos++; } const contentStart = pos; let indentAfterMarker; if (contentStart >= max) { // trimming space in "- \n 3" case, indent is 1 here indentAfterMarker = 1; } else { indentAfterMarker = offset - initial; } // If we have more than 4 spaces, the indent is 1 // (the rest is just indented code block) if (indentAfterMarker > 4) { indentAfterMarker = 1; } // " - test" // ^^^^^ - calculating total length of this thing const indent = initial + indentAfterMarker; // Run subparser & write tokens token = state.push('list_item_open', 'li', 1); token.markup = String.fromCharCode(markerCharCode); const itemLines = [nextLine, 0]; token.map = itemLines; if (isOrdered) { token.info = state.src.slice(start, posAfterMarker - 1); } // change current state, then restore it after parser subcall const oldTight = state.tight; const oldTShift = state.tShift[nextLine]; const oldSCount = state.sCount[nextLine]; // - example list // ^ listIndent position will be here // ^ blkIndent position will be here // const oldListIndent = state.listIndent; state.listIndent = state.blkIndent; state.blkIndent = indent; state.tight = true; state.tShift[nextLine] = contentStart - state.bMarks[nextLine]; state.sCount[nextLine] = offset; if (contentStart >= max && state.isEmpty(nextLine + 1)) { // workaround for this case // (list item is empty, list terminates before "foo"): // ~~~~~~~~ // - // // foo // ~~~~~~~~ state.line = Math.min(state.line + 2, endLine); } else { state.md.block.tokenize(state, nextLine, endLine, true); } // If any of list item is tight, mark list as tight if (!state.tight || prevEmptyEnd) { tight = false; } // Item become loose if finish with empty line, // but we should filter last element, because it means list finish prevEmptyEnd = (state.line - nextLine) > 1 && state.isEmpty(state.line - 1); state.blkIndent = state.listIndent; state.listIndent = oldListIndent; state.tShift[nextLine] = oldTShift; state.sCount[nextLine] = oldSCount; state.tight = oldTight; token = state.push('list_item_close', 'li', -1); token.markup = String.fromCharCode(markerCharCode); nextLine = state.line; itemLines[1] = nextLine; if (nextLine >= endLine) { break } // // Try to check if list is terminated or continued. // if (state.sCount[nextLine] < state.blkIndent) { break } // if it's indented more than 3 spaces, it should be a code block if (state.sCount[nextLine] - state.blkIndent >= 4) { break } // fail if terminating block found let terminate = false; for (let i = 0, l = terminatorRules.length; i < l; i++) { if (terminatorRules[i](state, nextLine, endLine, true)) { terminate = true; break } } if (terminate) { break } // fail if list has another type if (isOrdered) { posAfterMarker = skipOrderedListMarker(state, nextLine); if (posAfterMarker < 0) { break } start = state.bMarks[nextLine] + state.tShift[nextLine]; } else { posAfterMarker = skipBulletListMarker(state, nextLine); if (posAfterMarker < 0) { break } } if (markerCharCode !== state.src.charCodeAt(posAfterMarker - 1)) { break } } // Finalize list if (isOrdered) { token = state.push('ordered_list_close', 'ol', -1); } else { token = state.push('bullet_list_close', 'ul', -1); } token.markup = String.fromCharCode(markerCharCode); listLines[1] = nextLine; state.line = nextLine; state.parentType = oldParentType; // mark paragraphs tight if needed if (tight) { markTightParagraphs(state, listTokIdx); } return true } function reference (state, startLine, _endLine, silent) { let pos = state.bMarks[startLine] + state.tShift[startLine]; let max = state.eMarks[startLine]; let nextLine = startLine + 1; // if it's indented more than 3 spaces, it should be a code block if (state.sCount[startLine] - state.blkIndent >= 4) { return false } if (state.src.charCodeAt(pos) !== 0x5B/* [ */) { return false } function getNextLine (nextLine) { const endLine = state.lineMax; if (nextLine >= endLine || state.isEmpty(nextLine)) { // empty line or end of input return null } let isContinuation = false; // this would be a code block normally, but after paragraph // it's considered a lazy continuation regardless of what's there if (state.sCount[nextLine] - state.blkIndent > 3) { isContinuation = true; } // quirk for blockquotes, this line should already be checked by that rule if (state.sCount[nextLine] < 0) { isContinuation = true; } if (!isContinuation) { const terminatorRules = state.md.block.ruler.getRules('reference'); const oldParentType = state.parentType; state.parentType = 'reference'; // Some tags can terminate paragraph without empty line. let terminate = false; for (let i = 0, l = terminatorRules.length; i < l; i++) { if (terminatorRules[i](state, nextLine, endLine, true)) { terminate = true; break } } state.parentType = oldParentType; if (terminate) { // terminated by another block return null } } const pos = state.bMarks[nextLine] + state.tShift[nextLine]; const max = state.eMarks[nextLine]; // max + 1 explicitly includes the newline return state.src.slice(pos, max + 1) } let str = state.src.slice(pos, max + 1); max = str.length; let labelEnd = -1; for (pos = 1; pos < max; pos++) { const ch = str.charCodeAt(pos); if (ch === 0x5B /* [ */) { return false } else if (ch === 0x5D /* ] */) { labelEnd = pos; break } else if (ch === 0x0A /* \n */) { const lineContent = getNextLine(nextLine); if (lineContent !== null) { str += lineContent; max = str.length; nextLine++; } } else if (ch === 0x5C /* \ */) { pos++; if (pos < max && str.charCodeAt(pos) === 0x0A) { const lineContent = getNextLine(nextLine); if (lineContent !== null) { str += lineContent; max = str.length; nextLine++; } } } } if (labelEnd < 0 || str.charCodeAt(labelEnd + 1) !== 0x3A/* : */) { return false } // [label]: destination 'title' // ^^^ skip optional whitespace here for (pos = labelEnd + 2; pos < max; pos++) { const ch = str.charCodeAt(pos); if (ch === 0x0A) { const lineContent = getNextLine(nextLine); if (lineContent !== null) { str += lineContent; max = str.length; nextLine++; } } else if (isSpace(ch)) ; else { break } } // [label]: destination 'title' // ^^^^^^^^^^^ parse this const destRes = state.md.helpers.parseLinkDestination(str, pos, max); if (!destRes.ok) { return false } const href = state.md.normalizeLink(destRes.str); if (!state.md.validateLink(href)) { return false } pos = destRes.pos; // save cursor state, we could require to rollback later const destEndPos = pos; const destEndLineNo = nextLine; // [label]: destination 'title' // ^^^ skipping those spaces const start = pos; for (; pos < max; pos++) { const ch = str.charCodeAt(pos); if (ch === 0x0A) { const lineContent = getNextLine(nextLine); if (lineContent !== null) { str += lineContent; max = str.length; nextLine++; } } else if (isSpace(ch)) ; else { break } } // [label]: destination 'title' // ^^^^^^^ parse this let titleRes = state.md.helpers.parseLinkTitle(str, pos, max); while (titleRes.can_continue) { const lineContent = getNextLine(nextLine); if (lineContent === null) break str += lineContent; pos = max; max = str.length; nextLine++; titleRes = state.md.helpers.parseLinkTitle(str, pos, max, titleRes); } let title; if (pos < max && start !== pos && titleRes.ok) { title = titleRes.str; pos = titleRes.pos; } else { title = ''; pos = destEndPos; nextLine = destEndLineNo; } // skip trailing spaces until the rest of the line while (pos < max) { const ch = str.charCodeAt(pos); if (!isSpace(ch)) { break } pos++; } if (pos < max && str.charCodeAt(pos) !== 0x0A) { if (title) { // garbage at the end of the line after title, // but it could still be a valid reference if we roll back title = ''; pos = destEndPos; nextLine = destEndLineNo; while (pos < max) { const ch = str.charCodeAt(pos); if (!isSpace(ch)) { break } pos++; } } } if (pos < max && str.charCodeAt(pos) !== 0x0A) { // garbage at the end of the line return false } const label = normalizeReference(str.slice(1, labelEnd)); if (!label) { // CommonMark 0.20 disallows empty labels return false } // Reference can not terminate anything. This check is for safety only. /* istanbul ignore if */ if (silent) { return true } if (typeof state.env.references === 'undefined') { state.env.references = {}; } if (typeof state.env.references[label] === 'undefined') { state.env.references[label] = { title, href }; } state.line = nextLine; return true } // List of valid html blocks names, according to commonmark spec // https://spec.commonmark.org/0.30/#html-blocks var block_names = [ 'address', 'article', 'aside', 'base', 'basefont', 'blockquote', 'body', 'caption', 'center', 'col', 'colgroup', 'dd', 'details', 'dialog', 'dir', 'div', 'dl', 'dt', 'fieldset', 'figcaption', 'figure', 'footer', 'form', 'frame', 'frameset', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hr', 'html', 'iframe', 'legend', 'li', 'link', 'main', 'menu', 'menuitem', 'nav', 'noframes', 'ol', 'optgroup', 'option', 'p', 'param', 'search', 'section', 'summary', 'table', 'tbody', 'td', 'tfoot', 'th', 'thead', 'title', 'tr', 'track', 'ul' ]; // Regexps to match html elements const attr_name = '[a-zA-Z_:][a-zA-Z0-9:._-]*'; const unquoted = '[^"\'=<>`\\x00-\\x20]+'; const single_quoted = "'[^']*'"; const double_quoted = '"[^"]*"'; const attr_value = '(?:' + unquoted + '|' + single_quoted + '|' + double_quoted + ')'; const attribute$1 = '(?:\\s+' + attr_name + '(?:\\s*=\\s*' + attr_value + ')?)'; const open_tag = '<[A-Za-z][A-Za-z0-9\\-]*' + attribute$1 + '*\\s*\\/?>'; const close_tag = '<\\/[A-Za-z][A-Za-z0-9\\-]*\\s*>'; const comment$1 = ''; const processing = '<[?][\\s\\S]*?[?]>'; const declaration = ']*>'; const cdata = ''; const HTML_TAG_RE = new RegExp('^(?:' + open_tag + '|' + close_tag + '|' + comment$1 + '|' + processing + '|' + declaration + '|' + cdata + ')'); const HTML_OPEN_CLOSE_TAG_RE = new RegExp('^(?:' + open_tag + '|' + close_tag + ')'); // HTML block // An array of opening and corresponding closing sequences for html tags, // last argument defines whether it can terminate a paragraph or not // const HTML_SEQUENCES = [ [/^<(script|pre|style|textarea)(?=(\s|>|$))/i, /<\/(script|pre|style|textarea)>/i, true], [/^/, true], [/^<\?/, /\?>/, true], [/^/, true], [/^/, true], [new RegExp('^|$))', 'i'), /^$/, true], [new RegExp(HTML_OPEN_CLOSE_TAG_RE.source + '\\s*$'), /^$/, false] ]; function html_block (state, startLine, endLine, silent) { let pos = state.bMarks[startLine] + state.tShift[startLine]; let max = state.eMarks[startLine]; // if it's indented more than 3 spaces, it should be a code block if (state.sCount[startLine] - state.blkIndent >= 4) { return false } if (!state.md.options.html) { return false } if (state.src.charCodeAt(pos) !== 0x3C/* < */) { return false } let lineText = state.src.slice(pos, max); let i = 0; for (; i < HTML_SEQUENCES.length; i++) { if (HTML_SEQUENCES[i][0].test(lineText)) { break } } if (i === HTML_SEQUENCES.length) { return false } if (silent) { // true if this sequence can be a terminator, false otherwise return HTML_SEQUENCES[i][2] } let nextLine = startLine + 1; // If we are here - we detected HTML block. // Let's roll down till block end. if (!HTML_SEQUENCES[i][1].test(lineText)) { for (; nextLine < endLine; nextLine++) { if (state.sCount[nextLine] < state.blkIndent) { break } pos = state.bMarks[nextLine] + state.tShift[nextLine]; max = state.eMarks[nextLine]; lineText = state.src.slice(pos, max); if (HTML_SEQUENCES[i][1].test(lineText)) { if (lineText.length !== 0) { nextLine++; } break } } } state.line = nextLine; const token = state.push('html_block', '', 0); token.map = [startLine, nextLine]; token.content = state.getLines(startLine, nextLine, state.blkIndent, true); return true } // heading (#, ##, ...) function heading (state, startLine, endLine, silent) { let pos = state.bMarks[startLine] + state.tShift[startLine]; let max = state.eMarks[startLine]; // if it's indented more than 3 spaces, it should be a code block if (state.sCount[startLine] - state.blkIndent >= 4) { return false } let ch = state.src.charCodeAt(pos); if (ch !== 0x23/* # */ || pos >= max) { return false } // count heading level let level = 1; ch = state.src.charCodeAt(++pos); while (ch === 0x23/* # */ && pos < max && level <= 6) { level++; ch = state.src.charCodeAt(++pos); } if (level > 6 || (pos < max && !isSpace(ch))) { return false } if (silent) { return true } // Let's cut tails like ' ### ' from the end of string max = state.skipSpacesBack(max, pos); const tmp = state.skipCharsBack(max, 0x23, pos); // # if (tmp > pos && isSpace(state.src.charCodeAt(tmp - 1))) { max = tmp; } state.line = startLine + 1; const token_o = state.push('heading_open', 'h' + String(level), 1); token_o.markup = '########'.slice(0, level); token_o.map = [startLine, state.line]; const token_i = state.push('inline', '', 0); token_i.content = state.src.slice(pos, max).trim(); token_i.map = [startLine, state.line]; token_i.children = []; const token_c = state.push('heading_close', 'h' + String(level), -1); token_c.markup = '########'.slice(0, level); return true } // lheading (---, ===) function lheading (state, startLine, endLine/*, silent */) { const terminatorRules = state.md.block.ruler.getRules('paragraph'); // if it's indented more than 3 spaces, it should be a code block if (state.sCount[startLine] - state.blkIndent >= 4) { return false } const oldParentType = state.parentType; state.parentType = 'paragraph'; // use paragraph to match terminatorRules // jump line-by-line until empty one or EOF let level = 0; let marker; let nextLine = startLine + 1; for (; nextLine < endLine && !state.isEmpty(nextLine); nextLine++) { // this would be a code block normally, but after paragraph // it's considered a lazy continuation regardless of what's there if (state.sCount[nextLine] - state.blkIndent > 3) { continue } // // Check for underline in setext header // if (state.sCount[nextLine] >= state.blkIndent) { let pos = state.bMarks[nextLine] + state.tShift[nextLine]; const max = state.eMarks[nextLine]; if (pos < max) { marker = state.src.charCodeAt(pos); if (marker === 0x2D/* - */ || marker === 0x3D/* = */) { pos = state.skipChars(pos, marker); pos = state.skipSpaces(pos); if (pos >= max) { level = (marker === 0x3D/* = */ ? 1 : 2); break } } } } // quirk for blockquotes, this line should already be checked by that rule if (state.sCount[nextLine] < 0) { continue } // Some tags can terminate paragraph without empty line. let terminate = false; for (let i = 0, l = terminatorRules.length; i < l; i++) { if (terminatorRules[i](state, nextLine, endLine, true)) { terminate = true; break } } if (terminate) { break } } if (!level) { // Didn't find valid underline return false } const content = state.getLines(startLine, nextLine, state.blkIndent, false).trim(); state.line = nextLine + 1; const token_o = state.push('heading_open', 'h' + String(level), 1); token_o.markup = String.fromCharCode(marker); token_o.map = [startLine, state.line]; const token_i = state.push('inline', '', 0); token_i.content = content; token_i.map = [startLine, state.line - 1]; token_i.children = []; const token_c = state.push('heading_close', 'h' + String(level), -1); token_c.markup = String.fromCharCode(marker); state.parentType = oldParentType; return true } // Paragraph function paragraph (state, startLine, endLine) { const terminatorRules = state.md.block.ruler.getRules('paragraph'); const oldParentType = state.parentType; let nextLine = startLine + 1; state.parentType = 'paragraph'; // jump line-by-line until empty one or EOF for (; nextLine < endLine && !state.isEmpty(nextLine); nextLine++) { // this would be a code block normally, but after paragraph // it's considered a lazy continuation regardless of what's there if (state.sCount[nextLine] - state.blkIndent > 3) { continue } // quirk for blockquotes, this line should already be checked by that rule if (state.sCount[nextLine] < 0) { continue } // Some tags can terminate paragraph without empty line. let terminate = false; for (let i = 0, l = terminatorRules.length; i < l; i++) { if (terminatorRules[i](state, nextLine, endLine, true)) { terminate = true; break } } if (terminate) { break } } const content = state.getLines(startLine, nextLine, state.blkIndent, false).trim(); state.line = nextLine; const token_o = state.push('paragraph_open', 'p', 1); token_o.map = [startLine, state.line]; const token_i = state.push('inline', '', 0); token_i.content = content; token_i.map = [startLine, state.line]; token_i.children = []; state.push('paragraph_close', 'p', -1); state.parentType = oldParentType; return true } /** internal * class ParserBlock * * Block-level tokenizer. **/ const _rules$1 = [ // First 2 params - rule name & source. Secondary array - list of rules, // which can be terminated by this one. ['table', table, ['paragraph', 'reference']], ['code', code], ['fence', fence, ['paragraph', 'reference', 'blockquote', 'list']], ['blockquote', blockquote, ['paragraph', 'reference', 'blockquote', 'list']], ['hr', hr, ['paragraph', 'reference', 'blockquote', 'list']], ['list', list, ['paragraph', 'reference', 'blockquote']], ['reference', reference], ['html_block', html_block, ['paragraph', 'reference', 'blockquote']], ['heading', heading, ['paragraph', 'reference', 'blockquote']], ['lheading', lheading], ['paragraph', paragraph] ]; /** * new ParserBlock() **/ function ParserBlock () { /** * ParserBlock#ruler -> Ruler * * [[Ruler]] instance. Keep configuration of block rules. **/ this.ruler = new Ruler(); for (let i = 0; i < _rules$1.length; i++) { this.ruler.push(_rules$1[i][0], _rules$1[i][1], { alt: (_rules$1[i][2] || []).slice() }); } } // Generate tokens for input range // ParserBlock.prototype.tokenize = function (state, startLine, endLine) { const rules = this.ruler.getRules(''); const len = rules.length; const maxNesting = state.md.options.maxNesting; let line = startLine; let hasEmptyLines = false; while (line < endLine) { state.line = line = state.skipEmptyLines(line); if (line >= endLine) { break } // Termination condition for nested calls. // Nested calls currently used for blockquotes & lists if (state.sCount[line] < state.blkIndent) { break } // If nesting level exceeded - skip tail to the end. That's not ordinary // situation and we should not care about content. if (state.level >= maxNesting) { state.line = endLine; break } // Try all possible rules. // On success, rule should: // // - update `state.line` // - update `state.tokens` // - return true const prevLine = state.line; let ok = false; for (let i = 0; i < len; i++) { ok = rules[i](state, line, endLine, false); if (ok) { if (prevLine >= state.line) { throw new Error("block rule didn't increment state.line") } break } } // this can only happen if user disables paragraph rule if (!ok) throw new Error('none of the block rules matched') // set state.tight if we had an empty line before current tag // i.e. latest empty line should not count state.tight = !hasEmptyLines; // paragraph might "eat" one newline after it in nested lists if (state.isEmpty(state.line - 1)) { hasEmptyLines = true; } line = state.line; if (line < endLine && state.isEmpty(line)) { hasEmptyLines = true; line++; state.line = line; } } }; /** * ParserBlock.parse(str, md, env, outTokens) * * Process input string and push block tokens into `outTokens` **/ ParserBlock.prototype.parse = function (src, md, env, outTokens) { if (!src) { return } const state = new this.State(src, md, env, outTokens); this.tokenize(state, state.line, state.lineMax); }; ParserBlock.prototype.State = StateBlock; // Inline parser state function StateInline (src, md, env, outTokens) { this.src = src; this.env = env; this.md = md; this.tokens = outTokens; this.tokens_meta = Array(outTokens.length); this.pos = 0; this.posMax = this.src.length; this.level = 0; this.pending = ''; this.pendingLevel = 0; // Stores { start: end } pairs. Useful for backtrack // optimization of pairs parse (emphasis, strikes). this.cache = {}; // List of emphasis-like delimiters for current tag this.delimiters = []; // Stack of delimiter lists for upper level tags this._prev_delimiters = []; // backtick length => last seen position this.backticks = {}; this.backticksScanned = false; // Counter used to disable inline linkify-it execution // inside and markdown links this.linkLevel = 0; } // Flush pending text // StateInline.prototype.pushPending = function () { const token = new Token('text', '', 0); token.content = this.pending; token.level = this.pendingLevel; this.tokens.push(token); this.pending = ''; return token }; // Push new token to "stream". // If pending text exists - flush it as text token // StateInline.prototype.push = function (type, tag, nesting) { if (this.pending) { this.pushPending(); } const token = new Token(type, tag, nesting); let token_meta = null; if (nesting < 0) { // closing tag this.level--; this.delimiters = this._prev_delimiters.pop(); } token.level = this.level; if (nesting > 0) { // opening tag this.level++; this._prev_delimiters.push(this.delimiters); this.delimiters = []; token_meta = { delimiters: this.delimiters }; } this.pendingLevel = this.level; this.tokens.push(token); this.tokens_meta.push(token_meta); return token }; // Scan a sequence of emphasis-like markers, and determine whether // it can start an emphasis sequence or end an emphasis sequence. // // - start - position to scan from (it should point at a valid marker); // - canSplitWord - determine if these markers can be found inside a word // StateInline.prototype.scanDelims = function (start, canSplitWord) { const max = this.posMax; const marker = this.src.charCodeAt(start); // treat beginning of the line as a whitespace const lastChar = start > 0 ? this.src.charCodeAt(start - 1) : 0x20; let pos = start; while (pos < max && this.src.charCodeAt(pos) === marker) { pos++; } const count = pos - start; // treat end of the line as a whitespace const nextChar = pos < max ? this.src.charCodeAt(pos) : 0x20; const isLastPunctChar = isMdAsciiPunct(lastChar) || isPunctChar(String.fromCharCode(lastChar)); const isNextPunctChar = isMdAsciiPunct(nextChar) || isPunctChar(String.fromCharCode(nextChar)); const isLastWhiteSpace = isWhiteSpace(lastChar); const isNextWhiteSpace = isWhiteSpace(nextChar); const left_flanking = !isNextWhiteSpace && (!isNextPunctChar || isLastWhiteSpace || isLastPunctChar); const right_flanking = !isLastWhiteSpace && (!isLastPunctChar || isNextWhiteSpace || isNextPunctChar); const can_open = left_flanking && (canSplitWord || !right_flanking || isLastPunctChar); const can_close = right_flanking && (canSplitWord || !left_flanking || isNextPunctChar); return { can_open, can_close, length: count } }; // re-export Token class to use in block rules StateInline.prototype.Token = Token; // Skip text characters for text token, place those to pending buffer // and increment current pos // Rule to skip pure text // '{}$%@~+=:' reserved for extentions // !, ", #, $, %, &, ', (, ), *, +, ,, -, ., /, :, ;, <, =, >, ?, @, [, \, ], ^, _, `, {, |, }, or ~ // !!!! Don't confuse with "Markdown ASCII Punctuation" chars // http://spec.commonmark.org/0.15/#ascii-punctuation-character function isTerminatorChar (ch) { switch (ch) { case 0x0A/* \n */: case 0x21/* ! */: case 0x23/* # */: case 0x24/* $ */: case 0x25/* % */: case 0x26/* & */: case 0x2A/* * */: case 0x2B/* + */: case 0x2D/* - */: case 0x3A/* : */: case 0x3C/* < */: case 0x3D/* = */: case 0x3E/* > */: case 0x40/* @ */: case 0x5B/* [ */: case 0x5C/* \ */: case 0x5D/* ] */: case 0x5E/* ^ */: case 0x5F/* _ */: case 0x60/* ` */: case 0x7B/* { */: case 0x7D/* } */: case 0x7E/* ~ */: return true default: return false } } function text$1 (state, silent) { let pos = state.pos; while (pos < state.posMax && !isTerminatorChar(state.src.charCodeAt(pos))) { pos++; } if (pos === state.pos) { return false } if (!silent) { state.pending += state.src.slice(state.pos, pos); } state.pos = pos; return true } // Alternative implementation, for memory. // // It costs 10% of performance, but allows extend terminators list, if place it // to `ParserInline` property. Probably, will switch to it sometime, such // flexibility required. /* var TERMINATOR_RE = /[\n!#$%&*+\-:<=>@[\\\]^_`{}~]/; module.exports = function text(state, silent) { var pos = state.pos, idx = state.src.slice(pos).search(TERMINATOR_RE); // first char is terminator -> empty text if (idx === 0) { return false; } // no terminator -> text till end of string if (idx < 0) { if (!silent) { state.pending += state.src.slice(pos); } state.pos = state.src.length; return true; } if (!silent) { state.pending += state.src.slice(pos, pos + idx); } state.pos += idx; return true; }; */ // Process links like https://example.org/ // RFC3986: scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) const SCHEME_RE = /(?:^|[^a-z0-9.+-])([a-z][a-z0-9.+-]*)$/i; function linkify (state, silent) { if (!state.md.options.linkify) return false if (state.linkLevel > 0) return false const pos = state.pos; const max = state.posMax; if (pos + 3 > max) return false if (state.src.charCodeAt(pos) !== 0x3A/* : */) return false if (state.src.charCodeAt(pos + 1) !== 0x2F/* / */) return false if (state.src.charCodeAt(pos + 2) !== 0x2F/* / */) return false const match = state.pending.match(SCHEME_RE); if (!match) return false const proto = match[1]; const link = state.md.linkify.matchAtStart(state.src.slice(pos - proto.length)); if (!link) return false let url = link.url; // invalid link, but still detected by linkify somehow; // need to check to prevent infinite loop below if (url.length <= proto.length) return false // disallow '*' at the end of the link (conflicts with emphasis) url = url.replace(/\*+$/, ''); const fullUrl = state.md.normalizeLink(url); if (!state.md.validateLink(fullUrl)) return false if (!silent) { state.pending = state.pending.slice(0, -proto.length); const token_o = state.push('link_open', 'a', 1); token_o.attrs = [['href', fullUrl]]; token_o.markup = 'linkify'; token_o.info = 'auto'; const token_t = state.push('text', '', 0); token_t.content = state.md.normalizeLinkText(url); const token_c = state.push('link_close', 'a', -1); token_c.markup = 'linkify'; token_c.info = 'auto'; } state.pos += url.length - proto.length; return true } // Proceess '\n' function newline (state, silent) { let pos = state.pos; if (state.src.charCodeAt(pos) !== 0x0A/* \n */) { return false } const pmax = state.pending.length - 1; const max = state.posMax; // ' \n' -> hardbreak // Lookup in pending chars is bad practice! Don't copy to other rules! // Pending string is stored in concat mode, indexed lookups will cause // convertion to flat mode. if (!silent) { if (pmax >= 0 && state.pending.charCodeAt(pmax) === 0x20) { if (pmax >= 1 && state.pending.charCodeAt(pmax - 1) === 0x20) { // Find whitespaces tail of pending chars. let ws = pmax - 1; while (ws >= 1 && state.pending.charCodeAt(ws - 1) === 0x20) ws--; state.pending = state.pending.slice(0, ws); state.push('hardbreak', 'br', 0); } else { state.pending = state.pending.slice(0, -1); state.push('softbreak', 'br', 0); } } else { state.push('softbreak', 'br', 0); } } pos++; // skip heading spaces for next line while (pos < max && isSpace(state.src.charCodeAt(pos))) { pos++; } state.pos = pos; return true } // Process escaped chars and hardbreaks const ESCAPED = []; for (let i = 0; i < 256; i++) { ESCAPED.push(0); } '\\!"#$%&\'()*+,./:;<=>?@[]^_`{|}~-' .split('').forEach(function (ch) { ESCAPED[ch.charCodeAt(0)] = 1; }); function escape (state, silent) { let pos = state.pos; const max = state.posMax; if (state.src.charCodeAt(pos) !== 0x5C/* \ */) return false pos++; // '\' at the end of the inline block if (pos >= max) return false let ch1 = state.src.charCodeAt(pos); if (ch1 === 0x0A) { if (!silent) { state.push('hardbreak', 'br', 0); } pos++; // skip leading whitespaces from next line while (pos < max) { ch1 = state.src.charCodeAt(pos); if (!isSpace(ch1)) break pos++; } state.pos = pos; return true } let escapedStr = state.src[pos]; if (ch1 >= 0xD800 && ch1 <= 0xDBFF && pos + 1 < max) { const ch2 = state.src.charCodeAt(pos + 1); if (ch2 >= 0xDC00 && ch2 <= 0xDFFF) { escapedStr += state.src[pos + 1]; pos++; } } const origStr = '\\' + escapedStr; if (!silent) { const token = state.push('text_special', '', 0); if (ch1 < 256 && ESCAPED[ch1] !== 0) { token.content = escapedStr; } else { token.content = origStr; } token.markup = origStr; token.info = 'escape'; } state.pos = pos + 1; return true } // Parse backticks function backtick (state, silent) { let pos = state.pos; const ch = state.src.charCodeAt(pos); if (ch !== 0x60/* ` */) { return false } const start = pos; pos++; const max = state.posMax; // scan marker length while (pos < max && state.src.charCodeAt(pos) === 0x60/* ` */) { pos++; } const marker = state.src.slice(start, pos); const openerLength = marker.length; if (state.backticksScanned && (state.backticks[openerLength] || 0) <= start) { if (!silent) state.pending += marker; state.pos += openerLength; return true } let matchEnd = pos; let matchStart; // Nothing found in the cache, scan until the end of the line (or until marker is found) while ((matchStart = state.src.indexOf('`', matchEnd)) !== -1) { matchEnd = matchStart + 1; // scan marker length while (matchEnd < max && state.src.charCodeAt(matchEnd) === 0x60/* ` */) { matchEnd++; } const closerLength = matchEnd - matchStart; if (closerLength === openerLength) { // Found matching closer length. if (!silent) { const token = state.push('code_inline', 'code', 0); token.markup = marker; token.content = state.src.slice(pos, matchStart) .replace(/\n/g, ' ') .replace(/^ (.+) $/, '$1'); } state.pos = matchEnd; return true } // Some different length found, put it in cache as upper limit of where closer can be found state.backticks[closerLength] = matchStart; } // Scanned through the end, didn't find anything state.backticksScanned = true; if (!silent) state.pending += marker; state.pos += openerLength; return true } // ~~strike through~~ // // Insert each marker as a separate text token, and add it to delimiter list // function strikethrough_tokenize (state, silent) { const start = state.pos; const marker = state.src.charCodeAt(start); if (silent) { return false } if (marker !== 0x7E/* ~ */) { return false } const scanned = state.scanDelims(state.pos, true); let len = scanned.length; const ch = String.fromCharCode(marker); if (len < 2) { return false } let token; if (len % 2) { token = state.push('text', '', 0); token.content = ch; len--; } for (let i = 0; i < len; i += 2) { token = state.push('text', '', 0); token.content = ch + ch; state.delimiters.push({ marker, length: 0, // disable "rule of 3" length checks meant for emphasis token: state.tokens.length - 1, end: -1, open: scanned.can_open, close: scanned.can_close }); } state.pos += scanned.length; return true } function postProcess$1 (state, delimiters) { let token; const loneMarkers = []; const max = delimiters.length; for (let i = 0; i < max; i++) { const startDelim = delimiters[i]; if (startDelim.marker !== 0x7E/* ~ */) { continue } if (startDelim.end === -1) { continue } const endDelim = delimiters[startDelim.end]; token = state.tokens[startDelim.token]; token.type = 's_open'; token.tag = 's'; token.nesting = 1; token.markup = '~~'; token.content = ''; token = state.tokens[endDelim.token]; token.type = 's_close'; token.tag = 's'; token.nesting = -1; token.markup = '~~'; token.content = ''; if (state.tokens[endDelim.token - 1].type === 'text' && state.tokens[endDelim.token - 1].content === '~') { loneMarkers.push(endDelim.token - 1); } } // If a marker sequence has an odd number of characters, it's splitted // like this: `~~~~~` -> `~` + `~~` + `~~`, leaving one marker at the // start of the sequence. // // So, we have to move all those markers after subsequent s_close tags. // while (loneMarkers.length) { const i = loneMarkers.pop(); let j = i + 1; while (j < state.tokens.length && state.tokens[j].type === 's_close') { j++; } j--; if (i !== j) { token = state.tokens[j]; state.tokens[j] = state.tokens[i]; state.tokens[i] = token; } } } // Walk through delimiter list and replace text tokens with tags // function strikethrough_postProcess (state) { const tokens_meta = state.tokens_meta; const max = state.tokens_meta.length; postProcess$1(state, state.delimiters); for (let curr = 0; curr < max; curr++) { if (tokens_meta[curr] && tokens_meta[curr].delimiters) { postProcess$1(state, tokens_meta[curr].delimiters); } } } var r_strikethrough = { tokenize: strikethrough_tokenize, postProcess: strikethrough_postProcess }; // Process *this* and _that_ // // Insert each marker as a separate text token, and add it to delimiter list // function emphasis_tokenize (state, silent) { const start = state.pos; const marker = state.src.charCodeAt(start); if (silent) { return false } if (marker !== 0x5F /* _ */ && marker !== 0x2A /* * */) { return false } const scanned = state.scanDelims(state.pos, marker === 0x2A); for (let i = 0; i < scanned.length; i++) { const token = state.push('text', '', 0); token.content = String.fromCharCode(marker); state.delimiters.push({ // Char code of the starting marker (number). // marker, // Total length of these series of delimiters. // length: scanned.length, // A position of the token this delimiter corresponds to. // token: state.tokens.length - 1, // If this delimiter is matched as a valid opener, `end` will be // equal to its position, otherwise it's `-1`. // end: -1, // Boolean flags that determine if this delimiter could open or close // an emphasis. // open: scanned.can_open, close: scanned.can_close }); } state.pos += scanned.length; return true } function postProcess (state, delimiters) { const max = delimiters.length; for (let i = max - 1; i >= 0; i--) { const startDelim = delimiters[i]; if (startDelim.marker !== 0x5F/* _ */ && startDelim.marker !== 0x2A/* * */) { continue } // Process only opening markers if (startDelim.end === -1) { continue } const endDelim = delimiters[startDelim.end]; // If the previous delimiter has the same marker and is adjacent to this one, // merge those into one strong delimiter. // // `whatever` -> `whatever` // const isStrong = i > 0 && delimiters[i - 1].end === startDelim.end + 1 && // check that first two markers match and adjacent delimiters[i - 1].marker === startDelim.marker && delimiters[i - 1].token === startDelim.token - 1 && // check that last two markers are adjacent (we can safely assume they match) delimiters[startDelim.end + 1].token === endDelim.token + 1; const ch = String.fromCharCode(startDelim.marker); const token_o = state.tokens[startDelim.token]; token_o.type = isStrong ? 'strong_open' : 'em_open'; token_o.tag = isStrong ? 'strong' : 'em'; token_o.nesting = 1; token_o.markup = isStrong ? ch + ch : ch; token_o.content = ''; const token_c = state.tokens[endDelim.token]; token_c.type = isStrong ? 'strong_close' : 'em_close'; token_c.tag = isStrong ? 'strong' : 'em'; token_c.nesting = -1; token_c.markup = isStrong ? ch + ch : ch; token_c.content = ''; if (isStrong) { state.tokens[delimiters[i - 1].token].content = ''; state.tokens[delimiters[startDelim.end + 1].token].content = ''; i--; } } } // Walk through delimiter list and replace text tokens with tags // function emphasis_post_process (state) { const tokens_meta = state.tokens_meta; const max = state.tokens_meta.length; postProcess(state, state.delimiters); for (let curr = 0; curr < max; curr++) { if (tokens_meta[curr] && tokens_meta[curr].delimiters) { postProcess(state, tokens_meta[curr].delimiters); } } } var r_emphasis = { tokenize: emphasis_tokenize, postProcess: emphasis_post_process }; // Process [link]( "stuff") function link (state, silent) { let code, label, res, ref; let href = ''; let title = ''; let start = state.pos; let parseReference = true; if (state.src.charCodeAt(state.pos) !== 0x5B/* [ */) { return false } const oldPos = state.pos; const max = state.posMax; const labelStart = state.pos + 1; const labelEnd = state.md.helpers.parseLinkLabel(state, state.pos, true); // parser failed to find ']', so it's not a valid link if (labelEnd < 0) { return false } let pos = labelEnd + 1; if (pos < max && state.src.charCodeAt(pos) === 0x28/* ( */) { // // Inline link // // might have found a valid shortcut link, disable reference parsing parseReference = false; // [link]( "title" ) // ^^ skipping these spaces pos++; for (; pos < max; pos++) { code = state.src.charCodeAt(pos); if (!isSpace(code) && code !== 0x0A) { break } } if (pos >= max) { return false } // [link]( "title" ) // ^^^^^^ parsing link destination start = pos; res = state.md.helpers.parseLinkDestination(state.src, pos, state.posMax); if (res.ok) { href = state.md.normalizeLink(res.str); if (state.md.validateLink(href)) { pos = res.pos; } else { href = ''; } // [link]( "title" ) // ^^ skipping these spaces start = pos; for (; pos < max; pos++) { code = state.src.charCodeAt(pos); if (!isSpace(code) && code !== 0x0A) { break } } // [link]( "title" ) // ^^^^^^^ parsing link title res = state.md.helpers.parseLinkTitle(state.src, pos, state.posMax); if (pos < max && start !== pos && res.ok) { title = res.str; pos = res.pos; // [link]( "title" ) // ^^ skipping these spaces for (; pos < max; pos++) { code = state.src.charCodeAt(pos); if (!isSpace(code) && code !== 0x0A) { break } } } } if (pos >= max || state.src.charCodeAt(pos) !== 0x29/* ) */) { // parsing a valid shortcut link failed, fallback to reference parseReference = true; } pos++; } if (parseReference) { // // Link reference // if (typeof state.env.references === 'undefined') { return false } if (pos < max && state.src.charCodeAt(pos) === 0x5B/* [ */) { start = pos + 1; pos = state.md.helpers.parseLinkLabel(state, pos); if (pos >= 0) { label = state.src.slice(start, pos++); } else { pos = labelEnd + 1; } } else { pos = labelEnd + 1; } // covers label === '' and label === undefined // (collapsed reference link and shortcut reference link respectively) if (!label) { label = state.src.slice(labelStart, labelEnd); } ref = state.env.references[normalizeReference(label)]; if (!ref) { state.pos = oldPos; return false } href = ref.href; title = ref.title; } // // We found the end of the link, and know for a fact it's a valid link; // so all that's left to do is to call tokenizer. // if (!silent) { state.pos = labelStart; state.posMax = labelEnd; const token_o = state.push('link_open', 'a', 1); const attrs = [['href', href]]; token_o.attrs = attrs; if (title) { attrs.push(['title', title]); } state.linkLevel++; state.md.inline.tokenize(state); state.linkLevel--; state.push('link_close', 'a', -1); } state.pos = pos; state.posMax = max; return true } // Process ![image]( "title") function image (state, silent) { let code, content, label, pos, ref, res, title, start; let href = ''; const oldPos = state.pos; const max = state.posMax; if (state.src.charCodeAt(state.pos) !== 0x21/* ! */) { return false } if (state.src.charCodeAt(state.pos + 1) !== 0x5B/* [ */) { return false } const labelStart = state.pos + 2; const labelEnd = state.md.helpers.parseLinkLabel(state, state.pos + 1, false); // parser failed to find ']', so it's not a valid link if (labelEnd < 0) { return false } pos = labelEnd + 1; if (pos < max && state.src.charCodeAt(pos) === 0x28/* ( */) { // // Inline link // // [link]( "title" ) // ^^ skipping these spaces pos++; for (; pos < max; pos++) { code = state.src.charCodeAt(pos); if (!isSpace(code) && code !== 0x0A) { break } } if (pos >= max) { return false } // [link]( "title" ) // ^^^^^^ parsing link destination start = pos; res = state.md.helpers.parseLinkDestination(state.src, pos, state.posMax); if (res.ok) { href = state.md.normalizeLink(res.str); if (state.md.validateLink(href)) { pos = res.pos; } else { href = ''; } } // [link]( "title" ) // ^^ skipping these spaces start = pos; for (; pos < max; pos++) { code = state.src.charCodeAt(pos); if (!isSpace(code) && code !== 0x0A) { break } } // [link]( "title" ) // ^^^^^^^ parsing link title res = state.md.helpers.parseLinkTitle(state.src, pos, state.posMax); if (pos < max && start !== pos && res.ok) { title = res.str; pos = res.pos; // [link]( "title" ) // ^^ skipping these spaces for (; pos < max; pos++) { code = state.src.charCodeAt(pos); if (!isSpace(code) && code !== 0x0A) { break } } } else { title = ''; } if (pos >= max || state.src.charCodeAt(pos) !== 0x29/* ) */) { state.pos = oldPos; return false } pos++; } else { // // Link reference // if (typeof state.env.references === 'undefined') { return false } if (pos < max && state.src.charCodeAt(pos) === 0x5B/* [ */) { start = pos + 1; pos = state.md.helpers.parseLinkLabel(state, pos); if (pos >= 0) { label = state.src.slice(start, pos++); } else { pos = labelEnd + 1; } } else { pos = labelEnd + 1; } // covers label === '' and label === undefined // (collapsed reference link and shortcut reference link respectively) if (!label) { label = state.src.slice(labelStart, labelEnd); } ref = state.env.references[normalizeReference(label)]; if (!ref) { state.pos = oldPos; return false } href = ref.href; title = ref.title; } // // We found the end of the link, and know for a fact it's a valid link; // so all that's left to do is to call tokenizer. // if (!silent) { content = state.src.slice(labelStart, labelEnd); const tokens = []; state.md.inline.parse( content, state.md, state.env, tokens ); const token = state.push('image', 'img', 0); const attrs = [['src', href], ['alt', '']]; token.attrs = attrs; token.children = tokens; token.content = content; if (title) { attrs.push(['title', title]); } } state.pos = pos; state.posMax = max; return true } // Process autolinks '' /* eslint max-len:0 */ const EMAIL_RE = /^([a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)$/; /* eslint-disable-next-line no-control-regex */ const AUTOLINK_RE = /^([a-zA-Z][a-zA-Z0-9+.-]{1,31}):([^<>\x00-\x20]*)$/; function autolink (state, silent) { let pos = state.pos; if (state.src.charCodeAt(pos) !== 0x3C/* < */) { return false } const start = state.pos; const max = state.posMax; for (;;) { if (++pos >= max) return false const ch = state.src.charCodeAt(pos); if (ch === 0x3C /* < */) return false if (ch === 0x3E /* > */) break } const url = state.src.slice(start + 1, pos); if (AUTOLINK_RE.test(url)) { const fullUrl = state.md.normalizeLink(url); if (!state.md.validateLink(fullUrl)) { return false } if (!silent) { const token_o = state.push('link_open', 'a', 1); token_o.attrs = [['href', fullUrl]]; token_o.markup = 'autolink'; token_o.info = 'auto'; const token_t = state.push('text', '', 0); token_t.content = state.md.normalizeLinkText(url); const token_c = state.push('link_close', 'a', -1); token_c.markup = 'autolink'; token_c.info = 'auto'; } state.pos += url.length + 2; return true } if (EMAIL_RE.test(url)) { const fullUrl = state.md.normalizeLink('mailto:' + url); if (!state.md.validateLink(fullUrl)) { return false } if (!silent) { const token_o = state.push('link_open', 'a', 1); token_o.attrs = [['href', fullUrl]]; token_o.markup = 'autolink'; token_o.info = 'auto'; const token_t = state.push('text', '', 0); token_t.content = state.md.normalizeLinkText(url); const token_c = state.push('link_close', 'a', -1); token_c.markup = 'autolink'; token_c.info = 'auto'; } state.pos += url.length + 2; return true } return false } // Process html tags function isLinkOpen (str) { return /^\s]/i.test(str) } function isLinkClose (str) { return /^<\/a\s*>/i.test(str) } function isLetter (ch) { /* eslint no-bitwise:0 */ const lc = ch | 0x20; // to lower case return (lc >= 0x61/* a */) && (lc <= 0x7a/* z */) } function html_inline (state, silent) { if (!state.md.options.html) { return false } // Check start const max = state.posMax; const pos = state.pos; if (state.src.charCodeAt(pos) !== 0x3C/* < */ || pos + 2 >= max) { return false } // Quick fail on second char const ch = state.src.charCodeAt(pos + 1); if (ch !== 0x21/* ! */ && ch !== 0x3F/* ? */ && ch !== 0x2F/* / */ && !isLetter(ch)) { return false } const match = state.src.slice(pos).match(HTML_TAG_RE); if (!match) { return false } if (!silent) { const token = state.push('html_inline', '', 0); token.content = match[0]; if (isLinkOpen(token.content)) state.linkLevel++; if (isLinkClose(token.content)) state.linkLevel--; } state.pos += match[0].length; return true } // Process html entity - {, ¯, ", ... const DIGITAL_RE = /^&#((?:x[a-f0-9]{1,6}|[0-9]{1,7}));/i; const NAMED_RE = /^&([a-z][a-z0-9]{1,31});/i; function entity (state, silent) { const pos = state.pos; const max = state.posMax; if (state.src.charCodeAt(pos) !== 0x26/* & */) return false if (pos + 1 >= max) return false const ch = state.src.charCodeAt(pos + 1); if (ch === 0x23 /* # */) { const match = state.src.slice(pos).match(DIGITAL_RE); if (match) { if (!silent) { const code = match[1][0].toLowerCase() === 'x' ? parseInt(match[1].slice(1), 16) : parseInt(match[1], 10); const token = state.push('text_special', '', 0); token.content = isValidEntityCode(code) ? fromCodePoint(code) : fromCodePoint(0xFFFD); token.markup = match[0]; token.info = 'entity'; } state.pos += match[0].length; return true } } else { const match = state.src.slice(pos).match(NAMED_RE); if (match) { const decoded = decodeHTML(match[0]); if (decoded !== match[0]) { if (!silent) { const token = state.push('text_special', '', 0); token.content = decoded; token.markup = match[0]; token.info = 'entity'; } state.pos += match[0].length; return true } } } return false } // For each opening emphasis-like marker find a matching closing one // function processDelimiters (delimiters) { const openersBottom = {}; const max = delimiters.length; if (!max) return // headerIdx is the first delimiter of the current (where closer is) delimiter run let headerIdx = 0; let lastTokenIdx = -2; // needs any value lower than -1 const jumps = []; for (let closerIdx = 0; closerIdx < max; closerIdx++) { const closer = delimiters[closerIdx]; jumps.push(0); // markers belong to same delimiter run if: // - they have adjacent tokens // - AND markers are the same // if (delimiters[headerIdx].marker !== closer.marker || lastTokenIdx !== closer.token - 1) { headerIdx = closerIdx; } lastTokenIdx = closer.token; // Length is only used for emphasis-specific "rule of 3", // if it's not defined (in strikethrough or 3rd party plugins), // we can default it to 0 to disable those checks. // closer.length = closer.length || 0; if (!closer.close) continue // Previously calculated lower bounds (previous fails) // for each marker, each delimiter length modulo 3, // and for whether this closer can be an opener; // https://github.com/commonmark/cmark/commit/34250e12ccebdc6372b8b49c44fab57c72443460 /* eslint-disable-next-line no-prototype-builtins */ if (!openersBottom.hasOwnProperty(closer.marker)) { openersBottom[closer.marker] = [-1, -1, -1, -1, -1, -1]; } const minOpenerIdx = openersBottom[closer.marker][(closer.open ? 3 : 0) + (closer.length % 3)]; let openerIdx = headerIdx - jumps[headerIdx] - 1; let newMinOpenerIdx = openerIdx; for (; openerIdx > minOpenerIdx; openerIdx -= jumps[openerIdx] + 1) { const opener = delimiters[openerIdx]; if (opener.marker !== closer.marker) continue if (opener.open && opener.end < 0) { let isOddMatch = false; // from spec: // // If one of the delimiters can both open and close emphasis, then the // sum of the lengths of the delimiter runs containing the opening and // closing delimiters must not be a multiple of 3 unless both lengths // are multiples of 3. // if (opener.close || closer.open) { if ((opener.length + closer.length) % 3 === 0) { if (opener.length % 3 !== 0 || closer.length % 3 !== 0) { isOddMatch = true; } } } if (!isOddMatch) { // If previous delimiter cannot be an opener, we can safely skip // the entire sequence in future checks. This is required to make // sure algorithm has linear complexity (see *_*_*_*_*_... case). // const lastJump = openerIdx > 0 && !delimiters[openerIdx - 1].open ? jumps[openerIdx - 1] + 1 : 0; jumps[closerIdx] = closerIdx - openerIdx + lastJump; jumps[openerIdx] = lastJump; closer.open = false; opener.end = closerIdx; opener.close = false; newMinOpenerIdx = -1; // treat next token as start of run, // it optimizes skips in **<...>**a**<...>** pathological case lastTokenIdx = -2; break } } } if (newMinOpenerIdx !== -1) { // If match for this delimiter run failed, we want to set lower bound for // future lookups. This is required to make sure algorithm has linear // complexity. // // See details here: // https://github.com/commonmark/cmark/issues/178#issuecomment-270417442 // openersBottom[closer.marker][(closer.open ? 3 : 0) + ((closer.length || 0) % 3)] = newMinOpenerIdx; } } } function link_pairs (state) { const tokens_meta = state.tokens_meta; const max = state.tokens_meta.length; processDelimiters(state.delimiters); for (let curr = 0; curr < max; curr++) { if (tokens_meta[curr] && tokens_meta[curr].delimiters) { processDelimiters(tokens_meta[curr].delimiters); } } } // Clean up tokens after emphasis and strikethrough postprocessing: // merge adjacent text nodes into one and re-calculate all token levels // // This is necessary because initially emphasis delimiter markers (*, _, ~) // are treated as their own separate text tokens. Then emphasis rule either // leaves them as text (needed to merge with adjacent text) or turns them // into opening/closing tags (which messes up levels inside). // function fragments_join (state) { let curr, last; let level = 0; const tokens = state.tokens; const max = state.tokens.length; for (curr = last = 0; curr < max; curr++) { // re-calculate levels after emphasis/strikethrough turns some text nodes // into opening/closing tags if (tokens[curr].nesting < 0) level--; // closing tag tokens[curr].level = level; if (tokens[curr].nesting > 0) level++; // opening tag if (tokens[curr].type === 'text' && curr + 1 < max && tokens[curr + 1].type === 'text') { // collapse two adjacent text nodes tokens[curr + 1].content = tokens[curr].content + tokens[curr + 1].content; } else { if (curr !== last) { tokens[last] = tokens[curr]; } last++; } } if (curr !== last) { tokens.length = last; } } /** internal * class ParserInline * * Tokenizes paragraph content. **/ // Parser rules const _rules = [ ['text', text$1], ['linkify', linkify], ['newline', newline], ['escape', escape], ['backticks', backtick], ['strikethrough', r_strikethrough.tokenize], ['emphasis', r_emphasis.tokenize], ['link', link], ['image', image], ['autolink', autolink], ['html_inline', html_inline], ['entity', entity] ]; // `rule2` ruleset was created specifically for emphasis/strikethrough // post-processing and may be changed in the future. // // Don't use this for anything except pairs (plugins working with `balance_pairs`). // const _rules2 = [ ['balance_pairs', link_pairs], ['strikethrough', r_strikethrough.postProcess], ['emphasis', r_emphasis.postProcess], // rules for pairs separate '**' into its own text tokens, which may be left unused, // rule below merges unused segments back with the rest of the text ['fragments_join', fragments_join] ]; /** * new ParserInline() **/ function ParserInline () { /** * ParserInline#ruler -> Ruler * * [[Ruler]] instance. Keep configuration of inline rules. **/ this.ruler = new Ruler(); for (let i = 0; i < _rules.length; i++) { this.ruler.push(_rules[i][0], _rules[i][1]); } /** * ParserInline#ruler2 -> Ruler * * [[Ruler]] instance. Second ruler used for post-processing * (e.g. in emphasis-like rules). **/ this.ruler2 = new Ruler(); for (let i = 0; i < _rules2.length; i++) { this.ruler2.push(_rules2[i][0], _rules2[i][1]); } } // Skip single token by running all rules in validation mode; // returns `true` if any rule reported success // ParserInline.prototype.skipToken = function (state) { const pos = state.pos; const rules = this.ruler.getRules(''); const len = rules.length; const maxNesting = state.md.options.maxNesting; const cache = state.cache; if (typeof cache[pos] !== 'undefined') { state.pos = cache[pos]; return } let ok = false; if (state.level < maxNesting) { for (let i = 0; i < len; i++) { // Increment state.level and decrement it later to limit recursion. // It's harmless to do here, because no tokens are created. But ideally, // we'd need a separate private state variable for this purpose. // state.level++; ok = rules[i](state, true); state.level--; if (ok) { if (pos >= state.pos) { throw new Error("inline rule didn't increment state.pos") } break } } } else { // Too much nesting, just skip until the end of the paragraph. // // NOTE: this will cause links to behave incorrectly in the following case, // when an amount of `[` is exactly equal to `maxNesting + 1`: // // [[[[[[[[[[[[[[[[[[[[[foo]() // // TODO: remove this workaround when CM standard will allow nested links // (we can replace it by preventing links from being parsed in // validation mode) // state.pos = state.posMax; } if (!ok) { state.pos++; } cache[pos] = state.pos; }; // Generate tokens for input range // ParserInline.prototype.tokenize = function (state) { const rules = this.ruler.getRules(''); const len = rules.length; const end = state.posMax; const maxNesting = state.md.options.maxNesting; while (state.pos < end) { // Try all possible rules. // On success, rule should: // // - update `state.pos` // - update `state.tokens` // - return true const prevPos = state.pos; let ok = false; if (state.level < maxNesting) { for (let i = 0; i < len; i++) { ok = rules[i](state, false); if (ok) { if (prevPos >= state.pos) { throw new Error("inline rule didn't increment state.pos") } break } } } if (ok) { if (state.pos >= end) { break } continue } state.pending += state.src[state.pos++]; } if (state.pending) { state.pushPending(); } }; /** * ParserInline.parse(str, md, env, outTokens) * * Process input string and push inline tokens into `outTokens` **/ ParserInline.prototype.parse = function (str, md, env, outTokens) { const state = new this.State(str, md, env, outTokens); this.tokenize(state); const rules = this.ruler2.getRules(''); const len = rules.length; for (let i = 0; i < len; i++) { rules[i](state); } }; ParserInline.prototype.State = StateInline; function reFactory (opts) { const re = {}; opts = opts || {}; re.src_Any = Any.source; re.src_Cc = Cc.source; re.src_Z = Z$1.source; re.src_P = P$1.source; // \p{\Z\P\Cc\CF} (white spaces + control + format + punctuation) re.src_ZPCc = [re.src_Z, re.src_P, re.src_Cc].join('|'); // \p{\Z\Cc} (white spaces + control) re.src_ZCc = [re.src_Z, re.src_Cc].join('|'); // Experimental. List of chars, completely prohibited in links // because can separate it from other part of text const text_separators = '[><\uff5c]'; // All possible word characters (everything without punctuation, spaces & controls) // Defined via punctuation & spaces to save space // Should be something like \p{\L\N\S\M} (\w but without `_`) re.src_pseudo_letter = '(?:(?!' + text_separators + '|' + re.src_ZPCc + ')' + re.src_Any + ')'; // The same as abothe but without [0-9] // var src_pseudo_letter_non_d = '(?:(?![0-9]|' + src_ZPCc + ')' + src_Any + ')'; re.src_ip4 = '(?:(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)'; // Prohibit any of "@/[]()" in user/pass to avoid wrong domain fetch. re.src_auth = '(?:(?:(?!' + re.src_ZCc + '|[@/\\[\\]()]).)+@)?'; re.src_port = '(?::(?:6(?:[0-4]\\d{3}|5(?:[0-4]\\d{2}|5(?:[0-2]\\d|3[0-5])))|[1-5]?\\d{1,4}))?'; re.src_host_terminator = '(?=$|' + text_separators + '|' + re.src_ZPCc + ')' + '(?!' + (opts['---'] ? '-(?!--)|' : '-|') + '_|:\\d|\\.-|\\.(?!$|' + re.src_ZPCc + '))'; re.src_path = '(?:' + '[/?#]' + '(?:' + '(?!' + re.src_ZCc + '|' + text_separators + '|[()[\\]{}.,"\'?!\\-;]).|' + '\\[(?:(?!' + re.src_ZCc + '|\\]).)*\\]|' + '\\((?:(?!' + re.src_ZCc + '|[)]).)*\\)|' + '\\{(?:(?!' + re.src_ZCc + '|[}]).)*\\}|' + '\\"(?:(?!' + re.src_ZCc + '|["]).)+\\"|' + "\\'(?:(?!" + re.src_ZCc + "|[']).)+\\'|" + // allow `I'm_king` if no pair found "\\'(?=" + re.src_pseudo_letter + '|[-])|' + // google has many dots in "google search" links (#66, #81). // github has ... in commit range links, // Restrict to // - english // - percent-encoded // - parts of file path // - params separator // until more examples found. '\\.{2,}[a-zA-Z0-9%/&]|' + '\\.(?!' + re.src_ZCc + '|[.]|$)|' + (opts['---'] ? '\\-(?!--(?:[^-]|$))(?:-*)|' // `---` => long dash, terminate : '\\-+|' ) + // allow `,,,` in paths ',(?!' + re.src_ZCc + '|$)|' + // allow `;` if not followed by space-like char ';(?!' + re.src_ZCc + '|$)|' + // allow `!!!` in paths, but not at the end '\\!+(?!' + re.src_ZCc + '|[!]|$)|' + '\\?(?!' + re.src_ZCc + '|[?]|$)' + ')+' + '|\\/' + ')?'; // Allow anything in markdown spec, forbid quote (") at the first position // because emails enclosed in quotes are far more common re.src_email_name = '[\\-;:&=\\+\\$,\\.a-zA-Z0-9_][\\-;:&=\\+\\$,\\"\\.a-zA-Z0-9_]*'; re.src_xn = 'xn--[a-z0-9\\-]{1,59}'; // More to read about domain names // http://serverfault.com/questions/638260/ re.src_domain_root = // Allow letters & digits (http://test1) '(?:' + re.src_xn + '|' + re.src_pseudo_letter + '{1,63}' + ')'; re.src_domain = '(?:' + re.src_xn + '|' + '(?:' + re.src_pseudo_letter + ')' + '|' + '(?:' + re.src_pseudo_letter + '(?:-|' + re.src_pseudo_letter + '){0,61}' + re.src_pseudo_letter + ')' + ')'; re.src_host = '(?:' + // Don't need IP check, because digits are already allowed in normal domain names // src_ip4 + // '|' + '(?:(?:(?:' + re.src_domain + ')\\.)*' + re.src_domain/* _root */ + ')' + ')'; re.tpl_host_fuzzy = '(?:' + re.src_ip4 + '|' + '(?:(?:(?:' + re.src_domain + ')\\.)+(?:%TLDS%))' + ')'; re.tpl_host_no_ip_fuzzy = '(?:(?:(?:' + re.src_domain + ')\\.)+(?:%TLDS%))'; re.src_host_strict = re.src_host + re.src_host_terminator; re.tpl_host_fuzzy_strict = re.tpl_host_fuzzy + re.src_host_terminator; re.src_host_port_strict = re.src_host + re.src_port + re.src_host_terminator; re.tpl_host_port_fuzzy_strict = re.tpl_host_fuzzy + re.src_port + re.src_host_terminator; re.tpl_host_port_no_ip_fuzzy_strict = re.tpl_host_no_ip_fuzzy + re.src_port + re.src_host_terminator; // // Main rules // // Rude test fuzzy links by host, for quick deny re.tpl_host_fuzzy_test = 'localhost|www\\.|\\.\\d{1,3}\\.|(?:\\.(?:%TLDS%)(?:' + re.src_ZPCc + '|>|$))'; re.tpl_email_fuzzy = '(^|' + text_separators + '|"|\\(|' + re.src_ZCc + ')' + '(' + re.src_email_name + '@' + re.tpl_host_fuzzy_strict + ')'; re.tpl_link_fuzzy = // Fuzzy link can't be prepended with .:/\- and non punctuation. // but can start with > (markdown blockquote) '(^|(?![.:/\\-_@])(?:[$+<=>^`|\uff5c]|' + re.src_ZPCc + '))' + '((?![$+<=>^`|\uff5c])' + re.tpl_host_port_fuzzy_strict + re.src_path + ')'; re.tpl_link_no_ip_fuzzy = // Fuzzy link can't be prepended with .:/\- and non punctuation. // but can start with > (markdown blockquote) '(^|(?![.:/\\-_@])(?:[$+<=>^`|\uff5c]|' + re.src_ZPCc + '))' + '((?![$+<=>^`|\uff5c])' + re.tpl_host_port_no_ip_fuzzy_strict + re.src_path + ')'; return re } // // Helpers // // Merge objects // function assign (obj /* from1, from2, from3, ... */) { const sources = Array.prototype.slice.call(arguments, 1); sources.forEach(function (source) { if (!source) { return } Object.keys(source).forEach(function (key) { obj[key] = source[key]; }); }); return obj } function _class (obj) { return Object.prototype.toString.call(obj) } function isString (obj) { return _class(obj) === '[object String]' } function isObject (obj) { return _class(obj) === '[object Object]' } function isRegExp (obj) { return _class(obj) === '[object RegExp]' } function isFunction (obj) { return _class(obj) === '[object Function]' } function escapeRE (str) { return str.replace(/[.?*+^$[\]\\(){}|-]/g, '\\$&') } // const defaultOptions = { fuzzyLink: true, fuzzyEmail: true, fuzzyIP: false }; function isOptionsObj (obj) { return Object.keys(obj || {}).reduce(function (acc, k) { /* eslint-disable-next-line no-prototype-builtins */ return acc || defaultOptions.hasOwnProperty(k) }, false) } const defaultSchemas = { 'http:': { validate: function (text, pos, self) { const tail = text.slice(pos); if (!self.re.http) { // compile lazily, because "host"-containing variables can change on tlds update. self.re.http = new RegExp( '^\\/\\/' + self.re.src_auth + self.re.src_host_port_strict + self.re.src_path, 'i' ); } if (self.re.http.test(tail)) { return tail.match(self.re.http)[0].length } return 0 } }, 'https:': 'http:', 'ftp:': 'http:', '//': { validate: function (text, pos, self) { const tail = text.slice(pos); if (!self.re.no_http) { // compile lazily, because "host"-containing variables can change on tlds update. self.re.no_http = new RegExp( '^' + self.re.src_auth + // Don't allow single-level domains, because of false positives like '//test' // with code comments '(?:localhost|(?:(?:' + self.re.src_domain + ')\\.)+' + self.re.src_domain_root + ')' + self.re.src_port + self.re.src_host_terminator + self.re.src_path, 'i' ); } if (self.re.no_http.test(tail)) { // should not be `://` & `///`, that protects from errors in protocol name if (pos >= 3 && text[pos - 3] === ':') { return 0 } if (pos >= 3 && text[pos - 3] === '/') { return 0 } return tail.match(self.re.no_http)[0].length } return 0 } }, 'mailto:': { validate: function (text, pos, self) { const tail = text.slice(pos); if (!self.re.mailto) { self.re.mailto = new RegExp( '^' + self.re.src_email_name + '@' + self.re.src_host_strict, 'i' ); } if (self.re.mailto.test(tail)) { return tail.match(self.re.mailto)[0].length } return 0 } } }; // RE pattern for 2-character tlds (autogenerated by ./support/tlds_2char_gen.js) /* eslint-disable-next-line max-len */ const tlds_2ch_src_re = 'a[cdefgilmnoqrstuwxz]|b[abdefghijmnorstvwyz]|c[acdfghiklmnoruvwxyz]|d[ejkmoz]|e[cegrstu]|f[ijkmor]|g[abdefghilmnpqrstuwy]|h[kmnrtu]|i[delmnoqrst]|j[emop]|k[eghimnprwyz]|l[abcikrstuvy]|m[acdeghklmnopqrstuvwxyz]|n[acefgilopruz]|om|p[aefghklmnrstwy]|qa|r[eosuw]|s[abcdeghijklmnortuvxyz]|t[cdfghjklmnortvwz]|u[agksyz]|v[aceginu]|w[fs]|y[et]|z[amw]'; // DON'T try to make PRs with changes. Extend TLDs with LinkifyIt.tlds() instead const tlds_default = 'biz|com|edu|gov|net|org|pro|web|xxx|aero|asia|coop|info|museum|name|shop|рф'.split('|'); function resetScanCache (self) { self.__index__ = -1; self.__text_cache__ = ''; } function createValidator (re) { return function (text, pos) { const tail = text.slice(pos); if (re.test(tail)) { return tail.match(re)[0].length } return 0 } } function createNormalizer () { return function (match, self) { self.normalize(match); } } // Schemas compiler. Build regexps. // function compile (self) { // Load & clone RE patterns. const re = self.re = reFactory(self.__opts__); // Define dynamic patterns const tlds = self.__tlds__.slice(); self.onCompile(); if (!self.__tlds_replaced__) { tlds.push(tlds_2ch_src_re); } tlds.push(re.src_xn); re.src_tlds = tlds.join('|'); function untpl (tpl) { return tpl.replace('%TLDS%', re.src_tlds) } re.email_fuzzy = RegExp(untpl(re.tpl_email_fuzzy), 'i'); re.link_fuzzy = RegExp(untpl(re.tpl_link_fuzzy), 'i'); re.link_no_ip_fuzzy = RegExp(untpl(re.tpl_link_no_ip_fuzzy), 'i'); re.host_fuzzy_test = RegExp(untpl(re.tpl_host_fuzzy_test), 'i'); // // Compile each schema // const aliases = []; self.__compiled__ = {}; // Reset compiled data function schemaError (name, val) { throw new Error('(LinkifyIt) Invalid schema "' + name + '": ' + val) } Object.keys(self.__schemas__).forEach(function (name) { const val = self.__schemas__[name]; // skip disabled methods if (val === null) { return } const compiled = { validate: null, link: null }; self.__compiled__[name] = compiled; if (isObject(val)) { if (isRegExp(val.validate)) { compiled.validate = createValidator(val.validate); } else if (isFunction(val.validate)) { compiled.validate = val.validate; } else { schemaError(name, val); } if (isFunction(val.normalize)) { compiled.normalize = val.normalize; } else if (!val.normalize) { compiled.normalize = createNormalizer(); } else { schemaError(name, val); } return } if (isString(val)) { aliases.push(name); return } schemaError(name, val); }); // // Compile postponed aliases // aliases.forEach(function (alias) { if (!self.__compiled__[self.__schemas__[alias]]) { // Silently fail on missed schemas to avoid errons on disable. // schemaError(alias, self.__schemas__[alias]); return } self.__compiled__[alias].validate = self.__compiled__[self.__schemas__[alias]].validate; self.__compiled__[alias].normalize = self.__compiled__[self.__schemas__[alias]].normalize; }); // // Fake record for guessed links // self.__compiled__[''] = { validate: null, normalize: createNormalizer() }; // // Build schema condition // const slist = Object.keys(self.__compiled__) .filter(function (name) { // Filter disabled & fake schemas return name.length > 0 && self.__compiled__[name] }) .map(escapeRE) .join('|'); // (?!_) cause 1.5x slowdown self.re.schema_test = RegExp('(^|(?!_)(?:[><\uff5c]|' + re.src_ZPCc + '))(' + slist + ')', 'i'); self.re.schema_search = RegExp('(^|(?!_)(?:[><\uff5c]|' + re.src_ZPCc + '))(' + slist + ')', 'ig'); self.re.schema_at_start = RegExp('^' + self.re.schema_search.source, 'i'); self.re.pretest = RegExp( '(' + self.re.schema_test.source + ')|(' + self.re.host_fuzzy_test.source + ')|@', 'i' ); // // Cleanup // resetScanCache(self); } /** * class Match * * Match result. Single element of array, returned by [[LinkifyIt#match]] **/ function Match (self, shift) { const start = self.__index__; const end = self.__last_index__; const text = self.__text_cache__.slice(start, end); /** * Match#schema -> String * * Prefix (protocol) for matched string. **/ this.schema = self.__schema__.toLowerCase(); /** * Match#index -> Number * * First position of matched string. **/ this.index = start + shift; /** * Match#lastIndex -> Number * * Next position after matched string. **/ this.lastIndex = end + shift; /** * Match#raw -> String * * Matched string. **/ this.raw = text; /** * Match#text -> String * * Notmalized text of matched string. **/ this.text = text; /** * Match#url -> String * * Normalized url of matched string. **/ this.url = text; } function createMatch (self, shift) { const match = new Match(self, shift); self.__compiled__[match.schema].normalize(match, self); return match } /** * class LinkifyIt **/ /** * new LinkifyIt(schemas, options) * - schemas (Object): Optional. Additional schemas to validate (prefix/validator) * - options (Object): { fuzzyLink|fuzzyEmail|fuzzyIP: true|false } * * Creates new linkifier instance with optional additional schemas. * Can be called without `new` keyword for convenience. * * By default understands: * * - `http(s)://...` , `ftp://...`, `mailto:...` & `//...` links * - "fuzzy" links and emails (example.com, foo@bar.com). * * `schemas` is an object, where each key/value describes protocol/rule: * * - __key__ - link prefix (usually, protocol name with `:` at the end, `skype:` * for example). `linkify-it` makes shure that prefix is not preceeded with * alphanumeric char and symbols. Only whitespaces and punctuation allowed. * - __value__ - rule to check tail after link prefix * - _String_ - just alias to existing rule * - _Object_ * - _validate_ - validator function (should return matched length on success), * or `RegExp`. * - _normalize_ - optional function to normalize text & url of matched result * (for example, for @twitter mentions). * * `options`: * * - __fuzzyLink__ - recognige URL-s without `http(s):` prefix. Default `true`. * - __fuzzyIP__ - allow IPs in fuzzy links above. Can conflict with some texts * like version numbers. Default `false`. * - __fuzzyEmail__ - recognize emails without `mailto:` prefix. * **/ function LinkifyIt (schemas, options) { if (!(this instanceof LinkifyIt)) { return new LinkifyIt(schemas, options) } if (!options) { if (isOptionsObj(schemas)) { options = schemas; schemas = {}; } } this.__opts__ = assign({}, defaultOptions, options); // Cache last tested result. Used to skip repeating steps on next `match` call. this.__index__ = -1; this.__last_index__ = -1; // Next scan position this.__schema__ = ''; this.__text_cache__ = ''; this.__schemas__ = assign({}, defaultSchemas, schemas); this.__compiled__ = {}; this.__tlds__ = tlds_default; this.__tlds_replaced__ = false; this.re = {}; compile(this); } /** chainable * LinkifyIt#add(schema, definition) * - schema (String): rule name (fixed pattern prefix) * - definition (String|RegExp|Object): schema definition * * Add new rule definition. See constructor description for details. **/ LinkifyIt.prototype.add = function add (schema, definition) { this.__schemas__[schema] = definition; compile(this); return this }; /** chainable * LinkifyIt#set(options) * - options (Object): { fuzzyLink|fuzzyEmail|fuzzyIP: true|false } * * Set recognition options for links without schema. **/ LinkifyIt.prototype.set = function set (options) { this.__opts__ = assign(this.__opts__, options); return this }; /** * LinkifyIt#test(text) -> Boolean * * Searches linkifiable pattern and returns `true` on success or `false` on fail. **/ LinkifyIt.prototype.test = function test (text) { // Reset scan cache this.__text_cache__ = text; this.__index__ = -1; if (!text.length) { return false } let m, ml, me, len, shift, next, re, tld_pos, at_pos; // try to scan for link with schema - that's the most simple rule if (this.re.schema_test.test(text)) { re = this.re.schema_search; re.lastIndex = 0; while ((m = re.exec(text)) !== null) { len = this.testSchemaAt(text, m[2], re.lastIndex); if (len) { this.__schema__ = m[2]; this.__index__ = m.index + m[1].length; this.__last_index__ = m.index + m[0].length + len; break } } } if (this.__opts__.fuzzyLink && this.__compiled__['http:']) { // guess schemaless links tld_pos = text.search(this.re.host_fuzzy_test); if (tld_pos >= 0) { // if tld is located after found link - no need to check fuzzy pattern if (this.__index__ < 0 || tld_pos < this.__index__) { if ((ml = text.match(this.__opts__.fuzzyIP ? this.re.link_fuzzy : this.re.link_no_ip_fuzzy)) !== null) { shift = ml.index + ml[1].length; if (this.__index__ < 0 || shift < this.__index__) { this.__schema__ = ''; this.__index__ = shift; this.__last_index__ = ml.index + ml[0].length; } } } } } if (this.__opts__.fuzzyEmail && this.__compiled__['mailto:']) { // guess schemaless emails at_pos = text.indexOf('@'); if (at_pos >= 0) { // We can't skip this check, because this cases are possible: // 192.168.1.1@gmail.com, my.in@example.com if ((me = text.match(this.re.email_fuzzy)) !== null) { shift = me.index + me[1].length; next = me.index + me[0].length; if (this.__index__ < 0 || shift < this.__index__ || (shift === this.__index__ && next > this.__last_index__)) { this.__schema__ = 'mailto:'; this.__index__ = shift; this.__last_index__ = next; } } } } return this.__index__ >= 0 }; /** * LinkifyIt#pretest(text) -> Boolean * * Very quick check, that can give false positives. Returns true if link MAY BE * can exists. Can be used for speed optimization, when you need to check that * link NOT exists. **/ LinkifyIt.prototype.pretest = function pretest (text) { return this.re.pretest.test(text) }; /** * LinkifyIt#testSchemaAt(text, name, position) -> Number * - text (String): text to scan * - name (String): rule (schema) name * - position (Number): text offset to check from * * Similar to [[LinkifyIt#test]] but checks only specific protocol tail exactly * at given position. Returns length of found pattern (0 on fail). **/ LinkifyIt.prototype.testSchemaAt = function testSchemaAt (text, schema, pos) { // If not supported schema check requested - terminate if (!this.__compiled__[schema.toLowerCase()]) { return 0 } return this.__compiled__[schema.toLowerCase()].validate(text, pos, this) }; /** * LinkifyIt#match(text) -> Array|null * * Returns array of found link descriptions or `null` on fail. We strongly * recommend to use [[LinkifyIt#test]] first, for best speed. * * ##### Result match description * * - __schema__ - link schema, can be empty for fuzzy links, or `//` for * protocol-neutral links. * - __index__ - offset of matched text * - __lastIndex__ - index of next char after mathch end * - __raw__ - matched text * - __text__ - normalized text * - __url__ - link, generated from matched text **/ LinkifyIt.prototype.match = function match (text) { const result = []; let shift = 0; // Try to take previous element from cache, if .test() called before if (this.__index__ >= 0 && this.__text_cache__ === text) { result.push(createMatch(this, shift)); shift = this.__last_index__; } // Cut head if cache was used let tail = shift ? text.slice(shift) : text; // Scan string until end reached while (this.test(tail)) { result.push(createMatch(this, shift)); tail = tail.slice(this.__last_index__); shift += this.__last_index__; } if (result.length) { return result } return null }; /** * LinkifyIt#matchAtStart(text) -> Match|null * * Returns fully-formed (not fuzzy) link if it starts at the beginning * of the string, and null otherwise. **/ LinkifyIt.prototype.matchAtStart = function matchAtStart (text) { // Reset scan cache this.__text_cache__ = text; this.__index__ = -1; if (!text.length) return null const m = this.re.schema_at_start.exec(text); if (!m) return null const len = this.testSchemaAt(text, m[2], m[0].length); if (!len) return null this.__schema__ = m[2]; this.__index__ = m.index + m[1].length; this.__last_index__ = m.index + m[0].length + len; return createMatch(this, 0) }; /** chainable * LinkifyIt#tlds(list [, keepOld]) -> this * - list (Array): list of tlds * - keepOld (Boolean): merge with current list if `true` (`false` by default) * * Load (or merge) new tlds list. Those are user for fuzzy links (without prefix) * to avoid false positives. By default this algorythm used: * * - hostname with any 2-letter root zones are ok. * - biz|com|edu|gov|net|org|pro|web|xxx|aero|asia|coop|info|museum|name|shop|рф * are ok. * - encoded (`xn--...`) root zones are ok. * * If list is replaced, then exact match for 2-chars root zones will be checked. **/ LinkifyIt.prototype.tlds = function tlds (list, keepOld) { list = Array.isArray(list) ? list : [list]; if (!keepOld) { this.__tlds__ = list.slice(); this.__tlds_replaced__ = true; compile(this); return this } this.__tlds__ = this.__tlds__.concat(list) .sort() .filter(function (el, idx, arr) { return el !== arr[idx - 1] }) .reverse(); compile(this); return this }; /** * LinkifyIt#normalize(match) * * Default normalizer (if schema does not define it's own). **/ LinkifyIt.prototype.normalize = function normalize (match) { // Do minimal possible changes by default. Need to collect feedback prior // to move forward https://github.com/markdown-it/linkify-it/issues/1 if (!match.schema) { match.url = 'http://' + match.url; } if (match.schema === 'mailto:' && !/^mailto:/i.test(match.url)) { match.url = 'mailto:' + match.url; } }; /** * LinkifyIt#onCompile() * * Override to modify basic RegExp-s. **/ LinkifyIt.prototype.onCompile = function onCompile () { }; /** Highest positive signed 32-bit float value */ const maxInt = 2147483647; // aka. 0x7FFFFFFF or 2^31-1 /** Bootstring parameters */ const base = 36; const tMin = 1; const tMax = 26; const skew = 38; const damp = 700; const initialBias = 72; const initialN = 128; // 0x80 const delimiter = '-'; // '\x2D' /** Regular expressions */ const regexPunycode = /^xn--/; const regexNonASCII = /[^\0-\x7F]/; // Note: U+007F DEL is excluded too. const regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g; // RFC 3490 separators /** Error messages */ const errors = { 'overflow': 'Overflow: input needs wider integers to process', 'not-basic': 'Illegal input >= 0x80 (not a basic code point)', 'invalid-input': 'Invalid input' }; /** Convenience shortcuts */ const baseMinusTMin = base - tMin; const floor = Math.floor; const stringFromCharCode = String.fromCharCode; /*--------------------------------------------------------------------------*/ /** * A generic error utility function. * @private * @param {String} type The error type. * @returns {Error} Throws a `RangeError` with the applicable error message. */ function error$1(type) { throw new RangeError(errors[type]); } /** * A generic `Array#map` utility function. * @private * @param {Array} array The array to iterate over. * @param {Function} callback The function that gets called for every array * item. * @returns {Array} A new array of values returned by the callback function. */ function map(array, callback) { const result = []; let length = array.length; while (length--) { result[length] = callback(array[length]); } return result; } /** * A simple `Array#map`-like wrapper to work with domain name strings or email * addresses. * @private * @param {String} domain The domain name or email address. * @param {Function} callback The function that gets called for every * character. * @returns {String} A new string of characters returned by the callback * function. */ function mapDomain(domain, callback) { const parts = domain.split('@'); let result = ''; if (parts.length > 1) { // In email addresses, only the domain name should be punycoded. Leave // the local part (i.e. everything up to `@`) intact. result = parts[0] + '@'; domain = parts[1]; } // Avoid `split(regex)` for IE8 compatibility. See #17. domain = domain.replace(regexSeparators, '\x2E'); const labels = domain.split('.'); const encoded = map(labels, callback).join('.'); return result + encoded; } /** * Creates an array containing the numeric code points of each Unicode * character in the string. While JavaScript uses UCS-2 internally, * this function will convert a pair of surrogate halves (each of which * UCS-2 exposes as separate characters) into a single code point, * matching UTF-16. * @see `punycode.ucs2.encode` * @see * @memberOf punycode.ucs2 * @name decode * @param {String} string The Unicode input string (UCS-2). * @returns {Array} The new array of code points. */ function ucs2decode(string) { const output = []; let counter = 0; const length = string.length; while (counter < length) { const value = string.charCodeAt(counter++); if (value >= 0xD800 && value <= 0xDBFF && counter < length) { // It's a high surrogate, and there is a next character. const extra = string.charCodeAt(counter++); if ((extra & 0xFC00) == 0xDC00) { // Low surrogate. output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000); } else { // It's an unmatched surrogate; only append this code unit, in case the // next code unit is the high surrogate of a surrogate pair. output.push(value); counter--; } } else { output.push(value); } } return output; } /** * Creates a string based on an array of numeric code points. * @see `punycode.ucs2.decode` * @memberOf punycode.ucs2 * @name encode * @param {Array} codePoints The array of numeric code points. * @returns {String} The new Unicode string (UCS-2). */ const ucs2encode = codePoints => String.fromCodePoint(...codePoints); /** * Converts a basic code point into a digit/integer. * @see `digitToBasic()` * @private * @param {Number} codePoint The basic numeric code point value. * @returns {Number} The numeric value of a basic code point (for use in * representing integers) in the range `0` to `base - 1`, or `base` if * the code point does not represent a value. */ const basicToDigit = function(codePoint) { if (codePoint >= 0x30 && codePoint < 0x3A) { return 26 + (codePoint - 0x30); } if (codePoint >= 0x41 && codePoint < 0x5B) { return codePoint - 0x41; } if (codePoint >= 0x61 && codePoint < 0x7B) { return codePoint - 0x61; } return base; }; /** * Converts a digit/integer into a basic code point. * @see `basicToDigit()` * @private * @param {Number} digit The numeric value of a basic code point. * @returns {Number} The basic code point whose value (when used for * representing integers) is `digit`, which needs to be in the range * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is * used; else, the lowercase form is used. The behavior is undefined * if `flag` is non-zero and `digit` has no uppercase form. */ const digitToBasic = function(digit, flag) { // 0..25 map to ASCII a..z or A..Z // 26..35 map to ASCII 0..9 return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5); }; /** * Bias adaptation function as per section 3.4 of RFC 3492. * https://tools.ietf.org/html/rfc3492#section-3.4 * @private */ const adapt = function(delta, numPoints, firstTime) { let k = 0; delta = firstTime ? floor(delta / damp) : delta >> 1; delta += floor(delta / numPoints); for (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) { delta = floor(delta / baseMinusTMin); } return floor(k + (baseMinusTMin + 1) * delta / (delta + skew)); }; /** * Converts a Punycode string of ASCII-only symbols to a string of Unicode * symbols. * @memberOf punycode * @param {String} input The Punycode string of ASCII-only symbols. * @returns {String} The resulting string of Unicode symbols. */ const decode = function(input) { // Don't use UCS-2. const output = []; const inputLength = input.length; let i = 0; let n = initialN; let bias = initialBias; // Handle the basic code points: let `basic` be the number of input code // points before the last delimiter, or `0` if there is none, then copy // the first basic code points to the output. let basic = input.lastIndexOf(delimiter); if (basic < 0) { basic = 0; } for (let j = 0; j < basic; ++j) { // if it's not a basic code point if (input.charCodeAt(j) >= 0x80) { error$1('not-basic'); } output.push(input.charCodeAt(j)); } // Main decoding loop: start just after the last delimiter if any basic code // points were copied; start at the beginning otherwise. for (let index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) { // `index` is the index of the next character to be consumed. // Decode a generalized variable-length integer into `delta`, // which gets added to `i`. The overflow checking is easier // if we increase `i` as we go, then subtract off its starting // value at the end to obtain `delta`. const oldi = i; for (let w = 1, k = base; /* no condition */; k += base) { if (index >= inputLength) { error$1('invalid-input'); } const digit = basicToDigit(input.charCodeAt(index++)); if (digit >= base) { error$1('invalid-input'); } if (digit > floor((maxInt - i) / w)) { error$1('overflow'); } i += digit * w; const t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias); if (digit < t) { break; } const baseMinusT = base - t; if (w > floor(maxInt / baseMinusT)) { error$1('overflow'); } w *= baseMinusT; } const out = output.length + 1; bias = adapt(i - oldi, out, oldi == 0); // `i` was supposed to wrap around from `out` to `0`, // incrementing `n` each time, so we'll fix that now: if (floor(i / out) > maxInt - n) { error$1('overflow'); } n += floor(i / out); i %= out; // Insert `n` at position `i` of the output. output.splice(i++, 0, n); } return String.fromCodePoint(...output); }; /** * Converts a string of Unicode symbols (e.g. a domain name label) to a * Punycode string of ASCII-only symbols. * @memberOf punycode * @param {String} input The string of Unicode symbols. * @returns {String} The resulting Punycode string of ASCII-only symbols. */ const encode = function(input) { const output = []; // Convert the input in UCS-2 to an array of Unicode code points. input = ucs2decode(input); // Cache the length. const inputLength = input.length; // Initialize the state. let n = initialN; let delta = 0; let bias = initialBias; // Handle the basic code points. for (const currentValue of input) { if (currentValue < 0x80) { output.push(stringFromCharCode(currentValue)); } } const basicLength = output.length; let handledCPCount = basicLength; // `handledCPCount` is the number of code points that have been handled; // `basicLength` is the number of basic code points. // Finish the basic string with a delimiter unless it's empty. if (basicLength) { output.push(delimiter); } // Main encoding loop: while (handledCPCount < inputLength) { // All non-basic code points < n have been handled already. Find the next // larger one: let m = maxInt; for (const currentValue of input) { if (currentValue >= n && currentValue < m) { m = currentValue; } } // Increase `delta` enough to advance the decoder's state to , // but guard against overflow. const handledCPCountPlusOne = handledCPCount + 1; if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) { error$1('overflow'); } delta += (m - n) * handledCPCountPlusOne; n = m; for (const currentValue of input) { if (currentValue < n && ++delta > maxInt) { error$1('overflow'); } if (currentValue === n) { // Represent delta as a generalized variable-length integer. let q = delta; for (let k = base; /* no condition */; k += base) { const t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias); if (q < t) { break; } const qMinusT = q - t; const baseMinusT = base - t; output.push( stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0)) ); q = floor(qMinusT / baseMinusT); } output.push(stringFromCharCode(digitToBasic(q, 0))); bias = adapt(delta, handledCPCountPlusOne, handledCPCount === basicLength); delta = 0; ++handledCPCount; } } ++delta; ++n; } return output.join(''); }; /** * Converts a Punycode string representing a domain name or an email address * to Unicode. Only the Punycoded parts of the input will be converted, i.e. * it doesn't matter if you call it on a string that has already been * converted to Unicode. * @memberOf punycode * @param {String} input The Punycoded domain name or email address to * convert to Unicode. * @returns {String} The Unicode representation of the given Punycode * string. */ const toUnicode = function(input) { return mapDomain(input, function(string) { return regexPunycode.test(string) ? decode(string.slice(4).toLowerCase()) : string; }); }; /** * Converts a Unicode string representing a domain name or an email address to * Punycode. Only the non-ASCII parts of the domain name will be converted, * i.e. it doesn't matter if you call it with a domain that's already in * ASCII. * @memberOf punycode * @param {String} input The domain name or email address to convert, as a * Unicode string. * @returns {String} The Punycode representation of the given domain name or * email address. */ const toASCII = function(input) { return mapDomain(input, function(string) { return regexNonASCII.test(string) ? 'xn--' + encode(string) : string; }); }; /*--------------------------------------------------------------------------*/ /** Define the public API */ const punycode = { /** * A string representing the current Punycode.js version number. * @memberOf punycode * @type String */ 'version': '2.3.1', /** * An object of methods to convert from JavaScript's internal character * representation (UCS-2) to Unicode code points, and back. * @see * @memberOf punycode * @type Object */ 'ucs2': { 'decode': ucs2decode, 'encode': ucs2encode }, 'decode': decode, 'encode': encode, 'toASCII': toASCII, 'toUnicode': toUnicode }; // markdown-it default options var cfg_default = { options: { // Enable HTML tags in source html: false, // Use '/' to close single tags (
) xhtmlOut: false, // Convert '\n' in paragraphs into
breaks: false, // CSS language prefix for fenced blocks langPrefix: 'language-', // autoconvert URL-like texts to links linkify: false, // Enable some language-neutral replacements + quotes beautification typographer: false, // Double + single quotes replacement pairs, when typographer enabled, // and smartquotes on. Could be either a String or an Array. // // For example, you can use '«»„“' for Russian, '„“‚‘' for German, // and ['«\xA0', '\xA0»', '‹\xA0', '\xA0›'] for French (including nbsp). quotes: '\u201c\u201d\u2018\u2019', /* “”‘’ */ // Highlighter function. Should return escaped HTML, // or '' if the source string is not changed and should be escaped externaly. // If result starts with ) xhtmlOut: false, // Convert '\n' in paragraphs into
breaks: false, // CSS language prefix for fenced blocks langPrefix: 'language-', // autoconvert URL-like texts to links linkify: false, // Enable some language-neutral replacements + quotes beautification typographer: false, // Double + single quotes replacement pairs, when typographer enabled, // and smartquotes on. Could be either a String or an Array. // // For example, you can use '«»„“' for Russian, '„“‚‘' for German, // and ['«\xA0', '\xA0»', '‹\xA0', '\xA0›'] for French (including nbsp). quotes: '\u201c\u201d\u2018\u2019', /* “”‘’ */ // Highlighter function. Should return escaped HTML, // or '' if the source string is not changed and should be escaped externaly. // If result starts with ) xhtmlOut: true, // Convert '\n' in paragraphs into
breaks: false, // CSS language prefix for fenced blocks langPrefix: 'language-', // autoconvert URL-like texts to links linkify: false, // Enable some language-neutral replacements + quotes beautification typographer: false, // Double + single quotes replacement pairs, when typographer enabled, // and smartquotes on. Could be either a String or an Array. // // For example, you can use '«»„“' for Russian, '„“‚‘' for German, // and ['«\xA0', '\xA0»', '‹\xA0', '\xA0›'] for French (including nbsp). quotes: '\u201c\u201d\u2018\u2019', /* “”‘’ */ // Highlighter function. Should return escaped HTML, // or '' if the source string is not changed and should be escaped externaly. // If result starts with = 0) { try { parsed.hostname = punycode.toASCII(parsed.hostname); } catch (er) { /**/ } } } return encode$1(format(parsed)) } function normalizeLinkText (url) { const parsed = urlParse(url, true); if (parsed.hostname) { // Encode hostnames in urls like: // `http://host/`, `https://host/`, `mailto:user@host`, `//host/` // // We don't encode unknown schemas, because it's likely that we encode // something we shouldn't (e.g. `skype:name` treated as `skype:host`) // if (!parsed.protocol || RECODE_HOSTNAME_FOR.indexOf(parsed.protocol) >= 0) { try { parsed.hostname = punycode.toUnicode(parsed.hostname); } catch (er) { /**/ } } } // add '%' to exclude list because of https://github.com/markdown-it/markdown-it/issues/720 return decode$1(format(parsed), decode$1.defaultChars + '%') } /** * class MarkdownIt * * Main parser/renderer class. * * ##### Usage * * ```javascript * // node.js, "classic" way: * var MarkdownIt = require('markdown-it'), * md = new MarkdownIt(); * var result = md.render('# markdown-it rulezz!'); * * // node.js, the same, but with sugar: * var md = require('markdown-it')(); * var result = md.render('# markdown-it rulezz!'); * * // browser without AMD, added to "window" on script load * // Note, there are no dash. * var md = window.markdownit(); * var result = md.render('# markdown-it rulezz!'); * ``` * * Single line rendering, without paragraph wrap: * * ```javascript * var md = require('markdown-it')(); * var result = md.renderInline('__markdown-it__ rulezz!'); * ``` **/ /** * new MarkdownIt([presetName, options]) * - presetName (String): optional, `commonmark` / `zero` * - options (Object) * * Creates parser instanse with given config. Can be called without `new`. * * ##### presetName * * MarkdownIt provides named presets as a convenience to quickly * enable/disable active syntax rules and options for common use cases. * * - ["commonmark"](https://github.com/markdown-it/markdown-it/blob/master/lib/presets/commonmark.mjs) - * configures parser to strict [CommonMark](http://commonmark.org/) mode. * - [default](https://github.com/markdown-it/markdown-it/blob/master/lib/presets/default.mjs) - * similar to GFM, used when no preset name given. Enables all available rules, * but still without html, typographer & autolinker. * - ["zero"](https://github.com/markdown-it/markdown-it/blob/master/lib/presets/zero.mjs) - * all rules disabled. Useful to quickly setup your config via `.enable()`. * For example, when you need only `bold` and `italic` markup and nothing else. * * ##### options: * * - __html__ - `false`. Set `true` to enable HTML tags in source. Be careful! * That's not safe! You may need external sanitizer to protect output from XSS. * It's better to extend features via plugins, instead of enabling HTML. * - __xhtmlOut__ - `false`. Set `true` to add '/' when closing single tags * (`
`). This is needed only for full CommonMark compatibility. In real * world you will need HTML output. * - __breaks__ - `false`. Set `true` to convert `\n` in paragraphs into `
`. * - __langPrefix__ - `language-`. CSS language class prefix for fenced blocks. * Can be useful for external highlighters. * - __linkify__ - `false`. Set `true` to autoconvert URL-like text to links. * - __typographer__ - `false`. Set `true` to enable [some language-neutral * replacement](https://github.com/markdown-it/markdown-it/blob/master/lib/rules_core/replacements.mjs) + * quotes beautification (smartquotes). * - __quotes__ - `“”‘’`, String or Array. Double + single quotes replacement * pairs, when typographer enabled and smartquotes on. For example, you can * use `'«»„“'` for Russian, `'„“‚‘'` for German, and * `['«\xA0', '\xA0»', '‹\xA0', '\xA0›']` for French (including nbsp). * - __highlight__ - `null`. Highlighter function for fenced code blocks. * Highlighter `function (str, lang)` should return escaped HTML. It can also * return empty string if the source was not changed and should be escaped * externaly. If result starts with ` or ``): * * ```javascript * var hljs = require('highlight.js') // https://highlightjs.org/ * * // Actual default values * var md = require('markdown-it')({ * highlight: function (str, lang) { * if (lang && hljs.getLanguage(lang)) { * try { * return '
' +
 *                hljs.highlight(str, { language: lang, ignoreIllegals: true }).value +
 *                '
'; * } catch (__) {} * } * * return '
' + md.utils.escapeHtml(str) + '
'; * } * }); * ``` * **/ function MarkdownIt (presetName, options) { if (!(this instanceof MarkdownIt)) { return new MarkdownIt(presetName, options) } if (!options) { if (!isString$1(presetName)) { options = presetName || {}; presetName = 'default'; } } /** * MarkdownIt#inline -> ParserInline * * Instance of [[ParserInline]]. You may need it to add new rules when * writing plugins. For simple rules control use [[MarkdownIt.disable]] and * [[MarkdownIt.enable]]. **/ this.inline = new ParserInline(); /** * MarkdownIt#block -> ParserBlock * * Instance of [[ParserBlock]]. You may need it to add new rules when * writing plugins. For simple rules control use [[MarkdownIt.disable]] and * [[MarkdownIt.enable]]. **/ this.block = new ParserBlock(); /** * MarkdownIt#core -> Core * * Instance of [[Core]] chain executor. You may need it to add new rules when * writing plugins. For simple rules control use [[MarkdownIt.disable]] and * [[MarkdownIt.enable]]. **/ this.core = new Core(); /** * MarkdownIt#renderer -> Renderer * * Instance of [[Renderer]]. Use it to modify output look. Or to add rendering * rules for new token types, generated by plugins. * * ##### Example * * ```javascript * var md = require('markdown-it')(); * * function myToken(tokens, idx, options, env, self) { * //... * return result; * }; * * md.renderer.rules['my_token'] = myToken * ``` * * See [[Renderer]] docs and [source code](https://github.com/markdown-it/markdown-it/blob/master/lib/renderer.mjs). **/ this.renderer = new Renderer(); /** * MarkdownIt#linkify -> LinkifyIt * * [linkify-it](https://github.com/markdown-it/linkify-it) instance. * Used by [linkify](https://github.com/markdown-it/markdown-it/blob/master/lib/rules_core/linkify.mjs) * rule. **/ this.linkify = new LinkifyIt(); /** * MarkdownIt#validateLink(url) -> Boolean * * Link validation function. CommonMark allows too much in links. By default * we disable `javascript:`, `vbscript:`, `file:` schemas, and almost all `data:...` schemas * except some embedded image types. * * You can change this behaviour: * * ```javascript * var md = require('markdown-it')(); * // enable everything * md.validateLink = function () { return true; } * ``` **/ this.validateLink = validateLink; /** * MarkdownIt#normalizeLink(url) -> String * * Function used to encode link url to a machine-readable format, * which includes url-encoding, punycode, etc. **/ this.normalizeLink = normalizeLink; /** * MarkdownIt#normalizeLinkText(url) -> String * * Function used to decode link url to a human-readable format` **/ this.normalizeLinkText = normalizeLinkText; // Expose utils & helpers for easy acces from plugins /** * MarkdownIt#utils -> utils * * Assorted utility functions, useful to write plugins. See details * [here](https://github.com/markdown-it/markdown-it/blob/master/lib/common/utils.mjs). **/ this.utils = utils$1; /** * MarkdownIt#helpers -> helpers * * Link components parser functions, useful to write plugins. See details * [here](https://github.com/markdown-it/markdown-it/blob/master/lib/helpers). **/ this.helpers = assign$1({}, helpers); this.options = {}; this.configure(presetName); if (options) { this.set(options); } } /** chainable * MarkdownIt.set(options) * * Set parser options (in the same format as in constructor). Probably, you * will never need it, but you can change options after constructor call. * * ##### Example * * ```javascript * var md = require('markdown-it')() * .set({ html: true, breaks: true }) * .set({ typographer, true }); * ``` * * __Note:__ To achieve the best possible performance, don't modify a * `markdown-it` instance options on the fly. If you need multiple configurations * it's best to create multiple instances and initialize each with separate * config. **/ MarkdownIt.prototype.set = function (options) { assign$1(this.options, options); return this }; /** chainable, internal * MarkdownIt.configure(presets) * * Batch load of all options and compenent settings. This is internal method, * and you probably will not need it. But if you will - see available presets * and data structure [here](https://github.com/markdown-it/markdown-it/tree/master/lib/presets) * * We strongly recommend to use presets instead of direct config loads. That * will give better compatibility with next versions. **/ MarkdownIt.prototype.configure = function (presets) { const self = this; if (isString$1(presets)) { const presetName = presets; presets = config[presetName]; if (!presets) { throw new Error('Wrong `markdown-it` preset "' + presetName + '", check name') } } if (!presets) { throw new Error('Wrong `markdown-it` preset, can\'t be empty') } if (presets.options) { self.set(presets.options); } if (presets.components) { Object.keys(presets.components).forEach(function (name) { if (presets.components[name].rules) { self[name].ruler.enableOnly(presets.components[name].rules); } if (presets.components[name].rules2) { self[name].ruler2.enableOnly(presets.components[name].rules2); } }); } return this }; /** chainable * MarkdownIt.enable(list, ignoreInvalid) * - list (String|Array): rule name or list of rule names to enable * - ignoreInvalid (Boolean): set `true` to ignore errors when rule not found. * * Enable list or rules. It will automatically find appropriate components, * containing rules with given names. If rule not found, and `ignoreInvalid` * not set - throws exception. * * ##### Example * * ```javascript * var md = require('markdown-it')() * .enable(['sub', 'sup']) * .disable('smartquotes'); * ``` **/ MarkdownIt.prototype.enable = function (list, ignoreInvalid) { let result = []; if (!Array.isArray(list)) { list = [list]; } ['core', 'block', 'inline'].forEach(function (chain) { result = result.concat(this[chain].ruler.enable(list, true)); }, this); result = result.concat(this.inline.ruler2.enable(list, true)); const missed = list.filter(function (name) { return result.indexOf(name) < 0 }); if (missed.length && !ignoreInvalid) { throw new Error('MarkdownIt. Failed to enable unknown rule(s): ' + missed) } return this }; /** chainable * MarkdownIt.disable(list, ignoreInvalid) * - list (String|Array): rule name or list of rule names to disable. * - ignoreInvalid (Boolean): set `true` to ignore errors when rule not found. * * The same as [[MarkdownIt.enable]], but turn specified rules off. **/ MarkdownIt.prototype.disable = function (list, ignoreInvalid) { let result = []; if (!Array.isArray(list)) { list = [list]; } ['core', 'block', 'inline'].forEach(function (chain) { result = result.concat(this[chain].ruler.disable(list, true)); }, this); result = result.concat(this.inline.ruler2.disable(list, true)); const missed = list.filter(function (name) { return result.indexOf(name) < 0 }); if (missed.length && !ignoreInvalid) { throw new Error('MarkdownIt. Failed to disable unknown rule(s): ' + missed) } return this }; /** chainable * MarkdownIt.use(plugin, params) * * Load specified plugin with given params into current parser instance. * It's just a sugar to call `plugin(md, params)` with curring. * * ##### Example * * ```javascript * var iterator = require('markdown-it-for-inline'); * var md = require('markdown-it')() * .use(iterator, 'foo_replace', 'text', function (tokens, idx) { * tokens[idx].content = tokens[idx].content.replace(/foo/g, 'bar'); * }); * ``` **/ MarkdownIt.prototype.use = function (plugin /*, params, ... */) { const args = [this].concat(Array.prototype.slice.call(arguments, 1)); plugin.apply(plugin, args); return this }; /** internal * MarkdownIt.parse(src, env) -> Array * - src (String): source string * - env (Object): environment sandbox * * Parse input string and return list of block tokens (special token type * "inline" will contain list of inline tokens). You should not call this * method directly, until you write custom renderer (for example, to produce * AST). * * `env` is used to pass data between "distributed" rules and return additional * metadata like reference info, needed for the renderer. It also can be used to * inject data in specific cases. Usually, you will be ok to pass `{}`, * and then pass updated object to renderer. **/ MarkdownIt.prototype.parse = function (src, env) { if (typeof src !== 'string') { throw new Error('Input data should be a String') } const state = new this.core.State(src, this, env); this.core.process(state); return state.tokens }; /** * MarkdownIt.render(src [, env]) -> String * - src (String): source string * - env (Object): environment sandbox * * Render markdown string into html. It does all magic for you :). * * `env` can be used to inject additional metadata (`{}` by default). * But you will not need it with high probability. See also comment * in [[MarkdownIt.parse]]. **/ MarkdownIt.prototype.render = function (src, env) { env = env || {}; return this.renderer.render(this.parse(src, env), this.options, env) }; /** internal * MarkdownIt.parseInline(src, env) -> Array * - src (String): source string * - env (Object): environment sandbox * * The same as [[MarkdownIt.parse]] but skip all block rules. It returns the * block tokens list with the single `inline` element, containing parsed inline * tokens in `children` property. Also updates `env` object. **/ MarkdownIt.prototype.parseInline = function (src, env) { const state = new this.core.State(src, this, env); state.inlineMode = true; this.core.process(state); return state.tokens }; /** * MarkdownIt.renderInline(src [, env]) -> String * - src (String): source string * - env (Object): environment sandbox * * Similar to [[MarkdownIt.render]] but for single paragraph content. Result * will NOT be wrapped into `

` tags. **/ MarkdownIt.prototype.renderInline = function (src, env) { env = env || {}; return this.renderer.render(this.parseInline(src, env), this.options, env) }; const placeholder = (id, code) => `

${code}
`; const placeholderRe = /
[\s\S]*?<\/code><\/pre>/g;
function randStr() {
  return Math.random().toString(36).slice(2) + Math.random().toString(36).slice(2);
}
class MarkdownItAsync extends MarkdownIt {
  placeholderMap;
  disableWarn = false;
  constructor(...args) {
    const map = /* @__PURE__ */ new Map();
    const options = args.length === 2 ? args[1] : args[0];
    if (options && "highlight" in options)
      options.highlight = wrapHightlight(options.highlight, map);
    super(...args);
    this.placeholderMap = map;
  }
  // implementation
  use(plugin, ...params) {
    return super.use(plugin, ...params);
  }
  render(src, env) {
    if (this.options.warnOnSyncRender && !this.disableWarn) {
      console.warn("[markdown-it-async] Please use `md.renderAsync` instead of `md.render`");
    }
    return super.render(src, env);
  }
  async renderAsync(src, env) {
    this.options.highlight = wrapHightlight(this.options.highlight, this.placeholderMap);
    this.disableWarn = true;
    const result = this.render(src, env);
    this.disableWarn = false;
    return replaceAsync(result, placeholderRe, async (match, id) => {
      if (!this.placeholderMap.has(id))
        throw new Error(`Unknown highlight placeholder id: ${id}`);
      const [promise, _str, lang, _attrs] = this.placeholderMap.get(id);
      const result2 = await promise || "";
      this.placeholderMap.delete(id);
      if (result2.startsWith("${result2}
`; }); } } function replaceAsync(string, searchValue, replacer) { try { if (typeof replacer === "function") { const values = []; String.prototype.replace.call(string, searchValue, (...args) => { values.push(replacer(...args)); return ""; }); return Promise.all(values).then((resolvedValues) => { return String.prototype.replace.call(string, searchValue, () => { return resolvedValues.shift() || ""; }); }); } else { return Promise.resolve( String.prototype.replace.call(string, searchValue, replacer) ); } } catch (error) { return Promise.reject(error); } } const wrappedSet = /* @__PURE__ */ new WeakSet(); function escapeHtml(unsafe) { return unsafe.replace(/&/g, "&").replace(//g, ">").replace(/"/g, """).replace(/'/g, "'"); } function wrapHightlight(highlight, map) { if (!highlight) return void 0; if (wrappedSet.has(highlight)) return highlight; const wrapped = (str, lang, attrs) => { const promise = highlight(str, lang, attrs); if (typeof promise === "string") return promise; const id = randStr(); map.set(id, [promise, str, lang, attrs]); let code = str; if (code.endsWith("\n")) code = code.slice(0, -1); code = escapeHtml(code); return placeholder(id, code); }; wrappedSet.add(wrapped); return wrapped; } var utils = {}; /** * @typedef {import('.').Token} Token * @typedef {import('.').Options} Options * @typedef {import('.').AttributePair} AttributePair * @typedef {import('.').AllowedAttribute} AllowedAttribute * @typedef {import('.').DetectingStrRule} DetectingStrRule */ var hasRequiredUtils; function requireUtils () { if (hasRequiredUtils) return utils; hasRequiredUtils = 1; /** * parse {.class #id key=val} strings * @param {string} str: string to parse * @param {number} start: where to start parsing (including {) * @param {Options} options * @returns {AttributePair[]}: [['key', 'val'], ['class', 'red']] */ utils.getAttrs = function (str, start, options) { // not tab, line feed, form feed, space, solidus, greater than sign, quotation mark, apostrophe and equals sign const allowedKeyChars = /[^\t\n\f />"'=]/; const pairSeparator = ' '; const keySeparator = '='; const classChar = '.'; const idChar = '#'; const attrs = []; let key = ''; let value = ''; let parsingKey = true; let valueInsideQuotes = false; // read inside {} // start + left delimiter length to avoid beginning { // breaks when } is found or end of string for (let i = start + options.leftDelimiter.length; i < str.length; i++) { if (str.slice(i, i + options.rightDelimiter.length) === options.rightDelimiter) { if (key !== '') { attrs.push([key, value]); } break; } const char_ = str.charAt(i); // switch to reading value if equal sign if (char_ === keySeparator && parsingKey) { parsingKey = false; continue; } // {.class} {..css-module} if (char_ === classChar && key === '') { if (str.charAt(i + 1) === classChar) { key = 'css-module'; i += 1; } else { key = 'class'; } parsingKey = false; continue; } // {#id} if (char_ === idChar && key === '') { key = 'id'; parsingKey = false; continue; } // {value="inside quotes"} if (char_ === '"' && value === '' && !valueInsideQuotes) { valueInsideQuotes = true; continue; } if (char_ === '"' && valueInsideQuotes) { valueInsideQuotes = false; continue; } // read next key/value pair if ((char_ === pairSeparator && !valueInsideQuotes)) { if (key === '') { // beginning or ending space: { .red } vs {.red} continue; } attrs.push([key, value]); key = ''; value = ''; parsingKey = true; continue; } // continue if character not allowed if (parsingKey && char_.search(allowedKeyChars) === -1) { continue; } // no other conditions met; append to key/value if (parsingKey) { key += char_; continue; } value += char_; } if (options.allowedAttributes && options.allowedAttributes.length) { const allowedAttributes = options.allowedAttributes; return attrs.filter(function (attrPair) { const attr = attrPair[0]; /** * @param {AllowedAttribute} allowedAttribute */ function isAllowedAttribute (allowedAttribute) { return (attr === allowedAttribute || (allowedAttribute instanceof RegExp && allowedAttribute.test(attr)) ); } return allowedAttributes.some(isAllowedAttribute); }); } return attrs; }; /** * add attributes from [['key', 'val']] list * @param {AttributePair[]} attrs: [['key', 'val']] * @param {Token} token: which token to add attributes * @returns token */ utils.addAttrs = function (attrs, token) { for (let j = 0, l = attrs.length; j < l; ++j) { const key = attrs[j][0]; if (key === 'class') { token.attrJoin('class', attrs[j][1]); } else if (key === 'css-module') { token.attrJoin('css-module', attrs[j][1]); } else { token.attrPush(attrs[j]); } } return token; }; /** * Does string have properly formatted curly? * * start: '{.a} asdf' * end: 'asdf {.a}' * only: '{.a}' * * @param {'start'|'end'|'only'} where to expect {} curly. start, end or only. * @param {Options} options * @return {DetectingStrRule} Function which testes if string has curly. */ utils.hasDelimiters = function (where, options) { if (!where) { throw new Error('Parameter `where` not passed. Should be "start", "end" or "only".'); } /** * @param {string} str * @return {boolean} */ return function (str) { // we need minimum three chars, for example {b} const minCurlyLength = options.leftDelimiter.length + 1 + options.rightDelimiter.length; if (!str || typeof str !== 'string' || str.length < minCurlyLength) { return false; } /** * @param {string} curly */ function validCurlyLength (curly) { const isClass = curly.charAt(options.leftDelimiter.length) === '.'; const isId = curly.charAt(options.leftDelimiter.length) === '#'; return (isClass || isId) ? curly.length >= (minCurlyLength + 1) : curly.length >= minCurlyLength; } let start, end, slice, nextChar; const rightDelimiterMinimumShift = minCurlyLength - options.rightDelimiter.length; switch (where) { case 'start': // first char should be {, } found in char 2 or more slice = str.slice(0, options.leftDelimiter.length); start = slice === options.leftDelimiter ? 0 : -1; end = start === -1 ? -1 : str.indexOf(options.rightDelimiter, rightDelimiterMinimumShift); // check if next character is not one of the delimiters nextChar = str.charAt(end + options.rightDelimiter.length); if (nextChar && options.rightDelimiter.indexOf(nextChar) !== -1) { end = -1; } break; case 'end': // last char should be } start = str.lastIndexOf(options.leftDelimiter); end = start === -1 ? -1 : str.indexOf(options.rightDelimiter, start + rightDelimiterMinimumShift); end = end === str.length - options.rightDelimiter.length ? end : -1; break; case 'only': // '{.a}' slice = str.slice(0, options.leftDelimiter.length); start = slice === options.leftDelimiter ? 0 : -1; slice = str.slice(str.length - options.rightDelimiter.length); end = slice === options.rightDelimiter ? str.length - options.rightDelimiter.length : -1; break; default: throw new Error(`Unexpected case ${where}, expected 'start', 'end' or 'only'`); } return start !== -1 && end !== -1 && validCurlyLength(str.substring(start, end + options.rightDelimiter.length)); }; }; /** * Removes last curly from string. * @param {string} str * @param {Options} options */ utils.removeDelimiter = function (str, options) { const start = escapeRegExp(options.leftDelimiter); const end = escapeRegExp(options.rightDelimiter); const curly = new RegExp( '[ \\n]?' + start + '[^' + start + end + ']+' + end + '$' ); const pos = str.search(curly); return pos !== -1 ? str.slice(0, pos) : str; }; /** * Escapes special characters in string s such that the string * can be used in `new RegExp`. For example "[" becomes "\\[". * * @param {string} s Regex string. * @return {string} Escaped string. */ function escapeRegExp (s) { return s.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&'); } utils.escapeRegExp = escapeRegExp; /** * find corresponding opening block * @param {Token[]} tokens * @param {number} i */ utils.getMatchingOpeningToken = function (tokens, i) { if (tokens[i].type === 'softbreak') { return false; } // non closing blocks, example img if (tokens[i].nesting === 0) { return tokens[i]; } const level = tokens[i].level; const type = tokens[i].type.replace('_close', '_open'); for (; i >= 0; --i) { if (tokens[i].type === type && tokens[i].level === level) { return tokens[i]; } } return false; }; /** * from https://github.com/markdown-it/markdown-it/blob/master/lib/common/utils.js */ const HTML_ESCAPE_TEST_RE = /[&<>"]/; const HTML_ESCAPE_REPLACE_RE = /[&<>"]/g; const HTML_REPLACEMENTS = { '&': '&', '<': '<', '>': '>', '"': '"' }; /** * @param {string} ch * @returns {string} */ function replaceUnsafeChar(ch) { return HTML_REPLACEMENTS[ch]; } /** * @param {string} str * @returns {string} */ utils.escapeHtml = function (str) { if (HTML_ESCAPE_TEST_RE.test(str)) { return str.replace(HTML_ESCAPE_REPLACE_RE, replaceUnsafeChar); } return str; }; return utils; } var patterns; var hasRequiredPatterns; function requirePatterns () { if (hasRequiredPatterns) return patterns; hasRequiredPatterns = 1; /** * If a pattern matches the token stream, * then run transform. */ const utils = requireUtils(); /** * @param {import('.').Options} options * @returns {import('.').CurlyAttrsPattern[]} */ patterns = options => { const __hr = new RegExp('^ {0,3}[-*_]{3,} ?' + utils.escapeRegExp(options.leftDelimiter) + '[^' + utils.escapeRegExp(options.rightDelimiter) + ']'); return ([ { /** * ```python {.cls} * for i in range(10): * print(i) * ``` */ name: 'fenced code blocks', tests: [ { shift: 0, block: true, info: utils.hasDelimiters('end', options), markup: (str) => !/^[`~]{3,}$/.test(str) } ], transform: (tokens, i) => { const token = tokens[i]; const start = token.info.lastIndexOf(options.leftDelimiter); const attrs = utils.getAttrs(token.info, start, options); utils.addAttrs(attrs, token); token.info = utils.removeDelimiter(token.info, options); } }, { /** * bla `click()`{.c} ![](img.png){.d} * * differs from 'inline attributes' as it does * not have a closing tag (nesting: -1) */ name: 'inline nesting 0', tests: [ { shift: 0, type: 'inline', children: [ { shift: -1, type: (str) => str === 'image' || str === 'code_inline' }, { shift: 0, type: 'text', content: utils.hasDelimiters('start', options) } ] } ], /** * @param {!number} j */ transform: (tokens, i, j) => { const token = tokens[i].children[j]; const endChar = token.content.indexOf(options.rightDelimiter); const attrToken = tokens[i].children[j - 1]; const attrs = utils.getAttrs(token.content, 0, options); utils.addAttrs(attrs, attrToken); if (token.content.length === (endChar + options.rightDelimiter.length)) { tokens[i].children.splice(j, 1); } else { token.content = token.content.slice(endChar + options.rightDelimiter.length); } } }, { /** * | h1 | * | -- | * | c1 | * * {.c} */ name: 'tables', tests: [ { // let this token be i, such that for-loop continues at // next token after tokens.splice shift: 0, type: 'table_close' }, { shift: 1, type: 'paragraph_open' }, { shift: 2, type: 'inline', content: utils.hasDelimiters('only', options) } ], transform: (tokens, i) => { const token = tokens[i + 2]; const tableOpen = utils.getMatchingOpeningToken(tokens, i); const attrs = utils.getAttrs(token.content, 0, options); // add attributes utils.addAttrs(attrs, tableOpen); // remove

{.c}

tokens.splice(i + 1, 3); } }, { /** * | A | B | * | -- | -- | * | 1 | 2 | * * | C | D | * | -- | -- | * * only `| A | B |` sets the colsnum metadata */ name: 'tables thead metadata', tests: [ { shift: 0, type: 'tr_close', }, { shift: 1, type: 'thead_close' }, { shift: 2, type: 'tbody_open' } ], transform: (tokens, i) => { const tr = utils.getMatchingOpeningToken(tokens, i); const th = tokens[i - 1]; let colsnum = 0; let n = i; while (--n) { if (tokens[n] === tr) { tokens[n - 1].meta = Object.assign({}, tokens[n + 2].meta, { colsnum }); break; } colsnum += (tokens[n].level === th.level && tokens[n].type === th.type) >> 0; } tokens[i + 2].meta = Object.assign({}, tokens[i + 2].meta, { colsnum }); } }, { /** * | A | B | C | D | * | -- | -- | -- | -- | * | 1 | 11 | 111 | 1111 {rowspan=3} | * | 2 {colspan=2 rowspan=2} | 22 | 222 | 2222 | * | 3 | 33 | 333 | 3333 | */ name: 'tables tbody calculate', tests: [ { shift: 0, type: 'tbody_close', hidden: false } ], /** * @param {number} i index of the tbody ending */ transform: (tokens, i) => { /** index of the tbody beginning */ let idx = i - 2; while (idx > 0 && 'tbody_open' !== tokens[--idx].type); const calc = tokens[idx].meta.colsnum >> 0; if (calc < 2) { return; } const level = tokens[i].level + 2; for (let n = idx; n < i; n++) { if (tokens[n].level > level) { continue; } const token = tokens[n]; const rows = token.hidden ? 0 : token.attrGet('rowspan') >> 0; const cols = token.hidden ? 0 : token.attrGet('colspan') >> 0; if (rows > 1) { let colsnum = calc - (cols > 0 ? cols : 1); for (let k = n, num = rows; num > 1; k++) { if ('tr_open' == tokens[k].type) { tokens[k].meta = Object.assign({}, tokens[k].meta); if (tokens[k].meta && tokens[k].meta.colsnum) { colsnum -= 1; } tokens[k].meta.colsnum = colsnum; num--; } } } if ('tr_open' == token.type && token.meta && token.meta.colsnum) { const max = token.meta.colsnum; for (let k = n, num = 0; k < i; k++) { if ('td_open' == tokens[k].type) { num += 1; } else if ('tr_close' == tokens[k].type) { break; } num > max && (tokens[k].hidden || hidden(tokens[k])); } } if (cols > 1) { /** @type {number[]} index of one row's children */ const one = []; /** last index of the row's children */ let end = n + 3; /** number of the row's children */ let num = calc; for (let k = n; k > idx; k--) { if ('tr_open' == tokens[k].type) { num = tokens[k].meta && tokens[k].meta.colsnum || num; break; } else if ('td_open' === tokens[k].type) { one.unshift(k); } } for (let k = n + 2; k < i; k++) { if ('tr_close' == tokens[k].type) { end = k; break; } else if ('td_open' == tokens[k].type) { one.push(k); } } const off = one.indexOf(n); let real = num - off; real = real > cols ? cols : real; cols > real && token.attrSet('colspan', real + ''); for (let k = one.slice(num + 1 - calc - real)[0]; k < end; k++) { tokens[k].hidden || hidden(tokens[k]); } } } } }, { /** * *emphasis*{.with attrs=1} */ name: 'inline attributes', tests: [ { shift: 0, type: 'inline', children: [ { shift: -1, nesting: -1 // closing inline tag, {.a} }, { shift: 0, type: 'text', content: utils.hasDelimiters('start', options) } ] } ], /** * @param {!number} j */ transform: (tokens, i, j) => { const token = tokens[i].children[j]; const content = token.content; const attrs = utils.getAttrs(content, 0, options); const openingToken = utils.getMatchingOpeningToken(tokens[i].children, j - 1); utils.addAttrs(attrs, openingToken); token.content = content.slice(content.indexOf(options.rightDelimiter) + options.rightDelimiter.length); } }, { /** * - item * {.a} */ name: 'list softbreak', tests: [ { shift: -2, type: 'list_item_open' }, { shift: 0, type: 'inline', children: [ { position: -2, type: 'softbreak' }, { position: -1, type: 'text', content: utils.hasDelimiters('only', options) } ] } ], /** * @param {!number} j */ transform: (tokens, i, j) => { const token = tokens[i].children[j]; const content = token.content; const attrs = utils.getAttrs(content, 0, options); let ii = i - 2; while (tokens[ii - 1] && tokens[ii - 1].type !== 'ordered_list_open' && tokens[ii - 1].type !== 'bullet_list_open') { ii--; } utils.addAttrs(attrs, tokens[ii - 1]); tokens[i].children = tokens[i].children.slice(0, -2); } }, { /** * - nested list * - with double \n * {.a} <-- apply to nested ul * * {.b} <-- apply to root
    */ name: 'list double softbreak', tests: [ { // let this token be i = 0 so that we can erase // the

    {.a}

    tokens below shift: 0, type: (str) => str === 'bullet_list_close' || str === 'ordered_list_close' }, { shift: 1, type: 'paragraph_open' }, { shift: 2, type: 'inline', content: utils.hasDelimiters('only', options), children: (arr) => arr.length === 1 }, { shift: 3, type: 'paragraph_close' } ], transform: (tokens, i) => { const token = tokens[i + 2]; const content = token.content; const attrs = utils.getAttrs(content, 0, options); const openingToken = utils.getMatchingOpeningToken(tokens, i); utils.addAttrs(attrs, openingToken); tokens.splice(i + 1, 3); } }, { /** * - end of {.list-item} */ name: 'list item end', tests: [ { shift: -2, type: 'list_item_open' }, { shift: 0, type: 'inline', children: [ { position: -1, type: 'text', content: utils.hasDelimiters('end', options) } ] } ], /** * @param {!number} j */ transform: (tokens, i, j) => { const token = tokens[i].children[j]; const content = token.content; const attrs = utils.getAttrs(content, content.lastIndexOf(options.leftDelimiter), options); utils.addAttrs(attrs, tokens[i - 2]); const trimmed = content.slice(0, content.lastIndexOf(options.leftDelimiter)); token.content = last(trimmed) !== ' ' ? trimmed : trimmed.slice(0, -1); } }, { /** * something with softbreak * {.cls} */ name: '\n{.a} softbreak then curly in start', tests: [ { shift: 0, type: 'inline', children: [ { position: -2, type: 'softbreak' }, { position: -1, type: 'text', content: utils.hasDelimiters('only', options) } ] } ], /** * @param {!number} j */ transform: (tokens, i, j) => { const token = tokens[i].children[j]; const attrs = utils.getAttrs(token.content, 0, options); // find last closing tag let ii = i + 1; while (tokens[ii + 1] && tokens[ii + 1].nesting === -1) { ii++; } const openingToken = utils.getMatchingOpeningToken(tokens, ii); utils.addAttrs(attrs, openingToken); tokens[i].children = tokens[i].children.slice(0, -2); } }, { /** * horizontal rule --- {#id} */ name: 'horizontal rule', tests: [ { shift: 0, type: 'paragraph_open' }, { shift: 1, type: 'inline', children: (arr) => arr.length === 1, content: (str) => str.match(__hr) !== null, }, { shift: 2, type: 'paragraph_close' } ], transform: (tokens, i) => { const token = tokens[i]; token.type = 'hr'; token.tag = 'hr'; token.nesting = 0; const content = tokens[i + 1].content; const start = content.lastIndexOf(options.leftDelimiter); const attrs = utils.getAttrs(content, start, options); utils.addAttrs(attrs, token); token.markup = content; tokens.splice(i + 1, 2); } }, { /** * end of {.block} */ name: 'end of block', tests: [ { shift: 0, type: 'inline', children: [ { position: -1, content: utils.hasDelimiters('end', options), type: (t) => t !== 'code_inline' && t !== 'math_inline' } ] } ], /** * @param {!number} j */ transform: (tokens, i, j) => { const token = tokens[i].children[j]; const content = token.content; const attrs = utils.getAttrs(content, content.lastIndexOf(options.leftDelimiter), options); let ii = i + 1; do if (tokens[ii] && tokens[ii].nesting === -1) { break; } while (ii++ < tokens.length); const openingToken = utils.getMatchingOpeningToken(tokens, ii); utils.addAttrs(attrs, openingToken); const trimmed = content.slice(0, content.lastIndexOf(options.leftDelimiter)); token.content = last(trimmed) !== ' ' ? trimmed : trimmed.slice(0, -1); } } ]); }; // get last element of array or string function last(arr) { return arr.slice(-1)[0]; } /** * Hidden table's cells and them inline children, * specially cast inline's content as empty * to prevent that escapes the table's box model * @see https://github.com/markdown-it/markdown-it/issues/639 * @param {import('.').Token} token */ function hidden(token) { token.hidden = true; token.children && token.children.forEach(t => ( t.content = '', hidden(t), undefined )); } return patterns; } var markdownItAttrs; var hasRequiredMarkdownItAttrs; function requireMarkdownItAttrs () { if (hasRequiredMarkdownItAttrs) return markdownItAttrs; hasRequiredMarkdownItAttrs = 1; const patternsConfig = requirePatterns(); /** * @typedef {import('markdown-it')} MarkdownIt * * @typedef {import('markdown-it/lib/rules_core/state_core.mjs').default} StateCore * * @typedef {import('markdown-it/lib/token.mjs').default} Token * * @typedef {import('markdown-it/lib/token.mjs').Nesting} Nesting * * @typedef {Object} Options * @property {!string} leftDelimiter left delimiter, default is `{`(left curly bracket) * @property {!string} rightDelimiter right delimiter, default is `}`(right curly bracket) * @property {AllowedAttribute[]} allowedAttributes empty means no limit * * @typedef {string|RegExp} AllowedAttribute rule of allowed attribute * * @typedef {[string, string]} AttributePair * * @typedef {[number, number]} SourceLineInfo * * @typedef {Object} CurlyAttrsPattern * @property {string} name * @property {DetectingRule[]} tests * @property {(tokens: Token[], i: number, j?: number) => void} transform * * @typedef {Object} MatchedResult * @property {boolean} match true means matched * @property {number?} j postion index number of Array<{@link Token}> * * @typedef {(str: string) => boolean} DetectingStrRule * * @typedef {Object} DetectingRule rule for testing {@link Token}'s properties * @property {number=} shift offset index number of Array<{@link Token}> * @property {number=} position fixed index number of Array<{@link Token}> * @property {(string | DetectingStrRule)=} type * @property {(string | DetectingStrRule)=} tag * @property {DetectingRule[]=} children * @property {(string | DetectingStrRule)=} content * @property {(string | DetectingStrRule)=} markup * @property {(string | DetectingStrRule)=} info * @property {Nesting=} nesting * @property {number=} level * @property {boolean=} block * @property {boolean=} hidden * @property {AttributePair[]=} attrs * @property {SourceLineInfo[]=} map * @property {any=} meta */ /** @type {Options} */ const defaultOptions = { leftDelimiter: '{', rightDelimiter: '}', allowedAttributes: [] }; /** * @param {MarkdownIt} md * @param {Options=} options_ */ markdownItAttrs = function attributes(md, options_) { let options = Object.assign({}, defaultOptions); options = Object.assign(options, options_); const patterns = patternsConfig(options); /** * @param {StateCore} state */ function curlyAttrs(state) { const tokens = state.tokens; for (let i = 0; i < tokens.length; i++) { for (let p = 0; p < patterns.length; p++) { const pattern = patterns[p]; let j = null; // position of child with offset 0 const match = pattern.tests.every(t => { const res = test(tokens, i, t); if (res.j !== null) { j = res.j; } return res.match; }); if (match) { try { pattern.transform(tokens, i, j); if (pattern.name === 'inline attributes' || pattern.name === 'inline nesting 0') { // retry, may be several inline attributes p--; } } catch (error) { // eslint-disable-next-line no-console console.error(`markdown-it-attrs: Error in pattern '${pattern.name}': ${error.message}`); console.error(error.stack); } } } } } md.core.ruler.before('linkify', 'curly_attributes', curlyAttrs); }; /** * Test if t matches token stream. * * @param {Token[]} tokens * @param {number} i * @param {DetectingRule} t * @returns {MatchedResult} */ function test(tokens, i, t) { /** @type {MatchedResult} */ const res = { match: false, j: null // position of child }; const ii = t.shift !== undefined ? i + t.shift : t.position; if (t.shift !== undefined && ii < 0) { // we should never shift to negative indexes (rolling around to back of array) return res; } const token = get(tokens, ii); // supports negative ii if (token === undefined) { return res; } for (const key of Object.keys(t)) { if (key === 'shift' || key === 'position') { continue; } if (token[key] === undefined) { return res; } if (key === 'children' && isArrayOfObjects(t.children)) { if (token.children.length === 0) { return res; } let match; /** @type {DetectingRule[]} */ const childTests = t.children; /** @type {Token[]} */ const children = token.children; if (childTests.every(tt => tt.position !== undefined)) { // positions instead of shifts, do not loop all children match = childTests.every(tt => test(children, tt.position, tt).match); if (match) { // we may need position of child in transform const j = last(childTests).position; res.j = j >= 0 ? j : children.length + j; } } else { for (let j = 0; j < children.length; j++) { match = childTests.every(tt => test(children, j, tt).match); if (match) { res.j = j; // all tests true, continue with next key of pattern t break; } } } if (match === false) { return res; } continue; } switch (typeof t[key]) { case 'boolean': case 'number': case 'string': if (token[key] !== t[key]) { return res; } break; case 'function': if (!t[key](token[key])) { return res; } break; case 'object': if (isArrayOfFunctions(t[key])) { const r = t[key].every(tt => tt(token[key])); if (r === false) { return res; } break; } // fall through for objects !== arrays of functions default: throw new Error(`Unknown type of pattern test (key: ${key}). Test should be of type boolean, number, string, function or array of functions.`); } } // no tests returned false -> all tests returns true res.match = true; return res; } function isArrayOfObjects(arr) { return Array.isArray(arr) && arr.length && arr.every(i => typeof i === 'object'); } function isArrayOfFunctions(arr) { return Array.isArray(arr) && arr.length && arr.every(i => typeof i === 'function'); } /** * Get n item of array. Supports negative n, where -1 is last * element in array. * @param {Token[]} arr * @param {number} n * @returns {Token=} */ function get(arr, n) { return n >= 0 ? arr[n] : arr[arr.length + n]; } /** * get last element of array, safe - returns {} if not found * @param {DetectingRule[]} arr * @returns {DetectingRule} */ function last(arr) { return arr.slice(-1)[0] || {}; } return markdownItAttrs; } var markdownItAttrsExports = requireMarkdownItAttrs(); var attrsPlugin = /*@__PURE__*/getDefaultExportFromCjs(markdownItAttrsExports); // Generated code. function isAmbiguous(x) { return x === 0xA1 || x === 0xA4 || x === 0xA7 || x === 0xA8 || x === 0xAA || x === 0xAD || x === 0xAE || x >= 0xB0 && x <= 0xB4 || x >= 0xB6 && x <= 0xBA || x >= 0xBC && x <= 0xBF || x === 0xC6 || x === 0xD0 || x === 0xD7 || x === 0xD8 || x >= 0xDE && x <= 0xE1 || x === 0xE6 || x >= 0xE8 && x <= 0xEA || x === 0xEC || x === 0xED || x === 0xF0 || x === 0xF2 || x === 0xF3 || x >= 0xF7 && x <= 0xFA || x === 0xFC || x === 0xFE || x === 0x101 || x === 0x111 || x === 0x113 || x === 0x11B || x === 0x126 || x === 0x127 || x === 0x12B || x >= 0x131 && x <= 0x133 || x === 0x138 || x >= 0x13F && x <= 0x142 || x === 0x144 || x >= 0x148 && x <= 0x14B || x === 0x14D || x === 0x152 || x === 0x153 || x === 0x166 || x === 0x167 || x === 0x16B || x === 0x1CE || x === 0x1D0 || x === 0x1D2 || x === 0x1D4 || x === 0x1D6 || x === 0x1D8 || x === 0x1DA || x === 0x1DC || x === 0x251 || x === 0x261 || x === 0x2C4 || x === 0x2C7 || x >= 0x2C9 && x <= 0x2CB || x === 0x2CD || x === 0x2D0 || x >= 0x2D8 && x <= 0x2DB || x === 0x2DD || x === 0x2DF || x >= 0x300 && x <= 0x36F || x >= 0x391 && x <= 0x3A1 || x >= 0x3A3 && x <= 0x3A9 || x >= 0x3B1 && x <= 0x3C1 || x >= 0x3C3 && x <= 0x3C9 || x === 0x401 || x >= 0x410 && x <= 0x44F || x === 0x451 || x === 0x2010 || x >= 0x2013 && x <= 0x2016 || x === 0x2018 || x === 0x2019 || x === 0x201C || x === 0x201D || x >= 0x2020 && x <= 0x2022 || x >= 0x2024 && x <= 0x2027 || x === 0x2030 || x === 0x2032 || x === 0x2033 || x === 0x2035 || x === 0x203B || x === 0x203E || x === 0x2074 || x === 0x207F || x >= 0x2081 && x <= 0x2084 || x === 0x20AC || x === 0x2103 || x === 0x2105 || x === 0x2109 || x === 0x2113 || x === 0x2116 || x === 0x2121 || x === 0x2122 || x === 0x2126 || x === 0x212B || x === 0x2153 || x === 0x2154 || x >= 0x215B && x <= 0x215E || x >= 0x2160 && x <= 0x216B || x >= 0x2170 && x <= 0x2179 || x === 0x2189 || x >= 0x2190 && x <= 0x2199 || x === 0x21B8 || x === 0x21B9 || x === 0x21D2 || x === 0x21D4 || x === 0x21E7 || x === 0x2200 || x === 0x2202 || x === 0x2203 || x === 0x2207 || x === 0x2208 || x === 0x220B || x === 0x220F || x === 0x2211 || x === 0x2215 || x === 0x221A || x >= 0x221D && x <= 0x2220 || x === 0x2223 || x === 0x2225 || x >= 0x2227 && x <= 0x222C || x === 0x222E || x >= 0x2234 && x <= 0x2237 || x === 0x223C || x === 0x223D || x === 0x2248 || x === 0x224C || x === 0x2252 || x === 0x2260 || x === 0x2261 || x >= 0x2264 && x <= 0x2267 || x === 0x226A || x === 0x226B || x === 0x226E || x === 0x226F || x === 0x2282 || x === 0x2283 || x === 0x2286 || x === 0x2287 || x === 0x2295 || x === 0x2299 || x === 0x22A5 || x === 0x22BF || x === 0x2312 || x >= 0x2460 && x <= 0x24E9 || x >= 0x24EB && x <= 0x254B || x >= 0x2550 && x <= 0x2573 || x >= 0x2580 && x <= 0x258F || x >= 0x2592 && x <= 0x2595 || x === 0x25A0 || x === 0x25A1 || x >= 0x25A3 && x <= 0x25A9 || x === 0x25B2 || x === 0x25B3 || x === 0x25B6 || x === 0x25B7 || x === 0x25BC || x === 0x25BD || x === 0x25C0 || x === 0x25C1 || x >= 0x25C6 && x <= 0x25C8 || x === 0x25CB || x >= 0x25CE && x <= 0x25D1 || x >= 0x25E2 && x <= 0x25E5 || x === 0x25EF || x === 0x2605 || x === 0x2606 || x === 0x2609 || x === 0x260E || x === 0x260F || x === 0x261C || x === 0x261E || x === 0x2640 || x === 0x2642 || x === 0x2660 || x === 0x2661 || x >= 0x2663 && x <= 0x2665 || x >= 0x2667 && x <= 0x266A || x === 0x266C || x === 0x266D || x === 0x266F || x === 0x269E || x === 0x269F || x === 0x26BF || x >= 0x26C6 && x <= 0x26CD || x >= 0x26CF && x <= 0x26D3 || x >= 0x26D5 && x <= 0x26E1 || x === 0x26E3 || x === 0x26E8 || x === 0x26E9 || x >= 0x26EB && x <= 0x26F1 || x === 0x26F4 || x >= 0x26F6 && x <= 0x26F9 || x === 0x26FB || x === 0x26FC || x === 0x26FE || x === 0x26FF || x === 0x273D || x >= 0x2776 && x <= 0x277F || x >= 0x2B56 && x <= 0x2B59 || x >= 0x3248 && x <= 0x324F || x >= 0xE000 && x <= 0xF8FF || x >= 0xFE00 && x <= 0xFE0F || x === 0xFFFD || x >= 0x1F100 && x <= 0x1F10A || x >= 0x1F110 && x <= 0x1F12D || x >= 0x1F130 && x <= 0x1F169 || x >= 0x1F170 && x <= 0x1F18D || x === 0x1F18F || x === 0x1F190 || x >= 0x1F19B && x <= 0x1F1AC || x >= 0xE0100 && x <= 0xE01EF || x >= 0xF0000 && x <= 0xFFFFD || x >= 0x100000 && x <= 0x10FFFD; } function isFullWidth(x) { return x === 0x3000 || x >= 0xFF01 && x <= 0xFF60 || x >= 0xFFE0 && x <= 0xFFE6; } function isWide(x) { return x >= 0x1100 && x <= 0x115F || x === 0x231A || x === 0x231B || x === 0x2329 || x === 0x232A || x >= 0x23E9 && x <= 0x23EC || x === 0x23F0 || x === 0x23F3 || x === 0x25FD || x === 0x25FE || x === 0x2614 || x === 0x2615 || x >= 0x2630 && x <= 0x2637 || x >= 0x2648 && x <= 0x2653 || x === 0x267F || x >= 0x268A && x <= 0x268F || x === 0x2693 || x === 0x26A1 || x === 0x26AA || x === 0x26AB || x === 0x26BD || x === 0x26BE || x === 0x26C4 || x === 0x26C5 || x === 0x26CE || x === 0x26D4 || x === 0x26EA || x === 0x26F2 || x === 0x26F3 || x === 0x26F5 || x === 0x26FA || x === 0x26FD || x === 0x2705 || x === 0x270A || x === 0x270B || x === 0x2728 || x === 0x274C || x === 0x274E || x >= 0x2753 && x <= 0x2755 || x === 0x2757 || x >= 0x2795 && x <= 0x2797 || x === 0x27B0 || x === 0x27BF || x === 0x2B1B || x === 0x2B1C || x === 0x2B50 || x === 0x2B55 || x >= 0x2E80 && x <= 0x2E99 || x >= 0x2E9B && x <= 0x2EF3 || x >= 0x2F00 && x <= 0x2FD5 || x >= 0x2FF0 && x <= 0x2FFF || x >= 0x3001 && x <= 0x303E || x >= 0x3041 && x <= 0x3096 || x >= 0x3099 && x <= 0x30FF || x >= 0x3105 && x <= 0x312F || x >= 0x3131 && x <= 0x318E || x >= 0x3190 && x <= 0x31E5 || x >= 0x31EF && x <= 0x321E || x >= 0x3220 && x <= 0x3247 || x >= 0x3250 && x <= 0xA48C || x >= 0xA490 && x <= 0xA4C6 || x >= 0xA960 && x <= 0xA97C || x >= 0xAC00 && x <= 0xD7A3 || x >= 0xF900 && x <= 0xFAFF || x >= 0xFE10 && x <= 0xFE19 || x >= 0xFE30 && x <= 0xFE52 || x >= 0xFE54 && x <= 0xFE66 || x >= 0xFE68 && x <= 0xFE6B || x >= 0x16FE0 && x <= 0x16FE4 || x >= 0x16FF0 && x <= 0x16FF6 || x >= 0x17000 && x <= 0x18CD5 || x >= 0x18CFF && x <= 0x18D1E || x >= 0x18D80 && x <= 0x18DF2 || x >= 0x1AFF0 && x <= 0x1AFF3 || x >= 0x1AFF5 && x <= 0x1AFFB || x === 0x1AFFD || x === 0x1AFFE || x >= 0x1B000 && x <= 0x1B122 || x === 0x1B132 || x >= 0x1B150 && x <= 0x1B152 || x === 0x1B155 || x >= 0x1B164 && x <= 0x1B167 || x >= 0x1B170 && x <= 0x1B2FB || x >= 0x1D300 && x <= 0x1D356 || x >= 0x1D360 && x <= 0x1D376 || x === 0x1F004 || x === 0x1F0CF || x === 0x1F18E || x >= 0x1F191 && x <= 0x1F19A || x >= 0x1F200 && x <= 0x1F202 || x >= 0x1F210 && x <= 0x1F23B || x >= 0x1F240 && x <= 0x1F248 || x === 0x1F250 || x === 0x1F251 || x >= 0x1F260 && x <= 0x1F265 || x >= 0x1F300 && x <= 0x1F320 || x >= 0x1F32D && x <= 0x1F335 || x >= 0x1F337 && x <= 0x1F37C || x >= 0x1F37E && x <= 0x1F393 || x >= 0x1F3A0 && x <= 0x1F3CA || x >= 0x1F3CF && x <= 0x1F3D3 || x >= 0x1F3E0 && x <= 0x1F3F0 || x === 0x1F3F4 || x >= 0x1F3F8 && x <= 0x1F43E || x === 0x1F440 || x >= 0x1F442 && x <= 0x1F4FC || x >= 0x1F4FF && x <= 0x1F53D || x >= 0x1F54B && x <= 0x1F54E || x >= 0x1F550 && x <= 0x1F567 || x === 0x1F57A || x === 0x1F595 || x === 0x1F596 || x === 0x1F5A4 || x >= 0x1F5FB && x <= 0x1F64F || x >= 0x1F680 && x <= 0x1F6C5 || x === 0x1F6CC || x >= 0x1F6D0 && x <= 0x1F6D2 || x >= 0x1F6D5 && x <= 0x1F6D8 || x >= 0x1F6DC && x <= 0x1F6DF || x === 0x1F6EB || x === 0x1F6EC || x >= 0x1F6F4 && x <= 0x1F6FC || x >= 0x1F7E0 && x <= 0x1F7EB || x === 0x1F7F0 || x >= 0x1F90C && x <= 0x1F93A || x >= 0x1F93C && x <= 0x1F945 || x >= 0x1F947 && x <= 0x1F9FF || x >= 0x1FA70 && x <= 0x1FA7C || x >= 0x1FA80 && x <= 0x1FA8A || x >= 0x1FA8E && x <= 0x1FAC6 || x === 0x1FAC8 || x >= 0x1FACD && x <= 0x1FADC || x >= 0x1FADF && x <= 0x1FAEA || x >= 0x1FAEF && x <= 0x1FAF8 || x >= 0x20000 && x <= 0x2FFFD || x >= 0x30000 && x <= 0x3FFFD; } function getCategory(x) { if (isAmbiguous(x)) return 'ambiguous'; if (isFullWidth(x)) return 'fullwidth'; if ( x === 0x20A9 || x >= 0xFF61 && x <= 0xFFBE || x >= 0xFFC2 && x <= 0xFFC7 || x >= 0xFFCA && x <= 0xFFCF || x >= 0xFFD2 && x <= 0xFFD7 || x >= 0xFFDA && x <= 0xFFDC || x >= 0xFFE8 && x <= 0xFFEE ) { return 'halfwidth'; } if ( x >= 0x20 && x <= 0x7E || x === 0xA2 || x === 0xA3 || x === 0xA5 || x === 0xA6 || x === 0xAC || x === 0xAF || x >= 0x27E6 && x <= 0x27ED || x === 0x2985 || x === 0x2986 ) { return 'narrow'; } if (isWide(x)) return 'wide'; return 'neutral'; } function validate$1(codePoint) { if (!Number.isSafeInteger(codePoint)) { throw new TypeError(`Expected a code point, got \`${typeof codePoint}\`.`); } } function eastAsianWidthType(codePoint) { validate$1(codePoint); return getCategory(codePoint); } // src/index.ts function isEmoji(uc) { return /^\p{Emoji_Presentation}/u.test(String.fromCodePoint(uc)); } function isCjkBase(uc) { if (uc < 4352) return false; const eaw = eastAsianWidthType(uc); switch (eaw) { case "fullwidth": case "halfwidth": return true; // never be emoji case "wide": return !isEmoji(uc); case "narrow": return false; case "ambiguous": return null; case "neutral": return /^\p{sc=Hangul}/u.test(String.fromCodePoint(uc)); } } function is2PreviousCjk(uc, prev) { return isCjkBase(uc) ?? (prev === 65025 && isQuotationMark(uc)); function isQuotationMark(uc2) { return uc2 === 8216 || uc2 === 8217 || uc2 === 8220 || uc2 === 8221; } } function isPreviousCjk(uc) { return isCjkBase(uc) ?? (917760 <= uc && uc <= 917999); } function isNextCjk(uc) { return isCjkBase(uc) ?? false; } function nonEmojiGeneralUseVS(uc) { return uc >= 65024 && uc <= 65038; } function markdownItCjkFriendlyPlugin(md) { const PreviousState = md.inline.State; class CjFriendlyState extends PreviousState { scanDelims(start, canSplitWord) { const max = this.posMax; const marker = this.src.charCodeAt(start); const [lastChar, lastCharPos] = getLastCharCode(this.src, start); let lastMainChar = lastChar; let twoPrevChar = null; if (nonEmojiGeneralUseVS(lastChar)) { twoPrevChar = getLastCharCode(this.src, lastCharPos)[0]; if (!/^\p{Zs}/u.test(String.fromCodePoint(twoPrevChar))) { lastMainChar = twoPrevChar; } } let pos = start; while (pos < max && this.src.charCodeAt(pos) === marker) { pos++; } const count = pos - start; const nextChar = pos < max ? this.src.codePointAt(pos) : 32; const isLastCJKChar = twoPrevChar !== null ? is2PreviousCjk(twoPrevChar, lastChar) : isPreviousCjk(lastChar); const isNextCJKChar = isNextCjk(nextChar); const isLastPunctChar = isMdAsciiPunct(lastMainChar) || isPunctChar(String.fromCodePoint(lastMainChar)); const isNextPunctChar = isMdAsciiPunct(nextChar) || isPunctChar(String.fromCodePoint(nextChar)); const isLastNonCjkPunctChar = isLastPunctChar && !isLastCJKChar; const isNextNonCjkPunctChar = isNextPunctChar && !isNextCJKChar; const isLastWhiteSpace = isWhiteSpace(lastMainChar); const isNextWhiteSpace = isWhiteSpace(nextChar); const left_flanking = !isNextWhiteSpace && (!isNextNonCjkPunctChar || isLastNonCjkPunctChar || isLastWhiteSpace || isLastCJKChar); const right_flanking = !isLastWhiteSpace && (!isLastNonCjkPunctChar || isNextWhiteSpace || isNextNonCjkPunctChar || isNextCJKChar); const can_open = left_flanking && (canSplitWord || !right_flanking || isLastPunctChar); const can_close = right_flanking && (canSplitWord || !left_flanking || isNextPunctChar); return { can_open, can_close, length: count }; function getLastCharCode(str, pos2) { if (pos2 <= 0) { return [32, -1]; } const charCode = str.charCodeAt(pos2 - 1); if ((charCode & 64512) !== 56320) { return [charCode, pos2 - 1]; } const codePoint = str.codePointAt(pos2 - 2); return codePoint > 65535 ? ( // biome-ignore lint/style/noNonNullAssertion: ditto [codePoint, pos2 - 2] ) : [charCode, pos2 - 1]; } } } md.inline.State = CjFriendlyState; } function emoji_html (tokens, idx /*, options, env */) { return tokens[idx].content } // Emojies & shortcuts replacement logic. // // Note: In theory, it could be faster to parse :smile: in inline chain and // leave only shortcuts here. But, who care... // function create_rule (md, emojies, shortcuts, scanRE, replaceRE) { const arrayReplaceAt = md.utils.arrayReplaceAt; const ucm = md.utils.lib.ucmicro; const has = md.utils.has; const ZPCc = new RegExp([ucm.Z.source, ucm.P.source, ucm.Cc.source].join('|')); function splitTextToken (text, level, Token) { let last_pos = 0; const nodes = []; text.replace(replaceRE, function (match, offset, src) { let emoji_name; // Validate emoji name if (has(shortcuts, match)) { // replace shortcut with full name emoji_name = shortcuts[match]; // Don't allow letters before any shortcut (as in no ":/" in http://) if (offset > 0 && !ZPCc.test(src[offset - 1])) return // Don't allow letters after any shortcut if (offset + match.length < src.length && !ZPCc.test(src[offset + match.length])) { return } } else { emoji_name = match.slice(1, -1); } // Add new tokens to pending list if (offset > last_pos) { const token = new Token('text', '', 0); token.content = text.slice(last_pos, offset); nodes.push(token); } const token = new Token('emoji', '', 0); token.markup = emoji_name; token.content = emojies[emoji_name]; nodes.push(token); last_pos = offset + match.length; }); if (last_pos < text.length) { const token = new Token('text', '', 0); token.content = text.slice(last_pos); nodes.push(token); } return nodes } return function emoji_replace (state) { let token; const blockTokens = state.tokens; let autolinkLevel = 0; for (let j = 0, l = blockTokens.length; j < l; j++) { if (blockTokens[j].type !== 'inline') { continue } let tokens = blockTokens[j].children; // We scan from the end, to keep position when new tags added. // Use reversed logic in links start/end match for (let i = tokens.length - 1; i >= 0; i--) { token = tokens[i]; if (token.type === 'link_open' || token.type === 'link_close') { if (token.info === 'auto') { autolinkLevel -= token.nesting; } } if (token.type === 'text' && autolinkLevel === 0 && scanRE.test(token.content)) { // replace current node blockTokens[j].children = tokens = arrayReplaceAt( tokens, i, splitTextToken(token.content, token.level, state.Token) ); } } } } } // Convert input options to more useable format // and compile search regexp function quoteRE (str) { return str.replace(/[.?*+^$[\]\\(){}|-]/g, '\\$&') } function normalize_opts (options) { let emojies = options.defs; // Filter emojies by whitelist, if needed if (options.enabled.length) { emojies = Object.keys(emojies).reduce((acc, key) => { if (options.enabled.indexOf(key) >= 0) acc[key] = emojies[key]; return acc }, {}); } // Flatten shortcuts to simple object: { alias: emoji_name } const shortcuts = Object.keys(options.shortcuts).reduce((acc, key) => { // Skip aliases for filtered emojies, to reduce regexp if (!emojies[key]) return acc if (Array.isArray(options.shortcuts[key])) { options.shortcuts[key].forEach(alias => { acc[alias] = key; }); return acc } acc[options.shortcuts[key]] = key; return acc }, {}); const keys = Object.keys(emojies); let names; // If no definitions are given, return empty regex to avoid replacements with 'undefined'. if (keys.length === 0) { names = '^$'; } else { // Compile regexp names = keys .map(name => { return `:${name}:` }) .concat(Object.keys(shortcuts)) .sort() .reverse() .map(name => { return quoteRE(name) }) .join('|'); } const scanRE = RegExp(names); const replaceRE = RegExp(names, 'g'); return { defs: emojies, shortcuts, scanRE, replaceRE } } function emoji_plugin$1 (md, options) { const defaults = { defs: {}, shortcuts: {}, enabled: [] }; const opts = normalize_opts(md.utils.assign({}, defaults, options || {})); md.renderer.rules.emoji = emoji_html; md.core.ruler.after( 'linkify', 'emoji', create_rule(md, opts.defs, opts.shortcuts, opts.scanRE, opts.replaceRE) ); } // Emoticons -> Emoji mapping. // // (!) Some patterns skipped, to avoid collisions // without increase matcher complicity. Than can change in future. // // Places to look for more emoticons info: // // - http://en.wikipedia.org/wiki/List_of_emoticons#Western // - https://github.com/wooorm/emoticon/blob/master/Support.md // - http://factoryjoe.com/projects/emoticons/ // /* eslint-disable key-spacing */ var emojies_shortcuts = { angry: ['>:(', '>:-('], blush: [':")', ':-")'], broken_heart: ['= endLine) { // unclosed block should be autoclosed by end of document. // also block seems to be autoclosed by end of parent break } start = state.bMarks[nextLine] + state.tShift[nextLine]; max = state.eMarks[nextLine]; if (start < max && state.sCount[nextLine] < state.blkIndent) { // non-empty line with negative indent should stop the list: // - ``` // test break } if (marker_char !== state.src.charCodeAt(start)) { continue } if (state.sCount[nextLine] - state.blkIndent >= 4) { // closing fence should be indented less than 4 spaces continue } for (pos = start + 1; pos <= max; pos++) { if (marker_str[(pos - start) % marker_len] !== state.src[pos]) { break } } // closing code fence must be at least as long as the opening one if (Math.floor((pos - start) / marker_len) < marker_count) { continue } // make sure tail has spaces only pos -= (pos - start) % marker_len; pos = state.skipSpaces(pos); if (pos < max) { continue } // found! auto_closed = true; break } const old_parent = state.parentType; const old_line_max = state.lineMax; state.parentType = 'container'; // this will prevent lazy continuations from ever going past our end marker state.lineMax = nextLine; const token_o = state.push('container_' + name + '_open', 'div', 1); token_o.markup = markup; token_o.block = true; token_o.info = params; token_o.map = [startLine, nextLine]; state.md.block.tokenize(state, startLine + 1, nextLine); const token_c = state.push('container_' + name + '_close', 'div', -1); token_c.markup = state.src.slice(start, pos); token_c.block = true; state.parentType = old_parent; state.lineMax = old_line_max; state.line = nextLine + (auto_closed ? 1 : 0); return true } md.block.ruler.before('fence', 'container_' + name, container, { alt: ['paragraph', 'reference', 'blockquote', 'list'] }); md.renderer.rules['container_' + name + '_open'] = render; md.renderer.rules['container_' + name + '_close'] = render; } function preWrapperPlugin(md, options) { const langLabel = Object.fromEntries( Object.entries(options.languageLabel || {}).map(([k, v]) => [k.toLowerCase(), v]) ); const fence = md.renderer.rules.fence; md.renderer.rules.fence = (...args) => { const [tokens, idx] = args; const token = tokens[idx]; token.info = token.info.replace(/\[.*\]/, ""); const active = / active( |$)/.test(token.info) ? " active" : ""; token.info = token.info.replace(/ active$/, "").replace(/ active /, " "); const lang = extractLang(token.info); const label = langLabel[lang.toLowerCase()] || lang.replace(/_/g, " "); return `
    ${label}` + fence(...args) + "
    "; }; } function extractTitle(info, html = false) { if (html) { return info.replace(//g, "").match(/data-title="(.*?)"/)?.[1] || ""; } return info.match(/\[(.*)\]/)?.[1] || extractLang(info) || "txt"; } function extractLang(info) { return /^[a-zA-Z0-9-_]+/.exec(info)?.[0].replace(/-vue$/, "").replace(/^vue-html$/, "template").replace(/^ansi$/, "") || ""; } const containerPlugin = (md, options) => { md.use(...createContainer("tip", options?.tipLabel || "TIP", md)).use(...createContainer("info", options?.infoLabel || "INFO", md)).use(...createContainer("warning", options?.warningLabel || "WARNING", md)).use(...createContainer("danger", options?.dangerLabel || "DANGER", md)).use(...createContainer("details", options?.detailsLabel || "Details", md)).use(container_plugin, "v-pre", { render: (tokens, idx) => tokens[idx].nesting === 1 ? `
    ` : `
    ` }).use(container_plugin, "raw", { render: (tokens, idx) => tokens[idx].nesting === 1 ? `
    ` : `
    ` }).use(...createCodeGroup(md)); }; function createContainer(klass, defaultTitle, md) { return [ container_plugin, klass, { render(tokens, idx, _options, env) { const token = tokens[idx]; if (token.nesting === 1) { token.attrJoin("class", `${klass} custom-block`); const attrs = md.renderer.renderAttrs(token); const info = token.info.trim().slice(klass.length).trim(); const title = md.renderInline(info || defaultTitle, { references: env.references }); const titleClass = "custom-block-title" + (info ? "" : " custom-block-title-default"); if (klass === "details") return `
    ${title} `; return `

    ${title}

    `; } else return klass === "details" ? `
    ` : ` `; } } ]; } function createCodeGroup(md) { return [ container_plugin, "code-group", { render(tokens, idx) { if (tokens[idx].nesting === 1) { let tabs = ""; let checked = "checked"; for (let i = idx + 1; !(tokens[i].nesting === -1 && tokens[i].type === "container_code-group_close"); ++i) { const isHtml = tokens[i].type === "html_block"; if (tokens[i].type === "fence" && tokens[i].tag === "code" || isHtml) { const title = extractTitle( isHtml ? tokens[i].content : tokens[i].info, isHtml ); if (title) { tabs += ``; if (checked && !isHtml) tokens[i].info += " active"; checked = ""; } } } return `
    ${tabs}
    `; } return `
    `; } } ]; } const markerRE = /^\[!(TIP|NOTE|INFO|IMPORTANT|WARNING|CAUTION|DANGER)\]([^\n\r]*)/i; const gitHubAlertsPlugin = (md, options) => { const titleMark = { tip: options?.tipLabel || "TIP", note: options?.noteLabel || "NOTE", info: options?.infoLabel || "INFO", important: options?.importantLabel || "IMPORTANT", warning: options?.warningLabel || "WARNING", caution: options?.cautionLabel || "CAUTION", danger: options?.dangerLabel || "DANGER" }; md.core.ruler.after("block", "github-alerts", (state) => { const tokens = state.tokens; for (let i = 0; i < tokens.length; i++) { if (tokens[i].type === "blockquote_open") { const startIndex = i; const open = tokens[startIndex]; let endIndex = i + 1; while (endIndex < tokens.length && (tokens[endIndex].type !== "blockquote_close" || tokens[endIndex].level !== open.level)) endIndex++; if (endIndex === tokens.length) continue; const close = tokens[endIndex]; const firstContent = tokens.slice(startIndex, endIndex + 1).find((token) => token.type === "inline"); if (!firstContent) continue; const match = firstContent.content.match(markerRE); if (!match) continue; const type = match[1].toLowerCase(); const title = match[2].trim() || titleMark[type] || capitalize(type); firstContent.content = firstContent.content.slice(match[0].length).trimStart(); open.type = "github_alert_open"; open.tag = "div"; open.meta = { title, type }; close.type = "github_alert_close"; close.tag = "div"; } } }); md.renderer.rules.github_alert_open = function(tokens, idx) { const { title, type } = tokens[idx].meta; const attrs = ""; return `

    ${title}

    `; }; }; function capitalize(str) { return str.charAt(0).toUpperCase() + str.slice(1); } const POOL_SIZE_MULTIPLIER = 128; let pool, poolOffset; function fillPool(bytes) { if (!pool || pool.length < bytes) { pool = Buffer.allocUnsafe(bytes * POOL_SIZE_MULTIPLIER); webcrypto.getRandomValues(pool); poolOffset = 0; } else if (poolOffset + bytes > pool.length) { webcrypto.getRandomValues(pool); poolOffset = 0; } poolOffset += bytes; } function random(bytes) { fillPool((bytes |= 0)); return pool.subarray(poolOffset - bytes, poolOffset) } function customRandom(alphabet, defaultSize, getRandom) { let mask = (2 << (31 - Math.clz32((alphabet.length - 1) | 1))) - 1; let step = Math.ceil((1.6 * mask * defaultSize) / alphabet.length); return (size = defaultSize) => { if (!size) return '' let id = ''; while (true) { let bytes = getRandom(step); let i = step; while (i--) { id += alphabet[bytes[i] & mask] || ''; if (id.length >= size) return id } } } } function customAlphabet(alphabet, size = 21) { return customRandom(alphabet, size, random) } const nanoid = customAlphabet("abcdefghijklmnopqrstuvwxyz", 10); function transformerDisableShellSymbolSelect() { return { name: "vitepress:disable-shell-symbol-select", tokens(tokensByLine) { if (!isShell(this.options.lang)) return; for (const tokens of tokensByLine) { if (tokens.length < 2) continue; const firstTokenText = tokens[0].content.trim(); if (firstTokenText !== "$" && firstTokenText !== ">") continue; if (tokens[1].content[0] !== " ") continue; tokens[0].content = firstTokenText + " "; tokens[0].htmlStyle ??= {}; tokens[0].htmlStyle["user-select"] = "none"; tokens[0].htmlStyle["-webkit-user-select"] = "none"; tokens[1].content = tokens[1].content.slice(1); } } }; } async function highlight(theme, options, logger = console) { const { defaultHighlightLang: defaultLang = "txt", codeTransformers: userTransformers = [] } = options; const langAlias = Object.fromEntries( Object.entries(options.languageAlias || {}).map(([k, v]) => [k.toLowerCase(), v]) ); const highlighter = await createHighlighter({ themes: typeof theme === "object" && "light" in theme && "dark" in theme ? [theme.light, theme.dark] : [theme], langs: [...options.languages || [], ...Object.values(langAlias)], langAlias }); await options?.shikiSetup?.(highlighter); const transformers = [ transformerMetaHighlight(), transformerNotationDiff(), transformerNotationFocus({ classActiveLine: "has-focus", classActivePre: "has-focused-lines" }), transformerNotationHighlight(), transformerNotationErrorLevel(), transformerDisableShellSymbolSelect(), { name: "vitepress:add-dir", pre(node) { node.properties.dir = "ltr"; } } ]; const langRE = /^[a-zA-Z0-9-_]+/; const vueRE = /-vue$/; return [ async (str, lang, attrs) => { const match = langRE.exec(lang); if (match) { const orig = lang; lang = match[0].toLowerCase(); attrs = orig.slice(lang.length).replace(/(? { if (vPre) return s; return s.replace(/\{\{.*?\}\}/g, (match2) => { let marker = mustaches.get(match2); if (!marker) { marker = nanoid(); mustaches.set(match2, marker); } return marker; }); }; const restoreMustache = (s) => { mustaches.forEach((marker, match2) => { s = s.replaceAll(marker, match2); }); return s; }; str = removeMustache(str).trimEnd(); const embeddedLang = guessEmbeddedLanguages(str, lang, highlighter); await highlighter.loadLanguage(...embeddedLang); const highlighted = highlighter.codeToHtml(str, { lang, transformers: [ ...transformers, { name: "vitepress:v-pre", pre(node) { if (vPre) node.properties["v-pre"] = ""; } }, { name: "vitepress:empty-line", code(hast) { hast.children.forEach((span) => { if (span.type === "element" && span.tagName === "span" && Array.isArray(span.properties.class) && span.properties.class.includes("line") && span.children.length === 0) { span.children.push({ type: "element", tagName: "wbr", properties: {}, children: [] }); } }); } }, ...userTransformers ], meta: { __raw: attrs }, ...typeof theme === "object" && "light" in theme && "dark" in theme ? { themes: theme, defaultColor: false } : { theme } }); return restoreMustache(highlighted); }, highlighter.dispose ]; } const imagePlugin = (md, { lazyLoading } = {}) => { const imageRule = md.renderer.rules.image; md.renderer.rules.image = (tokens, idx, options, env, self) => { const token = tokens[idx]; let url = token.attrGet("src"); if (url && !EXTERNAL_URL_RE.test(url)) { if (!/^\.?\//.test(url)) url = "./" + url; token.attrSet("src", decodeURIComponent(url)); } if (lazyLoading) { token.attrSet("loading", "lazy"); } return imageRule(tokens, idx, options, env, self); }; }; const lineNumberPlugin = (md, enable = false) => { const fence = md.renderer.rules.fence; md.renderer.rules.fence = (...args) => { const rawCode = fence(...args); const [tokens, idx] = args; const info = tokens[idx].info; if (!enable && !/:line-numbers\b/.test(info) || enable && /:no-line-numbers\b/.test(info)) { return rawCode; } let startLineNumber = 1; const matchStartLineNumber = info.match(/=(\d+)/); if (matchStartLineNumber && matchStartLineNumber[1]) { startLineNumber = parseInt(matchStartLineNumber[1]); } const code = rawCode.slice( rawCode.indexOf(""), rawCode.indexOf("") ); const lines = code.split("\n"); const lineNumbersCode = [...Array(lines.length)].map( (_, index) => `${index + startLineNumber}
    ` ).join(""); const lineNumbersWrapperCode = ``; const finalCode = rawCode.replace(/<\/div>$/, `${lineNumbersWrapperCode}
    `).replace(/"(language-[^"]*?)"/, '"$1 line-numbers-mode"'); return finalCode; }; }; const indexRE = /(^|.*\/)index.md(#?.*)$/i; const linkPlugin = (md, externalAttrs, base, slugify) => { md.renderer.rules.link_open = (tokens, idx, options, env, self) => { const token = tokens[idx]; const hrefIndex = token.attrIndex("href"); if (hrefIndex >= 0 && token.attrIndex("target") < 0 && token.attrIndex("download") < 0 && token.attrGet("class") !== "header-anchor") { const hrefAttr = token.attrs[hrefIndex]; const url = hrefAttr[1]; if (isExternal(url)) { Object.entries(externalAttrs).forEach(([key, val]) => { token.attrSet(key, val); }); if (url.replace(EXTERNAL_URL_RE, "").startsWith("//localhost:")) { pushLink(url, env); } hrefAttr[1] = url; } else { const { pathname, protocol } = new URL$1(url, "http://a.com"); if ( // skip internal anchor links !url.startsWith("#") && // skip mail/custom protocol links protocol.startsWith("http") && // skip links to files (other than html/md) treatAsHtml(pathname) ) { normalizeHref(hrefAttr, env); } else if (url.startsWith("#")) { hrefAttr[1] = decodeURI(normalizeHash(hrefAttr[1])); } if (hrefAttr[1].startsWith("/")) { hrefAttr[1] = `${base}${hrefAttr[1]}`.replace(/\/+/g, "/"); } } } return self.renderToken(tokens, idx, options); }; function normalizeHref(hrefAttr, env) { let url = hrefAttr[1]; const indexMatch = url.match(indexRE); if (indexMatch) { const [, path, hash] = indexMatch; url = path + normalizeHash(hash); } else { let cleanUrl = url.replace(/[?#].*$/, ""); if (cleanUrl.endsWith(".md")) { cleanUrl = cleanUrl.replace(/\.md$/, env.cleanUrls ? "" : ".html"); } if (!env.cleanUrls && !cleanUrl.endsWith(".html") && !cleanUrl.endsWith("/")) { cleanUrl += ".html"; } const parsed = new URL$1(url, "http://a.com"); url = cleanUrl + parsed.search + normalizeHash(parsed.hash); } if (!url.startsWith("/") && !url.startsWith("./")) { url = "./" + url; } pushLink(url.replace(/\.html$/, ""), env); hrefAttr[1] = decodeURI(url); } function normalizeHash(str) { return str ? encodeURI("#" + slugify(decodeURI(str).slice(1))) : ""; } function pushLink(link, env) { const links = env.links || (env.links = []); links.push(link); } }; function restoreEntities(md) { md.core.ruler.at("text_join", text_join); md.renderer.rules.text = (tokens, idx) => escapeHtml$2(tokens[idx].content); } function text_join(state) { let curr, last; const blockTokens = state.tokens; const l = blockTokens.length; for (let j = 0; j < l; ++j) { if (blockTokens[j].type !== "inline") continue; const tokens = blockTokens[j].children || []; const max = tokens.length; for (curr = 0; curr < max; ++curr) if (tokens[curr].type === "text_special") tokens[curr].type = "text"; for (curr = last = 0; curr < max; ++curr) if (tokens[curr].type === "text" && curr + 1 < max && tokens[curr + 1].type === "text") { tokens[curr + 1].content = getContent(tokens[curr]) + getContent(tokens[curr + 1]); tokens[curr + 1].info = ""; tokens[curr + 1].markup = ""; } else { if (curr !== last) tokens[last] = tokens[curr]; ++last; } if (curr !== last) tokens.length = last; } } function getContent(token) { return token.info === "entity" ? token.markup : token.info === "escape" && token.content === "&" ? "&" : token.content; } const rawPathRegexp = /^(.+?(?:(?:\.([a-z0-9]+))?))(?:(#[\w-]+))?(?: ?(?:{(\d+(?:[,-]\d+)*)? ?(\S+)? ?(\S+)?}))? ?(?:\[(.+)\])?$/; function rawPathToToken(rawPath) { const [ filepath = "", extension = "", region = "", lines = "", lang = "", attrs = "", rawTitle = "" ] = (rawPathRegexp.exec(rawPath) || []).slice(1); const title = rawTitle || filepath.split("/").pop() || ""; return { filepath, extension, region, lines, lang, attrs, title }; } function dedent(text) { const lines = text.split("\n"); const minIndentLength = lines.reduce((acc, line) => { for (let i = 0; i < line.length; i++) { if (line[i] !== " " && line[i] !== " ") return Math.min(i, acc); } return acc; }, Infinity); if (minIndentLength < Infinity) { return lines.map((x) => x.slice(minIndentLength)).join("\n"); } return text; } const markers = [ { start: /^\s*\/\/\s*#?region\b\s*(.*?)\s*$/, end: /^\s*\/\/\s*#?endregion\b\s*(.*?)\s*$/ }, { start: /^\s*/, end: /^\s*/ }, { start: /^\s*\/\*\s*#region\b\s*(.*?)\s*\*\//, end: /^\s*\/\*\s*#endregion\b\s*(.*?)\s*\*\// }, { start: /^\s*#[rR]egion\b\s*(.*?)\s*$/, end: /^\s*#[eE]nd ?[rR]egion\b\s*(.*?)\s*$/ }, { start: /^\s*#\s*#?region\b\s*(.*?)\s*$/, end: /^\s*#\s*#?endregion\b\s*(.*?)\s*$/ }, { start: /^\s*(?:--|::|@?REM)\s*#region\b\s*(.*?)\s*$/, end: /^\s*(?:--|::|@?REM)\s*#endregion\b\s*(.*?)\s*$/ }, { start: /^\s*#pragma\s+region\b\s*(.*?)\s*$/, end: /^\s*#pragma\s+endregion\b\s*(.*?)\s*$/ }, { start: /^\s*\(\*\s*#region\b\s*(.*?)\s*\*\)/, end: /^\s*\(\*\s*#endregion\b\s*(.*?)\s*\*\)/ } ]; function findRegion(lines, regionName) { let chosen = null; for (let i = 0; i < lines.length; i++) { for (const re of markers) { if (re.start.exec(lines[i])?.[1] === regionName) { chosen = { re, start: i + 1 }; break; } } if (chosen) break; } if (!chosen) return null; let counter = 1; for (let i = chosen.start; i < lines.length; i++) { if (chosen.re.start.exec(lines[i])?.[1] === regionName) { counter++; continue; } const endRegion = chosen.re.end.exec(lines[i])?.[1]; if (endRegion === regionName || endRegion === "") { if (--counter === 0) return { ...chosen, end: i }; } } return null; } const snippetPlugin = (md, srcDir) => { const parser = (state, startLine, endLine, silent) => { const CH = "<".charCodeAt(0); const pos = state.bMarks[startLine] + state.tShift[startLine]; const max = state.eMarks[startLine]; if (state.sCount[startLine] - state.blkIndent >= 4) { return false; } for (let i = 0; i < 3; ++i) { const ch = state.src.charCodeAt(pos + i); if (ch !== CH || pos + i >= max) return false; } if (silent) { return true; } const start = pos + 3; const end = state.skipSpacesBack(max, pos); const rawPath = state.src.slice(start, end).trim().replace(/^@/, srcDir).trim(); const { filepath, extension, region, lines, lang, attrs, title } = rawPathToToken(rawPath); state.line = startLine + 1; const token = state.push("fence", "code", 0); token.info = `${lang || extension}${lines ? `{${lines}}` : ""}${title ? `[${title}]` : ""} ${attrs ?? ""}`; const { realPath, path: _path } = state.env; const resolvedPath = path$1.resolve(path$1.dirname(realPath ?? _path), filepath); token.src = [resolvedPath, region.slice(1)]; token.markup = "```"; token.map = [startLine, startLine + 1]; return true; }; const fence = md.renderer.rules.fence; md.renderer.rules.fence = (...args) => { const [tokens, idx, , { includes }] = args; const token = tokens[idx]; const [src, regionName] = token.src ?? []; if (!src) return fence(...args); if (includes) { includes.push(src); } const isAFile = fs.statSync(src).isFile(); if (!fs.existsSync(src) || !isAFile) { token.content = isAFile ? `Code snippet path not found: ${src}` : `Invalid code snippet option`; token.info = ""; return fence(...args); } let content = fs.readFileSync(src, "utf8").replace(/\r\n/g, "\n"); if (regionName) { const lines = content.split("\n"); const region = findRegion(lines, regionName); if (region) { content = dedent( lines.slice(region.start, region.end).filter((l) => !(region.re.start.test(l) || region.re.end.test(l))).join("\n") ); } } token.content = content; return fence(...args); }; md.block.ruler.before("fence", "snippet", parser); }; let md; let _disposeHighlighter; function disposeMdItInstance() { if (md) { md = void 0; _disposeHighlighter?.(); } } async function createMarkdownRenderer(srcDir, options = {}, base = "/", logger = console) { if (md) return md; const theme = options.theme ?? { light: "github-light", dark: "github-dark" }; const codeCopyButtonTitle = options.codeCopyButtonTitle || "Copy Code"; let [highlight$1, dispose] = options.highlight ? [options.highlight, () => { }] : await highlight(theme, options, logger); _disposeHighlighter = dispose; md = new MarkdownItAsync({ html: true, linkify: true, highlight: highlight$1, ...options }); md.linkify.set({ fuzzyLink: false }); restoreEntities(md); if (options.preConfig) { await options.preConfig(md); } const slugify$1 = options.anchor?.slugify ?? slugify; componentPlugin(md, options.component); preWrapperPlugin(md, { codeCopyButtonTitle, languageLabel: options.languageLabel }); snippetPlugin(md, srcDir); containerPlugin(md, options.container); imagePlugin(md, options.image); linkPlugin( md, { target: "_blank", rel: "noreferrer", ...options.externalLinks }, base, slugify$1 ); lineNumberPlugin(md, options.lineNumbers); const tableOpen = md.renderer.rules.table_open; md.renderer.rules.table_open = function(tokens, idx, options2, env, self) { const token = tokens[idx]; if (token.attrIndex("tabindex") < 0) token.attrPush(["tabindex", "0"]); return tableOpen ? tableOpen(tokens, idx, options2, env, self) : self.renderToken(tokens, idx, options2); }; if (options.gfmAlerts !== false) { gitHubAlertsPlugin(md, options.container); } if (!options.attrs?.disable) { attrsPlugin(md, options.attrs); } emoji_plugin(md, options.emoji); b$1(md, { slugify: slugify$1, getTokensText: (tokens) => { return tokens.filter((t) => !["html_inline", "emoji"].includes(t.type)).map((t) => t.content).join(""); }, permalink: (slug, _, state, idx) => { const title = state.tokens[idx + 1]?.children?.filter((token) => ["text", "code_inline"].includes(token.type)).reduce((acc, t) => acc + t.content, "").trim() || ""; const linkTokens = [ Object.assign(new state.Token("text", "", 0), { content: " " }), Object.assign(new state.Token("link_open", "a", 1), { attrs: [ ["class", "header-anchor"], ["href", `#${slug}`], ["aria-label", `Permalink to \u201C${title}\u201D`] ] }), Object.assign(new state.Token("html_inline", "", 0), { content: "​", meta: { isPermalinkSymbol: true } }), new state.Token("link_close", "a", -1) ]; state.tokens[idx + 1].children?.push(...linkTokens); }, ...options.anchor }); frontmatterPlugin(md, options.frontmatter); if (options.headers) { headersPlugin(md, { level: [2, 3, 4, 5, 6], slugify: slugify$1, ...typeof options.headers === "boolean" ? void 0 : options.headers }); } sfcPlugin(md, options.sfc); titlePlugin(md); tocPlugin(md, { slugify: slugify$1, ...options.toc, format: (s) => { const title = s.replaceAll("&", "&"); return options.toc?.format?.(title) ?? title; } }); if (options.math) { try { const mathPlugin = await import('markdown-it-mathjax3'); (mathPlugin.default ?? mathPlugin)(md, { ...typeof options.math === "boolean" ? {} : options.math }); const origMathInline = md.renderer.rules.math_inline; md.renderer.rules.math_inline = function(...args) { return origMathInline.apply(this, args).replace(/^ Object.assign(new Error(`not found: ${cmd}`), { code: 'ENOENT' }); const getPathInfo = (cmd, opt) => { const colon = opt.colon || COLON; // If it has a slash, then we don't bother searching the pathenv. // just check the file itself, and that's it. const pathEnv = cmd.match(/\//) || isWindows && cmd.match(/\\/) ? [''] : ( [ // windows always checks the cwd first ...(isWindows ? [process.cwd()] : []), ...(opt.path || process.env.PATH || /* istanbul ignore next: very unusual */ '').split(colon), ] ); const pathExtExe = isWindows ? opt.pathExt || process.env.PATHEXT || '.EXE;.CMD;.BAT;.COM' : ''; const pathExt = isWindows ? pathExtExe.split(colon) : ['']; if (isWindows) { if (cmd.indexOf('.') !== -1 && pathExt[0] !== '') pathExt.unshift(''); } return { pathEnv, pathExt, pathExtExe, } }; const which = (cmd, opt, cb) => { if (typeof opt === 'function') { cb = opt; opt = {}; } if (!opt) opt = {}; const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt); const found = []; const step = i => new Promise((resolve, reject) => { if (i === pathEnv.length) return opt.all && found.length ? resolve(found) : reject(getNotFoundError(cmd)) const ppRaw = pathEnv[i]; const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw; const pCmd = path.join(pathPart, cmd); const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd; resolve(subStep(p, i, 0)); }); const subStep = (p, i, ii) => new Promise((resolve, reject) => { if (ii === pathExt.length) return resolve(step(i + 1)) const ext = pathExt[ii]; isexe(p + ext, { pathExt: pathExtExe }, (er, is) => { if (!er && is) { if (opt.all) found.push(p + ext); else return resolve(p + ext) } return resolve(subStep(p, i, ii + 1)) }); }); return cb ? step(0).then(res => cb(null, res), cb) : step(0) }; const whichSync = (cmd, opt) => { opt = opt || {}; const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt); const found = []; for (let i = 0; i < pathEnv.length; i ++) { const ppRaw = pathEnv[i]; const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw; const pCmd = path.join(pathPart, cmd); const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd; for (let j = 0; j < pathExt.length; j ++) { const cur = p + pathExt[j]; try { const is = isexe.sync(cur, { pathExt: pathExtExe }); if (is) { if (opt.all) found.push(cur); else return cur } } catch (ex) {} } } if (opt.all && found.length) return found if (opt.nothrow) return null throw getNotFoundError(cmd) }; which_1 = which; which.sync = whichSync; return which_1; } var pathKey = {exports: {}}; var hasRequiredPathKey; function requirePathKey () { if (hasRequiredPathKey) return pathKey.exports; hasRequiredPathKey = 1; const pathKey$1 = (options = {}) => { const environment = options.env || process.env; const platform = options.platform || process.platform; if (platform !== 'win32') { return 'PATH'; } return Object.keys(environment).reverse().find(key => key.toUpperCase() === 'PATH') || 'Path'; }; pathKey.exports = pathKey$1; // TODO: Remove this for the next major release pathKey.exports.default = pathKey$1; return pathKey.exports; } var resolveCommand_1; var hasRequiredResolveCommand; function requireResolveCommand () { if (hasRequiredResolveCommand) return resolveCommand_1; hasRequiredResolveCommand = 1; const path = require$$1$1; const which = requireWhich(); const getPathKey = requirePathKey(); function resolveCommandAttempt(parsed, withoutPathExt) { const env = parsed.options.env || process.env; const cwd = process.cwd(); const hasCustomCwd = parsed.options.cwd != null; // Worker threads do not have process.chdir() const shouldSwitchCwd = hasCustomCwd && process.chdir !== undefined && !process.chdir.disabled; // If a custom `cwd` was specified, we need to change the process cwd // because `which` will do stat calls but does not support a custom cwd if (shouldSwitchCwd) { try { process.chdir(parsed.options.cwd); } catch (err) { /* Empty */ } } let resolved; try { resolved = which.sync(parsed.command, { path: env[getPathKey({ env })], pathExt: withoutPathExt ? path.delimiter : undefined, }); } catch (e) { /* Empty */ } finally { if (shouldSwitchCwd) { process.chdir(cwd); } } // If we successfully resolved, ensure that an absolute path is returned // Note that when a custom `cwd` was used, we need to resolve to an absolute path based on it if (resolved) { resolved = path.resolve(hasCustomCwd ? parsed.options.cwd : '', resolved); } return resolved; } function resolveCommand(parsed) { return resolveCommandAttempt(parsed) || resolveCommandAttempt(parsed, true); } resolveCommand_1 = resolveCommand; return resolveCommand_1; } var _escape = {}; var hasRequired_escape; function require_escape () { if (hasRequired_escape) return _escape; hasRequired_escape = 1; // See http://www.robvanderwoude.com/escapechars.php const metaCharsRegExp = /([()\][%!^"`<>&|;, *?])/g; function escapeCommand(arg) { // Escape meta chars arg = arg.replace(metaCharsRegExp, '^$1'); return arg; } function escapeArgument(arg, doubleEscapeMetaChars) { // Convert to string arg = `${arg}`; // Algorithm below is based on https://qntm.org/cmd // It's slightly altered to disable JS backtracking to avoid hanging on specially crafted input // Please see https://github.com/moxystudio/node-cross-spawn/pull/160 for more information // Sequence of backslashes followed by a double quote: // double up all the backslashes and escape the double quote arg = arg.replace(/(?=(\\+?)?)\1"/g, '$1$1\\"'); // Sequence of backslashes followed by the end of the string // (which will become a double quote later): // double up all the backslashes arg = arg.replace(/(?=(\\+?)?)\1$/, '$1$1'); // All other backslashes occur literally // Quote the whole thing: arg = `"${arg}"`; // Escape meta chars arg = arg.replace(metaCharsRegExp, '^$1'); // Double escape meta chars if necessary if (doubleEscapeMetaChars) { arg = arg.replace(metaCharsRegExp, '^$1'); } return arg; } _escape.command = escapeCommand; _escape.argument = escapeArgument; return _escape; } var shebangRegex; var hasRequiredShebangRegex; function requireShebangRegex () { if (hasRequiredShebangRegex) return shebangRegex; hasRequiredShebangRegex = 1; shebangRegex = /^#!(.*)/; return shebangRegex; } var shebangCommand; var hasRequiredShebangCommand; function requireShebangCommand () { if (hasRequiredShebangCommand) return shebangCommand; hasRequiredShebangCommand = 1; const shebangRegex = requireShebangRegex(); shebangCommand = (string = '') => { const match = string.match(shebangRegex); if (!match) { return null; } const [path, argument] = match[0].replace(/#! ?/, '').split(' '); const binary = path.split('/').pop(); if (binary === 'env') { return argument; } return argument ? `${binary} ${argument}` : binary; }; return shebangCommand; } var readShebang_1; var hasRequiredReadShebang; function requireReadShebang () { if (hasRequiredReadShebang) return readShebang_1; hasRequiredReadShebang = 1; const fs = nativeFs__default; const shebangCommand = requireShebangCommand(); function readShebang(command) { // Read the first 150 bytes from the file const size = 150; const buffer = Buffer.alloc(size); let fd; try { fd = fs.openSync(command, 'r'); fs.readSync(fd, buffer, 0, size, 0); fs.closeSync(fd); } catch (e) { /* Empty */ } // Attempt to extract shebang (null is returned if not a shebang) return shebangCommand(buffer.toString()); } readShebang_1 = readShebang; return readShebang_1; } var parse_1; var hasRequiredParse; function requireParse () { if (hasRequiredParse) return parse_1; hasRequiredParse = 1; const path = require$$1$1; const resolveCommand = requireResolveCommand(); const escape = require_escape(); const readShebang = requireReadShebang(); const isWin = process.platform === 'win32'; const isExecutableRegExp = /\.(?:com|exe)$/i; const isCmdShimRegExp = /node_modules[\\/].bin[\\/][^\\/]+\.cmd$/i; function detectShebang(parsed) { parsed.file = resolveCommand(parsed); const shebang = parsed.file && readShebang(parsed.file); if (shebang) { parsed.args.unshift(parsed.file); parsed.command = shebang; return resolveCommand(parsed); } return parsed.file; } function parseNonShell(parsed) { if (!isWin) { return parsed; } // Detect & add support for shebangs const commandFile = detectShebang(parsed); // We don't need a shell if the command filename is an executable const needsShell = !isExecutableRegExp.test(commandFile); // If a shell is required, use cmd.exe and take care of escaping everything correctly // Note that `forceShell` is an hidden option used only in tests if (parsed.options.forceShell || needsShell) { // Need to double escape meta chars if the command is a cmd-shim located in `node_modules/.bin/` // The cmd-shim simply calls execute the package bin file with NodeJS, proxying any argument // Because the escape of metachars with ^ gets interpreted when the cmd.exe is first called, // we need to double escape them const needsDoubleEscapeMetaChars = isCmdShimRegExp.test(commandFile); // Normalize posix paths into OS compatible paths (e.g.: foo/bar -> foo\bar) // This is necessary otherwise it will always fail with ENOENT in those cases parsed.command = path.normalize(parsed.command); // Escape command & arguments parsed.command = escape.command(parsed.command); parsed.args = parsed.args.map((arg) => escape.argument(arg, needsDoubleEscapeMetaChars)); const shellCommand = [parsed.command].concat(parsed.args).join(' '); parsed.args = ['/d', '/s', '/c', `"${shellCommand}"`]; parsed.command = process.env.comspec || 'cmd.exe'; parsed.options.windowsVerbatimArguments = true; // Tell node's spawn that the arguments are already escaped } return parsed; } function parse(command, args, options) { // Normalize arguments, similar to nodejs if (args && !Array.isArray(args)) { options = args; args = null; } args = args ? args.slice(0) : []; // Clone array to avoid changing the original options = Object.assign({}, options); // Clone object to avoid changing the original // Build our parsed object const parsed = { command, args, options, file: undefined, original: { command, args, }, }; // Delegate further parsing to shell or non-shell return options.shell ? parsed : parseNonShell(parsed); } parse_1 = parse; return parse_1; } var enoent; var hasRequiredEnoent; function requireEnoent () { if (hasRequiredEnoent) return enoent; hasRequiredEnoent = 1; const isWin = process.platform === 'win32'; function notFoundError(original, syscall) { return Object.assign(new Error(`${syscall} ${original.command} ENOENT`), { code: 'ENOENT', errno: 'ENOENT', syscall: `${syscall} ${original.command}`, path: original.command, spawnargs: original.args, }); } function hookChildProcess(cp, parsed) { if (!isWin) { return; } const originalEmit = cp.emit; cp.emit = function (name, arg1) { // If emitting "exit" event and exit code is 1, we need to check if // the command exists and emit an "error" instead // See https://github.com/IndigoUnited/node-cross-spawn/issues/16 if (name === 'exit') { const err = verifyENOENT(arg1, parsed); if (err) { return originalEmit.call(cp, 'error', err); } } return originalEmit.apply(cp, arguments); // eslint-disable-line prefer-rest-params }; } function verifyENOENT(status, parsed) { if (isWin && status === 1 && !parsed.file) { return notFoundError(parsed.original, 'spawn'); } return null; } function verifyENOENTSync(status, parsed) { if (isWin && status === 1 && !parsed.file) { return notFoundError(parsed.original, 'spawnSync'); } return null; } enoent = { hookChildProcess, verifyENOENT, verifyENOENTSync, notFoundError, }; return enoent; } var hasRequiredCrossSpawn; function requireCrossSpawn () { if (hasRequiredCrossSpawn) return crossSpawn.exports; hasRequiredCrossSpawn = 1; const cp = require$$0$3; const parse = requireParse(); const enoent = requireEnoent(); function spawn(command, args, options) { // Parse the arguments const parsed = parse(command, args, options); // Spawn the child process const spawned = cp.spawn(parsed.command, parsed.args, parsed.options); // Hook into child process "exit" event to emit an error if the command // does not exists, see: https://github.com/IndigoUnited/node-cross-spawn/issues/16 enoent.hookChildProcess(spawned, parsed); return spawned; } function spawnSync(command, args, options) { // Parse the arguments const parsed = parse(command, args, options); // Spawn the child process const result = cp.spawnSync(parsed.command, parsed.args, parsed.options); // Analyze if the command does not exist, see: https://github.com/IndigoUnited/node-cross-spawn/issues/16 result.error = result.error || enoent.verifyENOENTSync(result.status, parsed); return result; } crossSpawn.exports = spawn; crossSpawn.exports.spawn = spawn; crossSpawn.exports.sync = spawnSync; crossSpawn.exports._parse = parse; crossSpawn.exports._enoent = enoent; return crossSpawn.exports; } var crossSpawnExports = requireCrossSpawn(); const debug$2 = createDebug("vitepress:git"); const cache$2 = /* @__PURE__ */ new Map(); const RS = 30; const NUL = 0; const LF = 10; class GitLogParser extends Transform { #state = "READ_TS"; #tsBytes = []; #fileBytes = []; #files = []; constructor() { super({ readableObjectMode: true }); } _transform(chunk, _enc, cb) { try { for (let i = 0; i < chunk.length; i++) { const b = chunk[i] === LF ? NUL : chunk[i]; switch (this.#state) { case "READ_TS": { if (b === RS) { } else if (b === NUL) { this.#state = "READ_FILE"; } else { this.#tsBytes.push(b); } break; } case "READ_FILE": { if (b === RS) { this.#emitRecord(); } else if (b === NUL) { if (this.#fileBytes.length > 0) { this.#files.push(Buffer.from(this.#fileBytes).toString("utf8")); this.#fileBytes.length = 0; } } else { this.#fileBytes.push(b); } break; } } } cb(); } catch (err) { cb(err); } } _flush(cb) { try { if (this.#state === "READ_FILE") { if (this.#fileBytes.length > 0) { throw new Error("GitLogParser: unexpected EOF while reading filename"); } else { this.#emitRecord(); } } cb(); } catch (err) { cb(err); } } #emitRecord() { const ts = Buffer.from(this.#tsBytes).toString("utf8"); const rec = { ts: Number.parseInt(ts, 10) * 1e3, files: this.#files.slice() }; if (rec.ts > 0 && rec.files.length > 0) this.push(rec); this.#tsBytes.length = 0; this.#fileBytes.length = 0; this.#files.length = 0; this.#state = "READ_TS"; } } async function cacheAllGitTimestamps(root, pathspec = ["*.md"]) { const cp = crossSpawnExports.sync("git", ["rev-parse", "--show-toplevel"], { cwd: root }); if (cp.error) throw cp.error; const gitRoot = cp.stdout.toString("utf8").trim(); const args = [ "log", "--pretty=format:%x1e%at%x00", // RS + epoch + NUL "--name-only", "-z", "--", ...pathspec ]; return new Promise((resolve, reject) => { cache$2.clear(); const child = crossSpawnExports.spawn("git", args, { cwd: root }); child.stdout.pipe(new GitLogParser()).on("data", (rec) => { for (const file of rec.files) { const slashed = slash(path$1.resolve(gitRoot, file)); if (!cache$2.has(slashed)) cache$2.set(slashed, rec.ts); } }).on("error", reject).on("end", resolve); child.on("error", reject); }); } async function getGitTimestamp(file) { const cached = cache$2.get(file); if (cached) return cached; debug$2(`[cache miss] ${file}`); if (!fs__default.existsSync(file)) return 0; return new Promise((resolve, reject) => { const child = crossSpawnExports.spawn( "git", ["log", "-1", "--pretty=%at", "--", path$1.basename(file)], { cwd: path$1.dirname(file) } ); let output = ""; child.stdout.on("data", (d) => output += String(d)); child.on("close", () => { const ts = Number.parseInt(output.trim(), 10) * 1e3; if (!(ts > 0)) return resolve(0); cache$2.set(file, ts); resolve(ts); }); child.on("error", reject); }); } function processIncludes(md, srcDir, src, file, includes, cleanUrls) { const includesRE = //g; const regionRE = /(#[^\s\{]+)/; const rangeRE = /\{(\d*),(\d*)\}$/; return src.replace(includesRE, (m, m1) => { if (!m1.length) return m; const range = m1.match(rangeRE); const region = m1.match(regionRE); const hasMeta = !!(region || range); if (hasMeta) { const len = (region?.[0].length || 0) + (range?.[0].length || 0); m1 = m1.slice(0, -len); } const atPresent = m1[0] === "@"; try { const includePath = atPresent ? path$1.join(srcDir, m1.slice(m1[1] === "/" ? 2 : 1)) : path$1.join(path$1.dirname(file), m1); let content = fs.readFileSync(includePath, "utf-8"); if (region) { const [regionName] = region; const lines = content.split(/\r?\n/); let { start, end } = findRegion(lines, regionName.slice(1)) ?? {}; if (start === void 0) { const tokens = md.parse(content, { path: includePath, relativePath: slash(path$1.relative(srcDir, includePath)), cleanUrls }).filter((t) => t.type === "heading_open" && t.map); const idx = tokens.findIndex( (t) => t.attrGet("id") === regionName.slice(1) ); const token = tokens[idx]; if (token) { start = token.map[1]; const level = parseInt(token.tag.slice(1)); for (let i = idx + 1; i < tokens.length; i++) { if (parseInt(tokens[i].tag.slice(1)) <= level) { end = tokens[i].map[0]; break; } } } } content = lines.slice(start, end).join("\n"); } if (range) { const [, startLine, endLine] = range; const lines = content.split(/\r?\n/); content = lines.slice( startLine ? parseInt(startLine) - 1 : void 0, endLine ? parseInt(endLine) : void 0 ).join("\n"); } if (!hasMeta && path$1.extname(includePath) === ".md") { content = matter(content).content; } includes.push(slash(includePath)); return processIncludes( md, srcDir, content, includePath, includes, cleanUrls ); } catch (error) { if (process.env.DEBUG) { process.stderr.write(c$1.yellow(` Include file not found: ${m1}`)); } return m; } }); } const debug$1 = createDebug("vitepress:md"); const cache$1 = new LRUCache({ max: 1024 }); function clearCache(relativePath) { if (!relativePath) { cache$1.clear(); return; } relativePath = JSON.stringify({ relativePath }).slice(1); cache$1.find((_, key) => key.endsWith(relativePath) && cache$1.delete(key)); } let __pages = []; let __dynamicRoutes = /* @__PURE__ */ new Map(); let __rewrites = /* @__PURE__ */ new Map(); let __ts; function getResolutionCache(siteConfig) { if (siteConfig.__dirty) { __pages = siteConfig.pages.map((p) => slash(p.replace(/\.md$/, ""))); __dynamicRoutes = new Map( siteConfig.dynamicRoutes.map((r) => [ r.fullPath, [slash(path$1.join(siteConfig.srcDir, r.route)), r.loaderPath] ]) ); __rewrites = new Map( Object.entries(siteConfig.rewrites.map).map(([key, value]) => [ slash(path$1.join(siteConfig.srcDir, key)), slash(path$1.join(siteConfig.srcDir, value)) ]) ); __ts = Date.now(); siteConfig.__dirty = false; } return { pages: __pages, dynamicRoutes: __dynamicRoutes, rewrites: __rewrites, ts: __ts }; } async function createMarkdownToVueRenderFn(srcDir, options = {}, base = "/", includeLastUpdatedData = false, cleanUrls = false, siteConfig) { const md = await createMarkdownRenderer( srcDir, options, base, siteConfig?.logger ); return async (src, file, publicDir) => { const { pages, dynamicRoutes, rewrites, ts } = getResolutionCache(siteConfig); const dynamicRoute = dynamicRoutes.get(file); const fileOrig = dynamicRoute?.[0] || file; const transformPageData = [ siteConfig?.transformPageData, getPageDataTransformer(dynamicRoute?.[1]) ].filter((fn) => fn != null); file = rewrites.get(file) || file; const relativePath = slash(path$1.relative(srcDir, file)); const cacheKey = JSON.stringify({ src, ts, relativePath }); if (options.cache !== false) { const cached = cache$1.get(cacheKey); if (cached) { debug$1(`[cache hit] ${relativePath}`); return cached; } } const start = Date.now(); let params; src = src.replace( /^__VP_PARAMS_START([^]+?)__VP_PARAMS_END__/, (_, paramsString) => { params = JSON.parse(paramsString); return ""; } ); let includes = []; src = processIncludes(md, srcDir, src, fileOrig, includes, cleanUrls); const localeIndex = getLocaleForPath(siteConfig?.site, relativePath); const env = { path: file, relativePath, cleanUrls, includes, realPath: fileOrig, localeIndex }; const html = await md.renderAsync(src, env); const { frontmatter = {}, headers = [], links = [], sfcBlocks, title = "" } = env; const deadLinks = []; const recordDeadLink = (url) => { deadLinks.push({ url, file: fileOrig }); }; function shouldIgnoreDeadLink(url) { if (!siteConfig?.ignoreDeadLinks) { return false; } if (siteConfig.ignoreDeadLinks === true) { return true; } if (siteConfig.ignoreDeadLinks === "localhostLinks") { return url.replace(EXTERNAL_URL_RE, "").startsWith("//localhost"); } return siteConfig.ignoreDeadLinks.some((ignore) => { if (typeof ignore === "string") return url === ignore; if (ignore instanceof RegExp) return ignore.test(url); if (typeof ignore === "function") return ignore(url, fileOrig); return false; }); } if (links && siteConfig?.ignoreDeadLinks !== true) { const dir = path$1.dirname(file); for (let url of links) { const { pathname } = new URL(url, "http://a.com"); if (!treatAsHtml(pathname)) continue; url = url.replace(/[?#].*$/, "").replace(/\.(html|md)$/, ""); if (url.endsWith("/")) url += `index`; let resolved = decodeURIComponent( slash( url.startsWith("/") ? url.slice(1) : path$1.relative(srcDir, path$1.resolve(dir, url)) ) ); resolved = siteConfig?.rewrites.inv[resolved + ".md"]?.slice(0, -3) || resolved; if (!pages.includes(resolved) && !fs.existsSync(path$1.resolve(dir, publicDir, `${resolved}.html`)) && !shouldIgnoreDeadLink(url)) { recordDeadLink(url); } } } let pageData = { title: inferTitle(md, frontmatter, title), titleTemplate: frontmatter.titleTemplate, description: inferDescription(frontmatter), frontmatter, headers, params, relativePath, filePath: slash(path$1.relative(srcDir, fileOrig)) }; if (includeLastUpdatedData && frontmatter.lastUpdated !== false) { if (frontmatter.lastUpdated instanceof Date) { pageData.lastUpdated = +frontmatter.lastUpdated; } else { pageData.lastUpdated = await getGitTimestamp(fileOrig); } } for (const fn of transformPageData) { if (fn) { const dataToMerge = await fn(pageData, { siteConfig }); if (dataToMerge) pageData = { ...pageData, ...dataToMerge }; } } const vueSrc = [ ...injectPageDataCode( sfcBlocks?.scripts.map((item) => item.content) ?? [], pageData ), ``, ...sfcBlocks?.styles.map((item) => item.content) ?? [], ...sfcBlocks?.customBlocks.map((item) => item.content) ?? [] ].join("\n"); debug$1(`[render] ${file} in ${Date.now() - start}ms.`); const result = { vueSrc, pageData, deadLinks, includes }; if (options.cache !== false) cache$1.set(cacheKey, result); return result; }; } const scriptRE = /<\/script>/; const scriptLangTsRE = /<\s*script[^>]*\blang=['"]ts['"][^>]*/; const scriptSetupRE = /<\s*script[^>]*\bsetup\b[^>]*/; const scriptClientRE$1 = /<\s*script[^>]*\bclient\b[^>]*/; const defaultExportRE = /((?:^|\n|;)\s*)export(\s*)default/; const namedDefaultExportRE = /((?:^|\n|;)\s*)export(.+)as(\s*)default/; function injectPageDataCode(tags, data) { const code = ` export const __pageData = JSON.parse(${JSON.stringify( JSON.stringify(data) )})`; const existingScriptIndex = tags.findIndex((tag) => { return scriptRE.test(tag) && !scriptSetupRE.test(tag) && !scriptClientRE$1.test(tag); }); const isUsingTS = tags.findIndex((tag) => scriptLangTsRE.test(tag)) > -1; if (existingScriptIndex > -1) { const tagSrc = tags[existingScriptIndex]; const hasDefaultExport = defaultExportRE.test(tagSrc) || namedDefaultExportRE.test(tagSrc); tags[existingScriptIndex] = tagSrc.replace( scriptRE, code + (hasDefaultExport ? `` : ` export default {name:${JSON.stringify(data.relativePath)}}`) + `<\/script>` ); } else { tags.unshift( `