@jskit-ai/jskit-cli 0.2.39 → 0.2.40

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.
@@ -7,6 +7,7 @@ const ANSI_CYAN = "\u001b[36m";
7
7
  const ANSI_GREEN = "\u001b[32m";
8
8
  const ANSI_YELLOW = "\u001b[33m";
9
9
  const ANSI_WHITE = "\u001b[97m";
10
+ const ANSI_ESCAPE_PATTERN = new RegExp(String.raw`\u001b\[[0-9;]*m`, "gu");
10
11
 
11
12
  function createColorFormatter(stream) {
12
13
  const noColor = Object.prototype.hasOwnProperty.call(process.env, "NO_COLOR");
@@ -55,6 +56,148 @@ function resolveWrapWidth(stream, fallbackWidth = 80) {
55
56
  return Math.floor(columns);
56
57
  }
57
58
 
59
+ function measureVisibleLength(text = "") {
60
+ return String(text || "").replace(ANSI_ESCAPE_PATTERN, "").length;
61
+ }
62
+
63
+ function resolveLeadingWhitespace(text = "") {
64
+ const match = String(text || "").match(/^\s*/u);
65
+ return match?.[0] || "";
66
+ }
67
+
68
+ function buildContinuationIndent({ prefix = "", fallbackPrefix = "" } = {}) {
69
+ const prefixLength = measureVisibleLength(prefix);
70
+ const fallbackLength = measureVisibleLength(fallbackPrefix);
71
+ const continuationLength = prefixLength > fallbackLength + 24
72
+ ? fallbackLength
73
+ : prefixLength;
74
+ return " ".repeat(Math.max(0, continuationLength));
75
+ }
76
+
77
+ function resolveWrapPrefixes(line = "") {
78
+ const normalizedLine = String(line || "").replace(/[ \t]+$/u, "");
79
+ const prefixedPatterns = [
80
+ {
81
+ pattern: /^(\s+\S+)(\s{2,})(\S.*)$/u,
82
+ create(match) {
83
+ const prefix = `${match[1]}${match[2]}`;
84
+ return Object.freeze({
85
+ prefix,
86
+ continuationPrefix: buildContinuationIndent({
87
+ prefix,
88
+ fallbackPrefix: resolveLeadingWhitespace(match[1])
89
+ }),
90
+ text: match[3]
91
+ });
92
+ }
93
+ },
94
+ {
95
+ pattern: /^(\s*[-*]\s+)(.+)$/u,
96
+ create(match) {
97
+ return Object.freeze({
98
+ prefix: match[1],
99
+ continuationPrefix: buildContinuationIndent({
100
+ prefix: match[1],
101
+ fallbackPrefix: resolveLeadingWhitespace(match[1])
102
+ }),
103
+ text: match[2]
104
+ });
105
+ }
106
+ },
107
+ {
108
+ pattern: /^(\s*\d+[.)]\s+)(.+)$/u,
109
+ create(match) {
110
+ return Object.freeze({
111
+ prefix: match[1],
112
+ continuationPrefix: buildContinuationIndent({
113
+ prefix: match[1],
114
+ fallbackPrefix: resolveLeadingWhitespace(match[1])
115
+ }),
116
+ text: match[2]
117
+ });
118
+ }
119
+ },
120
+ {
121
+ pattern: /^(\s*[A-Za-z][A-Za-z0-9 ()/_-]*:\s+)(.+)$/u,
122
+ create(match) {
123
+ return Object.freeze({
124
+ prefix: match[1],
125
+ continuationPrefix: buildContinuationIndent({
126
+ prefix: match[1],
127
+ fallbackPrefix: resolveLeadingWhitespace(match[1])
128
+ }),
129
+ text: match[2]
130
+ });
131
+ }
132
+ }
133
+ ];
134
+
135
+ for (const entry of prefixedPatterns) {
136
+ const pattern = entry.pattern;
137
+ const match = normalizedLine.match(pattern);
138
+ if (!match) {
139
+ continue;
140
+ }
141
+ return entry.create(match);
142
+ }
143
+
144
+ const leadingWhitespaceMatch = normalizedLine.match(/^(\s*)(.*)$/u);
145
+ const prefix = leadingWhitespaceMatch?.[1] || "";
146
+ const text = leadingWhitespaceMatch?.[2] || "";
147
+ return Object.freeze({
148
+ prefix,
149
+ continuationPrefix: prefix,
150
+ text
151
+ });
152
+ }
153
+
154
+ function wrapOutputLine(line = "", { wrapWidth = 80 } = {}) {
155
+ const normalizedLine = String(line || "").replace(/[ \t]+$/u, "");
156
+ if (!normalizedLine.trim()) {
157
+ return [""];
158
+ }
159
+
160
+ const width = Math.max(20, Number(wrapWidth) || 80);
161
+ const { prefix, continuationPrefix, text } = resolveWrapPrefixes(normalizedLine);
162
+ const words = String(text || "").trim().split(/\s+/u).filter(Boolean);
163
+ if (words.length < 1) {
164
+ return [normalizedLine];
165
+ }
166
+
167
+ const lines = [];
168
+ let currentPrefix = prefix;
169
+ let currentLine = currentPrefix;
170
+ let currentLength = measureVisibleLength(currentPrefix);
171
+
172
+ for (const word of words) {
173
+ const separator = currentLength > measureVisibleLength(currentPrefix) ? " " : "";
174
+ const nextLength = currentLength + measureVisibleLength(separator) + measureVisibleLength(word);
175
+ if (currentLength > measureVisibleLength(currentPrefix) && nextLength > width) {
176
+ lines.push(currentLine);
177
+ currentPrefix = continuationPrefix;
178
+ currentLine = `${currentPrefix}${word}`;
179
+ currentLength = measureVisibleLength(currentPrefix) + measureVisibleLength(word);
180
+ continue;
181
+ }
182
+
183
+ currentLine = `${currentLine}${separator}${word}`;
184
+ currentLength = nextLength;
185
+ }
186
+
187
+ lines.push(currentLine);
188
+ return lines;
189
+ }
190
+
191
+ function writeWrappedLines({ stdout, lines, wrapWidth } = {}) {
192
+ const output = stdout || process.stdout;
193
+ const width = resolveWrapWidth(output, wrapWidth ?? 100);
194
+ for (const line of ensureArray(lines)) {
195
+ for (const wrappedLine of wrapOutputLine(line, { wrapWidth: width })) {
196
+ output.write(`${wrappedLine}\n`);
197
+ }
198
+ }
199
+ }
200
+
58
201
  function writeWrappedItems({ stdout, heading, items, lineIndent = " ", wrapWidth = 80 }) {
59
202
  const records = ensureArray(items)
60
203
  .map((entry) => {
@@ -96,8 +239,29 @@ function writeWrappedItems({ stdout, heading, items, lineIndent = " ", wrapWidt
96
239
  }
97
240
  }
98
241
 
242
+ function renderInlineCodeSpans(text = "", color = null) {
243
+ const sourceText = String(text || "");
244
+ if (!sourceText.includes("`")) {
245
+ return sourceText;
246
+ }
247
+
248
+ return sourceText.replace(/`([^`]+)`/g, (_match, codeText) => {
249
+ const normalizedCodeText = String(codeText || "");
250
+ if (!normalizedCodeText) {
251
+ return "``";
252
+ }
253
+ if (!color || typeof color.item !== "function") {
254
+ return `\`${normalizedCodeText}\``;
255
+ }
256
+ const rendered = String(color.item(normalizedCodeText));
257
+ return rendered === normalizedCodeText ? `\`${normalizedCodeText}\`` : rendered;
258
+ });
259
+ }
260
+
99
261
  export {
100
262
  createColorFormatter,
263
+ renderInlineCodeSpans,
101
264
  resolveWrapWidth,
265
+ writeWrappedLines,
102
266
  writeWrappedItems
103
267
  };