@@ -458,6 +458,18 @@ pub fn get_runtime_path_args(
458458 ] )
459459}
460460
461+ /// Output mode for compiler arguments.
462+ /// Controls whether bsc writes to files or outputs to stdout.
463+ pub enum OutputMode {
464+ /// Normal mode: write JS to files based on package-specs configuration.
465+ /// Includes -bs-package-name, -bs-package-output, -bs-suffix, -bs-module-system for each spec.
466+ ToFile ,
467+ /// Stdout mode: output JS to stdout for one-shot compilation.
468+ /// Only includes -bs-module-system with the specified format.
469+ /// Omits -bs-package-name (which triggers file output) and -bs-package-output.
470+ ToStdout { module_format : String } ,
471+ }
472+
461473pub fn compiler_args (
462474 config : & config:: Config ,
463475 ast_path : & Path ,
@@ -474,6 +486,8 @@ pub fn compiler_args(
474486 is_local_dep : bool ,
475487 // Command-line --warn-error flag override (takes precedence over rescript.json config)
476488 warn_error_override : Option < String > ,
489+ // Output mode: ToFile for normal compilation, ToStdout for one-shot compilation
490+ output_mode : OutputMode ,
477491) -> Result < Vec < String > > {
478492 let bsc_flags = config:: flatten_flags ( & config. compiler_flags ) ;
479493 let dependency_paths = get_dependency_paths ( config, project_context, packages, is_type_dev) ;
@@ -520,40 +534,52 @@ pub fn compiler_args(
520534 false => vec ! [ ] ,
521535 } ;
522536
523- let package_name_arg = vec ! [ "-bs-package-name" . to_string( ) , config. name. to_owned( ) ] ;
524-
525- let implementation_args = if is_interface {
526- debug ! ( "Compiling interface file: {}" , & module_name) ;
527- vec ! [ ]
528- } else {
529- debug ! ( "Compiling file: {}" , & module_name) ;
530- let specs = root_config. get_package_specs ( ) ;
537+ // Package name and implementation args depend on output mode
538+ let ( package_name_arg, implementation_args) = match & output_mode {
539+ OutputMode :: ToFile => {
540+ let package_name = vec ! [ "-bs-package-name" . to_string( ) , config. name. to_owned( ) ] ;
541+ let impl_args = if is_interface {
542+ debug ! ( "Compiling interface file: {}" , & module_name) ;
543+ vec ! [ ]
544+ } else {
545+ debug ! ( "Compiling file: {}" , & module_name) ;
546+ let specs = root_config. get_package_specs ( ) ;
531547
532- specs
533- . iter ( )
534- . flat_map ( |spec| {
535- // Pass module system, suffix, and output path as separate flags
536- vec ! [
537- "-bs-module-system" . to_string( ) ,
538- spec. module. clone( ) ,
539- "-bs-suffix" . to_string( ) ,
540- root_config. get_suffix( spec) ,
541- "-bs-package-output" . to_string( ) ,
542- if spec. in_source {
543- file_path. parent( ) . unwrap( ) . to_str( ) . unwrap( ) . to_string( )
544- } else {
545- Path :: new( "lib" )
546- . join( Path :: join(
547- Path :: new( & spec. get_out_of_source_dir( ) ) ,
548- file_path. parent( ) . unwrap( ) ,
549- ) )
550- . to_str( )
551- . unwrap( )
552- . to_string( )
553- } ,
554- ]
555- } )
556- . collect ( )
548+ specs
549+ . iter ( )
550+ . flat_map ( |spec| {
551+ // Pass module system, suffix, and output path as separate flags
552+ vec ! [
553+ "-bs-module-system" . to_string( ) ,
554+ spec. module. clone( ) ,
555+ "-bs-suffix" . to_string( ) ,
556+ root_config. get_suffix( spec) ,
557+ "-bs-package-output" . to_string( ) ,
558+ if spec. in_source {
559+ file_path. parent( ) . unwrap( ) . to_str( ) . unwrap( ) . to_string( )
560+ } else {
561+ Path :: new( "lib" )
562+ . join( Path :: join(
563+ Path :: new( & spec. get_out_of_source_dir( ) ) ,
564+ file_path. parent( ) . unwrap( ) ,
565+ ) )
566+ . to_str( )
567+ . unwrap( )
568+ . to_string( )
569+ } ,
570+ ]
571+ } )
572+ . collect ( )
573+ } ;
574+ ( package_name, impl_args)
575+ }
576+ OutputMode :: ToStdout { module_format } => {
577+ // For stdout mode: no -bs-package-name (triggers file output),
578+ // only -bs-module-system with the chosen format
579+ debug ! ( "Compiling file to stdout: {}" , & module_name) ;
580+ let impl_args = vec ! [ "-bs-module-system" . to_string( ) , module_format. clone( ) ] ;
581+ ( vec ! [ ] , impl_args)
582+ }
557583 } ;
558584
559585 let runtime_path_args = get_runtime_path_args ( config, project_context) ?;
@@ -592,11 +618,7 @@ pub fn compiler_args(
592618}
593619
594620/// Generate compiler arguments for stdout output (no file write).
595- ///
596- /// Calls `compiler_args` and then filters out flags that would cause file output:
597- /// - Removes `-bs-package-name` (triggers file output mode)
598- /// - Removes `-bs-package-output` and `-bs-suffix` (file output config)
599- /// - Keeps only a single `-bs-module-system` for the requested format
621+ /// This is a convenience wrapper around `compiler_args` with `OutputMode::ToStdout`.
600622pub fn compiler_args_for_stdout (
601623 config : & config:: Config ,
602624 ast_path : & Path ,
@@ -609,8 +631,7 @@ pub fn compiler_args_for_stdout(
609631 warn_error_override : Option < String > ,
610632 module_format : & str ,
611633) -> Result < Vec < String > > {
612- // Get the base compiler args
613- let base_args = compiler_args (
634+ compiler_args (
614635 config,
615636 ast_path,
616637 file_path,
@@ -621,48 +642,10 @@ pub fn compiler_args_for_stdout(
621642 is_type_dev,
622643 is_local_dep,
623644 warn_error_override,
624- ) ?;
625-
626- // Filter out flags that trigger file output, keeping track of what to skip
627- let mut result = Vec :: new ( ) ;
628- let mut skip_next = false ;
629- let mut seen_module_system = false ;
630-
631- for arg in base_args {
632- if skip_next {
633- skip_next = false ;
634- continue ;
635- }
636-
637- match arg. as_str ( ) {
638- // Skip -bs-package-name and its value (triggers file output)
639- "-bs-package-name" => {
640- skip_next = true ;
641- }
642- // Skip -bs-package-output and its value (file path)
643- "-bs-package-output" => {
644- skip_next = true ;
645- }
646- // Skip -bs-suffix and its value (not needed for stdout)
647- "-bs-suffix" => {
648- skip_next = true ;
649- }
650- // Keep only one -bs-module-system with our chosen format
651- "-bs-module-system" => {
652- if !seen_module_system {
653- result. push ( "-bs-module-system" . to_string ( ) ) ;
654- result. push ( module_format. to_string ( ) ) ;
655- seen_module_system = true ;
656- }
657- skip_next = true ; // skip the original value
658- }
659- _ => {
660- result. push ( arg) ;
661- }
662- }
663- }
664-
665- Ok ( result)
645+ OutputMode :: ToStdout {
646+ module_format : module_format. to_string ( ) ,
647+ } ,
648+ )
666649}
667650
668651/// Compile a single file and return its JavaScript output on stdout.
@@ -864,6 +847,7 @@ fn compile_file(
864847 is_type_dev,
865848 package. is_local_dep ,
866849 warn_error_override,
850+ OutputMode :: ToFile ,
867851 ) ?;
868852
869853 let to_mjs = Command :: new ( & compiler_info. bsc_path )
0 commit comments