diff --git a/crates/oxc_semantic/src/checker/mod.rs b/crates/oxc_semantic/src/checker/mod.rs index 13fadeb0012cd..2e693c30e888b 100644 --- a/crates/oxc_semantic/src/checker/mod.rs +++ b/crates/oxc_semantic/src/checker/mod.rs @@ -117,6 +117,9 @@ pub fn check<'a>(node: &AstNode<'a>, ctx: &SemanticBuilder<'a>) { AstKind::TSImportEqualsDeclaration(decl) => { ts::check_ts_import_equals_declaration(decl, ctx); } + AstKind::JSXExpressionContainer(container) => { + ts::check_jsx_expression_container(container, ctx); + } _ => {} } } diff --git a/crates/oxc_semantic/src/checker/typescript.rs b/crates/oxc_semantic/src/checker/typescript.rs index 2837dc5a0c199..36b653d0775af 100644 --- a/crates/oxc_semantic/src/checker/typescript.rs +++ b/crates/oxc_semantic/src/checker/typescript.rs @@ -542,3 +542,19 @@ pub fn check_for_statement_left(left: &ForStatementLeft, is_for_in: bool, ctx: & } } } + +fn invalid_jsx_attribute_value(span: Span) -> OxcDiagnostic { + ts_error("17000", "JSX attributes must only be assigned a non-empty 'expression'.") + .with_label(span) +} + +pub fn check_jsx_expression_container( + container: &JSXExpressionContainer, + ctx: &SemanticBuilder<'_>, +) { + if matches!(container.expression, JSXExpression::EmptyExpression(_)) + && matches!(ctx.nodes.parent_kind(ctx.current_node_id), Some(AstKind::JSXAttributeItem(_))) + { + ctx.error(invalid_jsx_attribute_value(container.span())); + } +} diff --git a/tasks/coverage/snapshots/parser_typescript.snap b/tasks/coverage/snapshots/parser_typescript.snap index 1587be1641251..140637e6ec16d 100644 --- a/tasks/coverage/snapshots/parser_typescript.snap +++ b/tasks/coverage/snapshots/parser_typescript.snap @@ -3,7 +3,7 @@ commit: d85767ab parser_typescript Summary: AST Parsed : 6494/6503 (99.86%) Positive Passed: 6483/6503 (99.69%) -Negative Passed: 1283/5747 (22.32%) +Negative Passed: 1284/5747 (22.34%) Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/ClassDeclaration24.ts Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/ExportAssignment7.ts 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 Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/jsdocTypeNongenericInstantiationAttempt.ts Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/jsdocTypedefMissingType.ts Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/jsdocTypedefNoCrash2.ts -Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/jsxAttributeWithoutExpressionReact.tsx Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/jsxCallElaborationCheckNoCrash1.tsx Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/jsxChildWrongType.tsx 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 2 │ const y = 0; ╰──── + × TS(17000): JSX attributes must only be assigned a non-empty 'expression'. + ╭─[typescript/tests/cases/compiler/jsxAttributeWithoutExpressionReact.tsx:4:35] + 3 │ + · ── + 5 │ } dataSource={this.state.ds} renderRow={}> + ╰──── + + × TS(17000): JSX attributes must only be assigned a non-empty 'expression'. + ╭─[typescript/tests/cases/compiler/jsxAttributeWithoutExpressionReact.tsx:4:49] + 3 │ + · ── + 5 │ } dataSource={this.state.ds} renderRow={}> + ╰──── + + × TS(17000): JSX attributes must only be assigned a non-empty 'expression'. + ╭─[typescript/tests/cases/compiler/jsxAttributeWithoutExpressionReact.tsx:5:44] + 4 │ + 5 │ } dataSource={this.state.ds} renderRow={}> + · ── + 6 │ + ╰──── + × Unexpected token ╭─[typescript/tests/cases/compiler/jsxNamespacePrefixInName.tsx:7:32] 6 │