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.
- package/README.md +154 -301
- package/lib/core/corePartialMatchRegExp.d.ts +24 -0
- package/lib/core/corePartialMatchRegExp.js +22 -0
- package/lib/core/index.d.ts +4 -0
- package/lib/core/index.js +2 -0
- package/lib/extend/index.d.ts +6 -7
- package/lib/extend/index.js +1 -1
- package/lib/features/index.d.ts +20 -0
- package/lib/features/index.js +23 -0
- package/lib/hitEnd/index.d.ts +45 -0
- package/lib/hitEnd/index.js +57 -0
- package/lib/hitEnd/matchHitEnd.d.ts +4 -0
- package/lib/hitEnd/matchHitEnd.js +51 -0
- package/lib/{partialMatchRegExp/isComplete → hitEnd}/partRole.d.ts +1 -1
- package/lib/hitEnd/partRole.js +17 -0
- package/lib/hitEnd/truncationProbe.d.ts +8 -0
- package/lib/hitEnd/truncationProbe.js +187 -0
- package/lib/hitEnd/truncationProbeCache.d.ts +14 -0
- package/lib/index.d.ts +4 -0
- package/lib/index.js +4 -0
- package/lib/modules/backreferences/asNativeAtom.d.ts +2 -0
- package/lib/{partialMatchRegExp/compilePartial → modules/backreferences}/asNativeAtom.js +2 -2
- package/lib/modules/backreferences/asPreScanPart.d.ts +2 -0
- package/lib/{partialMatchRegExp/compilePartial → modules/backreferences}/asPreScanPart.js +2 -2
- package/lib/modules/backreferences/backreferenceRecorder.d.ts +2 -0
- package/lib/modules/backreferences/backreferenceRecorder.js +38 -0
- package/lib/modules/backreferences/compileDynamic.d.ts +4 -0
- package/lib/modules/backreferences/compileDynamic.js +53 -0
- package/lib/modules/backreferences/compiledBackreferences.d.ts +9 -0
- package/lib/modules/backreferences/compiledBackreferences.js +9 -0
- package/lib/modules/backreferences/constants.d.ts +2 -0
- package/lib/modules/backreferences/constants.js +2 -0
- package/lib/modules/backreferences/execDynamic.d.ts +2 -0
- package/lib/modules/backreferences/execDynamic.js +43 -0
- package/lib/{partialMatchRegExp/compilePartial → modules/backreferences}/flagsAtBackreference.d.ts +1 -1
- package/lib/{partialMatchRegExp → modules/backreferences}/groupName.js +1 -1
- package/lib/modules/backreferences/index.d.ts +10 -0
- package/lib/modules/backreferences/index.js +20 -0
- package/lib/modules/backreferences/longestBakedPrefixEndingInput.js +46 -0
- package/lib/{partialMatchRegExp/compilePartial → modules/backreferences}/renderParts.d.ts +1 -1
- package/lib/{partialMatchRegExp/compilePartial → modules/backreferences}/renderParts.js +1 -1
- package/lib/{partialMatchRegExp/compilePartial → modules/backreferences}/resolvedFromScan.d.ts +1 -1
- package/lib/{partialMatchRegExp/compilePartial → modules/backreferences}/resolvedFromScan.js +2 -2
- package/lib/{partialMatchRegExp/compilePartial → modules/backreferences}/startsWithUnderFlags.js +1 -1
- package/lib/modules/carets/appendMultilineCaret.d.ts +7 -0
- package/lib/modules/carets/appendMultilineCaret.js +181 -0
- package/lib/modules/carets/caretRecorder.d.ts +2 -0
- package/lib/modules/carets/caretRecorder.js +164 -0
- package/lib/modules/carets/caretSyntax.d.ts +3 -0
- package/lib/modules/carets/caretSyntax.js +11 -0
- package/lib/modules/carets/index.d.ts +9 -0
- package/lib/modules/carets/index.js +18 -0
- package/lib/modules/carets/lineTerminator.d.ts +1 -0
- package/lib/modules/carets/lineTerminator.js +31 -0
- package/lib/modules/carets/needsCaretRules.d.ts +1 -0
- package/lib/modules/carets/needsCaretRules.js +15 -0
- package/lib/modules/carets/quantifierBounds.d.ts +3 -0
- package/lib/modules/carets/quantifierBounds.js +18 -0
- package/lib/modules/index.d.ts +3 -0
- package/lib/modules/index.js +2 -0
- package/lib/partialMatchRegExp/atomSyntax.d.ts +14 -1
- package/lib/partialMatchRegExp/atomSyntax.js +24 -1
- package/lib/partialMatchRegExp/backreferenceExpansion.d.ts +1 -6
- package/lib/partialMatchRegExp/backreferenceHook.d.ts +11 -0
- package/lib/partialMatchRegExp/backreferenceHook.js +1 -0
- package/lib/partialMatchRegExp/caretHook.d.ts +17 -0
- package/lib/partialMatchRegExp/caretHook.js +5 -0
- package/lib/partialMatchRegExp/compilePartial/compileWith.d.ts +3 -0
- package/lib/partialMatchRegExp/compilePartial/compileWith.js +36 -0
- package/lib/partialMatchRegExp/compilePartial/compiled.d.ts +17 -17
- package/lib/partialMatchRegExp/compilePartial/compiled.js +8 -21
- package/lib/partialMatchRegExp/compilePartial/constants.d.ts +4 -0
- package/lib/partialMatchRegExp/compilePartial/constants.js +4 -0
- package/lib/partialMatchRegExp/compilePartial/groupShape.d.ts +4 -0
- package/lib/partialMatchRegExp/compilePartial/groupShape.js +9 -0
- package/lib/partialMatchRegExp/compilePartial/toStatic.d.ts +2 -2
- package/lib/partialMatchRegExp/compilePartial/toStatic.js +2 -2
- package/lib/partialMatchRegExp/constants.d.ts +5 -0
- package/lib/partialMatchRegExp/constants.js +5 -0
- package/lib/partialMatchRegExp/createPartialMatchRegExp.d.ts +3 -0
- package/lib/partialMatchRegExp/createPartialMatchRegExp.js +21 -0
- package/lib/partialMatchRegExp/execFrom.d.ts +1 -0
- package/lib/partialMatchRegExp/execFrom.js +4 -0
- package/lib/partialMatchRegExp/index.d.ts +49 -3
- package/lib/partialMatchRegExp/index.js +31 -3
- package/lib/partialMatchRegExp/moduleHooks.d.ts +14 -0
- package/lib/partialMatchRegExp/moduleHooks.js +15 -0
- package/lib/partialMatchRegExp/opaqueModule.d.ts +9 -0
- package/lib/partialMatchRegExp/opaqueModule.js +1 -0
- package/lib/partialMatchRegExp/part.d.ts +2 -11
- package/lib/partialMatchRegExp/partialMatchInternals.d.ts +2 -1
- package/lib/partialMatchRegExp/partialMatchInternals.js +3 -1
- package/lib/partialMatchRegExp/quantifier.d.ts +6 -0
- package/lib/partialMatchRegExp/quantifier.js +9 -0
- package/lib/partialMatchRegExp/rawLookaroundInfo.d.ts +11 -0
- package/lib/partialMatchRegExp/rawLookaroundInfo.js +1 -0
- package/lib/partialMatchRegExp/regexFeatures.d.ts +1 -5
- package/lib/partialMatchRegExp/regexFeatures.js +2 -8
- package/lib/partialMatchRegExp/scope.d.ts +12 -0
- package/lib/partialMatchRegExp/scope.js +45 -0
- package/lib/partialMatchRegExp/walk.d.ts +13 -5
- package/lib/partialMatchRegExp/walk.js +211 -165
- package/lib/partialMatchRegExp/withModules.d.ts +13 -0
- package/lib/partialMatchRegExp/withModules.js +27 -0
- package/package.json +39 -56
- package/lib/partialMatchRegExp/compilePartial/asNativeAtom.d.ts +0 -2
- package/lib/partialMatchRegExp/compilePartial/asOptionalAtom.d.ts +0 -1
- package/lib/partialMatchRegExp/compilePartial/asOptionalAtom.js +0 -4
- package/lib/partialMatchRegExp/compilePartial/asPreScanPart.d.ts +0 -2
- package/lib/partialMatchRegExp/compilePartial/index.d.ts +0 -2
- package/lib/partialMatchRegExp/compilePartial/index.js +0 -79
- package/lib/partialMatchRegExp/compilePartial/longestBakedPrefixEndingInput.js +0 -50
- package/lib/partialMatchRegExp/compilePartial/reclassifyLegacyEscapes.d.ts +0 -2
- package/lib/partialMatchRegExp/compilePartial/reclassifyLegacyEscapes.js +0 -17
- package/lib/partialMatchRegExp/compilePartial/spliceOriginalSource.d.ts +0 -2
- package/lib/partialMatchRegExp/compilePartial/spliceOriginalSource.js +0 -12
- package/lib/partialMatchRegExp/isComplete/index.d.ts +0 -38
- package/lib/partialMatchRegExp/isComplete/index.js +0 -41
- package/lib/partialMatchRegExp/isComplete/isMatchComplete.d.ts +0 -3
- package/lib/partialMatchRegExp/isComplete/isMatchComplete.js +0 -14
- package/lib/partialMatchRegExp/isComplete/partRole.js +0 -28
- package/lib/partialMatchRegExp/isComplete/truncationProbe.d.ts +0 -8
- package/lib/partialMatchRegExp/isComplete/truncationProbe.js +0 -105
- package/lib/partialMatchRegExp/isComplete/truncationProbeCache.d.ts +0 -4
- package/lib/partialMatchRegExp/partialMatchRegExp.d.ts +0 -55
- package/lib/partialMatchRegExp/partialMatchRegExp.js +0 -114
- package/lib/partialMatchRegExp/preferLongerCaptures.d.ts +0 -1
- package/lib/partialMatchRegExp/preferLongerCaptures.js +0 -30
- /package/lib/{partialMatchRegExp/isComplete → hitEnd}/truncationProbeCache.js +0 -0
- /package/lib/{partialMatchRegExp/compilePartial → modules/backreferences}/caseFoldFlags.d.ts +0 -0
- /package/lib/{partialMatchRegExp/compilePartial → modules/backreferences}/caseFoldFlags.js +0 -0
- /package/lib/{partialMatchRegExp → modules/backreferences}/escapeAtom.d.ts +0 -0
- /package/lib/{partialMatchRegExp → modules/backreferences}/escapeAtom.js +0 -0
- /package/lib/{partialMatchRegExp/compilePartial → modules/backreferences}/flagsAtBackreference.js +0 -0
- /package/lib/{partialMatchRegExp → modules/backreferences}/groupName.d.ts +0 -0
- /package/lib/{partialMatchRegExp/compilePartial → modules/backreferences}/longestBakedPrefixEndingInput.d.ts +0 -0
- /package/lib/{partialMatchRegExp/compilePartial → modules/backreferences}/startsWithUnderFlags.d.ts +0 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { PartialMatchRegExpConstructor } from "../partialMatchRegExp/index.ts";
|
|
2
|
+
/**
|
|
3
|
+
* `PartialMatchRegExp` without the rules that place a `^` in a group or after
|
|
4
|
+
* other parts under the `m` flag, or match a backreference, so that a bundle
|
|
5
|
+
* importing only `regex-partial-match/core` leaves them out.
|
|
6
|
+
*
|
|
7
|
+
* A pattern that needs either throws one `TypeError` naming every module it
|
|
8
|
+
* needs; every other pattern is transformed exactly as the class exported
|
|
9
|
+
* from `regex-partial-match` transforms it.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* import PartialMatchRegExp from "regex-partial-match/core";
|
|
14
|
+
*
|
|
15
|
+
* new PartialMatchRegExp(/^hello world/).test("hello"); // true
|
|
16
|
+
* new PartialMatchRegExp(/(a)\1/); // throws TypeError
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* @see {@link https://github.com/TomStrepsil/regex-partial-match#readme | Documentation}
|
|
20
|
+
*/
|
|
21
|
+
declare const PartialMatchRegExp: PartialMatchRegExpConstructor;
|
|
22
|
+
type PartialMatchRegExp = InstanceType<typeof PartialMatchRegExp>;
|
|
23
|
+
export default PartialMatchRegExp;
|
|
24
|
+
export type { PartialMatchRegExp, PartialMatchRegExpConstructor };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import withModules from "../partialMatchRegExp/withModules.js";
|
|
2
|
+
/**
|
|
3
|
+
* `PartialMatchRegExp` without the rules that place a `^` in a group or after
|
|
4
|
+
* other parts under the `m` flag, or match a backreference, so that a bundle
|
|
5
|
+
* importing only `regex-partial-match/core` leaves them out.
|
|
6
|
+
*
|
|
7
|
+
* A pattern that needs either throws one `TypeError` naming every module it
|
|
8
|
+
* needs; every other pattern is transformed exactly as the class exported
|
|
9
|
+
* from `regex-partial-match` transforms it.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* import PartialMatchRegExp from "regex-partial-match/core";
|
|
14
|
+
*
|
|
15
|
+
* new PartialMatchRegExp(/^hello world/).test("hello"); // true
|
|
16
|
+
* new PartialMatchRegExp(/(a)\1/); // throws TypeError
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* @see {@link https://github.com/TomStrepsil/regex-partial-match#readme | Documentation}
|
|
20
|
+
*/
|
|
21
|
+
const PartialMatchRegExp = withModules();
|
|
22
|
+
export default PartialMatchRegExp;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { default } from "./corePartialMatchRegExp.ts";
|
|
2
|
+
export type { PartialMatchRegExp, PartialMatchRegExpConstructor } from "./corePartialMatchRegExp.ts";
|
|
3
|
+
export { default as withModules } from "../partialMatchRegExp/withModules.ts";
|
|
4
|
+
export type { Module } from "../partialMatchRegExp/opaqueModule.ts";
|
package/lib/extend/index.d.ts
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import PartialMatchRegExp from "../partialMatchRegExp/
|
|
1
|
+
import PartialMatchRegExp from "../partialMatchRegExp/index.ts";
|
|
2
2
|
declare global {
|
|
3
3
|
interface RegExp {
|
|
4
4
|
/**
|
|
5
5
|
* Transforms this regular expression to support partial matching.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* of the original pattern. This enables validation of incomplete input strings.
|
|
7
|
+
* The result matches any prefix of the original pattern, which enables
|
|
8
|
+
* validation of incomplete input strings.
|
|
10
9
|
*
|
|
11
10
|
* @returns A new PartialMatchRegExp that matches partial strings of the original pattern
|
|
12
11
|
*
|
|
@@ -23,9 +22,9 @@ declare global {
|
|
|
23
22
|
* ```
|
|
24
23
|
*
|
|
25
24
|
* @remarks
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
25
|
+
* The transformed pattern always matches an empty string at the end of input;
|
|
26
|
+
* use a start anchor (`^`) to prevent false positives from empty string matches.
|
|
27
|
+
* See the documentation for how the `y` (sticky) flag behaves.
|
|
29
28
|
*
|
|
30
29
|
* @see {@link https://github.com/TomStrepsil/regex-partial-match#readme | Documentation}
|
|
31
30
|
*/
|
package/lib/extend/index.js
CHANGED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type PartialMatchRegExp from "../partialMatchRegExp/index.ts";
|
|
2
|
+
import { type RegexFeature } from "../partialMatchRegExp/regexFeatures.ts";
|
|
3
|
+
export type { RegexFeature };
|
|
4
|
+
/**
|
|
5
|
+
* The syntactic constructs `partial`'s original pattern uses.
|
|
6
|
+
*
|
|
7
|
+
* The set iterates in `RegexFeature` declaration order, not the order the
|
|
8
|
+
* constructs appear in the pattern.
|
|
9
|
+
*
|
|
10
|
+
* @param partial - A `PartialMatchRegExp` instance, from any entry point
|
|
11
|
+
* @returns The features the original pattern contains
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* import PartialMatchRegExp, { features } from "regex-partial-match";
|
|
16
|
+
*
|
|
17
|
+
* features(new PartialMatchRegExp(/^[a-z]+/)).has("startAnchor"); // true
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export default function features(partial: PartialMatchRegExp): ReadonlySet<RegexFeature>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { compiledOf } from "../partialMatchRegExp/partialMatchInternals.js";
|
|
2
|
+
import { featureSet } from "../partialMatchRegExp/regexFeatures.js";
|
|
3
|
+
/**
|
|
4
|
+
* The syntactic constructs `partial`'s original pattern uses.
|
|
5
|
+
*
|
|
6
|
+
* The set iterates in `RegexFeature` declaration order, not the order the
|
|
7
|
+
* constructs appear in the pattern.
|
|
8
|
+
*
|
|
9
|
+
* @param partial - A `PartialMatchRegExp` instance, from any entry point
|
|
10
|
+
* @returns The features the original pattern contains
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* import PartialMatchRegExp, { features } from "regex-partial-match";
|
|
15
|
+
*
|
|
16
|
+
* features(new PartialMatchRegExp(/^[a-z]+/)).has("startAnchor"); // true
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export default function features(partial) {
|
|
20
|
+
var _a;
|
|
21
|
+
const compiled = compiledOf(partial);
|
|
22
|
+
return ((_a = compiled.features) !== null && _a !== void 0 ? _a : (compiled.features = featureSet(compiled.featureMask)));
|
|
23
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type PartialMatchRegExp from "../partialMatchRegExp/index.ts";
|
|
2
|
+
/**
|
|
3
|
+
* Whether the engine reached the end of the input while producing `match` —
|
|
4
|
+
* a match `partial` produced — so that more input could change it.
|
|
5
|
+
*
|
|
6
|
+
* The contract is that of the JDK's `Matcher.hitEnd()`: when this returns
|
|
7
|
+
* `false`, no continuation of the input changes the match's index or text,
|
|
8
|
+
* and its captures are the ones the original pattern produces, except for
|
|
9
|
+
* the two limits noted under `@remarks` below, where `false` is reported
|
|
10
|
+
* despite a read of the end. `true` means the match read the end of the
|
|
11
|
+
* input — an atom ran out of input, a greedy quantifier stopped there with
|
|
12
|
+
* nothing left to read, or `$`, `\b` or `\B` held there — so more input
|
|
13
|
+
* could extend it, change which alternative wins, or invalidate it, and
|
|
14
|
+
* its captures are the closest to what a full match would report rather
|
|
15
|
+
* than final.
|
|
16
|
+
*
|
|
17
|
+
* `false` is not "is a match": `/hello \w+/` matches `"hello world"` in full
|
|
18
|
+
* and still reports `true`, since `\w+` read the end looking for more. An
|
|
19
|
+
* exact-length match that consumed the last character without reading past
|
|
20
|
+
* it reports `false`.
|
|
21
|
+
*
|
|
22
|
+
* @param partial - The `PartialMatchRegExp` instance that produced `match`
|
|
23
|
+
* @param match - A match returned by `partial.exec()`
|
|
24
|
+
* @returns `true` when the match read the end of the input, `false` when it
|
|
25
|
+
* settled short of it
|
|
26
|
+
*
|
|
27
|
+
* @remarks
|
|
28
|
+
* Conservative where the JDK is exact in one place: a bounded greedy
|
|
29
|
+
* quantifier (`?`, `{n,m}`) fully taken at the end of the input reports
|
|
30
|
+
* `true` — on a group, and the same way for an unequal-bound `{n,m}`
|
|
31
|
+
* directly on a single atom once it's saturated at its maximum. Cannot see
|
|
32
|
+
* a read of the end inside a raw lookaround, or inside a lookahead in an
|
|
33
|
+
* earlier iteration of a quantified group.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* import PartialMatchRegExp, { hitEnd } from "regex-partial-match";
|
|
38
|
+
*
|
|
39
|
+
* const partial = new PartialMatchRegExp(/^\d{4}-\d{2}-\d{2}/);
|
|
40
|
+
* const match = partial.exec('2024-06');
|
|
41
|
+
*
|
|
42
|
+
* match !== null && hitEnd(partial, match); // true - keep typing
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export default function hitEnd(partial: PartialMatchRegExp, match: RegExpExecArray): boolean;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { compiledOf } from "../partialMatchRegExp/partialMatchInternals.js";
|
|
2
|
+
import matchHitEnd from "./matchHitEnd.js";
|
|
3
|
+
/**
|
|
4
|
+
* Whether the engine reached the end of the input while producing `match` —
|
|
5
|
+
* a match `partial` produced — so that more input could change it.
|
|
6
|
+
*
|
|
7
|
+
* The contract is that of the JDK's `Matcher.hitEnd()`: when this returns
|
|
8
|
+
* `false`, no continuation of the input changes the match's index or text,
|
|
9
|
+
* and its captures are the ones the original pattern produces, except for
|
|
10
|
+
* the two limits noted under `@remarks` below, where `false` is reported
|
|
11
|
+
* despite a read of the end. `true` means the match read the end of the
|
|
12
|
+
* input — an atom ran out of input, a greedy quantifier stopped there with
|
|
13
|
+
* nothing left to read, or `$`, `\b` or `\B` held there — so more input
|
|
14
|
+
* could extend it, change which alternative wins, or invalidate it, and
|
|
15
|
+
* its captures are the closest to what a full match would report rather
|
|
16
|
+
* than final.
|
|
17
|
+
*
|
|
18
|
+
* `false` is not "is a match": `/hello \w+/` matches `"hello world"` in full
|
|
19
|
+
* and still reports `true`, since `\w+` read the end looking for more. An
|
|
20
|
+
* exact-length match that consumed the last character without reading past
|
|
21
|
+
* it reports `false`.
|
|
22
|
+
*
|
|
23
|
+
* @param partial - The `PartialMatchRegExp` instance that produced `match`
|
|
24
|
+
* @param match - A match returned by `partial.exec()`
|
|
25
|
+
* @returns `true` when the match read the end of the input, `false` when it
|
|
26
|
+
* settled short of it
|
|
27
|
+
*
|
|
28
|
+
* @remarks
|
|
29
|
+
* Conservative where the JDK is exact in one place: a bounded greedy
|
|
30
|
+
* quantifier (`?`, `{n,m}`) fully taken at the end of the input reports
|
|
31
|
+
* `true` — on a group, and the same way for an unequal-bound `{n,m}`
|
|
32
|
+
* directly on a single atom once it's saturated at its maximum. Cannot see
|
|
33
|
+
* a read of the end inside a raw lookaround, or inside a lookahead in an
|
|
34
|
+
* earlier iteration of a quantified group.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```typescript
|
|
38
|
+
* import PartialMatchRegExp, { hitEnd } from "regex-partial-match";
|
|
39
|
+
*
|
|
40
|
+
* const partial = new PartialMatchRegExp(/^\d{4}-\d{2}-\d{2}/);
|
|
41
|
+
* const match = partial.exec('2024-06');
|
|
42
|
+
*
|
|
43
|
+
* match !== null && hitEnd(partial, match); // true - keep typing
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export default function hitEnd(partial, match) {
|
|
47
|
+
var _a, _b;
|
|
48
|
+
const compiled = compiledOf(partial);
|
|
49
|
+
return matchHitEnd(compiled, match, ((_a = compiled.probeCache) !== null && _a !== void 0 ? _a : (compiled.probeCache = {
|
|
50
|
+
rawLookarounds: (_b = compiled.rawLookarounds) !== null && _b !== void 0 ? _b : [],
|
|
51
|
+
flags: partial.flags,
|
|
52
|
+
probe: undefined,
|
|
53
|
+
stickyPreScan: undefined,
|
|
54
|
+
expansions: [],
|
|
55
|
+
oldestExpansion: 0
|
|
56
|
+
})));
|
|
57
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { CompiledPartial } from "../partialMatchRegExp/compilePartial/compiled.ts";
|
|
2
|
+
import type { TruncationProbeCache } from "./truncationProbeCache.ts";
|
|
3
|
+
export declare const EXPANDED_PROBES_KEPT = 12;
|
|
4
|
+
export default function matchHitEnd(compiled: CompiledPartial, match: RegExpExecArray, cache: TruncationProbeCache): boolean;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { buildTruncationProbe, tookTruncationBranch } from "./truncationProbe.js";
|
|
2
|
+
import { backreferenceExpansion } from "../partialMatchRegExp/backreferenceExpansion.js";
|
|
3
|
+
import { FLAGS_IRRELEVANT_TO_REBUILD } from "../partialMatchRegExp/constants.js";
|
|
4
|
+
export const EXPANDED_PROBES_KEPT = 12;
|
|
5
|
+
export default function matchHitEnd(compiled, match, cache) {
|
|
6
|
+
const probe = "dynamic" in compiled
|
|
7
|
+
? dynamicProbe(compiled, match, cache)
|
|
8
|
+
: unexpandedProbe(compiled, cache);
|
|
9
|
+
return tookTruncationBranch(probe, match.input, match.index);
|
|
10
|
+
}
|
|
11
|
+
function dynamicProbe(compiled, match, cache) {
|
|
12
|
+
var _a;
|
|
13
|
+
const parts = (_a = match[backreferenceExpansion]) !== null && _a !== void 0 ? _a : expandedPartsAt(compiled, match, cache);
|
|
14
|
+
if (parts === undefined)
|
|
15
|
+
return unexpandedProbe(compiled, cache);
|
|
16
|
+
for (const expansion of cache.expansions) {
|
|
17
|
+
if (sameParts(expansion.parts, parts))
|
|
18
|
+
return expansion.probe;
|
|
19
|
+
}
|
|
20
|
+
const probe = probeOf(parts, cache);
|
|
21
|
+
cache.expansions[cache.oldestExpansion] = { parts, probe };
|
|
22
|
+
cache.oldestExpansion = (cache.oldestExpansion + 1) % EXPANDED_PROBES_KEPT;
|
|
23
|
+
return probe;
|
|
24
|
+
}
|
|
25
|
+
function unexpandedProbe(compiled, cache) {
|
|
26
|
+
var _a;
|
|
27
|
+
return ((_a = cache.probe) !== null && _a !== void 0 ? _a : (cache.probe = probeOf(compiled.parts, cache)));
|
|
28
|
+
}
|
|
29
|
+
function probeOf(parts, { rawLookarounds, flags }) {
|
|
30
|
+
return buildTruncationProbe(parts, rawLookarounds, flags);
|
|
31
|
+
}
|
|
32
|
+
function expandedPartsAt(compiled, match, cache) {
|
|
33
|
+
var _a;
|
|
34
|
+
const { preScan, expand } = compiled.dynamic;
|
|
35
|
+
(_a = cache.stickyPreScan) !== null && _a !== void 0 ? _a : (cache.stickyPreScan = new RegExp(preScan.source, cache.flags.replace(FLAGS_IRRELEVANT_TO_REBUILD, "") + "y"));
|
|
36
|
+
cache.stickyPreScan.lastIndex = match.index;
|
|
37
|
+
const capture = cache.stickyPreScan.exec(match.input);
|
|
38
|
+
if (capture === null)
|
|
39
|
+
return undefined;
|
|
40
|
+
const parts = expand(capture);
|
|
41
|
+
return parts.length === compiled.parts.length ? undefined : parts;
|
|
42
|
+
}
|
|
43
|
+
function sameParts(cached, parts) {
|
|
44
|
+
if (cached.length !== parts.length)
|
|
45
|
+
return false;
|
|
46
|
+
for (let index = 0; index < parts.length; index++) {
|
|
47
|
+
if (cached[index] !== parts[index])
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { NAMED_GROUP_OPENING, endsAtTruncationBranch, isRawLookaround } from "../partialMatchRegExp/atomSyntax.js";
|
|
2
|
+
import { isBackreference } from "../partialMatchRegExp/part.js";
|
|
3
|
+
function isGroupOpen(part) {
|
|
4
|
+
return (part === "(" ||
|
|
5
|
+
(part.startsWith(NAMED_GROUP_OPENING) && !isRawLookaround(part)));
|
|
6
|
+
}
|
|
7
|
+
export function roleOf(part) {
|
|
8
|
+
if (isBackreference(part))
|
|
9
|
+
return "backreference";
|
|
10
|
+
if (isRawLookaround(part))
|
|
11
|
+
return "rawLookaround";
|
|
12
|
+
if (isGroupOpen(part))
|
|
13
|
+
return "groupOpen";
|
|
14
|
+
if (endsAtTruncationBranch(part))
|
|
15
|
+
return "truncationEnd";
|
|
16
|
+
return "plain";
|
|
17
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type Part } from "../partialMatchRegExp/part.ts";
|
|
2
|
+
import type { RawLookarounds } from "../partialMatchRegExp/rawLookaroundInfo.ts";
|
|
3
|
+
export interface TruncationProbe {
|
|
4
|
+
regex: RegExp;
|
|
5
|
+
markerGroups: readonly number[];
|
|
6
|
+
}
|
|
7
|
+
export declare const buildTruncationProbe: (parts: readonly Part[], rawLookarounds: RawLookarounds, flags: string) => TruncationProbe;
|
|
8
|
+
export declare const tookTruncationBranch: (probe: TruncationProbe, input: string, index: number) => boolean;
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { legacyEscapeAsLiteral } from "../partialMatchRegExp/legacyEscape.js";
|
|
2
|
+
import { FLAGS_IRRELEVANT_TO_REBUILD } from "../partialMatchRegExp/constants.js";
|
|
3
|
+
import { DISJUNCTION_TO_END_OF_INPUT, END_ANCHOR, OPTIONAL_ATOM_OPENING, isOptionalAtom, isWordBoundaryAtom } from "../partialMatchRegExp/atomSyntax.js";
|
|
4
|
+
import { isQuantifier, quantifierEndingAt } from "../partialMatchRegExp/quantifier.js";
|
|
5
|
+
import { isBackreference, isNumericBackreference } from "../partialMatchRegExp/part.js";
|
|
6
|
+
import { roleOf } from "./partRole.js";
|
|
7
|
+
const END_OF_INPUT = DISJUNCTION_TO_END_OF_INPUT.slice(1, -1);
|
|
8
|
+
const OPTIONAL_QUANTIFIER = "?";
|
|
9
|
+
const EXACT_QUANTIFIER = /^\{0*([1-9]\d*|0)(?:,0*\1)?\}$/;
|
|
10
|
+
const MARKING = {
|
|
11
|
+
none: 0,
|
|
12
|
+
groupOpen: 1,
|
|
13
|
+
rawLookaround: 2,
|
|
14
|
+
truncationBranch: 3,
|
|
15
|
+
wordBoundary: 4,
|
|
16
|
+
endAnchor: 5,
|
|
17
|
+
readAtEnd: 6,
|
|
18
|
+
optionalAtEnd: 7
|
|
19
|
+
};
|
|
20
|
+
function isGreedyReadAtEnd(parts, index) {
|
|
21
|
+
const part = parts[index];
|
|
22
|
+
return (isQuantifier(part) &&
|
|
23
|
+
!EXACT_QUANTIFIER.test(part) &&
|
|
24
|
+
parts[index + 1] !== OPTIONAL_QUANTIFIER &&
|
|
25
|
+
quantifierEndingAt(parts, index) === index);
|
|
26
|
+
}
|
|
27
|
+
function markingOf(parts, index) {
|
|
28
|
+
const part = parts[index];
|
|
29
|
+
switch (roleOf(part)) {
|
|
30
|
+
case "backreference":
|
|
31
|
+
return MARKING.truncationBranch;
|
|
32
|
+
case "rawLookaround":
|
|
33
|
+
return MARKING.rawLookaround;
|
|
34
|
+
case "groupOpen":
|
|
35
|
+
return MARKING.groupOpen;
|
|
36
|
+
case "truncationEnd":
|
|
37
|
+
return isWordBoundaryAtom(part)
|
|
38
|
+
? MARKING.wordBoundary
|
|
39
|
+
: MARKING.truncationBranch;
|
|
40
|
+
case "plain": {
|
|
41
|
+
if (part === END_ANCHOR)
|
|
42
|
+
return MARKING.endAnchor;
|
|
43
|
+
if (!isGreedyReadAtEnd(parts, index))
|
|
44
|
+
return MARKING.none;
|
|
45
|
+
const previous = parts[index - 1];
|
|
46
|
+
return part === OPTIONAL_QUANTIFIER &&
|
|
47
|
+
(isBackreference(previous) || isOptionalAtom(previous))
|
|
48
|
+
? MARKING.optionalAtEnd
|
|
49
|
+
: MARKING.readAtEnd;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const markingsOf = (parts) => parts.map((_, index) => markingOf(parts, index));
|
|
54
|
+
function markersAddedBy(marking) {
|
|
55
|
+
switch (marking) {
|
|
56
|
+
case MARKING.none:
|
|
57
|
+
case MARKING.groupOpen:
|
|
58
|
+
case MARKING.rawLookaround:
|
|
59
|
+
return 0;
|
|
60
|
+
case MARKING.wordBoundary:
|
|
61
|
+
return 2;
|
|
62
|
+
default:
|
|
63
|
+
return 1;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function groupShiftTable(markings, rawLookarounds) {
|
|
67
|
+
var _a, _b;
|
|
68
|
+
const shiftForGroup = [0];
|
|
69
|
+
let markerCount = 0;
|
|
70
|
+
let rawLookaroundIndex = 0;
|
|
71
|
+
for (const marking of markings) {
|
|
72
|
+
if (marking === MARKING.groupOpen) {
|
|
73
|
+
shiftForGroup.push(markerCount);
|
|
74
|
+
}
|
|
75
|
+
else if (marking === MARKING.rawLookaround) {
|
|
76
|
+
const capturingGroupsOpened = (_b = (_a = rawLookarounds[rawLookaroundIndex++]) === null || _a === void 0 ? void 0 : _a.capturingGroupsOpened) !== null && _b !== void 0 ? _b : 0;
|
|
77
|
+
for (let opened = 0; opened < capturingGroupsOpened; opened++) {
|
|
78
|
+
shiftForGroup.push(markerCount);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
markerCount += markersAddedBy(marking);
|
|
82
|
+
}
|
|
83
|
+
return shiftForGroup;
|
|
84
|
+
}
|
|
85
|
+
function renumberedToken(backreference, shiftForGroup) {
|
|
86
|
+
return isNumericBackreference(backreference)
|
|
87
|
+
? "\\" + String(backreference.ref + shiftForGroup[backreference.ref])
|
|
88
|
+
: "\\k<" + backreference.ref + ">";
|
|
89
|
+
}
|
|
90
|
+
function renumberRawBackreferences(part, info, shiftForGroup) {
|
|
91
|
+
let renumbered = "";
|
|
92
|
+
let cursor = 0;
|
|
93
|
+
for (const reference of info.references) {
|
|
94
|
+
const relativeStart = reference.start - info.sourceStart;
|
|
95
|
+
const relativeEnd = reference.end - info.sourceStart;
|
|
96
|
+
renumbered +=
|
|
97
|
+
part.slice(cursor, relativeStart) +
|
|
98
|
+
rawReferenceReplacement(part.slice(relativeStart, relativeEnd), reference, shiftForGroup);
|
|
99
|
+
cursor = relativeEnd;
|
|
100
|
+
}
|
|
101
|
+
return renumbered + part.slice(cursor);
|
|
102
|
+
}
|
|
103
|
+
function rawReferenceReplacement(spelling, { ref }, shiftForGroup) {
|
|
104
|
+
return ref >= 1 && ref < shiftForGroup.length
|
|
105
|
+
? "\\" + String(ref + shiftForGroup[ref])
|
|
106
|
+
: legacyEscapeAsLiteral(spelling.slice(1));
|
|
107
|
+
}
|
|
108
|
+
export const buildTruncationProbe = (parts, rawLookarounds, flags) => {
|
|
109
|
+
var _a;
|
|
110
|
+
const markings = markingsOf(parts);
|
|
111
|
+
const shiftForGroup = groupShiftTable(markings, rawLookarounds);
|
|
112
|
+
const markerGroups = [];
|
|
113
|
+
let groupsOpened = 0;
|
|
114
|
+
let rawLookaroundIndex = 0;
|
|
115
|
+
const marker = () => {
|
|
116
|
+
markerGroups.push(groupsOpened + markerGroups.length + 1);
|
|
117
|
+
return "()";
|
|
118
|
+
};
|
|
119
|
+
const truncationBranch = () => "|" + marker() + END_OF_INPUT + ")";
|
|
120
|
+
const readAtEnd = () => "(?:" + marker() + END_OF_INPUT + "|)";
|
|
121
|
+
const probed = [];
|
|
122
|
+
for (let index = 0; index < parts.length; index++) {
|
|
123
|
+
const part = parts[index];
|
|
124
|
+
if (isBackreference(part)) {
|
|
125
|
+
probed.push(OPTIONAL_ATOM_OPENING +
|
|
126
|
+
renumberedToken(part, shiftForGroup) +
|
|
127
|
+
truncationBranch());
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
switch (markings[index]) {
|
|
131
|
+
case MARKING.rawLookaround: {
|
|
132
|
+
const rawLookaround = rawLookarounds[rawLookaroundIndex++];
|
|
133
|
+
groupsOpened += (_a = rawLookaround === null || rawLookaround === void 0 ? void 0 : rawLookaround.capturingGroupsOpened) !== null && _a !== void 0 ? _a : 0;
|
|
134
|
+
probed.push(rawLookaround
|
|
135
|
+
? renumberRawBackreferences(part, rawLookaround, shiftForGroup)
|
|
136
|
+
: part);
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
case MARKING.groupOpen:
|
|
140
|
+
groupsOpened++;
|
|
141
|
+
probed.push(part);
|
|
142
|
+
break;
|
|
143
|
+
case MARKING.truncationBranch:
|
|
144
|
+
probed.push(part.slice(0, -DISJUNCTION_TO_END_OF_INPUT.length) + truncationBranch());
|
|
145
|
+
break;
|
|
146
|
+
case MARKING.wordBoundary:
|
|
147
|
+
probed.push(part.slice(0, -DISJUNCTION_TO_END_OF_INPUT.length) +
|
|
148
|
+
readAtEnd() +
|
|
149
|
+
truncationBranch());
|
|
150
|
+
break;
|
|
151
|
+
case MARKING.endAnchor:
|
|
152
|
+
probed.push(END_ANCHOR + "(?:" + marker() + "(?![\\s\\S])|)");
|
|
153
|
+
break;
|
|
154
|
+
case MARKING.readAtEnd:
|
|
155
|
+
probed.push(part + readAtEnd());
|
|
156
|
+
break;
|
|
157
|
+
case MARKING.optionalAtEnd:
|
|
158
|
+
probed[probed.length - 1] =
|
|
159
|
+
OPTIONAL_ATOM_OPENING +
|
|
160
|
+
probed[probed.length - 1] +
|
|
161
|
+
"|" +
|
|
162
|
+
marker() +
|
|
163
|
+
END_OF_INPUT +
|
|
164
|
+
"|)";
|
|
165
|
+
break;
|
|
166
|
+
default:
|
|
167
|
+
probed.push(part);
|
|
168
|
+
break;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return {
|
|
172
|
+
regex: new RegExp(probed.join(""), flags.replace(FLAGS_IRRELEVANT_TO_REBUILD, "") + "y"),
|
|
173
|
+
markerGroups
|
|
174
|
+
};
|
|
175
|
+
};
|
|
176
|
+
export const tookTruncationBranch = (probe, input, index) => {
|
|
177
|
+
const { regex, markerGroups } = probe;
|
|
178
|
+
regex.lastIndex = index;
|
|
179
|
+
const probed = regex.exec(input);
|
|
180
|
+
if (probed === null)
|
|
181
|
+
return true;
|
|
182
|
+
for (const group of markerGroups) {
|
|
183
|
+
if (probed[group] !== undefined)
|
|
184
|
+
return true;
|
|
185
|
+
}
|
|
186
|
+
return false;
|
|
187
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Part } from "../partialMatchRegExp/part.ts";
|
|
2
|
+
import type { RawLookarounds } from "../partialMatchRegExp/rawLookaroundInfo.ts";
|
|
3
|
+
import type { TruncationProbe } from "./truncationProbe.ts";
|
|
4
|
+
export interface TruncationProbeCache {
|
|
5
|
+
rawLookarounds: RawLookarounds;
|
|
6
|
+
flags: string;
|
|
7
|
+
probe: TruncationProbe | undefined;
|
|
8
|
+
stickyPreScan: RegExp | undefined;
|
|
9
|
+
expansions: {
|
|
10
|
+
parts: readonly Part[];
|
|
11
|
+
probe: TruncationProbe;
|
|
12
|
+
}[];
|
|
13
|
+
oldestExpansion: number;
|
|
14
|
+
}
|
package/lib/index.d.ts
ADDED
package/lib/index.js
ADDED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { isNumericBackreference } from "
|
|
2
|
-
import asOptionalAtom from "
|
|
1
|
+
import { isNumericBackreference } from "../../partialMatchRegExp/part.js";
|
|
2
|
+
import { asOptionalAtom } from "../../partialMatchRegExp/atomSyntax.js";
|
|
3
3
|
function backrefToken(backref) {
|
|
4
4
|
return isNumericBackreference(backref)
|
|
5
5
|
? "\\" + String(backref.ref)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ANY_CAPTURED_TEXT } from "
|
|
2
|
-
import { isBackreference } from "
|
|
1
|
+
import { ANY_CAPTURED_TEXT } from "./constants.js";
|
|
2
|
+
import { isBackreference } from "../../partialMatchRegExp/part.js";
|
|
3
3
|
import asNativeAtom from "./asNativeAtom.js";
|
|
4
4
|
export default function asPreScanPart(part) {
|
|
5
5
|
if (!isBackreference(part))
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { decodeGroupName, groupNameOf } from "./groupName.js";
|
|
2
|
+
import { isNumericBackreference } from "../../partialMatchRegExp/part.js";
|
|
3
|
+
import { CASE_INSENSITIVE } from "../../partialMatchRegExp/scope.js";
|
|
4
|
+
const UNNAMED_GROUP_OPENING = "(";
|
|
5
|
+
export default function backreferenceRecorder() {
|
|
6
|
+
let closedGroupNumbers;
|
|
7
|
+
let referencesSinceLastClose;
|
|
8
|
+
return {
|
|
9
|
+
groupClosed(groupNumber, opening) {
|
|
10
|
+
(closedGroupNumbers !== null && closedGroupNumbers !== void 0 ? closedGroupNumbers : (closedGroupNumbers = new Set())).add(groupNumber);
|
|
11
|
+
if (opening === UNNAMED_GROUP_OPENING)
|
|
12
|
+
return;
|
|
13
|
+
const name = decodeGroupName(groupNameOf(opening));
|
|
14
|
+
const earlierReferences = referencesSinceLastClose === null || referencesSinceLastClose === void 0 ? void 0 : referencesSinceLastClose.get(name);
|
|
15
|
+
if (earlierReferences === undefined)
|
|
16
|
+
return;
|
|
17
|
+
for (const earlier of earlierReferences)
|
|
18
|
+
earlier.forward = true;
|
|
19
|
+
referencesSinceLastClose === null || referencesSinceLastClose === void 0 ? void 0 : referencesSinceLastClose.delete(name);
|
|
20
|
+
},
|
|
21
|
+
backreference(backreference, scope) {
|
|
22
|
+
backreference.caseInsensitive = (scope & CASE_INSENSITIVE) !== 0;
|
|
23
|
+
if (isNumericBackreference(backreference)) {
|
|
24
|
+
backreference.forward = !(closedGroupNumbers === null || closedGroupNumbers === void 0 ? void 0 : closedGroupNumbers.has(backreference.ref));
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const name = decodeGroupName(backreference.ref);
|
|
28
|
+
backreference.forward = false;
|
|
29
|
+
referencesSinceLastClose !== null && referencesSinceLastClose !== void 0 ? referencesSinceLastClose : (referencesSinceLastClose = new Map());
|
|
30
|
+
const references = referencesSinceLastClose.get(name);
|
|
31
|
+
if (references === undefined) {
|
|
32
|
+
referencesSinceLastClose.set(name, [backreference]);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
references.push(backreference);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type Backreference, type Part } from "../../partialMatchRegExp/part.ts";
|
|
2
|
+
import type { Hooks } from "../../partialMatchRegExp/walk.ts";
|
|
3
|
+
import { CompiledBackreferences } from "./compiledBackreferences.ts";
|
|
4
|
+
export default function compileDynamic(parts: readonly Part[], backreferences: readonly Backreference[], flags: string, isUnicode: boolean, featureMask: number, hooks: Hooks): CompiledBackreferences;
|