123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314(*
* Copyright (c) 2016, 2017 Thomas Refis <trefis@janestreet.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*)openTypesmoduleComment=Odoc_model.CommentopenOdoc_model.Namesletsource_of_codes=ifs=""then[]else[Source.Elt[inline@@Inline.Texts]]moduleReference=structopenOdoc_model.Pathsletrecrender_resolved:Reference.Resolved.t->string=funr->letopenReference.Resolvedinmatchrwith|`Identifierid->Identifier.nameid|`Alias(_,r)->render_resolved(r:>t)|`AliasModuleType(_,r)->render_resolved(r:>t)|`Module(r,s)->render_resolved(r:>t)^"."^ModuleName.to_strings|`Canonical(_,`Resolvedr)->render_resolved(r:>t)|`Canonical(p,_)->render_resolved(p:>t)|`Hiddenp->render_resolved(p:>t)|`ModuleType(r,s)->render_resolved(r:>t)^"."^ModuleTypeName.to_strings|`Type(r,s)->render_resolved(r:>t)^"."^TypeName.to_strings|`Constructor(r,s)->render_resolved(r:>t)^"."^ConstructorName.to_strings|`Field(r,s)->render_resolved(r:>t)^"."^FieldName.to_strings|`Extension(r,s)->render_resolved(r:>t)^"."^ExtensionName.to_strings|`Exception(r,s)->render_resolved(r:>t)^"."^ExceptionName.to_strings|`Value(r,s)->render_resolved(r:>t)^"."^ValueName.to_strings|`Class(r,s)->render_resolved(r:>t)^"."^ClassName.to_strings|`ClassType(r,s)->render_resolved(r:>t)^"."^ClassTypeName.to_strings|`Method(r,s)->(* CR trefis: do we really want to print anything more than [s] here? *)render_resolved(r:>t)^"."^MethodName.to_strings|`InstanceVariable(r,s)->(* CR trefis: the following makes no sense to me... *)render_resolved(r:>t)^"."^InstanceVariableName.to_strings|`Label(_,s)->LabelName.to_strings(* This is the entry point. stop_before is false on entry, true on recursive
call. *)letrecto_ir:?text:Inline.t->stop_before:bool->Reference.t->Inline.t=fun?text~stop_beforeref->letopenReferenceinmatchrefwith|`Root(s,_)->(matchtextwith|None->lets=source_of_codesin[inline@@Inline.Sources]|Somes->[inline@@Inline.InternalLink(InternalLink.Unresolveds)])|`Dot(parent,s)->unresolved?text(parent:>t)s|`Module(parent,s)->unresolved?text(parent:>t)(ModuleName.to_strings)|`ModuleType(parent,s)->unresolved?text(parent:>t)(ModuleTypeName.to_strings)|`Type(parent,s)->unresolved?text(parent:>t)(TypeName.to_strings)|`Constructor(parent,s)->unresolved?text(parent:>t)(ConstructorName.to_strings)|`Field(parent,s)->unresolved?text(parent:>t)(FieldName.to_strings)|`Extension(parent,s)->unresolved?text(parent:>t)(ExtensionName.to_strings)|`Exception(parent,s)->unresolved?text(parent:>t)(ExceptionName.to_strings)|`Value(parent,s)->unresolved?text(parent:>t)(ValueName.to_strings)|`Class(parent,s)->unresolved?text(parent:>t)(ClassName.to_strings)|`ClassType(parent,s)->unresolved?text(parent:>t)(ClassTypeName.to_strings)|`Method(parent,s)->unresolved?text(parent:>t)(MethodName.to_strings)|`InstanceVariable(parent,s)->unresolved?text(parent:>t)(InstanceVariableName.to_strings)|`Label(parent,s)->unresolved?text(parent:>t)(LabelName.to_strings)|`Resolvedr->((* IDENTIFIER MUST BE RENAMED TO DEFINITION. *)letid=Reference.Resolved.identifierrinlettxt=matchtextwith|None->[inline@@Inline.Source(source_of_code(render_resolvedr))]|Somes->sinmatchUrl.from_identifier~stop_beforeidwith|Okurl->[inline@@Inline.InternalLink(InternalLink.Resolved(url,txt))]|Error(Not_linkable_)->txt|Errorexn->(* FIXME: better error message *)Printf.eprintf"Id.href failed: %S\n%!"(Url.Error.to_stringexn);txt)andunresolved:?text:Inline.t->Reference.t->string->Inline.t=fun?textparentfield->matchtextwith|Somes->[inline@@InternalLink(InternalLink.Unresolveds)]|None->lettail=[inline@@Text("."^field)]inletcontent=to_ir~stop_before:trueparentincontent@tailendletleaf_inline_element:Comment.leaf_inline_element->Inline.one=function|`Space->inline@@Text" "|`Words->inline@@Texts|`Code_spans->inline@@Source(source_of_codes)|`Raw_markup(target,s)->inline@@Raw_markup(target,s)letrecnon_link_inline_element:Comment.non_link_inline_element->Inline.one=function|#Comment.leaf_inline_elementase->leaf_inline_elemente|`Styled(style,content)->inline@@Styled(style,non_link_inline_element_listcontent)andnon_link_inline_element_list:_->Inline.t=funelements->List.map(funelt->non_link_inline_elementelt.Odoc_model.Location_.value)elementsletlink_content=non_link_inline_element_listletrecinline_element:Comment.inline_element->Inline.t=function|#Comment.leaf_inline_elementase->[leaf_inline_elemente]|`Styled(style,content)->[inline@@Styled(style,inline_element_listcontent)]|`Reference(path,content)->(* TODO Rework that ugly function. *)(* TODO References should be set in code style, if they are to code
elements. *)letcontent=matchcontentwith|[]->None|_->Some(non_link_inline_element_listcontent)(* XXX Span *)inReference.to_ir?text:content~stop_before:falsepath|`Link(target,content)->letcontent=matchcontentwith|[]->[inline@@Texttarget]|_->non_link_inline_element_listcontentin[inline@@Link(target,content)]andinline_element_listelements=List.concat@@List.map(funelt->inline_elementelt.Odoc_model.Location_.value)elementsletmodule_referencesms=letmodule_reference(m:Comment.module_reference)=letreference=Reference.to_ir~stop_before:false(m.module_reference:>Odoc_model.Paths.Reference.t)andsynopsis=matchm.module_synopsiswith|Somesynopsis->[block~attr:["synopsis"]@@Inline(inline_element_listsynopsis);]|None->[]in{Description.attr=[];key=reference;definition=synopsis}inletitems=List.mapmodule_referencemsinblock~attr:["modules"]@@Descriptionitemsletrecnestable_block_element:Comment.nestable_block_element->Block.one=funcontent->matchcontentwith|`Paragraphp->paragraphp|`Code_blockcode->block@@Source(source_of_code(Odoc_model.Location_.valuecode))|`Verbatims->block@@Verbatims|`Modulesms->module_referencesms|`List(kind,items)->letkind=matchkindwith|`Unordered->Block.Unordered|`Ordered->Block.Orderedinletf=function|[{Odoc_model.Location_.value=`Paragraphcontent;_}]->[block@@Block.Inline(inline_element_listcontent)]|item->nestable_block_element_listiteminletitems=List.mapfitemsinblock@@Block.List(kind,items)andparagraph:Comment.paragraph->Block.one=function|[{value=`Raw_markup(target,s);_}]->block@@Block.Raw_markup(target,s)|p->block@@Block.Paragraph(inline_element_listp)andnestable_block_element_listelements=elements|>List.mapOdoc_model.Location_.value|>List.mapnestable_block_elementlettag:Comment.tag->Description.one=funt->letitem?value~tagdefinition=letsp=inline(Text" ")inlettag_name=inline~attr:["at-tag"](Texttag)inlettag_value=matchvaluewith|None->[]|Somet->[sp;inline~attr:["value"]t]inletkey=tag_name::tag_valuein{Description.attr=[tag];key;definition}inlettext_defs=[block(Block.Inline[inline@@Texts])]inmatchtwith|`Authors->item~tag:"author"(text_defs)|`Deprecatedcontent->item~tag:"deprecated"(nestable_block_element_listcontent)|`Param(name,content)->letvalue=Inline.Textnameinitem~tag:"parameter"~value(nestable_block_element_listcontent)|`Raise(name,content)->letvalue=Inline.Textnameinitem~tag:"raises"~value(nestable_block_element_listcontent)|`Returncontent->item~tag:"returns"(nestable_block_element_listcontent)|`See(kind,target,content)->letvalue=matchkindwith|`Url->Inline.Link(target,[inline@@Texttarget])|`File->Inline.Source(source_of_codetarget)|`Document->Inline.Texttargetinitem~tag:"see"~value(nestable_block_element_listcontent)|`Sinces->item~tag:"since"(text_defs)|`Before(version,content)->letvalue=Inline.Textversioninitem~tag:"before"~value(nestable_block_element_listcontent)|`Versions->item~tag:"version"(text_defs)letattached_block_element:Comment.attached_block_element->Block.t=function|#Comment.nestable_block_elementase->[nestable_block_elemente]|`Tagt->[block~attr:["at-tags"]@@Description[tagt]](* TODO collaesce tags *)letblock_element:Comment.block_element->Block.t=function|#Comment.attached_block_elementase->attached_block_elemente|`Heading(_,_,text)->(* We are not supposed to receive Heading in this context.
TODO: Remove heading in attached documentation in the model *)[block@@Paragraph(non_link_inline_element_listtext)]letheading_level_to_int=function|`Title->0|`Section->1|`Subsection->2|`Subsubsection->3|`Paragraph->4|`Subparagraph->5letheading(attrs,`Label(_,label),text)=letlabel=Odoc_model.Names.LabelName.to_stringlabelinlettitle=non_link_inline_element_listtextinletlevel=heading_level_to_intattrs.Comment.heading_levelinletlabel=SomelabelinItem.Heading{label;level;title}letitem_element:Comment.block_element->Item.tlist=function|#Comment.attached_block_elementase->[Item.Text(attached_block_elemente)]|`Headingh->[headingh](** The documentation of the expansion is used if there is no comment attached
to the declaration. *)letsynopsis~decl_doc~expansion_doc=let([],Somedocs|docs,_)=(decl_doc,expansion_doc)inmatchComment.synopsisdocswithSomep->[paragraphp]|None->[]letstandalonedocs=Utils.flatmap~f:item_element@@List.map(funx->x.Odoc_model.Location_.value)docsletto_ir(docs:Comment.docs)=Utils.flatmap~f:block_element@@List.map(funx->x.Odoc_model.Location_.value)docslethas_docdocs=docs<>[]