@@ -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 > ) {
@@ -449,3 +450,66 @@ pub fn check_jsx_expression_container(
449450 ctx. error ( jsx_expressions_may_not_use_the_comma_operator ( container. expression . span ( ) ) ) ;
450451 }
451452}
453+
454+ fn ts_export_assignment_cannot_be_used_with_other_exports ( span : Span ) -> OxcDiagnostic {
455+ ts_error ( "2309" , "An export assignment cannot be used in a module with other exported elements" )
456+ . with_label ( span)
457+ . 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." )
458+ }
459+
460+ pub fn check_ts_export_assignment_in_program < ' a > ( program : & Program < ' a > , ctx : & SemanticBuilder < ' a > ) {
461+ if !ctx. source_type . is_typescript ( ) {
462+ return ;
463+ }
464+ check_ts_export_assignment_in_statements ( & program. body , ctx) ;
465+ }
466+
467+ fn check_ts_export_assignment_in_module_decl < ' a > (
468+ module_decl : & TSModuleDeclaration < ' a > ,
469+ ctx : & SemanticBuilder < ' a > ,
470+ ) {
471+ let Some ( body) = & module_decl. body else {
472+ return ;
473+ } ;
474+ match body {
475+ TSModuleDeclarationBody :: TSModuleDeclaration ( nested) => {
476+ check_ts_export_assignment_in_module_decl ( nested, ctx) ;
477+ }
478+ TSModuleDeclarationBody :: TSModuleBlock ( block) => {
479+ check_ts_export_assignment_in_statements ( & block. body , ctx) ;
480+ }
481+ }
482+ }
483+
484+ fn check_ts_export_assignment_in_statements < ' a > (
485+ statements : & [ Statement < ' a > ] ,
486+ ctx : & SemanticBuilder < ' a > ,
487+ ) {
488+ let mut export_assignment_span: Option < Span > = None ;
489+ let mut has_other_exports = false ;
490+
491+ for stmt in statements {
492+ match stmt {
493+ Statement :: TSExportAssignment ( export_assignment) => {
494+ export_assignment_span = Some ( export_assignment. span ) ;
495+ }
496+ Statement :: ExportNamedDeclaration ( export_decl) => {
497+ // ignore `export {}`
498+ if export_decl. declaration . is_none ( ) && export_decl. specifiers . is_empty ( ) {
499+ continue ;
500+ }
501+ has_other_exports = true ;
502+ }
503+ Statement :: ExportDefaultDeclaration ( _) | Statement :: ExportAllDeclaration ( _) => {
504+ has_other_exports = true ;
505+ }
506+ _ => { }
507+ }
508+ }
509+
510+ if let Some ( span) = export_assignment_span
511+ && has_other_exports
512+ {
513+ ctx. error ( ts_export_assignment_cannot_be_used_with_other_exports ( span) ) ;
514+ }
515+ }
0 commit comments