sgr-parser
Version:
Parse escape sequence for console. (Especially for SGR)
298 lines (297 loc) • 11.1 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var CODE_LF = 0x0a;
var CODE_CR = 0x0d;
var CODE_ESC = 0x1b;
var CODE_0 = 0x30;
var CODE_9 = 0x39;
var CODE_SEMI = 0x3b;
var CODE_A = 0x41;
var CODE_K = 0x4b;
var CODE_S = 0x53;
var CODE_f = 0x66;
var CODE_m = 0x6d;
function isValidEscapeChar(c) {
// A-H
if (c >= CODE_A && c <= CODE_A + 7)
return true;
// J,K
if (c === CODE_A + 9 || c === CODE_A + 10)
return true;
// S,T
if (c === CODE_S || c === CODE_S + 1)
return true;
// f,m
if (c === CODE_f || c == CODE_m)
return true;
return false;
}
var TokenType;
(function (TokenType) {
TokenType[TokenType["Escape"] = 0] = "Escape";
TokenType[TokenType["String"] = 1] = "String";
TokenType[TokenType["Error"] = 2] = "Error";
})(TokenType = exports.TokenType || (exports.TokenType = {}));
var TokenState;
(function (TokenState) {
TokenState[TokenState["Normal"] = 0] = "Normal";
TokenState[TokenState["Escape"] = 1] = "Escape";
})(TokenState || (TokenState = {}));
var EscapeToken = /** @class */ (function () {
function EscapeToken(_options, _code) {
this._options = _options;
this._code = _code;
}
Object.defineProperty(EscapeToken.prototype, "tokenType", {
get: function () { return TokenType.Escape; },
enumerable: true,
configurable: true
});
Object.defineProperty(EscapeToken.prototype, "options", {
get: function () { return this._options; },
enumerable: true,
configurable: true
});
Object.defineProperty(EscapeToken.prototype, "code", {
get: function () { return this._code; },
enumerable: true,
configurable: true
});
return EscapeToken;
}());
exports.EscapeToken = EscapeToken;
var StringToken = /** @class */ (function () {
function StringToken(_str) {
this._str = _str;
}
Object.defineProperty(StringToken.prototype, "tokenType", {
get: function () { return TokenType.String; },
enumerable: true,
configurable: true
});
Object.defineProperty(StringToken.prototype, "str", {
get: function () { return this._str; },
enumerable: true,
configurable: true
});
return StringToken;
}());
exports.StringToken = StringToken;
var ErrorToken = /** @class */ (function () {
function ErrorToken(_str) {
this._str = _str;
}
Object.defineProperty(ErrorToken.prototype, "tokenType", {
get: function () { return TokenType.Error; },
enumerable: true,
configurable: true
});
Object.defineProperty(ErrorToken.prototype, "str", {
get: function () { return this._str; },
enumerable: true,
configurable: true
});
return ErrorToken;
}());
exports.ErrorToken = ErrorToken;
var Line = /** @class */ (function () {
function Line(_str, _classname, _newLine, _removeLine) {
this._str = _str;
this._classname = _classname;
this._newLine = _newLine;
this._removeLine = _removeLine;
}
Object.defineProperty(Line.prototype, "str", {
get: function () { return this._str; },
enumerable: true,
configurable: true
});
Object.defineProperty(Line.prototype, "classname", {
get: function () { return this._classname; },
enumerable: true,
configurable: true
});
Object.defineProperty(Line.prototype, "newLine", {
get: function () { return this._newLine; },
enumerable: true,
configurable: true
});
Object.defineProperty(Line.prototype, "removeLine", {
get: function () { return this._removeLine; },
enumerable: true,
configurable: true
});
return Line;
}());
exports.Line = Line;
var SGRParser = /** @class */ (function () {
function SGRParser(keepState, handleCR) {
this.keepState = keepState;
this.handleCR = handleCR;
this.classes = [];
this.newLine = false;
this.state = TokenState.Normal;
this.options = [];
}
SGRParser.prototype.parse = function (line) {
var _this = this;
var classes = this.classes.concat([]);
var newLine = this.newLine;
var ret = [];
this.tokenize(line).forEach(function (token) {
switch (token.tokenType) {
case TokenType.String:
case TokenType.Error:
var nextNewLine = false;
var lines = token.str.split("\n");
if (lines.length > 1 && lines[lines.length - 1].length === 0) {
lines.pop();
nextNewLine = true;
}
lines.forEach(function (str, index) {
ret.push(new Line(str, classes.join(" "), newLine, false));
newLine = true;
});
newLine = nextNewLine;
break;
case TokenType.Escape:
var escapeToken = token;
switch (escapeToken.code) {
case CODE_K:
if (escapeToken.options.length === 1 && escapeToken.options[0] === 2) {
ret.push(new Line("", "", newLine, !newLine));
newLine = false;
}
break;
case CODE_m:
if (escapeToken.options.length > 0) {
switch (escapeToken.options[0]) {
case 0:
classes = [];
break;
case 39:
classes = classes.filter(function (v) {
return v.indexOf("sgr-3") === 0 && v !== "sgr-3-m";
});
break;
case 49:
classes = _this.classes.filter(function (v) {
return v.indexOf("sgr-4") === 0 && v !== "sgr-4-m";
});
break;
case 38:
case 48:
classes.push("sgr-" + escapeToken.options.join("-") + "-m");
break;
default:
escapeToken.options.forEach(function (n) {
classes.push("sgr-" + n + "-m");
});
break;
}
}
break;
}
break;
}
});
if (this.keepState) {
this.classes = classes;
this.newLine = newLine;
}
return ret;
};
SGRParser.prototype.tokenize = function (line) {
if (!line || line.length === 0) {
return [];
}
var state = this.state;
var options = this.options.concat([]);
var index = 0;
var spos = 0;
var ret = [];
while (index < line.length) {
var c = line.charCodeAt(index++);
switch (state) {
case TokenState.Normal:
switch (c) {
case CODE_ESC:
if (spos !== index - 1) {
ret.push(new StringToken(line.substring(spos, index - 1)));
}
if (line.charAt(index) === '[') {
index++;
state = TokenState.Escape;
options = [];
}
else {
ret.push(new ErrorToken(""));
spos = index;
}
break;
case CODE_CR:
if (this.handleCR) {
if (spos !== index - 1) {
ret.push(new StringToken(line.substring(spos, index - 1)));
}
ret.push(new EscapeToken([2], CODE_K));
spos = index;
}
break;
default:
break;
}
break;
case TokenState.Escape:
if (c >= 0x30 && c <= 0x39) {
if (options.length === 0) {
options.push(c - 0x30);
}
else {
var n = options[options.length - 1];
if (n === -1) {
options[options.length - 1] = c - 0x30;
}
else {
options[options.length - 1] = n * 10 + (c - 0x30);
}
}
}
else if (c === CODE_SEMI) {
if (options.length === 0) {
ret.push(new ErrorToken("[;"));
state = TokenState.Normal;
}
else {
options.push(-1);
}
}
else if (isValidEscapeChar(c)) {
ret.push(new EscapeToken(options.filter(function (n) { return n >= 0; }), c));
state = TokenState.Normal;
}
else {
ret.push(new ErrorToken("[" + options.filter(function (n) { return n >= 0; }).join(";") + line.charAt(index - 1)));
state = TokenState.Normal;
}
if (state === TokenState.Normal) {
spos = index;
}
break;
}
}
if (state === TokenState.Normal && spos < line.length) {
ret.push(new StringToken(line.substring(spos, line.length)));
}
else if (!this.keepState) {
ret.push(new ErrorToken("[" + options.filter(function (n) { return n >= 0; }).join(";")));
}
if (this.keepState) {
this.state = state;
this.options = options;
}
return ret;
};
return SGRParser;
}());
exports.SGRParser = SGRParser;