Skip to content

Commit 102f806

Browse files
committed
This is getting out of hand
1 parent 22e4f13 commit 102f806

File tree

1 file changed

+134
-38
lines changed

1 file changed

+134
-38
lines changed

compiler/core/js_name_of_module_id.ml

Lines changed: 134 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -220,21 +220,23 @@ let string_of_module_id
220220
match Config_util.find_opt cmj_file with
221221
| Some cmj_path ->
222222
let cmj_dir = Filename.dirname cmj_path in
223-
let lib_bs_pattern = "/lib/bs/" in
223+
(* Platform-independent: look for "lib<sep>bs<sep>" where <sep> is / or \\ *)
224224
let source_dir =
225225
try
226-
(* Find "/lib/bs/" in the path and extract everything after it *)
227-
let idx = String.rindex_from cmj_dir (String.length cmj_dir - 1) '/' in
226+
let sep = Filename.dir_sep.[0] in
227+
let lib_bs = "lib" ^ Filename.dir_sep ^ "bs" ^ Filename.dir_sep in
228+
(* Find "lib/bs/" or "lib\\bs\\" in the path and extract everything after it *)
229+
let idx = String.rindex_from cmj_dir (String.length cmj_dir - 1) sep in
228230
let rec find_lib_bs pos =
229231
if pos < 0 then None
230-
else if Ext_string.starts_with (String.sub cmj_dir pos (String.length cmj_dir - pos)) lib_bs_pattern then
231-
Some (pos + String.length lib_bs_pattern)
232+
else if Ext_string.starts_with (String.sub cmj_dir pos (String.length cmj_dir - pos)) lib_bs then
233+
Some (pos + String.length lib_bs)
232234
else
233235
find_lib_bs (pos - 1)
234236
in
235237
match find_lib_bs idx with
236238
| Some start_idx ->
237-
(* Example: extract "src/core/intl" from ".../lib/bs/src/core/intl" *)
239+
(* Example: extract "src/core/intl" from ".../lib/bs/src/core/intl" or "...\\lib\\bs\\src\\core\\intl" *)
238240
String.sub cmj_dir start_idx (String.length cmj_dir - start_idx)
239241
| None -> cmj_dir
240242
with Not_found -> cmj_dir
@@ -272,26 +274,36 @@ let string_of_module_id
272274
We extract the actual source directory from the dependency's .cmj file
273275
location and reconstruct the import path correctly.
274276
*)
275-
(* External package imports: check if pkg_rel_path ends with "/."
277+
(* External package imports: check if pkg_rel_path ends with "/." or "\."
276278
which indicates the dependency uses in-source builds *)
277-
if Ext_string.ends_with dep_pkg.pkg_rel_path "/." then begin
279+
let ends_with_dot =
280+
Ext_string.ends_with dep_pkg.pkg_rel_path "/." ||
281+
Ext_string.ends_with dep_pkg.pkg_rel_path "\\."
282+
in
283+
if ends_with_dot then begin
278284
let cmj_file = dep_module_id.id.name ^ Literals.suffix_cmj in
279285
(* Prefer lib/bs over lib/ocaml as lib/bs preserves source directory structure *)
286+
let lib_bs_pattern = "lib" ^ Filename.dir_sep ^ "bs" ^ Filename.dir_sep in
287+
let lib_ocaml_pattern = "lib" ^ Filename.dir_sep ^ "ocaml" ^ Filename.dir_sep in
280288
let cmj_opt =
281289
match Config_util.find_opt cmj_file with
282-
| Some path when Ext_string.contain_substring path "/lib/bs/" ->
290+
| Some path when Ext_string.contain_substring path lib_bs_pattern ->
283291
Some path
284292
| Some ocaml_path ->
285293
(* Found lib/ocaml, derive lib/bs path from it *)
286-
let lib_ocaml_pattern = "/lib/ocaml/" in
287294
let pkg_root =
288295
try
296+
let sep = Filename.dir_sep.[0] in
289297
let rec find_lib_ocaml pos =
290298
if pos < 0 then None
291299
else if Ext_string.starts_with (String.sub ocaml_path pos (String.length ocaml_path - pos)) lib_ocaml_pattern then
292300
Some (String.sub ocaml_path 0 pos)
293301
else
294-
find_lib_ocaml (pos - 1)
302+
let next_pos =
303+
try String.rindex_from ocaml_path (pos - 1) sep
304+
with Not_found -> -1
305+
in
306+
find_lib_ocaml next_pos
295307
in
296308
find_lib_ocaml (String.length ocaml_path - 1)
297309
with Not_found -> None
@@ -326,37 +338,121 @@ let string_of_module_id
326338
| None -> Some ocaml_path)
327339
| None -> None
328340
in
329-
match cmj_opt with
330-
| Some cmj_path ->
331-
(* External packages store .cmj at node_modules/<pkg>/lib/bs/<source_dir>/<module>.cmj
332-
Example: /Users/barry/Projects/rescript/node_modules/a/lib/bs/src/A-A.cmj
333-
We extract "src" from this path. *)
334-
let cmj_dir = Filename.dirname cmj_path in
335-
let lib_bs_pattern = "/lib/bs/" in
336-
let source_dir =
337-
try
338-
let idx = String.rindex_from cmj_dir (String.length cmj_dir - 1) '/' in
339-
let rec find_lib_bs pos =
340-
if pos < 0 then None
341-
else if Ext_string.starts_with (String.sub cmj_dir pos (String.length cmj_dir - pos)) lib_bs_pattern then
342-
Some (pos + String.length lib_bs_pattern)
343-
else
344-
find_lib_bs (pos - 1)
345-
in
346-
match find_lib_bs idx with
347-
| Some start_idx ->
348-
String.sub cmj_dir start_idx (String.length cmj_dir - start_idx)
349-
| None -> "."
350-
with Not_found -> "."
351-
in
352-
(* Extract package name from pkg_rel_path: "a/." -> "a" *)
341+
match cmj_opt with
342+
| Some cmj_path ->
343+
(* External packages store .cmj at node_modules/<pkg>/lib/bs/<source_dir>/<module>.cmj
344+
Example: /Users/barry/Projects/rescript/node_modules/a/lib/bs/src/A-A.cmj
345+
Or on Windows: C:\Users\barry\node_modules\a\lib\bs\src\A-A.cmj
346+
We extract "src" from this path.
347+
348+
For namespaced packages, there may be a namespace file at the root (lib/bs/A.cmj)
349+
and the actual module in a subdirectory (lib/bs/src/A-A.cmj). We want the latter. *)
350+
let cmj_dir = Filename.dirname cmj_path in
351+
let sep = Filename.dir_sep.[0] in
352+
let lib_bs_pattern = "lib" ^ Filename.dir_sep ^ "bs" ^ Filename.dir_sep in
353+
let source_dir =
354+
try
355+
let idx = String.rindex_from cmj_dir (String.length cmj_dir - 1) sep in
356+
let rec find_lib_bs pos =
357+
if pos < 0 then None
358+
else if Ext_string.starts_with (String.sub cmj_dir pos (String.length cmj_dir - pos)) lib_bs_pattern then
359+
Some (pos + String.length lib_bs_pattern)
360+
else
361+
let next_pos =
362+
try String.rindex_from cmj_dir (pos - 1) sep
363+
with Not_found -> -1
364+
in
365+
find_lib_bs next_pos
366+
in
367+
match find_lib_bs idx with
368+
| Some start_idx ->
369+
String.sub cmj_dir start_idx (String.length cmj_dir - start_idx)
370+
| None -> "."
371+
with Not_found -> "."
372+
in
373+
(* Extract package name from pkg_rel_path: "a/." or "a\\." -> "a" *)
353374
let pkg_name =
354375
String.sub dep_pkg.pkg_rel_path 0 (String.length dep_pkg.pkg_rel_path - 2)
355376
in
356-
if source_dir = "." then begin
377+
(* If source_dir is ".", we found a namespace file at the root.
378+
Try to find the actual module in subdirectories by searching lib/bs recursively. *)
379+
let final_source_dir =
380+
if source_dir = "." then begin
381+
(* Derive package root from cmj_path: .../node_modules/a/lib/bs/A.cmj -> .../node_modules/a *)
382+
try
383+
let rec find_pkg_root path =
384+
let parent = Filename.dirname path in
385+
let basename = Filename.basename path in
386+
if basename = pkg_name then Some path (* Return the path itself, not parent *)
387+
else if parent = path then None
388+
else find_pkg_root parent
389+
in
390+
match find_pkg_root cmj_path with
391+
| Some pkg_root ->
392+
let (//) = Filename.concat in
393+
let lib_bs_dir = pkg_root // "lib" // "bs" in
394+
(* Recursively search for the module file in subdirectories.
395+
For namespaced modules, the file may be A-Namespace.cmj instead of A.cmj *)
396+
let rec find_in_dir dir =
397+
(* Use the original module name directly, don't try to extract from js_file *)
398+
let module_base = dep_module_id.id.name in
399+
(* Check both exact match (A.cmj) and namespace pattern (A-*.cmj) *)
400+
let cmj_exact = module_base ^ Literals.suffix_cmj in
401+
let cmj_pattern_prefix = module_base ^ "-" in
402+
403+
(* First check if dir itself contains a matching file *)
404+
let found_in_current_dir =
405+
if dir <> lib_bs_dir then begin
406+
try
407+
let files = Sys.readdir dir in
408+
Array.fold_left (fun acc file ->
409+
match acc with
410+
| Some _ -> acc
411+
| None ->
412+
if file = cmj_exact || Ext_string.starts_with file cmj_pattern_prefix then begin
413+
if Ext_string.ends_with file Literals.suffix_cmj then begin
414+
let full_path = dir // file in
415+
if Sys.file_exists full_path && not (Sys.is_directory full_path) then
416+
(* Found in a subdirectory, extract relative path from lib/bs/ *)
417+
let rel_from_lib_bs = String.sub dir (String.length lib_bs_dir + 1) (String.length dir - String.length lib_bs_dir - 1) in
418+
Some rel_from_lib_bs
419+
else None
420+
end else None
421+
end else None
422+
) None files
423+
with _ -> None
424+
end else None
425+
in
426+
427+
match found_in_current_dir with
428+
| Some _ -> found_in_current_dir
429+
| None ->
430+
(* Not found in current dir, search subdirectories *)
431+
try
432+
let subdirs = Sys.readdir dir in
433+
Array.fold_left (fun acc subdir ->
434+
match acc with
435+
| Some _ -> acc
436+
| None ->
437+
let sub_path = dir // subdir in
438+
if Sys.is_directory sub_path then find_in_dir sub_path
439+
else None
440+
) None subdirs
441+
with _ -> None
442+
in
443+
(match find_in_dir lib_bs_dir with
444+
| Some subdir -> subdir
445+
| None -> ".")
446+
| None -> "."
447+
with _ -> "."
448+
end else
449+
source_dir
450+
in
451+
if final_source_dir = "." then
452+
(* Still couldn't find it, use default *)
357453
dep_pkg.pkg_rel_path // js_file
358-
end else begin
359-
let result = pkg_name // source_dir // js_file in
454+
else begin
455+
let result = pkg_name // final_source_dir // js_file in
360456
(* Reconstruct: "a" + "src" + "A.res.js" = "a/src/A.res.js" *)
361457
result
362458
end

0 commit comments

Comments
 (0)