2017-01-07 20:29:26 +03:00
|
|
|
module Main exposing (main)
|
|
|
|
|
2018-11-05 21:06:03 +03:00
|
|
|
import Browser
|
2019-07-28 13:33:29 +03:00
|
|
|
import Html exposing (Html, button, div, input, label, p, text, textarea)
|
2019-07-03 15:45:05 +03:00
|
|
|
import Html.Attributes as Attr
|
|
|
|
import Html.Events as Events
|
2019-07-25 15:35:58 +03:00
|
|
|
import Lint exposing (LintError, lintSource)
|
2019-06-24 23:55:16 +03:00
|
|
|
import Lint.Rule exposing (Rule)
|
2018-11-11 01:43:58 +03:00
|
|
|
import Lint.Rule.NoDebug
|
2019-06-16 16:31:40 +03:00
|
|
|
import Lint.Rule.NoExtraBooleanComparison
|
2019-06-03 01:30:24 +03:00
|
|
|
import Lint.Rule.NoImportingEverything
|
2019-07-05 00:57:55 +03:00
|
|
|
import Lint.Rule.NoUnusedTypeConstructors
|
2018-11-22 21:19:19 +03:00
|
|
|
import Lint.Rule.NoUnusedVariables
|
2019-07-28 13:33:29 +03:00
|
|
|
import Reporter
|
2017-01-07 20:29:26 +03:00
|
|
|
|
|
|
|
|
2019-06-24 02:20:10 +03:00
|
|
|
|
|
|
|
-- LINT CONFIGURATION
|
2017-01-07 20:29:26 +03:00
|
|
|
|
|
|
|
|
2019-07-25 15:35:58 +03:00
|
|
|
config : Model -> List Rule
|
2019-07-03 15:45:05 +03:00
|
|
|
config model =
|
2019-07-25 15:35:58 +03:00
|
|
|
[ ( model.noDebugEnabled, Lint.Rule.NoDebug.rule )
|
|
|
|
, ( model.noUnusedVariablesEnabled, Lint.Rule.NoUnusedVariables.rule )
|
|
|
|
, ( model.noImportingEverythingEnabled, Lint.Rule.NoImportingEverything.rule { exceptions = [ "Html" ] } )
|
|
|
|
, ( model.noExtraBooleanComparisonEnabled, Lint.Rule.NoExtraBooleanComparison.rule )
|
|
|
|
, ( model.noUnusedTypeConstructorsEnabled, Lint.Rule.NoUnusedTypeConstructors.rule )
|
|
|
|
|
|
|
|
-- , Lint.Rule.NoConstantCondition.rule
|
|
|
|
-- , Lint.Rule.NoDuplicateImports.rule
|
|
|
|
-- , Lint.Rule.NoExposingEverything.rule
|
|
|
|
-- , Lint.Rule.NoNestedLet.rule
|
|
|
|
-- , Lint.Rule.NoUnannotatedFunction.rule
|
|
|
|
-- , Lint.Rule.NoUselessIf.rule
|
|
|
|
-- , Lint.Rule.NoUselessPatternMatching.rule
|
|
|
|
-- , Lint.Rule.NoWarningComments.rule
|
|
|
|
-- , Lint.Rule.SimplifyPiping.rule
|
|
|
|
-- , Lint.Rule.SimplifyPropertyAccess.rule
|
|
|
|
-- , Lint.Rule.ElmTest.NoDuplicateTestBodies.rule
|
2017-01-20 01:31:55 +03:00
|
|
|
]
|
2019-07-03 19:11:38 +03:00
|
|
|
|> List.filter Tuple.first
|
|
|
|
|> List.map Tuple.second
|
2017-01-20 01:31:55 +03:00
|
|
|
|
|
|
|
|
2019-06-24 02:20:10 +03:00
|
|
|
|
|
|
|
-- MODEL
|
|
|
|
|
|
|
|
|
|
|
|
type alias Model =
|
|
|
|
{ sourceCode : String
|
2019-07-28 22:16:01 +03:00
|
|
|
, lintErrors : List LintError
|
2019-07-03 15:45:05 +03:00
|
|
|
, noDebugEnabled : Bool
|
|
|
|
, noUnusedVariablesEnabled : Bool
|
|
|
|
, noImportingEverythingEnabled : Bool
|
2019-07-03 19:26:53 +03:00
|
|
|
, noImportingEverythingExceptions : List String
|
2019-07-03 15:45:05 +03:00
|
|
|
, noExtraBooleanComparisonEnabled : Bool
|
2019-07-05 00:57:55 +03:00
|
|
|
, noUnusedTypeConstructorsEnabled : Bool
|
2019-07-03 19:11:38 +03:00
|
|
|
, showConfigurationAsText : Bool
|
2019-06-24 02:20:10 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-06-24 02:00:22 +03:00
|
|
|
init : Model
|
2017-01-07 20:29:26 +03:00
|
|
|
init =
|
2019-06-24 02:00:22 +03:00
|
|
|
let
|
|
|
|
sourceCode : String
|
|
|
|
sourceCode =
|
|
|
|
"""module Main exposing (f)
|
2017-01-19 23:02:21 +03:00
|
|
|
|
2019-06-03 01:30:24 +03:00
|
|
|
import Html.Events exposing (..)
|
2017-01-20 00:27:11 +03:00
|
|
|
import Html exposing (..)
|
2019-06-24 02:00:22 +03:00
|
|
|
import NotUsed
|
|
|
|
import SomeModule exposing (notUsed)
|
2017-01-07 20:29:26 +03:00
|
|
|
|
|
|
|
f : Int -> Int
|
2017-01-07 23:17:01 +03:00
|
|
|
f x = x Debug.log 1
|
2017-01-07 20:29:26 +03:00
|
|
|
|
2017-01-19 23:02:21 +03:00
|
|
|
g n = n + 1
|
2017-01-07 20:29:26 +03:00
|
|
|
"""
|
2019-07-03 15:45:05 +03:00
|
|
|
|
|
|
|
tmpModel : Model
|
|
|
|
tmpModel =
|
|
|
|
{ sourceCode = sourceCode
|
2019-07-28 22:16:01 +03:00
|
|
|
, lintErrors = []
|
2019-07-03 15:45:05 +03:00
|
|
|
, noDebugEnabled = True
|
|
|
|
, noUnusedVariablesEnabled = True
|
|
|
|
, noImportingEverythingEnabled = True
|
2019-07-03 19:26:53 +03:00
|
|
|
, noImportingEverythingExceptions = [ "Html", "Html.Attributes" ]
|
2019-07-03 15:45:05 +03:00
|
|
|
, noExtraBooleanComparisonEnabled = True
|
2019-07-05 00:57:55 +03:00
|
|
|
, noUnusedTypeConstructorsEnabled = True
|
2019-07-03 19:11:38 +03:00
|
|
|
, showConfigurationAsText = False
|
2019-07-03 15:45:05 +03:00
|
|
|
}
|
2019-06-24 02:00:22 +03:00
|
|
|
in
|
2019-07-28 22:16:01 +03:00
|
|
|
{ tmpModel | lintErrors = lintSource (config tmpModel) { fileName = "", source = sourceCode } }
|
2019-06-24 02:00:22 +03:00
|
|
|
|
2017-01-07 20:29:26 +03:00
|
|
|
|
2019-06-24 02:20:10 +03:00
|
|
|
|
|
|
|
-- UPDATE
|
|
|
|
|
|
|
|
|
|
|
|
type Msg
|
|
|
|
= UserEditedSourceCode String
|
2019-07-03 15:45:05 +03:00
|
|
|
| UserToggledNoDebugRule
|
|
|
|
| UserToggledNoUnusedVariablesRule
|
|
|
|
| UserToggledNoImportingEverythingRule
|
|
|
|
| UserToggledNoExtraBooleanComparisonRule
|
2019-07-05 00:57:55 +03:00
|
|
|
| UserToggledNoUnusedTypeConstructorsRule
|
2019-07-03 19:11:38 +03:00
|
|
|
| UserToggledConfigurationAsText
|
2017-01-07 20:29:26 +03:00
|
|
|
|
2019-06-24 02:00:22 +03:00
|
|
|
|
|
|
|
update : Msg -> Model -> Model
|
2017-01-07 20:29:26 +03:00
|
|
|
update action model =
|
|
|
|
case action of
|
2019-06-24 02:11:50 +03:00
|
|
|
UserEditedSourceCode sourceCode ->
|
2019-06-24 02:00:22 +03:00
|
|
|
{ model
|
|
|
|
| sourceCode = sourceCode
|
2019-07-30 01:03:07 +03:00
|
|
|
, lintErrors = lintSource (config model) { fileName = "Source code", source = sourceCode }
|
2019-06-24 02:00:22 +03:00
|
|
|
}
|
2017-01-07 20:29:26 +03:00
|
|
|
|
2019-07-03 15:45:05 +03:00
|
|
|
UserToggledNoDebugRule ->
|
|
|
|
{ model | noDebugEnabled = not model.noDebugEnabled }
|
|
|
|
|> rerunLinting
|
|
|
|
|
|
|
|
UserToggledNoUnusedVariablesRule ->
|
|
|
|
{ model | noUnusedVariablesEnabled = not model.noUnusedVariablesEnabled }
|
|
|
|
|> rerunLinting
|
|
|
|
|
|
|
|
UserToggledNoImportingEverythingRule ->
|
|
|
|
{ model | noImportingEverythingEnabled = not model.noImportingEverythingEnabled }
|
|
|
|
|> rerunLinting
|
|
|
|
|
|
|
|
UserToggledNoExtraBooleanComparisonRule ->
|
|
|
|
{ model | noExtraBooleanComparisonEnabled = not model.noExtraBooleanComparisonEnabled }
|
|
|
|
|> rerunLinting
|
|
|
|
|
2019-07-05 00:57:55 +03:00
|
|
|
UserToggledNoUnusedTypeConstructorsRule ->
|
|
|
|
{ model | noUnusedTypeConstructorsEnabled = not model.noUnusedTypeConstructorsEnabled }
|
|
|
|
|> rerunLinting
|
|
|
|
|
2019-07-03 19:11:38 +03:00
|
|
|
UserToggledConfigurationAsText ->
|
|
|
|
{ model | showConfigurationAsText = not model.showConfigurationAsText }
|
|
|
|
|
2019-07-03 15:45:05 +03:00
|
|
|
|
|
|
|
rerunLinting : Model -> Model
|
|
|
|
rerunLinting model =
|
2019-07-28 22:16:01 +03:00
|
|
|
{ model
|
|
|
|
| lintErrors =
|
|
|
|
lintSource (config model)
|
|
|
|
{ fileName = "Source code", source = model.sourceCode }
|
|
|
|
}
|
2019-07-03 15:45:05 +03:00
|
|
|
|
2017-01-07 20:29:26 +03:00
|
|
|
|
2018-11-06 15:15:23 +03:00
|
|
|
|
2019-06-24 02:20:10 +03:00
|
|
|
-- VIEW
|
2017-01-07 22:58:41 +03:00
|
|
|
|
|
|
|
|
2019-06-24 02:00:22 +03:00
|
|
|
view : Model -> Html Msg
|
2017-01-07 20:29:26 +03:00
|
|
|
view model =
|
2019-07-03 15:45:05 +03:00
|
|
|
div [ Attr.id "wrapper" ]
|
|
|
|
[ div [ Attr.id "left" ]
|
|
|
|
[ p [ Attr.class "title" ] [ text "Source code" ]
|
2019-06-24 02:11:18 +03:00
|
|
|
, div
|
2019-07-03 15:45:05 +03:00
|
|
|
[ Attr.style "display" "flex"
|
|
|
|
, Attr.style "flex-direction" "row"
|
2017-01-16 00:57:03 +03:00
|
|
|
]
|
2019-07-28 13:33:29 +03:00
|
|
|
[ div
|
|
|
|
[ Attr.style "width" "60%"
|
|
|
|
]
|
|
|
|
[ textarea
|
|
|
|
[ Attr.id "input"
|
|
|
|
, Events.onInput UserEditedSourceCode
|
|
|
|
, Attr.style "width" "100%"
|
|
|
|
, Attr.style "height" "500px"
|
|
|
|
]
|
|
|
|
[ text model.sourceCode ]
|
|
|
|
, div
|
|
|
|
[ Attr.style "border-radius" "4px"
|
|
|
|
, Attr.style "padding" "12px"
|
|
|
|
, Attr.style "max-width" "100%"
|
|
|
|
, Attr.style "width" "calc(100vw - 24px)"
|
|
|
|
, Attr.style "overflow-x" "auto"
|
|
|
|
, Attr.style "white-space" "pre"
|
|
|
|
, Attr.style "color" "white"
|
|
|
|
, Attr.style "font-family" "'Source Code Pro', monospace"
|
|
|
|
, Attr.style "font-size" "12px"
|
|
|
|
, Attr.style "background-color" "black"
|
|
|
|
]
|
2019-07-31 00:18:52 +03:00
|
|
|
[ viewLintErrors model
|
2019-07-28 13:33:29 +03:00
|
|
|
]
|
|
|
|
]
|
|
|
|
, div
|
|
|
|
[ Attr.style "margin-left" "2rem"
|
|
|
|
, Attr.style "width" "40%"
|
2019-06-24 02:11:18 +03:00
|
|
|
]
|
2019-07-03 15:45:05 +03:00
|
|
|
[ viewConfigurationPanel model
|
2019-07-03 19:11:38 +03:00
|
|
|
, viewConfigurationAsText model
|
2019-07-03 15:45:05 +03:00
|
|
|
, p [ Attr.class "title" ] [ text "Linting errors" ]
|
2019-06-24 02:11:18 +03:00
|
|
|
]
|
2017-01-16 00:57:03 +03:00
|
|
|
]
|
2017-01-10 00:12:37 +03:00
|
|
|
]
|
|
|
|
]
|
2017-01-07 20:29:26 +03:00
|
|
|
|
|
|
|
|
2019-07-03 15:45:05 +03:00
|
|
|
viewConfigurationPanel : Model -> Html Msg
|
|
|
|
viewConfigurationPanel model =
|
|
|
|
div []
|
|
|
|
[ p [ Attr.class "title" ] [ text "Configuration" ]
|
|
|
|
, div
|
|
|
|
[ Attr.style "display" "flex"
|
|
|
|
, Attr.style "flex-direction" "column"
|
|
|
|
]
|
|
|
|
[ viewCheckbox UserToggledNoDebugRule "NoDebug" model.noDebugEnabled
|
|
|
|
, viewCheckbox UserToggledNoUnusedVariablesRule "NoUnusedVariables" model.noUnusedVariablesEnabled
|
|
|
|
, viewCheckbox UserToggledNoImportingEverythingRule "NoImportingEverything" model.noImportingEverythingEnabled
|
|
|
|
, viewCheckbox UserToggledNoExtraBooleanComparisonRule "NoExtraBooleanComparison" model.noExtraBooleanComparisonEnabled
|
2019-07-05 00:57:55 +03:00
|
|
|
, viewCheckbox UserToggledNoUnusedTypeConstructorsRule "NoUnusedTypeConstructors" model.noUnusedTypeConstructorsEnabled
|
2019-07-03 15:45:05 +03:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
|
|
|
|
2019-07-03 19:11:38 +03:00
|
|
|
viewConfigurationAsText : Model -> Html Msg
|
|
|
|
viewConfigurationAsText model =
|
|
|
|
if model.showConfigurationAsText then
|
|
|
|
div
|
|
|
|
[ Attr.style "display" "flex"
|
|
|
|
, Attr.style "flex-direction" "column"
|
2019-07-28 13:33:29 +03:00
|
|
|
, Attr.style "width" "100%"
|
2019-07-03 19:11:38 +03:00
|
|
|
]
|
|
|
|
[ button
|
|
|
|
[ Attr.style "margin-top" "2rem"
|
|
|
|
, Events.onClick UserToggledConfigurationAsText
|
|
|
|
]
|
|
|
|
[ text "Hide configuration as Elm code" ]
|
|
|
|
, textarea
|
|
|
|
[ Events.onInput UserEditedSourceCode
|
|
|
|
, Attr.style "height" "300px"
|
|
|
|
, Attr.style "width" "100%"
|
|
|
|
]
|
|
|
|
[ text <| configurationAsText model ]
|
|
|
|
]
|
|
|
|
|
|
|
|
else
|
|
|
|
button
|
|
|
|
[ Attr.style "margin-top" "2rem"
|
|
|
|
, Events.onClick UserToggledConfigurationAsText
|
|
|
|
]
|
|
|
|
[ text "Show configuration as Elm code" ]
|
|
|
|
|
|
|
|
|
|
|
|
configurationAsText : Model -> String
|
|
|
|
configurationAsText model =
|
|
|
|
let
|
|
|
|
rules : List { import_ : String, configExpression : String }
|
|
|
|
rules =
|
|
|
|
[ ( model.noDebugEnabled
|
|
|
|
, { import_ = "Lint.Rule.NoDebug"
|
|
|
|
, configExpression = "Lint.Rule.NoDebug.rule"
|
|
|
|
}
|
|
|
|
)
|
|
|
|
, ( model.noUnusedVariablesEnabled
|
|
|
|
, { import_ = "Lint.Rule.NoUnusedVariables"
|
|
|
|
, configExpression = "Lint.Rule.NoUnusedVariables.rule"
|
|
|
|
}
|
|
|
|
)
|
|
|
|
, ( model.noImportingEverythingEnabled
|
|
|
|
, { import_ = "Lint.Rule.NoImportingEverything"
|
|
|
|
, configExpression = "Lint.Rule.NoImportingEverything.rule { exceptions = [] }"
|
|
|
|
}
|
|
|
|
)
|
|
|
|
, ( model.noExtraBooleanComparisonEnabled
|
|
|
|
, { import_ = "Lint.Rule.NoExtraBooleanComparison"
|
|
|
|
, configExpression = "Lint.Rule.NoExtraBooleanComparison.rule"
|
|
|
|
}
|
|
|
|
)
|
2019-07-05 00:57:55 +03:00
|
|
|
, ( model.noUnusedTypeConstructorsEnabled
|
|
|
|
, { import_ = "Lint.Rule.NoUnusedTypeConstructors"
|
|
|
|
, configExpression = "Lint.Rule.NoUnusedTypeConstructors.rule"
|
|
|
|
}
|
|
|
|
)
|
2019-07-03 19:11:38 +03:00
|
|
|
]
|
|
|
|
|> List.filter Tuple.first
|
|
|
|
|> List.map Tuple.second
|
|
|
|
|
|
|
|
importStatements : String
|
|
|
|
importStatements =
|
|
|
|
rules
|
|
|
|
|> List.map (\{ import_ } -> "import " ++ import_)
|
|
|
|
|> String.join "\n"
|
|
|
|
|
|
|
|
configExpressions : String
|
|
|
|
configExpressions =
|
|
|
|
rules
|
2019-07-25 15:35:58 +03:00
|
|
|
|> List.map (\{ configExpression } -> " " ++ configExpression)
|
2019-07-03 19:11:38 +03:00
|
|
|
|> String.join "\n ,"
|
|
|
|
in
|
|
|
|
"""module LintConfig exposing (config)
|
|
|
|
|
|
|
|
import Lint.Rule exposing (Rule)
|
|
|
|
""" ++ importStatements ++ """
|
|
|
|
|
|
|
|
|
2019-07-25 15:35:58 +03:00
|
|
|
config : List Rule
|
2019-07-03 19:11:38 +03:00
|
|
|
config =
|
|
|
|
[""" ++ configExpressions ++ """
|
|
|
|
]
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
2019-07-03 15:45:05 +03:00
|
|
|
viewCheckbox : Msg -> String -> Bool -> Html Msg
|
|
|
|
viewCheckbox onClick name checked =
|
|
|
|
label
|
|
|
|
[]
|
|
|
|
[ input
|
|
|
|
[ Attr.type_ "checkbox"
|
|
|
|
, Attr.checked checked
|
|
|
|
, Events.onClick onClick
|
|
|
|
]
|
|
|
|
[]
|
|
|
|
, text name
|
|
|
|
]
|
|
|
|
|
|
|
|
|
2019-07-31 00:18:52 +03:00
|
|
|
viewLintErrors : Model -> Html msg
|
|
|
|
viewLintErrors model =
|
|
|
|
lintErrors model
|
|
|
|
|> List.map viewPart
|
|
|
|
|> Html.div []
|
|
|
|
|
|
|
|
|
|
|
|
viewPart : { str : String, color : Maybe ( Int, Int, Int ) } -> Html msg
|
|
|
|
viewPart { str, color } =
|
|
|
|
Html.span
|
|
|
|
[ case color of
|
|
|
|
Just ( red, green, blue ) ->
|
|
|
|
Attr.style "color" <| "rgb(" ++ String.fromInt red ++ "," ++ String.fromInt green ++ "," ++ String.fromInt blue ++ ")"
|
|
|
|
|
|
|
|
Nothing ->
|
|
|
|
Attr.classList []
|
|
|
|
]
|
|
|
|
(str
|
|
|
|
|> String.lines
|
|
|
|
|> List.map Html.text
|
|
|
|
|> List.intersperse (Html.br [] [])
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
lintErrors : Model -> List { str : String, color : Maybe ( Int, Int, Int ) }
|
2019-06-24 02:20:10 +03:00
|
|
|
lintErrors model =
|
2019-07-28 22:16:01 +03:00
|
|
|
if List.isEmpty model.lintErrors then
|
2019-07-31 00:18:52 +03:00
|
|
|
[ { str = "I found no linting errors.\nYou're all good!"
|
|
|
|
, color = Nothing
|
|
|
|
}
|
|
|
|
]
|
2019-07-28 22:16:01 +03:00
|
|
|
|
|
|
|
else
|
2019-07-31 00:18:52 +03:00
|
|
|
[ ( { name = "Source code"
|
|
|
|
, source = model.sourceCode
|
|
|
|
}
|
|
|
|
, model.lintErrors
|
|
|
|
|> List.map fromLintError
|
|
|
|
)
|
|
|
|
]
|
|
|
|
|> Reporter.formatReport
|
|
|
|
|
|
|
|
|
|
|
|
fromLintError : LintError -> Reporter.Error
|
|
|
|
fromLintError error =
|
|
|
|
{ ruleName = Lint.errorRuleName error
|
|
|
|
, message = Lint.errorMessage error
|
|
|
|
, details = Lint.errorDetails error
|
|
|
|
, range = Lint.errorRange error
|
|
|
|
}
|
2019-06-24 02:20:10 +03:00
|
|
|
|
|
|
|
|
2019-06-24 02:00:22 +03:00
|
|
|
main : Program () Model Msg
|
2017-01-07 20:29:26 +03:00
|
|
|
main =
|
2018-11-05 21:06:03 +03:00
|
|
|
Browser.sandbox
|
2018-11-05 21:30:47 +03:00
|
|
|
{ init = init
|
2017-01-07 20:29:26 +03:00
|
|
|
, update = update
|
|
|
|
, view = view
|
|
|
|
}
|