Current section

Files

Jump to
cleam src internal ast.gleam
Raw

src/internal/ast.gleam

import glance.{
type Module as AST, Definition, Discarded, Function, Import, Module as AST,
Named, UnqualifiedImport,
}
import gleam/dict
import gleam/list
import gleam/option.{None, Some}
import gleam/string
import internal/fs.{FileContent, FilesDir, ModuleFullName}
pub type FileAst {
FileAst(AST)
}
pub type AnotherFilesAst {
AnotherFilesAst(List(FileAst))
}
pub type ModuleName {
ModuleName(String)
}
type ImportedInfo {
ModuleImported(ModuleName)
ImportedAsAlias
}
pub type PublicMember {
PublicFun(String)
PublicConst(String)
PublicType(String)
}
pub fn files_ast(files_contents) {
use content <- list.map(files_contents)
let assert FileContent(content) = content
let assert Ok(ast) = glance.module(content)
FileAst(ast)
}
pub fn files_paths_with_ast(dir, test_dir) {
let file_paths = fs.files_paths(dir)
let file_paths_idx =
file_paths
|> list.index_map(fn(fp, i) { #(i, fp) })
|> dict.from_list
let flle_contents = fs.files_contents(file_paths)
let test_file_contents = case test_dir {
Some(FilesDir(_) as test_dir) -> {
fs.files_paths(test_dir)
|> fs.files_contents
}
None -> []
}
let ast_list =
flle_contents
|> list.append(test_file_contents)
|> files_ast
let ast_list_idx =
ast_list
|> list.index_map(fn(ast, i) { #(i, ast) })
|> dict.from_list
let indexes = list.range(0, list.length(ast_list) - 1)
use index <- list.filter_map(indexes)
case dict.get(file_paths_idx, index) {
Ok(file_path) -> {
let assert Ok(file_ast) = dict.get(ast_list_idx, index)
Ok(#(
file_path,
file_ast,
AnotherFilesAst(
list.filter_map(indexes, fn(idx) {
case idx == index {
True -> Error(Nil)
False -> dict.get(ast_list_idx, idx)
}
}),
),
))
}
Error(Nil) -> Error(Nil)
}
}
fn imported_info(imports, module_full_name, exported) {
list.filter_map(imports, fn(imp) {
case imp {
Definition(_, Import(import_name, module_alias, type_aliases, aliases))
if ModuleFullName(import_name) == module_full_name
->
case
aliases
|> list.append(type_aliases)
|> list.any(fn(alias) {
let assert UnqualifiedImport(imported, _) = alias
PublicFun(imported) == exported
|| PublicConst(imported) == exported
|| PublicType(imported) == exported
})
{
True -> Ok(ImportedAsAlias)
False ->
case module_alias {
Some(Named(alias)) -> Ok(ModuleImported(ModuleName(alias)))
Some(Discarded(_)) -> Error(Nil)
None ->
Ok(
ModuleImported(module_full_name_to_module_name(
module_full_name,
)),
)
}
}
_ -> Error(Nil)
}
})
}
pub fn is_pub_member_used(
files_ast,
pub_member_name,
module_full_name,
check_usage,
) {
let assert AnotherFilesAst(files_ast) = files_ast
use file_ast <- list.find_map(files_ast)
let assert FileAst(ast) = file_ast
let assert AST(imports, _, _, _, fns) = ast
let imported_info_list =
imported_info(imports, module_full_name, pub_member_name)
use imported_info <- list.find_map(imported_info_list)
case imported_info {
ImportedAsAlias -> Ok(Nil)
ModuleImported(module_name) -> {
use fun_def <- list.find_map(fns)
let assert Definition(_, Function(_, _, _, _, statements, _)) = fun_def
check_usage(statements, pub_member_name, module_name)
}
}
}
fn module_full_name_to_module_name(module_full_name) {
let assert ModuleFullName(module_full_name) = module_full_name
let assert Ok(module_name) =
string.split(module_full_name, "/")
|> list.last
ModuleName(module_name)
}