regex-partial-match 0.1.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.
- package/LICENSE +7 -0
- package/README.md +266 -0
- package/lib/extend.d.ts +6 -0
- package/lib/extend.js +4 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +133 -0
- package/package.json +77 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
ISC License
|
|
2
|
+
|
|
3
|
+
Copyright 2025 Tom Pereira (https://github.com/TomStrepsil)
|
|
4
|
+
|
|
5
|
+
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
|
|
6
|
+
|
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
# regex-partial-match
|
|
2
|
+
|
|
3
|
+
A zero-dependency regular expression transform for partial matching, enabling validation of incomplete input strings against regex patterns.
|
|
4
|
+
|
|
5
|
+
## Problem statement
|
|
6
|
+
|
|
7
|
+
Unlike C/C++ (via [PCRE/PCRE2](https://www.pcre.org/original/doc/html/pcrepartial.html), [RE2](https://github.com/google/re2?tab=readme-ov-file#matching-interface), [Boost.Regex](https://www.boost.org/doc/libs/1_34_1/libs/regex/doc/partial_matches.html)), Python ([via third party regex module](https://pypi.org/project/regex/#:~:text=Added%20partial%20matches)) or Java (via [`hitEnd`](https://docs.oracle.com/javase/8/docs/api/java/util/regex/Matcher.html#hitEnd--)), Javascript has no canonical / innate partial-matching for regular expressions.
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
This library transforms regular expressions to best-effort support **partial matching**, allowing you to test if an incomplete string could potentially match the full pattern. This is particularly useful for real-time input validation, autocomplete systems, progressive form validation, stream chunk matching, etc.
|
|
12
|
+
|
|
13
|
+
**Based on an algorithm created by [Lucas Trzesniewski](https://github.com/ltrzesniewski)**, re-created for NPM via ISC license, with permission.
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install regex-partial-match
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
If your runtime doesn't support these features, attempting to use patterns with them will throw a `SyntaxError`.
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
### Basic Usage
|
|
26
|
+
|
|
27
|
+
```javascript
|
|
28
|
+
import createPartialMatchRegex from "regex-partial-match";
|
|
29
|
+
|
|
30
|
+
const pattern = /hello world/;
|
|
31
|
+
const partial = createPartialMatchRegex(pattern);
|
|
32
|
+
|
|
33
|
+
partial.test("h"); // true - could match
|
|
34
|
+
partial.test("hello"); // true - could match
|
|
35
|
+
partial.test("hello world"); // true - full match
|
|
36
|
+
partial.test("goodbye"); // false - cannot match
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Extending RegExp.prototype
|
|
40
|
+
|
|
41
|
+
```javascript
|
|
42
|
+
import "regex-partial-match/extend";
|
|
43
|
+
|
|
44
|
+
const partial = /hello world/.createPartialMatchRegexRegex();
|
|
45
|
+
|
|
46
|
+
partial.test("hel"); // true
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## How It Works
|
|
50
|
+
|
|
51
|
+
The library transforms a regular expression by wrapping each atomic element in a non-capturing group with an alternation to end-of-input (`$`):
|
|
52
|
+
|
|
53
|
+
```javascript
|
|
54
|
+
/abc/ → /(?:a|$)(?:b|$)(?:c|$)/
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
This allows the pattern to match prefixes of the original pattern, enabling validation of incomplete input.
|
|
58
|
+
|
|
59
|
+
Since the library accepts only valid regular expressions [^1], this enables the algorithm to make lots of unguarded assumptions about the source of the expression.
|
|
60
|
+
|
|
61
|
+
The library has been stress-tested with various regular expression features in isolation, and some in likely combination, but obviously its an unbounded test space, and syntactically valid regular expressions nevertheless support contradictory patterns e.g.
|
|
62
|
+
|
|
63
|
+
- `/\b\B/` - impossible to match both a word boundary and a non-word boundary
|
|
64
|
+
- `/$^/` - end cannot come before start
|
|
65
|
+
- `x{2}?` - lazy quantifiers are mutually exclusive to fixed-length assertions
|
|
66
|
+
|
|
67
|
+
Such combinations have not been tested.
|
|
68
|
+
|
|
69
|
+
[^1]: To remain lightweight, no runtime type validation is applied, so non-typescript consumers will be reliant on underlying errors thrown, if used incorrectly.
|
|
70
|
+
|
|
71
|
+
## Supported Features
|
|
72
|
+
|
|
73
|
+
- 🔤 [Literal characters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Regular_expressions/Literal_character)
|
|
74
|
+
- 📋 [Character classes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Regular_expressions/Character_class) (`[abc]`, `[^abc]`, `[a-z]`)
|
|
75
|
+
- 🔣 [Character escapes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Regular_expressions/Character_escape) (`\n`, `\t`, `\x61`, `\u0061`, `\u{1F600}`)
|
|
76
|
+
- 🌐 [Unicode character class escape](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Regular_expressions/Unicode_character_class_escape) (`\p{Letter}`, `\P{Letter}`)
|
|
77
|
+
- 🔢 [Quantifiers](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Regular_expressions/Quantifier) (`*`, `+`, `?`, `{n}`, `{n,}`, `{n,m}`)
|
|
78
|
+
- 🔀 [Disjunction](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Regular_expressions/Disjunction) (`a|b`)
|
|
79
|
+
- 👥 [Groups](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Regular_expressions/Capturing_group) (capturing and non-capturing) (`(?:abc)`, `(abc)`, `(?<named>abc)`)
|
|
80
|
+
- 👀 [Lookahead assertions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Regular_expressions/Lookahead_assertion) (`(?=...)`, `(?!...)`)
|
|
81
|
+
- 👈 [Lookbehind assertions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Regular_expressions/Lookbehind_assertion) (`(?<=...)`, `(?<!...)`)
|
|
82
|
+
- ⚓ [Anchors](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Regular_expressions/Input_boundary_assertion) (`^`, `$`)
|
|
83
|
+
- 🏴 [Flags](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/flags): `g`, `i`, `m`, `s`, `u`, `d`, `y` (See caveats for `y`)
|
|
84
|
+
|
|
85
|
+
## Unsupported Features
|
|
86
|
+
|
|
87
|
+
The following regex features are **not currently supported**:
|
|
88
|
+
|
|
89
|
+
- ⚠️ [Backreferences](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Regular_expressions/Backreference) (`\1`, `\k<name>`) - Can be included, but can't partially match. See [caveats](#caveats).
|
|
90
|
+
- ❌ [Unicode sets (`v` flag)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/unicodeSets) - ES2024+
|
|
91
|
+
- ❌ [Modifiers](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Regular_expressions/Modifier) (`(?ims:...)`, `(?-ims:...)`) - ES2025+
|
|
92
|
+
|
|
93
|
+
## Browser Compatibility
|
|
94
|
+
|
|
95
|
+
The library is compiled to **ES5** for broad compatibility with older browsers and JavaScript environments. However, certain regular expression features naturally require ES2015+ support:
|
|
96
|
+
|
|
97
|
+
- [**Unicode escapes**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Regular_expressions/Unicode_character_class_escape) (`\u{...}`) - ES2015+
|
|
98
|
+
- [**Unicode property escapes**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Regular_expressions/Unicode_character_class_escape) (`\p{...}`, `\P{...}`) - ES2018+
|
|
99
|
+
- [**Lookbehind assertions**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Regular_expressions/Lookbehind_assertion) (`(?<=...)`, `(?<!...)`) - ES2018+
|
|
100
|
+
- [**Named capturing groups**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Regular_expressions/Named_capturing_group) (`(?<name>...)`) - ES2018+
|
|
101
|
+
- [**`s` (dotAll) flag**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/dotAll) - ES2018+
|
|
102
|
+
- [**`d` (hasIndices) flag**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/hasIndices) - ES2022+
|
|
103
|
+
|
|
104
|
+
## Caveats
|
|
105
|
+
|
|
106
|
+
### Backreferences
|
|
107
|
+
|
|
108
|
+
**Backreferences with variable-length captures cannot be partially matched** due to ambiguity in how the pattern should be matched. While simple fixed-length backreferences like `/(abc)\1/` could theoretically be transformed (if accepting that the group indexes would be polluted, compared to the original), to become `/(?:(a)|$)(?:(b)|$)(?:(c)|$)(?:\1|$)(?:\2|$)(?:\3|$)/` variable-length patterns break down.
|
|
109
|
+
|
|
110
|
+
For example, with `/(\w+) \1/` (matches "hello hello"):
|
|
111
|
+
|
|
112
|
+
- A naive transformation `/(?:(\w+)|$)(?:( )|$)(?:\1|$)/` creates ambiguity
|
|
113
|
+
- For input "hello h", the regex can match in multiple ways:
|
|
114
|
+
- Capture group 1 as "hello", skip the space with `$`, skip `\1` with `$` ✓
|
|
115
|
+
- Capture group 1 as "h", skip the space with `$`, match `\1` as "h" ✓ (at position 6)
|
|
116
|
+
- The engine chooses the second interpretation, matching just "h" instead of recognizing "hello h" as a partial match
|
|
117
|
+
|
|
118
|
+
The core issue: **the regex engine cannot determine which part of the input should be captured vs. which part should match the backreference** when dealing with variable-length patterns and incomplete input. Fixed-length patterns like `/(abc)\1/` avoid this ambiguity since each character position has a clear role.
|
|
119
|
+
|
|
120
|
+
### Surrogate Pair Matching
|
|
121
|
+
|
|
122
|
+
In unicode-aware mode (`u` flag), **only whole astral characters are supported**. Partial matching of individual surrogate pairs is not supported. For example, `/😀/u` will match the complete emoji character, but not the first surrogate pair in isolation. Hence, if partially matching a byte stream, be sure to pipe via a [`TextDecoder`](https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder) first.
|
|
123
|
+
|
|
124
|
+
### [Sticky](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/sticky) Flag (`y`)
|
|
125
|
+
|
|
126
|
+
The **sticky flag may not behave as expected** in partial matching scenarios. The sticky flag requires matches to start at `lastIndex`, but a partial match failure resets `lastIndex` to 0. This means subsequent attempts cannot "continue" from where the previous match failed, making progressive character-by-character validation problematic.
|
|
127
|
+
|
|
128
|
+
**Example:**
|
|
129
|
+
|
|
130
|
+
```javascript
|
|
131
|
+
const pattern = /hello/y;
|
|
132
|
+
const partial = createPartialMatchRegex(pattern);
|
|
133
|
+
|
|
134
|
+
pattern.lastIndex = 0;
|
|
135
|
+
partial.test("h"); // succeeds, lastIndex advances
|
|
136
|
+
partial.test("he"); // succeeds, but lastIndex was reset by previous test
|
|
137
|
+
// Cannot reliably continue partial matching with sticky flag
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
**Recommendation:** Avoid using the `y` flag with partial matching unless you fully understand the implications.
|
|
141
|
+
|
|
142
|
+
### Global Flag (`g`)
|
|
143
|
+
|
|
144
|
+
The **global flag is preserved** but may not be necessary for partial matching use cases. The `g` flag affects behavior when using `.exec()` repeatedly to find all matches, but partial matching typically validates a single prefix at a time.
|
|
145
|
+
|
|
146
|
+
The global flag does not cause issues like the sticky flag, as partial patterns naturally match from the beginning of the input. However, if you're using `lastIndex` to track position, be aware that failed matches will reset it to 0.
|
|
147
|
+
|
|
148
|
+
## Examples
|
|
149
|
+
|
|
150
|
+
### Form Validation
|
|
151
|
+
|
|
152
|
+
```javascript
|
|
153
|
+
import createPartialMatchRegex from "regex-partial-match";
|
|
154
|
+
|
|
155
|
+
const emailPattern = /^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$/i;
|
|
156
|
+
const partial = createPartialMatchRegex(emailPattern);
|
|
157
|
+
|
|
158
|
+
function validateEmail(input) {
|
|
159
|
+
return partial.test(input) ? "valid" : "invalid";
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
validateEmail("user"); // 'valid' - could become valid
|
|
163
|
+
validateEmail("user@"); // 'valid' - could become valid
|
|
164
|
+
validateEmail("user@example"); // 'valid' - could become valid
|
|
165
|
+
validateEmail("user@example.com"); // 'valid' - complete match
|
|
166
|
+
validateEmail("@@invalid"); // 'invalid' - cannot match
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Autocomplete
|
|
170
|
+
|
|
171
|
+
```javascript
|
|
172
|
+
const commandPattern = /^(help|quit|save|load)/;
|
|
173
|
+
const partial = createPartialMatchRegex(commandPattern);
|
|
174
|
+
|
|
175
|
+
function getSuggestions(input) {
|
|
176
|
+
return partial.test(input) ? "valid prefix" : "no suggestions";
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
getSuggestions("h"); // 'valid prefix'
|
|
180
|
+
getSuggestions("hel"); // 'valid prefix'
|
|
181
|
+
getSuggestions("help"); // 'valid prefix'
|
|
182
|
+
getSuggestions("xyz"); // 'no suggestions'
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Stream Processing
|
|
186
|
+
|
|
187
|
+
```javascript
|
|
188
|
+
import createPartialMatchRegex from "regex-partial-match";
|
|
189
|
+
|
|
190
|
+
// Process streaming data with pattern matching at chunk boundaries
|
|
191
|
+
const pattern = /\{"[^"]+":"[^"]+"\}/; // Match JSON objects
|
|
192
|
+
const partial = createPartialMatchRegex(pattern);
|
|
193
|
+
let buffer = "";
|
|
194
|
+
|
|
195
|
+
function processChunk(chunk) {
|
|
196
|
+
buffer += chunk;
|
|
197
|
+
const matches = [];
|
|
198
|
+
|
|
199
|
+
// Extract complete matches
|
|
200
|
+
let match;
|
|
201
|
+
while ((match = pattern.exec(buffer))) {
|
|
202
|
+
matches.push(match[0]);
|
|
203
|
+
buffer = buffer.slice(match.index + match[0].length);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Discard buffer if it cannot possibly complete
|
|
207
|
+
if (buffer && !partial.test(buffer)) {
|
|
208
|
+
buffer = "";
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return matches;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
processChunk('{"na'); // [] - partial, buffer: '{"na'
|
|
215
|
+
processChunk('me":"Jo'); // [] - partial, buffer: '{"name":"Jo'
|
|
216
|
+
processChunk('hn"}{"age":'); // ['{"name":"John"}'] - buffer: '{"age":'
|
|
217
|
+
processChunk("25}"); // ['{"age":25}'] - buffer: ''
|
|
218
|
+
processChunk("invalid{"); // [] - discarded, buffer: ''
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
Useful for parsing log files, network streams, or any chunked data where records may be split across boundaries.
|
|
222
|
+
|
|
223
|
+
## API
|
|
224
|
+
|
|
225
|
+
### `createPartialMatchRegex(regex: RegExp): RegExp`
|
|
226
|
+
|
|
227
|
+
Transforms a regular expression to support partial matching.
|
|
228
|
+
|
|
229
|
+
Available via the default entry point of the package.
|
|
230
|
+
|
|
231
|
+
**Parameters:**
|
|
232
|
+
|
|
233
|
+
- `regex` - The regular expression to transform
|
|
234
|
+
|
|
235
|
+
**Returns:**
|
|
236
|
+
|
|
237
|
+
- A new `RegExp` that matches partial strings
|
|
238
|
+
|
|
239
|
+
### `RegExp.prototype.toPartialMatchRegex(): RegExp`
|
|
240
|
+
|
|
241
|
+
When using `import 'regex-partial-match/extend'`, this method is added to `RegExp.prototype`.
|
|
242
|
+
|
|
243
|
+
**Returns:**
|
|
244
|
+
|
|
245
|
+
- A new `RegExp` that matches partial strings, created from the `RegExp` instance the method was called on.
|
|
246
|
+
|
|
247
|
+
## License
|
|
248
|
+
|
|
249
|
+
ISC License - see [LICENSE](./LICENSE) file for details.
|
|
250
|
+
|
|
251
|
+
## Credits
|
|
252
|
+
|
|
253
|
+
Algorithm created by [Lucas Trzesniewski](https://github.com/ltrzesniewski).
|
|
254
|
+
|
|
255
|
+
## Contributing
|
|
256
|
+
|
|
257
|
+
Contributions are welcome! Please open an issue or pull request on [GitHub](https://github.com/TomStrepsil/regex-partial-match).
|
|
258
|
+
|
|
259
|
+
## Related packages
|
|
260
|
+
|
|
261
|
+
- [`incr-regex-package`](https://www.npmjs.com/package/incr-regex-package)
|
|
262
|
+
- Incremental regex matcher
|
|
263
|
+
- [`dfa`](https://github.com/foliojs/dfa)
|
|
264
|
+
- Compiles a regular expression like syntax to fast deterministic finite automata, which could be used to partial match?
|
|
265
|
+
- [`refa`](https://github.com/RunDevelopment/refa)
|
|
266
|
+
- Can [convert regular expressions to an Abstract Syntax Tree](https://rundevelopment.github.io/refa/docs/latest/classes/JS.Parser.html), which might afford partial-match capability?
|
package/lib/extend.d.ts
ADDED
package/lib/extend.js
ADDED
package/lib/index.d.ts
ADDED
package/lib/index.js
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
var characterClassGlobalRegex = /\[(?:\\.|.)*?\]/g;
|
|
2
|
+
var occurrencesRegex = /\{\d+,?\d*\}/g;
|
|
3
|
+
var createPartialMatchRegex = function (regex) {
|
|
4
|
+
var source = regex.source;
|
|
5
|
+
var i = 0;
|
|
6
|
+
function extractSubstring(length) {
|
|
7
|
+
return source.substring(i, (i += length));
|
|
8
|
+
}
|
|
9
|
+
function process() {
|
|
10
|
+
var result = "";
|
|
11
|
+
function appendOptional(length) {
|
|
12
|
+
result += "(?:" + extractSubstring(length) + "|$)";
|
|
13
|
+
}
|
|
14
|
+
function appendRaw(length) {
|
|
15
|
+
result += extractSubstring(length);
|
|
16
|
+
}
|
|
17
|
+
while (i < source.length) {
|
|
18
|
+
switch (source[i]) {
|
|
19
|
+
case "\\":
|
|
20
|
+
switch (source[i + 1]) {
|
|
21
|
+
case "c":
|
|
22
|
+
appendOptional(3);
|
|
23
|
+
break;
|
|
24
|
+
case "k":
|
|
25
|
+
appendOptional(source.indexOf(">", i) - i + 1);
|
|
26
|
+
break;
|
|
27
|
+
case "u":
|
|
28
|
+
if (regex.unicode && source[i + 2] === "{") {
|
|
29
|
+
appendOptional(source.indexOf("}", i) - i + 1);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
appendOptional(6);
|
|
33
|
+
}
|
|
34
|
+
break;
|
|
35
|
+
case "p":
|
|
36
|
+
case "P":
|
|
37
|
+
if (regex.unicode) {
|
|
38
|
+
appendOptional(source.indexOf("}", i) - i + 1);
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
appendOptional(2);
|
|
42
|
+
}
|
|
43
|
+
break;
|
|
44
|
+
case "x":
|
|
45
|
+
appendOptional(4);
|
|
46
|
+
break;
|
|
47
|
+
default:
|
|
48
|
+
appendOptional(2);
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
break;
|
|
52
|
+
case "[": {
|
|
53
|
+
characterClassGlobalRegex.lastIndex = i;
|
|
54
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- must match, since otherwise an invalid regex
|
|
55
|
+
var match = characterClassGlobalRegex.exec(source)[0];
|
|
56
|
+
appendOptional(match.length);
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
case "|":
|
|
60
|
+
case "^":
|
|
61
|
+
case "*":
|
|
62
|
+
case "+":
|
|
63
|
+
case "?":
|
|
64
|
+
case "$":
|
|
65
|
+
appendRaw(1);
|
|
66
|
+
break;
|
|
67
|
+
case "{": {
|
|
68
|
+
occurrencesRegex.lastIndex = i;
|
|
69
|
+
var regExpExecArray = occurrencesRegex.exec(source);
|
|
70
|
+
if (regExpExecArray) {
|
|
71
|
+
appendRaw(regExpExecArray[0].length);
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
appendOptional(1);
|
|
75
|
+
}
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
case "(":
|
|
79
|
+
if (source[i + 1] == "?") {
|
|
80
|
+
switch (source[i + 2]) {
|
|
81
|
+
case ":":
|
|
82
|
+
result += "(?:";
|
|
83
|
+
i += 3;
|
|
84
|
+
result += process() + "|$)";
|
|
85
|
+
break;
|
|
86
|
+
case "=":
|
|
87
|
+
result += "(?=";
|
|
88
|
+
i += 3;
|
|
89
|
+
result += process() + ")";
|
|
90
|
+
break;
|
|
91
|
+
case "!": {
|
|
92
|
+
var temp = i;
|
|
93
|
+
i += 3;
|
|
94
|
+
process();
|
|
95
|
+
result += source.substring(temp, i);
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
case "<":
|
|
99
|
+
switch (source[i + 3]) {
|
|
100
|
+
case "=":
|
|
101
|
+
case "!": {
|
|
102
|
+
var temp = i;
|
|
103
|
+
i += 4;
|
|
104
|
+
process();
|
|
105
|
+
result += source.substring(temp, i);
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
default:
|
|
109
|
+
appendRaw(source.indexOf(">", i) - i + 1);
|
|
110
|
+
result += process() + "|$)";
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
appendRaw(1);
|
|
118
|
+
result += process() + "|$)";
|
|
119
|
+
}
|
|
120
|
+
break;
|
|
121
|
+
case ")":
|
|
122
|
+
++i;
|
|
123
|
+
return result;
|
|
124
|
+
default:
|
|
125
|
+
appendOptional(1);
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return result;
|
|
130
|
+
}
|
|
131
|
+
return new RegExp(process(), regex.flags);
|
|
132
|
+
};
|
|
133
|
+
export default createPartialMatchRegex;
|
package/package.json
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "regex-partial-match",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "A regular expression transform for partial matching",
|
|
5
|
+
"engines": {
|
|
6
|
+
"node": ">=23"
|
|
7
|
+
},
|
|
8
|
+
"keywords": [
|
|
9
|
+
"regexp",
|
|
10
|
+
"regular expressions",
|
|
11
|
+
"partial matcher"
|
|
12
|
+
],
|
|
13
|
+
"license": "ISC",
|
|
14
|
+
"author": {
|
|
15
|
+
"name": "Tom Pereira",
|
|
16
|
+
"url": "https://github.com/TomStrepsil"
|
|
17
|
+
},
|
|
18
|
+
"bugs": {
|
|
19
|
+
"url": "https://github.com/TomStrepsil/regex-partial-match/issues"
|
|
20
|
+
},
|
|
21
|
+
"homepage": "https://github.com/TomStrepsil/regex-partial-match#readme",
|
|
22
|
+
"contributors": [
|
|
23
|
+
{
|
|
24
|
+
"name": "Lucas Trzesniewski",
|
|
25
|
+
"url": "https://github.com/ltrzesniewski"
|
|
26
|
+
}
|
|
27
|
+
],
|
|
28
|
+
"type": "module",
|
|
29
|
+
"main": "lib/index.js",
|
|
30
|
+
"exports": {
|
|
31
|
+
".": {
|
|
32
|
+
"import": "./lib/index.js",
|
|
33
|
+
"types": "./lib/index.d.ts"
|
|
34
|
+
},
|
|
35
|
+
"./extend": {
|
|
36
|
+
"import": "./lib/extend.js",
|
|
37
|
+
"types": "./lib/extend.d.ts"
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"files": [
|
|
41
|
+
"lib"
|
|
42
|
+
],
|
|
43
|
+
"repository": {
|
|
44
|
+
"type": "git",
|
|
45
|
+
"url": "git+https://github.com/TomStrepsil/regex-partial-match.git"
|
|
46
|
+
},
|
|
47
|
+
"sideEffects": false,
|
|
48
|
+
"scripts": {
|
|
49
|
+
"lint": "eslint .",
|
|
50
|
+
"lint:fix": "eslint . --fix",
|
|
51
|
+
"prepare": "simple-git-hooks",
|
|
52
|
+
"prepublishOnly": "tsc -p tsconfig.build.json",
|
|
53
|
+
"test": "vitest run --config ./test/vitest.config.ts",
|
|
54
|
+
"test:watch": "vitest --config ./test/vitest.config.ts"
|
|
55
|
+
},
|
|
56
|
+
"simple-git-hooks": {
|
|
57
|
+
"pre-commit": "node_modules/.bin/lint-staged"
|
|
58
|
+
},
|
|
59
|
+
"lint-staged": {
|
|
60
|
+
"*.{ts,js}": [
|
|
61
|
+
"npm run lint:fix"
|
|
62
|
+
]
|
|
63
|
+
},
|
|
64
|
+
"publishConfig": {
|
|
65
|
+
"registry": "https://registry.npmjs.org"
|
|
66
|
+
},
|
|
67
|
+
"devDependencies": {
|
|
68
|
+
"@eslint/js": "^9.17.0",
|
|
69
|
+
"eslint": "^9.17.0",
|
|
70
|
+
"jiti": "^2.6.1",
|
|
71
|
+
"lint-staged": "^15.2.11",
|
|
72
|
+
"simple-git-hooks": "^2.12.1",
|
|
73
|
+
"typescript": "^5.9.3",
|
|
74
|
+
"typescript-eslint": "^8.18.1",
|
|
75
|
+
"vitest": "^4.0.15"
|
|
76
|
+
}
|
|
77
|
+
}
|