JavaScript API
Errors and checks
Handle errors and check templates before rendering.
When something goes wrong, render rejects with an error that says which template failed, where, and often how to fix it. render never returns half a page. Streaming works differently once part of the page is sent.
KilnRenderError: Unknown variable "titel" in pages/page.kiln at line 4, column 9. Did you mean "title"?
3 | {% block content %}
> 4 | <h1>{{ titel }}</h1>
| ^^^^^
5 | {% endblock %}
Error types
There are two kinds of error, both exported from @lucidkiln/core:
KilnSyntaxErrormeans a template couldn't be parsed. Itsdiagnosticslist every problem found, not just the first.KilnRenderErrormeans something failed while rendering, such as a missing variable or a function that threw.
import { KilnRenderError, KilnSyntaxError } from "@lucidkiln/core";
try {
return await kiln.render("pages/page", context);
} catch (error) {
if (error instanceof KilnRenderError && error.cause instanceof NotFound) {
return notFoundPage();
}
throw error;
}
A KilnRenderError has these properties:
| Property | Description |
|---|---|
code | A stable code, such as undefined-variable or limit-steps |
template, line, column | Where the error happened |
frame | The lines of source around the error, with a marker |
templateStack | The templates involved, from the page down to the one that failed |
cause | The original error, when your code threw: one of your functions, a getter in your data, your loader or your cache store |
Checking templates
check parses a template and returns its problems without rendering it. Pass the source as the second argument to check text that isn't saved yet, such as a template being edited in a CMS.
const diagnostics = await kiln.check("pages/home", draftSource);
for (const problem of diagnostics) {
console.log(`${problem.start.line}:${problem.start.column} ${problem.message}`);
}
As well as syntax errors, check looks at the other templates this one uses, when their names are written out in full rather than built at render time. It reports:
- A template that doesn't exist, unless the
includesaysignore missing. - An
includeorcomponentthat passes a prop the template doesn't declare, leaves out a required prop, or passes a written-out value of the wrong type, such asvariant: "danger". - A page with
propsthat extends a layout, when the layout needs a prop the page neither declares nor sets. The page only accepts its own props, so the layout could never get it. A page with a rest prop passes everything on, so it isn't reported. - A warning for a variable that a template with
propsreads but doesn't declare, set or get from globals. Layouts may read their page's variables, so declare those as props to remove the warning. - A warning, in the same templates, for a variable a macro reads that is neither one of its parameters nor a global. A macro can't see the template's variables.
It also warns about obsolete and inaccessible HTML, such as an image with no alt. See HTML checks.
Apart from missing templates and HTML checks, these checks follow strict mode, so they are skipped when strict is off. check only knows what a template is passed when it can see the call, so it doesn't report unknown variables in templates without props.
Each diagnostic has a code, a message, a severity of "error" or "warning", the template, and start and end positions with a line and column. Codes are stable, so tools can match them.
Analysing templates
analyze reports what a template uses: the variables it reads, its props, the variables it sets at its top level, the functions, filters and tests it calls, the templates it extends, includes or imports, and its blocks and macros. Use it to build tooling, or to work out which data a page depends on.
const analysis = await kiln.analyze("pages/post");
analysis.functions; // ["document"]
analysis.templates; // [{ kind: "extends", name: "layouts/base.kiln", ... }]
A name built at render time, such as "sections/" ~ section.type, is reported with a name of null.
Reading the markup
templateText returns a template's source with every tag, output and comment, and the content of verbatim, replaced by spaces. Line breaks stay, so every offset, line and column still points at the same place. Hand it to HTML tools, such as a validator or an HTML language service, so they see only the markup you wrote.
import { templateText } from "@lucidkiln/core";
templateText('<a href="{{ url }}">{% if new %}New{% endif %}</a>');
// '<a href=" "> New </a>'