@lewishowles/cli-style 0.8.1 → 0.10.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.
- package/CHANGELOG.md +23 -0
- package/README.md +99 -1
- package/adapters/bash/cli-style.sh +128 -6
- package/adapters/python/cli_style.py +52 -3
- package/adapters/swift/CliStyle.swift +60 -6
- package/bin/cli-style.js +10 -0
- package/package.json +1 -1
- package/src/capability/terminal.js +98 -0
- package/src/catalogue/renderer-catalogue.js +62 -0
- package/src/cli/catalogue-command.js +108 -0
- package/src/cli/gallery-command.js +8 -1
- package/src/cli/help.js +5 -0
- package/src/cli/render-command.js +23 -2
- package/src/formatters/ansi.js +17 -1
- package/src/gallery/render-gallery.js +133 -2
- package/src/index.js +19 -2
- package/src/patterns/diff-block.js +333 -0
- package/src/primitives/chip.js +1 -1
- package/src/primitives/panel.js +6 -1
- package/src/primitives/row-group.js +84 -0
- package/src/primitives/sparkline.js +209 -0
- package/src/theme/colours.js +172 -36
|
@@ -1,6 +1,11 @@
|
|
|
1
|
+
import { isTheme, themes } from "../theme/colours.js";
|
|
2
|
+
|
|
1
3
|
// Default terminal width when no stream width is available.
|
|
2
4
|
const defaultWidth = 80;
|
|
3
5
|
|
|
6
|
+
// Known terminal signals support a conservative dark palette when no theme is explicit.
|
|
7
|
+
const terminalThemeSignals = ["COLORTERM", "TERM_PROGRAM"];
|
|
8
|
+
|
|
4
9
|
/**
|
|
5
10
|
* Resolve terminal output capabilities from injected args, env, and stream data.
|
|
6
11
|
*
|
|
@@ -47,11 +52,104 @@ export function resolveTerminalCapabilities(options = {}) {
|
|
|
47
52
|
isCi,
|
|
48
53
|
isDumb,
|
|
49
54
|
isTty,
|
|
55
|
+
theme: resolveTheme({
|
|
56
|
+
argv,
|
|
57
|
+
env,
|
|
58
|
+
theme: options.theme,
|
|
59
|
+
}),
|
|
50
60
|
unicode,
|
|
51
61
|
width,
|
|
52
62
|
};
|
|
53
63
|
}
|
|
54
64
|
|
|
65
|
+
/**
|
|
66
|
+
* Resolve a terminal theme from explicit overrides and terminal signals.
|
|
67
|
+
*
|
|
68
|
+
* @param {object} options
|
|
69
|
+
* Theme resolution inputs.
|
|
70
|
+
* @returns {string}
|
|
71
|
+
* Resolved light or dark theme.
|
|
72
|
+
*/
|
|
73
|
+
export function resolveTheme(options = {}) {
|
|
74
|
+
const flagTheme = readThemeFlag(options.argv ?? []);
|
|
75
|
+
|
|
76
|
+
if (flagTheme !== undefined) {
|
|
77
|
+
return flagTheme;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (isTheme(options.theme) && options.theme !== themes.AUTO) {
|
|
81
|
+
return options.theme;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const colourFgBgTheme = resolveColourFgBgTheme(options.env?.COLORFGBG);
|
|
85
|
+
|
|
86
|
+
if (colourFgBgTheme !== themes.AUTO) {
|
|
87
|
+
return colourFgBgTheme;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return resolveTerminalSignalTheme(options.env) ?? themes.DARK;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Resolve a conservative theme from best-effort terminal signals.
|
|
95
|
+
*
|
|
96
|
+
* @param {object} env
|
|
97
|
+
* Environment values to inspect.
|
|
98
|
+
* @returns {string|undefined}
|
|
99
|
+
* Dark theme when a known terminal signal is present.
|
|
100
|
+
*/
|
|
101
|
+
function resolveTerminalSignalTheme(env = {}) {
|
|
102
|
+
if (terminalThemeSignals.some((signal) => env[signal])) {
|
|
103
|
+
return themes.DARK;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return undefined;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Resolve known COLORFGBG background slots without guessing custom palettes.
|
|
111
|
+
*
|
|
112
|
+
* @param {string} colourFgBg
|
|
113
|
+
* Terminal foreground and background capability string.
|
|
114
|
+
* @returns {string}
|
|
115
|
+
* Resolved light, dark, or automatic theme.
|
|
116
|
+
*/
|
|
117
|
+
function resolveColourFgBgTheme(colourFgBg) {
|
|
118
|
+
const background = colourFgBg?.split(";").at(-1);
|
|
119
|
+
|
|
120
|
+
if (background === "0" || background === "8") {
|
|
121
|
+
return themes.DARK;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (background === "7" || background === "15") {
|
|
125
|
+
return themes.LIGHT;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return themes.AUTO;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Read the final explicit theme flag so later command arguments can override earlier ones.
|
|
133
|
+
*
|
|
134
|
+
* @param {string[]} argv
|
|
135
|
+
* CLI arguments to inspect.
|
|
136
|
+
* @returns {string|undefined}
|
|
137
|
+
* Explicit theme when present.
|
|
138
|
+
*/
|
|
139
|
+
function readThemeFlag(argv) {
|
|
140
|
+
let theme;
|
|
141
|
+
|
|
142
|
+
for (const argument of argv) {
|
|
143
|
+
if (argument === "--dark") {
|
|
144
|
+
theme = themes.DARK;
|
|
145
|
+
} else if (argument === "--light") {
|
|
146
|
+
theme = themes.LIGHT;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return theme;
|
|
151
|
+
}
|
|
152
|
+
|
|
55
153
|
/**
|
|
56
154
|
* Resolve colour support from explicit flags and terminal state.
|
|
57
155
|
*
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// Static renderer metadata shared by CLI discovery and render validation.
|
|
2
|
+
export const rendererCatalogue = [
|
|
3
|
+
["agent-transcript", "pattern", "agentTranscript", ["entries"], "agent-transcript"],
|
|
4
|
+
["audit-finding", "pattern", "auditFinding", ["finding", "result"], "audit-finding"],
|
|
5
|
+
["bar-chart", "primitive", "barChart", ["rows"], undefined],
|
|
6
|
+
["chip", "primitive", "chip", ["label", "tone"], undefined],
|
|
7
|
+
["command-result", "pattern", "commandResult", ["result", "summary"], "command-result"],
|
|
8
|
+
["compact-data-table", "pattern", "compactDataTable", ["columns", "rows"], "compact-data-table"],
|
|
9
|
+
[
|
|
10
|
+
"confirmation-result",
|
|
11
|
+
"pattern",
|
|
12
|
+
"confirmationResult",
|
|
13
|
+
["action", "state"],
|
|
14
|
+
"confirmation-result",
|
|
15
|
+
],
|
|
16
|
+
[
|
|
17
|
+
"diagnostic-report",
|
|
18
|
+
"pattern",
|
|
19
|
+
"diagnosticReport",
|
|
20
|
+
["findings", "summary"],
|
|
21
|
+
"diagnostic-report",
|
|
22
|
+
],
|
|
23
|
+
["diff-block", "pattern", "diffBlock", ["lines"], "diff-block"],
|
|
24
|
+
["divider", "primitive", "divider", ["label"], undefined],
|
|
25
|
+
["empty-state", "primitive", "emptyState", ["detail", "title"], undefined],
|
|
26
|
+
["error-block", "primitive", "errorBlock", ["lines", "title"], undefined],
|
|
27
|
+
["hint", "primitive", "hint", ["message"], undefined],
|
|
28
|
+
["next-step-block", "pattern", "nextStepBlock", ["next", "reason"], "next-step-block"],
|
|
29
|
+
["panel", "primitive", "panel", ["lines", "title", "tone"], undefined],
|
|
30
|
+
["progress-bar", "primitive", "progressBar", ["max", "value"], undefined],
|
|
31
|
+
["row", "primitive", "row", ["label", "value"], undefined],
|
|
32
|
+
["row-group", "primitive", "rowGroup", ["rows"], undefined],
|
|
33
|
+
["sparkline", "primitive", "sparkline", ["values"], "sparkline"],
|
|
34
|
+
["span", "primitive", "span", ["tone", "value"], undefined],
|
|
35
|
+
["status", "primitive", "status", ["detail", "type"], undefined],
|
|
36
|
+
["step", "primitive", "step", ["label", "state"], undefined],
|
|
37
|
+
["step-progress", "primitive", "stepProgress", ["current", "steps"], undefined],
|
|
38
|
+
["table", "primitive", "table", ["columns", "rows"], undefined],
|
|
39
|
+
["task-summary", "pattern", "taskSummary", ["result", "task"], "task-summary"],
|
|
40
|
+
].map(([name, category, api, fields, fixture]) => ({
|
|
41
|
+
api,
|
|
42
|
+
category,
|
|
43
|
+
fields,
|
|
44
|
+
fixture,
|
|
45
|
+
name,
|
|
46
|
+
purpose: `${api} renderer.`,
|
|
47
|
+
}));
|
|
48
|
+
|
|
49
|
+
// Stable CLI names derived from the catalogue.
|
|
50
|
+
export const rendererNames = rendererCatalogue.map((renderer) => renderer.name);
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Find renderer metadata by its stable CLI name.
|
|
54
|
+
*
|
|
55
|
+
* @param {string} name
|
|
56
|
+
* Renderer name to look up.
|
|
57
|
+
* @returns {object|undefined}
|
|
58
|
+
* Renderer metadata when found.
|
|
59
|
+
*/
|
|
60
|
+
export function getRendererMetadata(name) {
|
|
61
|
+
return rendererCatalogue.find((renderer) => renderer.name === name);
|
|
62
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { getRendererMetadata, rendererCatalogue } from "../catalogue/renderer-catalogue.js";
|
|
2
|
+
|
|
3
|
+
// Rendering flags are resolved before catalogue command parsing.
|
|
4
|
+
const globalRenderingFlags = new Set([
|
|
5
|
+
"--dark",
|
|
6
|
+
"--json",
|
|
7
|
+
"--light",
|
|
8
|
+
"--no-color",
|
|
9
|
+
"--no-colour",
|
|
10
|
+
"--no-unicode",
|
|
11
|
+
"--plain",
|
|
12
|
+
]);
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Parse a catalogue discovery request.
|
|
16
|
+
*
|
|
17
|
+
* @param {string} command
|
|
18
|
+
* Catalogue command name.
|
|
19
|
+
* @param {string[]} args
|
|
20
|
+
* Arguments after the command.
|
|
21
|
+
* @returns {object}
|
|
22
|
+
* Parsed catalogue request.
|
|
23
|
+
*/
|
|
24
|
+
export function parseCatalogueRequest(command, args = []) {
|
|
25
|
+
const commandArgs = args.filter((argument) => !globalRenderingFlags.has(argument));
|
|
26
|
+
|
|
27
|
+
if (command === "list" && commandArgs.length === 0) {
|
|
28
|
+
return {
|
|
29
|
+
command,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (
|
|
34
|
+
command === "describe" &&
|
|
35
|
+
commandArgs.length === 1 &&
|
|
36
|
+
getRendererMetadata(commandArgs[0]) !== undefined
|
|
37
|
+
) {
|
|
38
|
+
return {
|
|
39
|
+
command,
|
|
40
|
+
renderer: commandArgs[0],
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (command === "describe" && commandArgs.length === 1) {
|
|
45
|
+
throw new Error(`Unknown renderer: ${commandArgs[0]}`);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
throw new Error(
|
|
49
|
+
command === "describe" ? "Usage: cli-style describe <renderer>" : "Usage: cli-style list",
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Render catalogue data for the requested output profile.
|
|
55
|
+
*
|
|
56
|
+
* @param {object} request
|
|
57
|
+
* Parsed catalogue request.
|
|
58
|
+
* @param {object} options
|
|
59
|
+
* Resolved rendering options.
|
|
60
|
+
* @returns {string}
|
|
61
|
+
* Text or JSON catalogue output.
|
|
62
|
+
*/
|
|
63
|
+
export function renderCatalogue(request, options = {}) {
|
|
64
|
+
const data =
|
|
65
|
+
request.command === "list" ? rendererCatalogue : getRendererMetadata(request.renderer);
|
|
66
|
+
|
|
67
|
+
if (options.profile === "json") {
|
|
68
|
+
return JSON.stringify(data, null, 2);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (request.command === "describe") {
|
|
72
|
+
return renderDescription(data);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return ["primitive", "pattern"]
|
|
76
|
+
.flatMap((category) => [
|
|
77
|
+
category,
|
|
78
|
+
...rendererCatalogue
|
|
79
|
+
.filter((renderer) => renderer.category === category)
|
|
80
|
+
.map((renderer) => ` ${renderer.name} ${renderer.api}`),
|
|
81
|
+
"",
|
|
82
|
+
])
|
|
83
|
+
.slice(0, -1)
|
|
84
|
+
.join("\n");
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Render one renderer's discovery details.
|
|
89
|
+
*
|
|
90
|
+
* @param {object} renderer
|
|
91
|
+
* Renderer metadata.
|
|
92
|
+
* @returns {string}
|
|
93
|
+
* Human-readable renderer description.
|
|
94
|
+
*/
|
|
95
|
+
function renderDescription(renderer) {
|
|
96
|
+
const gallery =
|
|
97
|
+
renderer.fixture === undefined
|
|
98
|
+
? "No focused fixture."
|
|
99
|
+
: `cli-style gallery --fixture ${renderer.fixture}`;
|
|
100
|
+
|
|
101
|
+
return [
|
|
102
|
+
renderer.name,
|
|
103
|
+
`Category: ${renderer.category}`,
|
|
104
|
+
`JavaScript: ${renderer.api}`,
|
|
105
|
+
`Fields: ${renderer.fields.join(", ")}`,
|
|
106
|
+
`Gallery: ${gallery}`,
|
|
107
|
+
].join("\n");
|
|
108
|
+
}
|
|
@@ -4,7 +4,14 @@ import { galleryFixtures, gallerySections, galleryVariants } from "../gallery/re
|
|
|
4
4
|
import { isProfile, profiles } from "../profiles/profiles.js";
|
|
5
5
|
|
|
6
6
|
// Global rendering flags accepted after `gallery` for focused review commands.
|
|
7
|
-
const globalRenderingFlags = new Set([
|
|
7
|
+
const globalRenderingFlags = new Set([
|
|
8
|
+
"--dark",
|
|
9
|
+
"--light",
|
|
10
|
+
"--no-color",
|
|
11
|
+
"--no-colour",
|
|
12
|
+
"--no-unicode",
|
|
13
|
+
"--plain",
|
|
14
|
+
]);
|
|
8
15
|
|
|
9
16
|
/**
|
|
10
17
|
* Parse gallery command arguments.
|
package/src/cli/help.js
CHANGED
|
@@ -5,18 +5,23 @@ const helpLines = [
|
|
|
5
5
|
"Usage:",
|
|
6
6
|
" cli-style --help",
|
|
7
7
|
" cli-style adapter-path bash|python",
|
|
8
|
+
" cli-style list [options]",
|
|
9
|
+
" cli-style describe <renderer> [options]",
|
|
8
10
|
" cli-style gallery [variant] [options]",
|
|
9
11
|
" cli-style render <renderer> [options] < input.json",
|
|
10
12
|
"",
|
|
11
13
|
"Commands:",
|
|
12
14
|
" adapter-path Print a Bash or Python adapter path.",
|
|
13
15
|
" gallery Print the read-only style gallery.",
|
|
16
|
+
" list List available primitives and patterns.",
|
|
17
|
+
" describe Describe one renderer and its input fields.",
|
|
14
18
|
" render Render caller-provided JSON from stdin.",
|
|
15
19
|
"",
|
|
16
20
|
"Gallery variants:",
|
|
17
21
|
" current, no-colour, no-unicode, plain",
|
|
18
22
|
"",
|
|
19
23
|
"Options:",
|
|
24
|
+
" --light, --dark Override automatic terminal-theme detection.",
|
|
20
25
|
" --section <name> Show primitives or patterns.",
|
|
21
26
|
" --fixture <name> Show one named pattern fixture.",
|
|
22
27
|
" --profile <name> Render with a text profile.",
|
|
@@ -4,6 +4,7 @@ import { commandResult } from "../patterns/command-result.js";
|
|
|
4
4
|
import { compactDataTable } from "../patterns/compact-data-table.js";
|
|
5
5
|
import { confirmationResult } from "../patterns/confirmation-result.js";
|
|
6
6
|
import { diagnosticReport } from "../patterns/diagnostic-report.js";
|
|
7
|
+
import { diffBlock } from "../patterns/diff-block.js";
|
|
7
8
|
import { nextStepBlock } from "../patterns/next-step-block.js";
|
|
8
9
|
import { taskSummary } from "../patterns/task-summary.js";
|
|
9
10
|
import { barChart } from "../primitives/bar-chart.js";
|
|
@@ -13,11 +14,14 @@ import { emptyState, errorBlock, hint } from "../primitives/feedback.js";
|
|
|
13
14
|
import { panel } from "../primitives/panel.js";
|
|
14
15
|
import { progressBar } from "../primitives/progress-bar.js";
|
|
15
16
|
import { row } from "../primitives/row.js";
|
|
17
|
+
import { rowGroup } from "../primitives/row-group.js";
|
|
18
|
+
import { sparkline } from "../primitives/sparkline.js";
|
|
16
19
|
import { span } from "../primitives/span.js";
|
|
17
20
|
import { status } from "../primitives/status.js";
|
|
18
21
|
import { step, stepProgress } from "../primitives/step-progress.js";
|
|
19
22
|
import { table } from "../primitives/table.js";
|
|
20
23
|
import { isProfile, profiles } from "../profiles/profiles.js";
|
|
24
|
+
export { rendererNames } from "../catalogue/renderer-catalogue.js";
|
|
21
25
|
|
|
22
26
|
// Renderer names accepted by the custom-input render command.
|
|
23
27
|
const renderers = {
|
|
@@ -37,6 +41,7 @@ const renderers = {
|
|
|
37
41
|
"compact-data-table": (input, options) => compactDataTable(input, options),
|
|
38
42
|
"confirmation-result": (input, options) => confirmationResult(input, options),
|
|
39
43
|
"diagnostic-report": (input, options) => diagnosticReport(input, options),
|
|
44
|
+
"diff-block": (input, options) => diffBlock(input, options),
|
|
40
45
|
divider: (input, options) =>
|
|
41
46
|
divider({
|
|
42
47
|
...input,
|
|
@@ -73,6 +78,16 @@ const renderers = {
|
|
|
73
78
|
...input,
|
|
74
79
|
...options,
|
|
75
80
|
}),
|
|
81
|
+
"row-group": (input, options) =>
|
|
82
|
+
rowGroup({
|
|
83
|
+
...input,
|
|
84
|
+
...options,
|
|
85
|
+
}),
|
|
86
|
+
sparkline: (input, options) =>
|
|
87
|
+
sparkline({
|
|
88
|
+
...input,
|
|
89
|
+
...options,
|
|
90
|
+
}),
|
|
76
91
|
span: (input, options) =>
|
|
77
92
|
span(input.value, input.tone, {
|
|
78
93
|
...input,
|
|
@@ -102,10 +117,16 @@ const renderers = {
|
|
|
102
117
|
};
|
|
103
118
|
|
|
104
119
|
// Global rendering flags accepted after `render <renderer>`.
|
|
105
|
-
const globalRenderingFlags = new Set([
|
|
120
|
+
const globalRenderingFlags = new Set([
|
|
121
|
+
"--dark",
|
|
122
|
+
"--light",
|
|
123
|
+
"--no-color",
|
|
124
|
+
"--no-colour",
|
|
125
|
+
"--no-unicode",
|
|
126
|
+
"--plain",
|
|
127
|
+
]);
|
|
106
128
|
|
|
107
129
|
// Renderer names exposed for help text and tests.
|
|
108
|
-
export const rendererNames = Object.keys(renderers);
|
|
109
130
|
|
|
110
131
|
/**
|
|
111
132
|
* Parse render command arguments.
|
package/src/formatters/ansi.js
CHANGED
|
@@ -100,7 +100,7 @@ export function stripAnsi(value) {
|
|
|
100
100
|
* Coloured text, or the original text when colour is disabled.
|
|
101
101
|
*/
|
|
102
102
|
function wrapColour(value, colour, options, createCode) {
|
|
103
|
-
const resolvedColour = resolveColourValue(colour);
|
|
103
|
+
const resolvedColour = resolveColourValue(colour, options);
|
|
104
104
|
|
|
105
105
|
if (options.colour !== true || resolvedColour === null) {
|
|
106
106
|
return value;
|
|
@@ -118,6 +118,14 @@ function wrapColour(value, colour, options, createCode) {
|
|
|
118
118
|
* ANSI foreground sequence.
|
|
119
119
|
*/
|
|
120
120
|
function createForegroundCode(colour) {
|
|
121
|
+
if (colour === "default-foreground") {
|
|
122
|
+
return "\u001b[39m";
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (colour.startsWith("ansi-256:")) {
|
|
126
|
+
return `\u001b[38;5;${colour.slice("ansi-256:".length)}m`;
|
|
127
|
+
}
|
|
128
|
+
|
|
121
129
|
const { blue, green, red } = parseHexColour(colour);
|
|
122
130
|
|
|
123
131
|
return `\u001b[38;2;${red};${green};${blue}m`;
|
|
@@ -132,6 +140,14 @@ function createForegroundCode(colour) {
|
|
|
132
140
|
* ANSI background sequence.
|
|
133
141
|
*/
|
|
134
142
|
function createBackgroundCode(colour) {
|
|
143
|
+
if (colour === "default-background") {
|
|
144
|
+
return "\u001b[49m";
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (colour.startsWith("ansi-256:")) {
|
|
148
|
+
return `\u001b[48;5;${colour.slice("ansi-256:".length)}m`;
|
|
149
|
+
}
|
|
150
|
+
|
|
135
151
|
const { blue, green, red } = parseHexColour(colour);
|
|
136
152
|
|
|
137
153
|
return `\u001b[48;2;${red};${green};${blue}m`;
|
|
@@ -4,6 +4,7 @@ import { commandResult } from "../patterns/command-result.js";
|
|
|
4
4
|
import { compactDataTable } from "../patterns/compact-data-table.js";
|
|
5
5
|
import { confirmationResult } from "../patterns/confirmation-result.js";
|
|
6
6
|
import { diagnosticReport } from "../patterns/diagnostic-report.js";
|
|
7
|
+
import { diffBlock } from "../patterns/diff-block.js";
|
|
7
8
|
import { nextStepBlock } from "../patterns/next-step-block.js";
|
|
8
9
|
import { taskSummary } from "../patterns/task-summary.js";
|
|
9
10
|
import { stripAnsi } from "../formatters/ansi.js";
|
|
@@ -14,6 +15,8 @@ import { emptyState, errorBlock, hint } from "../primitives/feedback.js";
|
|
|
14
15
|
import { panel } from "../primitives/panel.js";
|
|
15
16
|
import { progressBar } from "../primitives/progress-bar.js";
|
|
16
17
|
import { row } from "../primitives/row.js";
|
|
18
|
+
import { rowGroup } from "../primitives/row-group.js";
|
|
19
|
+
import { sparkline } from "../primitives/sparkline.js";
|
|
17
20
|
import { span } from "../primitives/span.js";
|
|
18
21
|
import { status } from "../primitives/status.js";
|
|
19
22
|
import { step, stepProgress, stepStates } from "../primitives/step-progress.js";
|
|
@@ -114,7 +117,7 @@ export const galleryVariants = ["current", "no-colour", "no-unicode", "plain"];
|
|
|
114
117
|
// Gallery sections available for focused output.
|
|
115
118
|
export const gallerySections = ["primitives", "patterns"];
|
|
116
119
|
|
|
117
|
-
//
|
|
120
|
+
// Fixtures available for focused output and interactive search.
|
|
118
121
|
export const galleryFixtures = [
|
|
119
122
|
"diagnostic-report",
|
|
120
123
|
"reporter",
|
|
@@ -126,6 +129,8 @@ export const galleryFixtures = [
|
|
|
126
129
|
"compact-data-table-narrow",
|
|
127
130
|
"confirmation-result",
|
|
128
131
|
"next-step-block",
|
|
132
|
+
"diff-block",
|
|
133
|
+
"sparkline",
|
|
129
134
|
];
|
|
130
135
|
|
|
131
136
|
/**
|
|
@@ -178,7 +183,11 @@ function renderVariant(variant, options, request) {
|
|
|
178
183
|
const sections = [];
|
|
179
184
|
|
|
180
185
|
if (request.fixture !== undefined) {
|
|
181
|
-
sections.push(
|
|
186
|
+
sections.push(
|
|
187
|
+
request.fixture === "sparkline"
|
|
188
|
+
? renderSparklineFixture(resolvedVariant.options)
|
|
189
|
+
: renderPatterns(resolvedVariant.options, request.fixture),
|
|
190
|
+
);
|
|
182
191
|
} else {
|
|
183
192
|
if (request.section === undefined || request.section === "primitives") {
|
|
184
193
|
sections.push(renderPrimitives(resolvedVariant.options));
|
|
@@ -433,6 +442,36 @@ function renderPatterns(options, fixture) {
|
|
|
433
442
|
options,
|
|
434
443
|
);
|
|
435
444
|
|
|
445
|
+
const diff = diffBlock(
|
|
446
|
+
{
|
|
447
|
+
lines: [
|
|
448
|
+
{
|
|
449
|
+
text: "render()",
|
|
450
|
+
type: "header",
|
|
451
|
+
},
|
|
452
|
+
{
|
|
453
|
+
newLineNumber: 102,
|
|
454
|
+
text: "return nextStep;",
|
|
455
|
+
type: "added",
|
|
456
|
+
},
|
|
457
|
+
{
|
|
458
|
+
oldLineNumber: 101,
|
|
459
|
+
text: "return currentStep;",
|
|
460
|
+
type: "removed",
|
|
461
|
+
},
|
|
462
|
+
{
|
|
463
|
+
newLineNumber: 100,
|
|
464
|
+
oldLineNumber: 100,
|
|
465
|
+
text: "const currentStep = getStep();",
|
|
466
|
+
type: "context",
|
|
467
|
+
},
|
|
468
|
+
],
|
|
469
|
+
path: "src/render.js",
|
|
470
|
+
title: "Renderer change",
|
|
471
|
+
},
|
|
472
|
+
options,
|
|
473
|
+
);
|
|
474
|
+
|
|
436
475
|
const reporter = createReporter(options);
|
|
437
476
|
|
|
438
477
|
reporter.divider("Project setup", "Claude + Codex");
|
|
@@ -560,6 +599,7 @@ function renderPatterns(options, fixture) {
|
|
|
560
599
|
"compact-data-table-narrow": ["Compact data table (narrow)", narrowCompactTable],
|
|
561
600
|
"confirmation-result": ["Confirmation result", confirmation],
|
|
562
601
|
"diagnostic-report": ["Diagnostic report", report],
|
|
602
|
+
"diff-block": ["Diff block", diff],
|
|
563
603
|
"next-step-block": ["Next-step block", nextStep],
|
|
564
604
|
reporter: ["Reporter", reporterOutput],
|
|
565
605
|
"task-summary": ["Task summary", summary],
|
|
@@ -593,6 +633,9 @@ function renderPatterns(options, fixture) {
|
|
|
593
633
|
"Audit finding",
|
|
594
634
|
frameExample(audit, options),
|
|
595
635
|
"",
|
|
636
|
+
"Diff block",
|
|
637
|
+
frameExample(diff, options),
|
|
638
|
+
"",
|
|
596
639
|
"Compact data table",
|
|
597
640
|
frameExample(compactTable, options),
|
|
598
641
|
"",
|
|
@@ -621,6 +664,18 @@ function renderPatternFixture(fixture, options) {
|
|
|
621
664
|
return [fixture[0], frameExample(fixture[1], options)].join("\n");
|
|
622
665
|
}
|
|
623
666
|
|
|
667
|
+
/**
|
|
668
|
+
* Render the focused sparkline fixture.
|
|
669
|
+
*
|
|
670
|
+
* @param {object} options
|
|
671
|
+
* Rendering options.
|
|
672
|
+
* @returns {string}
|
|
673
|
+
* Framed sparkline fixture output.
|
|
674
|
+
*/
|
|
675
|
+
function renderSparklineFixture(options) {
|
|
676
|
+
return ["Sparkline", frameExample(renderSparklineExample(options), options)].join("\n");
|
|
677
|
+
}
|
|
678
|
+
|
|
624
679
|
/**
|
|
625
680
|
* Add gallery-only framing around one rendered example.
|
|
626
681
|
*
|
|
@@ -667,6 +722,9 @@ function renderPrimitives(options) {
|
|
|
667
722
|
"Bar charts",
|
|
668
723
|
renderBarChartExample(options),
|
|
669
724
|
"",
|
|
725
|
+
"Sparklines",
|
|
726
|
+
renderSparklineExample(options),
|
|
727
|
+
"",
|
|
670
728
|
"Tables",
|
|
671
729
|
renderTableExample(options),
|
|
672
730
|
"",
|
|
@@ -715,6 +773,30 @@ function renderPrimitives(options) {
|
|
|
715
773
|
labelWidth: 8,
|
|
716
774
|
result: resultTypes.FAILED,
|
|
717
775
|
}),
|
|
776
|
+
"",
|
|
777
|
+
"Row groups",
|
|
778
|
+
rowGroup({
|
|
779
|
+
...options,
|
|
780
|
+
rows: [
|
|
781
|
+
{
|
|
782
|
+
label: "Package",
|
|
783
|
+
value: "@lewishowles/components",
|
|
784
|
+
},
|
|
785
|
+
{
|
|
786
|
+
label: "Version",
|
|
787
|
+
value: "minor: 2.7.4 -> 2.8.0",
|
|
788
|
+
},
|
|
789
|
+
{
|
|
790
|
+
label: "Checks",
|
|
791
|
+
value: "type-check, unit, build",
|
|
792
|
+
},
|
|
793
|
+
{
|
|
794
|
+
label: "Bundle",
|
|
795
|
+
result: resultTypes.FAILED,
|
|
796
|
+
value: "is 22.3 KB, above the 12.0 KB budget",
|
|
797
|
+
},
|
|
798
|
+
],
|
|
799
|
+
}),
|
|
718
800
|
].join("\n");
|
|
719
801
|
}
|
|
720
802
|
|
|
@@ -781,6 +863,55 @@ function renderBarChartExample(options) {
|
|
|
781
863
|
});
|
|
782
864
|
}
|
|
783
865
|
|
|
866
|
+
/**
|
|
867
|
+
* Render representative sparkline sequences.
|
|
868
|
+
*
|
|
869
|
+
* @param {object} options
|
|
870
|
+
* Rendering options.
|
|
871
|
+
* @returns {string}
|
|
872
|
+
* Sparkline examples.
|
|
873
|
+
*/
|
|
874
|
+
function renderSparklineExample(options) {
|
|
875
|
+
const examples = [
|
|
876
|
+
{
|
|
877
|
+
label: "Rising",
|
|
878
|
+
tone: "success",
|
|
879
|
+
values: [1, 2, 3, 4, 5, 6],
|
|
880
|
+
},
|
|
881
|
+
{
|
|
882
|
+
label: "Falling",
|
|
883
|
+
tone: "danger",
|
|
884
|
+
values: [6, 5, 4, 3, 2, 1],
|
|
885
|
+
},
|
|
886
|
+
{
|
|
887
|
+
label: "Flat",
|
|
888
|
+
tone: "info",
|
|
889
|
+
values: [4, 4, 4, 4, 4, 4],
|
|
890
|
+
},
|
|
891
|
+
{
|
|
892
|
+
label: "Negative",
|
|
893
|
+
tone: "warning",
|
|
894
|
+
values: [-6, -4, -5, -2, -3, -1],
|
|
895
|
+
},
|
|
896
|
+
{
|
|
897
|
+
label: "Narrow mixed",
|
|
898
|
+
tone: "info",
|
|
899
|
+
values: [0, 10, -5, 5, 2, 8, -2],
|
|
900
|
+
width: 4,
|
|
901
|
+
},
|
|
902
|
+
];
|
|
903
|
+
|
|
904
|
+
return examples
|
|
905
|
+
.map((example) =>
|
|
906
|
+
sparkline({
|
|
907
|
+
...options,
|
|
908
|
+
...example,
|
|
909
|
+
width: example.width ?? 16,
|
|
910
|
+
}),
|
|
911
|
+
)
|
|
912
|
+
.join("\n");
|
|
913
|
+
}
|
|
914
|
+
|
|
784
915
|
/**
|
|
785
916
|
* Render common progress values and tones.
|
|
786
917
|
*
|