-
Notifications
You must be signed in to change notification settings - Fork 12
/
grammar.js
169 lines (132 loc) · 4.05 KB
/
grammar.js
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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
module.exports = grammar({
name: "heex",
rules: {
fragment: ($) => repeat($._node),
_node: ($) =>
choice($.doctype, $.tag, $.component, $.text, $.comment, $.directive),
doctype: ($) => seq("<!", "DOCTYPE", "html", ">"),
tag: ($) =>
choice(seq($.start_tag, repeat($._node), $.end_tag), $.self_closing_tag),
component: ($) =>
choice(
seq(
$.start_component,
repeat(choice($._node, $.slot)),
$.end_component
),
$.self_closing_component
),
slot: ($) =>
choice(
seq($.start_slot, repeat($._node), $.end_slot),
$.self_closing_slot
),
start_tag: ($) =>
seq(
"<",
$.tag_name,
repeat(choice($.attribute, $.expression, $.special_attribute)),
">"
),
end_tag: ($) => seq("</", $.tag_name, ">"),
self_closing_tag: ($) =>
seq(
"<",
$.tag_name,
repeat(choice($.attribute, $.expression, $.special_attribute)),
"/>"
),
start_component: ($) =>
seq(
"<",
$.component_name,
repeat(choice($.attribute, $.expression, $.special_attribute)),
">"
),
end_component: ($) => seq("</", $.component_name, ">"),
self_closing_component: ($) =>
seq(
"<",
$.component_name,
repeat(choice($.attribute, $.expression, $.special_attribute)),
"/>"
),
start_slot: ($) =>
seq(
"<:",
alias($.tag_name, $.slot_name),
repeat(choice($.attribute, $.expression, $.special_attribute)),
">"
),
end_slot: ($) => seq("</:", alias($.tag_name, $.slot_name), ">"),
self_closing_slot: ($) =>
seq(
"<:",
alias($.tag_name, $.slot_name),
repeat(choice($.attribute, $.expression, $.special_attribute)),
"/>"
),
expression: ($) =>
seq(
"{",
prec.left(
seq(alias(repeat($._expression_value), $.expression_value), "}")
)
),
_expression_value: ($) =>
choice(/[^{}]+/, seq("{", optional($._expression_value), "}")),
special_attribute: ($) => seq($.special_attribute_name, "=", $.expression),
special_attribute_name: ($) => choice(":let", ":for", ":stream", ":if"),
attribute: ($) =>
seq(
$.attribute_name,
optional(
seq(
"=",
choice($.quoted_attribute_value, $.attribute_value, $.expression)
)
)
),
attribute_value: ($) => /[^<>{}"'=\s]+/,
quoted_attribute_value: ($) =>
choice(
seq("'", optional(alias(/[^']+/, $.attribute_value)), "'"),
seq('"', optional(alias(/[^"]+/, $.attribute_value)), '"')
),
directive: ($) =>
seq(
choice("<%", "<%=", "<%%", "<%%="),
prec.left(
seq(
choice(
$.partial_expression_value,
$.ending_expression_value,
$.expression_value
),
"%>"
)
)
),
comment: ($) => choice($._html_comment, $._bang_comment, $._hash_comment),
_html_comment: ($) => seq("<!--", prec.left(seq(repeat(/[^-]+|-/), "-->"))),
_bang_comment: ($) =>
seq("<%!--", prec.left(seq(repeat(/[^-]+|-/), "--%>"))),
_hash_comment: ($) => seq("<%#", prec.left(seq(repeat($._code), "%>"))),
expression_value: ($) => repeat1($._code),
partial_expression_value: ($) =>
seq(
repeat($._code),
choice("do", "->"),
optional(seq("#", repeat($._code)))
),
ending_expression_value: ($) => seq(/end[\)\]\}]*/, repeat($._code)),
component_name: ($) =>
choice(seq(optional($.module), seq(".", $.function)), $.module),
module: ($) => /([A-Z][^\-<>{}!"'/=\s\.]*)(\.[A-Z][^\-<>{}!"'/=\s\.]*)*/,
function: ($) => /[a-z][^\-<>{}!"'/=\s\.]*/,
_code: ($) => /[^%\s]+|[%\s]/,
tag_name: ($) => /[a-z]+[^<>{}!"'/=\s]*/,
attribute_name: ($) => token(prec(-1, /[^:<>{}"'/=\s][^<>{}"'/=\s]*/)),
text: ($) => /[^<>{}\s]([^<>{}]*[^<>{}\s])?/,
},
});