Diagnostics
Every error and warning zerolith emits is the same record, whether the runtime, the build, or the dev tools found it. Tools read it as data: the inspector shows it, a test asserts on it, and a listener can send it anywhere.
The record
| Field | Holds |
|---|---|
code |
A stable snake_case identifier, such as signal_written_inside_computed |
severity |
"error", "warning", "deprecation", or "info" |
cause |
One sentence naming what happened |
fix |
One sentence naming what to do about it |
url |
The code's documentation page, with the arguments in its query string |
args |
The values the message is about, such as the index and the type of a refused value, kept apart so a tool can write its own text |
location |
Where it points, when known: a file, line, and column in the source, or a selector for a node in the page |
suggestion |
A change that would resolve it: its description, its replacement text, and its applicability |
The applicability of a suggestion follows the grades rustc uses for its own: machine_applicable for a change a tool can make without a human reading it, maybe_incorrect and has_placeholders for one a person should check or complete, and unspecified otherwise.
Errors and warnings
| Severity | Delivered |
|---|---|
error |
Thrown as a ZerolithError, with the record on .diagnostic and a message that holds the code, the cause, the fix, and the URL |
warning, deprecation, and info |
Passed to every onDiagnostic listener, and listed in the inspector's Diagnostics tab; with no listener registered, the development build prints them to the console |
import { type ZerolithError, onDiagnostic, onDispose } from "zerolith";
// Warnings go to every listener, such as one that reports them:
const stop = onDiagnostic((diagnostic) => console.warn(diagnostic.code));
// Errors are thrown, carrying the same record:
try
{
onDispose(() => undefined); // outside any effect or scope
}
catch (error)
{
const { diagnostic } = error as ZerolithError;
console.log(diagnostic.code); // "on_dispose_outside_scope"
console.log(diagnostic.url); // ".../e/on_dispose_outside_scope"
}
stop();onDiagnostic returns the function that removes the listener.
Production builds
The code and the URL are public API and never change meaning. The message text is not: production builds ship an empty catalog, so cause and fix are empty strings and an error's message carries only the code and the URL, and the page behind the URL carries the explanation. A report from production is still actionable: the code names the problem, and the URL's query string carries its arguments.
Every code
Each code has a page at https://zerolith.dev/e/<code>/ with its cause and its fix, and the diagnostics index lists them all:
| Area | Codes |
|---|---|
| Signals and effects | signal_written_inside_computed, computed_cycle, effect_cycle, effect_loop, on_dispose_outside_scope |
| Templates and JSX | binding_in_tag_position, binding_in_comment, binding_in_raw_text, binding_not_single, script_in_template, template_unclosed_tag, unrenderable_value, event_handler_not_function, when_condition_function, each_items_function, each_key_undefined, each_key_duplicate, ref_not_assignable, template_frozen_read, template_not_prepared, jsx_not_lowered |
| Unsafe values | unsafe_property_binding, unsafe_attribute_binding, unsafe_url_blocked, css_value_not_allowed |
| Mounting and hydration | mount_target_missing, mount_component_uncalled, hydration_mismatch |
| Accessibility | image_without_alt, button_without_name, frame_without_title |
| Builds and versions | lazy_module_not_split, package_version_mismatch |
The command line's own checks, such as the findings of zerolith doctor, use codes of their own with the same cause and fix, printed in the terminal; the command line guide lists them.