@ix-xs/node-comfort 1.2.0 → 2.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.
Files changed (75) hide show
  1. package/CHANGELOG.md +190 -0
  2. package/README.md +136 -549
  3. package/index.js +80 -35
  4. package/package.json +160 -33
  5. package/src/Arr.js +887 -419
  6. package/src/Async.js +585 -0
  7. package/src/Cache.js +329 -0
  8. package/src/Checker.js +971 -539
  9. package/src/Cli.js +1034 -0
  10. package/src/Color.js +415 -0
  11. package/src/Crypto.js +707 -0
  12. package/src/Emitter.js +289 -0
  13. package/src/Env.js +555 -0
  14. package/src/FS.js +1483 -894
  15. package/src/Func.js +670 -353
  16. package/src/Http.js +538 -0
  17. package/src/Id.js +384 -201
  18. package/src/Logger.js +739 -378
  19. package/src/Num.js +844 -361
  20. package/src/Obj.js +855 -372
  21. package/src/SQLite.js +1308 -1005
  22. package/src/Schema.js +1586 -0
  23. package/src/Str.js +983 -436
  24. package/src/Sys.js +511 -0
  25. package/src/Time.js +1260 -422
  26. package/src/Utils.js +321 -325
  27. package/src/errors.js +292 -0
  28. package/types/index.d.ts +693 -526
  29. package/types/src/Arr.d.ts +455 -145
  30. package/types/src/Arr.d.ts.map +1 -1
  31. package/types/src/Async.d.ts +321 -0
  32. package/types/src/Async.d.ts.map +1 -0
  33. package/types/src/Cache.d.ts +195 -0
  34. package/types/src/Cache.d.ts.map +1 -0
  35. package/types/src/Checker.d.ts +501 -235
  36. package/types/src/Checker.d.ts.map +1 -1
  37. package/types/src/Cli.d.ts +582 -0
  38. package/types/src/Cli.d.ts.map +1 -0
  39. package/types/src/Color.d.ts +294 -0
  40. package/types/src/Color.d.ts.map +1 -0
  41. package/types/src/Crypto.d.ts +534 -0
  42. package/types/src/Crypto.d.ts.map +1 -0
  43. package/types/src/Emitter.d.ts +170 -0
  44. package/types/src/Emitter.d.ts.map +1 -0
  45. package/types/src/Env.d.ts +382 -0
  46. package/types/src/Env.d.ts.map +1 -0
  47. package/types/src/FS.d.ts +686 -238
  48. package/types/src/FS.d.ts.map +1 -1
  49. package/types/src/Func.d.ts +380 -135
  50. package/types/src/Func.d.ts.map +1 -1
  51. package/types/src/Http.d.ts +374 -0
  52. package/types/src/Http.d.ts.map +1 -0
  53. package/types/src/Id.d.ts +149 -68
  54. package/types/src/Id.d.ts.map +1 -1
  55. package/types/src/Logger.d.ts +363 -46
  56. package/types/src/Logger.d.ts.map +1 -1
  57. package/types/src/Num.d.ts +473 -137
  58. package/types/src/Num.d.ts.map +1 -1
  59. package/types/src/Obj.d.ts +390 -104
  60. package/types/src/Obj.d.ts.map +1 -1
  61. package/types/src/SQLite.d.ts +646 -309
  62. package/types/src/SQLite.d.ts.map +1 -1
  63. package/types/src/Schema.d.ts +940 -0
  64. package/types/src/Schema.d.ts.map +1 -0
  65. package/types/src/Str.d.ts +569 -166
  66. package/types/src/Str.d.ts.map +1 -1
  67. package/types/src/Sys.d.ts +269 -0
  68. package/types/src/Sys.d.ts.map +1 -0
  69. package/types/src/Time.d.ts +663 -204
  70. package/types/src/Time.d.ts.map +1 -1
  71. package/types/src/Utils.d.ts +154 -102
  72. package/types/src/Utils.d.ts.map +1 -1
  73. package/types/src/errors.d.ts +292 -0
  74. package/types/src/errors.d.ts.map +1 -0
  75. package/types/index.d.ts.map +0 -1
package/src/Color.js ADDED
@@ -0,0 +1,415 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Terminal colors you can chain, like `chalk`. Truecolor is supported and
5
+ * downgraded on older terminals. Colors switch off by themselves when the
6
+ * output isn't a terminal or `NO_COLOR` is set; `FORCE_COLOR=1|2|3` turns
7
+ * them back on.
8
+ *
9
+ * @example
10
+ * console.log(color.green.bold("✔ Done"), color.gray("in 1.2s"));
11
+ * console.log(color.bgHex("#1e1e2e").hex("#cba6f7")(" nc "));
12
+ * console.log(color.gradient("node-comfort", ["#ff5f6d", "#ffc371"]));
13
+ */
14
+
15
+ /**
16
+ * Every named style.
17
+ * @typedef {"reset" | "bold" | "dim" | "italic" | "underline" | "overline" | "inverse" | "hidden" | "strikethrough"
18
+ * | "black" | "red" | "green" | "yellow" | "blue" | "magenta" | "cyan" | "white" | "gray" | "grey"
19
+ * | "blackBright" | "redBright" | "greenBright" | "yellowBright" | "blueBright" | "magentaBright" | "cyanBright" | "whiteBright"
20
+ * | "bgBlack" | "bgRed" | "bgGreen" | "bgYellow" | "bgBlue" | "bgMagenta" | "bgCyan" | "bgWhite" | "bgGray" | "bgGrey"
21
+ * | "bgBlackBright" | "bgRedBright" | "bgGreenBright" | "bgYellowBright" | "bgBlueBright" | "bgMagentaBright" | "bgCyanBright" | "bgWhiteBright"} StyleName
22
+ */
23
+
24
+ /**
25
+ * How many colors the terminal can show: `0` none, `1` 16, `2` 256, `3` millions.
26
+ * @typedef {0 | 1 | 2 | 3} ColorLevel
27
+ */
28
+
29
+ /**
30
+ * The named styles. Each one can be called on text or chained with others:
31
+ * `color.red("x")`, `color.red.bold.underline("x")`.
32
+ * @typedef {object} ColorStyleProps
33
+ * @property {ColorChain} reset Removes all styles.
34
+ * @property {ColorChain} bold Bold text.
35
+ * @property {ColorChain} dim Faint text.
36
+ * @property {ColorChain} italic Italic text, where the terminal supports it.
37
+ * @property {ColorChain} underline Underlined text.
38
+ * @property {ColorChain} overline Line above the text, where supported.
39
+ * @property {ColorChain} inverse Swaps text and background colors.
40
+ * @property {ColorChain} hidden Invisible text, still copyable.
41
+ * @property {ColorChain} strikethrough Crossed-out text.
42
+ * @property {ColorChain} black Black text.
43
+ * @property {ColorChain} red Red text.
44
+ * @property {ColorChain} green Green text.
45
+ * @property {ColorChain} yellow Yellow text.
46
+ * @property {ColorChain} blue Blue text.
47
+ * @property {ColorChain} magenta Magenta text.
48
+ * @property {ColorChain} cyan Cyan text.
49
+ * @property {ColorChain} white White text.
50
+ * @property {ColorChain} gray Gray text.
51
+ * @property {ColorChain} grey Same as `gray`.
52
+ * @property {ColorChain} blackBright Bright black text.
53
+ * @property {ColorChain} redBright Bright red text.
54
+ * @property {ColorChain} greenBright Bright green text.
55
+ * @property {ColorChain} yellowBright Bright yellow text.
56
+ * @property {ColorChain} blueBright Bright blue text.
57
+ * @property {ColorChain} magentaBright Bright magenta text.
58
+ * @property {ColorChain} cyanBright Bright cyan text.
59
+ * @property {ColorChain} whiteBright Bright white text.
60
+ * @property {ColorChain} bgBlack Black background.
61
+ * @property {ColorChain} bgRed Red background.
62
+ * @property {ColorChain} bgGreen Green background.
63
+ * @property {ColorChain} bgYellow Yellow background.
64
+ * @property {ColorChain} bgBlue Blue background.
65
+ * @property {ColorChain} bgMagenta Magenta background.
66
+ * @property {ColorChain} bgCyan Cyan background.
67
+ * @property {ColorChain} bgWhite White background.
68
+ * @property {ColorChain} bgGray Gray background.
69
+ * @property {ColorChain} bgGrey Same as `bgGray`.
70
+ * @property {ColorChain} bgBlackBright Bright black background.
71
+ * @property {ColorChain} bgRedBright Bright red background.
72
+ * @property {ColorChain} bgGreenBright Bright green background.
73
+ * @property {ColorChain} bgYellowBright Bright yellow background.
74
+ * @property {ColorChain} bgBlueBright Bright blue background.
75
+ * @property {ColorChain} bgMagentaBright Bright magenta background.
76
+ * @property {ColorChain} bgCyanBright Bright cyan background.
77
+ * @property {ColorChain} bgWhiteBright Bright white background.
78
+ */
79
+
80
+ /**
81
+ * The named styles, read-only.
82
+ * @typedef {Readonly<ColorStyleProps>} ColorStyles
83
+ */
84
+
85
+ /**
86
+ * A style you can call on text, or chain with more styles.
87
+ *
88
+ * @typedef {((...text: unknown[]) => string) & ColorStyles & ColorMethods} ColorChain
89
+ */
90
+
91
+ /**
92
+ * Custom colors, available on every chain.
93
+ * @typedef {object} ColorMethods
94
+ * @property {(r: number, g: number, b: number) => ColorChain} rgb Text color from red, green and blue (0-255).
95
+ * @property {(r: number, g: number, b: number) => ColorChain} bgRgb Background from red, green and blue (0-255).
96
+ * @property {(hex: string) => ColorChain} hex Text color from a hex code like `"#f80"`.
97
+ * @property {(hex: string) => ColorChain} bgHex Background from a hex code.
98
+ * @property {(code: number) => ColorChain} ansi256 Text color from the 256-color palette.
99
+ * @property {(code: number) => ColorChain} bgAnsi256 Background from the 256-color palette.
100
+ */
101
+
102
+ /**
103
+ * `nc.color`: every style and color, plus a few helpers.
104
+ *
105
+ * @typedef {ColorStyles & ColorMethods & ColorHelpers} ColorModule
106
+ */
107
+
108
+ /**
109
+ * Color helpers.
110
+ * @typedef {object} ColorHelpers
111
+ * @property {ColorLevel} level The current color level. Set it to force one; `0` turns colors off.
112
+ * @property {boolean} enabled Whether colors are being output.
113
+ * @property {(level?: ColorLevel) => ColorModule} create A separate instance with its own level, for another stream or for tests.
114
+ * @property {(stream?: NodeJS.WriteStream | { isTTY?: boolean }) => ColorLevel} detect The color level a stream supports, taking `NO_COLOR` and `FORCE_COLOR` into account.
115
+ * @property {(text: string) => string} strip Removes colors and other terminal escape codes.
116
+ * @property {(text: string) => number} width How many columns the text takes, ignoring colors and counting emoji and CJK as 2.
117
+ * @property {(text: string, url: string) => string} link A clickable link in terminals that support it, `"text (url)"` elsewhere.
118
+ * @property {(text: string, colors: string[]) => string} gradient Colors the text along a gradient of hex colors.
119
+ */
120
+
121
+ /** @type {Record<string, [number, number]>} */
122
+ const _CODES = {
123
+ reset: [0, 0], bold: [1, 22], dim: [2, 22], italic: [3, 23], underline: [4, 24], overline: [53, 55],
124
+ inverse: [7, 27], hidden: [8, 28], strikethrough: [9, 29],
125
+ black: [30, 39], red: [31, 39], green: [32, 39], yellow: [33, 39], blue: [34, 39], magenta: [35, 39], cyan: [36, 39], white: [37, 39],
126
+ gray: [90, 39], grey: [90, 39], blackBright: [90, 39], redBright: [91, 39], greenBright: [92, 39], yellowBright: [93, 39],
127
+ blueBright: [94, 39], magentaBright: [95, 39], cyanBright: [96, 39], whiteBright: [97, 39],
128
+ bgBlack: [40, 49], bgRed: [41, 49], bgGreen: [42, 49], bgYellow: [43, 49], bgBlue: [44, 49], bgMagenta: [45, 49], bgCyan: [46, 49], bgWhite: [47, 49],
129
+ bgGray: [100, 49], bgGrey: [100, 49], bgBlackBright: [100, 49], bgRedBright: [101, 49], bgGreenBright: [102, 49], bgYellowBright: [103, 49],
130
+ bgBlueBright: [104, 49], bgMagentaBright: [105, 49], bgCyanBright: [106, 49], bgWhiteBright: [107, 49],
131
+ };
132
+
133
+ /**
134
+ * A style in a chain: fixed codes, or a color resolved at output time.
135
+ * @typedef {{ open: string, close: string } | { rgb: [number, number, number], bg: boolean } | { ansi256: number, bg: boolean }} StyleEntry
136
+ */
137
+
138
+ const _ANSI_REGEX = /[\u001b\u009b](?:\][^\u0007\u001b]*(?:\u0007|\u001b\\)|[[\]()#;?]*(?:\d{1,4}(?:[;:]\d{0,4})*)?[\dA-PR-TZcf-nq-uy=><~])/g;
139
+
140
+ /**
141
+ * @param {string} hex
142
+ * @returns {[number, number, number]}
143
+ */
144
+ const _hexToRgb = (hex) => {
145
+ const clean = String(hex).replace(/^#/, "");
146
+ const full = clean.length === 3 || clean.length === 4 ? [...clean.slice(0, 3)].map((c) => c + c).join("") : clean.slice(0, 6);
147
+ if (!/^[0-9a-f]{6}$/i.test(full)) throw new TypeError(`Invalid hex color "${hex}"`);
148
+ return [parseInt(full.slice(0, 2), 16), parseInt(full.slice(2, 4), 16), parseInt(full.slice(4, 6), 16)];
149
+ };
150
+
151
+ /**
152
+ * @param {number} r
153
+ * @param {number} g
154
+ * @param {number} b
155
+ * @returns {number}
156
+ */
157
+ const _rgbToAnsi256 = (r, g, b) => {
158
+ if (r === g && g === b) {
159
+ if (r < 8) return 16;
160
+ if (r > 248) return 231;
161
+ return Math.round(((r - 8) / 247) * 24) + 232;
162
+ }
163
+ return 16 + 36 * Math.round((r / 255) * 5) + 6 * Math.round((g / 255) * 5) + Math.round((b / 255) * 5);
164
+ };
165
+
166
+ /**
167
+ * @param {number} code
168
+ * @returns {[number, number, number]}
169
+ */
170
+ const _ansi256ToRgb = (code) => {
171
+ if (code < 16) {
172
+ const base = [[0, 0, 0], [205, 0, 0], [0, 205, 0], [205, 205, 0], [0, 0, 238], [205, 0, 205], [0, 205, 205], [229, 229, 229],
173
+ [127, 127, 127], [255, 0, 0], [0, 255, 0], [255, 255, 0], [92, 92, 255], [255, 0, 255], [0, 255, 255], [255, 255, 255]];
174
+ return /** @type {[number, number, number]} */ (base[code]);
175
+ }
176
+ if (code >= 232) {
177
+ const v = (code - 232) * 10 + 8;
178
+ return [v, v, v];
179
+ }
180
+ const n = code - 16;
181
+ const step = (/** @type {number} */ x) => (x === 0 ? 0 : x * 40 + 55);
182
+ return [step(Math.floor(n / 36)), step(Math.floor((n % 36) / 6)), step(n % 6)];
183
+ };
184
+
185
+ /**
186
+ * @param {number} r
187
+ * @param {number} g
188
+ * @param {number} b
189
+ * @returns {number} A 16-color foreground code (30-37, 90-97).
190
+ */
191
+ const _rgbToAnsi16 = (r, g, b) => {
192
+ const value = Math.round((Math.max(r, g, b) / 255) * 2);
193
+ if (value === 0) return 30;
194
+ const code = 30 + ((Math.round(b / 255) << 2) | (Math.round(g / 255) << 1) | Math.round(r / 255));
195
+ return value === 2 ? code + 60 : code;
196
+ };
197
+
198
+ /**
199
+ * Resolves a style entry into escape codes for a given level.
200
+ * @param {StyleEntry} entry
201
+ * @param {ColorLevel} level
202
+ * @returns {{ open: string, close: string }}
203
+ */
204
+ const _resolve = (entry, level) => {
205
+ if ("open" in entry) return entry;
206
+ const close = entry.bg ? "\u001b[49m" : "\u001b[39m";
207
+ const rgb = "rgb" in entry ? entry.rgb : _ansi256ToRgb(entry.ansi256);
208
+ if (level >= 3 && "rgb" in entry) return { open: `\u001b[${entry.bg ? 48 : 38};2;${rgb[0]};${rgb[1]};${rgb[2]}m`, close };
209
+ if (level >= 2) {
210
+ const code = "ansi256" in entry ? entry.ansi256 : _rgbToAnsi256(...rgb);
211
+ return { open: `\u001b[${entry.bg ? 48 : 38};5;${code}m`, close };
212
+ }
213
+ const code = _rgbToAnsi16(...rgb) + (entry.bg ? 10 : 0);
214
+ return { open: `\u001b[${code}m`, close };
215
+ };
216
+
217
+ /**
218
+ * @param {NodeJS.WriteStream | { isTTY?: boolean } | undefined} stream
219
+ * @returns {ColorLevel}
220
+ */
221
+ const _detect = (stream = process.stdout) => {
222
+ const env = process.env;
223
+ const argv = process.argv;
224
+ if (argv.includes("--no-color") || argv.includes("--no-colors") || argv.includes("--color=false")) return 0;
225
+ if (env.NO_COLOR !== undefined && env.NO_COLOR !== "") return 0;
226
+ if (env.NODE_DISABLE_COLORS !== undefined && env.NODE_DISABLE_COLORS !== "") return 0;
227
+ if (env.FORCE_COLOR !== undefined) {
228
+ const value = env.FORCE_COLOR.toLowerCase();
229
+ if (value === "false" || value === "0") return 0;
230
+ if (value === "2") return 2;
231
+ if (value === "3") return 3;
232
+ return 1;
233
+ }
234
+ if (argv.includes("--color=16m") || argv.includes("--color=full") || argv.includes("--color=truecolor")) return 3;
235
+ if (argv.includes("--color=256")) return 2;
236
+ const forced = argv.includes("--color") || argv.includes("--colors") || argv.includes("--color=true") || argv.includes("--color=always");
237
+ if (env.TERM === "dumb" && !forced) return 0;
238
+ const tty = /** @type {NodeJS.WriteStream | undefined} */ (stream && "isTTY" in stream && stream.isTTY ? stream : undefined);
239
+ if (tty && typeof tty.getColorDepth === "function") {
240
+ const depth = tty.getColorDepth();
241
+ if (depth >= 24) return 3;
242
+ if (depth >= 8) return 2;
243
+ if (depth >= 4) return 1;
244
+ return forced ? 1 : 0;
245
+ }
246
+ if (env.CI !== undefined) {
247
+ if (env.GITHUB_ACTIONS || env.GITEA_ACTIONS) return 3;
248
+ if (["TRAVIS", "CIRCLECI", "APPVEYOR", "GITLAB_CI", "BUILDKITE", "DRONE"].some((name) => name in env)) return 1;
249
+ }
250
+ return forced ? 1 : 0;
251
+ };
252
+
253
+ /**
254
+ * Terminal width of one grapheme.
255
+ * @param {string} grapheme
256
+ * @returns {number}
257
+ */
258
+ const _charWidth = (grapheme) => {
259
+ const cp = /** @type {number} */ (grapheme.codePointAt(0));
260
+ if (cp < 32 || (cp >= 0x7f && cp < 0xa0)) return 0;
261
+ if (/^\p{Mark}+$/u.test(grapheme)) return 0;
262
+ if (/\p{Emoji_Presentation}/u.test(grapheme) || grapheme.includes("\ufe0f")) return 2;
263
+ if (/[ᄀ-ᅟ⺀-〾ぁ-㏿㐀-䶿一-鿿ꀀ-꓏가-힣豈-﫿︰-﹏＀-⦆¢-₩\u{20000}-\u{3FFFD}]/u.test(grapheme)) return 2;
264
+ return 1;
265
+ };
266
+
267
+ /** @type {Intl.Segmenter | undefined} */
268
+ let _segmenter;
269
+ const _graphemeSegmenter = () => (_segmenter ??= new Intl.Segmenter(undefined, { granularity: "grapheme" }));
270
+
271
+ /**
272
+ * @param {string} text
273
+ * @returns {string}
274
+ */
275
+ const strip = (text) => String(text).replace(_ANSI_REGEX, "");
276
+
277
+ /**
278
+ * @param {string} text
279
+ * @returns {number}
280
+ */
281
+ const width = (text) => {
282
+ const plain = strip(text);
283
+ if (/^[\x20-\x7e]*$/.test(plain)) return plain.length;
284
+ let total = 0;
285
+ for (const { segment } of _graphemeSegmenter().segment(plain)) total += _charWidth(segment);
286
+ return total;
287
+ };
288
+
289
+ const _supportsHyperlinks = () => {
290
+ const env = process.env;
291
+ if (env.FORCE_HYPERLINK === "1") return true;
292
+ if (env.FORCE_HYPERLINK === "0") return false;
293
+ if (!process.stdout.isTTY) return false;
294
+ if (env.WT_SESSION || env.KONSOLE_VERSION || env.DOMTERM) return true;
295
+ if (["iTerm.app", "WezTerm", "vscode", "Hyper", "ghostty", "Tabby"].includes(env.TERM_PROGRAM ?? "")) return true;
296
+ if (env.VTE_VERSION && Number(env.VTE_VERSION) >= 5000) return true;
297
+ return false;
298
+ };
299
+
300
+ /**
301
+ * Builds an independent color instance.
302
+ * @param {ColorLevel | undefined} forcedLevel
303
+ * @returns {ColorModule}
304
+ */
305
+ const _createModule = (forcedLevel) => {
306
+ /** @type {ColorLevel | undefined} */
307
+ let level = forcedLevel;
308
+ const currentLevel = () => (level === undefined ? (level = _detect()) : level);
309
+
310
+ /**
311
+ * @param {StyleEntry[]} stack
312
+ * @param {string} text
313
+ * @returns {string}
314
+ */
315
+ const apply = (stack, text) => {
316
+ const lvl = currentLevel();
317
+ if (lvl === 0 || !stack.length || text === "") return text;
318
+ const resolved = stack.map((entry) => _resolve(entry, lvl));
319
+ let result = text;
320
+ for (const { open, close } of resolved) {
321
+ if (close && result.includes(close)) result = result.split(close).join(close + open);
322
+ }
323
+ const opens = resolved.map((s) => s.open).join("");
324
+ const closes = resolved.map((s) => s.close).reverse().join("");
325
+ if (result.includes("\n")) result = result.replace(/\r?\n/g, (nl) => closes + nl + opens);
326
+ return opens + result + closes;
327
+ };
328
+
329
+ const STACK = Symbol("stack");
330
+ /** @type {any} */
331
+ const proto = Object.create(Function.prototype);
332
+
333
+ /**
334
+ * @param {StyleEntry[]} stack
335
+ * @returns {ColorChain}
336
+ */
337
+ const chain = (stack) => {
338
+ /** @type {any} */
339
+ const fn = (/** @type {unknown[]} */ ...text) => apply(stack, text.map((t) => String(t)).join(" "));
340
+ Object.setPrototypeOf(fn, proto);
341
+ fn[STACK] = stack;
342
+ return fn;
343
+ };
344
+
345
+ for (const [name, [open, close]] of Object.entries(_CODES)) {
346
+ Object.defineProperty(proto, name, {
347
+ get() {
348
+ return chain([...(this[STACK] ?? []), { open: `\u001b[${open}m`, close: `\u001b[${close}m` }]);
349
+ },
350
+ });
351
+ }
352
+ /** @type {Record<string, (this: any, ...args: any[]) => ColorChain>} */
353
+ const methods = {
354
+ rgb(r, g, b) { return chain([...(this[STACK] ?? []), { rgb: [r, g, b], bg: false }]); },
355
+ bgRgb(r, g, b) { return chain([...(this[STACK] ?? []), { rgb: [r, g, b], bg: true }]); },
356
+ hex(hex) { return chain([...(this[STACK] ?? []), { rgb: _hexToRgb(hex), bg: false }]); },
357
+ bgHex(hex) { return chain([...(this[STACK] ?? []), { rgb: _hexToRgb(hex), bg: true }]); },
358
+ ansi256(code) { return chain([...(this[STACK] ?? []), { ansi256: code, bg: false }]); },
359
+ bgAnsi256(code) { return chain([...(this[STACK] ?? []), { ansi256: code, bg: true }]); },
360
+ };
361
+ for (const [name, method] of Object.entries(methods)) Object.defineProperty(proto, name, { value: method });
362
+
363
+ /** @type {any} */
364
+ const root = Object.create(proto);
365
+ root[STACK] = [];
366
+ Object.defineProperties(root, {
367
+ level: {
368
+ enumerable: true,
369
+ get: currentLevel,
370
+ set(/** @type {ColorLevel} */ value) {
371
+ level = /** @type {ColorLevel} */ (Math.max(0, Math.min(3, Math.floor(value))));
372
+ },
373
+ },
374
+ enabled: { enumerable: true, get: () => currentLevel() > 0 },
375
+ create: { enumerable: true, value: (/** @type {ColorLevel | undefined} */ lvl) => _createModule(lvl) },
376
+ detect: { enumerable: true, value: _detect },
377
+ strip: { enumerable: true, value: strip },
378
+ width: { enumerable: true, value: width },
379
+ link: {
380
+ enumerable: true,
381
+ value: (/** @type {string} */ text, /** @type {string} */ url) =>
382
+ currentLevel() > 0 && _supportsHyperlinks() ? `\u001b]8;;${url}\u0007${text}\u001b]8;;\u0007` : `${text} (${url})`,
383
+ },
384
+ gradient: {
385
+ enumerable: true,
386
+ value: (/** @type {string} */ text, /** @type {string[]} */ colors) => {
387
+ const stops = colors.map(_hexToRgb);
388
+ if (!stops.length) return String(text);
389
+ const graphemes = Array.from(_graphemeSegmenter().segment(String(text)), (s) => s.segment);
390
+ const visible = graphemes.filter((g) => g.trim()).length;
391
+ let index = 0;
392
+ return graphemes
393
+ .map((g) => {
394
+ if (!g.trim()) return g;
395
+ const t = visible <= 1 ? 0 : index++ / (visible - 1);
396
+ const pos = t * (stops.length - 1);
397
+ const i = Math.min(Math.floor(pos), stops.length - 2 < 0 ? 0 : stops.length - 2);
398
+ const a = stops[i];
399
+ const b = stops[Math.min(i + 1, stops.length - 1)];
400
+ const f = pos - i;
401
+ const mix = /** @type {[number, number, number]} */ (a.map((v, k) => Math.round(v + (b[k] - v) * f)));
402
+ return apply([{ rgb: mix, bg: false }], g);
403
+ })
404
+ .join("");
405
+ },
406
+ },
407
+ });
408
+ return root;
409
+ };
410
+
411
+ /** @type {ColorModule} */
412
+ const color = _createModule(undefined);
413
+
414
+ module.exports = color;
415
+