# `MobNew.Templates.Lint`
[🔗](https://github.com/genericjam/mob_new/blob/master/lib/mob_new/templates/lint.ex#L1)

Structural lints for generator-rendered native source files.

EEx templates can produce output that string-match generator tests
miss — duplicate imports, missing braces, orphan `<%=` tags. Real
compilation would catch them but is expensive (needs Android SDK
for Kotlin, Xcode for Swift, etc.). These lints are the cheap
middle layer: language-agnostic structural checks that run in
sub-second time on every `mix test`.

Each check returns a list of `issue` maps; the empty list means
no problems. Aggregate functions (`check_kotlin/1`, `check_c/1`,
`check_swift/1`) run all checks relevant to a language and return
the combined issue list.

Use:

    content = File.read!("path/to/MobBridge.kt")
    assert MobNew.Templates.Lint.check_kotlin(content) == []

Or for finer-grained reporting:

    content
    |> MobNew.Templates.Lint.check_kotlin()
    |> Enum.each(&IO.puts(&1.message))

Limits: structural only. A typo that produces still-balanced
braces (`x_funtion` instead of `x_function`) won't be caught.
See `mix mob.lint_templates` (planned) for a fuller battery that
also invokes `zig cc -fsyntax-only` on rendered C.

# `issue`

```elixir
@type issue() :: %{kind: atom(), message: String.t()}
```

# `balanced_braces`

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

Asserts equal counts of `{` and `}`. Naive — strings containing
literal braces would skew the count, but template C/Kotlin/Swift
output rarely has JSON or `printf("{...}")` strings.

# `balanced_brackets`

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

Asserts equal counts of `[` and `]`.

# `balanced_parens`

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

Asserts equal counts of `(` and `)`.

# `check_c`

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

Runs all C-relevant checks on the given content. Returns
combined issue list.

# `check_kotlin`

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

Runs all Kotlin-relevant checks on the given content. Returns
combined issue list (empty = clean).

# `check_swift`

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

Runs all Swift-relevant checks on the given content.

# `external_fun_jni_consistency`

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

For Kotlin/C native bridges: every `external fun nativeFoo(...)`
declared in the Kotlin file must have a matching
`Java_..._MobBridge_nativeFoo` JNI thunk in the C file. Catches
the "added the Kotlin extern but forgot the C side" regression
(or vice versa). Pass both file contents.

The Java-class infix between `Java_` and `_native...` is
package-dependent; we just check the suffix matches.

# `no_eex_leaks`

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

Catches `<%=` / `<%` / `%>` left in rendered output. Indicates a
malformed template tag or a render-pipeline misconfiguration that
emitted the literal text instead of evaluating it.

# `unique_kotlin_imports`

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

Asserts every `^import ` line in Kotlin output is unique. kotlinc
rejects duplicate imports with "Conflicting import" and the build
fails. This was the bug class that hit 0.3.2 → 0.3.4 twice.

# `unique_swift_imports`

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

Asserts every `^import ` line in Swift output is unique. swiftc
is more forgiving than kotlinc (warns rather than errors on
duplicates) but Apple's archive-validation pass surfaces them.

---

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