clarity-pattern-parser 8.2.1 → 8.3.1

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.
@@ -1,3 +1,7 @@
1
1
  {
2
- "typescript.tsdk": "node_modules/typescript/lib"
2
+ "typescript.tsdk": "node_modules/typescript/lib",
3
+ "typescript.preferences.importModuleSpecifierEnding": "minimal",
4
+ "javascript.preferences.importModuleSpecifierEnding": "minimal",
5
+ "typescript.preferences.importModuleSpecifier": "relative",
6
+ "javascript.preferences.importModuleSpecifier": "relative"
3
7
  }
package/README.md CHANGED
@@ -129,14 +129,14 @@ ast.toJson(2); // Look Below for output
129
129
  ```
130
130
 
131
131
  ## Or
132
- The `Or` pattern mathes any of the patterns given to the constructor.
132
+ The `Or` pattern matches any of the patterns given to the constructor.
133
133
  ```ts
134
134
  import { Or, Literal } from "clarity-pattern-parser";
135
135
 
136
136
  const jane = new Literal("jane", "Jane");
137
137
  const john = new Literal("john", "John");
138
138
  const firstName = new Or("first-name", [jane, john]);
139
- const { ast }= firstName.exec("Jane");
139
+ const { ast } = firstName.exec("Jane");
140
140
 
141
141
  ast.toJson(2)
142
142
  ```
@@ -1,12 +1,29 @@
1
1
  import { Pattern } from "../patterns/Pattern";
2
+ export interface GrammarMeta {
3
+ originPath?: string;
4
+ }
5
+ export interface GrammarFile {
6
+ path: string;
7
+ expression: string;
8
+ }
9
+ export interface GrammarOptions {
10
+ resolveImport?: (path: string, originPath: string | null) => Promise<GrammarFile>;
11
+ meta?: GrammarMeta | null;
12
+ }
2
13
  export declare class Grammar {
14
+ private _meta;
15
+ private _resolveImport;
3
16
  private _parseContext;
4
17
  private _autoComplete;
5
- constructor();
6
- parse(expression: string): Map<string, Pattern>;
18
+ constructor(options?: GrammarOptions);
19
+ import(path: string): Promise<Map<string, Pattern>>;
20
+ parse(expression: string): Promise<Map<string, Pattern>>;
21
+ parseString(expression: string): Map<string, Pattern>;
7
22
  private _tryToParse;
23
+ private _hasImports;
8
24
  private _cleanAst;
9
25
  private _buildPatterns;
26
+ private _resolveImports;
10
27
  private _buildLiteral;
11
28
  private _buildRegex;
12
29
  private _buildOr;
@@ -14,5 +31,7 @@ export declare class Grammar {
14
31
  private _buildAnd;
15
32
  private _buildRepeat;
16
33
  private _buildAlias;
17
- static parse(expression: string): Map<string, Pattern>;
34
+ static parse(expression: string, options?: GrammarOptions): Promise<Map<string, Pattern>>;
35
+ static import(path: string, options?: GrammarOptions): Promise<Map<string, Pattern>>;
36
+ static parseString(expression: string): Map<string, Pattern>;
18
37
  }
@@ -0,0 +1,2 @@
1
+ import { And } from "../../patterns/And";
2
+ export declare const importStatement: And;
@@ -182,6 +182,36 @@
182
182
  }
183
183
  }
184
184
 
185
+ /******************************************************************************
186
+ Copyright (c) Microsoft Corporation.
187
+
188
+ Permission to use, copy, modify, and/or distribute this software for any
189
+ purpose with or without fee is hereby granted.
190
+
191
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
192
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
193
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
194
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
195
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
196
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
197
+ PERFORMANCE OF THIS SOFTWARE.
198
+ ***************************************************************************** */
199
+
200
+ function __awaiter(thisArg, _arguments, P, generator) {
201
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
202
+ return new (P || (P = Promise))(function (resolve, reject) {
203
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
204
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
205
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
206
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
207
+ });
208
+ }
209
+
210
+ typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
211
+ var e = new Error(message);
212
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
213
+ };
214
+
185
215
  class ParseError {
186
216
  constructor(startIndex, endIndex, pattern) {
187
217
  this.startIndex = startIndex;
@@ -976,8 +1006,9 @@
976
1006
  }
977
1007
  }
978
1008
  if (matchCount < this._min) {
1009
+ const lastIndex = cursor.index;
979
1010
  cursor.moveTo(startIndex);
980
- cursor.recordErrorAt(startIndex, startIndex, this);
1011
+ cursor.recordErrorAt(startIndex, lastIndex, this);
981
1012
  return null;
982
1013
  }
983
1014
  else if (nodes.length === 0) {
@@ -1094,10 +1125,10 @@
1094
1125
  const divider = options.divider;
1095
1126
  let children;
1096
1127
  if (divider != null) {
1097
- children = [pattern.clone(), divider.clone(divider.name, false)];
1128
+ children = [pattern.clone(pattern.name, false), divider.clone(divider.name, false)];
1098
1129
  }
1099
1130
  else {
1100
- children = [pattern.clone()];
1131
+ children = [pattern.clone(pattern.name, false)];
1101
1132
  }
1102
1133
  this._assignChildrenToParent(children);
1103
1134
  this._type = "infinite-repeat";
@@ -1217,6 +1248,10 @@
1217
1248
  const dividerNode = this._nodes.pop();
1218
1249
  cursor.moveTo(dividerNode.firstIndex);
1219
1250
  }
1251
+ // if (this._nodes.length === 0) {
1252
+ // cursor.moveTo(this._firstIndex);
1253
+ // return null;
1254
+ // }
1220
1255
  const lastIndex = this._nodes[this._nodes.length - 1].lastIndex;
1221
1256
  cursor.moveTo(lastIndex);
1222
1257
  return new Node(this._type, this._name, this._firstIndex, lastIndex, this._nodes);
@@ -1548,7 +1583,6 @@
1548
1583
  createNode(cursor) {
1549
1584
  const children = filterOutNull(this._nodes);
1550
1585
  const lastIndex = children[children.length - 1].lastIndex;
1551
- cursor.getChars(this._firstIndex, lastIndex);
1552
1586
  cursor.moveTo(lastIndex);
1553
1587
  return new Node("and", this._name, this._firstIndex, lastIndex, children);
1554
1588
  }
@@ -1590,9 +1624,6 @@
1590
1624
  let index = -1;
1591
1625
  for (let i = 0; i < this._children.length; i++) {
1592
1626
  if (this._children[i] === childReference) {
1593
- if (i + 1 < this._children.length) {
1594
- this._children[i + 1];
1595
- }
1596
1627
  nextSiblingIndex = i + 1;
1597
1628
  index = i;
1598
1629
  break;
@@ -1634,11 +1665,11 @@
1634
1665
  }
1635
1666
  }
1636
1667
 
1637
- const name = new Regex("name", "[a-zA-Z_-]+[a-zA-Z0-9_-]*");
1668
+ const name$1 = new Regex("name", "[a-zA-Z_-]+[a-zA-Z0-9_-]*");
1638
1669
 
1639
1670
  const optionalNot = new Literal("not", "!", true);
1640
1671
  const optionalIsOptional$1 = new Literal("is-optional", "?", true);
1641
- const patternName$1 = name.clone("pattern-name");
1672
+ const patternName$1 = name$1.clone("pattern-name");
1642
1673
  const pattern$1 = new And("pattern", [
1643
1674
  optionalNot,
1644
1675
  patternName$1,
@@ -1651,44 +1682,44 @@
1651
1682
 
1652
1683
  const divider = new Regex("or-divider", "\\s*[|]\\s*");
1653
1684
  divider.setTokens([" | "]);
1654
- const orLiteral = new Repeat("or-literal", name.clone("pattern-name"), { divider, min: 2 });
1685
+ const orLiteral = new Repeat("or-literal", name$1.clone("pattern-name"), { divider, min: 2 });
1655
1686
 
1656
1687
  const regexLiteral = new Regex("regex-literal", "/(\\\\/|[^/\\n\\r])*/");
1657
1688
 
1658
- const spaces = new Regex("spaces", "[ \\t]+");
1659
- spaces.setTokens([" "]);
1689
+ const spaces$1 = new Regex("spaces", "[ \\t]+");
1690
+ spaces$1.setTokens([" "]);
1660
1691
 
1661
1692
  const optionalIsOptional = new Literal("is-optional", "?", true);
1662
- const patternName = name.clone("pattern-name");
1693
+ const patternName = name$1.clone("pattern-name");
1663
1694
  const pattern = new And("pattern", [
1664
1695
  patternName,
1665
1696
  optionalIsOptional,
1666
1697
  ]);
1667
- const optionalSpaces$1 = spaces.clone("optional-spaces", true);
1668
- const dividerPattern = name.clone("divider-pattern");
1669
- const openBracket = new Literal("open-bracket", "{");
1670
- const closeBracket = new Literal("close-bracket", "}");
1698
+ const optionalSpaces$2 = spaces$1.clone("optional-spaces", true);
1699
+ const dividerPattern = name$1.clone("divider-pattern");
1700
+ const openBracket$1 = new Literal("open-bracket", "{");
1701
+ const closeBracket$1 = new Literal("close-bracket", "}");
1671
1702
  const comma = new Literal("comma", ",");
1672
1703
  const integer = new Regex("integer", "([1-9][0-9]*)|0");
1673
1704
  integer.setTokens(["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]);
1674
1705
  const optionalInteger = integer.clone("integer", true);
1675
1706
  const bounds = new And("bounds", [
1676
- openBracket,
1677
- optionalSpaces$1,
1707
+ openBracket$1,
1708
+ optionalSpaces$2,
1678
1709
  optionalInteger.clone("min"),
1679
- optionalSpaces$1,
1710
+ optionalSpaces$2,
1680
1711
  comma,
1681
- optionalSpaces$1,
1712
+ optionalSpaces$2,
1682
1713
  optionalInteger.clone("max"),
1683
- optionalSpaces$1,
1684
- closeBracket
1714
+ optionalSpaces$2,
1715
+ closeBracket$1
1685
1716
  ]);
1686
1717
  const exactCount = new And("exact-count", [
1687
- openBracket,
1688
- optionalSpaces$1,
1718
+ openBracket$1,
1719
+ optionalSpaces$2,
1689
1720
  integer,
1690
- optionalSpaces$1,
1691
- closeBracket,
1721
+ optionalSpaces$2,
1722
+ closeBracket$1,
1692
1723
  ]);
1693
1724
  const quantifierShorthand = new Regex("quantifier-shorthand", "\\*|\\+");
1694
1725
  quantifierShorthand.setTokens(["*", "+"]);
@@ -1705,19 +1736,19 @@
1705
1736
  dividerComma.setTokens([", "]);
1706
1737
  const repeatLiteral = new And("repeat-literal", [
1707
1738
  openParen,
1708
- optionalSpaces$1,
1739
+ optionalSpaces$2,
1709
1740
  pattern,
1710
1741
  optional,
1711
1742
  new And("optional-divider-section", [dividerComma, dividerPattern], true),
1712
- optionalSpaces$1,
1743
+ optionalSpaces$2,
1713
1744
  closeParen,
1714
- new And("quantifier-section", [optionalSpaces$1, quantifier]),
1715
- new And("optional-trim-divider-section", [spaces, trimDivider], true)
1745
+ new And("quantifier-section", [optionalSpaces$2, quantifier]),
1746
+ new And("optional-trim-divider-section", [spaces$1, trimDivider], true)
1716
1747
  ]);
1717
1748
 
1718
1749
  const literal = new Regex("literal", "\"(?:\\\\[\"\\\\]|[^\n\"\\\\])*\"");
1719
1750
 
1720
- const optionalSpaces = spaces.clone("optional-spaces", true);
1751
+ const optionalSpaces$1 = spaces$1.clone("optional-spaces", true);
1721
1752
  const assignOperator = new Literal("assign-operator", "=");
1722
1753
  const optionalComment = comment.clone("inline-comment", true);
1723
1754
  const statements = new Or("statements", [
@@ -1726,30 +1757,55 @@
1726
1757
  orLiteral,
1727
1758
  andLiteral,
1728
1759
  repeatLiteral,
1729
- name.clone("alias-literal"),
1760
+ name$1.clone("alias-literal"),
1730
1761
  ]);
1731
1762
  const statement = new And("statement", [
1732
- optionalSpaces,
1733
- name,
1734
- optionalSpaces,
1763
+ optionalSpaces$1,
1764
+ name$1,
1765
+ optionalSpaces$1,
1735
1766
  assignOperator,
1736
- optionalSpaces,
1767
+ optionalSpaces$1,
1737
1768
  statements,
1738
- optionalSpaces,
1769
+ optionalSpaces$1,
1739
1770
  optionalComment,
1771
+ optionalSpaces$1,
1772
+ ]);
1773
+
1774
+ const spaces = new Regex("spaces", "\\s+", true);
1775
+ const importNameDivider = new Regex("import-name-divider", "(\\s+)?,(\\s+)?");
1776
+ const importKeyword = new Literal("import", "import");
1777
+ const fromKeyword = new Literal("from", "from");
1778
+ const openBracket = new Literal("open-bracket", "{");
1779
+ const closeBracket = new Literal("close-bracket", "}");
1780
+ const name = new Regex("import-name", "[^}\\s,]+");
1781
+ const importedNames = new Repeat("imported-names", name, { divider: importNameDivider });
1782
+ const optionalSpaces = spaces.clone("optional-spaces", true);
1783
+ const importStatement = new And("import-statement", [
1784
+ importKeyword,
1785
+ optionalSpaces,
1786
+ openBracket,
1740
1787
  optionalSpaces,
1788
+ importedNames,
1789
+ optionalSpaces,
1790
+ closeBracket,
1791
+ optionalSpaces,
1792
+ fromKeyword,
1793
+ spaces,
1794
+ literal.clone("url"),
1741
1795
  ]);
1742
1796
 
1743
- const whitespace = new Regex("whitespace", "[ \\t]+");
1797
+ const whitespace = new Regex("whitespace", "[ \\t]+((\\r?\\n)+)?");
1744
1798
  const newLine = new Regex("new-line", "(\\r?\\n)+");
1745
1799
  whitespace.setTokens([" "]);
1746
1800
  newLine.setTokens(["\n"]);
1747
1801
  const line = new Or("line", [
1802
+ newLine,
1803
+ whitespace,
1748
1804
  comment,
1749
- statement,
1750
- whitespace
1751
- ], true);
1752
- const grammar = new Repeat("grammar", line, { divider: newLine });
1805
+ importStatement,
1806
+ statement
1807
+ ]);
1808
+ const grammar = new Repeat("grammer", line);
1753
1809
 
1754
1810
  class Not {
1755
1811
  get type() {
@@ -2046,10 +2102,16 @@
2046
2102
  class ParseContext {
2047
2103
  constructor() {
2048
2104
  this.patternsByName = new Map();
2105
+ this.importedPatternsByName = new Map();
2049
2106
  }
2050
2107
  }
2108
+ function defaultImportResolver(_path, _basePath) {
2109
+ throw new Error("No import resolver supplied.");
2110
+ }
2051
2111
  class Grammar {
2052
- constructor() {
2112
+ constructor(options = {}) {
2113
+ this._meta = options.meta == null ? null : options.meta;
2114
+ this._resolveImport = options.resolveImport == null ? defaultImportResolver : options.resolveImport;
2053
2115
  this._parseContext = new ParseContext();
2054
2116
  this._autoComplete = new AutoComplete(grammar, {
2055
2117
  greedyPatternNames: ["spaces", "optional-spaces", "whitespace", "new-line"],
@@ -2061,9 +2123,31 @@
2061
2123
  }
2062
2124
  });
2063
2125
  }
2126
+ import(path) {
2127
+ return __awaiter(this, void 0, void 0, function* () {
2128
+ const grammarFile = yield this._resolveImport(path, null);
2129
+ const grammar = new Grammar({ resolveImport: this._resolveImport, meta: { originPath: grammarFile.path } });
2130
+ return grammar.parse(grammarFile.expression);
2131
+ });
2132
+ }
2064
2133
  parse(expression) {
2134
+ return __awaiter(this, void 0, void 0, function* () {
2135
+ this._parseContext = new ParseContext();
2136
+ const ast = this._tryToParse(expression);
2137
+ yield this._resolveImports(ast);
2138
+ this._buildPatterns(ast);
2139
+ this._cleanAst(ast);
2140
+ return this._parseContext.patternsByName;
2141
+ });
2142
+ }
2143
+ parseString(expression) {
2065
2144
  this._parseContext = new ParseContext();
2066
- this._tryToParse(expression);
2145
+ const ast = this._tryToParse(expression);
2146
+ if (this._hasImports(ast)) {
2147
+ throw new Error("Cannot use imports on parseString, use parse instead.");
2148
+ }
2149
+ this._buildPatterns(ast);
2150
+ this._cleanAst(ast);
2067
2151
  return this._parseContext.patternsByName;
2068
2152
  }
2069
2153
  _tryToParse(expression) {
@@ -2080,8 +2164,14 @@
2080
2164
  throw new Error(message);
2081
2165
  }
2082
2166
  // If it is complete it will always have a node. So we have to cast it.
2083
- this._cleanAst(ast);
2084
- this._buildPatterns(ast);
2167
+ return ast;
2168
+ }
2169
+ _hasImports(ast) {
2170
+ const importBlock = ast.find(n => n.name === "import-block");
2171
+ if (importBlock == null) {
2172
+ return false;
2173
+ }
2174
+ return importBlock && importBlock.children.length > 0;
2085
2175
  }
2086
2176
  _cleanAst(ast) {
2087
2177
  ast.findAll(n => n.name === "spaces" ||
@@ -2122,6 +2212,36 @@
2122
2212
  }
2123
2213
  });
2124
2214
  }
2215
+ _resolveImports(ast) {
2216
+ var _a;
2217
+ return __awaiter(this, void 0, void 0, function* () {
2218
+ const parseContext = this._parseContext;
2219
+ const importStatements = ast.findAll(n => n.name === "import-statement");
2220
+ for (const importStatement of importStatements) {
2221
+ const urlNode = importStatement.find(n => n.name === "url");
2222
+ const url = urlNode.value.slice(1, -1);
2223
+ const grammarFile = yield this._resolveImport(url, ((_a = this._meta) === null || _a === void 0 ? void 0 : _a.originPath) || null);
2224
+ const grammar = new Grammar({ resolveImport: this._resolveImport, meta: { originPath: grammarFile.path } });
2225
+ try {
2226
+ const patterns = yield grammar.parse(grammarFile.expression);
2227
+ const importNames = importStatement.findAll(n => n.name === "import-name").map(n => n.value);
2228
+ importNames.forEach((importName) => {
2229
+ if (parseContext.importedPatternsByName.has(importName)) {
2230
+ throw new Error(`'${importName}' was already used within another import.`);
2231
+ }
2232
+ const pattern = patterns.get(importName);
2233
+ if (pattern == null) {
2234
+ throw new Error(`Couldn't find pattern with name: ${importName}, from import: ${url}.`);
2235
+ }
2236
+ parseContext.importedPatternsByName.set(importName, pattern);
2237
+ });
2238
+ }
2239
+ catch (e) {
2240
+ throw new Error(`Failed loading expression from: "${url}". Error details: "${e.message}"`);
2241
+ }
2242
+ }
2243
+ });
2244
+ }
2125
2245
  _buildLiteral(statementNode) {
2126
2246
  const nameNode = statementNode.find(n => n.name === "name");
2127
2247
  const literalNode = statementNode.find(n => n.name === "literal");
@@ -2148,7 +2268,10 @@
2148
2268
  this._parseContext.patternsByName.set(name, or);
2149
2269
  }
2150
2270
  _getPattern(name) {
2151
- const pattern = this._parseContext.patternsByName.get(name);
2271
+ let pattern = this._parseContext.patternsByName.get(name);
2272
+ if (pattern == null) {
2273
+ pattern = this._parseContext.importedPatternsByName.get(name);
2274
+ }
2152
2275
  if (pattern == null) {
2153
2276
  return new Reference(name);
2154
2277
  }
@@ -2233,10 +2356,18 @@
2233
2356
  const alias = pattern.clone(name);
2234
2357
  this._parseContext.patternsByName.set(name, alias);
2235
2358
  }
2236
- static parse(expression) {
2237
- const grammar = new Grammar();
2359
+ static parse(expression, options) {
2360
+ const grammar = new Grammar(options);
2238
2361
  return grammar.parse(expression);
2239
2362
  }
2363
+ static import(path, options) {
2364
+ const grammar = new Grammar(options);
2365
+ return grammar.import(path);
2366
+ }
2367
+ static parseString(expression) {
2368
+ const grammar = new Grammar();
2369
+ return grammar.parseString(expression);
2370
+ }
2240
2371
  }
2241
2372
 
2242
2373
  exports.And = And;
@@ -2252,6 +2383,7 @@
2252
2383
  exports.Reference = Reference;
2253
2384
  exports.Regex = Regex;
2254
2385
  exports.Repeat = Repeat;
2386
+ exports.grammar = grammar;
2255
2387
 
2256
2388
  Object.defineProperty(exports, '__esModule', { value: true });
2257
2389