paperlint 10.4.1 → 11.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/.github/workflows/deadlines.yml +27 -7
- package/README.md +16 -15
- package/dist/adapters/hotcrp/index.d.ts +6 -4
- package/dist/adapters/hotcrp/index.d.ts.map +1 -1
- package/dist/adapters/hotcrp/index.js +6 -4
- package/dist/adapters/hotcrp/index.js.map +1 -1
- package/dist/adapters/hotcrp/portal.io.d.ts +3 -1
- package/dist/adapters/hotcrp/portal.io.d.ts.map +1 -1
- package/dist/adapters/hotcrp/portal.io.js +36 -11
- package/dist/adapters/hotcrp/portal.io.js.map +1 -1
- package/dist/adapters/hotcrp/response.d.ts +6 -1
- package/dist/adapters/hotcrp/response.d.ts.map +1 -1
- package/dist/adapters/hotcrp/response.js +17 -0
- package/dist/adapters/hotcrp/response.js.map +1 -1
- package/dist/adapters/hotcrp/site.d.ts +9 -0
- package/dist/adapters/hotcrp/site.d.ts.map +1 -0
- package/dist/adapters/hotcrp/site.js +22 -0
- package/dist/adapters/hotcrp/site.js.map +1 -0
- package/dist/adapters/hotcrp/token.d.ts +13 -0
- package/dist/adapters/hotcrp/token.d.ts.map +1 -0
- package/dist/adapters/hotcrp/token.js +48 -0
- package/dist/adapters/hotcrp/token.js.map +1 -0
- package/dist/adapters/latex/abstract.d.ts +22 -0
- package/dist/adapters/latex/abstract.d.ts.map +1 -0
- package/dist/adapters/latex/abstract.js +187 -0
- package/dist/adapters/latex/abstract.js.map +1 -0
- package/dist/adapters/latex/headings.d.ts +6 -0
- package/dist/adapters/latex/headings.d.ts.map +1 -1
- package/dist/adapters/latex/headings.js +5 -4
- package/dist/adapters/latex/headings.js.map +1 -1
- package/dist/adapters/latex/index.d.ts.map +1 -1
- package/dist/adapters/latex/index.js +2 -0
- package/dist/adapters/latex/index.js.map +1 -1
- package/dist/adapters/latex/parse.d.ts +15 -0
- package/dist/adapters/latex/parse.d.ts.map +1 -1
- package/dist/adapters/latex/parse.js +58 -1
- package/dist/adapters/latex/parse.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +20 -8
- package/dist/cli.js.map +1 -1
- package/dist/cycle-rules.d.ts.map +1 -1
- package/dist/cycle-rules.js +3 -4
- package/dist/cycle-rules.js.map +1 -1
- package/dist/domain/deadline.d.ts +8 -1
- package/dist/domain/deadline.d.ts.map +1 -1
- package/dist/domain/deadline.js +26 -12
- package/dist/domain/deadline.js.map +1 -1
- package/dist/domain/portal-token.d.ts +44 -0
- package/dist/domain/portal-token.d.ts.map +1 -0
- package/dist/domain/portal-token.js +32 -0
- package/dist/domain/portal-token.js.map +1 -0
- package/dist/domain/submission.d.ts +30 -0
- package/dist/domain/submission.d.ts.map +1 -1
- package/dist/domain/submission.js +68 -0
- package/dist/domain/submission.js.map +1 -1
- package/dist/lib/paper-config.d.ts +1 -1
- package/dist/lib/paper-config.d.ts.map +1 -1
- package/dist/lib/paper-config.js +6 -4
- package/dist/lib/paper-config.js.map +1 -1
- package/dist/paper-settings.d.ts +3 -1
- package/dist/paper-settings.d.ts.map +1 -1
- package/dist/paper-settings.js +11 -5
- package/dist/paper-settings.js.map +1 -1
- package/dist/ports/latex.d.ts +23 -0
- package/dist/ports/latex.d.ts.map +1 -1
- package/dist/ports/submission-portal.d.ts +39 -2
- package/dist/ports/submission-portal.d.ts.map +1 -1
- package/dist/ports/venue-deadlines.d.ts +1 -1
- package/dist/submission.d.ts +49 -11
- package/dist/submission.d.ts.map +1 -1
- package/dist/submission.js +332 -44
- package/dist/submission.js.map +1 -1
- package/docs/configuration.md +2 -1
- package/docs/rules/cycle/record.md +9 -6
- package/docs/submission.md +47 -48
- package/eslint.config.mjs +3 -0
- package/lib/paper-config.ts +7 -4
- package/package.json +6 -1
- package/presets/msr.jsonc +9 -7
- package/presets/msr.md +14 -10
- package/scripts/check.ts +1 -1
- package/scripts/refresh-deadlines/compare.test.ts +75 -0
- package/scripts/refresh-deadlines/compare.ts +101 -0
- package/scripts/refresh-deadlines/main.test.ts +140 -0
- package/scripts/refresh-deadlines/main.ts +56 -0
- package/scripts/refresh-deadlines/refresh.test.ts +287 -0
- package/scripts/refresh-deadlines/refresh.ts +183 -0
- package/skills/submission-portal/SKILL.md +60 -44
- package/skills/submission-portal/SKILL.md.spec.ts +62 -43
- package/skills/submission-portal/submission-portal.test.ts +4 -73
- package/src/adapters/hotcrp/cassette/README.md +4 -4
- package/src/adapters/hotcrp/cassette/deadlines-msr2027.html +9 -9
- package/src/adapters/hotcrp/deadlines.io.test.ts +2 -2
- package/src/adapters/hotcrp/deadlines.test.ts +3 -3
- package/src/adapters/hotcrp/index.ts +15 -3
- package/src/adapters/hotcrp/portal.io.ts +61 -17
- package/src/adapters/hotcrp/portal.test.ts +105 -1
- package/src/adapters/hotcrp/response.ts +21 -0
- package/src/adapters/hotcrp/site.ts +34 -0
- package/src/adapters/hotcrp/token.test.ts +69 -0
- package/src/adapters/hotcrp/token.ts +51 -0
- package/src/adapters/latex/abstract.test.ts +280 -0
- package/src/adapters/latex/abstract.ts +272 -0
- package/src/adapters/latex/headings.ts +5 -4
- package/src/adapters/latex/index.test.ts +31 -1
- package/src/adapters/latex/index.ts +2 -0
- package/src/adapters/latex/parse.ts +64 -3
- package/src/cli.test.ts +20 -8
- package/src/cli.ts +22 -13
- package/src/cycle-rules.test.ts +6 -6
- package/src/cycle-rules.ts +7 -4
- package/src/domain/deadline.test.ts +31 -2
- package/src/domain/deadline.ts +42 -16
- package/src/domain/portal-token.test.ts +55 -0
- package/src/domain/portal-token.ts +63 -0
- package/src/domain/submission.test.ts +88 -0
- package/src/domain/submission.ts +99 -0
- package/src/new-paper.test.ts +1 -0
- package/src/paper-settings.test.ts +20 -0
- package/src/paper-settings.ts +17 -5
- package/src/ports/latex.ts +25 -0
- package/src/ports/submission-portal.ts +43 -1
- package/src/ports/venue-deadlines.ts +1 -1
- package/src/presets.test.ts +8 -5
- package/src/submission-new.test.ts +569 -0
- package/src/submission-show.test.ts +210 -0
- package/src/submission-update.test.ts +160 -0
- package/src/submission.test.ts +140 -518
- package/src/submission.ts +494 -61
- package/scripts/refresh-deadlines.test.ts +0 -431
- package/scripts/refresh-deadlines.ts +0 -387
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
#
|
|
3
3
|
# A shipped venue preset (presets/msr.jsonc, presets/aidc.jsonc) carries its portal's deadlines,
|
|
4
4
|
# each with the day it was read. Chairs move deadlines; a paper only learns it if the preset does.
|
|
5
|
-
# So this job reads every preset's portal (`
|
|
5
|
+
# So this job reads every preset's portal (`npm run refresh-deadlines`, through the HotCRP adapter
|
|
6
6
|
# in src/adapters/hotcrp/ — the public deadlines page, no account, no secret) and, when a value
|
|
7
7
|
# changed, opens ONE pull request with the new values, or updates the one already open. Its commit
|
|
8
8
|
# and title are `fix(presets): …`, which semantic-release (.releaserc.json, conventionalcommits)
|
|
@@ -13,7 +13,8 @@
|
|
|
13
13
|
# line in the pull request's body, and the script exits 0: the venue's outage is not a defect of this
|
|
14
14
|
# repository, and tomorrow's run reads it again. Only a preset that does not parse fails the run
|
|
15
15
|
# (exit 1) — that one IS ours, and `ci` fails on it too. `ci` itself never touches the network for
|
|
16
|
-
# this: scripts/refresh-deadlines.test.ts replays the
|
|
16
|
+
# this: scripts/refresh-deadlines/main.test.ts replays the MSR page recorded in
|
|
17
|
+
# src/adapters/hotcrp/cassette/, and refresh.test.ts fakes the portal.
|
|
17
18
|
#
|
|
18
19
|
# ⚠️ A pull request opened with GITHUB_TOKEN does not start other workflows (GitHub's rule against
|
|
19
20
|
# loops), so `ci` would never run on it and the PR could not show green. The last step therefore
|
|
@@ -37,11 +38,13 @@ concurrency:
|
|
|
37
38
|
group: deadlines
|
|
38
39
|
cancel-in-progress: false
|
|
39
40
|
|
|
40
|
-
# Push the bot's branch · open or edit its pull request · dispatch `ci` on it
|
|
41
|
+
# Push the bot's branch · open or edit its pull request · dispatch `ci` on it · report a failed run
|
|
42
|
+
# in one issue. Nothing else.
|
|
41
43
|
permissions:
|
|
42
44
|
contents: write
|
|
43
45
|
pull-requests: write
|
|
44
46
|
actions: write
|
|
47
|
+
issues: write
|
|
45
48
|
|
|
46
49
|
jobs:
|
|
47
50
|
refresh:
|
|
@@ -57,14 +60,17 @@ jobs:
|
|
|
57
60
|
node-version: "22"
|
|
58
61
|
cache: npm
|
|
59
62
|
|
|
60
|
-
# `--ignore-scripts`:
|
|
61
|
-
#
|
|
63
|
+
# `--ignore-scripts`: no `prepare` build, so there is no `dist/`. The npm script runs the code
|
|
64
|
+
# from source with `--conditions=paperlint-source` (package.json); without it `#lib/*` resolves
|
|
65
|
+
# to `dist/`, and every run from 2026-10-06 to 2026-10-19 died on ERR_MODULE_NOT_FOUND
|
|
66
|
+
# dist/lib/paper-config.js. scripts/refresh-deadlines/main.test.ts runs the same npm script on every
|
|
67
|
+
# pull request under test/no-dist.ts, which refuses any module in `dist/`.
|
|
62
68
|
- name: npm ci
|
|
63
69
|
run: npm ci --ignore-scripts
|
|
64
70
|
timeout-minutes: 5
|
|
65
71
|
|
|
66
72
|
- name: read every preset's portal
|
|
67
|
-
run:
|
|
73
|
+
run: npm run refresh-deadlines -- --summary "$RUNNER_TEMP/deadlines.md"
|
|
68
74
|
timeout-minutes: 3
|
|
69
75
|
|
|
70
76
|
- name: open or update the pull request
|
|
@@ -85,7 +91,7 @@ jobs:
|
|
|
85
91
|
git commit -F - <<'MSG'
|
|
86
92
|
fix(presets): venue deadlines as their portals publish them now
|
|
87
93
|
|
|
88
|
-
Re-read by .github/workflows/deadlines.yml (
|
|
94
|
+
Re-read by .github/workflows/deadlines.yml (npm run refresh-deadlines); the pull
|
|
89
95
|
request's body lists each value that changed and where it was read.
|
|
90
96
|
MSG
|
|
91
97
|
# The branch is the bot's own and is rebuilt from main on every run: force is the point.
|
|
@@ -98,3 +104,17 @@ jobs:
|
|
|
98
104
|
gh pr edit "$open" --repo "$REPO" --title "$title" --body-file "$RUNNER_TEMP/deadlines.md"
|
|
99
105
|
fi
|
|
100
106
|
gh workflow run ci.yml --repo "$REPO" --ref "$BRANCH"
|
|
107
|
+
|
|
108
|
+
# 🔴 A FAILED RUN IS AN ISSUE, NOT A RED DOT NOBODY OPENS. The job failed on every scheduled run
|
|
109
|
+
# from 2026-10-06 to 2026-10-19 and nobody looked: MSR moved both deadlines and the preset kept
|
|
110
|
+
# the old ones (#235). So any failure opens ONE issue labelled and titled "deadline refresh
|
|
111
|
+
# failing", or comments on the open one, with the run's link. A portal that is down is not a
|
|
112
|
+
# failure (the script warns and exits 0), so this fires only for a defect of ours.
|
|
113
|
+
- name: report a failed refresh in one issue
|
|
114
|
+
if: failure()
|
|
115
|
+
uses: jayqi/failed-build-issue-action@940568ce50eeef3f31a920614cefcc6102d2f930 # v1.3.0
|
|
116
|
+
with:
|
|
117
|
+
label-name: deadline refresh failing
|
|
118
|
+
title-template: deadline refresh failing
|
|
119
|
+
body-template: |
|
|
120
|
+
The scheduled refresh of the venue presets' deadlines failed: {{serverUrl}}/{{repo.owner}}/{{repo.repo}}/actions/runs/{{runId}} — until it is fixed, a deadline a portal moves is not picked up by the presets.
|
package/README.md
CHANGED
|
@@ -150,20 +150,21 @@ Each stage's skills, what it writes and what checks it, drawn as one flow, with
|
|
|
150
150
|
|
|
151
151
|
## 🧰 Commands
|
|
152
152
|
|
|
153
|
-
| command | what it does
|
|
154
|
-
| ----------------------------------------------------------- |
|
|
155
|
-
| `npx paperlint init` | sets the project up
|
|
156
|
-
| `npx paperlint new my-paper --venue <preset> --kind <kind>` | creates a paper folder for that venue, or completes an existing one
|
|
157
|
-
| `npx paperlint build <paper>` | compiles `paper.tex` to `paper.pdf`, measures it, checks the references online
|
|
158
|
-
| `npx paperlint lint` | runs every check over your papers; `--fix` fixes what can be fixed
|
|
159
|
-
| `npx paperlint toolchain` | installs TeX Live with the packages your venues need (~270 MB, ~3 min, once)
|
|
160
|
-
| `npx paperlint doctor` | checks the setup and exits non-zero if something is miswired
|
|
161
|
-
| `npx paperlint submission
|
|
162
|
-
| `npx paperlint submission
|
|
163
|
-
| `npx paperlint
|
|
164
|
-
| `npx paperlint studies
|
|
165
|
-
| `npx paperlint studies
|
|
166
|
-
| `npx paperlint
|
|
153
|
+
| command | what it does |
|
|
154
|
+
| ----------------------------------------------------------- | --------------------------------------------------------------------------------------- |
|
|
155
|
+
| `npx paperlint init` | sets the project up |
|
|
156
|
+
| `npx paperlint new my-paper --venue <preset> --kind <kind>` | creates a paper folder for that venue, or completes an existing one |
|
|
157
|
+
| `npx paperlint build <paper>` | compiles `paper.tex` to `paper.pdf`, measures it, checks the references online |
|
|
158
|
+
| `npx paperlint lint` | runs every check over your papers; `--fix` fixes what can be fixed |
|
|
159
|
+
| `npx paperlint toolchain` | installs TeX Live with the packages your venues need (~270 MB, ~3 min, once) |
|
|
160
|
+
| `npx paperlint doctor` | checks the setup and exits non-zero if something is miswired |
|
|
161
|
+
| `npx paperlint submission new <paper>` | creates the submission on the portal (title, abstract, authors, PDF); `--save` for real |
|
|
162
|
+
| `npx paperlint submission show <paper>` | the paper's submission on the venue's portal, and whether it holds your build |
|
|
163
|
+
| `npx paperlint submission update <paper>` | checks a new PDF/abstract against the portal; `--save` sends it for real |
|
|
164
|
+
| `npx paperlint studies new <paper> "<title>"` | registers a study: the next id in `repro/studies.json`, its folder, the index |
|
|
165
|
+
| `npx paperlint studies index <paper>` | regenerates the index of the studies in `repro/README.md` |
|
|
166
|
+
| `npx paperlint studies gate <paper> <id>` | exits 0 only once the study's decision is committed: run it before the study |
|
|
167
|
+
| `npx paperlint --help` | every command and flag |
|
|
167
168
|
|
|
168
169
|
## 🧠 Skills
|
|
169
170
|
|
|
@@ -276,7 +277,7 @@ Only `paperlint lint --fix`, and only three rules: `paper/section-word` (`§`
|
|
|
276
277
|
- [`docs/configuration.md`](docs/configuration.md) — every setting, how `build` compiles, using your own ESLint
|
|
277
278
|
- [`docs/rules.md`](docs/rules.md) — every check, venue presets, recording a submitted PDF
|
|
278
279
|
- [`docs/references.md`](docs/references.md) — the reference check, and the cache file to commit
|
|
279
|
-
- [`docs/submission.md`](docs/submission.md) — reading and updating a submission on the venue's portal (HotCRP)
|
|
280
|
+
- [`docs/submission.md`](docs/submission.md) — creating, reading and updating a submission on the venue's portal (HotCRP); one token variable per site
|
|
280
281
|
- [`docs/optional-rules.md`](docs/optional-rules.md) — checks only some venues need
|
|
281
282
|
- [`docs/toolchain.md`](docs/toolchain.md) — TeX Live, and Banal (HotCRP's page-geometry checker, GPL)
|
|
282
283
|
- [`CONTRIBUTING.md`](CONTRIBUTING.md) — how the package is tested and released, and adding a venue to it
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* HotCRP, as the `SubmissionPortal`
|
|
3
|
-
* parsed here. Everything that changes if HotCRP's API does lives in this folder.
|
|
2
|
+
* HotCRP, as the `PortalSite` and `SubmissionPortal` ports: its token variables and token page, its
|
|
3
|
+
* REST API read and written over `fetch`, its answers parsed here. Everything that changes if HotCRP's API does lives in this folder.
|
|
4
4
|
*/
|
|
5
|
-
export { CONTENT_FIELD, changeObject, hotcrpPortal, type HotcrpOptions, } from "./portal.io.ts";
|
|
6
|
-
export { parseShow, parseUpdate, sha256OfHash } from "./response.ts";
|
|
5
|
+
export { CONTENT_FIELD, changeObject, createObject, hotcrpPortal, type HotcrpOptions, } from "./portal.io.ts";
|
|
6
|
+
export { parseCreate, parseShow, parseUpdate, sha256OfHash, } from "./response.ts";
|
|
7
7
|
export { hotcrpDeadlines } from "./deadlines.io.ts";
|
|
8
|
+
export { hotcrpSite } from "./site.ts";
|
|
9
|
+
export { SITE_LESS_VARIABLE, VARIABLE_PATTERN, tokenVariable, } from "./token.ts";
|
|
8
10
|
export { parseDeadlinesPage, whatOf } from "./deadlines.ts";
|
|
9
11
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/adapters/hotcrp/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EACL,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,KAAK,aAAa,GACnB,MAAM,gBAAgB,CAAC;AACxB,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/adapters/hotcrp/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EACL,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,KAAK,aAAa,GACnB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,WAAW,EACX,SAAS,EACT,WAAW,EACX,YAAY,GACb,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,aAAa,GACd,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,kBAAkB,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* HotCRP, as the `SubmissionPortal`
|
|
3
|
-
* parsed here. Everything that changes if HotCRP's API does lives in this folder.
|
|
2
|
+
* HotCRP, as the `PortalSite` and `SubmissionPortal` ports: its token variables and token page, its
|
|
3
|
+
* REST API read and written over `fetch`, its answers parsed here. Everything that changes if HotCRP's API does lives in this folder.
|
|
4
4
|
*/
|
|
5
|
-
export { CONTENT_FIELD, changeObject, hotcrpPortal, } from "./portal.io.js";
|
|
6
|
-
export { parseShow, parseUpdate, sha256OfHash } from "./response.js";
|
|
5
|
+
export { CONTENT_FIELD, changeObject, createObject, hotcrpPortal, } from "./portal.io.js";
|
|
6
|
+
export { parseCreate, parseShow, parseUpdate, sha256OfHash, } from "./response.js";
|
|
7
7
|
export { hotcrpDeadlines } from "./deadlines.io.js";
|
|
8
|
+
export { hotcrpSite } from "./site.js";
|
|
9
|
+
export { SITE_LESS_VARIABLE, VARIABLE_PATTERN, tokenVariable, } from "./token.js";
|
|
8
10
|
export { parseDeadlinesPage, whatOf } from "./deadlines.js";
|
|
9
11
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/adapters/hotcrp/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EACL,aAAa,EACb,YAAY,EACZ,YAAY,GAEb,MAAM,gBAAgB,CAAC;AACxB,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/adapters/hotcrp/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EACL,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,YAAY,GAEb,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,WAAW,EACX,SAAS,EACT,WAAW,EACX,YAAY,GACb,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,aAAa,GACd,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,kBAAkB,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { SubmissionChange } from "../../domain/submission.ts";
|
|
1
|
+
import type { NewSubmission, SubmissionChange } from "../../domain/submission.ts";
|
|
2
2
|
import type { SubmissionPortal } from "../../ports/submission-portal.ts";
|
|
3
3
|
/**
|
|
4
4
|
* The form field the PDF travels in, and the name the `json` object's `content_file` refers to it
|
|
@@ -15,6 +15,8 @@ export interface HotcrpOptions {
|
|
|
15
15
|
}
|
|
16
16
|
/** The submission object a change sends: only the fields it changes. */
|
|
17
17
|
export declare function changeObject(id: number, c: SubmissionChange): Readonly<Record<string, unknown>>;
|
|
18
|
+
/** The submission object a creation sends: title, abstract, authors and the PDF's field. */
|
|
19
|
+
export declare function createObject(p: NewSubmission): Readonly<Record<string, unknown>>;
|
|
18
20
|
/** HotCRP at `o.url`, read and changed with `o.token`. */
|
|
19
21
|
export declare function hotcrpPortal(o: HotcrpOptions): SubmissionPortal;
|
|
20
22
|
//# sourceMappingURL=portal.io.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"portal.io.d.ts","sourceRoot":"","sources":["../../../src/adapters/hotcrp/portal.io.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"portal.io.d.ts","sourceRoot":"","sources":["../../../src/adapters/hotcrp/portal.io.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAEV,aAAa,EAEb,gBAAgB,EACjB,MAAM,4BAA4B,CAAC;AACpC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AAGzE;;;;;;GAMG;AACH,eAAO,MAAM,aAAa,kBAAkB,CAAC;AAM7C,MAAM,WAAW,aAAa;IAC5B,qEAAqE;IACrE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAmCD,wEAAwE;AACxE,wBAAgB,YAAY,CAC1B,EAAE,EAAE,MAAM,EACV,CAAC,EAAE,gBAAgB,GAClB,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAQnC;AASD,4FAA4F;AAC5F,wBAAgB,YAAY,CAC1B,CAAC,EAAE,aAAa,GACf,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CASnC;AAuCD,0DAA0D;AAC1D,wBAAgB,YAAY,CAAC,CAAC,EAAE,aAAa,GAAG,gBAAgB,CAkB/D"}
|
|
@@ -9,12 +9,17 @@
|
|
|
9
9
|
* (the documented form: `curl -F "json=<data.json" -F paper.pdf=@paper.pdf SITEURL/api/paper`).
|
|
10
10
|
* Without `save` the request carries `dry_run=1`: HotCRP checks the change and keeps nothing.
|
|
11
11
|
*
|
|
12
|
+
* Create: the same `POST`, with `p=new` and `"pid": "new"` in the object — «Setting `p=new` will
|
|
13
|
+
* create a new submission; the response will contain the chosen submission ID»
|
|
14
|
+
* (`devel/apidoc/submissions.md`, `post /paper`, in kohler/hotcrp). The object carries the title, the
|
|
15
|
+
* abstract, the authors and the PDF; nothing else is sent.
|
|
16
|
+
*
|
|
12
17
|
* 🔴 THE TOKEN goes in the `Authorization` header and nowhere else: not into a URL, a message, or an
|
|
13
18
|
* error. A failure is described by HTTP status, HotCRP's own messages, or the network error's text.
|
|
14
19
|
*/
|
|
15
20
|
import { messageOf } from "../../domain/text.js";
|
|
16
21
|
import { err } from "../../domain/result.js";
|
|
17
|
-
import { parseShow, parseUpdate } from "./response.js";
|
|
22
|
+
import { parseCreate, parseShow, parseUpdate } from "./response.js";
|
|
18
23
|
/**
|
|
19
24
|
* The form field the PDF travels in, and the name the `json` object's `content_file` refers to it
|
|
20
25
|
* by. 🔴 NO DOT, SPACE OR BRACKET: HotCRP looks the name up in PHP's `$_FILES`, and PHP renames a
|
|
@@ -60,14 +65,33 @@ export function changeObject(id, c) {
|
|
|
60
65
|
...(c.submit ? { status: "submitted" } : {}),
|
|
61
66
|
};
|
|
62
67
|
}
|
|
63
|
-
|
|
68
|
+
/** An author as HotCRP's submission object spells one (`Author::make_keyed` reads `name`). */
|
|
69
|
+
const authorObject = (a) => ({
|
|
70
|
+
name: a.name,
|
|
71
|
+
email: a.email,
|
|
72
|
+
...(a.affiliation === null ? {} : { affiliation: a.affiliation }),
|
|
73
|
+
});
|
|
74
|
+
/** The submission object a creation sends: title, abstract, authors and the PDF's field. */
|
|
75
|
+
export function createObject(p) {
|
|
76
|
+
return {
|
|
77
|
+
object: "paper",
|
|
78
|
+
pid: "new",
|
|
79
|
+
title: p.title,
|
|
80
|
+
abstract: p.abstract,
|
|
81
|
+
authors: p.authors.map(authorObject),
|
|
82
|
+
submission: { content_file: CONTENT_FIELD },
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
function formOf(object, pdf) {
|
|
64
86
|
const form = new FormData();
|
|
65
|
-
form.append("json", JSON.stringify(
|
|
66
|
-
if (
|
|
67
|
-
form.append(CONTENT_FIELD, new Blob([new Uint8Array(
|
|
87
|
+
form.append("json", JSON.stringify(object));
|
|
88
|
+
if (pdf !== null)
|
|
89
|
+
form.append(CONTENT_FIELD, new Blob([new Uint8Array(pdf.bytes)], { type: "application/pdf" }), pdf.name);
|
|
68
90
|
return form;
|
|
69
91
|
}
|
|
70
92
|
const endpoint = (base, params) => `${base}/api/paper?${new URLSearchParams(params).toString()}`;
|
|
93
|
+
/** A `POST /api/paper` carrying the object and the PDF, a dry run unless saving. */
|
|
94
|
+
const post = (o, w) => call(endpoint(o.url, { p: w.p, ...(w.save ? {} : { dry_run: "1" }) }), { method: "POST", body: formOf(w.object, w.pdf) }, o.token, WRITE_TIMEOUT_MS);
|
|
71
95
|
/** HotCRP at `o.url`, read and changed with `o.token`. */
|
|
72
96
|
export function hotcrpPortal(o) {
|
|
73
97
|
return {
|
|
@@ -77,14 +101,15 @@ export function hotcrpPortal(o) {
|
|
|
77
101
|
return a.ok ? parseShow(a.value.status, a.value.body) : a;
|
|
78
102
|
},
|
|
79
103
|
async update(id, change, { save }) {
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
...(save ? {} : { dry_run: "1" }),
|
|
83
|
-
});
|
|
84
|
-
const body = formOf(id, change);
|
|
85
|
-
const a = await call(url, { method: "POST", body }, o.token, WRITE_TIMEOUT_MS);
|
|
104
|
+
const object = changeObject(id, change);
|
|
105
|
+
const a = await post(o, { p: String(id), object, pdf: change.pdf, save });
|
|
86
106
|
return a.ok ? parseUpdate(a.value.status, a.value.body) : a;
|
|
87
107
|
},
|
|
108
|
+
async create(paper, { save }) {
|
|
109
|
+
const object = createObject(paper);
|
|
110
|
+
const a = await post(o, { p: "new", object, pdf: paper.pdf, save });
|
|
111
|
+
return a.ok ? parseCreate(a.value.status, a.value.body) : a;
|
|
112
|
+
},
|
|
88
113
|
};
|
|
89
114
|
}
|
|
90
115
|
//# sourceMappingURL=portal.io.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"portal.io.js","sourceRoot":"","sources":["../../../src/adapters/hotcrp/portal.io.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"portal.io.js","sourceRoot":"","sources":["../../../src/adapters/hotcrp/portal.io.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type Result } from "../../domain/result.ts";
|
|
2
2
|
import { type Sha256 } from "../../domain/sha256.ts";
|
|
3
|
-
import type { PortalFailure, SubmissionView, UpdateOutcome } from "../../domain/submission.ts";
|
|
3
|
+
import type { CreateOutcome, PortalFailure, SubmissionView, UpdateOutcome } from "../../domain/submission.ts";
|
|
4
4
|
/** HotCRP's `sha2-<hex>` → the sha256; null for any other hash it may name. */
|
|
5
5
|
export declare function sha256OfHash(hash: string): Sha256 | null;
|
|
6
6
|
/** `GET /api/paper` → the submission, or why there is none. */
|
|
@@ -10,4 +10,9 @@ export declare function parseShow(httpStatus: number, body: unknown): Result<Sub
|
|
|
10
10
|
* the change whatever the HTTP status; the caller decides the exit from both.
|
|
11
11
|
*/
|
|
12
12
|
export declare function parseUpdate(httpStatus: number, body: unknown): Result<UpdateOutcome, PortalFailure>;
|
|
13
|
+
/**
|
|
14
|
+
* `POST /api/paper?p=new` → the outcome, with the id HotCRP chose: its `pid`, a number only when the
|
|
15
|
+
* submission was saved (a dry run answers `"pid": "new"`).
|
|
16
|
+
*/
|
|
17
|
+
export declare function parseCreate(httpStatus: number, body: unknown): Result<CreateOutcome, PortalFailure>;
|
|
13
18
|
//# sourceMappingURL=response.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"response.d.ts","sourceRoot":"","sources":["../../../src/adapters/hotcrp/response.ts"],"names":[],"mappings":"AAUA,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAe,KAAK,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"response.d.ts","sourceRoot":"","sources":["../../../src/adapters/hotcrp/response.ts"],"names":[],"mappings":"AAUA,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAe,KAAK,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,KAAK,EACV,aAAa,EAEb,aAAa,EAEb,cAAc,EACd,aAAa,EACd,MAAM,4BAA4B,CAAC;AA+CpC,+EAA+E;AAC/E,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGxD;AAkFD,+DAA+D;AAC/D,wBAAgB,SAAS,CACvB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,OAAO,GACZ,MAAM,CAAC,cAAc,EAAE,aAAa,CAAC,CAMvC;AAED;;;GAGG;AACH,wBAAgB,WAAW,CACzB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,OAAO,GACZ,MAAM,CAAC,aAAa,EAAE,aAAa,CAAC,CAYtC;AAED;;;GAGG;AACH,wBAAgB,WAAW,CACzB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,OAAO,GACZ,MAAM,CAAC,aAAa,EAAE,aAAa,CAAC,CAStC"}
|
|
@@ -43,6 +43,8 @@ const UpdateBody = z.object({
|
|
|
43
43
|
change_list: z.array(z.string()).optional(),
|
|
44
44
|
message_list: Messages,
|
|
45
45
|
dry_run: z.boolean().optional(),
|
|
46
|
+
// The submission's id: a number once saved, `"new"` for a creation that was not.
|
|
47
|
+
pid: z.union([z.number(), z.string()]).optional(),
|
|
46
48
|
});
|
|
47
49
|
const Envelope = z.object({ message_list: Messages });
|
|
48
50
|
const SHA2 = /^sha2-([0-9a-f]{64})$/;
|
|
@@ -135,4 +137,19 @@ export function parseUpdate(httpStatus, body) {
|
|
|
135
137
|
dryRun: b.data.dry_run ?? false,
|
|
136
138
|
});
|
|
137
139
|
}
|
|
140
|
+
/**
|
|
141
|
+
* `POST /api/paper?p=new` → the outcome, with the id HotCRP chose: its `pid`, a number only when the
|
|
142
|
+
* submission was saved (a dry run answers `"pid": "new"`).
|
|
143
|
+
*/
|
|
144
|
+
export function parseCreate(httpStatus, body) {
|
|
145
|
+
const u = parseUpdate(httpStatus, body);
|
|
146
|
+
if (!u.ok)
|
|
147
|
+
return u;
|
|
148
|
+
const pid = UpdateBody.safeParse(body).data?.pid;
|
|
149
|
+
const saved = u.value.valid && !u.value.dryRun;
|
|
150
|
+
return ok({
|
|
151
|
+
...u.value,
|
|
152
|
+
id: saved && typeof pid === "number" ? pid : null,
|
|
153
|
+
});
|
|
154
|
+
}
|
|
138
155
|
//# sourceMappingURL=response.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"response.js","sourceRoot":"","sources":["../../../src/adapters/hotcrp/response.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,GAAG,EAAE,EAAE,EAAe,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAe,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"response.js","sourceRoot":"","sources":["../../../src/adapters/hotcrp/response.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A HotCRP site before any token, as the `PortalSite` port: the variable its token is read from,
|
|
3
|
+
* where on the site an author makes one and with which scopes, what `submission new` leaves to the
|
|
4
|
+
* site, a submission's page — and the API, once there is a token. Every word here is HotCRP's.
|
|
5
|
+
*/
|
|
6
|
+
import type { PortalSite } from "../../ports/submission-portal.ts";
|
|
7
|
+
/** The HotCRP site at `url` (no trailing slash). */
|
|
8
|
+
export declare const hotcrpSite: (url: string) => PortalSite;
|
|
9
|
+
//# sourceMappingURL=site.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"site.d.ts","sourceRoot":"","sources":["../../../src/adapters/hotcrp/site.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAC;AAQnE,oDAAoD;AACpD,eAAO,MAAM,UAAU,GAAI,KAAK,MAAM,KAAG,UAmBvC,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { hotcrpPortal } from "./portal.io.js";
|
|
2
|
+
import { SITE_LESS_VARIABLE, VARIABLE_PATTERN, tokenVariable, } from "./token.js";
|
|
3
|
+
/** The HotCRP site at `url` (no trailing slash). */
|
|
4
|
+
export const hotcrpSite = (url) => ({
|
|
5
|
+
tokenVariable: tokenVariable(url),
|
|
6
|
+
siteLessVariable: SITE_LESS_VARIABLE,
|
|
7
|
+
variablePattern: VARIABLE_PATTERN,
|
|
8
|
+
credentials: {
|
|
9
|
+
// HotCRP's own link to it: `hotlink("Profile > Developer", "profile", ["t" => "developer"])`
|
|
10
|
+
// (src/help/h_developer.php in kohler/hotcrp).
|
|
11
|
+
page: `${url}/profile?t=developer`,
|
|
12
|
+
where: "Account settings → Developer → API tokens",
|
|
13
|
+
scopes: "submeta:read and document:read (show), submeta:write and document:write (update, new) — tick all four to use every subcommand",
|
|
14
|
+
},
|
|
15
|
+
siteOnly: [
|
|
16
|
+
"PC conflicts (HotCRP's API takes them as pc_conflicts; paperlint does not send them)",
|
|
17
|
+
"topics, and every field the venue adds (paper type, artifact, consent boxes …)",
|
|
18
|
+
],
|
|
19
|
+
submissionPage: (id) => `${url}/paper/${id === null ? "<its number>" : String(id)}`,
|
|
20
|
+
connect: (token) => hotcrpPortal({ url, token }),
|
|
21
|
+
});
|
|
22
|
+
//# sourceMappingURL=site.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"site.js","sourceRoot":"","sources":["../../../src/adapters/hotcrp/site.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,aAAa,GACd,MAAM,YAAY,CAAC;AAEpB,oDAAoD;AACpD,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,GAAW,EAAc,EAAE,CAAC,CAAC;IACtD,aAAa,EAAE,aAAa,CAAC,GAAG,CAAC;IACjC,gBAAgB,EAAE,kBAAkB;IACpC,eAAe,EAAE,gBAAgB;IACjC,WAAW,EAAE;QACX,6FAA6F;QAC7F,+CAA+C;QAC/C,IAAI,EAAE,GAAG,GAAG,sBAAsB;QAClC,KAAK,EAAE,2CAA2C;QAClD,MAAM,EACJ,+HAA+H;KAClI;IACD,QAAQ,EAAE;QACR,sFAAsF;QACtF,gFAAgF;KACjF;IACD,cAAc,EAAE,CAAC,EAAE,EAAE,EAAE,CACrB,GAAG,GAAG,UAAU,EAAE,KAAK,IAAI,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE;IAC7D,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,YAAY,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;CACjD,CAAC,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** The site-less variable, read until #236: named when it is still set, never used. */
|
|
2
|
+
export declare const SITE_LESS_VARIABLE = "HOTCRP_TOKEN";
|
|
3
|
+
/** The shape of a site's variable, as a message names it. */
|
|
4
|
+
export declare const VARIABLE_PATTERN = "HOTCRP_TOKEN_<LABEL>";
|
|
5
|
+
/**
|
|
6
|
+
* The variable a HotCRP site's token is read from: `HOTCRP_TOKEN_` and the site's label upper-cased,
|
|
7
|
+
* every run of characters but letters and digits made one `_`, none at either end.
|
|
8
|
+
* `https://msr2027.hotcrp.com` → `HOTCRP_TOKEN_MSR2027`; `https://aidc.submit.acsac.org` →
|
|
9
|
+
* `HOTCRP_TOKEN_AIDC_SUBMIT_ACSAC_ORG`; `https://hotcrp.example.edu/conf2027` →
|
|
10
|
+
* `HOTCRP_TOKEN_HOTCRP_EXAMPLE_EDU_CONF2027`.
|
|
11
|
+
*/
|
|
12
|
+
export declare function tokenVariable(url: string): string;
|
|
13
|
+
//# sourceMappingURL=token.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token.d.ts","sourceRoot":"","sources":["../../../src/adapters/hotcrp/token.ts"],"names":[],"mappings":"AAaA,uFAAuF;AACvF,eAAO,MAAM,kBAAkB,iBAAiB,CAAC;AAEjD,6DAA6D;AAC7D,eAAO,MAAM,gBAAgB,yBAAkC,CAAC;AAmBhE;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAOjD"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WHICH ENVIRONMENT VARIABLE HOLDS A HOTCRP SITE'S API TOKEN — HotCRP's fact, so HotCRP's adapter.
|
|
3
|
+
* Pure.
|
|
4
|
+
*
|
|
5
|
+
* A HotCRP token works on the site it was made on and nowhere else (measured 2026-10-19: a token
|
|
6
|
+
* made on one HotCRP site gets `401 Unauthorized` from `msr2027.hotcrp.com`'s `/api/whoami`). So the
|
|
7
|
+
* variable is named after the site, and no two sites share one — `HOTCRP_TOKEN_<subdomain>` on the
|
|
8
|
+
* hosted service, `HOTCRP_TOKEN_<host and path>` anywhere else — and an author with live submissions
|
|
9
|
+
* at two venues sets two variables (#236). The site-less `HOTCRP_TOKEN` is no longer read; the policy that refuses it
|
|
10
|
+
* by name is the domain's (`src/domain/portal-token.ts`).
|
|
11
|
+
*/
|
|
12
|
+
import { hostOf } from "../../domain/portal-token.js";
|
|
13
|
+
/** The site-less variable, read until #236: named when it is still set, never used. */
|
|
14
|
+
export const SITE_LESS_VARIABLE = "HOTCRP_TOKEN";
|
|
15
|
+
/** The shape of a site's variable, as a message names it. */
|
|
16
|
+
export const VARIABLE_PATTERN = `${SITE_LESS_VARIABLE}_<LABEL>`;
|
|
17
|
+
/** The hosted service, where each conference is a subdomain of its own. */
|
|
18
|
+
const HOSTED = ".hotcrp.com";
|
|
19
|
+
/**
|
|
20
|
+
* What names a site, and no other: on the hosted service the subdomain alone
|
|
21
|
+
* (`msr2027.hotcrp.com` → `msr2027`); anywhere else the whole host, with a port other than the
|
|
22
|
+
* scheme's default, and path (`hotcrp.example.edu/conf2027`, `review.example.org:8443/conf`),
|
|
23
|
+
* because one install may serve several conferences under paths or ports, and two hosts may share a
|
|
24
|
+
* first label.
|
|
25
|
+
*/
|
|
26
|
+
function siteLabel(url) {
|
|
27
|
+
const host = hostOf(url);
|
|
28
|
+
if (host.endsWith(HOSTED))
|
|
29
|
+
return host.slice(0, -HOSTED.length);
|
|
30
|
+
const path = URL.canParse(url) ? new URL(url).pathname : "";
|
|
31
|
+
return `${host}${path}`;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* The variable a HotCRP site's token is read from: `HOTCRP_TOKEN_` and the site's label upper-cased,
|
|
35
|
+
* every run of characters but letters and digits made one `_`, none at either end.
|
|
36
|
+
* `https://msr2027.hotcrp.com` → `HOTCRP_TOKEN_MSR2027`; `https://aidc.submit.acsac.org` →
|
|
37
|
+
* `HOTCRP_TOKEN_AIDC_SUBMIT_ACSAC_ORG`; `https://hotcrp.example.edu/conf2027` →
|
|
38
|
+
* `HOTCRP_TOKEN_HOTCRP_EXAMPLE_EDU_CONF2027`.
|
|
39
|
+
*/
|
|
40
|
+
export function tokenVariable(url) {
|
|
41
|
+
const label = siteLabel(url);
|
|
42
|
+
const name = label
|
|
43
|
+
.toUpperCase()
|
|
44
|
+
.replace(/[^A-Z0-9]+/g, "_")
|
|
45
|
+
.replace(/^_+|_+$/g, "");
|
|
46
|
+
return `${SITE_LESS_VARIABLE}_${name}`;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=token.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token.js","sourceRoot":"","sources":["../../../src/adapters/hotcrp/token.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,8BAA8B,CAAC;AAEtD,uFAAuF;AACvF,MAAM,CAAC,MAAM,kBAAkB,GAAG,cAAc,CAAC;AAEjD,6DAA6D;AAC7D,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,kBAAkB,UAAU,CAAC;AAEhE,2EAA2E;AAC3E,MAAM,MAAM,GAAG,aAAa,CAAC;AAE7B;;;;;;GAMG;AACH,SAAS,SAAS,CAAC,GAAW;IAC5B,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IACzB,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAChE,MAAM,IAAI,GAAG,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5D,OAAO,GAAG,IAAI,GAAG,IAAI,EAAE,CAAC;AAC1B,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,MAAM,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;IAC7B,MAAM,IAAI,GAAG,KAAK;SACf,WAAW,EAAE;SACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;SAC3B,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IAC3B,OAAO,GAAG,kBAAkB,IAAI,IAAI,EAAE,CAAC;AACzC,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THE ABSTRACT AS PLAIN TEXT, FROM THE SOURCE — the body of `\begin{abstract}…\end{abstract}`, as
|
|
3
|
+
* `paperlint submission new` sends it. Pure.
|
|
4
|
+
*
|
|
5
|
+
* unified-latex does the TeX: util-macros reads `\newcommand`/`\renewcommand`/`\providecommand` and
|
|
6
|
+
* expands them, util-ligatures turns `--`, ``` `` ```, `~`, `\%`, `\ldots`, accents… into the
|
|
7
|
+
* characters TeX prints. The macro categories are the adapter's shared sets (parse.ts, headings.ts).
|
|
8
|
+
* What is ours is the policy. A macro the source defines once, before the abstract, is expanded (`\def`, which
|
|
9
|
+
* util-macros does not read, by hand). One it defines more than once is refused with every
|
|
10
|
+
* definition's place: which one TeX uses depends on order, groups and the definer
|
|
11
|
+
* (`\providecommand` keeps an earlier one), and paperlint does not reimplement that. Refused too, with
|
|
12
|
+
* where it stands: a macro nobody defined, one that takes arguments or expands into itself, math
|
|
13
|
+
* beyond digits and symbols, any other construct. Never guessed.
|
|
14
|
+
*/
|
|
15
|
+
import type * as Ast from "@unified-latex/unified-latex-types";
|
|
16
|
+
import { type Result } from "../../domain/result.ts";
|
|
17
|
+
import type { AbstractProblem } from "../../ports/latex.ts";
|
|
18
|
+
/** The abstract of `src` as one paragraph of plain text, or what stops it; nothing after `\\end{document}` is read. */
|
|
19
|
+
export declare const abstractText: (src: string) => Result<string, AbstractProblem>;
|
|
20
|
+
/** The same, over a tree already parsed from `src`. */
|
|
21
|
+
export declare function abstractOfTree(root: Readonly<Ast.Root>, src: string): Result<string, AbstractProblem>;
|
|
22
|
+
//# sourceMappingURL=abstract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"abstract.d.ts","sourceRoot":"","sources":["../../../src/adapters/latex/abstract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,KAAK,GAAG,MAAM,oCAAoC,CAAC;AAW/D,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAkO5D,uHAAuH;AACvH,eAAO,MAAM,YAAY,GAAI,KAAK,MAAM,KAAG,MAAM,CAAC,MAAM,EAAE,eAAe,CACzB,CAAC;AAEjD,uDAAuD;AACvD,wBAAgB,cAAc,CAC5B,IAAI,EAAE,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,EACxB,GAAG,EAAE,MAAM,GACV,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAWjC"}
|