mdat-plugin-cli-help 2.0.2 → 2.1.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.
Files changed (3) hide show
  1. package/dist/index.js +272 -0
  2. package/package.json +8 -5
  3. package/readme.md +1 -1
package/dist/index.js CHANGED
@@ -134,6 +134,277 @@ function setLogger(logger) {
134
134
  log = injectionHelper(logger);
135
135
  }
136
136
  //#endregion
137
+ //#region src/utilities/parsers/commander.ts
138
+ const flag$2 = createToken({
139
+ name: "flag",
140
+ pattern: /--[\w-]+/
141
+ });
142
+ const alias$2 = createToken({
143
+ name: "alias",
144
+ pattern: /-[A-Z]/i
145
+ });
146
+ const comma$2 = createToken({
147
+ group: Lexer.SKIPPED,
148
+ name: "comma",
149
+ pattern: /,/
150
+ });
151
+ const word$2 = createToken({
152
+ name: "word",
153
+ pattern: /\S+/
154
+ });
155
+ const argument$2 = createToken({
156
+ name: "argument",
157
+ pattern: /<\S+>|\[\S+\]/
158
+ });
159
+ const defaultInfoParens = createToken({
160
+ name: "defaultInfoParens",
161
+ pattern: /\(default:\s.+?\)/
162
+ });
163
+ const whiteSpace$2 = createToken({
164
+ group: Lexer.SKIPPED,
165
+ name: "whiteSpace",
166
+ pattern: /\s/
167
+ });
168
+ const usagePrefix = createToken({
169
+ group: Lexer.SKIPPED,
170
+ name: "usagePrefix",
171
+ pattern: /Usage:\s/
172
+ });
173
+ const startProgramDescription$1 = createToken({
174
+ group: Lexer.SKIPPED,
175
+ name: "startProgramDescription",
176
+ pattern: /\n\n/,
177
+ push_mode: "PROGRAM_DESCRIPTION_MODE"
178
+ });
179
+ const programDescription$2 = createToken({
180
+ name: "programDescription",
181
+ pattern: /.+/
182
+ });
183
+ const endProgramDescription$1 = createToken({
184
+ group: Lexer.SKIPPED,
185
+ name: "endProgramDescription",
186
+ pattern: /\n\n/,
187
+ pop_mode: true
188
+ });
189
+ const startOptionsSection$1 = createToken({
190
+ name: "startOptionsSection",
191
+ pattern: /Options:\n/,
192
+ push_mode: "SECTION_MODE"
193
+ });
194
+ const startCommandsSection$1 = createToken({
195
+ name: "startCommandsSection",
196
+ pattern: /Commands:\n/,
197
+ push_mode: "SECTION_MODE"
198
+ });
199
+ const startRow$2 = createToken({
200
+ name: "startRow",
201
+ pattern: / {2,}/,
202
+ push_mode: "ROW_MODE"
203
+ });
204
+ const rowDescription$2 = createToken({
205
+ name: "rowDescription",
206
+ pattern: / {2}\w.+? {2}/
207
+ });
208
+ const rowDescriptionTerminal$1 = createToken({
209
+ name: "rowDescriptionTerminal",
210
+ pattern: / {2}\w[^(\n]+(?=\(default:)| {2}\w.+/
211
+ });
212
+ const endRow$2 = createToken({
213
+ group: Lexer.SKIPPED,
214
+ name: "endRow",
215
+ pattern: /\n/,
216
+ pop_mode: true
217
+ });
218
+ const endSection$1 = createToken({
219
+ group: Lexer.SKIPPED,
220
+ name: "endSection",
221
+ pattern: /\n+/,
222
+ pop_mode: true
223
+ });
224
+ const lexer$2 = new Lexer({
225
+ defaultMode: "DEFAULT_MODE",
226
+ modes: {
227
+ DEFAULT_MODE: [
228
+ startOptionsSection$1,
229
+ startCommandsSection$1,
230
+ usagePrefix,
231
+ startProgramDescription$1,
232
+ argument$2,
233
+ word$2,
234
+ whiteSpace$2
235
+ ],
236
+ PROGRAM_DESCRIPTION_MODE: [endProgramDescription$1, programDescription$2],
237
+ ROW_MODE: [
238
+ endRow$2,
239
+ comma$2,
240
+ defaultInfoParens,
241
+ rowDescription$2,
242
+ rowDescriptionTerminal$1,
243
+ flag$2,
244
+ alias$2,
245
+ argument$2,
246
+ word$2,
247
+ whiteSpace$2
248
+ ],
249
+ SECTION_MODE: [startRow$2, endSection$1]
250
+ }
251
+ });
252
+ const allTokens$2 = [
253
+ flag$2,
254
+ alias$2,
255
+ comma$2,
256
+ word$2,
257
+ argument$2,
258
+ defaultInfoParens,
259
+ whiteSpace$2,
260
+ usagePrefix,
261
+ startProgramDescription$1,
262
+ programDescription$2,
263
+ endProgramDescription$1,
264
+ startOptionsSection$1,
265
+ startCommandsSection$1,
266
+ startRow$2,
267
+ rowDescription$2,
268
+ rowDescriptionTerminal$1,
269
+ endRow$2,
270
+ endSection$1
271
+ ];
272
+ var CliParser$2 = class extends CstParser {
273
+ sectionRow = this.RULE("sectionRow", () => {
274
+ this.CONSUME(startRow$2);
275
+ this.MANY(() => {
276
+ this.OR([
277
+ { ALT: () => this.CONSUME(argument$2) },
278
+ { ALT: () => this.CONSUME(alias$2) },
279
+ { ALT: () => this.CONSUME(flag$2) },
280
+ { ALT: () => this.CONSUME(rowDescription$2, { LABEL: "description" }) },
281
+ { ALT: () => this.CONSUME(rowDescriptionTerminal$1, { LABEL: "description" }) },
282
+ { ALT: () => this.CONSUME(defaultInfoParens) },
283
+ { ALT: () => this.CONSUME(word$2, { LABEL: "commandName" }) }
284
+ ]);
285
+ });
286
+ });
287
+ commandsSection = this.RULE("commandsSection", () => {
288
+ this.CONSUME(startCommandsSection$1);
289
+ this.MANY1(() => {
290
+ this.SUBRULE1(this.sectionRow);
291
+ });
292
+ });
293
+ optionsSection = this.RULE("optionsSection", () => {
294
+ this.CONSUME(startOptionsSection$1);
295
+ this.MANY2(() => {
296
+ this.SUBRULE2(this.sectionRow);
297
+ });
298
+ });
299
+ programHelp = this.RULE("programHelp", () => {
300
+ this.AT_LEAST_ONE(() => {
301
+ this.CONSUME(word$2, { LABEL: "commandName" });
302
+ });
303
+ this.MANY1(() => {
304
+ this.CONSUME(argument$2);
305
+ });
306
+ this.OPTION(() => {
307
+ this.CONSUME(programDescription$2, { LABEL: "description" });
308
+ });
309
+ this.OPTION1(() => {
310
+ this.SUBRULE(this.optionsSection);
311
+ });
312
+ this.OPTION2(() => {
313
+ this.SUBRULE(this.commandsSection);
314
+ });
315
+ });
316
+ constructor() {
317
+ super(allTokens$2);
318
+ this.performSelfAnalysis();
319
+ }
320
+ };
321
+ const parser$2 = new CliParser$2();
322
+ var CliHelpToObjectVisitor$2 = class extends parser$2.getBaseCstVisitorConstructor() {
323
+ constructor() {
324
+ super();
325
+ this.validateVisitor();
326
+ }
327
+ commandsSection(context) {
328
+ return context.sectionRow.map((entry) => this.visit(entry));
329
+ }
330
+ optionsSection(context) {
331
+ return context.sectionRow.map((entry) => this.visit(entry));
332
+ }
333
+ programHelp(context) {
334
+ const { command: commandName, subcommand: subcommandName } = getCommandParts(this.getString(context.commandName));
335
+ return {
336
+ arguments: this.getArray(context.argument),
337
+ commandName,
338
+ commands: context.commandsSection ? this.visit(context.commandsSection) : void 0,
339
+ description: this.getString(context.description),
340
+ options: context.optionsSection ? this.visit(context.optionsSection) : void 0,
341
+ subcommandName
342
+ };
343
+ }
344
+ sectionRow(context) {
345
+ return {
346
+ aliases: this.getArray(context.alias),
347
+ arguments: this.getArray(context.argument),
348
+ commandName: this.getString(context.commandName),
349
+ defaultValue: this.cleanDefault(this.getString(context.defaultInfoParens)),
350
+ description: this.trimDescription(this.getString(context.description)),
351
+ flags: this.getArray(context.flag)
352
+ };
353
+ }
354
+ /**
355
+ * Clean a Commander default value: strip `(default: ...)` wrapper, env info, and quotes.
356
+ */
357
+ cleanDefault(text) {
358
+ if (text === void 0) return void 0;
359
+ let cleaned = text.replaceAll(/^\(default:\s*/g, "").replaceAll(/\)$/g, "").trim();
360
+ cleaned = cleaned.replaceAll(/,\s*env:\s*\S+$/g, "").trim();
361
+ cleaned = cleaned.replaceAll(/^["']|["']$/g, "");
362
+ return cleaned || void 0;
363
+ }
364
+ getArray(context) {
365
+ if (context === void 0) return void 0;
366
+ return context.map((entry) => entry.image);
367
+ }
368
+ getString(context) {
369
+ if (context === void 0) return void 0;
370
+ return context.map((entry) => entry.image).join(" ");
371
+ }
372
+ /**
373
+ * Trim leading/trailing whitespace from description text.
374
+ */
375
+ trimDescription(text) {
376
+ if (text === void 0) return void 0;
377
+ return text.trim() || void 0;
378
+ }
379
+ };
380
+ const visitor$2 = new CliHelpToObjectVisitor$2();
381
+ /**
382
+ * Converts an unstructured help string emitted from a CLI tool built with the
383
+ * `Commander` CLI library and turn it into a structured POJO describing the
384
+ * command.
385
+ */
386
+ function helpStringToObject$3(helpString) {
387
+ if (!helpString.trimStart().startsWith("Usage:")) throw new Error("Not a Commander-format help string (must start with \"Usage:\")");
388
+ const lexingResult = lexer$2.tokenize(helpString);
389
+ if (lexingResult.errors.length > 0) throw new Error(`Errors lexing CLI command: ${JSON.stringify(lexingResult.errors, void 0, 2)}`);
390
+ parser$2.input = lexingResult.tokens;
391
+ const cst = parser$2.programHelp();
392
+ if (parser$2.errors.length > 0) throw new Error(`Errors parsing CLI command help text: ${JSON.stringify(parser$2.errors, void 0, 2)}`);
393
+ let programInfo;
394
+ try {
395
+ programInfo = visitor$2.visit(cst);
396
+ } catch (error) {
397
+ if (error instanceof Error) throw new TypeError(`Errors visiting CLI command help text: ${String(error)}`);
398
+ }
399
+ if (programInfo === void 0) throw new Error("Could not parse help string");
400
+ if (programInfo.commands) {
401
+ programInfo.commands = programInfo.commands.filter((cmd) => cmd.commandName !== void 0 || cmd.description !== void 0);
402
+ for (const cmd of programInfo.commands) if (cmd.commandName && !cmd.parentCommandName) cmd.parentCommandName = programInfo.commandName;
403
+ if (programInfo.commands.length === 0) programInfo.commands = void 0;
404
+ }
405
+ return programInfo;
406
+ }
407
+ //#endregion
137
408
  //#region src/utilities/parsers/meow.ts
138
409
  const flag$1 = createToken({
139
410
  name: "flag",
@@ -674,6 +945,7 @@ function helpStringToObject$1(helpString) {
674
945
  //#endregion
675
946
  //#region src/utilities/parsers/index.ts
676
947
  var parsers_default = {
948
+ commander: helpStringToObject$3,
677
949
  yargs: helpStringToObject$1,
678
950
  meow: helpStringToObject$2
679
951
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mdat-plugin-cli-help",
3
- "version": "2.0.2",
3
+ "version": "2.1.0",
4
4
  "description": "Mdat plugin to generate tabular help documentation for CLI tools in Markdown files.",
5
5
  "keywords": [
6
6
  "markdown",
@@ -38,20 +38,23 @@
38
38
  "@types/which": "^3.0.4",
39
39
  "chevrotain": "^12.0.0",
40
40
  "execa": "^9.6.1",
41
- "lognow": "^0.6.0",
41
+ "lognow": "^0.6.1",
42
42
  "type-fest": "^5.5.0",
43
43
  "which": "^6.0.1",
44
44
  "zod": "^4.3.6"
45
45
  },
46
46
  "devDependencies": {
47
- "@kitschpatrol/shared-config": "^7.0.0",
47
+ "@kitschpatrol/shared-config": "^7.1.0",
48
48
  "@types/node": "~22.17.2",
49
+ "@types/yargs": "^17.0.35",
49
50
  "bumpp": "^11.0.1",
50
- "mdat": "^2.0.0",
51
+ "commander": "^14.0.3",
52
+ "mdat": "^2.2.0",
51
53
  "meow": "^14.1.0",
52
54
  "tsdown": "^0.21.7",
53
55
  "typescript": "~5.9.3",
54
- "vitest": "^4.1.2"
56
+ "vitest": "^4.1.2",
57
+ "yargs": "^18.0.0"
55
58
  },
56
59
  "peerDependencies": {
57
60
  "mdat": "^2.0.0"
package/readme.md CHANGED
@@ -26,7 +26,7 @@ This plugin automatically transforms a CLI command's `--help` output into nicely
26
26
 
27
27
  The rule also recursively calls `--help` on any subcommands found for inclusion in the output.
28
28
 
29
- Currently, the rule can only parse help output in the format provided by [Yargs](https://yargs.js.org)- and [Meow](https://github.com/sindresorhus/meow)-based tools. If parsing fails, the rule will fall back to show the raw help output in a regular code block instead.
29
+ Currently, the rule can parse help output in the format provided by [Commander](https://github.com/tj/commander.js)-, [Yargs](https://yargs.js.org)-, and [Meow](https://github.com/sindresorhus/meow)-based tools. If parsing fails, the rule will fall back to show the raw help output in a regular code block instead.
30
30
 
31
31
  ## Getting started
32
32