toolcraft-openapi 0.0.10 → 0.0.12

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.
@@ -0,0 +1,4 @@
1
+ import type { CommandInfo, FormatColumnsOptions, OptionInfo } from "./help-formatter.js";
2
+ export declare function formatColumns(opts: FormatColumnsOptions): string;
3
+ export declare function formatCommandList(commands: CommandInfo[]): string;
4
+ export declare function formatOptionList(options: OptionInfo[]): string;
@@ -0,0 +1,132 @@
1
+ function stripAnsi(value) {
2
+ let output = "";
3
+ for (let index = 0; index < value.length; index += 1) {
4
+ if (value[index] === "\u001b") {
5
+ if (value[index + 1] === "[") {
6
+ index += 2;
7
+ while (index < value.length) {
8
+ const code = value.charCodeAt(index);
9
+ if (code >= 0x40 && code <= 0x7e) {
10
+ break;
11
+ }
12
+ index += 1;
13
+ }
14
+ }
15
+ continue;
16
+ }
17
+ output += value[index];
18
+ }
19
+ return output;
20
+ }
21
+ function toAscii(value) {
22
+ let output = "";
23
+ const stripped = stripAnsi(value);
24
+ for (let index = 0; index < stripped.length; index += 1) {
25
+ const code = stripped.charCodeAt(index);
26
+ output += code <= 0x7f ? stripped[index] : "?";
27
+ }
28
+ return output;
29
+ }
30
+ function clamp(value, min, max) {
31
+ return Math.min(Math.max(value, min), max);
32
+ }
33
+ function padEndVisible(value, width) {
34
+ return value + " ".repeat(Math.max(0, width - value.length));
35
+ }
36
+ function isWhitespace(char) {
37
+ return char === " " || char === "\n" || char === "\t" || char === "\r";
38
+ }
39
+ function splitWords(value) {
40
+ const words = [];
41
+ let word = "";
42
+ for (const char of value) {
43
+ if (isWhitespace(char)) {
44
+ if (word) {
45
+ words.push(word);
46
+ word = "";
47
+ }
48
+ continue;
49
+ }
50
+ word += char;
51
+ }
52
+ if (word) {
53
+ words.push(word);
54
+ }
55
+ return words;
56
+ }
57
+ function wrapWords(value, width) {
58
+ const words = splitWords(value);
59
+ if (words.length === 0) {
60
+ return [""];
61
+ }
62
+ const lines = [];
63
+ let line = "";
64
+ for (const word of words) {
65
+ if (!line) {
66
+ line = word;
67
+ continue;
68
+ }
69
+ if (line.length + 1 + word.length <= width) {
70
+ line += ` ${word}`;
71
+ continue;
72
+ }
73
+ lines.push(line);
74
+ line = word;
75
+ }
76
+ lines.push(line);
77
+ return lines;
78
+ }
79
+ export function formatColumns(opts) {
80
+ const rows = opts.rows.map((row) => ({
81
+ left: toAscii(row.left),
82
+ right: toAscii(row.right)
83
+ }));
84
+ if (rows.length === 0) {
85
+ return "";
86
+ }
87
+ const totalWidth = opts.totalWidth ?? process.stdout.columns ?? 100;
88
+ const minLeftWidth = opts.minLeftWidth ?? 12;
89
+ const maxLeftWidth = opts.maxLeftWidth ?? 32;
90
+ const gap = opts.gap ?? 3;
91
+ const indent = opts.indent ?? 2;
92
+ const maxLeftContentWidth = Math.max(...rows.map((row) => row.left.length));
93
+ const leftWidth = clamp(maxLeftContentWidth + gap, minLeftWidth, maxLeftWidth);
94
+ const rightWidth = Math.max(20, totalWidth - leftWidth - indent);
95
+ const firstIndent = " ".repeat(indent);
96
+ const continuationIndent = " ".repeat(indent + leftWidth);
97
+ return rows
98
+ .flatMap((row) => {
99
+ if (row.right.length === 0) {
100
+ return [`${firstIndent}${row.left}`];
101
+ }
102
+ const rightLines = wrapWords(row.right, rightWidth);
103
+ if (row.left.length > leftWidth) {
104
+ return [
105
+ `${firstIndent}${row.left}`,
106
+ ...rightLines.map((line) => `${continuationIndent}${line}`)
107
+ ];
108
+ }
109
+ const firstLine = `${firstIndent}${padEndVisible(row.left, leftWidth)}${rightLines[0]}`;
110
+ const continuationLines = rightLines
111
+ .slice(1)
112
+ .map((line) => `${continuationIndent}${line}`);
113
+ return [firstLine, ...continuationLines];
114
+ })
115
+ .join("\n");
116
+ }
117
+ export function formatCommandList(commands) {
118
+ return formatColumns({
119
+ rows: commands.map((cmd) => ({
120
+ left: cmd.name,
121
+ right: cmd.description
122
+ }))
123
+ });
124
+ }
125
+ export function formatOptionList(options) {
126
+ return formatColumns({
127
+ rows: options.map((opt) => ({
128
+ left: opt.flags,
129
+ right: opt.description
130
+ }))
131
+ });
132
+ }
@@ -6,12 +6,25 @@ export interface OptionInfo {
6
6
  flags: string;
7
7
  description: string;
8
8
  }
9
+ export interface FormatColumnsOptions {
10
+ rows: Array<{
11
+ left: string;
12
+ right: string;
13
+ }>;
14
+ totalWidth?: number;
15
+ minLeftWidth?: number;
16
+ maxLeftWidth?: number;
17
+ gap?: number;
18
+ indent?: number;
19
+ }
20
+ export declare function formatColumns(opts: FormatColumnsOptions): string;
9
21
  export declare function formatCommand(name: string, description: string): string;
10
22
  export declare function formatUsage(command: string, args?: string): string;
11
23
  export declare function formatOption(flags: string, description: string): string;
12
24
  export declare function formatCommandList(commands: CommandInfo[]): string;
13
25
  export declare function formatOptionList(options: OptionInfo[]): string;
14
26
  export declare const helpFormatter: {
27
+ readonly formatColumns: typeof formatColumns;
15
28
  readonly formatCommand: typeof formatCommand;
16
29
  readonly formatUsage: typeof formatUsage;
17
30
  readonly formatOption: typeof formatOption;
@@ -1,24 +1,133 @@
1
1
  import { text } from "./text.js";
2
- import { widths } from "../tokens/widths.js";
2
+ function stripAnsi(value) {
3
+ let output = "";
4
+ for (let index = 0; index < value.length; index += 1)
5
+ if (value[index] === "\u001b" && value[index + 1] === "[")
6
+ while (index < value.length && value[index] !== "m")
7
+ index += 1;
8
+ else
9
+ output += value[index];
10
+ return output;
11
+ }
12
+ function visibleWidth(value) {
13
+ return stripAnsi(value).length;
14
+ }
15
+ function clamp(value, min, max) {
16
+ return Math.min(Math.max(value, min), max);
17
+ }
18
+ function padEndVisible(value, width) {
19
+ return value + " ".repeat(Math.max(0, width - visibleWidth(value)));
20
+ }
21
+ function isWhitespace(char) {
22
+ return char === " " || char === "\n" || char === "\t" || char === "\r";
23
+ }
24
+ function splitWords(value) {
25
+ const words = [];
26
+ let word = "";
27
+ for (const char of value) {
28
+ if (isWhitespace(char)) {
29
+ if (word) {
30
+ words.push(word);
31
+ word = "";
32
+ }
33
+ continue;
34
+ }
35
+ word += char;
36
+ }
37
+ if (word) {
38
+ words.push(word);
39
+ }
40
+ return words;
41
+ }
42
+ function wrapWords(value, width) {
43
+ const words = splitWords(value);
44
+ if (words.length === 0) {
45
+ return [""];
46
+ }
47
+ const lines = [];
48
+ let line = "";
49
+ for (const word of words) {
50
+ if (!line) {
51
+ line = word;
52
+ continue;
53
+ }
54
+ if (visibleWidth(line) + 1 + visibleWidth(word) <= width) {
55
+ line += ` ${word}`;
56
+ continue;
57
+ }
58
+ lines.push(line);
59
+ line = word;
60
+ }
61
+ lines.push(line);
62
+ return lines;
63
+ }
64
+ export function formatColumns(opts) {
65
+ const { rows } = opts;
66
+ if (rows.length === 0) {
67
+ return "";
68
+ }
69
+ const totalWidth = opts.totalWidth ?? process.stdout.columns ?? 100;
70
+ const minLeftWidth = opts.minLeftWidth ?? 12;
71
+ const maxLeftWidth = opts.maxLeftWidth ?? 32;
72
+ const gap = opts.gap ?? 3;
73
+ const indent = opts.indent ?? 2;
74
+ const maxLeftContentWidth = Math.max(...rows.map((row) => visibleWidth(row.left)));
75
+ const leftWidth = clamp(maxLeftContentWidth + gap, minLeftWidth, maxLeftWidth);
76
+ const rightWidth = Math.max(20, totalWidth - leftWidth - indent);
77
+ const firstIndent = " ".repeat(indent);
78
+ const continuationIndent = " ".repeat(indent + leftWidth);
79
+ return rows
80
+ .flatMap((row) => {
81
+ if (row.right.length === 0) {
82
+ return [`${firstIndent}${row.left}`];
83
+ }
84
+ const rightLines = wrapWords(row.right, rightWidth);
85
+ if (visibleWidth(row.left) > leftWidth) {
86
+ return [
87
+ `${firstIndent}${row.left}`,
88
+ ...rightLines.map((line) => `${continuationIndent}${line}`)
89
+ ];
90
+ }
91
+ const firstLine = `${firstIndent}${padEndVisible(row.left, leftWidth)}${rightLines[0]}`;
92
+ const continuationLines = rightLines
93
+ .slice(1)
94
+ .map((line) => `${continuationIndent}${line}`);
95
+ return [firstLine, ...continuationLines];
96
+ })
97
+ .join("\n");
98
+ }
3
99
  export function formatCommand(name, description) {
4
- const paddedName = name.padEnd(widths.helpColumn);
5
- return ` ${text.command(paddedName)} ${description}`;
100
+ return formatColumns({
101
+ rows: [{ left: text.command(name), right: description }]
102
+ });
6
103
  }
7
104
  export function formatUsage(command, args) {
8
105
  const argsStr = args ? ` ${text.argument(args)}` : "";
9
106
  return `${text.usageCommand(command)}${argsStr}`;
10
107
  }
11
108
  export function formatOption(flags, description) {
12
- const paddedFlags = flags.padEnd(widths.helpColumn);
13
- return ` ${text.option(paddedFlags)} ${description}`;
109
+ return formatColumns({
110
+ rows: [{ left: text.option(flags), right: description }]
111
+ });
14
112
  }
15
113
  export function formatCommandList(commands) {
16
- return commands.map((cmd) => formatCommand(cmd.name, cmd.description)).join("\n");
114
+ return formatColumns({
115
+ rows: commands.map((cmd) => ({
116
+ left: text.command(cmd.name),
117
+ right: cmd.description
118
+ }))
119
+ });
17
120
  }
18
121
  export function formatOptionList(options) {
19
- return options.map((opt) => formatOption(opt.flags, opt.description)).join("\n");
122
+ return formatColumns({
123
+ rows: options.map((opt) => ({
124
+ left: text.option(opt.flags),
125
+ right: opt.description
126
+ }))
127
+ });
20
128
  }
21
129
  export const helpFormatter = {
130
+ formatColumns,
22
131
  formatCommand,
23
132
  formatUsage,
24
133
  formatOption,
@@ -2,8 +2,8 @@ export { text } from "./text.js";
2
2
  export { symbols } from "./symbols.js";
3
3
  export { createLogger, logger } from "./logger.js";
4
4
  export type { LoggerOutput } from "./logger.js";
5
- export { helpFormatter, formatCommand, formatUsage, formatOption, formatCommandList, formatOptionList } from "./help-formatter.js";
6
- export type { CommandInfo, OptionInfo } from "./help-formatter.js";
5
+ export { helpFormatter, formatColumns, formatCommand, formatUsage, formatOption, formatCommandList, formatOptionList } from "./help-formatter.js";
6
+ export type { CommandInfo, OptionInfo, FormatColumnsOptions } from "./help-formatter.js";
7
7
  export { formatCommandNotFound } from "./command-errors.js";
8
8
  export { formatCommandNotFoundPanel } from "./command-errors.js";
9
9
  export { renderTable } from "./table.js";
@@ -1,7 +1,7 @@
1
1
  export { text } from "./text.js";
2
2
  export { symbols } from "./symbols.js";
3
3
  export { createLogger, logger } from "./logger.js";
4
- export { helpFormatter, formatCommand, formatUsage, formatOption, formatCommandList, formatOptionList } from "./help-formatter.js";
4
+ export { helpFormatter, formatColumns, formatCommand, formatUsage, formatOption, formatCommandList, formatOptionList } from "./help-formatter.js";
5
5
  export { formatCommandNotFound } from "./command-errors.js";
6
6
  export { formatCommandNotFoundPanel } from "./command-errors.js";
7
7
  export { renderTable } from "./table.js";
@@ -2,6 +2,7 @@ export declare const text: {
2
2
  readonly intro: (content: string) => string;
3
3
  readonly heading: (content: string) => string;
4
4
  readonly section: (content: string) => string;
5
+ readonly sectionHeader: (content: string) => string;
5
6
  readonly command: (content: string) => string;
6
7
  readonly argument: (content: string) => string;
7
8
  readonly option: (content: string) => string;
@@ -27,6 +27,14 @@ export const text = {
27
27
  return `**${content}**`;
28
28
  return typography.bold(content);
29
29
  },
30
+ sectionHeader(content) {
31
+ const format = resolveOutputFormat();
32
+ if (format === "json")
33
+ return content;
34
+ if (format === "markdown")
35
+ return `## ${content}`;
36
+ return typography.bold(content.toUpperCase());
37
+ },
30
38
  command(content) {
31
39
  const format = resolveOutputFormat();
32
40
  if (format === "json")
@@ -8,8 +8,9 @@ export { text } from "./components/text.js";
8
8
  export { symbols } from "./components/symbols.js";
9
9
  export { createLogger, logger } from "./components/logger.js";
10
10
  export type { LoggerOutput } from "./components/logger.js";
11
- export { helpFormatter, formatCommand, formatUsage, formatOption, formatCommandList, formatOptionList } from "./components/help-formatter.js";
12
- export type { CommandInfo, OptionInfo } from "./components/help-formatter.js";
11
+ export { helpFormatter, formatColumns, formatCommand, formatUsage, formatOption, formatCommandList, formatOptionList } from "./components/help-formatter.js";
12
+ export * as helpFormatterPlain from "./components/help-formatter-plain.js";
13
+ export type { CommandInfo, OptionInfo, FormatColumnsOptions } from "./components/help-formatter.js";
13
14
  export { formatCommandNotFound } from "./components/command-errors.js";
14
15
  export { formatCommandNotFoundPanel } from "./components/command-errors.js";
15
16
  export { renderTable } from "./components/table.js";
@@ -8,7 +8,8 @@ export { widths } from "./tokens/widths.js";
8
8
  export { text } from "./components/text.js";
9
9
  export { symbols } from "./components/symbols.js";
10
10
  export { createLogger, logger } from "./components/logger.js";
11
- export { helpFormatter, formatCommand, formatUsage, formatOption, formatCommandList, formatOptionList } from "./components/help-formatter.js";
11
+ export { helpFormatter, formatColumns, formatCommand, formatUsage, formatOption, formatCommandList, formatOptionList } from "./components/help-formatter.js";
12
+ export * as helpFormatterPlain from "./components/help-formatter-plain.js";
12
13
  export { formatCommandNotFound } from "./components/command-errors.js";
13
14
  export { formatCommandNotFoundPanel } from "./components/command-errors.js";
14
15
  export { renderTable } from "./components/table.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toolcraft-openapi",
3
- "version": "0.0.10",
3
+ "version": "0.0.12",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -30,7 +30,7 @@
30
30
  "auth-store": "^0.0.1",
31
31
  "chalk": "^5.6.2",
32
32
  "console-table-printer": "^2.15.0",
33
- "toolcraft": "^0.0.10",
33
+ "toolcraft": "^0.0.12",
34
34
  "yaml": "^2.8.2"
35
35
  },
36
36
  "engines": {