paperlint 7.2.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 +41 -30
- package/dist/build.js.map +1 -1
- package/dist/claim-provenance.d.ts +2 -2
- package/dist/cli.d.ts +9 -5
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +43 -68
- 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/latex-language.d.ts.map +1 -1
- package/dist/eslint-rules/latex-language.js +10 -13
- package/dist/eslint-rules/latex-language.js.map +1 -1
- package/dist/eslint-rules/paper-context.d.ts.map +1 -1
- package/dist/eslint-rules/paper-context.js +6 -5
- 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 +34 -96
- package/dist/eslint-rules/paper-typography.js.map +1 -1
- package/dist/eslint-rules/papers.d.ts +1 -3
- package/dist/eslint-rules/papers.d.ts.map +1 -1
- package/dist/eslint-rules/papers.js +2 -4
- package/dist/eslint-rules/papers.js.map +1 -1
- package/dist/eslint-rules/tex-build.d.ts.map +1 -1
- package/dist/eslint-rules/tex-build.js +8 -25
- package/dist/eslint-rules/tex-build.js.map +1 -1
- package/dist/init.d.ts +1 -4
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +3 -9
- package/dist/init.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/lib/markdown.d.ts +5 -81
- package/dist/lib/markdown.d.ts.map +1 -1
- package/dist/lib/markdown.js +5 -116
- package/dist/lib/markdown.js.map +1 -1
- package/dist/lib/paper-config.d.ts.map +1 -1
- package/dist/lib/paper-config.js +0 -2
- package/dist/lib/paper-config.js.map +1 -1
- package/dist/lib/skill-eval-fixture.d.ts +6 -4
- package/dist/lib/skill-eval-fixture.d.ts.map +1 -1
- package/dist/lib/skill-eval-fixture.js +25 -18
- package/dist/lib/skill-eval-fixture.js.map +1 -1
- package/dist/new-paper.d.ts +5 -11
- package/dist/new-paper.d.ts.map +1 -1
- package/dist/new-paper.js +12 -23
- package/dist/new-paper.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-files.d.ts +4 -4
- 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 +17 -0
- package/dist/paper-prose.d.ts.map +1 -0
- package/dist/paper-prose.js +46 -0
- package/dist/paper-prose.js.map +1 -0
- 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/structure.d.ts.map +1 -1
- package/dist/structure.js +4 -3
- package/dist/structure.js.map +1 -1
- 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/dist/types.d.ts +0 -2
- package/dist/types.d.ts.map +1 -1
- package/docs/configuration.md +18 -12
- package/docs/design/paper-sources.md +197 -0
- package/docs/e2e.md +4 -6
- package/docs/package-shape-options.md +1 -1
- package/docs/prior-art/paper-folder-scaffolding.md +24 -29
- 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/tex/claim-provenance.md +0 -1
- package/docs/rules.md +62 -61
- package/eslint-rules/latex-language.harness.mjs +3 -3
- package/eslint-rules/latex-language.ts +10 -13
- package/eslint-rules/paper-context.ts +6 -5
- package/eslint-rules/paper-typography.test.mjs +29 -157
- package/eslint-rules/paper-typography.ts +35 -104
- package/eslint-rules/papers.harness.mjs +1 -1
- package/eslint-rules/papers.ts +2 -4
- package/eslint-rules/tex-build.harness.mjs +2 -2
- package/eslint-rules/tex-build.ts +8 -25
- package/eslint.config.mjs +22 -1
- 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/hooks/hooks.harness.ts +15 -15
- package/hooks/paper-edit-guard.hook.mjs +5 -8
- package/hooks/paper-edit-guard.test.ts +12 -3
- package/hooks/paper-skills-nudge.hook.mjs +2 -3
- package/hooks/paper-skills-nudge.test.ts +13 -3
- package/hooks/paper-status-gates.hook.mjs +2 -2
- package/hooks/paper-status-gates.test.ts +14 -2
- package/lib/markdown.test.mjs +5 -60
- package/lib/markdown.ts +9 -136
- package/lib/paper-config.ts +0 -2
- package/lib/skill-checks.test.mjs +4 -1
- package/lib/skill-eval-fixture.ts +25 -18
- package/package.json +2 -12
- package/presets/realm.jsonc +1 -1
- package/scripts/check.test.ts +23 -1
- package/scripts/check.ts +7 -3
- package/scripts/coverage-config.test.ts +19 -10
- package/scripts/harness-api.frozen.json +0 -5
- package/scripts/layer-legacy-frozen.test.ts +41 -2
- package/scripts/layer-legacy-frozen.ts +31 -2
- package/skills/cold-read-diff/SKILL.md +3 -3
- package/skills/cold-read-diff/SKILL.md.spec.ts +2 -2
- package/skills/grade-paper-writing/SKILL.md +15 -22
- package/skills/grade-paper-writing/SKILL.md.spec.ts +14 -21
- package/skills/grade-paper-writing/__snapshots__/prose-lint.test.ts.snap +40 -26
- package/skills/grade-paper-writing/prose-lint.mjs +117 -278
- package/skills/grade-paper-writing/prose-lint.test.ts +230 -79
- package/skills/paper-adversarial-review/SKILL.md +2 -2
- package/skills/paper-adversarial-review/SKILL.md.spec.ts +1 -1
- package/skills/paper-pipeline/SKILL.md +9 -12
- package/skills/paper-pipeline/SKILL.md.spec.ts +8 -11
- package/skills/paper-pipeline/description-language.eval.mjs +25 -15
- package/skills/paper-pipeline/framing-vs-vocabulary.eval.mjs +25 -15
- package/skills/paper-pipeline/grade-paper-writing-ablation.eval.mjs +25 -15
- package/skills/paper-pipeline/pipeline-firing.eval.mjs +27 -16
- package/skills/paper-pipeline/pipeline-language.eval.mjs +25 -15
- package/skills/paper-pipeline/references/acceptance-gate.md +16 -20
- package/skills/paper-pipeline/references/artifact-checklist.md +4 -5
- package/skills/paper-pipeline/references/pipeline-status-template.md +1 -1
- package/skills/paper-pipeline/scripts/README.md +0 -4
- package/skills/paper-pipeline/scripts/extract-ref-facts.harness.mjs +91 -105
- package/skills/paper-pipeline/scripts/extract-ref-facts.mjs +85 -241
- package/skills/paper-pipeline/scripts/extract-ref-facts.test.mjs +166 -153
- package/skills/paper-pipeline/scripts/generated-code.harness.mjs +3 -3
- package/skills/paper-status/SKILL.md +2 -2
- package/skills/paper-status/SKILL.md.spec.ts +1 -1
- package/skills/render-paper/SKILL.md +2 -2
- package/skills/render-paper/SKILL.md.spec.ts +1 -1
- package/skills/render-paper/extract-pdf-facts.mjs +2 -2
- package/skills/tighten-paper/SKILL.md +29 -42
- package/skills/tighten-paper/SKILL.md.spec.ts +28 -41
- 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 -32
- package/skills/verify-citations/scripts/bib-authors.cli.test.ts +138 -43
- package/skills/verify-citations/scripts/bib-authors.d.mts +22 -2
- package/skills/verify-citations/scripts/bib-authors.mjs +54 -193
- package/skills/verify-citations/scripts/bib-authors.test.mjs +1 -44
- 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.harness.mjs +2 -2
- package/src/build.test.ts +211 -1
- package/src/build.ts +101 -41
- package/src/claim-provenance.test.ts +33 -7
- package/src/claim-provenance.ts +2 -2
- package/src/cli.harness.mjs +46 -56
- package/src/cli.test.ts +44 -48
- package/src/cli.ts +51 -82
- 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/folder-venue-rule.test.ts +1 -1
- package/src/heading-case.test.ts +24 -10
- package/src/init.test.ts +6 -7
- package/src/init.ts +3 -22
- package/src/latex-log.ts +20 -0
- package/src/latex-loop.harness.ts +1 -0
- package/src/latex-loop.ts +2 -0
- package/src/lint-fix.test.ts +10 -4
- package/src/linted-set.test.ts +9 -1
- package/src/new-paper.harness.mjs +12 -30
- package/src/new-paper.test.ts +15 -11
- package/src/new-paper.ts +11 -30
- package/src/package-dirs.ts +3 -2
- package/src/paper-files.test.ts +5 -4
- package/src/paper-files.ts +4 -4
- package/src/paper-includes.test.ts +157 -38
- package/src/paper-includes.ts +39 -35
- package/src/paper-prose.test.ts +78 -0
- package/src/paper-prose.ts +67 -0
- 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/parse-args.test.ts +0 -1
- 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/structure.harness.ts +5 -11
- package/src/structure.ts +4 -3
- 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/src/types.ts +0 -2
- 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
- package/fixtures/real-markdown-paper/baseline.json +0 -22
- package/fixtures/real-markdown-paper/baseline.ts +0 -70
- package/skills/paper-pipeline/PIPELINE-MAP.md +0 -381
- package/skills/paper-pipeline/pipeline-firing.baseline.json +0 -270
- package/skills/paper-pipeline/references/sweep-2026-08-09-ideal-pipeline.md +0 -585
- package/skills/paper-pipeline/scripts/artifact-coverage.harness.mjs +0 -492
- package/skills/paper-pipeline/scripts/artifact-coverage.mjs +0 -397
- package/skills/paper-pipeline/scripts/artifact-coverage.test.ts +0 -86
- package/skills/paper-pipeline/scripts/check-provenance.mjs +0 -184
- package/skills/paper-pipeline/scripts/population-map.harness.mjs +0 -135
- package/skills/paper-pipeline/scripts/population-map.mjs +0 -188
- package/skills/paper-pipeline/scripts/population-map.test.mjs +0 -154
- package/skills/paper-pipeline/scripts/provenance.harness.mjs +0 -266
- package/skills/paper-pipeline/scripts/round-diff.harness.ts +0 -907
- package/skills/paper-pipeline/scripts/round-diff.mjs +0 -583
- package/skills/paper-pipeline/scripts/round-diff.test.mjs +0 -159
- package/skills/tighten-paper/__snapshots__/structure.test.ts.snap +0 -133
- package/skills/tighten-paper/structure.mjs +0 -364
- package/skills/tighten-paper/structure.test.ts +0 -117
- package/templates/paper/paper.md +0 -4
package/src/cli.test.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import assert from "node:assert/strict";
|
|
8
8
|
import { spawn } from "node:child_process";
|
|
9
|
-
import { existsSync } from "node:fs";
|
|
9
|
+
import { existsSync, readdirSync } from "node:fs";
|
|
10
10
|
import { createServer } from "node:http";
|
|
11
11
|
import { dirname, join } from "node:path";
|
|
12
12
|
import { test } from "vitest";
|
|
@@ -33,13 +33,18 @@ import { texInputsDir } from "./package-dirs.ts";
|
|
|
33
33
|
const root = useTempDir("cli-test-");
|
|
34
34
|
|
|
35
35
|
/** `run(argv)` from `cwd`, the output as one string per stream. */
|
|
36
|
-
async function cli(
|
|
36
|
+
async function cli(
|
|
37
|
+
argv: string[],
|
|
38
|
+
cwd: string,
|
|
39
|
+
deps: Pick<NonNullable<Parameters<typeof run>[1]>, "loadTexLanguage"> = {},
|
|
40
|
+
) {
|
|
37
41
|
const out: string[] = [];
|
|
38
42
|
const err: string[] = [];
|
|
39
43
|
const code = await run(argv, {
|
|
40
44
|
log: (...a: unknown[]) => out.push(a.join(" ")),
|
|
41
45
|
err: (...a: unknown[]) => err.push(a.join(" ")),
|
|
42
46
|
cwd,
|
|
47
|
+
...deps,
|
|
43
48
|
});
|
|
44
49
|
return { code, out: out.join("\n"), err: err.join("\n") };
|
|
45
50
|
}
|
|
@@ -50,14 +55,14 @@ test("parseArgs: the boolean flags of build and toolchain, and a value flag with
|
|
|
50
55
|
[
|
|
51
56
|
parseArgs(["build", "--all", "--dry-run", "papers/p"]),
|
|
52
57
|
parseArgs(["toolchain", "--check"]),
|
|
53
|
-
parseArgs(["new", "x", "--
|
|
58
|
+
parseArgs(["new", "x", "--paper"]),
|
|
54
59
|
parseArgs(["new", "x", "--venue="]),
|
|
55
60
|
parseArgs(["new", "x", "--kind", "short", "--max-warnings=3"]),
|
|
56
61
|
],
|
|
57
62
|
[
|
|
58
63
|
{ ...base, cmd: "build", all: true, dryRun: true, paths: ["papers/p"] },
|
|
59
64
|
{ ...base, cmd: "toolchain", check: true },
|
|
60
|
-
{ ...base, cmd: "new", paths: ["x"], missingValue: "--
|
|
65
|
+
{ ...base, cmd: "new", paths: ["x"], missingValue: "--paper" },
|
|
61
66
|
{ ...base, cmd: "new", paths: ["x"], missingValue: "--venue" },
|
|
62
67
|
{ ...base, cmd: "new", paths: ["x"], kind: "short", maxWarnings: 3 },
|
|
63
68
|
],
|
|
@@ -142,20 +147,18 @@ test("build refuses with no target, and --all over no papers", async () => {
|
|
|
142
147
|
);
|
|
143
148
|
});
|
|
144
149
|
|
|
145
|
-
test("new refuses
|
|
150
|
+
test("new refuses a broken config, and a config that names no papers directory", async () => {
|
|
146
151
|
const broken = join(root, "new-broken");
|
|
147
152
|
writeTree(broken, { "paperlint.json": "{ not json" });
|
|
148
153
|
const none = join(root, "new-none");
|
|
149
154
|
writeTree(none, { "paperlint.json": JSON.stringify({ papersDir: [] }) });
|
|
150
155
|
const results = [
|
|
151
|
-
await cli(["new", "p"
|
|
152
|
-
await cli(["new", "p"
|
|
153
|
-
await cli(["new", "p", "--format", "md"], none),
|
|
156
|
+
await cli(["new", "p"], broken),
|
|
157
|
+
await cli(["new", "p"], none),
|
|
154
158
|
];
|
|
155
159
|
assert.deepEqual(
|
|
156
160
|
results.map((r) => ({ code: r.code, err: r.err.split(":")[0] })),
|
|
157
161
|
[
|
|
158
|
-
{ code: 2, err: "--format must be one of tex, md — got `docx`" },
|
|
159
162
|
{ code: 2, err: join(broken, "paperlint.json is not valid JSON") },
|
|
160
163
|
{
|
|
161
164
|
code: 2,
|
|
@@ -170,7 +173,7 @@ test("new with several papers directories says which one it used", async () => {
|
|
|
170
173
|
writeTree(dir, {
|
|
171
174
|
"paperlint.json": JSON.stringify({ papersDir: ["a", "b"] }),
|
|
172
175
|
});
|
|
173
|
-
const r = await cli(["new", "p", "--
|
|
176
|
+
const r = await cli(["new", "p", "--yes"], dir);
|
|
174
177
|
assert.equal(
|
|
175
178
|
r.out.split("\n")[0],
|
|
176
179
|
"several papers directories are declared — using the first: a",
|
|
@@ -274,20 +277,20 @@ async function withoutTex<T>(dir: string, fn: () => Promise<T>): Promise<T> {
|
|
|
274
277
|
const noTexDir = join(root, "build-notex");
|
|
275
278
|
writeTree(noTexDir, {
|
|
276
279
|
"package.json": "{}",
|
|
277
|
-
"papers/
|
|
280
|
+
"papers/nosource/notes.txt": "x\n",
|
|
278
281
|
"papers/tex/paper.tex":
|
|
279
282
|
"\\documentclass{article}\\begin{document}x\\end{document}\n",
|
|
280
283
|
});
|
|
281
284
|
const venues = texInputsDir();
|
|
282
285
|
|
|
283
|
-
test("build: a
|
|
284
|
-
const
|
|
285
|
-
cli(["build", "papers/
|
|
286
|
+
test("build: a paper with no paper.tex is refused, naming paper.tex", async () => {
|
|
287
|
+
const none = await withoutTex(noTexDir, () =>
|
|
288
|
+
cli(["build", "papers/nosource"], noTexDir),
|
|
286
289
|
);
|
|
287
|
-
assert.deepEqual(
|
|
290
|
+
assert.deepEqual(none, {
|
|
288
291
|
code: 1,
|
|
289
292
|
out: [
|
|
290
|
-
"papers/
|
|
293
|
+
"papers/nosource",
|
|
291
294
|
` inputs: TEXINPUTS += the paper's directory, then ${venues}`,
|
|
292
295
|
" compile: refused — no paper.tex; paperlint compiles LaTeX, and this paper has none",
|
|
293
296
|
" measure: skipped — nothing is compiled",
|
|
@@ -295,7 +298,7 @@ test("build: a markdown-only paper is refused", async () => {
|
|
|
295
298
|
" ✗ nothing to compile: no paper.tex",
|
|
296
299
|
].join("\n"),
|
|
297
300
|
err:
|
|
298
|
-
"\nNo paper.tex in: papers/
|
|
301
|
+
"\nNo paper.tex in: papers/nosource.\n" +
|
|
299
302
|
'This is NOT "nothing to build" — paperlint compiles LaTeX, and these papers have no LaTeX source.\n' +
|
|
300
303
|
"Write the paper in paper.tex; `paperlint new <name>` creates one.",
|
|
301
304
|
});
|
|
@@ -399,7 +402,7 @@ test("build --dry-run on a paper with a venue plans for the preset's packages",
|
|
|
399
402
|
|
|
400
403
|
test("a paper's paperlint.json that does not parse stops the lint with its path", () => {
|
|
401
404
|
const dir = writeTree(join(root, "rules-broken"), {
|
|
402
|
-
"p/paper.
|
|
405
|
+
"p/paper.tex": "% P\n",
|
|
403
406
|
"p/paperlint.json": "{ nope",
|
|
404
407
|
});
|
|
405
408
|
const r = paperRuleBlocks([join(dir, "p")]);
|
|
@@ -444,15 +447,12 @@ test("silentOptionalRules: a rule no block names for any paper is silent — a g
|
|
|
444
447
|
);
|
|
445
448
|
});
|
|
446
449
|
|
|
447
|
-
test("init with no path
|
|
450
|
+
test("init with no path sets up the current directory, and its first paper is paper.tex", async () => {
|
|
448
451
|
const dir = writeTree(join(root, "init-here"), { "package.json": "{}" });
|
|
449
|
-
const r = await cli(
|
|
450
|
-
|
|
451
|
-
dir,
|
|
452
|
-
|
|
453
|
-
assert.equal(
|
|
454
|
-
existsSync(join(dir, "papers", "first", "paper.md")),
|
|
455
|
-
true,
|
|
452
|
+
const r = await cli(["init", "--yes", "--no-hooks", "--paper", "first"], dir);
|
|
453
|
+
assert.deepEqual(
|
|
454
|
+
readdirSync(join(dir, "papers", "first")).sort(),
|
|
455
|
+
["PIPELINE-STATUS.md", "paper.tex", "paperlint.json"],
|
|
456
456
|
r.out + r.err,
|
|
457
457
|
);
|
|
458
458
|
});
|
|
@@ -488,12 +488,9 @@ test("lint: a named directory with nothing paperlint lints is named in full when
|
|
|
488
488
|
test("new from inside the paper it names adds the missing files and names the paper in full", async () => {
|
|
489
489
|
const dir = writeTree(join(root, "new-inside"), {
|
|
490
490
|
"paperlint.json": JSON.stringify({ papersDir: "papers" }),
|
|
491
|
-
"papers/p/paper.
|
|
491
|
+
"papers/p/paper.tex": "% P\n",
|
|
492
492
|
});
|
|
493
|
-
const r = await cli(
|
|
494
|
-
["new", "p", "--format", "md", "--yes"],
|
|
495
|
-
join(dir, "papers", "p"),
|
|
496
|
-
);
|
|
493
|
+
const r = await cli(["new", "p", "--yes"], join(dir, "papers", "p"));
|
|
497
494
|
assert.match(
|
|
498
495
|
r.out,
|
|
499
496
|
new RegExp(
|
|
@@ -507,7 +504,7 @@ test("new with several directories, run from the first, names it in full", async
|
|
|
507
504
|
"paperlint.json": JSON.stringify({ papersDir: ["a", "b"] }),
|
|
508
505
|
"a/.keep": "",
|
|
509
506
|
});
|
|
510
|
-
const r = await cli(["new", "p", "--
|
|
507
|
+
const r = await cli(["new", "p", "--yes"], join(dir, "a"));
|
|
511
508
|
assert.equal(
|
|
512
509
|
r.out.split("\n")[0],
|
|
513
510
|
`several papers directories are declared — using the first: ${join(dir, "a")}`,
|
|
@@ -519,7 +516,7 @@ test("lint: an ESLint failure that is not an empty set is not swallowed", async
|
|
|
519
516
|
"paperlint.json": JSON.stringify({
|
|
520
517
|
rules: { "paper/stages": ["error", { x: 1 }] },
|
|
521
518
|
}),
|
|
522
|
-
"papers/p/paper.
|
|
519
|
+
"papers/p/paper.tex": "% P\n",
|
|
523
520
|
"papers/p/PIPELINE-STATUS.md": "---\nstages: []\n---\n# S\n",
|
|
524
521
|
});
|
|
525
522
|
await assert.rejects(cli(["lint"], dir), {
|
|
@@ -582,11 +579,11 @@ function newAtTerminal(cwd: string, answers: Record<string, string>) {
|
|
|
582
579
|
});
|
|
583
580
|
}
|
|
584
581
|
|
|
585
|
-
test("new at a terminal asks for the
|
|
586
|
-
const
|
|
587
|
-
const r = await newAtTerminal(
|
|
582
|
+
test("new at a terminal asks for the venue; the answer picks it", async () => {
|
|
583
|
+
const dir = writeTree(join(root, "new-tty"), { "package.json": "{}" });
|
|
584
|
+
const r = await newAtTerminal(dir, { "venue:": "none\n" });
|
|
588
585
|
assert.equal(r.status, 0, r.out);
|
|
589
|
-
assert.equal(existsSync(join(
|
|
586
|
+
assert.equal(existsSync(join(dir, "papers", "first", "paper.tex")), true);
|
|
590
587
|
});
|
|
591
588
|
|
|
592
589
|
test("chooseVenue: a question that fails (the stream ended) takes the default, no venue", async () => {
|
|
@@ -625,21 +622,20 @@ test("init's TeX Live install runs the toolchain over the project's papers, neve
|
|
|
625
622
|
assert.equal(typeof here.installed(), "boolean");
|
|
626
623
|
});
|
|
627
624
|
|
|
628
|
-
test("lint with its LaTeX language missing from the install still lints the
|
|
625
|
+
test("lint with its LaTeX language missing from the install still lints the scorecards", async () => {
|
|
629
626
|
const dir = writeTree(join(root, "lint-no-tex-language"), {
|
|
630
|
-
"papers/p/
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
627
|
+
"papers/p/PIPELINE-STATUS.md": "---\nstages: []\n---\n# S\n",
|
|
628
|
+
});
|
|
629
|
+
const gone = Object.assign(new Error("gone"), {
|
|
630
|
+
code: "ERR_MODULE_NOT_FOUND",
|
|
634
631
|
});
|
|
635
|
-
const without =
|
|
636
|
-
|
|
637
|
-
nodeArgs: ["--import", join(dir, "no-latex.mjs")],
|
|
632
|
+
const without = await cli(["lint", "papers"], dir, {
|
|
633
|
+
loadTexLanguage: () => Promise.reject(gone),
|
|
638
634
|
});
|
|
639
|
-
const whole =
|
|
640
|
-
// A
|
|
635
|
+
const whole = await cli(["lint", "papers"], dir);
|
|
636
|
+
// A scorecard needs no LaTeX language: the same report, the same code.
|
|
641
637
|
assert.deepEqual(without, whole);
|
|
642
|
-
assert.match(whole.
|
|
638
|
+
assert.match(whole.out, /missing all of `paper\.tex`/);
|
|
643
639
|
});
|
|
644
640
|
|
|
645
641
|
test("`paperlint hook` with no name: exit 2, and the usage names an example", async () => {
|
package/src/cli.ts
CHANGED
|
@@ -46,11 +46,11 @@ import {
|
|
|
46
46
|
FRAGMENT_FILES,
|
|
47
47
|
includeBlocks,
|
|
48
48
|
paperBodies,
|
|
49
|
-
unreadLines,
|
|
50
49
|
} from "./paper-includes.ts";
|
|
51
50
|
import { prepareEngine } from "./build-engine.ts";
|
|
52
51
|
import { cacheRoot, cachedTree, runToolchain } from "./toolchain.ts";
|
|
53
52
|
import { banalInstaller, parseBanalSettings } from "./adapters/banal/index.ts";
|
|
53
|
+
import { bibReader } from "./adapters/bibtex/index.ts";
|
|
54
54
|
import { curlDownload } from "./adapters/curl/index.ts";
|
|
55
55
|
import { latexReader } from "./adapters/latex/index.ts";
|
|
56
56
|
import {
|
|
@@ -93,6 +93,12 @@ import {
|
|
|
93
93
|
type PaperSettings,
|
|
94
94
|
} from "./paper-settings.ts";
|
|
95
95
|
import { referenceRules, REFERENCE_RULE_LEVELS } from "./reference-rules.ts";
|
|
96
|
+
import { SOURCES_RULE_LEVELS, sourcesRules } from "./sources-rules.ts";
|
|
97
|
+
import { sourcesRecorder } from "./sources-record.ts";
|
|
98
|
+
import { sourcesCodec } from "./adapters/sources-record/index.ts";
|
|
99
|
+
import { texOutput } from "./adapters/tex-output/index.ts";
|
|
100
|
+
import { BIB_RULE_LEVELS, bibRules } from "./bib-rules.ts";
|
|
101
|
+
import { bibliographyReader } from "./references.ts";
|
|
96
102
|
import { onlineReferences } from "./adapters/references/index.ts";
|
|
97
103
|
import { hotcrpPortal } from "./adapters/hotcrp/index.ts";
|
|
98
104
|
import { runSubmission } from "./submission.ts";
|
|
@@ -132,15 +138,7 @@ import {
|
|
|
132
138
|
init,
|
|
133
139
|
processInteractivity,
|
|
134
140
|
} from "./init.ts";
|
|
135
|
-
import {
|
|
136
|
-
DEFAULT_FORMAT,
|
|
137
|
-
FORMATS,
|
|
138
|
-
isFormat,
|
|
139
|
-
newPaper,
|
|
140
|
-
reportNewPaper,
|
|
141
|
-
type PaperFormat,
|
|
142
|
-
type VenueSetting,
|
|
143
|
-
} from "./new-paper.ts";
|
|
141
|
+
import { newPaper, reportNewPaper, type VenueSetting } from "./new-paper.ts";
|
|
144
142
|
// The one source for the consumer's config key lives in lib/ (the ESLint rules and the skill scripts
|
|
145
143
|
// import it too). It is imported compiled, from dist/, the one path that resolves the same from src/
|
|
146
144
|
// and from dist/ — see CONTRIBUTING.md.
|
|
@@ -174,7 +172,6 @@ import {
|
|
|
174
172
|
} from "./folder-venue-rule.ts";
|
|
175
173
|
import typography from "#eslint-rules/paper-typography";
|
|
176
174
|
import texBuild from "#eslint-rules/tex-build";
|
|
177
|
-
import bibReachable from "#eslint-rules/bib-reachable-entry";
|
|
178
175
|
import reviewFrontmatter from "#eslint-rules/review-frontmatter";
|
|
179
176
|
import siblingFrontmatter from "#eslint-rules/sibling-frontmatter";
|
|
180
177
|
import pdfRules from "#eslint-rules/pdf-last-page-balance";
|
|
@@ -189,7 +186,7 @@ const USAGE = `paperlint — machine-checkable gates for a paper kept in git
|
|
|
189
186
|
npx paperlint init [dir] set the project up: detect the papers directory, declare it
|
|
190
187
|
in package.json, link the skills, wire the hooks into
|
|
191
188
|
.claude/settings.json, offer the CI step, report what is missing
|
|
192
|
-
npx paperlint new <name> [--venue <preset>] [--kind <kind>]
|
|
189
|
+
npx paperlint new <name> [--venue <preset>] [--kind <kind>]
|
|
193
190
|
create <papers>/<name>/ from the template; never overwrites,
|
|
194
191
|
on an existing folder adds only the missing files, then lints it.
|
|
195
192
|
A <name> that names a venue (aisec-2026) is refused: name the
|
|
@@ -225,7 +222,6 @@ init:
|
|
|
225
222
|
or with CI set, nothing is asked either
|
|
226
223
|
--no-hooks do not wire the hooks (the default without a human is to wire them)
|
|
227
224
|
--paper <name> create this paper too (without a human, the only way init creates one)
|
|
228
|
-
--format tex|md the new paper's source format; default tex
|
|
229
225
|
|
|
230
226
|
new:
|
|
231
227
|
--venue <preset> the venue preset, written as "extends" into the paper's paperlint.json:
|
|
@@ -234,7 +230,6 @@ new:
|
|
|
234
230
|
On a terminal without --venue, new asks; "none" leaves it unset
|
|
235
231
|
--kind <kind> the paper's kind at that venue (its page limit), e.g. short — one of the
|
|
236
232
|
preset's kinds; needs --venue
|
|
237
|
-
--format tex|md the paper's source format; default tex
|
|
238
233
|
--allow-venue-name create the folder even though its name names a venue (a whole word such as
|
|
239
234
|
"realm" can be the work's own). Without it such a name is refused: a rejected
|
|
240
235
|
paper moves to another venue and keeps its folder
|
|
@@ -312,11 +307,17 @@ settings — paperlint.json, at two levels, one schema. Both are optional.
|
|
|
312
307
|
unknown key, in either file, is an error.
|
|
313
308
|
`;
|
|
314
309
|
|
|
315
|
-
/** What the
|
|
310
|
+
/** What reads the build's record of a paper: the disk, and the schema its text is parsed with. */
|
|
311
|
+
const RECORD_DEPS = { files: nodeFiles, codec: sourcesCodec };
|
|
312
|
+
|
|
313
|
+
/** What reads the bibliography the last build recorded: the record, and the readers of its databases and blocks. */
|
|
314
|
+
const RECORDED_DEPS = { ...RECORD_DEPS, latex: latexReader, bib: bibReader };
|
|
315
|
+
|
|
316
|
+
/** What the rules over a paper.tex read with: the paper's disk and LaTeX reader, the build's record, and the shipped presets. */
|
|
316
317
|
const TEX_RULE_DEPS = {
|
|
317
|
-
|
|
318
|
-
venuesDir: presetsDir(),
|
|
318
|
+
...RECORD_DEPS,
|
|
319
319
|
latex: latexReader,
|
|
320
|
+
venuesDir: presetsDir(),
|
|
320
321
|
};
|
|
321
322
|
|
|
322
323
|
/** The register band rules and `tex/heading-case`: the rules of the `tex` plugin that read a paper's words. */
|
|
@@ -364,7 +365,8 @@ export function buildConfig(
|
|
|
364
365
|
// The reference rules judge `_build/references.json`, and only on `paper.tex`.
|
|
365
366
|
const texPaperRules = {
|
|
366
367
|
...paperRules,
|
|
367
|
-
...referenceRules(
|
|
368
|
+
...referenceRules(RECORDED_DEPS),
|
|
369
|
+
...sourcesRules(RECORD_DEPS),
|
|
368
370
|
};
|
|
369
371
|
// Each typography rule reports every occurrence where it is, and fixes it (`--fix`).
|
|
370
372
|
const prose = {
|
|
@@ -399,8 +401,8 @@ export function buildConfig(
|
|
|
399
401
|
},
|
|
400
402
|
{
|
|
401
403
|
files: ["**/PIPELINE-STATUS.md"],
|
|
402
|
-
// Every paper folder has one
|
|
403
|
-
//
|
|
404
|
+
// Every paper folder has one: the rules about the folder itself (its stages, its frozen
|
|
405
|
+
// sources, its name) are judged here, once per paper.
|
|
404
406
|
plugins: {
|
|
405
407
|
markdown,
|
|
406
408
|
paper: {
|
|
@@ -419,12 +421,6 @@ export function buildConfig(
|
|
|
419
421
|
...CYCLE_RULE_LEVELS,
|
|
420
422
|
},
|
|
421
423
|
},
|
|
422
|
-
{
|
|
423
|
-
files: ["**/paper.md", "**/draft.md"],
|
|
424
|
-
plugins: { markdown, paper: { rules: paperRules } },
|
|
425
|
-
...md,
|
|
426
|
-
rules: prose,
|
|
427
|
-
},
|
|
428
424
|
{
|
|
429
425
|
files: ["**/reviews/*.md"],
|
|
430
426
|
plugins: { markdown, review: reviewFrontmatter },
|
|
@@ -461,7 +457,7 @@ export function buildConfig(
|
|
|
461
457
|
},
|
|
462
458
|
},
|
|
463
459
|
paper: { rules: texPaperRules },
|
|
464
|
-
bib:
|
|
460
|
+
bib: { rules: bibRules(RECORDED_DEPS) },
|
|
465
461
|
talk: { rules: talkRules(TALK_RULE_DEPS) },
|
|
466
462
|
format: {
|
|
467
463
|
rules: {
|
|
@@ -475,8 +471,9 @@ export function buildConfig(
|
|
|
475
471
|
rules: {
|
|
476
472
|
...prose,
|
|
477
473
|
...REFERENCE_RULE_LEVELS,
|
|
474
|
+
...SOURCES_RULE_LEVELS,
|
|
478
475
|
"paper/figure-ref-style": "warn",
|
|
479
|
-
|
|
476
|
+
...BIB_RULE_LEVELS,
|
|
480
477
|
"tex/future-promise": "warn",
|
|
481
478
|
// A number with no owner: a prose rule, on beside the others above.
|
|
482
479
|
"tex/claim-provenance": "warn",
|
|
@@ -585,8 +582,7 @@ export interface RulePlugin {
|
|
|
585
582
|
* file knows every rule id. `@eslint/markdown` is a dependency's plugin and is left out. The LaTeX
|
|
586
583
|
* language rides on `tex` when `texLanguage` is given, and that is how a consumer registers it: a
|
|
587
584
|
* second `tex` plugin of its own is refused by ESLint ("Cannot redefine plugin "tex"", measured
|
|
588
|
-
* with and without the language here). Without it, `tex` carries rules only
|
|
589
|
-
* lints markdown papers alone.
|
|
585
|
+
* with and without the language here). Without it, `tex` carries rules only.
|
|
590
586
|
*/
|
|
591
587
|
export function rulePlugins(texLanguage?: unknown): Record<string, RulePlugin> {
|
|
592
588
|
const out: Record<string, { rules: Record<string, unknown> }> = {};
|
|
@@ -888,7 +884,6 @@ export function parseArgs(argv: readonly string[]): Args {
|
|
|
888
884
|
noHooks: false,
|
|
889
885
|
allowVenueName: false,
|
|
890
886
|
paper: null,
|
|
891
|
-
format: null,
|
|
892
887
|
venue: null,
|
|
893
888
|
kind: null,
|
|
894
889
|
pdf: null,
|
|
@@ -987,10 +982,9 @@ const SWITCHES: ReadonlyMap<
|
|
|
987
982
|
/** The flags whose value is one string field of `Args`. */
|
|
988
983
|
const STRING_FLAGS: ReadonlyMap<
|
|
989
984
|
string,
|
|
990
|
-
"paper" | "
|
|
985
|
+
"paper" | "venue" | "kind" | "pdf" | "abstract"
|
|
991
986
|
> = new Map([
|
|
992
987
|
["--paper", "paper"],
|
|
993
|
-
["--format", "format"],
|
|
994
988
|
["--venue", "venue"],
|
|
995
989
|
["--kind", "kind"],
|
|
996
990
|
["--pdf", "pdf"],
|
|
@@ -1184,7 +1178,6 @@ export function runHook(
|
|
|
1184
1178
|
export async function createPaperAt(
|
|
1185
1179
|
papersRoot: string,
|
|
1186
1180
|
name: string,
|
|
1187
|
-
format: PaperFormat,
|
|
1188
1181
|
{
|
|
1189
1182
|
log,
|
|
1190
1183
|
err,
|
|
@@ -1201,7 +1194,7 @@ export async function createPaperAt(
|
|
|
1201
1194
|
allowVenueName?: boolean;
|
|
1202
1195
|
},
|
|
1203
1196
|
): Promise<number> {
|
|
1204
|
-
const result = newPaper(papersRoot, name,
|
|
1197
|
+
const result = newPaper(papersRoot, name, {
|
|
1205
1198
|
venue,
|
|
1206
1199
|
venues: allowVenueName ? [] : shippedVenueNames(PRESET_DEPS),
|
|
1207
1200
|
});
|
|
@@ -1366,25 +1359,10 @@ async function runNew(
|
|
|
1366
1359
|
const [name, ...extra] = a.paths;
|
|
1367
1360
|
if (!name || extra.length > 0) {
|
|
1368
1361
|
err(
|
|
1369
|
-
`\`new\` takes exactly one paper name: \`paperlint new my-paper [--venue <preset>] [--kind <kind>]
|
|
1362
|
+
`\`new\` takes exactly one paper name: \`paperlint new my-paper [--venue <preset>] [--kind <kind>]\``,
|
|
1370
1363
|
);
|
|
1371
1364
|
return 2;
|
|
1372
1365
|
}
|
|
1373
|
-
let format: PaperFormat = DEFAULT_FORMAT;
|
|
1374
|
-
if (a.format !== null) {
|
|
1375
|
-
if (!isFormat(a.format)) {
|
|
1376
|
-
err(
|
|
1377
|
-
`--format must be one of ${FORMATS.join(", ")} — got \`${a.format}\``,
|
|
1378
|
-
);
|
|
1379
|
-
return 2;
|
|
1380
|
-
}
|
|
1381
|
-
format = a.format;
|
|
1382
|
-
} else if (processInteractivity(a.yes).interactive) {
|
|
1383
|
-
const f = (
|
|
1384
|
-
await askOrDefault(ask, `format: tex / md [${DEFAULT_FORMAT}] `)
|
|
1385
|
-
)?.trim();
|
|
1386
|
-
if (isFormat(f)) format = f;
|
|
1387
|
-
}
|
|
1388
1366
|
const cfg = readConfig({ ...a, json: false }, { log: () => {}, err, cwd });
|
|
1389
1367
|
if (cfg.code !== undefined) return cfg.code;
|
|
1390
1368
|
const roots = papersRoots(cfg);
|
|
@@ -1417,7 +1395,7 @@ async function runNew(
|
|
|
1417
1395
|
ask,
|
|
1418
1396
|
});
|
|
1419
1397
|
if (!venue.ok) return (err(venue.error), 2);
|
|
1420
|
-
return createPaperAt(papersRoot, name,
|
|
1398
|
+
return createPaperAt(papersRoot, name, {
|
|
1421
1399
|
log,
|
|
1422
1400
|
err,
|
|
1423
1401
|
cwd,
|
|
@@ -1478,6 +1456,12 @@ async function runBuild(
|
|
|
1478
1456
|
dryRun: a.dryRun,
|
|
1479
1457
|
log,
|
|
1480
1458
|
checkReferences,
|
|
1459
|
+
readBibliography: bibliographyReader(RECORDED_DEPS),
|
|
1460
|
+
recordSources: sourcesRecorder({
|
|
1461
|
+
files: nodeFiles,
|
|
1462
|
+
listDir: nodeListDir,
|
|
1463
|
+
texOutput,
|
|
1464
|
+
}),
|
|
1481
1465
|
engine: () => engineEnv(targets, a, { log, err }),
|
|
1482
1466
|
});
|
|
1483
1467
|
if (out.kind === "no-engine") return 1;
|
|
@@ -1668,10 +1652,6 @@ async function runInit(
|
|
|
1668
1652
|
);
|
|
1669
1653
|
return 2;
|
|
1670
1654
|
}
|
|
1671
|
-
if (a.format !== null && !isFormat(a.format)) {
|
|
1672
|
-
err(`--format must be one of ${FORMATS.join(", ")} — got \`${a.format}\``);
|
|
1673
|
-
return 2;
|
|
1674
|
-
}
|
|
1675
1655
|
return await init(a.paths[0] ?? ".", {
|
|
1676
1656
|
log,
|
|
1677
1657
|
err,
|
|
@@ -1679,9 +1659,8 @@ async function runInit(
|
|
|
1679
1659
|
yes: a.yes,
|
|
1680
1660
|
hooks: !a.noHooks,
|
|
1681
1661
|
paper: a.paper,
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
createPaperAt(papersRoot, name, format, { log, err, cwd }),
|
|
1662
|
+
createPaper: (papersRoot, name) =>
|
|
1663
|
+
createPaperAt(papersRoot, name, { log, err, cwd }),
|
|
1685
1664
|
venues: shippedVenueNames(PRESET_DEPS),
|
|
1686
1665
|
tex: initTexLive(a, { log, err, cwd }),
|
|
1687
1666
|
resolveCliPapers: (root: string): string | null =>
|
|
@@ -1696,10 +1675,17 @@ export async function run(
|
|
|
1696
1675
|
err = console.error,
|
|
1697
1676
|
cwd = process.cwd(),
|
|
1698
1677
|
checkReferences = onlineReferences,
|
|
1678
|
+
loadTexLanguage = async () =>
|
|
1679
|
+
(await import("#eslint-rules/latex-language")).texLanguage,
|
|
1699
1680
|
}: {
|
|
1700
1681
|
log?: typeof console.log;
|
|
1701
1682
|
err?: typeof console.error;
|
|
1702
1683
|
cwd?: string;
|
|
1684
|
+
/**
|
|
1685
|
+
* `lint`'s LaTeX language, loaded lazily because only `lint` needs it. A test hands one that
|
|
1686
|
+
* fails, as a broken install would.
|
|
1687
|
+
*/
|
|
1688
|
+
loadTexLanguage?: () => Promise<unknown>;
|
|
1703
1689
|
/**
|
|
1704
1690
|
* `build`'s online reference check — the real services by default. The e2e build passes a
|
|
1705
1691
|
* fake: no test depends on Crossref, Semantic Scholar or DBLP answering.
|
|
@@ -1803,33 +1789,16 @@ export async function run(
|
|
|
1803
1789
|
};
|
|
1804
1790
|
|
|
1805
1791
|
// Loaded lazily because only `lint` needs it. If the module cannot be loaded (a broken install:
|
|
1806
|
-
// the file missing from the package), lint still runs over the
|
|
1807
|
-
// failing outright — the LaTeX rules simply have no language to run in.
|
|
1808
|
-
|
|
1809
|
-
try {
|
|
1810
|
-
({ texLanguage } = await import("#eslint-rules/latex-language"));
|
|
1811
|
-
} catch {
|
|
1812
|
-
texLanguage = null;
|
|
1813
|
-
}
|
|
1792
|
+
// the file missing from the package), lint still runs over the scorecards and the review notes
|
|
1793
|
+
// rather than failing outright — the LaTeX rules simply have no language to run in.
|
|
1794
|
+
const texLanguage: unknown = await loadTexLanguage().catch(() => null);
|
|
1814
1795
|
|
|
1815
|
-
// Each paper's body files,
|
|
1796
|
+
// Each paper's body files, as the last build recorded TeX reading them — only when the LaTeX language
|
|
1816
1797
|
// loaded, since only its rules read them. The project's papers too: `paperlint lint .` reaches
|
|
1817
1798
|
// papers two levels down, which a directory's immediate papers do not.
|
|
1818
1799
|
const bodies = texLanguage
|
|
1819
|
-
? paperBodies(paperDirs([...paths, ...papersRoots(cfg)]),
|
|
1820
|
-
files: nodeFiles,
|
|
1821
|
-
latex: latexReader,
|
|
1822
|
-
})
|
|
1800
|
+
? paperBodies(paperDirs([...paths, ...papersRoots(cfg)]), RECORD_DEPS)
|
|
1823
1801
|
: [];
|
|
1824
|
-
// Named only for the papers this run lints: a paper elsewhere in the project is not this run's.
|
|
1825
|
-
const inScope = (dir: string) =>
|
|
1826
|
-
paths.some((p) => dir === p || dir.startsWith(`${p}${sep}`));
|
|
1827
|
-
unreadLines(
|
|
1828
|
-
bodies.filter((b) => inScope(b.dir)),
|
|
1829
|
-
(p) => shown(cwd, p),
|
|
1830
|
-
).forEach((l) => {
|
|
1831
|
-
err(l);
|
|
1832
|
-
});
|
|
1833
1802
|
|
|
1834
1803
|
const eslint = new ESLint({
|
|
1835
1804
|
cwd: lintRoot(root, paths),
|
|
@@ -1870,7 +1839,7 @@ export async function run(
|
|
|
1870
1839
|
// is not invoked — and, not being invoked, it physically cannot report that.
|
|
1871
1840
|
if (results.length === 0) {
|
|
1872
1841
|
err(
|
|
1873
|
-
`nothing was linted under ${paths.map((x) => shown(cwd, x)).join(", ")} — no PIPELINE-STATUS.md, paper.
|
|
1842
|
+
`nothing was linted under ${paths.map((x) => shown(cwd, x)).join(", ")} — no PIPELINE-STATUS.md, paper.tex or reviews/ found there. A clean report over zero files is not a clean report.`,
|
|
1874
1843
|
);
|
|
1875
1844
|
return 1;
|
|
1876
1845
|
}
|