readability-cli 0.8.5__tar.gz → 0.8.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. {readability_cli-0.8.5 → readability_cli-0.8.6}/.github/workflows/ci.yml +1 -1
  2. {readability_cli-0.8.5 → readability_cli-0.8.6}/.github/workflows/publish.yml +2 -2
  3. {readability_cli-0.8.5 → readability_cli-0.8.6}/.github/workflows/update-guides.yml +2 -2
  4. readability_cli-0.8.6/.prettierignore +2 -0
  5. {readability_cli-0.8.5 → readability_cli-0.8.6}/PKG-INFO +88 -88
  6. {readability_cli-0.8.5 → readability_cli-0.8.6}/README.md +87 -87
  7. {readability_cli-0.8.5 → readability_cli-0.8.6}/pyproject.toml +1 -1
  8. {readability_cli-0.8.5 → readability_cli-0.8.6}/readability.py +30 -9
  9. {readability_cli-0.8.5 → readability_cli-0.8.6}/test_readability.py +84 -2
  10. {readability_cli-0.8.5 → readability_cli-0.8.6}/uv.lock +1 -1
  11. {readability_cli-0.8.5 → readability_cli-0.8.6}/.gitignore +0 -0
  12. {readability_cli-0.8.5 → readability_cli-0.8.6}/.python-version +0 -0
  13. {readability_cli-0.8.5 → readability_cli-0.8.6}/LICENSE +0 -0
  14. {readability_cli-0.8.5 → readability_cli-0.8.6}/configs/biome-default.json +0 -0
  15. {readability_cli-0.8.5 → readability_cli-0.8.6}/configs/pyrefly.toml +0 -0
  16. {readability_cli-0.8.5 → readability_cli-0.8.6}/configs/ruff.toml +0 -0
  17. {readability_cli-0.8.5 → readability_cli-0.8.6}/guides/Rguide.md +0 -0
  18. {readability_cli-0.8.5 → readability_cli-0.8.6}/guides/cppguide.md +0 -0
  19. {readability_cli-0.8.5 → readability_cli-0.8.6}/guides/csharp-style.md +0 -0
  20. {readability_cli-0.8.5 → readability_cli-0.8.6}/guides/docguide-style.md +0 -0
  21. {readability_cli-0.8.5 → readability_cli-0.8.6}/guides/go-guide.md +0 -0
  22. {readability_cli-0.8.5 → readability_cli-0.8.6}/guides/htmlcssguide.md +0 -0
  23. {readability_cli-0.8.5 → readability_cli-0.8.6}/guides/javaguide.md +0 -0
  24. {readability_cli-0.8.5 → readability_cli-0.8.6}/guides/jsguide.md +0 -0
  25. {readability_cli-0.8.5 → readability_cli-0.8.6}/guides/jsoncstyleguide.md +0 -0
  26. {readability_cli-0.8.5 → readability_cli-0.8.6}/guides/objcguide.md +0 -0
  27. {readability_cli-0.8.5 → readability_cli-0.8.6}/guides/pyguide.md +0 -0
  28. {readability_cli-0.8.5 → readability_cli-0.8.6}/guides/shellguide.md +0 -0
  29. {readability_cli-0.8.5 → readability_cli-0.8.6}/guides/tsguide.md +0 -0
  30. {readability_cli-0.8.5 → readability_cli-0.8.6}/guides/vimscriptguide.md +0 -0
@@ -16,7 +16,7 @@ jobs:
16
16
  - name: Set up Python
17
17
  uses: astral-sh/setup-uv@v7
18
18
  with:
19
- python-version: '3.14'
19
+ python-version: "3.14"
20
20
 
21
21
  - name: Install dependencies
22
22
  run: uv sync
@@ -2,7 +2,7 @@ name: Publish
2
2
 
3
3
  on:
4
4
  push:
5
- tags: ['v*']
5
+ tags: ["v*"]
6
6
 
7
7
  jobs:
8
8
  publish:
@@ -17,7 +17,7 @@ jobs:
17
17
  - name: Set up Python
18
18
  uses: astral-sh/setup-uv@v7
19
19
  with:
20
- python-version: '3.14'
20
+ python-version: "3.14"
21
21
 
22
22
  - name: Build distribution
23
23
  run: uv build
@@ -2,7 +2,7 @@ name: Update Style Guides
2
2
 
3
3
  on:
4
4
  schedule:
5
- - cron: '0 0 * * 0' # Weekly on Sunday at midnight
5
+ - cron: "0 0 * * 0" # Weekly on Sunday at midnight
6
6
  workflow_dispatch: # Ad-hoc trigger
7
7
 
8
8
  jobs:
@@ -30,4 +30,4 @@ jobs:
30
30
  uses: stefanzweifel/git-auto-commit-action@v5
31
31
  with:
32
32
  commit_message: "chore: update style guides [skip ci]"
33
- file_pattern: 'guides/*.md'
33
+ file_pattern: "guides/*.md"
@@ -0,0 +1,2 @@
1
+ # Synced upstream guides remain byte-for-byte faithful to their source.
2
+ guides/
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: readability-cli
3
- Version: 0.8.5
3
+ Version: 0.8.6
4
4
  Summary: A CLI to lint, format, and type-check code with Google-style defaults, and pull Google style guides in markdown format.
5
5
  Project-URL: Homepage, https://github.com/owahltinez/readability
6
6
  Project-URL: Repository, https://github.com/owahltinez/readability
@@ -17,22 +17,21 @@ Description-Content-Type: text/markdown
17
17
  A CLI tool that keeps code aligned with Google style conventions. It runs the
18
18
  right linters, formatters, and type checkers for your project with sensible
19
19
  defaults, and serves the official Google style guides in Markdown format. This
20
- is ideal for AI agents or developers who want consistent code quality checks
21
- and quick access to style conventions without browsing HTML pages.
20
+ is ideal for AI agents or developers who want consistent code quality checks and
21
+ quick access to style conventions without browsing HTML pages.
22
22
 
23
23
  ## Features
24
24
 
25
25
  - **Linting & Formatting**: A `check` command that automatically detects and
26
26
  runs relevant tools (Ruff, Pyrefly, Biome, Prettier, gofmt) for your project.
27
- - **Sensible Defaults**: Bundled Google-style configurations for Ruff,
28
- Pyrefly, and Biome are used automatically when a project does not define its
29
- own.
27
+ - **Sensible Defaults**: Google-style defaults for Ruff, Pyrefly, Biome, and
28
+ Prettier are used automatically when a project does not define its own.
30
29
  - **Style Guides**: A `guide` command that fetches the latest Google style
31
- guides (Python, Shell, C++, Java, JS/TS, Go, etc.) converted to Markdown,
32
- and outlines, addresses, and searches them by section rather than serving
33
- 200 KB to be read whole.
34
- - **Offline Mode**: Local caching of style guides for fast, offline access,
35
- kept fresh with a single `sync` command.
30
+ guides (Python, Shell, C++, Java, JS/TS, Go, etc.) converted to Markdown, and
31
+ outlines, addresses, and searches them by section rather than serving 200 KB
32
+ to be read whole.
33
+ - **Offline Mode**: Local caching of style guides for fast, offline access, kept
34
+ fresh with a single `sync` command.
36
35
 
37
36
  ## Quick Start
38
37
 
@@ -95,38 +94,39 @@ readability check . --fix
95
94
 
96
95
  ### Supported Tools
97
96
 
98
- | Tool | Supported Extensions | Config Needed | Fetched By |
99
- |------|----------------------|---------------|------------|
100
- | **Ruff** | `.py` | none, bundled | `uvx` |
101
- | **Pyrefly** | `.py` | none, bundled | `uvx` |
102
- | **Biome** | `.js`, `.ts`, `.jsx`, `.tsx`, `.json`, `.jsonc`, `.css`, `.html` | none, bundled | `npx` |
103
- | **Prettier** | `.js`, `.ts`, `.jsx`, `.tsx`, `.json`, `.css`, `.scss`, `.html`, `.md`, `.yml`, `.yaml` | `.prettierrc*` or `prettier.config.*` | `npx` |
104
- | **gofmt** | `.go` | `go.mod` | — |
97
+ | Tool | Supported Extensions | Config Needed | Fetched By |
98
+ | ------------ | --------------------------------------------------------------------------------------- | --------------------------------- | ---------- |
99
+ | **Ruff** | `.py` | none, bundled | `uvx` |
100
+ | **Pyrefly** | `.py` | none, bundled | `uvx` |
101
+ | **Biome** | `.js`, `.ts`, `.jsx`, `.tsx`, `.json`, `.jsonc`, `.css`, `.html` | none, bundled | `npx` |
102
+ | **Prettier** | `.js`, `.ts`, `.jsx`, `.tsx`, `.json`, `.css`, `.scss`, `.html`, `.md`, `.yml`, `.yaml` | none for Markdown, YAML, and SCSS | `npx` |
103
+ | **gofmt** | `.go` | `go.mod` | — |
105
104
 
106
105
  **You do not need to install any of these.** Each is resolved in order: a
107
- project-local install (`node_modules/.bin`, `.venv/bin`) first, then whatever
108
- is on your `PATH`, and only then fetched by `uvx` or `npx`. The runners cache
109
- what they download, so the fetch happens once per machine and later runs are
110
- served from disk and work offline.
106
+ project-local install (`node_modules/.bin`, `.venv/bin`) first, then whatever is
107
+ on your `PATH`, and only then fetched by `uvx` or `npx`. The runners cache what
108
+ they download, so the fetch happens once per machine and later runs are served
109
+ from disk and work offline.
111
110
 
112
- That keeps this package at ~4 MB rather than the ~54 MB it would take to
113
- carry Ruff and Pyrefly itself — a cost that would fall on everyone using only
114
- `guide`. An installed copy always wins over a fetched one, so a project that
115
- pinned a version is linted against the rules it chose.
111
+ That keeps this package at ~4 MB rather than the ~54 MB it would take to carry
112
+ Ruff and Pyrefly itself — a cost that would fall on everyone using only `guide`.
113
+ An installed copy always wins over a fetched one, so a project that pinned a
114
+ version is linted against the rules it chose.
116
115
 
117
116
  Fetched tools carry a minimum version, enough to understand the bundled
118
117
  configurations, and no maximum. A ceiling would freeze anyone who installed
119
- nothing at whatever was current when this package shipped, and tie its
120
- releases to Ruff's — which has published seventeen minor series, roughly one
121
- every six weeks. If you need a fixed version, install it: an installed tool
122
- always wins over a fetched one.
118
+ nothing at whatever was current when this package shipped, and tie its releases
119
+ to Ruff's — which has published seventeen minor series, roughly one every six
120
+ weeks. If you need a fixed version, install it: an installed tool always wins
121
+ over a fetched one.
123
122
 
124
- Set `UV_OFFLINE=1` to forbid fetching. A tool that then cannot be reached
125
- fails the run rather than passing it.
123
+ Set `UV_OFFLINE=1` to forbid fetching. A tool that then cannot be reached fails
124
+ the run rather than passing it.
126
125
 
127
126
  Ruff, Pyrefly, and Biome ship with bundled configurations, so they run on any
128
- file they handle without the project arranging anything. Prettier and gofmt
129
- bring no defaults here, so they wait until the project asks with a config file.
127
+ file they handle without the project arranging anything. Prettier does the same
128
+ for Markdown, YAML, and SCSS; a Prettier configuration opts its overlapping web
129
+ formats into Prettier too. Gofmt waits for a `go.mod` file.
130
130
 
131
131
  A tool that could not be reached at all is never skipped quietly:
132
132
 
@@ -141,8 +141,8 @@ $ readability check src/
141
141
  Error: Every tool for 1 path(s) is missing, so nothing was verified.
142
142
  ```
143
143
 
144
- That second case needs neither the tool nor a runner to be present, which is
145
- the state a container image is usually in.
144
+ That second case needs neither the tool nor a runner to be present, which is the
145
+ state a container image is usually in.
146
146
 
147
147
  `check` exits non-zero on findings, tool failures, and when every applicable
148
148
  tool is absent, so it can gate CI without a clean exit meaning required tools
@@ -165,26 +165,28 @@ if report.findings or report.failed or not report.ran:
165
165
  ```
166
166
 
167
167
  The returned `CheckReport` records only whether findings occurred and which
168
- tools ran, were skipped, or failed. Detailed tool findings are still written
169
- as each tool runs. Every path is validated before any tool runs, and a missing
170
- one raises `FileNotFoundError` rather than being misreported as a finding.
171
- Relative paths remain relative to the process working directory;
172
- `project_root` controls configuration discovery only.
168
+ tools ran, were skipped, or failed. Detailed tool findings are still written as
169
+ each tool runs. Every path is validated before any tool runs, and a missing one
170
+ raises `FileNotFoundError` rather than being misreported as a finding. Relative
171
+ paths remain relative to the process working directory; `project_root` controls
172
+ configuration discovery only.
173
173
 
174
174
  ### Default Configurations
175
175
 
176
176
  Ruff and Pyrefly defaults follow the
177
177
  [Google Python style guide](https://google.github.io/styleguide/pyguide.html):
178
- 80-column lines, Google docstrings, import ordering, and full type checking.
179
- The Biome default applies the 80-column lines and two-space indentation of the
178
+ 80-column lines, Google docstrings, import ordering, and full type checking. The
179
+ Biome default applies the 80-column lines and two-space indentation of the
180
180
  [Google JavaScript style guide](https://google.github.io/styleguide/jsguide.html)
181
- and enables Biome's recommended lint rules. These defaults apply only when the
182
- project does not define its own configuration. To override them, add a
183
- `[tool.ruff]` or `[tool.pyrefly]` section to your `pyproject.toml`, or a
184
- dedicated `ruff.toml`, `pyrefly.toml`, `biome.json`, or `biome.jsonc` any
185
- project-level configuration takes full precedence. The bundled Biome file
186
- requires Biome 2.5 or later, matching the version floor used by the fallback
187
- runner.
181
+ and enables Biome's recommended lint rules. Prettier wraps prose at 80 columns,
182
+ following the
183
+ [Google Markdown style guide](https://google.github.io/styleguide/docguide/style.html#character-line-limit).
184
+ These defaults apply only when the project does not define its own
185
+ configuration. To override them, add a `[tool.ruff]` or `[tool.pyrefly]` section
186
+ to your `pyproject.toml`, or a dedicated `ruff.toml`, `pyrefly.toml`,
187
+ `biome.json`, `biome.jsonc`, or Prettier configuration — any project-level
188
+ configuration takes full precedence. The bundled Biome file requires Biome 2.5
189
+ or later, matching the version floor used by the fallback runner.
188
190
 
189
191
  ## Style Guides
190
192
 
@@ -210,17 +212,17 @@ readability guide python --full | grep -i f-string
210
212
 
211
213
  A guide can exceed 200 KB, so the outline is what a bare invocation prints:
212
214
  listing the sections and fetching the one you need beats reading the lot.
213
- Nothing is written to disk, which is what a coding agent should do rather
214
- than redirecting a guide into the repository it is working on — use a shell
215
- redirect if you do want a copy.
215
+ Nothing is written to disk, which is what a coding agent should do rather than
216
+ redirecting a guide into the repository it is working on — use a shell redirect
217
+ if you do want a copy.
216
218
 
217
- `REF` and `--full` cannot be combined; that is refused rather than resolved
218
- by a precedence rule you would have to know.
219
+ `REF` and `--full` cannot be combined; that is refused rather than resolved by a
220
+ precedence rule you would have to know.
219
221
 
220
222
  ### Navigating a Guide
221
223
 
222
- The outline gives each section an index to fetch it by, and flags the ones
223
- large enough to be worth knowing about first:
224
+ The outline gives each section an index to fetch it by, and flags the ones large
225
+ enough to be worth knowing about first:
224
226
 
225
227
  ```bash
226
228
  $ readability guide cpp
@@ -234,28 +236,28 @@ Google C++ Style Guide
234
236
  # 140 sections · print one: readability guide cpp 4.5.1
235
237
  ```
236
238
 
237
- Sizes appear only at 1200 words and above — the 4% of sections expensive
238
- enough that you would want warning. They include subsections, since that is
239
- what the reference returns. The trailing line goes to stderr, so it never
240
- contaminates a piped outline.
239
+ Sizes appear only at 1200 words and above — the 4% of sections expensive enough
240
+ that you would want warning. They include subsections, since that is what the
241
+ reference returns. The trailing line goes to stderr, so it never contaminates a
242
+ piped outline.
241
243
 
242
244
  A section reference can be any of the following:
243
245
 
244
- | Reference | Example |
245
- |-----------|---------|
246
- | Section index, as shown by the outline | `2.2.4` |
247
- | Heading text, case-insensitive, or its slug | `"function comments"` |
246
+ | Reference | Example |
247
+ | ------------------------------------------- | ---------------------- |
248
+ | Section index, as shown by the outline | `2.2.4` |
249
+ | Heading text, case-insensitive, or its slug | `"function comments"` |
248
250
  | A parent-scoped path, spaces around the `>` | `"Imports > Decision"` |
249
251
 
250
- Whole matches are preferred; a reference that matches nothing in full is
251
- retried as a substring of the heading text.
252
+ Whole matches are preferred; a reference that matches nothing in full is retried
253
+ as a substring of the heading text.
252
254
 
253
255
  Three of the shipped guides — Python, JavaScript, and Java — number their own
254
256
  sections, and those numbers are the index. A rule cited from the outline then
255
- matches the published guide exactly, including where the guide skips a
256
- number: the Python guide has no 2.15 at all, so its 2.16 is listed as 2.16
257
- rather than renumbered. The other eleven guides number nothing, so their
258
- index comes from each heading's position in the tree.
257
+ matches the published guide exactly, including where the guide skips a number:
258
+ the Python guide has no 2.15 at all, so its 2.16 is listed as 2.16 rather than
259
+ renumbered. The other eleven guides number nothing, so their index comes from
260
+ each heading's position in the tree.
259
261
 
260
262
  Either way the index is unique, which is what makes a repeated heading
261
263
  addressable — `Definition`, `Pros`, `Cons`, and `Decision` appear under every
@@ -278,8 +280,8 @@ Error: 'Decision' matches 19 headings in the 'python' guide. Repeat with one of:
278
280
 
279
281
  A guide discusses plenty that no heading is named after, so a reference that
280
282
  matches nothing is usually a vocabulary mismatch rather than a mistake. The
281
- sections that mention the words are reported, which turns the miss into the
282
- next command:
283
+ sections that mention the words are reported, which turns the miss into the next
284
+ command:
283
285
 
284
286
  ```bash
285
287
  $ readability guide python f-string
@@ -289,22 +291,21 @@ It appears in these sections:
289
291
  3.10.1 Python Style Rules > Strings > Logging
290
292
  ```
291
293
 
292
- This locates a rule; it does not search text. For that, pipe `--full` to
293
- `grep`, which you already know and which brings its own `-i`, `-A`, `-c` and
294
- the rest:
294
+ This locates a rule; it does not search text. For that, pipe `--full` to `grep`,
295
+ which you already know and which brings its own `-i`, `-A`, `-c` and the rest:
295
296
 
296
297
  ```bash
297
298
  readability guide python --full | grep -in -A2 "f-string"
298
299
  ```
299
300
 
300
- Content goes to stdout and diagnostics to stderr, so every form is safe to
301
- pipe. Headings inside fenced code blocks are ignored, which matters for the
302
- Shell and Python guides where `#` starts a comment.
301
+ Content goes to stdout and diagnostics to stderr, so every form is safe to pipe.
302
+ Headings inside fenced code blocks are ignored, which matters for the Shell and
303
+ Python guides where `#` starts a comment.
303
304
 
304
305
  ### Supported Languages
305
306
 
306
- Run `readability guide` with no language for the full list and which guides
307
- are cached:
307
+ Run `readability guide` with no language for the full list and which guides are
308
+ cached:
308
309
 
309
310
  ```bash
310
311
  $ readability guide
@@ -337,17 +338,16 @@ readability sync
337
338
 
338
339
  ### Offline Mode
339
340
 
340
- The tool stores local copies of the style guides in the `guides/` directory
341
- and the `guide` command uses these local files when they exist. The bundled
342
- copies are automatically synchronized weekly from the official
341
+ The tool stores local copies of the style guides in the `guides/` directory and
342
+ the `guide` command uses these local files when they exist. The bundled copies
343
+ are automatically synchronized weekly from the official
343
344
  [Google Style Guides](https://google.github.io/styleguide/) repository via
344
- GitHub Actions, and you can refresh your local cache at any time with the
345
- `sync` command.
345
+ GitHub Actions, and you can refresh your local cache at any time with the `sync`
346
+ command.
346
347
 
347
348
  You can override the default `guides/` directory by setting the
348
349
  `READABILITY_CACHE` environment variable. This is useful if you want to store
349
- the guides in a specific location or share them across different
350
- installations:
350
+ the guides in a specific location or share them across different installations:
351
351
 
352
352
  ```bash
353
353
  export READABILITY_CACHE=/path/to/my/guides
@@ -3,22 +3,21 @@
3
3
  A CLI tool that keeps code aligned with Google style conventions. It runs the
4
4
  right linters, formatters, and type checkers for your project with sensible
5
5
  defaults, and serves the official Google style guides in Markdown format. This
6
- is ideal for AI agents or developers who want consistent code quality checks
7
- and quick access to style conventions without browsing HTML pages.
6
+ is ideal for AI agents or developers who want consistent code quality checks and
7
+ quick access to style conventions without browsing HTML pages.
8
8
 
9
9
  ## Features
10
10
 
11
11
  - **Linting & Formatting**: A `check` command that automatically detects and
12
12
  runs relevant tools (Ruff, Pyrefly, Biome, Prettier, gofmt) for your project.
13
- - **Sensible Defaults**: Bundled Google-style configurations for Ruff,
14
- Pyrefly, and Biome are used automatically when a project does not define its
15
- own.
13
+ - **Sensible Defaults**: Google-style defaults for Ruff, Pyrefly, Biome, and
14
+ Prettier are used automatically when a project does not define its own.
16
15
  - **Style Guides**: A `guide` command that fetches the latest Google style
17
- guides (Python, Shell, C++, Java, JS/TS, Go, etc.) converted to Markdown,
18
- and outlines, addresses, and searches them by section rather than serving
19
- 200 KB to be read whole.
20
- - **Offline Mode**: Local caching of style guides for fast, offline access,
21
- kept fresh with a single `sync` command.
16
+ guides (Python, Shell, C++, Java, JS/TS, Go, etc.) converted to Markdown, and
17
+ outlines, addresses, and searches them by section rather than serving 200 KB
18
+ to be read whole.
19
+ - **Offline Mode**: Local caching of style guides for fast, offline access, kept
20
+ fresh with a single `sync` command.
22
21
 
23
22
  ## Quick Start
24
23
 
@@ -81,38 +80,39 @@ readability check . --fix
81
80
 
82
81
  ### Supported Tools
83
82
 
84
- | Tool | Supported Extensions | Config Needed | Fetched By |
85
- |------|----------------------|---------------|------------|
86
- | **Ruff** | `.py` | none, bundled | `uvx` |
87
- | **Pyrefly** | `.py` | none, bundled | `uvx` |
88
- | **Biome** | `.js`, `.ts`, `.jsx`, `.tsx`, `.json`, `.jsonc`, `.css`, `.html` | none, bundled | `npx` |
89
- | **Prettier** | `.js`, `.ts`, `.jsx`, `.tsx`, `.json`, `.css`, `.scss`, `.html`, `.md`, `.yml`, `.yaml` | `.prettierrc*` or `prettier.config.*` | `npx` |
90
- | **gofmt** | `.go` | `go.mod` | — |
83
+ | Tool | Supported Extensions | Config Needed | Fetched By |
84
+ | ------------ | --------------------------------------------------------------------------------------- | --------------------------------- | ---------- |
85
+ | **Ruff** | `.py` | none, bundled | `uvx` |
86
+ | **Pyrefly** | `.py` | none, bundled | `uvx` |
87
+ | **Biome** | `.js`, `.ts`, `.jsx`, `.tsx`, `.json`, `.jsonc`, `.css`, `.html` | none, bundled | `npx` |
88
+ | **Prettier** | `.js`, `.ts`, `.jsx`, `.tsx`, `.json`, `.css`, `.scss`, `.html`, `.md`, `.yml`, `.yaml` | none for Markdown, YAML, and SCSS | `npx` |
89
+ | **gofmt** | `.go` | `go.mod` | — |
91
90
 
92
91
  **You do not need to install any of these.** Each is resolved in order: a
93
- project-local install (`node_modules/.bin`, `.venv/bin`) first, then whatever
94
- is on your `PATH`, and only then fetched by `uvx` or `npx`. The runners cache
95
- what they download, so the fetch happens once per machine and later runs are
96
- served from disk and work offline.
92
+ project-local install (`node_modules/.bin`, `.venv/bin`) first, then whatever is
93
+ on your `PATH`, and only then fetched by `uvx` or `npx`. The runners cache what
94
+ they download, so the fetch happens once per machine and later runs are served
95
+ from disk and work offline.
97
96
 
98
- That keeps this package at ~4 MB rather than the ~54 MB it would take to
99
- carry Ruff and Pyrefly itself — a cost that would fall on everyone using only
100
- `guide`. An installed copy always wins over a fetched one, so a project that
101
- pinned a version is linted against the rules it chose.
97
+ That keeps this package at ~4 MB rather than the ~54 MB it would take to carry
98
+ Ruff and Pyrefly itself — a cost that would fall on everyone using only `guide`.
99
+ An installed copy always wins over a fetched one, so a project that pinned a
100
+ version is linted against the rules it chose.
102
101
 
103
102
  Fetched tools carry a minimum version, enough to understand the bundled
104
103
  configurations, and no maximum. A ceiling would freeze anyone who installed
105
- nothing at whatever was current when this package shipped, and tie its
106
- releases to Ruff's — which has published seventeen minor series, roughly one
107
- every six weeks. If you need a fixed version, install it: an installed tool
108
- always wins over a fetched one.
104
+ nothing at whatever was current when this package shipped, and tie its releases
105
+ to Ruff's — which has published seventeen minor series, roughly one every six
106
+ weeks. If you need a fixed version, install it: an installed tool always wins
107
+ over a fetched one.
109
108
 
110
- Set `UV_OFFLINE=1` to forbid fetching. A tool that then cannot be reached
111
- fails the run rather than passing it.
109
+ Set `UV_OFFLINE=1` to forbid fetching. A tool that then cannot be reached fails
110
+ the run rather than passing it.
112
111
 
113
112
  Ruff, Pyrefly, and Biome ship with bundled configurations, so they run on any
114
- file they handle without the project arranging anything. Prettier and gofmt
115
- bring no defaults here, so they wait until the project asks with a config file.
113
+ file they handle without the project arranging anything. Prettier does the same
114
+ for Markdown, YAML, and SCSS; a Prettier configuration opts its overlapping web
115
+ formats into Prettier too. Gofmt waits for a `go.mod` file.
116
116
 
117
117
  A tool that could not be reached at all is never skipped quietly:
118
118
 
@@ -127,8 +127,8 @@ $ readability check src/
127
127
  Error: Every tool for 1 path(s) is missing, so nothing was verified.
128
128
  ```
129
129
 
130
- That second case needs neither the tool nor a runner to be present, which is
131
- the state a container image is usually in.
130
+ That second case needs neither the tool nor a runner to be present, which is the
131
+ state a container image is usually in.
132
132
 
133
133
  `check` exits non-zero on findings, tool failures, and when every applicable
134
134
  tool is absent, so it can gate CI without a clean exit meaning required tools
@@ -151,26 +151,28 @@ if report.findings or report.failed or not report.ran:
151
151
  ```
152
152
 
153
153
  The returned `CheckReport` records only whether findings occurred and which
154
- tools ran, were skipped, or failed. Detailed tool findings are still written
155
- as each tool runs. Every path is validated before any tool runs, and a missing
156
- one raises `FileNotFoundError` rather than being misreported as a finding.
157
- Relative paths remain relative to the process working directory;
158
- `project_root` controls configuration discovery only.
154
+ tools ran, were skipped, or failed. Detailed tool findings are still written as
155
+ each tool runs. Every path is validated before any tool runs, and a missing one
156
+ raises `FileNotFoundError` rather than being misreported as a finding. Relative
157
+ paths remain relative to the process working directory; `project_root` controls
158
+ configuration discovery only.
159
159
 
160
160
  ### Default Configurations
161
161
 
162
162
  Ruff and Pyrefly defaults follow the
163
163
  [Google Python style guide](https://google.github.io/styleguide/pyguide.html):
164
- 80-column lines, Google docstrings, import ordering, and full type checking.
165
- The Biome default applies the 80-column lines and two-space indentation of the
164
+ 80-column lines, Google docstrings, import ordering, and full type checking. The
165
+ Biome default applies the 80-column lines and two-space indentation of the
166
166
  [Google JavaScript style guide](https://google.github.io/styleguide/jsguide.html)
167
- and enables Biome's recommended lint rules. These defaults apply only when the
168
- project does not define its own configuration. To override them, add a
169
- `[tool.ruff]` or `[tool.pyrefly]` section to your `pyproject.toml`, or a
170
- dedicated `ruff.toml`, `pyrefly.toml`, `biome.json`, or `biome.jsonc` any
171
- project-level configuration takes full precedence. The bundled Biome file
172
- requires Biome 2.5 or later, matching the version floor used by the fallback
173
- runner.
167
+ and enables Biome's recommended lint rules. Prettier wraps prose at 80 columns,
168
+ following the
169
+ [Google Markdown style guide](https://google.github.io/styleguide/docguide/style.html#character-line-limit).
170
+ These defaults apply only when the project does not define its own
171
+ configuration. To override them, add a `[tool.ruff]` or `[tool.pyrefly]` section
172
+ to your `pyproject.toml`, or a dedicated `ruff.toml`, `pyrefly.toml`,
173
+ `biome.json`, `biome.jsonc`, or Prettier configuration — any project-level
174
+ configuration takes full precedence. The bundled Biome file requires Biome 2.5
175
+ or later, matching the version floor used by the fallback runner.
174
176
 
175
177
  ## Style Guides
176
178
 
@@ -196,17 +198,17 @@ readability guide python --full | grep -i f-string
196
198
 
197
199
  A guide can exceed 200 KB, so the outline is what a bare invocation prints:
198
200
  listing the sections and fetching the one you need beats reading the lot.
199
- Nothing is written to disk, which is what a coding agent should do rather
200
- than redirecting a guide into the repository it is working on — use a shell
201
- redirect if you do want a copy.
201
+ Nothing is written to disk, which is what a coding agent should do rather than
202
+ redirecting a guide into the repository it is working on — use a shell redirect
203
+ if you do want a copy.
202
204
 
203
- `REF` and `--full` cannot be combined; that is refused rather than resolved
204
- by a precedence rule you would have to know.
205
+ `REF` and `--full` cannot be combined; that is refused rather than resolved by a
206
+ precedence rule you would have to know.
205
207
 
206
208
  ### Navigating a Guide
207
209
 
208
- The outline gives each section an index to fetch it by, and flags the ones
209
- large enough to be worth knowing about first:
210
+ The outline gives each section an index to fetch it by, and flags the ones large
211
+ enough to be worth knowing about first:
210
212
 
211
213
  ```bash
212
214
  $ readability guide cpp
@@ -220,28 +222,28 @@ Google C++ Style Guide
220
222
  # 140 sections · print one: readability guide cpp 4.5.1
221
223
  ```
222
224
 
223
- Sizes appear only at 1200 words and above — the 4% of sections expensive
224
- enough that you would want warning. They include subsections, since that is
225
- what the reference returns. The trailing line goes to stderr, so it never
226
- contaminates a piped outline.
225
+ Sizes appear only at 1200 words and above — the 4% of sections expensive enough
226
+ that you would want warning. They include subsections, since that is what the
227
+ reference returns. The trailing line goes to stderr, so it never contaminates a
228
+ piped outline.
227
229
 
228
230
  A section reference can be any of the following:
229
231
 
230
- | Reference | Example |
231
- |-----------|---------|
232
- | Section index, as shown by the outline | `2.2.4` |
233
- | Heading text, case-insensitive, or its slug | `"function comments"` |
232
+ | Reference | Example |
233
+ | ------------------------------------------- | ---------------------- |
234
+ | Section index, as shown by the outline | `2.2.4` |
235
+ | Heading text, case-insensitive, or its slug | `"function comments"` |
234
236
  | A parent-scoped path, spaces around the `>` | `"Imports > Decision"` |
235
237
 
236
- Whole matches are preferred; a reference that matches nothing in full is
237
- retried as a substring of the heading text.
238
+ Whole matches are preferred; a reference that matches nothing in full is retried
239
+ as a substring of the heading text.
238
240
 
239
241
  Three of the shipped guides — Python, JavaScript, and Java — number their own
240
242
  sections, and those numbers are the index. A rule cited from the outline then
241
- matches the published guide exactly, including where the guide skips a
242
- number: the Python guide has no 2.15 at all, so its 2.16 is listed as 2.16
243
- rather than renumbered. The other eleven guides number nothing, so their
244
- index comes from each heading's position in the tree.
243
+ matches the published guide exactly, including where the guide skips a number:
244
+ the Python guide has no 2.15 at all, so its 2.16 is listed as 2.16 rather than
245
+ renumbered. The other eleven guides number nothing, so their index comes from
246
+ each heading's position in the tree.
245
247
 
246
248
  Either way the index is unique, which is what makes a repeated heading
247
249
  addressable — `Definition`, `Pros`, `Cons`, and `Decision` appear under every
@@ -264,8 +266,8 @@ Error: 'Decision' matches 19 headings in the 'python' guide. Repeat with one of:
264
266
 
265
267
  A guide discusses plenty that no heading is named after, so a reference that
266
268
  matches nothing is usually a vocabulary mismatch rather than a mistake. The
267
- sections that mention the words are reported, which turns the miss into the
268
- next command:
269
+ sections that mention the words are reported, which turns the miss into the next
270
+ command:
269
271
 
270
272
  ```bash
271
273
  $ readability guide python f-string
@@ -275,22 +277,21 @@ It appears in these sections:
275
277
  3.10.1 Python Style Rules > Strings > Logging
276
278
  ```
277
279
 
278
- This locates a rule; it does not search text. For that, pipe `--full` to
279
- `grep`, which you already know and which brings its own `-i`, `-A`, `-c` and
280
- the rest:
280
+ This locates a rule; it does not search text. For that, pipe `--full` to `grep`,
281
+ which you already know and which brings its own `-i`, `-A`, `-c` and the rest:
281
282
 
282
283
  ```bash
283
284
  readability guide python --full | grep -in -A2 "f-string"
284
285
  ```
285
286
 
286
- Content goes to stdout and diagnostics to stderr, so every form is safe to
287
- pipe. Headings inside fenced code blocks are ignored, which matters for the
288
- Shell and Python guides where `#` starts a comment.
287
+ Content goes to stdout and diagnostics to stderr, so every form is safe to pipe.
288
+ Headings inside fenced code blocks are ignored, which matters for the Shell and
289
+ Python guides where `#` starts a comment.
289
290
 
290
291
  ### Supported Languages
291
292
 
292
- Run `readability guide` with no language for the full list and which guides
293
- are cached:
293
+ Run `readability guide` with no language for the full list and which guides are
294
+ cached:
294
295
 
295
296
  ```bash
296
297
  $ readability guide
@@ -323,17 +324,16 @@ readability sync
323
324
 
324
325
  ### Offline Mode
325
326
 
326
- The tool stores local copies of the style guides in the `guides/` directory
327
- and the `guide` command uses these local files when they exist. The bundled
328
- copies are automatically synchronized weekly from the official
327
+ The tool stores local copies of the style guides in the `guides/` directory and
328
+ the `guide` command uses these local files when they exist. The bundled copies
329
+ are automatically synchronized weekly from the official
329
330
  [Google Style Guides](https://google.github.io/styleguide/) repository via
330
- GitHub Actions, and you can refresh your local cache at any time with the
331
- `sync` command.
331
+ GitHub Actions, and you can refresh your local cache at any time with the `sync`
332
+ command.
332
333
 
333
334
  You can override the default `guides/` directory by setting the
334
335
  `READABILITY_CACHE` environment variable. This is useful if you want to store
335
- the guides in a specific location or share them across different
336
- installations:
336
+ the guides in a specific location or share them across different installations:
337
337
 
338
338
  ```bash
339
339
  export READABILITY_CACHE=/path/to/my/guides
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "readability-cli"
3
- version = "0.8.5"
3
+ version = "0.8.6"
4
4
  description = "A CLI to lint, format, and type-check code with Google-style defaults, and pull Google style guides in markdown format."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
@@ -1288,27 +1288,27 @@ def _should_run_tool(
1288
1288
  Returns:
1289
1289
  True if the tool should run, False otherwise.
1290
1290
  """
1291
- # A tool shipping bundled defaults needs nothing from the project, so
1292
- # requiring a config file made those defaults unreachable by exactly the
1293
- # projects they exist for: an empty pyproject.toml was the difference
1294
- # between checking a file and checking nothing. Tools without defaults
1295
- # still wait to be asked, since there is no sane way to run them.
1296
- has_trigger = _bundled_config(tool["name"]).exists() or any(
1291
+ # Project configuration opts a tool into every extension it supports;
1292
+ # otherwise it handles only the formats with safe readability defaults.
1293
+ has_project_config = any(
1297
1294
  (project_root / t).exists() for t in tool["trigger"]
1298
1295
  )
1296
+ extensions = (
1297
+ tool["extensions"] if has_project_config else tool["default_extensions"]
1298
+ )
1299
1299
 
1300
1300
  # Files must match one of the tool's supported extensions.
1301
1301
  if path.is_file():
1302
- return has_trigger and path.suffix in tool["extensions"]
1302
+ return path.suffix in extensions
1303
1303
 
1304
- if not has_trigger:
1304
+ if not extensions:
1305
1305
  return False
1306
1306
 
1307
1307
  # A directory trigger alone is not evidence that the tool checked a file.
1308
1308
  # Several tools deliberately exit zero when nothing matches, which would
1309
1309
  # otherwise turn an unsupported-only tree into a reported clean result.
1310
1310
  return any(
1311
- candidate.is_file() and candidate.suffix in tool["extensions"]
1311
+ candidate.is_file() and candidate.suffix in extensions
1312
1312
  for candidate in path.rglob("*")
1313
1313
  )
1314
1314
 
@@ -1518,6 +1518,11 @@ def _get_tool_definitions(
1518
1518
  pyrefly = _tool_command("pyrefly", project_root)
1519
1519
  biome = _tool_command("biome", project_root)
1520
1520
  prettier = _tool_command("prettier", project_root)
1521
+ prettier_defaults = [
1522
+ "--print-width=80",
1523
+ "--prose-wrap=always",
1524
+ "--config-precedence=prefer-file",
1525
+ ]
1521
1526
 
1522
1527
  return [
1523
1528
  {
@@ -1554,6 +1559,7 @@ def _get_tool_definitions(
1554
1559
  ],
1555
1560
  "trigger": ["pyproject.toml", "ruff.toml", ".ruff.toml"],
1556
1561
  "extensions": [".py"],
1562
+ "default_extensions": [".py"],
1557
1563
  },
1558
1564
  {
1559
1565
  # Type checker only: it reports findings but cannot fix or format
@@ -1567,6 +1573,7 @@ def _get_tool_definitions(
1567
1573
  **({"cwd": project_root} if pyrefly_project_mode else {}),
1568
1574
  "trigger": ["pyproject.toml", "pyrefly.toml"],
1569
1575
  "extensions": [".py"],
1576
+ "default_extensions": [".py"],
1570
1577
  },
1571
1578
  {
1572
1579
  "name": "biome",
@@ -1611,18 +1618,30 @@ def _get_tool_definitions(
1611
1618
  ".css",
1612
1619
  ".html",
1613
1620
  ],
1621
+ "default_extensions": [
1622
+ ".js",
1623
+ ".ts",
1624
+ ".jsx",
1625
+ ".tsx",
1626
+ ".json",
1627
+ ".jsonc",
1628
+ ".css",
1629
+ ".html",
1630
+ ],
1614
1631
  },
1615
1632
  {
1616
1633
  "name": "prettier",
1617
1634
  "check_format": [
1618
1635
  *prettier,
1619
1636
  "--check",
1637
+ *prettier_defaults,
1620
1638
  "--no-error-on-unmatched-pattern",
1621
1639
  path_str,
1622
1640
  ],
1623
1641
  "format": [
1624
1642
  *prettier,
1625
1643
  "--write",
1644
+ *prettier_defaults,
1626
1645
  "--no-error-on-unmatched-pattern",
1627
1646
  path_str,
1628
1647
  ],
@@ -1648,6 +1667,7 @@ def _get_tool_definitions(
1648
1667
  ".yml",
1649
1668
  ".yaml",
1650
1669
  ],
1670
+ "default_extensions": [".md", ".yml", ".yaml", ".scss"],
1651
1671
  },
1652
1672
  {
1653
1673
  "name": "go fmt",
@@ -1655,6 +1675,7 @@ def _get_tool_definitions(
1655
1675
  "format": ["go", "fmt", path_str],
1656
1676
  "trigger": ["go.mod"],
1657
1677
  "extensions": [".go"],
1678
+ "default_extensions": [],
1658
1679
  },
1659
1680
  ]
1660
1681
 
@@ -1979,6 +1979,88 @@ def test_check_runs_biome_without_a_project_config(
1979
1979
  )
1980
1980
 
1981
1981
 
1982
+ @pytest.mark.parametrize("extension", (".md", ".yml", ".yaml", ".scss"))
1983
+ @patch("shutil.which")
1984
+ @patch("subprocess.run")
1985
+ def test_check_runs_prettier_for_unsupported_biome_formats_without_config(
1986
+ mock_run: MagicMock,
1987
+ mock_which: MagicMock,
1988
+ tmp_path: Path,
1989
+ extension: str,
1990
+ ) -> None:
1991
+ """Prettier covers its default formats without project configuration."""
1992
+ mock_which.side_effect = lambda name: name
1993
+ mock_run.return_value = MagicMock(returncode=0, stdout="", stderr="")
1994
+
1995
+ runner = CliRunner()
1996
+ with runner.isolated_filesystem(temp_dir=tmp_path):
1997
+ Path(f"document{extension}").touch()
1998
+
1999
+ result = runner.invoke(cli, ["check", f"document{extension}"])
2000
+
2001
+ assert result.exit_code == 0
2002
+ commands = [invocation.args[0] for invocation in mock_run.call_args_list]
2003
+ assert len(commands) == 1
2004
+ assert commands[0][0] == "prettier"
2005
+
2006
+
2007
+ def test_prettier_uses_google_markdown_defaults(tmp_path: Path) -> None:
2008
+ """CLI defaults wrap Markdown while deferring to project configuration."""
2009
+ tools = {
2010
+ tool["name"]: tool
2011
+ for tool in _get_tool_definitions(Path("document.md"), tmp_path)
2012
+ }
2013
+
2014
+ for command_name in ("check_format", "format"):
2015
+ command = tools["prettier"][command_name]
2016
+ assert "--print-width=80" in command
2017
+ assert "--prose-wrap=always" in command
2018
+ assert "--config-precedence=prefer-file" in command
2019
+
2020
+
2021
+ @patch("shutil.which")
2022
+ @patch("subprocess.run")
2023
+ def test_check_runs_prettier_for_configless_markdown_directory(
2024
+ mock_run: MagicMock, mock_which: MagicMock, tmp_path: Path
2025
+ ) -> None:
2026
+ """Default applicability also works when checking a directory."""
2027
+ mock_which.side_effect = lambda name: name
2028
+ mock_run.return_value = MagicMock(returncode=0, stdout="", stderr="")
2029
+
2030
+ runner = CliRunner()
2031
+ with runner.isolated_filesystem(temp_dir=tmp_path):
2032
+ Path("docs").mkdir()
2033
+ Path("docs/guide.md").touch()
2034
+
2035
+ result = runner.invoke(cli, ["check", "docs"])
2036
+
2037
+ assert result.exit_code == 0
2038
+ commands = [invocation.args[0] for invocation in mock_run.call_args_list]
2039
+ assert len(commands) == 1
2040
+ assert commands[0][0] == "prettier"
2041
+
2042
+
2043
+ @patch("shutil.which")
2044
+ @patch("subprocess.run")
2045
+ def test_prettier_project_config_opts_in_javascript(
2046
+ mock_run: MagicMock, mock_which: MagicMock, tmp_path: Path
2047
+ ) -> None:
2048
+ """A project configuration retains Prettier's existing broad coverage."""
2049
+ mock_which.side_effect = lambda name: name
2050
+ mock_run.return_value = MagicMock(returncode=0, stdout="", stderr="")
2051
+
2052
+ runner = CliRunner()
2053
+ with runner.isolated_filesystem(temp_dir=tmp_path):
2054
+ Path(".prettierrc").touch()
2055
+ Path("script.js").touch()
2056
+
2057
+ result = runner.invoke(cli, ["check", "script.js"])
2058
+
2059
+ assert result.exit_code == 0
2060
+ commands = [invocation.args[0][0] for invocation in mock_run.call_args_list]
2061
+ assert commands.count("prettier") == 1
2062
+
2063
+
1982
2064
  @patch("shutil.which")
1983
2065
  @patch("subprocess.run")
1984
2066
  def test_bundled_tools_do_not_claim_an_unsupported_directory(
@@ -1990,7 +2072,7 @@ def test_bundled_tools_do_not_claim_an_unsupported_directory(
1990
2072
 
1991
2073
  runner = CliRunner()
1992
2074
  with runner.isolated_filesystem(temp_dir=tmp_path):
1993
- Path("notes.md").touch()
2075
+ Path("notes.txt").touch()
1994
2076
 
1995
2077
  result = runner.invoke(cli, ["check", "."])
1996
2078
 
@@ -2024,7 +2106,7 @@ def test_biome_zero_file_result_is_not_reported_as_clean(
2024
2106
  Path(".gitignore").write_text("node_modules/\n")
2025
2107
  Path("node_modules/example").mkdir(parents=True)
2026
2108
  Path("node_modules/example/index.js").touch()
2027
- Path("README.md").touch()
2109
+ Path("README.txt").touch()
2028
2110
 
2029
2111
  for extra_args, expected_calls in (([], 2), (["--fix"], 3)):
2030
2112
  mock_run.side_effect = (
@@ -194,7 +194,7 @@ wheels = [
194
194
 
195
195
  [[package]]
196
196
  name = "readability-cli"
197
- version = "0.8.5"
197
+ version = "0.8.6"
198
198
  source = { editable = "." }
199
199
  dependencies = [
200
200
  { name = "beautifulsoup4" },
File without changes