Skip to content

Commit 2a5999e

Browse files
committed
Add --module-format parameter
1 parent 5d480bb commit 2a5999e

3 files changed

Lines changed: 73 additions & 7 deletions

File tree

rewatch/src/build.rs

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,7 @@ pub fn compile_one(
579579
project_root: &Path,
580580
plain_output: bool,
581581
warn_error: Option<String>,
582+
module_format: Option<String>,
582583
) -> Result<String> {
583584
use std::fs;
584585

@@ -593,6 +594,12 @@ pub fn compile_one(
593594
warn_error,
594595
)?;
595596

597+
// Determine which package spec to use for output
598+
let root_config = build_state.get_root_config();
599+
let package_specs = root_config.get_package_specs();
600+
601+
let selected_spec_index = select_package_spec(&package_specs, &module_format)?;
602+
596603
// Step 2: Find target module from file path
597604
let target_module_name = find_module_for_file(&build_state, target_file)
598605
.ok_or_else(|| anyhow!("File not found in project: {}", target_file.display()))?;
@@ -633,13 +640,57 @@ pub fn compile_one(
633640
.map_err(|e| anyhow!("Compilation failed: {}", e))?;
634641

635642
// Step 7: Find and read the generated JavaScript file
636-
let js_path = get_js_output_path(&build_state, &target_module_name, target_file)?;
643+
let js_path = get_js_output_path(&build_state, &target_module_name, selected_spec_index)?;
637644
let js_content = fs::read_to_string(&js_path)
638645
.map_err(|e| anyhow!("Failed to read generated JS file {}: {}", js_path.display(), e))?;
639646

640647
Ok(js_content)
641648
}
642649

650+
/// Select the appropriate package spec based on the module_format argument.
651+
///
652+
/// If module_format is specified, find the matching spec.
653+
/// If not specified and there are multiple specs, warn and use the first one.
654+
/// Returns the index of the selected package spec.
655+
fn select_package_spec(
656+
package_specs: &[config::PackageSpec],
657+
module_format: &Option<String>,
658+
) -> Result<usize> {
659+
if package_specs.is_empty() {
660+
return Err(anyhow!("No package-specs configured in rescript.json"));
661+
}
662+
663+
match module_format {
664+
Some(format) => {
665+
// Find the package spec matching the requested format
666+
package_specs
667+
.iter()
668+
.position(|spec| spec.module == *format)
669+
.ok_or_else(|| {
670+
let available: Vec<&str> = package_specs.iter().map(|s| s.module.as_str()).collect();
671+
anyhow!(
672+
"Module format '{}' not found in package-specs. Available: {}",
673+
format,
674+
available.join(", ")
675+
)
676+
})
677+
}
678+
None => {
679+
// No format specified - use first, but warn if multiple exist
680+
if package_specs.len() > 1 {
681+
let available: Vec<&str> = package_specs.iter().map(|s| s.module.as_str()).collect();
682+
eprintln!(
683+
"Warning: Multiple package-specs configured ({}). Using '{}'. \
684+
Specify --module-format to choose a different one.",
685+
available.join(", "),
686+
package_specs[0].module
687+
);
688+
}
689+
Ok(0)
690+
}
691+
}
692+
}
693+
643694
/// Find the module name for a given file path by searching through all modules.
644695
///
645696
/// This performs a linear search through the build state's modules to match
@@ -705,11 +756,11 @@ fn get_dependency_closure(module_name: &str, build_state: &BuildState) -> AHashS
705756
/// Respects the package's configuration for output location and format:
706757
/// - in-source: JS file next to the .res file
707758
/// - out-of-source: JS file in lib/js or lib/es6
708-
/// - Uses first package spec to determine .js vs .mjs extension
759+
/// - Uses the selected package spec to determine .js vs .mjs extension
709760
fn get_js_output_path(
710761
build_state: &BuildCommandState,
711762
module_name: &str,
712-
_original_file: &Path,
763+
spec_index: usize,
713764
) -> Result<PathBuf> {
714765
let module = build_state
715766
.get_module(module_name)
@@ -722,8 +773,8 @@ fn get_js_output_path(
722773
let root_config = build_state.get_root_config();
723774
let package_specs = root_config.get_package_specs();
724775
let package_spec = package_specs
725-
.first()
726-
.ok_or_else(|| anyhow!("No package specs configured"))?;
776+
.get(spec_index)
777+
.ok_or_else(|| anyhow!("Package spec index {} out of bounds", spec_index))?;
727778

728779
let suffix = root_config.get_suffix(package_spec);
729780

rewatch/src/cli.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,11 @@ pub enum Command {
466466
/// Path to a ReScript source file (.res or .resi)
467467
path: String,
468468

469+
/// Module format to use (commonjs or esmodule). If not specified and multiple
470+
/// package-specs are configured, the first one is used with a warning.
471+
#[arg(long)]
472+
module_format: Option<String>,
473+
469474
#[command(flatten)]
470475
warn_error: WarnErrorArg,
471476
},

rewatch/src/main.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,11 @@ fn main() -> Result<()> {
5050
println!("{}", build::get_compiler_args(Path::new(&path))?);
5151
std::process::exit(0);
5252
}
53-
cli::Command::CompileFile { path, warn_error } => {
53+
cli::Command::CompileFile {
54+
path,
55+
module_format,
56+
warn_error,
57+
} => {
5458
// Find project root by walking up from file path (same as CompilerArgs command)
5559
let file_path = Path::new(&path);
5660
let project_root = helpers::get_abs_path(
@@ -59,7 +63,13 @@ fn main() -> Result<()> {
5963

6064
let _lock = get_lock(project_root.to_str().unwrap());
6165

62-
match build::compile_one(file_path, &project_root, plain_output, (*warn_error).clone()) {
66+
match build::compile_one(
67+
file_path,
68+
&project_root,
69+
plain_output,
70+
(*warn_error).clone(),
71+
module_format,
72+
) {
6373
Ok(js_output) => {
6474
// Output JS to stdout (clean for piping)
6575
print!("{js_output}");

0 commit comments

Comments
 (0)