paperlint 3.1.2 → 3.2.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 +3 -3
- package/CONTRIBUTING.md +34 -5
- package/dist/adapters/banal/index.d.ts.map +1 -1
- package/dist/adapters/banal/index.js +9 -5
- package/dist/adapters/banal/index.js.map +1 -1
- package/dist/adapters/banal/invocation.d.ts +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 +0 -5
- 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/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 +4 -5
- 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.js +2 -2
- package/dist/build-engine.js.map +1 -1
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +14 -11
- package/dist/build.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +31 -34
- package/dist/cli.js.map +1 -1
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +3 -2
- 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/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.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 +2 -1
- 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 +14 -9
- package/dist/hooks-settings.js.map +1 -1
- package/dist/init.d.ts +5 -5
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +15 -7
- 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 +142 -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 +2 -2
- package/dist/new-paper.js.map +1 -1
- package/dist/paper-settings.d.ts.map +1 -1
- package/dist/paper-settings.js +5 -4
- package/dist/paper-settings.js.map +1 -1
- package/dist/pdf-facts.d.ts.map +1 -1
- package/dist/pdf-facts.js +2 -1
- package/dist/pdf-facts.js.map +1 -1
- package/dist/pdf-geometry.d.ts.map +1 -1
- package/dist/pdf-geometry.js +1 -1
- package/dist/pdf-geometry.js.map +1 -1
- package/dist/presets.d.ts.map +1 -1
- package/dist/presets.js +3 -2
- package/dist/presets.js.map +1 -1
- package/dist/references.d.ts.map +1 -1
- package/dist/references.js +11 -6
- package/dist/references.js.map +1 -1
- package/dist/rules-config.d.ts.map +1 -1
- package/dist/rules-config.js +6 -3
- 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.map +1 -1
- package/dist/tex-requirements.js +8 -3
- 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/venue-rules.js +1 -1
- package/dist/venue-rules.js.map +1 -1
- 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} +4 -3
- package/eslint-rules/install-path-literals.harness.mjs +1 -1
- package/eslint-rules/{install-path-literals.mjs → install-path-literals.ts} +16 -8
- 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} +34 -15
- 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} +74 -29
- package/eslint-rules/paper-typography.test.mjs +3 -3
- package/eslint-rules/{paper-typography.mjs → paper-typography.ts} +132 -54
- 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} +88 -31
- package/eslint-rules/review-frontmatter.test.mjs +2 -2
- package/eslint-rules/{review-frontmatter.mjs → review-frontmatter.ts} +37 -15
- 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} +19 -6
- package/eslint-rules/tex-build.harness.mjs +2 -2
- package/eslint-rules/{tex-build.mjs → tex-build.ts} +4 -3
- package/eslint.config.mjs +139 -30
- 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.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 +8 -8
- package/lib/{paper-config.mjs → paper-config.ts} +19 -14
- package/lib/skill-checks.mjs +1 -1
- package/lib/skill-checks.test.mjs +1 -1
- package/lib/skill-corpus.mjs +1 -1
- package/lib/skill-eval-kit.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 -37
- package/scripts/eslint-report-guard.test.mjs +1 -1
- package/scripts/harness-api.frozen.json +14 -15
- 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/grade-paper-writing/prose-lint.mjs +1 -1
- package/skills/grade-paper-writing/{prose-lint.test.mjs → prose-lint.test.ts} +2 -2
- 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 +1 -1
- package/skills/paper-pipeline/pipeline-firing.eval.mjs +1 -1
- package/skills/paper-pipeline/pipeline-language.eval.mjs +1 -1
- package/skills/paper-pipeline/scripts/README.md +1 -1
- package/skills/paper-pipeline/scripts/announce.test.mjs +1 -1
- 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.mjs +1 -5
- 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/fixtures/{scorecard.mjs → scorecard.ts} +36 -7
- package/skills/paper-pipeline/scripts/{generated-code.test.mjs → generated-code.test.ts} +3 -3
- package/skills/paper-pipeline/scripts/ledger.cli.test.mjs +1 -1
- package/skills/paper-pipeline/scripts/pipeline-check.cli.test.mjs +2 -2
- package/skills/paper-pipeline/scripts/pipeline-check.harness.mjs +2 -2
- package/skills/paper-pipeline/scripts/pipeline-check.mjs +1 -4
- 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-pipeline/scripts/run-mechanical.test.mjs +1 -1
- package/skills/paper-pipeline/scripts/status.test.mjs +1 -1
- 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/{extract-pdf-facts.harness.mjs → extract-pdf-facts.harness.ts} +34 -9
- package/skills/render-paper/render-paper.harness.mjs +2 -2
- package/skills/tighten-paper/structure.mjs +1 -1
- package/skills/tighten-paper/{structure.test.mjs → structure.test.ts} +4 -3
- 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/skills/verify-citations/scripts/verify-cites.mjs +11 -1
- package/skills/verify-citations/scripts/verify-cites.net.test.mjs +35 -0
- package/skills/verify-citations/scripts/verify-cites.test.mjs +14 -0
- package/src/CLAUDE.md +1 -1
- package/src/adapters/banal/index.test.ts +3 -6
- package/src/adapters/banal/index.ts +7 -4
- package/src/adapters/banal/invocation.test.ts +3 -1
- package/src/adapters/banal/invocation.ts +1 -1
- package/src/adapters/banal/output.test.ts +1 -1
- package/src/adapters/banal/run.test.ts +3 -3
- package/src/adapters/banal/xml.test.ts +1 -1
- package/src/adapters/curl/download.test.ts +4 -2
- package/src/adapters/node/files.io.ts +2 -2
- package/src/adapters/node/files.test.ts +3 -1
- package/src/adapters/node/process.io.ts +4 -3
- package/src/adapters/node/process.test.ts +1 -1
- 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 +26 -58
- 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 +2 -2
- package/src/build-engine.ts +2 -2
- package/src/build.harness.mjs +2 -2
- package/src/build.test.ts +15 -14
- package/src/build.ts +28 -19
- package/src/cli.harness.mjs +6 -6
- package/src/cli.test.ts +13 -6
- package/src/cli.ts +39 -37
- package/src/doctor.harness.mjs +3 -3
- package/src/doctor.ts +3 -2
- package/src/domain/lookup-cache.ts +21 -11
- package/src/domain/result.test.ts +2 -2
- 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 +4 -3
- package/src/facts-file.test.ts +9 -7
- package/src/facts-file.ts +2 -1
- package/src/{hooks-settings.harness.mjs → hooks-settings.harness.ts} +39 -20
- package/src/hooks-settings.ts +20 -9
- package/src/init.test.ts +12 -9
- package/src/init.ts +22 -12
- 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 +2 -2
- package/src/new-paper.test.ts +8 -10
- package/src/new-paper.ts +2 -2
- package/src/paper-files.test.ts +3 -5
- package/src/paper-settings-commands.test.ts +5 -4
- package/src/paper-settings.test.ts +5 -5
- package/src/paper-settings.ts +8 -9
- package/src/{pdf-facts.harness.mjs → pdf-facts.harness.ts} +9 -8
- package/src/pdf-facts.test.ts +10 -11
- package/src/pdf-facts.ts +2 -1
- package/src/{pdf-geometry.harness.mjs → pdf-geometry.harness.ts} +19 -12
- package/src/pdf-geometry.ts +3 -1
- package/src/presets.ts +3 -2
- package/src/references.test.ts +51 -43
- package/src/references.ts +14 -7
- package/src/{rules-config.harness.mjs → rules-config.harness.ts} +7 -13
- package/src/rules-config.ts +7 -4
- 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.ts +8 -5
- package/src/toolchain.harness.mjs +2 -2
- package/src/toolchain.test.ts +1 -1
- package/src/toolchain.ts +31 -17
- package/src/venue-rules.test.ts +62 -64
- package/src/venue-rules.ts +1 -1
- 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/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/osf-artifact-upload/{osf-artifact-upload.harness.mjs → osf-artifact-upload.harness.ts} +0 -0
- /package/skills/tighten-paper/__snapshots__/{structure.test.mjs.snap → structure.test.ts.snap} +0 -0
|
@@ -15,18 +15,27 @@ import {
|
|
|
15
15
|
} from "node:fs";
|
|
16
16
|
import { tmpdir } from "node:os";
|
|
17
17
|
import { join, dirname } from "node:path";
|
|
18
|
-
import {
|
|
19
|
-
import { createChecker } from "../lib/check.
|
|
18
|
+
import { z } from "zod";
|
|
19
|
+
import { createChecker } from "../lib/check.ts";
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
/** `asEslintResults` promises only `unknown[]`; these are the fields the checks read. */
|
|
22
|
+
const EslintResults = z.array(
|
|
23
|
+
z.object({
|
|
24
|
+
errorCount: z.number(),
|
|
25
|
+
warningCount: z.number(),
|
|
26
|
+
messages: z.array(
|
|
27
|
+
z.object({ ruleId: z.string().nullable(), severity: z.number() }),
|
|
28
|
+
),
|
|
29
|
+
}),
|
|
30
|
+
);
|
|
22
31
|
const { checkStructure, formatStructure, asEslintResults, STRUCTURE_DEFAULTS } =
|
|
23
|
-
await import(
|
|
32
|
+
await import("./structure.ts");
|
|
24
33
|
|
|
25
34
|
const check = createChecker();
|
|
26
35
|
|
|
27
36
|
const root = realpathSync(mkdtempSync(join(tmpdir(), "paperlint-struct-")));
|
|
28
37
|
const papers = join(root, "papers");
|
|
29
|
-
const paper = (name, files) => {
|
|
38
|
+
const paper = (name: string, files: readonly string[]) => {
|
|
30
39
|
const dir = join(papers, name);
|
|
31
40
|
mkdirSync(dir, { recursive: true });
|
|
32
41
|
for (const f of files) {
|
|
@@ -50,7 +59,7 @@ try {
|
|
|
50
59
|
writeFileSync(join(papers, ".hidden", "paper.tex"), "x");
|
|
51
60
|
|
|
52
61
|
const f = checkStructure([papers], undefined, { cwd: root });
|
|
53
|
-
const at = (name) => f.filter((x) => x.file.endsWith(name));
|
|
62
|
+
const at = (name: string) => f.filter((x) => x.file.endsWith(name));
|
|
54
63
|
|
|
55
64
|
check(
|
|
56
65
|
"a complete paper directory — NOT A SINGLE finding",
|
|
@@ -63,24 +72,26 @@ try {
|
|
|
63
72
|
check(
|
|
64
73
|
"a missing scorecard — a finding",
|
|
65
74
|
at("no-scorecard").length === 1 &&
|
|
66
|
-
/missing `PIPELINE-STATUS\.md`/.test(
|
|
75
|
+
/missing `PIPELINE-STATUS\.md`/.test(
|
|
76
|
+
at("no-scorecard")[0]?.message ?? "",
|
|
77
|
+
),
|
|
67
78
|
);
|
|
68
79
|
check(
|
|
69
80
|
"and the message names the CONSEQUENCE, not a restatement of the condition",
|
|
70
|
-
/are skipped/.test(at("no-scorecard")[0]
|
|
81
|
+
/are skipped/.test(at("no-scorecard")[0]?.message ?? "") &&
|
|
71
82
|
/stage, source and research-question checks/.test(
|
|
72
|
-
at("no-scorecard")[0]
|
|
83
|
+
at("no-scorecard")[0]?.message ?? "",
|
|
73
84
|
),
|
|
74
85
|
);
|
|
75
86
|
check(
|
|
76
87
|
"and the consequence names THIS directory by name",
|
|
77
|
-
/no-scorecard/.test(at("no-scorecard")[0]
|
|
88
|
+
/no-scorecard/.test(at("no-scorecard")[0]?.message ?? ""),
|
|
78
89
|
);
|
|
79
90
|
check(
|
|
80
91
|
"a directory with no source — a finding, and BOTH accepted forms are listed",
|
|
81
92
|
at("no-source").length === 1 &&
|
|
82
|
-
/`paper\.tex`/.test(at("no-source")[0]
|
|
83
|
-
/`paper\.md`/.test(at("no-source")[0]
|
|
93
|
+
/`paper\.tex`/.test(at("no-source")[0]?.message ?? "") &&
|
|
94
|
+
/`paper\.md`/.test(at("no-source")[0]?.message ?? ""),
|
|
84
95
|
);
|
|
85
96
|
|
|
86
97
|
// 🔴 THE PAIRED HALF: detection is GENEROUS. Without this the check would scream about every
|
|
@@ -136,7 +147,7 @@ try {
|
|
|
136
147
|
);
|
|
137
148
|
|
|
138
149
|
// ── one schema for both halves ────────────────────────────────────────────────────────
|
|
139
|
-
const asResults = asEslintResults(f);
|
|
150
|
+
const asResults = EslintResults.parse(asEslintResults(f));
|
|
140
151
|
check(
|
|
141
152
|
"findings come back shaped like an ESLint result — `--json` stays one array",
|
|
142
153
|
asResults.length === 2 &&
|
|
@@ -144,7 +155,7 @@ try {
|
|
|
144
155
|
(r) =>
|
|
145
156
|
r.errorCount === 1 &&
|
|
146
157
|
r.warningCount === 0 &&
|
|
147
|
-
r.messages[0]
|
|
158
|
+
r.messages[0]?.ruleId === "structure/required-file" &&
|
|
148
159
|
r.messages[0].severity === 2,
|
|
149
160
|
),
|
|
150
161
|
);
|
|
@@ -156,7 +167,7 @@ try {
|
|
|
156
167
|
{ require: ["PIPELINE-STATUS.md", "refs.bib"] },
|
|
157
168
|
{ cwd: root },
|
|
158
169
|
).filter((x) => x.file.endsWith("no-source"));
|
|
159
|
-
return asEslintResults(two)[0]
|
|
170
|
+
return EslintResults.parse(asEslintResults(two))[0]?.errorCount === 2;
|
|
160
171
|
})(),
|
|
161
172
|
);
|
|
162
173
|
check(
|
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`);
|
package/src/tex-requirements.ts
CHANGED
|
@@ -26,7 +26,7 @@ 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
30
|
|
|
31
31
|
/** CTAN package name → the names that prove it is installed. */
|
|
32
32
|
export type PackageProofs = Readonly<Record<string, readonly string[]>>;
|
|
@@ -64,9 +64,10 @@ const validators = new Map<string, Validate>();
|
|
|
64
64
|
function validatorFor(dir: string): Validate {
|
|
65
65
|
const known = validators.get(dir);
|
|
66
66
|
if (known) return known;
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
)
|
|
67
|
+
const path = join(dir, SCHEMA_FILE);
|
|
68
|
+
const schema: unknown = JSON.parse(readFileSync(path, "utf8"));
|
|
69
|
+
if (typeof schema !== "object" || schema === null)
|
|
70
|
+
throw new Error(`${path}: not a JSON Schema object`);
|
|
70
71
|
const v = new Ajv({ allErrors: true }).compile(schema);
|
|
71
72
|
validators.set(dir, v);
|
|
72
73
|
return v;
|
|
@@ -214,7 +215,9 @@ export function parsePreset(
|
|
|
214
215
|
file: string,
|
|
215
216
|
dir: string = packageVenuesDir(),
|
|
216
217
|
): PresetFile {
|
|
217
|
-
const
|
|
218
|
+
const parsed = typescript().parseConfigFileTextToJson(file, text);
|
|
219
|
+
const config: unknown = parsed.config;
|
|
220
|
+
const error = parsed.error;
|
|
218
221
|
if (error)
|
|
219
222
|
throw new Error(
|
|
220
223
|
`${file}: not valid JSONC — ${typescript().flattenDiagnosticMessageText(error.messageText, " ")}`,
|
|
@@ -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,
|
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
|
}
|