Skip to content

Commit

Permalink
Merge pull request #30 from mateusfpleite/main
Browse files Browse the repository at this point in the history
Install.Function: Split replace and insertion functionalities
  • Loading branch information
jxxcarlson authored Jun 22, 2024
2 parents d122c2e + dd247f0 commit fc62a8b
Show file tree
Hide file tree
Showing 8 changed files with 387 additions and 250 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,8 @@ update msg model =
- **Install.FieldInTypeAlias**: Add a field to a specified type alias in a specified module. For more details, see the [docs](https://package.elm-lang.org/packages/jxxcarlson/elm-review-codeinstaller/latest/Install-FieldInTypeAlias).
- **Install.Initializer**: Add a field to the body of an initializer function where the return value is of the form `( Model, Cmd msg )`. For more details, see the [docs](https://package.elm-lang.org/packages/jxxcarlson/elm-review-codeinstaller/latest/Install-Initializer).
- **Install.TypeVariant**: Add a variant to a specified type in a specified module. For more details, see the [docs](https://package.elm-lang.org/packages/jxxcarlson/elm-review-codeinstaller/latest/Install-TypeVariant).
- **Install.Function**: Replace a function in a given module with a new implementation or add that function definition if it is not present in the module. For more details, see the [docs](https://package.elm-lang.org/packages/jxxcarlson/elm-review-codeinstaller/latest/Install-Function).
- **Install.Function.ReplaceFunction**: Replace a function in a given module with a new implementation. For more details, see the [docs](https://package.elm-lang.org/packages/jxxcarlson/elm-review-codeinstaller/latest/Install-Function-ReplaceFunction).
- **Install.Function.InsertFunction**: Add a function in a given module if it is not present. For more details, see the [docs](https://package.elm-lang.org/packages/jxxcarlson/elm-review-codeinstaller/latest/Install-Function-InsertFunction).
- **Install.Import**: Add import statements to a given module. For more details, see the [docs](https://package.elm-lang.org/packages/jxxcarlson/elm-review-codeinstaller/latest/Install-Import).

## Try it out
Expand Down
3 changes: 2 additions & 1 deletion elm.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
"Install.FieldInTypeAlias",
"Install.Initializer",
"Install.TypeVariant",
"Install.Function",
"Install.Function.InsertFunction",
"Install.Function.ReplaceFunction",
"Install.Import",
"Install.Type"
],
Expand Down
290 changes: 157 additions & 133 deletions preview/src/ReviewConfig.elm

Large diffs are not rendered by default.

9 changes: 3 additions & 6 deletions review/elm.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"elm/core": "1.0.5",
"elm/json": "1.1.3",
"elm/project-metadata-utils": "1.0.2",
"jfmengels/elm-review": "2.13.2",
"jfmengels/elm-review": "2.14.0",
"jfmengels/elm-review-debug": "1.0.8",
"jfmengels/elm-review-unused": "1.2.3",
"jxxcarlson/elm-review-codeinstaller": "1.0.0",
Expand All @@ -20,11 +20,11 @@
"elm/html": "1.0.0",
"elm/parser": "1.1.0",
"elm/random": "1.0.0",
"elm/regex": "1.0.0",
"elm/time": "1.0.0",
"elm/virtual-dom": "1.0.3",
"elm-explorations/test": "2.2.0",
"miniBill/elm-unicode": "1.1.1",
"pzp1997/assoc-list": "1.0.0",
"rtfeldman/elm-hex": "1.0.0",
"stil4m/structured-writer": "1.0.3"
}
Expand All @@ -33,9 +33,6 @@
"direct": {
"elm-explorations/test": "2.2.0"
},
"indirect": {
"elm/regex": "1.0.0",
"pzp1997/assoc-list": "1.0.0"
}
"indirect": {}
}
}
121 changes: 28 additions & 93 deletions src/Install/Function.elm → src/Install/Function/InsertFunction.elm
Original file line number Diff line number Diff line change
@@ -1,45 +1,43 @@
module Install.Function exposing (makeRule, init, Config, CustomError, withInsertAfter)
module Install.Function.InsertFunction exposing (makeRule, init, Config, CustomError, withInsertAfter)

{-| Replace a function in a given module with a new implementation or
add that function definition if it is not present in the module.
{-| Add a function in a given module if it is not present.
-- code for ReviewConfig.elm:
rule =
Install.Function.init
Install.Function.InsertFunction.init
"Frontend"
"view"
"""view model =
Html.text "This is a test\""""
|> Install.Function.makeRule
Html.text "This is a test\""""
|> Install.Function.InsertFunction.makeRule
Running this rule will insert the function `view` in the module `Frontend` with the provided implementation.
Running this rule will insert or replace the function `view` in the module `Frontend` with the new implementation.
The form of the rule is the same for nested modules:
rule =
Install.Function.init
Install.Function.InsertFunction.init
"Foo.Bar"
"earnInterest"
"hoho model = { model | interest = 1.03 * model.interest }"
|> Install.Function.makeRule
|> Install.Function.InsertFunction.makeRule
@docs makeRule, init, Config, CustomError, withInsertAfter
-}

import Elm.Syntax.Declaration exposing (Declaration(..))
import Elm.Syntax.Expression exposing (Expression, Function)
import Elm.Syntax.Declaration exposing (Declaration)
import Elm.Syntax.Expression exposing (Expression)
import Elm.Syntax.ModuleName exposing (ModuleName)
import Elm.Syntax.Node as Node exposing (Node)
import Elm.Syntax.Range as Range exposing (Range)
import Install.Infer as Infer
import Install.Library
import Install.Normalize as Normalize
import Review.Fix as Fix
import Review.ModuleNameLookupTable exposing (ModuleNameLookupTable)
import Review.Rule as Rule exposing (Error, Rule)


{-| Configuration for makeRule: add (or replace if function already exists) a function in a specified module.
{-| Configuration for makeRule: add a function in a specified module if it does not already exist.
-}
type Config
= Config
Expand Down Expand Up @@ -79,13 +77,12 @@ init moduleNaeme functionName functionImplementation =
, functionName = functionName
, functionImplementation = functionImplementation
, theFunctionNodeExpression = Install.Library.maybeNodeExpressionFromString { moduleName = String.split "." moduleNaeme } functionImplementation
, customErrorMessage = CustomError { message = "Replace function \"" ++ functionName ++ "\" with new code.", details = [ "" ] }
, customErrorMessage = CustomError { message = "Add function \"" ++ functionName ++ "\".", details = [ "" ] }
, insertAt = AtEnd
}


{-| Create a rule that replaces a function in a given module with a new implementation or
creates it if it is not present.
{-| Create a rule that adds a function in a given module if it is not present.
-}
makeRule : Config -> Rule
makeRule config =
Expand All @@ -94,7 +91,7 @@ makeRule config =
visitor declaration context =
declarationVisitor context config declaration
in
Rule.newModuleRuleSchemaUsingContextCreator "Install.Function" initialContext
Rule.newModuleRuleSchemaUsingContextCreator "Install.Function.InsertFunction" initialContext
|> Rule.withDeclarationEnterVisitor visitor
|> Rule.withFinalModuleEvaluation (finalEvaluation config)
|> Rule.providesFixesForModuleRule
Expand All @@ -120,10 +117,13 @@ initialContext =
declarationVisitor : Context -> Config -> Node Declaration -> ( List (Rule.Error {}), Context )
declarationVisitor context (Config config) declaration =
let
declarationName =
Install.Library.getDeclarationName declaration

contextWithLastDeclarationRange =
case config.insertAt of
After previousDeclaration ->
if getDeclarationName declaration == previousDeclaration then
if Install.Library.getDeclarationName declaration == previousDeclaration then
{ context | lastDeclarationRange = Node.range declaration }

else
Expand All @@ -132,49 +132,11 @@ declarationVisitor context (Config config) declaration =
AtEnd ->
{ context | lastDeclarationRange = Node.range declaration }
in
case Node.value declaration of
FunctionDeclaration function ->
let
name : String
name =
getDeclarationName declaration

isInCorrectModule =
Install.Library.isInCorrectModule config.moduleName context

resources =
{ lookupTable = context.lookupTable, inferredConstants = ( Infer.empty, [] ) }

-- isNotImplemented returns True if the values of the current function expression and the replacement expression are different
isNotImplemented : Function -> { a | functionImplementation : String } -> Bool
isNotImplemented f confg =
Maybe.map2 (Normalize.compare resources)
(f.declaration |> Node.value |> .expression |> Just)
(Install.Library.getExpressionFromString context confg.functionImplementation)
== Just Normalize.ConfirmedEquality
|> not

isImplemented =
not (isNotImplemented function config)
in
if isImplemented then
( [], { contextWithLastDeclarationRange | appliedFix = True } )

else if name == config.functionName && isInCorrectModule && isNotImplemented function config then
replaceFunction { range = Node.range declaration, functionName = config.functionName, functionImplementation = config.functionImplementation } context

else
( [], contextWithLastDeclarationRange )
if declarationName == config.functionName then
( [], { context | appliedFix = True } )

_ ->
( [], contextWithLastDeclarationRange )


type alias FixConfig =
{ range : Range
, functionName : String
, functionImplementation : String
}
else
( [], contextWithLastDeclarationRange )


finalEvaluation : Config -> Context -> List (Rule.Error {})
Expand All @@ -186,15 +148,11 @@ finalEvaluation (Config config) context =
[]


replaceFunction : FixConfig -> Context -> ( List (Error {}), Context )
replaceFunction fixConfig context =
( [ Rule.errorWithFix
{ message = "Replace function \"" ++ fixConfig.functionName ++ "\"", details = [ "" ] }
fixConfig.range
[ Fix.replaceRangeBy fixConfig.range fixConfig.functionImplementation ]
]
, { context | appliedFix = True }
)
type alias FixConfig =
{ range : Range
, functionName : String
, functionImplementation : String
}


addFunction : FixConfig -> List (Error {})
Expand All @@ -204,26 +162,3 @@ addFunction fixConfig =
fixConfig.range
[ Fix.insertAt { row = fixConfig.range.end.row + 1, column = 0 } fixConfig.functionImplementation ]
]


getDeclarationName : Node Declaration -> String
getDeclarationName declaration =
let
getName declaration_ =
declaration_ |> .name >> Node.value
in
case Node.value declaration of
FunctionDeclaration function ->
getName (Node.value function.declaration)

AliasDeclaration alias_ ->
getName alias_

CustomTypeDeclaration customType ->
getName customType

PortDeclaration port_ ->
getName port_

_ ->
""
Loading

0 comments on commit fc62a8b

Please sign in to comment.