@ptolemy2002/rgx 8.2.0 → 10.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/dist/concat.js +2 -0
- package/dist/errors/invalidRegexString.d.ts +2 -1
- package/dist/errors/invalidRegexString.js +3 -2
- package/dist/index.d.ts +3 -3
- package/dist/index.js +5 -4
- package/dist/internal/taggedTemplateToArray.d.ts +2 -1
- package/dist/internal/taggedTemplateToArray.js +22 -5
- package/dist/lexer/base.d.ts +11 -10
- package/dist/lexer/base.js +2 -1
- package/dist/resolve.js +52 -38
- package/dist/typeGuards.js +23 -4
- package/dist/types.d.ts +4 -1
- package/dist/walker/base.d.ts +16 -14
- package/dist/walker/base.js +23 -4
- package/dist/walker/part.d.ts +21 -16
- package/dist/walker/part.js +4 -2
- package/package.json +1 -1
package/dist/concat.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.rgxConcat = rgxConcat;
|
|
4
|
+
const ExtRegExp_1 = require("./ExtRegExp");
|
|
4
5
|
const internal_1 = require("./internal");
|
|
5
6
|
const resolve_1 = require("./resolve");
|
|
6
7
|
// Wrapper for letting an array of tokens be resolved as a concatenation instead of a union.
|
|
7
8
|
function rgxConcat(tokens, groupWrap = true, currentFlags = '') {
|
|
9
|
+
(0, ExtRegExp_1.assertValidRegexFlags)(currentFlags);
|
|
8
10
|
const result = tokens.map(t => (0, resolve_1.resolveRGXToken)(t, groupWrap, true, currentFlags)).join('');
|
|
9
11
|
(0, internal_1.assureAcceptance)(tokens, currentFlags);
|
|
10
12
|
return result;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { RGXError } from "./";
|
|
2
2
|
export declare class RGXInvalidRegexStringError extends RGXError {
|
|
3
3
|
got: string;
|
|
4
|
-
|
|
4
|
+
cause: SyntaxError;
|
|
5
|
+
constructor(message: string, got: string, cause: SyntaxError);
|
|
5
6
|
calcMessage(message: string): string;
|
|
6
7
|
}
|
|
@@ -3,13 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.RGXInvalidRegexStringError = void 0;
|
|
4
4
|
const errors_1 = require("./");
|
|
5
5
|
class RGXInvalidRegexStringError extends errors_1.RGXError {
|
|
6
|
-
constructor(message, got) {
|
|
6
|
+
constructor(message, got, cause) {
|
|
7
7
|
super(message, 'INVALID_REGEX_STRING');
|
|
8
8
|
this.name = 'RGXInvalidRegexStringError';
|
|
9
9
|
this.got = got;
|
|
10
|
+
this.cause = cause;
|
|
10
11
|
}
|
|
11
12
|
calcMessage(message) {
|
|
12
|
-
return `${message}; Got: ${JSON.stringify(this.got)}`;
|
|
13
|
+
return `${message}; Got: ${JSON.stringify(this.got)}; Cause: ${this.cause.message}`;
|
|
13
14
|
}
|
|
14
15
|
}
|
|
15
16
|
exports.RGXInvalidRegexStringError = RGXInvalidRegexStringError;
|
package/dist/index.d.ts
CHANGED
|
@@ -16,6 +16,6 @@ export * from "./constants";
|
|
|
16
16
|
export * from "./walker";
|
|
17
17
|
export * from "./lexer";
|
|
18
18
|
export declare function rgxa(tokens: t.RGXToken[], flags?: string): ExtRegExp;
|
|
19
|
-
export default function rgx(flags?: string, multiline?: boolean): (strings: TemplateStringsArray, ...tokens: t.RGXToken[]) => ExtRegExp;
|
|
20
|
-
export declare function rgxwa<R = unknown, T = unknown>(source: string, tokens: RGXTokenOrPart<R, T>[], options?: Omit<t.RGXWOptions<R>, "multiline">): RGXWalker<R>;
|
|
21
|
-
export declare function rgxw<R = unknown, T = unknown>(source: string, { multiline, ...options }?: t.RGXWOptions<R>): (strings: TemplateStringsArray, ...tokens: RGXTokenOrPart<R, T>[]) => RGXWalker<R>;
|
|
19
|
+
export default function rgx(flags?: string, multiline?: boolean, verbatim?: boolean): (strings: TemplateStringsArray, ...tokens: t.RGXToken[]) => ExtRegExp;
|
|
20
|
+
export declare function rgxwa<R = unknown, S = unknown, T = unknown>(source: string, tokens: RGXTokenOrPart<R, S, T>[], options?: Omit<t.RGXWOptions<R, S>, "multiline">): RGXWalker<R, S>;
|
|
21
|
+
export declare function rgxw<R = unknown, S = unknown, T = unknown>(source: string, { multiline, verbatim, ...options }?: t.RGXWOptions<R, S>): (strings: TemplateStringsArray, ...tokens: RGXTokenOrPart<R, S, T>[]) => RGXWalker<R, S>;
|
package/dist/index.js
CHANGED
|
@@ -48,18 +48,19 @@ function rgxa(tokens, flags = '') {
|
|
|
48
48
|
const pattern = (0, concat_1.rgxConcat)(tokens, true, flags);
|
|
49
49
|
return (0, ExtRegExp_1.extRegExp)(pattern, flags);
|
|
50
50
|
}
|
|
51
|
-
function rgx(flags = '', multiline = true) {
|
|
51
|
+
function rgx(flags = '', multiline = true, verbatim = true) {
|
|
52
52
|
(0, ExtRegExp_1.assertValidRegexFlags)(flags);
|
|
53
53
|
return (strings, ...tokens) => {
|
|
54
|
-
|
|
54
|
+
// It is safe to assert the result because we know there will be no parts passed in here.
|
|
55
|
+
return rgxa((0, internal_1.rgxTaggedTemplateToArray)(strings, tokens, multiline, verbatim), flags);
|
|
55
56
|
};
|
|
56
57
|
}
|
|
57
58
|
function rgxwa(source, tokens, options = {}) {
|
|
58
59
|
(0, internal_1.assureAcceptance)(tokens.map(t => walker_1.RGXPart.check(t) ? t.token : t), '');
|
|
59
60
|
return new walker_1.RGXWalker(source, tokens, options);
|
|
60
61
|
}
|
|
61
|
-
function rgxw(source, { multiline = true, ...options } = {}) {
|
|
62
|
+
function rgxw(source, { multiline = true, verbatim = true, ...options } = {}) {
|
|
62
63
|
return (strings, ...tokens) => {
|
|
63
|
-
return rgxwa(source, (0, internal_1.
|
|
64
|
+
return rgxwa(source, (0, internal_1.rgxTaggedTemplateToArray)(strings, tokens, multiline, verbatim), options);
|
|
64
65
|
};
|
|
65
66
|
}
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
import { RGXTokenOrPart } from "../walker";
|
|
2
|
+
export declare function rgxTaggedTemplateToArray<R = unknown, S = unknown, T = unknown>(strings: TemplateStringsArray, tokens: RGXTokenOrPart<R, S, T>[], multiline: boolean, verbatim: boolean): RGXTokenOrPart<R, S, T>[];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
function
|
|
3
|
+
exports.rgxTaggedTemplateToArray = rgxTaggedTemplateToArray;
|
|
4
|
+
function rgxTaggedTemplateToArray(strings, tokens, multiline, verbatim) {
|
|
5
5
|
function isNullOrUndefined(value) {
|
|
6
6
|
return value === null || value === undefined;
|
|
7
7
|
}
|
|
@@ -12,13 +12,27 @@ function taggedTemplateToArray(strings, tokens, multiline) {
|
|
|
12
12
|
// Strings always come before tokens
|
|
13
13
|
if (!isNullOrUndefined(string)) {
|
|
14
14
|
if (!multiline) {
|
|
15
|
-
|
|
15
|
+
if (verbatim)
|
|
16
|
+
array.push(string);
|
|
17
|
+
else
|
|
18
|
+
array.push({ rgxInterpolate: true, toRgx: () => string });
|
|
16
19
|
}
|
|
17
20
|
else {
|
|
21
|
+
const startsNewLine = string.startsWith("\n");
|
|
18
22
|
// Remove all empty lines, remove comments, and trim whitespace from the start of each line.
|
|
19
23
|
let lines = string
|
|
20
24
|
.split("\n")
|
|
21
|
-
|
|
25
|
+
/*
|
|
26
|
+
This check makes sure
|
|
27
|
+
`
|
|
28
|
+
foo |
|
|
29
|
+
${'bar'} |
|
|
30
|
+
baz
|
|
31
|
+
`
|
|
32
|
+
|
|
33
|
+
resolves to "foo | bar |baz" instead of "foo | bar|baz"
|
|
34
|
+
*/
|
|
35
|
+
.map((line, i) => (i !== 0 || startsNewLine) ? line.trimStart() : line)
|
|
22
36
|
// Remove comments both for the start of the line.
|
|
23
37
|
.filter(line => !line.startsWith("//"))
|
|
24
38
|
.filter(line => line.length > 0)
|
|
@@ -31,7 +45,10 @@ function taggedTemplateToArray(strings, tokens, multiline) {
|
|
|
31
45
|
return line;
|
|
32
46
|
})
|
|
33
47
|
.join("");
|
|
34
|
-
|
|
48
|
+
if (verbatim)
|
|
49
|
+
array.push(lines);
|
|
50
|
+
else
|
|
51
|
+
array.push({ rgxInterpolate: true, toRgx: () => lines });
|
|
35
52
|
}
|
|
36
53
|
}
|
|
37
54
|
if (!isNullOrUndefined(token))
|
package/dist/lexer/base.d.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { RGXToken } from "../types";
|
|
2
2
|
import { RGXTokenOrPart, RGXWalkerOptions } from "../walker";
|
|
3
|
-
export type RGXLexemeDefinition<Data> = Readonly<({
|
|
3
|
+
export type RGXLexemeDefinition<Data, Share = unknown> = Readonly<({
|
|
4
4
|
type: "resolve";
|
|
5
5
|
token: RGXToken;
|
|
6
6
|
} | {
|
|
7
7
|
type: "walk";
|
|
8
|
-
tokens: RGXTokenOrPart<Data>[];
|
|
9
|
-
options?: Omit<RGXWalkerOptions<Data>, "startingSourcePosition" | "reduced"> & {
|
|
8
|
+
tokens: RGXTokenOrPart<Data, Share>[];
|
|
9
|
+
options?: Omit<RGXWalkerOptions<Data, Share>, "startingSourcePosition" | "reduced" | "share"> & {
|
|
10
10
|
reduced?: (() => Data) | null;
|
|
11
|
+
share?: (() => Share) | null;
|
|
11
12
|
};
|
|
12
13
|
}) & {
|
|
13
14
|
id: string;
|
|
@@ -20,23 +21,23 @@ export type RGXLexeme<Data> = {
|
|
|
20
21
|
end: RGXLexemeLocation;
|
|
21
22
|
data?: Data;
|
|
22
23
|
};
|
|
23
|
-
export type RGXLexemeDefinitions<Data> = Readonly<Record<string, ReadonlyArray<RGXLexemeDefinition<Data>>>>;
|
|
24
|
+
export type RGXLexemeDefinitions<Data, Share = unknown> = Readonly<Record<string, ReadonlyArray<RGXLexemeDefinition<Data, Share>>>>;
|
|
24
25
|
export type RGXLexemeLocation = {
|
|
25
26
|
index: number;
|
|
26
27
|
line: number;
|
|
27
28
|
column: number;
|
|
28
29
|
};
|
|
29
30
|
export declare function rgxLexemeLocationFromIndex(source: string, index: number): RGXLexemeLocation;
|
|
30
|
-
export declare class RGXLexer<Data> {
|
|
31
|
+
export declare class RGXLexer<Data, Share = unknown> {
|
|
31
32
|
readonly source: string;
|
|
32
33
|
_position: number;
|
|
33
|
-
readonly lexemeDefinitions: RGXLexemeDefinitions<Data>;
|
|
34
|
+
readonly lexemeDefinitions: RGXLexemeDefinitions<Data, Share>;
|
|
34
35
|
readonly matched: RGXLexeme<Data>[];
|
|
35
|
-
static check: (value: unknown) => value is RGXLexer<unknown>;
|
|
36
|
-
static assert: (value: unknown) => asserts value is RGXLexer<unknown>;
|
|
36
|
+
static check: (value: unknown) => value is RGXLexer<unknown, unknown>;
|
|
37
|
+
static assert: (value: unknown) => asserts value is RGXLexer<unknown, unknown>;
|
|
37
38
|
get position(): number;
|
|
38
39
|
set position(value: number);
|
|
39
|
-
constructor(source: string, lexemeDefinitions?: RGXLexemeDefinitions<Data>, startingPosition?: number);
|
|
40
|
+
constructor(source: string, lexemeDefinitions?: RGXLexemeDefinitions<Data, Share>, startingPosition?: number);
|
|
40
41
|
private matchDefinition;
|
|
41
42
|
private next;
|
|
42
43
|
private expect;
|
|
@@ -56,4 +57,4 @@ export declare class RGXLexer<Data> {
|
|
|
56
57
|
consumeWhile(predicate: (lexeme: RGXLexeme<Data>) => boolean, mode?: string, skipWhitespace?: boolean): RGXLexeme<Data>[];
|
|
57
58
|
consumeUntil(predicate: (lexeme: RGXLexeme<Data>) => boolean, mode?: string, skipWhitespace?: boolean): RGXLexeme<Data>[];
|
|
58
59
|
}
|
|
59
|
-
export declare const rgxLexer: <Data>(...args: ConstructorParameters<typeof RGXLexer<Data>>) => RGXLexer<Data>;
|
|
60
|
+
export declare const rgxLexer: <Data, Share = unknown>(...args: ConstructorParameters<typeof RGXLexer<Data, Share>>) => RGXLexer<Data, Share>;
|
package/dist/lexer/base.js
CHANGED
|
@@ -52,10 +52,11 @@ class RGXLexer {
|
|
|
52
52
|
// No data part for token lexemes.
|
|
53
53
|
}
|
|
54
54
|
else {
|
|
55
|
-
const { tokens, options: { reduced, ...options } = {} } = lexemeDefinition;
|
|
55
|
+
const { tokens, options: { reduced, share, ...options } = {} } = lexemeDefinition;
|
|
56
56
|
const walker = new walker_1.RGXWalker(this.source, tokens, {
|
|
57
57
|
...options,
|
|
58
58
|
reduced: reduced?.() ?? undefined,
|
|
59
|
+
share: share?.() ?? undefined,
|
|
59
60
|
startingSourcePosition: startPosition
|
|
60
61
|
});
|
|
61
62
|
// Since the walker will throw an error if it fails to match to the end of its tokens (assuming it isn't stopped before then), this is safe.
|
package/dist/resolve.js
CHANGED
|
@@ -37,9 +37,12 @@ exports.escapeRegex = escapeRegex;
|
|
|
37
37
|
exports.resolveRGXToken = resolveRGXToken;
|
|
38
38
|
const class_1 = require("./class");
|
|
39
39
|
const e = __importStar(require("./errors"));
|
|
40
|
+
const ExtRegExp_1 = require("./ExtRegExp");
|
|
40
41
|
const tg = __importStar(require("./typeGuards"));
|
|
41
42
|
function escapeRegex(value) {
|
|
42
|
-
|
|
43
|
+
const result = value.replaceAll(/[\-\^\$.*+?^${}()|[\]\\]/g, '\\$&');
|
|
44
|
+
tg.assertValidRegexString(result);
|
|
45
|
+
return result;
|
|
43
46
|
}
|
|
44
47
|
function localizableVanillaRegexFlagDiff(prev, next) {
|
|
45
48
|
// Remove anything other than the "ims" flags from both strings, as
|
|
@@ -56,44 +59,55 @@ function localizableVanillaRegexFlagDiff(prev, next) {
|
|
|
56
59
|
return `${added}-${removed}`;
|
|
57
60
|
}
|
|
58
61
|
function resolveRGXToken(token, groupWrap = true, topLevel = true, currentFlags = '') {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
62
|
+
(0, ExtRegExp_1.assertValidRegexFlags)(currentFlags);
|
|
63
|
+
const innerResolve = () => {
|
|
64
|
+
if (tg.isRGXNoOpToken(token))
|
|
65
|
+
return '';
|
|
66
|
+
if (tg.isRGXLiteralToken(token)) {
|
|
67
|
+
const localizableFlagDiff = localizableVanillaRegexFlagDiff(currentFlags, token.flags);
|
|
68
|
+
currentFlags = token.flags;
|
|
69
|
+
if (!localizableFlagDiff) {
|
|
70
|
+
if (groupWrap)
|
|
71
|
+
return '(?:' + token.source + ')';
|
|
72
|
+
else
|
|
73
|
+
return token.source;
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
return `(?${localizableFlagDiff}:${token.source})`;
|
|
77
|
+
}
|
|
69
78
|
}
|
|
70
|
-
|
|
71
|
-
return
|
|
79
|
+
if (tg.isRGXNativeToken(token))
|
|
80
|
+
return escapeRegex(String(token));
|
|
81
|
+
if (tg.isRGXConvertibleToken(token)) {
|
|
82
|
+
// If it's an interpolation, we want to just return it as-is.
|
|
83
|
+
// This will mean the result might be an invalid regex string,
|
|
84
|
+
// but that's why we have a check.
|
|
85
|
+
if (token.rgxInterpolate)
|
|
86
|
+
return String(token.toRgx());
|
|
87
|
+
// The top-level group-wrapping preference propogates to a direct convertible token, but after that
|
|
88
|
+
// the preference falls back to true whenever a token doesn't explicitly specify a preference.
|
|
89
|
+
return resolveRGXToken(token.toRgx(), token.rgxGroupWrap ?? (topLevel ? groupWrap : true), false, currentFlags);
|
|
72
90
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
token = [...(0, class_1.removeRgxUnionDuplicates)(...token)];
|
|
88
|
-
// Don't preserve group wrapping preference for the recursive calls
|
|
89
|
-
if (groupWrap)
|
|
90
|
-
return '(?:' + token.map(t => resolveRGXToken(t, true, false, currentFlags)).join('|') + ')';
|
|
91
|
-
else
|
|
92
|
-
return token.map(t => resolveRGXToken(t, true, false, currentFlags)).join('|');
|
|
91
|
+
// Interpret arrays as unions
|
|
92
|
+
if (tg.isRGXArrayToken(token, false)) {
|
|
93
|
+
if (token.length === 0)
|
|
94
|
+
return '';
|
|
95
|
+
if (token.length > 1) {
|
|
96
|
+
// Remove duplicates
|
|
97
|
+
token = [...(0, class_1.removeRgxUnionDuplicates)(...token)];
|
|
98
|
+
// Don't preserve group wrapping preference for the recursive calls
|
|
99
|
+
if (groupWrap)
|
|
100
|
+
return '(?:' + token.map(t => resolveRGXToken(t, true, false, currentFlags)).join('|') + ')';
|
|
101
|
+
else
|
|
102
|
+
return token.map(t => resolveRGXToken(t, true, false, currentFlags)).join('|');
|
|
103
|
+
}
|
|
104
|
+
return resolveRGXToken(token[0], true, false, currentFlags);
|
|
93
105
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
106
|
+
// Ignoring this line since it should be impossible to reach if the types are correct, but we need it to satisfy the return type
|
|
107
|
+
/* istanbul ignore next */
|
|
108
|
+
throw new e.RGXInvalidTokenError(`Invalid RGX token: ${token}`, null, token);
|
|
109
|
+
};
|
|
110
|
+
const result = innerResolve();
|
|
111
|
+
tg.assertValidRegexString(result);
|
|
112
|
+
return result;
|
|
99
113
|
}
|
package/dist/typeGuards.js
CHANGED
|
@@ -93,13 +93,15 @@ function assertRGXNativeToken(value) {
|
|
|
93
93
|
}
|
|
94
94
|
function isRGXConvertibleToken(value, returnCheck = true) {
|
|
95
95
|
if (typeof value === 'object' && value !== null && 'toRgx' in value) {
|
|
96
|
-
// The rgxGroupWrap, rgxIsRepeatable, and rgxIsGroup properties are optional, but if they exist they must be booleans.
|
|
96
|
+
// The rgxGroupWrap, interpolate, rgxIsRepeatable, and rgxIsGroup properties are optional, but if they exist they must be booleans.
|
|
97
97
|
if ('rgxGroupWrap' in value && typeof value.rgxGroupWrap !== 'boolean')
|
|
98
98
|
return false;
|
|
99
99
|
if ('rgxIsRepeatable' in value && typeof value.rgxIsRepeatable !== 'boolean')
|
|
100
100
|
return false;
|
|
101
101
|
if ('rgxIsGroup' in value && typeof value.rgxIsGroup !== 'boolean')
|
|
102
102
|
return false;
|
|
103
|
+
if ('rgxInterpolate' in value && typeof value.rgxInterpolate !== 'boolean')
|
|
104
|
+
return false;
|
|
103
105
|
// If the rgxAcceptInsertion property exists, it must be a function that returns a string or boolean.
|
|
104
106
|
if ('rgxAcceptInsertion' in value) {
|
|
105
107
|
if (!(0, is_callable_1.default)(value.rgxAcceptInsertion))
|
|
@@ -240,13 +242,30 @@ function isValidRegexString(value) {
|
|
|
240
242
|
new RegExp(value);
|
|
241
243
|
return true;
|
|
242
244
|
}
|
|
243
|
-
catch {
|
|
244
|
-
|
|
245
|
+
catch (e) {
|
|
246
|
+
if (e instanceof SyntaxError) {
|
|
247
|
+
return false;
|
|
248
|
+
}
|
|
249
|
+
// This is ignored because I don't know what king of
|
|
250
|
+
// unexpected errors might happen.
|
|
251
|
+
/* istanbul ignore next */
|
|
252
|
+
throw e;
|
|
245
253
|
}
|
|
246
254
|
}
|
|
247
255
|
function assertValidRegexString(value) {
|
|
248
256
|
if (!isValidRegexString(value)) {
|
|
249
|
-
|
|
257
|
+
try {
|
|
258
|
+
new RegExp(value);
|
|
259
|
+
}
|
|
260
|
+
catch (err) {
|
|
261
|
+
if (err instanceof SyntaxError) {
|
|
262
|
+
throw new e.RGXInvalidRegexStringError("Invalid regex string", value, err);
|
|
263
|
+
}
|
|
264
|
+
// This is ignored because I don't know what king of
|
|
265
|
+
// unexpected errors might happen.
|
|
266
|
+
/* istanbul ignore next */
|
|
267
|
+
throw err;
|
|
268
|
+
}
|
|
250
269
|
}
|
|
251
270
|
}
|
|
252
271
|
function isValidVanillaRegexFlags(value) {
|
package/dist/types.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export type RGXConvertibleToken = {
|
|
|
12
12
|
readonly rgxGroupWrap?: boolean;
|
|
13
13
|
readonly rgxIsGroup?: boolean;
|
|
14
14
|
readonly rgxIsRepeatable?: boolean;
|
|
15
|
+
readonly rgxInterpolate?: boolean;
|
|
15
16
|
};
|
|
16
17
|
export type RGXToken = RGXNativeToken | RGXLiteralToken | RGXConvertibleToken | RGXToken[];
|
|
17
18
|
export type RGXClassTokenConstructor = new (...args: unknown[]) => RGXClassToken;
|
|
@@ -49,6 +50,8 @@ export type ValidRegexFlags = Branded<string, [ValidRegexFlagsBrandSymbol]> | Va
|
|
|
49
50
|
export declare const validIdentifierSymbol: unique symbol;
|
|
50
51
|
export type ValidIdentifierBrandSymbol = typeof validIdentifierSymbol;
|
|
51
52
|
export type ValidIdentifier = Branded<string, [ValidIdentifierBrandSymbol]>;
|
|
52
|
-
export type
|
|
53
|
+
export type RGXOptions = {
|
|
53
54
|
multiline?: boolean;
|
|
55
|
+
verbatim?: boolean;
|
|
54
56
|
};
|
|
57
|
+
export type RGXWOptions<R = unknown, S = unknown> = RGXWalkerOptions<R, S> & RGXOptions;
|
package/dist/walker/base.d.ts
CHANGED
|
@@ -1,46 +1,48 @@
|
|
|
1
1
|
import { CloneDepth } from "@ptolemy2002/immutability-utils";
|
|
2
2
|
import { RGXToken } from "../types";
|
|
3
3
|
import { RGXPart, RGXCapture } from "./part";
|
|
4
|
-
export type RGXWalkerOptions<R> = {
|
|
4
|
+
export type RGXWalkerOptions<R, S = unknown> = {
|
|
5
5
|
startingSourcePosition?: number;
|
|
6
6
|
reduced?: R;
|
|
7
|
+
share?: S;
|
|
7
8
|
infinite?: boolean;
|
|
8
9
|
looping?: boolean;
|
|
9
10
|
};
|
|
10
|
-
export type RGXTokenOrPart<R, T = unknown> = RGXToken | RGXPart<R, T>;
|
|
11
|
-
export declare class RGXWalker<R> {
|
|
11
|
+
export type RGXTokenOrPart<R, S = unknown, T = unknown> = RGXToken | RGXPart<R, S, T>;
|
|
12
|
+
export declare class RGXWalker<R, S = unknown> {
|
|
12
13
|
readonly source: string;
|
|
13
14
|
_sourcePosition: number;
|
|
14
|
-
readonly tokens: RGXTokenOrPart<R>[];
|
|
15
|
+
readonly tokens: RGXTokenOrPart<R, S>[];
|
|
15
16
|
_tokenPosition: number;
|
|
16
17
|
reduced: R;
|
|
18
|
+
share: S;
|
|
17
19
|
captures: RGXCapture[];
|
|
18
20
|
namedCaptures: Record<string, RGXCapture[]>;
|
|
19
21
|
infinite: boolean;
|
|
20
22
|
looping: boolean;
|
|
21
23
|
private _stopped;
|
|
22
|
-
static check: (value: unknown) => value is RGXWalker<unknown>;
|
|
23
|
-
static assert: (value: unknown) => asserts value is RGXWalker<unknown>;
|
|
24
|
+
static check: (value: unknown) => value is RGXWalker<unknown, unknown>;
|
|
25
|
+
static assert: (value: unknown) => asserts value is RGXWalker<unknown, unknown>;
|
|
24
26
|
get sourcePosition(): number;
|
|
25
27
|
set sourcePosition(value: number);
|
|
26
28
|
get tokenPosition(): number;
|
|
27
29
|
set tokenPosition(value: number);
|
|
28
30
|
get stopped(): boolean;
|
|
29
|
-
constructor(source: string, tokens: RGXTokenOrPart<R>[], options?: RGXWalkerOptions<R>);
|
|
31
|
+
constructor(source: string, tokens: RGXTokenOrPart<R, S>[], options?: RGXWalkerOptions<R, S>);
|
|
30
32
|
stop(): this;
|
|
31
33
|
atTokenEnd(): boolean;
|
|
32
|
-
hasNextToken(predicate?: (token: RGXToken | RGXPart<R>) => boolean): boolean;
|
|
34
|
+
hasNextToken(predicate?: (token: RGXToken | RGXPart<R, S>) => boolean): boolean;
|
|
33
35
|
atSourceEnd(): boolean;
|
|
34
36
|
hasNextSource(predicate?: (rest: string) => boolean): boolean;
|
|
35
37
|
lastCapture(): RGXCapture | null;
|
|
36
|
-
currentToken(): RGXTokenOrPart<R, unknown>;
|
|
38
|
+
currentToken(): RGXTokenOrPart<R, S, unknown>;
|
|
37
39
|
remainingSource(): string | null;
|
|
38
|
-
capture(token: RGXTokenOrPart<R>, includeMatch: true): RegExpExecArray;
|
|
39
|
-
capture(token: RGXTokenOrPart<R>, includeMatch?: false): string;
|
|
40
|
+
capture(token: RGXTokenOrPart<R, S>, includeMatch: true): RegExpExecArray;
|
|
41
|
+
capture(token: RGXTokenOrPart<R, S>, includeMatch?: false): string;
|
|
40
42
|
step(): RGXCapture | null;
|
|
41
43
|
stepToToken(predicate: (token: RGXTokenOrPart<R>) => boolean): this;
|
|
42
|
-
stepToPart(predicate?: (part: RGXPart<R, unknown>) => boolean): this;
|
|
44
|
+
stepToPart(predicate?: (part: RGXPart<R, S, unknown>) => boolean): this;
|
|
43
45
|
walk(): this;
|
|
44
|
-
clone(depth?: CloneDepth): RGXWalker<R>;
|
|
46
|
+
clone(depth?: CloneDepth): RGXWalker<R, S>;
|
|
45
47
|
}
|
|
46
|
-
export declare function rgxWalker<R>(...args: ConstructorParameters<typeof RGXWalker<R>>): RGXWalker<R>;
|
|
48
|
+
export declare function rgxWalker<R, S = unknown>(...args: ConstructorParameters<typeof RGXWalker<R, S>>): RGXWalker<R, S>;
|
package/dist/walker/base.js
CHANGED
|
@@ -52,6 +52,7 @@ class RGXWalker {
|
|
|
52
52
|
this.tokens = tokens;
|
|
53
53
|
this.tokenPosition = 0;
|
|
54
54
|
this.reduced = options.reduced ?? null;
|
|
55
|
+
this.share = options.share ?? null;
|
|
55
56
|
this.infinite = options.infinite ?? false;
|
|
56
57
|
this.looping = options.looping ?? false;
|
|
57
58
|
}
|
|
@@ -107,7 +108,7 @@ class RGXWalker {
|
|
|
107
108
|
let silent = false;
|
|
108
109
|
// Ask Part what to do — control flow via return values, not flags.
|
|
109
110
|
if (isPart) {
|
|
110
|
-
const control = token.beforeCapture?.(token, this);
|
|
111
|
+
const control = token.beforeCapture?.(this.share, token, this);
|
|
111
112
|
if (control === "stop") {
|
|
112
113
|
this._stopped = true;
|
|
113
114
|
return null;
|
|
@@ -127,7 +128,16 @@ class RGXWalker {
|
|
|
127
128
|
branchedToken = createBranchGroups(token.token);
|
|
128
129
|
else
|
|
129
130
|
branchedToken = createBranchGroups(token);
|
|
130
|
-
|
|
131
|
+
let capture;
|
|
132
|
+
try {
|
|
133
|
+
capture = this.capture(branchedToken, true);
|
|
134
|
+
}
|
|
135
|
+
catch (e) {
|
|
136
|
+
if (isPart && e instanceof errors_1.RGXRegexNotMatchedAtPositionError) {
|
|
137
|
+
token.afterFailure?.(e, this.share, token, this);
|
|
138
|
+
}
|
|
139
|
+
throw e;
|
|
140
|
+
}
|
|
131
141
|
const raw = isPart ? token.rawTransform(capture[0]) : capture[0];
|
|
132
142
|
const end = this.sourcePosition;
|
|
133
143
|
const value = isPart ? token.transform(raw) : raw;
|
|
@@ -148,7 +158,15 @@ class RGXWalker {
|
|
|
148
158
|
};
|
|
149
159
|
// Validate the part. If validation fails, it will throw an error, so nothing below will run.
|
|
150
160
|
if (isPart) {
|
|
151
|
-
|
|
161
|
+
try {
|
|
162
|
+
token.validate(captureResult, this.share, this);
|
|
163
|
+
}
|
|
164
|
+
catch (e) {
|
|
165
|
+
if (e instanceof errors_1.RGXPartValidationFailedError) {
|
|
166
|
+
token.afterValidationFailure?.(e, this.share, token, this);
|
|
167
|
+
}
|
|
168
|
+
throw e;
|
|
169
|
+
}
|
|
152
170
|
}
|
|
153
171
|
// Skip adding the capture if in silent mode.
|
|
154
172
|
if (!silent) {
|
|
@@ -161,7 +179,7 @@ class RGXWalker {
|
|
|
161
179
|
}
|
|
162
180
|
// Notify Part after capture
|
|
163
181
|
if (isPart) {
|
|
164
|
-
token.afterCapture?.(captureResult, token, this);
|
|
182
|
+
token.afterCapture?.(captureResult, this.share, token, this);
|
|
165
183
|
}
|
|
166
184
|
if (!this.infinite || this.tokenPosition < this.tokens.length - 1) {
|
|
167
185
|
this.tokenPosition++;
|
|
@@ -204,6 +222,7 @@ class RGXWalker {
|
|
|
204
222
|
const clone = new RGXWalker(this.source, (0, immutability_utils_1.extClone)(this.tokens, (0, immutability_utils_1.depthDecrement)(1)), {
|
|
205
223
|
startingSourcePosition: this.sourcePosition,
|
|
206
224
|
reduced: (0, immutability_utils_1.extClone)(this.reduced, (0, immutability_utils_1.depthDecrement)(1)),
|
|
225
|
+
share: (0, immutability_utils_1.extClone)(this.share, (0, immutability_utils_1.depthDecrement)(1)),
|
|
207
226
|
infinite: this.infinite,
|
|
208
227
|
looping: this.looping
|
|
209
228
|
});
|
package/dist/walker/part.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { RGXToken } from "../types";
|
|
2
2
|
import type { RGXWalker } from "./base";
|
|
3
3
|
import { CloneDepth } from "@ptolemy2002/immutability-utils";
|
|
4
|
+
import { RGXPartValidationFailedError, RGXRegexNotMatchedAtPositionError } from "../errors";
|
|
4
5
|
export type RGXPartControl = "skip" | "stop" | "silent" | void;
|
|
5
6
|
export type RGXCapture<T = unknown> = {
|
|
6
7
|
raw: string;
|
|
@@ -11,29 +12,33 @@ export type RGXCapture<T = unknown> = {
|
|
|
11
12
|
branch: number;
|
|
12
13
|
groups: Record<string, string> | null;
|
|
13
14
|
};
|
|
14
|
-
export type RGXPartOptions<R, T = string> = {
|
|
15
|
+
export type RGXPartOptions<R, S = unknown, T = string> = {
|
|
15
16
|
id: string;
|
|
16
17
|
rawTransform: (captured: string) => string;
|
|
17
18
|
transform: (captured: string) => T;
|
|
18
|
-
validate: (captured: RGXCapture<T>, part: RGXPart<R, T>, walker: RGXWalker<R>) => boolean | string;
|
|
19
|
-
beforeCapture: ((part: RGXPart<R, T>, walker: RGXWalker<R>) => RGXPartControl) | null;
|
|
20
|
-
afterCapture: ((capture: RGXCapture<T>, part: RGXPart<R, T>, walker: RGXWalker<R>) => void) | null;
|
|
19
|
+
validate: (captured: RGXCapture<T>, share: S, part: RGXPart<R, S, T>, walker: RGXWalker<R, S>) => boolean | string;
|
|
20
|
+
beforeCapture: ((share: S, part: RGXPart<R, S, T>, walker: RGXWalker<R, S>) => RGXPartControl) | null;
|
|
21
|
+
afterCapture: ((capture: RGXCapture<T>, share: S, part: RGXPart<R, S, T>, walker: RGXWalker<R, S>) => void) | null;
|
|
22
|
+
afterFailure: ((e: RGXRegexNotMatchedAtPositionError, share: S, part: RGXPart<R, S, T>, walker: RGXWalker<R, S>) => void) | null;
|
|
23
|
+
afterValidationFailure: ((e: RGXPartValidationFailedError, share: S, part: RGXPart<R, S, T>, walker: RGXWalker<R, S>) => void) | null;
|
|
21
24
|
};
|
|
22
|
-
export declare class RGXPart<R, T = string> {
|
|
25
|
+
export declare class RGXPart<R, S = unknown, T = string> {
|
|
23
26
|
id: string | null;
|
|
24
27
|
token: RGXToken;
|
|
25
|
-
readonly rawTransform: RGXPartOptions<R, T>["rawTransform"];
|
|
26
|
-
readonly transform: RGXPartOptions<R, T>["transform"];
|
|
28
|
+
readonly rawTransform: RGXPartOptions<R, S, T>["rawTransform"];
|
|
29
|
+
readonly transform: RGXPartOptions<R, S, T>["transform"];
|
|
27
30
|
private readonly _validate;
|
|
28
|
-
readonly beforeCapture: RGXPartOptions<R, T>["beforeCapture"];
|
|
29
|
-
readonly afterCapture: RGXPartOptions<R, T>["afterCapture"];
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
readonly beforeCapture: RGXPartOptions<R, S, T>["beforeCapture"];
|
|
32
|
+
readonly afterCapture: RGXPartOptions<R, S, T>["afterCapture"];
|
|
33
|
+
readonly afterFailure: RGXPartOptions<R, S, T>["afterFailure"];
|
|
34
|
+
readonly afterValidationFailure: RGXPartOptions<R, S, T>["afterValidationFailure"];
|
|
35
|
+
static check: (value: unknown) => value is RGXPart<unknown, unknown, unknown>;
|
|
36
|
+
static assert: (value: unknown) => asserts value is RGXPart<unknown, unknown, unknown>;
|
|
37
|
+
constructor(token: RGXToken, options?: Partial<RGXPartOptions<R, S, T>>);
|
|
38
|
+
hasId(): this is RGXPart<R, S, T> & {
|
|
34
39
|
id: string;
|
|
35
40
|
};
|
|
36
|
-
validate(capture: RGXCapture<T>, walker: RGXWalker<R>): void;
|
|
37
|
-
clone(depth?: CloneDepth): RGXPart<R, T>;
|
|
41
|
+
validate(capture: RGXCapture<T>, share: S, walker: RGXWalker<R, S>): void;
|
|
42
|
+
clone(depth?: CloneDepth): RGXPart<R, S, T>;
|
|
38
43
|
}
|
|
39
|
-
export declare function rgxPart<R, T = string>(...args: ConstructorParameters<typeof RGXPart<R, T>>): RGXPart<R, T>;
|
|
44
|
+
export declare function rgxPart<R, S = unknown, T = string>(...args: ConstructorParameters<typeof RGXPart<R, S, T>>): RGXPart<R, S, T>;
|
package/dist/walker/part.js
CHANGED
|
@@ -15,12 +15,14 @@ class RGXPart {
|
|
|
15
15
|
this._validate = options.validate ?? (() => true);
|
|
16
16
|
this.beforeCapture = options.beforeCapture ?? null;
|
|
17
17
|
this.afterCapture = options.afterCapture ?? null;
|
|
18
|
+
this.afterFailure = options.afterFailure ?? null;
|
|
19
|
+
this.afterValidationFailure = options.afterValidationFailure ?? null;
|
|
18
20
|
}
|
|
19
21
|
hasId() {
|
|
20
22
|
return this.id !== null;
|
|
21
23
|
}
|
|
22
|
-
validate(capture, walker) {
|
|
23
|
-
const result = this._validate(capture, this, walker);
|
|
24
|
+
validate(capture, share, walker) {
|
|
25
|
+
const result = this._validate(capture, share, this, walker);
|
|
24
26
|
if (result === true)
|
|
25
27
|
return;
|
|
26
28
|
const message = typeof result === "string" ? result : "Part Validation Failed";
|