@optique/core 1.1.0-dev.1998 → 1.1.0-dev.2053

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.
@@ -260,7 +260,7 @@ function* suggestOptionSync(optionNames$1, valueParser, hidden, context, prefix)
260
260
  }
261
261
  } else {
262
262
  const expectingValue = context.buffer.length > 0 && optionNames$1.includes(context.buffer[context.buffer.length - 1]);
263
- if (!expectingValue && (prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/"))) {
263
+ if (!expectingValue && (prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/") || prefix.startsWith("+"))) {
264
264
  for (const optionName$1 of optionNames$1) if (optionName$1.startsWith(prefix)) {
265
265
  if (prefix === "-" && optionName$1.length !== 2) continue;
266
266
  yield {
@@ -274,7 +274,7 @@ function* suggestOptionSync(optionNames$1, valueParser, hidden, context, prefix)
274
274
  if (context.buffer.length > 0) {
275
275
  const lastToken = context.buffer[context.buffer.length - 1];
276
276
  if (optionNames$1.includes(lastToken)) shouldSuggestValues = true;
277
- } else if (require_annotation_state.isAnnotationWrappedInitialState(context.state) && context.buffer.length === 0 && (context.exec?.path?.length ?? 0) === 0 && !(prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/"))) shouldSuggestValues = true;
277
+ } else if (require_annotation_state.isAnnotationWrappedInitialState(context.state) && context.buffer.length === 0 && (context.exec?.path?.length ?? 0) === 0 && !(prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/") || prefix.startsWith("+"))) shouldSuggestValues = true;
278
278
  if (shouldSuggestValues) yield* getSuggestionsWithDependency(valueParser, prefix, context.dependencyRegistry, context.exec);
279
279
  }
280
280
  }
@@ -344,7 +344,7 @@ async function* suggestOptionAsync(optionNames$1, valueParser, hidden, context,
344
344
  }
345
345
  } else {
346
346
  const expectingValue = context.buffer.length > 0 && optionNames$1.includes(context.buffer[context.buffer.length - 1]);
347
- if (!expectingValue && (prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/"))) {
347
+ if (!expectingValue && (prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/") || prefix.startsWith("+"))) {
348
348
  for (const optionName$1 of optionNames$1) if (optionName$1.startsWith(prefix)) {
349
349
  if (prefix === "-" && optionName$1.length !== 2) continue;
350
350
  yield {
@@ -358,7 +358,7 @@ async function* suggestOptionAsync(optionNames$1, valueParser, hidden, context,
358
358
  if (context.buffer.length > 0) {
359
359
  const lastToken = context.buffer[context.buffer.length - 1];
360
360
  if (optionNames$1.includes(lastToken)) shouldSuggestValues = true;
361
- } else if (require_annotation_state.isAnnotationWrappedInitialState(context.state) && context.buffer.length === 0 && (context.exec?.path?.length ?? 0) === 0 && !(prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/"))) shouldSuggestValues = true;
361
+ } else if (require_annotation_state.isAnnotationWrappedInitialState(context.state) && context.buffer.length === 0 && (context.exec?.path?.length ?? 0) === 0 && !(prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/") || prefix.startsWith("+"))) shouldSuggestValues = true;
362
362
  if (shouldSuggestValues) for await (const suggestion of getSuggestionsWithDependencyAsync(valueParser, prefix, context.dependencyRegistry, context.exec)) yield suggestion;
363
363
  }
364
364
  }
@@ -888,7 +888,7 @@ function flag(...args) {
888
888
  suggest(_context, prefix) {
889
889
  if (require_usage.isSuggestionHidden(options.hidden)) return [];
890
890
  const suggestions = [];
891
- if (prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/")) {
891
+ if (prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/") || prefix.startsWith("+")) {
892
892
  for (const optionName$1 of optionNames$1) if (optionName$1.startsWith(prefix)) {
893
893
  if (prefix === "-" && optionName$1.length !== 2) continue;
894
894
  suggestions.push({
@@ -929,6 +929,221 @@ function flag(...args) {
929
929
  });
930
930
  return result;
931
931
  }
932
+ function normalizeNegatableFlagNameList(names) {
933
+ return typeof names === "string" ? [names] : names;
934
+ }
935
+ function validateNoDuplicateOptionNames(names, label) {
936
+ const seen = /* @__PURE__ */ new Set();
937
+ for (const name of names) {
938
+ if (seen.has(name)) throw new TypeError(`${label} has a duplicate name: "${name}".`);
939
+ seen.add(name);
940
+ }
941
+ }
942
+ function validateNoNegatableFlagNameCollision(positiveNames, negativeNames) {
943
+ const positiveSet = new Set(positiveNames);
944
+ for (const name of negativeNames) if (positiveSet.has(name)) throw new TypeError(`Negatable flag name is both positive and negative: "${name}".`);
945
+ }
946
+ function formatNegatableFlagDuplicateError(options, token) {
947
+ return options.errors?.duplicate ? typeof options.errors.duplicate === "function" ? options.errors.duplicate(token) : options.errors.duplicate : require_message.message`${require_message.optionName(token)} cannot be used multiple times.`;
948
+ }
949
+ function formatNegatableFlagConflictError(options, previousToken, token) {
950
+ return options.errors?.conflict ? typeof options.errors.conflict === "function" ? options.errors.conflict(previousToken, token) : options.errors.conflict : require_message.message`${require_message.optionName(previousToken)} and ${require_message.optionName(token)} cannot be used together.`;
951
+ }
952
+ function formatNegatableFlagUnexpectedValueError(options, optionName$1, value) {
953
+ return options.errors?.unexpectedValue ? typeof options.errors.unexpectedValue === "function" ? options.errors.unexpectedValue(optionName$1, value) : options.errors.unexpectedValue : require_message.message`Flag ${require_message.optionName(optionName$1)} does not accept a value, but got: ${value}.`;
954
+ }
955
+ function parseMatchedNegatableFlag(context, token, value, consumed, consumedOnFailure, buffer, options) {
956
+ if (context.state != null) return {
957
+ success: false,
958
+ consumed: consumedOnFailure,
959
+ error: context.state.value === value ? formatNegatableFlagDuplicateError(options, token) : formatNegatableFlagConflictError(options, context.state.token, token)
960
+ };
961
+ return {
962
+ success: true,
963
+ next: {
964
+ ...context,
965
+ state: {
966
+ value,
967
+ token
968
+ },
969
+ buffer
970
+ },
971
+ consumed
972
+ };
973
+ }
974
+ /**
975
+ * Creates a parser for a pair of command-line flags that explicitly enable or
976
+ * disable a Boolean value.
977
+ *
978
+ * The positive names produce `true`; the negative names produce `false`.
979
+ * Unlike {@link option}, this parser fails when neither side is present,
980
+ * matching {@link flag} semantics. Wrap it in {@link optional} for a
981
+ * tri-state override or {@link withDefault} for a concrete fallback.
982
+ *
983
+ * @param names The positive and negative option names to parse.
984
+ * @param options Optional metadata and error customization.
985
+ * @returns A {@link Parser} that produces `true` for positive names and
986
+ * `false` for negative names.
987
+ * @throws {TypeError} If any option name is invalid, duplicated within one
988
+ * side, or shared by the positive and negative sides.
989
+ * @since 1.1.0
990
+ */
991
+ function negatableFlag(names, options = {}) {
992
+ const positiveNames = normalizeNegatableFlagNameList(names.positive);
993
+ const negativeNames = normalizeNegatableFlagNameList(names.negative);
994
+ require_validate.validateOptionNames(positiveNames, "Positive flag");
995
+ require_validate.validateOptionNames(negativeNames, "Negative flag");
996
+ validateNoDuplicateOptionNames(positiveNames, "Positive flag");
997
+ validateNoDuplicateOptionNames(negativeNames, "Negative flag");
998
+ validateNoNegatableFlagNameCollision(positiveNames, negativeNames);
999
+ const optionNames$1 = [...positiveNames, ...negativeNames];
1000
+ const valueByName = /* @__PURE__ */ new Map();
1001
+ for (const name of positiveNames) valueByName.set(name, true);
1002
+ for (const name of negativeNames) valueByName.set(name, false);
1003
+ const result = {
1004
+ $valueType: [],
1005
+ $stateType: [],
1006
+ mode: "sync",
1007
+ priority: 10,
1008
+ usage: [{
1009
+ type: "option",
1010
+ names: optionNames$1,
1011
+ ...options.hidden != null && { hidden: options.hidden }
1012
+ }],
1013
+ leadingNames: new Set(optionNames$1),
1014
+ acceptingAnyToken: false,
1015
+ initialState: void 0,
1016
+ parse(context) {
1017
+ if (context.optionsTerminated) return {
1018
+ success: false,
1019
+ consumed: 0,
1020
+ error: options.errors?.optionsTerminated ?? require_message.message`No more options can be parsed.`
1021
+ };
1022
+ else if (context.buffer.length < 1) return {
1023
+ success: false,
1024
+ consumed: 0,
1025
+ error: options.errors?.endOfInput ?? require_message.message`Expected an option, but got end of input.`
1026
+ };
1027
+ if (context.buffer[0] === "--") return {
1028
+ success: true,
1029
+ next: {
1030
+ ...context,
1031
+ buffer: context.buffer.slice(1),
1032
+ state: context.state,
1033
+ optionsTerminated: true
1034
+ },
1035
+ consumed: context.buffer.slice(0, 1)
1036
+ };
1037
+ const directValue = valueByName.get(context.buffer[0]);
1038
+ if (directValue != null) return parseMatchedNegatableFlag(context, context.buffer[0], directValue, context.buffer.slice(0, 1), 1, context.buffer.slice(1), options);
1039
+ for (const name of optionNames$1) {
1040
+ if (!name.startsWith("--") && !name.startsWith("/") && !name.startsWith("+") && !(name.startsWith("-") && name.length > 2)) continue;
1041
+ const prefix = name.startsWith("/") ? `${name}:` : `${name}=`;
1042
+ if (context.buffer[0].startsWith(prefix)) {
1043
+ const value = context.buffer[0].slice(prefix.length);
1044
+ return {
1045
+ success: false,
1046
+ consumed: 1,
1047
+ error: formatNegatableFlagUnexpectedValueError(options, prefix.slice(0, -1), value)
1048
+ };
1049
+ }
1050
+ }
1051
+ for (const shortOption of optionNames$1) {
1052
+ if (!shortOption.match(/^-[^-]$/)) continue;
1053
+ if (!context.buffer[0].startsWith(shortOption)) continue;
1054
+ return parseMatchedNegatableFlag(context, shortOption, valueByName.get(shortOption), [context.buffer[0].slice(0, 2)], 1, [`-${context.buffer[0].slice(2)}`, ...context.buffer.slice(1)], options);
1055
+ }
1056
+ const invalidOption = context.buffer[0];
1057
+ if (options.errors?.noMatch) {
1058
+ const candidates = /* @__PURE__ */ new Set();
1059
+ for (const name of require_usage.extractOptionNames(context.usage)) candidates.add(name);
1060
+ const suggestions = require_suggestion.findSimilar(invalidOption, candidates, require_suggestion.DEFAULT_FIND_SIMILAR_OPTIONS);
1061
+ return {
1062
+ success: false,
1063
+ consumed: 0,
1064
+ error: typeof options.errors.noMatch === "function" ? options.errors.noMatch(invalidOption, suggestions) : options.errors.noMatch
1065
+ };
1066
+ }
1067
+ const baseError = require_message.message`No matched option for ${require_message.optionName(invalidOption)}.`;
1068
+ return {
1069
+ success: false,
1070
+ consumed: 0,
1071
+ error: require_suggestion.createErrorWithSuggestions(baseError, invalidOption, context.usage, "option")
1072
+ };
1073
+ },
1074
+ complete(state, _exec) {
1075
+ if (state == null) return {
1076
+ success: false,
1077
+ error: options.errors?.missing ? typeof options.errors.missing === "function" ? options.errors.missing(positiveNames, negativeNames) : options.errors.missing : require_message.message`Required flag ${require_message.optionNames(optionNames$1)} is missing.`
1078
+ };
1079
+ return {
1080
+ success: true,
1081
+ value: state.value
1082
+ };
1083
+ },
1084
+ suggest(_context, prefix) {
1085
+ if (require_usage.isSuggestionHidden(options.hidden)) return [];
1086
+ const suggestions = [];
1087
+ if (prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/") || prefix.startsWith("+")) {
1088
+ for (const optionName$1 of optionNames$1) if (optionName$1.startsWith(prefix)) {
1089
+ if (prefix === "-" && optionName$1.length !== 2) continue;
1090
+ suggestions.push({
1091
+ kind: "literal",
1092
+ text: optionName$1
1093
+ });
1094
+ }
1095
+ }
1096
+ return suggestions;
1097
+ },
1098
+ getDocFragments(_state, _defaultValue) {
1099
+ if (require_usage.isDocHidden(options.hidden)) return {
1100
+ fragments: [],
1101
+ description: options.description
1102
+ };
1103
+ const fragments = [{
1104
+ type: "entry",
1105
+ term: {
1106
+ type: "option",
1107
+ names: optionNames$1
1108
+ },
1109
+ description: options.description
1110
+ }];
1111
+ return {
1112
+ fragments,
1113
+ description: options.description
1114
+ };
1115
+ },
1116
+ [Symbol.for("Deno.customInspect")]() {
1117
+ const args = [`positive: ${JSON.stringify(positiveNames)}`, `negative: ${JSON.stringify(negativeNames)}`];
1118
+ return `negatableFlag({ ${args.join(", ")} })`;
1119
+ }
1120
+ };
1121
+ Object.defineProperty(result, "validateValue", {
1122
+ value(v) {
1123
+ if (typeof v !== "boolean") {
1124
+ const actualType = v === null ? "null" : typeof v;
1125
+ return {
1126
+ success: false,
1127
+ error: require_message.message`${require_message.optionNames(optionNames$1)}: Expected a boolean value, but received ${actualType}.`
1128
+ };
1129
+ }
1130
+ return {
1131
+ success: true,
1132
+ value: v
1133
+ };
1134
+ },
1135
+ configurable: true,
1136
+ enumerable: false,
1137
+ writable: false
1138
+ });
1139
+ Object.defineProperty(result, "placeholder", {
1140
+ value: false,
1141
+ configurable: true,
1142
+ enumerable: false,
1143
+ writable: false
1144
+ });
1145
+ return result;
1146
+ }
932
1147
  /**
933
1148
  * Creates a parser that expects a single argument value.
934
1149
  * This parser is typically used for positional arguments
@@ -1606,5 +1821,6 @@ exports.command = command;
1606
1821
  exports.constant = constant;
1607
1822
  exports.fail = fail;
1608
1823
  exports.flag = flag;
1824
+ exports.negatableFlag = negatableFlag;
1609
1825
  exports.option = option;
1610
1826
  exports.passThrough = passThrough;
@@ -237,6 +237,110 @@ interface FlagErrorOptions {
237
237
  * ```
238
238
  */
239
239
  declare function flag(...args: readonly [OptionName, ...readonly OptionName[], FlagOptions] | readonly [OptionName, ...readonly OptionName[]]): Parser<"sync", true, ValueParserResult<true> | undefined>;
240
+ /**
241
+ * A non-empty list of option names, or a single option name.
242
+ * @since 1.1.0
243
+ */
244
+ type NegatableFlagNameList = OptionName | readonly [OptionName, ...readonly OptionName[]];
245
+ /**
246
+ * Option names for the {@link negatableFlag} parser.
247
+ * @since 1.1.0
248
+ */
249
+ interface NegatableFlagNames {
250
+ /**
251
+ * Option names that produce `true`.
252
+ */
253
+ readonly positive: NegatableFlagNameList;
254
+ /**
255
+ * Option names that produce `false`.
256
+ */
257
+ readonly negative: NegatableFlagNameList;
258
+ }
259
+ /**
260
+ * Options for the {@link negatableFlag} parser.
261
+ * @since 1.1.0
262
+ */
263
+ interface NegatableFlagOptions {
264
+ /**
265
+ * The description of the flag pair, which can be used for help messages.
266
+ */
267
+ readonly description?: Message;
268
+ /**
269
+ * Controls flag visibility:
270
+ *
271
+ * - `true`: hide from usage, docs, and suggestions
272
+ * - `"usage"`: hide from usage only
273
+ * - `"doc"`: hide from docs only
274
+ * - `"help"`: hide from usage and docs, keep suggestions
275
+ */
276
+ readonly hidden?: HiddenVisibility;
277
+ /**
278
+ * Error message customization options.
279
+ */
280
+ readonly errors?: NegatableFlagErrorOptions;
281
+ }
282
+ /**
283
+ * Options for customizing error messages in the {@link negatableFlag} parser.
284
+ * @since 1.1.0
285
+ */
286
+ interface NegatableFlagErrorOptions {
287
+ /**
288
+ * Custom error message when neither flag is provided.
289
+ * Can be a static message or a function that receives the positive and
290
+ * negative option names.
291
+ */
292
+ readonly missing?: Message | ((positiveNames: readonly string[], negativeNames: readonly string[]) => Message);
293
+ /**
294
+ * Custom error message when options are terminated (after --).
295
+ */
296
+ readonly optionsTerminated?: Message;
297
+ /**
298
+ * Custom error message when input is empty but a flag is expected.
299
+ */
300
+ readonly endOfInput?: Message;
301
+ /**
302
+ * Custom error message when the same polarity is used multiple times.
303
+ */
304
+ readonly duplicate?: Message | ((token: string) => Message);
305
+ /**
306
+ * Custom error message when both positive and negative flags are used.
307
+ */
308
+ readonly conflict?: Message | ((previousToken: string, token: string) => Message);
309
+ /**
310
+ * Custom error message when a flag receives an unexpected value.
311
+ */
312
+ readonly unexpectedValue?: Message | ((optionName: string, value: string) => Message);
313
+ /**
314
+ * Custom error message when no matching flag is found.
315
+ */
316
+ readonly noMatch?: Message | ((invalidOption: string, suggestions: readonly string[]) => Message);
317
+ }
318
+ /**
319
+ * State stored by the {@link negatableFlag} parser.
320
+ * @since 1.1.0
321
+ */
322
+ interface NegatableFlagState {
323
+ readonly value: boolean;
324
+ readonly token: string;
325
+ }
326
+ /**
327
+ * Creates a parser for a pair of command-line flags that explicitly enable or
328
+ * disable a Boolean value.
329
+ *
330
+ * The positive names produce `true`; the negative names produce `false`.
331
+ * Unlike {@link option}, this parser fails when neither side is present,
332
+ * matching {@link flag} semantics. Wrap it in {@link optional} for a
333
+ * tri-state override or {@link withDefault} for a concrete fallback.
334
+ *
335
+ * @param names The positive and negative option names to parse.
336
+ * @param options Optional metadata and error customization.
337
+ * @returns A {@link Parser} that produces `true` for positive names and
338
+ * `false` for negative names.
339
+ * @throws {TypeError} If any option name is invalid, duplicated within one
340
+ * side, or shared by the positive and negative sides.
341
+ * @since 1.1.0
342
+ */
343
+ declare function negatableFlag(names: NegatableFlagNames, options?: NegatableFlagOptions): Parser<"sync", boolean, NegatableFlagState | undefined>;
240
344
  /**
241
345
  * Options for the {@link argument} parser.
242
346
  */
@@ -483,4 +587,4 @@ interface PassThroughOptions {
483
587
  */
484
588
  declare function passThrough(options?: PassThroughOptions): Parser<"sync", readonly string[], readonly string[]>;
485
589
  //#endregion
486
- export { ArgumentErrorOptions, ArgumentOptions, CommandErrorOptions, CommandOptions, FlagErrorOptions, FlagOptions, OptionErrorOptions, OptionOptions, OptionState, PassThroughFormat, PassThroughOptions, argument, command, constant, fail, flag, option, passThrough };
590
+ export { ArgumentErrorOptions, ArgumentOptions, CommandErrorOptions, CommandOptions, FlagErrorOptions, FlagOptions, NegatableFlagErrorOptions, NegatableFlagNameList, NegatableFlagNames, NegatableFlagOptions, NegatableFlagState, OptionErrorOptions, OptionOptions, OptionState, PassThroughFormat, PassThroughOptions, argument, command, constant, fail, flag, negatableFlag, option, passThrough };
@@ -237,6 +237,110 @@ interface FlagErrorOptions {
237
237
  * ```
238
238
  */
239
239
  declare function flag(...args: readonly [OptionName, ...readonly OptionName[], FlagOptions] | readonly [OptionName, ...readonly OptionName[]]): Parser<"sync", true, ValueParserResult<true> | undefined>;
240
+ /**
241
+ * A non-empty list of option names, or a single option name.
242
+ * @since 1.1.0
243
+ */
244
+ type NegatableFlagNameList = OptionName | readonly [OptionName, ...readonly OptionName[]];
245
+ /**
246
+ * Option names for the {@link negatableFlag} parser.
247
+ * @since 1.1.0
248
+ */
249
+ interface NegatableFlagNames {
250
+ /**
251
+ * Option names that produce `true`.
252
+ */
253
+ readonly positive: NegatableFlagNameList;
254
+ /**
255
+ * Option names that produce `false`.
256
+ */
257
+ readonly negative: NegatableFlagNameList;
258
+ }
259
+ /**
260
+ * Options for the {@link negatableFlag} parser.
261
+ * @since 1.1.0
262
+ */
263
+ interface NegatableFlagOptions {
264
+ /**
265
+ * The description of the flag pair, which can be used for help messages.
266
+ */
267
+ readonly description?: Message;
268
+ /**
269
+ * Controls flag visibility:
270
+ *
271
+ * - `true`: hide from usage, docs, and suggestions
272
+ * - `"usage"`: hide from usage only
273
+ * - `"doc"`: hide from docs only
274
+ * - `"help"`: hide from usage and docs, keep suggestions
275
+ */
276
+ readonly hidden?: HiddenVisibility;
277
+ /**
278
+ * Error message customization options.
279
+ */
280
+ readonly errors?: NegatableFlagErrorOptions;
281
+ }
282
+ /**
283
+ * Options for customizing error messages in the {@link negatableFlag} parser.
284
+ * @since 1.1.0
285
+ */
286
+ interface NegatableFlagErrorOptions {
287
+ /**
288
+ * Custom error message when neither flag is provided.
289
+ * Can be a static message or a function that receives the positive and
290
+ * negative option names.
291
+ */
292
+ readonly missing?: Message | ((positiveNames: readonly string[], negativeNames: readonly string[]) => Message);
293
+ /**
294
+ * Custom error message when options are terminated (after --).
295
+ */
296
+ readonly optionsTerminated?: Message;
297
+ /**
298
+ * Custom error message when input is empty but a flag is expected.
299
+ */
300
+ readonly endOfInput?: Message;
301
+ /**
302
+ * Custom error message when the same polarity is used multiple times.
303
+ */
304
+ readonly duplicate?: Message | ((token: string) => Message);
305
+ /**
306
+ * Custom error message when both positive and negative flags are used.
307
+ */
308
+ readonly conflict?: Message | ((previousToken: string, token: string) => Message);
309
+ /**
310
+ * Custom error message when a flag receives an unexpected value.
311
+ */
312
+ readonly unexpectedValue?: Message | ((optionName: string, value: string) => Message);
313
+ /**
314
+ * Custom error message when no matching flag is found.
315
+ */
316
+ readonly noMatch?: Message | ((invalidOption: string, suggestions: readonly string[]) => Message);
317
+ }
318
+ /**
319
+ * State stored by the {@link negatableFlag} parser.
320
+ * @since 1.1.0
321
+ */
322
+ interface NegatableFlagState {
323
+ readonly value: boolean;
324
+ readonly token: string;
325
+ }
326
+ /**
327
+ * Creates a parser for a pair of command-line flags that explicitly enable or
328
+ * disable a Boolean value.
329
+ *
330
+ * The positive names produce `true`; the negative names produce `false`.
331
+ * Unlike {@link option}, this parser fails when neither side is present,
332
+ * matching {@link flag} semantics. Wrap it in {@link optional} for a
333
+ * tri-state override or {@link withDefault} for a concrete fallback.
334
+ *
335
+ * @param names The positive and negative option names to parse.
336
+ * @param options Optional metadata and error customization.
337
+ * @returns A {@link Parser} that produces `true` for positive names and
338
+ * `false` for negative names.
339
+ * @throws {TypeError} If any option name is invalid, duplicated within one
340
+ * side, or shared by the positive and negative sides.
341
+ * @since 1.1.0
342
+ */
343
+ declare function negatableFlag(names: NegatableFlagNames, options?: NegatableFlagOptions): Parser<"sync", boolean, NegatableFlagState | undefined>;
240
344
  /**
241
345
  * Options for the {@link argument} parser.
242
346
  */
@@ -483,4 +587,4 @@ interface PassThroughOptions {
483
587
  */
484
588
  declare function passThrough(options?: PassThroughOptions): Parser<"sync", readonly string[], readonly string[]>;
485
589
  //#endregion
486
- export { ArgumentErrorOptions, ArgumentOptions, CommandErrorOptions, CommandOptions, FlagErrorOptions, FlagOptions, OptionErrorOptions, OptionOptions, OptionState, PassThroughFormat, PassThroughOptions, argument, command, constant, fail, flag, option, passThrough };
590
+ export { ArgumentErrorOptions, ArgumentOptions, CommandErrorOptions, CommandOptions, FlagErrorOptions, FlagOptions, NegatableFlagErrorOptions, NegatableFlagNameList, NegatableFlagNames, NegatableFlagOptions, NegatableFlagState, OptionErrorOptions, OptionOptions, OptionState, PassThroughFormat, PassThroughOptions, argument, command, constant, fail, flag, negatableFlag, option, passThrough };