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.
Files changed (356) hide show
  1. package/CLAUDE.md +9 -25
  2. package/CONTRIBUTING.md +5 -4
  3. package/README.md +4 -3
  4. package/dist/adapters/bibtex/index.d.ts +3 -0
  5. package/dist/adapters/bibtex/index.d.ts.map +1 -0
  6. package/dist/adapters/bibtex/index.js +103 -0
  7. package/dist/adapters/bibtex/index.js.map +1 -0
  8. package/dist/adapters/latex/filecontents.d.ts +33 -0
  9. package/dist/adapters/latex/filecontents.d.ts.map +1 -0
  10. package/dist/adapters/latex/filecontents.js +65 -0
  11. package/dist/adapters/latex/filecontents.js.map +1 -0
  12. package/dist/adapters/latex/includes.d.ts +3 -3
  13. package/dist/adapters/latex/includes.d.ts.map +1 -1
  14. package/dist/adapters/latex/includes.js +18 -10
  15. package/dist/adapters/latex/includes.js.map +1 -1
  16. package/dist/adapters/latex/index.d.ts.map +1 -1
  17. package/dist/adapters/latex/index.js +2 -0
  18. package/dist/adapters/latex/index.js.map +1 -1
  19. package/dist/adapters/latex/nodes.d.ts +12 -0
  20. package/dist/adapters/latex/nodes.d.ts.map +1 -1
  21. package/dist/adapters/latex/nodes.js +39 -0
  22. package/dist/adapters/latex/nodes.js.map +1 -1
  23. package/dist/adapters/latex/parse.d.ts +7 -1
  24. package/dist/adapters/latex/parse.d.ts.map +1 -1
  25. package/dist/adapters/latex/parse.js +55 -6
  26. package/dist/adapters/latex/parse.js.map +1 -1
  27. package/dist/adapters/memory/index.d.ts +3 -0
  28. package/dist/adapters/memory/index.d.ts.map +1 -1
  29. package/dist/adapters/memory/index.js +9 -0
  30. package/dist/adapters/memory/index.js.map +1 -1
  31. package/dist/adapters/references/index.d.ts.map +1 -1
  32. package/dist/adapters/references/index.js +27 -24
  33. package/dist/adapters/references/index.js.map +1 -1
  34. package/dist/adapters/sources-record/index.d.ts +9 -0
  35. package/dist/adapters/sources-record/index.d.ts.map +1 -0
  36. package/dist/adapters/sources-record/index.js +68 -0
  37. package/dist/adapters/sources-record/index.js.map +1 -0
  38. package/dist/adapters/tex-output/blg.d.ts +9 -0
  39. package/dist/adapters/tex-output/blg.d.ts.map +1 -0
  40. package/dist/adapters/tex-output/blg.js +20 -0
  41. package/dist/adapters/tex-output/blg.js.map +1 -0
  42. package/dist/adapters/tex-output/fls.d.ts +8 -0
  43. package/dist/adapters/tex-output/fls.d.ts.map +1 -0
  44. package/dist/adapters/tex-output/fls.js +16 -0
  45. package/dist/adapters/tex-output/fls.js.map +1 -0
  46. package/dist/adapters/tex-output/index.d.ts +7 -0
  47. package/dist/adapters/tex-output/index.d.ts.map +1 -0
  48. package/dist/adapters/tex-output/index.js +7 -0
  49. package/dist/adapters/tex-output/index.js.map +1 -0
  50. package/dist/bib-rules.d.ts +47 -0
  51. package/dist/bib-rules.d.ts.map +1 -0
  52. package/dist/bib-rules.js +127 -0
  53. package/dist/bib-rules.js.map +1 -0
  54. package/dist/build.d.ts +29 -1
  55. package/dist/build.d.ts.map +1 -1
  56. package/dist/build.js +40 -24
  57. package/dist/build.js.map +1 -1
  58. package/dist/claim-provenance.d.ts +2 -2
  59. package/dist/cli.d.ts +6 -1
  60. package/dist/cli.d.ts.map +1 -1
  61. package/dist/cli.js +30 -26
  62. package/dist/cli.js.map +1 -1
  63. package/dist/domain/paper-source.d.ts +1 -10
  64. package/dist/domain/paper-source.d.ts.map +1 -1
  65. package/dist/domain/paper-source.js +34 -24
  66. package/dist/domain/paper-source.js.map +1 -1
  67. package/dist/domain/paper-sources.d.ts +72 -0
  68. package/dist/domain/paper-sources.d.ts.map +1 -0
  69. package/dist/domain/paper-sources.js +18 -0
  70. package/dist/domain/paper-sources.js.map +1 -0
  71. package/dist/domain/sources-record.d.ts +102 -0
  72. package/dist/domain/sources-record.d.ts.map +1 -0
  73. package/dist/domain/sources-record.js +38 -0
  74. package/dist/domain/sources-record.js.map +1 -0
  75. package/dist/domain/tex-run.d.ts +25 -0
  76. package/dist/domain/tex-run.d.ts.map +1 -0
  77. package/dist/domain/tex-run.js +79 -0
  78. package/dist/domain/tex-run.js.map +1 -0
  79. package/dist/eslint-rules/paper-context.d.ts.map +1 -1
  80. package/dist/eslint-rules/paper-context.js +4 -3
  81. package/dist/eslint-rules/paper-context.js.map +1 -1
  82. package/dist/eslint-rules/paper-typography.d.ts +0 -9
  83. package/dist/eslint-rules/paper-typography.d.ts.map +1 -1
  84. package/dist/eslint-rules/paper-typography.js +12 -5
  85. package/dist/eslint-rules/paper-typography.js.map +1 -1
  86. package/dist/latex-log.d.ts +10 -0
  87. package/dist/latex-log.d.ts.map +1 -1
  88. package/dist/latex-log.js +10 -0
  89. package/dist/latex-log.js.map +1 -1
  90. package/dist/latex-loop.d.ts +2 -0
  91. package/dist/latex-loop.d.ts.map +1 -1
  92. package/dist/latex-loop.js.map +1 -1
  93. package/dist/package-dirs.d.ts.map +1 -1
  94. package/dist/package-dirs.js +3 -2
  95. package/dist/package-dirs.js.map +1 -1
  96. package/dist/paper-includes.d.ts +4 -7
  97. package/dist/paper-includes.d.ts.map +1 -1
  98. package/dist/paper-includes.js +29 -21
  99. package/dist/paper-includes.js.map +1 -1
  100. package/dist/paper-prose.d.ts +2 -2
  101. package/dist/paper-record.d.ts +25 -0
  102. package/dist/paper-record.d.ts.map +1 -0
  103. package/dist/paper-record.js +39 -0
  104. package/dist/paper-record.js.map +1 -0
  105. package/dist/paper-sources.d.ts +66 -0
  106. package/dist/paper-sources.d.ts.map +1 -0
  107. package/dist/paper-sources.js +92 -0
  108. package/dist/paper-sources.js.map +1 -0
  109. package/dist/ports/bib-reader.d.ts +18 -0
  110. package/dist/ports/bib-reader.d.ts.map +1 -0
  111. package/dist/ports/bib-reader.js +2 -0
  112. package/dist/ports/bib-reader.js.map +1 -0
  113. package/dist/ports/check-references.d.ts +9 -4
  114. package/dist/ports/check-references.d.ts.map +1 -1
  115. package/dist/ports/latex.d.ts +15 -0
  116. package/dist/ports/latex.d.ts.map +1 -1
  117. package/dist/ports/sources-codec.d.ts +11 -0
  118. package/dist/ports/sources-codec.d.ts.map +1 -0
  119. package/dist/ports/sources-codec.js +2 -0
  120. package/dist/ports/sources-codec.js.map +1 -0
  121. package/dist/ports/tex-output.d.ts +17 -0
  122. package/dist/ports/tex-output.d.ts.map +1 -0
  123. package/dist/ports/tex-output.js +2 -0
  124. package/dist/ports/tex-output.js.map +1 -0
  125. package/dist/recorded-bibliography.d.ts +89 -0
  126. package/dist/recorded-bibliography.d.ts.map +1 -0
  127. package/dist/recorded-bibliography.js +136 -0
  128. package/dist/recorded-bibliography.js.map +1 -0
  129. package/dist/reference-rules.d.ts +5 -5
  130. package/dist/reference-rules.d.ts.map +1 -1
  131. package/dist/reference-rules.js +150 -77
  132. package/dist/reference-rules.js.map +1 -1
  133. package/dist/references.d.ts +71 -16
  134. package/dist/references.d.ts.map +1 -1
  135. package/dist/references.js +110 -26
  136. package/dist/references.js.map +1 -1
  137. package/dist/register-bands.d.ts +3 -3
  138. package/dist/register-bands.d.ts.map +1 -1
  139. package/dist/register-bands.js.map +1 -1
  140. package/dist/register.d.ts +2 -2
  141. package/dist/sources-record.d.ts +38 -0
  142. package/dist/sources-record.d.ts.map +1 -0
  143. package/dist/sources-record.js +123 -0
  144. package/dist/sources-record.js.map +1 -0
  145. package/dist/sources-rules.d.ts +44 -0
  146. package/dist/sources-rules.d.ts.map +1 -0
  147. package/dist/sources-rules.js +76 -0
  148. package/dist/sources-rules.js.map +1 -0
  149. package/dist/tex-paper.d.ts +10 -15
  150. package/dist/tex-paper.d.ts.map +1 -1
  151. package/dist/tex-paper.js +24 -40
  152. package/dist/tex-paper.js.map +1 -1
  153. package/dist/tex-venue-rules.d.ts +3 -3
  154. package/dist/tex-venue-rules.d.ts.map +1 -1
  155. package/dist/tex-venue-rules.js.map +1 -1
  156. package/docs/configuration.md +12 -4
  157. package/docs/design/paper-sources.md +197 -0
  158. package/docs/package-shape-options.md +1 -1
  159. package/docs/references.md +34 -8
  160. package/docs/rules/bib/reachable-entry.md +64 -0
  161. package/docs/rules/paper/sources-fresh.md +81 -0
  162. package/docs/rules.md +62 -57
  163. package/eslint-rules/paper-context.ts +4 -3
  164. package/eslint-rules/paper-typography.test.mjs +12 -72
  165. package/eslint-rules/paper-typography.ts +13 -6
  166. package/eslint.config.mjs +22 -0
  167. package/fixtures/build-e2e/aidc/paper.tex +1 -1
  168. package/fixtures/build-e2e/anon-ack/paper.tex +1 -1
  169. package/fixtures/build-e2e/anon-author/paper.tex +1 -1
  170. package/fixtures/build-e2e/anon-bib/paper.tex +1 -1
  171. package/fixtures/build-e2e/anon-href/paper.tex +1 -1
  172. package/fixtures/build-e2e/anon-macro/paper.tex +1 -1
  173. package/fixtures/build-e2e/anon-pdfauthor/paper.tex +1 -1
  174. package/fixtures/paper-sources/p1/paper.tex +30 -0
  175. package/fixtures/paper-sources/p1/refs.bib +6 -0
  176. package/fixtures/paper-sources/p1/sections/dead.tex +6 -0
  177. package/fixtures/paper-sources/p1/sections/intro.tex +7 -0
  178. package/fixtures/paper-sources/p1/sections/parked.tex +6 -0
  179. package/fixtures/paper-sources/p1/tex-truth.json +37 -0
  180. package/fixtures/paper-sources/p1/versions/2026-01-01-review.tex +4 -0
  181. package/fixtures/paper-sources/v1-stale/paper.tex +14 -0
  182. package/fixtures/paper-sources/v1-stale/refs.bib +6 -0
  183. package/fixtures/paper-sources/v1-stale/tex-truth.json +32 -0
  184. package/fixtures/paper-sources/v10-ifthenelse/anon.bib +1 -0
  185. package/fixtures/paper-sources/v10-ifthenelse/paper.tex +9 -0
  186. package/fixtures/paper-sources/v10-ifthenelse/real.bib +1 -0
  187. package/fixtures/paper-sources/v10-ifthenelse/tex-truth.json +28 -0
  188. package/fixtures/paper-sources/v11-two-blocks/paper.tex +12 -0
  189. package/fixtures/paper-sources/v11-two-blocks/tex-truth.json +30 -0
  190. package/fixtures/paper-sources/v13-percent-text/paper.tex +6 -0
  191. package/fixtures/paper-sources/v13-percent-text/refs.bib +3 -0
  192. package/fixtures/paper-sources/v13-percent-text/tex-truth.json +30 -0
  193. package/fixtures/paper-sources/v15-after-end/paper.tex +6 -0
  194. package/fixtures/paper-sources/v15-after-end/refs.bib +1 -0
  195. package/fixtures/paper-sources/v15-after-end/tex-truth.json +17 -0
  196. package/fixtures/paper-sources/v16-included-block/bibblock.tex +3 -0
  197. package/fixtures/paper-sources/v16-included-block/paper.tex +7 -0
  198. package/fixtures/paper-sources/v16-included-block/refs.bib +1 -0
  199. package/fixtures/paper-sources/v16-included-block/tex-truth.json +35 -0
  200. package/fixtures/paper-sources/v17-include-order/bibsetup.tex +1 -0
  201. package/fixtures/paper-sources/v17-include-order/first.bib +1 -0
  202. package/fixtures/paper-sources/v17-include-order/later.bib +1 -0
  203. package/fixtures/paper-sources/v17-include-order/paper.tex +7 -0
  204. package/fixtures/paper-sources/v17-include-order/tex-truth.json +40 -0
  205. package/fixtures/paper-sources/v2-overwrite/paper.tex +14 -0
  206. package/fixtures/paper-sources/v2-overwrite/refs.bib +6 -0
  207. package/fixtures/paper-sources/v2-overwrite/tex-truth.json +30 -0
  208. package/fixtures/paper-sources/v22-parked-thebibliography/paper.tex +7 -0
  209. package/fixtures/paper-sources/v22-parked-thebibliography/tex-truth.json +17 -0
  210. package/fixtures/paper-sources/v23-parked-include/old.bib +1 -0
  211. package/fixtures/paper-sources/v23-parked-include/paper.tex +7 -0
  212. package/fixtures/paper-sources/v23-parked-include/parked.tex +1 -0
  213. package/fixtures/paper-sources/v23-parked-include/refs.bib +1 -0
  214. package/fixtures/paper-sources/v23-parked-include/tex-truth.json +28 -0
  215. package/fixtures/paper-sources/v24-quoted-fields/paper.tex +6 -0
  216. package/fixtures/paper-sources/v24-quoted-fields/refs.bib +5 -0
  217. package/fixtures/paper-sources/v24-quoted-fields/tex-truth.json +32 -0
  218. package/fixtures/paper-sources/v25-string-differs/paper.tex +10 -0
  219. package/fixtures/paper-sources/v25-string-differs/refs.bib +2 -0
  220. package/fixtures/paper-sources/v25-string-differs/tex-truth.json +32 -0
  221. package/fixtures/paper-sources/v26-comment-in-names/one.bib +1 -0
  222. package/fixtures/paper-sources/v26-comment-in-names/paper.tex +7 -0
  223. package/fixtures/paper-sources/v26-comment-in-names/tex-truth.json +32 -0
  224. package/fixtures/paper-sources/v26-comment-in-names/two.bib +1 -0
  225. package/fixtures/paper-sources/v27-shared-string/abbreviations.bib +2 -0
  226. package/fixtures/paper-sources/v27-shared-string/paper.tex +6 -0
  227. package/fixtures/paper-sources/v27-shared-string/references.bib +6 -0
  228. package/fixtures/paper-sources/v27-shared-string/tex-truth.json +31 -0
  229. package/fixtures/paper-sources/v28-shared-string-block/abbreviations.bib +2 -0
  230. package/fixtures/paper-sources/v28-shared-string-block/paper.tex +14 -0
  231. package/fixtures/paper-sources/v28-shared-string-block/tex-truth.json +33 -0
  232. package/fixtures/paper-sources/v29-generated-input/paper.tex +9 -0
  233. package/fixtures/paper-sources/v29-generated-input/tex-truth.json +24 -0
  234. package/fixtures/paper-sources/v3-declared/paper.bib +6 -0
  235. package/fixtures/paper-sources/v3-declared/paper.tex +6 -0
  236. package/fixtures/paper-sources/v3-declared/tex-truth.json +28 -0
  237. package/fixtures/paper-sources/v30-name-next-line/paper.tex +14 -0
  238. package/fixtures/paper-sources/v30-name-next-line/tex-truth.json +30 -0
  239. package/fixtures/paper-sources/v4-commented/paper.tex +14 -0
  240. package/fixtures/paper-sources/v4-commented/refs.bib +6 -0
  241. package/fixtures/paper-sources/v4-commented/tex-truth.json +28 -0
  242. package/fixtures/paper-sources/v5-percent-entry/paper.tex +20 -0
  243. package/fixtures/paper-sources/v5-percent-entry/tex-truth.json +37 -0
  244. package/fixtures/paper-sources/v6-unclosed/paper.tex +6 -0
  245. package/fixtures/paper-sources/v6-unclosed/refs.bib +5 -0
  246. package/fixtures/paper-sources/v6-unclosed/tex-truth.json +37 -0
  247. package/fixtures/paper-sources/v8-jobname/paper.tex +9 -0
  248. package/fixtures/paper-sources/v8-jobname/tex-truth.json +30 -0
  249. package/fixtures/paper-sources/v9-two-bibliographies/one.bib +1 -0
  250. package/fixtures/paper-sources/v9-two-bibliographies/paper.tex +7 -0
  251. package/fixtures/paper-sources/v9-two-bibliographies/tex-truth.json +35 -0
  252. package/fixtures/paper-sources/v9-two-bibliographies/two.bib +1 -0
  253. package/fixtures/paper-typography/clean-paper/paper.tex +1 -1
  254. package/fixtures/paper-typography/messy-paper/paper.tex +1 -1
  255. package/package.json +2 -10
  256. package/scripts/check.test.ts +23 -1
  257. package/scripts/check.ts +7 -3
  258. package/scripts/coverage-config.test.ts +19 -10
  259. package/scripts/layer-legacy-frozen.test.ts +41 -2
  260. package/scripts/layer-legacy-frozen.ts +31 -2
  261. package/skills/grade-paper-writing/SKILL.md +4 -3
  262. package/skills/grade-paper-writing/SKILL.md.spec.ts +3 -2
  263. package/skills/grade-paper-writing/prose-lint.mjs +11 -2
  264. package/skills/grade-paper-writing/prose-lint.test.ts +52 -4
  265. package/skills/paper-pipeline/scripts/extract-ref-facts.harness.mjs +83 -33
  266. package/skills/paper-pipeline/scripts/extract-ref-facts.mjs +67 -115
  267. package/skills/paper-pipeline/scripts/extract-ref-facts.test.mjs +128 -121
  268. package/skills/verify-citations/SKILL.md +7 -4
  269. package/skills/verify-citations/SKILL.md.spec.ts +6 -3
  270. package/skills/verify-citations/scripts/bib-authors.check.test.mjs +17 -19
  271. package/skills/verify-citations/scripts/bib-authors.cli.test.ts +129 -46
  272. package/skills/verify-citations/scripts/bib-authors.d.mts +22 -2
  273. package/skills/verify-citations/scripts/bib-authors.mjs +57 -111
  274. package/skills/verify-citations/scripts/verify-cites.cli.test.ts +16 -0
  275. package/skills/verify-citations/scripts/verify-cites.d.mts +19 -3
  276. package/skills/verify-citations/scripts/verify-cites.mjs +42 -108
  277. package/skills/verify-citations/scripts/verify-cites.test.mjs +23 -36
  278. package/src/adapters/bibtex/index.test.ts +163 -0
  279. package/src/adapters/bibtex/index.ts +155 -0
  280. package/src/adapters/latex/filecontents.ts +114 -0
  281. package/src/adapters/latex/includes.ts +18 -10
  282. package/src/adapters/latex/index.test.ts +73 -0
  283. package/src/adapters/latex/index.ts +2 -0
  284. package/src/adapters/latex/nodes.ts +64 -0
  285. package/src/adapters/latex/parse.test.ts +38 -0
  286. package/src/adapters/latex/parse.ts +67 -6
  287. package/src/adapters/memory/index.ts +17 -0
  288. package/src/adapters/references/index.test.ts +75 -21
  289. package/src/adapters/references/index.ts +37 -32
  290. package/src/adapters/sources-record/index.test.ts +87 -0
  291. package/src/adapters/sources-record/index.ts +82 -0
  292. package/src/adapters/tex-output/blg.ts +27 -0
  293. package/src/adapters/tex-output/fls.ts +24 -0
  294. package/src/adapters/tex-output/index.test.ts +171 -0
  295. package/src/adapters/tex-output/index.ts +12 -0
  296. package/src/bib-rules.test.ts +356 -0
  297. package/src/bib-rules.ts +228 -0
  298. package/src/bibliography-at.test.ts +286 -0
  299. package/src/build.test.ts +210 -0
  300. package/src/build.ts +100 -35
  301. package/src/claim-provenance.test.ts +33 -7
  302. package/src/claim-provenance.ts +2 -2
  303. package/src/cli.harness.mjs +20 -10
  304. package/src/cli.test.ts +14 -10
  305. package/src/cli.ts +37 -28
  306. package/src/domain/paper-source.test.ts +58 -20
  307. package/src/domain/paper-source.ts +38 -42
  308. package/src/domain/paper-sources.ts +94 -0
  309. package/src/domain/sources-record.test.ts +71 -0
  310. package/src/domain/sources-record.ts +136 -0
  311. package/src/domain/tex-run.test.ts +228 -0
  312. package/src/domain/tex-run.ts +139 -0
  313. package/src/heading-case.test.ts +24 -10
  314. package/src/latex-log.ts +20 -0
  315. package/src/latex-loop.harness.ts +1 -0
  316. package/src/latex-loop.ts +2 -0
  317. package/src/linted-set.test.ts +9 -1
  318. package/src/new-paper.harness.mjs +3 -2
  319. package/src/new-paper.test.ts +9 -5
  320. package/src/package-dirs.ts +3 -2
  321. package/src/paper-includes.test.ts +157 -38
  322. package/src/paper-includes.ts +39 -35
  323. package/src/paper-prose.test.ts +34 -5
  324. package/src/paper-prose.ts +2 -2
  325. package/src/paper-record.test.ts +173 -0
  326. package/src/paper-record.ts +66 -0
  327. package/src/paper-settings-commands.test.ts +5 -2
  328. package/src/paper-sources.ts +151 -0
  329. package/src/ports/bib-reader.ts +27 -0
  330. package/src/ports/check-references.ts +7 -3
  331. package/src/ports/latex.ts +19 -0
  332. package/src/ports/sources-codec.ts +11 -0
  333. package/src/ports/tex-output.ts +17 -0
  334. package/src/recorded-bibliography.ts +297 -0
  335. package/src/reference-rules.ts +217 -104
  336. package/src/references.test.ts +520 -177
  337. package/src/references.ts +185 -37
  338. package/src/register-bands.test.ts +5 -1
  339. package/src/register-bands.ts +3 -5
  340. package/src/register.test.ts +6 -1
  341. package/src/register.ts +2 -2
  342. package/src/rule-cases.test.ts +68 -12
  343. package/src/rule-docs.test.ts +0 -1
  344. package/src/sources-record.test.ts +308 -0
  345. package/src/sources-record.ts +231 -0
  346. package/src/sources-rules.test.ts +152 -0
  347. package/src/sources-rules.ts +117 -0
  348. package/src/tex-paper.test.ts +148 -78
  349. package/src/tex-paper.ts +31 -61
  350. package/src/tex-venue-rules.test.ts +36 -8
  351. package/src/tex-venue-rules.ts +3 -5
  352. package/dist/eslint-rules/bib-reachable-entry.d.ts +0 -22
  353. package/dist/eslint-rules/bib-reachable-entry.d.ts.map +0 -1
  354. package/dist/eslint-rules/bib-reachable-entry.js +0 -75
  355. package/dist/eslint-rules/bib-reachable-entry.js.map +0 -1
  356. package/eslint-rules/bib-reachable-entry.ts +0 -76
@@ -0,0 +1,32 @@
1
+ {
2
+ "schema": 1,
3
+ "inputs": [
4
+ {
5
+ "path": "paper.tex",
6
+ "role": "body"
7
+ },
8
+ {
9
+ "path": "refs.bib",
10
+ "role": "preamble"
11
+ }
12
+ ],
13
+ "written": [],
14
+ "bibdata": [
15
+ "refs"
16
+ ],
17
+ "bibtex": {
18
+ "ran": true,
19
+ "databases": [
20
+ "refs.bib"
21
+ ],
22
+ "keys": [
23
+ "k1"
24
+ ],
25
+ "exit": 0,
26
+ "errors": []
27
+ },
28
+ "sha256": {
29
+ "paper.tex": "98021312aca10dcc347305e9de1abdd5549db5af26481af53fd5ca7c91c41635",
30
+ "refs.bib": "92432cd43420f561b25535a756ffe77a6c9270706e47ce1ea69950861878537f"
31
+ }
32
+ }
@@ -0,0 +1 @@
1
+ @misc{onekey, title={One}, author={A, B}, year={2020}}
@@ -0,0 +1,7 @@
1
+ \documentclass{article}
2
+ \begin{document}
3
+ \nocite{*}
4
+ \bibliographystyle{plain}
5
+ \bibliography{one,% the second database
6
+ two}
7
+ \end{document}
@@ -0,0 +1,32 @@
1
+ {
2
+ "schema": 1,
3
+ "inputs": [
4
+ {
5
+ "path": "paper.tex",
6
+ "role": "body"
7
+ }
8
+ ],
9
+ "written": [],
10
+ "bibdata": [
11
+ "one",
12
+ "two"
13
+ ],
14
+ "bibtex": {
15
+ "ran": true,
16
+ "databases": [
17
+ "one.bib",
18
+ "two.bib"
19
+ ],
20
+ "keys": [
21
+ "onekey",
22
+ "twokey"
23
+ ],
24
+ "exit": 0,
25
+ "errors": []
26
+ },
27
+ "sha256": {
28
+ "paper.tex": "3b8fd4a4505559b5c59a59cdec628b49fb89a6eb597cca9c2a2fe72d5911e4c0",
29
+ "one.bib": "61cca311ca7d77570ed410fc536c655ba76d36168fc3e56068235a2c4b16f7bf",
30
+ "two.bib": "bcceb63d26bb7fce0425b896cbceb533060dd7dd5616e8e0ff00a2e8749f4335"
31
+ }
32
+ }
@@ -0,0 +1 @@
1
+ @misc{twokey, title={Two}, author={A, B}, year={2020}}
@@ -0,0 +1,2 @@
1
+ @string{venue = "Proceedings of the Shared Venue"}
2
+ @string{who = "Lovelace, Ada"}
@@ -0,0 +1,6 @@
1
+ \documentclass{article}
2
+ \begin{document}
3
+ Text that cites~\cite{late}.
4
+ \bibliographystyle{plain}
5
+ \bibliography{abbreviations,references}
6
+ \end{document}
@@ -0,0 +1,6 @@
1
+ @inproceedings{late,
2
+ author = who,
3
+ title = {A Title},
4
+ booktitle = venue,
5
+ year = 2020,
6
+ }
@@ -0,0 +1,31 @@
1
+ {
2
+ "schema": 1,
3
+ "inputs": [
4
+ {
5
+ "path": "paper.tex",
6
+ "role": "body"
7
+ }
8
+ ],
9
+ "written": [],
10
+ "bibdata": [
11
+ "abbreviations",
12
+ "references"
13
+ ],
14
+ "bibtex": {
15
+ "ran": true,
16
+ "databases": [
17
+ "abbreviations.bib",
18
+ "references.bib"
19
+ ],
20
+ "keys": [
21
+ "late"
22
+ ],
23
+ "exit": 0,
24
+ "errors": []
25
+ },
26
+ "sha256": {
27
+ "paper.tex": "f6ba2a563017e122deabc252bc7b36f4d2ffc79ffcf1b4fca349465987aabbeb",
28
+ "abbreviations.bib": "73084cf971a07ab999e668a8ad68734052fb0bb113226082a16b8badf0570f65",
29
+ "references.bib": "e37a1b173ecba38d5b748338276f48b4d014c9975e919bdfd1c8bfe755d76ca2"
30
+ }
31
+ }
@@ -0,0 +1,2 @@
1
+ @string{venue = "Proceedings of the Shared Venue"}
2
+ @string{who = "Lovelace, Ada"}
@@ -0,0 +1,14 @@
1
+ \documentclass{article}
2
+ \begin{filecontents*}[overwrite]{refs.bib}
3
+ @inproceedings{late,
4
+ author = who,
5
+ title = {A Title},
6
+ booktitle = venue,
7
+ year = 2020,
8
+ }
9
+ \end{filecontents*}
10
+ \begin{document}
11
+ Text that cites~\cite{late}.
12
+ \bibliographystyle{plain}
13
+ \bibliography{abbreviations,refs}
14
+ \end{document}
@@ -0,0 +1,33 @@
1
+ {
2
+ "schema": 1,
3
+ "inputs": [
4
+ {
5
+ "path": "paper.tex",
6
+ "role": "body"
7
+ }
8
+ ],
9
+ "written": [
10
+ "refs.bib"
11
+ ],
12
+ "bibdata": [
13
+ "abbreviations",
14
+ "refs"
15
+ ],
16
+ "bibtex": {
17
+ "ran": true,
18
+ "databases": [
19
+ "abbreviations.bib",
20
+ "refs.bib"
21
+ ],
22
+ "keys": [
23
+ "late"
24
+ ],
25
+ "exit": 0,
26
+ "errors": []
27
+ },
28
+ "sha256": {
29
+ "paper.tex": "4a5f26663b1e9625a8e9b78dbcf5c5c2bc11aa019bbe63a7abbca25a8d97df9b",
30
+ "abbreviations.bib": "73084cf971a07ab999e668a8ad68734052fb0bb113226082a16b8badf0570f65",
31
+ "refs.bib": "e37a1b173ecba38d5b748338276f48b4d014c9975e919bdfd1c8bfe755d76ca2"
32
+ }
33
+ }
@@ -0,0 +1,9 @@
1
+ \documentclass{article}
2
+ \begin{filecontents*}{body.tex}
3
+ This sentence is typeset from a file a block wrote.
4
+ \end{filecontents*}
5
+ \begin{document}
6
+ Before the generated file.
7
+ \input{body}
8
+ After it.
9
+ \end{document}
@@ -0,0 +1,24 @@
1
+ {
2
+ "schema": 1,
3
+ "inputs": [
4
+ {
5
+ "path": "paper.tex",
6
+ "role": "body"
7
+ },
8
+ {
9
+ "path": "body.tex",
10
+ "role": "body"
11
+ }
12
+ ],
13
+ "written": [
14
+ "body.tex"
15
+ ],
16
+ "bibdata": [],
17
+ "bibtex": {
18
+ "ran": false
19
+ },
20
+ "sha256": {
21
+ "paper.tex": "4f7503a4dc744d30800a8dabe648769f174dcbdf5391e85e3cda1a02e742ea44",
22
+ "body.tex": "db9b3a64e25a0b579cb16e3b189d50d562fcdff6c38b33b0f76c6c0d567d965c"
23
+ }
24
+ }
@@ -0,0 +1,6 @@
1
+ @misc{declared2023,
2
+ title = {The Declared Entry},
3
+ author = {Poe, Paula},
4
+ year = {2023},
5
+ url = {https://example.org/declared}
6
+ }
@@ -0,0 +1,6 @@
1
+ \documentclass{article}
2
+ \begin{document}
3
+ Text that cites~\cite{declared2023}.
4
+ \bibliographystyle{plain}
5
+ \bibliography{paper}
6
+ \end{document}
@@ -0,0 +1,28 @@
1
+ {
2
+ "schema": 1,
3
+ "inputs": [
4
+ {
5
+ "path": "paper.tex",
6
+ "role": "body"
7
+ }
8
+ ],
9
+ "written": [],
10
+ "bibdata": [
11
+ "paper"
12
+ ],
13
+ "bibtex": {
14
+ "ran": true,
15
+ "databases": [
16
+ "paper.bib"
17
+ ],
18
+ "keys": [
19
+ "declared2023"
20
+ ],
21
+ "exit": 0,
22
+ "errors": []
23
+ },
24
+ "sha256": {
25
+ "paper.tex": "365c348f503b060973c7b1d5db0348659dffa91d7b149d10181204ae27e31dfb",
26
+ "paper.bib": "efe5f0577c8173e99be73ed728679904dcac9c90b1ec56350cf64d0771f8305e"
27
+ }
28
+ }
@@ -0,0 +1,14 @@
1
+ \documentclass{article}
2
+ \begin{filecontents*}
3
+ {refs.bib}
4
+ @misc{nl2024,
5
+ title = {The Name on the Next Line},
6
+ author = {Doe, Jane},
7
+ year = {2024}
8
+ }
9
+ \end{filecontents*}
10
+ \begin{document}
11
+ Text that cites~\cite{nl2024}.
12
+ \bibliographystyle{plain}
13
+ \bibliography{refs}
14
+ \end{document}
@@ -0,0 +1,30 @@
1
+ {
2
+ "schema": 1,
3
+ "inputs": [
4
+ {
5
+ "path": "paper.tex",
6
+ "role": "body"
7
+ }
8
+ ],
9
+ "written": [
10
+ "refs.bib"
11
+ ],
12
+ "bibdata": [
13
+ "refs"
14
+ ],
15
+ "bibtex": {
16
+ "ran": true,
17
+ "databases": [
18
+ "refs.bib"
19
+ ],
20
+ "keys": [
21
+ "nl2024"
22
+ ],
23
+ "exit": 0,
24
+ "errors": []
25
+ },
26
+ "sha256": {
27
+ "paper.tex": "143d03485e70ffefc525e6f783601c6f71e6650ccf779c77a4d7a8f12ba6075b",
28
+ "refs.bib": "b4c47cdd91aff598589dae3f0f068495af3680e5cdf0bce4747332750812ee1d"
29
+ }
30
+ }
@@ -0,0 +1,14 @@
1
+ \documentclass{article}
2
+ % \begin{filecontents*}{refs.bib}
3
+ % @misc{commented2024,
4
+ % title = {The Inline Entry},
5
+ % author = {Doe, Jane},
6
+ % year = {2024},
7
+ % url = {https://example.org/inline}
8
+ % }
9
+ % \end{filecontents*}
10
+ \begin{document}
11
+ Text that cites~\cite{commented2024} and~\cite{stale2020}.
12
+ \bibliographystyle{plain}
13
+ \bibliography{refs}
14
+ \end{document}
@@ -0,0 +1,6 @@
1
+ @misc{stale2020,
2
+ title = {The Stale Entry},
3
+ author = {Roe, Rich},
4
+ year = {2020},
5
+ url = {https://example.org/stale}
6
+ }
@@ -0,0 +1,28 @@
1
+ {
2
+ "schema": 1,
3
+ "inputs": [
4
+ {
5
+ "path": "paper.tex",
6
+ "role": "body"
7
+ }
8
+ ],
9
+ "written": [],
10
+ "bibdata": [
11
+ "refs"
12
+ ],
13
+ "bibtex": {
14
+ "ran": true,
15
+ "databases": [
16
+ "refs.bib"
17
+ ],
18
+ "keys": [
19
+ "stale2020"
20
+ ],
21
+ "exit": 0,
22
+ "errors": []
23
+ },
24
+ "sha256": {
25
+ "paper.tex": "a0a0349afca7a2de8b41bdbdf777de14d8e07df5993a351492ca11c858f8c34e",
26
+ "refs.bib": "7a720777755f3dd727c2428f66f06d5f818f367e41fe4c47543aa9f55adfebb4"
27
+ }
28
+ }
@@ -0,0 +1,20 @@
1
+ \documentclass{article}
2
+ \begin{filecontents*}[overwrite]{refs.bib}
3
+ @misc{inline2024,
4
+ title = {The Inline Entry},
5
+ author = {Doe, Jane},
6
+ year = {2024},
7
+ url = {https://example.org/inline}
8
+ }
9
+ % @misc{dead2020,
10
+ % title = {The Entry Behind a Percent Sign},
11
+ % author = {Moe, Max},
12
+ % year = {2020},
13
+ % url = {https://example.org/dead}
14
+ % }
15
+ \end{filecontents*}
16
+ \begin{document}
17
+ Text that cites~\cite{inline2024} and~\cite{dead2020}.
18
+ \bibliographystyle{plain}
19
+ \bibliography{refs}
20
+ \end{document}
@@ -0,0 +1,37 @@
1
+ {
2
+ "schema": 1,
3
+ "inputs": [
4
+ {
5
+ "path": "paper.tex",
6
+ "role": "body"
7
+ }
8
+ ],
9
+ "written": [
10
+ "refs.bib"
11
+ ],
12
+ "bibdata": [
13
+ "refs"
14
+ ],
15
+ "bibtex": {
16
+ "ran": true,
17
+ "databases": [
18
+ "refs.bib"
19
+ ],
20
+ "keys": [
21
+ "dead2020",
22
+ "inline2024"
23
+ ],
24
+ "exit": 2,
25
+ "errors": [
26
+ {
27
+ "message": "You're missing a field name",
28
+ "file": "refs.bib",
29
+ "line": 8
30
+ }
31
+ ]
32
+ },
33
+ "sha256": {
34
+ "paper.tex": "f520de6b9f34e249851913d2e9fc23532603378787b034e08e0b43e2bc111994",
35
+ "refs.bib": "247d564a35129b3fa087ae2541cd51130c1e6875fafe5dad36d694f6a4d1b7fc"
36
+ }
37
+ }
@@ -0,0 +1,6 @@
1
+ \documentclass{article}
2
+ \begin{document}
3
+ \nocite{*}
4
+ \bibliographystyle{plain}
5
+ \bibliography{refs}
6
+ \end{document}
@@ -0,0 +1,5 @@
1
+ @misc{a1, title={A}, author={A, B}, year={2020}, url={https://e.org/a1}}
2
+ @misc{a2unclosed, title={Two}, author={A, B}, year={2020}, url={https://e.org/a2}
3
+
4
+ @misc{a3, title={Three}, author={A, B}, year={2020}}
5
+ % @misc{a4, title={Four}, author={A, B}, year={2020}}
@@ -0,0 +1,37 @@
1
+ {
2
+ "schema": 1,
3
+ "inputs": [
4
+ {
5
+ "path": "paper.tex",
6
+ "role": "body"
7
+ }
8
+ ],
9
+ "written": [],
10
+ "bibdata": [
11
+ "refs"
12
+ ],
13
+ "bibtex": {
14
+ "ran": true,
15
+ "databases": [
16
+ "refs.bib"
17
+ ],
18
+ "keys": [
19
+ "a1",
20
+ "a4",
21
+ "a3",
22
+ "a2unclosed"
23
+ ],
24
+ "exit": 2,
25
+ "errors": [
26
+ {
27
+ "message": "I was expecting a `,' or a `}'",
28
+ "file": "refs.bib",
29
+ "line": 4
30
+ }
31
+ ]
32
+ },
33
+ "sha256": {
34
+ "paper.tex": "9ad22f9c50070c2620c5bf8885ed53cee4b0901e7bfdc83c61f70902686ac5e0",
35
+ "refs.bib": "1d33d35cf2e384fc54acf45654493881315c98a4b494b952464668d33924aeec"
36
+ }
37
+ }
@@ -0,0 +1,9 @@
1
+ \documentclass{article}
2
+ \begin{filecontents*}[overwrite]{\jobname.bib}
3
+ @misc{jkey, title={J}, author={Doe, J}, year={2024}}
4
+ % @misc{jdead, title={D}, author={Doe, J}, year={2020}}
5
+ \end{filecontents*}
6
+ \begin{document}
7
+ Text~\cite{jkey}.
8
+ \bibliographystyle{plain}\bibliography{\jobname}
9
+ \end{document}
@@ -0,0 +1,30 @@
1
+ {
2
+ "schema": 1,
3
+ "inputs": [
4
+ {
5
+ "path": "paper.tex",
6
+ "role": "body"
7
+ }
8
+ ],
9
+ "written": [
10
+ "paper.bib"
11
+ ],
12
+ "bibdata": [
13
+ "paper"
14
+ ],
15
+ "bibtex": {
16
+ "ran": true,
17
+ "databases": [
18
+ "paper.bib"
19
+ ],
20
+ "keys": [
21
+ "jkey"
22
+ ],
23
+ "exit": 0,
24
+ "errors": []
25
+ },
26
+ "sha256": {
27
+ "paper.tex": "d68bcaabe9be4cbc07f5a1e672e8cd448e96bc9b5134be350d2906ee48834482",
28
+ "paper.bib": "bc5a9faf4bbdcdf22705c4c8b69d656382ab9d1d03f57388c00631c3aa6ebf70"
29
+ }
30
+ }
@@ -0,0 +1 @@
1
+ @misc{onekey, title={One}, author={A, B}, year={2020}}
@@ -0,0 +1,7 @@
1
+ \documentclass{article}
2
+ \begin{document}
3
+ \nocite{*}
4
+ \bibliographystyle{plain}
5
+ \bibliography{one}
6
+ \bibliography{two}
7
+ \end{document}
@@ -0,0 +1,35 @@
1
+ {
2
+ "schema": 1,
3
+ "inputs": [
4
+ {
5
+ "path": "paper.tex",
6
+ "role": "body"
7
+ }
8
+ ],
9
+ "written": [],
10
+ "bibdata": [
11
+ "one",
12
+ "two"
13
+ ],
14
+ "bibtex": {
15
+ "ran": true,
16
+ "databases": [
17
+ "one.bib"
18
+ ],
19
+ "keys": [
20
+ "onekey"
21
+ ],
22
+ "exit": 2,
23
+ "errors": [
24
+ {
25
+ "message": "Illegal, another \\bibdata command",
26
+ "file": "paper.aux",
27
+ "line": 5
28
+ }
29
+ ]
30
+ },
31
+ "sha256": {
32
+ "paper.tex": "f45db61354f01066eb49ab48d240033bea99ed172f04a2c4558daca8640ce796",
33
+ "one.bib": "61cca311ca7d77570ed410fc536c655ba76d36168fc3e56068235a2c4b16f7bf"
34
+ }
35
+ }
@@ -0,0 +1 @@
1
+ @misc{twokey, title={Two}, author={A, B}, year={2020}}
@@ -1,5 +1,5 @@
1
1
  \documentclass{acmart}
2
- \begin{filecontents*}{refs.bib}
2
+ \begin{filecontents*}[overwrite]{refs.bib}
3
3
  @inproceedings{reachable,
4
4
  title = {A paper a reader can actually open},
5
5
  author = {Doe, Jane},
@@ -1,5 +1,5 @@
1
1
  \documentclass{acmart}
2
- \begin{filecontents*}{refs.bib}
2
+ \begin{filecontents*}[overwrite]{refs.bib}
3
3
  @inproceedings{unreachableone,
4
4
  title = {No doi, no url, no arXiv id},
5
5
  author = {Doe, Jane},
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "paperlint",
3
- "version": "8.0.0",
3
+ "version": "9.0.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",
@@ -20,6 +20,7 @@
20
20
  "dependencies": {
21
21
  "@eslint/markdown": "^8.0.3",
22
22
  "@eslint/plugin-kit": "^0.7.2",
23
+ "@retorquere/bibtex-parser": "^10.0.1",
23
24
  "@unified-latex/unified-latex-types": "^1.8.4",
24
25
  "@unified-latex/unified-latex-util-parse": "^1.8.4",
25
26
  "@unified-latex/unified-latex-util-visit": "^1.8.4",
@@ -37,7 +38,6 @@
37
38
  "zod": "^4.6.5"
38
39
  },
39
40
  "devDependencies": {
40
- "@retorquere/bibtex-parser": "^10.0.1",
41
41
  "@semantic-release/commit-analyzer": "13.0.1",
42
42
  "@semantic-release/release-notes-generator": "14.1.1",
43
43
  "@types/js-yaml": "^4.0.9",
@@ -56,14 +56,6 @@
56
56
  "typescript-eslint": "^8.70.1",
57
57
  "vitest": "^4.1.11"
58
58
  },
59
- "peerDependencies": {
60
- "@retorquere/bibtex-parser": "^10.0.1"
61
- },
62
- "peerDependenciesMeta": {
63
- "@retorquere/bibtex-parser": {
64
- "optional": true
65
- }
66
- },
67
59
  "repository": {
68
60
  "type": "git",
69
61
  "url": "git+https://github.com/zernie/paperlint.git"
@@ -6,7 +6,7 @@
6
6
  import assert from "node:assert/strict";
7
7
  import { spawnSync } from "node:child_process";
8
8
  import { fileURLToPath } from "node:url";
9
- import { test } from "vitest";
9
+ import { test, vi } from "vitest";
10
10
  import {
11
11
  GATES,
12
12
  NOT_COVERED,
@@ -122,6 +122,28 @@ test("🔴 runGates: a vitest gate that exits 0 but leaves no report is a FAILUR
122
122
  );
123
123
  });
124
124
 
125
+ test("🔴 every gate runs with CI=true, as CI runs it — a local check is the CI check", () => {
126
+ // Libraries change behaviour under CI=true (typescript-eslint infers a single run and parses from
127
+ // disk): a gate run without it passed locally and failed in CI on 2026-10-07.
128
+ // Whatever the caller's shell says: on CI it is already "true", so the test sets it otherwise.
129
+ vi.stubEnv("CI", "false");
130
+ const seen: (string | undefined)[] = [];
131
+ runGates({
132
+ gates: [
133
+ { name: "a", job: "gates", run: ["true"] },
134
+ { name: "b", job: "gates", script: "build" },
135
+ ],
136
+ spawn: (_cmd, _args, options) => {
137
+ seen.push(options.env["CI"]);
138
+ return { status: 0 };
139
+ },
140
+ write: () => {},
141
+ ...capture().io,
142
+ });
143
+ vi.unstubAllEnvs();
144
+ assert.deepEqual(seen, ["true", "true"]);
145
+ });
146
+
125
147
  test("run as a program with every gate passing: the plain verdict, exit 0", () => {
126
148
  // spawnSync is replaced before check.ts loads, so the real file runs end to end — every gate
127
149
  // "passes" in microseconds instead of the eleven real ones running.