clarity-pattern-parser
Advanced tools
Comparing version 11.0.22 to 11.0.23
@@ -16,3 +16,2 @@ import { Pattern } from "../patterns/Pattern"; | ||
private _parseContext; | ||
private _autoComplete; | ||
constructor(options?: GrammarOptions); | ||
@@ -19,0 +18,0 @@ import(path: string): Promise<Record<string, Pattern>>; |
@@ -27,3 +27,4 @@ import { Cursor } from "./Cursor"; | ||
private getLastValidNode; | ||
private areRemainingPatternsOptional; | ||
private _areAllPatternsOptional; | ||
private _areRemainingPatternsOptional; | ||
private createNode; | ||
@@ -30,0 +31,0 @@ getTokens(): string[]; |
{ | ||
"name": "clarity-pattern-parser", | ||
"version": "11.0.22", | ||
"version": "11.0.23", | ||
"description": "Parsing Library for Typescript and Javascript.", | ||
@@ -5,0 +5,0 @@ "main": "./dist/index.js", |
@@ -11,3 +11,2 @@ import { Node } from "../ast/Node"; | ||
import { Repeat, RepeatOptions } from "../patterns/Repeat"; | ||
import { AutoComplete } from "../intellisense/AutoComplete"; | ||
import { Optional } from "../patterns/Optional"; | ||
@@ -17,2 +16,3 @@ import { Context } from "../patterns/Context"; | ||
import { RightAssociated } from "../patterns/RightAssociated"; | ||
import { generateErrorMessage } from "../patterns/generate_error_message"; | ||
@@ -60,3 +60,2 @@ let anonymousIndexId = 0; | ||
private _parseContext: ParseContext; | ||
private _autoComplete: AutoComplete; | ||
@@ -68,5 +67,2 @@ constructor(options: GrammarOptions = {}) { | ||
this._parseContext = new ParseContext(this._params); | ||
this._autoComplete = new AutoComplete(grammar, { | ||
greedyPatternNames: ["spaces", "optional-spaces", "whitespace", "new-line"], | ||
}); | ||
} | ||
@@ -120,18 +116,10 @@ | ||
private _tryToParse(expression: string): Node { | ||
const { ast, cursor, options, isComplete } = this._autoComplete.suggestFor(expression); | ||
const { ast, cursor } = grammar.exec(expression, true); | ||
if (!isComplete) { | ||
const text = cursor?.text || ""; | ||
const index = options.reduce((num, o) => Math.max(o.startIndex, num), 0); | ||
const foundText = text.slice(Math.max(index - 10, 0), index + 10); | ||
const expectedTexts = "'" + options.map(o => { | ||
const startText = text.slice(Math.max(o.startIndex - 10), o.startIndex); | ||
return startText + o.text; | ||
}).join("' or '") + "'"; | ||
const message = `[Parse Error] Found: '${foundText}', expected: ${expectedTexts}.`; | ||
throw new Error(message); | ||
if (ast == null) { | ||
const message = generateErrorMessage(grammar, cursor); | ||
throw new Error(`[Invalid Grammar] ${message}`); | ||
} | ||
// If it is complete it will always have a node. So we have to cast it. | ||
return ast as Node; | ||
return ast; | ||
} | ||
@@ -299,3 +287,3 @@ | ||
const isLongEnough = pattern.children.length >= 2; | ||
return pattern.type === "sequence" && isLongEnough && | ||
@@ -302,0 +290,0 @@ (firstChild.name === name || |
@@ -97,2 +97,6 @@ import { Node } from "../ast/Node"; | ||
if (!cursor.hasNext){ | ||
return false; | ||
} | ||
for (let i = 0; i < literalRuneLength; i++) { | ||
@@ -99,0 +103,0 @@ const literalRune = this._runes[i]; |
@@ -89,2 +89,4 @@ import { Node } from "../ast/Node"; | ||
if (!this._cachedAncestors) { | ||
this._cachedAncestors = true; | ||
let pattern: Pattern | null = this.parent; | ||
@@ -105,3 +107,3 @@ | ||
for (let pattern of this._recursiveAncestors) { | ||
if (pattern._firstIndex === this._firstIndex) { | ||
if (pattern.startedOnIndex === this.startedOnIndex) { | ||
depth++; | ||
@@ -108,0 +110,0 @@ |
@@ -326,2 +326,13 @@ import { Cursor } from "./Cursor"; | ||
test("All Patterns are Optional", () => { | ||
const sequence = new Sequence("sequence", [ | ||
new Optional("optional-a", new Literal("a", "A")), | ||
new Optional("optional-b", new Literal("b", "B")) | ||
]); | ||
const result = sequence.exec(""); | ||
expect(result.ast).toBe(null); | ||
expect(result.cursor.hasError).toBeFalsy(); | ||
}); | ||
}); |
@@ -86,4 +86,4 @@ import { Cursor } from "./Cursor"; | ||
const passed = this.tryToParse(cursor); | ||
if (passed) { | ||
if (passed) { | ||
const node = this.createNode(cursor); | ||
@@ -125,3 +125,3 @@ | ||
// following patterns are optional. | ||
if (this.areRemainingPatternsOptional(i)) { | ||
if (this._areRemainingPatternsOptional(i)) { | ||
passed = true; | ||
@@ -144,3 +144,3 @@ break; | ||
const lastNode = this.getLastValidNode(); | ||
if (lastNode === null) { | ||
if (lastNode === null && !this._areAllPatternsOptional()) { | ||
cursor.recordErrorAt(this._firstIndex, cursor.index, this); | ||
@@ -174,3 +174,7 @@ break; | ||
private areRemainingPatternsOptional(fromIndex: number): boolean { | ||
private _areAllPatternsOptional() { | ||
return this._areRemainingPatternsOptional(-1); | ||
} | ||
private _areRemainingPatternsOptional(fromIndex: number): boolean { | ||
const startOnIndex = fromIndex + 1; | ||
@@ -192,2 +196,7 @@ const length = this._children.length; | ||
if (children.length === 0) { | ||
cursor.moveTo(this._firstIndex); | ||
return null; | ||
} | ||
const lastIndex = children[children.length - 1].lastIndex; | ||
@@ -194,0 +203,0 @@ |
@@ -0,1 +1,4 @@ | ||
import { Node } from "../ast/Node"; | ||
import { Selector } from "./selector"; | ||
export class Query { | ||
@@ -5,11 +8,98 @@ private _context: Node[]; | ||
constructor(context: Node[], selector?: string, prevQuery: Query | null = null) { | ||
constructor(context: Node[], prevQuery: Query | null = null) { | ||
this._context = context; | ||
this._prevQuery = prevQuery; | ||
} | ||
if (selector != null) { | ||
this.find(selector); | ||
} | ||
toArray() { | ||
return this._context.slice(); | ||
} | ||
// Modifiers | ||
append(visitor: (node: Node) => Node) { | ||
this._context.forEach(n => { | ||
const parent = n.parent; | ||
if (parent == null) { | ||
return; | ||
} | ||
const newNode = visitor(n); | ||
n.appendChild(newNode); | ||
}); | ||
return this; | ||
} | ||
prepend(visitor: (node: Node) => Node) { | ||
this._context.forEach(n => { | ||
const parent = n.parent; | ||
if (parent == null) { | ||
return; | ||
} | ||
const newNode = visitor(n); | ||
n.insertBefore(newNode, n.children[0]); | ||
}); | ||
return this; | ||
} | ||
after(visitor: (node: Node) => Node) { | ||
this._context.forEach(n => { | ||
const parent = n.parent; | ||
if (parent == null) { | ||
return; | ||
} | ||
const index = parent.findChildIndex(n); | ||
const newNode = visitor(n); | ||
parent.spliceChildren(index + 1, 0, newNode); | ||
}); | ||
return this; | ||
} | ||
before(visitor: (node: Node) => Node) { | ||
this._context.forEach(n => { | ||
const parent = n.parent; | ||
if (parent == null) { | ||
return; | ||
} | ||
const index = parent.findChildIndex(n); | ||
const newNode = visitor(n); | ||
parent.spliceChildren(index, 0, newNode); | ||
}); | ||
return this; | ||
} | ||
replaceWith(visitor: (node: Node) => Node) { | ||
this._context.forEach(n => { | ||
const newNode = visitor(n); | ||
n.replaceWith(newNode); | ||
}); | ||
return this; | ||
} | ||
compact() { | ||
this._context.forEach(n => { | ||
n.compact(); | ||
}); | ||
return this; | ||
} | ||
remove() { | ||
this._context.forEach(n => { | ||
n.remove(); | ||
}); | ||
return this; | ||
} | ||
// Filters from the currently matched nodes | ||
slice(start: number, end?: number) { | ||
@@ -19,24 +109,61 @@ return new Query(this._context.slice(start, end)); | ||
// Modifiers | ||
append() { } | ||
filter(selectorString: string) { | ||
const selector = new Selector(selectorString); | ||
const newContext = selector.filter(this._context); | ||
prepend() { } | ||
return new Query(newContext, this); | ||
} | ||
after() { } | ||
// Selects out of all descedants of currently matched nodes | ||
find(selectorString: string) { | ||
const selector = new Selector(selectorString); | ||
const newContext = selector.find(this._context); | ||
before() { } | ||
return new Query(newContext, this); | ||
} | ||
// Remove nodes from the set of matched nodes. | ||
not(selectorString: string) { | ||
const selector = new Selector(selectorString); | ||
const newContext = selector.not(this._context); | ||
// Refiners | ||
filter(selector: string) { } | ||
return new Query(newContext, this); | ||
} | ||
find(selector: string) { } | ||
// Select the parent of currently matched nodes | ||
parent() { | ||
const parents = this._context.map(n => n.parent); | ||
const result = new Set<Node>(); | ||
parents.forEach((n) => { | ||
if (n != null) { | ||
result.add(n); | ||
} | ||
}); | ||
not(selector: string) { } | ||
return new Query(Array.from(result), this); | ||
} | ||
parent() { } | ||
// Select the ancestors of currently matched nodes | ||
parents(selectorString: string) { | ||
const selector = new Selector(selectorString); | ||
const newContext = selector.parents(this._context); | ||
parents(selector: string) { } | ||
const result = new Set<Node>(); | ||
newContext.forEach((n) => { | ||
if (n != null) { | ||
result.add(n); | ||
} | ||
}); | ||
return new Query(Array.from(result), this); | ||
} | ||
first() { | ||
return new Query(this._context.slice(0, 1), this); | ||
} | ||
last() { | ||
return new Query(this._context.slice(-1), this); | ||
} | ||
// Pop query stack | ||
@@ -50,2 +177,11 @@ end() { | ||
} | ||
} | ||
export function $(root: Node, selector?: string) { | ||
if (selector == null) { | ||
return new Query([root]); | ||
} else { | ||
return new Query([root]).find(selector); | ||
} | ||
} |
import { patterns } from "../grammar/patterns"; | ||
const {selector} = patterns` | ||
const { expression } = patterns` | ||
number = /[+-]?(\\d+(\\.\\d*)?|\\.\\d+)([eE][+-]?\\d+)?/ | ||
spaces = /\\s+/ | ||
single-quote-string-literal = /'(?:\\\\.|[^'\\\\])*'/ | ||
name = /[a-zA-Z_-]+[a-zA-Z0-9_-]*/ | ||
comma = /\\s*,\\s*/ | ||
wild-card = "*" | ||
equal = "=" | ||
not-equal = "!=" | ||
starts-with = "^=" | ||
ends-with = "$=" | ||
contains = "*=" | ||
greater-than-or-equal = ">=" | ||
less-than-or-equal = "<=" | ||
greater-than = ">" | ||
less-than = "<" | ||
operators = equal | | ||
not-equal | | ||
starts-with | | ||
ends-with | | ||
contains | | ||
greater-than-or-equal | | ||
less-than-or-equal | | ||
greater-than | | ||
less-than | ||
attribute-name = name | ||
value = name | ||
attribute-value = single-quote-string-literal | number | value | ||
attribute-selector = "[" + spaces? + attribute-name + spaces? + operators + spaces? + attribute-value + "]" | ||
adjacent = spaces? + "+" + spaces? | ||
after = spaces? + "~" + spaces? | ||
direct-child = spaces? + ">" + spaces? | ||
descendant = spaces | ||
combinators = adjacent | after | direct-child | descendant | ||
name-selector = name-selector-expression + attribute-selector | ||
name-selector-expression = name-selector | name | ||
node-selector = wild-card | attribute-selector | name-selector-expression | ||
or-selector = (node-selector, comma){2} | ||
`; | ||
selector-expression = expression + combinators + expression | ||
expression = selector-expression | or-selector | node-selector | ||
`; | ||
export const selectorParser = expression; |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
1346593
190
23429