rule : Config -> Review.Rule.Rule
Automatically generates used record field helpers that don't exist yet.
Examples are
config =
[ RecordFieldHelper.GenerateUsed.rule
{ generator = RecordFieldHelper.GenerateUsed.accessors
, generateIn = ( "Accessors", [ "Library", "Fields" ] )
}
]
generator
: What kind of lens to generate:
generateIn
: The module where all field lenses will be generated in
understand ( "Accessors", [ "Library", "Fields" ] )
as Accessors.Library.Fields
module SomeModule exposing (scoreAPoint)
import Accessors.Library.Fields as Field
scoreAPoint =
Accessors.over Field.score (\score -> score + 1)
module Accessors.Library.Fields exposing (name)
...
module Accessors.Library.Fields exposing (score)
...
{ generator : FieldLensGenerator
, generateIn : ( String
, List String )
}
The rule's configuration.
generate
: What kind of lens to generate:
generateIn
: The module where all field lenses will be generated in
read ( "Module", [ "Name" ] )
as Module.Name
accessors : FieldLensGenerator
FieldLensGenerator
for named erlandsona/elm-accessors
in the form
import Accessors exposing (Lens, makeOneToOne_)
score : Lens { record | score : score } transformed score wrap
score =
makeOneToOne_ ".score" .score (\alter record -> { record | score = record.score |> alter })
monocle : FieldLensGenerator
FieldLensGenerator
for arturopala's elm-monocle in the form
import Monocle.Lens exposing (Lens)
score : Lens { record | score : score } score
score =
{ get = .score, set = \replacement record -> { record | score = replacement } }
fields : FieldLensGenerator
FieldLensGenerator
for sjorn3's elm-fields in the form
score :
{ get : { record0 | score : score } -> score
, set : score -> { record1 | score : score } -> { record1 | score : score }
}
score =
{ get = .score, set = \replacement record -> { record | score = replacement } }
zipper : FieldLensGenerator
FieldLensGenerator
for z5h's zipper in the form
import Zipper exposing (Zipper, into)
intoScore : Zipper { record | score : score } root -> Zipper score root
intoScore =
into .score (\replacement record -> { record | score = replacement })
accessorsBChiquet : FieldLensGenerator
FieldLensGenerator
for bChiquet/elm-accessors
in the form
import Accessors exposing (Relation, makeOneToOne)
score : Relation score transformed wrap -> Relation { record | score : score } transformed wrap
score =
makeOneToOne .score (\alter record -> { record | score = record.score |> alter })
accessors
generates for erlandsona/elm-accessors
which adds names.
{ imports : List Elm.CodeGen.Import
, declaration : { fieldName : String } -> FieldLensDeclaration
}
How to generate a FieldLensDeclaration
plus the necessary imports.
Out of the box there are lenses for
You can also create a custom one with the help of the-sett's elm-syntax-dsl:
customLens : FieldLensGenerator
customLens =
{ imports =
[ importStmt [ "CustomLens" ]
Nothing
(exposeExplicit
[ typeOrAliasExpose "CustomLens" ]
|> Just
)
]
, declaration =
\{ fieldName } ->
{ documentation =
emptyDocComment
|> markdown
("`CustomLens` for the field `." ++ fieldName ++ "`.")
|> Just
, name = fieldName
, annotation =
typed "CustomLens"
[ extRecordAnn "record"
[ ( fieldName, typeVar fieldName ) ]
, typeVar fieldName
]
|> Just
, implementation =
let
{ access, set } =
functionsForField fieldName
in
fqConstruct [ "CustomLens" ] "create" [ access, at ]
}
}
{ documentation : Maybe (Elm.CodeGen.Comment Elm.CodeGen.DocComment)
, name : String
, annotation : Maybe Elm.CodeGen.TypeAnnotation
, implementation : Elm.CodeGen.Expression
}
All the components to build a field lens declaration:
{-| [documentation]
-}
[name] : [annotation]
[name] =
[implementation]
You can customize existing FieldLensDeclaration
s with withDocumentation
and withName
or create custom lens (functionsForField
and getSetRecordForField
can be helpful).
customLensDeclaration { fieldName } =
{ documentation =
emptyDocComment
|> markdown
("`CustomLens` for the field `." ++ fieldName ++ "`.")
|> Just
, name = fieldName
, annotation =
typed "CustomLens"
[ extRecordAnn "record"
[ ( fieldName, typeVar fieldName ) ]
, typeVar fieldName
]
|> Just
, implementation =
let
{ access, set } =
functionsForField fieldName
in
fqConstruct [ "CustomLens" ] "create" [ access, at ]
}
functionsForField : String -> { access : Elm.CodeGen.Expression, set : Elm.CodeGen.Expression, update : Elm.CodeGen.Expression }
access, set and update functions for a given record field.
functionsForField "score"
-->
{ access = accessFun ("." ++ fieldName)
, set =
lambda
[ varPattern "replacement"
, varPattern "record"
]
(update "record"
[ ( fieldName
, val "replacement"
)
]
)
, update =
lambda
[ varPattern "alter"
, varPattern "record"
]
(update "record"
[ ( fieldName
, applyBinOp
(access (val "record") fieldName)
piper
(fun "alter")
)
]
)
}
getSetRecordForField : String -> Elm.CodeGen.Expression
Generate a field lens implementation in the form
{ get = .score, set = \replacement record -> { record | score = replacement } }
This is equivalent to
let
{ access, set } =
functionsForField fieldName
in
record [ ( "get", access ), ( "set", set ) ]
withDocumentation : Elm.CodeGen.Comment Elm.CodeGen.DocComment -> FieldLensDeclaration -> FieldLensDeclaration
The provided FieldLensGenerator
s in this package have no documentation comment.
You can generate your own documentation, though:
accessorsWithDocumentation { fieldName } =
accessors { fieldName = fieldName }
|> withDocumentation
(emptyDocComment
|> markdown
("Accessor for the field `." ++ fieldName ++ "`.")
)
withName : String -> FieldLensDeclaration -> FieldLensDeclaration
Use a different name for the generated lens.
accessorsWithFieldSuffix { fieldName } =
accessors { fieldName = fieldName }
|> withName (fieldName ++ "Field")