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/structure.ts
CHANGED
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
import { readdirSync, existsSync } from "node:fs";
|
|
26
26
|
import { join, relative, basename, isAbsolute, sep } from "node:path";
|
|
27
27
|
import type { StructureConfig, StructureFinding } from "./types.ts";
|
|
28
|
-
import { CONFIG_FILE } from "
|
|
28
|
+
import { CONFIG_FILE } from "#lib/paper-config";
|
|
29
29
|
|
|
30
30
|
/** The requirements after the consumer's config is laid over the defaults. */
|
|
31
31
|
type Rules = Required<StructureConfig>;
|
|
@@ -13,12 +13,14 @@ import {
|
|
|
13
13
|
readFileSync,
|
|
14
14
|
realpathSync,
|
|
15
15
|
rmSync,
|
|
16
|
+
writeFileSync,
|
|
16
17
|
} from "node:fs";
|
|
17
18
|
import { tmpdir } from "node:os";
|
|
18
19
|
import { dirname, join } from "node:path";
|
|
19
20
|
import { fileURLToPath } from "node:url";
|
|
20
21
|
import ts from "typescript";
|
|
21
|
-
import {
|
|
22
|
+
import { z } from "zod";
|
|
23
|
+
import { createChecker } from "../lib/check.ts";
|
|
22
24
|
|
|
23
25
|
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
24
26
|
const VENUES = join(
|
|
@@ -29,18 +31,18 @@ const VENUES = join(
|
|
|
29
31
|
"references",
|
|
30
32
|
"venues",
|
|
31
33
|
);
|
|
32
|
-
const R = await import(
|
|
34
|
+
const R = await import("./tex-requirements.ts");
|
|
33
35
|
|
|
34
36
|
const check = createChecker();
|
|
35
|
-
const throws = (fn) => {
|
|
37
|
+
const throws = (fn: () => unknown): string => {
|
|
36
38
|
try {
|
|
37
39
|
fn();
|
|
38
40
|
return "";
|
|
39
41
|
} catch (e) {
|
|
40
|
-
return e.message;
|
|
42
|
+
return e instanceof Error ? e.message : String(e);
|
|
41
43
|
}
|
|
42
44
|
};
|
|
43
|
-
const read = (f) =>
|
|
45
|
+
const read = (f: string) =>
|
|
44
46
|
R.parseProfile(readFileSync(join(VENUES, f), "utf8"), f, VENUES);
|
|
45
47
|
|
|
46
48
|
// ── 1. the shipped data ─────────────────────────────────────────────────────────────────
|
|
@@ -69,11 +71,14 @@ check(
|
|
|
69
71
|
);
|
|
70
72
|
|
|
71
73
|
// The whole profile, parsed the way the other harnesses read these files — never a line of text.
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
74
|
+
const TemplateField = z.object({ template: z.unknown().optional() });
|
|
75
|
+
const templateOf = (v: string): unknown =>
|
|
76
|
+
TemplateField.parse(
|
|
77
|
+
ts.parseConfigFileTextToJson(
|
|
78
|
+
v,
|
|
79
|
+
readFileSync(join(VENUES, `${v}.jsonc`), "utf8"),
|
|
80
|
+
).config,
|
|
81
|
+
).template;
|
|
77
82
|
const acm = venues.filter((v) => templateOf(v) === "acmart");
|
|
78
83
|
check(
|
|
79
84
|
"at least one acmart venue is shipped (else the next checks see nothing)",
|
|
@@ -92,7 +97,7 @@ for (const v of acm) {
|
|
|
92
97
|
// minimal one.
|
|
93
98
|
["fancyhdr", "fancyhdr.sty"],
|
|
94
99
|
["acmart", "acmart.cls"],
|
|
95
|
-
])
|
|
100
|
+
] satisfies [string, string][])
|
|
96
101
|
check(
|
|
97
102
|
`🔴 ${v}: declares ${pkg}, proved by ${file}`,
|
|
98
103
|
tex.packages[pkg]?.includes(file),
|
|
@@ -102,22 +107,39 @@ for (const v of acm) {
|
|
|
102
107
|
// dictionaries diverged. Since the ACM venues extend the `acm-sigconf` family, only the family
|
|
103
108
|
// declares the template's packages, so this holds by construction; the check stays for any two
|
|
104
109
|
// standalone presets that name the same template.
|
|
105
|
-
const byTemplate = new Map();
|
|
110
|
+
const byTemplate = new Map<unknown, string[]>();
|
|
106
111
|
for (const v of venues) {
|
|
107
112
|
const t = templateOf(v);
|
|
108
113
|
byTemplate.set(t, [...(byTemplate.get(t) ?? []), v]);
|
|
109
114
|
}
|
|
110
115
|
for (const [t, vs] of byTemplate)
|
|
111
116
|
check(
|
|
112
|
-
`venues on template ${t} declare the SAME packages (${vs.join(", ")})`,
|
|
117
|
+
`venues on template ${String(t)} declare the SAME packages (${vs.join(", ")})`,
|
|
113
118
|
new Set(vs.map((v) => JSON.stringify(read(`${v}.jsonc`)))).size === 1,
|
|
114
119
|
);
|
|
115
120
|
|
|
121
|
+
// A venues directory whose schema file is JSON but not a schema: refused where it is read, with
|
|
122
|
+
// the file's name — not deep inside Ajv as "schema should be object or boolean".
|
|
123
|
+
{
|
|
124
|
+
const odd = realpathSync(
|
|
125
|
+
mkdtempSync(join(tmpdir(), "paperlint-texreq-schema-")),
|
|
126
|
+
);
|
|
127
|
+
writeFileSync(join(odd, R.SCHEMA_FILE), "3\n");
|
|
128
|
+
check(
|
|
129
|
+
"a schema file that is not a JSON object is refused, naming the file",
|
|
130
|
+
new RegExp(
|
|
131
|
+
`${R.SCHEMA_FILE.replace(/\./g, "\\.")}: not a JSON Schema object`,
|
|
132
|
+
).test(throws(() => R.parsePreset("{}", "odd.jsonc", odd))),
|
|
133
|
+
throws(() => R.parsePreset("{}", "odd.jsonc", odd)),
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
|
|
116
137
|
// ── 2. the schema rejects ───────────────────────────────────────────────────────────────
|
|
117
138
|
const tmp = realpathSync(mkdtempSync(join(tmpdir(), "paperlint-texreq-h-")));
|
|
118
139
|
copyFileSync(join(VENUES, R.SCHEMA_FILE), join(tmp, R.SCHEMA_FILE));
|
|
119
|
-
const bad = (text
|
|
120
|
-
|
|
140
|
+
const bad = (text: string) =>
|
|
141
|
+
throws(() => R.parseProfile(text, "bad.jsonc", tmp));
|
|
142
|
+
const BAD: [string, string, string][] = [
|
|
121
143
|
["no `tex` block at all", `{ "template": "acmart" }`, "tex"],
|
|
122
144
|
// Guards: typo detection — `templat` would be accepted and the field silently unread.
|
|
123
145
|
[
|
|
@@ -181,13 +203,12 @@ rmSync(tmp, { recursive: true, force: true });
|
|
|
181
203
|
// Which preset a paper resolves to — a typo, the base file, a missing one — is src/presets.ts's
|
|
182
204
|
// question now, tested in src/presets.test.ts; this function only adds a resolved preset's packages.
|
|
183
205
|
{
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
);
|
|
206
|
+
// `acm` is non-empty: the check above it throws otherwise.
|
|
207
|
+
const [label = ""] = acm;
|
|
208
|
+
const r = R.requirementsFor({ label, tex: read(`${label}.jsonc`) }, VENUES);
|
|
188
209
|
check(
|
|
189
210
|
"a resolved preset → its packages ON TOP OF the base set, and the source names its label",
|
|
190
|
-
r.source === `venue ${
|
|
211
|
+
r.source === `venue ${label}` &&
|
|
191
212
|
"acmart" in r.tex.packages &&
|
|
192
213
|
"hyperref" in r.tex.packages &&
|
|
193
214
|
"texcount" in r.tex.tools,
|
|
@@ -251,9 +272,16 @@ rmSync(tmp, { recursive: true, force: true });
|
|
|
251
272
|
"violations: Ajv's null `errors` is no violation; a message Ajv left out is an empty one",
|
|
252
273
|
R.violations("f.jsonc", { errors: null }).length === 0 &&
|
|
253
274
|
R.violations("f.jsonc", {
|
|
254
|
-
errors: [
|
|
275
|
+
errors: [
|
|
276
|
+
{
|
|
277
|
+
keyword: "required",
|
|
278
|
+
dataPath: "",
|
|
279
|
+
schemaPath: "#/required",
|
|
280
|
+
params: {},
|
|
281
|
+
},
|
|
282
|
+
],
|
|
255
283
|
})[0] === "f.jsonc: (top level) ",
|
|
256
284
|
);
|
|
257
285
|
}
|
|
258
286
|
|
|
259
|
-
console.log(`tex-requirements: ${check.count} checks passed`);
|
|
287
|
+
console.log(`tex-requirements: ${String(check.count)} checks passed`);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { test } from "vitest";
|
|
3
|
+
import { loadTypescript } from "./tex-requirements.ts";
|
|
4
|
+
|
|
5
|
+
test("loadTypescript refuses a module without the two functions a profile is read with", () => {
|
|
6
|
+
assert.throws(
|
|
7
|
+
() => loadTypescript(() => ({})),
|
|
8
|
+
/loaded without parseConfigFileTextToJson/,
|
|
9
|
+
);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
test("loadTypescript hands back what `require` loaded when it has them", () => {
|
|
13
|
+
const ts = {
|
|
14
|
+
parseConfigFileTextToJson: () => ({ config: {} }),
|
|
15
|
+
flattenDiagnosticMessageText: () => "",
|
|
16
|
+
};
|
|
17
|
+
assert.equal(
|
|
18
|
+
loadTypescript(() => ts),
|
|
19
|
+
ts,
|
|
20
|
+
);
|
|
21
|
+
});
|
package/src/tex-requirements.ts
CHANGED
|
@@ -26,7 +26,8 @@ import { join } from "node:path";
|
|
|
26
26
|
// eslint-disable-next-line boundaries/dependencies -- legacy layer, moves behind a port in #76
|
|
27
27
|
import Ajv from "ajv";
|
|
28
28
|
import { packageVenuesDir } from "../skills/paper-pipeline/scripts/consumer.mjs";
|
|
29
|
-
import { CONFIG_FILE } from "
|
|
29
|
+
import { CONFIG_FILE } from "#lib/paper-config";
|
|
30
|
+
import { fieldOf } from "./domain/record.ts";
|
|
30
31
|
|
|
31
32
|
/** CTAN package name → the names that prove it is installed. */
|
|
32
33
|
export type PackageProofs = Readonly<Record<string, readonly string[]>>;
|
|
@@ -51,22 +52,45 @@ const PROFILE_EXT = ".jsonc";
|
|
|
51
52
|
|
|
52
53
|
export const NO_REQUIREMENTS: TexRequirements = { packages: {}, tools: {} };
|
|
53
54
|
|
|
54
|
-
|
|
55
|
-
|
|
55
|
+
/** The two functions of `typescript` a profile is read with. */
|
|
56
|
+
type TsJsonc = Pick<
|
|
57
|
+
typeof import("typescript"),
|
|
58
|
+
"parseConfigFileTextToJson" | "flattenDiagnosticMessageText"
|
|
59
|
+
>;
|
|
60
|
+
|
|
61
|
+
const isTsJsonc = (m: unknown): m is TsJsonc =>
|
|
62
|
+
typeof fieldOf(m, "parseConfigFileTextToJson") === "function" &&
|
|
63
|
+
typeof fieldOf(m, "flattenDiagnosticMessageText") === "function";
|
|
64
|
+
|
|
65
|
+
/** `typescript` as `load` returns it — `require` answers `any` — checked for the two functions used. */
|
|
66
|
+
export function loadTypescript(load: (id: string) => unknown): TsJsonc {
|
|
67
|
+
const m = load("typescript");
|
|
68
|
+
if (!isTsJsonc(m))
|
|
69
|
+
throw new Error(
|
|
70
|
+
"`typescript` loaded without parseConfigFileTextToJson — reinstall this package",
|
|
71
|
+
);
|
|
72
|
+
return m;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
let ts: TsJsonc | null = null;
|
|
56
76
|
/** TypeScript is loaded only when a profile is read: `paperlint lint` never pays for it. */
|
|
57
|
-
function typescript():
|
|
58
|
-
ts ??= createRequire(import.meta.url)
|
|
77
|
+
function typescript(): TsJsonc {
|
|
78
|
+
ts ??= loadTypescript(createRequire(import.meta.url));
|
|
59
79
|
return ts;
|
|
60
80
|
}
|
|
61
81
|
|
|
62
82
|
type Validate = ReturnType<Ajv.Ajv["compile"]>;
|
|
83
|
+
/** `PresetJson` is the TypeScript side of the profile schema: a document the schema accepts is one. */
|
|
84
|
+
const matchesSchema = (v: unknown, validate: Validate): v is PresetJson =>
|
|
85
|
+
validate(v) === true;
|
|
63
86
|
const validators = new Map<string, Validate>();
|
|
64
87
|
function validatorFor(dir: string): Validate {
|
|
65
88
|
const known = validators.get(dir);
|
|
66
89
|
if (known) return known;
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
)
|
|
90
|
+
const path = join(dir, SCHEMA_FILE);
|
|
91
|
+
const schema: unknown = JSON.parse(readFileSync(path, "utf8"));
|
|
92
|
+
if (typeof schema !== "object" || schema === null)
|
|
93
|
+
throw new Error(`${path}: not a JSON Schema object`);
|
|
70
94
|
const v = new Ajv({ allErrors: true }).compile(schema);
|
|
71
95
|
validators.set(dir, v);
|
|
72
96
|
return v;
|
|
@@ -214,17 +238,19 @@ export function parsePreset(
|
|
|
214
238
|
file: string,
|
|
215
239
|
dir: string = packageVenuesDir(),
|
|
216
240
|
): PresetFile {
|
|
217
|
-
const
|
|
241
|
+
const parsed = typescript().parseConfigFileTextToJson(file, text);
|
|
242
|
+
const config: unknown = parsed.config;
|
|
243
|
+
const error = parsed.error;
|
|
218
244
|
if (error)
|
|
219
245
|
throw new Error(
|
|
220
246
|
`${file}: not valid JSONC — ${typescript().flattenDiagnosticMessageText(error.messageText, " ")}`,
|
|
221
247
|
);
|
|
222
248
|
const validate = validatorFor(dir);
|
|
223
|
-
if (!
|
|
249
|
+
if (!matchesSchema(config, validate))
|
|
224
250
|
throw new Error(
|
|
225
251
|
`${file} does not match ${SCHEMA_FILE}:\n ${violations(file, validate).join("\n ")}`,
|
|
226
252
|
);
|
|
227
|
-
const j = config
|
|
253
|
+
const j = config;
|
|
228
254
|
return {
|
|
229
255
|
extends: orNull(j.extends),
|
|
230
256
|
name: orNull(j.name),
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* inside is `fixtures/toolchain-mirror/install-tl`, which lays out a tree whose `kpsewhich` and
|
|
7
7
|
* `tlmgr` answer from two text files. So what runs is paperlint's own download, fallback, unpack,
|
|
8
8
|
* install and verify logic — the part that decides success — and what is faked is only TeX.
|
|
9
|
-
* The real TeX Live half is `test/e2e/toolchain.
|
|
9
|
+
* The real TeX Live half is `test/e2e/toolchain.ts`.
|
|
10
10
|
*
|
|
11
11
|
* Tables, in order:
|
|
12
12
|
* 1. the pure pieces (year, profile, tlmgr's unknown names, cache location);
|
|
@@ -32,7 +32,7 @@ import {
|
|
|
32
32
|
import { tmpdir } from "node:os";
|
|
33
33
|
import { dirname, join } from "node:path";
|
|
34
34
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
35
|
-
import { createChecker } from "../lib/check.
|
|
35
|
+
import { createChecker } from "../lib/check.ts";
|
|
36
36
|
|
|
37
37
|
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
38
38
|
const FIXTURE = join(HERE, "..", "fixtures", "toolchain-mirror");
|
package/src/toolchain.test.ts
CHANGED
|
@@ -9,7 +9,7 @@ import { chmodSync, mkdirSync, writeFileSync } from "node:fs";
|
|
|
9
9
|
import { dirname } from "node:path";
|
|
10
10
|
import { join } from "node:path";
|
|
11
11
|
import { test } from "vitest";
|
|
12
|
-
import { useTempDir, writeTree } from "../test/support.
|
|
12
|
+
import { useTempDir, writeTree } from "../test/support.ts";
|
|
13
13
|
import {
|
|
14
14
|
cachedTrees,
|
|
15
15
|
CACHE_ENV,
|
|
@@ -34,19 +34,19 @@ type Answer = {
|
|
|
34
34
|
};
|
|
35
35
|
/** A runner answering by program name (the last path segment); `onRun` may write files first. */
|
|
36
36
|
function io(
|
|
37
|
-
answers: Record<string, (args: string[]) => Answer>,
|
|
37
|
+
answers: Record<string, (args: readonly string[]) => Answer>,
|
|
38
38
|
): ToolchainIO & { lines: string[] } {
|
|
39
39
|
const lines: string[] = [];
|
|
40
40
|
return {
|
|
41
41
|
lines,
|
|
42
42
|
log: (l) => lines.push(l),
|
|
43
43
|
env: {},
|
|
44
|
-
run: (
|
|
44
|
+
run: (cmd, args) => {
|
|
45
45
|
const name = cmd.split("/").pop() ?? cmd;
|
|
46
46
|
const answer = answers[`${name} ${args[0] ?? ""}`] ?? answers[name];
|
|
47
47
|
if (!answer) throw new Error(`unexpected ${name} ${args.join(" ")}`);
|
|
48
48
|
return answer(args);
|
|
49
|
-
}
|
|
49
|
+
},
|
|
50
50
|
};
|
|
51
51
|
}
|
|
52
52
|
const ok = (stdout = ""): Answer => ({ status: 0, stdout, stderr: "" });
|
|
@@ -194,7 +194,7 @@ function cacheWith(name: string, year: string): string {
|
|
|
194
194
|
const ACMART = { packages: { acmart: ["acmart.cls"] }, tools: {} };
|
|
195
195
|
function ensure(
|
|
196
196
|
cache: string,
|
|
197
|
-
answers: Record<string, (args: string[]) => Answer>,
|
|
197
|
+
answers: Record<string, (args: readonly string[]) => Answer>,
|
|
198
198
|
) {
|
|
199
199
|
const t = io(answers);
|
|
200
200
|
const errs: string[] = [];
|
|
@@ -272,7 +272,11 @@ test("runToolchain with only its installer: the console is the default output",
|
|
|
272
272
|
const saved = console.error;
|
|
273
273
|
console.error = (...a: unknown[]) => void seen.push(a.join(" "));
|
|
274
274
|
try {
|
|
275
|
-
|
|
275
|
+
const unused = (): never => {
|
|
276
|
+
throw new Error("an unsupported platform installs nothing");
|
|
277
|
+
};
|
|
278
|
+
const banal = { label: "banal", ensure: unused, check: unused };
|
|
279
|
+
assert.equal(runToolchain({ platform: "win32", banal }), 1);
|
|
276
280
|
} finally {
|
|
277
281
|
console.error = saved;
|
|
278
282
|
}
|
package/src/toolchain.ts
CHANGED
|
@@ -56,6 +56,10 @@ import {
|
|
|
56
56
|
packageNames,
|
|
57
57
|
type TexRequirements,
|
|
58
58
|
} from "./tex-requirements.ts";
|
|
59
|
+
import { printed } from "./domain/text.ts";
|
|
60
|
+
|
|
61
|
+
/** stdin closed, stdout and stderr captured — the tuple type spawnSync's `stdio` wants. */
|
|
62
|
+
const PIPED: ["ignore", "pipe", "pipe"] = ["ignore", "pipe", "pipe"];
|
|
59
63
|
|
|
60
64
|
export const CACHE_ENV = "PAPERLINT_TEXLIVE_DIR";
|
|
61
65
|
export const MIRROR_ENV = "PAPERLINT_CTAN_MIRROR";
|
|
@@ -274,23 +278,29 @@ export function describeGaps(g: Gaps, tex: TexRequirements): string {
|
|
|
274
278
|
export function formatDuration(ms: number): string {
|
|
275
279
|
const s = Math.round(ms / 1000);
|
|
276
280
|
return s < 60
|
|
277
|
-
? `${s}s`
|
|
278
|
-
: `${Math.floor(s / 60)}m${String(s % 60).padStart(2, "0")}s`;
|
|
281
|
+
? `${String(s)}s`
|
|
282
|
+
: `${String(Math.floor(s / 60))}m${String(s % 60).padStart(2, "0")}s`;
|
|
279
283
|
}
|
|
280
284
|
|
|
281
285
|
// ── processes ────────────────────────────────────────────────────────────────────────
|
|
282
286
|
|
|
283
287
|
const quiet = (io: ToolchainIO, timeout?: number) => ({
|
|
284
288
|
encoding: "utf8" as const,
|
|
285
|
-
stdio:
|
|
289
|
+
stdio: PIPED,
|
|
286
290
|
env: io.env,
|
|
287
291
|
maxBuffer: 64 * 1024 * 1024,
|
|
288
292
|
...(timeout ? { timeout } : {}),
|
|
289
293
|
});
|
|
290
294
|
|
|
291
295
|
/** The last lines a process printed — what a failure shows. */
|
|
292
|
-
function tail(
|
|
293
|
-
|
|
296
|
+
function tail(
|
|
297
|
+
r: {
|
|
298
|
+
readonly stdout?: string | undefined;
|
|
299
|
+
readonly stderr?: string | undefined;
|
|
300
|
+
},
|
|
301
|
+
n = 12,
|
|
302
|
+
): string[] {
|
|
303
|
+
const text = `${printed(r.stdout)}\n${printed(r.stderr)}`;
|
|
294
304
|
return text
|
|
295
305
|
.split("\n")
|
|
296
306
|
.filter((l) => l.trim())
|
|
@@ -475,13 +485,15 @@ export function installPackages(
|
|
|
475
485
|
if (noGaps(gaps)) break;
|
|
476
486
|
const want = [...gaps.packages, ...gaps.tools, ...gaps.dependencies];
|
|
477
487
|
const repairsBase = gaps.dependencies.length > 0;
|
|
478
|
-
io.log(
|
|
488
|
+
io.log(
|
|
489
|
+
` tlmgr: installing ${String(want.length)} package(s) from ${mirror}…`,
|
|
490
|
+
);
|
|
479
491
|
const r = io.run(
|
|
480
492
|
join(tree.bin, "tlmgr"),
|
|
481
493
|
["--repository", mirror, "install", ...want],
|
|
482
494
|
quiet(io, TLMGR_MS),
|
|
483
495
|
);
|
|
484
|
-
const output = `${
|
|
496
|
+
const output = `${printed(r.stdout)}\n${printed(r.stderr)}`;
|
|
485
497
|
// A new release: every mirror serves it, so trying the next one only repeats the refusal.
|
|
486
498
|
const newer = releaseGap(output);
|
|
487
499
|
if (newer) return { ok: false, newer };
|
|
@@ -567,7 +579,7 @@ export function ensureTexLive(
|
|
|
567
579
|
if (!verified.ok) return fail(o.err, verified.lines);
|
|
568
580
|
o.log(
|
|
569
581
|
`✓ TeX Live ${used.year} is ready in ${used.dir}: ${verified.value} ` +
|
|
570
|
-
`${sizeMB(used.dir)} MB, ${formatDuration(o.now() - started)}`,
|
|
582
|
+
`${String(sizeMB(used.dir))} MB, ${formatDuration(o.now() - started)}`,
|
|
571
583
|
);
|
|
572
584
|
o.log(binLine(used));
|
|
573
585
|
if (used !== tree.value) o.log(leftInPlace(tree.value));
|
|
@@ -638,14 +650,14 @@ function verify(
|
|
|
638
650
|
return {
|
|
639
651
|
ok: true,
|
|
640
652
|
value:
|
|
641
|
-
`${packageNames(tex).length} packages verified ` +
|
|
642
|
-
`(${files} files found by kpsewhich, ${Object.keys(tex.tools).length} tools),`,
|
|
653
|
+
`${String(packageNames(tex).length)} packages verified ` +
|
|
654
|
+
`(${String(files)} files found by kpsewhich, ${String(Object.keys(tex.tools).length)} tools),`,
|
|
643
655
|
};
|
|
644
656
|
}
|
|
645
657
|
|
|
646
658
|
/** The superseded tree is named, with the space it holds — and left alone. */
|
|
647
659
|
export const leftInPlace = (old: CachedTree): string =>
|
|
648
|
-
` TeX Live ${old.year} in ${old.dir} is left in place and no longer used (${sizeMB(old.dir)} MB); ` +
|
|
660
|
+
` TeX Live ${old.year} in ${old.dir} is left in place and no longer used (${String(sizeMB(old.dir))} MB); ` +
|
|
649
661
|
`delete that directory to free the space`;
|
|
650
662
|
|
|
651
663
|
/**
|
|
@@ -693,14 +705,14 @@ function report(o: Resolved, tree: CachedTree | null): number {
|
|
|
693
705
|
const n = packageNames(o.tex).length;
|
|
694
706
|
if (!tree) {
|
|
695
707
|
o.log(
|
|
696
|
-
`✗ no TeX Live in ${cacheRoot(o.env, o.home)} — \`npx paperlint toolchain\` installs ${n} packages (~230 MB, ~2 min)`,
|
|
708
|
+
`✗ no TeX Live in ${cacheRoot(o.env, o.home)} — \`npx paperlint toolchain\` installs ${String(n)} packages (~230 MB, ~2 min)`,
|
|
697
709
|
);
|
|
698
710
|
return 1;
|
|
699
711
|
}
|
|
700
712
|
const gaps = gapsOf(tree, o.tex, o.run);
|
|
701
713
|
if (noGaps(gaps)) {
|
|
702
714
|
o.log(
|
|
703
|
-
`✓ TeX Live ${tree.year} in ${tree.dir} has all ${n} declared packages`,
|
|
715
|
+
`✓ TeX Live ${tree.year} in ${tree.dir} has all ${String(n)} declared packages`,
|
|
704
716
|
);
|
|
705
717
|
o.log(binLine(tree));
|
|
706
718
|
return 0;
|
|
@@ -709,9 +721,11 @@ function report(o: Resolved, tree: CachedTree | null): number {
|
|
|
709
721
|
// A dependency the install left out is not one of the venue's declared packages: counted apart,
|
|
710
722
|
// so the line never reads "lacks 0 of 51" followed by a name.
|
|
711
723
|
const what = [
|
|
712
|
-
...(declared
|
|
724
|
+
...(declared
|
|
725
|
+
? [`${String(declared)} of ${String(n)} declared packages`]
|
|
726
|
+
: []),
|
|
713
727
|
...(gaps.dependencies.length
|
|
714
|
-
? [`${gaps.dependencies.length} TeX Live base package(s)`]
|
|
728
|
+
? [`${String(gaps.dependencies.length)} TeX Live base package(s)`]
|
|
715
729
|
: []),
|
|
716
730
|
].join(" and ");
|
|
717
731
|
o.log(
|
|
@@ -759,13 +773,13 @@ function texPart(o: Resolved): number {
|
|
|
759
773
|
// reason to install only when tlmgr refuses to add a newly declared package to the old tree.
|
|
760
774
|
if (tree && complete(tree)) {
|
|
761
775
|
o.log(
|
|
762
|
-
`✓ TeX Live ${tree.year} in ${tree.dir} already has all ${n} declared packages — nothing to do`,
|
|
776
|
+
`✓ TeX Live ${tree.year} in ${tree.dir} already has all ${String(n)} declared packages — nothing to do`,
|
|
763
777
|
);
|
|
764
778
|
o.log(binLine(tree));
|
|
765
779
|
return 0;
|
|
766
780
|
}
|
|
767
781
|
o.log(
|
|
768
|
-
`paperlint toolchain: TeX Live with ${n} packages into ${cacheRoot(o.env, o.home)}`,
|
|
782
|
+
`paperlint toolchain: TeX Live with ${String(n)} packages into ${cacheRoot(o.env, o.home)}`,
|
|
769
783
|
);
|
|
770
784
|
return ensureTexLive(o.tex, o).ok ? 0 : 1;
|
|
771
785
|
}
|
package/src/types.ts
CHANGED
|
@@ -12,10 +12,12 @@ import type { RuleBlock } from "./rules-config.ts";
|
|
|
12
12
|
*/
|
|
13
13
|
export interface PaperlintConfig {
|
|
14
14
|
/** The paper director(ies), relative to the project root. Default `papers`. The field name is
|
|
15
|
-
* `PAPERS_DIR_FIELD` in lib/paper-config.mjs; code reads it through `papersDirOf()` in cli.ts.
|
|
16
|
-
|
|
15
|
+
* `PAPERS_DIR_FIELD` in lib/paper-config.mjs; code reads it through `papersDirOf()` in cli.ts.
|
|
16
|
+
* As written in the file: `toPaths` turns a string or a list of strings into directories, and
|
|
17
|
+
* reads anything else as none. */
|
|
18
|
+
papersDir?: unknown;
|
|
17
19
|
/** Which files a paper directory must carry; `false` turns the check off entirely. */
|
|
18
|
-
structure?: StructureConfig | false;
|
|
20
|
+
structure?: StructureConfig | false | undefined;
|
|
19
21
|
/** ESLint config blocks appended after paperlint's own — PARSED by `parseSettings` in cli.ts. */
|
|
20
22
|
rules?: readonly RuleBlock[];
|
|
21
23
|
/** The default venue preset of every paper that names none (`src/paper-settings.ts`). */
|