@@ -157,6 +157,7 @@ fn not_allowed_namespace_declaration(span: Span) -> OxcDiagnostic {
157157
158158pub fn check_ts_module_declaration < ' a > ( decl : & TSModuleDeclaration < ' a > , ctx : & SemanticBuilder < ' a > ) {
159159 check_ts_module_or_global_declaration ( decl. span , ctx) ;
160+ check_ts_export_assignment_in_module_decl ( decl, ctx) ;
160161}
161162
162163pub fn check_ts_global_declaration < ' a > ( decl : & TSGlobalDeclaration < ' a > , ctx : & SemanticBuilder < ' a > ) {
@@ -438,3 +439,66 @@ pub fn check_jsx_expression_container(
438439 ctx. error ( jsx_expressions_may_not_use_the_comma_operator ( container. expression . span ( ) ) ) ;
439440 }
440441}
442+
443+ fn ts_export_assignment_cannot_be_used_with_other_exports ( span : Span ) -> OxcDiagnostic {
444+ ts_error ( "2309" , "An export assignment cannot be used in a module with other exported elements" )
445+ . with_label ( span)
446+ . with_help ( "If you want to use `export =`, remove other `export`s and put all of them to the right hand value of `export =`. If you want to use `export`s, remove `export =` statement." )
447+ }
448+
449+ pub fn check_ts_export_assignment_in_program < ' a > ( program : & Program < ' a > , ctx : & SemanticBuilder < ' a > ) {
450+ if !ctx. source_type . is_typescript ( ) {
451+ return ;
452+ }
453+ check_ts_export_assignment_in_statements ( & program. body , ctx) ;
454+ }
455+
456+ fn check_ts_export_assignment_in_module_decl < ' a > (
457+ module_decl : & TSModuleDeclaration < ' a > ,
458+ ctx : & SemanticBuilder < ' a > ,
459+ ) {
460+ let Some ( body) = & module_decl. body else {
461+ return ;
462+ } ;
463+ match body {
464+ TSModuleDeclarationBody :: TSModuleDeclaration ( nested) => {
465+ check_ts_export_assignment_in_module_decl ( nested, ctx) ;
466+ }
467+ TSModuleDeclarationBody :: TSModuleBlock ( block) => {
468+ check_ts_export_assignment_in_statements ( & block. body , ctx) ;
469+ }
470+ }
471+ }
472+
473+ fn check_ts_export_assignment_in_statements < ' a > (
474+ statements : & [ Statement < ' a > ] ,
475+ ctx : & SemanticBuilder < ' a > ,
476+ ) {
477+ let mut export_assignment_spans = vec ! [ ] ;
478+ let mut has_other_exports = false ;
479+
480+ for stmt in statements {
481+ match stmt {
482+ Statement :: TSExportAssignment ( export_assignment) => {
483+ export_assignment_spans. push ( export_assignment. span ) ;
484+ }
485+ Statement :: ExportNamedDeclaration ( export_decl) => {
486+ // ignore `export {}`
487+ if export_decl. declaration . is_none ( ) && export_decl. specifiers . is_empty ( ) {
488+ continue ;
489+ }
490+ has_other_exports = true ;
491+ }
492+ Statement :: ExportDefaultDeclaration ( _) | Statement :: ExportAllDeclaration ( _) => {
493+ has_other_exports = true ;
494+ }
495+ _ => { }
496+ }
497+ }
498+
499+ if has_other_exports {
500+ for span in export_assignment_spans {
501+ ctx. error ( ts_export_assignment_cannot_be_used_with_other_exports ( span) ) ;
502+ }
503+ }
504+ }
0 commit comments