@xmorse/cac 6.0.1 → 6.0.3
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/deno/CAC.ts +15 -6
- package/deno/Command.ts +36 -14
- package/deno/utils.ts +1 -41
- package/dist/index.js +2 -35
- package/dist/index.mjs +2 -35
- package/package.json +2 -2
package/deno/CAC.ts
CHANGED
|
@@ -160,18 +160,27 @@ class CAC extends EventEmitter {
|
|
|
160
160
|
}
|
|
161
161
|
let shouldParse = true;
|
|
162
162
|
|
|
163
|
+
// Sort by name length (longest first) so "mcp login" matches before "mcp"
|
|
164
|
+
const sortedCommands = [...this.commands].sort((a, b) => {
|
|
165
|
+
const aLength = a.name.split(' ').filter(Boolean).length;
|
|
166
|
+
const bLength = b.name.split(' ').filter(Boolean).length;
|
|
167
|
+
return bLength - aLength;
|
|
168
|
+
});
|
|
169
|
+
|
|
163
170
|
// Search sub-commands
|
|
164
|
-
for (const command of
|
|
171
|
+
for (const command of sortedCommands) {
|
|
165
172
|
const parsed = this.mri(argv.slice(2), command);
|
|
166
|
-
const
|
|
167
|
-
if (
|
|
173
|
+
const result = command.isMatched(parsed.args as string[]);
|
|
174
|
+
if (result.matched) {
|
|
168
175
|
shouldParse = false;
|
|
176
|
+
const matchedCommandName = parsed.args.slice(0, result.consumedArgs).join(' ');
|
|
169
177
|
const parsedInfo = {
|
|
170
178
|
...parsed,
|
|
171
|
-
args: parsed.args.slice(
|
|
179
|
+
args: parsed.args.slice(result.consumedArgs)
|
|
172
180
|
};
|
|
173
|
-
this.setParsedInfo(parsedInfo, command,
|
|
174
|
-
this.emit(`command:${
|
|
181
|
+
this.setParsedInfo(parsedInfo, command, matchedCommandName);
|
|
182
|
+
this.emit(`command:${matchedCommandName}`, command);
|
|
183
|
+
break; // Stop after first match (greedy matching)
|
|
175
184
|
}
|
|
176
185
|
}
|
|
177
186
|
if (shouldParse) {
|
package/deno/Command.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import CAC from "./CAC.ts";
|
|
2
2
|
import Option, { OptionConfig } from "./Option.ts";
|
|
3
|
-
import { removeBrackets, findAllBrackets, findLongest, padRight, CACError
|
|
3
|
+
import { removeBrackets, findAllBrackets, findLongest, padRight, CACError } from "./utils.ts";
|
|
4
4
|
import { platformInfo } from "./deno.ts";
|
|
5
5
|
interface CommandArg {
|
|
6
6
|
required: boolean;
|
|
@@ -77,13 +77,38 @@ class Command {
|
|
|
77
77
|
this.commandAction = callback;
|
|
78
78
|
return this;
|
|
79
79
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
80
|
+
isMatched(args: string[]): {
|
|
81
|
+
matched: boolean;
|
|
82
|
+
consumedArgs: number;
|
|
83
|
+
} {
|
|
84
|
+
const nameParts = this.name.split(' ').filter(Boolean);
|
|
85
|
+
if (nameParts.length === 0) {
|
|
86
|
+
return {
|
|
87
|
+
matched: false,
|
|
88
|
+
consumedArgs: 0
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
if (args.length < nameParts.length) {
|
|
92
|
+
return {
|
|
93
|
+
matched: false,
|
|
94
|
+
consumedArgs: 0
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
for (let i = 0; i < nameParts.length; i++) {
|
|
98
|
+
if (nameParts[i] !== args[i]) {
|
|
99
|
+
if (i === 0 && this.aliasNames.includes(args[i])) {
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
matched: false,
|
|
104
|
+
consumedArgs: 0
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return {
|
|
109
|
+
matched: true,
|
|
110
|
+
consumedArgs: nameParts.length
|
|
111
|
+
};
|
|
87
112
|
}
|
|
88
113
|
get isDefaultCommand() {
|
|
89
114
|
return this.name === '' || this.aliasNames.includes('!');
|
|
@@ -120,12 +145,11 @@ class Command {
|
|
|
120
145
|
body: ` $ ${name} ${this.usageText || this.rawName}`
|
|
121
146
|
});
|
|
122
147
|
|
|
123
|
-
// Show description for specific commands (not global/default)
|
|
148
|
+
// Show full description for specific commands (not global/default)
|
|
124
149
|
if (!this.isGlobalCommand && !this.isDefaultCommand && this.description) {
|
|
125
|
-
const terminalWidth = process.stdout?.columns || 80;
|
|
126
150
|
sections.push({
|
|
127
151
|
title: 'Description',
|
|
128
|
-
body:
|
|
152
|
+
body: this.description.split('\n').map(line => ` ${line}`).join('\n')
|
|
129
153
|
});
|
|
130
154
|
}
|
|
131
155
|
const showCommands = (this.isGlobalCommand || this.isDefaultCommand) && commands.length > 0;
|
|
@@ -134,9 +158,7 @@ class Command {
|
|
|
134
158
|
sections.push({
|
|
135
159
|
title: 'Commands',
|
|
136
160
|
body: commands.map(command => {
|
|
137
|
-
|
|
138
|
-
const firstLine = command.description.split('\n')[0].trim();
|
|
139
|
-
return ` ${padRight(command.rawName, longestCommandName.length)} ${firstLine}`;
|
|
161
|
+
return ` ${padRight(command.rawName, longestCommandName.length)} ${command.description}`;
|
|
140
162
|
}).join('\n')
|
|
141
163
|
});
|
|
142
164
|
sections.push({
|
package/deno/utils.ts
CHANGED
|
@@ -126,44 +126,4 @@ export class CACError extends Error {
|
|
|
126
126
|
this.stack = new Error(message).stack;
|
|
127
127
|
}
|
|
128
128
|
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Wrap text to fit within a given width, preserving existing line breaks
|
|
133
|
-
* and special formatting (lists, code blocks, etc.)
|
|
134
|
-
*/
|
|
135
|
-
export const wrapText = (text: string, width = 80, indent = ' '): string => {
|
|
136
|
-
const lines = text.split('\n');
|
|
137
|
-
const result: string[] = [];
|
|
138
|
-
for (const line of lines) {
|
|
139
|
-
// Preserve empty lines
|
|
140
|
-
if (line.trim() === '') {
|
|
141
|
-
result.push('');
|
|
142
|
-
continue;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// Preserve lines that start with special chars (bullets, headers, code, indented)
|
|
146
|
-
if (/^(\s*[-*>#`]|\s{4,}|#{1,6}\s)/.test(line)) {
|
|
147
|
-
result.push(indent + line);
|
|
148
|
-
continue;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// Wrap normal paragraphs
|
|
152
|
-
const words = line.split(' ');
|
|
153
|
-
let currentLine = indent;
|
|
154
|
-
for (const word of words) {
|
|
155
|
-
if (currentLine.length + word.length + 1 > width) {
|
|
156
|
-
if (currentLine.trim()) {
|
|
157
|
-
result.push(currentLine);
|
|
158
|
-
}
|
|
159
|
-
currentLine = indent + word;
|
|
160
|
-
} else {
|
|
161
|
-
currentLine = currentLine === indent ? indent + word : `${currentLine} ${word}`;
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
if (currentLine.trim()) {
|
|
165
|
-
result.push(currentLine);
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
return result.join('\n');
|
|
169
|
-
};
|
|
129
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -4,37 +4,6 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
4
4
|
|
|
5
5
|
var events = require('events');
|
|
6
6
|
|
|
7
|
-
function wrapText(text, width = 80, indent = ' ') {
|
|
8
|
-
const lines = text.split('\n');
|
|
9
|
-
const result = [];
|
|
10
|
-
for (const line of lines) {
|
|
11
|
-
if (line.trim() === '') {
|
|
12
|
-
result.push('');
|
|
13
|
-
continue;
|
|
14
|
-
}
|
|
15
|
-
if (/^(\s*[-*>#`]|\s{4,}|#{1,6}\s)/.test(line)) {
|
|
16
|
-
result.push(indent + line);
|
|
17
|
-
continue;
|
|
18
|
-
}
|
|
19
|
-
const words = line.split(' ');
|
|
20
|
-
let currentLine = indent;
|
|
21
|
-
for (const word of words) {
|
|
22
|
-
if (currentLine.length + word.length + 1 > width) {
|
|
23
|
-
if (currentLine.trim()) {
|
|
24
|
-
result.push(currentLine);
|
|
25
|
-
}
|
|
26
|
-
currentLine = indent + word;
|
|
27
|
-
} else {
|
|
28
|
-
currentLine = currentLine === indent ? indent + word : `${currentLine} ${word}`;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
if (currentLine.trim()) {
|
|
32
|
-
result.push(currentLine);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
return result.join('\n');
|
|
36
|
-
}
|
|
37
|
-
|
|
38
7
|
function toArr(any) {
|
|
39
8
|
return any == null ? [] : Array.isArray(any) ? any : [any];
|
|
40
9
|
}
|
|
@@ -384,10 +353,9 @@ class Command {
|
|
|
384
353
|
body: ` $ ${name} ${this.usageText || this.rawName}`
|
|
385
354
|
});
|
|
386
355
|
if (!this.isGlobalCommand && !this.isDefaultCommand && this.description) {
|
|
387
|
-
const terminalWidth = process.stdout?.columns || 80;
|
|
388
356
|
sections.push({
|
|
389
357
|
title: "Description",
|
|
390
|
-
body:
|
|
358
|
+
body: this.description.split("\n").map((line) => ` ${line}`).join("\n")
|
|
391
359
|
});
|
|
392
360
|
}
|
|
393
361
|
const showCommands = (this.isGlobalCommand || this.isDefaultCommand) && commands.length > 0;
|
|
@@ -396,8 +364,7 @@ class Command {
|
|
|
396
364
|
sections.push({
|
|
397
365
|
title: "Commands",
|
|
398
366
|
body: commands.map((command) => {
|
|
399
|
-
|
|
400
|
-
return ` ${padRight(command.rawName, longestCommandName.length)} ${firstLine}`;
|
|
367
|
+
return ` ${padRight(command.rawName, longestCommandName.length)} ${command.description}`;
|
|
401
368
|
}).join("\n")
|
|
402
369
|
});
|
|
403
370
|
sections.push({
|
package/dist/index.mjs
CHANGED
|
@@ -1,36 +1,5 @@
|
|
|
1
1
|
import { EventEmitter } from 'events';
|
|
2
2
|
|
|
3
|
-
function wrapText(text, width = 80, indent = ' ') {
|
|
4
|
-
const lines = text.split('\n');
|
|
5
|
-
const result = [];
|
|
6
|
-
for (const line of lines) {
|
|
7
|
-
if (line.trim() === '') {
|
|
8
|
-
result.push('');
|
|
9
|
-
continue;
|
|
10
|
-
}
|
|
11
|
-
if (/^(\s*[-*>#`]|\s{4,}|#{1,6}\s)/.test(line)) {
|
|
12
|
-
result.push(indent + line);
|
|
13
|
-
continue;
|
|
14
|
-
}
|
|
15
|
-
const words = line.split(' ');
|
|
16
|
-
let currentLine = indent;
|
|
17
|
-
for (const word of words) {
|
|
18
|
-
if (currentLine.length + word.length + 1 > width) {
|
|
19
|
-
if (currentLine.trim()) {
|
|
20
|
-
result.push(currentLine);
|
|
21
|
-
}
|
|
22
|
-
currentLine = indent + word;
|
|
23
|
-
} else {
|
|
24
|
-
currentLine = currentLine === indent ? indent + word : `${currentLine} ${word}`;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
if (currentLine.trim()) {
|
|
28
|
-
result.push(currentLine);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
return result.join('\n');
|
|
32
|
-
}
|
|
33
|
-
|
|
34
3
|
function toArr(any) {
|
|
35
4
|
return any == null ? [] : Array.isArray(any) ? any : [any];
|
|
36
5
|
}
|
|
@@ -380,10 +349,9 @@ class Command {
|
|
|
380
349
|
body: ` $ ${name} ${this.usageText || this.rawName}`
|
|
381
350
|
});
|
|
382
351
|
if (!this.isGlobalCommand && !this.isDefaultCommand && this.description) {
|
|
383
|
-
const terminalWidth = process.stdout?.columns || 80;
|
|
384
352
|
sections.push({
|
|
385
353
|
title: "Description",
|
|
386
|
-
body:
|
|
354
|
+
body: this.description.split("\n").map((line) => ` ${line}`).join("\n")
|
|
387
355
|
});
|
|
388
356
|
}
|
|
389
357
|
const showCommands = (this.isGlobalCommand || this.isDefaultCommand) && commands.length > 0;
|
|
@@ -392,8 +360,7 @@ class Command {
|
|
|
392
360
|
sections.push({
|
|
393
361
|
title: "Commands",
|
|
394
362
|
body: commands.map((command) => {
|
|
395
|
-
|
|
396
|
-
return ` ${padRight(command.rawName, longestCommandName.length)} ${firstLine}`;
|
|
363
|
+
return ` ${padRight(command.rawName, longestCommandName.length)} ${command.description}`;
|
|
397
364
|
}).join("\n")
|
|
398
365
|
});
|
|
399
366
|
sections.push({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xmorse/cac",
|
|
3
|
-
"version": "6.0.
|
|
3
|
+
"version": "6.0.3",
|
|
4
4
|
"description": "Simple yet powerful framework for building command-line apps.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"url": "egoist/cac",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"test:cov": "jest --coverage",
|
|
32
32
|
"build:deno": "node -r sucrase/register scripts/build-deno.ts",
|
|
33
33
|
"build:node": "rollup -c",
|
|
34
|
-
"build": "
|
|
34
|
+
"build": "npm run build:deno && npm run build:node",
|
|
35
35
|
"toc": "markdown-toc -i README.md",
|
|
36
36
|
"prepublishOnly": "npm run build && cp mod.js mod.mjs",
|
|
37
37
|
"docs:api": "typedoc --out api-doc --readme none --exclude \"**/__test__/**\" --theme minimal"
|