paperlint 2.0.1 → 2.1.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/CONTRIBUTING.md +21 -0
- package/README.md +56 -14
- 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 +1 -1
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +4 -3
- package/dist/build.js.map +1 -1
- package/dist/cli.d.ts +15 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +138 -24
- package/dist/cli.js.map +1 -1
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +21 -4
- 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/init.d.ts +11 -0
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +67 -3
- package/dist/init.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 +17 -2
- package/dist/new-paper.js.map +1 -1
- package/dist/paper-settings.d.ts +68 -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/presets.d.ts +84 -0
- package/dist/presets.d.ts.map +1 -0
- package/dist/presets.js +186 -0
- package/dist/presets.js.map +1 -0
- package/dist/rules-config.d.ts +7 -0
- package/dist/rules-config.d.ts.map +1 -1
- package/dist/rules-config.js +11 -6
- package/dist/rules-config.js.map +1 -1
- package/dist/structure.d.ts.map +1 -1
- package/dist/structure.js +2 -1
- 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/venue-rules.d.ts +109 -0
- package/dist/venue-rules.d.ts.map +1 -0
- package/dist/venue-rules.js +387 -0
- package/dist/venue-rules.js.map +1 -0
- package/docs/configuration.md +67 -7
- package/docs/optional-rules.md +25 -24
- package/docs/rules.md +131 -2
- package/eslint-rules/papers.mjs +6 -2
- package/eslint-rules/pdf-last-page-balance.mjs +23 -2
- package/fixtures/build-e2e/acmart/paperlint.json +1 -0
- package/lib/paper-config.d.mts +7 -0
- package/lib/paper-config.mjs +31 -0
- package/package.json +1 -1
- package/skills/find-venue/SKILL.md +5 -1
- package/skills/find-venue/SKILL.md.spec.ts +4 -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/render-paper/extract-pdf-facts.harness.mjs +5 -5
- package/skills/render-paper/extract-pdf-facts.mjs +4 -4
- 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/src/build-engine.ts +10 -2
- package/src/build.harness.mjs +23 -18
- package/src/build.ts +5 -4
- package/src/cli.harness.mjs +4 -2
- package/src/cli.ts +158 -29
- package/src/doctor.ts +28 -3
- package/src/facts-file.test.ts +54 -7
- package/src/facts-file.ts +145 -24
- package/src/init.ts +81 -3
- package/src/new-paper.harness.mjs +9 -6
- package/src/new-paper.test.ts +145 -0
- package/src/new-paper.ts +22 -2
- package/src/paper-settings-commands.test.ts +311 -0
- package/src/paper-settings.test.ts +220 -0
- package/src/paper-settings.ts +206 -0
- package/src/presets.test.ts +236 -0
- package/src/presets.ts +307 -0
- package/src/rules-config.ts +12 -7
- package/src/structure.harness.mjs +3 -3
- package/src/structure.ts +2 -1
- package/src/tex-requirements.harness.mjs +11 -17
- package/src/tex-requirements.ts +179 -29
- package/src/venue-rules.test.ts +545 -0
- package/src/venue-rules.ts +573 -0
- package/templates/paper/paperlint.json +4 -0
- package/fixtures/build-e2e/acmart/venue.json +0 -1
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THE VENUE RULES — a built PDF judged against the format its venue's call for papers sets.
|
|
3
|
+
*
|
|
4
|
+
* pdf/fresh error the facts describe the PDF on disk (not an earlier build)
|
|
5
|
+
* pdf/profile error the preset the paper extends resolves, and the kind it names exists
|
|
6
|
+
* pdf/fonts error every font is embedded, none is Type 3, the venue's families are present
|
|
7
|
+
* pdf/geometry error page size and column count match the preset
|
|
8
|
+
* pdf/limits error body and reference pages within the kind's limit; reference font size
|
|
9
|
+
* pdf/body-size warn body font size within the preset's tolerance
|
|
10
|
+
* pdf/measured warn the venue checks ran at all (a preset is named, facts exist, geometry measured)
|
|
11
|
+
*
|
|
12
|
+
* ── WHAT THEY READ ───────────────────────────────────────────────────────────────
|
|
13
|
+
* Like `pdf/last-page-balance`, they run on a paper's `paper.tex` and judge the files beside it:
|
|
14
|
+
* `paperlint.json` (which preset, which kind), `_build/paper.facts.json` (what `paperlint build`
|
|
15
|
+
* measured) and the PDF the facts name (hashed, never measured). The preset is resolved by
|
|
16
|
+
* `paperPreset` in `src/presets.ts` — the same resolution the build, the toolchain and the lint
|
|
17
|
+
* config use — so there is one answer to "which venue is this paper judged against".
|
|
18
|
+
*
|
|
19
|
+
* The venue is taken from `paperlint.json`, not from the facts: the facts are venue-independent
|
|
20
|
+
* measurements, and a paper whose `paperlint.json` changed after the build is judged against the venue
|
|
21
|
+
* it names now.
|
|
22
|
+
*
|
|
23
|
+
* ── WHO SPEAKS WHEN THE INPUT CANNOT BE JUDGED ───────────────────────────────────
|
|
24
|
+
* One rule per reason, and the others are silent — so a paper gets one finding that says what to
|
|
25
|
+
* do, not six that say the same thing:
|
|
26
|
+
*
|
|
27
|
+
* no paperlint.json every rule silent — a paper from before 2.1.0 (`paperlint new` writes one)
|
|
28
|
+
* extends null / absent pdf/measured (warn) — no venue chosen yet; it names the file to set
|
|
29
|
+
* preset does not resolve pdf/profile (error) — a typo would otherwise switch every check off
|
|
30
|
+
* not built / no facts pdf/measured (warn) — lint often runs before or without a build (the
|
|
31
|
+
* CI action only lints); a warning is printed and does not fail
|
|
32
|
+
* facts about another PDF pdf/fresh (error) — judging them would judge an earlier build
|
|
33
|
+
* no geometry (no banal) pdf/measured (warn); geometry, limits, body-size silent; fonts still judge
|
|
34
|
+
* kind does not resolve pdf/profile (error); limits silent; everything else still judges
|
|
35
|
+
*/
|
|
36
|
+
import { dirname, isAbsolute, join, basename, relative } from "node:path";
|
|
37
|
+
import { FACTS_DIR, FACTS_FILE, factsPath, parseFactsText, } from "./facts-file.js";
|
|
38
|
+
import { paperPreset, presetProblemText } from "./presets.js";
|
|
39
|
+
import { sha256Hex } from "./domain/sha256.js";
|
|
40
|
+
import { LEGACY_PAPER_SETTINGS_MESSAGE, PAPER_SETTINGS_FILE, } from "../lib/paper-config.mjs";
|
|
41
|
+
const finding = (messageId, data = {}) => ({ messageId, data });
|
|
42
|
+
const at = (p) => p;
|
|
43
|
+
const text = (files, p) => {
|
|
44
|
+
const b = files.readBytes(at(p));
|
|
45
|
+
return b === null ? null : new TextDecoder().decode(b);
|
|
46
|
+
};
|
|
47
|
+
// ── resolving the declaration ────────────────────────────────────────────────────────
|
|
48
|
+
function kindOf(venue, format, kind) {
|
|
49
|
+
const known = [...format.kinds.keys()].join(", ") || "(none)";
|
|
50
|
+
if (kind === null)
|
|
51
|
+
return {
|
|
52
|
+
kind: null,
|
|
53
|
+
kindProblem: finding("kindMissing", { venue, known }),
|
|
54
|
+
};
|
|
55
|
+
const limits = format.kinds.get(kind);
|
|
56
|
+
return limits
|
|
57
|
+
? { kind: { name: kind, limits }, kindProblem: null }
|
|
58
|
+
: {
|
|
59
|
+
kind: null,
|
|
60
|
+
kindProblem: finding("kindUnknown", { venue, kind, known }),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/** The facts about the PDF on disk, or the `pdf/fresh` finding that says why they are not. */
|
|
64
|
+
function freshFacts(files, paperDir, body) {
|
|
65
|
+
const parsed = parseFactsText(body);
|
|
66
|
+
if (!parsed.ok)
|
|
67
|
+
return parsed.error.kind === "schema"
|
|
68
|
+
? finding("schema", { got: parsed.error.got })
|
|
69
|
+
: finding("factsBroken", { why: parsed.error.why });
|
|
70
|
+
const f = parsed.value;
|
|
71
|
+
const pdf = files.readBytes(at(isAbsolute(f.pdf) ? f.pdf : join(paperDir, f.pdf)));
|
|
72
|
+
if (pdf === null)
|
|
73
|
+
return finding("pdfMissing", { pdf: f.pdf });
|
|
74
|
+
return sha256Hex(pdf) === f.sha ? f : finding("stale", { pdf: f.pdf });
|
|
75
|
+
}
|
|
76
|
+
const isFinding = (v) => "messageId" in v;
|
|
77
|
+
/** One paper, assessed. Reads through `deps.files` only; never throws on a paper's files. */
|
|
78
|
+
export function assessPaper(paperDir, deps) {
|
|
79
|
+
const p = paperPreset(paperDir, deps);
|
|
80
|
+
if (p.kind === "none")
|
|
81
|
+
return p.settings === null
|
|
82
|
+
? { kind: "no-venue" }
|
|
83
|
+
: { kind: "no-preset", file: join(paperDir, PAPER_SETTINGS_FILE) };
|
|
84
|
+
if (p.kind === "settings-problem")
|
|
85
|
+
return {
|
|
86
|
+
kind: "unresolved",
|
|
87
|
+
finding: p.problem.kind === "legacy"
|
|
88
|
+
? finding("legacySettings")
|
|
89
|
+
: finding("settingsBroken", { why: p.problem.why }),
|
|
90
|
+
};
|
|
91
|
+
if (p.kind === "preset-problem")
|
|
92
|
+
return {
|
|
93
|
+
kind: "unresolved",
|
|
94
|
+
finding: finding("preset", { why: presetProblemText(p.problem) }),
|
|
95
|
+
};
|
|
96
|
+
const label = p.preset.label;
|
|
97
|
+
const venue = {
|
|
98
|
+
venue: label,
|
|
99
|
+
format: p.preset.format,
|
|
100
|
+
...kindOf(label, p.preset.format, p.settings.kind),
|
|
101
|
+
};
|
|
102
|
+
const factsText = text(deps.files, factsPath(paperDir));
|
|
103
|
+
if (factsText === null)
|
|
104
|
+
return { kind: "unbuilt", venue };
|
|
105
|
+
const facts = freshFacts(deps.files, paperDir, factsText);
|
|
106
|
+
return isFinding(facts)
|
|
107
|
+
? { kind: "stale", finding: facts }
|
|
108
|
+
: { kind: "ready", venue, facts };
|
|
109
|
+
}
|
|
110
|
+
// ── the judges: typed facts + typed format → findings. Pure. ─────────────────────────
|
|
111
|
+
/** Type 3, not embedded, and each family the venue names missing from every font. */
|
|
112
|
+
export function judgeFonts(fonts, format, venue) {
|
|
113
|
+
const out = [];
|
|
114
|
+
for (const f of fonts) {
|
|
115
|
+
if (f.program === "Type3")
|
|
116
|
+
out.push(finding("type3", { name: f.name }));
|
|
117
|
+
if (!f.embedded)
|
|
118
|
+
out.push(finding("notEmbedded", { name: f.name }));
|
|
119
|
+
}
|
|
120
|
+
const names = [...new Set(fonts.map((f) => f.name))];
|
|
121
|
+
const families = [
|
|
122
|
+
[format.fontsText, "body text"],
|
|
123
|
+
[format.fontsTitle, "headings"],
|
|
124
|
+
];
|
|
125
|
+
for (const [prefix, what] of families)
|
|
126
|
+
if (prefix !== null && !names.some((n) => n.startsWith(prefix)))
|
|
127
|
+
out.push(finding("noFamily", {
|
|
128
|
+
prefix,
|
|
129
|
+
what,
|
|
130
|
+
venue,
|
|
131
|
+
have: names.slice(0, 8).join(", ") || "(no fonts)",
|
|
132
|
+
}));
|
|
133
|
+
return out;
|
|
134
|
+
}
|
|
135
|
+
/** Page width and height within `dimTol` inches, and the column count, against the preset. */
|
|
136
|
+
export function judgeGeometry(g, format, venue, dimTol) {
|
|
137
|
+
const out = [];
|
|
138
|
+
const dims = [
|
|
139
|
+
[format.pageWidthIn, g.page_w_in, "page width", "page_w_in"],
|
|
140
|
+
[format.pageHeightIn, g.page_h_in, "page height", "page_h_in"],
|
|
141
|
+
];
|
|
142
|
+
for (const [want, got, what, key] of dims) {
|
|
143
|
+
if (want === null)
|
|
144
|
+
continue;
|
|
145
|
+
if (got === null)
|
|
146
|
+
out.push(finding("dimMissing", { key, venue, want }));
|
|
147
|
+
else if (Math.abs(got - want) > dimTol)
|
|
148
|
+
out.push(finding("dim", { what, got, want, tol: dimTol, venue }));
|
|
149
|
+
}
|
|
150
|
+
if (format.columns !== null &&
|
|
151
|
+
g.columns !== null &&
|
|
152
|
+
g.columns !== format.columns)
|
|
153
|
+
out.push(finding("columns", { got: g.columns, want: format.columns, venue }));
|
|
154
|
+
return out;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Body and reference pages against the kind's limits, and the reference font size against the
|
|
158
|
+
* profile's range. The range is about the DECLARED size and banal measures the rendered mode, so
|
|
159
|
+
* it is widened by `body_pt_tol` — the drift the preset itself names — or a correct paper fails.
|
|
160
|
+
*/
|
|
161
|
+
export function judgeLimits(g, resolved) {
|
|
162
|
+
return [...judgePages(g, resolved), ...judgeRefPt(g, resolved)];
|
|
163
|
+
}
|
|
164
|
+
function judgePages(g, resolved) {
|
|
165
|
+
const kind = resolved.kind;
|
|
166
|
+
if (kind === null)
|
|
167
|
+
return [];
|
|
168
|
+
const pages = [
|
|
169
|
+
[kind.limits.bodyPagesMax, g.body_pages, "body pages"],
|
|
170
|
+
[kind.limits.refPagesMax, g.ref_pages, "reference pages"],
|
|
171
|
+
];
|
|
172
|
+
return pages
|
|
173
|
+
.filter(([max, got]) => max !== null && got > max)
|
|
174
|
+
.map(([max, got, what]) => finding("pages", {
|
|
175
|
+
what,
|
|
176
|
+
got,
|
|
177
|
+
max: max ?? 0,
|
|
178
|
+
venue: resolved.venue,
|
|
179
|
+
kind: kind.name,
|
|
180
|
+
}));
|
|
181
|
+
}
|
|
182
|
+
function judgeRefPt(g, resolved) {
|
|
183
|
+
const f = resolved.format;
|
|
184
|
+
const slop = f.bodyPtTol ?? 0;
|
|
185
|
+
if (f.refPtMin === null || f.refPtMax === null || g.ref_pt === null)
|
|
186
|
+
return [];
|
|
187
|
+
return g.ref_pt < f.refPtMin - slop || g.ref_pt > f.refPtMax + slop
|
|
188
|
+
? [
|
|
189
|
+
finding("refPt", {
|
|
190
|
+
got: g.ref_pt,
|
|
191
|
+
min: f.refPtMin,
|
|
192
|
+
max: f.refPtMax,
|
|
193
|
+
slop,
|
|
194
|
+
venue: resolved.venue,
|
|
195
|
+
}),
|
|
196
|
+
]
|
|
197
|
+
: [];
|
|
198
|
+
}
|
|
199
|
+
/** The body font size against `body_pt ± body_pt_tol`. */
|
|
200
|
+
export function judgeBodySize(g, format, venue) {
|
|
201
|
+
const want = format.bodyPt;
|
|
202
|
+
const tol = format.bodyPtTol;
|
|
203
|
+
if (want === null || tol === null)
|
|
204
|
+
return [];
|
|
205
|
+
if (g.body_pt === null)
|
|
206
|
+
return [finding("bodyMissing")];
|
|
207
|
+
return Math.abs(g.body_pt - want) > tol
|
|
208
|
+
? [finding("body", { got: g.body_pt, want, tol, venue })]
|
|
209
|
+
: [];
|
|
210
|
+
}
|
|
211
|
+
const REBUILD = "rebuild the paper (`paperlint build`) to rewrite it";
|
|
212
|
+
/** Which rule reports what: each takes the assessment and returns its own findings. */
|
|
213
|
+
const JUDGES = {
|
|
214
|
+
profile: (a) => a.kind === "unresolved"
|
|
215
|
+
? [a.finding]
|
|
216
|
+
: a.kind === "ready" && a.venue.kindProblem
|
|
217
|
+
? [a.venue.kindProblem]
|
|
218
|
+
: a.kind === "unbuilt" && a.venue.kindProblem
|
|
219
|
+
? [a.venue.kindProblem]
|
|
220
|
+
: [],
|
|
221
|
+
fresh: (a) => (a.kind === "stale" ? [a.finding] : []),
|
|
222
|
+
measured: (a, { shown }) => a.kind === "no-preset"
|
|
223
|
+
? [finding("noPreset", { file: shown(a.file) })]
|
|
224
|
+
: a.kind === "unbuilt"
|
|
225
|
+
? [
|
|
226
|
+
finding("unbuilt", {
|
|
227
|
+
file: `${FACTS_DIR}/${FACTS_FILE}`,
|
|
228
|
+
venue: a.venue.venue,
|
|
229
|
+
}),
|
|
230
|
+
]
|
|
231
|
+
: a.kind === "ready" && a.facts.geometry === null
|
|
232
|
+
? [finding("noGeometry")]
|
|
233
|
+
: [],
|
|
234
|
+
fonts: (a) => a.kind === "ready"
|
|
235
|
+
? judgeFonts(a.facts.fonts, a.venue.format, a.venue.venue)
|
|
236
|
+
: [],
|
|
237
|
+
geometry: (a, { options }) => a.kind === "ready" && a.facts.geometry
|
|
238
|
+
? judgeGeometry(a.facts.geometry, a.venue.format, a.venue.venue, options[0]?.dimTol ??
|
|
239
|
+
DEFAULT_DIM_TOL_IN)
|
|
240
|
+
: [],
|
|
241
|
+
limits: (a) => a.kind === "ready" && a.facts.geometry
|
|
242
|
+
? judgeLimits(a.facts.geometry, a.venue)
|
|
243
|
+
: [],
|
|
244
|
+
"body-size": (a) => a.kind === "ready" && a.facts.geometry
|
|
245
|
+
? judgeBodySize(a.facts.geometry, a.venue.format, a.venue.venue)
|
|
246
|
+
: [],
|
|
247
|
+
};
|
|
248
|
+
/** How far, in inches, a measured page dimension may be from the preset's. */
|
|
249
|
+
export const DEFAULT_DIM_TOL_IN = 0.05;
|
|
250
|
+
const META = {
|
|
251
|
+
fresh: {
|
|
252
|
+
docs: {
|
|
253
|
+
description: "the build facts describe the PDF on disk, not an earlier build",
|
|
254
|
+
},
|
|
255
|
+
messages: {
|
|
256
|
+
factsBroken: `_build/paper.facts.json cannot be read: {{why}} — ${REBUILD}`,
|
|
257
|
+
schema: `_build/paper.facts.json has schema {{got}}; the venue rules read schema 2 — ${REBUILD}`,
|
|
258
|
+
pdfMissing: "_build/paper.facts.json describes {{pdf}}, which is not on disk (a failed build removes it) — rebuild the paper",
|
|
259
|
+
stale: "_build/paper.facts.json describes a DIFFERENT {{pdf}} than the one on disk (its SHA-256 differs), so the venue checks would judge an earlier build — rebuild the paper",
|
|
260
|
+
},
|
|
261
|
+
},
|
|
262
|
+
profile: {
|
|
263
|
+
docs: {
|
|
264
|
+
description: "the venue preset a paper's paperlint.json extends resolves, and the kind it names exists",
|
|
265
|
+
},
|
|
266
|
+
messages: {
|
|
267
|
+
settingsBroken: `${PAPER_SETTINGS_FILE} cannot be read: {{why}}`,
|
|
268
|
+
legacySettings: `this paper's venue checks do not run — ${LEGACY_PAPER_SETTINGS_MESSAGE}`,
|
|
269
|
+
preset: "{{why}} — so this paper's page limit, fonts and format are not checked. Fix `extends` in its paperlint.json, or turn pdf/profile off for this paper",
|
|
270
|
+
kindMissing: `${PAPER_SETTINGS_FILE} names no \`kind\`, so the page limit of \`{{venue}}\` is not checked; its kinds: {{known}}`,
|
|
271
|
+
kindUnknown: "`{{venue}}` has no kind `{{kind}}`, so the page limit is not checked; its kinds: {{known}}",
|
|
272
|
+
},
|
|
273
|
+
},
|
|
274
|
+
measured: {
|
|
275
|
+
type: "suggestion",
|
|
276
|
+
docs: {
|
|
277
|
+
description: "the venue checks ran: the paper names a venue preset, and it was built and measured",
|
|
278
|
+
},
|
|
279
|
+
messages: {
|
|
280
|
+
unbuilt: "this paper names the venue `{{venue}}`, but {{file}} does not exist, so its page limit, fonts and format were NOT checked — run `paperlint build` before `paperlint lint`",
|
|
281
|
+
noPreset: 'this paper names no venue preset yet, so its page limit, fonts and format are not checked — set "extends" in {{file}} (e.g. "paperlint:agenticdev"; see docs/rules.md)',
|
|
282
|
+
noGeometry: "the build measured no page geometry (banal was not found or failed), so page size, columns, page limits and font sizes were NOT checked — run `paperlint toolchain`, then `paperlint build`",
|
|
283
|
+
},
|
|
284
|
+
},
|
|
285
|
+
fonts: {
|
|
286
|
+
docs: {
|
|
287
|
+
description: "every font is embedded and none is Type 3, and the venue's font families are present",
|
|
288
|
+
},
|
|
289
|
+
messages: {
|
|
290
|
+
type3: "the font {{name}} is Type 3 (a bitmap or procedure font); ACM and ACL reject such a PDF",
|
|
291
|
+
notEmbedded: "the font {{name}} is not embedded, so the reader's viewer substitutes another",
|
|
292
|
+
noFamily: "no font starts with `{{prefix}}` ({{what}} of {{venue}}); the PDF has: {{have}}. Usually a font package is missing and the class silently fell back to Computer Modern — run `paperlint toolchain`",
|
|
293
|
+
},
|
|
294
|
+
},
|
|
295
|
+
geometry: {
|
|
296
|
+
schema: [
|
|
297
|
+
{
|
|
298
|
+
type: "object",
|
|
299
|
+
properties: { dimTol: { type: "number", minimum: 0 } },
|
|
300
|
+
additionalProperties: false,
|
|
301
|
+
},
|
|
302
|
+
],
|
|
303
|
+
docs: {
|
|
304
|
+
description: "page size and column count match the venue's profile",
|
|
305
|
+
},
|
|
306
|
+
messages: {
|
|
307
|
+
dim: "{{what}} is {{got}} in, {{venue}} requires {{want}} in (tolerance {{tol}}) — the template sets the wrong paper size",
|
|
308
|
+
dimMissing: "{{venue}} sets `{{key}}` = {{want}}, and the build did not measure it — rebuild the paper",
|
|
309
|
+
columns: "{{got}} column(s), {{venue}} requires {{want}} — the wrong document class or class option",
|
|
310
|
+
},
|
|
311
|
+
},
|
|
312
|
+
limits: {
|
|
313
|
+
docs: {
|
|
314
|
+
description: "body and reference pages within the limit of the paper's kind; reference font size in range",
|
|
315
|
+
},
|
|
316
|
+
messages: {
|
|
317
|
+
pages: "{{what}}: {{got}}, over the limit {{max}} for {{venue}}/{{kind}} — a desk reject; cut the text",
|
|
318
|
+
refPt: "the reference font size is {{got}} pt, outside {{min}}–{{max}} pt for {{venue}} (allowing ±{{slop}} pt for the measuring drift) — fix the bibliography's font size",
|
|
319
|
+
},
|
|
320
|
+
},
|
|
321
|
+
"body-size": {
|
|
322
|
+
type: "suggestion",
|
|
323
|
+
docs: {
|
|
324
|
+
description: "body font size within the venue preset's tolerance (a measured mode, so a warning)",
|
|
325
|
+
},
|
|
326
|
+
messages: {
|
|
327
|
+
body: "the body font size measures {{got}} pt against {{want}} ± {{tol}} pt for {{venue}}. The measurement is the mode of the rendered text, not the declared size — check \\documentclass and its options",
|
|
328
|
+
bodyMissing: "the build did not measure a body font size — rebuild the paper",
|
|
329
|
+
},
|
|
330
|
+
},
|
|
331
|
+
};
|
|
332
|
+
/**
|
|
333
|
+
* The level each venue rule is on at in paperlint's own config, for every `paper.tex`. One owner:
|
|
334
|
+
* the config reads it, the docs describe it, a consumer overrides it in `rules`.
|
|
335
|
+
*/
|
|
336
|
+
export const VENUE_RULE_LEVELS = {
|
|
337
|
+
"pdf/fresh": "error",
|
|
338
|
+
"pdf/profile": "error",
|
|
339
|
+
"pdf/fonts": "error",
|
|
340
|
+
"pdf/geometry": "error",
|
|
341
|
+
"pdf/limits": "error",
|
|
342
|
+
"pdf/body-size": "warn",
|
|
343
|
+
"pdf/measured": "warn",
|
|
344
|
+
};
|
|
345
|
+
/** The line of `\documentclass`, where the class and its options — most of the fixes — live. */
|
|
346
|
+
function reportLine(source) {
|
|
347
|
+
const i = source
|
|
348
|
+
.split("\n")
|
|
349
|
+
.findIndex((l) => l.trimStart().startsWith("\\documentclass"));
|
|
350
|
+
return i >= 0 ? i + 1 : 1;
|
|
351
|
+
}
|
|
352
|
+
function rule(name, deps) {
|
|
353
|
+
const meta = META[name];
|
|
354
|
+
return {
|
|
355
|
+
meta: {
|
|
356
|
+
type: meta.type ?? "problem",
|
|
357
|
+
docs: meta.docs,
|
|
358
|
+
schema: meta.schema ?? [],
|
|
359
|
+
messages: meta.messages,
|
|
360
|
+
},
|
|
361
|
+
create(context) {
|
|
362
|
+
// Judged once per paper, on its paper.tex: the paper directory is the file's directory.
|
|
363
|
+
if (basename(context.filename) !== "paper.tex")
|
|
364
|
+
return {};
|
|
365
|
+
return {
|
|
366
|
+
root() {
|
|
367
|
+
const a = assessPaper(dirname(context.filename), deps);
|
|
368
|
+
const line = reportLine(context.sourceCode.text);
|
|
369
|
+
const loc = {
|
|
370
|
+
start: { line, column: 1 },
|
|
371
|
+
end: { line, column: 2 },
|
|
372
|
+
};
|
|
373
|
+
const cwd = context.cwd;
|
|
374
|
+
const shown = (p) => (cwd ? relative(cwd, p) || p : p);
|
|
375
|
+
for (const f of JUDGES[name](a, { options: context.options, shown }))
|
|
376
|
+
context.report({ loc, messageId: f.messageId, data: f.data });
|
|
377
|
+
},
|
|
378
|
+
};
|
|
379
|
+
},
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
/** The venue rules, as the rules of the `pdf` plugin (beside `last-page-balance`). */
|
|
383
|
+
export function venueRules(deps) {
|
|
384
|
+
const names = Object.keys(META);
|
|
385
|
+
return Object.fromEntries(names.map((n) => [n, rule(n, deps)]));
|
|
386
|
+
}
|
|
387
|
+
//# sourceMappingURL=venue-rules.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"venue-rules.js","sourceRoot":"","sources":["../src/venue-rules.ts"],"names":[],"mappings":"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"}
|
package/docs/configuration.md
CHANGED
|
@@ -18,8 +18,8 @@ The README carries the minimal version of this. Everything below is the full sur
|
|
|
18
18
|
"causeMarker": "Cause:",
|
|
19
19
|
"rules": [
|
|
20
20
|
{
|
|
21
|
-
"files": ["papers/
|
|
22
|
-
"rules": { "
|
|
21
|
+
"files": ["papers/old-draft/**"],
|
|
22
|
+
"rules": { "paper/typography": "off" }
|
|
23
23
|
}
|
|
24
24
|
]
|
|
25
25
|
}
|
|
@@ -57,6 +57,61 @@ Until 2026-09-24 this field was called `papers`. The old name is not read as a f
|
|
|
57
57
|
hooks stay silent instead. The name is defined once, as `PAPERS_DIR_FIELD` in
|
|
58
58
|
`lib/paper-config.mjs`.
|
|
59
59
|
|
|
60
|
+
## Three levels of settings
|
|
61
|
+
|
|
62
|
+
Each level is named after the tool, and each says something the others cannot:
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
package.json "paperlint": { … } the PROJECT: where the papers are, what every paper gets
|
|
66
|
+
papers/
|
|
67
|
+
my-paper/
|
|
68
|
+
paper.tex
|
|
69
|
+
PIPELINE-STATUS.md
|
|
70
|
+
paperlint.json { "extends": … } THIS PAPER: its venue preset, its kind, its own rules — `paperlint new` writes it
|
|
71
|
+
venues/usenix-sec.jsonc (optional, your own) a VENUE PRESET: format, page limits, TeX packages, rules
|
|
72
|
+
node_modules/paperlint/skills/submit-paper/references/venues/
|
|
73
|
+
acm-sigconf.jsonc agenticdev.jsonc aisec.jsonc realm.jsonc the shipped presets (paperlint:<name>)
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
`paperlint new` writes `<paper>/paperlint.json` from the template (`templates/paper/paperlint.json`,
|
|
77
|
+
or your `<papers>/.template/paperlint.json` if you keep one), with `"extends": null` — no venue chosen
|
|
78
|
+
yet — and a `$comment` saying what goes there. Until `extends` names a preset, `paperlint lint` gives
|
|
79
|
+
that paper one warning, `pdf/measured`: "this paper names no venue preset yet … set "extends" in
|
|
80
|
+
papers/my-paper/paperlint.json". A paper folder with no `paperlint.json` at all — one created before
|
|
81
|
+
2.1.0 — gets no venue checks and no warning; `npx paperlint new <its name>` adds the file and
|
|
82
|
+
changes nothing else.
|
|
83
|
+
|
|
84
|
+
```json
|
|
85
|
+
{
|
|
86
|
+
"extends": "paperlint:aisec",
|
|
87
|
+
"kind": "research",
|
|
88
|
+
"rules": { "pdf/body-size": "off" }
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
| key | what it is |
|
|
93
|
+
| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
94
|
+
| `extends` | the venue preset the built PDF is judged against: `paperlint:<name>` (shipped) or `./path` / `../path` (your own, relative to this file) — [`rules.md`](rules.md#checks-against-the-venue) |
|
|
95
|
+
| `kind` | the kind of paper (`short`, `research`, …) whose page limit applies |
|
|
96
|
+
| `pdf` | where the built PDF is, relative to the paper, when it is not `paper.pdf` |
|
|
97
|
+
| `rules` | rule id → severity, for this paper alone — the same entries as a `rules` block below |
|
|
98
|
+
| `$comment` | a note for humans (JSON Schema's comment keyword); ignored |
|
|
99
|
+
|
|
100
|
+
Any other key is an error naming the file and the key, as in `package.json`.
|
|
101
|
+
|
|
102
|
+
**Where a paper's rules come from, in order — a later one wins, rule by rule:** paperlint's own
|
|
103
|
+
configuration → the preset chain's `rules`, from the root preset to the one the paper extends →
|
|
104
|
+
the paper's own `rules` → the project's `rules` blocks in `package.json`. So a venue can turn a
|
|
105
|
+
rule on for its papers, a paper can turn it off for itself, and the project can still override
|
|
106
|
+
both. Only rules paperlint ships may be named, at every level.
|
|
107
|
+
|
|
108
|
+
**`paperlint.json` replaces `venue.json` (2.1.0); `npx paperlint init` moves it.** The old name is not
|
|
109
|
+
read: a paper with only a `venue.json` gets a `pdf/profile` error and `paperlint doctor` names the
|
|
110
|
+
file, both pointing at `init`. `init` writes the same settings as `paperlint.json` —
|
|
111
|
+
`"venue": "aisec"` becomes `"extends": "paperlint:aisec"`, and the `"_"` some files used as a
|
|
112
|
+
comment becomes `"$comment"` — then deletes `venue.json`. It removes a `venue.json` whose
|
|
113
|
+
`paperlint.json` already says the same, and refuses, changing nothing, when both exist and differ.
|
|
114
|
+
|
|
60
115
|
## Why the key lives in `package.json`
|
|
61
116
|
|
|
62
117
|
Because of a count: the `package.json` key has **five** readers — the three editor hooks, the
|
|
@@ -76,11 +131,15 @@ the three keys that make sense in JSON — `files`, `ignores` and `rules`. paper
|
|
|
76
131
|
**after** its own configuration, so, as in ESLint, a later block wins: a block can turn on a rule
|
|
77
132
|
that is off by default, or change the severity of one that is on.
|
|
78
133
|
|
|
134
|
+
For ONE paper, the paper's own `paperlint.json` is simpler — no glob to get wrong
|
|
135
|
+
([above](#three-levels-of-settings)). Use a block here for a rule across several papers, or to
|
|
136
|
+
override what a paper says:
|
|
137
|
+
|
|
79
138
|
```json
|
|
80
139
|
"rules": [
|
|
81
140
|
{
|
|
82
|
-
"files": ["papers
|
|
83
|
-
"rules": { "pdf/
|
|
141
|
+
"files": ["papers/**"],
|
|
142
|
+
"rules": { "pdf/body-size": "off" }
|
|
84
143
|
},
|
|
85
144
|
{
|
|
86
145
|
"files": ["papers/old-draft/**"],
|
|
@@ -116,7 +175,7 @@ and the real findings leave with it.
|
|
|
116
175
|
|
|
117
176
|
```json
|
|
118
177
|
"structure": {
|
|
119
|
-
"markers": ["PIPELINE-STATUS.md", "paper.tex", "paper.md", "
|
|
178
|
+
"markers": ["PIPELINE-STATUS.md", "paper.tex", "paper.md", "paperlint.json"],
|
|
120
179
|
"require": ["PIPELINE-STATUS.md"],
|
|
121
180
|
"requireOneOf": [["paper.tex", "paper.md"]],
|
|
122
181
|
"ignore": []
|
|
@@ -173,11 +232,12 @@ papers/my-paper
|
|
|
173
232
|
|
|
174
233
|
The build does **not** judge the layout. A balanced last page, a page limit, the fonts a venue
|
|
175
234
|
wants — those are verdicts about the finished PDF, and they belong to lint rules that can be
|
|
176
|
-
turned on per venue, given a severity and suppressed with a reason
|
|
235
|
+
turned on per venue, given a severity and suppressed with a reason: the `pdf/` venue rules
|
|
236
|
+
([`rules.md`](rules.md#checks-against-the-venue)) and the optional `pdf/last-page-balance`. paperlint once searched for a
|
|
177
237
|
`\balance` position itself and failed the build when none worked; that was removed on
|
|
178
238
|
2026-09-24.
|
|
179
239
|
|
|
180
|
-
The class and its options and the venue in `
|
|
240
|
+
The class and its options and the venue in `paperlint.json` are read from the paper and shown in the
|
|
181
241
|
plan; later steps decide from them whether they apply.
|
|
182
242
|
|
|
183
243
|
**`paper.pdf` is deleted before anything runs**, for every targeted paper — before the TeX Live is
|
package/docs/optional-rules.md
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
# Optional rules
|
|
2
2
|
|
|
3
|
-
Some checks matter only for some venues. paperlint ships them **off
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
Some checks matter only for some venues. paperlint ships them **off**. A venue preset that needs one
|
|
4
|
+
turns it on for its papers (AgenticDev's turns on `pdf/last-page-balance`), and a paper can turn one
|
|
5
|
+
on or off for itself in its own `paperlint.json`
|
|
6
|
+
([`configuration.md`](configuration.md#three-levels-of-settings)). No glob is involved: a paper's
|
|
7
|
+
rules apply to that paper. The `rules` setting of your `package.json` still overrides both, for one
|
|
8
|
+
paper or many ([`configuration.md`](configuration.md#the-rules-key-turning-rules-on-and-off)).
|
|
6
9
|
|
|
7
10
|
| rule | what it checks | who needs it |
|
|
8
11
|
| ----------------------- | ------------------------------------------------------------- | --------------------------------------------------------- |
|
|
@@ -12,21 +15,18 @@ papers that need them, in the `rules` setting of your `package.json`
|
|
|
12
15
|
|
|
13
16
|
### Turning it on
|
|
14
17
|
|
|
18
|
+
A paper that extends `paperlint:agenticdev` has it already, at 120 pt. For any other paper, in its
|
|
19
|
+
`papers/my-paper/paperlint.json`:
|
|
20
|
+
|
|
15
21
|
```json
|
|
16
22
|
{
|
|
17
|
-
"
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
{
|
|
21
|
-
"files": ["papers/agenticdev-2026/**"],
|
|
22
|
-
"rules": { "pdf/last-page-balance": ["error", { "tolerancePt": 120 }] }
|
|
23
|
-
}
|
|
24
|
-
]
|
|
25
|
-
}
|
|
23
|
+
"extends": "paperlint:aisec",
|
|
24
|
+
"kind": "research",
|
|
25
|
+
"rules": { "pdf/last-page-balance": ["error", { "tolerancePt": 120 }] }
|
|
26
26
|
}
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
`
|
|
29
|
+
It applies to that paper alone; `"off"` there turns it off for a paper whose preset turns it on. `tolerancePt` is how far apart, in points, the two
|
|
30
30
|
columns may end; it defaults to 120. On a real accepted paper the balanced build ended 2.7 pt apart
|
|
31
31
|
and the one the publisher sent back 321.4 pt apart — nothing in between — so the default leaves a
|
|
32
32
|
wide margin on both sides.
|
|
@@ -38,17 +38,18 @@ the result to `<paper>/_build/paper.facts.json` ([`configuration.md`](configurat
|
|
|
38
38
|
and the rule judges that file, reporting on the paper's `paper.tex` at the `\documentclass` line.
|
|
39
39
|
So: **build, then lint.**
|
|
40
40
|
|
|
41
|
-
| the rule finds | it says
|
|
42
|
-
| --------------------------------------------------- |
|
|
43
|
-
| columns further apart than `tolerancePt` | **the finding**, with both heights and how to fix it (below)
|
|
44
|
-
| no `_build/paper.facts.json` | build the paper first
|
|
45
|
-
| facts about a different PDF than the one on disk | the facts are stale (their SHA-256 differs) — rebuild
|
|
46
|
-
| facts whose PDF is gone (a failed build removes it) | rebuild
|
|
47
|
-
| a last page of a few lines | nothing — there is no layout to balance
|
|
48
|
-
| a review build with numbered lines | nothing — the numbers run down the whole page, so both columns measure full height, and balance is a camera-ready requirement
|
|
49
|
-
|
|
50
|
-
If you turn the rule on
|
|
51
|
-
so, rather than reporting a clean
|
|
41
|
+
| the rule finds | it says |
|
|
42
|
+
| --------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
|
|
43
|
+
| columns further apart than `tolerancePt` | **the finding**, with both heights and how to fix it (below) |
|
|
44
|
+
| no `_build/paper.facts.json` | build the paper first — unless the paper extends a venue preset: then `pdf/measured` already warns, once, and this rule is silent |
|
|
45
|
+
| facts about a different PDF than the one on disk | the facts are stale (their SHA-256 differs) — rebuild |
|
|
46
|
+
| facts whose PDF is gone (a failed build removes it) | rebuild |
|
|
47
|
+
| a last page of a few lines | nothing — there is no layout to balance |
|
|
48
|
+
| a review build with numbered lines | nothing — the numbers run down the whole page, so both columns measure full height, and balance is a camera-ready requirement |
|
|
49
|
+
|
|
50
|
+
If you turn the rule on — in a `paperlint.json` beside no `paper.tex`, or with a `files` glob in
|
|
51
|
+
`package.json` that reaches none — `paperlint lint` fails and says so, rather than reporting a clean
|
|
52
|
+
run for a rule that never ran.
|
|
52
53
|
|
|
53
54
|
### Which venues need it
|
|
54
55
|
|