-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrun-validate.mjs
More file actions
117 lines (104 loc) · 3.59 KB
/
run-validate.mjs
File metadata and controls
117 lines (104 loc) · 3.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#!/usr/bin/env node
/**
* Run task validation from the terminal. Uses the operation log by default:
* reads logs/user_actions.log, replays operations (validate/replay), then
* runs the selected task validator.
*
* Usage:
* node run-validate.mjs # log -> replay -> validate (default task)
* TASK=equilateral-triangle node run-validate.mjs
* TASK=parallel-lines node run-validate.mjs
* node run-validate.mjs snapshot.json # validate snapshot file
* node run-validate.mjs - < snapshot.json # validate from stdin (explicit -)
*
* Tasks: line-and-points (default) | equilateral-triangle | parallel-lines |
* prove-opposite-rays | prove-perpendicular-bisector
* LOG_FILE=path/to.log to override log path.
* Exit code: 0 = valid, 1 = invalid or error.
*/
import { readFileSync, existsSync } from 'fs';
import { resolve, dirname } from 'path';
import { createRequire } from 'module';
import { fileURLToPath } from 'url';
const __dirname = dirname(fileURLToPath(import.meta.url));
const require = createRequire(import.meta.url);
const DEFAULT_LOG_FILE = resolve(process.cwd(), 'logs', 'user_actions.log');
const replay = require('./validate/replay.js');
const tasks = require('./validate/tasks.js');
const { formatProofStep } = require('./validate/format-proof-steps.js');
const PROOF_TASKS = new Set(['prove-opposite-rays', 'prove-perpendicular-bisector']);
function readSnapshotFromFile(path) {
const fullPath = resolve(process.cwd(), path);
if (!existsSync(fullPath)) {
console.error('File not found:', fullPath);
process.exit(1);
}
return JSON.parse(readFileSync(fullPath, 'utf8'));
}
function readStdin() {
return new Promise((resolveStdin, reject) => {
const chunks = [];
process.stdin.setEncoding('utf8');
process.stdin.on('data', (chunk) => chunks.push(chunk));
process.stdin.on('end', () => {
const text = chunks.join('').trim();
if (!text) {
reject(new Error('No snapshot provided. Pass a file path or pipe JSON to stdin.'));
return;
}
try {
resolveStdin(JSON.parse(text));
} catch (e) {
reject(new Error('Invalid JSON: ' + e.message));
}
});
process.stdin.on('error', reject);
});
}
async function main() {
const fileArg = process.argv[2];
const taskId = process.env.TASK || 'line-and-points';
let snapshot;
let proofSteps;
let taskStatement;
if (fileArg && fileArg !== '-') {
snapshot = readSnapshotFromFile(fileArg);
proofSteps = undefined;
taskStatement = undefined;
} else if (fileArg === '-') {
snapshot = await readStdin();
proofSteps = undefined;
taskStatement = undefined;
} else {
const logPath = process.env.LOG_FILE ? resolve(process.cwd(), process.env.LOG_FILE) : DEFAULT_LOG_FILE;
try {
if (PROOF_TASKS.has(taskId)) {
const parsed = replay.parseLogFile(logPath);
snapshot = parsed.snapshot;
proofSteps = parsed.proofSteps;
taskStatement = undefined;
} else {
snapshot = replay.replayLogToSnapshot(logPath);
proofSteps = undefined;
taskStatement = undefined;
}
} catch (e) {
console.error(e.message);
process.exit(1);
}
}
if (proofSteps?.length) {
console.log('Proof steps:');
proofSteps.forEach((step, i) => {
console.log(' ' + formatProofStep(step, i));
});
console.log('');
}
const result = tasks.runTask(taskId, snapshot, { proofSteps, taskStatement });
console.log(result.message);
process.exit(result.valid ? 0 : 1);
}
main().catch((err) => {
console.error(err.message);
process.exit(1);
});