@reliverse/relico 1.0.1 → 1.1.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 +43 -1
- package/bin/main.d.ts +124 -0
- package/bin/main.js +369 -0
- package/package.json +42 -69
- package/dist-npm/main.d.ts +0 -79
- package/dist-npm/main.js +0 -269
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
</a>
|
|
12
12
|
</p>
|
|
13
13
|
|
|
14
|
-
**@reliverse/relico is
|
|
14
|
+
**@reliverse/relico is an accessible and modern terminal color formatting library** that provides a type-safe and flexible way to add colors and styles to your command-line output. Built with TypeScript and TypeBox for enhanced reliability and developer experience.
|
|
15
15
|
|
|
16
16
|
## Installation
|
|
17
17
|
|
|
@@ -19,6 +19,48 @@
|
|
|
19
19
|
bun add @reliverse/relico # Replace "bun" with npm, pnpm, or yarn if desired
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
+
**Configure `relico.config.ts`**:
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
import { defineConfig } from "@reliverse/relico";
|
|
26
|
+
|
|
27
|
+
export default defineConfig({
|
|
28
|
+
// Set the color level: 3 for truecolor
|
|
29
|
+
colorLevel: 3,
|
|
30
|
+
// Choose the theme: "primary" or "secondary"
|
|
31
|
+
theme: "secondary",
|
|
32
|
+
// Override specific colors
|
|
33
|
+
// Use Intellisense to see the available colors
|
|
34
|
+
customColors: {
|
|
35
|
+
blue: ["#5f87ff", "#5f87ff"],
|
|
36
|
+
red: ["#ff5555", "#ff0000"],
|
|
37
|
+
green: ["#00ff00", "#00cc00"],
|
|
38
|
+
// Note: The following text formatting
|
|
39
|
+
// colors can be defined only via ANSI:
|
|
40
|
+
// reset: ["\x1b[0m", "\x1b[0m"],
|
|
41
|
+
// bold: ["\x1b[1m", "\x1b[22m", "\x1b[22m\x1b[1m"],
|
|
42
|
+
// dim: ["\x1b[2m", "\x1b[22m", "\x1b[22m\x1b[2m"],
|
|
43
|
+
// italic: ["\x1b[3m", "\x1b[23m"],
|
|
44
|
+
// underline: ["\x1b[4m", "\x1b[24m"],
|
|
45
|
+
// inverse: ["\x1b[7m", "\x1b[27m"],
|
|
46
|
+
// hidden: ["\x1b[8m", "\x1b[28m"],
|
|
47
|
+
// strikethrough: ["\x1b[9m", "\x1b[29m"],
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**To load config (example)**:
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
// Initialize user config, so you override any relico's default settings
|
|
56
|
+
function main() {
|
|
57
|
+
console.log(re.blue("Loading user config..."));
|
|
58
|
+
await initUserConfig();
|
|
59
|
+
console.log(re.blue("If this blue log looks different than line above, then config is loaded successfully. Yay! 🎉"));
|
|
60
|
+
}
|
|
61
|
+
main();
|
|
62
|
+
```
|
|
63
|
+
|
|
22
64
|
## Key Features
|
|
23
65
|
|
|
24
66
|
- **Smart Terminal Detection**: Automatically detects terminal type and color support level
|
package/bin/main.d.ts
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/** A color definition: [primary, secondary]. */
|
|
2
|
+
export type ColorDefinition = [string, string];
|
|
3
|
+
/** A list of default color keys. */
|
|
4
|
+
export declare const defaultColorKeys: readonly ["reset", "bold", "dim", "italic", "underline", "inverse", "hidden", "strikethrough", "black", "red", "green", "yellow", "blue", "magenta", "cyan", "white", "gray", "bgBlack", "bgRed", "bgGreen", "bgYellow", "bgBlue", "bgMagenta", "bgCyan", "bgWhite", "blackBright", "redBright", "greenBright", "yellowBright", "blueBright", "magentaBright", "cyanBright", "whiteBright", "bgBlackBright", "bgRedBright", "bgGreenBright", "bgYellowBright", "bgBlueBright", "bgMagentaBright", "bgCyanBright", "bgWhiteBright"];
|
|
5
|
+
/** Union of all default color keys */
|
|
6
|
+
export type DefaultColorKeys = (typeof defaultColorKeys)[number];
|
|
7
|
+
/**
|
|
8
|
+
* Format keys that must NOT be overridden by the user.
|
|
9
|
+
* We'll exclude them from IntelliSense and also skip them at runtime.
|
|
10
|
+
*/
|
|
11
|
+
type RestrictedKeys = "reset" | "bold" | "dim" | "italic" | "underline" | "inverse" | "hidden" | "strikethrough";
|
|
12
|
+
/** All the keys user is allowed to override */
|
|
13
|
+
type OverridableColorKeys = Exclude<DefaultColorKeys, RestrictedKeys>;
|
|
14
|
+
/** A map of user-overridable color definitions (no format keys) */
|
|
15
|
+
export type OverridableColorMap = Partial<Record<OverridableColorKeys, ColorDefinition>>;
|
|
16
|
+
/**
|
|
17
|
+
* `relico.config.ts` configuration options.
|
|
18
|
+
* Note: `customColors` is restricted to OverridableColorMap.
|
|
19
|
+
*/
|
|
20
|
+
export type RelicoConfig = {
|
|
21
|
+
/**
|
|
22
|
+
* Determines which ANSI mode is used:
|
|
23
|
+
* - 0: no color
|
|
24
|
+
* - 1: basic ANSI (8 colors)
|
|
25
|
+
* - 2: 256 color palette
|
|
26
|
+
* - 3: 24-bit truecolor (default)
|
|
27
|
+
*/
|
|
28
|
+
colorLevel?: 0 | 1 | 2 | 3;
|
|
29
|
+
/**
|
|
30
|
+
* Theme to use for color definitions.
|
|
31
|
+
* - "primary": primary theme (default)
|
|
32
|
+
* - "secondary": secondary theme
|
|
33
|
+
*/
|
|
34
|
+
theme?: "primary" | "secondary";
|
|
35
|
+
/**
|
|
36
|
+
* Custom color definitions.
|
|
37
|
+
* - Theming: ["primary", "secondary"]
|
|
38
|
+
*/
|
|
39
|
+
customColors?: OverridableColorMap;
|
|
40
|
+
};
|
|
41
|
+
export type IRelicoColors = {
|
|
42
|
+
reset(text: string | number): string;
|
|
43
|
+
bold(text: string | number): string;
|
|
44
|
+
dim(text: string | number): string;
|
|
45
|
+
italic(text: string | number): string;
|
|
46
|
+
underline(text: string | number): string;
|
|
47
|
+
inverse(text: string | number): string;
|
|
48
|
+
hidden(text: string | number): string;
|
|
49
|
+
strikethrough(text: string | number): string;
|
|
50
|
+
black(text: string | number): string;
|
|
51
|
+
red(text: string | number): string;
|
|
52
|
+
green(text: string | number): string;
|
|
53
|
+
yellow(text: string | number): string;
|
|
54
|
+
blue(text: string | number): string;
|
|
55
|
+
magenta(text: string | number): string;
|
|
56
|
+
cyan(text: string | number): string;
|
|
57
|
+
white(text: string | number): string;
|
|
58
|
+
gray(text: string | number): string;
|
|
59
|
+
bgBlack(text: string | number): string;
|
|
60
|
+
bgRed(text: string | number): string;
|
|
61
|
+
bgGreen(text: string | number): string;
|
|
62
|
+
bgYellow(text: string | number): string;
|
|
63
|
+
bgBlue(text: string | number): string;
|
|
64
|
+
bgMagenta(text: string | number): string;
|
|
65
|
+
bgCyan(text: string | number): string;
|
|
66
|
+
bgWhite(text: string | number): string;
|
|
67
|
+
blackBright(text: string | number): string;
|
|
68
|
+
redBright(text: string | number): string;
|
|
69
|
+
greenBright(text: string | number): string;
|
|
70
|
+
yellowBright(text: string | number): string;
|
|
71
|
+
blueBright(text: string | number): string;
|
|
72
|
+
magentaBright(text: string | number): string;
|
|
73
|
+
cyanBright(text: string | number): string;
|
|
74
|
+
whiteBright(text: string | number): string;
|
|
75
|
+
bgBlackBright(text: string | number): string;
|
|
76
|
+
bgRedBright(text: string | number): string;
|
|
77
|
+
bgGreenBright(text: string | number): string;
|
|
78
|
+
bgYellowBright(text: string | number): string;
|
|
79
|
+
bgBlueBright(text: string | number): string;
|
|
80
|
+
bgMagentaBright(text: string | number): string;
|
|
81
|
+
bgCyanBright(text: string | number): string;
|
|
82
|
+
bgWhiteBright(text: string | number): string;
|
|
83
|
+
[k: string]: (text: string | number) => string;
|
|
84
|
+
};
|
|
85
|
+
export declare const re: IRelicoColors;
|
|
86
|
+
/**
|
|
87
|
+
* Configures the library with a partial or complete
|
|
88
|
+
* `RelicoConfig`. Invalid fields are just ignored.
|
|
89
|
+
*/
|
|
90
|
+
export declare function configure(userInput: unknown): void;
|
|
91
|
+
/** Returns a color function by name (or `reset` or identity if not found). */
|
|
92
|
+
export declare function getColor(name: string): (text: string | number) => string;
|
|
93
|
+
/** Colorizes text with a color function. */
|
|
94
|
+
export declare function colorize(name: string, text: string | number): string;
|
|
95
|
+
/** Sets the color level (0=none, 1=basic, 2=256, 3=truecolor). */
|
|
96
|
+
export declare function setColorLevel(level: 0 | 1 | 2 | 3): void;
|
|
97
|
+
/** Returns a custom "rgb" color function if level is truecolor, otherwise identity. */
|
|
98
|
+
export declare function rgb(r: number, g: number, b: number): (text: string | number) => string;
|
|
99
|
+
export type ColorSupport = {
|
|
100
|
+
isColorSupported: boolean;
|
|
101
|
+
isForced: boolean;
|
|
102
|
+
isDisabled: boolean;
|
|
103
|
+
terminalName: string;
|
|
104
|
+
};
|
|
105
|
+
export declare const colorSupport: ColorSupport;
|
|
106
|
+
export declare function initUserConfig(): Promise<void>;
|
|
107
|
+
/**
|
|
108
|
+
* Provides type safety and IntelliSense for user configuration.
|
|
109
|
+
* Example usage in `relico.config.ts`:
|
|
110
|
+
* ```ts
|
|
111
|
+
* import { defineConfig } from "@reliverse/relico-cfg";
|
|
112
|
+
* export default defineConfig({
|
|
113
|
+
* colorLevel: 3,
|
|
114
|
+
* theme: "secondary",
|
|
115
|
+
* customColors: {
|
|
116
|
+
* red: ["#f00", "#c00"],
|
|
117
|
+
* blue: ["#0af", "#08f"],
|
|
118
|
+
* green: ["#00ff00", "#00cc00"],
|
|
119
|
+
* },
|
|
120
|
+
* });
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
123
|
+
export declare function defineConfig(cfg: RelicoConfig): RelicoConfig;
|
|
124
|
+
export {};
|
package/bin/main.js
ADDED
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
import { getCurrentTerminalName } from "@reliverse/runtime";
|
|
2
|
+
import { env, isWindows } from "@reliverse/runtime";
|
|
3
|
+
import { loadConfig } from "c12";
|
|
4
|
+
export const defaultColorKeys = [
|
|
5
|
+
"reset",
|
|
6
|
+
"bold",
|
|
7
|
+
"dim",
|
|
8
|
+
"italic",
|
|
9
|
+
"underline",
|
|
10
|
+
"inverse",
|
|
11
|
+
"hidden",
|
|
12
|
+
"strikethrough",
|
|
13
|
+
"black",
|
|
14
|
+
"red",
|
|
15
|
+
"green",
|
|
16
|
+
"yellow",
|
|
17
|
+
"blue",
|
|
18
|
+
"magenta",
|
|
19
|
+
"cyan",
|
|
20
|
+
"white",
|
|
21
|
+
"gray",
|
|
22
|
+
"bgBlack",
|
|
23
|
+
"bgRed",
|
|
24
|
+
"bgGreen",
|
|
25
|
+
"bgYellow",
|
|
26
|
+
"bgBlue",
|
|
27
|
+
"bgMagenta",
|
|
28
|
+
"bgCyan",
|
|
29
|
+
"bgWhite",
|
|
30
|
+
"blackBright",
|
|
31
|
+
"redBright",
|
|
32
|
+
"greenBright",
|
|
33
|
+
"yellowBright",
|
|
34
|
+
"blueBright",
|
|
35
|
+
"magentaBright",
|
|
36
|
+
"cyanBright",
|
|
37
|
+
"whiteBright",
|
|
38
|
+
"bgBlackBright",
|
|
39
|
+
"bgRedBright",
|
|
40
|
+
"bgGreenBright",
|
|
41
|
+
"bgYellowBright",
|
|
42
|
+
"bgBlueBright",
|
|
43
|
+
"bgMagentaBright",
|
|
44
|
+
"bgCyanBright",
|
|
45
|
+
"bgWhiteBright"
|
|
46
|
+
];
|
|
47
|
+
const argv = typeof process === "undefined" ? [] : process.argv;
|
|
48
|
+
const isDisabled = "NO_COLOR" in env || argv.includes("--no-color");
|
|
49
|
+
const isForced = "FORCE_COLOR" in env || argv.includes("--color");
|
|
50
|
+
const isCI = "CI" in env && ("GITHUB_ACTIONS" in env || "GITLAB_CI" in env || "CIRCLECI" in env);
|
|
51
|
+
const isCompatibleTerminal = typeof process !== "undefined" && Boolean(process.stdout) && Boolean(process.stdout.isTTY) && env.TERM !== "dumb";
|
|
52
|
+
const colorterm = (env.COLORTERM ?? "").toLowerCase();
|
|
53
|
+
const supportsTrueColor = colorterm === "truecolor" || colorterm === "24bit";
|
|
54
|
+
function detectColorLevel() {
|
|
55
|
+
if (isDisabled) return 0;
|
|
56
|
+
if (isForced) return 3;
|
|
57
|
+
if (supportsTrueColor) return 3;
|
|
58
|
+
if (isWindows) return 2;
|
|
59
|
+
if (isCI) return 2;
|
|
60
|
+
if (isCompatibleTerminal) return 2;
|
|
61
|
+
return 0;
|
|
62
|
+
}
|
|
63
|
+
const baseColors = {
|
|
64
|
+
// Text formatting
|
|
65
|
+
reset: ["\x1B[0m", "\x1B[0m"],
|
|
66
|
+
bold: ["\x1B[1m", "\x1B[22m"],
|
|
67
|
+
dim: ["\x1B[2m", "\x1B[22m"],
|
|
68
|
+
italic: ["\x1B[3m", "\x1B[23m"],
|
|
69
|
+
underline: ["\x1B[4m", "\x1B[24m"],
|
|
70
|
+
inverse: ["\x1B[7m", "\x1B[27m"],
|
|
71
|
+
hidden: ["\x1B[8m", "\x1B[28m"],
|
|
72
|
+
strikethrough: ["\x1B[9m", "\x1B[29m"],
|
|
73
|
+
// Foreground colors
|
|
74
|
+
black: ["#000000", "#000000"],
|
|
75
|
+
red: ["#ff5555", "#ff0000"],
|
|
76
|
+
green: ["#00ff00", "#00ff00"],
|
|
77
|
+
yellow: ["#ffff00", "#ffff00"],
|
|
78
|
+
blue: ["#0000ff", "#0000ff"],
|
|
79
|
+
magenta: ["#ff00ff", "#ff00ff"],
|
|
80
|
+
cyan: ["#00ffff", "#00ffff"],
|
|
81
|
+
white: ["#ffffff", "#ffffff"],
|
|
82
|
+
gray: ["#808080", "#808080"],
|
|
83
|
+
// Background colors
|
|
84
|
+
bgBlack: ["#000000", "#000000"],
|
|
85
|
+
bgRed: ["#ff5555", "#ff0000"],
|
|
86
|
+
bgGreen: ["#00ff00", "#00ff00"],
|
|
87
|
+
bgYellow: ["#ffff00", "#ffff00"],
|
|
88
|
+
bgBlue: ["#0000ff", "#0000ff"],
|
|
89
|
+
bgMagenta: ["#ff00ff", "#ff00ff"],
|
|
90
|
+
bgCyan: ["#00ffff", "#00ffff"],
|
|
91
|
+
bgWhite: ["#ffffff", "#ffffff"],
|
|
92
|
+
// Bright colors.
|
|
93
|
+
blackBright: ["#000000", "#000000"],
|
|
94
|
+
redBright: ["#ff5555", "#ff5555"],
|
|
95
|
+
greenBright: ["#50fa7b", "#50fa7b"],
|
|
96
|
+
yellowBright: ["#f1fa8c", "#f1fa8c"],
|
|
97
|
+
blueBright: ["#24bdff", "#24bdff"],
|
|
98
|
+
magentaBright: ["#ff79c6", "#ff79c6"],
|
|
99
|
+
cyanBright: ["#8be9fd", "#8be9fd"],
|
|
100
|
+
whiteBright: ["#ffffff", "#ffffff"],
|
|
101
|
+
// Bright background colors.
|
|
102
|
+
bgBlackBright: ["#000000", "#000000"],
|
|
103
|
+
bgRedBright: ["#ff5555", "#ff5555"],
|
|
104
|
+
bgGreenBright: ["#50fa7b", "#50fa7b"],
|
|
105
|
+
bgYellowBright: ["#f1fa8c", "#f1fa8c"],
|
|
106
|
+
bgBlueBright: ["#24bdff", "#24bdff"],
|
|
107
|
+
bgMagentaBright: ["#ff79c6", "#ff79c6"],
|
|
108
|
+
bgCyanBright: ["#8be9fd", "#8be9fd"],
|
|
109
|
+
bgWhiteBright: ["#ffffff", "#ffffff"]
|
|
110
|
+
};
|
|
111
|
+
const windowsTerminalColors = {
|
|
112
|
+
...baseColors,
|
|
113
|
+
red: ["#ff5555", "#ff5555"],
|
|
114
|
+
green: ["#50fa7b", "#50fa7b"],
|
|
115
|
+
yellow: ["#f1fa8c", "#f1fa8c"],
|
|
116
|
+
blue: ["#6272a4", "#6272a4"],
|
|
117
|
+
magenta: ["#ff79c6", "#ff79c6"],
|
|
118
|
+
cyan: ["#8be9fd", "#8be9fd"]
|
|
119
|
+
};
|
|
120
|
+
const restrictedKeys = /* @__PURE__ */ new Set([
|
|
121
|
+
"reset",
|
|
122
|
+
"bold",
|
|
123
|
+
"dim",
|
|
124
|
+
"italic",
|
|
125
|
+
"underline",
|
|
126
|
+
"inverse",
|
|
127
|
+
"hidden",
|
|
128
|
+
"strikethrough"
|
|
129
|
+
]);
|
|
130
|
+
let config = {
|
|
131
|
+
colorLevel: detectColorLevel(),
|
|
132
|
+
theme: "primary"
|
|
133
|
+
// default theme; can be overridden in user config
|
|
134
|
+
};
|
|
135
|
+
let colorMap = {};
|
|
136
|
+
let colorFunctions = {};
|
|
137
|
+
function hexToRGB(hex) {
|
|
138
|
+
if (hex.startsWith("#")) {
|
|
139
|
+
hex = hex.slice(1);
|
|
140
|
+
}
|
|
141
|
+
if (hex.length === 3) {
|
|
142
|
+
hex = hex.split("").map((c) => c + c).join("");
|
|
143
|
+
}
|
|
144
|
+
if (hex.length !== 6) {
|
|
145
|
+
throw new Error(`Invalid hex color: ${hex}`);
|
|
146
|
+
}
|
|
147
|
+
const r = Number.parseInt(hex.substring(0, 2), 16);
|
|
148
|
+
const g = Number.parseInt(hex.substring(2, 4), 16);
|
|
149
|
+
const b = Number.parseInt(hex.substring(4, 6), 16);
|
|
150
|
+
return { r, g, b };
|
|
151
|
+
}
|
|
152
|
+
function hexToAnsiParts(hex, isBg = false) {
|
|
153
|
+
const { r, g, b } = hexToRGB(hex);
|
|
154
|
+
const open = isBg ? `\x1B[48;2;${r};${g};${b}m` : `\x1B[38;2;${r};${g};${b}m`;
|
|
155
|
+
const close = isBg ? "\x1B[49m" : "\x1B[39m";
|
|
156
|
+
return { open, close };
|
|
157
|
+
}
|
|
158
|
+
function hexToAnsi256(hex, isBg = false) {
|
|
159
|
+
const { r, g, b } = hexToRGB(hex);
|
|
160
|
+
const r5 = Math.round(r / 51);
|
|
161
|
+
const g5 = Math.round(g / 51);
|
|
162
|
+
const b5 = Math.round(b / 51);
|
|
163
|
+
const index = 16 + 36 * r5 + 6 * g5 + b5;
|
|
164
|
+
return isBg ? `\x1B[48;5;${index}m` : `\x1B[38;5;${index}m`;
|
|
165
|
+
}
|
|
166
|
+
const basicColors = [
|
|
167
|
+
{ name: "black", rgb: { r: 0, g: 0, b: 0 }, fg: 30, bg: 40 },
|
|
168
|
+
{ name: "red", rgb: { r: 205, g: 0, b: 0 }, fg: 31, bg: 41 },
|
|
169
|
+
{ name: "green", rgb: { r: 0, g: 205, b: 0 }, fg: 32, bg: 42 },
|
|
170
|
+
{ name: "yellow", rgb: { r: 205, g: 205, b: 0 }, fg: 33, bg: 43 },
|
|
171
|
+
{ name: "blue", rgb: { r: 0, g: 0, b: 238 }, fg: 34, bg: 44 },
|
|
172
|
+
{ name: "magenta", rgb: { r: 205, g: 0, b: 205 }, fg: 35, bg: 45 },
|
|
173
|
+
{ name: "cyan", rgb: { r: 0, g: 205, b: 205 }, fg: 36, bg: 46 },
|
|
174
|
+
{ name: "white", rgb: { r: 229, g: 229, b: 229 }, fg: 37, bg: 47 }
|
|
175
|
+
];
|
|
176
|
+
function hexToAnsiBasic(hex, isBg = false) {
|
|
177
|
+
const { r, g, b } = hexToRGB(hex);
|
|
178
|
+
let bestMatch = basicColors[0];
|
|
179
|
+
let bestDistance = Number.MAX_VALUE;
|
|
180
|
+
for (const color of basicColors) {
|
|
181
|
+
const dr = r - color.rgb.r;
|
|
182
|
+
const dg = g - color.rgb.g;
|
|
183
|
+
const db = b - color.rgb.b;
|
|
184
|
+
const distance = dr * dr + dg * dg + db * db;
|
|
185
|
+
if (distance < bestDistance) {
|
|
186
|
+
bestDistance = distance;
|
|
187
|
+
bestMatch = color;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
const code = isBg ? bestMatch.bg : bestMatch.fg;
|
|
191
|
+
return `\x1B[${code}m`;
|
|
192
|
+
}
|
|
193
|
+
function convertColorDefinition(key, def) {
|
|
194
|
+
const isBg = key.toLowerCase().startsWith("bg");
|
|
195
|
+
const theme = config.theme ?? "primary";
|
|
196
|
+
const chosen = theme === "primary" ? def[0] : def[1];
|
|
197
|
+
function convert(str) {
|
|
198
|
+
if (!str.startsWith("#")) return str;
|
|
199
|
+
if (config.colorLevel === 3) {
|
|
200
|
+
return hexToAnsiParts(str, isBg).open;
|
|
201
|
+
}
|
|
202
|
+
if (config.colorLevel === 2) {
|
|
203
|
+
return hexToAnsi256(str, isBg);
|
|
204
|
+
}
|
|
205
|
+
if (config.colorLevel === 1) {
|
|
206
|
+
return hexToAnsiBasic(str, isBg);
|
|
207
|
+
}
|
|
208
|
+
return "";
|
|
209
|
+
}
|
|
210
|
+
const openConverted = convert(chosen);
|
|
211
|
+
const close = isBg ? "\x1B[49m" : "\x1B[39m";
|
|
212
|
+
return [openConverted, close];
|
|
213
|
+
}
|
|
214
|
+
function buildColorMap(cfg) {
|
|
215
|
+
const terminalName = getCurrentTerminalName();
|
|
216
|
+
const isWinTerm = terminalName === "Windows Terminal";
|
|
217
|
+
if (cfg.colorLevel === 0) {
|
|
218
|
+
const noColorMap = {};
|
|
219
|
+
for (const k of Object.keys(baseColors)) {
|
|
220
|
+
noColorMap[k] = ["", ""];
|
|
221
|
+
}
|
|
222
|
+
return noColorMap;
|
|
223
|
+
}
|
|
224
|
+
let builtIn = { ...baseColors };
|
|
225
|
+
if (cfg.customColors) {
|
|
226
|
+
for (const [k, v] of Object.entries(cfg.customColors)) {
|
|
227
|
+
if (!restrictedKeys.has(k)) {
|
|
228
|
+
builtIn[k] = v;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
if (isWinTerm && cfg.colorLevel === 3) {
|
|
233
|
+
builtIn = { ...windowsTerminalColors, ...builtIn };
|
|
234
|
+
}
|
|
235
|
+
for (const key of Object.keys(builtIn)) {
|
|
236
|
+
builtIn[key] = convertColorDefinition(key, builtIn[key]);
|
|
237
|
+
}
|
|
238
|
+
return builtIn;
|
|
239
|
+
}
|
|
240
|
+
function createFormatter(open, close) {
|
|
241
|
+
return (input) => {
|
|
242
|
+
return open + String(input) + close;
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
function identityColor(text) {
|
|
246
|
+
return String(text);
|
|
247
|
+
}
|
|
248
|
+
const typedRe = {
|
|
249
|
+
reset: identityColor,
|
|
250
|
+
bold: identityColor,
|
|
251
|
+
dim: identityColor,
|
|
252
|
+
italic: identityColor,
|
|
253
|
+
underline: identityColor,
|
|
254
|
+
inverse: identityColor,
|
|
255
|
+
hidden: identityColor,
|
|
256
|
+
strikethrough: identityColor,
|
|
257
|
+
black: identityColor,
|
|
258
|
+
red: identityColor,
|
|
259
|
+
green: identityColor,
|
|
260
|
+
yellow: identityColor,
|
|
261
|
+
blue: identityColor,
|
|
262
|
+
magenta: identityColor,
|
|
263
|
+
cyan: identityColor,
|
|
264
|
+
white: identityColor,
|
|
265
|
+
gray: identityColor,
|
|
266
|
+
bgBlack: identityColor,
|
|
267
|
+
bgRed: identityColor,
|
|
268
|
+
bgGreen: identityColor,
|
|
269
|
+
bgYellow: identityColor,
|
|
270
|
+
bgBlue: identityColor,
|
|
271
|
+
bgMagenta: identityColor,
|
|
272
|
+
bgCyan: identityColor,
|
|
273
|
+
bgWhite: identityColor,
|
|
274
|
+
blackBright: identityColor,
|
|
275
|
+
redBright: identityColor,
|
|
276
|
+
greenBright: identityColor,
|
|
277
|
+
yellowBright: identityColor,
|
|
278
|
+
blueBright: identityColor,
|
|
279
|
+
magentaBright: identityColor,
|
|
280
|
+
cyanBright: identityColor,
|
|
281
|
+
whiteBright: identityColor,
|
|
282
|
+
bgBlackBright: identityColor,
|
|
283
|
+
bgRedBright: identityColor,
|
|
284
|
+
bgGreenBright: identityColor,
|
|
285
|
+
bgYellowBright: identityColor,
|
|
286
|
+
bgBlueBright: identityColor,
|
|
287
|
+
bgMagentaBright: identityColor,
|
|
288
|
+
bgCyanBright: identityColor,
|
|
289
|
+
bgWhiteBright: identityColor
|
|
290
|
+
};
|
|
291
|
+
export const re = typedRe;
|
|
292
|
+
function refreshTypedRe() {
|
|
293
|
+
for (const colorName of Object.keys(typedRe)) {
|
|
294
|
+
typedRe[colorName] = identityColor;
|
|
295
|
+
}
|
|
296
|
+
for (const [k, fn] of Object.entries(colorFunctions)) {
|
|
297
|
+
typedRe[k] = fn;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
function initColorFunctions() {
|
|
301
|
+
colorFunctions = {};
|
|
302
|
+
if (config.colorLevel === 0) {
|
|
303
|
+
for (const k of Object.keys(baseColors)) {
|
|
304
|
+
colorFunctions[k] = identityColor;
|
|
305
|
+
}
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
for (const [key, [open, close]] of Object.entries(colorMap)) {
|
|
309
|
+
colorFunctions[key] = createFormatter(open, close);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
function rebuild() {
|
|
313
|
+
colorMap = buildColorMap(config);
|
|
314
|
+
initColorFunctions();
|
|
315
|
+
refreshTypedRe();
|
|
316
|
+
}
|
|
317
|
+
rebuild();
|
|
318
|
+
export function configure(userInput) {
|
|
319
|
+
let newConfig;
|
|
320
|
+
if (typeof userInput === "object" && userInput !== null) {
|
|
321
|
+
newConfig = { ...config, ...userInput };
|
|
322
|
+
} else {
|
|
323
|
+
newConfig = { ...config };
|
|
324
|
+
}
|
|
325
|
+
config = newConfig;
|
|
326
|
+
rebuild();
|
|
327
|
+
}
|
|
328
|
+
export function getColor(name) {
|
|
329
|
+
const maybeFn = colorFunctions[name];
|
|
330
|
+
if (maybeFn) return maybeFn;
|
|
331
|
+
const resetFn = colorFunctions.reset;
|
|
332
|
+
if (resetFn) return resetFn;
|
|
333
|
+
return identityColor;
|
|
334
|
+
}
|
|
335
|
+
export function colorize(name, text) {
|
|
336
|
+
const fn = getColor(name);
|
|
337
|
+
return fn(text);
|
|
338
|
+
}
|
|
339
|
+
export function setColorLevel(level) {
|
|
340
|
+
configure({ colorLevel: level });
|
|
341
|
+
}
|
|
342
|
+
export function rgb(r, g, b) {
|
|
343
|
+
if (config.colorLevel === 3) {
|
|
344
|
+
const open = `\x1B[38;2;${r};${g};${b}m`;
|
|
345
|
+
const close = "\x1B[39m";
|
|
346
|
+
return createFormatter(open, close);
|
|
347
|
+
}
|
|
348
|
+
return identityColor;
|
|
349
|
+
}
|
|
350
|
+
function getConfig() {
|
|
351
|
+
return { ...config };
|
|
352
|
+
}
|
|
353
|
+
export const colorSupport = {
|
|
354
|
+
isColorSupported: getConfig().colorLevel !== 0,
|
|
355
|
+
isForced,
|
|
356
|
+
isDisabled,
|
|
357
|
+
terminalName: getCurrentTerminalName()
|
|
358
|
+
};
|
|
359
|
+
export async function initUserConfig() {
|
|
360
|
+
try {
|
|
361
|
+
const { config: userConfig } = await loadConfig({ name: "relico" });
|
|
362
|
+
configure(userConfig);
|
|
363
|
+
} catch (err) {
|
|
364
|
+
console.warn("Failed to load user config via c12:", err);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
export function defineConfig(cfg) {
|
|
368
|
+
return cfg;
|
|
369
|
+
}
|
package/package.json
CHANGED
|
@@ -1,82 +1,55 @@
|
|
|
1
1
|
{
|
|
2
|
+
"dependencies": {
|
|
3
|
+
"@reliverse/runtime": "^1.0.3",
|
|
4
|
+
"c12": "^3.0.2",
|
|
5
|
+
"pathe": "^2.0.3"
|
|
6
|
+
},
|
|
7
|
+
"description": "@reliverse/relico is doing its best to improve your terminal colorization experience by leveraging TypeScript and TypeBox for enhanced reliability and type safety.",
|
|
8
|
+
"homepage": "https://docs.reliverse.org",
|
|
9
|
+
"license": "MIT",
|
|
2
10
|
"name": "@reliverse/relico",
|
|
3
|
-
"version": "1.0.1",
|
|
4
|
-
"author": "reliverse",
|
|
5
11
|
"type": "module",
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"build:jsr": "bun build.optim.ts --jsr",
|
|
12
|
-
"build": "bun build:npm && bun build:jsr",
|
|
13
|
-
"pub:npm": "bun build.publish.ts",
|
|
14
|
-
"pub:jsr": "bun build.publish.ts --jsr",
|
|
15
|
-
"pub:dry": "bun build.publish.ts --dry-run",
|
|
16
|
-
"pub": "bun publish.ts",
|
|
17
|
-
"typecheck": "tsc --noEmit",
|
|
18
|
-
"lint": "eslint --cache --fix .",
|
|
19
|
-
"lint:i": "eslint --inspect-config",
|
|
20
|
-
"format": "biome check --write .",
|
|
21
|
-
"attw": "bunx @arethetypeswrong/cli",
|
|
22
|
-
"unpub": "npm unpublish",
|
|
23
|
-
"test": "vitest",
|
|
24
|
-
"knip": "knip",
|
|
25
|
-
"latest": "bun update --latest"
|
|
26
|
-
},
|
|
27
|
-
"publishConfig": {
|
|
28
|
-
"access": "public"
|
|
12
|
+
"version": "1.1.0",
|
|
13
|
+
"author": "reliverse",
|
|
14
|
+
"bugs": {
|
|
15
|
+
"email": "blefnk@gmail.com",
|
|
16
|
+
"url": "https://github.com/reliverse/relico/issues"
|
|
29
17
|
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"reliverse"
|
|
20
|
+
],
|
|
30
21
|
"repository": {
|
|
31
22
|
"type": "git",
|
|
32
23
|
"url": "git+https://github.com/reliverse/relico.git"
|
|
33
24
|
},
|
|
34
|
-
"types": "./dist-npm/main.d.ts",
|
|
35
|
-
"module": "./dist-npm/main.js",
|
|
36
|
-
"main": "./dist-npm/main.js",
|
|
37
|
-
"exports": {
|
|
38
|
-
"import": "./dist-npm/main.js",
|
|
39
|
-
"types": "./dist-npm/main.d.ts"
|
|
40
|
-
},
|
|
41
|
-
"bugs": {
|
|
42
|
-
"url": "https://github.com/reliverse/relico/issues",
|
|
43
|
-
"email": "blefnk@gmail.com"
|
|
44
|
-
},
|
|
45
|
-
"files": ["package.json", "README.md", "LICENSE.md", "dist-npm"],
|
|
46
|
-
"homepage": "https://github.com/reliverse/relico",
|
|
47
|
-
"keywords": ["cli", "reliverse"],
|
|
48
|
-
"license": "MIT",
|
|
49
|
-
"dependencies": {
|
|
50
|
-
"@reliverse/runtime": "^1.0.2",
|
|
51
|
-
"@sinclair/typebox": "^0.34.14",
|
|
52
|
-
"bun-types": "^1.2.0",
|
|
53
|
-
"confbox": "^0.1.8",
|
|
54
|
-
"destr": "^2.0.3",
|
|
55
|
-
"fs-extra": "^11.3.0",
|
|
56
|
-
"globby": "^14.0.2",
|
|
57
|
-
"mri": "^1.2.0",
|
|
58
|
-
"pathe": "^2.0.2"
|
|
59
|
-
},
|
|
60
25
|
"devDependencies": {
|
|
61
|
-
"@arethetypeswrong/cli": "^0.17.3",
|
|
62
26
|
"@biomejs/biome": "1.9.4",
|
|
63
|
-
"@eslint/js": "^9.
|
|
64
|
-
"@
|
|
65
|
-
"@eslint
|
|
66
|
-
"@
|
|
67
|
-
"@types/
|
|
68
|
-
"
|
|
69
|
-
"
|
|
70
|
-
"
|
|
71
|
-
"citty": "^0.1.6",
|
|
72
|
-
"eslint": "^9.19.0",
|
|
73
|
-
"eslint-plugin-perfectionist": "^4.7.0",
|
|
74
|
-
"execa": "^9.5.2",
|
|
27
|
+
"@eslint/js": "^9.23.0",
|
|
28
|
+
"@reliverse/relidler-cfg": "^1.1.3",
|
|
29
|
+
"@stylistic/eslint-plugin": "^4.2.0",
|
|
30
|
+
"@types/bun": "^1.2.8",
|
|
31
|
+
"@types/node": "^22.13.17",
|
|
32
|
+
"eslint": "^9.23.0",
|
|
33
|
+
"eslint-plugin-no-relative-import-paths": "^1.6.1",
|
|
34
|
+
"eslint-plugin-perfectionist": "^4.11.0",
|
|
75
35
|
"jiti": "^2.4.2",
|
|
76
|
-
"knip": "^5.
|
|
77
|
-
"typescript": "^5.
|
|
78
|
-
"typescript-eslint": "^8.
|
|
79
|
-
"
|
|
80
|
-
|
|
36
|
+
"knip": "^5.46.4",
|
|
37
|
+
"typescript": "^5.8.2",
|
|
38
|
+
"typescript-eslint": "^8.29.0",
|
|
39
|
+
"vitest": "^3.1.1"
|
|
40
|
+
},
|
|
41
|
+
"exports": {
|
|
42
|
+
".": "./bin/main.js"
|
|
43
|
+
},
|
|
44
|
+
"files": [
|
|
45
|
+
"bin",
|
|
46
|
+
"package.json",
|
|
47
|
+
"README.md",
|
|
48
|
+
"LICENSE"
|
|
49
|
+
],
|
|
50
|
+
"main": "./bin/main.js",
|
|
51
|
+
"module": "./bin/main.js",
|
|
52
|
+
"publishConfig": {
|
|
53
|
+
"access": "public"
|
|
81
54
|
}
|
|
82
55
|
}
|
package/dist-npm/main.d.ts
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import type { Static } from "@sinclair/typebox";
|
|
2
|
-
export declare const ColorDefinitionSchema: import("@sinclair/typebox").TTuple<[import("@sinclair/typebox").TString, import("@sinclair/typebox").TString, import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>]>;
|
|
3
|
-
export declare const ColorMapSchema: import("@sinclair/typebox").TRecord<import("@sinclair/typebox").TString, import("@sinclair/typebox").TTuple<[import("@sinclair/typebox").TString, import("@sinclair/typebox").TString, import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>]>>;
|
|
4
|
-
export declare const RelicoConfigSchema: import("@sinclair/typebox").TObject<{
|
|
5
|
-
colorLevel: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<0>, import("@sinclair/typebox").TLiteral<1>, import("@sinclair/typebox").TLiteral<2>, import("@sinclair/typebox").TLiteral<3>]>>;
|
|
6
|
-
customColors: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TRecord<import("@sinclair/typebox").TString, import("@sinclair/typebox").TTuple<[import("@sinclair/typebox").TString, import("@sinclair/typebox").TString, import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>]>>>;
|
|
7
|
-
}>;
|
|
8
|
-
export type RelicoConfig = Static<typeof RelicoConfigSchema>;
|
|
9
|
-
/**
|
|
10
|
-
* Configures the library with a partial or complete `RelicoConfig`.
|
|
11
|
-
* For any invalid fields, a warning is shown and they are ignored.
|
|
12
|
-
*/
|
|
13
|
-
export declare function configure(userInput: unknown): void;
|
|
14
|
-
/** Returns a read-only copy of the current configuration. */
|
|
15
|
-
export declare function getConfig(): RelicoConfig;
|
|
16
|
-
/** Returns a color function by name (or `reset` or identity if not found). */
|
|
17
|
-
export declare function getColor(name: string): (text: string | number) => string;
|
|
18
|
-
/** Colorize text with a color function. */
|
|
19
|
-
export declare function colorize(name: string, text: string | number): string;
|
|
20
|
-
/** Set the color level (0=none,1=basic,2=256,3=truecolor). */
|
|
21
|
-
export declare function setColorLevel(level: 0 | 1 | 2 | 3): void;
|
|
22
|
-
/** Returns a custom "rgb" color function if level=3, otherwise identity. */
|
|
23
|
-
export declare function rgb(r: number, g: number, b: number): (text: string | number) => string;
|
|
24
|
-
export type IRelicoColors = {
|
|
25
|
-
reset(text: string | number): string;
|
|
26
|
-
bold(text: string | number): string;
|
|
27
|
-
dim(text: string | number): string;
|
|
28
|
-
italic(text: string | number): string;
|
|
29
|
-
underline(text: string | number): string;
|
|
30
|
-
inverse(text: string | number): string;
|
|
31
|
-
hidden(text: string | number): string;
|
|
32
|
-
strikethrough(text: string | number): string;
|
|
33
|
-
black(text: string | number): string;
|
|
34
|
-
red(text: string | number): string;
|
|
35
|
-
green(text: string | number): string;
|
|
36
|
-
yellow(text: string | number): string;
|
|
37
|
-
blue(text: string | number): string;
|
|
38
|
-
magenta(text: string | number): string;
|
|
39
|
-
cyan(text: string | number): string;
|
|
40
|
-
white(text: string | number): string;
|
|
41
|
-
gray(text: string | number): string;
|
|
42
|
-
bgBlack(text: string | number): string;
|
|
43
|
-
bgRed(text: string | number): string;
|
|
44
|
-
bgGreen(text: string | number): string;
|
|
45
|
-
bgYellow(text: string | number): string;
|
|
46
|
-
bgBlue(text: string | number): string;
|
|
47
|
-
bgMagenta(text: string | number): string;
|
|
48
|
-
bgCyan(text: string | number): string;
|
|
49
|
-
bgWhite(text: string | number): string;
|
|
50
|
-
blackBright(text: string | number): string;
|
|
51
|
-
redBright(text: string | number): string;
|
|
52
|
-
greenBright(text: string | number): string;
|
|
53
|
-
yellowBright(text: string | number): string;
|
|
54
|
-
blueBright(text: string | number): string;
|
|
55
|
-
magentaBright(text: string | number): string;
|
|
56
|
-
cyanBright(text: string | number): string;
|
|
57
|
-
whiteBright(text: string | number): string;
|
|
58
|
-
bgBlackBright(text: string | number): string;
|
|
59
|
-
bgRedBright(text: string | number): string;
|
|
60
|
-
bgGreenBright(text: string | number): string;
|
|
61
|
-
bgYellowBright(text: string | number): string;
|
|
62
|
-
bgBlueBright(text: string | number): string;
|
|
63
|
-
bgMagentaBright(text: string | number): string;
|
|
64
|
-
bgCyanBright(text: string | number): string;
|
|
65
|
-
bgWhiteBright(text: string | number): string;
|
|
66
|
-
[k: string]: (text: string | number) => string;
|
|
67
|
-
};
|
|
68
|
-
/**
|
|
69
|
-
* The typed `re` object with all known color methods
|
|
70
|
-
* plus user-defined ones (index signature).
|
|
71
|
-
*/
|
|
72
|
-
export declare const re: IRelicoColors;
|
|
73
|
-
export type ColorSupport = {
|
|
74
|
-
isColorSupported: boolean;
|
|
75
|
-
isForced: boolean;
|
|
76
|
-
isDisabled: boolean;
|
|
77
|
-
terminalName: string;
|
|
78
|
-
};
|
|
79
|
-
export declare const colorSupport: ColorSupport;
|
package/dist-npm/main.js
DELETED
|
@@ -1,269 +0,0 @@
|
|
|
1
|
-
import { getCurrentTerminalName } from "@reliverse/runtime";
|
|
2
|
-
import { env, isWindows } from "@reliverse/runtime";
|
|
3
|
-
import { Type } from "@sinclair/typebox";
|
|
4
|
-
import { Value } from "@sinclair/typebox/value";
|
|
5
|
-
export const ColorDefinitionSchema = Type.Tuple([
|
|
6
|
-
Type.String(),
|
|
7
|
-
Type.String(),
|
|
8
|
-
Type.Optional(Type.String())
|
|
9
|
-
]);
|
|
10
|
-
export const ColorMapSchema = Type.Record(Type.String(), ColorDefinitionSchema);
|
|
11
|
-
export const RelicoConfigSchema = Type.Object(
|
|
12
|
-
{
|
|
13
|
-
colorLevel: Type.Optional(
|
|
14
|
-
Type.Union([
|
|
15
|
-
Type.Literal(0),
|
|
16
|
-
Type.Literal(1),
|
|
17
|
-
Type.Literal(2),
|
|
18
|
-
Type.Literal(3)
|
|
19
|
-
])
|
|
20
|
-
),
|
|
21
|
-
customColors: Type.Optional(ColorMapSchema)
|
|
22
|
-
},
|
|
23
|
-
{ additionalProperties: false }
|
|
24
|
-
);
|
|
25
|
-
const argv = typeof process === "undefined" ? [] : process.argv;
|
|
26
|
-
const isDisabled = "NO_COLOR" in env || argv.includes("--no-color");
|
|
27
|
-
const isForced = "FORCE_COLOR" in env || argv.includes("--color");
|
|
28
|
-
const isCI = "CI" in env && ("GITHUB_ACTIONS" in env || "GITLAB_CI" in env || "CIRCLECI" in env);
|
|
29
|
-
const isCompatibleTerminal = typeof process !== "undefined" && Boolean(process.stdout) && Boolean(process.stdout.isTTY) && env["TERM"] !== "dumb";
|
|
30
|
-
const colorterm = (env["COLORTERM"] ?? "").toLowerCase();
|
|
31
|
-
const supportsTrueColor = colorterm === "truecolor" || colorterm === "24bit";
|
|
32
|
-
function detectColorLevel() {
|
|
33
|
-
if (isDisabled) return 0;
|
|
34
|
-
if (isForced) return 3;
|
|
35
|
-
if (supportsTrueColor) return 3;
|
|
36
|
-
if (isWindows) return 2;
|
|
37
|
-
if (isCI) return 2;
|
|
38
|
-
if (isCompatibleTerminal) {
|
|
39
|
-
return 2;
|
|
40
|
-
}
|
|
41
|
-
return 0;
|
|
42
|
-
}
|
|
43
|
-
const baseColors = {
|
|
44
|
-
reset: ["\x1B[0m", "\x1B[0m"],
|
|
45
|
-
bold: ["\x1B[1m", "\x1B[22m", "\x1B[22m\x1B[1m"],
|
|
46
|
-
dim: ["\x1B[2m", "\x1B[22m", "\x1B[22m\x1B[2m"],
|
|
47
|
-
italic: ["\x1B[3m", "\x1B[23m"],
|
|
48
|
-
underline: ["\x1B[4m", "\x1B[24m"],
|
|
49
|
-
inverse: ["\x1B[7m", "\x1B[27m"],
|
|
50
|
-
hidden: ["\x1B[8m", "\x1B[28m"],
|
|
51
|
-
strikethrough: ["\x1B[9m", "\x1B[29m"],
|
|
52
|
-
black: ["\x1B[30m", "\x1B[39m"],
|
|
53
|
-
red: ["\x1B[31m", "\x1B[39m"],
|
|
54
|
-
green: ["\x1B[32m", "\x1B[39m"],
|
|
55
|
-
yellow: ["\x1B[33m", "\x1B[39m"],
|
|
56
|
-
blue: ["\x1B[34m", "\x1B[39m"],
|
|
57
|
-
magenta: ["\x1B[35m", "\x1B[39m"],
|
|
58
|
-
cyan: ["\x1B[36m", "\x1B[39m"],
|
|
59
|
-
white: ["\x1B[37m", "\x1B[39m"],
|
|
60
|
-
gray: ["\x1B[90m", "\x1B[39m"],
|
|
61
|
-
bgBlack: ["\x1B[40m", "\x1B[49m"],
|
|
62
|
-
bgRed: ["\x1B[41m", "\x1B[49m"],
|
|
63
|
-
bgGreen: ["\x1B[42m", "\x1B[49m"],
|
|
64
|
-
bgYellow: ["\x1B[43m", "\x1B[49m"],
|
|
65
|
-
bgBlue: ["\x1B[44m", "\x1B[49m"],
|
|
66
|
-
bgMagenta: ["\x1B[45m", "\x1B[49m"],
|
|
67
|
-
bgCyan: ["\x1B[46m", "\x1B[49m"],
|
|
68
|
-
bgWhite: ["\x1B[47m", "\x1B[49m"],
|
|
69
|
-
blackBright: ["\x1B[90m", "\x1B[39m"],
|
|
70
|
-
redBright: ["\x1B[91m", "\x1B[39m"],
|
|
71
|
-
greenBright: ["\x1B[92m", "\x1B[39m"],
|
|
72
|
-
yellowBright: ["\x1B[93m", "\x1B[39m"],
|
|
73
|
-
blueBright: ["\x1B[94m", "\x1B[39m"],
|
|
74
|
-
magentaBright: ["\x1B[95m", "\x1B[39m"],
|
|
75
|
-
cyanBright: ["\x1B[96m", "\x1B[39m"],
|
|
76
|
-
whiteBright: ["\x1B[97m", "\x1B[39m"],
|
|
77
|
-
bgBlackBright: ["\x1B[100m", "\x1B[49m"],
|
|
78
|
-
bgRedBright: ["\x1B[101m", "\x1B[49m"],
|
|
79
|
-
bgGreenBright: ["\x1B[102m", "\x1B[49m"],
|
|
80
|
-
bgYellowBright: ["\x1B[103m", "\x1B[49m"],
|
|
81
|
-
bgBlueBright: ["\x1B[104m", "\x1B[49m"],
|
|
82
|
-
bgMagentaBright: ["\x1B[105m", "\x1B[49m"],
|
|
83
|
-
bgCyanBright: ["\x1B[106m", "\x1B[49m"],
|
|
84
|
-
bgWhiteBright: ["\x1B[107m", "\x1B[49m"]
|
|
85
|
-
};
|
|
86
|
-
const windowsTerminalColors = {
|
|
87
|
-
...baseColors,
|
|
88
|
-
red: ["\x1B[38;2;255;85;85m", "\x1B[39m"],
|
|
89
|
-
green: ["\x1B[38;2;80;250;123m", "\x1B[39m"],
|
|
90
|
-
yellow: ["\x1B[38;2;241;250;140m", "\x1B[39m"],
|
|
91
|
-
blue: ["\x1B[38;2;98;114;164m", "\x1B[39m"],
|
|
92
|
-
magenta: ["\x1B[38;2;255;121;198m", "\x1B[39m"],
|
|
93
|
-
cyan: ["\x1B[38;2;139;233;253m", "\x1B[39m"]
|
|
94
|
-
};
|
|
95
|
-
let config = {
|
|
96
|
-
colorLevel: detectColorLevel()
|
|
97
|
-
};
|
|
98
|
-
let colorMap = {};
|
|
99
|
-
let colorFunctions = {};
|
|
100
|
-
function replaceClose(str, close, replace, index) {
|
|
101
|
-
let result = "";
|
|
102
|
-
let cursor = 0;
|
|
103
|
-
let i = index;
|
|
104
|
-
while (i !== -1) {
|
|
105
|
-
result += str.substring(cursor, i) + replace;
|
|
106
|
-
cursor = i + close.length;
|
|
107
|
-
i = str.indexOf(close, cursor);
|
|
108
|
-
}
|
|
109
|
-
return result + str.substring(cursor);
|
|
110
|
-
}
|
|
111
|
-
function createFormatter(open, close, replace = open) {
|
|
112
|
-
return (input) => {
|
|
113
|
-
const stringed = String(input);
|
|
114
|
-
const idx = stringed.indexOf(close, open.length);
|
|
115
|
-
if (idx !== -1) {
|
|
116
|
-
return open + replaceClose(stringed, close, replace, idx) + close;
|
|
117
|
-
}
|
|
118
|
-
return open + stringed + close;
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
function buildColorMap(cfg) {
|
|
122
|
-
const terminalName = getCurrentTerminalName();
|
|
123
|
-
const isWinTerm = terminalName === "Windows Terminal";
|
|
124
|
-
if (cfg.colorLevel === 0) {
|
|
125
|
-
const map = {};
|
|
126
|
-
for (const k of Object.keys(baseColors)) {
|
|
127
|
-
map[k] = ["", "", ""];
|
|
128
|
-
}
|
|
129
|
-
return map;
|
|
130
|
-
}
|
|
131
|
-
let builtIn;
|
|
132
|
-
if (isWinTerm && cfg.colorLevel === 3) {
|
|
133
|
-
builtIn = { ...windowsTerminalColors };
|
|
134
|
-
} else {
|
|
135
|
-
builtIn = { ...baseColors };
|
|
136
|
-
}
|
|
137
|
-
if (cfg.customColors) {
|
|
138
|
-
for (const [k, v] of Object.entries(cfg.customColors)) {
|
|
139
|
-
builtIn[k] = v;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
return builtIn;
|
|
143
|
-
}
|
|
144
|
-
function initColorFunctions() {
|
|
145
|
-
colorFunctions = {};
|
|
146
|
-
if (config.colorLevel === 0) {
|
|
147
|
-
for (const k of Object.keys(baseColors)) {
|
|
148
|
-
colorFunctions[k] = identityColor;
|
|
149
|
-
}
|
|
150
|
-
return;
|
|
151
|
-
}
|
|
152
|
-
for (const [key, [open, close, replace]] of Object.entries(colorMap)) {
|
|
153
|
-
colorFunctions[key] = createFormatter(open, close, replace ?? open);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
function rebuild() {
|
|
157
|
-
colorMap = buildColorMap(config);
|
|
158
|
-
initColorFunctions();
|
|
159
|
-
}
|
|
160
|
-
function identityColor(text) {
|
|
161
|
-
return String(text);
|
|
162
|
-
}
|
|
163
|
-
rebuild();
|
|
164
|
-
export function configure(userInput) {
|
|
165
|
-
let newObj = null;
|
|
166
|
-
if (typeof userInput === "object" && userInput !== null) {
|
|
167
|
-
newObj = { ...config, ...userInput };
|
|
168
|
-
} else {
|
|
169
|
-
newObj = { ...config };
|
|
170
|
-
}
|
|
171
|
-
try {
|
|
172
|
-
const parsed = Value.Cast(RelicoConfigSchema, newObj);
|
|
173
|
-
config = parsed;
|
|
174
|
-
} catch (err) {
|
|
175
|
-
console.warn("Invalid relico config:", err);
|
|
176
|
-
return;
|
|
177
|
-
}
|
|
178
|
-
rebuild();
|
|
179
|
-
}
|
|
180
|
-
export function getConfig() {
|
|
181
|
-
return { ...config };
|
|
182
|
-
}
|
|
183
|
-
export function getColor(name) {
|
|
184
|
-
const maybeFn = colorFunctions[name];
|
|
185
|
-
if (maybeFn) return maybeFn;
|
|
186
|
-
const resetFn = colorFunctions["reset"];
|
|
187
|
-
if (resetFn) return resetFn;
|
|
188
|
-
return identityColor;
|
|
189
|
-
}
|
|
190
|
-
export function colorize(name, text) {
|
|
191
|
-
const fn = getColor(name);
|
|
192
|
-
return fn(text);
|
|
193
|
-
}
|
|
194
|
-
export function setColorLevel(level) {
|
|
195
|
-
configure({ colorLevel: level });
|
|
196
|
-
}
|
|
197
|
-
export function rgb(r, g, b) {
|
|
198
|
-
if (config.colorLevel === 3) {
|
|
199
|
-
const open = `\x1B[38;2;${String(r)};${String(g)};${String(b)}m`;
|
|
200
|
-
const close = "\x1B[39m";
|
|
201
|
-
return createFormatter(open, close);
|
|
202
|
-
}
|
|
203
|
-
return identityColor;
|
|
204
|
-
}
|
|
205
|
-
const typedRe = {
|
|
206
|
-
reset: identityColor,
|
|
207
|
-
bold: identityColor,
|
|
208
|
-
dim: identityColor,
|
|
209
|
-
italic: identityColor,
|
|
210
|
-
underline: identityColor,
|
|
211
|
-
inverse: identityColor,
|
|
212
|
-
hidden: identityColor,
|
|
213
|
-
strikethrough: identityColor,
|
|
214
|
-
black: identityColor,
|
|
215
|
-
red: identityColor,
|
|
216
|
-
green: identityColor,
|
|
217
|
-
yellow: identityColor,
|
|
218
|
-
blue: identityColor,
|
|
219
|
-
magenta: identityColor,
|
|
220
|
-
cyan: identityColor,
|
|
221
|
-
white: identityColor,
|
|
222
|
-
gray: identityColor,
|
|
223
|
-
bgBlack: identityColor,
|
|
224
|
-
bgRed: identityColor,
|
|
225
|
-
bgGreen: identityColor,
|
|
226
|
-
bgYellow: identityColor,
|
|
227
|
-
bgBlue: identityColor,
|
|
228
|
-
bgMagenta: identityColor,
|
|
229
|
-
bgCyan: identityColor,
|
|
230
|
-
bgWhite: identityColor,
|
|
231
|
-
blackBright: identityColor,
|
|
232
|
-
redBright: identityColor,
|
|
233
|
-
greenBright: identityColor,
|
|
234
|
-
yellowBright: identityColor,
|
|
235
|
-
blueBright: identityColor,
|
|
236
|
-
magentaBright: identityColor,
|
|
237
|
-
cyanBright: identityColor,
|
|
238
|
-
whiteBright: identityColor,
|
|
239
|
-
bgBlackBright: identityColor,
|
|
240
|
-
bgRedBright: identityColor,
|
|
241
|
-
bgGreenBright: identityColor,
|
|
242
|
-
bgYellowBright: identityColor,
|
|
243
|
-
bgBlueBright: identityColor,
|
|
244
|
-
bgMagentaBright: identityColor,
|
|
245
|
-
bgCyanBright: identityColor,
|
|
246
|
-
bgWhiteBright: identityColor
|
|
247
|
-
};
|
|
248
|
-
function refreshTypedRe() {
|
|
249
|
-
for (const colorName of Object.keys(typedRe)) {
|
|
250
|
-
typedRe[colorName] = identityColor;
|
|
251
|
-
}
|
|
252
|
-
for (const [k, fn] of Object.entries(colorFunctions)) {
|
|
253
|
-
typedRe[k] = fn;
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
const originalRebuild = rebuild;
|
|
257
|
-
function newRebuild() {
|
|
258
|
-
originalRebuild();
|
|
259
|
-
refreshTypedRe();
|
|
260
|
-
}
|
|
261
|
-
rebuild = newRebuild;
|
|
262
|
-
newRebuild();
|
|
263
|
-
export const re = typedRe;
|
|
264
|
-
export const colorSupport = {
|
|
265
|
-
isColorSupported: getConfig().colorLevel !== 0,
|
|
266
|
-
isForced,
|
|
267
|
-
isDisabled,
|
|
268
|
-
terminalName: getCurrentTerminalName()
|
|
269
|
-
};
|