paperlint 4.1.0 → 4.2.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.
Files changed (113) hide show
  1. package/CLAUDE.md +24 -0
  2. package/CONTRIBUTING.md +7 -0
  3. package/dist/adapters/latex/document-class.d.ts +6 -5
  4. package/dist/adapters/latex/document-class.d.ts.map +1 -1
  5. package/dist/adapters/latex/document-class.js +18 -10
  6. package/dist/adapters/latex/document-class.js.map +1 -1
  7. package/dist/adapters/latex/includes.d.ts +12 -0
  8. package/dist/adapters/latex/includes.d.ts.map +1 -0
  9. package/dist/adapters/latex/includes.js +42 -0
  10. package/dist/adapters/latex/includes.js.map +1 -0
  11. package/dist/adapters/latex/index.d.ts +9 -5
  12. package/dist/adapters/latex/index.d.ts.map +1 -1
  13. package/dist/adapters/latex/index.js +8 -1
  14. package/dist/adapters/latex/index.js.map +1 -1
  15. package/dist/adapters/latex/nodes.d.ts +5 -1
  16. package/dist/adapters/latex/nodes.d.ts.map +1 -1
  17. package/dist/adapters/latex/nodes.js +6 -2
  18. package/dist/adapters/latex/nodes.js.map +1 -1
  19. package/dist/adapters/latex/parse.d.ts.map +1 -1
  20. package/dist/adapters/latex/parse.js +1 -0
  21. package/dist/adapters/latex/parse.js.map +1 -1
  22. package/dist/adapters/latex/prose.d.ts +8 -0
  23. package/dist/adapters/latex/prose.d.ts.map +1 -0
  24. package/dist/adapters/latex/prose.js +353 -0
  25. package/dist/adapters/latex/prose.js.map +1 -0
  26. package/dist/claim-provenance.d.ts +34 -0
  27. package/dist/claim-provenance.d.ts.map +1 -0
  28. package/dist/claim-provenance.js +146 -0
  29. package/dist/claim-provenance.js.map +1 -0
  30. package/dist/cli.d.ts.map +1 -1
  31. package/dist/cli.js +20 -0
  32. package/dist/cli.js.map +1 -1
  33. package/dist/domain/paper-source.d.ts +58 -0
  34. package/dist/domain/paper-source.d.ts.map +1 -0
  35. package/dist/domain/paper-source.js +109 -0
  36. package/dist/domain/paper-source.js.map +1 -0
  37. package/dist/domain/sentences.d.ts +26 -0
  38. package/dist/domain/sentences.d.ts.map +1 -0
  39. package/dist/domain/sentences.js +48 -0
  40. package/dist/domain/sentences.js.map +1 -0
  41. package/dist/domain/tex-document.d.ts +39 -4
  42. package/dist/domain/tex-document.d.ts.map +1 -1
  43. package/dist/domain/tex-document.js.map +1 -1
  44. package/dist/eslint-rules/paper-typography.d.ts +7 -0
  45. package/dist/eslint-rules/paper-typography.d.ts.map +1 -1
  46. package/dist/eslint-rules/paper-typography.js +53 -1
  47. package/dist/eslint-rules/paper-typography.js.map +1 -1
  48. package/dist/ports/latex.d.ts +12 -1
  49. package/dist/ports/latex.d.ts.map +1 -1
  50. package/dist/register.d.ts +40 -0
  51. package/dist/register.d.ts.map +1 -0
  52. package/dist/register.js +134 -0
  53. package/dist/register.js.map +1 -0
  54. package/dist/tex-paper.d.ts +19 -0
  55. package/dist/tex-paper.d.ts.map +1 -0
  56. package/dist/tex-paper.js +105 -0
  57. package/dist/tex-paper.js.map +1 -0
  58. package/dist/tex-venue-rules.d.ts +7 -2
  59. package/dist/tex-venue-rules.d.ts.map +1 -1
  60. package/dist/tex-venue-rules.js +31 -17
  61. package/dist/tex-venue-rules.js.map +1 -1
  62. package/docs/rules/tex/claim-provenance.md +83 -0
  63. package/docs/rules/tex/missing-input.md +58 -0
  64. package/docs/rules/tex/register.md +77 -0
  65. package/docs/rules/tex/required-section.md +3 -1
  66. package/docs/rules/tex/template.md +12 -0
  67. package/docs/rules/tex/venue-leftover.md +4 -2
  68. package/docs/rules.md +3 -0
  69. package/eslint-rules/paper-typography.test.mjs +48 -1
  70. package/eslint-rules/paper-typography.ts +72 -1
  71. package/eslint.config.mjs +1 -0
  72. package/fixtures/real-markdown-paper/baseline.ts +8 -7
  73. package/package.json +2 -1
  74. package/skills/cold-read-diff/SKILL.md +31 -10
  75. package/skills/cold-read-diff/SKILL.md.spec.ts +30 -9
  76. package/skills/draft-paper/SKILL.md +2 -2
  77. package/skills/draft-paper/SKILL.md.spec.ts +1 -1
  78. package/skills/grade-paper-writing/SKILL.md +109 -44
  79. package/skills/grade-paper-writing/SKILL.md.spec.ts +108 -43
  80. package/skills/harden-paper/SKILL.md +35 -36
  81. package/skills/harden-paper/SKILL.md.spec.ts +34 -35
  82. package/skills/paper-adversarial-review/SKILL.md +2 -2
  83. package/skills/paper-adversarial-review/SKILL.md.spec.ts +1 -1
  84. package/skills/paper-pipeline/SKILL.md +3 -3
  85. package/skills/paper-pipeline/SKILL.md.spec.ts +2 -2
  86. package/skills/paper-pipeline/grade-paper-writing-ablation.eval.mjs +6 -6
  87. package/skills/paper-pipeline/references/writing-craft.md +53 -18
  88. package/skills/pc-panel-review/SKILL.md +36 -11
  89. package/skills/pc-panel-review/SKILL.md.spec.ts +35 -10
  90. package/src/adapters/latex/document-class.ts +20 -12
  91. package/src/adapters/latex/includes.ts +66 -0
  92. package/src/adapters/latex/index.test.ts +175 -1
  93. package/src/adapters/latex/index.ts +14 -4
  94. package/src/adapters/latex/nodes.ts +11 -2
  95. package/src/adapters/latex/parse.ts +1 -0
  96. package/src/adapters/latex/prose.ts +484 -0
  97. package/src/claim-provenance.test.ts +352 -0
  98. package/src/claim-provenance.ts +217 -0
  99. package/src/cli.ts +20 -0
  100. package/src/domain/paper-source.test.ts +156 -0
  101. package/src/domain/paper-source.ts +233 -0
  102. package/src/domain/sentences.ts +67 -0
  103. package/src/domain/tex-document.ts +36 -3
  104. package/src/ports/latex.ts +13 -0
  105. package/src/register.test.ts +165 -0
  106. package/src/register.ts +177 -0
  107. package/src/rule-cases.test.ts +54 -4
  108. package/src/tex-paper.test.ts +131 -0
  109. package/src/tex-paper.ts +152 -0
  110. package/src/tex-venue-rules.test.ts +87 -5
  111. package/src/tex-venue-rules.ts +62 -30
  112. package/skills/harden-paper/fixtures/uncited-assertions-sample.md +0 -43
  113. package/skills/harden-paper/fixtures/uncited-assertions-sample.tex +0 -77
@@ -24,6 +24,7 @@ import { basename, dirname, join } from "node:path";
24
24
  import { CONFIG_FILE } from "#lib/paper-config";
25
25
  import { collapse, documentClassLine, missingOptions, runText, spanIn, } from "./domain/tex-document.js";
26
26
  import { paperPreset, resolvePreset, SHIPPED_PREFIX, shippedPresets, } from "./presets.js";
27
+ import { readPaper, reportInPaper } from "./tex-paper.js";
27
28
  // ── the judges: what the source says + a resolved preset → findings. Pure. ─────────
28
29
  /** A place as a finding points at it: its span, or null — the top of the file — when unplaced. */
29
30
  const spanOf = (p) => (p.kind === "at" ? p.span : null);
@@ -38,6 +39,22 @@ function judgeClass(line, want, data) {
38
39
  at,
39
40
  }));
40
41
  }
42
+ /** A candidate as the message names it: its line, or an empty `\documentclass{}`. */
43
+ const candidateLine = (c) => c.kind === "class" ? documentClassLine(c) : "\\documentclass{}";
44
+ /**
45
+ * Several class lines behind a TeX switch: satisfied when any candidate is the template's class
46
+ * with its options; otherwise one finding, at the first candidate, naming every one.
47
+ */
48
+ function judgeCandidates(candidates, want, data) {
49
+ const matches = candidates.some((c) => c.kind === "class" && judgeClass(c, want, data).length === 0);
50
+ if (matches)
51
+ return [];
52
+ const named = candidates.map((c) => `\`${candidateLine(c)}\``).join(", ");
53
+ const found = { ...data, count: candidates.length, candidates: named };
54
+ return [
55
+ { messageId: "noCandidate", data: found, at: spanOf(candidates[0].place) },
56
+ ];
57
+ }
41
58
  /** The paper's class line against a template that was read: present, naming a class, that class. */
42
59
  function judgeClassLine(line, want, data) {
43
60
  switch (line.kind) {
@@ -47,6 +64,8 @@ function judgeClassLine(line, want, data) {
47
64
  return [{ messageId: "emptyClass", data, at: spanOf(line.place) }];
48
65
  case "class":
49
66
  return judgeClass(line, want, data);
67
+ case "ambiguous":
68
+ return judgeCandidates(line.candidates, want, data);
50
69
  }
51
70
  }
52
71
  /**
@@ -148,6 +167,7 @@ const RULES = {
148
167
  badTemplate: '{{file}}: the preset\'s "template" {{text}} is neither a \\documentclass line nor a class name, so the class cannot be checked',
149
168
  wrongClass: "the class is `{{got}}`, and {{venue}} requires `{{template}}` — the page size, fonts and layout the venue checks come from the class",
150
169
  missingOption: "the class option `{{option}}` is missing: {{venue}} requires `{{template}}`",
170
+ noCandidate: "none of the {{count}} \\documentclass lines is `{{template}}`, which {{venue}} requires: {{candidates}}. The source picks one behind a TeX switch, which is not evaluated; make one of them the venue's",
151
171
  },
152
172
  },
153
173
  },
@@ -201,8 +221,9 @@ export function otherVenues(preset, fromFile, deps) {
201
221
  });
202
222
  }
203
223
  /**
204
- * What a judge reads for the paper whose `paper.tex` is `filename`, or null when the paper has no
205
- * resolved preset (`pdf/measured` and `pdf/profile` already say so).
224
+ * What a judge reads for the paper whose `paper.tex` is `filename` — the paper with its includes
225
+ * spliced (`readPaper`) — or null when the paper has no resolved preset (`pdf/measured` and
226
+ * `pdf/profile` already say so).
206
227
  */
207
228
  function readingOf(filename, src, deps) {
208
229
  const dir = dirname(filename);
@@ -211,18 +232,11 @@ function readingOf(filename, src, deps) {
211
232
  return null;
212
233
  const preset = p.preset;
213
234
  const others = () => otherVenues(preset, join(dir, CONFIG_FILE), deps);
214
- return { src, latex: deps.latex, preset, others };
215
- }
216
- /** Each finding reported at its span, or at the top of the file when it has none. */
217
- function reportAll(context, findings) {
218
- const at = (i) => context.sourceCode.getLocFromIndex(i);
219
- findings.forEach((f) => {
220
- context.report({
221
- loc: { start: at(f.at?.start ?? 0), end: at(f.at?.end ?? 0) },
222
- messageId: f.messageId,
223
- data: f.data,
224
- });
225
- });
235
+ const paper = readPaper(filename, src, deps);
236
+ return {
237
+ reading: { src: paper.text, latex: deps.latex, preset, others },
238
+ paper,
239
+ };
226
240
  }
227
241
  function rule(name, deps) {
228
242
  const { judge, meta } = RULES[name];
@@ -235,9 +249,9 @@ function rule(name, deps) {
235
249
  return {
236
250
  root() {
237
251
  const sc = context.sourceCode;
238
- const reading = readingOf(context.filename, sc.raw ?? sc.text, deps);
239
- if (reading !== null)
240
- reportAll(context, judge(reading));
252
+ const r = readingOf(context.filename, sc.raw ?? sc.text, deps);
253
+ if (r !== null)
254
+ reportInPaper(context, meta.messages, r.paper, judge(r.reading));
241
255
  },
242
256
  };
243
257
  },
@@ -1 +1 @@
1
- {"version":3,"file":"tex-venue-rules.js","sourceRoot":"","sources":["../src/tex-venue-rules.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tex-venue-rules.js","sourceRoot":"","sources":["../src/tex-venue-rules.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,83 @@
1
+ # tex/claim-provenance
2
+
3
+ **Level:** warn · **Reads:** `paper.tex`
4
+
5
+ ## What it catches
6
+
7
+ A sentence of the body that states a number and does not say whose the number is. The sentence is
8
+ reported once, however many numbers it holds. Any one of these owners silences it:
9
+
10
+ | owner | in the sentence |
11
+ | ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
12
+ | a work outside the paper | a `\cite` (any of natbib's or biblatex's forms), a `\url`, an `\href`, or a footnote that cites or links |
13
+ | the authors | _we_, _our_, _ours_, _us_ (the capitalised country _US_ is not the authors) |
14
+ | a place in the paper | `\ref`, `\cref`, `\autoref` and their kin, or the words _Section 4_, _Table 2_, _Fig. 3_, _Appendix B_, _§4_ |
15
+ | a claimant named as one | _advertises_, _claims_: _"the skill advertises a 65% reduction"_, _"(claim 63%)"_ |
16
+ | the sample the number counts | _n = 134_ (in prose or in math), or a count followed by what it counts: _48 runs_, _48 independent runs_, _of 1,836 repositories_ |
17
+
18
+ It reads the body of the whole paper — `paper.tex` with the files it `\input`s, `\include`s or
19
+ `\subfile`s spliced in — from the start of the document, the abstract included, to `\appendix` or the
20
+ bibliography. A sentence in an included file is reported at that include, with the file and line at
21
+ the front of the message. Footnotes are read as sentences of their own. A citation or a footnote set right after
22
+ the full stop belongs to the sentence the full stop ends.
23
+
24
+ A number is digits a reader sees — `42\%`, `0.37`, `1,836`, `3x`, `3×`. Not a number: a year on its
25
+ own (1900–2099); a number right after a capitalised word inside the sentence (_Claude 3_, _Python
26
+ 3.12_, _Node 22_), which is a name; the level of an interval (the 95 of _95% CI_); digits glued to a letter, a hyphen or a point (`GPT-4`, `COVID-19`, `v1.2`, `10k`,
27
+ `0x1F`); anything inside math, a table, a figure, a caption, a heading (a run-in one too: `\textbf{Threats.}` opening a paragraph), code, a comment, a macro
28
+ definition, or the title block.
29
+
30
+ ## Why
31
+
32
+ A reviewer who cannot tell a property of the world from a cited finding from the authors' own
33
+ measurement says so, and scores the paper's soundness on it. Academic prose carries the owner by
34
+ default — _we found_, _[12] report_, _(Table 2)_ — and a sentence rewritten for punch loses it first:
35
+ _"Under test the rules held in 97% of cases"_ has no subject, and a reader takes it
36
+ for a result from the literature. This rule is the floor under the rules that shorten sentences.
37
+
38
+ ## Examples
39
+
40
+ ```latex
41
+ Agents ignore 42\% of the rules they are given. % warns
42
+ Under test the rules held in 97\% of cases. % warns: no one ran the test
43
+ We find that agents ignore 42\% of the rules. % silent: the authors
44
+ Agents ignore 42\% of the rules~\cite{smith2025}. % silent: a citation
45
+ Agents ignore 42\% of the rules (Table~\ref{t:rates}). % silent: a place in the paper
46
+ Of 1,836 repositories, 12\% ship hooks. % silent: the sample
47
+ In 2024 the first agents shipped with GPT-4. % silent: a year and a name
48
+ ```
49
+
50
+ The first line reports:
51
+
52
+ > «42%» — whose number is this? A reader cannot tell a cited finding from your own measurement from
53
+ > a general fact. Say it in the sentence: cite the work (\cite), claim it (we measured, our census),
54
+ > point to where it is shown (\ref, Section N, Table N), or name the sample it counts (n = 134, 48
55
+ > runs)
56
+
57
+ ## Options / preset fields
58
+
59
+ None. It is on, as a warning, for every `paper.tex`; turn it off or up in the `rules` setting like
60
+ any other rule.
61
+
62
+ ## What it does not check
63
+
64
+ - Whether the owner is the right one: a citation that does not report the number, or a _we_ in a
65
+ sentence about someone else's work, silences the sentence all the same.
66
+ - What a custom macro prints: `\rate{}` defined as `42\%` is not a number here.
67
+ - Which numbers are names, beyond the two shapes it knows: a number after a lowercase word (_version
68
+ 3 of the model_) is read as a quantity, and so is the number of a name that opens the sentence
69
+ (_Claude 3 fails …_).
70
+ - Whether a count followed by a plural noun is really the sample (_3 times faster_ passes as one).
71
+ - Markdown papers (`paper.md`): it reads the LaTeX parse tree only.
72
+
73
+ ## How to fix
74
+
75
+ Say whose the number is, in the sentence — usually by putting back the subject a punchy rewrite took
76
+ out: _"We ran the rules in 48 sessions and saw no violation"_, not _"No violation in 48 runs."_ A
77
+ number that is common knowledge, or quoted on purpose, keeps its sentence with ESLint's directive and
78
+ the reason:
79
+
80
+ ```latex
81
+ % eslint-disable-next-line tex/claim-provenance -- the venue's own page limit, quoted
82
+ The limit is 8.
83
+ ```
@@ -0,0 +1,58 @@
1
+ # tex/missing-input
2
+
3
+ **Level:** warn · **Reads:** `paper.tex`, and every file it includes
4
+
5
+ ## What it catches
6
+
7
+ An `\input`, `\include` or `\subfile` that names a file which is not there. The path is resolved the
8
+ way TeX resolves it, from the paper's directory: `name.tex` first, then `name` as written. An
9
+ include inside an included file is resolved from the paper's directory too.
10
+
11
+ ## Why
12
+
13
+ The rules that read the parse tree — `tex/template`, `tex/required-section`, `tex/venue-leftover`,
14
+ `tex/claim-provenance` — read the whole paper: `paper.tex` with every included file spliced in where
15
+ it is included, as TeX reads it. A file that is not there cannot be read, and without this rule the
16
+ others would report a clean body for text they never saw. TeX stops on it too.
17
+
18
+ ## Examples
19
+
20
+ ```latex
21
+ \input{sections/results} % warns when neither sections/results.tex nor sections/results exists
22
+ \input{sections/intro} % silent: sections/intro.tex is there
23
+ ```
24
+
25
+ The first line reports:
26
+
27
+ > `sections/results` is not there (tried `sections/results.tex` and `sections/results`, from the
28
+ > paper's directory): TeX stops on it, and no rule read what it should hold
29
+
30
+ A missing file included by another included file is reported at the include in `paper.tex` that
31
+ brought that file in, and the message names the file that holds it.
32
+
33
+ ## Options / preset fields
34
+
35
+ None.
36
+
37
+ ## What it does not check
38
+
39
+ - A path built from a macro (`\input{\dir/intro}`): macros are not expanded, so the path is looked
40
+ up as written.
41
+ - `\import{dir}{file}` and other packages' include macros.
42
+
43
+ ## How to fix
44
+
45
+ Correct the path, or add the file. A file that a build step writes (a table of generated numbers)
46
+ is absent before that step runs — keep the include with a disable directive and the reason:
47
+
48
+ ```latex
49
+ % eslint-disable-next-line tex/missing-input -- written by repro/numbers.sh before the build
50
+ \input{generated/numbers}
51
+ ```
52
+
53
+ ## Where findings in included files are reported
54
+
55
+ ESLint reports a finding in the file it lints, and paperlint lints `paper.tex`. A finding of any of
56
+ the rules above whose text came from an included file is reported at the include in `paper.tex`,
57
+ with the included file, line and column at the front of its message
58
+ (`sections/results.tex:12:3: …`). A disable directive for it goes above that include.
@@ -0,0 +1,77 @@
1
+ # tex/register
2
+
3
+ **Level:** warn · **Reads:** `paper.tex` and the files it includes
4
+
5
+ ## What it catches
6
+
7
+ A body in which more than 0.8 sentences per 1000 words open with _And_, _So_, _But_, _Nor_, _Or_ or
8
+ _Yet_. It is reported once, at the body's first sentence, with the count, the rate and the first
9
+ three such sentences.
10
+
11
+ It reads the body of the whole paper — `paper.tex` with the files it `\input`s, `\include`s or
12
+ `\subfile`s spliced in — from the start of the document, the abstract included, to `\appendix` or the
13
+ bibliography: paragraphs, list items and footnotes. Headings are not sentences, and neither is a
14
+ run-in heading — a bold or italic phrase ending in `.` or `:` that opens a paragraph or an item
15
+ (`\textbf{Threats.} …`). Captions, tables, figures, code and math environments are left out. A
16
+ citation, a cross-reference or inline math counts as one word, as it reads on the page. Sentences
17
+ are cut exactly as [`tex/claim-provenance`](claim-provenance.md) cuts them.
18
+
19
+ A conjunction counts only as the capitalised first word of a sentence; the _and_ that opens a list
20
+ item continuing the sentence before the list does not.
21
+
22
+ A body under 2 000 words is not judged: there one sentence decides the rate.
23
+
24
+ ## Why
25
+
26
+ Reviewers called our prose "too informal" and "a blogpost". Measured against eleven accepted
27
+ papers, sentences opening with a coordinating conjunction set our four drafts apart:
28
+
29
+ | measure | 11 accepted papers | our 4 drafts |
30
+ | ------------------------------------------------------------ | ---------------------------: | -----------: |
31
+ | sentences opening with And/So/But/Nor/Or/Yet, per 1000 words | 0–0.58 (the ACSAC papers: 0) | 0.29–2.98 |
32
+
33
+ The limit sits above the accepted range with room to spare: the rule flags a body that has drifted
34
+ to a post's register, not one a little above the median. Mean sentence length did not separate the
35
+ two groups. The share of sentences under eight words did not either, once measured on the parse
36
+ tree: 3.3–7.3% on the two accepted papers in this repository's corpus, 5.1–7.0% on three of ours.
37
+
38
+ On the corpus (`fixtures/accepted-papers/`) the rule measures:
39
+
40
+ | paper | per 1000 words |
41
+ | ----------------------------------- | -------------: |
42
+ | `secure-acsac24` (ACSAC 2024) | 0.00 |
43
+ | `llm-splained-acsac25` (ACSAC 2025) | 0.00 |
44
+ | `agenticdev-acm26` (ours, accepted) | 1.60 |
45
+
46
+ The vocabulary of machine-written text (_delve_, _crucial_) is a different question, and a different
47
+ check; a paper can avoid every such word and still read as a post.
48
+
49
+ ## Examples
50
+
51
+ ```latex
52
+ We measured the cost on four tools. But the bill barely moves. % a conjunction start
53
+ We measured the cost on four tools, and the bill barely moves. % none
54
+ We measured the cost on four tools. However, the bill barely moves. % none
55
+ ```
56
+
57
+ On a body where such sentences run above the limit, the rule reports:
58
+
59
+ > 7 sentences open with And, So, But, Nor, Or or Yet — 1.60 per 1000 words (first: «…», «…», «…»).
60
+ > Accepted papers measured 0–0.58; this rule warns above 0.8. Join the sentence to the one before,
61
+ > or open with the connective a paper uses (However, Therefore, Moreover)
62
+
63
+ ## Options / preset fields
64
+
65
+ In a paper's `paperlint.json`:
66
+
67
+ ```json
68
+ {
69
+ "rules": {
70
+ "tex/register": ["warn", { "conjunctionStartsPer1000": 0.8 }]
71
+ }
72
+ }
73
+ ```
74
+
75
+ | option | default | what it is |
76
+ | -------------------------- | ------: | ---------------------------------------------------------- |
77
+ | `conjunctionStartsPer1000` | 0.8 | the conjunction starts per 1000 words above which it warns |
@@ -9,6 +9,9 @@ the required sections by title in `required_sections`; the paper must have a `\s
9
9
  `\section*` with exactly that title (whitespace collapsed), and, when the preset says
10
10
  `position: "last"`, no section of the main text may come after it.
11
11
 
12
+ It reads the sections of the whole paper, the files `paper.tex` includes spliced in where they are
13
+ included, so a required section kept in `sections/llm-usage.tex` counts.
14
+
12
15
  It only knows the sections a preset lists. A paper whose `paperlint.json` names no preset, or a
13
16
  preset with no `required_sections`, gets no finding.
14
17
 
@@ -66,7 +69,6 @@ the bibliography or an appendix is fine. Without `position`, anywhere will do.
66
69
  ## What it does not check
67
70
 
68
71
  - Whether LLMs were used, or what the section says.
69
- - Sections pulled in with `\input` or `\include`: the rule reads `paper.tex` alone.
70
72
 
71
73
  ## How to fix
72
74
 
@@ -8,6 +8,17 @@ The paper is not set in the class its venue requires. The rule compares the `\do
8
8
  of `paper.tex` with the preset's `template`: the class must be the same, and every option the
9
9
  template names must be there. The paper may add options of its own.
10
10
 
11
+ A source that keeps one file for several venues and picks the class behind a TeX switch has several
12
+ `\documentclass` lines. The switch is not evaluated: each line is a candidate, the paper passes when
13
+ one of them is the template's class with its options, and when none is, one finding at the first
14
+ candidate names every one:
15
+
16
+ ```latex
17
+ \def\venue{2}
18
+ \if\venue1 \documentclass{article} \fi
19
+ \if\venue2 \documentclass[conference,compsoc]{IEEEtran} \fi % passes: the second candidate matches
20
+ ```
21
+
11
22
  It only knows the class a preset names. A paper whose `paperlint.json` names no preset, or a
12
23
  preset with no `template`, gets no finding.
13
24
 
@@ -55,6 +66,7 @@ and no option. A value that is neither is reported as a finding that names the p
55
66
  requires is there.
56
67
  - The version of the class file (#94).
57
68
  - A `\documentclass` inside a comment: the rule reads the parse tree, so it does not count.
69
+ - Which branch of a TeX switch builds: with several class lines, one matching candidate is enough.
58
70
 
59
71
  ## How to fix
60
72
 
@@ -11,7 +11,9 @@ now going to VenueB.
11
11
  It only knows the venues paperlint ships a preset for, by each preset's `name` and `aliases`. A
12
12
  venue with no preset is not recognized.
13
13
 
14
- It looks at what a reader sees — prose, the author block, captions, footnotes, a citation's note in
14
+ It reads the whole paper — `paper.tex` with the files it `\input`s, `\include`s or `\subfile`s
15
+ spliced in; a name found in an included file is reported at that include, with the file and line at
16
+ the front of the message. It looks at what a reader sees — prose, the author block, captions, footnotes, a citation's note in
15
17
  square brackets, and front-matter macros such as `\acmConference` — and ignores comments, citation
16
18
  keys, labels, URLs (a `\url`, and the address of an `\href` — its link text is read), math, code and
17
19
  the bibliography. Names are matched as whole words, case-sensitive.
@@ -58,7 +60,7 @@ reported.
58
60
  ## What it does not check
59
61
 
60
62
  - A venue no shipped preset describes.
61
- - A name split by markup (`\textbf{AI}Sec`), and text pulled in with `\input`.
63
+ - A name split by markup (`\textbf{AI}Sec`).
62
64
 
63
65
  ## How to fix
64
66
 
package/docs/rules.md CHANGED
@@ -21,6 +21,9 @@ reads and when it fails. Errors fail `paperlint lint`; warnings print and do not
21
21
  | [`tex/template`](rules/tex/template.md) | error | `paper.tex` → `paperlint.json` | the `\documentclass` is not the preset's `template` class, or lacks an option it names — [page](rules/tex/template.md) |
22
22
  | [`tex/required-section`](rules/tex/required-section.md) | error | `paper.tex` → `paperlint.json` | a section the preset requires (AIDC: «LLM Usage Statement», last) is missing or not where it must be — [page](rules/tex/required-section.md) |
23
23
  | [`tex/venue-leftover`](rules/tex/venue-leftover.md) | warn | `paper.tex` → `paperlint.json` | the text names another shipped venue than the one the paper extends («Submission to VenueA 2026» in a paper now set for VenueB) — [page](rules/tex/venue-leftover.md) |
24
+ | [`tex/claim-provenance`](rules/tex/claim-provenance.md) | warn | `paper.tex` | a sentence of the body states a number and does not say whose it is — no citation or link, no _we_/_our_, no `\ref` or "Table 2", no sample ("n = 134", "48 runs") — [page](rules/tex/claim-provenance.md) |
25
+ | [`tex/missing-input`](rules/tex/missing-input.md) | warn | `paper.tex` and the files it includes | an `\input`, `\include` or `\subfile` names a file that is not there, so no rule read its text — [page](rules/tex/missing-input.md) |
26
+ | [`tex/register`](rules/tex/register.md) | warn | `paper.tex` and the files it includes | the body runs to a post's register: more than 0.8 sentences per 1000 words open with _And_, _So_, _But_, _Nor_, _Or_ or _Yet_ — the limit is an option — [page](rules/tex/register.md) |
24
27
  | `review/frontmatter` | error | `reviews/*.md` | the review's frontmatter fails paperlint's JSON Schema — a `findings` record without `id`/`status`, an unknown field, or an **open** finding with no `cause` (`skill-defect` · `missing-skill` · `hook` · `rule`). A review with no `findings` key is not checked for findings |
25
28
  | `sibling/frontmatter` | warn | `siblings/*.md` (not `README.md`) | a sibling card's frontmatter has no `read:` saying how much of the competing paper was read (`full` · `abstract` · `none`) |
26
29
  | `pdf/fresh` | error | `paper.tex` → `_build/paper.facts.json` | the paper names a venue and the facts cannot be judged: not JSON, a schema other than 2, or they describe a PDF that is gone or differs from the one on disk (its SHA-256) |
@@ -16,7 +16,10 @@ import { readFileSync } from "node:fs";
16
16
  import { dirname, join } from "node:path";
17
17
  import { fileURLToPath } from "node:url";
18
18
  import { texLanguage } from "./latex-language.ts";
19
- import typography, { texVisibleRuns } from "./paper-typography.ts";
19
+ import typography, {
20
+ crefDefinitionRanges,
21
+ texVisibleRuns,
22
+ } from "./paper-typography.ts";
20
23
  import bib from "./bib-reachable-entry.ts";
21
24
 
22
25
  const HERE = dirname(fileURLToPath(import.meta.url));
@@ -118,6 +121,50 @@ describe("paper/section-word", () => {
118
121
  expect(ids(await lint(src), "paper/section-word")).toEqual([]);
119
122
  });
120
123
 
124
+ it("🔴 a cleveref name definition is not prose: silent, and --fix leaves it as written", async () => {
125
+ const src =
126
+ "\\documentclass{article}\n\\usepackage{cleveref}\n\\crefname{section}{§}{§§}\n\\Crefname{section}{§}{§§}\n" +
127
+ "\\begin{document}\nText.\n\\end{document}\n";
128
+ expect(ids(await lint(src), "paper/section-word")).toEqual([]);
129
+ expect(await fixed(src)).toBe(src);
130
+ });
131
+
132
+ it("a definition's range: its attached arguments, or the groups after a macro the parser did not sign", () => {
133
+ const signed = "\\crefname{section}{}{§§}";
134
+ expect(crefDefinitionRanges(signed)).toEqual([[0, signed.length]]);
135
+ const at = (s, e) => ({ start: { offset: s }, end: { offset: e } });
136
+ const tree = (macro, after) => ({ content: [macro, ...after] });
137
+ expect(
138
+ crefDefinitionRanges("", {
139
+ parse: () =>
140
+ tree({ type: "macro", content: "Crefname", position: at(0, 9) }, [
141
+ { type: "group", content: [], position: at(9, 14) },
142
+ { type: "string", content: "x", position: at(14, 15) },
143
+ ]),
144
+ }),
145
+ ).toEqual([[0, 14]]);
146
+ // A node with no position has no range; an argument with no content ends nothing.
147
+ expect(
148
+ crefDefinitionRanges("", {
149
+ parse: () =>
150
+ tree(
151
+ {
152
+ type: "macro",
153
+ content: "crefname",
154
+ args: [{ type: "argument" }],
155
+ },
156
+ [],
157
+ ),
158
+ }),
159
+ ).toEqual([]);
160
+ });
161
+
162
+ it("…while a § in prose next to such a definition is still reported", async () => {
163
+ const src =
164
+ "\\documentclass{article}\n\\crefname{section}{§}{§§}\n\\begin{document}\nSee §5.\n\\end{document}\n";
165
+ expect(ids(await lint(src), "paper/section-word")).toHaveLength(1);
166
+ });
167
+
121
168
  it("markdown: `§5` → `Section 5`, code untouched", async () => {
122
169
  const src = "See §5 and `§3` here.\n";
123
170
  expect(ids(await lint(src, "paper.md"), "paper/section-word")).toHaveLength(
@@ -61,6 +61,7 @@
61
61
  */
62
62
  import assert from "node:assert/strict";
63
63
  import { getParser } from "@unified-latex/unified-latex-util-parse";
64
+ import { takeWhile } from "remeda";
64
65
  import type { Nodes } from "mdast";
65
66
  import type { TexArg, TexNode, TexRoot } from "./latex-language.ts";
66
67
  import type {
@@ -121,7 +122,77 @@ function skippedRanges(
121
122
  }
122
123
  const bib = bibRange(raw);
123
124
  if (bib) out.push([bib.start, bib.end]);
124
- return out;
125
+ return [...out, ...crefDefinitionRanges(raw)];
126
+ }
127
+
128
+ /**
129
+ * cleveref's name and format definitions (`\crefname{section}{§}{§§}`): the label a reference
130
+ * prints is set there, not written as prose, so a sign in them is not a sign in the text.
131
+ */
132
+ const CREF_DEFINITIONS: ReadonlySet<string> = new Set([
133
+ "crefname",
134
+ "Crefname",
135
+ "crefformat",
136
+ "Crefformat",
137
+ "crefrangeformat",
138
+ "Crefrangeformat",
139
+ "crefmultiformat",
140
+ "Crefmultiformat",
141
+ "crefrangemultiformat",
142
+ "Crefrangemultiformat",
143
+ ]);
144
+
145
+ const isGroup = (n: TexNode): boolean => n.type === "group";
146
+
147
+ /**
148
+ * A macro's range with its arguments: the ones the parser attached (cleveref's are signed) or the
149
+ * `{…}` groups standing right after it when it was given none — from the first to the last offset
150
+ * any of them carries. An argument's closing brace is one character past its last node.
151
+ */
152
+ function withArguments(
153
+ m: TexNode & { readonly type: "macro" },
154
+ after: readonly TexNode[],
155
+ ): readonly [number, number][] {
156
+ const offsets = [
157
+ m.position?.start.offset,
158
+ m.position?.end.offset,
159
+ ...(m.args ?? []).map((a) => {
160
+ const last = a.content?.at(-1)?.position?.end.offset;
161
+ return last === undefined ? undefined : last + 1;
162
+ }),
163
+ takeWhile(after, isGroup).at(-1)?.position?.end.offset,
164
+ ].filter((o): o is number => o !== undefined);
165
+ return offsets.length === 0
166
+ ? []
167
+ : [[Math.min(...offsets), Math.max(...offsets)]];
168
+ }
169
+
170
+ /**
171
+ * The ranges of the cleveref definitions in the preamble and in the document body. `parse` is
172
+ * unified-latex's; a test hands in a tree with the fields the walk tolerates being absent.
173
+ */
174
+ export function crefDefinitionRanges(
175
+ raw: string,
176
+ {
177
+ parse = (s: string): TexRoot => getParser().parse(s),
178
+ }: { readonly parse?: (s: string) => TexRoot } = {},
179
+ ): readonly [number, number][] {
180
+ const root = parse(raw);
181
+ const doc = root.content.find(
182
+ (n): n is Extract<TexNode, { type: "environment" | "mathenv" }> =>
183
+ n.type === "environment" && n.env === "document",
184
+ );
185
+ const lists: readonly (readonly TexNode[])[] = [
186
+ root.content,
187
+ doc?.content ?? [],
188
+ ];
189
+ return lists.flatMap((list) =>
190
+ list.flatMap((n, i) =>
191
+ n.type === "macro" && CREF_DEFINITIONS.has(n.content)
192
+ ? withArguments(n, list.slice(i + 1))
193
+ : [],
194
+ ),
195
+ );
125
196
  }
126
197
  const inside = (ranges: readonly [number, number][], i: number) =>
127
198
  ranges.some(([s, e]) => i >= s && i < e);
package/eslint.config.mjs CHANGED
@@ -428,6 +428,7 @@ const TYPESCRIPT_ONLY = [
428
428
  "test/*.{js,mjs,cjs}",
429
429
  "test/e2e/**/*.{js,mjs,cjs}",
430
430
  "test/fixtures/layers/src/**/*.{js,mjs,cjs}",
431
+ "fixtures/accepted-papers/**/*.{js,mjs,cjs}",
431
432
  "fixtures/real-markdown-paper/**/*.{js,mjs,cjs}",
432
433
  "skills/paper-pipeline/scripts/fixtures/**/*.{js,mjs,cjs}",
433
434
  "skills/plan-paper-timeline/fixtures/**/*.{js,mjs,cjs}",
@@ -1,8 +1,9 @@
1
1
  /**
2
- * ONE reader of `baseline.json`, shared by the two runs that compare against it: the harness
3
- * beside this file (the repository's own `bin/paperlint.mjs`) and `test/e2e/install/install.e2e.ts` (the binary
4
- * a consumer actually got). Two copies of "growth fails, a drop never does" would drift the first
5
- * time one of them is tightened, and the two runs would then disagree about the same article.
2
+ * ONE reader of `baseline.json`, shared by every run that compares against one: the harness beside
3
+ * this file (the repository's own `bin/paperlint.mjs`), `test/e2e/install/install.e2e.ts` (the
4
+ * binary a consumer actually got), and `fixtures/accepted-papers/accepted-papers.test.ts` (one
5
+ * baseline per accepted paper). Two copies of "growth fails, a drop never does" would drift the
6
+ * first time one of them is tightened, and the runs would then disagree about the same rules.
6
7
  */
7
8
  import { readFileSync } from "node:fs";
8
9
  import { dirname, join } from "node:path";
@@ -21,10 +22,10 @@ const LintOutput = z.array(
21
22
 
22
23
  const HERE = dirname(fileURLToPath(import.meta.url));
23
24
 
24
- /** The recorded counts, `{ruleId: n}`. */
25
- export function recordedFindings(): Counts {
25
+ /** The counts recorded in `dir`'s `baseline.json` (this article's by default), `{ruleId: n}`. */
26
+ export function recordedFindings(dir: string = HERE): Counts {
26
27
  return Baseline.parse(
27
- JSON.parse(readFileSync(join(HERE, "baseline.json"), "utf8")),
28
+ JSON.parse(readFileSync(join(dir, "baseline.json"), "utf8")),
28
29
  ).findings;
29
30
  }
30
31
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "paperlint",
3
- "version": "4.1.0",
3
+ "version": "4.2.0",
4
4
  "description": "A linter for scientific papers written in LaTeX: catches mistakes before you submit to a conference or journal.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -110,6 +110,7 @@
110
110
  "eslint-rules",
111
111
  "eslint.config.mjs",
112
112
  "fixtures",
113
+ "!fixtures/accepted-papers",
113
114
  "!fixtures/real-markdown-paper",
114
115
  "fixtures/real-markdown-paper/baseline.*",
115
116
  "hooks",