-
-
Notifications
You must be signed in to change notification settings - Fork 7
/
parser.ts
118 lines (94 loc) · 3.72 KB
/
parser.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import { simple } from "acorn-walk"
import { Parser as AcornParser } from "acorn"
import staticClassFeatures from "acorn-static-class-features"
import privateMethods from "acorn-private-methods"
import classFields from "acorn-class-fields"
import { Project } from "./project"
import { ControllerDefinition, defaultValuesForType } from "./controller_definition"
import { NodeElement, PropertyValue } from "./types"
export class Parser {
private readonly project: Project
private parser: typeof AcornParser
constructor(project: Project) {
this.project = project
this.parser = AcornParser
.extend(staticClassFeatures)
.extend(privateMethods)
.extend(classFields)
}
parse(code: string) {
return this.parser.parse(code, {
sourceType: "module",
ecmaVersion: 2020,
})
}
parseController(code: string, filename: string) {
try {
const ast = this.parse(code)
const controller = new ControllerDefinition(this.project, filename)
simple(ast, {
MethodDefinition(node: any): void {
if (node.kind === "method") {
controller.methods.push(node.key.name)
}
},
PropertyDefinition(node: any): void {
const { name } = node.key
if (node.value.type === "ArrowFunctionExpression") {
controller.methods.push(name)
}
if (name === "targets") {
controller.targets = node.value.elements.map((element: NodeElement) => element.value)
}
if (name === "classes") {
controller.classes = node.value.elements.map((element: NodeElement) => element.value)
}
if (name === "values") {
node.value.properties.forEach((property: NodeElement) => {
const value = property.value
let type
let defaultValue
if (value.name && typeof value.name === "string") {
type = value.name
defaultValue = defaultValuesForType[type]
} else {
const properties = property.value.properties
const convertArrayExpression = (value: PropertyValue) => {
return value.elements.map((node) => node.value)
}
const convertObjectExpression = (value: PropertyValue) => {
return Object.fromEntries(value.properties.map((property) => [property.key.name, property.value.value]))
}
const convertProperty = (value: PropertyValue) => {
switch (value.type) {
case "ArrayExpression":
return convertArrayExpression(value)
case "ObjectExpression":
return convertObjectExpression(value)
}
}
const typeProperty = properties.find((property) => property.key.name === "type")
const defaultProperty = properties.find((property) => property.key.name === "default")
type = typeProperty?.value.name || ""
defaultValue = defaultProperty?.value.value
if (!defaultValue && defaultProperty) {
defaultValue = convertProperty(defaultProperty.value)
}
}
controller.values[property.key.name] = {
type: type,
default: defaultValue,
}
})
}
},
})
return controller
} catch(error: any) {
console.error(`Error while parsing controller in '${filename}': ${error.message}`)
const controller = new ControllerDefinition(this.project, filename)
controller.parseError = error.message
return controller
}
}
}