Odin/src/odin/utils.cjs
2026-06-02 16:04:49 +01:00

86 lines
2.1 KiB
JavaScript

"use strict";
const fs = require("fs");
function parseArgs(argv) {
const parsed = {};
for (let index = 0; index < argv.length; index += 1) {
const arg = argv[index];
if (!arg.startsWith("--")) continue;
const key = arg.slice(2);
const next = argv[index + 1];
if (!next || next.startsWith("--")) {
parsed[key] = true;
} else {
parsed[key] = next;
index += 1;
}
}
return parsed;
}
function parseObjectDocument(label) {
return {
parse(value) {
if (!value || typeof value !== "object") {
throw new Error(`${label} must be an object`);
}
return value;
},
};
}
function positiveNumber(value, fallback) {
const number = Number(value);
return Number.isFinite(number) && number > 0 ? number : fallback;
}
function stableId(value) {
return String(value).toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
}
function clampNumber(value, min, max) {
if (!Number.isFinite(value)) return min;
return Math.max(min, Math.min(max, Math.round(value)));
}
function tailTextFile(filePath, maxBytes) {
const stat = fs.statSync(filePath);
const length = Math.min(stat.size, maxBytes);
const buffer = Buffer.alloc(length);
const fd = fs.openSync(filePath, "r");
try {
fs.readSync(fd, buffer, 0, length, stat.size - length);
} finally {
fs.closeSync(fd);
}
return buffer.toString("utf8");
}
function httpGet(url, timeoutMs) {
return new Promise((resolve, reject) => {
const req = require("http").get(url, { timeout: timeoutMs }, (res) => {
if ((res.statusCode || 0) >= 400) {
reject(new Error(`HTTP ${res.statusCode}`));
res.resume();
return;
}
const chunks = [];
res.on("data", (chunk) => chunks.push(chunk));
res.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
});
req.on("timeout", () => req.destroy(new Error("HTTP request timed out")));
req.on("error", reject);
});
}
module.exports = {
clampNumber,
httpGet,
parseArgs,
parseObjectDocument,
positiveNumber,
stableId,
tailTextFile,
};