toolcraft-openapi 0.0.64 → 0.0.66
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/generate.js +148 -5
- package/dist/generate.d.ts +8 -0
- package/dist/generate.js +238 -19
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/node_modules/toolcraft-design/dist/components/inspector-card.d.ts +21 -0
- package/node_modules/toolcraft-design/dist/components/inspector-card.js +42 -0
- package/node_modules/toolcraft-design/dist/components/resource-browser.d.ts +21 -0
- package/node_modules/toolcraft-design/dist/components/resource-browser.js +98 -0
- package/node_modules/toolcraft-design/dist/explorer/index.d.ts +2 -0
- package/node_modules/toolcraft-design/dist/explorer/index.js +1 -0
- package/node_modules/toolcraft-design/dist/explorer/two-pane.d.ts +94 -0
- package/node_modules/toolcraft-design/dist/explorer/two-pane.js +446 -0
- package/node_modules/toolcraft-design/dist/index.d.ts +6 -2
- package/node_modules/toolcraft-design/dist/index.js +3 -1
- package/package.json +2 -2
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ThemePalette } from "../tokens/colors.js";
|
|
2
|
+
export interface InspectorField {
|
|
3
|
+
label: string;
|
|
4
|
+
value: string;
|
|
5
|
+
}
|
|
6
|
+
export interface InspectorSection {
|
|
7
|
+
title?: string;
|
|
8
|
+
fields: InspectorField[];
|
|
9
|
+
}
|
|
10
|
+
export interface RenderInspectorCardOptions {
|
|
11
|
+
theme: ThemePalette;
|
|
12
|
+
title: string;
|
|
13
|
+
subtitle?: string;
|
|
14
|
+
badges?: string[];
|
|
15
|
+
preview?: string;
|
|
16
|
+
previewTitle?: string;
|
|
17
|
+
sections?: InspectorSection[];
|
|
18
|
+
width?: number;
|
|
19
|
+
maxPreviewLines?: number;
|
|
20
|
+
}
|
|
21
|
+
export declare function renderInspectorCard(options: RenderInspectorCardOptions): string;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { renderDetailCard } from "./detail-card.js";
|
|
2
|
+
export function renderInspectorCard(options) {
|
|
3
|
+
const preview = truncatePreview(options.preview, options.maxPreviewLines ?? 8);
|
|
4
|
+
const sections = (options.sections ?? [])
|
|
5
|
+
.filter((section) => section.fields.length > 0)
|
|
6
|
+
.map((section) => ({
|
|
7
|
+
title: section.title,
|
|
8
|
+
rows: section.fields.map((field) => ({ label: field.label, value: field.value }))
|
|
9
|
+
}));
|
|
10
|
+
return renderDetailCard({
|
|
11
|
+
theme: options.theme,
|
|
12
|
+
title: options.title,
|
|
13
|
+
subtitle: options.subtitle,
|
|
14
|
+
badges: options.badges,
|
|
15
|
+
prose: preview === undefined
|
|
16
|
+
? undefined
|
|
17
|
+
: [{
|
|
18
|
+
title: options.previewTitle ?? "Preview",
|
|
19
|
+
value: preview
|
|
20
|
+
}],
|
|
21
|
+
sections,
|
|
22
|
+
width: options.width
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
function truncatePreview(value, maxLines) {
|
|
26
|
+
if (value === undefined) {
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
const lines = splitLines(value).map((line) => line.trimEnd());
|
|
30
|
+
const firstContent = lines.findIndex((line) => line.trim().length > 0);
|
|
31
|
+
const contentLines = firstContent === -1 ? [] : lines.slice(firstContent);
|
|
32
|
+
if (contentLines.length === 0) {
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
if (contentLines.length <= maxLines) {
|
|
36
|
+
return contentLines.join("\n");
|
|
37
|
+
}
|
|
38
|
+
return [...contentLines.slice(0, maxLines), `... ${contentLines.length - maxLines} more line(s)`].join("\n");
|
|
39
|
+
}
|
|
40
|
+
function splitLines(content) {
|
|
41
|
+
return content.split("\n").map((line) => line.endsWith("\r") ? line.slice(0, -1) : line);
|
|
42
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ThemePalette } from "../tokens/colors.js";
|
|
2
|
+
export interface ResourceBrowserItem {
|
|
3
|
+
label: string;
|
|
4
|
+
meta?: string[];
|
|
5
|
+
preview?: string;
|
|
6
|
+
badge?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface ResourceBrowserGroup {
|
|
9
|
+
title: string;
|
|
10
|
+
description?: string;
|
|
11
|
+
emptyHint?: string;
|
|
12
|
+
items: ResourceBrowserItem[];
|
|
13
|
+
}
|
|
14
|
+
export interface RenderResourceBrowserOptions {
|
|
15
|
+
theme: ThemePalette;
|
|
16
|
+
title: string;
|
|
17
|
+
subtitle?: string;
|
|
18
|
+
groups: ResourceBrowserGroup[];
|
|
19
|
+
footer?: string;
|
|
20
|
+
}
|
|
21
|
+
export declare function renderResourceBrowser(options: RenderResourceBrowserOptions): string;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { resolveOutputFormat } from "../internal/output-format.js";
|
|
2
|
+
import { stripAnsi } from "../internal/strip-ansi.js";
|
|
3
|
+
export function renderResourceBrowser(options) {
|
|
4
|
+
switch (resolveOutputFormat()) {
|
|
5
|
+
case "markdown":
|
|
6
|
+
return renderMarkdown(options);
|
|
7
|
+
case "json":
|
|
8
|
+
return renderJson(options);
|
|
9
|
+
default:
|
|
10
|
+
return renderTerminal(options);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
function renderTerminal(options) {
|
|
14
|
+
const blocks = [renderTitle(options)];
|
|
15
|
+
for (const group of options.groups) {
|
|
16
|
+
blocks.push(renderTerminalGroup(options.theme, group));
|
|
17
|
+
}
|
|
18
|
+
if (options.footer !== undefined) {
|
|
19
|
+
blocks.push(options.theme.muted(options.footer));
|
|
20
|
+
}
|
|
21
|
+
return blocks.join("\n\n");
|
|
22
|
+
}
|
|
23
|
+
function renderTitle(options) {
|
|
24
|
+
return [
|
|
25
|
+
options.theme.header(options.title),
|
|
26
|
+
options.subtitle === undefined ? undefined : options.theme.muted(options.subtitle)
|
|
27
|
+
].filter((value) => value !== undefined).join(" ");
|
|
28
|
+
}
|
|
29
|
+
function renderTerminalGroup(theme, group) {
|
|
30
|
+
const lines = [
|
|
31
|
+
`${theme.header(group.title)} ${theme.muted(String(group.items.length))}`,
|
|
32
|
+
...(group.description === undefined ? [] : [theme.muted(group.description)])
|
|
33
|
+
];
|
|
34
|
+
if (group.items.length === 0) {
|
|
35
|
+
lines.push(theme.muted(group.emptyHint ?? "No items"));
|
|
36
|
+
return lines.join("\n");
|
|
37
|
+
}
|
|
38
|
+
for (const [index, item] of group.items.entries()) {
|
|
39
|
+
lines.push(...renderTerminalItem(theme, item));
|
|
40
|
+
if (index < group.items.length - 1) {
|
|
41
|
+
lines.push("");
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return lines.join("\n");
|
|
45
|
+
}
|
|
46
|
+
function renderTerminalItem(theme, item) {
|
|
47
|
+
return [
|
|
48
|
+
`${theme.accent(">")} ${theme.header(item.label)}${item.badge === undefined ? "" : ` ${theme.info(item.badge)}`}`,
|
|
49
|
+
...(item.meta === undefined || item.meta.length === 0 ? [] : [` ${theme.muted(item.meta.join(" · "))}`]),
|
|
50
|
+
...(item.preview === undefined || item.preview.length === 0 ? [] : [` ${theme.muted(item.preview)}`])
|
|
51
|
+
];
|
|
52
|
+
}
|
|
53
|
+
function renderMarkdown(options) {
|
|
54
|
+
const blocks = [`# ${stripAnsi(options.title)}`];
|
|
55
|
+
if (options.subtitle !== undefined) {
|
|
56
|
+
blocks.push(stripAnsi(options.subtitle));
|
|
57
|
+
}
|
|
58
|
+
for (const group of options.groups) {
|
|
59
|
+
const lines = [`## ${stripAnsi(group.title)} (${group.items.length})`];
|
|
60
|
+
if (group.description !== undefined) {
|
|
61
|
+
lines.push(stripAnsi(group.description));
|
|
62
|
+
}
|
|
63
|
+
if (group.items.length === 0) {
|
|
64
|
+
lines.push(stripAnsi(group.emptyHint ?? "No items"));
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
lines.push(...group.items.map((item) => renderMarkdownItem(item)));
|
|
68
|
+
}
|
|
69
|
+
blocks.push(lines.join("\n\n"));
|
|
70
|
+
}
|
|
71
|
+
if (options.footer !== undefined) {
|
|
72
|
+
blocks.push(stripAnsi(options.footer));
|
|
73
|
+
}
|
|
74
|
+
return blocks.join("\n\n");
|
|
75
|
+
}
|
|
76
|
+
function renderMarkdownItem(item) {
|
|
77
|
+
const meta = item.meta === undefined || item.meta.length === 0 ? "" : ` — ${item.meta.map(stripAnsi).join(" · ")}`;
|
|
78
|
+
const preview = item.preview === undefined || item.preview.length === 0 ? "" : `: ${stripAnsi(item.preview)}`;
|
|
79
|
+
return `- **${stripAnsi(item.label)}**${meta}${preview}`;
|
|
80
|
+
}
|
|
81
|
+
function renderJson(options) {
|
|
82
|
+
return JSON.stringify({
|
|
83
|
+
title: stripAnsi(options.title),
|
|
84
|
+
...(options.subtitle === undefined ? {} : { subtitle: stripAnsi(options.subtitle) }),
|
|
85
|
+
groups: options.groups.map((group) => ({
|
|
86
|
+
title: stripAnsi(group.title),
|
|
87
|
+
...(group.description === undefined ? {} : { description: stripAnsi(group.description) }),
|
|
88
|
+
...(group.emptyHint === undefined ? {} : { emptyHint: stripAnsi(group.emptyHint) }),
|
|
89
|
+
items: group.items.map((item) => ({
|
|
90
|
+
label: stripAnsi(item.label),
|
|
91
|
+
...(item.meta === undefined ? {} : { meta: item.meta.map(stripAnsi) }),
|
|
92
|
+
...(item.preview === undefined ? {} : { preview: stripAnsi(item.preview) }),
|
|
93
|
+
...(item.badge === undefined ? {} : { badge: stripAnsi(item.badge) })
|
|
94
|
+
}))
|
|
95
|
+
})),
|
|
96
|
+
...(options.footer === undefined ? {} : { footer: stripAnsi(options.footer) })
|
|
97
|
+
}, null, 2);
|
|
98
|
+
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import type { Detail, DetailCtx, Row } from "./state.js";
|
|
2
2
|
export { runExplorer } from "./runtime.js";
|
|
3
|
+
export { runTwoPaneExplorer, renderTwoPaneExplorer, TwoPaneExplorerRuntime } from "./two-pane.js";
|
|
3
4
|
export { createInitialState } from "./state.js";
|
|
4
5
|
export { resolveBindings } from "./keymap.js";
|
|
5
6
|
export type { Effect, ExplorerEvent } from "./events.js";
|
|
6
7
|
export type { BindingTarget, ExplorerBindingDefaults, ExplorerBuiltinCommand, ResolvedBindings } from "./keymap.js";
|
|
7
8
|
export type { Action, ActionContext, Detail, DetailCtx, DetailItem, Dirty, ExplorerConfig, ExplorerLayoutMode, ExplorerSize, ExplorerState, ReorderContext, Row, Tone } from "./state.js";
|
|
9
|
+
export type { TwoPaneAction, TwoPaneActionContext, TwoPaneDefinition, TwoPaneExplorerConfig, TwoPaneExplorerState, TwoPanePaneState, TwoPaneRow } from "./two-pane.js";
|
|
8
10
|
export declare function singleDetail<R>(fn: (row: Row, ctx: DetailCtx) => string | Promise<string>): Detail<R>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { runExplorer } from "./runtime.js";
|
|
2
|
+
export { runTwoPaneExplorer, renderTwoPaneExplorer, TwoPaneExplorerRuntime } from "./two-pane.js";
|
|
2
3
|
export { createInitialState } from "./state.js";
|
|
3
4
|
export { resolveBindings } from "./keymap.js";
|
|
4
5
|
export function singleDetail(fn) {
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { ScreenBuffer } from "../dashboard/buffer.js";
|
|
2
|
+
import { type TerminalDriver } from "../dashboard/terminal.js";
|
|
3
|
+
import type { Tone } from "./state.js";
|
|
4
|
+
export interface TwoPaneRow {
|
|
5
|
+
id: string;
|
|
6
|
+
title: string;
|
|
7
|
+
subtitle?: string;
|
|
8
|
+
badge?: {
|
|
9
|
+
text: string;
|
|
10
|
+
tone?: Tone;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export interface TwoPaneDefinition {
|
|
14
|
+
id: string;
|
|
15
|
+
title: string;
|
|
16
|
+
rows: () => Promise<TwoPaneRow[]>;
|
|
17
|
+
emptyHint?: string;
|
|
18
|
+
}
|
|
19
|
+
export interface TwoPaneActionContext<R> {
|
|
20
|
+
activePane: TwoPanePaneState;
|
|
21
|
+
inactivePane: TwoPanePaneState;
|
|
22
|
+
row: TwoPaneRow;
|
|
23
|
+
rows: TwoPaneRow[];
|
|
24
|
+
refresh: () => Promise<void>;
|
|
25
|
+
suspendAnd: <T>(fn: () => Promise<T>) => Promise<T>;
|
|
26
|
+
toast: (message: string, tone?: Tone) => void;
|
|
27
|
+
exit: (result?: R | null) => void;
|
|
28
|
+
}
|
|
29
|
+
export interface TwoPaneAction<R> {
|
|
30
|
+
id: string;
|
|
31
|
+
label: string;
|
|
32
|
+
key: string | string[];
|
|
33
|
+
handler: (ctx: TwoPaneActionContext<R>) => void | Promise<void>;
|
|
34
|
+
}
|
|
35
|
+
export interface TwoPaneExplorerConfig<R> {
|
|
36
|
+
title: string;
|
|
37
|
+
panes: [TwoPaneDefinition, TwoPaneDefinition];
|
|
38
|
+
actions: TwoPaneAction<R>[];
|
|
39
|
+
refresh?: () => void | Promise<void>;
|
|
40
|
+
}
|
|
41
|
+
export interface TwoPanePaneState {
|
|
42
|
+
id: string;
|
|
43
|
+
title: string;
|
|
44
|
+
rows: TwoPaneRow[];
|
|
45
|
+
cursor: number;
|
|
46
|
+
selected: Set<string>;
|
|
47
|
+
filter: string;
|
|
48
|
+
emptyHint: string;
|
|
49
|
+
}
|
|
50
|
+
export interface TwoPaneExplorerState {
|
|
51
|
+
title: string;
|
|
52
|
+
panes: [TwoPanePaneState, TwoPanePaneState];
|
|
53
|
+
activePaneIndex: 0 | 1;
|
|
54
|
+
filterFocused: boolean;
|
|
55
|
+
toast: {
|
|
56
|
+
message: string;
|
|
57
|
+
tone: Tone;
|
|
58
|
+
} | null;
|
|
59
|
+
size: {
|
|
60
|
+
cols: number;
|
|
61
|
+
rows: number;
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
export declare function runTwoPaneExplorer<R = void>(config: TwoPaneExplorerConfig<R>): Promise<R | null>;
|
|
65
|
+
export declare class TwoPaneExplorerRuntime<R> {
|
|
66
|
+
private readonly config;
|
|
67
|
+
private readonly driver;
|
|
68
|
+
private state;
|
|
69
|
+
private unsubscribeKeypress;
|
|
70
|
+
private unsubscribeResize;
|
|
71
|
+
private toastTimer;
|
|
72
|
+
private stopped;
|
|
73
|
+
private rowsRequestToken;
|
|
74
|
+
private settle;
|
|
75
|
+
constructor(config: TwoPaneExplorerConfig<R>, driver: TerminalDriver);
|
|
76
|
+
run(): Promise<R | null>;
|
|
77
|
+
private startTerminal;
|
|
78
|
+
private loadRows;
|
|
79
|
+
private refresh;
|
|
80
|
+
private dispatchKey;
|
|
81
|
+
private dispatchFilterKey;
|
|
82
|
+
private moveCursor;
|
|
83
|
+
private setCursor;
|
|
84
|
+
private toggleSelection;
|
|
85
|
+
private runAction;
|
|
86
|
+
private suspendAnd;
|
|
87
|
+
private showToast;
|
|
88
|
+
private activePane;
|
|
89
|
+
private inactivePane;
|
|
90
|
+
private render;
|
|
91
|
+
private exit;
|
|
92
|
+
private fail;
|
|
93
|
+
}
|
|
94
|
+
export declare function renderTwoPaneExplorer<R>(state: TwoPaneExplorerState, actions: TwoPaneAction<R>[], screen: ScreenBuffer): void;
|