diff --git a/.gitignore b/.gitignore index d86667f4..1aa8ebbb 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ *~ .*.swo .*.swp +.clj-kondo/ .DS_Store .eastwood .idea/ diff --git a/project.clj b/project.clj index 0f8f3cb8..331047b6 100644 --- a/project.clj +++ b/project.clj @@ -1,7 +1,7 @@ ;; Please don't bump the library version by hand - use ci.release-workflow instead. (defproject formatting-stack "1.0.1" ;; Please keep the dependencies sorted a-z. - :dependencies [[clj-kondo "2019.05.19-alpha"] + :dependencies [[clj-kondo "2020.01.13"] [cljfmt "0.6.5" :exclusions [rewrite-clj]] [com.gfredericks/how-to-ns "0.2.6"] [com.gfredericks/lein-all-my-files-should-end-with-exactly-one-newline-character "0.1.1"] diff --git a/src/formatting_stack/branch_formatter.clj b/src/formatting_stack/branch_formatter.clj index 62857d75..86b79374 100644 --- a/src/formatting_stack/branch_formatter.clj +++ b/src/formatting_stack/branch_formatter.clj @@ -59,7 +59,7 @@ strategies/exclude-cljs strategies/jvm-requirable-files strategies/namespaces-within-refresh-dirs-only))) - (-> (linters.kondo/new) + (-> (linters.kondo/new {}) (assoc :strategies (conj default-strategies strategies/exclude-edn strategies/exclude-clj diff --git a/src/formatting_stack/core.clj b/src/formatting_stack/core.clj index 21e5fa51..66c484e1 100644 --- a/src/formatting_stack/core.clj +++ b/src/formatting_stack/core.clj @@ -2,7 +2,7 @@ (:require [clojure.main] [formatting-stack.background] - [formatting-stack.defaults :refer :all] + [formatting-stack.defaults :refer [default-processors default-formatters default-linters default-strategies]] [formatting-stack.indent-specs :refer [default-third-party-indent-specs]] [formatting-stack.protocols.formatter :as protocols.formatter] [formatting-stack.protocols.linter :as protocols.linter] @@ -69,14 +69,9 @@ in-background? (if (some? in-background?) in-background? true) - {formatters-strategies - :formatters - linters-strategies - :linters - processors-strategies - :processors - default-strategies - :default} strategies + {formatters-strategies :formatters + linters-strategies :linters + processors-strategies :processors} strategies impl (bound-fn [] ;; important that it's a bound-fn (for an undetermined reason) (process! protocols.formatter/format! formatters formatters-strategies strategies intersperse-newlines?) (when intersperse-newlines? diff --git a/src/formatting_stack/defaults.clj b/src/formatting_stack/defaults.clj index 74ea9f7b..d45ec9e6 100644 --- a/src/formatting_stack/defaults.clj +++ b/src/formatting_stack/defaults.clj @@ -59,7 +59,7 @@ strategies/exclude-cljs strategies/jvm-requirable-files strategies/namespaces-within-refresh-dirs-only))) - (-> (linters.kondo/new) + (-> (linters.kondo/new {}) (assoc :strategies (conj extended-strategies strategies/exclude-edn strategies/exclude-clj diff --git a/src/formatting_stack/formatters/clean_ns/impl.clj b/src/formatting_stack/formatters/clean_ns/impl.clj index 67f85f86..05f4ebf6 100644 --- a/src/formatting_stack/formatters/clean_ns/impl.clj +++ b/src/formatting_stack/formatters/clean_ns/impl.clj @@ -4,11 +4,12 @@ [clojure.tools.reader :as tools.reader] [clojure.tools.reader.reader-types :refer [push-back-reader]] [clojure.walk :as walk] - [formatting-stack.util :refer [ensure-coll rcomp try-require]] + [formatting-stack.util :refer [ensure-coll rcomp]] [nedap.speced.def :as speced] [refactor-nrepl.config] [refactor-nrepl.ns.clean-ns :refer [clean-ns]]) (:import + (clojure.lang Namespace) (java.io File))) (speced/defn ns-form-of [^string? filename] @@ -20,7 +21,7 @@ nil (throw e)))))) -(speced/defn safely-read-ns-contents [^string? buffer, ^clojure.lang.Namespace ns-obj] +(speced/defn safely-read-ns-contents [^string? buffer, ^Namespace ns-obj] (binding [tools.reader/*alias-map* (ns-aliases ns-obj)] (tools.reader/read-string {:read-cond :allow :features #{:clj}} diff --git a/src/formatting_stack/formatters/cljfmt/impl.clj b/src/formatting_stack/formatters/cljfmt/impl.clj index d67ee7c6..7b4a0678 100644 --- a/src/formatting_stack/formatters/cljfmt/impl.clj +++ b/src/formatting_stack/formatters/cljfmt/impl.clj @@ -23,7 +23,7 @@ (locking require-lock (require namespace)) (ns-map namespace) - (catch Exception e + (catch Exception _ {}))) (spec/def ::indent-key #{:style/indent :style.cljfmt/indent :style.cljfmt/type}) @@ -106,7 +106,7 @@ (doseq [[sym var-ref] ns-mappings :when (var? var-ref) :let [fqn (fully-qualified-name-of var-ref)] - :when (some (fn [[k v]] + :when (some (fn [[k _]] (= k fqn)) @result) :let [indent (get @result fqn)]] diff --git a/src/formatting_stack/linters/kondo.clj b/src/formatting_stack/linters/kondo.clj index 527a0355..f4ae7374 100644 --- a/src/formatting_stack/linters/kondo.clj +++ b/src/formatting_stack/linters/kondo.clj @@ -1,22 +1,50 @@ (ns formatting-stack.linters.kondo (:require - [formatting-stack.linters.kondo.impl :as impl] + [clj-kondo.core :as clj-kondo] [formatting-stack.protocols.linter :as linter] + [medley.core :refer [deep-merge]] [nedap.utils.modular.api :refer [implement]])) (def off {:level :off}) (def default-options - (list "--config" (pr-str {:linters {:invalid-arity off - :cond-without-else off}}))) + {:linters {:cond-else off ;; undesired + :missing-docstring off ;; undesired + :unused-symbol off ;; undesired because potentially unreliable + :unused-private-var off ;; undesired because potentially unreliable + :consistent-alias off ;; duped by how-to-ns + :duplicate-require off ;; duped by clean-ns + :unused-import off ;; duped by clean-ns + :unused-namespace off ;; duped by clean-ns + :unused-referred-var off ;; duped by clean-ns + :unresolved-namespace off} ;; duped by clean-ns + :lint-as '{nedap.speced.def/def-with-doc clojure.core/defonce + nedap.speced.def/defn clojure.core/defn + nedap.speced.def/defprotocol clojure.core/defprotocol + nedap.speced.def/doc clojure.repl/doc + nedap.speced.def/fn clojure.core/fn + nedap.speced.def/let clojure.core/let + nedap.speced.def/letfn clojure.core/letfn} + :output {:exclude-files ["test-resources/*" + "test/unit/formatting_stack/formatters/cljfmt/impl/sample_data.clj"]}}) -(defn lint! [this filenames] - (->> filenames - (cons "--lint") - (concat default-options) - (impl/parse-opts) - impl/lint!)) +(def clj-options + "CLJ files are also linted by eastwood, disable duplicate linters" + {:linters {:misplaced-docstring off + :deprecated-var off + :redefined-var off}}) -(defn new [] - (implement {} +(defn lint! [{:keys [kondo-options]} filenames] + (let [{cljs-files true + clj-files false} (group-by (fn [f] (boolean (re-find #"\.cljs$" f))) filenames) + findings (->> [(clj-kondo/run! {:lint clj-files + :config (deep-merge default-options clj-options (or kondo-options {}))}) + (clj-kondo/run! {:lint cljs-files + :config (deep-merge default-options (or kondo-options {}))})] + (map :findings) + (reduce into))] + (clj-kondo/print! {:findings findings}))) + +(defn new [{:keys [kondo-options] :as options}] + (implement options linter/--lint! lint!)) diff --git a/src/formatting_stack/linters/kondo/impl.clj b/src/formatting_stack/linters/kondo/impl.clj deleted file mode 100644 index a206c0d2..00000000 --- a/src/formatting_stack/linters/kondo/impl.clj +++ /dev/null @@ -1,292 +0,0 @@ -(ns formatting-stack.linters.kondo.impl - "Vendorized/forked copy of clj-kondo.main. https://github.com/borkdude/clj-kondo#license" - (:require - [clj-kondo.impl.analyzer :as ana] - [clj-kondo.impl.cache :as cache] - [clj-kondo.impl.config :as config] - [clj-kondo.impl.linters :as l] - [clj-kondo.impl.namespace :as namespace] - [clj-kondo.impl.overrides :refer [overrides]] - [clj-kondo.impl.profiler :as profiler] - [clj-kondo.impl.state :as state] - [clojure.edn :as edn] - [clojure.java.io :as io] - [clojure.string :as str :refer [ends-with? starts-with?]]) - (:import - (java.util.jar JarFile JarFile$JarFileEntry))) - -(def dev? (= "true" (System/getenv "CLJ_KONDO_DEV"))) - -(def ^:private version (str/trim - (slurp (io/resource "CLJ_KONDO_VERSION")))) -(set! *warn-on-reflection* true) - -(defn- format-output [] - (if-let [^String pattern (-> @config/config :output :pattern)] - (fn [filename row col level message] - (-> pattern - (str/replace "{{filename}}" filename) - (str/replace "{{row}}" (str row)) - (str/replace "{{col}}" (str col)) - (str/replace "{{level}}" (name level)) - (str/replace "{{LEVEL}}" (str/upper-case (name level))) - (str/replace "{{message}}" message))) - (fn [filename row col level message] - (str filename ":" row ":" col ": " (name level) ": " message)))) - -(defn- print-findings [findings] - (let [format-fn (format-output)] - (doseq [{:keys [filename message level row col] :as finding} - (dedupe (sort-by (juxt :filename :row :col) findings))] - (println (format-fn filename row col level message))))) - -(defn- print-version [] - (println (str "clj-kondo v" version))) - -(defn- print-help [] - (print-version) - ;; TODO: document config format when stable enough - (println (format " -Usage: [ --help ] [ --version ] [ --lint ] [ --lang (clj|cljs) ] [ --cache [ ] ] [ --config ] - -Options: - - --lint: a file can either be a normal file, directory or classpath. In the - case of a directory or classpath, only .clj, .cljs and .cljc will be - processed. Use - as filename for reading from stdin. - - --lang: if lang cannot be derived from the file extension this option will be - used. - - --cache: if dir exists it is used to write and read data from, to enrich - analysis over multiple runs. If no value is provided, the nearest .clj-kondo - parent directory is detected and a cache directory will be created in it. - - --config: config may be a file or an EDN expression. See - https://cljdoc.org/d/clj-kondo/clj-kondo/%s/doc/configuration. -" version)) - nil) - -(defn- source-file? [filename] - (or (ends-with? filename ".clj") - (ends-with? filename ".cljc") - (ends-with? filename ".cljs"))) - -(defn- sources-from-jar - [^String jar-path] - (let [jar (JarFile. jar-path) - entries (enumeration-seq (.entries jar)) - entries (filter (fn [^JarFile$JarFileEntry x] - (let [nm (.getName x)] - (source-file? nm))) entries)] - (map (fn [^JarFile$JarFileEntry entry] - {:filename (.getName entry) - :source (slurp (.getInputStream jar entry))}) entries))) - -(defn- sources-from-dir - [dir] - (let [files (file-seq dir)] - (keep (fn [^java.io.File file] - (let [nm (.getPath file) - can-read? (.canRead file) - source? (source-file? nm)] - (cond - (and can-read? source?) - {:filename nm - :source (slurp file)} - (and (not can-read?) source?) - (do (println (str nm ":0:0:") "warning: can't read, check file permissions") - nil) - :else nil))) - files))) - -(defn- lang-from-file [file default-language] - (cond (ends-with? file ".clj") - :clj - (ends-with? file ".cljc") - :cljc - (ends-with? file ".cljs") - :cljs - :else default-language)) - -(def ^:private cp-sep (System/getProperty "path.separator")) - -(defn- classpath? [f] - (str/includes? f cp-sep)) - -(defn- process-file [filename default-language] - (try - (let [file (io/file filename)] - (cond - (.exists file) - (if (.isFile file) - (if (ends-with? file ".jar") - ;; process jar file - (mapcat #(ana/analyze-input (:filename %) (:source %) - (lang-from-file (:filename %) default-language) - dev?) - (sources-from-jar filename)) - ;; assume normal source file - (ana/analyze-input filename (slurp filename) - (lang-from-file filename default-language) - dev?)) - ;; assume directory - (mapcat #(ana/analyze-input (:filename %) (:source %) - (lang-from-file (:filename %) default-language) - dev?) - (sources-from-dir file))) - (= "-" filename) - (ana/analyze-input "" (slurp *in*) default-language dev?) - (classpath? filename) - (mapcat #(process-file % default-language) - (str/split filename - (re-pattern cp-sep))) - :else - [{:findings [{:level :warning - :filename filename - :col 0 - :row 0 - :message "file does not exist"}]}])) - (catch Throwable e - (if dev? (throw e) - [{:findings [{:level :warning - :filename filename - :col 0 - :row 0 - :message "could not process file"}]}])))) - -(defn- process-files [files default-lang] - (mapcat #(process-file % default-lang) files)) - -;;;; find cache/config dir - -(defn- config-dir - ([] (config-dir - (io/file - (System/getProperty "user.dir")))) - ([cwd] - (loop [dir (io/file cwd)] - (let [cfg-dir (io/file dir ".clj-kondo")] - (if (.exists cfg-dir) - (if (.isDirectory cfg-dir) - cfg-dir - (throw (Exception. (str cfg-dir " must be a directory")))) - (when-let [parent (.getParentFile dir)] - (recur parent))))))) - -(def ^:private - empty-cache-opt-warning - "WARNING: --cache option didn't specify directory, but no .clj-kondo directory found. Continuing without cache. See https://github.com/borkdude/clj-kondo/blob/master/README.md#project-setup.") - -(defn parse-opts [options] - (let [opts (loop [options options - opts-map {} - current-opt nil] - (if-let [opt (first options)] - (if (starts-with? opt "--") - (recur (rest options) - (assoc opts-map opt []) - opt) - (recur (rest options) - (update opts-map current-opt conj opt) - current-opt)) - opts-map)) - default-lang (case (first (get opts "--lang")) - "clj" :clj - "cljs" :cljs - "cljc" :cljc - :clj) - cache-opt (get opts "--cache") - cfg-dir (config-dir) - cache-dir (when cache-opt - (if-let [cd (first cache-opt)] - (io/file cd version) - (if cfg-dir (io/file cfg-dir ".cache" version) - (do (println empty-cache-opt-warning) - nil)))) - files (get opts "--lint") - raw-config (first (get opts "--config")) - config-edn? (when raw-config - (str/starts-with? raw-config "{")) - config-opt (and raw-config - (if config-edn? - (edn/read-string raw-config) - (edn/read-string (slurp raw-config)))) - config-edn (when cfg-dir - (let [f (io/file cfg-dir "config.edn")] - (when (.exists f) - (edn/read-string (slurp f)))))] - {:opts opts - :files files - :cache-dir cache-dir - :default-lang default-lang - :configs [config-edn config-opt]})) - -(defn- mmerge - "Merges maps no deeper than two levels" - [a b] - (merge-with merge a b)) - -(defn- index-defs-and-calls [defs-and-calls] - (reduce - (fn [acc {:keys [:calls :defs :used :lang] :as m}] - (-> acc - (update-in [lang :calls] (fn [prev-calls] - (merge-with into prev-calls calls))) - (update-in [lang :defs] mmerge defs) - (update-in [lang :used] into used))) - {:clj {:calls {} :defs {} :used #{}} - :cljs {:calls {} :defs {} :used #{}} - :cljc {:calls {} :defs {} :used #{}}} - defs-and-calls)) - -(def ^:private zinc (fnil inc 0)) - -(defn- summarize [findings] - (reduce (fn [acc {:keys [:level]}] - (update acc level zinc)) - {:error 0 :warning 0 :info 0} - findings)) - -(defn- filter-findings [findings] - (let [print-debug? (:debug @config/config) - filter-output (not-empty (-> @config/config :output :include-files)) - remove-output (not-empty (-> @config/config :output :exclude-files))] - (for [{:keys [:filename :level :type] :as f} findings - :let [level (or (when type (-> @config/config :linters type :level)) - level)] - :when (and level (not= :off level)) - :when (if (= :debug type) - print-debug? - true) - :when (if filter-output - (some (fn [pattern] - (re-find (re-pattern pattern) filename)) - filter-output) - true) - :when (not-any? (fn [pattern] - (re-find (re-pattern pattern) filename)) - remove-output)] - (assoc f :level level)))) - -(defn lint! [{:keys [opts files default-lang cache-dir configs]}] - (state/clear-findings!) - (reset! namespace/namespaces {}) - (run! config/merge-config! configs) - (let [processed (process-files files default-lang) - idacs (-> processed - index-defs-and-calls - (cache/sync-cache cache-dir) - overrides) - linted-calls (doall (l/lint-calls idacs)) - _ (l/lint-unused-namespaces!) - all-findings (concat linted-calls (mapcat :findings processed) - @state/findings) - all-findings (filter-findings all-findings) - {:keys [error warning]} (summarize all-findings)] - (when (-> @config/config :output :show-progress) - (println)) - (print-findings all-findings) - (cond (pos? error) 3 - (pos? warning) 2 - :else 0))) diff --git a/src/formatting_stack/processors/kondo.clj b/src/formatting_stack/processors/kondo.clj new file mode 100644 index 00000000..f1e6f89d --- /dev/null +++ b/src/formatting_stack/processors/kondo.clj @@ -0,0 +1,26 @@ +(ns formatting-stack.processors.kondo + "Creates cache for entire classpath to make better use of the project-wide analysis capabilities." + (:require + [clj-kondo.core :as clj-kondo] + [clojure.string :as str] + [formatting-stack.kondo :refer [initial-run?]] + [formatting-stack.protocols.processor :as processor] + [nedap.utils.modular.api :refer [implement]]) + (:import + (java.io File))) + +(defn process! [_this files] + (let [cache-dir ".clj-kondo"] + (-> cache-dir File. .mkdirs) + (when-not @initial-run? + (reset! initial-run? true) + (clj-kondo/run! {:lint (-> (System/getProperty "java.class.path") + (str/split #"\:")) + :cache-dir cache-dir})) + (clj-kondo/run! {:lint files + :cache-dir cache-dir})) + nil) + +(defn new [] + (implement {} + processor/--process! process!)) diff --git a/src/formatting_stack/processors/test_runner.clj b/src/formatting_stack/processors/test_runner.clj index 728efbb0..7462e066 100644 --- a/src/formatting_stack/processors/test_runner.clj +++ b/src/formatting_stack/processors/test_runner.clj @@ -6,7 +6,7 @@ and invokes `#'clojure.test/run-tests` out of that result." (:require [clojure.test] - [formatting-stack.processors.test-runner.impl :refer :all] + [formatting-stack.processors.test-runner.impl :refer [ns->sym testable-namespaces]] [formatting-stack.protocols.processor :as processor] [formatting-stack.strategies :refer [git-completely-staged git-diff-against-default-branch git-not-completely-staged]] [nedap.utils.modular.api :refer [implement]])) diff --git a/src/formatting_stack/processors/test_runner/impl.clj b/src/formatting_stack/processors/test_runner/impl.clj index c5057560..d4640c1a 100644 --- a/src/formatting_stack/processors/test_runner/impl.clj +++ b/src/formatting_stack/processors/test_runner/impl.clj @@ -23,8 +23,7 @@ "Some projects have the naming convention of prefixing the last segment with `t-` to denote a testing namespace." [^Namespace n] - (let [s (str n) - segments (-> n str (string/split #"\.")) + (let [segments (-> n str (string/split #"\.")) first-segments (butlast segments) last-segment (->> segments last (str "t-"))] (->> [last-segment] diff --git a/src/formatting_stack/project_formatter.clj b/src/formatting_stack/project_formatter.clj index 7972e1c0..6f587728 100644 --- a/src/formatting_stack/project_formatter.clj +++ b/src/formatting_stack/project_formatter.clj @@ -60,7 +60,7 @@ strategies/exclude-cljs strategies/jvm-requirable-files strategies/namespaces-within-refresh-dirs-only))) - (-> (linters.kondo/new) + (-> (linters.kondo/new {}) (assoc :strategies (conj default-strategies strategies/exclude-edn strategies/exclude-clj diff --git a/src/formatting_stack/strategies/impl.clj b/src/formatting_stack/strategies/impl.clj index 60d821c4..f191dd1a 100644 --- a/src/formatting_stack/strategies/impl.clj +++ b/src/formatting_stack/strategies/impl.clj @@ -46,9 +46,9 @@ (-> decl parse/deps-from-ns-decl) ;; no exceptions thrown true) true))) - (catch Exception e + (catch Exception _ false) - (catch AssertionError e + (catch AssertionError _ false)))) (defn extract-clj-files [files] diff --git a/test/functional/formatting_stack/formatters/clean_ns.clj b/test/functional/formatting_stack/formatters/clean_ns.clj index 2ea31768..9bcd9b4e 100644 --- a/test/functional/formatting_stack/formatters/clean_ns.clj +++ b/test/functional/formatting_stack/formatters/clean_ns.clj @@ -52,7 +52,7 @@ (is (seq (impl/used-namespace-names should-not-be-cleaned-2-f #{})))) (deftest clean-ns-form - (are [op filename ns-form libspec-whitelist namespaces-that-should-never-cleaned] + (are [op filename libspec-whitelist namespaces-that-should-never-cleaned] (let [cleaner (sut/make-cleaner formatting-stack.formatters.how-to-ns/default-how-to-ns-opts sut/default-nrepl-opts namespaces-that-should-never-cleaned @@ -60,16 +60,16 @@ filename) v (util.ns/replaceable-ns-form filename cleaner formatting-stack.formatters.how-to-ns/default-how-to-ns-opts)] (op v)) - some? should-be-cleaned-f should-be-cleaned sut/default-libspec-whitelist #{} - nil? should-be-cleaned-f should-be-cleaned sut/default-libspec-whitelist #{'functional.formatting-stack.formatters.clean-ns.should-be-cleaned} - some? "dev/user.clj" (ns-form-of "dev/user.clj") sut/default-libspec-whitelist #{} - nil? "dev/user.clj" (ns-form-of "dev/user.clj") sut/default-libspec-whitelist sut/default-namespaces-that-should-never-cleaned - nil? should-not-be-partially-cleaned-f should-not-be-partially-cleaned sut/default-libspec-whitelist #{} - nil? should-not-be-cleaned-f should-not-be-cleaned sut/default-libspec-whitelist #{} - nil? should-not-be-cleaned-2-f should-not-be-cleaned-2 sut/default-libspec-whitelist #{} - nil? should-not-be-cleaned-3-f should-not-be-cleaned-3 sut/default-libspec-whitelist #{} - nil? should-not-be-cleaned-4-f should-not-be-cleaned-4 sut/default-libspec-whitelist #{} - nil? should-not-be-cleaned-5-f should-not-be-cleaned-5 sut/default-libspec-whitelist #{} - some? should-not-be-cleaned-3-f should-not-be-cleaned-3 #{} #{} - some? should-not-be-cleaned-4-f should-not-be-cleaned-4 #{} #{} - some? should-not-be-cleaned-5-f should-not-be-cleaned-5 #{} #{})) + some? should-be-cleaned-f sut/default-libspec-whitelist #{} + nil? should-be-cleaned-f sut/default-libspec-whitelist #{'functional.formatting-stack.formatters.clean-ns.should-be-cleaned} + some? "dev/user.clj" sut/default-libspec-whitelist #{} + nil? "dev/user.clj" sut/default-libspec-whitelist sut/default-namespaces-that-should-never-cleaned + nil? should-not-be-partially-cleaned-f sut/default-libspec-whitelist #{} + nil? should-not-be-cleaned-f sut/default-libspec-whitelist #{} + nil? should-not-be-cleaned-2-f sut/default-libspec-whitelist #{} + nil? should-not-be-cleaned-3-f sut/default-libspec-whitelist #{} + nil? should-not-be-cleaned-4-f sut/default-libspec-whitelist #{} + nil? should-not-be-cleaned-5-f sut/default-libspec-whitelist #{} + some? should-not-be-cleaned-3-f #{} #{} + some? should-not-be-cleaned-4-f #{} #{} + some? should-not-be-cleaned-5-f #{} #{})) diff --git a/test/unit/formatting_stack/formatters/trivial_ns_duplicates.clj b/test/unit/formatting_stack/formatters/trivial_ns_duplicates.clj index 61d48590..9f168d4e 100644 --- a/test/unit/formatting_stack/formatters/trivial_ns_duplicates.clj +++ b/test/unit/formatting_stack/formatters/trivial_ns_duplicates.clj @@ -30,8 +30,10 @@ '[[a :refer [b c]] [a :refer [b c d]]] '[[a :refer [b c d]]])) (deftest remove-exact-duplicates - (are [desc input expected] (= expected - (sut/remove-exact-duplicates input)) + (are [desc input expected] (testing desc + (is (= expected + (sut/remove-exact-duplicates input))) + true) "returns nil when there's nothing to fix" '(ns foo) diff --git a/worker/formatting_stack/kondo.clj b/worker/formatting_stack/kondo.clj new file mode 100644 index 00000000..a5bb2381 --- /dev/null +++ b/worker/formatting_stack/kondo.clj @@ -0,0 +1,5 @@ +(ns formatting-stack.kondo + "This file live in a distinct source-paths so it's not affected by the Reloaded workflow, + while developing formatting-stack itself.") + +(defonce initial-run? (atom false))