@ptolemy2002/rgx 8.0.0 → 8.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -21,6 +21,7 @@ Because there is so much to document, it has been broken up into multiple files.
21
21
  - [collection](./docs/class/collection.md) - The `RGXTokenCollection` class, which is a collection of tokens.
22
22
  - [RGXError](./docs/class/RGXError.md) - Details on all custom error classes and the base `RGXError` class.
23
23
  - [walker](./docs/class/walker.md) - Details on both `RGXWalker` and `RGXPart`, which are used for creating custom matchers that can validate partial matches and transform captured values with custom logic.
24
+ - [lexer](./docs/class/lexer.md) - Details on `RGXLexer`, which tokenizes a source string into structured lexemes using named lexeme definitions grouped by mode.
24
25
  - `token` - A directory containing documentation for all token classes in the library, which are classes that represent specific types of tokens that can be used in regular expressions.
25
26
  - [base](./docs/class/token/base.md) - The `RGXClassToken` class, which is the base class for all token classes in the library.
26
27
  - [group](./docs/class/token/group.md) - The `RGXGroupToken` class, which represents a group of tokens that can be treated as a single unit in a regular expression.
@@ -95,6 +95,10 @@ export declare const RGX_PREDEFINED_CONSTANTS: {
95
95
  readonly rgxGroupWrap: false;
96
96
  readonly toRgx: () => RegExp;
97
97
  };
98
+ readonly "whitespace-block": {
99
+ readonly rgxGroupWrap: false;
100
+ readonly toRgx: () => RegExp;
101
+ };
98
102
  readonly "non-whitespace": {
99
103
  readonly rgxGroupWrap: false;
100
104
  readonly toRgx: () => RegExp;
package/dist/constants.js CHANGED
@@ -118,6 +118,10 @@ exports.RGX_PREDEFINED_CONSTANTS = {
118
118
  rgxGroupWrap: false,
119
119
  toRgx() { return /\s/; }
120
120
  },
121
+ "whitespace-block": {
122
+ rgxGroupWrap: false,
123
+ toRgx() { return /\s+/; }
124
+ },
121
125
  "non-whitespace": {
122
126
  rgxGroupWrap: false,
123
127
  toRgx() { return /\S/; }
@@ -1,4 +1,4 @@
1
- export type RGXErrorCode = 'UNKNOWN' | 'INVALID_RGX_TOKEN' | 'INVALID_REGEX_STRING' | 'INVALID_REGEX_FLAGS' | 'INVALID_VANILLA_REGEX_FLAGS' | 'NOT_IMPLEMENTED' | 'NOT_SUPPORTED' | 'INVALID_IDENTIFIER' | 'OUT_OF_BOUNDS' | 'INVALID_FLAG_TRANSFORMER_KEY' | 'FLAG_TRANSFORMER_CONFLICT' | 'CONSTANT_CONFLICT' | 'INVALID_CONSTANT_KEY' | 'INSERTION_REJECTED' | 'REGEX_NOT_MATCHED_AT_POSITION' | 'PART_VALIDATION_FAILED';
1
+ export type RGXErrorCode = 'UNKNOWN' | 'INVALID_RGX_TOKEN' | 'INVALID_REGEX_STRING' | 'INVALID_REGEX_FLAGS' | 'INVALID_VANILLA_REGEX_FLAGS' | 'NOT_IMPLEMENTED' | 'NOT_SUPPORTED' | 'INVALID_IDENTIFIER' | 'OUT_OF_BOUNDS' | 'INVALID_FLAG_TRANSFORMER_KEY' | 'FLAG_TRANSFORMER_CONFLICT' | 'CONSTANT_CONFLICT' | 'INVALID_CONSTANT_KEY' | 'INSERTION_REJECTED' | 'REGEX_NOT_MATCHED_AT_POSITION' | 'PART_VALIDATION_FAILED' | 'INVALID_LEXER_MODE' | 'LEXEME_NOT_MATCHED_AT_POSITION' | 'INVALID_RGX_LEXER';
2
2
  export declare class RGXError extends Error {
3
3
  _message: string;
4
4
  code: RGXErrorCode;
@@ -14,3 +14,6 @@ export * from './constantConflict';
14
14
  export * from './invalidConstantKey';
15
15
  export * from './regexNotMatchedAtPosition';
16
16
  export * from './partValidationFailed';
17
+ export * from './invalidLexerMode';
18
+ export * from './lexemeNotMatchedAtPosition';
19
+ export * from './invalidLexer';
@@ -30,3 +30,6 @@ __exportStar(require("./constantConflict"), exports);
30
30
  __exportStar(require("./invalidConstantKey"), exports);
31
31
  __exportStar(require("./regexNotMatchedAtPosition"), exports);
32
32
  __exportStar(require("./partValidationFailed"), exports);
33
+ __exportStar(require("./invalidLexerMode"), exports);
34
+ __exportStar(require("./lexemeNotMatchedAtPosition"), exports);
35
+ __exportStar(require("./invalidLexer"), exports);
@@ -0,0 +1,7 @@
1
+ import { RGXError } from "./";
2
+ export declare class RGXInvalidLexerError extends RGXError {
3
+ constructorName: string;
4
+ got: unknown;
5
+ constructor(message: string, got: unknown, constructorName?: string);
6
+ calcMessage(message: string): string;
7
+ }
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RGXInvalidLexerError = void 0;
4
+ const errors_1 = require("./");
5
+ const class_1 = require("../class");
6
+ class RGXInvalidLexerError extends errors_1.RGXError {
7
+ constructor(message, got, constructorName = "RGXLexer") {
8
+ super(message, 'INVALID_RGX_LEXER');
9
+ this.name = 'RGXInvalidLexerError';
10
+ this.got = got;
11
+ this.constructorName = constructorName;
12
+ }
13
+ calcMessage(message) {
14
+ const gotString = class_1.RGXClassToken.check(this.got) ? `instance of ${this.got.constructor.name}` : JSON.stringify(this.got);
15
+ return `${message}; Expected: [instance of ${this.constructorName}]; Got: [${gotString}]`;
16
+ }
17
+ }
18
+ exports.RGXInvalidLexerError = RGXInvalidLexerError;
@@ -0,0 +1,6 @@
1
+ import { RGXError } from "./";
2
+ export declare class RGXInvalidLexerModeError extends RGXError {
3
+ got: string;
4
+ constructor(message: string, got: string);
5
+ calcMessage(message: string): string;
6
+ }
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RGXInvalidLexerModeError = void 0;
4
+ const errors_1 = require("./");
5
+ class RGXInvalidLexerModeError extends errors_1.RGXError {
6
+ constructor(message, got) {
7
+ super(message, 'INVALID_LEXER_MODE');
8
+ this.name = 'RGXInvalidLexerModeError';
9
+ this.got = got;
10
+ }
11
+ calcMessage(message) {
12
+ return `${message}; Got: ${JSON.stringify(this.got)}`;
13
+ }
14
+ }
15
+ exports.RGXInvalidLexerModeError = RGXInvalidLexerModeError;
@@ -0,0 +1,22 @@
1
+ import { RGXError, RGXPartValidationFailedError, RGXRegexNotMatchedAtPositionError } from "./";
2
+ export type LexemeNotMatchedCauseError = RGXRegexNotMatchedAtPositionError | RGXPartValidationFailedError;
3
+ export type LexemeNotMatchedCause = {
4
+ id: string;
5
+ error: LexemeNotMatchedCauseError;
6
+ };
7
+ export declare function isLexemeNotMatchedCauseError(error: unknown): error is LexemeNotMatchedCauseError;
8
+ export declare class RGXLexemeNotMatchedAtPositionError extends RGXError {
9
+ source: string;
10
+ mode: string;
11
+ _position: number;
12
+ contextSize: number | null;
13
+ causes: LexemeNotMatchedCause[];
14
+ get position(): number;
15
+ set position(value: number);
16
+ constructor(message: string, source: string, mode: string, position: number, causes?: LexemeNotMatchedCause[], contextSize?: number | null);
17
+ sourceContext(): string;
18
+ hasLeftContext(): boolean;
19
+ hasRightContext(): boolean;
20
+ hasFullContext(): boolean;
21
+ calcMessage(message: string): string;
22
+ }
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RGXLexemeNotMatchedAtPositionError = void 0;
4
+ exports.isLexemeNotMatchedCauseError = isLexemeNotMatchedCauseError;
5
+ const errors_1 = require("./");
6
+ function isLexemeNotMatchedCauseError(error) {
7
+ return error instanceof errors_1.RGXRegexNotMatchedAtPositionError || error instanceof errors_1.RGXPartValidationFailedError;
8
+ }
9
+ class RGXLexemeNotMatchedAtPositionError extends errors_1.RGXError {
10
+ get position() {
11
+ return this._position;
12
+ }
13
+ set position(value) {
14
+ (0, errors_1.assertInRange)(value, { min: 0, max: this.source.length }, "position is outside the bounds of the source string");
15
+ this._position = value;
16
+ }
17
+ constructor(message, source, mode, position, causes = [], contextSize = null) {
18
+ super(message, 'LEXEME_NOT_MATCHED_AT_POSITION');
19
+ this.name = 'RGXLexemeNotMatchedAtPositionError';
20
+ this.source = source;
21
+ this.mode = mode;
22
+ this.position = position;
23
+ this.causes = causes;
24
+ this.contextSize = contextSize;
25
+ }
26
+ sourceContext() {
27
+ if (this.hasFullContext())
28
+ return this.source;
29
+ const start = Math.max(0, this.position - this.contextSize);
30
+ const end = Math.min(this.source.length, this.position + this.contextSize);
31
+ return this.source.slice(start, end);
32
+ }
33
+ hasLeftContext() {
34
+ if (this.contextSize === null)
35
+ return false;
36
+ return this.position - this.contextSize >= 0;
37
+ }
38
+ hasRightContext() {
39
+ if (this.contextSize === null)
40
+ return false;
41
+ return this.position + this.contextSize <= this.source.length;
42
+ }
43
+ hasFullContext() {
44
+ return !this.hasLeftContext() && !this.hasRightContext();
45
+ }
46
+ calcMessage(message) {
47
+ let context = this.sourceContext();
48
+ if (this.contextSize !== null) {
49
+ if (this.hasLeftContext())
50
+ context = `...${context}`;
51
+ if (this.hasRightContext())
52
+ context = `${context}...`;
53
+ }
54
+ return `${message}; Mode: ${this.mode}, Position: ${this.position}, Context: ${context}`;
55
+ }
56
+ }
57
+ exports.RGXLexemeNotMatchedAtPositionError = RGXLexemeNotMatchedAtPositionError;
@@ -5,7 +5,7 @@ const base_1 = require("./base");
5
5
  const outOfBounds_1 = require("./outOfBounds");
6
6
  class RGXRegexNotMatchedAtPositionError extends base_1.RGXError {
7
7
  set position(value) {
8
- (0, outOfBounds_1.assertInRange)(value, { min: 0, max: this.source.length, inclusiveRight: false }, "position is outside the bounds of the source string");
8
+ (0, outOfBounds_1.assertInRange)(value, { min: 0, max: this.source.length }, "position is outside the bounds of the source string");
9
9
  this._position = value;
10
10
  }
11
11
  get position() {
package/dist/index.d.ts CHANGED
@@ -14,6 +14,7 @@ export * from "./flag-transformer";
14
14
  export * from "./clone";
15
15
  export * from "./constants";
16
16
  export * from "./walker";
17
+ export * from "./lexer";
17
18
  export declare function rgxa(tokens: t.RGXToken[], flags?: string): ExtRegExp;
18
19
  export default function rgx(flags?: string, multiline?: boolean): (strings: TemplateStringsArray, ...tokens: t.RGXToken[]) => ExtRegExp;
19
20
  export declare function rgxwa<R = unknown, T = unknown>(source: string, tokens: RGXTokenOrPart<R, T>[], options?: Omit<t.RGXWOptions<R>, "multiline">): RGXWalker<R>;
package/dist/index.js CHANGED
@@ -37,6 +37,7 @@ __exportStar(require("./flag-transformer"), exports);
37
37
  __exportStar(require("./clone"), exports);
38
38
  __exportStar(require("./constants"), exports);
39
39
  __exportStar(require("./walker"), exports);
40
+ __exportStar(require("./lexer"), exports);
40
41
  // Call this for certain class methods to work correctly
41
42
  (0, class_1.rgxClassInit)();
42
43
  // Call this for our custom flags to work correctly
@@ -1,2 +1,3 @@
1
+ import { RGXError } from "../errors";
1
2
  export declare function createClassGuardFunction<T extends new (...args: unknown[]) => unknown>(constructor: T): (value: unknown) => value is InstanceType<T>;
2
- export declare function createAssertClassGuardFunction<T extends new (...args: unknown[]) => unknown>(constructor: T): (value: unknown) => asserts value is InstanceType<T>;
3
+ export declare function createAssertClassGuardFunction<T extends new (...args: unknown[]) => unknown>(constructor: T, constructError?: (value: unknown, constructor: T) => RGXError): (value: unknown) => asserts value is InstanceType<T>;
@@ -6,10 +6,10 @@ const errors_1 = require("../errors");
6
6
  function createClassGuardFunction(constructor) {
7
7
  return (value) => value instanceof constructor;
8
8
  }
9
- function createAssertClassGuardFunction(constructor) {
9
+ function createAssertClassGuardFunction(constructor, constructError = (value, constructor) => new errors_1.RGXInvalidTokenError("Invalid token type", { type: "custom", values: [`instance of ${constructor.name}`] }, value)) {
10
10
  return (value) => {
11
11
  if (!(value instanceof constructor)) {
12
- throw new errors_1.RGXInvalidTokenError("Invalid token type", { type: "custom", values: [`instance of ${constructor.name}`] }, value);
12
+ throw constructError(value, constructor);
13
13
  }
14
14
  };
15
15
  }
@@ -0,0 +1,59 @@
1
+ import { RGXToken } from "../types";
2
+ import { RGXTokenOrPart, RGXWalkerOptions } from "../walker";
3
+ export type RGXLexemeDefinition<Data> = Readonly<({
4
+ type: "resolve";
5
+ token: RGXToken;
6
+ } | {
7
+ type: "walk";
8
+ tokens: RGXTokenOrPart<Data>[];
9
+ options?: Omit<RGXWalkerOptions<Data>, "startingSourcePosition" | "reduced"> & {
10
+ reduced?: (() => Data) | null;
11
+ };
12
+ }) & {
13
+ id: string;
14
+ priority?: number;
15
+ }>;
16
+ export type RGXLexeme<Data> = {
17
+ id: string;
18
+ raw: string;
19
+ start: RGXLexemeLocation;
20
+ end: RGXLexemeLocation;
21
+ data?: Data;
22
+ };
23
+ export type RGXLexemeDefinitions<Data> = Readonly<Record<string, ReadonlyArray<RGXLexemeDefinition<Data>>>>;
24
+ export type RGXLexemeLocation = {
25
+ index: number;
26
+ line: number;
27
+ column: number;
28
+ };
29
+ export declare function rgxLexemeLocationFromIndex(source: string, index: number): RGXLexemeLocation;
30
+ export declare class RGXLexer<Data> {
31
+ readonly source: string;
32
+ _position: number;
33
+ readonly lexemeDefinitions: RGXLexemeDefinitions<Data>;
34
+ readonly matched: RGXLexeme<Data>[];
35
+ static check: (value: unknown) => value is RGXLexer<unknown>;
36
+ static assert: (value: unknown) => asserts value is RGXLexer<unknown>;
37
+ get position(): number;
38
+ set position(value: number);
39
+ constructor(source: string, lexemeDefinitions?: RGXLexemeDefinitions<Data>, startingPosition?: number);
40
+ private matchDefinition;
41
+ private next;
42
+ private expect;
43
+ validateMode(value: string): void;
44
+ lastMatched(): RGXLexeme<Data> | null;
45
+ hasNext(): boolean;
46
+ isAtEnd(): boolean;
47
+ remaining(): string;
48
+ backtrack(tokens?: number): void;
49
+ consume(mode?: string, log?: boolean): RGXLexeme<Data> | null;
50
+ peek(mode?: string): RGXLexeme<Data> | null;
51
+ expectConsume(id: string, mode?: string, log?: boolean): RGXLexeme<Data>;
52
+ expectPeek(id: string, mode?: string): RGXLexeme<Data>;
53
+ skip(count?: number, mode?: string): void;
54
+ skipWhitespace(): void;
55
+ consumeAll(mode?: string, skipWhitespace?: boolean): RGXLexeme<Data>[];
56
+ consumeWhile(predicate: (lexeme: RGXLexeme<Data>) => boolean, mode?: string, skipWhitespace?: boolean): RGXLexeme<Data>[];
57
+ consumeUntil(predicate: (lexeme: RGXLexeme<Data>) => boolean, mode?: string, skipWhitespace?: boolean): RGXLexeme<Data>[];
58
+ }
59
+ export declare const rgxLexer: <Data>(...args: ConstructorParameters<typeof RGXLexer<Data>>) => RGXLexer<Data>;
@@ -0,0 +1,198 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.rgxLexer = exports.RGXLexer = void 0;
4
+ exports.rgxLexemeLocationFromIndex = rgxLexemeLocationFromIndex;
5
+ const resolve_1 = require("../resolve");
6
+ const errors_1 = require("../errors");
7
+ const walker_1 = require("../walker");
8
+ const utils_1 = require("../utils");
9
+ const internal_1 = require("../internal");
10
+ const constants_1 = require("../constants");
11
+ function rgxLexemeLocationFromIndex(source, index) {
12
+ (0, errors_1.assertInRange)(index, { min: 0, max: source.length }, "index is outside the bounds of the source string");
13
+ const lines = source.slice(0, index).split("\n");
14
+ const line = lines.length;
15
+ const column = lines[lines.length - 1].length + 1;
16
+ return { index, line, column };
17
+ }
18
+ class RGXLexer {
19
+ get position() {
20
+ return this._position;
21
+ }
22
+ set position(value) {
23
+ (0, errors_1.assertInRange)(value, { min: 0, max: this.source.length }, "position is outside the bounds of the source string");
24
+ this._position = Math.floor(value);
25
+ }
26
+ constructor(source, lexemeDefinitions = {}, startingPosition = 0) {
27
+ this.matched = [];
28
+ // Copy to ensure we don't modify the original, which will be used across constructions.
29
+ const lexemeDefinitionsCopy = { ...lexemeDefinitions };
30
+ lexemeDefinitionsCopy["default"] ??= [];
31
+ this.source = source;
32
+ this.lexemeDefinitions = Object.fromEntries(Object.entries(lexemeDefinitionsCopy).map(([mode, defs]) => [
33
+ mode, [...defs].sort(
34
+ // Sort by priority, with higher priority first. If no priority is specified, it defaults to 0.
35
+ (a, b) => (b.priority ?? 0) - (a.priority ?? 0))
36
+ ]));
37
+ this.position = startingPosition;
38
+ }
39
+ matchDefinition(lexemeDefinition, advance) {
40
+ const id = lexemeDefinition.id;
41
+ const startPosition = this.position;
42
+ let endPosition;
43
+ let raw;
44
+ let dataPart = {};
45
+ if (lexemeDefinition.type === "resolve") {
46
+ const { token } = lexemeDefinition;
47
+ const regex = new RegExp((0, resolve_1.resolveRGXToken)(token));
48
+ // Since the assertion will throw an error if there is no match, this is safe.
49
+ const match = (0, utils_1.assertRegexMatchesAtPosition)(regex, this.source, startPosition, 10, true);
50
+ raw = match[0];
51
+ endPosition = startPosition + raw.length;
52
+ // No data part for token lexemes.
53
+ }
54
+ else {
55
+ const { tokens, options: { reduced, ...options } = {} } = lexemeDefinition;
56
+ const walker = new walker_1.RGXWalker(this.source, tokens, {
57
+ ...options,
58
+ reduced: reduced?.() ?? undefined,
59
+ startingSourcePosition: startPosition
60
+ });
61
+ // 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.
62
+ walker.walk();
63
+ raw = this.source.slice(startPosition, walker.sourcePosition);
64
+ endPosition = walker.sourcePosition;
65
+ dataPart.data = walker.reduced;
66
+ }
67
+ if (advance) {
68
+ this.position = endPosition;
69
+ }
70
+ return {
71
+ id,
72
+ raw,
73
+ start: rgxLexemeLocationFromIndex(this.source, startPosition),
74
+ end: rgxLexemeLocationFromIndex(this.source, endPosition),
75
+ ...dataPart
76
+ };
77
+ }
78
+ next(mode, advance, log) {
79
+ if (this.isAtEnd())
80
+ return null;
81
+ this.validateMode(mode);
82
+ const lexemeDefs = this.lexemeDefinitions[mode];
83
+ const causes = [];
84
+ for (const lexemeDef of lexemeDefs) {
85
+ try {
86
+ const lexeme = this.matchDefinition(lexemeDef, advance);
87
+ if (advance && log)
88
+ this.matched.push(lexeme);
89
+ return lexeme;
90
+ }
91
+ catch (e) {
92
+ if ((0, errors_1.isLexemeNotMatchedCauseError)(e)) {
93
+ // Log the error as a cause and continue trying other lexeme definitions.
94
+ causes.push({ id: lexemeDef.id, error: e });
95
+ }
96
+ else {
97
+ // If it's an unexpected error, rethrow it.
98
+ throw e;
99
+ }
100
+ }
101
+ }
102
+ // If no lexeme definitions matched, throw an error.
103
+ throw new errors_1.RGXLexemeNotMatchedAtPositionError("No lexeme definition matched", this.source, mode, this.position, causes);
104
+ }
105
+ expect(id, mode, consume, log) {
106
+ const lexeme = consume ? this.consume(mode, log) : this.peek(mode);
107
+ if (!lexeme || lexeme.id !== id) {
108
+ throw new errors_1.RGXLexemeNotMatchedAtPositionError(`Expected lexeme "${id}" but got ${lexeme?.id ? `lexeme "${lexeme.id}"` : "source end"}`, this.source, mode, this.position);
109
+ }
110
+ return lexeme;
111
+ }
112
+ validateMode(value) {
113
+ if (!(value in this.lexemeDefinitions)) {
114
+ throw new errors_1.RGXInvalidLexerModeError("Lexer mode does not exist in this lexer", value);
115
+ }
116
+ }
117
+ lastMatched() {
118
+ if (this.matched.length === 0)
119
+ return null;
120
+ return this.matched[this.matched.length - 1];
121
+ }
122
+ hasNext() {
123
+ return this.position < this.source.length;
124
+ }
125
+ isAtEnd() {
126
+ return !this.hasNext();
127
+ }
128
+ remaining() {
129
+ return this.source.slice(this.position);
130
+ }
131
+ backtrack(tokens = 1) {
132
+ if (tokens <= 0)
133
+ return;
134
+ (0, errors_1.assertInRange)(tokens, { max: this.matched.length }, "Cannot backtrack more tokens than have been matched");
135
+ const targetLexeme = this.matched[this.matched.length - tokens];
136
+ this.position = targetLexeme.start.index;
137
+ this.matched.splice(this.matched.length - tokens, tokens);
138
+ }
139
+ consume(mode = "default", log = true) {
140
+ return this.next(mode, true, log);
141
+ }
142
+ peek(mode = "default") {
143
+ return this.next(mode, false, false);
144
+ }
145
+ expectConsume(id, mode = "default", log = true) {
146
+ return this.expect(id, mode, true, log);
147
+ }
148
+ expectPeek(id, mode = "default") {
149
+ return this.expect(id, mode, false, false);
150
+ }
151
+ skip(count = 1, mode = "default") {
152
+ for (let i = 0; i < count; i++) {
153
+ if (!this.hasNext())
154
+ break;
155
+ this.consume(mode, false);
156
+ }
157
+ }
158
+ skipWhitespace() {
159
+ if (this.isAtEnd())
160
+ return;
161
+ const regex = new RegExp((0, resolve_1.resolveRGXToken)((0, constants_1.rgxConstant)("whitespace-block")));
162
+ const match = (0, utils_1.regexMatchAtPosition)(regex, this.source, this.position, true);
163
+ if (match !== null) {
164
+ this.position += match[0].length;
165
+ }
166
+ }
167
+ consumeAll(mode = "default", skipWhitespace = true) {
168
+ const lexemes = [];
169
+ while (this.hasNext()) {
170
+ if (skipWhitespace)
171
+ this.skipWhitespace();
172
+ const lexeme = this.consume(mode);
173
+ if (lexeme)
174
+ lexemes.push(lexeme);
175
+ }
176
+ return lexemes;
177
+ }
178
+ consumeWhile(predicate, mode = "default", skipWhitespace = true) {
179
+ const lexemes = [];
180
+ while (this.hasNext()) {
181
+ if (skipWhitespace)
182
+ this.skipWhitespace();
183
+ const next = this.consume(mode);
184
+ if (!next || !predicate(next))
185
+ break;
186
+ lexemes.push(next);
187
+ }
188
+ return lexemes;
189
+ }
190
+ consumeUntil(predicate, mode = "default", skipWhitespace = true) {
191
+ return this.consumeWhile(lexeme => !predicate(lexeme), mode, skipWhitespace);
192
+ }
193
+ }
194
+ exports.RGXLexer = RGXLexer;
195
+ RGXLexer.check = (0, internal_1.createClassGuardFunction)(RGXLexer);
196
+ RGXLexer.assert = (0, internal_1.createAssertClassGuardFunction)(RGXLexer, (value, c) => new errors_1.RGXInvalidLexerError("Invalid Lexer", value, c.name));
197
+ const rgxLexer = (...args) => new RGXLexer(...args);
198
+ exports.rgxLexer = rgxLexer;
@@ -0,0 +1 @@
1
+ export * from "./base";
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./base"), exports);
package/dist/types.d.ts CHANGED
@@ -3,7 +3,6 @@ import type { RGXClassToken } from "./class";
3
3
  import type { ExtRegExp } from "./ExtRegExp";
4
4
  import type { RGXTokenCollection } from "./collection";
5
5
  import type { RGXWalkerOptions } from "./walker";
6
- import type { RGXPart, RGXWalker } from "./walker";
7
6
  export type RGXNoOpToken = null | undefined;
8
7
  export type RGXLiteralToken = RegExp;
9
8
  export type RGXNativeToken = string | number | boolean | RGXNoOpToken;
@@ -28,7 +27,7 @@ export type RGXRepeatableConvertibleToken = RGXConvertibleToken & {
28
27
  };
29
28
  export type RGXTokenType = 'no-op' | 'literal' | 'native' | 'convertible' | 'class' | RGXTokenType[];
30
29
  export type RGXTokenTypeFlat = Exclude<RGXTokenType, RGXTokenType[]> | "array";
31
- export type RGXTokenTypeGuardInput = "repeatable" | RGXTokenTypeFlat | null | RGXClassTokenConstructor | typeof RegExp | typeof ExtRegExp | typeof RGXTokenCollection | typeof RGXWalker | typeof RGXPart | RGXTokenTypeGuardInput[];
30
+ export type RGXTokenTypeGuardInput = "repeatable" | RGXTokenTypeFlat | null | RGXClassTokenConstructor | typeof RegExp | typeof ExtRegExp | typeof RGXTokenCollection | RGXTokenTypeGuardInput[];
32
31
  export type RGXTokenFromType<T extends RGXTokenTypeGuardInput> = T extends null ? RGXToken : T extends 'no-op' ? RGXNoOpToken : T extends 'literal' ? RGXLiteralToken : T extends 'native' ? RGXNativeToken : T extends 'convertible' ? RGXConvertibleToken : T extends 'class' ? RGXClassToken : T extends 'array' ? RGXToken[] : T extends 'repeatable' ? Exclude<RGXToken, RGXConvertibleToken> | RGXRepeatableConvertibleToken : T extends new (...args: unknown[]) => infer R ? R : T extends RGXTokenTypeGuardInput[] ? {
33
32
  [K in keyof T]: T[K] extends RGXTokenTypeGuardInput ? RGXTokenFromType<T[K]> : never;
34
33
  } : never;
@@ -6,17 +6,20 @@ const immutability_utils_1 = require("@ptolemy2002/immutability-utils");
6
6
  const collection_1 = require("../collection");
7
7
  const errors_1 = require("../errors");
8
8
  const part_1 = require("./part");
9
- const index_1 = require("../index");
9
+ const resolve_1 = require("../resolve");
10
+ const utils_1 = require("../utils");
11
+ const typeGuards_1 = require("../typeGuards");
12
+ const class_1 = require("../class");
10
13
  const internal_1 = require("../internal");
11
14
  function createBranchGroups(tokens) {
12
15
  if ((tokens instanceof collection_1.RGXTokenCollection && tokens.mode === "union") ||
13
- index_1.RGXClassUnionToken.check(tokens))
16
+ class_1.RGXClassUnionToken.check(tokens))
14
17
  return createBranchGroups(tokens.tokens);
15
- if ((0, index_1.isRGXArrayToken)(tokens)) {
18
+ if ((0, typeGuards_1.isRGXArrayToken)(tokens)) {
16
19
  const newTokens = tokens.map((token, i) => {
17
- return new index_1.RGXGroupToken({ name: `rgx_branch_${i}` }, [token]);
20
+ return new class_1.RGXGroupToken({ name: `rgx_branch_${i}` }, [token]);
18
21
  });
19
- return new index_1.RGXClassUnionToken(newTokens);
22
+ return new class_1.RGXClassUnionToken(newTokens);
20
23
  }
21
24
  else {
22
25
  return tokens;
@@ -28,14 +31,14 @@ class RGXWalker {
28
31
  }
29
32
  set sourcePosition(value) {
30
33
  (0, errors_1.assertInRange)(value, { min: 0, max: this.source.length }, "sourcePosition is outside the bounds of the source string");
31
- this._sourcePosition = value;
34
+ this._sourcePosition = Math.floor(value);
32
35
  }
33
36
  get tokenPosition() {
34
37
  return this._tokenPosition;
35
38
  }
36
39
  set tokenPosition(value) {
37
40
  (0, errors_1.assertInRange)(value, { min: 0, max: this.tokens.length }, "tokenPosition is outside the bounds of the token collection");
38
- this._tokenPosition = value;
41
+ this._tokenPosition = Math.floor(value);
39
42
  }
40
43
  get stopped() {
41
44
  return this._stopped;
@@ -84,8 +87,8 @@ class RGXWalker {
84
87
  return this.source.slice(this.sourcePosition);
85
88
  }
86
89
  capture(token, includeMatch = false) {
87
- const regex = (0, index_1.rgxa)([part_1.RGXPart.check(token) ? token.token : token]);
88
- const match = (0, index_1.assertRegexMatchesAtPosition)(regex, this.source, this.sourcePosition, 10, true);
90
+ const regex = new RegExp((0, resolve_1.resolveRGXToken)(part_1.RGXPart.check(token) ? token.token : token));
91
+ const match = (0, utils_1.assertRegexMatchesAtPosition)(regex, this.source, this.sourcePosition, 10, true);
89
92
  this.sourcePosition += match[0].length;
90
93
  return includeMatch ? match : match[0];
91
94
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ptolemy2002/rgx",
3
- "version": "8.0.0",
3
+ "version": "8.1.0",
4
4
  "private": false,
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",