diff --git a/lang/semgrep-grammars/src/Makefile.common b/lang/semgrep-grammars/src/Makefile.common
index 29c4bbe6..f20f5b59 100644
--- a/lang/semgrep-grammars/src/Makefile.common
+++ b/lang/semgrep-grammars/src/Makefile.common
@@ -42,7 +42,7 @@ test:
# messages when compiling 'parser.c'.
set -e; \
for dir in $$(find . | grep 'grammar.js$$' | xargs -L1 dirname); do \
- echo "Test $$(pwd)"; \
+ echo "Test $$(pwd)/$$dir"; \
(cd "$$dir"; \
show_log() { echo "..."; tail -n 1000 test.log; }; \
if tree-sitter test > test.log 2>&1; then \
diff --git a/lang/semgrep-grammars/src/semgrep-typescript/common/semgrep-ext.js b/lang/semgrep-grammars/src/semgrep-typescript/common/semgrep-ext.js
index 37b66a6e..9972b89b 100644
--- a/lang/semgrep-grammars/src/semgrep-typescript/common/semgrep-ext.js
+++ b/lang/semgrep-grammars/src/semgrep-typescript/common/semgrep-ext.js
@@ -28,6 +28,7 @@ module.exports = {
*/
semgrep_ellipsis: $ => '...',
+ semgrep_metavar_ellipsis: $ => /\$\.\.\.[A-Z_][A-Z_0-9]*/,
/* In the expression context, there are LR(1) conflicts with spread and
* rest. I (nmote) don't think that these are true ambiguities, but just in
@@ -40,6 +41,12 @@ module.exports = {
$.semgrep_expression_ellipsis,
),
+ _jsx_attribute: ($, previous) => choice(
+ previous,
+ $.semgrep_ellipsis,
+ $.semgrep_metavar_ellipsis
+ ),
+
// TODO Remove this when we update tree-sitter-typescript past
// https://github.com/tree-sitter/tree-sitter-typescript/pull/239. I (nmote)
// ran into unrelated issues updating it, documented in
diff --git a/lang/semgrep-grammars/src/semgrep-typescript/tsx/corpus/semgrep-ext.txt b/lang/semgrep-grammars/src/semgrep-typescript/tsx/corpus/semgrep-ext.txt
new file mode 100644
index 00000000..e7ebac8c
--- /dev/null
+++ b/lang/semgrep-grammars/src/semgrep-typescript/tsx/corpus/semgrep-ext.txt
@@ -0,0 +1,49 @@
+==================================
+JSX with ellipsis
+==================================
+
+
+
+---
+
+(program
+ (expression_statement
+ (jsx_self_closing_element
+ (identifier)
+ (semgrep_ellipsis))))
+
+==================================
+JSX with ellipsis and other props
+==================================
+
+
+
+---
+
+(program
+ (expression_statement
+ (jsx_self_closing_element
+ (identifier)
+ (jsx_attribute
+ (property_identifier)
+ (string
+ (string_fragment)))
+ (semgrep_ellipsis)
+ (jsx_attribute
+ (property_identifier)
+ (jsx_expression
+ (identifier))))))
+
+==================================
+JSX with metavariable ellipsis
+==================================
+
+
+
+---
+
+(program
+ (expression_statement
+ (jsx_self_closing_element
+ (identifier)
+ (semgrep_metavar_ellipsis))))