This changelog is loose. Versions are not semantic, they are incremental. Splint is not meant to be infrastructure, so don't rely on it like infrastructure; it is a helpful development tool.
lint/misplaced-type-hint
: Prefer(defn make-str ^String [] "abc")
over(defn ^String make-str [] "abc")
. Only checksdefn
forms at the moment.
- Support Clojure 1.10, don't force downstream users to update.
- Add matrix testing for each supported clojure version to GHA.
- Update
edamame
to 1.4.28.
style/redundant-nested-call
: Prefer(+ 1 2 3 4)
to(+ 1 2 (+ 3 4))
.
- Table of Contents to each of the rules pages.
style/into-literal
ignores when in a threaded context.lint/def-fn
ignores when in a syntax-quoted context.
lint/defmethod-names
: Require thatdefmethod
calls define a name for the function body. This helps improve stack traces. Suggested names are built from the dispatch value and cannot be trusted to be unique or usable, so while the rule is safe, it does not support autocorrect. Disabled by default.
style/is-eq-order
relaxed expected input to accept any non-quoted list. (See #25.)
- Autocorrect skips quoted forms.
- Autocorrect only saves non-empty files.
- Autocorrect removes all rules that don't have
:autocorrect
. --interactive
has been added to the CLI options, making it usable. (oops)--interactive
now applies:autocorrect
so it doesn't need to be specified.
Big feature: Safety and Autocorrection
Every rule has been marked as safe or unsafe. Safe rules don't generate false positives and any suggested alternatives can be used directly. Unsafe rules may generate false positives or their suggested alternatives may contain errors.
Rules that are safe may also perform autocorrection, which is tracked in defrule
with :autocorrect
. Rules may only perform autocorrection if they're safe.
The Rules Overview has been expanded as well.
- Update dependencies.
edamame
1.4.27 supports the Clojure 1.12 array syntax:Integer/1
. - Rules documentation can now handle 3 different directives:
@note
,@safety
, and@examples
. All existing# Examples
have been converted to@examples
, and the relevant rule docstrings have been updated. - Rules documentation generation has been changed to handle the above.
- Added
:autocorrect
todefrule
,:safe
to config schema.
lint/redundant-str-call
ignores when used in threading macros. (See #20.)lint/redundant-call
ignores when used in threading macros. (See #21.)- Fix matching
nil
when input is too short in patterns, which fixes subtle issues withlint/cond-else
. - Make
support-clojure-version?
only compare minor versions if major version numbers match, and likewise with incremental/minor version numbers.
lint/redundant-str-call
: Don't callstr
on input that's guaranteed to be a string: Prefer"foo"
to(str "foo")
,(str "foo" bar)
to(str (str "foo" bar))
, and(format "foo%s" bar)
to(str (format "foo%s" bar))
. (See clj-kondo#2323 for inspiration.)lint/duplicate-case-test
: Don't use the same case test constant more than once.lint/locking-object
: Prefer to lock on a symbol bound to(Object.)
.
--only RULE
cli flag to run only specified rules or genres. Can be used multiple times. (#13)
- Switched from
clojure.pprint
to fipp for pretty-printing code. Fast and easy to extend. - Use org.flatland/ordered (when run in Clojure) to keep parsed maps and sets in their read order.
- Add exceptions to diagnostics and print stack traces in all errors. Should fix bugs where all that's printed is
Splint encountered an error: ""
which is unhelpful and shameful. - External links in
default.edn
are now:links
, a vector of strings. This allows for listing multiple references. - Switch all tests to Lazytest to do some dogfooding.
- Enforce that
??
only 1 or 2 arguments, and if provided, that the predicate is a symbol. - Updated all dependencies.
- Switch tests to use Lazytest.
- Outputs
json
andjson-pretty
now work with Babashka, by relying on Babashka's built-inchehire.core
instead ofclojure.data.json
. This shouldn't result in any observable differences. I'd usecheshire.core
for both, butcheshire.core
is much bigger and more complicated thanclojure.data.json
, and it's a pain in the ass imo.
- Expanded documentation, added CONTRIBUTING.md.
- Switch all existing uses of
deftest
(including innew_rule.tmpl
) back to usingdefexpect
. Sean fixed the 3-arg issue when I raised it in clojure-expectations/clojure-test#35, and it's nice to only import a single namespace instead of multiple. - Add table of namespaces to aliases in
naming/conventional-aliases
docs. naming/record-name
now usescamel-snake-kebab
to check and convert the given record name to PascalCase.- Add
:method-value
style tostyle/new-object
to suggestFoo/new
instead ofFoo.
. - Disable
lint/dot-class-method
andlint/dot-obj-method
whenlint/prefer-method-values
is enabled. - Track rules on ctx instead of passing as a separate argument in
runner
functions. - Move rules from
(:config ctx)
to(:rules ctx)
as map of rule-name to rule map. Add(:rules-by-type ctx)
, a map of simple-type to vector of rule names. Changecheck-all-rules-of-type
to reduce over rule names and pull the rule map fromctx
.
- Remove incorrect guide-ref in
lint/duplicate-field-name
. - Get auto-gen-config working again. (See #16)
- Updated all rules examples to use "avoid" and "prefer" instead of "bad" and "good". This aligns closer with Splint's perspective on the issues found.
- Updated configuration docs to be more explicit about enabling and disabling rules and the use of
global
. (See #11 and #12)
- False positive in
lint/assoc-fn
whenf
is a macro. Coveredor
explicitly, no good generalized solution at the moment. (See #15.) --print-config
properly includes the genre of printed rules.
style/is-eq-order
: Prefer(is (= 200 status))
over(is (= status 200))
when writing assertions.style/prefer-for-with-literals
: Prefer(for [item coll] {:a 1 :b item})
over(map #(hash-map :a 1 :b %) coll)
. (See #10.)
-r
/--require
cli flag that can be used multiple times andrequire
top-level config option that takes a vector of strings. These are loaded withload-file
at run-time to allow for custom rules to be written and used. (See #8.) This is inherently unsafe, so don't run code you don't know.
- Slight change to the patterns, now a final-position
?*
or?+
will immediately return the rest of the current input instead of accumulating it one-by-one. - Reformatted every file to use Tonsky's Better Clojure formatting.
lint/warn-on-reflection
now checks that the file contains a properns
form before issuing a diagnostic.- Updated README speed comparison chart.
-
General performance increases in rules:
lint/body-unquote-splicing
lint/if-else-nil
lint/underscore-in-namespace
lint/warn-on-reflection
metrics/parameter-count
naming/conversion-function
naming/predicate
naming/record-name
naming/single-segment-namespace
style/def-fn
style/eq-zero
style/prefer-clj-string
style/prefer-condp
style/reduce-str
style/single-key-in
style/tostring
style/useless-do
-
Remove documentation about
?_
short form, as it's covered by the existing?
and_
binding rules. -
Expand
?foo
short-forms in patterns to their(? foo)
special form. Simplifies matching functions, makes the pattern DSL more consistent. Now?|foo
will throw immediately instead of part-way through macroexpansion. -
Updated pattern docs with a small example at the top.
-
Simplified
?|
matcher logic to use a set, as that's faster than creating multipleread-form
patterns in a let block and checking each one.
- Correctly suggest
Obj/staticMethod
when given(. Obj (staticMethod))
inlint/dot-class-usage
. - Only suggest
naming/conversion-functions
when there's no-
in the part before-to-
. (Will warn onf-to-g
, will not warn onexpect-f-to-c
.) - Correctly render args in
lint/assoc-fn
.
lint/prefer-method-values
: Prefer(^[] String/toUpperCase "noah")
to(.toUpperCase "noah")
.lint/require-explicit-param-tags
: Prefer(^[File] File/mkdir (io/file \"a\"))
to(File/mkdir (io/file \"a\"))
. Prefer(^[String String] File/createTempFile \"abc\" \"b\")
to(^[_ _] File/createTempFile \"abc\" \"b\")
. Has:missing
,:wildcard
, and:both
styles, which check for lack of any:param-tags
, usage of_
in a:param-tags
, and both. Defaults to:wildcard
.
- Add support for
lint/prefer-method-values
inperformance/dot-equals
. - Switch
new_rule.tmpl
to usedeftest
.defexpect
is a thin wrapper and has the annoying "if given two non-expect entries, wrap in expect", which doesn't work when we use custom expect macros.
re-find:
andstring:
syntaxes for path:excludes
.re-find
usesclojure.core/re-find
, so the regex doesn't have to match the entire file path, just any portion.string
usesclojure.string/includes?
, so a fixed string anywhere in the file path.
- Updated edamame to v1.4.25 in support of the new Clojure 1.12
^[]
/:param-tags
feature.
lint/underscore-in-namespace
: Prefer(ns foo-bar)
to(ns foo_bar)
.performance/dot-equals
: Prefer(.equals "foo" bar)
to(= "foo" bar)
. Only cares about string literals right now.performance/single-literal-merge
: Prefer(assoc m :a 1 :b 2)
to(merge m {:a 1 :b 2})
. Has:single
and:multiple
styles, either a singleassoc
call or threaded multiple calls.performance/into-transducer
: Prefer(into [] (map f) coll)
to(into [] (map f coll))
.style/trivial-for
: Prefer(map f items)
over(for [item items] (f item))
.style/reduce-str
: Prefer(clojure.string/join coll)
over(reduce str coll)
.
global
top-level.splint.edn
config that applies to all rules.- Support
:excludes
in bothglobal
and rules-specific configs. Accepts a vector of java.nio.file.FileSystem/getPathMatcher globs or regexes. When inglobal
, matching files are removed from being processed at all. When in a specific rule, the rule is disabled before matching files are checked.
- Added
min
,max
, anddistinct?
tolint/redundant-call
. - Change
style/set-literal-as-fn
default tofalse
. It's not idiomatic and I don't know that it's any faster either.
- Project file now accepts all reader macros.
--auto-gen-config
, adds test.
performance/assoc-many
should only trigger when there are more than 1 pair.
The big feature here is adding support to run splint
without specifying paths. Now Splint will read the deps.edn
or project.clj
file in the current directory and check the paths in the base definition as well as :dev
and :test
aliases/profiles if no path argument is given. Splint still doesn't support specifying paths in .splint.edn
, nor does it allow for using paths from a project file as well as additional paths when called, but those are planned.
The second big change is moving from the old DSL to the new pangloss/pattern
inspired DSL. More flexible, more usable, overall better.
The third is adding performance
rules. These are off by default and are designed for those who want to pinch their cycles. Some affect common code (get-in
) and some are much more rare (satisfies
), but they're all designed to help you be mindful of slower paths.
- Moved
spat.parser
tosplint.parser
. - Moved
spat.pattern
tosplint.pattern
. RIPspat
, you treated me well for 9 months, but keepingspat
andsplint
separate is no longer helpful. - Switched to the new pattern system, updated all rules.
performance/assoc-many
: Prefer(-> m (assoc :k1 1) (assoc :k2 2))
over(assoc m :k1 1 :k2 2)
.performance/avoid-satisfies
: Do not useclojure.core/satisfies?
, full stop.performance/get-in-literals
: Prefer(-> m :k1 :k2 :k3)
over(get-in m [:k1 :k2 :k3])
.performance/get-keyword
: Prefer(:k m)
over(get m :k)
.style/redundant-regex-constructor
: Prefer#"abc"
over(re-pattern #"abc")
.
- Implemented faster/more efficient versions of Clojure standard library functions:
->list
: concrete list building instead of apply . Useful anywhere a lazy-seq might be returned otherwise. seq/vec input: 40/43 us -> 28/15 usmapv*
:mapv
but short-circuits empty input and usesobject-array
. Still unsure of this one. 36 us -> 36 usrun!*
:run!
but short-circuits empty input and uses.iterator
to perform the side-effects. Does not supportreduced
. 7 us -> 950 nspmap*
: Avoids lazy-seq overhead and relies on Java's built-in Executors. 3.34 s -> 202 mswalk*
andpostwalk*
: Primarily useful inreplace
, but may prove useful otherwise. Only supportssimple-type
defined types. 72 us -> 25 us
splint.config/read-project-file
returns a map of:clojure-version
and:paths
, taken from the project file (deps.edn
orproject.clj
) in the current directory. If no file is found,:paths
isnil
and:clojure-version
is pulled from*clojure-version*
.:min-clojure-version
indefrule
, allowing for rules to specify the minimum version of clojure they require. Rules that are below the supported version are disabled at preparation time and can't be enabled during a run. Acceptable shape is a map of at least one of:major
,:minor
, and:incremental
.- Include this in rule documentation.
test-helpers/with-temp-file
andtest-helpers/print-to-file!
to test file contents.
- Move
spat.parser/parse-string
andspat.parser/parse-string-all
into the test-helper namespace, and replace withparse-file
which accepts thefile-obj
map. - Parse data reader/tagged literals as maps instead of lists, and put the extension (dialect) into the symbol's metadata.
- Defer building cli summary until needed.
- Use new
splint.config/slurp-edn
to read config files, parsed with edamame. - Changed
:spat/lit
metadata to:splint/lit
.:spat/lit
still works for the time being, but no promises. splint.printer/print-results
now accepts only theresults
object, which should additionally have:checked-files
and:total-time
.- Output formats
simple
,full,
andclj-kondo
now print the number of files checked as well:"Linting took 1ms, checked 3 files, 3 style warnings"
- Moved
splint.replace/revert-splint-reader-macros
intosplint.printer
where it belongs. - Rely on undefined behavior in
symbol
to correctly print unprintable special characters by converting sexprs to strings and then converting those to symbols. - Move
simple-type
anddrop-quote
tosplint.utils
.
style/prefer-clj-string
: Preferclojure.string
functions over raw interop. Defaults totrue
.
--[no]summary
cli flag to print or not print the summary line.
:filename
inDiagnostic
is now ajava.io.File
object, not a string. This is propogated through everything. I suspect no one is using these so I think I could change theDiagnostic
as well, but maybe I'll wait a min.make-edamame-opts
now accepts bothfeatures
andns-state
, andparse-string
andparse-string-all
take infeatures
instead ofns-state
.- The runner tracks the filetype of each file and runs over
cljc
files twice, bothclj
andcljs
, with their respective sides of the reader conditionals applied. - Diagnostics are deduped before printing.
lint/warn-on-reflection
only runs inclj
files.- Remove
farolero
. Didn't provide any benefits over judicioustry
/catch
use. :( - Extend the
matcher-combinators.core/Matcher
protocol tojava.io.File
, makingmatch?
work nicely with both strings and file objects. - Performance improvements by converting
rules-by-type
from a map of simple-type -> map of rule name -> rule to simple-type -> vec of rule.
- Correctly print special characters/clojure.core vars (
@
, notsplint/deref
, etc).
lint/warn-on-reflection
: Require that(set! *warn-on-reflection* true)
is called after thens
declaration at the start of every file. Defaults tofalse
.
- Deprecate
--config
. Add--print-config
. No timeline for removal of--config
(maybe never?).
edn
/edn-pretty
output: Print diagnostics as edn usingclojure.core/prn
andclojure.pprint/pprint
.- Continue to process files after running into errors during rules checking.
- Dependencies are updated to latest.
json
andjson-pretty
keys are now sorted.- Small performance improvements to patterns.
metrics/parameter-count
: Function parameter vectors shouldn't have more than 4 positional parameters. Has:positional
and:include-rest
styles (only positional or include& args
rest params too?), and:count
configurable value to set maximum number of parameters allowed.
- Add Metrics rules to documentation.
- Add
-s
/--silent
command line flag to print literally nothing when running Splint. json
output: Print diagnostics as json usingclojure.data.json
.json-pretty
output: Same asjson
but prettified withpprint
.- Track processed files in
:checked-files
. - Add initial
corpus
files to handle large-scale tests.
- Move Splint-specific dev code to proper namespaces in
dev/
. - Extract
splint.runner/run-impl
to decomplect processing cli options and returning a status code from performing the actual config loading and rule building and running. - Rewrite test helper
check-all
to properly call the existing architecture instead of mock it, to accurately test therun-impl
flow. - Use farolero to handle
splint.runner
errors. Shows no signs of slowing down the app, so will investigate other areas for usage as well.
- Only attach parsed
defn
metadata when fn name exactly matchesdefn
ordefn-
and second form is a symbol. --no-parallel
was producing a lazy seq, now consumes to actually check all files. Oops lol.- Map over top-level forms with
nil
parent form instead of treating the whole file as a top-level vector of forms. Fixesnaming/lisp-case
. - Add pre- and post-
attr-maps
todefn
metadata when parsingdefn
forms. - Added license headers where necessary.
- Re-fix deploy script.
- Multiple self tests for consistency.
- New test runner based on Cognitect test-runner to print better summary and skip printing namespaces.
- Cleaned up deploy recipe.
- Wrote short descriptions for all empty config.edn rule descriptions.
- Removed tools.cli defaults for
--parallel
and--output
, now those are added later (see #5).
- Correctly merge cli and local options (#5).
- Edge cases for
lint/if-not-do
,style/when-not-do
.
metrics/fn-length
: Function bodies shouldn't be longer than 10 lines. Has:body
and:defn
styles, and:length
configurable value to set maximum length.
- Add
test-helpers/expect-match
to assert on submatches, transition all existingcheck-X
functions to use it instead. - Track end position of diagnostics.
- Attach location metadata to function "arities" when a defn arg+body isn't wrapped in a list.
- Parse
defn
forms in postprocessing and attach as metadata instead of parsing in individual rules.
- Fix
style/multiple-arity-order
with:arglists
metadata. - Fix binding pattern when binding is falsey.
- Skip
#(.someMethod %)
inlint/fn-wrapper
. - Skip
and
andor
instyle/prefer-condp
.
- Fix
io/resource
issue. - Remove
.class
files fromjar
.
-v
and--version
cli flags to print the current version.--config TYPE
cli flag to print thediff
,local
, orfull
configuration.
- Fix "Don't know how to create ISeq from: clojure.lang.Symbol" error in
splint.rules.helpers.parse-defn
when trying to parse ill-formed function definitions. - "Fix" error messages. Honestly, I'm not great at these so I'm not entirely sure how to best display this stuff.
- Skip
#(do [%1 %2])
instyle/useless-do
, add docstring note about it.
- Babashka compatibility
- Set up Github CI
- Links in docs for style guide.
naming/single-segment-namespace
: Prefer(ns foo.bar)
to(ns foo)
.lint/prefer-require-over-use
: Prefer(:require [clojure.string ...])
to(:use clojure.string)
. Accepts different styles in the replacement form::as
,:refer [...]
and:refer :all
.naming/conventional-aliases
: Prefer idiomatic aliases for core libraries ([clojure.string :as str]
to[clojure.string :as string]
).naming/lisp-case
: Prefer kebab-case over other cases for top-level definitions. Relies on camel-snake-kebab.style/multiple-arity-order
: Function definitions should have multiple arities sorted fewest arguments to most:(defn foo ([a] 1) ([a b] 2) ([a b & more] 3))
- Parsing bug in
lint/fn-wrapper
introduced in v1.2.3.
*warn-on-reflection*
to all rules and rule template.- Use
:spat/import-ns
metadata as way to track when a symbol has been imported.
- Various performance enhancements:
- Use protocols in
noahtheduke.spat.pattern/simple-type
for performance. - Use
volatile
instead ofatom
for bindings innoahtheduke.spat.pattern
. - Switch
keep
toreduce
to avoid seq and laziness manipulation. - Use
some->
where appropriate for short-circuiting.
- Use protocols in
- Fix #2, false positive on interop fn-wrappers.
- Lots of small namespace parsing fixes.
- Differentiate between
&&.
rest args and parsed lists in:on-match
handlers by attaching:noahtheduke.spat.pattern/rest
metadata to bound rest args. - Bump
edamame
to v1.3.21 to handle#:: {:a 1}
auto-resolved namespaced maps with spaces between the colons and the map literal. - Use correct url in install docs. (Thanks @dpassen)
lint/thread-macro-one-arg
supports:inline
and:avoid-collections
styles.:updated
field in configuration edn, show in rule docs.:guide-ref
forstyle/prefer-clj-math
.- Interpose
<hr>
between each rule's docs.
- Clarify docstring for
lint/dorun-map
.
- Left align contents of tables in rule docs.
- Correctly render bare links in rule docs.
- Correctly export clojars info in
deploy
justfile recipe.
markdown
output: Same text asfull
but with a fancy horizontal bar, header, and code blocks.:chosen-style
allows for rules to have configuration and different "styles". The first supported islint/not-empty?
showing eitherseq
ornot-empty
.
ctx
is no longer an atom, but a plain map. The:diagnostics
entry is now the atom.splint.runner/check-form
returns the entire updatedctx
object instead of just the diagnostics. (I'm not entirely sure that's reasonable, but it's easily changed.)- Move a lot of rules from
lint
tostyle
genre:apply-str
apply-str-interpose
apply-str-reverse
assoc-assoc
conj-vector
eq-false
eq-nil
eq-true
eq-zero
filter-complement
filter-vec-filterv
first-first
first-next
let-do
mapcat-apply-apply
mapcat-concat-map
minus-one
minus-zero
multiply-by-one
multiply-by-zero
neg-checks
nested-addition
nested-multiply
next-first
next-next
not-eq
not-nil
not-some-pred
plus-one
plus-zero
pos-checks
tostring
update-in-assoc
useless-do
when-do
when-not-call
when-not-do
when-not-empty
when-not-not
- Add
ctx
as first argument to:on-match
functions to pass in config to rules. Update functions insplint.runner
as necessary.
- Update Rule Documentation.
- Include new documentation in cljdoc.edn
- Write documentation for rules and patterns.
- Write docstrings for a bunch of
noahtheduke.spat.pattern
functions. - Include outside links in config in rules docs.
- Check
:spat/lit
metadata to treat special symbols in pattern DSL as their literal values.
- Attempt to resolve predicates in calling namespace first, then in
clojure.core
, then innoahtheduke.splint.rules.helpers
. - Rename read-dispatch type from
:var
to:binding
.
- Run linting over syntax-quoted forms again.
style/def-fn
: Prefer(let [z f] (defn x [y] (z y)))
over(def x (let [z f] (fn [y] (z y))))
lint/try-splicing
: Prefer(try (do ~@body) (finally ...))
over(try ~@body (finally ...))
.lint/body-unquote-splicing
: Prefer(binding [max mymax] (let [res# (do ~@body)] res#))
over(binding [max mymax] ~@body)
.
- Use markdownlint to pretty up the markdown in the repo. Will do my best to keep up with it.
- Add
--parallel
and--no-parallel
for running splint in parallel or not. Defaults totrue
. - No longer run linting over quoted or syntax-quoted forms.
- Rely on edamame's newly built-in
:uneval
config option for:splint/disable
. - Move version from
build.clj
toresources/SPLINT_VERSION
.
naming/record-name
: Add:message
.style/prefer-condp
: Only runs if given more than 1 predicate branch.style/set-literal-as-fn
: Allow quoted symbols in sets.
Actually wrote out something of a changelog.
lint/duplicate-field-name
:(defrecord Foo [a b a])
naming/conversion-functions
: Should usex->y
instead ofx-to-y
.style/set-literal-as-fn
: Should use(case elem (a b) true false)
instead of(#{'a 'b} elem)
- The
:new-rule
task now creates a test stub in the correct test directory. #_:splint/disable
is treated as metadata on the following form and disables all rules.#_{:splint/disable []}
can take genres of rules ([lint]
) and/or specific rules ([lint/loop-do]
) and disables those rules. See below (Thoughts and Followup) for discussion and Configuration for more details.
defrule
now requires the provided rule-name to be fully qualified, and doesn't perform any*ns*
magic to derive the genre.- Add support for specifying
:init-type
indefrule
to handle symbol matching. - All of the
:dispatch
reader macros provided by Edamame now wrap their sexps in the appropriate(splint/X sexp)
form, to distinguish them from the symbol forms. Aka#(inc %)
is now rendered as(splint/fn [%1] (inc %1))
, vs the original(fn* ...)
, or#'x
is now(splint/var x)
vs(var x)
. This allows for writing rules targeting the literal form instead of the symbol form, and requires that rule patterns rely on functions innoahtheduke.splint.rules.helpers
to cover these alternates. - Split all rules tests into their own matching namespaces.
- Add
noahtheduke.splint.rules.helpers
as an autoresolving namespace so rules can use predicates defined within it without importing or qualifying. - Renamed errors from
violation
todiagnostic
. - Merge rules configs into rules maps at load-time.
lint/duplicate-field-name
wasn't checking that?fields
was a vector before callingcount
on it.
I want another parser because I want access to comments. Without comments, I can't parse magic comments, meaning I can't enable or disable rules inline, only globally. That's annoying and not ideal. However, every solution I've dreamed up has some deep issue.
-
Edamame is our current parser and it's extremely fast (40ms to parse
clojure/core.clj
) but it drops comments. I've forked it to try to add them, but that would mean handling them in every other part of the parser, such as syntax-quote and maps and sets, making dealing with those objects really hard. 😭 -
Rewrite-clj only exposes comments in the zip api, meaning I have to operate on the zipper objects with zipper functions (horrible and slow). It's nice to rely on Clojure built-ins instead of
(loop [zloc zloc] (z/next* ...))
nonsense. -
clj-kondo is faster than rewrite-clj and has a nicer api, but the resulting tree isn't as easy to work with as Edamame and it's slower. Originally built Spat in it and found it to be annoying to use.
-
parcera looked promising, but the pre-processing in
parcera/ast
is slow and operating on the Java directly is deeply cumbersome. The included grammar also makes some odd choices and I don't know ANTLR4 well enough to know how to fix them (such as including the:
in keyword strings). Additionally, if I were to switch, I would have to update/touch every existing rule.
After tinkering with Edamame for a bit, I've found a solution that requires no changes to edamame to support: #_:splint/disable
. This style of directive applies metadata to the following form: #_{:splint/disable [lint/plus-one]} (+ 1 x)
. Edamame normally discard #_
/discarded forms, so on Borkdude's recommendation, I use str/replace
to convert it at parse-time to metadata. This uses an existing convention and handles the issue of disabling multiple items or disabling for only a certain portion of the file.
Update readme with some better writing.
dev/sorted-rules-require
for internal use only
- Annotate all rules with
:no-doc
. - Rename
lint/cond-else
tostyle/cond-else
. - Cleaned up readme.
Renamed to Splint! Things are really coming together now.
lint/assoc-in-one-arg
lint/update-in-one-arg
naming/predicate
naming/record-name
style/let-if
style/let-when
style/new-object
style/prefer-boolean
style/prefer-condp
style/redundant-let
style/single-key-in
- Basic CLI.
- Basic config file and config management.
- cljdoc support.
-M:gen-docs
for rule documentation generation and formatting.-M:new-rule
task to generate a new rule file from a template.-M:deploy
task to push to clojars.
- Split main file into multiple files: core functionality to namespaces, each rule to a separate file.
- Rename
lint/with-meta-vary-meta
tostyle/prefer-vary-meta
. - Rename
lint/thread-macro-no-arg
tolint/redundant-call
.
Initial release of spat
, announcement on Clojurian Slack and bbin installation set up. Contains working pattern matching system, a bunch of rules, and a simple runner.