regex-partial-match 1.3.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. package/README.md +154 -301
  2. package/lib/core/corePartialMatchRegExp.d.ts +24 -0
  3. package/lib/core/corePartialMatchRegExp.js +22 -0
  4. package/lib/core/index.d.ts +4 -0
  5. package/lib/core/index.js +2 -0
  6. package/lib/extend/index.d.ts +6 -7
  7. package/lib/extend/index.js +1 -1
  8. package/lib/features/index.d.ts +20 -0
  9. package/lib/features/index.js +23 -0
  10. package/lib/hitEnd/index.d.ts +45 -0
  11. package/lib/hitEnd/index.js +57 -0
  12. package/lib/hitEnd/matchHitEnd.d.ts +4 -0
  13. package/lib/hitEnd/matchHitEnd.js +51 -0
  14. package/lib/{partialMatchRegExp/isComplete → hitEnd}/partRole.d.ts +1 -1
  15. package/lib/hitEnd/partRole.js +17 -0
  16. package/lib/hitEnd/truncationProbe.d.ts +8 -0
  17. package/lib/hitEnd/truncationProbe.js +187 -0
  18. package/lib/hitEnd/truncationProbeCache.d.ts +14 -0
  19. package/lib/index.d.ts +4 -0
  20. package/lib/index.js +4 -0
  21. package/lib/modules/backreferences/asNativeAtom.d.ts +2 -0
  22. package/lib/{partialMatchRegExp/compilePartial → modules/backreferences}/asNativeAtom.js +2 -2
  23. package/lib/modules/backreferences/asPreScanPart.d.ts +2 -0
  24. package/lib/{partialMatchRegExp/compilePartial → modules/backreferences}/asPreScanPart.js +2 -2
  25. package/lib/modules/backreferences/backreferenceRecorder.d.ts +2 -0
  26. package/lib/modules/backreferences/backreferenceRecorder.js +38 -0
  27. package/lib/modules/backreferences/compileDynamic.d.ts +4 -0
  28. package/lib/modules/backreferences/compileDynamic.js +53 -0
  29. package/lib/modules/backreferences/compiledBackreferences.d.ts +9 -0
  30. package/lib/modules/backreferences/compiledBackreferences.js +9 -0
  31. package/lib/modules/backreferences/constants.d.ts +2 -0
  32. package/lib/modules/backreferences/constants.js +2 -0
  33. package/lib/modules/backreferences/execDynamic.d.ts +2 -0
  34. package/lib/modules/backreferences/execDynamic.js +43 -0
  35. package/lib/{partialMatchRegExp/compilePartial → modules/backreferences}/flagsAtBackreference.d.ts +1 -1
  36. package/lib/{partialMatchRegExp → modules/backreferences}/groupName.js +1 -1
  37. package/lib/modules/backreferences/index.d.ts +10 -0
  38. package/lib/modules/backreferences/index.js +20 -0
  39. package/lib/modules/backreferences/longestBakedPrefixEndingInput.js +46 -0
  40. package/lib/{partialMatchRegExp/compilePartial → modules/backreferences}/renderParts.d.ts +1 -1
  41. package/lib/{partialMatchRegExp/compilePartial → modules/backreferences}/renderParts.js +1 -1
  42. package/lib/{partialMatchRegExp/compilePartial → modules/backreferences}/resolvedFromScan.d.ts +1 -1
  43. package/lib/{partialMatchRegExp/compilePartial → modules/backreferences}/resolvedFromScan.js +2 -2
  44. package/lib/{partialMatchRegExp/compilePartial → modules/backreferences}/startsWithUnderFlags.js +1 -1
  45. package/lib/modules/carets/appendMultilineCaret.d.ts +7 -0
  46. package/lib/modules/carets/appendMultilineCaret.js +181 -0
  47. package/lib/modules/carets/caretRecorder.d.ts +2 -0
  48. package/lib/modules/carets/caretRecorder.js +164 -0
  49. package/lib/modules/carets/caretSyntax.d.ts +3 -0
  50. package/lib/modules/carets/caretSyntax.js +11 -0
  51. package/lib/modules/carets/index.d.ts +9 -0
  52. package/lib/modules/carets/index.js +18 -0
  53. package/lib/modules/carets/lineTerminator.d.ts +1 -0
  54. package/lib/modules/carets/lineTerminator.js +31 -0
  55. package/lib/modules/carets/needsCaretRules.d.ts +1 -0
  56. package/lib/modules/carets/needsCaretRules.js +15 -0
  57. package/lib/modules/carets/quantifierBounds.d.ts +3 -0
  58. package/lib/modules/carets/quantifierBounds.js +18 -0
  59. package/lib/modules/index.d.ts +3 -0
  60. package/lib/modules/index.js +2 -0
  61. package/lib/partialMatchRegExp/atomSyntax.d.ts +14 -1
  62. package/lib/partialMatchRegExp/atomSyntax.js +24 -1
  63. package/lib/partialMatchRegExp/backreferenceExpansion.d.ts +1 -6
  64. package/lib/partialMatchRegExp/backreferenceHook.d.ts +11 -0
  65. package/lib/partialMatchRegExp/backreferenceHook.js +1 -0
  66. package/lib/partialMatchRegExp/caretHook.d.ts +17 -0
  67. package/lib/partialMatchRegExp/caretHook.js +5 -0
  68. package/lib/partialMatchRegExp/compilePartial/compileWith.d.ts +3 -0
  69. package/lib/partialMatchRegExp/compilePartial/compileWith.js +36 -0
  70. package/lib/partialMatchRegExp/compilePartial/compiled.d.ts +17 -17
  71. package/lib/partialMatchRegExp/compilePartial/compiled.js +8 -21
  72. package/lib/partialMatchRegExp/compilePartial/constants.d.ts +4 -0
  73. package/lib/partialMatchRegExp/compilePartial/constants.js +4 -0
  74. package/lib/partialMatchRegExp/compilePartial/groupShape.d.ts +4 -0
  75. package/lib/partialMatchRegExp/compilePartial/groupShape.js +9 -0
  76. package/lib/partialMatchRegExp/compilePartial/toStatic.d.ts +2 -2
  77. package/lib/partialMatchRegExp/compilePartial/toStatic.js +2 -2
  78. package/lib/partialMatchRegExp/constants.d.ts +5 -0
  79. package/lib/partialMatchRegExp/constants.js +5 -0
  80. package/lib/partialMatchRegExp/createPartialMatchRegExp.d.ts +3 -0
  81. package/lib/partialMatchRegExp/createPartialMatchRegExp.js +21 -0
  82. package/lib/partialMatchRegExp/execFrom.d.ts +1 -0
  83. package/lib/partialMatchRegExp/execFrom.js +4 -0
  84. package/lib/partialMatchRegExp/index.d.ts +49 -3
  85. package/lib/partialMatchRegExp/index.js +31 -3
  86. package/lib/partialMatchRegExp/moduleHooks.d.ts +14 -0
  87. package/lib/partialMatchRegExp/moduleHooks.js +15 -0
  88. package/lib/partialMatchRegExp/opaqueModule.d.ts +9 -0
  89. package/lib/partialMatchRegExp/opaqueModule.js +1 -0
  90. package/lib/partialMatchRegExp/part.d.ts +2 -11
  91. package/lib/partialMatchRegExp/partialMatchInternals.d.ts +2 -1
  92. package/lib/partialMatchRegExp/partialMatchInternals.js +3 -1
  93. package/lib/partialMatchRegExp/quantifier.d.ts +6 -0
  94. package/lib/partialMatchRegExp/quantifier.js +9 -0
  95. package/lib/partialMatchRegExp/rawLookaroundInfo.d.ts +11 -0
  96. package/lib/partialMatchRegExp/rawLookaroundInfo.js +1 -0
  97. package/lib/partialMatchRegExp/regexFeatures.d.ts +1 -5
  98. package/lib/partialMatchRegExp/regexFeatures.js +2 -8
  99. package/lib/partialMatchRegExp/scope.d.ts +12 -0
  100. package/lib/partialMatchRegExp/scope.js +45 -0
  101. package/lib/partialMatchRegExp/walk.d.ts +13 -5
  102. package/lib/partialMatchRegExp/walk.js +211 -165
  103. package/lib/partialMatchRegExp/withModules.d.ts +13 -0
  104. package/lib/partialMatchRegExp/withModules.js +27 -0
  105. package/package.json +39 -56
  106. package/lib/partialMatchRegExp/compilePartial/asNativeAtom.d.ts +0 -2
  107. package/lib/partialMatchRegExp/compilePartial/asOptionalAtom.d.ts +0 -1
  108. package/lib/partialMatchRegExp/compilePartial/asOptionalAtom.js +0 -4
  109. package/lib/partialMatchRegExp/compilePartial/asPreScanPart.d.ts +0 -2
  110. package/lib/partialMatchRegExp/compilePartial/index.d.ts +0 -2
  111. package/lib/partialMatchRegExp/compilePartial/index.js +0 -79
  112. package/lib/partialMatchRegExp/compilePartial/longestBakedPrefixEndingInput.js +0 -50
  113. package/lib/partialMatchRegExp/compilePartial/reclassifyLegacyEscapes.d.ts +0 -2
  114. package/lib/partialMatchRegExp/compilePartial/reclassifyLegacyEscapes.js +0 -17
  115. package/lib/partialMatchRegExp/compilePartial/spliceOriginalSource.d.ts +0 -2
  116. package/lib/partialMatchRegExp/compilePartial/spliceOriginalSource.js +0 -12
  117. package/lib/partialMatchRegExp/isComplete/index.d.ts +0 -38
  118. package/lib/partialMatchRegExp/isComplete/index.js +0 -41
  119. package/lib/partialMatchRegExp/isComplete/isMatchComplete.d.ts +0 -3
  120. package/lib/partialMatchRegExp/isComplete/isMatchComplete.js +0 -14
  121. package/lib/partialMatchRegExp/isComplete/partRole.js +0 -28
  122. package/lib/partialMatchRegExp/isComplete/truncationProbe.d.ts +0 -8
  123. package/lib/partialMatchRegExp/isComplete/truncationProbe.js +0 -105
  124. package/lib/partialMatchRegExp/isComplete/truncationProbeCache.d.ts +0 -4
  125. package/lib/partialMatchRegExp/partialMatchRegExp.d.ts +0 -55
  126. package/lib/partialMatchRegExp/partialMatchRegExp.js +0 -114
  127. package/lib/partialMatchRegExp/preferLongerCaptures.d.ts +0 -1
  128. package/lib/partialMatchRegExp/preferLongerCaptures.js +0 -30
  129. /package/lib/{partialMatchRegExp/isComplete → hitEnd}/truncationProbeCache.js +0 -0
  130. /package/lib/{partialMatchRegExp/compilePartial → modules/backreferences}/caseFoldFlags.d.ts +0 -0
  131. /package/lib/{partialMatchRegExp/compilePartial → modules/backreferences}/caseFoldFlags.js +0 -0
  132. /package/lib/{partialMatchRegExp → modules/backreferences}/escapeAtom.d.ts +0 -0
  133. /package/lib/{partialMatchRegExp → modules/backreferences}/escapeAtom.js +0 -0
  134. /package/lib/{partialMatchRegExp/compilePartial → modules/backreferences}/flagsAtBackreference.js +0 -0
  135. /package/lib/{partialMatchRegExp → modules/backreferences}/groupName.d.ts +0 -0
  136. /package/lib/{partialMatchRegExp/compilePartial → modules/backreferences}/longestBakedPrefixEndingInput.d.ts +0 -0
  137. /package/lib/{partialMatchRegExp/compilePartial → modules/backreferences}/startsWithUnderFlags.d.ts +0 -0
@@ -0,0 +1,53 @@
1
+ import escapeAtom from "./escapeAtom.js";
2
+ import { ALTERNATION } from "./constants.js";
3
+ import { GROUP_CLOSING, ONLY_AT_END_OF_INPUT, OPTIONAL_ATOM_OPENING, asOptionalAtom } from "../../partialMatchRegExp/atomSyntax.js";
4
+ import { isBackreference } from "../../partialMatchRegExp/part.js";
5
+ import { CompiledBackreferences } from "./compiledBackreferences.js";
6
+ import asPreScanPart from "./asPreScanPart.js";
7
+ import resolvedFromScan from "./resolvedFromScan.js";
8
+ import startsWithUnderFlags from "./startsWithUnderFlags.js";
9
+ import longestBakedPrefixEndingInput from "./longestBakedPrefixEndingInput.js";
10
+ import flagsAtBackreference from "./flagsAtBackreference.js";
11
+ export default function compileDynamic(parts, backreferences, flags, isUnicode, featureMask, hooks) {
12
+ const dynamic = {
13
+ preScan: new RegExp(parts.map(asPreScanPart).join(""), flags),
14
+ expansionFitsCaptures: (expandedFrom, match, input) => {
15
+ var _a;
16
+ for (const backref of backreferences) {
17
+ const baked = resolvedFromScan(backref, expandedFrom);
18
+ if (baked === undefined)
19
+ continue;
20
+ const resolved = (_a = resolvedFromScan(backref, match)) !== null && _a !== void 0 ? _a : "";
21
+ if (resolved === baked)
22
+ continue;
23
+ const backrefFlags = flagsAtBackreference(backref, flags);
24
+ const consumed = longestBakedPrefixEndingInput(baked, input, backrefFlags);
25
+ if (!startsWithUnderFlags(resolved, consumed, backrefFlags))
26
+ return false;
27
+ }
28
+ return true;
29
+ },
30
+ expand: (capture) => {
31
+ const expanded = [];
32
+ for (const part of parts) {
33
+ if (!isBackreference(part)) {
34
+ expanded.push(part);
35
+ continue;
36
+ }
37
+ const captured = resolvedFromScan(part, capture);
38
+ if (captured === undefined || captured === "") {
39
+ expanded.push(part);
40
+ continue;
41
+ }
42
+ const atoms = isUnicode ? Array.from(captured) : captured.split("");
43
+ expanded.push(OPTIONAL_ATOM_OPENING, part, ALTERNATION);
44
+ for (const atom of atoms) {
45
+ expanded.push(asOptionalAtom(escapeAtom(atom)));
46
+ }
47
+ expanded.push(ONLY_AT_END_OF_INPUT, GROUP_CLOSING);
48
+ }
49
+ return expanded;
50
+ }
51
+ };
52
+ return new CompiledBackreferences(dynamic, parts, featureMask, hooks);
53
+ }
@@ -0,0 +1,9 @@
1
+ import { Compiled, type CompiledDynamic, type DynamicPath } from "../../partialMatchRegExp/compilePartial/compiled.ts";
2
+ import type { Part } from "../../partialMatchRegExp/part.ts";
3
+ import type { Hooks } from "../../partialMatchRegExp/walk.ts";
4
+ import execDynamic from "./execDynamic.ts";
5
+ export declare class CompiledBackreferences extends Compiled implements CompiledDynamic {
6
+ readonly dynamic: DynamicPath;
7
+ readonly execDynamic: typeof execDynamic;
8
+ constructor(dynamic: DynamicPath, parts: readonly Part[], featureMask: number, hooks: Hooks);
9
+ }
@@ -0,0 +1,9 @@
1
+ import { Compiled } from "../../partialMatchRegExp/compilePartial/compiled.js";
2
+ import execDynamic from "./execDynamic.js";
3
+ export class CompiledBackreferences extends Compiled {
4
+ constructor(dynamic, parts, featureMask, hooks) {
5
+ super(parts, featureMask, hooks);
6
+ this.dynamic = dynamic;
7
+ this.execDynamic = execDynamic;
8
+ }
9
+ }
@@ -0,0 +1,2 @@
1
+ export declare const ANY_CAPTURED_TEXT = "(?:[\\s\\S]*?)";
2
+ export declare const ALTERNATION = "|";
@@ -0,0 +1,2 @@
1
+ export const ANY_CAPTURED_TEXT = "(?:[\\s\\S]*?)";
2
+ export const ALTERNATION = "|";
@@ -0,0 +1,2 @@
1
+ import type { DynamicPath } from "../../partialMatchRegExp/compilePartial/compiled.ts";
2
+ export default function execDynamic(this: RegExp, dynamic: DynamicPath, input: string): RegExpExecArray | null;
@@ -0,0 +1,43 @@
1
+ import renderParts from "./renderParts.js";
2
+ import { backreferenceExpansion } from "../../partialMatchRegExp/backreferenceExpansion.js";
3
+ import execFrom from "../../partialMatchRegExp/execFrom.js";
4
+ function isAtOrBefore(match, index) {
5
+ return match !== null && match.index <= index;
6
+ }
7
+ export default function execDynamic(dynamic, input) {
8
+ const { preScan, expand, expansionFitsCaptures } = dynamic;
9
+ const honoursLastIndex = this.global || this.sticky;
10
+ const start = honoursLastIndex ? this.lastIndex : 0;
11
+ const originalMatch = RegExp.prototype.exec.call(this, input);
12
+ if (isAtOrBefore(originalMatch, start))
13
+ return originalMatch;
14
+ let preScanMatch = null;
15
+ if (originalMatch) {
16
+ preScanMatch = execFrom(preScan, input, start);
17
+ const noEarlierPartialPossible = preScanMatch === null || preScanMatch.index >= originalMatch.index;
18
+ if (noEarlierPartialPossible)
19
+ return originalMatch;
20
+ }
21
+ const capture = preScanMatch !== null && preScanMatch !== void 0 ? preScanMatch : execFrom(preScan, input, start);
22
+ if (capture === null)
23
+ return originalMatch;
24
+ const scanningFlags = honoursLastIndex ? this.flags : this.flags + "g";
25
+ let expandedFrom = capture;
26
+ let expandedParts = expand(expandedFrom);
27
+ let expanded = new RegExp(renderParts(expandedParts), scanningFlags);
28
+ let match = execFrom(expanded, input, start);
29
+ if (match !== null && !expansionFitsCaptures(expandedFrom, match, input)) {
30
+ expandedFrom = match;
31
+ expandedParts = expand(expandedFrom);
32
+ expanded = new RegExp(renderParts(expandedParts), scanningFlags);
33
+ match = execFrom(expanded, input, expandedFrom.index);
34
+ if (match !== null && !expansionFitsCaptures(expandedFrom, match, input))
35
+ match = null;
36
+ }
37
+ if (match === null || isAtOrBefore(originalMatch, match.index))
38
+ return originalMatch;
39
+ if (honoursLastIndex)
40
+ this.lastIndex = expanded.lastIndex;
41
+ match[backreferenceExpansion] = expandedParts;
42
+ return match;
43
+ }
@@ -1,2 +1,2 @@
1
- import type { Backreference } from "../part.ts";
1
+ import type { Backreference } from "../../partialMatchRegExp/part.ts";
2
2
  export default function flagsAtBackreference(backref: Backreference, flags: string): string;
@@ -1,4 +1,4 @@
1
- import { NAMED_GROUP_OPENING } from "./atomSyntax.js";
1
+ import { NAMED_GROUP_OPENING } from "../../partialMatchRegExp/atomSyntax.js";
2
2
  const UNICODE_ESCAPE_IN_NAME_REGEX = /\\u\{([0-9a-fA-F]+)\}|\\u([0-9a-fA-F]{4})/g;
3
3
  export const groupNameOf = (namedGroupOpening) => namedGroupOpening.slice(NAMED_GROUP_OPENING.length, -1);
4
4
  export function decodeGroupName(rawName) {
@@ -0,0 +1,10 @@
1
+ import type { Module } from "../../partialMatchRegExp/opaqueModule.ts";
2
+ /**
3
+ * The module that matches a backreference against the text its group
4
+ * captured, for `withModules` from `regex-partial-match/core`.
5
+ *
6
+ * Without it, the `core` class throws a `TypeError` for a pattern whose
7
+ * backreference can only be resolved at match time.
8
+ */
9
+ declare const backreferences: Module;
10
+ export default backreferences;
@@ -0,0 +1,20 @@
1
+ import { BACKREFERENCES_MODULE, defineModule } from "../../partialMatchRegExp/moduleHooks.js";
2
+ import backreferenceRecorder from "./backreferenceRecorder.js";
3
+ import compileDynamic from "./compileDynamic.js";
4
+ import { scopeWithModifiers } from "../../partialMatchRegExp/scope.js";
5
+ /**
6
+ * The module that matches a backreference against the text its group
7
+ * captured, for `withModules` from `regex-partial-match/core`.
8
+ *
9
+ * Without it, the `core` class throws a `TypeError` for a pattern whose
10
+ * backreference can only be resolved at match time.
11
+ */
12
+ const backreferences = defineModule({
13
+ bit: BACKREFERENCES_MODULE,
14
+ backreference: Object.freeze({
15
+ record: backreferenceRecorder,
16
+ compile: compileDynamic
17
+ }),
18
+ modifiers: scopeWithModifiers
19
+ });
20
+ export default backreferences;
@@ -0,0 +1,46 @@
1
+ import escapeAtom from "./escapeAtom.js";
2
+ import caseFoldFlags from "./caseFoldFlags.js";
3
+ const NO_CASE_FOLDING = { __proto__: null };
4
+ function foldMatchersFor(atoms, flags) {
5
+ if (!flags.includes("i"))
6
+ return NO_CASE_FOLDING;
7
+ const matchers = { __proto__: null };
8
+ const foldFlags = caseFoldFlags(flags);
9
+ for (const atom of atoms) {
10
+ if (!(atom in matchers)) {
11
+ matchers[atom] = new RegExp("^" + escapeAtom(atom), foldFlags);
12
+ }
13
+ }
14
+ return matchers;
15
+ }
16
+ export default function longestBakedPrefixEndingInput(baked, input, flags) {
17
+ if (baked === "")
18
+ return "";
19
+ const isUnicode = flags.includes("u") || flags.includes("v");
20
+ const bakedAtoms = isUnicode ? Array.from(baked) : baked.split("");
21
+ const reach = bakedAtoms.length;
22
+ const withinReach = input.slice(isUnicode ? -2 * reach : -reach);
23
+ const inputAtoms = (isUnicode ? Array.from(withinReach) : withinReach.split("")).slice(-reach);
24
+ const foldMatchers = foldMatchersFor(bakedAtoms, flags);
25
+ const agrees = (bakedIndex, atom) => {
26
+ var _a, _b;
27
+ const bakedAtom = bakedAtoms[bakedIndex];
28
+ return bakedAtom === atom || ((_b = (_a = foldMatchers[bakedAtom]) === null || _a === void 0 ? void 0 : _a.test(atom)) !== null && _b !== void 0 ? _b : false);
29
+ };
30
+ const longestBorder = [0];
31
+ for (let index = 1; index < reach; index++) {
32
+ const atom = bakedAtoms[index];
33
+ let matched = longestBorder[index - 1];
34
+ while (matched > 0 && !agrees(matched, atom))
35
+ matched = longestBorder[matched - 1];
36
+ longestBorder.push(agrees(matched, atom) ? matched + 1 : 0);
37
+ }
38
+ let matched = 0;
39
+ for (const atom of inputAtoms) {
40
+ while (matched > 0 && !agrees(matched, atom))
41
+ matched = longestBorder[matched - 1];
42
+ if (agrees(matched, atom))
43
+ matched++;
44
+ }
45
+ return bakedAtoms.slice(0, matched).join("");
46
+ }
@@ -1,2 +1,2 @@
1
- import { type Part } from "../part.ts";
1
+ import { type Part } from "../../partialMatchRegExp/part.ts";
2
2
  export default function renderParts(parts: readonly Part[]): string;
@@ -1,4 +1,4 @@
1
- import { isBackreference } from "../part.js";
1
+ import { isBackreference } from "../../partialMatchRegExp/part.js";
2
2
  import asNativeAtom from "./asNativeAtom.js";
3
3
  export default function renderParts(parts) {
4
4
  let rendered = "";
@@ -1,2 +1,2 @@
1
- import { type Backreference } from "../part.ts";
1
+ import { type Backreference } from "../../partialMatchRegExp/part.ts";
2
2
  export default function resolvedFromScan(backref: Backreference, capture: RegExpExecArray): string | undefined;
@@ -1,5 +1,5 @@
1
- import { decodeGroupName } from "../groupName.js";
2
- import { isNumericBackreference } from "../part.js";
1
+ import { decodeGroupName } from "./groupName.js";
2
+ import { isNumericBackreference } from "../../partialMatchRegExp/part.js";
3
3
  export default function resolvedFromScan(backref, capture) {
4
4
  var _a;
5
5
  if (backref.forward)
@@ -1,4 +1,4 @@
1
- import escapeAtom from "../escapeAtom.js";
1
+ import escapeAtom from "./escapeAtom.js";
2
2
  import caseFoldFlags from "./caseFoldFlags.js";
3
3
  export default function startsWithUnderFlags(text, prefix, flags) {
4
4
  if (prefix === "" || !flags.includes("i"))
@@ -0,0 +1,7 @@
1
+ import { type Part } from "../../partialMatchRegExp/part.ts";
2
+ export type LookaheadSpan = [open: number, close: number];
3
+ export declare const CANNOT_END_LINE = -2;
4
+ export declare function partDecidingCaret(result: Part[], index: number, floor: number, scope: number, lookaheadSpans: LookaheadSpan[] | undefined, spanOffset: number): number;
5
+ export declare function canEndLine(body: Part[], starts: readonly number[], scope: number, lookaheadSpans: LookaheadSpan[] | undefined): boolean;
6
+ declare function appendMultilineCaret(result: Part[], lastGroupOpen: number, lastGroupClose: number, lastGroupScope: number, lastGroupAlternativeStarts: number[] | undefined, lastGroupLookaheadSpans: LookaheadSpan[] | undefined, lookaheadSpans: LookaheadSpan[] | undefined, scope: number): number;
7
+ export default appendMultilineCaret;
@@ -0,0 +1,181 @@
1
+ import { DISJUNCTION_TO_END_OF_INPUT, END_ANCHOR, GROUP_CLOSING, ONLY_AT_END_OF_INPUT, OPTIONAL_ATOM_OPENING, UNSATISFIABLE, asOptionalAtom, isOptionalAtom, isRawLookaround, isWordBoundaryAtom } from "../../partialMatchRegExp/atomSyntax.js";
2
+ import { caretFor, isCaret } from "./caretSyntax.js";
3
+ import canMatchLineTerminator from "./lineTerminator.js";
4
+ import { isBackreference } from "../../partialMatchRegExp/part.js";
5
+ import { isQuantifier, quantifierEndingAt } from "../../partialMatchRegExp/quantifier.js";
6
+ import { minimumOf } from "./quantifierBounds.js";
7
+ export const CANNOT_END_LINE = -2;
8
+ const NO_LOOKAHEAD = -1;
9
+ const isTransparentToCaret = (part) => typeof part === "string" &&
10
+ (part === END_ANCHOR ||
11
+ isWordBoundaryAtom(part) ||
12
+ isCaret(part) ||
13
+ isRawLookaround(part));
14
+ function lookaheadOpeningClosedAt(lookaheadSpans, index, spanOffset) {
15
+ for (const span of lookaheadSpans) {
16
+ if (span[1] + spanOffset === index)
17
+ return span[0] + spanOffset;
18
+ }
19
+ return NO_LOOKAHEAD;
20
+ }
21
+ export function partDecidingCaret(result, index, floor, scope, lookaheadSpans, spanOffset) {
22
+ while (index > floor) {
23
+ const part = result[index];
24
+ if (lookaheadSpans !== undefined) {
25
+ const lookaheadOpening = lookaheadOpeningClosedAt(lookaheadSpans, index, spanOffset);
26
+ if (lookaheadOpening !== NO_LOOKAHEAD) {
27
+ index = lookaheadOpening - 1;
28
+ continue;
29
+ }
30
+ }
31
+ if (isTransparentToCaret(part)) {
32
+ index--;
33
+ continue;
34
+ }
35
+ if (isOptionalAtom(part)) {
36
+ return canMatchLineTerminator(part, scope) ? index : CANNOT_END_LINE;
37
+ }
38
+ if (!isQuantifier(part))
39
+ return result[index] === UNSATISFIABLE ? CANNOT_END_LINE : index;
40
+ const quantifierIndex = quantifierEndingAt(result, index);
41
+ const atom = result[quantifierIndex - 1];
42
+ if (!isOptionalAtom(atom) || canMatchLineTerminator(atom, scope)) {
43
+ return index;
44
+ }
45
+ if (minimumOf(result[quantifierIndex]) > 0) {
46
+ return CANNOT_END_LINE;
47
+ }
48
+ result[quantifierIndex - 1] = ONLY_AT_END_OF_INPUT;
49
+ index = quantifierIndex - 2;
50
+ }
51
+ return floor;
52
+ }
53
+ export function canEndLine(body, starts, scope, lookaheadSpans) {
54
+ const scanned = body.slice();
55
+ let end = body.length;
56
+ for (let k = starts.length; k--;) {
57
+ const start = starts[k];
58
+ if (partDecidingCaret(scanned, end - 1, start - 1, scope, lookaheadSpans, 0) !== CANNOT_END_LINE)
59
+ return true;
60
+ end = start - 1;
61
+ }
62
+ return false;
63
+ }
64
+ function shiftSpans(lookaheadSpans, after, by) {
65
+ if (!lookaheadSpans)
66
+ return;
67
+ for (const span of lookaheadSpans) {
68
+ if (span[0] > after) {
69
+ span[0] += by;
70
+ span[1] += by;
71
+ }
72
+ }
73
+ }
74
+ const isPositionUncertain = (part) => isBackreference(part) || isQuantifier(part);
75
+ function foldCaret(result, index, caret) {
76
+ const atom = result[index];
77
+ result[index] =
78
+ atom.slice(0, -DISJUNCTION_TO_END_OF_INPUT.length) +
79
+ caret +
80
+ DISJUNCTION_TO_END_OF_INPUT;
81
+ }
82
+ function wrapGroup(result, open, close, scope, lookaheadSpans) {
83
+ result.splice(open + 1, 0, OPTIONAL_ATOM_OPENING);
84
+ result.splice(close + 1, 1, GROUP_CLOSING + caretFor(scope), DISJUNCTION_TO_END_OF_INPUT);
85
+ shiftSpans(lookaheadSpans, close, 2);
86
+ return close + 2;
87
+ }
88
+ function appendCaretToAlternatives(result, open, close, scope, starts, bodySpans, lookaheadSpans) {
89
+ const anchors = [];
90
+ const ends = [];
91
+ let end = close;
92
+ for (let k = starts.length; k--;) {
93
+ const floor = open + starts[k];
94
+ const anchor = partDecidingCaret(result, end - 1, floor, scope, bodySpans, open + 1);
95
+ if (anchor === floor ||
96
+ (anchor !== CANNOT_END_LINE &&
97
+ !isOptionalAtom(result[anchor]) &&
98
+ !isPositionUncertain(result[anchor])))
99
+ return wrapGroup(result, open, close, scope, lookaheadSpans);
100
+ anchors.push(anchor);
101
+ ends.push(end);
102
+ end = floor;
103
+ }
104
+ const caret = caretFor(scope);
105
+ let inserted = 0;
106
+ for (let n = 0; n < anchors.length; n++) {
107
+ const anchor = anchors[n];
108
+ if (anchor !== CANNOT_END_LINE && isOptionalAtom(result[anchor])) {
109
+ foldCaret(result, anchor, caret);
110
+ continue;
111
+ }
112
+ const at = anchor === CANNOT_END_LINE ? ends[n] : anchor + 1;
113
+ result.splice(at, 0, anchor === CANNOT_END_LINE ? UNSATISFIABLE : asOptionalAtom(caret));
114
+ shiftSpans(lookaheadSpans, at - 1, 1);
115
+ shiftSpans(bodySpans, at - open - 2, 1);
116
+ for (let k = starts.length; k--;)
117
+ if (open + starts[k] >= at)
118
+ starts[k]++;
119
+ inserted++;
120
+ }
121
+ return close + inserted;
122
+ }
123
+ function appendMultilineCaret(result, lastGroupOpen, lastGroupClose, lastGroupScope, lastGroupAlternativeStarts, lastGroupLookaheadSpans, lookaheadSpans, scope) {
124
+ const caret = caretFor(scope);
125
+ let lookedThroughGroup = false;
126
+ let anchor = partDecidingCaret(result, result.length - 1, -1, scope, lookaheadSpans, 0);
127
+ if (anchor >= 0 && anchor === lastGroupClose) {
128
+ if (lastGroupAlternativeStarts)
129
+ return appendCaretToAlternatives(result, lastGroupOpen, lastGroupClose, lastGroupScope, lastGroupAlternativeStarts, lastGroupLookaheadSpans, lookaheadSpans);
130
+ const bodyAnchor = partDecidingCaret(result, anchor - 1, lastGroupOpen, lastGroupScope, lastGroupLookaheadSpans, lastGroupOpen + 1);
131
+ if (bodyAnchor === CANNOT_END_LINE) {
132
+ anchor = CANNOT_END_LINE;
133
+ }
134
+ else if (bodyAnchor === lastGroupOpen) {
135
+ lookedThroughGroup = true;
136
+ anchor = partDecidingCaret(result, lastGroupOpen - 1, -1, scope, lookaheadSpans, 0);
137
+ }
138
+ else if (isOptionalAtom(result[bodyAnchor])) {
139
+ foldCaret(result, bodyAnchor, caretFor(lastGroupScope));
140
+ return lastGroupClose;
141
+ }
142
+ else if (isPositionUncertain(result[bodyAnchor])) {
143
+ result.splice(bodyAnchor + 1, 0, asOptionalAtom(caretFor(lastGroupScope)));
144
+ shiftSpans(lookaheadSpans, bodyAnchor, 1);
145
+ shiftSpans(lastGroupLookaheadSpans, bodyAnchor - lastGroupOpen - 1, 1);
146
+ return lastGroupClose + 1;
147
+ }
148
+ else {
149
+ return wrapGroup(result, lastGroupOpen, lastGroupClose, lastGroupScope, lookaheadSpans);
150
+ }
151
+ }
152
+ if (anchor === CANNOT_END_LINE) {
153
+ result.push(UNSATISFIABLE);
154
+ return lastGroupClose;
155
+ }
156
+ if (anchor < 0) {
157
+ result.push(caret);
158
+ return lastGroupClose;
159
+ }
160
+ const previous = result[anchor];
161
+ if (isOptionalAtom(previous)) {
162
+ foldCaret(result, anchor, caret);
163
+ return lastGroupClose;
164
+ }
165
+ const positionUncertain = isBackreference(previous) || isQuantifier(previous);
166
+ if (lookedThroughGroup &&
167
+ (positionUncertain ||
168
+ previous === DISJUNCTION_TO_END_OF_INPUT ||
169
+ previous === GROUP_CLOSING)) {
170
+ return wrapGroup(result, lastGroupOpen, lastGroupClose, lastGroupScope, lookaheadSpans);
171
+ }
172
+ if (positionUncertain) {
173
+ result.splice(anchor + 1, 0, asOptionalAtom(caret));
174
+ shiftSpans(lookaheadSpans, anchor, 1);
175
+ }
176
+ else {
177
+ result.push(caret);
178
+ }
179
+ return lastGroupClose;
180
+ }
181
+ export default appendMultilineCaret;
@@ -0,0 +1,2 @@
1
+ import { type CaretRecorder } from "../../partialMatchRegExp/caretHook.ts";
2
+ export default function caretRecorder(): CaretRecorder;
@@ -0,0 +1,164 @@
1
+ import { DISJUNCTION_TO_END_OF_INPUT, END_ANCHOR, GROUP_CLOSING, LOOKAHEAD_OPENING, ONLY_AT_END_OF_INPUT, START_ANCHOR, UNSATISFIABLE, asOptionalAtom, isRawLookaround, isWordBoundaryAtom } from "../../partialMatchRegExp/atomSyntax.js";
2
+ import { LAZY_MARK, isQuantifier } from "../../partialMatchRegExp/quantifier.js";
3
+ import { MULTILINE } from "../../partialMatchRegExp/scope.js";
4
+ import { ON_ALTERNATIVE, ON_CARET, ON_GROUP, ON_LOOKAHEAD } from "../../partialMatchRegExp/caretHook.js";
5
+ import appendMultilineCaret, { canEndLine } from "./appendMultilineCaret.js";
6
+ import { isQuantifierAhead, minimumOf, quantifierAhead } from "./quantifierBounds.js";
7
+ const NO_ALTERNATIVES = [0];
8
+ const NO_LOOKAHEAD_SPANS = [];
9
+ const GROUP_OPENING = /^\((?:\?(?:<[^=!][^>]*>|[a-z-]*:))?$/;
10
+ function lookaheadClosing(lookaheadSpans, opening) {
11
+ let closing = opening;
12
+ for (const span of lookaheadSpans) {
13
+ if (span[0] === opening)
14
+ closing = span[1];
15
+ }
16
+ return closing;
17
+ }
18
+ function leadingCaret(body, index, lookaheadSpans) {
19
+ for (;;) {
20
+ const part = body[index];
21
+ if (part === START_ANCHOR)
22
+ return index;
23
+ if (typeof part !== "string")
24
+ return -1;
25
+ if (part === END_ANCHOR ||
26
+ isWordBoundaryAtom(part) ||
27
+ isRawLookaround(part))
28
+ index++;
29
+ else if (part === LOOKAHEAD_OPENING)
30
+ index = lookaheadClosing(lookaheadSpans, index) + 1;
31
+ else if (part === ONLY_AT_END_OF_INPUT && isQuantifier(body[index + 1]))
32
+ index++;
33
+ else if ((body[index + 1] === GROUP_CLOSING ||
34
+ body[index + 1] === DISJUNCTION_TO_END_OF_INPUT) &&
35
+ GROUP_OPENING.test(part))
36
+ index += 2;
37
+ else
38
+ return -1;
39
+ if (isQuantifier(body[index]))
40
+ index += body[index + 1] === LAZY_MARK ? 2 : 1;
41
+ }
42
+ }
43
+ function leadingCarets(body, starts, lookaheadSpans) {
44
+ const carets = [];
45
+ for (const start of starts) {
46
+ const caret = leadingCaret(body, start, lookaheadSpans);
47
+ if (caret === -1)
48
+ return undefined;
49
+ carets.push(caret);
50
+ }
51
+ return carets;
52
+ }
53
+ export default function caretRecorder() {
54
+ let lastBodyAlternativeStarts;
55
+ let lastBodyLookaheadSpans;
56
+ let lastBodyCaretsBefore = 0;
57
+ let lastBodyVerbatimMultilineCaretsBefore = 0;
58
+ let caretsSeen = 0;
59
+ let verbatimMultilineCarets = 0;
60
+ return (result, scope) => {
61
+ const caretsBefore = caretsSeen;
62
+ const verbatimMultilineCaretsBefore = verbatimMultilineCarets;
63
+ let lastGroupOpen = -1;
64
+ let lastGroupClose = -1;
65
+ let lastGroupScope = scope;
66
+ let lastGroupAlternativeStarts;
67
+ let lastGroupLookaheadSpans;
68
+ let lookaheadSpans;
69
+ let alternativeStarts;
70
+ return ((event, body, groupScope, source, i, closing, containsRawLookaround) => {
71
+ if (event === ON_CARET) {
72
+ caretsSeen++;
73
+ if (scope & MULTILINE) {
74
+ lastGroupClose = appendMultilineCaret(result, lastGroupOpen, lastGroupClose, lastGroupScope, lastGroupAlternativeStarts, lastGroupLookaheadSpans, lookaheadSpans, scope);
75
+ if (result[result.length - 1] === START_ANCHOR)
76
+ verbatimMultilineCarets++;
77
+ }
78
+ else {
79
+ result.push(START_ANCHOR);
80
+ }
81
+ }
82
+ else if (event === ON_ALTERNATIVE) {
83
+ (alternativeStarts !== null && alternativeStarts !== void 0 ? alternativeStarts : (alternativeStarts = [0])).push(result.length + 1);
84
+ }
85
+ else if (event === ON_LOOKAHEAD) {
86
+ if (scope & MULTILINE &&
87
+ body[0] === START_ANCHOR &&
88
+ !lastBodyAlternativeStarts &&
89
+ !isQuantifierAhead(source, i)) {
90
+ body.shift();
91
+ lastGroupClose = appendMultilineCaret(result, lastGroupOpen, lastGroupClose, lastGroupScope, lastGroupAlternativeStarts, lastGroupLookaheadSpans, lookaheadSpans, scope);
92
+ }
93
+ const lookaheadOpen = result.length;
94
+ const lookaheadClose = lookaheadOpen + body.length + 1;
95
+ (lookaheadSpans !== null && lookaheadSpans !== void 0 ? lookaheadSpans : (lookaheadSpans = [])).push([lookaheadOpen, lookaheadClose]);
96
+ }
97
+ else if (event === ON_GROUP) {
98
+ const starts = lastBodyAlternativeStarts !== null && lastBodyAlternativeStarts !== void 0 ? lastBodyAlternativeStarts : NO_ALTERNATIVES;
99
+ const containsCaret = caretsSeen !== lastBodyCaretsBefore;
100
+ const carets = containsCaret
101
+ ? leadingCarets(body, starts, lastBodyLookaheadSpans !== null && lastBodyLookaheadSpans !== void 0 ? lastBodyLookaheadSpans : NO_LOOKAHEAD_SPANS)
102
+ : undefined;
103
+ const containsMultilineCaret = verbatimMultilineCarets !== lastBodyVerbatimMultilineCaretsBefore;
104
+ let hoistedCaretStays = false;
105
+ if (carets && (groupScope & MULTILINE || !(scope & MULTILINE))) {
106
+ const quantifier = quantifierAhead(source, i);
107
+ const minimum = quantifier === undefined ? 1 : minimumOf(quantifier);
108
+ if (minimum > 0) {
109
+ if (groupScope & MULTILINE) {
110
+ hoistedCaretStays = !(scope & MULTILINE);
111
+ lastGroupClose = appendMultilineCaret(result, lastGroupOpen, lastGroupClose, lastGroupScope, lastGroupAlternativeStarts, lastGroupLookaheadSpans, lookaheadSpans, scope);
112
+ }
113
+ else
114
+ result.push(START_ANCHOR);
115
+ }
116
+ if (quantifier === undefined) {
117
+ for (let k = carets.length; k--;) {
118
+ body.splice(carets[k], 1);
119
+ if (lastBodyLookaheadSpans)
120
+ for (const span of lastBodyLookaheadSpans) {
121
+ if (span[0] > carets[k]) {
122
+ span[0]--;
123
+ span[1]--;
124
+ }
125
+ }
126
+ }
127
+ if (lastBodyAlternativeStarts)
128
+ for (let k = starts.length; k--;)
129
+ lastBodyAlternativeStarts[k] -= k;
130
+ }
131
+ else if (groupScope & MULTILINE) {
132
+ const repeatedCaret = minimum > 1 &&
133
+ !canEndLine(body, starts, groupScope, lastBodyLookaheadSpans)
134
+ ? UNSATISFIABLE
135
+ : asOptionalAtom(START_ANCHOR);
136
+ for (const caret of carets)
137
+ body[caret] = repeatedCaret;
138
+ }
139
+ else if (!containsRawLookaround)
140
+ closing = GROUP_CLOSING;
141
+ }
142
+ let forced = false;
143
+ if (groupScope & MULTILINE &&
144
+ containsMultilineCaret &&
145
+ body.indexOf(START_ANCHOR) !== -1) {
146
+ closing = DISJUNCTION_TO_END_OF_INPUT;
147
+ forced = true;
148
+ }
149
+ lastGroupOpen = result.length;
150
+ lastGroupClose = lastGroupOpen + body.length + 1;
151
+ lastGroupScope = groupScope;
152
+ lastGroupAlternativeStarts = lastBodyAlternativeStarts;
153
+ lastGroupLookaheadSpans = lastBodyLookaheadSpans;
154
+ return { closing, forced, stays: hoistedCaretStays };
155
+ }
156
+ else {
157
+ lastBodyAlternativeStarts = alternativeStarts;
158
+ lastBodyLookaheadSpans = lookaheadSpans;
159
+ lastBodyCaretsBefore = caretsBefore;
160
+ lastBodyVerbatimMultilineCaretsBefore = verbatimMultilineCaretsBefore;
161
+ }
162
+ });
163
+ };
164
+ }
@@ -0,0 +1,3 @@
1
+ export declare const caretFor: (scope: number) => "^" | "(?m:^)";
2
+ export declare const isCaret: (part: string) => boolean;
3
+ export declare const optionalAtomTextOf: (atom: string) => string;
@@ -0,0 +1,11 @@
1
+ import { DISJUNCTION_TO_END_OF_INPUT, MULTILINE_CARET, OPTIONAL_ATOM_OPENING, START_ANCHOR, asOptionalAtom } from "../../partialMatchRegExp/atomSyntax.js";
2
+ import { MULTILINE } from "../../partialMatchRegExp/scope.js";
3
+ const CARET_SPELLINGS = [
4
+ START_ANCHOR,
5
+ MULTILINE_CARET,
6
+ asOptionalAtom(START_ANCHOR),
7
+ asOptionalAtom(MULTILINE_CARET)
8
+ ];
9
+ export const caretFor = (scope) => scope & MULTILINE ? START_ANCHOR : MULTILINE_CARET;
10
+ export const isCaret = (part) => CARET_SPELLINGS.indexOf(part) !== -1;
11
+ export const optionalAtomTextOf = (atom) => atom.slice(OPTIONAL_ATOM_OPENING.length, -DISJUNCTION_TO_END_OF_INPUT.length);
@@ -0,0 +1,9 @@
1
+ import type { Module } from "../../partialMatchRegExp/opaqueModule.ts";
2
+ /**
3
+ * The carets module: the rules for a `^` inside a group or positive
4
+ * lookahead, or after other input under the `m` flag. Bind it with
5
+ * `withModules` from `regex-partial-match/core` to render `^` exactly as the
6
+ * default `PartialMatchRegExp` does.
7
+ */
8
+ declare const carets: Module;
9
+ export default carets;