From 371f8b4d216281c3343f2efa1d6318bd557c6b30 Mon Sep 17 00:00:00 2001 From: Jeroen de Jong Date: Sat, 28 Dec 2019 20:41:19 +0100 Subject: [PATCH 01/52] Migrate to clj-kondo's JVM API Part of #91 --- .gitignore | 1 + project.clj | 2 +- src/formatting_stack/compilers/kondo.clj | 24 ++ src/formatting_stack/linters/kondo.clj | 36 ++- src/formatting_stack/linters/kondo/impl.clj | 292 -------------------- 5 files changed, 54 insertions(+), 301 deletions(-) create mode 100644 src/formatting_stack/compilers/kondo.clj delete mode 100644 src/formatting_stack/linters/kondo/impl.clj 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 58682a30..52cea157 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 "2.0.1-alpha2" ;; 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/compilers/kondo.clj b/src/formatting_stack/compilers/kondo.clj new file mode 100644 index 00000000..83a42114 --- /dev/null +++ b/src/formatting_stack/compilers/kondo.clj @@ -0,0 +1,24 @@ +(ns formatting-stack.compilers.kondo + "Creates cache for entire classpath to make better use of the project-wide analysis capabilities. + + Excluded from the formatting-stack defaults: + building the cache can be quite slow (much more than a `clojure.tools.namespace.repl/refresh`), + increasing the chances for concurrent (buggy) refreshing of Clojure namespaces." + (:require + [clj-kondo.core :as clj-kondo] + [clojure.string :as str] + [formatting-stack.protocols.compiler]) + (:import (java.io File))) + +(ns-unmap *ns* 'Compiler) + +(defrecord Compiler [] + formatting-stack.protocols.compiler/Compiler + (compile! [_ _] + (let [files (-> (System/getProperty "java.class.path") + (str/split #"\:")) + cache-dir ".clj-kondo"] + (-> ".clj-kondo" File. .mkdirs) + (clj-kondo/run! {:lint files + :cache-dir cache-dir})) + nil)) diff --git a/src/formatting_stack/linters/kondo.clj b/src/formatting_stack/linters/kondo.clj index 527a0355..ab7b6718 100644 --- a/src/formatting_stack/linters/kondo.clj +++ b/src/formatting_stack/linters/kondo.clj @@ -1,21 +1,41 @@ (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] [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 ;; can give false positives + :unused-private-var off ;; can give false positives + :consistent-alias off ;; already offered by how-to-ns + :duplicate-require off ;; already offered by clean-ns + :unused-import off ;; already offered by clean-ns + :unused-namespace off ;; already offered by clean-ns + :unused-referred-var off ;; already offered by clean-ns + :unresolved-namespace off ;; already offered by clean-ns + :misplaced-docstring off ;; already offered by Eastwood + :deprecated-var off ;; already offered by Eastwood + :redefined-var off ;; already offered by Eastwood + } + :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!)) + (-> (clj-kondo/run! {:lint filenames + :config default-options}) + (select-keys [:findings]) + clj-kondo/print!)) (defn new [] (implement {} 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))) From 77d37580e0a91fd481cea97337993d71e2ac3b25 Mon Sep 17 00:00:00 2001 From: Jeroen de Jong Date: Mon, 6 Jan 2020 14:42:13 +0100 Subject: [PATCH 02/52] Address various linter warnings --- src/formatting_stack/compilers/kondo.clj | 24 ------------------- src/formatting_stack/core.clj | 13 ++++------ .../formatters/clean_ns/impl.clj | 5 ++-- .../formatters/cljfmt/impl.clj | 4 ++-- src/formatting_stack/processors/kondo.clj | 22 +++++++++++++++++ .../processors/test_runner.clj | 2 +- .../processors/test_runner/impl.clj | 3 +-- src/formatting_stack/strategies/impl.clj | 4 ++-- .../formatting_stack/formatters/clean_ns.clj | 14 +++++------ .../formatters/trivial_ns_duplicates.clj | 6 +++-- 10 files changed, 46 insertions(+), 51 deletions(-) delete mode 100644 src/formatting_stack/compilers/kondo.clj create mode 100644 src/formatting_stack/processors/kondo.clj diff --git a/src/formatting_stack/compilers/kondo.clj b/src/formatting_stack/compilers/kondo.clj deleted file mode 100644 index 83a42114..00000000 --- a/src/formatting_stack/compilers/kondo.clj +++ /dev/null @@ -1,24 +0,0 @@ -(ns formatting-stack.compilers.kondo - "Creates cache for entire classpath to make better use of the project-wide analysis capabilities. - - Excluded from the formatting-stack defaults: - building the cache can be quite slow (much more than a `clojure.tools.namespace.repl/refresh`), - increasing the chances for concurrent (buggy) refreshing of Clojure namespaces." - (:require - [clj-kondo.core :as clj-kondo] - [clojure.string :as str] - [formatting-stack.protocols.compiler]) - (:import (java.io File))) - -(ns-unmap *ns* 'Compiler) - -(defrecord Compiler [] - formatting-stack.protocols.compiler/Compiler - (compile! [_ _] - (let [files (-> (System/getProperty "java.class.path") - (str/split #"\:")) - cache-dir ".clj-kondo"] - (-> ".clj-kondo" File. .mkdirs) - (clj-kondo/run! {:lint files - :cache-dir cache-dir})) - nil)) 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/formatters/clean_ns/impl.clj b/src/formatting_stack/formatters/clean_ns/impl.clj index 4f425ad0..1c9d84bd 100644 --- a/src/formatting_stack/formatters/clean_ns/impl.clj +++ b/src/formatting_stack/formatters/clean_ns/impl.clj @@ -4,9 +4,10 @@ [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]) (:import + (clojure.lang Namespace) (java.io File))) (speced/defn ns-form-of [^string? filename] @@ -18,7 +19,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/processors/kondo.clj b/src/formatting_stack/processors/kondo.clj new file mode 100644 index 00000000..1364e128 --- /dev/null +++ b/src/formatting_stack/processors/kondo.clj @@ -0,0 +1,22 @@ +(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.protocols.processor :as processor] + [nedap.utils.modular.api :refer [implement]]) + (:import (java.io File))) + + +(defn process! [_ _] + (let [files (-> (System/getProperty "java.class.path") + (str/split #"\:")) + cache-dir ".clj-kondo"] + (-> ".clj-kondo" File. .mkdirs) + (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/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 cef4e659..9dfa7f03 100644 --- a/test/functional/formatting_stack/formatters/clean_ns.clj +++ b/test/functional/formatting_stack/formatters/clean_ns.clj @@ -56,13 +56,13 @@ (when (strategies/refactor-nrepl-available?) (deftest clean-ns-form (are [op filename ns-form 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 - libspec-whitelist - filename) - v (util.ns/replaceable-ns-form filename cleaner formatting-stack.formatters.how-to-ns/default-how-to-ns-opts)] - (op v)) + (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 + libspec-whitelist + 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 #{} 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) From 421dd5ebb1cf6cd1cfdb8ab75432d99ba333af0d Mon Sep 17 00:00:00 2001 From: Jeroen de Jong Date: Tue, 7 Jan 2020 08:13:15 +0100 Subject: [PATCH 03/52] Add configurability for kondo-options --- src/formatting_stack/linters/kondo.clj | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/formatting_stack/linters/kondo.clj b/src/formatting_stack/linters/kondo.clj index ab7b6718..2d8bd69d 100644 --- a/src/formatting_stack/linters/kondo.clj +++ b/src/formatting_stack/linters/kondo.clj @@ -2,6 +2,7 @@ (:require [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}) @@ -31,9 +32,9 @@ :output {:exclude-files ["test-resources/*" "test/unit/formatting_stack/formatters/cljfmt/impl/sample_data.clj"]}}) -(defn lint! [this filenames] +(defn lint! [{:keys [kondo-options]} filenames] (-> (clj-kondo/run! {:lint filenames - :config default-options}) + :config (deep-merge kondo-options default-options)}) (select-keys [:findings]) clj-kondo/print!)) From c5b2e24874159b654383a5bf4c00be9a9309b98b Mon Sep 17 00:00:00 2001 From: Jeroen de Jong Date: Tue, 7 Jan 2020 08:52:44 +0100 Subject: [PATCH 04/52] Split Kondo linters by platform (clj/cljs) --- src/formatting_stack/linters/kondo.clj | 22 +++++++++++++++------- src/formatting_stack/processors/kondo.clj | 1 - 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/formatting_stack/linters/kondo.clj b/src/formatting_stack/linters/kondo.clj index 2d8bd69d..7a79891f 100644 --- a/src/formatting_stack/linters/kondo.clj +++ b/src/formatting_stack/linters/kondo.clj @@ -18,9 +18,6 @@ :unused-namespace off ;; already offered by clean-ns :unused-referred-var off ;; already offered by clean-ns :unresolved-namespace off ;; already offered by clean-ns - :misplaced-docstring off ;; already offered by Eastwood - :deprecated-var off ;; already offered by Eastwood - :redefined-var off ;; already offered by Eastwood } :lint-as '{nedap.speced.def/def-with-doc clojure.core/defonce nedap.speced.def/defn clojure.core/defn @@ -32,11 +29,22 @@ :output {:exclude-files ["test-resources/*" "test/unit/formatting_stack/formatters/cljfmt/impl/sample_data.clj"]}}) +(def clj-options + "CLJ files are also linted by eastwood, disable duplicate linters" + {:linters {:misplaced-docstring off + :deprecated-var off + :redefined-var off}}) + (defn lint! [{:keys [kondo-options]} filenames] - (-> (clj-kondo/run! {:lint filenames - :config (deep-merge kondo-options default-options)}) - (select-keys [:findings]) - clj-kondo/print!)) + (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 [] (implement {} diff --git a/src/formatting_stack/processors/kondo.clj b/src/formatting_stack/processors/kondo.clj index 1364e128..60dca6d3 100644 --- a/src/formatting_stack/processors/kondo.clj +++ b/src/formatting_stack/processors/kondo.clj @@ -7,7 +7,6 @@ [nedap.utils.modular.api :refer [implement]]) (:import (java.io File))) - (defn process! [_ _] (let [files (-> (System/getProperty "java.class.path") (str/split #"\:")) From fb1277cfa870c6e0d6c5248cf0c73b912f469629 Mon Sep 17 00:00:00 2001 From: Jeroen de Jong Date: Sun, 19 Jan 2020 11:16:02 +0100 Subject: [PATCH 05/52] Return report from Kondo --- src/formatting_stack/linters/kondo.clj | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/formatting_stack/linters/kondo.clj b/src/formatting_stack/linters/kondo.clj index 7a79891f..a4eeb061 100644 --- a/src/formatting_stack/linters/kondo.clj +++ b/src/formatting_stack/linters/kondo.clj @@ -3,7 +3,8 @@ [clj-kondo.core :as clj-kondo] [formatting-stack.protocols.linter :as linter] [medley.core :refer [deep-merge]] - [nedap.utils.modular.api :refer [implement]])) + [nedap.utils.modular.api :refer [implement]] + [clojure.set :as set])) (def off {:level :off}) @@ -37,14 +38,18 @@ (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}))) + clj-files false} (group-by (fn [f] (boolean (re-find #"\.cljs$" f))) filenames)] + (->> [(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 {}))})] + (mapcat :findings) + (map (fn [m] + (-> (set/rename-keys m {:row :line + :message :msg + :type :linter + :col :column}) + (update :linter (fn [k] (keyword "kondo" (name k)))))))))) (defn new [] (implement {} From e6d27ba7776c32d8a760323f6aab092d1e81fb21 Mon Sep 17 00:00:00 2001 From: Jeroen de Jong Date: Sun, 19 Jan 2020 11:16:59 +0100 Subject: [PATCH 06/52] Return report from loc-per-ns --- src/formatting_stack/linters/loc_per_ns.clj | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/formatting_stack/linters/loc_per_ns.clj b/src/formatting_stack/linters/loc_per_ns.clj index 9ad3c9c4..57cbad75 100644 --- a/src/formatting_stack/linters/loc_per_ns.clj +++ b/src/formatting_stack/linters/loc_per_ns.clj @@ -16,11 +16,12 @@ (->> filenames (process-in-parallel! (fn [filename] (when (overly-long-ns? filename max-lines-per-ns) - (println "Warning:" - filename - "is longer than" - max-lines-per-ns - "LOC. Consider refactoring.")))))) + {:filename filename + :linter :formatting-stack/loc-per-ns + :msg (str "Longer than " max-lines-per-ns " LOC. consider refactoring") + :line (+ 1 max-lines-per-ns) ;; first line after limit is the issue + :column 1}))) + (remove nil?))) (defn new [{:keys [max-lines-per-ns] :or {max-lines-per-ns 350}}] From 322a6a5b9cc9a799949fed6de9b534f71eff6a62 Mon Sep 17 00:00:00 2001 From: Jeroen de Jong Date: Sun, 19 Jan 2020 00:29:04 +0100 Subject: [PATCH 07/52] Replace bikeshed with custom linter --- project.clj | 1 - src/formatting_stack/branch_formatter.clj | 4 +-- src/formatting_stack/defaults.clj | 4 +-- src/formatting_stack/linters/bikeshed.clj | 32 -------------------- src/formatting_stack/linters/line_length.clj | 27 +++++++++++++++++ src/formatting_stack/project_formatter.clj | 4 +-- 6 files changed, 33 insertions(+), 39 deletions(-) delete mode 100644 src/formatting_stack/linters/bikeshed.clj create mode 100644 src/formatting_stack/linters/line_length.clj diff --git a/project.clj b/project.clj index 52cea157..84a9112e 100644 --- a/project.clj +++ b/project.clj @@ -12,7 +12,6 @@ [com.stuartsierra/component "0.4.0"] [integrant "0.7.0"] [jonase/eastwood "0.3.5"] - [lein-bikeshed "0.5.1"] [medley "1.2.0"] [org.clojure/clojure "1.10.1"] [org.clojure/tools.namespace "0.3.1"] diff --git a/src/formatting_stack/branch_formatter.clj b/src/formatting_stack/branch_formatter.clj index 1a73a134..6855c998 100644 --- a/src/formatting_stack/branch_formatter.clj +++ b/src/formatting_stack/branch_formatter.clj @@ -9,9 +9,9 @@ [formatting-stack.formatters.no-extra-blank-lines :as formatters.no-extra-blank-lines] [formatting-stack.formatters.trivial-ns-duplicates :as formatters.trivial-ns-duplicates] [formatting-stack.indent-specs] - [formatting-stack.linters.bikeshed :as linters.bikeshed] [formatting-stack.linters.eastwood :as linters.eastwood] [formatting-stack.linters.kondo :as linters.kondo] + [formatting-stack.linters.line-length :as linters.line-length] [formatting-stack.linters.loc-per-ns :as linters.loc-per-ns] [formatting-stack.linters.ns-aliases :as linters.ns-aliases] [formatting-stack.linters.one-resource-per-ns :as linters.one-resource-per-ns] @@ -56,7 +56,7 @@ (-> (linters.loc-per-ns/new {}) (assoc :strategies (conj default-strategies strategies/exclude-edn))) - (-> (linters.bikeshed/new {}) + (-> (linters.line-length/new {}) (assoc :strategies (conj default-strategies strategies/exclude-edn))) (-> (linters.eastwood/new {}) diff --git a/src/formatting_stack/defaults.clj b/src/formatting_stack/defaults.clj index 28c5d7a4..25ba2831 100644 --- a/src/formatting_stack/defaults.clj +++ b/src/formatting_stack/defaults.clj @@ -6,9 +6,9 @@ [formatting-stack.formatters.newlines :as formatters.newlines] [formatting-stack.formatters.no-extra-blank-lines :as formatters.no-extra-blank-lines] [formatting-stack.formatters.trivial-ns-duplicates :as formatters.trivial-ns-duplicates] - [formatting-stack.linters.bikeshed :as linters.bikeshed] [formatting-stack.linters.eastwood :as linters.eastwood] [formatting-stack.linters.kondo :as linters.kondo] + [formatting-stack.linters.line-length :as linters.line-length] [formatting-stack.linters.loc-per-ns :as linters.loc-per-ns] [formatting-stack.linters.ns-aliases :as linters.ns-aliases] [formatting-stack.linters.one-resource-per-ns :as linters.one-resource-per-ns] @@ -56,7 +56,7 @@ (-> (linters.loc-per-ns/new {}) (assoc :strategies (conj extended-strategies strategies/exclude-edn))) - (-> (linters.bikeshed/new {}) + (-> (linters.line-length/new {}) (assoc :strategies (conj extended-strategies strategies/exclude-edn))) (-> (linters.eastwood/new {}) diff --git a/src/formatting_stack/linters/bikeshed.clj b/src/formatting_stack/linters/bikeshed.clj deleted file mode 100644 index ddfb25b3..00000000 --- a/src/formatting_stack/linters/bikeshed.clj +++ /dev/null @@ -1,32 +0,0 @@ -(ns formatting-stack.linters.bikeshed - (:require - [bikeshed.core :as bikeshed] - [clojure.java.io :as io] - [clojure.string :as str] - [formatting-stack.protocols.linter :as linter] - [nedap.utils.modular.api :refer [implement]])) - -(defn lint! [{:keys [max-line-length]} filenames] - (let [files (map io/file filenames) - output (->> (with-out-str - (bikeshed/long-lines files :max-line-length max-line-length)) - (str/split-lines) - (remove (fn [line] - (or (str/blank? line) - (some (fn [re] - (re-find re line)) - [#"^Checking for lines" - #":refer \[" - #"^No lines found"])))))] - (when (-> output count (> 1)) - (let [[head & tail] output - replacement (str "Lines exceeding " max-line-length " columns") - output (-> head - (str/replace #"^Badly formatted files" replacement) - (cons tail))] - (->> output (str/join "\n") println))))) - -(defn new [{:keys [max-line-length] - :or {max-line-length 130}}] - (implement {:max-line-length max-line-length} - linter/--lint! lint!)) diff --git a/src/formatting_stack/linters/line_length.clj b/src/formatting_stack/linters/line_length.clj new file mode 100644 index 00000000..958d9dd0 --- /dev/null +++ b/src/formatting_stack/linters/line_length.clj @@ -0,0 +1,27 @@ +(ns formatting-stack.linters.line-length + (:require + [clojure.string :as string] + [formatting-stack.protocols.linter :as linter] + [formatting-stack.util :refer [process-in-parallel!]] + [nedap.utils.modular.api :refer [implement]])) + +(defn exceeding-lines [threshold filename] + (->> (-> filename slurp (string/split #"\n")) + (map-indexed (fn [i row] + (when (< threshold (count row)) + {:filename filename + :linter :formatting-stack/line-length + :column (+ 1 threshold) + :line (+ 1 i) + :msg (str "Line exceeding " threshold " columns")}))) + (remove nil?))) + +(defn lint! [{:keys [max-line-length]} filenames] + (->> filenames + (process-in-parallel! (partial exceeding-lines max-line-length)) + (mapcat identity))) + +(defn new [{:keys [max-line-length] + :or {max-line-length 130}}] + (implement {:max-line-length max-line-length} + linter/--lint! lint!)) diff --git a/src/formatting_stack/project_formatter.clj b/src/formatting_stack/project_formatter.clj index 93cc997a..fae7ec7e 100644 --- a/src/formatting_stack/project_formatter.clj +++ b/src/formatting_stack/project_formatter.clj @@ -9,9 +9,9 @@ [formatting-stack.formatters.no-extra-blank-lines :as formatters.no-extra-blank-lines] [formatting-stack.formatters.trivial-ns-duplicates :as formatters.trivial-ns-duplicates] [formatting-stack.indent-specs] - [formatting-stack.linters.bikeshed :as linters.bikeshed] [formatting-stack.linters.eastwood :as linters.eastwood] [formatting-stack.linters.kondo :as linters.kondo] + [formatting-stack.linters.line-length :as linters.line-length] [formatting-stack.linters.loc-per-ns :as linters.loc-per-ns] [formatting-stack.linters.ns-aliases :as linters.ns-aliases] [formatting-stack.linters.one-resource-per-ns :as linters.one-resource-per-ns] @@ -57,7 +57,7 @@ (-> (linters.loc-per-ns/new {}) (assoc :strategies (conj default-strategies strategies/exclude-edn))) - (-> (linters.bikeshed/new {}) + (-> (linters.line-length/new {}) (assoc :strategies (conj default-strategies strategies/exclude-edn))) (-> (linters.eastwood/new {}) From 601808a55d11fc296baa165230eae409c270a35e Mon Sep 17 00:00:00 2001 From: Jeroen de Jong Date: Sun, 19 Jan 2020 12:05:38 +0100 Subject: [PATCH 08/52] Return report from ns-aliases --- src/formatting_stack/linters/ns_aliases.clj | 46 ++++++++++++--------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/src/formatting_stack/linters/ns_aliases.clj b/src/formatting_stack/linters/ns_aliases.clj index fa23e57c..886b701f 100644 --- a/src/formatting_stack/linters/ns_aliases.clj +++ b/src/formatting_stack/linters/ns_aliases.clj @@ -1,11 +1,15 @@ (ns formatting-stack.linters.ns-aliases "Observes these guidelines: https://stuartsierra.com/2015/05/10/clojure-namespace-aliases" (:require + [clojure.java.io :as io] [clojure.string :as string] - [clojure.tools.namespace.file :as file] + [clojure.tools.namespace.parse :as parse] + [clojure.tools.reader.reader-types :refer [indexing-push-back-reader]] [formatting-stack.protocols.linter :as linter] [formatting-stack.util :refer [process-in-parallel!]] - [nedap.utils.modular.api :refer [implement]])) + [nedap.utils.modular.api :refer [implement]]) + (:import + (java.io PushbackReader))) (defn clause= [a b] (->> [a b] @@ -69,27 +73,29 @@ (derived? alias :from ns-name)) (boolean)))))) +(defn read-ns-decl + "Reads file with line/column metadata" + [filename] + (with-open [rdr (-> (io/reader filename) PushbackReader. indexing-push-back-reader)] + (parse/read-ns-decl rdr))) + (defn lint! [{:keys [acceptable-aliases-whitelist]} filenames] (->> filenames (process-in-parallel! (fn [filename] - (let [bad-require-clauses (->> filename - file/read-file-ns-decl - formatting-stack.util/require-from-ns-decl - (rest) - (remove (partial acceptable-require-clause? - acceptable-aliases-whitelist)))] - (when (seq bad-require-clauses) - (let [formatted-bad-requires (->> bad-require-clauses - (map (fn [x] - (str " " x))) - (string/join "\n"))] - (-> (str "Warning for " - filename - ": the following :require aliases are not derived from their refered namespace:" - "\n" - formatted-bad-requires - ". See https://stuartsierra.com/2015/05/10/clojure-namespace-aliases\n") - (println))))))))) + (->> filename + read-ns-decl + formatting-stack.util/require-from-ns-decl + (rest) + (remove (partial acceptable-require-clause? + acceptable-aliases-whitelist)) + (map (fn [bad-alias] + {:filename filename + :line (:line (meta bad-alias)) + :column (:column (meta bad-alias)) + :warning-details-url "https://stuartsierra.com/2015/05/10/clojure-namespace-aliases" + :msg (str bad-alias " is not a derived alias") + :linter :formatting-stack/ns-aliases}))))) + (mapcat identity))) (defn new [{:keys [acceptable-aliases-whitelist] :or {acceptable-aliases-whitelist default-acceptable-aliases-whitelist}}] From 3d7a76be815a2e6f3bd28b7cadcb91f5042873e3 Mon Sep 17 00:00:00 2001 From: Jeroen de Jong Date: Sat, 18 Jan 2020 21:05:17 +0100 Subject: [PATCH 09/52] Return report from Eastwood --- src/formatting_stack/linters/eastwood.clj | 64 ++++++++++++----------- 1 file changed, 34 insertions(+), 30 deletions(-) diff --git a/src/formatting_stack/linters/eastwood.clj b/src/formatting_stack/linters/eastwood.clj index b0adc798..afeaed2e 100644 --- a/src/formatting_stack/linters/eastwood.clj +++ b/src/formatting_stack/linters/eastwood.clj @@ -6,7 +6,8 @@ [formatting-stack.protocols.linter :as linter] [formatting-stack.util :refer [ns-name-from-filename]] [medley.core :refer [deep-merge]] - [nedap.utils.modular.api :refer [implement]])) + [nedap.utils.modular.api :refer [implement]]) + (:import (java.io File))) (def default-eastwood-options ;; Avoid false positives or more-annoying-than-useful checks: @@ -15,39 +16,42 @@ (-> eastwood.lint/default-opts (assoc :linters linters)))) -(def default-warnings-to-silence - [#"== Eastwood" - #"^dbg " - #"Warning: protocol .* is overwriting function" ;; False positive with nedap.speced.def - #"Directories scanned" - #"Entering directory" - #".*wrong-pre-post.*\*.*\*" ;; False positives for dynamic vars https://git.io/fhQTx - #"== Warnings" - #"== Linting done"]) +(defrecord TrackingReporter [reports]) -(defn lint! [{:keys [options warnings-to-silence]} filenames] +(defmethod eastwood.reporting-callbacks/lint-warning TrackingReporter [{:keys [reports]} warning] + (swap! reports update :warnings (fnil conj []) warning) + nil) + +(defmethod eastwood.reporting-callbacks/analyzer-exception TrackingReporter [{:keys [reports]} exception] + (swap! reports update :errors (fnil conj []) exception) + nil) + +(defmethod eastwood.reporting-callbacks/note TrackingReporter [{:keys [reports]} msg] + (swap! reports update :note (fnil conj []) msg) + nil) + +(defn lint! [{:keys [options]} filenames] (reset! eastwood.util/warning-enable-config-atom []) ;; https://github.com/jonase/eastwood/issues/317 (let [namespaces (->> filenames (remove #(str/ends-with? % ".edn")) (keep ns-name-from-filename)) - result (->> (with-out-str - (binding [*warn-on-reflection* true] - (eastwood.lint/eastwood (-> options - (assoc :namespaces namespaces))))) - (str/split-lines) - (remove (fn [line] - (or (str/blank? line) - (some (fn [re] - (re-find re line)) - warnings-to-silence)))))] - (when-not (every? (fn [line] - (str/starts-with? line "== Linting")) - result) - (->> result (str/join "\n") println)))) + root-dir (-> (File. "") .getAbsolutePath) + reports (atom nil)] + (with-out-str + (eastwood.lint/eastwood (assoc options :namespaces namespaces) + (->TrackingReporter reports))) + (->> (:warnings @reports) + (map :warn-data) + (map (fn [{:keys [uri-or-file-name] :as m}] + (-> m + (update :linter (fn [k] (keyword "eastwood" (name k)))) + (assoc :filename (if (string? uri-or-file-name) + uri-or-file-name + (str/replace (-> uri-or-file-name .getPath) + root-dir + ""))))))))) -(defn new [{:keys [eastwood-options warnings-to-silence] - :or {warnings-to-silence default-warnings-to-silence - eastwood-options {}}}] - (implement {:options (deep-merge default-eastwood-options eastwood-options) - :warnings-to-silence warnings-to-silence} +(defn new [{:keys [eastwood-options] + :or {eastwood-options {}}}] + (implement {:options (deep-merge default-eastwood-options eastwood-options)} linter/--lint! lint!)) From 8a3c703e8bb15f3aad0638be777efad8f7e5f6a5 Mon Sep 17 00:00:00 2001 From: Jeroen de Jong Date: Sun, 19 Jan 2020 12:06:18 +0100 Subject: [PATCH 10/52] Use reporter to print lint-results --- src/formatting_stack/core.clj | 60 +++++++++------------- src/formatting_stack/project_formatter.clj | 6 +-- src/formatting_stack/reporter.clj | 25 +++++++++ 3 files changed, 51 insertions(+), 40 deletions(-) create mode 100644 src/formatting_stack/reporter.clj diff --git a/src/formatting_stack/core.clj b/src/formatting_stack/core.clj index 66c484e1..db9a11d0 100644 --- a/src/formatting_stack/core.clj +++ b/src/formatting_stack/core.clj @@ -7,6 +7,7 @@ [formatting-stack.protocols.formatter :as protocols.formatter] [formatting-stack.protocols.linter :as protocols.linter] [formatting-stack.protocols.processor :as protocols.processor] + [formatting-stack.reporter :as reporter] [formatting-stack.util :refer [with-serialized-output]] [nedap.utils.modular.api :refer [implement]])) @@ -17,49 +18,39 @@ []) distinct)) -(def print-newline - (constantly println)) - -(def newliner - (implement {} - protocols.linter/--lint! print-newline - protocols.processor/--process! print-newline - protocols.formatter/--format! print-newline)) - -(defn process! [method members category-strategies default-strategies intersperse-newlines?] +(defn process! [method members category-strategies default-strategies] ;; `memoize` rationale: results are cached not for performance, ;; but for avoiding the scenario where one `member` alters the git status, ;; so the subsequent `member`s' strategies won't perceive the same set of files than the first one. ;; e.g. cljfmt may operate upon `strategies/git-completely-staged`, formatting some files accordingly. ;; Then `how-to-ns`, which follows the same strategy, would perceive a dirty git status. ;; Accordingly it would do nothing, which is undesirable. - (let [members (if-not intersperse-newlines? - members - (->> members (interpose newliner))) - files (memoize (fn [strategies] + (let [files (memoize (fn [strategies] (files-from-strategies strategies)))] (with-serialized-output - (doseq [member members] - (let [{specific-strategies :strategies} member - strategies (or specific-strategies category-strategies default-strategies)] - (try - (->> strategies files (method member)) - (catch Exception e - (println "Encountered an exception, which will be printed in the next line." - "formatting-stack execution has *not* been aborted.") - (-> e .printStackTrace)) - (catch AssertionError e - (println "Encountered an exception, which will be printed in the next line." - "formatting-stack execution has *not* been aborted.") - (-> e .printStackTrace)))))))) + (->> members + (mapcat (fn [member] + (let [{specific-strategies :strategies} member + strategies (or specific-strategies category-strategies default-strategies)] + (try + (->> strategies files (method member)) + (catch Exception e + (println "Encountered an exception, which will be printed in the next line." + "formatting-stack execution has *not* been aborted.") + (-> e .printStackTrace) + nil) + (catch AssertionError e + (println "Encountered an exception, which will be printed in the next line." + "formatting-stack execution has *not* been aborted.") + (-> e .printStackTrace) + nil))))))))) (defn format! [& {:keys [strategies third-party-indent-specs formatters linters processors - in-background? - intersperse-newlines?]}] + in-background?]}] ;; the following `or` clauses ensure that Components don't pass nil values (let [strategies (or strategies default-strategies) third-party-indent-specs (or third-party-indent-specs default-third-party-indent-specs) @@ -73,13 +64,10 @@ 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? - (println)) - (process! protocols.linter/lint! linters linters-strategies strategies intersperse-newlines?) - (when intersperse-newlines? - (println)) - (process! protocols.processor/process! processors processors-strategies strategies intersperse-newlines?))] + (process! protocols.formatter/format! formatters formatters-strategies strategies) + (->> (process! protocols.linter/lint! linters linters-strategies strategies) + reporter/print-report) + (process! protocols.processor/process! processors processors-strategies strategies))] (if in-background? (do (reset! formatting-stack.background/workload impl) diff --git a/src/formatting_stack/project_formatter.clj b/src/formatting_stack/project_formatter.clj index fae7ec7e..b4f233ea 100644 --- a/src/formatting_stack/project_formatter.clj +++ b/src/formatting_stack/project_formatter.clj @@ -83,8 +83,7 @@ :formatters default-formatters :linters default-linters :processors default-processors - :in-background? in-background? - :intersperse-newlines? true)) + :in-background? in-background?)) (defn lint-project! [& {:keys [in-background?] :or {in-background? false}}] @@ -92,5 +91,4 @@ :formatters [] :processors default-processors :linters default-linters - :in-background? in-background? - :intersperse-newlines? true)) + :in-background? in-background?)) diff --git a/src/formatting_stack/reporter.clj b/src/formatting_stack/reporter.clj new file mode 100644 index 00000000..6700e760 --- /dev/null +++ b/src/formatting_stack/reporter.clj @@ -0,0 +1,25 @@ +(ns formatting-stack.reporter) + +(def ansi-colors + {:reset "[0m" + :red "[031m" + :green "[032m" + :cyan "[036m" + :grey "[037m"}) + +(defn colorize [s color] + (str \u001b (ansi-colors color) s \u001b (ansi-colors :reset))) + +(defn print-report [report] + (->> (group-by :filename report) + (into (sorted-map-by compare)) ;; sort filenames for consistent output + (run! (fn [[title warnings]] + (println (colorize title :cyan)) + (doseq [{:keys [msg column line linter] :as warn} (sort-by :line warnings)] + (println (colorize (format "%3d:%-3d" line column) :grey) + (format "%-120.120s" msg) ;; fixme configure 120 + (colorize (str " " linter) :grey))) + (println)))) + + (when (seq report) + (println (colorize (str (count report) " errors found") :red)))) From 9aa519d197d8ceab11a164b2d135043a0911c4ec Mon Sep 17 00:00:00 2001 From: Jeroen de Jong Date: Wed, 22 Jan 2020 00:19:44 +0100 Subject: [PATCH 11/52] Return nil from linter/processors for now at least --- src/formatting_stack/defaults.clj | 1 + src/formatting_stack/formatters/clean_ns.clj | 3 ++- src/formatting_stack/formatters/cljfmt.clj | 3 ++- src/formatting_stack/formatters/how_to_ns.clj | 3 ++- src/formatting_stack/formatters/newlines.clj | 3 ++- src/formatting_stack/formatters/no_extra_blank_lines.clj | 3 ++- src/formatting_stack/formatters/trivial_ns_duplicates.clj | 3 ++- src/formatting_stack/processors/test_runner.clj | 3 ++- src/formatting_stack/protocols/formatter.clj | 2 +- src/formatting_stack/protocols/processor.clj | 2 +- 10 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/formatting_stack/defaults.clj b/src/formatting_stack/defaults.clj index 25ba2831..26fafb80 100644 --- a/src/formatting_stack/defaults.clj +++ b/src/formatting_stack/defaults.clj @@ -20,6 +20,7 @@ (def extended-strategies [strategies/git-completely-staged strategies/git-not-completely-staged]) +;; fixme use assoc because new doesn't allow extra keys (defn default-formatters [third-party-indent-specs] (let [opts {:third-party-indent-specs third-party-indent-specs} ;; the following exists (for now) to guarantee that how-to-ns uses cached git results from cljfmt. diff --git a/src/formatting_stack/formatters/clean_ns.clj b/src/formatting_stack/formatters/clean_ns.clj index af47b94b..abd203af 100644 --- a/src/formatting_stack/formatters/clean_ns.clj +++ b/src/formatting_stack/formatters/clean_ns.clj @@ -68,7 +68,8 @@ refactor-nrepl-opts namespaces-that-should-never-cleaned libspec-whitelist - filename)))))) + filename))))) + nil) (defn new [{:keys [refactor-nrepl-opts libspec-whitelist how-to-ns-opts namespaces-that-should-never-cleaned] :or {namespaces-that-should-never-cleaned default-namespaces-that-should-never-cleaned diff --git a/src/formatting_stack/formatters/cljfmt.clj b/src/formatting_stack/formatters/cljfmt.clj index 2c922d21..feea8c73 100644 --- a/src/formatting_stack/formatters/cljfmt.clj +++ b/src/formatting_stack/formatters/cljfmt.clj @@ -11,7 +11,8 @@ (->> files (process-in-parallel! (fn [filename] (let [indents (impl/cljfmt-indents-for filename third-party-indent-specs)] - (cljfmt.main/fix [filename] {:indents indents})))))) + (cljfmt.main/fix [filename] {:indents indents}))))) + nil) (speced/defn new [{:keys [third-party-indent-specs] :as options}] (implement options diff --git a/src/formatting_stack/formatters/how_to_ns.clj b/src/formatting_stack/formatters/how_to_ns.clj index dc34ef17..eaa0907e 100644 --- a/src/formatting_stack/formatters/how_to_ns.clj +++ b/src/formatting_stack/formatters/how_to_ns.clj @@ -18,7 +18,8 @@ (defn format! [{:keys [how-to-ns-options]} files] (->> (remove #(str/ends-with? % ".edn") files) (process-in-parallel! (fn [filename] - (how-to-ns.main/fix [filename] how-to-ns-options))))) + (how-to-ns.main/fix [filename] how-to-ns-options)))) + nil) (defn new [{:keys [how-to-ns-options] :or {how-to-ns-options {}}}] diff --git a/src/formatting_stack/formatters/newlines.clj b/src/formatting_stack/formatters/newlines.clj index d4d1d601..40b70f7e 100644 --- a/src/formatting_stack/formatters/newlines.clj +++ b/src/formatting_stack/formatters/newlines.clj @@ -10,7 +10,8 @@ (with-out-str ;; Supress "All newlines are good, nothing to fix." (->> files (process-in-parallel! (fn [filename] - (impl/so-fix-them [filename] :expected-newline-count expected-newline-count)))))) + (impl/so-fix-them [filename] :expected-newline-count expected-newline-count))))) + nil) (speced/defn new [{:keys [^pos-int? expected-newline-count] :or {expected-newline-count 1}}] diff --git a/src/formatting_stack/formatters/no_extra_blank_lines.clj b/src/formatting_stack/formatters/no_extra_blank_lines.clj index c03746c4..a5c02073 100644 --- a/src/formatting_stack/formatters/no_extra_blank_lines.clj +++ b/src/formatting_stack/formatters/no_extra_blank_lines.clj @@ -18,7 +18,8 @@ formatted (without-extra-newlines contents)] (when-not (= contents formatted) (println "Removing extra blank lines:" filename) - (spit filename formatted))))))) + (spit filename formatted)))))) + nil) (defn new [] (implement {} diff --git a/src/formatting_stack/formatters/trivial_ns_duplicates.clj b/src/formatting_stack/formatters/trivial_ns_duplicates.clj index 2234117e..28417a8c 100644 --- a/src/formatting_stack/formatters/trivial_ns_duplicates.clj +++ b/src/formatting_stack/formatters/trivial_ns_duplicates.clj @@ -142,7 +142,8 @@ (speced/fn ^{::speced/spec (complement #{"nil"})} [ns-form] (some-> ns-form remove-exact-duplicates pr-str)) "Removing trivial duplicates in `ns` form:" - how-to-ns-opts)))))) + how-to-ns-opts))))) + nil) (defn new [{:keys [how-to-ns-opts] :or {how-to-ns-opts {}}}] diff --git a/src/formatting_stack/processors/test_runner.clj b/src/formatting_stack/processors/test_runner.clj index 7462e066..43968b4b 100644 --- a/src/formatting_stack/processors/test_runner.clj +++ b/src/formatting_stack/processors/test_runner.clj @@ -18,7 +18,8 @@ (testable-namespaces) (map ns->sym) (seq))] - (apply clojure.test/run-tests test-namespaces))) + (apply clojure.test/run-tests test-namespaces)) + nil) (defn test! "Convenience function provided in case it is desired to leverage this ns's functionality, diff --git a/src/formatting_stack/protocols/formatter.clj b/src/formatting_stack/protocols/formatter.clj index 2c0f9fdb..fc1b0f7f 100644 --- a/src/formatting_stack/protocols/formatter.clj +++ b/src/formatting_stack/protocols/formatter.clj @@ -8,5 +8,5 @@ Normally it's a wrapper around a formatting library, with extra configuration, performance improvements, etc." - (format! [this, ^::protocols.spec/filenames filenames] + (^nil? format! [this, ^::protocols.spec/filenames filenames] "Formats `filenames` according to a formatter of your choice.")) diff --git a/src/formatting_stack/protocols/processor.clj b/src/formatting_stack/protocols/processor.clj index 3e5a0f52..c29c79e0 100644 --- a/src/formatting_stack/protocols/processor.clj +++ b/src/formatting_stack/protocols/processor.clj @@ -6,6 +6,6 @@ (speced/defprotocol Processor "Any file-processing component that isn't a formatter or a linter." - (process! [this, ^::protocols.spec/filenames filenames] + (^nil? process! [this, ^::protocols.spec/filenames filenames] "Performs a compilation according to a processor of your choice: e.g. the ClojureScript processor, or Garden, Stefon, etc. You are free to ignore `filenames`, compiling the whole project instead.")) From b31b93fc95f3ccfdbf5056aac5a33858989ec7b2 Mon Sep 17 00:00:00 2001 From: Jeroen de Jong Date: Wed, 22 Jan 2020 00:20:54 +0100 Subject: [PATCH 12/52] Add Reporter specs and protocol --- src/formatting_stack/core.clj | 5 +- src/formatting_stack/protocols/linter.clj | 2 +- src/formatting_stack/protocols/reporter.clj | 10 ++++ src/formatting_stack/protocols/spec.clj | 38 ++++++++++++- src/formatting_stack/reporter.clj | 25 -------- .../reporters/pretty_printer.clj | 57 +++++++++++++++++++ 6 files changed, 108 insertions(+), 29 deletions(-) create mode 100644 src/formatting_stack/protocols/reporter.clj delete mode 100644 src/formatting_stack/reporter.clj create mode 100644 src/formatting_stack/reporters/pretty_printer.clj diff --git a/src/formatting_stack/core.clj b/src/formatting_stack/core.clj index db9a11d0..c89acb56 100644 --- a/src/formatting_stack/core.clj +++ b/src/formatting_stack/core.clj @@ -7,7 +7,7 @@ [formatting-stack.protocols.formatter :as protocols.formatter] [formatting-stack.protocols.linter :as protocols.linter] [formatting-stack.protocols.processor :as protocols.processor] - [formatting-stack.reporter :as reporter] + [formatting-stack.protocols.reporter :refer [report]] [formatting-stack.util :refer [with-serialized-output]] [nedap.utils.modular.api :refer [implement]])) @@ -50,6 +50,7 @@ formatters linters processors + reporter in-background?]}] ;; the following `or` clauses ensure that Components don't pass nil values (let [strategies (or strategies default-strategies) @@ -66,7 +67,7 @@ impl (bound-fn [] ;; important that it's a bound-fn (for an undetermined reason) (process! protocols.formatter/format! formatters formatters-strategies strategies) (->> (process! protocols.linter/lint! linters linters-strategies strategies) - reporter/print-report) + (report reporter)) (process! protocols.processor/process! processors processors-strategies strategies))] (if in-background? (do diff --git a/src/formatting_stack/protocols/linter.clj b/src/formatting_stack/protocols/linter.clj index 70d36238..98d7c104 100644 --- a/src/formatting_stack/protocols/linter.clj +++ b/src/formatting_stack/protocols/linter.clj @@ -8,5 +8,5 @@ Normally it's a wrapper around a linting library, with extra configuration, performance improvements, etc." - (lint! [this, ^::protocols.spec/filenames filenames] + (^::protocols.spec/reports lint! [this, ^::protocols.spec/filenames filenames] "Lints `filenames` according to a linter of your choice: e.g. Eastwood, or Kibit, lein-dependency-check, etc.")) diff --git a/src/formatting_stack/protocols/reporter.clj b/src/formatting_stack/protocols/reporter.clj new file mode 100644 index 00000000..2bd2f5db --- /dev/null +++ b/src/formatting_stack/protocols/reporter.clj @@ -0,0 +1,10 @@ +(ns formatting-stack.protocols.reporter + (:require + [formatting-stack.protocols.spec :as protocols.spec] + [nedap.speced.def :as speced])) + +(speced/defprotocol Reporter + "A Reporter prints (or writes) info coming from other members, such as Formatters, Linters, etc." + + (report [this, ^::protocols.spec/reports reports] + "Emits a report, out of the `reports` argument (namely a collection of discrete actionable items).")) diff --git a/src/formatting_stack/protocols/spec.clj b/src/formatting_stack/protocols/spec.clj index e4606a7b..a9e3ee0f 100644 --- a/src/formatting_stack/protocols/spec.clj +++ b/src/formatting_stack/protocols/spec.clj @@ -3,4 +3,40 @@ [clojure.spec.alpha :as spec] [nedap.utils.spec.predicates :refer [present-string?]])) -(spec/def ::filenames (spec/coll-of present-string?)) +(spec/def ::filename present-string?) +(spec/def ::filenames (spec/coll-of ::filename)) + +(spec/def ::msg present-string?) +(spec/def ::linter ;; fixme, should be generic. ::source ? + (fn [x] + (and (keyword? x) + (namespace x)))) + +(spec/def ::column + (fn [x] + (or (zero? x) + (pos-int? x)))) + +(spec/def ::line ::column) +(spec/def ::level #{:warning :error :exception :info}) + +(defmulti reportmm :level) +(defmethod reportmm :exception [_] + (spec/keys :req-un [::msg + ::level] + :opt-un [::column + ::linter + ::filename + ::line])) +(defmethod reportmm :default [_] + (spec/keys :req-un [::filename + ::linter + ::msg + ::level] + :opt-un [::column + ::line])) + +(spec/def ::report + (spec/multi-spec reportmm :level)) + +(spec/def ::reports (spec/coll-of ::report)) diff --git a/src/formatting_stack/reporter.clj b/src/formatting_stack/reporter.clj deleted file mode 100644 index 6700e760..00000000 --- a/src/formatting_stack/reporter.clj +++ /dev/null @@ -1,25 +0,0 @@ -(ns formatting-stack.reporter) - -(def ansi-colors - {:reset "[0m" - :red "[031m" - :green "[032m" - :cyan "[036m" - :grey "[037m"}) - -(defn colorize [s color] - (str \u001b (ansi-colors color) s \u001b (ansi-colors :reset))) - -(defn print-report [report] - (->> (group-by :filename report) - (into (sorted-map-by compare)) ;; sort filenames for consistent output - (run! (fn [[title warnings]] - (println (colorize title :cyan)) - (doseq [{:keys [msg column line linter] :as warn} (sort-by :line warnings)] - (println (colorize (format "%3d:%-3d" line column) :grey) - (format "%-120.120s" msg) ;; fixme configure 120 - (colorize (str " " linter) :grey))) - (println)))) - - (when (seq report) - (println (colorize (str (count report) " errors found") :red)))) diff --git a/src/formatting_stack/reporters/pretty_printer.clj b/src/formatting_stack/reporters/pretty_printer.clj new file mode 100644 index 00000000..800cd3ae --- /dev/null +++ b/src/formatting_stack/reporters/pretty_printer.clj @@ -0,0 +1,57 @@ +(ns formatting-stack.reporters.pretty-printer + (:require + [nedap.utils.modular.api :refer [implement]] + [medley.core :refer [map-vals]] + [formatting-stack.protocols.reporter :as reporter])) + +;; fixme move to util +(def ansi-colors + {:reset "[0m" + :red "[031m" + :green "[032m" + :yellow "[033m" + :cyan "[036m" + :grey "[037m"}) + +(defn colorize [s color] + (str \u001b (ansi-colors color) s \u001b (ansi-colors :reset))) + +;; fixme split into separate parts +(defn print-report [{:keys [max-msg-length]} reports] + (->> (filter (fn [{:keys [level]}] (#{:error :warning} level)) reports) + (group-by :filename) + (into (sorted-map-by compare)) ;; sort filenames for consistent output + (run! (fn [[title warnings]] + (println (colorize title :cyan)) + (doseq [{:keys [msg column line linter level]} (sort-by :line warnings)] + (println (case level + :error (colorize "ˣ" :red) + :warning (colorize "⚠" :yellow)) + (if (and line column) + (colorize (format "%3d:%-3d" line column) :grey) + "") + (format (str "%-" max-msg-length "." max-msg-length "s") msg) + (colorize (str " " linter) :grey))) + (println)))) + + (->> (filter (fn [{:keys [level]}] (#{:exception} level)) reports) + (group-by :level) + (run! (fn [[_ exceptions]] + (println (colorize (str (count exceptions) " exceptions occurred") :red)) + (doseq [{:keys [msg]} exceptions] + (println msg) + (println))))) + + (doseq [[level amount] (select-keys (->> (group-by :level reports) + (map-vals count)) + #{:error, :warning})] + (when-not (zero? amount) + (println (colorize (str (count reports) " " (name level) "s found") + (case level + :error :red + :warning :yellow)))))) + +(defn new [{:keys [max-msg-length] + :or {max-msg-length 120}}] + (implement {:max-msg-length max-msg-length} + reporter/--report print-report)) From 325cfc9abe33546de37a4edaffcaed84af8875b6 Mon Sep 17 00:00:00 2001 From: Jeroen de Jong Date: Wed, 22 Jan 2020 00:21:04 +0100 Subject: [PATCH 13/52] Add :level to linter-reports --- src/formatting_stack/linters/eastwood.clj | 3 ++- src/formatting_stack/linters/line_length.clj | 1 + src/formatting_stack/linters/loc_per_ns.clj | 1 + src/formatting_stack/linters/ns_aliases.clj | 2 ++ src/formatting_stack/project_formatter.clj | 6 ++++++ 5 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/formatting_stack/linters/eastwood.clj b/src/formatting_stack/linters/eastwood.clj index afeaed2e..36337e53 100644 --- a/src/formatting_stack/linters/eastwood.clj +++ b/src/formatting_stack/linters/eastwood.clj @@ -45,7 +45,8 @@ (map (fn [{:keys [uri-or-file-name] :as m}] (-> m (update :linter (fn [k] (keyword "eastwood" (name k)))) - (assoc :filename (if (string? uri-or-file-name) + (assoc :level :warning + :filename (if (string? uri-or-file-name) uri-or-file-name (str/replace (-> uri-or-file-name .getPath) root-dir diff --git a/src/formatting_stack/linters/line_length.clj b/src/formatting_stack/linters/line_length.clj index 958d9dd0..e16cedf7 100644 --- a/src/formatting_stack/linters/line_length.clj +++ b/src/formatting_stack/linters/line_length.clj @@ -11,6 +11,7 @@ (when (< threshold (count row)) {:filename filename :linter :formatting-stack/line-length + :level :warning :column (+ 1 threshold) :line (+ 1 i) :msg (str "Line exceeding " threshold " columns")}))) diff --git a/src/formatting_stack/linters/loc_per_ns.clj b/src/formatting_stack/linters/loc_per_ns.clj index 57cbad75..edb67592 100644 --- a/src/formatting_stack/linters/loc_per_ns.clj +++ b/src/formatting_stack/linters/loc_per_ns.clj @@ -18,6 +18,7 @@ (when (overly-long-ns? filename max-lines-per-ns) {:filename filename :linter :formatting-stack/loc-per-ns + :level :warning :msg (str "Longer than " max-lines-per-ns " LOC. consider refactoring") :line (+ 1 max-lines-per-ns) ;; first line after limit is the issue :column 1}))) diff --git a/src/formatting_stack/linters/ns_aliases.clj b/src/formatting_stack/linters/ns_aliases.clj index 886b701f..b9732ec1 100644 --- a/src/formatting_stack/linters/ns_aliases.clj +++ b/src/formatting_stack/linters/ns_aliases.clj @@ -92,6 +92,8 @@ {:filename filename :line (:line (meta bad-alias)) :column (:column (meta bad-alias)) + :level :warning + :w (throw (ex-info "wat" {:pa :tat})) ;; fixme remove, testing :warning-details-url "https://stuartsierra.com/2015/05/10/clojure-namespace-aliases" :msg (str bad-alias " is not a derived alias") :linter :formatting-stack/ns-aliases}))))) diff --git a/src/formatting_stack/project_formatter.clj b/src/formatting_stack/project_formatter.clj index b4f233ea..414c0559 100644 --- a/src/formatting_stack/project_formatter.clj +++ b/src/formatting_stack/project_formatter.clj @@ -16,12 +16,16 @@ [formatting-stack.linters.ns-aliases :as linters.ns-aliases] [formatting-stack.linters.one-resource-per-ns :as linters.one-resource-per-ns] [formatting-stack.processors.cider :as processors.cider] + [formatting-stack.reporters.pretty-printer :as pretty-printer] [formatting-stack.strategies :as strategies])) (def third-party-indent-specs formatting-stack.indent-specs/default-third-party-indent-specs) (def default-strategies [strategies/all-files]) +(def default-reporter + (pretty-printer/new {})) + (def default-formatters (->> [(formatters.cljfmt/new {:third-party-indent-specs third-party-indent-specs}) (-> (formatters.how-to-ns/new {}) @@ -82,6 +86,7 @@ (formatting-stack.core/format! :strategies default-strategies :formatters default-formatters :linters default-linters + :reporter default-reporter :processors default-processors :in-background? in-background?)) @@ -90,5 +95,6 @@ (formatting-stack.core/format! :strategies default-strategies :formatters [] :processors default-processors + :reporter default-reporter :linters default-linters :in-background? in-background?)) From 03405cee02685a7a77e5d95319abe3987bfbcf87 Mon Sep 17 00:00:00 2001 From: Jeroen de Jong Date: Wed, 22 Jan 2020 00:25:43 +0100 Subject: [PATCH 14/52] Present exceptions as a regular report --- src/formatting_stack/core.clj | 23 +++++++++---------- src/formatting_stack/protocols/spec.clj | 12 ++++------ .../reporters/pretty_printer.clj | 4 +--- 3 files changed, 16 insertions(+), 23 deletions(-) diff --git a/src/formatting_stack/core.clj b/src/formatting_stack/core.clj index c89acb56..48488f83 100644 --- a/src/formatting_stack/core.clj +++ b/src/formatting_stack/core.clj @@ -35,15 +35,13 @@ (try (->> strategies files (method member)) (catch Exception e - (println "Encountered an exception, which will be printed in the next line." - "formatting-stack execution has *not* been aborted.") - (-> e .printStackTrace) - nil) + [{:msg (str "Encountered an exception, which will be printed in the next line.\n" + (with-out-str (clojure.stacktrace/print-stack-trace e))) + :level :exception}]) (catch AssertionError e - (println "Encountered an exception, which will be printed in the next line." - "formatting-stack execution has *not* been aborted.") - (-> e .printStackTrace) - nil))))))))) + [{:msg (str "Encountered an exception, which will be printed in the next line.\n" + (with-out-str (clojure.stacktrace/print-stack-trace e))) + :level :exception}]))))))))) (defn format! [& {:keys [strategies third-party-indent-specs @@ -65,10 +63,11 @@ 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) - (->> (process! protocols.linter/lint! linters linters-strategies strategies) - (report reporter)) - (process! protocols.processor/process! processors processors-strategies strategies))] + (->> [(process! protocols.formatter/format! formatters formatters-strategies strategies) + (process! protocols.linter/lint! linters linters-strategies strategies) + (process! protocols.processor/process! processors processors-strategies strategies)] + (mapcat identity) + (report reporter)))] (if in-background? (do (reset! formatting-stack.background/workload impl) diff --git a/src/formatting_stack/protocols/spec.clj b/src/formatting_stack/protocols/spec.clj index a9e3ee0f..a91ce219 100644 --- a/src/formatting_stack/protocols/spec.clj +++ b/src/formatting_stack/protocols/spec.clj @@ -18,22 +18,18 @@ (pos-int? x)))) (spec/def ::line ::column) -(spec/def ::level #{:warning :error :exception :info}) +(spec/def ::level #{:warning :error :exception}) (defmulti reportmm :level) (defmethod reportmm :exception [_] (spec/keys :req-un [::msg - ::level] - :opt-un [::column - ::linter - ::filename - ::line])) + ::level])) (defmethod reportmm :default [_] (spec/keys :req-un [::filename ::linter ::msg - ::level] - :opt-un [::column + ::level + ::column ::line])) (spec/def ::report diff --git a/src/formatting_stack/reporters/pretty_printer.clj b/src/formatting_stack/reporters/pretty_printer.clj index 800cd3ae..e34a9fb2 100644 --- a/src/formatting_stack/reporters/pretty_printer.clj +++ b/src/formatting_stack/reporters/pretty_printer.clj @@ -27,9 +27,7 @@ (println (case level :error (colorize "ˣ" :red) :warning (colorize "⚠" :yellow)) - (if (and line column) - (colorize (format "%3d:%-3d" line column) :grey) - "") + (colorize (format "%3d:%-3d" line column) :grey) (format (str "%-" max-msg-length "." max-msg-length "s") msg) (colorize (str " " linter) :grey))) (println)))) From 9bd4036ee80e411f205d58aaabc5fbaae527049a Mon Sep 17 00:00:00 2001 From: Jeroen de Jong Date: Mon, 27 Jan 2020 20:59:37 +0100 Subject: [PATCH 15/52] Handle exceptions as reports --- src/formatting_stack/branch_formatter.clj | 6 +++ src/formatting_stack/core.clj | 6 +-- src/formatting_stack/linters/line_length.clj | 4 +- src/formatting_stack/linters/ns_aliases.clj | 5 +- .../reporters/pretty_printer.clj | 49 ++++++++++--------- src/formatting_stack/util.clj | 19 ++----- 6 files changed, 44 insertions(+), 45 deletions(-) diff --git a/src/formatting_stack/branch_formatter.clj b/src/formatting_stack/branch_formatter.clj index 6855c998..9de10d36 100644 --- a/src/formatting_stack/branch_formatter.clj +++ b/src/formatting_stack/branch_formatter.clj @@ -16,6 +16,7 @@ [formatting-stack.linters.ns-aliases :as linters.ns-aliases] [formatting-stack.linters.one-resource-per-ns :as linters.one-resource-per-ns] [formatting-stack.processors.cider :as processors.cider] + [formatting-stack.reporters.pretty-printer :as pretty-printer] [formatting-stack.strategies :as strategies] [medley.core :refer [mapply]])) @@ -76,6 +77,9 @@ (def default-processors [(processors.cider/new {:third-party-indent-specs third-party-indent-specs})]) +(def default-reporter + (pretty-printer/new {})) + (defn format-and-lint-branch! [& {:keys [target-branch in-background?] :or {target-branch "master" in-background? (not (System/getenv "CI"))}}] @@ -86,6 +90,7 @@ (formatting-stack.core/format! :strategies default-strategies :processors default-processors :formatters formatters + :reporter default-reporter :linters linters :in-background? in-background?))) @@ -97,5 +102,6 @@ (formatting-stack.core/format! :strategies default-strategies :formatters [] :processors default-processors + :reporter default-reporter :linters linters :in-background? in-background?))) diff --git a/src/formatting_stack/core.clj b/src/formatting_stack/core.clj index 48488f83..cbe2eaff 100644 --- a/src/formatting_stack/core.clj +++ b/src/formatting_stack/core.clj @@ -35,12 +35,10 @@ (try (->> strategies files (method member)) (catch Exception e - [{:msg (str "Encountered an exception, which will be printed in the next line.\n" - (with-out-str (clojure.stacktrace/print-stack-trace e))) + [{:exception e :level :exception}]) (catch AssertionError e - [{:msg (str "Encountered an exception, which will be printed in the next line.\n" - (with-out-str (clojure.stacktrace/print-stack-trace e))) + [{:exception e :level :exception}]))))))))) (defn format! [& {:keys [strategies diff --git a/src/formatting_stack/linters/line_length.clj b/src/formatting_stack/linters/line_length.clj index e16cedf7..87e8bf57 100644 --- a/src/formatting_stack/linters/line_length.clj +++ b/src/formatting_stack/linters/line_length.clj @@ -2,7 +2,7 @@ (:require [clojure.string :as string] [formatting-stack.protocols.linter :as linter] - [formatting-stack.util :refer [process-in-parallel!]] + [formatting-stack.util :refer [process-in-parallel! ensure-coll]] [nedap.utils.modular.api :refer [implement]])) (defn exceeding-lines [threshold filename] @@ -20,7 +20,7 @@ (defn lint! [{:keys [max-line-length]} filenames] (->> filenames (process-in-parallel! (partial exceeding-lines max-line-length)) - (mapcat identity))) + (mapcat ensure-coll))) (defn new [{:keys [max-line-length] :or {max-line-length 130}}] diff --git a/src/formatting_stack/linters/ns_aliases.clj b/src/formatting_stack/linters/ns_aliases.clj index b9732ec1..cb222f31 100644 --- a/src/formatting_stack/linters/ns_aliases.clj +++ b/src/formatting_stack/linters/ns_aliases.clj @@ -6,7 +6,7 @@ [clojure.tools.namespace.parse :as parse] [clojure.tools.reader.reader-types :refer [indexing-push-back-reader]] [formatting-stack.protocols.linter :as linter] - [formatting-stack.util :refer [process-in-parallel!]] + [formatting-stack.util :refer [process-in-parallel! ensure-coll]] [nedap.utils.modular.api :refer [implement]]) (:import (java.io PushbackReader))) @@ -93,11 +93,10 @@ :line (:line (meta bad-alias)) :column (:column (meta bad-alias)) :level :warning - :w (throw (ex-info "wat" {:pa :tat})) ;; fixme remove, testing :warning-details-url "https://stuartsierra.com/2015/05/10/clojure-namespace-aliases" :msg (str bad-alias " is not a derived alias") :linter :formatting-stack/ns-aliases}))))) - (mapcat identity))) + (mapcat ensure-coll))) (defn new [{:keys [acceptable-aliases-whitelist] :or {acceptable-aliases-whitelist default-acceptable-aliases-whitelist}}] diff --git a/src/formatting_stack/reporters/pretty_printer.clj b/src/formatting_stack/reporters/pretty_printer.clj index e34a9fb2..c997b557 100644 --- a/src/formatting_stack/reporters/pretty_printer.clj +++ b/src/formatting_stack/reporters/pretty_printer.clj @@ -17,13 +17,23 @@ (str \u001b (ansi-colors color) s \u001b (ansi-colors :reset))) ;; fixme split into separate parts -(defn print-report [{:keys [max-msg-length]} reports] +(defn print-report [{:keys [max-msg-length print-stacktraces?]} reports] + (->> (filter (fn [{:keys [level]}] (#{:exception} level)) reports) + (group-by :filename) + (run! (fn [[title reports]] + (println (colorize title :cyan)) + (doseq [{:keys [^Throwable exception]} reports] + (if print-stacktraces? + (clojure.stacktrace/print-stack-trace exception) + (println (ex-message exception))) + (println))))) + (->> (filter (fn [{:keys [level]}] (#{:error :warning} level)) reports) (group-by :filename) (into (sorted-map-by compare)) ;; sort filenames for consistent output - (run! (fn [[title warnings]] + (run! (fn [[title reports]] (println (colorize title :cyan)) - (doseq [{:keys [msg column line linter level]} (sort-by :line warnings)] + (doseq [{:keys [msg column line linter level]} (sort-by :line reports)] (println (case level :error (colorize "ˣ" :red) :warning (colorize "⚠" :yellow)) @@ -32,24 +42,19 @@ (colorize (str " " linter) :grey))) (println)))) - (->> (filter (fn [{:keys [level]}] (#{:exception} level)) reports) - (group-by :level) - (run! (fn [[_ exceptions]] - (println (colorize (str (count exceptions) " exceptions occurred") :red)) - (doseq [{:keys [msg]} exceptions] - (println msg) - (println))))) - - (doseq [[level amount] (select-keys (->> (group-by :level reports) - (map-vals count)) - #{:error, :warning})] - (when-not (zero? amount) - (println (colorize (str (count reports) " " (name level) "s found") - (case level - :error :red - :warning :yellow)))))) + ;; fixme dedupe + (let [summary (->> (group-by :level reports) + (map-vals count))] + (when-let [exceptions (:exception summary)] + (println (colorize (str exceptions " exceptions occurred") :red))) + (when-let [error (:error summary)] + (println (colorize (str error " errors found") :red))) + (when-let [warning (:warning summary)] + (println (colorize (str warning " warnings found") :yellow))))) -(defn new [{:keys [max-msg-length] - :or {max-msg-length 120}}] - (implement {:max-msg-length max-msg-length} +(defn new [{:keys [max-msg-length print-stacktraces?] + :or {max-msg-length 120 + print-stacktraces? true}}] + (implement {:max-msg-length max-msg-length + :print-stacktraces? print-stacktraces?} reporter/--report print-report)) diff --git a/src/formatting_stack/util.clj b/src/formatting_stack/util.clj index 45149ed2..552e8d95 100644 --- a/src/formatting_stack/util.clj +++ b/src/formatting_stack/util.clj @@ -55,19 +55,10 @@ ~@forms)) (defn report-processing-error [^Throwable e filename] - (let [s (->> e - .getStackTrace - (map (fn [x] - (str " " x))) - (interpose "\n"))] - (println (apply str - "Encountered an exception, processing file: " - filename - ". The exception will be printed in the next line. " - "formatting-stack execution has *not* been aborted.\n" - (-> e .getMessage) - "\n" - s)))) + {:level :exception + :filename filename + :msg "Encountered an exception" + :exception e}) (defn process-in-parallel! [f files] (->> files @@ -101,6 +92,6 @@ false))) (speced/defn ensure-coll [^some? x] - (if (coll? x) + (if (sequential? x) x [x])) From 3024ee9444c3a00255b609d1c2ddf170d738b8fc Mon Sep 17 00:00:00 2001 From: Jeroen de Jong Date: Mon, 27 Jan 2020 21:23:33 +0100 Subject: [PATCH 16/52] Rename :linter to :source --- src/formatting_stack/core.clj | 4 ++++ src/formatting_stack/linters/eastwood.clj | 21 ++++++++++--------- src/formatting_stack/linters/kondo.clj | 9 ++++---- src/formatting_stack/linters/line_length.clj | 2 +- src/formatting_stack/linters/loc_per_ns.clj | 2 +- src/formatting_stack/linters/ns_aliases.clj | 2 +- src/formatting_stack/protocols/spec.clj | 10 ++++++--- .../reporters/pretty_printer.clj | 4 ++-- src/formatting_stack/util.clj | 1 + 9 files changed, 32 insertions(+), 23 deletions(-) diff --git a/src/formatting_stack/core.clj b/src/formatting_stack/core.clj index cbe2eaff..2a63b1c7 100644 --- a/src/formatting_stack/core.clj +++ b/src/formatting_stack/core.clj @@ -36,9 +36,13 @@ (->> strategies files (method member)) (catch Exception e [{:exception e + :source :formatting-stack/process! + :msg (str "Exception during " member) :level :exception}]) (catch AssertionError e [{:exception e + :source :formatting-stack/process! + :msg (str "Exception during " member) :level :exception}]))))))))) (defn format! [& {:keys [strategies diff --git a/src/formatting_stack/linters/eastwood.clj b/src/formatting_stack/linters/eastwood.clj index 36337e53..ebd963e3 100644 --- a/src/formatting_stack/linters/eastwood.clj +++ b/src/formatting_stack/linters/eastwood.clj @@ -7,7 +7,8 @@ [formatting-stack.util :refer [ns-name-from-filename]] [medley.core :refer [deep-merge]] [nedap.utils.modular.api :refer [implement]]) - (:import (java.io File))) + (:import + (java.io File))) (def default-eastwood-options ;; Avoid false positives or more-annoying-than-useful checks: @@ -42,15 +43,15 @@ (->TrackingReporter reports))) (->> (:warnings @reports) (map :warn-data) - (map (fn [{:keys [uri-or-file-name] :as m}] - (-> m - (update :linter (fn [k] (keyword "eastwood" (name k)))) - (assoc :level :warning - :filename (if (string? uri-or-file-name) - uri-or-file-name - (str/replace (-> uri-or-file-name .getPath) - root-dir - ""))))))))) + (map (fn [{:keys [uri-or-file-name linter] :as m}] + (assoc m + :level :warning + :source (keyword "eastwood" (str linter)) + :filename (if (string? uri-or-file-name) + uri-or-file-name + (str/replace (-> uri-or-file-name .getPath) + root-dir + "")))))))) (defn new [{:keys [eastwood-options] :or {eastwood-options {}}}] diff --git a/src/formatting_stack/linters/kondo.clj b/src/formatting_stack/linters/kondo.clj index a4eeb061..3717a11f 100644 --- a/src/formatting_stack/linters/kondo.clj +++ b/src/formatting_stack/linters/kondo.clj @@ -1,10 +1,10 @@ (ns formatting-stack.linters.kondo (:require [clj-kondo.core :as clj-kondo] + [clojure.set :as set] [formatting-stack.protocols.linter :as linter] [medley.core :refer [deep-merge]] - [nedap.utils.modular.api :refer [implement]] - [clojure.set :as set])) + [nedap.utils.modular.api :refer [implement]])) (def off {:level :off}) @@ -44,12 +44,11 @@ (clj-kondo/run! {:lint cljs-files :config (deep-merge default-options (or kondo-options {}))})] (mapcat :findings) - (map (fn [m] + (map (fn [{:keys [type] :as m}] (-> (set/rename-keys m {:row :line :message :msg - :type :linter :col :column}) - (update :linter (fn [k] (keyword "kondo" (name k)))))))))) + (assoc :source (keyword "kondo" (name type))))))))) (defn new [] (implement {} diff --git a/src/formatting_stack/linters/line_length.clj b/src/formatting_stack/linters/line_length.clj index 87e8bf57..9334cb39 100644 --- a/src/formatting_stack/linters/line_length.clj +++ b/src/formatting_stack/linters/line_length.clj @@ -10,7 +10,7 @@ (map-indexed (fn [i row] (when (< threshold (count row)) {:filename filename - :linter :formatting-stack/line-length + :source :formatting-stack/line-length :level :warning :column (+ 1 threshold) :line (+ 1 i) diff --git a/src/formatting_stack/linters/loc_per_ns.clj b/src/formatting_stack/linters/loc_per_ns.clj index edb67592..1418c3d3 100644 --- a/src/formatting_stack/linters/loc_per_ns.clj +++ b/src/formatting_stack/linters/loc_per_ns.clj @@ -17,7 +17,7 @@ (process-in-parallel! (fn [filename] (when (overly-long-ns? filename max-lines-per-ns) {:filename filename - :linter :formatting-stack/loc-per-ns + :source :formatting-stack/loc-per-ns :level :warning :msg (str "Longer than " max-lines-per-ns " LOC. consider refactoring") :line (+ 1 max-lines-per-ns) ;; first line after limit is the issue diff --git a/src/formatting_stack/linters/ns_aliases.clj b/src/formatting_stack/linters/ns_aliases.clj index cb222f31..88208494 100644 --- a/src/formatting_stack/linters/ns_aliases.clj +++ b/src/formatting_stack/linters/ns_aliases.clj @@ -95,7 +95,7 @@ :level :warning :warning-details-url "https://stuartsierra.com/2015/05/10/clojure-namespace-aliases" :msg (str bad-alias " is not a derived alias") - :linter :formatting-stack/ns-aliases}))))) + :source :formatting-stack/ns-aliases}))))) (mapcat ensure-coll))) (defn new [{:keys [acceptable-aliases-whitelist] diff --git a/src/formatting_stack/protocols/spec.clj b/src/formatting_stack/protocols/spec.clj index a91ce219..071818ea 100644 --- a/src/formatting_stack/protocols/spec.clj +++ b/src/formatting_stack/protocols/spec.clj @@ -7,7 +7,7 @@ (spec/def ::filenames (spec/coll-of ::filename)) (spec/def ::msg present-string?) -(spec/def ::linter ;; fixme, should be generic. ::source ? +(spec/def ::source (fn [x] (and (keyword? x) (namespace x)))) @@ -23,10 +23,14 @@ (defmulti reportmm :level) (defmethod reportmm :exception [_] (spec/keys :req-un [::msg - ::level])) + ::exception + ::source + ::level] + :opt-un [::filename])) + (defmethod reportmm :default [_] (spec/keys :req-un [::filename - ::linter + ::source ::msg ::level ::column diff --git a/src/formatting_stack/reporters/pretty_printer.clj b/src/formatting_stack/reporters/pretty_printer.clj index c997b557..8ac52ccb 100644 --- a/src/formatting_stack/reporters/pretty_printer.clj +++ b/src/formatting_stack/reporters/pretty_printer.clj @@ -33,13 +33,13 @@ (into (sorted-map-by compare)) ;; sort filenames for consistent output (run! (fn [[title reports]] (println (colorize title :cyan)) - (doseq [{:keys [msg column line linter level]} (sort-by :line reports)] + (doseq [{:keys [msg column line source level]} (sort-by :line reports)] (println (case level :error (colorize "ˣ" :red) :warning (colorize "⚠" :yellow)) (colorize (format "%3d:%-3d" line column) :grey) (format (str "%-" max-msg-length "." max-msg-length "s") msg) - (colorize (str " " linter) :grey))) + (colorize (str " " source) :grey))) (println)))) ;; fixme dedupe diff --git a/src/formatting_stack/util.clj b/src/formatting_stack/util.clj index 552e8d95..7bea353e 100644 --- a/src/formatting_stack/util.clj +++ b/src/formatting_stack/util.clj @@ -56,6 +56,7 @@ (defn report-processing-error [^Throwable e filename] {:level :exception + :source :formatting-stack/report-processing-error :filename filename :msg "Encountered an exception" :exception e}) From 2cc69d24745aeaaf9f20eab2041d57a665188b43 Mon Sep 17 00:00:00 2001 From: Jeroen de Jong Date: Mon, 27 Jan 2020 21:26:55 +0100 Subject: [PATCH 17/52] Fix docs --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 04ae36a6..94e7452f 100644 --- a/README.md +++ b/README.md @@ -22,8 +22,6 @@ As of today, it is integrated with: * Defaults to processing .cljs files only, given the overlap with Eastwood. * [refactor-nrepl](https://github.com/clojure-emacs/refactor-nrepl) * Used for "clean unused imports" functionality - * [bikeshed](https://github.com/dakrone/lein-bikeshed) - * Used for checking max column count * [all-my-files-should-end-with-exactly-one-newline-character](https://github.com/gfredericks/lein-all-my-files-should-end-with-exactly-one-newline-character) * Configurable, you can ensure either 0 or 1 ending newlines per file. @@ -32,6 +30,7 @@ And it also bundles a few tiny linters of its own: * [loc-per-ns](https://github.com/nedap/formatting-stack/blob/debdab8129dae7779d390216490625a3264c9d2c/src/formatting_stack/linters/loc_per_ns.clj) warns if a given NS surpasses a targeted LOC count. * [ns-aliases](https://github.com/nedap/formatting-stack/blob/debdab8129dae7779d390216490625a3264c9d2c/src/formatting_stack/linters/ns_aliases.clj) warns if [Sierra's](https://stuartsierra.com/2015/05/10/clojure-namespace-aliases) aliasing guide is disregarded. * [one-resource-per-ns](https://github.com/nedap/formatting-stack/blob/master/src/formatting_stack/linters/one_resource_per_ns.clj) warns if a Clojure namespace is defined in more than one file. + * [line-length](https://github.com/nedap/formatting-stack/blob/f1cf4206399a77a83fde4140095d4c59c10b1605/src/formatting_stack/linters/line_length.clj) warns if max line length is reached. It is fully extensible: you can configure the bundled formatters, remove them, and/or add your own. From 28f2277f848127979bbf34fbcd48e3337ab3f91d Mon Sep 17 00:00:00 2001 From: Jeroen de Jong Date: Tue, 28 Jan 2020 08:39:20 +0100 Subject: [PATCH 18/52] Add functional tests for Linter results --- project.clj | 3 +- src/formatting_stack/linters/eastwood.clj | 2 +- src/formatting_stack/linters/kondo.clj | 5 ++-- test-resources/eastwood_warning.clj | 3 ++ test-resources/invalid_syntax.clj | 1 + test-resources/kondo_warning.clj | 4 +++ test-resources/ns_aliases_warning.clj | 3 ++ .../formatting_stack/linters/eastwood.clj | 28 +++++++++++++++++++ .../formatting_stack/linters/kondo.clj | 27 ++++++++++++++++++ .../formatting_stack/linters/line_length.clj | 20 +++++++++++++ .../formatting_stack/linters/loc_per_ns.clj | 20 +++++++++++++ .../formatting_stack/linters/ns_aliases.clj | 26 +++++++++++++++++ 12 files changed, 138 insertions(+), 4 deletions(-) create mode 100644 test-resources/eastwood_warning.clj create mode 100644 test-resources/invalid_syntax.clj create mode 100644 test-resources/kondo_warning.clj create mode 100644 test-resources/ns_aliases_warning.clj create mode 100644 test/functional/formatting_stack/linters/eastwood.clj create mode 100644 test/functional/formatting_stack/linters/kondo.clj create mode 100644 test/functional/formatting_stack/linters/line_length.clj create mode 100644 test/functional/formatting_stack/linters/loc_per_ns.clj create mode 100644 test/functional/formatting_stack/linters/ns_aliases.clj diff --git a/project.clj b/project.clj index 84a9112e..89d1a990 100644 --- a/project.clj +++ b/project.clj @@ -76,7 +76,8 @@ ;; `dev` in :test is important - a test depends on it: :test {:source-paths ["dev"] - :dependencies [[com.nedap.staffing-solutions/utils.test "1.6.2"]] + :dependencies [[com.nedap.staffing-solutions/utils.test "1.6.2"] + [nubank/matcher-combinators "1.0.1"]] :jvm-opts ["-Dclojure.core.async.go-checking=true" "-Duser.language=en-US"] :resource-paths ["test-resources-extra" diff --git a/src/formatting_stack/linters/eastwood.clj b/src/formatting_stack/linters/eastwood.clj index ebd963e3..9b27657f 100644 --- a/src/formatting_stack/linters/eastwood.clj +++ b/src/formatting_stack/linters/eastwood.clj @@ -46,7 +46,7 @@ (map (fn [{:keys [uri-or-file-name linter] :as m}] (assoc m :level :warning - :source (keyword "eastwood" (str linter)) + :source (keyword "eastwood" (name linter)) :filename (if (string? uri-or-file-name) uri-or-file-name (str/replace (-> uri-or-file-name .getPath) diff --git a/src/formatting_stack/linters/kondo.clj b/src/formatting_stack/linters/kondo.clj index 3717a11f..c2e73532 100644 --- a/src/formatting_stack/linters/kondo.clj +++ b/src/formatting_stack/linters/kondo.clj @@ -34,6 +34,7 @@ "CLJ files are also linted by eastwood, disable duplicate linters" {:linters {:misplaced-docstring off :deprecated-var off + :inline-def off :redefined-var off}}) (defn lint! [{:keys [kondo-options]} filenames] @@ -50,6 +51,6 @@ :col :column}) (assoc :source (keyword "kondo" (name type))))))))) -(defn new [] - (implement {} +(defn new [{:keys [kondo-options]}] + (implement {:kondo-options kondo-options} linter/--lint! lint!)) diff --git a/test-resources/eastwood_warning.clj b/test-resources/eastwood_warning.clj new file mode 100644 index 00000000..e3d1f501 --- /dev/null +++ b/test-resources/eastwood_warning.clj @@ -0,0 +1,3 @@ +(ns eastwood-warning) + +(def x (def y ::z)) diff --git a/test-resources/invalid_syntax.clj b/test-resources/invalid_syntax.clj new file mode 100644 index 00000000..6893e8da --- /dev/null +++ b/test-resources/invalid_syntax.clj @@ -0,0 +1 @@ +#{] diff --git a/test-resources/kondo_warning.clj b/test-resources/kondo_warning.clj new file mode 100644 index 00000000..5d94f1b8 --- /dev/null +++ b/test-resources/kondo_warning.clj @@ -0,0 +1,4 @@ +(ns kondo-warning) + +(let [unused ::unused] + ::return) diff --git a/test-resources/ns_aliases_warning.clj b/test-resources/ns_aliases_warning.clj new file mode 100644 index 00000000..d3c1e771 --- /dev/null +++ b/test-resources/ns_aliases_warning.clj @@ -0,0 +1,3 @@ +(ns kondo-warning + (:require + [clojure.string :as foo])) diff --git a/test/functional/formatting_stack/linters/eastwood.clj b/test/functional/formatting_stack/linters/eastwood.clj new file mode 100644 index 00000000..9efdfda0 --- /dev/null +++ b/test/functional/formatting_stack/linters/eastwood.clj @@ -0,0 +1,28 @@ +(ns functional.formatting-stack.linters.eastwood + (:require + [clojure.test :refer :all] + [formatting-stack.linters.eastwood :as sut] + [formatting-stack.protocols.linter :as linter] + [matcher-combinators.matchers :as m] + [matcher-combinators.test :refer [match?]])) + +(deftest lint! + (let [linter (sut/new {})] + (are [filename expected] (match? expected + (linter/lint! linter [filename])) + ;; fixme should return a :reader-exception, currently lost in :note. lint! yields empty list + #_#_ + "test-resources/invalid_syntax.clj" + (m/embeds + [{:level :exception, + :filename "test-resources/invalid_syntax.clj", + :line 3, + :column 2, + :source :eastwood/lint!}]) + + "test-resources/eastwood_warning.clj" + (m/embeds + [{:source :eastwood/def-in-def + :line 3 + :column 13 + :filename "test-resources/eastwood_warning.clj"}])))) diff --git a/test/functional/formatting_stack/linters/kondo.clj b/test/functional/formatting_stack/linters/kondo.clj new file mode 100644 index 00000000..d4b7467d --- /dev/null +++ b/test/functional/formatting_stack/linters/kondo.clj @@ -0,0 +1,27 @@ +(ns functional.formatting-stack.linters.kondo + (:require + [clojure.test :refer :all] + [formatting-stack.linters.kondo :as sut] + [formatting-stack.protocols.linter :as linter] + [matcher-combinators.matchers :as m] + [matcher-combinators.test :refer [match?]])) + +(deftest lint! + (let [linter (sut/new {:kondo-options {:output {:exclude-files []}}})] + (are [filename expected] (match? expected + (linter/lint! linter [filename])) + "test-resources/invalid_syntax.clj" + (m/embeds + [{:level :error, + :filename "test-resources/invalid_syntax.clj", + :line 1, + :column 2, + :source :kondo/syntax}]) + + "test-resources/kondo_warning.clj" + (m/embeds + [{:source :kondo/unused-binding + :level :warning + :line 3 + :column 7 + :filename "test-resources/kondo_warning.clj"}])))) diff --git a/test/functional/formatting_stack/linters/line_length.clj b/test/functional/formatting_stack/linters/line_length.clj new file mode 100644 index 00000000..fcc1c63f --- /dev/null +++ b/test/functional/formatting_stack/linters/line_length.clj @@ -0,0 +1,20 @@ +(ns functional.formatting-stack.linters.line-length + (:require + [clojure.test :refer :all] + [formatting-stack.linters.line-length :as sut] + [formatting-stack.protocols.linter :as linter] + [matcher-combinators.test :refer [match?]])) + +(deftest lint! + (let [linter (sut/new {:max-line-length 22})] + (are [filename expected] (match? expected + (linter/lint! linter [filename])) + "test-resources/invalid_syntax.clj" + [] + + "test-resources/sample_clj_ns.clj" + [{:source :formatting-stack/line-length + :line 3 + :column 23 + :msg "Line exceeding 22 columns" + :filename "test-resources/sample_clj_ns.clj"}]))) diff --git a/test/functional/formatting_stack/linters/loc_per_ns.clj b/test/functional/formatting_stack/linters/loc_per_ns.clj new file mode 100644 index 00000000..28300976 --- /dev/null +++ b/test/functional/formatting_stack/linters/loc_per_ns.clj @@ -0,0 +1,20 @@ +(ns functional.formatting-stack.linters.loc-per-ns + (:require + [clojure.test :refer :all] + [formatting-stack.linters.loc-per-ns :as sut] + [formatting-stack.protocols.linter :as linter] + [matcher-combinators.test :refer [match?]])) + +(deftest lint! + (let [linter (sut/new {:max-lines-per-ns 4})] + (are [filename expected] (match? expected + (linter/lint! linter [filename])) + "test-resources/invalid_syntax.clj" + [] + + "test-resources/sample_clj_ns.clj" + [{:source :formatting-stack/loc-per-ns + :line 5 + :column 1 + :msg "Longer than 4 LOC. consider refactoring" + :filename "test-resources/sample_clj_ns.clj"}]))) diff --git a/test/functional/formatting_stack/linters/ns_aliases.clj b/test/functional/formatting_stack/linters/ns_aliases.clj new file mode 100644 index 00000000..be46ae60 --- /dev/null +++ b/test/functional/formatting_stack/linters/ns_aliases.clj @@ -0,0 +1,26 @@ +(ns functional.formatting-stack.linters.ns-aliases + (:require + [clojure.test :refer :all] + [formatting-stack.linters.ns-aliases :as sut] + [formatting-stack.protocols.linter :as linter] + [matcher-combinators.test :refer [match?]])) + +(deftest lint! + (let [linter (sut/new {:max-lines-per-ns 4})] + (are [filename expected] (match? expected + (linter/lint! linter [filename])) + "test-resources/invalid_syntax.clj" + [{:source :formatting-stack/report-processing-error + :filename "test-resources/invalid_syntax.clj" + :msg "Encountered an exception" + :level :exception + :exception #(instance? Throwable %)}] + + "test-resources/ns_aliases_warning.clj" + [{:source :formatting-stack/ns-aliases + :line 3 + :column 4 + :warning-details-url "https://stuartsierra.com/2015/05/10/clojure-namespace-aliases" + :msg "[clojure.string :as foo] is not a derived alias" + :filename "test-resources/ns_aliases_warning.clj"}]))) + From 9bcec711406fc7989e132483c54fe1cb9c473b4f Mon Sep 17 00:00:00 2001 From: Jeroen de Jong Date: Thu, 30 Jan 2020 11:36:55 +0100 Subject: [PATCH 19/52] Add reporters.file-writer, clean pretty-printer --- src/formatting_stack/branch_formatter.clj | 17 ++--- src/formatting_stack/defaults.clj | 2 +- src/formatting_stack/linters/eastwood.clj | 7 ++- src/formatting_stack/project_formatter.clj | 17 ++--- .../reporters/file_writer.clj | 17 +++++ .../reporters/pretty_printer.clj | 63 ++++++++++--------- src/formatting_stack/util.clj | 11 ++++ 7 files changed, 86 insertions(+), 48 deletions(-) create mode 100644 src/formatting_stack/reporters/file_writer.clj diff --git a/src/formatting_stack/branch_formatter.clj b/src/formatting_stack/branch_formatter.clj index 9de10d36..62b6d55f 100644 --- a/src/formatting_stack/branch_formatter.clj +++ b/src/formatting_stack/branch_formatter.clj @@ -65,7 +65,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 @@ -80,9 +80,10 @@ (def default-reporter (pretty-printer/new {})) -(defn format-and-lint-branch! [& {:keys [target-branch in-background?] +(defn format-and-lint-branch! [& {:keys [target-branch in-background? reporter] :or {target-branch "master" - in-background? (not (System/getenv "CI"))}}] + in-background? (not (System/getenv "CI")) + reporter default-reporter}}] (let [default-strategies [(fn [& {:as options}] (mapply strategies/git-diff-against-default-branch (assoc options :target-branch target-branch)))] formatters (default-formatters default-strategies) @@ -90,18 +91,20 @@ (formatting-stack.core/format! :strategies default-strategies :processors default-processors :formatters formatters - :reporter default-reporter + :reporter reporter :linters linters :in-background? in-background?))) -(defn lint-branch! [& {:keys [target-branch in-background?] - :or {target-branch "master"}}] +(defn lint-branch! [& {:keys [target-branch in-background? reporter] + :or {target-branch "master" + in-background? false + reporter default-reporter}}] (let [default-strategies [(fn [& {:as options}] (mapply strategies/git-diff-against-default-branch (assoc options :target-branch target-branch)))] linters (default-linters default-strategies)] (formatting-stack.core/format! :strategies default-strategies :formatters [] :processors default-processors - :reporter default-reporter + :reporter reporter :linters linters :in-background? in-background?))) diff --git a/src/formatting_stack/defaults.clj b/src/formatting_stack/defaults.clj index 26fafb80..06ecfd9e 100644 --- a/src/formatting_stack/defaults.clj +++ b/src/formatting_stack/defaults.clj @@ -65,7 +65,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/linters/eastwood.clj b/src/formatting_stack/linters/eastwood.clj index 9b27657f..d9b0e563 100644 --- a/src/formatting_stack/linters/eastwood.clj +++ b/src/formatting_stack/linters/eastwood.clj @@ -2,6 +2,7 @@ (:require [clojure.string :as str] [eastwood.lint] + [eastwood.reporting-callbacks :as reporting-callbacks] [eastwood.util] [formatting-stack.protocols.linter :as linter] [formatting-stack.util :refer [ns-name-from-filename]] @@ -19,15 +20,15 @@ (defrecord TrackingReporter [reports]) -(defmethod eastwood.reporting-callbacks/lint-warning TrackingReporter [{:keys [reports]} warning] +(defmethod reporting-callbacks/lint-warning TrackingReporter [{:keys [reports]} warning] (swap! reports update :warnings (fnil conj []) warning) nil) -(defmethod eastwood.reporting-callbacks/analyzer-exception TrackingReporter [{:keys [reports]} exception] +(defmethod reporting-callbacks/analyzer-exception TrackingReporter [{:keys [reports]} exception] (swap! reports update :errors (fnil conj []) exception) nil) -(defmethod eastwood.reporting-callbacks/note TrackingReporter [{:keys [reports]} msg] +(defmethod reporting-callbacks/note TrackingReporter [{:keys [reports]} msg] (swap! reports update :note (fnil conj []) msg) nil) diff --git a/src/formatting_stack/project_formatter.clj b/src/formatting_stack/project_formatter.clj index 414c0559..b58e2f7a 100644 --- a/src/formatting_stack/project_formatter.clj +++ b/src/formatting_stack/project_formatter.clj @@ -17,6 +17,7 @@ [formatting-stack.linters.one-resource-per-ns :as linters.one-resource-per-ns] [formatting-stack.processors.cider :as processors.cider] [formatting-stack.reporters.pretty-printer :as pretty-printer] + [formatting-stack.reporters.file-writer :as file-writer] [formatting-stack.strategies :as strategies])) (def third-party-indent-specs formatting-stack.indent-specs/default-third-party-indent-specs) @@ -69,7 +70,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 @@ -81,20 +82,22 @@ (def default-processors [(processors.cider/new {:third-party-indent-specs third-party-indent-specs})]) -(defn format-and-lint-project! [& {:keys [in-background?] - :or {in-background? false}}] +(defn format-and-lint-project! [& {:keys [in-background? reporter] + :or {in-background? false + reporter default-reporter}}] (formatting-stack.core/format! :strategies default-strategies :formatters default-formatters :linters default-linters - :reporter default-reporter + :reporter reporter :processors default-processors :in-background? in-background?)) -(defn lint-project! [& {:keys [in-background?] - :or {in-background? false}}] +(defn lint-project! [& {:keys [in-background? reporter] + :or {in-background? false + reporter default-reporter}}] (formatting-stack.core/format! :strategies default-strategies :formatters [] :processors default-processors - :reporter default-reporter + :reporter reporter :linters default-linters :in-background? in-background?)) diff --git a/src/formatting_stack/reporters/file_writer.clj b/src/formatting_stack/reporters/file_writer.clj new file mode 100644 index 00000000..aa7e5e3d --- /dev/null +++ b/src/formatting_stack/reporters/file_writer.clj @@ -0,0 +1,17 @@ +(ns formatting-stack.reporters.file-writer + "writes the output to a file which can be tailed with `watch --color -n 1 cat .fs-output.txt`" + (:require + [formatting-stack.protocols.reporter :as reporter] + [formatting-stack.reporters.pretty-printer :as pretty-printer] + [nedap.utils.modular.api :refer [implement]])) + +(defn write-report [{:keys [printer filename]} reports] + (->> (with-out-str (reporter/report printer reports)) + (spit filename))) + +(defn new [{:keys [printer filename] + :or {printer (pretty-printer/new {}) + filename ".fs-output.txt"}}] + (implement {:printer printer + :filename filename} + reporter/--report write-report)) diff --git a/src/formatting_stack/reporters/pretty_printer.clj b/src/formatting_stack/reporters/pretty_printer.clj index 8ac52ccb..771d219c 100644 --- a/src/formatting_stack/reporters/pretty_printer.clj +++ b/src/formatting_stack/reporters/pretty_printer.clj @@ -1,33 +1,40 @@ (ns formatting-stack.reporters.pretty-printer + "Prints a colorized output of the reports" (:require - [nedap.utils.modular.api :refer [implement]] + [clojure.stacktrace :refer [print-stack-trace]] + [formatting-stack.protocols.reporter :as reporter] + [formatting-stack.util :refer [colorize]] [medley.core :refer [map-vals]] - [formatting-stack.protocols.reporter :as reporter])) + [nedap.utils.modular.api :refer [implement]])) -;; fixme move to util -(def ansi-colors - {:reset "[0m" - :red "[031m" - :green "[032m" - :yellow "[033m" - :cyan "[036m" - :grey "[037m"}) +(defn print-summary [{:keys [summary?]} reports] + (when summary? + (->> (group-by :level reports) + (map-vals count) + (into (sorted-map-by compare)) ;; print summary in order + (run! (fn [[type n]] + (-> (str n (case type + :exception " exceptions occurred" + :error " errors found" + :warning " warnings found")) + (colorize (case type + :exception :red + :error :red + :warning :yellow)) + (println))))))) -(defn colorize [s color] - (str \u001b (ansi-colors color) s \u001b (ansi-colors :reset))) - -;; fixme split into separate parts -(defn print-report [{:keys [max-msg-length print-stacktraces?]} reports] +(defn print-exceptions [{:keys [print-stacktraces?]} reports] (->> (filter (fn [{:keys [level]}] (#{:exception} level)) reports) (group-by :filename) (run! (fn [[title reports]] (println (colorize title :cyan)) (doseq [{:keys [^Throwable exception]} reports] (if print-stacktraces? - (clojure.stacktrace/print-stack-trace exception) - (println (ex-message exception))) - (println))))) + (print-stack-trace exception) + (println (ex-message exception))) + (println)))))) +(defn print-warnings [{:keys [max-msg-length] } reports] (->> (filter (fn [{:keys [level]}] (#{:error :warning} level)) reports) (group-by :filename) (into (sorted-map-by compare)) ;; sort filenames for consistent output @@ -40,21 +47,17 @@ (colorize (format "%3d:%-3d" line column) :grey) (format (str "%-" max-msg-length "." max-msg-length "s") msg) (colorize (str " " source) :grey))) - (println)))) + (println))))) - ;; fixme dedupe - (let [summary (->> (group-by :level reports) - (map-vals count))] - (when-let [exceptions (:exception summary)] - (println (colorize (str exceptions " exceptions occurred") :red))) - (when-let [error (:error summary)] - (println (colorize (str error " errors found") :red))) - (when-let [warning (:warning summary)] - (println (colorize (str warning " warnings found") :yellow))))) +(defn print-report [this reports] + (print-exceptions this reports) + (print-warnings this reports) + (print-summary this reports)) -(defn new [{:keys [max-msg-length print-stacktraces?] +(defn new [{:keys [max-msg-length print-stacktraces? summary?] :or {max-msg-length 120 - print-stacktraces? true}}] + print-stacktraces? true + summary? true}}] (implement {:max-msg-length max-msg-length :print-stacktraces? print-stacktraces?} reporter/--report print-report)) diff --git a/src/formatting_stack/util.clj b/src/formatting_stack/util.clj index 7bea353e..7130da59 100644 --- a/src/formatting_stack/util.clj +++ b/src/formatting_stack/util.clj @@ -96,3 +96,14 @@ (if (sequential? x) x [x])) + +(def ansi-colors + {:reset "[0m" + :red "[031m" + :green "[032m" + :yellow "[033m" + :cyan "[036m" + :grey "[037m"}) + +(defn colorize [s color] + (str \u001b (ansi-colors color) s \u001b (ansi-colors :reset))) From d80d2826034d521d305f1f3e0ec2d83b24dc9ea3 Mon Sep 17 00:00:00 2001 From: Jeroen de Jong Date: Thu, 30 Jan 2020 13:53:24 +0100 Subject: [PATCH 20/52] Fix :strategies for cljfmt/how-to-ns --- src/formatting_stack/defaults.clj | 42 +++++++++---------- src/formatting_stack/formatters/how_to_ns.clj | 2 +- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/formatting_stack/defaults.clj b/src/formatting_stack/defaults.clj index 06ecfd9e..c3bc2db2 100644 --- a/src/formatting_stack/defaults.clj +++ b/src/formatting_stack/defaults.clj @@ -20,31 +20,31 @@ (def extended-strategies [strategies/git-completely-staged strategies/git-not-completely-staged]) -;; fixme use assoc because new doesn't allow extra keys (defn default-formatters [third-party-indent-specs] - (let [opts {:third-party-indent-specs third-party-indent-specs} - ;; the following exists (for now) to guarantee that how-to-ns uses cached git results from cljfmt. + (let [;; the following exists (for now) to guarantee that how-to-ns uses cached git results from cljfmt. ;; ideally the how-to-ns formatter would have an extra `files-with-a-namespace` strategy but that would break git caching, ;; making usage more awkward. ;; the strategies mechanism needs some rework to avoid this limitation. - cljfmt-and-how-to-ns-opts (-> opts (assoc :strategies default-strategies))] - (->> [(formatters.cljfmt/new cljfmt-and-how-to-ns-opts) - (formatters.how-to-ns/new cljfmt-and-how-to-ns-opts) + cached-strategies default-strategies] + (->> [(-> (formatters.cljfmt/new {:third-party-indent-specs third-party-indent-specs}) + (assoc :strategies cached-strategies)) + (-> (formatters.how-to-ns/new {}) + (assoc :strategies cached-strategies)) (formatters.no-extra-blank-lines/new) - (formatters.newlines/new opts) - (formatters.trivial-ns-duplicates/new (assoc opts :strategies (conj default-strategies - strategies/files-with-a-namespace - strategies/exclude-edn))) + (formatters.newlines/new {}) + (-> (formatters.trivial-ns-duplicates/new {}) + (assoc :strategies (conj default-strategies + strategies/files-with-a-namespace + strategies/exclude-edn))) (when (strategies/refactor-nrepl-available?) - (formatters.clean-ns/new (assoc opts :strategies (conj default-strategies - strategies/when-refactor-nrepl - strategies/files-with-a-namespace - strategies/exclude-cljc - strategies/exclude-cljs - strategies/exclude-edn - strategies/namespaces-within-refresh-dirs-only - strategies/do-not-use-cached-results!))))] - + (-> (formatters.clean-ns/new {}) + (assoc :strategies (conj default-strategies + strategies/files-with-a-namespace + strategies/exclude-cljc + strategies/exclude-cljs + strategies/exclude-edn + strategies/namespaces-within-refresh-dirs-only + strategies/do-not-use-cached-results!))))] (filterv some?)))) (def default-linters [(-> (linters.ns-aliases/new {}) @@ -75,5 +75,5 @@ strategies/files-with-a-namespace)))]) (defn default-processors [third-party-indent-specs] - [(processors.cider/new {:third-party-indent-specs third-party-indent-specs - :strategies extended-strategies})]) + [(-> (processors.cider/new {:third-party-indent-specs third-party-indent-specs}) + (assoc :strategies extended-strategies))]) diff --git a/src/formatting_stack/formatters/how_to_ns.clj b/src/formatting_stack/formatters/how_to_ns.clj index eaa0907e..04bd57e2 100644 --- a/src/formatting_stack/formatters/how_to_ns.clj +++ b/src/formatting_stack/formatters/how_to_ns.clj @@ -23,5 +23,5 @@ (defn new [{:keys [how-to-ns-options] :or {how-to-ns-options {}}}] - (implement {:how-to-ns-options (deep-merge formatting-stack.formatters.how-to-ns/default-how-to-ns-opts how-to-ns-options)} + (implement {:how-to-ns-options (deep-merge default-how-to-ns-opts how-to-ns-options)} formatter/--format! format!)) From 2b34030f402c19f7aabdd0ca360127d355067fc2 Mon Sep 17 00:00:00 2001 From: Jeroen de Jong Date: Tue, 4 Feb 2020 10:36:07 +0100 Subject: [PATCH 21/52] Formatting --- src/formatting_stack/core.clj | 37 +++++++++---------- src/formatting_stack/linters/eastwood.clj | 14 +++---- src/formatting_stack/linters/line_length.clj | 12 +++--- src/formatting_stack/linters/ns_aliases.clj | 3 +- src/formatting_stack/processors/kondo.clj | 3 +- src/formatting_stack/project_formatter.clj | 1 - .../reporters/pretty_printer.clj | 2 +- .../formatting_stack/linters/eastwood.clj | 15 ++++---- .../formatting_stack/linters/ns_aliases.clj | 1 - 9 files changed, 43 insertions(+), 45 deletions(-) diff --git a/src/formatting_stack/core.clj b/src/formatting_stack/core.clj index 2a63b1c7..f5bd6c7b 100644 --- a/src/formatting_stack/core.clj +++ b/src/formatting_stack/core.clj @@ -2,14 +2,13 @@ (:require [clojure.main] [formatting-stack.background] - [formatting-stack.defaults :refer [default-processors default-formatters default-linters default-strategies]] + [formatting-stack.defaults :refer [default-formatters default-linters default-processors 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] [formatting-stack.protocols.processor :as protocols.processor] [formatting-stack.protocols.reporter :refer [report]] - [formatting-stack.util :refer [with-serialized-output]] - [nedap.utils.modular.api :refer [implement]])) + [formatting-stack.util :refer [with-serialized-output]])) (defn files-from-strategies [strategies] (->> strategies @@ -28,22 +27,22 @@ (let [files (memoize (fn [strategies] (files-from-strategies strategies)))] (with-serialized-output - (->> members - (mapcat (fn [member] - (let [{specific-strategies :strategies} member - strategies (or specific-strategies category-strategies default-strategies)] - (try - (->> strategies files (method member)) - (catch Exception e - [{:exception e - :source :formatting-stack/process! - :msg (str "Exception during " member) - :level :exception}]) - (catch AssertionError e - [{:exception e - :source :formatting-stack/process! - :msg (str "Exception during " member) - :level :exception}]))))))))) + (->> members + (mapcat (fn [member] + (let [{specific-strategies :strategies} member + strategies (or specific-strategies category-strategies default-strategies)] + (try + (->> strategies files (method member)) + (catch Exception e + [{:exception e + :source :formatting-stack/process! + :msg (str "Exception during " member) + :level :exception}]) + (catch AssertionError e + [{:exception e + :source :formatting-stack/process! + :msg (str "Exception during " member) + :level :exception}]))))))))) (defn format! [& {:keys [strategies third-party-indent-specs diff --git a/src/formatting_stack/linters/eastwood.clj b/src/formatting_stack/linters/eastwood.clj index d9b0e563..a59be9e4 100644 --- a/src/formatting_stack/linters/eastwood.clj +++ b/src/formatting_stack/linters/eastwood.clj @@ -46,13 +46,13 @@ (map :warn-data) (map (fn [{:keys [uri-or-file-name linter] :as m}] (assoc m - :level :warning - :source (keyword "eastwood" (name linter)) - :filename (if (string? uri-or-file-name) - uri-or-file-name - (str/replace (-> uri-or-file-name .getPath) - root-dir - "")))))))) + :level :warning + :source (keyword "eastwood" (name linter)) + :filename (if (string? uri-or-file-name) + uri-or-file-name + (str/replace (-> uri-or-file-name .getPath) + root-dir + "")))))))) (defn new [{:keys [eastwood-options] :or {eastwood-options {}}}] diff --git a/src/formatting_stack/linters/line_length.clj b/src/formatting_stack/linters/line_length.clj index 9334cb39..fb79e550 100644 --- a/src/formatting_stack/linters/line_length.clj +++ b/src/formatting_stack/linters/line_length.clj @@ -1,9 +1,9 @@ (ns formatting-stack.linters.line-length - (:require - [clojure.string :as string] - [formatting-stack.protocols.linter :as linter] - [formatting-stack.util :refer [process-in-parallel! ensure-coll]] - [nedap.utils.modular.api :refer [implement]])) + (:require + [clojure.string :as string] + [formatting-stack.protocols.linter :as linter] + [formatting-stack.util :refer [ensure-coll process-in-parallel!]] + [nedap.utils.modular.api :refer [implement]])) (defn exceeding-lines [threshold filename] (->> (-> filename slurp (string/split #"\n")) @@ -25,4 +25,4 @@ (defn new [{:keys [max-line-length] :or {max-line-length 130}}] (implement {:max-line-length max-line-length} - linter/--lint! lint!)) + linter/--lint! lint!)) diff --git a/src/formatting_stack/linters/ns_aliases.clj b/src/formatting_stack/linters/ns_aliases.clj index 88208494..68b6c33f 100644 --- a/src/formatting_stack/linters/ns_aliases.clj +++ b/src/formatting_stack/linters/ns_aliases.clj @@ -6,7 +6,7 @@ [clojure.tools.namespace.parse :as parse] [clojure.tools.reader.reader-types :refer [indexing-push-back-reader]] [formatting-stack.protocols.linter :as linter] - [formatting-stack.util :refer [process-in-parallel! ensure-coll]] + [formatting-stack.util :refer [ensure-coll process-in-parallel!]] [nedap.utils.modular.api :refer [implement]]) (:import (java.io PushbackReader))) @@ -54,6 +54,7 @@ '{d [datomic.api datomic.client.api] impl [::anything] log [::anything] + m [matcher-combinators.matchers] s [clojure.spec.alpha cljs.spec.alpha] spec [clojure.spec.alpha cljs.spec.alpha] speced [nedap.speced.def] diff --git a/src/formatting_stack/processors/kondo.clj b/src/formatting_stack/processors/kondo.clj index 60dca6d3..d12d0c19 100644 --- a/src/formatting_stack/processors/kondo.clj +++ b/src/formatting_stack/processors/kondo.clj @@ -5,7 +5,8 @@ [clojure.string :as str] [formatting-stack.protocols.processor :as processor] [nedap.utils.modular.api :refer [implement]]) - (:import (java.io File))) + (:import + (java.io File))) (defn process! [_ _] (let [files (-> (System/getProperty "java.class.path") diff --git a/src/formatting_stack/project_formatter.clj b/src/formatting_stack/project_formatter.clj index b58e2f7a..47de072c 100644 --- a/src/formatting_stack/project_formatter.clj +++ b/src/formatting_stack/project_formatter.clj @@ -17,7 +17,6 @@ [formatting-stack.linters.one-resource-per-ns :as linters.one-resource-per-ns] [formatting-stack.processors.cider :as processors.cider] [formatting-stack.reporters.pretty-printer :as pretty-printer] - [formatting-stack.reporters.file-writer :as file-writer] [formatting-stack.strategies :as strategies])) (def third-party-indent-specs formatting-stack.indent-specs/default-third-party-indent-specs) diff --git a/src/formatting_stack/reporters/pretty_printer.clj b/src/formatting_stack/reporters/pretty_printer.clj index 771d219c..c940e3b2 100644 --- a/src/formatting_stack/reporters/pretty_printer.clj +++ b/src/formatting_stack/reporters/pretty_printer.clj @@ -34,7 +34,7 @@ (println (ex-message exception))) (println)))))) -(defn print-warnings [{:keys [max-msg-length] } reports] +(defn print-warnings [{:keys [max-msg-length]} reports] (->> (filter (fn [{:keys [level]}] (#{:error :warning} level)) reports) (group-by :filename) (into (sorted-map-by compare)) ;; sort filenames for consistent output diff --git a/test/functional/formatting_stack/linters/eastwood.clj b/test/functional/formatting_stack/linters/eastwood.clj index 9efdfda0..cd52dba0 100644 --- a/test/functional/formatting_stack/linters/eastwood.clj +++ b/test/functional/formatting_stack/linters/eastwood.clj @@ -11,14 +11,13 @@ (are [filename expected] (match? expected (linter/lint! linter [filename])) ;; fixme should return a :reader-exception, currently lost in :note. lint! yields empty list - #_#_ - "test-resources/invalid_syntax.clj" - (m/embeds - [{:level :exception, - :filename "test-resources/invalid_syntax.clj", - :line 3, - :column 2, - :source :eastwood/lint!}]) + #_#_"test-resources/invalid_syntax.clj" + (m/embeds + [{:level :exception, + :filename "test-resources/invalid_syntax.clj", + :line 3, + :column 2, + :source :eastwood/lint!}]) "test-resources/eastwood_warning.clj" (m/embeds diff --git a/test/functional/formatting_stack/linters/ns_aliases.clj b/test/functional/formatting_stack/linters/ns_aliases.clj index be46ae60..f2af541d 100644 --- a/test/functional/formatting_stack/linters/ns_aliases.clj +++ b/test/functional/formatting_stack/linters/ns_aliases.clj @@ -23,4 +23,3 @@ :warning-details-url "https://stuartsierra.com/2015/05/10/clojure-namespace-aliases" :msg "[clojure.string :as foo] is not a derived alias" :filename "test-resources/ns_aliases_warning.clj"}]))) - From b124984d10d631a81ee05957c02107277b22bdf6 Mon Sep 17 00:00:00 2001 From: vemv Date: Fri, 7 Feb 2020 11:17:07 +0100 Subject: [PATCH 22/52] Satisfy pedantic --- project.clj | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/project.clj b/project.clj index 89d1a990..37264817 100644 --- a/project.clj +++ b/project.clj @@ -77,7 +77,8 @@ ;; `dev` in :test is important - a test depends on it: :test {:source-paths ["dev"] :dependencies [[com.nedap.staffing-solutions/utils.test "1.6.2"] - [nubank/matcher-combinators "1.0.1"]] + [nubank/matcher-combinators "1.0.1" + :exclusions [commons-codec]]] :jvm-opts ["-Dclojure.core.async.go-checking=true" "-Duser.language=en-US"] :resource-paths ["test-resources-extra" From 4ba418e3ea2123b9c39fca1dbda59bdca6207783 Mon Sep 17 00:00:00 2001 From: vemv Date: Fri, 7 Feb 2020 11:27:52 +0100 Subject: [PATCH 23/52] Adapt `functional.formatting-stack.component` to `protocols.reporter` --- src/formatting_stack/reporters/passthrough.clj | 13 +++++++++++++ test/functional/formatting_stack/component.clj | 6 ++++-- 2 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 src/formatting_stack/reporters/passthrough.clj diff --git a/src/formatting_stack/reporters/passthrough.clj b/src/formatting_stack/reporters/passthrough.clj new file mode 100644 index 00000000..e22b82fc --- /dev/null +++ b/src/formatting_stack/reporters/passthrough.clj @@ -0,0 +1,13 @@ +(ns formatting-stack.reporters.passthrough + (:require + [formatting-stack.protocols.reporter :as protocols.reporter] + [nedap.utils.modular.api :refer [implement]])) + +(defn report [_ _] + []) + +(defn new + "Does not perform a report. Apt for the test suite." + [] + (implement {} + protocols.reporter/--report report)) diff --git a/test/functional/formatting_stack/component.clj b/test/functional/formatting_stack/component.clj index fe593e20..79a81e58 100644 --- a/test/functional/formatting_stack/component.clj +++ b/test/functional/formatting_stack/component.clj @@ -2,7 +2,8 @@ (:require [clojure.test :refer :all] [com.stuartsierra.component :as component] - [formatting-stack.component :as sut])) + [formatting-stack.component :as sut] + [formatting-stack.reporters.passthrough :as reporters.passthrough])) (deftest works (testing "It can be started/stopped without errors" @@ -13,7 +14,8 @@ :linters [] :processors [] :in-background? false - :intersperse-newlines? false} + :intersperse-newlines? false + :reporter (reporters.passthrough/new)} instance (sut/new opts)] (is (= instance (component/start instance))) From 9b54df4f10e408154017952ef3efd869583922a7 Mon Sep 17 00:00:00 2001 From: vemv Date: Fri, 7 Feb 2020 11:48:04 +0100 Subject: [PATCH 24/52] Draft `formatting-stack.reporters.printer`, default to it A non-colorized variant. A default is necessary, because `formatting-stack.core/format!` can be always be invoked from the REPL (as oppposed to branch-formatter etc). --- src/formatting_stack/core.clj | 14 +++-- .../reporters/pretty_printer.clj | 22 ++++--- src/formatting_stack/reporters/printer.cljc | 62 +++++++++++++++++++ 3 files changed, 83 insertions(+), 15 deletions(-) create mode 100644 src/formatting_stack/reporters/printer.cljc diff --git a/src/formatting_stack/core.clj b/src/formatting_stack/core.clj index f5bd6c7b..6a9984ee 100644 --- a/src/formatting_stack/core.clj +++ b/src/formatting_stack/core.clj @@ -1,6 +1,7 @@ (ns formatting-stack.core (:require [clojure.main] + [formatting-stack.reporters.printer :as reporters.printer] [formatting-stack.background] [formatting-stack.defaults :refer [default-formatters default-linters default-processors default-strategies]] [formatting-stack.indent-specs :refer [default-third-party-indent-specs]] @@ -35,14 +36,14 @@ (->> strategies files (method member)) (catch Exception e [{:exception e - :source :formatting-stack/process! - :msg (str "Exception during " member) - :level :exception}]) + :source :formatting-stack/process! + :msg (str "Exception during " member) + :level :exception}]) (catch AssertionError e [{:exception e - :source :formatting-stack/process! - :msg (str "Exception during " member) - :level :exception}]))))))))) + :source :formatting-stack/process! + :msg (str "Exception during " member) + :level :exception}]))))))))) (defn format! [& {:keys [strategies third-party-indent-specs @@ -57,6 +58,7 @@ formatters (or formatters (default-formatters third-party-indent-specs)) linters (or linters default-linters) processors (or processors (default-processors third-party-indent-specs)) + reporter (or reporter (reporters.printer/new {})) in-background? (if (some? in-background?) in-background? true) diff --git a/src/formatting_stack/reporters/pretty_printer.clj b/src/formatting_stack/reporters/pretty_printer.clj index c940e3b2..5bbd35ae 100644 --- a/src/formatting_stack/reporters/pretty_printer.clj +++ b/src/formatting_stack/reporters/pretty_printer.clj @@ -15,16 +15,18 @@ (run! (fn [[type n]] (-> (str n (case type :exception " exceptions occurred" - :error " errors found" - :warning " warnings found")) + :error " errors found" + :warning " warnings found")) (colorize (case type :exception :red - :error :red - :warning :yellow)) + :error :red + :warning :yellow)) (println))))))) (defn print-exceptions [{:keys [print-stacktraces?]} reports] - (->> (filter (fn [{:keys [level]}] (#{:exception} level)) reports) + (->> reports + (filter (fn [{:keys [level]}] + (#{:exception} level))) (group-by :filename) (run! (fn [[title reports]] (println (colorize title :cyan)) @@ -35,7 +37,9 @@ (println)))))) (defn print-warnings [{:keys [max-msg-length]} reports] - (->> (filter (fn [{:keys [level]}] (#{:error :warning} level)) reports) + (->> reports + (filter (fn [{:keys [level]}] + (#{:error :warning} level))) (group-by :filename) (into (sorted-map-by compare)) ;; sort filenames for consistent output (run! (fn [[title reports]] @@ -55,9 +59,9 @@ (print-summary this reports)) (defn new [{:keys [max-msg-length print-stacktraces? summary?] - :or {max-msg-length 120 - print-stacktraces? true - summary? true}}] + :or {max-msg-length 120 + print-stacktraces? true + summary? true}}] (implement {:max-msg-length max-msg-length :print-stacktraces? print-stacktraces?} reporter/--report print-report)) diff --git a/src/formatting_stack/reporters/printer.cljc b/src/formatting_stack/reporters/printer.cljc new file mode 100644 index 00000000..bdfa06d5 --- /dev/null +++ b/src/formatting_stack/reporters/printer.cljc @@ -0,0 +1,62 @@ +(ns formatting-stack.reporters.printer + "Prints a non-colorized output of the reports" + (:require + [clojure.stacktrace :refer [print-stack-trace]] + [formatting-stack.protocols.reporter :as reporter] + [medley.core :refer [map-vals]] + [nedap.utils.modular.api :refer [implement]])) + +(defn print-summary [{:keys [summary?]} reports] + (when summary? + (->> (group-by :level reports) + (map-vals count) + (into (sorted-map-by compare)) ;; print summary in order + (run! (fn [[type n]] + (-> (str n (case type + :exception " exceptions occurred" + :error " errors found" + :warning " warnings found")) + (println))))))) + +(defn print-exceptions [{:keys [print-stacktraces?]} reports] + (->> reports + (filter (fn [{:keys [level]}] + (#{:exception} level))) + (group-by :filename) + (run! (fn [[title reports]] + (println title) + (doseq [{:keys [^Throwable exception]} reports] + (if print-stacktraces? + (print-stack-trace exception) + (println (ex-message exception))) + (println)))))) + +(defn print-warnings [{:keys [max-msg-length]} reports] + (->> reports + (filter (fn [{:keys [level]}] + (#{:error :warning} level))) + (group-by :filename) + (into (sorted-map-by compare)) ;; sort filenames for consistent output + (run! (fn [[title reports]] + (println title) + (doseq [{:keys [msg column line source level]} (sort-by :line reports)] + (println (case level + :error "ˣ" + :warning "⚠") + (format "%3d:%-3d" line column) + (format (str "%-" max-msg-length "." max-msg-length "s") msg) + (str " " source))) + (println))))) + +(defn print-report [this reports] + (print-exceptions this reports) + (print-warnings this reports) + (print-summary this reports)) + +(defn new [{:keys [max-msg-length print-stacktraces? summary?] + :or {max-msg-length 120 + print-stacktraces? true + summary? true}}] + (implement {:max-msg-length max-msg-length + :print-stacktraces? print-stacktraces?} + reporter/--report print-report)) From 58101d0337b0e77ffc0afc04fdf93657e21c87ae Mon Sep 17 00:00:00 2001 From: vemv Date: Fri, 7 Feb 2020 11:48:30 +0100 Subject: [PATCH 25/52] Patch linters.one-resource-per-ns so it satisfies the specs --- src/formatting_stack/linters/one_resource_per_ns.clj | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/formatting_stack/linters/one_resource_per_ns.clj b/src/formatting_stack/linters/one_resource_per_ns.clj index fe528e72..c79c5336 100644 --- a/src/formatting_stack/linters/one_resource_per_ns.clj +++ b/src/formatting_stack/linters/one_resource_per_ns.clj @@ -54,7 +54,8 @@ (println "Warning: the namespace" (str "`" ns-name "`") "is defined over more than one file.\nFound:" - (->> filenames (interpose ", ") (apply str)))))))))) + (->> filenames (interpose ", ") (apply str))))))))) + []) (speced/defn new [^map? opts] (implement opts From a53d56571f37c16baf11af12bc990b4bf07f23a6 Mon Sep 17 00:00:00 2001 From: vemv Date: Sat, 8 Feb 2020 02:19:21 +0100 Subject: [PATCH 26/52] project.clj: honor exclusions via custom middleware --- project.clj | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/project.clj b/project.clj index 37264817..9cbaf9f9 100644 --- a/project.clj +++ b/project.clj @@ -72,7 +72,25 @@ [org.clojure/test.check "0.10.0-alpha3"]] :jvm-opts ["-Dclojure.compiler.disable-locals-clearing=true"] :source-paths ["dev"] - :repl-options {:init-ns dev}} + :repl-options {:init-ns dev} + :middleware [~(do ;; the following ensures that :exclusions are honored in all cases + (create-ns 'user) + (intern 'user + 'nedap-ensure-exclusions + (fn [project] + (let [exclusions (->> project + :exclusions + (map (fn [x] + (str (if (namespace (symbol x)) + x + (symbol (str x) (str x)))))) + (set))] + (update project :dependencies (fn [deps] + (->> deps + (remove (fn [[dep version]] + (exclusions (str dep)))) + vec)))))) + 'user/nedap-ensure-exclusions)]} ;; `dev` in :test is important - a test depends on it: :test {:source-paths ["dev"] From 1ff8a37204b5ead7daef9072f1af1c396ed1c5f2 Mon Sep 17 00:00:00 2001 From: vemv Date: Sat, 8 Feb 2020 02:30:02 +0100 Subject: [PATCH 27/52] Kondo: skip `:unused-binding` linter I tend to prefer `[k v]` bindings to `[k _]`, since the names can be informative of the type of things, which can be particularly imiportant in a dynamic language like Clojure. --- src/formatting_stack/formatters/cljfmt/impl.clj | 2 +- src/formatting_stack/linters/kondo.clj | 1 + test/functional/formatting_stack/linters/kondo.clj | 3 ++- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/formatting_stack/formatters/cljfmt/impl.clj b/src/formatting_stack/formatters/cljfmt/impl.clj index 7b4a0678..5d12c0ba 100644 --- a/src/formatting_stack/formatters/cljfmt/impl.clj +++ b/src/formatting_stack/formatters/cljfmt/impl.clj @@ -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 _]] + :when (some (fn [[k v]] (= 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 c2e73532..c1f747c7 100644 --- a/src/formatting_stack/linters/kondo.clj +++ b/src/formatting_stack/linters/kondo.clj @@ -11,6 +11,7 @@ (def default-options {:linters {:cond-else off ;; undesired :missing-docstring off ;; undesired + :unused-binding off ;; undesired :unused-symbol off ;; can give false positives :unused-private-var off ;; can give false positives :consistent-alias off ;; already offered by how-to-ns diff --git a/test/functional/formatting_stack/linters/kondo.clj b/test/functional/formatting_stack/linters/kondo.clj index d4b7467d..1889f8a0 100644 --- a/test/functional/formatting_stack/linters/kondo.clj +++ b/test/functional/formatting_stack/linters/kondo.clj @@ -7,7 +7,8 @@ [matcher-combinators.test :refer [match?]])) (deftest lint! - (let [linter (sut/new {:kondo-options {:output {:exclude-files []}}})] + (let [linter (sut/new {:kondo-options {:output {:exclude-files []} + :linters {:unused-binding {:level :warning}}}})] (are [filename expected] (match? expected (linter/lint! linter [filename])) "test-resources/invalid_syntax.clj" From 3f87d5ad0c63e24472d04c9af43b1d9f1e71cfa6 Mon Sep 17 00:00:00 2001 From: vemv Date: Sat, 8 Feb 2020 02:43:43 +0100 Subject: [PATCH 28/52] Cleanup `formatting-stack.linters.kondo` --- src/formatting_stack/linters/kondo.clj | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/formatting_stack/linters/kondo.clj b/src/formatting_stack/linters/kondo.clj index c1f747c7..dd178abf 100644 --- a/src/formatting_stack/linters/kondo.clj +++ b/src/formatting_stack/linters/kondo.clj @@ -2,7 +2,7 @@ (:require [clj-kondo.core :as clj-kondo] [clojure.set :as set] - [formatting-stack.protocols.linter :as linter] + [formatting-stack.protocols.linter :as protocols.linter] [medley.core :refer [deep-merge]] [nedap.utils.modular.api :refer [implement]])) @@ -32,26 +32,30 @@ "test/unit/formatting_stack/formatters/cljfmt/impl/sample_data.clj"]}}) (def clj-options - "CLJ files are also linted by eastwood, disable duplicate linters" + ;; .clj files are also linted by Eastwood, so we disable duplicate linters: {:linters {:misplaced-docstring off :deprecated-var off :inline-def off :redefined-var off}}) (defn lint! [{:keys [kondo-options]} filenames] - (let [{cljs-files true - clj-files false} (group-by (fn [f] (boolean (re-find #"\.cljs$" f))) filenames)] + (let [kondo-options (or kondo-options {}) + {cljs-files true + clj-files false} (->> filenames + (group-by (fn [f] + (-> (re-find #"\.cljs$" f) + boolean))))] (->> [(clj-kondo/run! {:lint clj-files - :config (deep-merge default-options clj-options (or kondo-options {}))}) + :config (deep-merge default-options clj-options kondo-options)}) (clj-kondo/run! {:lint cljs-files - :config (deep-merge default-options (or kondo-options {}))})] + :config (deep-merge default-options kondo-options)})] (mapcat :findings) - (map (fn [{:keys [type] :as m}] + (map (fn [{source-type :type :as m}] (-> (set/rename-keys m {:row :line :message :msg :col :column}) - (assoc :source (keyword "kondo" (name type))))))))) + (assoc :source (keyword "kondo" (name source-type))))))))) (defn new [{:keys [kondo-options]}] (implement {:kondo-options kondo-options} - linter/--lint! lint!)) + protocols.linter/--lint! lint!)) From b1a6f3de3c40ab23d9fc3e25744033fb5b95f2c8 Mon Sep 17 00:00:00 2001 From: vemv Date: Sat, 8 Feb 2020 02:46:47 +0100 Subject: [PATCH 29/52] Strategies: don't exclude Kondo from JVM files anymore (At least for the time being) `formatting-stack.linters.kondo` already has logic for separating clj from cljs options. --- src/formatting_stack/branch_formatter.clj | 10 ++++------ src/formatting_stack/defaults.clj | 4 +--- src/formatting_stack/project_formatter.clj | 8 +++----- 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/formatting_stack/branch_formatter.clj b/src/formatting_stack/branch_formatter.clj index 62b6d55f..4dbed24e 100644 --- a/src/formatting_stack/branch_formatter.clj +++ b/src/formatting_stack/branch_formatter.clj @@ -67,9 +67,7 @@ strategies/namespaces-within-refresh-dirs-only))) (-> (linters.kondo/new {}) (assoc :strategies (conj default-strategies - strategies/exclude-edn - strategies/exclude-clj - strategies/exclude-cljc))) + strategies/exclude-edn))) (-> (linters.one-resource-per-ns/new {}) (assoc :strategies (conj default-strategies strategies/files-with-a-namespace)))]) @@ -83,7 +81,7 @@ (defn format-and-lint-branch! [& {:keys [target-branch in-background? reporter] :or {target-branch "master" in-background? (not (System/getenv "CI")) - reporter default-reporter}}] + reporter default-reporter}}] (let [default-strategies [(fn [& {:as options}] (mapply strategies/git-diff-against-default-branch (assoc options :target-branch target-branch)))] formatters (default-formatters default-strategies) @@ -96,9 +94,9 @@ :in-background? in-background?))) (defn lint-branch! [& {:keys [target-branch in-background? reporter] - :or {target-branch "master" + :or {target-branch "master" in-background? false - reporter default-reporter}}] + reporter default-reporter}}] (let [default-strategies [(fn [& {:as options}] (mapply strategies/git-diff-against-default-branch (assoc options :target-branch target-branch)))] linters (default-linters default-strategies)] diff --git a/src/formatting_stack/defaults.clj b/src/formatting_stack/defaults.clj index c3bc2db2..35b46e5f 100644 --- a/src/formatting_stack/defaults.clj +++ b/src/formatting_stack/defaults.clj @@ -67,9 +67,7 @@ strategies/namespaces-within-refresh-dirs-only))) (-> (linters.kondo/new {}) (assoc :strategies (conj extended-strategies - strategies/exclude-edn - strategies/exclude-clj - strategies/exclude-cljc))) + strategies/exclude-edn))) (-> (linters.one-resource-per-ns/new {}) (assoc :strategies (conj extended-strategies strategies/files-with-a-namespace)))]) diff --git a/src/formatting_stack/project_formatter.clj b/src/formatting_stack/project_formatter.clj index 47de072c..af4a6880 100644 --- a/src/formatting_stack/project_formatter.clj +++ b/src/formatting_stack/project_formatter.clj @@ -71,9 +71,7 @@ strategies/namespaces-within-refresh-dirs-only))) (-> (linters.kondo/new {}) (assoc :strategies (conj default-strategies - strategies/exclude-edn - strategies/exclude-clj - strategies/exclude-cljc))) + strategies/exclude-edn))) (-> (linters.one-resource-per-ns/new {}) (assoc :strategies (conj default-strategies strategies/files-with-a-namespace)))]) @@ -83,7 +81,7 @@ (defn format-and-lint-project! [& {:keys [in-background? reporter] :or {in-background? false - reporter default-reporter}}] + reporter default-reporter}}] (formatting-stack.core/format! :strategies default-strategies :formatters default-formatters :linters default-linters @@ -93,7 +91,7 @@ (defn lint-project! [& {:keys [in-background? reporter] :or {in-background? false - reporter default-reporter}}] + reporter default-reporter}}] (formatting-stack.core/format! :strategies default-strategies :formatters [] :processors default-processors From 01f311bc40d849fe61e5ccb3eb0aa693fc02bff1 Mon Sep 17 00:00:00 2001 From: vemv Date: Sat, 8 Feb 2020 03:31:17 +0100 Subject: [PATCH 30/52] Cleanup project --- dev/dev.clj | 11 ++++++--- src/formatting_stack/core.clj | 7 +++--- src/formatting_stack/linters/line_length.clj | 6 ++--- src/formatting_stack/linters/loc_per_ns.clj | 12 +++++----- src/formatting_stack/linters/ns_aliases.clj | 15 ++++++------ .../reporters/file_writer.clj | 13 +++++----- .../reporters/pretty_printer.clj | 3 ++- src/formatting_stack/util.clj | 10 ++++---- .../functional/formatting_stack/component.clj | 3 +-- .../formatting_stack/formatters/clean_ns.clj | 16 ++++++------- .../formatters/clean_ns/impl.clj | 2 +- .../formatting_stack/linters/eastwood.clj | 22 ++++++++--------- .../formatting_stack/linters/kondo.clj | 24 +++++++++---------- .../formatting_stack/linters/line_length.clj | 10 ++++---- .../formatting_stack/linters/loc_per_ns.clj | 10 ++++---- .../formatting_stack/linters/ns_aliases.clj | 20 ++++++++-------- .../linters/one_resource_per_ns.clj | 2 +- .../formatting_stack/strategies/impl.clj | 2 +- test/unit/formatting_stack/component/impl.clj | 2 +- .../formatters/cljfmt/impl.clj | 2 +- .../formatters/cljfmt/impl/magic_symbols.clj | 2 +- .../formatters/no_extra_blank_lines.clj | 2 +- .../formatters/trivial_ns_duplicates.clj | 2 +- test/unit/formatting_stack/indent_specs.clj | 2 +- .../formatting_stack/linters/ns_aliases.clj | 2 +- .../linters/one_resource_per_ns.clj | 2 +- .../processors/test_runner/impl.clj | 2 +- test/unit/formatting_stack/strategies.clj | 2 +- 28 files changed, 107 insertions(+), 101 deletions(-) diff --git a/dev/dev.clj b/dev/dev.clj index 03b1338a..1d1c7fec 100644 --- a/dev/dev.clj +++ b/dev/dev.clj @@ -12,16 +12,21 @@ ;; the "worker" source-path must be excluded. (set-refresh-dirs "src" "test" "dev") +(defn prepare-tests [] + (clear) + (alter-var-root #'clojure.test/*load-tests* (constantly true)) + (refresh)) + (defn suite [] - (refresh) + (prepare-tests) (run-all-tests #".*\.formatting-stack.*")) (defn unit [] - (refresh) + (prepare-tests) (run-all-tests #"unit\.formatting-stack.*")) (defn slow [] - (refresh) + (prepare-tests) (run-all-tests #"integration\.formatting-stack.*")) (defn diff [x y] diff --git a/src/formatting_stack/core.clj b/src/formatting_stack/core.clj index 6a9984ee..b945f7a7 100644 --- a/src/formatting_stack/core.clj +++ b/src/formatting_stack/core.clj @@ -1,7 +1,6 @@ (ns formatting-stack.core (:require [clojure.main] - [formatting-stack.reporters.printer :as reporters.printer] [formatting-stack.background] [formatting-stack.defaults :refer [default-formatters default-linters default-processors default-strategies]] [formatting-stack.indent-specs :refer [default-third-party-indent-specs]] @@ -9,6 +8,7 @@ [formatting-stack.protocols.linter :as protocols.linter] [formatting-stack.protocols.processor :as protocols.processor] [formatting-stack.protocols.reporter :refer [report]] + [formatting-stack.reporters.printer :as reporters.printer] [formatting-stack.util :refer [with-serialized-output]])) (defn files-from-strategies [strategies] @@ -43,7 +43,8 @@ [{:exception e :source :formatting-stack/process! :msg (str "Exception during " member) - :level :exception}]))))))))) + :level :exception}]))))) + (doall))))) (defn format! [& {:keys [strategies third-party-indent-specs @@ -69,7 +70,7 @@ (->> [(process! protocols.formatter/format! formatters formatters-strategies strategies) (process! protocols.linter/lint! linters linters-strategies strategies) (process! protocols.processor/process! processors processors-strategies strategies)] - (mapcat identity) + (apply concat) (report reporter)))] (if in-background? (do diff --git a/src/formatting_stack/linters/line_length.clj b/src/formatting_stack/linters/line_length.clj index fb79e550..d10b1c15 100644 --- a/src/formatting_stack/linters/line_length.clj +++ b/src/formatting_stack/linters/line_length.clj @@ -12,8 +12,8 @@ {:filename filename :source :formatting-stack/line-length :level :warning - :column (+ 1 threshold) - :line (+ 1 i) + :column (inc threshold) + :line (inc i) :msg (str "Line exceeding " threshold " columns")}))) (remove nil?))) @@ -23,6 +23,6 @@ (mapcat ensure-coll))) (defn new [{:keys [max-line-length] - :or {max-line-length 130}}] + :or {max-line-length 130}}] (implement {:max-line-length max-line-length} linter/--lint! lint!)) diff --git a/src/formatting_stack/linters/loc_per_ns.clj b/src/formatting_stack/linters/loc_per_ns.clj index 1418c3d3..489262de 100644 --- a/src/formatting_stack/linters/loc_per_ns.clj +++ b/src/formatting_stack/linters/loc_per_ns.clj @@ -17,14 +17,14 @@ (process-in-parallel! (fn [filename] (when (overly-long-ns? filename max-lines-per-ns) {:filename filename - :source :formatting-stack/loc-per-ns - :level :warning - :msg (str "Longer than " max-lines-per-ns " LOC. consider refactoring") - :line (+ 1 max-lines-per-ns) ;; first line after limit is the issue - :column 1}))) + :source :formatting-stack/loc-per-ns + :level :warning + :msg (str "Longer than " max-lines-per-ns " LOC. consider refactoring") + :line (inc max-lines-per-ns) ;; first line after limit is the issue + :column 1}))) (remove nil?))) (defn new [{:keys [max-lines-per-ns] - :or {max-lines-per-ns 350}}] + :or {max-lines-per-ns 350}}] (implement {:max-lines-per-ns max-lines-per-ns} linter/--lint! lint!)) diff --git a/src/formatting_stack/linters/ns_aliases.clj b/src/formatting_stack/linters/ns_aliases.clj index 68b6c33f..960a9555 100644 --- a/src/formatting_stack/linters/ns_aliases.clj +++ b/src/formatting_stack/linters/ns_aliases.clj @@ -54,7 +54,6 @@ '{d [datomic.api datomic.client.api] impl [::anything] log [::anything] - m [matcher-combinators.matchers] s [clojure.spec.alpha cljs.spec.alpha] spec [clojure.spec.alpha cljs.spec.alpha] speced [nedap.speced.def] @@ -90,16 +89,16 @@ (remove (partial acceptable-require-clause? acceptable-aliases-whitelist)) (map (fn [bad-alias] - {:filename filename - :line (:line (meta bad-alias)) - :column (:column (meta bad-alias)) - :level :warning + {:filename filename + :line (:line (meta bad-alias)) + :column (:column (meta bad-alias)) + :level :warning :warning-details-url "https://stuartsierra.com/2015/05/10/clojure-namespace-aliases" - :msg (str bad-alias " is not a derived alias") - :source :formatting-stack/ns-aliases}))))) + :msg (str bad-alias " is not a derived alias") + :source :formatting-stack/ns-aliases}))))) (mapcat ensure-coll))) (defn new [{:keys [acceptable-aliases-whitelist] - :or {acceptable-aliases-whitelist default-acceptable-aliases-whitelist}}] + :or {acceptable-aliases-whitelist default-acceptable-aliases-whitelist}}] (implement {:acceptable-aliases-whitelist acceptable-aliases-whitelist} linter/--lint! lint!)) diff --git a/src/formatting_stack/reporters/file_writer.clj b/src/formatting_stack/reporters/file_writer.clj index aa7e5e3d..7df3e673 100644 --- a/src/formatting_stack/reporters/file_writer.clj +++ b/src/formatting_stack/reporters/file_writer.clj @@ -1,17 +1,18 @@ (ns formatting-stack.reporters.file-writer "writes the output to a file which can be tailed with `watch --color -n 1 cat .fs-output.txt`" (:require - [formatting-stack.protocols.reporter :as reporter] + [formatting-stack.protocols.reporter :as protocols.reporter] [formatting-stack.reporters.pretty-printer :as pretty-printer] [nedap.utils.modular.api :refer [implement]])) (defn write-report [{:keys [printer filename]} reports] - (->> (with-out-str (reporter/report printer reports)) + (->> (with-out-str + (protocols.reporter/report printer reports)) (spit filename))) (defn new [{:keys [printer filename] - :or {printer (pretty-printer/new {}) - filename ".fs-output.txt"}}] - (implement {:printer printer + :or {printer (pretty-printer/new {}) + filename ".fs-output.txt"}}] + (implement {:printer printer :filename filename} - reporter/--report write-report)) + protocols.reporter/--report write-report)) diff --git a/src/formatting_stack/reporters/pretty_printer.clj b/src/formatting_stack/reporters/pretty_printer.clj index 5bbd35ae..2b3cb684 100644 --- a/src/formatting_stack/reporters/pretty_printer.clj +++ b/src/formatting_stack/reporters/pretty_printer.clj @@ -9,7 +9,8 @@ (defn print-summary [{:keys [summary?]} reports] (when summary? - (->> (group-by :level reports) + (->> reports + (group-by :level) (map-vals count) (into (sorted-map-by compare)) ;; print summary in order (run! (fn [[type n]] diff --git a/src/formatting_stack/util.clj b/src/formatting_stack/util.clj index 7130da59..b266fc55 100644 --- a/src/formatting_stack/util.clj +++ b/src/formatting_stack/util.clj @@ -54,11 +54,11 @@ *flush-on-newline* true] ~@forms)) -(defn report-processing-error [^Throwable e filename] - {:level :exception - :source :formatting-stack/report-processing-error - :filename filename - :msg "Encountered an exception" +(speced/defn report-processing-error [^Throwable e, filename] + {:level :exception + :source :formatting-stack/report-processing-error + :filename filename + :msg "Encountered an exception" :exception e}) (defn process-in-parallel! [f files] diff --git a/test/functional/formatting_stack/component.clj b/test/functional/formatting_stack/component.clj index 79a81e58..c26a50fa 100644 --- a/test/functional/formatting_stack/component.clj +++ b/test/functional/formatting_stack/component.clj @@ -1,6 +1,6 @@ (ns functional.formatting-stack.component (:require - [clojure.test :refer :all] + [clojure.test :refer [deftest is testing]] [com.stuartsierra.component :as component] [formatting-stack.component :as sut] [formatting-stack.reporters.passthrough :as reporters.passthrough])) @@ -14,7 +14,6 @@ :linters [] :processors [] :in-background? false - :intersperse-newlines? false :reporter (reporters.passthrough/new)} instance (sut/new opts)] (is (= instance diff --git a/test/functional/formatting_stack/formatters/clean_ns.clj b/test/functional/formatting_stack/formatters/clean_ns.clj index 9dfa7f03..dc2a6476 100644 --- a/test/functional/formatting_stack/formatters/clean_ns.clj +++ b/test/functional/formatting_stack/formatters/clean_ns.clj @@ -1,6 +1,6 @@ (ns functional.formatting-stack.formatters.clean-ns (:require - [clojure.test :refer :all] + [clojure.test :refer [are deftest is]] [formatting-stack.formatters.clean-ns :as sut] [formatting-stack.formatters.clean-ns.impl :as impl :refer [ns-form-of]] [formatting-stack.formatters.how-to-ns] @@ -56,13 +56,13 @@ (when (strategies/refactor-nrepl-available?) (deftest clean-ns-form (are [op filename ns-form 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 - libspec-whitelist - filename) - v (util.ns/replaceable-ns-form filename cleaner formatting-stack.formatters.how-to-ns/default-how-to-ns-opts)] - (op v)) + (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 + libspec-whitelist + 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 #{} diff --git a/test/functional/formatting_stack/formatters/clean_ns/impl.clj b/test/functional/formatting_stack/formatters/clean_ns/impl.clj index 90f9cf37..7f66061a 100644 --- a/test/functional/formatting_stack/formatters/clean_ns/impl.clj +++ b/test/functional/formatting_stack/formatters/clean_ns/impl.clj @@ -1,7 +1,7 @@ (ns functional.formatting-stack.formatters.clean-ns.impl (:require [clojure.java.io :as io] - [clojure.test :refer :all] + [clojure.test :refer [are deftest]] [formatting-stack.formatters.clean-ns.impl :as sut])) (deftest has-duplicate-requires? diff --git a/test/functional/formatting_stack/linters/eastwood.clj b/test/functional/formatting_stack/linters/eastwood.clj index cd52dba0..00c57cd7 100644 --- a/test/functional/formatting_stack/linters/eastwood.clj +++ b/test/functional/formatting_stack/linters/eastwood.clj @@ -1,9 +1,9 @@ (ns functional.formatting-stack.linters.eastwood (:require - [clojure.test :refer :all] + [clojure.test :refer [are deftest]] [formatting-stack.linters.eastwood :as sut] [formatting-stack.protocols.linter :as linter] - [matcher-combinators.matchers :as m] + [matcher-combinators.matchers :as matchers] [matcher-combinators.test :refer [match?]])) (deftest lint! @@ -12,16 +12,16 @@ (linter/lint! linter [filename])) ;; fixme should return a :reader-exception, currently lost in :note. lint! yields empty list #_#_"test-resources/invalid_syntax.clj" - (m/embeds - [{:level :exception, + (matchers/embeds + [{:level :exception, :filename "test-resources/invalid_syntax.clj", - :line 3, - :column 2, - :source :eastwood/lint!}]) + :line 3, + :column 2, + :source :eastwood/lint!}]) "test-resources/eastwood_warning.clj" - (m/embeds - [{:source :eastwood/def-in-def - :line 3 - :column 13 + (matchers/embeds + [{:source :eastwood/def-in-def + :line 3 + :column 13 :filename "test-resources/eastwood_warning.clj"}])))) diff --git a/test/functional/formatting_stack/linters/kondo.clj b/test/functional/formatting_stack/linters/kondo.clj index 1889f8a0..d7d2c25b 100644 --- a/test/functional/formatting_stack/linters/kondo.clj +++ b/test/functional/formatting_stack/linters/kondo.clj @@ -1,9 +1,9 @@ (ns functional.formatting-stack.linters.kondo (:require - [clojure.test :refer :all] + [clojure.test :refer [are deftest]] [formatting-stack.linters.kondo :as sut] [formatting-stack.protocols.linter :as linter] - [matcher-combinators.matchers :as m] + [matcher-combinators.matchers :as matchers] [matcher-combinators.test :refer [match?]])) (deftest lint! @@ -12,17 +12,17 @@ (are [filename expected] (match? expected (linter/lint! linter [filename])) "test-resources/invalid_syntax.clj" - (m/embeds - [{:level :error, + (matchers/embeds + [{:level :error, :filename "test-resources/invalid_syntax.clj", - :line 1, - :column 2, - :source :kondo/syntax}]) + :line 1, + :column 2, + :source :kondo/syntax}]) "test-resources/kondo_warning.clj" - (m/embeds - [{:source :kondo/unused-binding - :level :warning - :line 3 - :column 7 + (matchers/embeds + [{:source :kondo/unused-binding + :level :warning + :line 3 + :column 7 :filename "test-resources/kondo_warning.clj"}])))) diff --git a/test/functional/formatting_stack/linters/line_length.clj b/test/functional/formatting_stack/linters/line_length.clj index fcc1c63f..c6ee54c5 100644 --- a/test/functional/formatting_stack/linters/line_length.clj +++ b/test/functional/formatting_stack/linters/line_length.clj @@ -1,6 +1,6 @@ (ns functional.formatting-stack.linters.line-length (:require - [clojure.test :refer :all] + [clojure.test :refer [are deftest]] [formatting-stack.linters.line-length :as sut] [formatting-stack.protocols.linter :as linter] [matcher-combinators.test :refer [match?]])) @@ -13,8 +13,8 @@ [] "test-resources/sample_clj_ns.clj" - [{:source :formatting-stack/line-length - :line 3 - :column 23 - :msg "Line exceeding 22 columns" + [{:source :formatting-stack/line-length + :line 3 + :column 23 + :msg "Line exceeding 22 columns" :filename "test-resources/sample_clj_ns.clj"}]))) diff --git a/test/functional/formatting_stack/linters/loc_per_ns.clj b/test/functional/formatting_stack/linters/loc_per_ns.clj index 28300976..5049c3db 100644 --- a/test/functional/formatting_stack/linters/loc_per_ns.clj +++ b/test/functional/formatting_stack/linters/loc_per_ns.clj @@ -1,6 +1,6 @@ (ns functional.formatting-stack.linters.loc-per-ns (:require - [clojure.test :refer :all] + [clojure.test :refer [are deftest]] [formatting-stack.linters.loc-per-ns :as sut] [formatting-stack.protocols.linter :as linter] [matcher-combinators.test :refer [match?]])) @@ -13,8 +13,8 @@ [] "test-resources/sample_clj_ns.clj" - [{:source :formatting-stack/loc-per-ns - :line 5 - :column 1 - :msg "Longer than 4 LOC. consider refactoring" + [{:source :formatting-stack/loc-per-ns + :line 5 + :column 1 + :msg "Longer than 4 LOC. consider refactoring" :filename "test-resources/sample_clj_ns.clj"}]))) diff --git a/test/functional/formatting_stack/linters/ns_aliases.clj b/test/functional/formatting_stack/linters/ns_aliases.clj index f2af541d..a978c196 100644 --- a/test/functional/formatting_stack/linters/ns_aliases.clj +++ b/test/functional/formatting_stack/linters/ns_aliases.clj @@ -1,6 +1,6 @@ (ns functional.formatting-stack.linters.ns-aliases (:require - [clojure.test :refer :all] + [clojure.test :refer [are deftest]] [formatting-stack.linters.ns-aliases :as sut] [formatting-stack.protocols.linter :as linter] [matcher-combinators.test :refer [match?]])) @@ -10,16 +10,16 @@ (are [filename expected] (match? expected (linter/lint! linter [filename])) "test-resources/invalid_syntax.clj" - [{:source :formatting-stack/report-processing-error - :filename "test-resources/invalid_syntax.clj" - :msg "Encountered an exception" - :level :exception + [{:source :formatting-stack/report-processing-error + :filename "test-resources/invalid_syntax.clj" + :msg "Encountered an exception" + :level :exception :exception #(instance? Throwable %)}] "test-resources/ns_aliases_warning.clj" - [{:source :formatting-stack/ns-aliases - :line 3 - :column 4 + [{:source :formatting-stack/ns-aliases + :line 3 + :column 4 :warning-details-url "https://stuartsierra.com/2015/05/10/clojure-namespace-aliases" - :msg "[clojure.string :as foo] is not a derived alias" - :filename "test-resources/ns_aliases_warning.clj"}]))) + :msg "[clojure.string :as foo] is not a derived alias" + :filename "test-resources/ns_aliases_warning.clj"}]))) diff --git a/test/integration/formatting_stack/linters/one_resource_per_ns.clj b/test/integration/formatting_stack/linters/one_resource_per_ns.clj index 41e37241..1f1b8c55 100644 --- a/test/integration/formatting_stack/linters/one_resource_per_ns.clj +++ b/test/integration/formatting_stack/linters/one_resource_per_ns.clj @@ -1,6 +1,6 @@ (ns integration.formatting-stack.linters.one-resource-per-ns (:require - [clojure.test :refer :all] + [clojure.test :refer [are deftest is testing]] [formatting-stack.linters.one-resource-per-ns :as sut] [formatting-stack.test-helpers :as test-helpers] [formatting-stack.util :refer [rcomp]])) diff --git a/test/integration/formatting_stack/strategies/impl.clj b/test/integration/formatting_stack/strategies/impl.clj index 6e6dcedf..0a2349f6 100644 --- a/test/integration/formatting_stack/strategies/impl.clj +++ b/test/integration/formatting_stack/strategies/impl.clj @@ -1,6 +1,6 @@ (ns integration.formatting-stack.strategies.impl (:require - [clojure.test :refer :all] + [clojure.test :refer [are deftest]] [formatting-stack.strategies.impl :as sut]) (:import (java.io File))) diff --git a/test/unit/formatting_stack/component/impl.clj b/test/unit/formatting_stack/component/impl.clj index 2dd1ab47..ea9fdba9 100644 --- a/test/unit/formatting_stack/component/impl.clj +++ b/test/unit/formatting_stack/component/impl.clj @@ -1,6 +1,6 @@ (ns unit.formatting-stack.component.impl (:require - [clojure.test :refer :all] + [clojure.test :refer [are deftest is testing]] [formatting-stack.component.impl :as sut])) (deftest parse-options diff --git a/test/unit/formatting_stack/formatters/cljfmt/impl.clj b/test/unit/formatting_stack/formatters/cljfmt/impl.clj index 9a10af08..0c76731d 100644 --- a/test/unit/formatting_stack/formatters/cljfmt/impl.clj +++ b/test/unit/formatting_stack/formatters/cljfmt/impl.clj @@ -1,7 +1,7 @@ (ns unit.formatting-stack.formatters.cljfmt.impl (:require [clojure.java.io :as io] - [clojure.test :refer :all] + [clojure.test :refer [are deftest is testing]] [formatting-stack.formatters.cljfmt.impl :as sut] [unit.formatting-stack.formatters.cljfmt.impl.sample-data :refer [foo]]) (:import diff --git a/test/unit/formatting_stack/formatters/cljfmt/impl/magic_symbols.clj b/test/unit/formatting_stack/formatters/cljfmt/impl/magic_symbols.clj index 13a4949e..480ac3c5 100644 --- a/test/unit/formatting_stack/formatters/cljfmt/impl/magic_symbols.clj +++ b/test/unit/formatting_stack/formatters/cljfmt/impl/magic_symbols.clj @@ -1,7 +1,7 @@ (ns unit.formatting-stack.formatters.cljfmt.impl.magic-symbols (:require [clojure.java.io :as io] - [clojure.test :refer :all] + [clojure.test :refer [are deftest is]] [formatting-stack.formatters.cljfmt.impl :as sut])) (deftest works diff --git a/test/unit/formatting_stack/formatters/no_extra_blank_lines.clj b/test/unit/formatting_stack/formatters/no_extra_blank_lines.clj index 2739fd56..b8c569e4 100644 --- a/test/unit/formatting_stack/formatters/no_extra_blank_lines.clj +++ b/test/unit/formatting_stack/formatters/no_extra_blank_lines.clj @@ -1,6 +1,6 @@ (ns unit.formatting-stack.formatters.no-extra-blank-lines (:require - [clojure.test :refer :all] + [clojure.test :refer [are deftest]] [formatting-stack.formatters.no-extra-blank-lines :as sut])) (deftest without-extra-newlines diff --git a/test/unit/formatting_stack/formatters/trivial_ns_duplicates.clj b/test/unit/formatting_stack/formatters/trivial_ns_duplicates.clj index 9f168d4e..63e54057 100644 --- a/test/unit/formatting_stack/formatters/trivial_ns_duplicates.clj +++ b/test/unit/formatting_stack/formatters/trivial_ns_duplicates.clj @@ -1,6 +1,6 @@ (ns unit.formatting-stack.formatters.trivial-ns-duplicates (:require - [clojure.test :refer :all] + [clojure.test :refer [are deftest is testing]] [formatting-stack.formatters.trivial-ns-duplicates :as sut] [formatting-stack.util.ns :as util.ns])) diff --git a/test/unit/formatting_stack/indent_specs.clj b/test/unit/formatting_stack/indent_specs.clj index 23fff490..3983a93d 100644 --- a/test/unit/formatting_stack/indent_specs.clj +++ b/test/unit/formatting_stack/indent_specs.clj @@ -1,6 +1,6 @@ (ns unit.formatting-stack.indent-specs (:require - [clojure.test :refer :all] + [clojure.test :refer [deftest is testing]] [formatting-stack.formatters.cljfmt.impl :as cljfmt.impl] [formatting-stack.indent-specs :as sut] [formatting-stack.processors.cider :as processors.cider] diff --git a/test/unit/formatting_stack/linters/ns_aliases.clj b/test/unit/formatting_stack/linters/ns_aliases.clj index 2ea756a2..a449e773 100644 --- a/test/unit/formatting_stack/linters/ns_aliases.clj +++ b/test/unit/formatting_stack/linters/ns_aliases.clj @@ -1,6 +1,6 @@ (ns unit.formatting-stack.linters.ns-aliases (:require - [clojure.test :refer :all] + [clojure.test :refer [are deftest]] [formatting-stack.linters.ns-aliases :as sut])) (deftest name-and-alias diff --git a/test/unit/formatting_stack/linters/one_resource_per_ns.clj b/test/unit/formatting_stack/linters/one_resource_per_ns.clj index e9ae3191..c1800187 100644 --- a/test/unit/formatting_stack/linters/one_resource_per_ns.clj +++ b/test/unit/formatting_stack/linters/one_resource_per_ns.clj @@ -1,6 +1,6 @@ (ns unit.formatting-stack.linters.one-resource-per-ns (:require - [clojure.test :refer :all] + [clojure.test :refer [are deftest is testing]] [formatting-stack.linters.one-resource-per-ns :as sut] [formatting-stack.test-helpers :as test-helpers])) diff --git a/test/unit/formatting_stack/processors/test_runner/impl.clj b/test/unit/formatting_stack/processors/test_runner/impl.clj index e88fb1c9..db17acd7 100644 --- a/test/unit/formatting_stack/processors/test_runner/impl.clj +++ b/test/unit/formatting_stack/processors/test_runner/impl.clj @@ -1,7 +1,7 @@ (ns unit.formatting-stack.processors.test-runner.impl (:require [clojure.string :as string] - [clojure.test :refer :all] + [clojure.test :refer [are deftest is testing]] [formatting-stack.processors.test-runner.impl :as sut] [formatting-stack.project-parsing :refer [project-namespaces]] [nedap.speced.def :as speced])) diff --git a/test/unit/formatting_stack/strategies.clj b/test/unit/formatting_stack/strategies.clj index eb83a4f4..38ba777c 100644 --- a/test/unit/formatting_stack/strategies.clj +++ b/test/unit/formatting_stack/strategies.clj @@ -1,7 +1,7 @@ (ns unit.formatting-stack.strategies (:require [clojure.string :as str] - [clojure.test :refer :all] + [clojure.test :refer [deftest is use-fixtures]] [formatting-stack.strategies :as sut] [formatting-stack.strategies.impl :as sut.impl])) From 7f7677aa1df21b90deb014915c318e9cef51573b Mon Sep 17 00:00:00 2001 From: vemv Date: Sat, 8 Feb 2020 03:32:16 +0100 Subject: [PATCH 31/52] Setup a JDK test matrix Part of nedap/formatting-stack#69 --- .circleci/config.yml | 78 ++++++++++++++++++++++++++++++++------------ 1 file changed, 58 insertions(+), 20 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index e170a8ee..786110ad 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -15,28 +15,43 @@ commands: - ~/.m2 key: v1-dependencies-{{ checksum "project.clj" }} +executor_defaults: &executor_defaults + working_directory: ~/repo + executors: - lein-executor: + openjdk8: docker: - image: circleci/clojure:openjdk-8-lein-2.9.1 - working_directory: ~/repo environment: LEIN_ROOT: "true" JVM_OPTS: -Xmx3200m + <<: *executor_defaults + openjdk11: + docker: + - image: circleci/clojure:openjdk-11-lein-2.9.1 + environment: + LEIN_ROOT: "true" + JVM_OPTS: -Xmx3200m --illegal-access=deny + <<: *executor_defaults jobs: - build: - executor: lein-executor + test_code: + description: | + Runs tests against given version of the JDK + parameters: + jdk_version: + description: Version of the JDK to test against + type: string + lein_test_command: + description: A Leiningen command that will run a test suite + type: string + executor: << parameters.jdk_version >> steps: - setup-env - run: - name: 'Run JVM tests, including refactor-nrepl functionality' - command: lein with-profile -dev,+ci,+refactor-nrepl do clean, test - - run: - name: 'Run JVM tests, excluding refactor-nrepl functionality' - command: lein with-profile -dev,+ci do clean, test + command: << parameters.lein_test_command >> deploy: - executor: lein-executor + executor: openjdk8 steps: - setup-env - run: @@ -52,21 +67,44 @@ jobs: name: release to Clojars command: lein deploy clojars +test_code_filters: &test_code_filters + filters: + branches: + only: /.*/ + tags: + only: /^v\d+\.\d+\.\d+(-alpha\d+)?$/ + workflows: - version: 2 - CircleCI: + version: 2.1 + ci-test-matrix: jobs: - - build: - context: JFrog - filters: - branches: - only: /.*/ - tags: - only: /^v\d+\.\d+\.\d+(-alpha\d+)?$/ + - test_code: + name: "JDK 8 including refactor-nrepl" + jdk_version: openjdk8 + lein_test_command: lein with-profile -dev,+ci,+refactor-nrepl do clean, test + <<: *test_code_filters + - test_code: + name: "JDK 8 excluding refactor-nrepl" + jdk_version: openjdk8 + lein_test_command: lein with-profile -dev,+ci do clean, test + <<: *test_code_filters + - test_code: + name: "JDK 11 including refactor-nrepl" + jdk_version: openjdk11 + lein_test_command: lein with-profile -dev,+ci,+refactor-nrepl do clean, test + <<: *test_code_filters + - test_code: + name: "JDK 11 excluding refactor-nrepl" + jdk_version: openjdk11 + lein_test_command: lein with-profile -dev,+ci do clean, test + <<: *test_code_filters - deploy: context: JFrog requires: - - build + - "JDK 8 including refactor-nrepl" + - "JDK 8 excluding refactor-nrepl" + - "JDK 11 including refactor-nrepl" + - "JDK 11 excluding refactor-nrepl" filters: branches: ignore: /.*/ From 5a5c3322de5616743cb924f033a22b01b59a76fc Mon Sep 17 00:00:00 2001 From: vemv Date: Sat, 8 Feb 2020 05:14:40 +0100 Subject: [PATCH 32/52] Upgrade utils.modular It's the first publicly-available release. --- project.clj | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/project.clj b/project.clj index 9cbaf9f9..6ac93e66 100644 --- a/project.clj +++ b/project.clj @@ -7,7 +7,7 @@ [com.gfredericks/lein-all-my-files-should-end-with-exactly-one-newline-character "0.1.1"] [com.nedap.staffing-solutions/speced.def "2.0.0"] [com.nedap.staffing-solutions/utils.collections "2.0.0"] - [com.nedap.staffing-solutions/utils.modular "2.0.0"] + [com.nedap.staffing-solutions/utils.modular "2.1.0"] [com.nedap.staffing-solutions/utils.spec.predicates "1.1.0"] [com.stuartsierra/component "0.4.0"] [integrant "0.7.0"] @@ -92,6 +92,16 @@ vec)))))) 'user/nedap-ensure-exclusions)]} + :provided {:dependencies [[org.clojure/clojurescript "1.10.597" + :exclusions [com.cognitect/transit-clj + com.google.code.findbugs/jsr305 + com.google.errorprone/error_prone_annotations]] + [com.google.guava/guava "25.1-jre" #_"transitive"] + [com.google.protobuf/protobuf-java "3.4.0" #_"transitive"] + [com.cognitect/transit-clj "0.8.313" #_"transitive"] + [com.google.errorprone/error_prone_annotations "2.1.3" #_"transitive"] + [com.google.code.findbugs/jsr305 "3.0.2" #_"transitive"]]} + ;; `dev` in :test is important - a test depends on it: :test {:source-paths ["dev"] :dependencies [[com.nedap.staffing-solutions/utils.test "1.6.2"] From 3259cc507112114388d13c7238ab098bd9b109ad Mon Sep 17 00:00:00 2001 From: vemv Date: Sat, 8 Feb 2020 05:15:22 +0100 Subject: [PATCH 33/52] Kondo: use the classpath cache --- src/formatting_stack/linters/kondo.clj | 57 ++++++++++--------- src/formatting_stack/processors/kondo.clj | 22 ------- .../kondo_classpath_cache.clj | 19 +++++++ 3 files changed, 50 insertions(+), 48 deletions(-) delete mode 100644 src/formatting_stack/processors/kondo.clj create mode 100644 worker/formatting_stack/kondo_classpath_cache.clj diff --git a/src/formatting_stack/linters/kondo.clj b/src/formatting_stack/linters/kondo.clj index dd178abf..ec6ae570 100644 --- a/src/formatting_stack/linters/kondo.clj +++ b/src/formatting_stack/linters/kondo.clj @@ -1,7 +1,8 @@ (ns formatting-stack.linters.kondo (:require - [clj-kondo.core :as clj-kondo] + [clj-kondo.core :as kondo] [clojure.set :as set] + [formatting-stack.kondo-classpath-cache] [formatting-stack.protocols.linter :as protocols.linter] [medley.core :refer [deep-merge]] [nedap.utils.modular.api :refer [implement]])) @@ -9,27 +10,28 @@ (def off {:level :off}) (def default-options - {:linters {:cond-else off ;; undesired - :missing-docstring off ;; undesired - :unused-binding off ;; undesired - :unused-symbol off ;; can give false positives - :unused-private-var off ;; can give false positives - :consistent-alias off ;; already offered by how-to-ns - :duplicate-require off ;; already offered by clean-ns - :unused-import off ;; already offered by clean-ns - :unused-namespace off ;; already offered by clean-ns - :unused-referred-var off ;; already offered by clean-ns - :unresolved-namespace off ;; already offered 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"]}}) + {:cache-dir formatting-stack.kondo-classpath-cache/cache-dir + :linters {:cond-else off ;; undesired + :missing-docstring off ;; undesired + :unused-binding off ;; undesired + :unused-symbol off ;; can give false positives + :unused-private-var off ;; can give false positives + :consistent-alias off ;; already offered by how-to-ns + :duplicate-require off ;; already offered by clean-ns + :unused-import off ;; already offered by clean-ns + :unused-namespace off ;; already offered by clean-ns + :unused-referred-var off ;; already offered by clean-ns + :unresolved-namespace off ;; already offered 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"]}}) (def clj-options ;; .clj files are also linted by Eastwood, so we disable duplicate linters: @@ -39,16 +41,19 @@ :redefined-var off}}) (defn lint! [{:keys [kondo-options]} filenames] + + @formatting-stack.kondo-classpath-cache/classpath-cache + (let [kondo-options (or kondo-options {}) {cljs-files true clj-files false} (->> filenames (group-by (fn [f] (-> (re-find #"\.cljs$" f) boolean))))] - (->> [(clj-kondo/run! {:lint clj-files - :config (deep-merge default-options clj-options kondo-options)}) - (clj-kondo/run! {:lint cljs-files - :config (deep-merge default-options kondo-options)})] + (->> [(kondo/run! {:lint clj-files + :config (deep-merge default-options clj-options kondo-options)}) + (kondo/run! {:lint cljs-files + :config (deep-merge default-options kondo-options)})] (mapcat :findings) (map (fn [{source-type :type :as m}] (-> (set/rename-keys m {:row :line diff --git a/src/formatting_stack/processors/kondo.clj b/src/formatting_stack/processors/kondo.clj deleted file mode 100644 index d12d0c19..00000000 --- a/src/formatting_stack/processors/kondo.clj +++ /dev/null @@ -1,22 +0,0 @@ -(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.protocols.processor :as processor] - [nedap.utils.modular.api :refer [implement]]) - (:import - (java.io File))) - -(defn process! [_ _] - (let [files (-> (System/getProperty "java.class.path") - (str/split #"\:")) - cache-dir ".clj-kondo"] - (-> ".clj-kondo" File. .mkdirs) - (clj-kondo/run! {:lint files - :cache-dir cache-dir})) - nil) - -(defn new [] - (implement {} - processor/--process! process!)) diff --git a/worker/formatting_stack/kondo_classpath_cache.clj b/worker/formatting_stack/kondo_classpath_cache.clj new file mode 100644 index 00000000..c1434714 --- /dev/null +++ b/worker/formatting_stack/kondo_classpath_cache.clj @@ -0,0 +1,19 @@ +(ns formatting-stack.kondo-classpath-cache + "Holds a cache for the entire classpath, to make better use of the project-wide analysis capabilities. + + Only needs to be created once, as the classpath never changes." + (:require + [clj-kondo.core :as kondo] + [clojure.string :as string]) + (:import + (java.io File))) + +(def cache-dir ".clj-kondo") + +(def classpath-cache + (delay + (let [files (-> (System/getProperty "java.class.path") + (string/split #"\:"))] + (-> ".clj-kondo" File. .mkdirs) + (kondo/run! {:lint files + :cache-dir cache-dir})))) From 64ef1f7ece3ebaa265340eab49c8c246535b00a2 Mon Sep 17 00:00:00 2001 From: vemv Date: Sat, 8 Feb 2020 05:31:32 +0100 Subject: [PATCH 34/52] Expand `linters.kondo/clj-options` with `:invalid-arity` Already offered by Eastwood. --- src/formatting_stack/linters/kondo.clj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/formatting_stack/linters/kondo.clj b/src/formatting_stack/linters/kondo.clj index ec6ae570..315806df 100644 --- a/src/formatting_stack/linters/kondo.clj +++ b/src/formatting_stack/linters/kondo.clj @@ -36,6 +36,7 @@ (def clj-options ;; .clj files are also linted by Eastwood, so we disable duplicate linters: {:linters {:misplaced-docstring off + :invalid-arity off :deprecated-var off :inline-def off :redefined-var off}}) From a1433c5ae77fdd46737ed1a6e36df7395c5c58c2 Mon Sep 17 00:00:00 2001 From: vemv Date: Sat, 8 Feb 2020 06:22:17 +0100 Subject: [PATCH 35/52] v3.0.0-alpha1 --- README.md | 2 +- project.clj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 94e7452f..fc50077b 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ The general intent is to make formatting: #### Coordinates ```clojure -[formatting-stack "2.0.1-alpha2"] +[formatting-stack "3.0.0-alpha1"] ``` **Also** you might have to add the [refactor-nrepl](https://github.com/clojure-emacs/refactor-nrepl) dependency. diff --git a/project.clj b/project.clj index 6ac93e66..eed32b86 100644 --- a/project.clj +++ b/project.clj @@ -1,5 +1,5 @@ ;; Please don't bump the library version by hand - use ci.release-workflow instead. -(defproject formatting-stack "2.0.1-alpha2" +(defproject formatting-stack "3.0.0-alpha1" ;; Please keep the dependencies sorted a-z. :dependencies [[clj-kondo "2020.01.13"] [cljfmt "0.6.5" :exclusions [rewrite-clj]] From 2e674c25fca82cf2970a99e57086a9e0508c638e Mon Sep 17 00:00:00 2001 From: vemv Date: Sat, 8 Feb 2020 06:58:54 +0100 Subject: [PATCH 36/52] Expand `linters.kondo/default-options` with `:unresolved-symbol` Said linter can very easily trigger a lot of false positives. --- src/formatting_stack/linters/kondo.clj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/formatting_stack/linters/kondo.clj b/src/formatting_stack/linters/kondo.clj index 315806df..99f15e70 100644 --- a/src/formatting_stack/linters/kondo.clj +++ b/src/formatting_stack/linters/kondo.clj @@ -14,6 +14,7 @@ :linters {:cond-else off ;; undesired :missing-docstring off ;; undesired :unused-binding off ;; undesired + :unresolved-symbol off ;; can give false positives :unused-symbol off ;; can give false positives :unused-private-var off ;; can give false positives :consistent-alias off ;; already offered by how-to-ns From 7ededc7749f735a98c2937a2070c3a6a07a28801 Mon Sep 17 00:00:00 2001 From: vemv Date: Sat, 8 Feb 2020 13:53:14 +0100 Subject: [PATCH 37/52] v3.0.0-alpha3 --- README.md | 2 +- project.clj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fc50077b..5b2ae6fd 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ The general intent is to make formatting: #### Coordinates ```clojure -[formatting-stack "3.0.0-alpha1"] +[formatting-stack "3.0.0-alpha3"] ``` **Also** you might have to add the [refactor-nrepl](https://github.com/clojure-emacs/refactor-nrepl) dependency. diff --git a/project.clj b/project.clj index eed32b86..0617c160 100644 --- a/project.clj +++ b/project.clj @@ -1,5 +1,5 @@ ;; Please don't bump the library version by hand - use ci.release-workflow instead. -(defproject formatting-stack "3.0.0-alpha1" +(defproject formatting-stack "3.0.0-alpha3" ;; Please keep the dependencies sorted a-z. :dependencies [[clj-kondo "2020.01.13"] [cljfmt "0.6.5" :exclusions [rewrite-clj]] From 32a2ec77d618a09a226c1ce2106bfa1256817936 Mon Sep 17 00:00:00 2001 From: vemv Date: Mon, 10 Feb 2020 03:22:27 +0100 Subject: [PATCH 38/52] Rework `reporters.pretty-printer` * Prefer truncation to padding * Use a hierarchical format * Prefer coloring to icons * Make coloring optional * (far simpler than detecting tty capabilities, from what I could research) * Within a given file report, group the reports by `:source` Accordingly, `reporters.printer` has been discarded. --- src/formatting_stack/core.clj | 4 +- src/formatting_stack/linters/ns_aliases.clj | 10 +-- src/formatting_stack/protocols/spec.clj | 9 +-- .../reporters/pretty_printer.clj | 65 ++++++++++++++----- src/formatting_stack/reporters/printer.cljc | 62 ------------------ .../reporters/pretty_printer.clj | 46 +++++++++++++ 6 files changed, 105 insertions(+), 91 deletions(-) delete mode 100644 src/formatting_stack/reporters/printer.cljc create mode 100644 test/unit/formatting_stack/reporters/pretty_printer.clj diff --git a/src/formatting_stack/core.clj b/src/formatting_stack/core.clj index b945f7a7..70d264d6 100644 --- a/src/formatting_stack/core.clj +++ b/src/formatting_stack/core.clj @@ -8,7 +8,7 @@ [formatting-stack.protocols.linter :as protocols.linter] [formatting-stack.protocols.processor :as protocols.processor] [formatting-stack.protocols.reporter :refer [report]] - [formatting-stack.reporters.printer :as reporters.printer] + [formatting-stack.reporters.pretty-printer :as reporters.pretty-printer] [formatting-stack.util :refer [with-serialized-output]])) (defn files-from-strategies [strategies] @@ -59,7 +59,7 @@ formatters (or formatters (default-formatters third-party-indent-specs)) linters (or linters default-linters) processors (or processors (default-processors third-party-indent-specs)) - reporter (or reporter (reporters.printer/new {})) + reporter (or reporter (reporters.pretty-printer/new {})) in-background? (if (some? in-background?) in-background? true) diff --git a/src/formatting_stack/linters/ns_aliases.clj b/src/formatting_stack/linters/ns_aliases.clj index 960a9555..cae504b8 100644 --- a/src/formatting_stack/linters/ns_aliases.clj +++ b/src/formatting_stack/linters/ns_aliases.clj @@ -76,8 +76,8 @@ (defn read-ns-decl "Reads file with line/column metadata" [filename] - (with-open [rdr (-> (io/reader filename) PushbackReader. indexing-push-back-reader)] - (parse/read-ns-decl rdr))) + (with-open [reader (-> (io/reader filename) PushbackReader. indexing-push-back-reader)] + (parse/read-ns-decl reader))) (defn lint! [{:keys [acceptable-aliases-whitelist]} filenames] (->> filenames @@ -90,11 +90,11 @@ acceptable-aliases-whitelist)) (map (fn [bad-alias] {:filename filename - :line (:line (meta bad-alias)) - :column (:column (meta bad-alias)) + :line (-> bad-alias meta :line) + :column (-> bad-alias meta :column) :level :warning :warning-details-url "https://stuartsierra.com/2015/05/10/clojure-namespace-aliases" - :msg (str bad-alias " is not a derived alias") + :msg (str bad-alias " is not a derived alias.") :source :formatting-stack/ns-aliases}))))) (mapcat ensure-coll))) diff --git a/src/formatting_stack/protocols/spec.clj b/src/formatting_stack/protocols/spec.clj index 071818ea..1ab2ac6d 100644 --- a/src/formatting_stack/protocols/spec.clj +++ b/src/formatting_stack/protocols/spec.clj @@ -4,23 +4,24 @@ [nedap.utils.spec.predicates :refer [present-string?]])) (spec/def ::filename present-string?) + (spec/def ::filenames (spec/coll-of ::filename)) (spec/def ::msg present-string?) + (spec/def ::source (fn [x] (and (keyword? x) (namespace x)))) -(spec/def ::column - (fn [x] - (or (zero? x) - (pos-int? x)))) +(spec/def ::column nat-int?) (spec/def ::line ::column) + (spec/def ::level #{:warning :error :exception}) (defmulti reportmm :level) + (defmethod reportmm :exception [_] (spec/keys :req-un [::msg ::exception diff --git a/src/formatting_stack/reporters/pretty_printer.clj b/src/formatting_stack/reporters/pretty_printer.clj index 2b3cb684..c32f9987 100644 --- a/src/formatting_stack/reporters/pretty_printer.clj +++ b/src/formatting_stack/reporters/pretty_printer.clj @@ -1,20 +1,39 @@ (ns formatting-stack.reporters.pretty-printer - "Prints a colorized output of the reports" + "Prints an optionally colorized, indented, possibly truncated output of the reports." (:require [clojure.stacktrace :refer [print-stack-trace]] + [clojure.string :as string] [formatting-stack.protocols.reporter :as reporter] + [formatting-stack.protocols.spec :as protocols.spec] [formatting-stack.util :refer [colorize]] [medley.core :refer [map-vals]] + [nedap.speced.def :as speced] [nedap.utils.modular.api :refer [implement]])) +(speced/defn truncate-line-wise [^string? s, length] + (if (= s "\n") + s + (->> (string/split s #"\n") + (map (fn [s] + (let [suffix "…" + string-length (count s) + suffix-length (count suffix)] + (if (<= string-length length) + s + (str (subs s + 0 + (- length suffix-length)) + suffix))))) + (string/join "\n")))) + (defn print-summary [{:keys [summary?]} reports] (when summary? (->> reports (group-by :level) (map-vals count) (into (sorted-map-by compare)) ;; print summary in order - (run! (fn [[type n]] - (-> (str n (case type + (run! (fn [[report-type n]] + (-> (str n (case report-type :exception " exceptions occurred" :error " errors found" :warning " warnings found")) @@ -26,7 +45,7 @@ (defn print-exceptions [{:keys [print-stacktraces?]} reports] (->> reports - (filter (fn [{:keys [level]}] + (filter (speced/fn [{:keys [^::protocols.spec/level level]}] (#{:exception} level))) (group-by :filename) (run! (fn [[title reports]] @@ -37,21 +56,29 @@ (println (ex-message exception))) (println)))))) -(defn print-warnings [{:keys [max-msg-length]} reports] +(speced/defn print-warnings [{:keys [max-msg-length + ^boolean? colorize?]} + ^::protocols.spec/reports reports] (->> reports - (filter (fn [{:keys [level]}] + (filter (speced/fn [{:keys [^::protocols.spec/level level]}] (#{:error :warning} level))) (group-by :filename) (into (sorted-map-by compare)) ;; sort filenames for consistent output (run! (fn [[title reports]] - (println (colorize title :cyan)) - (doseq [{:keys [msg column line source level]} (sort-by :line reports)] - (println (case level - :error (colorize "ˣ" :red) - :warning (colorize "⚠" :yellow)) - (colorize (format "%3d:%-3d" line column) :grey) - (format (str "%-" max-msg-length "." max-msg-length "s") msg) - (colorize (str " " source) :grey))) + (println (cond-> title + colorize? (colorize :cyan))) + (doseq [[source-group group-entries] (->> reports + (group-by :source)) + :let [_ (println " " (cond-> source-group + colorize? (colorize (case (-> group-entries first :level) + :error :red + :warning :yellow))))] + {:keys [msg column line source level]} (->> group-entries + (sort-by :line))] + + (println (cond-> (str " " line ":" column) + colorize? (colorize :grey)) + (truncate-line-wise msg max-msg-length))) (println))))) (defn print-report [this reports] @@ -59,10 +86,12 @@ (print-warnings this reports) (print-summary this reports)) -(defn new [{:keys [max-msg-length print-stacktraces? summary?] - :or {max-msg-length 120 +(defn new [{:keys [max-msg-length print-stacktraces? summary? colorize?] + :or {max-msg-length 200 print-stacktraces? true - summary? true}}] + summary? true + colorize? true}}] (implement {:max-msg-length max-msg-length - :print-stacktraces? print-stacktraces?} + :print-stacktraces? print-stacktraces? + :colorize? colorize?} reporter/--report print-report)) diff --git a/src/formatting_stack/reporters/printer.cljc b/src/formatting_stack/reporters/printer.cljc deleted file mode 100644 index bdfa06d5..00000000 --- a/src/formatting_stack/reporters/printer.cljc +++ /dev/null @@ -1,62 +0,0 @@ -(ns formatting-stack.reporters.printer - "Prints a non-colorized output of the reports" - (:require - [clojure.stacktrace :refer [print-stack-trace]] - [formatting-stack.protocols.reporter :as reporter] - [medley.core :refer [map-vals]] - [nedap.utils.modular.api :refer [implement]])) - -(defn print-summary [{:keys [summary?]} reports] - (when summary? - (->> (group-by :level reports) - (map-vals count) - (into (sorted-map-by compare)) ;; print summary in order - (run! (fn [[type n]] - (-> (str n (case type - :exception " exceptions occurred" - :error " errors found" - :warning " warnings found")) - (println))))))) - -(defn print-exceptions [{:keys [print-stacktraces?]} reports] - (->> reports - (filter (fn [{:keys [level]}] - (#{:exception} level))) - (group-by :filename) - (run! (fn [[title reports]] - (println title) - (doseq [{:keys [^Throwable exception]} reports] - (if print-stacktraces? - (print-stack-trace exception) - (println (ex-message exception))) - (println)))))) - -(defn print-warnings [{:keys [max-msg-length]} reports] - (->> reports - (filter (fn [{:keys [level]}] - (#{:error :warning} level))) - (group-by :filename) - (into (sorted-map-by compare)) ;; sort filenames for consistent output - (run! (fn [[title reports]] - (println title) - (doseq [{:keys [msg column line source level]} (sort-by :line reports)] - (println (case level - :error "ˣ" - :warning "⚠") - (format "%3d:%-3d" line column) - (format (str "%-" max-msg-length "." max-msg-length "s") msg) - (str " " source))) - (println))))) - -(defn print-report [this reports] - (print-exceptions this reports) - (print-warnings this reports) - (print-summary this reports)) - -(defn new [{:keys [max-msg-length print-stacktraces? summary?] - :or {max-msg-length 120 - print-stacktraces? true - summary? true}}] - (implement {:max-msg-length max-msg-length - :print-stacktraces? print-stacktraces?} - reporter/--report print-report)) diff --git a/test/unit/formatting_stack/reporters/pretty_printer.clj b/test/unit/formatting_stack/reporters/pretty_printer.clj new file mode 100644 index 00000000..c5439324 --- /dev/null +++ b/test/unit/formatting_stack/reporters/pretty_printer.clj @@ -0,0 +1,46 @@ +(ns unit.formatting-stack.reporters.pretty-printer + (:require + [clojure.test :refer [are deftest is testing]] + [formatting-stack.reporters.pretty-printer :as sut])) + +(deftest truncate-line-wise + (are [input expected] (testing input + (is (= expected + (sut/truncate-line-wise input 5))) + true) + "" "" + "a" "a" + "aaaaa" "aaaaa" + "aaaaaEXCEEDING" "aaaa…" + "\n" "\n" + "a\na" "a\na" + "a\naaaaaEXCEEDING" "a\naaaa…" + "aaaaaEXCEEDING\na" "aaaa…\na")) + +(deftest print-warnings + (are [desc input expected] (testing [desc input] + (is (= expected + (with-out-str + (sut/print-warnings {:colorize? false + :max-msg-length 20} + input)))) + true) + "Empty" + [] + "" + + "Basic" + [{:filename "filename", :msg "message", :source ::source, :level :warning, :line 0 :column 0}] + "filename\n :unit.formatting-stack.reporters.pretty-printer/source\n 0:0 message\n\n" + + "Sorts by `:line`" + [{:filename "filename", :msg "message", :source ::source, :level :warning, :line 0 :column 0} + {:filename "filename", :msg "message", :source ::source, :level :warning, :line 2 :column 2} + {:filename "filename", :msg "message", :source ::source, :level :warning, :line 1 :column 1}] + "filename\n :unit.formatting-stack.reporters.pretty-printer/source\n 0:0 message\n 1:1 message\n 2:2 message\n\n" + + "Groups by `:source`" + [{:filename "filename", :msg "message", :source ::source-A, :level :warning, :line 0 :column 0} + {:filename "filename", :msg "message", :source ::source-B, :level :warning, :line 2 :column 2} + {:filename "filename", :msg "message", :source ::source-A, :level :warning, :line 1 :column 1}] + "filename\n :unit.formatting-stack.reporters.pretty-printer/source-A\n 0:0 message\n 1:1 message\n :unit.formatting-stack.reporters.pretty-printer/source-B\n 2:2 message\n\n")) From e716a55e09c6aae9416fdd6ebead988e36f53350 Mon Sep 17 00:00:00 2001 From: vemv Date: Mon, 10 Feb 2020 03:38:47 +0100 Subject: [PATCH 39/52] kondo-classpath-cache: prefer `future` to `delay` This trades some eagerness, in exchange for a faster first run of kondo. --- worker/formatting_stack/kondo_classpath_cache.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worker/formatting_stack/kondo_classpath_cache.clj b/worker/formatting_stack/kondo_classpath_cache.clj index c1434714..fceaefa7 100644 --- a/worker/formatting_stack/kondo_classpath_cache.clj +++ b/worker/formatting_stack/kondo_classpath_cache.clj @@ -11,7 +11,7 @@ (def cache-dir ".clj-kondo") (def classpath-cache - (delay + (future (let [files (-> (System/getProperty "java.class.path") (string/split #"\:"))] (-> ".clj-kondo" File. .mkdirs) From 21a9935ee8fbbe296e0b30ac89794176b6773ba4 Mon Sep 17 00:00:00 2001 From: vemv Date: Mon, 10 Feb 2020 03:58:37 +0100 Subject: [PATCH 40/52] `kondo-classpath-cache`: use a safer `cache-dir` --- worker/formatting_stack/kondo_classpath_cache.clj | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/worker/formatting_stack/kondo_classpath_cache.clj b/worker/formatting_stack/kondo_classpath_cache.clj index fceaefa7..c4efa2ed 100644 --- a/worker/formatting_stack/kondo_classpath_cache.clj +++ b/worker/formatting_stack/kondo_classpath_cache.clj @@ -8,12 +8,18 @@ (:import (java.io File))) -(def cache-dir ".clj-kondo") +;; Use kondo's official default config dir, so that we don't bloat consumers' project layouts: +(def cache-parent-dir ".clj-kondo") + +;; Don't use .clj-kondo directly since it can be accessed concurrently (e.g. f-s + a second Kondo from VS Code): +(def cache-subdir "formatting-stack-cache") + +(def cache-dir (str cache-parent-dir File/separator cache-subdir)) (def classpath-cache (future (let [files (-> (System/getProperty "java.class.path") (string/split #"\:"))] - (-> ".clj-kondo" File. .mkdirs) + (-> (File. cache-parent-dir cache-subdir) .mkdirs) (kondo/run! {:lint files :cache-dir cache-dir})))) From 97e4cf573eadb0cc976a1c674ea27fd6991eca96 Mon Sep 17 00:00:00 2001 From: vemv Date: Mon, 10 Feb 2020 04:18:45 +0100 Subject: [PATCH 41/52] Adapt `linters.one-resource-per-ns` to the Reporters feature --- .../linters/one_resource_per_ns.clj | 23 +++++++++++++------ src/formatting_stack/protocols/spec.clj | 10 ++++---- .../reporters/pretty_printer.clj | 9 +++++--- .../reporters/pretty_printer.clj | 7 +++++- 4 files changed, 33 insertions(+), 16 deletions(-) diff --git a/src/formatting_stack/linters/one_resource_per_ns.clj b/src/formatting_stack/linters/one_resource_per_ns.clj index c79c5336..cd488dbc 100644 --- a/src/formatting_stack/linters/one_resource_per_ns.clj +++ b/src/formatting_stack/linters/one_resource_per_ns.clj @@ -36,7 +36,9 @@ (mapv str))) (speced/defn analyze [^present-string? filename] - (for [extension [".clj" ".cljs" ".cljc"] + (for [extension (->> [".clj" ".cljs" ".cljc"] + (filter (fn [x] + (string/ends-with? filename x)))) :let [decl (-> filename file/read-file-ns-decl) resource-path (ns-decl->resource-path decl extension) filenames (resource-path->filenames resource-path)] @@ -50,12 +52,19 @@ (process-in-parallel! (fn [filename] (->> filename analyze - (run! (speced/fn [{:keys [^symbol? ns-name, ^coll? filenames]}] - (println "Warning: the namespace" - (str "`" ns-name "`") - "is defined over more than one file.\nFound:" - (->> filenames (interpose ", ") (apply str))))))))) - []) + (map (speced/fn [{:keys [^symbol? ns-name, ^coll? filenames]}] + {:filename filename + :level :warning + :line 0 + :column 0 + :msg (str "The namespace " + "`" ns-name "`" + " is defined over more than one file. Found:") + :msg-extra-data (->> filenames + (mapv (fn [s] + (string/replace s #"^file:" "")))) + :source :formatting-stack/one-resource-per-ns}))))) + (apply concat))) (speced/defn new [^map? opts] (implement opts diff --git a/src/formatting_stack/protocols/spec.clj b/src/formatting_stack/protocols/spec.clj index 1ab2ac6d..059698ac 100644 --- a/src/formatting_stack/protocols/spec.clj +++ b/src/formatting_stack/protocols/spec.clj @@ -9,10 +9,9 @@ (spec/def ::msg present-string?) -(spec/def ::source - (fn [x] - (and (keyword? x) - (namespace x)))) +(spec/def ::msg-extra-data (spec/coll-of present-string?)) + +(spec/def ::source qualified-keyword?) (spec/def ::column nat-int?) @@ -35,7 +34,8 @@ ::msg ::level ::column - ::line])) + ::line] + :opt-un [::msg-extra-data])) (spec/def ::report (spec/multi-spec reportmm :level)) diff --git a/src/formatting_stack/reporters/pretty_printer.clj b/src/formatting_stack/reporters/pretty_printer.clj index c32f9987..9aef3a4a 100644 --- a/src/formatting_stack/reporters/pretty_printer.clj +++ b/src/formatting_stack/reporters/pretty_printer.clj @@ -73,12 +73,15 @@ colorize? (colorize (case (-> group-entries first :level) :error :red :warning :yellow))))] - {:keys [msg column line source level]} (->> group-entries - (sort-by :line))] + {:keys [msg column line source level msg-extra-data]} (->> group-entries + (sort-by :line))] (println (cond-> (str " " line ":" column) colorize? (colorize :grey)) - (truncate-line-wise msg max-msg-length))) + (truncate-line-wise msg max-msg-length)) + (doseq [entry msg-extra-data] + (println " " + (truncate-line-wise entry max-msg-length)))) (println))))) (defn print-report [this reports] diff --git a/test/unit/formatting_stack/reporters/pretty_printer.clj b/test/unit/formatting_stack/reporters/pretty_printer.clj index c5439324..02968258 100644 --- a/test/unit/formatting_stack/reporters/pretty_printer.clj +++ b/test/unit/formatting_stack/reporters/pretty_printer.clj @@ -43,4 +43,9 @@ [{:filename "filename", :msg "message", :source ::source-A, :level :warning, :line 0 :column 0} {:filename "filename", :msg "message", :source ::source-B, :level :warning, :line 2 :column 2} {:filename "filename", :msg "message", :source ::source-A, :level :warning, :line 1 :column 1}] - "filename\n :unit.formatting-stack.reporters.pretty-printer/source-A\n 0:0 message\n 1:1 message\n :unit.formatting-stack.reporters.pretty-printer/source-B\n 2:2 message\n\n")) + "filename\n :unit.formatting-stack.reporters.pretty-printer/source-A\n 0:0 message\n 1:1 message\n :unit.formatting-stack.reporters.pretty-printer/source-B\n 2:2 message\n\n" + + "Can print `:msg-extra-data` (at the correct indentation level)" + [{:filename "filename", :msg "message", :source ::source, :level :warning, :line 0 :column 0, + :msg-extra-data ["Foo" "Bar"]}] + "filename\n :unit.formatting-stack.reporters.pretty-printer/source\n 0:0 message\n Foo\n Bar\n\n")) From 03703af7cb02e9a0274394ec7c296527f7ed9f3e Mon Sep 17 00:00:00 2001 From: vemv Date: Mon, 10 Feb 2020 04:28:21 +0100 Subject: [PATCH 42/52] Use :warning-details-url --- src/formatting_stack/reporters/pretty_printer.clj | 12 +++++++++--- .../formatting_stack/linters/ns_aliases.clj | 2 +- .../formatting_stack/reporters/pretty_printer.clj | 8 ++++++-- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/formatting_stack/reporters/pretty_printer.clj b/src/formatting_stack/reporters/pretty_printer.clj index 9aef3a4a..77c14527 100644 --- a/src/formatting_stack/reporters/pretty_printer.clj +++ b/src/formatting_stack/reporters/pretty_printer.clj @@ -72,9 +72,15 @@ :let [_ (println " " (cond-> source-group colorize? (colorize (case (-> group-entries first :level) :error :red - :warning :yellow))))] - {:keys [msg column line source level msg-extra-data]} (->> group-entries - (sort-by :line))] + :warning :yellow)))) + _ (when-let [url (->> group-entries + (keep :warning-details-url) + first)] + (cond-> (str " See: " url) + colorize? (colorize :grey) + true println))] + {:keys [msg column line source level msg-extra-data warning-details-url]} (->> group-entries + (sort-by :line))] (println (cond-> (str " " line ":" column) colorize? (colorize :grey)) diff --git a/test/functional/formatting_stack/linters/ns_aliases.clj b/test/functional/formatting_stack/linters/ns_aliases.clj index a978c196..68321083 100644 --- a/test/functional/formatting_stack/linters/ns_aliases.clj +++ b/test/functional/formatting_stack/linters/ns_aliases.clj @@ -21,5 +21,5 @@ :line 3 :column 4 :warning-details-url "https://stuartsierra.com/2015/05/10/clojure-namespace-aliases" - :msg "[clojure.string :as foo] is not a derived alias" + :msg "[clojure.string :as foo] is not a derived alias." :filename "test-resources/ns_aliases_warning.clj"}]))) diff --git a/test/unit/formatting_stack/reporters/pretty_printer.clj b/test/unit/formatting_stack/reporters/pretty_printer.clj index 02968258..c3eceadc 100644 --- a/test/unit/formatting_stack/reporters/pretty_printer.clj +++ b/test/unit/formatting_stack/reporters/pretty_printer.clj @@ -45,7 +45,11 @@ {:filename "filename", :msg "message", :source ::source-A, :level :warning, :line 1 :column 1}] "filename\n :unit.formatting-stack.reporters.pretty-printer/source-A\n 0:0 message\n 1:1 message\n :unit.formatting-stack.reporters.pretty-printer/source-B\n 2:2 message\n\n" + "Can print a given `:warning-details-url`, once at most per `:source` group" + [{:filename "filename", :msg "message", :source ::source-A, :level :warning, :line 0 :column 0} + {:filename "filename", :msg "message", :source ::source-A, :level :warning, :line 1 :column 1 :warning-details-url "http://example.test/foo"}] + "filename\n :unit.formatting-stack.reporters.pretty-printer/source-A\n See: http://example.test/foo\n 0:0 message\n 1:1 message\n\n" + "Can print `:msg-extra-data` (at the correct indentation level)" - [{:filename "filename", :msg "message", :source ::source, :level :warning, :line 0 :column 0, - :msg-extra-data ["Foo" "Bar"]}] + [{:filename "filename", :msg "message", :source ::source, :level :warning, :line 0 :column 0, :msg-extra-data ["Foo" "Bar"]}] "filename\n :unit.formatting-stack.reporters.pretty-printer/source\n 0:0 message\n Foo\n Bar\n\n")) From f4f316910ecc6bea8e4b78fdb014a4f6ecdd6b6b Mon Sep 17 00:00:00 2001 From: vemv Date: Mon, 10 Feb 2020 04:53:58 +0100 Subject: [PATCH 43/52] Make `line-length`/`loc-per-ns` reports more informative By making the emitted :column/:line info more variable, users can get an idea of how greatly was a given limit surpassed. --- src/formatting_stack/linters/line_length.clj | 15 +++++++------- src/formatting_stack/linters/loc_per_ns.clj | 20 +++++++++---------- .../formatting_stack/linters/line_length.clj | 2 +- .../formatting_stack/linters/loc_per_ns.clj | 4 ++-- 4 files changed, 21 insertions(+), 20 deletions(-) diff --git a/src/formatting_stack/linters/line_length.clj b/src/formatting_stack/linters/line_length.clj index d10b1c15..c0f49f4a 100644 --- a/src/formatting_stack/linters/line_length.clj +++ b/src/formatting_stack/linters/line_length.clj @@ -8,13 +8,14 @@ (defn exceeding-lines [threshold filename] (->> (-> filename slurp (string/split #"\n")) (map-indexed (fn [i row] - (when (< threshold (count row)) - {:filename filename - :source :formatting-stack/line-length - :level :warning - :column (inc threshold) - :line (inc i) - :msg (str "Line exceeding " threshold " columns")}))) + (let [column-count (count row)] + (when (< threshold column-count) + {:filename filename + :source :formatting-stack/line-length + :level :warning + :column column-count + :line (inc i) + :msg (str "Line exceeding " threshold " columns")})))) (remove nil?))) (defn lint! [{:keys [max-line-length]} filenames] diff --git a/src/formatting_stack/linters/loc_per_ns.clj b/src/formatting_stack/linters/loc_per_ns.clj index 489262de..118565db 100644 --- a/src/formatting_stack/linters/loc_per_ns.clj +++ b/src/formatting_stack/linters/loc_per_ns.clj @@ -5,23 +5,23 @@ [formatting-stack.util :refer [process-in-parallel!]] [nedap.utils.modular.api :refer [implement]])) -(defn overly-long-ns? [filename threshold] +(defn count-lines [filename] (-> filename slurp (string/split #"\n") - (count) - (> threshold))) + (count))) (defn lint! [{:keys [max-lines-per-ns]} filenames] (->> filenames (process-in-parallel! (fn [filename] - (when (overly-long-ns? filename max-lines-per-ns) - {:filename filename - :source :formatting-stack/loc-per-ns - :level :warning - :msg (str "Longer than " max-lines-per-ns " LOC. consider refactoring") - :line (inc max-lines-per-ns) ;; first line after limit is the issue - :column 1}))) + (let [lines (count-lines filename)] + (when (> lines max-lines-per-ns) + {:filename filename + :source :formatting-stack/loc-per-ns + :level :warning + :msg (str "Longer than " max-lines-per-ns " LOC. Consider refactoring.") + :line lines + :column 0})))) (remove nil?))) (defn new [{:keys [max-lines-per-ns] diff --git a/test/functional/formatting_stack/linters/line_length.clj b/test/functional/formatting_stack/linters/line_length.clj index c6ee54c5..a6f90b8d 100644 --- a/test/functional/formatting_stack/linters/line_length.clj +++ b/test/functional/formatting_stack/linters/line_length.clj @@ -15,6 +15,6 @@ "test-resources/sample_clj_ns.clj" [{:source :formatting-stack/line-length :line 3 - :column 23 + :column 25 :msg "Line exceeding 22 columns" :filename "test-resources/sample_clj_ns.clj"}]))) diff --git a/test/functional/formatting_stack/linters/loc_per_ns.clj b/test/functional/formatting_stack/linters/loc_per_ns.clj index 5049c3db..ae2643fe 100644 --- a/test/functional/formatting_stack/linters/loc_per_ns.clj +++ b/test/functional/formatting_stack/linters/loc_per_ns.clj @@ -15,6 +15,6 @@ "test-resources/sample_clj_ns.clj" [{:source :formatting-stack/loc-per-ns :line 5 - :column 1 - :msg "Longer than 4 LOC. consider refactoring" + :column 0 + :msg "Longer than 4 LOC. Consider refactoring." :filename "test-resources/sample_clj_ns.clj"}]))) From f0c8928cb348f2d688a392ba2325a9c85d97a588 Mon Sep 17 00:00:00 2001 From: vemv Date: Mon, 10 Feb 2020 05:10:11 +0100 Subject: [PATCH 44/52] v3.0.0-alpha6 --- README.md | 2 +- project.clj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5b2ae6fd..63a8628e 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ The general intent is to make formatting: #### Coordinates ```clojure -[formatting-stack "3.0.0-alpha3"] +[formatting-stack "3.0.0-alpha6"] ``` **Also** you might have to add the [refactor-nrepl](https://github.com/clojure-emacs/refactor-nrepl) dependency. diff --git a/project.clj b/project.clj index 0617c160..b67e3df4 100644 --- a/project.clj +++ b/project.clj @@ -1,5 +1,5 @@ ;; Please don't bump the library version by hand - use ci.release-workflow instead. -(defproject formatting-stack "3.0.0-alpha3" +(defproject formatting-stack "3.0.0-alpha6" ;; Please keep the dependencies sorted a-z. :dependencies [[clj-kondo "2020.01.13"] [cljfmt "0.6.5" :exclusions [rewrite-clj]] From d4ba329d28f078f2478aca83b585ec2fb48aeb35 Mon Sep 17 00:00:00 2001 From: vemv Date: Tue, 11 Feb 2020 00:45:39 +0100 Subject: [PATCH 45/52] Ensure `process-in-parallel!` workloads are performed eagerly A callback passed to `process-in-parallel!` shouldn't return a lazy computation, since that would make the parallel machinery useless (a lazy computation is expressed in parallel, but it's only realised later, in a non-parallel context). --- src/formatting_stack/linters/line_length.clj | 3 ++- src/formatting_stack/linters/ns_aliases.clj | 17 ++++++------- .../linters/one_resource_per_ns.clj | 24 +++++++++---------- src/formatting_stack/util.clj | 16 ++++++++++++- 4 files changed, 38 insertions(+), 22 deletions(-) diff --git a/src/formatting_stack/linters/line_length.clj b/src/formatting_stack/linters/line_length.clj index c0f49f4a..b109e747 100644 --- a/src/formatting_stack/linters/line_length.clj +++ b/src/formatting_stack/linters/line_length.clj @@ -16,7 +16,8 @@ :column column-count :line (inc i) :msg (str "Line exceeding " threshold " columns")})))) - (remove nil?))) + (remove nil?) + (vec))) (defn lint! [{:keys [max-line-length]} filenames] (->> filenames diff --git a/src/formatting_stack/linters/ns_aliases.clj b/src/formatting_stack/linters/ns_aliases.clj index cae504b8..9fae0f62 100644 --- a/src/formatting_stack/linters/ns_aliases.clj +++ b/src/formatting_stack/linters/ns_aliases.clj @@ -88,14 +88,15 @@ (rest) (remove (partial acceptable-require-clause? acceptable-aliases-whitelist)) - (map (fn [bad-alias] - {:filename filename - :line (-> bad-alias meta :line) - :column (-> bad-alias meta :column) - :level :warning - :warning-details-url "https://stuartsierra.com/2015/05/10/clojure-namespace-aliases" - :msg (str bad-alias " is not a derived alias.") - :source :formatting-stack/ns-aliases}))))) + (filter some?) + (mapv (fn [bad-alias] + {:filename filename + :line (-> bad-alias meta :line) + :column (-> bad-alias meta :column) + :level :warning + :warning-details-url "https://stuartsierra.com/2015/05/10/clojure-namespace-aliases" + :msg (str bad-alias " is not a derived alias.") + :source :formatting-stack/ns-aliases}))))) (mapcat ensure-coll))) (defn new [{:keys [acceptable-aliases-whitelist] diff --git a/src/formatting_stack/linters/one_resource_per_ns.clj b/src/formatting_stack/linters/one_resource_per_ns.clj index cd488dbc..d76b3427 100644 --- a/src/formatting_stack/linters/one_resource_per_ns.clj +++ b/src/formatting_stack/linters/one_resource_per_ns.clj @@ -52,18 +52,18 @@ (process-in-parallel! (fn [filename] (->> filename analyze - (map (speced/fn [{:keys [^symbol? ns-name, ^coll? filenames]}] - {:filename filename - :level :warning - :line 0 - :column 0 - :msg (str "The namespace " - "`" ns-name "`" - " is defined over more than one file. Found:") - :msg-extra-data (->> filenames - (mapv (fn [s] - (string/replace s #"^file:" "")))) - :source :formatting-stack/one-resource-per-ns}))))) + (mapv (speced/fn [{:keys [^symbol? ns-name, ^coll? filenames]}] + {:filename filename + :level :warning + :line 0 + :column 0 + :msg (str "The namespace " + "`" ns-name "`" + " is defined over more than one file. Found:") + :msg-extra-data (->> filenames + (mapv (fn [s] + (string/replace s #"^file:" "")))) + :source :formatting-stack/one-resource-per-ns}))))) (apply concat))) (speced/defn new [^map? opts] diff --git a/src/formatting_stack/util.clj b/src/formatting_stack/util.clj index b266fc55..855ecbe3 100644 --- a/src/formatting_stack/util.clj +++ b/src/formatting_stack/util.clj @@ -1,5 +1,6 @@ (ns formatting-stack.util (:require + [clojure.spec.alpha :as spec] [clojure.tools.namespace.file :as file] [clojure.tools.namespace.parse :as parse] [medley.core :refer [find-first]] @@ -8,6 +9,7 @@ [nedap.utils.collections.seq :refer [distribute-evenly-by]] [nedap.utils.spec.predicates :refer [present-string?]]) (:import + (clojure.lang IBlockingDeref IPending) (java.io File))) (defmacro rcomp @@ -61,13 +63,25 @@ :msg "Encountered an exception" :exception e}) +(spec/def ::non-lazy-result + (fn [x] + (cond + (sequential? x) (vector? x) + (instance? IBlockingDeref x) false + (instance? IPending x) false + true true))) + (defn process-in-parallel! [f files] (->> files (distribute-evenly-by {:f (fn [^String filename] (-> (File. filename) .length))}) (partitioning-pmap (bound-fn [filename] (try - (f filename) + (let [v (f filename)] + (assert (spec/valid? ::non-lazy-result v) + (pr-str "Parallel processing shouldn't return lazy computations" + f)) + v) (catch Exception e (report-processing-error e filename)) (catch AssertionError e From 95cad72c26523d4e93470e04f655fd23f7fff726 Mon Sep 17 00:00:00 2001 From: vemv Date: Tue, 11 Feb 2020 01:00:01 +0100 Subject: [PATCH 46/52] Rearrange linters order The idea is to place linters with a best usefuleness/speed ratio first. --- src/formatting_stack/branch_formatter.clj | 20 ++++++++++---------- src/formatting_stack/defaults.clj | 20 ++++++++++---------- src/formatting_stack/project_formatter.clj | 20 ++++++++++---------- src/formatting_stack/project_parsing.clj | 1 + 4 files changed, 31 insertions(+), 30 deletions(-) diff --git a/src/formatting_stack/branch_formatter.clj b/src/formatting_stack/branch_formatter.clj index 4dbed24e..95ba50ca 100644 --- a/src/formatting_stack/branch_formatter.clj +++ b/src/formatting_stack/branch_formatter.clj @@ -47,30 +47,30 @@ (filterv some?))) (defn default-linters [default-strategies] - [(-> (linters.ns-aliases/new {}) + [(-> (linters.kondo/new {}) + (assoc :strategies (conj default-strategies + strategies/exclude-edn))) + (-> (linters.one-resource-per-ns/new {}) + (assoc :strategies (conj default-strategies + strategies/files-with-a-namespace))) + (-> (linters.ns-aliases/new {}) (assoc :strategies (conj default-strategies strategies/files-with-a-namespace ;; reader conditionals may confuse `linters.ns-aliases` strategies/exclude-cljc ;; string requires may confuse clojure.tools.* strategies/exclude-cljs))) - (-> (linters.loc-per-ns/new {}) + (-> (linters.line-length/new {}) (assoc :strategies (conj default-strategies strategies/exclude-edn))) - (-> (linters.line-length/new {}) + (-> (linters.loc-per-ns/new {}) (assoc :strategies (conj default-strategies strategies/exclude-edn))) (-> (linters.eastwood/new {}) (assoc :strategies (conj default-strategies strategies/exclude-cljs strategies/jvm-requirable-files - strategies/namespaces-within-refresh-dirs-only))) - (-> (linters.kondo/new {}) - (assoc :strategies (conj default-strategies - strategies/exclude-edn))) - (-> (linters.one-resource-per-ns/new {}) - (assoc :strategies (conj default-strategies - strategies/files-with-a-namespace)))]) + strategies/namespaces-within-refresh-dirs-only)))]) (def default-processors [(processors.cider/new {:third-party-indent-specs third-party-indent-specs})]) diff --git a/src/formatting_stack/defaults.clj b/src/formatting_stack/defaults.clj index 35b46e5f..3df34555 100644 --- a/src/formatting_stack/defaults.clj +++ b/src/formatting_stack/defaults.clj @@ -47,30 +47,30 @@ strategies/do-not-use-cached-results!))))] (filterv some?)))) -(def default-linters [(-> (linters.ns-aliases/new {}) +(def default-linters [(-> (linters.kondo/new {}) + (assoc :strategies (conj extended-strategies + strategies/exclude-edn))) + (-> (linters.one-resource-per-ns/new {}) + (assoc :strategies (conj extended-strategies + strategies/files-with-a-namespace))) + (-> (linters.ns-aliases/new {}) (assoc :strategies (conj extended-strategies strategies/files-with-a-namespace ;; reader conditionals may confuse `linters.ns-aliases` strategies/exclude-cljc ;; string requires may confuse clojure.tools.* strategies/exclude-cljs))) - (-> (linters.loc-per-ns/new {}) + (-> (linters.line-length/new {}) (assoc :strategies (conj extended-strategies strategies/exclude-edn))) - (-> (linters.line-length/new {}) + (-> (linters.loc-per-ns/new {}) (assoc :strategies (conj extended-strategies strategies/exclude-edn))) (-> (linters.eastwood/new {}) (assoc :strategies (conj extended-strategies strategies/exclude-cljs strategies/jvm-requirable-files - strategies/namespaces-within-refresh-dirs-only))) - (-> (linters.kondo/new {}) - (assoc :strategies (conj extended-strategies - strategies/exclude-edn))) - (-> (linters.one-resource-per-ns/new {}) - (assoc :strategies (conj extended-strategies - strategies/files-with-a-namespace)))]) + strategies/namespaces-within-refresh-dirs-only)))]) (defn default-processors [third-party-indent-specs] [(-> (processors.cider/new {:third-party-indent-specs third-party-indent-specs}) diff --git a/src/formatting_stack/project_formatter.clj b/src/formatting_stack/project_formatter.clj index af4a6880..43e1e614 100644 --- a/src/formatting_stack/project_formatter.clj +++ b/src/formatting_stack/project_formatter.clj @@ -51,30 +51,30 @@ (filterv some?))) (def default-linters - [(-> (linters.ns-aliases/new {}) + [(-> (linters.kondo/new {}) + (assoc :strategies (conj default-strategies + strategies/exclude-edn))) + (-> (linters.one-resource-per-ns/new {}) + (assoc :strategies (conj default-strategies + strategies/files-with-a-namespace))) + (-> (linters.ns-aliases/new {}) (assoc :strategies (conj default-strategies strategies/files-with-a-namespace ;; reader conditionals may confuse `linters.ns-aliases` strategies/exclude-cljc ;; string requires may confuse clojure.tools.* strategies/exclude-cljs))) - (-> (linters.loc-per-ns/new {}) + (-> (linters.line-length/new {}) (assoc :strategies (conj default-strategies strategies/exclude-edn))) - (-> (linters.line-length/new {}) + (-> (linters.loc-per-ns/new {}) (assoc :strategies (conj default-strategies strategies/exclude-edn))) (-> (linters.eastwood/new {}) (assoc :strategies (conj default-strategies strategies/exclude-cljs strategies/jvm-requirable-files - strategies/namespaces-within-refresh-dirs-only))) - (-> (linters.kondo/new {}) - (assoc :strategies (conj default-strategies - strategies/exclude-edn))) - (-> (linters.one-resource-per-ns/new {}) - (assoc :strategies (conj default-strategies - strategies/files-with-a-namespace)))]) + strategies/namespaces-within-refresh-dirs-only)))]) (def default-processors [(processors.cider/new {:third-party-indent-specs third-party-indent-specs})]) diff --git a/src/formatting_stack/project_parsing.clj b/src/formatting_stack/project_parsing.clj index 77b7d8e0..682e1a84 100644 --- a/src/formatting_stack/project_parsing.clj +++ b/src/formatting_stack/project_parsing.clj @@ -2,6 +2,7 @@ (:require [clojure.java.classpath :as classpath] [clojure.java.io :as io] + [clojure.stacktrace] [clojure.tools.namespace.file :as file] [clojure.tools.namespace.find :as find] [clojure.tools.namespace.parse :as parse] From e4d04c0478abd811362cea68e7577b6584a3ebf2 Mon Sep 17 00:00:00 2001 From: vemv Date: Tue, 11 Feb 2020 01:08:31 +0100 Subject: [PATCH 47/52] Introduce `ensure-sequential` This allows restoring `ensure-coll` its old semantics, preventing complexities. --- src/formatting_stack/linters/line_length.clj | 4 ++-- src/formatting_stack/linters/ns_aliases.clj | 4 ++-- src/formatting_stack/util.clj | 6 ++++++ 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/formatting_stack/linters/line_length.clj b/src/formatting_stack/linters/line_length.clj index b109e747..b50f023e 100644 --- a/src/formatting_stack/linters/line_length.clj +++ b/src/formatting_stack/linters/line_length.clj @@ -2,7 +2,7 @@ (:require [clojure.string :as string] [formatting-stack.protocols.linter :as linter] - [formatting-stack.util :refer [ensure-coll process-in-parallel!]] + [formatting-stack.util :refer [ensure-coll ensure-sequential process-in-parallel!]] [nedap.utils.modular.api :refer [implement]])) (defn exceeding-lines [threshold filename] @@ -22,7 +22,7 @@ (defn lint! [{:keys [max-line-length]} filenames] (->> filenames (process-in-parallel! (partial exceeding-lines max-line-length)) - (mapcat ensure-coll))) + (mapcat ensure-sequential))) (defn new [{:keys [max-line-length] :or {max-line-length 130}}] diff --git a/src/formatting_stack/linters/ns_aliases.clj b/src/formatting_stack/linters/ns_aliases.clj index 9fae0f62..1184af9c 100644 --- a/src/formatting_stack/linters/ns_aliases.clj +++ b/src/formatting_stack/linters/ns_aliases.clj @@ -6,7 +6,7 @@ [clojure.tools.namespace.parse :as parse] [clojure.tools.reader.reader-types :refer [indexing-push-back-reader]] [formatting-stack.protocols.linter :as linter] - [formatting-stack.util :refer [ensure-coll process-in-parallel!]] + [formatting-stack.util :refer [ensure-sequential ensure-coll process-in-parallel!]] [nedap.utils.modular.api :refer [implement]]) (:import (java.io PushbackReader))) @@ -97,7 +97,7 @@ :warning-details-url "https://stuartsierra.com/2015/05/10/clojure-namespace-aliases" :msg (str bad-alias " is not a derived alias.") :source :formatting-stack/ns-aliases}))))) - (mapcat ensure-coll))) + (mapcat ensure-sequential))) (defn new [{:keys [acceptable-aliases-whitelist] :or {acceptable-aliases-whitelist default-acceptable-aliases-whitelist}}] diff --git a/src/formatting_stack/util.clj b/src/formatting_stack/util.clj index 855ecbe3..ad50fda7 100644 --- a/src/formatting_stack/util.clj +++ b/src/formatting_stack/util.clj @@ -107,6 +107,12 @@ false))) (speced/defn ensure-coll [^some? x] + (if (coll? x) + x + [x])) + +;; Rationale: https://github.com/nedap/formatting-stack/pull/109/files#r376891779 +(speced/defn ensure-sequential [^some? x] (if (sequential? x) x [x])) From 5a0a72d44e9d176e96379cb41cd42fd7a8fb1f25 Mon Sep 17 00:00:00 2001 From: vemv Date: Tue, 11 Feb 2020 01:16:56 +0100 Subject: [PATCH 48/52] `reporters.file-writer`: rename the default filename --- src/formatting_stack/reporters/file_writer.clj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/formatting_stack/reporters/file_writer.clj b/src/formatting_stack/reporters/file_writer.clj index 7df3e673..ea6505d5 100644 --- a/src/formatting_stack/reporters/file_writer.clj +++ b/src/formatting_stack/reporters/file_writer.clj @@ -1,5 +1,5 @@ (ns formatting-stack.reporters.file-writer - "writes the output to a file which can be tailed with `watch --color -n 1 cat .fs-output.txt`" + "Writes the output to a file which can be observed with e.g. `watch --color -n 1 cat .formatting-stack-report`." (:require [formatting-stack.protocols.reporter :as protocols.reporter] [formatting-stack.reporters.pretty-printer :as pretty-printer] @@ -12,7 +12,7 @@ (defn new [{:keys [printer filename] :or {printer (pretty-printer/new {}) - filename ".fs-output.txt"}}] + filename ".formatting-stack-report"}}] (implement {:printer printer :filename filename} protocols.reporter/--report write-report)) From 27f90e09f1ef187108c1da765375b00a870da17a Mon Sep 17 00:00:00 2001 From: vemv Date: Tue, 11 Feb 2020 01:22:25 +0100 Subject: [PATCH 49/52] Split kondo options per-platform --- src/formatting_stack/linters/kondo.clj | 16 ++++++++++------ .../formatting_stack/linters/kondo.clj | 4 ++-- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/formatting_stack/linters/kondo.clj b/src/formatting_stack/linters/kondo.clj index 99f15e70..df6ecdac 100644 --- a/src/formatting_stack/linters/kondo.clj +++ b/src/formatting_stack/linters/kondo.clj @@ -42,20 +42,22 @@ :inline-def off :redefined-var off}}) -(defn lint! [{:keys [kondo-options]} filenames] +(defn lint! [{:keys [kondo-clj-options kondo-cljs-options]} + filenames] @formatting-stack.kondo-classpath-cache/classpath-cache - (let [kondo-options (or kondo-options {}) + (let [kondo-clj-options (or kondo-clj-options {}) + kondo-cljs-options (or kondo-cljs-options {}) {cljs-files true clj-files false} (->> filenames (group-by (fn [f] (-> (re-find #"\.cljs$" f) boolean))))] (->> [(kondo/run! {:lint clj-files - :config (deep-merge default-options clj-options kondo-options)}) + :config (deep-merge default-options clj-options kondo-clj-options)}) (kondo/run! {:lint cljs-files - :config (deep-merge default-options kondo-options)})] + :config (deep-merge default-options kondo-cljs-options)})] (mapcat :findings) (map (fn [{source-type :type :as m}] (-> (set/rename-keys m {:row :line @@ -63,6 +65,8 @@ :col :column}) (assoc :source (keyword "kondo" (name source-type))))))))) -(defn new [{:keys [kondo-options]}] - (implement {:kondo-options kondo-options} +(defn new [{:keys [kondo-clj-options + kondo-cljs-options]}] + (implement {:kondo-clj-options kondo-clj-options + :kondo-cljs-options kondo-cljs-options} protocols.linter/--lint! lint!)) diff --git a/test/functional/formatting_stack/linters/kondo.clj b/test/functional/formatting_stack/linters/kondo.clj index d7d2c25b..d58c66c4 100644 --- a/test/functional/formatting_stack/linters/kondo.clj +++ b/test/functional/formatting_stack/linters/kondo.clj @@ -7,8 +7,8 @@ [matcher-combinators.test :refer [match?]])) (deftest lint! - (let [linter (sut/new {:kondo-options {:output {:exclude-files []} - :linters {:unused-binding {:level :warning}}}})] + (let [linter (sut/new {:kondo-clj-options {:output {:exclude-files []} + :linters {:unused-binding {:level :warning}}}})] (are [filename expected] (match? expected (linter/lint! linter [filename])) "test-resources/invalid_syntax.clj" From ebf52ec85e3cec02b37a8785b2acd1b0b298f3e3 Mon Sep 17 00:00:00 2001 From: vemv Date: Tue, 11 Feb 2020 01:52:32 +0100 Subject: [PATCH 50/52] Strengthen `project-parsing/project-namespaces` Now it can handle files containing invalid syntax. There was a previous attempt of this, but too coarse-grained. --- src/formatting_stack/project_parsing.clj | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/formatting_stack/project_parsing.clj b/src/formatting_stack/project_parsing.clj index 682e1a84..29fc6322 100644 --- a/src/formatting_stack/project_parsing.clj +++ b/src/formatting_stack/project_parsing.clj @@ -2,10 +2,9 @@ (:require [clojure.java.classpath :as classpath] [clojure.java.io :as io] - [clojure.stacktrace] - [clojure.tools.namespace.file :as file] [clojure.tools.namespace.find :as find] [clojure.tools.namespace.parse :as parse] + [formatting-stack.formatters.clean-ns.impl :refer [ns-form-of]] [nedap.speced.def :as speced] [nedap.utils.collections.eager :refer [partitioning-pmap]]) (:import @@ -29,11 +28,12 @@ Includes third-party dependencies." [] (->> (find-files (classpath/classpath-directories) find/clj) - (partitioning-pmap (fn [file] - (let [decl (-> file file/read-file-ns-decl) - n (-> decl parse/name-from-ns-decl) - deps (-> decl parse/deps-from-ns-decl)] - (conj deps n)))) + + (partitioning-pmap (speced/fn [^File file] + (let [decl (-> file str ns-form-of) + n (some-> decl parse/name-from-ns-decl) + deps (some-> decl parse/deps-from-ns-decl)] + (some-> deps (conj n))))) (apply concat) (distinct) (filter identity) From 5b9ca386efb3b1e0140ff678d64cd94a4c920f71 Mon Sep 17 00:00:00 2001 From: vemv Date: Tue, 11 Feb 2020 01:52:56 +0100 Subject: [PATCH 51/52] Tweak some linters' `:msg`s --- src/formatting_stack/linters/line_length.clj | 2 +- src/formatting_stack/linters/loc_per_ns.clj | 2 +- test/functional/formatting_stack/linters/line_length.clj | 2 +- test/functional/formatting_stack/linters/loc_per_ns.clj | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/formatting_stack/linters/line_length.clj b/src/formatting_stack/linters/line_length.clj index b50f023e..ec087590 100644 --- a/src/formatting_stack/linters/line_length.clj +++ b/src/formatting_stack/linters/line_length.clj @@ -15,7 +15,7 @@ :level :warning :column column-count :line (inc i) - :msg (str "Line exceeding " threshold " columns")})))) + :msg (str "Line exceeding " threshold " columns.")})))) (remove nil?) (vec))) diff --git a/src/formatting_stack/linters/loc_per_ns.clj b/src/formatting_stack/linters/loc_per_ns.clj index 118565db..02068141 100644 --- a/src/formatting_stack/linters/loc_per_ns.clj +++ b/src/formatting_stack/linters/loc_per_ns.clj @@ -19,7 +19,7 @@ {:filename filename :source :formatting-stack/loc-per-ns :level :warning - :msg (str "Longer than " max-lines-per-ns " LOC. Consider refactoring.") + :msg (str "Longer than " max-lines-per-ns " LOC.") :line lines :column 0})))) (remove nil?))) diff --git a/test/functional/formatting_stack/linters/line_length.clj b/test/functional/formatting_stack/linters/line_length.clj index a6f90b8d..36adb174 100644 --- a/test/functional/formatting_stack/linters/line_length.clj +++ b/test/functional/formatting_stack/linters/line_length.clj @@ -16,5 +16,5 @@ [{:source :formatting-stack/line-length :line 3 :column 25 - :msg "Line exceeding 22 columns" + :msg "Line exceeding 22 columns." :filename "test-resources/sample_clj_ns.clj"}]))) diff --git a/test/functional/formatting_stack/linters/loc_per_ns.clj b/test/functional/formatting_stack/linters/loc_per_ns.clj index ae2643fe..9e6e165f 100644 --- a/test/functional/formatting_stack/linters/loc_per_ns.clj +++ b/test/functional/formatting_stack/linters/loc_per_ns.clj @@ -16,5 +16,5 @@ [{:source :formatting-stack/loc-per-ns :line 5 :column 0 - :msg "Longer than 4 LOC. Consider refactoring." + :msg "Longer than 4 LOC." :filename "test-resources/sample_clj_ns.clj"}]))) From b1c488bbe66fdc1ca3a0ec836db192910d22d415 Mon Sep 17 00:00:00 2001 From: vemv Date: Tue, 11 Feb 2020 02:15:04 +0100 Subject: [PATCH 52/52] Remove a disabled test It would be anomalous that Eastwood hit a syntactically broken anyway - it could indicate room for improvement in strategies/etc. --- test/functional/formatting_stack/linters/eastwood.clj | 9 --------- 1 file changed, 9 deletions(-) diff --git a/test/functional/formatting_stack/linters/eastwood.clj b/test/functional/formatting_stack/linters/eastwood.clj index 00c57cd7..3bddf70f 100644 --- a/test/functional/formatting_stack/linters/eastwood.clj +++ b/test/functional/formatting_stack/linters/eastwood.clj @@ -10,15 +10,6 @@ (let [linter (sut/new {})] (are [filename expected] (match? expected (linter/lint! linter [filename])) - ;; fixme should return a :reader-exception, currently lost in :note. lint! yields empty list - #_#_"test-resources/invalid_syntax.clj" - (matchers/embeds - [{:level :exception, - :filename "test-resources/invalid_syntax.clj", - :line 3, - :column 2, - :source :eastwood/lint!}]) - "test-resources/eastwood_warning.clj" (matchers/embeds [{:source :eastwood/def-in-def