@peteanderson/ansi 3.7.1 → 3.8.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 (233) hide show
  1. package/README.md +40 -0
  2. package/dist/cjs/ansi.d.ts +7 -3
  3. package/dist/cjs/ansi.d.ts.map +1 -1
  4. package/dist/cjs/ansi.js +6 -1
  5. package/dist/cjs/ansi.js.map +1 -1
  6. package/dist/cjs/code.d.ts +10 -0
  7. package/dist/cjs/code.d.ts.map +1 -0
  8. package/dist/cjs/code.js +9 -0
  9. package/dist/cjs/code.js.map +1 -0
  10. package/dist/cjs/cursor.js +30 -30
  11. package/dist/cjs/cursor.js.map +1 -1
  12. package/dist/cjs/index.d.ts +12 -7
  13. package/dist/cjs/index.d.ts.map +1 -1
  14. package/dist/cjs/ins-del.js +16 -16
  15. package/dist/cjs/ins-del.js.map +1 -1
  16. package/dist/cjs/package.json +25 -0
  17. package/dist/cjs/scroll.js +9 -9
  18. package/dist/cjs/scroll.js.map +1 -1
  19. package/dist/cjs/sgr/chain/attach.d.ts +5 -0
  20. package/dist/cjs/sgr/chain/attach.d.ts.map +1 -0
  21. package/dist/cjs/sgr/chain/attach.js +10 -0
  22. package/dist/cjs/sgr/chain/attach.js.map +1 -0
  23. package/dist/cjs/sgr/chain/build.d.ts +8 -0
  24. package/dist/cjs/sgr/chain/build.d.ts.map +1 -0
  25. package/dist/cjs/sgr/chain/build.js +15 -0
  26. package/dist/cjs/sgr/chain/build.js.map +1 -0
  27. package/dist/cjs/sgr/chain/chain.d.ts +13 -0
  28. package/dist/cjs/sgr/chain/chain.d.ts.map +1 -0
  29. package/dist/cjs/sgr/chain/chain.js +36 -0
  30. package/dist/cjs/sgr/chain/chain.js.map +1 -0
  31. package/dist/cjs/sgr/chain/index.d.ts +5 -0
  32. package/dist/cjs/sgr/chain/index.d.ts.map +1 -0
  33. package/dist/cjs/sgr/chain/index.js +20 -0
  34. package/dist/cjs/sgr/chain/index.js.map +1 -0
  35. package/dist/cjs/sgr/chain/keys.d.ts +5 -0
  36. package/dist/cjs/sgr/chain/keys.d.ts.map +1 -0
  37. package/dist/cjs/sgr/chain/keys.js +8 -0
  38. package/dist/cjs/sgr/chain/keys.js.map +1 -0
  39. package/dist/cjs/sgr/color/channel.d.ts +29 -3
  40. package/dist/cjs/sgr/color/channel.d.ts.map +1 -1
  41. package/dist/cjs/sgr/color/channel.js +8 -8
  42. package/dist/cjs/sgr/color/channel.js.map +1 -1
  43. package/dist/cjs/sgr/color/color.d.ts +9 -3
  44. package/dist/cjs/sgr/color/color.d.ts.map +1 -1
  45. package/dist/cjs/sgr/color/color.js +6 -10
  46. package/dist/cjs/sgr/color/color.js.map +1 -1
  47. package/dist/cjs/sgr/color/context.d.ts +12 -8
  48. package/dist/cjs/sgr/color/context.d.ts.map +1 -1
  49. package/dist/cjs/sgr/color/context.js +28 -18
  50. package/dist/cjs/sgr/color/context.js.map +1 -1
  51. package/dist/cjs/sgr/color/rgb.d.ts +7 -4
  52. package/dist/cjs/sgr/color/rgb.d.ts.map +1 -1
  53. package/dist/cjs/sgr/color/rgb.js +12 -12
  54. package/dist/cjs/sgr/color/rgb.js.map +1 -1
  55. package/dist/cjs/sgr/combine.d.ts +1 -1
  56. package/dist/cjs/sgr/combine.d.ts.map +1 -1
  57. package/dist/cjs/sgr/context.d.ts +16 -0
  58. package/dist/cjs/sgr/context.d.ts.map +1 -0
  59. package/dist/cjs/sgr/context.js +43 -0
  60. package/dist/cjs/sgr/context.js.map +1 -0
  61. package/dist/cjs/sgr/format.d.ts +19 -0
  62. package/dist/cjs/sgr/format.d.ts.map +1 -0
  63. package/dist/cjs/sgr/format.js +35 -0
  64. package/dist/cjs/sgr/format.js.map +1 -0
  65. package/dist/cjs/sgr/index.d.ts +3 -1
  66. package/dist/cjs/sgr/index.d.ts.map +1 -1
  67. package/dist/cjs/sgr/index.js +3 -0
  68. package/dist/cjs/sgr/index.js.map +1 -1
  69. package/dist/cjs/sgr/reset.js +2 -2
  70. package/dist/cjs/sgr/reset.js.map +1 -1
  71. package/dist/cjs/sgr/sgr.d.ts +10 -2
  72. package/dist/cjs/sgr/sgr.d.ts.map +1 -1
  73. package/dist/cjs/sgr/sgr.js +7 -32
  74. package/dist/cjs/sgr/sgr.js.map +1 -1
  75. package/dist/cjs/sgr/style.d.ts +9 -2
  76. package/dist/cjs/sgr/style.d.ts.map +1 -1
  77. package/dist/cjs/sgr/style.js +13 -12
  78. package/dist/cjs/sgr/style.js.map +1 -1
  79. package/dist/cjs/simplify/simplify.d.ts.map +1 -1
  80. package/dist/cjs/simplify/simplify.js +4 -7
  81. package/dist/cjs/simplify/simplify.js.map +1 -1
  82. package/dist/cjs/slice.js +3 -3
  83. package/dist/cjs/slice.js.map +1 -1
  84. package/dist/cjs/strip.js +3 -3
  85. package/dist/cjs/strip.js.map +1 -1
  86. package/dist/cjs/terminal.js +13 -13
  87. package/dist/cjs/terminal.js.map +1 -1
  88. package/dist/cjs/types.d.ts +2 -1
  89. package/dist/cjs/types.d.ts.map +1 -1
  90. package/dist/cjs/utils.d.ts +3 -1
  91. package/dist/cjs/utils.d.ts.map +1 -1
  92. package/dist/cjs/utils.js +9 -6
  93. package/dist/cjs/utils.js.map +1 -1
  94. package/dist/esm/ansi.d.ts +7 -3
  95. package/dist/esm/ansi.d.ts.map +1 -1
  96. package/dist/esm/ansi.js +3 -2
  97. package/dist/esm/ansi.js.map +1 -1
  98. package/dist/esm/code.d.ts +10 -0
  99. package/dist/esm/code.d.ts.map +1 -0
  100. package/dist/esm/code.js +6 -0
  101. package/dist/esm/code.js.map +1 -0
  102. package/dist/esm/cursor.js +5 -5
  103. package/dist/esm/cursor.js.map +1 -1
  104. package/dist/esm/index.d.ts +1 -1
  105. package/dist/esm/index.d.ts.map +1 -1
  106. package/dist/esm/ins-del.js +1 -1
  107. package/dist/esm/ins-del.js.map +1 -1
  108. package/dist/esm/package.json +25 -1
  109. package/dist/esm/scroll.js +3 -3
  110. package/dist/esm/scroll.js.map +1 -1
  111. package/dist/esm/sgr/chain/attach.d.ts +5 -0
  112. package/dist/esm/sgr/chain/attach.d.ts.map +1 -0
  113. package/dist/esm/sgr/chain/attach.js +6 -0
  114. package/dist/esm/sgr/chain/attach.js.map +1 -0
  115. package/dist/esm/sgr/chain/build.d.ts +8 -0
  116. package/dist/esm/sgr/chain/build.d.ts.map +1 -0
  117. package/dist/esm/sgr/chain/build.js +12 -0
  118. package/dist/esm/sgr/chain/build.js.map +1 -0
  119. package/dist/esm/sgr/chain/chain.d.ts +13 -0
  120. package/dist/esm/sgr/chain/chain.d.ts.map +1 -0
  121. package/dist/esm/sgr/chain/chain.js +33 -0
  122. package/dist/esm/sgr/chain/chain.js.map +1 -0
  123. package/dist/esm/sgr/chain/index.d.ts +5 -0
  124. package/dist/esm/sgr/chain/index.d.ts.map +1 -0
  125. package/dist/esm/sgr/chain/index.js +4 -0
  126. package/dist/esm/sgr/chain/index.js.map +1 -0
  127. package/dist/esm/sgr/chain/keys.d.ts +5 -0
  128. package/dist/esm/sgr/chain/keys.d.ts.map +1 -0
  129. package/dist/esm/sgr/chain/keys.js +5 -0
  130. package/dist/esm/sgr/chain/keys.js.map +1 -0
  131. package/dist/esm/sgr/color/channel.d.ts +29 -3
  132. package/dist/esm/sgr/color/channel.d.ts.map +1 -1
  133. package/dist/esm/sgr/color/channel.js +9 -9
  134. package/dist/esm/sgr/color/channel.js.map +1 -1
  135. package/dist/esm/sgr/color/color.d.ts +9 -3
  136. package/dist/esm/sgr/color/color.d.ts.map +1 -1
  137. package/dist/esm/sgr/color/color.js +4 -10
  138. package/dist/esm/sgr/color/color.js.map +1 -1
  139. package/dist/esm/sgr/color/context.d.ts +12 -8
  140. package/dist/esm/sgr/color/context.d.ts.map +1 -1
  141. package/dist/esm/sgr/color/context.js +27 -17
  142. package/dist/esm/sgr/color/context.js.map +1 -1
  143. package/dist/esm/sgr/color/rgb.d.ts +7 -4
  144. package/dist/esm/sgr/color/rgb.d.ts.map +1 -1
  145. package/dist/esm/sgr/color/rgb.js +12 -12
  146. package/dist/esm/sgr/color/rgb.js.map +1 -1
  147. package/dist/esm/sgr/combine.d.ts +1 -1
  148. package/dist/esm/sgr/combine.d.ts.map +1 -1
  149. package/dist/esm/sgr/context.d.ts +16 -0
  150. package/dist/esm/sgr/context.d.ts.map +1 -0
  151. package/dist/esm/sgr/context.js +39 -0
  152. package/dist/esm/sgr/context.js.map +1 -0
  153. package/dist/esm/sgr/format.d.ts +19 -0
  154. package/dist/esm/sgr/format.d.ts.map +1 -0
  155. package/dist/esm/sgr/format.js +32 -0
  156. package/dist/esm/sgr/format.js.map +1 -0
  157. package/dist/esm/sgr/index.d.ts +3 -1
  158. package/dist/esm/sgr/index.d.ts.map +1 -1
  159. package/dist/esm/sgr/index.js +1 -0
  160. package/dist/esm/sgr/index.js.map +1 -1
  161. package/dist/esm/sgr/reset.js +1 -1
  162. package/dist/esm/sgr/reset.js.map +1 -1
  163. package/dist/esm/sgr/sgr.d.ts +10 -2
  164. package/dist/esm/sgr/sgr.d.ts.map +1 -1
  165. package/dist/esm/sgr/sgr.js +7 -32
  166. package/dist/esm/sgr/sgr.js.map +1 -1
  167. package/dist/esm/sgr/style.d.ts +9 -2
  168. package/dist/esm/sgr/style.d.ts.map +1 -1
  169. package/dist/esm/sgr/style.js +12 -12
  170. package/dist/esm/sgr/style.js.map +1 -1
  171. package/dist/esm/simplify/simplify.d.ts.map +1 -1
  172. package/dist/esm/simplify/simplify.js +3 -6
  173. package/dist/esm/simplify/simplify.js.map +1 -1
  174. package/dist/esm/slice.js +1 -1
  175. package/dist/esm/slice.js.map +1 -1
  176. package/dist/esm/strip.js +1 -1
  177. package/dist/esm/strip.js.map +1 -1
  178. package/dist/esm/terminal.js +1 -1
  179. package/dist/esm/terminal.js.map +1 -1
  180. package/dist/esm/types.d.ts +2 -1
  181. package/dist/esm/types.d.ts.map +1 -1
  182. package/dist/esm/utils.d.ts +3 -1
  183. package/dist/esm/utils.d.ts.map +1 -1
  184. package/dist/esm/utils.js +7 -5
  185. package/dist/esm/utils.js.map +1 -1
  186. package/package.json +13 -5
  187. package/src/ansi.ts +3 -2
  188. package/src/code.ts +9 -0
  189. package/src/cursor.ts +5 -5
  190. package/src/index.ts +1 -1
  191. package/src/ins-del.ts +1 -1
  192. package/src/require.ts +3 -3
  193. package/src/scroll.ts +3 -3
  194. package/src/sgr/chain/attach.ts +13 -0
  195. package/src/sgr/chain/build.ts +25 -0
  196. package/src/sgr/chain/chain.ts +60 -0
  197. package/src/sgr/chain/index.ts +5 -0
  198. package/src/sgr/chain/keys.ts +8 -0
  199. package/src/sgr/color/channel.ts +47 -19
  200. package/src/sgr/color/color.ts +14 -19
  201. package/src/sgr/color/context.ts +37 -31
  202. package/src/sgr/color/rgb.ts +21 -20
  203. package/src/sgr/combine.ts +1 -1
  204. package/src/sgr/context.ts +68 -0
  205. package/src/sgr/format.ts +72 -0
  206. package/src/sgr/index.ts +4 -2
  207. package/src/sgr/reset.ts +1 -1
  208. package/src/sgr/sgr.ts +21 -49
  209. package/src/sgr/style.ts +31 -21
  210. package/src/simplify/simplify.ts +3 -6
  211. package/src/slice.ts +1 -1
  212. package/src/strip.ts +1 -1
  213. package/src/terminal.ts +1 -1
  214. package/src/types.ts +2 -1
  215. package/src/utils.ts +12 -7
  216. package/dist/cjs/sgr/format-builder.d.ts +0 -3
  217. package/dist/cjs/sgr/format-builder.d.ts.map +0 -1
  218. package/dist/cjs/sgr/format-builder.js +0 -34
  219. package/dist/cjs/sgr/format-builder.js.map +0 -1
  220. package/dist/cjs/sgr/types.d.ts +0 -61
  221. package/dist/cjs/sgr/types.d.ts.map +0 -1
  222. package/dist/cjs/sgr/types.js +0 -3
  223. package/dist/cjs/sgr/types.js.map +0 -1
  224. package/dist/esm/sgr/format-builder.d.ts +0 -3
  225. package/dist/esm/sgr/format-builder.d.ts.map +0 -1
  226. package/dist/esm/sgr/format-builder.js +0 -30
  227. package/dist/esm/sgr/format-builder.js.map +0 -1
  228. package/dist/esm/sgr/types.d.ts +0 -61
  229. package/dist/esm/sgr/types.d.ts.map +0 -1
  230. package/dist/esm/sgr/types.js +0 -2
  231. package/dist/esm/sgr/types.js.map +0 -1
  232. package/src/sgr/format-builder.ts +0 -52
  233. package/src/sgr/types.ts +0 -93
@@ -0,0 +1,25 @@
1
+ import {makeColor} from "../color";
2
+ import {combineCodes} from "../combine";
3
+ import {makeStyle} from "../style";
4
+
5
+ import type {Color} from "../color";
6
+ import type {FormatContext} from "../context";
7
+ import type {FormatBase} from "../format";
8
+ import type {Style} from "../style";
9
+ import type {ChainKey} from "./keys";
10
+
11
+ export type Chain<Keys extends ChainKey> = Color<Keys> & Style<Keys>;
12
+
13
+ export function makeChain<Keys extends ChainKey>(
14
+ context : FormatContext<Keys>,
15
+ baseFormat : FormatBase,
16
+ ): Chain<Keys> {
17
+ const parentCodes = context.parentCodes ? {
18
+ open : combineCodes(context.parentCodes.open, baseFormat.codes.open),
19
+ close : combineCodes(baseFormat.codes.close, context.parentCodes.close),
20
+ } : baseFormat.codes;
21
+
22
+ const chainedContext: FormatContext<Keys> = {...context, parentCodes};
23
+
24
+ return {...makeColor(chainedContext), ...makeStyle(chainedContext)};
25
+ }
@@ -0,0 +1,60 @@
1
+ import {define, ownProperties} from "@peteanderson/props";
2
+ import {getContext} from "../context";
3
+ import {attachChain} from "./attach";
4
+ import {allKeys} from "./keys";
5
+
6
+ import type {Features} from "#features";
7
+ import type {Format, FormatBase} from "../format";
8
+ import type {ChainKey} from "./keys";
9
+
10
+ function cloneFormatBase(baseFormat: FormatBase): FormatBase {
11
+ const clone = (text: string) => baseFormat(text);
12
+ const descriptors = ownProperties(baseFormat);
13
+
14
+ delete descriptors.and;
15
+
16
+ return define(clone, descriptors);
17
+ }
18
+
19
+ function keysMatch(a: ReadonlySet<ChainKey>, b: ReadonlySet<ChainKey>): boolean {
20
+ if (a.size !== b.size)
21
+ return false;
22
+
23
+ for (const key of a)
24
+ if (!b.has(key))
25
+ return false;
26
+
27
+ return true;
28
+ }
29
+
30
+ type ChainArgs<Keys extends ChainKey> = [
31
+ keys : ReadonlySet<Keys>,
32
+ baseFormat : FormatBase,
33
+ features? : Features,
34
+ ];
35
+
36
+ type OverloadedArgs<Keys extends ChainKey> = [FormatBase, Features?] | ChainArgs<Keys>;
37
+
38
+ const resolveArgs = <Keys extends ChainKey>(args: OverloadedArgs<Keys>): ChainArgs<Keys> =>
39
+ args.length === 1 ?
40
+ [allKeys as ReadonlySet<Keys>, args[0], undefined] :
41
+ args.length === 2 ?
42
+ typeof args[0] === "function"
43
+ ? [allKeys as ReadonlySet<Keys>, ...args as [FormatBase]]
44
+ : args as ChainArgs<Keys> :
45
+ args as ChainArgs<Keys>;
46
+
47
+ export function chain(baseFormat: FormatBase, features?: Features): Format<ChainKey>;
48
+ export function chain<Keys extends ChainKey = ChainKey>(...args: ChainArgs<Keys>): Format<Keys>;
49
+
50
+ export function chain<Keys extends ChainKey>(...args: OverloadedArgs<Keys>): Format<Keys> {
51
+ const [keys, baseFormat, features] = resolveArgs(args);
52
+
53
+ let context = getContext(baseFormat, features);
54
+ if (!keysMatch(context.keys, keys))
55
+ context = {...context, keys};
56
+
57
+ return attachChain(context, cloneFormatBase(baseFormat));
58
+ }
59
+
60
+ export type AddChain = typeof chain;
@@ -0,0 +1,5 @@
1
+ export * from "./attach";
2
+ export * from "./chain";
3
+ export * from "./keys";
4
+
5
+ export type {Chain} from "./build";
@@ -0,0 +1,8 @@
1
+ import {channels} from "../color";
2
+ import {styleKeys} from "../style";
3
+
4
+ const chainKeys = [...channels, ...styleKeys] as const;
5
+
6
+ export type ChainKey = typeof chainKeys[number];
7
+
8
+ export const allKeys: ReadonlySet<ChainKey> = new Set(chainKeys);
@@ -1,10 +1,41 @@
1
- import {csi} from "../../utils";
2
- import {lazy} from "../lazy";
3
- import {buildContext} from "./context";
4
- import {makeRGB, makeX256} from "./rgb";
1
+ import {csi} from "#utils";
2
+ import {lazy} from "../lazy";
3
+ import {buildChannelContext} from "./context";
4
+ import {makeRGB, makeX256} from "./rgb";
5
5
 
6
- import type {ColorDepth} from "../../features";
7
- import type {ChainKey, Channel, ColorKey, FormatBuilder, Style} from "../types";
6
+ import type {ChainKey} from "../chain";
7
+ import type {FormatContext} from "../context";
8
+ import type {Format} from "../format";
9
+ import type {ColorKey} from "./color";
10
+
11
+ export interface Channel<Keys extends ChainKey = ChainKey> {
12
+ black : Format<Keys>;
13
+ red : Format<Keys>;
14
+ green : Format<Keys>;
15
+ yellow : Format<Keys>;
16
+ blue : Format<Keys>;
17
+ magenta : Format<Keys>;
18
+ cyan : Format<Keys>;
19
+ white : Format<Keys>;
20
+
21
+ brightBlack : Format<Keys>;
22
+ brightRed : Format<Keys>;
23
+ brightGreen : Format<Keys>;
24
+ brightYellow : Format<Keys>;
25
+ brightBlue : Format<Keys>;
26
+ brightMagenta : Format<Keys>;
27
+ brightCyan : Format<Keys>;
28
+ brightWhite : Format<Keys>;
29
+
30
+ rgb: (r: number, g: number, b: number) => Format<Keys>;
31
+
32
+ x256: {
33
+ (code: number): Format<Keys>;
34
+ (r: number, g: number, b: number): Format<Keys>;
35
+ };
36
+
37
+ default: string,
38
+ }
8
39
 
9
40
  const colors = [
10
41
  "black",
@@ -17,27 +48,24 @@ const colors = [
17
48
  "white",
18
49
  ] as const;
19
50
 
20
- export function makeChannel(
21
- keys : ReadonlySet<ChainKey>,
22
- makeFormatter : FormatBuilder,
23
- style : Style,
24
- colorDepth : ColorDepth,
51
+ export function makeChannel<Keys extends ChainKey>(
52
+ formatContext : FormatContext<Keys>,
25
53
  channel : ColorKey,
26
- ): Channel {
27
- const ctx = buildContext(keys, makeFormatter, style, colorDepth, channel);
28
- const {build, bright, open, close} = ctx;
54
+ ): Channel<Keys> {
55
+ const channelContext = buildChannelContext(formatContext, channel);
56
+ const {build, bright, close, offset} = channelContext;
29
57
 
30
58
  const rtn = {
31
- rgb : makeRGB(ctx),
32
- x256 : makeX256(ctx),
33
- default : colorDepth > 1 ? csi(close, "m") : "",
34
- } as Channel;
59
+ rgb : makeRGB(channelContext),
60
+ x256 : makeX256(channelContext),
61
+ default : csi(close, "m"),
62
+ } as unknown as Channel<Keys>;
35
63
 
36
64
  for (let i = 0; i < colors.length; i++) {
37
65
  const color = colors[i];
38
66
  const brightColor = `bright${color[0].toUpperCase()}${color.slice(1)}`;
39
67
 
40
- lazy.add(rtn, color, () => build(open + i));
68
+ lazy.add(rtn, color, () => build(offset(i)));
41
69
  lazy.add(rtn, brightColor, () => bright(i));
42
70
  }
43
71
 
@@ -1,29 +1,24 @@
1
- "use strict";
2
-
3
1
  import {lazy} from "../lazy";
4
2
  import {makeChannel} from "./channel";
5
3
 
6
- import type {ColorDepth} from "../../features";
7
- import type {ChainKey, Color, FormatBuilder, Style} from "../types";
4
+ import type {ChainKey} from "../chain";
5
+ import type {FormatContext} from "../context";
6
+ import type {Channel} from "./channel";
7
+
8
+ export const channels = ["fg", "bg"] as const;
9
+
10
+ export type ColorKey = typeof channels[number];
8
11
 
9
- const channels = ["fg", "bg"] as const;
12
+ export type Color<Keys extends ChainKey = ChainKey> = {
13
+ [K in Extract<ColorKey, Keys>]: Channel<Exclude<Keys, K>>;
14
+ };
10
15
 
11
- export function makeColor(
12
- keys : ReadonlySet<ChainKey>,
13
- makeFormatter : FormatBuilder,
14
- style : Style,
15
- colorDepth : ColorDepth,
16
- ): Color<any> {
17
- const rtn = {} as Color<any>;
16
+ export function makeColor<Keys extends ChainKey>(context: FormatContext<Keys>): Color<Keys> {
17
+ const rtn = {} as Color<Keys>;
18
18
 
19
19
  for (const channel of channels) {
20
- if (keys.has(channel)) {
21
- lazy.add(rtn, channel, () => {
22
- const newKeys = new Set(keys);
23
- newKeys.delete(channel);
24
- return makeChannel(newKeys, makeFormatter, style, colorDepth, channel);
25
- });
26
- }
20
+ if (context.keys.has(channel as Keys))
21
+ lazy.add(rtn, channel, () => makeChannel(context.removeKey(channel as Keys), channel));
27
22
  }
28
23
 
29
24
  return rtn;
@@ -1,46 +1,52 @@
1
+ import {Code} from "#code";
1
2
  import {combineCodes} from "../combine";
2
-
3
- import type {ColorDepth} from "../../features";
4
- import type {ChainKey, Code, ColorKey, Format, FormatBase, FormatBuilder, Style} from "../types";
5
-
6
- const baseCodes = {
7
- fg: {open: 30, close: 39},
8
- bg: {open: 40, close: 49},
3
+ import {makeFormat} from "../format";
4
+
5
+ import type {FormatContext} from "../context";
6
+ import type {Format, FormatBase} from "../format";
7
+ import type {ColorKey} from "./color";
8
+
9
+ const codes = (open: number) => ({
10
+ open : open as Code,
11
+ close : open + 9 as Code,
12
+ offset : (delta: number): Code => open + delta,
13
+ extended : (...args: number[]): Code => [open + 8, ...args],
14
+ });
15
+
16
+ const baseCodes = {fg: codes(30), bg: codes(40)};
17
+
18
+ const disabledCodes: ReturnType<typeof codes> = {
19
+ open : Code.disabled,
20
+ close : Code.disabled,
21
+ offset : () => Code.disabled,
22
+ extended : () => Code.disabled,
9
23
  };
10
24
 
11
- export function buildContext(
12
- keys : ReadonlySet<ChainKey>,
13
- makeFormatter : FormatBuilder,
14
- style : Style,
15
- colorDepth : ColorDepth,
16
- channel : ColorKey
17
- ) {
18
- const {open, close} = baseCodes[channel];
19
-
20
- const build = colorDepth > 1
21
- ? (open: Code): Format => makeFormatter(keys, open, close)
22
- : () => makeFormatter(keys, [], []);
23
-
24
- const combine = (base: FormatBase, style: FormatBase): Format => makeFormatter(
25
- keys,
25
+ export function buildChannelContext(formatContext: FormatContext, channel: ColorKey) {
26
+ const {colorDepth} = formatContext.features;
27
+ const {open, close, extended, offset} = colorDepth > 1 ? baseCodes[channel] : disabledCodes;
28
+
29
+ const build = (open: Code): Format => makeFormat(formatContext, open, close);
30
+ const combine = (base: FormatBase, style: FormatBase): Format => makeFormat(
31
+ formatContext,
26
32
  combineCodes(base.codes.open, style.codes.open),
27
33
  combineCodes(base.codes.close, style.codes.close),
28
34
  );
29
35
 
30
36
  const bright: (index: number) => Format =
31
- colorDepth >= 4 ? index => build(open + 60 + index) :
37
+ colorDepth >= 4 ? index => build(offset(60 + index)) :
32
38
  colorDepth === 3 ?
33
39
  channel === "fg" ?
34
- index => combine(style.bold, build(open + index)) :
35
- index => build(open + index) :
36
- () => build([]);
40
+ index => combine(formatContext.style.bold, build(offset(index))) :
41
+ index => build(offset(index)) :
42
+ () => build(Code.disabled);
37
43
 
38
44
  const x16ToX8: (code: number) => Format =
39
- channel === "fg" ?
40
- code => code >= 60 ? combine(style.bold, build(open + code - 60)) : build(open + code) :
41
- code => code >= 60 ? build(open + code - 60) : build(open + code);
45
+ channel === "fg"
46
+ ? code => code >= 60 ? bright(code - 60) : build(offset(code))
47
+ : code => build(offset(code % 60));
42
48
 
43
- return {colorDepth, channel, open, close, build, bright, x16ToX8};
49
+ return {colorDepth, channel, open, close, offset, extended, build, bright, x16ToX8};
44
50
  }
45
51
 
46
- export type Context = ReturnType<typeof buildContext>;
52
+ export type ChannelContext = ReturnType<typeof buildChannelContext>;
@@ -1,35 +1,38 @@
1
+ import {Code} from "#code";
1
2
  import {clip, rgbToX256, rgbToX16, rgbToX8, x256ToRgb} from "./utils";
2
3
 
3
- import type {Channel, Format} from "../types";
4
- import type {Context} from "./context";
4
+ import type {Format} from "../format";
5
+ import type {Channel} from "./channel";
6
+ import type {ChannelContext} from "./context";
5
7
 
6
- export function makeRGB(ctx: Context): Channel["rgb"] {
7
- const {colorDepth, channel, build, open, x16ToX8} = ctx;
8
+ export function makeRGB(ctx: ChannelContext): Channel["rgb"] {
9
+ const {colorDepth, channel, build, offset, extended, x16ToX8} = ctx;
8
10
 
9
11
  return (
10
- colorDepth >= 24 ? (r, g, b) => build([open + 8, 2, ...clip(r, g, b)]) :
11
- colorDepth >= 8 ? (r, g, b) => build([open + 8, 5, rgbToX256(...clip(r, g, b))]) :
12
- colorDepth >= 4 ? (r, g, b) => build(open + rgbToX16(...clip(r, g, b))) :
12
+ colorDepth >= 24 ? (r, g, b) => build(extended(2, ...clip(r, g, b))) :
13
+ colorDepth >= 8 ? (r, g, b) => build(extended(5, rgbToX256(...clip(r, g, b)))) :
14
+ colorDepth >= 4 ? (r, g, b) => build(offset(rgbToX16(...clip(r, g, b)))) :
13
15
  colorDepth === 3 ?
14
16
  channel === "fg" ?
15
17
  (r, g, b) => x16ToX8(rgbToX16(...clip(r, g, b))) :
16
- (r, g, b) => build(open + rgbToX8(...clip(r, g, b))) :
17
- () => build([])
18
+ (r, g, b) => build(offset(rgbToX8(...clip(r, g, b)))) :
19
+ () => build(Code.disabled)
18
20
  );
19
21
  }
20
22
 
21
- export function makeX256(ctx: Context): (...args: [number] | [number, number, number]) => Format {
22
- const {colorDepth, channel, build, open, x16ToX8} = ctx;
23
+ type X256 = (...args: [number] | [number, number, number]) => Format;
24
+
25
+ export function makeX256(ctx: ChannelContext): X256 {
26
+ const {colorDepth, channel, build, offset, extended, x16ToX8} = ctx;
23
27
 
24
28
  return (
25
29
  colorDepth >= 8 ?
26
30
  (...args) => build(
27
- [open + 8, 5, args.length === 3 ? rgbToX256(...clip(...args)) : clip(args[0])],
31
+ extended(5, args.length === 3 ? rgbToX256(...clip(...args)) : clip(args[0])),
28
32
  ) :
29
33
  colorDepth >= 4 ?
30
34
  (...args) => build(
31
- open +
32
- rgbToX16(...(args.length === 3 ? clip(...args) : x256ToRgb(clip(args[0])))),
35
+ offset(rgbToX16(...(args.length === 3 ? clip(...args) : x256ToRgb(clip(args[0]))))),
33
36
  ) :
34
37
  colorDepth === 3 ?
35
38
  channel === "fg" ?
@@ -38,11 +41,9 @@ export function makeX256(ctx: Context): (...args: [number] | [number, number, nu
38
41
  rgbToX16(...clip(...args)) :
39
42
  rgbToX16(...x256ToRgb(clip(args[0]))),
40
43
  ) :
41
- (...args) => build(
42
- open + rgbToX8(
43
- ...args.length === 3 ? clip(...args) : x256ToRgb(clip(args[0])),
44
- ),
45
- ) :
46
- () => build([])
44
+ (...args) => build(offset(rgbToX8(
45
+ ...args.length === 3 ? clip(...args) : x256ToRgb(clip(args[0])),
46
+ ))) :
47
+ () => build(Code.disabled)
47
48
  );
48
49
  }
@@ -1,6 +1,6 @@
1
1
  import {State} from "../simplify/state";
2
2
 
3
- import type {Code} from "./types";
3
+ import type {Code} from "#code";
4
4
 
5
5
  export const combineCodes = (base: Code, ...codes: Code[]): Code =>
6
6
  new State().update([base, ...codes].flat());
@@ -0,0 +1,68 @@
1
+ import {getFeatures} from "#features";
2
+ import {allKeys} from "./chain";
3
+ import {makeStyle} from "./style";
4
+
5
+ import type {Codes} from "#code";
6
+ import type {Features} from "#features";
7
+ import type {ChainKey} from "./chain";
8
+ import type {FormatBase} from "./format";
9
+ import type {Style} from "./style";
10
+
11
+ export interface FormatContext<Keys extends ChainKey = ChainKey> {
12
+ features : Features;
13
+ keys : ReadonlySet<Keys>;
14
+ parentCodes? : Codes;
15
+ style : Style;
16
+ removeKey : <Key extends Keys>(key: Key) => FormatContext<Exclude<Keys, Key>>;
17
+ registerFormat : (format: FormatBase) => void;
18
+ }
19
+
20
+ function removeKey<Keys extends ChainKey, Key extends Keys>(
21
+ context : FormatContext<Keys>,
22
+ key : Key,
23
+ ): FormatContext<Exclude<Keys, Key>> {
24
+ const keys = new Set(context.keys);
25
+ keys.delete(key);
26
+ return {...context, keys: keys as unknown as ReadonlySet<Exclude<Keys, Key>>};
27
+ }
28
+
29
+ const cache = new WeakMap<FormatBase, FormatContext<any>>();
30
+
31
+ export function getContext(format: FormatBase, features?: Features): FormatContext<any> {
32
+ let context = cache.get(format);
33
+ if (context)
34
+ return context;
35
+
36
+ features ??= getFeatures(format.open ? 24 : 1);
37
+
38
+ context = {
39
+ features,
40
+ keys : allKeys,
41
+ parentCodes : format.codes,
42
+ style : undefined as unknown as Style,
43
+ removeKey : key => removeKey(context!, key),
44
+ registerFormat : (format: FormatBase) => void cache.set(format, context!),
45
+ };
46
+ context.style = makeStyle(context);
47
+
48
+ cache.set(format, context);
49
+ return context;
50
+ }
51
+
52
+ export function createContext<Keys extends ChainKey = ChainKey>(
53
+ features : Features,
54
+ parentCodes? : Codes,
55
+ keys? : ReadonlySet<Keys>,
56
+ ): FormatContext<Keys> {
57
+ const context: FormatContext<Keys> = {
58
+ features,
59
+ keys : keys ?? allKeys as ReadonlySet<Keys>,
60
+ parentCodes,
61
+ style : undefined as unknown as Style,
62
+ removeKey : key => removeKey(context, key),
63
+ registerFormat : format => void cache.set(format, context),
64
+ };
65
+ context.style = makeStyle(keys ? {...context, keys: allKeys} : context);
66
+
67
+ return context;
68
+ }
@@ -0,0 +1,72 @@
1
+ import {Code} from "#code";
2
+ import {codeSequence, csi} from "#utils";
3
+ import {define} from "@peteanderson/props";
4
+ import {attachChain} from "./chain";
5
+ import {combineCodes} from "./combine";
6
+
7
+ import type {Codes} from "#code";
8
+ import type {Chain, ChainKey} from "./chain";
9
+ import type {FormatContext} from "./context";
10
+
11
+ export interface FormatBase {
12
+ (text: string): string;
13
+
14
+ open : string;
15
+ close : string;
16
+ codes : Codes;
17
+ combine : (...formats: [FormatBase, ...FormatBase[]]) => FormatBase;
18
+ }
19
+
20
+ export interface ChainedFormat<Keys extends ChainKey = ChainKey> extends FormatBase {
21
+ and: Chain<Keys>;
22
+ }
23
+
24
+ export type Format<Keys extends ChainKey = ChainKey> =
25
+ [Keys] extends [never] ? FormatBase : ChainedFormat<Keys>;
26
+
27
+ export function makeFormat<Keys extends ChainKey = ChainKey>(
28
+ context : FormatContext<Keys>,
29
+ open : Code,
30
+ close : Code,
31
+ reset? : boolean,
32
+ ): Format<Keys> {
33
+ if (context.parentCodes) {
34
+ open = combineCodes(context.parentCodes.open, open);
35
+ close = combineCodes(close, context.parentCodes.close);
36
+ }
37
+
38
+ const openCode = codeSequence(open);
39
+ const closeCode = codeSequence(close);
40
+ const openSequence = csi(open, "m");
41
+ const closeSequence = csi(close, "m");
42
+ const reopenCode = reset ? `${closeCode};${openCode}` : openCode;
43
+
44
+ const rxClose = new RegExp(
45
+ `(?<start>\\x1b\\[(?:\\d+;)*)${closeCode}(?<end>(?:;\\d+)*m)`,
46
+ "g"
47
+ );
48
+ const replace = `$<start>${reopenCode}$<end>`;
49
+
50
+ const format = attachChain(context, define(
51
+ openSequence
52
+ ? (s: string) => s ? openSequence + s.replace(rxClose, replace) + closeSequence : s
53
+ : (s: string) => s,
54
+ {
55
+ open : {value: openSequence, enumerable: true},
56
+ close : {value: closeSequence, enumerable: true},
57
+ codes : {value: {open, close}, enumerable: true},
58
+ combine : {
59
+ value: (...formats: [FormatBase, ...FormatBase[]]) => makeFormat(
60
+ context,
61
+ combineCodes(open, ...formats.map(f => f.codes.open)),
62
+ combineCodes(close, ...formats.map(f => f.codes.close)),
63
+ reset,
64
+ ),
65
+ enumerable: true,
66
+ },
67
+ },
68
+ ));
69
+
70
+ context.registerFormat(format);
71
+ return format;
72
+ };
package/src/sgr/index.ts CHANGED
@@ -1,3 +1,5 @@
1
- export * from "./sgr";
1
+ export {chain} from "./chain"; // This export must come first to avoid circular dependency issues.
2
+ export * from "./sgr";
2
3
 
3
- export {SGR} from "./types";
4
+ export type {AddChain, ChainKey} from "./chain";
5
+ export type {Format, FormatBase} from "./format";
package/src/sgr/reset.ts CHANGED
@@ -1,3 +1,3 @@
1
- import {csi} from "../utils";
1
+ import {csi} from "#utils";
2
2
 
3
3
  export const makeReset = (enabled = true): string => enabled ? csi("m") : "";
package/src/sgr/sgr.ts CHANGED
@@ -1,30 +1,20 @@
1
- import {TypedObject} from "../typed-object";
2
- import {makeColor} from "./color";
3
- import {combineCodes} from "./combine";
4
- import {makeFormatBuilder} from "./format-builder";
5
- import {makeReset} from "./reset";
6
- import {makeStyle} from "./style";
7
-
8
- import type {ColorDepth, Features} from "../features";
9
- import type {Chain, ChainKey, FormatBase, FormatBuilder, SGR} from "./types";
10
-
11
- const keyMap: Record<ChainKey, undefined> = {
12
- fg : undefined,
13
- bg : undefined,
14
- bold : undefined,
15
- dim : undefined,
16
- italic : undefined,
17
- underline : undefined,
18
- inverse : undefined,
19
- hidden : undefined,
20
- strikethrough : undefined,
21
- doubleUnderline : undefined,
22
- frame : undefined,
23
- encircle : undefined,
24
- overline : undefined,
25
- };
26
-
27
- const allKeys: ReadonlySet<ChainKey> = new Set(TypedObject.keys(keyMap));
1
+ import {Code} from "#code";
2
+ import {makeColor} from "./color";
3
+ import {createContext} from "./context";
4
+ import {makeFormat} from "./format";
5
+ import {makeReset} from "./reset";
6
+
7
+ import type {ColorDepth, Features} from "#features";
8
+ import type {ChainKey} from "./chain";
9
+ import type {Color} from "./color";
10
+ import type {Format} from "./format";
11
+ import type {Style} from "./style";
12
+
13
+ export interface SGR extends Color<ChainKey> {
14
+ style : Style;
15
+ plain : Format<ChainKey>;
16
+ reset : string;
17
+ }
28
18
 
29
19
  const cache: Partial<Record<`${ColorDepth}.${boolean}`, SGR>> = {};
30
20
 
@@ -33,30 +23,12 @@ export function makeSGR(features: Features): SGR {
33
23
  if (cache[cacheKey])
34
24
  return cache[cacheKey];
35
25
 
36
- const makeFormat = makeFormatBuilder(makeChain);
37
- const style = makeStyle(allKeys, makeFormat, features.style);
38
-
39
- function makeChain<Keys extends ChainKey>(
40
- keys : ReadonlySet<Keys>,
41
- baseFormat : FormatBase,
42
- ): Chain<Keys> {
43
- const makeChainedFormat: FormatBuilder = (keys, open, close, reset) => makeFormat(
44
- keys,
45
- combineCodes(baseFormat.codes.open, open),
46
- combineCodes(baseFormat.codes.close, close),
47
- reset,
48
- );
49
-
50
- return {
51
- ...makeColor(keys, makeChainedFormat, style, features.colorDepth),
52
- ...makeStyle(keys, makeChainedFormat, features.style),
53
- };
54
- }
26
+ const context = createContext(features);
55
27
 
56
28
  const rtn: SGR = {
57
- ...makeColor(allKeys, makeFormat, style, features.colorDepth),
58
- style,
59
- plain : makeFormat(allKeys, [], []),
29
+ ...makeColor(context),
30
+ style : context.style,
31
+ plain : makeFormat(context, Code.disabled, Code.disabled),
60
32
  reset : makeReset(features.colorDepth > 1 || features.style),
61
33
  };
62
34