@sema-agent/core
Version:
Stateless, task-oriented AI agent core
50 lines (49 loc) • 1.93 kB
JavaScript
export function detectFileEncoding(bytes) {
if (bytes.length >= 2 && bytes[0] === 0xff && bytes[1] === 0xfe)
return { encoding: "utf16le", hadBom: true };
if (bytes.length >= 3 && bytes[0] === 0xef && bytes[1] === 0xbb && bytes[2] === 0xbf)
return { encoding: "utf8", hadBom: true };
return { encoding: "utf8", hadBom: false };
}
function detectLineEndings(raw) {
let crlf = 0;
let lf = 0;
for (let i = 0; i < raw.length; i++) {
if (raw.charCodeAt(i) === 0x0a) {
if (i > 0 && raw.charCodeAt(i - 1) === 0x0d)
crlf++;
else
lf++;
}
}
return crlf > lf ? "CRLF" : "LF";
}
export function decodeTextBytes(bytes) {
const encoding = detectFileEncoding(bytes);
const body = encoding.hadBom ? bytes.subarray(encoding.encoding === "utf16le" ? 2 : 3) : bytes;
const raw = Buffer.from(body).toString(encoding.encoding);
const decoded = { text: raw.replaceAll("\r\n", "\n"), encoding, endings: detectLineEndings(raw) };
if (encoding.encoding === "utf16le" && body.length % 2 !== 0)
decoded.malformed = true;
return decoded;
}
export function encodeTextForFile(text, encoding, endings) {
const out = endings === "CRLF" ? text.replaceAll("\n", "\r\n") : text;
if (encoding.encoding === "utf16le") {
const body = Buffer.from(out, "utf16le");
return Buffer.concat([Buffer.from([0xff, 0xfe]), body]);
}
if (encoding.hadBom) {
return Buffer.concat([Buffer.from([0xef, 0xbb, 0xbf]), Buffer.from(out, "utf8")]);
}
return out;
}
export function normalizeEditText(s) {
return s.replaceAll("\r\n", "\n");
}
export function splitLeadingBom(text) {
return text.charCodeAt(0) === 0xfeff ? { hadBom: true, text: text.slice(1) } : { hadBom: false, text };
}
export function normalizeFileText(s) {
return normalizeEditText(splitLeadingBom(s).text);
}