@optique/core 1.0.0-dev.908 → 1.0.0

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.
Files changed (109) hide show
  1. package/dist/annotation-state.cjs +425 -0
  2. package/dist/annotation-state.d.cts +24 -0
  3. package/dist/annotation-state.d.ts +24 -0
  4. package/dist/annotation-state.js +414 -0
  5. package/dist/annotations.cjs +2 -248
  6. package/dist/annotations.d.cts +2 -137
  7. package/dist/annotations.d.ts +2 -137
  8. package/dist/annotations.js +2 -238
  9. package/dist/completion.cjs +611 -100
  10. package/dist/completion.d.cts +1 -1
  11. package/dist/completion.d.ts +1 -1
  12. package/dist/completion.js +611 -100
  13. package/dist/constructs.cjs +3338 -827
  14. package/dist/constructs.d.cts +48 -7
  15. package/dist/constructs.d.ts +48 -7
  16. package/dist/constructs.js +3338 -827
  17. package/dist/context.cjs +0 -23
  18. package/dist/context.d.cts +119 -53
  19. package/dist/context.d.ts +119 -53
  20. package/dist/context.js +0 -22
  21. package/dist/dependency-metadata.cjs +139 -0
  22. package/dist/dependency-metadata.d.cts +112 -0
  23. package/dist/dependency-metadata.d.ts +112 -0
  24. package/dist/dependency-metadata.js +138 -0
  25. package/dist/dependency-runtime.cjs +698 -0
  26. package/dist/dependency-runtime.d.cts +149 -0
  27. package/dist/dependency-runtime.d.ts +149 -0
  28. package/dist/dependency-runtime.js +687 -0
  29. package/dist/dependency.cjs +7 -928
  30. package/dist/dependency.d.cts +2 -794
  31. package/dist/dependency.d.ts +2 -794
  32. package/dist/dependency.js +2 -899
  33. package/dist/displaywidth.cjs +44 -0
  34. package/dist/displaywidth.js +43 -0
  35. package/dist/doc.cjs +285 -23
  36. package/dist/doc.d.cts +57 -2
  37. package/dist/doc.d.ts +57 -2
  38. package/dist/doc.js +283 -25
  39. package/dist/execution-context.cjs +56 -0
  40. package/dist/execution-context.js +53 -0
  41. package/dist/extension.cjs +87 -0
  42. package/dist/extension.d.cts +97 -0
  43. package/dist/extension.d.ts +97 -0
  44. package/dist/extension.js +76 -0
  45. package/dist/facade.cjs +718 -523
  46. package/dist/facade.d.cts +87 -18
  47. package/dist/facade.d.ts +87 -18
  48. package/dist/facade.js +718 -523
  49. package/dist/index.cjs +14 -29
  50. package/dist/index.d.cts +10 -10
  51. package/dist/index.d.ts +10 -10
  52. package/dist/index.js +7 -7
  53. package/dist/input-trace.cjs +56 -0
  54. package/dist/input-trace.d.cts +77 -0
  55. package/dist/input-trace.d.ts +77 -0
  56. package/dist/input-trace.js +55 -0
  57. package/dist/internal/annotations.cjs +316 -0
  58. package/dist/internal/annotations.d.cts +140 -0
  59. package/dist/internal/annotations.d.ts +140 -0
  60. package/dist/internal/annotations.js +306 -0
  61. package/dist/internal/dependency.cjs +984 -0
  62. package/dist/internal/dependency.d.cts +539 -0
  63. package/dist/internal/dependency.d.ts +539 -0
  64. package/dist/internal/dependency.js +964 -0
  65. package/dist/{mode-dispatch.cjs → internal/mode-dispatch.cjs} +1 -3
  66. package/dist/{mode-dispatch.d.cts → internal/mode-dispatch.d.cts} +3 -7
  67. package/dist/{mode-dispatch.d.ts → internal/mode-dispatch.d.ts} +3 -7
  68. package/dist/{mode-dispatch.js → internal/mode-dispatch.js} +1 -3
  69. package/dist/internal/parser.cjs +728 -0
  70. package/dist/internal/parser.d.cts +947 -0
  71. package/dist/internal/parser.d.ts +947 -0
  72. package/dist/internal/parser.js +711 -0
  73. package/dist/message.cjs +84 -26
  74. package/dist/message.d.cts +49 -9
  75. package/dist/message.d.ts +49 -9
  76. package/dist/message.js +84 -27
  77. package/dist/modifiers.cjs +1023 -240
  78. package/dist/modifiers.d.cts +42 -1
  79. package/dist/modifiers.d.ts +42 -1
  80. package/dist/modifiers.js +1023 -240
  81. package/dist/parser.cjs +11 -463
  82. package/dist/parser.d.cts +3 -537
  83. package/dist/parser.d.ts +3 -537
  84. package/dist/parser.js +2 -433
  85. package/dist/phase2-seed.cjs +59 -0
  86. package/dist/phase2-seed.js +56 -0
  87. package/dist/primitives.cjs +557 -208
  88. package/dist/primitives.d.cts +10 -14
  89. package/dist/primitives.d.ts +10 -14
  90. package/dist/primitives.js +557 -208
  91. package/dist/program.cjs +5 -1
  92. package/dist/program.d.cts +5 -3
  93. package/dist/program.d.ts +5 -3
  94. package/dist/program.js +6 -1
  95. package/dist/suggestion.cjs +22 -8
  96. package/dist/suggestion.js +22 -8
  97. package/dist/usage-internals.cjs +3 -2
  98. package/dist/usage-internals.js +4 -2
  99. package/dist/usage.cjs +195 -40
  100. package/dist/usage.d.cts +92 -11
  101. package/dist/usage.d.ts +92 -11
  102. package/dist/usage.js +194 -41
  103. package/dist/validate.cjs +170 -0
  104. package/dist/validate.js +164 -0
  105. package/dist/valueparser.cjs +1278 -191
  106. package/dist/valueparser.d.cts +330 -20
  107. package/dist/valueparser.d.ts +330 -20
  108. package/dist/valueparser.js +1277 -192
  109. package/package.json +9 -9
package/dist/message.cjs CHANGED
@@ -1,6 +1,45 @@
1
+ const require_displaywidth = require('./displaywidth.cjs');
1
2
 
2
3
  //#region src/message.ts
3
4
  /**
5
+ * Creates a deep clone of a {@link MessageTerm}. Most variants contain only
6
+ * primitive fields and are cloned via object spread. The `url` variant
7
+ * receives a new `URL` object (since `structuredClone` cannot handle `URL`
8
+ * on Node.js), and array-valued fields (`optionNames`, `values`) are
9
+ * shallow-copied.
10
+ *
11
+ * @param term The message term to clone.
12
+ * @returns A structurally equal but referentially distinct copy.
13
+ * @since 1.0.0
14
+ */
15
+ function cloneMessageTerm(term) {
16
+ switch (term.type) {
17
+ case "optionNames": return {
18
+ ...term,
19
+ optionNames: [...term.optionNames]
20
+ };
21
+ case "values": return {
22
+ ...term,
23
+ values: [...term.values]
24
+ };
25
+ case "url": return {
26
+ type: "url",
27
+ url: new URL(term.url.href)
28
+ };
29
+ default: return { ...term };
30
+ }
31
+ }
32
+ /**
33
+ * Creates a deep clone of a {@link Message} array and all of its terms.
34
+ *
35
+ * @param msg The message to clone.
36
+ * @returns A structurally equal but referentially distinct copy.
37
+ * @since 1.0.0
38
+ */
39
+ function cloneMessage(msg) {
40
+ return msg.map(cloneMessageTerm);
41
+ }
42
+ /**
4
43
  * Creates a structured message with template strings and values.
5
44
  *
6
45
  * This function allows creating messages where specific values can be
@@ -29,8 +68,8 @@ function message(message$1, ...values$1) {
29
68
  type: "value",
30
69
  value: value$1
31
70
  });
32
- else if (Array.isArray(value$1)) messageTerms.push(...value$1);
33
- else if (typeof value$1 === "object" && value$1 != null && "type" in value$1) messageTerms.push(value$1);
71
+ else if (Array.isArray(value$1)) messageTerms.push(...cloneMessage(value$1));
72
+ else if (typeof value$1 === "object" && value$1 != null && "type" in value$1) messageTerms.push(cloneMessageTerm(value$1));
34
73
  else throw new TypeError(`Invalid value type in message: ${typeof value$1}.`);
35
74
  }
36
75
  return messageTerms;
@@ -68,7 +107,7 @@ function optionName(name) {
68
107
  function optionNames(names) {
69
108
  return {
70
109
  type: "optionNames",
71
- optionNames: names
110
+ optionNames: [...names]
72
111
  };
73
112
  }
74
113
  /**
@@ -105,11 +144,13 @@ function value(value$1) {
105
144
  * string representations of consecutive values.
106
145
  * For example, `["42", "hello"]`.
107
146
  * @returns A {@link MessageTerm} representing the list of values.
147
+ * @throws {TypeError} If the values array is empty.
108
148
  */
109
149
  function values(values$1) {
150
+ if (values$1.length === 0) throw new TypeError("values must not be empty.");
110
151
  return {
111
152
  type: "values",
112
- values: values$1
153
+ values: [...values$1]
113
154
  };
114
155
  }
115
156
  /**
@@ -165,7 +206,7 @@ function url(url$1) {
165
206
  if (typeof url$1 === "string") {
166
207
  if (!URL.canParse(url$1)) throw new RangeError(`Invalid URL: ${url$1}.`);
167
208
  urlObj = new URL(url$1);
168
- } else urlObj = url$1;
209
+ } else urlObj = new URL(url$1.href);
169
210
  return {
170
211
  type: "url",
171
212
  url: urlObj
@@ -198,29 +239,44 @@ function link(href) {
198
239
  * to be styled independently while respecting the locale's list formatting
199
240
  * conventions.
200
241
  *
242
+ * A fallback must be provided for when the values array is empty. This can
243
+ * be either a simple string (shorthand) or an options object with a
244
+ * `fallback` field. When the values array is empty, the fallback text
245
+ * is returned as a single text term. An empty fallback string produces
246
+ * an empty {@link Message}.
247
+ *
201
248
  * @example
202
249
  * ```typescript
203
250
  * // English conjunction (default): "error", "warn", and "info"
204
- * const msg1 = message`Expected one of ${valueSet(["error", "warn", "info"])}.`;
251
+ * const msg1 = message`Expected one of ${
252
+ * valueSet(["error", "warn", "info"], "")
253
+ * }.`;
205
254
  *
206
255
  * // English disjunction: "error", "warn", or "info"
207
256
  * const msg2 = message`Expected ${
208
- * valueSet(["error", "warn", "info"], { type: "disjunction" })
257
+ * valueSet(["error", "warn", "info"], { fallback: "", type: "disjunction" })
209
258
  * }.`;
210
259
  *
211
- * // Korean disjunction: "error", "warn" 또는 "info"
212
- * const msg3 = message`${
213
- * valueSet(["error", "warn", "info"], { locale: "ko", type: "disjunction" })
214
- * } 중 하나여야 합니다.`;
260
+ * // Fallback for empty list:
261
+ * const msg3 = message`Expected one of ${valueSet([], "(none)")}.`;
262
+ * // "Expected one of (none)."
215
263
  * ```
216
264
  *
217
265
  * @param values The list of values to format.
218
- * @param options Optional formatting options including locale and list type.
266
+ * @param fallbackOrOptions A fallback string for empty lists, or an options
267
+ * object including the fallback and formatting
268
+ * options such as locale and list type.
219
269
  * @returns A {@link Message} with alternating value and text terms.
270
+ * @throws {TypeError} If the fallback parameter is missing or invalid.
220
271
  * @since 0.9.0
221
272
  */
222
- function valueSet(values$1, options) {
223
- if (values$1.length === 0) return [];
273
+ function valueSet(values$1, fallbackOrOptions) {
274
+ if (fallbackOrOptions == null || typeof fallbackOrOptions !== "string" && typeof fallbackOrOptions.fallback !== "string") throw new TypeError("valueSet() requires a fallback string or an options object with a fallback field.");
275
+ const options = typeof fallbackOrOptions === "string" ? { fallback: fallbackOrOptions } : fallbackOrOptions;
276
+ if (values$1.length === 0) return options.fallback === "" ? [] : [{
277
+ type: "text",
278
+ text: options.fallback
279
+ }];
224
280
  const formatter = new Intl.ListFormat(options?.locale, {
225
281
  type: options?.type,
226
282
  style: options?.style
@@ -268,7 +324,7 @@ function formatMessage(msg, options = {}) {
268
324
  if (match == null) break;
269
325
  yield {
270
326
  text: match[0],
271
- width: match[0].length
327
+ width: require_displaywidth.getDisplayWidth(match[0])
272
328
  };
273
329
  }
274
330
  }
@@ -285,7 +341,7 @@ function formatMessage(msg, options = {}) {
285
341
  if (match == null) break;
286
342
  yield {
287
343
  text: match[0],
288
- width: match[0].length
344
+ width: require_displaywidth.getDisplayWidth(match[0])
289
345
  };
290
346
  }
291
347
  }
@@ -294,7 +350,7 @@ function formatMessage(msg, options = {}) {
294
350
  const name = useQuotes ? `\`${term.optionName}\`` : term.optionName;
295
351
  yield {
296
352
  text: useColors ? `\x1b[3m${name}${resetSequence}` : name,
297
- width: name.length
353
+ width: require_displaywidth.getDisplayWidth(name)
298
354
  };
299
355
  } else if (term.type === "optionNames") {
300
356
  const names = term.optionNames.map((name) => useQuotes ? `\`${name}\`` : name);
@@ -306,7 +362,7 @@ function formatMessage(msg, options = {}) {
306
362
  };
307
363
  yield {
308
364
  text: useColors ? `\x1b[3m${name}${resetSequence}` : name,
309
- width: name.length
365
+ width: require_displaywidth.getDisplayWidth(name)
310
366
  };
311
367
  i++;
312
368
  }
@@ -314,13 +370,13 @@ function formatMessage(msg, options = {}) {
314
370
  const metavar$1 = useQuotes ? `\`${term.metavar}\`` : term.metavar;
315
371
  yield {
316
372
  text: useColors ? `\x1b[1m${metavar$1}${resetSequence}` : metavar$1,
317
- width: metavar$1.length
373
+ width: require_displaywidth.getDisplayWidth(metavar$1)
318
374
  };
319
375
  } else if (term.type === "value") {
320
376
  const value$1 = useQuotes ? `${JSON.stringify(term.value)}` : term.value;
321
377
  yield {
322
378
  text: useColors ? `\x1b[32m${value$1}${resetSequence}` : value$1,
323
- width: value$1.length
379
+ width: require_displaywidth.getDisplayWidth(value$1)
324
380
  };
325
381
  } else if (term.type === "values") for (let i = 0; i < term.values.length; i++) {
326
382
  if (i > 0) yield {
@@ -330,20 +386,20 @@ function formatMessage(msg, options = {}) {
330
386
  const value$1 = useQuotes ? JSON.stringify(term.values[i]) : term.values[i];
331
387
  yield {
332
388
  text: useColors ? i <= 0 ? `\x1b[32m${value$1}` : i + 1 >= term.values.length ? `${value$1}${resetSequence}` : value$1 : value$1,
333
- width: value$1.length
389
+ width: require_displaywidth.getDisplayWidth(value$1)
334
390
  };
335
391
  }
336
392
  else if (term.type === "envVar") {
337
393
  const envVar$1 = useQuotes ? `\`${term.envVar}\`` : term.envVar;
338
394
  yield {
339
395
  text: useColors ? `\x1b[1;4m${envVar$1}${resetSequence}` : envVar$1,
340
- width: envVar$1.length
396
+ width: require_displaywidth.getDisplayWidth(envVar$1)
341
397
  };
342
398
  } else if (term.type === "commandLine") {
343
399
  const cmd = useQuotes ? `\`${term.commandLine}\`` : term.commandLine;
344
400
  yield {
345
401
  text: useColors ? `\x1b[36m${cmd}${resetSequence}` : cmd,
346
- width: cmd.length
402
+ width: require_displaywidth.getDisplayWidth(cmd)
347
403
  };
348
404
  } else if (term.type === "lineBreak") {
349
405
  yield {
@@ -358,11 +414,11 @@ function formatMessage(msg, options = {}) {
358
414
  const hyperlink = `\x1b]8;;${urlString}\x1b\\${displayText}\x1b]8;;\x1b\\${resetSuffix}`;
359
415
  yield {
360
416
  text: hyperlink,
361
- width: displayText.length
417
+ width: require_displaywidth.getDisplayWidth(displayText)
362
418
  };
363
419
  } else yield {
364
420
  text: displayText,
365
- width: displayText.length
421
+ width: require_displaywidth.getDisplayWidth(displayText)
366
422
  };
367
423
  } else throw new TypeError(`Invalid MessageTerm type: ${term["type"]}.`);
368
424
  }
@@ -375,7 +431,7 @@ function formatMessage(msg, options = {}) {
375
431
  totalWidth = 0;
376
432
  continue;
377
433
  }
378
- if (options.maxWidth != null && totalWidth + width > options.maxWidth) {
434
+ if (options.maxWidth != null && totalWidth > 0 && totalWidth + width > options.maxWidth) {
379
435
  output += "\n";
380
436
  totalWidth = 0;
381
437
  }
@@ -386,6 +442,8 @@ function formatMessage(msg, options = {}) {
386
442
  }
387
443
 
388
444
  //#endregion
445
+ exports.cloneMessage = cloneMessage;
446
+ exports.cloneMessageTerm = cloneMessageTerm;
389
447
  exports.commandLine = commandLine;
390
448
  exports.envVar = envVar;
391
449
  exports.formatMessage = formatMessage;
@@ -151,6 +151,26 @@ type MessageTerm =
151
151
  * displayed to the user with specific formatting.
152
152
  */
153
153
  type Message = readonly MessageTerm[];
154
+ /**
155
+ * Creates a deep clone of a {@link MessageTerm}. Most variants contain only
156
+ * primitive fields and are cloned via object spread. The `url` variant
157
+ * receives a new `URL` object (since `structuredClone` cannot handle `URL`
158
+ * on Node.js), and array-valued fields (`optionNames`, `values`) are
159
+ * shallow-copied.
160
+ *
161
+ * @param term The message term to clone.
162
+ * @returns A structurally equal but referentially distinct copy.
163
+ * @since 1.0.0
164
+ */
165
+ declare function cloneMessageTerm(term: MessageTerm): MessageTerm;
166
+ /**
167
+ * Creates a deep clone of a {@link Message} array and all of its terms.
168
+ *
169
+ * @param msg The message to clone.
170
+ * @returns A structurally equal but referentially distinct copy.
171
+ * @since 1.0.0
172
+ */
173
+ declare function cloneMessage(msg: Message): Message;
154
174
  /**
155
175
  * Creates a structured message with template strings and values.
156
176
  *
@@ -213,6 +233,7 @@ declare function value(value: string): MessageTerm;
213
233
  * string representations of consecutive values.
214
234
  * For example, `["42", "hello"]`.
215
235
  * @returns A {@link MessageTerm} representing the list of values.
236
+ * @throws {TypeError} If the values array is empty.
216
237
  */
217
238
  declare function values(values: readonly string[]): MessageTerm;
218
239
  /**
@@ -299,6 +320,15 @@ interface ValueSetOptions {
299
320
  * @default `"long"`
300
321
  */
301
322
  readonly style?: "long" | "short" | "narrow";
323
+ /**
324
+ * A fallback text to return when the values array is empty. When provided
325
+ * and the values array is empty, a {@link Message} containing a single text
326
+ * term with this string is returned instead of an empty {@link Message}.
327
+ * An empty string produces an empty {@link Message}.
328
+ *
329
+ * @since 1.0.0
330
+ */
331
+ readonly fallback: string;
302
332
  }
303
333
  /**
304
334
  * Creates a {@link Message} for a formatted list of values using the
@@ -310,28 +340,38 @@ interface ValueSetOptions {
310
340
  * to be styled independently while respecting the locale's list formatting
311
341
  * conventions.
312
342
  *
343
+ * A fallback must be provided for when the values array is empty. This can
344
+ * be either a simple string (shorthand) or an options object with a
345
+ * `fallback` field. When the values array is empty, the fallback text
346
+ * is returned as a single text term. An empty fallback string produces
347
+ * an empty {@link Message}.
348
+ *
313
349
  * @example
314
350
  * ```typescript
315
351
  * // English conjunction (default): "error", "warn", and "info"
316
- * const msg1 = message`Expected one of ${valueSet(["error", "warn", "info"])}.`;
352
+ * const msg1 = message`Expected one of ${
353
+ * valueSet(["error", "warn", "info"], "")
354
+ * }.`;
317
355
  *
318
356
  * // English disjunction: "error", "warn", or "info"
319
357
  * const msg2 = message`Expected ${
320
- * valueSet(["error", "warn", "info"], { type: "disjunction" })
358
+ * valueSet(["error", "warn", "info"], { fallback: "", type: "disjunction" })
321
359
  * }.`;
322
360
  *
323
- * // Korean disjunction: "error", "warn" 또는 "info"
324
- * const msg3 = message`${
325
- * valueSet(["error", "warn", "info"], { locale: "ko", type: "disjunction" })
326
- * } 중 하나여야 합니다.`;
361
+ * // Fallback for empty list:
362
+ * const msg3 = message`Expected one of ${valueSet([], "(none)")}.`;
363
+ * // "Expected one of (none)."
327
364
  * ```
328
365
  *
329
366
  * @param values The list of values to format.
330
- * @param options Optional formatting options including locale and list type.
367
+ * @param fallbackOrOptions A fallback string for empty lists, or an options
368
+ * object including the fallback and formatting
369
+ * options such as locale and list type.
331
370
  * @returns A {@link Message} with alternating value and text terms.
371
+ * @throws {TypeError} If the fallback parameter is missing or invalid.
332
372
  * @since 0.9.0
333
373
  */
334
- declare function valueSet(values: readonly string[], options?: ValueSetOptions): Message;
374
+ declare function valueSet(values: readonly string[], fallbackOrOptions: string | ValueSetOptions): Message;
335
375
  /**
336
376
  * Options for the {@link formatMessage} function.
337
377
  */
@@ -380,4 +420,4 @@ interface MessageFormatOptions {
380
420
  */
381
421
  declare function formatMessage(msg: Message, options?: MessageFormatOptions): string;
382
422
  //#endregion
383
- export { Message, MessageFormatOptions, MessageTerm, ValueSetOptions, commandLine, envVar, formatMessage, lineBreak, link, message, metavar, optionName, optionNames, text, url, value, valueSet, values };
423
+ export { Message, MessageFormatOptions, MessageTerm, ValueSetOptions, cloneMessage, cloneMessageTerm, commandLine, envVar, formatMessage, lineBreak, link, message, metavar, optionName, optionNames, text, url, value, valueSet, values };
package/dist/message.d.ts CHANGED
@@ -151,6 +151,26 @@ type MessageTerm =
151
151
  * displayed to the user with specific formatting.
152
152
  */
153
153
  type Message = readonly MessageTerm[];
154
+ /**
155
+ * Creates a deep clone of a {@link MessageTerm}. Most variants contain only
156
+ * primitive fields and are cloned via object spread. The `url` variant
157
+ * receives a new `URL` object (since `structuredClone` cannot handle `URL`
158
+ * on Node.js), and array-valued fields (`optionNames`, `values`) are
159
+ * shallow-copied.
160
+ *
161
+ * @param term The message term to clone.
162
+ * @returns A structurally equal but referentially distinct copy.
163
+ * @since 1.0.0
164
+ */
165
+ declare function cloneMessageTerm(term: MessageTerm): MessageTerm;
166
+ /**
167
+ * Creates a deep clone of a {@link Message} array and all of its terms.
168
+ *
169
+ * @param msg The message to clone.
170
+ * @returns A structurally equal but referentially distinct copy.
171
+ * @since 1.0.0
172
+ */
173
+ declare function cloneMessage(msg: Message): Message;
154
174
  /**
155
175
  * Creates a structured message with template strings and values.
156
176
  *
@@ -213,6 +233,7 @@ declare function value(value: string): MessageTerm;
213
233
  * string representations of consecutive values.
214
234
  * For example, `["42", "hello"]`.
215
235
  * @returns A {@link MessageTerm} representing the list of values.
236
+ * @throws {TypeError} If the values array is empty.
216
237
  */
217
238
  declare function values(values: readonly string[]): MessageTerm;
218
239
  /**
@@ -299,6 +320,15 @@ interface ValueSetOptions {
299
320
  * @default `"long"`
300
321
  */
301
322
  readonly style?: "long" | "short" | "narrow";
323
+ /**
324
+ * A fallback text to return when the values array is empty. When provided
325
+ * and the values array is empty, a {@link Message} containing a single text
326
+ * term with this string is returned instead of an empty {@link Message}.
327
+ * An empty string produces an empty {@link Message}.
328
+ *
329
+ * @since 1.0.0
330
+ */
331
+ readonly fallback: string;
302
332
  }
303
333
  /**
304
334
  * Creates a {@link Message} for a formatted list of values using the
@@ -310,28 +340,38 @@ interface ValueSetOptions {
310
340
  * to be styled independently while respecting the locale's list formatting
311
341
  * conventions.
312
342
  *
343
+ * A fallback must be provided for when the values array is empty. This can
344
+ * be either a simple string (shorthand) or an options object with a
345
+ * `fallback` field. When the values array is empty, the fallback text
346
+ * is returned as a single text term. An empty fallback string produces
347
+ * an empty {@link Message}.
348
+ *
313
349
  * @example
314
350
  * ```typescript
315
351
  * // English conjunction (default): "error", "warn", and "info"
316
- * const msg1 = message`Expected one of ${valueSet(["error", "warn", "info"])}.`;
352
+ * const msg1 = message`Expected one of ${
353
+ * valueSet(["error", "warn", "info"], "")
354
+ * }.`;
317
355
  *
318
356
  * // English disjunction: "error", "warn", or "info"
319
357
  * const msg2 = message`Expected ${
320
- * valueSet(["error", "warn", "info"], { type: "disjunction" })
358
+ * valueSet(["error", "warn", "info"], { fallback: "", type: "disjunction" })
321
359
  * }.`;
322
360
  *
323
- * // Korean disjunction: "error", "warn" 또는 "info"
324
- * const msg3 = message`${
325
- * valueSet(["error", "warn", "info"], { locale: "ko", type: "disjunction" })
326
- * } 중 하나여야 합니다.`;
361
+ * // Fallback for empty list:
362
+ * const msg3 = message`Expected one of ${valueSet([], "(none)")}.`;
363
+ * // "Expected one of (none)."
327
364
  * ```
328
365
  *
329
366
  * @param values The list of values to format.
330
- * @param options Optional formatting options including locale and list type.
367
+ * @param fallbackOrOptions A fallback string for empty lists, or an options
368
+ * object including the fallback and formatting
369
+ * options such as locale and list type.
331
370
  * @returns A {@link Message} with alternating value and text terms.
371
+ * @throws {TypeError} If the fallback parameter is missing or invalid.
332
372
  * @since 0.9.0
333
373
  */
334
- declare function valueSet(values: readonly string[], options?: ValueSetOptions): Message;
374
+ declare function valueSet(values: readonly string[], fallbackOrOptions: string | ValueSetOptions): Message;
335
375
  /**
336
376
  * Options for the {@link formatMessage} function.
337
377
  */
@@ -380,4 +420,4 @@ interface MessageFormatOptions {
380
420
  */
381
421
  declare function formatMessage(msg: Message, options?: MessageFormatOptions): string;
382
422
  //#endregion
383
- export { Message, MessageFormatOptions, MessageTerm, ValueSetOptions, commandLine, envVar, formatMessage, lineBreak, link, message, metavar, optionName, optionNames, text, url, value, valueSet, values };
423
+ export { Message, MessageFormatOptions, MessageTerm, ValueSetOptions, cloneMessage, cloneMessageTerm, commandLine, envVar, formatMessage, lineBreak, link, message, metavar, optionName, optionNames, text, url, value, valueSet, values };