123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808(*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*)openFlow_astmoduleE=ExpressionmoduleI=Identifiertype'locbinding='loc*stringtype'locident='loc*string[@@derivingshow]type'locsource='loc*string[@@derivingshow]letrecfold_bindings_of_pattern=Pattern.(letpropertyfacc=Object.(function|Property(_,{Property.pattern=p;_})|RestElement(_,{RestElement.argument=p;comments=_})->fold_bindings_of_patternfaccp)inletelementfacc=Array.(function|Hole_->acc|Element(_,{Element.argument=p;default=_})|RestElement(_,{RestElement.argument=p;comments=_})->fold_bindings_of_patternfaccp)infunfacc->function|(_,Identifier{Identifier.name;_})->faccname|(_,Object{Object.properties;_})->List.fold_left(propertyf)accproperties|(_,Array{Array.elements;_})->List.fold_left(elementf)accelements(* This is for assignment and default param destructuring `[a.b=1]=c`, ignore these for now. *)|(_,Expression_)->acc)letfold_bindings_of_variable_declarationsfaccdeclarations=letopenStatement.VariableDeclarationinList.fold_left(funacc->function|(_,{Declarator.id=pattern;_})->lethas_anno=(* Only the toplevel annotation in a pattern is meaningful *)letopenPatterninmatchpatternwith|(_,Array{Array.annot=Type.Available_;_})|(_,Object{Object.annot=Type.Available_;_})|(_,Identifier{Identifier.annot=Type.Available_;_})->true|_->falseinfold_bindings_of_pattern(fhas_anno)accpattern)accdeclarationsletrecpattern_has_binding=letopenPatterninletproperty=letopenObjectinfunction|Property(_,{Property.pattern=p;_})|RestElement(_,{RestElement.argument=p;comments=_})->pattern_has_bindingpinletelement=letopenArrayinfunction|Hole_->false|Element(_,{Element.argument=p;default=_})|RestElement(_,{RestElement.argument=p;comments=_})->pattern_has_bindingpinfunction|(_,Identifier_)->true|(_,Object{Object.properties;_})->List.existspropertyproperties|(_,Array{Array.elements;_})->List.existselementelements|(_,Expression_)->falseletrecmatch_pattern_has_binding=letopenMatchPatterninletproperty=function|(_,ObjectPattern.Property.Valid{ObjectPattern.Property.pattern=p;_})->match_pattern_has_bindingp|(_,ObjectPattern.Property.InvalidShorthand_)->falseinletrest_has_binding=function|Some(_,{RestPattern.argument=Some_;comments=_})->true|_->falseinfunction|(_,WildcardPattern_)|(_,NumberPattern_)|(_,BigIntPattern_)|(_,StringPattern_)|(_,BooleanPattern_)|(_,NullPattern_)|(_,UnaryPattern_)|(_,IdentifierPattern_)|(_,MemberPattern_)->false|(_,BindingPattern_)->true|(_,ObjectPattern{ObjectPattern.properties;rest;comments=_})->rest_has_bindingrest||List.existspropertyproperties|(_,ArrayPattern{ArrayPattern.elements;rest;comments=_})->rest_has_bindingrest||List.exists(fun{ArrayPattern.Element.pattern;_}->match_pattern_has_bindingpattern)elements|(_,OrPattern{OrPattern.patterns;_})->List.existsmatch_pattern_has_bindingpatterns|(_,AsPattern_)->trueletstring_of_variable_kind=function|Variable.Var->"var"|Variable.Let->"let"|Variable.Const->"const"letpartition_directivesstatements=letopenStatementinletrechelperdirectives=function|((_,Expression{Expression.directive=Some_;_})asdirective)::rest->helper(directive::directives)rest|rest->(List.revdirectives,rest)inhelper[]statementslethoist_function_and_component_declarationsstmts=letopenStatementinlet(func_and_component_decs,other_stmts)=List.partition(function(* function f() {} / component F() {} *)|(_,(FunctionDeclaration{Function.id=Some_;_}|ComponentDeclaration_))(* export function f() {} / export component F() {} *)|(_,ExportNamedDeclaration{ExportNamedDeclaration.declaration=Some(_,(FunctionDeclaration{Function.id=Some_;_}|ComponentDeclaration_));_;})(* export default function f() {} / export default component F() {} *)|(_,ExportDefaultDeclaration{ExportDefaultDeclaration.declaration=ExportDefaultDeclaration.Declaration(_,(FunctionDeclaration{Function.id=Some_;_}|ComponentDeclaration_));_;})(* TODO(jmbrown): Hoist declared components *)(* declare function f(): void; *)|(_,DeclareFunction_)(* declare export function f(): void; *)|(_,DeclareExportDeclarationDeclareExportDeclaration.{declaration=Some(Function_);_})->true|_->false)stmtsinfunc_and_component_decs@other_stmtsletnegate_raw_litraw=letraw_len=String.lengthrawinifraw_len>0&&raw.[0]='-'thenString.subraw1(raw_len-1)else"-"^rawletnegate_number_literal(value,raw)=(~-.value,negate_raw_litraw)letnegate_bigint_literal(value,raw)=matchvaluewith|None->(None,raw)|Somevalue->(Some(Int64.negvalue),negate_raw_litraw)letis_number_literalnode=matchnodewith|Expression.NumberLiteral_|Expression.Unary{Expression.Unary.operator=Expression.Unary.Minus;argument=(_,Expression.NumberLiteral_);comments=_;}->true|_->falseletextract_number_literalnode=matchnodewith|Expression.NumberLiteral{NumberLiteral.value;raw;comments=_}->Some(value,raw)|Expression.Unary{Expression.Unary.operator=Expression.Unary.Minus;argument=(_,Expression.NumberLiteral{NumberLiteral.value;raw;_});comments=_;}->Some(negate_number_literal(value,raw))|_->Noneletis_bigint_literalnode=matchnodewith|Expression.BigIntLiteral_|Expression.Unary{Expression.Unary.operator=Expression.Unary.Minus;argument=(_,Expression.BigIntLiteral_);comments=_;}->true|_->falseletextract_bigint_literalnode=matchnodewith|Expression.BigIntLiteral{BigIntLiteral.value;raw;comments=_}->Some(value,raw)|Expression.Unary{Expression.Unary.operator=Expression.Unary.Minus;argument=(_,Expression.BigIntLiteral{BigIntLiteral.value;raw;comments=_});comments=_;}->Some(negate_bigint_literal(value,raw))|_->Noneletis_call_to_invariantcallee=matchcalleewith|(_,Expression.Identifier(_,{Identifier.name="invariant";_}))->true|_->falseletis_call_to_requirecallee=matchcalleewith|(_,Expression.Identifier(_,{Identifier.name="require";_}))->true|_->falseletis_call_to_is_arraycallee=matchcalleewith|(_,E.Member{E.Member._object=(_,E.Identifier(_,{I.name="Array";comments=_}));property=E.Member.PropertyIdentifier(_,{I.name="isArray";comments=_});comments=_;})->true|_->falseletis_call_to_object_dot_freezecallee=matchcalleewith|(_,E.Member{E.Member._object=(_,E.Identifier(_,{I.name="Object";comments=_}));property=E.Member.PropertyIdentifier(_,{I.name="freeze";comments=_});comments=_;})->true|_->falseletget_call_to_object_dot_freeze_argcalleetargsargs=match(targs,args)with|(None,(_args_loc,{E.ArgList.arguments=[E.Expression(obj_loc,E.Objecto)];comments=_}))whenis_call_to_object_dot_freezecallee->Some(obj_loc,o)|_->Noneletis_call_to_object_static_methodcallee=matchcalleewith|(_,E.Member{E.Member._object=(_,E.Identifier(_,{I.name="Object";comments=_}));property=E.Member.PropertyIdentifier_;comments=_;})->true|_->falseletis_module_dot_exportscallee=matchcalleewith|(_,E.Member{E.Member._object=(_,E.Identifier(_,{I.name="module";comments=_}));property=E.Member.PropertyIdentifier(_,{I.name="exports";comments=_});comments=_;})->true|_->falseletget_call_to_jest_module_mocking_fncalleearguments=match(callee,arguments)with|((_,E.Member{E.Member._object=(_,E.Identifier(jest_loc,{I.name="jest";comments=_}));property=E.Member.PropertyIdentifier(_,(* See https://jestjs.io/docs/jest-object#mock-modules *){I.name=("createMockFromModule"|"mock"|"unmock"|"deepUnmock"|"doMock"|"dontMock"|"setMock"|"requireActual"|"requireMock");comments=_;});_;}),(_,{E.ArgList.arguments=E.Expression(source_loc,(E.StringLiteral{StringLiteral.value=name;_}|E.TemplateLiteral{E.TemplateLiteral.quasis=[(_,{E.TemplateLiteral.Element.value={E.TemplateLiteral.Element.cooked=name;_};_;});];_;}))::_;comments=_;}))->Some(jest_loc,source_loc,name)|_->Noneletis_super_member_access=function|{E.Member._object=(_,E.Super_);_}->true|_->falseletacceptable_statement_in_declaration_context~in_declare_namespace=letopenStatementinfunction|Block_->Error"block"|Break_->Error"break"|ClassDeclaration_->Error"class declaration"|ComponentDeclaration_->Error"component declaration"|Continue_->Error"continue"|Debugger_->Error"debugger"|DoWhile_->Error"do while"|ExportDefaultDeclaration_->Error"export default"|ExportNamedDeclaration{ExportNamedDeclaration.export_kind=ExportValue;_}->Error"value export"|Expression_->Error"expression"|For_->Error"for"|ForIn_->Error"for in"|ForOf_->Error"for of"|FunctionDeclaration_->Error"function declaration"|If_->Error"if"|Labeled_->Error"labeled"|Match_->Error"match"|Return_->Error"return"|Switch_->Error"switch"|Throw_->Error"throw"|Try_->Error"try"|VariableDeclaration_->Error"variable declaration"|While_->Error"while"|With_->Error"with"|ImportDeclaration_->ifin_declare_namespacethenError"import declaration"elseOk()|DeclareModuleExports_->ifin_declare_namespacethenError"declare module.exports"elseOk()|DeclareClass_|DeclareComponent_|DeclareEnum_|DeclareExportDeclaration_|DeclareFunction_|DeclareInterface_|DeclareModule_|DeclareNamespace_|DeclareOpaqueType_|DeclareTypeAlias_|DeclareVariable_|Empty_|EnumDeclaration_|ExportNamedDeclaration{ExportNamedDeclaration.export_kind=ExportType;_}|InterfaceDeclaration_|OpaqueType_|TypeAlias_->Ok()letrecis_type_only_declaration_statement(_,stmt')=letopenStatementinletis_type_only_declaration_statement'=function|DeclareInterface_|DeclareOpaqueType_|DeclareTypeAlias_|Empty_|InterfaceDeclaration_|OpaqueType_|TypeAlias_->true|DeclareExportDeclarationDeclareExportDeclaration.{declaration=Some(NamedType_|NamedOpaqueType_|Interface_);_}->true|DeclareNamespace{DeclareNamespace.body=(_,{Block.body;_});_}->List.for_allis_type_only_declaration_statementbody|ExportNamedDeclaration{ExportNamedDeclaration.export_kind;_}->export_kind=ExportType|Block_|Break_|ClassDeclaration_|ComponentDeclaration_|Continue_|Debugger_|DoWhile_|EnumDeclaration_|ExportDefaultDeclaration_|Expression_|For_|ForIn_|ForOf_|FunctionDeclaration_|If_|Labeled_|Match_|Return_|Switch_|Throw_|Try_|VariableDeclaration_|While_|With_|ImportDeclaration_|DeclareClass_|DeclareComponent_|DeclareEnum_|DeclareExportDeclaration_|DeclareFunction_|DeclareModule_|DeclareModuleExports_|DeclareVariable_->falseinis_type_only_declaration_statement'stmt'letloc_of_statement=fstletloc_of_expression=fstletloc_of_pattern=fstletloc_of_ident=fstletname_of_ident(_,{Identifier.name;comments=_})=nameletsource_of_ident(loc,{Identifier.name;comments=_})=(loc,name)letident_of_source?comments(loc,name)=(loc,{Identifier.name;comments})letmk_comments?(leading=[])?(trailing=[])a={Syntax.leading;trailing;internal=a}letmk_comments_opt?(leading=[])?(trailing=[])()=match(leading,trailing)with|([],[])->None|(_,_)->Some(mk_comments~leading~trailing())letmk_comments_with_internal_opt?(leading=[])?(trailing=[])~internal()=match(leading,trailing,internal)with|([],[],[])->None|_->Some(mk_comments~leading~trailinginternal)letmerge_comments~inner~outer=letopenSyntaxinmatch(inner,outer)with|(None,c)|(c,None)->c|(Someinner,Someouter)->mk_comments_opt~leading:(outer.leading@inner.leading)~trailing:(inner.trailing@outer.trailing)()letmerge_comments_with_internal~inner~outer=match(inner,outer)with|(inner,None)->inner|(None,Some{Syntax.leading;trailing;_})->mk_comments_with_internal_opt~leading~trailing~internal:[]()|(Some{Syntax.leading=inner_leading;trailing=inner_trailing;internal},Some{Syntax.leading=outer_leading;trailing=outer_trailing;_})->mk_comments_with_internal_opt~leading:(outer_leading@inner_leading)~trailing:(inner_trailing@outer_trailing)~internal()letsplit_commentscomments=matchcommentswith|None->(None,None)|Some{Syntax.leading;trailing;_}->(mk_comments_opt~leading(),mk_comments_opt~trailing())letstring_of_assignment_operatorop=letopenE.Assignmentinmatchopwith|PlusAssign->"+="|MinusAssign->"-="|MultAssign->"*="|ExpAssign->"**="|DivAssign->"/="|ModAssign->"%="|LShiftAssign->"<<="|RShiftAssign->">>="|RShift3Assign->">>>="|BitOrAssign->"|="|BitXorAssign->"^="|BitAndAssign->"&="|NullishAssign->"??="|AndAssign->"&&="|OrAssign->"||="letstring_of_binary_operatorop=letopenE.Binaryinmatchopwith|Equal->"=="|NotEqual->"!="|StrictEqual->"==="|StrictNotEqual->"!=="|LessThan->"<"|LessThanEqual->"<="|GreaterThan->">"|GreaterThanEqual->">="|LShift->"<<"|RShift->">>"|RShift3->">>>"|Plus->"+"|Minus->"-"|Mult->"*"|Exp->"**"|Div->"/"|Mod->"%"|BitOr->"|"|Xor->"^"|BitAnd->"&"|In->"in"|Instanceof->"instanceof"moduleExpressionSort=structtypet=|Array|ArrowFunction|Assignment|Binary|Call|Class|Conditional|Function|Identifier|Import|JSXElement|JSXFragment|Literal|Logical|Match|Member|MetaProperty|New|Object|OptionalCall|OptionalMember|Satisfies|Sequence|Super|TaggedTemplate|TemplateLiteral|This|TypeCast|Unary|Update|Yield[@@derivingshow]letto_string=function|Array->"array"|ArrowFunction->"arrow function"|Assignment->"assignment expression"|Binary->"binary expression"|Call->"call expression"|Class->"class"|Conditional->"conditional expression"|Function->"function"|Identifier->"identifier"|Import->"import expression"|JSXElement->"JSX element"|JSXFragment->"JSX fragment"|Literal->"literal"|Logical->"logical expression"|Match->"match expression"|Member->"member expression"|MetaProperty->"metaproperty expression"|New->"new expression"|Object->"object"|OptionalCall->"optional call expression"|OptionalMember->"optional member expression"|Satisfies->"satisfies expression"|Sequence->"sequence"|Super->"`super` reference"|TaggedTemplate->"tagged template expression"|TemplateLiteral->"template literal"|This->"`this` reference"|TypeCast->"type cast"|Unary->"unary expression"|Update->"update expression"|Yield->"yield expression"endletloc_of_annotation_or_hint=letopenTypeinfunction|Missingloc|Available(_,(loc,_))->locletloc_of_return_annot=letopenFunction.ReturnAnnotinfunction|Missingloc|Available(_,(loc,_))|TypeGuard(loc,_)->loc(* Apply type [t] at the toplevel of expression [exp]. This is straightforward overall
* except for the case of Identifier and Member, where we push the type within the
* identifier and member property type position as well. This is to ensure that
* type-at-pos searcher will detect the updated type. *)letpush_toplevel_typetexp=letopenEinletpush_toplevel_identifierid=let((id_loc,_),id)=idin((id_loc,t),id)inletpush_to_membermem=matchmemwith|{Member.property=Member.PropertyIdentifierid;_}->{memwithMember.property=Member.PropertyIdentifier(push_toplevel_identifierid)}|p->pinlet((loc,_),e)=expinlete'=matchewith|Identifierid->Identifier(push_toplevel_identifierid)|Membermember->Member(push_to_membermember)|OptionalMember({OptionalMember.member;_}asomem)->OptionalMember{omemwithOptionalMember.member=push_to_membermember}|_->ein((loc,t),e')lethook_names=letis_capc=c=Char.uppercase_asciicinString.starts_with~prefix:"use"s&&(String.lengths=3||is_caps.[3])lethook_function{Function.id;_}=matchidwith|Some(loc,{I.name;_})whenhook_namename->Someloc|_->Nonelethook_call{E.Call.callee;_}=(* A.B.C.useFoo() is a hook, A().useFoo() is not *)letopenEinletrechook_calleetopexp=matchexpwith|(_,Identifier(_,{I.name;_}))->hook_namename||nottop|(_,Member{Member._object;property=Member.PropertyIdentifier(_,{I.name;_});_})->(hook_namename||nottop)&&hook_calleefalse_object|_->falseinhook_calleetruecallee(* Match *)letmatch_root_name="<match_root>"letmatch_root_identloc=(loc,{Identifier.name=match_root_name;comments=None})letexpression_of_match_member_pattern~visit_expressionpattern=letopenMatchPatterninletrecf(loc,{MemberPattern.base;property;comments})=let(_object,root_name)=matchbasewith|MemberPattern.BaseIdentifier((loc,_)asid)->((loc,Expression.Identifierid),id)|MemberPattern.BaseMembermem->fmeminletproperty=matchpropertywith|MemberPattern.PropertyIdentifierid->Expression.Member.PropertyIdentifierid|MemberPattern.PropertyString(loc,lit)->Expression.Member.PropertyExpression(loc,Expression.StringLiterallit)|MemberPattern.PropertyNumber(loc,lit)->Expression.Member.PropertyExpression(loc,Expression.NumberLiterallit)|MemberPattern.PropertyBigInt(loc,lit)->Expression.Member.PropertyExpression(loc,Expression.BigIntLiterallit)inletexp=(loc,Expression.Member{Expression.Member._object;property;comments})invisit_expressionexp;(exp,root_name)infpattern(* Type Guards *)letget_inferred_type_guard_candidateparamsbodyreturn=match(body,return)with|(Function.BodyExpression_,Function.ReturnAnnot.Missing_)->beginmatchparamswith|(_,{Function.Params.params=[(_,{Function.Param.argument=(_,Pattern.Identifier{Pattern.Identifier.name=(loc,{Identifier.name;_});_});_;});];rest=None;_;})->Some(loc,name)|_->Noneend|_->Noneletrecunwrap_nonnull_lhs_expr:'loc'tloc1'tloc2.('loc,'tloc1)Expression.t->('loc,'tloc1)Expression.t*bool*(('loc,'tloc2)Expression.t->filter_nullish:('tloc1->'tloc2)->('loc,'tloc2)Expression.t)=funexpr->matchexprwith|(loc,Expression.Unary{Expression.Unary.operator=Expression.Unary.Nonnull;argument;comments})->let(argument,_,reconstruct)=unwrap_nonnull_lhs_exprargumentinletreconstructargument~filter_nullish=(filter_nullishloc,Expression.Unary{Expression.Unary.operator=Expression.Unary.Nonnull;argument=reconstruct~filter_nullishargument;comments;})in(argument,true,reconstruct)|_->(expr,false,(funargument~filter_nullish:_->argument))letunwrap_nonnull_lhs:'loc'tloc.('loc,'tloc)Pattern.t->('loc,'tloc)Pattern.t*bool=funpat->matchpatwith|(loc,Pattern.Expressionexpr)->let(expr,optional,_)=unwrap_nonnull_lhs_exprexprinbeginmatchexprwith|(e_loc,Expression.Identifiername)->assertoptional;((loc,Pattern.Identifier{Pattern.Identifier.name;optional=false;annot=Type.Missinge_loc}),true)|_->((loc,Pattern.Expressionexpr),optional)end|_->(pat,false)