colorino 0.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.
@@ -0,0 +1,204 @@
1
+ import { err, ok } from 'neverthrow';
2
+
3
+ function hexToRgb(hex) {
4
+ const match = hex.toString().match(/[a-f0-9]{6}|[a-f0-9]{3}/i);
5
+ if (!match) {
6
+ return [0, 0, 0];
7
+ }
8
+ let colorString = match[0];
9
+ if (match[0].length === 3) {
10
+ colorString = [...colorString].map((char) => char + char).join("");
11
+ }
12
+ const integer = parseInt(colorString, 16);
13
+ const r = integer >> 16 & 255;
14
+ const g = integer >> 8 & 255;
15
+ const b = integer & 255;
16
+ return [r, g, b];
17
+ }
18
+ function rgbToAnsi256(rgb) {
19
+ const [r, g, b] = rgb;
20
+ if (r === g && g === b) {
21
+ if (r < 8) return 16;
22
+ if (r > 248) return 231;
23
+ return Math.round((r - 8) / 247 * 24) + 232;
24
+ }
25
+ return 16 + 36 * Math.round(r / 255 * 5) + 6 * Math.round(g / 255 * 5) + Math.round(b / 255 * 5);
26
+ }
27
+ function rgbToHsvValue(rgb) {
28
+ const r = rgb[0] / 255;
29
+ const g = rgb[1] / 255;
30
+ const b = rgb[2] / 255;
31
+ const v = Math.max(r, g, b);
32
+ return v * 100;
33
+ }
34
+ function rgbToAnsi16(rgb) {
35
+ const [r, g, b] = rgb;
36
+ const value = rgbToHsvValue(rgb);
37
+ const roundedValue = Math.round(value / 50);
38
+ if (roundedValue === 0) {
39
+ return 30;
40
+ }
41
+ let ansi = 30 + (Math.round(b / 255) << 2 | Math.round(g / 255) << 1 | Math.round(r / 255));
42
+ if (roundedValue === 2) {
43
+ ansi += 60;
44
+ }
45
+ return ansi;
46
+ }
47
+ const colorConverter = {
48
+ hex: {
49
+ toRgb: hexToRgb,
50
+ toAnsi16: (hex) => rgbToAnsi16(hexToRgb(hex)),
51
+ toAnsi256: (hex) => rgbToAnsi256(hexToRgb(hex))
52
+ }};
53
+
54
+ var ColorLevel = /* @__PURE__ */ ((ColorLevel2) => {
55
+ ColorLevel2[ColorLevel2["NO_COLOR"] = 0] = "NO_COLOR";
56
+ ColorLevel2[ColorLevel2["ANSI"] = 1] = "ANSI";
57
+ ColorLevel2[ColorLevel2["ANSI256"] = 2] = "ANSI256";
58
+ ColorLevel2[ColorLevel2["TRUECOLOR"] = 3] = "TRUECOLOR";
59
+ return ColorLevel2;
60
+ })(ColorLevel || {});
61
+
62
+ function isConsoleMethod(level) {
63
+ return ["log", "info", "warn", "error", "trace", "debug"].includes(level);
64
+ }
65
+
66
+ class Colorino {
67
+ constructor(_palette, _validator, _browserColorSupportDetector, _nodeColorSupportDetector, _options = {}) {
68
+ this._palette = _palette;
69
+ this._validator = _validator;
70
+ this._browserColorSupportDetector = _browserColorSupportDetector;
71
+ this._nodeColorSupportDetector = _nodeColorSupportDetector;
72
+ this._options = _options;
73
+ this._colorLevel = this._detectColorSupport();
74
+ const validatePaletteResult = this._validator.validatePalette(this._palette);
75
+ if (validatePaletteResult.isErr()) throw validatePaletteResult.error;
76
+ if ((this._colorLevel === ColorLevel.NO_COLOR || this._colorLevel === "UnknownEnv") && !this._options.disableWarnings) {
77
+ this._maybeWarnUser();
78
+ }
79
+ }
80
+ _alreadyWarned = false;
81
+ _colorLevel;
82
+ color(level, text) {
83
+ const hex = this._palette[level];
84
+ let ansiCode;
85
+ switch (this._colorLevel) {
86
+ case ColorLevel.TRUECOLOR: {
87
+ const [r, g, b] = colorConverter.hex.toRgb(hex);
88
+ ansiCode = `\x1B[38;2;${r};${g};${b}m`;
89
+ break;
90
+ }
91
+ case ColorLevel.ANSI256: {
92
+ const code = colorConverter.hex.toAnsi256(hex);
93
+ ansiCode = `\x1B[38;5;${code}m`;
94
+ break;
95
+ }
96
+ case ColorLevel.ANSI: {
97
+ const code = colorConverter.hex.toAnsi16(hex);
98
+ if (code < 38) {
99
+ ansiCode = `\x1B[${code}m`;
100
+ } else {
101
+ ansiCode = `\x1B[${code}m`;
102
+ }
103
+ break;
104
+ }
105
+ case "UnknownEnv": {
106
+ return text;
107
+ }
108
+ default:
109
+ return text;
110
+ }
111
+ return `${ansiCode}${text}\x1B[0m`;
112
+ }
113
+ log(...args) {
114
+ this._out("log", args);
115
+ }
116
+ info(...args) {
117
+ this._out("info", args);
118
+ }
119
+ warn(...args) {
120
+ this._out("warn", args);
121
+ }
122
+ error(...args) {
123
+ this._out("error", args);
124
+ }
125
+ trace(...args) {
126
+ this._out("trace", args);
127
+ }
128
+ debug(...args) {
129
+ this._out("debug", args);
130
+ }
131
+ _detectColorSupport() {
132
+ const isBrowserEnv = this._browserColorSupportDetector?.isBrowserEnv();
133
+ if (isBrowserEnv) {
134
+ this._colorLevel = this._browserColorSupportDetector?.getColorLevel() ?? "UnknownEnv";
135
+ return this._colorLevel;
136
+ }
137
+ const isNodeEnv = this._nodeColorSupportDetector?.isNodeEnv();
138
+ if (isNodeEnv) {
139
+ this._colorLevel = this._nodeColorSupportDetector?.getColorLevel() ?? "UnknownEnv";
140
+ return this._colorLevel;
141
+ }
142
+ return "UnknownEnv";
143
+ }
144
+ _maybeWarnUser() {
145
+ if (this._alreadyWarned) return;
146
+ this._alreadyWarned = true;
147
+ console.warn(
148
+ "[Colorino] No ANSI color support detected in this terminal. See https://github.com/chalk/supports-color#support-matrix to learn how to enable terminal color."
149
+ );
150
+ }
151
+ _out(level, args) {
152
+ const processedArgs = args.map(
153
+ (arg) => typeof arg === "string" ? this.color(level, arg) : arg
154
+ );
155
+ if (isConsoleMethod(level)) console[level](...processedArgs);
156
+ else console.log(...processedArgs);
157
+ }
158
+ }
159
+
160
+ class ColorinoError extends Error {
161
+ constructor(message) {
162
+ super(message);
163
+ this.name = "ColorinoError";
164
+ Object.setPrototypeOf(this, ColorinoError.prototype);
165
+ }
166
+ }
167
+ class OscQueryError extends Error {
168
+ constructor(message) {
169
+ super(message);
170
+ this.name = "OscQueryError";
171
+ }
172
+ }
173
+
174
+ class InputValidator {
175
+ validateHex(hex) {
176
+ const trimmedHex = hex.trim();
177
+ const isHexValid = /^#[0-9A-F]{6}$/i.test(trimmedHex);
178
+ if (!isHexValid) {
179
+ return err(new ColorinoError(`Invalid hex color: '${hex}'`));
180
+ }
181
+ return ok(true);
182
+ }
183
+ validatePalette(palette) {
184
+ for (const level in palette) {
185
+ const hex = palette[level];
186
+ const result = this.validateHex(hex);
187
+ if (result.isErr()) {
188
+ return err(result.error);
189
+ }
190
+ }
191
+ return ok(true);
192
+ }
193
+ }
194
+
195
+ const darkDraculaPalette = {
196
+ log: "#f8f8f2",
197
+ debug: "#f1fa8c",
198
+ error: "#ff5555",
199
+ info: " #8be9fd",
200
+ trace: "#bd93f9",
201
+ warn: "#ffb86c"
202
+ };
203
+
204
+ export { ColorLevel as C, InputValidator as I, OscQueryError as O, Colorino as a, darkDraculaPalette as d };
package/package.json ADDED
@@ -0,0 +1,90 @@
1
+ {
2
+ "name": "colorino",
3
+ "version": "0.1.0",
4
+ "description": "A super simple colorized logger that gets the most out of your terminal",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": "simwai",
8
+ "keywords": [
9
+ "color",
10
+ "logger",
11
+ "terminal",
12
+ "ansi",
13
+ "console"
14
+ ],
15
+ "homepage": "https://github.com/simwai/colorino",
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "https://github.com/simwai/colorino.git"
19
+ },
20
+ "bugs": {
21
+ "url": "https://github.com/simwai/colorino/issues"
22
+ },
23
+ "main": "./dist/node.cjs",
24
+ "module": "./dist/browser.mjs",
25
+ "types": "./dist/browser.d.ts",
26
+ "exports": {
27
+ "node": {
28
+ "types": "./dist/node.d.ts",
29
+ "import": "./dist/node.mjs",
30
+ "require": "./dist/node.cjs"
31
+ },
32
+ "browser": {
33
+ "types": "./dist/browser.d.ts",
34
+ "import": "./dist/browser.mjs",
35
+ "require": "./dist/browser.cjs"
36
+ }
37
+ },
38
+ "files": [
39
+ "dist",
40
+ "README.md",
41
+ "package.json",
42
+ "LICENSE"
43
+ ],
44
+ "scripts": {
45
+ "build": "unbuild",
46
+ "lint": "oxlint",
47
+ "lint:fix": "oxlint --fix",
48
+ "format": "npm run lint:fix && oxfmt",
49
+ "format:check": "prettier --check .",
50
+ "check": "npm run lint && npm run format:check",
51
+ "fix": "npm run lint:fix && npm run format",
52
+ "test": "npm run test:node && npm run test:browser",
53
+ "test:node": "vitest run --config vitest.config.ts",
54
+ "test:browser": "vitest run --config vitest.browser.config.ts",
55
+ "test:coverage": "vitest run --config vitest.config.ts --coverage",
56
+ "test:ui": "vitest --ui --config vitest.config.ts",
57
+ "prepublishonly": "npm run build && npm run test:all && npm run check",
58
+ "prepare": "husky"
59
+ },
60
+ "dependencies": {
61
+ "neverthrow": "^8.2.0"
62
+ },
63
+ "devDependencies": {
64
+ "@sindresorhus/tsconfig": "^8.1.0",
65
+ "@types/node": "^24.9.2",
66
+ "@vitest/coverage-v8": "^4.0.6",
67
+ "@vitest/ui": "^4.0.6",
68
+ "husky": "^9.0.0",
69
+ "jsdom": "^27.1.0",
70
+ "lint-staged": "^15.2.0",
71
+ "oxfmt": "^0.9.0",
72
+ "oxlint": "^0.2.0",
73
+ "tsx": "^4.20.6",
74
+ "unbuild": "^3.6.1",
75
+ "vitest": "^4.0.6"
76
+ },
77
+ "lint-staged": {
78
+ "*.{ts,json,md,yml,yaml}": [
79
+ "oxlint --fix",
80
+ "oxfmt"
81
+ ]
82
+ },
83
+ "engines": {
84
+ "node": ">=16.0.0",
85
+ "npm": ">=8.0.0"
86
+ },
87
+ "publishConfig": {
88
+ "access": "public"
89
+ }
90
+ }