|
1 | 1 | (ns clojure.java.doc.impl |
2 | 2 | (:require |
3 | | - [clojure.string :as str]) |
| 3 | + [clojure.string :as str] |
| 4 | + [clojure.tools.deps :as deps]) |
4 | 5 | (:import [com.vladsch.flexmark.html2md.converter FlexmarkHtmlConverter] |
5 | | - [org.jsoup Jsoup])) |
| 6 | + [org.jsoup Jsoup] |
| 7 | + [java.util.jar JarFile])) |
6 | 8 |
|
7 | 9 | (set! *warn-on-reflection* true) |
8 | 10 |
|
|
15 | 17 | {:current-version version-str |
16 | 18 | :minimum-version min-version}))))) |
17 | 19 |
|
18 | | -(defn- javadoc-url [^String classname] |
| 20 | +(defn- find-jar-coords [jar-url-str] |
| 21 | + (let [libs (:libs (deps/create-basis {:aliases []}))] |
| 22 | + (first (for [[lib-sym lib-info] libs |
| 23 | + path (:paths lib-info) |
| 24 | + :when (str/includes? jar-url-str path)] |
| 25 | + {:protocol :jar |
| 26 | + :lib lib-sym |
| 27 | + :version (select-keys lib-info [:mvn/version])})))) |
| 28 | + |
| 29 | +(defn- find-javadoc-coords [^Class c] |
| 30 | + (let [class-name (.getName c) |
| 31 | + url (.getResource c (str (.getSimpleName c) ".class"))] |
| 32 | + (merge |
| 33 | + {:class-name class-name} |
| 34 | + (case (.getProtocol url) |
| 35 | + "jar" (find-jar-coords (.toString url)) |
| 36 | + "jrt" {:protocol :jrt :lib 'java/java} |
| 37 | + "file" nil)))) |
| 38 | + |
| 39 | +(defn- download-javadoc-jar [{:keys [lib version]}] |
| 40 | + (let [javadoc-lib (symbol (str lib "$javadoc")) |
| 41 | + deps-map {:deps {javadoc-lib version} :mvn/repos (:mvn/repos (deps/root-deps))} |
| 42 | + result (deps/resolve-deps deps-map {})] |
| 43 | + (first (:paths (get result javadoc-lib))))) |
| 44 | + |
| 45 | +(defn- extract-html-from-jar [jar-path class-name] |
| 46 | + (with-open [jar (JarFile. ^String jar-path)] |
| 47 | + (if-let [entry (.getJarEntry jar (str (str/replace class-name "." "/") ".html"))] |
| 48 | + (slurp (.getInputStream jar entry)) |
| 49 | + (throw (ex-info (str "Could not find HTML for class in javadoc jar: " class-name) |
| 50 | + {:class-name class-name :jar-path jar-path}))))) |
| 51 | + |
| 52 | +(defn- javadoc-url [^String classname ^Class klass] |
19 | 53 | (let [java-version (System/getProperty "java.specification.version") |
20 | | - _ (check-java-version java-version) |
21 | | - classname (str/replace classname #"\$.*" "") |
22 | | - klass (Class/forName classname) |
23 | 54 | module-name (.getName (.getModule klass)) |
24 | 55 | url-path (.replace classname \. \/)] |
| 56 | + (check-java-version java-version) |
25 | 57 | (str "https://docs.oracle.com/en/java/javase/" java-version "/docs/api/" module-name "/" url-path ".html"))) |
26 | 58 |
|
| 59 | +(defn- get-javadoc-html [^String classname] |
| 60 | + (let [classname (str/replace classname #"\$.*" "") |
| 61 | + klass (Class/forName classname) |
| 62 | + coords (find-javadoc-coords klass)] |
| 63 | + (case (:protocol coords) |
| 64 | + :jar (extract-html-from-jar (download-javadoc-jar coords) classname) |
| 65 | + :jrt (slurp (javadoc-url classname klass)) |
| 66 | + (throw (ex-info (str "No javadoc available for local class: " classname) {:class-name classname}))))) |
| 67 | + |
27 | 68 | (defn- html-to-md [^String html] |
28 | 69 | (.convert ^FlexmarkHtmlConverter (.build (FlexmarkHtmlConverter/builder)) html)) |
29 | 70 |
|
|
130 | 171 | [s param-tags] |
131 | 172 | (let [[class-part method-part] (str/split s #"/\.?" 2) |
132 | 173 | class-name (resolve-class-name class-part) |
133 | | - doc (Jsoup/parse (slurp (javadoc-url class-name))) |
134 | | - class-desc-section (.selectFirst doc "section.class-description") |
135 | | - method-rows (.select doc "div.method-summary-table.col-second") |
| 174 | + html (get-javadoc-html class-name) |
| 175 | + doc (Jsoup/parse ^String html) |
| 176 | + class-desc-section (.selectFirst ^org.jsoup.nodes.Document doc "section.class-description") |
| 177 | + method-rows (.select ^org.jsoup.nodes.Document doc "div.method-summary-table.col-second") |
136 | 178 | all-methods (vec (for [^org.jsoup.nodes.Element method-div method-rows] |
137 | 179 | (let [desc-div ^org.jsoup.nodes.Element (.nextElementSibling method-div) |
138 | 180 | signature (.text (.select method-div "code")) |
|
141 | 183 | is-static? (and modifier-html (str/includes? modifier-html "static"))] |
142 | 184 | {:signature signature |
143 | 185 | :description (.text (.select desc-div ".block")) |
144 | | - :static? is-static? |
145 | | - :clojure-call (clojure-call-syntax class-part signature is-static?)}))) |
146 | | - class-html (.outerHtml class-desc-section) |
147 | | - result {:classname class-name |
| 186 | + :static? is-static? |
| 187 | + :clojure-call (clojure-call-syntax class-part signature is-static?)}))) |
| 188 | + class-html (.outerHtml ^org.jsoup.nodes.Element class-desc-section) result {:classname class-name |
148 | 189 | :class-description-html class-html |
149 | 190 | :class-description-md (html-to-md class-html) |
150 | 191 | :methods all-methods}] |
|
0 commit comments