@@ -1744,6 +1744,9 @@ val inter4 : string -> string -> string -> string -> string
17441744val concat_array : string -> string array -> string
17451745
17461746val single_colon : string
1747+
1748+ val parent_dir_lit : string
1749+ val current_dir_lit : string
17471750end = struct
17481751#1 "ext_string.ml"
17491752(* Copyright (C) 2015-2016 Bloomberg Finance L.P.
@@ -2217,6 +2220,8 @@ let inter4 a b c d =
22172220 concat_array single_space [| a; b ; c; d|]
22182221
22192222
2223+ let parent_dir_lit = ".."
2224+ let current_dir_lit = "."
22202225end
22212226module Ounit_array_tests
22222227= struct
@@ -9658,7 +9663,7 @@ val path_as_directory : string -> string
96589663 just treat it as a library instead
96599664 *)
96609665
9661- val node_relative_path : t -> [`File of string] -> string
9666+ val node_relative_path : bool -> t -> [`File of string] -> string
96629667
96639668val chop_extension : ?loc:string -> string -> string
96649669
@@ -9867,12 +9872,15 @@ let relative_path file_or_dir_1 file_or_dir_2 =
98679872
98689873 [file1] is currently compilation file
98699874 [file2] is the dependency
9875+
9876+ TODO: this is a hackish function: FIXME
98709877*)
9871- let node_relative_path (file1 : t)
9878+ let node_relative_path node_modules_shorten (file1 : t)
98729879 (`File file2 as dep_file : [`File of string]) =
98739880 let v = Ext_string.find file2 ~sub:Literals.node_modules in
98749881 let len = String.length file2 in
9875- if v >= 0 then
9882+ if node_modules_shorten && v >= 0 then
9883+
98769884 let rec skip i =
98779885 if i >= len then
98789886 Ext_pervasives.failwithf ~loc:__LOC__ "invalid path: %s" file2
@@ -9958,34 +9966,64 @@ let combine p1 p2 =
99589966 split_aux "//ghosg//ghsogh/";;
99599967 - : string * string list = ("/", ["ghosg"; "ghsogh"])
99609968 ]}
9969+ Note that
9970+ {[
9971+ Filename.dirname "/a/" = "/"
9972+ Filename.dirname "/a/b/" = Filename.dirname "/a/b" = "/a"
9973+ ]}
9974+ Special case:
9975+ {[
9976+ basename "//" = "/"
9977+ basename "///" = "/"
9978+ ]}
9979+ {[
9980+ basename "" = "."
9981+ basename "" = "."
9982+ dirname "" = "."
9983+ dirname "" = "."
9984+ ]}
99619985*)
99629986let split_aux p =
99639987 let rec go p acc =
99649988 let dir = Filename.dirname p in
99659989 if dir = p then dir, acc
9966- else go dir (Filename.basename p :: acc)
9990+ else
9991+ let new_path = Filename.basename p in
9992+ if Ext_string.equal new_path Filename.dir_sep then
9993+ go dir acc
9994+ (* We could do more path simplification here
9995+ leave to [rel_normalized_absolute_path]
9996+ *)
9997+ else
9998+ go dir (new_path :: acc)
9999+
996710000 in go p []
996810001
10002+
10003+
996910004(**
997010005 TODO: optimization
997110006 if [from] and [to] resolve to the same path, a zero-length string is returned
997210007*)
997310008let rel_normalized_absolute_path from to_ =
997410009 let root1, paths1 = split_aux from in
997510010 let root2, paths2 = split_aux to_ in
9976- if root1 <> root2 then root2 else
10011+ if root1 <> root2 then root2
10012+ else
997710013 let rec go xss yss =
997810014 match xss, yss with
997910015 | x::xs, y::ys ->
9980- if x = y then go xs ys
10016+ if Ext_string.equal x y then go xs ys
998110017 else
998210018 let start =
9983- List.fold_left (fun acc _ -> acc // ".." ) ".." xs in
10019+ List.fold_left (fun acc _ -> acc // Ext_string.parent_dir_lit )
10020+ Ext_string.parent_dir_lit xs in
998410021 List.fold_left (fun acc v -> acc // v) start yss
9985- | [], [] -> ""
10022+ | [], [] -> Ext_string.empty
998610023 | [], y::ys -> List.fold_left (fun acc x -> acc // x) y ys
998710024 | x::xs, [] ->
9988- List.fold_left (fun acc _ -> acc // ".." ) ".." xs in
10025+ List.fold_left (fun acc _ -> acc // Ext_string.parent_dir_lit )
10026+ Ext_string.parent_dir_lit xs in
998910027 go paths1 paths2
999010028
999110029(*TODO: could be hgighly optimized later
@@ -10007,6 +10045,7 @@ let rel_normalized_absolute_path from to_ =
1000710045 normalize_absolute_path "/a";;
1000810046 ]}
1000910047*)
10048+ (** See tests in {!Ounit_path_tests} *)
1001010049let normalize_absolute_path x =
1001110050 let drop_if_exist xs =
1001210051 match xs with
@@ -10015,11 +10054,13 @@ let normalize_absolute_path x =
1001510054 let rec normalize_list acc paths =
1001610055 match paths with
1001710056 | [] -> acc
10018- | "." :: xs -> normalize_list acc xs
10019- | ".." :: xs ->
10020- normalize_list (drop_if_exist acc ) xs
1002110057 | x :: xs ->
10022- normalize_list (x::acc) xs
10058+ if Ext_string.equal x Ext_string.current_dir_lit then
10059+ normalize_list acc xs
10060+ else if Ext_string.equal x Ext_string.parent_dir_lit then
10061+ normalize_list (drop_if_exist acc ) xs
10062+ else
10063+ normalize_list (x::acc) xs
1002310064 in
1002410065 let root, paths = split_aux x in
1002510066 let rev_paths = normalize_list [] paths in
@@ -10048,13 +10089,13 @@ module Ounit_path_tests
1004810089= struct
1004910090#1 "ounit_path_tests.ml"
1005010091let ((>::),
10051- (>:::)) = OUnit.((>::),(>:::))
10092+ (>:::)) = OUnit.((>::),(>:::))
1005210093
1005310094
1005410095let normalize = Ext_filename.normalize_absolute_path
1005510096let (=~) x y =
1005610097 OUnit.assert_equal ~cmp:(fun x y -> Ext_string.equal x y ) x y
10057-
10098+
1005810099let suites =
1005910100 __FILE__
1006010101 >:::
@@ -10093,7 +10134,68 @@ let suites =
1009310134 end;
1009410135 __LOC__ >:: begin fun _ ->
1009510136 normalize "/./a/.////////j/k//../////..///././b/./c/d/././../" =~ "/a/b/c"
10096- end
10137+ end;
10138+
10139+ __LOC__ >:: begin fun _ ->
10140+ let aux a b result =
10141+
10142+ Ext_filename.rel_normalized_absolute_path
10143+ a b =~ result ;
10144+
10145+ Ext_filename.rel_normalized_absolute_path
10146+ (String.sub a 0 (String.length a - 1))
10147+ b =~ result ;
10148+
10149+ Ext_filename.rel_normalized_absolute_path
10150+ a
10151+ (String.sub b 0 (String.length b - 1)) =~ result
10152+ ;
10153+
10154+
10155+ Ext_filename.rel_normalized_absolute_path
10156+ (String.sub a 0 (String.length a - 1 ))
10157+ (String.sub b 0 (String.length b - 1))
10158+ =~ result
10159+ in
10160+ aux
10161+ "/a/b/c/"
10162+ "/a/b/c/d/" "d";
10163+ aux
10164+ "/a/b/c/"
10165+ "/a/b/c/d/e/f/" "d/e/f" ;
10166+ aux
10167+ "/a/b/c/d/"
10168+ "/a/b/c/" ".." ;
10169+ aux
10170+ "/a/b/c/d/"
10171+ "/a/b/" "../.." ;
10172+ aux
10173+ "/a/b/c/d/"
10174+ "/a/" "../../.." ;
10175+ aux
10176+ "/a/b/c/d/"
10177+ "//" "../../../.." ;
10178+
10179+
10180+ end;
10181+ (* This is still correct just not optimal depends
10182+ on user's perspective *)
10183+ __LOC__ >:: begin fun _ ->
10184+ Ext_filename.rel_normalized_absolute_path
10185+ "/a/b/c/d"
10186+ "/x/y" =~ "../../../../x/y"
10187+
10188+ end;
10189+
10190+ __LOC__ >:: begin fun _ ->
10191+ Ext_filename.rel_normalized_absolute_path
10192+ "/usr/local/lib/node_modules/"
10193+ "//" =~ "../../../..";
10194+ Ext_filename.rel_normalized_absolute_path
10195+ "/usr/local/lib/node_modules/"
10196+ "/" =~ "../../../.."
10197+ end;
10198+
1009710199 ]
1009810200
1009910201end
0 commit comments