regex-partial-match 1.1.2 → 1.3.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 (69) hide show
  1. package/README.md +151 -10
  2. package/lib/{extend.d.ts → extend/index.d.ts} +1 -1
  3. package/lib/{extend.js → extend/index.js} +1 -1
  4. package/lib/partialMatchRegExp/atomSyntax.d.ts +4 -0
  5. package/lib/partialMatchRegExp/atomSyntax.js +4 -0
  6. package/lib/partialMatchRegExp/backreferenceExpansion.d.ts +10 -0
  7. package/lib/partialMatchRegExp/backreferenceExpansion.js +1 -0
  8. package/lib/partialMatchRegExp/compilePartial/asNativeAtom.d.ts +2 -0
  9. package/lib/partialMatchRegExp/compilePartial/asNativeAtom.js +10 -0
  10. package/lib/partialMatchRegExp/compilePartial/asOptionalAtom.d.ts +1 -0
  11. package/lib/partialMatchRegExp/compilePartial/asOptionalAtom.js +4 -0
  12. package/lib/partialMatchRegExp/compilePartial/asPreScanPart.d.ts +2 -0
  13. package/lib/partialMatchRegExp/compilePartial/asPreScanPart.js +8 -0
  14. package/lib/partialMatchRegExp/compilePartial/caseFoldFlags.d.ts +1 -0
  15. package/lib/partialMatchRegExp/compilePartial/caseFoldFlags.js +3 -0
  16. package/lib/partialMatchRegExp/compilePartial/compiled.d.ts +29 -0
  17. package/lib/partialMatchRegExp/compilePartial/compiled.js +27 -0
  18. package/lib/partialMatchRegExp/compilePartial/flagsAtBackreference.d.ts +2 -0
  19. package/lib/partialMatchRegExp/compilePartial/flagsAtBackreference.js +4 -0
  20. package/lib/partialMatchRegExp/compilePartial/index.d.ts +2 -0
  21. package/lib/partialMatchRegExp/compilePartial/index.js +79 -0
  22. package/lib/partialMatchRegExp/compilePartial/longestBakedPrefixEndingInput.d.ts +1 -0
  23. package/lib/partialMatchRegExp/compilePartial/longestBakedPrefixEndingInput.js +50 -0
  24. package/lib/partialMatchRegExp/compilePartial/reclassifyLegacyEscapes.d.ts +2 -0
  25. package/lib/partialMatchRegExp/compilePartial/reclassifyLegacyEscapes.js +17 -0
  26. package/lib/partialMatchRegExp/compilePartial/renderParts.d.ts +2 -0
  27. package/lib/partialMatchRegExp/compilePartial/renderParts.js +9 -0
  28. package/lib/partialMatchRegExp/compilePartial/resolvedFromScan.d.ts +2 -0
  29. package/lib/partialMatchRegExp/compilePartial/resolvedFromScan.js +10 -0
  30. package/lib/partialMatchRegExp/compilePartial/spliceOriginalSource.d.ts +2 -0
  31. package/lib/partialMatchRegExp/compilePartial/spliceOriginalSource.js +12 -0
  32. package/lib/partialMatchRegExp/compilePartial/startsWithUnderFlags.d.ts +1 -0
  33. package/lib/partialMatchRegExp/compilePartial/startsWithUnderFlags.js +7 -0
  34. package/lib/partialMatchRegExp/compilePartial/toStatic.d.ts +3 -0
  35. package/lib/partialMatchRegExp/compilePartial/toStatic.js +4 -0
  36. package/lib/partialMatchRegExp/groupName.d.ts +2 -0
  37. package/lib/partialMatchRegExp/groupName.js +8 -0
  38. package/lib/partialMatchRegExp/index.d.ts +3 -0
  39. package/lib/partialMatchRegExp/index.js +3 -0
  40. package/lib/partialMatchRegExp/isComplete/index.d.ts +38 -0
  41. package/lib/partialMatchRegExp/isComplete/index.js +41 -0
  42. package/lib/partialMatchRegExp/isComplete/isMatchComplete.d.ts +3 -0
  43. package/lib/partialMatchRegExp/isComplete/isMatchComplete.js +14 -0
  44. package/lib/partialMatchRegExp/isComplete/partRole.d.ts +3 -0
  45. package/lib/partialMatchRegExp/isComplete/partRole.js +28 -0
  46. package/lib/partialMatchRegExp/isComplete/truncationProbe.d.ts +8 -0
  47. package/lib/partialMatchRegExp/isComplete/truncationProbe.js +105 -0
  48. package/lib/partialMatchRegExp/isComplete/truncationProbeCache.d.ts +4 -0
  49. package/lib/partialMatchRegExp/isComplete/truncationProbeCache.js +1 -0
  50. package/lib/partialMatchRegExp/legacyEscape.d.ts +2 -0
  51. package/lib/partialMatchRegExp/legacyEscape.js +18 -0
  52. package/lib/partialMatchRegExp/part.d.ts +24 -0
  53. package/lib/partialMatchRegExp/part.js +2 -0
  54. package/lib/partialMatchRegExp/partialMatchInternals.d.ts +2 -0
  55. package/lib/partialMatchRegExp/partialMatchInternals.js +2 -0
  56. package/lib/{partialMatchRegExp.d.ts → partialMatchRegExp/partialMatchRegExp.d.ts} +22 -3
  57. package/lib/partialMatchRegExp/partialMatchRegExp.js +114 -0
  58. package/lib/partialMatchRegExp/preferLongerCaptures.d.ts +1 -0
  59. package/lib/partialMatchRegExp/preferLongerCaptures.js +30 -0
  60. package/lib/partialMatchRegExp/regexFeatures.d.ts +6 -0
  61. package/lib/partialMatchRegExp/regexFeatures.js +47 -0
  62. package/lib/partialMatchRegExp/walk.d.ts +8 -0
  63. package/lib/partialMatchRegExp/walk.js +366 -0
  64. package/package.json +25 -15
  65. package/lib/compilePartial.d.ts +0 -16
  66. package/lib/compilePartial.js +0 -334
  67. package/lib/partialMatchRegExp.js +0 -122
  68. /package/lib/{escapeAtom.d.ts → partialMatchRegExp/escapeAtom.d.ts} +0 -0
  69. /package/lib/{escapeAtom.js → partialMatchRegExp/escapeAtom.js} +0 -0
@@ -1,334 +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 isBackreference = (part) => typeof part !== "string";
7
- const isNumericBackreference = (part) => isBackreference(part) && typeof part.ref === "number";
8
- function walk(regex) {
9
- const source = regex.source;
10
- const isUnicode = regex.unicode || regex.unicodeSets;
11
- let i = 0;
12
- let groupCount = 0;
13
- const features = new Set();
14
- function extractSlice(length) {
15
- return source.slice(i, (i += length));
16
- }
17
- function process() {
18
- var _a;
19
- const result = [];
20
- function appendOptional(length) {
21
- result.push("(?:" + extractSlice(length) + DISJUNCTION_TO_END_OF_INPUT);
22
- }
23
- function appendRaw(length) {
24
- result.push(extractSlice(length));
25
- }
26
- function appendRawGroup(prefixLength) {
27
- const start = i;
28
- i += prefixLength;
29
- process();
30
- result.push(source.slice(start, i));
31
- }
32
- while (i < source.length) {
33
- switch (source[i]) {
34
- case "\\":
35
- switch (source[i + 1]) {
36
- case "c":
37
- features.add("controlLetterEscape");
38
- appendOptional(3);
39
- break;
40
- case "k": {
41
- const referenceEnd = source[i + 2] === "<" ? source.indexOf(">", i) : -1;
42
- if (referenceEnd === -1) {
43
- appendOptional(2);
44
- }
45
- else {
46
- features.add("namedBackreference");
47
- const start = i;
48
- const ref = source.slice(i + 3, referenceEnd);
49
- i = referenceEnd + 1;
50
- result.push({ ref, start, end: i });
51
- }
52
- break;
53
- }
54
- case "u":
55
- features.add("unicodeEscapeSequence");
56
- if (isUnicode && source[i + 2] === "{") {
57
- appendOptional(source.indexOf("}", i) - i + 1);
58
- }
59
- else {
60
- appendOptional(6);
61
- }
62
- break;
63
- case "p":
64
- case "P":
65
- if (isUnicode) {
66
- features.add("unicodePropertyEscape");
67
- appendOptional(source.indexOf("}", i) - i + 1);
68
- }
69
- else {
70
- appendOptional(2);
71
- }
72
- break;
73
- case "x":
74
- features.add("hexEscapeSequence");
75
- appendOptional(4);
76
- break;
77
- case "b":
78
- features.add("wordBoundary");
79
- appendOptional(2);
80
- break;
81
- case "B":
82
- features.add("nonWordBoundary");
83
- appendOptional(2);
84
- break;
85
- case "f":
86
- case "n":
87
- case "r":
88
- case "t":
89
- case "v":
90
- features.add("controlEscape");
91
- appendOptional(2);
92
- break;
93
- case "1":
94
- case "2":
95
- case "3":
96
- case "4":
97
- case "5":
98
- case "6":
99
- case "7":
100
- case "8":
101
- case "9": {
102
- features.add("backreference");
103
- NOT_NUMBERS_REGEX.lastIndex = i + 1;
104
- const nextNonDigit = NOT_NUMBERS_REGEX.exec(source);
105
- const start = i;
106
- const end = nextNonDigit ? nextNonDigit.index : source.length;
107
- const ref = Number(source.slice(start + 1, end));
108
- i = end;
109
- result.push({ ref, start, end });
110
- break;
111
- }
112
- case "d":
113
- case "D":
114
- case "w":
115
- case "W":
116
- case "s":
117
- case "S":
118
- features.add("characterClassEscape");
119
- appendOptional(2);
120
- break;
121
- default:
122
- features.add("otherEscape");
123
- appendOptional(2);
124
- break;
125
- }
126
- break;
127
- case "[": {
128
- features.add("characterClass");
129
- let depth = 1, j = i + 1, previousSetOperatorCharacter;
130
- while (depth) {
131
- const character = source[j];
132
- switch (character) {
133
- case "\\":
134
- j += 2;
135
- previousSetOperatorCharacter = undefined;
136
- continue;
137
- case "[":
138
- if (regex.unicodeSets) {
139
- features.add("nestedCharacterClass");
140
- depth++;
141
- }
142
- break;
143
- case "]":
144
- depth--;
145
- break;
146
- case "&":
147
- if (regex.unicodeSets && previousSetOperatorCharacter === "&") {
148
- features.add("classIntersection");
149
- }
150
- break;
151
- case "-":
152
- if (regex.unicodeSets && previousSetOperatorCharacter === "-") {
153
- features.add("classSubtraction");
154
- }
155
- break;
156
- }
157
- previousSetOperatorCharacter = character;
158
- j++;
159
- }
160
- appendOptional(j - i);
161
- break;
162
- }
163
- case "^":
164
- features.add("startAnchor");
165
- appendRaw(1);
166
- break;
167
- case "$":
168
- features.add("endAnchor");
169
- appendRaw(1);
170
- break;
171
- case "|":
172
- features.add("disjunction");
173
- appendRaw(1);
174
- break;
175
- case "*":
176
- case "+":
177
- case "?":
178
- features.add("quantifier");
179
- appendRaw(1);
180
- break;
181
- case "{": {
182
- OCCURRENCES_REGEX.lastIndex = i;
183
- const regExpExecArray = OCCURRENCES_REGEX.exec(source);
184
- if (regExpExecArray) {
185
- features.add("quantifier");
186
- appendRaw(regExpExecArray[0].length);
187
- }
188
- else {
189
- appendOptional(1);
190
- }
191
- break;
192
- }
193
- case "(":
194
- if (source[i + 1] == "?") {
195
- switch (source[i + 2]) {
196
- case ":":
197
- features.add("nonCapturingGroup");
198
- result.push("(?:");
199
- i += 3;
200
- result.push(...process(), DISJUNCTION_TO_END_OF_INPUT);
201
- break;
202
- case "=":
203
- features.add("lookahead");
204
- result.push("(?=");
205
- i += 3;
206
- result.push(...process(), ")");
207
- break;
208
- case "-":
209
- case "i":
210
- case "s":
211
- case "m": {
212
- const flagsStart = i + 2, colonIndex = source.indexOf(":", flagsStart);
213
- const modifiers = source.slice(flagsStart, colonIndex);
214
- features.add(modifiers.includes("-")
215
- ? "modifierGroupWithRemoval"
216
- : "modifierGroup");
217
- result.push("(?" + modifiers + ":");
218
- i = colonIndex + 1;
219
- result.push(...process(), ")");
220
- break;
221
- }
222
- case "!":
223
- features.add("negativeLookahead");
224
- appendRawGroup(3);
225
- break;
226
- case "<":
227
- switch (source[i + 3]) {
228
- case "=":
229
- features.add("lookbehind");
230
- appendRawGroup(4);
231
- break;
232
- case "!":
233
- features.add("negativeLookbehind");
234
- appendRawGroup(4);
235
- break;
236
- default:
237
- features.add("namedGroup");
238
- features.add("capturingGroup");
239
- ++groupCount;
240
- appendRaw(source.indexOf(">", i) - i + 1);
241
- result.push(...process(), DISJUNCTION_TO_END_OF_INPUT);
242
- break;
243
- }
244
- break;
245
- }
246
- }
247
- else {
248
- features.add("capturingGroup");
249
- ++groupCount;
250
- appendRaw(1);
251
- result.push(...process(), DISJUNCTION_TO_END_OF_INPUT);
252
- }
253
- break;
254
- case ")":
255
- ++i;
256
- return result;
257
- default:
258
- features.add("patternCharacter");
259
- appendOptional(isUnicode && ((_a = source.codePointAt(i)) !== null && _a !== void 0 ? _a : 0) > 0xffff ? 2 : 1);
260
- break;
261
- }
262
- }
263
- return result;
264
- }
265
- return { parts: process(), groupCount, features };
266
- }
267
- function render(parts, renderBackref) {
268
- return parts
269
- .map((part) => (isBackreference(part) ? renderBackref(part) : part))
270
- .join("");
271
- }
272
- function backrefToken(backref) {
273
- return isNumericBackreference(backref)
274
- ? "\\" + String(backref.ref)
275
- : "\\k<" + backref.ref + ">";
276
- }
277
- function reclassifyOctalEscapes(parts, source, groupCount) {
278
- return parts.map((part) => isNumericBackreference(part) && part.ref > groupCount
279
- ? "(?:" + source.slice(part.start, part.end) + DISJUNCTION_TO_END_OF_INPUT
280
- : part);
281
- }
282
- function spliceOriginalSource(source, backrefs) {
283
- let result = "";
284
- let cursor = 0;
285
- for (const { start, end } of backrefs) {
286
- result += source.slice(cursor, start) + "(?:[\\s\\S]*?)";
287
- cursor = end;
288
- }
289
- return result + source.slice(cursor);
290
- }
291
- function expandCaptured(value, isUnicode) {
292
- return (isUnicode ? Array.from(value) : value.split(""))
293
- .map((atom) => "(?:" + escapeAtom(atom) + DISJUNCTION_TO_END_OF_INPUT)
294
- .join("");
295
- }
296
- export const compilePartial = (regex) => {
297
- const { parts, groupCount, features } = walk(regex);
298
- if (!MAYBE_HAS_BACKREFERENCE_REGEX.test(regex.source)) {
299
- return {
300
- kind: "static",
301
- regex: new RegExp(render(parts, backrefToken), regex.flags),
302
- features
303
- };
304
- }
305
- const isUnicode = regex.unicode || regex.unicodeSets;
306
- const sanitisedParts = isUnicode
307
- ? parts
308
- : reclassifyOctalEscapes(parts, regex.source, groupCount);
309
- const backreferences = sanitisedParts.filter(isBackreference);
310
- if (backreferences.length === 0) {
311
- return {
312
- kind: "static",
313
- regex: new RegExp(render(sanitisedParts, backrefToken), regex.flags),
314
- features
315
- };
316
- }
317
- return {
318
- kind: "dynamic",
319
- features,
320
- dynamic: {
321
- originalCaptureScan: new RegExp(spliceOriginalSource(regex.source, backreferences), regex.flags),
322
- preScan: new RegExp(render(parts, () => "(?:[\\s\\S]*?)"), regex.flags),
323
- expand: (capture) => render(parts, (backref) => {
324
- var _a;
325
- const captured = isNumericBackreference(backref)
326
- ? capture[backref.ref]
327
- : (_a = capture.groups) === null || _a === void 0 ? void 0 : _a[backref.ref];
328
- return captured === undefined
329
- ? "(?:" + backrefToken(backref) + DISJUNCTION_TO_END_OF_INPUT
330
- : expandCaptured(captured, isUnicode);
331
- })
332
- }
333
- };
334
- };
@@ -1,122 +0,0 @@
1
- var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
2
- if (kind === "m") throw new TypeError("Private method is not writable");
3
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
4
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
5
- return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
6
- };
7
- var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
8
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
9
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
- return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
- };
12
- var _PartialMatchRegExp_compiledPartial;
13
- import { compilePartial } from "./compilePartial.js";
14
- /**
15
- * A `RegExp` subclass that supports partial (prefix) matching.
16
- *
17
- * An instance behaves like a normal `RegExp` but also matches any input string
18
- * that is a valid prefix of the original pattern — i.e. strings that could still
19
- * lead to a full match with more input. This enables validation of incomplete
20
- * input strings.
21
- *
22
- * @example
23
- * ```typescript
24
- * const pattern = /^hello world/;
25
- * const partial = new PartialMatchRegExp(pattern);
26
- *
27
- * partial.test('h'); // true - could match
28
- * partial.test('hello'); // true - could match
29
- * partial.test('hello world'); // true - full match
30
- * partial.test('goodbye'); // false - cannot match
31
- * ```
32
- *
33
- * @remarks
34
- * - The transformed pattern always matches an empty string at the end of input;
35
- * use a start anchor (`^`) to prevent false positives from empty string matches
36
- * - The `y` (sticky) flag may not behave as expected in partial matching scenarios
37
- *
38
- * @see {@link https://github.com/TomStrepsil/regex-partial-match#readme | Documentation}
39
- */
40
- class PartialMatchRegExp extends RegExp {
41
- constructor(pattern, flags) {
42
- super(pattern, flags);
43
- _PartialMatchRegExp_compiledPartial.set(this, void 0);
44
- __classPrivateFieldSet(this, _PartialMatchRegExp_compiledPartial, compilePartial(this), "f");
45
- this.features = __classPrivateFieldGet(this, _PartialMatchRegExp_compiledPartial, "f").features;
46
- }
47
- exec(input) {
48
- const compiled = __classPrivateFieldGet(this, _PartialMatchRegExp_compiledPartial, "f");
49
- if (compiled.kind === "dynamic")
50
- return this._execDynamic(compiled.dynamic, input);
51
- const { regex } = compiled;
52
- const match = execFrom(regex, input, this.lastIndex);
53
- this.lastIndex = regex.lastIndex;
54
- return match;
55
- }
56
- _execDynamic(dynamic, input) {
57
- var _a, _b;
58
- const { originalCaptureScan, preScan, expand } = dynamic;
59
- const honoursLastIndex = this.global || this.sticky;
60
- const start = honoursLastIndex ? this.lastIndex : 0;
61
- const originalMatch = super.exec(input);
62
- if (isAtOrBefore(originalMatch, start))
63
- return originalMatch;
64
- let preScanMatch = null;
65
- if (originalMatch) {
66
- preScanMatch = execFrom(preScan, input, start);
67
- const noEarlierPartialPossible = preScanMatch === null || preScanMatch.index >= originalMatch.index;
68
- if (noEarlierPartialPossible)
69
- return originalMatch;
70
- }
71
- const capture = (_b = (_a = execFrom(originalCaptureScan, input, start)) !== null && _a !== void 0 ? _a : preScanMatch) !== null && _b !== void 0 ? _b : execFrom(preScan, input, start);
72
- if (capture === null)
73
- return originalMatch;
74
- const expanded = new RegExp(expand(capture), this.flags);
75
- const match = execFrom(expanded, input, start);
76
- if (match === null || isAtOrBefore(originalMatch, match.index))
77
- return originalMatch;
78
- preferLongerCaptures(match, capture);
79
- if (honoursLastIndex)
80
- this.lastIndex = expanded.lastIndex;
81
- return match;
82
- }
83
- }
84
- _PartialMatchRegExp_compiledPartial = new WeakMap();
85
- function execFrom(regex, input, start) {
86
- regex.lastIndex = start;
87
- return regex.exec(input);
88
- }
89
- function isAtOrBefore(match, index) {
90
- return match !== null && match.index <= index;
91
- }
92
- function pickLonger(scanned, matched) {
93
- return scanned !== undefined &&
94
- matched !== undefined &&
95
- scanned.length > matched.length
96
- ? scanned
97
- : undefined;
98
- }
99
- function preferLongerCaptures(match, scanned) {
100
- var _a, _b, _c, _d;
101
- for (let index = 1; index < match.length; index++) {
102
- const longer = pickLonger(scanned[index], match[index]);
103
- if (longer === undefined)
104
- continue;
105
- match[index] = longer;
106
- if (match.indices && ((_a = scanned.indices) === null || _a === void 0 ? void 0 : _a[index])) {
107
- match.indices[index] = scanned.indices[index];
108
- }
109
- }
110
- if (match.groups && scanned.groups) {
111
- for (const name of Object.keys(match.groups)) {
112
- const longer = pickLonger(scanned.groups[name], match.groups[name]);
113
- if (longer === undefined)
114
- continue;
115
- match.groups[name] = longer;
116
- if ((_b = match.indices) === null || _b === void 0 ? void 0 : _b.groups) {
117
- match.indices.groups[name] = (_d = (_c = scanned.indices) === null || _c === void 0 ? void 0 : _c.groups) === null || _d === void 0 ? void 0 : _d[name];
118
- }
119
- }
120
- }
121
- }
122
- export default PartialMatchRegExp;