diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 0000000..4869b6d --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,49 @@ +# Clojure CircleCI 2.0 configuration file +# +# Check https://circleci.com/docs/2.0/language-clojure/ for more details +# +version: 2 +jobs: + build: + branches: + only: + - /cljs-proper.*/ + + docker: + - image: circleci/clojure:tools-deps-1.10.0.442 + + working_directory: ~/repo + + steps: + - checkout + + - restore_cache: + keys: + - v1-dependencies-{{ checksum "codox/deps.edn" }} + - v1-dependencies- # fallback if cache not found + + - run: + name: Dump tool versions + command: clojure -e '(println (System/getProperty "java.runtime.name") (System/getProperty "java.runtime.version") "\nClojure" (clojure-version))' + working_directory: ~/repo/codox + + - run: + name: Dump classpath + command: clojure -Spath + working_directory: ~/repo/codox + + - run: + name: Run tests + command: clojure -Atest --reporter documentation --plugin kaocha.plugin/junit-xml --junit-xml-file target/test-results/unit/results.xml + working_directory: ~/repo/codox + + - save_cache: + paths: + - ~/.m2 + key: v1-dependencies-{{ checksum "codox/deps.edn" }} + + - store_test_results: + path: codox/target/test-results + + - store_artifacts: + path: codox/target/test-results diff --git a/.gitignore b/.gitignore index 872d9ad..f56393d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,11 @@ pom.xml pom.xml.asc *jar +.cpcache/ lib/ classes/ target/ +out/ checkouts/ .lein-* .nrepl-port diff --git a/README.md b/README.md index 6d76013..b804ca0 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,12 @@ ### Notes about this fork -- Focused on extracting structured data (EDN) from jars. +[![CircleCI](https://circleci.com/gh/cljdoc/codox/tree/cljs-proper.svg?style=svg)](https://circleci.com/gh/cljdoc/codox/tree/cljs-proper) + +- Focused on extracting structured data (EDN) from jars for cljdoc which makes use of work under codox subdir only. - Any writing-related (HTML etc.) dependencies have been removed. - Any remaining unused files are kept only to keep diff to mainline manageable. - Various tweaks have been done to align the results of Clojure and ClojureScript analysis. +- During dev, tests can be run via `clojure -A:test --watch` --- diff --git a/codox/deps.edn b/codox/deps.edn index 7bc1466..f58a189 100644 --- a/codox/deps.edn +++ b/codox/deps.edn @@ -1,4 +1,9 @@ -{:paths ["src" "resources" "test-sources"] +{:paths ["src"] :deps {org.clojure/clojure {:mvn/version "1.9.0"} org.clojure/tools.namespace {:mvn/version "0.2.11"} - org.clojure/clojurescript {:mvn/version "1.10.339"}}} + org.clojure/clojurescript {:mvn/version "1.10.520"}} + :aliases {:test + {:extra-paths ["test" "test-sources"] + :extra-deps {lambdaisland/kaocha {:mvn/version "0.0-413"} + lambdaisland/kaocha-junit-xml {:mvn/version "0.0-70"}} + :main-opts ["-m" "kaocha.runner"]}}} diff --git a/codox/src/codox/main.clj b/codox/src/codox/main.clj index 777da7f..7ebdc3a 100644 --- a/codox/src/codox/main.clj +++ b/codox/src/codox/main.clj @@ -4,9 +4,11 @@ (:require [clojure.string :as str] [clojure.pprint] [clojure.java.shell :as shell] + [clojure.java.io :as io] [codox.reader.clojure :as clj] [codox.reader.clojurescript :as cljs] - [codox.reader.plaintext :as text])) + [codox.reader.plaintext :as text] + [codox.utils :as util])) (defn- writer [{:keys [writer]}] (let [writer-sym (or writer 'codox.writer.html/write-docs) @@ -44,9 +46,11 @@ (update-in [:members] add-var-defaults defaults)))) (defn- add-ns-defaults [namespaces defaults] - (for [namespace namespaces] - (-> (merge defaults namespace) - (update-in [:publics] add-var-defaults defaults)))) + (if (seq defaults) + (for [namespace namespaces] + (-> (merge defaults namespace) + (update-in [:publics] add-var-defaults defaults))) + namespaces)) (defn- ns-matches? [{ns-name :name} pattern] (cond @@ -100,13 +104,15 @@ ([] (generate-docs {})) ([options] - (let [options (merge defaults options) - write-fn (writer options) - namespaces (read-namespaces options) - documents (read-documents options)] - (write-fn (assoc options - :namespaces namespaces - :documents documents))))) + (let [options (-> (merge defaults options) + (update :root-path util/canonical-path) + (update :souce-paths #(map util/canonical-path %))) + write-fn (writer options) + namespaces (read-namespaces options) + documents (read-documents options)] + (write-fn (assoc options + :namespaces namespaces + :documents documents))))) (defn -main "The main entry point for reading API information from files in a directory. diff --git a/codox/src/codox/reader/clojure.clj b/codox/src/codox/reader/clojure.clj index 119f2e8..648d9a8 100644 --- a/codox/src/codox/reader/clojure.clj +++ b/codox/src/codox/reader/clojure.clj @@ -5,7 +5,8 @@ (:use [codox.utils :only (assoc-some update-some correct-indent)]) (:require [clojure.java.io :as io] [clojure.tools.namespace.find :as ns] - [clojure.string :as str])) + [clojure.string :as str] + [codox.utils :as util])) (defn try-require [namespace] (try @@ -53,6 +54,14 @@ (if-let [p (:protocol (meta var))] (some #{p} vars))) +(defn- include-record-factory-as-defrecord [var-meta] + (let [n (str (:name var-meta))] + (if (re-find #"map->\p{Upper}" n) + (-> var-meta + (assoc :name (symbol (subs n 5))) + (dissoc :doc :arglists)) + var-meta))) + (defn- protocol-methods [protocol vars] (filter #(= protocol (:protocol (meta %))) vars)) @@ -68,26 +77,30 @@ (if (empty? delayed-errors) (:t ret)))) -(defn- read-var [vars var] - (-> (meta var) - (select-keys [:name :file :line :arglists :doc :dynamic - :added :deprecated :doc/format]) - (update-some :doc correct-indent) - (assoc-some :type (var-type var) - :type-sig (if (core-typed?) (core-typed-type var)) - :members (seq (map (partial read-var vars) - (protocol-methods var vars)))))) - -(defn- read-publics [namespace] +(defn- read-var [source-path vars var] + (let [normalize (partial util/normalize-to-source-path source-path)] + (-> (meta var) + (include-record-factory-as-defrecord) + (select-keys [:name :file :line :arglists :doc :dynamic + :added :deprecated :doc/format]) + (update-some :doc correct-indent) + (update-some :file normalize) + (assoc-some :type (var-type var) + :type-sig (if (core-typed?) (core-typed-type var)) + :members (seq (map (partial read-var source-path vars) + (protocol-methods var vars)))) + util/remove-empties))) + +(defn- read-publics [source-path namespace] (let [vars (sorted-public-vars namespace)] (->> vars (remove proxy?) (remove no-doc?) (remove (partial protocol-method? vars)) - (map (partial read-var vars)) + (map (partial read-var source-path vars)) (sort-by (comp str/lower-case :name))))) -(defn- read-ns [namespace exception-handler] +(defn- read-ns [namespace source-path exception-handler] (try-require 'clojure.core.typed.check) (when (core-typed?) (typecheck-namespace namespace)) @@ -95,8 +108,9 @@ (require namespace) (-> (find-ns namespace) (meta) + (dissoc :file :line :column :end-column :end-line) (assoc :name namespace) - (assoc :publics (read-publics namespace)) + (assoc :publics (read-publics source-path namespace)) (update-some :doc correct-indent) (list)) (catch Exception e @@ -148,8 +162,9 @@ ([paths {:keys [exception-handler] :or {exception-handler default-exception-handler}}] (mapcat (fn [path] - (->> (io/file path) - (find-namespaces) - (mapcat #(read-ns % exception-handler)) - (remove :no-doc))) + (let [path (util/canonical-path path)] + (->> (io/file path) + (find-namespaces) + (mapcat #(read-ns % path exception-handler)) + (remove :no-doc)))) paths))) diff --git a/codox/src/codox/reader/clojurescript.clj b/codox/src/codox/reader/clojurescript.clj index 1db1296..6ea8f94 100644 --- a/codox/src/codox/reader/clojurescript.clj +++ b/codox/src/codox/reader/clojurescript.clj @@ -6,7 +6,8 @@ [cljs.analyzer.api :as ana] [cljs.closure] [cljs.env] - [clojure.string :as str])) + [clojure.string :as str] + [codox.utils :as util])) (defn- cljs-filename? [filename] (or (.endsWith filename ".cljs") @@ -51,25 +52,39 @@ (multimethod? opts) :multimethod :else :var)) -(defn- read-var [file vars var] - (let [vt (var-type var)] +(defn- read-var [source-path file vars var] + (let [vt (var-type var) + normalize (partial util/normalize-to-source-path source-path)] (-> var - (select-keys [:name :line :arglists :doc :dynamic :added :deprecated :doc/format]) + (select-keys [:name :file :line :arglists :doc :dynamic :added :deprecated :doc/format]) (update-some :name (comp symbol name)) (update-some :arglists remove-quote) (update-some :doc correct-indent) - (assoc-some :file (if (= vt :macro) (:file var) (.getPath file)) - :type vt - :members (map (partial read-var file vars) - (protocol-methods var vars)))))) - -(defn- read-publics [state namespace file] - (let [vars (vals (ana/ns-publics state namespace))] + (update-some :file normalize) + (assoc-some :type vt + :members (->> (protocol-methods var vars) + (map (partial read-var source-path file vars)) + (map util/remove-empties) + (map #(dissoc % :file :line)) + (sort-by :name))) + util/remove-empties))) + +(defn- unreferenced-protocol-fn? + "Tools like potemkin import-vars can create a new function in one namespace point to an existing function within a protocol. + In these cases, we want to include the new function." + [source-path actual-file vars] + (let [meta-file (util/normalize-to-source-path source-path (:file vars)) + actual-file (util/normalize-to-source-path source-path (str actual-file))] + (and (:protocol vars) (= meta-file actual-file)))) + +(defn- read-publics [state namespace source-path file] + (let [vars (vals (ana/ns-publics state namespace)) + unreferenced-protocol? (partial unreferenced-protocol-fn? source-path file)] (->> vars - (remove :protocol) (remove :anonymous) + (remove unreferenced-protocol?) (remove no-doc?) - (map (partial read-var file vars)) + (map (partial read-var source-path file vars)) (sort-by (comp str/lower-case :name))))) (defn- analyze-file [file] @@ -80,9 +95,10 @@ (ana/analyze-file state file opts)) state)) -(defn- read-file [path file exception-handler] +(defn- read-file [source-path file exception-handler] (try - (let [source (io/file path file) + + (let [source (io/file source-path file) ns-name (:ns (ana/parse-ns source)) state (analyze-file source)] {ns-name @@ -90,7 +106,8 @@ (select-keys [:name :doc]) (update-some :doc correct-indent) (merge (-> ns-name meta (select-keys [:no-doc]))) - (assoc :publics (read-publics state ns-name file)))}) + (util/remove-empties) + (assoc :publics (read-publics state ns-name source-path file)))}) (catch Exception e (exception-handler e file)))) @@ -129,7 +146,7 @@ ([paths {:keys [exception-handler] :or {exception-handler default-exception-handler}}] (mapcat (fn [path] - (let [path (io/file path) + (let [path (io/file (util/canonical-path path)) file-reader #(read-file path % exception-handler)] (->> (find-files path) (map file-reader) diff --git a/codox/src/codox/utils.clj b/codox/src/codox/utils.clj index 9485eb9..df225ab 100644 --- a/codox/src/codox/utils.clj +++ b/codox/src/codox/utils.clj @@ -3,6 +3,12 @@ (:require [clojure.java.io :as io] [clojure.string :as str])) +(defn- empty-seq?[x] + (and (seqable? x) (not (seq x)))) + +(defn remove-empties[m] + (into {} (filter (comp not empty-seq? second) m))) + (defn assoc-some "Associates a key with a value in a map, if and only if the value is not nil." ([m k v] @@ -29,15 +35,21 @@ (map count) (find-minimum))) +(defn is-absolute?[file] + (and file (.isAbsolute (io/file file)))) + (defn- find-file-in-repo - "Given a classpath-relative file (as from the output of - `codox.reader/read-namespaces`), and a sequence of source directory paths, - returns a File object indicating the file from the repo root." + "Given a classpath-relative `file` (as from the output of + `codox.reader.clojure/read-namespaces`), and a sequence of `sources` + representing the classpaths, returns a File object `file` relative + to the repo root." [file sources] - (if (and file (not (.isAbsolute (io/file file)))) - (->> (map #(io/file % file) sources) - (filter #(.exists %)) - first))) + (->> (map #(io/file % file) sources) + (filter #(.exists %)) + first)) + +(defn canonical-path[file] + (.getCanonicalPath (io/file file))) (defn unindent "Unindent a block of text by a specific amount or the smallest common @@ -61,25 +73,58 @@ (defn uri-path [path] (str/replace (str path) java.io.File/separator "/")) -(defn- normalize-path [path root] - (let [root (str (uri-path root) "/") - path (uri-path (.getAbsolutePath (io/file path)))] - (if (.startsWith path root) - (.substring path (.length root)) - path))) +(defn normalize-path [path root] + (when path + (let [root (str (uri-path root) "/") + path (uri-path (.getAbsolutePath (io/file path)))] + (if (.startsWith path root) + (.substring path (.length root)) + path)))) + +(defn- dejarify + "Return the classpath relative file for `file`. + + Some manipulated metadata analysis :file elements (from techniques such as + potemkin import-vars) can point to a file inside the jar instead of the file + on file system when codox is invoked from cljdoc. This could likely be + handled by altering the classpath cljdoc uses, but we handle the case + here none-the-less. + + Oddly, the syntax of the file url is missing the jar: prefix so we add that + if needed before converting." + [file] + (if (re-find #"^(jar:)?file:/.*\.jar!/" file) + (->> (if (str/starts-with? file "jar:") file (str "jar:" file)) + java.net.URL. + .openConnection + (cast java.net.JarURLConnection) + .getEntryName) + file)) + +(defn normalize-to-source-path + [source-path file] + (when file + (let [file (dejarify file)] + (if (.exists (io/file file)) + (normalize-path file source-path) + file)))) (defn add-source-paths - "Accepts a sequence of namespaces (generated by - `codox.reader/read-namespaces`), the project root, and a list of - source directories. The sequence is returned with :path items added - in each public var's entry in the :publics map, which indicate the - path to the source file relative to the repo root." + "Accepts `ns-seq`, a sequence of namespaces (generated by + `codox.reader.clojure/read-namespaces` or + `codox.reader.clojurescript/read-namespaces`), the project directory + `root`, and a list of `sources` directories. + Returns the sequence of namespaces with `:path` added to `:publics` ns + var entries, which is just `:file` relative to the repo `root`." [ns-seq root sources] - (let [sources (map #(normalize-path % root) sources)] - (for [ns ns-seq] - (assoc ns - :publics (map #(assoc % :path (find-file-in-repo (:file %) sources)) - (:publics ns)))))) + (for [ns ns-seq] + (assoc ns + :publics (map #(let [f (:file %) + p (if (.exists (io/file f)) + (normalize-path f root) + (normalize-path (find-file-in-repo f sources) root))] + (assoc % :path (and p (io/file p)))) + (:publics ns))))) (defn summary "Return the summary of a docstring. diff --git a/codox/test-sources/codox_test/alter_meta_clj.clj b/codox/test-sources/codox_test/alter_meta_clj.clj new file mode 100644 index 0000000..9d61816 --- /dev/null +++ b/codox/test-sources/codox_test/alter_meta_clj.clj @@ -0,0 +1,21 @@ +(ns codox-test.alter-meta-clj + (:require [clojure.java.io :as io])) + +(defmacro alter-the-meta-data![ns name meta-changes] + (alter-meta! (ns-resolve ns name) merge meta-changes) + nil) + +(defmacro alter-the-meta-data-abs![ns name meta-changes] + `(alter-the-meta-data! ~ns ~name ~(update meta-changes :file #(str (.getAbsolutePath (io/file %)))))) + + +(defn resolve-fn-location[var-meta] + (if-let [p (:protocol var-meta)] + (-> (meta p) + (select-keys [:file :line]) + (merge var-meta)) + var-meta)) + +(defmacro copy-the-meta-data! [target-ns target-name source-sym] + (alter-meta! (ns-resolve target-ns target-name) merge (dissoc (resolve-fn-location (meta (resolve source-sym))) :name)) + nil) diff --git a/codox/test-sources/codox_test/alter_meta_cljs.clj b/codox/test-sources/codox_test/alter_meta_cljs.clj new file mode 100644 index 0000000..4d306e7 --- /dev/null +++ b/codox/test-sources/codox_test/alter_meta_cljs.clj @@ -0,0 +1,23 @@ +(ns codox-test.alter-meta-cljs + (:require [cljs.analyzer :as ana] + [cljs.analyzer.api :as ana-api] + [cljs.env :as env] + [clojure.java.io :as io])) + +(defmacro alter-the-meta-data![ns name meta-changes] + (swap! env/*compiler* + update-in [::ana/namespaces ns :defs name] + merge meta-changes) + nil) + +(defmacro alter-the-meta-data-abs![ns name meta-changes] + `(alter-the-meta-data! ~ns ~name ~(update meta-changes :file #(str (.getAbsolutePath (io/file %)))))) + +(defmacro copy-the-meta-data! [target-ns target-name src-sym] + (let [src-ns (symbol (namespace src-sym)) + src-name (symbol (name src-sym)) + src-meta (get-in @env/*compiler* [::ana/namespaces src-ns :defs src-name])] + (swap! env/*compiler* + update-in [::ana/namespaces target-ns :defs target-name] + merge (dissoc src-meta :name)) + nil)) diff --git a/codox/test-sources/codox_test/altered.cljc b/codox/test-sources/codox_test/altered.cljc new file mode 100644 index 0000000..4b63a69 --- /dev/null +++ b/codox/test-sources/codox_test/altered.cljc @@ -0,0 +1,32 @@ +;; +;; Note: this file is used in tests that rely on line numbers +;; +(ns codox-test.altered + (:require codox-test.protocols) + #?(:clj (:require [codox-test.alter-meta-clj :refer [alter-the-meta-data! alter-the-meta-data-abs! copy-the-meta-data!]]) + :cljs (:require-macros [codox-test.alter-meta-cljs :refer [alter-the-meta-data! alter-the-meta-data-abs! copy-the-meta-data!]]))) + + +(defmacro altered-macro-with-root-relative-file[] + '(println "it's good day to lie")) +(alter-the-meta-data! codox-test.altered altered-macro-with-root-relative-file + {:doc "added doc" + :file "test-sources/codox_test/multimethod.cljc" + :line 3}) + + + +(defn altered-fn-with-source-relative-file[] + '(prinln "I lie too")) +(alter-the-meta-data! codox-test.altered altered-fn-with-source-relative-file + {:file "codox_test/multimethod.cljc" + :line 14}) + + +(def altered-def-with-absolute-file 42) +(alter-the-meta-data-abs! codox-test.altered altered-def-with-absolute-file + {:file "test-sources/codox_test/record.cljc" + :line 7}) + +(def fn-pointing-to-protocol-fn codox-test.protocols/operation-one) +(copy-the-meta-data! codox-test.altered fn-pointing-to-protocol-fn codox-test.protocols/operation-one) diff --git a/codox/test-sources/codox_test/macro.cljc b/codox/test-sources/codox_test/macro.cljc index 0023108..59e236c 100644 --- a/codox/test-sources/codox_test/macro.cljc +++ b/codox/test-sources/codox_test/macro.cljc @@ -1,18 +1,26 @@ +;; +;; Note: this file is used in tests that rely on line numbers +;; (ns codox-test.macro) -(defmacro test + + + + + +(defmacro simple [a b] `(+ ~a ~b)) -(defmacro test2 + + +(defmacro varargs [a & xs] `(reduce + ~a ~(vec xs))) -;; https://github.com/jarohen/nomad/blob/5520c332c5c6d5eef4dcb0930c735900d63dea2a/src/nomad/config.clj#L98-L111 -(defn with-config-override* [{:keys [switches secret-keys override-switches] :as opts-override} f] - nil) -(doto (defmacro with-config-override [opts & body] - `(with-config-override* ~opts (fn [] ~@body))) - (alter-meta! assoc :arglists '([{:keys [switches secret-keys override-switches] :as opts-override} & body]))) +(defmacro macdoc + "Macro docs" + [a b c d] + `(+ ~a ~b ~c ~ d)) diff --git a/codox/test-sources/codox_test/multiarity.cljc b/codox/test-sources/codox_test/multiarity.cljc new file mode 100644 index 0000000..e8994e9 --- /dev/null +++ b/codox/test-sources/codox_test/multiarity.cljc @@ -0,0 +1,12 @@ +;; +;; Note: this file is used in tests that rely on line numbers +;; +(ns codox-test.multiarity) + + +(defn multiarity + "Multiarity comment" + ([] (println "no args")) + ([a] (println "1 arg")) + ([a b] (println "2 args")) + ([a b c d] (println "4 args"))) diff --git a/codox/test-sources/codox_test/multimethod.cljc b/codox/test-sources/codox_test/multimethod.cljc index 00b9d53..2d547f8 100644 --- a/codox/test-sources/codox_test/multimethod.cljc +++ b/codox/test-sources/codox_test/multimethod.cljc @@ -1,3 +1,6 @@ +;; +;; Note: this file is used in tests that rely on line numbers +;; (ns codox-test.multimethod) (defmulti start (fn [k opts] k)) diff --git a/codox/test-sources/codox_test/no_doc_ns.cljc b/codox/test-sources/codox_test/no_doc_ns.cljc new file mode 100644 index 0000000..7f57e92 --- /dev/null +++ b/codox/test-sources/codox_test/no_doc_ns.cljc @@ -0,0 +1,3 @@ +(ns ^:no-doc codox-test.no-doc-ns) + +(defn not-documented[a] a) diff --git a/codox/test-sources/codox_test/protocols.cljc b/codox/test-sources/codox_test/protocols.cljc new file mode 100644 index 0000000..e760b77 --- /dev/null +++ b/codox/test-sources/codox_test/protocols.cljc @@ -0,0 +1,15 @@ +;; +;; Note: this file is used in tests that rely on line numbers +;; +(ns codox-test.protocols) + +(defprotocol ProtoTest + "Protocol comment." + (operation-one [x] + "Operation 1 docs") + (multi-args [x] [x y] + "Multi args docs") + (alpha [a]) + (zoolander [y]) + (beta [z]) + (matilda [m])) diff --git a/codox/test-sources/codox_test/record.cljc b/codox/test-sources/codox_test/record.cljc index 480302d..626d682 100644 --- a/codox/test-sources/codox_test/record.cljc +++ b/codox/test-sources/codox_test/record.cljc @@ -1,3 +1,8 @@ +;; +;; Note: this file is used in tests that rely on line numbers +;; (ns codox-test.record) -(defrecord CodoxSystem [components]) +(defrecord DefRecordTest [components]) + +(def record-test (->DefRecordTest "moodog")) diff --git a/codox/test-sources/codox_test/spec.cljc b/codox/test-sources/codox_test/spec.cljc deleted file mode 100644 index c228c6e..0000000 --- a/codox/test-sources/codox_test/spec.cljc +++ /dev/null @@ -1,4 +0,0 @@ -(ns codox-test.spec - (:require [clojure.spec.test.alpha :as st])) - -(st/with-instrument-disabled (+ 1 2 3)) diff --git a/codox/test-sources/codox_test/spec_two.cljs b/codox/test-sources/codox_test/spec_two.cljs deleted file mode 100644 index a985d42..0000000 --- a/codox/test-sources/codox_test/spec_two.cljs +++ /dev/null @@ -1,4 +0,0 @@ -(ns codox-test.spec-two - (:require [clojure.spec.test.alpha :as st])) - -(st/with-instrument-disabled (+ 1 2 3)) diff --git a/codox/test-sources/codox_test/special_tags.cljc b/codox/test-sources/codox_test/special_tags.cljc new file mode 100644 index 0000000..f93fcd4 --- /dev/null +++ b/codox/test-sources/codox_test/special_tags.cljc @@ -0,0 +1,26 @@ +;; +;; Note: this file is used in tests that rely on line numbers +;; +(ns codox-test.special-tags) + + + + + +(defn ^{:deprecated "0.4.0"} deprecated-fn[x]) + + + + + +(defn ^:no-doc dont-doc-me "no docs please" [x] x) + + + + +(def ^:dynamic dynamic-def "dynamic def docs" 42) + + + + +(defn ^{:added "10.2.2"} added-fn[a b] (+ a b)) diff --git a/codox/test/codox/main_test.clj b/codox/test/codox/main_test.clj new file mode 100644 index 0000000..b3cfdd8 --- /dev/null +++ b/codox/test/codox/main_test.clj @@ -0,0 +1,156 @@ +(ns codox.main-test + (:require [clojure.test :as t] + [codox.main :as main])) + +(defn- analyze-sources[language] + (->> (main/generate-docs {:source-paths ["test-sources"] + :root-path "test-sources" + :language language + :writer 'clojure.core/identity}) + :namespaces)) + +(defn- check-paths[ns-data] + (update ns-data :publics + #(map (fn [v] + ;; cljdoc does not currently use the :path, but it might change its mind so we check it + (t/is (= (str (:path v)) (:file v)) "for our tests config, :file and :path should be the equivalent") + (dissoc v :path)) + %))) + +(defn- publics[r ns] + (some->> r + (filter #(= (:name %) ns)) + first + check-paths)) + +(defn- common-analysis-testing[analysis] + + (t/testing "altered-metadata" + (t/is (= {:name 'codox-test.altered + :publics [{:name 'altered-def-with-absolute-file + :type :var + :file "codox_test/record.cljc" + :line 7} + {:name 'altered-fn-with-source-relative-file + :arglists '([]) + :type :var + :file "codox_test/multimethod.cljc" + :line 14} + {:name 'altered-macro-with-root-relative-file + :arglists '([]) + :type :macro + :doc "added doc\n" + :file "codox_test/multimethod.cljc" + :line 3} + {:arglists '([x]), + :doc "Operation 1 docs\n", + :file "codox_test/protocols.cljc", + :line 6, + :name 'fn-pointing-to-protocol-fn, + :type :var}]} + (publics analysis 'codox-test.altered)))) + + (t/testing "macros" + (t/is (= {:name 'codox-test.macro + :publics [{:name 'macdoc + :arglists '([a b c d]) + :type :macro + :doc "Macro docs\n" + :file "codox_test/macro.cljc" + :line 23} + {:name 'simple + :arglists '([a b]) + :type :macro + :file "codox_test/macro.cljc" + :line 11} + {:name 'varargs + :arglists '([a & xs]) + :type :macro + :file "codox_test/macro.cljc" + :line 17}]} + (publics analysis 'codox-test.macro)))) + + (t/testing "multiarity" + (t/is (= {:name 'codox-test.multiarity + :publics [{:name 'multiarity + :arglists '([] [a] [a b] [a b c d]) + :type :var + :doc "Multiarity comment\n" + :file "codox_test/multiarity.cljc" + :line 7}]} + (publics analysis 'codox-test.multiarity)))) + + (t/testing "multimethods" + (t/is (= {:name 'codox-test.multimethod + :publics [{:name 'start + :type :multimethod + :file "codox_test/multimethod.cljc" + :line 6}]} + (publics analysis 'codox-test.multimethod)))) + + (t/testing "no-doc-ns" + (t/is (= [] (filter #(= (:name %) 'codox-test.no-doc-ns) analysis)))) + + (t/testing "protocols" + (t/is (= {:name 'codox-test.protocols + :publics [{:name 'ProtoTest + :type :protocol + :doc "Protocol comment.\n" + :members '({:arglists ([a]), :name alpha :type :var} + {:arglists ([z]), :name beta :type :var} + {:arglists ([m]), :name matilda :type :var} + {:arglists ([x] [x y]) + :doc "Multi args docs\n" + :name multi-args + :type :var} + {:arglists ([x]) + :doc "Operation 1 docs\n" + :name operation-one, + :type :var} + {:arglists ([y]), :name zoolander, :type :var}) + :file "codox_test/protocols.cljc" + :line 6}]} + (publics analysis 'codox-test.protocols)))) + + + (t/testing "records" + (t/is (= {:name 'codox-test.record + :publics [{:name 'DefRecordTest + :type :var + :file "codox_test/record.cljc" + :line 6} + {:name 'record-test + :type :var + :file "codox_test/record.cljc" + :line 8}]} + (publics analysis 'codox-test.record)))) + + (t/testing "special-tags" + (t/is (= {:name 'codox-test.special-tags + :publics [{:name 'added-fn + :arglists '([a b]) + :type :var + :added "10.2.2" + :file "codox_test/special_tags.cljc" + :line 26} + {:name 'deprecated-fn + :arglists '([x]) + :type :var + :deprecated "0.4.0" + :file "codox_test/special_tags.cljc" + :line 10} + {:name 'dynamic-def + :type :var + :doc "dynamic def docs\n" + :dynamic true + :file "codox_test/special_tags.cljc" + :line 21}]} + (publics analysis 'codox-test.special-tags))))) + +(t/deftest analyze-clojure-code-test + (let [a (analyze-sources :clojure)] + (common-analysis-testing a))) + +(t/deftest analyze-clojurecript-code-test + (let [a (analyze-sources :clojurescript)] + (common-analysis-testing a))) diff --git a/codox/tests.edn b/codox/tests.edn new file mode 100644 index 0000000..a9ac6fc --- /dev/null +++ b/codox/tests.edn @@ -0,0 +1,6 @@ +#kaocha/v1 +{:tests [{:id :unit + :source-paths ["src" "test-sources"] + :test-paths ["test"]}] + :reporter kaocha.report.progress/report + :plugins [:kaocha.plugin/notifier]}