paperlint 8.0.0 → 9.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 +9 -25
- package/CONTRIBUTING.md +5 -4
- package/README.md +4 -3
- package/dist/adapters/bibtex/index.d.ts +3 -0
- package/dist/adapters/bibtex/index.d.ts.map +1 -0
- package/dist/adapters/bibtex/index.js +103 -0
- package/dist/adapters/bibtex/index.js.map +1 -0
- package/dist/adapters/latex/filecontents.d.ts +33 -0
- package/dist/adapters/latex/filecontents.d.ts.map +1 -0
- package/dist/adapters/latex/filecontents.js +65 -0
- package/dist/adapters/latex/filecontents.js.map +1 -0
- package/dist/adapters/latex/includes.d.ts +3 -3
- package/dist/adapters/latex/includes.d.ts.map +1 -1
- package/dist/adapters/latex/includes.js +18 -10
- package/dist/adapters/latex/includes.js.map +1 -1
- package/dist/adapters/latex/index.d.ts.map +1 -1
- package/dist/adapters/latex/index.js +2 -0
- package/dist/adapters/latex/index.js.map +1 -1
- package/dist/adapters/latex/nodes.d.ts +12 -0
- package/dist/adapters/latex/nodes.d.ts.map +1 -1
- package/dist/adapters/latex/nodes.js +39 -0
- package/dist/adapters/latex/nodes.js.map +1 -1
- package/dist/adapters/latex/parse.d.ts +7 -1
- package/dist/adapters/latex/parse.d.ts.map +1 -1
- package/dist/adapters/latex/parse.js +55 -6
- package/dist/adapters/latex/parse.js.map +1 -1
- package/dist/adapters/memory/index.d.ts +3 -0
- package/dist/adapters/memory/index.d.ts.map +1 -1
- package/dist/adapters/memory/index.js +9 -0
- package/dist/adapters/memory/index.js.map +1 -1
- package/dist/adapters/references/index.d.ts.map +1 -1
- package/dist/adapters/references/index.js +27 -24
- package/dist/adapters/references/index.js.map +1 -1
- package/dist/adapters/sources-record/index.d.ts +9 -0
- package/dist/adapters/sources-record/index.d.ts.map +1 -0
- package/dist/adapters/sources-record/index.js +68 -0
- package/dist/adapters/sources-record/index.js.map +1 -0
- package/dist/adapters/tex-output/blg.d.ts +9 -0
- package/dist/adapters/tex-output/blg.d.ts.map +1 -0
- package/dist/adapters/tex-output/blg.js +20 -0
- package/dist/adapters/tex-output/blg.js.map +1 -0
- package/dist/adapters/tex-output/fls.d.ts +8 -0
- package/dist/adapters/tex-output/fls.d.ts.map +1 -0
- package/dist/adapters/tex-output/fls.js +16 -0
- package/dist/adapters/tex-output/fls.js.map +1 -0
- package/dist/adapters/tex-output/index.d.ts +7 -0
- package/dist/adapters/tex-output/index.d.ts.map +1 -0
- package/dist/adapters/tex-output/index.js +7 -0
- package/dist/adapters/tex-output/index.js.map +1 -0
- package/dist/bib-rules.d.ts +47 -0
- package/dist/bib-rules.d.ts.map +1 -0
- package/dist/bib-rules.js +127 -0
- package/dist/bib-rules.js.map +1 -0
- package/dist/build.d.ts +29 -1
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +40 -24
- package/dist/build.js.map +1 -1
- package/dist/claim-provenance.d.ts +2 -2
- package/dist/cli.d.ts +6 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +30 -26
- package/dist/cli.js.map +1 -1
- package/dist/domain/paper-source.d.ts +1 -10
- package/dist/domain/paper-source.d.ts.map +1 -1
- package/dist/domain/paper-source.js +34 -24
- package/dist/domain/paper-source.js.map +1 -1
- package/dist/domain/paper-sources.d.ts +72 -0
- package/dist/domain/paper-sources.d.ts.map +1 -0
- package/dist/domain/paper-sources.js +18 -0
- package/dist/domain/paper-sources.js.map +1 -0
- package/dist/domain/sources-record.d.ts +102 -0
- package/dist/domain/sources-record.d.ts.map +1 -0
- package/dist/domain/sources-record.js +38 -0
- package/dist/domain/sources-record.js.map +1 -0
- package/dist/domain/tex-run.d.ts +25 -0
- package/dist/domain/tex-run.d.ts.map +1 -0
- package/dist/domain/tex-run.js +79 -0
- package/dist/domain/tex-run.js.map +1 -0
- package/dist/eslint-rules/paper-context.d.ts.map +1 -1
- package/dist/eslint-rules/paper-context.js +4 -3
- package/dist/eslint-rules/paper-context.js.map +1 -1
- package/dist/eslint-rules/paper-typography.d.ts +0 -9
- package/dist/eslint-rules/paper-typography.d.ts.map +1 -1
- package/dist/eslint-rules/paper-typography.js +12 -5
- package/dist/eslint-rules/paper-typography.js.map +1 -1
- package/dist/latex-log.d.ts +10 -0
- package/dist/latex-log.d.ts.map +1 -1
- package/dist/latex-log.js +10 -0
- package/dist/latex-log.js.map +1 -1
- package/dist/latex-loop.d.ts +2 -0
- package/dist/latex-loop.d.ts.map +1 -1
- package/dist/latex-loop.js.map +1 -1
- package/dist/package-dirs.d.ts.map +1 -1
- package/dist/package-dirs.js +3 -2
- package/dist/package-dirs.js.map +1 -1
- package/dist/paper-includes.d.ts +4 -7
- package/dist/paper-includes.d.ts.map +1 -1
- package/dist/paper-includes.js +29 -21
- package/dist/paper-includes.js.map +1 -1
- package/dist/paper-prose.d.ts +2 -2
- package/dist/paper-record.d.ts +25 -0
- package/dist/paper-record.d.ts.map +1 -0
- package/dist/paper-record.js +39 -0
- package/dist/paper-record.js.map +1 -0
- package/dist/paper-sources.d.ts +66 -0
- package/dist/paper-sources.d.ts.map +1 -0
- package/dist/paper-sources.js +92 -0
- package/dist/paper-sources.js.map +1 -0
- package/dist/ports/bib-reader.d.ts +18 -0
- package/dist/ports/bib-reader.d.ts.map +1 -0
- package/dist/ports/bib-reader.js +2 -0
- package/dist/ports/bib-reader.js.map +1 -0
- package/dist/ports/check-references.d.ts +9 -4
- package/dist/ports/check-references.d.ts.map +1 -1
- package/dist/ports/latex.d.ts +15 -0
- package/dist/ports/latex.d.ts.map +1 -1
- package/dist/ports/sources-codec.d.ts +11 -0
- package/dist/ports/sources-codec.d.ts.map +1 -0
- package/dist/ports/sources-codec.js +2 -0
- package/dist/ports/sources-codec.js.map +1 -0
- package/dist/ports/tex-output.d.ts +17 -0
- package/dist/ports/tex-output.d.ts.map +1 -0
- package/dist/ports/tex-output.js +2 -0
- package/dist/ports/tex-output.js.map +1 -0
- package/dist/recorded-bibliography.d.ts +89 -0
- package/dist/recorded-bibliography.d.ts.map +1 -0
- package/dist/recorded-bibliography.js +136 -0
- package/dist/recorded-bibliography.js.map +1 -0
- package/dist/reference-rules.d.ts +5 -5
- package/dist/reference-rules.d.ts.map +1 -1
- package/dist/reference-rules.js +150 -77
- package/dist/reference-rules.js.map +1 -1
- package/dist/references.d.ts +71 -16
- package/dist/references.d.ts.map +1 -1
- package/dist/references.js +110 -26
- package/dist/references.js.map +1 -1
- package/dist/register-bands.d.ts +3 -3
- package/dist/register-bands.d.ts.map +1 -1
- package/dist/register-bands.js.map +1 -1
- package/dist/register.d.ts +2 -2
- package/dist/sources-record.d.ts +38 -0
- package/dist/sources-record.d.ts.map +1 -0
- package/dist/sources-record.js +123 -0
- package/dist/sources-record.js.map +1 -0
- package/dist/sources-rules.d.ts +44 -0
- package/dist/sources-rules.d.ts.map +1 -0
- package/dist/sources-rules.js +76 -0
- package/dist/sources-rules.js.map +1 -0
- package/dist/tex-paper.d.ts +10 -15
- package/dist/tex-paper.d.ts.map +1 -1
- package/dist/tex-paper.js +24 -40
- package/dist/tex-paper.js.map +1 -1
- package/dist/tex-venue-rules.d.ts +3 -3
- package/dist/tex-venue-rules.d.ts.map +1 -1
- package/dist/tex-venue-rules.js.map +1 -1
- package/docs/configuration.md +12 -4
- package/docs/design/paper-sources.md +197 -0
- package/docs/package-shape-options.md +1 -1
- package/docs/references.md +34 -8
- package/docs/rules/bib/reachable-entry.md +64 -0
- package/docs/rules/paper/sources-fresh.md +81 -0
- package/docs/rules.md +62 -57
- package/eslint-rules/paper-context.ts +4 -3
- package/eslint-rules/paper-typography.test.mjs +12 -72
- package/eslint-rules/paper-typography.ts +13 -6
- package/eslint.config.mjs +22 -0
- package/fixtures/build-e2e/aidc/paper.tex +1 -1
- package/fixtures/build-e2e/anon-ack/paper.tex +1 -1
- package/fixtures/build-e2e/anon-author/paper.tex +1 -1
- package/fixtures/build-e2e/anon-bib/paper.tex +1 -1
- package/fixtures/build-e2e/anon-href/paper.tex +1 -1
- package/fixtures/build-e2e/anon-macro/paper.tex +1 -1
- package/fixtures/build-e2e/anon-pdfauthor/paper.tex +1 -1
- package/fixtures/paper-sources/p1/paper.tex +30 -0
- package/fixtures/paper-sources/p1/refs.bib +6 -0
- package/fixtures/paper-sources/p1/sections/dead.tex +6 -0
- package/fixtures/paper-sources/p1/sections/intro.tex +7 -0
- package/fixtures/paper-sources/p1/sections/parked.tex +6 -0
- package/fixtures/paper-sources/p1/tex-truth.json +37 -0
- package/fixtures/paper-sources/p1/versions/2026-01-01-review.tex +4 -0
- package/fixtures/paper-sources/v1-stale/paper.tex +14 -0
- package/fixtures/paper-sources/v1-stale/refs.bib +6 -0
- package/fixtures/paper-sources/v1-stale/tex-truth.json +32 -0
- package/fixtures/paper-sources/v10-ifthenelse/anon.bib +1 -0
- package/fixtures/paper-sources/v10-ifthenelse/paper.tex +9 -0
- package/fixtures/paper-sources/v10-ifthenelse/real.bib +1 -0
- package/fixtures/paper-sources/v10-ifthenelse/tex-truth.json +28 -0
- package/fixtures/paper-sources/v11-two-blocks/paper.tex +12 -0
- package/fixtures/paper-sources/v11-two-blocks/tex-truth.json +30 -0
- package/fixtures/paper-sources/v13-percent-text/paper.tex +6 -0
- package/fixtures/paper-sources/v13-percent-text/refs.bib +3 -0
- package/fixtures/paper-sources/v13-percent-text/tex-truth.json +30 -0
- package/fixtures/paper-sources/v15-after-end/paper.tex +6 -0
- package/fixtures/paper-sources/v15-after-end/refs.bib +1 -0
- package/fixtures/paper-sources/v15-after-end/tex-truth.json +17 -0
- package/fixtures/paper-sources/v16-included-block/bibblock.tex +3 -0
- package/fixtures/paper-sources/v16-included-block/paper.tex +7 -0
- package/fixtures/paper-sources/v16-included-block/refs.bib +1 -0
- package/fixtures/paper-sources/v16-included-block/tex-truth.json +35 -0
- package/fixtures/paper-sources/v17-include-order/bibsetup.tex +1 -0
- package/fixtures/paper-sources/v17-include-order/first.bib +1 -0
- package/fixtures/paper-sources/v17-include-order/later.bib +1 -0
- package/fixtures/paper-sources/v17-include-order/paper.tex +7 -0
- package/fixtures/paper-sources/v17-include-order/tex-truth.json +40 -0
- package/fixtures/paper-sources/v2-overwrite/paper.tex +14 -0
- package/fixtures/paper-sources/v2-overwrite/refs.bib +6 -0
- package/fixtures/paper-sources/v2-overwrite/tex-truth.json +30 -0
- package/fixtures/paper-sources/v22-parked-thebibliography/paper.tex +7 -0
- package/fixtures/paper-sources/v22-parked-thebibliography/tex-truth.json +17 -0
- package/fixtures/paper-sources/v23-parked-include/old.bib +1 -0
- package/fixtures/paper-sources/v23-parked-include/paper.tex +7 -0
- package/fixtures/paper-sources/v23-parked-include/parked.tex +1 -0
- package/fixtures/paper-sources/v23-parked-include/refs.bib +1 -0
- package/fixtures/paper-sources/v23-parked-include/tex-truth.json +28 -0
- package/fixtures/paper-sources/v24-quoted-fields/paper.tex +6 -0
- package/fixtures/paper-sources/v24-quoted-fields/refs.bib +5 -0
- package/fixtures/paper-sources/v24-quoted-fields/tex-truth.json +32 -0
- package/fixtures/paper-sources/v25-string-differs/paper.tex +10 -0
- package/fixtures/paper-sources/v25-string-differs/refs.bib +2 -0
- package/fixtures/paper-sources/v25-string-differs/tex-truth.json +32 -0
- package/fixtures/paper-sources/v26-comment-in-names/one.bib +1 -0
- package/fixtures/paper-sources/v26-comment-in-names/paper.tex +7 -0
- package/fixtures/paper-sources/v26-comment-in-names/tex-truth.json +32 -0
- package/fixtures/paper-sources/v26-comment-in-names/two.bib +1 -0
- package/fixtures/paper-sources/v27-shared-string/abbreviations.bib +2 -0
- package/fixtures/paper-sources/v27-shared-string/paper.tex +6 -0
- package/fixtures/paper-sources/v27-shared-string/references.bib +6 -0
- package/fixtures/paper-sources/v27-shared-string/tex-truth.json +31 -0
- package/fixtures/paper-sources/v28-shared-string-block/abbreviations.bib +2 -0
- package/fixtures/paper-sources/v28-shared-string-block/paper.tex +14 -0
- package/fixtures/paper-sources/v28-shared-string-block/tex-truth.json +33 -0
- package/fixtures/paper-sources/v29-generated-input/paper.tex +9 -0
- package/fixtures/paper-sources/v29-generated-input/tex-truth.json +24 -0
- package/fixtures/paper-sources/v3-declared/paper.bib +6 -0
- package/fixtures/paper-sources/v3-declared/paper.tex +6 -0
- package/fixtures/paper-sources/v3-declared/tex-truth.json +28 -0
- package/fixtures/paper-sources/v30-name-next-line/paper.tex +14 -0
- package/fixtures/paper-sources/v30-name-next-line/tex-truth.json +30 -0
- package/fixtures/paper-sources/v4-commented/paper.tex +14 -0
- package/fixtures/paper-sources/v4-commented/refs.bib +6 -0
- package/fixtures/paper-sources/v4-commented/tex-truth.json +28 -0
- package/fixtures/paper-sources/v5-percent-entry/paper.tex +20 -0
- package/fixtures/paper-sources/v5-percent-entry/tex-truth.json +37 -0
- package/fixtures/paper-sources/v6-unclosed/paper.tex +6 -0
- package/fixtures/paper-sources/v6-unclosed/refs.bib +5 -0
- package/fixtures/paper-sources/v6-unclosed/tex-truth.json +37 -0
- package/fixtures/paper-sources/v8-jobname/paper.tex +9 -0
- package/fixtures/paper-sources/v8-jobname/tex-truth.json +30 -0
- package/fixtures/paper-sources/v9-two-bibliographies/one.bib +1 -0
- package/fixtures/paper-sources/v9-two-bibliographies/paper.tex +7 -0
- package/fixtures/paper-sources/v9-two-bibliographies/tex-truth.json +35 -0
- package/fixtures/paper-sources/v9-two-bibliographies/two.bib +1 -0
- package/fixtures/paper-typography/clean-paper/paper.tex +1 -1
- package/fixtures/paper-typography/messy-paper/paper.tex +1 -1
- package/package.json +2 -10
- package/scripts/check.test.ts +23 -1
- package/scripts/check.ts +7 -3
- package/scripts/coverage-config.test.ts +19 -10
- package/scripts/layer-legacy-frozen.test.ts +41 -2
- package/scripts/layer-legacy-frozen.ts +31 -2
- package/skills/grade-paper-writing/SKILL.md +4 -3
- package/skills/grade-paper-writing/SKILL.md.spec.ts +3 -2
- package/skills/grade-paper-writing/prose-lint.mjs +11 -2
- package/skills/grade-paper-writing/prose-lint.test.ts +52 -4
- package/skills/paper-pipeline/scripts/extract-ref-facts.harness.mjs +83 -33
- package/skills/paper-pipeline/scripts/extract-ref-facts.mjs +67 -115
- package/skills/paper-pipeline/scripts/extract-ref-facts.test.mjs +128 -121
- package/skills/verify-citations/SKILL.md +7 -4
- package/skills/verify-citations/SKILL.md.spec.ts +6 -3
- package/skills/verify-citations/scripts/bib-authors.check.test.mjs +17 -19
- package/skills/verify-citations/scripts/bib-authors.cli.test.ts +129 -46
- package/skills/verify-citations/scripts/bib-authors.d.mts +22 -2
- package/skills/verify-citations/scripts/bib-authors.mjs +57 -111
- package/skills/verify-citations/scripts/verify-cites.cli.test.ts +16 -0
- package/skills/verify-citations/scripts/verify-cites.d.mts +19 -3
- package/skills/verify-citations/scripts/verify-cites.mjs +42 -108
- package/skills/verify-citations/scripts/verify-cites.test.mjs +23 -36
- package/src/adapters/bibtex/index.test.ts +163 -0
- package/src/adapters/bibtex/index.ts +155 -0
- package/src/adapters/latex/filecontents.ts +114 -0
- package/src/adapters/latex/includes.ts +18 -10
- package/src/adapters/latex/index.test.ts +73 -0
- package/src/adapters/latex/index.ts +2 -0
- package/src/adapters/latex/nodes.ts +64 -0
- package/src/adapters/latex/parse.test.ts +38 -0
- package/src/adapters/latex/parse.ts +67 -6
- package/src/adapters/memory/index.ts +17 -0
- package/src/adapters/references/index.test.ts +75 -21
- package/src/adapters/references/index.ts +37 -32
- package/src/adapters/sources-record/index.test.ts +87 -0
- package/src/adapters/sources-record/index.ts +82 -0
- package/src/adapters/tex-output/blg.ts +27 -0
- package/src/adapters/tex-output/fls.ts +24 -0
- package/src/adapters/tex-output/index.test.ts +171 -0
- package/src/adapters/tex-output/index.ts +12 -0
- package/src/bib-rules.test.ts +356 -0
- package/src/bib-rules.ts +228 -0
- package/src/bibliography-at.test.ts +286 -0
- package/src/build.test.ts +210 -0
- package/src/build.ts +100 -35
- package/src/claim-provenance.test.ts +33 -7
- package/src/claim-provenance.ts +2 -2
- package/src/cli.harness.mjs +20 -10
- package/src/cli.test.ts +14 -10
- package/src/cli.ts +37 -28
- package/src/domain/paper-source.test.ts +58 -20
- package/src/domain/paper-source.ts +38 -42
- package/src/domain/paper-sources.ts +94 -0
- package/src/domain/sources-record.test.ts +71 -0
- package/src/domain/sources-record.ts +136 -0
- package/src/domain/tex-run.test.ts +228 -0
- package/src/domain/tex-run.ts +139 -0
- package/src/heading-case.test.ts +24 -10
- package/src/latex-log.ts +20 -0
- package/src/latex-loop.harness.ts +1 -0
- package/src/latex-loop.ts +2 -0
- package/src/linted-set.test.ts +9 -1
- package/src/new-paper.harness.mjs +3 -2
- package/src/new-paper.test.ts +9 -5
- package/src/package-dirs.ts +3 -2
- package/src/paper-includes.test.ts +157 -38
- package/src/paper-includes.ts +39 -35
- package/src/paper-prose.test.ts +34 -5
- package/src/paper-prose.ts +2 -2
- package/src/paper-record.test.ts +173 -0
- package/src/paper-record.ts +66 -0
- package/src/paper-settings-commands.test.ts +5 -2
- package/src/paper-sources.ts +151 -0
- package/src/ports/bib-reader.ts +27 -0
- package/src/ports/check-references.ts +7 -3
- package/src/ports/latex.ts +19 -0
- package/src/ports/sources-codec.ts +11 -0
- package/src/ports/tex-output.ts +17 -0
- package/src/recorded-bibliography.ts +297 -0
- package/src/reference-rules.ts +217 -104
- package/src/references.test.ts +520 -177
- package/src/references.ts +185 -37
- package/src/register-bands.test.ts +5 -1
- package/src/register-bands.ts +3 -5
- package/src/register.test.ts +6 -1
- package/src/register.ts +2 -2
- package/src/rule-cases.test.ts +68 -12
- package/src/rule-docs.test.ts +0 -1
- package/src/sources-record.test.ts +308 -0
- package/src/sources-record.ts +231 -0
- package/src/sources-rules.test.ts +152 -0
- package/src/sources-rules.ts +117 -0
- package/src/tex-paper.test.ts +148 -78
- package/src/tex-paper.ts +31 -61
- package/src/tex-venue-rules.test.ts +36 -8
- package/src/tex-venue-rules.ts +3 -5
- package/dist/eslint-rules/bib-reachable-entry.d.ts +0 -22
- package/dist/eslint-rules/bib-reachable-entry.d.ts.map +0 -1
- package/dist/eslint-rules/bib-reachable-entry.js +0 -75
- package/dist/eslint-rules/bib-reachable-entry.js.map +0 -1
- package/eslint-rules/bib-reachable-entry.ts +0 -76
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
# Paper sources — TeX answers "which files, which bibliography"
|
|
2
|
+
|
|
3
|
+
As built in PR #174. Everything that asks which files make up a paper, or which bibliography TeX reads,
|
|
4
|
+
reads the record the last build wrote from TeX's own files; nothing in paperlint reads TeX source to
|
|
5
|
+
decide either, and nothing reads a `.bib` but one adapter. TeX's own answer for each planted paper is
|
|
6
|
+
recorded beside it (§8), and the consumers are tested against that, not against prose.
|
|
7
|
+
|
|
8
|
+
## 1. TeX is the one source of truth
|
|
9
|
+
|
|
10
|
+
Which files make up the paper, and which bibliography it uses, are answered by TeX, from the last
|
|
11
|
+
build — never by reading TeX by hand. There is no static decision: no declaration scan, no
|
|
12
|
+
`filecontents` runs, no include ordering. Lint never runs TeX; it reads what the build recorded.
|
|
13
|
+
|
|
14
|
+
**What the build records — `_build/sources.json`, schema 1.** Written by the compile step, after
|
|
15
|
+
the last pdflatex pass and bibtex, from TeX's own files in the paper directory:
|
|
16
|
+
|
|
17
|
+
| field | from | holds |
|
|
18
|
+
| --------- | ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
19
|
+
| `inputs` | `paper.fls` (`-recorder`) | every file in the paper directory TeX read, in first-read order, each `role: preamble` or `body` — before or after TeX opens `paper.aux` for writing (`\begin{document}`, measured) |
|
|
20
|
+
| `written` | `paper.fls` `OUTPUT` | the `.bib` and `.tex` files TeX wrote (a `filecontents` block) |
|
|
21
|
+
| `bibdata` | `paper.aux` `\bibdata{…}` | the databases bibtex was told to read, after every switch, macro and `\input` |
|
|
22
|
+
| `bibtex` | `paper.blg`, `paper.bbl` | the database files bibtex opened, the keys it typeset, its exit and errors |
|
|
23
|
+
| `sha256` | the files themselves | every `inputs` file and every database bibtex opened (one TeX wrote too), by path and bytes |
|
|
24
|
+
|
|
25
|
+
A file TeX wrote is an input only when it is a `.tex`: a `filecontents` block that writes `body.tex` the
|
|
26
|
+
body `\input`s puts that text in the PDF, so the file is hashed and spliced like any other (measured:
|
|
27
|
+
pass 1 `OUTPUT body.tex` then `INPUT ./body.tex` after `\begin{document}`). Every other file a pass
|
|
28
|
+
wrote — `.aux`, `.out`, `.toc`, a block's `.bib` — is TeX's bookkeeping or a database, not an input.
|
|
29
|
+
The written `.tex` is not handed to ESLint as a file of its own: its words are the block's, and the
|
|
30
|
+
block's body is no prose to the rules, so the text is judged once, where `readPaper` splices it.
|
|
31
|
+
|
|
32
|
+
Every path is relative to the paper directory and spelled as the directory entries spell it: TeX
|
|
33
|
+
logs the name it opened, which on a file system that ignores case is the source's spelling, so the
|
|
34
|
+
record takes each segment's spelling from the disk and one paper gets one record on every platform.
|
|
35
|
+
|
|
36
|
+
A record of its own, not `references.json`: it is written by every build (the references step is
|
|
37
|
+
optional and may record "not checked"), it is read by rules that have nothing to do with references,
|
|
38
|
+
and it goes stale when the SOURCES change, not when one `.bib` does — one staleness key per file.
|
|
39
|
+
`references.json` keeps its verdicts, one per entry of `sources.json`'s databases, and loses its
|
|
40
|
+
`bibtex` field.
|
|
41
|
+
|
|
42
|
+
**Staleness.** A rule recomputes `sha256` over the files the record lists. No record, or a different
|
|
43
|
+
hash (a file edited, added to an `\input`, deleted), is one finding of a new rule,
|
|
44
|
+
`paper/sources-fresh` — "not built" / "the paper changed since the last build — run
|
|
45
|
+
`npx paperlint build`" — and every rule below is silent until a build records the paper again.
|
|
46
|
+
|
|
47
|
+
**The consumers.**
|
|
48
|
+
|
|
49
|
+
| consumer | reads | no record / stale |
|
|
50
|
+
| ---------------------------------------------------------------- | ------------------------------------------------------------------- | ------------------------------------------------------------------ |
|
|
51
|
+
| `bib/reachable-entry`, `paper/author-list`, `paper/cite-exists` | the entries of the databases bibtex opened, through the `BibReader` | silent (`paper/sources-fresh` speaks) |
|
|
52
|
+
| `paper/refs-checked` | keys bibtex typeset that the reader did not read (`%`, `@comment`) | silent |
|
|
53
|
+
| `extract-ref-facts`, `bib-authors`, `verify-cites` (dir, `.tex`) | `bibliographyAt` → the record's databases | refused: "run `npx paperlint build` first" |
|
|
54
|
+
| `bibliographyAt` with a `.bib` | that file alone, unchanged | — |
|
|
55
|
+
| `paperlint lint`'s files (`paper-includes.ts`), `paper-context` | the `body` `.tex` files of `inputs` TeX did not write | `paper.tex` only; `paper/sources-fresh` says the rest is unlinted |
|
|
56
|
+
| the prose rules' text (`readPaper`) | `paper.tex` with the files of `inputs` spliced where they stand | `paper.tex` alone; `paper/sources-fresh` says the rest is unlinted |
|
|
57
|
+
|
|
58
|
+
An entry in a `.bib` TeX wrote is reported at the `filecontents` block whose body bibtex takes as
|
|
59
|
+
the same database (`sameDatabase`) — a lookup of where the text stands, not a decision of what TeX
|
|
60
|
+
reads; an entry in any other `.bib` at the top of `paper.tex`, `refs.bib:12:1:` first.
|
|
61
|
+
|
|
62
|
+
**What stays syntactic: where an include stands, and nothing else.** The prose rules read
|
|
63
|
+
`paper.tex` with the files of `inputs` spliced in (`readPaper`): a projection of the text for rules to
|
|
64
|
+
read in context, which decides nothing above. Which files are spliced is the record's answer — an
|
|
65
|
+
include of a file `inputs` does not list (behind `\iffalse`, or past `\end{document}`) contributes
|
|
66
|
+
nothing, as it did to TeX, and no include is looked for on disk. Where the macro stands in the text
|
|
67
|
+
is the one thing read from the text, because `.fls` records no position: files are spliced in the
|
|
68
|
+
order the text names them, which is the order TeX read them, each ended the way TeX ends the last
|
|
69
|
+
line of a file it reads (a newline when the file has none — measured: `a\input{f}b` with `f` holding
|
|
70
|
+
`foo` typesets "afoo b"). With no record, or a stale one, the text is `paper.tex` alone. A file the
|
|
71
|
+
record lists that no include macro in the text stands for (an `\input` inside a macro's body, #177)
|
|
72
|
+
is linted as a file of its own and is absent from the whole-paper text.
|
|
73
|
+
|
|
74
|
+
**Ground truth.** `test/e2e/tex/paper-sources.e2e.ts` runs the build's own record step on each
|
|
75
|
+
planted paper and snapshots its `sources.json` as `tex-truth.json`; the unit tests run the
|
|
76
|
+
consumers on the fixture with that record. TeX is the expectation and the input at once.
|
|
77
|
+
|
|
78
|
+
## 4. One bibtex reader
|
|
79
|
+
|
|
80
|
+
The port is `BibReader` (`src/ports/bib-reader.ts`: `read(path, text, body, inherited?)` for a block,
|
|
81
|
+
`readFile(path, text, inherited?)` for a `.bib`). bibtex reads a paper's databases in sequence with one
|
|
82
|
+
table of `@string`s, so a `@string` of `abbrev.bib` expands an entry of `refs.bib` under
|
|
83
|
+
`\bibliography{abbrev,refs}` (measured; in the other order bibtex warns it is undefined).
|
|
84
|
+
`recordedBibliography` reads the databases in the order bibtex opened them, each with the `strings` the
|
|
85
|
+
one before it left in force (`inherited`), and reads a block with the `@string`s its database was read
|
|
86
|
+
with; each database is still parsed as its own text, so each entry keeps its place in its own file.
|
|
87
|
+
|
|
88
|
+
The adapter, `src/adapters/bibtex/`, is the only code that knows `@retorquere/bibtex-parser`. It reads each database twice:
|
|
89
|
+
|
|
90
|
+
- **`entries`** — LaTeX read into text (`{\"u}` → `ü`, `\url{x}` → a link), names split into parts,
|
|
91
|
+
`@string`s expanded where they are used. What the checks judge.
|
|
92
|
+
- **`written`** — `raw: true`, every field verbatim, no outer braces dropped: each field as bibtex
|
|
93
|
+
takes it, `@string`s expanded where used, LaTeX as written. What `sameDatabase` compares, with the
|
|
94
|
+
`@preamble` commands, so `{\"o}` and `ö` stay two values, as they are in the `.bbl`.
|
|
95
|
+
|
|
96
|
+
**The fence is lint, not prose.** `eslint.config.mjs` sets `n/no-restricted-import` on
|
|
97
|
+
`@retorquere/bibtex-parser` (and its subpaths) for every file but `src/adapters/bibtex/**`
|
|
98
|
+
(`test/eslint-bib-parser.test.ts` plants imports in the app, the domain, another adapter and a
|
|
99
|
+
skill's script).
|
|
100
|
+
|
|
101
|
+
## 5. A path a person gave → `bibliographyAt`
|
|
102
|
+
|
|
103
|
+
`extract-ref-facts`, `bib-authors` and `verify-cites` (its `.bib` input) take a path on the command
|
|
104
|
+
line. All three ask `bibliographyAt(path, deps)`: a `.bib` is read alone, as named; a `.tex`, or a
|
|
105
|
+
directory holding `paper.tex`, is the bibliography the last build's bibtex opened for that paper
|
|
106
|
+
(`recordedBibliography`) — for a database TeX wrote, the text of the `filecontents` block (or included
|
|
107
|
+
file) that holds it, so an entry stands where the author edits it. A refusal is a `BibliographyUnread`
|
|
108
|
+
(`missing`, `not-bib-or-tex`, `no-paper`, `not-built`, `no-database`, `outside-paper`), and
|
|
109
|
+
`bibliographyUnreadWhy` is its one sentence; `outside-paper` is a paper whose bibtex also opened a
|
|
110
|
+
database the paper directory does not hold (BIBINPUTS) — refused rather than read in part;
|
|
111
|
+
`not-built` covers a missing, unreadable and stale record alike: run `npx paperlint build` first. Each script keeps its own CLI frame around it.
|
|
112
|
+
|
|
113
|
+
## 6. The references a build checks
|
|
114
|
+
|
|
115
|
+
The build's references step (`src/references.ts`) checks entries, not keys: two databases may each
|
|
116
|
+
define a key with other metadata.
|
|
117
|
+
|
|
118
|
+
- **What is checked is `readBibliography`**: the databases the build's bibtex opened, in the order it
|
|
119
|
+
opened them, each once, read by the bibtex reader — a view over `recordedBibliography`, the one reader
|
|
120
|
+
of the record's databases. Without a fresh record the step checks nothing and its note names the
|
|
121
|
+
reason; a database bibtex opened that is not in the paper directory (bibtex found it on its search
|
|
122
|
+
path, `BIBINPUTS`) is named, not skipped. One removed after the build — a `.bib` TeX wrote, then a
|
|
123
|
+
clean — makes the record stale: every database bibtex opened is hashed.
|
|
124
|
+
- **One verdict per entry, in order.** The `CheckReferences` port returns verdict `i` for entry `i`;
|
|
125
|
+
the adapter runs verify-cites and bib-authors per entry and pairs them by position.
|
|
126
|
+
- **`_build/references.json`, schema 3**: `bib {sources, sha256}`, `status`, `entries`. `sources` are
|
|
127
|
+
the database names as bibtex names them and `sha256` covers their text. Lint lays the verdicts on the
|
|
128
|
+
entries of the same databases and reports each at its entry (`entryReports`); a record that is not one
|
|
129
|
+
verdict per entry, in order, about the bytes the databases hold now, is not about this bibliography
|
|
130
|
+
(`paper/refs-fresh`).
|
|
131
|
+
|
|
132
|
+
## 7. The post-build check — where bibtex reads differently
|
|
133
|
+
|
|
134
|
+
bibtex has no comment syntax and recovers from malformed text as no parser does, so the reader does
|
|
135
|
+
not emulate it. Each difference has an owner:
|
|
136
|
+
|
|
137
|
+
| shape | answered by |
|
|
138
|
+
| -------------------------------------------------------------- | ---------------------------------------------------------------------- |
|
|
139
|
+
| malformed: an entry or brace never closed, `%` inside an entry | the build — bibtex exits 2, and `paperlint build` fails with its lines |
|
|
140
|
+
| an entry behind `%`, or inside `@comment{…}` | `paper/refs-checked`, from the keys bibtex typeset |
|
|
141
|
+
| `@`, `)` or `{"}` inside a quoted field | the reader, which reads it as bibtex does |
|
|
142
|
+
|
|
143
|
+
`paper/refs-checked` names every key bibtex typeset (`paper.bbl`) that no entry of the databases it
|
|
144
|
+
opened has (`unseenKeys`; keys compare case-insensitively, as bibtex's do), and every database bibtex
|
|
145
|
+
opened that is not in the paper directory.
|
|
146
|
+
|
|
147
|
+
## 8. Ground truth — `tex-truth.json`
|
|
148
|
+
|
|
149
|
+
Each planted paper of `fixtures/paper-sources/` carries `tex-truth.json`, written by TeX:
|
|
150
|
+
`test/e2e/tex/paper-sources.e2e.ts` builds it with `pdflatex -recorder` and `bibtex` and snapshots the
|
|
151
|
+
record the build writes. `-u` re-records; a TeX that answers differently fails. The unit tests of the
|
|
152
|
+
consumers lay that file at `_build/sources.json` (`test/recorded-fixture.ts`). The accepted papers of
|
|
153
|
+
`fixtures/accepted-papers/` carry theirs the same way (`test/e2e/tex/accepted-papers-record.e2e.ts`).
|
|
154
|
+
The files are the numbers; this document does not copy them.
|
|
155
|
+
|
|
156
|
+
## 9. Decisions
|
|
157
|
+
|
|
158
|
+
- **The record, not a reading** — which files and databases a paper has is what TeX did on the last
|
|
159
|
+
build; a static reading of the text agrees only on the cases its author thought of.
|
|
160
|
+
- **No record, no verdict** — a rule that needs the record is silent without a current one, and one
|
|
161
|
+
rule (`paper/sources-fresh`) says so once; a stale answer is worse than none.
|
|
162
|
+
- **Prose rules splice only the files the record lists** — an include behind `\iffalse` contributes
|
|
163
|
+
nothing; without a record the text is `paper.tex` alone and `paper/sources-fresh` says the rest went
|
|
164
|
+
unlinted.
|
|
165
|
+
- **A lookup of where a text stands is not a decision of what TeX reads** — `filecontents` blocks are
|
|
166
|
+
found in the text only to put a finding on the line that holds an entry (`sameDatabase`).
|
|
167
|
+
- **One verdict per entry, not per key** — a key does not identify an entry; a verdict that cannot say
|
|
168
|
+
which entry it is about reports at the wrong one.
|
|
169
|
+
- **"Same database" is what bibtex takes** — raw bytes and the final `@string` map are a proxy that
|
|
170
|
+
misses a `@string` redefined after use; the text between entries reaches no `.bbl`.
|
|
171
|
+
- **One `.bib` reader, fenced by lint** — three readers grew before there was one; the parser's name
|
|
172
|
+
may appear in one folder only.
|
|
173
|
+
- **One path → bibliography function** — three scripts each resolved it by hand, each with its own
|
|
174
|
+
refusals.
|
|
175
|
+
- **Recorded TeX truth, not hand-written expectations** — the consumers' tests compare with what TeX
|
|
176
|
+
did, so a wrong belief about TeX cannot be written into both the code and its test.
|
|
177
|
+
- **The post-build check, not emulation** — no parser recovers as bibtex does; bibtex's own output
|
|
178
|
+
is compared instead.
|
|
179
|
+
|
|
180
|
+
## 10. Scope: what this PR does not decide
|
|
181
|
+
|
|
182
|
+
- A finding for a `filecontents` block without `[overwrite]` (#176).
|
|
183
|
+
- A listed body file that no include macro in the text stands for (an `\input` inside a macro's body,
|
|
184
|
+
#177): linted as a file of its own, absent from the whole-paper text.
|
|
185
|
+
- `eslint --cache`: `bib/reachable-entry` depends on files other than the linted one, so a cached
|
|
186
|
+
result can be stale after a `.bib` changes. `paperlint lint` does not cache.
|
|
187
|
+
- Reading past `\end{document}` in `headings.ts`, `layout.ts` and `rendered.ts` (#178).
|
|
188
|
+
- A file a `filecontents` block writes under another extension than `.tex` (a `.pgf` the body
|
|
189
|
+
`\input`s) is not an input: its text reaches the PDF, but the record neither hashes nor splices it.
|
|
190
|
+
- A database TeX wrote is read from the file it left on disk, which the record does not hash: edited
|
|
191
|
+
after a build, that file is not detected as stale.
|
|
192
|
+
- Two copies compared where bibtex and the parser differ in what no check reads: a `@preamble` is
|
|
193
|
+
compared as written, so a `@string` it uses that is redefined between the copies is not seen; and
|
|
194
|
+
`keywords` are compared as the parser splits, dedupes and sorts them — it does so for that field
|
|
195
|
+
name unconditionally, with no option to keep it as written.
|
|
196
|
+
- Q3 (one projection of the live text, replacing `paper-typography`'s `skippedRanges` and
|
|
197
|
+
`texToMdast`'s own parse), the hooks, and an enforcement rule for Q1–Q3: later PRs.
|
|
@@ -138,7 +138,7 @@ lockfile in that array was not.
|
|
|
138
138
|
zero: `pipeline-check.mjs`, `extract-ref-facts.mjs` and `bib-authors.mjs`, all reaching
|
|
139
139
|
`markdown-it`. Which retires a number this note carried: the closure is **two** third-party
|
|
140
140
|
packages over **eight** referenced scripts, not one over seven — `extract-ref-facts.mjs` reaches
|
|
141
|
-
`@retorquere/bibtex-parser
|
|
141
|
+
`@retorquere/bibtex-parser`, now through `#src/adapters/bibtex/index`.
|
|
142
142
|
|
|
143
143
|
⏳ **Not measured, recorded as such:** the documented 60-second install timeout; the personal
|
|
144
144
|
`~/.claude/skills` and `--add-dir` channels (2 of 4 locations verified); and a genuine
|
package/docs/references.md
CHANGED
|
@@ -7,7 +7,11 @@ what happens in CI and without a network.
|
|
|
7
7
|
|
|
8
8
|
## What is checked, and where
|
|
9
9
|
|
|
10
|
-
For each entry
|
|
10
|
+
For each entry of the databases the build's bibtex **opened** — the `.bib` files its `\bibliography` /
|
|
11
|
+
`\addbibresource` named after every switch and macro, and the file a `filecontents` block wrote. The
|
|
12
|
+
build records them in `<paper>/_build/sources.json` from TeX's own files (`paper.blg`), so nothing here
|
|
13
|
+
guesses which `.bib` TeX reads by reading the `.tex`. Their text is read by the one bibtex reader
|
|
14
|
+
(`src/ports/bib-reader.ts`):
|
|
11
15
|
|
|
12
16
|
| question | asked of |
|
|
13
17
|
| -------------------------------------------------------------------------------------------------------- | ------------------------------------------- |
|
|
@@ -23,18 +27,40 @@ A work that is simply not found is `unresolvable`, never a failure: plenty of re
|
|
|
23
27
|
indexed. Only a positive disproof fails an entry, for example a DOI that resolves to a different
|
|
24
28
|
paper, or one the DOI authority says does not exist.
|
|
25
29
|
|
|
26
|
-
The verdicts land in `<paper>/_build/references.json
|
|
30
|
+
The verdicts land in `<paper>/_build/references.json`: one verdict per entry of those databases, in the
|
|
31
|
+
order bibtex opened them, and a hash of their text. `paperlint lint` reads that file and reports:
|
|
27
32
|
|
|
28
|
-
| rule | when
|
|
29
|
-
| -------------------- |
|
|
30
|
-
| `paper/cite-exists` | an entry's identifier provably does not resolve to the work cited
|
|
31
|
-
| `paper/author-list` | an entry's authors are the preprint's under a published venue
|
|
32
|
-
| `paper/refs-fresh` | the
|
|
33
|
-
| `paper/refs-checked` | no build has checked the references, or the last one could not
|
|
33
|
+
| rule | when |
|
|
34
|
+
| -------------------- | ----------------------------------------------------------------------------------------- |
|
|
35
|
+
| `paper/cite-exists` | an entry's identifier provably does not resolve to the work cited |
|
|
36
|
+
| `paper/author-list` | an entry's authors are the preprint's under a published venue |
|
|
37
|
+
| `paper/refs-fresh` | the databases changed since the build checked them — build again |
|
|
38
|
+
| `paper/refs-checked` | no build has checked the references, or the last one could not, or the reader missed some |
|
|
39
|
+
|
|
40
|
+
An entry of a `.bib` is reported at the first line of `paper.tex`, with the entry's file, line and
|
|
41
|
+
column at the front of the message (`refs.bib:12:1: …`): ESLint does not lint a `.bib`.
|
|
34
42
|
|
|
35
43
|
The step never fails the build. Without a network the PDF is still built and lint warns that the
|
|
36
44
|
references were not checked.
|
|
37
45
|
|
|
46
|
+
**No record of the build, no answer.** Which databases bibtex opened is in `sources.json`, so a paper
|
|
47
|
+
with no record (never built), or one whose files changed since (`paper/sources-fresh`), has none to
|
|
48
|
+
check: the step records nothing, and the four rules are silent while `paper/sources-fresh` says once
|
|
49
|
+
that the paper must be built.
|
|
50
|
+
|
|
51
|
+
**What bibtex typeset, against what paperlint read.** The record also holds the keys bibtex typeset
|
|
52
|
+
(its `paper.bbl`). bibtex has no comment syntax, so an entry behind `%` or inside `@comment{…}` is one
|
|
53
|
+
it typesets and paperlint's reader does not; `paper/refs-checked` names each such key as not checked.
|
|
54
|
+
(bibtex's keys are case-insensitive: `\cite{SMITH}` typesets `\bibitem{SMITH}` from an entry `smith`,
|
|
55
|
+
which is the same entry.) A malformed `.bib` never gets that far: bibtex fails on it, and `paperlint
|
|
56
|
+
build` fails with bibtex's own lines.
|
|
57
|
+
|
|
58
|
+
A database TeX wrote itself (a `filecontents` block) is read from the file it left beside the paper.
|
|
59
|
+
The build hashes it like any other, so when that file is edited or removed after the build the record
|
|
60
|
+
is stale and `paper/sources-fresh` says so: build again to write it. A database bibtex found outside
|
|
61
|
+
the paper directory, on its search path (`BIBINPUTS`), is not read: the step says which and
|
|
62
|
+
`paper/refs-checked` warns.
|
|
63
|
+
|
|
38
64
|
## `repro/references-cache.json` — commit it
|
|
39
65
|
|
|
40
66
|
Asking five services about every entry is slow. DBLP asks clients to pause between requests, and a
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# bib/reachable-entry
|
|
2
|
+
|
|
3
|
+
**Level:** warn · **Reads:** `paper.tex`, and `_build/sources.json` — the databases the last build's
|
|
4
|
+
bibtex opened, read through the bibtex reader
|
|
5
|
+
|
|
6
|
+
## What it catches
|
|
7
|
+
|
|
8
|
+
A bibliography entry with no `doi`, no `url` and no arXiv id: nothing a reader can follow. The entries
|
|
9
|
+
judged are those of the databases bibtex opened in the last build — TeX's own answer, recorded by
|
|
10
|
+
`paperlint build`, not a reading of the source for `\bibliography`.
|
|
11
|
+
|
|
12
|
+
## Why
|
|
13
|
+
|
|
14
|
+
Reviewer A on HotCRP #20 (2026-08-23): "not every entry has a DOI/link" — one paper had 0 of 47
|
|
15
|
+
entries reachable. Not "no doi": ICLR, NeurIPS and TMLR issue no DOIs at all (measured 2026-08-24),
|
|
16
|
+
so a url or an arXiv id counts.
|
|
17
|
+
|
|
18
|
+
## Examples
|
|
19
|
+
|
|
20
|
+
Reported on the entry's own line when the `.bib` bibtex opened is one TeX wrote from a `filecontents`
|
|
21
|
+
block of `paper.tex`; any other entry — a `.bib` file the author keeps, or a block in an included file —
|
|
22
|
+
at the top of `paper.tex`, with the entry's file, line and column first:
|
|
23
|
+
|
|
24
|
+
```bibtex
|
|
25
|
+
@book{lost2026, title = {A Book}, year = {2026}}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
> refs.bib:12:1: `lost2026` has no doi, url or arXiv id — a reader has nothing to follow. If none
|
|
29
|
+
> exists, keep the exception with `% eslint-disable-next-line bib/reachable-entry -- <why>` above
|
|
30
|
+
> the entry
|
|
31
|
+
|
|
32
|
+
Not reported:
|
|
33
|
+
|
|
34
|
+
```bibtex
|
|
35
|
+
@article{a, doi = {10.1/x}}
|
|
36
|
+
@misc{b, url = {https://example.org}}
|
|
37
|
+
@misc{c, note = {arXiv:2310.05736}}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Options / preset fields
|
|
41
|
+
|
|
42
|
+
None.
|
|
43
|
+
|
|
44
|
+
## What it does not check
|
|
45
|
+
|
|
46
|
+
- Whether the link resolves: that is the references check of `paperlint build`.
|
|
47
|
+
- `@string` and `@preamble`, which are not entries.
|
|
48
|
+
- A paper with no record of a build, or one changed since: the rule is silent, and
|
|
49
|
+
[`paper/sources-fresh`](../paper/sources-fresh.md) says once that it was not built.
|
|
50
|
+
- A database bibtex found outside the paper directory, and an entry bibtex reads that the `.bib` reader
|
|
51
|
+
does not (behind `%`, inside `@comment{…}`): that is the post-build check's.
|
|
52
|
+
- With `eslint --cache`, a change to a `.bib` alone does not re-run the rule: its findings depend on
|
|
53
|
+
files other than `paper.tex`. `paperlint lint` does not cache.
|
|
54
|
+
|
|
55
|
+
## How to fix
|
|
56
|
+
|
|
57
|
+
Add the entry's `doi`, `url` or arXiv id. An entry that has none — a talk, a personal communication
|
|
58
|
+
— keeps its exception where it is written, on the line above the entry, in the block or in the
|
|
59
|
+
`.bib`:
|
|
60
|
+
|
|
61
|
+
```bibtex
|
|
62
|
+
% eslint-disable-next-line bib/reachable-entry -- an invited talk, no recording exists
|
|
63
|
+
@misc{smith2024talk, …}
|
|
64
|
+
```
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# paper/sources-fresh
|
|
2
|
+
|
|
3
|
+
**Level:** warn · **Reads:** `paper.tex` and `_build/sources.json` · **Reported on:** the first line of
|
|
4
|
+
`paper.tex`
|
|
5
|
+
|
|
6
|
+
## What it catches
|
|
7
|
+
|
|
8
|
+
The paper has no usable record of the last build, so paperlint does not know which files TeX reads for
|
|
9
|
+
it. One finding, in one of three forms:
|
|
10
|
+
|
|
11
|
+
- **not built** — there is no `_build/sources.json`;
|
|
12
|
+
- **unreadable** — the file is not JSON, is of another schema number, or does not have the shape of
|
|
13
|
+
schema 1;
|
|
14
|
+
- **stale** — a file the build read has other bytes now, was deleted, or appeared where the build saw
|
|
15
|
+
none. The message names each: `sections/intro.tex edited, refs.bib deleted`.
|
|
16
|
+
|
|
17
|
+
## Why
|
|
18
|
+
|
|
19
|
+
`paperlint build` asks TeX itself which files it read (`pdflatex -recorder`) and which databases bibtex
|
|
20
|
+
opened, and writes the answer, with a SHA-256 of every file, to `_build/sources.json`. Nothing in
|
|
21
|
+
paperlint answers "which files make up this paper" or "which bibliography does it use" by reading the
|
|
22
|
+
TeX source: `\input` behind a macro, a `.bib` written by `filecontents`, a database named by a
|
|
23
|
+
switch are TeX's to decide, and TeX has already decided.
|
|
24
|
+
|
|
25
|
+
The rules that need that answer — the ones over the bibliography, and the prose rules over the files
|
|
26
|
+
`paper.tex` includes — read the record. With no record, or one about an earlier paper, they would
|
|
27
|
+
judge files that are not the paper's, so they stay silent, and this rule speaks once in their place.
|
|
28
|
+
Without it a paper that was never built would lint clean because nothing was looked at.
|
|
29
|
+
|
|
30
|
+
## Examples
|
|
31
|
+
|
|
32
|
+
Failing — a paper that was never built:
|
|
33
|
+
|
|
34
|
+
```text
|
|
35
|
+
papers/my-paper/paper.tex
|
|
36
|
+
1:1 warning the paper has not been built — run `npx paperlint build`, which records the files TeX
|
|
37
|
+
reads. Until it has, the files `paper.tex` includes are not linted, and the rules that
|
|
38
|
+
read the bibliography say nothing
|
|
39
|
+
paper/sources-fresh
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Failing — `sections/intro.tex` was edited after the last build:
|
|
43
|
+
|
|
44
|
+
```text
|
|
45
|
+
papers/my-paper/paper.tex
|
|
46
|
+
1:1 warning the paper changed since the last build (sections/intro.tex edited) — run `npx paperlint
|
|
47
|
+
build`; until then the files `paper.tex` includes are not linted, and the rules that
|
|
48
|
+
read the bibliography say nothing
|
|
49
|
+
paper/sources-fresh
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Passing: a paper whose files are byte for byte what the last build read. Editing a file TeX did not
|
|
53
|
+
read (a figure source the paper does not include, a note beside it) changes nothing.
|
|
54
|
+
|
|
55
|
+
## Options / preset fields
|
|
56
|
+
|
|
57
|
+
No rule options. The level is `warn` for every paper; set it in the paper's `paperlint.json`:
|
|
58
|
+
|
|
59
|
+
```json
|
|
60
|
+
{ "rules": { "paper/sources-fresh": "error" } }
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
`error` suits a CI job that builds first; `off` suits one that only lints and would rather not hear it.
|
|
64
|
+
|
|
65
|
+
## What it does not check
|
|
66
|
+
|
|
67
|
+
- That the build was clean. A record is written after a build whose pdflatex and bibtex runs ended;
|
|
68
|
+
what they reported is `paper/refs-checked`'s and the build's own.
|
|
69
|
+
- Files TeX never read. A file the paper does not include is not in the record, so its edits are not
|
|
70
|
+
changes, and it is not linted.
|
|
71
|
+
- A file edited in an editor and not saved: the rule compares the bytes on disk with the record.
|
|
72
|
+
- `.bib` files TeX wrote itself (`filecontents`): their bytes are the block's, which is in a file the
|
|
73
|
+
record hashes.
|
|
74
|
+
|
|
75
|
+
## How to fix
|
|
76
|
+
|
|
77
|
+
Build the paper again; the record is rewritten from the files as they are:
|
|
78
|
+
|
|
79
|
+
```sh
|
|
80
|
+
npx paperlint build papers/my-paper
|
|
81
|
+
```
|