paperlint 2.0.1 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +6 -1
- package/CONTRIBUTING.md +21 -0
- package/README.md +231 -180
- package/action.yml +4 -6
- package/dist/adapters/references/index.d.ts +13 -0
- package/dist/adapters/references/index.d.ts.map +1 -0
- package/dist/adapters/references/index.js +55 -0
- package/dist/adapters/references/index.js.map +1 -0
- package/dist/adapters/references/reach.io.d.ts +3 -0
- package/dist/adapters/references/reach.io.d.ts.map +1 -0
- package/dist/adapters/references/reach.io.js +14 -0
- package/dist/adapters/references/reach.io.js.map +1 -0
- package/dist/build-engine.d.ts.map +1 -1
- package/dist/build-engine.js +5 -2
- package/dist/build-engine.js.map +1 -1
- package/dist/build.d.ts +16 -1
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +40 -5
- package/dist/build.js.map +1 -1
- package/dist/cli.d.ts +37 -20
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +377 -251
- package/dist/cli.js.map +1 -1
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +37 -52
- package/dist/doctor.js.map +1 -1
- package/dist/facts-file.d.ts +33 -9
- package/dist/facts-file.d.ts.map +1 -1
- package/dist/facts-file.js +117 -17
- package/dist/facts-file.js.map +1 -1
- package/dist/hooks-settings.d.ts +0 -21
- package/dist/hooks-settings.d.ts.map +1 -1
- package/dist/hooks-settings.js +17 -135
- package/dist/hooks-settings.js.map +1 -1
- package/dist/init.d.ts +40 -19
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +144 -109
- package/dist/init.js.map +1 -1
- package/dist/link-skills.d.ts +1 -1
- package/dist/link-skills.d.ts.map +1 -1
- package/dist/link-skills.js +11 -29
- package/dist/link-skills.js.map +1 -1
- package/dist/new-paper.d.ts +2 -2
- package/dist/new-paper.d.ts.map +1 -1
- package/dist/new-paper.js +6 -2
- package/dist/new-paper.js.map +1 -1
- package/dist/paper-files.d.ts +63 -0
- package/dist/paper-files.d.ts.map +1 -0
- package/dist/paper-files.js +69 -0
- package/dist/paper-files.js.map +1 -0
- package/dist/paper-settings.d.ts +40 -0
- package/dist/paper-settings.d.ts.map +1 -0
- package/dist/paper-settings.js +144 -0
- package/dist/paper-settings.js.map +1 -0
- package/dist/ports/check-references.d.ts +31 -0
- package/dist/ports/check-references.d.ts.map +1 -0
- package/dist/ports/check-references.js +7 -0
- package/dist/ports/check-references.js.map +1 -0
- package/dist/presets.d.ts +84 -0
- package/dist/presets.d.ts.map +1 -0
- package/dist/presets.js +184 -0
- package/dist/presets.js.map +1 -0
- package/dist/reference-rules.d.ts +47 -0
- package/dist/reference-rules.d.ts.map +1 -0
- package/dist/reference-rules.js +156 -0
- package/dist/reference-rules.js.map +1 -0
- package/dist/references.d.ts +36 -0
- package/dist/references.d.ts.map +1 -0
- package/dist/references.js +91 -0
- package/dist/references.js.map +1 -0
- package/dist/rules-config.d.ts +11 -2
- package/dist/rules-config.d.ts.map +1 -1
- package/dist/rules-config.js +25 -11
- package/dist/rules-config.js.map +1 -1
- package/dist/structure.d.ts.map +1 -1
- package/dist/structure.js +3 -2
- package/dist/structure.js.map +1 -1
- package/dist/tex-requirements.d.ts +63 -7
- package/dist/tex-requirements.d.ts.map +1 -1
- package/dist/tex-requirements.js +91 -24
- package/dist/tex-requirements.js.map +1 -1
- package/dist/types.d.ts +20 -18
- package/dist/types.d.ts.map +1 -1
- package/dist/venue-rules.d.ts +109 -0
- package/dist/venue-rules.d.ts.map +1 -0
- package/dist/venue-rules.js +389 -0
- package/dist/venue-rules.js.map +1 -0
- package/docs/configuration.md +152 -77
- package/docs/e2e.md +1 -1
- package/docs/install.md +25 -40
- package/docs/optional-rules.md +26 -24
- package/docs/rules.md +181 -15
- package/eslint-rules/bib-reachable-entry.mjs +75 -0
- package/eslint-rules/latex-language.mjs +29 -1
- package/eslint-rules/paper-stages.harness.mjs +1 -117
- package/eslint-rules/paper-stages.mjs +0 -120
- package/eslint-rules/paper-stages.mutations.mjs +0 -76
- package/eslint-rules/paper-typography.mjs +267 -192
- package/eslint-rules/paper-typography.test.mjs +297 -0
- package/eslint-rules/papers.harness.mjs +8 -12
- package/eslint-rules/papers.mjs +17 -27
- package/eslint-rules/pdf-last-page-balance.mjs +23 -5
- package/eslint-rules/review-frontmatter.mjs +118 -0
- package/eslint-rules/review-frontmatter.schema.json +36 -0
- package/eslint-rules/review-frontmatter.test.mjs +118 -0
- package/eslint-rules/sibling-frontmatter.mjs +19 -0
- package/eslint-rules/sibling-frontmatter.schema.json +14 -0
- package/eslint.config.mjs +0 -15
- package/fixtures/build-e2e/acmart/paperlint.json +1 -0
- package/fixtures/real-markdown-paper/baseline.json +6 -7
- package/hooks/hooks.harness.mjs +39 -98
- package/hooks/hooks.mutations.mjs +6 -6
- package/hooks/paper-edit-guard.hook.d.mts +2 -3
- package/hooks/paper-edit-guard.hook.mjs +31 -42
- package/hooks/paper-skills-nudge.hook.mjs +21 -19
- package/hooks/paper-status-gates.hook.mjs +21 -19
- package/hooks/paper-status-gates.sh +8 -13
- package/lib/paper-config.d.mts +15 -18
- package/lib/paper-config.harness.mjs +18 -35
- package/lib/paper-config.mjs +90 -81
- package/lib/paper-config.mutations.mjs +2 -2
- package/lib/skill-checks.mjs +1 -1
- package/lib/skill-trigger-cases.harness.mjs +9 -8
- package/lib/skill-trigger-cases.mjs +7 -15
- package/package.json +1 -1
- package/scripts/eslint-report-guard.mjs +1 -1
- package/scripts/harness-api.frozen.json +0 -3
- package/scripts/mutation-batteries.frozen.json +4 -13
- package/skills/analyze-sibling-paper/SKILL.md +16 -12
- package/skills/analyze-sibling-paper/SKILL.md.spec.ts +15 -11
- package/skills/cold-read-diff/SKILL.md +20 -1
- package/skills/cold-read-diff/SKILL.md.spec.ts +19 -0
- package/skills/find-venue/SKILL.md +5 -1
- package/skills/find-venue/SKILL.md.spec.ts +4 -0
- package/skills/grade-paper-writing/SKILL.md +20 -1
- package/skills/grade-paper-writing/SKILL.md.spec.ts +19 -0
- package/skills/paper-pipeline/PIPELINE-MAP.md +14 -4
- package/skills/paper-pipeline/SKILL.md +4 -3
- package/skills/paper-pipeline/SKILL.md.spec.ts +3 -2
- package/skills/paper-pipeline/scripts/consumer.d.mts +0 -1
- package/skills/paper-pipeline/scripts/consumer.harness.mjs +8 -12
- package/skills/paper-pipeline/scripts/consumer.mjs +19 -33
- package/skills/paper-pipeline/scripts/extract-ref-facts.harness.mjs +6 -4
- package/skills/paper-pipeline/scripts/run-mechanical.mjs +2 -11
- package/skills/plan-paper-timeline/SKILL.md +2 -2
- package/skills/plan-paper-timeline/SKILL.md.spec.ts +1 -1
- package/skills/plan-paper-timeline/plan-paper-timeline.effects.harness.mjs +1 -1
- package/skills/plan-paper-timeline/plan-paper-timeline.effects.mutations.mjs +2 -2
- package/skills/render-paper/check-render.sh +2 -3
- package/skills/render-paper/extract-pdf-facts.harness.mjs +5 -5
- package/skills/render-paper/extract-pdf-facts.mjs +4 -4
- package/skills/render-paper/render-paper.harness.mjs +2 -2
- package/skills/study-accepted-papers/SKILL.md +2 -1
- package/skills/study-accepted-papers/SKILL.md.spec.ts +1 -0
- package/skills/submit-paper/SKILL.md +9 -1
- package/skills/submit-paper/SKILL.md.spec.ts +8 -0
- package/skills/submit-paper/references/venues/acm-sigconf.jsonc +86 -0
- package/skills/submit-paper/references/venues/agenticdev.jsonc +34 -102
- package/skills/submit-paper/references/venues/aisec.jsonc +21 -82
- package/skills/submit-paper/references/venues/realm.jsonc +45 -43
- package/skills/submit-paper/references/venues/tex-base.jsonc +1 -1
- package/skills/submit-paper/references/venues/venue-profile.schema.json +119 -29
- package/skills/verify-citations/SKILL.md +10 -1
- package/skills/verify-citations/SKILL.md.spec.ts +9 -0
- package/skills/verify-citations/scripts/bib-authors.mjs +48 -26
- package/src/adapters/references/index.ts +102 -0
- package/src/adapters/references/reach.io.ts +12 -0
- package/src/build-engine.ts +10 -2
- package/src/build.harness.mjs +31 -22
- package/src/build.ts +65 -8
- package/src/cli.harness.mjs +151 -294
- package/src/cli.mutations.mjs +35 -44
- package/src/cli.ts +457 -288
- package/src/doctor.harness.mjs +41 -84
- package/src/doctor.mutations.mjs +9 -9
- package/src/doctor.ts +41 -61
- package/src/facts-file.test.ts +47 -7
- package/src/facts-file.ts +145 -24
- package/src/hooks-settings.harness.mjs +7 -92
- package/src/hooks-settings.mutations.mjs +2 -17
- package/src/hooks-settings.ts +18 -162
- package/src/init.test.ts +206 -0
- package/src/init.ts +193 -159
- package/src/link-skills.harness.mjs +1 -38
- package/src/link-skills.mutations.mjs +9 -5
- package/src/link-skills.ts +10 -34
- package/src/lint-fix.test.ts +120 -0
- package/src/new-paper.harness.mjs +9 -6
- package/src/new-paper.test.ts +133 -0
- package/src/new-paper.ts +7 -2
- package/src/paper-files.test.ts +290 -0
- package/src/paper-files.ts +144 -0
- package/src/paper-settings-commands.test.ts +274 -0
- package/src/paper-settings.test.ts +249 -0
- package/src/paper-settings.ts +208 -0
- package/src/ports/check-references.ts +28 -0
- package/src/presets.test.ts +236 -0
- package/src/presets.ts +297 -0
- package/src/reference-rules.ts +229 -0
- package/src/references.test.ts +209 -0
- package/src/references.ts +138 -0
- package/src/rules-config.harness.mjs +24 -8
- package/src/rules-config.ts +30 -13
- package/src/structure.harness.mjs +6 -4
- package/src/structure.ts +3 -2
- package/src/tex-requirements.harness.mjs +11 -17
- package/src/tex-requirements.ts +179 -29
- package/src/types.ts +30 -18
- package/src/venue-rules.test.ts +554 -0
- package/src/venue-rules.ts +571 -0
- package/templates/paper/paperlint.json +4 -0
- package/eslint-rules/doc-fields.harness.mjs +0 -336
- package/eslint-rules/doc-fields.mjs +0 -186
- package/eslint-rules/doc-fields.mutations.mjs +0 -96
- package/eslint-rules/paper-typography.harness.mjs +0 -291
- package/eslint-rules/paper-typography.mutations.mjs +0 -131
- package/eslint-rules/review-findings-cause.harness.mjs +0 -228
- package/eslint-rules/review-findings-cause.mjs +0 -135
- package/eslint-rules/review-findings-cause.mutations.mjs +0 -72
- package/fixtures/build-e2e/acmart/venue.json +0 -1
- package/fixtures/paper-stages/authors-ran/PIPELINE-STATUS.md +0 -16
- package/fixtures/paper-stages/marker-in-prose/PIPELINE-STATUS.md +0 -17
- package/fixtures/review-findings-cause/clean.md +0 -17
- package/fixtures/review-findings-cause/defect.md +0 -14
- package/fixtures/review-findings-cause/old-debt.md +0 -14
- package/fixtures/review-findings-cause/quiet-in-fence.md +0 -16
package/dist/presets.js
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VENUE PRESETS — what `"extends"` in a paper's `paperlint.json` resolves to.
|
|
3
|
+
*
|
|
4
|
+
* A venue is a preset, the way an ESLint config is a shareable config: a file with the venue's
|
|
5
|
+
* format (page size, columns, fonts, font sizes, page limits per kind), the TeX packages its
|
|
6
|
+
* template needs, and the rules it implies. A preset may build on another with its own `extends`:
|
|
7
|
+
* `agenticdev` extends the family `acm-sigconf`, which holds everything the ACM template decides.
|
|
8
|
+
*
|
|
9
|
+
* ── TWO SPEC FORMS, AND ONLY TWO ─────────────────────────────────────────────────
|
|
10
|
+
* paperlint:<name> a preset shipped in the package's venues directory
|
|
11
|
+
* ./x.jsonc, ../x a file of the project's own, relative to the file that names it
|
|
12
|
+
* Anything else — an npm package name, a bare name — is refused by name. npm presets are not
|
|
13
|
+
* supported yet; a bare name is almost always a shipped name missing its prefix, and the message says so.
|
|
14
|
+
*
|
|
15
|
+
* ── THE CHAIN ─────────────────────────────────────────────────────────────────────
|
|
16
|
+
* At most `MAX_PRESET_DEPTH` files, root to leaf. A cycle (relative paths can form one) is refused
|
|
17
|
+
* naming the chain. The chain is merged block by block:
|
|
18
|
+
*
|
|
19
|
+
* tex union — a child never removes a package its parent needs
|
|
20
|
+
* format per key, the child wins; `kinds` by kind name, a child's kind replaces that kind
|
|
21
|
+
* rules per rule id, the child wins
|
|
22
|
+
* template the child wins; so does `name`
|
|
23
|
+
*
|
|
24
|
+
* ── THE LABEL ─────────────────────────────────────────────────────────────────────
|
|
25
|
+
* Messages, the facts file and the build plan need a word for the venue. It is the most derived
|
|
26
|
+
* preset's `name` when one sets it, else the spec's file name without its extension
|
|
27
|
+
* (`paperlint:agenticdev` → `agenticdev`, `./venues/usenix-sec.jsonc` → `usenix-sec`). Display
|
|
28
|
+
* only: nothing is ever resolved by it.
|
|
29
|
+
*/
|
|
30
|
+
import { basename, dirname, extname, join, resolve } from "node:path";
|
|
31
|
+
import { mergeRequirements, NO_FORMAT, NO_REQUIREMENTS, parsePreset, profileFileOf, venueNames, } from "./tex-requirements.js";
|
|
32
|
+
import { err, ok } from "./domain/result.js";
|
|
33
|
+
import { readPaperSettings, } from "./paper-settings.js";
|
|
34
|
+
import { CONFIG_FILE } from "../lib/paper-config.mjs";
|
|
35
|
+
/** The prefix of a shipped preset's spec. */
|
|
36
|
+
export const SHIPPED_PREFIX = "paperlint:";
|
|
37
|
+
/** The longest chain of presets, the paper's own target included. */
|
|
38
|
+
export const MAX_PRESET_DEPTH = 4;
|
|
39
|
+
/** The display label of a spec: the file name without its extension. Pure. */
|
|
40
|
+
export function labelOf(spec) {
|
|
41
|
+
const name = spec.startsWith(SHIPPED_PREFIX)
|
|
42
|
+
? spec.slice(SHIPPED_PREFIX.length)
|
|
43
|
+
: basename(spec);
|
|
44
|
+
return name.slice(0, name.length - extname(name).length) || name;
|
|
45
|
+
}
|
|
46
|
+
const isRelative = (spec) => spec.startsWith("./") || spec.startsWith("../");
|
|
47
|
+
/** A spec → the file it names, or why it names none. Pure. */
|
|
48
|
+
function fileOf(spec, from, venuesDir) {
|
|
49
|
+
if (isRelative(spec))
|
|
50
|
+
return ok(resolve(dirname(from), spec));
|
|
51
|
+
if (!spec.startsWith(SHIPPED_PREFIX))
|
|
52
|
+
return err({ kind: "unsupported", spec });
|
|
53
|
+
const file = profileFileOf(spec.slice(SHIPPED_PREFIX.length));
|
|
54
|
+
return file === null
|
|
55
|
+
? err({ kind: "not-found", spec, file: spec, shipped: [] })
|
|
56
|
+
: ok(join(venuesDir, file));
|
|
57
|
+
}
|
|
58
|
+
/** One file of the chain: read and parsed, or why not. */
|
|
59
|
+
function readPreset(spec, from, deps) {
|
|
60
|
+
const where = fileOf(spec, from, deps.venuesDir);
|
|
61
|
+
if (!where.ok)
|
|
62
|
+
return where;
|
|
63
|
+
const bytes = deps.files.readBytes(where.value);
|
|
64
|
+
if (bytes === null)
|
|
65
|
+
return err({ kind: "not-found", spec, file: where.value, shipped: [] });
|
|
66
|
+
try {
|
|
67
|
+
const text = new TextDecoder().decode(bytes);
|
|
68
|
+
return ok({
|
|
69
|
+
file: where.value,
|
|
70
|
+
preset: parsePreset(text, where.value, deps.venuesDir),
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
catch (e) {
|
|
74
|
+
return err({
|
|
75
|
+
kind: "broken",
|
|
76
|
+
file: where.value,
|
|
77
|
+
why: e.message.split("\n").join(" "),
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/** The chain's files, leaf first, each parsed. */
|
|
82
|
+
function chainOf(spec, from, deps) {
|
|
83
|
+
const out = [];
|
|
84
|
+
let next = { spec, from };
|
|
85
|
+
while (next !== null) {
|
|
86
|
+
const r = readPreset(next.spec, next.from, deps);
|
|
87
|
+
if (!r.ok)
|
|
88
|
+
return r;
|
|
89
|
+
const files = out.map((x) => x.file);
|
|
90
|
+
if (files.includes(r.value.file))
|
|
91
|
+
return err({ kind: "cycle", chain: [...files, r.value.file] });
|
|
92
|
+
if (out.length === MAX_PRESET_DEPTH)
|
|
93
|
+
return err({ kind: "too-deep", chain: [...files, r.value.file] });
|
|
94
|
+
out.push(r.value);
|
|
95
|
+
const up = r.value.preset.extends;
|
|
96
|
+
next = up === null ? null : { spec: up, from: r.value.file };
|
|
97
|
+
}
|
|
98
|
+
return ok(out);
|
|
99
|
+
}
|
|
100
|
+
/** A child's format over its parent's: per key the child wins, kinds by name. Pure. */
|
|
101
|
+
export function mergeFormat(parent, child) {
|
|
102
|
+
const keys = Object.keys(NO_FORMAT).filter((k) => k !== "kinds");
|
|
103
|
+
const scalars = Object.fromEntries(keys.map((k) => [k, child[k] ?? parent[k]]));
|
|
104
|
+
return { ...scalars, kinds: new Map([...parent.kinds, ...child.kinds]) };
|
|
105
|
+
}
|
|
106
|
+
/** The chain, root first, merged into one preset. Pure. */
|
|
107
|
+
function merged(spec, rootFirst, files) {
|
|
108
|
+
const base = {
|
|
109
|
+
name: null,
|
|
110
|
+
template: null,
|
|
111
|
+
tex: NO_REQUIREMENTS,
|
|
112
|
+
format: NO_FORMAT,
|
|
113
|
+
rules: {},
|
|
114
|
+
};
|
|
115
|
+
const m = rootFirst.reduce((acc, p) => ({
|
|
116
|
+
name: p.name ?? acc.name,
|
|
117
|
+
template: p.template ?? acc.template,
|
|
118
|
+
tex: p.tex ? mergeRequirements(acc.tex, p.tex) : acc.tex,
|
|
119
|
+
format: mergeFormat(acc.format, p.format),
|
|
120
|
+
rules: { ...acc.rules, ...p.rules },
|
|
121
|
+
}), base);
|
|
122
|
+
return {
|
|
123
|
+
label: m.name ?? labelOf(spec),
|
|
124
|
+
chain: files,
|
|
125
|
+
template: m.template,
|
|
126
|
+
tex: m.tex,
|
|
127
|
+
format: m.format,
|
|
128
|
+
rules: m.rules,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* `spec`, as written in `fromFile` (a paper's `paperlint.json`), → the merged preset, or why it
|
|
133
|
+
* does not resolve. Reads through `deps.files` only; never throws.
|
|
134
|
+
*/
|
|
135
|
+
export function resolvePreset(spec, fromFile, deps) {
|
|
136
|
+
const chain = chainOf(spec, fromFile, deps);
|
|
137
|
+
if (!chain.ok)
|
|
138
|
+
return chain.error.kind === "not-found"
|
|
139
|
+
? err({ ...chain.error, shipped: shippedPresets(deps.venuesDir) })
|
|
140
|
+
: chain;
|
|
141
|
+
const rootFirst = [...chain.value].reverse();
|
|
142
|
+
return ok(merged(spec, rootFirst.map((x) => x.preset), rootFirst.map((x) => x.file)));
|
|
143
|
+
}
|
|
144
|
+
/** The shipped presets' names (each is spelled `paperlint:<name>`). */
|
|
145
|
+
export function shippedPresets(venuesDir) {
|
|
146
|
+
return venueNames(venuesDir);
|
|
147
|
+
}
|
|
148
|
+
/** One line for a problem, naming what to change. Pure. */
|
|
149
|
+
export function presetProblemText(p) {
|
|
150
|
+
switch (p.kind) {
|
|
151
|
+
case "unsupported":
|
|
152
|
+
return `"extends": "${p.spec}" — a preset is \`paperlint:<name>\` (shipped) or a path starting with ./ or ../ (your own); npm presets: not yet supported. Did you mean "${SHIPPED_PREFIX}${p.spec}"?`;
|
|
153
|
+
case "not-found":
|
|
154
|
+
return `"extends": "${p.spec}" names no preset (${p.file}); shipped presets (${SHIPPED_PREFIX}<name>): ${p.shipped.join(", ")}`;
|
|
155
|
+
case "cycle":
|
|
156
|
+
return `the presets extend each other in a cycle: ${p.chain.join(" → ")}`;
|
|
157
|
+
case "too-deep":
|
|
158
|
+
return `the preset chain is longer than ${String(MAX_PRESET_DEPTH)}: ${p.chain.join(" → ")}`;
|
|
159
|
+
case "broken":
|
|
160
|
+
return `the preset ${p.file} does not parse: ${p.why}`;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/** A paper directory → its settings and its resolved preset. Reads through `deps.files`; never throws. */
|
|
164
|
+
export function paperPreset(paperDir, deps) {
|
|
165
|
+
const read = readPaperSettings(deps.files, paperDir);
|
|
166
|
+
if (!read.ok)
|
|
167
|
+
return { kind: "settings-problem", problem: read.error };
|
|
168
|
+
const settings = read.value;
|
|
169
|
+
if (settings?.extends == null)
|
|
170
|
+
return { kind: "none", settings };
|
|
171
|
+
const r = resolvePreset(settings.extends, join(paperDir, CONFIG_FILE), deps);
|
|
172
|
+
return r.ok
|
|
173
|
+
? { kind: "resolved", settings, preset: r.value }
|
|
174
|
+
: { kind: "preset-problem", settings, problem: r.error };
|
|
175
|
+
}
|
|
176
|
+
/** The one-line reason a paper's settings or preset cannot be used, or null when they can. */
|
|
177
|
+
export function paperPresetProblem(paperDir, p) {
|
|
178
|
+
if (p.kind === "preset-problem")
|
|
179
|
+
return `${join(paperDir, CONFIG_FILE)}: ${presetProblemText(p.problem)}`;
|
|
180
|
+
if (p.kind !== "settings-problem")
|
|
181
|
+
return null;
|
|
182
|
+
return `${join(paperDir, CONFIG_FILE)}: ${p.problem.why}`;
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=presets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presets.js","sourceRoot":"","sources":["../src/presets.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { Files } from "./ports/files.ts";
|
|
2
|
+
interface Loc {
|
|
3
|
+
readonly line: number;
|
|
4
|
+
readonly column: number;
|
|
5
|
+
}
|
|
6
|
+
interface RuleContext {
|
|
7
|
+
readonly filename: string;
|
|
8
|
+
readonly cwd: string;
|
|
9
|
+
readonly sourceCode: {
|
|
10
|
+
getLocFromIndex(i: number): Loc;
|
|
11
|
+
};
|
|
12
|
+
report(d: {
|
|
13
|
+
loc: {
|
|
14
|
+
start: Loc;
|
|
15
|
+
end: Loc;
|
|
16
|
+
};
|
|
17
|
+
messageId: string;
|
|
18
|
+
data?: Record<string, string>;
|
|
19
|
+
}): void;
|
|
20
|
+
}
|
|
21
|
+
export interface ReferenceRuleModule {
|
|
22
|
+
readonly meta: {
|
|
23
|
+
readonly type: "problem" | "suggestion";
|
|
24
|
+
readonly docs: {
|
|
25
|
+
readonly description: string;
|
|
26
|
+
};
|
|
27
|
+
readonly schema: readonly object[];
|
|
28
|
+
readonly messages: Readonly<Record<string, string>>;
|
|
29
|
+
};
|
|
30
|
+
create(context: RuleContext): {
|
|
31
|
+
"root:exit"?: () => void;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
type Name = "author-list" | "cite-exists" | "refs-checked" | "refs-fresh";
|
|
35
|
+
/** The four rules, reading through `files`. They act on `paper.tex` only. */
|
|
36
|
+
export declare function referenceRules({ files, }: {
|
|
37
|
+
files: Files;
|
|
38
|
+
}): Record<Name, ReferenceRuleModule>;
|
|
39
|
+
/** The level each is on at for every `paper.tex` in paperlint's own config. */
|
|
40
|
+
export declare const REFERENCE_RULE_LEVELS: {
|
|
41
|
+
readonly "paper/author-list": "error";
|
|
42
|
+
readonly "paper/cite-exists": "error";
|
|
43
|
+
readonly "paper/refs-checked": "warn";
|
|
44
|
+
readonly "paper/refs-fresh": "error";
|
|
45
|
+
};
|
|
46
|
+
export {};
|
|
47
|
+
//# sourceMappingURL=reference-rules.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reference-rules.d.ts","sourceRoot":"","sources":["../src/reference-rules.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAS9C,UAAU,GAAG;IACX,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AACD,UAAU,WAAW;IACnB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,UAAU,EAAE;QACnB,eAAe,CAAC,CAAC,EAAE,MAAM,GAAG,GAAG,CAAC;KACjC,CAAC;IACF,MAAM,CAAC,CAAC,EAAE;QACR,GAAG,EAAE;YAAE,KAAK,EAAE,GAAG,CAAC;YAAC,GAAG,EAAE,GAAG,CAAA;SAAE,CAAC;QAC9B,SAAS,EAAE,MAAM,CAAC;QAClB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KAC/B,GAAG,IAAI,CAAC;CACV;AACD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE;QACb,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,YAAY,CAAC;QACxC,QAAQ,CAAC,IAAI,EAAE;YAAE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;SAAE,CAAC;QAChD,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;QACnC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;KACrD,CAAC;IACF,MAAM,CAAC,OAAO,EAAE,WAAW,GAAG;QAAE,WAAW,CAAC,EAAE,MAAM,IAAI,CAAA;KAAE,CAAC;CAC5D;AAED,KAAK,IAAI,GAAG,aAAa,GAAG,aAAa,GAAG,cAAc,GAAG,YAAY,CAAC;AAgI1E,6EAA6E;AAC7E,wBAAgB,cAAc,CAAC,EAC7B,KAAK,GACN,EAAE;IACD,KAAK,EAAE,KAAK,CAAC;CACd,GAAG,MAAM,CAAC,IAAI,EAAE,mBAAmB,CAAC,CAiCpC;AAED,+EAA+E;AAC/E,eAAO,MAAM,qBAAqB;;;;;CAKxB,CAAC"}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The reference rules — `paper/author-list`, `paper/cite-exists`, `paper/refs-checked`,
|
|
3
|
+
* `paper/refs-fresh` — judge `_build/references.json` (`references.ts`), offline. `paperlint build`
|
|
4
|
+
* does the online work; lint never touches the network.
|
|
5
|
+
*
|
|
6
|
+
* entry whose authors are the preprint's paper/author-list (error), on the entry
|
|
7
|
+
* entry whose identifier provably fails paper/cite-exists (error), on the entry
|
|
8
|
+
* no record, or recorded "not checked" paper/refs-checked (warn) — like pdf/measured
|
|
9
|
+
* bibliography edited after the build paper/refs-fresh (error) — like pdf/fresh
|
|
10
|
+
*
|
|
11
|
+
* While the record is stale, the per-entry rules are silent: they would judge a bibliography
|
|
12
|
+
* that no longer exists, and refs-fresh already says so once. A paper with no bibliography gets
|
|
13
|
+
* nothing.
|
|
14
|
+
*
|
|
15
|
+
* `paper/author-list` used to live on PIPELINE-STATUS.md and ask whether the scorecard mentioned
|
|
16
|
+
* a run. It lives here now because its subject is the bibliography, and the record of the run is
|
|
17
|
+
* the run's own output.
|
|
18
|
+
*/
|
|
19
|
+
import { basename, dirname } from "node:path";
|
|
20
|
+
import { bibHash, bibliographyOf, readReferences, REFERENCES_FILE, } from "./references.js";
|
|
21
|
+
function assess(files, paperDir) {
|
|
22
|
+
const bib = bibliographyOf(files, paperDir);
|
|
23
|
+
if (bib === null)
|
|
24
|
+
return { kind: "no-bibliography" };
|
|
25
|
+
const doc = readReferences(files, paperDir);
|
|
26
|
+
if (doc === null)
|
|
27
|
+
return { kind: "unrecorded" };
|
|
28
|
+
if (doc.bib.sha256 !== bibHash(bib))
|
|
29
|
+
return { kind: "stale" };
|
|
30
|
+
if (doc.status === "not-checked")
|
|
31
|
+
return { kind: "not-checked", why: doc.why ?? "no reason recorded" };
|
|
32
|
+
const failing = doc.entries.flatMap((e) => [
|
|
33
|
+
...(e.authors === "mismatch"
|
|
34
|
+
? [{ key: e.key, rule: "author-list", why: e.why ?? "" }]
|
|
35
|
+
: []),
|
|
36
|
+
...(e.exists === "false"
|
|
37
|
+
? [{ key: e.key, rule: "cite-exists", why: e.why ?? "" }]
|
|
38
|
+
: []),
|
|
39
|
+
]);
|
|
40
|
+
return { kind: "ready", bib, failing };
|
|
41
|
+
}
|
|
42
|
+
/** Where entry `key` starts in the source file: its `@type{key,` line, or the file's start. */
|
|
43
|
+
function entryOffset(bib, key) {
|
|
44
|
+
const escaped = key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
45
|
+
const m = new RegExp(`^@\\w+\\s*\\{\\s*${escaped}\\s*,`, "m").exec(bib.text);
|
|
46
|
+
return m ? bib.offset + m.index : 0;
|
|
47
|
+
}
|
|
48
|
+
const BUILD = "`npx paperlint build`";
|
|
49
|
+
const META = {
|
|
50
|
+
"author-list": {
|
|
51
|
+
type: "problem",
|
|
52
|
+
docs: {
|
|
53
|
+
description: "each entry's authors are those of the version it cites, not the preprint's (recorded by paperlint build)",
|
|
54
|
+
},
|
|
55
|
+
schema: [],
|
|
56
|
+
messages: {
|
|
57
|
+
mismatch: "`{{key}}`: the authors are not those of the version cited — {{why}}. The citation resolves and the id resolves, and the list is the PREPRINT's under a published venue",
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
"cite-exists": {
|
|
61
|
+
type: "problem",
|
|
62
|
+
docs: {
|
|
63
|
+
description: "each entry's identifier resolves to the work cited (recorded by paperlint build)",
|
|
64
|
+
},
|
|
65
|
+
schema: [],
|
|
66
|
+
messages: {
|
|
67
|
+
missing: "`{{key}}` does not resolve to the work cited — {{why}}",
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
"refs-checked": {
|
|
71
|
+
type: "suggestion",
|
|
72
|
+
docs: {
|
|
73
|
+
description: "the build checked the references online (existence, title, authors); a warning when it could not",
|
|
74
|
+
},
|
|
75
|
+
schema: [],
|
|
76
|
+
messages: {
|
|
77
|
+
unrecorded: `the references have not been checked — ${BUILD} checks them online and records the result in _build/${REFERENCES_FILE}`,
|
|
78
|
+
notChecked: `the last build could not check the references ({{why}}) — run ${BUILD} with network`,
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
"refs-fresh": {
|
|
82
|
+
type: "problem",
|
|
83
|
+
docs: {
|
|
84
|
+
description: "the recorded reference verdicts are about the bibliography on disk, not an earlier one",
|
|
85
|
+
},
|
|
86
|
+
schema: [],
|
|
87
|
+
messages: {
|
|
88
|
+
stale: `the references changed since the last build checked them — run ${BUILD}`,
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
const JUDGES = {
|
|
93
|
+
"author-list": (a) => a.kind === "ready"
|
|
94
|
+
? a.failing
|
|
95
|
+
.filter((f) => f.rule === "author-list")
|
|
96
|
+
.map((f) => ({
|
|
97
|
+
at: entryOffset(a.bib, f.key),
|
|
98
|
+
messageId: "mismatch",
|
|
99
|
+
data: { key: f.key, why: f.why },
|
|
100
|
+
}))
|
|
101
|
+
: [],
|
|
102
|
+
"cite-exists": (a) => a.kind === "ready"
|
|
103
|
+
? a.failing
|
|
104
|
+
.filter((f) => f.rule === "cite-exists")
|
|
105
|
+
.map((f) => ({
|
|
106
|
+
at: entryOffset(a.bib, f.key),
|
|
107
|
+
messageId: "missing",
|
|
108
|
+
data: { key: f.key, why: f.why },
|
|
109
|
+
}))
|
|
110
|
+
: [],
|
|
111
|
+
"refs-checked": (a) => a.kind === "unrecorded"
|
|
112
|
+
? [{ at: 0, messageId: "unrecorded" }]
|
|
113
|
+
: a.kind === "not-checked"
|
|
114
|
+
? [{ at: 0, messageId: "notChecked", data: { why: a.why } }]
|
|
115
|
+
: [],
|
|
116
|
+
"refs-fresh": (a) => a.kind === "stale" ? [{ at: 0, messageId: "stale" }] : [],
|
|
117
|
+
};
|
|
118
|
+
/** The four rules, reading through `files`. They act on `paper.tex` only. */
|
|
119
|
+
export function referenceRules({ files, }) {
|
|
120
|
+
const make = (name) => ({
|
|
121
|
+
meta: META[name],
|
|
122
|
+
create: (context) => basename(context.filename) !== "paper.tex"
|
|
123
|
+
? {}
|
|
124
|
+
: {
|
|
125
|
+
"root:exit": () => {
|
|
126
|
+
const paperDir = dirname(context.filename);
|
|
127
|
+
const a = assess(files, paperDir);
|
|
128
|
+
// An external refs.bib: the entry is not in this file, so the finding sits at its
|
|
129
|
+
// start and names the key.
|
|
130
|
+
const external = a.kind === "ready" && a.bib.source !== "paper.tex";
|
|
131
|
+
for (const r of JUDGES[name](a)) {
|
|
132
|
+
const loc = context.sourceCode.getLocFromIndex(external ? 0 : r.at);
|
|
133
|
+
context.report({
|
|
134
|
+
loc: { start: loc, end: loc },
|
|
135
|
+
messageId: r.messageId,
|
|
136
|
+
...(r.data ? { data: r.data } : {}),
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
return {
|
|
143
|
+
"author-list": make("author-list"),
|
|
144
|
+
"cite-exists": make("cite-exists"),
|
|
145
|
+
"refs-checked": make("refs-checked"),
|
|
146
|
+
"refs-fresh": make("refs-fresh"),
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
/** The level each is on at for every `paper.tex` in paperlint's own config. */
|
|
150
|
+
export const REFERENCE_RULE_LEVELS = {
|
|
151
|
+
"paper/author-list": "error",
|
|
152
|
+
"paper/cite-exists": "error",
|
|
153
|
+
"paper/refs-checked": "warn",
|
|
154
|
+
"paper/refs-fresh": "error",
|
|
155
|
+
};
|
|
156
|
+
//# sourceMappingURL=reference-rules.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reference-rules.js","sourceRoot":"","sources":["../src/reference-rules.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { Files } from "./ports/files.ts";
|
|
2
|
+
import type { CheckReferences, EntryVerdict, ReferencesCheck } from "./ports/check-references.ts";
|
|
3
|
+
export declare const REFERENCES_SCHEMA = 1;
|
|
4
|
+
export declare const REFERENCES_FILE = "references.json";
|
|
5
|
+
/** Where a paper's reference verdicts live — beside `paper.facts.json`. */
|
|
6
|
+
export declare const referencesPath: (paperDir: string) => string;
|
|
7
|
+
/** The bibliography a paper carries: inside `paper.tex` (`filecontents`), else `refs.bib`. */
|
|
8
|
+
export interface Bibliography {
|
|
9
|
+
readonly source: "paper.tex" | "refs.bib";
|
|
10
|
+
readonly text: string;
|
|
11
|
+
/** Where `text` starts in the source file — so a finding can point at an entry. */
|
|
12
|
+
readonly offset: number;
|
|
13
|
+
}
|
|
14
|
+
export declare function bibliographyOf(files: Files, paperDir: string): Bibliography | null;
|
|
15
|
+
export declare const bibHash: (b: Bibliography) => string;
|
|
16
|
+
/** What `_build/references.json` holds. */
|
|
17
|
+
export interface ReferencesDocument {
|
|
18
|
+
readonly schema: number;
|
|
19
|
+
readonly bib: {
|
|
20
|
+
readonly source: string;
|
|
21
|
+
readonly sha256: string;
|
|
22
|
+
};
|
|
23
|
+
readonly status: "checked" | "not-checked";
|
|
24
|
+
readonly why?: string;
|
|
25
|
+
readonly entries: readonly EntryVerdict[];
|
|
26
|
+
}
|
|
27
|
+
export declare const documentOf: (bib: Bibliography, check: ReferencesCheck) => ReferencesDocument;
|
|
28
|
+
/** The recorded verdicts, or null when there are none or they do not parse. */
|
|
29
|
+
export declare function readReferences(files: Files, paperDir: string): ReferencesDocument | null;
|
|
30
|
+
/**
|
|
31
|
+
* The build step's work: check the bibliography and record the verdicts. Returns the one-line
|
|
32
|
+
* note the build prints. A checker that throws is recorded as `not-checked` — the step reports,
|
|
33
|
+
* it never refuses.
|
|
34
|
+
*/
|
|
35
|
+
export declare function recordReferences(files: Files, paperDir: string, check: CheckReferences): Promise<string>;
|
|
36
|
+
//# sourceMappingURL=references.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"references.d.ts","sourceRoot":"","sources":["../src/references.ts"],"names":[],"mappings":"AA0BA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,KAAK,EACV,eAAe,EACf,YAAY,EACZ,eAAe,EAChB,MAAM,6BAA6B,CAAC;AAIrC,eAAO,MAAM,iBAAiB,IAAI,CAAC;AACnC,eAAO,MAAM,eAAe,oBAAoB,CAAC;AAEjD,2EAA2E;AAC3E,eAAO,MAAM,cAAc,GAAI,UAAU,MAAM,KAAG,MACP,CAAC;AAQ5C,8FAA8F;AAC9F,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,MAAM,EAAE,WAAW,GAAG,UAAU,CAAC;IAC1C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,mFAAmF;IACnF,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,wBAAgB,cAAc,CAC5B,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,MAAM,GACf,YAAY,GAAG,IAAI,CAOrB;AAED,eAAO,MAAM,OAAO,GAAI,GAAG,YAAY,KAAG,MACG,CAAC;AAE9C,2CAA2C;AAC3C,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,GAAG,EAAE;QAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IACnE,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,aAAa,CAAC;IAC3C,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,CAAC;CAC3C;AAED,eAAO,MAAM,UAAU,GACrB,KAAK,YAAY,EACjB,OAAO,eAAe,KACrB,kBAMD,CAAC;AAEH,+EAA+E;AAC/E,wBAAgB,cAAc,CAC5B,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,MAAM,GACf,kBAAkB,GAAG,IAAI,CAW3B;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,eAAe,GACrB,OAAO,CAAC,MAAM,CAAC,CAoBjB"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THE REFERENCES A BUILD CHECKED — `<paper>/_build/references.json`, written by `paperlint build`
|
|
3
|
+
* and read, offline, by the lint rules in `reference-rules.ts`.
|
|
4
|
+
*
|
|
5
|
+
* The package ships two online checks: `verify-cites` (the cited work exists and its title
|
|
6
|
+
* matches) and `bib-authors` (the authors are those of the version cited, not the preprint's).
|
|
7
|
+
* Until 3.0.0 lint could only ask whether someone had run them — by finding the word
|
|
8
|
+
* "bib-authors" in a scorecard table, or a command the project configured. Now the build runs
|
|
9
|
+
* them and records the result as data, beside the facts it already writes about the PDF:
|
|
10
|
+
*
|
|
11
|
+
* { "schema": 1,
|
|
12
|
+
* "bib": { "source": "paper.tex", "sha256": "…" }, the bibliography that was checked
|
|
13
|
+
* "status": "checked" | "not-checked", "why": "…", not-checked: nothing could be asked
|
|
14
|
+
* "entries": [ { "key", "exists", "authors", "why" } ] }
|
|
15
|
+
*
|
|
16
|
+
* A sibling file, not a new field of `paper.facts.json`: those facts are about ONE PDF and are
|
|
17
|
+
* stale when it changes (`pdf_sha256`); these are about the bibliography and are stale when IT
|
|
18
|
+
* changes (`bib.sha256`). One staleness key per file, the way `pdf/fresh` already works.
|
|
19
|
+
*
|
|
20
|
+
* 🔴 THE STEP NEVER FAILS THE BUILD. A build without network still builds the PDF; the reference
|
|
21
|
+
* step records `not-checked` and the lint rule says so, as a warning. Recording "not checked" as
|
|
22
|
+
* a pass would be the counter that counts what it never looked at.
|
|
23
|
+
*/
|
|
24
|
+
import { join } from "node:path";
|
|
25
|
+
import { sha256Hex } from "./domain/sha256.js";
|
|
26
|
+
// @ts-expect-error — an ESLint rule module in .mjs, it has no types
|
|
27
|
+
import { bibRange } from "../eslint-rules/paper-typography.mjs";
|
|
28
|
+
export const REFERENCES_SCHEMA = 1;
|
|
29
|
+
export const REFERENCES_FILE = "references.json";
|
|
30
|
+
/** Where a paper's reference verdicts live — beside `paper.facts.json`. */
|
|
31
|
+
export const referencesPath = (paperDir) => join(paperDir, "_build", REFERENCES_FILE);
|
|
32
|
+
const at = (p) => p;
|
|
33
|
+
const text = (files, p) => {
|
|
34
|
+
const b = files.readBytes(at(p));
|
|
35
|
+
return b === null ? null : new TextDecoder().decode(b);
|
|
36
|
+
};
|
|
37
|
+
export function bibliographyOf(files, paperDir) {
|
|
38
|
+
const tex = text(files, join(paperDir, "paper.tex"));
|
|
39
|
+
const inline = tex === null ? null : bibRange(tex);
|
|
40
|
+
if (inline)
|
|
41
|
+
return { source: "paper.tex", text: inline.body, offset: inline.bodyStart };
|
|
42
|
+
const bib = text(files, join(paperDir, "refs.bib"));
|
|
43
|
+
return bib === null ? null : { source: "refs.bib", text: bib, offset: 0 };
|
|
44
|
+
}
|
|
45
|
+
export const bibHash = (b) => sha256Hex(new TextEncoder().encode(b.text));
|
|
46
|
+
export const documentOf = (bib, check) => ({
|
|
47
|
+
schema: REFERENCES_SCHEMA,
|
|
48
|
+
bib: { source: bib.source, sha256: bibHash(bib) },
|
|
49
|
+
...(check.kind === "checked"
|
|
50
|
+
? { status: "checked", entries: check.entries }
|
|
51
|
+
: { status: "not-checked", why: check.why, entries: [] }),
|
|
52
|
+
});
|
|
53
|
+
/** The recorded verdicts, or null when there are none or they do not parse. */
|
|
54
|
+
export function readReferences(files, paperDir) {
|
|
55
|
+
const raw = text(files, referencesPath(paperDir));
|
|
56
|
+
if (raw === null)
|
|
57
|
+
return null;
|
|
58
|
+
try {
|
|
59
|
+
const d = JSON.parse(raw);
|
|
60
|
+
return d?.schema === REFERENCES_SCHEMA && Array.isArray(d.entries)
|
|
61
|
+
? d
|
|
62
|
+
: null;
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* The build step's work: check the bibliography and record the verdicts. Returns the one-line
|
|
70
|
+
* note the build prints. A checker that throws is recorded as `not-checked` — the step reports,
|
|
71
|
+
* it never refuses.
|
|
72
|
+
*/
|
|
73
|
+
export async function recordReferences(files, paperDir, check) {
|
|
74
|
+
const bib = bibliographyOf(files, paperDir);
|
|
75
|
+
if (bib === null)
|
|
76
|
+
return "no bibliography — nothing to check";
|
|
77
|
+
let result;
|
|
78
|
+
try {
|
|
79
|
+
result = await check(bib.text);
|
|
80
|
+
}
|
|
81
|
+
catch (e) {
|
|
82
|
+
result = { kind: "not-checked", why: e.message };
|
|
83
|
+
}
|
|
84
|
+
const doc = documentOf(bib, result);
|
|
85
|
+
files.writeAtomic(at(referencesPath(paperDir)), new TextEncoder().encode(`${JSON.stringify(doc, null, 2)}\n`));
|
|
86
|
+
if (doc.status === "not-checked")
|
|
87
|
+
return `references NOT checked — ${doc.why ?? "no reason given"}; lint will say so`;
|
|
88
|
+
const bad = doc.entries.filter((e) => e.exists === "false" || e.authors === "mismatch").length;
|
|
89
|
+
return `references: ${String(doc.entries.length)} checked, ${String(bad)} failing → _build/${REFERENCES_FILE}`;
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=references.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"references.js","sourceRoot":"","sources":["../src/references.ts"],"names":[],"mappings":"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"}
|
package/dist/rules-config.d.ts
CHANGED
|
@@ -18,10 +18,19 @@ export type Parsed<T> = {
|
|
|
18
18
|
/** Every top-level key must be one paperlint or its skills read. */
|
|
19
19
|
export declare function unknownKeys(settings: Record<string, unknown>): string[];
|
|
20
20
|
/**
|
|
21
|
-
*
|
|
21
|
+
* A `rules` object — rule id → severity or `[severity, ...options]` — with only the rules paperlint
|
|
22
|
+
* ships. Read from every `paperlint.json`, the root's and each paper's.
|
|
23
|
+
*
|
|
24
|
+
* @param where the key path to name in messages, e.g. `package.json → "paperlint".rules[0].rules`
|
|
25
|
+
*/
|
|
26
|
+
export declare function parseRuleEntries(v: unknown, where: string, shipped: ReadonlySet<string>): Parsed<Record<string, RuleEntry>>;
|
|
27
|
+
/**
|
|
28
|
+
* The `rules` key → config blocks, or one error naming the key path. Two shapes, at every level:
|
|
29
|
+
* `{ id: severity }` is one block over every paper file under `baseDir`; a list is ESLint blocks
|
|
30
|
+
* (`files`, `ignores`, `rules`), their globs relative to `baseDir`.
|
|
22
31
|
*
|
|
23
32
|
* @param raw the value under `rules` (undefined when absent)
|
|
24
|
-
* @param where how the settings are named in messages, e.g. `
|
|
33
|
+
* @param where how the settings are named in messages, e.g. `paperlint.json`
|
|
25
34
|
* @param shipped the rule ids paperlint ships (`shippedRuleIds`)
|
|
26
35
|
* @param baseDir the directory of the file holding the settings
|
|
27
36
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rules-config.d.ts","sourceRoot":"","sources":["../src/rules-config.ts"],"names":[],"mappings":"AA6BA,qDAAqD;AACrD,MAAM,MAAM,QAAQ,GAAG,KAAK,GAAG,MAAM,GAAG,OAAO,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAC5D,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC,QAAQ,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC;AAErE,yFAAyF;AACzF,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;CACrD;AAED,MAAM,MAAM,MAAM,CAAC,CAAC,IAChB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAA;CAAE,GACxC;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"rules-config.d.ts","sourceRoot":"","sources":["../src/rules-config.ts"],"names":[],"mappings":"AA6BA,qDAAqD;AACrD,MAAM,MAAM,QAAQ,GAAG,KAAK,GAAG,MAAM,GAAG,OAAO,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAC5D,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC,QAAQ,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC;AAErE,yFAAyF;AACzF,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;CACrD;AAED,MAAM,MAAM,MAAM,CAAC,CAAC,IAChB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAA;CAAE,GACxC;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAQnD,oEAAoE;AACpE,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,EAAE,CAEvE;AAcD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,CAAC,EAAE,OAAO,EACV,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,GAC3B,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAiBnC;AA6CD;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,EAC5B,OAAO,EAAE,MAAM,GACd,MAAM,CAAC,SAAS,SAAS,EAAE,CAAC,CAmB9B;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,SAAS,OAAO,EAAE,EAC1B,OAAO,EAAE,SAAS,OAAO,EAAE,GAC1B,GAAG,CAAC,MAAM,CAAC,CAWb"}
|