paperlint 3.1.3 → 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/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
package/src/cli.ts
CHANGED
|
@@ -30,7 +30,7 @@ import { spawnSync } from "node:child_process";
|
|
|
30
30
|
import { fileURLToPath } from "node:url";
|
|
31
31
|
import { join, dirname, resolve, relative, basename, sep } from "node:path";
|
|
32
32
|
import markdown from "@eslint/markdown";
|
|
33
|
-
// Types come from consumer.d.mts beside it
|
|
33
|
+
// Types come from consumer.d.mts beside it.
|
|
34
34
|
import {
|
|
35
35
|
isMain,
|
|
36
36
|
packageVenuesDir,
|
|
@@ -96,15 +96,16 @@ import {
|
|
|
96
96
|
type PaperFormat,
|
|
97
97
|
type VenueSetting,
|
|
98
98
|
} from "./new-paper.ts";
|
|
99
|
-
// The one source for the consumer's config key lives in the
|
|
100
|
-
//
|
|
99
|
+
// The one source for the consumer's config key lives in lib/ (the ESLint rules and the skill scripts
|
|
100
|
+
// import it too). It is imported compiled, from dist/, the one path that resolves the same from src/
|
|
101
|
+
// and from dist/ — see CONTRIBUTING.md.
|
|
101
102
|
import {
|
|
102
103
|
CONFIG_FILE,
|
|
103
104
|
DEFAULT_PAPERS_ROOT,
|
|
104
105
|
PAPERS_DIR_FIELD,
|
|
105
106
|
SETTINGS_KEYS,
|
|
106
107
|
findProjectRoot,
|
|
107
|
-
} from "
|
|
108
|
+
} from "#lib/paper-config";
|
|
108
109
|
import {
|
|
109
110
|
parseRuleBlocks,
|
|
110
111
|
parseRuleEntries,
|
|
@@ -117,22 +118,15 @@ import {
|
|
|
117
118
|
export { init };
|
|
118
119
|
export { nextSteps } from "./init.ts";
|
|
119
120
|
|
|
120
|
-
|
|
121
|
-
import
|
|
122
|
-
|
|
123
|
-
import
|
|
124
|
-
|
|
125
|
-
import
|
|
126
|
-
|
|
127
|
-
import
|
|
128
|
-
|
|
129
|
-
import bibReachable from "../eslint-rules/bib-reachable-entry.mjs";
|
|
130
|
-
// @ts-expect-error — an ESLint rule in .mjs, it has no types
|
|
131
|
-
import reviewFrontmatter from "../eslint-rules/review-frontmatter.mjs";
|
|
132
|
-
// @ts-expect-error — an ESLint rule in .mjs, it has no types
|
|
133
|
-
import siblingFrontmatter from "../eslint-rules/sibling-frontmatter.mjs";
|
|
134
|
-
// @ts-expect-error — an ESLint rule in .mjs, it has no types
|
|
135
|
-
import pdfRules from "../eslint-rules/pdf-last-page-balance.mjs";
|
|
121
|
+
import paperStages from "#eslint-rules/paper-stages";
|
|
122
|
+
import researchQuestion from "#eslint-rules/paper-research-question";
|
|
123
|
+
import typography from "#eslint-rules/paper-typography";
|
|
124
|
+
import texBuild from "#eslint-rules/tex-build";
|
|
125
|
+
import bibReachable from "#eslint-rules/bib-reachable-entry";
|
|
126
|
+
import reviewFrontmatter from "#eslint-rules/review-frontmatter";
|
|
127
|
+
import siblingFrontmatter from "#eslint-rules/sibling-frontmatter";
|
|
128
|
+
import pdfRules from "#eslint-rules/pdf-last-page-balance";
|
|
129
|
+
import { messageOf } from "./domain/text.ts";
|
|
136
130
|
|
|
137
131
|
/** The shipped venue presets, read from the package's venues directory — the one list. */
|
|
138
132
|
const SHIPPED_VENUES = (): string[] => shippedPresets(packageVenuesDir());
|
|
@@ -244,8 +238,7 @@ export function buildConfig(
|
|
|
244
238
|
languageOptions: { frontmatter: "yaml" },
|
|
245
239
|
};
|
|
246
240
|
|
|
247
|
-
|
|
248
|
-
const cfg: any[] = [
|
|
241
|
+
const cfg: unknown[] = [
|
|
249
242
|
// 🔴 THE PROJECT'S PAPER TEMPLATE IS NOT A PAPER. `paperlint new` reads `<papers>/.template/`, and
|
|
250
243
|
// its files carry every marker a paper does. Flat config does NOT ignore dot-directories by
|
|
251
244
|
// default (only `node_modules/` and `.git/`), so without this block `paperlint lint` would lint the
|
|
@@ -392,7 +385,9 @@ export function rulesOff(texLanguage?: unknown): Linter.Config[] {
|
|
|
392
385
|
return [
|
|
393
386
|
{
|
|
394
387
|
name: "paperlint/rules-off",
|
|
395
|
-
plugins: rulePlugins(texLanguage) as
|
|
388
|
+
plugins: rulePlugins(texLanguage) as NonNullable<
|
|
389
|
+
Linter.Config["plugins"]
|
|
390
|
+
>,
|
|
396
391
|
rules: Object.fromEntries([...SHIPPED_RULES].map((id) => [id, "off"])),
|
|
397
392
|
},
|
|
398
393
|
{
|
|
@@ -405,7 +400,7 @@ export function rulesOff(texLanguage?: unknown): Linter.Config[] {
|
|
|
405
400
|
|
|
406
401
|
/** Whether a rule entry (`"error"`, `2`, `["warn", {…}]`) turns the rule on. */
|
|
407
402
|
const isOn = (entry: unknown): boolean => {
|
|
408
|
-
const sev = Array.isArray(entry) ? entry[0] : entry;
|
|
403
|
+
const sev: unknown = Array.isArray(entry) ? entry[0] : entry;
|
|
409
404
|
return sev !== undefined && sev !== "off" && sev !== 0;
|
|
410
405
|
};
|
|
411
406
|
|
|
@@ -470,7 +465,10 @@ export function paperRuleBlocks(
|
|
|
470
465
|
existsSync(p) && statSync(p).isFile() ? dirname(p) : p,
|
|
471
466
|
);
|
|
472
467
|
const papers = [...new Set(dirs.flatMap((p) => [p, ...papersIn(p)]))];
|
|
473
|
-
const out
|
|
468
|
+
const out: { preset: RuleBlock[]; own: RuleBlock[] } = {
|
|
469
|
+
preset: [],
|
|
470
|
+
own: [],
|
|
471
|
+
};
|
|
474
472
|
for (const dir of papers) {
|
|
475
473
|
const p = paperPreset(dir, PRESET_DEPS);
|
|
476
474
|
if (p.kind === "settings-problem")
|
|
@@ -701,8 +699,13 @@ export function ownVersion(
|
|
|
701
699
|
readFileSync(new URL("../package.json", import.meta.url), "utf8"),
|
|
702
700
|
): string | undefined {
|
|
703
701
|
try {
|
|
704
|
-
const
|
|
705
|
-
return typeof
|
|
702
|
+
const manifest: unknown = JSON.parse(readManifest());
|
|
703
|
+
return typeof manifest === "object" &&
|
|
704
|
+
manifest !== null &&
|
|
705
|
+
"version" in manifest &&
|
|
706
|
+
typeof manifest.version === "string"
|
|
707
|
+
? manifest.version
|
|
708
|
+
: undefined;
|
|
706
709
|
} catch {
|
|
707
710
|
return undefined;
|
|
708
711
|
}
|
|
@@ -747,7 +750,7 @@ export function readConfig(
|
|
|
747
750
|
try {
|
|
748
751
|
parsed = JSON.parse(readFileSync(configPath, "utf8"));
|
|
749
752
|
} catch (e) {
|
|
750
|
-
err(`${configPath} is not valid JSON: ${(e
|
|
753
|
+
err(`${configPath} is not valid JSON: ${messageOf(e)}`);
|
|
751
754
|
return { code: 2 };
|
|
752
755
|
}
|
|
753
756
|
// The discovered config is NAMED out loud. Otherwise a run from someone else's directory picks
|
|
@@ -787,7 +790,9 @@ export const papersRoots = (cfg: {
|
|
|
787
790
|
export function toPaths(papers: unknown): string[] {
|
|
788
791
|
if (typeof papers === "string") return papers.trim() ? [papers.trim()] : [];
|
|
789
792
|
if (Array.isArray(papers))
|
|
790
|
-
return papers.filter(
|
|
793
|
+
return papers.filter(
|
|
794
|
+
(x): x is string => typeof x === "string" && x.trim() !== "",
|
|
795
|
+
);
|
|
791
796
|
return [];
|
|
792
797
|
}
|
|
793
798
|
|
|
@@ -1453,8 +1458,7 @@ export async function run(
|
|
|
1453
1458
|
// failing outright — the LaTeX rules simply have no language to run in.
|
|
1454
1459
|
let texLanguage: unknown = null;
|
|
1455
1460
|
try {
|
|
1456
|
-
|
|
1457
|
-
({ texLanguage } = await import("../eslint-rules/latex-language.mjs"));
|
|
1461
|
+
({ texLanguage } = await import("#eslint-rules/latex-language"));
|
|
1458
1462
|
} catch {
|
|
1459
1463
|
texLanguage = null;
|
|
1460
1464
|
}
|
|
@@ -1478,8 +1482,7 @@ export async function run(
|
|
|
1478
1482
|
// reached, which is what the very first run over an empty directory showed: instead of a clear
|
|
1479
1483
|
// message a stack from the depths of eslint-helpers.js flew out. A failure stays a failure, but
|
|
1480
1484
|
// an explicable one.
|
|
1481
|
-
|
|
1482
|
-
let results: any[];
|
|
1485
|
+
let results: ESLint.LintResult[];
|
|
1483
1486
|
try {
|
|
1484
1487
|
results = await eslint.lintFiles(paths);
|
|
1485
1488
|
} catch (e) {
|
|
@@ -1555,8 +1558,7 @@ const isEmptySet = (e: unknown): boolean => {
|
|
|
1555
1558
|
*/
|
|
1556
1559
|
async function reportLint(
|
|
1557
1560
|
eslint: ESLint,
|
|
1558
|
-
|
|
1559
|
-
results: any[],
|
|
1561
|
+
results: ESLint.LintResult[],
|
|
1560
1562
|
structure: ReturnType<typeof checkStructure>,
|
|
1561
1563
|
{
|
|
1562
1564
|
a,
|
|
@@ -1598,7 +1600,7 @@ async function reportLint(
|
|
|
1598
1600
|
out.trim() ||
|
|
1599
1601
|
(structure.length > 0
|
|
1600
1602
|
? ""
|
|
1601
|
-
: `✓ ${results.length} file(s) checked, no findings`),
|
|
1603
|
+
: `✓ ${String(results.length)} file(s) checked, no findings`),
|
|
1602
1604
|
);
|
|
1603
1605
|
}
|
|
1604
1606
|
if (structure.length > 0 || results.some((r) => r.errorCount > 0)) return 1;
|
|
@@ -1608,7 +1610,7 @@ async function reportLint(
|
|
|
1608
1610
|
const warnings = results.reduce((n, r) => n + r.warningCount, 0);
|
|
1609
1611
|
if (warnings > a.maxWarnings) {
|
|
1610
1612
|
err(
|
|
1611
|
-
`${warnings} warning(s) exceed the --max-warnings limit of ${a.maxWarnings}`,
|
|
1613
|
+
`${String(warnings)} warning(s) exceed the --max-warnings limit of ${String(a.maxWarnings)}`,
|
|
1612
1614
|
);
|
|
1613
1615
|
return 1;
|
|
1614
1616
|
}
|
package/src/doctor.harness.mjs
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*
|
|
11
11
|
* Run: npx vigiles test src/doctor.harness.mjs
|
|
12
12
|
*/
|
|
13
|
-
import { PAPERS_DIR_FIELD } from "../lib/paper-config.
|
|
13
|
+
import { PAPERS_DIR_FIELD } from "../lib/paper-config.ts";
|
|
14
14
|
import {
|
|
15
15
|
mkdtempSync,
|
|
16
16
|
mkdirSync,
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
import { tmpdir } from "node:os";
|
|
22
22
|
import { dirname, join } from "node:path";
|
|
23
23
|
import { fileURLToPath } from "node:url";
|
|
24
|
-
import { createChecker } from "../lib/check.
|
|
24
|
+
import { createChecker } from "../lib/check.ts";
|
|
25
25
|
|
|
26
26
|
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
27
27
|
const { doctor, detectPapers, PROGRAMS, found } = await import(
|
|
@@ -279,7 +279,7 @@ const runDoctor = (
|
|
|
279
279
|
|
|
280
280
|
// ── VII-bis. SKILLS THAT ARE NOT LINKED ARE NAMED — AND DO NOT FAIL THE RUN ─────────────────
|
|
281
281
|
// Before this section a consumer without `.claude/skills/` links had no `/paper-pipeline`, and
|
|
282
|
-
// nothing anywhere said so. The link state itself is `link-skills.harness.
|
|
282
|
+
// nothing anywhere said so. The link state itself is `link-skills.harness.ts`'s subject; here
|
|
283
283
|
// only doctor's REPORTING of it is judged, so the state is handed in rather than built on disk.
|
|
284
284
|
{
|
|
285
285
|
const dir = consumer({ papersDir: "papers", declared: "papers" });
|
package/src/doctor.ts
CHANGED
|
@@ -36,6 +36,7 @@ import {
|
|
|
36
36
|
import { PAPER_MARKERS } from "./build.ts";
|
|
37
37
|
import { linkSkills, SKILLS_HOME, type LinkReport } from "./link-skills.ts";
|
|
38
38
|
import { doctorHooks } from "./hooks-settings.ts";
|
|
39
|
+
import { messageOf } from "./domain/text.ts";
|
|
39
40
|
|
|
40
41
|
export interface Program {
|
|
41
42
|
readonly bin: string;
|
|
@@ -169,7 +170,7 @@ function declarationVerdict(raw: string | null): {
|
|
|
169
170
|
} catch (e) {
|
|
170
171
|
return {
|
|
171
172
|
lines: [
|
|
172
|
-
` ✗ ${CONFIG_FILE} is not valid JSON: ${(e
|
|
173
|
+
` ✗ ${CONFIG_FILE} is not valid JSON: ${messageOf(e)}`,
|
|
173
174
|
` the edit guard refuses every Bash command until it parses — fix it with Edit or Write`,
|
|
174
175
|
],
|
|
175
176
|
bad: 1,
|
|
@@ -334,7 +335,7 @@ export function doctor({
|
|
|
334
335
|
try {
|
|
335
336
|
out.push(...doctorHooks(root));
|
|
336
337
|
} catch (e) {
|
|
337
|
-
out.push(`hooks`, ` ⚠ not checked — ${(e
|
|
338
|
+
out.push(`hooks`, ` ⚠ not checked — ${messageOf(e)}`);
|
|
338
339
|
}
|
|
339
340
|
out.push("");
|
|
340
341
|
log(out.join("\n"));
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
* never read as empty.
|
|
32
32
|
*/
|
|
33
33
|
import { err, ok, type Result } from "./result.ts";
|
|
34
|
+
import { messageOf } from "./text.ts";
|
|
34
35
|
|
|
35
36
|
export const LOOKUP_CACHE_SCHEMA = 1;
|
|
36
37
|
|
|
@@ -106,7 +107,7 @@ function sectionOf<T>(
|
|
|
106
107
|
name: string,
|
|
107
108
|
section: unknown,
|
|
108
109
|
known: readonly string[],
|
|
109
|
-
one: (o: Json, at: string) => Result<T, string>,
|
|
110
|
+
one: (o: Json, fetched: string, at: string) => Result<T, string>,
|
|
110
111
|
): Result<Map<string, T>, string> {
|
|
111
112
|
if (!isObject(section)) return err(`\`${name}\`: expected an object`);
|
|
112
113
|
const out = new Map<string, T>();
|
|
@@ -115,18 +116,23 @@ function sectionOf<T>(
|
|
|
115
116
|
if (!isObject(v)) return err(`${at}\`: expected an object`);
|
|
116
117
|
const extra = unknownField(v, known);
|
|
117
118
|
if (extra !== undefined) return err(`${at}\`: unknown field \`${extra}\``);
|
|
118
|
-
|
|
119
|
+
const fetched = v["fetched"];
|
|
120
|
+
if (!isDate(fetched))
|
|
119
121
|
return err(`${at}.fetched\`: expected a date, YYYY-MM-DD`);
|
|
120
|
-
const r = one(v, at);
|
|
122
|
+
const r = one(v, fetched, at);
|
|
121
123
|
if (!r.ok) return r;
|
|
122
124
|
out.set(key, r.value);
|
|
123
125
|
}
|
|
124
126
|
return ok(out);
|
|
125
127
|
}
|
|
126
128
|
|
|
127
|
-
const cachedResponse = (
|
|
129
|
+
const cachedResponse = (
|
|
130
|
+
o: Json,
|
|
131
|
+
fetched: string,
|
|
132
|
+
at: string,
|
|
133
|
+
): Result<CachedResponse, string> =>
|
|
128
134
|
isObject(o["response"]) && o["response"]["transport"] === "ok"
|
|
129
|
-
? ok({ fetched
|
|
135
|
+
? ok({ fetched, response: o["response"] })
|
|
130
136
|
: err(
|
|
131
137
|
`${at}.response\`: expected a successful response ({"transport": "ok", …})`,
|
|
132
138
|
);
|
|
@@ -137,7 +143,11 @@ const isHit = (h: unknown): h is DblpHit =>
|
|
|
137
143
|
Array.isArray(h["authors"]) &&
|
|
138
144
|
h["authors"].every((a) => typeof a === "string");
|
|
139
145
|
|
|
140
|
-
function cachedDblp(
|
|
146
|
+
function cachedDblp(
|
|
147
|
+
o: Json,
|
|
148
|
+
fetched: string,
|
|
149
|
+
at: string,
|
|
150
|
+
): Result<CachedDblp, string> {
|
|
141
151
|
const { title, hits } = o;
|
|
142
152
|
if (typeof title !== "string") return err(`${at}.title\`: expected a string`);
|
|
143
153
|
if (!Array.isArray(hits)) return err(`${at}.hits\`: expected an array`);
|
|
@@ -147,9 +157,9 @@ function cachedDblp(o: Json, at: string): Result<CachedDblp, string> {
|
|
|
147
157
|
`${at}.hits[${String(bad)}]\`: expected {venue, year, type, title: string; authors: string[]}`,
|
|
148
158
|
);
|
|
149
159
|
return ok({
|
|
150
|
-
fetched
|
|
160
|
+
fetched,
|
|
151
161
|
title,
|
|
152
|
-
hits: hits
|
|
162
|
+
hits: hits.filter(isHit),
|
|
153
163
|
});
|
|
154
164
|
}
|
|
155
165
|
|
|
@@ -159,7 +169,7 @@ export function parseLookupCache(text: string): Result<LookupCache, string> {
|
|
|
159
169
|
try {
|
|
160
170
|
json = JSON.parse(text);
|
|
161
171
|
} catch (e) {
|
|
162
|
-
return err(`not JSON: ${(e
|
|
172
|
+
return err(`not JSON: ${messageOf(e)}`);
|
|
163
173
|
}
|
|
164
174
|
if (!isObject(json))
|
|
165
175
|
return err("expected an object with `schema`, `citations` and `dblp`");
|
|
@@ -186,8 +196,8 @@ export function parseLookupCache(text: string): Result<LookupCache, string> {
|
|
|
186
196
|
return ok({ citations: citations.value, dblp: dblp.value });
|
|
187
197
|
}
|
|
188
198
|
|
|
189
|
-
const sorted = <T>(m: ReadonlyMap<string, T>): Record<string, T> =>
|
|
190
|
-
Object.fromEntries([...m.keys()].sort().map((k) => [k, m.get(k)
|
|
199
|
+
const sorted = <T>(m: ReadonlyMap<string, T>): Record<string, T | undefined> =>
|
|
200
|
+
Object.fromEntries([...m.keys()].sort().map((k) => [k, m.get(k)]));
|
|
191
201
|
|
|
192
202
|
/** The cache as the file holds it: keys sorted, so one new answer is a small diff. */
|
|
193
203
|
export const serializeLookupCache = (c: LookupCache): string =>
|
|
@@ -3,7 +3,7 @@ import { test } from "vitest";
|
|
|
3
3
|
import { andThen, err, map, match, ok, type Result } from "./result.ts";
|
|
4
4
|
|
|
5
5
|
const half = (n: number): Result<number, string> =>
|
|
6
|
-
n % 2 === 0 ? ok(n / 2) : err(`${n} is odd`);
|
|
6
|
+
n % 2 === 0 ? ok(n / 2) : err(`${String(n)} is odd`);
|
|
7
7
|
|
|
8
8
|
test("map and andThen run on ok and pass an error through untouched", () => {
|
|
9
9
|
assert.deepEqual(
|
|
@@ -24,7 +24,7 @@ test("map and andThen run on ok and pass an error through untouched", () => {
|
|
|
24
24
|
|
|
25
25
|
test("match picks the branch by `ok`", () => {
|
|
26
26
|
const say = (r: Result<number, string>) =>
|
|
27
|
-
match(r, { ok: (n) => `got ${n}`, err: (e) => `no: ${e}` });
|
|
27
|
+
match(r, { ok: (n) => `got ${String(n)}`, err: (e) => `no: ${e}` });
|
|
28
28
|
assert.equal(say(half(4)), "got 2");
|
|
29
29
|
assert.equal(say(half(5)), "no: 5 is odd");
|
|
30
30
|
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { test } from "vitest";
|
|
3
|
+
import { codeOf, firstLine, messageOf, printed } from "./text.ts";
|
|
4
|
+
|
|
5
|
+
test("messageOf: an Error's message, and anything else thrown as its text", () => {
|
|
6
|
+
assert.equal(messageOf(new Error("boom")), "boom");
|
|
7
|
+
// `throw "x"` and `throw 3` are legal JavaScript; `(e as Error).message` read them as undefined.
|
|
8
|
+
assert.equal(messageOf("plain string"), "plain string");
|
|
9
|
+
assert.equal(messageOf(3), "3");
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
test("codeOf: a string `code` only", () => {
|
|
13
|
+
assert.equal(
|
|
14
|
+
codeOf(Object.assign(new Error("x"), { code: "ENOENT" })),
|
|
15
|
+
"ENOENT",
|
|
16
|
+
);
|
|
17
|
+
assert.equal(codeOf(new Error("no code")), undefined);
|
|
18
|
+
assert.equal(codeOf({ code: 3 }), undefined);
|
|
19
|
+
assert.equal(codeOf(null), undefined);
|
|
20
|
+
assert.equal(codeOf("ENOENT"), undefined);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test("printed: a stream a failed spawn left undefined reads as empty text", () => {
|
|
24
|
+
assert.equal(printed(undefined), "");
|
|
25
|
+
assert.equal(printed(null), "");
|
|
26
|
+
assert.equal(printed("out"), "out");
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test("firstLine: the first non-blank line, trimmed", () => {
|
|
30
|
+
assert.equal(firstLine("\n \n first \nsecond"), "first");
|
|
31
|
+
assert.equal(firstLine(""), "");
|
|
32
|
+
});
|
package/src/domain/text.ts
CHANGED
|
@@ -9,3 +9,26 @@ export const firstLine = (s: string): string =>
|
|
|
9
9
|
.split("\n")
|
|
10
10
|
.map((l) => l.trim())
|
|
11
11
|
.find(Boolean) ?? "";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* What a process printed on one stream, as text. Node types `spawnSync(…, { encoding })`'s
|
|
15
|
+
* `stdout`/`stderr` as `string`, but both are `undefined` when the spawn itself failed (measured:
|
|
16
|
+
* `spawnSync("no-such-program", [], { encoding: "utf8" }).stdout` is `undefined`). The parameter
|
|
17
|
+
* takes the stream as it really arrives, so the fallback guards a real case instead of reading
|
|
18
|
+
* as dead code against a type that lies.
|
|
19
|
+
*/
|
|
20
|
+
export const printed = (stream: string | null | undefined): string =>
|
|
21
|
+
stream ?? "";
|
|
22
|
+
|
|
23
|
+
/** What a caught value says: an `Error`'s message, anything else as text (`catch` gets `unknown`). */
|
|
24
|
+
export const messageOf = (e: unknown): string =>
|
|
25
|
+
e instanceof Error ? e.message : String(e);
|
|
26
|
+
|
|
27
|
+
/** The `code` a Node error carries (`ENOENT`, `EACCES`, …), when it carries a string one. */
|
|
28
|
+
export const codeOf = (e: unknown): string | undefined =>
|
|
29
|
+
typeof e === "object" &&
|
|
30
|
+
e !== null &&
|
|
31
|
+
"code" in e &&
|
|
32
|
+
typeof e.code === "string"
|
|
33
|
+
? e.code
|
|
34
|
+
: undefined;
|
package/src/engine.harness.mjs
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* 1. `resolveEngine` over `EngineFacts` — one row per branch of the order;
|
|
6
6
|
* 2. the fact readers: `missingPackages` over kpsewhich output, `missingTools`, `whichOnPath`,
|
|
7
7
|
* `probeTree` through a fake runner.
|
|
8
|
-
* All pure or port-driven: no TeX needed. The real-TeX half is `test/e2e/build.
|
|
8
|
+
* All pure or port-driven: no TeX needed. The real-TeX half is `test/e2e/build.ts`.
|
|
9
9
|
*/
|
|
10
10
|
import {
|
|
11
11
|
chmodSync,
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
import { tmpdir } from "node:os";
|
|
19
19
|
import { dirname, join } from "node:path";
|
|
20
20
|
import { fileURLToPath } from "node:url";
|
|
21
|
-
import { createChecker } from "../lib/check.
|
|
21
|
+
import { createChecker } from "../lib/check.ts";
|
|
22
22
|
|
|
23
23
|
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
24
24
|
const {
|
package/src/engine.ts
CHANGED
|
@@ -24,6 +24,7 @@ import { spawnSync } from "node:child_process";
|
|
|
24
24
|
import { accessSync, constants, statSync } from "node:fs";
|
|
25
25
|
import { basename, delimiter, join } from "node:path";
|
|
26
26
|
import type { TexRequirements } from "./tex-requirements.ts";
|
|
27
|
+
import { printed } from "./domain/text.ts";
|
|
27
28
|
|
|
28
29
|
/** A process runner with `spawnSync`'s shape — the port the harness replaces. */
|
|
29
30
|
export type Runner = typeof spawnSync;
|
|
@@ -161,7 +162,7 @@ export function probeTree(
|
|
|
161
162
|
stdio: ["ignore", "pipe", "pipe"],
|
|
162
163
|
});
|
|
163
164
|
if (r.error) return Object.keys(packages).sort();
|
|
164
|
-
return missingPackages(packages,
|
|
165
|
+
return missingPackages(packages, printed(r.stdout));
|
|
165
166
|
}
|
|
166
167
|
|
|
167
168
|
/**
|
|
@@ -181,7 +182,7 @@ export function missingDependencies(
|
|
|
181
182
|
stdio: ["ignore", "pipe", "pipe"],
|
|
182
183
|
});
|
|
183
184
|
if (r.error) return [];
|
|
184
|
-
const lines =
|
|
185
|
+
const lines = printed(r.stdout).split("\n");
|
|
185
186
|
const start = lines.findIndex(
|
|
186
187
|
(l) => l.trim() === "DEPENDS WITHOUT PACKAGES:",
|
|
187
188
|
);
|
|
@@ -193,7 +194,7 @@ export function missingDependencies(
|
|
|
193
194
|
return [
|
|
194
195
|
...new Set(
|
|
195
196
|
(end < 0 ? section : section.slice(0, end)).map((l) =>
|
|
196
|
-
l.
|
|
197
|
+
l.replace(/ in: [\s\S]*/, "").trim(),
|
|
197
198
|
),
|
|
198
199
|
),
|
|
199
200
|
].sort();
|
package/src/facts-file.test.ts
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* The document is assembled from hand-made measurements (pure), and `measurePaper` runs on
|
|
5
5
|
* in-memory files with a FAKE pdf.js reader and a FAKE measurer, so each outcome — read failed, not
|
|
6
6
|
* measured, measured — is chosen rather than hoped for. Reading real PDFs is
|
|
7
|
-
* `pdf-facts.harness.
|
|
8
|
-
* real banal is `test/e2e/banal.
|
|
7
|
+
* `pdf-facts.harness.ts`'s job; banal as the measurer is `adapters/banal/index.test.ts`, and the
|
|
8
|
+
* real banal is `test/e2e/banal.ts`.
|
|
9
9
|
*/
|
|
10
10
|
import assert from "node:assert/strict";
|
|
11
11
|
import { readdirSync, readFileSync } from "node:fs";
|
|
@@ -147,10 +147,11 @@ test("🔴 geometry_source and the nine columns come from ONE branch", () => {
|
|
|
147
147
|
const PAPER = "/r/papers/p";
|
|
148
148
|
const PDF = `${PAPER}/paper.pdf`;
|
|
149
149
|
const PDF_BYTES = "%PDF-pretend";
|
|
150
|
-
const good: PdfReader =
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
}
|
|
150
|
+
const good: PdfReader = () =>
|
|
151
|
+
Promise.resolve({
|
|
152
|
+
ok: true,
|
|
153
|
+
facts: { pages: 2, fonts: FONTS, last: lastPage(60, 60), layout: [] },
|
|
154
|
+
});
|
|
154
155
|
/** The shipped presets at their real paths: `extends` resolves through the same Files port. */
|
|
155
156
|
const SHIPPED_PRESETS = Object.fromEntries(
|
|
156
157
|
readdirSync(packageVenuesDir())
|
|
@@ -232,7 +233,8 @@ test("a failed read is the one error line, and nothing is written", async () =>
|
|
|
232
233
|
const before = files.map.size;
|
|
233
234
|
const m = await measurePaper(PAPER, PDF, {
|
|
234
235
|
...o,
|
|
235
|
-
readPdf:
|
|
236
|
+
readPdf: () =>
|
|
237
|
+
Promise.resolve({ ok: false, reason: "unreadable", detail: "boom" }),
|
|
236
238
|
});
|
|
237
239
|
assert.match(!m.ok ? m.error : "", /pdf\.js \(unreadable\): boom/);
|
|
238
240
|
assert.equal(files.map.size, before);
|
package/src/facts-file.ts
CHANGED
|
@@ -50,6 +50,7 @@ import type { Files } from "./ports/files.ts";
|
|
|
50
50
|
import { err, ok, type Result } from "./domain/result.ts";
|
|
51
51
|
import { paperPreset, paperPresetProblem } from "./presets.ts";
|
|
52
52
|
import { packageVenuesDir } from "../skills/paper-pipeline/scripts/consumer.mjs";
|
|
53
|
+
import { messageOf } from "./domain/text.ts";
|
|
53
54
|
|
|
54
55
|
export const FACTS_SCHEMA = 2;
|
|
55
56
|
export const FACTS_DIR = "_build";
|
|
@@ -338,7 +339,7 @@ export function parseFactsText(text: string): Result<ReadFacts, FactsProblem> {
|
|
|
338
339
|
try {
|
|
339
340
|
d = JSON.parse(text);
|
|
340
341
|
} catch (e) {
|
|
341
|
-
return err({ kind: "broken", why: `not JSON (${(e
|
|
342
|
+
return err({ kind: "broken", why: `not JSON (${messageOf(e)})` });
|
|
342
343
|
}
|
|
343
344
|
if (!isRecord(d)) return err({ kind: "broken", why: "not a JSON object" });
|
|
344
345
|
if (d["schema"] !== FACTS_SCHEMA)
|