@ptolemy2002/rgx 5.5.0 → 6.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 +171 -3
- package/dist/collection.d.ts +2 -2
- package/dist/errors/base.d.ts +1 -1
- package/dist/errors/index.d.ts +2 -0
- package/dist/errors/index.js +2 -0
- package/dist/errors/partValidationFailed.d.ts +7 -0
- package/dist/errors/partValidationFailed.js +16 -0
- package/dist/errors/regexNotMatchedAtPosition.d.ts +15 -0
- package/dist/errors/regexNotMatchedAtPosition.js +53 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/utils/regexMatchAtPosition.d.ts +3 -1
- package/dist/utils/regexMatchAtPosition.js +15 -1
- package/dist/walker/base.d.ts +41 -0
- package/dist/walker/base.js +161 -0
- package/dist/walker/index.d.ts +2 -0
- package/dist/walker/index.js +18 -0
- package/dist/walker/part.d.ts +30 -0
- package/dist/walker/part.js +56 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -54,7 +54,7 @@ type RGXTokenFromType<T extends RGXTokenTypeGuardInput> =
|
|
|
54
54
|
// ... see source for full definition
|
|
55
55
|
;
|
|
56
56
|
|
|
57
|
-
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';
|
|
57
|
+
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';
|
|
58
58
|
|
|
59
59
|
type RangeObject = {
|
|
60
60
|
min?: number | null;
|
|
@@ -78,6 +78,25 @@ type RGXGroupTokenArgs = {
|
|
|
78
78
|
name?: string | null;
|
|
79
79
|
capturing?: boolean;
|
|
80
80
|
};
|
|
81
|
+
|
|
82
|
+
type RGXPartControl = "skip" | "stop" | "silent" | void;
|
|
83
|
+
|
|
84
|
+
type RGXCapture<T = unknown> = {
|
|
85
|
+
raw: string;
|
|
86
|
+
value: T;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
type RGXPartOptions<R, T=string> = {
|
|
90
|
+
transform: (captured: string) => T;
|
|
91
|
+
validate: (captured: RGXCapture<T>, part: RGXPart<R, T>, walker: RGXWalker<R>) => boolean | string;
|
|
92
|
+
beforeCapture: ((part: RGXPart<R, T>, walker: RGXWalker<R>) => RGXPartControl) | null;
|
|
93
|
+
afterCapture: ((capture: RGXCapture<T>, part: RGXPart<R, T>, walker: RGXWalker<R>) => void) | null;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
type RGXWalkerOptions<R> = {
|
|
97
|
+
startingSourcePosition?: number;
|
|
98
|
+
reduced?: R;
|
|
99
|
+
};
|
|
81
100
|
```
|
|
82
101
|
|
|
83
102
|
## Classes
|
|
@@ -257,6 +276,31 @@ constructor(reason?: string | null, message?: string | null)
|
|
|
257
276
|
#### Properties
|
|
258
277
|
- `reason` (`string | null`): The reason the insertion was rejected, or `null` if no reason was provided.
|
|
259
278
|
|
|
279
|
+
### RGXRegexNotMatchedAtPositionError extends RGXError
|
|
280
|
+
A specific error class for regex match failures at a given position. This error is thrown when a regex is expected to match at a specific position in a string but does not (e.g., via `assertRegexMatchesAtPosition`). The error code is set to `REGEX_NOT_MATCHED_AT_POSITION` on instantiation.
|
|
281
|
+
|
|
282
|
+
#### Constructor
|
|
283
|
+
```typescript
|
|
284
|
+
constructor(message: string, pattern: RegExp, source: string, position: number, contextSize?: number | null)
|
|
285
|
+
```
|
|
286
|
+
- `message` (`string`): The error message.
|
|
287
|
+
- `pattern` (`RegExp`): The regex pattern that failed to match.
|
|
288
|
+
- `source` (`string`): The string that was being matched against.
|
|
289
|
+
- `position` (`number`): The zero-based index in the source string where the match was expected. Must be >= 0 and < `source.length`, or an `RGXOutOfBoundsError` will be thrown.
|
|
290
|
+
- `contextSize` (`number | null`, optional): The number of characters on each side of the position to include in contextual output. Defaults to `null` (full source shown).
|
|
291
|
+
|
|
292
|
+
#### Properties
|
|
293
|
+
- `pattern` (`RegExp`): The regex pattern that failed to match.
|
|
294
|
+
- `source` (`string`): The string that was being matched against.
|
|
295
|
+
- `position` (`number`): The position where the match was expected. Setting this validates that the value is >= 0 and < `source.length`, throwing `RGXOutOfBoundsError` if not.
|
|
296
|
+
- `contextSize` (`number | null`): The number of characters on each side of the position to include in contextual output, or `null` for the full source.
|
|
297
|
+
|
|
298
|
+
#### Methods
|
|
299
|
+
- `sourceContext() => string`: Returns the relevant portion of the source string around the position. When `contextSize` is `null` or covers the entire string, returns the full source. Otherwise, returns a substring from `max(0, position - contextSize)` to `min(source.length, position + contextSize)`.
|
|
300
|
+
- `hasLeftContext() => boolean`: Returns `true` if the context window starts after the beginning of the source string (i.e., there is truncated content on the left). Returns `false` when `contextSize` is `null`.
|
|
301
|
+
- `hasRightContext() => boolean`: Returns `true` if the context window ends before the end of the source string (i.e., there is truncated content on the right). Returns `false` when `contextSize` is `null`.
|
|
302
|
+
- `hasFullContext() => boolean`: Returns `true` when the full source is shown (neither side is truncated). This is the case when `contextSize` is `null` or when the context window covers the entire source string.
|
|
303
|
+
|
|
260
304
|
### RGXOutOfBoundsError extends RGXError
|
|
261
305
|
A specific error class for out-of-bounds values. This error is thrown when a numeric value falls outside an expected range. The error code is set to `OUT_OF_BOUNDS` on instantiation.
|
|
262
306
|
|
|
@@ -283,6 +327,21 @@ constructor(message: string, got: number, { min, max, inclusiveLeft, inclusiveRi
|
|
|
283
327
|
- `failedAtMax() => boolean`: Returns `true` if the `got` value is above the maximum bound (respecting `inclusiveRight`), otherwise `false`. Returns `false` if `max` is `null`.
|
|
284
328
|
- `failedAtAny() => boolean`: Returns `true` if the value failed at either the minimum or maximum bound.
|
|
285
329
|
|
|
330
|
+
### RGXPartValidationFailedError extends RGXError
|
|
331
|
+
A specific error class for RGX part validation failures. This error is thrown when a captured value fails validation in a custom part's `validate` function. The error code is set to `PART_VALIDATION_FAILED` on instantiation.
|
|
332
|
+
|
|
333
|
+
#### Constructor
|
|
334
|
+
```typescript
|
|
335
|
+
constructor(message: string, gotRaw: string, gotTransformed: unknown)
|
|
336
|
+
```
|
|
337
|
+
- `message` (`string`): The error message.
|
|
338
|
+
- `gotRaw` (`string`): The raw captured string value that failed validation.
|
|
339
|
+
- `gotTransformed` (`unknown`): The transformed value that was produced by the part's `transform` function, which also failed validation.
|
|
340
|
+
|
|
341
|
+
#### Properties
|
|
342
|
+
- `gotRaw` (`string`): The raw captured string value that failed validation.
|
|
343
|
+
- `gotTransformed` (`unknown`): The transformed value that was produced by the part's `transform` function, which also failed validation.
|
|
344
|
+
|
|
286
345
|
### RGXTokenCollection
|
|
287
346
|
A class representing a collection of RGX tokens. This class manages collections of RGX tokens like an array, but with additional metadata about the collection mode (union or concat). Since `toRgx()` returns a `RegExp`, instances of this class satisfy the `RGXConvertibleToken` interface and can be used directly as tokens in `rgx`, `rgxa`, and other token-accepting functions.
|
|
288
347
|
|
|
@@ -536,6 +595,84 @@ constructor(pattern: string | RegExp, flags?: string)
|
|
|
536
595
|
#### Static Properties
|
|
537
596
|
- `[Symbol.species]` (`RegExpConstructor`): Returns `ExtRegExp`, ensuring that derived `RegExp` methods (like those returning new regex instances) produce `ExtRegExp` instances rather than plain `RegExp`.
|
|
538
597
|
|
|
598
|
+
### RGXPart\<R, T=string\>
|
|
599
|
+
A class that wraps an `RGXToken` with optional callbacks for use within an `RGXWalker`. It implements `RGXConvertibleToken`, delegating `rgxIsGroup` and `rgxIsRepeatable` to the wrapped token. Unlike plain tokens, Parts can control walker behavior via `beforeCapture` (returning an `RGXPartControl` value) and react to captures via `afterCapture`. Parts are purely definitions and do not store capture state — all captures are stored on the walker as `RGXCapture` objects.
|
|
600
|
+
|
|
601
|
+
A function `rgxPart` is provided with the same parameters as this class' constructor, for easier instantiation without needing to use the `new` keyword.
|
|
602
|
+
|
|
603
|
+
#### Static Properties
|
|
604
|
+
- `check(value: unknown): value is RGXPart`: A type guard that checks if the given value is an instance of `RGXPart`.
|
|
605
|
+
- `assert(value: unknown): asserts value is RGXPart`: An assertion that checks if the given value is an instance of `RGXPart`. If the assertion fails, an `RGXInvalidTokenError` will be thrown.
|
|
606
|
+
|
|
607
|
+
#### Constructor
|
|
608
|
+
```typescript
|
|
609
|
+
constructor(token: RGXToken, options?: Partial<RGXPartOptions<R, T>>)
|
|
610
|
+
```
|
|
611
|
+
- `token` (`RGXToken`): The token to wrap.
|
|
612
|
+
- `options` (`Partial<RGXPartOptions<R, T>>`, optional): Configuration options. Defaults to `{}`.
|
|
613
|
+
- `transform` (`(captured: string) => T`, optional): A function that transforms the captured string into the desired type `T`. Defaults to an identity function that casts the string to `T`.
|
|
614
|
+
- `beforeCapture` (`((part: RGXPart<R, T>, walker: RGXWalker<R>) => RGXPartControl) | null`, optional): A callback invoked before capturing this part during walking. Returns an `RGXPartControl` value to control walker behavior: `"skip"` to skip this token without capturing, `"silent"` to capture but not record in `captures`, `"stop"` to halt immediately without capturing or advancing, or `void`/`undefined` to proceed normally. Defaults to `null`.
|
|
615
|
+
- `afterCapture` (`((capture: RGXCapture<T>, part: RGXPart<R, T>, walker: RGXWalker<R>) => void) | null`, optional): A callback invoked after capturing this part during walking. Receives the typed `RGXCapture<T>` result. Can call `walker.stop()` to halt walking after this capture. Defaults to `null`.
|
|
616
|
+
- `validate` (`((capture: RGXCapture<T>, walker: RGXWalker<R>) => boolean | string) | null`, optional): A callback invoked during validation after capturing and transforming, but before `afterCapture`. Returns `true` if validation passes, `false` to fail with a generic error, or a string to fail with that string as the error message. Defaults to `null`.
|
|
617
|
+
|
|
618
|
+
#### Properties
|
|
619
|
+
- `token` (`RGXToken`): The wrapped token.
|
|
620
|
+
- `transform` (`(captured: string) => T`, readonly): The transform function used to convert captured strings to values of type `T`.
|
|
621
|
+
- `beforeCapture` (`((part: RGXPart<R, T>, walker: RGXWalker<R>) => RGXPartControl) | null`, readonly): The before-capture callback, or `null`.
|
|
622
|
+
- `afterCapture` (`((capture: RGXCapture<T>, part: RGXPart<R, T>, walker: RGXWalker<R>) => void) | null`, readonly): The after-capture callback, or `null`.
|
|
623
|
+
- `rgxIsGroup` (`boolean`): Delegates to the wrapped token's group status via `isRGXGroupedToken`.
|
|
624
|
+
- `rgxIsRepeatable` (`boolean`): If the wrapped token is an `RGXConvertibleToken`, delegates to its `rgxIsRepeatable` property (defaulting to `true` if not present). Otherwise, returns `true`.
|
|
625
|
+
|
|
626
|
+
#### Methods
|
|
627
|
+
- `toRgx() => RGXToken`: Returns the wrapped token.
|
|
628
|
+
- `clone(depth: CloneDepth = "max") => RGXPart`: Creates a clone of this part. When `depth` is `0`, returns `this`; otherwise, returns a new `RGXPart` with a cloned token and the same `transform`, `beforeCapture`, and `afterCapture` references.
|
|
629
|
+
- `validate(capture: RGXCapture<T>, walker: RGXWalker<R>) => void`: A method that calls the inner passed validation logic for this part, if any. If it returns `false`, a generic `RGXPartValidationFailedError` is thrown. If it returns a string, an `RGXPartValidationFailedError` is thrown with that string as the message. If it returns `true`, validation passed. This is called internally by the walker after capturing and transforming a part, before invoking `afterCapture`.
|
|
630
|
+
|
|
631
|
+
### RGXWalker\<R\>
|
|
632
|
+
A class that walks through a sequence of RGX tokens, matching each token against a source string at the current position. It implements `RGXConvertibleToken`, delegating to its internal `RGXTokenCollection`. The walker maintains a source position and a token position, advancing through both as tokens are matched. When an `RGXPart` is encountered, its `beforeCapture` callback can control behavior via return values (`RGXPartControl`), and its `afterCapture` callback is invoked with the typed capture result. All captures are stored as structured `RGXCapture` objects on the walker. The generic type `R` represents a user-defined "reduced" value that can accumulate state during walking (e.g., via `RGXPart` callbacks).
|
|
633
|
+
|
|
634
|
+
A function `rgxWalker` is provided with the same parameters as this class' constructor, for easier instantiation without needing to use the `new` keyword.
|
|
635
|
+
|
|
636
|
+
#### Static Properties
|
|
637
|
+
- `check(value: unknown): value is RGXWalker`: A type guard that checks if the given value is an instance of `RGXWalker`.
|
|
638
|
+
- `assert(value: unknown): asserts value is RGXWalker`: An assertion that checks if the given value is an instance of `RGXWalker`. If the assertion fails, an `RGXInvalidTokenError` will be thrown.
|
|
639
|
+
|
|
640
|
+
#### Constructor
|
|
641
|
+
```typescript
|
|
642
|
+
constructor(source: string, tokens: RGXTokenCollectionInput, options?: RGXWalkerOptions<R>)
|
|
643
|
+
```
|
|
644
|
+
- `source` (`string`): The string to walk through, matching tokens against.
|
|
645
|
+
- `tokens` (`RGXTokenCollectionInput`): The tokens to match sequentially. Internally stored as an `RGXTokenCollection` in 'concat' mode.
|
|
646
|
+
- `options` (`RGXWalkerOptions<R>`, optional): Configuration options. Defaults to `{}`.
|
|
647
|
+
- `startingSourcePosition` (`number`, optional): The starting index in the source string. Defaults to `0`.
|
|
648
|
+
- `reduced` (`R`, optional): The initial value for the `reduced` accumulator. Defaults to `null`.
|
|
649
|
+
|
|
650
|
+
#### Properties
|
|
651
|
+
- `source` (`string`): The source string being walked (readonly).
|
|
652
|
+
- `sourcePosition` (`number`): The current index in the source string. Range is `[0, source.length]` inclusive, where `source.length` represents "fully consumed". Setting this validates that the value is >= 0 and <= `source.length`, throwing `RGXOutOfBoundsError` if not.
|
|
653
|
+
- `tokens` (`RGXTokenCollection`): The internal collection of tokens in 'concat' mode (readonly).
|
|
654
|
+
- `tokenPosition` (`number`): The current index in the token collection. Setting this validates that the value is >= 0 and <= `tokens.length`, throwing `RGXOutOfBoundsError` if not.
|
|
655
|
+
- `reduced` (`R`): A user-defined accumulator value, typically updated by `RGXPart` callbacks during walking.
|
|
656
|
+
- `captures` (`RGXCapture[]`): An array of structured capture results recorded during walking. Each entry has a `raw` string and a `value` (the transform result for Parts, or the raw string for plain tokens).
|
|
657
|
+
- `stopped` (`boolean`, readonly): Whether the walker has been stopped, either by a Part's `beforeCapture` returning `"stop"` or by calling `stop()` in an `afterCapture` callback.
|
|
658
|
+
|
|
659
|
+
#### Methods
|
|
660
|
+
- `stop() => void`: Sets `stopped` to `true`, causing any active `stepToToken`, `stepToPart`, or `walk` loop to halt after the current iteration. Typically called from an `afterCapture` callback to stop walking after the current capture.
|
|
661
|
+
- `atTokenEnd() => boolean`: Returns `true` if the token position is at or past the end of the token collection.
|
|
662
|
+
- `hasNextToken(predicate?: (token: RGXToken) => boolean) => boolean`: Returns `true` if there is a current token and it satisfies the optional predicate (defaults to `() => true`).
|
|
663
|
+
- `atSourceEnd() => boolean`: Returns `true` if the source has been fully consumed (`sourcePosition >= source.length`).
|
|
664
|
+
- `hasNextSource(predicate?: (rest: string) => boolean) => boolean`: Returns `true` if the source is not fully consumed and the remaining source satisfies the optional predicate (defaults to `() => true`).
|
|
665
|
+
- `lastCapture() => RGXCapture | null`: Returns the last entry in `captures`, or `null` if empty.
|
|
666
|
+
- `currentToken() => RGXToken | null`: Returns the token at the current token position, or `null` if at the end.
|
|
667
|
+
- `remainingSource() => string | null`: Returns the remaining source string from the current position onward, or `null` if the source is fully consumed.
|
|
668
|
+
- `capture(token: RGXToken) => string`: Resolves the token to a regex, asserts that it matches at the current source position (throwing `RGXRegexNotMatchedAtPositionError` if not), and advances the source position by the match length. Returns the matched string.
|
|
669
|
+
- `step() => RGXCapture | null`: Steps through the next token in the collection. If the token is an `RGXPart`, calls `beforeCapture` first — if it returns `"stop"`, sets `stopped` and returns `null` without advancing; if `"skip"`, advances the token position and returns `null` without capturing; if `"silent"`, captures but does not add to `captures`. After capturing, validates. After validating, calls `afterCapture` if present. Returns the `RGXCapture` result, or `null` if there are no more tokens, the step was skipped, or the walker was stopped.
|
|
670
|
+
- `stepToToken(predicate: (token: RGXToken) => boolean) => void`: Steps through tokens until the predicate returns `true` for the current token or the walker is stopped. The matching token is not consumed.
|
|
671
|
+
- `stepToPart(predicate?: (part: RGXPart<R>) => boolean) => void`: Steps through tokens until the next `RGXPart` satisfying the predicate is reached. If already at a Part, steps once first to move past it. The matching Part is not consumed.
|
|
672
|
+
- `walk() => void`: Steps through all remaining tokens until the end of the token collection or the walker is stopped.
|
|
673
|
+
- `toRgx() => RGXToken`: Returns the internal `RGXTokenCollection`, allowing the walker to be used as a convertible token.
|
|
674
|
+
- `clone(depth: CloneDepth = "max") => RGXWalker`: Creates a clone of the walker. When `depth` is `0`, returns `this`; otherwise, creates a new `RGXWalker` with cloned tokens, source position, reduced value, captures, and stopped state.
|
|
675
|
+
|
|
539
676
|
## Functions
|
|
540
677
|
The following functions are exported by the library:
|
|
541
678
|
|
|
@@ -1287,10 +1424,25 @@ Creates a new `ExtRegExp` from an existing one with additional or replaced flags
|
|
|
1287
1424
|
|
|
1288
1425
|
### regexMatchAtPosition
|
|
1289
1426
|
```typescript
|
|
1290
|
-
function regexMatchAtPosition(regex: RegExp, str: string, position: number):
|
|
1427
|
+
function regexMatchAtPosition(regex: RegExp, str: string, position: number): string | null
|
|
1428
|
+
```
|
|
1429
|
+
|
|
1430
|
+
Attempts to match the given regular expression at a specific position in the string and returns the matched string, or `null` if there is no match. This is done by creating a sticky (`y` flag) copy of the regex and setting its `lastIndex` to the desired position. The position must be within the bounds of the string (>= 0 and < string length), or an `RGXOutOfBoundsError` will be thrown.
|
|
1431
|
+
|
|
1432
|
+
#### Parameters
|
|
1433
|
+
- `regex` (`RegExp`): The regular expression to match.
|
|
1434
|
+
- `str` (`string`): The string to match against.
|
|
1435
|
+
- `position` (`number`): The zero-based index in the string at which to attempt the match. Must be >= 0 and < `str.length`.
|
|
1436
|
+
|
|
1437
|
+
#### Returns
|
|
1438
|
+
- `string | null`: The matched string if the regex matches at the specified position, otherwise `null`.
|
|
1439
|
+
|
|
1440
|
+
### doesRegexMatchAtPosition
|
|
1441
|
+
```typescript
|
|
1442
|
+
function doesRegexMatchAtPosition(regex: RegExp, str: string, position: number): boolean
|
|
1291
1443
|
```
|
|
1292
1444
|
|
|
1293
|
-
Tests whether the given regular expression matches at a specific position in the string. This is
|
|
1445
|
+
Tests whether the given regular expression matches at a specific position in the string. This is a boolean wrapper around `regexMatchAtPosition`, returning `true` if the match is non-null.
|
|
1294
1446
|
|
|
1295
1447
|
#### Parameters
|
|
1296
1448
|
- `regex` (`RegExp`): The regular expression to test.
|
|
@@ -1300,6 +1452,22 @@ Tests whether the given regular expression matches at a specific position in the
|
|
|
1300
1452
|
#### Returns
|
|
1301
1453
|
- `boolean`: `true` if the regex matches at the specified position, otherwise `false`.
|
|
1302
1454
|
|
|
1455
|
+
### assertRegexMatchesAtPosition
|
|
1456
|
+
```typescript
|
|
1457
|
+
function assertRegexMatchesAtPosition(regex: RegExp, str: string, position: number, contextSize?: number | null): string
|
|
1458
|
+
```
|
|
1459
|
+
|
|
1460
|
+
Asserts that the given regular expression matches at a specific position in the string, throwing an `RGXRegexNotMatchedAtPositionError` if it does not. On success, returns the matched string.
|
|
1461
|
+
|
|
1462
|
+
#### Parameters
|
|
1463
|
+
- `regex` (`RegExp`): The regular expression to match.
|
|
1464
|
+
- `str` (`string`): The string to match against.
|
|
1465
|
+
- `position` (`number`): The zero-based index in the string at which to assert the match. Must be >= 0 and < `str.length`.
|
|
1466
|
+
- `contextSize` (`number | null`, optional): The number of characters on each side of the position to include in the error's context output. Defaults to `10`.
|
|
1467
|
+
|
|
1468
|
+
#### Returns
|
|
1469
|
+
- `string`: The matched string if the regex matches at the specified position. Throws `RGXRegexNotMatchedAtPositionError` if there is no match.
|
|
1470
|
+
|
|
1303
1471
|
### cloneRGXToken
|
|
1304
1472
|
```typescript
|
|
1305
1473
|
function cloneRGXTokeN<T extends RGXToken>(token: T, depth: CloneDepth="max"): T
|
package/dist/collection.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { RGXToken, ValidRegexString } from "./types";
|
|
1
|
+
import { RGXConvertibleToken, RGXToken, ValidRegexString } from "./types";
|
|
2
2
|
import { CloneDepth } from "@ptolemy2002/immutability-utils";
|
|
3
3
|
import { Collection } from "@ptolemy2002/ts-utils";
|
|
4
4
|
export type RGXTokenCollectionMode = 'union' | 'concat';
|
|
5
5
|
export type RGXTokenCollectionInput = RGXToken | RGXTokenCollection;
|
|
6
|
-
export declare class RGXTokenCollection implements Collection<RGXToken
|
|
6
|
+
export declare class RGXTokenCollection implements Collection<RGXToken>, RGXConvertibleToken {
|
|
7
7
|
mode: RGXTokenCollectionMode;
|
|
8
8
|
tokens: RGXToken[];
|
|
9
9
|
static check: (value: unknown) => value is RGXTokenCollection;
|
package/dist/errors/base.d.ts
CHANGED
|
@@ -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';
|
|
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';
|
|
2
2
|
export declare class RGXError extends Error {
|
|
3
3
|
_message: string;
|
|
4
4
|
code: RGXErrorCode;
|
package/dist/errors/index.d.ts
CHANGED
package/dist/errors/index.js
CHANGED
|
@@ -28,3 +28,5 @@ __exportStar(require("./notSupported"), exports);
|
|
|
28
28
|
__exportStar(require("./insertionRejected"), exports);
|
|
29
29
|
__exportStar(require("./constantConflict"), exports);
|
|
30
30
|
__exportStar(require("./invalidConstantKey"), exports);
|
|
31
|
+
__exportStar(require("./regexNotMatchedAtPosition"), exports);
|
|
32
|
+
__exportStar(require("./partValidationFailed"), exports);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RGXPartValidationFailedError = void 0;
|
|
4
|
+
const base_1 = require("./base");
|
|
5
|
+
class RGXPartValidationFailedError extends base_1.RGXError {
|
|
6
|
+
constructor(message, gotRaw, gotTransformed) {
|
|
7
|
+
super(message, 'PART_VALIDATION_FAILED');
|
|
8
|
+
this.name = 'RGXPartValidationFailedError';
|
|
9
|
+
this.gotRaw = gotRaw;
|
|
10
|
+
this.gotTransformed = gotTransformed;
|
|
11
|
+
}
|
|
12
|
+
calcMessage(message) {
|
|
13
|
+
return `${message}; Got: ${this.gotRaw} (transformed: ${JSON.stringify(this.gotTransformed)})`;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
exports.RGXPartValidationFailedError = RGXPartValidationFailedError;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { RGXError } from "./base";
|
|
2
|
+
export declare class RGXRegexNotMatchedAtPositionError extends RGXError {
|
|
3
|
+
pattern: RegExp;
|
|
4
|
+
source: string;
|
|
5
|
+
_position: number;
|
|
6
|
+
contextSize: number | null;
|
|
7
|
+
set position(value: number);
|
|
8
|
+
get position(): number;
|
|
9
|
+
constructor(message: string, pattern: RegExp, source: string, position: number, contextSize?: number | null);
|
|
10
|
+
sourceContext(): string;
|
|
11
|
+
hasLeftContext(): boolean;
|
|
12
|
+
hasRightContext(): boolean;
|
|
13
|
+
hasFullContext(): boolean;
|
|
14
|
+
calcMessage(message: string): string;
|
|
15
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RGXRegexNotMatchedAtPositionError = void 0;
|
|
4
|
+
const base_1 = require("./base");
|
|
5
|
+
const outOfBounds_1 = require("./outOfBounds");
|
|
6
|
+
class RGXRegexNotMatchedAtPositionError extends base_1.RGXError {
|
|
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");
|
|
9
|
+
this._position = value;
|
|
10
|
+
}
|
|
11
|
+
get position() {
|
|
12
|
+
return this._position;
|
|
13
|
+
}
|
|
14
|
+
constructor(message, pattern, source, position, contextSize = null) {
|
|
15
|
+
super(message, 'REGEX_NOT_MATCHED_AT_POSITION');
|
|
16
|
+
this.name = 'RGXRegexNotMatchedAtPositionError';
|
|
17
|
+
this.pattern = pattern;
|
|
18
|
+
this.source = source;
|
|
19
|
+
this.position = position;
|
|
20
|
+
this.contextSize = contextSize;
|
|
21
|
+
}
|
|
22
|
+
sourceContext() {
|
|
23
|
+
if (this.hasFullContext())
|
|
24
|
+
return this.source;
|
|
25
|
+
const start = Math.max(0, this.position - this.contextSize);
|
|
26
|
+
const end = Math.min(this.source.length, this.position + this.contextSize);
|
|
27
|
+
return this.source.slice(start, end);
|
|
28
|
+
}
|
|
29
|
+
hasLeftContext() {
|
|
30
|
+
if (this.contextSize === null)
|
|
31
|
+
return false;
|
|
32
|
+
return this.position - this.contextSize >= 0;
|
|
33
|
+
}
|
|
34
|
+
hasRightContext() {
|
|
35
|
+
if (this.contextSize === null)
|
|
36
|
+
return false;
|
|
37
|
+
return this.position + this.contextSize <= this.source.length;
|
|
38
|
+
}
|
|
39
|
+
hasFullContext() {
|
|
40
|
+
return !this.hasLeftContext() && !this.hasRightContext();
|
|
41
|
+
}
|
|
42
|
+
calcMessage(message) {
|
|
43
|
+
let context = this.sourceContext();
|
|
44
|
+
if (this.contextSize !== null) {
|
|
45
|
+
if (this.hasLeftContext())
|
|
46
|
+
context = `...${context}`;
|
|
47
|
+
if (this.hasRightContext())
|
|
48
|
+
context = `${context}...`;
|
|
49
|
+
}
|
|
50
|
+
return `${message}; Pattern: ${this.pattern.toString()}, Position: ${this.position}, Context: ${context}`;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
exports.RGXRegexNotMatchedAtPositionError = RGXRegexNotMatchedAtPositionError;
|
package/dist/index.d.ts
CHANGED
|
@@ -12,5 +12,6 @@ export * from "./ExtRegExp";
|
|
|
12
12
|
export * from "./flag-transformer";
|
|
13
13
|
export * from "./clone";
|
|
14
14
|
export * from "./constants";
|
|
15
|
+
export * from "./walker";
|
|
15
16
|
export declare function rgxa(tokens: t.RGXToken[], flags?: string): ExtRegExp;
|
|
16
17
|
export default function rgx(flags?: string, multiline?: boolean): (strings: TemplateStringsArray, ...tokens: t.RGXToken[]) => ExtRegExp;
|
package/dist/index.js
CHANGED
|
@@ -33,6 +33,7 @@ __exportStar(require("./ExtRegExp"), exports);
|
|
|
33
33
|
__exportStar(require("./flag-transformer"), exports);
|
|
34
34
|
__exportStar(require("./clone"), exports);
|
|
35
35
|
__exportStar(require("./constants"), exports);
|
|
36
|
+
__exportStar(require("./walker"), exports);
|
|
36
37
|
// Call this for certain class methods to work correctly
|
|
37
38
|
(0, class_1.rgxClassInit)();
|
|
38
39
|
// Call this for our custom flags to work correctly
|
|
@@ -1 +1,3 @@
|
|
|
1
|
-
export declare function regexMatchAtPosition(regex: RegExp, str: string, position: number):
|
|
1
|
+
export declare function regexMatchAtPosition(regex: RegExp, str: string, position: number): string | null;
|
|
2
|
+
export declare function doesRegexMatchAtPosition(regex: RegExp, str: string, position: number): boolean;
|
|
3
|
+
export declare function assertRegexMatchesAtPosition(regex: RegExp, str: string, position: number, contextSize?: number | null): string;
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.regexMatchAtPosition = regexMatchAtPosition;
|
|
4
|
+
exports.doesRegexMatchAtPosition = doesRegexMatchAtPosition;
|
|
5
|
+
exports.assertRegexMatchesAtPosition = assertRegexMatchesAtPosition;
|
|
4
6
|
const outOfBounds_1 = require("../errors/outOfBounds");
|
|
5
7
|
const regexWithFlags_1 = require("./regexWithFlags");
|
|
8
|
+
const errors_1 = require("../errors");
|
|
6
9
|
function regexMatchAtPosition(regex, str, position) {
|
|
7
10
|
/*
|
|
8
11
|
The y flag means sticky mode, which means the next match must start at
|
|
@@ -12,5 +15,16 @@ function regexMatchAtPosition(regex, str, position) {
|
|
|
12
15
|
(0, outOfBounds_1.assertInRange)(position, { min: 0, max: str.length, inclusiveRight: false }, 'String index out of bounds');
|
|
13
16
|
const stickyRegex = (0, regexWithFlags_1.regexWithFlags)(regex, "y");
|
|
14
17
|
stickyRegex.lastIndex = position;
|
|
15
|
-
|
|
18
|
+
const match = stickyRegex.exec(str);
|
|
19
|
+
return match ? match[0] : null;
|
|
20
|
+
}
|
|
21
|
+
function doesRegexMatchAtPosition(regex, str, position) {
|
|
22
|
+
return regexMatchAtPosition(regex, str, position) !== null;
|
|
23
|
+
}
|
|
24
|
+
function assertRegexMatchesAtPosition(regex, str, position, contextSize = 10) {
|
|
25
|
+
const result = regexMatchAtPosition(regex, str, position);
|
|
26
|
+
if (result === null) {
|
|
27
|
+
throw new errors_1.RGXRegexNotMatchedAtPositionError("Regex not matched at index", regex, str, position, contextSize);
|
|
28
|
+
}
|
|
29
|
+
return result;
|
|
16
30
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { CloneDepth } from "@ptolemy2002/immutability-utils";
|
|
2
|
+
import { RGXTokenCollection, RGXTokenCollectionInput } from "../collection";
|
|
3
|
+
import { RGXConvertibleToken, RGXToken } from "../types";
|
|
4
|
+
import { RGXPart, RGXCapture } from "./part";
|
|
5
|
+
export type RGXWalkerOptions<R> = {
|
|
6
|
+
startingSourcePosition?: number;
|
|
7
|
+
reduced?: R;
|
|
8
|
+
};
|
|
9
|
+
export declare class RGXWalker<R> implements RGXConvertibleToken {
|
|
10
|
+
readonly source: string;
|
|
11
|
+
_sourcePosition: number;
|
|
12
|
+
readonly tokens: RGXTokenCollection;
|
|
13
|
+
_tokenPosition: number;
|
|
14
|
+
reduced: R;
|
|
15
|
+
captures: RGXCapture[];
|
|
16
|
+
private _stopped;
|
|
17
|
+
static check: (value: unknown) => value is RGXWalker<unknown>;
|
|
18
|
+
static assert: (value: unknown) => asserts value is RGXWalker<unknown>;
|
|
19
|
+
get sourcePosition(): number;
|
|
20
|
+
set sourcePosition(value: number);
|
|
21
|
+
get tokenPosition(): number;
|
|
22
|
+
set tokenPosition(value: number);
|
|
23
|
+
get stopped(): boolean;
|
|
24
|
+
constructor(source: string, tokens: RGXTokenCollectionInput, options?: RGXWalkerOptions<R>);
|
|
25
|
+
stop(): void;
|
|
26
|
+
atTokenEnd(): boolean;
|
|
27
|
+
hasNextToken(predicate?: (token: RGXToken) => boolean): boolean;
|
|
28
|
+
atSourceEnd(): boolean;
|
|
29
|
+
hasNextSource(predicate?: (rest: string) => boolean): boolean;
|
|
30
|
+
lastCapture(): RGXCapture | null;
|
|
31
|
+
currentToken(): RGXToken;
|
|
32
|
+
remainingSource(): string | null;
|
|
33
|
+
capture(token: RGXToken): string;
|
|
34
|
+
step(): RGXCapture | null;
|
|
35
|
+
stepToToken(predicate: (token: RGXToken) => boolean): void;
|
|
36
|
+
stepToPart(predicate?: (part: RGXPart<R>) => boolean): void;
|
|
37
|
+
walk(): void;
|
|
38
|
+
toRgx(): RGXTokenCollection;
|
|
39
|
+
clone(depth?: CloneDepth): RGXWalker<R>;
|
|
40
|
+
}
|
|
41
|
+
export declare function rgxWalker<R>(...args: ConstructorParameters<typeof RGXWalker<R>>): RGXWalker<R>;
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RGXWalker = void 0;
|
|
4
|
+
exports.rgxWalker = rgxWalker;
|
|
5
|
+
const immutability_utils_1 = require("@ptolemy2002/immutability-utils");
|
|
6
|
+
const collection_1 = require("../collection");
|
|
7
|
+
const errors_1 = require("../errors");
|
|
8
|
+
const part_1 = require("./part");
|
|
9
|
+
const index_1 = require("../index");
|
|
10
|
+
const internal_1 = require("../internal");
|
|
11
|
+
class RGXWalker {
|
|
12
|
+
get sourcePosition() {
|
|
13
|
+
return this._sourcePosition;
|
|
14
|
+
}
|
|
15
|
+
set sourcePosition(value) {
|
|
16
|
+
(0, errors_1.assertInRange)(value, { min: 0, max: this.source.length }, "sourcePosition is outside the bounds of the source string");
|
|
17
|
+
this._sourcePosition = value;
|
|
18
|
+
}
|
|
19
|
+
get tokenPosition() {
|
|
20
|
+
return this._tokenPosition;
|
|
21
|
+
}
|
|
22
|
+
set tokenPosition(value) {
|
|
23
|
+
(0, errors_1.assertInRange)(value, { min: 0, max: this.tokens.length }, "tokenPosition is outside the bounds of the token collection");
|
|
24
|
+
this._tokenPosition = value;
|
|
25
|
+
}
|
|
26
|
+
get stopped() {
|
|
27
|
+
return this._stopped;
|
|
28
|
+
}
|
|
29
|
+
constructor(source, tokens, options = {}) {
|
|
30
|
+
this.captures = [];
|
|
31
|
+
this._stopped = false;
|
|
32
|
+
this.source = source;
|
|
33
|
+
this.sourcePosition = options.startingSourcePosition ?? 0;
|
|
34
|
+
this.tokens = new collection_1.RGXTokenCollection(tokens, "concat");
|
|
35
|
+
this.tokenPosition = 0;
|
|
36
|
+
this.reduced = options.reduced ?? null;
|
|
37
|
+
}
|
|
38
|
+
stop() {
|
|
39
|
+
this._stopped = true;
|
|
40
|
+
}
|
|
41
|
+
atTokenEnd() {
|
|
42
|
+
return this.tokenPosition >= this.tokens.length;
|
|
43
|
+
}
|
|
44
|
+
hasNextToken(predicate = () => true) {
|
|
45
|
+
return !this.atTokenEnd() && predicate(this.currentToken());
|
|
46
|
+
}
|
|
47
|
+
atSourceEnd() {
|
|
48
|
+
return this.sourcePosition >= this.source.length;
|
|
49
|
+
}
|
|
50
|
+
hasNextSource(predicate = () => true) {
|
|
51
|
+
return !this.atSourceEnd() && predicate(this.remainingSource());
|
|
52
|
+
}
|
|
53
|
+
lastCapture() {
|
|
54
|
+
if (this.captures.length === 0)
|
|
55
|
+
return null;
|
|
56
|
+
return this.captures[this.captures.length - 1];
|
|
57
|
+
}
|
|
58
|
+
currentToken() {
|
|
59
|
+
if (this.atTokenEnd())
|
|
60
|
+
return null;
|
|
61
|
+
return this.tokens.at(this.tokenPosition);
|
|
62
|
+
}
|
|
63
|
+
remainingSource() {
|
|
64
|
+
if (this.atSourceEnd())
|
|
65
|
+
return null;
|
|
66
|
+
return this.source.slice(this.sourcePosition);
|
|
67
|
+
}
|
|
68
|
+
capture(token) {
|
|
69
|
+
const regex = (0, index_1.rgxa)([token]);
|
|
70
|
+
const match = (0, index_1.assertRegexMatchesAtPosition)(regex, this.source, this.sourcePosition);
|
|
71
|
+
this.sourcePosition += match.length;
|
|
72
|
+
return match;
|
|
73
|
+
}
|
|
74
|
+
step() {
|
|
75
|
+
if (this.atTokenEnd())
|
|
76
|
+
return null;
|
|
77
|
+
const token = this.currentToken();
|
|
78
|
+
const isPart = token instanceof part_1.RGXPart;
|
|
79
|
+
let silent = false;
|
|
80
|
+
// Ask Part what to do — control flow via return values, not flags.
|
|
81
|
+
if (isPart) {
|
|
82
|
+
const control = token.beforeCapture?.(token, this);
|
|
83
|
+
if (control === "stop") {
|
|
84
|
+
this._stopped = true;
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
if (control === "skip") {
|
|
88
|
+
this.tokenPosition++;
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
if (control === "silent") {
|
|
92
|
+
silent = true;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// Capture the match
|
|
96
|
+
const raw = this.capture(token);
|
|
97
|
+
const value = isPart ? token.transform(raw) : raw;
|
|
98
|
+
const captureResult = { raw, value };
|
|
99
|
+
// Validate the part. If validation fails, it will throw an error, so nothing below will run.
|
|
100
|
+
if (isPart) {
|
|
101
|
+
token.validate(captureResult, this);
|
|
102
|
+
}
|
|
103
|
+
// Skip adding the capture if in silent mode.
|
|
104
|
+
if (!silent) {
|
|
105
|
+
this.captures.push(captureResult);
|
|
106
|
+
}
|
|
107
|
+
// Notify Part after capture
|
|
108
|
+
if (isPart) {
|
|
109
|
+
token.afterCapture?.(captureResult, token, this);
|
|
110
|
+
}
|
|
111
|
+
this.tokenPosition++;
|
|
112
|
+
return captureResult;
|
|
113
|
+
}
|
|
114
|
+
stepToToken(predicate) {
|
|
115
|
+
while (this.hasNextToken()) {
|
|
116
|
+
this._stopped = false;
|
|
117
|
+
if (predicate(this.currentToken()))
|
|
118
|
+
break;
|
|
119
|
+
this.step();
|
|
120
|
+
if (this._stopped)
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
stepToPart(predicate = () => true) {
|
|
125
|
+
// If currently at a Part, step past it first so repeated
|
|
126
|
+
// calls advance to the next Part rather than getting stuck.
|
|
127
|
+
if (this.currentToken() instanceof part_1.RGXPart) {
|
|
128
|
+
this._stopped = false;
|
|
129
|
+
this.step();
|
|
130
|
+
if (this._stopped)
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
this.stepToToken(token => token instanceof part_1.RGXPart && predicate(token));
|
|
134
|
+
}
|
|
135
|
+
walk() {
|
|
136
|
+
return this.stepToToken(() => false);
|
|
137
|
+
}
|
|
138
|
+
// When used as a convertible token, treat the walker as its collection.
|
|
139
|
+
toRgx() {
|
|
140
|
+
return this.tokens;
|
|
141
|
+
}
|
|
142
|
+
// Clone method
|
|
143
|
+
clone(depth = "max") {
|
|
144
|
+
if (depth === 0)
|
|
145
|
+
return this;
|
|
146
|
+
const clone = new RGXWalker(this.source, this.tokens.clone((0, immutability_utils_1.depthDecrement)(1)), {
|
|
147
|
+
startingSourcePosition: this.sourcePosition,
|
|
148
|
+
reduced: (0, immutability_utils_1.extClone)(this.reduced, (0, immutability_utils_1.depthDecrement)(1))
|
|
149
|
+
});
|
|
150
|
+
clone._tokenPosition = this.tokenPosition;
|
|
151
|
+
clone.captures = (0, immutability_utils_1.extClone)(this.captures, (0, immutability_utils_1.depthDecrement)(1));
|
|
152
|
+
clone._stopped = this._stopped;
|
|
153
|
+
return clone;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
exports.RGXWalker = RGXWalker;
|
|
157
|
+
RGXWalker.check = (0, internal_1.createClassGuardFunction)(RGXWalker);
|
|
158
|
+
RGXWalker.assert = (0, internal_1.createAssertClassGuardFunction)(RGXWalker);
|
|
159
|
+
function rgxWalker(...args) {
|
|
160
|
+
return new RGXWalker(...args);
|
|
161
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
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);
|
|
18
|
+
__exportStar(require("./part"), exports);
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { RGXConvertibleToken, RGXToken } from "../types";
|
|
2
|
+
import type { RGXWalker } from "./base";
|
|
3
|
+
import { CloneDepth } from "@ptolemy2002/immutability-utils";
|
|
4
|
+
export type RGXPartControl = "skip" | "stop" | "silent" | void;
|
|
5
|
+
export type RGXCapture<T = unknown> = {
|
|
6
|
+
raw: string;
|
|
7
|
+
value: T;
|
|
8
|
+
};
|
|
9
|
+
export type RGXPartOptions<R, T = string> = {
|
|
10
|
+
transform: (captured: string) => T;
|
|
11
|
+
validate: (captured: RGXCapture<T>, part: RGXPart<R, T>, walker: RGXWalker<R>) => boolean | string;
|
|
12
|
+
beforeCapture: ((part: RGXPart<R, T>, walker: RGXWalker<R>) => RGXPartControl) | null;
|
|
13
|
+
afterCapture: ((capture: RGXCapture<T>, part: RGXPart<R, T>, walker: RGXWalker<R>) => void) | null;
|
|
14
|
+
};
|
|
15
|
+
export declare class RGXPart<R, T = string> implements RGXConvertibleToken {
|
|
16
|
+
token: RGXToken;
|
|
17
|
+
readonly transform: RGXPartOptions<R, T>["transform"];
|
|
18
|
+
private readonly _validate;
|
|
19
|
+
readonly beforeCapture: RGXPartOptions<R, T>["beforeCapture"];
|
|
20
|
+
readonly afterCapture: RGXPartOptions<R, T>["afterCapture"];
|
|
21
|
+
static check: (value: unknown) => value is RGXPart<unknown, unknown>;
|
|
22
|
+
static assert: (value: unknown) => asserts value is RGXPart<unknown, unknown>;
|
|
23
|
+
constructor(token: RGXToken, options?: Partial<RGXPartOptions<R, T>>);
|
|
24
|
+
validate(capture: RGXCapture<T>, walker: RGXWalker<R>): void;
|
|
25
|
+
get rgxIsGroup(): boolean;
|
|
26
|
+
get rgxIsRepeatable(): boolean;
|
|
27
|
+
toRgx(): RGXToken;
|
|
28
|
+
clone(depth?: CloneDepth): RGXPart<R, T>;
|
|
29
|
+
}
|
|
30
|
+
export declare function rgxPart<R, T = string>(...args: ConstructorParameters<typeof RGXPart<R, T>>): RGXPart<R, T>;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RGXPart = void 0;
|
|
4
|
+
exports.rgxPart = rgxPart;
|
|
5
|
+
const typeGuards_1 = require("../typeGuards");
|
|
6
|
+
const internal_1 = require("../internal");
|
|
7
|
+
const clone_1 = require("../clone");
|
|
8
|
+
const immutability_utils_1 = require("@ptolemy2002/immutability-utils");
|
|
9
|
+
const errors_1 = require("../errors");
|
|
10
|
+
// A Part is purely a definition: a token + optional callbacks.
|
|
11
|
+
// It does NOT store capture state — that lives on the walker.
|
|
12
|
+
class RGXPart {
|
|
13
|
+
constructor(token, options = {}) {
|
|
14
|
+
this.token = token;
|
|
15
|
+
this.transform = options.transform ?? ((captured) => captured);
|
|
16
|
+
this._validate = options.validate ?? (() => true);
|
|
17
|
+
this.beforeCapture = options.beforeCapture ?? null;
|
|
18
|
+
this.afterCapture = options.afterCapture ?? null;
|
|
19
|
+
}
|
|
20
|
+
validate(capture, walker) {
|
|
21
|
+
const result = this._validate(capture, this, walker);
|
|
22
|
+
if (result === true)
|
|
23
|
+
return;
|
|
24
|
+
const message = typeof result === "string" ? result : "Part Validation Failed";
|
|
25
|
+
throw new errors_1.RGXPartValidationFailedError(message, capture.raw, capture.value);
|
|
26
|
+
}
|
|
27
|
+
// Properties used for conversion to an RGXToken
|
|
28
|
+
get rgxIsGroup() {
|
|
29
|
+
return (0, typeGuards_1.isRGXGroupedToken)(this.token);
|
|
30
|
+
}
|
|
31
|
+
get rgxIsRepeatable() {
|
|
32
|
+
if ((0, typeGuards_1.isRGXToken)(this.token, 'convertible'))
|
|
33
|
+
return this.token.rgxIsRepeatable ?? true;
|
|
34
|
+
// Assume any other token is repeatable, since we don't know its implementation.
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
toRgx() {
|
|
38
|
+
return this.token;
|
|
39
|
+
}
|
|
40
|
+
// Clone method
|
|
41
|
+
clone(depth = "max") {
|
|
42
|
+
if (depth === 0)
|
|
43
|
+
return this;
|
|
44
|
+
return new RGXPart((0, clone_1.cloneRGXToken)(this.token, (0, immutability_utils_1.depthDecrement)(depth, 1)), {
|
|
45
|
+
transform: this.transform,
|
|
46
|
+
beforeCapture: this.beforeCapture,
|
|
47
|
+
afterCapture: this.afterCapture,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
exports.RGXPart = RGXPart;
|
|
52
|
+
RGXPart.check = (0, internal_1.createClassGuardFunction)(RGXPart);
|
|
53
|
+
RGXPart.assert = (0, internal_1.createAssertClassGuardFunction)(RGXPart);
|
|
54
|
+
function rgxPart(...args) {
|
|
55
|
+
return new RGXPart(...args);
|
|
56
|
+
}
|