# `MixAffected.TestMap.Ast`
[🔗](https://github.com/mnox/mix_affected/blob/v0.1.0/lib/mix_affected/test_map/ast.ex#L1)

Reads a test file's source without compiling it: the modules it names
(the fallback when requiring the file fails) and its `affected_by` globs.

Alias resolution is file-wide, not lexical: `alias A.B` anywhere makes
every `B...` reference resolve to `A.B...`, and the unaliased reading is
kept too. Over-matching only selects more tests; it never drops one.

# `affected_by`

```elixir
@spec affected_by(String.t()) :: [String.t()]
```

The globs of every literal `@moduletag affected_by: ["glob", ...]` (also
among other tags in the same keyword list) and `@affected_by ["glob", ...]`
in the source; `[]` if none or unparseable.

# `defimpl?`

```elixir
@spec defimpl?(String.t()) :: boolean()
```

Whether the source defines a protocol impl (`defimpl`); `true` if it does not parse.

# `reads`

```elixir
@spec reads(String.t(), String.t(), [String.t()]) :: [String.t()]
```

The root-relative globs of the files a test reads from the repo itself
(a source-scanning guard reading `lib/**`, a doc test reading
`guides/*.md`, a Dockerfile test), found without compiling it: `[]` when
the source calls no file-reading or -listing function (`File.read!/1`,
`Path.wildcard/1`, ... or `@external_resource`), else a glob per path
literal anywhere in the file whose first segment is one of `top_level`
(the entries of the project root). A literal names a file or a directory,
so `"lib/app"` reads `lib/app` and `lib/app/**`; literal globs are kept.

`Path.join/1,2` of leading literals reads the joined path, `Path.expand/2`
and `Path.join/2` from `__DIR__` resolve against `test_file`'s directory,
`:code.priv_dir/1` is `priv`, `~w` words and the literal parts of an
interpolation (`"#{File.cwd!()}/guides/x.md"`) count as literals, other
sigils (regexes) do not.

`["**"]` (reads everything) when the reads cannot be pinned to the repo:
the source does not parse, it reads but no literal names a repo path, a
reading call's literal argument is not anchored at the root (`"."`,
`"**/*.ex"`, a relative `"fixtures/x.json"`), it lists the working
directory (`File.ls!/0`, `File.cwd!()`), a `__DIR__` path leaves the root,
or a literal glob does not compile (`MixAffected.Glob.compile/1`) or uses
a `[...]` character class `MixAffected.Glob` does not implement, so
selection never matches against it.

# `references`

```elixir
@spec references(String.t()) :: {:ok, [module()]} | :error
```

Every module the source names through an alias (`Foo.Bar`), resolving
`alias`, `alias ..., as:` and `alias Foo.{A, B}`. `:error` if it does not parse.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
