Skip to content

Latest commit

 

History

History
467 lines (350 loc) · 17.3 KB

for-library-authors.adoc

File metadata and controls

467 lines (350 loc) · 17.3 KB

Cljdoc for Library Authors

Why Cljdoc?

Cljdoc offers a centralized hosted library of docs which are:

  • Easy to publish

  • Automatically stay up to date

  • Discoverable by users

  • Look good

The Bare Minimum

If you publish your library to Clojars, its docs should already be available (or available to build) on cljdoc.org.

Default handling:

Mechanics

When cljdoc is triggered to build your library’s documentation, it:

  1. Downloads your library’s release jar from Clojars

  2. Analyzes your library’s sources on git

  3. Analyzes your library’s jar to discover its public API.

After building your docs, they are available at cljdoc.org for online and offline browsing.

See also: System Overview.

Markup Formats

Cljdoc supports two markup formats:

Cljdoc Badge

Important

The following examples use metosin/malli. Replace with your library’s Clojars group-id/artifact-id (hint: not the GitHub org/repo name).

Include a cljdoc badge in your README. Here malli’s badge: cljdoc badge.

Expressed in Markdown:

[![cljdoc badge](https://cljdoc.org/badge/metosin/malli)](https://cljdoc.org/d/metosin/malli)

and AsciiDoc:

https://cljdoc.org/d/metosin/malli[image:https://cljdoc.org/badge/metosin/malli[cljdoc badge]]

Git Sources

Cljdoc starts with the release jar downloaded from Clojars. A jar is associated with its specific git revision of sources via the <scm> entry in the jar’s pom. This allows cljdoc to consult git hosted:

  • cljdoc config - options on how cljdoc should process your docs

  • articles - to include and present as part of your docs

  • sources files - to allows cljdoc to intelligently link back to articles, API source code, and your git repo

Tip
a valid pom <scm> also allows other services like Clojars to point back to your release’s sources.
Note
  • SCM stands for Source Control Management

  • pom is the Maven Project Object Model

An example <scm> entry from metosin/malli:

  <scm>
    <url>https://github.com/metosin/malli</url>
    <connection>scm:git:git://github.com/metosin/malli.git</connection>
    <developerConnection>scm:git:ssh://[email protected]/metosin/malli.git</developerConnection>
    <tag>0.8.4</tag>
  </scm>

Another from juxt/bidi:

  <scm>
    <url>https://github.com/juxt/bidi</url>
    <connection>scm:git:git://github.com/juxt/bidi.git</connection>
    <developerConnection>scm:git:ssh://[email protected]/juxt/bidi.git</developerConnection>
    <tag>d1bfcc9c4fe247b8ada19cd7ee25acd81dd93f26</tag>
  </scm>

Cljdoc will look at the <url> and the <tag>:

  • <url> points to your hosted git repo

  • <tag> is a valid pointer to the git commit of your release’s sources. It can be a git tag, or commit sha.

Here are some common ways folks set <scm> values:

Whatever method you choose, take care to ensure that your jar’s pom points back to the exact revision of its sources on git.

Configuration

When building your docs, cljdoc will look under the doc (else docs) directory for a cljdoc.edn file in your library’s git repo.

You can use this configuration file to tell cljdoc more about your documentation.

  • :cljdoc.doc/tree - Tells cljdoc what articles to present and in what hierarchy.
    By default, cljdoc will automatically infer articles.

  • :cljdoc/languages - Tells cljdoc which languages your API uses.
    By default, cljdoc will automatically detect languages based on the sources it finds in your jar.

  • :cljdoc/include-namespaces-from-dependencies - Tells cljdoc to amalgamate API docs from multiple modules.
    Rarely used, but very useful when your project is made up of modules.

As an example, a version of honeysql's cljdoc.edn

{:cljdoc.doc/tree
 [["Readme" {:file "README.md"}]
  ["Changes" {:file "CHANGELOG.md"}]
  ["Getting Started" {:file "doc/getting-started.md"}
   ["General Reference" {:file "doc/general-reference.md"}]
   ["SQL Clause Reference" {:file "doc/clause-reference.md"}]
   ["SQL Operator Reference" {:file "doc/operator-reference.md"}]
   ["SQL 'Special Syntax'" {:file "doc/special-syntax.md"}]
   ["PostgreSQL Support" {:file "doc/postgresql.md"}]
   ["Extending HoneySQL" {:file "doc/extending-honeysql.md"}]]
  ["Differences from 1.x" {:file "doc/differences-from-1-x.md"}]]}

Linking to docs on cljdoc

See also: badges.

API Documentation

Declaring your Public API

Cljdoc will document all namespaces and public vars it finds. To exclude namespaces and/or vars from API documentation, annotate them with :no-doc metadata:

(defn ^:no-doc hidden "Won't see me on cljdoc.org!" [x])
(ns ^:no-doc namespace.hidden
  "This ns shouldn't show in the docs.")
(ns namespace.hidden
  "This ns shouldn't show in the docs."
  {:no-doc true})

API Languages

Cljdoc will auto-detect which languages your library supports based on the types of source files it finds. You can choose to override this auto-detection in your doc/cljdoc.edn file via the :cljdoc/languages option.

Example :cljdoc/languages value API Analysis run for

["clj"]

Clojure only

["cljs"]

ClojureScript only

["clj" "cljs"]

Both Clojure and ClojureScript

:auto-detect

Dependent upon source files found in your library, the default behavior.

Example usage:

{:cljdoc/languages ["clj"]}

Getting Dependencies Right

Cljdoc discovers your API via dynamic runtime analysis. It will try to load all namespaces found in your jar. If a dependency is not found, the load, and therefore API analysis, will fail.

If you include namespaces that require additional/optional dependencies, make sure you declare them in your pom.xml.

If these dependencies are expected to be provided by, for example, some container or JVM, mark them with a scope of "provided" in our pom.xml. Provided dependencies are skipped at runtime, but inform cljdoc they are required for API analysis.

Tip
You can express provided in a project.clj, for example. The deps.edn file does not support scoping, you’ll have to express these directly in your pom.xml.

Docstrings

Docstrings are rendered as Markdown. Consider these recommendations when writing your docstrings:

  1. Backtick-Quote ` function arguments & special keywords to make them stand out more

  2. Link to other functions using [[wikilink]] syntax

  3. Include small examples using markdown fenced ```Clojure …​ ``` code blocks

  4. Use Markdown tables to describe complex options maps

  5. You can include images and links to articles, just be sure to use git repo root-relative links (links that start with a /):

    • ![my image](/dir1/dir2/image1.png)

    • [my article](/dir1/dir2/article.adoc)

Any HTML embedded within docstrings is escaped.

You can link to other namespaces and functions from your docstrings using the [[wikilink]] syntax.

Note that if you want to link to vars outside the current namespace you need to either fully qualify those vars or specify them relative to the current namespace. An example: if you want to link to compojure.core/GET from compojure.route you’ll need to provide the wiki in one of the two forms below:

[[compojure.core/GET]]
[[core/GET]]

Article Documentation

Libraries often include additional guides and tutorials in markup files. Cljdoc calls these articles.

For cljdoc to find your articles:

This allows cljdoc to retrieve article files at the revision/commit of the release.

Cljdoc hosted articles will have their links rewritten to link back to cljdoc. All links that work on GitHub should also work on cljdoc.

Auto-inferred Articles

If your git repository does not contain a doc tree configuration, cljdoc will automatically include:

  • README.md else README.adoc - filename search is case insensitive

    • Title is Readme

  • CHANGELOG.md else CHANGELOG.adoc- filename search is case insensitive

    • Title is Changelog

  • Markup articles from your doc/ else docs/ folder

    • The title is read from the file’s first heading. There will be no nesting and articles will be ordered alphabetically by filename.

Tip
Use filenames prefixed with digits like 01-intro.md to define the order of articles.

Configuring Articles

If you need more control, use a doc/cljdoc.edn file to specify a tree of articles.

Assuming you have a directory doc/ in your repository as follows:

doc/
  getting-started.md
  installation.md
  configuration.md

You can explicitly add these articles to your cljdoc build by with the following doc/cljdoc.edn file:

{:cljdoc.doc/tree [["Readme" {:file "README.md"}]
                   ["Getting Started" {:file "doc/getting-started.md"}
                    ["Installation" {:file "doc/installation.md"}]]
                   ["Configuration" {:file "doc/configuration.md"}]]}

Your articles will be presented with the following hierarchy and titles:

├── Readme
├── Getting Started
│   └── Installation
└── Configuration
Important
The resulting URLs for those articles will be based on the title provided in the cljdoc.edn file and not on the filename or title within the article file.

See also: verifying articles

Article Slugs

Slugs for articles are currently based on the article title. Titles can be explicitly configured or inferred.

AsciiDoc Environment

Similar to env-github on GitHub, cljdoc will set an env-cljdoc attribute when rendering your AsciiDoc file. This allows you to hide or show sections of your document or set configuration parameters.

As an example, this AsciiDoctor snippet:

ifdef::env-cljdoc[]
THIS WILL BE SHOWN ON CLJDOC
endif::[]
ifndef::env-cljdoc[]
THIS WILL BE SHOWN EVERYWHERE ELSE
endif::[]

will render as so:

THIS WILL BE SHOWN EVERYWHERE ELSE

Testing & Verifying

Previewing Docs Locally

You can preview what your docs will look like before a Clojars release by running cljdoc locally.

Snapshot Builds

If you are already publishing SNAPSHOT releases to Clojars, this can also be a useful way to experiment/preview on cljdoc. A SNAPSHOT release will use master as the git revision as they usually have no tag in your repo nor sha/tag in a pom scm.

Article Verification Script

Sometimes people forget to update the paths after moving files around, we recommend you add the following to your CI setup:

curl -fsSL https://raw.githubusercontent.com/cljdoc/cljdoc/master/script/verify-cljdoc-edn | bash -s doc/cljdoc.edn

GitHub Action

We have a Cljdoc check action you can incorporate into your CI workflows.

Doc Build Triggers

  • Automatically

    • Every 60 seconds, cljdoc reaches out to clojars to discover new releases.

    • Every 10 minutes, it queues new releases to build

  • By request at cljdoc.org

    • If cljdoc has not already built a requested version of a library, you are given the option to build it from cljdoc.org.

  • By rebuild request at cljdoc.org

    • If your docs have already been built, you can request a rebuild via the barely visible rebuild hover link on the top right corner of your library docs page.

  • By REST request

Module Support

Some libraries are made up of submodules. Cljdoc provides some support amalgamating docs for these types of libraries.

APIs

To include API documentation for some or all of a projects submodules, specify their maven coordinates under :cljdoc/include-namespaces-from-dependencies:

{:cljdoc/include-namespaces-from-dependencies
 [metosin/reitit
  metosin/reitit-core
  metosin/reitit-ring
  metosin/reitit-spec
  metosin/reitit-schema
  metosin/reitit-swagger
  metosin/reitit-swagger-ui]}
Note
To be included, each dependency must also be specified as a maven dependency of the project itself (in the project’s deps.edn, project.clj, etc). The project’s resulting POM file will be used to load API information for the correct version.
Tip
Reitit is a great example reference for a project with submodules.
Warning
If analysis for a specified dependency has failed or hasn’t been run, its API documentation will not appear on cljdoc.

Articles

The following example shows how to provide a different doc tree for project metosin/reitit via cljdoc.edn:

{
  ;; used for metosin/reitit
  ;; when building docs for metosin/reitit this will be used as if
  ;; the doc/cljdoc.edn file contained just the value of this key
  metosin/reitit {:cljdoc.doc/tree [["Introduction" {:file "intro.md"}]]}

  ;; used for any project except metosin/reitit
  ;; could contain an overview about all modules and a pointer
  ;; to the overarching documentation for metosin/reitit
  :cljdoc.doc/tree [["Overview" {:file "modules/README.md"}]]
}
Note
We haven’t found an example usage of this in the wild yet.