Skip to content

feat: add --fix flag for auto-fixing violations #385

Description

@shinagawa-web

Overview

Add a `--fix` flag that automatically repairs auto-fixable violations in Markdown files in-place.

Problem

gomarklint currently only detects and reports violations — users must fix them manually. Many violations follow deterministic patterns that can be repaired automatically (e.g., missing blank lines around fences, bare URLs, trailing punctuation in headings).

Design

Fix representation

Each `LintError` optionally carries a `Fix` describing how to repair the violation:

```go
type Fix struct {
StartLine int // first affected line (1-indexed)
EndLine int // last affected line (inclusive); == StartLine for single-line
Lines []string // replacement lines (nil = delete the range)
}
```

Rules that can produce a fix attach it to the `LintError` they return. Rules that cannot fix a violation leave `Fix` nil.

Application order

Fixes are applied from the bottom of the file upward (descending line order) so that insertions and deletions on earlier lines do not shift the line numbers of later fixes.

CLI

```
gomarklint --fix [files...]
```

Exits 0 when all violations were fixed (or there were none). Exits non-zero if any unfixable violations remain after applying fixes.

Idempotency

Running `--fix` twice must produce identical output.

Fixable rules

Rule Fix
`final-blank-line` Append a newline at end of file
`no-hard-tabs` Replace `\t` with spaces
`no-bare-urls` Wrap in angle brackets: ``
`no-setext-headings` Convert setext heading to ATX (`#` / `##`)
`no-multiple-blank-lines` Collapse consecutive blank lines to one
`blanks-around-fences` Insert / delete blank lines around code fences
`blanks-around-headings` Insert / delete blank lines around headings
`blanks-around-lists` Insert / delete blank lines around lists
`no-trailing-punctuation` Strip trailing punctuation from heading text
`consistent-code-fence` Normalize all fences to the file's first style
`consistent-emphasis-style` Normalize `*` / `_` to the file's first style
`consistent-list-marker` Normalize `-` / `*` / `+` to the file's first style
`max-line-length` Hard-wrap prose lines at word boundaries (skip code blocks and bare URLs)

Not auto-fixable

Rule Reason
`single-h1` Cannot decide which H1 to keep
`duplicate-heading` Cannot decide which to rename
`empty-alt-text` Cannot generate meaningful alt text
`no-empty-links` Cannot supply a URL
`fenced-code-language` Cannot guess the language
`external-link` Cannot repair broken URLs
`link-fragments` Cannot repair broken anchors
`heading-level` Structural change — too risky to automate
`no-emphasis-as-heading` Conversion is ambiguous (heading level unknown)
`unclosed-code-block` Cannot determine where to close

Open questions

  • Should `--fix` also print remaining (unfixable) violations, or stay silent on success?
  • For `no-hard-tabs`: hard-code 4 spaces per tab, or add a config option?
  • Add `--fix-dry-run` to preview changes without writing?

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions