@taml/encoder
Version:
Convert ANSI escape sequences to TAML (Terminal ANSI Markup Language) tags
89 lines • 7.41 kB
JavaScript
import { applyAnsiSequence, createInitialAnsiState, getActiveStyleTags, tokenizeAnsiText, } from "./ansi-parser.js";
/**
* Escapes special characters in a string for TAML.
* @param text The input string.
* @returns The escaped string.
*/
function escapeText(text) {
return text
.replace(/&/g, "&") // First escape existing &
.replace(/</g, "&lt;") // Then escape existing <
.replace(/</g, "<"); // Finally escape remaining <
}
/**
* Encode ANSI escape sequences to TAML (Terminal ANSI Markup Language) tags
* @param ansiText Input text containing ANSI escape sequences
* @returns Text with ANSI sequences converted to TAML tags
*/
export function encode(ansiText) {
if (!ansiText) {
return "";
}
const tokens = tokenizeAnsiText(ansiText);
let result = "";
let currentState = createInitialAnsiState();
const tagStack = [];
for (const token of tokens) {
if (token.type === "text") {
// Add text content with current formatting
result += escapeText(token.content);
}
else if (token.type === "sequence" && token.sequence) {
const newState = applyAnsiSequence(currentState, token.sequence);
// Handle state changes
if (token.sequence.type === "reset") {
// Close all open tags when reset
while (tagStack.length > 0) {
const tag = tagStack.pop();
if (tag) {
result += `</${tag}>`;
}
}
currentState = newState;
}
else {
// Get the difference between old and new states
const oldTags = getActiveStyleTags(currentState);
const newTags = getActiveStyleTags(newState);
// Close tags that are no longer active
const tagsToClose = oldTags.filter((tag) => !newTags.includes(tag));
for (let i = tagStack.length - 1; i >= 0; i--) {
const tag = tagStack[i];
if (tag && tagsToClose.includes(tag)) {
// Close this tag and all tags after it
const closedTags = tagStack.splice(i);
for (let j = closedTags.length - 1; j >= 0; j--) {
const closedTag = closedTags[j];
if (closedTag) {
result += `</${closedTag}>`;
}
}
// Reopen tags that should still be active
const tagsToReopen = closedTags.filter((t) => t && newTags.includes(t));
for (const reopenTag of tagsToReopen) {
result += `<${reopenTag}>`;
tagStack.push(reopenTag);
}
break;
}
}
// Open new tags
const tagsToOpen = newTags.filter((tag) => !oldTags.includes(tag));
for (const tag of tagsToOpen) {
result += `<${tag}>`;
tagStack.push(tag);
}
currentState = newState;
}
}
}
// Close any remaining open tags at the end
while (tagStack.length > 0) {
const tag = tagStack.pop();
if (tag) {
result += `</${tag}>`;
}
}
return result;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW5jb2Rlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL2VuY29kZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNMLGlCQUFpQixFQUNqQixzQkFBc0IsRUFDdEIsa0JBQWtCLEVBQ2xCLGdCQUFnQixHQUNqQixNQUFNLGtCQUFrQixDQUFDO0FBRTFCOzs7O0dBSUc7QUFDSCxTQUFTLFVBQVUsQ0FBQyxJQUFZO0lBQzlCLE9BQU8sSUFBSTtTQUNSLE9BQU8sQ0FBQyxRQUFRLEVBQUUsV0FBVyxDQUFDLENBQUMsOEJBQThCO1NBQzdELE9BQU8sQ0FBQyxPQUFPLEVBQUUsVUFBVSxDQUFDLENBQUMsNEJBQTRCO1NBQ3pELE9BQU8sQ0FBQyxJQUFJLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQyw2QkFBNkI7QUFDekQsQ0FBQztBQUVEOzs7O0dBSUc7QUFDSCxNQUFNLFVBQVUsTUFBTSxDQUFDLFFBQWdCO0lBQ3JDLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztRQUNkLE9BQU8sRUFBRSxDQUFDO0lBQ1osQ0FBQztJQUVELE1BQU0sTUFBTSxHQUFHLGdCQUFnQixDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQzFDLElBQUksTUFBTSxHQUFHLEVBQUUsQ0FBQztJQUNoQixJQUFJLFlBQVksR0FBRyxzQkFBc0IsRUFBRSxDQUFDO0lBQzVDLE1BQU0sUUFBUSxHQUFhLEVBQUUsQ0FBQztJQUU5QixLQUFLLE1BQU0sS0FBSyxJQUFJLE1BQU0sRUFBRSxDQUFDO1FBQzNCLElBQUksS0FBSyxDQUFDLElBQUksS0FBSyxNQUFNLEVBQUUsQ0FBQztZQUMxQiwyQ0FBMkM7WUFDM0MsTUFBTSxJQUFJLFVBQVUsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDdEMsQ0FBQzthQUFNLElBQUksS0FBSyxDQUFDLElBQUksS0FBSyxVQUFVLElBQUksS0FBSyxDQUFDLFFBQVEsRUFBRSxDQUFDO1lBQ3ZELE1BQU0sUUFBUSxHQUFH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