Liking cljdoc? Tell your friends :D

ifu

Clojars Project

Miette-style diagnostic rendering for Clojure/ClojureScript. Takes a map describing a source location and renders a coloured, annotated snippet to the terminal.

error: unexpected value
  --> config.edn:2:5
   │
 2 │ bar baz
   │     ^^^ expected keyword

Usage

Add ifu to your deps:

{:deps {io.github.socksy/ifu {:mvn/version "0.2.2"}}}

Then call render:

(require '[ifu.core :as ifu])

(println
  (ifu/render {:file    "config.edn"
               :source  "{:port \"abc\"}"
               :row     1
               :col     8
               :end-col 13
               :message "expected integer"
               :hint    "port must be a number"}))

Diagnostic map

KeyRequiredDescription
:fileyesFilename shown in the header
:sourceyesFull source text (used to extract lines)
:rowyes1-based start line
:colyes1-based start column
:end-colnoEnd column (exclusive). Defaults to one past :col
:end-rownoEnd line for multi-line spans. Defaults to :row
:messageyesError message shown in the header
:hintnoText shown after the pointer
:severityno:error, :warning, :info, or :note. Defaults to :error
:relatednoVector of additional span maps (:file, :source, :row, :col, :end-col, :message)

Severity levels

(ifu/render {:file "x.edn" :source "bad" :row 1 :col 1
             :message "hmm" :severity :warning})
;; warning: hmm
;;   --> x.edn:1:1

Each severity gets its own colour: error (red), warning (yellow), info (blue), note (green).

Multi-line spans

(ifu/render {:file "x.edn" :source "aaa\nbbb\nccc"
             :row 1 :col 1 :end-row 3 :end-col 4
             :message "spans three lines"})

Shows all lines in the range with the pointer on the last line.

Related diagnostics

Point to other locations that help explain the error:

(ifu/render {:file "a.edn" :source "foo bar" :row 1 :col 5 :end-col 8
             :message "type mismatch"
             :related [{:file "b.edn" :source "baz qux"
                        :row 1 :col 1 :end-col 4
                        :message "defined here"}]})

Validating EDN files

ifu/parse parses an EDN string with source positions and validates it. It returns the parsed data if valid, or throws an ex-info with rendered diagnostics if not.

It takes a validator function (fn [data] -> [{:in [:path] :message "..."}] | nil), so it works with any validation library.

With malli

Require ifu.malli (you need metosin/malli in your own deps):

(require '[ifu.core :as ifu]
         '[ifu.malli :as ifu-malli])

(ifu/parse "{:port \"abc\"}" "config.edn"
  (ifu-malli/validator [:map [:port :int]]))

With spec

Require ifu.spec:

(require '[ifu.core :as ifu]
         '[ifu.spec :as ifu-spec]
         '[clojure.spec.alpha :as s])

(s/def ::port int?)
(s/def ::config (s/keys :req-un [::port]))

(ifu/parse "{:port \"abc\"}" "config.edn"
  (ifu-spec/validator ::config))

Custom validator

Any function that returns a seq of {:in path :message msg} maps works:

(ifu/parse "{:port -1}" "config.edn"
  (fn [data]
    (when (neg? (:port data))
      [{:in [:port] :message "port must be positive"}])))

Running tests

bb test              # core tests only
clojure -M:test      # all tests (including malli/spec)

Can you improve this documentation?Edit on GitHub

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close