clarity-pattern-parser 10.3.1 → 10.3.2

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.
@@ -17,6 +17,7 @@ export declare class Context implements Pattern {
17
17
  get parent(): Pattern | null;
18
18
  set parent(pattern: Pattern | null);
19
19
  get children(): Pattern[];
20
+ get startedOnIndex(): number;
20
21
  getPatternWithinContext(name: string): Pattern | null;
21
22
  getPatternsWithinContext(): {
22
23
  [x: string]: Pattern;
@@ -29,6 +29,7 @@ export declare class ExpressionPattern implements Pattern {
29
29
  get unaryPatterns(): readonly Pattern[];
30
30
  get binaryPatterns(): readonly Pattern[];
31
31
  get recursivePatterns(): readonly Pattern[];
32
+ get startedOnIndex(): number;
32
33
  constructor(name: string, patterns: Pattern[]);
33
34
  private _organizePatterns;
34
35
  private _isBinary;
@@ -42,6 +43,7 @@ export declare class ExpressionPattern implements Pattern {
42
43
  parse(cursor: Cursor): Node | null;
43
44
  private _compactResult;
44
45
  private _tryToParse;
46
+ private _isBeyondRecursiveAllowance;
45
47
  test(text: string): boolean;
46
48
  exec(text: string, record?: boolean): ParseResult;
47
49
  getTokens(): string[];
@@ -18,6 +18,7 @@ export declare class FiniteRepeat implements Pattern {
18
18
  private _min;
19
19
  private _max;
20
20
  private _trimDivider;
21
+ private _firstIndex;
21
22
  shouldCompactAst: boolean;
22
23
  get id(): string;
23
24
  get type(): string;
@@ -27,6 +28,7 @@ export declare class FiniteRepeat implements Pattern {
27
28
  get children(): Pattern[];
28
29
  get min(): number;
29
30
  get max(): number;
31
+ get startedOnIndex(): number;
30
32
  constructor(name: string, pattern: Pattern, options?: FiniteRepeatOptions);
31
33
  parse(cursor: Cursor): Node | null;
32
34
  test(text: string): boolean;
@@ -27,6 +27,7 @@ export declare class InfiniteRepeat implements Pattern {
27
27
  set parent(pattern: Pattern | null);
28
28
  get children(): Pattern[];
29
29
  get min(): number;
30
+ get startedOnIndex(): number;
30
31
  constructor(name: string, pattern: Pattern, options?: InfiniteRepeatOptions);
31
32
  private _assignChildrenToParent;
32
33
  test(text: string): boolean;
@@ -20,6 +20,7 @@ export declare class Literal implements Pattern {
20
20
  get parent(): Pattern | null;
21
21
  set parent(pattern: Pattern | null);
22
22
  get children(): Pattern[];
23
+ get startedOnIndex(): number;
23
24
  constructor(name: string, value: string);
24
25
  test(text: string, record?: boolean): boolean;
25
26
  exec(text: string, record?: boolean): ParseResult;
@@ -15,6 +15,7 @@ export declare class Not implements Pattern {
15
15
  get parent(): Pattern | null;
16
16
  set parent(pattern: Pattern | null);
17
17
  get children(): Pattern[];
18
+ get startedOnIndex(): number;
18
19
  constructor(name: string, pattern: Pattern);
19
20
  test(text: string): boolean;
20
21
  exec(text: string, record?: boolean): ParseResult;
@@ -15,6 +15,7 @@ export declare class Optional implements Pattern {
15
15
  get parent(): Pattern | null;
16
16
  set parent(pattern: Pattern | null);
17
17
  get children(): Pattern[];
18
+ get startedOnIndex(): number;
18
19
  constructor(name: string, pattern: Pattern);
19
20
  test(text: string): boolean;
20
21
  exec(text: string, record?: boolean): ParseResult;
@@ -17,12 +17,14 @@ export declare class Options implements Pattern {
17
17
  get parent(): Pattern | null;
18
18
  set parent(pattern: Pattern | null);
19
19
  get children(): Pattern[];
20
+ get startedOnIndex(): number;
20
21
  constructor(name: string, options: Pattern[], isGreedy?: boolean);
21
22
  private _assignChildrenToParent;
22
23
  test(text: string): boolean;
23
24
  exec(text: string, record?: boolean): ParseResult;
24
25
  parse(cursor: Cursor): Node | null;
25
26
  private _tryToParse;
27
+ private _isBeyondRecursiveAllowance;
26
28
  getTokens(): string[];
27
29
  getTokensAfter(_childReference: Pattern): string[];
28
30
  getNextTokens(): string[];
@@ -6,6 +6,7 @@ export interface Pattern {
6
6
  type: string;
7
7
  name: string;
8
8
  shouldCompactAst: boolean;
9
+ startedOnIndex: number;
9
10
  parent: Pattern | null;
10
11
  children: Pattern[];
11
12
  parse(cursor: Cursor): Node | null;
@@ -10,6 +10,7 @@ export declare class Reference implements Pattern {
10
10
  private _cachedPattern;
11
11
  private _pattern;
12
12
  private _children;
13
+ private _firstIndex;
13
14
  shouldCompactAst: boolean;
14
15
  get id(): string;
15
16
  get type(): string;
@@ -17,6 +18,7 @@ export declare class Reference implements Pattern {
17
18
  get parent(): Pattern | null;
18
19
  set parent(pattern: Pattern | null);
19
20
  get children(): Pattern[];
21
+ get startedOnIndex(): number;
20
22
  constructor(name: string);
21
23
  test(text: string): boolean;
22
24
  exec(text: string, record?: boolean): ParseResult;
@@ -22,6 +22,7 @@ export declare class Regex implements Pattern {
22
22
  get parent(): Pattern | null;
23
23
  set parent(pattern: Pattern | null);
24
24
  get children(): Pattern[];
25
+ get startedOnIndex(): number;
25
26
  constructor(name: string, regex: string);
26
27
  private assertArguments;
27
28
  test(text: string): boolean;
@@ -26,6 +26,7 @@ export declare class Repeat implements Pattern {
26
26
  get children(): Pattern[];
27
27
  get min(): number;
28
28
  get max(): number;
29
+ get startedOnIndex(): number;
29
30
  constructor(name: string, pattern: Pattern, options?: RepeatOptions);
30
31
  parse(cursor: Cursor): Node | null;
31
32
  exec(text: string): ParseResult;
@@ -16,6 +16,7 @@ export declare class Sequence implements Pattern {
16
16
  get parent(): Pattern | null;
17
17
  set parent(pattern: Pattern | null);
18
18
  get children(): Pattern[];
19
+ get startedOnIndex(): number;
19
20
  constructor(name: string, sequence: Pattern[]);
20
21
  private _assignChildrenToParent;
21
22
  test(text: string): boolean;
@@ -26,6 +27,7 @@ export declare class Sequence implements Pattern {
26
27
  parse(cursor: Cursor): Node | null;
27
28
  private tryToParse;
28
29
  private getLastValidNode;
30
+ private _isBeyondRecursiveAllowance;
29
31
  private areRemainingPatternsOptional;
30
32
  private createNode;
31
33
  getTokens(): string[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clarity-pattern-parser",
3
- "version": "10.3.1",
3
+ "version": "10.3.2",
4
4
  "description": "Parsing Library for Typescript and Javascript.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.esm.js",
@@ -40,6 +40,10 @@ export class Context implements Pattern {
40
40
  return this._children;
41
41
  }
42
42
 
43
+ get startedOnIndex(){
44
+ return this.children[0].startedOnIndex;
45
+ }
46
+
43
47
  getPatternWithinContext(name: string): Pattern | null {
44
48
  return this._patterns[name] || null;
45
49
  }
@@ -1,13 +1,11 @@
1
1
  import { Node } from "../ast/Node";
2
2
  import { Cursor } from "./Cursor";
3
- import { DepthCache } from "./DepthCache";
4
3
  import { ParseResult } from "./ParseResult";
5
4
  import { Pattern } from "./Pattern";
6
5
  import { findPattern } from "./findPattern";
7
6
  import { Sequence } from "./Sequence";
8
7
 
9
8
  let indexId = 0;
10
- const depthCache = new DepthCache();
11
9
 
12
10
  function createNode(name: string, children: Node[]) {
13
11
  return new Node("expression", name, 0, 0, children, "");
@@ -74,6 +72,10 @@ export class ExpressionPattern implements Pattern {
74
72
  return this._recursivePatterns;
75
73
  }
76
74
 
75
+ get startedOnIndex() {
76
+ return this._firstIndex;
77
+ }
78
+
77
79
  constructor(name: string, patterns: Pattern[]) {
78
80
  if (patterns.length === 0) {
79
81
  throw new Error("Need at least one pattern with an 'expression' pattern.");
@@ -211,14 +213,9 @@ export class ExpressionPattern implements Pattern {
211
213
  }
212
214
 
213
215
  parse(cursor: Cursor): Node | null {
214
- this._firstIndex = cursor.index;
215
- depthCache.incrementDepth(this._id, this._firstIndex);
216
-
217
216
  this._firstIndex = cursor.index;
218
217
  const node = this._tryToParse(cursor);
219
218
 
220
- depthCache.decrementDepth(this._id, this._firstIndex);
221
-
222
219
  if (node != null) {
223
220
  cursor.moveTo(node.lastIndex);
224
221
  cursor.resolveError();
@@ -253,12 +250,11 @@ export class ExpressionPattern implements Pattern {
253
250
  }
254
251
 
255
252
  private _tryToParse(cursor: Cursor): Node | null {
256
- if (depthCache.getDepth(this._id, this._firstIndex) > 2) {
253
+ if (this._isBeyondRecursiveAllowance()) {
257
254
  cursor.recordErrorAt(this._firstIndex, this._firstIndex, this);
258
255
  return null;
259
256
  }
260
257
 
261
-
262
258
  let lastUnaryNode: Node | null = null;
263
259
  let lastBinaryNode: Node | null = null;
264
260
  let onIndex = cursor.index;
@@ -447,6 +443,24 @@ export class ExpressionPattern implements Pattern {
447
443
  }
448
444
  }
449
445
 
446
+ private _isBeyondRecursiveAllowance() {
447
+ let depth = 0;
448
+ let pattern: Pattern | null = this;
449
+
450
+ while (pattern != null) {
451
+ if (pattern.id === this.id && pattern.startedOnIndex === this.startedOnIndex) {
452
+ depth++;
453
+ }
454
+
455
+ if (depth > 2) {
456
+ return true;
457
+ }
458
+ pattern = pattern.parent;
459
+ }
460
+
461
+ return false;
462
+ }
463
+
450
464
  test(text: string) {
451
465
  const cursor = new Cursor(text);
452
466
  const ast = this.parse(cursor);
@@ -23,6 +23,7 @@ export class FiniteRepeat implements Pattern {
23
23
  private _min: number;
24
24
  private _max: number;
25
25
  private _trimDivider: boolean;
26
+ private _firstIndex: number;
26
27
 
27
28
  shouldCompactAst = false;
28
29
 
@@ -58,6 +59,10 @@ export class FiniteRepeat implements Pattern {
58
59
  return this._max;
59
60
  }
60
61
 
62
+ get startedOnIndex() {
63
+ return this._firstIndex;
64
+ }
65
+
61
66
  constructor(name: string, pattern: Pattern, options: FiniteRepeatOptions = {}) {
62
67
  this._id = `finite-repeat-${idIndex++}`;
63
68
  this._type = "finite-repeat";
@@ -68,6 +73,7 @@ export class FiniteRepeat implements Pattern {
68
73
  this._min = options.min != null ? Math.max(options.min, 1) : 1;
69
74
  this._max = Math.max(this.min, options.max || this.min);
70
75
  this._trimDivider = options.trimDivider == null ? false : options.trimDivider;
76
+ this._firstIndex = 0;
71
77
 
72
78
  for (let i = 0; i < this._max; i++) {
73
79
  const child = pattern.clone();
@@ -85,6 +91,8 @@ export class FiniteRepeat implements Pattern {
85
91
  }
86
92
 
87
93
  parse(cursor: Cursor): Node | null {
94
+ this._firstIndex = cursor.index;
95
+
88
96
  const startIndex = cursor.index;
89
97
  const nodes: Node[] = [];
90
98
  const modulo = this._hasDivider ? 2 : 1;
@@ -56,6 +56,10 @@ export class InfiniteRepeat implements Pattern {
56
56
  return this._min;
57
57
  }
58
58
 
59
+ get startedOnIndex(){
60
+ return this._firstIndex;
61
+ }
62
+
59
63
  constructor(name: string, pattern: Pattern, options: InfiniteRepeatOptions = {}) {
60
64
  const min = options.min != null ? Math.max(options.min, 1) : 1;
61
65
  const divider = options.divider;
@@ -46,6 +46,10 @@ export class Literal implements Pattern {
46
46
  return [];
47
47
  }
48
48
 
49
+ get startedOnIndex() {
50
+ return this._firstIndex;
51
+ }
52
+
49
53
  constructor(name: string, value: string) {
50
54
  if (value.length === 0) {
51
55
  throw new Error("Value Cannot be empty.");
@@ -38,6 +38,10 @@ export class Not implements Pattern {
38
38
  return this._children;
39
39
  }
40
40
 
41
+ get startedOnIndex() {
42
+ return this.children[0].startedOnIndex;
43
+ }
44
+
41
45
  constructor(name: string, pattern: Pattern) {
42
46
  this._id = `not-${idIndex++}`;
43
47
  this._type = "not";
@@ -38,6 +38,10 @@ export class Optional implements Pattern {
38
38
  return this._children;
39
39
  }
40
40
 
41
+ get startedOnIndex() {
42
+ return this._children[0].startedOnIndex;
43
+ }
44
+
41
45
  constructor(name: string, pattern: Pattern) {
42
46
  this._id = `optional-${idIndex++}`;
43
47
  this._type = "optional";
@@ -4,14 +4,8 @@ import { Pattern } from "./Pattern";
4
4
  import { clonePatterns } from "./clonePatterns";
5
5
  import { findPattern } from "./findPattern";
6
6
  import { ParseResult } from "./ParseResult";
7
- import { DepthCache } from './DepthCache';
8
7
  import { isRecursivePattern } from "./isRecursivePattern";
9
8
 
10
- /*
11
- The following is created to reduce the overhead of recursion check.
12
- */
13
-
14
- const depthCache = new DepthCache();
15
9
  let idIndex = 0;
16
10
 
17
11
  export class Options implements Pattern {
@@ -49,6 +43,10 @@ export class Options implements Pattern {
49
43
  return this._children;
50
44
  }
51
45
 
46
+ get startedOnIndex() {
47
+ return this._firstIndex;
48
+ }
49
+
52
50
  constructor(name: string, options: Pattern[], isGreedy = false) {
53
51
  if (options.length === 0) {
54
52
  throw new Error("Need at least one pattern with an 'options' pattern.");
@@ -92,15 +90,9 @@ export class Options implements Pattern {
92
90
  }
93
91
 
94
92
  parse(cursor: Cursor): Node | null {
95
- // This is a cache to help with speed
96
- this._firstIndex = cursor.index;
97
- depthCache.incrementDepth(this._id, this._firstIndex);
98
-
99
93
  this._firstIndex = cursor.index;
100
94
  const node = this._tryToParse(cursor);
101
95
 
102
- depthCache.decrementDepth(this._id, this._firstIndex);
103
-
104
96
  if (node != null) {
105
97
  cursor.moveTo(node.lastIndex);
106
98
  cursor.resolveError();
@@ -117,7 +109,7 @@ export class Options implements Pattern {
117
109
  }
118
110
 
119
111
  private _tryToParse(cursor: Cursor): Node | null {
120
- if (depthCache.getDepth(this._id, this._firstIndex) > 2) {
112
+ if (this._isBeyondRecursiveAllowance()) {
121
113
  return null;
122
114
  }
123
115
 
@@ -146,6 +138,24 @@ export class Options implements Pattern {
146
138
  return nonNullResults[0] || null;
147
139
  }
148
140
 
141
+ private _isBeyondRecursiveAllowance() {
142
+ let depth = 0;
143
+ let pattern: Pattern | null = this;
144
+
145
+ while (pattern != null) {
146
+ if (pattern.id === this.id && pattern.startedOnIndex === this.startedOnIndex) {
147
+ depth++;
148
+ }
149
+
150
+ if (depth > 2) {
151
+ return true;
152
+ }
153
+ pattern = pattern.parent;
154
+ }
155
+
156
+ return false;
157
+ }
158
+
149
159
  getTokens(): string[] {
150
160
  const tokens: string[] = [];
151
161
 
@@ -7,6 +7,7 @@ export interface Pattern {
7
7
  type: string;
8
8
  name: string;
9
9
  shouldCompactAst: boolean;
10
+ startedOnIndex: number;
10
11
  parent: Pattern | null;
11
12
  children: Pattern[];
12
13
 
@@ -15,6 +15,7 @@ export class Reference implements Pattern {
15
15
  private _cachedPattern: Pattern | null;
16
16
  private _pattern: Pattern | null;
17
17
  private _children: Pattern[];
18
+ private _firstIndex: number;
18
19
 
19
20
  shouldCompactAst = false;
20
21
 
@@ -42,6 +43,10 @@ export class Reference implements Pattern {
42
43
  return this._children;
43
44
  }
44
45
 
46
+ get startedOnIndex() {
47
+ return this._firstIndex;
48
+ }
49
+
45
50
  constructor(name: string) {
46
51
  this._id = `reference-${idIndex++}`;
47
52
  this._type = "reference";
@@ -50,6 +55,7 @@ export class Reference implements Pattern {
50
55
  this._pattern = null;
51
56
  this._cachedPattern = null;
52
57
  this._children = [];
58
+ this._firstIndex = 0;
53
59
  }
54
60
 
55
61
  test(text: string) {
@@ -72,6 +78,7 @@ export class Reference implements Pattern {
72
78
  }
73
79
 
74
80
  parse(cursor: Cursor): Node | null {
81
+ this._firstIndex = cursor.index;
75
82
  return this.getReferencePatternSafely().parse(cursor);
76
83
  }
77
84
 
@@ -14,7 +14,7 @@ export class Regex implements Pattern {
14
14
  private _regex: RegExp;
15
15
  private _node: Node | null = null;
16
16
  private _cursor: Cursor | null = null;
17
- private _firstIndex = -1;
17
+ private _firstIndex = 0;
18
18
  private _substring = "";
19
19
  private _tokens: string[] = [];
20
20
 
@@ -48,6 +48,10 @@ export class Regex implements Pattern {
48
48
  return [];
49
49
  }
50
50
 
51
+ get startedOnIndex() {
52
+ return this._firstIndex;
53
+ }
54
+
51
55
  constructor(name: string, regex: string) {
52
56
  this._id = `regex-${idIndex++}`;
53
57
  this._type = "regex";
@@ -149,7 +153,7 @@ export class Regex implements Pattern {
149
153
  clone._tokens = this._tokens.slice();
150
154
  clone._id = this._id;
151
155
  clone.shouldCompactAst = this.shouldCompactAst;
152
-
156
+
153
157
  return clone;
154
158
  }
155
159
 
@@ -70,6 +70,10 @@ export class Repeat implements Pattern {
70
70
  return this._options.max;
71
71
  }
72
72
 
73
+ get startedOnIndex(){
74
+ return this._repeatPattern.startedOnIndex;
75
+ }
76
+
73
77
  constructor(name: string, pattern: Pattern, options: RepeatOptions = {}) {
74
78
  this._id = `repeat-${idIndex++}`;
75
79
  this._pattern = pattern;
@@ -38,6 +38,10 @@ export class RightAssociatedPattern implements Pattern {
38
38
  return this._children;
39
39
  }
40
40
 
41
+ get startedOnIndex() {
42
+ return this._children[0].startedOnIndex;
43
+ }
44
+
41
45
  constructor(pattern: Pattern) {
42
46
  this._id = `right-associated-${indexId++}`;
43
47
  this._type = "right-associated";
@@ -4,10 +4,8 @@ import { Node } from "../ast/Node";
4
4
  import { clonePatterns } from "./clonePatterns";
5
5
  import { filterOutNull } from "./filterOutNull";
6
6
  import { findPattern } from "./findPattern";
7
- import { DepthCache } from "./DepthCache";
8
7
  import { isRecursivePattern } from "./isRecursivePattern";
9
8
 
10
- const depthCache = new DepthCache();
11
9
  let idIndex = 0;
12
10
 
13
11
  export class Sequence implements Pattern {
@@ -45,6 +43,10 @@ export class Sequence implements Pattern {
45
43
  return this._children;
46
44
  }
47
45
 
46
+ get startedOnIndex() {
47
+ return this._firstIndex;
48
+ }
49
+
48
50
  constructor(name: string, sequence: Pattern[]) {
49
51
  if (sequence.length === 0) {
50
52
  throw new Error("Need at least one pattern with a 'sequence' pattern.");
@@ -88,14 +90,9 @@ export class Sequence implements Pattern {
88
90
  }
89
91
 
90
92
  parse(cursor: Cursor): Node | null {
91
- // This is a cache to help with speed
92
93
  this._firstIndex = cursor.index;
93
- depthCache.incrementDepth(this._id, this._firstIndex);
94
-
95
94
  this._nodes = [];
96
-
97
95
  const passed = this.tryToParse(cursor);
98
- depthCache.decrementDepth(this._id, this._firstIndex);
99
96
 
100
97
  if (passed) {
101
98
  const node = this.createNode(cursor);
@@ -115,7 +112,7 @@ export class Sequence implements Pattern {
115
112
  }
116
113
 
117
114
  private tryToParse(cursor: Cursor): boolean {
118
- if (depthCache.getDepth(this._id, this._firstIndex) > 1) {
115
+ if (this._isBeyondRecursiveAllowance()) {
119
116
  cursor.recordErrorAt(this._firstIndex, this._firstIndex, this);
120
117
  return false;
121
118
  }
@@ -190,6 +187,24 @@ export class Sequence implements Pattern {
190
187
  return nodes[nodes.length - 1];
191
188
  }
192
189
 
190
+ private _isBeyondRecursiveAllowance() {
191
+ let depth = 0;
192
+ let pattern: Pattern | null = this;
193
+
194
+ while (pattern != null) {
195
+ if (pattern.id === this.id && pattern.startedOnIndex === this.startedOnIndex) {
196
+ depth++;
197
+ }
198
+
199
+ if (depth > 1) {
200
+ return true;
201
+ }
202
+ pattern = pattern.parent;
203
+ }
204
+
205
+ return false;
206
+ }
207
+
193
208
  private areRemainingPatternsOptional(fromIndex: number): boolean {
194
209
  const startOnIndex = fromIndex + 1;
195
210
  const length = this._children.length;
@@ -1,26 +0,0 @@
1
- export class DepthCache {
2
- private _depthMap: Record<string, Record<number, number>> = {};
3
-
4
- getDepth(name: string, cursorIndex: number) {
5
- if (this._depthMap[name] == null) {
6
- this._depthMap[name] = {};
7
- }
8
-
9
- if (this._depthMap[name][cursorIndex] == null) {
10
- this._depthMap[name][cursorIndex] = 0;
11
- }
12
-
13
-
14
- return this._depthMap[name][cursorIndex];
15
- }
16
-
17
- incrementDepth(name: string, cursorIndex: number) {
18
- const depth = this.getDepth(name, cursorIndex);
19
- this._depthMap[name][cursorIndex] = depth + 1;
20
- }
21
-
22
- decrementDepth(name: string, cursorIndex: number) {
23
- const depth = this.getDepth(name, cursorIndex);
24
- this._depthMap[name][cursorIndex] = depth - 1;
25
- }
26
- }