Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions compiler/bsc/rescript_compiler_main.ml
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,8 @@ let command_line_flags : (string * Bsc_args.spec * string) array =
set Clflags.transparent_modules,
"*internal*Do not record dependencies for module aliases" );
("-bs-gentype", set Clflags.bs_gentype, "*internal* Pass gentype command");
<<<<<<< HEAD
<<<<<<< HEAD
( "-bs-gentype-module",
string_call (fun s ->
GenTypeConfig.module_flag := GenTypeConfig.module_of_string s),
Expand Down Expand Up @@ -341,6 +343,9 @@ let command_line_flags : (string * Bsc_args.spec * string) array =
string_call (fun s -> GenTypeConfig.bsb_project_root := s),
"*internal* Set gentype bsb project root (workspace root containing \
.sourcedirs.json)" );
( "-bs-multi-entry",
set Js_config.multi_entry,
"*internal* Preserve lowercase file module names" );
(******************************************************************************)
( "-unboxed-types",
set Clflags.unboxed_types,
Expand Down
1 change: 1 addition & 0 deletions compiler/common/js_config.ml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ let jsx_module = ref React
let jsx_preserve = ref false
let js_stdout = ref true
let all_module_aliases = ref false
let multi_entry = ref false
let no_stdlib = ref false
let no_export = ref false
let int_of_jsx_version = function
Expand Down
2 changes: 2 additions & 0 deletions compiler/common/js_config.mli
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ val js_stdout : bool ref

val all_module_aliases : bool ref

val multi_entry : bool ref

val no_stdlib : bool ref

val no_export : bool ref
Expand Down
11 changes: 8 additions & 3 deletions compiler/core/js_implementation.ml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ let module_of_filename outputprefix =
String.sub basename 0 pos
with Not_found -> basename
in
String.capitalize_ascii name
if !Js_config.multi_entry then name else String.capitalize_ascii name

let fprintf = Format.fprintf

Expand Down Expand Up @@ -129,7 +129,10 @@ let after_parsing_impl ppf outputprefix (ast : Parsetree.structure) =
output_value stdout ast);
if !Js_config.syntax_only then Warnings.check_fatal ()
else
let modulename = Ext_filename.module_name outputprefix in
let modulename =
Ext_filename.module_name ~preserve_case:!Js_config.multi_entry
outputprefix
in
Lam_compile_env.reset ();
let env = Res_compmisc.initial_env ~modulename () in
Env.set_unit_name modulename;
Expand Down Expand Up @@ -192,7 +195,9 @@ let implementation_map ppf sourcefile =
seek_in ichan (Ext_digest.length + 1);
let list_of_modules = Ext_io.rev_lines_of_chann ichan in
close_in ichan;
let ns = Ext_filename.module_name sourcefile in
let ns =
Ext_filename.module_name ~preserve_case:!Js_config.multi_entry sourcefile
in
let ml_ast =
Ext_list.fold_left list_of_modules [] (fun acc line ->
if Ext_string.is_empty line then acc
Expand Down
9 changes: 6 additions & 3 deletions compiler/ext/ext_filename.ml
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,13 @@ let new_extension name (ext : string) =
we can not tell the difference between "x.cpp.ml"
and "x.ml"
*)
let module_name name =
let module_name ?(preserve_case = false) name =
let rec search_dot i name =
if i < 0 then Ext_string.capitalize_ascii name
else if String.unsafe_get name i = '.' then Ext_string.capitalize_sub name i
if i < 0 then
if preserve_case then name else Ext_string.capitalize_ascii name
else if String.unsafe_get name i = '.' then
if preserve_case then String.sub name 0 i
else Ext_string.capitalize_sub name i
else search_dot (i - 1) name
in
let name = Filename.basename name in
Expand Down
2 changes: 1 addition & 1 deletion compiler/ext/ext_filename.mli
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ val new_extension : string -> string -> string
val chop_all_extensions_maybe : string -> string

(* OCaml specific abstraction*)
val module_name : string -> string
val module_name : ?preserve_case:bool -> string -> string

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

Expand Down
4 changes: 4 additions & 0 deletions docs/docson/build-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,10 @@
"$ref": "#/definitions/namespace-spec",
"description": "can be true/false or a customized name"
},
"multi-entry": {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the name "multi-entry", it is pretty unclear what this option does.

Feedback from Codex

"multi-entry" is misleading here. It sounds like “multiple entrypoints” or a bundler feature, while the actual semantic change is module visibility and naming.

It suggests these alternatives:

  • private-file-modules
  • private-lowercase-modules
  • file-private-modules

Maybe the second one is clearest? Any other suggestions?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll have a think / rename this. I agree multi-entry is a bit vague

"type": "boolean",
"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."
},
"sources": {
"$ref": "#/definitions/sources",
"description": "Source code location"
Expand Down
17 changes: 7 additions & 10 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,15 +76,13 @@
"#cli/*": "./cli/common/*.js",
"#dev/*": "./lib_dev/*.js"
},
"dependencies": {
"@rescript/runtime": "workspace:packages/@rescript/runtime"
},
"optionalDependencies": {
"@rescript/darwin-arm64": "workspace:packages/@rescript/darwin-arm64",
"@rescript/darwin-x64": "workspace:packages/@rescript/darwin-x64",
"@rescript/linux-arm64": "workspace:packages/@rescript/linux-arm64",
"@rescript/linux-x64": "workspace:packages/@rescript/linux-x64",
"@rescript/win32-x64": "workspace:packages/@rescript/win32-x64"
"@rescript/darwin-arm64": "workspace:*",
"@rescript/darwin-x64": "workspace:*",
"@rescript/linux-arm64": "workspace:*",
"@rescript/linux-x64": "workspace:*",
"@rescript/runtime": "workspace:*",
"@rescript/win32-x64": "workspace:*"
},
"devDependencies": {
"@biomejs/biome": "2.4.10",
Expand All @@ -97,8 +95,7 @@
"typescript": "6.0.3"
},
"workspaces": [
"packages/playground",
"packages/@rescript/*",
"packages/**",
"tests/dependencies/**",
"tests/analysis_tests/**",
"tests/docstring_tests",
Expand Down
1 change: 1 addition & 0 deletions rewatch/CompilerConfigurationSpec.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ This document contains a list of all config parameters with remarks, and whether
| name | string | | [x] |
| namespace | boolean | | [x] |
| namespace | string | | [x] |
| multi-entry | boolean | Lowercase file modules stay private and duplicate lowercase file stems are allowed | [x] |
| sources | string | | [x] |
| sources | array of string | | [x] |
| sources | Source | | [x] |
Expand Down
29 changes: 16 additions & 13 deletions rewatch/src/build/clean.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,23 @@ use std::io::Write;
use std::path::{Path, PathBuf};
use std::time::Instant;

fn remove_ast_cache(package: &packages::Package, source_file: &Path, extension: &str) {
let ast_cache_path = helpers::get_ocaml_ast_cache_path_for_extension(package, source_file, extension);
let _ = std::fs::remove_file(&ast_cache_path);

let legacy_ast_cache_path =
helpers::get_compiler_asset(package, &packages::Namespace::NoNamespace, source_file, extension);
if legacy_ast_cache_path != ast_cache_path {
let _ = std::fs::remove_file(legacy_ast_cache_path);
}
}

fn remove_ast(package: &packages::Package, source_file: &Path) {
let _ = std::fs::remove_file(helpers::get_compiler_asset(
package,
&packages::Namespace::NoNamespace,
source_file,
"ast",
));
remove_ast_cache(package, source_file, "ast");
}

fn remove_iast(package: &packages::Package, source_file: &Path) {
let _ = std::fs::remove_file(helpers::get_compiler_asset(
package,
&packages::Namespace::NoNamespace,
source_file,
"iast",
));
remove_ast_cache(package, source_file, "iast");
}

fn remove_mjs_file(source_file: &Path, suffix: &str) {
Expand Down Expand Up @@ -250,7 +251,9 @@ pub fn cleanup_previous_build(
.difference(&all_module_names)
.flat_map(|module_name| {
// if the module is a namespace, we need to mark the whole namespace as dirty when a module has been deleted
if let Some(namespace) = helpers::get_namespace_from_module_name(module_name) {
if !module_name.contains(':')
&& let Some(namespace) = helpers::get_namespace_from_module_name(module_name)
{
return vec![namespace, module_name.to_string()];
}
vec![module_name.to_string()]
Expand Down
67 changes: 47 additions & 20 deletions rewatch/src/build/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -526,10 +526,14 @@ pub fn compiler_args(
) -> Result<Vec<String>> {
let bsc_flags = config::flatten_flags(&config.compiler_flags);
let dependency_paths = get_dependency_paths(config, project_context, packages, is_type_dev);
let module_name = helpers::file_path_to_module_name(file_path, &config.get_namespace());
let multi_entry = config.is_multi_entry_enabled();
let module_name =
helpers::file_path_to_constructible_module_name(file_path, &config.get_namespace(), multi_entry);

let namespace_args = match &config.get_namespace() {
packages::Namespace::NamespaceWithEntry { namespace: _, entry } if &module_name == entry => {
packages::Namespace::NamespaceWithEntry { namespace: _, entry }
if module_name.as_ref() == Some(entry) =>
{
// if the module is the entry we just want to open the namespace
vec![
"-open".to_string(),
Expand Down Expand Up @@ -586,11 +590,23 @@ pub fn compiler_args(
let package_name_arg = vec!["-bs-package-name".to_string(), config.name.to_owned()];
let project_root_args = config.get_project_root_args();

let multi_entry_arg = if multi_entry {
vec!["-bs-multi-entry".to_string()]
} else {
vec![]
};

let implementation_args = if is_interface {
debug!("Compiling interface file: {}", &module_name);
debug!(
"Compiling interface file: {}",
module_name.as_deref().unwrap_or("<private file module>")
);
vec![]
} else {
debug!("Compiling file: {}", &module_name);
debug!(
"Compiling file: {}",
module_name.as_deref().unwrap_or("<private file module>")
);
let specs = root_config.get_package_specs();

specs
Expand Down Expand Up @@ -639,6 +655,7 @@ pub fn compiler_args(
warning_args,
gentype_arg,
experimental_args,
multi_entry_arg,
// vec!["-warn-error".to_string(), "A".to_string()],
// ^^ this one fails for bisect-ppx
// this is the default
Expand Down Expand Up @@ -770,6 +787,12 @@ fn compile_file(
.map_err(|e| anyhow!(e))?;
let basename =
helpers::file_path_to_compiler_asset_basename(implementation_file_path, &package.namespace);
let is_constructible_module = helpers::file_path_to_constructible_module_name(
implementation_file_path,
&package.namespace,
package.config.is_multi_entry_enabled(),
)
.is_some();
let has_interface = module.get_interface().is_some();
let is_type_dev = module.is_type_dev;
// `gentype_dirs` is populated once during package discovery, so we just
Expand Down Expand Up @@ -817,7 +840,7 @@ fn compile_file(
let dir = Path::new(implementation_file_path).parent().unwrap();

// perhaps we can do this copying somewhere else
if !is_interface {
if !is_interface && is_constructible_module {
let _ = std::fs::copy(
package
.get_build_path()
Expand All @@ -842,7 +865,7 @@ fn compile_file(
.join(format!("{basename}.cmt")),
ocaml_build_path_abs.join(format!("{basename}.cmt")),
);
} else {
} else if is_interface && is_constructible_module {
let _ = std::fs::copy(
package
.get_build_path()
Expand Down Expand Up @@ -870,13 +893,15 @@ fn compile_file(
)
.expect("copying source file failed");

let _ = std::fs::copy(
Path::new(&package.path).join(path),
package
.get_ocaml_build_path()
.join(std::path::Path::new(path).file_name().unwrap()),
)
.expect("copying source file failed");
if is_constructible_module {
let _ = std::fs::copy(
Path::new(&package.path).join(path),
package
.get_ocaml_build_path()
.join(std::path::Path::new(path).file_name().unwrap()),
)
.expect("copying source file failed");
}
}
if let SourceType::SourceFile(SourceFile {
implementation: Implementation { path, .. },
Expand All @@ -892,13 +917,15 @@ fn compile_file(
)
.expect("copying source file failed");

let _ = std::fs::copy(
Path::new(&package.path).join(path),
package
.get_ocaml_build_path()
.join(std::path::Path::new(path).file_name().unwrap()),
)
.expect("copying source file failed");
if is_constructible_module {
let _ = std::fs::copy(
Path::new(&package.path).join(path),
package
.get_ocaml_build_path()
.join(std::path::Path::new(path).file_name().unwrap()),
)
.expect("copying source file failed");
}
}

// copy js file
Expand Down
Loading
Loading