deno
969f8cd8 - feat(fmt): infer config from .editorconfig (#34071)

Commit
7 days ago
feat(fmt): infer config from .editorconfig (#34071) ## Summary `deno fmt` now reads `.editorconfig` files and uses their settings to fill in fmt config fields that aren't otherwise set. This is the long-standing ask in #14717. Precedence (highest to lowest): 1. CLI flags (`--indent-width`, `--use-tabs`, ...) 2. `deno.json` `fmt` block 3. `.editorconfig` 4. Built-in defaults So `.editorconfig` only fills in fields the user hasn't already configured. Mappings: | `.editorconfig` | Deno fmt | | ----------------- | ----------------- | | `indent_style` | `useTabs` | | `indent_size` | `indentWidth` | | `tab_width` | `indentWidth` (fallback when `indent_style = tab` and `indent_size` is unset) | | `max_line_length` | `lineWidth` (ignored when `off`) | | `end_of_line` | `newLineKind` (`lf`/`crlf`) | `.editorconfig` resolution walks up from the file being formatted, parsing each file it finds, and stops at the first one with `root = true` (or at the filesystem root). Sections farther from the file are applied first so nearer files override them — matching the editorconfig spec. A small glob-to-regex translator handles the section header patterns: `*`, `**`, `**/`, `?`, `[abc]`, `[!abc]`, `{a,b,c}`, and `{n..m}`. The `**/foo.ts` form is treated as matching `foo.ts` at any depth including the root, matching gitignore-style user expectations. Parsed `.editorconfig` files are cached per-fmt-run via `EditorConfigCache`, so repeated lookups within a batch do not re-read or re-parse them. When a file is found, fmt logs `Found .editorconfig at <path> and using it` at `debug` level (visible with `-L debug`), once per discovered file. ### Incremental cache The fmt incremental cache is keyed on file content plus the batch-level fmt options. Because `.editorconfig` resolves per-file options that the batch-level key does not capture, those resolved options are folded into the cached hash for each file. Editing an `.editorconfig` value therefore invalidates the cached "already formatted" result even when the file body is unchanged, so a subsequent `--check` re-evaluates the file rather than returning a stale pass. Files not governed by any `.editorconfig` keep their existing cache entries and hash the file text as-is (no extra allocation). ### Test coverage - `cli/tools/fmt_editorconfig.rs` — 16 unit tests covering the parser, glob translation, and `apply_to`/precedence behavior. - `tests/specs/fmt/editorconfig` — 7 spec tests: - `infers_indent_size` — `.editorconfig` sets `indent_size = 4` and `fmt --check` passes on a 4-space file. - `infers_indent_size_negative` — `--indent-width=2` on the CLI overrides `.editorconfig`, so check fails for the same file. - `infers_use_tabs` — `indent_style = tab` in a subdirectory. - `infers_max_line_length` — `max_line_length = 200` lets a long line through that would otherwise wrap. - `deno_json_takes_precedence` — explicit `indentWidth: 2` in `deno.json` is not overridden by `.editorconfig`'s `indent_size = 4`. - `nested_overrides_parent` — a nearer non-root `.editorconfig` overrides a farther `root = true` one (exercises the walk-up and nearer-overrides-farther merge order). - `logs_at_debug` — `-L debug` prints the "found and using it" notice. ### Robustness The `.editorconfig` glob translator and value parser degrade gracefully on malformed or adversarial input rather than crashing: - Numeric range `{n..m}` expansion is bounded, so a pathological span such as `{1..1000000000}` does not build a giant regex; oversized ranges fall back to a literal that simply will not match. - Brace-nesting recursion is depth-capped, so deeply nested alternations like `{a,{a,{a,...}}}` cannot overflow the stack. - `indent_size` / `tab_width` / `max_line_length` parse with saturating integer conversion, clamping out-of-range values instead of silently dropping them. - Literal brace/bracket characters are escaped so unbalanced or degraded patterns still compile to a valid regex (a section that fails to compile is simply inert). Closes #14717 --------- Co-authored-by: lunadogbot <lunadogbot@users.noreply.github.com> Co-authored-by: Bartek Iwańczuk <biwanczuk@gmail.com>
Author
Parents
Loading