@@ -469,6 +469,18 @@ pub fn get_runtime_path_args(
469469 ] )
470470}
471471
472+ /// Output mode for compiler arguments.
473+ /// Controls whether bsc writes to files or outputs to stdout.
474+ pub enum OutputMode {
475+ /// Normal mode: write JS to files based on package-specs configuration.
476+ /// Includes -bs-package-name, -bs-package-output, -bs-suffix, -bs-module-system for each spec.
477+ ToFile ,
478+ /// Stdout mode: output JS to stdout for one-shot compilation.
479+ /// Only includes -bs-module-system with the specified format.
480+ /// Omits -bs-package-name (which triggers file output) and -bs-package-output.
481+ ToStdout { module_format : String } ,
482+ }
483+
472484pub fn compiler_args (
473485 config : & config:: Config ,
474486 ast_path : & Path ,
@@ -485,6 +497,8 @@ pub fn compiler_args(
485497 is_local_dep : bool ,
486498 // Command-line --warn-error flag override (takes precedence over rescript.json config)
487499 warn_error_override : Option < String > ,
500+ // Output mode: ToFile for normal compilation, ToStdout for one-shot compilation
501+ output_mode : OutputMode ,
488502) -> Result < Vec < String > > {
489503 let bsc_flags = config:: flatten_flags ( & config. compiler_flags ) ;
490504 let dependency_paths = get_dependency_paths ( config, project_context, packages, is_type_dev) ;
@@ -531,40 +545,52 @@ pub fn compiler_args(
531545 false => vec ! [ ] ,
532546 } ;
533547
534- let package_name_arg = vec ! [ "-bs-package-name" . to_string( ) , config. name. to_owned( ) ] ;
535-
536- let implementation_args = if is_interface {
537- debug ! ( "Compiling interface file: {}" , & module_name) ;
538- vec ! [ ]
539- } else {
540- debug ! ( "Compiling file: {}" , & module_name) ;
541- let specs = root_config. get_package_specs ( ) ;
548+ // Package name and implementation args depend on output mode
549+ let ( package_name_arg, implementation_args) = match & output_mode {
550+ OutputMode :: ToFile => {
551+ let package_name = vec ! [ "-bs-package-name" . to_string( ) , config. name. to_owned( ) ] ;
552+ let impl_args = if is_interface {
553+ debug ! ( "Compiling interface file: {}" , & module_name) ;
554+ vec ! [ ]
555+ } else {
556+ debug ! ( "Compiling file: {}" , & module_name) ;
557+ let specs = root_config. get_package_specs ( ) ;
542558
543- specs
544- . iter ( )
545- . flat_map ( |spec| {
546- // Pass module system, suffix, and output path as separate flags
547- vec ! [
548- "-bs-module-system" . to_string( ) ,
549- spec. module. clone( ) ,
550- "-bs-suffix" . to_string( ) ,
551- root_config. get_suffix( spec) ,
552- "-bs-package-output" . to_string( ) ,
553- if spec. in_source {
554- file_path. parent( ) . unwrap( ) . to_str( ) . unwrap( ) . to_string( )
555- } else {
556- Path :: new( "lib" )
557- . join( Path :: join(
558- Path :: new( & spec. get_out_of_source_dir( ) ) ,
559- file_path. parent( ) . unwrap( ) ,
560- ) )
561- . to_str( )
562- . unwrap( )
563- . to_string( )
564- } ,
565- ]
566- } )
567- . collect ( )
559+ specs
560+ . iter ( )
561+ . flat_map ( |spec| {
562+ // Pass module system, suffix, and output path as separate flags
563+ vec ! [
564+ "-bs-module-system" . to_string( ) ,
565+ spec. module. clone( ) ,
566+ "-bs-suffix" . to_string( ) ,
567+ root_config. get_suffix( spec) ,
568+ "-bs-package-output" . to_string( ) ,
569+ if spec. in_source {
570+ file_path. parent( ) . unwrap( ) . to_str( ) . unwrap( ) . to_string( )
571+ } else {
572+ Path :: new( "lib" )
573+ . join( Path :: join(
574+ Path :: new( & spec. get_out_of_source_dir( ) ) ,
575+ file_path. parent( ) . unwrap( ) ,
576+ ) )
577+ . to_str( )
578+ . unwrap( )
579+ . to_string( )
580+ } ,
581+ ]
582+ } )
583+ . collect ( )
584+ } ;
585+ ( package_name, impl_args)
586+ }
587+ OutputMode :: ToStdout { module_format } => {
588+ // For stdout mode: no -bs-package-name (triggers file output),
589+ // only -bs-module-system with the chosen format
590+ debug ! ( "Compiling file to stdout: {}" , & module_name) ;
591+ let impl_args = vec ! [ "-bs-module-system" . to_string( ) , module_format. clone( ) ] ;
592+ ( vec ! [ ] , impl_args)
593+ }
568594 } ;
569595
570596 let runtime_path_args = get_runtime_path_args ( config, project_context) ?;
@@ -603,11 +629,7 @@ pub fn compiler_args(
603629}
604630
605631/// Generate compiler arguments for stdout output (no file write).
606- ///
607- /// Calls `compiler_args` and then filters out flags that would cause file output:
608- /// - Removes `-bs-package-name` (triggers file output mode)
609- /// - Removes `-bs-package-output` and `-bs-suffix` (file output config)
610- /// - Keeps only a single `-bs-module-system` for the requested format
632+ /// This is a convenience wrapper around `compiler_args` with `OutputMode::ToStdout`.
611633pub fn compiler_args_for_stdout (
612634 config : & config:: Config ,
613635 ast_path : & Path ,
@@ -620,8 +642,7 @@ pub fn compiler_args_for_stdout(
620642 warn_error_override : Option < String > ,
621643 module_format : & str ,
622644) -> Result < Vec < String > > {
623- // Get the base compiler args
624- let base_args = compiler_args (
645+ compiler_args (
625646 config,
626647 ast_path,
627648 file_path,
@@ -632,48 +653,10 @@ pub fn compiler_args_for_stdout(
632653 is_type_dev,
633654 is_local_dep,
634655 warn_error_override,
635- ) ?;
636-
637- // Filter out flags that trigger file output, keeping track of what to skip
638- let mut result = Vec :: new ( ) ;
639- let mut skip_next = false ;
640- let mut seen_module_system = false ;
641-
642- for arg in base_args {
643- if skip_next {
644- skip_next = false ;
645- continue ;
646- }
647-
648- match arg. as_str ( ) {
649- // Skip -bs-package-name and its value (triggers file output)
650- "-bs-package-name" => {
651- skip_next = true ;
652- }
653- // Skip -bs-package-output and its value (file path)
654- "-bs-package-output" => {
655- skip_next = true ;
656- }
657- // Skip -bs-suffix and its value (not needed for stdout)
658- "-bs-suffix" => {
659- skip_next = true ;
660- }
661- // Keep only one -bs-module-system with our chosen format
662- "-bs-module-system" => {
663- if !seen_module_system {
664- result. push ( "-bs-module-system" . to_string ( ) ) ;
665- result. push ( module_format. to_string ( ) ) ;
666- seen_module_system = true ;
667- }
668- skip_next = true ; // skip the original value
669- }
670- _ => {
671- result. push ( arg) ;
672- }
673- }
674- }
675-
676- Ok ( result)
656+ OutputMode :: ToStdout {
657+ module_format : module_format. to_string ( ) ,
658+ } ,
659+ )
677660}
678661
679662/// Compile a single file and return its JavaScript output on stdout.
@@ -875,6 +858,7 @@ fn compile_file(
875858 is_type_dev,
876859 package. is_local_dep ,
877860 warn_error_override,
861+ OutputMode :: ToFile ,
878862 ) ?;
879863
880864 let to_mjs = Command :: new ( & compiler_info. bsc_path )
0 commit comments