@ptolemy2002/rgx 8.2.0 → 9.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/index.d.ts CHANGED
@@ -17,5 +17,5 @@ export * from "./walker";
17
17
  export * from "./lexer";
18
18
  export declare function rgxa(tokens: t.RGXToken[], flags?: string): ExtRegExp;
19
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>;
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, ...options }?: t.RGXWOptions<R, S>): (strings: TemplateStringsArray, ...tokens: RGXTokenOrPart<R, S, T>[]) => RGXWalker<R, S>;
@@ -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>;
@@ -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/types.d.ts CHANGED
@@ -49,6 +49,6 @@ export type ValidRegexFlags = Branded<string, [ValidRegexFlagsBrandSymbol]> | Va
49
49
  export declare const validIdentifierSymbol: unique symbol;
50
50
  export type ValidIdentifierBrandSymbol = typeof validIdentifierSymbol;
51
51
  export type ValidIdentifier = Branded<string, [ValidIdentifierBrandSymbol]>;
52
- export type RGXWOptions<R = unknown> = RGXWalkerOptions<R> & {
52
+ export type RGXWOptions<R = unknown, S = unknown> = RGXWalkerOptions<R, S> & {
53
53
  multiline?: boolean;
54
54
  };
@@ -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>;
@@ -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
- const capture = this.capture(branchedToken, true);
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
- token.validate(captureResult, this);
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
  });
@@ -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
- static check: (value: unknown) => value is RGXPart<unknown, unknown>;
31
- static assert: (value: unknown) => asserts value is RGXPart<unknown, unknown>;
32
- constructor(token: RGXToken, options?: Partial<RGXPartOptions<R, T>>);
33
- hasId(): this is RGXPart<R, T> & {
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>;
@@ -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";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ptolemy2002/rgx",
3
- "version": "8.2.0",
3
+ "version": "9.0.0",
4
4
  "private": false,
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",