Add format command with prettier-rs and taplo integration#10
Open
Add format command with prettier-rs and taplo integration#10
Conversation
Introduce three new crates: - `lintel-cli-common`: shared CLI global options (--colors, --verbose, --log-level) - `prettier-rs`: Rust-native prettier implementation for JSON/JSONC/JSON5/YAML with config resolution, Wadler-Lindig document IR, and comment preservation - `lintel-format`: format command routing to prettier-rs or taplo by file type, with --check mode, --exclude patterns, and directory walking Update the lintel CLI to use CliGlobalOptions from lintel-cli-common across all subcommands, add `format`/`fmt` command, and wire up --log-level and --colors to tracing and miette respectively.
Replace needless raw string hashes and wildcard match arms with specific variant patterns.
…ication Import test fixture files from prettier/prettier repository to serve as a comprehensive test suite for verifying prettier-rs formatting correctness. Includes .prettierignore to prevent pre-commit hooks from reformatting fixtures.
…ness Add a comprehensive test harness (prettier_compat.rs, snapshot_parser.rs) that parses Jest snapshot files from prettier's test fixtures and validates our formatter output against prettier's expected output. Major improvements to YAML comment placement and indentation: - Track per-comment source line, column, and blank_line_before in Comment struct - Add depth-filtered comment collection to prevent child nodes from capturing parent-scope comments (collect_comments_between_lines_at_depth) - Use content_end instead of event_end for prev_end_line so comments skipped by depth filtering remain available for sibling nodes - Add comment_indent_capped to prevent trailing comments from rendering deeper than their structural context allows - Add comment and blank line support to nested sequence inline formatting - Fix double-counted blank lines with has_blank_line_immediately_before Test results: yaml/comment 4→14/17, yaml/spec 289→291/384, all 42 unit tests pass.
Split the monolithic prettier-rs/src/yaml.rs (3,412 lines) into a new crates/prettier-yaml/ crate with well-organized modules: - ast.rs: AST node types - parser.rs: saphyr event-based parser and AST builder - comments.rs: comment extraction from source text - printer.rs: main formatting dispatch and scalar formatting - print/block.rs: block scalar formatting - print/flow.rs: flow collection formatting - print/mapping_item.rs: block mapping formatting - print/misc.rs: indentation and comment helpers - utilities.rs: node inspection utilities prettier-rs now delegates YAML formatting to prettier-yaml via a thin options conversion layer. All test scores are preserved exactly.
Key fixes: - Implement prettier-ignore support (emit raw source for ignored nodes) - Fix proseWrap:always for block-folded scalars with explicit indent - Add splitWithSingleSpace for preserving multi-space runs in prose wrap - Fix sequence item blank_line_before with block scalars (marker_line) - Fix leading comment indentation for first entries vs subsequent - Fix block scalar body detection when tag is on separate line from indicator - Fix trim() vs trim_start() in folded block rewrap (trailing whitespace) - Improve explicit key handling with between-comments detection - Fix flow collection formatting with prettier-ignore and anchors - Add comment_indent_capped for flow collection comments
# Conflicts: # Cargo.lock # crates/lintel-cli-common/Cargo.toml # crates/lintel-cli-common/src/lib.rs # crates/lintel/Cargo.toml # crates/lintel/src/main.rs
Improve prettier-yaml compat from 682/712 (95.8%) to 698/712 (98.0%): - Fix flow sequence trailing comment attachment to last item per line - Fix closing_comment capture for outermost flow sequences only - Track block scalar body end for accurate comment positioning - Restore comment_indent_capped for mapping trailing_comments - Fix clippy warnings across prettier-yaml and prettier-rs crates
- Add preserve_order feature to serde_json for correct key ordering - Add useTabs option parsing to snapshot parser - Add trailing newline normalization to snapshot parser (matching prettier-yaml) - Fall back to JSONC parser when JSON parsing fails (handles comments) - Fix clippy warnings in examples and tests
Add `has_explicit_braces` field to MappingNode, detected by checking
whether the saphyr MappingStart span has non-zero length (start != end
indicates explicit `{`). This reliably distinguishes:
- `{ &e e: f }` → explicit braces (MappingStart span covers `{`)
- `a: b` → implicit mapping (zero-length MappingStart span)
- `{ JSON: like }: adjacent` → outer mapping is implicit (no braces)
Use this field in format_flow_sequence_flat/broken to keep braces on
flow mappings that had explicit `{...}` in the source, fixing the
`various-location-of-anchors-in-flow-sequence` test cases.
Also tightens flow_source extraction to only set when has_explicit_braces
is true, avoiding false positives when a mapping key starts with `{`.
Use has_explicit_braces (span.start != span.end) to determine if a
mapping is flow-style, instead of checking source[span.start] == '{'.
The old check had false positives: when a block mapping's key is a
flow mapping like `{ first: Sammy }: value`, the outer mapping's
span.start coincides with the key's `{`, causing the block mapping
to be incorrectly treated as flow.
Fixes spec-example-6-12 where `{ first: Sammy, last: Sosa }:` was
converted from block to flow format.
Use group-min floor snapping for leading comments after scalar values to normalize off-grid comments (col 1→0 in spec-8-5). After collection values, use individual ceil-rounding to preserve scope-aligned comments (col 1→2 in end-comment.yml). Apply same heuristic to mapping trailing comments after block scalar values at top level.
…nuation (707/712 compat) Two fixes: - Collect trailing comments on flow collection opening brackets as key_trailing_comment (spec-6-1: `key: [ # comment` now renders as `key: # comment\n [...]`) - Preserve line structure for segments with backslash continuation in double-quoted strings under proseWrap:always (spec-7-5)
# Conflicts: # Cargo.lock # crates/lintel/Cargo.toml
…/712 compat) Only capture a trailing comment as key_trailing_comment when the flow collection opening bracket has no items on the same line. Previously, `key: [ item, # comment` would incorrectly steal the item's trailing comment as a key comment. Now checks the source line between the bracket and the # to verify there's no content.
Move JSON/JSONC/JSON5 formatting from prettier-rs into a standalone prettier-jsonc crate. Add support for JSON6 features (backtick strings, octal/binary numbers, numeric separators, sparse arrays, undefined), numeric key normalization, hex lowercasing, source breakpoint preservation, and forced trailing commas for array holes.
Moves config types and resolution logic into a standalone `prettier-config` crate that all formatters share. This eliminates duplicate ProseWrap enums and manual field-by-field config conversion between prettier-jsonc and prettier-yaml. Override merging now uses JSON Value merge instead of typed `apply_to()`. All compat tests pass (101/101 JSON, 702/712 YAML).
…coverage Split prettier-jsonc into three focused crates: - wadler-lindig: Doc IR + Wadler-Lindig pretty-printing algorithm - prettier-json5: standalone JSON5 formatter with hand-written parser - prettier-jsonc: now handles only JSON and JSONC formats Added json-test-suite snapshot (444 RFC 8259 compliance test cases) to both prettier-jsonc (248/296 json/jsonc entries pass) and prettier-json5 (144/148 json5 entries pass). The json5 fallback for Format::Json moved from prettier-jsonc to prettier-rs umbrella crate.
Implements markdown formatting using comrak for parsing and the shared wadler-lindig Doc IR for pretty-printing. Supports paragraphs with prose wrapping (always/never/preserve), ATX and setext headings, fenced and indented code blocks, ordered/unordered lists with alignment and renumbering, blockquotes, tables, emphasis, links, images, YAML frontmatter formatting, and CJK-aware wrapping. Extends wadler-lindig with Align(n) for fixed-space alignment and whitespace-only line trimming. Integrates into prettier-rs and lintel-format for .md/.markdown file support.
Adds language-specific formatting for fenced code blocks with supported info strings (json, jsonc, json5, yaml, yml, toml). Falls back to pass-through when the formatter fails or the language is unsupported. Makes compat tests CI-safe with an explicit KNOWN_FAILURES exclusion list that documents why each test fails. The harness now fails on unexpected failures (regressions) and stale exclusions (tests that start passing). Known failure categories: - Embedded CSS/JS/TS/Angular formatting (no formatters available) - JSON object collapsing differences vs prettier's JSON formatter - prettier-ignore semantics not implemented - Link reference definitions removed from AST by comrak - Link/image escape and alt text wrapping differences - Hard break + prose wrap interaction
- Add `<!-- prettier-ignore -->` support: skips formatting the next block node and outputs it as raw source (works in all contexts: top-level, blockquotes, list items) - Add `<!-- prettier-ignore-start/end -->` range support: outputs entire range as raw source (top-level only, matching prettier's behavior) - Fix wadler-lindig `fits()`: separate Hardline (returns true, line ends) from BreakParent (returns false, forces group to break). This was making BreakParent a no-op, improving JSONC with-comment 12→24/24 and JSON5 json 20→26/28 - Suppress blank lines between consecutive HTML blocks (prettier behavior) - Download prettier's markdown/ignore test fixtures (3/3 pass)
Adopt the KNOWN_FAILURES pattern (from prettier-markdown) across prettier-json5, prettier-jsonc, prettier-yaml, and prettier-rs. Each known failure is documented with a reason explaining why it differs from prettier's output. The test harness now asserts on both unexpected failures (must be added to KNOWN_FAILURES or fixed) and stale exclusions (must be removed when tests start passing), replacing the old PRETTIER_STRICT env var gating.
Move the duplicated snapshot parser and test harness code from 5 separate snapshot_parser.rs + prettier_compat.rs files into a shared prettier-test-harness crate. Each consumer now only contains its KNOWN_FAILURES list, a thin format closure, and #[test] functions. Reduces total test infrastructure from ~3000 lines (across 10 files) to ~1600 lines (5 slim compat files + 1 shared crate).
…ify deps - Move force_group_break and trim_trailing_whitespace to wadler-lindig - Delete dead prettier-jsonc json module and its serde deps - Remove duplicate test fixtures and compat tests from prettier-rs - Delete debug example and debug_spec_88_ast test - Hoist resolve_config call in lintel-format format_single_file - Unify taplo version via workspace dependency - Remove stale PrettierOptions/YamlFormatOptions type aliases - Add Cargo.toml metadata to all 8 prettier crates
Bug fixes: - Fix tab-width column tracking in wadler-lindig printer (pos was counting bytes instead of visual columns when using tab indentation) - Fix escaped quote handling in prettier-yaml flow source extraction (backslash-escaped double quotes inside flow scalars were prematurely closing the string) - Handle empty .prettierrc files gracefully (treat as "use all defaults" instead of erroring) Quick wins: - Strip UTF-8 BOM in prettier-jsonc and prettier-json5 formatters - Remove dead code: format_tag, line_preceded_by_blank, duplicate has_node_props, extern crate alloc, unused _base_value param - Remove unused tracing dependency from lintel-format - Add PartialEq/Eq derives to PrettierConfig - Fix json_merge doc comment (deep -> shallow) - Simplify identity match in lintel/src/main.rs - Add prettier-json5 fixtures to .prettierignore
Take higher dependency versions from master while keeping lintel-format dependency from the feature branch.
Furnish lintel-format, prettier-config, prettier-json5, prettier-jsonc, prettier-markdown, prettier-rs, prettier-test-harness, prettier-yaml, and wadler-lindig with descriptions, keywords, categories, READMEs, and #![doc] attributes.
Swap out the custom JSON/JSONC formatter (jsonc-parser + wadler-lindig doc IR) for biome's JSON formatter, reducing jsonc.rs from 712 to 60 lines (-871 net lines across the crate). Dependencies changed: - Removed: jsonc-parser, wadler-lindig - Added: biome_json_parser, biome_json_formatter, biome_formatter (0.5.7) - Pinned: biome_rowan, biome_parser, biome_diagnostics, biome_unicode_table to =0.5.7 to avoid cross-version incompatibilities Known behavioral changes vs the custom formatter: - Single-quoted strings rejected (biome requires double quotes) - Unquoted property keys rejected - \/ escape not preserved (stripped to /) - No number normalization (verbatim output) - Bracket spacing always enabled (0.5.7 limitation) Updated KNOWN_FAILURES: removed 46 stale exclusions that biome now handles correctly, added 11 new exclusions for the above limitations.
JSON5 is effectively dead — downloads are transitive from Babel and JSONC covers the only feature people actually use (comments). Remove the dedicated formatter and all JSON5-only test fixtures/known-failures to reduce maintenance surface.
Resolve conflicts in Cargo.toml (version bumps + lintel-format dep) and Cargo.lock (regenerated).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
lintel fmt/lintel formatcommand for formatting JSON, JSONC, JSON5, YAML, and TOML filesprettier-rscrate: Rust-native prettier implementation with Wadler-Lindig document IR, config resolution, and comment preservation for JSON/JSONC/JSON5/YAMLlintel-cli-commoncrate: shared CLI global options (--colors,--verbose,--log-level) reused across binarieslintel-formatcrate: format command with file routing to prettier-rs or taplo,--checkmode,--excludepatterns, and.gitignore-respecting directory walkingCliGlobalOptionsacross all subcommands and wires--log-levelto tracing and--colorsto mietteTest plan
cargo check --workspacecompiles cleanlycargo clippy --workspacepasses with no warningscargo test --workspace— 183 tests passcargo run -- fmt --helpshows help with global optionscargo run -- fmt .formats filescargo run -- fmt --check .check mode workscargo run -p lintel-format -- --helpstandalone binary works