KogenCredo.CoreSupport.Ast (KogenCredo v0.1.0)

View Source

AST helpers shared by the KogenCredo checks.

Everything here is syntactic: no compilation, no type information.

Summary

Types

Dotted module name without Elixir. (MyApp.Repo is the string MyApp.Repo); Erlang modules keep a colon (:ets is the string :ets).

Functions

True for any variable node, including _ and _name.

The name of an existing module atom: Enum is "Enum", :rand is ":rand". Only for atoms that already exist (literals in this package's source, configuration, compiled metadata).

Parses a def/defp clause into {:ok, {kind, name, args, guard, body, meta}} or :error.

Rewrites a |> f(b) into f(a, b) everywhere so arities and argument positions are real.

Renders a list of module names the way inspect/1 renders the same list of module atoms ([MyApp.Shared, MyApp.Ports]), including its truncation of very long lists.

Joins alias segments ([:MyApp, :Billing], or a resolved prefix name followed by more segments) into a module name ("MyApp.Billing"). A leading Elixir segment is dropped.

Last expression of a block.

Module name from a literal alias node or an atom, else nil. Aliases are not expanded.

Every defmodule as {name_ast, meta, body} (nested modules included).

Shape of code: variables renamed by first appearance, metadata dropped, pipes expanded.

Variable names bound at the top of a parameter pattern (x, x = %{}, x \\ 1).

True when the atom's text starts with prefix (e.g. _ignored with "_").

Node count.

Flattens a literal or interpolated string into the text of its literal parts, or nil.

Removes nested defmodule nodes so per-module counts exclude inner modules.

True when name is prefix or lies under it (A.B.C is under A.B, A.BC is not).

True for a plain variable node that is not underscore-prefixed or a __MODULE__-style form.

Depth-first accumulate over every node.

Types

module_name()

@type module_name() :: String.t()

Dotted module name without Elixir. (MyApp.Repo is the string MyApp.Repo); Erlang modules keep a colon (:ets is the string :ets).

Functions

any_var?(arg1)

@spec any_var?(Macro.t()) :: boolean()

True for any variable node, including _ and _name.

atom_name(atom)

@spec atom_name(atom()) :: module_name()

The name of an existing module atom: Enum is "Enum", :rand is ":rand". Only for atoms that already exist (literals in this package's source, configuration, compiled metadata).

def_clause(arg1)

@spec def_clause(Macro.t()) :: {:ok, tuple()} | :error

Parses a def/defp clause into {:ok, {kind, name, args, guard, body, meta}} or :error.

expand_pipes(ast)

@spec expand_pipes(Macro.t()) :: Macro.t()

Rewrites a |> f(b) into f(a, b) everywhere so arities and argument positions are real.

inspect_names(names)

@spec inspect_names([module_name()]) :: String.t()

Renders a list of module names the way inspect/1 renders the same list of module atoms ([MyApp.Shared, MyApp.Ports]), including its truncation of very long lists.

join_name(parts)

@spec join_name([atom() | String.t()]) :: module_name()

Joins alias segments ([:MyApp, :Billing], or a resolved prefix name followed by more segments) into a module name ("MyApp.Billing"). A leading Elixir segment is dropped.

last_expr(other)

@spec last_expr(Macro.t()) :: Macro.t()

Last expression of a block.

module_name(atom)

@spec module_name(Macro.t()) :: module_name() | nil

Module name from a literal alias node or an atom, else nil. Aliases are not expanded.

modules(ast)

@spec modules(Macro.t()) :: [{Macro.t(), keyword(), Macro.t()}]

Every defmodule as {name_ast, meta, body} (nested modules included).

normalize(ast)

@spec normalize(Macro.t()) :: Macro.t()

Shape of code: variables renamed by first appearance, metadata dropped, pipes expanded.

param_names(v)

@spec param_names(Macro.t()) :: [atom()]

Variable names bound at the top of a parameter pattern (x, x = %{}, x \\ 1).

prefixed?(name, prefix)

@spec prefixed?(atom(), String.t()) :: boolean()

True when the atom's text starts with prefix (e.g. _ignored with "_").

size(ast)

@spec size(Macro.t()) :: non_neg_integer()

Node count.

string_text(s)

@spec string_text(Macro.t()) :: String.t() | nil

Flattens a literal or interpolated string into the text of its literal parts, or nil.

strip_modules(body)

@spec strip_modules(Macro.t()) :: Macro.t()

Removes nested defmodule nodes so per-module counts exclude inner modules.

under_name?(name, prefix)

@spec under_name?(module_name(), module_name()) :: boolean()

True when name is prefix or lies under it (A.B.C is under A.B, A.BC is not).

var?(arg1)

@spec var?(Macro.t()) :: boolean()

True for a plain variable node that is not underscore-prefixed or a __MODULE__-style form.

walk(ast, acc, fun)

@spec walk(Macro.t(), acc, (Macro.t(), acc -> acc)) :: acc when acc: term()

Depth-first accumulate over every node.