├── rum ├── rum.png ├── .clj-kondo │ └── config.edn ├── README.md └── test │ └── clj_kondo │ └── rum_test.cljs ├── mockery ├── .clj-kondo │ └── config.edn ├── README.md └── test │ └── clj_kondo │ └── mockery_test.clj ├── claypoole ├── .clj-kondo │ └── config.edn ├── README.md └── test │ └── clj_kondo │ └── claypoole_test.clj ├── slingshot ├── .clj-kondo │ └── config.edn ├── README.md └── test │ └── clj_kondo │ └── slingshot_test.clj ├── resources └── clj-kondo.exports │ └── clj-kondo │ ├── slingshot │ ├── config.edn │ └── clj_kondo │ │ └── slingshot │ │ └── try_plus.clj │ ├── rum │ ├── config.edn │ └── clj_kondo │ │ └── rum.clj │ ├── mockery │ ├── config.edn │ └── clj_kondo │ │ └── mockery │ │ ├── with_mock.clj │ │ └── with_mocks.clj │ └── claypoole │ ├── clj_kondo │ └── claypoole.clj │ └── config.edn ├── deps.edn ├── hugsql └── README.md ├── .gitignore ├── README.md ├── src └── clj_kondo │ └── config.clj └── LICENSE /rum/rum.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clj-kondo/config/HEAD/rum/rum.png -------------------------------------------------------------------------------- /rum/.clj-kondo/config.edn: -------------------------------------------------------------------------------- 1 | {:config-paths ["../../resources/clj-kondo.exports/clj-kondo/rum"]} 2 | -------------------------------------------------------------------------------- /mockery/.clj-kondo/config.edn: -------------------------------------------------------------------------------- 1 | {:config-paths ["../../resources/clj-kondo.exports/clj-kondo/mockery"]} 2 | -------------------------------------------------------------------------------- /claypoole/.clj-kondo/config.edn: -------------------------------------------------------------------------------- 1 | {:config-paths ["../../resources/clj-kondo.exports/clj-kondo/claypoole"]} 2 | -------------------------------------------------------------------------------- /slingshot/.clj-kondo/config.edn: -------------------------------------------------------------------------------- 1 | {:config-paths ["../../resources/clj-kondo.exports/clj-kondo/slingshot"]} 2 | -------------------------------------------------------------------------------- /resources/clj-kondo.exports/clj-kondo/slingshot/config.edn: -------------------------------------------------------------------------------- 1 | {:hooks 2 | {:analyze-call {slingshot.slingshot/try+ clj-kondo.slingshot.try-plus/try+}}} 3 | -------------------------------------------------------------------------------- /deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src" "resources"] 2 | :deps {org.clojure/tools.cli {:mvn/version "1.0.194"} 3 | cpath-clj/cpath-clj {:mvn/version "0.1.2"}}} 4 | -------------------------------------------------------------------------------- /mockery/README.md: -------------------------------------------------------------------------------- 1 | # Mockery 2 | 3 | See the `.clj-kondo` directory for configuration for the [Mockery](https://github.com/igrishaev/mockery) library. 4 | -------------------------------------------------------------------------------- /slingshot/README.md: -------------------------------------------------------------------------------- 1 | # Slingshot 2 | 3 | See the `.clj-kondo` directory for configuration for the 4 | [Slingshot](https://github.com/scgilardi/slingshot) library. 5 | -------------------------------------------------------------------------------- /rum/README.md: -------------------------------------------------------------------------------- 1 | # Rum 2 | 3 | See the `.clj-kondo` directory for configuration for the [Rum](https://github.com/tonsky/rum) library. 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /resources/clj-kondo.exports/clj-kondo/rum/config.edn: -------------------------------------------------------------------------------- 1 | {:hooks {:analyze-call {rum.core/defc clj-kondo.rum/defc 2 | rum.core/defcs clj-kondo.rum/defcs}} 3 | :lint-as {rum.core/defcc rum.core/defc}} 4 | -------------------------------------------------------------------------------- /resources/clj-kondo.exports/clj-kondo/mockery/config.edn: -------------------------------------------------------------------------------- 1 | {:linters {:mockery {:level :warning}} 2 | :hooks {:analyze-call {mockery.core/with-mock clj-kondo.mockery.with-mock/with-mock 3 | mockery.core/with-mocks clj-kondo.mockery.with-mocks/with-mocks}}} 4 | -------------------------------------------------------------------------------- /slingshot/test/clj_kondo/slingshot_test.clj: -------------------------------------------------------------------------------- 1 | (ns math.expression 2 | (:require [slingshot.slingshot :refer [throw+ try+]])) 3 | 4 | (defn read-file [file] 5 | (try+ 6 | (prn file) 7 | (catch [:type :tensor.parse/bad-tree] {:keys [tree hint]} 8 | (prn tree hint) 9 | (throw+)) 10 | (catch Object _ 11 | (throw+)))) 12 | -------------------------------------------------------------------------------- /hugsql/README.md: -------------------------------------------------------------------------------- 1 | # HugSQL 2 | 3 | The [HugSQL](https://github.com/layerware/hugsql) macro `def-db-fns` introduces 4 | vars into the namespace in which it is called. You can teach clj-kondo about 5 | these vars by using `declare`. Example: 6 | 7 | ``` clojure 8 | (ns foo.db 9 | (:require [hugsql.core :as hugsql])) 10 | 11 | (declare select-things) 12 | 13 | ;; this will define a var #'select-things: 14 | (hugsql/def-db-fns "select_things.sql") 15 | 16 | (defn get-my-things [conn params] 17 | (select-things conn params)) 18 | ``` 19 | 20 | If the amount of symbols introduced by HugSQL becomes too unwieldy, consider 21 | introducing a separate namespace in which HugSQL generates the vars: 22 | 23 | ``` clojure 24 | (ns foo.db.hugsql 25 | (:require [hugsql.core :as hugsql])) 26 | 27 | (hugsql/def-db-fns "select_things.sql") 28 | ``` 29 | 30 | You can then use this namespace like: 31 | 32 | ``` clojure 33 | (ns foo.db 34 | (:require [foo.db.hugsql :as sql])) 35 | 36 | (defn get-my-things [conn params] 37 | (sql/select-things conn params)) 38 | ``` 39 | 40 | and clj-kondo will not complain about this. 41 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/emacs,clojure 3 | 4 | ### Clojure ### 5 | pom.xml 6 | pom.xml.asc 7 | *.jar 8 | *.class 9 | /lib/ 10 | /classes/ 11 | /target/ 12 | /checkouts/ 13 | .lein-deps-sum 14 | .lein-repl-history 15 | .lein-plugins/ 16 | .lein-failures 17 | .nrepl-port 18 | .cpcache/ 19 | 20 | ### IntelliJ/Cursive ### 21 | .idea/ 22 | *.iml 23 | 24 | ### Emacs ### 25 | # -*- mode: gitignore; -*- 26 | *~ 27 | \#*\# 28 | /.emacs.desktop 29 | /.emacs.desktop.lock 30 | *.elc 31 | auto-save-list 32 | tramp 33 | .\#* 34 | 35 | # Org-mode 36 | .org-id-locations 37 | *_archive 38 | 39 | # flymake-mode 40 | *_flymake.* 41 | 42 | # eshell files 43 | /eshell/history 44 | /eshell/lastdir 45 | 46 | # elpa packages 47 | /elpa/ 48 | 49 | # reftex files 50 | *.rel 51 | 52 | # AUCTeX auto folder 53 | /auto/ 54 | 55 | # cask packages 56 | .cask/ 57 | dist/ 58 | 59 | # Flycheck 60 | flycheck_*.el 61 | 62 | # server auth directory 63 | /server/ 64 | 65 | # projectiles files 66 | .projectile 67 | 68 | # directory configuration 69 | .dir-locals.el 70 | 71 | 72 | # End of https://www.gitignore.io/api/emacs,clojure 73 | .cache 74 | .clj-kondo 75 | .lsp 76 | -------------------------------------------------------------------------------- /claypoole/README.md: -------------------------------------------------------------------------------- 1 | # Claypoole 2 | 3 | See the `.clj-kondo` directory for configuration for the [Claypoole](https://github.com/TheClimateCorporation/claypoole) library. 4 | 5 | The example effectively remaps the following to their `clojure.core` counterparts: 6 | 7 | 8 | 9 | | Original | Remapped | 10 | |--------------------------------------------|-----------| 11 | | `com.climate.claypoole/future` | `future` | 12 | | `com.climate.claypoole/completable-future` | `future` | 13 | | `com.climate.claypoole/pdoseq` | `doseq` | 14 | | `com.climate.claypoole/pmap` | `map` | 15 | | `com.climate.claypoole/upmap` | `map` | 16 | | `com.climate.claypoole/pvalues` | `pvalues` | 17 | | `com.climate.claypoole/upvalues` | `pvalues` | 18 | | `com.climate.claypoole/pfor` | `for` | 19 | | `com.climate.claypoole/upfor` | `for` | 20 | | `com.climate.claypoole.lazy/pdoseq` | `doseq` | 21 | | `com.climate.claypoole.lazy/pmap` | `map` | 22 | | `com.climate.claypoole.lazy/upmap` | `map` | 23 | | `com.climate.claypoole.lazy/pvalues` | `pvalues` | 24 | | `com.climate.claypoole.lazy/upvalues` | `pvalues` | 25 | | `com.climate.claypoole.lazy/pfor` | `for` | 26 | | `com.climate.claypoole.lazy/upfor` | `for` | 27 | -------------------------------------------------------------------------------- /resources/clj-kondo.exports/clj-kondo/mockery/clj_kondo/mockery/with_mock.clj: -------------------------------------------------------------------------------- 1 | (ns clj-kondo.mockery.with-mock 2 | (:require [clj-kondo.hooks-api :as api])) 3 | 4 | (defn with-mock [{:keys [:node]}] 5 | (let [[mock map & body] (rest (:children node))] 6 | (try 7 | (when-not (symbol? (api/sexpr mock)) 8 | (throw (ex-info "Mock is not a symbol" (meta mock)))) 9 | (when-not (map? (api/sexpr map)) 10 | (throw (ex-info "Mock binding is not a map" (meta map)))) 11 | (if-let [target (:target (api/sexpr map))] 12 | (when-not (qualified-keyword? target) 13 | (throw (ex-info (str target " must be fully qualified") (meta map)))) 14 | (throw (ex-info "no target specified" (meta map)))) 15 | (when-not body 16 | (api/reg-finding! (assoc (meta (first (:children node))) 17 | :message "with-mock with empty body" 18 | :type :mockery))) 19 | {:node (api/list-node 20 | (list* 21 | (api/token-node 'let*) 22 | (api/vector-node [mock map]) 23 | mock 24 | body))} 25 | (catch Exception e 26 | (api/reg-finding! (assoc (ex-data e) :message (ex-message e) :type :hook)) 27 | ;; when there is an error, ignore macro and only return body (in vector to prevent redundant do) 28 | {:node (api/vector-node body)})))) 29 | -------------------------------------------------------------------------------- /resources/clj-kondo.exports/clj-kondo/claypoole/clj_kondo/claypoole.clj: -------------------------------------------------------------------------------- 1 | (ns clj-kondo.claypoole 2 | (:refer-clojure :exclude [future pmap pvalues]) 3 | (:require [clj-kondo.hooks-api :as api])) 4 | 5 | (defn pool-and-body 6 | [token] 7 | (fn [{:keys [:node]}] 8 | (let [[pool & body] (rest (:children node)) 9 | new-node (api/list-node 10 | (list* 11 | (api/token-node token) 12 | (api/list-node 13 | (list* (api/token-node 'do) 14 | pool 15 | body))))] 16 | {:node (with-meta new-node 17 | (meta node))}))) 18 | 19 | (defn pool-with-binding-vec-or-exprs-and-body 20 | [token] 21 | (fn [{:keys [:node]}] 22 | (let [[pool binding-vec-or-exprs & body] (rest (:children node)) 23 | new-node (api/list-node 24 | [(api/token-node token) 25 | binding-vec-or-exprs 26 | (api/list-node 27 | (list* (api/token-node 'do) 28 | pool 29 | body))])] 30 | {:node (with-meta new-node 31 | (meta node))}))) 32 | 33 | (def future (pool-and-body 'future)) 34 | (def completable-future (pool-and-body 'future)) 35 | (def pdoseq (pool-with-binding-vec-or-exprs-and-body 'doseq)) 36 | (def pmap (pool-and-body 'map)) 37 | (def upmap (pool-and-body 'map)) 38 | (def pvalues (pool-and-body 'pvalues)) 39 | (def upvalues (pool-and-body 'pvalues)) 40 | (def pfor (pool-with-binding-vec-or-exprs-and-body 'for)) 41 | (def upfor (pool-with-binding-vec-or-exprs-and-body 'for)) 42 | -------------------------------------------------------------------------------- /resources/clj-kondo.exports/clj-kondo/claypoole/config.edn: -------------------------------------------------------------------------------- 1 | {:linters {:claypoole {:level :warning}} 2 | :lint-as {com.climate.claypoole/with-shutdown! clojure.core/let} 3 | :hooks {:analyze-call {com.climate.claypoole/future clj-kondo.claypoole/future 4 | com.climate.claypoole/completable-future clj-kondo.claypoole/completable-future 5 | com.climate.claypoole/pdoseq clj-kondo.claypoole/pdoseq 6 | com.climate.claypoole/pmap clj-kondo.claypoole/pmap 7 | com.climate.claypoole/upmap clj-kondo.claypoole/upmap 8 | com.climate.claypoole/pvalues clj-kondo.claypoole/pvalues 9 | com.climate.claypoole/upvalues clj-kondo.claypoole/upvalues 10 | com.climate.claypoole/pfor clj-kondo.claypoole/pfor 11 | com.climate.claypoole/upfor clj-kondo.claypoole/upfor 12 | com.climate.claypoole.lazy/pdoseq clj-kondo.claypoole/pdoseq 13 | com.climate.claypoole.lazy/pmap clj-kondo.claypoole/pmap 14 | com.climate.claypoole.lazy/upmap clj-kondo.claypoole/upmap 15 | com.climate.claypoole.lazy/pvalues clj-kondo.claypoole/pvalues 16 | com.climate.claypoole.lazy/upvalues clj-kondo.claypoole/upvalues 17 | com.climate.claypoole.lazy/pfor clj-kondo.claypoole/pfor 18 | com.climate.claypoole.lazy/upfor clj-kondo.claypoole/upfor}}} 19 | -------------------------------------------------------------------------------- /mockery/test/clj_kondo/mockery_test.clj: -------------------------------------------------------------------------------- 1 | (ns clj-kondo.mockery-test 2 | (:require [clojure.test :refer [is]] 3 | [example.foo :as example] 4 | [mockery.core :as mockery :refer [with-mock with-mocks]])) 5 | 6 | (with-mock _ 7 | {:target ::test-fn 8 | :return (fn [& _] 100500)} 9 | (example/test-fn 10)) 10 | 11 | (with-mock _ 12 | {:target :test-fn ;; :test-fn must be fully qualified 13 | :return (fn [& _] 100500)} 14 | (example/test-fn 10)) 15 | 16 | (with-mock _ 17 | {:return (fn [& _] 100500)} ;; no target specified 18 | (example/test-fn 10)) 19 | 20 | ;; all valid 21 | (with-mocks 22 | [foo {:target ::test-fn} 23 | bar {:target :example/test-fn-2}] 24 | (example/test-fn 1) 25 | (example/test-fn-2 1 2) 26 | (is (= @foo 27 | {:called? true 28 | :call-count 1 29 | :call-args '(1) 30 | :call-args-list '[(1)] 31 | :target ::test-fn})) 32 | (is (= @bar 33 | {:called? true 34 | :call-count 1 35 | :call-args '(1 2) 36 | :call-args-list '[(1 2)] 37 | :target ::test-fn-2}))) 38 | 39 | (with-mocks 40 | ;; no target specified 41 | [foo {:target ::test-fn} 42 | bar {}] 43 | (example/test-fn 1) 44 | (example/test-fn-2 1 2) 45 | (is (= @foo ;; no warning about foo, despite error in bindings 46 | {:called? true 47 | :call-count 1 48 | :call-args '(1) 49 | :call-args-list '[(1)] 50 | :target ::test-fn})) 51 | (is (= @bar ;; no warning about foo, despite error in bindings 52 | {:called? true 53 | :call-count 1 54 | :call-args '(1 2) 55 | :call-args-list '[(1 2)] 56 | :target ::test-fn-2}))) 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Clj-kondo config 2 | 3 | **Deprecated** 4 | 5 | Use [configs](https://github.com/clj-kondo/configs) instead. 6 | 7 | This repo contains configurations and/or recommendations that can be used with 8 | [clj-kondo](https://github.com/borkdude/clj-kondo/). Check the `resources` folder for available configs. 9 | 10 | ## Installation 11 | 12 | This repo has an **experimental** main entrypoint that copies library specific config and hooks to your `.clj-kondo`. 13 | 14 | Assuming the following alias in your `deps.edn`: 15 | 16 | ``` clojure 17 | :clj-kondo/config 18 | {:extra-deps {clj-kondo/config {:git/url "https://github.com/clj-kondo/config" 19 | :sha ""}} 20 | :main-opts ["-m" "clj-kondo.config"]} 21 | ``` 22 | 23 | you can invoke it with: 24 | 25 | ``` shell 26 | $ clojure -M:clj-kondo/config --lib rum --lib slingshot 27 | ``` 28 | 29 | This then copies Rum and Slingshot config into `.clj-kondo/configs/rum` and `.clj-kondo/configs/slingshot` respectively: 30 | 31 | ``` shell 32 | $ clojure -M:clj-kondo/config --lib rum --lib slingshot 33 | Copying rum config to .clj-kondo/configs/rum 34 | Copying slingshot config to .clj-kondo/configs/slingshot 35 | Add "configs/rum", "configs/slingshot" to :config-paths in .clj-kondo/config.edn to activate configs. 36 | ``` 37 | 38 | To activate, you then add `"configs/rum"` and `"configs/slingshot"` to your `:config-paths` in `config.edn` and Rum and Slinghot syntax will be recognized. 39 | 40 | Also see the 41 | [config.md](https://github.com/borkdude/clj-kondo/blob/master/doc/config.md#exporting-and-importing-configuration) 42 | section on importing and exporting configs. 43 | 44 | ## License 45 | 46 | Copyright © 2020 Michiel Borkent 47 | 48 | Distributed under the EPL License, same as Clojure. See LICENSE. 49 | -------------------------------------------------------------------------------- /src/clj_kondo/config.clj: -------------------------------------------------------------------------------- 1 | (ns clj-kondo.config 2 | (:require [clojure.java.io :as io] 3 | [clojure.string :as str] 4 | [clojure.tools.cli :refer [parse-opts]] 5 | [cpath-clj.core :as cp])) 6 | 7 | (def cli-options 8 | [["-l" "--lib LIBRARY" "Library" 9 | :default [] 10 | :assoc-fn (fn [m k v] 11 | (update m k (fnil conj []) v))]]) 12 | 13 | (defn delete-files-recursively 14 | ([f1] (delete-files-recursively f1 false)) 15 | ([f1 silently] 16 | (when (.isDirectory (io/file f1)) 17 | (doseq [f2 (.listFiles (io/file f1))] 18 | (delete-files-recursively f2 silently))) 19 | (io/delete-file f1 silently))) 20 | 21 | (defn -main [& args] 22 | (let [{:keys [:lib ]} (:options (parse-opts args cli-options))] 23 | (doseq [l lib] 24 | (if-let [resource (io/resource (str "clj-kondo.exports/clj-kondo/" l))] 25 | (let [config-dir (io/file ".clj-kondo" "configs" l)] 26 | (when (.exists config-dir) 27 | (println "Removing previous" l "config in" (.getPath config-dir)) 28 | (delete-files-recursively config-dir)) 29 | (println "Copying" l "config to" (.getPath config-dir)) 30 | (doseq [[path uris] (cp/resources resource) 31 | :let [uri (first uris) 32 | relative-path (subs path 1) 33 | output-file (io/file config-dir relative-path)]] 34 | (io/make-parents output-file) 35 | (with-open [in (io/input-stream uri)] 36 | (io/copy in output-file)))) 37 | (println "No config found for " l))) 38 | (println "Add" (str/join 39 | ", " 40 | (map (fn [lib] 41 | (pr-str (.getPath (io/file "configs" lib)))) 42 | lib)) 43 | "to :config-paths in .clj-kondo/config.edn to activate configs."))) 44 | -------------------------------------------------------------------------------- /resources/clj-kondo.exports/clj-kondo/slingshot/clj_kondo/slingshot/try_plus.clj: -------------------------------------------------------------------------------- 1 | (ns clj-kondo.slingshot.try-plus 2 | (:require [clj-kondo.hooks-api :as api])) 3 | 4 | (defn expand-catch [catch-node] 5 | (let [[catch catchee & exprs] (:children catch-node) 6 | catchee-sexpr (api/sexpr catchee)] 7 | (cond (vector? catchee-sexpr) 8 | (let [[selector & exprs] exprs] 9 | (api/list-node 10 | [catch (api/token-node 'Exception) (api/token-node '_e#) 11 | (api/list-node 12 | (list* (api/token-node 'let) 13 | (api/vector-node [selector (api/token-node nil)]) 14 | exprs))])) 15 | :else catch-node))) 16 | 17 | (defn try+ [{:keys [node]}] 18 | (let [children (rest (:children node)) 19 | [body catches] 20 | (loop [body children 21 | body-exprs [] 22 | catches []] 23 | (if (seq body) 24 | (let [f (first body) 25 | f-sexpr (api/sexpr f)] 26 | (if (and (seq? f-sexpr) (= 'catch (first f-sexpr))) 27 | (recur (rest body) 28 | body-exprs 29 | (conj catches (expand-catch f))) 30 | (recur (rest body) 31 | (conj body-exprs f) 32 | catches))) 33 | [body-exprs catches])) 34 | new-node (api/list-node 35 | [(api/token-node 'let) 36 | (api/vector-node 37 | [(api/token-node '&throw-context) (api/token-node nil)]) 38 | (api/token-node '&throw-context) ;; use throw-context to avoid warning 39 | (with-meta (api/list-node (list* (api/token-node 'try) 40 | (concat body catches))) 41 | (meta node))])] 42 | ;; (prn (api/sexpr new-node)) 43 | {:node new-node})) 44 | 45 | -------------------------------------------------------------------------------- /rum/test/clj_kondo/rum_test.cljs: -------------------------------------------------------------------------------- 1 | (ns clj-kondo.rum-test 2 | (:require [rum.core :as rum])) 3 | 4 | ;;;; defc 5 | 6 | (rum/defc label [text] ;; text is recognized as a binding 7 | [:div {:class "label"} text]) 8 | 9 | (rum/defc label ;; redefined var 10 | [text] ;; unused binding 11 | [:div {:class "label"} text']) ;; unresolved binding text' 12 | 13 | (rum/defc with-docstring 14 | "docstring" ;; docstring is placed correctly 15 | < { :will-mount (fn [x] ;; mixin is parsed correctly 16 | (assoc x ::time (js/Date.))) } 17 | [_text]) 18 | 19 | (rum/defc defc-multiple-bodies 20 | "docstring" ;; docstring is placed correctly 21 | < { :will-mount (fn [x] ;; mixin is parsed correctly 22 | (assoc x ::time (js/Date.))) } 23 | ([foo] (if foo 24 | (defc-multiple-bodies foo nil) 25 | (defc-multiple-bodies))) ;; invalid arity 26 | ([foo bar] ;; bar is unused 27 | foo)) 28 | 29 | ;;;; defcs 30 | 31 | (rum/defcs time-label ;; defcs is linted as defc 32 | < { :will-mount (fn [x] ;; mixin is parsed correctly 33 | (assoc x ::time (js/Date.))) } 34 | [state x] ;; unused 35 | [:div y ;; unresolved 36 | ": " (str (::time state))]) 37 | 38 | (rum/defcs SomeComponent < 39 | {:did-mount (fn [state] state)} 40 | [state input another] 41 | input ;; binding input is used, another is unused 42 | (let [x "Hello"] ;; binding is unused 43 | nil)) 44 | 45 | (SomeComponent "hello") ;; amount of args is invalid 46 | (SomeComponent "hello" "there") ;; amount of args is correct 47 | 48 | (rum/defcs ComponentWithDocString 49 | "docstring" ;; docstring is placed correctly 50 | < {:did-mount (fn [state] state)} 51 | [state input] 52 | input) 53 | 54 | (rum/defcs defcs-multiple-bodies 55 | "docstring" ;; docstring is placed correctly 56 | < {:dir-mount (fn [state] state)} 57 | ([state foo]) ;; foo is unused, but state isn't 58 | ([state foo bar])) 59 | 60 | (defcs-multiple-bodies) ;; invalid arity 61 | (defcs-multiple-bodies "hello") ;; valid arity 62 | -------------------------------------------------------------------------------- /claypoole/test/clj_kondo/claypoole_test.clj: -------------------------------------------------------------------------------- 1 | (ns example 2 | (:require 3 | [com.climate.claypoole :as cp])) 4 | 5 | (def pool (cp/threadpool 8)) 6 | (def coll [1 2 3]) 7 | 8 | (defn -main 9 | [& _] 10 | ;; future 11 | (cp/future pool (println "Hi from future")) 12 | 13 | ;; pdoseq 14 | (cp/pdoseq 8 [x coll] 15 | (println "Doseqing over" x)) 16 | (cp/pdoseq pool [x coll :when (= x 1)] 17 | (println "Doseqing over" x)) 18 | 19 | ;; pmap 20 | (cp/pmap 8 21 | (fn [x] (println "Mapping over" x)) 22 | coll) 23 | (cp/pmap pool 24 | (fn [x y] (println "Mapping over" [x y])) 25 | coll 26 | coll) 27 | 28 | ;; upmap 29 | (cp/upmap 8 30 | (fn [x] (println "Mapping over" x)) 31 | coll) 32 | (cp/upmap pool 33 | (fn [x y] (println "Mapping over" [x y])) 34 | coll 35 | coll) 36 | 37 | ;; pvalues 38 | (println "Parallel values" 39 | (cp/pvalues 8 40 | (do (Thread/sleep 100) 41 | (+ 1 2)) 42 | (+ 3 4))) 43 | (println "Parallel values" 44 | (cp/pvalues pool 45 | (do (Thread/sleep 100) 46 | (+ 1 2)) 47 | (+ 3 4))) 48 | 49 | ;; upvalues 50 | (println "Ordered parallel values" 51 | (cp/upvalues 8 52 | (do (Thread/sleep 100) 53 | (+ 1 2)) 54 | (+ 3 4))) 55 | (println "Ordered parallel values" 56 | (cp/upvalues pool 57 | (do (Thread/sleep 100) 58 | (+ 1 2)) 59 | (+ 3 4))) 60 | 61 | ;; pfor 62 | (cp/pfor 8 [x coll] 63 | (println "For over" x)) 64 | (cp/pfor pool [x coll 65 | y coll 66 | :when (and (= x 1) (= y 1))] 67 | (println "For over" [x y])) 68 | 69 | ;; upfor 70 | (cp/upfor 8 [x coll] 71 | (println "Ordered for over" x)) 72 | (cp/upfor pool [x coll 73 | y coll 74 | :when (and (= x 1) (= y 1))] 75 | (println "Ordered for over" [x y])) 76 | 77 | (cp/upfor 8) ;; arity warning with correct location 78 | 79 | (let [x 8] ;; binding is used 80 | (cp/upfor x [y coll] (println y))) 81 | ) 82 | -------------------------------------------------------------------------------- /resources/clj-kondo.exports/clj-kondo/mockery/clj_kondo/mockery/with_mocks.clj: -------------------------------------------------------------------------------- 1 | (ns clj-kondo.mockery.with-mocks 2 | (:require [clj-kondo.hooks-api :as api])) 3 | 4 | (defn with-mocks [{:keys [:node]}] 5 | (let [[binding-vec & body] (rest (:children node)) 6 | bindings (:children binding-vec) 7 | binding-count (count bindings) 8 | bvec (api/sexpr binding-vec)] 9 | (try 10 | (when-not binding-vec 11 | (throw (ex-info "No mocks provided" (meta node)))) 12 | (when-not (vector? bvec) 13 | (throw (ex-info "with-mocks requires vector for its bindings" (meta binding-vec)))) 14 | (when (zero? binding-count) 15 | (api/reg-finding! (assoc (meta (first (:children node))) 16 | :message "with-mocks with no mocks" 17 | :type :mockery))) 18 | (when-not (and binding-vec 19 | (even? binding-count)) 20 | (throw (ex-info "Mock vector requires an even number of forms" 21 | (meta binding-vec)))) 22 | (when-let [mock (first (drop-while #(symbol? (api/sexpr %)) 23 | (take-nth 2 bindings)))] 24 | (throw (ex-info "Mock is not a symbol" (meta mock)))) 25 | (when-let [value (first (drop-while #(map? (api/sexpr %)) 26 | (take-nth 2 (drop 1 bindings))))] 27 | (throw (ex-info "Mock binding is not a map" (meta value)))) 28 | (doseq [m (take-nth 2 (drop 1 bvec))] 29 | (if-let [target (:target m)] 30 | (when-not (qualified-keyword? target) 31 | (throw (ex-info (str target " must be fully qualified") (meta binding-vec)))) 32 | (throw (ex-info "no target specified" (meta binding-vec))))) 33 | (when-not body 34 | (api/reg-finding! (assoc (meta (first (:children node))) 35 | :message "with-mocks with empty body" 36 | :type :mockery))) 37 | {:node (api/list-node 38 | (list* 39 | (api/token-node 'let*) 40 | (api/vector-node bindings) 41 | `(~(into [] (take-nth 2 bindings)) 42 | ~@body)))} 43 | (catch Exception e 44 | (api/reg-finding! (assoc (ex-data e) :message (ex-message e) :type :hook)) 45 | ;; when there is an error, use this fallback node 46 | (let [fallback (api/list-node (list* (api/token-node 'let*) binding-vec body))] 47 | ;; (println fallback) 48 | {:node fallback}))))) 49 | -------------------------------------------------------------------------------- /resources/clj-kondo.exports/clj-kondo/rum/clj_kondo/rum.clj: -------------------------------------------------------------------------------- 1 | (ns clj-kondo.rum 2 | (:require [clj-kondo.hooks-api :as api])) 3 | 4 | (defn fn-body? [x] 5 | (and (seq? x) 6 | (vector? (first x)))) 7 | 8 | (defn rewrite-body [mixins body defcs?] 9 | (if defcs? 10 | (let [[binding-vec & body] (:children body) 11 | [state-arg & rest-args] (:children binding-vec) 12 | ;; the original vector without the state argument 13 | fn-args (assoc binding-vec :children rest-args) 14 | body (api/list-node 15 | (list* (api/token-node 'let*) 16 | (api/vector-node [state-arg (api/token-node nil)]) 17 | state-arg 18 | (concat mixins body))) 19 | body (api/list-node [fn-args body])] 20 | body) 21 | (let [[binding-vec & body] (:children body)] 22 | (api/list-node (cons binding-vec (concat mixins body)))))) 23 | 24 | (defn rewrite 25 | ([node] (rewrite node false)) 26 | ([node defcs?] 27 | (let [args (rest (:children node)) 28 | component-name (first args) 29 | ?docstring (when (string? (api/sexpr (second args))) 30 | (second args)) 31 | args (if ?docstring 32 | (nnext args) 33 | (next args)) 34 | bodies 35 | (loop [args* (seq args) 36 | mixins [] 37 | bodies []] 38 | (if args* 39 | (let [a (first args*) 40 | a-sexpr (api/sexpr a)] 41 | (cond (vector? a-sexpr) ;; a-sexpr is a binding vec and the rest is the body of the function 42 | [(rewrite-body mixins (api/list-node args*) defcs?)] 43 | (fn-body? a-sexpr) 44 | (recur (next args*) 45 | mixins 46 | (conj bodies (rewrite-body mixins a defcs?))) 47 | ;; assume mixin 48 | :else (recur (next args*) 49 | (conj mixins a) 50 | bodies))) 51 | bodies)) 52 | new-node (with-meta 53 | (api/list-node 54 | (list* (api/token-node 'defn) 55 | component-name 56 | (if ?docstring 57 | (cons ?docstring bodies) 58 | bodies))) 59 | (meta node))] 60 | new-node))) 61 | 62 | (defn defc [{:keys [:node]}] 63 | (let [new-node (rewrite node)] 64 | {:node new-node})) 65 | 66 | (defn defcs [{:keys [:node]}] 67 | (let [new-node (rewrite node true)] 68 | {:node new-node})) 69 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Eclipse Public License - v 1.0 2 | 3 | THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC 4 | LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM 5 | CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. 6 | 7 | 1. DEFINITIONS 8 | 9 | "Contribution" means: 10 | 11 | a) in the case of the initial Contributor, the initial code and documentation 12 | distributed under this Agreement, and 13 | b) in the case of each subsequent Contributor: 14 | i) changes to the Program, and 15 | ii) additions to the Program; 16 | 17 | where such changes and/or additions to the Program originate from and are 18 | distributed by that particular Contributor. A Contribution 'originates' from 19 | a Contributor if it was added to the Program by such Contributor itself or 20 | anyone acting on such Contributor's behalf. Contributions do not include 21 | additions to the Program which: (i) are separate modules of software 22 | distributed in conjunction with the Program under their own license 23 | agreement, and (ii) are not derivative works of the Program. 24 | 25 | "Contributor" means any person or entity that distributes the Program. 26 | 27 | "Licensed Patents" mean patent claims licensable by a Contributor which are 28 | necessarily infringed by the use or sale of its Contribution alone or when 29 | combined with the Program. 30 | 31 | "Program" means the Contributions distributed in accordance with this Agreement. 32 | 33 | "Recipient" means anyone who receives the Program under this Agreement, 34 | including all Contributors. 35 | 36 | 2. GRANT OF RIGHTS 37 | a) Subject to the terms of this Agreement, each Contributor hereby grants 38 | Recipient a non-exclusive, worldwide, royalty-free copyright license to 39 | reproduce, prepare derivative works of, publicly display, publicly perform, 40 | distribute and sublicense the Contribution of such Contributor, if any, and 41 | such derivative works, in source code and object code form. 42 | b) Subject to the terms of this Agreement, each Contributor hereby grants 43 | Recipient a non-exclusive, worldwide, royalty-free patent license under 44 | Licensed Patents to make, use, sell, offer to sell, import and otherwise 45 | transfer the Contribution of such Contributor, if any, in source code and 46 | object code form. This patent license shall apply to the combination of the 47 | Contribution and the Program if, at the time the Contribution is added by 48 | the Contributor, such addition of the Contribution causes such combination 49 | to be covered by the Licensed Patents. The patent license shall not apply 50 | to any other combinations which include the Contribution. No hardware per 51 | se is licensed hereunder. 52 | c) Recipient understands that although each Contributor grants the licenses to 53 | its Contributions set forth herein, no assurances are provided by any 54 | Contributor that the Program does not infringe the patent or other 55 | intellectual property rights of any other entity. Each Contributor 56 | disclaims any liability to Recipient for claims brought by any other entity 57 | based on infringement of intellectual property rights or otherwise. As a 58 | condition to exercising the rights and licenses granted hereunder, each 59 | Recipient hereby assumes sole responsibility to secure any other 60 | intellectual property rights needed, if any. For example, if a third party 61 | patent license is required to allow Recipient to distribute the Program, it 62 | is Recipient's responsibility to acquire that license before distributing 63 | the Program. 64 | d) Each Contributor represents that to its knowledge it has sufficient 65 | copyright rights in its Contribution, if any, to grant the copyright 66 | license set forth in this Agreement. 67 | 68 | 3. REQUIREMENTS 69 | 70 | A Contributor may choose to distribute the Program in object code form under its 71 | own license agreement, provided that: 72 | 73 | a) it complies with the terms and conditions of this Agreement; and 74 | b) its license agreement: 75 | i) effectively disclaims on behalf of all Contributors all warranties and 76 | conditions, express and implied, including warranties or conditions of 77 | title and non-infringement, and implied warranties or conditions of 78 | merchantability and fitness for a particular purpose; 79 | ii) effectively excludes on behalf of all Contributors all liability for 80 | damages, including direct, indirect, special, incidental and 81 | consequential damages, such as lost profits; 82 | iii) states that any provisions which differ from this Agreement are offered 83 | by that Contributor alone and not by any other party; and 84 | iv) states that source code for the Program is available from such 85 | Contributor, and informs licensees how to obtain it in a reasonable 86 | manner on or through a medium customarily used for software exchange. 87 | 88 | When the Program is made available in source code form: 89 | 90 | a) it must be made available under this Agreement; and 91 | b) a copy of this Agreement must be included with each copy of the Program. 92 | Contributors may not remove or alter any copyright notices contained within 93 | the Program. 94 | 95 | Each Contributor must identify itself as the originator of its Contribution, if 96 | any, in a manner that reasonably allows subsequent Recipients to identify the 97 | originator of the Contribution. 98 | 99 | 4. COMMERCIAL DISTRIBUTION 100 | 101 | Commercial distributors of software may accept certain responsibilities with 102 | respect to end users, business partners and the like. While this license is 103 | intended to facilitate the commercial use of the Program, the Contributor who 104 | includes the Program in a commercial product offering should do so in a manner 105 | which does not create potential liability for other Contributors. Therefore, if 106 | a Contributor includes the Program in a commercial product offering, such 107 | Contributor ("Commercial Contributor") hereby agrees to defend and indemnify 108 | every other Contributor ("Indemnified Contributor") against any losses, damages 109 | and costs (collectively "Losses") arising from claims, lawsuits and other legal 110 | actions brought by a third party against the Indemnified Contributor to the 111 | extent caused by the acts or omissions of such Commercial Contributor in 112 | connection with its distribution of the Program in a commercial product 113 | offering. The obligations in this section do not apply to any claims or Losses 114 | relating to any actual or alleged intellectual property infringement. In order 115 | to qualify, an Indemnified Contributor must: a) promptly notify the Commercial 116 | Contributor in writing of such claim, and b) allow the Commercial Contributor to 117 | control, and cooperate with the Commercial Contributor in, the defense and any 118 | related settlement negotiations. The Indemnified Contributor may participate in 119 | any such claim at its own expense. 120 | 121 | For example, a Contributor might include the Program in a commercial product 122 | offering, Product X. That Contributor is then a Commercial Contributor. If that 123 | Commercial Contributor then makes performance claims, or offers warranties 124 | related to Product X, those performance claims and warranties are such 125 | Commercial Contributor's responsibility alone. Under this section, the 126 | Commercial Contributor would have to defend claims against the other 127 | Contributors related to those performance claims and warranties, and if a court 128 | requires any other Contributor to pay any damages as a result, the Commercial 129 | Contributor must pay those damages. 130 | 131 | 5. NO WARRANTY 132 | 133 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN 134 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR 135 | IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, 136 | NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each 137 | Recipient is solely responsible for determining the appropriateness of using and 138 | distributing the Program and assumes all risks associated with its exercise of 139 | rights under this Agreement , including but not limited to the risks and costs 140 | of program errors, compliance with applicable laws, damage to or loss of data, 141 | programs or equipment, and unavailability or interruption of operations. 142 | 143 | 6. DISCLAIMER OF LIABILITY 144 | 145 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY 146 | CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, 147 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST 148 | PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 149 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 150 | OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS 151 | GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 152 | 153 | 7. GENERAL 154 | 155 | If any provision of this Agreement is invalid or unenforceable under applicable 156 | law, it shall not affect the validity or enforceability of the remainder of the 157 | terms of this Agreement, and without further action by the parties hereto, such 158 | provision shall be reformed to the minimum extent necessary to make such 159 | provision valid and enforceable. 160 | 161 | If Recipient institutes patent litigation against any entity (including a 162 | cross-claim or counterclaim in a lawsuit) alleging that the Program itself 163 | (excluding combinations of the Program with other software or hardware) 164 | infringes such Recipient's patent(s), then such Recipient's rights granted under 165 | Section 2(b) shall terminate as of the date such litigation is filed. 166 | 167 | All Recipient's rights under this Agreement shall terminate if it fails to 168 | comply with any of the material terms or conditions of this Agreement and does 169 | not cure such failure in a reasonable period of time after becoming aware of 170 | such noncompliance. If all Recipient's rights under this Agreement terminate, 171 | Recipient agrees to cease use and distribution of the Program as soon as 172 | reasonably practicable. However, Recipient's obligations under this Agreement 173 | and any licenses granted by Recipient relating to the Program shall continue and 174 | survive. 175 | 176 | Everyone is permitted to copy and distribute copies of this Agreement, but in 177 | order to avoid inconsistency the Agreement is copyrighted and may only be 178 | modified in the following manner. The Agreement Steward reserves the right to 179 | publish new versions (including revisions) of this Agreement from time to time. 180 | No one other than the Agreement Steward has the right to modify this Agreement. 181 | The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation 182 | may assign the responsibility to serve as the Agreement Steward to a suitable 183 | separate entity. Each new version of the Agreement will be given a 184 | distinguishing version number. The Program (including Contributions) may always 185 | be distributed subject to the version of the Agreement under which it was 186 | received. In addition, after a new version of the Agreement is published, 187 | Contributor may elect to distribute the Program (including its Contributions) 188 | under the new version. Except as expressly stated in Sections 2(a) and 2(b) 189 | above, Recipient receives no rights or licenses to the intellectual property of 190 | any Contributor under this Agreement, whether expressly, by implication, 191 | estoppel or otherwise. All rights in the Program not expressly granted under 192 | this Agreement are reserved. 193 | 194 | This Agreement is governed by the laws of the State of New York and the 195 | intellectual property laws of the United States of America. No party to this 196 | Agreement will bring a legal action under this Agreement more than one year 197 | after the cause of action arose. Each party waives its rights to a jury trial in 198 | any resulting litigation. 199 | --------------------------------------------------------------------------------