@reliverse/relico 1.4.1 → 1.4.2

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/dist/mod.d.ts ADDED
@@ -0,0 +1,51 @@
1
+ type ColorLevel = 0 | 1 | 2 | 3;
2
+ interface Rgb {
3
+ r: number;
4
+ g: number;
5
+ b: number;
6
+ }
7
+ type SgrOp = {
8
+ kind: "style";
9
+ open: number[];
10
+ } | {
11
+ kind: "fg-basic";
12
+ idx: number;
13
+ bright: boolean;
14
+ } | {
15
+ kind: "bg-basic";
16
+ idx: number;
17
+ bright: boolean;
18
+ } | {
19
+ kind: "fg-256";
20
+ code: number;
21
+ } | {
22
+ kind: "bg-256";
23
+ code: number;
24
+ } | {
25
+ kind: "fg-true";
26
+ rgb: Rgb;
27
+ } | {
28
+ kind: "bg-true";
29
+ rgb: Rgb;
30
+ };
31
+ type ApplyInput = string | number;
32
+ type FormatCallable = ((input: ApplyInput) => string) & {
33
+ readonly [OP_SYMBOL]: SgrOp[];
34
+ };
35
+ export type BaseColorName = "black" | "red" | "green" | "yellow" | "blue" | "magenta" | "cyan" | "white" | "gray" | "orange" | "pink" | "purple" | "teal" | "lime" | "brown" | "navy" | "maroon" | "olive" | "silver";
36
+ export type ColorName = BaseColorName | BrightColorName | BgColorName;
37
+ export type BrightColorName = "blackBright" | "redBright" | "greenBright" | "yellowBright" | "blueBright" | "magentaBright" | "cyanBright" | "whiteBright" | "orangeBright" | "pinkBright" | "purpleBright" | "tealBright" | "limeBright" | "brownBright" | "navyBright" | "maroonBright" | "oliveBright" | "silverBright";
38
+ export type BgColorName = `bg${Capitalize<BaseColorName>}` | `bg${Capitalize<BrightColorName>}`;
39
+ export type ReStyleKey = "reset" | "bold" | "dim" | "italic" | "underline" | "inverse" | "hidden" | "strikethrough";
40
+ export type Re = FormatCallable & {
41
+ readonly [K in ReStyleKey]: Re;
42
+ } & {
43
+ readonly [K in ColorName]: Re;
44
+ } & {
45
+ readonly [K in BgColorName]: Re;
46
+ };
47
+ declare const OP_SYMBOL: unique symbol;
48
+ export declare const setColorLevel: (level: ColorLevel) => void;
49
+ export declare const re: Re;
50
+ export declare const chain: (...parts: FormatCallable[]) => Re;
51
+ export {};
@@ -1,110 +1,13 @@
1
- /* @reliverse/relico - Tiny, type-safe terminal color library with chainable API
2
- - Levels: 0 (off), 1 (ANSI 8/bright), 2 (ANSI 256), 3 (Truecolor)
3
- - Named palettes (std, web, grayscale), Bright & Pastel variants, bg-variants
4
- - Chainable: re.bold.red.underline("text"), chain(re.bold, re.red)("text")
5
- - Multiline-safe: styles applied per line with reset to prevent bleed
6
- */
7
-
8
- type ColorLevel = 0 | 1 | 2 | 3;
9
-
10
- interface Rgb {
11
- r: number;
12
- g: number;
13
- b: number;
14
- }
15
-
16
- type SgrOp =
17
- | { kind: "style"; open: number[] } // closed by global reset at line end
18
- | { kind: "fg-basic"; idx: number; bright: boolean }
19
- | { kind: "bg-basic"; idx: number; bright: boolean }
20
- | { kind: "fg-256"; code: number }
21
- | { kind: "bg-256"; code: number }
22
- | { kind: "fg-true"; rgb: Rgb }
23
- | { kind: "bg-true"; rgb: Rgb };
24
-
25
- type ApplyInput = string | number;
26
-
27
- type FormatCallable = ((input: ApplyInput) => string) & { readonly [OP_SYMBOL]: SgrOp[] };
28
-
29
- export type BaseColorName =
30
- | "black"
31
- | "red"
32
- | "green"
33
- | "yellow"
34
- | "blue"
35
- | "magenta"
36
- | "cyan"
37
- | "white"
38
- | "gray"
39
- | "orange"
40
- | "pink"
41
- | "purple"
42
- | "teal"
43
- | "lime"
44
- | "brown"
45
- | "navy"
46
- | "maroon"
47
- | "olive"
48
- | "silver";
49
-
50
- export type ColorName = BaseColorName | BrightColorName | BgColorName;
51
-
52
- export type BrightColorName =
53
- | "blackBright"
54
- | "redBright"
55
- | "greenBright"
56
- | "yellowBright"
57
- | "blueBright"
58
- | "magentaBright"
59
- | "cyanBright"
60
- | "whiteBright"
61
- | "orangeBright"
62
- | "pinkBright"
63
- | "purpleBright"
64
- | "tealBright"
65
- | "limeBright"
66
- | "brownBright"
67
- | "navyBright"
68
- | "maroonBright"
69
- | "oliveBright"
70
- | "silverBright";
71
-
72
- export type BgColorName = `bg${Capitalize<BaseColorName>}` | `bg${Capitalize<BrightColorName>}`;
73
-
74
- export type ReStyleKey =
75
- | "reset"
76
- | "bold"
77
- | "dim"
78
- | "italic"
79
- | "underline"
80
- | "inverse"
81
- | "hidden"
82
- | "strikethrough";
83
-
84
- export type Re = FormatCallable & {
85
- readonly [K in ReStyleKey]: Re;
86
- } & {
87
- readonly [K in ColorName]: Re;
88
- } & {
89
- readonly [K in BgColorName]: Re;
90
- };
91
-
92
1
  const ESC = "\x1B[";
93
2
  const RESET = `${ESC}0m`;
94
- const OP_SYMBOL: unique symbol = Symbol("re.ops");
95
-
96
- // Color level constants
3
+ const OP_SYMBOL = Symbol("re.ops");
97
4
  const COLOR_LEVEL_OFF = 0;
98
5
  const COLOR_LEVEL_BASIC = 1;
99
6
  const COLOR_LEVEL_256 = 2;
100
7
  const COLOR_LEVEL_TRUECOLOR = 3;
101
-
102
- // RGB and byte constants
103
8
  const MIN_BYTE = 0;
104
9
  const MAX_BYTE = 255;
105
10
  const WHITE_RGB = 255;
106
-
107
- // ANSI 256 color constants
108
11
  const ANSI_256_GRAYSCALE_MIN = 8;
109
12
  const ANSI_256_GRAYSCALE_MAX = 248;
110
13
  const ANSI_256_BASE_OFFSET = 16;
@@ -115,14 +18,10 @@ const ANSI_256_BRIGHT_THRESHOLD = 231;
115
18
  const ANSI_256_RGB_LEVELS = 5;
116
19
  const ANSI_256_RGB_RED_MULTIPLIER = 36;
117
20
  const ANSI_256_RGB_GREEN_MULTIPLIER = 6;
118
-
119
- // SGR code constants
120
21
  const SGR_FG_BASE = 30;
121
22
  const SGR_BG_BASE = 40;
122
23
  const SGR_FG_BRIGHT_BASE = 90;
123
24
  const SGR_BG_BRIGHT_BASE = 100;
124
-
125
- // Style SGR codes
126
25
  const SGR_RESET = 0;
127
26
  const SGR_BOLD = 1;
128
27
  const SGR_DIM = 2;
@@ -131,41 +30,25 @@ const SGR_UNDERLINE = 4;
131
30
  const SGR_INVERSE = 7;
132
31
  const SGR_HIDDEN = 8;
133
32
  const SGR_STRIKETHROUGH = 9;
134
-
135
- // Hex parsing constants
136
33
  const HEX_BYTE_LENGTH = 2;
137
34
  const HEX_RED_START = 0;
138
35
  const HEX_GREEN_START = 2;
139
36
  const HEX_BLUE_START = 4;
140
37
  const HEX_BLUE_END = 6;
141
38
  const HEX_RADIX = 16;
142
-
143
- // String processing constants
144
39
  const BRIGHT_SUFFIX_LENGTH = 6;
145
40
  const BG_PREFIX_LENGTH = 2;
146
41
  const BG_COLOR_START = 3;
147
-
148
- // Color mixing constants
149
42
  const BRIGHT_MIX_FACTOR = 0.25;
150
-
151
- // Regex constants
152
43
  const BRIGHT_SUFFIX_REGEX = /Bright$/u;
153
-
154
- let CURRENT_LEVEL: ColorLevel = COLOR_LEVEL_TRUECOLOR;
155
-
156
- export const setColorLevel = (level: ColorLevel): void => {
157
- if (
158
- level !== COLOR_LEVEL_OFF &&
159
- level !== COLOR_LEVEL_BASIC &&
160
- level !== COLOR_LEVEL_256 &&
161
- level !== COLOR_LEVEL_TRUECOLOR
162
- ) {
44
+ let CURRENT_LEVEL = COLOR_LEVEL_TRUECOLOR;
45
+ export const setColorLevel = (level) => {
46
+ if (level !== COLOR_LEVEL_OFF && level !== COLOR_LEVEL_BASIC && level !== COLOR_LEVEL_256 && level !== COLOR_LEVEL_TRUECOLOR) {
163
47
  throw new Error("Invalid color level");
164
48
  }
165
49
  CURRENT_LEVEL = level;
166
50
  };
167
-
168
- const clampByte = (n: number): number => {
51
+ const clampByte = (n) => {
169
52
  if (!Number.isFinite(n)) {
170
53
  return MIN_BYTE;
171
54
  }
@@ -177,24 +60,26 @@ const clampByte = (n: number): number => {
177
60
  }
178
61
  return Math.round(n);
179
62
  };
180
-
181
- // Base 8-color RGB anchors (non-bright)
182
- const BASIC8: Rgb[] = [
183
- { r: 0, g: 0, b: 0 }, // black
184
- { r: 205, g: 0, b: 0 }, // red
185
- { r: 0, g: 205, b: 0 }, // green
186
- { r: 205, g: 205, b: 0 }, // yellow
187
- { r: 0, g: 0, b: 238 }, // blue
188
- { r: 205, g: 0, b: 205 }, // magenta
189
- { r: 0, g: 205, b: 205 }, // cyan
190
- { r: 229, g: 229, b: 229 }, // white (light gray)
63
+ const BASIC8 = [
64
+ { r: 0, g: 0, b: 0 },
65
+ // black
66
+ { r: 205, g: 0, b: 0 },
67
+ // red
68
+ { r: 0, g: 205, b: 0 },
69
+ // green
70
+ { r: 205, g: 205, b: 0 },
71
+ // yellow
72
+ { r: 0, g: 0, b: 238 },
73
+ // blue
74
+ { r: 205, g: 0, b: 205 },
75
+ // magenta
76
+ { r: 0, g: 205, b: 205 },
77
+ // cyan
78
+ { r: 229, g: 229, b: 229 }
79
+ // white (light gray)
191
80
  ];
192
-
193
- // SGR code builders
194
- const sgr = (codes: number[]): string => `${ESC}${codes.join(";")}m`;
195
-
196
- // RGB → closest of BASIC8 index (0..7)
197
- const nearestBasicIndex = (rgb: Rgb): number => {
81
+ const sgr = (codes) => `${ESC}${codes.join(";")}m`;
82
+ const nearestBasicIndex = (rgb) => {
198
83
  let best = 0;
199
84
  let bestDist = Number.POSITIVE_INFINITY;
200
85
  for (let i = 0; i < BASIC8.length; i++) {
@@ -210,10 +95,7 @@ const nearestBasicIndex = (rgb: Rgb): number => {
210
95
  }
211
96
  return best;
212
97
  };
213
-
214
- // RGB → ANSI 256 index
215
- const rgbToAnsi256 = (rgb: Rgb): number => {
216
- // Try grayscale if r≈g≈b
98
+ const rgbToAnsi256 = (rgb) => {
217
99
  if (rgb.r === rgb.g && rgb.g === rgb.b) {
218
100
  if (rgb.r < ANSI_256_GRAYSCALE_MIN) {
219
101
  return ANSI_256_BASE_OFFSET;
@@ -222,20 +104,16 @@ const rgbToAnsi256 = (rgb: Rgb): number => {
222
104
  return ANSI_256_BRIGHT_THRESHOLD;
223
105
  }
224
106
  const step = Math.round(
225
- ((rgb.r - ANSI_256_GRAYSCALE_MIN) / ANSI_256_GRAYSCALE_RANGE) * ANSI_256_GRAYSCALE_STEPS,
107
+ (rgb.r - ANSI_256_GRAYSCALE_MIN) / ANSI_256_GRAYSCALE_RANGE * ANSI_256_GRAYSCALE_STEPS
226
108
  );
227
109
  return ANSI_256_GRAYSCALE_BASE + step;
228
110
  }
229
- const r = Math.round((rgb.r / MAX_BYTE) * ANSI_256_RGB_LEVELS);
230
- const g = Math.round((rgb.g / MAX_BYTE) * ANSI_256_RGB_LEVELS);
231
- const b = Math.round((rgb.b / MAX_BYTE) * ANSI_256_RGB_LEVELS);
232
- return (
233
- ANSI_256_BASE_OFFSET + ANSI_256_RGB_RED_MULTIPLIER * r + ANSI_256_RGB_GREEN_MULTIPLIER * g + b
234
- );
111
+ const r = Math.round(rgb.r / MAX_BYTE * ANSI_256_RGB_LEVELS);
112
+ const g = Math.round(rgb.g / MAX_BYTE * ANSI_256_RGB_LEVELS);
113
+ const b = Math.round(rgb.b / MAX_BYTE * ANSI_256_RGB_LEVELS);
114
+ return ANSI_256_BASE_OFFSET + ANSI_256_RGB_RED_MULTIPLIER * r + ANSI_256_RGB_GREEN_MULTIPLIER * g + b;
235
115
  };
236
-
237
- // Color data
238
- const NAMED_COLORS: Record<BaseColorName, string> = {
116
+ const NAMED_COLORS = {
239
117
  black: "#000000",
240
118
  red: "#ff0000",
241
119
  green: "#00ff00",
@@ -254,34 +132,27 @@ const NAMED_COLORS: Record<BaseColorName, string> = {
254
132
  navy: "#000080",
255
133
  maroon: "#800000",
256
134
  olive: "#808000",
257
- silver: "#c0c0c0",
135
+ silver: "#c0c0c0"
258
136
  };
259
-
260
- const mixWithWhite = (rgb: Rgb, factor: number): Rgb => {
137
+ const mixWithWhite = (rgb, factor) => {
261
138
  const t = factor;
262
139
  return {
263
140
  r: clampByte(rgb.r * (1 - t) + WHITE_RGB * t),
264
141
  g: clampByte(rgb.g * (1 - t) + WHITE_RGB * t),
265
- b: clampByte(rgb.b * (1 - t) + WHITE_RGB * t),
142
+ b: clampByte(rgb.b * (1 - t) + WHITE_RGB * t)
266
143
  };
267
144
  };
268
-
269
- const fromNamed = (name: BaseColorName): Rgb => {
145
+ const fromNamed = (name) => {
270
146
  const hex = NAMED_COLORS[name];
271
147
  if (!hex || typeof hex !== "string") {
272
- // Return black as fallback for invalid color names
273
148
  return { r: 0, g: 0, b: 0 };
274
149
  }
275
- // Simple hex to RGB conversion for named colors only
276
150
  const clean = hex.startsWith("#") ? hex.slice(1) : hex;
277
151
  if (clean.length !== HEX_BLUE_END && clean.length !== 3) {
278
- // Return black as fallback for invalid hex format
279
152
  return { r: 0, g: 0, b: 0 };
280
153
  }
281
-
282
- let rHex: string, gHex: string, bHex: string;
154
+ let rHex, gHex, bHex;
283
155
  if (clean.length === 3) {
284
- // Expand short hex format (e.g., "abc" -> "aabbcc")
285
156
  rHex = clean[0].repeat(2);
286
157
  gHex = clean[1].repeat(2);
287
158
  bHex = clean[2].repeat(2);
@@ -290,48 +161,38 @@ const fromNamed = (name: BaseColorName): Rgb => {
290
161
  gHex = clean.slice(HEX_GREEN_START, HEX_BLUE_START);
291
162
  bHex = clean.slice(HEX_BLUE_START, HEX_BLUE_END);
292
163
  }
293
-
294
164
  const r = Number.parseInt(rHex, HEX_RADIX);
295
165
  const g = Number.parseInt(gHex, HEX_RADIX);
296
166
  const b = Number.parseInt(bHex, HEX_RADIX);
297
-
298
- // Validate parsed RGB values
299
167
  if (Number.isNaN(r) || Number.isNaN(g) || Number.isNaN(b)) {
300
168
  return { r: 0, g: 0, b: 0 };
301
169
  }
302
-
303
170
  return { r, g, b };
304
171
  };
305
-
306
- const toBaseName = (compound: BrightColorName): BaseColorName => {
172
+ const toBaseName = (compound) => {
307
173
  if (!compound || typeof compound !== "string") {
308
- return "black"; // fallback for invalid input
174
+ return "black";
309
175
  }
310
176
  const base = compound.replace(BRIGHT_SUFFIX_REGEX, "");
311
177
  if (!base) {
312
- return "black"; // fallback for empty result
178
+ return "black";
313
179
  }
314
180
  const key = base.charAt(0).toLowerCase() + base.slice(1);
315
- return key as BaseColorName;
181
+ return key;
316
182
  };
317
-
318
- const parseColorName = (name: ColorName): { rgb: Rgb; wantBright: boolean } => {
183
+ const parseColorName = (name) => {
319
184
  if (!name || typeof name !== "string") {
320
- // Return black as fallback for invalid input
321
185
  return { rgb: { r: 0, g: 0, b: 0 }, wantBright: false };
322
186
  }
323
-
324
187
  if (name.endsWith("Bright")) {
325
- const base = toBaseName(name as BrightColorName);
188
+ const base = toBaseName(name);
326
189
  const rgb = fromNamed(base);
327
- // Lighten a bit in high levels; level 1 will use bright SGR
328
190
  const rgbAdj = mixWithWhite(rgb, BRIGHT_MIX_FACTOR);
329
191
  return { rgb: rgbAdj, wantBright: true };
330
192
  }
331
- return { rgb: fromNamed(name as BaseColorName), wantBright: false };
193
+ return { rgb: fromNamed(name), wantBright: false };
332
194
  };
333
-
334
- const openForOp = (op: SgrOp): string => {
195
+ const openForOp = (op) => {
335
196
  if (CURRENT_LEVEL === COLOR_LEVEL_OFF) {
336
197
  return "";
337
198
  }
@@ -354,8 +215,7 @@ const openForOp = (op: SgrOp): string => {
354
215
  return "";
355
216
  }
356
217
  };
357
-
358
- const opsToOpen = (ops: SgrOp[]): string => {
218
+ const opsToOpen = (ops) => {
359
219
  if (CURRENT_LEVEL === COLOR_LEVEL_OFF) {
360
220
  return "";
361
221
  }
@@ -365,25 +225,17 @@ const opsToOpen = (ops: SgrOp[]): string => {
365
225
  }
366
226
  return out;
367
227
  };
368
-
369
- // Optimized multiline processing with fewer allocations and branches
370
- const applyOpsToText = (ops: SgrOp[], input: ApplyInput): string => {
228
+ const applyOpsToText = (ops, input) => {
371
229
  const text = String(input);
372
230
  if (CURRENT_LEVEL === COLOR_LEVEL_OFF || ops.length === 0 || text.length === 0) {
373
231
  return text;
374
232
  }
375
-
376
233
  const open = opsToOpen(ops);
377
-
378
- // Fast path for single-line text (most common case)
379
234
  if (!text.includes("\n")) {
380
235
  return `${open}${text}${RESET}`;
381
236
  }
382
-
383
- // Optimized multiline handling with pre-calculated string lengths
384
237
  const lines = text.split("\n");
385
238
  const result = new Array(lines.length);
386
-
387
239
  for (let i = 0; i < lines.length; i++) {
388
240
  const line = lines[i];
389
241
  if (line.endsWith("\r")) {
@@ -392,12 +244,9 @@ const applyOpsToText = (ops: SgrOp[], input: ApplyInput): string => {
392
244
  result[i] = `${open}${line}${RESET}`;
393
245
  }
394
246
  }
395
-
396
247
  return result.join("\n");
397
248
  };
398
-
399
- // Build operations for a color request according to CURRENT_LEVEL
400
- const mkFgOpsFromRgb = (rgb: Rgb, wantBright = false): SgrOp[] => {
249
+ const mkFgOpsFromRgb = (rgb, wantBright = false) => {
401
250
  if (CURRENT_LEVEL === COLOR_LEVEL_BASIC) {
402
251
  const idx = nearestBasicIndex(rgb);
403
252
  return [{ kind: "fg-basic", idx, bright: wantBright }];
@@ -407,8 +256,7 @@ const mkFgOpsFromRgb = (rgb: Rgb, wantBright = false): SgrOp[] => {
407
256
  }
408
257
  return [{ kind: "fg-true", rgb }];
409
258
  };
410
-
411
- const mkBgOpsFromRgb = (rgb: Rgb, wantBright = false): SgrOp[] => {
259
+ const mkBgOpsFromRgb = (rgb, wantBright = false) => {
412
260
  if (CURRENT_LEVEL === COLOR_LEVEL_BASIC) {
413
261
  const idx = nearestBasicIndex(rgb);
414
262
  return [{ kind: "bg-basic", idx, bright: wantBright }];
@@ -418,9 +266,7 @@ const mkBgOpsFromRgb = (rgb: Rgb, wantBright = false): SgrOp[] => {
418
266
  }
419
267
  return [{ kind: "bg-true", rgb }];
420
268
  };
421
-
422
- // Style ops
423
- const STYLE_TABLE: Record<ReStyleKey, SgrOp> = {
269
+ const STYLE_TABLE = {
424
270
  reset: { kind: "style", open: [SGR_RESET] },
425
271
  bold: { kind: "style", open: [SGR_BOLD] },
426
272
  dim: { kind: "style", open: [SGR_DIM] },
@@ -428,11 +274,9 @@ const STYLE_TABLE: Record<ReStyleKey, SgrOp> = {
428
274
  underline: { kind: "style", open: [SGR_UNDERLINE] },
429
275
  inverse: { kind: "style", open: [SGR_INVERSE] },
430
276
  hidden: { kind: "style", open: [SGR_HIDDEN] },
431
- strikethrough: { kind: "style", open: [SGR_STRIKETHROUGH] },
277
+ strikethrough: { kind: "style", open: [SGR_STRIKETHROUGH] }
432
278
  };
433
-
434
- // Lookup maps
435
- const STYLE_KEYS = new Set([
279
+ const STYLE_KEYS = /* @__PURE__ */ new Set([
436
280
  "reset",
437
281
  "bold",
438
282
  "dim",
@@ -440,93 +284,72 @@ const STYLE_KEYS = new Set([
440
284
  "underline",
441
285
  "inverse",
442
286
  "hidden",
443
- "strikethrough",
287
+ "strikethrough"
444
288
  ]);
445
-
446
- // Direct color/bg key checks
447
- const isColorKey = (key: string): boolean => {
289
+ const isColorKey = (key) => {
448
290
  if (!key || typeof key !== "string") {
449
291
  return false;
450
292
  }
451
- // Base colors and extended colors
452
293
  if (key in NAMED_COLORS) {
453
294
  return true;
454
295
  }
455
- // Bright variants
456
296
  if (key.endsWith("Bright") && key.length > BRIGHT_SUFFIX_LENGTH) {
457
297
  const baseName = key.slice(0, -BRIGHT_SUFFIX_LENGTH);
458
298
  return baseName in NAMED_COLORS;
459
299
  }
460
300
  return false;
461
301
  };
462
-
463
- const isBgKey = (key: string): boolean => {
302
+ const isBgKey = (key) => {
464
303
  if (!key || typeof key !== "string" || !key.startsWith("bg") || key.length <= BG_PREFIX_LENGTH) {
465
304
  return false;
466
305
  }
467
306
  const colorPart = key.charAt(BG_PREFIX_LENGTH).toLowerCase() + key.slice(BG_COLOR_START);
468
307
  return isColorKey(colorPart);
469
308
  };
470
-
471
- // Proxy with performance through pre-computed lookups
472
- const callableProxy = (ops: SgrOp[]): Re => {
473
- const base = ((input: ApplyInput) => applyOpsToText(ops, input)) as FormatCallable;
309
+ const callableProxy = (ops) => {
310
+ const base = ((input) => applyOpsToText(ops, input));
474
311
  Object.defineProperty(base, OP_SYMBOL, {
475
312
  value: ops,
476
313
  enumerable: false,
477
314
  configurable: false,
478
- writable: false,
315
+ writable: false
479
316
  });
480
-
481
- return new Proxy(base as unknown as Re, {
317
+ return new Proxy(base, {
482
318
  apply(_target, _thisArg, argArray) {
483
- const [input] = argArray as [ApplyInput];
319
+ const [input] = argArray;
484
320
  return applyOpsToText(ops, input);
485
321
  },
486
322
  get(_target, prop) {
487
323
  const key = String(prop);
488
-
489
- // Ops extractor for chain()
490
324
  if (prop === OP_SYMBOL) {
491
325
  return ops;
492
326
  }
493
-
494
- // Fast path for styles using Set lookup
495
327
  if (STYLE_KEYS.has(key)) {
496
- const op = STYLE_TABLE[key as ReStyleKey];
328
+ const op = STYLE_TABLE[key];
497
329
  return callableProxy([...ops, op]);
498
330
  }
499
-
500
- // Fast path for colors
501
331
  if (isBgKey(key)) {
502
- const raw = key.slice(BG_PREFIX_LENGTH); // remove 'bg'
332
+ const raw = key.slice(BG_PREFIX_LENGTH);
503
333
  if (!raw) {
504
- return callableProxy(ops); // no-op for empty color name
334
+ return callableProxy(ops);
505
335
  }
506
336
  const colorName = raw.charAt(0).toLowerCase() + raw.slice(1);
507
- const { rgb, wantBright } = parseColorName(colorName as ColorName);
337
+ const { rgb, wantBright } = parseColorName(colorName);
508
338
  return callableProxy([...ops, ...mkBgOpsFromRgb(rgb, wantBright)]);
509
339
  }
510
-
511
340
  if (isColorKey(key)) {
512
- const { rgb, wantBright } = parseColorName(key as ColorName);
341
+ const { rgb, wantBright } = parseColorName(key);
513
342
  return callableProxy([...ops, ...mkFgOpsFromRgb(rgb, wantBright)]);
514
343
  }
515
-
516
- // Unknown key → return self (no-op), keeps chain resilient
517
344
  return callableProxy(ops);
518
- },
345
+ }
519
346
  });
520
347
  };
521
-
522
- // Public root
523
- export const re: Re = callableProxy([]);
524
-
525
- // chain(re.bold, re.red, re.underline)("text")
526
- export const chain = (...parts: FormatCallable[]): Re => {
527
- const collected: SgrOp[] = [];
348
+ export const re = callableProxy([]);
349
+ export const chain = (...parts) => {
350
+ const collected = [];
528
351
  for (const p of parts) {
529
- const ops = (p as FormatCallable)[OP_SYMBOL] as SgrOp[] | undefined;
352
+ const ops = p[OP_SYMBOL];
530
353
  if (ops && ops.length > 0) {
531
354
  for (const op of ops) {
532
355
  collected.push(op);
package/package.json CHANGED
@@ -1,25 +1,21 @@
1
1
  {
2
2
  "name": "@reliverse/relico",
3
3
  "author": "reliverse",
4
- "version": "1.4.1",
4
+ "version": "1.4.2",
5
5
  "type": "module",
6
6
  "description": "@reliverse/relico is a themeable, chainable, typed, truecolor-powered, modern terminal styling toolkit. Designed to make your CLI output colorful, accessible, and human-friendly. It gives you a flexible way to apply colors and styles — with reliability and a smart developer experience baked in. Built for humans, not just terminals.",
7
- "scripts": {
8
- "pub": "bun rse publish",
9
- "dev": "bun examples/core.ts",
10
- "perf": "bun bench && bun size",
11
- "latest": "bun rse update && bun install",
12
- "size": "bun examples/benchmarks/bundle-size.ts",
13
- "bench": "bun examples/benchmarks/performance.ts",
14
- "check": "bun tsc --noEmit && bun biome check --fix --unsafe"
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/mod.d.ts",
10
+ "default": "./dist/mod.js"
11
+ }
15
12
  },
16
- "devDependencies": {
17
- "@biomejs/biome": "2.2.2",
18
- "@reliverse/rse": "^1.7.27",
19
- "@total-typescript/ts-reset": "^0.6.1",
20
- "@types/bun": "^1.2.21",
21
- "@types/node": "^24.3.0",
22
- "typescript": "^5.9.2",
23
- "ultracite": "^5.2.17"
24
- }
25
- }
13
+ "files": [
14
+ "dist",
15
+ "package.json"
16
+ ],
17
+ "publishConfig": {
18
+ "access": "public"
19
+ },
20
+ "license": "MIT"
21
+ }
@@ -1,8 +0,0 @@
1
- {
2
- "recommendations": [
3
- "fabiospampinato.vscode-open-multiple-files",
4
- "davidanson.vscode-markdownlint",
5
- "usernamehw.errorlens",
6
- "yoavbls.pretty-ts-errors"
7
- ]
8
- }