All notable changes to this project will be documented in this file. This changelog follows keepachangelog.com.
[:table opts? & cols]): The
clj-format entry point now dispatches table specs through the new
clj-format.table facility, matching the Hiccup convention used
throughout the library. Writer semantics (nil/false, true, or a
Writer) are unchanged — there is no separate format-table or
print-table function.
:name), explicit [:col :name {...}] forms,
and raw column maps all accepted.:ascii, :unicode, :rounded, :heavy,
:double, :markdown, :org, :simple, :none, plus custom maps.:left, :right, :center), auto-sizing,
fixed widths, min/max constraints.:int, :money, :roman,
[:int {:group true}], [:if "Yes" "No"], [:money {:sign :always}],
or custom (fn [v] string).:ellipsis truncation, :clip, and
:wrap word-wrapping. Wrap mode expands one logical row into
multiple physical rows with other columns shown only on the first
line.:sum, :avg, :min, :max,
:count) or custom aggregate functions.[:col (fn [row] ...) {...}].clj-format.core/table-dsl exposes the generated DSL + argument
list for inspection and reuse.:figlet directive via clj-format.figlet — renders
FIGlet ASCII-art banners using
clj-figlet. Requiring the
namespace installs an expander into the new
clj-format.core/*dsl-preprocessor* hook; the directive is inert
for projects that don't opt in. clj-figlet is declared with
:scope "provided" so it is not pulled transitively — consumers
that want :figlet add [com.github.danlentz/clj-figlet "0.1.4"]
to their own dependencies.clj-format.core/*dsl-preprocessor* — a dynamic
var that extension namespaces can rebind to transform DSL forms
before compilation. Defaults to identity.~; support for :justify and :logical-block via
[:clause opts & body], allowing the DSL to preserve and compile
separator-local parameters and flags such as ~0,20:;.~<...~>
example that previously had to be shown as string passthrough only.Ran N tests summary, so an empty or short-circuited test run can no
longer pass CI silently.lein test was silently running only a subset of the test suite. The
bb_runner.clj file has a top-level (-main) call (so bb bb_runner.clj works as a script); when Leiningen's bultitude-based
discovery scanned the test directory it required the namespace, the
(-main) fired at load time, ran its own hardcoded subset of tests,
and called System/exit — which killed Leiningen's actual test run
before it could execute the remaining namespaces. The auto-invoke is
now guarded by (when (System/getProperty "babashka.version") ...) so
it only fires under Babashka. Bare lein test now finds and runs
every test namespace (including the new clj-format.table-test,
clj-format.figlet-test, and clj-format.naughty-nopes-test).bin/test-cljs) was silently running zero
tests: the -c (compile-only) invocation of cljs.main does not set
*main-cli-fn*, so cljs.nodejscli had nothing to call when node
launched the compiled bundle. clj-format.cljs-runner now sets
*main-cli-fn* at load time, so the CLJS suite actually executes under
both local runs and CI. The new CI Ran N tests assertion guards
against any future regression of this kind.~; behavior correctly
in justification forms, with regression coverage across JVM, CLJS, and
Babashka.:overflow :wrap now preserves interior whitespace on any
line that already fits the column width, so pre-formatted multi-line
content (ASCII art, nested tables, FIGlet banners) drops cleanly into
cells without having its load-bearing spacing collapsed..cljc parser/compiler/directive
namespaces plus a unified clj-format.core (.cljc) that delegates to
the host cl-format on both JVM and ClojureScript.bb.lein
and deps.edn workflows.test.check for DSL canonicalization,
compile idempotence, execution equivalence, and structured error reporting.~R, ~*, ~_) to use shared
data-driven metadata in clj-format.directives, simplifying parser and
compiler logic while preserving behavior.clj-format API now validates output targets and reports
invalid ones with structured ExceptionInfo.:scope "provided" in project.clj.~C flag combinations during parse/compile round-trips,
escaped :each separators containing ~, and added regression tests
for special-dispatch edge cases.Parser (clj-format.parser/parse-format): Recursive descent parser
that converts any cl-format string into the clj-format s-expression DSL.
Covers all 33 cl-format directives including compound/nested forms.
Compiler (clj-format.compiler/compile-format): Serializes the DSL
back into cl-format strings. Full round-trip fidelity:
(= s (compile-format (parse-format s))) for any valid format string.
Core API (clj-format.core/clj-format): Drop-in replacement for
clojure.pprint/cl-format. Accepts format strings (passthrough),
DSL vectors, or bare keywords. Supports all writer modes (nil, true,
false, Writer).
Shared directive config (clj-format.directives): Single source of
truth for all directive metadata (characters, parameter names, flag
mappings). Used by both parser and compiler.
DSL design: Hiccup-convention [:keyword opts? & body] with:
:width, :group, :sign, :sep, etc.)
instead of cl-format's :colon/:at flags:cardinal/:ordinal/
:roman; :if/:when/:choose):case option, flattened into the element:str for [:str]):sep on :each abstracts the ~^separator patternDocumentation:
doc/dsl.md — complete DSL referencedoc/examples.md — 50+ side-by-side examples from Practical Common
Lisp, CLtL2, ClojureDocs, and the CL HyperSpecREADME.md — quick start, DSL overview, real-world examplesCan you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |