elm-review/tests/NoMissingTypeExpose.elm

748 lines
24 KiB
Elm
Raw Permalink Normal View History

2020-08-09 19:55:15 +03:00
module NoMissingTypeExpose exposing (rule)
{-|
@docs rule
-}
import Dict exposing (Dict)
import Elm.Module
import Elm.Project exposing (Project)
import Elm.Syntax.Declaration as Declaration exposing (Declaration)
import Elm.Syntax.Exposing as Exposing exposing (Exposing)
import Elm.Syntax.Import exposing (Import)
import Elm.Syntax.Module as Module exposing (Module)
import Elm.Syntax.ModuleName exposing (ModuleName)
import Elm.Syntax.Node as Node exposing (Node(..))
import Elm.Syntax.Range as Range
import Elm.Syntax.Signature exposing (Signature)
import Elm.Syntax.Type as Type
import Elm.Syntax.TypeAnnotation as TypeAnnotation exposing (TypeAnnotation)
import Review.Fix as Fix exposing (Fix)
2021-08-19 21:50:50 +03:00
import Review.ModuleNameLookupTable as ModuleNameLookupTable exposing (ModuleNameLookupTable)
2020-08-09 19:55:15 +03:00
import Review.Project.Dependency as Dependency exposing (Dependency)
import Review.Rule as Rule exposing (Rule)
import Set exposing (Set)
{-| Reports types that should be exposed but are not.
2021-08-19 21:50:50 +03:00
🔧 Running with `--fix` will automatically fix all the reported errors.
2020-08-09 19:55:15 +03:00
If a type is not exposed then it can be impossible to annotate functions or values that use them outside of the module. Affected types may be used in exposed function signatures, type aliases or other custom types.
import NoMissingTypeExpose
config : List Rule
config =
[ NoMissingTypeExpose.rule
]
## Fail
module Happiness exposing (happy, toString)
-- Type `Happiness` is private because it's not been exposed
type Happiness
= Happy
-- Private type `Happiness` used by exposed function `toString`
toString : Happiness -> String
toString happiness =
"Happy"
-- Private type `Happiness` used by exposed value `happy`
happy : Happiness
happy =
Happy
## Success
module Happiness exposing (Happiness, happy, toString)
type Happiness
= Happy
toString : Happiness -> String
toString happiness =
"Happy"
happy : Happiness
happy =
Happy
## Try it out
You can try this rule out by running the following command:
```bash
2020-09-22 20:40:30 +03:00
elm-review --template jfmengels/elm-review-common/example --rules NoMissingTypeExpose
2020-08-09 19:55:15 +03:00
```
-}
rule : Rule
rule =
Rule.newProjectRuleSchema "NoMissingTypeExpose" initialProjectContext
|> Rule.withElmJsonProjectVisitor elmJsonVisitor
|> Rule.withDirectDependenciesProjectVisitor dependencyDictVisitor
2020-08-09 19:55:15 +03:00
|> Rule.withModuleVisitor moduleVisitor
|> Rule.withContextFromImportedModules
2021-08-19 21:50:50 +03:00
|> Rule.withModuleContextUsingContextCreator
2020-08-09 19:55:15 +03:00
{ fromProjectToModule = fromProjectToModuleContext
, fromModuleToProject = fromModuleToProjectContext
, foldProjectContexts = foldProjectContexts
}
|> Rule.providesFixesForProjectRule
2020-08-09 19:55:15 +03:00
|> Rule.fromProjectRuleSchema
elmJsonVisitor : Maybe { a | project : Project } -> ProjectContext -> ( List nothing, ProjectContext )
elmJsonVisitor maybeProject context =
case maybeProject of
Just { project } ->
( []
, { context
| exposedModules = exposedModulesForElmJson project
}
)
Nothing ->
( [], context )
exposedModulesForElmJson : Project -> ExposedModules
exposedModulesForElmJson project =
case project of
Elm.Project.Package { exposed } ->
Package (elmProjectExposedList exposed)
Elm.Project.Application _ ->
Application
elmProjectExposedList : Elm.Project.Exposed -> Set String
elmProjectExposedList exposed =
case exposed of
Elm.Project.ExposedList list ->
List.foldl (Elm.Module.toString >> Set.insert) Set.empty list
Elm.Project.ExposedDict dict ->
List.foldl
(\( _, list ) acc ->
List.foldl (Elm.Module.toString >> Set.insert) acc list
)
Set.empty
dict
dependencyDictVisitor : Dict String Dependency -> ProjectContext -> ( List nothing, ProjectContext )
dependencyDictVisitor dependencies context =
( []
, { context
| exposedModules =
Dict.values dependencies
|> List.foldl exposedModulesForDependency context.exposedModules
}
)
exposedModulesForDependency : Dependency -> ExposedModules -> ExposedModules
exposedModulesForDependency dependency exposedModules =
Dependency.modules dependency
|> List.foldl (.name >> addExposedModule) exposedModules
moduleVisitor :
Rule.ModuleRuleSchema state ModuleContext
-> Rule.ModuleRuleSchema { state | hasAtLeastOneVisitor : () } ModuleContext
moduleVisitor schema =
schema
|> Rule.withModuleDefinitionVisitor moduleDefinitionVisitor
|> Rule.withImportVisitor importVisitor
|> Rule.withDeclarationListVisitor declarationListVisitor
|> Rule.withFinalModuleEvaluation finalEvaluation
moduleDefinitionVisitor : Node Module -> ModuleContext -> ( List nothing, ModuleContext )
moduleDefinitionVisitor (Node _ mod) context =
2021-08-19 21:50:50 +03:00
case context.moduleType of
2020-08-09 19:55:15 +03:00
InternalModule data ->
2021-08-19 21:50:50 +03:00
( []
, { lookupTable = context.lookupTable
, modulesFromTheProject = context.modulesFromTheProject
, moduleType = InternalModule { data | exposes = Module.exposingList mod }
}
)
2020-08-09 19:55:15 +03:00
ExposedModule data ->
( []
2021-08-19 21:50:50 +03:00
, { lookupTable = context.lookupTable
, modulesFromTheProject = context.modulesFromTheProject
, moduleType =
ExposedModule
{ data
| exposes = Module.exposingList mod
, exposingListStart = exposingListStartLocation (Module.exposingList mod)
}
}
2020-08-09 19:55:15 +03:00
)
exposingListStartLocation : Exposing -> Maybe Range.Location
exposingListStartLocation exposes =
case exposes of
Exposing.Explicit ((Node range _) :: _) ->
Just range.start
_ ->
Nothing
importVisitor : Node Import -> ModuleContext -> ( List nothing, ModuleContext )
2021-08-19 21:50:50 +03:00
importVisitor (Node _ { moduleName, moduleAlias }) context =
case context.moduleType of
2020-08-09 19:55:15 +03:00
InternalModule _ ->
( [], context )
ExposedModule data ->
( []
2021-08-19 21:50:50 +03:00
, { lookupTable = context.lookupTable
, modulesFromTheProject = context.modulesFromTheProject
, moduleType =
ExposedModule
{ data | exposedModules = exposedModulesForImportAlias (Node.value moduleName) moduleAlias data.exposedModules }
}
2020-08-09 19:55:15 +03:00
)
exposedModulesForImportAlias : ModuleName -> Maybe (Node ModuleName) -> ExposedModules -> ExposedModules
exposedModulesForImportAlias moduleName maybeModuleAlias exposedModules =
case maybeModuleAlias of
Just (Node _ moduleAlias) ->
addExposedModuleAlias moduleName
(String.join "." moduleAlias)
exposedModules
Nothing ->
exposedModules
declarationListVisitor : List (Node Declaration) -> ModuleContext -> ( List nothing, ModuleContext )
declarationListVisitor nodes context =
( []
2021-08-19 21:50:50 +03:00
, case context.moduleType of
2020-08-09 19:55:15 +03:00
InternalModule data ->
2021-08-19 21:50:50 +03:00
{ lookupTable = context.lookupTable
, modulesFromTheProject = context.modulesFromTheProject
, moduleType =
InternalModule
{ data
| exposedTypes =
exposedTypesForDeclarationList data.exposes nodes data.exposedTypes
}
}
2020-08-09 19:55:15 +03:00
ExposedModule data ->
2021-08-19 21:50:50 +03:00
{ lookupTable = context.lookupTable
, modulesFromTheProject = context.modulesFromTheProject
, moduleType =
ExposedModule
{ data
| declaredTypes = declaredTypesForDeclarationList nodes data.declaredTypes
, exposedSignatureTypes = exposedSignatureTypesForDeclarationList context.lookupTable data.exposes nodes data.exposedSignatureTypes
}
}
2020-08-09 19:55:15 +03:00
)
exposedTypesForDeclarationList : Exposing -> List (Node Declaration) -> Set String -> Set String
exposedTypesForDeclarationList exposes list exposedTypes =
List.foldl (exposedTypesForDeclaration exposes) exposedTypes list
exposedTypesForDeclaration : Exposing -> Node Declaration -> Set String -> Set String
exposedTypesForDeclaration exposes (Node _ declaration) exposedTypes =
case declaration of
Declaration.CustomTypeDeclaration { name } ->
rememberExposedType exposes name exposedTypes
Declaration.AliasDeclaration { name } ->
rememberExposedType exposes name exposedTypes
_ ->
exposedTypes
rememberExposedType : Exposing -> Node String -> Set String -> Set String
rememberExposedType exposes (Node _ name) exposedTypes =
if isTypeExposed exposes name then
Set.insert name exposedTypes
else
exposedTypes
declaredTypesForDeclarationList : List (Node Declaration) -> Set String -> Set String
declaredTypesForDeclarationList list declaredTypes =
List.foldl declaredTypesForDeclaration declaredTypes list
declaredTypesForDeclaration : Node Declaration -> Set String -> Set String
declaredTypesForDeclaration (Node _ declaration) declaredTypes =
case declaration of
Declaration.CustomTypeDeclaration { name } ->
rememberDeclaredType name declaredTypes
Declaration.AliasDeclaration { name } ->
rememberDeclaredType name declaredTypes
_ ->
declaredTypes
rememberDeclaredType : Node String -> Set String -> Set String
rememberDeclaredType (Node _ name) declaredTypes =
Set.insert name declaredTypes
exposedSignatureTypesForDeclarationList :
2021-08-19 21:50:50 +03:00
ModuleNameLookupTable
-> Exposing
2020-08-09 19:55:15 +03:00
-> List (Node Declaration)
-> List (Node ( ModuleName, String ))
-> List (Node ( ModuleName, String ))
2021-08-19 21:50:50 +03:00
exposedSignatureTypesForDeclarationList lookupTable exposes list exposedSignatureTypes =
List.foldl (exposedSignatureTypesForDeclaration lookupTable exposes) exposedSignatureTypes list
2020-08-09 19:55:15 +03:00
exposedSignatureTypesForDeclaration :
2021-08-19 21:50:50 +03:00
ModuleNameLookupTable
-> Exposing
2020-08-09 19:55:15 +03:00
-> Node Declaration
-> List (Node ( ModuleName, String ))
-> List (Node ( ModuleName, String ))
2021-08-19 21:50:50 +03:00
exposedSignatureTypesForDeclaration lookupTable exposes (Node _ declaration) exposedSignatureTypes =
2020-08-09 19:55:15 +03:00
case declaration of
Declaration.CustomTypeDeclaration { name, constructors } ->
2021-08-19 21:50:50 +03:00
exposedSignatureTypesForConstructorList lookupTable exposes name constructors exposedSignatureTypes
2020-08-09 19:55:15 +03:00
Declaration.AliasDeclaration { name, typeAnnotation } ->
2021-08-19 21:50:50 +03:00
exposedSignatureTypesForAlias lookupTable exposes name typeAnnotation exposedSignatureTypes
2020-08-09 19:55:15 +03:00
Declaration.FunctionDeclaration { signature } ->
2021-08-19 21:50:50 +03:00
exposedSignatureTypesForSignature lookupTable exposes signature exposedSignatureTypes
2020-08-09 19:55:15 +03:00
_ ->
exposedSignatureTypes
exposedSignatureTypesForConstructorList :
2021-08-19 21:50:50 +03:00
ModuleNameLookupTable
-> Exposing
2020-08-09 19:55:15 +03:00
-> Node String
-> List (Node Type.ValueConstructor)
-> List (Node ( ModuleName, String ))
-> List (Node ( ModuleName, String ))
2021-08-19 21:50:50 +03:00
exposedSignatureTypesForConstructorList lookupTable exposes (Node _ name) list exposedSignatureTypes =
2020-08-09 19:55:15 +03:00
if isTypeExposedOpen exposes name then
2021-08-19 21:50:50 +03:00
List.foldl (exposedSignatureTypesForConstructor lookupTable) exposedSignatureTypes list
2020-08-09 19:55:15 +03:00
else
exposedSignatureTypes
exposedSignatureTypesForConstructor :
2021-08-19 21:50:50 +03:00
ModuleNameLookupTable
-> Node Type.ValueConstructor
2020-08-09 19:55:15 +03:00
-> List (Node ( ModuleName, String ))
-> List (Node ( ModuleName, String ))
2021-08-19 21:50:50 +03:00
exposedSignatureTypesForConstructor lookupTable (Node _ { arguments }) exposedSignatureTypes =
exposedSignatureTypesForTypeAnnotationList lookupTable arguments exposedSignatureTypes
2020-08-09 19:55:15 +03:00
exposedSignatureTypesForAlias :
2021-08-19 21:50:50 +03:00
ModuleNameLookupTable
-> Exposing
2020-08-09 19:55:15 +03:00
-> Node String
-> Node TypeAnnotation
-> List (Node ( ModuleName, String ))
-> List (Node ( ModuleName, String ))
2021-08-19 21:50:50 +03:00
exposedSignatureTypesForAlias lookupTable exposes (Node _ name) typeAnnotation exposedSignatureTypes =
2020-08-09 19:55:15 +03:00
if isTypeExposed exposes name then
case typeAnnotation of
Node _ (TypeAnnotation.Typed _ list) ->
2021-08-19 21:50:50 +03:00
exposedSignatureTypesForTypeAnnotationList lookupTable list exposedSignatureTypes
2020-08-09 19:55:15 +03:00
_ ->
2021-08-19 21:50:50 +03:00
exposedSignatureTypesForTypeAnnotation lookupTable typeAnnotation exposedSignatureTypes
2020-08-09 19:55:15 +03:00
else
exposedSignatureTypes
exposedSignatureTypesForSignature :
2021-08-19 21:50:50 +03:00
ModuleNameLookupTable
-> Exposing
2020-08-09 19:55:15 +03:00
-> Maybe (Node Signature)
-> List (Node ( ModuleName, String ))
-> List (Node ( ModuleName, String ))
2021-08-19 21:50:50 +03:00
exposedSignatureTypesForSignature lookupTable exposes maybeSignature exposedSignatureTypes =
2020-08-09 19:55:15 +03:00
case maybeSignature of
Just (Node _ { name, typeAnnotation }) ->
if Exposing.exposesFunction (Node.value name) exposes then
2021-08-19 21:50:50 +03:00
exposedSignatureTypesForTypeAnnotation lookupTable typeAnnotation exposedSignatureTypes
2020-08-09 19:55:15 +03:00
else
exposedSignatureTypes
Nothing ->
exposedSignatureTypes
exposedSignatureTypesForRecordFieldList :
2021-08-19 21:50:50 +03:00
ModuleNameLookupTable
-> List (Node TypeAnnotation.RecordField)
2020-08-09 19:55:15 +03:00
-> List (Node ( ModuleName, String ))
-> List (Node ( ModuleName, String ))
2021-08-19 21:50:50 +03:00
exposedSignatureTypesForRecordFieldList lookupTable fields exposedSignatureTypes =
List.foldl (exposedSignatureTypesForRecordField lookupTable) exposedSignatureTypes fields
2020-08-09 19:55:15 +03:00
exposedSignatureTypesForRecordField :
2021-08-19 21:50:50 +03:00
ModuleNameLookupTable
-> Node TypeAnnotation.RecordField
2020-08-09 19:55:15 +03:00
-> List (Node ( ModuleName, String ))
-> List (Node ( ModuleName, String ))
2021-08-19 21:50:50 +03:00
exposedSignatureTypesForRecordField lookupTable (Node _ ( _, typeAnnotation )) exposedSignatureTypes =
exposedSignatureTypesForTypeAnnotation lookupTable typeAnnotation exposedSignatureTypes
2020-08-09 19:55:15 +03:00
exposedSignatureTypesForTypeAnnotationList :
2021-08-19 21:50:50 +03:00
ModuleNameLookupTable
-> List (Node TypeAnnotation)
2020-08-09 19:55:15 +03:00
-> List (Node ( ModuleName, String ))
-> List (Node ( ModuleName, String ))
2021-08-19 21:50:50 +03:00
exposedSignatureTypesForTypeAnnotationList lookupTable list exposedSignatureTypes =
List.foldl (exposedSignatureTypesForTypeAnnotation lookupTable) exposedSignatureTypes list
2020-08-09 19:55:15 +03:00
exposedSignatureTypesForTypeAnnotation :
2021-08-19 21:50:50 +03:00
ModuleNameLookupTable
-> Node TypeAnnotation
2020-08-09 19:55:15 +03:00
-> List (Node ( ModuleName, String ))
-> List (Node ( ModuleName, String ))
2021-08-19 21:50:50 +03:00
exposedSignatureTypesForTypeAnnotation lookupTable (Node _ typeAnnotation) exposedSignatureTypes =
2020-08-09 19:55:15 +03:00
case typeAnnotation of
TypeAnnotation.Typed name list ->
2021-08-19 21:50:50 +03:00
case ModuleNameLookupTable.moduleNameFor lookupTable name of
Just moduleName ->
(Node.map (\( _, typeName ) -> ( moduleName, typeName )) name :: exposedSignatureTypes)
|> exposedSignatureTypesForTypeAnnotationList lookupTable list
Nothing ->
(name :: exposedSignatureTypes)
|> exposedSignatureTypesForTypeAnnotationList lookupTable list
2020-08-09 19:55:15 +03:00
TypeAnnotation.FunctionTypeAnnotation left right ->
exposedSignatureTypes
2021-08-19 21:50:50 +03:00
|> exposedSignatureTypesForTypeAnnotation lookupTable left
|> exposedSignatureTypesForTypeAnnotation lookupTable right
2020-08-09 19:55:15 +03:00
TypeAnnotation.Tupled list ->
exposedSignatureTypes
2021-08-19 21:50:50 +03:00
|> exposedSignatureTypesForTypeAnnotationList lookupTable list
2020-08-09 19:55:15 +03:00
TypeAnnotation.Record fields ->
exposedSignatureTypes
2021-08-19 21:50:50 +03:00
|> exposedSignatureTypesForRecordFieldList lookupTable fields
2020-08-09 19:55:15 +03:00
TypeAnnotation.GenericRecord _ (Node _ fields) ->
exposedSignatureTypes
2021-08-19 21:50:50 +03:00
|> exposedSignatureTypesForRecordFieldList lookupTable fields
2020-08-09 19:55:15 +03:00
TypeAnnotation.Unit ->
exposedSignatureTypes
TypeAnnotation.GenericType _ ->
exposedSignatureTypes
finalEvaluation : ModuleContext -> List (Rule.Error {})
finalEvaluation context =
2021-08-19 21:50:50 +03:00
case context.moduleType of
2020-08-09 19:55:15 +03:00
InternalModule _ ->
[]
ExposedModule data ->
data.exposedSignatureTypes
2021-08-19 21:50:50 +03:00
|> List.filter (isTypePrivate context.modulesFromTheProject data)
2020-08-09 19:55:15 +03:00
|> List.map (makeError data.exposingListStart)
2021-08-19 21:50:50 +03:00
isTypePrivate : Set ModuleName -> ExposedModuleData -> Node ( ModuleName, String ) -> Bool
isTypePrivate modulesFromTheProject data (Node _ typeCall) =
2020-08-09 19:55:15 +03:00
case typeCall of
( [], name ) ->
2021-08-19 21:50:50 +03:00
Set.member name data.declaredTypes
&& not (isTypeExposed data.exposes name)
2020-08-09 19:55:15 +03:00
( moduleName, _ ) ->
2021-08-19 21:50:50 +03:00
Set.member moduleName modulesFromTheProject
&& not (isModuleExposed data.exposedModules moduleName)
2020-08-09 19:55:15 +03:00
isTypeExposed : Exposing -> String -> Bool
isTypeExposed exposes name =
case exposes of
Exposing.All _ ->
True
Exposing.Explicit list ->
List.any (isExposingATypeNamed name) list
isTypeExposedOpen : Exposing -> String -> Bool
isTypeExposedOpen exposes name =
case exposes of
Exposing.All _ ->
True
Exposing.Explicit list ->
List.any (isExposingAnOpenTypeNamed name) list
isExposingATypeNamed : String -> Node Exposing.TopLevelExpose -> Bool
isExposingATypeNamed needle (Node _ topLevelExpose) =
case topLevelExpose of
Exposing.InfixExpose _ ->
False
Exposing.FunctionExpose _ ->
False
Exposing.TypeOrAliasExpose name ->
name == needle
Exposing.TypeExpose { name } ->
name == needle
isExposingAnOpenTypeNamed : String -> Node Exposing.TopLevelExpose -> Bool
isExposingAnOpenTypeNamed needle (Node _ expose) =
case expose of
Exposing.TypeExpose { name, open } ->
name == needle && open /= Nothing
_ ->
False
addExposedModule : String -> ExposedModules -> ExposedModules
addExposedModule moduleName exposedModules =
case exposedModules of
Application ->
exposedModules
Package list ->
Package (Set.insert moduleName list)
addExposedModuleAlias : ModuleName -> String -> ExposedModules -> ExposedModules
addExposedModuleAlias moduleName moduleAlias exposedModules =
case exposedModules of
Application ->
exposedModules
Package list ->
if Set.member (String.join "." moduleName) list then
Package (Set.insert moduleAlias list)
else
exposedModules
isModuleExposed : ExposedModules -> ModuleName -> Bool
isModuleExposed exposedModules moduleName =
case exposedModules of
Application ->
True
Package list ->
Set.member (String.join "." moduleName) list
makeError : Maybe Range.Location -> Node ( ModuleName, String ) -> Rule.Error {}
makeError exposingListStart (Node range typeName) =
let
formattedName : String
formattedName =
formatTypeName typeName
in
Rule.errorWithFix
{ message = "Private type `" ++ formattedName ++ "` should be exposed"
, details =
[ "Users of this module will not be able to annotate a value of this type if they wanted to. You should expose this type or an alias of this type."
]
}
range
(exposeTypeFix exposingListStart typeName)
exposeTypeFix : Maybe Range.Location -> ( ModuleName, String ) -> List Fix
exposeTypeFix exposingListStart ( moduleName, name ) =
case ( exposingListStart, moduleName ) of
( Just start, [] ) ->
[ Fix.insertAt start (name ++ ", ") ]
_ ->
[]
formatTypeName : ( ModuleName, String ) -> String
formatTypeName ( moduleName, name ) =
String.join "." (moduleName ++ [ name ])
2021-08-19 21:50:50 +03:00
fromProjectToModuleContext : Rule.ContextCreator ProjectContext ModuleContext
fromProjectToModuleContext =
Rule.initContextCreator
(\lookupTable moduleName { exposedModules, moduleTypes } ->
2021-08-19 21:50:50 +03:00
let
moduleType : ModuleType
moduleType =
if isModuleExposed exposedModules moduleName then
2021-08-19 21:50:50 +03:00
initialExposedModuleType exposedModules moduleTypes
else
initialInternalModuleType
in
{ lookupTable = lookupTable
, modulesFromTheProject = Dict.keys moduleTypes |> Set.fromList
, moduleType = moduleType
}
)
|> Rule.withModuleNameLookupTable
|> Rule.withModuleName
2020-08-09 19:55:15 +03:00
2021-08-19 21:50:50 +03:00
fromModuleToProjectContext : Rule.ContextCreator ModuleContext ProjectContext
fromModuleToProjectContext =
Rule.initContextCreator
(\moduleName context ->
2021-08-19 21:50:50 +03:00
case context.moduleType of
InternalModule { exposedTypes } ->
{ initialProjectContext | moduleTypes = Dict.singleton moduleName exposedTypes }
2020-08-09 19:55:15 +03:00
2021-08-19 21:50:50 +03:00
ExposedModule _ ->
initialProjectContext
)
|> Rule.withModuleName
2020-08-09 19:55:15 +03:00
foldProjectContexts : ProjectContext -> ProjectContext -> ProjectContext
foldProjectContexts new old =
{ exposedModules = foldExposedModules new.exposedModules old.exposedModules
, moduleTypes = foldModuleTypes new.moduleTypes old.moduleTypes
}
foldExposedModules : ExposedModules -> ExposedModules -> ExposedModules
foldExposedModules newExposedModules oldExposedModules =
case ( oldExposedModules, newExposedModules ) of
( Application, Application ) ->
Application
( Application, Package _ ) ->
newExposedModules
( Package _, Application ) ->
oldExposedModules
( Package oldList, Package newList ) ->
2022-09-19 12:58:02 +03:00
Package (Set.union newList oldList)
2020-08-09 19:55:15 +03:00
foldModuleTypes : Dict ModuleName (Set String) -> Dict ModuleName (Set String) -> Dict ModuleName (Set String)
foldModuleTypes newModuleTypes oldModuleTypes =
Dict.foldl foldModuleTypesHelp newModuleTypes oldModuleTypes
foldModuleTypesHelp : ModuleName -> Set String -> Dict ModuleName (Set String) -> Dict ModuleName (Set String)
foldModuleTypesHelp moduleName newTypes moduleTypes =
case Dict.get moduleName moduleTypes of
Just oldTypes ->
Dict.insert moduleName (Set.union oldTypes newTypes) moduleTypes
Nothing ->
Dict.insert moduleName newTypes moduleTypes
initialProjectContext : ProjectContext
initialProjectContext =
{ exposedModules = Application
, moduleTypes = Dict.empty
}
2021-08-19 21:50:50 +03:00
initialInternalModuleType : ModuleType
initialInternalModuleType =
InternalModule
{ exposedTypes = Set.empty
, exposes = Exposing.Explicit []
}
2020-08-09 19:55:15 +03:00
2021-08-19 21:50:50 +03:00
initialExposedModuleType : ExposedModules -> Dict ModuleName (Set String) -> ModuleType
initialExposedModuleType exposedModules moduleTypes =
2020-08-09 19:55:15 +03:00
ExposedModule
{ declaredTypes = Set.empty
, exposedModules = exposedModules
, exposedSignatureTypes = []
, exposes = Exposing.Explicit []
, exposingListStart = Nothing
, moduleTypes = moduleTypes
}
type alias ProjectContext =
{ exposedModules : ExposedModules
, moduleTypes : Dict ModuleName (Set String)
}
2021-08-19 21:50:50 +03:00
type alias ModuleContext =
{ lookupTable : ModuleNameLookupTable
, modulesFromTheProject : Set ModuleName
, moduleType : ModuleType
}
type ModuleType
2020-08-09 19:55:15 +03:00
= InternalModule InternalModuleData
| ExposedModule ExposedModuleData
type alias InternalModuleData =
{ exposedTypes : Set String
, exposes : Exposing
}
type alias ExposedModuleData =
{ declaredTypes : Set String
, exposedModules : ExposedModules
, exposedSignatureTypes : List (Node ( ModuleName, String ))
, exposes : Exposing
, exposingListStart : Maybe Range.Location
, moduleTypes : Dict ModuleName (Set String)
}
type ExposedModules
= Application
| Package (Set String)