KogenCredo.SafetySupport (KogenCredo v0.1.0)
View SourceShared AST helpers for the safety checks and the diff rules.
Everything here is syntactic. Aliases are resolved from alias directives
found anywhere in the parsed tree (not by scope), and a Repo receiver is
recognised by name, never by compiling the project. That is a heuristic:
a Repo that is really something else, or a repo hidden behind a variable
or a macro, is invisible.
Repo receivers
repo_call/3 returns {function_name, args} when a call node looks like
Repo.all(...). A receiver counts as a repo when its alias-expanded module
either equals one of the configured :repo_modules (full names such as
MyApp.Repo) or its last segment is in :repo_names (default [:Repo]).
Summary
Functions
Collects alias directives into a map from the local name (first segment) to
the expanded segment list. Handles alias A.B, alias A.B, as: C and
alias A.{B, C}.
Counts nodes of ast matching pred.
Expands the first segment of an alias through aliases/1 output.
True when the expanded module segments equal the given module (e.g. Enum).
Strips metadata so two ASTs compare structurally.
Matches a source file path against glob-like patterns.
Splits a |> chain into its stages, left to right.
If node is Mod.fun(...), returns {expanded_module_segments, fun, args}.
Returns {fun, args} when node is a call on a repo receiver
(Repo.all(q)), else nil. Pipe-stage calls come in without the piped
first argument, so args may be one shorter than the real arity.
Repo functions that read rows.
True when receiver_ast is a module alias that denotes a repo.
Repo functions that write rows.
Default test-file patterns.
Types
Functions
Collects alias directives into a map from the local name (first segment) to
the expanded segment list. Handles alias A.B, alias A.B, as: C and
alias A.{B, C}.
@spec count(Macro.t(), (Macro.t() -> boolean())) :: non_neg_integer()
Counts nodes of ast matching pred.
Expands the first segment of an alias through aliases/1 output.
True when the expanded module segments equal the given module (e.g. Enum).
Strips metadata so two ASTs compare structurally.
Matches a source file path against glob-like patterns.
** matches any characters including /, * matches anything but /.
Patterns are matched against the path as a suffix, so lib/** also matches
/abs/project/lib/a.ex. An empty pattern list matches everything.
Splits a |> chain into its stages, left to right.
If node is Mod.fun(...), returns {expanded_module_segments, fun, args}.
Returns {fun, args} when node is a call on a repo receiver
(Repo.all(q)), else nil. Pipe-stage calls come in without the piped
first argument, so args may be one shorter than the real arity.
@spec repo_reads() :: [atom()]
Repo functions that read rows.
True when receiver_ast is a module alias that denotes a repo.
Options: :repo_names (last segments, default [:Repo]) and :repo_modules
(full module names, default []). Both take atoms or strings and are compared by name, so a
repo that is not loaded (or does not exist) is matched like any other.
@spec repo_writes() :: [atom()]
Repo functions that write rows.
@spec test_patterns() :: [String.t()]
Default test-file patterns.