Skip to content

Instantly share code, notes, and snippets.

@pete-murphy
Created December 11, 2023 22:34
Show Gist options
  • Save pete-murphy/5ead0bbea3bd2760caf5465adf80c3f5 to your computer and use it in GitHub Desktop.
Save pete-murphy/5ead0bbea3bd2760caf5465adf80c3f5 to your computer and use it in GitHub Desktop.
module ExtractImportGraph exposing (rule)
import Dict exposing (Dict)
import Elm.Syntax.Import exposing (Import)
import Elm.Syntax.ModuleName exposing (ModuleName)
import Elm.Syntax.Node as Node exposing (Node)
import Json.Encode as Encode
import Review.Project.Dependency as Dependency exposing (Dependency)
import Review.Rule as Rule exposing (Rule)
import Set exposing (Set)
rule : Rule
rule =
Rule.newProjectRuleSchema "ExtractImportGraph" initContext
|> Rule.withDependenciesProjectVisitor dependencyVisitor
|> Rule.withModuleVisitor moduleVisitor
|> Rule.withModuleContextUsingContextCreator
{ fromProjectToModule = fromProjectToModule
, fromModuleToProject = fromModuleToProject
, foldProjectContexts = foldProjectContexts
}
|> Rule.withDataExtractor dataExtractor
|> Rule.fromProjectRuleSchema
type alias ProjectContext =
{ imports : Dict ModuleName (List ModuleName)
, dependencyModules : Set ModuleName
}
type alias ModuleContext =
{ imports : List ModuleName
, dependencyModules : Set ModuleName
}
initContext : ProjectContext
initContext =
{ imports = Dict.empty
, dependencyModules = Set.empty
}
dependencyVisitor : Dict String Dependency -> ProjectContext -> ( List never, ProjectContext )
dependencyVisitor ds context =
Dict.values ds
|> List.concatMap Dependency.modules
|> List.map (String.split "." << .name)
|> Set.fromList
|> (\dModules -> ( [], { context | dependencyModules = dModules } ))
fromProjectToModule : Rule.ContextCreator ProjectContext ModuleContext
fromProjectToModule =
Rule.initContextCreator
(\projectContext ->
{ imports = []
, dependencyModules = projectContext.dependencyModules
}
)
fromModuleToProject : Rule.ContextCreator ModuleContext ProjectContext
fromModuleToProject =
Rule.initContextCreator
(\moduleName moduleContext ->
{ imports =
if not (List.isEmpty moduleContext.imports) then
moduleContext.imports
|> List.sort
|> Dict.singleton moduleName
else
Dict.empty
, dependencyModules = moduleContext.dependencyModules
}
)
|> Rule.withModuleName
foldProjectContexts : ProjectContext -> ProjectContext -> ProjectContext
foldProjectContexts newContext previousContext =
{ imports = Dict.union newContext.imports previousContext.imports
, dependencyModules = previousContext.dependencyModules
}
moduleVisitor :
Rule.ModuleRuleSchema {} ModuleContext
-> Rule.ModuleRuleSchema { hasAtLeastOneVisitor : () } ModuleContext
moduleVisitor schema =
schema
|> Rule.withImportVisitor importVisitor
dataExtractor : ProjectContext -> Encode.Value
dataExtractor projectContext =
Encode.object
[ ( "json", Encode.dict unwrapModuleName (Encode.list (unwrapModuleName >> Encode.string)) projectContext.imports )
]
unwrapModuleName : ModuleName -> String
unwrapModuleName =
String.join "."
importVisitor : Node Import -> ModuleContext -> ( List never, ModuleContext )
importVisitor imp context =
let
moduleName : ModuleName
moduleName =
Node.value imp
|> .moduleName
|> Node.value
in
( []
, { context
| imports = moduleName :: context.imports
}
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment