paperlint 12.0.0 → 13.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 +2 -1
- package/dist/adapters/memory/index.d.ts +5 -0
- package/dist/adapters/memory/index.d.ts.map +1 -1
- package/dist/adapters/memory/index.js +16 -0
- package/dist/adapters/memory/index.js.map +1 -1
- package/dist/adapters/node/index.d.ts +1 -0
- package/dist/adapters/node/index.d.ts.map +1 -1
- package/dist/adapters/node/index.js +1 -0
- package/dist/adapters/node/index.js.map +1 -1
- package/dist/adapters/node/move-file.io.d.ts +4 -0
- package/dist/adapters/node/move-file.io.d.ts.map +1 -0
- package/dist/adapters/node/move-file.io.js +12 -0
- package/dist/adapters/node/move-file.io.js.map +1 -0
- package/dist/adapters/yaml/index.d.ts +3 -0
- package/dist/adapters/yaml/index.d.ts.map +1 -0
- package/dist/adapters/yaml/index.js +17 -0
- package/dist/adapters/yaml/index.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +48 -7
- package/dist/cli.js.map +1 -1
- package/dist/cycle-rules.d.ts +3 -3
- package/dist/cycle-rules.d.ts.map +1 -1
- package/dist/cycle-rules.js +1 -2
- package/dist/cycle-rules.js.map +1 -1
- package/dist/domain/cycle.d.ts +16 -2
- package/dist/domain/cycle.d.ts.map +1 -1
- package/dist/domain/cycle.js +21 -42
- package/dist/domain/cycle.js.map +1 -1
- package/dist/domain/paper-layout.d.ts.map +1 -1
- package/dist/domain/paper-layout.js +5 -2
- package/dist/domain/paper-layout.js.map +1 -1
- package/dist/domain/paths.d.ts +12 -0
- package/dist/domain/paths.d.ts.map +1 -1
- package/dist/domain/paths.js +22 -1
- package/dist/domain/paths.js.map +1 -1
- package/dist/domain/scaffold-layout.js +1 -1
- package/dist/domain/versions-migration.d.ts +51 -0
- package/dist/domain/versions-migration.d.ts.map +1 -0
- package/dist/domain/versions-migration.js +252 -0
- package/dist/domain/versions-migration.js.map +1 -0
- package/dist/domain/versions.d.ts +167 -0
- package/dist/domain/versions.d.ts.map +1 -0
- package/dist/domain/versions.js +457 -0
- package/dist/domain/versions.js.map +1 -0
- package/dist/eslint-rules/paper-stages.d.ts +7 -0
- package/dist/eslint-rules/paper-stages.d.ts.map +1 -1
- package/dist/eslint-rules/paper-stages.js +62 -7
- package/dist/eslint-rules/paper-stages.js.map +1 -1
- package/dist/eslint-rules/rule-context.d.ts +2 -0
- package/dist/eslint-rules/rule-context.d.ts.map +1 -1
- package/dist/ports/move-file.d.ts +7 -0
- package/dist/ports/move-file.d.ts.map +1 -0
- package/dist/ports/move-file.js +2 -0
- package/dist/ports/move-file.js.map +1 -0
- package/dist/ports/yaml.d.ts +5 -0
- package/dist/ports/yaml.d.ts.map +1 -0
- package/dist/ports/yaml.js +2 -0
- package/dist/ports/yaml.js.map +1 -0
- package/dist/submission.d.ts +2 -0
- package/dist/submission.d.ts.map +1 -1
- package/dist/submission.js +49 -9
- package/dist/submission.js.map +1 -1
- package/dist/version-rules.d.ts +16 -0
- package/dist/version-rules.d.ts.map +1 -0
- package/dist/version-rules.js +201 -0
- package/dist/version-rules.js.map +1 -0
- package/dist/versions-command.d.ts +37 -0
- package/dist/versions-command.d.ts.map +1 -0
- package/dist/versions-command.js +209 -0
- package/dist/versions-command.js.map +1 -0
- package/dist/versions.d.ts +76 -0
- package/dist/versions.d.ts.map +1 -0
- package/dist/versions.js +164 -0
- package/dist/versions.js.map +1 -0
- package/docs/configuration.md +76 -2
- package/docs/layout.md +5 -5
- package/docs/rules/cycle/camera-ready-source.md +62 -0
- package/docs/rules/cycle/draft-drift.md +47 -0
- package/docs/rules/cycle/port-done.md +2 -2
- package/docs/rules/cycle/record.md +2 -1
- package/docs/rules/cycle/submitted-frozen.md +65 -0
- package/docs/rules/paper/allowed-files-only.md +1 -1
- package/docs/rules/versions/layout.md +88 -0
- package/docs/rules.md +25 -11
- package/docs/submission.md +21 -3
- package/eslint-rules/paper-stages.test.mjs +62 -0
- package/eslint-rules/paper-stages.ts +67 -8
- package/eslint-rules/prereg-coverage.test.ts +1 -0
- package/eslint-rules/rule-context.ts +2 -0
- package/package.json +2 -1
- package/presets/agent.jsonc +75 -0
- package/presets/agent.md +70 -0
- package/presets/agentverify.jsonc +72 -0
- package/presets/agentverify.md +85 -0
- package/presets/ieee-conference.md +1 -1
- package/presets/nlbse.jsonc +76 -0
- package/presets/nlbse.md +85 -0
- package/scripts/coverage-config.test.ts +3 -0
- package/skills/CLAUDE.md +2 -2
- package/skills/CLAUDE.md.spec.ts +1 -1
- package/skills/paper-pipeline/references/pipeline-status-template.md +4 -1
- package/skills/submit-paper/SKILL.md +18 -10
- package/skills/submit-paper/SKILL.md.spec.ts +17 -9
- package/skills/submit-paper/references/publishers/acm.md +5 -3
- package/src/adapters/memory/index.test.ts +22 -0
- package/src/adapters/memory/index.ts +21 -0
- package/src/adapters/node/index.ts +1 -0
- package/src/adapters/node/move-file.io.ts +21 -0
- package/src/adapters/node/move-file.test.ts +51 -0
- package/src/adapters/yaml/index.test.ts +16 -0
- package/src/adapters/yaml/index.ts +17 -0
- package/src/cli.test.ts +43 -0
- package/src/cli.ts +58 -6
- package/src/cycle-rules.ts +4 -5
- package/src/domain/cycle.test.ts +27 -0
- package/src/domain/cycle.ts +38 -6
- package/src/domain/paper-layout.ts +5 -2
- package/src/domain/paths.test.ts +28 -1
- package/src/domain/paths.ts +34 -1
- package/src/domain/scaffold-layout.ts +1 -1
- package/src/domain/versions-migration.test.ts +410 -0
- package/src/domain/versions-migration.ts +429 -0
- package/src/domain/versions.test.ts +564 -0
- package/src/domain/versions.ts +706 -0
- package/src/paper-settings-commands.test.ts +1 -1
- package/src/ports/move-file.ts +8 -0
- package/src/ports/yaml.ts +5 -0
- package/src/preset-card-rule.test.ts +3 -0
- package/src/presets.test.ts +55 -31
- package/src/rule-cases.test.ts +157 -8
- package/src/submission-freeze.test.ts +320 -0
- package/src/submission-new.test.ts +11 -1
- package/src/submission.ts +82 -11
- package/src/tex-venue-rules.test.ts +3 -0
- package/src/venue-rules.test.ts +2 -2
- package/src/version-rules.test.ts +222 -0
- package/src/version-rules.ts +282 -0
- package/src/versions-command.test.ts +594 -0
- package/src/versions-command.ts +360 -0
- package/src/versions.ts +286 -0
- package/dist/eslint-rules/cycle-stage.d.ts +0 -39
- package/dist/eslint-rules/cycle-stage.d.ts.map +0 -1
- package/dist/eslint-rules/cycle-stage.js +0 -119
- package/dist/eslint-rules/cycle-stage.js.map +0 -1
- package/docs/rules/cycle/stage.md +0 -85
- package/eslint-rules/cycle-stage.test.mjs +0 -131
- package/eslint-rules/cycle-stage.ts +0 -141
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THE RULES OVER A PAPER'S FROZEN VERSIONS — the convention `versions/<cycle>/<stage>.{pdf,tex}` and
|
|
3
|
+
* its lock (src/domain/versions.ts):
|
|
4
|
+
*
|
|
5
|
+
* versions/layout error on PIPELINE-STATUS.md: every entry of versions/ is a cycle's
|
|
6
|
+
* folder or the lock, every file in a folder a stage's .pdf or
|
|
7
|
+
* .tex, every PDF with its source, nothing sent from a cycle still
|
|
8
|
+
* porting, every file as the lock recorded it
|
|
9
|
+
* cycle/submitted-frozen error on PIPELINE-STATUS.md: a cycle with a submission on the portal
|
|
10
|
+
* has `versions/<id>/submitted.pdf` (#308)
|
|
11
|
+
* cycle/draft-drift warn on paper.tex: the draft has moved on from the open cycle's
|
|
12
|
+
* frozen source, by so many lines
|
|
13
|
+
* cycle/camera-ready-source error on paper.tex: the last cycle is accepted and its camera-ready is
|
|
14
|
+
* frozen, and that camera-ready keeps less than half of the
|
|
15
|
+
* accepted source's lines — silent until the camera-ready is frozen
|
|
16
|
+
*
|
|
17
|
+
* ── WHY THE FOLDER IS LISTED AND NOT LINTED ─────────────────────────────────────────────────
|
|
18
|
+
* A frozen PDF is never handed to ESLint, and a frozen `.tex` is kept out of the linted set on purpose
|
|
19
|
+
* (src/paper-includes.ts): a rule fired per file could not see either. The folder is listed once per
|
|
20
|
+
* paper, from the scorecard every paper has, as `paper/allowed-files-only` lists the paper's root.
|
|
21
|
+
*
|
|
22
|
+
* ── WHO SPEAKS WHEN THERE IS NOTHING TO JUDGE ───────────────────────────────────────────────
|
|
23
|
+
* A paper that keeps no `cycles` (the flat form) has no attempt to name a folder after: all four are
|
|
24
|
+
* silent, and `paper/stages` with `paper/source` judge its `stages:` list as before. A `cycles` record
|
|
25
|
+
* that does not read is refused by `paperlint lint` before any rule runs.
|
|
26
|
+
*
|
|
27
|
+
* ── WHY THE DRIFT IS A WARNING, AND THE CAMERA-READY AN ERROR ───────────────────────────────
|
|
28
|
+
* Between venues the draft is SUPPOSED to move on from what is under review: the warning says how far,
|
|
29
|
+
* so an author answering a reviewer knows the line numbers point into the frozen file. Once the venue
|
|
30
|
+
* accepts, the camera-ready has to be what was accepted plus the changes asked for — building it from
|
|
31
|
+
* a draft that moved on sends the venue a paper its reviewers never read.
|
|
32
|
+
*
|
|
33
|
+
* ── WHY THE CAMERA-READY IS JUDGED ONLY ONCE IT IS FROZEN ───────────────────────────────────
|
|
34
|
+
* While the camera-ready is being edited, paper.tex differs from what was accepted BY DESIGN: the
|
|
35
|
+
* reviewers' changes go in. A check on the draft in those weeks fires on correct work, so the rule waits
|
|
36
|
+
* for `submission update --save` to freeze `camera-ready.{pdf,tex}`, then judges the frozen source:
|
|
37
|
+
* it must keep at least half of the accepted source's lines (`derivesFrom`, src/domain/versions.ts).
|
|
38
|
+
* After the freeze the draft is not judged at all — what the venue holds is fixed, and the draft is
|
|
39
|
+
* free to head for the next paper.
|
|
40
|
+
*/
|
|
41
|
+
import { basename, dirname } from "node:path";
|
|
42
|
+
import { derivesFrom, driftText, frozenKey, judgeVersions, lineage, unfrozenSubmissions, venueName, } from "./domain/versions.js";
|
|
43
|
+
import { readPaper } from "./tex-paper.js";
|
|
44
|
+
import { rulePageUrl } from "./venue-rules.js";
|
|
45
|
+
import { cyclesIn, draftDrift, entriesIn, factsOfFrozen, frozenText, hasFrozen, readLock, versionsDir, } from "./versions.js";
|
|
46
|
+
const STATUS_FILE = "PIPELINE-STATUS.md";
|
|
47
|
+
const LOCK_COMMAND = "`npx paperlint versions lock <paper>`";
|
|
48
|
+
const LAYOUT_META = {
|
|
49
|
+
type: "suggestion",
|
|
50
|
+
docs: {
|
|
51
|
+
description: "versions/ holds a folder per cycle and a file per stage, every PDF with its source, each file as versions/lock.json recorded it",
|
|
52
|
+
url: rulePageUrl("versions/layout"),
|
|
53
|
+
},
|
|
54
|
+
schema: [],
|
|
55
|
+
messages: {
|
|
56
|
+
stray: "`versions/{{path}}` is not part of the layout — {{hint}}",
|
|
57
|
+
unknownCycle: "`versions/{{folder}}/` names no cycle in paperlint.json — a folder in versions/ is one attempt, named by its cycle's id ({{known}}): rename it to the attempt it holds, or move it to extra/",
|
|
58
|
+
noSource: `\`versions/{{pdf}}\` is frozen without its source: freeze the .tex it was built from as \`versions/{{tex}}\` and run ${LOCK_COMMAND} — a reviewer's line numbers point into that source, and squash merges and \`git gc\` destroy the commit that held it`,
|
|
59
|
+
porting: "`versions/{{file}}` was sent in the cycle «{{id}}», whose phase is still `porting`: a PDF went to the venue while the record says the source is in the previous venue's template — finish the port and drop the phase, or the file is in the wrong folder",
|
|
60
|
+
noLock: `versions/ holds frozen files and no lock.json — ${LOCK_COMMAND} records their bytes and digests; paperlint writes the lock, nobody edits it`,
|
|
61
|
+
badLock: `versions/lock.json: {{why}} — paperlint writes this file: restore it from git, or write it anew with ${LOCK_COMMAND}`,
|
|
62
|
+
notLocked: `\`versions/{{file}}\` is not in versions/lock.json — ${LOCK_COMMAND} records it (a file \`submission … --save\` froze is locked already)`,
|
|
63
|
+
changed: `\`versions/{{file}}\` is not the file the lock recorded on {{frozen}} ({{want}} bytes then, {{got}} now, and another digest) — a frozen file does not change: restore it from git; if it was replaced on purpose, ${LOCK_COMMAND} records it anew`,
|
|
64
|
+
lockedGone: `versions/lock.json records \`{{file}}\`, and the file is not there — a frozen version was deleted: restore it from git; if it went on purpose, ${LOCK_COMMAND} drops the entry`,
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
const FROZEN_META = {
|
|
68
|
+
type: "suggestion",
|
|
69
|
+
docs: {
|
|
70
|
+
description: "a cycle with a submission on the venue's portal has the PDF it sent frozen as versions/<cycle>/submitted.pdf",
|
|
71
|
+
url: rulePageUrl("cycle/submitted-frozen"),
|
|
72
|
+
},
|
|
73
|
+
schema: [],
|
|
74
|
+
messages: {
|
|
75
|
+
unfrozen: `cycle «{{id}}» has submission {{submission}} on the portal, and \`versions/{{pdf}}\` is not there: what the reviewers read is not frozen. \`npx paperlint submission update <paper> --save\` freezes what it sends; for an upload made before, put that PDF there (\`submission show\` gives its size and sha256) with the source it was built from beside it as submitted.tex, then run ${LOCK_COMMAND}`,
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
/** The findings of one scorecard rule for the paper folder `dir`; none for a paper without cycles. */
|
|
79
|
+
function statusFindings(name, dir, deps) {
|
|
80
|
+
const cycles = cyclesIn(dir, deps.files);
|
|
81
|
+
if (cycles === null)
|
|
82
|
+
return [];
|
|
83
|
+
const root = versionsDir(dir);
|
|
84
|
+
return name === "layout"
|
|
85
|
+
? judgeVersions({
|
|
86
|
+
cycles: cycles.list,
|
|
87
|
+
root: entriesIn(root, deps),
|
|
88
|
+
inFolder: (folder) => entriesIn(`${root}/${folder}`, deps),
|
|
89
|
+
lock: readLock(dir, deps.files),
|
|
90
|
+
factsOf: factsOfFrozen(dir, deps.files),
|
|
91
|
+
})
|
|
92
|
+
: unfrozenSubmissions(cycles.list, hasFrozen(dir, deps.files));
|
|
93
|
+
}
|
|
94
|
+
const statusRule = (meta, name, deps) => ({
|
|
95
|
+
meta,
|
|
96
|
+
create(context) {
|
|
97
|
+
if (basename(context.filename) !== STATUS_FILE)
|
|
98
|
+
return {};
|
|
99
|
+
return {
|
|
100
|
+
root() {
|
|
101
|
+
const at = context.sourceCode.getLocFromIndex(0);
|
|
102
|
+
statusFindings(name, dirname(context.filename), deps).forEach((f) => {
|
|
103
|
+
context.report({ loc: { start: at, end: at }, ...f });
|
|
104
|
+
});
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
/** The `versions` plugin's rule, on every `PIPELINE-STATUS.md`. */
|
|
110
|
+
export const versionLayoutRules = (deps) => ({
|
|
111
|
+
layout: statusRule(LAYOUT_META, "layout", deps),
|
|
112
|
+
});
|
|
113
|
+
/** The `cycle` plugin's rule over the frozen folder, on every `PIPELINE-STATUS.md`. */
|
|
114
|
+
export const submittedFrozenRules = (deps) => ({
|
|
115
|
+
"submitted-frozen": statusRule(FROZEN_META, "submitted-frozen", deps),
|
|
116
|
+
});
|
|
117
|
+
// ── on paper.tex: the draft against the frozen source ────────────────────────────────────
|
|
118
|
+
const DRIFT_META = {
|
|
119
|
+
type: "suggestion",
|
|
120
|
+
docs: {
|
|
121
|
+
description: "paper.tex has moved on from the source frozen when the open cycle's PDF was sent — said with how many lines",
|
|
122
|
+
url: rulePageUrl("cycle/draft-drift"),
|
|
123
|
+
},
|
|
124
|
+
schema: [],
|
|
125
|
+
messages: {
|
|
126
|
+
drift: "paper.tex has moved on from `versions/{{key}}`, the version under review at {{venue}}: {{drift}} — expected while the draft heads for its next venue; a reviewer's line numbers point into the frozen file, not this one",
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
const CAMERA_META = {
|
|
130
|
+
type: "problem",
|
|
131
|
+
docs: {
|
|
132
|
+
description: "once the last cycle is accepted and its camera-ready frozen, the camera-ready started from the source that was accepted",
|
|
133
|
+
url: rulePageUrl("cycle/camera-ready-source"),
|
|
134
|
+
},
|
|
135
|
+
schema: [],
|
|
136
|
+
messages: {
|
|
137
|
+
base: "cycle «{{id}}» is accepted, and its frozen camera-ready, `versions/{{id}}/camera-ready.tex`, keeps {{kept}} of the {{total}} lines of what was accepted, `versions/{{id}}/submitted.tex` — under half, so it was not built from the accepted source. The camera-ready is what was accepted plus the changes the reviewers asked for: copy submitted.tex over paper.tex, carry over those changes, build, and send it again with `npx paperlint submission update <paper> --save`, which replaces the frozen one",
|
|
138
|
+
},
|
|
139
|
+
};
|
|
140
|
+
/** The draft against the open cycle's frozen source, or none. */
|
|
141
|
+
function driftFinding(dir, draft, deps) {
|
|
142
|
+
const cycles = cyclesIn(dir, deps.files);
|
|
143
|
+
if (cycles === null || cycles.current.kind !== "cycle")
|
|
144
|
+
return null;
|
|
145
|
+
const c = cycles.current.cycle;
|
|
146
|
+
const d = draftDrift(dir, cycles, draft, deps.files);
|
|
147
|
+
return d.kind === "drift"
|
|
148
|
+
? {
|
|
149
|
+
messageId: "drift",
|
|
150
|
+
data: { key: d.key, venue: venueName(c), drift: driftText(d.drift) },
|
|
151
|
+
}
|
|
152
|
+
: null;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* The accepted cycle's frozen camera-ready against its frozen `submitted.tex`, or none: nothing to judge
|
|
156
|
+
* before the camera-ready is frozen (or without either source), and nothing wrong when it derives.
|
|
157
|
+
*/
|
|
158
|
+
function cameraFinding(dir, files) {
|
|
159
|
+
const cycles = cyclesIn(dir, files);
|
|
160
|
+
if (cycles === null || cycles.current.kind !== "accepted")
|
|
161
|
+
return null;
|
|
162
|
+
const id = cycles.current.cycle.id;
|
|
163
|
+
const camera = frozenText(dir, frozenKey(id, "camera-ready", "tex"), files);
|
|
164
|
+
const accepted = frozenText(dir, frozenKey(id, "submitted", "tex"), files);
|
|
165
|
+
if (camera === null || accepted === null)
|
|
166
|
+
return null;
|
|
167
|
+
const l = lineage(accepted, camera);
|
|
168
|
+
return derivesFrom(l)
|
|
169
|
+
? null
|
|
170
|
+
: {
|
|
171
|
+
messageId: "base",
|
|
172
|
+
data: { id, kept: String(l.kept), total: String(l.total) },
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
/** A rule on paper.tex: its one finding, reported on the first line. */
|
|
176
|
+
const paperRule = (meta, finding, deps) => ({
|
|
177
|
+
meta,
|
|
178
|
+
create(context) {
|
|
179
|
+
if (basename(context.filename) !== "paper.tex")
|
|
180
|
+
return {};
|
|
181
|
+
return {
|
|
182
|
+
root() {
|
|
183
|
+
const sc = context.sourceCode;
|
|
184
|
+
const f = finding(dirname(context.filename), () => readPaper(context.filename, sc.raw ?? sc.text, deps).text);
|
|
185
|
+
if (f === null)
|
|
186
|
+
return;
|
|
187
|
+
const at = sc.getLocFromIndex(0);
|
|
188
|
+
context.report({ loc: { start: at, end: at }, ...f });
|
|
189
|
+
},
|
|
190
|
+
};
|
|
191
|
+
},
|
|
192
|
+
});
|
|
193
|
+
/** The `cycle` plugin's rules over the draft, for every `paper.tex`. */
|
|
194
|
+
export const draftRules = (deps) => ({
|
|
195
|
+
"draft-drift": paperRule(DRIFT_META, (dir, draft) => driftFinding(dir, draft(), deps), deps),
|
|
196
|
+
"camera-ready-source": paperRule(CAMERA_META, (dir) => cameraFinding(dir, deps.files), deps),
|
|
197
|
+
});
|
|
198
|
+
/** The levels they are on at in paperlint's own config. */
|
|
199
|
+
export const VERSION_STATUS_RULE_LEVELS = { "versions/layout": "error", "cycle/submitted-frozen": "error" };
|
|
200
|
+
export const DRAFT_RULE_LEVELS = { "cycle/draft-drift": "warn", "cycle/camera-ready-source": "error" };
|
|
201
|
+
//# sourceMappingURL=version-rules.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version-rules.js","sourceRoot":"","sources":["../src/version-rules.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { type MigrationPlan } from "./domain/versions-migration.ts";
|
|
2
|
+
import type { CopyFile, MoveFile } from "./ports/move-file.ts";
|
|
3
|
+
import type { ParseYaml } from "./ports/yaml.ts";
|
|
4
|
+
import type { ProseDeps } from "./tex-paper.ts";
|
|
5
|
+
import { type VersionsDeps } from "./versions.ts";
|
|
6
|
+
declare const SUBS: readonly ["show", "lock", "migrate"];
|
|
7
|
+
type Sub = (typeof SUBS)[number];
|
|
8
|
+
export interface VersionsCommandDeps extends ProseDeps, VersionsDeps {
|
|
9
|
+
readonly move: MoveFile;
|
|
10
|
+
readonly copy: CopyFile;
|
|
11
|
+
readonly yaml: ParseYaml;
|
|
12
|
+
/** The instant a lock entry records, ISO 8601. */
|
|
13
|
+
readonly now: () => string;
|
|
14
|
+
readonly cwd: string;
|
|
15
|
+
readonly log: (line: string) => void;
|
|
16
|
+
readonly err: (line: string) => void;
|
|
17
|
+
}
|
|
18
|
+
/** The words after `versions` → the subcommand, the paper folder, and what is left over. Pure. */
|
|
19
|
+
export declare function versionsArgs(words: readonly string[]): {
|
|
20
|
+
readonly sub: Sub;
|
|
21
|
+
readonly paper: string;
|
|
22
|
+
readonly extra: readonly string[];
|
|
23
|
+
};
|
|
24
|
+
/** What the scorecard holds for the migration: its `stages:` list, and its text without it (null: none to take out). */
|
|
25
|
+
export interface Scorecard {
|
|
26
|
+
readonly stages: readonly unknown[];
|
|
27
|
+
readonly without: string | null;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* A plan carried out only once its rehearsal on the paths it touches went through (src/domain/
|
|
31
|
+
* versions-migration.ts, `rehearse`): a plan that could stop half-way is a refusal, nothing written.
|
|
32
|
+
*/
|
|
33
|
+
export declare function carryOut(paperDir: string, plan: MigrationPlan, card: Scorecard, deps: VersionsCommandDeps): number;
|
|
34
|
+
/** `paperlint versions …`: exit 0, or 2 for a command line or a paper it cannot run on. */
|
|
35
|
+
export declare function runVersions(words: readonly string[], deps: VersionsCommandDeps): number;
|
|
36
|
+
export {};
|
|
37
|
+
//# sourceMappingURL=versions-command.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"versions-command.d.ts","sourceRoot":"","sources":["../src/versions-command.ts"],"names":[],"mappings":"AAuBA,OAAO,EAKL,KAAK,aAAa,EACnB,MAAM,gCAAgC,CAAC;AAUxC,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAOL,KAAK,YAAY,EAClB,MAAM,eAAe,CAAC;AAEvB,QAAA,MAAM,IAAI,sCAAuC,CAAC;AAClD,KAAK,GAAG,GAAG,CAAC,OAAO,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC;AAKjC,MAAM,WAAW,mBAAoB,SAAQ,SAAS,EAAE,YAAY;IAClE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,kDAAkD;IAClD,QAAQ,CAAC,GAAG,EAAE,MAAM,MAAM,CAAC;IAC3B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACtC;AAED,kGAAkG;AAClG,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG;IACtD,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC;IAClB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC,CASA;AA4ED,wHAAwH;AACxH,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,MAAM,EAAE,SAAS,OAAO,EAAE,CAAC;IACpC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AA6FD;;;GAGG;AACH,wBAAgB,QAAQ,CACtB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,aAAa,EACnB,IAAI,EAAE,SAAS,EACf,IAAI,EAAE,mBAAmB,GACxB,MAAM,CAOR;AA8DD,2FAA2F;AAC3F,wBAAgB,WAAW,CACzB,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,IAAI,EAAE,mBAAmB,GACxB,MAAM,CAqBR"}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `paperlint versions [show|lock|migrate] [paper]` — a paper's frozen versions, one folder per
|
|
3
|
+
* attempt (src/domain/versions.ts):
|
|
4
|
+
*
|
|
5
|
+
* show (the default) each attempt's frozen versions and what they are, newest first, then the
|
|
6
|
+
* draft and how far it has moved from the version it is measured against
|
|
7
|
+
* lock record the files of versions/ in versions/lock.json: what `submission --save` did not
|
|
8
|
+
* freeze — a file put there by hand, an arXiv copy, a recovered upload
|
|
9
|
+
* migrate from the `stages:` list and dated files to folders per attempt, once
|
|
10
|
+
*
|
|
11
|
+
* ── WHY ONE NOUN, THREE VERBS ───────────────────────────────────────────────────────────────
|
|
12
|
+
* docs/prior-art/multi-mode-tools.md: tools that stay small add verbs to a noun the project already
|
|
13
|
+
* has, not nouns. The table is also printed by `paperlint submission show`, beside the portal's copy;
|
|
14
|
+
* `versions` prints it without a token or a network call. `lock` is the `npm install` slot — make the
|
|
15
|
+
* generated file match the disk — and `migrate` runs once per paper.
|
|
16
|
+
*/
|
|
17
|
+
import { join, relative, resolve } from "node:path";
|
|
18
|
+
import * as R from "remeda";
|
|
19
|
+
import { callerPath } from "./caller-path.js";
|
|
20
|
+
import { fieldOf, isRecord } from "./domain/record.js";
|
|
21
|
+
import { err, ok } from "./domain/result.js";
|
|
22
|
+
import { sha256Hex } from "./domain/sha256.js";
|
|
23
|
+
import { frontmatterOf, planMigration, rehearse, withoutStages, } from "./domain/versions-migration.js";
|
|
24
|
+
import { frozenKey, frozenName, LOCK_FILE, lockText, relock, } from "./domain/versions.js";
|
|
25
|
+
import { cyclesIn, entriesIn, factsOfFrozen, readLock, versionLines, versionsDir, } from "./versions.js";
|
|
26
|
+
const SUBS = ["show", "lock", "migrate"];
|
|
27
|
+
const isSub = (s) => SUBS.some((x) => x === s);
|
|
28
|
+
const STATUS_FILE = "PIPELINE-STATUS.md";
|
|
29
|
+
/** The words after `versions` → the subcommand, the paper folder, and what is left over. Pure. */
|
|
30
|
+
export function versionsArgs(words) {
|
|
31
|
+
const [first, ...rest] = words;
|
|
32
|
+
const named = isSub(first);
|
|
33
|
+
const after = named ? rest : words;
|
|
34
|
+
return {
|
|
35
|
+
sub: named ? first : "show",
|
|
36
|
+
paper: after[0] ?? ".",
|
|
37
|
+
extra: after.slice(1),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
/** The paper as a command line names it, from where the command runs. */
|
|
41
|
+
const shown = (cwd, p) => relative(cwd, p) || ".";
|
|
42
|
+
const logAll = (lines, deps) => {
|
|
43
|
+
lines.forEach((l) => {
|
|
44
|
+
deps.log(l);
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
// ── lock ────────────────────────────────────────────────────────────────────────────────
|
|
48
|
+
/** Every frozen file in the cycles' folders, with what it holds. */
|
|
49
|
+
function onDisk(paperDir, cycles, deps) {
|
|
50
|
+
const root = versionsDir(paperDir);
|
|
51
|
+
const facts = factsOfFrozen(paperDir, deps.files);
|
|
52
|
+
return cycles.list.flatMap((c) => entriesIn(join(root, c.id), deps).flatMap((e) => {
|
|
53
|
+
const n = e.kind === "file" ? frozenName(e.name) : null;
|
|
54
|
+
return n === null
|
|
55
|
+
? []
|
|
56
|
+
: [
|
|
57
|
+
{
|
|
58
|
+
key: frozenKey(c.id, n.stage, n.ext),
|
|
59
|
+
facts: facts(frozenKey(c.id, n.stage, n.ext)),
|
|
60
|
+
},
|
|
61
|
+
];
|
|
62
|
+
}));
|
|
63
|
+
}
|
|
64
|
+
const writeLock = (paperDir, lock, deps) => {
|
|
65
|
+
deps.files.writeAtomic(callerPath(join(versionsDir(paperDir), LOCK_FILE)), new TextEncoder().encode(lockText(lock)));
|
|
66
|
+
};
|
|
67
|
+
function runLock(paperDir, cycles, deps) {
|
|
68
|
+
const found = onDisk(paperDir, cycles, deps);
|
|
69
|
+
const old = readLock(paperDir, deps.files);
|
|
70
|
+
if (found.length === 0 && old === null)
|
|
71
|
+
return (deps.log("nothing frozen in versions/ — no lock to write"), 0);
|
|
72
|
+
const r = relock(found, old?.ok === true ? old.value : {}, deps.now());
|
|
73
|
+
writeLock(paperDir, r.lock, deps);
|
|
74
|
+
logAll([
|
|
75
|
+
...(old?.ok === false
|
|
76
|
+
? [
|
|
77
|
+
`versions/lock.json did not read (${old.error}): written anew from the files`,
|
|
78
|
+
]
|
|
79
|
+
: []),
|
|
80
|
+
...r.lines,
|
|
81
|
+
], deps);
|
|
82
|
+
if (old?.ok !== false && r.lines.length === 0)
|
|
83
|
+
deps.log("versions/lock.json records every frozen file as it stands");
|
|
84
|
+
return 0;
|
|
85
|
+
}
|
|
86
|
+
/** The scorecard's text, "" when there is none. */
|
|
87
|
+
const statusText = (paperDir, deps) => new TextDecoder().decode(deps.files.readBytes(callerPath(join(paperDir, STATUS_FILE))) ??
|
|
88
|
+
new Uint8Array());
|
|
89
|
+
/** Whether the scorecard without its list says everything else it said: parsed, both, and compared. */
|
|
90
|
+
function keepsTheRest(before, without, yaml) {
|
|
91
|
+
const after = yaml(frontmatterOf(without) ?? "");
|
|
92
|
+
return (after.ok && R.isDeepEqual(R.omit(before, ["stages"]), after.value ?? {}));
|
|
93
|
+
}
|
|
94
|
+
/** The scorecard read and its list taken out — checked by parsing both, so a cut that misreads is refused. */
|
|
95
|
+
function scorecard(paperDir, deps) {
|
|
96
|
+
const text = statusText(paperDir, deps);
|
|
97
|
+
const before = deps.yaml(frontmatterOf(text) ?? "");
|
|
98
|
+
if (!before.ok)
|
|
99
|
+
return err(`${STATUS_FILE}: the frontmatter does not parse (${before.error}) — fix it, then migrate`);
|
|
100
|
+
// A frontmatter that is no mapping (none, or a bare value) has no `stages:` key to take out.
|
|
101
|
+
const fields = isRecord(before.value) ? before.value : {};
|
|
102
|
+
const list = fieldOf(fields, "stages");
|
|
103
|
+
const stages = Array.isArray(list) ? list : [];
|
|
104
|
+
const without = withoutStages(text);
|
|
105
|
+
return without === null || keepsTheRest(fields, without, deps.yaml)
|
|
106
|
+
? ok({ stages, without })
|
|
107
|
+
: err(`${STATUS_FILE}: taking the stages: list out would change the rest of its frontmatter — take it out by hand, then migrate`);
|
|
108
|
+
}
|
|
109
|
+
/** A file of the paper, by its path relative to the paper: its size and digest, or null. */
|
|
110
|
+
const paperFacts = (paperDir, deps) => (rel) => {
|
|
111
|
+
const b = deps.files.readBytes(callerPath(resolve(paperDir, rel)));
|
|
112
|
+
return b === null ? null : { bytes: b.length, sha256: sha256Hex(b) };
|
|
113
|
+
};
|
|
114
|
+
/** Each copy, then each move: a shared source is copied before the move takes it away. */
|
|
115
|
+
function carry(paperDir, plan, deps) {
|
|
116
|
+
const at = (rel) => callerPath(resolve(paperDir, rel));
|
|
117
|
+
plan.copies.forEach((m) => {
|
|
118
|
+
deps.copy(at(m.from), at(m.to));
|
|
119
|
+
deps.log(`copied ${m.from} → ${m.to}`);
|
|
120
|
+
});
|
|
121
|
+
plan.moves.forEach((m) => {
|
|
122
|
+
deps.move(at(m.from), at(m.to));
|
|
123
|
+
deps.log(`moved ${m.from} → ${m.to}`);
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
/** The plan carried out: the files, the lock, the scorecard without its list. */
|
|
127
|
+
function migrate(paperDir, plan, card, deps) {
|
|
128
|
+
carry(paperDir, plan, deps);
|
|
129
|
+
const entries = Object.keys(plan.lock).length;
|
|
130
|
+
if (entries > 0) {
|
|
131
|
+
writeLock(paperDir, plan.lock, deps);
|
|
132
|
+
deps.log(`recorded versions/lock.json, ${String(entries)} entries`);
|
|
133
|
+
}
|
|
134
|
+
if (card.without !== null) {
|
|
135
|
+
deps.files.writeAtomic(callerPath(join(paperDir, STATUS_FILE)), new TextEncoder().encode(card.without));
|
|
136
|
+
deps.log(`removed the stages: list from ${STATUS_FILE} — the folders and the lock are the record now`);
|
|
137
|
+
}
|
|
138
|
+
return 0;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* A plan carried out only once its rehearsal on the paths it touches went through (src/domain/
|
|
142
|
+
* versions-migration.ts, `rehearse`): a plan that could stop half-way is a refusal, nothing written.
|
|
143
|
+
*/
|
|
144
|
+
export function carryOut(paperDir, plan, card, deps) {
|
|
145
|
+
const ran = rehearse(plan, (p) => deps.files.isFile(callerPath(resolve(paperDir, p))));
|
|
146
|
+
return ran.ok
|
|
147
|
+
? migrate(paperDir, plan, card, deps)
|
|
148
|
+
: refused([...ran.error, "nothing was moved"], deps);
|
|
149
|
+
}
|
|
150
|
+
/** The lock already there, or the line saying it must be written first. */
|
|
151
|
+
function lockBefore(paperDir, deps) {
|
|
152
|
+
const lock = readLock(paperDir, deps.files) ?? ok({});
|
|
153
|
+
return lock.ok
|
|
154
|
+
? lock
|
|
155
|
+
: err(`versions/lock.json: ${lock.error} — \`npx paperlint versions lock ${shown(deps.cwd, paperDir)}\` writes it anew; then migrate`);
|
|
156
|
+
}
|
|
157
|
+
function runMigrate(paperDir, cycles, deps) {
|
|
158
|
+
const card = scorecard(paperDir, deps);
|
|
159
|
+
if (!card.ok)
|
|
160
|
+
return (deps.err(card.error), 2);
|
|
161
|
+
const lock = lockBefore(paperDir, deps);
|
|
162
|
+
if (!lock.ok)
|
|
163
|
+
return (deps.err(lock.error), 2);
|
|
164
|
+
const plan = planMigration({
|
|
165
|
+
cycleIds: cycles.list.map((c) => c.id),
|
|
166
|
+
stages: card.value.stages,
|
|
167
|
+
root: entriesIn(versionsDir(paperDir), deps),
|
|
168
|
+
factsOf: paperFacts(paperDir, deps),
|
|
169
|
+
lock: lock.value,
|
|
170
|
+
exists: (rel) => deps.files.isFile(callerPath(resolve(paperDir, rel))),
|
|
171
|
+
});
|
|
172
|
+
if (!plan.ok)
|
|
173
|
+
return refused([...plan.error, "nothing was moved"], deps);
|
|
174
|
+
// A copy always has its move: the last destination of a shared source is moved, not copied.
|
|
175
|
+
if (plan.value.moves.length === 0 && card.value.without === null)
|
|
176
|
+
return (deps.log(`nothing to migrate: ${STATUS_FILE} has no stages: list, and no file of the old layout is left in versions/`),
|
|
177
|
+
0);
|
|
178
|
+
return carryOut(paperDir, plan.value, card.value, deps);
|
|
179
|
+
}
|
|
180
|
+
const refused = (lines, deps) => {
|
|
181
|
+
lines.forEach((l) => {
|
|
182
|
+
deps.err(l);
|
|
183
|
+
});
|
|
184
|
+
return 2;
|
|
185
|
+
};
|
|
186
|
+
// ── the command ─────────────────────────────────────────────────────────────────────────
|
|
187
|
+
const NO_CYCLES_LOCK = 'the paper keeps no "cycles" in paperlint.json: there is no versions/<cycle>/ to lock (docs/configuration.md, "The paper\'s cycles")';
|
|
188
|
+
const NO_CYCLES_MIGRATE = 'the paper keeps no "cycles" in paperlint.json: its stages: list stays its record — folders per attempt are named by cycle ids (docs/configuration.md, "The paper\'s cycles")';
|
|
189
|
+
/** `paperlint versions …`: exit 0, or 2 for a command line or a paper it cannot run on. */
|
|
190
|
+
export function runVersions(words, deps) {
|
|
191
|
+
const a = versionsArgs(words);
|
|
192
|
+
if (a.extra.length > 0)
|
|
193
|
+
return (deps.err(`\`versions ${a.sub}\` takes one paper folder — got also \`${a.extra.join(" ")}\``),
|
|
194
|
+
2);
|
|
195
|
+
const paperDir = resolve(deps.cwd, a.paper);
|
|
196
|
+
if (a.sub === "show") {
|
|
197
|
+
const lines = versionLines(paperDir, deps);
|
|
198
|
+
if (!lines.ok)
|
|
199
|
+
return (deps.err(lines.error), 2);
|
|
200
|
+
return (logAll(lines.value, deps), 0);
|
|
201
|
+
}
|
|
202
|
+
const cycles = cyclesIn(paperDir, deps.files);
|
|
203
|
+
if (cycles === null)
|
|
204
|
+
return (deps.err(a.sub === "lock" ? NO_CYCLES_LOCK : NO_CYCLES_MIGRATE), 2);
|
|
205
|
+
return a.sub === "lock"
|
|
206
|
+
? runLock(paperDir, cycles, deps)
|
|
207
|
+
: runMigrate(paperDir, cycles, deps);
|
|
208
|
+
}
|
|
209
|
+
//# sourceMappingURL=versions-command.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"versions-command.js","sourceRoot":"","sources":["../src/versions-command.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,KAAK,CAAC,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,GAAG,EAAE,EAAE,EAAe,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EACL,aAAa,EACb,aAAa,EACb,QAAQ,EACR,aAAa,GAEd,MAAM,gCAAgC,CAAC;AACxC,OAAO,EACL,SAAS,EACT,UAAU,EACV,SAAS,EACT,QAAQ,EACR,MAAM,GAGP,MAAM,sBAAsB,CAAC;AAI9B,OAAO,EACL,QAAQ,EACR,SAAS,EACT,aAAa,EACb,QAAQ,EACR,YAAY,EACZ,WAAW,GAEZ,MAAM,eAAe,CAAC;AAEvB,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAU,CAAC;AAElD,MAAM,KAAK,GAAG,CAAC,CAAU,EAAY,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AAElE,MAAM,WAAW,GAAG,oBAAoB,CAAC;AAazC,kGAAkG;AAClG,MAAM,UAAU,YAAY,CAAC,KAAwB;IAKnD,MAAM,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,GAAG,KAAK,CAAC;IAC/B,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;IAC3B,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC;IACnC,OAAO;QACL,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM;QAC3B,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,GAAG;QACtB,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;KACtB,CAAC;AACJ,CAAC;AAED,yEAAyE;AACzE,MAAM,KAAK,GAAG,CAAC,GAAW,EAAE,CAAS,EAAU,EAAE,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,GAAG,CAAC;AAE1E,MAAM,MAAM,GAAG,CAAC,KAAwB,EAAE,IAAyB,EAAQ,EAAE;IAC3E,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE;QAClB,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACd,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AAEF,2FAA2F;AAE3F,oEAAoE;AACpE,SAAS,MAAM,CACb,QAAgB,EAChB,MAAc,EACd,IAAyB;IAEzB,MAAM,IAAI,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;IACnC,MAAM,KAAK,GAAG,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;IAClD,OAAO,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAC/B,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE;QAC9C,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACxD,OAAO,CAAC,KAAK,IAAI;YACf,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC;gBACE;oBACE,GAAG,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,CAAC;oBACpC,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;iBAC9C;aACF,CAAC;IACR,CAAC,CAAC,CACH,CAAC;AACJ,CAAC;AAED,MAAM,SAAS,GAAG,CAChB,QAAgB,EAChB,IAAU,EACV,IAAyB,EACnB,EAAE;IACR,IAAI,CAAC,KAAK,CAAC,WAAW,CACpB,UAAU,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAC,CAAC,EAClD,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CACzC,CAAC;AACJ,CAAC,CAAC;AAEF,SAAS,OAAO,CACd,QAAgB,EAChB,MAAc,EACd,IAAyB;IAEzB,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;IAC7C,MAAM,GAAG,GAAG,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;IAC3C,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,GAAG,KAAK,IAAI;QACpC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,gDAAgD,CAAC,EAAE,CAAC,CAAC,CAAC;IACzE,MAAM,CAAC,GAAG,MAAM,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,KAAK,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IACvE,SAAS,CAAC,QAAQ,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAClC,MAAM,CACJ;QACE,GAAG,CAAC,GAAG,EAAE,EAAE,KAAK,KAAK;YACnB,CAAC,CAAC;gBACE,oCAAoC,GAAG,CAAC,KAAK,gCAAgC;aAC9E;YACH,CAAC,CAAC,EAAE,CAAC;QACP,GAAG,CAAC,CAAC,KAAK;KACX,EACD,IAAI,CACL,CAAC;IACF,IAAI,GAAG,EAAE,EAAE,KAAK,KAAK,IAAI,CAAC,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC;QAC3C,IAAI,CAAC,GAAG,CAAC,2DAA2D,CAAC,CAAC;IACxE,OAAO,CAAC,CAAC;AACX,CAAC;AAUD,mDAAmD;AACnD,MAAM,UAAU,GAAG,CAAC,QAAgB,EAAE,IAAyB,EAAU,EAAE,CACzE,IAAI,WAAW,EAAE,CAAC,MAAM,CACtB,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC;IAC3D,IAAI,UAAU,EAAE,CACnB,CAAC;AAEJ,uGAAuG;AACvG,SAAS,YAAY,CACnB,MAAyC,EACzC,OAAe,EACf,IAAe;IAEf,MAAM,KAAK,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IACjD,OAAO,CACL,KAAK,CAAC,EAAE,IAAI,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC,CACzE,CAAC;AACJ,CAAC;AAED,8GAA8G;AAC9G,SAAS,SAAS,CAChB,QAAgB,EAChB,IAAyB;IAEzB,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IACxC,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IACpD,IAAI,CAAC,MAAM,CAAC,EAAE;QACZ,OAAO,GAAG,CACR,GAAG,WAAW,qCAAqC,MAAM,CAAC,KAAK,0BAA0B,CAC1F,CAAC;IACJ,6FAA6F;IAC7F,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1D,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACvC,MAAM,MAAM,GAAuB,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IACnE,MAAM,OAAO,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;IACpC,OAAO,OAAO,KAAK,IAAI,IAAI,YAAY,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC;QACjE,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;QACzB,CAAC,CAAC,GAAG,CACD,GAAG,WAAW,4GAA4G,CAC3H,CAAC;AACR,CAAC;AAED,4FAA4F;AAC5F,MAAM,UAAU,GACd,CAAC,QAAgB,EAAE,IAAyB,EAAE,EAAE,CAAC,CAAC,GAAW,EAAE,EAAE;IAC/D,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;IACnE,OAAO,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;AACvE,CAAC,CAAC;AAEJ,0FAA0F;AAC1F,SAAS,KAAK,CACZ,QAAgB,EAChB,IAAmB,EACnB,IAAyB;IAEzB,MAAM,EAAE,GAAG,CAAC,GAAW,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC;IAC/D,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE;QACxB,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAChC,IAAI,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IACH,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE;QACvB,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAChC,IAAI,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;AACL,CAAC;AAED,iFAAiF;AACjF,SAAS,OAAO,CACd,QAAgB,EAChB,IAAmB,EACnB,IAAe,EACf,IAAyB;IAEzB,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IAC5B,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;IAC9C,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;QAChB,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QACrC,IAAI,CAAC,GAAG,CAAC,qCAAqC,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAC3E,CAAC;IACD,IAAI,IAAI,CAAC,OAAO,KAAK,IAAI,EAAE,CAAC;QAC1B,IAAI,CAAC,KAAK,CAAC,WAAW,CACpB,UAAU,CAAC,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC,EACvC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CACvC,CAAC;QACF,IAAI,CAAC,GAAG,CACN,uCAAuC,WAAW,gDAAgD,CACnG,CAAC;IACJ,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,QAAQ,CACtB,QAAgB,EAChB,IAAmB,EACnB,IAAe,EACf,IAAyB;IAEzB,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAC/B,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,CACpD,CAAC;IACF,OAAO,GAAG,CAAC,EAAE;QACX,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC;QACrC,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,GAAG,CAAC,KAAK,EAAE,mBAAmB,CAAC,EAAE,IAAI,CAAC,CAAC;AACzD,CAAC;AAED,2EAA2E;AAC3E,SAAS,UAAU,CACjB,QAAgB,EAChB,IAAyB;IAEzB,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;IACtD,OAAO,IAAI,CAAC,EAAE;QACZ,CAAC,CAAC,IAAI;QACN,CAAC,CAAC,GAAG,CACD,uBAAuB,IAAI,CAAC,KAAK,oCAAoC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,iCAAiC,CAChI,CAAC;AACR,CAAC;AAED,SAAS,UAAU,CACjB,QAAgB,EAChB,MAAc,EACd,IAAyB;IAEzB,MAAM,IAAI,GAAG,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IACvC,IAAI,CAAC,IAAI,CAAC,EAAE;QAAE,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;IAC/C,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IACxC,IAAI,CAAC,IAAI,CAAC,EAAE;QAAE,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;IAC/C,MAAM,IAAI,GAAG,aAAa,CAAC;QACzB,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACtC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM;QACzB,IAAI,EAAE,SAAS,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC;QAC5C,OAAO,EAAE,UAAU,CAAC,QAAQ,EAAE,IAAI,CAAC;QACnC,IAAI,EAAE,IAAI,CAAC,KAAK;QAChB,MAAM,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC;KACvE,CAAC,CAAC;IACH,IAAI,CAAC,IAAI,CAAC,EAAE;QAAE,OAAO,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,EAAE,mBAAmB,CAAC,EAAE,IAAI,CAAC,CAAC;IACzE,4FAA4F;IAC5F,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,KAAK,IAAI;QAC9D,OAAO,CACL,IAAI,CAAC,GAAG,CACN,uBAAuB,WAAW,0EAA0E,CAC7G;YACD,CAAC,CACF,CAAC;IACJ,OAAO,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;AAC1D,CAAC;AAED,MAAM,OAAO,GAAG,CACd,KAAwB,EACxB,IAAyB,EACjB,EAAE;IACV,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE;QAClB,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACd,CAAC,CAAC,CAAC;IACH,OAAO,CAAC,CAAC;AACX,CAAC,CAAC;AAEF,2FAA2F;AAE3F,MAAM,cAAc,GAClB,qIAAqI,CAAC;AAExI,MAAM,iBAAiB,GACrB,8KAA8K,CAAC;AAEjL,2FAA2F;AAC3F,MAAM,UAAU,WAAW,CACzB,KAAwB,EACxB,IAAyB;IAEzB,MAAM,CAAC,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;IAC9B,IAAI,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC;QACpB,OAAO,CACL,IAAI,CAAC,GAAG,CACN,cAAc,CAAC,CAAC,GAAG,0CAA0C,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CACnF;YACD,CAAC,CACF,CAAC;IACJ,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC;IAC5C,IAAI,CAAC,CAAC,GAAG,KAAK,MAAM,EAAE,CAAC;QACrB,MAAM,KAAK,GAAG,YAAY,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QAC3C,IAAI,CAAC,KAAK,CAAC,EAAE;YAAE,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;QACjD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;IACxC,CAAC;IACD,MAAM,MAAM,GAAG,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;IAC9C,IAAI,MAAM,KAAK,IAAI;QACjB,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,KAAK,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC,CAAC;IAC9E,OAAO,CAAC,CAAC,GAAG,KAAK,MAAM;QACrB,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC;QACjC,CAAC,CAAC,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;AACzC,CAAC"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { type CycleId, type Cycles } from "./domain/cycle.ts";
|
|
2
|
+
import { type Result } from "./domain/result.ts";
|
|
3
|
+
import { type DraftDrift, type Entry, type FileFacts, type Lock } from "./domain/versions.ts";
|
|
4
|
+
import type { Files } from "./ports/files.ts";
|
|
5
|
+
import type { ListDir } from "./ports/talk-media.ts";
|
|
6
|
+
import { type ProseDeps } from "./tex-paper.ts";
|
|
7
|
+
/** The paper's `versions/` folder. */
|
|
8
|
+
export declare const versionsDir: (paperDir: string) => string;
|
|
9
|
+
/** A frozen file's path, by its key. */
|
|
10
|
+
export declare const frozenPath: (paperDir: string, key: string) => string;
|
|
11
|
+
/** Whether a frozen file is on disk, by its key. */
|
|
12
|
+
export declare const hasFrozen: (paperDir: string, files: Files) => (key: string) => boolean;
|
|
13
|
+
/** A frozen file's text, by its key; null when it is not there. */
|
|
14
|
+
export declare const frozenText: (paperDir: string, key: string, files: Files) => string | null;
|
|
15
|
+
/** The size and digest of a frozen file on disk, by its key: zero bytes of nothing when it is gone. */
|
|
16
|
+
export declare const factsOfFrozen: (paperDir: string, files: Files) => (key: string) => FileFacts;
|
|
17
|
+
/** `versions/lock.json`: null when there is none; else parsed, or why it does not parse. */
|
|
18
|
+
export declare function readLock(paperDir: string, files: Files): Result<Lock, string> | null;
|
|
19
|
+
/** What reading the folder needs: the disk and its listings. */
|
|
20
|
+
export interface VersionsDeps {
|
|
21
|
+
readonly files: Files;
|
|
22
|
+
readonly listDir: ListDir;
|
|
23
|
+
}
|
|
24
|
+
/** The entries of a folder, each a file or a folder, by name. */
|
|
25
|
+
export declare const entriesIn: (dir: string, deps: VersionsDeps) => readonly Entry[];
|
|
26
|
+
/** The paper's cycles, when it keeps them and they read; null for the flat form or a broken record. */
|
|
27
|
+
export declare function cyclesIn(paperDir: string, files: Files): Cycles | null;
|
|
28
|
+
/** paper.tex, assembled as the last build read it (its includes spliced in); null without one. */
|
|
29
|
+
export declare function draftText(paperDir: string, deps: ProseDeps): string | null;
|
|
30
|
+
/** The draft against the frozen source of the paper's attempt: none, nothing frozen, the same, or drifted. */
|
|
31
|
+
export declare function draftDrift(paperDir: string, cycles: Cycles, draft: string, files: Files): DraftDrift;
|
|
32
|
+
/**
|
|
33
|
+
* The version → state table of the paper in `paperDir`: each attempt's frozen files and what they
|
|
34
|
+
* are, then the draft. Or why there is none: the paper keeps no `cycles`.
|
|
35
|
+
*/
|
|
36
|
+
export declare function versionLines(paperDir: string, deps: ProseDeps): Result<readonly string[], string>;
|
|
37
|
+
/** What a `--save` will freeze once the portal takes the PDF: nothing for the flat form, else where. */
|
|
38
|
+
export type FreezePlan = {
|
|
39
|
+
readonly kind: "flat";
|
|
40
|
+
} | {
|
|
41
|
+
readonly kind: "freeze";
|
|
42
|
+
readonly cycle: CycleId;
|
|
43
|
+
readonly stage: "submitted" | "camera-ready";
|
|
44
|
+
/** paper.tex as the build read it, includes spliced in: the source the PDF was built from. */
|
|
45
|
+
readonly source: string;
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Before a `--save` sends: what it will freeze — the open cycle's `submitted`, or the accepted one's
|
|
49
|
+
* `camera-ready` — and the source to freeze beside the PDF. Refused when the build's record does not
|
|
50
|
+
* say the source on disk is the one the PDF was built from: a PDF frozen with another source is a
|
|
51
|
+
* pair that lies.
|
|
52
|
+
*/
|
|
53
|
+
export declare function freezePlan(paperDir: string, cycles: Cycles | null, deps: ProseDeps): Result<FreezePlan, string>;
|
|
54
|
+
/** What freezing writes with: the disk, and the instant the lock records (ISO 8601). */
|
|
55
|
+
export interface FreezeDeps {
|
|
56
|
+
readonly files: Files;
|
|
57
|
+
readonly now: () => string;
|
|
58
|
+
}
|
|
59
|
+
/** What was sent: the paper, its plan, the PDF's bytes, and the paper as the command names it. */
|
|
60
|
+
export interface Sent {
|
|
61
|
+
readonly paperDir: string;
|
|
62
|
+
readonly plan: Extract<FreezePlan, {
|
|
63
|
+
readonly kind: "freeze";
|
|
64
|
+
}>;
|
|
65
|
+
readonly pdf: Uint8Array;
|
|
66
|
+
readonly shownPaper: string;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* After the portal took the PDF: the PDF and its source written to `versions/<cycle>/<stage>.*`,
|
|
70
|
+
* replacing an earlier upload's, and recorded in the lock. The line to print; an error line when the
|
|
71
|
+
* lock does not read (the files are frozen, the lock left as it is).
|
|
72
|
+
*/
|
|
73
|
+
export declare function freezeSent(s: Sent, deps: FreezeDeps): Result<string, string>;
|
|
74
|
+
/** What a send in the flat form says instead of a freeze. */
|
|
75
|
+
export declare const NOT_FROZEN = "not frozen the paper keeps no \"cycles\" in paperlint.json: versions are frozen per attempt, in versions/<cycle>/ (docs/configuration.md, \"The paper's cycles\")";
|
|
76
|
+
//# sourceMappingURL=versions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"versions.d.ts","sourceRoot":"","sources":["../src/versions.ts"],"names":[],"mappings":"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"}
|