Skip to content

Commit d7ebd03

Browse files
committed
Multi Entry Paths
1 parent 4143b81 commit d7ebd03

16 files changed

Lines changed: 310 additions & 49 deletions

compiler/bsc/rescript_compiler_main.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,7 @@ let command_line_flags : (string * Bsc_args.spec * string) array =
293293
set Clflags.transparent_modules,
294294
"*internal*Do not record dependencies for module aliases" );
295295
("-bs-gentype", set Clflags.bs_gentype, "*internal* Pass gentype command");
296+
("-bs-multi-entry", set Js_config.multi_entry, "*internal* Preserve lowercase file module names");
296297
(******************************************************************************)
297298
( "-unboxed-types",
298299
set Clflags.unboxed_types,

compiler/common/js_config.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ let jsx_module = ref React
5454
let jsx_preserve = ref false
5555
let js_stdout = ref true
5656
let all_module_aliases = ref false
57+
let multi_entry = ref false
5758
let no_stdlib = ref false
5859
let no_export = ref false
5960
let int_of_jsx_version = function

compiler/common/js_config.mli

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ val js_stdout : bool ref
8888

8989
val all_module_aliases : bool ref
9090

91+
val multi_entry : bool ref
92+
9193
val no_stdlib : bool ref
9294

9395
val no_export : bool ref

compiler/core/js_implementation.ml

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ let module_of_filename outputprefix =
2020
String.sub basename 0 pos
2121
with Not_found -> basename
2222
in
23-
String.capitalize_ascii name
23+
if !Js_config.multi_entry then name else String.capitalize_ascii name
2424

2525
let fprintf = Format.fprintf
2626

@@ -129,7 +129,11 @@ let after_parsing_impl ppf outputprefix (ast : Parsetree.structure) =
129129
output_value stdout ast);
130130
if !Js_config.syntax_only then Warnings.check_fatal ()
131131
else
132-
let modulename = Ext_filename.module_name outputprefix in
132+
let modulename =
133+
Ext_filename.module_name
134+
~preserve_case:(!Js_config.multi_entry)
135+
outputprefix
136+
in
133137
Lam_compile_env.reset ();
134138
let env = Res_compmisc.initial_env ~modulename () in
135139
Env.set_unit_name modulename;
@@ -192,7 +196,9 @@ let implementation_map ppf sourcefile =
192196
seek_in ichan (Ext_digest.length + 1);
193197
let list_of_modules = Ext_io.rev_lines_of_chann ichan in
194198
close_in ichan;
195-
let ns = Ext_filename.module_name sourcefile in
199+
let ns =
200+
Ext_filename.module_name ~preserve_case:(!Js_config.multi_entry) sourcefile
201+
in
196202
let ml_ast =
197203
Ext_list.fold_left list_of_modules [] (fun acc line ->
198204
if Ext_string.is_empty line then acc

compiler/ext/ext_filename.ml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,11 @@ let new_extension name (ext : string) =
7676
we can not tell the difference between "x.cpp.ml"
7777
and "x.ml"
7878
*)
79-
let module_name name =
79+
let module_name ?(preserve_case = false) name =
8080
let rec search_dot i name =
81-
if i < 0 then Ext_string.capitalize_ascii name
82-
else if String.unsafe_get name i = '.' then Ext_string.capitalize_sub name i
81+
if i < 0 then if preserve_case then name else Ext_string.capitalize_ascii name
82+
else if String.unsafe_get name i = '.' then
83+
if preserve_case then String.sub name 0 i else Ext_string.capitalize_sub name i
8384
else search_dot (i - 1) name
8485
in
8586
let name = Filename.basename name in

compiler/ext/ext_filename.mli

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ val new_extension : string -> string -> string
4343
val chop_all_extensions_maybe : string -> string
4444

4545
(* OCaml specific abstraction*)
46-
val module_name : string -> string
46+
val module_name : ?preserve_case:bool -> string -> string
4747

4848
type module_info = {module_name: string; case: bool}
4949

docs/docson/build-schema.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,10 @@
364364
"$ref": "#/definitions/namespace-spec",
365365
"description": "can be true/false or a customized name"
366366
},
367+
"multi-entry": {
368+
"type": "boolean",
369+
"description": "Default: false. When true, lowercase source files are compiled as private file-level modules without capitalizing their file module name. They cannot be referenced from ReScript code, are not exported through namespaces, and duplicate lowercase file stems are allowed across source folders. Pascal-case file modules keep the normal globally unique module behavior."
370+
},
367371
"sources": {
368372
"$ref": "#/definitions/sources",
369373
"description": "Source code location"

rewatch/CompilerConfigurationSpec.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ This document contains a list of all config parameters with remarks, and whether
77
| name | string | | [x] |
88
| namespace | boolean | | [x] |
99
| namespace | string | | [x] |
10+
| multi-entry | boolean | Lowercase file modules stay private and duplicate lowercase file stems are allowed | [x] |
1011
| sources | string | | [x] |
1112
| sources | array of string | | [x] |
1213
| sources | Source | | [x] |

rewatch/src/build/clean.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,9 @@ pub fn cleanup_previous_build(
250250
.difference(&all_module_names)
251251
.flat_map(|module_name| {
252252
// if the module is a namespace, we need to mark the whole namespace as dirty when a module has been deleted
253-
if let Some(namespace) = helpers::get_namespace_from_module_name(module_name) {
253+
if !module_name.contains(':')
254+
&& let Some(namespace) = helpers::get_namespace_from_module_name(module_name)
255+
{
254256
return vec![namespace, module_name.to_string()];
255257
}
256258
vec![module_name.to_string()]

rewatch/src/build/compile.rs

Lines changed: 46 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -523,10 +523,14 @@ pub fn compiler_args(
523523
) -> Result<Vec<String>> {
524524
let bsc_flags = config::flatten_flags(&config.compiler_flags);
525525
let dependency_paths = get_dependency_paths(config, project_context, packages, is_type_dev);
526-
let module_name = helpers::file_path_to_module_name(file_path, &config.get_namespace());
526+
let multi_entry = config.is_multi_entry_enabled();
527+
let module_name =
528+
helpers::file_path_to_constructible_module_name(file_path, &config.get_namespace(), multi_entry);
527529

528530
let namespace_args = match &config.get_namespace() {
529-
packages::Namespace::NamespaceWithEntry { namespace: _, entry } if &module_name == entry => {
531+
packages::Namespace::NamespaceWithEntry { namespace: _, entry }
532+
if module_name.as_ref() == Some(entry) =>
533+
{
530534
// if the module is the entry we just want to open the namespace
531535
vec![
532536
"-open".to_string(),
@@ -567,12 +571,23 @@ pub fn compiler_args(
567571
};
568572

569573
let package_name_arg = vec!["-bs-package-name".to_string(), config.name.to_owned()];
574+
let multi_entry_arg = if multi_entry {
575+
vec!["-bs-multi-entry".to_string()]
576+
} else {
577+
vec![]
578+
};
570579

571580
let implementation_args = if is_interface {
572-
debug!("Compiling interface file: {}", &module_name);
581+
debug!(
582+
"Compiling interface file: {}",
583+
module_name.as_deref().unwrap_or("<private file module>")
584+
);
573585
vec![]
574586
} else {
575-
debug!("Compiling file: {}", &module_name);
587+
debug!(
588+
"Compiling file: {}",
589+
module_name.as_deref().unwrap_or("<private file module>")
590+
);
576591
let specs = root_config.get_package_specs();
577592

578593
specs
@@ -621,6 +636,7 @@ pub fn compiler_args(
621636
warning_args,
622637
gentype_arg,
623638
experimental_args,
639+
multi_entry_arg,
624640
// vec!["-warn-error".to_string(), "A".to_string()],
625641
// ^^ this one fails for bisect-ppx
626642
// this is the default
@@ -751,6 +767,12 @@ fn compile_file(
751767
.map_err(|e| anyhow!(e))?;
752768
let basename =
753769
helpers::file_path_to_compiler_asset_basename(implementation_file_path, &package.namespace);
770+
let is_constructible_module = helpers::file_path_to_constructible_module_name(
771+
implementation_file_path,
772+
&package.namespace,
773+
package.config.is_multi_entry_enabled(),
774+
)
775+
.is_some();
754776
let has_interface = module.get_interface().is_some();
755777
let is_type_dev = module.is_type_dev;
756778
let to_mjs_args = compiler_args(
@@ -794,7 +816,7 @@ fn compile_file(
794816
let dir = Path::new(implementation_file_path).parent().unwrap();
795817

796818
// perhaps we can do this copying somewhere else
797-
if !is_interface {
819+
if !is_interface && is_constructible_module {
798820
let _ = std::fs::copy(
799821
package
800822
.get_build_path()
@@ -819,7 +841,7 @@ fn compile_file(
819841
.join(format!("{basename}.cmt")),
820842
ocaml_build_path_abs.join(format!("{basename}.cmt")),
821843
);
822-
} else {
844+
} else if is_interface && is_constructible_module {
823845
let _ = std::fs::copy(
824846
package
825847
.get_build_path()
@@ -847,13 +869,15 @@ fn compile_file(
847869
)
848870
.expect("copying source file failed");
849871

850-
let _ = std::fs::copy(
851-
Path::new(&package.path).join(path),
852-
package
853-
.get_ocaml_build_path()
854-
.join(std::path::Path::new(path).file_name().unwrap()),
855-
)
856-
.expect("copying source file failed");
872+
if is_constructible_module {
873+
let _ = std::fs::copy(
874+
Path::new(&package.path).join(path),
875+
package
876+
.get_ocaml_build_path()
877+
.join(std::path::Path::new(path).file_name().unwrap()),
878+
)
879+
.expect("copying source file failed");
880+
}
857881
}
858882
if let SourceType::SourceFile(SourceFile {
859883
implementation: Implementation { path, .. },
@@ -869,13 +893,15 @@ fn compile_file(
869893
)
870894
.expect("copying source file failed");
871895

872-
let _ = std::fs::copy(
873-
Path::new(&package.path).join(path),
874-
package
875-
.get_ocaml_build_path()
876-
.join(std::path::Path::new(path).file_name().unwrap()),
877-
)
878-
.expect("copying source file failed");
896+
if is_constructible_module {
897+
let _ = std::fs::copy(
898+
Path::new(&package.path).join(path),
899+
package
900+
.get_ocaml_build_path()
901+
.join(std::path::Path::new(path).file_name().unwrap()),
902+
)
903+
.expect("copying source file failed");
904+
}
879905
}
880906

881907
// copy js file

0 commit comments

Comments
 (0)