fix: exempt doc comments from the code-comment budget
Rustdoc, JSDoc, NatSpec and docstrings document a surface for callers and are read by tooling — NatSpec ends up in contract metadata. The rule read as an instruction to delete them, and the linter blocked a legitimate rustdoc block. Also: plain block comment bodies were never linted (no per-line marker), and a literal double-star in a code span was flagged as bold. Merges the landmine and MUST categories, which said the same thing.
This commit is contained in:
@@ -8,10 +8,10 @@ paths:
|
||||
Budget: 1-3 lines. Write one only when an agent with the repo and thirty
|
||||
seconds of grep would still get it wrong. That means one of:
|
||||
|
||||
- a landmine no test catches
|
||||
- something that breaks silently — no test catches it, or a caller can
|
||||
break it from outside
|
||||
- a fact not in the repo (deployed bytecode, chain quirk, library bug)
|
||||
- a unit or epoch the type cannot carry (wei, ms, 18-dp)
|
||||
- a MUST or MUST NOT a caller can break
|
||||
|
||||
Good:
|
||||
|
||||
@@ -22,3 +22,11 @@ Everything else: delete. Design rationale and rejected alternatives go in
|
||||
MUST / NEVER.
|
||||
|
||||
Deleting a comment is cheap and reversible. When unsure, delete.
|
||||
|
||||
### Doc comments are not this
|
||||
|
||||
Rustdoc `///`, JSDoc `/** */`, Solidity NatSpec `@notice`/`@dev`, Python
|
||||
docstrings: different genre, budget does not apply. They document a surface
|
||||
for callers who cannot see the body, and tooling reads them — NatSpec ends
|
||||
up in contract metadata. Follow the language's convention, and never strip
|
||||
them to satisfy the budget above.
|
||||
|
||||
+37
-2
@@ -32,6 +32,15 @@ HASH_ONLY_EXT = {".py", ".sh", ".bash", ".zsh", ".rb", ".ex", ".nix",
|
||||
".yaml", ".yml", ".toml"}
|
||||
HASH_RE = re.compile(r"^\s*(#+)\s?(.*)$")
|
||||
|
||||
# Doc comments are a different genre and the budget does not apply: they
|
||||
# document a surface for callers, and tooling reads them — NatSpec ends up in
|
||||
# contract metadata. A two-star opener starts a doc block; a lone slash-star
|
||||
# does not.
|
||||
DOC_LINE_RE = re.compile(r"^\s*(///|//!)")
|
||||
DOC_BLOCK_OPEN_RE = re.compile(r"^\s*/\*\*")
|
||||
BLOCK_OPEN_RE = re.compile(r"^\s*/\*")
|
||||
BLOCK_CLOSE_RE = re.compile(r"\*/")
|
||||
|
||||
# Design rationale, alternatives, history: capped at 1-2 lines, belongs in docs.
|
||||
DOC_IN_SOURCE = [
|
||||
(r"rejected alternative", "rejected alternatives belong in docs/ or an ADR"),
|
||||
@@ -82,10 +91,34 @@ def added_text(tool_input):
|
||||
|
||||
|
||||
def comment_lines(text, ext=""):
|
||||
"""[(index, body)] for lines that are wholly a comment."""
|
||||
"""[(index, body)] for lines that are wholly a non-doc comment."""
|
||||
pattern = HASH_RE if ext in HASH_ONLY_EXT else COMMENT_RE
|
||||
hash_only = ext in HASH_ONLY_EXT
|
||||
out = []
|
||||
in_doc_block = False
|
||||
in_block = False
|
||||
for i, line in enumerate(text.splitlines()):
|
||||
if not hash_only:
|
||||
if in_doc_block:
|
||||
if BLOCK_CLOSE_RE.search(line):
|
||||
in_doc_block = False
|
||||
continue
|
||||
if DOC_BLOCK_OPEN_RE.match(line):
|
||||
in_doc_block = not BLOCK_CLOSE_RE.search(line)
|
||||
continue
|
||||
if DOC_LINE_RE.match(line):
|
||||
continue
|
||||
if in_block:
|
||||
if BLOCK_CLOSE_RE.search(line):
|
||||
in_block = False
|
||||
else:
|
||||
out.append((i, line.strip()))
|
||||
continue
|
||||
# A plain block opener carries no per-line marker, so its body is
|
||||
# invisible to the regexes below unless tracked.
|
||||
if BLOCK_OPEN_RE.match(line) and not BLOCK_CLOSE_RE.search(line):
|
||||
in_block = True
|
||||
continue
|
||||
m = pattern.match(line)
|
||||
if m and line.strip() not in ("*/", "/*"):
|
||||
out.append((i, m.group(2)))
|
||||
@@ -133,7 +166,9 @@ def lint(text, ext=""):
|
||||
if hits:
|
||||
problems.append(f"Superlatives in comments: {', '.join(sorted(set(hits)))}. Cut them.")
|
||||
|
||||
if "**" in blob:
|
||||
# Strip code spans first: a comment naming a doc-block opener or a glob
|
||||
# carries a literal double-star that is not emphasis.
|
||||
if "**" in re.sub(r"`[^`]*`", "", blob):
|
||||
problems.append("Bold inside a comment. No emphasis in comments.")
|
||||
|
||||
return problems, notes
|
||||
|
||||
Reference in New Issue
Block a user