-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathgrammar.js
126 lines (111 loc) · 3.37 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
"use strict";
const JavaScript = require("tree-sitter-javascript/grammar");
function noJSX(obj) {
if (!obj) return;
if (Array.isArray(obj)) {
obj.forEach(noJSX);
return;
}
if (typeof obj === "object") {
if (obj === null) return;
if (obj.type === "CHOICE" && Array.isArray(obj.members)) {
obj.members = obj.members.filter((member) => {
if (!member.name) return true;
return !member.name.includes("jsx");
});
noJSX(obj.members);
return;
}
for (let [key, value] of Object.entries(obj)) {
if (key.includes("jsx")) {
delete obj[key];
} else {
noJSX(value);
}
}
}
}
noJSX(JavaScript);
/**
* A <template></template> block can exist in
* two types of locations:
* 1. class body
* 2. any expression
*
* The contents of `<template>contents</template>`
* are handled by tree-sitter-glimmer
* https://github.com/ember-tooling/tree-sitter-glimmer
*/
module.exports = grammar(JavaScript, {
name: "glimmer_javascript",
externals: ($, previous) => previous.concat([$.raw_text]),
rules: {
/**
* TODO: add support for attributes
* e.g.:
*
* <template trim-invisibles>
* <template signature:{SomeInterface}>
*
* Either will require RFC
* https://github.com/emberjs/rfcs/
*/
glimmer_template: ($) =>
seq(
field("open_tag", $.glimmer_opening_tag),
optional($.raw_text),
field("close_tag", $.glimmer_closing_tag),
),
glimmer_opening_tag: ($) => seq("<", $.glimmer_template_tag_name, ">"),
glimmer_closing_tag: ($) => seq("</", $.glimmer_template_tag_name, ">"),
glimmer_template_tag_name: (_) => "template",
/**
* 2. Any Expression.
* e.g.:
*
* ```gts
* export const Foo = <template>...</template>
* ```
*
* TS: https://github.com/tree-sitter/tree-sitter-typescript/blob/master/common/define-grammar.js#L212
* JS: https://github.com/tree-sitter/tree-sitter-javascript/blob/master/grammar.js#L479
*/
expression: ($, previous) => {
const choices = [
...previous.members.filter((member) => {
// glimmer stuff is already in the upstream javascript grammar,
// but they want to remove it.
// So as a transitional step, I'll pretend it's already removed here.
return (
member.name !== "_jsx_element" && !member.name.includes("glimmer")
);
}),
$.glimmer_template,
];
return choice(...choices);
},
/**
* This one can't be extended as nicely as Expression, because this node
* contains a character sequence (seq)
*
* Most of thish is copied from upstream (TS), and only $.glimmer_template is added
*
* TS: https://github.com/tree-sitter/tree-sitter-typescript/blob/master/common/define-grammar.js#L419
* JS: https://github.com/tree-sitter/tree-sitter-javascript/blob/master/grammar.js#L1150
*/
class_body: ($) =>
seq(
"{",
repeat(
choice(
seq(field("member", $.method_definition), optional(";")),
seq(field("member", $.field_definition), $._semicolon),
field("member", $.class_static_block),
field("template", $.glimmer_template),
";",
),
),
"}",
),
},
});