Skip to content

Commit 56562c1

Browse files
committed
Added help document generator.
1 parent 703ba5d commit 56562c1

File tree

9 files changed

+734
-37
lines changed

9 files changed

+734
-37
lines changed

.vscode/launch.json

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
// Use IntelliSense to learn about possible attributes.
3+
// Hover to view descriptions of existing attributes.
4+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5+
"version": "0.2.0",
6+
"configurations": [
7+
{
8+
"type": "node",
9+
"request": "launch",
10+
"name": "[LiteRT/Clap.js] Sample 01 - Commandless",
11+
"program": "${workspaceFolder}/src/samples/01-command-less.ts",
12+
"cwd": "${workspaceFolder}",
13+
"sourceMaps": true,
14+
"outFiles": [
15+
"${workspaceFolder}/lib/*.js",
16+
"${workspaceFolder}/samples/*.js"
17+
]
18+
},
19+
{
20+
"type": "node",
21+
"request": "launch",
22+
"name": "[LiteRT/Clap.js] Sample 02 - Command help",
23+
"program": "${workspaceFolder}/src/samples/02-command.ts",
24+
"cwd": "${workspaceFolder}",
25+
"sourceMaps": true,
26+
"outFiles": [
27+
"${workspaceFolder}/lib/*.js",
28+
"${workspaceFolder}/samples/*.js"
29+
]
30+
}
31+
]
32+
}

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ npm i @litert/clap --save
1515

1616
## Documents
1717

18-
- [简体中文版](./docs/zh-CN/index.md)
18+
Preparing yet.
1919

2020
## License
2121

src/lib/AbstractParser.ts

Lines changed: 86 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@ export class Option {
3131

3232
public path?: string,
3333

34-
public parent?: Command
34+
public parent?: Command,
35+
36+
public argName: string = "VALUE"
3537
) {
3638

3739
}
@@ -43,12 +45,12 @@ export class Option {
4345

4446
public static isValidName(name: string): boolean {
4547

46-
return /^[a-zA-Z0-9][-a-zA-Z0-9]+$/.test(name);
48+
return /^[a-z0-9][-a-z0-9]+$/i.test(name);
4749
}
4850

4951
public static isValidShortcut(shortcut: string): boolean {
5052

51-
return /^[a-zA-Z0-9]$/.test(shortcut);
53+
return /^[a-z0-9]$/i.test(shortcut);
5254
}
5355

5456
}
@@ -73,7 +75,7 @@ export class Command {
7375

7476
public description: string,
7577

76-
public alias?: string[],
78+
public aliases?: string[],
7779

7880
public parent?: Command
7981
) {
@@ -99,6 +101,16 @@ export class Command {
99101
return null;
100102
}
101103

104+
public get hasSubCommands(): boolean {
105+
106+
return !!Object.keys(this.subCommands).length;
107+
}
108+
109+
public get hasOptions(): boolean {
110+
111+
return !!Object.keys(this.options).length;
112+
}
113+
102114
public getOptionByShortcut(shortcut: string): Option | null {
103115

104116
if (this.optionShortcuts[shortcut]) {
@@ -116,12 +128,12 @@ export class Command {
116128

117129
public static isValidName(name: string): boolean {
118130

119-
return /^[-a-zA-Z0-9]+$/.test(name);
131+
return /^[a-z0-9][-a-z0-9]*$/i.test(name);
120132
}
121133

122134
public static isValidPath(path: string): boolean {
123135

124-
return /^[-a-zA-Z0-9]+(\.[-a-zA-Z0-9]+)*$/.test(path);
136+
return /^[a-z0-9][-a-z0-9]*(\.[a-z0-9][-a-z0-9]*)*$/i.test(path);
125137
}
126138
}
127139

@@ -143,6 +155,50 @@ export abstract class AbstractParser implements C.IParser {
143155
this._cmdAliases = {};
144156
this._options = {};
145157
this._optionShortcuts = {};
158+
159+
if (this._config.help.delegated) {
160+
161+
if (
162+
!this._config.help.flag &&
163+
!this._config.help.command
164+
) {
165+
166+
throw new E.E_CONFLICT_CONFIG({
167+
"message": "Must enable at least one of help-command or help-flag."
168+
});
169+
}
170+
}
171+
172+
if (this._config.help.delegated && this._config.help.flag) {
173+
174+
this.addOption({
175+
"name": "help",
176+
"description": "Display the help information.",
177+
"shortcut": this._config.help.flagShortchut ? "h" : undefined,
178+
"arguments": 0
179+
});
180+
}
181+
182+
if (
183+
!this._config.options.long.followArgument &&
184+
!this._config.options.long.assignArgument
185+
) {
186+
187+
throw new E.E_CONFLICT_CONFIG({
188+
"message": "Must enable at least one of follow-mode or assign-mode."
189+
});
190+
}
191+
192+
if (
193+
!this._config.options.shortcut.followArgument &&
194+
!this._config.options.shortcut.assignArgument &&
195+
!this._config.options.shortcut.attachArgument
196+
) {
197+
198+
throw new E.E_CONFLICT_CONFIG({
199+
"message": "Must enable at least one of follow-mode, attach-mode or assign-mode."
200+
});
201+
}
146202
}
147203

148204
public addCommand(settings: C.ICommandSettings): this {
@@ -156,7 +212,7 @@ export abstract class AbstractParser implements C.IParser {
156212

157213
if (settings.path) {
158214

159-
const cmd = this._findCommandByPath(settings.path);
215+
const cmd = this._getCommandByPath(settings.path);
160216

161217
if (!cmd) {
162218

@@ -249,7 +305,8 @@ export abstract class AbstractParser implements C.IParser {
249305
settings,
250306
path,
251307
optName,
252-
optShortcut
308+
optShortcut,
309+
settings.argumentName
253310
);
254311
}
255312
}
@@ -258,7 +315,8 @@ export abstract class AbstractParser implements C.IParser {
258315
this._addOption(
259316
settings,
260317
optName,
261-
optShortcut
318+
optShortcut,
319+
settings.argumentName
262320
);
263321
}
264322

@@ -269,10 +327,11 @@ export abstract class AbstractParser implements C.IParser {
269327
settings: C.IOptionSettings,
270328
path: string,
271329
optName: string,
272-
optShortcut: string | undefined
330+
optShortcut: string | undefined,
331+
argName?: string
273332
): void {
274333

275-
const cmd = this._findCommandByPath(path);
334+
const cmd = this._getCommandByPath(path);
276335

277336
if (!cmd) {
278337

@@ -301,7 +360,8 @@ export abstract class AbstractParser implements C.IParser {
301360
optShortcut,
302361
settings.arguments,
303362
path,
304-
cmd
363+
cmd,
364+
argName
305365
);
306366

307367
if (optShortcut) {
@@ -313,7 +373,8 @@ export abstract class AbstractParser implements C.IParser {
313373
protected _addOption(
314374
settings: C.IOptionSettings,
315375
optName: string,
316-
optShortcut: string | undefined
376+
optShortcut: string | undefined,
377+
argName?: string
317378
): void {
318379

319380
if (this._options[optName]) {
@@ -334,7 +395,10 @@ export abstract class AbstractParser implements C.IParser {
334395
optName,
335396
settings.description,
336397
optShortcut,
337-
settings.arguments
398+
settings.arguments,
399+
undefined,
400+
undefined,
401+
argName
338402
);
339403

340404
if (optShortcut) {
@@ -413,7 +477,7 @@ export abstract class AbstractParser implements C.IParser {
413477
return ret;
414478
}
415479

416-
protected _findCommandByPath(path: string): Command | null {
480+
protected _getCommandByPath(path: string): Command | null {
417481

418482
path = this._prepareCommandPath(path);
419483

@@ -434,5 +498,11 @@ export abstract class AbstractParser implements C.IParser {
434498
}
435499
}
436500

437-
public abstract parse(args: string[]): C.IResult | false;
501+
public abstract parse(args: string[]): C.IResult;
502+
503+
public abstract generateHelp(
504+
appName: string,
505+
path: string,
506+
width?: number
507+
): string[];
438508
}

src/lib/Common.ts

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,13 @@ export interface IOptionSettings {
7676
* @default -1
7777
*/
7878
"arguments"?: number;
79+
80+
/**
81+
* The name for argument, used in HELP documents.
82+
*
83+
* @default "VALUE"
84+
*/
85+
"argumentName"?: string;
7986
}
8087

8188
export interface ICommandResult {
@@ -91,6 +98,11 @@ export interface ICommandResult {
9198

9299
export interface IResult {
93100

101+
/**
102+
* Tell if this request showing help document.
103+
*/
104+
"help": string;
105+
94106
/**
95107
* The parsed commands.
96108
*/
@@ -138,17 +150,22 @@ export interface IParser {
138150
/**
139151
* Parse the input arguments.
140152
*
141-
* @returns A `IResult` will be returned when parsed successfully. If help
142-
* is handled by the parser, `false` will be returned. When error occurs,
143-
* an exception will be thrown.
153+
* @returns A `IResult` will be returned when parsed successfully. When
154+
* error occurs, an exception will be thrown.
144155
*
145156
* @example
146157
*
147158
* ```ts
148159
* parser.parse(process.argv.slice(2));
149160
* ```
150161
*/
151-
parse(args: string[]): IResult | false;
162+
parse(args: string[]): IResult;
163+
164+
generateHelp(
165+
appName: string,
166+
path: string,
167+
width?: number
168+
): string[];
152169
}
153170

154171
export type DeepPartial<T> = {
@@ -167,21 +184,23 @@ export interface IParserHelpConfig {
167184
*
168185
* @default true
169186
*/
170-
"useCommand": boolean;
187+
"command": boolean;
171188

172189
/**
173-
* Use `-h` for shortcut.
190+
* Use `--help` (or `-help` when `go` style).
174191
*
175192
* @default true
176193
*/
177-
"shortFlag": boolean;
194+
"flag": boolean;
178195

179196
/**
180-
* Use `--help` (or `-help` when `go` style).
197+
* Use `-h` for shortcut.
198+
*
199+
* > Only work while `flag` is set to `true`.
181200
*
182201
* @default true
183202
*/
184-
"longFlag": boolean;
203+
"flagShortchut": boolean;
185204
}
186205

187206
export interface IParserCommandConfig {

src/lib/Errors.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
import * as Core from "@litert/core";
1818

19-
export const ErrorHub = Core.createErrorHub("@litert/clap");
19+
export const ErrorHub = Core.createErrorHub<Record<string, any>>("@litert/clap");
2020

2121
export const E_DUP_COMMAND_NAME = ErrorHub.define(
2222
null,
@@ -96,7 +96,7 @@ export const E_EXPECT_OPTION_ARGUMENT = ErrorHub.define(
9696
export const E_UNKNOWN_COMMAND = ErrorHub.define(
9797
null,
9898
"E_UNKNOWN_COMMAND",
99-
"Missing the command."
99+
"The command doesn't exist."
100100
);
101101

102102
export const E_TOO_MANY_ARGUMENTS = ErrorHub.define(
@@ -110,3 +110,15 @@ export const E_NO_ENOUGH_ARGUMENTS = ErrorHub.define(
110110
"E_NO_ENOUGH_ARGUMENTS",
111111
"The quantity of arguments is not enough."
112112
);
113+
114+
export const E_COMMAND_EXPECTED = ErrorHub.define(
115+
null,
116+
"E_COMMAND_EXPECTED",
117+
"Missing command or sub command."
118+
);
119+
120+
export const E_CONFLICT_CONFIG = ErrorHub.define(
121+
null,
122+
"E_CONFLICT_CONFIG",
123+
"The configuration is invalid because it's conflicted."
124+
);

0 commit comments

Comments
 (0)