├── .clj-kondo └── config.edn ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── API.md ├── CHANGELOG.md ├── LICENSE ├── README.md ├── bb.edn ├── bb └── tasks.clj ├── deps.edn ├── jvm └── deps.edn ├── scratch ├── API.md ├── deps.edn └── src │ └── scratch.clj ├── script └── changelog.clj ├── src └── quickdoc │ ├── api.cljc │ └── impl.clj ├── test-resources └── source.clj └── test ├── quickdoc ├── api_test.clj └── impl_test.clj └── runner.clj /.clj-kondo/config.edn: -------------------------------------------------------------------------------- 1 | {:cljc {:features [:clj]} 2 | :config-in-ns {quickdoc.api 3 | {:linters 4 | {:unused-binding {:exclude-destructured-keys-in-fn-args true}}}}} 5 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | 7 | clojure: 8 | 9 | strategy: 10 | matrix: 11 | os: [ubuntu-latest, macOS-latest, windows-latest] 12 | 13 | runs-on: ${{ matrix.os }} 14 | 15 | steps: 16 | - name: Checkout 17 | uses: actions/checkout@v3 18 | 19 | # It is important to install java before installing clojure tools which needs java 20 | # exclusions: babashka, clj-kondo and cljstyle 21 | - name: Prepare java 22 | uses: actions/setup-java@v3 23 | with: 24 | distribution: 'zulu' 25 | java-version: '8' 26 | 27 | - name: Install clojure tools 28 | uses: DeLaGuardo/setup-clojure@10.0 29 | with: 30 | bb: latest 31 | 32 | # Optional step: 33 | - name: Cache clojure dependencies 34 | uses: actions/cache@v3 35 | with: 36 | path: | 37 | ~/.m2/repository 38 | ~/.gitlibs 39 | ~/.deps.clj 40 | # List all files containing dependencies: 41 | key: cljdeps-${{ hashFiles('deps.edn') }} 42 | # key: cljdeps-${{ hashFiles('deps.edn', 'bb.edn') }} 43 | # key: cljdeps-${{ hashFiles('project.clj') }} 44 | # key: cljdeps-${{ hashFiles('build.boot') }} 45 | restore-keys: cljdeps- 46 | 47 | - name: Test Clojure 48 | run: bb test:jvm 49 | 50 | - name: Test bb 51 | run: bb test:bb 52 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .cache 2 | .cpcache 3 | .nrepl-port 4 | test/out 5 | -------------------------------------------------------------------------------- /API.md: -------------------------------------------------------------------------------- 1 | # Table of contents 2 | - [`quickdoc.api`](#quickdoc.api) - API namespace for quickdoc. 3 | - [`quickdoc`](#quickdoc.api/quickdoc) - Generate API docs. 4 | 5 | ----- 6 | # quickdoc.api 7 | 8 | 9 | API namespace for quickdoc. 10 | 11 | 12 | 13 | 14 | ## `quickdoc` 15 | ``` clojure 16 | 17 | (quickdoc opts) 18 | ``` 19 | Function. 20 | 21 | Generate API docs. Options: 22 | * `:github/repo` - a link like `https://github.com/borkdude/quickdoc` 23 | * `:git/branch` - branch name for source links, default to `"main"` 24 | * `:source-uri` - source link template. Supports `{row}`, `{end-row}`, `{col}`, `{end-col}`, `{filename}`, `{branch}`, `{path}`, `{repo}`. 25 | * `:outfile` - file where API docs are written, or falsey if you don't need a file. Defaults to `"API.md"` 26 | * `:source-paths` - sources that are scanned for vars. Defaults to `["src"]`. 27 | * `:toc` - generate table of contents. Defaults to `true`. 28 | * `:var-links` - generate links to vars within the same namespace. Defauls to `true`. 29 | * `:var-pattern` - detecting vars for linking, either `:backticks` (default) or `:wikilinks` (double brackets) 30 | * `:overrides` - overrides in the form `{namespace {:no-doc true var {:no-doc true :doc ...}}}` 31 | * `:filename-add-prefix` - add a prefix to the filename for source links. 32 | * `:filename-remove-prefix` - remove a prefix from the filename for source links. 33 | * `:filename-fn` - transformation of filename before it is rendered to markdown, e.g. for source links. 34 | 35 | Returns a map containing the generated markdown string under the key `:markdown`. 36 |
37 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | [Quickdoc](https://github.com/borkdude/quickdoc) 4 | 5 | Quick and minimal API doc generation for Clojure 6 | 7 | ## v0.2.5 (2025-05-01) 8 | 9 | - Fix [#32](https://github.com/borkdude/quickdoc/issues/32): fix anchor links to take into account var names that differ only by case 10 | 11 | ## v0.2.4 (2025-05-01) 12 | 13 | - Revert source link in var title and move back to `` 14 | - Specify clojure 1.11 as the minimal Clojure version in `deps.edn` 15 | - Fix macro information 16 | - Fix [#39](https://github.com/borkdude/quickdoc/issues/39): fix link when var is named multiple times in docstring 17 | - Upgrade clj-kondo to `2025.04.07` 18 | - Add explicit `org.babashka/cli` dependency 19 | 20 | ## v0.2.3 21 | 22 | - Add `:filename-add-prefix` and `:filename-remove-prefix` options so quickdoc can more easily be configured from EDN 23 | 24 | ## v0.2.2 25 | 26 | - Improved table of contents and source links ([@helins](https://github.com/helins)) 27 | - Support wiki syntax for var linking: `[[foo]]` ([@helins](https://github.com/helins)) 28 | - Upgrade clj-kondo to 2022.10.05 29 | 30 | ## v0.1.1 31 | 32 | - [#14](https://github.com/borkdude/quickdoc/issues/14): Skip vars defined in comments 33 | - [#18](https://github.com/borkdude/quickdoc/issues/18): Quickdoc ignores arglists metadata 34 | - [#17](https://github.com/borkdude/quickdoc/issues/17): Change toc var descriptions to be the first sentence of their doc 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Michiel Borkent 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Quickdoc 2 | 3 | ## API docs 4 | 5 | See [API.md](API.md). 6 | 7 | ## Rationale 8 | 9 | This library came out of the desire to have a fast and light weight tool that 10 | produces API docs from any Clojure code (`.clj`, `.cljs`, `.cljc`) without 11 | executing that code. This tool produces pure Markdown that you can read directly 12 | on Github and the output does not need CSS or JavaScript. 13 | 14 | Quickdoc's properties: 15 | 16 | - Based on [clj-kondo static analysis](https://github.com/clj-kondo/clj-kondo/tree/master/analysis) 17 | - Fast to run using [babashka](#babashka) (around 100ms for this project) 18 | 19 | ## Projects using quickdoc 20 | 21 | - [fs](https://github.com/babashka/fs/blob/master/API.md) 22 | - [process](https://github.com/babashka/process/blob/master/API.md) 23 | - [quickdoc](https://github.com/borkdude/quickdoc/blob/main/API.md) 24 | - [SCI](https://github.com/babashka/sci/blob/master/API.md) 25 | 26 | ## Babashka 27 | 28 | ### task 29 | 30 | Use as a babashka dependency and task: 31 | 32 | ``` clojure 33 | # bb.edn 34 | :tasks { 35 | ,,, 36 | quickdoc {:doc "Invoke quickdoc" 37 | :extra-deps {io.github.borkdude/quickdoc {:git/tag "v0.2.5", :git/sha "25784ca"}} 38 | :task (exec 'quickdoc.api/quickdoc) 39 | :exec-args {:git/branch "master" 40 | :github/repo "https://github.com/clj-kondo/clj-kondo" 41 | :source-paths ["src/clj_kondo/core.clj"]}} 42 | ,,, 43 | } 44 | ``` 45 | 46 | Now you can run `bb quickdoc` and your API docs will be generated in `API.md`. 47 | 48 | ## Clojure CLI 49 | 50 | Add the following alias to your global or project-local `deps.edn`: 51 | 52 | ``` clojure 53 | :aliases { 54 | ,,, 55 | :quickdoc 56 | {:deps {io.github.borkdude/quickdoc {:git/tag "v0.2.5" :git/sha "25784ca"} 57 | :main-opts ["-m" "babashka.cli.exec" "quickdoc.api" "quickdoc"]} 58 | ,,, 59 | } 60 | ``` 61 | 62 | Then you can call quickdoc using: 63 | 64 | ``` clojure 65 | clj -M:quickdoc :github/repo https://github.com/clj-kondo :git/branch master 66 | ``` 67 | 68 | You can add default arguments to `:exec-args` in the alias: 69 | 70 | ``` clojure 71 | :quickdoc 72 | {,,, 73 | :exec-args {:github/repo "https://github.com/clj-kondo" 74 | :git/branch "master"} 75 | ``` 76 | 77 | So the command line invocation simply becomes: 78 | 79 | ``` clojure 80 | clj -M:quickdoc 81 | ``` 82 | 83 | ## Clojure tool 84 | 85 | Quickdoc is also available as a [clj 86 | tool](https://clojure.org/reference/deps_and_cli#_tool_usage). Note that this 87 | way of invoking quickdoc is slower to start than with babashka. 88 | 89 | To install the latest version, run: 90 | 91 | ``` clojure 92 | clj -Ttools install-latest :lib io.github.borkdude/quickdoc :as quickdoc 93 | ``` 94 | 95 | To install a specific version, run: 96 | 97 | ``` 98 | clj -Ttools install io.github.borkdude/quickdoc '{:git/tag "v0.2.5" :git/sha "25784ca"}' :as quickdoc 99 | ``` 100 | 101 | 102 | Then invoke quickdoc using: 103 | 104 | ``` 105 | clj -Tquickdoc quickdoc '{:github/repo "https://github.com/borkdude/quickdoc"}' 106 | ``` 107 | 108 | ## Can it be improved to do ...? 109 | 110 | Probably yes! Let me know in [Github Discussions](https://github.com/borkdude/quickdoc/discussions) or create an [issue](https://github.com/borkdude/quickdoc/issues). 111 | 112 | ## License 113 | 114 | See [LICENSE](LICENSE). 115 | -------------------------------------------------------------------------------- /bb.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src" "bb"] 2 | 3 | :bbin/bin {quickdoc {:ns-default quickdoc.api}} 4 | 5 | :tasks {quickdoc {:requires ([quickdoc.api :as api]) 6 | :task (api/quickdoc {:git/branch "main" 7 | :github/repo "https://github.com/borkdude/quickdoc" 8 | :toc true})} 9 | test:bb {:extra-paths ["test"] 10 | :task (exec 'runner/run-tests)} 11 | test:jvm {:task (clojure "-Sdeps" '{:paths ["src" "test"]} "-X" 'runner/run-tests)}}} 12 | -------------------------------------------------------------------------------- /bb/tasks.clj: -------------------------------------------------------------------------------- 1 | (ns tasks 2 | (:require 3 | [clojure.string :as str] 4 | [quickdoc.api :refer [quickdoc]])) 5 | 6 | (defn test-root [_] 7 | (quickdoc {:source-paths ["../clj-kondo/src/clj_kondo/core.clj"] 8 | :outfile "test/clj-kondo.md" 9 | :github/repo "https://github.com/clj-kondo/clj-kondo" 10 | :git/branch "master" 11 | :filename-fn (fn [filename] 12 | (str/replace filename #"^\.\./clj-kondo/" ""))}) 13 | nil) 14 | -------------------------------------------------------------------------------- /deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src"] 2 | :deps {org.clojure/clojure {:mvn/version "1.11.1"} 3 | clj-kondo/clj-kondo {:mvn/version "2025.04.07"} 4 | org.babashka/cli {:mvn/version "0.8.65"}} 5 | :tools/usage {:ns-default quickdoc.api}} 6 | -------------------------------------------------------------------------------- /jvm/deps.edn: -------------------------------------------------------------------------------- 1 | {:deps {io.github.borkdude/quickdoc-sources {:local/root ".."}} 2 | :tools/usage {:ns-default quickdoc.api}} 3 | -------------------------------------------------------------------------------- /scratch/API.md: -------------------------------------------------------------------------------- 1 | # Table of contents 2 | - [`user`](#user) 3 | - [`+and`](#user/+and) - Logical AND of heavy-bools which evaluates to aheavy-bool
.
4 | - [`heavy-bool`](#user/heavy-bool)
5 |
6 | -----
7 | # user
8 |
9 |
10 |
11 |
12 |
13 |
14 | ## `+and`
15 | ``` clojure
16 |
17 | (+and & rest)
18 | ```
19 | Macro.
20 |
21 | Logical AND of heavy-bools which evaluates to a [`heavy-bool`](#user/heavy-bool).
22 | Expands to code which evaluates to the left-most [`heavy-bool`](#user/heavy-bool) value
23 | in the argument list, otherwise evaluates to the right-most
24 | value. If the argument list is empty, evaluates explicitly to
25 | `+true`
26 |
27 |
28 | ## `heavy-bool`
29 | ``` clojure
30 |
31 | (heavy-bool)
32 | ```
33 | Function.
34 |
35 |
--------------------------------------------------------------------------------
/scratch/deps.edn:
--------------------------------------------------------------------------------
1 | {:deps {io.github.borkdude/quickdoc {:local/root ".."}}}
2 |
--------------------------------------------------------------------------------
/scratch/src/scratch.clj:
--------------------------------------------------------------------------------
1 | (defn heavy-bool [])
2 |
3 | (defmacro +and
4 | "Logical AND of heavy-bools which evaluates to a `heavy-bool`.
5 | Expands to code which evaluates to the left-most `heavy-bool` value
6 | in the argument list, otherwise evaluates to the right-most
7 | value. If the argument list is empty, evaluates explicitly to
8 | `+true`"
9 | [& rest]
10 | (case (count rest)
11 | (0) true
12 | (1) (first rest)
13 | (let [v (gensym)
14 | [head & tail] rest]
15 | `(let [~v ~head]
16 | (+if ~v
17 | (+and ~@tail)
18 | ~v)))))
19 |
--------------------------------------------------------------------------------
/script/changelog.clj:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bb
2 |
3 | (ns changelog
4 | (:require [clojure.string :as str]))
5 |
6 | (let [changelog (slurp "CHANGELOG.md")
7 | replaced (str/replace changelog
8 | #" #(\d+)"
9 | (fn [[_ issue after]]
10 | (format " [#%s](https://github.com/borkdude/quickdoc/issues/%s)%s"
11 | issue issue (str after))))
12 | replaced (str/replace replaced
13 | #"@([a-zA-Z0-9-_]+)([, \.)])"
14 | (fn [[_ name after]]
15 | (format "[@%s](https://github.com/%s)%s"
16 | name name after)))]
17 | (spit "CHANGELOG.md" replaced))
18 |
--------------------------------------------------------------------------------
/src/quickdoc/api.cljc:
--------------------------------------------------------------------------------
1 | (ns quickdoc.api
2 | "API namespace for quickdoc."
3 | (:require
4 | #?(:bb [babashka.pods :as pods]
5 | :clj [clj-kondo.core :as clj-kondo])
6 | [clojure.java.io :as io]
7 | [clojure.string :as str]
8 | [quickdoc.impl :as impl]))
9 |
10 | #?(:bb
11 | (or (try (requiring-resolve 'pod.borkdude.clj-kondo/run!)
12 | (catch Exception _ nil)) ;; pod is loaded via bb.edn
13 | (pods/load-pod 'clj-kondo/clj-kondo "2025.04.07")))
14 |
15 | #?(:bb
16 | (require '[pod.borkdude.clj-kondo :as clj-kondo]))
17 |
18 | (defn quickdoc
19 | "Generate API docs. Options:
20 | * `:github/repo` - a link like `https://github.com/borkdude/quickdoc`
21 | * `:git/branch` - branch name for source links, default to `\"main\"`
22 | * `:source-uri` - source link template. Supports `{row}`, `{end-row}`, `{col}`, `{end-col}`, `{filename}`, `{branch}`, `{path}`, `{repo}`.
23 | * `:outfile` - file where API docs are written, or falsey if you don't need a file. Defaults to `\"API.md\"`
24 | * `:source-paths` - sources that are scanned for vars. Defaults to `[\"src\"]`.
25 | * `:toc` - generate table of contents. Defaults to `true`.
26 | * `:var-links` - generate links to vars within the same namespace. Defauls to `true`.
27 | * `:var-pattern` - detecting vars for linking, either `:backticks` (default) or `:wikilinks` (double brackets)
28 | * `:overrides` - overrides in the form `{namespace {:no-doc true var {:no-doc true :doc ...}}}`
29 | * `:filename-add-prefix` - add a prefix to the filename for source links.
30 | * `:filename-remove-prefix` - remove a prefix from the filename for source links.
31 | * `:filename-fn` - transformation of filename before it is rendered to markdown, e.g. for source links.
32 |
33 | Returns a map containing the generated markdown string under the key `:markdown`."
34 | {:org.babashka/cli
35 | {:coerce {:outfile (fn [s]
36 | (if (or (= "false" s)
37 | (= "nil" s))
38 | false
39 | s))
40 | :toc :boolean
41 | :var-links :boolean}
42 | :collect {:source-paths []}}}
43 | [opts]
44 | (let [{:as opts
45 | :keys [outfile
46 | source-paths
47 | overrides]} (merge {:git/branch "main"
48 | :outfile "API.md"
49 | :source-paths ["src"]
50 | :toc true
51 | :var-links true
52 | :var-pattern :backticks}
53 | opts)
54 | opts (assoc opts :var-regex (case (:var-pattern opts)
55 | :backticks #"`(.*?)`"
56 | :wikilinks #"\[\[(.*?)\]\]"))
57 | ana (-> (clj-kondo/run! {:lint source-paths
58 | :config {:skip-comments true
59 | :output {:analysis
60 | {:arglists true
61 | :var-definitions {:meta [:no-doc
62 | :skip-wiki
63 | :arglists]}
64 | :namespace-definitions {:meta [:no-doc
65 | :skip-wiki]}}}}})
66 | :analysis)
67 | var-defs (:var-definitions ana)
68 | ns-defs (:namespace-definitions ana)
69 | ns-defs (group-by :name ns-defs)
70 | nss (group-by :ns var-defs)
71 | ns->vars (update-vals nss (comp set (partial map :name)))
72 | toc (with-out-str (impl/print-toc nss ns-defs opts overrides))
73 | docs (with-out-str
74 | (run! (fn [[ns-name vars]]
75 | (impl/print-namespace ns-defs ns->vars ns-name vars opts overrides))
76 | (sort-by first nss)))
77 | docs (str toc docs)]
78 | (when outfile
79 | (io/make-parents outfile)
80 | (spit outfile docs))
81 | {:markdown docs}))
82 |
--------------------------------------------------------------------------------
/src/quickdoc/impl.clj:
--------------------------------------------------------------------------------
1 | (ns quickdoc.impl
2 | {:no-doc true}
3 | (:require
4 | [clojure.edn :as edn]
5 | [clojure.pprint :as pprint]
6 | [clojure.string :as str]))
7 |
8 | (defn debug [& xs]
9 | (binding [*out* *err*]
10 | (apply println xs)))
11 |
12 | (defn- var-filter [var]
13 | (let [mvar (merge (:meta var) var)]
14 | (and (not (:no-doc mvar))
15 | (not (:skip-wiki mvar))
16 | (not (:private var))
17 | (not (= 'clojure.core/defrecord (or (:defined-by->lint-as var)
18 | (:defined-by var)))))))
19 |
20 | ;; Adapted from `hiccup.core/escape-html`
21 | (defn escape-html
22 | "Change special characters into HTML character entities."
23 | [text]
24 | (.. ^String text
25 | (replace "&" "&")
26 | (replace "<" "<")
27 | (replace ">" ">")
28 | (replace "\"" """)
29 | (replace "'" "'")))
30 |
31 | (defn mini-markdown [s]
32 | (str/replace s #"`(.*?)`"
33 | (fn [[_ s]]
34 | (format "%s
" (escape-html s)))))
35 |
36 | (defn var-summary
37 | "Returns the first sentence of the var's DOC'umentation, if any
38 |
39 | It collapses all continuous whitespaces to a single space."
40 | [{:keys [doc] :as _var}]
41 | (when-not (str/blank? doc)
42 | (let [norm (-> (str/replace doc #"\s+" " ")
43 | str/trim)
44 | sen (or (some->> (re-find #"(.*?\.)[\s]|(.*?\.)$" norm)
45 | rest
46 | (some identity))
47 | (str norm "."))]
48 | (mini-markdown sen))))
49 |
50 | (defn var-source [var {:keys [github/repo git/branch
51 | filename-remove-prefix
52 | filename-add-prefix
53 | source-uri
54 | filename-fn]
55 | :or {filename-fn identity
56 | source-uri "{repo}/blob/{branch}/{filename}#L{row}-L{end-row}"}}]
57 | (let [var-filename (:filename var)
58 | filename
59 | (cond
60 | (and filename-remove-prefix (str/starts-with? var-filename filename-remove-prefix))
61 | (str/replace-first var-filename filename-remove-prefix "")
62 | filename-add-prefix (str filename-add-prefix var-filename)
63 | :else var-filename)
64 | filename (filename-fn filename)]
65 | (->
66 | source-uri
67 | (str/replace "{repo}" (str repo))
68 | (str/replace "{branch}" branch)
69 | (str/replace "{filename}" filename)
70 | (str/replace "{row}" (str (:row var)))
71 | (str/replace "{col}" (str (:col var)))
72 | (str/replace "{end-row}" (str (:end-row var)))
73 | (str/replace "{end-col}" (str (:end-col var))))))
74 |
75 | (defn anchor-munge
76 | "Transforms an input string into a URL-safe fragment identifier."
77 | [s]
78 | (-> s
79 | str/lower-case
80 | #_(java.net.URLEncoder/encode)))
81 |
82 | (let [memo (atom {})]
83 | (defn anchor* [s]
84 | (let [s (anchor-munge s)
85 | v (swap! memo update s (fnil inc -1))
86 | c (get v s)]
87 | (if (zero? c)
88 | s
89 | (str s "-" c))))
90 | (def anchor (memoize anchor*)))
91 |
92 | (defn print-docstring [ns->vars current-ns docstring opts]
93 | (println
94 | (if-some [var-regex (:var-regex opts)]
95 | (reduce (fn [docstring [raw inner]]
96 | (cond
97 | ;; Looks qualified
98 | (str/includes? inner "/")
99 | (let [split (str/split inner #"/")]
100 | (if (and (= 2 (count split))
101 | (get-in ns->vars [(symbol (first split))
102 | (symbol (second split))]))
103 | (str/replace docstring raw (format "[`%s`](#%s)" inner inner))
104 | docstring))
105 | ;; Not qualified, maybe a namespace
106 | (contains? ns->vars (symbol inner))
107 | (str/replace docstring raw (format "[`%s`](#%s)" inner inner))
108 | ;; Not qualified, maybe a var in the current namespace
109 | (get-in ns->vars [current-ns (symbol inner)])
110 | (str/replace docstring raw (format "[`%s`](#%s)" inner (anchor (str current-ns "/" inner))))
111 | ;; Just regular markdown backticks
112 | :else
113 | docstring))
114 | docstring
115 | (distinct (re-seq var-regex docstring)))
116 | docstring)))
117 |
118 | (defn print-var [ns->vars ns-name var _source {:keys [collapse-vars] :as opts}]
119 | (println)
120 | (when (var-filter var)
121 | (when collapse-vars (println "" (:name var) "
"
124 | (when-let [summary (var-summary var)]
125 | (str " - " summary)))
126 | "" ns-name "
4
." (var-summary {:doc "1 `4`. 8"}))))
22 |
23 | (deftest var-source-test
24 | (is (= "https://github.com/babashka/process/blob/master/src/babashka/process.cljc#L158-L163"
25 | (var-source
26 | {:filename "src/babashka/process.cljc"
27 | :row 158
28 | :end-row 163}
29 | {:github/repo "https://github.com/babashka/process"
30 | :git/branch "master"})))
31 | (is (= "https://github.com/foo/blob/main/prefix/src/bar/baz.clj#L1-L10"
32 | (var-source
33 | {:filename "src/bar/baz.clj"
34 | :row 1
35 | :end-row 10}
36 | {:github/repo "https://github.com/foo"
37 | :git/branch "main"
38 | :filename-add-prefix "prefix/"})))
39 | (is (= "https://github.com/foo/blob/main/src/bar/baz.clj#L1-L10"
40 | (var-source
41 | {:filename "extra/src/bar/baz.clj"
42 | :row 1
43 | :end-row 10}
44 | {:github/repo "https://github.com/foo"
45 | :git/branch "main"
46 | :filename-remove-prefix "extra/"})))
47 | (is (= "https://github.com/foo/blob/main/src/bar/baz.clj#L1-L10"
48 | (var-source
49 | {:filename "SRC/BAR/BAZ.CLJ"
50 | :row 1
51 | :end-row 10}
52 | {:github/repo "https://github.com/foo"
53 | :git/branch "main"
54 | :filename-fn str/lower-case})))
55 | (is (= "http://example.com/main/src/bar/baz.clj;1,2-10,4"
56 | (var-source
57 | {:filename "src/bar/baz.clj"
58 | :row 1
59 | :col 2
60 | :end-row 10
61 | :end-col 4}
62 | {:source-uri "{repo}{branch}/{filename};{row},{col}-{end-row},{end-col}"
63 | :github/repo "http://example.com/"
64 | :git/branch "main"}))))
--------------------------------------------------------------------------------
/test/runner.clj:
--------------------------------------------------------------------------------
1 | (ns runner
2 | (:require
3 | [clojure.test]
4 | [quickdoc.api-test]
5 | [quickdoc.impl-test]))
6 |
7 | (defn run-tests [_]
8 | (let [{:keys [fail error]} (clojure.test/run-tests 'quickdoc.api-test
9 | 'quickdoc.impl-test)]
10 | (when (pos? (+ fail error))
11 | (System/exit 1))))
12 |
--------------------------------------------------------------------------------