Skip to content

Add oxfmt for JS, CSS, JSON and YAML, with Jinja masking for templates - #356

Merged
cboos merged 2 commits into
mainfrom
dev/oxfmt
Oct 8, 2026
Merged

cboos merged 2 commits into
mainfrom
dev/oxfmt

Conversation

@cboos

@cboos cboos commented Oct 8, 2026 •

Copy link
Copy Markdown
Collaborator

This adds a formatter for the JavaScript, CSS, JSON and YAML in the repo — oxfmt, oxlint's sibling — without running it yet. It is the first of three PRs, so the approach can be agreed on before anything is reformatted.

What's in it

  • oxfmt 0.69.0 in the optional js group, next to oxlint. It is a native binary from PyPI: no Node. The version is pinned exactly, because its output changes between releases.

  • .oxfmtrc.json: width 120 and a 4-space indent with single quotes in JS, close to how the files are written today, plus 2-space JSON and YAML. Its ignorePatterns leave out, each with a comment saying why:

    • Markdown and TOML;
    • test data, snapshots and generated output;
    • the two Pygments sheets, which scripts/generate_minimal_pygments_css.py reads line by line.
  • scripts/fmt_templates.py for the five template components that hold Jinja (an {% include %} or a {# comment #}), which no JS or CSS parser accepts. The script:

    1. masks each Jinja construct as a /* jinja:N */ comment, which is valid in both languages;
    2. formats the masked copy in a staging directory;
    3. puts each construct back verbatim, at its original column.

    A construct that shares a line with code is refused rather than guessed at. Files are found by their content, and a unit test checks that each one is also in ignorePatterns.

  • just fmt-js formats and just fmt-check checks. Neither is part of just ci or CI yet.

  • CONTRIBUTING: a "Formatting JS, CSS, JSON and YAML" section.

Why not TOML

oxfmt collapses multi-line TOML arrays and squashes aligned comments. Worse, uv add writes pyproject.toml's dependency groups back out multi-line, so the formatter and uv would undo each other's work.

Planned impact (PRs 2 and 3)

Both follow only if you agree with the approach here.

PR 2 reformats the tree in one commit, together with the regenerated HTML snapshot. The numbers are from a trial run on a copy of the tree:

files lines notes
JS (components/**/*.js) 10 +3004/−2486 +745/−227 with -w: most of it is dropping the 8–16-space base indent the files carry. minimal_dag.js alone is +2255/−1842
CSS 13 +515/−162
JSON (.vscode, .claude) 2 +2/−2
YAML (CI workflows) 2 +92/−92 the sequence indent of ci.yml, and [ main ] becomes [main]
HTML snapshot (.ambr) 1 +13530/−9304 changes only inside <style>/<script>

Every change was checked for meaning:

  • JS: acorn ASTs are equal for every file, the Jinja ones included.
  • CSS: equal once quotes, hex case and .5/0.5 are normalized.
  • YAML: yaml.safe_load gives equal results, with comments, anchors and block scalars kept.
  • JSON: parses equal.

With <style> and <script> stripped, the snapshot is identical before and after, so no page markup changes. oxlint reports nothing, and the browser suite passes on the formatted tree. The component sources shrink by 9.6 KB in all (2%), from the dropped indent.

PR 3 adds PR 2's commit on main to a new .git-blame-ignore-revs, so git blame skips it (GitHub's blame view reads that file too), and turns just fmt-check on in just ci and in CI's primary job.

The reformat and the blame-ignore entry are separate PRs because a squash merge gives the reformat a new SHA, and only that SHA can be listed.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Chores
    • Added consistent formatting checks for JavaScript, CSS, JSON, and YAML, including component files that contain templates.
    • Added commands to apply formatting and check for formatting issues.
  • Documentation
    • Added contributor guidance on running formatting checks, supported file coverage, and formatter updates.
  • Tests
    • Added checks to verify template formatting preserves template content and follows formatting configuration.

cboos and others added 2 commits October 8, 2026 19:07
oxfmt 0.69.0 (oxlint's sibling, a native binary from PyPI) joins the
optional `js` group. `.oxfmtrc.json` sets the style (width 120, 4-space
indent, single quotes in JS; 2-space JSON and YAML) and ignores Markdown,
TOML, data, generated files and the two Pygments sheets that
generate_minimal_pygments_css.py reads line by line.

Five template components hold Jinja ({% include %}, {# #}), which oxfmt
cannot parse. scripts/fmt_templates.py masks each construct as a
`/* jinja:N */` comment, formats the masked copy in a staging directory,
and restores the constructs verbatim; a construct sharing a line with code
is refused. `just fmt-js` formats, `just fmt-check` checks.

Machinery only: nothing is reformatted yet, and fmt-check is not part of
`just ci` or CI until the reformat lands.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Annotate the four untyped containers so the script is pyright-strict
clean, like lint_js.py. fmt-check now runs the template check even when
the plain oxfmt check fails, so one run lists every file to format.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 200b48f0-db46-4fb4-a10a-cda08b83ca43
📥 Commits

Reviewing files that changed from the base of the PR and between 6ad6110 and 8bfef70.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (6)
  • .oxfmtrc.json
  • CONTRIBUTING.md
  • justfile
  • pyproject.toml
  • scripts/fmt_templates.py
  • test/test_fmt_templates.py

Included review availability: This review used your included allowance. Your plan provides up to 4 included reviews per hour; 3 remain after this review.


📝 Walkthrough

Walkthrough

This change adds oxfmt configuration and commands for JS, CSS, JSON, and YAML. It adds a script that masks standalone Jinja constructs in component files, formats the masked files, then restores the constructs. Tests cover masking, restoration, and formatter ignore-pattern requirements.

Changes

Formatting workflow

Layer / File(s) Summary
Configure the formatter
.oxfmtrc.json, pyproject.toml
Adds oxfmt formatting defaults, file-specific overrides, ignore patterns, and the pinned oxfmt dependency.
Mask and restore Jinja constructs
scripts/fmt_templates.py, test/test_fmt_templates.py
Adds helpers that replace standalone Jinja constructs with placeholders and restore them after formatting. Tests cover round-tripping, mixed-content lines, and missing or duplicated placeholders.
Wire formatting commands
scripts/fmt_templates.py, justfile, CONTRIBUTING.md, test/test_fmt_templates.py
Adds content-based template discovery, formatter execution, and --check behavior. Adds fmt-js and fmt-check targets and documents their use and constraints. A repository-wide test checks that Jinja components are ignored by plain oxfmt and round-trip unchanged.

Priority: ⬇️ Low

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Feature

Suggested reviewers: daaain

Merge Risk: ⚪ Minimal · up to 8bfef

The formatting workflow is mergeable after normal checks. No actionable issue remains.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.57% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 14 functions across 2 files. (4 skipped: … Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding oxfmt for multiple file types and masking Jinja in templates.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

Docstring coverage is 28.57% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 14 functions across 2 files. (4 skipped: 4 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Warning

Some tools did not complete. Review the errors below.

🔧 Biome (2.5.14)
.oxfmtrc.json

File contains syntax errors that prevent linting: Line 2: Expected a property but instead found '// oxfmt formats the JS, CSS, JSON and YAML; just fmt-js runs it, and'.; Line 6: End of file expected; Line 6: End of file expected; Line 6: End of file expected; Line 6: End of file expected; Line 7: End of file expected; Line 7: End of file expected; Line 7: End of file expected; Line 7: End of file expected; Line 8: End of file expected; Line 8: End of file expected; Line 8: End of file expected; Line 8: End of file expected; Line 9: End of file expected; Line 9: End of file expected; Line 9: End of file expected; Line 9: End of file expected; Line 10: End of file expected; Line 10: End of file expected; Line 10: End of file expected; Line 10: End of file expected; Line 11: End of file expected; Line 11: End of file expected; Line 11: End of file expected; Line 28: End of file expected; Line 29: End of file expected; Line 29: End of file expected; Line 30: Expected an array, an object,

... [truncated 283 characters] ...

35: End of file expected; Line 35: End of file expected; Line 36: End of file expected; Line 36: End of file expected; Line 37: End of file expected; Line 37: End of file expected; Line 38: End of file expected; Line 38: End of file expected; Line 39: End of file expected; Line 39: End of file expected; Line 40: End of file expected; Line 40: End of file expected; Line 43: End of file expected; Line 43: End of file expected; Line 44: End of file expected; Line 44: End of file expected; Line 46: End of file expected; Line 46: End of file expected; Line 47: End of file expected; Line 47: End of file expected; Line 48: End of file expected; Line 48: End of file expected; Line 49: End of file expected; Line 49: End of file expected; Line 50: End of file expected; Line 51: End of file expected


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@daaain

daaain commented Oct 8, 2026

Copy link
Copy Markdown
Owner

Love it, I'm all for oxfmt and oxlint, but agree on preventing yaml threshing

@cboos
cboos merged commit 2bf660e into main Oct 8, 2026
17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants