@hatterjiang/term-color-render 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -0
- package/index.js +126 -0
- package/index.ts +135 -0
- package/package.json +12 -0
package/README.md
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# term color render
|
|
2
|
+
|
|
3
|
+
```js
|
|
4
|
+
import {renderColor} from "./index";
|
|
5
|
+
|
|
6
|
+
console.log(renderColor('hello [red]red world[/red], [bold][green]bold and green text[/green][/bold]'));
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
Supported colors:
|
|
11
|
+
- `[red]red text[/red]`
|
|
12
|
+
- `[blue]blue text[/blue]`
|
|
13
|
+
- `[green]green text[/green]`
|
|
14
|
+
- `[yellow]yellow text[/yellow]`
|
|
15
|
+
- `[cyan]cyan text[/cyan]`
|
|
16
|
+
- `[pink]cyan text[/pink]`
|
|
17
|
+
- `[bold]bold text[/bold]`
|
|
18
|
+
- `[under]under text[/under]`
|
package/index.js
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
// index.ts
|
|
2
|
+
function parseColorTokens(message) {
|
|
3
|
+
const tokens = [];
|
|
4
|
+
if (message) {
|
|
5
|
+
let inColorStart = false;
|
|
6
|
+
let inColorEnd = false;
|
|
7
|
+
let chars = [];
|
|
8
|
+
const messageLength = message.length;
|
|
9
|
+
for (let i = 0; i < messageLength; i++) {
|
|
10
|
+
const c = message.charAt(i);
|
|
11
|
+
const nextC = i + 1 < messageLength ? message.charAt(i + 1) : null;
|
|
12
|
+
switch (c) {
|
|
13
|
+
case "\\":
|
|
14
|
+
if (nextC === null) {
|
|
15
|
+
chars.push(c);
|
|
16
|
+
} else {
|
|
17
|
+
chars.push(nextC);
|
|
18
|
+
i++;
|
|
19
|
+
}
|
|
20
|
+
break;
|
|
21
|
+
case "[":
|
|
22
|
+
if (inColorStart || inColorEnd) {
|
|
23
|
+
break;
|
|
24
|
+
} else if (nextC == "/") {
|
|
25
|
+
inColorEnd = true;
|
|
26
|
+
i++;
|
|
27
|
+
} else {
|
|
28
|
+
inColorStart = true;
|
|
29
|
+
}
|
|
30
|
+
if (chars.length > 0) {
|
|
31
|
+
tokens.push({
|
|
32
|
+
type: "text",
|
|
33
|
+
content: chars.join("")
|
|
34
|
+
});
|
|
35
|
+
chars = [];
|
|
36
|
+
}
|
|
37
|
+
break;
|
|
38
|
+
case "]":
|
|
39
|
+
if (inColorStart || inColorEnd) {
|
|
40
|
+
if (chars.length > 0) {
|
|
41
|
+
tokens.push({
|
|
42
|
+
type: "color",
|
|
43
|
+
colorStart: inColorStart,
|
|
44
|
+
color: chars.join("")
|
|
45
|
+
});
|
|
46
|
+
chars = [];
|
|
47
|
+
}
|
|
48
|
+
inColorStart = false;
|
|
49
|
+
inColorEnd = false;
|
|
50
|
+
} else {
|
|
51
|
+
chars.push(c);
|
|
52
|
+
}
|
|
53
|
+
break;
|
|
54
|
+
default:
|
|
55
|
+
chars.push(c);
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const inColor = inColorStart || inColorEnd;
|
|
60
|
+
if (chars.length > 0 && !inColor) {
|
|
61
|
+
tokens.push({
|
|
62
|
+
type: "text",
|
|
63
|
+
content: chars.join("")
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return tokens;
|
|
68
|
+
}
|
|
69
|
+
var COLOR_MAP = {
|
|
70
|
+
blink: "5",
|
|
71
|
+
bold: "1",
|
|
72
|
+
under: "4",
|
|
73
|
+
red: "31",
|
|
74
|
+
green: "32",
|
|
75
|
+
yellow: "33",
|
|
76
|
+
blue: "34",
|
|
77
|
+
pink: "35",
|
|
78
|
+
cyan: "36"
|
|
79
|
+
};
|
|
80
|
+
function renderColorTokens(tokens) {
|
|
81
|
+
const text = [];
|
|
82
|
+
const colorMapStack = /* @__PURE__ */ new Map();
|
|
83
|
+
for (const token of tokens) {
|
|
84
|
+
if (token.type === "color") {
|
|
85
|
+
const color = token.color;
|
|
86
|
+
if (color) {
|
|
87
|
+
const colorCode = COLOR_MAP[color];
|
|
88
|
+
if (!colorCode) {
|
|
89
|
+
text.push(`[${token.colorStart ? "" : "/"}${color}]`);
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
const colorStack = colorMapStack.get(color) ?? [];
|
|
93
|
+
if (colorStack.length == 0) {
|
|
94
|
+
colorMapStack.set(color, colorStack);
|
|
95
|
+
}
|
|
96
|
+
if (token.colorStart) {
|
|
97
|
+
colorStack.push(1);
|
|
98
|
+
} else {
|
|
99
|
+
colorStack.pop();
|
|
100
|
+
text.push("\x1B[0m");
|
|
101
|
+
}
|
|
102
|
+
const colors = [];
|
|
103
|
+
for (const [color2, colorStack2] of colorMapStack) {
|
|
104
|
+
if (colorStack2.length > 0) {
|
|
105
|
+
colors.push(colorCode);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (colors.length > 0) {
|
|
109
|
+
text.push(`\x1B[${colors.join(";")}m`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
} else {
|
|
113
|
+
if (token.content) {
|
|
114
|
+
text.push(token.content);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
text.push("\x1B[0m");
|
|
119
|
+
return text.join("");
|
|
120
|
+
}
|
|
121
|
+
function renderColor(message) {
|
|
122
|
+
return renderColorTokens(parseColorTokens(message));
|
|
123
|
+
}
|
|
124
|
+
export {
|
|
125
|
+
renderColor
|
|
126
|
+
};
|
package/index.ts
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
interface ColorToken {
|
|
2
|
+
type: "color" | "text";
|
|
3
|
+
content?: string;
|
|
4
|
+
colorStart?: boolean;
|
|
5
|
+
color?: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function parseColorTokens(message: string): ColorToken[] {
|
|
9
|
+
const tokens: ColorToken[] = [];
|
|
10
|
+
if (message) {
|
|
11
|
+
let inColorStart = false;
|
|
12
|
+
let inColorEnd = false;
|
|
13
|
+
let chars: string[] = [];
|
|
14
|
+
const messageLength = message.length;
|
|
15
|
+
for (let i = 0; i < messageLength; i++) {
|
|
16
|
+
const c = message.charAt(i);
|
|
17
|
+
const nextC = (i + 1) < messageLength
|
|
18
|
+
? message.charAt(i + 1)
|
|
19
|
+
: null;
|
|
20
|
+
switch (c) {
|
|
21
|
+
case "\\":
|
|
22
|
+
if (nextC === null) {
|
|
23
|
+
chars.push(c);
|
|
24
|
+
} else {
|
|
25
|
+
chars.push(nextC);
|
|
26
|
+
i++;
|
|
27
|
+
}
|
|
28
|
+
break;
|
|
29
|
+
case "[":
|
|
30
|
+
if (inColorStart || inColorEnd) {
|
|
31
|
+
// SHOULD NOT HAPPEN
|
|
32
|
+
break;
|
|
33
|
+
} else if (nextC == "/") {
|
|
34
|
+
inColorEnd = true;
|
|
35
|
+
i++;
|
|
36
|
+
} else {
|
|
37
|
+
inColorStart = true;
|
|
38
|
+
}
|
|
39
|
+
if (chars.length > 0) {
|
|
40
|
+
tokens.push({
|
|
41
|
+
type: "text",
|
|
42
|
+
content: chars.join(""),
|
|
43
|
+
});
|
|
44
|
+
chars = [];
|
|
45
|
+
}
|
|
46
|
+
break;
|
|
47
|
+
case "]":
|
|
48
|
+
if (inColorStart || inColorEnd) {
|
|
49
|
+
if (chars.length > 0) {
|
|
50
|
+
tokens.push({
|
|
51
|
+
type: "color",
|
|
52
|
+
colorStart: inColorStart,
|
|
53
|
+
color: chars.join(""),
|
|
54
|
+
});
|
|
55
|
+
chars = [];
|
|
56
|
+
}
|
|
57
|
+
inColorStart = false;
|
|
58
|
+
inColorEnd = false;
|
|
59
|
+
} else {
|
|
60
|
+
chars.push(c);
|
|
61
|
+
}
|
|
62
|
+
break;
|
|
63
|
+
default:
|
|
64
|
+
chars.push(c);
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const inColor = inColorStart || inColorEnd;
|
|
69
|
+
if (chars.length > 0 && !inColor) {
|
|
70
|
+
tokens.push({
|
|
71
|
+
type: "text",
|
|
72
|
+
content: chars.join(""),
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return tokens;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const COLOR_MAP: Record<string, string> = {
|
|
80
|
+
blink: "5",
|
|
81
|
+
bold: "1",
|
|
82
|
+
under: "4",
|
|
83
|
+
red: "31",
|
|
84
|
+
green: "32",
|
|
85
|
+
yellow: "33",
|
|
86
|
+
blue: "34",
|
|
87
|
+
pink: "35",
|
|
88
|
+
cyan: "36",
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
function renderColorTokens(tokens: ColorToken[]): string {
|
|
92
|
+
const text: string[] = [];
|
|
93
|
+
const colorMapStack = new Map<string, number[]>();
|
|
94
|
+
for (const token of tokens) {
|
|
95
|
+
if (token.type === "color") {
|
|
96
|
+
const color = token.color;
|
|
97
|
+
if (color) {
|
|
98
|
+
const colorCode = COLOR_MAP[color];
|
|
99
|
+
if (!colorCode) {
|
|
100
|
+
text.push(`[${token.colorStart ? "" : "/"}${color}]`);
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
const colorStack = colorMapStack.get(color) ?? [];
|
|
104
|
+
if (colorStack.length == 0) {
|
|
105
|
+
colorMapStack.set(color, colorStack);
|
|
106
|
+
}
|
|
107
|
+
if (token.colorStart) {
|
|
108
|
+
colorStack.push(1);
|
|
109
|
+
} else {
|
|
110
|
+
colorStack.pop();
|
|
111
|
+
text.push("\x1b[0m");
|
|
112
|
+
}
|
|
113
|
+
const colors: string[] = [];
|
|
114
|
+
for (const [color, colorStack] of colorMapStack) {
|
|
115
|
+
if (colorStack.length > 0) {
|
|
116
|
+
colors.push(colorCode);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (colors.length > 0) {
|
|
120
|
+
text.push(`\x1b[${colors.join(";")}m`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
} else {
|
|
124
|
+
if (token.content) {
|
|
125
|
+
text.push(token.content);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
text.push("\x1b[0m"); // FINALLY END ALL COLOR
|
|
130
|
+
return text.join("");
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export function renderColor(message: string): string {
|
|
134
|
+
return renderColorTokens(parseColorTokens(message));
|
|
135
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hatterjiang/term-color-render",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Render color for term use syntax like [red]text[/red]",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "hatterjiang",
|
|
7
|
+
"type": "commonjs",
|
|
8
|
+
"main": "index.ts",
|
|
9
|
+
"scripts": {
|
|
10
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
11
|
+
}
|
|
12
|
+
}
|