Files
Tiber365/node_modules/regex/dist/esm/regex.js

1267 lines
42 KiB
JavaScript

// node_modules/.pnpm/regex-utilities@2.3.0/node_modules/regex-utilities/src/index.js
var Context = Object.freeze({
DEFAULT: "DEFAULT",
CHAR_CLASS: "CHAR_CLASS"
});
function replaceUnescaped(expression, needle, replacement, context) {
const re = new RegExp(String.raw`${needle}|(?<$skip>\[\^?|\\?.)`, "gsu");
const negated = [false];
let numCharClassesOpen = 0;
let result = "";
for (const match of expression.matchAll(re)) {
const { 0: m, groups: { $skip } } = match;
if (!$skip && (!context || context === Context.DEFAULT === !numCharClassesOpen)) {
if (replacement instanceof Function) {
result += replacement(match, {
context: numCharClassesOpen ? Context.CHAR_CLASS : Context.DEFAULT,
negated: negated[negated.length - 1]
});
} else {
result += replacement;
}
continue;
}
if (m[0] === "[") {
numCharClassesOpen++;
negated.push(m[1] === "^");
} else if (m === "]" && numCharClassesOpen) {
numCharClassesOpen--;
negated.pop();
}
result += m;
}
return result;
}
function forEachUnescaped(expression, needle, callback, context) {
replaceUnescaped(expression, needle, callback, context);
}
function execUnescaped(expression, needle, pos = 0, context) {
if (!new RegExp(needle, "su").test(expression)) {
return null;
}
const re = new RegExp(`${needle}|(?<$skip>\\\\?.)`, "gsu");
re.lastIndex = pos;
let numCharClassesOpen = 0;
let match;
while (match = re.exec(expression)) {
const { 0: m, groups: { $skip } } = match;
if (!$skip && (!context || context === Context.DEFAULT === !numCharClassesOpen)) {
return match;
}
if (m === "[") {
numCharClassesOpen++;
} else if (m === "]" && numCharClassesOpen) {
numCharClassesOpen--;
}
if (re.lastIndex == match.index) {
re.lastIndex++;
}
}
return null;
}
function hasUnescaped(expression, needle, context) {
return !!execUnescaped(expression, needle, 0, context);
}
function getGroupContents(expression, contentsStartPos) {
const token5 = /\\?./gsu;
token5.lastIndex = contentsStartPos;
let contentsEndPos = expression.length;
let numCharClassesOpen = 0;
let numGroupsOpen = 1;
let match;
while (match = token5.exec(expression)) {
const [m] = match;
if (m === "[") {
numCharClassesOpen++;
} else if (!numCharClassesOpen) {
if (m === "(") {
numGroupsOpen++;
} else if (m === ")") {
numGroupsOpen--;
if (!numGroupsOpen) {
contentsEndPos = match.index;
break;
}
}
} else if (m === "]") {
numCharClassesOpen--;
}
}
return expression.slice(contentsStartPos, contentsEndPos);
}
// src/subclass.js
var emulationGroupMarker = "$E$";
var RegExpSubclass = class _RegExpSubclass extends RegExp {
// Avoid `#private` to allow for subclassing
/**
@private
@type {Array<{
exclude: boolean;
transfer?: number;
}> | undefined}
*/
_captureMap;
/**
@private
@type {Record<number, string> | undefined}
*/
_namesByIndex;
/**
@param {string | RegExpSubclass} expression
@param {string} [flags]
@param {{useEmulationGroups: boolean;}} [options]
*/
constructor(expression, flags, options) {
if (expression instanceof RegExp && options) {
throw new Error("Cannot provide options when copying a regexp");
}
const useEmulationGroups = !!options?.useEmulationGroups;
const unmarked = useEmulationGroups ? unmarkEmulationGroups(expression) : null;
super(unmarked?.expression || expression, flags);
const src = useEmulationGroups ? unmarked : expression instanceof _RegExpSubclass ? expression : null;
if (src) {
this._captureMap = src._captureMap;
this._namesByIndex = src._namesByIndex;
}
}
/**
Called internally by all String/RegExp methods that use regexes.
@override
@param {string} str
@returns {RegExpExecArray | null}
*/
exec(str) {
const match = RegExp.prototype.exec.call(this, str);
if (!match || !this._captureMap) {
return match;
}
const matchCopy = [...match];
match.length = 1;
let indicesCopy;
if (this.hasIndices) {
indicesCopy = [...match.indices];
match.indices.length = 1;
}
for (let i = 1; i < matchCopy.length; i++) {
if (this._captureMap[i].exclude) {
const transfer = this._captureMap[i].transfer;
if (transfer && match.length > transfer) {
match[transfer] = matchCopy[i];
const transferName = this._namesByIndex[transfer];
if (transferName) {
match.groups[transferName] = matchCopy[i];
if (this.hasIndices) {
match.indices.groups[transferName] = indicesCopy[i];
}
}
if (this.hasIndices) {
match.indices[transfer] = indicesCopy[i];
}
}
} else {
match.push(matchCopy[i]);
if (this.hasIndices) {
match.indices.push(indicesCopy[i]);
}
}
}
return match;
}
};
function unmarkEmulationGroups(expression) {
const marker = emulationGroupMarker.replace(/\$/g, "\\$");
const _captureMap = [{ exclude: false }];
const _namesByIndex = { 0: "" };
let realCaptureNum = 0;
expression = replaceUnescaped(
expression,
String.raw`\((?:(?!\?)|\?<(?![=!])(?<name>[^>]+)>)(?<mark>(?:\$(?<transfer>[1-9]\d*))?${marker})?`,
({ 0: m, groups: { name, mark, transfer } }) => {
if (mark) {
_captureMap.push({
exclude: true,
transfer: transfer && +transfer
});
return m.slice(0, -mark.length);
}
realCaptureNum++;
if (name) {
_namesByIndex[realCaptureNum] = name;
}
_captureMap.push({
exclude: false
});
return m;
},
Context.DEFAULT
);
return {
_captureMap,
_namesByIndex,
expression
};
}
// src/utils-internals.js
var noncapturingDelim = String.raw`\(\?(?:[:=!>A-Za-z\-]|<[=!]|\(DEFINE\))`;
function spliceStr(str, pos, oldValue, newValue) {
return str.slice(0, pos) + newValue + str.slice(pos + oldValue.length);
}
// src/atomic.js
var atomicPluginToken = new RegExp(String.raw`(?<noncapturingStart>${noncapturingDelim})|(?<capturingStart>\((?:\?<[^>]+>)?)|\\?.`, "gsu");
function atomic(expression, data) {
if (!/\(\?>/.test(expression)) {
return expression;
}
const aGDelim = "(?>";
const emulatedAGDelim = `(?:(?=(${data?.useEmulationGroups ? emulationGroupMarker : ""}`;
const captureNumMap = [0];
let numCapturesBeforeAG = 0;
let numAGs = 0;
let aGPos = NaN;
let hasProcessedAG;
do {
hasProcessedAG = false;
let numCharClassesOpen = 0;
let numGroupsOpenInAG = 0;
let inAG = false;
let match;
atomicPluginToken.lastIndex = Number.isNaN(aGPos) ? 0 : aGPos + emulatedAGDelim.length;
while (match = atomicPluginToken.exec(expression)) {
const { 0: m, index, groups: { capturingStart, noncapturingStart } } = match;
if (m === "[") {
numCharClassesOpen++;
} else if (!numCharClassesOpen) {
if (m === aGDelim && !inAG) {
aGPos = index;
inAG = true;
} else if (inAG && noncapturingStart) {
numGroupsOpenInAG++;
} else if (capturingStart) {
if (inAG) {
numGroupsOpenInAG++;
} else {
numCapturesBeforeAG++;
captureNumMap.push(numCapturesBeforeAG + numAGs);
}
} else if (m === ")" && inAG) {
if (!numGroupsOpenInAG) {
numAGs++;
expression = `${expression.slice(0, aGPos)}${emulatedAGDelim}${expression.slice(aGPos + aGDelim.length, index)}))<$$${numAGs + numCapturesBeforeAG}>)${expression.slice(index + 1)}`;
hasProcessedAG = true;
break;
}
numGroupsOpenInAG--;
}
} else if (m === "]") {
numCharClassesOpen--;
}
}
} while (hasProcessedAG);
expression = replaceUnescaped(
expression,
String.raw`\\(?<backrefNum>[1-9]\d*)|<\$\$(?<wrappedBackrefNum>\d+)>`,
({ 0: m, groups: { backrefNum, wrappedBackrefNum } }) => {
if (backrefNum) {
const bNum = +backrefNum;
if (bNum > captureNumMap.length - 1) {
throw new Error(`Backref "${m}" greater than number of captures`);
}
return `\\${captureNumMap[bNum]}`;
}
return `\\${wrappedBackrefNum}`;
},
Context.DEFAULT
);
return expression;
}
var baseQuantifier = String.raw`(?:[?*+]|\{\d+(?:,\d*)?\})`;
var possessivePluginToken = new RegExp(String.raw`
\\(?: \d+
| c[A-Za-z]
| [gk]<[^>]+>
| [pPu]\{[^\}]+\}
| u[A-Fa-f\d]{4}
| x[A-Fa-f\d]{2}
)
| \((?: \? (?: [:=!>]
| <(?:[=!]|[^>]+>)
| [A-Za-z\-]+:
| \(DEFINE\)
))?
| (?<qBase>${baseQuantifier})(?<qMod>[?+]?)(?<invalidQ>[?*+\{]?)
| \\?.
`.replace(/\s+/g, ""), "gsu");
function possessive(expression) {
if (!new RegExp(`${baseQuantifier}\\+`).test(expression)) {
return expression;
}
const openGroupIndices = [];
let lastGroupIndex = null;
let lastCharClassIndex = null;
let lastToken = "";
let numCharClassesOpen = 0;
let match;
possessivePluginToken.lastIndex = 0;
while (match = possessivePluginToken.exec(expression)) {
const { 0: m, index, groups: { qBase, qMod, invalidQ } } = match;
if (m === "[") {
if (!numCharClassesOpen) {
lastCharClassIndex = index;
}
numCharClassesOpen++;
} else if (m === "]") {
if (numCharClassesOpen) {
numCharClassesOpen--;
} else {
lastCharClassIndex = null;
}
} else if (!numCharClassesOpen) {
if (qMod === "+" && lastToken && !lastToken.startsWith("(")) {
if (invalidQ) {
throw new Error(`Invalid quantifier "${m}"`);
}
let charsAdded = -1;
if (/^\{\d+\}$/.test(qBase)) {
expression = spliceStr(expression, index + qBase.length, qMod, "");
} else {
if (lastToken === ")" || lastToken === "]") {
const nodeIndex = lastToken === ")" ? lastGroupIndex : lastCharClassIndex;
if (nodeIndex === null) {
throw new Error(`Invalid unmatched "${lastToken}"`);
}
expression = `${expression.slice(0, nodeIndex)}(?>${expression.slice(nodeIndex, index)}${qBase})${expression.slice(index + m.length)}`;
} else {
expression = `${expression.slice(0, index - lastToken.length)}(?>${lastToken}${qBase})${expression.slice(index + m.length)}`;
}
charsAdded += 4;
}
possessivePluginToken.lastIndex += charsAdded;
} else if (m[0] === "(") {
openGroupIndices.push(index);
} else if (m === ")") {
lastGroupIndex = openGroupIndices.length ? openGroupIndices.pop() : null;
}
}
lastToken = m;
}
return expression;
}
// src/pattern.js
var Pattern = class {
#value;
/** @param {string} value */
constructor(value) {
this.#value = value;
}
/** @returns {string} */
toString() {
return String(this.#value);
}
};
function pattern(first, ...substitutions) {
if (Array.isArray(first?.raw)) {
return new Pattern(
// Intersperse raw template strings and substitutions
first.raw.flatMap((raw, i) => i < first.raw.length - 1 ? [raw, substitutions[i]] : raw).join("")
);
} else if (!substitutions.length) {
return new Pattern(first === void 0 ? "" : first);
}
throw new Error(`Unexpected arguments: ${JSON.stringify([first, ...substitutions])}`);
}
// src/utils.js
var RegexContext = {
DEFAULT: "DEFAULT",
CHAR_CLASS: "CHAR_CLASS",
ENCLOSED_P: "ENCLOSED_P",
ENCLOSED_U: "ENCLOSED_U",
GROUP_NAME: "GROUP_NAME",
INTERVAL_QUANTIFIER: "INTERVAL_QUANTIFIER",
INVALID_INCOMPLETE_TOKEN: "INVALID_INCOMPLETE_TOKEN"
};
var CharClassContext = {
DEFAULT: "DEFAULT",
ENCLOSED_P: "ENCLOSED_P",
ENCLOSED_Q: "ENCLOSED_Q",
ENCLOSED_U: "ENCLOSED_U",
INVALID_INCOMPLETE_TOKEN: "INVALID_INCOMPLETE_TOKEN",
RANGE: "RANGE"
};
var enclosedTokenRegexContexts = /* @__PURE__ */ new Set([
RegexContext.ENCLOSED_P,
RegexContext.ENCLOSED_U
]);
var enclosedTokenCharClassContexts = /* @__PURE__ */ new Set([
CharClassContext.ENCLOSED_P,
CharClassContext.ENCLOSED_Q,
CharClassContext.ENCLOSED_U
]);
var envSupportsFlagGroups = (() => {
try {
new RegExp("(?i:)");
} catch {
return false;
}
return true;
})();
var envSupportsFlagV = (() => {
try {
new RegExp("", "v");
} catch {
return false;
}
return true;
})();
var doublePunctuatorChars = "&!#$%*+,.:;<=>?@^`~";
var namedCapturingDelim = String.raw`\(\?<(?![=!])(?<captureName>[^>]+)>`;
var capturingDelim = String.raw`\((?!\?)(?!(?<=\(\?\()DEFINE\))|${namedCapturingDelim}`;
function adjustNumberedBackrefs(expression, precedingCaptures) {
return replaceUnescaped(
expression,
String.raw`\\(?<num>[1-9]\d*)`,
({ groups: { num } }) => `\\${+num + precedingCaptures}`,
Context.DEFAULT
);
}
var stringPropertyNames = [
"Basic_Emoji",
"Emoji_Keycap_Sequence",
"RGI_Emoji_Modifier_Sequence",
"RGI_Emoji_Flag_Sequence",
"RGI_Emoji_Tag_Sequence",
"RGI_Emoji_ZWJ_Sequence",
"RGI_Emoji"
].join("|");
var charClassUnionToken = new RegExp(String.raw`
\\(?: c[A-Za-z]
| p\{(?<pStrProp>${stringPropertyNames})\}
| [pP]\{[^\}]+\}
| (?<qStrProp>q)
| u(?:[A-Fa-f\d]{4}|\{[A-Fa-f\d]+\})
| x[A-Fa-f\d]{2}
| .
)
| --
| &&
| .
`.replace(/\s+/g, ""), "gsu");
function containsCharClassUnion(charClassPattern) {
let hasFirst = false;
let lastM;
for (const { 0: m, groups } of charClassPattern.matchAll(charClassUnionToken)) {
if (groups.pStrProp || groups.qStrProp) {
return true;
}
if (m === "[" && hasFirst) {
return true;
}
if (["-", "--", "&&"].includes(m)) {
hasFirst = false;
} else if (m !== "[" && m !== "]") {
if (hasFirst || lastM === "]") {
return true;
}
hasFirst = true;
}
lastM = m;
}
return false;
}
function countCaptures(expression) {
let num = 0;
forEachUnescaped(expression, capturingDelim, () => num++, Context.DEFAULT);
return num;
}
function escapeV(str, context) {
if (context === Context.CHAR_CLASS) {
return str.replace(new RegExp(String.raw`[()\[\]{}|\\/\-${doublePunctuatorChars}]`, "g"), "\\$&");
}
return str.replace(/[()\[\]{}|\\^$*+?.]/g, "\\$&");
}
function getBreakoutChar(expression, regexContext, charClassContext) {
const escapesRemoved = expression.replace(/\\./gsu, "");
if (escapesRemoved.endsWith("\\")) {
return "\\";
}
if (regexContext === RegexContext.DEFAULT) {
return getUnbalancedChar(escapesRemoved, "(", ")");
} else if (regexContext === RegexContext.CHAR_CLASS && !enclosedTokenCharClassContexts.has(charClassContext)) {
return getUnbalancedChar(escapesRemoved, "[", "]");
} else if (regexContext === RegexContext.INTERVAL_QUANTIFIER || enclosedTokenRegexContexts.has(regexContext) || enclosedTokenCharClassContexts.has(charClassContext)) {
if (escapesRemoved.includes("}")) {
return "}";
}
} else if (regexContext === RegexContext.GROUP_NAME) {
if (escapesRemoved.includes(">")) {
return ">";
}
}
return "";
}
var contextToken = new RegExp(String.raw`
(?<groupN>\(\?<(?![=!])|\\[gk]<)
| (?<enclosedPU>\\[pPu]\{)
| (?<enclosedQ>\\q\{)
| (?<intervalQ>\{)
| (?<incompleteT>\\(?: $
| c(?![A-Za-z])
| u(?![A-Fa-f\d]{4})[A-Fa-f\d]{0,3}
| x(?![A-Fa-f\d]{2})[A-Fa-f\d]?
)
)
| --
| \\?.
`.replace(/\s+/g, ""), "gsu");
function getEndContextForIncompleteExpression(incompleteExpression, runningContext) {
let { regexContext, charClassContext, charClassDepth, lastPos } = {
regexContext: RegexContext.DEFAULT,
charClassContext: CharClassContext.DEFAULT,
charClassDepth: 0,
lastPos: 0,
...runningContext
};
contextToken.lastIndex = lastPos;
let match;
while (match = contextToken.exec(incompleteExpression)) {
const { 0: m, groups: { groupN, enclosedPU, enclosedQ, intervalQ, incompleteT } } = match;
if (m === "[") {
charClassDepth++;
regexContext = RegexContext.CHAR_CLASS;
charClassContext = CharClassContext.DEFAULT;
} else if (m === "]" && regexContext === RegexContext.CHAR_CLASS) {
if (charClassDepth) {
charClassDepth--;
}
if (!charClassDepth) {
regexContext = RegexContext.DEFAULT;
}
charClassContext = CharClassContext.DEFAULT;
} else if (regexContext === RegexContext.CHAR_CLASS) {
if (incompleteT) {
charClassContext = CharClassContext.INVALID_INCOMPLETE_TOKEN;
} else if (m === "-") {
charClassContext = CharClassContext.RANGE;
} else if (enclosedPU) {
charClassContext = m[1] === "u" ? CharClassContext.ENCLOSED_U : CharClassContext.ENCLOSED_P;
} else if (enclosedQ) {
charClassContext = CharClassContext.ENCLOSED_Q;
} else if (m === "}" && enclosedTokenCharClassContexts.has(charClassContext) || // Don't continue in these contexts since we've advanced another token
charClassContext === CharClassContext.INVALID_INCOMPLETE_TOKEN || charClassContext === CharClassContext.RANGE) {
charClassContext = CharClassContext.DEFAULT;
}
} else {
if (incompleteT) {
regexContext = RegexContext.INVALID_INCOMPLETE_TOKEN;
} else if (groupN) {
regexContext = RegexContext.GROUP_NAME;
} else if (enclosedPU) {
regexContext = m[1] === "u" ? RegexContext.ENCLOSED_U : RegexContext.ENCLOSED_P;
} else if (intervalQ) {
regexContext = RegexContext.INTERVAL_QUANTIFIER;
} else if (m === ">" && regexContext === RegexContext.GROUP_NAME || m === "}" && (regexContext === RegexContext.INTERVAL_QUANTIFIER || enclosedTokenRegexContexts.has(regexContext)) || // Don't continue in this context since we've advanced another token
regexContext === RegexContext.INVALID_INCOMPLETE_TOKEN) {
regexContext = RegexContext.DEFAULT;
}
}
}
return {
regexContext,
charClassContext,
charClassDepth,
lastPos: incompleteExpression.length
};
}
function getUnbalancedChar(expression, leftChar, rightChar) {
let numOpen = 0;
for (const [m] of expression.matchAll(new RegExp(`[${escapeV(leftChar + rightChar, Context.CHAR_CLASS)}]`, "g"))) {
numOpen += m === leftChar ? 1 : -1;
if (numOpen < 0) {
return rightChar;
}
}
if (numOpen > 0) {
return leftChar;
}
return "";
}
function preprocess(template, substitutions, preprocessor, options) {
let newTemplate = { raw: [] };
let newSubstitutions = [];
let runningContext;
template.raw.forEach((raw, i) => {
const result = preprocessor(raw, { ...runningContext, lastPos: 0 }, options);
newTemplate.raw.push(result.transformed);
runningContext = result.runningContext;
if (i < template.raw.length - 1) {
const substitution = substitutions[i];
if (substitution instanceof Pattern) {
const result2 = preprocessor(substitution, { ...runningContext, lastPos: 0 }, options);
newSubstitutions.push(pattern(result2.transformed));
runningContext = result2.runningContext;
} else {
newSubstitutions.push(substitution);
}
}
});
return {
template: newTemplate,
substitutions: newSubstitutions
};
}
function sandboxLoneCharClassCaret(str) {
return str.replace(/^\^/, "\\^^");
}
function sandboxLoneDoublePunctuatorChar(str) {
return str.replace(new RegExp(`^([${doublePunctuatorChars}])(?!\\1)`), (m, _, pos) => {
return `\\${m}${pos + 1 === str.length ? "" : m}`;
});
}
function sandboxUnsafeNulls(str, context) {
return replaceUnescaped(str, String.raw`\\0(?!\d)`, "\\x00", context);
}
// src/backcompat.js
var incompatibleEscapeChars = "&!#%,:;<=>@`~";
var token = new RegExp(String.raw`
\[\^?-?
| --?\]
| (?<dp>[${doublePunctuatorChars}])\k<dp>
| --
| \\(?<vOnlyEscape>[${incompatibleEscapeChars}])
| \\[pPu]\{[^}]+\}
| \\?.
`.replace(/\s+/g, ""), "gsu");
function backcompatPlugin(expression) {
const unescapedLiteralHyphenMsg = 'Invalid unescaped "-" in character class';
let inCharClass = false;
let result = "";
for (const { 0: m, groups: { dp, vOnlyEscape } } of expression.matchAll(token)) {
if (m[0] === "[") {
if (inCharClass) {
throw new Error("Invalid nested character class when flag v not supported; possibly from interpolation");
}
if (m.endsWith("-")) {
throw new Error(unescapedLiteralHyphenMsg);
}
inCharClass = true;
} else if (m.endsWith("]")) {
if (m[0] === "-") {
throw new Error(unescapedLiteralHyphenMsg);
}
inCharClass = false;
} else if (inCharClass) {
if (m === "&&" || m === "--") {
throw new Error(`Invalid set operator "${m}" when flag v not supported`);
} else if (dp) {
throw new Error(`Invalid double punctuator "${m}", reserved by flag v`);
} else if ("(){}/|".includes(m)) {
throw new Error(`Invalid unescaped "${m}" in character class`);
} else if (vOnlyEscape) {
result += vOnlyEscape;
continue;
}
}
result += m;
}
return result;
}
// src/flag-n.js
var token2 = new RegExp(String.raw`
${noncapturingDelim}
| \(\?<
| (?<backrefNum>\\[1-9]\d*)
| \\?.
`.replace(/\s+/g, ""), "gsu");
function flagNPreprocessor(value, runningContext) {
value = String(value);
let expression = "";
let transformed = "";
for (const { 0: m, groups: { backrefNum } } of value.matchAll(token2)) {
expression += m;
runningContext = getEndContextForIncompleteExpression(expression, runningContext);
const { regexContext } = runningContext;
if (regexContext === RegexContext.DEFAULT) {
if (m === "(") {
transformed += "(?:";
} else if (backrefNum) {
throw new Error(`Invalid decimal escape "${m}" with implicit flag n; replace with named backreference`);
} else {
transformed += m;
}
} else {
transformed += m;
}
}
return {
transformed,
runningContext
};
}
// src/flag-x.js
var ws = /^\s$/;
var escapedWsOrHash = /^\\[\s#]$/;
var charClassWs = /^[ \t]$/;
var escapedCharClassWs = /^\\[ \t]$/;
var token3 = new RegExp(String.raw`
\\(?: [gk]<
| [pPu]\{
| c[A-Za-z]
| u[A-Fa-f\d]{4}
| x[A-Fa-f\d]{2}
| 0\d+
)
| \[\^
| ${noncapturingDelim}
| \(\?<
| (?<dp>[${doublePunctuatorChars}])\k<dp>
| --
| \\?.
`.replace(/\s+/g, ""), "gsu");
function flagXPreprocessor(value, runningContext, options) {
value = String(value);
let ignoringWs = false;
let ignoringCharClassWs = false;
let ignoringComment = false;
let expression = "";
let transformed = "";
let lastSignificantToken = "";
let lastSignificantCharClassContext = "";
let separatorNeeded = false;
const update = (str, options2) => {
const opts = {
prefix: true,
postfix: false,
...options2
};
str = (separatorNeeded && opts.prefix ? "(?:)" : "") + str + (opts.postfix ? "(?:)" : "");
separatorNeeded = false;
return str;
};
for (const { 0: m, index } of value.matchAll(token3)) {
if (ignoringComment) {
if (m === "\n") {
ignoringComment = false;
separatorNeeded = true;
}
continue;
}
if (ignoringWs) {
if (ws.test(m)) {
continue;
}
ignoringWs = false;
separatorNeeded = true;
} else if (ignoringCharClassWs) {
if (charClassWs.test(m)) {
continue;
}
ignoringCharClassWs = false;
}
expression += m;
runningContext = getEndContextForIncompleteExpression(expression, runningContext);
const { regexContext, charClassContext } = runningContext;
if (
// `--` is matched in one step, so boundary chars aren't `-` unless separated by whitespace
m === "-" && regexContext === RegexContext.CHAR_CLASS && lastSignificantCharClassContext === CharClassContext.RANGE && (options.flags.includes("v") || options.unicodeSetsPlugin)
) {
throw new Error("Invalid unescaped hyphen as the end value for a range");
}
if (
// `??` is matched in one step by the double punctuator token
regexContext === RegexContext.DEFAULT && /^(?:[?*+]|\?\?)$/.test(m) || regexContext === RegexContext.INTERVAL_QUANTIFIER && m === "{"
) {
transformed += update(m, { prefix: false, postfix: lastSignificantToken === "(" && m === "?" });
} else if (regexContext === RegexContext.DEFAULT) {
if (ws.test(m)) {
ignoringWs = true;
} else if (m.startsWith("#")) {
ignoringComment = true;
} else if (escapedWsOrHash.test(m)) {
transformed += update(m[1], { prefix: false });
} else {
transformed += update(m);
}
} else if (regexContext === RegexContext.CHAR_CLASS && m !== "[" && m !== "[^") {
if (charClassWs.test(m) && (charClassContext === CharClassContext.DEFAULT || charClassContext === CharClassContext.ENCLOSED_Q || charClassContext === CharClassContext.RANGE)) {
ignoringCharClassWs = true;
} else if (charClassContext === CharClassContext.INVALID_INCOMPLETE_TOKEN) {
throw new Error(`Invalid incomplete token in character class: "${m}"`);
} else if (escapedCharClassWs.test(m) && (charClassContext === CharClassContext.DEFAULT || charClassContext === CharClassContext.ENCLOSED_Q)) {
transformed += update(m[1], { prefix: false });
} else if (charClassContext === CharClassContext.DEFAULT) {
const nextChar = value[index + 1] ?? "";
let updated = sandboxUnsafeNulls(m);
if (charClassWs.test(nextChar) || m === "^") {
updated = sandboxLoneDoublePunctuatorChar(updated);
}
transformed += update(updated);
} else {
transformed += update(m);
}
} else {
transformed += update(m);
}
if (!(ignoringWs || ignoringCharClassWs || ignoringComment)) {
lastSignificantToken = m;
lastSignificantCharClassContext = charClassContext;
}
}
return {
transformed,
runningContext
};
}
function clean(expression) {
const sep = String.raw`\(\?:\)`;
expression = replaceUnescaped(expression, `(?:${sep}){2,}`, "(?:)", Context.DEFAULT);
const marker = emulationGroupMarker.replace(/\$/g, "\\$");
expression = replaceUnescaped(
expression,
String.raw`(?:${sep}(?=[)|.[$\\]|\((?!DEFINE)|$)|(?<=[()|.\]^>]|\\[bBdDfnrsStvwW]|\(\?(?:[:=!]|<[=!])|^)${sep}(?![?*+{]))(?!${marker})`,
"",
Context.DEFAULT
);
return expression;
}
// src/subroutines.js
function subroutines(expression, data) {
const namedGroups = getNamedCapturingGroups(expression, { includeContents: true });
const transformed = processSubroutines(expression, namedGroups, !!data?.useEmulationGroups);
return processDefinitionGroup(transformed, namedGroups);
}
var subroutinePattern = String.raw`\\g<(?<subroutineName>[^>&]+)>`;
var token4 = new RegExp(String.raw`
${subroutinePattern}
| (?<capturingStart>${capturingDelim})
| \\(?<backrefNum>[1-9]\d*)
| \\k<(?<backrefName>[^>]+)>
| \\?.
`.replace(/\s+/g, ""), "gsu");
function processSubroutines(expression, namedGroups, useEmulationGroups) {
if (!/\\g</.test(expression)) {
return expression;
}
const hasBackrefs = hasUnescaped(expression, "\\\\(?:[1-9]|k<[^>]+>)", Context.DEFAULT);
const subroutineWrapper = hasBackrefs ? `(${useEmulationGroups ? emulationGroupMarker : ""}` : "(?:";
const openSubroutines = /* @__PURE__ */ new Map();
const openSubroutinesStack = [];
const captureNumMap = [0];
let numCapturesPassedOutsideSubroutines = 0;
let numCapturesPassedInsideSubroutines = 0;
let numCapturesPassedInsideThisSubroutine = 0;
let numSubroutineCapturesTrackedInRemap = 0;
let numCharClassesOpen = 0;
let result = expression;
let match;
token4.lastIndex = 0;
while (match = token4.exec(result)) {
const { 0: m, index, groups: { subroutineName, capturingStart, backrefNum, backrefName } } = match;
if (m === "[") {
numCharClassesOpen++;
} else if (!numCharClassesOpen) {
if (subroutineName) {
if (!namedGroups.has(subroutineName)) {
throw new Error(`Invalid named capture referenced by subroutine ${m}`);
}
if (openSubroutines.has(subroutineName)) {
throw new Error(`Subroutine ${m} followed a recursive reference`);
}
const contents = namedGroups.get(subroutineName).contents;
const subroutineValue = `${subroutineWrapper}${contents})`;
if (hasBackrefs) {
numCapturesPassedInsideThisSubroutine = 0;
numCapturesPassedInsideSubroutines++;
}
openSubroutines.set(subroutineName, {
// Incrementally decremented to track when we've left the group
unclosedGroupCount: countOpenParens(subroutineValue)
});
openSubroutinesStack.push(subroutineName);
result = spliceStr(result, index, m, subroutineValue);
token4.lastIndex -= m.length - subroutineWrapper.length;
} else if (capturingStart) {
if (openSubroutines.size) {
if (hasBackrefs) {
numCapturesPassedInsideThisSubroutine++;
numCapturesPassedInsideSubroutines++;
}
if (m !== "(") {
result = spliceStr(result, index, m, subroutineWrapper);
token4.lastIndex -= m.length - subroutineWrapper.length;
}
} else if (hasBackrefs) {
captureNumMap.push(
lastOf(captureNumMap) + 1 + numCapturesPassedInsideSubroutines - numSubroutineCapturesTrackedInRemap
);
numSubroutineCapturesTrackedInRemap = numCapturesPassedInsideSubroutines;
numCapturesPassedOutsideSubroutines++;
}
} else if ((backrefNum || backrefName) && openSubroutines.size) {
const num = backrefNum ? +backrefNum : namedGroups.get(backrefName)?.groupNum;
let isGroupFromThisSubroutine = false;
for (const s of openSubroutinesStack) {
const group = namedGroups.get(s);
if (num >= group.groupNum && num <= group.groupNum + group.numCaptures) {
isGroupFromThisSubroutine = true;
break;
}
}
if (isGroupFromThisSubroutine) {
const group = namedGroups.get(lastOf(openSubroutinesStack));
const subroutineNum = numCapturesPassedOutsideSubroutines + numCapturesPassedInsideSubroutines - numCapturesPassedInsideThisSubroutine;
const metadata = `\\k<$$b${num}s${subroutineNum}r${group.groupNum}c${group.numCaptures}>`;
result = spliceStr(result, index, m, metadata);
token4.lastIndex += metadata.length - m.length;
}
} else if (m === ")") {
if (openSubroutines.size) {
const subroutine = openSubroutines.get(lastOf(openSubroutinesStack));
subroutine.unclosedGroupCount--;
if (!subroutine.unclosedGroupCount) {
openSubroutines.delete(openSubroutinesStack.pop());
}
}
}
} else if (m === "]") {
numCharClassesOpen--;
}
}
if (hasBackrefs) {
result = replaceUnescaped(
result,
String.raw`\\(?:(?<bNum>[1-9]\d*)|k<\$\$b(?<bNumSub>\d+)s(?<subNum>\d+)r(?<refNum>\d+)c(?<refCaps>\d+)>)`,
({ 0: m, groups: { bNum, bNumSub, subNum, refNum, refCaps } }) => {
if (bNum) {
const backrefNum = +bNum;
if (backrefNum > captureNumMap.length - 1) {
throw new Error(`Backref "${m}" greater than number of captures`);
}
return `\\${captureNumMap[backrefNum]}`;
}
const backrefNumInSubroutine = +bNumSub;
const subroutineGroupNum = +subNum;
const refGroupNum = +refNum;
const numCapturesInRef = +refCaps;
if (backrefNumInSubroutine < refGroupNum || backrefNumInSubroutine > refGroupNum + numCapturesInRef) {
return `\\${captureNumMap[backrefNumInSubroutine]}`;
}
return `\\${subroutineGroupNum - refGroupNum + backrefNumInSubroutine}`;
},
Context.DEFAULT
);
}
return result;
}
var defineGroupToken = new RegExp(String.raw`${namedCapturingDelim}|\(\?:\)|(?<invalid>\\?.)`, "gsu");
function processDefinitionGroup(expression, namedGroups) {
const defineMatch = execUnescaped(expression, String.raw`\(\?\(DEFINE\)`, 0, Context.DEFAULT);
if (!defineMatch) {
return expression;
}
const defineGroup = getGroup(expression, defineMatch);
if (defineGroup.afterPos < expression.length) {
throw new Error("DEFINE group allowed only at the end of a regex");
} else if (defineGroup.afterPos > expression.length) {
throw new Error("DEFINE group is unclosed");
}
let match;
defineGroupToken.lastIndex = 0;
while (match = defineGroupToken.exec(defineGroup.contents)) {
const { captureName, invalid } = match.groups;
if (captureName) {
const group = getGroup(defineGroup.contents, match);
let duplicateName;
if (!namedGroups.get(captureName).isUnique) {
duplicateName = captureName;
} else {
const nestedNamedGroups = getNamedCapturingGroups(group.contents, { includeContents: false });
for (const name of nestedNamedGroups.keys()) {
if (!namedGroups.get(name).isUnique) {
duplicateName = name;
break;
}
}
}
if (duplicateName) {
throw new Error(`Duplicate group name "${duplicateName}" within DEFINE`);
}
defineGroupToken.lastIndex = group.afterPos;
} else if (invalid) {
throw new Error(`DEFINE group includes unsupported syntax at top level`);
}
}
return expression.slice(0, defineMatch.index);
}
function countOpenParens(expression) {
let num = 0;
forEachUnescaped(expression, "\\(", () => num++, Context.DEFAULT);
return num;
}
function getCaptureNum(expression, groupName) {
let num = 0;
let pos = 0;
let match;
while (match = execUnescaped(expression, capturingDelim, pos, Context.DEFAULT)) {
const { 0: m, index, groups: { captureName } } = match;
num++;
if (captureName === groupName) {
break;
}
pos = index + m.length;
}
return num;
}
function getGroup(expression, delimMatch) {
const contentsStart = delimMatch.index + delimMatch[0].length;
const contents = getGroupContents(expression, contentsStart);
const afterPos = contentsStart + contents.length + 1;
return {
contents,
afterPos
};
}
function getNamedCapturingGroups(expression, { includeContents }) {
const namedGroups = /* @__PURE__ */ new Map();
forEachUnescaped(
expression,
namedCapturingDelim,
({ 0: m, index, groups: { captureName } }) => {
if (namedGroups.has(captureName)) {
namedGroups.get(captureName).isUnique = false;
} else {
const group = { isUnique: true };
if (includeContents) {
const contents = getGroupContents(expression, index + m.length);
Object.assign(group, {
contents,
groupNum: getCaptureNum(expression, captureName),
numCaptures: countCaptures(contents)
});
}
namedGroups.set(captureName, group);
}
},
Context.DEFAULT
);
return namedGroups;
}
function lastOf(arr) {
return arr[arr.length - 1];
}
// src/regex.js
var regex = (first, ...substitutions) => {
if (Array.isArray(first?.raw)) {
return regexFromTemplate({}, first, ...substitutions);
} else if ((typeof first === "string" || first === void 0) && !substitutions.length) {
return regexFromTemplate.bind(null, { flags: first ?? "" });
} else if ({}.toString.call(first) === "[object Object]" && !substitutions.length) {
return regexFromTemplate.bind(null, first);
}
throw new Error(`Unexpected arguments: ${JSON.stringify([first, ...substitutions])}`);
};
var regexFromTemplate = (options, template, ...substitutions) => {
const opts = getOptions(options);
const prepped = handlePreprocessors(template, substitutions, opts);
let precedingCaptures = 0;
let expression = "";
let runningContext;
prepped.template.raw.forEach((raw, i) => {
const wrapEscapedStr = !!(prepped.template.raw[i] || prepped.template.raw[i + 1]);
precedingCaptures += countCaptures(raw);
expression += sandboxUnsafeNulls(raw, Context.CHAR_CLASS);
runningContext = getEndContextForIncompleteExpression(expression, runningContext);
const { regexContext, charClassContext } = runningContext;
if (i < prepped.template.raw.length - 1) {
const substitution = prepped.substitutions[i];
expression += interpolate(substitution, opts.flags, regexContext, charClassContext, wrapEscapedStr, precedingCaptures);
if (substitution instanceof RegExp) {
precedingCaptures += countCaptures(substitution.source);
} else if (substitution instanceof Pattern) {
precedingCaptures += countCaptures(String(substitution));
}
}
});
expression = handlePlugins(expression, opts);
try {
return opts.subclass ? new RegExpSubclass(expression, opts.flags, { useEmulationGroups: true }) : new RegExp(expression, opts.flags);
} catch (err) {
const stripped = err.message.replace(/ \/.+\/[a-z]*:/, "");
err.message = `${stripped}: /${expression}/${opts.flags}`;
throw err;
}
};
function rewrite(expression = "", options) {
const opts = getOptions(options);
if (opts.subclass) {
throw new Error("Cannot use option subclass");
}
return {
expression: handlePlugins(
handlePreprocessors({ raw: [expression] }, [], opts).template.raw[0],
opts
),
flags: opts.flags
};
}
function getOptions(options) {
const opts = {
flags: "",
subclass: false,
plugins: [],
unicodeSetsPlugin: backcompatPlugin,
disable: {
/* n, v, x, atomic, subroutines */
},
force: {
/* v */
},
...options
};
if (/[nuvx]/.test(opts.flags)) {
throw new Error("Implicit flags v/u/x/n cannot be explicitly added");
}
const useFlagV = opts.force.v || (opts.disable.v ? false : envSupportsFlagV);
opts.flags += useFlagV ? "v" : "u";
if (useFlagV) {
opts.unicodeSetsPlugin = null;
}
return opts;
}
function handlePreprocessors(template, substitutions, options) {
const preprocessors = [];
if (!options.disable.x) {
preprocessors.push(flagXPreprocessor);
}
if (!options.disable.n) {
preprocessors.push(flagNPreprocessor);
}
for (const pp of preprocessors) {
({ template, substitutions } = preprocess(template, substitutions, pp, options));
}
return {
template,
substitutions
};
}
function handlePlugins(expression, options) {
const { flags, plugins, unicodeSetsPlugin, disable, subclass } = options;
[
...plugins,
// Run first, so provided plugins can output extended syntax
...disable.subroutines ? [] : [subroutines],
...disable.atomic ? [] : [possessive, atomic],
...disable.x ? [] : [clean],
// Run last, so it doesn't have to worry about parsing extended syntax
...!unicodeSetsPlugin ? [] : [unicodeSetsPlugin]
].forEach((p) => expression = p(expression, { flags, useEmulationGroups: subclass }));
return expression;
}
function interpolate(value, flags, regexContext, charClassContext, wrapEscapedStr, precedingCaptures) {
if (value instanceof RegExp && regexContext !== RegexContext.DEFAULT) {
throw new Error("Cannot interpolate a RegExp at this position because the syntax context does not match");
}
if (regexContext === RegexContext.INVALID_INCOMPLETE_TOKEN || charClassContext === CharClassContext.INVALID_INCOMPLETE_TOKEN) {
throw new Error("Interpolation preceded by invalid incomplete token");
}
if (typeof value === "number" && (regexContext === RegexContext.ENCLOSED_U || charClassContext === CharClassContext.ENCLOSED_U)) {
return value.toString(16);
}
const isPattern = value instanceof Pattern;
let escapedValue = "";
if (!(value instanceof RegExp)) {
value = String(value);
if (!isPattern) {
escapedValue = escapeV(
value,
regexContext === RegexContext.CHAR_CLASS ? Context.CHAR_CLASS : Context.DEFAULT
);
}
const breakoutChar = getBreakoutChar(escapedValue || value, regexContext, charClassContext);
if (breakoutChar) {
throw new Error(`Unescaped stray "${breakoutChar}" in the interpolated value would have side effects outside it`);
}
}
if (regexContext === RegexContext.INTERVAL_QUANTIFIER || regexContext === RegexContext.GROUP_NAME || enclosedTokenRegexContexts.has(regexContext) || enclosedTokenCharClassContexts.has(charClassContext)) {
return isPattern ? String(value) : escapedValue;
} else if (regexContext === RegexContext.CHAR_CLASS) {
if (isPattern) {
if (hasUnescaped(String(value), "^-|^&&|-$|&&$")) {
throw new Error("Cannot use range or set operator at boundary of interpolated pattern; move the operation into the pattern or the operator outside of it");
}
const sandboxedValue = sandboxLoneCharClassCaret(sandboxLoneDoublePunctuatorChar(value));
return containsCharClassUnion(value) ? `[${sandboxedValue}]` : sandboxUnsafeNulls(sandboxedValue);
}
return containsCharClassUnion(escapedValue) ? `[${escapedValue}]` : escapedValue;
}
if (value instanceof RegExp) {
const transformed = transformForLocalFlags(value, flags);
const backrefsAdjusted = adjustNumberedBackrefs(transformed.value, precedingCaptures);
return transformed.usedModifier ? backrefsAdjusted : `(?:${backrefsAdjusted})`;
}
if (isPattern) {
return `(?:${value})`;
}
return wrapEscapedStr ? `(?:${escapedValue})` : escapedValue;
}
function transformForLocalFlags(re, outerFlags) {
const modFlagsObj = {
i: null,
m: null,
s: null
};
const newlines = "\\n\\r\\u2028\\u2029";
let value = re.source;
if (re.ignoreCase !== outerFlags.includes("i")) {
if (envSupportsFlagGroups) {
modFlagsObj.i = re.ignoreCase;
} else {
throw new Error("Pattern modifiers not supported, so flag i on the outer and interpolated regex must match");
}
}
if (re.dotAll !== outerFlags.includes("s")) {
if (envSupportsFlagGroups) {
modFlagsObj.s = re.dotAll;
} else {
value = replaceUnescaped(value, "\\.", re.dotAll ? "[^]" : `[^${newlines}]`, Context.DEFAULT);
}
}
if (re.multiline !== outerFlags.includes("m")) {
if (envSupportsFlagGroups) {
modFlagsObj.m = re.multiline;
} else {
value = replaceUnescaped(value, "\\^", re.multiline ? `(?<=^|[${newlines}])` : "(?<![^])", Context.DEFAULT);
value = replaceUnescaped(value, "\\$", re.multiline ? `(?=$|[${newlines}])` : "(?![^])", Context.DEFAULT);
}
}
if (envSupportsFlagGroups) {
const keys = Object.keys(modFlagsObj);
let modifier = keys.filter((k) => modFlagsObj[k] === true).join("");
const modOff = keys.filter((k) => modFlagsObj[k] === false).join("");
if (modOff) {
modifier += `-${modOff}`;
}
if (modifier) {
return {
value: `(?${modifier}:${value})`,
usedModifier: true
};
}
}
return { value };
}
export {
pattern,
regex,
rewrite
};
//# sourceMappingURL=regex.js.map