@reliverse/relico 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/LICENSE +21 -0
- package/README.md +121 -0
- package/dist-npm/main.d.ts +80 -0
- package/dist-npm/main.js +329 -0
- package/package.json +81 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Nazarii Korniienko
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# @reliverse/relico
|
|
2
|
+
|
|
3
|
+
[**Docs**](.github/DOCS.md) | [**NPM**](https://npmjs.com/package/@reliverse/relico) | [**GitHub**](https://github.com/reliverse/relico)
|
|
4
|
+
|
|
5
|
+
<p align="left">
|
|
6
|
+
<a href="https://npmjs.org/package/@reliverse/relico">
|
|
7
|
+
<img src="https://img.shields.io/npm/v/@reliverse/relico.svg" alt="version" />
|
|
8
|
+
</a>
|
|
9
|
+
<a href="https://npmjs.org/package/@reliverse/relico">
|
|
10
|
+
<img src="https://img.shields.io/npm/dm/@reliverse/relico.svg" alt="downloads" />
|
|
11
|
+
</a>
|
|
12
|
+
</p>
|
|
13
|
+
|
|
14
|
+
**@reliverse/relico is a 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
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```sh
|
|
19
|
+
bun add @reliverse/relico # Replace "bun" with npm, pnpm, or yarn if desired
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Key Features
|
|
23
|
+
|
|
24
|
+
- **Smart Terminal Detection**: Automatically detects terminal type and color support level
|
|
25
|
+
- **Type Safety**: Built with TypeScript and TypeBox for reliable type checking
|
|
26
|
+
- **Multiple Color Levels**: Supports different color levels (none, basic, 256-color, truecolor)
|
|
27
|
+
- **Flexible API**: Multiple ways to apply colors (object syntax, functions, RGB)
|
|
28
|
+
- **Windows Support**: Special color handling for Windows Terminal
|
|
29
|
+
- **Environment Aware**: Respects NO_COLOR and FORCE_COLOR environment variables
|
|
30
|
+
|
|
31
|
+
## Usage Examples
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
import { re, colorize, rgb } from "@reliverse/relico";
|
|
35
|
+
|
|
36
|
+
// Using the "re" object for basic colors
|
|
37
|
+
console.log(re.red("This is red text"));
|
|
38
|
+
console.log(re.blue("This is blue text"));
|
|
39
|
+
|
|
40
|
+
// Combining styles
|
|
41
|
+
console.log(re.bold(re.green("Bold green text")));
|
|
42
|
+
|
|
43
|
+
// Using the colorize function
|
|
44
|
+
console.log(colorize("magenta", "This is magenta text"));
|
|
45
|
+
|
|
46
|
+
// Using RGB colors (requires truecolor support)
|
|
47
|
+
const salmon = rgb(250, 128, 114);
|
|
48
|
+
console.log(salmon("This is salmon colored text"));
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Color Support
|
|
52
|
+
|
|
53
|
+
The library automatically detects the terminal's color support level:
|
|
54
|
+
|
|
55
|
+
- Level 0: No color support
|
|
56
|
+
- Level 1: Basic color support
|
|
57
|
+
- Level 2: 256 color support
|
|
58
|
+
- Level 3: Truecolor (16 million colors) support
|
|
59
|
+
|
|
60
|
+
You can check color support information:
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
import { colorSupport } from "@reliverse/relico";
|
|
64
|
+
|
|
65
|
+
console.log("Terminal:", colorSupport.terminalName);
|
|
66
|
+
console.log("Colors Supported:", colorSupport.isColorSupported);
|
|
67
|
+
console.log("Colors Forced:", colorSupport.isForced);
|
|
68
|
+
console.log("Colors Disabled:", colorSupport.isDisabled);
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Available Styles
|
|
72
|
+
|
|
73
|
+
- **Basic Colors**: `red`, `green`, `blue`, `yellow`, `magenta`, `cyan`, `white`, `black`, `gray`
|
|
74
|
+
- **Bright Colors**: `redBright`, `greenBright`, `blueBright`, etc.
|
|
75
|
+
- **Background Colors**: `bgRed`, `bgGreen`, `bgBlue`, etc.
|
|
76
|
+
- **Text Styles**: `bold`, `dim`, `italic`, `underline`, `inverse`, `hidden`, `strikethrough`
|
|
77
|
+
|
|
78
|
+
## Configuration
|
|
79
|
+
|
|
80
|
+
You can customize the library's behavior:
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
import { configure } from "@reliverse/relico";
|
|
84
|
+
|
|
85
|
+
configure({
|
|
86
|
+
colorLevel: 3, // Force truecolor support
|
|
87
|
+
customColors: {
|
|
88
|
+
// Add custom color definitions
|
|
89
|
+
success: ["\x1b[38;2;0;255;0m", "\x1b[0m"]
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Example Project
|
|
95
|
+
|
|
96
|
+
Check out [examples/example.ts](./examples/example.ts) for a comprehensive demonstration of all features, including:
|
|
97
|
+
|
|
98
|
+
- Basic color usage
|
|
99
|
+
- Text styling
|
|
100
|
+
- Background colors
|
|
101
|
+
- RGB colors
|
|
102
|
+
- Color level switching
|
|
103
|
+
- Terminal detection
|
|
104
|
+
|
|
105
|
+
## Contributing
|
|
106
|
+
|
|
107
|
+
@reliverse/relico is open to contributions. To get started:
|
|
108
|
+
|
|
109
|
+
```sh
|
|
110
|
+
git clone https://github.com/reliverse/relico.git
|
|
111
|
+
cd relico
|
|
112
|
+
bun i
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Learn More
|
|
116
|
+
|
|
117
|
+
- [ANSI Color Codes](https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797)
|
|
118
|
+
|
|
119
|
+
## License
|
|
120
|
+
|
|
121
|
+
[MIT](./LICENSE.md) © [Nazarii Korniienko](https://github.com/blefnk)
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { Static } from "@sinclair/typebox";
|
|
2
|
+
export declare function getCurrentTerminalName(): string;
|
|
3
|
+
export declare const ColorDefinitionSchema: import("@sinclair/typebox").TTuple<[import("@sinclair/typebox").TString, import("@sinclair/typebox").TString, import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>]>;
|
|
4
|
+
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>]>>;
|
|
5
|
+
export declare const RelicoConfigSchema: import("@sinclair/typebox").TObject<{
|
|
6
|
+
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>]>>;
|
|
7
|
+
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>]>>>;
|
|
8
|
+
}>;
|
|
9
|
+
export type RelicoConfig = Static<typeof RelicoConfigSchema>;
|
|
10
|
+
/**
|
|
11
|
+
* Configures the library with a partial or complete `RelicoConfig`.
|
|
12
|
+
* For any invalid fields, a warning is shown and they are ignored.
|
|
13
|
+
*/
|
|
14
|
+
export declare function configure(userInput: unknown): void;
|
|
15
|
+
/** Returns a read-only copy of the current configuration. */
|
|
16
|
+
export declare function getConfig(): RelicoConfig;
|
|
17
|
+
/** Returns a color function by name (or `reset` or identity if not found). */
|
|
18
|
+
export declare function getColor(name: string): (text: string | number) => string;
|
|
19
|
+
/** Colorize text with a color function. */
|
|
20
|
+
export declare function colorize(name: string, text: string | number): string;
|
|
21
|
+
/** Set the color level (0=none,1=basic,2=256,3=truecolor). */
|
|
22
|
+
export declare function setColorLevel(level: 0 | 1 | 2 | 3): void;
|
|
23
|
+
/** Returns a custom "rgb" color function if level=3, otherwise identity. */
|
|
24
|
+
export declare function rgb(r: number, g: number, b: number): (text: string | number) => string;
|
|
25
|
+
export type IRelicoColors = {
|
|
26
|
+
reset(text: string | number): string;
|
|
27
|
+
bold(text: string | number): string;
|
|
28
|
+
dim(text: string | number): string;
|
|
29
|
+
italic(text: string | number): string;
|
|
30
|
+
underline(text: string | number): string;
|
|
31
|
+
inverse(text: string | number): string;
|
|
32
|
+
hidden(text: string | number): string;
|
|
33
|
+
strikethrough(text: string | number): string;
|
|
34
|
+
black(text: string | number): string;
|
|
35
|
+
red(text: string | number): string;
|
|
36
|
+
green(text: string | number): string;
|
|
37
|
+
yellow(text: string | number): string;
|
|
38
|
+
blue(text: string | number): string;
|
|
39
|
+
magenta(text: string | number): string;
|
|
40
|
+
cyan(text: string | number): string;
|
|
41
|
+
white(text: string | number): string;
|
|
42
|
+
gray(text: string | number): string;
|
|
43
|
+
bgBlack(text: string | number): string;
|
|
44
|
+
bgRed(text: string | number): string;
|
|
45
|
+
bgGreen(text: string | number): string;
|
|
46
|
+
bgYellow(text: string | number): string;
|
|
47
|
+
bgBlue(text: string | number): string;
|
|
48
|
+
bgMagenta(text: string | number): string;
|
|
49
|
+
bgCyan(text: string | number): string;
|
|
50
|
+
bgWhite(text: string | number): string;
|
|
51
|
+
blackBright(text: string | number): string;
|
|
52
|
+
redBright(text: string | number): string;
|
|
53
|
+
greenBright(text: string | number): string;
|
|
54
|
+
yellowBright(text: string | number): string;
|
|
55
|
+
blueBright(text: string | number): string;
|
|
56
|
+
magentaBright(text: string | number): string;
|
|
57
|
+
cyanBright(text: string | number): string;
|
|
58
|
+
whiteBright(text: string | number): string;
|
|
59
|
+
bgBlackBright(text: string | number): string;
|
|
60
|
+
bgRedBright(text: string | number): string;
|
|
61
|
+
bgGreenBright(text: string | number): string;
|
|
62
|
+
bgYellowBright(text: string | number): string;
|
|
63
|
+
bgBlueBright(text: string | number): string;
|
|
64
|
+
bgMagentaBright(text: string | number): string;
|
|
65
|
+
bgCyanBright(text: string | number): string;
|
|
66
|
+
bgWhiteBright(text: string | number): string;
|
|
67
|
+
[k: string]: (text: string | number) => string;
|
|
68
|
+
};
|
|
69
|
+
/**
|
|
70
|
+
* The typed `re` object with all known color methods
|
|
71
|
+
* plus user-defined ones (index signature).
|
|
72
|
+
*/
|
|
73
|
+
export declare const re: IRelicoColors;
|
|
74
|
+
export type ColorSupport = {
|
|
75
|
+
isColorSupported: boolean;
|
|
76
|
+
isForced: boolean;
|
|
77
|
+
isDisabled: boolean;
|
|
78
|
+
terminalName: string;
|
|
79
|
+
};
|
|
80
|
+
export declare const colorSupport: ColorSupport;
|
package/dist-npm/main.js
ADDED
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
import { Type } from "@sinclair/typebox";
|
|
2
|
+
import { Value } from "@sinclair/typebox/value";
|
|
3
|
+
import { env, isWindows, isLinux, isMacOS } from "std-env";
|
|
4
|
+
export function getCurrentTerminalName() {
|
|
5
|
+
const termProgram = env["TERM_PROGRAM"];
|
|
6
|
+
const term = env["TERM"];
|
|
7
|
+
const terminalEmulator = env["TERMINAL_EMULATOR"];
|
|
8
|
+
if (termProgram) {
|
|
9
|
+
switch (termProgram.toLowerCase()) {
|
|
10
|
+
case "vscode":
|
|
11
|
+
return "VSCode Terminal";
|
|
12
|
+
case "terminus-sublime":
|
|
13
|
+
return "Terminus Sublime";
|
|
14
|
+
case "hyper":
|
|
15
|
+
return "Hyper";
|
|
16
|
+
case "iterm.app":
|
|
17
|
+
case "iterm":
|
|
18
|
+
return "iTerm2";
|
|
19
|
+
case "alacritty":
|
|
20
|
+
return "Alacritty";
|
|
21
|
+
case "wezterm":
|
|
22
|
+
return "WezTerm";
|
|
23
|
+
case "terminus":
|
|
24
|
+
return "Terminus";
|
|
25
|
+
default:
|
|
26
|
+
return `TERM_PROGRAM: ${termProgram}`;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
if (terminalEmulator) {
|
|
30
|
+
switch (terminalEmulator.toLowerCase()) {
|
|
31
|
+
case "jetbrains-jediterm":
|
|
32
|
+
return "JetBrains JediTerm";
|
|
33
|
+
case "cmder":
|
|
34
|
+
return "Cmder";
|
|
35
|
+
case "conemu":
|
|
36
|
+
return "ConEmu";
|
|
37
|
+
default:
|
|
38
|
+
return `TERMINAL_EMULATOR: ${terminalEmulator}`;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (term) {
|
|
42
|
+
const lowered = term.toLowerCase();
|
|
43
|
+
switch (lowered) {
|
|
44
|
+
case "xterm-256color":
|
|
45
|
+
return "Xterm 256 Color";
|
|
46
|
+
case "alacritty":
|
|
47
|
+
return "Alacritty";
|
|
48
|
+
case "xterm":
|
|
49
|
+
return "Xterm";
|
|
50
|
+
case "linux":
|
|
51
|
+
return "Linux Console Kernel";
|
|
52
|
+
default:
|
|
53
|
+
return `TERM: ${term}`;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (isWindows) {
|
|
57
|
+
return "Windows Terminal";
|
|
58
|
+
} else if (isMacOS) {
|
|
59
|
+
return "macOS Terminal";
|
|
60
|
+
} else if (isLinux) {
|
|
61
|
+
return "Linux Terminal";
|
|
62
|
+
}
|
|
63
|
+
return "Unknown Terminal";
|
|
64
|
+
}
|
|
65
|
+
export const ColorDefinitionSchema = Type.Tuple([
|
|
66
|
+
Type.String(),
|
|
67
|
+
Type.String(),
|
|
68
|
+
Type.Optional(Type.String())
|
|
69
|
+
]);
|
|
70
|
+
export const ColorMapSchema = Type.Record(Type.String(), ColorDefinitionSchema);
|
|
71
|
+
export const RelicoConfigSchema = Type.Object(
|
|
72
|
+
{
|
|
73
|
+
colorLevel: Type.Optional(
|
|
74
|
+
Type.Union([
|
|
75
|
+
Type.Literal(0),
|
|
76
|
+
Type.Literal(1),
|
|
77
|
+
Type.Literal(2),
|
|
78
|
+
Type.Literal(3)
|
|
79
|
+
])
|
|
80
|
+
),
|
|
81
|
+
customColors: Type.Optional(ColorMapSchema)
|
|
82
|
+
},
|
|
83
|
+
{ additionalProperties: false }
|
|
84
|
+
);
|
|
85
|
+
const argv = typeof process === "undefined" ? [] : process.argv;
|
|
86
|
+
const isDisabled = "NO_COLOR" in env || argv.includes("--no-color");
|
|
87
|
+
const isForced = "FORCE_COLOR" in env || argv.includes("--color");
|
|
88
|
+
const isCI = "CI" in env && ("GITHUB_ACTIONS" in env || "GITLAB_CI" in env || "CIRCLECI" in env);
|
|
89
|
+
const isCompatibleTerminal = typeof process !== "undefined" && Boolean(process.stdout) && Boolean(process.stdout.isTTY) && env["TERM"] !== "dumb";
|
|
90
|
+
const colorterm = (env["COLORTERM"] ?? "").toLowerCase();
|
|
91
|
+
const supportsTrueColor = colorterm === "truecolor" || colorterm === "24bit";
|
|
92
|
+
function detectColorLevel() {
|
|
93
|
+
if (isDisabled) return 0;
|
|
94
|
+
if (isForced) return 3;
|
|
95
|
+
if (supportsTrueColor) return 3;
|
|
96
|
+
if (isWindows) return 2;
|
|
97
|
+
if (isCI) return 2;
|
|
98
|
+
if (isCompatibleTerminal) {
|
|
99
|
+
return 2;
|
|
100
|
+
}
|
|
101
|
+
return 0;
|
|
102
|
+
}
|
|
103
|
+
const baseColors = {
|
|
104
|
+
reset: ["\x1B[0m", "\x1B[0m"],
|
|
105
|
+
bold: ["\x1B[1m", "\x1B[22m", "\x1B[22m\x1B[1m"],
|
|
106
|
+
dim: ["\x1B[2m", "\x1B[22m", "\x1B[22m\x1B[2m"],
|
|
107
|
+
italic: ["\x1B[3m", "\x1B[23m"],
|
|
108
|
+
underline: ["\x1B[4m", "\x1B[24m"],
|
|
109
|
+
inverse: ["\x1B[7m", "\x1B[27m"],
|
|
110
|
+
hidden: ["\x1B[8m", "\x1B[28m"],
|
|
111
|
+
strikethrough: ["\x1B[9m", "\x1B[29m"],
|
|
112
|
+
black: ["\x1B[30m", "\x1B[39m"],
|
|
113
|
+
red: ["\x1B[31m", "\x1B[39m"],
|
|
114
|
+
green: ["\x1B[32m", "\x1B[39m"],
|
|
115
|
+
yellow: ["\x1B[33m", "\x1B[39m"],
|
|
116
|
+
blue: ["\x1B[34m", "\x1B[39m"],
|
|
117
|
+
magenta: ["\x1B[35m", "\x1B[39m"],
|
|
118
|
+
cyan: ["\x1B[36m", "\x1B[39m"],
|
|
119
|
+
white: ["\x1B[37m", "\x1B[39m"],
|
|
120
|
+
gray: ["\x1B[90m", "\x1B[39m"],
|
|
121
|
+
bgBlack: ["\x1B[40m", "\x1B[49m"],
|
|
122
|
+
bgRed: ["\x1B[41m", "\x1B[49m"],
|
|
123
|
+
bgGreen: ["\x1B[42m", "\x1B[49m"],
|
|
124
|
+
bgYellow: ["\x1B[43m", "\x1B[49m"],
|
|
125
|
+
bgBlue: ["\x1B[44m", "\x1B[49m"],
|
|
126
|
+
bgMagenta: ["\x1B[45m", "\x1B[49m"],
|
|
127
|
+
bgCyan: ["\x1B[46m", "\x1B[49m"],
|
|
128
|
+
bgWhite: ["\x1B[47m", "\x1B[49m"],
|
|
129
|
+
blackBright: ["\x1B[90m", "\x1B[39m"],
|
|
130
|
+
redBright: ["\x1B[91m", "\x1B[39m"],
|
|
131
|
+
greenBright: ["\x1B[92m", "\x1B[39m"],
|
|
132
|
+
yellowBright: ["\x1B[93m", "\x1B[39m"],
|
|
133
|
+
blueBright: ["\x1B[94m", "\x1B[39m"],
|
|
134
|
+
magentaBright: ["\x1B[95m", "\x1B[39m"],
|
|
135
|
+
cyanBright: ["\x1B[96m", "\x1B[39m"],
|
|
136
|
+
whiteBright: ["\x1B[97m", "\x1B[39m"],
|
|
137
|
+
bgBlackBright: ["\x1B[100m", "\x1B[49m"],
|
|
138
|
+
bgRedBright: ["\x1B[101m", "\x1B[49m"],
|
|
139
|
+
bgGreenBright: ["\x1B[102m", "\x1B[49m"],
|
|
140
|
+
bgYellowBright: ["\x1B[103m", "\x1B[49m"],
|
|
141
|
+
bgBlueBright: ["\x1B[104m", "\x1B[49m"],
|
|
142
|
+
bgMagentaBright: ["\x1B[105m", "\x1B[49m"],
|
|
143
|
+
bgCyanBright: ["\x1B[106m", "\x1B[49m"],
|
|
144
|
+
bgWhiteBright: ["\x1B[107m", "\x1B[49m"]
|
|
145
|
+
};
|
|
146
|
+
const windowsTerminalColors = {
|
|
147
|
+
...baseColors,
|
|
148
|
+
red: ["\x1B[38;2;255;85;85m", "\x1B[39m"],
|
|
149
|
+
green: ["\x1B[38;2;80;250;123m", "\x1B[39m"],
|
|
150
|
+
yellow: ["\x1B[38;2;241;250;140m", "\x1B[39m"],
|
|
151
|
+
blue: ["\x1B[38;2;98;114;164m", "\x1B[39m"],
|
|
152
|
+
magenta: ["\x1B[38;2;255;121;198m", "\x1B[39m"],
|
|
153
|
+
cyan: ["\x1B[38;2;139;233;253m", "\x1B[39m"]
|
|
154
|
+
};
|
|
155
|
+
let config = {
|
|
156
|
+
colorLevel: detectColorLevel()
|
|
157
|
+
};
|
|
158
|
+
let colorMap = {};
|
|
159
|
+
let colorFunctions = {};
|
|
160
|
+
function replaceClose(str, close, replace, index) {
|
|
161
|
+
let result = "";
|
|
162
|
+
let cursor = 0;
|
|
163
|
+
let i = index;
|
|
164
|
+
while (i !== -1) {
|
|
165
|
+
result += str.substring(cursor, i) + replace;
|
|
166
|
+
cursor = i + close.length;
|
|
167
|
+
i = str.indexOf(close, cursor);
|
|
168
|
+
}
|
|
169
|
+
return result + str.substring(cursor);
|
|
170
|
+
}
|
|
171
|
+
function createFormatter(open, close, replace = open) {
|
|
172
|
+
return (input) => {
|
|
173
|
+
const stringed = String(input);
|
|
174
|
+
const idx = stringed.indexOf(close, open.length);
|
|
175
|
+
if (idx !== -1) {
|
|
176
|
+
return open + replaceClose(stringed, close, replace, idx) + close;
|
|
177
|
+
}
|
|
178
|
+
return open + stringed + close;
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
function buildColorMap(cfg) {
|
|
182
|
+
const terminalName = getCurrentTerminalName();
|
|
183
|
+
const isWinTerm = terminalName === "Windows Terminal";
|
|
184
|
+
if (cfg.colorLevel === 0) {
|
|
185
|
+
const map = {};
|
|
186
|
+
for (const k of Object.keys(baseColors)) {
|
|
187
|
+
map[k] = ["", "", ""];
|
|
188
|
+
}
|
|
189
|
+
return map;
|
|
190
|
+
}
|
|
191
|
+
let builtIn;
|
|
192
|
+
if (isWinTerm && cfg.colorLevel === 3) {
|
|
193
|
+
builtIn = { ...windowsTerminalColors };
|
|
194
|
+
} else {
|
|
195
|
+
builtIn = { ...baseColors };
|
|
196
|
+
}
|
|
197
|
+
if (cfg.customColors) {
|
|
198
|
+
for (const [k, v] of Object.entries(cfg.customColors)) {
|
|
199
|
+
builtIn[k] = v;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return builtIn;
|
|
203
|
+
}
|
|
204
|
+
function initColorFunctions() {
|
|
205
|
+
colorFunctions = {};
|
|
206
|
+
if (config.colorLevel === 0) {
|
|
207
|
+
for (const k of Object.keys(baseColors)) {
|
|
208
|
+
colorFunctions[k] = identityColor;
|
|
209
|
+
}
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
for (const [key, [open, close, replace]] of Object.entries(colorMap)) {
|
|
213
|
+
colorFunctions[key] = createFormatter(open, close, replace ?? open);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
function rebuild() {
|
|
217
|
+
colorMap = buildColorMap(config);
|
|
218
|
+
initColorFunctions();
|
|
219
|
+
}
|
|
220
|
+
function identityColor(text) {
|
|
221
|
+
return String(text);
|
|
222
|
+
}
|
|
223
|
+
rebuild();
|
|
224
|
+
export function configure(userInput) {
|
|
225
|
+
let newObj = null;
|
|
226
|
+
if (typeof userInput === "object" && userInput !== null) {
|
|
227
|
+
newObj = { ...config, ...userInput };
|
|
228
|
+
} else {
|
|
229
|
+
newObj = { ...config };
|
|
230
|
+
}
|
|
231
|
+
try {
|
|
232
|
+
const parsed = Value.Cast(RelicoConfigSchema, newObj);
|
|
233
|
+
config = parsed;
|
|
234
|
+
} catch (err) {
|
|
235
|
+
console.warn("Invalid relico config:", err);
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
rebuild();
|
|
239
|
+
}
|
|
240
|
+
export function getConfig() {
|
|
241
|
+
return { ...config };
|
|
242
|
+
}
|
|
243
|
+
export function getColor(name) {
|
|
244
|
+
const maybeFn = colorFunctions[name];
|
|
245
|
+
if (maybeFn) return maybeFn;
|
|
246
|
+
const resetFn = colorFunctions["reset"];
|
|
247
|
+
if (resetFn) return resetFn;
|
|
248
|
+
return identityColor;
|
|
249
|
+
}
|
|
250
|
+
export function colorize(name, text) {
|
|
251
|
+
const fn = getColor(name);
|
|
252
|
+
return fn(text);
|
|
253
|
+
}
|
|
254
|
+
export function setColorLevel(level) {
|
|
255
|
+
configure({ colorLevel: level });
|
|
256
|
+
}
|
|
257
|
+
export function rgb(r, g, b) {
|
|
258
|
+
if (config.colorLevel === 3) {
|
|
259
|
+
const open = `\x1B[38;2;${String(r)};${String(g)};${String(b)}m`;
|
|
260
|
+
const close = "\x1B[39m";
|
|
261
|
+
return createFormatter(open, close);
|
|
262
|
+
}
|
|
263
|
+
return identityColor;
|
|
264
|
+
}
|
|
265
|
+
const typedRe = {
|
|
266
|
+
reset: identityColor,
|
|
267
|
+
bold: identityColor,
|
|
268
|
+
dim: identityColor,
|
|
269
|
+
italic: identityColor,
|
|
270
|
+
underline: identityColor,
|
|
271
|
+
inverse: identityColor,
|
|
272
|
+
hidden: identityColor,
|
|
273
|
+
strikethrough: identityColor,
|
|
274
|
+
black: identityColor,
|
|
275
|
+
red: identityColor,
|
|
276
|
+
green: identityColor,
|
|
277
|
+
yellow: identityColor,
|
|
278
|
+
blue: identityColor,
|
|
279
|
+
magenta: identityColor,
|
|
280
|
+
cyan: identityColor,
|
|
281
|
+
white: identityColor,
|
|
282
|
+
gray: identityColor,
|
|
283
|
+
bgBlack: identityColor,
|
|
284
|
+
bgRed: identityColor,
|
|
285
|
+
bgGreen: identityColor,
|
|
286
|
+
bgYellow: identityColor,
|
|
287
|
+
bgBlue: identityColor,
|
|
288
|
+
bgMagenta: identityColor,
|
|
289
|
+
bgCyan: identityColor,
|
|
290
|
+
bgWhite: identityColor,
|
|
291
|
+
blackBright: identityColor,
|
|
292
|
+
redBright: identityColor,
|
|
293
|
+
greenBright: identityColor,
|
|
294
|
+
yellowBright: identityColor,
|
|
295
|
+
blueBright: identityColor,
|
|
296
|
+
magentaBright: identityColor,
|
|
297
|
+
cyanBright: identityColor,
|
|
298
|
+
whiteBright: identityColor,
|
|
299
|
+
bgBlackBright: identityColor,
|
|
300
|
+
bgRedBright: identityColor,
|
|
301
|
+
bgGreenBright: identityColor,
|
|
302
|
+
bgYellowBright: identityColor,
|
|
303
|
+
bgBlueBright: identityColor,
|
|
304
|
+
bgMagentaBright: identityColor,
|
|
305
|
+
bgCyanBright: identityColor,
|
|
306
|
+
bgWhiteBright: identityColor
|
|
307
|
+
};
|
|
308
|
+
function refreshTypedRe() {
|
|
309
|
+
for (const colorName of Object.keys(typedRe)) {
|
|
310
|
+
typedRe[colorName] = identityColor;
|
|
311
|
+
}
|
|
312
|
+
for (const [k, fn] of Object.entries(colorFunctions)) {
|
|
313
|
+
typedRe[k] = fn;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
const originalRebuild = rebuild;
|
|
317
|
+
function newRebuild() {
|
|
318
|
+
originalRebuild();
|
|
319
|
+
refreshTypedRe();
|
|
320
|
+
}
|
|
321
|
+
rebuild = newRebuild;
|
|
322
|
+
newRebuild();
|
|
323
|
+
export const re = typedRe;
|
|
324
|
+
export const colorSupport = {
|
|
325
|
+
isColorSupported: getConfig().colorLevel !== 0,
|
|
326
|
+
isForced,
|
|
327
|
+
isDisabled,
|
|
328
|
+
terminalName: getCurrentTerminalName()
|
|
329
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@reliverse/relico",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"author": "blefnk",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"description": "@reliverse/relico is doing its best to improve your terminal colorization experience by leveraging TypeScript and TypeBox for enhanced reliability and type safety.",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"dev": "bun examples/example.ts",
|
|
9
|
+
"check": "bun typecheck && bun test && bun knip && bun lint && bun format",
|
|
10
|
+
"build:npm": "unbuild && bun build.optim.ts",
|
|
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 check && 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"
|
|
29
|
+
},
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "git+https://github.com/reliverse/relico.git"
|
|
33
|
+
},
|
|
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
|
+
"@sinclair/typebox": "^0.34.14",
|
|
51
|
+
"confbox": "^0.1.8",
|
|
52
|
+
"destr": "^2.0.3",
|
|
53
|
+
"fs-extra": "^11.3.0",
|
|
54
|
+
"globby": "^14.0.2",
|
|
55
|
+
"mri": "^1.2.0",
|
|
56
|
+
"pathe": "^2.0.2",
|
|
57
|
+
"std-env": "^3.8.0"
|
|
58
|
+
},
|
|
59
|
+
"devDependencies": {
|
|
60
|
+
"@arethetypeswrong/cli": "^0.17.3",
|
|
61
|
+
"@biomejs/biome": "1.9.4",
|
|
62
|
+
"@eslint/js": "^9.18.0",
|
|
63
|
+
"@eslint/json": "^0.9.1",
|
|
64
|
+
"@eslint/markdown": "^6.2.1",
|
|
65
|
+
"@stylistic/eslint-plugin": "^2.13.0",
|
|
66
|
+
"@types/bun": "^1.1.18",
|
|
67
|
+
"@types/eslint__js": "^8.42.3",
|
|
68
|
+
"@types/fs-extra": "^11.0.4",
|
|
69
|
+
"@types/node": "^22.10.7",
|
|
70
|
+
"citty": "^0.1.6",
|
|
71
|
+
"eslint": "^9.18.0",
|
|
72
|
+
"eslint-plugin-perfectionist": "^4.7.0",
|
|
73
|
+
"execa": "^9.5.2",
|
|
74
|
+
"jiti": "^2.4.2",
|
|
75
|
+
"knip": "^5.42.3",
|
|
76
|
+
"typescript": "^5.7.3",
|
|
77
|
+
"typescript-eslint": "^8.21.0",
|
|
78
|
+
"unbuild": "^3.3.1",
|
|
79
|
+
"vitest": "^3.0.3"
|
|
80
|
+
}
|
|
81
|
+
}
|