Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add JSX Support #335

Merged
merged 7 commits into from
Nov 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
318 changes: 315 additions & 3 deletions languages/tree-sitter-stack-graphs-javascript/src/stack-graphs.tsg
Original file line number Diff line number Diff line change
Expand Up @@ -3476,6 +3476,321 @@ inherit .return_or_yield
edge @class.after_scope -> @name.after_scope
}

(jsx_element
open_tag:(_)@open_tag
close_tag:(_)@close_tag
(_)*@children)@jsx_element {

node @jsx_element.before_scope
node @jsx_element.after_scope
node @jsx_element.value

edge @open_tag.before_scope -> @jsx_element.before_scope
edge @jsx_element.after_scope -> @close_tag.after_scope

if (is-empty @children) {
edge @close_tag.before_scope -> @open_tag.after_scope
}

}

(jsx_element
open_tag:(_)@open_tag
.
[
(jsx_text)
(jsx_element)
(jsx_self_closing_element)
(jsx_fragment)
(jsx_expression)
]@first_child
) {
edge @first_child.before_scope -> @open_tag.after_scope
}

(jsx_element
[
(jsx_text)
(jsx_element)
(jsx_self_closing_element)
(jsx_fragment)
(jsx_expression)
]@left_child
.
[
(jsx_text)
(jsx_element)
(jsx_self_closing_element)
(jsx_fragment)
(jsx_expression)
]@right_child
) {
edge @right_child.before_scope -> @left_child.after_scope
}

(jsx_element
[
(jsx_text)
(jsx_element)
(jsx_self_closing_element)
(jsx_fragment)
(jsx_expression)
]@last_child
.
close_tag:(_)@close_tag
) {
edge @close_tag.before_scope -> @last_child.after_scope
}

(jsx_text)@jsx_text {
node @jsx_text.before_scope
node @jsx_text.after_scope

edge @jsx_text.after_scope -> @jsx_text.before_scope
}

(jsx_opening_element
name:(_)@element_name)@jsx_opening_element {

node @jsx_opening_element.before_scope
node @jsx_opening_element.after_scope

edge @element_name.before_scope -> @jsx_opening_element.before_scope

}

(jsx_opening_element
name:(_)@element_name
!attribute)@jsx_opening_element
{

edge @jsx_opening_element.after_scope -> @element_name.after_scope

}

(jsx_opening_element
name:(_)@element_name
.
attribute:(_)@first_attr
) {

edge @first_attr.before_scope -> @element_name.after_scope

}

(jsx_opening_element
attribute:(_)@left_attr
.
attribute:(_)@right_attr
) {

edge @right_attr.before_scope -> @left_attr.after_scope

}

(jsx_opening_element
attribute:(_)@last_attr
.)@jsx_opening_element
{

edge @jsx_opening_element.after_scope -> @last_attr.after_scope

}

(jsx_attribute (_) . (_)?@attr_value)@jsx_attribute {

node @jsx_attribute.before_scope
node @jsx_attribute.after_scope

if none @attr_value {
edge @jsx_attribute.after_scope -> @jsx_attribute.before_scope
} else {
edge @attr_value.before_scope -> @jsx_attribute.before_scope
edge @jsx_attribute.after_scope -> @attr_value.after_scope
}

}

(jsx_self_closing_element
name:(_)@element_name)@jsx_self_closing_element {

node @jsx_self_closing_element.before_scope
node @jsx_self_closing_element.after_scope
node @jsx_self_closing_element.value

edge @element_name.before_scope -> @jsx_self_closing_element.before_scope

}

(jsx_self_closing_element
name:(_)@element_name
!attribute)@jsx_self_closing_element
{

edge @jsx_self_closing_element.after_scope -> @element_name.after_scope

}

(jsx_self_closing_element
name:(_)@element_name
.
attribute:(_)@first_attr
) {

edge @first_attr.before_scope -> @element_name.after_scope

}

(jsx_self_closing_element
attribute:(_)@left_attr
.
attribute:(_)@right_attr
) {

edge @right_attr.before_scope -> @left_attr.after_scope

}

(jsx_self_closing_element
attribute:(_)@last_attr
.)@jsx_self_closing_element
{

edge @jsx_self_closing_element.after_scope -> @last_attr.after_scope

}

(jsx_expression (_)?@child)@jsx_expression {

node @jsx_expression.before_scope
node @jsx_expression.after_scope

if none @child {
edge @jsx_expression.after_scope -> @jsx_expression.before_scope
} else {
edge @child.before_scope -> @jsx_expression.before_scope
edge @jsx_expression.after_scope -> @child.after_scope
}

}

(jsx_closing_element
name:(_)@element_name)@jsx_closing_element
{

node @jsx_closing_element.before_scope
node @jsx_closing_element.after_scope

edge @element_name.before_scope -> @jsx_closing_element.before_scope
edge @jsx_closing_element.after_scope -> @element_name.after_scope

}

[
(jsx_opening_element
name:(identifier)@element_name)
(jsx_self_closing_element
name:(identifier)@element_name)
(jsx_closing_element
name:(identifier)@element_name)
]
{

node @element_name.before_scope
node @element_name.after_scope

edge @element_name.after_scope -> @element_name.before_scope

scan (source-text @element_name) {
; standard HTML elements
"^(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)$" {
; do nothing!
}

; everything else
"^.+$" {
node element_name_pop
attr (element_name_pop) node_reference = @element_name
edge element_name_pop -> @element_name.before_scope
}
}

}

(nested_identifier)@nested_identifier {
node @nested_identifier.before_scope
node @nested_identifier.after_scope
node @nested_identifier.value

edge @nested_identifier.after_scope -> @nested_identifier.before_scope
}

(nested_identifier
(identifier)@first_part
(identifier)@second_part)@nested_identifier
{
node @first_part.value
node @second_part.value
node guard_member

attr (@first_part.value) node_reference = @first_part
attr (@second_part.value) node_reference = @second_part
attr (guard_member) symbol_reference = "GUARD:MEMBER"

edge @first_part.value -> @nested_identifier.before_scope
edge guard_member -> @first_part.value
edge @second_part.value -> guard_member
edge @nested_identifier.value -> @second_part.value
}

(nested_identifier
(nested_identifier)@first_part
(identifier)@second_part)@nested_identifier
{
node @second_part.value
node guard_member

attr (@second_part.value) node_reference = @second_part
attr (guard_member) symbol_reference = "GUARD:MEMBER"

edge @first_part.before_scope -> @nested_identifier.before_scope
edge guard_member -> @first_part.value
edge @second_part.value -> guard_member
edge @nested_identifier.value -> @second_part.value
}

(jsx_fragment (_)*@children)@jsx_fragment {
node @jsx_fragment.before_scope
node @jsx_fragment.after_scope
node @jsx_fragment.value

if (is-empty @children) {
edge @jsx_fragment.after_scope -> @jsx_fragment.before_scope
}
}

(jsx_fragment
.
(_)@first_child)@jsx_fragment
{
edge @first_child.before_scope -> @jsx_fragment.before_scope
}

(jsx_fragment
(_)@left_child
.
(_)@right_child)
{
edge @right_child.before_scope -> @left_child.after_scope
}

(jsx_fragment
(_)@last_child
.)@jsx_fragment
{
edge @jsx_fragment.after_scope -> @last_child.after_scope
}




Expand Down Expand Up @@ -3764,9 +4079,6 @@ inherit .return_or_yield

;; #### Object Patterns

; LATER-TODO scope propagation through empty object patterns
; currently unsupported by tree sitter queries
; THIS IS A HUGE HACK AND MUST BE FIXED
(object_pattern (_)* @entries)@object_pat {
if (is-empty @entries) {
edge @object_pat.after_scope -> @object_pat.before_scope
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,9 @@ x++;
x += 1;
(1, 2);
1 ? 2 : 3;
class { };
class { };
<foo bar={baz}>
<quux0.quux1.quux2 />
<>doo</>
{garply}
</foo>
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// The core of JSX tests here verify the behavior of the following node types:
// jsx_element
// jsx_identifier
// jsx_attribute
// jsx_expression
// jsx_opening_element
// jsx_closing_element
// There is no real way to avoid testing all of these at once,
// and so we don't even try to.

let x = 1;

// Flow In

const el = <foo bar={x}>{x}</foo>;
// ^ defined: 11
// ^ defined: 11

const el2 = <x></x>
// ^ defined: 11
// ^ defined: 11

// Flow Out

const el = <foo bar={y = 1}>
{z = 3}
</foo>;

/**/ y;
// ^ defined: 25

/**/ z;
// ^ defined: 26

// Flow Across

const el = <foo bar={w = 1}>
{w}</foo>;
// ^ defined: 37

const el = <foo bar={q = 1}
baz={q}></foo>;
// ^ defined: 41

// Flow Around

/**/ x;
// ^ defined: 11
Loading
Loading