Tooling
Formatting
Format templates from the command line or JavaScript.
Kiln has a formatter. It indents templates to match their structure and tidies the spacing inside tags, so every template in a project looks the same. It only changes whitespace that HTML ignores, so pages look the same before and after.
{# Before #}
<ul>
{% for post in posts %}
<li><a href="{{post.url}}">{{ post.title|upper }}</a></li>
{%endfor%}
</ul>
{# After #}
<ul>
{% for post in posts %}
<li><a href="{{ post.url }}">{{ post.title|upper }}</a></li>
{% endfor %}
</ul>
Running it
Run kiln format with the files or folders to format. Folders are searched for .kiln files.
npx kiln format templates
npx kiln format --check templates
- Without
--check, it rewrites files that need formatting and lists them. - With
--check, it changes nothing. It lists files that need formatting and exits with code 1 if there are any, which suits CI and pre-commit hooks. - Files and folders whose names start with a dot, and
node_modules, are skipped. So are files you name that aren't.kilnfiles, with a warning. - A file named twice, or named and also inside a folder you name, is formatted once.
- A path that doesn't exist is reported, and nothing is formatted. It exits with code 2.
- A file it can't format is reported, and the other files are still formatted. It exits with code 1.
- Indentation uses tabs. Pass
--spaces 2, or any other width, to indent with spaces.
Editors format through the language server. See Editor support.
What it changes
- Indentation. Each line is indented one step for every block tag and HTML element it sits inside.
- Spacing inside delimiters. One space inside
{{ }}and{% %}, and consistent spacing around operators, commas and colons. Trim markers such as{%-stay where they are. - Blank lines. Runs of blank lines become one.
- Line ends. Trailing spaces are removed, and line breaks become
\n.
It never joins or splits lines, rewraps text or reorders anything. A line break inside a tag stays, and the lines after it are indented one step further, or to match the brackets they are inside:
{% include "components/card" with {
title: post.title,
url: post.url,
} %}
Expressions
Inside delimiters, the formatter puts:
- one space either side of operators such as
==,+,~,??,=and=>, and of the?and:ina ? b : c. - no space around
.,?.,|and.., so you getpost.title|upperand1..10. - no space after
(or[or before)or], and none before a call's brackets:range(1, 3). - a space after a comma, and after the colon in
name: value, but not before them. - a space inside a hash's braces:
{ title: "Home" }. An empty hash stays{}. - no space after a minus or plus sign that makes a number negative or positive:
-1.
In props, | joins types, so it gets a space either side: variant: "primary" | "secondary". Strings are left exactly as written, quotes and all.
HTML
- Void elements such as
<br>and<img>, and self-closing tags, don't indent what follows. - An element that the next sibling closes, such as a
<li>without</li>, doesn't indent the next one. - Attributes on lines of their own are indented one step from their tag. A
>on a line of its own lines up with the tag. - An element opened inside a block tag counts only until that block, or that branch of an
if, ends. Templates that open an element in one branch and close it in another format without errors.
What it leaves alone
- Everything inside
<pre>,<textarea>,<xmp>,<listing>,<plaintext>andverbatim, because whitespace there shows on the page. - The body of a
setorapplywhose tag shares its line with other content. Kiln keeps its whitespace, so changing it would change the value. When the tag stands on its own line, Kiln removes the body's shared indentation, and the formatter indents it. - Whitespace and blank lines before the first content in the file and after the last. They show wherever the template is placed, such as an icon included inside a link. A file ends with a line break only if it did before, and a file of only whitespace is left as it is.
- Text inside attribute values.
- The lines inside
<script>,<style>, HTML comments and Kiln comments. They move with their opening line, but keep their own indentation relative to it.
Safety
The formatter only changes whitespace and the spacing inside delimiters. To prove it, it parses the template before and after, and compares the two. If anything differs apart from whitespace at the start and end of lines and runs of blank lines, it changes nothing and reports an error. Please open an issue if you see one.
Whitespace at the start of a line can still change in the output, because the formatter assumes the template writes HTML, where it doesn't show. If a template writes plain text, such as an email's text version, or is included inside a <pre> in another template, check the output after formatting.
A template with syntax errors isn't formatted. Fix the errors first. kiln format lists them.
From JavaScript
format comes from its own entry point, @lucidkiln/core/format. Like the rest of Kiln, it runs anywhere, including in the browser and on Workers.
import { format } from "@lucidkiln/core/format";
const formatted = format(source);
const withSpaces = format(source, { useTabs: false, tabWidth: 2 });
| Option | Description |
|---|---|
useTabs | Indent with tabs. Default true. |
tabWidth | Spaces per step when useTabs is false, and the width of a tab when lining up the lines of a script or comment. A whole number of at least 1. Default 4. |
range | Only format lines that overlap this range, given as { start, end } offsets. Editors use it to format a selection. |
format throws a KilnSyntaxError when the template has syntax errors, a KilnFormatError if the safety check fails, and a RangeError if tabWidth isn't a whole number of at least 1.
formatEdits takes the same arguments and returns the changes as a list of { start, end, text } edits, from first to last, instead of the new source. Editors apply them so the cursor and undo history stay put.