@optique/core 0.5.0-dev.64 → 0.5.0-dev.65

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/doc.cjs CHANGED
@@ -81,7 +81,10 @@ function formatDocPage(programName, page, options = {}) {
81
81
  if (options.showDefault && entry.default != null) {
82
82
  const prefix = typeof options.showDefault === "object" ? options.showDefault.prefix ?? " [" : " [";
83
83
  const suffix = typeof options.showDefault === "object" ? options.showDefault.suffix ?? "]" : "]";
84
- const defaultText = `${prefix}${entry.default}${suffix}`;
84
+ const defaultText = `${prefix}${require_message.formatMessage(entry.default, {
85
+ colors: options.colors ? { resetSuffix: "\x1B[2m" } : false,
86
+ quotes: !options.colors
87
+ })}${suffix}`;
85
88
  const formattedDefault = options.colors ? `\x1b[2m${defaultText}\x1b[0m` : defaultText;
86
89
  description += formattedDefault;
87
90
  }
package/dist/doc.d.cts CHANGED
@@ -24,7 +24,7 @@ interface DocEntry {
24
24
  * indicate what the default behavior is if the command or option is not
25
25
  * specified.
26
26
  */
27
- readonly default?: string;
27
+ readonly default?: Message;
28
28
  }
29
29
  /**
30
30
  * A section in a document that groups related entries together.
package/dist/doc.d.ts CHANGED
@@ -24,7 +24,7 @@ interface DocEntry {
24
24
  * indicate what the default behavior is if the command or option is not
25
25
  * specified.
26
26
  */
27
- readonly default?: string;
27
+ readonly default?: Message;
28
28
  }
29
29
  /**
30
30
  * A section in a document that groups related entries together.
package/dist/doc.js CHANGED
@@ -81,7 +81,10 @@ function formatDocPage(programName, page, options = {}) {
81
81
  if (options.showDefault && entry.default != null) {
82
82
  const prefix = typeof options.showDefault === "object" ? options.showDefault.prefix ?? " [" : " [";
83
83
  const suffix = typeof options.showDefault === "object" ? options.showDefault.suffix ?? "]" : "]";
84
- const defaultText = `${prefix}${entry.default}${suffix}`;
84
+ const defaultText = `${prefix}${formatMessage(entry.default, {
85
+ colors: options.colors ? { resetSuffix: "\x1B[2m" } : false,
86
+ quotes: !options.colors
87
+ })}${suffix}`;
85
88
  const formattedDefault = options.colors ? `\x1b[2m${defaultText}\x1b[0m` : defaultText;
86
89
  description += formattedDefault;
87
90
  }
package/dist/index.d.cts CHANGED
@@ -2,6 +2,6 @@ import { Message, MessageFormatOptions, MessageTerm, envVar, formatMessage, mess
2
2
  import { OptionName, Usage, UsageFormatOptions, UsageTerm, UsageTermFormatOptions, formatUsage, formatUsageTerm, normalizeUsage } from "./usage.cjs";
3
3
  import { DocEntry, DocFragment, DocFragments, DocPage, DocPageFormatOptions, DocSection, ShowDefaultOptions, formatDocPage } from "./doc.cjs";
4
4
  import { ChoiceOptions, FloatOptions, IntegerOptionsBigInt, IntegerOptionsNumber, LocaleOptions, StringOptions, UrlOptions, Uuid, UuidOptions, ValueParser, ValueParserResult, choice, float, integer, isValueParser, locale, string, url, uuid } from "./valueparser.cjs";
5
- import { ArgumentOptions, CommandOptions, DocState, FlagOptions, InferValue, MultipleOptions, OptionOptions, Parser, ParserContext, ParserResult, Result, WithDefaultError, argument, command, concat, constant, flag, getDocPage, group, longestMatch, map, merge, multiple, object, option, optional, or, parse, tuple, withDefault } from "./parser.cjs";
5
+ import { ArgumentOptions, CommandOptions, DocState, FlagOptions, InferValue, MultipleOptions, OptionOptions, Parser, ParserContext, ParserResult, Result, WithDefaultError, WithDefaultOptions, argument, command, concat, constant, flag, getDocPage, group, longestMatch, map, merge, multiple, object, option, optional, or, parse, tuple, withDefault } from "./parser.cjs";
6
6
  import { RunError, RunOptions, run } from "./facade.cjs";
7
- export { ArgumentOptions, ChoiceOptions, CommandOptions, DocEntry, DocFragment, DocFragments, DocPage, DocPageFormatOptions, DocSection, DocState, FlagOptions, FloatOptions, InferValue, IntegerOptionsBigInt, IntegerOptionsNumber, LocaleOptions, Message, MessageFormatOptions, MessageTerm, MultipleOptions, OptionName, OptionOptions, Parser, ParserContext, ParserResult, Result, RunError, RunOptions, ShowDefaultOptions, StringOptions, UrlOptions, Usage, UsageFormatOptions, UsageTerm, UsageTermFormatOptions, Uuid, UuidOptions, ValueParser, ValueParserResult, WithDefaultError, argument, choice, command, concat, constant, envVar, flag, float, formatDocPage, formatMessage, formatUsage, formatUsageTerm, getDocPage, group, integer, isValueParser, locale, longestMatch, map, merge, message, metavar, multiple, normalizeUsage, object, option, optionName, optionNames, optional, or, parse, run, string, text, tuple, url, uuid, value, values, withDefault };
7
+ export { ArgumentOptions, ChoiceOptions, CommandOptions, DocEntry, DocFragment, DocFragments, DocPage, DocPageFormatOptions, DocSection, DocState, FlagOptions, FloatOptions, InferValue, IntegerOptionsBigInt, IntegerOptionsNumber, LocaleOptions, Message, MessageFormatOptions, MessageTerm, MultipleOptions, OptionName, OptionOptions, Parser, ParserContext, ParserResult, Result, RunError, RunOptions, ShowDefaultOptions, StringOptions, UrlOptions, Usage, UsageFormatOptions, UsageTerm, UsageTermFormatOptions, Uuid, UuidOptions, ValueParser, ValueParserResult, WithDefaultError, WithDefaultOptions, argument, choice, command, concat, constant, envVar, flag, float, formatDocPage, formatMessage, formatUsage, formatUsageTerm, getDocPage, group, integer, isValueParser, locale, longestMatch, map, merge, message, metavar, multiple, normalizeUsage, object, option, optionName, optionNames, optional, or, parse, run, string, text, tuple, url, uuid, value, values, withDefault };
package/dist/index.d.ts CHANGED
@@ -2,6 +2,6 @@ import { Message, MessageFormatOptions, MessageTerm, envVar, formatMessage, mess
2
2
  import { OptionName, Usage, UsageFormatOptions, UsageTerm, UsageTermFormatOptions, formatUsage, formatUsageTerm, normalizeUsage } from "./usage.js";
3
3
  import { DocEntry, DocFragment, DocFragments, DocPage, DocPageFormatOptions, DocSection, ShowDefaultOptions, formatDocPage } from "./doc.js";
4
4
  import { ChoiceOptions, FloatOptions, IntegerOptionsBigInt, IntegerOptionsNumber, LocaleOptions, StringOptions, UrlOptions, Uuid, UuidOptions, ValueParser, ValueParserResult, choice, float, integer, isValueParser, locale, string, url, uuid } from "./valueparser.js";
5
- import { ArgumentOptions, CommandOptions, DocState, FlagOptions, InferValue, MultipleOptions, OptionOptions, Parser, ParserContext, ParserResult, Result, WithDefaultError, argument, command, concat, constant, flag, getDocPage, group, longestMatch, map, merge, multiple, object, option, optional, or, parse, tuple, withDefault } from "./parser.js";
5
+ import { ArgumentOptions, CommandOptions, DocState, FlagOptions, InferValue, MultipleOptions, OptionOptions, Parser, ParserContext, ParserResult, Result, WithDefaultError, WithDefaultOptions, argument, command, concat, constant, flag, getDocPage, group, longestMatch, map, merge, multiple, object, option, optional, or, parse, tuple, withDefault } from "./parser.js";
6
6
  import { RunError, RunOptions, run } from "./facade.js";
7
- export { ArgumentOptions, ChoiceOptions, CommandOptions, DocEntry, DocFragment, DocFragments, DocPage, DocPageFormatOptions, DocSection, DocState, FlagOptions, FloatOptions, InferValue, IntegerOptionsBigInt, IntegerOptionsNumber, LocaleOptions, Message, MessageFormatOptions, MessageTerm, MultipleOptions, OptionName, OptionOptions, Parser, ParserContext, ParserResult, Result, RunError, RunOptions, ShowDefaultOptions, StringOptions, UrlOptions, Usage, UsageFormatOptions, UsageTerm, UsageTermFormatOptions, Uuid, UuidOptions, ValueParser, ValueParserResult, WithDefaultError, argument, choice, command, concat, constant, envVar, flag, float, formatDocPage, formatMessage, formatUsage, formatUsageTerm, getDocPage, group, integer, isValueParser, locale, longestMatch, map, merge, message, metavar, multiple, normalizeUsage, object, option, optionName, optionNames, optional, or, parse, run, string, text, tuple, url, uuid, value, values, withDefault };
7
+ export { ArgumentOptions, ChoiceOptions, CommandOptions, DocEntry, DocFragment, DocFragments, DocPage, DocPageFormatOptions, DocSection, DocState, FlagOptions, FloatOptions, InferValue, IntegerOptionsBigInt, IntegerOptionsNumber, LocaleOptions, Message, MessageFormatOptions, MessageTerm, MultipleOptions, OptionName, OptionOptions, Parser, ParserContext, ParserResult, Result, RunError, RunOptions, ShowDefaultOptions, StringOptions, UrlOptions, Usage, UsageFormatOptions, UsageTerm, UsageTermFormatOptions, Uuid, UuidOptions, ValueParser, ValueParserResult, WithDefaultError, WithDefaultOptions, argument, choice, command, concat, constant, envVar, flag, float, formatDocPage, formatMessage, formatUsage, formatUsageTerm, getDocPage, group, integer, isValueParser, locale, longestMatch, map, merge, message, metavar, multiple, normalizeUsage, object, option, optionName, optionNames, optional, or, parse, run, string, text, tuple, url, uuid, value, values, withDefault };
package/dist/message.cjs CHANGED
@@ -134,8 +134,11 @@ function envVar(envVar$1) {
134
134
  * @returns A formatted string representation of the message.
135
135
  */
136
136
  function formatMessage(msg, options = {}) {
137
- const useColors = options.colors ?? false;
137
+ const colorConfig = options.colors ?? false;
138
+ const useColors = typeof colorConfig === "boolean" ? colorConfig : true;
139
+ const resetSuffix = typeof colorConfig === "object" ? colorConfig.resetSuffix ?? "" : "";
138
140
  const useQuotes = options.quotes ?? true;
141
+ const resetSequence = `\x1b[0m${resetSuffix}`;
139
142
  function* stream() {
140
143
  const wordPattern = /\s*\S+\s*/g;
141
144
  for (const term of msg) if (term.type === "text") while (true) {
@@ -149,7 +152,7 @@ function formatMessage(msg, options = {}) {
149
152
  else if (term.type === "optionName") {
150
153
  const name = useQuotes ? `\`${term.optionName}\`` : term.optionName;
151
154
  yield {
152
- text: useColors ? `\x1b[3m${name}\x1b[0m` : name,
155
+ text: useColors ? `\x1b[3m${name}${resetSequence}` : name,
153
156
  width: name.length
154
157
  };
155
158
  } else if (term.type === "optionNames") {
@@ -161,7 +164,7 @@ function formatMessage(msg, options = {}) {
161
164
  width: 1
162
165
  };
163
166
  yield {
164
- text: useColors ? `\x1b[3m${name}\x1b[0m` : name,
167
+ text: useColors ? `\x1b[3m${name}${resetSequence}` : name,
165
168
  width: name.length
166
169
  };
167
170
  i++;
@@ -169,13 +172,13 @@ function formatMessage(msg, options = {}) {
169
172
  } else if (term.type === "metavar") {
170
173
  const metavar$1 = useQuotes ? `\`${term.metavar}\`` : term.metavar;
171
174
  yield {
172
- text: useColors ? `\x1b[1m${metavar$1}\x1b[0m` : metavar$1,
175
+ text: useColors ? `\x1b[1m${metavar$1}${resetSequence}` : metavar$1,
173
176
  width: metavar$1.length
174
177
  };
175
178
  } else if (term.type === "value") {
176
179
  const value$1 = useQuotes ? `${JSON.stringify(term.value)}` : term.value;
177
180
  yield {
178
- text: useColors ? `\x1b[32m${value$1}\x1b[0m` : value$1,
181
+ text: useColors ? `\x1b[32m${value$1}${resetSequence}` : value$1,
179
182
  width: value$1.length
180
183
  };
181
184
  } else if (term.type === "values") for (let i = 0; i < term.values.length; i++) {
@@ -185,14 +188,14 @@ function formatMessage(msg, options = {}) {
185
188
  };
186
189
  const value$1 = useQuotes ? JSON.stringify(term.values[i]) : term.values[i];
187
190
  yield {
188
- text: useColors ? i <= 0 ? `\x1b[32m${value$1}` : i + 1 >= term.values.length ? `${value$1}\x1b[0m` : value$1 : value$1,
191
+ text: useColors ? i <= 0 ? `\x1b[32m${value$1}` : i + 1 >= term.values.length ? `${value$1}${resetSequence}` : value$1 : value$1,
189
192
  width: value$1.length
190
193
  };
191
194
  }
192
195
  else if (term.type === "envVar") {
193
196
  const envVar$1 = useQuotes ? `\`${term.envVar}\`` : term.envVar;
194
197
  yield {
195
- text: useColors ? `\x1b[1;4m${envVar$1}\x1b[0m` : envVar$1,
198
+ text: useColors ? `\x1b[1;4m${envVar$1}${resetSequence}` : envVar$1,
196
199
  width: envVar$1.length
197
200
  };
198
201
  } else throw new TypeError(`Invalid MessageTerm type: ${term["type"]}.`);
@@ -191,9 +191,21 @@ interface MessageFormatOptions {
191
191
  * Whether to use colors in the formatted message. If `true`,
192
192
  * the formatted message will include ANSI escape codes for colors.
193
193
  * If `false`, the message will be plain text without colors.
194
+ *
195
+ * Can also be an object with additional color options:
196
+ *
197
+ * - `resetSuffix`: String to append after each ANSI reset sequence (`\x1b[0m`)
198
+ * to maintain parent styling context.
199
+ *
194
200
  * @default `false`
195
201
  */
196
- readonly colors?: boolean;
202
+ readonly colors?: boolean | {
203
+ /**
204
+ * String to append after each ANSI reset sequence to maintain
205
+ * parent styling context (e.g., `"\x1b[2m"` for dim text).
206
+ */
207
+ readonly resetSuffix?: string;
208
+ };
197
209
  /**
198
210
  * Whether to use quotes around values in the formatted message.
199
211
  * If `true`, values will be wrapped in quotes (e.g., `"value"`).
package/dist/message.d.ts CHANGED
@@ -191,9 +191,21 @@ interface MessageFormatOptions {
191
191
  * Whether to use colors in the formatted message. If `true`,
192
192
  * the formatted message will include ANSI escape codes for colors.
193
193
  * If `false`, the message will be plain text without colors.
194
+ *
195
+ * Can also be an object with additional color options:
196
+ *
197
+ * - `resetSuffix`: String to append after each ANSI reset sequence (`\x1b[0m`)
198
+ * to maintain parent styling context.
199
+ *
194
200
  * @default `false`
195
201
  */
196
- readonly colors?: boolean;
202
+ readonly colors?: boolean | {
203
+ /**
204
+ * String to append after each ANSI reset sequence to maintain
205
+ * parent styling context (e.g., `"\x1b[2m"` for dim text).
206
+ */
207
+ readonly resetSuffix?: string;
208
+ };
197
209
  /**
198
210
  * Whether to use quotes around values in the formatted message.
199
211
  * If `true`, values will be wrapped in quotes (e.g., `"value"`).
package/dist/message.js CHANGED
@@ -133,8 +133,11 @@ function envVar(envVar$1) {
133
133
  * @returns A formatted string representation of the message.
134
134
  */
135
135
  function formatMessage(msg, options = {}) {
136
- const useColors = options.colors ?? false;
136
+ const colorConfig = options.colors ?? false;
137
+ const useColors = typeof colorConfig === "boolean" ? colorConfig : true;
138
+ const resetSuffix = typeof colorConfig === "object" ? colorConfig.resetSuffix ?? "" : "";
137
139
  const useQuotes = options.quotes ?? true;
140
+ const resetSequence = `\x1b[0m${resetSuffix}`;
138
141
  function* stream() {
139
142
  const wordPattern = /\s*\S+\s*/g;
140
143
  for (const term of msg) if (term.type === "text") while (true) {
@@ -148,7 +151,7 @@ function formatMessage(msg, options = {}) {
148
151
  else if (term.type === "optionName") {
149
152
  const name = useQuotes ? `\`${term.optionName}\`` : term.optionName;
150
153
  yield {
151
- text: useColors ? `\x1b[3m${name}\x1b[0m` : name,
154
+ text: useColors ? `\x1b[3m${name}${resetSequence}` : name,
152
155
  width: name.length
153
156
  };
154
157
  } else if (term.type === "optionNames") {
@@ -160,7 +163,7 @@ function formatMessage(msg, options = {}) {
160
163
  width: 1
161
164
  };
162
165
  yield {
163
- text: useColors ? `\x1b[3m${name}\x1b[0m` : name,
166
+ text: useColors ? `\x1b[3m${name}${resetSequence}` : name,
164
167
  width: name.length
165
168
  };
166
169
  i++;
@@ -168,13 +171,13 @@ function formatMessage(msg, options = {}) {
168
171
  } else if (term.type === "metavar") {
169
172
  const metavar$1 = useQuotes ? `\`${term.metavar}\`` : term.metavar;
170
173
  yield {
171
- text: useColors ? `\x1b[1m${metavar$1}\x1b[0m` : metavar$1,
174
+ text: useColors ? `\x1b[1m${metavar$1}${resetSequence}` : metavar$1,
172
175
  width: metavar$1.length
173
176
  };
174
177
  } else if (term.type === "value") {
175
178
  const value$1 = useQuotes ? `${JSON.stringify(term.value)}` : term.value;
176
179
  yield {
177
- text: useColors ? `\x1b[32m${value$1}\x1b[0m` : value$1,
180
+ text: useColors ? `\x1b[32m${value$1}${resetSequence}` : value$1,
178
181
  width: value$1.length
179
182
  };
180
183
  } else if (term.type === "values") for (let i = 0; i < term.values.length; i++) {
@@ -184,14 +187,14 @@ function formatMessage(msg, options = {}) {
184
187
  };
185
188
  const value$1 = useQuotes ? JSON.stringify(term.values[i]) : term.values[i];
186
189
  yield {
187
- text: useColors ? i <= 0 ? `\x1b[32m${value$1}` : i + 1 >= term.values.length ? `${value$1}\x1b[0m` : value$1 : value$1,
190
+ text: useColors ? i <= 0 ? `\x1b[32m${value$1}` : i + 1 >= term.values.length ? `${value$1}${resetSequence}` : value$1 : value$1,
188
191
  width: value$1.length
189
192
  };
190
193
  }
191
194
  else if (term.type === "envVar") {
192
195
  const envVar$1 = useQuotes ? `\`${term.envVar}\`` : term.envVar;
193
196
  yield {
194
- text: useColors ? `\x1b[1;4m${envVar$1}\x1b[0m` : envVar$1,
197
+ text: useColors ? `\x1b[1;4m${envVar$1}${resetSequence}` : envVar$1,
195
198
  width: envVar$1.length
196
199
  };
197
200
  } else throw new TypeError(`Invalid MessageTerm type: ${term["type"]}.`);
package/dist/parser.cjs CHANGED
@@ -209,7 +209,7 @@ function option(...args) {
209
209
  metavar: valueParser?.metavar
210
210
  },
211
211
  description: options.description,
212
- default: defaultValue != null && valueParser != null ? valueParser.format(defaultValue) : void 0
212
+ default: defaultValue != null && valueParser != null ? require_message.message`${valueParser.format(defaultValue)}` : void 0
213
213
  }];
214
214
  return {
215
215
  fragments,
@@ -458,7 +458,7 @@ function argument(valueParser, options = {}) {
458
458
  type: "entry",
459
459
  term,
460
460
  description: options.description,
461
- default: defaultValue == null ? void 0 : valueParser.format(defaultValue)
461
+ default: defaultValue == null ? void 0 : require_message.message`${valueParser.format(defaultValue)}`
462
462
  }];
463
463
  return {
464
464
  fragments,
@@ -556,22 +556,7 @@ var WithDefaultError = class extends Error {
556
556
  this.name = "WithDefaultError";
557
557
  }
558
558
  };
559
- /**
560
- * Creates a parser that makes another parser use a default value when it fails
561
- * to match or consume input. This is similar to {@link optional}, but instead
562
- * of returning `undefined` when the wrapped parser doesn't match, it returns
563
- * a specified default value.
564
- * @template TValue The type of the value returned by the wrapped parser.
565
- * @template TState The type of the state used by the wrapped parser.
566
- * @template TDefault The type of the default value.
567
- * @param parser The {@link Parser} to wrap with default behavior.
568
- * @param defaultValue The default value to return when the wrapped parser
569
- * doesn't match or consume input. Can be a value of type
570
- * {@link TDefault} or a function that returns such a value.
571
- * @returns A {@link Parser} that produces either the result of the wrapped parser
572
- * or the default value if the wrapped parser fails to match (union type {@link TValue} | {@link TDefault}).
573
- */
574
- function withDefault(parser, defaultValue) {
559
+ function withDefault(parser, defaultValue, options) {
575
560
  return {
576
561
  $valueType: [],
577
562
  $stateType: [],
@@ -616,7 +601,22 @@ function withDefault(parser, defaultValue) {
616
601
  kind: "available",
617
602
  state: state.state[0]
618
603
  };
619
- return parser.getDocFragments(innerState, upperDefaultValue != null ? upperDefaultValue : typeof defaultValue === "function" ? defaultValue() : defaultValue);
604
+ const actualDefaultValue = upperDefaultValue != null ? upperDefaultValue : typeof defaultValue === "function" ? defaultValue() : defaultValue;
605
+ const fragments = parser.getDocFragments(innerState, actualDefaultValue);
606
+ if (options?.message) {
607
+ const modifiedFragments = fragments.fragments.map((fragment) => {
608
+ if (fragment.type === "entry") return {
609
+ ...fragment,
610
+ default: options.message
611
+ };
612
+ return fragment;
613
+ });
614
+ return {
615
+ ...fragments,
616
+ fragments: modifiedFragments
617
+ };
618
+ }
619
+ return fragments;
620
620
  }
621
621
  };
622
622
  }
package/dist/parser.d.cts CHANGED
@@ -276,6 +276,26 @@ declare function argument<T>(valueParser: ValueParser<T>, options?: ArgumentOpti
276
276
  * or `undefined` if the wrapped parser fails to match.
277
277
  */
278
278
  declare function optional<TValue, TState>(parser: Parser<TValue, TState>): Parser<TValue | undefined, [TState] | undefined>;
279
+ /**
280
+ * Options for the {@link withDefault} parser.
281
+ */
282
+ interface WithDefaultOptions {
283
+ /**
284
+ * Custom message to display in help output instead of the formatted default value.
285
+ * This allows showing descriptive text like "SERVICE_URL environment variable"
286
+ * instead of the actual default value.
287
+ *
288
+ * @example
289
+ * ```typescript
290
+ * withDefault(
291
+ * option("--url", url()),
292
+ * process.env["SERVICE_URL"],
293
+ * { message: message`${envVar("SERVICE_URL")} environment variable` }
294
+ * )
295
+ * ```
296
+ */
297
+ readonly message?: Message;
298
+ }
279
299
  /**
280
300
  * Error type for structured error messages in {@link withDefault} default value callbacks.
281
301
  * Unlike regular errors that only support string messages, this error type accepts
@@ -319,9 +339,29 @@ declare class WithDefaultError extends Error {
319
339
  * doesn't match or consume input. Can be a value of type
320
340
  * {@link TDefault} or a function that returns such a value.
321
341
  * @returns A {@link Parser} that produces either the result of the wrapped parser
322
- * or the default value if the wrapped parser fails to match (union type {@link TValue} | {@link TDefault}).
342
+ * or the default value if the wrapped parser fails to match
343
+ * (union type {@link TValue} | {@link TDefault}).
323
344
  */
324
345
  declare function withDefault<TValue, TState, TDefault = TValue>(parser: Parser<TValue, TState>, defaultValue: TDefault | (() => TDefault)): Parser<TValue | TDefault, [TState] | undefined>;
346
+ /**
347
+ * Creates a parser that makes another parser use a default value when it fails
348
+ * to match or consume input. This is similar to {@link optional}, but instead
349
+ * of returning `undefined` when the wrapped parser doesn't match, it returns
350
+ * a specified default value.
351
+ * @template TValue The type of the value returned by the wrapped parser.
352
+ * @template TState The type of the state used by the wrapped parser.
353
+ * @template TDefault The type of the default value.
354
+ * @param parser The {@link Parser} to wrap with default behavior.
355
+ * @param defaultValue The default value to return when the wrapped parser
356
+ * doesn't match or consume input. Can be a value of type
357
+ * {@link TDefault} or a function that returns such a value.
358
+ * @param options Optional configuration including custom help display message.
359
+ * @returns A {@link Parser} that produces either the result of the wrapped parser
360
+ * or the default value if the wrapped parser fails to match
361
+ * (union type {@link TValue} | {@link TDefault}).
362
+ * @since 0.5.0
363
+ */
364
+ declare function withDefault<TValue, TState, TDefault = TValue>(parser: Parser<TValue, TState>, defaultValue: TDefault | (() => TDefault), options?: WithDefaultOptions): Parser<TValue | TDefault, [TState] | undefined>;
325
365
  /**
326
366
  * Creates a parser that transforms the result value of another parser using
327
367
  * a mapping function. This enables value transformation while preserving
@@ -1461,4 +1501,4 @@ declare function group<TValue, TState>(label: string, parser: Parser<TValue, TSt
1461
1501
  */
1462
1502
  declare function getDocPage(parser: Parser<unknown, unknown>, args?: readonly string[]): DocPage | undefined;
1463
1503
  //#endregion
1464
- export { ArgumentOptions, CommandOptions, DocState, FlagOptions, InferValue, MultipleOptions, OptionOptions, Parser, ParserContext, ParserResult, Result, WithDefaultError, argument, command, concat, constant, flag, getDocPage, group, longestMatch, map, merge, multiple, object, option, optional, or, parse, tuple, withDefault };
1504
+ export { ArgumentOptions, CommandOptions, DocState, FlagOptions, InferValue, MultipleOptions, OptionOptions, Parser, ParserContext, ParserResult, Result, WithDefaultError, WithDefaultOptions, argument, command, concat, constant, flag, getDocPage, group, longestMatch, map, merge, multiple, object, option, optional, or, parse, tuple, withDefault };
package/dist/parser.d.ts CHANGED
@@ -276,6 +276,26 @@ declare function argument<T>(valueParser: ValueParser<T>, options?: ArgumentOpti
276
276
  * or `undefined` if the wrapped parser fails to match.
277
277
  */
278
278
  declare function optional<TValue, TState>(parser: Parser<TValue, TState>): Parser<TValue | undefined, [TState] | undefined>;
279
+ /**
280
+ * Options for the {@link withDefault} parser.
281
+ */
282
+ interface WithDefaultOptions {
283
+ /**
284
+ * Custom message to display in help output instead of the formatted default value.
285
+ * This allows showing descriptive text like "SERVICE_URL environment variable"
286
+ * instead of the actual default value.
287
+ *
288
+ * @example
289
+ * ```typescript
290
+ * withDefault(
291
+ * option("--url", url()),
292
+ * process.env["SERVICE_URL"],
293
+ * { message: message`${envVar("SERVICE_URL")} environment variable` }
294
+ * )
295
+ * ```
296
+ */
297
+ readonly message?: Message;
298
+ }
279
299
  /**
280
300
  * Error type for structured error messages in {@link withDefault} default value callbacks.
281
301
  * Unlike regular errors that only support string messages, this error type accepts
@@ -319,9 +339,29 @@ declare class WithDefaultError extends Error {
319
339
  * doesn't match or consume input. Can be a value of type
320
340
  * {@link TDefault} or a function that returns such a value.
321
341
  * @returns A {@link Parser} that produces either the result of the wrapped parser
322
- * or the default value if the wrapped parser fails to match (union type {@link TValue} | {@link TDefault}).
342
+ * or the default value if the wrapped parser fails to match
343
+ * (union type {@link TValue} | {@link TDefault}).
323
344
  */
324
345
  declare function withDefault<TValue, TState, TDefault = TValue>(parser: Parser<TValue, TState>, defaultValue: TDefault | (() => TDefault)): Parser<TValue | TDefault, [TState] | undefined>;
346
+ /**
347
+ * Creates a parser that makes another parser use a default value when it fails
348
+ * to match or consume input. This is similar to {@link optional}, but instead
349
+ * of returning `undefined` when the wrapped parser doesn't match, it returns
350
+ * a specified default value.
351
+ * @template TValue The type of the value returned by the wrapped parser.
352
+ * @template TState The type of the state used by the wrapped parser.
353
+ * @template TDefault The type of the default value.
354
+ * @param parser The {@link Parser} to wrap with default behavior.
355
+ * @param defaultValue The default value to return when the wrapped parser
356
+ * doesn't match or consume input. Can be a value of type
357
+ * {@link TDefault} or a function that returns such a value.
358
+ * @param options Optional configuration including custom help display message.
359
+ * @returns A {@link Parser} that produces either the result of the wrapped parser
360
+ * or the default value if the wrapped parser fails to match
361
+ * (union type {@link TValue} | {@link TDefault}).
362
+ * @since 0.5.0
363
+ */
364
+ declare function withDefault<TValue, TState, TDefault = TValue>(parser: Parser<TValue, TState>, defaultValue: TDefault | (() => TDefault), options?: WithDefaultOptions): Parser<TValue | TDefault, [TState] | undefined>;
325
365
  /**
326
366
  * Creates a parser that transforms the result value of another parser using
327
367
  * a mapping function. This enables value transformation while preserving
@@ -1461,4 +1501,4 @@ declare function group<TValue, TState>(label: string, parser: Parser<TValue, TSt
1461
1501
  */
1462
1502
  declare function getDocPage(parser: Parser<unknown, unknown>, args?: readonly string[]): DocPage | undefined;
1463
1503
  //#endregion
1464
- export { ArgumentOptions, CommandOptions, DocState, FlagOptions, InferValue, MultipleOptions, OptionOptions, Parser, ParserContext, ParserResult, Result, WithDefaultError, argument, command, concat, constant, flag, getDocPage, group, longestMatch, map, merge, multiple, object, option, optional, or, parse, tuple, withDefault };
1504
+ export { ArgumentOptions, CommandOptions, DocState, FlagOptions, InferValue, MultipleOptions, OptionOptions, Parser, ParserContext, ParserResult, Result, WithDefaultError, WithDefaultOptions, argument, command, concat, constant, flag, getDocPage, group, longestMatch, map, merge, multiple, object, option, optional, or, parse, tuple, withDefault };
package/dist/parser.js CHANGED
@@ -209,7 +209,7 @@ function option(...args) {
209
209
  metavar: valueParser?.metavar
210
210
  },
211
211
  description: options.description,
212
- default: defaultValue != null && valueParser != null ? valueParser.format(defaultValue) : void 0
212
+ default: defaultValue != null && valueParser != null ? message`${valueParser.format(defaultValue)}` : void 0
213
213
  }];
214
214
  return {
215
215
  fragments,
@@ -458,7 +458,7 @@ function argument(valueParser, options = {}) {
458
458
  type: "entry",
459
459
  term,
460
460
  description: options.description,
461
- default: defaultValue == null ? void 0 : valueParser.format(defaultValue)
461
+ default: defaultValue == null ? void 0 : message`${valueParser.format(defaultValue)}`
462
462
  }];
463
463
  return {
464
464
  fragments,
@@ -556,22 +556,7 @@ var WithDefaultError = class extends Error {
556
556
  this.name = "WithDefaultError";
557
557
  }
558
558
  };
559
- /**
560
- * Creates a parser that makes another parser use a default value when it fails
561
- * to match or consume input. This is similar to {@link optional}, but instead
562
- * of returning `undefined` when the wrapped parser doesn't match, it returns
563
- * a specified default value.
564
- * @template TValue The type of the value returned by the wrapped parser.
565
- * @template TState The type of the state used by the wrapped parser.
566
- * @template TDefault The type of the default value.
567
- * @param parser The {@link Parser} to wrap with default behavior.
568
- * @param defaultValue The default value to return when the wrapped parser
569
- * doesn't match or consume input. Can be a value of type
570
- * {@link TDefault} or a function that returns such a value.
571
- * @returns A {@link Parser} that produces either the result of the wrapped parser
572
- * or the default value if the wrapped parser fails to match (union type {@link TValue} | {@link TDefault}).
573
- */
574
- function withDefault(parser, defaultValue) {
559
+ function withDefault(parser, defaultValue, options) {
575
560
  return {
576
561
  $valueType: [],
577
562
  $stateType: [],
@@ -616,7 +601,22 @@ function withDefault(parser, defaultValue) {
616
601
  kind: "available",
617
602
  state: state.state[0]
618
603
  };
619
- return parser.getDocFragments(innerState, upperDefaultValue != null ? upperDefaultValue : typeof defaultValue === "function" ? defaultValue() : defaultValue);
604
+ const actualDefaultValue = upperDefaultValue != null ? upperDefaultValue : typeof defaultValue === "function" ? defaultValue() : defaultValue;
605
+ const fragments = parser.getDocFragments(innerState, actualDefaultValue);
606
+ if (options?.message) {
607
+ const modifiedFragments = fragments.fragments.map((fragment) => {
608
+ if (fragment.type === "entry") return {
609
+ ...fragment,
610
+ default: options.message
611
+ };
612
+ return fragment;
613
+ });
614
+ return {
615
+ ...fragments,
616
+ fragments: modifiedFragments
617
+ };
618
+ }
619
+ return fragments;
620
620
  }
621
621
  };
622
622
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optique/core",
3
- "version": "0.5.0-dev.64+84de5850",
3
+ "version": "0.5.0-dev.65+6fcdf2be",
4
4
  "description": "Type-safe combinatorial command-line interface parser",
5
5
  "keywords": [
6
6
  "CLI",