regex-partial-match 1.2.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/README.md +169 -178
  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.d.ts → extend/index.d.ts} +6 -7
  7. package/lib/{extend.js → 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/hitEnd/partRole.d.ts +3 -0
  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/hitEnd/truncationProbeCache.js +1 -0
  20. package/lib/index.d.ts +4 -0
  21. package/lib/index.js +4 -0
  22. package/lib/modules/backreferences/asNativeAtom.d.ts +2 -0
  23. package/lib/modules/backreferences/asNativeAtom.js +10 -0
  24. package/lib/modules/backreferences/asPreScanPart.d.ts +2 -0
  25. package/lib/modules/backreferences/asPreScanPart.js +8 -0
  26. package/lib/modules/backreferences/backreferenceRecorder.d.ts +2 -0
  27. package/lib/modules/backreferences/backreferenceRecorder.js +38 -0
  28. package/lib/modules/backreferences/caseFoldFlags.d.ts +1 -0
  29. package/lib/modules/backreferences/caseFoldFlags.js +3 -0
  30. package/lib/modules/backreferences/compileDynamic.d.ts +4 -0
  31. package/lib/modules/backreferences/compileDynamic.js +53 -0
  32. package/lib/modules/backreferences/compiledBackreferences.d.ts +9 -0
  33. package/lib/modules/backreferences/compiledBackreferences.js +9 -0
  34. package/lib/modules/backreferences/constants.d.ts +2 -0
  35. package/lib/modules/backreferences/constants.js +2 -0
  36. package/lib/modules/backreferences/execDynamic.d.ts +2 -0
  37. package/lib/modules/backreferences/execDynamic.js +43 -0
  38. package/lib/modules/backreferences/flagsAtBackreference.d.ts +2 -0
  39. package/lib/modules/backreferences/flagsAtBackreference.js +4 -0
  40. package/lib/modules/backreferences/groupName.d.ts +2 -0
  41. package/lib/modules/backreferences/groupName.js +8 -0
  42. package/lib/modules/backreferences/index.d.ts +10 -0
  43. package/lib/modules/backreferences/index.js +20 -0
  44. package/lib/modules/backreferences/longestBakedPrefixEndingInput.d.ts +1 -0
  45. package/lib/modules/backreferences/longestBakedPrefixEndingInput.js +46 -0
  46. package/lib/modules/backreferences/renderParts.d.ts +2 -0
  47. package/lib/modules/backreferences/renderParts.js +9 -0
  48. package/lib/modules/backreferences/resolvedFromScan.d.ts +2 -0
  49. package/lib/modules/backreferences/resolvedFromScan.js +10 -0
  50. package/lib/modules/backreferences/startsWithUnderFlags.d.ts +1 -0
  51. package/lib/modules/backreferences/startsWithUnderFlags.js +7 -0
  52. package/lib/modules/carets/appendMultilineCaret.d.ts +7 -0
  53. package/lib/modules/carets/appendMultilineCaret.js +181 -0
  54. package/lib/modules/carets/caretRecorder.d.ts +2 -0
  55. package/lib/modules/carets/caretRecorder.js +164 -0
  56. package/lib/modules/carets/caretSyntax.d.ts +3 -0
  57. package/lib/modules/carets/caretSyntax.js +11 -0
  58. package/lib/modules/carets/index.d.ts +9 -0
  59. package/lib/modules/carets/index.js +18 -0
  60. package/lib/modules/carets/lineTerminator.d.ts +1 -0
  61. package/lib/modules/carets/lineTerminator.js +31 -0
  62. package/lib/modules/carets/needsCaretRules.d.ts +1 -0
  63. package/lib/modules/carets/needsCaretRules.js +15 -0
  64. package/lib/modules/carets/quantifierBounds.d.ts +3 -0
  65. package/lib/modules/carets/quantifierBounds.js +18 -0
  66. package/lib/modules/index.d.ts +3 -0
  67. package/lib/modules/index.js +2 -0
  68. package/lib/partialMatchRegExp/atomSyntax.d.ts +17 -0
  69. package/lib/partialMatchRegExp/atomSyntax.js +27 -0
  70. package/lib/partialMatchRegExp/backreferenceExpansion.d.ts +5 -0
  71. package/lib/partialMatchRegExp/backreferenceExpansion.js +1 -0
  72. package/lib/partialMatchRegExp/backreferenceHook.d.ts +11 -0
  73. package/lib/partialMatchRegExp/backreferenceHook.js +1 -0
  74. package/lib/partialMatchRegExp/caretHook.d.ts +17 -0
  75. package/lib/partialMatchRegExp/caretHook.js +5 -0
  76. package/lib/partialMatchRegExp/compilePartial/compileWith.d.ts +3 -0
  77. package/lib/partialMatchRegExp/compilePartial/compileWith.js +36 -0
  78. package/lib/partialMatchRegExp/compilePartial/compiled.d.ts +29 -0
  79. package/lib/partialMatchRegExp/compilePartial/compiled.js +14 -0
  80. package/lib/partialMatchRegExp/compilePartial/constants.d.ts +4 -0
  81. package/lib/partialMatchRegExp/compilePartial/constants.js +4 -0
  82. package/lib/partialMatchRegExp/compilePartial/groupShape.d.ts +4 -0
  83. package/lib/partialMatchRegExp/compilePartial/groupShape.js +9 -0
  84. package/lib/partialMatchRegExp/compilePartial/toStatic.d.ts +3 -0
  85. package/lib/partialMatchRegExp/compilePartial/toStatic.js +4 -0
  86. package/lib/partialMatchRegExp/constants.d.ts +5 -0
  87. package/lib/partialMatchRegExp/constants.js +5 -0
  88. package/lib/partialMatchRegExp/createPartialMatchRegExp.d.ts +3 -0
  89. package/lib/partialMatchRegExp/createPartialMatchRegExp.js +21 -0
  90. package/lib/partialMatchRegExp/execFrom.d.ts +1 -0
  91. package/lib/partialMatchRegExp/execFrom.js +4 -0
  92. package/lib/partialMatchRegExp/index.d.ts +49 -0
  93. package/lib/partialMatchRegExp/index.js +31 -0
  94. package/lib/partialMatchRegExp/legacyEscape.d.ts +2 -0
  95. package/lib/partialMatchRegExp/legacyEscape.js +18 -0
  96. package/lib/partialMatchRegExp/moduleHooks.d.ts +14 -0
  97. package/lib/partialMatchRegExp/moduleHooks.js +15 -0
  98. package/lib/partialMatchRegExp/opaqueModule.d.ts +9 -0
  99. package/lib/partialMatchRegExp/opaqueModule.js +1 -0
  100. package/lib/partialMatchRegExp/part.d.ts +15 -0
  101. package/lib/partialMatchRegExp/part.js +2 -0
  102. package/lib/partialMatchRegExp/partialMatchInternals.d.ts +3 -0
  103. package/lib/partialMatchRegExp/partialMatchInternals.js +4 -0
  104. package/lib/partialMatchRegExp/quantifier.d.ts +6 -0
  105. package/lib/partialMatchRegExp/quantifier.js +9 -0
  106. package/lib/partialMatchRegExp/rawLookaroundInfo.d.ts +11 -0
  107. package/lib/partialMatchRegExp/rawLookaroundInfo.js +1 -0
  108. package/lib/partialMatchRegExp/regexFeatures.d.ts +2 -0
  109. package/lib/partialMatchRegExp/regexFeatures.js +41 -0
  110. package/lib/partialMatchRegExp/scope.d.ts +12 -0
  111. package/lib/partialMatchRegExp/scope.js +45 -0
  112. package/lib/partialMatchRegExp/walk.d.ts +16 -0
  113. package/lib/partialMatchRegExp/walk.js +412 -0
  114. package/lib/partialMatchRegExp/withModules.d.ts +13 -0
  115. package/lib/partialMatchRegExp/withModules.js +27 -0
  116. package/package.json +46 -53
  117. package/lib/compilePartial.d.ts +0 -26
  118. package/lib/compilePartial.js +0 -397
  119. package/lib/partialMatchRegExp.d.ts +0 -52
  120. package/lib/partialMatchRegExp.js +0 -126
  121. /package/lib/{escapeAtom.d.ts → modules/backreferences/escapeAtom.d.ts} +0 -0
  122. /package/lib/{escapeAtom.js → modules/backreferences/escapeAtom.js} +0 -0
@@ -1,397 +0,0 @@
1
- import escapeAtom from "./escapeAtom.js";
2
- const OCCURRENCES_REGEX = /\{\d+,?\d*\}/y;
3
- const NOT_NUMBERS_REGEX = /\D/g;
4
- const MAYBE_HAS_BACKREFERENCE_REGEX = /\\[1-9]|\\k</;
5
- const DISJUNCTION_TO_END_OF_INPUT = "|$(?![\\s\\S]))";
6
- const ANY_CAPTURED_TEXT = "(?:[\\s\\S]*?)";
7
- const isBackreference = (part) => typeof part !== "string";
8
- const isNumericBackreference = (part) => isBackreference(part) && typeof part.ref === "number";
9
- const REGEX_FEATURES = [
10
- "patternCharacter",
11
- "startAnchor",
12
- "endAnchor",
13
- "wordBoundary",
14
- "nonWordBoundary",
15
- "lookahead",
16
- "negativeLookahead",
17
- "lookbehind",
18
- "negativeLookbehind",
19
- "backreference",
20
- "namedBackreference",
21
- "namedGroup",
22
- "capturingGroup",
23
- "lookaroundCapture",
24
- "nonCapturingGroup",
25
- "modifierGroup",
26
- "modifierGroupWithRemoval",
27
- "characterClass",
28
- "nestedCharacterClass",
29
- "classIntersection",
30
- "classSubtraction",
31
- "disjunction",
32
- "quantifier",
33
- "unicodePropertyEscape",
34
- "characterClassEscape",
35
- "controlEscape",
36
- "controlLetterEscape",
37
- "hexEscapeSequence",
38
- "unicodeEscapeSequence",
39
- "otherEscape"
40
- ];
41
- const FEATURE_BIT = {};
42
- for (let index = 0; index < REGEX_FEATURES.length; index++) {
43
- FEATURE_BIT[REGEX_FEATURES[index]] = 1 << index;
44
- }
45
- function featureSet(mask) {
46
- const features = new Set();
47
- for (let index = 0; index < REGEX_FEATURES.length; index++) {
48
- if (mask & (1 << index))
49
- features.add(REGEX_FEATURES[index]);
50
- }
51
- return features;
52
- }
53
- function walk(regex) {
54
- const source = regex.source;
55
- const isUnicode = regex.unicode || regex.unicodeSets;
56
- let i = 0;
57
- let groupCount = 0;
58
- let featureMask = 0;
59
- function extractSlice(length) {
60
- return source.slice(i, (i += length));
61
- }
62
- function process(withinLookaround) {
63
- var _a;
64
- const result = [];
65
- function appendOptional(length) {
66
- result.push("(?:" + extractSlice(length) + DISJUNCTION_TO_END_OF_INPUT);
67
- }
68
- function appendRaw(length) {
69
- result.push(extractSlice(length));
70
- }
71
- function appendRawLookaround(prefixLength) {
72
- const start = i;
73
- i += prefixLength;
74
- process(true);
75
- result.push(source.slice(start, i));
76
- }
77
- while (i < source.length) {
78
- switch (source[i]) {
79
- case "\\":
80
- switch (source[i + 1]) {
81
- case "c":
82
- featureMask |= FEATURE_BIT.controlLetterEscape;
83
- appendOptional(3);
84
- break;
85
- case "k": {
86
- const referenceEnd = source[i + 2] === "<" ? source.indexOf(">", i) : -1;
87
- if (referenceEnd === -1) {
88
- appendOptional(2);
89
- }
90
- else {
91
- featureMask |= FEATURE_BIT.namedBackreference;
92
- const start = i;
93
- const ref = source.slice(i + 3, referenceEnd);
94
- i = referenceEnd + 1;
95
- result.push({ ref, start, end: i });
96
- }
97
- break;
98
- }
99
- case "u":
100
- featureMask |= FEATURE_BIT.unicodeEscapeSequence;
101
- if (isUnicode && source[i + 2] === "{") {
102
- appendOptional(source.indexOf("}", i) - i + 1);
103
- }
104
- else {
105
- appendOptional(6);
106
- }
107
- break;
108
- case "p":
109
- case "P":
110
- if (isUnicode) {
111
- featureMask |= FEATURE_BIT.unicodePropertyEscape;
112
- appendOptional(source.indexOf("}", i) - i + 1);
113
- }
114
- else {
115
- appendOptional(2);
116
- }
117
- break;
118
- case "x":
119
- featureMask |= FEATURE_BIT.hexEscapeSequence;
120
- appendOptional(4);
121
- break;
122
- case "b":
123
- featureMask |= FEATURE_BIT.wordBoundary;
124
- appendOptional(2);
125
- break;
126
- case "B":
127
- featureMask |= FEATURE_BIT.nonWordBoundary;
128
- appendOptional(2);
129
- break;
130
- case "f":
131
- case "n":
132
- case "r":
133
- case "t":
134
- case "v":
135
- featureMask |= FEATURE_BIT.controlEscape;
136
- appendOptional(2);
137
- break;
138
- case "1":
139
- case "2":
140
- case "3":
141
- case "4":
142
- case "5":
143
- case "6":
144
- case "7":
145
- case "8":
146
- case "9": {
147
- featureMask |= FEATURE_BIT.backreference;
148
- NOT_NUMBERS_REGEX.lastIndex = i + 1;
149
- const nextNonDigit = NOT_NUMBERS_REGEX.exec(source);
150
- const start = i;
151
- const end = nextNonDigit ? nextNonDigit.index : source.length;
152
- const ref = Number(source.slice(start + 1, end));
153
- i = end;
154
- result.push({ ref, start, end });
155
- break;
156
- }
157
- case "d":
158
- case "D":
159
- case "w":
160
- case "W":
161
- case "s":
162
- case "S":
163
- featureMask |= FEATURE_BIT.characterClassEscape;
164
- appendOptional(2);
165
- break;
166
- default:
167
- featureMask |= FEATURE_BIT.otherEscape;
168
- appendOptional(2);
169
- break;
170
- }
171
- break;
172
- case "[": {
173
- featureMask |= FEATURE_BIT.characterClass;
174
- let depth = 1, j = i + 1, previousSetOperatorCharacter;
175
- while (depth) {
176
- const character = source[j];
177
- switch (character) {
178
- case "\\":
179
- j += 2;
180
- previousSetOperatorCharacter = undefined;
181
- continue;
182
- case "[":
183
- if (regex.unicodeSets) {
184
- featureMask |= FEATURE_BIT.nestedCharacterClass;
185
- depth++;
186
- }
187
- break;
188
- case "]":
189
- depth--;
190
- break;
191
- case "&":
192
- if (regex.unicodeSets && previousSetOperatorCharacter === "&") {
193
- featureMask |= FEATURE_BIT.classIntersection;
194
- }
195
- break;
196
- case "-":
197
- if (regex.unicodeSets && previousSetOperatorCharacter === "-") {
198
- featureMask |= FEATURE_BIT.classSubtraction;
199
- }
200
- break;
201
- }
202
- previousSetOperatorCharacter = character;
203
- j++;
204
- }
205
- appendOptional(j - i);
206
- break;
207
- }
208
- case "^":
209
- featureMask |= FEATURE_BIT.startAnchor;
210
- appendRaw(1);
211
- break;
212
- case "$":
213
- featureMask |= FEATURE_BIT.endAnchor;
214
- appendRaw(1);
215
- break;
216
- case "|":
217
- featureMask |= FEATURE_BIT.disjunction;
218
- appendRaw(1);
219
- break;
220
- case "*":
221
- case "+":
222
- case "?":
223
- featureMask |= FEATURE_BIT.quantifier;
224
- appendRaw(1);
225
- break;
226
- case "{": {
227
- OCCURRENCES_REGEX.lastIndex = i;
228
- const regExpExecArray = OCCURRENCES_REGEX.exec(source);
229
- if (regExpExecArray) {
230
- featureMask |= FEATURE_BIT.quantifier;
231
- appendRaw(regExpExecArray[0].length);
232
- }
233
- else {
234
- appendOptional(1);
235
- }
236
- break;
237
- }
238
- case "(":
239
- if (source[i + 1] == "?") {
240
- switch (source[i + 2]) {
241
- case ":":
242
- featureMask |= FEATURE_BIT.nonCapturingGroup;
243
- result.push("(?:");
244
- i += 3;
245
- result.push(...process(withinLookaround), DISJUNCTION_TO_END_OF_INPUT);
246
- break;
247
- case "=":
248
- featureMask |= FEATURE_BIT.lookahead;
249
- result.push("(?=");
250
- i += 3;
251
- result.push(...process(true), ")");
252
- break;
253
- case "-":
254
- case "i":
255
- case "s":
256
- case "m": {
257
- const flagsStart = i + 2, colonIndex = source.indexOf(":", flagsStart);
258
- const modifiers = source.slice(flagsStart, colonIndex);
259
- featureMask |= modifiers.includes("-")
260
- ? FEATURE_BIT.modifierGroupWithRemoval
261
- : FEATURE_BIT.modifierGroup;
262
- result.push("(?" + modifiers + ":");
263
- i = colonIndex + 1;
264
- result.push(...process(withinLookaround), ")");
265
- break;
266
- }
267
- case "!":
268
- featureMask |= FEATURE_BIT.negativeLookahead;
269
- appendRawLookaround(3);
270
- break;
271
- case "<":
272
- switch (source[i + 3]) {
273
- case "=":
274
- featureMask |= FEATURE_BIT.lookbehind;
275
- appendRawLookaround(4);
276
- break;
277
- case "!":
278
- featureMask |= FEATURE_BIT.negativeLookbehind;
279
- appendRawLookaround(4);
280
- break;
281
- default:
282
- featureMask |= FEATURE_BIT.namedGroup;
283
- featureMask |= FEATURE_BIT.capturingGroup;
284
- if (withinLookaround)
285
- featureMask |= FEATURE_BIT.lookaroundCapture;
286
- ++groupCount;
287
- appendRaw(source.indexOf(">", i) - i + 1);
288
- result.push(...process(withinLookaround), DISJUNCTION_TO_END_OF_INPUT);
289
- break;
290
- }
291
- break;
292
- }
293
- }
294
- else {
295
- featureMask |= FEATURE_BIT.capturingGroup;
296
- if (withinLookaround)
297
- featureMask |= FEATURE_BIT.lookaroundCapture;
298
- ++groupCount;
299
- appendRaw(1);
300
- result.push(...process(withinLookaround), DISJUNCTION_TO_END_OF_INPUT);
301
- }
302
- break;
303
- case ")":
304
- ++i;
305
- return result;
306
- default:
307
- featureMask |= FEATURE_BIT.patternCharacter;
308
- appendOptional(isUnicode && ((_a = source.codePointAt(i)) !== null && _a !== void 0 ? _a : 0) > 0xffff ? 2 : 1);
309
- break;
310
- }
311
- }
312
- return result;
313
- }
314
- return { parts: process(false), groupCount, featureMask };
315
- }
316
- function render(parts, renderBackref) {
317
- let rendered = "";
318
- for (const part of parts) {
319
- rendered += isBackreference(part) ? renderBackref(part) : part;
320
- }
321
- return rendered;
322
- }
323
- function backrefToken(backref) {
324
- return isNumericBackreference(backref)
325
- ? "\\" + String(backref.ref)
326
- : "\\k<" + backref.ref + ">";
327
- }
328
- function reclassifyOctalEscapes(parts, source, groupCount) {
329
- return parts.map((part) => isNumericBackreference(part) && part.ref > groupCount
330
- ? "(?:" + source.slice(part.start, part.end) + DISJUNCTION_TO_END_OF_INPUT
331
- : part);
332
- }
333
- function spliceOriginalSource(source, backrefs) {
334
- let result = "";
335
- let cursor = 0;
336
- for (const { start, end } of backrefs) {
337
- result += source.slice(cursor, start) + ANY_CAPTURED_TEXT;
338
- cursor = end;
339
- }
340
- return result + source.slice(cursor);
341
- }
342
- function expandCaptured(value, isUnicode) {
343
- return (isUnicode ? Array.from(value) : value.split(""))
344
- .map((atom) => "(?:" + escapeAtom(atom) + DISJUNCTION_TO_END_OF_INPUT)
345
- .join("");
346
- }
347
- class Compiled {
348
- constructor(_featureMask) {
349
- this._featureMask = _featureMask;
350
- }
351
- get features() {
352
- var _a;
353
- return ((_a = this._features) !== null && _a !== void 0 ? _a : (this._features = featureSet(this._featureMask)));
354
- }
355
- }
356
- class CompiledStatic extends Compiled {
357
- constructor(regex, featureMask) {
358
- super(featureMask);
359
- this.regex = regex;
360
- this.kind = "static";
361
- }
362
- }
363
- class CompiledDynamic extends Compiled {
364
- constructor(dynamic, featureMask) {
365
- super(featureMask);
366
- this.dynamic = dynamic;
367
- this.kind = "dynamic";
368
- }
369
- }
370
- export const compilePartial = (regex) => {
371
- const { parts, groupCount, featureMask } = walk(regex);
372
- const flags = regex.flags;
373
- if (!MAYBE_HAS_BACKREFERENCE_REGEX.test(regex.source)) {
374
- return new CompiledStatic(new RegExp(render(parts, backrefToken), flags), featureMask);
375
- }
376
- const isUnicode = regex.unicode || regex.unicodeSets;
377
- const sanitisedParts = isUnicode
378
- ? parts
379
- : reclassifyOctalEscapes(parts, regex.source, groupCount);
380
- const backreferences = sanitisedParts.filter(isBackreference);
381
- if (backreferences.length === 0) {
382
- return new CompiledStatic(new RegExp(render(sanitisedParts, backrefToken), flags), featureMask);
383
- }
384
- return new CompiledDynamic({
385
- originalCaptureScan: new RegExp(spliceOriginalSource(regex.source, backreferences), flags),
386
- preScan: new RegExp(render(parts, () => ANY_CAPTURED_TEXT), flags),
387
- expand: (capture) => render(parts, (backref) => {
388
- var _a;
389
- const captured = isNumericBackreference(backref)
390
- ? capture[backref.ref]
391
- : (_a = capture.groups) === null || _a === void 0 ? void 0 : _a[backref.ref];
392
- return captured === undefined
393
- ? "(?:" + backrefToken(backref) + DISJUNCTION_TO_END_OF_INPUT
394
- : expandCaptured(captured, isUnicode);
395
- })
396
- }, featureMask);
397
- };
@@ -1,52 +0,0 @@
1
- import { type RegexFeature } from "./compilePartial.ts";
2
- export type { RegexFeature };
3
- declare const compiledPartial: unique symbol;
4
- /**
5
- * A `RegExp` subclass that supports partial (prefix) matching.
6
- *
7
- * An instance behaves like a normal `RegExp` but also matches any input string
8
- * that is a valid prefix of the original pattern — i.e. strings that could still
9
- * lead to a full match with more input. This enables validation of incomplete
10
- * input strings.
11
- *
12
- * @example
13
- * ```typescript
14
- * const pattern = /^hello world/;
15
- * const partial = new PartialMatchRegExp(pattern);
16
- *
17
- * partial.test('h'); // true - could match
18
- * partial.test('hello'); // true - could match
19
- * partial.test('hello world'); // true - full match
20
- * partial.test('goodbye'); // false - cannot match
21
- * ```
22
- *
23
- * @remarks
24
- * - The transformed pattern always matches an empty string at the end of input;
25
- * use a start anchor (`^`) to prevent false positives from empty string matches
26
- * - The `y` (sticky) flag may not behave as expected in partial matching scenarios
27
- *
28
- * @see {@link https://github.com/TomStrepsil/regex-partial-match#readme | Documentation}
29
- */
30
- declare class PartialMatchRegExp extends RegExp {
31
- private [compiledPartial];
32
- constructor(pattern: RegExp | string, flags?: string);
33
- /**
34
- * The syntactic constructs the original pattern uses, recorded as a side
35
- * effect of the single walk that builds the partial-match regex.
36
- *
37
- * The set is built on first read and cached, so patterns that are only ever
38
- * matched against never pay for it. It iterates in `RegexFeature` declaration
39
- * order, not the order the constructs appear in the pattern.
40
- *
41
- * @returns The features the original pattern contains
42
- *
43
- * @example
44
- * ```typescript
45
- * new PartialMatchRegExp(/^[a-z]+/).features.has("startAnchor"); // true
46
- * ```
47
- */
48
- get features(): ReadonlySet<RegexFeature>;
49
- exec(input: string): RegExpExecArray | null;
50
- private _execDynamic;
51
- }
52
- export default PartialMatchRegExp;
@@ -1,126 +0,0 @@
1
- import { compilePartial } from "./compilePartial.js";
2
- const compiledPartial = Symbol("compiledPartial");
3
- /**
4
- * A `RegExp` subclass that supports partial (prefix) matching.
5
- *
6
- * An instance behaves like a normal `RegExp` but also matches any input string
7
- * that is a valid prefix of the original pattern — i.e. strings that could still
8
- * lead to a full match with more input. This enables validation of incomplete
9
- * input strings.
10
- *
11
- * @example
12
- * ```typescript
13
- * const pattern = /^hello world/;
14
- * const partial = new PartialMatchRegExp(pattern);
15
- *
16
- * partial.test('h'); // true - could match
17
- * partial.test('hello'); // true - could match
18
- * partial.test('hello world'); // true - full match
19
- * partial.test('goodbye'); // false - cannot match
20
- * ```
21
- *
22
- * @remarks
23
- * - The transformed pattern always matches an empty string at the end of input;
24
- * use a start anchor (`^`) to prevent false positives from empty string matches
25
- * - The `y` (sticky) flag may not behave as expected in partial matching scenarios
26
- *
27
- * @see {@link https://github.com/TomStrepsil/regex-partial-match#readme | Documentation}
28
- */
29
- class PartialMatchRegExp extends RegExp {
30
- constructor(pattern, flags) {
31
- super(pattern, flags);
32
- this[compiledPartial] = compilePartial(this);
33
- }
34
- /**
35
- * The syntactic constructs the original pattern uses, recorded as a side
36
- * effect of the single walk that builds the partial-match regex.
37
- *
38
- * The set is built on first read and cached, so patterns that are only ever
39
- * matched against never pay for it. It iterates in `RegexFeature` declaration
40
- * order, not the order the constructs appear in the pattern.
41
- *
42
- * @returns The features the original pattern contains
43
- *
44
- * @example
45
- * ```typescript
46
- * new PartialMatchRegExp(/^[a-z]+/).features.has("startAnchor"); // true
47
- * ```
48
- */
49
- get features() {
50
- return this[compiledPartial].features;
51
- }
52
- exec(input) {
53
- const compiled = this[compiledPartial];
54
- if (compiled.kind === "dynamic")
55
- return this._execDynamic(compiled.dynamic, input);
56
- const { regex } = compiled;
57
- const match = execFrom(regex, input, this.lastIndex);
58
- this.lastIndex = regex.lastIndex;
59
- return match;
60
- }
61
- _execDynamic(dynamic, input) {
62
- var _a, _b;
63
- const { originalCaptureScan, preScan, expand } = dynamic;
64
- const honoursLastIndex = this.global || this.sticky;
65
- const start = honoursLastIndex ? this.lastIndex : 0;
66
- const originalMatch = super.exec(input);
67
- if (isAtOrBefore(originalMatch, start))
68
- return originalMatch;
69
- let preScanMatch = null;
70
- if (originalMatch) {
71
- preScanMatch = execFrom(preScan, input, start);
72
- const noEarlierPartialPossible = preScanMatch === null || preScanMatch.index >= originalMatch.index;
73
- if (noEarlierPartialPossible)
74
- return originalMatch;
75
- }
76
- const capture = (_b = (_a = execFrom(originalCaptureScan, input, start)) !== null && _a !== void 0 ? _a : preScanMatch) !== null && _b !== void 0 ? _b : execFrom(preScan, input, start);
77
- if (capture === null)
78
- return originalMatch;
79
- const expanded = new RegExp(expand(capture), this.flags);
80
- const match = execFrom(expanded, input, start);
81
- if (match === null || isAtOrBefore(originalMatch, match.index))
82
- return originalMatch;
83
- preferLongerCaptures(match, capture);
84
- if (honoursLastIndex)
85
- this.lastIndex = expanded.lastIndex;
86
- return match;
87
- }
88
- }
89
- function execFrom(regex, input, start) {
90
- regex.lastIndex = start;
91
- return regex.exec(input);
92
- }
93
- function isAtOrBefore(match, index) {
94
- return match !== null && match.index <= index;
95
- }
96
- function pickLonger(scanned, matched) {
97
- return scanned !== undefined &&
98
- matched !== undefined &&
99
- scanned.length > matched.length
100
- ? scanned
101
- : undefined;
102
- }
103
- function preferLongerCaptures(match, scanned) {
104
- var _a, _b, _c, _d;
105
- for (let index = 1; index < match.length; index++) {
106
- const longer = pickLonger(scanned[index], match[index]);
107
- if (longer === undefined)
108
- continue;
109
- match[index] = longer;
110
- if (match.indices && ((_a = scanned.indices) === null || _a === void 0 ? void 0 : _a[index])) {
111
- match.indices[index] = scanned.indices[index];
112
- }
113
- }
114
- if (match.groups && scanned.groups) {
115
- for (const name of Object.keys(match.groups)) {
116
- const longer = pickLonger(scanned.groups[name], match.groups[name]);
117
- if (longer === undefined)
118
- continue;
119
- match.groups[name] = longer;
120
- if ((_b = match.indices) === null || _b === void 0 ? void 0 : _b.groups) {
121
- match.indices.groups[name] = (_d = (_c = scanned.indices) === null || _c === void 0 ? void 0 : _c.groups) === null || _d === void 0 ? void 0 : _d[name];
122
- }
123
- }
124
- }
125
- }
126
- export default PartialMatchRegExp;