From 77eb42f0ccbe7117a405db81f2aa9a7d11c741bd Mon Sep 17 00:00:00 2001 From: Jeroen Engels Date: Mon, 18 Sep 2023 12:02:34 +0200 Subject: [PATCH] 2.1.1 --- CHANGELOG.md | 5 ++++- README.md | 2 +- docs.json | 2 +- elm.json | 4 ++-- example/elm.json | 4 ++-- 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c70ccf7ae..d47dfd39b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## [Unreleased] +## [2.1.1] - 2023-09-18 + - A very large number of error messages were reworded to be more consistent, precise and descriptive. - Checks that applied on `[ a ]` now also report for `List.singleton a` (ex: `List.concatMap f (List.singleton 1)` gets simplified to `f 1`) @@ -395,7 +397,8 @@ The rule now simplifies: Help would be appreciated to fill the blanks! -[Unreleased]: https://github.com/jfmengels/elm-review-simplify/compare/v2.1.0...HEAD +[Unreleased]: https://github.com/jfmengels/elm-review-simplify/compare/v2.1.1...HEAD +[2.1.1]: https://github.com/jfmengels/elm-review-simplify/releases/tag/2.1.1 [2.1.0]: https://github.com/jfmengels/elm-review-simplify/releases/tag/2.1.0 [2.0.33]: https://github.com/jfmengels/elm-review-simplify/releases/tag/2.0.33 [2.0.32]: https://github.com/jfmengels/elm-review-simplify/releases/tag/2.0.32 diff --git a/README.md b/README.md index 34aafadf4..73b8ee536 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Provides [`elm-review`](https://package.elm-lang.org/packages/jfmengels/elm-revi ## Provided rules -- [šŸ”§ `Simplify`](https://package.elm-lang.org/packages/jfmengels/elm-review-simplify/2.1.0/Simplify/ "Provides automatic fixes") - Reports when an expression can be simplified. +- [šŸ”§ `Simplify`](https://package.elm-lang.org/packages/jfmengels/elm-review-simplify/2.1.1/Simplify/ "Provides automatic fixes") - Reports when an expression can be simplified. ## Configuration diff --git a/docs.json b/docs.json index 29581521e..8f91bc80b 100644 --- a/docs.json +++ b/docs.json @@ -1 +1 @@ -[{"name":"Simplify","comment":" Reports when an expression can be simplified.\n\nšŸ”§ Running with `--fix` will automatically remove all the reported errors.\n\n config =\n [ Simplify.rule Simplify.defaults\n ]\n\n@docs rule\n@docs Configuration, defaults, expectNaN, ignoreCaseOfForTypes\n\n\n## Try it out\n\nYou can try this rule out by running the following command:\n\n```bash\nelm-review --template jfmengels/elm-review-simplify/example --rules Simplify\n```\n\n\n## Simplifications\n\nBelow is the list of all kinds of simplifications this rule applies.\n\n\n### Booleans\n\n x || True\n --> True\n\n x || False\n --> x\n\n x && True\n --> x\n\n x && False\n --> False\n\n not True\n --> False\n\n not (not x)\n --> x\n\n -- for `<`, `>`, `<=`, `>=`, `==` and `/=`\n not (a < b)\n --> a >= b\n\n\n### Comparisons\n\n x == True\n --> x\n\n x /= False\n --> x\n\n not x == not y\n --> x == y\n\n anything == anything\n --> True\n\n anything /= anything\n --> False\n\n { r | a = 1 } == { r | a = 2 }\n --> False\n\n\n### If expressions\n\n if True then x else y\n --> x\n\n if False then x else y\n --> y\n\n if condition then x else x\n --> x\n\n if condition then True else False\n --> condition\n\n if condition then False else True\n --> not condition\n\n a =\n if condition then\n if not condition then\n 1\n else\n 2\n else\n 3\n --> if condition then 2 else 3\n\n\n### Case expressions\n\n case condition of\n True -> x\n False -> y\n --> if condition then x else y\n\n case condition of\n False -> y\n True -> x\n --> if not condition then x else y\n\n -- only when no variables are introduced in the pattern\n -- and no custom types defined in the project are referenced\n case value of\n Just _ -> x\n Nothing -> x\n --> x\n\nDestructuring using case expressions\n\n case value of\n ( x, y ) ->\n x + y\n\n -->\n let\n ( x, y ) =\n value\n in\n x + y\n\n\n### Let expressions\n\n let\n a =\n 1\n in\n let\n b =\n 1\n in\n a + b\n\n -->\n let\n a =\n 1\n\n b =\n 1\n in\n a + b\n\n\n### Record updates\n\n { a | b = a.b }\n --> a\n\n { a | b = a.b, c = 1 }\n --> { a | c = 1 }\n\n\n### Field access\n\n { a = b }.a\n --> b\n\n { a | b = c }.b\n --> c\n\n { a | b = c }.d\n --> a.d\n\n (let a = b in c).d\n --> let a = b in c.d\n\n\n### Basics functions\n\n identity x\n --> x\n\n f >> identity\n --> f\n\n always x y\n --> x\n\n f >> always x\n --> always x\n\n\n### Lambdas\n\n (\\_ -> x) data\n --> x\n\n (\\() y -> x) ()\n --> (\\y -> x)\n\n (\\_ y -> x) data\n --> (\\y -> x)\n\n (\\x y -> x + y) n m\n -- Reported because simplifiable but not autofixed\n\n\n### Operators\n\n (++) a b\n --> a ++ b\n\n a |> f >> g\n --> a |> f |> g\n\n\n### Numbers\n\n n + 0\n --> n\n\n n - 0\n --> n\n\n 0 - n\n --> -n\n\n n * 1\n --> n\n\n n / 1\n --> n\n\n 0 / n\n --> 0\n\n -(-n)\n --> n\n\n negate (negate n)\n --> n\n\n n - n\n --> 0\n\n\n### Strings\n\n \"a\" ++ \"\"\n --> \"a\"\n\n String.fromList []\n --> \"\"\n\n String.fromList [ a ]\n --> String.fromChar a\n\n String.isEmpty \"\"\n --> True\n\n String.isEmpty \"a\"\n --> False\n\n String.concat []\n --> \"\"\n\n String.join str []\n --> \"\"\n\n String.join \"\" list\n --> String.concat list\n\n String.length \"abc\"\n --> 3\n\n String.repeat n \"\"\n --> \"\"\n\n String.repeat 0 str\n --> \"\"\n\n String.repeat 1 str\n --> str\n\n String.replace x y \"\"\n --> \"\"\n\n String.replace x x z\n --> z\n\n String.replace \"x\" \"y\" \"z\"\n --> \"z\" -- only when resulting string is unchanged\n\n String.words \"\"\n --> []\n\n String.lines \"\"\n --> []\n\n String.reverse \"\"\n --> \"\"\n\n String.reverse (String.reverse str)\n --> str\n\n String.slice n n str\n --> \"\"\n\n String.slice n 0 str\n --> \"\"\n\n String.slice a z \"\"\n --> \"\"\n\n String.left 0 str\n --> \"\"\n\n String.left -1 str\n --> \"\"\n\n String.left n \"\"\n --> \"\"\n\n String.right 0 str\n --> \"\"\n\n String.right -1 str\n --> \"\"\n\n String.right n \"\"\n --> \"\"\n\n String.slice 2 1 str\n --> \"\"\n\n String.slice -1 -2 str\n --> \"\"\n\n\n### Maybes\n\n Maybe.map identity x\n --> x\n\n Maybe.map f Nothing\n --> Nothing\n\n Maybe.map f (Just x)\n --> Just (f x)\n\n Maybe.andThen f Nothing\n --> Nothing\n\n Maybe.andThen (always Nothing) x\n --> Nothing\n\n Maybe.andThen (\\a -> Just b) x\n --> Maybe.map (\\a -> b) x\n\n Maybe.andThen (\\a -> if condition a then Just b else Just c) x\n --> Maybe.map (\\a -> if condition a then b else c) x\n\n Maybe.andThen f (Just x)\n --> f x\n\n Maybe.withDefault x Nothing\n --> x\n\n Maybe.withDefault x (Just y)\n --> y\n\n\n### Results\n\n Result.map identity x\n --> x\n\n Result.map f (Err x)\n --> Err x\n\n Result.map f (Ok x)\n --> Ok (f x)\n\n Result.mapError identity x\n --> x\n\n Result.mapError f (Ok x)\n --> Ok x\n\n Result.mapError f (Err x)\n --> Err (f x)\n\n Result.andThen f (Err x)\n --> Err x\n\n Result.andThen f (Ok x)\n --> f x\n\n Result.andThen (\\a -> Ok b) x\n --> Result.map (\\a -> b) x\n\n Result.withDefault x (Err y)\n --> x\n\n Result.withDefault x (Ok y)\n --> y\n\n Result.toMaybe (Ok x)\n --> Just x\n\n Result.toMaybe (Err e)\n --> Nothing\n\n\n### Lists\n\n a :: []\n --> [ a ]\n\n a :: [ b ]\n --> [ a, b ]\n\n [ a ] ++ list\n --> a :: list\n\n [] ++ list\n --> list\n\n [ a, b ] ++ [ c ]\n --> [ a, b, c ]\n\n List.append [] ys\n --> ys\n\n List.append [ a, b ] [ c ]\n --> [ a, b, c ]\n\n List.head []\n --> Nothing\n\n List.head (a :: bToZ)\n --> Just a\n\n List.tail []\n --> Nothing\n\n List.tail (a :: bToZ)\n --> Just bToZ\n\n List.member a []\n --> False\n\n List.member a [ a, b, c ]\n --> True\n\n List.member a [ b ]\n --> a == b\n\n List.map f [] -- same for most List functions like List.filter, List.filterMap, ...\n --> []\n\n List.map identity list\n --> list\n\n List.filter (always True) list\n --> list\n\n List.filter (always False) list\n --> []\n\n List.filterMap Just list\n --> list\n\n List.filterMap (\\a -> if condition a then Just b else Just c) list\n --> List.map (\\a -> if condition a then b else c) list\n\n List.filterMap (always Nothing) list\n --> []\n\n List.filterMap identity (List.map f list)\n --> List.filterMap f list\n\n List.filterMap identity [ Just x, Just y ]\n --> [ x, y ]\n\n List.concat [ [ a, b ], [ c ] ]\n --> [ a, b, c ]\n\n List.concat [ a, [ 1 ], [ 2 ] ]\n --> List.concat [ a, [ 1, 2 ] ]\n\n List.concat [ a, [], b ]\n --> List.concat [ a, b ]\n\n List.concatMap identity list\n --> List.concat list\n\n List.concatMap (\\a -> [ b ]) list\n --> List.map (\\a -> b) list\n\n List.concatMap f [ x ]\n --> f x\n\n List.concatMap (always []) list\n --> []\n\n List.concat (List.map f list)\n --> List.concatMap f list\n\n List.indexedMap (\\_ value -> f value) list\n --> List.map (\\value -> f value) list\n\n List.intersperse a []\n --> []\n\n List.isEmpty []\n --> True\n\n List.isEmpty [ a ]\n --> False\n\n List.isEmpty (x :: xs)\n --> False\n\n List.sum []\n --> 0\n\n List.sum [ a ]\n --> a\n\n List.product []\n --> 1\n\n List.product [ a ]\n --> a\n\n List.minimum []\n --> Nothing\n\n List.minimum [ a ]\n --> Just a\n\n List.maximum []\n --> Nothing\n\n List.maximum [ a ]\n --> Just a\n\n -- The following simplifications for List.foldl also work for List.foldr\n List.foldl f x []\n --> x\n\n List.foldl (\\_ soFar -> soFar) x list\n --> x\n\n List.foldl (+) 0 list\n --> List.sum list\n\n List.foldl (+) initial list\n --> initial + List.sum list\n\n List.foldl (*) 1 list\n --> List.product list\n\n List.foldl (*) 0 list\n --> 0\n\n List.foldl (*) initial list\n --> initial * List.product list\n\n List.foldl (&&) True list\n --> List.all identity list\n\n List.foldl (&&) False list\n --> False\n\n List.foldl (||) False list\n --> List.any identity list\n\n List.foldl (||) True list\n --> True\n\n List.all f []\n --> True\n\n List.all (always True) list\n --> True\n\n List.any f []\n --> True\n\n List.any (always False) list\n --> False\n\n List.any ((==) x) list\n --> List.member x list\n\n List.range 6 3\n --> []\n\n List.length [ a, b, c ]\n --> 3\n\n List.repeat 0 x\n --> []\n\n List.partition f []\n --> ( [], [] )\n\n List.partition (always True) list\n --> ( list, [] )\n\n List.partition (always False) list\n --> ( [], list )\n\n List.take 0 list\n --> []\n\n List.drop 0 list\n --> list\n\n List.reverse (List.reverse list)\n --> list\n\n List.sortBy (always a) list\n --> list\n\n List.sortBy identity list\n --> List.sort list\n\n List.sortWith (\\_ _ -> LT) list\n --> List.reverse list\n\n List.sortWith (\\_ _ -> EQ) list\n --> list\n\n List.sortWith (\\_ _ -> GT) list\n --> list\n\n -- The following simplifications for List.sort also work for List.sortBy f and List.sortWith f\n List.sort []\n --> []\n\n List.sort [ a ]\n --> [ a ]\n\n -- same for up to List.map5 when any list is empty\n List.map2 f xs []\n --> []\n\n List.map2 f [] ys\n --> []\n\n List.unzip []\n --> ( [], [] )\n\n\n### Sets\n\n Set.map f Set.empty -- same for Set.filter, Set.remove...\n --> Set.empty\n\n Set.map identity set\n --> set\n\n Set.isEmpty Set.empty\n --> True\n\n Set.member x Set.empty\n --> False\n\n Set.fromList []\n --> Set.empty\n\n Set.fromList [ a ]\n --> Set.singleton a\n\n Set.toList Set.empty\n --> []\n\n Set.length Set.empty\n --> 0\n\n Set.intersect Set.empty set\n --> Set.empty\n\n Set.diff Set.empty set\n --> Set.empty\n\n Set.diff set Set.empty\n --> set\n\n Set.union set Set.empty\n --> set\n\n Set.insert x Set.empty\n --> Set.singleton x\n\n -- same for foldr\n List.foldl f x (Set.toList set)\n --> Set.foldl f x set\n\n Set.partition f Set.empty\n --> ( Set.empty, Set.empty )\n\n Set.partition (always True) set\n --> ( set, Set.empty )\n\n\n### Dict\n\n Dict.isEmpty Dict.empty\n --> True\n\n Dict.fromList []\n --> Dict.empty\n\n Dict.toList Dict.empty\n --> []\n\n Dict.size Dict.empty\n --> 0\n\n Dict.member x Dict.empty\n --> False\n\n Dict.partition f Dict.empty\n --> ( Dict.empty, Dict.empty )\n\n Dict.partition (always True) dict\n --> ( dict, Dict.empty )\n\n Dict.partition (always False) dict\n --> ( Dict.empty, dict )\n\n List.map Tuple.first (Dict.toList dict)\n --> Dict.keys dict\n\n List.map Tuple.second (Dict.toList dict)\n --> Dict.values dict\n\n\n### Cmd / Sub\n\nAll of these also apply for `Sub`.\n\n Cmd.batch []\n --> Cmd.none\n\n Cmd.batch [ a ]\n --> a\n\n Cmd.batch [ a, Cmd.none, b ]\n --> Cmd.batch [ a, b ]\n\n Cmd.map identity cmd\n --> cmd\n\n Cmd.map f Cmd.none\n --> Cmd.none\n\n\n### Html.Attributes\n\n Html.Attributes.classList [ x, y, ( z, False ) ]\n --> Html.Attributes.classList [ x, y ]\n\n Html.Attributes.classList [ ( onlyOneThing, True ) ]\n --> Html.Attributes.class onlyOneThing\n\n\n### Json.Decode\n\n Json.Decode.oneOf [ a ]\n --> a\n\n\n### Parser\n\n Parser.oneOf [ a ]\n --> a\n\n\n### Random\n\n Random.uniform a []\n --> Random.constant a\n\n Random.weighted ( weight, a ) []\n --> Random.constant a\n\n Random.weighted tuple []\n --> Random.constant (Tuple.first tuple)\n\n Random.list 0 generator\n --> Random.constant []\n\n Random.list 1 generator\n --> Random.map List.singleton generator\n\n Random.list n (Random.constant el)\n --> Random.constant (List.repeat n el)\n\n Random.map identity generator\n --> generator\n\n Random.map (always a) generator\n --> Random.constant a\n\n Random.map f (Random.constant x)\n --> Random.constant (f x)\n\n","unions":[{"name":"Configuration","comment":" Configuration for this rule. Create a new one with [`defaults`](#defaults) and use [`ignoreCaseOfForTypes`](#ignoreCaseOfForTypes) to alter it.\n","args":[],"cases":[]}],"aliases":[],"values":[{"name":"defaults","comment":" Default configuration for this rule.\n\nThe rule aims tries to improve the code through simplifications that don't impact the behavior. An exception to this are\nwhen the presence of `NaN` values\n\nUse [`expectNaN`](#expectNaN) if you want to opt out of changes that can impact the behaviour of your code if you expect to work with `NaN` values.\n\nUse [`ignoreCaseOfForTypes`](#ignoreCaseOfForTypes) if you want to prevent simplifying case expressions that work on custom types defined in dependencies.\n\n config =\n [ Simplify.rule Simplify.defaults\n ]\n\n -- or\n config =\n [ Simplify.defaults\n |> Simplify.expectNaN\n |> Simplify.ignoreCaseOfForTypes [ \"Module.Name.Type\" ]\n |> Simplify.rule\n ]\n\n","type":"Simplify.Configuration"},{"name":"expectNaN","comment":" Usually, `elm-review-simplify` will only suggest simplifications that are safe to apply without risk of changing the original behavior.\nHowever, when encountering [`NaN`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NaN)\nvalues, some simplifications can actually impact behavior.\n\nFor instance, the following expression will evaluate to `True`:\n\n x == x\n --> True\n\nHowever, if `x` is `NaN` or a value containing `NaN` then the expression will evaluate to `False`:\n\n -- given x = NaN\n x == x\n --> False\n\n -- given x = { a = ( NaN, 0 ) }\n x == x\n --> False\n\nGiven the potential presence of `NaN`, some simplifications become unsafe to apply:\n\n - `x == x` to `True`\n - `List.member x [ x ]` to `True`\n - `n * 0` to `0`\n\nThis special value is hard to recreate in Elm code both intentionally and unintentionally,\nand it's therefore unlikely to be found in your application,\nwhich is why the rule applies these simplifications by defaults.\n\nIf you somehow expect to create and encounter `NaN` values in your codebase, then you can use this function to disable these simplifications altogether.\n\n config =\n [ Simplify.defaults\n |> Simplify.expectNaN\n |> Simplify.rule\n ]\n\n","type":"Simplify.Configuration -> Simplify.Configuration"},{"name":"ignoreCaseOfForTypes","comment":" Ignore some reports about types from dependencies used in case expressions.\n\nThis rule simplifies the following construct:\n\n module Module.Name exposing (..)\n\n case value of\n Just _ -> x\n Nothing -> x\n --> x\n\n(Since `v2.0.19`) it will not try to simplify the case expression when some of the patterns references custom types constructors\ndefined in the project. It will only do so for custom types that are defined in dependencies (including `elm/core`).\n\nIf you do happen to want to disable this simplification for a type `Module.Name.Type`, you can configure the rule like this:\n\n config =\n [ Simplify.defaults\n |> Simplify.ignoreCaseOfForTypes [ \"Module.Name.Type\" ]\n |> Simplify.rule\n ]\n\nI personally don't recommend to use this function too much, because this could be a sign of premature abstraction, and because\nI think that often [You Aren't Gonna Need this code](https://jfmengels.net/safe-dead-code-removal/#yagni-you-arent-gonna-need-it).\n\nPlease let me know by opening an issue if you do use this function, I am very curious to know;\n\n","type":"List.List String.String -> Simplify.Configuration -> Simplify.Configuration"},{"name":"rule","comment":" Rule to simplify Elm code.\n","type":"Simplify.Configuration -> Review.Rule.Rule"}],"binops":[]}] \ No newline at end of file +[{"name":"Simplify","comment":" Reports when an expression can be simplified.\n\nšŸ”§ Running with `--fix` will automatically remove all the reported errors.\n\n config =\n [ Simplify.rule Simplify.defaults\n ]\n\n@docs rule\n@docs Configuration, defaults, expectNaN, ignoreCaseOfForTypes\n\n\n## Try it out\n\nYou can try this rule out by running the following command:\n\n```bash\nelm-review --template jfmengels/elm-review-simplify/example --rules Simplify\n```\n\n\n## Simplifications\n\nBelow is the list of all kinds of simplifications this rule applies.\n\n\n### Booleans\n\n x || True\n --> True\n\n x || False\n --> x\n\n x && True\n --> x\n\n x && False\n --> False\n\n not True\n --> False\n\n not (not x)\n --> x\n\n -- for `<`, `>`, `<=`, `>=`, `==` and `/=`\n not (a < b)\n --> a >= b\n\n\n### Comparisons\n\n x == True\n --> x\n\n x /= False\n --> x\n\n not x == not y\n --> x == y\n\n anything == anything\n --> True\n\n anything /= anything\n --> False\n\n { r | a = 1 } == { r | a = 2 }\n --> False\n\n\n### If expressions\n\n if True then x else y\n --> x\n\n if False then x else y\n --> y\n\n if condition then x else x\n --> x\n\n if condition then True else False\n --> condition\n\n if condition then False else True\n --> not condition\n\n a =\n if condition then\n if not condition then\n 1\n else\n 2\n else\n 3\n --> if condition then 2 else 3\n\n\n### Case expressions\n\n case condition of\n True -> x\n False -> y\n --> if condition then x else y\n\n case condition of\n False -> y\n True -> x\n --> if not condition then x else y\n\n -- only when no variables are introduced in the pattern\n -- and no custom types defined in the project are referenced\n case value of\n Just _ -> x\n Nothing -> x\n --> x\n\nDestructuring using case expressions\n\n case value of\n ( x, y ) ->\n x + y\n\n -->\n let\n ( x, y ) =\n value\n in\n x + y\n\n\n### Let expressions\n\n let\n a =\n 1\n in\n let\n b =\n 1\n in\n a + b\n\n -->\n let\n a =\n 1\n\n b =\n 1\n in\n a + b\n\n\n### Record updates\n\n { a | b = a.b }\n --> a\n\n { a | b = a.b, c = 1 }\n --> { a | c = 1 }\n\n\n### Field access\n\n { a = b }.a\n --> b\n\n { a | b = c }.b\n --> c\n\n { a | b = c }.d\n --> a.d\n\n (let a = b in c).d\n --> let a = b in c.d\n\n\n### Basics functions\n\n identity x\n --> x\n\n f >> identity\n --> f\n\n always x y\n --> x\n\n f >> always x\n --> always x\n\n\n### Lambdas\n\n (\\_ -> x) data\n --> x\n\n (\\() y -> x) ()\n --> (\\y -> x)\n\n (\\_ y -> x) data\n --> (\\y -> x)\n\n\n### Operators\n\n (++) a b\n --> a ++ b\n\n a |> f >> g\n --> a |> f |> g\n\n\n### Numbers\n\n n + 0\n --> n\n\n n - 0\n --> n\n\n 0 - n\n --> -n\n\n n * 1\n --> n\n\n 0 // n\n --> 0\n\n n // 0\n --> 0\n\n n // 1\n --> n\n\n n / 1\n --> n\n\n 0 / n\n --> 0\n\n -(-n)\n --> n\n\n negate (negate n)\n --> n\n\n n - n\n --> 0\n\n\n### Tuples\n\n Tuple.pair a b\n --> ( a, b )\n\n Tuple.first ( a, b )\n --> a\n\n Tuple.second ( a, b )\n --> b\n\n\n### Strings\n\n \"a\" ++ \"\"\n --> \"a\"\n\n String.fromList []\n --> \"\"\n\n String.fromList [ a ]\n --> String.fromChar a\n\n String.isEmpty \"\"\n --> True\n\n String.isEmpty \"a\"\n --> False\n\n String.concat []\n --> \"\"\n\n String.join str []\n --> \"\"\n\n String.join \"\" list\n --> String.concat list\n\n String.length \"abc\"\n --> 3\n\n String.repeat n \"\"\n --> \"\"\n\n String.repeat 0 str\n --> \"\"\n\n String.repeat 1 str\n --> str\n\n String.replace x y \"\"\n --> \"\"\n\n String.replace x x z\n --> z\n\n String.replace \"x\" \"y\" \"z\"\n --> \"z\" -- only when resulting string is unchanged\n\n String.words \"\"\n --> []\n\n String.lines \"\"\n --> []\n\n String.reverse \"\"\n --> \"\"\n\n String.reverse (String.fromChar a)\n --> String.fromChar a\n\n String.reverse (String.reverse str)\n --> str\n\n String.slice n n str\n --> \"\"\n\n String.slice n 0 str\n --> \"\"\n\n String.slice a z \"\"\n --> \"\"\n\n String.left 0 str\n --> \"\"\n\n String.left -1 str\n --> \"\"\n\n String.left n \"\"\n --> \"\"\n\n String.right 0 str\n --> \"\"\n\n String.right -1 str\n --> \"\"\n\n String.right n \"\"\n --> \"\"\n\n String.slice 2 1 str\n --> \"\"\n\n String.slice -1 -2 str\n --> \"\"\n\n\n### Maybes\n\n Maybe.map identity x\n --> x\n\n Maybe.map f Nothing\n --> Nothing\n\n Maybe.map f (Just x)\n --> Just (f x)\n\n Maybe.andThen f Nothing\n --> Nothing\n\n Maybe.andThen (always Nothing) x\n --> Nothing\n\n Maybe.andThen (\\a -> Just b) x\n --> Maybe.map (\\a -> b) x\n\n Maybe.andThen (\\a -> if condition a then Just b else Just c) x\n --> Maybe.map (\\a -> if condition a then b else c) x\n\n Maybe.andThen f (Just x)\n --> f x\n\n Maybe.withDefault x Nothing\n --> x\n\n Maybe.withDefault x (Just y)\n --> y\n\n\n### Results\n\n Result.map identity x\n --> x\n\n Result.map f (Err x)\n --> Err x\n\n Result.map f (Ok x)\n --> Ok (f x)\n\n Result.mapError identity x\n --> x\n\n Result.mapError f (Ok x)\n --> Ok x\n\n Result.mapError f (Err x)\n --> Err (f x)\n\n Result.andThen f (Err x)\n --> Err x\n\n Result.andThen f (Ok x)\n --> f x\n\n Result.andThen (\\a -> Ok b) x\n --> Result.map (\\a -> b) x\n\n Result.withDefault x (Err y)\n --> x\n\n Result.withDefault x (Ok y)\n --> y\n\n Result.toMaybe (Ok x)\n --> Just x\n\n Result.toMaybe (Err e)\n --> Nothing\n\n\n### Lists\n\n a :: []\n --> [ a ]\n\n a :: [ b ]\n --> [ a, b ]\n\n [ a ] ++ list\n --> a :: list\n\n [] ++ list\n --> list\n\n [ a, b ] ++ [ c ]\n --> [ a, b, c ]\n\n List.append [] ys\n --> ys\n\n List.append [ a, b ] [ c ]\n --> [ a, b, c ]\n\n List.head []\n --> Nothing\n\n List.head (a :: bToZ)\n --> Just a\n\n List.tail []\n --> Nothing\n\n List.tail (a :: bToZ)\n --> Just bToZ\n\n List.member a []\n --> False\n\n List.member a [ a, b, c ]\n --> True\n\n List.member a [ b ]\n --> a == b\n\n List.map f [] -- same for most List functions like List.filter, List.filterMap, ...\n --> []\n\n List.map identity list\n --> list\n\n List.filter (always True) list\n --> list\n\n List.filter (always False) list\n --> []\n\n List.filterMap Just list\n --> list\n\n List.filterMap (\\a -> if condition a then Just b else Just c) list\n --> List.map (\\a -> if condition a then b else c) list\n\n List.filterMap (always Nothing) list\n --> []\n\n List.filterMap identity (List.map f list)\n --> List.filterMap f list\n\n List.filterMap identity [ Just x, Just y ]\n --> [ x, y ]\n\n List.concat [ [ a, b ], [ c ] ]\n --> [ a, b, c ]\n\n List.concat [ a, [ 1 ], [ 2 ] ]\n --> List.concat [ a, [ 1, 2 ] ]\n\n List.concat [ a, [], b ]\n --> List.concat [ a, b ]\n\n List.concatMap identity list\n --> List.concat list\n\n List.concatMap (\\a -> [ b ]) list\n --> List.map (\\a -> b) list\n\n List.concatMap f [ x ]\n --> f x\n\n List.concatMap (always []) list\n --> []\n\n List.concat (List.map f list)\n --> List.concatMap f list\n\n List.indexedMap (\\_ value -> f value) list\n --> List.map (\\value -> f value) list\n\n List.intersperse a []\n --> []\n\n List.intersperse s [ a ]\n --> [ a ]\n\n List.isEmpty []\n --> True\n\n List.isEmpty [ a ]\n --> False\n\n List.isEmpty (x :: xs)\n --> False\n\n List.sum []\n --> 0\n\n List.sum [ a ]\n --> a\n\n List.product []\n --> 1\n\n List.product [ a ]\n --> a\n\n List.minimum []\n --> Nothing\n\n List.minimum [ a ]\n --> Just a\n\n List.maximum []\n --> Nothing\n\n List.maximum [ a ]\n --> Just a\n\n -- The following simplifications for List.foldl also work for List.foldr\n List.foldl f x []\n --> x\n\n List.foldl (\\_ soFar -> soFar) x list\n --> x\n\n List.foldl (+) 0 list\n --> List.sum list\n\n List.foldl (+) initial list\n --> initial + List.sum list\n\n List.foldl (*) 1 list\n --> List.product list\n\n List.foldl (*) 0 list\n --> 0\n\n List.foldl (*) initial list\n --> initial * List.product list\n\n List.foldl (&&) True list\n --> List.all identity list\n\n List.foldl (&&) False list\n --> False\n\n List.foldl (||) False list\n --> List.any identity list\n\n List.foldl (||) True list\n --> True\n\n List.all f []\n --> True\n\n List.all (always True) list\n --> True\n\n List.any f []\n --> True\n\n List.any (always False) list\n --> False\n\n List.any ((==) x) list\n --> List.member x list\n\n List.range 6 3\n --> []\n\n List.length [ a, b, c ]\n --> 3\n\n List.repeat 0 x\n --> []\n\n List.repeat 1 x\n --> List.singleton x\n\n List.partition f []\n --> ( [], [] )\n\n List.partition (always True) list\n --> ( list, [] )\n\n List.partition (always False) list\n --> ( [], list )\n\n List.take 0 list\n --> []\n\n List.drop 0 list\n --> list\n\n List.reverse []\n --> []\n\n List.reverse [ a ]\n --> [ a ]\n\n List.reverse (List.reverse list)\n --> list\n\n List.sortBy (always a) list\n --> list\n\n List.sortBy identity list\n --> List.sort list\n\n List.sortWith (\\_ _ -> LT) list\n --> List.reverse list\n\n List.sortWith (\\_ _ -> EQ) list\n --> list\n\n List.sortWith (\\_ _ -> GT) list\n --> list\n\n -- The following simplifications for List.sort also work for List.sortBy f and List.sortWith f\n List.sort []\n --> []\n\n List.sort [ a ]\n --> [ a ]\n\n -- same for up to List.map5 when any list is empty\n List.map2 f xs []\n --> []\n\n List.map2 f [] ys\n --> []\n\n List.unzip []\n --> ( [], [] )\n\n\n### Sets\n\n Set.map f Set.empty -- same for Set.filter, Set.remove...\n --> Set.empty\n\n Set.map identity set\n --> set\n\n Set.isEmpty Set.empty\n --> True\n\n Set.member x Set.empty\n --> False\n\n Set.fromList []\n --> Set.empty\n\n Set.fromList [ a ]\n --> Set.singleton a\n\n Set.toList Set.empty\n --> []\n\n Set.length Set.empty\n --> 0\n\n Set.intersect Set.empty set\n --> Set.empty\n\n Set.diff Set.empty set\n --> Set.empty\n\n Set.diff set Set.empty\n --> set\n\n Set.union set Set.empty\n --> set\n\n Set.insert x Set.empty\n --> Set.singleton x\n\n -- same for foldr\n List.foldl f x (Set.toList set)\n --> Set.foldl f x set\n\n Set.partition f Set.empty\n --> ( Set.empty, Set.empty )\n\n Set.partition (always True) set\n --> ( set, Set.empty )\n\n\n### Dict\n\n Dict.isEmpty Dict.empty\n --> True\n\n Dict.fromList []\n --> Dict.empty\n\n Dict.toList Dict.empty\n --> []\n\n Dict.size Dict.empty\n --> 0\n\n Dict.member x Dict.empty\n --> False\n\n Dict.intersect Dict.empty dict\n --> Dict.empty\n\n Dict.diff Dict.empty dict\n --> Dict.empty\n\n Dict.diff dict Dict.empty\n --> dict\n\n Dict.union dict Dict.empty\n --> dict\n\n Dict.partition f Dict.empty\n --> ( Dict.empty, Dict.empty )\n\n Dict.partition (always True) dict\n --> ( dict, Dict.empty )\n\n Dict.partition (always False) dict\n --> ( Dict.empty, dict )\n\n List.map Tuple.first (Dict.toList dict)\n --> Dict.keys dict\n\n List.map Tuple.second (Dict.toList dict)\n --> Dict.values dict\n\n\n### Cmd / Sub\n\nAll of these also apply for `Sub`.\n\n Cmd.batch []\n --> Cmd.none\n\n Cmd.batch [ a ]\n --> a\n\n Cmd.batch [ a, Cmd.none, b ]\n --> Cmd.batch [ a, b ]\n\n Cmd.map identity cmd\n --> cmd\n\n Cmd.map f Cmd.none\n --> Cmd.none\n\n\n### Html.Attributes\n\n Html.Attributes.classList [ x, y, ( z, False ) ]\n --> Html.Attributes.classList [ x, y ]\n\n Html.Attributes.classList [ ( onlyOneThing, True ) ]\n --> Html.Attributes.class onlyOneThing\n\n\n### Json.Decode\n\n Json.Decode.oneOf [ a ]\n --> a\n\n\n### Parser\n\n Parser.oneOf [ a ]\n --> a\n\n\n### Random\n\n Random.uniform a []\n --> Random.constant a\n\n Random.weighted ( weight, a ) []\n --> Random.constant a\n\n Random.weighted tuple []\n --> Random.constant (Tuple.first tuple)\n\n Random.list 0 generator\n --> Random.constant []\n\n Random.list 1 generator\n --> Random.map List.singleton generator\n\n Random.list n (Random.constant el)\n --> Random.constant (List.repeat n el)\n\n Random.map identity generator\n --> generator\n\n Random.map (always a) generator\n --> Random.constant a\n\n Random.map f (Random.constant x)\n --> Random.constant (f x)\n\n Random.andThen f (Random.constant x)\n --> f x\n\n Random.andThen Random.constant generator\n --> generator\n\n Random.andThen (\\a -> Random.constant b) generator\n --> Random.map (\\a -> b) generator\n\n Random.andThen (always thenGenerator) generator\n --> thenGenerator\n\n","unions":[{"name":"Configuration","comment":" Configuration for this rule. Create a new one with [`defaults`](#defaults) and use [`ignoreCaseOfForTypes`](#ignoreCaseOfForTypes) to alter it.\n","args":[],"cases":[]}],"aliases":[],"values":[{"name":"defaults","comment":" Default configuration for this rule.\n\nThe rule aims tries to improve the code through simplifications that don't impact the behavior. An exception to this are\nwhen the presence of `NaN` values\n\nUse [`expectNaN`](#expectNaN) if you want to opt out of changes that can impact the behaviour of your code if you expect to work with `NaN` values.\n\nUse [`ignoreCaseOfForTypes`](#ignoreCaseOfForTypes) if you want to prevent simplifying case expressions that work on custom types defined in dependencies.\n\n config =\n [ Simplify.rule Simplify.defaults\n ]\n\n -- or\n config =\n [ Simplify.defaults\n |> Simplify.expectNaN\n |> Simplify.ignoreCaseOfForTypes [ \"Module.Name.Type\" ]\n |> Simplify.rule\n ]\n\n","type":"Simplify.Configuration"},{"name":"expectNaN","comment":" Usually, `elm-review-simplify` will only suggest simplifications that are safe to apply without risk of changing the original behavior.\nHowever, when encountering [`NaN`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NaN)\nvalues, some simplifications can actually impact behavior.\n\nFor instance, the following expression will evaluate to `True`:\n\n x == x\n --> True\n\nHowever, if `x` is `NaN` or a value containing `NaN` then the expression will evaluate to `False`:\n\n -- given x = NaN\n x == x\n --> False\n\n -- given x = { a = ( NaN, 0 ) }\n x == x\n --> False\n\nGiven the potential presence of `NaN`, some simplifications become unsafe to apply:\n\n - `x == x` to `True`\n - `List.member x [ x ]` to `True`\n - `n * 0` to `0`\n\nThis special value is hard to recreate in Elm code both intentionally and unintentionally,\nand it's therefore unlikely to be found in your application,\nwhich is why the rule applies these simplifications by defaults.\n\nIf you somehow expect to create and encounter `NaN` values in your codebase, then you can use this function to disable these simplifications altogether.\n\n config =\n [ Simplify.defaults\n |> Simplify.expectNaN\n |> Simplify.rule\n ]\n\n","type":"Simplify.Configuration -> Simplify.Configuration"},{"name":"ignoreCaseOfForTypes","comment":" Ignore some reports about types from dependencies used in case expressions.\n\nThis rule simplifies the following construct:\n\n module Module.Name exposing (..)\n\n case value of\n Just _ -> x\n Nothing -> x\n --> x\n\n(Since `v2.0.19`) it will not try to simplify the case expression when some of the patterns references custom types constructors\ndefined in the project. It will only do so for custom types that are defined in dependencies (including `elm/core`).\n\nIf you do happen to want to disable this simplification for a type `Module.Name.Type`, you can configure the rule like this:\n\n config =\n [ Simplify.defaults\n |> Simplify.ignoreCaseOfForTypes [ \"Module.Name.Type\" ]\n |> Simplify.rule\n ]\n\nI personally don't recommend to use this function too much, because this could be a sign of premature abstraction, and because\nI think that often [You Aren't Gonna Need this code](https://jfmengels.net/safe-dead-code-removal/#yagni-you-arent-gonna-need-it).\n\nPlease let me know by opening an issue if you do use this function, I am very curious to know;\n\n","type":"List.List String.String -> Simplify.Configuration -> Simplify.Configuration"},{"name":"rule","comment":" Rule to simplify Elm code.\n","type":"Simplify.Configuration -> Review.Rule.Rule"}],"binops":[]}] \ No newline at end of file diff --git a/elm.json b/elm.json index 7245818ed..26559566a 100644 --- a/elm.json +++ b/elm.json @@ -3,7 +3,7 @@ "name": "jfmengels/elm-review-simplify", "summary": "Provides elm-review rules to simplify Elm code", "license": "BSD-3-Clause", - "version": "2.1.0", + "version": "2.1.1", "exposed-modules": [ "Simplify" ], @@ -18,4 +18,4 @@ "test-dependencies": { "elm-explorations/test": "2.0.1 <= v < 3.0.0" } -} \ No newline at end of file +} diff --git a/example/elm.json b/example/elm.json index 5c10cba60..147ea64c1 100644 --- a/example/elm.json +++ b/example/elm.json @@ -10,8 +10,8 @@ "elm/project-metadata-utils": "1.0.2", "jfmengels/elm-review": "2.13.1", "pzp1997/assoc-list": "1.0.0", - "stil4m/elm-syntax": "7.2.9", - "jfmengels/elm-review-simplify": "2.1.0" + "stil4m/elm-syntax": "7.3.1", + "jfmengels/elm-review-simplify": "2.1.1" }, "indirect": { "elm/bytes": "1.0.8",