paperlint 4.2.0 → 6.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 +15 -2
- package/CONTRIBUTING.md +3 -0
- package/README.md +23 -12
- package/action.harness.mjs +54 -36
- package/action.yml +12 -27
- package/bin/paperlint.mjs +5 -1
- package/dist/adapters/latex/includes.d.ts +5 -1
- package/dist/adapters/latex/includes.d.ts.map +1 -1
- package/dist/adapters/latex/includes.js +8 -2
- package/dist/adapters/latex/includes.js.map +1 -1
- 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/layout.d.ts +27 -0
- package/dist/adapters/latex/layout.d.ts.map +1 -0
- package/dist/adapters/latex/layout.js +62 -0
- package/dist/adapters/latex/layout.js.map +1 -0
- package/dist/adapters/latex/nodes.d.ts.map +1 -1
- package/dist/adapters/latex/nodes.js +11 -1
- package/dist/adapters/latex/nodes.js.map +1 -1
- package/dist/adapters/latex/parse.d.ts.map +1 -1
- package/dist/adapters/latex/parse.js +5 -1
- package/dist/adapters/latex/parse.js.map +1 -1
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +7 -3
- package/dist/build.js.map +1 -1
- package/dist/cli.d.ts +2 -8
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +92 -42
- package/dist/cli.js.map +1 -1
- package/dist/domain/anonymity.d.ts +68 -0
- package/dist/domain/anonymity.d.ts.map +1 -0
- package/dist/domain/anonymity.js +94 -0
- package/dist/domain/anonymity.js.map +1 -0
- package/dist/domain/body-pages.d.ts +69 -0
- package/dist/domain/body-pages.d.ts.map +1 -0
- package/dist/domain/body-pages.js +141 -0
- package/dist/domain/body-pages.js.map +1 -0
- package/dist/domain/paper-source.js +2 -2
- package/dist/domain/tex-document.d.ts +9 -0
- package/dist/domain/tex-document.d.ts.map +1 -1
- package/dist/eslint-rules/latex-language.d.ts +5 -1
- package/dist/eslint-rules/latex-language.d.ts.map +1 -1
- package/dist/eslint-rules/latex-language.js +6 -3
- package/dist/eslint-rules/latex-language.js.map +1 -1
- package/dist/eslint-rules/paper-context.d.ts +20 -0
- package/dist/eslint-rules/paper-context.d.ts.map +1 -0
- package/dist/eslint-rules/paper-context.js +44 -0
- package/dist/eslint-rules/paper-context.js.map +1 -0
- package/dist/eslint-rules/paper-typography.d.ts +1 -1
- package/dist/eslint-rules/paper-typography.d.ts.map +1 -1
- package/dist/eslint-rules/paper-typography.js +32 -18
- package/dist/eslint-rules/paper-typography.js.map +1 -1
- package/dist/eslint-rules/pdf-last-page-balance.d.ts +1 -1
- package/dist/eslint-rules/pdf-last-page-balance.js +2 -2
- package/dist/eslint-rules/tex-build.d.ts.map +1 -1
- package/dist/eslint-rules/tex-build.js +7 -1
- package/dist/eslint-rules/tex-build.js.map +1 -1
- package/dist/facts-file.d.ts +28 -2
- package/dist/facts-file.d.ts.map +1 -1
- package/dist/facts-file.js +54 -9
- package/dist/facts-file.js.map +1 -1
- package/dist/init.d.ts +4 -19
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +24 -29
- package/dist/init.js.map +1 -1
- package/dist/lib/paper-config.d.ts.map +1 -1
- package/dist/lib/paper-config.js +2 -1
- package/dist/lib/paper-config.js.map +1 -1
- package/dist/package-dirs.d.ts +2 -0
- package/dist/package-dirs.d.ts.map +1 -1
- package/dist/package-dirs.js +8 -0
- package/dist/package-dirs.js.map +1 -1
- package/dist/paper-files.d.ts +2 -2
- package/dist/paper-includes.d.ts +17 -0
- package/dist/paper-includes.d.ts.map +1 -0
- package/dist/paper-includes.js +51 -0
- package/dist/paper-includes.js.map +1 -0
- package/dist/paper-settings.d.ts +11 -0
- package/dist/paper-settings.d.ts.map +1 -1
- package/dist/paper-settings.js +38 -4
- package/dist/paper-settings.js.map +1 -1
- package/dist/pdf-content.d.ts +40 -0
- package/dist/pdf-content.d.ts.map +1 -0
- package/dist/pdf-content.js +97 -0
- package/dist/pdf-content.js.map +1 -0
- package/dist/pdf-facts.d.ts +30 -0
- package/dist/pdf-facts.d.ts.map +1 -1
- package/dist/pdf-facts.js +37 -1
- package/dist/pdf-facts.js.map +1 -1
- package/dist/ports/latex.d.ts +3 -1
- package/dist/ports/latex.d.ts.map +1 -1
- package/dist/presets.d.ts +2 -0
- package/dist/presets.d.ts.map +1 -1
- package/dist/presets.js +4 -0
- package/dist/presets.js.map +1 -1
- package/dist/rules-config.d.ts +1 -0
- package/dist/rules-config.d.ts.map +1 -1
- package/dist/rules-config.js.map +1 -1
- package/dist/structure.js +1 -1
- package/dist/structure.js.map +1 -1
- package/dist/tex-paper.d.ts +17 -3
- package/dist/tex-paper.d.ts.map +1 -1
- package/dist/tex-paper.js +36 -38
- package/dist/tex-paper.js.map +1 -1
- package/dist/tex-requirements.d.ts +4 -0
- package/dist/tex-requirements.d.ts.map +1 -1
- package/dist/tex-requirements.js +3 -0
- package/dist/tex-requirements.js.map +1 -1
- package/dist/tex-venue-rules.d.ts +7 -1
- package/dist/tex-venue-rules.d.ts.map +1 -1
- package/dist/tex-venue-rules.js +40 -0
- package/dist/tex-venue-rules.js.map +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/venue-rules.d.ts +38 -8
- package/dist/venue-rules.d.ts.map +1 -1
- package/dist/venue-rules.js +179 -41
- package/dist/venue-rules.js.map +1 -1
- package/docs/configuration.md +23 -20
- package/docs/e2e.md +32 -11
- package/docs/install.md +8 -8
- package/docs/prior-art/paper-folder-scaffolding.md +4 -7
- package/docs/rules/anonymity/identity.md +111 -0
- package/docs/rules/format/layout-override.md +61 -0
- package/docs/rules/format/page-limit.md +108 -0
- package/docs/rules/pdf/body-size.md +87 -0
- package/docs/rules.md +55 -46
- package/eslint-rules/latex-language.ts +10 -4
- package/eslint-rules/paper-context.test.ts +47 -0
- package/eslint-rules/paper-context.ts +57 -0
- package/eslint-rules/paper-typography.ts +67 -23
- package/eslint-rules/pdf-last-page-balance.harness.mjs +6 -1
- package/eslint-rules/pdf-last-page-balance.ts +2 -2
- package/eslint-rules/tex-build.ts +8 -1
- package/fixtures/build-e2e/aidc/expect.json +1 -1
- package/fixtures/build-e2e/aidc/paperlint.json +1 -1
- package/fixtures/build-e2e/anon-ack/PIPELINE-STATUS.md +3 -0
- package/fixtures/build-e2e/anon-ack/expect.json +19 -0
- package/fixtures/build-e2e/anon-ack/paper.tex +31 -0
- package/fixtures/build-e2e/anon-ack/paperlint.json +1 -0
- package/fixtures/build-e2e/anon-author/PIPELINE-STATUS.md +3 -0
- package/fixtures/build-e2e/anon-author/expect.json +19 -0
- package/fixtures/build-e2e/anon-author/paper.tex +29 -0
- package/fixtures/build-e2e/anon-author/paperlint.json +1 -0
- package/fixtures/build-e2e/anon-bib/PIPELINE-STATUS.md +3 -0
- package/fixtures/build-e2e/anon-bib/expect.json +20 -0
- package/fixtures/build-e2e/anon-bib/paper.tex +35 -0
- package/fixtures/build-e2e/anon-bib/paperlint.json +1 -0
- package/fixtures/build-e2e/anon-href/PIPELINE-STATUS.md +3 -0
- package/fixtures/build-e2e/anon-href/expect.json +19 -0
- package/fixtures/build-e2e/anon-href/paper.tex +30 -0
- package/fixtures/build-e2e/anon-href/paperlint.json +1 -0
- package/fixtures/build-e2e/anon-macro/PIPELINE-STATUS.md +3 -0
- package/fixtures/build-e2e/anon-macro/expect.json +19 -0
- package/fixtures/build-e2e/anon-macro/paper.tex +30 -0
- package/fixtures/build-e2e/anon-macro/paperlint.json +1 -0
- package/fixtures/build-e2e/anon-pdfauthor/PIPELINE-STATUS.md +3 -0
- package/fixtures/build-e2e/anon-pdfauthor/expect.json +19 -0
- package/fixtures/build-e2e/anon-pdfauthor/paper.tex +31 -0
- package/fixtures/build-e2e/anon-pdfauthor/paperlint.json +1 -0
- package/fixtures/build-e2e/unbalanced/expect.json +2 -2
- package/fixtures/real-markdown-paper/baseline.json +1 -2
- package/lib/paper-config.ts +3 -1
- package/package.json +1 -1
- package/presets/acm-sigconf.jsonc +3 -1
- package/presets/aidc.jsonc +16 -17
- package/presets/ieee-conference.jsonc +8 -0
- package/presets/venue-profile.schema.json +9 -0
- package/scripts/check.ts +2 -2
- package/scripts/eslint-report-guard.mjs +5 -2
- package/scripts/harness-api.frozen.json +0 -1
- package/skills/paper-pipeline/references/pipeline-status-template.md +2 -16
- package/skills/render-paper/extract-pdf-facts.harness.ts +3 -3
- package/src/adapters/latex/includes.ts +10 -2
- package/src/adapters/latex/index.test.ts +8 -0
- package/src/adapters/latex/index.ts +3 -0
- package/src/adapters/latex/layout.ts +106 -0
- package/src/adapters/latex/nodes.ts +11 -3
- package/src/adapters/latex/parse.ts +5 -1
- package/src/build.harness.mjs +6 -4
- package/src/build.test.ts +23 -1
- package/src/build.ts +7 -3
- package/src/cli.harness.mjs +22 -54
- package/src/cli.test.ts +15 -18
- package/src/cli.ts +114 -46
- package/src/domain/anonymity.test.ts +163 -0
- package/src/domain/anonymity.ts +129 -0
- package/src/domain/body-pages.test.ts +300 -0
- package/src/domain/body-pages.ts +223 -0
- package/src/domain/paper-source.ts +2 -2
- package/src/domain/tex-document.ts +10 -0
- package/src/facts-file.test.ts +100 -4
- package/src/facts-file.ts +91 -9
- package/src/init.test.ts +33 -13
- package/src/init.ts +25 -48
- package/src/linted-set.test.ts +11 -1
- package/src/new-paper.harness.mjs +1 -5
- package/src/new-paper.test.ts +7 -1
- package/src/package-dirs.ts +9 -0
- package/src/paper-files.ts +2 -2
- package/src/paper-includes.test.ts +161 -0
- package/src/paper-includes.ts +77 -0
- package/src/paper-settings.test.ts +63 -6
- package/src/paper-settings.ts +53 -5
- package/src/pdf-content.test.ts +71 -0
- package/src/pdf-content.ts +125 -0
- package/src/pdf-facts.test.ts +110 -2
- package/src/pdf-facts.ts +106 -8
- package/src/ports/latex.ts +3 -0
- package/src/presets.ts +8 -8
- package/src/rule-cases.test.ts +29 -33
- package/src/rule-docs.test.ts +0 -3
- package/src/rules-config.ts +1 -0
- package/src/structure.harness.ts +1 -3
- package/src/structure.ts +1 -1
- package/src/tex-paper.test.ts +78 -61
- package/src/tex-paper.ts +57 -48
- package/src/tex-requirements.ts +9 -0
- package/src/tex-venue-rules.test.ts +111 -6
- package/src/tex-venue-rules.ts +57 -2
- package/src/types.ts +2 -0
- package/src/venue-rules.test.ts +351 -39
- package/src/venue-rules.ts +247 -47
- package/templates/paper/PIPELINE-STATUS.md +0 -4
- package/dist/action-ref.d.ts +0 -12
- package/dist/action-ref.d.ts.map +0 -1
- package/dist/action-ref.js +0 -16
- package/dist/action-ref.js.map +0 -1
- package/dist/eslint-rules/paper-research-question.d.ts +0 -31
- package/dist/eslint-rules/paper-research-question.d.ts.map +0 -1
- package/dist/eslint-rules/paper-research-question.js +0 -188
- package/dist/eslint-rules/paper-research-question.js.map +0 -1
- package/docs/rules/tex/missing-input.md +0 -58
- package/eslint-rules/paper-research-question.harness.mjs +0 -212
- package/eslint-rules/paper-research-question.ts +0 -199
- package/fixtures/paper-research-question/comment-only/PIPELINE-STATUS.md +0 -9
- package/fixtures/paper-research-question/comment-only/paper.tex +0 -7
- package/fixtures/paper-research-question/declared-not-in-paper/PIPELINE-STATUS.md +0 -10
- package/fixtures/paper-research-question/declared-not-in-paper/paper.tex +0 -6
- package/fixtures/paper-research-question/draft/PIPELINE-STATUS.md +0 -6
- package/fixtures/paper-research-question/draft/paper.tex +0 -2
- package/fixtures/paper-research-question/markdown-no-rq/PIPELINE-STATUS.md +0 -9
- package/fixtures/paper-research-question/markdown-no-rq/paper.md +0 -4
- package/fixtures/paper-research-question/shipped-no-rq/PIPELINE-STATUS.md +0 -12
- package/fixtures/paper-research-question/shipped-no-rq/paper.tex +0 -3
- package/fixtures/paper-research-question/shipped-with-rq/PIPELINE-STATUS.md +0 -10
- package/fixtures/paper-research-question/shipped-with-rq/paper.tex +0 -2
- package/src/action-ref.test.ts +0 -26
- package/src/action-ref.ts +0 -15
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"extends": "paperlint:aidc", "kind": "short", "identity": ["Ada Example", "adaexample", "ada@example.org", "Example University", "exampletool"]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$comment": "anonymity/identity on a real IEEEtran build: A: the name in the author block. Exactly one finding, naming where.",
|
|
3
|
+
"build": {
|
|
4
|
+
"outcome": "pdf"
|
|
5
|
+
},
|
|
6
|
+
"lint": {
|
|
7
|
+
"rules": {
|
|
8
|
+
"anonymity/identity": [
|
|
9
|
+
{
|
|
10
|
+
"severity": 2,
|
|
11
|
+
"says": [
|
|
12
|
+
"«Ada Example»",
|
|
13
|
+
"PDF, page 1"
|
|
14
|
+
]
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
% A: the name in the author block.
|
|
2
|
+
% The declared identity is invented: "Ada Example", handle "adaexample" (paperlint.json).
|
|
3
|
+
\documentclass[conference,compsoc]{IEEEtran}
|
|
4
|
+
\begin{filecontents*}{refs.bib}
|
|
5
|
+
@article{knuth84,
|
|
6
|
+
title = {Literate Programming},
|
|
7
|
+
author = {Knuth, Donald E.},
|
|
8
|
+
journal = {The Computer Journal},
|
|
9
|
+
volume = {27},
|
|
10
|
+
number = {2},
|
|
11
|
+
pages = {97--111},
|
|
12
|
+
year = {1984},
|
|
13
|
+
doi = {10.1093/comjnl/27.2.97}
|
|
14
|
+
}
|
|
15
|
+
\end{filecontents*}
|
|
16
|
+
\begin{document}
|
|
17
|
+
\title{A Fixture for Double-Blind Review}
|
|
18
|
+
\author{\IEEEauthorblockN{Ada Example}\IEEEauthorblockA{Anonymous Institution}}
|
|
19
|
+
\maketitle
|
|
20
|
+
\section{Introduction}
|
|
21
|
+
This paper builds on earlier work~\cite{knuth84}.
|
|
22
|
+
|
|
23
|
+
\section{Conclusion}
|
|
24
|
+
The conclusion restates that the fixture builds.
|
|
25
|
+
\bibliographystyle{IEEEtran}
|
|
26
|
+
\bibliography{refs}
|
|
27
|
+
\section*{LLM Usage Statement}
|
|
28
|
+
No LLMs were used in writing this fixture.
|
|
29
|
+
\end{document}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"extends": "paperlint:aidc", "kind": "short", "identity": ["Ada Example", "adaexample", "ada@example.org", "Example University", "exampletool"]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$comment": "anonymity/identity on a real IEEEtran build: C: a self-citation: the name only in a .bib author field, printed by IEEEtran.bst as \"A. Example\". Exactly one finding, naming where.",
|
|
3
|
+
"build": {
|
|
4
|
+
"outcome": "pdf"
|
|
5
|
+
},
|
|
6
|
+
"lint": {
|
|
7
|
+
"rules": {
|
|
8
|
+
"anonymity/identity": [
|
|
9
|
+
{
|
|
10
|
+
"severity": 2,
|
|
11
|
+
"says": [
|
|
12
|
+
"«A. Example»",
|
|
13
|
+
"matches «Ada Example»",
|
|
14
|
+
"PDF, page"
|
|
15
|
+
]
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
% C: a self-citation: the name only in a .bib author field, printed by IEEEtran.bst as "A. Example".
|
|
2
|
+
% The declared identity is invented: "Ada Example", handle "adaexample" (paperlint.json).
|
|
3
|
+
\documentclass[conference,compsoc]{IEEEtran}
|
|
4
|
+
\begin{filecontents*}{refs.bib}
|
|
5
|
+
@article{knuth84,
|
|
6
|
+
title = {Literate Programming},
|
|
7
|
+
author = {Knuth, Donald E.},
|
|
8
|
+
journal = {The Computer Journal},
|
|
9
|
+
volume = {27},
|
|
10
|
+
number = {2},
|
|
11
|
+
pages = {97--111},
|
|
12
|
+
year = {1984},
|
|
13
|
+
doi = {10.1093/comjnl/27.2.97}
|
|
14
|
+
}
|
|
15
|
+
@misc{example25,
|
|
16
|
+
title = {A Tool for Measuring Things},
|
|
17
|
+
author = {Example, Ada and Other, Bob},
|
|
18
|
+
year = {2025},
|
|
19
|
+
note = {Technical report}
|
|
20
|
+
}
|
|
21
|
+
\end{filecontents*}
|
|
22
|
+
\begin{document}
|
|
23
|
+
\title{A Fixture for Double-Blind Review}
|
|
24
|
+
\author{\IEEEauthorblockN{Anonymous Authors}}
|
|
25
|
+
\maketitle
|
|
26
|
+
\section{Introduction}
|
|
27
|
+
This paper builds on earlier work~\cite{knuth84,example25}.
|
|
28
|
+
|
|
29
|
+
\section{Conclusion}
|
|
30
|
+
The conclusion restates that the fixture builds.
|
|
31
|
+
\bibliographystyle{IEEEtran}
|
|
32
|
+
\bibliography{refs}
|
|
33
|
+
\section*{LLM Usage Statement}
|
|
34
|
+
No LLMs were used in writing this fixture.
|
|
35
|
+
\end{document}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"extends": "paperlint:aidc", "kind": "short", "identity": ["Ada Example", "adaexample", "ada@example.org", "Example University", "exampletool"]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$comment": "anonymity/identity on a real IEEEtran build: E: a link whose visible text names nobody and whose target is the author's account. The anonymous mirror beside it is not reported. Exactly one finding, naming where.",
|
|
3
|
+
"build": {
|
|
4
|
+
"outcome": "pdf"
|
|
5
|
+
},
|
|
6
|
+
"lint": {
|
|
7
|
+
"rules": {
|
|
8
|
+
"anonymity/identity": [
|
|
9
|
+
{
|
|
10
|
+
"severity": 2,
|
|
11
|
+
"says": [
|
|
12
|
+
"link target on page 1 (https://github.com/adaexample/tool)",
|
|
13
|
+
"«adaexample»"
|
|
14
|
+
]
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
% E: a link whose visible text names nobody and whose target is the author's account. The anonymous mirror beside it is not reported.
|
|
2
|
+
% The declared identity is invented: "Ada Example", handle "adaexample" (paperlint.json).
|
|
3
|
+
\documentclass[conference,compsoc]{IEEEtran}
|
|
4
|
+
\usepackage{hyperref}
|
|
5
|
+
\begin{filecontents*}{refs.bib}
|
|
6
|
+
@article{knuth84,
|
|
7
|
+
title = {Literate Programming},
|
|
8
|
+
author = {Knuth, Donald E.},
|
|
9
|
+
journal = {The Computer Journal},
|
|
10
|
+
volume = {27},
|
|
11
|
+
number = {2},
|
|
12
|
+
pages = {97--111},
|
|
13
|
+
year = {1984},
|
|
14
|
+
doi = {10.1093/comjnl/27.2.97}
|
|
15
|
+
}
|
|
16
|
+
\end{filecontents*}
|
|
17
|
+
\begin{document}
|
|
18
|
+
\title{A Fixture for Double-Blind Review}
|
|
19
|
+
\author{\IEEEauthorblockN{Anonymous Authors}}
|
|
20
|
+
\maketitle
|
|
21
|
+
\section{Introduction}
|
|
22
|
+
This paper builds on earlier work~\cite{knuth84}.
|
|
23
|
+
The code is at \href{https://github.com/adaexample/tool}{the tool's repository}, mirrored anonymously at \href{https://anonymous.4open.science/r/tool-1A2B}{an anonymous mirror}.
|
|
24
|
+
\section{Conclusion}
|
|
25
|
+
The conclusion restates that the fixture builds.
|
|
26
|
+
\bibliographystyle{IEEEtran}
|
|
27
|
+
\bibliography{refs}
|
|
28
|
+
\section*{LLM Usage Statement}
|
|
29
|
+
No LLMs were used in writing this fixture.
|
|
30
|
+
\end{document}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"extends": "paperlint:aidc", "kind": "short", "identity": ["Ada Example", "adaexample", "ada@example.org", "Example University", "exampletool"]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$comment": "anonymity/identity on a real IEEEtran build: F: the name hidden behind a macro; only the typeset text shows it. Exactly one finding, naming where.",
|
|
3
|
+
"build": {
|
|
4
|
+
"outcome": "pdf"
|
|
5
|
+
},
|
|
6
|
+
"lint": {
|
|
7
|
+
"rules": {
|
|
8
|
+
"anonymity/identity": [
|
|
9
|
+
{
|
|
10
|
+
"severity": 2,
|
|
11
|
+
"says": [
|
|
12
|
+
"«Ada Example»",
|
|
13
|
+
"PDF, page 1"
|
|
14
|
+
]
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
% F: the name hidden behind a macro; only the typeset text shows it.
|
|
2
|
+
% The declared identity is invented: "Ada Example", handle "adaexample" (paperlint.json).
|
|
3
|
+
\documentclass[conference,compsoc]{IEEEtran}
|
|
4
|
+
\newcommand{\me}{Ada Example}
|
|
5
|
+
\begin{filecontents*}{refs.bib}
|
|
6
|
+
@article{knuth84,
|
|
7
|
+
title = {Literate Programming},
|
|
8
|
+
author = {Knuth, Donald E.},
|
|
9
|
+
journal = {The Computer Journal},
|
|
10
|
+
volume = {27},
|
|
11
|
+
number = {2},
|
|
12
|
+
pages = {97--111},
|
|
13
|
+
year = {1984},
|
|
14
|
+
doi = {10.1093/comjnl/27.2.97}
|
|
15
|
+
}
|
|
16
|
+
\end{filecontents*}
|
|
17
|
+
\begin{document}
|
|
18
|
+
\title{A Fixture for Double-Blind Review}
|
|
19
|
+
\author{\IEEEauthorblockN{Anonymous Authors}}
|
|
20
|
+
\maketitle
|
|
21
|
+
\section{Introduction}
|
|
22
|
+
This paper builds on earlier work~\cite{knuth84}.
|
|
23
|
+
This extends a tool first described by \me.
|
|
24
|
+
\section{Conclusion}
|
|
25
|
+
The conclusion restates that the fixture builds.
|
|
26
|
+
\bibliographystyle{IEEEtran}
|
|
27
|
+
\bibliography{refs}
|
|
28
|
+
\section*{LLM Usage Statement}
|
|
29
|
+
No LLMs were used in writing this fixture.
|
|
30
|
+
\end{document}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"extends": "paperlint:aidc", "kind": "short", "identity": ["Ada Example", "adaexample", "ada@example.org", "Example University", "exampletool"]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$comment": "anonymity/identity on a real IEEEtran build: D: the name only in the PDF metadata, set by hyperref; no page shows it. Exactly one finding, naming where.",
|
|
3
|
+
"build": {
|
|
4
|
+
"outcome": "pdf"
|
|
5
|
+
},
|
|
6
|
+
"lint": {
|
|
7
|
+
"rules": {
|
|
8
|
+
"anonymity/identity": [
|
|
9
|
+
{
|
|
10
|
+
"severity": 2,
|
|
11
|
+
"says": [
|
|
12
|
+
"PDF metadata: Author",
|
|
13
|
+
"«Ada Example»"
|
|
14
|
+
]
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
% D: the name only in the PDF metadata, set by hyperref; no page shows it.
|
|
2
|
+
% The declared identity is invented: "Ada Example", handle "adaexample" (paperlint.json).
|
|
3
|
+
\documentclass[conference,compsoc]{IEEEtran}
|
|
4
|
+
\usepackage{hyperref}
|
|
5
|
+
\hypersetup{pdfauthor={Ada Example}}
|
|
6
|
+
\begin{filecontents*}{refs.bib}
|
|
7
|
+
@article{knuth84,
|
|
8
|
+
title = {Literate Programming},
|
|
9
|
+
author = {Knuth, Donald E.},
|
|
10
|
+
journal = {The Computer Journal},
|
|
11
|
+
volume = {27},
|
|
12
|
+
number = {2},
|
|
13
|
+
pages = {97--111},
|
|
14
|
+
year = {1984},
|
|
15
|
+
doi = {10.1093/comjnl/27.2.97}
|
|
16
|
+
}
|
|
17
|
+
\end{filecontents*}
|
|
18
|
+
\begin{document}
|
|
19
|
+
\title{A Fixture for Double-Blind Review}
|
|
20
|
+
\author{\IEEEauthorblockN{Anonymous Authors}}
|
|
21
|
+
\maketitle
|
|
22
|
+
\section{Introduction}
|
|
23
|
+
This paper builds on earlier work~\cite{knuth84}.
|
|
24
|
+
|
|
25
|
+
\section{Conclusion}
|
|
26
|
+
The conclusion restates that the fixture builds.
|
|
27
|
+
\bibliographystyle{IEEEtran}
|
|
28
|
+
\bibliography{refs}
|
|
29
|
+
\section*{LLM Usage Statement}
|
|
30
|
+
No LLMs were used in writing this fixture.
|
|
31
|
+
\end{document}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"extends": "paperlint:aidc", "kind": "short", "identity": ["Ada Example", "adaexample", "ada@example.org", "Example University", "exampletool"]}
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
}
|
|
19
19
|
},
|
|
20
20
|
"facts": {
|
|
21
|
-
"schema":
|
|
21
|
+
"schema": 3,
|
|
22
22
|
"lastPageColumnsPt": [
|
|
23
23
|
621.5,
|
|
24
24
|
264.8
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"pdf/profile": [],
|
|
46
46
|
"pdf/fonts": [],
|
|
47
47
|
"pdf/geometry": [],
|
|
48
|
-
"
|
|
48
|
+
"format/page-limit": [],
|
|
49
49
|
"pdf/body-size": [],
|
|
50
50
|
"pdf/measured": [
|
|
51
51
|
{
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"this file names the rule. That is not expressible on an eleven-line stub, where every line was",
|
|
8
8
|
"written by someone who already knew which rule would read it.",
|
|
9
9
|
"",
|
|
10
|
-
"Recorded 2026-09-19, re-recorded 2026-09-26 for 3.0.0.
|
|
10
|
+
"Recorded 2026-09-19, re-recorded 2026-09-26 for 3.0.0. Two of the three rules are about the",
|
|
11
11
|
"scorecard being deliberately thin (no pdf, no frozen source) rather than about the prose.",
|
|
12
12
|
"paper/leading-zero reports each of the 18 p-values of paperlint#44 where it is (one finding per",
|
|
13
13
|
"occurrence since 3.0.0; before, paper/typography reported them as one count). They are real",
|
|
@@ -17,7 +17,6 @@
|
|
|
17
17
|
"findings": {
|
|
18
18
|
"paper/stages": 2,
|
|
19
19
|
"paper/source": 1,
|
|
20
|
-
"paper/research-question": 1,
|
|
21
20
|
"paper/leading-zero": 18
|
|
22
21
|
}
|
|
23
22
|
}
|
package/lib/paper-config.ts
CHANGED
|
@@ -136,8 +136,10 @@ export const SETTINGS_KEYS: Readonly<Record<string, string>> = Object.freeze({
|
|
|
136
136
|
"rule overrides: { id: severity } for every paper in scope, or ESLint blocks (files, ignores, rules) — paperlint lint",
|
|
137
137
|
extends:
|
|
138
138
|
"the venue preset: paperlint:<name> or ./path.jsonc — the pdf/ venue rules, paperlint build",
|
|
139
|
-
kind: "the kind of paper, whose page limit applies —
|
|
139
|
+
kind: "the kind of paper, whose page limit applies — format/page-limit",
|
|
140
140
|
pdf: "where the built PDF is, relative to the paper, when it is not paper.pdf — the facts",
|
|
141
|
+
identity:
|
|
142
|
+
"what identifies the authors — names, handles, emails, affiliations, own project names; a blind venue's PDF must not say any of them — anonymity/identity. The root's list and a paper's are joined",
|
|
141
143
|
scripts: "how skill prose names the scripts — consumer.mjs",
|
|
142
144
|
timezone: "the zone deadline anchors are written in — consumer.mjs",
|
|
143
145
|
contactEmail: "the polite-pool address for citation lookups — consumer.mjs",
|
package/package.json
CHANGED
|
@@ -74,7 +74,9 @@
|
|
|
74
74
|
// «font size is 9 pt for all body text»
|
|
75
75
|
"body_pt": 9,
|
|
76
76
|
// banal measures the MODE of the rendered text, not the declared size (measured 08-26: 9.30 at
|
|
77
|
-
// acmart's declared 9). Hence the tolerance
|
|
77
|
+
// acmart's declared 9). Hence the tolerance: banal reads 0.3 pt high on every template measured
|
|
78
|
+
// (fixtures/accepted-papers/body-size.json), and 0.5 absorbs that while a paper one size off is
|
|
79
|
+
// still reported.
|
|
78
80
|
"body_pt_tol": 0.5,
|
|
79
81
|
|
|
80
82
|
// «font size of the references can be from 7 pt to 9 pt»
|
package/presets/aidc.jsonc
CHANGED
|
@@ -22,6 +22,10 @@
|
|
|
22
22
|
{
|
|
23
23
|
"extends": "paperlint:ieee-conference",
|
|
24
24
|
|
|
25
|
+
// «Submissions must be properly anonymized for double-blind review.» (the call above), and
|
|
26
|
+
// `"blind":true` in the portal's data. anonymity/identity then requires the paper's `identity`.
|
|
27
|
+
"blind": true,
|
|
28
|
+
|
|
25
29
|
// What the venue is called in a paper's text (tex/venue-leftover): the workshop, and the
|
|
26
30
|
// conference it is held at.
|
|
27
31
|
"aliases": ["AIDC", "ACSAC"],
|
|
@@ -44,30 +48,25 @@
|
|
|
44
48
|
"textblock_w_in": 7.0,
|
|
45
49
|
"textblock_h_in": 9.02,
|
|
46
50
|
|
|
47
|
-
// 🔴 PAGE
|
|
48
|
-
// and references by what is on them, and a page that holds ANY non-bibliography text
|
|
49
|
-
// body. Measured 2026-09-27 on a [conference,compsoc] paper whose body ends at the
|
|
50
|
-
// page 12:
|
|
51
|
+
// 🔴 THE PAGE LIMIT IS COUNTED BEFORE THE REFERENCES, NOT BY banal. banal splits pages into
|
|
52
|
+
// body and references by what is on them, and a page that holds ANY non-bibliography text
|
|
53
|
+
// counts as body. Measured 2026-09-27 on a [conference,compsoc] paper whose body ends at the
|
|
54
|
+
// foot of page 12:
|
|
51
55
|
// LLM Usage Statement before the references → body 13, references 0
|
|
52
56
|
// an appendix before the references → body 13, references 2
|
|
53
57
|
// both placed after the references → body right, the tail counted as references
|
|
54
58
|
// AIDC counts neither in the limit («excluding references and appendices»; the ACSAC AI policy:
|
|
55
|
-
// the LLM Usage Statement «does not count towards the page limit»)
|
|
56
|
-
//
|
|
57
|
-
//
|
|
58
|
-
//
|
|
59
|
-
"
|
|
60
|
-
"_": "Body pages, excluding references, appendices and the LLM Usage Statement. banal counts a page holding an appendix or the statement before the bibliography as body, so its body count is not this number.",
|
|
61
|
-
"regular": 12,
|
|
62
|
-
"short": 6,
|
|
63
|
-
"references_and_appendices": "unlimited",
|
|
64
|
-
"llm_usage_statement": "not counted (ACSAC AI policy)",
|
|
65
|
-
},
|
|
59
|
+
// the LLM Usage Statement «does not count towards the page limit»). So format/page-limit counts
|
|
60
|
+
// the body up to where the references start (`body_ends_at`): the page they start on counts
|
|
61
|
+
// when body text stands above the heading there, and the limit below is gated. An appendix
|
|
62
|
+
// ends the body too, wherever it sits, when hyperref anchors it (docs/rules/format/page-limit.md).
|
|
63
|
+
"body_ends_at": "references",
|
|
66
64
|
|
|
67
65
|
// «Short position papers or work-in-progress (WIP) papers» share one limit, so one kind.
|
|
66
|
+
// References, appendices and the LLM Usage Statement: unlimited.
|
|
68
67
|
"kinds": {
|
|
69
|
-
"regular": {},
|
|
70
|
-
"short": {},
|
|
68
|
+
"regular": { "body_pages_max": 12 },
|
|
69
|
+
"short": { "body_pages_max": 6 },
|
|
71
70
|
},
|
|
72
71
|
},
|
|
73
72
|
}
|
|
@@ -59,6 +59,14 @@
|
|
|
59
59
|
"body_pt": 10,
|
|
60
60
|
"body_pt_tol": 0.5,
|
|
61
61
|
|
|
62
|
+
// The class sets the bibliography in \footnotesize, 8 pt at 10pt and at 9pt (IEEEtran.cls,
|
|
63
|
+
// \thebibliography). Measured 2026-09-29 on the four built ACSAC papers in
|
|
64
|
+
// fixtures/accepted-papers (body-size.json): pdf.js reads the reference glyphs at 8.00 pt
|
|
65
|
+
// (7.97 without compsoc), banal gives 8.3 on all four. body_pt_tol widens it to 7.5-8.5, so a
|
|
66
|
+
// bibliography shrunk to \scriptsize (7.3) or grown to \small (9.3) is reported.
|
|
67
|
+
"ref_pt_min": 8,
|
|
68
|
+
"ref_pt_max": 8,
|
|
69
|
+
|
|
62
70
|
// The Times clone. Headings and the title are set in the same family, so a `fonts_title` would
|
|
63
71
|
// repeat this check and report a Computer Modern build twice.
|
|
64
72
|
"fonts_text": "NimbusRomNo9L",
|
|
@@ -24,6 +24,10 @@
|
|
|
24
24
|
"type": "string",
|
|
25
25
|
"minLength": 1
|
|
26
26
|
},
|
|
27
|
+
"blind": {
|
|
28
|
+
"description": "The venue reviews double-blind: its call says submissions must be anonymized. Read by `anonymity/identity`, which then requires the paper's `identity` and finds none of it in the PDF. Set only where the venue says so, with the quote. A child's value replaces its parent's.",
|
|
29
|
+
"type": "boolean"
|
|
30
|
+
},
|
|
27
31
|
"aliases": {
|
|
28
32
|
"description": "Other names the venue goes by in a paper's text — its acronym, its parent conference (`[\"AISec\", \"ACM CCS\"]`). Read by `tex/venue-leftover`: a paper that extends another venue and says one of these is flagged. Matched as whole words, case-sensitive. Collected along the `extends` chain, with `name`.",
|
|
29
33
|
"type": "array",
|
|
@@ -105,6 +109,11 @@
|
|
|
105
109
|
"type": "string",
|
|
106
110
|
"minLength": 1
|
|
107
111
|
},
|
|
112
|
+
"body_ends_at": {
|
|
113
|
+
"description": "How `format/page-limit` counts body pages. Absent: banal's body count (every page holding non-bibliography text). `references`: the pages up to where the body ends — at the references or the appendix, whichever comes first, found by hyperref's anchors and then the heading line — with that page counted when body text stands above the heading on it; for a venue whose limit excludes references and appendices (and what follows them, such as statements).",
|
|
114
|
+
"type": "string",
|
|
115
|
+
"enum": ["references"]
|
|
116
|
+
},
|
|
108
117
|
"page_limits_not_gated": {
|
|
109
118
|
"type": "object"
|
|
110
119
|
},
|
package/scripts/check.ts
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
* `npm run check` — ONE command you run on yourself before pushing.
|
|
4
4
|
*
|
|
5
5
|
* ── WHY IT EXISTS, AND IT IS A MEASURED FAILURE, NOT A TIDINESS IDEA ───────────────────────
|
|
6
|
-
* On 2026-09-19 a change to
|
|
6
|
+
* On 2026-09-19 a change to a lint rule was pushed that broke the test suite.
|
|
7
7
|
* The gates were run afterwards — `lint`, `check:readme`, `check:globs`, `check:content-only`,
|
|
8
|
-
* and the rule's own
|
|
8
|
+
* and the rule's own mutation battery, all green — but `npm test` and `test:install` were not,
|
|
9
9
|
* because there were eleven separate scripts and no way to run them except from memory. Five
|
|
10
10
|
* callers across two files had been left behind by the change, and the suite said so; nobody
|
|
11
11
|
* asked it.
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
* proves the BEHAVIOUR rather than the presence of a string in YAML.
|
|
18
18
|
*
|
|
19
19
|
* Usage: node scripts/eslint-report-guard.mjs <report.json> <eslint-rc> [paths] [config]
|
|
20
|
+
* An empty or absent `paths` means the CLI was given none and linted the papersDir of the config.
|
|
20
21
|
* Exit: 1 when nothing was measured (unparsable report, or zero files linted)
|
|
21
22
|
* otherwise ESLint's own return code, passed through untouched
|
|
22
23
|
*/
|
|
@@ -26,8 +27,10 @@ import { readFileSync } from "node:fs";
|
|
|
26
27
|
export function guard(
|
|
27
28
|
reportPath,
|
|
28
29
|
eslintRc,
|
|
29
|
-
{ paths = "
|
|
30
|
+
{ paths = "", config = "paperlint.json" } = {},
|
|
30
31
|
) {
|
|
32
|
+
const scope =
|
|
33
|
+
paths.trim() === "" ? "(none: the papersDir of paperlint.json)" : paths;
|
|
31
34
|
const lines = [];
|
|
32
35
|
let res;
|
|
33
36
|
try {
|
|
@@ -48,7 +51,7 @@ export function guard(
|
|
|
48
51
|
if (res.length === 0) {
|
|
49
52
|
lines.push(
|
|
50
53
|
"::error::ESLint linted ZERO files. In the exit code this is indistinguishable from a clean " +
|
|
51
|
-
`run, and it means the paths or the config matched nothing. paths=${
|
|
54
|
+
`run, and it means the paths or the config matched nothing. paths=${scope} config=${config}`,
|
|
52
55
|
);
|
|
53
56
|
return { code: 1, lines };
|
|
54
57
|
}
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
"action.harness.mjs",
|
|
6
6
|
"eslint-rules/install-path-literals.harness.mjs",
|
|
7
7
|
"eslint-rules/latex-language.harness.mjs",
|
|
8
|
-
"eslint-rules/paper-research-question.harness.mjs",
|
|
9
8
|
"eslint-rules/paper-stages.harness.mjs",
|
|
10
9
|
"eslint-rules/papers.harness.mjs",
|
|
11
10
|
"eslint-rules/pdf-last-page-balance.harness.mjs",
|
|
@@ -11,7 +11,7 @@ the verdict line's wording and the `☐`/`☑` marks as they are, or the hook go
|
|
|
11
11
|
|
|
12
12
|
## The front matter
|
|
13
13
|
|
|
14
|
-
Above the sections, the file carries YAML.
|
|
14
|
+
Above the sections, the file carries YAML. The rules read its `stages` field:
|
|
15
15
|
|
|
16
16
|
```yaml
|
|
17
17
|
---
|
|
@@ -22,20 +22,9 @@ stages:
|
|
|
22
22
|
bytes: 305412
|
|
23
23
|
source: versions/2026-07-22-submitted.tex
|
|
24
24
|
sourceBytes: 57210
|
|
25
|
-
researchQuestion: "Does pruning the state space reduce review cost?"
|
|
26
25
|
---
|
|
27
26
|
```
|
|
28
27
|
|
|
29
|
-
`researchQuestion` is **your sentence, written once** — not a label the checker hunts for in the
|
|
30
|
-
prose. `paper/research-question` then asks two things it can actually answer: is it written down,
|
|
31
|
-
and does the paper contain it (whitespace collapsed). Leave the field out and a shipped paper gets
|
|
32
|
-
an advisory finding, which is the right outcome for a position paper with no question: the absence
|
|
33
|
-
becomes a decision on the record rather than an omission.
|
|
34
|
-
|
|
35
|
-
⚠️ Write the sentence the way it appears in the paper. If the paper breaks it across lines that is
|
|
36
|
-
fine — only whitespace is normalised — but LaTeX markup inside the sentence (`\emph{cost}`) will not
|
|
37
|
-
match, and the finding will quote exactly what it looked for.
|
|
38
|
-
|
|
39
28
|
## The row ids, and what each one runs
|
|
40
29
|
|
|
41
30
|
The `id` cell is the **join key** — the same string appears in this template, in every paper's
|
|
@@ -116,10 +105,7 @@ existed. Neither is expressible now. Keep new ids lowercase, one word, and say w
|
|
|
116
105
|
The template itself is a FILE, not this page: `templates/paper/PIPELINE-STATUS.md` at the package
|
|
117
106
|
root (beside `templates/paper/paper.tex` and `paper.md`). `paperlint new <name>` copies it with the paper's
|
|
118
107
|
name filled in, and a project that keeps its own richer scorecard puts one at
|
|
119
|
-
`<papers>/.template/PIPELINE-STATUS.md`, which `paperlint new` prefers.
|
|
120
|
-
here, which meant a command would have had to parse markdown to extract it, and a human had to copy
|
|
121
|
-
it by hand. The copy carries `researchQuestion` (empty) and no `stages` — a new paper has shipped
|
|
122
|
-
nothing.
|
|
108
|
+
`<papers>/.template/PIPELINE-STATUS.md`, which `paperlint new` prefers. The copy carries no `stages` — a new paper has shipped nothing.
|
|
123
109
|
|
|
124
110
|
---
|
|
125
111
|
|
|
@@ -119,8 +119,8 @@ try {
|
|
|
119
119
|
const fonts = Fonts.safeParse(facts.fonts);
|
|
120
120
|
const fontList = fonts.success ? fonts.data : [];
|
|
121
121
|
check(
|
|
122
|
-
"the facts are schema
|
|
123
|
-
facts.schema ===
|
|
122
|
+
"the facts are schema 3, about paper.pdf, for the venue paperlint.json declares",
|
|
123
|
+
facts.schema === 3 &&
|
|
124
124
|
facts.pdf === "paper.pdf" &&
|
|
125
125
|
facts.venue === "agenticdev" &&
|
|
126
126
|
facts.kind === "short",
|
|
@@ -236,5 +236,5 @@ try {
|
|
|
236
236
|
}
|
|
237
237
|
|
|
238
238
|
console.log(
|
|
239
|
-
`✓ ${String(check.count)} assertions passed — extract-pdf-facts: the exit-code contract, schema
|
|
239
|
+
`✓ ${String(check.count)} assertions passed — extract-pdf-facts: the exit-code contract, schema 3, and the no-no-yes font`,
|
|
240
240
|
);
|
|
@@ -55,10 +55,18 @@ export const includesOf = (t: ParsedTex): readonly Include[] =>
|
|
|
55
55
|
const isDocument = (n: Node): n is Readonly<Ast.Environment> =>
|
|
56
56
|
n.type === "environment" && n.env === "document";
|
|
57
57
|
|
|
58
|
-
/**
|
|
58
|
+
/**
|
|
59
|
+
* The span of the `document` environment's body, or null when the source has none. A macro's own
|
|
60
|
+
* position ends at its name, so its place is taken with its arguments: a body ending in
|
|
61
|
+
* `\input{sections/a}` ends at the closing brace.
|
|
62
|
+
*/
|
|
59
63
|
export const documentBodyOf = (t: ParsedTex): Span | null =>
|
|
60
64
|
(t.root.content.find(isDocument)?.content ?? [])
|
|
61
|
-
.flatMap((n) =>
|
|
65
|
+
.flatMap((n) =>
|
|
66
|
+
inPlace(n.type === "macro" ? macroPlace(n) : placeOf(n), (span) => [
|
|
67
|
+
span,
|
|
68
|
+
]),
|
|
69
|
+
)
|
|
62
70
|
.reduce<Span | null>(
|
|
63
71
|
(body, span) =>
|
|
64
72
|
body === null ? span : { start: body.start, end: span.end },
|
|
@@ -526,6 +526,14 @@ describe("documentBodyOf — the body of a source that is a document of its own"
|
|
|
526
526
|
expect(latexReader.documentBody(src)).toEqual(body);
|
|
527
527
|
});
|
|
528
528
|
|
|
529
|
+
it("a body ending in a macro ends after that macro's arguments, not after its name", () => {
|
|
530
|
+
const src = "\\begin{document}\nText.\n\\input{sections/a}\\end{document}";
|
|
531
|
+
const body = documentBodyOf(parseLatex(src));
|
|
532
|
+
expect(body && src.slice(body.start, body.end)).toBe(
|
|
533
|
+
"Text.\n\\input{sections/a}",
|
|
534
|
+
);
|
|
535
|
+
});
|
|
536
|
+
|
|
529
537
|
it("none without a document environment, or with an empty one", () => {
|
|
530
538
|
expect(documentBodyOf(parseLatex("just text"))).toBe(null);
|
|
531
539
|
expect(documentBodyOf(parseLatex("\\begin{document}\\end{document}"))).toBe(
|