@optique/core 0.8.0-dev.165 → 0.8.0-dev.167
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/constructs.cjs +108 -184
- package/dist/constructs.d.cts +10 -1
- package/dist/constructs.d.ts +10 -1
- package/dist/constructs.js +109 -186
- package/dist/index.cjs +1 -0
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/modifiers.cjs +41 -58
- package/dist/modifiers.js +41 -58
- package/dist/parser.cjs +14 -9
- package/dist/parser.d.cts +2 -2
- package/dist/parser.d.ts +2 -2
- package/dist/parser.js +15 -11
- package/dist/suggestion.cjs +50 -0
- package/dist/suggestion.js +50 -1
- package/dist/valueparser.cjs +1 -1
- package/dist/valueparser.js +1 -1
- package/package.json +1 -1
package/dist/modifiers.js
CHANGED
|
@@ -2,6 +2,45 @@ import { formatMessage, message, text } from "./message.js";
|
|
|
2
2
|
|
|
3
3
|
//#region src/modifiers.ts
|
|
4
4
|
/**
|
|
5
|
+
* Internal helper for optional-style parsing logic shared by optional()
|
|
6
|
+
* and withDefault(). Handles the common pattern of:
|
|
7
|
+
* - Unwrapping optional state to inner parser state
|
|
8
|
+
* - Detecting if inner parser actually matched (state changed or no consumption)
|
|
9
|
+
* - Returning success with undefined state when inner parser fails without consuming
|
|
10
|
+
* @internal
|
|
11
|
+
*/
|
|
12
|
+
function parseOptionalStyle(context, parser) {
|
|
13
|
+
const innerState = typeof context.state === "undefined" ? parser.initialState : context.state[0];
|
|
14
|
+
const result = parser.parse({
|
|
15
|
+
...context,
|
|
16
|
+
state: innerState
|
|
17
|
+
});
|
|
18
|
+
if (result.success) {
|
|
19
|
+
if (result.next.state !== innerState || result.consumed.length === 0) return {
|
|
20
|
+
success: true,
|
|
21
|
+
next: {
|
|
22
|
+
...result.next,
|
|
23
|
+
state: [result.next.state]
|
|
24
|
+
},
|
|
25
|
+
consumed: result.consumed
|
|
26
|
+
};
|
|
27
|
+
return {
|
|
28
|
+
success: true,
|
|
29
|
+
next: {
|
|
30
|
+
...result.next,
|
|
31
|
+
state: context.state
|
|
32
|
+
},
|
|
33
|
+
consumed: result.consumed
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
if (result.consumed === 0) return {
|
|
37
|
+
success: true,
|
|
38
|
+
next: context,
|
|
39
|
+
consumed: []
|
|
40
|
+
};
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
5
44
|
* Creates a parser that makes another parser optional, allowing it to succeed
|
|
6
45
|
* without consuming input if the wrapped parser fails to match.
|
|
7
46
|
* If the wrapped parser succeeds, this returns its value.
|
|
@@ -23,35 +62,7 @@ function optional(parser) {
|
|
|
23
62
|
}],
|
|
24
63
|
initialState: void 0,
|
|
25
64
|
parse(context) {
|
|
26
|
-
|
|
27
|
-
const result = parser.parse({
|
|
28
|
-
...context,
|
|
29
|
-
state: innerState
|
|
30
|
-
});
|
|
31
|
-
if (result.success) {
|
|
32
|
-
if (result.next.state !== innerState || result.consumed.length === 0) return {
|
|
33
|
-
success: true,
|
|
34
|
-
next: {
|
|
35
|
-
...result.next,
|
|
36
|
-
state: [result.next.state]
|
|
37
|
-
},
|
|
38
|
-
consumed: result.consumed
|
|
39
|
-
};
|
|
40
|
-
return {
|
|
41
|
-
success: true,
|
|
42
|
-
next: {
|
|
43
|
-
...result.next,
|
|
44
|
-
state: context.state
|
|
45
|
-
},
|
|
46
|
-
consumed: result.consumed
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
if (result.consumed === 0) return {
|
|
50
|
-
success: true,
|
|
51
|
-
next: context,
|
|
52
|
-
consumed: []
|
|
53
|
-
};
|
|
54
|
-
return result;
|
|
65
|
+
return parseOptionalStyle(context, parser);
|
|
55
66
|
},
|
|
56
67
|
complete(state) {
|
|
57
68
|
if (typeof state === "undefined") return {
|
|
@@ -121,35 +132,7 @@ function withDefault(parser, defaultValue, options) {
|
|
|
121
132
|
}],
|
|
122
133
|
initialState: void 0,
|
|
123
134
|
parse(context) {
|
|
124
|
-
|
|
125
|
-
const result = parser.parse({
|
|
126
|
-
...context,
|
|
127
|
-
state: innerState
|
|
128
|
-
});
|
|
129
|
-
if (result.success) {
|
|
130
|
-
if (result.next.state !== innerState || result.consumed.length === 0) return {
|
|
131
|
-
success: true,
|
|
132
|
-
next: {
|
|
133
|
-
...result.next,
|
|
134
|
-
state: [result.next.state]
|
|
135
|
-
},
|
|
136
|
-
consumed: result.consumed
|
|
137
|
-
};
|
|
138
|
-
return {
|
|
139
|
-
success: true,
|
|
140
|
-
next: {
|
|
141
|
-
...result.next,
|
|
142
|
-
state: context.state
|
|
143
|
-
},
|
|
144
|
-
consumed: result.consumed
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
if (result.consumed === 0) return {
|
|
148
|
-
success: true,
|
|
149
|
-
next: context,
|
|
150
|
-
consumed: []
|
|
151
|
-
};
|
|
152
|
-
return result;
|
|
135
|
+
return parseOptionalStyle(context, parser);
|
|
153
136
|
},
|
|
154
137
|
complete(state) {
|
|
155
138
|
if (typeof state === "undefined") try {
|
package/dist/parser.cjs
CHANGED
|
@@ -34,7 +34,7 @@ function parse(parser, args) {
|
|
|
34
34
|
};
|
|
35
35
|
const previousBuffer = context.buffer;
|
|
36
36
|
context = result.next;
|
|
37
|
-
if (context.buffer.length > 0 && context.buffer.length === previousBuffer.length && context.buffer
|
|
37
|
+
if (context.buffer.length > 0 && context.buffer.length === previousBuffer.length && context.buffer.every((item, i) => item === previousBuffer[i])) return {
|
|
38
38
|
success: false,
|
|
39
39
|
error: require_message.message`Unexpected option or argument: ${context.buffer[0]}.`
|
|
40
40
|
};
|
|
@@ -90,7 +90,7 @@ function suggest(parser, args) {
|
|
|
90
90
|
if (!result.success) return Array.from(parser.suggest(context, prefix));
|
|
91
91
|
const previousBuffer = context.buffer;
|
|
92
92
|
context = result.next;
|
|
93
|
-
if (context.buffer.length > 0 && context.buffer.length === previousBuffer.length && context.buffer
|
|
93
|
+
if (context.buffer.length > 0 && context.buffer.length === previousBuffer.length && context.buffer.every((item, i) => item === previousBuffer[i])) return [];
|
|
94
94
|
}
|
|
95
95
|
return Array.from(parser.suggest(context, prefix));
|
|
96
96
|
}
|
|
@@ -154,14 +154,18 @@ function getDocPage(parser, args = []) {
|
|
|
154
154
|
const usage = [...require_usage.normalizeUsage(parser.usage)];
|
|
155
155
|
let i = 0;
|
|
156
156
|
for (const arg of args) {
|
|
157
|
+
if (i >= usage.length) break;
|
|
157
158
|
const term = usage[i];
|
|
158
|
-
if (
|
|
159
|
-
const
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
159
|
+
if (term.type === "exclusive") {
|
|
160
|
+
for (const termGroup of term.terms) {
|
|
161
|
+
const firstTerm = termGroup[0];
|
|
162
|
+
if (firstTerm?.type !== "command" || firstTerm.name !== arg) continue;
|
|
163
|
+
usage.splice(i, 1, ...termGroup);
|
|
164
|
+
i += termGroup.length;
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
if (usage[i] === term) i++;
|
|
168
|
+
} else i++;
|
|
165
169
|
}
|
|
166
170
|
return {
|
|
167
171
|
usage,
|
|
@@ -172,6 +176,7 @@ function getDocPage(parser, args = []) {
|
|
|
172
176
|
}
|
|
173
177
|
|
|
174
178
|
//#endregion
|
|
179
|
+
exports.DuplicateOptionError = require_constructs.DuplicateOptionError;
|
|
175
180
|
exports.WithDefaultError = require_modifiers.WithDefaultError;
|
|
176
181
|
exports.argument = require_primitives.argument;
|
|
177
182
|
exports.command = require_primitives.command;
|
package/dist/parser.d.cts
CHANGED
|
@@ -4,7 +4,7 @@ import { DocFragments, DocPage } from "./doc.cjs";
|
|
|
4
4
|
import { ValueParserResult } from "./valueparser.cjs";
|
|
5
5
|
import { MultipleErrorOptions, MultipleOptions, WithDefaultError, WithDefaultOptions, map, multiple, optional, withDefault } from "./modifiers.cjs";
|
|
6
6
|
import { ArgumentErrorOptions, ArgumentOptions, CommandErrorOptions, CommandOptions, FlagErrorOptions, FlagOptions, OptionErrorOptions, OptionOptions, PassThroughFormat, PassThroughOptions, argument, command, constant, flag, option, passThrough } from "./primitives.cjs";
|
|
7
|
-
import { ConditionalErrorOptions, ConditionalOptions, LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, NoMatchContext, ObjectErrorOptions, ObjectOptions, OrErrorOptions, OrOptions, TupleOptions, concat, conditional, group, longestMatch, merge, object, or, tuple } from "./constructs.cjs";
|
|
7
|
+
import { ConditionalErrorOptions, ConditionalOptions, DuplicateOptionError, LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, NoMatchContext, ObjectErrorOptions, ObjectOptions, OrErrorOptions, OrOptions, TupleOptions, concat, conditional, group, longestMatch, merge, object, or, tuple } from "./constructs.cjs";
|
|
8
8
|
|
|
9
9
|
//#region src/parser.d.ts
|
|
10
10
|
|
|
@@ -323,4 +323,4 @@ declare function suggest<T>(parser: Parser<T, unknown>, args: readonly [string,
|
|
|
323
323
|
*/
|
|
324
324
|
declare function getDocPage(parser: Parser<unknown, unknown>, args?: readonly string[]): DocPage | undefined;
|
|
325
325
|
//#endregion
|
|
326
|
-
export { ArgumentErrorOptions, ArgumentOptions, CommandErrorOptions, CommandOptions, ConditionalErrorOptions, ConditionalOptions, DocState, FlagErrorOptions, FlagOptions, InferValue, LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, MultipleErrorOptions, MultipleOptions, NoMatchContext, ObjectErrorOptions, ObjectOptions, OptionErrorOptions, OptionOptions, OrErrorOptions, OrOptions, Parser, ParserContext, ParserResult, PassThroughFormat, PassThroughOptions, Result, Suggestion, TupleOptions, WithDefaultError, WithDefaultOptions, argument, command, concat, conditional, constant, flag, getDocPage, group, longestMatch, map, merge, multiple, object, option, optional, or, parse, passThrough, suggest, tuple, withDefault };
|
|
326
|
+
export { ArgumentErrorOptions, ArgumentOptions, CommandErrorOptions, CommandOptions, ConditionalErrorOptions, ConditionalOptions, DocState, DuplicateOptionError, FlagErrorOptions, FlagOptions, InferValue, LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, MultipleErrorOptions, MultipleOptions, NoMatchContext, ObjectErrorOptions, ObjectOptions, OptionErrorOptions, OptionOptions, OrErrorOptions, OrOptions, Parser, ParserContext, ParserResult, PassThroughFormat, PassThroughOptions, Result, Suggestion, TupleOptions, WithDefaultError, WithDefaultOptions, argument, command, concat, conditional, constant, flag, getDocPage, group, longestMatch, map, merge, multiple, object, option, optional, or, parse, passThrough, suggest, tuple, withDefault };
|
package/dist/parser.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { DocFragments, DocPage } from "./doc.js";
|
|
|
4
4
|
import { ValueParserResult } from "./valueparser.js";
|
|
5
5
|
import { MultipleErrorOptions, MultipleOptions, WithDefaultError, WithDefaultOptions, map, multiple, optional, withDefault } from "./modifiers.js";
|
|
6
6
|
import { ArgumentErrorOptions, ArgumentOptions, CommandErrorOptions, CommandOptions, FlagErrorOptions, FlagOptions, OptionErrorOptions, OptionOptions, PassThroughFormat, PassThroughOptions, argument, command, constant, flag, option, passThrough } from "./primitives.js";
|
|
7
|
-
import { ConditionalErrorOptions, ConditionalOptions, LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, NoMatchContext, ObjectErrorOptions, ObjectOptions, OrErrorOptions, OrOptions, TupleOptions, concat, conditional, group, longestMatch, merge, object, or, tuple } from "./constructs.js";
|
|
7
|
+
import { ConditionalErrorOptions, ConditionalOptions, DuplicateOptionError, LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, NoMatchContext, ObjectErrorOptions, ObjectOptions, OrErrorOptions, OrOptions, TupleOptions, concat, conditional, group, longestMatch, merge, object, or, tuple } from "./constructs.js";
|
|
8
8
|
|
|
9
9
|
//#region src/parser.d.ts
|
|
10
10
|
|
|
@@ -323,4 +323,4 @@ declare function suggest<T>(parser: Parser<T, unknown>, args: readonly [string,
|
|
|
323
323
|
*/
|
|
324
324
|
declare function getDocPage(parser: Parser<unknown, unknown>, args?: readonly string[]): DocPage | undefined;
|
|
325
325
|
//#endregion
|
|
326
|
-
export { ArgumentErrorOptions, ArgumentOptions, CommandErrorOptions, CommandOptions, ConditionalErrorOptions, ConditionalOptions, DocState, FlagErrorOptions, FlagOptions, InferValue, LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, MultipleErrorOptions, MultipleOptions, NoMatchContext, ObjectErrorOptions, ObjectOptions, OptionErrorOptions, OptionOptions, OrErrorOptions, OrOptions, Parser, ParserContext, ParserResult, PassThroughFormat, PassThroughOptions, Result, Suggestion, TupleOptions, WithDefaultError, WithDefaultOptions, argument, command, concat, conditional, constant, flag, getDocPage, group, longestMatch, map, merge, multiple, object, option, optional, or, parse, passThrough, suggest, tuple, withDefault };
|
|
326
|
+
export { ArgumentErrorOptions, ArgumentOptions, CommandErrorOptions, CommandOptions, ConditionalErrorOptions, ConditionalOptions, DocState, DuplicateOptionError, FlagErrorOptions, FlagOptions, InferValue, LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, MultipleErrorOptions, MultipleOptions, NoMatchContext, ObjectErrorOptions, ObjectOptions, OptionErrorOptions, OptionOptions, OrErrorOptions, OrOptions, Parser, ParserContext, ParserResult, PassThroughFormat, PassThroughOptions, Result, Suggestion, TupleOptions, WithDefaultError, WithDefaultOptions, argument, command, concat, conditional, constant, flag, getDocPage, group, longestMatch, map, merge, multiple, object, option, optional, or, parse, passThrough, suggest, tuple, withDefault };
|
package/dist/parser.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { message } from "./message.js";
|
|
2
2
|
import { normalizeUsage } from "./usage.js";
|
|
3
|
-
import { concat, conditional, group, longestMatch, merge, object, or, tuple } from "./constructs.js";
|
|
3
|
+
import { DuplicateOptionError, concat, conditional, group, longestMatch, merge, object, or, tuple } from "./constructs.js";
|
|
4
4
|
import { WithDefaultError, map, multiple, optional, withDefault } from "./modifiers.js";
|
|
5
5
|
import { argument, command, constant, flag, option, passThrough } from "./primitives.js";
|
|
6
6
|
|
|
@@ -34,7 +34,7 @@ function parse(parser, args) {
|
|
|
34
34
|
};
|
|
35
35
|
const previousBuffer = context.buffer;
|
|
36
36
|
context = result.next;
|
|
37
|
-
if (context.buffer.length > 0 && context.buffer.length === previousBuffer.length && context.buffer
|
|
37
|
+
if (context.buffer.length > 0 && context.buffer.length === previousBuffer.length && context.buffer.every((item, i) => item === previousBuffer[i])) return {
|
|
38
38
|
success: false,
|
|
39
39
|
error: message`Unexpected option or argument: ${context.buffer[0]}.`
|
|
40
40
|
};
|
|
@@ -90,7 +90,7 @@ function suggest(parser, args) {
|
|
|
90
90
|
if (!result.success) return Array.from(parser.suggest(context, prefix));
|
|
91
91
|
const previousBuffer = context.buffer;
|
|
92
92
|
context = result.next;
|
|
93
|
-
if (context.buffer.length > 0 && context.buffer.length === previousBuffer.length && context.buffer
|
|
93
|
+
if (context.buffer.length > 0 && context.buffer.length === previousBuffer.length && context.buffer.every((item, i) => item === previousBuffer[i])) return [];
|
|
94
94
|
}
|
|
95
95
|
return Array.from(parser.suggest(context, prefix));
|
|
96
96
|
}
|
|
@@ -154,14 +154,18 @@ function getDocPage(parser, args = []) {
|
|
|
154
154
|
const usage = [...normalizeUsage(parser.usage)];
|
|
155
155
|
let i = 0;
|
|
156
156
|
for (const arg of args) {
|
|
157
|
+
if (i >= usage.length) break;
|
|
157
158
|
const term = usage[i];
|
|
158
|
-
if (
|
|
159
|
-
const
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
159
|
+
if (term.type === "exclusive") {
|
|
160
|
+
for (const termGroup of term.terms) {
|
|
161
|
+
const firstTerm = termGroup[0];
|
|
162
|
+
if (firstTerm?.type !== "command" || firstTerm.name !== arg) continue;
|
|
163
|
+
usage.splice(i, 1, ...termGroup);
|
|
164
|
+
i += termGroup.length;
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
if (usage[i] === term) i++;
|
|
168
|
+
} else i++;
|
|
165
169
|
}
|
|
166
170
|
return {
|
|
167
171
|
usage,
|
|
@@ -172,4 +176,4 @@ function getDocPage(parser, args = []) {
|
|
|
172
176
|
}
|
|
173
177
|
|
|
174
178
|
//#endregion
|
|
175
|
-
export { WithDefaultError, argument, command, concat, conditional, constant, flag, getDocPage, group, longestMatch, map, merge, multiple, object, option, optional, or, parse, passThrough, suggest, tuple, withDefault };
|
|
179
|
+
export { DuplicateOptionError, WithDefaultError, argument, command, concat, conditional, constant, flag, getDocPage, group, longestMatch, map, merge, multiple, object, option, optional, or, parse, passThrough, suggest, tuple, withDefault };
|
package/dist/suggestion.cjs
CHANGED
|
@@ -179,8 +179,58 @@ function createErrorWithSuggestions(baseError, invalidInput, usage, type = "both
|
|
|
179
179
|
...suggestionMsg
|
|
180
180
|
] : baseError;
|
|
181
181
|
}
|
|
182
|
+
/**
|
|
183
|
+
* Creates a unique key for a suggestion to enable deduplication.
|
|
184
|
+
*
|
|
185
|
+
* For literal suggestions, the text itself is used as the key.
|
|
186
|
+
* For file suggestions, a composite key is created from the type,
|
|
187
|
+
* extensions, and pattern.
|
|
188
|
+
*
|
|
189
|
+
* @param suggestion The suggestion to create a key for
|
|
190
|
+
* @returns A string key that uniquely identifies this suggestion
|
|
191
|
+
* @internal
|
|
192
|
+
*/
|
|
193
|
+
function getSuggestionKey(suggestion) {
|
|
194
|
+
if (suggestion.kind === "literal") return suggestion.text;
|
|
195
|
+
return `__FILE__:${suggestion.type}:${suggestion.extensions?.join(",") ?? ""}:${suggestion.pattern ?? ""}`;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Removes duplicate suggestions from an array while preserving order.
|
|
199
|
+
*
|
|
200
|
+
* Suggestions are considered duplicates if they have the same key:
|
|
201
|
+
* - Literal suggestions: same text
|
|
202
|
+
* - File suggestions: same type, extensions, and pattern
|
|
203
|
+
*
|
|
204
|
+
* The first occurrence of each unique suggestion is kept.
|
|
205
|
+
*
|
|
206
|
+
* @param suggestions Array of suggestions that may contain duplicates
|
|
207
|
+
* @returns A new array with duplicates removed, preserving order of first occurrences
|
|
208
|
+
*
|
|
209
|
+
* @example
|
|
210
|
+
* ```typescript
|
|
211
|
+
* const suggestions = [
|
|
212
|
+
* { kind: "literal", text: "--verbose" },
|
|
213
|
+
* { kind: "literal", text: "--help" },
|
|
214
|
+
* { kind: "literal", text: "--verbose" }, // duplicate
|
|
215
|
+
* ];
|
|
216
|
+
* deduplicateSuggestions(suggestions);
|
|
217
|
+
* // returns [{ kind: "literal", text: "--verbose" }, { kind: "literal", text: "--help" }]
|
|
218
|
+
* ```
|
|
219
|
+
*
|
|
220
|
+
* @since 0.9.0
|
|
221
|
+
*/
|
|
222
|
+
function deduplicateSuggestions(suggestions) {
|
|
223
|
+
const seen = /* @__PURE__ */ new Set();
|
|
224
|
+
return suggestions.filter((suggestion) => {
|
|
225
|
+
const key = getSuggestionKey(suggestion);
|
|
226
|
+
if (seen.has(key)) return false;
|
|
227
|
+
seen.add(key);
|
|
228
|
+
return true;
|
|
229
|
+
});
|
|
230
|
+
}
|
|
182
231
|
|
|
183
232
|
//#endregion
|
|
184
233
|
exports.DEFAULT_FIND_SIMILAR_OPTIONS = DEFAULT_FIND_SIMILAR_OPTIONS;
|
|
185
234
|
exports.createErrorWithSuggestions = createErrorWithSuggestions;
|
|
235
|
+
exports.deduplicateSuggestions = deduplicateSuggestions;
|
|
186
236
|
exports.findSimilar = findSimilar;
|
package/dist/suggestion.js
CHANGED
|
@@ -179,6 +179,55 @@ function createErrorWithSuggestions(baseError, invalidInput, usage, type = "both
|
|
|
179
179
|
...suggestionMsg
|
|
180
180
|
] : baseError;
|
|
181
181
|
}
|
|
182
|
+
/**
|
|
183
|
+
* Creates a unique key for a suggestion to enable deduplication.
|
|
184
|
+
*
|
|
185
|
+
* For literal suggestions, the text itself is used as the key.
|
|
186
|
+
* For file suggestions, a composite key is created from the type,
|
|
187
|
+
* extensions, and pattern.
|
|
188
|
+
*
|
|
189
|
+
* @param suggestion The suggestion to create a key for
|
|
190
|
+
* @returns A string key that uniquely identifies this suggestion
|
|
191
|
+
* @internal
|
|
192
|
+
*/
|
|
193
|
+
function getSuggestionKey(suggestion) {
|
|
194
|
+
if (suggestion.kind === "literal") return suggestion.text;
|
|
195
|
+
return `__FILE__:${suggestion.type}:${suggestion.extensions?.join(",") ?? ""}:${suggestion.pattern ?? ""}`;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Removes duplicate suggestions from an array while preserving order.
|
|
199
|
+
*
|
|
200
|
+
* Suggestions are considered duplicates if they have the same key:
|
|
201
|
+
* - Literal suggestions: same text
|
|
202
|
+
* - File suggestions: same type, extensions, and pattern
|
|
203
|
+
*
|
|
204
|
+
* The first occurrence of each unique suggestion is kept.
|
|
205
|
+
*
|
|
206
|
+
* @param suggestions Array of suggestions that may contain duplicates
|
|
207
|
+
* @returns A new array with duplicates removed, preserving order of first occurrences
|
|
208
|
+
*
|
|
209
|
+
* @example
|
|
210
|
+
* ```typescript
|
|
211
|
+
* const suggestions = [
|
|
212
|
+
* { kind: "literal", text: "--verbose" },
|
|
213
|
+
* { kind: "literal", text: "--help" },
|
|
214
|
+
* { kind: "literal", text: "--verbose" }, // duplicate
|
|
215
|
+
* ];
|
|
216
|
+
* deduplicateSuggestions(suggestions);
|
|
217
|
+
* // returns [{ kind: "literal", text: "--verbose" }, { kind: "literal", text: "--help" }]
|
|
218
|
+
* ```
|
|
219
|
+
*
|
|
220
|
+
* @since 0.9.0
|
|
221
|
+
*/
|
|
222
|
+
function deduplicateSuggestions(suggestions) {
|
|
223
|
+
const seen = /* @__PURE__ */ new Set();
|
|
224
|
+
return suggestions.filter((suggestion) => {
|
|
225
|
+
const key = getSuggestionKey(suggestion);
|
|
226
|
+
if (seen.has(key)) return false;
|
|
227
|
+
seen.add(key);
|
|
228
|
+
return true;
|
|
229
|
+
});
|
|
230
|
+
}
|
|
182
231
|
|
|
183
232
|
//#endregion
|
|
184
|
-
export { DEFAULT_FIND_SIMILAR_OPTIONS, createErrorWithSuggestions, findSimilar };
|
|
233
|
+
export { DEFAULT_FIND_SIMILAR_OPTIONS, createErrorWithSuggestions, deduplicateSuggestions, findSimilar };
|
package/dist/valueparser.cjs
CHANGED
|
@@ -153,7 +153,7 @@ function integer(options) {
|
|
|
153
153
|
return {
|
|
154
154
|
metavar: options?.metavar ?? "INTEGER",
|
|
155
155
|
parse(input) {
|
|
156
|
-
if (!input.match(
|
|
156
|
+
if (!input.match(/^-?\d+$/)) return {
|
|
157
157
|
success: false,
|
|
158
158
|
error: options?.errors?.invalidInteger ? typeof options.errors.invalidInteger === "function" ? options.errors.invalidInteger(input) : options.errors.invalidInteger : require_message.message`Expected a valid integer, but got ${input}.`
|
|
159
159
|
};
|
package/dist/valueparser.js
CHANGED
|
@@ -153,7 +153,7 @@ function integer(options) {
|
|
|
153
153
|
return {
|
|
154
154
|
metavar: options?.metavar ?? "INTEGER",
|
|
155
155
|
parse(input) {
|
|
156
|
-
if (!input.match(
|
|
156
|
+
if (!input.match(/^-?\d+$/)) return {
|
|
157
157
|
success: false,
|
|
158
158
|
error: options?.errors?.invalidInteger ? typeof options.errors.invalidInteger === "function" ? options.errors.invalidInteger(input) : options.errors.invalidInteger : message`Expected a valid integer, but got ${input}.`
|
|
159
159
|
};
|