ecko check
ecko check file.ecko
ecko check src/
Static analysis. It is also run automatically before every ecko file.ecko, where an error-level finding stops the program before its first line.
What it finds
Errors (these stop a run):
- Undefined names, with a did-you-mean suggestion for near misses.
- Wrong arity - calling a function with too few or too many arguments, including the built-ins.
- Use before definition at the top level.
- Non-exhaustive
match- a variant with no arm and no_. - Unknown struct or variant members.
- Unwrapped credentials - a credential read from the environment that does not flow into
secret(...). A name ending_KEY,_TOKEN,_SECRET,_APIKEY, or containingPASSWORD, is treated as one. Testing for presence is exempt, because it never reads the value:
Comparing against anything other thanif os.env("MY_API_KEY") != null { ... } # fine if is_null(os.env("MY_API_KEY")) { ... } # fine key = secret(os.env("MY_API_KEY")) # fine print(os.env("MY_API_KEY")) # flaggednullor""is a read, and still flagged -os.env("K_KEY") == "sk_live_x"is both a leak and a timing-unsafe comparison.
Warnings (reported, do not stop a run):
- Unused bindings, scope-aware, so a name used only inside a nested closure is not flagged.
- Unused imports.
- Shadowing a built-in, which is legal and occasionally deliberate - the
core.*escape hatch exists for exactly that case. - Deprecated syntax, with the migration (
ecko fmt) named. - A regex pattern written as a plain string.
re.test("^[A-Z]{3}$", s)looks like a regex and is not one:{3}is an interpolation hole, so the engine receives^[A-Z]3$and returns the wrong answer with no error. Write every pattern as a raw string,r"^[A-Z]{3}$".
Why a dynamic language gates on this
Ecko has no static type system, and adding one is not the plan. But the errors above are not type errors - they are definitely wrong regardless of types. A misspelled function name is never correct. A match missing a variant is never correct. Finding those before execution costs nothing and removes the most common way a script fails halfway through doing something it cannot undo.
The same analysis backs ecko lsp, so an editor shows these findings as you type.
Exit status
0 when there is nothing at error level. Non-zero otherwise. Warnings alone do not change the exit status, so ecko check is usable as a CI gate without forcing warning-free code.
Warnings are still printed, and a run that ends with warnings and no errors says so, so a 0 beside printed findings does not read as something being missed.
ecko check src/*.ecko # errors fail, warnings inform
ecko check --strict src/*.ecko # any finding fails
--strict is for a project that controls all of its own source and wants a clean board. Leave it off where a warning is a considered choice, since there is no way to silence a single finding.
One note on shadows-builtin: a package that exports get, set, push or find is naming its API, not making a mistake, so an exported function is exempt. The rule fires on a private helper that quietly displaced a builtin, which is the case worth hearing about.