@d3lm/lint-preset 1.5.5 → 1.6.0
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.
- package/README.md +42 -7
- package/dist/bin/comments.js +559 -123
- package/dist/bin/comments.js.map +1 -1
- package/dist/comments.cjs +462 -77
- package/dist/comments.cjs.map +1 -1
- package/dist/comments.d.cts +46 -20
- package/dist/comments.d.ts +46 -20
- package/dist/comments.js +464 -81
- package/dist/comments.js.map +1 -1
- package/native/comments.darwin-arm64.node +0 -0
- package/native/comments.darwin-x64.node +0 -0
- package/native/comments.linux-arm64-gnu.node +0 -0
- package/native/comments.linux-x64-gnu.node +0 -0
- package/package.json +9 -6
package/README.md
CHANGED
|
@@ -233,7 +233,7 @@ createOxlintConfig({
|
|
|
233
233
|
|
|
234
234
|
## Comment Formatting (`comments`)
|
|
235
235
|
|
|
236
|
-
The preset ships a `comments` CLI that checks how comments in JavaScript and
|
|
236
|
+
The preset ships a `comments` CLI that checks how comments in JavaScript, TypeScript, and Rust files fit the configured width. Line breaks are left to the tool, except where only the meaning of the prose shows whether a line ends with the start of a sentence. `list`, `check`, and `wrap` never change files. By default, `agent` and the hook send an agent only the comments with hints, plus comments with issues in parts the tool never rewraps (see [Text Kept as Written](#text-kept-as-written)). That default is a cheap triage, not a full review of the language. With `--failing` or `agent.scope: 'failing'`, the agent only gets the comments that fail `check`, and none that only have hints. With `--all` or `agent.scope: 'all'`, the agent reviews the wording of every comment in scope against its rules. The agent fixes the wording and moves the start of a sentence to the next line where a hint applies. Then the tool applies its exact rewrap to every comment in scope that still has a layout issue. The rewrap only changes whitespace in prose, like line breaks, runs of spaces, trailing spaces, and the indentation of continuation lines. It never changes a word, a punctuation character, a code span, or text kept as written, and it keeps the line endings of the file. Comments are found with a real parser, so strings, template literals, and regexes never produce false matches. Block and JSDoc comments get every check. Line comments (`//`) are never rewrapped, and they are only reported when a line is longer than `maxWidth` (see [Text Kept as Written](#text-kept-as-written)). Rust files get the same checks for their doc comments too (see [Rust](#rust)).
|
|
237
237
|
|
|
238
238
|
```bash
|
|
239
239
|
comments list # comments in uncommitted changes, with line lengths and issues
|
|
@@ -242,6 +242,7 @@ comments check --base main # print layout violations and exit with code
|
|
|
242
242
|
comments list src/a.ts:42 --json # the comment on line 42, with its rewrap suggestion
|
|
243
243
|
comments wrap src/a.ts:42 # print the exact rewrap of that comment to stdout
|
|
244
244
|
comments agent # hand suspicious comments to an agent, then verify the result
|
|
245
|
+
comments agent --failing # hand only the comments that fail check to an agent
|
|
245
246
|
comments check --cwd ../other-app # run as if started in another project
|
|
246
247
|
```
|
|
247
248
|
|
|
@@ -256,7 +257,7 @@ Verdicts are layout issues that can be measured without reading the prose. They
|
|
|
256
257
|
- `overflow` means a measured prose line exceeds `maxWidth`
|
|
257
258
|
- `underfill` means a line ends early, so the paragraph needs more lines than it should
|
|
258
259
|
- `widow` means fewer than three words sit on the last line of a paragraph
|
|
259
|
-
- `unbalanced` means the lines are less even than in the suggested rewrap
|
|
260
|
+
- `unbalanced` means the lines are less even than in the suggested rewrap, or a line ends inside a link, code span, or `{...}` group (see [Text That Stays on One Line](#text-that-stays-on-one-line))
|
|
260
261
|
|
|
261
262
|
Hints come from heuristics and can be false positives, because only the meaning of the prose shows whether the rule applies. A hint only sends a comment to the agent, which decides whether to change it. `check` only prints comments with verdicts, so a passing check stays quiet apart from its summary, even when hints remain after review. Use `list --suspicious` to inspect hints, which are marked with `(hint)` and never fail a check:
|
|
262
263
|
|
|
@@ -273,21 +274,51 @@ A paragraph with an `orphan` hint is not reported as `unbalanced` when that word
|
|
|
273
274
|
|
|
274
275
|
In the same way, a paragraph that splits a parenthetical is not reported as `unbalanced` when the split is all that sets it apart from the suggested rewrap, because the split can read as well and keep the line closer to `width`. This holds when the lines before the split match the rewrap and the lines after it match the rewrap of the text after the split. Otherwise the paragraph is still `unbalanced`.
|
|
275
276
|
|
|
277
|
+
With a `tolerance`, a paragraph has no `underfill`, `widow`, or `unbalanced` verdict when it already has the layout that the tool produces for a wider `width`, up to `width` plus `tolerance`. Its suggestion then keeps the lines as they are. With `width: 100` and `tolerance: 5`, a paragraph that is laid out the way the tool lays it out for a width of 105 passes. A paragraph that only has hints keeps them, and a line past `maxWidth` is still an `overflow`.
|
|
278
|
+
|
|
276
279
|
Hints are only checked in prose, never in code spans, code blocks, `@example`, or URLs. Rules that can't be measured, like writing complete sentences, are part of the agent's prompt (see `DEFAULT_RULES` in `src/comments/agent.ts`). The prompt treats the style rules as preferences, so the agent keeps punctuation that carries meaning or reads clearly, and never changes code, code spans, literals, patterns, or quotations.
|
|
277
280
|
|
|
281
|
+
### Text That Stays on One Line
|
|
282
|
+
|
|
283
|
+
The rewrap never breaks a line inside a code span, a `{...}` group like a JSDoc type or `{@link ...}`, or a Markdown link. A link is the text in brackets with the target right after it, which is `[text](target)` with an optional title, `[text][label]`, or `[text]` on its own. Brackets pair up like in Markdown, so a bracket in a code span or after a backslash doesn't count. Only the syntax counts, because only the renderer knows whether `[text]` resolves to anything, like an intra-doc link in Rust. A link that continues on the next line can't be followed in an editor. rust-analyzer, for one, only resolves an intra-doc link that sits on one line of a `///` comment.
|
|
284
|
+
|
|
285
|
+
Each of them is one word for the layout. A line that ends inside one is `unbalanced`, whatever else holds for the paragraph, so `check` fails and the rewrap joins it. The only exception is a code span in a Rust file, which keeps its paragraph as written (see [Rust](#rust)). One that is longer than `maxWidth` allows stays intact. On a single line it is an `overflow`. When it continues on the next line, joining it would add a line that is too long, so its paragraph is kept as written (`unbreakable text across lines`), and only shortening it or moving its target to a link reference definition fixes it.
|
|
286
|
+
|
|
278
287
|
### Text Kept as Written
|
|
279
288
|
|
|
280
289
|
The tool rewraps prose paragraphs, list items, and JSDoc tag descriptions. Everything else is kept exactly as written and has no suggestion, so the agent or you have to fix it by hand:
|
|
281
290
|
|
|
282
|
-
- Code gets no checks besides `banner`. This covers code blocks, `@example`, `@default`, and `@defaultValue`, tool directives like `eslint-disable-next-line` or `@ts-expect-error`, legal comments (`/*!`, `@license`, `@preserve`, and copyright notices), and paragraphs that parse as JavaScript.
|
|
291
|
+
- Code gets no checks besides `banner`. This covers code blocks, `@example`, `@default`, and `@defaultValue`, tool directives like `eslint-disable-next-line` or `@ts-expect-error`, legal comments (`/*!`, `@license`, `@preserve`, and copyright notices), and paragraphs that parse as JavaScript, or as Rust in a Rust file.
|
|
283
292
|
- Layout syntax gets hints but no verdicts, in the whole paragraph around it. This covers Markdown tables (a line that starts with `|`, or a delimiter row like `--- | ---`), box-drawing characters (U+2500 to U+257F), a line that starts with four or more of the same character among `-=*#_~+/\` or ends with four or more among `-=*#_~` (except Markdown headings and column underlines like `---- ----`), and aligned columns (a gap of two or more spaces after which text continues at the same column on at least two lines).
|
|
284
|
-
- Text that only looks like code or hand layout keeps its line breaks but still gets `overflow`, since prose can look like that too. Lines that look like code, such as ones that end with `{` or `;` or start with `import`, get no hints. Hand layout, such as Markdown hard line breaks, headings, quotes, arrows, and `term - description` lists, still gets hints.
|
|
293
|
+
- Text that only looks like code or hand layout keeps its line breaks but still gets `overflow`, since prose can look like that too. Lines that look like code, such as ones that end with `{` or `;` or start with `import` (or with `let`, `use`, or an attribute like `#[derive(Debug)]` in Rust files), get no hints. Hand layout, such as Markdown hard line breaks, headings, quotes, arrows, and `term - description` lists, still gets hints.
|
|
294
|
+
- Line comments (`//`) on their own lines get `overflow` and nothing else, so a line comment that fits `maxWidth` is never reported. A run of them on consecutive lines with the same indentation is one comment, and an empty `//` line separates its paragraphs. Code and layout syntax in them are exempt like above, and so is each line with a tool directive. A line comment after code on the same line is never checked. The agent fixes an overflowing line comment by shortening it, or by turning it into a multi-line block comment (`/** */` in JavaScript and TypeScript, `/* */` in Rust), which the tool then rewraps.
|
|
285
295
|
|
|
286
296
|
To keep a drawing that is wider than the width, put it in a code fence or add `comments-ignore` to the comment.
|
|
287
297
|
|
|
298
|
+
### Rust
|
|
299
|
+
|
|
300
|
+
In `.rs` files, the tool checks plain block comments (`/* */`) and every kind of doc comment: outer and inner line doc comments (`///` and `//!`) and outer and inner block doc comments (`/** */` and `/*! */`). A run of `///` or `//!` lines with the same indentation is one comment, and each line holds a prefix like the ` * ` of a block comment, so a run is checked and rewrapped like a JSDoc comment with the same text. The run ends at an empty line, at another marker, or at a line with other indentation. Other line comments, including `////`, and block comments that rustdoc doesn't read as docs, like `/***` and `/**/`, are plain comments, like in rustc. Plain line comments are only checked for lines past `maxWidth`, like `//` comments in JavaScript.
|
|
301
|
+
|
|
302
|
+
Rust comments are found with `rustc`'s own lexer (`ra_ap_rustc_lexer`, built into a native addon with [NAPI-RS](https://napi.rs)), so raw strings, byte and C strings, characters, lifetimes, nested block comments, a shebang, and the frontmatter of a cargo script never produce false matches. The lexer never stops early. A source with a token that never ends, like an unterminated block comment or string, is skipped and named like a file with a syntax error, because that token holds every comment after it. Like rustc, the tool reads a `/*` inside a block comment as the start of a nested comment, even inside a code span.
|
|
303
|
+
|
|
304
|
+
Doc comments are Markdown, and the checks above already treat them that way. Code blocks are doctests, so they are never touched, including hidden lines that start with `#`. Headings like `# Examples` and link reference definitions like ``[`Foo`]: crate::Foo`` are kept as written. Intra-doc links like ``[`count_provider_reads`]``, ``[`permissions`](crate::permissions)``, ``[the parser][`Parser`]``, or `[HashMap<K, V>]` always stay on one line, with their text and their target (see [Text That Stays on One Line](#text-that-stays-on-one-line)). A link that continues on the next line is joined, which rustdoc resolves the same way, since it reads runs of whitespace in a link as one space. A code span that continues on the next line is different. rustdoc shows the spaces at the start of the next line inside the code span, and how many there are depends on the indentation of every line of the item's docs, so a paragraph with such a code span is kept as written in Rust (`code span across lines`), and the tool never splits a code span itself. Rust has no JSDoc tags, so a line that starts with `@` is prose. Paragraphs are code when they parse as Rust statements, items, fields, match arms, or associated items (with `ra_ap_syntax`, the parser of rust-analyzer). A `/*!` or `//!` comment is an inner doc comment, not a legal comment, so only `@license`, `@preserve`, and copyright notices make a Rust comment legal.
|
|
305
|
+
|
|
306
|
+
The code fingerprint that makes sure only comments changed compares the tokens of a Rust file, without whitespace and comments. Each run of doc comments counts as one token of its style, since doc comments are attributes of the item after them. So rewording or rewrapping a doc comment is no code change, but turning `///` into `//`, into `//!`, or into `/** */`, or moving it to another item, is.
|
|
307
|
+
|
|
308
|
+
The width of a Rust file defaults to `comment_width` from the nearest `rustfmt.toml` or `.rustfmt.toml`, which is 80 when it's not set, like in rustfmt, and tabs count as `tab_spaces` columns (4 by default). Prettier's config never applies to Rust files. `width` in the `comments` config still overrides both.
|
|
309
|
+
|
|
310
|
+
The package ships the addon for macOS on arm64 and x64, and for Linux with glibc 2.17 or later on x64 and arm64. CI builds each of these `targets` from `native/napi.json` on its own runner and tests it there, and publishing fails when one of them is missing. In this repository, the addon is built with `pnpm run build:native`, which `build` and `test` run too, and needs a Rust toolchain. Without an addon for the platform, like on Windows or on Linux with musl, Rust files fail with a message that says how to build it, and JavaScript and TypeScript files work as before. To skip Rust files, leave `.rs` out of `extensions`, or pass `--ignore '**/*.rs'` for a single run.
|
|
311
|
+
|
|
312
|
+
`native/verify/verify.mjs` verifies that rewrapping Rust comments never changes code or what rustdoc renders. It rewraps the fixture crate in `native/verify/fixture` with the CLI and the comments of any `--corpus` directory, like `~/.cargo/registry/src/<index>`, with the library, at several widths. Then it checks that the code fingerprint and the words of every comment stay the same, that a second rewrap changes nothing, that every paragraph keeps its kind, and that no prose has a verdict left. The only exception is an overflow from a word that is longer than the maximum on its own, or from a line that holds no more text than the longest line of its paragraph did before, since a rewrap never adds a line like that. For the fixture, it also checks that the crate compiles and that its doctests pass. Last, it compares the JSON output of nightly rustdoc before and after: every item must render the same Markdown events, resolve the same intra-doc links, and have the same doc text apart from whitespace. It also finds the links of every item with pulldown-cmark, so the check doesn't rely on what the tool takes for a link. A link that was on one line must never continue on the next line after the rewrap, and no link of the fixture may continue on the next line at all, as long as each of them fits on a line.
|
|
313
|
+
|
|
314
|
+
```bash
|
|
315
|
+
pnpm run build
|
|
316
|
+
node native/verify/verify.mjs --corpus ~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f
|
|
317
|
+
```
|
|
318
|
+
|
|
288
319
|
### Configuration
|
|
289
320
|
|
|
290
|
-
`width` is the preferred line length, and `maxWidth` is the hard maximum, including indentation and the comment prefix. The CLI defaults `maxWidth` to 120, or to `width` if that is larger. The wrapper may go past `width`, up to `maxWidth`, to keep a parenthetical on one line. `tolerance` (default 0) lets lines in paragraphs of three or more lines go that many columns past `width` when that saves a line. A comment that is one paragraph stays on one line up to `singleLineWidth` plus `tolerance`, capped by `maxWidth`. A word
|
|
321
|
+
`width` is the preferred line length, and `maxWidth` is the hard maximum, including indentation and the comment prefix. The CLI defaults `maxWidth` to 120, or to `width` if that is larger. The wrapper may go past `width`, up to `maxWidth`, to keep a parenthetical on one line. `tolerance` (default 0) lets lines in paragraphs of three or more lines go that many columns past `width` when that saves a line. `check` also accepts a paragraph that already has the layout for a wider `width`, up to `width` plus `tolerance`, while the tool itself still wraps to `width`. A comment that is one paragraph stays on one line up to `singleLineWidth` plus `tolerance`, capped by `maxWidth`. A word, code span, or link longer than `maxWidth` is never split and is reported as `overflow`.
|
|
291
322
|
|
|
292
323
|
Like prettier, `comments` looks for a config file in the current directory and its parents, up to the repository root. The config can be a `comments.config.{ts,mts,js,mjs,cjs}`, `.commentsrc`, or `.commentsrc.json` file, or a `comments` key in `package.json`. All options are optional.
|
|
293
324
|
|
|
@@ -296,7 +327,7 @@ Like prettier, `comments` looks for a config file in the current directory and i
|
|
|
296
327
|
import { defineConfig } from '@d3lm/lint-preset/comments';
|
|
297
328
|
|
|
298
329
|
export default defineConfig({
|
|
299
|
-
// defaults to prettier's printWidth, or 80
|
|
330
|
+
// defaults to prettier's printWidth, or 80, and to rustfmt's comment_width in Rust files
|
|
300
331
|
width: 100,
|
|
301
332
|
maxWidth: 120,
|
|
302
333
|
tolerance: 0,
|
|
@@ -304,6 +335,8 @@ export default defineConfig({
|
|
|
304
335
|
avoidSentenceOrphans: true,
|
|
305
336
|
// report the style hints, like `em-dash` and `semicolon`
|
|
306
337
|
style: true,
|
|
338
|
+
// only these files, unless `ignore` skips them
|
|
339
|
+
include: ['src/**'],
|
|
307
340
|
ignore: ['src/generated/**'],
|
|
308
341
|
agent: {
|
|
309
342
|
runner: 'claude', // or 'codex', 'cursor'
|
|
@@ -312,7 +345,7 @@ export default defineConfig({
|
|
|
312
345
|
batchSize: 20, // most comments per agent
|
|
313
346
|
maxFiles: 10, // most files per agent
|
|
314
347
|
maxAgents: 6, // most agents running at once
|
|
315
|
-
scope: 'suspicious', // a triage,
|
|
348
|
+
scope: 'suspicious', // a triage, 'failing' for only comments that fail check, or 'all' for every changed comment
|
|
316
349
|
instructions: 'Rewording is allowed when a sentence reads awkwardly.',
|
|
317
350
|
},
|
|
318
351
|
hook: {
|
|
@@ -323,6 +356,8 @@ export default defineConfig({
|
|
|
323
356
|
|
|
324
357
|
Most options also have a command line flag that overrides the config file for a single run. See `comments --help` for the full list.
|
|
325
358
|
|
|
359
|
+
`include` and `ignore` take globs relative to the repository root, and apply to every scope, including files and directories passed as targets. A file is checked when it has one of the `extensions`, matches an `include` glob (or `include` is empty), and matches no `ignore` glob. `--include` replaces `include` from the config file, and `--ignore` adds to `ignore`, so `comments check --repo --include '**/*.rs'` checks only Rust files, and `--ignore '**/*.rs'` skips them.
|
|
360
|
+
|
|
326
361
|
Comments are split across several agents, and all comments of a file go to the same agent. In a terminal, `comments agent` shows the agents while they run, then lists the comments that still have issues. `--no-interactive` skips that list, and `--verbose` prints every agent's reply.
|
|
327
362
|
|
|
328
363
|
`agent.rules` points to a Markdown file that replaces the built-in formatting rules. `agent.command` runs any other agent CLI, like `['my-agent', '--prompt', '{prompt}']`. Without a `{prompt}` placeholder, the prompt goes to stdin.
|