paperlint 10.2.0 → 10.4.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/ci.yml +15 -4
- package/README.md +1 -0
- package/dist/adapters/git/index.d.ts +10 -0
- package/dist/adapters/git/index.d.ts.map +1 -0
- package/dist/adapters/git/index.js +151 -0
- package/dist/adapters/git/index.js.map +1 -0
- package/dist/adapters/memory/index.d.ts +6 -0
- package/dist/adapters/memory/index.d.ts.map +1 -1
- package/dist/adapters/memory/index.js +8 -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/list-entries.io.d.ts +3 -0
- package/dist/adapters/node/list-entries.io.d.ts.map +1 -0
- package/dist/adapters/node/list-entries.io.js +24 -0
- package/dist/adapters/node/list-entries.io.js.map +1 -0
- package/dist/adapters/study-registry/index.d.ts +412 -1
- package/dist/adapters/study-registry/index.d.ts.map +1 -1
- package/dist/adapters/study-registry/index.js +245 -8
- package/dist/adapters/study-registry/index.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +38 -6
- package/dist/cli.js.map +1 -1
- package/dist/domain/decide-first.d.ts +100 -0
- package/dist/domain/decide-first.d.ts.map +1 -0
- package/dist/domain/decide-first.js +102 -0
- package/dist/domain/decide-first.js.map +1 -0
- package/dist/domain/index-columns.d.ts +45 -0
- package/dist/domain/index-columns.d.ts.map +1 -0
- package/dist/domain/index-columns.js +62 -0
- package/dist/domain/index-columns.js.map +1 -0
- package/dist/domain/study-mode.d.ts +37 -0
- package/dist/domain/study-mode.d.ts.map +1 -0
- package/dist/domain/study-mode.js +45 -0
- package/dist/domain/study-mode.js.map +1 -0
- package/dist/domain/study-registry.d.ts +253 -10
- package/dist/domain/study-registry.d.ts.map +1 -1
- package/dist/domain/study-registry.js +325 -27
- package/dist/domain/study-registry.js.map +1 -1
- package/dist/outputs-before-decision-rule.d.ts +17 -0
- package/dist/outputs-before-decision-rule.d.ts.map +1 -0
- package/dist/outputs-before-decision-rule.js +90 -0
- package/dist/outputs-before-decision-rule.js.map +1 -0
- package/dist/ports/git-history.d.ts +44 -0
- package/dist/ports/git-history.d.ts.map +1 -0
- package/dist/ports/git-history.js +2 -0
- package/dist/ports/git-history.js.map +1 -0
- package/dist/ports/list-entries.d.ts +17 -0
- package/dist/ports/list-entries.d.ts.map +1 -0
- package/dist/ports/list-entries.js +2 -0
- package/dist/ports/list-entries.js.map +1 -0
- package/dist/ports/study-registry-codec.d.ts +9 -2
- package/dist/ports/study-registry-codec.d.ts.map +1 -1
- package/dist/studies.d.ts +4 -0
- package/dist/studies.d.ts.map +1 -1
- package/dist/studies.js +55 -24
- package/dist/studies.js.map +1 -1
- package/dist/study-gate.d.ts +14 -0
- package/dist/study-gate.d.ts.map +1 -0
- package/dist/study-gate.js +95 -0
- package/dist/study-gate.js.map +1 -0
- package/dist/study-index-input.d.ts +5 -0
- package/dist/study-index-input.d.ts.map +1 -0
- package/dist/study-index-input.js +13 -0
- package/dist/study-index-input.js.map +1 -0
- package/dist/study-modes.d.ts +45 -0
- package/dist/study-modes.d.ts.map +1 -0
- package/dist/study-modes.js +70 -0
- package/dist/study-modes.js.map +1 -0
- package/dist/study-registry-rule.d.ts +29 -6
- package/dist/study-registry-rule.d.ts.map +1 -1
- package/dist/study-registry-rule.js +91 -40
- package/dist/study-registry-rule.js.map +1 -1
- package/dist/study-run.d.ts +19 -0
- package/dist/study-run.d.ts.map +1 -0
- package/dist/study-run.js +9 -0
- package/dist/study-run.js.map +1 -0
- package/docs/design/study-modes.md +247 -0
- package/docs/design/study-registry.md +137 -15
- package/docs/e2e.md +8 -4
- package/docs/layout.md +26 -21
- package/docs/rules/repro/outputs-before-decision.md +119 -0
- package/docs/rules/repro/study-plan-name.md +70 -0
- package/docs/rules/repro/study-registered.md +206 -15
- package/docs/rules.md +54 -52
- package/docs/testing.md +1 -0
- package/package.json +2 -1
- package/scripts/check.ts +6 -0
- package/skills/build-benchmark/SKILL.md +24 -12
- package/skills/build-benchmark/SKILL.md.spec.ts +23 -11
- package/skills/build-label-page/SKILL.md +9 -7
- package/skills/build-label-page/SKILL.md.spec.ts +8 -6
- package/skills/camera-ready/SKILL.md +6 -1
- package/skills/camera-ready/SKILL.md.spec.ts +5 -0
- package/skills/draft-paper/SKILL.md +11 -3
- package/skills/draft-paper/SKILL.md.spec.ts +10 -2
- package/skills/harden-paper/SKILL.md +12 -2
- package/skills/harden-paper/SKILL.md.spec.ts +11 -1
- package/skills/osf-artifact-upload/SKILL.md +7 -1
- package/skills/osf-artifact-upload/SKILL.md.spec.ts +6 -0
- package/skills/pc-panel-review/SKILL.md +10 -3
- package/skills/pc-panel-review/SKILL.md.spec.ts +9 -2
- package/skills/run-agent-grid/SKILL.md +10 -5
- package/skills/run-agent-grid/SKILL.md.spec.ts +9 -4
- package/skills/tighten-paper/SKILL.md +5 -1
- package/skills/tighten-paper/SKILL.md.spec.ts +4 -0
- package/src/adapters/git/history.test.ts +121 -0
- package/src/adapters/git/index.test.ts +268 -0
- package/src/adapters/git/index.ts +227 -0
- package/src/adapters/memory/index.test.ts +15 -1
- package/src/adapters/memory/index.ts +13 -0
- package/src/adapters/node/index.ts +1 -0
- package/src/adapters/node/list-entries.io.ts +26 -0
- package/src/adapters/node/list-entries.test.ts +43 -0
- package/src/adapters/study-registry/index.test.ts +343 -0
- package/src/adapters/study-registry/index.ts +374 -10
- package/src/adapters/study-registry/mode.test.ts +162 -0
- package/src/cli.ts +52 -6
- package/src/domain/decide-first.test.ts +258 -0
- package/src/domain/decide-first.ts +243 -0
- package/src/domain/index-columns.test.ts +216 -0
- package/src/domain/index-columns.ts +105 -0
- package/src/domain/study-measurements.test.ts +633 -0
- package/src/domain/study-mode.test.ts +55 -0
- package/src/domain/study-mode.ts +78 -0
- package/src/domain/study-registry.test.ts +48 -32
- package/src/domain/study-registry.ts +621 -36
- package/src/new-paper.test.ts +6 -1
- package/src/outputs-before-decision-rule.test.ts +206 -0
- package/src/outputs-before-decision-rule.ts +124 -0
- package/src/ports/git-history.ts +44 -0
- package/src/ports/list-entries.ts +18 -0
- package/src/ports/study-registry-codec.ts +13 -2
- package/src/rule-cases.test.ts +103 -1
- package/src/studies-cli.test.ts +2 -2
- package/src/studies-index-modes.test.ts +129 -0
- package/src/studies.test.ts +39 -9
- package/src/studies.ts +99 -29
- package/src/study-gate.test.ts +316 -0
- package/src/study-gate.ts +161 -0
- package/src/study-index-input.ts +23 -0
- package/src/study-modes.ts +120 -0
- package/src/study-registry-rule.test.ts +333 -7
- package/src/study-registry-rule.ts +145 -41
- package/src/study-run.ts +21 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `repro/outputs-before-decision` — a study decided before its run shows that order in git's
|
|
3
|
+
* history: every output entered history after the decision file did, and no output exists while the
|
|
4
|
+
* decision is uncommitted. What is judged, and why, is `src/domain/decide-first.ts` and
|
|
5
|
+
* docs/rules/repro/outputs-before-decision.md; this file finds the decide-first studies, lists their
|
|
6
|
+
* folders, asks git through the `GitOrder` port, and reports.
|
|
7
|
+
*
|
|
8
|
+
* ── WHY A RULE MAY ASK GIT HERE ────────────────────────────────────────────────
|
|
9
|
+
* `eslint-rules/` may not run git (eslint.config.mjs, `GIT_IN_A_RULE`): a pinned sha is deleted by a
|
|
10
|
+
* squash or a gc, and a shallow CI checkout has none. This rule pins no sha. It asks the history the
|
|
11
|
+
* checkout has for an ORDER, which a squash merge keeps when the decision was merged before the run
|
|
12
|
+
* (the decide-first workflow), and it reports a shallow clone by name instead of judging it.
|
|
13
|
+
*
|
|
14
|
+
* Reported on `PIPELINE-STATUS.md`, first line, like the other `repro/` rules.
|
|
15
|
+
*/
|
|
16
|
+
import { basename, dirname, join } from "node:path";
|
|
17
|
+
import { callerPath } from "./caller-path.js";
|
|
18
|
+
import { filesUnder, modeStudies, onDisk, } from "./study-modes.js";
|
|
19
|
+
import { judgeOrder, orderMessage, } from "./domain/decide-first.js";
|
|
20
|
+
import { REPRO_DIR } from "./domain/repro-layout.js";
|
|
21
|
+
import { rulePageUrl } from "./venue-rules.js";
|
|
22
|
+
const STATUS_FILE = "PIPELINE-STATUS.md";
|
|
23
|
+
/** Every decide-first study of the paper folder `paper`, with its tree and its history's order. */
|
|
24
|
+
export const decideFirstStudies = (paper, deps) => modeStudies(paper, deps).flatMap(({ row, plan, mode, empty }) => {
|
|
25
|
+
// Only a ready plan decides: a draft may name no outputs, or an empty decision file.
|
|
26
|
+
if (mode.kind !== "decide_before_run" || empty.length > 0)
|
|
27
|
+
return [];
|
|
28
|
+
const folder = join(paper, REPRO_DIR, row.folder);
|
|
29
|
+
const decision = join(paper, mode.decision.file);
|
|
30
|
+
const on = onDisk(decision, deps);
|
|
31
|
+
return [
|
|
32
|
+
{
|
|
33
|
+
id: row.id,
|
|
34
|
+
folder: row.folder,
|
|
35
|
+
plan,
|
|
36
|
+
mode,
|
|
37
|
+
tree: filesUnder(folder, deps),
|
|
38
|
+
facts: on === "directory" || on === "symbolic link"
|
|
39
|
+
? { kind: "not-a-file", what: on }
|
|
40
|
+
: deps.git.order(callerPath(folder), callerPath(decision)),
|
|
41
|
+
},
|
|
42
|
+
];
|
|
43
|
+
});
|
|
44
|
+
const PROBLEMS = [
|
|
45
|
+
"decision-is-output",
|
|
46
|
+
"decision-deleted",
|
|
47
|
+
"decision-not-file",
|
|
48
|
+
"no-history",
|
|
49
|
+
"shallow",
|
|
50
|
+
"undecided-output",
|
|
51
|
+
"output-before-decision",
|
|
52
|
+
];
|
|
53
|
+
const NAME = "repro/outputs-before-decision";
|
|
54
|
+
/** On `PIPELINE-STATUS.md`, every finding of every decide-first study of its paper, at its first line. */
|
|
55
|
+
const reportOn = (context, deps) => {
|
|
56
|
+
if (basename(context.filename) !== STATUS_FILE)
|
|
57
|
+
return {};
|
|
58
|
+
return {
|
|
59
|
+
root() {
|
|
60
|
+
const at = context.sourceCode.getLocFromIndex(0);
|
|
61
|
+
decideFirstStudies(dirname(context.filename), deps)
|
|
62
|
+
.flatMap(judgeOrder)
|
|
63
|
+
.forEach((f) => {
|
|
64
|
+
context.report({
|
|
65
|
+
loc: { start: at, end: at },
|
|
66
|
+
messageId: f.problem,
|
|
67
|
+
data: { text: orderMessage(f) },
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
/** The rule, reading the folder and git through `deps`. */
|
|
74
|
+
export const outputsBeforeDecisionRules = (deps) => ({
|
|
75
|
+
"outputs-before-decision": {
|
|
76
|
+
meta: {
|
|
77
|
+
type: "suggestion",
|
|
78
|
+
docs: {
|
|
79
|
+
description: "a study decided before its run shows it in git's history: every output entered history after its decision file, and none exists while the decision is uncommitted",
|
|
80
|
+
url: rulePageUrl(NAME),
|
|
81
|
+
},
|
|
82
|
+
schema: [],
|
|
83
|
+
messages: Object.fromEntries(PROBLEMS.map((p) => [p, "{{text}}"])),
|
|
84
|
+
},
|
|
85
|
+
create: (context) => reportOn(context, deps),
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
/** Its level in paperlint's own config: an error. */
|
|
89
|
+
export const ORDER_RULE_LEVELS = { "repro/outputs-before-decision": "error" };
|
|
90
|
+
//# sourceMappingURL=outputs-before-decision-rule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outputs-before-decision-rule.js","sourceRoot":"","sources":["../src/outputs-before-decision-rule.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What git says of a study's files — shaped by what the decide-first gate needs: whether a decision
|
|
3
|
+
* file is committed as it stands, and in which commit (`studies gate`); and whether
|
|
4
|
+
* each output entered history after the decision (`repro/outputs-before-decision`). The one
|
|
5
|
+
* implementation is `src/adapters/git/`; `src/cli.ts` wires it.
|
|
6
|
+
*/
|
|
7
|
+
import type { OrderFacts } from "../domain/decide-first.ts";
|
|
8
|
+
import type { AbsolutePath } from "../domain/paths.ts";
|
|
9
|
+
export type { CommitAt, FirstCommit, Order, OrderFacts, } from "../domain/decide-first.ts";
|
|
10
|
+
export type Committed =
|
|
11
|
+
/** No commit has the file: untracked, ignored, only staged, or absent. */
|
|
12
|
+
{
|
|
13
|
+
readonly kind: "not-committed";
|
|
14
|
+
}
|
|
15
|
+
/** Committed, and changed since (edited, staged, deleted): the commit is not what is on disk. */
|
|
16
|
+
| {
|
|
17
|
+
readonly kind: "changed";
|
|
18
|
+
readonly commit: string;
|
|
19
|
+
}
|
|
20
|
+
/** Committed, then deleted in a later commit: it is not in HEAD, so there is nothing to gate on. */
|
|
21
|
+
| {
|
|
22
|
+
readonly kind: "deleted";
|
|
23
|
+
readonly commit: string;
|
|
24
|
+
}
|
|
25
|
+
/** Committed as it stands: the last commit that touched it, and that commit's date. */
|
|
26
|
+
| {
|
|
27
|
+
readonly kind: "committed";
|
|
28
|
+
readonly commit: string;
|
|
29
|
+
readonly date: string;
|
|
30
|
+
}
|
|
31
|
+
/** git could not answer: not installed, not a repository. */
|
|
32
|
+
| {
|
|
33
|
+
readonly kind: "unknown";
|
|
34
|
+
readonly why: string;
|
|
35
|
+
};
|
|
36
|
+
export interface GitHistory {
|
|
37
|
+
/** `file` (absolute, in the repository that holds `paper`), asked from the paper's folder. */
|
|
38
|
+
readonly committed: (paper: AbsolutePath, file: AbsolutePath) => Committed;
|
|
39
|
+
}
|
|
40
|
+
export interface GitOrder {
|
|
41
|
+
/** The order of `decision`'s first commit against every file's under `studyDir` (a folder that exists). */
|
|
42
|
+
readonly order: (studyDir: AbsolutePath, decision: AbsolutePath) => OrderFacts;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=git-history.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-history.d.ts","sourceRoot":"","sources":["../../src/ports/git-history.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,YAAY,EACV,QAAQ,EACR,WAAW,EACX,KAAK,EACL,UAAU,GACX,MAAM,2BAA2B,CAAC;AAEnC,MAAM,MAAM,SAAS;AACnB,0EAA0E;AACxE;IAAE,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAA;CAAE;AACpC,iGAAiG;GAC/F;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE;AACvD,oGAAoG;GAClG;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE;AACvD,uFAAuF;GACrF;IACE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AACH,6DAA6D;GAC3D;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvD,MAAM,WAAW,UAAU;IACzB,8FAA8F;IAC9F,QAAQ,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,YAAY,KAAK,SAAS,CAAC;CAC5E;AAED,MAAM,WAAW,QAAQ;IACvB,2GAA2G;IAC3G,QAAQ,CAAC,KAAK,EAAE,CACd,QAAQ,EAAE,YAAY,EACtB,QAAQ,EAAE,YAAY,KACnB,UAAU,CAAC;CACjB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-history.js","sourceRoot":"","sources":["../../src/ports/git-history.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A directory's entries with what each one is, read without following a symbolic link — so a walk
|
|
3
|
+
* that descends only into `dir` entries can neither loop on a link to an ancestor nor wander into a
|
|
4
|
+
* tree outside through one. The walker of a study's folder (`src/study-modes.ts`) reads with it.
|
|
5
|
+
*/
|
|
6
|
+
import type { AbsolutePath } from "../domain/paths.ts";
|
|
7
|
+
/**
|
|
8
|
+
* One entry of a directory: a directory, a symbolic link (not followed), or a file — anything else on
|
|
9
|
+
* disk (a socket, a FIFO) reads as a file: a name, never descended into.
|
|
10
|
+
*/
|
|
11
|
+
export interface DirEntry {
|
|
12
|
+
readonly name: string;
|
|
13
|
+
readonly kind: "file" | "dir" | "symlink";
|
|
14
|
+
}
|
|
15
|
+
/** The entries of `dir`; none when it does not exist or is not a directory. */
|
|
16
|
+
export type ListEntries = (dir: AbsolutePath) => readonly DirEntry[];
|
|
17
|
+
//# sourceMappingURL=list-entries.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-entries.d.ts","sourceRoot":"","sources":["../../src/ports/list-entries.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD;;;GAGG;AACH,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS,CAAC;CAC3C;AAED,+EAA+E;AAC/E,MAAM,MAAM,WAAW,GAAG,CAAC,GAAG,EAAE,YAAY,KAAK,SAAS,QAAQ,EAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-entries.js","sourceRoot":"","sources":["../../src/ports/list-entries.ts"],"names":[],"mappings":""}
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* How a `repro/studies.json
|
|
2
|
+
* How a `repro/studies.json`, and a study's `plan.json`, become values: its text parsed once, where it enters, against the schema
|
|
3
3
|
* of `StudyRegistry` (`src/domain/study-registry.ts`). The one implementation is
|
|
4
4
|
* `src/adapters/study-registry/` (zod); `src/cli.ts` wires it.
|
|
5
5
|
*/
|
|
6
|
-
import type { ParsedRegistry } from "../domain/study-registry.ts";
|
|
6
|
+
import type { ParsedPlan, ParsedRegistry, StudyKind } from "../domain/study-registry.ts";
|
|
7
7
|
export interface StudyRegistryCodec {
|
|
8
8
|
/** A `studies.json`'s text: the registry, or the one reason it is not one of this schema. */
|
|
9
9
|
readonly parse: (text: string) => ParsedRegistry;
|
|
10
|
+
/**
|
|
11
|
+
* A study's `plan.json` text, strict: ready, a draft naming its empty texts, or why it is no plan. A
|
|
12
|
+
* study of a `kind` that must declare its mode (a measurement) is ready only with one.
|
|
13
|
+
*/
|
|
14
|
+
readonly parsePlan: (text: string, kind: StudyKind) => ParsedPlan;
|
|
15
|
+
/** A plan still named `prereg.json`, loose: the same three outcomes. */
|
|
16
|
+
readonly parseLegacyPlan: (text: string) => ParsedPlan;
|
|
10
17
|
}
|
|
11
18
|
//# sourceMappingURL=study-registry-codec.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"study-registry-codec.d.ts","sourceRoot":"","sources":["../../src/ports/study-registry-codec.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"study-registry-codec.d.ts","sourceRoot":"","sources":["../../src/ports/study-registry-codec.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EACV,UAAU,EACV,cAAc,EACd,SAAS,EACV,MAAM,6BAA6B,CAAC;AAErC,MAAM,WAAW,kBAAkB;IACjC,6FAA6F;IAC7F,QAAQ,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,cAAc,CAAC;IACjD;;;OAGG;IACH,QAAQ,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,KAAK,UAAU,CAAC;IAClE,wEAAwE;IACxE,QAAQ,CAAC,eAAe,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,UAAU,CAAC;CACxD"}
|
package/dist/studies.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { Files } from "./ports/files.ts";
|
|
2
2
|
import type { StudyRegistryCodec } from "./ports/study-registry-codec.ts";
|
|
3
|
+
import type { ListEntries } from "./ports/list-entries.ts";
|
|
3
4
|
import type { ListDir } from "./ports/talk-media.ts";
|
|
5
|
+
import type { GitHistory, GitOrder } from "./ports/git-history.ts";
|
|
4
6
|
/** What one `studies` run was asked, after the command line. */
|
|
5
7
|
export interface StudiesArgs {
|
|
6
8
|
readonly sub: string | undefined;
|
|
@@ -13,8 +15,10 @@ export interface StudiesArgs {
|
|
|
13
15
|
readonly kind: string | null;
|
|
14
16
|
}
|
|
15
17
|
export interface StudiesDeps {
|
|
18
|
+
readonly git: GitHistory & GitOrder;
|
|
16
19
|
readonly files: Files;
|
|
17
20
|
readonly listDir: ListDir;
|
|
21
|
+
readonly entries: ListEntries;
|
|
18
22
|
readonly codec: StudyRegistryCodec;
|
|
19
23
|
readonly cwd: string;
|
|
20
24
|
/** Today, `YYYY-MM-DD`: the root reads the clock. */
|
package/dist/studies.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"studies.d.ts","sourceRoot":"","sources":["../src/studies.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"studies.d.ts","sourceRoot":"","sources":["../src/studies.ts"],"names":[],"mappings":"AAsCA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AAC1E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAIrD,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAEnE,gEAAgE;AAChE,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,wDAAwD;IACxD,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,oDAAoD;IACpD,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,0CAA0C;IAC1C,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,GAAG,EAAE,UAAU,GAAG,QAAQ,CAAC;IACpC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,kBAAkB,CAAC;IACnC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,qDAAqD;IACrD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACtC;AAsPD,sFAAsF;AACtF,wBAAgB,UAAU,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,WAAW,GAAG,MAAM,CAWpE"}
|
package/dist/studies.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `paperlint studies new|index <paper-dir>` — the two commands that write a paper's study registry,
|
|
3
|
-
* `repro/studies.json`, and its index in `repro/README.md` (docs/design/study-registry.md)
|
|
3
|
+
* `repro/studies.json`, and its index in `repro/README.md` (docs/design/study-registry.md) — and
|
|
4
|
+
* `studies gate <paper-dir> <id>` (src/study-gate.ts), over the studies' modes
|
|
5
|
+
* (docs/design/study-modes.md).
|
|
4
6
|
*
|
|
5
7
|
* new <paper-dir> "<title>" [--kind <kind>]
|
|
6
|
-
* the next id; `repro/<id>-<slug>/README.md` with the id and title in its frontmatter
|
|
7
|
-
* row, `status: designing`, today's date
|
|
8
|
+
* the next id; `repro/<id>-<slug>/README.md` with the id and title in its frontmatter, and
|
|
9
|
+
* `plan.json`, the plan's template; the row, `status: designing`, today's date, its `plan`;
|
|
10
|
+
* the index regenerated
|
|
8
11
|
* index <paper-dir>
|
|
9
12
|
* the index block of `repro/README.md`, regenerated from the registry
|
|
10
13
|
*
|
|
@@ -15,11 +18,14 @@
|
|
|
15
18
|
import { join, relative, resolve } from "node:path";
|
|
16
19
|
import { callerPath } from "./caller-path.js";
|
|
17
20
|
import { README, REPRO_DIR } from "./domain/repro-layout.js";
|
|
18
|
-
import { DEFAULT_KIND, STUDIES_FILE, STUDY_KINDS, addStudy,
|
|
19
|
-
import { registryOf } from "./study-registry-rule.js";
|
|
21
|
+
import { DEFAULT_KIND, PLAN_FILE, STUDIES_FILE, STUDY_KINDS, addStudy, indexCurrent, isStudyKind, planTemplate, planText, registryText, studyReadme, withIndex, } from "./domain/study-registry.js";
|
|
22
|
+
import { readableFolders, registryOf } from "./study-registry-rule.js";
|
|
23
|
+
import { runGate } from "./study-gate.js";
|
|
24
|
+
import { indexInputOf } from "./study-index-input.js";
|
|
20
25
|
const NEW_USAGE = 'npx paperlint studies new <paper-dir> "<title>" [--kind <kind>]';
|
|
21
26
|
const INDEX_USAGE = "npx paperlint studies index <paper-dir>";
|
|
22
|
-
const
|
|
27
|
+
const GATE_USAGE = "npx paperlint studies gate <paper-dir> <id>";
|
|
28
|
+
const SUBS = `new, index or gate — ${[NEW_USAGE, INDEX_USAGE, GATE_USAGE].join(" · ")}`;
|
|
23
29
|
const STATUS_FILE = "PIPELINE-STATUS.md";
|
|
24
30
|
const refuse = (code, line) => ({ code, line });
|
|
25
31
|
/** The paper folder's registry, or the refusal naming why there is none to write to. */
|
|
@@ -32,9 +38,17 @@ function registryIn(p, deps) {
|
|
|
32
38
|
case "unreadable":
|
|
33
39
|
return refuse(1, `${file} is not a study registry: ${r.why}`);
|
|
34
40
|
case "read":
|
|
35
|
-
return r.registry;
|
|
41
|
+
return escaping(p, r.registry, deps) ?? r.registry;
|
|
36
42
|
}
|
|
37
43
|
}
|
|
44
|
+
/** The refusal when a row names a folder that is not one inside `repro/`; null when none does. */
|
|
45
|
+
function escaping(p, r, deps) {
|
|
46
|
+
const readable = readableFolders(p.dir, deps);
|
|
47
|
+
const s = r.studies.find((row) => !readable(row.folder));
|
|
48
|
+
return s === undefined
|
|
49
|
+
? null
|
|
50
|
+
: refuse(1, `${s.id} in ${p.shown}/${REPRO_DIR}/${STUDIES_FILE} names the folder \`${s.folder}\`, which is not one folder inside ${REPRO_DIR}/: nothing is read or written through it. Give the row its own folder's name, then run this again.`);
|
|
51
|
+
}
|
|
38
52
|
const isRefusal = (v) => typeof v === "object" && v !== null && "code" in v && "line" in v;
|
|
39
53
|
const text = (s) => new TextEncoder().encode(s);
|
|
40
54
|
/** The README's text; null when there is none. */
|
|
@@ -47,11 +61,12 @@ const studiesCount = (r) => `${String(r.studies.length)} ${r.studies.length ===
|
|
|
47
61
|
* Write the index of `r` into the README; whether it wrote. A block already in sync is left as it
|
|
48
62
|
* is, so the padding a formatter gave the table is never undone.
|
|
49
63
|
*/
|
|
50
|
-
function writeIndex(dir, r,
|
|
51
|
-
const before = readmeOf(dir, files);
|
|
52
|
-
|
|
64
|
+
function writeIndex(dir, r, deps) {
|
|
65
|
+
const before = readmeOf(dir, deps.files);
|
|
66
|
+
const at = indexInputOf(dir, { kind: "read", registry: r }, deps);
|
|
67
|
+
if (indexCurrent(before, r, at))
|
|
53
68
|
return false;
|
|
54
|
-
files.writeAtomic(callerPath(join(dir, REPRO_DIR, README)), text(withIndex(before, r)));
|
|
69
|
+
deps.files.writeAtomic(callerPath(join(dir, REPRO_DIR, README)), text(withIndex(before, r, at)));
|
|
55
70
|
return true;
|
|
56
71
|
}
|
|
57
72
|
/** The refusal when something that is not a file sits where `repro/README.md` goes; null when none. */
|
|
@@ -75,7 +90,7 @@ function runIndex(p, a, deps) {
|
|
|
75
90
|
return blocked;
|
|
76
91
|
const readme = `${p.shown}/${REPRO_DIR}/${README}`;
|
|
77
92
|
return [
|
|
78
|
-
writeIndex(p.dir, r, deps
|
|
93
|
+
writeIndex(p.dir, r, deps)
|
|
79
94
|
? `wrote the index of ${studiesCount(r)} in ${readme}`
|
|
80
95
|
: `the index in ${readme} is in sync with ${studiesCount(r)}`,
|
|
81
96
|
];
|
|
@@ -92,16 +107,19 @@ function newArgs(a) {
|
|
|
92
107
|
? { title: a.title, kind }
|
|
93
108
|
: refuse(2, `--kind ${kind} is not a kind of study: one of ${STUDY_KINDS.join(", ")}`);
|
|
94
109
|
}
|
|
95
|
-
/** Write a new study's README.md, the registry, and the index; the lines that say so. */
|
|
96
|
-
function writeStudy(p, added,
|
|
110
|
+
/** Write a new study's README.md and plan.json, the registry, and the index; the lines that say so. */
|
|
111
|
+
function writeStudy(p, added, deps) {
|
|
97
112
|
const { study, registry } = added;
|
|
113
|
+
const { files } = deps;
|
|
98
114
|
const at = (...names) => callerPath(join(p.dir, REPRO_DIR, ...names));
|
|
99
115
|
files.writeAtomic(at(study.folder, README), text(studyReadme(study)));
|
|
116
|
+
files.writeAtomic(at(study.folder, PLAN_FILE), text(planText(planTemplate(study.kind, study.folder))));
|
|
100
117
|
files.writeAtomic(at(STUDIES_FILE), text(registryText(registry)));
|
|
101
|
-
writeIndex(p.dir, registry,
|
|
118
|
+
writeIndex(p.dir, registry, deps);
|
|
102
119
|
const repro = `${p.shown}/${REPRO_DIR}`;
|
|
103
120
|
return [
|
|
104
121
|
`created ${repro}/${study.folder}/${README}`,
|
|
122
|
+
`created ${repro}/${study.folder}/${PLAN_FILE}, the study's plan: its fields are there to fill in before the first run`,
|
|
105
123
|
`added ${study.id} to ${repro}/${STUDIES_FILE}: kind ${study.kind}, status ${study.status}, ${study.date}`,
|
|
106
124
|
`wrote the index of ${studiesCount(registry)} in ${repro}/${README}`,
|
|
107
125
|
`Next: write the study's one-sentence question in its row (\`question\`) and in its README.md. When it ends, set \`status\`, \`result\`, \`result_file\` and \`in_paper\` in its row, then run \`npx paperlint studies index ${p.shown}\`.`,
|
|
@@ -124,30 +142,43 @@ function runNew(p, a, deps) {
|
|
|
124
142
|
const folder = added.study.folder;
|
|
125
143
|
return deps.listDir(callerPath(join(p.dir, REPRO_DIR))).includes(folder)
|
|
126
144
|
? refuse(1, `${p.shown}/${REPRO_DIR}/${folder}/ already exists; it is never overwritten. Register it by hand, or remove it and run this again.`)
|
|
127
|
-
: writeStudy(p, added, deps
|
|
145
|
+
: writeStudy(p, added, deps);
|
|
128
146
|
}
|
|
129
147
|
/** The paper folder the command line names, or the refusal. */
|
|
130
148
|
function paperOf(a, deps) {
|
|
131
149
|
if (a.sub === undefined)
|
|
132
150
|
return refuse(2, `studies needs a subcommand: ${SUBS}`);
|
|
133
|
-
|
|
151
|
+
const sub = COMMANDS.get(a.sub);
|
|
152
|
+
if (sub === undefined)
|
|
134
153
|
return refuse(2, `unknown subcommand \`studies ${a.sub}\`: ${SUBS}`);
|
|
135
154
|
if (a.paperDir === undefined)
|
|
136
|
-
return refuse(2, `studies ${a.sub} needs the paper's folder: ${
|
|
155
|
+
return refuse(2, `studies ${a.sub} needs the paper's folder: ${sub.usage}`);
|
|
137
156
|
const dir = resolve(deps.cwd, a.paperDir);
|
|
138
157
|
const shown = relative(deps.cwd, dir) || ".";
|
|
139
158
|
return deps.files.isFile(callerPath(join(dir, STATUS_FILE)))
|
|
140
|
-
? { dir, shown }
|
|
159
|
+
? { dir, shown, run: sub.run }
|
|
141
160
|
: refuse(2, `${shown} is not a paper folder: it has no ${STATUS_FILE}`);
|
|
142
161
|
}
|
|
162
|
+
/** `gate`: the study's id, one argument, then the gate. */
|
|
163
|
+
const gateRun = (p, a, deps) => {
|
|
164
|
+
if (a.title === undefined)
|
|
165
|
+
return refuse(2, `studies gate needs the study's id: ${GATE_USAGE}`);
|
|
166
|
+
const [surplus] = a.extra;
|
|
167
|
+
if (surplus !== undefined)
|
|
168
|
+
return refuse(2, `studies gate takes the paper's folder and one id — \`${surplus}\` is one argument too many`);
|
|
169
|
+
const out = runGate(p.dir, p.shown, a.title, deps);
|
|
170
|
+
return out.ok ? out.lines : out.refusal;
|
|
171
|
+
};
|
|
172
|
+
/** Each subcommand: its usage line and its run. */
|
|
173
|
+
const COMMANDS = new Map([
|
|
174
|
+
["new", { usage: NEW_USAGE, run: runNew }],
|
|
175
|
+
["index", { usage: INDEX_USAGE, run: runIndex }],
|
|
176
|
+
["gate", { usage: GATE_USAGE, run: gateRun }],
|
|
177
|
+
]);
|
|
143
178
|
/** The run: 0 done, 1 refused by the paper's state, 2 refused by the command line. */
|
|
144
179
|
export function runStudies(a, deps) {
|
|
145
180
|
const p = paperOf(a, deps);
|
|
146
|
-
const out = isRefusal(p)
|
|
147
|
-
? p
|
|
148
|
-
: a.sub === "new"
|
|
149
|
-
? runNew(p, a, deps)
|
|
150
|
-
: runIndex(p, a, deps);
|
|
181
|
+
const out = isRefusal(p) ? p : p.run(p, a, deps);
|
|
151
182
|
if (isRefusal(out)) {
|
|
152
183
|
deps.err(out.line);
|
|
153
184
|
return out.code;
|
package/dist/studies.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"studies.js","sourceRoot":"","sources":["../src/studies.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"studies.js","sourceRoot":"","sources":["../src/studies.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type StudyDeps } from "./study-modes.ts";
|
|
2
|
+
import type { Committed, GitHistory } from "./ports/git-history.ts";
|
|
3
|
+
import { type StudyRun } from "./study-run.ts";
|
|
4
|
+
export interface GateDeps extends StudyDeps {
|
|
5
|
+
readonly git: GitHistory;
|
|
6
|
+
}
|
|
7
|
+
/** What a decision's committed state means for the run. */
|
|
8
|
+
export declare const gateLine: (id: string, file: string, c: Committed) => {
|
|
9
|
+
readonly open: boolean;
|
|
10
|
+
readonly line: string;
|
|
11
|
+
};
|
|
12
|
+
/** `studies gate`: 0 when the run may start, 1 with the reason when not. */
|
|
13
|
+
export declare function runGate(paper: string, shown: string, id: string, deps: GateDeps): StudyRun;
|
|
14
|
+
//# sourceMappingURL=study-gate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"study-gate.d.ts","sourceRoot":"","sources":["../src/study-gate.ts"],"names":[],"mappings":"AAYA,OAAO,EAIL,KAAK,SAAS,EACf,MAAM,kBAAkB,CAAC;AAI1B,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEpE,OAAO,EAIL,KAAK,QAAQ,EACd,MAAM,gBAAgB,CAAC;AAExB,MAAM,WAAW,QAAS,SAAQ,SAAS;IACzC,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAC;CAC1B;AAoBD,2DAA2D;AAC3D,eAAO,MAAM,QAAQ,GACnB,IAAI,MAAM,EACV,MAAM,MAAM,EACZ,GAAG,SAAS,KACX;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAMA,CAAC;AAwEnD,4EAA4E;AAC5E,wBAAgB,OAAO,CACrB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,QAAQ,GACb,QAAQ,CAmBV"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `paperlint studies gate <paper-dir> <id>` — may the study's run start? For a study decided before
|
|
3
|
+
* its run (the default mode), only once its decision file exists and is committed as it stands: exit 0
|
|
4
|
+
* with the commit and its date, else exit 1 saying why. A runner calls it first:
|
|
5
|
+
*
|
|
6
|
+
* npx paperlint studies gate papers/my-paper P1-S03 && ./run.sh
|
|
7
|
+
*
|
|
8
|
+
* An exploratory study has no gate: it exits 0 and says so. A study that declares no mode, names no
|
|
9
|
+
* decision file, or whose row names a folder that is not one inside `repro/`, is refused.
|
|
10
|
+
*/
|
|
11
|
+
import { join } from "node:path";
|
|
12
|
+
import { callerPath } from "./caller-path.js";
|
|
13
|
+
import { modeStudies, onDisk, } from "./study-modes.js";
|
|
14
|
+
import { REPRO_DIR } from "./domain/repro-layout.js";
|
|
15
|
+
import { decisionAsOutput } from "./domain/study-mode.js";
|
|
16
|
+
import { readableFolders, registryOf } from "./study-registry-rule.js";
|
|
17
|
+
import { refusal, refused, } from "./study-run.js";
|
|
18
|
+
/** The line of a committed state that holds the run back. */
|
|
19
|
+
const shutLine = (id, file, c) => {
|
|
20
|
+
switch (c.kind) {
|
|
21
|
+
case "changed":
|
|
22
|
+
return `${id}: the decision ${file} has changed since its last commit, ${c.commit}; the run waits for the decision as committed. Commit it, then run this again.`;
|
|
23
|
+
case "deleted":
|
|
24
|
+
return `${id}: the decision ${file} is not in HEAD: it was deleted in ${c.commit}; the run waits for a decision that stands. Restore it, commit it, then run this again.`;
|
|
25
|
+
case "not-committed":
|
|
26
|
+
return `${id}: the decision ${file} is not committed; the run waits for it. Write the decision there, commit it, then run this again.`;
|
|
27
|
+
case "unknown":
|
|
28
|
+
return `${id}: git could not say whether the decision ${file} is committed: ${c.why}.`;
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
/** What a decision's committed state means for the run. */
|
|
32
|
+
export const gateLine = (id, file, c) => c.kind === "committed"
|
|
33
|
+
? {
|
|
34
|
+
open: true,
|
|
35
|
+
line: `${id}: the decision ${file} is committed in ${c.commit} (${c.date}); the run may start.`,
|
|
36
|
+
}
|
|
37
|
+
: { open: false, line: shutLine(id, file, c) };
|
|
38
|
+
/**
|
|
39
|
+
* Why the decision cannot gate the run though it is named: its own outputs match it, or it is a
|
|
40
|
+
* directory (git answers for a directory with the last commit of anything under it); null when usable.
|
|
41
|
+
*/
|
|
42
|
+
const unusable = (paper, { id, folder }, mode, deps) => {
|
|
43
|
+
const file = mode.decision.file;
|
|
44
|
+
const glob = decisionAsOutput(folder, mode);
|
|
45
|
+
if (glob !== null)
|
|
46
|
+
return refusal(`${id}: its decision ${file} is matched by its output \`${glob}\`; a decision cannot be what its own run produces.`);
|
|
47
|
+
const on = onDisk(join(paper, file), deps);
|
|
48
|
+
return on === "directory" || on === "symbolic link"
|
|
49
|
+
? refusal(`${id}: its decision ${file} is a ${on}, not a file; the run cannot be gated on it. Name the decision file in \`mode.decision.file\`.`)
|
|
50
|
+
: null;
|
|
51
|
+
};
|
|
52
|
+
/** The gate of a decide-first study. */
|
|
53
|
+
const gateDecided = (paper, { id, folder }, mode, deps) => {
|
|
54
|
+
const file = mode.decision.file;
|
|
55
|
+
const blocked = unusable(paper, { id, folder }, mode, deps);
|
|
56
|
+
if (blocked !== null)
|
|
57
|
+
return refused(blocked);
|
|
58
|
+
const g = gateLine(id, file, deps.git.committed(callerPath(paper), callerPath(join(paper, file))));
|
|
59
|
+
return g.open ? { ok: true, lines: [g.line] } : refused(refusal(g.line));
|
|
60
|
+
};
|
|
61
|
+
/** The refusal when the row of `id` names a folder that is not one inside `repro/`; null when none does. */
|
|
62
|
+
const escapingRow = (paper, shown, id, deps) => {
|
|
63
|
+
const r = registryOf(paper, deps);
|
|
64
|
+
const readable = readableFolders(paper, deps);
|
|
65
|
+
const row = (r.kind === "read" ? r.registry.studies : []).find((x) => x.id === id && !readable(x.folder));
|
|
66
|
+
return row === undefined
|
|
67
|
+
? null
|
|
68
|
+
: refusal(`${id}: its row names the folder \`${row.folder}\`, which is not one folder inside ${shown}/${REPRO_DIR}/; nothing is read through it. Give the row its own folder's name.`);
|
|
69
|
+
};
|
|
70
|
+
/** The refusal of a study whose plan is still a draft: a mode decides nothing until its plan is ready. */
|
|
71
|
+
const draftRefusal = (id, s) => {
|
|
72
|
+
const names = s.empty.map((f) => `\`${f}\``).join(", ");
|
|
73
|
+
const verb = s.empty.length === 1 ? "is" : "are";
|
|
74
|
+
return refusal(`${id}: its ${s.plan} is a draft — ${names} ${verb} empty; the run waits for a ready plan. Fill it in, then run this again.`);
|
|
75
|
+
};
|
|
76
|
+
/** `studies gate`: 0 when the run may start, 1 with the reason when not. */
|
|
77
|
+
export function runGate(paper, shown, id, deps) {
|
|
78
|
+
const escaping = escapingRow(paper, shown, id, deps);
|
|
79
|
+
if (escaping !== null)
|
|
80
|
+
return refused(escaping);
|
|
81
|
+
const s = modeStudies(paper, deps).find((m) => m.row.id === id);
|
|
82
|
+
if (s === undefined)
|
|
83
|
+
return refused(refusal(`${id} declares no mode in ${shown}: no row of ${shown}/${REPRO_DIR}/studies.json with this id names a plan.json that parses with \`mode\`. Lint the paper (\`npx paperlint lint\`) to see why.`));
|
|
84
|
+
if (s.empty.length > 0)
|
|
85
|
+
return refused(draftRefusal(id, s));
|
|
86
|
+
return s.mode.kind === "decide_before_run"
|
|
87
|
+
? gateDecided(paper, s.row, s.mode, deps)
|
|
88
|
+
: {
|
|
89
|
+
ok: true,
|
|
90
|
+
lines: [
|
|
91
|
+
`${id} is exploratory (${s.mode.reason}): it has no gate, and its results are reported as exploratory.`,
|
|
92
|
+
],
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=study-gate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"study-gate.js","sourceRoot":"","sources":["../src/study-gate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { IndexInput, RegistryState } from "./domain/study-registry.ts";
|
|
2
|
+
import { type OrderDeps } from "./outputs-before-decision-rule.ts";
|
|
3
|
+
/** The plans and the histories of the paper folder `paper`, whose registry is `r`. */
|
|
4
|
+
export declare const indexInputOf: (paper: string, r: RegistryState, deps: OrderDeps) => IndexInput;
|
|
5
|
+
//# sourceMappingURL=study-index-input.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"study-index-input.d.ts","sourceRoot":"","sources":["../src/study-index-input.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC5E,OAAO,EAEL,KAAK,SAAS,EACf,MAAM,mCAAmC,CAAC;AAG3C,sFAAsF;AACtF,eAAO,MAAM,YAAY,GACvB,OAAO,MAAM,EACb,GAAG,aAAa,EAChB,MAAM,SAAS,KACd,UAKD,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What `paperlint studies index` and `studies new` generate the index from beyond the registry: each
|
|
3
|
+
* row's plan, and each decide-first study's history as git gives it now (src/domain/index-columns.ts).
|
|
4
|
+
*/
|
|
5
|
+
import { indexHistory } from "./domain/index-columns.js";
|
|
6
|
+
import { decideFirstStudies, } from "./outputs-before-decision-rule.js";
|
|
7
|
+
import { plansOf, readableFolders } from "./study-registry-rule.js";
|
|
8
|
+
/** The plans and the histories of the paper folder `paper`, whose registry is `r`. */
|
|
9
|
+
export const indexInputOf = (paper, r, deps) => ({
|
|
10
|
+
plans: plansOf(paper, r, deps, readableFolders(paper, deps)),
|
|
11
|
+
history: new Map(decideFirstStudies(paper, deps).map((s) => [s.id, indexHistory(s)])),
|
|
12
|
+
});
|
|
13
|
+
//# sourceMappingURL=study-index-input.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"study-index-input.js","sourceRoot":"","sources":["../src/study-index-input.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAEzD,OAAO,EACL,kBAAkB,GAEnB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAEpE,sFAAsF;AACtF,MAAM,CAAC,MAAM,YAAY,GAAG,CAC1B,KAAa,EACb,CAAgB,EAChB,IAAe,EACH,EAAE,CAAC,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,eAAe,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IAC5D,OAAO,EAAE,IAAI,GAAG,CACd,kBAAkB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CACpE;CACF,CAAC,CAAC"}
|