Giter Club home page Giter Club logo

Clojars Project Financial Contributors on Open Collective CircleCI Build status cljdoc badge project chat twitter

A static analyzer and linter for Clojure code that sparks joy.

Thanks a lot for clj-kondo. It is like a companion for me. It has made clojure fun again.

@geraldodev on Clojurians Slack

Rationale

Clj-kondo performs static analysis on Clojure, ClojureScript and EDN, without the need of a running REPL. It informs you about potential errors while you are typing.

Features

Clj-kondo detects:

  • inline def expressions
  • redundant do and let wrappings
  • arity errors:
    • within the same namespace and across namespaces
    • of static Java method calls
    • of local let and letfn binding calls
    • of recursive calls (including recur)
    • conflicting arities in overloaded functions
  • unused private vars
  • private and deprecated var usage
  • required but unused namespaces
  • unsorted required namespaces
  • referred but unused vars
  • duplicate requires
  • unused function arguments and let bindings
  • marked as unused, but used arguments and let bindings (optional)
  • unused imports
  • redefined vars
  • unresolved symbols, vars and namespaces
  • misplaced docstrings
  • duplicate map keys and set elements
  • duplicates and quoting in case test constants
  • missing map keys
  • invalid number of forms in binding vectors
  • missing assertions in clojure.test/deftest
  • alias consistency
  • type checking
  • Datalog syntax checking
  • format string argument mismatches
  • shadowed vars
  • 2 argument usage of reduce (optional)

before your form hits the REPL.

It suggests several style guide recommendations, such as:

It has support for syntax of commonly used macros like clojure.core.async/alt!!, schema.core/defn and potemkin/import-vars.

It detects common errors in deps.edn and bb.edn

It provides analysis data so you build your own custom linters.

View all available linters here.

This linter is:

  • compatible with .clj, .cljs, .cljc and .edn files
  • build tool and editor agnostic
  • a static code analyzer
  • compiled to native code using GraalVM

Try clj-kondo at the interactive playground.

Watch the talk:

Clj-kondo at ClojuTRE 2019

Support ❤️

You can support this project via Github Sponsors, OpenCollective, Ko-fi or indirectly via Clojurists Together.

Top sponsors

Usage

Command line

Lint from stdin:

$ echo '(def x (def x 1))' | clj-kondo --lint -
<stdin>:1:8: warning: inline def

Lint a file:

$ echo '(def x (def x 1))' > /tmp/foo.clj
$ clj-kondo --lint /tmp/foo.clj
/tmp/foo.clj:1:8: warning: inline def

Lint a directory:

$ clj-kondo --lint src
src/clj_kondo/test.cljs:7:1: warning: redundant do
src/clj_kondo/calls.clj:291:3: error: Wrong number of args (1) passed to clj-kondo.calls/analyze-calls

Lint a project classpath:

$ clj-kondo --lint "$(lein classpath)"

Project setup

To detect lint errors across namespaces in your project, a cache is needed. To let clj-kondo know where to create one, make a .clj-kondo directory in the root of your project, meaning on the same level as your project.clj, deps.edn or build.boot. A cache will be created inside of it when you run clj-kondo. Before linting inside your editor, it is recommended to lint the entire classpath to teach clj-kondo about all the libraries you are using, including Clojure and/or ClojureScript itself:

$ clj-kondo --lint "<classpath>" --dependencies --parallel --copy-configs

The --dependencies flag indicates that clj-kondo is used to analyze sources to populate the cache. When enabled, clj-kondo will suppress warnings and skips over already linted .jar files for performance.

The --parallel option will use multiple threads to lint your sources, going through them faster.

The --copy-configs flag will search and copy configurations from dependencies into the .clj-kondo directory, while linting (see config.md).

Build tool specific ways to get a classpath:

  • lein classpath
  • boot with-cp -w -f -
  • clojure -Spath
  • npx shadow-cljs classpath

So for lein the entire command would be:

$ clj-kondo --lint "$(lein classpath)" --dependencies --parallel --copy-configs

Now you are ready to lint single files using editor integration. A simulation of what happens when you edit a file in your editor:

$ echo '(select-keys)' | clj-kondo --lang cljs --lint -
<stdin>:1:1: error: Wrong number of args (0) passed to cljs.core/select-keys

Since clj-kondo now knows about your version of ClojureScript via the cache, it detects that the number of arguments you passed to select-keys is invalid. Each time you edit a file, the cache is incrementally updated, so clj-kondo is informed about new functions you just wrote.

If you want to use a different directory to read and write the cache, use the --cache-dir option. To disable the cache even if you have a .clj-kondo directory, use --cache false.

Exit codes

Exit codes can be controlled by the --fail-level <level> option. The default fail level is warning which returns exit codes as follows:

  • 0: no errors or warnings were found
  • 2: one or more warnings were found
  • 3: one or more errors were found

If --fail-level error is supplied, warnings do not lead to a non-zero exit code:

  • 0: no errors were found
  • 0: one or more warnings were found
  • 3: one or more errors were found

All exit codes other than 0, 2 and 3 indicate an error because of a bug in clj-kondo or some other unexpected error beyond the control of clj-kondo.

Companies using clj-kondo

Macros

As clj-kondo is a static analyzer is does not need a runtime (JVM, browser, Node.js, etc.). It doesn't execute your code. As such it can be a faster alternative to linters that do use a runtime, like eastwood. This approach comes with the limitation that clj-kondo cannot execute your macros as macros can use arbitrary features from a runtime. Clj-kondo has support for clojure core macros and some popular libraries from the community. Macros that are not supported out of the box can be supported using configuration. One of the ways to configure macros is to write hooks for them (also see this blogpost). For many libraries there is already a configuration available that you can import. Also check out clj-kondo configs which contains configurations for third party libraries.

Babashka pod

Clj-kondo can be invoked as a babashka pod.

#!/usr/bin/env bb
(ns script
  (:require [babashka.pods :as pods]))

(pods/load-pod "clj-kondo")
(require '[pod.borkdude.clj-kondo :as clj-kondo])

(clj-kondo/merge-configs
 '{:linters {:unresolved-symbol {:exclude [(foo1.bar)]}}}
 '{:linters {:unresolved-symbol {:exclude [(foo2.bar)]}}})
;;=> {:linters {:unresolved-symbol {:exclude [(foo1.bar) (foo2.bar)]}}}

(-> (clj-kondo/run! {:lint ["src"]})
    :summary)
;;=> {:error 0, :warning 0, :info 0, :type :summary, :duration 779}

Podcasts

Articles

Thanks to:

License

Copyright © 2019 - 2023 Michiel Borkent

Distributed under the EPL License, same as Clojure. See LICENSE.

The directory inlined contains source from tools.reader which is licensed under the EPL license.

The directory parser contains modified source from rewrite-clj which is licensed under the MIT license.

clj-kondo's Projects

clj-kondo icon clj-kondo

Static analyzer and linter for Clojure code that sparks joy

clj-kondo.lsp icon clj-kondo.lsp

Clj-kondo language server and VSCode extension: https://marketplace.visualstudio.com/items?itemName=borkdude.clj-kondo

config icon config

Please use https://github.com/clj-kondo/configs instead

configs icon configs

Library configurations as dependencies for clj-kondo

inspector icon inspector

Turn Clojure specs into clj-kondo type annotations

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.