@scientific-method/standard-checker 1.1.0 → 2.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.
|
@@ -6,6 +6,7 @@ import { isSuperseded } from "../evidence.js";
|
|
|
6
6
|
import { asList } from "../ids.js";
|
|
7
7
|
import { checkAddress, checkOffset } from "../locations.js";
|
|
8
8
|
import { locationRule } from "../standard.js";
|
|
9
|
+
import { parseScalar } from "../yaml.js";
|
|
9
10
|
/** Checks a finding's method, environment and locations. */
|
|
10
11
|
export function checkFinding(ctx, e) {
|
|
11
12
|
const { problem } = ctx;
|
|
@@ -121,6 +122,24 @@ export function checkExperiment(ctx, id, e, isSup) {
|
|
|
121
122
|
const builds = asList(meta.builds);
|
|
122
123
|
if (builds.length !== 1)
|
|
123
124
|
problem(file, "an experiment lists exactly one build", "ENTRY-TYPES-7");
|
|
125
|
+
// The standard's experiment entry lists the starting states: a save patch, a save, new-game,
|
|
126
|
+
// emulated-call or null, where a save or a patch is in saves/. A missing field is reported with
|
|
127
|
+
// the other required fields. Which save hashes the fixture needs depends on the form, so an
|
|
128
|
+
// unknown one gets no save hash problem. A path in saves/ names a file under it, so it has a
|
|
129
|
+
// name after saves/ and no empty, . or .. segment.
|
|
130
|
+
const state = meta.starting_state;
|
|
131
|
+
const savePath = typeof state === "string" &&
|
|
132
|
+
state.startsWith("saves/") &&
|
|
133
|
+
state
|
|
134
|
+
.split("/")
|
|
135
|
+
.slice(1)
|
|
136
|
+
.every((s) => s !== "" && s !== "." && s !== "..");
|
|
137
|
+
const fromSave = state === null || savePath;
|
|
138
|
+
if (state !== undefined && !fromSave && state !== "new-game" && state !== "emulated-call") {
|
|
139
|
+
// A string the front matter would read as another value, such as a quoted "null", is shown quoted.
|
|
140
|
+
const shown = typeof state === "string" && state !== "" && parseScalar(state) === state ? state : JSON.stringify(state);
|
|
141
|
+
problem(file, `starting_state ${shown} is none of the forms the standard defines: a save or save patch in saves/, new-game, emulated-call or null`);
|
|
142
|
+
}
|
|
124
143
|
const fixture = meta.fixture && join(specDir, "experiments", meta.fixture);
|
|
125
144
|
if (!fixture || !existsSync(fixture))
|
|
126
145
|
problem(file, `fixture ${meta.fixture} does not exist`);
|
|
@@ -132,13 +151,13 @@ export function checkExperiment(ctx, id, e, isSup) {
|
|
|
132
151
|
// Only a new game and an emulated call start without a save. starting_state null still has
|
|
133
152
|
// one: a save that cannot be committed, kept with the captures and found by its hash.
|
|
134
153
|
const save = fx.starting_state;
|
|
135
|
-
if (
|
|
154
|
+
if (fromSave && !save?.xxh3) {
|
|
136
155
|
const where = "gives the hash of the save its runs started from in starting_state.xxh3";
|
|
137
|
-
problem(fixture,
|
|
156
|
+
problem(fixture, state === null
|
|
138
157
|
? `${where}; starting_state null names a save kept with the captures, and an experiment that starts without a save has starting_state new-game or emulated-call`
|
|
139
158
|
: where);
|
|
140
159
|
}
|
|
141
|
-
if (
|
|
160
|
+
if (savePath && state.endsWith(".patch.json") && !save?.base_xxh3)
|
|
142
161
|
problem(fixture, "a patch fixture gives the base save's hash as well");
|
|
143
162
|
for (const key of ["xxh3", "base_xxh3"])
|
|
144
163
|
if (save?.[key] && !/^[0-9a-f]{32}$/.test(String(save[key])))
|
|
@@ -156,10 +175,8 @@ export function checkExperiment(ctx, id, e, isSup) {
|
|
|
156
175
|
problem(fixture, `is not valid JSON: ${err.message}`);
|
|
157
176
|
}
|
|
158
177
|
}
|
|
159
|
-
if (
|
|
160
|
-
|
|
161
|
-
!existsSync(join(specDir, "experiments", meta.starting_state)))
|
|
162
|
-
problem(file, `starting_state ${meta.starting_state} does not exist`);
|
|
178
|
+
if (savePath && !existsSync(join(specDir, "experiments", state)))
|
|
179
|
+
problem(file, `starting_state ${state} does not exist`);
|
|
163
180
|
// A recording is committed in recordings/, kept with the captures, or one of the build's files.
|
|
164
181
|
if (typeof meta.recording === "string" && meta.recording !== "") {
|
|
165
182
|
const rec = meta.recording;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scientific-method/standard-checker",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Checks a restoration's spec/, parity/ and deviations/ against version 1 of the dinorefurb documentation standard.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|