Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 6 additions & 12 deletions .github/agents/knowledge/design.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,15 @@
2. **`editorconfig-checker` deference**: `editorconfig-checker`
(binary: `ec`) runs on all files but skips file types owned
by active line-length-enforcing formatters (`cargo-fmt`,
`ruff-format`, `biome-format`, `prettier`). Implemented
`ruff-format`, `biome-format`, `rumdl`, `yaml-lint`). Implemented
via `.defer_to_formatters()` on the `editorconfig-checker`
entry. This avoids its `max_line_length` check conflicting
with formatter output.

3. **markdownlint + prettier on `*.md`**: Both checkers are
active when their tools are installed. They cover
different concerns (markdownlint: structural rules;
prettier: formatting). To avoid MD013 (line length)
conflicting with prettier's line wrapping, consuming
repos must disable MD013 in `.markdownlint.json`:

```json
{ "MD013": false }
```
3. **Rust-native docs/config stack**: Markdown is owned by
`rumdl`, YAML by `yaml-lint`, and JS/TS/JSON by `biome`.
This keeps ownership boundaries explicit and avoids the
old markdownlint/prettier overlap on `*.md`.

4. **Fix mode runs serially**: `runner.rs` runs checks in
parallel in check mode, but serially in fix mode to
Expand All @@ -43,6 +37,6 @@
`BUILTIN_EXCLUDES` slice of paths that are always removed
from the file list before any linter sees it. Currently
contains `.github/renovate-tracked-deps.json` (a
generated file that should never be linted by prettier,
generated file that should never be linted by `rumdl`,
ec, etc.). Add entries here — not in user-facing `exclude`
docs — when a file is managed by flint itself.
13 changes: 7 additions & 6 deletions .github/agents/knowledge/linters.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ Available builder modifiers:
| `.mise_tool(name)` | Look up availability under a different mise key (e.g. `rust` for `cargo-fmt`) |
| `.version_req(range)` | Restrict to a semver range (e.g. `">=1.0.0"`) |
| `.excludes(names)` | Skip files already owned by these active checks |
| `.slow()` | Mark as slow — skipped by `--fast-only` |
| `.slow()` | Mark as comprehensive-only and skipped by `--fast-only` |
| `.adaptive()` | Mark as comprehensive-only and relevance-gated in `--fast-only` |
| `.linter_config(file, flag)` | Inject a config flag when `FLINT_CONFIG_DIR/<file>` exists (see below) |

## Config File Injection (`.linter_config`)
Expand All @@ -43,11 +44,11 @@ If the file is absent the flag is silently omitted — native config discovery
remains in effect.

```rust
// Example: markdownlint accepts --config <path>
Check::file("markdownlint", "markdownlint {FILE}", &["*.md"])
.fix("markdownlint --fix {FILE}")
.linter_config(".markdownlint.json", "--config"),
// → markdownlint --config /repo/.github/config/.markdownlint.json <file>
// Example: rumdl accepts --config <path>
Check::file("rumdl", "rumdl check {FILE}", &["*.md"])
.fix("rumdl check --fix {FILE}")
.linter_config(".rumdl.toml", "--config"),
// → rumdl --config /repo/.github/config/.rumdl.toml check <file>
```

**When NOT to use it:**
Expand Down
32 changes: 0 additions & 32 deletions .github/config/super-linter.env

This file was deleted.

6 changes: 3 additions & 3 deletions .github/renovate-tracked-deps.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@
"mise.toml": {
"mise": [
"actionlint",
"biome",
"cargo:xmloxide",
"cargo:yaml-lint",
"dotnet",
"editorconfig-checker",
"github:google/google-java-format",
Expand All @@ -33,12 +35,10 @@
"hadolint",
"lychee",
"node",
"npm:@biomejs/biome",
"npm:markdownlint-cli2",
"npm:prettier",
"npm:renovate",
"pipx:codespell",
"pipx:ruff",
"rumdl",
"rust",
"shfmt"
]
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.idea
.mise.super-linter-*.toml
/target
.cache/
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,9 @@ Add the linting tools your project needs alongside the `flint` binary itself:
shellcheck = "v0.11.0"
"github:mvdan/sh" = "v3.13.1" # activates shfmt
actionlint = "1.7.10"
"npm:markdownlint-cli2" = "0.47.0"
"npm:prettier" = "3.5.0"
rumdl = "0.1.78"
"cargo:yaml-lint" = "0.1.0"
biome = "2.4.12"
rust = "1.87.0" # activates cargo-fmt + cargo-clippy
go = "1.24.0" # activates gofmt
lychee = "0.18.0" # activates links check
Expand Down Expand Up @@ -176,14 +177,14 @@ Click a name in the table below for details. See the
| [`ktlint`](docs/linters.md#ktlint) | Lint and format Kotlin code | yes |
| [`license-header`](docs/linters.md#license-header) | Check source files have the required license header | — |
| [`lychee`](docs/linters.md#lychee) | Check for broken links | — |
| [`markdownlint-cli2`](docs/linters.md#markdownlint-cli2) | Lint Markdown files for style and consistency | yes |
| [`prettier`](docs/linters.md#prettier) | Format Markdown and YAML files | yes |
| [`renovate-deps`](docs/linters.md#renovate-deps) | Verify Renovate dependency snapshot is up to date | yes |
| [`ruff`](docs/linters.md#ruff) | Lint Python code | yes |
| [`ruff-format`](docs/linters.md#ruff-format) | Format Python code | yes |
| [`rumdl`](docs/linters.md#rumdl) | Lint Markdown files for style and consistency | yes |
| [`shellcheck`](docs/linters.md#shellcheck) | Lint shell scripts for common mistakes | — |
| [`shfmt`](docs/linters.md#shfmt) | Format shell scripts | yes |
| [`xmllint`](docs/linters.md#xmllint) | Validate XML files are well-formed | — |
| [`yaml-lint`](docs/linters.md#yaml-lint) | Lint YAML files for style and consistency | yes |

<!-- registry-table-end -->
<!-- editorconfig-checker-enable -->
Expand Down
6 changes: 3 additions & 3 deletions docs/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ Every flag has an env var equivalent: `FLINT_FIX`, `FLINT_FULL`, `FLINT_FAST_ONL
expressed as the exact command to run:

```text
flint: 2 checks failed — flint run --fix prettier cargo-fmt | review: shellcheck
flint: 2 checks failed — flint run --fix rumdl cargo-fmt | review: shellcheck
```

**`--fix` output** — fixes what's fixable, then prints the full output of
Expand All @@ -61,7 +61,7 @@ Pass one or more linter names to run only those:

```bash
flint run shellcheck shfmt # run only shellcheck and shfmt
flint run --fix prettier # fix only prettier
flint run --fix rumdl # fix only Markdown issues
```

## `flint update`
Expand All @@ -71,7 +71,7 @@ tool keys with their modern equivalents, preserving the declared version. Run it
`flint run` reports an obsolete key error:

```text
flint: obsolete tool key in mise.toml: "npm:markdownlint-cli" (replaced by "npm:markdownlint-cli2")
flint: obsolete tool key in mise.toml: "github:mvdan/sh" (replaced by "shfmt")
Run `flint update` to apply the migration automatically.
```

Expand Down
75 changes: 43 additions & 32 deletions docs/linters.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ Every supported check, its config file (when applicable), and its scope. The
config injection for `biome` and `biome-format` is not yet implemented.

<!-- editorconfig-checker-disable -->
<!-- markdownlint-disable MD013 -->
<!-- linter-details-start -->
<!-- Generated. Run `UPDATE_README=1 cargo test readme_linter_table_in_sync` to regenerate. -->

## `actionlint`

| | |
Expand Down Expand Up @@ -176,28 +176,6 @@ config = ".github/config/lychee.toml"
check_all_local = true
```

## `markdownlint-cli2`

| | |
| ----------- | --------------------------------------------- |
| Description | Lint Markdown files for style and consistency |
| Fix | yes |
| Binary | `markdownlint-cli2` |
| Scope | [file](#scopes) |
| Patterns | `*.md` |
| Config | `.markdownlint.jsonc` |

## `prettier`

| | |
| ----------- | ------------------------------ |
| Description | Format Markdown and YAML files |
| Fix | yes |
| Binary | `prettier` |
| Scope | [files](#scopes) |
| Patterns | `*.md *.yml *.yaml` |
| Config | `.prettierrc` |

## `renovate-deps`

| | |
Expand All @@ -207,6 +185,7 @@ check_all_local = true
| Binary | `renovate` |
| Scope | [special](#scopes) |
| Patterns | `renovate.json renovate.json5 .github/renovate.json .github/renovate.json5 .renovaterc .renovaterc.json .renovaterc.json5` |
| Run policy | adaptive — runs in `--fast-only` only when relevant |

Verifies `.github/renovate-tracked-deps.json` is up to date by running Renovate locally and comparing its output against the committed snapshot. Requires `renovate` in `[tools]`.

Expand Down Expand Up @@ -241,6 +220,17 @@ exclude_managers = ["github-actions", "github-runners"]
| Patterns | `*.py` |
| Config | `ruff.toml` |

## `rumdl`

| | |
| ----------- | --------------------------------------------- |
| Description | Lint Markdown files for style and consistency |
| Fix | yes |
| Binary | `rumdl` |
| Scope | [file](#scopes) |
| Patterns | `*.md` |
| Config | `.rumdl.toml` |

## `shellcheck`

| | |
Expand Down Expand Up @@ -272,26 +262,47 @@ exclude_managers = ["github-actions", "github-runners"]
| Scope | [files](#scopes) |
| Patterns | `*.xml` |

## `yaml-lint`

| | |
| ----------- | ----------------------------------------- |
| Description | Lint YAML files for style and consistency |
| Fix | yes |
| Binary | `yaml-lint` |
| Scope | [files](#scopes) |
| Patterns | `*.yml *.yaml` |
| Config | `.yamllint.yml` |

<!-- linter-details-end -->
<!-- markdownlint-enable MD013 -->
<!-- editorconfig-checker-enable -->

## Scopes

- `file` — invoked once per matched file
- `files` — invoked once with all matched files as args; only changed files are passed
- `files` — invoked once with all matched files as args; only changed files are
passed
- `project` — invoked once with no file args; for checks with patterns set
(e.g. `cargo-clippy`), skipped entirely if no matching files changed, but runs on
the whole project when it does run. `golangci-lint` is the exception — it uses
(e.g. `cargo-clippy`), skipped entirely if no matching files changed, but
runs on the whole project when it does run. `golangci-lint` is the
exception — it uses
`--new-from-rev` to scope analysis to changed code even within the project run.

Checks tagged slow in the registry are skipped by `--fast-only`. Use
`--fast-only` for local/pre-push feedback and the full set in CI. (No
builtin is currently marked slow, but the mechanism is preserved.)
Checks use one of three run policies:

- `fast` — always runs, including in `--fast-only`
- `slow` — skipped by `--fast-only`
- `adaptive` — runs in `--fast-only` only when the changed files are relevant

Use `--fast-only` for local/pre-push feedback and the full set in CI.

**`editorconfig-checker` defers to formatters**: `editorconfig-checker` runs on all files, but
**`editorconfig-checker` defers to formatters**: `editorconfig-checker` runs on
all files, but
automatically skips file types owned by an active line-length-enforcing
formatter. When `cargo-fmt`, `ruff-format`, `biome-format`, or `prettier`
are active, their file types are excluded from `editorconfig-checker` — those formatters
formatter. When `cargo-fmt`, `ruff-format`, `biome-format`, `rumdl`, or
`yaml-lint`
are active, their file types are excluded from `editorconfig-checker` — those
formatters
already enforce line length and would conflict with `editorconfig-checker`'s
`max_line_length` editorconfig check. If none of those formatters are
installed, `editorconfig-checker` checks those files itself.
2 changes: 1 addition & 1 deletion docs/why.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,4 @@ use everywhere" promise of mise. Container startup also adds latency to every ru

5. **Autofix where possible** — `--fix` checks first, fixes what's fixable,
reports what needs review. Fix mode runs serially to avoid concurrent writes.
Pass specific linter names to limit which fixers run (`flint run --fix prettier shfmt`).
Pass specific linter names to limit which fixers run (`flint run --fix rumdl shfmt`).
8 changes: 4 additions & 4 deletions mise.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,15 @@
FLINT_CONFIG_DIR = ".github/config"

[tools]
biome = "2.4.12"
lychee = "0.22.0"
node = "24.15.0"
"npm:renovate" = "43.129.0"
"github:koalaman/shellcheck" = "v0.11.0"
shfmt = "v3.13.1"
actionlint = "1.7.10"
editorconfig-checker = "v3.6.1"
"npm:markdownlint-cli2" = "0.22.0"
"npm:prettier" = "3.8.3"
"npm:@biomejs/biome" = "2.4.12"
"cargo:yaml-lint" = "0.1.0"
"rumdl" = "0.1.78"
"pipx:ruff" = "0.15.11"
"pipx:codespell" = "2.4.2"
rust = { version = "1.95.0", components = "clippy,rustfmt" }
Expand All @@ -24,6 +23,7 @@ dotnet = "10.0.201"
"cargo:xmloxide" = "0.4.1"
golangci-lint = "2.11.4"
"github:google/google-java-format" = "1.35.0"
node = "24.15.0"

[tasks."setup:update-super-linter-versions"]
description = "Generate super-linter version mapping from the super-linter repo"
Expand Down
19 changes: 19 additions & 0 deletions src/files.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,5 +171,24 @@ fn filter_names(
.filter(|name| !BUILTIN_EXCLUDES.contains(&name.as_str()))
.filter(|name| !exclude.is_match(name))
.map(|name| project_root.join(name))
.filter(|path| path.exists())
.collect()
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn filter_names_skips_deleted_worktree_paths() {
let tmp = tempfile::TempDir::new().unwrap();
std::fs::write(tmp.path().join("present.md"), "ok\n").unwrap();
let names = ["missing.md".to_string(), "present.md".to_string()]
.into_iter()
.collect();

let files = filter_names(tmp.path(), &GlobSetBuilder::new().build().unwrap(), names);

assert_eq!(files, vec![tmp.path().join("present.md")]);
}
}
Loading
Loading