123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102(* Yoann Padioleau
*
* Copyright (C) 2019 r2c
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* version 2.1 as published by the Free Software Foundation, with the
* special exception on linking described in file license.txt.
*
* This library 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 file
* license.txt for more details.
*)openCommonmoduleJ=Json_type(*****************************************************************************)(* Prelude *)(*****************************************************************************)(* Resolving paths mentioned in imports (andreturning a canonical form).
*
* You can do:
* - import './xxx.js'
* - import '../xxx/yyy.js'
* - import 'xxx/yyy.js'
* - import 'xxx'
*
* and this leads to different files on the disk:
* - src/xxx.js
* - xxx/yyy.js
* - node_modules/xxx/yyy.js
* - node_modules/xxx/index.js
* - node_modules/xxx/api/dist.js
*
* By resolving paths we can have canonical names for imports
* and so reference the same module entity in codegraph even
* if the module is represented by different strings.
*
* reference:
* - TODO https://nodejs.org/api/modules.html
*)(*****************************************************************************)(* Helpers *)(*****************************************************************************)letmain_entry_of_package_jsonfilejson=matchjsonwith|J.Object(xs)->(try(matchList.assoc"main"xswith|J.Strings->s|_->raiseNot_found)withNot_found->failwith(spf"no main entry in %s"file))|_->failwith(spf"wrong package.json format for %s"file)(*****************************************************************************)(* Entry point *)(*****************************************************************************)letresolve_path~root~pwdstr=letcandidates=[Filename.concatroot(Filename.concatpwdstr);Filename.concatroot(Filename.concatpwd(spf"%s.js"str));(* less: should always look at package.json? or useful opti? *)Filename.concatroot(spf"node_modules/%s"str);Filename.concatroot(spf"node_modules/%s.js"str);Filename.concatroot(spf"node_modules/%s/index.js"str);]intryletfound=candidates|>List.find(funpath->Sys.file_existspath&¬(Sys.is_directorypath))inSome(Common.fullpathfound)withNot_found->(* look in package.json (of root/package or root/node_modules/package) *)letpackage_json_candidates=[Filename.concatroot(spf"%s/package.json"str);Filename.concatroot(spf"node_modules/%s/package.json"str);]in(tryletpackage_json=package_json_candidates|>List.findSys.file_existsinletjson=Json_io.load_jsonpackage_jsoninletmain_path=main_entry_of_package_jsonpackage_jsonjsoninletdir=Filename.dirnamepackage_jsoninletfile=Filename.concatdirmain_pathinletcandidates=[file;spf"%s.js"file]incandidates|>Common.find_opt(funpath->Sys.file_existspath&¬(Sys.is_directorypath))withNot_found->pr2(spf"could not find a package.json for %s"str);None)