1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495(*********************************************************************************)(* Dunolint - A tool to lint and help manage files in dune projects *)(* Copyright (C) 2024-2025 Mathieu Barbin <mathieu.barbin@gmail.com> *)(* *)(* This file is part of Dunolint. *)(* *)(* Dunolint is free software; you can redistribute it and/or modify it *)(* under the terms of the GNU Lesser General Public License as published by *)(* the Free Software Foundation either version 3 of the License, or any later *)(* version, with the LGPL-3.0 Linking Exception. *)(* *)(* Dunolint is distributed in the hope that it will be useful, but WITHOUT *)(* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *)(* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *)(* and the file `NOTICE.md` at the root of this repository for more details. *)(* *)(* You should have received a copy of the GNU Lesser General Public License *)(* and the LGPL-3.0 Linking Exception along with this library. If not, see *)(* <http://www.gnu.org/licenses/> and <https://spdx.org>, respectively. *)(*********************************************************************************)typet=Relative_path.tletis_parent_segments=String.equal".."slethas_parent_segmentssegs=List.exists~f:is_parent_segmentsegsletcheck_escape_path_exn(t:t)=ifhas_parent_segments(Fpath.segs(t:>Fpath.t))theninvalid_arg(Printf.sprintf"'%s': relative path escapes upward past starting point"(Relative_path.to_stringt));;letchop_prefixt~prefix=ifRelative_path.equalprefixRelative_path.emptythenSometelse(matchRelative_path.chop_prefixt~prefixwith|None->None|Sometassome->check_escape_path_exnt;some);;letparentt=ifRelative_path.equaltRelative_path.emptythenNoneelse(matchRelative_path.parenttwith|None->(* This is the problematic case from upstream, as the function never
returns [None]. Pending upgrades and TBD. *)None[@coverageoff]|Sometassome->check_escape_path_exnt;some);;letancestors_autoloading_dirs~path=ifRelative_path.equalpathRelative_path.emptythen[]else(check_escape_path_exnpath;letsegs=Fpath.segs(Relative_path.rem_empty_segpath:>Fpath.t)inList.init(List.lengthsegs)~f:(funi->List.takesegsi|>List.map~f:Fsegment.v|>Relative_path.of_list|>Relative_path.to_dir_path));;letpaths_to_check_for_skip_predicates~path=ifRelative_path.equalpathRelative_path.emptythen[]else(check_escape_path_exnpath;letsegs=Fpath.segs(path:>Fpath.t)inletancestors=List.init(List.lengthsegs-1)~f:(funi->List.takesegs(i+1)|>List.map~f:Fsegment.v|>Relative_path.of_list|>Relative_path.to_dir_path)in(* For directories, the last ancestor is already the directory itself.
For files, we need to append the file path. *)ifList.memancestorspath~equal:Relative_path.equalthenancestorselseancestors@[path]);;