@promptctl/rich-js 0.17.0 → 0.18.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 (206) hide show
  1. package/README.md +13 -26
  2. package/package.json +7 -3
  3. package/dist/core/box.d.ts +0 -144
  4. package/dist/core/box.js +0 -391
  5. package/dist/core/cells.d.ts +0 -148
  6. package/dist/core/cells.js +0 -266
  7. package/dist/core/color.d.ts +0 -250
  8. package/dist/core/color.js +0 -1029
  9. package/dist/core/console.d.ts +0 -156
  10. package/dist/core/console.js +0 -472
  11. package/dist/core/emoji.d.ts +0 -24
  12. package/dist/core/emoji.js +0 -391
  13. package/dist/core/export-html.d.ts +0 -24
  14. package/dist/core/export-html.js +0 -106
  15. package/dist/core/export-lines.d.ts +0 -121
  16. package/dist/core/export-lines.js +0 -141
  17. package/dist/core/highlighter.d.ts +0 -33
  18. package/dist/core/highlighter.js +0 -124
  19. package/dist/core/json.d.ts +0 -27
  20. package/dist/core/json.js +0 -53
  21. package/dist/core/markup.d.ts +0 -97
  22. package/dist/core/markup.js +0 -619
  23. package/dist/core/measure.d.ts +0 -27
  24. package/dist/core/measure.js +0 -61
  25. package/dist/core/oklch.d.ts +0 -161
  26. package/dist/core/oklch.js +0 -312
  27. package/dist/core/osc8.d.ts +0 -68
  28. package/dist/core/osc8.js +0 -90
  29. package/dist/core/pretty.d.ts +0 -141
  30. package/dist/core/pretty.js +0 -472
  31. package/dist/core/protocol.d.ts +0 -137
  32. package/dist/core/protocol.js +0 -101
  33. package/dist/core/render.d.ts +0 -84
  34. package/dist/core/render.js +0 -145
  35. package/dist/core/segment.d.ts +0 -142
  36. package/dist/core/segment.js +0 -433
  37. package/dist/core/spinnerData.d.ts +0 -10
  38. package/dist/core/spinnerData.js +0 -115
  39. package/dist/core/strip.d.ts +0 -145
  40. package/dist/core/strip.js +0 -308
  41. package/dist/core/style.d.ts +0 -144
  42. package/dist/core/style.js +0 -723
  43. package/dist/core/subscription.d.ts +0 -12
  44. package/dist/core/subscription.js +0 -12
  45. package/dist/core/text.d.ts +0 -255
  46. package/dist/core/text.js +0 -990
  47. package/dist/core/wrap.d.ts +0 -41
  48. package/dist/core/wrap.js +0 -127
  49. package/dist/host/host-stream.d.ts +0 -30
  50. package/dist/host/host-stream.js +0 -35
  51. package/dist/host/index.d.ts +0 -3
  52. package/dist/host/index.js +0 -2
  53. package/dist/host/terminal-host.d.ts +0 -143
  54. package/dist/host/terminal-host.js +0 -132
  55. package/dist/index.d.ts +0 -87
  56. package/dist/index.js +0 -104
  57. package/dist/node/prompt.d.ts +0 -21
  58. package/dist/node/prompt.js +0 -30
  59. package/dist/node/save.d.ts +0 -17
  60. package/dist/node/save.js +0 -21
  61. package/dist/node/terminal-host.d.ts +0 -84
  62. package/dist/node/terminal-host.js +0 -160
  63. package/dist/node/traceback.d.ts +0 -27
  64. package/dist/node/traceback.js +0 -112
  65. package/dist/renderables/align.d.ts +0 -16
  66. package/dist/renderables/align.js +0 -46
  67. package/dist/renderables/columns.d.ts +0 -61
  68. package/dist/renderables/columns.js +0 -168
  69. package/dist/renderables/constrain.d.ts +0 -15
  70. package/dist/renderables/constrain.js +0 -37
  71. package/dist/renderables/flexStrip.d.ts +0 -41
  72. package/dist/renderables/flexStrip.js +0 -200
  73. package/dist/renderables/group.d.ts +0 -11
  74. package/dist/renderables/group.js +0 -15
  75. package/dist/renderables/layout.d.ts +0 -92
  76. package/dist/renderables/layout.js +0 -315
  77. package/dist/renderables/live.d.ts +0 -47
  78. package/dist/renderables/live.js +0 -131
  79. package/dist/renderables/markdown.d.ts +0 -24
  80. package/dist/renderables/markdown.js +0 -182
  81. package/dist/renderables/padding.d.ts +0 -38
  82. package/dist/renderables/padding.js +0 -140
  83. package/dist/renderables/panel.d.ts +0 -116
  84. package/dist/renderables/panel.js +0 -322
  85. package/dist/renderables/progress.d.ts +0 -90
  86. package/dist/renderables/progress.js +0 -241
  87. package/dist/renderables/progressBar.d.ts +0 -31
  88. package/dist/renderables/progressBar.js +0 -52
  89. package/dist/renderables/prompt.d.ts +0 -49
  90. package/dist/renderables/prompt.js +0 -125
  91. package/dist/renderables/rule.d.ts +0 -24
  92. package/dist/renderables/rule.js +0 -90
  93. package/dist/renderables/spinner.d.ts +0 -29
  94. package/dist/renderables/spinner.js +0 -64
  95. package/dist/renderables/status.d.ts +0 -23
  96. package/dist/renderables/status.js +0 -60
  97. package/dist/renderables/syntax.d.ts +0 -35
  98. package/dist/renderables/syntax.js +0 -114
  99. package/dist/renderables/table.d.ts +0 -182
  100. package/dist/renderables/table.js +0 -697
  101. package/dist/renderables/traceback.d.ts +0 -31
  102. package/dist/renderables/traceback.js +0 -109
  103. package/dist/renderables/tree.d.ts +0 -54
  104. package/dist/renderables/tree.js +0 -159
  105. package/dist/template-bindings/color-funcs.d.ts +0 -87
  106. package/dist/template-bindings/color-funcs.js +0 -219
  107. package/dist/template-bindings/helpers.d.ts +0 -24
  108. package/dist/template-bindings/helpers.js +0 -48
  109. package/dist/template-bindings/index.d.ts +0 -107
  110. package/dist/template-bindings/index.js +0 -144
  111. package/dist/template-bindings/palette-funcs.d.ts +0 -94
  112. package/dist/template-bindings/palette-funcs.js +0 -151
  113. package/dist/template-bindings/style-funcs.d.ts +0 -28
  114. package/dist/template-bindings/style-funcs.js +0 -151
  115. package/dist/themes/buildPalette.d.ts +0 -36
  116. package/dist/themes/buildPalette.js +0 -56
  117. package/dist/themes/colorMath.d.ts +0 -82
  118. package/dist/themes/colorMath.js +0 -254
  119. package/dist/themes/colorRef.d.ts +0 -51
  120. package/dist/themes/colorRef.js +0 -96
  121. package/dist/themes/data/atom-one-dark.d.ts +0 -3
  122. package/dist/themes/data/atom-one-dark.js +0 -158
  123. package/dist/themes/data/atom-one-light.d.ts +0 -3
  124. package/dist/themes/data/atom-one-light.js +0 -158
  125. package/dist/themes/data/catppuccin-frappe.d.ts +0 -3
  126. package/dist/themes/data/catppuccin-frappe.js +0 -158
  127. package/dist/themes/data/catppuccin-latte.d.ts +0 -3
  128. package/dist/themes/data/catppuccin-latte.js +0 -158
  129. package/dist/themes/data/catppuccin-macchiato.d.ts +0 -3
  130. package/dist/themes/data/catppuccin-macchiato.js +0 -158
  131. package/dist/themes/data/catppuccin-mocha.d.ts +0 -3
  132. package/dist/themes/data/catppuccin-mocha.js +0 -158
  133. package/dist/themes/data/cyberpunk.d.ts +0 -17
  134. package/dist/themes/data/cyberpunk.js +0 -191
  135. package/dist/themes/data/default.d.ts +0 -3
  136. package/dist/themes/data/default.js +0 -158
  137. package/dist/themes/data/dracula.d.ts +0 -3
  138. package/dist/themes/data/dracula.js +0 -158
  139. package/dist/themes/data/flexoki.d.ts +0 -3
  140. package/dist/themes/data/flexoki.js +0 -158
  141. package/dist/themes/data/gruvbox.d.ts +0 -3
  142. package/dist/themes/data/gruvbox.js +0 -158
  143. package/dist/themes/data/index.d.ts +0 -35
  144. package/dist/themes/data/index.js +0 -64
  145. package/dist/themes/data/monokai.d.ts +0 -3
  146. package/dist/themes/data/monokai.js +0 -158
  147. package/dist/themes/data/nord.d.ts +0 -3
  148. package/dist/themes/data/nord.js +0 -158
  149. package/dist/themes/data/rose-pine-dawn.d.ts +0 -3
  150. package/dist/themes/data/rose-pine-dawn.js +0 -158
  151. package/dist/themes/data/rose-pine-moon.d.ts +0 -3
  152. package/dist/themes/data/rose-pine-moon.js +0 -158
  153. package/dist/themes/data/rose-pine.d.ts +0 -3
  154. package/dist/themes/data/rose-pine.js +0 -158
  155. package/dist/themes/data/solarized-dark.d.ts +0 -3
  156. package/dist/themes/data/solarized-dark.js +0 -158
  157. package/dist/themes/data/solarized-light.d.ts +0 -3
  158. package/dist/themes/data/solarized-light.js +0 -158
  159. package/dist/themes/data/svg-export.d.ts +0 -3
  160. package/dist/themes/data/svg-export.js +0 -158
  161. package/dist/themes/data/textual-ansi.d.ts +0 -3
  162. package/dist/themes/data/textual-ansi.js +0 -158
  163. package/dist/themes/data/textual-dark.d.ts +0 -3
  164. package/dist/themes/data/textual-dark.js +0 -158
  165. package/dist/themes/data/textual-light.d.ts +0 -3
  166. package/dist/themes/data/textual-light.js +0 -158
  167. package/dist/themes/data/tokyo-night.d.ts +0 -3
  168. package/dist/themes/data/tokyo-night.js +0 -158
  169. package/dist/themes/data/types.d.ts +0 -15
  170. package/dist/themes/data/types.js +0 -1
  171. package/dist/themes/palette.d.ts +0 -21
  172. package/dist/themes/palette.js +0 -28
  173. package/dist/themes/ramp.d.ts +0 -83
  174. package/dist/themes/ramp.js +0 -122
  175. package/dist/themes/registry.d.ts +0 -43
  176. package/dist/themes/registry.js +0 -82
  177. package/dist/themes/terminalThemes.d.ts +0 -54
  178. package/dist/themes/terminalThemes.js +0 -68
  179. package/dist/themes/transpose.d.ts +0 -87
  180. package/dist/themes/transpose.js +0 -138
  181. package/dist/widgets/button.d.ts +0 -49
  182. package/dist/widgets/button.js +0 -206
  183. package/dist/widgets/checkbox.d.ts +0 -41
  184. package/dist/widgets/checkbox.js +0 -155
  185. package/dist/widgets/dropdown.d.ts +0 -67
  186. package/dist/widgets/dropdown.js +0 -453
  187. package/dist/widgets/event-router.d.ts +0 -78
  188. package/dist/widgets/event-router.js +0 -622
  189. package/dist/widgets/focus-manager.d.ts +0 -26
  190. package/dist/widgets/focus-manager.js +0 -193
  191. package/dist/widgets/index.d.ts +0 -22
  192. package/dist/widgets/index.js +0 -15
  193. package/dist/widgets/screen.d.ts +0 -98
  194. package/dist/widgets/screen.js +0 -530
  195. package/dist/widgets/slider.d.ts +0 -57
  196. package/dist/widgets/slider.js +0 -270
  197. package/dist/widgets/static-item.d.ts +0 -40
  198. package/dist/widgets/static-item.js +0 -60
  199. package/dist/widgets/text-input.d.ts +0 -274
  200. package/dist/widgets/text-input.js +0 -1162
  201. package/dist/widgets/toggle.d.ts +0 -44
  202. package/dist/widgets/toggle.js +0 -179
  203. package/dist/widgets/types.d.ts +0 -108
  204. package/dist/widgets/types.js +0 -31
  205. package/dist/widgets/widget-base.d.ts +0 -42
  206. package/dist/widgets/widget-base.js +0 -173
@@ -1,141 +0,0 @@
1
- /**
2
- * export-lines — recorded segments resolved against a `TerminalTheme` into the
3
- * lines every exporter draws.
4
- *
5
- * The HTML and SVG exporters are two encodings of one picture, and this module
6
- * is the picture. What a styled cell *looks like* — which colour its glyph is,
7
- * whether its background is painted, which decorations it carries, where it
8
- * links — is decided here, once, and an exporter decides only how to write
9
- * that down. Before it existed the decision was made twice, by a CSS method
10
- * on `Style` and by a private converter on `Console`, and the two had already
11
- * disagreed: one honoured `underline2`, the other dropped it.
12
- *
13
- * [LAW:types-are-the-program] `ExportLook` has no `reverse`, `dim`, `conceal`
14
- * or default colour, because all four are consumed by `resolveLook` and turned
15
- * into plain RGB. An exporter holding a look cannot forget to swap a reversed
16
- * run or to fade a dim one: there is nothing left in its hands to forget. That
17
- * is the whole reason the representation is resolved rather than a `Style`
18
- * handed through.
19
- *
20
- * Runs rather than a cell grid. A grid gives a wide character a phantom
21
- * continuation cell every consumer must know to skip, and gives an HTML
22
- * exporter — which lays text out by flowing it — nothing it needs. A run's
23
- * column and cell width are `cellLen` of the text before it and of its own
24
- * text; they are not stored, so they cannot disagree with the text
25
- * [LAW:one-source-of-truth]. The SVG exporter, the one consumer that positions
26
- * anything, derives them.
27
- *
28
- * Browser-safe by construction: this imports `color`, `style`, `segment` and
29
- * nothing that touches the host, so `Console` can reach it from the main
30
- * barrel and the fs half of exporting stays in `src/node/save.ts`.
31
- */
32
- import { blendRgb, ColorSpec } from "./color.js";
33
- import { NULL_STYLE } from "./style.js";
34
- /**
35
- * The URL schemes an export will link.
36
- *
37
- * A terminal hands an OSC 8 target to the user's opener; an exported page hands
38
- * it to whoever loads the page, and exports are made to be published. A
39
- * `javascript:` target that was inert in a terminal is script in a README. The
40
- * list is an allowance, not a denylist, so a scheme nobody considered is
41
- * refused rather than trusted.
42
- */
43
- const LINKABLE_SCHEMES = new Set(["http:", "https:", "mailto:", "ftp:", "file:"]);
44
- /**
45
- * `Style.link` as a link an export may write, or `null` when it may not.
46
- *
47
- * A refused link loses only its target: the run keeps its text and every other
48
- * attribute, so nothing the terminal showed disappears from the export. The
49
- * canonical `URL.href` is what comes back, since the parse is what vouches for
50
- * it.
51
- */
52
- export function parseHref(link) {
53
- if (!URL.canParse(link))
54
- return null;
55
- const url = new URL(link);
56
- return LINKABLE_SCHEMES.has(url.protocol) ? url.href : null;
57
- }
58
- /**
59
- * How far a dim glyph moves toward its background — Rich's own factor, so an
60
- * export of the same program matches the library this ports.
61
- */
62
- const DIM_FADE = 0.4;
63
- const DEFAULT_COLOR = ColorSpec.default();
64
- /**
65
- * The ground every export is drawn on under `theme`.
66
- *
67
- * An exporter paints its page or window with this; `resolveLook` flattens
68
- * every run over the same `background`, so a run showing the canvas and the
69
- * page around it cannot come out different colours.
70
- */
71
- export function exportCanvas(theme) {
72
- return {
73
- background: DEFAULT_COLOR.getTruecolor(theme, false),
74
- foreground: DEFAULT_COLOR.getTruecolor(theme, true),
75
- };
76
- }
77
- /**
78
- * A `Style` as it appears on screen under `theme`.
79
- *
80
- * The order is the terminal's: colours resolve through the theme and lose
81
- * their alpha — paper over the canvas, ink over the paper, as `toSgrCodes`
82
- * flattens them — `reverse` swaps them, `dim` fades the glyph toward whatever
83
- * background it ended up on, and `conceal` finally paints the glyph in that
84
- * background. Every step after flattening works on opaque colour, so no
85
- * exporter ever draws a translucent one. Text under `conceal` is still
86
- * present, and still selectable, in both formats.
87
- *
88
- * The one difference from `toSgrCodes` is the substrate: a terminal cannot
89
- * know what lies under its cells and assumes black, while an export draws its
90
- * own canvas and flattens over that.
91
- *
92
- * `theme` omitted is `ColorSpec.getTruecolor`'s own fallback — black canvas,
93
- * white ink, the standard ANSI table. Choosing it there rather than naming a
94
- * preset here is what keeps `core/` from a third upward edge into `themes/`.
95
- */
96
- export function resolveLook(style, theme) {
97
- const inkSpec = style.color ?? DEFAULT_COLOR;
98
- const paperSpec = style.bgcolor ?? DEFAULT_COLOR;
99
- const canvas = exportCanvas(theme).background;
100
- // [LAW:single-enforcer] `flattenAlpha` is the one place alpha is composited.
101
- const paper = paperSpec.flattenAlpha(canvas).getTruecolor(theme, false);
102
- const ink = inkSpec.flattenAlpha(paper).getTruecolor(theme, true);
103
- // A reversed run always paints: its background is the ink, which is never
104
- // the canvas, even when the ink is the theme's default foreground.
105
- const glyph = style.reverse ? paper : ink;
106
- const ground = style.reverse ? ink : paper;
107
- const background = style.reverse || !paperSpec.isDefault ? ground : "canvas";
108
- const faded = style.dim ? blendRgb(glyph, ground, DIM_FADE) : glyph;
109
- return {
110
- foreground: style.conceal ? ground : faded,
111
- background,
112
- bold: style.bold === true,
113
- italic: style.italic === true,
114
- underline: style.underline2 ? "double" : style.underline ? "single" : "none",
115
- strike: style.strike === true,
116
- overline: style.overline === true,
117
- blink: style.blink2 ? "fast" : style.blink ? "slow" : "none",
118
- outline: style.encircle ? "encircle" : style.frame ? "frame" : "none",
119
- href: style.link === undefined ? null : parseHref(style.link),
120
- };
121
- }
122
- /**
123
- * Recorded segments as terminal rows under `theme`.
124
- *
125
- * `"\n"` ends a row, so output that ends with a newline — every `print` does —
126
- * has no empty row after it, and `"a\n\nb"` keeps its blank row. Callers pass
127
- * the recording buffer, which already holds no control segments.
128
- */
129
- export function exportLines(segments, theme) {
130
- const rows = [[]];
131
- for (const segment of segments) {
132
- const look = resolveLook(segment.style ?? NULL_STYLE, theme);
133
- segment.text.split("\n").forEach((piece, index) => {
134
- if (index > 0)
135
- rows.push([]);
136
- if (piece.length > 0)
137
- rows[rows.length - 1].push({ text: piece, look });
138
- });
139
- }
140
- return rows[rows.length - 1].length === 0 ? rows.slice(0, -1) : rows;
141
- }
@@ -1,33 +0,0 @@
1
- /**
2
- * Highlighters — apply styled spans to RichText based on pattern matching.
3
- */
4
- import { RichText } from "./text.js";
5
- export declare abstract class Highlighter {
6
- abstract highlight(text: RichText): void;
7
- call(input: string): RichText;
8
- }
9
- export declare class NullHighlighter extends Highlighter {
10
- highlight(_text: RichText): void;
11
- }
12
- export declare class RegexHighlighter extends Highlighter {
13
- static highlights: (string | RegExp)[];
14
- /** Style applied to matches. When ending with "." it acts as a namespace
15
- * prefix: named groups become `baseStyle + groupName` (e.g. "repr." + "url"
16
- * → "repr.url"). Otherwise it's used as a literal style for all matches
17
- * (e.g. "bold red" applies "bold red" to every named group). */
18
- static baseStyle: string;
19
- highlight(text: RichText): void;
20
- }
21
- export declare class ReprHighlighter extends RegexHighlighter {
22
- static baseStyle: string;
23
- static highlights: RegExp[];
24
- }
25
- export declare class JSONHighlighter extends RegexHighlighter {
26
- static baseStyle: string;
27
- static highlights: string[];
28
- highlight(text: RichText): void;
29
- }
30
- export declare class ISO8601Highlighter extends RegexHighlighter {
31
- static baseStyle: string;
32
- static highlights: RegExp[];
33
- }
@@ -1,124 +0,0 @@
1
- /**
2
- * Highlighters — apply styled spans to RichText based on pattern matching.
3
- */
4
- import { RichText } from "./text.js";
5
- // --- Base ---
6
- export class Highlighter {
7
- call(input) {
8
- const text = new RichText(input);
9
- this.highlight(text);
10
- return text;
11
- }
12
- }
13
- // --- NullHighlighter ---
14
- export class NullHighlighter extends Highlighter {
15
- highlight(_text) {
16
- // No-op
17
- }
18
- }
19
- // --- RegexHighlighter ---
20
- export class RegexHighlighter extends Highlighter {
21
- static highlights = [];
22
- /** Style applied to matches. When ending with "." it acts as a namespace
23
- * prefix: named groups become `baseStyle + groupName` (e.g. "repr." + "url"
24
- * → "repr.url"). Otherwise it's used as a literal style for all matches
25
- * (e.g. "bold red" applies "bold red" to every named group). */
26
- static baseStyle = "";
27
- highlight(text) {
28
- const ctor = this.constructor;
29
- const baseStyle = ctor.baseStyle;
30
- // Namespace mode: "repr." + groupName → "repr.url"
31
- // Literal mode: "bold red" → applied directly to every match
32
- const isNamespace = baseStyle.endsWith(".");
33
- for (const pattern of ctor.highlights) {
34
- const re = pattern instanceof RegExp
35
- ? new RegExp(pattern.source, pattern.flags.includes("g") ? pattern.flags : pattern.flags + "g")
36
- : new RegExp(pattern, "g");
37
- let match;
38
- while ((match = re.exec(text.plain)) !== null) {
39
- if (match[0].length === 0) {
40
- re.lastIndex++;
41
- continue;
42
- }
43
- if (match.groups) {
44
- let searchFrom = 0;
45
- for (const [groupName, groupValue] of Object.entries(match.groups)) {
46
- if (groupValue !== undefined) {
47
- const posInMatch = match[0].indexOf(groupValue, searchFrom);
48
- if (posInMatch >= 0) {
49
- const start = match.index + posInMatch;
50
- const style = isNamespace
51
- ? `${baseStyle}${groupName}`
52
- : baseStyle || groupName;
53
- text.stylize(style, start, start + groupValue.length);
54
- searchFrom = posInMatch + groupValue.length;
55
- }
56
- }
57
- }
58
- }
59
- }
60
- }
61
- }
62
- }
63
- // --- ReprHighlighter ---
64
- // [LAW:one-type-per-behavior] All repr patterns use the same RegexHighlighter mechanism
65
- export class ReprHighlighter extends RegexHighlighter {
66
- static baseStyle = "repr.";
67
- static highlights = [
68
- // URLs
69
- /(?<url>https?:\/\/[^\s<>"']+)/g,
70
- // UUIDs
71
- /(?<uuid>[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/gi,
72
- // Quoted strings
73
- /(?<str>'[^']*'|"[^"]*")/g,
74
- // Booleans
75
- /(?<bool>\btrue\b|\bfalse\b)/g,
76
- // None/null/undefined
77
- /(?<none>\bnull\b|\bundefined\b|\bNone\b)/g,
78
- // Numbers (integers and floats)
79
- /(?<number>(?<!\w)-?(?:0x[0-9a-f]+|\d+(?:\.\d+)?(?:e[+-]?\d+)?)(?!\w))/gi,
80
- ];
81
- }
82
- // --- JSONHighlighter ---
83
- // A JSON string as Python Rich 9d8f9a3 matches one, `b` bytes prefix included:
84
- // an opening quote with no backslash or word character before it, through the
85
- // first quote with no backslash before it, so an escaped quote stays inside.
86
- const JSON_STR = String.raw `(?<![\\\w])(?<str>b?".*?(?<!\\)")`;
87
- export class JSONHighlighter extends RegexHighlighter {
88
- static baseStyle = "json.";
89
- // [LAW:dataflow-not-control-flow] One alternation, scanned once, as Rich's
90
- // `_combine_regex` joins it. A token claims its characters where the scan
91
- // meets it, so the `true` and `12` inside `"true 12"` belong to the string.
92
- static highlights = [
93
- [
94
- String.raw `(?<brace>[\{\[\(\)\]\}])`,
95
- String.raw `\b(?<bool_true>true)\b|\b(?<bool_false>false)\b|\b(?<null>null)\b`,
96
- String.raw `(?<number>(?<!\w)\-?[0-9]+\.?[0-9]*(e[\-\+]?\d+?)?\b|0x[0-9a-fA-F]*)`,
97
- JSON_STR,
98
- ].join("|"),
99
- ];
100
- // A string followed by a colon is also a key. Its `json.key` span comes after
101
- // its `json.str` span, so the key style lands on top. Each string is found on
102
- // its own and then checked for a colon. One `string(?=:)` pattern would get
103
- // this wrong: its lazy body can stretch past a value's closing quote to the
104
- // next key's, marking `"b", "c"` in `{"a": "b", "c": 1}` as one key.
105
- highlight(text) {
106
- super.highlight(text);
107
- const colon = /[ \n\r\t]*:/y;
108
- for (const { index, 0: str } of text.plain.matchAll(new RegExp(JSON_STR, "g"))) {
109
- const end = index + str.length;
110
- colon.lastIndex = end;
111
- if (colon.test(text.plain))
112
- text.stylize("json.key", index, end);
113
- }
114
- }
115
- }
116
- // --- ISO8601Highlighter ---
117
- export class ISO8601Highlighter extends RegexHighlighter {
118
- static baseStyle = "iso8601.";
119
- static highlights = [
120
- /(?<date>\d{4}-\d{2}-\d{2})/g,
121
- /(?<time>\d{2}:\d{2}:\d{2}(?:\.\d+)?)/g,
122
- /(?<timezone>[+-]\d{2}:\d{2}|Z)/g,
123
- ];
124
- }
@@ -1,27 +0,0 @@
1
- /**
2
- * JSON — renders JSON data with syntax highlighting and pretty-printing.
3
- *
4
- * Lives in `core/` for the reason `pretty.ts` does, argued in its header: it
5
- * turns foreign input into `RichText`, composes no other renderable, and
6
- * imports core primitives only. `Console.printJson` delegates here, so this is
7
- * where the console can reach it without an upward edge. [LAW:one-way-deps]
8
- */
9
- import { Segment } from "./segment.js";
10
- import { RichText } from "./text.js";
11
- import type { Renderable, Measurable, RenderOptions } from "./protocol.js";
12
- export interface JSONOptions {
13
- indent?: number;
14
- sortKeys?: boolean;
15
- highlight?: boolean;
16
- }
17
- export declare class JSONRenderable implements Renderable, Measurable {
18
- readonly text: RichText;
19
- private constructor();
20
- static fromString(jsonString: string, options?: JSONOptions): JSONRenderable;
21
- static fromData(data: unknown, options?: JSONOptions): JSONRenderable;
22
- render(options: RenderOptions): Iterable<Segment>;
23
- measure(options: RenderOptions): {
24
- minimum: number;
25
- maximum: number;
26
- };
27
- }
package/dist/core/json.js DELETED
@@ -1,53 +0,0 @@
1
- /**
2
- * JSON — renders JSON data with syntax highlighting and pretty-printing.
3
- *
4
- * Lives in `core/` for the reason `pretty.ts` does, argued in its header: it
5
- * turns foreign input into `RichText`, composes no other renderable, and
6
- * imports core primitives only. `Console.printJson` delegates here, so this is
7
- * where the console can reach it without an upward edge. [LAW:one-way-deps]
8
- */
9
- import { RichText } from "./text.js";
10
- import { JSONHighlighter } from "./highlighter.js";
11
- const highlighter = new JSONHighlighter();
12
- export class JSONRenderable {
13
- text;
14
- constructor(text) {
15
- this.text = text;
16
- }
17
- static fromString(jsonString, options) {
18
- const indent = options?.indent ?? 2;
19
- const sortKeys = options?.sortKeys ?? false;
20
- // Parse and re-serialize for consistent formatting
21
- const data = JSON.parse(jsonString);
22
- return JSONRenderable.fromData(data, { ...options, indent, sortKeys });
23
- }
24
- static fromData(data, options) {
25
- const indent = options?.indent ?? 2;
26
- const sortKeys = options?.sortKeys ?? false;
27
- const doHighlight = options?.highlight !== false;
28
- const replacer = sortKeys
29
- ? (_key, value) => {
30
- if (value !== null && typeof value === "object" && !Array.isArray(value)) {
31
- const sorted = {};
32
- for (const k of Object.keys(value).sort()) {
33
- sorted[k] = value[k];
34
- }
35
- return sorted;
36
- }
37
- return value;
38
- }
39
- : undefined;
40
- const jsonStr = JSON.stringify(data, replacer, indent);
41
- const text = new RichText(jsonStr, { end: "" });
42
- if (doHighlight) {
43
- highlighter.highlight(text);
44
- }
45
- return new JSONRenderable(text);
46
- }
47
- *render(options) {
48
- yield* this.text.render(options);
49
- }
50
- measure(options) {
51
- return this.text.measure(options);
52
- }
53
- }
@@ -1,97 +0,0 @@
1
- /**
2
- * Markup — BBCode-inspired markup parser for inline styling.
3
- * Parses `[bold red]text[/bold red]` into RichText with styled spans.
4
- *
5
- * Plugin tags ([LAW:locality-or-seam]): a `MarkupRegistry` lets consumers
6
- * register tag handlers without forking the parser. When the parser sees
7
- * `[name attrs...]inner[/name]` and `name` is registered, it parses attrs,
8
- * recursively renders the inner markup as a child Renderable, and calls the
9
- * handler — splicing the handler's returned Renderable into the output. The
10
- * built-in style dialect and the plugin dialect are routed by the registry,
11
- * which is the single trust boundary between them.
12
- *
13
- * Plugin pairs must nest. The built-in dialect admits non-strict nesting
14
- * (`[bold]a[italic]b[/bold]c[/italic]`) because a style is an annotation and
15
- * annotations may overlap freely; a plugin tag is a replacement whose handler
16
- * takes one contiguous `inner`, so an overlapping pair has no slice to hand it
17
- * and is rejected with a `MarkupSyntaxError`.
18
- */
19
- import { Style } from "./style.js";
20
- import { RichText } from "./text.js";
21
- export declare class Tag {
22
- readonly name: string;
23
- readonly parameters: string | undefined;
24
- constructor(name: string, parameters?: string);
25
- toString(): string;
26
- get markup(): string;
27
- }
28
- export declare class MarkupError extends Error {
29
- constructor(message: string);
30
- }
31
- /**
32
- * A markup string that cannot be parsed, with where it went wrong.
33
- *
34
- * [LAW:types-are-the-program] A subclass rather than optional fields on
35
- * `MarkupError`, because the parent is also what `MarkupRegistry.register`
36
- * throws, and a registration has no source text to point into. Every error this
37
- * class describes has a location, so none of its fields is optional and no
38
- * caller has to ask whether one is present — `instanceof` is the only question.
39
- *
40
- * [LAW:one-source-of-truth] The constructor takes the facts the parser holds —
41
- * the string, the offset of the offending tag, what was open — and derives
42
- * `line`, `column` and the message from them, so the numbers a caller reads
43
- * and the caret the message draws cannot disagree.
44
- */
45
- export declare class MarkupSyntaxError extends MarkupError {
46
- /** The problem alone, with no location, for callers building their own message. */
47
- readonly reason: string;
48
- /** The whole markup string that failed, as the caller passed it. */
49
- readonly markup: string;
50
- /** Index into `markup` of the tag the parser rejected. */
51
- readonly offset: number;
52
- /** 1-based line of `offset`; lines are separated by `\n`. */
53
- readonly line: number;
54
- /** 1-based column of `offset` within its line, in UTF-16 code units. */
55
- readonly column: number;
56
- /**
57
- * The opening tags still open at `offset`, outermost first, as written. For
58
- * overlapping plugin tags, only plugin tags are named.
59
- */
60
- readonly openTags: readonly string[];
61
- constructor(reason: string, markup: string, offset: number, openTags: readonly string[]);
62
- }
63
- /**
64
- * Escapes markup characters so they render as literal text.
65
- */
66
- export declare function escape(text: string): string;
67
- export interface MarkupTagContext {
68
- /** Parsed `key=value` attributes from the opening tag. */
69
- attrs: Record<string, string>;
70
- /** Inner markup, already parsed (registry-aware) into a `RichText`. */
71
- children: RichText;
72
- /** Raw inner markup text (between the opening tag's `]` and the closing tag's `[`). */
73
- raw: string;
74
- }
75
- export type MarkupTagHandler = (ctx: MarkupTagContext) => RichText;
76
- export declare class MarkupRegistry {
77
- private readonly _handlers;
78
- register(name: string, handler: MarkupTagHandler): void;
79
- unregister(name: string): void;
80
- has(name: string): boolean;
81
- get(name: string): MarkupTagHandler | undefined;
82
- }
83
- export declare const globalMarkupRegistry: MarkupRegistry;
84
- export interface RenderMarkupOptions {
85
- registry?: MarkupRegistry;
86
- baseStyle?: string | Style;
87
- emoji?: boolean;
88
- }
89
- /**
90
- * Plugin-aware markup render. Always returns a `RichText`. Built-in style
91
- * tags become spans; registered plugin tags are resolved by their handler,
92
- * whose returned `RichText` is appended (text + spans) into the output. The
93
- * recursion is over markup *slices* — between top-level plugin tag pairs and
94
- * inside each pair — and every recursion node returns a `RichText`, so the
95
- * append path is uniform.
96
- */
97
- export declare function renderMarkup(markup: string, options?: RenderMarkupOptions): RichText;