Copyright (c) 2026 Michael Welter me@mikinho.com
A dedicated, lightning-fast linter and formatter for Squirrelly (.sqrl) templates, built specifically for the @ynode
Fastify ecosystem. Uses a tag-aware scanner to normalise spacing only inside {{ ... }} boundaries, leaving surrounding
HTML, CSS, and JS untouched.
- Strict Formatting: Enforces consistent spacing for helpers (
{{@,{{#), base brackets ({{,}}), raw outputs ({{{,}}}), and block closures ({{/). - Read-Only Linters: Fails CI pipelines seamlessly by returning exit code
1when files violate spacing norms. - Lightning Fast: Analyzes and natively formats files in sub-millisecond per-file times, with CLI timing metrics built-in.
- Quality of Life: Automatically ignores
node_modulesby default and presents beautiful, colorized error logs and success reports. - Auto-Repair: The
--fixoption seamlessly rewrites dirty files back to pristine format natively. - Fast-Glob Powered: Built-in
fast-globprocessing natively supports arbitrary inclusion and exclusion targeting.
npm install -D @ynode/sqrl-lintYou can use the linter either manually via npx or wire it directly into your package.json scripts block.
npx sqrl-lint "src/**/*.sqrl"If any files are formatted improperly, an error will be logged to stderr and the process will exit with a non-zero
code (see Exit Codes).
npx sqrl-lint "src/**/*.sqrl" --fixAutomatically targets syntax violations and corrects the text natively.
npx sqrl-lint "src/**/*.sqrl" --report jsonEmits a machine-readable JSON summary to stdout, suitable for CI/log parsers.
npx sqrl-lint "src/**/*.sqrl" --no-colorDisables ANSI color styling in text output.
npx sqrl-lint "src/**/*.sqrl" --diffShows a unified diff for each file that needs formatting, making CI failures actionable.
npx sqrl-lint "src/**/*.sqrl" --fix --concurrency 4Processes files with bounded parallelism for faster runs on large repositories.
cat src/views/home.sqrl | npx sqrl-lint --stdin --fixReads template content from stdin and writes the formatted output to stdout, making it ideal for editor "format on save"
integrations, shell pipelines, and git hooks. Use --stdin-filepath <path> to control the filename shown in error
messages and diffs.
npx sqrl-lint "src/**/*.sqrl" --quietSuppresses all output; only the exit code indicates the result.
npx sqrl-lint --versionPrints the installed package version and exits.
| Code | Meaning |
|---|---|
0 |
All files are formatted correctly, or --fix completed without error |
1 |
One or more files need formatting (check mode only) |
2 |
Operational error (I/O failure, invalid arguments, permission denied) |
The linter enforces consistent spacing inside Squirrelly tag boundaries. Rules are applied in order; the first match wins.
| Tag Type | Before | After |
|---|---|---|
| Helper / Macro open | {{@extends()}} |
{{@ extends() }} |
| Helper / Macro open | {{#if(user)}} |
{{# if(user) }} |
| Self-closing helper | {{@partial("x")/}} |
{{@ partial("x") /}} |
| Block close | {{/if}} |
{{/ if }} |
| Expression | {{name}} |
{{ name }} |
| Raw output (triple) | {{{rawHtml}}} |
{{{ rawHtml }}} |
Content outside {{ ... }} boundaries (HTML, CSS, JS) is never modified.
The package ships a Prettier plugin so you can format .sqrl files alongside the rest of your codebase:
{
"plugins": ["@ynode/sqrl-lint/prettier"]
}Once configured, prettier --write "**/*.sqrl" will apply the same tag-spacing rules used by the CLI.
Because this is a standard ecosystem plugin, you can easily wire it into your @ynode lint:guardrails group alongside
CSS and HTML linting:
"scripts": {
"lint:sqrl:format": "sqrl-lint \"src/**/*.sqrl\"",
"lint:sqrl:format:fix": "sqrl-lint \"src/**/*.sqrl\" --fix",
"lint:guardrails": "npm run lint:css && npm run lint:sqrl:format"
}The tag-aware scanner treats every {{ sequence as the start of a Squirrelly tag. There is currently no escape
mechanism for outputting a literal {{ or }} in your template without it being interpreted as tag syntax. If your
templates need to emit raw double-brace strings (for example, Vue.js or Handlebars snippets embedded in a Squirrelly
layout), wrap them in a Squirrelly raw helper or move the content to a partial that the linter does not process.