paperlint 3.1.3 → 4.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/.github/workflows/ci.yml +12 -7
- package/CLAUDE.md +5 -5
- package/CONTRIBUTING.md +34 -5
- package/dist/adapters/banal/failure.d.ts +1 -7
- package/dist/adapters/banal/failure.d.ts.map +1 -1
- package/dist/adapters/banal/failure.js +5 -7
- package/dist/adapters/banal/failure.js.map +1 -1
- package/dist/adapters/banal/index.d.ts.map +1 -1
- package/dist/adapters/banal/index.js +4 -3
- package/dist/adapters/banal/index.js.map +1 -1
- package/dist/adapters/banal/install.d.ts.map +1 -1
- package/dist/adapters/banal/install.js +4 -3
- package/dist/adapters/banal/install.js.map +1 -1
- package/dist/adapters/banal/invocation.d.ts +10 -5
- package/dist/adapters/banal/invocation.d.ts.map +1 -1
- package/dist/adapters/banal/invocation.js +13 -1
- package/dist/adapters/banal/invocation.js.map +1 -1
- package/dist/adapters/banal/locate.d.ts +12 -9
- package/dist/adapters/banal/locate.d.ts.map +1 -1
- package/dist/adapters/banal/locate.js +19 -12
- package/dist/adapters/banal/locate.js.map +1 -1
- package/dist/adapters/banal/run.d.ts +10 -1
- package/dist/adapters/banal/run.d.ts.map +1 -1
- package/dist/adapters/banal/run.js +8 -4
- package/dist/adapters/banal/run.js.map +1 -1
- package/dist/adapters/banal/settings.d.ts +1 -1
- package/dist/adapters/banal/settings.d.ts.map +1 -1
- package/dist/adapters/banal/settings.js +2 -1
- package/dist/adapters/banal/settings.js.map +1 -1
- package/dist/adapters/memory/index.d.ts.map +1 -1
- package/dist/adapters/memory/index.js +8 -2
- package/dist/adapters/memory/index.js.map +1 -1
- package/dist/adapters/node/files.io.d.ts.map +1 -1
- package/dist/adapters/node/files.io.js +2 -1
- package/dist/adapters/node/files.io.js.map +1 -1
- package/dist/adapters/node/process.io.d.ts +5 -7
- package/dist/adapters/node/process.io.d.ts.map +1 -1
- package/dist/adapters/node/process.io.js +4 -3
- package/dist/adapters/node/process.io.js.map +1 -1
- package/dist/adapters/node/workspace.io.d.ts.map +1 -1
- package/dist/adapters/node/workspace.io.js +4 -2
- package/dist/adapters/node/workspace.io.js.map +1 -1
- package/dist/adapters/pdfjs/fill.d.ts.map +1 -1
- package/dist/adapters/pdfjs/fill.js +13 -7
- package/dist/adapters/pdfjs/fill.js.map +1 -1
- package/dist/adapters/references/index.d.ts.map +1 -1
- package/dist/adapters/references/index.js +8 -7
- package/dist/adapters/references/index.js.map +1 -1
- package/dist/adapters/references/pool.d.ts.map +1 -1
- package/dist/adapters/references/pool.js +4 -5
- package/dist/adapters/references/pool.js.map +1 -1
- package/dist/adapters/references/reach.io.d.ts.map +1 -1
- package/dist/adapters/references/reach.io.js +2 -1
- package/dist/adapters/references/reach.io.js.map +1 -1
- package/dist/build-engine.d.ts +1 -1
- package/dist/build-engine.d.ts.map +1 -1
- package/dist/build-engine.js +10 -3
- package/dist/build-engine.js.map +1 -1
- package/dist/build.d.ts +2 -3
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +19 -17
- package/dist/build.js.map +1 -1
- package/dist/caller-path.d.ts +3 -0
- package/dist/caller-path.d.ts.map +1 -0
- package/dist/caller-path.js +13 -0
- package/dist/caller-path.js.map +1 -0
- package/dist/cli.d.ts +10 -17
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +93 -46
- package/dist/cli.js.map +1 -1
- package/dist/doctor.d.ts +12 -3
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +5 -3
- package/dist/doctor.js.map +1 -1
- package/dist/domain/lookup-cache.d.ts.map +1 -1
- package/dist/domain/lookup-cache.js +10 -8
- package/dist/domain/lookup-cache.js.map +1 -1
- package/dist/domain/paths.d.ts +8 -2
- package/dist/domain/paths.d.ts.map +1 -1
- package/dist/domain/paths.js +12 -1
- package/dist/domain/paths.js.map +1 -1
- package/dist/domain/ready.d.ts +24 -0
- package/dist/domain/ready.d.ts.map +1 -0
- package/dist/domain/ready.js +11 -0
- package/dist/domain/ready.js.map +1 -0
- package/dist/domain/record.d.ts +8 -0
- package/dist/domain/record.d.ts.map +1 -0
- package/dist/domain/record.js +8 -0
- package/dist/domain/record.js.map +1 -0
- package/dist/domain/sha256.d.ts.map +1 -1
- package/dist/domain/sha256.js +4 -2
- package/dist/domain/sha256.js.map +1 -1
- package/dist/domain/text.d.ts +12 -0
- package/dist/domain/text.d.ts.map +1 -1
- package/dist/domain/text.js +17 -0
- package/dist/domain/text.js.map +1 -1
- package/dist/engine.d.ts +23 -22
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +4 -3
- package/dist/engine.js.map +1 -1
- package/dist/eslint-rules/bib-reachable-entry.d.ts +22 -0
- package/dist/eslint-rules/bib-reachable-entry.d.ts.map +1 -0
- package/dist/eslint-rules/bib-reachable-entry.js +75 -0
- package/dist/eslint-rules/bib-reachable-entry.js.map +1 -0
- package/dist/eslint-rules/install-path-literals.d.ts +80 -0
- package/dist/eslint-rules/install-path-literals.d.ts.map +1 -0
- package/dist/eslint-rules/install-path-literals.js +105 -0
- package/dist/eslint-rules/install-path-literals.js.map +1 -0
- package/dist/eslint-rules/latex-language.d.ts +136 -0
- package/dist/eslint-rules/latex-language.d.ts.map +1 -0
- package/dist/eslint-rules/latex-language.js +639 -0
- package/dist/eslint-rules/latex-language.js.map +1 -0
- package/dist/eslint-rules/paper-research-question.d.ts +31 -0
- package/dist/eslint-rules/paper-research-question.d.ts.map +1 -0
- package/dist/eslint-rules/paper-research-question.js +188 -0
- package/dist/eslint-rules/paper-research-question.js.map +1 -0
- package/dist/eslint-rules/paper-stages.d.ts +83 -0
- package/dist/eslint-rules/paper-stages.d.ts.map +1 -0
- package/dist/eslint-rules/paper-stages.js +358 -0
- package/dist/eslint-rules/paper-stages.js.map +1 -0
- package/dist/eslint-rules/paper-typography.d.ts +74 -0
- package/dist/eslint-rules/paper-typography.d.ts.map +1 -0
- package/dist/eslint-rules/paper-typography.js +404 -0
- package/dist/eslint-rules/paper-typography.js.map +1 -0
- package/dist/eslint-rules/papers.d.ts +42 -0
- package/dist/eslint-rules/papers.d.ts.map +1 -0
- package/dist/eslint-rules/papers.js +145 -0
- package/dist/eslint-rules/papers.js.map +1 -0
- package/dist/eslint-rules/pdf-last-page-balance.d.ts +72 -0
- package/dist/eslint-rules/pdf-last-page-balance.d.ts.map +1 -0
- package/dist/eslint-rules/pdf-last-page-balance.js +237 -0
- package/dist/eslint-rules/pdf-last-page-balance.js.map +1 -0
- package/dist/eslint-rules/review-frontmatter.d.ts +57 -0
- package/dist/eslint-rules/review-frontmatter.d.ts.map +1 -0
- package/dist/eslint-rules/review-frontmatter.js +126 -0
- package/dist/eslint-rules/review-frontmatter.js.map +1 -0
- package/dist/eslint-rules/review-frontmatter.schema.json +36 -0
- package/dist/eslint-rules/rule-context.d.ts +55 -0
- package/dist/eslint-rules/rule-context.d.ts.map +1 -0
- package/dist/eslint-rules/rule-context.js +9 -0
- package/dist/eslint-rules/rule-context.js.map +1 -0
- package/dist/eslint-rules/sibling-frontmatter.d.ts +25 -0
- package/dist/eslint-rules/sibling-frontmatter.d.ts.map +1 -0
- package/dist/eslint-rules/sibling-frontmatter.js +16 -0
- package/dist/eslint-rules/sibling-frontmatter.js.map +1 -0
- package/dist/eslint-rules/sibling-frontmatter.schema.json +14 -0
- package/dist/eslint-rules/temp-root-realpath.d.ts +71 -0
- package/dist/eslint-rules/temp-root-realpath.d.ts.map +1 -0
- package/dist/eslint-rules/temp-root-realpath.js +139 -0
- package/dist/eslint-rules/temp-root-realpath.js.map +1 -0
- package/dist/eslint-rules/tex-build.d.ts +35 -0
- package/dist/eslint-rules/tex-build.d.ts.map +1 -0
- package/dist/eslint-rules/tex-build.js +313 -0
- package/dist/eslint-rules/tex-build.js.map +1 -0
- package/dist/facts-file.d.ts.map +1 -1
- package/dist/facts-file.js +31 -27
- package/dist/facts-file.js.map +1 -1
- package/dist/hooks-settings.d.ts +1 -1
- package/dist/hooks-settings.d.ts.map +1 -1
- package/dist/hooks-settings.js +31 -11
- package/dist/hooks-settings.js.map +1 -1
- package/dist/init.d.ts +8 -9
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +33 -15
- package/dist/init.js.map +1 -1
- package/dist/latex-loop.d.ts +2 -2
- package/dist/latex-loop.d.ts.map +1 -1
- package/dist/latex-loop.js +2 -2
- package/dist/latex-loop.js.map +1 -1
- package/dist/lib/agent-cli-version.d.ts +65 -0
- package/dist/lib/agent-cli-version.d.ts.map +1 -0
- package/dist/lib/agent-cli-version.js +77 -0
- package/dist/lib/agent-cli-version.js.map +1 -0
- package/dist/lib/check.d.ts +19 -0
- package/dist/lib/check.d.ts.map +1 -0
- package/dist/lib/check.js +52 -0
- package/dist/lib/check.js.map +1 -0
- package/dist/lib/markdown.d.ts +180 -0
- package/dist/lib/markdown.d.ts.map +1 -0
- package/dist/lib/markdown.js +302 -0
- package/dist/lib/markdown.js.map +1 -0
- package/dist/lib/paper-config.d.ts +84 -0
- package/dist/lib/paper-config.d.ts.map +1 -0
- package/dist/lib/paper-config.js +138 -0
- package/dist/lib/paper-config.js.map +1 -0
- package/dist/lib/skill-eval-fixture.d.ts +29 -0
- package/dist/lib/skill-eval-fixture.d.ts.map +1 -0
- package/dist/lib/skill-eval-fixture.js +62 -0
- package/dist/lib/skill-eval-fixture.js.map +1 -0
- package/dist/link-skills.d.ts.map +1 -1
- package/dist/link-skills.js +5 -4
- package/dist/link-skills.js.map +1 -1
- package/dist/new-paper.d.ts.map +1 -1
- package/dist/new-paper.js +7 -3
- package/dist/new-paper.js.map +1 -1
- package/dist/paper-files.d.ts +4 -4
- package/dist/paper-files.d.ts.map +1 -1
- package/dist/paper-files.js +6 -6
- package/dist/paper-files.js.map +1 -1
- package/dist/paper-settings.d.ts.map +1 -1
- package/dist/paper-settings.js +8 -7
- package/dist/paper-settings.js.map +1 -1
- package/dist/pdf-facts.d.ts +51 -1
- package/dist/pdf-facts.d.ts.map +1 -1
- package/dist/pdf-facts.js +25 -16
- package/dist/pdf-facts.js.map +1 -1
- package/dist/pdf-geometry.d.ts.map +1 -1
- package/dist/pdf-geometry.js +3 -4
- package/dist/pdf-geometry.js.map +1 -1
- package/dist/ports/tool-installer.d.ts +2 -14
- package/dist/ports/tool-installer.d.ts.map +1 -1
- package/dist/presets.d.ts.map +1 -1
- package/dist/presets.js +19 -6
- package/dist/presets.js.map +1 -1
- package/dist/references.d.ts.map +1 -1
- package/dist/references.js +15 -10
- package/dist/references.js.map +1 -1
- package/dist/rules-config.d.ts +26 -1
- package/dist/rules-config.d.ts.map +1 -1
- package/dist/rules-config.js +15 -12
- package/dist/rules-config.js.map +1 -1
- package/dist/structure.js +1 -1
- package/dist/structure.js.map +1 -1
- package/dist/tex-requirements.d.ts +4 -0
- package/dist/tex-requirements.d.ts.map +1 -1
- package/dist/tex-requirements.js +22 -5
- package/dist/tex-requirements.js.map +1 -1
- package/dist/toolchain.d.ts.map +1 -1
- package/dist/toolchain.js +21 -16
- package/dist/toolchain.js.map +1 -1
- package/dist/types.d.ts +5 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/venue-rules.d.ts.map +1 -1
- package/dist/venue-rules.js +21 -8
- package/dist/venue-rules.js.map +1 -1
- package/docs/configuration.md +2 -2
- package/docs/e2e.md +7 -7
- package/docs/install.md +1 -1
- package/docs/prior-art/README.md +1 -1
- package/docs/prior-art/package-location.md +5 -5
- package/docs/prior-art/repro/README.md +1 -1
- package/docs/prior-art/test-tooling.md +2 -2
- package/docs/testing.md +11 -8
- package/docs/toolchain.md +1 -1
- package/eslint-rules/{bib-reachable-entry.mjs → bib-reachable-entry.ts} +5 -4
- package/eslint-rules/install-path-literals.harness.mjs +1 -1
- package/eslint-rules/{install-path-literals.mjs → install-path-literals.ts} +18 -10
- package/eslint-rules/latex-language.harness.mjs +2 -2
- package/eslint-rules/latex-language.test.mjs +7 -1
- package/eslint-rules/{latex-language.mjs → latex-language.ts} +297 -109
- package/eslint-rules/paper-research-question.harness.mjs +3 -3
- package/eslint-rules/{paper-research-question.mjs → paper-research-question.ts} +35 -16
- package/eslint-rules/paper-stages.harness.mjs +2 -2
- package/eslint-rules/paper-stages.test.mjs +8 -2
- package/eslint-rules/{paper-stages.mjs → paper-stages.ts} +76 -31
- package/eslint-rules/paper-typography.test.mjs +3 -3
- package/eslint-rules/{paper-typography.mjs → paper-typography.ts} +134 -56
- package/eslint-rules/papers.harness.mjs +2 -2
- package/eslint-rules/{papers.mjs → papers.ts} +7 -4
- package/eslint-rules/pdf-last-page-balance.harness.mjs +3 -3
- package/eslint-rules/{pdf-last-page-balance.mjs → pdf-last-page-balance.ts} +89 -32
- package/eslint-rules/review-frontmatter.test.mjs +2 -2
- package/eslint-rules/{review-frontmatter.mjs → review-frontmatter.ts} +38 -16
- package/eslint-rules/rule-context.ts +62 -0
- package/eslint-rules/{sibling-frontmatter.mjs → sibling-frontmatter.ts} +1 -1
- package/eslint-rules/temp-root-realpath.harness.mjs +1 -1
- package/eslint-rules/{temp-root-realpath.mjs → temp-root-realpath.ts} +20 -7
- package/eslint-rules/tex-build.harness.mjs +2 -2
- package/eslint-rules/{tex-build.mjs → tex-build.ts} +6 -5
- package/eslint.config.mjs +146 -30
- package/fixtures/install-path-literals/clean.fixture.mjs +1 -1
- package/fixtures/install-path-literals/clean.md +2 -2
- package/fixtures/install-path-literals/defect.fixture.mjs +1 -1
- package/fixtures/install-path-literals/defect.md +2 -2
- package/fixtures/pdf-facts/README.md +2 -2
- package/fixtures/real-markdown-paper/{baseline.mjs → baseline.ts} +31 -10
- package/hooks/{hooks.harness.mjs → hooks.harness.ts} +51 -34
- package/hooks/paper-edit-guard.hook.mjs +1 -1
- package/hooks/{paper-edit-guard.test.mjs → paper-edit-guard.test.ts} +3 -7
- package/hooks/paper-skills-nudge.hook.mjs +1 -1
- package/hooks/{paper-skills-nudge.test.mjs → paper-skills-nudge.test.ts} +2 -6
- package/hooks/paper-status-gates.sh +9 -19
- package/hooks/{paper-status-gates.test.mjs → paper-status-gates.test.ts} +2 -6
- package/lib/agent-cli-version.harness.mjs +1 -1
- package/lib/{agent-cli-version.mjs → agent-cli-version.ts} +32 -18
- package/lib/check.test.ts +14 -9
- package/lib/{check.mjs → check.ts} +22 -9
- package/lib/markdown.test.mjs +7 -7
- package/lib/{markdown.mjs → markdown.ts} +68 -29
- package/lib/paper-config.harness.mjs +9 -9
- package/lib/{paper-config.mjs → paper-config.ts} +20 -19
- package/lib/skill-checks.mjs +24 -381
- package/lib/skill-checks.test.mjs +64 -116
- package/lib/skill-corpus.mjs +10 -251
- package/lib/skill-corpus.test.mjs +2 -13
- package/lib/skill-eval-kit.mjs +1 -1
- package/lib/skill-trigger-cases.mjs +1 -1
- package/package.json +42 -10
- package/scripts/{check.harness.mjs → check.harness.ts} +111 -10
- package/scripts/{check.test.mjs → check.test.ts} +13 -10
- package/scripts/{check.mjs → check.ts} +116 -42
- package/scripts/coverage-config.test.ts +80 -38
- package/scripts/eslint-report-guard.test.mjs +1 -1
- package/scripts/harness-api.frozen.json +14 -16
- package/scripts/harness-api.test.ts +8 -5
- package/scripts/layer-legacy-frozen.test.ts +17 -13
- package/scripts/{layer-legacy-frozen.mjs → layer-legacy-frozen.ts} +128 -39
- package/scripts/release-config.test.ts +12 -4
- package/scripts/rules-see-files.test.mjs +1 -1
- package/scripts/test.test.ts +78 -0
- package/scripts/test.ts +87 -0
- package/skills/analyze-sibling-paper/SKILL.md +1 -39
- package/skills/analyze-sibling-paper/SKILL.md.spec.ts +0 -38
- package/skills/argument-arc/SKILL.md +2 -36
- package/skills/argument-arc/SKILL.md.spec.ts +1 -43
- package/skills/build-benchmark/SKILL.md +1 -41
- package/skills/build-benchmark/SKILL.md.spec.ts +0 -40
- package/skills/camera-ready/SKILL.md +1 -34
- package/skills/camera-ready/SKILL.md.spec.ts +0 -33
- package/skills/cold-read-diff/SKILL.md +1 -35
- package/skills/cold-read-diff/SKILL.md.spec.ts +0 -34
- package/skills/draft-paper/SKILL.md +2 -41
- package/skills/draft-paper/SKILL.md.spec.ts +1 -50
- package/skills/extend-paper/SKILL.md +2 -33
- package/skills/extend-paper/SKILL.md.spec.ts +1 -42
- package/skills/find-venue/SKILL.md +2 -38
- package/skills/find-venue/SKILL.md.spec.ts +1 -47
- package/skills/grade-paper-writing/SKILL.md +3 -38
- package/skills/grade-paper-writing/SKILL.md.spec.ts +2 -47
- package/skills/grade-paper-writing/prose-lint.mjs +3 -4
- package/skills/grade-paper-writing/{prose-lint.test.mjs → prose-lint.test.ts} +3 -3
- package/skills/harden-paper/SKILL.md +1 -39
- package/skills/harden-paper/SKILL.md.spec.ts +0 -38
- package/skills/map-prior-work/SKILL.md +1 -35
- package/skills/map-prior-work/SKILL.md.spec.ts +0 -34
- package/skills/osf-artifact-upload/{osf-artifact-upload.harness.mjs → osf-artifact-upload.harness.ts} +3 -4
- package/skills/paper-adversarial-review/SKILL.md +2 -35
- package/skills/paper-adversarial-review/SKILL.md.spec.ts +1 -43
- package/skills/paper-pipeline/SKILL.md +2 -28
- package/skills/paper-pipeline/SKILL.md.spec.ts +1 -27
- package/skills/paper-pipeline/description-language.eval.mjs +1 -1
- package/skills/paper-pipeline/framing-vs-vocabulary.eval.mjs +1 -1
- package/skills/paper-pipeline/grade-paper-writing-ablation.eval.mjs +2 -2
- package/skills/paper-pipeline/paper-pipeline.harness.mjs +25 -40
- package/skills/paper-pipeline/pipeline-firing.eval.mjs +1 -1
- package/skills/paper-pipeline/pipeline-language.eval.mjs +1 -1
- package/skills/paper-pipeline/references/acceptance-gate.md +1 -6
- package/skills/paper-pipeline/references/pipeline-status-template.md +8 -35
- package/skills/paper-pipeline/scripts/README.md +30 -225
- package/skills/paper-pipeline/scripts/artifact-coverage.harness.mjs +4 -8
- package/skills/paper-pipeline/scripts/artifact-coverage.mjs +1 -1
- package/skills/paper-pipeline/scripts/{artifact-coverage.test.mjs → artifact-coverage.test.ts} +2 -2
- package/skills/paper-pipeline/scripts/consumer.harness.mjs +6 -104
- package/skills/paper-pipeline/scripts/consumer.mjs +24 -109
- package/skills/paper-pipeline/scripts/consumer.test.mjs +1 -1
- package/skills/paper-pipeline/scripts/extract-ref-facts.harness.mjs +1 -1
- package/skills/paper-pipeline/scripts/extract-ref-facts.mjs +1 -4
- package/skills/paper-pipeline/scripts/extract-ref-facts.test.mjs +1 -1
- package/skills/paper-pipeline/scripts/generated-code.harness.mjs +2 -3
- package/skills/paper-pipeline/scripts/{generated-code.test.mjs → generated-code.test.ts} +3 -3
- package/skills/paper-pipeline/scripts/population-map.harness.mjs +3 -3
- package/skills/paper-pipeline/scripts/population-map.mjs +1 -4
- package/skills/paper-pipeline/scripts/population-map.test.mjs +1 -1
- package/skills/paper-pipeline/scripts/{round-diff.harness.mjs → round-diff.harness.ts} +45 -18
- package/skills/paper-pipeline/scripts/round-diff.mjs +1 -1
- package/skills/paper-pipeline/scripts/round-diff.test.mjs +1 -1
- package/skills/paper-status/SKILL.md +2 -42
- package/skills/paper-status/SKILL.md.spec.ts +1 -41
- package/skills/pc-panel-review/SKILL.md +2 -46
- package/skills/pc-panel-review/SKILL.md.spec.ts +1 -45
- package/skills/plan-paper-timeline/SKILL.md +2 -36
- package/skills/plan-paper-timeline/SKILL.md.spec.ts +0 -36
- package/skills/plan-paper-timeline/fixtures/{fake-google-calendar.mjs → fake-google-calendar.ts} +101 -70
- package/skills/plan-paper-timeline/plan-paper-timeline.effects.harness.mjs +3 -3
- package/skills/render-paper/SKILL.md +1 -37
- package/skills/render-paper/SKILL.md.spec.ts +0 -36
- package/skills/render-paper/{extract-pdf-facts.harness.mjs → extract-pdf-facts.harness.ts} +34 -9
- package/skills/render-paper/render-paper.harness.mjs +2 -2
- package/skills/research-ideate/SKILL.md +2 -39
- package/skills/research-ideate/SKILL.md.spec.ts +1 -47
- package/skills/study-accepted-papers/SKILL.md +1 -34
- package/skills/study-accepted-papers/SKILL.md.spec.ts +0 -33
- package/skills/submit-paper/SKILL.md +1 -33
- package/skills/submit-paper/SKILL.md.spec.ts +0 -32
- package/skills/sweep-design-space/SKILL.md +1 -38
- package/skills/sweep-design-space/SKILL.md.spec.ts +0 -37
- package/skills/tighten-paper/SKILL.md +2 -39
- package/skills/tighten-paper/SKILL.md.spec.ts +1 -47
- package/skills/tighten-paper/structure.mjs +5 -12
- package/skills/tighten-paper/{structure.test.mjs → structure.test.ts} +4 -3
- package/skills/verify-citations/SKILL.md +2 -38
- package/skills/verify-citations/SKILL.md.spec.ts +1 -37
- package/skills/verify-citations/scripts/{bib-authors.cli.test.mjs → bib-authors.cli.test.ts} +14 -4
- package/skills/verify-citations/scripts/bib-authors.d.mts +63 -0
- package/skills/verify-citations/scripts/bib-authors.mjs +1 -4
- package/skills/verify-citations/scripts/{verify-cites.cli.test.mjs → verify-cites.cli.test.ts} +32 -9
- package/skills/verify-citations/scripts/verify-cites.d.mts +58 -0
- package/src/CLAUDE.md +1 -1
- package/src/adapters/banal/failure.ts +9 -10
- package/src/adapters/banal/index.test.ts +5 -8
- package/src/adapters/banal/index.ts +8 -7
- package/src/adapters/banal/install.ts +9 -4
- package/src/adapters/banal/invocation.test.ts +23 -9
- package/src/adapters/banal/invocation.ts +24 -9
- package/src/adapters/banal/locate.test.ts +2 -2
- package/src/adapters/banal/locate.ts +27 -21
- package/src/adapters/banal/output.test.ts +1 -1
- package/src/adapters/banal/run.test.ts +5 -5
- package/src/adapters/banal/run.ts +16 -10
- package/src/adapters/banal/settings.ts +2 -2
- package/src/adapters/banal/xml.test.ts +1 -1
- package/src/adapters/curl/download.test.ts +8 -6
- package/src/adapters/memory/index.ts +4 -3
- package/src/adapters/node/files.io.ts +2 -2
- package/src/adapters/node/files.test.ts +8 -4
- package/src/adapters/node/process.io.ts +13 -5
- package/src/adapters/node/process.test.ts +5 -5
- package/src/adapters/node/workspace.io.ts +9 -4
- package/src/adapters/node/workspace.test.ts +3 -1
- package/src/adapters/pdfjs/fill.test.ts +2 -2
- package/src/adapters/pdfjs/fill.ts +14 -7
- package/src/adapters/references/index.test.ts +31 -38
- package/src/adapters/references/index.ts +33 -60
- package/src/adapters/references/pool.ts +3 -5
- package/src/adapters/references/reach.io.ts +2 -1
- package/src/build-engine.harness.mjs +1 -1
- package/src/build-engine.test.ts +13 -8
- package/src/build-engine.ts +12 -7
- package/src/build.harness.mjs +2 -2
- package/src/build.test.ts +24 -24
- package/src/build.ts +34 -26
- package/src/caller-path.ts +13 -0
- package/src/cli.harness.mjs +6 -8
- package/src/cli.test.ts +31 -13
- package/src/cli.ts +117 -58
- package/src/doctor.harness.mjs +3 -3
- package/src/doctor.test.ts +1 -1
- package/src/doctor.ts +17 -7
- package/src/domain/lookup-cache.ts +21 -11
- package/src/domain/paths.test.ts +15 -0
- package/src/domain/paths.ts +20 -1
- package/src/domain/ready.ts +31 -0
- package/src/domain/record.test.ts +20 -0
- package/src/domain/record.ts +12 -0
- package/src/domain/result.test.ts +2 -2
- package/src/domain/sha256.ts +5 -3
- package/src/domain/text.test.ts +32 -0
- package/src/domain/text.ts +23 -0
- package/src/engine.harness.mjs +2 -2
- package/src/engine.ts +34 -5
- package/src/facts-file.test.ts +9 -7
- package/src/facts-file.ts +45 -29
- package/src/{hooks-settings.harness.mjs → hooks-settings.harness.ts} +56 -20
- package/src/hooks-settings.ts +48 -13
- package/src/init.test.ts +37 -14
- package/src/init.ts +48 -24
- package/src/{latex-log.harness.mjs → latex-log.harness.ts} +14 -14
- package/src/{latex-loop.harness.mjs → latex-loop.harness.ts} +64 -36
- package/src/latex-loop.ts +3 -3
- package/src/{link-skills.harness.mjs → link-skills.harness.ts} +19 -19
- package/src/link-skills.test.ts +3 -3
- package/src/link-skills.ts +5 -4
- package/src/lint-fix.test.ts +4 -6
- package/src/linted-set.test.ts +2 -2
- package/src/new-paper.harness.mjs +9 -25
- package/src/new-paper.test.ts +8 -10
- package/src/new-paper.ts +9 -5
- package/src/paper-files.test.ts +25 -24
- package/src/paper-files.ts +16 -27
- package/src/paper-settings-commands.test.ts +5 -4
- package/src/paper-settings.test.ts +7 -7
- package/src/paper-settings.ts +13 -14
- package/src/{pdf-facts.harness.mjs → pdf-facts.harness.ts} +9 -8
- package/src/pdf-facts.test.ts +25 -15
- package/src/pdf-facts.ts +81 -23
- package/src/{pdf-geometry.harness.mjs → pdf-geometry.harness.ts} +19 -12
- package/src/pdf-geometry.ts +8 -4
- package/src/ports/tool-installer.ts +2 -17
- package/src/presets.ts +31 -16
- package/src/references.test.ts +76 -62
- package/src/references.ts +18 -12
- package/src/{rules-config.harness.mjs → rules-config.harness.ts} +7 -13
- package/src/rules-config.ts +46 -14
- package/src/rules-off.test.ts +6 -4
- package/src/{structure.harness.mjs → structure.harness.ts} +26 -15
- package/src/structure.ts +1 -1
- package/src/{tex-requirements.harness.mjs → tex-requirements.harness.ts} +50 -22
- package/src/tex-requirements.test.ts +21 -0
- package/src/tex-requirements.ts +37 -11
- package/src/toolchain.harness.mjs +2 -2
- package/src/toolchain.test.ts +10 -6
- package/src/toolchain.ts +31 -17
- package/src/types.ts +5 -3
- package/src/venue-rules.test.ts +70 -68
- package/src/venue-rules.ts +22 -12
- package/tsconfig.json +6 -3
- package/tsconfig.pkg.json +10 -0
- package/lib/check.d.mts +0 -17
- package/lib/paper-config.d.mts +0 -31
- package/scripts/layer-legacy-frozen.d.mts +0 -36
- package/scripts/rules-are-content-only.harness.mjs +0 -105
- package/scripts/rules-are-content-only.mjs +0 -148
- package/scripts/rules-are-content-only.test.mjs +0 -61
- package/scripts/test.mjs +0 -44
- package/scripts/test.test.mjs +0 -52
- package/skills/paper-pipeline/scripts/announce.mjs +0 -67
- package/skills/paper-pipeline/scripts/announce.test.mjs +0 -102
- package/skills/paper-pipeline/scripts/fixtures/clean/PIPELINE-STATUS.md +0 -51
- package/skills/paper-pipeline/scripts/fixtures/dirty/PIPELINE-STATUS.md +0 -52
- package/skills/paper-pipeline/scripts/fixtures/dirty/paper.md +0 -6
- package/skills/paper-pipeline/scripts/fixtures/scorecard.mjs +0 -71
- package/skills/paper-pipeline/scripts/ledger.cli.test.mjs +0 -302
- package/skills/paper-pipeline/scripts/ledger.mjs +0 -623
- package/skills/paper-pipeline/scripts/ledger.test.mjs +0 -254
- package/skills/paper-pipeline/scripts/pipeline-check.cli.test.mjs +0 -474
- package/skills/paper-pipeline/scripts/pipeline-check.harness.mjs +0 -328
- package/skills/paper-pipeline/scripts/pipeline-check.mjs +0 -753
- package/skills/paper-pipeline/scripts/pipeline-edges.mjs +0 -169
- package/skills/paper-pipeline/scripts/pipeline-edges.test.mjs +0 -73
- package/skills/paper-pipeline/scripts/run-mechanical.mjs +0 -648
- package/skills/paper-pipeline/scripts/run-mechanical.test.mjs +0 -468
- package/skills/paper-pipeline/scripts/status.mjs +0 -295
- package/skills/paper-pipeline/scripts/status.test.mjs +0 -232
- /package/bin/{paperlint.test.mjs → paperlint.test.ts} +0 -0
- /package/lib/{skill-eval-fixture.mjs → skill-eval-fixture.ts} +0 -0
- /package/skills/grade-paper-writing/__snapshots__/{prose-lint.test.mjs.snap → prose-lint.test.ts.snap} +0 -0
- /package/skills/tighten-paper/__snapshots__/{structure.test.mjs.snap → structure.test.ts.snap} +0 -0
package/src/venue-rules.test.ts
CHANGED
|
@@ -13,12 +13,9 @@ import { describe, expect, it } from "vitest";
|
|
|
13
13
|
import { memoryFiles } from "./adapters/memory/index.ts";
|
|
14
14
|
import { sha256Hex } from "./domain/sha256.ts";
|
|
15
15
|
import { packageVenuesDir } from "../skills/paper-pipeline/scripts/consumer.mjs";
|
|
16
|
-
import {
|
|
17
|
-
VENUE_RULE_LEVELS,
|
|
18
|
-
venueRules,
|
|
19
|
-
type VenueRuleModule,
|
|
20
|
-
} from "./venue-rules.ts";
|
|
16
|
+
import { VENUE_RULE_LEVELS, venueRules } from "./venue-rules.ts";
|
|
21
17
|
import { buildConfig, OPTIONAL_RULES, SHIPPED_RULES } from "./cli.ts";
|
|
18
|
+
import { present } from "../test/support.ts";
|
|
22
19
|
|
|
23
20
|
const VENUES = packageVenuesDir();
|
|
24
21
|
const PAPER = "/work/papers/p";
|
|
@@ -34,9 +31,18 @@ const shipped = Object.fromEntries(
|
|
|
34
31
|
);
|
|
35
32
|
|
|
36
33
|
type Json = Record<string, unknown>;
|
|
34
|
+
interface Font {
|
|
35
|
+
name: string;
|
|
36
|
+
type: string;
|
|
37
|
+
embedded: boolean;
|
|
38
|
+
program: string;
|
|
39
|
+
}
|
|
40
|
+
/** The facts file as these tests edit it: free-form, except the fonts they reach into. */
|
|
41
|
+
type Facts = Json & { fonts: Font[] };
|
|
42
|
+
type Patch = (f: Facts) => void;
|
|
37
43
|
|
|
38
44
|
/** The facts of a short agenticdev paper that meets every number in its profile. */
|
|
39
|
-
function goodFacts():
|
|
45
|
+
function goodFacts(): Facts {
|
|
40
46
|
return {
|
|
41
47
|
schema: 2,
|
|
42
48
|
pdf: "paper.pdf",
|
|
@@ -118,10 +124,7 @@ function lint(
|
|
|
118
124
|
const files = memoryFiles(paperFiles(p));
|
|
119
125
|
const rules = venueRules({ files, venuesDir: VENUES });
|
|
120
126
|
const out: Finding[] = [];
|
|
121
|
-
for (const [name, rule] of Object.entries(rules)
|
|
122
|
-
string,
|
|
123
|
-
VenueRuleModule,
|
|
124
|
-
][]) {
|
|
127
|
+
for (const [name, rule] of Object.entries(rules)) {
|
|
125
128
|
const visitor = rule.create({
|
|
126
129
|
filename,
|
|
127
130
|
...(cwd === undefined ? {} : { cwd }),
|
|
@@ -147,7 +150,13 @@ function lint(
|
|
|
147
150
|
const DECL = { extends: "paperlint:agenticdev", kind: "short" };
|
|
148
151
|
const ids = (fs: readonly Finding[]) =>
|
|
149
152
|
fs.map((f) => `${f.rule}:${f.messageId}`).sort();
|
|
150
|
-
|
|
153
|
+
/** A patch that changes one field set of the `i`-th font. */
|
|
154
|
+
const font =
|
|
155
|
+
(i: number, change: Partial<Font>): Patch =>
|
|
156
|
+
(f) => {
|
|
157
|
+
f.fonts = f.fonts.map((x, j) => (j === i ? { ...x, ...change } : x));
|
|
158
|
+
};
|
|
159
|
+
const withFacts = (patch: Patch): Facts => {
|
|
151
160
|
const f = goodFacts();
|
|
152
161
|
patch(f);
|
|
153
162
|
return f;
|
|
@@ -260,7 +269,7 @@ describe("pdf/profile — the kind", () => {
|
|
|
260
269
|
// the fonts rule still runs with an unresolved kind
|
|
261
270
|
const fonts = lint({
|
|
262
271
|
venue,
|
|
263
|
-
facts: withFacts((
|
|
272
|
+
facts: withFacts(font(0, { embedded: false })),
|
|
264
273
|
});
|
|
265
274
|
expect(ids(fonts)).toEqual([
|
|
266
275
|
`pdf/fonts:notEmbedded`,
|
|
@@ -338,7 +347,7 @@ describe("pdf/measured — a paper that names a venue and was not measured says
|
|
|
338
347
|
"pages_by_type",
|
|
339
348
|
])
|
|
340
349
|
f[k] = null;
|
|
341
|
-
(
|
|
350
|
+
font(0, { program: "Type3" })(f);
|
|
342
351
|
});
|
|
343
352
|
expect(ids(lint({ venue: DECL, facts: g }))).toEqual([
|
|
344
353
|
"pdf/fonts:type3",
|
|
@@ -348,7 +357,7 @@ describe("pdf/measured — a paper that names a venue and was not measured says
|
|
|
348
357
|
});
|
|
349
358
|
|
|
350
359
|
describe("pdf/fresh — facts about another build are not judged", () => {
|
|
351
|
-
it.each([
|
|
360
|
+
it.each<[string, Paper, string]>([
|
|
352
361
|
[
|
|
353
362
|
"a changed PDF",
|
|
354
363
|
{ pdf: new TextEncoder().encode("another build") },
|
|
@@ -364,55 +373,48 @@ describe("pdf/fresh — facts about another build are not judged", () => {
|
|
|
364
373
|
],
|
|
365
374
|
[
|
|
366
375
|
"a font entry of the wrong shape",
|
|
367
|
-
{ facts:
|
|
376
|
+
{ facts: { ...goodFacts(), fonts: [{ name: 3 }] } },
|
|
368
377
|
"factsBroken",
|
|
369
378
|
],
|
|
370
|
-
]
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
]);
|
|
379
|
-
},
|
|
380
|
-
);
|
|
379
|
+
])("%s: one finding, from pdf/fresh only", (_, p, messageId) => {
|
|
380
|
+
// Everything else planted wrong too — none of it may be reported over stale facts.
|
|
381
|
+
const facts =
|
|
382
|
+
p.facts ?? withFacts((f) => ((f.body_pages = 99), (f.columns = 1)));
|
|
383
|
+
expect(ids(lint({ venue: DECL, ...p, facts }))).toEqual([
|
|
384
|
+
`pdf/fresh:${messageId}`,
|
|
385
|
+
]);
|
|
386
|
+
});
|
|
381
387
|
});
|
|
382
388
|
|
|
383
389
|
describe("pdf/fonts", () => {
|
|
384
|
-
it.each([
|
|
385
|
-
[
|
|
386
|
-
"a Type 3 font",
|
|
387
|
-
(f: Json) => ((f.fonts as Json[])[0]!.program = "Type3"),
|
|
388
|
-
["pdf/fonts:type3"],
|
|
389
|
-
],
|
|
390
|
+
it.each<[string, (f: Facts) => void, string[]]>([
|
|
391
|
+
["a Type 3 font", font(0, { program: "Type3" }), ["pdf/fonts:type3"]],
|
|
390
392
|
[
|
|
391
393
|
"a font not embedded",
|
|
392
|
-
(
|
|
394
|
+
font(1, { embedded: false }),
|
|
393
395
|
["pdf/fonts:notEmbedded"],
|
|
394
396
|
],
|
|
395
397
|
[
|
|
396
398
|
"the text family missing — acmart fell back to Computer Modern",
|
|
397
|
-
(
|
|
399
|
+
font(0, { name: "CMR10" }),
|
|
398
400
|
["pdf/fonts:noFamily"],
|
|
399
401
|
],
|
|
400
402
|
[
|
|
401
403
|
"both families missing: one finding per family",
|
|
402
|
-
(f:
|
|
404
|
+
(f: Facts) =>
|
|
403
405
|
(f.fonts = [
|
|
404
406
|
{ name: "CMR10", type: "Type 1", embedded: true, program: "Type1" },
|
|
405
407
|
]),
|
|
406
408
|
["pdf/fonts:noFamily", "pdf/fonts:noFamily"],
|
|
407
409
|
],
|
|
408
|
-
]
|
|
410
|
+
])("%s", (_, patch, want) => {
|
|
409
411
|
expect(ids(lint({ venue: DECL, facts: withFacts(patch) }))).toEqual(want);
|
|
410
412
|
});
|
|
411
413
|
|
|
412
414
|
it("names the family and the fonts the PDF does have", () => {
|
|
413
415
|
const [f] = lint({
|
|
414
416
|
venue: DECL,
|
|
415
|
-
facts: withFacts((
|
|
417
|
+
facts: withFacts(font(0, { name: "CMR10" })),
|
|
416
418
|
});
|
|
417
419
|
expect(f?.message).toMatch(/LinLibertine/);
|
|
418
420
|
expect(f?.message).toMatch(/CMR10/);
|
|
@@ -420,28 +422,28 @@ describe("pdf/fonts", () => {
|
|
|
420
422
|
});
|
|
421
423
|
|
|
422
424
|
describe("pdf/geometry", () => {
|
|
423
|
-
it.each([
|
|
425
|
+
it.each<[string, (f: Facts) => void, string[]]>([
|
|
424
426
|
[
|
|
425
427
|
"A4 instead of letter",
|
|
426
|
-
(f:
|
|
428
|
+
(f: Facts) => ((f.page_w_in = 8.27), (f.page_h_in = 11.69)),
|
|
427
429
|
["pdf/geometry:dim", "pdf/geometry:dim"],
|
|
428
430
|
],
|
|
429
431
|
[
|
|
430
432
|
"one column instead of two",
|
|
431
|
-
(f:
|
|
433
|
+
(f: Facts) => (f.columns = 1),
|
|
432
434
|
["pdf/geometry:columns"],
|
|
433
435
|
],
|
|
434
436
|
[
|
|
435
437
|
"a page size banal could not read",
|
|
436
|
-
(f:
|
|
438
|
+
(f: Facts) => (f.page_w_in = null),
|
|
437
439
|
["pdf/geometry:dimMissing"],
|
|
438
440
|
],
|
|
439
441
|
[
|
|
440
442
|
"0.03 in off is inside the default tolerance",
|
|
441
|
-
(f:
|
|
443
|
+
(f: Facts) => (f.page_w_in = 8.53),
|
|
442
444
|
[],
|
|
443
445
|
],
|
|
444
|
-
]
|
|
446
|
+
])("%s", (_, patch, want) => {
|
|
445
447
|
expect(ids(lint({ venue: DECL, facts: withFacts(patch) }))).toEqual(want);
|
|
446
448
|
});
|
|
447
449
|
|
|
@@ -455,46 +457,43 @@ describe("pdf/geometry", () => {
|
|
|
455
457
|
});
|
|
456
458
|
|
|
457
459
|
describe("pdf/limits", () => {
|
|
458
|
-
it.each([
|
|
460
|
+
it.each<[string, (f: Facts) => void, string[], RegExp | null]>([
|
|
459
461
|
[
|
|
460
462
|
"one body page over the short-paper limit",
|
|
461
|
-
(f:
|
|
463
|
+
(f: Facts) => (f.body_pages = 6),
|
|
462
464
|
["pdf/limits:pages"],
|
|
463
465
|
/body pages: 6, over the limit 5 for agenticdev\/short/,
|
|
464
466
|
],
|
|
465
467
|
[
|
|
466
468
|
"one reference page over",
|
|
467
|
-
(f:
|
|
469
|
+
(f: Facts) => (f.ref_pages = 3),
|
|
468
470
|
["pdf/limits:pages"],
|
|
469
471
|
/reference pages: 3, over the limit 2/,
|
|
470
472
|
],
|
|
471
|
-
["exactly at the limit", (f:
|
|
473
|
+
["exactly at the limit", (f: Facts) => (f.body_pages = 5), [], null],
|
|
472
474
|
[
|
|
473
475
|
"a reference font below the range",
|
|
474
|
-
(f:
|
|
476
|
+
(f: Facts) => (f.ref_pt = 6),
|
|
475
477
|
["pdf/limits:refPt"],
|
|
476
478
|
/6 pt/,
|
|
477
479
|
],
|
|
478
480
|
[
|
|
479
481
|
"6.8 pt is inside the range once the measuring drift (body_pt_tol) is allowed",
|
|
480
|
-
(f:
|
|
482
|
+
(f: Facts) => (f.ref_pt = 6.8),
|
|
481
483
|
[],
|
|
482
484
|
null,
|
|
483
485
|
],
|
|
484
486
|
[
|
|
485
487
|
"no reference font measured (no bibliography) is not a finding",
|
|
486
|
-
(f:
|
|
488
|
+
(f: Facts) => (f.ref_pt = null),
|
|
487
489
|
[],
|
|
488
490
|
null,
|
|
489
491
|
],
|
|
490
|
-
]
|
|
491
|
-
|
|
492
|
-
(
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
if (text) expect(fs[0]?.message).toMatch(text);
|
|
496
|
-
},
|
|
497
|
-
);
|
|
492
|
+
])("%s", (_, patch, want, text) => {
|
|
493
|
+
const fs = lint({ venue: DECL, facts: withFacts(patch) });
|
|
494
|
+
expect(ids(fs)).toEqual(want);
|
|
495
|
+
if (text) expect(fs[0]?.message).toMatch(text);
|
|
496
|
+
});
|
|
498
497
|
|
|
499
498
|
it("a longer kind of the same venue passes the same page count", () => {
|
|
500
499
|
const facts = withFacts((f) => (f.body_pages = 9));
|
|
@@ -506,19 +505,19 @@ describe("pdf/limits", () => {
|
|
|
506
505
|
});
|
|
507
506
|
|
|
508
507
|
describe("pdf/body-size", () => {
|
|
509
|
-
it.each([
|
|
508
|
+
it.each<[string, (f: Facts) => void, string[]]>([
|
|
510
509
|
[
|
|
511
510
|
"10.2 pt against 9 ± 0.5",
|
|
512
|
-
(f:
|
|
511
|
+
(f: Facts) => (f.body_pt = 10.2),
|
|
513
512
|
["pdf/body-size:body"],
|
|
514
513
|
],
|
|
515
|
-
["9.4 pt is inside the tolerance", (f:
|
|
514
|
+
["9.4 pt is inside the tolerance", (f: Facts) => (f.body_pt = 9.4), []],
|
|
516
515
|
[
|
|
517
516
|
"no body size measured",
|
|
518
|
-
(f:
|
|
517
|
+
(f: Facts) => (f.body_pt = null),
|
|
519
518
|
["pdf/body-size:bodyMissing"],
|
|
520
519
|
],
|
|
521
|
-
]
|
|
520
|
+
])("%s", (_, patch, want) => {
|
|
522
521
|
expect(ids(lint({ venue: DECL, facts: withFacts(patch) }))).toEqual(want);
|
|
523
522
|
});
|
|
524
523
|
});
|
|
@@ -531,12 +530,15 @@ describe("where a finding points", () => {
|
|
|
531
530
|
});
|
|
532
531
|
|
|
533
532
|
describe("paperlint's own config turns the venue rules on for every paper.tex", () => {
|
|
534
|
-
const
|
|
535
|
-
(
|
|
536
|
-
|
|
533
|
+
const texRules = present(
|
|
534
|
+
buildConfig({}, { sentinel: "tex language" }).find((b) =>
|
|
535
|
+
(b.files ?? []).includes("**/paper.tex"),
|
|
536
|
+
)?.rules,
|
|
537
|
+
"the paper.tex block's rules",
|
|
538
|
+
);
|
|
537
539
|
|
|
538
540
|
it.each(Object.entries(VENUE_RULE_LEVELS))("%s is on at %s", (id, level) => {
|
|
539
|
-
expect(
|
|
541
|
+
expect(texRules[id]).toBe(level);
|
|
540
542
|
expect(SHIPPED_RULES.has(id)).toBe(true);
|
|
541
543
|
expect(OPTIONAL_RULES.has(id)).toBe(false);
|
|
542
544
|
});
|
|
@@ -567,7 +569,7 @@ describe("a project's own preset, and the facts' other spellings", () => {
|
|
|
567
569
|
format: { columns: 2, body_pt: 9, ref_pt_min: 7, ref_pt_max: 8 },
|
|
568
570
|
}),
|
|
569
571
|
};
|
|
570
|
-
const house = (patch: (f:
|
|
572
|
+
const house = (patch: (f: Facts) => void = () => {}) =>
|
|
571
573
|
lint({
|
|
572
574
|
venue: { extends: "./house.jsonc" },
|
|
573
575
|
facts: withFacts(patch),
|
package/src/venue-rules.ts
CHANGED
|
@@ -45,10 +45,11 @@ import {
|
|
|
45
45
|
import type { KindLimits, VenueFormat } from "./tex-requirements.ts";
|
|
46
46
|
import { paperPreset, presetProblemText } from "./presets.ts";
|
|
47
47
|
import type { FlatGeometry } from "./domain/geometry.ts";
|
|
48
|
-
import
|
|
48
|
+
import { callerPath } from "./caller-path.ts";
|
|
49
49
|
import { sha256Hex } from "./domain/sha256.ts";
|
|
50
|
+
import { fieldOf } from "./domain/record.ts";
|
|
50
51
|
import type { Files } from "./ports/files.ts";
|
|
51
|
-
import { CONFIG_FILE } from "
|
|
52
|
+
import { CONFIG_FILE } from "#lib/paper-config";
|
|
52
53
|
|
|
53
54
|
// ── the verdict's vocabulary ─────────────────────────────────────────────────────────
|
|
54
55
|
|
|
@@ -92,9 +93,8 @@ export interface VenueRuleDeps {
|
|
|
92
93
|
readonly venuesDir: string;
|
|
93
94
|
}
|
|
94
95
|
|
|
95
|
-
const at = (p: string): AbsolutePath => p as AbsolutePath;
|
|
96
96
|
const text = (files: Files, p: string): string | null => {
|
|
97
|
-
const b = files.readBytes(
|
|
97
|
+
const b = files.readBytes(callerPath(p));
|
|
98
98
|
return b === null ? null : new TextDecoder().decode(b);
|
|
99
99
|
};
|
|
100
100
|
|
|
@@ -138,7 +138,7 @@ function freshFacts(
|
|
|
138
138
|
: finding("factsBroken", { why: parsed.error.why });
|
|
139
139
|
const f = parsed.value;
|
|
140
140
|
const pdf = files.readBytes(
|
|
141
|
-
|
|
141
|
+
callerPath(isAbsolute(f.pdf) ? f.pdf : join(paperDir, f.pdf)),
|
|
142
142
|
);
|
|
143
143
|
if (pdf === null) return finding("pdfMissing", { pdf: f.pdf });
|
|
144
144
|
return sha256Hex(pdf) === f.sha ? f : finding("stale", { pdf: f.pdf });
|
|
@@ -373,8 +373,7 @@ const JUDGES: Readonly<Record<VenueRuleName, Judge>> = {
|
|
|
373
373
|
a.facts.geometry,
|
|
374
374
|
a.venue.format,
|
|
375
375
|
a.venue.venue,
|
|
376
|
-
(options[0]
|
|
377
|
-
DEFAULT_DIM_TOL_IN,
|
|
376
|
+
dimTolOf(options[0]),
|
|
378
377
|
)
|
|
379
378
|
: [],
|
|
380
379
|
limits: (a) =>
|
|
@@ -390,6 +389,12 @@ const JUDGES: Readonly<Record<VenueRuleName, Judge>> = {
|
|
|
390
389
|
/** How far, in inches, a measured page dimension may be from the preset's. */
|
|
391
390
|
export const DEFAULT_DIM_TOL_IN = 0.05;
|
|
392
391
|
|
|
392
|
+
/** `geometry`'s `dimTol` option in inches, or the default when the rule was given none. */
|
|
393
|
+
function dimTolOf(options: unknown): number {
|
|
394
|
+
const tol = fieldOf(options, "dimTol");
|
|
395
|
+
return typeof tol === "number" ? tol : DEFAULT_DIM_TOL_IN;
|
|
396
|
+
}
|
|
397
|
+
|
|
393
398
|
type Meta = Pick<VenueRuleModule["meta"], "docs" | "messages"> & {
|
|
394
399
|
readonly type?: "suggestion";
|
|
395
400
|
readonly schema?: readonly object[];
|
|
@@ -565,9 +570,14 @@ function rule(name: VenueRuleName, deps: VenueRuleDeps): VenueRuleModule {
|
|
|
565
570
|
export function venueRules(
|
|
566
571
|
deps: VenueRuleDeps,
|
|
567
572
|
): Record<VenueRuleName, VenueRuleModule> {
|
|
568
|
-
|
|
569
|
-
return
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
+
// Every name listed: a record missing one is a compile error.
|
|
574
|
+
return {
|
|
575
|
+
fresh: rule("fresh", deps),
|
|
576
|
+
profile: rule("profile", deps),
|
|
577
|
+
measured: rule("measured", deps),
|
|
578
|
+
fonts: rule("fonts", deps),
|
|
579
|
+
geometry: rule("geometry", deps),
|
|
580
|
+
limits: rule("limits", deps),
|
|
581
|
+
"body-size": rule("body-size", deps),
|
|
582
|
+
};
|
|
573
583
|
}
|
package/tsconfig.json
CHANGED
|
@@ -11,13 +11,16 @@
|
|
|
11
11
|
"sourceMap": true,
|
|
12
12
|
"strict": true,
|
|
13
13
|
"noUncheckedIndexedAccess": true,
|
|
14
|
-
"exactOptionalPropertyTypes":
|
|
14
|
+
"exactOptionalPropertyTypes": true,
|
|
15
15
|
"skipLibCheck": true,
|
|
16
16
|
"verbatimModuleSyntax": false,
|
|
17
17
|
"types": ["node"],
|
|
18
18
|
"allowImportingTsExtensions": true,
|
|
19
|
-
"rewriteRelativeImportExtensions": true
|
|
19
|
+
"rewriteRelativeImportExtensions": true,
|
|
20
|
+
"noImplicitOverride": true,
|
|
21
|
+
"noImplicitReturns": true,
|
|
22
|
+
"noFallthroughCasesInSwitch": true
|
|
20
23
|
},
|
|
21
24
|
"include": ["src/**/*.ts"],
|
|
22
|
-
"exclude": ["src/**/*.test.ts"]
|
|
25
|
+
"exclude": ["src/**/*.test.ts", "src/**/*.harness.ts"]
|
|
23
26
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "./tsconfig.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"rootDir": ".",
|
|
5
|
+
"outDir": "dist",
|
|
6
|
+
"resolveJsonModule": true
|
|
7
|
+
},
|
|
8
|
+
"include": ["lib/*.ts", "eslint-rules/*.ts", "eslint-rules/*.json"],
|
|
9
|
+
"exclude": ["**/*.test.ts", "**/*.harness.ts", "**/*.d.ts"]
|
|
10
|
+
}
|
package/lib/check.d.mts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
// Types for lib/check.mjs — the shared harness assertion helper (see the module).
|
|
2
|
-
|
|
3
|
-
/** A failure detail: text, any value (rendered with `util.inspect`), or a thunk producing one. */
|
|
4
|
-
export type Detail = unknown;
|
|
5
|
-
|
|
6
|
-
export declare function renderDetail(detail: Detail): string;
|
|
7
|
-
export declare function failureMessage(label: string, detail: Detail): string;
|
|
8
|
-
|
|
9
|
-
export interface Check {
|
|
10
|
-
(label: string, cond: unknown, detail?: Detail): void;
|
|
11
|
-
/** How many times this checker has been called. */
|
|
12
|
-
readonly count: number;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export declare function createChecker(options?: {
|
|
16
|
-
log?: (line: string) => void;
|
|
17
|
-
}): Check;
|
package/lib/paper-config.d.mts
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
// Types for lib/paper-config.mjs, which `src/*.ts` imports. Without this file TypeScript sees
|
|
2
|
-
// `any` and each import needs a `@ts-expect-error`, which covers only the next line and stops
|
|
3
|
-
// working as soon as a formatter wraps the import across several lines.
|
|
4
|
-
//
|
|
5
|
-
// The field names are typed as `string`, not as their values, so that the value is written
|
|
6
|
-
// once, in paper-config.mjs.
|
|
7
|
-
|
|
8
|
-
/** The tool's name — its settings file is named after it. */
|
|
9
|
-
export declare const CONFIG_KEY: string;
|
|
10
|
-
/** `paperlint.json`: the settings file, at the project root and in each paper. */
|
|
11
|
-
export declare const CONFIG_FILE: string;
|
|
12
|
-
/** The files that make a directory a paper. */
|
|
13
|
-
export declare const PAPER_MARKERS: readonly string[];
|
|
14
|
-
|
|
15
|
-
/** The project root, walking up from `startDir` (see the module). */
|
|
16
|
-
export declare function findProjectRoot(
|
|
17
|
-
startDir: string,
|
|
18
|
-
isFile?: (path: string) => boolean,
|
|
19
|
-
): string;
|
|
20
|
-
|
|
21
|
-
/** The root `paperlint.json` of `root` — undefined when absent, unparsable or not an object. */
|
|
22
|
-
export declare function settingsOf(
|
|
23
|
-
root: string,
|
|
24
|
-
): Readonly<Record<string, unknown>> | undefined;
|
|
25
|
-
export declare const DEFAULT_PAPERS_ROOT: string;
|
|
26
|
-
export declare const PAPERS_DIR_FIELD: string;
|
|
27
|
-
|
|
28
|
-
/** Every key a `paperlint.json` may hold, at either level, mapped to who reads it. */
|
|
29
|
-
export declare const SETTINGS_KEYS: Readonly<Record<string, string>>;
|
|
30
|
-
/** The keys refused in a paper's `paperlint.json`. */
|
|
31
|
-
export declare const ROOT_ONLY_KEYS: readonly string[];
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/** Types for `layer-legacy-frozen.mjs`, for its TypeScript test. */
|
|
2
|
-
export interface Suppressed {
|
|
3
|
-
readonly filePath: string;
|
|
4
|
-
readonly suppressedMessages?: readonly {
|
|
5
|
-
readonly ruleId: string | null;
|
|
6
|
-
readonly line: number;
|
|
7
|
-
readonly suppressions?: readonly { readonly justification?: string }[];
|
|
8
|
-
}[];
|
|
9
|
-
}
|
|
10
|
-
export type Counts = Record<string, Record<string, number>>;
|
|
11
|
-
export declare const FROZEN_FILE: string;
|
|
12
|
-
export declare const LAYER_RULES: readonly string[];
|
|
13
|
-
export declare const NO_LEGACY_UNDER: readonly string[];
|
|
14
|
-
export declare const LEGACY: RegExp;
|
|
15
|
-
export declare function tally(results: readonly Suppressed[]): {
|
|
16
|
-
counts: Counts;
|
|
17
|
-
unexplained: string[];
|
|
18
|
-
};
|
|
19
|
-
export declare function judge(o: {
|
|
20
|
-
counts: Counts;
|
|
21
|
-
unexplained: readonly string[];
|
|
22
|
-
frozen: Counts;
|
|
23
|
-
}): string[];
|
|
24
|
-
export declare function checkFrozen(
|
|
25
|
-
root?: string,
|
|
26
|
-
options?: { lint?: (cwd: string) => Promise<unknown[]> },
|
|
27
|
-
): Promise<{
|
|
28
|
-
problems: string[];
|
|
29
|
-
frozen: Counts;
|
|
30
|
-
counts: Counts;
|
|
31
|
-
}>;
|
|
32
|
-
export declare function main(options?: {
|
|
33
|
-
check?: () => Promise<{ problems: string[]; frozen: Counts; counts: Counts }>;
|
|
34
|
-
log?: (line: string) => void;
|
|
35
|
-
err?: (line: string) => void;
|
|
36
|
-
}): Promise<number>;
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Colocated test for `scripts/rules-are-content-only.mjs` — a rule may not ask git.
|
|
3
|
-
* Run: `npx vigiles test scripts/rules-are-content-only.harness.mjs`
|
|
4
|
-
*
|
|
5
|
-
* 🔴 BOTH HALVES. Like its sibling, this guard's success state is silence, so silence alone is
|
|
6
|
-
* no evidence it works:
|
|
7
|
-
* I. QUIET on this repository's real `eslint-rules/`, and the count is asserted non-zero —
|
|
8
|
-
* a guard that scanned nothing is also quiet, and that is the reading to rule out first.
|
|
9
|
-
* II. FIRES on each form the defect takes: static `import`, `require()`, dynamic `import()`,
|
|
10
|
-
* and the `node:` prefix — the prefix matters because a set membership test that lists
|
|
11
|
-
* only the bare specifier passes a file that writes the modern spelling.
|
|
12
|
-
* III. QUIET on sources that merely TALK about the banned module — a comment and a string
|
|
13
|
-
* literal. This is the half a grep cannot have, and the reason the check parses.
|
|
14
|
-
*/
|
|
15
|
-
import { dirname, join } from "node:path";
|
|
16
|
-
import { fileURLToPath } from "node:url";
|
|
17
|
-
import { createChecker } from "../lib/check.mjs";
|
|
18
|
-
|
|
19
|
-
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
20
|
-
const { rulesAreContentOnly, processImports } = await import(
|
|
21
|
-
join(HERE, "rules-are-content-only.mjs")
|
|
22
|
-
);
|
|
23
|
-
|
|
24
|
-
const check = createChecker();
|
|
25
|
-
|
|
26
|
-
// ── I. quiet on the real corpus, and it actually looked ───────────────────────
|
|
27
|
-
{
|
|
28
|
-
const { checked, findings } = rulesAreContentOnly({ cwd: join(HERE, "..") });
|
|
29
|
-
check(
|
|
30
|
-
`scanned something (${checked.length} rule sources)`,
|
|
31
|
-
checked.length > 0,
|
|
32
|
-
);
|
|
33
|
-
check(
|
|
34
|
-
`quiet on the real corpus (${findings.length} findings)`,
|
|
35
|
-
findings.length === 0,
|
|
36
|
-
);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// ── II. fires on every form the defect has taken ────────────────────────────
|
|
40
|
-
for (const [label, src] of [
|
|
41
|
-
[
|
|
42
|
-
"execFileSync with a git argv",
|
|
43
|
-
`import { execFileSync } from "node:child_process";
|
|
44
|
-
execFileSync("git", ["cat-file", "-e", sha]);`,
|
|
45
|
-
],
|
|
46
|
-
[
|
|
47
|
-
"a namespaced call",
|
|
48
|
-
`import cp from "node:child_process";
|
|
49
|
-
cp.spawnSync("git", ["rev-parse", ref]);`,
|
|
50
|
-
],
|
|
51
|
-
[
|
|
52
|
-
"execSync with a git shell line",
|
|
53
|
-
`import { execSync } from "child_process";
|
|
54
|
-
execSync("git log --oneline -1");`,
|
|
55
|
-
],
|
|
56
|
-
["exec, async form", `exec("git rev-list --all", cb);`],
|
|
57
|
-
]) {
|
|
58
|
-
check(`FIRES on ${label}`, processImports(src).length === 1);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// ── III. the FALSE POSITIVE that forced the narrowing, asserted so it cannot return ──
|
|
62
|
-
// 🔴 `paper-texcount.mjs` in the consumer shells out to `texcount` to count words in a .tex.
|
|
63
|
-
// The first version of this check keyed on importing `child_process` at all, so it claimed that
|
|
64
|
-
// rule on its first run — a false positive on an `error` gate, which is worse than a miss
|
|
65
|
-
// because the gate that cannot be cleared gets switched off rather than fixed.
|
|
66
|
-
for (const [label, src] of [
|
|
67
|
-
[
|
|
68
|
-
"a rule spawning texcount",
|
|
69
|
-
`import { execFileSync } from "node:child_process";
|
|
70
|
-
execFileSync("texcount", ["-brief", file]);`,
|
|
71
|
-
],
|
|
72
|
-
[
|
|
73
|
-
"a rule spawning pdflatex",
|
|
74
|
-
`import { spawnSync } from "node:child_process";
|
|
75
|
-
spawnSync("pdflatex", [tex]);`,
|
|
76
|
-
],
|
|
77
|
-
[
|
|
78
|
-
"importing child_process without running git",
|
|
79
|
-
`import { execFileSync } from "node:child_process";
|
|
80
|
-
export default {};`,
|
|
81
|
-
],
|
|
82
|
-
]) {
|
|
83
|
-
check(`quiet on ${label}`, processImports(src).length === 0);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// ── IV. quiet on sources that only MENTION it — what a grep cannot do ───────
|
|
87
|
-
for (const [label, src] of [
|
|
88
|
-
[
|
|
89
|
-
"a comment naming git",
|
|
90
|
-
`// never reach for git cat-file here\nexport default {};`,
|
|
91
|
-
],
|
|
92
|
-
["a string literal", `export const why = "git cat-file is banned in rules";`],
|
|
93
|
-
[
|
|
94
|
-
"a reported message",
|
|
95
|
-
`export default { meta: { messages: { m: "run git cat-file? no" } } };`,
|
|
96
|
-
],
|
|
97
|
-
[
|
|
98
|
-
"a program merely NAMED git-something",
|
|
99
|
-
`execFileSync("git-lfs-helper", []);`,
|
|
100
|
-
],
|
|
101
|
-
]) {
|
|
102
|
-
check(`quiet on ${label}`, processImports(src).length === 0);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
console.log(`rules-are-content-only.harness: ${check.count} assertions passed`);
|