paperlint 6.2.3 → 7.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/CONTRIBUTING.md +4 -2
- package/README.md +10 -3
- package/dist/adapters/hotcrp/index.d.ts +7 -0
- package/dist/adapters/hotcrp/index.d.ts.map +1 -0
- package/dist/adapters/hotcrp/index.js +7 -0
- package/dist/adapters/hotcrp/index.js.map +1 -0
- package/dist/adapters/hotcrp/portal.io.d.ts +20 -0
- package/dist/adapters/hotcrp/portal.io.d.ts.map +1 -0
- package/dist/adapters/hotcrp/portal.io.js +90 -0
- package/dist/adapters/hotcrp/portal.io.js.map +1 -0
- package/dist/adapters/hotcrp/response.d.ts +13 -0
- package/dist/adapters/hotcrp/response.d.ts.map +1 -0
- package/dist/adapters/hotcrp/response.js +138 -0
- package/dist/adapters/hotcrp/response.js.map +1 -0
- package/dist/adapters/latex/conditionals.d.ts +21 -0
- package/dist/adapters/latex/conditionals.d.ts.map +1 -0
- package/dist/adapters/latex/conditionals.js +75 -0
- package/dist/adapters/latex/conditionals.js.map +1 -0
- package/dist/adapters/latex/headings.d.ts +10 -0
- package/dist/adapters/latex/headings.d.ts.map +1 -0
- package/dist/adapters/latex/headings.js +129 -0
- package/dist/adapters/latex/headings.js.map +1 -0
- package/dist/adapters/latex/index.d.ts +1 -0
- package/dist/adapters/latex/index.d.ts.map +1 -1
- package/dist/adapters/latex/index.js +3 -0
- package/dist/adapters/latex/index.js.map +1 -1
- package/dist/adapters/latex/parse.d.ts +1 -1
- package/dist/adapters/latex/parse.d.ts.map +1 -1
- package/dist/adapters/latex/parse.js +3 -2
- package/dist/adapters/latex/parse.js.map +1 -1
- package/dist/build.d.ts +1 -1
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +1 -1
- package/dist/build.js.map +1 -1
- package/dist/cli.d.ts +4 -2
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +126 -37
- package/dist/cli.js.map +1 -1
- package/dist/domain/heading-case.d.ts +100 -0
- package/dist/domain/heading-case.d.ts.map +1 -0
- package/dist/domain/heading-case.js +365 -0
- package/dist/domain/heading-case.js.map +1 -0
- package/dist/domain/result.d.ts +4 -0
- package/dist/domain/result.d.ts.map +1 -1
- package/dist/domain/result.js +2 -0
- package/dist/domain/result.js.map +1 -1
- package/dist/domain/submission.d.ts +106 -0
- package/dist/domain/submission.d.ts.map +1 -0
- package/dist/domain/submission.js +39 -0
- package/dist/domain/submission.js.map +1 -0
- package/dist/domain/tex-document.d.ts +32 -0
- package/dist/domain/tex-document.d.ts.map +1 -1
- package/dist/domain/tex-document.js +11 -0
- package/dist/domain/tex-document.js.map +1 -1
- package/dist/domain/venue-name.d.ts +38 -0
- package/dist/domain/venue-name.d.ts.map +1 -0
- package/dist/domain/venue-name.js +71 -0
- package/dist/domain/venue-name.js.map +1 -0
- package/dist/eslint-rules/latex-language.d.ts.map +1 -1
- package/dist/eslint-rules/latex-language.js +16 -3
- package/dist/eslint-rules/latex-language.js.map +1 -1
- package/dist/facts-file.d.ts +3 -3
- package/dist/facts-file.d.ts.map +1 -1
- package/dist/facts-file.js +3 -3
- package/dist/facts-file.js.map +1 -1
- package/dist/folder-venue-rule.d.ts +51 -0
- package/dist/folder-venue-rule.d.ts.map +1 -0
- package/dist/folder-venue-rule.js +96 -0
- package/dist/folder-venue-rule.js.map +1 -0
- package/dist/heading-case.d.ts +48 -0
- package/dist/heading-case.d.ts.map +1 -0
- package/dist/heading-case.js +191 -0
- package/dist/heading-case.js.map +1 -0
- package/dist/init.d.ts +6 -0
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +3 -3
- package/dist/init.js.map +1 -1
- package/dist/lib/paper-config.d.ts.map +1 -1
- package/dist/lib/paper-config.js +5 -1
- package/dist/lib/paper-config.js.map +1 -1
- package/dist/new-paper.d.ts +19 -5
- package/dist/new-paper.d.ts.map +1 -1
- package/dist/new-paper.js +23 -4
- package/dist/new-paper.js.map +1 -1
- package/dist/paper-settings.d.ts +3 -0
- package/dist/paper-settings.d.ts.map +1 -1
- package/dist/paper-settings.js +20 -4
- package/dist/paper-settings.js.map +1 -1
- package/dist/ports/latex.d.ts +7 -1
- package/dist/ports/latex.d.ts.map +1 -1
- package/dist/ports/submission-portal.d.ts +19 -0
- package/dist/ports/submission-portal.d.ts.map +1 -0
- package/dist/ports/submission-portal.js +2 -0
- package/dist/ports/submission-portal.js.map +1 -0
- package/dist/preset-card-rule.d.ts +100 -0
- package/dist/preset-card-rule.d.ts.map +1 -0
- package/dist/preset-card-rule.js +221 -0
- package/dist/preset-card-rule.js.map +1 -0
- package/dist/presets.d.ts +43 -2
- package/dist/presets.d.ts.map +1 -1
- package/dist/presets.js +130 -63
- package/dist/presets.js.map +1 -1
- package/dist/rules-config.js +1 -1
- package/dist/submission.d.ts +61 -0
- package/dist/submission.d.ts.map +1 -0
- package/dist/submission.js +211 -0
- package/dist/submission.js.map +1 -0
- package/dist/tex-requirements.d.ts +36 -3
- package/dist/tex-requirements.d.ts.map +1 -1
- package/dist/tex-requirements.js +30 -2
- package/dist/tex-requirements.js.map +1 -1
- package/dist/tex-venue-rules.d.ts +7 -8
- package/dist/tex-venue-rules.d.ts.map +1 -1
- package/dist/tex-venue-rules.js +10 -14
- package/dist/tex-venue-rules.js.map +1 -1
- package/dist/types.d.ts +13 -0
- package/dist/types.d.ts.map +1 -1
- package/docs/configuration.md +30 -11
- package/docs/optional-rules.md +4 -3
- package/docs/rules/format/page-limit.md +1 -1
- package/docs/rules/paper/folder-venue-leftover.md +104 -0
- package/docs/rules/talk/captions-cover.md +1 -1
- package/docs/rules/talk/duration-floor.md +1 -1
- package/docs/rules/talk/profile.md +1 -1
- package/docs/rules/tex/heading-case.md +424 -0
- package/docs/rules.md +64 -53
- package/docs/skills.md +5 -4
- package/docs/submission.md +64 -0
- package/docs/talk.md +1 -1
- package/eslint-rules/latex-language.test.mjs +12 -0
- package/eslint-rules/latex-language.ts +17 -4
- package/eslint-rules/paper-typography.test.mjs +12 -0
- package/eslint.config.mjs +59 -1
- package/fixtures/build-e2e/acmart/paper.tex +1 -1
- package/fixtures/build-e2e/fallback/expect.json +3 -3
- package/lib/paper-config.ts +6 -1
- package/lib/skill-checks.d.mts +7 -0
- package/lib/skill-checks.mjs +31 -0
- package/lib/skill-trigger-cases.mjs +11 -0
- package/package.json +8 -2
- package/presets/acm-sigconf.jsonc +5 -0
- package/presets/acm-sigconf.md +43 -0
- package/presets/agenticdev.jsonc +27 -6
- package/presets/agenticdev.md +151 -0
- package/presets/aidc.jsonc +12 -0
- package/presets/aidc.md +75 -0
- package/presets/aisec.jsonc +5 -1
- package/presets/aisec.md +117 -0
- package/presets/ieee-conference.jsonc +5 -0
- package/presets/ieee-conference.md +38 -0
- package/presets/realm.jsonc +7 -2
- package/presets/realm.md +166 -0
- package/presets/tex/agenticdev.tex +1 -1
- package/presets/tex-base.jsonc +6 -0
- package/presets/tex-base.md +30 -0
- package/presets/venue-profile.schema.json +57 -2
- package/skills/find-venue/SKILL.md +6 -5
- package/skills/find-venue/SKILL.md.spec.ts +5 -4
- package/skills/paper-pipeline/SKILL.md +5 -6
- package/skills/paper-pipeline/SKILL.md.spec.ts +4 -5
- package/skills/paper-pipeline/paper-pipeline.harness.mjs +4 -0
- package/skills/paper-pipeline/references/acl-venue-rules.md +1 -1
- package/skills/study-accepted-papers/SKILL.md +3 -3
- package/skills/study-accepted-papers/SKILL.md.spec.ts +2 -2
- package/skills/submission-portal/SKILL.md +69 -0
- package/skills/submission-portal/SKILL.md.spec.ts +71 -0
- package/skills/submission-portal/submission-portal.eval.mjs +15 -0
- package/skills/submission-portal/submission-portal.test.ts +81 -0
- package/skills/submit-paper/SKILL.md +27 -22
- package/skills/submit-paper/SKILL.md.spec.ts +26 -21
- package/skills/submit-paper/references/publishers/acm.md +1 -1
- package/src/adapters/hotcrp/cassette/README.md +24 -0
- package/src/adapters/hotcrp/cassette/get-noauth.json +10 -0
- package/src/adapters/hotcrp/cassette/get-paper.json +39 -0
- package/src/adapters/hotcrp/cassette/post-dot.json +21 -0
- package/src/adapters/hotcrp/cassette/post-ok.json +12 -0
- package/src/adapters/hotcrp/index.ts +11 -0
- package/src/adapters/hotcrp/portal.io.ts +130 -0
- package/src/adapters/hotcrp/portal.test.ts +503 -0
- package/src/adapters/hotcrp/response.ts +181 -0
- package/src/adapters/latex/conditionals.ts +130 -0
- package/src/adapters/latex/headings.ts +163 -0
- package/src/adapters/latex/index.test.ts +65 -0
- package/src/adapters/latex/index.ts +3 -0
- package/src/adapters/latex/parse.ts +3 -2
- package/src/build.ts +2 -2
- package/src/cli.test.ts +155 -3
- package/src/cli.ts +161 -25
- package/src/domain/heading-case.test.ts +660 -0
- package/src/domain/heading-case.ts +538 -0
- package/src/domain/result.test.ts +9 -1
- package/src/domain/result.ts +5 -0
- package/src/domain/submission.test.ts +45 -0
- package/src/domain/submission.ts +141 -0
- package/src/domain/tex-document.ts +36 -0
- package/src/domain/venue-name.test.ts +121 -0
- package/src/domain/venue-name.ts +129 -0
- package/src/facts-file.test.ts +4 -4
- package/src/facts-file.ts +6 -6
- package/src/folder-venue-rule.test.ts +182 -0
- package/src/folder-venue-rule.ts +141 -0
- package/src/heading-case.test.ts +500 -0
- package/src/heading-case.ts +275 -0
- package/src/init.test.ts +22 -0
- package/src/init.ts +9 -2
- package/src/new-paper.harness.mjs +11 -9
- package/src/new-paper.test.ts +135 -10
- package/src/new-paper.ts +38 -7
- package/src/paper-settings-commands.test.ts +25 -10
- package/src/paper-settings.test.ts +12 -1
- package/src/paper-settings.ts +25 -5
- package/src/parse-args.test.ts +19 -0
- package/src/ports/latex.ts +7 -0
- package/src/ports/submission-portal.ts +26 -0
- package/src/preset-card-rule.test.ts +266 -0
- package/src/preset-card-rule.ts +384 -0
- package/src/presets.test.ts +212 -37
- package/src/presets.ts +183 -71
- package/src/rule-cases.test.ts +147 -42
- package/src/rules-config.ts +1 -1
- package/src/submission.test.ts +497 -0
- package/src/submission.ts +311 -0
- package/src/talk-rules.test.ts +6 -3
- package/src/tex-requirements.harness.ts +25 -11
- package/src/tex-requirements.test.ts +127 -1
- package/src/tex-requirements.ts +78 -8
- package/src/tex-venue-rules.test.ts +36 -22
- package/src/tex-venue-rules.ts +14 -26
- package/src/types.ts +13 -0
- package/src/venue-rules.test.ts +7 -6
- package/templates/paper/paper.tex +1 -1
- package/skills/submit-paper/references/venues/agenticdev.md +0 -171
- package/skills/submit-paper/references/venues/aisec.md +0 -105
- package/skills/submit-paper/references/venues/realm.md +0 -155
package/src/presets.test.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* resolving shows here.
|
|
8
8
|
*/
|
|
9
9
|
import { readdirSync, readFileSync } from "node:fs";
|
|
10
|
-
import { join } from "node:path";
|
|
10
|
+
import { join, relative } from "node:path";
|
|
11
11
|
import { describe, expect, it } from "vitest";
|
|
12
12
|
import { memoryFiles } from "./adapters/memory/index.ts";
|
|
13
13
|
import { presetsDir } from "./package-dirs.ts";
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
MAX_PRESET_DEPTH,
|
|
17
17
|
SHIPPED_PREFIX,
|
|
18
18
|
shippedPresets,
|
|
19
|
+
shippedVenueNames,
|
|
19
20
|
labelOf,
|
|
20
21
|
presetProblemText,
|
|
21
22
|
resolvePreset,
|
|
@@ -34,6 +35,17 @@ const deps = (extra: Record<string, string> = {}) => ({
|
|
|
34
35
|
});
|
|
35
36
|
const resolve = (spec: string, extra: Record<string, string> = {}) =>
|
|
36
37
|
resolvePreset(spec, PAPER_FILE, deps(extra));
|
|
38
|
+
/** A venue preset of a project's own: the identity every venue declares, then `body`. */
|
|
39
|
+
const venue = (body: Record<string, unknown>, name = "Our Workshop"): string =>
|
|
40
|
+
JSON.stringify({
|
|
41
|
+
type: "venue",
|
|
42
|
+
name,
|
|
43
|
+
url: "https://example.org/cfp",
|
|
44
|
+
...body,
|
|
45
|
+
});
|
|
46
|
+
/** A template family of a project's own. */
|
|
47
|
+
const family = (body: Record<string, unknown>): string =>
|
|
48
|
+
JSON.stringify({ type: "family", ...body });
|
|
37
49
|
|
|
38
50
|
describe("shipped presets", () => {
|
|
39
51
|
it("paperlint:agenticdev → agenticdev over acm-sigconf: the family's format, the venue's kinds", () => {
|
|
@@ -53,7 +65,15 @@ describe("shipped presets", () => {
|
|
|
53
65
|
file: join(VENUES, "acm-sigconf.jsonc"),
|
|
54
66
|
});
|
|
55
67
|
expect("acmart" in r.value.tex.packages).toBe(true);
|
|
56
|
-
|
|
68
|
+
// The label is the venue's own name, from its file's `name`; the id stays the file name — the
|
|
69
|
+
// stable key the facts file and the build plan carry.
|
|
70
|
+
expect(r.value.label).toBe("AgenticDev");
|
|
71
|
+
expect(r.value.id).toBe("agenticdev");
|
|
72
|
+
expect(r.value.identity).toEqual({
|
|
73
|
+
type: "venue",
|
|
74
|
+
name: "AgenticDev",
|
|
75
|
+
url: "https://conf.researchr.org/home/ase-2026/agenticdev-2026",
|
|
76
|
+
});
|
|
57
77
|
});
|
|
58
78
|
|
|
59
79
|
it("a paper may extend a family directly: format and fonts, and no kinds", () => {
|
|
@@ -77,19 +97,72 @@ describe("shipped presets", () => {
|
|
|
77
97
|
});
|
|
78
98
|
});
|
|
79
99
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
100
|
+
// Each shipped preset, parsed: its file name and what it extends. The families are DERIVED — a
|
|
101
|
+
// shipped preset another shipped preset extends — so a new family is checked the day it ships.
|
|
102
|
+
const PARSED = shippedPresets(VENUES).map((name) => {
|
|
103
|
+
const file = join(VENUES, `${name}.jsonc`);
|
|
104
|
+
return {
|
|
105
|
+
name,
|
|
106
|
+
preset: parsePreset(readFileSync(file, "utf8"), file, VENUES),
|
|
107
|
+
};
|
|
108
|
+
});
|
|
109
|
+
const FAMILIES = PARSED.filter((p) =>
|
|
110
|
+
PARSED.some((q) => q.preset.extends === `${SHIPPED_PREFIX}${p.name}`),
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
describe("what each shipped preset declares itself to be", () => {
|
|
114
|
+
it("every shipped preset loads and declares what it is; a venue links its call", () => {
|
|
115
|
+
const declared = Object.fromEntries(
|
|
116
|
+
readdirSync(VENUES)
|
|
117
|
+
.filter((f) => f.endsWith(".jsonc"))
|
|
118
|
+
.map((f) => [
|
|
119
|
+
f,
|
|
120
|
+
parsePreset(readFileSync(join(VENUES, f), "utf8"), f, VENUES)
|
|
121
|
+
.identity,
|
|
122
|
+
]),
|
|
123
|
+
);
|
|
124
|
+
expect(declared).toEqual({
|
|
125
|
+
"acm-sigconf.jsonc": { type: "family" },
|
|
126
|
+
"agenticdev.jsonc": {
|
|
127
|
+
type: "venue",
|
|
128
|
+
name: "AgenticDev",
|
|
129
|
+
url: "https://conf.researchr.org/home/ase-2026/agenticdev-2026",
|
|
130
|
+
},
|
|
131
|
+
"aidc.jsonc": {
|
|
132
|
+
type: "venue",
|
|
133
|
+
name: "AIDC",
|
|
134
|
+
url: "https://aidcworkshop.github.io/",
|
|
135
|
+
},
|
|
136
|
+
"aisec.jsonc": {
|
|
137
|
+
type: "venue",
|
|
138
|
+
name: "AISec",
|
|
139
|
+
url: "https://aisec.cc/",
|
|
140
|
+
},
|
|
141
|
+
"ieee-conference.jsonc": { type: "family" },
|
|
142
|
+
"realm.jsonc": {
|
|
143
|
+
type: "venue",
|
|
144
|
+
name: "REALM",
|
|
145
|
+
url: "https://realm-workshop.github.io/call_for_papers",
|
|
146
|
+
},
|
|
147
|
+
"tex-base.jsonc": { type: "base" },
|
|
148
|
+
});
|
|
89
149
|
});
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
150
|
+
|
|
151
|
+
it("the families another preset extends are exactly the ones that declare `family`", () => {
|
|
152
|
+
expect(
|
|
153
|
+
PARSED.filter((p) => p.preset.identity.type === "family").map(
|
|
154
|
+
(p) => p.name,
|
|
155
|
+
),
|
|
156
|
+
).toEqual(FAMILIES.map((f) => f.name));
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
describe("the naming convention of shipped presets (docs/rules.md)", () => {
|
|
161
|
+
const families = FAMILIES;
|
|
162
|
+
const presets = PARSED.map((p) => ({
|
|
163
|
+
name: p.name,
|
|
164
|
+
extends: p.preset.extends,
|
|
165
|
+
}));
|
|
93
166
|
const publishers = families.map((f) => f.name.slice(0, f.name.indexOf("-")));
|
|
94
167
|
|
|
95
168
|
it("there are families to check (else the checks below see nothing)", () => {
|
|
@@ -117,16 +190,18 @@ describe("the naming convention of shipped presets (docs/rules.md)", () => {
|
|
|
117
190
|
});
|
|
118
191
|
|
|
119
192
|
describe("a project's own preset, by relative path", () => {
|
|
120
|
-
const usenix =
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
193
|
+
const usenix = venue(
|
|
194
|
+
{
|
|
195
|
+
extends: "paperlint:acm-sigconf",
|
|
196
|
+
format: {
|
|
197
|
+
columns: 1,
|
|
198
|
+
kinds: { full: { body_pages_max: 13, ref_pages_max: 0 } },
|
|
199
|
+
},
|
|
200
|
+
tex: { packages: { usenix: ["usenix.sty"] } },
|
|
201
|
+
rules: { "pdf/body-size": "off" },
|
|
126
202
|
},
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
});
|
|
203
|
+
"USENIX Security",
|
|
204
|
+
);
|
|
130
205
|
|
|
131
206
|
it("./ is relative to the file that says it; merged per block, child wins", () => {
|
|
132
207
|
const r = resolve("../../venues/usenix-sec.jsonc", {
|
|
@@ -146,18 +221,21 @@ describe("a project's own preset, by relative path", () => {
|
|
|
146
221
|
expect(r.value.label).toBe("USENIX Security");
|
|
147
222
|
});
|
|
148
223
|
|
|
149
|
-
it("
|
|
224
|
+
it("a family names no venue: its label is the file name without its extension", () => {
|
|
150
225
|
const r = resolve("./venues/usenix-sec.jsonc", {
|
|
151
|
-
"/work/papers/p/venues/usenix-sec.jsonc":
|
|
226
|
+
"/work/papers/p/venues/usenix-sec.jsonc": family({
|
|
152
227
|
extends: "paperlint:acm-sigconf",
|
|
153
228
|
}),
|
|
154
229
|
});
|
|
155
230
|
expect(r.ok && r.value.label).toBe("usenix-sec");
|
|
231
|
+
expect(r.ok && r.value.identity).toEqual({ type: "family" });
|
|
156
232
|
});
|
|
233
|
+
});
|
|
157
234
|
|
|
235
|
+
describe("a project's own preset: what its children replace", () => {
|
|
158
236
|
it("a child kind replaces that kind wholesale; other kinds are kept", () => {
|
|
159
237
|
const r = resolve("./mine.jsonc", {
|
|
160
|
-
"/work/papers/p/mine.jsonc":
|
|
238
|
+
"/work/papers/p/mine.jsonc": venue({
|
|
161
239
|
extends: "paperlint:agenticdev",
|
|
162
240
|
format: { kinds: { short: { body_pages_max: 6 } } },
|
|
163
241
|
}),
|
|
@@ -173,13 +251,40 @@ describe("a project's own preset, by relative path", () => {
|
|
|
173
251
|
|
|
174
252
|
it("rules: the leaf wins over its parent, per rule id", () => {
|
|
175
253
|
const r = resolve("./mine.jsonc", {
|
|
176
|
-
"/work/papers/p/mine.jsonc":
|
|
254
|
+
"/work/papers/p/mine.jsonc": venue({
|
|
177
255
|
extends: "paperlint:agenticdev",
|
|
178
256
|
rules: { "pdf/last-page-balance": "off" },
|
|
179
257
|
}),
|
|
180
258
|
});
|
|
181
259
|
expect(r.ok && r.value.rules["pdf/last-page-balance"]).toBe("off");
|
|
182
260
|
});
|
|
261
|
+
|
|
262
|
+
it("ruleOrigins: each rule's entry names the file of the chain that set it", () => {
|
|
263
|
+
const r = resolve("./mine.jsonc", {
|
|
264
|
+
"/work/papers/p/mine.jsonc": venue({
|
|
265
|
+
extends: "paperlint:agenticdev",
|
|
266
|
+
rules: { "pdf/body-size": "off" },
|
|
267
|
+
}),
|
|
268
|
+
});
|
|
269
|
+
// Guards: an own rule is the leaf's, an inherited one names the parent that set it.
|
|
270
|
+
expect(r.ok && r.value.ruleOrigins).toEqual({
|
|
271
|
+
"pdf/last-page-balance": join(VENUES, "agenticdev.jsonc"),
|
|
272
|
+
"tex/heading-case": join(VENUES, "agenticdev.jsonc"),
|
|
273
|
+
"pdf/body-size": "/work/papers/p/mine.jsonc",
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
it("ruleOrigins: a rule the leaf sets again is the leaf's, not its parent's", () => {
|
|
278
|
+
const r = resolve("./mine.jsonc", {
|
|
279
|
+
"/work/papers/p/mine.jsonc": venue({
|
|
280
|
+
extends: "paperlint:agenticdev",
|
|
281
|
+
rules: { "tex/heading-case": "off" },
|
|
282
|
+
}),
|
|
283
|
+
});
|
|
284
|
+
expect(r.ok && r.value.ruleOrigins["tex/heading-case"]).toBe(
|
|
285
|
+
"/work/papers/p/mine.jsonc",
|
|
286
|
+
);
|
|
287
|
+
});
|
|
183
288
|
});
|
|
184
289
|
|
|
185
290
|
describe("what does not resolve, and says why", () => {
|
|
@@ -216,8 +321,8 @@ describe("what does not resolve, and says why", () => {
|
|
|
216
321
|
describe("chains that do not resolve", () => {
|
|
217
322
|
it("a cycle is refused, naming the chain", () => {
|
|
218
323
|
const r = resolve("./a.jsonc", {
|
|
219
|
-
"/work/papers/p/a.jsonc":
|
|
220
|
-
"/work/papers/p/b.jsonc":
|
|
324
|
+
"/work/papers/p/a.jsonc": family({ extends: "./b.jsonc" }),
|
|
325
|
+
"/work/papers/p/b.jsonc": family({ extends: "./a.jsonc" }),
|
|
221
326
|
});
|
|
222
327
|
expect(r.ok).toBe(false);
|
|
223
328
|
if (r.ok) return;
|
|
@@ -230,7 +335,7 @@ describe("chains that do not resolve", () => {
|
|
|
230
335
|
it(`a chain longer than ${String(MAX_PRESET_DEPTH)} is refused, printing it`, () => {
|
|
231
336
|
const files: Record<string, string> = {};
|
|
232
337
|
for (let i = 1; i <= 5; i++)
|
|
233
|
-
files[`/work/papers/p/p${String(i)}.jsonc`] =
|
|
338
|
+
files[`/work/papers/p/p${String(i)}.jsonc`] = venue({
|
|
234
339
|
extends: i < 5 ? `./p${String(i + 1)}.jsonc` : "paperlint:acm-sigconf",
|
|
235
340
|
});
|
|
236
341
|
const r = resolve("./p1.jsonc", files);
|
|
@@ -242,17 +347,17 @@ describe("chains that do not resolve", () => {
|
|
|
242
347
|
|
|
243
348
|
it("a chain of exactly the limit resolves", () => {
|
|
244
349
|
const r = resolve("./p1.jsonc", {
|
|
245
|
-
"/work/papers/p/p1.jsonc":
|
|
246
|
-
"/work/papers/p/p2.jsonc":
|
|
247
|
-
extends: "paperlint:agenticdev",
|
|
248
|
-
}),
|
|
350
|
+
"/work/papers/p/p1.jsonc": venue({ extends: "./p2.jsonc" }),
|
|
351
|
+
"/work/papers/p/p2.jsonc": venue({ extends: "paperlint:agenticdev" }),
|
|
249
352
|
});
|
|
250
353
|
expect(r.ok && r.value.chain.length).toBe(MAX_PRESET_DEPTH);
|
|
251
354
|
});
|
|
355
|
+
});
|
|
252
356
|
|
|
357
|
+
describe("chains that do not resolve: the files themselves", () => {
|
|
253
358
|
it("a preset that fails the schema is named with its file", () => {
|
|
254
359
|
const r = resolve("./bad.jsonc", {
|
|
255
|
-
"/work/papers/p/bad.jsonc":
|
|
360
|
+
"/work/papers/p/bad.jsonc": family({
|
|
256
361
|
extends: "paperlint:acm-sigconf",
|
|
257
362
|
colums: 2,
|
|
258
363
|
}),
|
|
@@ -265,16 +370,51 @@ describe("chains that do not resolve", () => {
|
|
|
265
370
|
|
|
266
371
|
it("a preset with no `extends` must carry `tex` (it is a root)", () => {
|
|
267
372
|
const r = resolve("./root.jsonc", {
|
|
268
|
-
"/work/papers/p/root.jsonc":
|
|
373
|
+
"/work/papers/p/root.jsonc": family({ format: { columns: 1 } }),
|
|
269
374
|
});
|
|
270
375
|
expect(r.ok).toBe(false);
|
|
271
376
|
});
|
|
377
|
+
|
|
378
|
+
it("a family that extends a venue is refused, naming both files", () => {
|
|
379
|
+
const r = resolve("./fam.jsonc", {
|
|
380
|
+
"/work/papers/p/fam.jsonc": family({ extends: "paperlint:aisec" }),
|
|
381
|
+
});
|
|
382
|
+
expect(r.ok).toBe(false);
|
|
383
|
+
if (r.ok) return;
|
|
384
|
+
expect(presetProblemText(r.error)).toBe(
|
|
385
|
+
`the preset /work/papers/p/fam.jsonc is a template family and extends ${join(VENUES, "aisec.jsonc")}, a venue — a family builds only on a family; a venue extends a family or another venue`,
|
|
386
|
+
);
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
it("nothing extends the TeX base set, even by a relative path", () => {
|
|
390
|
+
const r = resolve("./mine.jsonc", {
|
|
391
|
+
"/work/papers/p/mine.jsonc": venue({
|
|
392
|
+
extends: relative("/work/papers/p", join(VENUES, "tex-base.jsonc")),
|
|
393
|
+
}),
|
|
394
|
+
});
|
|
395
|
+
expect(r.ok).toBe(false);
|
|
396
|
+
if (r.ok) return;
|
|
397
|
+
expect(presetProblemText(r.error)).toBe(
|
|
398
|
+
`the preset /work/papers/p/mine.jsonc extends ${join(VENUES, "tex-base.jsonc")}, the TeX base set — every paper gets that set already, and no preset extends it`,
|
|
399
|
+
);
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
it("a venue may extend a venue, and the resolved identity is the leaf's", () => {
|
|
403
|
+
const r = resolve("./mine.jsonc", {
|
|
404
|
+
"/work/papers/p/mine.jsonc": venue({ extends: "paperlint:aisec" }),
|
|
405
|
+
});
|
|
406
|
+
expect(r.ok && r.value.identity).toEqual({
|
|
407
|
+
type: "venue",
|
|
408
|
+
name: "Our Workshop",
|
|
409
|
+
url: "https://example.org/cfp",
|
|
410
|
+
});
|
|
411
|
+
});
|
|
272
412
|
});
|
|
273
413
|
|
|
274
414
|
describe("a preset's template: kept as its file spells it, with that file", () => {
|
|
275
415
|
it("a child's template replaces its parent's, and names its own file", () => {
|
|
276
416
|
const r = resolve("./own.jsonc", {
|
|
277
|
-
"/work/papers/p/own.jsonc":
|
|
417
|
+
"/work/papers/p/own.jsonc": venue({
|
|
278
418
|
extends: "paperlint:aidc",
|
|
279
419
|
template: "\\documentclass[conference]{IEEEtran}",
|
|
280
420
|
}),
|
|
@@ -297,3 +437,38 @@ describe("labelOf — display only, never used to resolve", () => {
|
|
|
297
437
|
expect(labelOf(spec)).toBe(label);
|
|
298
438
|
});
|
|
299
439
|
});
|
|
440
|
+
|
|
441
|
+
describe("shippedVenueNames — what each shipped venue is called", () => {
|
|
442
|
+
it("every shipped preset, by its label and the names along its chain", () => {
|
|
443
|
+
const names = shippedVenueNames(deps());
|
|
444
|
+
// A venue is labelled by its `name`, a family by its file name.
|
|
445
|
+
expect(names.map((n) => n.label)).toEqual([
|
|
446
|
+
"acm-sigconf",
|
|
447
|
+
"AgenticDev",
|
|
448
|
+
"AIDC",
|
|
449
|
+
"AISec",
|
|
450
|
+
"ieee-conference",
|
|
451
|
+
"REALM",
|
|
452
|
+
]);
|
|
453
|
+
expect(names.find((n) => n.label === "AISec")?.aliases).toEqual(
|
|
454
|
+
expect.arrayContaining(["AISec", "ACM CCS"]),
|
|
455
|
+
);
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
it("a preset that does not resolve is left out", () => {
|
|
459
|
+
const files = memoryFiles(
|
|
460
|
+
Object.fromEntries(
|
|
461
|
+
Object.entries(shipped).filter(([f]) => !f.endsWith("realm.jsonc")),
|
|
462
|
+
),
|
|
463
|
+
);
|
|
464
|
+
expect(
|
|
465
|
+
shippedVenueNames({ files, venuesDir: VENUES }).map((n) => n.label),
|
|
466
|
+
).toEqual([
|
|
467
|
+
"acm-sigconf",
|
|
468
|
+
"AgenticDev",
|
|
469
|
+
"AIDC",
|
|
470
|
+
"AISec",
|
|
471
|
+
"ieee-conference",
|
|
472
|
+
]);
|
|
473
|
+
});
|
|
474
|
+
});
|