Files
CPLv4.0/mocks/scripts/retimeAllCharts.mjs
ISA d6fcf95795 feat(mocks): retime chart mocks to today; add global/all-slot scripts
Add retimeAnalogInputs.mjs (all slots, single slot, or path)
Add retimeAllCharts.mjs (recursive under chartsData)
Update package.json with npm scripts:
mocks:retime:ai (all analog slots)
mocks:retime:ai:slot (single slot via %SLOT%)
mocks:retime:all (entire chartsData tree)
Preserve relative deltas; set first entry to today (same time); DIA2 daily at 00:00
Skip files/arrays without parsable "t" timestamps
2025-09-03 11:45:44 +02:00

165 lines
4.3 KiB
JavaScript

#!/usr/bin/env node
/**
* Retime all chart JSON files under mocks/device-cgi-simulator/chartsData (recursively).
* For any JSON array where elements contain a 't' timestamp string in format 'YYYY-MM-DD HH:mm:ss',
* rebase timestamps so the first element's time-of-day is preserved but moved to today's date,
* and all other elements keep their original relative deltas.
*
* Usage:
* node ./mocks/scripts/retimeAllCharts.mjs [baseDir]
* Default baseDir: mocks/device-cgi-simulator/chartsData
*/
import fs from "node:fs/promises";
import path from "node:path";
import { fileURLToPath } from "node:url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const workspaceRoot = path.resolve(__dirname, "../..");
function pad(n) {
return String(n).padStart(2, "0");
}
function formatDate(d) {
const yyyy = d.getFullYear();
const MM = pad(d.getMonth() + 1);
const dd = pad(d.getDate());
const hh = pad(d.getHours());
const mm = pad(d.getMinutes());
const ss = pad(d.getSeconds());
return `${yyyy}-${MM}-${dd} ${hh}:${mm}:${ss}`;
}
function parseDateTime(str) {
const m =
typeof str === "string" &&
str.match(/(\d{4})-(\d{2})-(\d{2})\s+(\d{2}):(\d{2}):(\d{2})/);
if (!m) return null;
const [, y, mo, d, h, mi, s] = m.map(Number);
return new Date(y, mo - 1, d, h, mi, s, 0);
}
function withTodayDateAndTimeOf(baseTime) {
const today = new Date();
return new Date(
today.getFullYear(),
today.getMonth(),
today.getDate(),
baseTime.getHours(),
baseTime.getMinutes(),
baseTime.getSeconds(),
0
);
}
async function readJson(filePath) {
const raw = await fs.readFile(filePath, "utf-8");
return JSON.parse(raw);
}
async function writeJson(filePath, data) {
const content = JSON.stringify(data, null, 2);
await fs.writeFile(filePath, content + "\n", "utf-8");
}
async function retimeArrayWithT(arr) {
// Find first element with parsable 't'
let idx0 = -1;
let t0 = null;
for (let i = 0; i < arr.length; i++) {
const t = arr[i]?.t;
const d = parseDateTime(t);
if (d) {
idx0 = i;
t0 = d;
break;
}
}
if (idx0 === -1) return null; // nothing to retime
const newBase = withTodayDateAndTimeOf(t0);
const t0ms = t0.getTime();
const updated = arr.map((item) => {
if (!item || typeof item !== "object") return item;
if (!("t" in item)) return item;
const d = parseDateTime(item.t);
if (!d) return item;
const delta = t0ms - d.getTime();
const newDate = new Date(newBase.getTime() - delta);
return { ...item, t: formatDate(newDate) };
});
return updated;
}
async function processJsonFile(filePath) {
try {
const data = await readJson(filePath);
if (!Array.isArray(data) || data.length === 0) {
return { status: "skip", reason: "not an array or empty" };
}
const updated = await retimeArrayWithT(data);
if (!updated) {
return { status: "skip", reason: "no parsable t fields" };
}
await writeJson(filePath, updated);
return { status: "ok" };
} catch (e) {
return { status: "error", message: e.message };
}
}
async function walk(dir, visitor) {
const entries = await fs.readdir(dir, { withFileTypes: true });
for (const entry of entries) {
const p = path.join(dir, entry.name);
if (entry.isDirectory()) {
await walk(p, visitor);
} else if (entry.isFile() && p.toLowerCase().endsWith(".json")) {
await visitor(p);
}
}
}
async function main() {
const baseArg = process.argv[2];
const baseDir = path.resolve(
workspaceRoot,
baseArg || "mocks/device-cgi-simulator/chartsData"
);
let ok = 0,
skipped = 0,
errors = 0;
const rel = (p) => path.relative(workspaceRoot, p) || p;
try {
await walk(baseDir, async (file) => {
const res = await processJsonFile(file);
if (res.status === "ok") {
ok++;
console.log(`[ok] Updated ${rel(file)}`);
} else if (res.status === "skip") {
skipped++;
console.log(`[skip] ${rel(file)}: ${res.reason}`);
} else {
errors++;
console.log(`[error] ${rel(file)}: ${res.message}`);
}
});
} catch (err) {
console.error("Failed to retime charts:", err);
process.exitCode = 1;
return;
}
console.log(`\nDone. ok=${ok}, skipped=${skipped}, errors=${errors}`);
}
await main();