New nested-associative-operator lint
I want to also get like (if a (if b c)) at some point, but this lint only covers the ones where flattening fixes it always.
This commit is contained in:
parent
ea826576e3
commit
0817af9488
@ -10,6 +10,7 @@
|
|||||||
* Disabled by default because it requires following fennel's optional argument naming conventions
|
* Disabled by default because it requires following fennel's optional argument naming conventions
|
||||||
* New lint `invalid-flsproject-settings` checks your `flsproject.fnl` file as you edit it
|
* New lint `invalid-flsproject-settings` checks your `flsproject.fnl` file as you edit it
|
||||||
* Renamed lint `unnecessary-do-values` to `unnecessary-unary` and made it apply to many more forms
|
* Renamed lint `unnecessary-do-values` to `unnecessary-unary` and made it apply to many more forms
|
||||||
|
* New lint `nested-associative-operator` checks for nested operations that could be flattened (eg. `(+ 1 2 (+ 3 4) 5)`)
|
||||||
|
|
||||||
### Changes
|
### Changes
|
||||||
* Updated to dkjson 2.8
|
* Updated to dkjson 2.8
|
||||||
|
|||||||
@ -782,6 +782,54 @@ You can read more about how to add lints in docs/linting.md"
|
|||||||
:severity message.severity.WARN}))))
|
:severity message.severity.WARN}))))
|
||||||
nil)})
|
nil)})
|
||||||
|
|
||||||
|
(local associative-ops {:and true :or true :+ true :* true :band true :bor true :.. true})
|
||||||
|
|
||||||
|
(add-lint :nested-associative-operator
|
||||||
|
{:what-it-does
|
||||||
|
"Identifies forms that could be written in a flattr way, like `(and foo (and bar baz))`."
|
||||||
|
:why-care?
|
||||||
|
"Collapsing nested forms reduces unnecessary nesting and makes code more readable and idiomatic."
|
||||||
|
:example
|
||||||
|
"```fnl
|
||||||
|
(and foo bar (and baz buzz) xyz)
|
||||||
|
(+ a (+ b c) d)
|
||||||
|
(or x (or y z))
|
||||||
|
```
|
||||||
|
|
||||||
|
Instead, use:
|
||||||
|
```fnl
|
||||||
|
;; Flattened forms:
|
||||||
|
(and foo bar baz buzz xyz)
|
||||||
|
(+ a b c d)
|
||||||
|
(or x y z)
|
||||||
|
```"
|
||||||
|
:since "0.2.2-dev"
|
||||||
|
:type :special-call
|
||||||
|
:impl (fn [server file ast]
|
||||||
|
(let [op (. ast 1)]
|
||||||
|
(when (and (sym? op)
|
||||||
|
(. associative-ops (tostring op)))
|
||||||
|
(faccumulate [diagnostic nil
|
||||||
|
i 2 (length ast)
|
||||||
|
&until diagnostic]
|
||||||
|
(let [arg (. ast i)
|
||||||
|
op-str (tostring op)]
|
||||||
|
(when (and (list? arg) (= op (. arg 1)))
|
||||||
|
{:range (message.ast->range server file arg)
|
||||||
|
:message (.. "nested " op-str " can be collapsed")
|
||||||
|
:severity message.severity.WARN
|
||||||
|
:fix #(let [new-form (list (. ast 1))]
|
||||||
|
(for [j 2 (length ast)]
|
||||||
|
(let [item (. ast j)]
|
||||||
|
(if (and (list? item)
|
||||||
|
(sym? (. item 1) op-str))
|
||||||
|
(fcollect [k 2 (length item) &into new-form]
|
||||||
|
(. item k))
|
||||||
|
(table.insert new-form item))))
|
||||||
|
{:title (.. "Collapse all nested " op-str)
|
||||||
|
:changes [{:range (message.ast->range server file ast)
|
||||||
|
:newText (view new-form)}]})}))))))})
|
||||||
|
|
||||||
(local lint-mt {:__tojson (fn [{: self} state] (dkjson.encode self state))
|
(local lint-mt {:__tojson (fn [{: self} state] (dkjson.encode self state))
|
||||||
:__index #(. $1 :self $2)})
|
:__index #(. $1 :self $2)})
|
||||||
|
|
||||||
|
|||||||
@ -347,6 +347,29 @@
|
|||||||
|
|
||||||
;; unused variable, when a function binding is only used in its body, and the function value is discarded
|
;; unused variable, when a function binding is only used in its body, and the function value is discarded
|
||||||
|
|
||||||
|
(fn test-nested-associative-operator []
|
||||||
|
(check "(and foo (and bar baz) xyz)"
|
||||||
|
[{:message "nested and can be collapsed"
|
||||||
|
:code :nested-associative-operator}])
|
||||||
|
|
||||||
|
(check "(+ a (+ b c) d)"
|
||||||
|
[{:message "nested + can be collapsed"
|
||||||
|
:code :nested-associative-operator}])
|
||||||
|
|
||||||
|
(check "(or x (or y z))"
|
||||||
|
[{:message "nested or can be collapsed"
|
||||||
|
:code :nested-associative-operator}])
|
||||||
|
|
||||||
|
(check "(and foo (and bar baz) (and this that))"
|
||||||
|
[{:message "nested and can be collapsed"
|
||||||
|
:code :nested-associative-operator}])
|
||||||
|
|
||||||
|
(assert-ok "(and true false true)") ; no nesting
|
||||||
|
(assert-ok "(+ 1 2 3)") ; no nesting
|
||||||
|
(assert-ok "(* (+ 1 2) 3)") ; different operations
|
||||||
|
(assert-ok "(and true (or false true))") ; different operators
|
||||||
|
nil)
|
||||||
|
|
||||||
{: test-unused
|
{: test-unused
|
||||||
: test-ampersand
|
: test-ampersand
|
||||||
: test-unknown-module-field
|
: test-unknown-module-field
|
||||||
@ -362,4 +385,5 @@
|
|||||||
: test-empty-let
|
: test-empty-let
|
||||||
: test-decreasing-comparison
|
: test-decreasing-comparison
|
||||||
: test-arg-count
|
: test-arg-count
|
||||||
: test-duplicate-keys}
|
: test-duplicate-keys
|
||||||
|
: test-nested-associative-operator}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user