paperlint 3.1.0 → 3.1.1

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.
Files changed (284) hide show
  1. package/.github/workflows/ci.yml +28 -41
  2. package/.github/workflows/dependabot-automerge.yml +1 -1
  3. package/CLAUDE.md +51 -56
  4. package/CONTRIBUTING.md +30 -18
  5. package/bin/paperlint.test.mjs +45 -0
  6. package/dist/adapters/node/files.io.d.ts +2 -0
  7. package/dist/adapters/node/files.io.d.ts.map +1 -1
  8. package/dist/adapters/node/files.io.js +3 -2
  9. package/dist/adapters/node/files.io.js.map +1 -1
  10. package/dist/adapters/pdfjs/fill.d.ts +15 -4
  11. package/dist/adapters/pdfjs/fill.d.ts.map +1 -1
  12. package/dist/adapters/pdfjs/fill.js +31 -21
  13. package/dist/adapters/pdfjs/fill.js.map +1 -1
  14. package/dist/adapters/references/index.d.ts.map +1 -1
  15. package/dist/adapters/references/index.js +14 -5
  16. package/dist/adapters/references/index.js.map +1 -1
  17. package/dist/adapters/references/pool.d.ts +8 -0
  18. package/dist/adapters/references/pool.d.ts.map +1 -0
  19. package/dist/adapters/references/pool.js +19 -0
  20. package/dist/adapters/references/pool.js.map +1 -0
  21. package/dist/build.d.ts +10 -2
  22. package/dist/build.d.ts.map +1 -1
  23. package/dist/build.js +7 -8
  24. package/dist/build.js.map +1 -1
  25. package/dist/cli.d.ts +27 -1
  26. package/dist/cli.d.ts.map +1 -1
  27. package/dist/cli.js +71 -55
  28. package/dist/cli.js.map +1 -1
  29. package/dist/doctor.d.ts +27 -1
  30. package/dist/doctor.d.ts.map +1 -1
  31. package/dist/doctor.js +4 -3
  32. package/dist/doctor.js.map +1 -1
  33. package/dist/domain/result.d.ts +0 -2
  34. package/dist/domain/result.d.ts.map +1 -1
  35. package/dist/domain/result.js +0 -4
  36. package/dist/domain/result.js.map +1 -1
  37. package/dist/hooks-settings.d.ts +8 -5
  38. package/dist/hooks-settings.d.ts.map +1 -1
  39. package/dist/hooks-settings.js +32 -32
  40. package/dist/hooks-settings.js.map +1 -1
  41. package/dist/init.d.ts +8 -0
  42. package/dist/init.d.ts.map +1 -1
  43. package/dist/init.js +3 -3
  44. package/dist/init.js.map +1 -1
  45. package/dist/latex-log.d.ts +0 -2
  46. package/dist/latex-log.d.ts.map +1 -1
  47. package/dist/latex-log.js +7 -13
  48. package/dist/latex-log.js.map +1 -1
  49. package/dist/link-skills.d.ts +15 -2
  50. package/dist/link-skills.d.ts.map +1 -1
  51. package/dist/link-skills.js +36 -20
  52. package/dist/link-skills.js.map +1 -1
  53. package/dist/paper-files.d.ts.map +1 -1
  54. package/dist/paper-files.js +6 -4
  55. package/dist/paper-files.js.map +1 -1
  56. package/dist/pdf-facts.d.ts +11 -0
  57. package/dist/pdf-facts.d.ts.map +1 -1
  58. package/dist/pdf-facts.js +16 -18
  59. package/dist/pdf-facts.js.map +1 -1
  60. package/dist/pdf-geometry.js +1 -1
  61. package/dist/pdf-geometry.js.map +1 -1
  62. package/dist/presets.d.ts +2 -0
  63. package/dist/presets.d.ts.map +1 -1
  64. package/dist/presets.js +3 -1
  65. package/dist/presets.js.map +1 -1
  66. package/dist/references.js +2 -2
  67. package/dist/references.js.map +1 -1
  68. package/dist/tex-requirements.d.ts +8 -0
  69. package/dist/tex-requirements.d.ts.map +1 -1
  70. package/dist/tex-requirements.js +6 -5
  71. package/dist/tex-requirements.js.map +1 -1
  72. package/dist/toolchain.d.ts +3 -2
  73. package/dist/toolchain.d.ts.map +1 -1
  74. package/dist/toolchain.js +4 -5
  75. package/dist/toolchain.js.map +1 -1
  76. package/dist/venue-rules.d.ts.map +1 -1
  77. package/dist/venue-rules.js +11 -9
  78. package/dist/venue-rules.js.map +1 -1
  79. package/docs/prior-art/README.md +1 -1
  80. package/docs/prior-art/test-tooling.md +7 -30
  81. package/eslint-rules/install-path-literals.harness.mjs +17 -1
  82. package/eslint-rules/latex-language.harness.mjs +3 -3
  83. package/eslint-rules/latex-language.mjs +12 -9
  84. package/eslint-rules/latex-language.test.mjs +200 -0
  85. package/eslint-rules/paper-research-question.harness.mjs +73 -7
  86. package/eslint-rules/paper-stages.harness.mjs +9 -14
  87. package/eslint-rules/paper-stages.test.mjs +135 -0
  88. package/eslint-rules/paper-typography.mjs +9 -2
  89. package/eslint-rules/paper-typography.test.mjs +146 -1
  90. package/eslint-rules/pdf-last-page-balance.harness.mjs +63 -7
  91. package/eslint-rules/review-frontmatter.mjs +2 -1
  92. package/eslint-rules/review-frontmatter.test.mjs +37 -1
  93. package/eslint-rules/temp-root-realpath.harness.mjs +49 -0
  94. package/eslint-rules/tex-build.mjs +13 -13
  95. package/eslint.config.mjs +6 -2
  96. package/hooks/hooks.harness.mjs +6 -11
  97. package/hooks/paper-edit-guard.hook.mjs +2 -2
  98. package/hooks/paper-edit-guard.test.mjs +61 -0
  99. package/hooks/paper-skills-nudge.hook.mjs +2 -2
  100. package/hooks/paper-skills-nudge.test.mjs +38 -0
  101. package/hooks/paper-status-gates.test.mjs +42 -0
  102. package/lib/agent-cli-version.harness.mjs +7 -0
  103. package/lib/check.d.mts +17 -0
  104. package/lib/check.mjs +50 -0
  105. package/lib/check.test.ts +67 -0
  106. package/lib/markdown.mjs +16 -69
  107. package/lib/markdown.test.mjs +246 -0
  108. package/lib/paper-config.harness.mjs +28 -9
  109. package/lib/paper-config.mjs +7 -2
  110. package/lib/skill-checks.mjs +18 -46
  111. package/lib/skill-checks.test.mjs +297 -0
  112. package/lib/skill-corpus.mjs +11 -13
  113. package/lib/skill-corpus.test.mjs +54 -0
  114. package/lib/skill-trigger-cases.harness.mjs +57 -4
  115. package/package.json +6 -5
  116. package/scripts/check.harness.mjs +4 -10
  117. package/scripts/check.mjs +45 -42
  118. package/scripts/check.test.mjs +104 -0
  119. package/scripts/coverage-config.test.ts +406 -0
  120. package/scripts/eslint-report-guard.test.mjs +48 -0
  121. package/scripts/harness-api.frozen.json +0 -2
  122. package/scripts/layer-legacy-frozen.d.mts +9 -1
  123. package/scripts/layer-legacy-frozen.mjs +28 -11
  124. package/scripts/layer-legacy-frozen.test.ts +143 -1
  125. package/scripts/rules-are-content-only.harness.mjs +3 -11
  126. package/scripts/rules-are-content-only.mjs +29 -19
  127. package/scripts/rules-are-content-only.test.mjs +61 -0
  128. package/scripts/rules-see-files.mjs +11 -9
  129. package/scripts/rules-see-files.test.mjs +71 -0
  130. package/scripts/test.mjs +44 -0
  131. package/scripts/test.test.mjs +52 -0
  132. package/skills/grade-paper-writing/__snapshots__/prose-lint.test.mjs.snap +57 -0
  133. package/skills/grade-paper-writing/prose-lint.mjs +31 -12
  134. package/skills/grade-paper-writing/prose-lint.test.mjs +153 -0
  135. package/skills/paper-pipeline/grade-paper-writing-ablation.eval.mjs +3 -3
  136. package/skills/paper-pipeline/scripts/README.md +13 -132
  137. package/skills/paper-pipeline/scripts/announce.test.mjs +102 -0
  138. package/skills/paper-pipeline/scripts/artifact-coverage.test.mjs +86 -0
  139. package/skills/paper-pipeline/scripts/consumer.d.mts +8 -1
  140. package/skills/paper-pipeline/scripts/consumer.harness.mjs +3 -3
  141. package/skills/paper-pipeline/scripts/consumer.mjs +13 -25
  142. package/skills/paper-pipeline/scripts/consumer.test.mjs +113 -0
  143. package/skills/paper-pipeline/scripts/extract-ref-facts.mjs +9 -4
  144. package/skills/paper-pipeline/scripts/extract-ref-facts.test.mjs +380 -0
  145. package/skills/paper-pipeline/scripts/fixtures/scorecard.mjs +71 -0
  146. package/skills/paper-pipeline/scripts/generated-code.harness.mjs +4 -4
  147. package/skills/paper-pipeline/scripts/generated-code.mjs +3 -2
  148. package/skills/paper-pipeline/scripts/generated-code.test.mjs +62 -0
  149. package/skills/paper-pipeline/scripts/ledger.cli.test.mjs +302 -0
  150. package/skills/paper-pipeline/scripts/ledger.mjs +1 -1
  151. package/skills/paper-pipeline/scripts/{ledger.selftest.mjs → ledger.test.mjs} +44 -76
  152. package/skills/paper-pipeline/scripts/pipeline-check.cli.test.mjs +474 -0
  153. package/skills/paper-pipeline/scripts/pipeline-check.harness.mjs +2 -63
  154. package/skills/paper-pipeline/scripts/pipeline-check.mjs +37 -21
  155. package/skills/paper-pipeline/scripts/pipeline-edges.mjs +2 -2
  156. package/skills/paper-pipeline/scripts/pipeline-edges.test.mjs +73 -0
  157. package/skills/paper-pipeline/scripts/population-map.harness.mjs +4 -47
  158. package/skills/paper-pipeline/scripts/population-map.mjs +12 -2
  159. package/skills/paper-pipeline/scripts/population-map.test.mjs +154 -0
  160. package/skills/paper-pipeline/scripts/provenance.harness.mjs +26 -0
  161. package/skills/paper-pipeline/scripts/round-diff.harness.mjs +1 -2
  162. package/skills/paper-pipeline/scripts/round-diff.mjs +13 -6
  163. package/skills/paper-pipeline/scripts/round-diff.test.mjs +159 -0
  164. package/skills/paper-pipeline/scripts/run-mechanical.mjs +30 -6
  165. package/skills/paper-pipeline/scripts/run-mechanical.test.mjs +468 -0
  166. package/skills/paper-pipeline/scripts/status.mjs +2 -2
  167. package/skills/paper-pipeline/scripts/status.test.mjs +232 -0
  168. package/skills/plan-paper-timeline/plan-paper-timeline.effects.harness.mjs +2 -2
  169. package/skills/render-paper/extract-pdf-facts.harness.mjs +56 -7
  170. package/skills/tighten-paper/__snapshots__/structure.test.mjs.snap +133 -0
  171. package/skills/tighten-paper/structure.test.mjs +116 -0
  172. package/skills/verify-citations/SKILL.md +5 -5
  173. package/skills/verify-citations/SKILL.md.spec.ts +4 -4
  174. package/skills/verify-citations/scripts/__snapshots__/verify-cites.net.test.mjs.snap +235 -0
  175. package/skills/verify-citations/scripts/bib-authors.check.test.mjs +274 -0
  176. package/skills/verify-citations/scripts/bib-authors.cli.test.mjs +178 -0
  177. package/skills/verify-citations/scripts/bib-authors.mjs +2 -1
  178. package/skills/verify-citations/scripts/verify-cites.cli.test.mjs +160 -0
  179. package/skills/verify-citations/scripts/verify-cites.mjs +96 -96
  180. package/skills/verify-citations/scripts/verify-cites.net.test.mjs +287 -0
  181. package/skills/verify-citations/scripts/verify-cites.test.mjs +149 -5
  182. package/src/adapters/banal/failure.test.ts +70 -1
  183. package/src/adapters/banal/index.test.ts +16 -0
  184. package/src/adapters/banal/output.test.ts +5 -0
  185. package/src/adapters/curl/download.test.ts +43 -1
  186. package/src/adapters/memory/index.test.ts +25 -0
  187. package/src/adapters/node/files.io.ts +3 -2
  188. package/src/adapters/node/files.test.ts +13 -1
  189. package/src/adapters/node/process.test.ts +38 -0
  190. package/src/adapters/pdfjs/fill.test.ts +34 -0
  191. package/src/adapters/pdfjs/fill.ts +44 -25
  192. package/src/adapters/references/index.test.ts +228 -0
  193. package/src/adapters/references/index.ts +21 -6
  194. package/src/adapters/references/pool.test.ts +31 -0
  195. package/src/adapters/references/pool.ts +24 -0
  196. package/src/build-engine.harness.mjs +3 -7
  197. package/src/build-engine.test.ts +137 -0
  198. package/src/build.harness.mjs +5 -9
  199. package/src/build.test.ts +362 -0
  200. package/src/build.ts +13 -9
  201. package/src/cli.harness.mjs +10 -17
  202. package/src/cli.test.ts +584 -0
  203. package/src/cli.ts +112 -66
  204. package/src/doctor.harness.mjs +3 -8
  205. package/src/doctor.test.ts +64 -0
  206. package/src/doctor.ts +12 -4
  207. package/src/domain/result.test.ts +4 -0
  208. package/src/domain/result.ts +0 -5
  209. package/src/engine.harness.mjs +27 -7
  210. package/src/facts-file.test.ts +110 -0
  211. package/src/hooks-settings.harness.mjs +43 -13
  212. package/src/hooks-settings.ts +41 -35
  213. package/src/init.test.ts +308 -5
  214. package/src/init.ts +3 -3
  215. package/src/latex-log.harness.mjs +32 -7
  216. package/src/latex-log.ts +6 -13
  217. package/src/latex-loop.harness.mjs +8 -7
  218. package/src/link-skills.harness.mjs +3 -8
  219. package/src/link-skills.test.ts +105 -0
  220. package/src/link-skills.ts +75 -21
  221. package/src/new-paper.harness.mjs +3 -7
  222. package/src/new-paper.test.ts +31 -1
  223. package/src/paper-files.test.ts +12 -0
  224. package/src/paper-files.ts +9 -5
  225. package/src/paper-settings.test.ts +20 -0
  226. package/src/pdf-facts.harness.mjs +3 -6
  227. package/src/pdf-facts.test.ts +144 -0
  228. package/src/pdf-facts.ts +17 -19
  229. package/src/pdf-geometry.harness.mjs +3 -7
  230. package/src/pdf-geometry.ts +1 -1
  231. package/src/presets.test.ts +2 -0
  232. package/src/presets.ts +7 -1
  233. package/src/references.test.ts +97 -0
  234. package/src/references.ts +2 -2
  235. package/src/rules-config.harness.mjs +10 -8
  236. package/src/structure.harness.mjs +3 -7
  237. package/src/tex-requirements.harness.mjs +34 -7
  238. package/src/tex-requirements.ts +12 -6
  239. package/src/toolchain.harness.mjs +3 -7
  240. package/src/toolchain.test.ts +280 -0
  241. package/src/toolchain.ts +8 -7
  242. package/src/venue-rules.test.ts +60 -0
  243. package/src/venue-rules.ts +13 -11
  244. package/action.mutations.mjs +0 -162
  245. package/eslint-rules/install-path-literals.mutations.mjs +0 -62
  246. package/eslint-rules/latex-language.mutations.mjs +0 -196
  247. package/eslint-rules/paper-research-question.mutations.mjs +0 -127
  248. package/eslint-rules/paper-stages.mutations.mjs +0 -81
  249. package/eslint-rules/papers.mutations.mjs +0 -186
  250. package/eslint-rules/temp-root-realpath.mutations.mjs +0 -99
  251. package/eslint-rules/tex-build.mutations.mjs +0 -258
  252. package/hooks/hooks.mutations.mjs +0 -337
  253. package/lib/agent-cli-version.mutations.mjs +0 -109
  254. package/lib/mutation-driver.harness.mjs +0 -227
  255. package/lib/mutation-driver.mjs +0 -397
  256. package/lib/mutation-driver.mutations.mjs +0 -68
  257. package/lib/paper-config.mutations.mjs +0 -143
  258. package/lib/skill-trigger-cases.mutations.mjs +0 -65
  259. package/scripts/check.mutations.mjs +0 -110
  260. package/scripts/exclusive.mjs +0 -138
  261. package/scripts/mutation-batteries-frozen.harness.mjs +0 -204
  262. package/scripts/mutation-batteries-frozen.mjs +0 -238
  263. package/scripts/mutation-batteries.frozen.json +0 -108
  264. package/scripts/rules-are-content-only.mutations.mjs +0 -81
  265. package/scripts/rules-see-files.mutations.mjs +0 -131
  266. package/scripts/run-mutations.mjs +0 -100
  267. package/skills/paper-pipeline/scripts/artifact-coverage.mutations.mjs +0 -218
  268. package/skills/paper-pipeline/scripts/consumer.mutations.mjs +0 -190
  269. package/skills/paper-pipeline/scripts/extract-ref-facts.mutations.mjs +0 -54
  270. package/skills/paper-pipeline/scripts/generated-code.mutations.mjs +0 -254
  271. package/skills/paper-pipeline/scripts/pipeline-check.mutations.mjs +0 -54
  272. package/skills/paper-pipeline/scripts/population-map.mutations.mjs +0 -65
  273. package/skills/paper-pipeline/scripts/population-map.selftest.mjs +0 -122
  274. package/skills/paper-pipeline/scripts/provenance.mutations.mjs +0 -59
  275. package/skills/paper-pipeline/scripts/round-diff.mutations.mjs +0 -276
  276. package/skills/plan-paper-timeline/plan-paper-timeline.effects.mutations.mjs +0 -65
  277. package/skills/skill-contract.mutations.mjs +0 -179
  278. package/src/build.mutations.mjs +0 -196
  279. package/src/cli.mutations.mjs +0 -414
  280. package/src/doctor.mutations.mjs +0 -175
  281. package/src/hooks-settings.mutations.mjs +0 -99
  282. package/src/link-skills.mutations.mjs +0 -140
  283. package/src/new-paper.mutations.mjs +0 -65
  284. package/src/structure.mutations.mjs +0 -83
@@ -1,140 +0,0 @@
1
- /**
2
- * Battery for `link-skills.ts`.
3
- *
4
- * Every case below reintroduces a way the skills stop being where Claude Code looks — or, worse,
5
- * a way the linker destroys something the consumer made. Both fail silently in real life: a
6
- * missing skill is simply absent from the listing, and a replaced directory is simply gone.
7
- */
8
- import { fileURLToPath } from "node:url";
9
- import { dirname, join, resolve } from "node:path";
10
- import { runMutations } from "../lib/mutation-driver.mjs";
11
-
12
- const HERE = dirname(fileURLToPath(import.meta.url));
13
- const ROOT = resolve(HERE, "..");
14
- const SRC = join(HERE, "link-skills.ts");
15
- const HARNESS = join(HERE, "link-skills.harness.mjs");
16
- const CONSUMER = join(
17
- ROOT,
18
- "skills",
19
- "paper-pipeline",
20
- "scripts",
21
- "consumer.mjs",
22
- );
23
-
24
- process.exit(
25
- runMutations({
26
- root: ROOT,
27
- runner: "node",
28
- cases: [
29
- {
30
- // The definition lives in the port since paperlint#62 (`installedSkills` in consumer.mjs), so
31
- // the defect is planted THERE and must still die in THIS harness — the evidence that the
32
- // linker reads it through the shared function rather than through a copy of its own.
33
- name: "any directory counts as a skill",
34
- harness: HARNESS,
35
- expect: "a directory without SKILL.md is not one",
36
- disables:
37
- "the definition of a skill. A helper directory beside the skills gets a link, and Claude " +
38
- "Code lists an entry with no SKILL.md behind it",
39
- edits: [
40
- [
41
- CONSUMER,
42
- ' if (st.isDirectory() && existsSync(join(entry, "SKILL.md")))\n names.push(name);',
43
- " if (st.isDirectory())\n names.push(name);",
44
- ],
45
- ],
46
- },
47
- {
48
- name: "the link is written absolute",
49
- harness: HARNESS,
50
- expect: "the link is RELATIVE",
51
- disables:
52
- "portability of the checkout. An absolute link works on the machine that ran init and " +
53
- "dangles in every other clone, container and CI runner",
54
- edits: [
55
- [
56
- SRC,
57
- ' symlinkSync(target, entry, "dir");',
58
- ' symlinkSync(resolve(dirname(entry), target), entry, "dir");',
59
- ],
60
- ],
61
- },
62
- {
63
- name: "an existing correct link is not recognised",
64
- harness: HARNESS,
65
- expect: "a second run reports every link as ALREADY present",
66
- disables:
67
- "idempotency. Every re-run of init would report its own links as someone else's " +
68
- "and tell the consumer to move them",
69
- edits: [
70
- [
71
- SRC,
72
- ' if (realpathSync(entry) === want) return { status: "present" };',
73
- ' if (realpathSync(entry) === "") return { status: "present" };',
74
- ],
75
- ],
76
- },
77
- {
78
- name: "a foreign entry is replaced instead of reported",
79
- harness: HARNESS,
80
- expect: "a foreign DIRECTORY is left untouched",
81
- disables:
82
- "the one promise that makes init safe to run on a real project: a consumer's own skill " +
83
- "of the same name, or a link they aimed elsewhere, is deleted without a word",
84
- edits: [
85
- [
86
- SRC,
87
- ' symlinkSync,\n} from "node:fs";',
88
- ' symlinkSync,\n rmSync,\n} from "node:fs";',
89
- ],
90
- [
91
- SRC,
92
- ' if (!write || seen.status !== "missing")',
93
- ' if (!write || seen.status === "present")',
94
- ],
95
- [
96
- SRC,
97
- ' symlinkSync(target, entry, "dir");',
98
- ' rmSync(entry, { recursive: true, force: true });\n symlinkSync(target, entry, "dir");',
99
- ],
100
- ],
101
- },
102
- {
103
- name: "the resolved store path is linked instead of the project's own spelling",
104
- harness: HARNESS,
105
- expect: "under pnpm the link goes through node_modules/<package>",
106
- disables:
107
- "the link surviving an upgrade under pnpm. The store directory carries the version in " +
108
- "its name; the next install removes it and every skill link dangles until init is re-run",
109
- edits: [
110
- [
111
- SRC,
112
- " if (realpathSync(candidate) === dir) return { dir, spelled: candidate };",
113
- ' if (realpathSync(candidate) === "") return { dir, spelled: candidate };',
114
- ],
115
- ],
116
- },
117
- {
118
- name: "doctor's read-only call writes links",
119
- harness: HARNESS,
120
- expect:
121
- "write:false reports every skill as missing and creates nothing",
122
- disables:
123
- "the difference between looking and changing. `paperlint doctor` would quietly repair the " +
124
- "state it is supposed to report, so the report can never show the gap",
125
- edits: [
126
- [
127
- SRC,
128
- ' if (!write || seen.status !== "missing")',
129
- ' if (seen.status !== "missing")',
130
- ],
131
- [
132
- SRC,
133
- " if (write && shipped.names.length > 0) {",
134
- " if (shipped.names.length > 0) {",
135
- ],
136
- ],
137
- },
138
- ],
139
- }),
140
- );
@@ -1,65 +0,0 @@
1
- /**
2
- * Battery for `new-paper.ts`.
3
- *
4
- * Every case reintroduces a way `paperlint new` damages a paper folder or produces one the linter
5
- * refuses — the first a loss nobody notices until the text is gone, the second the exact
6
- * "missing file on the first run" this command was written to end.
7
- */
8
- import { fileURLToPath } from "node:url";
9
- import { dirname, join, resolve } from "node:path";
10
- import { runMutations } from "../lib/mutation-driver.mjs";
11
-
12
- const HERE = dirname(fileURLToPath(import.meta.url));
13
- const ROOT = resolve(HERE, "..");
14
- const SRC = join(HERE, "new-paper.ts");
15
- const HARNESS = join(HERE, "new-paper.harness.mjs");
16
-
17
- process.exit(
18
- runMutations({
19
- root: ROOT,
20
- runner: "node",
21
- cases: [
22
- {
23
- name: "an existing file is overwritten",
24
- harness: HARNESS,
25
- expect: "a second run overwrites nothing",
26
- disables:
27
- "the one promise that makes `paperlint new` safe on an existing folder. A scorecard with a " +
28
- "year of journal in it is replaced by the empty template",
29
- edits: [
30
- [
31
- SRC,
32
- ' if (existsSync(join(dir, file))) {\n files.push({ file, status: "kept" });\n continue;\n }\n',
33
- "",
34
- ],
35
- [SRC, '{ encoding: "utf8", flag: "wx" }', '{ encoding: "utf8" }'],
36
- ],
37
- },
38
- {
39
- name: "a second source is added beside an existing one",
40
- harness: HARNESS,
41
- // The first owner is the re-run on a .tex paper asked for md: it must add no paper.md.
42
- expect: "adds no second source",
43
- disables:
44
- "the migration of an old folder: a paper written in Markdown gains a stub paper.tex, " +
45
- "and every tex rule starts linting a file the author never wrote",
46
- edits: [
47
- [
48
- SRC,
49
- " return hasSource ? [STATUS_FILE] : [STATUS_FILE, SOURCE_FILE[format]];",
50
- " return [STATUS_FILE, SOURCE_FILE[format]];",
51
- ],
52
- ],
53
- },
54
- {
55
- name: "a leading dot is accepted",
56
- harness: HARNESS,
57
- expect: "discovery skips dot-directories",
58
- disables:
59
- "the refusal of a name that would be created and then never linted — the scaffold " +
60
- "would sit beside the papers, invisible to every check",
61
- edits: [[SRC, ' if (name.startsWith("."))', " if (false)"]],
62
- },
63
- ],
64
- }),
65
- );
@@ -1,83 +0,0 @@
1
- /**
2
- * Battery for `structure.ts` — the package's only check whose subject is a file's ABSENCE.
3
- *
4
- * A check like this is especially vulnerable to silent failure: it reports on what is missing,
5
- * so a broken one looks exactly like a clean corpus. This battery exists because the mutation gate
6
- * refused to accept a harness that nothing could kill.
7
- */
8
- import { fileURLToPath } from "node:url";
9
- import { dirname, join, resolve } from "node:path";
10
- import { runMutations } from "../lib/mutation-driver.mjs";
11
-
12
- const HERE = dirname(fileURLToPath(import.meta.url));
13
- const ROOT = resolve(HERE, "..");
14
- const SRC = join(HERE, "structure.ts");
15
- const HARNESS = join(HERE, "structure.harness.mjs");
16
-
17
- process.exit(
18
- runMutations({
19
- root: ROOT,
20
- runner: "node",
21
- cases: [
22
- {
23
- name: "generous detection is removed — any directory counts as a paper",
24
- harness: HARNESS,
25
- expect:
26
- "a directory WITHOUT a single pipeline marker is left alone entirely",
27
- disables:
28
- "the condition the check uses at all to decide it is looking at a paper. Without it, " +
29
- "findings would rain down on `data/`, `figures/` and any neighboring directory — and a " +
30
- "rule that yells at the innocent gets turned off entirely, real findings and all",
31
- edits: [
32
- [
33
- SRC,
34
- " if (!rules.markers.some((m: string) => existsSync(join(dir, m))))\n continue;",
35
- " if (false) continue;",
36
- ],
37
- ],
38
- },
39
- {
40
- name: "`ignore` stops exempting",
41
- harness: HARNESS,
42
- expect: "`ignore` exempts a directory by name",
43
- disables:
44
- 'the consumer\'s only way to say "this directory is not a paper". Without it, an ' +
45
- "exemption has to be expressed by renaming the directory",
46
- edits: [
47
- [SRC, " if (rules.ignore.includes(name)) continue;\n", ""],
48
- ],
49
- },
50
- {
51
- name: "the second accepted source form falls out of the defaults",
52
- harness: HARNESS,
53
- expect: "`paper.md` counts on equal footing with `paper.tex`",
54
- disables:
55
- "the second source form the live corpus keeps. A paper on `paper.md` would become a " +
56
- '"no source" finding while its source is right there — i.e. the check would yell at ' +
57
- "the innocent, and such rules get turned off entirely, real findings and all",
58
- edits: [
59
- [
60
- SRC,
61
- 'requireOneOf: [["paper.tex", "paper.md"]]',
62
- 'requireOneOf: [["paper.tex"]]',
63
- ],
64
- ],
65
- },
66
- {
67
- name: "the path in a finding goes absolute again",
68
- harness: HARNESS,
69
- expect: "and the path is RELATIVE",
70
- disables:
71
- "the readability of the finding. An absolute path to the run's temp directory tells " +
72
- "the reader nothing and on top of that makes the output useless for comparing across machines",
73
- edits: [
74
- [
75
- SRC,
76
- ' return rel &&\n rel !== ".." &&\n !rel.startsWith(`..${sep}`) &&\n !isAbsolute(rel)\n ? rel\n : p;',
77
- " return p;",
78
- ],
79
- ],
80
- },
81
- ],
82
- }),
83
- );