|
| 1 | +xquery version "3.1"; |
| 2 | + |
| 3 | + |
| 4 | +(:~ |
| 5 | + : This module scans the database instance for library modules and |
| 6 | + : generates XQDoc for each one that is found. |
| 7 | + : This collection of XQDoc definitions is then used to render |
| 8 | + : the function documentation. |
| 9 | + :) |
| 10 | +module namespace generate="http://exist-db.org/apps/fundocs/generate"; |
| 11 | + |
| 12 | + |
| 13 | +import module namespace xmldb="http://exist-db.org/xquery/xmldb"; |
| 14 | +import module namespace inspect="http://exist-db.org/xquery/inspection" at "java:org.exist.xquery.functions.inspect.InspectionModule"; |
| 15 | +import module namespace config="http://exist-db.org/xquery/apps/config" at "config.xqm"; |
| 16 | +import module namespace dbutil="http://exist-db.org/xquery/dbutil" at "dbutil.xqm"; |
| 17 | + |
| 18 | + |
| 19 | +declare namespace xqdoc="http://www.xqdoc.org/1.0"; |
| 20 | + |
| 21 | + |
| 22 | +declare variable $generate:doc-collection := $config:app-root || "/data"; |
| 23 | + |
| 24 | + |
| 25 | +declare function generate:fundocs() { |
| 26 | + ( |
| 27 | + generate:load-mapped-modules(), |
| 28 | + generate:load-internal-modules(), |
| 29 | + generate:load-stored-modules() |
| 30 | + ) |
| 31 | + => filter(generate:has-definition#1) |
| 32 | + => for-each(generate:generate-and-store-xqdoc#1) |
| 33 | +}; |
| 34 | + |
| 35 | +declare %private function generate:load-mapped-modules() as array(*)* { |
| 36 | + for $path in util:mapped-modules() |
| 37 | + let $uri := xs:anyURI($path) |
| 38 | + return generate:safe-inspect($uri, inspect:inspect-module-uri#1) |
| 39 | +}; |
| 40 | + |
| 41 | +declare %private function generate:load-internal-modules() as array(*)* { |
| 42 | + for $path in util:registered-modules() |
| 43 | + let $uri := xs:anyURI($path) |
| 44 | + return generate:safe-inspect($uri, inspect:inspect-module-uri#1) |
| 45 | +}; |
| 46 | + |
| 47 | +declare %private function generate:load-stored-modules() as array(*)* { |
| 48 | + for $uri in dbutil:find-by-mimetype(xs:anyURI("/db"), "application/xquery") |
| 49 | + return generate:safe-inspect($uri, inspect:inspect-module#1) |
| 50 | +}; |
| 51 | + |
| 52 | +declare %private function generate:safe-inspect ($moduleUri as xs:anyURI, $inspect as function(xs:anyURI) as element(module)?) as array(*)? { |
| 53 | + try { |
| 54 | + [$moduleUri, $inspect($moduleUri)] |
| 55 | + } catch * { |
| 56 | + (: |
| 57 | + : Expected to fail if XQuery file is not a library module |
| 58 | + : Will also guard against malformed and missing modules |
| 59 | + :) |
| 60 | + util:log("WARN", ( |
| 61 | + "Could not compile function documentation for: ", |
| 62 | + $moduleUri, " (", $err:code, ")", $err:description |
| 63 | + )) |
| 64 | + } |
| 65 | +}; |
| 66 | + |
| 67 | +declare %private function generate:has-definition($module-info as array(*)) as xs:boolean { |
| 68 | + exists($module-info?2) |
| 69 | +}; |
| 70 | + |
| 71 | +declare %private function generate:generate-and-store-xqdoc ($module-info as array(*)) { |
| 72 | + let $filename := concat(util:hash($module-info?1, "md5"), ".xml"), |
| 73 | + $xqdoc := generate:module-to-xqdoc($module-info?2) |
| 74 | + return |
| 75 | + xmldb:store($generate:doc-collection, $filename, $xqdoc) |
| 76 | + => xs:anyURI() |
| 77 | + => sm:chmod("rw-rw-r--") |
| 78 | +}; |
| 79 | + |
| 80 | +declare %private function generate:module-to-xqdoc($module as element(module)) as element(xqdoc:xqdoc) { |
| 81 | + <xqdoc:xqdoc xmlns:xqdoc="http://www.xqdoc.org/1.0"> |
| 82 | + <xqdoc:control> |
| 83 | + <xqdoc:date>{current-dateTime()}</xqdoc:date> |
| 84 | + <xqdoc:location>{$module/@location/string()}</xqdoc:location> |
| 85 | + </xqdoc:control> |
| 86 | + <xqdoc:module type="library"> |
| 87 | + <xqdoc:uri>{$module/@uri/string()}</xqdoc:uri> |
| 88 | + <xqdoc:name>{$module/@prefix/string()}</xqdoc:name> |
| 89 | + <xqdoc:comment> |
| 90 | + <xqdoc:description>{$module/description/string()}</xqdoc:description> |
| 91 | + { |
| 92 | + if (empty($module/version)) then () |
| 93 | + else |
| 94 | + <xqdoc:version>{$module/version/string()}</xqdoc:version> |
| 95 | + } |
| 96 | + { |
| 97 | + if (empty($module/author)) then () |
| 98 | + else |
| 99 | + <xqdoc:author>{$module/author/string()}</xqdoc:author> |
| 100 | + } |
| 101 | + </xqdoc:comment> |
| 102 | + </xqdoc:module> |
| 103 | + <xqdoc:functions> |
| 104 | + { |
| 105 | + for $function in $module/function |
| 106 | + return generate:function-to-xqdoc($function) |
| 107 | + } |
| 108 | + </xqdoc:functions> |
| 109 | + </xqdoc:xqdoc> |
| 110 | +}; |
| 111 | + |
| 112 | +declare %private function generate:function-to-xqdoc($function as element(function)) as element(xqdoc:function) { |
| 113 | + <xqdoc:function> |
| 114 | + <xqdoc:name>{$function/@name/string()}</xqdoc:name> |
| 115 | + <xqdoc:signature>{generate:signature($function)}</xqdoc:signature> |
| 116 | + <xqdoc:comment> |
| 117 | + <xqdoc:description>{$function/description/string()}</xqdoc:description> |
| 118 | + { |
| 119 | + for $argument in $function/argument |
| 120 | + return |
| 121 | + <xqdoc:param>{ |
| 122 | + "$" || $argument/@var || generate:cardinality($argument/@cardinality) || |
| 123 | + " " || $argument/text() |
| 124 | + }</xqdoc:param> |
| 125 | + } |
| 126 | + <xqdoc:return> |
| 127 | + { |
| 128 | + $function/returns/@type/string() || generate:cardinality($function/returns/@cardinality) |
| 129 | + }{ |
| 130 | + if (empty($function/returns/text())) then () |
| 131 | + else " : " || $function/returns/text() |
| 132 | + } |
| 133 | + </xqdoc:return> |
| 134 | + { |
| 135 | + if (empty($function/deprecated)) then () |
| 136 | + else |
| 137 | + <xqdoc:deprecated>{$function/deprecated/string()}</xqdoc:deprecated> |
| 138 | + } |
| 139 | + </xqdoc:comment> |
| 140 | + </xqdoc:function> |
| 141 | +}; |
| 142 | + |
| 143 | +declare %private function generate:cardinality($cardinality as xs:string) as xs:string? { |
| 144 | + switch ($cardinality) |
| 145 | + case "zero or one" return "?" |
| 146 | + case "zero or more" return "*" |
| 147 | + case "one or more" return "+" |
| 148 | + default return () |
| 149 | +}; |
| 150 | + |
| 151 | +declare %private function generate:signature($function as element(function)) as xs:string { |
| 152 | + let $arguments := |
| 153 | + for $argument in $function/argument |
| 154 | + return |
| 155 | + "$" || $argument/@var || " as " || $argument/@type || generate:cardinality($argument/@cardinality) |
| 156 | + |
| 157 | + return |
| 158 | + $function/@name/string() || "(" || string-join($arguments, ", ") || ")" || |
| 159 | + " as " || $function/returns/@type || generate:cardinality($function/returns/@cardinality) |
| 160 | +}; |
0 commit comments