Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file database_light_js.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270(* Yoann Padioleau
*
* Copyright (C) 2010 Facebook
*
* 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.
*)openCommonmoduleAst=Cst_jsmoduleE=Entity_codemoduleHC=Highlight_codemoduleT=Parser_jsmodulePI=Parse_infomoduleDb=Database_code(*****************************************************************************)(* Prelude *)(*****************************************************************************)(* We build the full database in multiple steps as some
* operations need the information computed globally by the
* previous step:
*
* - collect all definitions and their file
* - collect all uses, updating the count number of the
* corresponding entity (if it's used in a different file)
*
* Currently the analysis is just lexical-based (yes I know, I am
* ridiculous) so there is some ambiguity when we find a use.
* We don't know to which precise entity it corresponds to
* (to be precise would require to resolve module name).
*
*)(*****************************************************************************)(* Helpers *)(*****************************************************************************)lethcommon_methods=Common.hashset_of_list["construct";"getInstance";]letis_common_methods=Hashtbl.memhcommon_methodssletremove_quotes_if_presents=(* for JX the entity names are passed as strings when
* defining the entity (e.g. JX.Install('Typeahead'. ...)
* but use normally (e.g. var x = JX.Typeahead(...))
* so here we normalize.
*)matchswith|_whens=~"'\\(.*\\)'$"->Common.matched1s|_whens=~"\"\\(.*\\)\"$"->Common.matched1s|_->sletmk_entity~root~hcomplete_name_of_infoinfocateg=lets=Parse_info.str_of_infoinfoin(* when using frameworks like Javelin/JX, the defs are
* actually in strings, as in JX.install("MyClass", { ... });
*)lets=remove_quotes_if_presentsin(*pr2 (spf "mk_entity %s" s);*)letl=PI.line_of_infoinfoinletc=PI.col_of_infoinfoinletname=sinletfullname=tryHashtbl.findhcomplete_name_of_infoinfo+>sndwithNot_found->""in{Database_code.e_name=name;e_fullname=iffullname<>namethenfullnameelse"";e_file=PI.file_of_infoinfo+>Common.readable~root;e_pos={Common2.l=l;c};e_kind=Common2.some(Database_code.entity_kind_of_highlight_category_defcateg);(* filled in step 2 *)e_number_external_users=0;(* TODO *)e_good_examples_of_use=[];(* TODO *)e_properties=[];}(*****************************************************************************)(* Main entry point *)(*****************************************************************************)letcompute_database?(verbose=false)files_or_dirs=(* when we want to merge this database with the db of another language
* like PHP, the other database may use realpath for the path of the files
* so we want to behave the same.
*)letfiles_or_dirs=files_or_dirs+>List.mapCommon.fullpathinletroot=Common2.common_prefix_of_files_or_dirsfiles_or_dirsinpr2(spf"generating JS db_light with root = %s"root);letfiles=Lib_parsing_js.find_source_files_of_dir_or_filesfiles_or_dirsinletdirs=files+>List.mapFilename.dirname+>Common2.uniq_effin(* step1: collecting definitions *)let(hdefs:(string,Db.entity)Hashtbl.t)=Hashtbl.create1001in(* remember the position of the def so avoid some false positives
* when looking for uses.
*)let(hdefs_pos:(Ast.tok,bool)Hashtbl.t)=Hashtbl.create1001infiles+>List.iter(funfile->ifverbosethenpr2(spf"PHASE 1: %s"file);let((astopt,toks),_stat)=Parse_js.parsefileinletast=astopt|||[]inlethcomplete_name_of_info=Class_pre_es6.extract_complete_name_of_infoastinletprefs=Highlight_code.default_highlighter_preferencesinHighlight_js.visit_program~tag_hook:(funinfocateg->(* todo: use is_entity_def_category ? *)matchcategwith|HC.Entity(_kind,(HC.Def2_))->Hashtbl.addhdefs_posinfotrue;lete=mk_entity~root~hcomplete_name_of_infoinfocateginHashtbl.addhdefse.Db.e_namee;|_->())prefs(ast,toks););(* step2: collecting uses *)files+>List.iter(funfile->ifverbosethenpr2(spf"PHASE 2: %s"file);iffile=~".*external/"thenpr2(spf"skipping external file: %s"file)elsebeginlet((_ast,toks),_stat)=Parse_js.parsefileinlettoks=toks+>Common.exclude(function|T.TCommentSpace_->true|_->false)in(* Only consider function or method calls. Otherwise names such
* as 'x', or 'yylex' which are variables or internal functions
* are considered as having a huge count.
*
*)letrecaux_tokstoks=matchtokswith(* The order of the rules are important here. We are
* being less and less precise in the pattern so the
* precise pattern has to be first
*)|T.T_IDENTIFIER("JX",ii1)::T.T_PERIOD(_)::T.T_IDENTIFIER(s,_ii_last)::T.T_LPAREN(_)::xswhenPI.col_of_infoii1<>0->Hashtbl.find_allhdefss+>List.iter(funentity->(* todo: should check that method of appropriate class
* but class analysis is complicated in Javascript.
*)matchentity.Db.e_kindwith|E.Class->entity.Db.e_number_external_users<-entity.Db.e_number_external_users+1;|_->());aux_toksxs|T.T_PERIOD_::T.T_IDENTIFIER(s,_ii)::T.T_LPAREN(_)::xs->ifnot(is_common_methods)thenHashtbl.find_allhdefss+>List.iter(funentity->(* todo: should check that method of appropriate class
* but class analysis is complicated in Javascript
* I compensate at least a little this problem by
* calling adjust_method_external_users below.
*)(matchentity.Db.e_kindwith|E.Method->entity.Db.e_number_external_users<-entity.Db.e_number_external_users+1;|_->()));aux_toksxs|T.T_IDENTIFIER(s,ii)::T.T_LPAREN(_)::xs->(* could be the tokens for the def *)ifnot(Hashtbl.memhdefs_posii)thenbeginHashtbl.find_allhdefss+>List.iter(funentity->(* todo: should check that method of appropriate class
* but class analysis is complicated in Javascript
*)ifentity.Db.e_kind=E.Functionthenentity.Db.e_number_external_users<-entity.Db.e_number_external_users+1;);end;aux_toksxs|[]->()|_x::xs->aux_toksxsinaux_tokstoks;end);(* step3: adding cross reference information *)letentities_arr=Common.hash_to_listhdefs+>List.mapsnd+>Array.of_listinDb.adjust_method_or_field_external_users~verboseentities_arr;letdirs=dirs+>List.map(funs->Common.readable~roots)inletdirs=Db.alldirs_and_parent_dirs_of_relative_dirsdirsin{Db.root=root;dirs=dirs+>List.map(fund->d,0);(* TODO *)files=files+>List.map(funf->Common.readable~rootf,0);(* TODO *)entities=entities_arr;}