@@ -220,21 +220,23 @@ let string_of_module_id
220220match Config_util. find_opt cmj_filewith
221221| Some cmj_path ->
222222let cmj_dir= Filename. dirname cmj_pathin
223- let lib_bs_pattern = " / lib/bs/ " in
223+ (* Platform-independent: look for " lib<sep>bs<sep>" where <sep> is / or \\ *)
224224let source_dir=
225225try
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_sepin
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 ) sepin
228230let rec find_lib_bs pos =
229231if 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. lengthlib_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. lengthlib_bs )
232234else
233235 find_lib_bs (pos- 1 )
234236in
235237match find_lib_bs idxwith
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" *)
238240String. sub cmj_dir start_idx (String. length cmj_dir- start_idx)
239241| None -> cmj_dir
240242with 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_dotthen begin
278284let cmj_file= dep_module_id.id.name^ Literals. suffix_cmjin
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_sepin
287+ let lib_ocaml_pattern= " lib" ^ Filename. dir_sep^ " ocaml" ^ Filename. dir_sepin
280288let cmj_opt=
281289match Config_util. find_opt cmj_filewith
282- | Some path when Ext_string. contain_substring path" /lib/bs/ " ->
290+ | Some path when Ext_string. contain_substring pathlib_bs_pattern ->
283291Some path
284292| Some ocaml_path ->
285293(* Found lib/ocaml, derive lib/bs path from it*)
286- let lib_ocaml_pattern= " /lib/ocaml/" in
287294let pkg_root=
288295try
296+ let sep= Filename. dir_sep.[0 ]in
289297let rec find_lib_ocaml pos =
290298if pos< 0 then None
291299else if Ext_string. starts_with (String. sub ocaml_path pos (String. length ocaml_path- pos)) lib_ocaml_patternthen
292300Some (String. sub ocaml_path0 pos)
293301else
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
295307in
296308 find_lib_ocaml (String. length ocaml_path- 1 )
297309with Not_found ->None
@@ -326,37 +338,121 @@ let string_of_module_id
326338| None ->Some ocaml_path)
327339| None ->None
328340in
329- match cmj_optwith
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_pathin
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_patternthen
342- Some (pos+ String. length lib_bs_pattern)
343- else
344- find_lib_bs (pos- 1 )
345- in
346- match find_lib_bs idxwith
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_optwith
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_pathin
351+ let sep= Filename. dir_sep.[0 ]in
352+ let lib_bs_pattern= " lib" ^ Filename. dir_sep^ " bs" ^ Filename. dir_sepin
353+ let source_dir=
354+ try
355+ let idx= String. rindex_from cmj_dir (String. length cmj_dir- 1 ) sepin
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_patternthen
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 idxwith
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"*)
353374let pkg_name=
354375String. sub dep_pkg.pkg_rel_path0 (String. length dep_pkg.pkg_rel_path- 2 )
355376in
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 pathin
385+ let basename= Filename. basename pathin
386+ if basename= pkg_namethen Some path(* Return the path itself, not parent*)
387+ else if parent= paththen None
388+ else find_pkg_root parent
389+ in
390+ match find_pkg_root cmj_pathwith
391+ | Some pkg_root ->
392+ let (// )= Filename. concatin
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.namein
399+ (* Check both exact match (A.cmj) and namespace pattern (A-*.cmj)*)
400+ let cmj_exact= module_base^ Literals. suffix_cmjin
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_dirthen begin
406+ try
407+ let files= Sys. readdir dirin
408+ Array. fold_left (fun acc file ->
409+ match accwith
410+ | Some _ -> acc
411+ | None ->
412+ if file= cmj_exact|| Ext_string. starts_with file cmj_pattern_prefixthen begin
413+ if Ext_string. ends_with fileLiterals. suffix_cmjthen begin
414+ let full_path= dir// filein
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_dirwith
428+ | Some _ -> found_in_current_dir
429+ | None ->
430+ (* Not found in current dir, search subdirectories*)
431+ try
432+ let subdirs= Sys. readdir dirin
433+ Array. fold_left (fun acc subdir ->
434+ match accwith
435+ | Some _ -> acc
436+ | None ->
437+ let sub_path= dir// subdirin
438+ if Sys. is_directory sub_paththen find_in_dir sub_path
439+ else None
440+ )None subdirs
441+ with _ ->None
442+ in
443+ (match find_in_dir lib_bs_dirwith
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_filein
454+ else begin
455+ let result= pkg_name// final_source_dir // js_filein
360456(* Reconstruct: "a" + "src" + "A.res.js" = "a/src/A.res.js"*)
361457 result
362458end