paperlint 2.1.0 → 3.0.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/CLAUDE.md +6 -1
- package/README.md +233 -224
- package/action.yml +4 -6
- package/dist/adapters/references/index.d.ts +13 -0
- package/dist/adapters/references/index.d.ts.map +1 -0
- package/dist/adapters/references/index.js +55 -0
- package/dist/adapters/references/index.js.map +1 -0
- package/dist/adapters/references/reach.io.d.ts +3 -0
- package/dist/adapters/references/reach.io.d.ts.map +1 -0
- package/dist/adapters/references/reach.io.js +14 -0
- package/dist/adapters/references/reach.io.js.map +1 -0
- package/dist/build.d.ts +15 -0
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +38 -4
- package/dist/build.js.map +1 -1
- package/dist/cli.d.ts +28 -25
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +277 -265
- package/dist/cli.js.map +1 -1
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +40 -72
- package/dist/doctor.js.map +1 -1
- package/dist/facts-file.d.ts +2 -2
- package/dist/facts-file.js +2 -2
- package/dist/hooks-settings.d.ts +0 -21
- package/dist/hooks-settings.d.ts.map +1 -1
- package/dist/hooks-settings.js +17 -135
- package/dist/hooks-settings.js.map +1 -1
- package/dist/init.d.ts +39 -29
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +143 -172
- package/dist/init.js.map +1 -1
- package/dist/link-skills.d.ts +1 -1
- package/dist/link-skills.d.ts.map +1 -1
- package/dist/link-skills.js +11 -29
- package/dist/link-skills.js.map +1 -1
- package/dist/new-paper.d.ts.map +1 -1
- package/dist/new-paper.js +2 -13
- package/dist/new-paper.js.map +1 -1
- package/dist/paper-files.d.ts +63 -0
- package/dist/paper-files.d.ts.map +1 -0
- package/dist/paper-files.js +69 -0
- package/dist/paper-files.js.map +1 -0
- package/dist/paper-settings.d.ts +13 -41
- package/dist/paper-settings.d.ts.map +1 -1
- package/dist/paper-settings.js +71 -71
- package/dist/paper-settings.js.map +1 -1
- package/dist/ports/check-references.d.ts +31 -0
- package/dist/ports/check-references.d.ts.map +1 -0
- package/dist/ports/check-references.js +7 -0
- package/dist/ports/check-references.js.map +1 -0
- package/dist/presets.d.ts +1 -1
- package/dist/presets.d.ts.map +1 -1
- package/dist/presets.js +4 -6
- package/dist/presets.js.map +1 -1
- package/dist/reference-rules.d.ts +47 -0
- package/dist/reference-rules.d.ts.map +1 -0
- package/dist/reference-rules.js +156 -0
- package/dist/reference-rules.js.map +1 -0
- package/dist/references.d.ts +36 -0
- package/dist/references.d.ts.map +1 -0
- package/dist/references.js +91 -0
- package/dist/references.js.map +1 -0
- package/dist/rules-config.d.ts +5 -3
- package/dist/rules-config.d.ts.map +1 -1
- package/dist/rules-config.js +15 -6
- package/dist/rules-config.js.map +1 -1
- package/dist/structure.js +3 -3
- package/dist/structure.js.map +1 -1
- package/dist/tex-requirements.js +2 -2
- package/dist/tex-requirements.js.map +1 -1
- package/dist/types.d.ts +20 -18
- package/dist/types.d.ts.map +1 -1
- package/dist/venue-rules.d.ts.map +1 -1
- package/dist/venue-rules.js +11 -9
- package/dist/venue-rules.js.map +1 -1
- package/docs/configuration.md +119 -104
- package/docs/e2e.md +1 -1
- package/docs/install.md +25 -40
- package/docs/optional-rules.md +5 -4
- package/docs/rules.md +60 -23
- package/eslint-rules/bib-reachable-entry.mjs +75 -0
- package/eslint-rules/latex-language.mjs +29 -1
- package/eslint-rules/paper-stages.harness.mjs +1 -117
- package/eslint-rules/paper-stages.mjs +0 -120
- package/eslint-rules/paper-stages.mutations.mjs +0 -76
- package/eslint-rules/paper-typography.mjs +267 -192
- package/eslint-rules/paper-typography.test.mjs +297 -0
- package/eslint-rules/papers.harness.mjs +8 -12
- package/eslint-rules/papers.mjs +17 -31
- package/eslint-rules/pdf-last-page-balance.mjs +4 -7
- package/eslint-rules/review-frontmatter.mjs +118 -0
- package/eslint-rules/review-frontmatter.schema.json +36 -0
- package/eslint-rules/review-frontmatter.test.mjs +118 -0
- package/eslint-rules/sibling-frontmatter.mjs +19 -0
- package/eslint-rules/sibling-frontmatter.schema.json +14 -0
- package/eslint.config.mjs +0 -15
- package/fixtures/real-markdown-paper/baseline.json +6 -7
- package/hooks/hooks.harness.mjs +39 -98
- package/hooks/hooks.mutations.mjs +6 -6
- package/hooks/paper-edit-guard.hook.d.mts +2 -3
- package/hooks/paper-edit-guard.hook.mjs +31 -42
- package/hooks/paper-skills-nudge.hook.mjs +21 -19
- package/hooks/paper-status-gates.hook.mjs +21 -19
- package/hooks/paper-status-gates.sh +8 -13
- package/lib/paper-config.d.mts +15 -25
- package/lib/paper-config.harness.mjs +18 -35
- package/lib/paper-config.mjs +83 -105
- package/lib/paper-config.mutations.mjs +2 -2
- package/lib/skill-checks.mjs +1 -1
- package/lib/skill-trigger-cases.harness.mjs +9 -8
- package/lib/skill-trigger-cases.mjs +7 -15
- package/package.json +1 -1
- package/scripts/eslint-report-guard.mjs +1 -1
- package/scripts/harness-api.frozen.json +0 -3
- package/scripts/mutation-batteries.frozen.json +4 -13
- package/skills/analyze-sibling-paper/SKILL.md +16 -12
- package/skills/analyze-sibling-paper/SKILL.md.spec.ts +15 -11
- package/skills/cold-read-diff/SKILL.md +20 -1
- package/skills/cold-read-diff/SKILL.md.spec.ts +19 -0
- package/skills/grade-paper-writing/SKILL.md +20 -1
- package/skills/grade-paper-writing/SKILL.md.spec.ts +19 -0
- package/skills/paper-pipeline/scripts/consumer.d.mts +0 -1
- package/skills/paper-pipeline/scripts/consumer.harness.mjs +8 -12
- package/skills/paper-pipeline/scripts/consumer.mjs +19 -33
- package/skills/paper-pipeline/scripts/extract-ref-facts.harness.mjs +6 -4
- package/skills/paper-pipeline/scripts/run-mechanical.mjs +2 -11
- package/skills/plan-paper-timeline/SKILL.md +2 -2
- package/skills/plan-paper-timeline/SKILL.md.spec.ts +1 -1
- package/skills/plan-paper-timeline/plan-paper-timeline.effects.harness.mjs +1 -1
- package/skills/plan-paper-timeline/plan-paper-timeline.effects.mutations.mjs +2 -2
- package/skills/render-paper/check-render.sh +2 -3
- package/skills/render-paper/render-paper.harness.mjs +2 -2
- package/skills/verify-citations/SKILL.md +10 -1
- package/skills/verify-citations/SKILL.md.spec.ts +9 -0
- package/skills/verify-citations/scripts/bib-authors.mjs +48 -26
- package/src/adapters/references/index.ts +102 -0
- package/src/adapters/references/reach.io.ts +12 -0
- package/src/build.harness.mjs +8 -4
- package/src/build.ts +62 -6
- package/src/cli.harness.mjs +147 -292
- package/src/cli.mutations.mjs +35 -44
- package/src/cli.ts +344 -304
- package/src/doctor.harness.mjs +41 -84
- package/src/doctor.mutations.mjs +9 -9
- package/src/doctor.ts +44 -89
- package/src/facts-file.test.ts +0 -7
- package/src/facts-file.ts +2 -2
- package/src/hooks-settings.harness.mjs +7 -92
- package/src/hooks-settings.mutations.mjs +2 -17
- package/src/hooks-settings.ts +18 -162
- package/src/init.test.ts +206 -0
- package/src/init.ts +186 -230
- package/src/link-skills.harness.mjs +1 -38
- package/src/link-skills.mutations.mjs +9 -5
- package/src/link-skills.ts +10 -34
- package/src/lint-fix.test.ts +120 -0
- package/src/new-paper.test.ts +1 -13
- package/src/new-paper.ts +2 -17
- package/src/paper-files.test.ts +290 -0
- package/src/paper-files.ts +144 -0
- package/src/paper-settings-commands.test.ts +84 -121
- package/src/paper-settings.test.ts +93 -64
- package/src/paper-settings.ts +99 -97
- package/src/ports/check-references.ts +28 -0
- package/src/presets.ts +5 -15
- package/src/reference-rules.ts +229 -0
- package/src/references.test.ts +209 -0
- package/src/references.ts +138 -0
- package/src/rules-config.harness.mjs +24 -8
- package/src/rules-config.ts +19 -7
- package/src/structure.harness.mjs +3 -1
- package/src/structure.ts +3 -3
- package/src/tex-requirements.ts +2 -2
- package/src/types.ts +30 -18
- package/src/venue-rules.test.ts +20 -11
- package/src/venue-rules.ts +11 -13
- package/eslint-rules/doc-fields.harness.mjs +0 -336
- package/eslint-rules/doc-fields.mjs +0 -186
- package/eslint-rules/doc-fields.mutations.mjs +0 -96
- package/eslint-rules/paper-typography.harness.mjs +0 -291
- package/eslint-rules/paper-typography.mutations.mjs +0 -131
- package/eslint-rules/review-findings-cause.harness.mjs +0 -228
- package/eslint-rules/review-findings-cause.mjs +0 -135
- package/eslint-rules/review-findings-cause.mutations.mjs +0 -72
- package/fixtures/paper-stages/authors-ran/PIPELINE-STATUS.md +0 -16
- package/fixtures/paper-stages/marker-in-prose/PIPELINE-STATUS.md +0 -17
- package/fixtures/review-findings-cause/clean.md +0 -17
- package/fixtures/review-findings-cause/defect.md +0 -14
- package/fixtures/review-findings-cause/old-debt.md +0 -14
- package/fixtures/review-findings-cause/quiet-in-fence.md +0 -16
package/CLAUDE.md
CHANGED
|
@@ -193,7 +193,7 @@ the CONFIG is not declaring something. Check that before adding a verb.
|
|
|
193
193
|
|
|
194
194
|
`npm i -D paperlint` brings all the code — rules, skills, hooks, scripts. `paperlint init`
|
|
195
195
|
then does what only a command can, because it depends on the project it lands in: it finds the
|
|
196
|
-
papers directory and declares it in `
|
|
196
|
+
papers directory and declares it in a root `paperlint.json` when it is not the default `papers`, links each skill into `.claude/skills/`, writes
|
|
197
197
|
the hook commands into `.claude/settings.json` (vigiles' `mergeRegistrations`, reading
|
|
198
198
|
`plugin/hooks/hooks.json` as the one source), and offers a CI workflow pinned to the installed
|
|
199
199
|
release's tag. `paperlint doctor` reads all of it back. Details: `docs/install.md`.
|
|
@@ -520,6 +520,11 @@ import none of the three are frozen in `scripts/harness-api.frozen.json`, which
|
|
|
520
520
|
exits 1 when no file matches, and it transpiles without type-checking, so `npm run check` runs
|
|
521
521
|
`tsc -p tsconfig.test.json` as its own gate.
|
|
522
522
|
|
|
523
|
+
**Local = the fast gates on what you touched; the full `npm run check` = CI.** Locally run vitest on
|
|
524
|
+
the touched test files, `npx tsc --noEmit`, `npx eslint <touched files>` and `npm run fmt:check`, then
|
|
525
|
+
push and read CI by job name. The repo is public, so CI is free, and it also runs the TeX e2e that
|
|
526
|
+
cannot run locally; a local full run takes 10-15 min, most of it the mutation batteries (#52).
|
|
527
|
+
|
|
523
528
|
⚠️ **Not `vigiles test .`** — the `.` is read as a FILE, the runner dies with
|
|
524
529
|
`ERR_UNSUPPORTED_DIR_IMPORT`, and it still exits 0. See the measured table below.
|
|
525
530
|
|
package/README.md
CHANGED
|
@@ -1,297 +1,306 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
README style — keep it scannable, not a wall of text:
|
|
3
|
+
- One idea per paragraph; paragraphs ≤ 3 lines. Split anything longer.
|
|
4
|
+
- Every section starts with a heading (##); sub-topics get ###. No section longer than one screen.
|
|
5
|
+
- Lists over prose for anything with 3+ items; bullets ≤ 2 lines.
|
|
6
|
+
- Tables for comparisons (commands, venues, checks). Code blocks for every command and file.
|
|
7
|
+
- A blank line between every block. Bold only for the one phrase a skimmer must see.
|
|
8
|
+
- Mechanics and edge cases live in docs/, linked — not inline.
|
|
9
|
+
- A reader must be able to answer "what is it, which venues, how do I start" from the first screen.
|
|
10
|
+
- Sparse emoji are fine where they help rhythm and scanning (e.g. one per section heading or feature bullet); never decorative, never several in a row.
|
|
11
|
+
-->
|
|
12
|
+
|
|
1
13
|
# paperlint
|
|
2
14
|
|
|
3
15
|
[](https://www.npmjs.com/package/paperlint)
|
|
4
16
|

|
|
5
17
|
|
|
6
|
-
A linter for scientific papers written in LaTeX
|
|
18
|
+
**A linter for scientific papers written in LaTeX.** It catches the mechanical mistakes that get a
|
|
7
19
|
paper desk-rejected or sent back at camera-ready, before you submit.
|
|
8
20
|
|
|
9
|
-
A LaTeX paper can build without an error and still be wrong
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
- **
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
21
|
+
A LaTeX paper can build without an error and still be wrong: a missing font package silently
|
|
22
|
+
changes the font, another template version changes the pagination, the submitted PDF gets
|
|
23
|
+
overwritten. paperlint checks for these on your machine and in CI:
|
|
24
|
+
|
|
25
|
+
- 📏 **Checks against your venue.** Page limit, embedded fonts, paper size, columns and font sizes,
|
|
26
|
+
as the call for papers sets them.
|
|
27
|
+
- 🧱 **Builds the same PDF everywhere.** `paperlint toolchain` installs TeX Live with exactly the
|
|
28
|
+
packages your venue's template needs.
|
|
29
|
+
- 📌 **Keeps what you submitted.** Record the PDF you sent, and paperlint fails if it changes or
|
|
30
|
+
disappears, or its LaTeX source was not kept.
|
|
31
|
+
- 🔗 **Checks your references online.** At build time: each cited work exists, and its author list
|
|
32
|
+
is the published version's.
|
|
33
|
+
- ✏️ **Knows the classic slips.** `§` instead of "Section", `.05` instead of `0.05`.
|
|
34
|
+
`paperlint lint --fix` fixes them.
|
|
35
|
+
|
|
36
|
+
It is built on ESLint: the checks are ESLint rules over `.tex` and `.md` files, named like
|
|
37
|
+
`paper/leading-zero`. You do not need to know ESLint to use it.
|
|
38
|
+
|
|
39
|
+
## Contents
|
|
40
|
+
|
|
41
|
+
- [Supported venues](#-supported-venues)
|
|
42
|
+
- [Skills](#-skills)
|
|
43
|
+
- [Getting started](#-getting-started)
|
|
44
|
+
- [Commands](#-commands)
|
|
45
|
+
- [Configuration](#-configuration)
|
|
46
|
+
- [Run it in CI](#-run-it-in-ci)
|
|
47
|
+
- [FAQ](#-faq)
|
|
48
|
+
- [Docs](#-docs)
|
|
49
|
+
|
|
50
|
+
## 🎯 Supported venues
|
|
51
|
+
|
|
52
|
+
A preset holds a venue's format and page limits. Its **kind** is the paper type the venue sets a
|
|
53
|
+
limit for — `short`, `full`, `research` — named once per paper in its `paperlint.json`.
|
|
54
|
+
|
|
55
|
+
| preset | venue | format | page limit |
|
|
56
|
+
| ----------------------- | ------------------ | -------------------------------- | -------------------------------------------------------------- |
|
|
57
|
+
| `paperlint:acm-sigconf` | any ACM conference | ACM two-column conference format | not checked: the family sets no kinds |
|
|
58
|
+
| `paperlint:agenticdev` | AgenticDev @ ASE | ACM two-column conference format | `short` 5, `full` 10, `demo` 5 body pages, + 2 of references |
|
|
59
|
+
| `paperlint:aisec` | AISec @ ACM CCS | ACM two-column conference format | 10 body pages + 2 (`research`, `benchmark`, `position`, `sok`) |
|
|
60
|
+
| `paperlint:realm` | REALM @ EMNLP | ACL two-column format, A4 | `long` 8, `short` 4 — recorded, not checked (below) |
|
|
61
|
+
|
|
62
|
+
REALM's limit is recorded but not checked because ACL leaves the Limitations and Ethics sections
|
|
63
|
+
out of the page count, and the PDF measurement counts them as body pages: a paper within the limit
|
|
64
|
+
would fail.
|
|
65
|
+
|
|
66
|
+
Another venue: [a four-line preset file](#another-venue).
|
|
67
|
+
|
|
68
|
+
## 🧠 Skills
|
|
69
|
+
|
|
70
|
+
paperlint has two halves:
|
|
71
|
+
|
|
72
|
+
1. **The linter** — `lint` and `build` — is deterministic: the same paper gives the same verdict,
|
|
73
|
+
so it belongs in CI.
|
|
74
|
+
2. **The skills** help with the work itself, where the answer is a judgment call. They are
|
|
75
|
+
optional; `paperlint init` installs them for [Claude Code](https://claude.com/claude-code).
|
|
76
|
+
|
|
77
|
+
- **Start here** — run the whole process step by step (`paper-pipeline`), or ask where the paper
|
|
78
|
+
stands (`paper-status`).
|
|
79
|
+
- **Judge the idea** — is it worth doing (`research-ideate`), who else works on it
|
|
80
|
+
(`map-prior-work`), read a close competitor in depth (`analyze-sibling-paper`).
|
|
81
|
+
- **Pick a venue** — find where to send it (`find-venue`), see what gets accepted there
|
|
82
|
+
(`study-accepted-papers`), put the deadlines in your calendar (`plan-paper-timeline`).
|
|
83
|
+
- **Do the study and write** — design the study and its artifact (`build-benchmark`), write the
|
|
84
|
+
draft (`draft-paper`), fix the outline (`argument-arc`), cut it down (`tighten-paper`).
|
|
85
|
+
- **Review before you submit** — a reader with no context (`cold-read-diff`), the prose
|
|
86
|
+
(`grade-paper-writing`), a hostile reviewer (`paper-adversarial-review`), a simulated committee
|
|
87
|
+
(`pc-panel-review`), the references (`verify-citations`), the final check (`harden-paper`).
|
|
88
|
+
- **Submit and after** — render pages to images (`render-paper`), submit (`submit-paper`), upload
|
|
89
|
+
the artifact (`osf-artifact-upload`), camera-ready (`camera-ready`), the next paper (`extend-paper`).
|
|
90
|
+
|
|
91
|
+
## 🚀 Getting started
|
|
37
92
|
|
|
38
93
|
<!-- `vigiles:symbol src/init.ts#init` — `npm run check` fails if this function is renamed or removed. -->
|
|
39
94
|
|
|
40
|
-
|
|
41
|
-
npm i -D paperlint
|
|
42
|
-
npx paperlint init
|
|
43
|
-
```
|
|
95
|
+
1. Install (Node 22.13 or newer):
|
|
44
96
|
|
|
45
|
-
|
|
46
|
-
|
|
97
|
+
```sh
|
|
98
|
+
npm i -D paperlint
|
|
99
|
+
```
|
|
47
100
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
asks questions only when you run it in a terminal; an agent, CI or `--yes` gets the defaults, and
|
|
51
|
-
each default it takes is printed. It ends by running `paperlint doctor`, which checks the setup.
|
|
52
|
-
Exactly what it writes: [`docs/install.md`](docs/install.md#what-paperlint-init-writes).
|
|
101
|
+
2. Set up — it finds your papers directory, offers a CI workflow and a first paper, and (with
|
|
102
|
+
Claude Code) links the skills:
|
|
53
103
|
|
|
54
|
-
|
|
104
|
+
```sh
|
|
105
|
+
npx paperlint init
|
|
106
|
+
```
|
|
55
107
|
|
|
56
|
-
|
|
57
|
-
| ----------------------------- | -------------------------------------------------------------------------------------------------- |
|
|
58
|
-
| `npx paperlint init` | sets the project up (see above) |
|
|
59
|
-
| `npx paperlint new my-paper` | creates a paper folder from a template; never overwrites a file |
|
|
60
|
-
| `npx paperlint lint` | runs every check over your papers; `npx paperlint lint papers/my-paper` checks one |
|
|
61
|
-
| `npx paperlint build <paper>` | compiles `paper.tex` to `paper.pdf` with pdflatex and bibtex; `--all` builds every paper |
|
|
62
|
-
| `npx paperlint toolchain` | installs TeX Live with the LaTeX packages your venues need; `--check` only reports what is missing |
|
|
63
|
-
| `npx paperlint doctor` | checks the setup and exits non-zero if something is miswired |
|
|
64
|
-
| `npx paperlint --help` | every command and flag |
|
|
108
|
+
3. TeX Live, for building — once. `init` offers it; `paperlint lint` alone needs no TeX:
|
|
65
109
|
|
|
66
|
-
|
|
67
|
-
|
|
110
|
+
```sh
|
|
111
|
+
npx paperlint toolchain # ~270 MB, ~3 min, once
|
|
112
|
+
```
|
|
68
113
|
|
|
69
|
-
|
|
114
|
+
4. Create a paper:
|
|
70
115
|
|
|
71
|
-
|
|
116
|
+
<!-- `vigiles:symbol src/new-paper.ts#newPaper` — `npm run check` fails if this function is renamed or removed. -->
|
|
72
117
|
|
|
73
|
-
|
|
118
|
+
```sh
|
|
119
|
+
npx paperlint new my-paper
|
|
120
|
+
```
|
|
74
121
|
|
|
75
|
-
|
|
122
|
+
```
|
|
123
|
+
✓ created papers/my-paper
|
|
124
|
+
+ PIPELINE-STATUS.md (from the package template)
|
|
125
|
+
+ paper.tex (from the package template)
|
|
126
|
+
+ paperlint.json (from the package template)
|
|
127
|
+
```
|
|
76
128
|
|
|
77
|
-
|
|
78
|
-
npx paperlint new my-paper
|
|
79
|
-
```
|
|
129
|
+
5. Pick the venue ([the table above](#-supported-venues)) in `papers/my-paper/paperlint.json`:
|
|
80
130
|
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
+ paper.tex (from the package template)
|
|
85
|
-
+ paperlint.json (from the package template)
|
|
131
|
+
```json
|
|
132
|
+
{ "extends": "paperlint:agenticdev", "kind": "short" }
|
|
133
|
+
```
|
|
86
134
|
|
|
87
|
-
|
|
88
|
-
…/papers/my-paper/paper.tex
|
|
89
|
-
1:1 warning this paper names no venue preset yet, so its page limit, fonts and format are not checked — set "extends" in papers/my-paper/paperlint.json (e.g. "paperlint:agenticdev"; see docs/rules.md) pdf/measured
|
|
135
|
+
6. Build the PDF:
|
|
90
136
|
|
|
91
|
-
|
|
92
|
-
|
|
137
|
+
```sh
|
|
138
|
+
npx paperlint build papers/my-paper
|
|
139
|
+
```
|
|
93
140
|
|
|
94
|
-
|
|
141
|
+
7. Check every paper:
|
|
95
142
|
|
|
96
|
-
|
|
143
|
+
```sh
|
|
144
|
+
npx paperlint lint
|
|
145
|
+
```
|
|
97
146
|
|
|
98
|
-
|
|
99
|
-
papers/
|
|
100
|
-
my-paper/
|
|
101
|
-
paper.tex the paper, in LaTeX
|
|
102
|
-
PIPELINE-STATUS.md the paper's record: its research question and the stages it reached
|
|
103
|
-
paperlint.json this paper's settings: its venue preset and kind — `new` writes it
|
|
104
|
-
reviews/*.md review notes (optional)
|
|
105
|
-
versions/ the exact PDF and source you sent at each stage, never edited
|
|
106
|
-
```
|
|
147
|
+
Sample output, on a paper with two slips and no `PIPELINE-STATUS.md`:
|
|
107
148
|
|
|
108
|
-
|
|
109
|
-
|
|
149
|
+
```
|
|
150
|
+
papers/hand
|
|
151
|
+
error missing `PIPELINE-STATUS.md` — `paper/stages`, `paper/source` and `paper/research-question` read this file, so nothing `hand` declares about its stages, sources or research question is checked
|
|
152
|
+
…/papers/hand/paper.tex
|
|
153
|
+
3:4 warning `§` instead of the word «Section» — `paperlint lint --fix` writes it paper/section-word
|
|
154
|
+
3:19 warning `.05` has no leading zero — write `0.05` (IEEE / ISO 80000-1); `paperlint lint --fix` inserts it paper/leading-zero
|
|
110
155
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
```
|
|
156
|
+
✖ 2 problems (0 errors, 2 warnings)
|
|
157
|
+
0 errors and 2 warnings potentially fixable with the `--fix` option.
|
|
158
|
+
```
|
|
114
159
|
|
|
115
|
-
|
|
160
|
+
Errors fail the run (exit 1); warnings only print, unless you pass `--max-warnings <n>`. To keep
|
|
161
|
+
a deliberate exception, put the reason on the line above:
|
|
162
|
+
`% eslint-disable-next-line paper/leading-zero -- quoted from the reviewer`.
|
|
116
163
|
|
|
117
|
-
|
|
118
|
-
package.json "paperlint": { "papersDir": "papers" } the project
|
|
119
|
-
papers/my-paper/
|
|
120
|
-
paperlint.json { "extends": "paperlint:aisec", … } this paper
|
|
121
|
-
paperlint:aisec a venue preset: shipped, or ./your-venue.jsonc the venue
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
More in [`docs/configuration.md`](docs/configuration.md#three-levels-of-settings).
|
|
125
|
-
`paperlint.json` replaces `venue.json` (2.1.0); `npx paperlint init` moves it.
|
|
126
|
-
|
|
127
|
-
A **stage** is a point the paper has reached, such as `submitted` or `camera-ready` (the final
|
|
128
|
-
version for the proceedings). The name may use `a-z`, `0-9`, `.`, `_` and `-`. On a folder that
|
|
129
|
-
already exists, `paperlint new` adds only the missing files. To use your own templates, put files with
|
|
130
|
-
the same names in `papers/.template/`; `{{name}}` in them becomes the paper's name.
|
|
164
|
+
### 📌 When you submit
|
|
131
165
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
```sh
|
|
135
|
-
npx paperlint lint # check every paper
|
|
136
|
-
npx paperlint build papers/my-paper # writes papers/my-paper/paper.pdf
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
`paperlint build` runs pdflatex and bibtex until the references settle. There is no build script to
|
|
140
|
-
write; a `build.sh` in the paper folder is ignored.
|
|
141
|
-
|
|
142
|
-
When you submit, copy the PDF and `paper.tex` into `versions/` and record the stage in the front
|
|
143
|
-
matter of `PIPELINE-STATUS.md`, with the file sizes in bytes:
|
|
166
|
+
Copy the PDF and `paper.tex` into `versions/`, and record the stage in the front matter of
|
|
167
|
+
`PIPELINE-STATUS.md`. You write the sizes yourself (`wc -c < file`):
|
|
144
168
|
|
|
145
169
|
```yaml
|
|
146
170
|
stages:
|
|
147
171
|
- stage: submitted
|
|
148
172
|
date: 2026-07-22
|
|
149
|
-
venue: A Venue 2026
|
|
150
173
|
pdf: versions/2026-07-22-submitted.pdf
|
|
151
174
|
bytes: 305412
|
|
152
175
|
source: versions/2026-07-22-submitted.tex
|
|
153
176
|
sourceBytes: 57210
|
|
154
177
|
```
|
|
155
178
|
|
|
156
|
-
From then on `paperlint lint` fails if that PDF goes missing or changes size
|
|
157
|
-
change, so a size that no longer matches means the file was replaced after you recorded it
|
|
179
|
+
From then on `paperlint lint` fails if that PDF goes missing or changes size
|
|
158
180
|
([`docs/rules.md`](docs/rules.md#the-scorecards-bytes-and-sourcebytes)).
|
|
159
181
|
|
|
160
|
-
|
|
182
|
+
## 🧰 Commands
|
|
183
|
+
|
|
184
|
+
| command | what it does |
|
|
185
|
+
| ----------------------------- | ------------------------------------------------------------------------------ |
|
|
186
|
+
| `npx paperlint init` | sets the project up |
|
|
187
|
+
| `npx paperlint new my-paper` | creates a paper folder from a template; never overwrites a file |
|
|
188
|
+
| `npx paperlint lint` | runs every check over your papers; `--fix` fixes what can be fixed |
|
|
189
|
+
| `npx paperlint build <paper>` | compiles `paper.tex` to `paper.pdf`, measures it, checks the references online |
|
|
190
|
+
| `npx paperlint toolchain` | installs TeX Live with the packages your venues need (~270 MB, ~3 min, once) |
|
|
191
|
+
| `npx paperlint doctor` | checks the setup and exits non-zero if something is miswired |
|
|
192
|
+
| `npx paperlint --help` | every command and flag |
|
|
193
|
+
|
|
194
|
+
### 🔍 What the checks catch
|
|
161
195
|
|
|
162
|
-
|
|
196
|
+
| check | catches |
|
|
197
|
+
| --------------------- | ---------------------------------------------------------------------- |
|
|
198
|
+
| `pdf/fonts` | the template's fonts are missing — LaTeX silently used Computer Modern |
|
|
199
|
+
| `pdf/limits` | more pages than the venue allows for your kind of paper |
|
|
200
|
+
| `paper/stages` | the PDF you recorded as submitted changed or disappeared |
|
|
201
|
+
| `paper/source` | the LaTeX source of a submitted version was not kept |
|
|
202
|
+
| `bib/reachable-entry` | a reference with no DOI, URL or arXiv id |
|
|
203
|
+
| `paper/author-list` | a reference lists the preprint's authors, not the published version's |
|
|
204
|
+
|
|
205
|
+
Every check: [`docs/rules.md`](docs/rules.md). Checks only some venues need are off until you
|
|
206
|
+
turn them on: [`docs/optional-rules.md`](docs/optional-rules.md).
|
|
207
|
+
|
|
208
|
+
## 🧩 Configuration
|
|
209
|
+
|
|
210
|
+
Two levels, one file name, both optional:
|
|
163
211
|
|
|
164
212
|
```
|
|
165
|
-
|
|
166
|
-
papers/my-paper
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
213
|
+
paperlint.json the project: papersDir, rules, defaults for every paper
|
|
214
|
+
papers/my-paper/paperlint.json one paper: its venue, its kind, its own rules
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
`papersDir` defaults to `papers`. If your papers live elsewhere, say so in a `paperlint.json`
|
|
218
|
+
beside your `package.json`:
|
|
219
|
+
|
|
220
|
+
```json
|
|
221
|
+
{ "papersDir": "docs/papers" }
|
|
173
222
|
```
|
|
174
223
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
alone. The two warnings count typography slips against an allowance you can set per paper: going over
|
|
179
|
-
it is reported, fixing some is not ("paying the debt down is silent").
|
|
224
|
+
- A paper's file merges over the root's: its `extends` and `kind` win, its `rules` apply last.
|
|
225
|
+
- Only the paper files under `papersDir` are linted, never a `repro/` script beside a paper.
|
|
226
|
+
- An unknown key is an error, so a typo cannot silently turn a setting off.
|
|
180
227
|
|
|
181
|
-
|
|
182
|
-
only the warnings in files), or when it checked no files at all (usually a wrong path). Warnings
|
|
183
|
-
never fail the run unless you pass `--max-warnings <n>`. `--json` prints the findings as JSON.
|
|
228
|
+
Every key: [`docs/configuration.md`](docs/configuration.md).
|
|
184
229
|
|
|
185
|
-
|
|
230
|
+
### Another venue
|
|
186
231
|
|
|
187
|
-
|
|
232
|
+
Write a preset in your repository, and extend it by path from the paper's `paperlint.json`
|
|
233
|
+
(`"extends": "../../venues/my-venue.jsonc"`):
|
|
234
|
+
|
|
235
|
+
```jsonc
|
|
236
|
+
{
|
|
237
|
+
"extends": "paperlint:acm-sigconf",
|
|
238
|
+
"format": { "kinds": { "short": { "body_pages_max": 4 } } },
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
The full shape: [`docs/rules.md`](docs/rules.md#writing-your-own-venue-preset).
|
|
243
|
+
|
|
244
|
+
## 🤖 Run it in CI
|
|
245
|
+
|
|
246
|
+
`paperlint init` offers to write this workflow for you, pinned to the version you installed. By
|
|
247
|
+
hand:
|
|
188
248
|
|
|
189
249
|
```yaml
|
|
190
|
-
- uses: zernie/paperlint@
|
|
250
|
+
- uses: zernie/paperlint@v3.0.0
|
|
191
251
|
with:
|
|
192
252
|
paths: papers
|
|
193
253
|
```
|
|
194
254
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
`paperlint lint`. `paths` is required, and the step fails if it checked zero files, so a typo in the path
|
|
198
|
-
shows up red. Optional inputs: `config`, `max-warnings` (default `-1`, no limit), `texcount` (default
|
|
199
|
-
`true`), `working-directory`.
|
|
200
|
-
|
|
201
|
-
## What the checks catch
|
|
202
|
-
|
|
203
|
-
| check | level | catches |
|
|
204
|
-
| ------------------------------ | ------- | ---------------------------------------------------------------------------------------------------------------- |
|
|
205
|
-
| `paper/stages` | error | a stage's PDF is missing, or it is not the same file any more (its size changed) |
|
|
206
|
-
| `paper/source` | error | a stage has no frozen source file next to its PDF |
|
|
207
|
-
| `paper/author-list` | warning | a stage is declared, but `PIPELINE-STATUS.md` does not record that the author list was checked |
|
|
208
|
-
| `paper/research-question` | warning | the research question is missing from `PIPELINE-STATUS.md`, or the paper does not contain that sentence |
|
|
209
|
-
| `paper/typography` | warning | more `§`, `.05`-style decimals, mixed `Fig.`/`Figure`, or references without a DOI or URL than you allowed |
|
|
210
|
-
| `tex/future-promise` | warning | a camera-ready still says your code "will be released" |
|
|
211
|
-
| `tex/acm-frontmatter-override` | error | an ACM paper overrides the template's title-page commands, so parts of page 1 go missing |
|
|
212
|
-
| `review/findings-cause` | error | a review note lists several findings and names no cause for any of them |
|
|
213
|
-
| `doc/fields` | warning | a review note's front matter is missing a field you require (off unless configured) |
|
|
214
|
-
| `pdf/limits` | error | more body or reference pages than the venue allows for your kind of paper, or a reference font size out of range |
|
|
215
|
-
| `pdf/fonts` | error | a Type 3 or unembedded font, or the venue template's fonts are missing (a silent Computer Modern fallback) |
|
|
216
|
-
| `pdf/geometry` | error | the paper size or column count differs from the venue's |
|
|
217
|
-
| `pdf/body-size` | warning | the body font size is off the venue's |
|
|
218
|
-
| `pdf/profile` | error | the paper's `extends` names no preset (a typo), or a kind of paper the venue does not have |
|
|
219
|
-
| `pdf/fresh` | error | the build facts describe an earlier PDF than the one on disk |
|
|
220
|
-
| `pdf/measured` | warning | the venue checks did not run: the paper names no venue preset yet, or was not built |
|
|
221
|
-
|
|
222
|
-
The `pdf/` checks run only for a paper whose `paperlint.json` extends a venue preset, and they judge the PDF
|
|
223
|
-
`paperlint build` made: build, then lint. Errors fail the run; warnings only print. What each check
|
|
224
|
-
reads: [`docs/rules.md`](docs/rules.md).
|
|
225
|
-
Checks that only some venues need are off until you turn them on:
|
|
226
|
-
[`docs/optional-rules.md`](docs/optional-rules.md).
|
|
227
|
-
|
|
228
|
-
## Configuration
|
|
229
|
-
|
|
230
|
-
`paperlint init` writes the one required setting into `package.json`:
|
|
255
|
+
- Pin the tag of the version you installed: `npm ls paperlint` prints it.
|
|
256
|
+
- The step runs `paperlint lint`. It does not build, so CI needs no TeX Live.
|
|
231
257
|
|
|
232
|
-
|
|
233
|
-
{
|
|
234
|
-
"paperlint": {
|
|
235
|
-
"papersDir": "papers"
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
```
|
|
258
|
+
## ❓ FAQ
|
|
239
259
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
[`docs/configuration.md`](docs/configuration.md). TeX Live, its install location and the external
|
|
244
|
-
programs the skills use are in [`docs/toolchain.md`](docs/toolchain.md).
|
|
260
|
+
**Does it install anything without asking?**
|
|
261
|
+
No. TeX Live comes only from `paperlint toolchain`, or when you say yes in `init` or `build`. On
|
|
262
|
+
Windows, install TeX Live yourself.
|
|
245
263
|
|
|
246
|
-
|
|
264
|
+
**Will `new` or `init` overwrite my files?**
|
|
265
|
+
No. They only add what is missing, and `init` keeps a `papersDir` you already declared.
|
|
247
266
|
|
|
248
|
-
|
|
267
|
+
**My venue isn't listed — what now?**
|
|
268
|
+
Write [a four-line preset](#another-venue) that extends the closest template family. For any ACM
|
|
269
|
+
venue, `paperlint:acm-sigconf` already checks the format, without a page limit.
|
|
249
270
|
|
|
250
|
-
**
|
|
251
|
-
|
|
252
|
-
it routes to the rest. Some call Java or Python 3, which you install yourself.
|
|
271
|
+
**Do I need TeX Live just to lint?**
|
|
272
|
+
No. `paperlint lint` needs only Node. `paperlint build` needs TeX Live.
|
|
253
273
|
|
|
254
|
-
**
|
|
255
|
-
|
|
274
|
+
**What does a CI failure look like?**
|
|
275
|
+
The step fails, and its log lists each finding with file, line, check and message. It also fails
|
|
276
|
+
when it checked zero files, so a wrong `paths` shows up red.
|
|
256
277
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
| `paper-edit-guard` | yes | stops a shell command from writing to a paper file |
|
|
260
|
-
| `paper-skills-nudge` | no | after a paper edit, shows the agent the pre-submission checklist |
|
|
261
|
-
| `paper-status-gates` | no | after a paper edit, lists the stages that have not run yet |
|
|
278
|
+
**Several papers for different venues in one repo?**
|
|
279
|
+
Yes. Each paper names its own venue in its own `paperlint.json`.
|
|
262
280
|
|
|
263
|
-
**
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
with a normal file edit — those are not blocked.
|
|
281
|
+
**Where does my configuration live?**
|
|
282
|
+
In `paperlint.json` — at the project root (optional) and in each paper. Nothing goes into
|
|
283
|
+
`package.json`.
|
|
267
284
|
|
|
268
|
-
|
|
285
|
+
**Do I need Claude Code?**
|
|
286
|
+
No. The linter needs only Node. With Claude Code, `init` also links the skills and wires three
|
|
287
|
+
hooks into `.claude/settings.json`: one stops a shell command from writing to a paper file, two
|
|
288
|
+
remind the agent what is left after a paper edit ([`docs/install.md`](docs/install.md)).
|
|
269
289
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
- **It does not guess what to check.** There is no default papers directory.
|
|
274
|
-
- **It does not overwrite your files.** `paperlint new` and `paperlint init` only add what is missing.
|
|
275
|
-
- **It does not run your build script.** `paperlint build` compiles the paper itself.
|
|
276
|
-
- **It does not write or grade the paper.** `paperlint lint` checks records and a few mechanical
|
|
277
|
-
mistakes; judging the writing is what the optional skills are for.
|
|
278
|
-
- **New papers are LaTeX.** Markdown papers (`paper.md`) are still read but deprecated
|
|
279
|
-
([#57](https://github.com/zernie/paperlint/issues/57)).
|
|
280
|
-
- **No Yarn Plug'n'Play.** npm and pnpm are supported
|
|
281
|
-
([`docs/install.md`](docs/install.md#package-managers)).
|
|
290
|
+
**Does it change my paper?**
|
|
291
|
+
Only `paperlint lint --fix`, and only three rules: `paper/section-word` (`§` → Section),
|
|
292
|
+
`paper/leading-zero` (`.05` → `0.05`) and `paper/figure-ref-style` (one figure-reference style).
|
|
282
293
|
|
|
283
|
-
##
|
|
294
|
+
## 📚 Docs
|
|
284
295
|
|
|
285
|
-
|
|
286
|
-
every
|
|
287
|
-
|
|
296
|
+
- [`docs/install.md`](docs/install.md) — what `init` does, package managers, troubleshooting
|
|
297
|
+
- [`docs/configuration.md`](docs/configuration.md) — every setting, and how `build` compiles
|
|
298
|
+
- [`docs/rules.md`](docs/rules.md) — every check, what it reads and when it fails
|
|
299
|
+
- [`docs/optional-rules.md`](docs/optional-rules.md) — checks only some venues need
|
|
300
|
+
- [`docs/toolchain.md`](docs/toolchain.md) — TeX Live, and Banal (HotCRP's page-geometry checker, GPL)
|
|
301
|
+
- [`CONTRIBUTING.md`](CONTRIBUTING.md) — how the package is tested and released
|
|
288
302
|
|
|
289
303
|
## License
|
|
290
304
|
|
|
291
|
-
MIT.
|
|
292
|
-
|
|
293
|
-
**banal is not part of this package.** banal, the page-geometry script from
|
|
294
|
-
[HotCRP](https://github.com/kohler/hotcrp) (Geoffrey M. Voelker, Eddie Kohler), is licensed
|
|
295
|
-
GPL-2.0-or-later. paperlint does not contain, copy or modify it: `paperlint toolchain` downloads it from HotCRP
|
|
296
|
-
at a pinned commit, checks its sha256, and paperlint runs it as a separate program (`perl banal …`),
|
|
297
|
-
reading its JSON output. Details: [`docs/toolchain.md`](docs/toolchain.md#page-geometry-banal-without-poppler).
|
|
305
|
+
MIT. Banal, used for page geometry, is GPL and not part of this package:
|
|
306
|
+
[`docs/toolchain.md`](docs/toolchain.md#page-geometry-banal-without-poppler).
|
package/action.yml
CHANGED
|
@@ -26,11 +26,9 @@ description: Install the toolchain the texcount/* rules need, run ESLint, and re
|
|
|
26
26
|
inputs:
|
|
27
27
|
config:
|
|
28
28
|
description: >-
|
|
29
|
-
Path to the `
|
|
30
|
-
the way eslint and tsc find theirs, so
|
|
31
|
-
|
|
32
|
-
ESLint FLAT CONFIG and defaulted to `eslint.config.mjs`; a caller still passing one will
|
|
33
|
-
fail loudly on the first run rather than lint against it.
|
|
29
|
+
Path to the project's root `paperlint.json`. Optional, and so is the file: `paperlint lint`
|
|
30
|
+
finds it by walking up from the working directory, the way eslint and tsc find theirs, so
|
|
31
|
+
most callers never set this. Pass it only when the file is somewhere the walk cannot reach.
|
|
34
32
|
required: false
|
|
35
33
|
default: ""
|
|
36
34
|
paths:
|
|
@@ -135,4 +133,4 @@ runs:
|
|
|
135
133
|
npx paperlint lint $PAPERLINT_PATHS ${PAPERLINT_CONFIG:+--config "$PAPERLINT_CONFIG"} \
|
|
136
134
|
--max-warnings="$PAPERLINT_MAXWARN" --json > "$RUNNER_TEMP/paperlint-report.json" || RC=$?
|
|
137
135
|
node "$GITHUB_ACTION_PATH/scripts/eslint-report-guard.mjs" \
|
|
138
|
-
"$RUNNER_TEMP/paperlint-report.json" "$RC" "$PAPERLINT_PATHS" "${PAPERLINT_CONFIG:-
|
|
136
|
+
"$RUNNER_TEMP/paperlint-report.json" "$RC" "$PAPERLINT_PATHS" "${PAPERLINT_CONFIG:-paperlint.json}"
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The online reference checks, as the `CheckReferences` port: `verify-cites` (the cited work
|
|
3
|
+
* exists, the title matches — Crossref, OpenAlex, Semantic Scholar, arXiv) and `bib-authors` (the
|
|
4
|
+
* authors are the published version's — DBLP). Both ship in this package's verify-citations skill;
|
|
5
|
+
* this adapter only runs them and shapes their answers.
|
|
6
|
+
*
|
|
7
|
+
* "Not checked" is decided up front, by one request: when Crossref cannot be reached at all, the
|
|
8
|
+
* checkers would degrade every entry to `unresolvable` / `unchecked`, which reads like a result.
|
|
9
|
+
* Saying `not-checked` with the reason is the honest record.
|
|
10
|
+
*/
|
|
11
|
+
import type { CheckReferences } from "../../ports/check-references.ts";
|
|
12
|
+
export declare const onlineReferences: CheckReferences;
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/adapters/references/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EACV,eAAe,EAEhB,MAAM,iCAAiC,CAAC;AAwEzC,eAAO,MAAM,gBAAgB,EAAE,eAgB9B,CAAC"}
|