Skip to content

Commit 256ae78

Browse files
committed
feat(semantic): report error for empty JSX attribute expression (#8815)
https://www.typescriptlang.org/play/?#code/DwEwlgbgBAhgvAbwL4D5gHpwRUA This is not a valid JSX syntax
1 parent 1a41181 commit 256ae78

File tree

3 files changed

+44
-2
lines changed

3 files changed

+44
-2
lines changed

crates/oxc_semantic/src/checker/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,9 @@ pub fn check<'a>(node: &AstNode<'a>, ctx: &SemanticBuilder<'a>) {
117117
AstKind::TSImportEqualsDeclaration(decl) => {
118118
ts::check_ts_import_equals_declaration(decl, ctx);
119119
}
120+
AstKind::JSXExpressionContainer(container) => {
121+
ts::check_jsx_expression_container(container, ctx);
122+
}
120123
_ => {}
121124
}
122125
}

crates/oxc_semantic/src/checker/typescript.rs

+16
Original file line numberDiff line numberDiff line change
@@ -542,3 +542,19 @@ pub fn check_for_statement_left(left: &ForStatementLeft, is_for_in: bool, ctx: &
542542
}
543543
}
544544
}
545+
546+
fn invalid_jsx_attribute_value(span: Span) -> OxcDiagnostic {
547+
ts_error("17000", "JSX attributes must only be assigned a non-empty 'expression'.")
548+
.with_label(span)
549+
}
550+
551+
pub fn check_jsx_expression_container(
552+
container: &JSXExpressionContainer,
553+
ctx: &SemanticBuilder<'_>,
554+
) {
555+
if matches!(container.expression, JSXExpression::EmptyExpression(_))
556+
&& matches!(ctx.nodes.parent_kind(ctx.current_node_id), Some(AstKind::JSXAttributeItem(_)))
557+
{
558+
ctx.error(invalid_jsx_attribute_value(container.span()));
559+
}
560+
}

tasks/coverage/snapshots/parser_typescript.snap

+25-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ commit: d85767ab
33
parser_typescript Summary:
44
AST Parsed : 6494/6503 (99.86%)
55
Positive Passed: 6483/6503 (99.69%)
6-
Negative Passed: 1283/5747 (22.32%)
6+
Negative Passed: 1284/5747 (22.34%)
77
Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/ClassDeclaration24.ts
88
Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/ExportAssignment7.ts
99
Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/ExportAssignment8.ts
@@ -1279,7 +1279,6 @@ Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/jsdocTypeCas
12791279
Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/jsdocTypeNongenericInstantiationAttempt.ts
12801280
Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/jsdocTypedefMissingType.ts
12811281
Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/jsdocTypedefNoCrash2.ts
1282-
Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/jsxAttributeWithoutExpressionReact.tsx
12831282
Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/jsxCallElaborationCheckNoCrash1.tsx
12841283
Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/jsxChildWrongType.tsx
12851284
Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/jsxChildrenArrayWrongType.tsx
@@ -8920,6 +8919,30 @@ Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/salsa/private
89208919
2 │ const y = 0;
89218920
╰────
89228921

8922+
× TS(17000): JSX attributes must only be assigned a non-empty 'expression'.
8923+
╭─[typescript/tests/cases/compiler/jsxAttributeWithoutExpressionReact.tsx:4:35]
8924+
3 │ <ListView refreshControl={
8925+
4 │ <RefreshControl onRefresh={} refreshing={} />
8926+
· ──
8927+
5 │ } dataSource={this.state.ds} renderRow={}>
8928+
╰────
8929+
8930+
× TS(17000): JSX attributes must only be assigned a non-empty 'expression'.
8931+
╭─[typescript/tests/cases/compiler/jsxAttributeWithoutExpressionReact.tsx:4:49]
8932+
3 │ <ListView refreshControl={
8933+
4 │ <RefreshControl onRefresh={} refreshing={} />
8934+
· ──
8935+
5 │ } dataSource={this.state.ds} renderRow={}>
8936+
╰────
8937+
8938+
× TS(17000): JSX attributes must only be assigned a non-empty 'expression'.
8939+
╭─[typescript/tests/cases/compiler/jsxAttributeWithoutExpressionReact.tsx:5:44]
8940+
4 │ <RefreshControl onRefresh={} refreshing={} />
8941+
5 │ } dataSource={this.state.ds} renderRow={}>
8942+
· ──
8943+
6 │ </ListView>
8944+
╰────
8945+
89238946
× Unexpected token
89248947
╭─[typescript/tests/cases/compiler/jsxNamespacePrefixInName.tsx:7:32]
89258948
6 │

0 commit comments

Comments
 (0)