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.
Summary
Functions
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.
Asserts equal counts of [ and ].
Asserts equal counts of ( and ).
Runs all C-relevant checks on the given content. Returns combined issue list.
Runs all Kotlin-relevant checks on the given content. Returns combined issue list (empty = clean).
Runs all Swift-relevant checks on the given content.
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.
Every external fun nativeFoo in MobBridge.kt must be a direct
member of object MobBridge — not just positionally somewhere inside
its braces, and not just present somewhere in the file.
Catches <%= / <% / %> left in rendered output. Indicates a
malformed template tag or a render-pipeline misconfiguration that
emitted the literal text instead of evaluating it.
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.
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.
Types
Functions
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.
Asserts equal counts of [ and ].
Asserts equal counts of ( and ).
Runs all C-relevant checks on the given content. Returns combined issue list.
Runs all Kotlin-relevant checks on the given content. Returns combined issue list (empty = clean).
Runs all Swift-relevant checks on the given content.
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.
Every external fun nativeFoo in MobBridge.kt must be a direct
member of object MobBridge — not just positionally somewhere inside
its braces, and not just present somewhere in the file.
external_fun_jni_consistency/2 above only checks that Kotlin and C
agree on the native function's NAME; it can't tell which enclosing
class/object actually owns the Kotlin declaration. JNI resolves a
native method by its declaring class, and every generated JNI thunk
in this template is Java_<pkg>_MobBridge_nativeFoo — so a
nativeFoo declared on some OTHER object (e.g. a helper registry)
passes the name-consistency check cleanly and then throws
UnsatisfiedLinkError the first time it's actually called. This is
the check that would have caught MOB-98's JNI owner mismatch. Only
meaningful against MobBridge.kt's content — returns [] (nothing to
flag) if the content has no object MobBridge block at all.
Brace-depth aware, not just byte-position aware: external fun bar
inside a hypothetical object MobBridge { class Foo { external fun bar() } } sits at byte-position inside the span but is NOT a direct
member — JNI would need MobBridge$Foo, not MobBridge. Flagged the
same as if it were outside the span entirely.
Catches <%= / <% / %> left in rendered output. Indicates a
malformed template tag or a render-pipeline misconfiguration that
emitted the literal text instead of evaluating it.
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.
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.