Skip to content
This repository was archived by the owner on Sep 9, 2025. It is now read-only.

Commit a8c7109

Browse files
author
Hendrik van Antwerpen
authored
Merge pull request #415 from eyakubovich/ey/support-tsx-jsx-element
Support JSX elements in TSX
2 parents cebac48 + 1e12072 commit a8c7109

File tree

7 files changed

+311
-14
lines changed

7 files changed

+311
-14
lines changed

languages/tree-sitter-stack-graphs-typescript/rust/test.rs

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,18 @@ use tree_sitter_stack_graphs::ci::Tester;
1111
use tree_sitter_stack_graphs::NoCancellation;
1212

1313
fn main() -> anyhow::Result<()> {
14-
let lc = match tree_sitter_stack_graphs_typescript::try_language_configuration_typescript(
15-
&NoCancellation,
16-
) {
17-
Ok(lc) => lc,
18-
Err(err) => {
19-
eprintln!("{}", err.display_pretty());
20-
return Err(anyhow!("Language configuration error"));
21-
}
22-
};
14+
let lc_factories = [
15+
tree_sitter_stack_graphs_typescript::try_language_configuration_typescript,
16+
tree_sitter_stack_graphs_typescript::try_language_configuration_tsx,
17+
];
18+
19+
let lcs = lc_factories
20+
.iter()
21+
.map(|lc_factory| lc_factory(&NoCancellation))
22+
.collect::<Result<Vec<_>, _>>()
23+
.inspect_err(|err| eprintln!("{}", err.display_pretty()))
24+
.map_err(|_| anyhow!("Language configuration error"))?;
25+
2326
let test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test");
24-
Tester::new(vec![lc], vec![test_path]).run()
27+
Tester::new(lcs, vec![test_path]).run()
2528
}

languages/tree-sitter-stack-graphs-typescript/src/stack-graphs.tsg

Lines changed: 172 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2667,6 +2667,13 @@ if none @is_async {
26672667
(true)
26682668
; #dialect typescript
26692669
(type_assertion)
2670+
; #end
2671+
; #dialect tsx
2672+
(jsx_element)
2673+
(jsx_self_closing_element)
2674+
(jsx_opening_element)
2675+
(jsx_closing_element)
2676+
(jsx_expression)
26702677
; #end
26712678
(unary_expression)
26722679
(undefined)
@@ -2805,6 +2812,15 @@ if none @is_async {
28052812
(decorator (call_expression function:(member_expression object:(identifier)@name)))
28062813
(decorator (call_expression function:(member_expression object:(member_expression object:(identifier)@name))))
28072814
(decorator (call_expression function:(member_expression object:(member_expression object:(member_expression object:(identifier)@name)))))
2815+
; #dialect tsx
2816+
(nested_identifier (identifier)@name)
2817+
(nested_identifier (nested_identifier)@name)
2818+
(nested_type_identifier module:(nested_identifier)@name)
2819+
(internal_module name:(_)@name)
2820+
(jsx_opening_element name: (_)@name)
2821+
(jsx_closing_element name: (_)@name)
2822+
(jsx_self_closing_element name: (_)@name)
2823+
; #end
28082824
] {
28092825
if none @is_def {
28102826
node @name.cotype
@@ -2852,6 +2868,12 @@ if none @is_def {
28522868
(decorator (call_expression function:(member_expression object:(identifier)@name)))
28532869
(decorator (call_expression function:(member_expression object:(member_expression object:(identifier)@name))))
28542870
(decorator (call_expression function:(member_expression object:(member_expression object:(member_expression object:(identifier)@name)))))
2871+
; #dialect tsx
2872+
(nested_identifier (identifier)@name (identifier)) ; to pick up foo in JSX: <foo.bar.baz />
2873+
(jsx_opening_element name: (identifier)@name)
2874+
(jsx_closing_element name: (identifier)@name)
2875+
(jsx_self_closing_element name: (identifier)@name)
2876+
; #end
28552877
] {
28562878
if none @is_def {
28572879
node @name.expr_ref
@@ -3524,10 +3546,22 @@ if none @is_async {
35243546
; (member_expression (identifier) (property_identifier))
35253547
; (subscript_expression (identifier) (string))
35263548

3527-
(member_expression
3528-
object: (_)@object
3529-
property: (_)@prop
3530-
)@member_expr {
3549+
[
3550+
(member_expression
3551+
object: (_)@object
3552+
property: (_)@prop
3553+
)@member_expr
3554+
; #dialect tsx
3555+
(nested_identifier
3556+
(nested_identifier)@object
3557+
(identifier)@prop
3558+
)@member_expr
3559+
(nested_identifier
3560+
(identifier)@object
3561+
(identifier)@prop
3562+
)@member_expr
3563+
; #end
3564+
] {
35313565
node @member_expr.member
35323566
node @prop.expr_ref
35333567
node @prop.expr_ref__typeof
@@ -6160,3 +6194,137 @@ if none @is_acc {
61606194
attr (@async.async_type__promise_ref__ns) push_symbol = "%T"
61616195
edge @async.async_type__promise_ref__ns -> @async.lexical_scope
61626196
}
6197+
6198+
;
6199+
; # ##### # #
6200+
; # # # # #
6201+
; # # # #
6202+
; # ##### #
6203+
; # # # # #
6204+
; # # # # # #
6205+
; ##### ##### # #
6206+
;
6207+
; ;;;;;;;;;;;;;;;;;;;;
6208+
; #dialect tsx
6209+
; ;;;;;;;;;;;;;;;;;;;;
6210+
6211+
(jsx_element
6212+
open_tag:(_)@open_tag
6213+
close_tag:(_)@close_tag)@jsx_element {
6214+
6215+
edge @open_tag.lexical_scope -> @jsx_element.lexical_scope
6216+
edge @close_tag.lexical_scope -> @jsx_element.lexical_scope
6217+
}
6218+
6219+
(jsx_element
6220+
[
6221+
(jsx_text)
6222+
(jsx_element)
6223+
(jsx_fragment)
6224+
(jsx_self_closing_element)
6225+
(jsx_expression)
6226+
]@child
6227+
)@parent {
6228+
edge @child.lexical_scope -> @parent.lexical_scope
6229+
}
6230+
6231+
(jsx_fragment)@fragment {
6232+
node @fragment.lexical_scope
6233+
node @fragment.value
6234+
node @fragment.type
6235+
}
6236+
6237+
(jsx_fragment
6238+
[
6239+
(jsx_text)
6240+
(jsx_element)
6241+
(jsx_fragment)
6242+
(jsx_self_closing_element)
6243+
(jsx_expression)
6244+
]@child
6245+
) @parent {
6246+
edge @child.lexical_scope -> @parent.lexical_scope
6247+
}
6248+
6249+
(jsx_text)@jsx_text {
6250+
node @jsx_text.lexical_scope
6251+
}
6252+
6253+
[
6254+
(jsx_opening_element name: (_)@name)@element
6255+
(jsx_closing_element name: (_)@name)@element
6256+
(jsx_self_closing_element name: (_)@name)@element
6257+
] {
6258+
edge @name.lexical_scope -> @element.lexical_scope
6259+
}
6260+
6261+
(jsx_opening_element
6262+
name:(_)@element_name
6263+
attribute:(_)@attr
6264+
) {
6265+
edge @attr.lexical_scope -> @element_name.lexical_scope
6266+
}
6267+
6268+
(jsx_attribute (_) . (_)?@attr_value)@jsx_attribute {
6269+
node @jsx_attribute.lexical_scope
6270+
6271+
if some @attr_value {
6272+
edge @attr_value.lexical_scope -> @jsx_attribute.lexical_scope
6273+
}
6274+
}
6275+
6276+
(jsx_namespace_name (_) @lhs (_) @rhs)@name {
6277+
node @name.lexical_scope
6278+
6279+
edge @lhs.lexical_scope -> @name.lexical_scope
6280+
edge @rhs.lexical_scope -> @name.lexical_scope
6281+
}
6282+
6283+
(jsx_self_closing_element
6284+
name:(_)@element_name)@element {
6285+
edge @element_name.lexical_scope -> @element.lexical_scope
6286+
}
6287+
6288+
(jsx_self_closing_element
6289+
name:(_)@element_name
6290+
attribute:(_)@attr
6291+
) {
6292+
edge @attr.lexical_scope -> @element_name.lexical_scope
6293+
}
6294+
6295+
(jsx_expression (_)@child)@expr {
6296+
edge @child.lexical_scope -> @expr.lexical_scope
6297+
}
6298+
6299+
(jsx_closing_element
6300+
name:(_)@element_name)@element
6301+
{
6302+
edge @element_name.lexical_scope -> @element.lexical_scope
6303+
}
6304+
6305+
[
6306+
(jsx_opening_element
6307+
name:(identifier)@element_name)
6308+
(jsx_self_closing_element
6309+
name:(identifier)@element_name)
6310+
(jsx_closing_element
6311+
name:(identifier)@element_name)
6312+
] {
6313+
scan (source-text @element_name) {
6314+
; standard HTML elements
6315+
"^(a|abbr|acronym|address|applet|area|article|aside|audio|b|base|basefont|bdi|bdo|big|blockquote|body|br|button|canvas|caption|center|cite|code|col|colgroup|data|datalist|dd|del|details|dfn|dialog|dir|div|dl|dt|em|embed|fieldset|figcaption|figure|font|footer|form|frame|frameset|h1|h2|h3|h4|h5|h6|head|header|hgroup|hr|html|i|iframe|input|ins|kbd|label|legend|li|link|main|map|mark|menu|meta|meter|nav|noframes|noscript|object|ol|optgroup|option|output|p|param|picture|pre|progress|q|rp|rt|ruby|s|samp|script|search|section|select|small|source|span|strike|strong|style|sub|summary|sup|svg|table|tbody|td|template|textarea|tfoot|th|thead|time|title|tr|track|tt|u|ul|var|video|wbr)$" {
6316+
; do nothing!
6317+
}
6318+
6319+
; everything else
6320+
"^.+$" {
6321+
node element_name_pop
6322+
attr (element_name_pop) node_reference = @element_name
6323+
edge element_name_pop -> @element_name.lexical_scope
6324+
}
6325+
}
6326+
}
6327+
6328+
; ;;;;;;;;;;;;;;;;;;;;
6329+
; #end
6330+
; ;;;;;;;;;;;;;;;;;;;;
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// The core of JSX tests here verify the behavior of the following node types:
2+
// jsx_element
3+
// jsx_identifier
4+
// jsx_attribute
5+
// jsx_expression
6+
// jsx_opening_element
7+
// jsx_closing_element
8+
// There is no real way to avoid testing all of these at once,
9+
// and so we don't even try to.
10+
11+
let x = 1;
12+
13+
// Flow In
14+
15+
const el = <foo bar={x}>{x}</foo>;
16+
// ^ defined: 11
17+
// ^ defined: 11
18+
19+
const el2 = <x></x>
20+
// ^ defined: 11
21+
// ^ defined: 11
22+
23+
let y = 0;
24+
let z = 2;
25+
26+
const el = <foo bar={y = 1}>
27+
// ^ defined: 23
28+
{z = 3}
29+
// ^ defined: 24
30+
</foo>;
31+
32+
/**/ y;
33+
// ^ defined: 23
34+
35+
/**/ z;
36+
// ^ defined: 24
37+
38+
/**/ x;
39+
// ^ defined: 11
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
let x = 1;
2+
3+
// Flow Around
4+
5+
const el = <></>;
6+
7+
/**/ x;
8+
// ^ defined: 1
9+
10+
// Children
11+
(<foo><bar>{x}</bar></foo>);
12+
// ^ defined: 1
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
let x = 1;
2+
3+
// Flow Around
4+
namespace noo.bar {
5+
export let baz = 1;
6+
}
7+
8+
const el = <noo.bar.baz></noo.bar.baz>;
9+
// ^ defined: 4
10+
// ^ defined: 4
11+
// ^ defined: 5
12+
// ^ defined: 4
13+
// ^ defined: 4
14+
// ^ defined: 5
15+
16+
/**/ x;
17+
// ^ defined: 1
18+
19+
// Flow In
20+
21+
let foo = {
22+
bar: {
23+
baz: 1
24+
}
25+
};
26+
27+
const el2 = <foo.bar.baz />;
28+
// ^ defined: 21
29+
// ^ defined: 22
30+
// ^ defined: 23
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// The core of JSX tests here verify the behavior of the following node types:
2+
// jsx_element
3+
// jsx_identifier
4+
// jsx_attribute
5+
// jsx_expression
6+
// jsx_opening_element
7+
// jsx_closing_element
8+
// There is no real way to avoid testing all of these at once,
9+
// and so we don't even try to.
10+
11+
let x = 1;
12+
13+
// Flow In
14+
15+
const el = <foo bar={x} />;
16+
// ^ defined: 11
17+
18+
const el2 = <x />
19+
// ^ defined: 11
20+
21+
// Flow Out
22+
23+
let y = 2;
24+
25+
const el = <foo bar={y = 1} />;
26+
// ^ defined: 23
27+
28+
// Flow Across
29+
30+
const el = <foo bar={y = 1}
31+
baz={y} />;
32+
// ^ defined: 23
33+
34+
// Flow Around
35+
36+
/**/ x;
37+
// ^ defined: 11
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
let x = 1;
2+
3+
// Flow Around
4+
5+
const el = <foo>bar</foo>;
6+
7+
/**/ x;
8+
// ^ defined: 1

0 commit comments

Comments
 (0)