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.
- package/README.md +169 -178
- 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.d.ts → extend/index.d.ts} +6 -7
- package/lib/{extend.js → 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/hitEnd/partRole.d.ts +3 -0
- 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/hitEnd/truncationProbeCache.js +1 -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/modules/backreferences/asNativeAtom.js +10 -0
- package/lib/modules/backreferences/asPreScanPart.d.ts +2 -0
- package/lib/modules/backreferences/asPreScanPart.js +8 -0
- package/lib/modules/backreferences/backreferenceRecorder.d.ts +2 -0
- package/lib/modules/backreferences/backreferenceRecorder.js +38 -0
- package/lib/modules/backreferences/caseFoldFlags.d.ts +1 -0
- package/lib/modules/backreferences/caseFoldFlags.js +3 -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/modules/backreferences/flagsAtBackreference.d.ts +2 -0
- package/lib/modules/backreferences/flagsAtBackreference.js +4 -0
- package/lib/modules/backreferences/groupName.d.ts +2 -0
- package/lib/modules/backreferences/groupName.js +8 -0
- package/lib/modules/backreferences/index.d.ts +10 -0
- package/lib/modules/backreferences/index.js +20 -0
- package/lib/modules/backreferences/longestBakedPrefixEndingInput.d.ts +1 -0
- package/lib/modules/backreferences/longestBakedPrefixEndingInput.js +46 -0
- package/lib/modules/backreferences/renderParts.d.ts +2 -0
- package/lib/modules/backreferences/renderParts.js +9 -0
- package/lib/modules/backreferences/resolvedFromScan.d.ts +2 -0
- package/lib/modules/backreferences/resolvedFromScan.js +10 -0
- package/lib/modules/backreferences/startsWithUnderFlags.d.ts +1 -0
- package/lib/modules/backreferences/startsWithUnderFlags.js +7 -0
- 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 +17 -0
- package/lib/partialMatchRegExp/atomSyntax.js +27 -0
- package/lib/partialMatchRegExp/backreferenceExpansion.d.ts +5 -0
- package/lib/partialMatchRegExp/backreferenceExpansion.js +1 -0
- 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 +29 -0
- package/lib/partialMatchRegExp/compilePartial/compiled.js +14 -0
- 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 +3 -0
- package/lib/partialMatchRegExp/compilePartial/toStatic.js +4 -0
- 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 -0
- package/lib/partialMatchRegExp/index.js +31 -0
- package/lib/partialMatchRegExp/legacyEscape.d.ts +2 -0
- package/lib/partialMatchRegExp/legacyEscape.js +18 -0
- 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 +15 -0
- package/lib/partialMatchRegExp/part.js +2 -0
- package/lib/partialMatchRegExp/partialMatchInternals.d.ts +3 -0
- package/lib/partialMatchRegExp/partialMatchInternals.js +4 -0
- 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 +2 -0
- package/lib/partialMatchRegExp/regexFeatures.js +41 -0
- package/lib/partialMatchRegExp/scope.d.ts +12 -0
- package/lib/partialMatchRegExp/scope.js +45 -0
- package/lib/partialMatchRegExp/walk.d.ts +16 -0
- package/lib/partialMatchRegExp/walk.js +412 -0
- package/lib/partialMatchRegExp/withModules.d.ts +13 -0
- package/lib/partialMatchRegExp/withModules.js +27 -0
- package/package.json +46 -53
- package/lib/compilePartial.d.ts +0 -26
- package/lib/compilePartial.js +0 -397
- package/lib/partialMatchRegExp.d.ts +0 -52
- package/lib/partialMatchRegExp.js +0 -126
- /package/lib/{escapeAtom.d.ts → modules/backreferences/escapeAtom.d.ts} +0 -0
- /package/lib/{escapeAtom.js → modules/backreferences/escapeAtom.js} +0 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export const START_ANCHOR = "^";
|
|
2
|
+
export const END_ANCHOR = "$";
|
|
3
|
+
export const GROUP_CLOSING = ")";
|
|
4
|
+
export const LOOKAHEAD_OPENING = "(?=";
|
|
5
|
+
export const DISJUNCTION_TO_END_OF_INPUT = "|$(?![\\s\\S]))";
|
|
6
|
+
export const OPTIONAL_ATOM_OPENING = "(?:";
|
|
7
|
+
export const NAMED_GROUP_OPENING = "(?<";
|
|
8
|
+
export function asOptionalAtom(text) {
|
|
9
|
+
return OPTIONAL_ATOM_OPENING + text + DISJUNCTION_TO_END_OF_INPUT;
|
|
10
|
+
}
|
|
11
|
+
export const MULTILINE_CARET = "(?m:^)";
|
|
12
|
+
export const UNSATISFIABLE = "[]";
|
|
13
|
+
export const ONLY_AT_END_OF_INPUT = asOptionalAtom(UNSATISFIABLE);
|
|
14
|
+
export const WORD_BOUNDARY_ATOMS = [
|
|
15
|
+
asOptionalAtom("\\b"),
|
|
16
|
+
asOptionalAtom("\\B")
|
|
17
|
+
];
|
|
18
|
+
export const isWordBoundaryAtom = (part) => part === WORD_BOUNDARY_ATOMS[0] || part === WORD_BOUNDARY_ATOMS[1];
|
|
19
|
+
export const isOptionalAtom = (part) => typeof part === "string" &&
|
|
20
|
+
part.startsWith(OPTIONAL_ATOM_OPENING) &&
|
|
21
|
+
part.endsWith(DISJUNCTION_TO_END_OF_INPUT);
|
|
22
|
+
export function isRawLookaround(part) {
|
|
23
|
+
return (part.startsWith("(?!") ||
|
|
24
|
+
(part.startsWith(NAMED_GROUP_OPENING) &&
|
|
25
|
+
"=!".includes(part[NAMED_GROUP_OPENING.length])));
|
|
26
|
+
}
|
|
27
|
+
export const endsAtTruncationBranch = (part) => part === DISJUNCTION_TO_END_OF_INPUT || isOptionalAtom(part);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const backreferenceExpansion = Symbol("backreferenceExpansion");
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Backreference, Part } from "./part.ts";
|
|
2
|
+
import type { Hooks } from "./walk.ts";
|
|
3
|
+
import type { CompiledDynamic } from "./compilePartial/compiled.ts";
|
|
4
|
+
export interface BackreferenceRecorder {
|
|
5
|
+
groupClosed(groupNumber: number, opening: string): void;
|
|
6
|
+
backreference(backreference: Backreference, scope: number): void;
|
|
7
|
+
}
|
|
8
|
+
export interface BackreferenceHook {
|
|
9
|
+
record: () => BackreferenceRecorder;
|
|
10
|
+
compile: (parts: readonly Part[], backreferences: readonly Backreference[], flags: string, isUnicode: boolean, featureMask: number, hooks: Hooks) => CompiledDynamic;
|
|
11
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Part } from "./part.ts";
|
|
2
|
+
export declare const ON_CARET = 0;
|
|
3
|
+
export declare const ON_ALTERNATIVE = 1;
|
|
4
|
+
export declare const ON_LOOKAHEAD = 2;
|
|
5
|
+
export declare const ON_GROUP = 3;
|
|
6
|
+
export declare const ON_END = 4;
|
|
7
|
+
export interface CaretFrame {
|
|
8
|
+
(event: typeof ON_CARET | typeof ON_ALTERNATIVE | typeof ON_END): void;
|
|
9
|
+
(event: typeof ON_LOOKAHEAD, body: Part[], scope: number, source: string, i: number): void;
|
|
10
|
+
(event: typeof ON_GROUP, body: Part[], groupScope: number, source: string, i: number, closing: string, containsRawLookaround: boolean): {
|
|
11
|
+
closing: string;
|
|
12
|
+
forced: boolean;
|
|
13
|
+
stays: boolean;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export type CaretRecorder = (result: Part[], scope: number) => CaretFrame;
|
|
17
|
+
export type CaretHook = (source?: string) => CaretRecorder | undefined;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { walk } from "../walk.js";
|
|
2
|
+
import { CARETS_MODULE, MODULES_NAMED_BY_MASK } from "../moduleHooks.js";
|
|
3
|
+
import { MAYBE_HAS_BACKREFERENCE_REGEX } from "../constants.js";
|
|
4
|
+
import { UNCONSTRAINED_GROUP_SHAPE } from "./constants.js";
|
|
5
|
+
import { isBackreference } from "../part.js";
|
|
6
|
+
import groupShape from "./groupShape.js";
|
|
7
|
+
import toStatic from "./toStatic.js";
|
|
8
|
+
function walkWithCaretRulesWhereNeeded(regex, declaresNamedGroup, groupLimit, caret, record, withModifiers) {
|
|
9
|
+
const walked = walk(regex, declaresNamedGroup, groupLimit, caret === null || caret === void 0 ? void 0 : caret(regex.source), record === null || record === void 0 ? void 0 : record(), withModifiers);
|
|
10
|
+
return walked.needs & CARETS_MODULE && caret !== undefined
|
|
11
|
+
? walk(regex, declaresNamedGroup, groupLimit, caret(), record === null || record === void 0 ? void 0 : record(), withModifiers)
|
|
12
|
+
: walked;
|
|
13
|
+
}
|
|
14
|
+
export default function compileWith(regex, hooks) {
|
|
15
|
+
const flags = regex.flags;
|
|
16
|
+
const isUnicode = regex.unicode || regex.unicodeSets;
|
|
17
|
+
const maybeHasBackreference = MAYBE_HAS_BACKREFERENCE_REGEX.test(regex.source);
|
|
18
|
+
const { groupLimit, declaresNamedGroup } = maybeHasBackreference && !isUnicode
|
|
19
|
+
? groupShape(regex)
|
|
20
|
+
: UNCONSTRAINED_GROUP_SHAPE;
|
|
21
|
+
const backreferenceHook = maybeHasBackreference
|
|
22
|
+
? hooks.backreference
|
|
23
|
+
: undefined;
|
|
24
|
+
const { parts, featureMask, needs, rawLookarounds } = walkWithCaretRulesWhereNeeded(regex, declaresNamedGroup, groupLimit, hooks.caret, backreferenceHook === null || backreferenceHook === void 0 ? void 0 : backreferenceHook.record, hooks.modifiers);
|
|
25
|
+
if (needs)
|
|
26
|
+
throw new TypeError("Needs the " + MODULES_NAMED_BY_MASK[needs]);
|
|
27
|
+
const backreferences = backreferenceHook
|
|
28
|
+
? parts.filter(isBackreference)
|
|
29
|
+
: [];
|
|
30
|
+
const compiled = backreferenceHook === undefined || backreferences.length === 0
|
|
31
|
+
? toStatic(parts, flags, featureMask, hooks)
|
|
32
|
+
: backreferenceHook.compile(parts, backreferences, flags, isUnicode, featureMask, hooks);
|
|
33
|
+
if (rawLookarounds)
|
|
34
|
+
compiled.rawLookarounds = rawLookarounds;
|
|
35
|
+
return compiled;
|
|
36
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Part } from "../part.ts";
|
|
2
|
+
import type { Hooks } from "../walk.ts";
|
|
3
|
+
import type { RegexFeature } from "../regexFeatures.ts";
|
|
4
|
+
import type { TruncationProbeCache } from "../../hitEnd/truncationProbeCache.ts";
|
|
5
|
+
import type { RawLookarounds } from "../rawLookaroundInfo.ts";
|
|
6
|
+
export interface DynamicPath {
|
|
7
|
+
preScan: RegExp;
|
|
8
|
+
expand: (capture: RegExpExecArray) => Part[];
|
|
9
|
+
expansionFitsCaptures: (expandedFrom: RegExpExecArray, match: RegExpExecArray, input: string) => boolean;
|
|
10
|
+
}
|
|
11
|
+
export declare abstract class Compiled {
|
|
12
|
+
readonly parts: readonly Part[];
|
|
13
|
+
readonly featureMask: number;
|
|
14
|
+
readonly hooks: Hooks;
|
|
15
|
+
features?: ReadonlySet<RegexFeature>;
|
|
16
|
+
probeCache?: TruncationProbeCache;
|
|
17
|
+
rawLookarounds?: RawLookarounds;
|
|
18
|
+
constructor(parts: readonly Part[], featureMask: number, hooks: Hooks);
|
|
19
|
+
}
|
|
20
|
+
export declare class CompiledStatic extends Compiled {
|
|
21
|
+
readonly regex: RegExp;
|
|
22
|
+
readonly honoursLastIndex: boolean;
|
|
23
|
+
constructor(regex: RegExp, parts: string[], featureMask: number, hooks: Hooks);
|
|
24
|
+
}
|
|
25
|
+
export interface CompiledDynamic extends Compiled {
|
|
26
|
+
readonly dynamic: DynamicPath;
|
|
27
|
+
readonly execDynamic: (this: RegExp, dynamic: DynamicPath, input: string) => RegExpExecArray | null;
|
|
28
|
+
}
|
|
29
|
+
export type CompiledPartial = CompiledStatic | CompiledDynamic;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export class Compiled {
|
|
2
|
+
constructor(parts, featureMask, hooks) {
|
|
3
|
+
this.parts = parts;
|
|
4
|
+
this.featureMask = featureMask;
|
|
5
|
+
this.hooks = hooks;
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
export class CompiledStatic extends Compiled {
|
|
9
|
+
constructor(regex, parts, featureMask, hooks) {
|
|
10
|
+
super(parts, featureMask, hooks);
|
|
11
|
+
this.regex = regex;
|
|
12
|
+
this.honoursLastIndex = regex.global || regex.sticky;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { FLAGS_IRRELEVANT_TO_REBUILD } from "../constants.js";
|
|
2
|
+
export default function groupShape(regex) {
|
|
3
|
+
const emptyMatch = new RegExp("|" + regex.source, regex.flags.replace(FLAGS_IRRELEVANT_TO_REBUILD, "")).exec("");
|
|
4
|
+
return {
|
|
5
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- match must succeed, since pattern starts with empty alternative
|
|
6
|
+
groupLimit: emptyMatch.length - 1,
|
|
7
|
+
declaresNamedGroup: (emptyMatch === null || emptyMatch === void 0 ? void 0 : emptyMatch.groups) !== undefined
|
|
8
|
+
};
|
|
9
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import compileWith from "./compilePartial/compileWith.js";
|
|
2
|
+
import { compiledPartial } from "./partialMatchInternals.js";
|
|
3
|
+
import execFrom from "./execFrom.js";
|
|
4
|
+
export default function createPartialMatchRegExp(hooks) {
|
|
5
|
+
return class PartialMatchRegExp extends RegExp {
|
|
6
|
+
constructor(pattern, flags) {
|
|
7
|
+
super(pattern, flags);
|
|
8
|
+
this[compiledPartial] = compileWith(this, hooks);
|
|
9
|
+
}
|
|
10
|
+
exec(input) {
|
|
11
|
+
const compiled = this[compiledPartial];
|
|
12
|
+
if ("dynamic" in compiled)
|
|
13
|
+
return compiled.execDynamic.call(this, compiled.dynamic, input);
|
|
14
|
+
const { regex } = compiled;
|
|
15
|
+
const match = execFrom(regex, input, this.lastIndex);
|
|
16
|
+
if (compiled.honoursLastIndex)
|
|
17
|
+
this.lastIndex = regex.lastIndex;
|
|
18
|
+
return match;
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function execFrom(regex: RegExp, input: string, start: number): RegExpExecArray | null;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { RegexFeature } from "./regexFeatures.ts";
|
|
2
|
+
export type { RegexFeature };
|
|
3
|
+
declare const partialMatchRegExpBrand: unique symbol;
|
|
4
|
+
/**
|
|
5
|
+
* An instance of `PartialMatchRegExp`, from any entry point. Declarations
|
|
6
|
+
* merged into this interface apply to every such instance.
|
|
7
|
+
*/
|
|
8
|
+
interface PartialMatchRegExp extends RegExp {
|
|
9
|
+
readonly [partialMatchRegExpBrand]: true;
|
|
10
|
+
exec(input: string): RegExpExecArray | null;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* The type of a `PartialMatchRegExp` class, from any entry point or
|
|
14
|
+
* `withModules`.
|
|
15
|
+
*/
|
|
16
|
+
interface PartialMatchRegExpConstructor extends Omit<RegExpConstructor, "prototype" | typeof Symbol.species> {
|
|
17
|
+
new (pattern: RegExp | string, flags?: string): PartialMatchRegExp;
|
|
18
|
+
readonly prototype: PartialMatchRegExp;
|
|
19
|
+
readonly [Symbol.species]: PartialMatchRegExpConstructor;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* A `RegExp` subclass that supports partial (prefix) matching.
|
|
23
|
+
*
|
|
24
|
+
* An instance behaves like a normal `RegExp` but also matches any input string
|
|
25
|
+
* that is a valid prefix of the original pattern — i.e. strings that could still
|
|
26
|
+
* lead to a full match with more input. This enables validation of incomplete
|
|
27
|
+
* input strings.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```typescript
|
|
31
|
+
* const pattern = /^hello world/;
|
|
32
|
+
* const partial = new PartialMatchRegExp(pattern);
|
|
33
|
+
*
|
|
34
|
+
* partial.test('h'); // true - could match
|
|
35
|
+
* partial.test('hello'); // true - could match
|
|
36
|
+
* partial.test('hello world'); // true - full match
|
|
37
|
+
* partial.test('goodbye'); // false - cannot match
|
|
38
|
+
* ```
|
|
39
|
+
*
|
|
40
|
+
* @remarks
|
|
41
|
+
* The transformed pattern always matches an empty string at the end of input;
|
|
42
|
+
* use a start anchor (`^`) to prevent false positives from empty string matches.
|
|
43
|
+
* See the documentation for how the `y` (sticky) flag behaves.
|
|
44
|
+
*
|
|
45
|
+
* @see {@link https://github.com/TomStrepsil/regex-partial-match#readme | Documentation}
|
|
46
|
+
*/
|
|
47
|
+
declare const PartialMatchRegExp: PartialMatchRegExpConstructor;
|
|
48
|
+
export default PartialMatchRegExp;
|
|
49
|
+
export type { PartialMatchRegExp, PartialMatchRegExpConstructor };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import carets from "../modules/carets/index.js";
|
|
2
|
+
import backreferences from "../modules/backreferences/index.js";
|
|
3
|
+
import withModules from "./withModules.js";
|
|
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
|
+
* See the documentation for how the `y` (sticky) flag behaves.
|
|
27
|
+
*
|
|
28
|
+
* @see {@link https://github.com/TomStrepsil/regex-partial-match#readme | Documentation}
|
|
29
|
+
*/
|
|
30
|
+
const PartialMatchRegExp = withModules(carets, backreferences);
|
|
31
|
+
export default PartialMatchRegExp;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const LEGACY_OCTAL_ESCAPE_REGEX = /^(?:[0-3][0-7]{0,2}|[4-7][0-7]?)/;
|
|
2
|
+
const hexEscape = (codeUnit) => "\\x" + (codeUnit < 0x10 ? "0" : "") + codeUnit.toString(16);
|
|
3
|
+
export function legacyEscapeAsLiteral(digits) {
|
|
4
|
+
return legacyEscapeAtoms(digits).join("");
|
|
5
|
+
}
|
|
6
|
+
export function legacyEscapeAtoms(digits) {
|
|
7
|
+
var _a;
|
|
8
|
+
const octal = (_a = LEGACY_OCTAL_ESCAPE_REGEX.exec(digits)) === null || _a === void 0 ? void 0 : _a[0];
|
|
9
|
+
const atoms = [];
|
|
10
|
+
let index = 0;
|
|
11
|
+
if (octal !== undefined) {
|
|
12
|
+
atoms.push(hexEscape(parseInt(octal, 8)));
|
|
13
|
+
index = octal.length;
|
|
14
|
+
}
|
|
15
|
+
for (; index < digits.length; index++)
|
|
16
|
+
atoms.push(digits[index]);
|
|
17
|
+
return atoms;
|
|
18
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Module } from "./opaqueModule.ts";
|
|
2
|
+
import type { Hooks } from "./walk.ts";
|
|
3
|
+
export declare const CARETS_MODULE = 1;
|
|
4
|
+
export declare const BACKREFERENCES_MODULE = 2;
|
|
5
|
+
export declare const MODULES_NAMED_BY_MASK: Record<number, string>;
|
|
6
|
+
export declare const moduleHooks: unique symbol;
|
|
7
|
+
export interface ModuleHooks extends Hooks {
|
|
8
|
+
readonly bit: number;
|
|
9
|
+
}
|
|
10
|
+
export interface HooksOfModule extends Module {
|
|
11
|
+
readonly [moduleHooks]: ModuleHooks;
|
|
12
|
+
}
|
|
13
|
+
export declare const definedModuleHooks: Set<unknown>;
|
|
14
|
+
export declare function defineModule(hooks: ModuleHooks): Module;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export const CARETS_MODULE = 1;
|
|
2
|
+
export const BACKREFERENCES_MODULE = 2;
|
|
3
|
+
export const MODULES_NAMED_BY_MASK = {
|
|
4
|
+
[CARETS_MODULE]: "carets module",
|
|
5
|
+
[BACKREFERENCES_MODULE]: "backreferences module",
|
|
6
|
+
[CARETS_MODULE | BACKREFERENCES_MODULE]: "carets and backreferences modules"
|
|
7
|
+
};
|
|
8
|
+
export const moduleHooks = Symbol();
|
|
9
|
+
export const definedModuleHooks = new Set();
|
|
10
|
+
export function defineModule(hooks) {
|
|
11
|
+
definedModuleHooks.add(Object.freeze(hooks));
|
|
12
|
+
return Object.freeze({
|
|
13
|
+
[moduleHooks]: hooks
|
|
14
|
+
});
|
|
15
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
interface NumericBackreference {
|
|
2
|
+
ref: number;
|
|
3
|
+
forward?: boolean;
|
|
4
|
+
caseInsensitive?: boolean;
|
|
5
|
+
}
|
|
6
|
+
interface NamedBackreference {
|
|
7
|
+
ref: string;
|
|
8
|
+
forward?: boolean;
|
|
9
|
+
caseInsensitive?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export type Backreference = NumericBackreference | NamedBackreference;
|
|
12
|
+
export type Part = string | Backreference;
|
|
13
|
+
export declare const isBackreference: (part: Part) => part is Backreference;
|
|
14
|
+
export declare const isNumericBackreference: (part: Part) => part is NumericBackreference;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Part } from "./part.ts";
|
|
2
|
+
export declare const OCCURRENCES_REGEX: RegExp;
|
|
3
|
+
export declare const QUANTIFIER_PART: RegExp;
|
|
4
|
+
export declare const LAZY_MARK = "?";
|
|
5
|
+
export declare const isQuantifier: (part: Part | undefined) => part is string;
|
|
6
|
+
export declare function quantifierEndingAt(parts: readonly Part[], index: number): number;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export const OCCURRENCES_REGEX = /\{\d+(?:,\d*)?\}/y;
|
|
2
|
+
export const QUANTIFIER_PART = /^(?:[*+?]|\{\d+(?:,\d*)?\})$/;
|
|
3
|
+
export const LAZY_MARK = "?";
|
|
4
|
+
export const isQuantifier = (part) => typeof part === "string" && QUANTIFIER_PART.test(part);
|
|
5
|
+
export function quantifierEndingAt(parts, index) {
|
|
6
|
+
return parts[index] === LAZY_MARK && isQuantifier(parts[index - 1])
|
|
7
|
+
? index - 1
|
|
8
|
+
: index;
|
|
9
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface RawReference {
|
|
2
|
+
ref: number;
|
|
3
|
+
start: number;
|
|
4
|
+
end: number;
|
|
5
|
+
}
|
|
6
|
+
export interface RawLookaroundInfo {
|
|
7
|
+
sourceStart: number;
|
|
8
|
+
capturingGroupsOpened: number;
|
|
9
|
+
references: readonly RawReference[];
|
|
10
|
+
}
|
|
11
|
+
export type RawLookarounds = readonly (RawLookaroundInfo | undefined)[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export declare const REGEX_FEATURES: readonly ["patternCharacter", "startAnchor", "endAnchor", "wordBoundary", "nonWordBoundary", "lookahead", "negativeLookahead", "lookbehind", "negativeLookbehind", "backreference", "namedBackreference", "namedGroup", "capturingGroup", "lookaroundCapture", "nonCapturingGroup", "modifierGroup", "modifierGroupWithRemoval", "characterClass", "nestedCharacterClass", "classIntersection", "classSubtraction", "disjunction", "quantifier", "unicodePropertyEscape", "characterClassEscape", "controlEscape", "controlLetterEscape", "hexEscapeSequence", "unicodeEscapeSequence", "otherEscape"];
|
|
2
|
+
export type RegexFeature = (typeof REGEX_FEATURES)[number];
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export const REGEX_FEATURES = [
|
|
2
|
+
"patternCharacter",
|
|
3
|
+
"startAnchor",
|
|
4
|
+
"endAnchor",
|
|
5
|
+
"wordBoundary",
|
|
6
|
+
"nonWordBoundary",
|
|
7
|
+
"lookahead",
|
|
8
|
+
"negativeLookahead",
|
|
9
|
+
"lookbehind",
|
|
10
|
+
"negativeLookbehind",
|
|
11
|
+
"backreference",
|
|
12
|
+
"namedBackreference",
|
|
13
|
+
"namedGroup",
|
|
14
|
+
"capturingGroup",
|
|
15
|
+
"lookaroundCapture",
|
|
16
|
+
"nonCapturingGroup",
|
|
17
|
+
"modifierGroup",
|
|
18
|
+
"modifierGroupWithRemoval",
|
|
19
|
+
"characterClass",
|
|
20
|
+
"nestedCharacterClass",
|
|
21
|
+
"classIntersection",
|
|
22
|
+
"classSubtraction",
|
|
23
|
+
"disjunction",
|
|
24
|
+
"quantifier",
|
|
25
|
+
"unicodePropertyEscape",
|
|
26
|
+
"characterClassEscape",
|
|
27
|
+
"controlEscape",
|
|
28
|
+
"controlLetterEscape",
|
|
29
|
+
"hexEscapeSequence",
|
|
30
|
+
"unicodeEscapeSequence",
|
|
31
|
+
"otherEscape"
|
|
32
|
+
];
|
|
33
|
+
/** @internal */
|
|
34
|
+
export function featureSet(mask) {
|
|
35
|
+
const features = new Set();
|
|
36
|
+
for (let index = 0; index < REGEX_FEATURES.length; index++) {
|
|
37
|
+
if (mask & (1 << index))
|
|
38
|
+
features.add(REGEX_FEATURES[index]);
|
|
39
|
+
}
|
|
40
|
+
return features;
|
|
41
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare const CASE_INSENSITIVE = 1;
|
|
2
|
+
export declare const MULTILINE = 2;
|
|
3
|
+
export declare const DOT_ALL = 4;
|
|
4
|
+
export declare const UNICODE = 8;
|
|
5
|
+
export declare const UNICODE_SETS = 16;
|
|
6
|
+
export declare const WITHIN_LOOKAROUND = 32;
|
|
7
|
+
export declare const WITHIN_GROUP = 64;
|
|
8
|
+
export declare const WITHIN_RAW_LOOKAROUND = 128;
|
|
9
|
+
export declare function scopeOf(regex: RegExp): number;
|
|
10
|
+
export type ModifiersHook = (scope: number, modifiers: string) => number;
|
|
11
|
+
export declare function scopeWithModifiers(scope: number, modifiers: string): number;
|
|
12
|
+
export declare function flagsOf(scope: number): string;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export const CASE_INSENSITIVE = 1;
|
|
2
|
+
export const MULTILINE = 2;
|
|
3
|
+
export const DOT_ALL = 4;
|
|
4
|
+
export const UNICODE = 8;
|
|
5
|
+
export const UNICODE_SETS = 16;
|
|
6
|
+
export const WITHIN_LOOKAROUND = 32;
|
|
7
|
+
export const WITHIN_GROUP = 64;
|
|
8
|
+
export const WITHIN_RAW_LOOKAROUND = 128;
|
|
9
|
+
const MODIFIER_REMOVAL = "-";
|
|
10
|
+
function modifierBit(modifier) {
|
|
11
|
+
switch (modifier) {
|
|
12
|
+
case "i":
|
|
13
|
+
return CASE_INSENSITIVE;
|
|
14
|
+
case "m":
|
|
15
|
+
return MULTILINE;
|
|
16
|
+
default:
|
|
17
|
+
return DOT_ALL;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export function scopeOf(regex) {
|
|
21
|
+
return ((regex.ignoreCase ? CASE_INSENSITIVE : 0) |
|
|
22
|
+
(regex.multiline ? MULTILINE : 0) |
|
|
23
|
+
(regex.dotAll ? DOT_ALL : 0) |
|
|
24
|
+
(regex.unicode ? UNICODE : 0) |
|
|
25
|
+
(regex.unicodeSets ? UNICODE | UNICODE_SETS : 0));
|
|
26
|
+
}
|
|
27
|
+
export function scopeWithModifiers(scope, modifiers) {
|
|
28
|
+
let removing = false;
|
|
29
|
+
for (let index = 0; index < modifiers.length; index++) {
|
|
30
|
+
const modifier = modifiers[index];
|
|
31
|
+
if (modifier === MODIFIER_REMOVAL)
|
|
32
|
+
removing = true;
|
|
33
|
+
else if (removing)
|
|
34
|
+
scope &= ~modifierBit(modifier);
|
|
35
|
+
else
|
|
36
|
+
scope |= modifierBit(modifier);
|
|
37
|
+
}
|
|
38
|
+
return scope;
|
|
39
|
+
}
|
|
40
|
+
export function flagsOf(scope) {
|
|
41
|
+
return ((scope & CASE_INSENSITIVE ? "i" : "") +
|
|
42
|
+
(scope & MULTILINE ? "m" : "") +
|
|
43
|
+
(scope & DOT_ALL ? "s" : "") +
|
|
44
|
+
(scope & UNICODE_SETS ? "v" : scope & UNICODE ? "u" : ""));
|
|
45
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Part } from "./part.ts";
|
|
2
|
+
import { type CaretHook, type CaretRecorder } from "./caretHook.ts";
|
|
3
|
+
import type { BackreferenceRecorder, BackreferenceHook } from "./backreferenceHook.ts";
|
|
4
|
+
import type { RawLookaroundInfo } from "./rawLookaroundInfo.ts";
|
|
5
|
+
import { type ModifiersHook } from "./scope.ts";
|
|
6
|
+
export interface Hooks {
|
|
7
|
+
caret?: CaretHook;
|
|
8
|
+
backreference?: BackreferenceHook;
|
|
9
|
+
modifiers?: ModifiersHook;
|
|
10
|
+
}
|
|
11
|
+
export declare function walk(regex: RegExp, declaresNamedGroup: boolean, groupLimit: number, caretRecorder: CaretRecorder | undefined, backreferenceRecorder: BackreferenceRecorder | undefined, withModifiers: Hooks["modifiers"]): {
|
|
12
|
+
parts: Part[];
|
|
13
|
+
featureMask: number;
|
|
14
|
+
needs: number;
|
|
15
|
+
rawLookarounds: RawLookaroundInfo[] | undefined;
|
|
16
|
+
};
|