@herb-tools/core 0.1.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/CHANGELOG.md +3 -0
- package/README.md +9 -0
- package/dist/herb-core.browser.js +2704 -0
- package/dist/herb-core.browser.js.map +1 -0
- package/dist/herb-core.cjs +2759 -0
- package/dist/herb-core.cjs.map +1 -0
- package/dist/herb-core.esm.js +2704 -0
- package/dist/herb-core.esm.js.map +1 -0
- package/dist/herb-core.umd.js +2765 -0
- package/dist/herb-core.umd.js.map +1 -0
- package/dist/types/ast.d.ts +4 -0
- package/dist/types/backend.d.ts +24 -0
- package/dist/types/error.d.ts +16 -0
- package/dist/types/errors.d.ts +222 -0
- package/dist/types/herb-backend.d.ts +87 -0
- package/dist/types/index.d.ts +15 -0
- package/dist/types/lex-result.d.ts +50 -0
- package/dist/types/location.d.ts +18 -0
- package/dist/types/node.d.ts +27 -0
- package/dist/types/nodes.d.ts +682 -0
- package/dist/types/parse-result.d.ts +62 -0
- package/dist/types/position.d.ts +15 -0
- package/dist/types/range.d.ts +12 -0
- package/dist/types/result.d.ts +10 -0
- package/dist/types/token-list.d.ts +16 -0
- package/dist/types/token.d.ts +22 -0
- package/dist/types/util.d.ts +2 -0
- package/dist/types/visitor.d.ts +11 -0
- package/dist/types/warning.d.ts +11 -0
- package/package.json +49 -0
- package/src/ast.ts +7 -0
- package/src/backend.ts +85 -0
- package/src/error.ts +38 -0
- package/src/errors.ts +820 -0
- package/src/herb-backend.ts +152 -0
- package/src/index.ts +15 -0
- package/src/lex-result.ts +78 -0
- package/src/location.ts +51 -0
- package/src/node.ts +106 -0
- package/src/nodes.ts +2294 -0
- package/src/parse-result.ts +101 -0
- package/src/position.ts +38 -0
- package/src/range.ts +35 -0
- package/src/result.ts +26 -0
- package/src/token-list.ts +57 -0
- package/src/token.ts +63 -0
- package/src/util.ts +19 -0
- package/src/visitor.ts +14 -0
- package/src/warning.ts +20 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { Result } from "./result.js"
|
|
2
|
+
import { DocumentNode } from "./nodes.js"
|
|
3
|
+
import { HerbError } from "./error.js"
|
|
4
|
+
import { HerbWarning } from "./warning.js"
|
|
5
|
+
|
|
6
|
+
import type { SerializedHerbError } from "./error.js"
|
|
7
|
+
import type { SerializedHerbWarning } from "./warning.js"
|
|
8
|
+
import type { SerializedDocumentNode } from "./nodes.js"
|
|
9
|
+
import type { Visitor } from "./visitor.js"
|
|
10
|
+
|
|
11
|
+
export type SerializedParseResult = {
|
|
12
|
+
value: SerializedDocumentNode
|
|
13
|
+
source: string
|
|
14
|
+
warnings: SerializedHerbWarning[]
|
|
15
|
+
errors: SerializedHerbError[]
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Represents the result of a parsing operation, extending the base `Result` class.
|
|
20
|
+
* It contains the parsed document node, source code, warnings, and errors.
|
|
21
|
+
*/
|
|
22
|
+
export class ParseResult extends Result {
|
|
23
|
+
/** The document node generated from the source code. */
|
|
24
|
+
readonly value: DocumentNode
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Creates a `ParseResult` instance from a serialized result.
|
|
28
|
+
* @param result - The serialized parse result containing the value and source.
|
|
29
|
+
* @returns A new `ParseResult` instance.
|
|
30
|
+
*/
|
|
31
|
+
static from(result: SerializedParseResult) {
|
|
32
|
+
return new ParseResult(
|
|
33
|
+
DocumentNode.from(result.value),
|
|
34
|
+
result.source,
|
|
35
|
+
result.warnings.map((warning) => HerbWarning.from(warning)),
|
|
36
|
+
result.errors.map((error) => HerbError.from(error)),
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Constructs a new `ParseResult`.
|
|
42
|
+
* @param value - The document node.
|
|
43
|
+
* @param source - The source code that was parsed.
|
|
44
|
+
* @param warnings - An array of warnings encountered during parsing.
|
|
45
|
+
* @param errors - An array of errors encountered during parsing.
|
|
46
|
+
*/
|
|
47
|
+
constructor(
|
|
48
|
+
value: DocumentNode,
|
|
49
|
+
source: string,
|
|
50
|
+
warnings: HerbWarning[] = [],
|
|
51
|
+
errors: HerbError[] = [],
|
|
52
|
+
) {
|
|
53
|
+
super(source, warnings, errors)
|
|
54
|
+
this.value = value
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Determines if the parsing failed.
|
|
59
|
+
* @returns `true` if there are errors, otherwise `false`.
|
|
60
|
+
*/
|
|
61
|
+
failed(): boolean {
|
|
62
|
+
// TODO: this should probably be recursive as noted in the Ruby version
|
|
63
|
+
return this.errors.length > 0 || this.value.errors.length > 0
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Determines if the parsing was successful.
|
|
68
|
+
* @returns `true` if there are no errors, otherwise `false`.
|
|
69
|
+
*/
|
|
70
|
+
success(): boolean {
|
|
71
|
+
return !this.failed()
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Returns a pretty-printed JSON string of the errors.
|
|
76
|
+
* @returns A string representation of the errors.
|
|
77
|
+
*/
|
|
78
|
+
prettyErrors(): string {
|
|
79
|
+
return JSON.stringify([...this.errors, ...this.value.errors], null, 2)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
recursiveErrors(): HerbError[] {
|
|
83
|
+
return [...this.errors, ...this.value.recursiveErrors()]
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Returns a pretty-printed string of the parse result.
|
|
88
|
+
* @returns A string representation of the parse result.
|
|
89
|
+
*/
|
|
90
|
+
inspect(): string {
|
|
91
|
+
return this.value.inspect()
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Accepts a visitor to traverse the document node.
|
|
96
|
+
* @param visitor - The visitor instance.
|
|
97
|
+
*/
|
|
98
|
+
visit(visitor: Visitor): void {
|
|
99
|
+
visitor.visit(this.value)
|
|
100
|
+
}
|
|
101
|
+
}
|
package/src/position.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export type SerializedPosition = {
|
|
2
|
+
line: number
|
|
3
|
+
column: number
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export class Position {
|
|
7
|
+
readonly line: number
|
|
8
|
+
readonly column: number
|
|
9
|
+
|
|
10
|
+
static from(position: SerializedPosition) {
|
|
11
|
+
return new Position(position.line, position.column)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
constructor(line: number, column: number) {
|
|
15
|
+
this.line = line
|
|
16
|
+
this.column = column
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
toHash(): SerializedPosition {
|
|
20
|
+
return { line: this.line, column: this.column }
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
toJSON(): SerializedPosition {
|
|
24
|
+
return this.toHash()
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
treeInspect(): string {
|
|
28
|
+
return `(${this.line}:${this.column})`
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
inspect(): string {
|
|
32
|
+
return `#<Herb::Position ${this.treeInspect()}>`
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
toString(): string {
|
|
36
|
+
return this.inspect()
|
|
37
|
+
}
|
|
38
|
+
}
|
package/src/range.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export type SerializedRange = [number, number]
|
|
2
|
+
|
|
3
|
+
export class Range {
|
|
4
|
+
readonly start: number
|
|
5
|
+
readonly end: number
|
|
6
|
+
|
|
7
|
+
static from(range: SerializedRange) {
|
|
8
|
+
return new Range(range[0], range[1])
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
constructor(start: number, end: number) {
|
|
12
|
+
this.start = start
|
|
13
|
+
this.end = end
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
toArray(): SerializedRange {
|
|
17
|
+
return [this.start, this.end]
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
toJSON(): SerializedRange {
|
|
21
|
+
return this.toArray()
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
treeInspect(): string {
|
|
25
|
+
return `[${this.start}, ${this.end}]`
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
inspect(): string {
|
|
29
|
+
return `#<Herb::Range ${this.toArray()}>`
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
toString(): string {
|
|
33
|
+
return this.inspect()
|
|
34
|
+
}
|
|
35
|
+
}
|
package/src/result.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { HerbError } from "./error.js"
|
|
2
|
+
import { HerbWarning } from "./warning.js"
|
|
3
|
+
|
|
4
|
+
export class Result {
|
|
5
|
+
readonly source: string
|
|
6
|
+
readonly warnings: HerbWarning[]
|
|
7
|
+
readonly errors: HerbError[]
|
|
8
|
+
|
|
9
|
+
constructor(
|
|
10
|
+
source: string,
|
|
11
|
+
warnings: HerbWarning[] = [],
|
|
12
|
+
errors: HerbError[] = [],
|
|
13
|
+
) {
|
|
14
|
+
this.source = source
|
|
15
|
+
this.warnings = warnings || []
|
|
16
|
+
this.errors = errors || []
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
success(): boolean {
|
|
20
|
+
return false
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
failed(): boolean {
|
|
24
|
+
return true
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { Token, SerializedToken } from "./token.js"
|
|
2
|
+
|
|
3
|
+
export type SerializedTokenList = SerializedToken[]
|
|
4
|
+
|
|
5
|
+
export class TokenList implements Iterable<Token> {
|
|
6
|
+
private list: Token[]
|
|
7
|
+
|
|
8
|
+
static from(list: SerializedTokenList) {
|
|
9
|
+
return new TokenList(
|
|
10
|
+
list.map((token: SerializedToken) => Token.from(token)),
|
|
11
|
+
)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
constructor(list: Token[]) {
|
|
15
|
+
this.list = list
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
get length(): number {
|
|
19
|
+
return this.list.length
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
[Symbol.iterator](): Iterator<Token> {
|
|
23
|
+
return this.list[Symbol.iterator]()
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
at(index: number): Token | undefined {
|
|
27
|
+
return this.list.at(index)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
forEach(
|
|
31
|
+
callback: (token: Token, index: number, array: Token[]) => void,
|
|
32
|
+
): void {
|
|
33
|
+
this.list.forEach(callback)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
map<U>(callback: (token: Token, index: number, array: Token[]) => U): U[] {
|
|
37
|
+
return this.list.map(callback)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
filter(
|
|
41
|
+
predicate: (token: Token, index: number, array: Token[]) => boolean,
|
|
42
|
+
): Token[] {
|
|
43
|
+
return this.list.filter(predicate)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
__getobj__(): Token[] {
|
|
47
|
+
return this.list
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
inspect(): string {
|
|
51
|
+
return this.list.map((token) => token.inspect()).join("\n") + "\n"
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
toString(): string {
|
|
55
|
+
return this.inspect()
|
|
56
|
+
}
|
|
57
|
+
}
|
package/src/token.ts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { Range, SerializedRange } from "./range.js"
|
|
2
|
+
import { Location, SerializedLocation } from "./location.js"
|
|
3
|
+
|
|
4
|
+
export type SerializedToken = {
|
|
5
|
+
value: string
|
|
6
|
+
range: SerializedRange
|
|
7
|
+
location: SerializedLocation
|
|
8
|
+
type: string
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export class Token {
|
|
12
|
+
readonly value: string
|
|
13
|
+
readonly range: Range
|
|
14
|
+
readonly location: Location
|
|
15
|
+
readonly type: string
|
|
16
|
+
|
|
17
|
+
static from(token: SerializedToken) {
|
|
18
|
+
return new Token(
|
|
19
|
+
token.value,
|
|
20
|
+
Range.from(token.range),
|
|
21
|
+
Location.from(token.location),
|
|
22
|
+
token.type,
|
|
23
|
+
)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
constructor(value: string, range: Range, location: Location, type: string) {
|
|
27
|
+
this.value = value
|
|
28
|
+
this.range = range
|
|
29
|
+
this.location = location
|
|
30
|
+
this.type = type
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
toHash(): SerializedToken {
|
|
34
|
+
return {
|
|
35
|
+
value: this.value,
|
|
36
|
+
range: this.range?.toArray(),
|
|
37
|
+
location: this.location?.toHash(),
|
|
38
|
+
type: this.type,
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
toJSON(): SerializedToken {
|
|
43
|
+
return this.toHash()
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
treeInspect(): string {
|
|
47
|
+
return `"${this.value}" ${this.location.treeInspectWithLabel()}`
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
valueInspect(): string {
|
|
51
|
+
return this.type === "TOKEN_EOF"
|
|
52
|
+
? JSON.stringify("<EOF>")
|
|
53
|
+
: JSON.stringify(this.value)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
inspect(): string {
|
|
57
|
+
return `#<Herb::Token type="${this.type}" value=${this.valueInspect()} range=${this.range.treeInspect()} start=${this.location.start.treeInspect()} end=${this.location.end.treeInspect()}>`
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
toString(): string {
|
|
61
|
+
return this.inspect()
|
|
62
|
+
}
|
|
63
|
+
}
|
package/src/util.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export function ensureString(object: any): string {
|
|
2
|
+
if (typeof object === "string") {
|
|
3
|
+
return object
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
throw new TypeError("Argument must be a string")
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function convertToUTF8(string: string) {
|
|
10
|
+
const bytes = []
|
|
11
|
+
|
|
12
|
+
for (let i = 0; i < string.length; i++) {
|
|
13
|
+
bytes.push(string.charCodeAt(i))
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const decoder = new TextDecoder("utf-8")
|
|
17
|
+
|
|
18
|
+
return decoder.decode(new Uint8Array(bytes))
|
|
19
|
+
}
|
package/src/visitor.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Node } from "./node.js"
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Represents a visitor that can traverse nodes.
|
|
5
|
+
*/
|
|
6
|
+
export class Visitor {
|
|
7
|
+
/**
|
|
8
|
+
* Visits a node and performs an action.
|
|
9
|
+
* @param node - The node to visit.
|
|
10
|
+
*/
|
|
11
|
+
visit(node: Node) {
|
|
12
|
+
console.log("Node", node) // TODO: implement
|
|
13
|
+
}
|
|
14
|
+
}
|
package/src/warning.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Location, SerializedLocation } from "./location.js"
|
|
2
|
+
|
|
3
|
+
export interface SerializedHerbWarning {
|
|
4
|
+
message: string
|
|
5
|
+
location: SerializedLocation
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export class HerbWarning {
|
|
9
|
+
message: string
|
|
10
|
+
location: Location
|
|
11
|
+
|
|
12
|
+
static from(warning: SerializedHerbWarning) {
|
|
13
|
+
return new HerbWarning(warning.message, Location.from(warning.location))
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
constructor(message: string, location: Location) {
|
|
17
|
+
this.message = message
|
|
18
|
+
this.location = location
|
|
19
|
+
}
|
|
20
|
+
}
|