@optique/core 1.1.0-dev.2096 → 1.1.0-dev.2146
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/dist/annotation-state.cjs +26 -26
- package/dist/annotation-state.d.cts +133 -1
- package/dist/annotation-state.d.ts +133 -1
- package/dist/annotations.cjs +2 -2
- package/dist/constructs.cjs +141 -73
- package/dist/constructs.js +70 -2
- package/dist/dependency-metadata.cjs +12 -12
- package/dist/dependency-metadata.d.cts +34 -3
- package/dist/dependency-metadata.d.ts +34 -3
- package/dist/dependency-runtime.cjs +37 -13
- package/dist/dependency-runtime.d.cts +197 -2
- package/dist/dependency-runtime.d.ts +197 -2
- package/dist/dependency-runtime.js +22 -1
- package/dist/dependency.cjs +7 -7
- package/dist/displaywidth.d.cts +12 -0
- package/dist/displaywidth.d.ts +12 -0
- package/dist/execution-context.d.cts +23 -0
- package/dist/execution-context.d.ts +23 -0
- package/dist/extension.cjs +14 -14
- package/dist/facade.cjs +46 -36
- package/dist/facade.js +31 -21
- package/dist/index.cjs +22 -21
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +3 -3
- package/dist/input-trace.d.cts +2 -1
- package/dist/input-trace.d.ts +2 -1
- package/dist/internal/annotations.cjs +3 -0
- package/dist/internal/annotations.d.cts +47 -5
- package/dist/internal/annotations.d.ts +47 -5
- package/dist/internal/annotations.js +1 -1
- package/dist/internal/command-alias.cjs +16 -0
- package/dist/internal/command-alias.js +14 -0
- package/dist/internal/dependency.cjs +131 -0
- package/dist/internal/dependency.d.cts +311 -2
- package/dist/internal/dependency.d.ts +311 -2
- package/dist/internal/dependency.js +119 -1
- package/dist/internal/parser.cjs +35 -13
- package/dist/internal/parser.d.cts +44 -3
- package/dist/internal/parser.d.ts +44 -3
- package/dist/internal/parser.js +28 -6
- package/dist/modifiers.cjs +41 -41
- package/dist/parser.cjs +11 -11
- package/dist/phase2-seed.cjs +2 -2
- package/dist/phase2-seed.d.cts +50 -0
- package/dist/phase2-seed.d.ts +50 -0
- package/dist/primitives.cjs +74 -33
- package/dist/primitives.d.cts +10 -0
- package/dist/primitives.d.ts +10 -0
- package/dist/primitives.js +54 -13
- package/dist/suggestion.cjs +72 -2
- package/dist/suggestion.d.cts +188 -0
- package/dist/suggestion.d.ts +188 -0
- package/dist/suggestion.js +71 -3
- package/dist/usage-internals.cjs +5 -1
- package/dist/usage-internals.js +5 -1
- package/dist/usage.cjs +9 -1
- package/dist/usage.d.cts +14 -0
- package/dist/usage.d.ts +14 -0
- package/dist/usage.js +9 -1
- package/dist/validate.cjs +1 -0
- package/dist/validate.d.cts +99 -0
- package/dist/validate.d.ts +99 -0
- package/dist/validate.js +1 -1
- package/dist/valueparser.cjs +333 -79
- package/dist/valueparser.d.cts +197 -1
- package/dist/valueparser.d.ts +197 -1
- package/dist/valueparser.js +334 -81
- package/package.json +19 -4
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { Message } from "./message.cjs";
|
|
2
|
+
import { Usage } from "./usage.cjs";
|
|
3
|
+
import { Suggestion } from "./internal/parser.cjs";
|
|
4
|
+
|
|
5
|
+
//#region src/suggestion.d.ts
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Calculates the Levenshtein distance between two strings.
|
|
9
|
+
*
|
|
10
|
+
* The Levenshtein distance is the minimum number of single-character edits
|
|
11
|
+
* (insertions, deletions, or substitutions) required to transform one string
|
|
12
|
+
* into another.
|
|
13
|
+
*
|
|
14
|
+
* @param source The source string
|
|
15
|
+
* @param target The target string
|
|
16
|
+
* @returns The edit distance (number of insertions, deletions, substitutions)
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* levenshteinDistance("kitten", "sitting"); // returns 3
|
|
21
|
+
* levenshteinDistance("--verbos", "--verbose"); // returns 1
|
|
22
|
+
* levenshteinDistance("hello", "hello"); // returns 0
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
declare function levenshteinDistance(source: string, target: string): number;
|
|
26
|
+
/**
|
|
27
|
+
* Options for finding similar strings.
|
|
28
|
+
*/
|
|
29
|
+
interface FindSimilarOptions {
|
|
30
|
+
/**
|
|
31
|
+
* Maximum edit distance to consider a match.
|
|
32
|
+
* Strings with a distance greater than this value will not be suggested.
|
|
33
|
+
* @default 3
|
|
34
|
+
*/
|
|
35
|
+
readonly maxDistance?: number;
|
|
36
|
+
/**
|
|
37
|
+
* Maximum distance ratio (distance / input length).
|
|
38
|
+
* Prevents suggesting long strings for very short inputs.
|
|
39
|
+
* For example, with maxDistanceRatio=0.5, an input of length 2
|
|
40
|
+
* will only suggest strings within distance 1.
|
|
41
|
+
* @default 0.5
|
|
42
|
+
*/
|
|
43
|
+
readonly maxDistanceRatio?: number;
|
|
44
|
+
/**
|
|
45
|
+
* Maximum number of suggestions to return.
|
|
46
|
+
* @default 3
|
|
47
|
+
*/
|
|
48
|
+
readonly maxSuggestions?: number;
|
|
49
|
+
/**
|
|
50
|
+
* Case-sensitive comparison.
|
|
51
|
+
* If false, strings are compared case-insensitively.
|
|
52
|
+
* @default false
|
|
53
|
+
*/
|
|
54
|
+
readonly caseSensitive?: boolean;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Default options for finding similar strings.
|
|
58
|
+
* These values are optimized for command-line option/command name suggestions.
|
|
59
|
+
*
|
|
60
|
+
* @since 0.7.0
|
|
61
|
+
*/
|
|
62
|
+
declare const DEFAULT_FIND_SIMILAR_OPTIONS: Required<FindSimilarOptions>;
|
|
63
|
+
/**
|
|
64
|
+
* Finds similar strings from a list of candidates.
|
|
65
|
+
*
|
|
66
|
+
* This function uses Levenshtein distance to find strings that are similar
|
|
67
|
+
* to the input string. Results are sorted by similarity (most similar first).
|
|
68
|
+
*
|
|
69
|
+
* @param input The input string to find matches for
|
|
70
|
+
* @param candidates List of candidate strings to compare against
|
|
71
|
+
* @param options Configuration options
|
|
72
|
+
* @returns Array of similar strings, sorted by similarity (most similar first)
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```typescript
|
|
76
|
+
* const candidates = ["--verbose", "--version", "--verify", "--help"];
|
|
77
|
+
* findSimilar("--verbos", candidates);
|
|
78
|
+
* // returns ["--verbose"]
|
|
79
|
+
*
|
|
80
|
+
* findSimilar("--ver", candidates, { maxDistance: 5 });
|
|
81
|
+
* // returns ["--verify", "--version", "--verbose"]
|
|
82
|
+
*
|
|
83
|
+
* findSimilar("--xyz", candidates);
|
|
84
|
+
* // returns [] (no similar matches)
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
declare function findSimilar(input: string, candidates: Iterable<string>, options?: FindSimilarOptions): string[];
|
|
88
|
+
/**
|
|
89
|
+
* Creates a suggestion message for a mismatched option/command.
|
|
90
|
+
*
|
|
91
|
+
* This function formats suggestions in a user-friendly way:
|
|
92
|
+
* - No suggestions: returns empty message
|
|
93
|
+
* - One suggestion: "Did you mean `option`?"
|
|
94
|
+
* - Multiple suggestions: "Did you mean one of these?\n option1\n option2"
|
|
95
|
+
*
|
|
96
|
+
* @param suggestions List of similar valid options/commands
|
|
97
|
+
* @returns A Message array with suggestion text
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```typescript
|
|
101
|
+
* createSuggestionMessage(["--verbose", "--version"]);
|
|
102
|
+
* // returns message parts for:
|
|
103
|
+
* // "Did you mean one of these?
|
|
104
|
+
* // --verbose
|
|
105
|
+
* // --version"
|
|
106
|
+
*
|
|
107
|
+
* createSuggestionMessage(["--verbose"]);
|
|
108
|
+
* // returns message parts for:
|
|
109
|
+
* // "Did you mean `--verbose`?"
|
|
110
|
+
*
|
|
111
|
+
* createSuggestionMessage([]);
|
|
112
|
+
* // returns []
|
|
113
|
+
* ```
|
|
114
|
+
*/
|
|
115
|
+
declare function createSuggestionMessage(suggestions: readonly string[]): Message;
|
|
116
|
+
/**
|
|
117
|
+
* Expands command alias suggestions so an alias typo can point at both the
|
|
118
|
+
* canonical command and the alias that matched.
|
|
119
|
+
*
|
|
120
|
+
* @param usage Usage terms that define command aliases.
|
|
121
|
+
* @param suggestions Candidate suggestions returned by {@link findSimilar}.
|
|
122
|
+
* @returns Suggestions with alias hits expanded to canonical name + alias.
|
|
123
|
+
* @internal
|
|
124
|
+
*/
|
|
125
|
+
declare function expandCommandAliasSuggestions(usage: Usage, suggestions: readonly string[]): readonly string[];
|
|
126
|
+
/**
|
|
127
|
+
* Creates an error message with suggestions for similar options or commands.
|
|
128
|
+
*
|
|
129
|
+
* This is a convenience function that combines the functionality of
|
|
130
|
+
* `findSimilar()` and `createSuggestionMessage()` to generate user-friendly
|
|
131
|
+
* error messages with "Did you mean?" suggestions.
|
|
132
|
+
*
|
|
133
|
+
* @param baseError The base error message to display
|
|
134
|
+
* @param invalidInput The invalid option or command name that the user typed
|
|
135
|
+
* @param usage The usage information to extract available options/commands from
|
|
136
|
+
* @param type What type of names to suggest ("option", "command", or "both")
|
|
137
|
+
* @param customFormatter Optional custom function to format suggestions instead
|
|
138
|
+
* of using the default "Did you mean?" formatting
|
|
139
|
+
* @returns A message combining the base error with suggestions, or just the
|
|
140
|
+
* base error if no similar names are found
|
|
141
|
+
*
|
|
142
|
+
* @example
|
|
143
|
+
* ```typescript
|
|
144
|
+
* const baseError = message`No matched option for ${optionName("--verbos")}.`;
|
|
145
|
+
* const error = createErrorWithSuggestions(
|
|
146
|
+
* baseError,
|
|
147
|
+
* "--verbos",
|
|
148
|
+
* context.usage,
|
|
149
|
+
* "option"
|
|
150
|
+
* );
|
|
151
|
+
* // Returns: "No matched option for `--verbos`.\nDid you mean `--verbose`?"
|
|
152
|
+
* ```
|
|
153
|
+
*
|
|
154
|
+
* @since 0.7.0
|
|
155
|
+
*/
|
|
156
|
+
declare function createErrorWithSuggestions(baseError: Message, invalidInput: string, usage: Usage, type?: "option" | "command" | "both", customFormatter?: (suggestions: readonly string[]) => Message): Message;
|
|
157
|
+
/**
|
|
158
|
+
* Removes duplicate suggestions from an array while preserving order.
|
|
159
|
+
*
|
|
160
|
+
* Suggestions are considered duplicates if they have the same key:
|
|
161
|
+
* - Literal suggestions: same text
|
|
162
|
+
* - File suggestions: same type, extensions, and pattern
|
|
163
|
+
*
|
|
164
|
+
* The first occurrence of each unique suggestion is kept. For file
|
|
165
|
+
* suggestions, `includeHidden` is merged across duplicates: if any
|
|
166
|
+
* duplicate has `includeHidden: true`, the kept suggestion is upgraded
|
|
167
|
+
* to `includeHidden: true` because it is a superset of the non-hidden
|
|
168
|
+
* variant.
|
|
169
|
+
*
|
|
170
|
+
* @param suggestions Array of suggestions that may contain duplicates
|
|
171
|
+
* @returns A new array with duplicates removed, preserving order of first occurrences
|
|
172
|
+
*
|
|
173
|
+
* @example
|
|
174
|
+
* ```typescript
|
|
175
|
+
* const suggestions = [
|
|
176
|
+
* { kind: "literal", text: "--verbose" },
|
|
177
|
+
* { kind: "literal", text: "--help" },
|
|
178
|
+
* { kind: "literal", text: "--verbose" }, // duplicate
|
|
179
|
+
* ];
|
|
180
|
+
* deduplicateSuggestions(suggestions);
|
|
181
|
+
* // returns [{ kind: "literal", text: "--verbose" }, { kind: "literal", text: "--help" }]
|
|
182
|
+
* ```
|
|
183
|
+
*
|
|
184
|
+
* @since 0.9.0
|
|
185
|
+
*/
|
|
186
|
+
declare function deduplicateSuggestions(suggestions: readonly Suggestion[]): Suggestion[];
|
|
187
|
+
//#endregion
|
|
188
|
+
export { DEFAULT_FIND_SIMILAR_OPTIONS, FindSimilarOptions, createErrorWithSuggestions, createSuggestionMessage, deduplicateSuggestions, expandCommandAliasSuggestions, findSimilar, levenshteinDistance };
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { Message } from "./message.js";
|
|
2
|
+
import { Usage } from "./usage.js";
|
|
3
|
+
import { Suggestion } from "./internal/parser.js";
|
|
4
|
+
|
|
5
|
+
//#region src/suggestion.d.ts
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Calculates the Levenshtein distance between two strings.
|
|
9
|
+
*
|
|
10
|
+
* The Levenshtein distance is the minimum number of single-character edits
|
|
11
|
+
* (insertions, deletions, or substitutions) required to transform one string
|
|
12
|
+
* into another.
|
|
13
|
+
*
|
|
14
|
+
* @param source The source string
|
|
15
|
+
* @param target The target string
|
|
16
|
+
* @returns The edit distance (number of insertions, deletions, substitutions)
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* levenshteinDistance("kitten", "sitting"); // returns 3
|
|
21
|
+
* levenshteinDistance("--verbos", "--verbose"); // returns 1
|
|
22
|
+
* levenshteinDistance("hello", "hello"); // returns 0
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
declare function levenshteinDistance(source: string, target: string): number;
|
|
26
|
+
/**
|
|
27
|
+
* Options for finding similar strings.
|
|
28
|
+
*/
|
|
29
|
+
interface FindSimilarOptions {
|
|
30
|
+
/**
|
|
31
|
+
* Maximum edit distance to consider a match.
|
|
32
|
+
* Strings with a distance greater than this value will not be suggested.
|
|
33
|
+
* @default 3
|
|
34
|
+
*/
|
|
35
|
+
readonly maxDistance?: number;
|
|
36
|
+
/**
|
|
37
|
+
* Maximum distance ratio (distance / input length).
|
|
38
|
+
* Prevents suggesting long strings for very short inputs.
|
|
39
|
+
* For example, with maxDistanceRatio=0.5, an input of length 2
|
|
40
|
+
* will only suggest strings within distance 1.
|
|
41
|
+
* @default 0.5
|
|
42
|
+
*/
|
|
43
|
+
readonly maxDistanceRatio?: number;
|
|
44
|
+
/**
|
|
45
|
+
* Maximum number of suggestions to return.
|
|
46
|
+
* @default 3
|
|
47
|
+
*/
|
|
48
|
+
readonly maxSuggestions?: number;
|
|
49
|
+
/**
|
|
50
|
+
* Case-sensitive comparison.
|
|
51
|
+
* If false, strings are compared case-insensitively.
|
|
52
|
+
* @default false
|
|
53
|
+
*/
|
|
54
|
+
readonly caseSensitive?: boolean;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Default options for finding similar strings.
|
|
58
|
+
* These values are optimized for command-line option/command name suggestions.
|
|
59
|
+
*
|
|
60
|
+
* @since 0.7.0
|
|
61
|
+
*/
|
|
62
|
+
declare const DEFAULT_FIND_SIMILAR_OPTIONS: Required<FindSimilarOptions>;
|
|
63
|
+
/**
|
|
64
|
+
* Finds similar strings from a list of candidates.
|
|
65
|
+
*
|
|
66
|
+
* This function uses Levenshtein distance to find strings that are similar
|
|
67
|
+
* to the input string. Results are sorted by similarity (most similar first).
|
|
68
|
+
*
|
|
69
|
+
* @param input The input string to find matches for
|
|
70
|
+
* @param candidates List of candidate strings to compare against
|
|
71
|
+
* @param options Configuration options
|
|
72
|
+
* @returns Array of similar strings, sorted by similarity (most similar first)
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```typescript
|
|
76
|
+
* const candidates = ["--verbose", "--version", "--verify", "--help"];
|
|
77
|
+
* findSimilar("--verbos", candidates);
|
|
78
|
+
* // returns ["--verbose"]
|
|
79
|
+
*
|
|
80
|
+
* findSimilar("--ver", candidates, { maxDistance: 5 });
|
|
81
|
+
* // returns ["--verify", "--version", "--verbose"]
|
|
82
|
+
*
|
|
83
|
+
* findSimilar("--xyz", candidates);
|
|
84
|
+
* // returns [] (no similar matches)
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
declare function findSimilar(input: string, candidates: Iterable<string>, options?: FindSimilarOptions): string[];
|
|
88
|
+
/**
|
|
89
|
+
* Creates a suggestion message for a mismatched option/command.
|
|
90
|
+
*
|
|
91
|
+
* This function formats suggestions in a user-friendly way:
|
|
92
|
+
* - No suggestions: returns empty message
|
|
93
|
+
* - One suggestion: "Did you mean `option`?"
|
|
94
|
+
* - Multiple suggestions: "Did you mean one of these?\n option1\n option2"
|
|
95
|
+
*
|
|
96
|
+
* @param suggestions List of similar valid options/commands
|
|
97
|
+
* @returns A Message array with suggestion text
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```typescript
|
|
101
|
+
* createSuggestionMessage(["--verbose", "--version"]);
|
|
102
|
+
* // returns message parts for:
|
|
103
|
+
* // "Did you mean one of these?
|
|
104
|
+
* // --verbose
|
|
105
|
+
* // --version"
|
|
106
|
+
*
|
|
107
|
+
* createSuggestionMessage(["--verbose"]);
|
|
108
|
+
* // returns message parts for:
|
|
109
|
+
* // "Did you mean `--verbose`?"
|
|
110
|
+
*
|
|
111
|
+
* createSuggestionMessage([]);
|
|
112
|
+
* // returns []
|
|
113
|
+
* ```
|
|
114
|
+
*/
|
|
115
|
+
declare function createSuggestionMessage(suggestions: readonly string[]): Message;
|
|
116
|
+
/**
|
|
117
|
+
* Expands command alias suggestions so an alias typo can point at both the
|
|
118
|
+
* canonical command and the alias that matched.
|
|
119
|
+
*
|
|
120
|
+
* @param usage Usage terms that define command aliases.
|
|
121
|
+
* @param suggestions Candidate suggestions returned by {@link findSimilar}.
|
|
122
|
+
* @returns Suggestions with alias hits expanded to canonical name + alias.
|
|
123
|
+
* @internal
|
|
124
|
+
*/
|
|
125
|
+
declare function expandCommandAliasSuggestions(usage: Usage, suggestions: readonly string[]): readonly string[];
|
|
126
|
+
/**
|
|
127
|
+
* Creates an error message with suggestions for similar options or commands.
|
|
128
|
+
*
|
|
129
|
+
* This is a convenience function that combines the functionality of
|
|
130
|
+
* `findSimilar()` and `createSuggestionMessage()` to generate user-friendly
|
|
131
|
+
* error messages with "Did you mean?" suggestions.
|
|
132
|
+
*
|
|
133
|
+
* @param baseError The base error message to display
|
|
134
|
+
* @param invalidInput The invalid option or command name that the user typed
|
|
135
|
+
* @param usage The usage information to extract available options/commands from
|
|
136
|
+
* @param type What type of names to suggest ("option", "command", or "both")
|
|
137
|
+
* @param customFormatter Optional custom function to format suggestions instead
|
|
138
|
+
* of using the default "Did you mean?" formatting
|
|
139
|
+
* @returns A message combining the base error with suggestions, or just the
|
|
140
|
+
* base error if no similar names are found
|
|
141
|
+
*
|
|
142
|
+
* @example
|
|
143
|
+
* ```typescript
|
|
144
|
+
* const baseError = message`No matched option for ${optionName("--verbos")}.`;
|
|
145
|
+
* const error = createErrorWithSuggestions(
|
|
146
|
+
* baseError,
|
|
147
|
+
* "--verbos",
|
|
148
|
+
* context.usage,
|
|
149
|
+
* "option"
|
|
150
|
+
* );
|
|
151
|
+
* // Returns: "No matched option for `--verbos`.\nDid you mean `--verbose`?"
|
|
152
|
+
* ```
|
|
153
|
+
*
|
|
154
|
+
* @since 0.7.0
|
|
155
|
+
*/
|
|
156
|
+
declare function createErrorWithSuggestions(baseError: Message, invalidInput: string, usage: Usage, type?: "option" | "command" | "both", customFormatter?: (suggestions: readonly string[]) => Message): Message;
|
|
157
|
+
/**
|
|
158
|
+
* Removes duplicate suggestions from an array while preserving order.
|
|
159
|
+
*
|
|
160
|
+
* Suggestions are considered duplicates if they have the same key:
|
|
161
|
+
* - Literal suggestions: same text
|
|
162
|
+
* - File suggestions: same type, extensions, and pattern
|
|
163
|
+
*
|
|
164
|
+
* The first occurrence of each unique suggestion is kept. For file
|
|
165
|
+
* suggestions, `includeHidden` is merged across duplicates: if any
|
|
166
|
+
* duplicate has `includeHidden: true`, the kept suggestion is upgraded
|
|
167
|
+
* to `includeHidden: true` because it is a superset of the non-hidden
|
|
168
|
+
* variant.
|
|
169
|
+
*
|
|
170
|
+
* @param suggestions Array of suggestions that may contain duplicates
|
|
171
|
+
* @returns A new array with duplicates removed, preserving order of first occurrences
|
|
172
|
+
*
|
|
173
|
+
* @example
|
|
174
|
+
* ```typescript
|
|
175
|
+
* const suggestions = [
|
|
176
|
+
* { kind: "literal", text: "--verbose" },
|
|
177
|
+
* { kind: "literal", text: "--help" },
|
|
178
|
+
* { kind: "literal", text: "--verbose" }, // duplicate
|
|
179
|
+
* ];
|
|
180
|
+
* deduplicateSuggestions(suggestions);
|
|
181
|
+
* // returns [{ kind: "literal", text: "--verbose" }, { kind: "literal", text: "--help" }]
|
|
182
|
+
* ```
|
|
183
|
+
*
|
|
184
|
+
* @since 0.9.0
|
|
185
|
+
*/
|
|
186
|
+
declare function deduplicateSuggestions(suggestions: readonly Suggestion[]): Suggestion[];
|
|
187
|
+
//#endregion
|
|
188
|
+
export { DEFAULT_FIND_SIMILAR_OPTIONS, FindSimilarOptions, createErrorWithSuggestions, createSuggestionMessage, deduplicateSuggestions, expandCommandAliasSuggestions, findSimilar, levenshteinDistance };
|
package/dist/suggestion.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { message, optionName, text } from "./message.js";
|
|
2
|
-
import { extractCommandNames, extractOptionNames } from "./usage.js";
|
|
2
|
+
import { extractCommandNames, extractOptionNames, isSuggestionHidden } from "./usage.js";
|
|
3
3
|
|
|
4
4
|
//#region src/suggestion.ts
|
|
5
5
|
/**
|
|
@@ -141,6 +141,73 @@ function createSuggestionMessage(suggestions) {
|
|
|
141
141
|
return messageParts;
|
|
142
142
|
}
|
|
143
143
|
/**
|
|
144
|
+
* Expands command alias suggestions so an alias typo can point at both the
|
|
145
|
+
* canonical command and the alias that matched.
|
|
146
|
+
*
|
|
147
|
+
* @param usage Usage terms that define command aliases.
|
|
148
|
+
* @param suggestions Candidate suggestions returned by {@link findSimilar}.
|
|
149
|
+
* @returns Suggestions with alias hits expanded to canonical name + alias.
|
|
150
|
+
* @internal
|
|
151
|
+
*/
|
|
152
|
+
function expandCommandAliasSuggestions(usage, suggestions) {
|
|
153
|
+
if (suggestions.length === 0) return suggestions;
|
|
154
|
+
const commandAliasTargets = collectCommandAliasTargets(usage);
|
|
155
|
+
const expanded = [];
|
|
156
|
+
const seen = /* @__PURE__ */ new Set();
|
|
157
|
+
for (const suggestion of suggestions) {
|
|
158
|
+
const targets = commandAliasTargets.get(suggestion) ?? [suggestion];
|
|
159
|
+
for (const target of targets) {
|
|
160
|
+
if (seen.has(target)) continue;
|
|
161
|
+
seen.add(target);
|
|
162
|
+
expanded.push(target);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return expanded;
|
|
166
|
+
}
|
|
167
|
+
function collectCommandAliasTargets(usage) {
|
|
168
|
+
const targets = /* @__PURE__ */ new Map();
|
|
169
|
+
function traverse(terms) {
|
|
170
|
+
if (!terms || !Array.isArray(terms)) return true;
|
|
171
|
+
for (const term of terms) {
|
|
172
|
+
if (term.type === "option") continue;
|
|
173
|
+
if (term.type === "argument") return false;
|
|
174
|
+
if (term.type === "command") {
|
|
175
|
+
if (isSuggestionHidden(term.hidden)) return false;
|
|
176
|
+
if (!targets.has(term.name)) targets.set(term.name, [term.name]);
|
|
177
|
+
for (const alias of term.aliases ?? []) if (!targets.has(alias)) targets.set(alias, [term.name, alias]);
|
|
178
|
+
for (const alias of term.hiddenAliases ?? []) if (!targets.has(alias)) targets.set(alias, [term.name]);
|
|
179
|
+
return false;
|
|
180
|
+
}
|
|
181
|
+
if (term.type === "optional") {
|
|
182
|
+
traverse(term.terms);
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
if (term.type === "multiple") {
|
|
186
|
+
const termsSkippable = traverse(term.terms);
|
|
187
|
+
if (term.min === 0 || termsSkippable) continue;
|
|
188
|
+
return false;
|
|
189
|
+
}
|
|
190
|
+
if (term.type === "sequence") {
|
|
191
|
+
if (traverse(term.terms)) continue;
|
|
192
|
+
return false;
|
|
193
|
+
}
|
|
194
|
+
if (term.type === "exclusive") {
|
|
195
|
+
let anySkippable = false;
|
|
196
|
+
for (const branch of term.terms) {
|
|
197
|
+
const branchSkippable = traverse(branch);
|
|
198
|
+
anySkippable = anySkippable || branchSkippable;
|
|
199
|
+
}
|
|
200
|
+
if (anySkippable) continue;
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
return false;
|
|
204
|
+
}
|
|
205
|
+
return true;
|
|
206
|
+
}
|
|
207
|
+
traverse(usage);
|
|
208
|
+
return targets;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
144
211
|
* Creates an error message with suggestions for similar options or commands.
|
|
145
212
|
*
|
|
146
213
|
* This is a convenience function that combines the functionality of
|
|
@@ -175,7 +242,8 @@ function createErrorWithSuggestions(baseError, invalidInput, usage, type = "both
|
|
|
175
242
|
if (type === "option" || type === "both") for (const name of extractOptionNames(usage)) candidates.add(name);
|
|
176
243
|
if (type === "command" || type === "both") for (const name of extractCommandNames(usage)) candidates.add(name);
|
|
177
244
|
const suggestions = findSimilar(invalidInput, candidates, DEFAULT_FIND_SIMILAR_OPTIONS);
|
|
178
|
-
const
|
|
245
|
+
const displaySuggestions = type === "option" ? suggestions : expandCommandAliasSuggestions(usage, suggestions);
|
|
246
|
+
const suggestionMsg = customFormatter ? customFormatter(displaySuggestions) : createSuggestionMessage(displaySuggestions);
|
|
179
247
|
return suggestionMsg.length > 0 ? [
|
|
180
248
|
...baseError,
|
|
181
249
|
text("\n\n"),
|
|
@@ -244,4 +312,4 @@ function deduplicateSuggestions(suggestions) {
|
|
|
244
312
|
}
|
|
245
313
|
|
|
246
314
|
//#endregion
|
|
247
|
-
export { DEFAULT_FIND_SIMILAR_OPTIONS, createErrorWithSuggestions, createSuggestionMessage, deduplicateSuggestions, findSimilar };
|
|
315
|
+
export { DEFAULT_FIND_SIMILAR_OPTIONS, createErrorWithSuggestions, createSuggestionMessage, deduplicateSuggestions, expandCommandAliasSuggestions, findSimilar, levenshteinDistance };
|
package/dist/usage-internals.cjs
CHANGED
|
@@ -24,7 +24,11 @@ function collectLeadingCandidates(terms, optionNames, commandNames, includeHidde
|
|
|
24
24
|
return false;
|
|
25
25
|
}
|
|
26
26
|
if (term.type === "command") {
|
|
27
|
-
if (includeHidden || !require_usage.isSuggestionHidden(term.hidden))
|
|
27
|
+
if (includeHidden || !require_usage.isSuggestionHidden(term.hidden)) {
|
|
28
|
+
commandNames.add(term.name);
|
|
29
|
+
for (const alias of term.aliases ?? []) commandNames.add(alias);
|
|
30
|
+
for (const alias of term.hiddenAliases ?? []) commandNames.add(alias);
|
|
31
|
+
}
|
|
28
32
|
return false;
|
|
29
33
|
}
|
|
30
34
|
if (term.type === "argument") return false;
|
package/dist/usage-internals.js
CHANGED
|
@@ -24,7 +24,11 @@ function collectLeadingCandidates(terms, optionNames, commandNames, includeHidde
|
|
|
24
24
|
return false;
|
|
25
25
|
}
|
|
26
26
|
if (term.type === "command") {
|
|
27
|
-
if (includeHidden || !isSuggestionHidden(term.hidden))
|
|
27
|
+
if (includeHidden || !isSuggestionHidden(term.hidden)) {
|
|
28
|
+
commandNames.add(term.name);
|
|
29
|
+
for (const alias of term.aliases ?? []) commandNames.add(alias);
|
|
30
|
+
for (const alias of term.hiddenAliases ?? []) commandNames.add(alias);
|
|
31
|
+
}
|
|
28
32
|
return false;
|
|
29
33
|
}
|
|
30
34
|
if (term.type === "argument") return false;
|
package/dist/usage.cjs
CHANGED
|
@@ -98,6 +98,8 @@ function extractCommandNames(usage, includeHidden) {
|
|
|
98
98
|
for (const term of terms) if (term.type === "command") {
|
|
99
99
|
if (!includeHidden && isSuggestionHidden(term.hidden)) continue;
|
|
100
100
|
names.add(term.name);
|
|
101
|
+
for (const alias of term.aliases ?? []) names.add(alias);
|
|
102
|
+
if (includeHidden) for (const alias of term.hiddenAliases ?? []) names.add(alias);
|
|
101
103
|
} else if (term.type === "optional" || term.type === "multiple" || term.type === "sequence") traverseUsage(term.terms);
|
|
102
104
|
else if (term.type === "exclusive") for (const exclusiveUsage of term.terms) traverseUsage(exclusiveUsage);
|
|
103
105
|
}
|
|
@@ -354,9 +356,15 @@ function cloneUsageTerm(term) {
|
|
|
354
356
|
names: [...term.names]
|
|
355
357
|
};
|
|
356
358
|
case "command": {
|
|
357
|
-
if (term.usageLine == null || typeof term.usageLine === "function") return {
|
|
359
|
+
if (term.usageLine == null || typeof term.usageLine === "function") return {
|
|
360
|
+
...term,
|
|
361
|
+
...term.aliases != null ? { aliases: [...term.aliases] } : {},
|
|
362
|
+
...term.hiddenAliases != null ? { hiddenAliases: [...term.hiddenAliases] } : {}
|
|
363
|
+
};
|
|
358
364
|
return {
|
|
359
365
|
...term,
|
|
366
|
+
...term.aliases != null ? { aliases: [...term.aliases] } : {},
|
|
367
|
+
...term.hiddenAliases != null ? { hiddenAliases: [...term.hiddenAliases] } : {},
|
|
360
368
|
usageLine: term.usageLine.map(cloneUsageTerm)
|
|
361
369
|
};
|
|
362
370
|
}
|
package/dist/usage.d.cts
CHANGED
|
@@ -104,6 +104,20 @@ type UsageTerm =
|
|
|
104
104
|
* in the command-line usage.
|
|
105
105
|
*/
|
|
106
106
|
readonly name: string;
|
|
107
|
+
/**
|
|
108
|
+
* Additional command names that invoke the same parser.
|
|
109
|
+
* These aliases participate in parsing, completion, and typo
|
|
110
|
+
* suggestions, but are not rendered in usage or documentation output.
|
|
111
|
+
* @since 1.1.0
|
|
112
|
+
*/
|
|
113
|
+
readonly aliases?: readonly string[];
|
|
114
|
+
/**
|
|
115
|
+
* Additional command names that invoke the same parser but are not
|
|
116
|
+
* rendered or suggested. They are still available to parsers and
|
|
117
|
+
* suggestion matchers so alias typos can resolve to the canonical command.
|
|
118
|
+
* @since 1.1.0
|
|
119
|
+
*/
|
|
120
|
+
readonly hiddenAliases?: readonly string[];
|
|
107
121
|
/**
|
|
108
122
|
* Optional usage line override for this command's own help page.
|
|
109
123
|
* This affects help/documentation rendering only.
|
package/dist/usage.d.ts
CHANGED
|
@@ -104,6 +104,20 @@ type UsageTerm =
|
|
|
104
104
|
* in the command-line usage.
|
|
105
105
|
*/
|
|
106
106
|
readonly name: string;
|
|
107
|
+
/**
|
|
108
|
+
* Additional command names that invoke the same parser.
|
|
109
|
+
* These aliases participate in parsing, completion, and typo
|
|
110
|
+
* suggestions, but are not rendered in usage or documentation output.
|
|
111
|
+
* @since 1.1.0
|
|
112
|
+
*/
|
|
113
|
+
readonly aliases?: readonly string[];
|
|
114
|
+
/**
|
|
115
|
+
* Additional command names that invoke the same parser but are not
|
|
116
|
+
* rendered or suggested. They are still available to parsers and
|
|
117
|
+
* suggestion matchers so alias typos can resolve to the canonical command.
|
|
118
|
+
* @since 1.1.0
|
|
119
|
+
*/
|
|
120
|
+
readonly hiddenAliases?: readonly string[];
|
|
107
121
|
/**
|
|
108
122
|
* Optional usage line override for this command's own help page.
|
|
109
123
|
* This affects help/documentation rendering only.
|
package/dist/usage.js
CHANGED
|
@@ -98,6 +98,8 @@ function extractCommandNames(usage, includeHidden) {
|
|
|
98
98
|
for (const term of terms) if (term.type === "command") {
|
|
99
99
|
if (!includeHidden && isSuggestionHidden(term.hidden)) continue;
|
|
100
100
|
names.add(term.name);
|
|
101
|
+
for (const alias of term.aliases ?? []) names.add(alias);
|
|
102
|
+
if (includeHidden) for (const alias of term.hiddenAliases ?? []) names.add(alias);
|
|
101
103
|
} else if (term.type === "optional" || term.type === "multiple" || term.type === "sequence") traverseUsage(term.terms);
|
|
102
104
|
else if (term.type === "exclusive") for (const exclusiveUsage of term.terms) traverseUsage(exclusiveUsage);
|
|
103
105
|
}
|
|
@@ -354,9 +356,15 @@ function cloneUsageTerm(term) {
|
|
|
354
356
|
names: [...term.names]
|
|
355
357
|
};
|
|
356
358
|
case "command": {
|
|
357
|
-
if (term.usageLine == null || typeof term.usageLine === "function") return {
|
|
359
|
+
if (term.usageLine == null || typeof term.usageLine === "function") return {
|
|
360
|
+
...term,
|
|
361
|
+
...term.aliases != null ? { aliases: [...term.aliases] } : {},
|
|
362
|
+
...term.hiddenAliases != null ? { hiddenAliases: [...term.hiddenAliases] } : {}
|
|
363
|
+
};
|
|
358
364
|
return {
|
|
359
365
|
...term,
|
|
366
|
+
...term.aliases != null ? { aliases: [...term.aliases] } : {},
|
|
367
|
+
...term.hiddenAliases != null ? { hiddenAliases: [...term.hiddenAliases] } : {},
|
|
360
368
|
usageLine: term.usageLine.map(cloneUsageTerm)
|
|
361
369
|
};
|
|
362
370
|
}
|
package/dist/validate.cjs
CHANGED
|
@@ -162,6 +162,7 @@ function validateContextIds(contexts) {
|
|
|
162
162
|
}
|
|
163
163
|
|
|
164
164
|
//#endregion
|
|
165
|
+
exports.escapeControlChars = escapeControlChars;
|
|
165
166
|
exports.validateCommandNames = validateCommandNames;
|
|
166
167
|
exports.validateContextIds = validateContextIds;
|
|
167
168
|
exports.validateLabel = validateLabel;
|