@optique/core 1.0.0-dev.1519 → 1.0.0-dev.1523

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.
@@ -2,6 +2,7 @@ const require_annotations = require('./annotations.cjs');
2
2
  const require_message = require('./message.cjs');
3
3
  const require_dependency = require('./dependency.cjs');
4
4
  const require_mode_dispatch = require('./mode-dispatch.cjs');
5
+ const require_validate = require('./validate.cjs');
5
6
  const require_usage = require('./usage.cjs');
6
7
  const require_doc = require('./doc.cjs');
7
8
  const require_suggestion = require('./suggestion.cjs');
@@ -1001,6 +1002,7 @@ async function resolveDeferredParseStatesAsync(fieldStates, initialRegistry) {
1001
1002
  }
1002
1003
  function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
1003
1004
  const label = typeof labelOrParsers === "string" ? labelOrParsers : void 0;
1005
+ if (label != null) require_validate.validateLabel(label);
1004
1006
  let parsers;
1005
1007
  let options = {};
1006
1008
  if (typeof labelOrParsers === "string") {
@@ -1410,6 +1412,7 @@ async function* suggestTupleAsync(context, prefix, parsers) {
1410
1412
  }
1411
1413
  function tuple(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
1412
1414
  const label = typeof labelOrParsers === "string" ? labelOrParsers : void 0;
1415
+ if (label != null) require_validate.validateLabel(label);
1413
1416
  let parsers;
1414
1417
  let options = {};
1415
1418
  if (typeof labelOrParsers === "string") {
@@ -1723,6 +1726,7 @@ function tuple(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
1723
1726
  }
1724
1727
  function merge(...args) {
1725
1728
  const label = typeof args[0] === "string" ? args[0] : void 0;
1729
+ if (label != null) require_validate.validateLabel(label);
1726
1730
  const lastArg = args[args.length - 1];
1727
1731
  const hasOptions = lastArg != null && typeof lastArg === "object" && !("$valueType" in lastArg);
1728
1732
  const options = hasOptions ? lastArg : {};
@@ -2481,6 +2485,7 @@ function concat(...parsers) {
2481
2485
  };
2482
2486
  }
2483
2487
  function group(label, parser, options = {}) {
2488
+ require_validate.validateLabel(label);
2484
2489
  const groupParser = {
2485
2490
  $mode: parser.$mode,
2486
2491
  $valueType: parser.$valueType,
@@ -1023,6 +1023,8 @@ declare function object<T extends {
1023
1023
  * @returns A {@link Parser} that produces an object with the same keys as
1024
1024
  * the input, where each value is the result of the corresponding
1025
1025
  * parser.
1026
+ * @throws {TypeError} If the label is not a string, is empty,
1027
+ * whitespace-only, or contains control characters.
1026
1028
  */
1027
1029
  declare function object<T extends {
1028
1030
  readonly [key: string | symbol]: Parser<Mode, unknown, unknown>;
@@ -1040,6 +1042,8 @@ declare function object<T extends {
1040
1042
  * @returns A {@link Parser} that produces an object with the same keys as
1041
1043
  * the input, where each value is the result of the corresponding
1042
1044
  * parser.
1045
+ * @throws {TypeError} If the label is not a string, is empty,
1046
+ * whitespace-only, or contains control characters.
1043
1047
  * @since 0.5.0
1044
1048
  */
1045
1049
  declare function object<T extends {
@@ -1084,6 +1088,8 @@ declare function tuple<const T extends readonly Parser<Mode, unknown, unknown>[]
1084
1088
  * @returns A {@link Parser} that produces a readonly tuple with the same length
1085
1089
  * as the input array, where each element is the result of the
1086
1090
  * corresponding parser.
1091
+ * @throws {TypeError} If the label is not a string, is empty,
1092
+ * whitespace-only, or contains control characters.
1087
1093
  */
1088
1094
  declare function tuple<const T extends readonly Parser<Mode, unknown, unknown>[]>(label: string, parsers: T, options?: TupleOptions): Parser<CombineTupleModes<T>, { readonly [K in keyof T]: T[K]["$valueType"][number] extends (infer U) ? U : never }, { readonly [K in keyof T]: T[K]["$stateType"][number] extends (infer U2) ? U2 : never }>;
1089
1095
  /**
@@ -1152,6 +1158,8 @@ declare function merge<const TParsers extends MergeParsers>(...rest: [...parsers
1152
1158
  * @returns A parser that merges parsed object fields from all parsers.
1153
1159
  * Type inference is precise for tuple calls up to 15 parser arguments.
1154
1160
  * @throws {TypeError} If no parser arguments are provided.
1161
+ * @throws {TypeError} If the label is not a string, is empty,
1162
+ * whitespace-only, or contains control characters.
1155
1163
  * @since 0.4.0
1156
1164
  */
1157
1165
  declare function merge<const TParsers extends MergeParsers>(label: string, ...parsers: EnsureMergeParsers<TParsers> & MergeArityGuard<TParsers>): MergeReturnType<TParsers>;
@@ -1166,6 +1174,8 @@ declare function merge<const TParsers extends MergeParsers>(label: string, ...pa
1166
1174
  * @returns A parser that merges parsed object fields from all parsers.
1167
1175
  * Type inference is precise for tuple calls up to 15 parser arguments.
1168
1176
  * @throws {TypeError} If no parser arguments are provided.
1177
+ * @throws {TypeError} If the label is not a string, is empty,
1178
+ * whitespace-only, or contains control characters.
1169
1179
  * @since 0.7.0
1170
1180
  */
1171
1181
  declare function merge<const TParsers extends MergeParsers>(label: string, ...rest: [...parsers: EnsureMergeParsers<TParsers>, options: MergeTailOptions] & MergeArityGuard<TParsers>): MergeReturnType<TParsers>;
@@ -1271,6 +1281,8 @@ declare function concat<const TParsers extends ConcatParsers>(...parsers: TParse
1271
1281
  * @param options Optional visibility controls for the wrapped parser terms.
1272
1282
  * @returns A new parser that behaves identically to the input parser
1273
1283
  * but generates documentation within a labeled section.
1284
+ * @throws {TypeError} If the label is not a string, is empty,
1285
+ * whitespace-only, or contains control characters.
1274
1286
  * @since 0.4.0
1275
1287
  */
1276
1288
  /**
@@ -1023,6 +1023,8 @@ declare function object<T extends {
1023
1023
  * @returns A {@link Parser} that produces an object with the same keys as
1024
1024
  * the input, where each value is the result of the corresponding
1025
1025
  * parser.
1026
+ * @throws {TypeError} If the label is not a string, is empty,
1027
+ * whitespace-only, or contains control characters.
1026
1028
  */
1027
1029
  declare function object<T extends {
1028
1030
  readonly [key: string | symbol]: Parser<Mode, unknown, unknown>;
@@ -1040,6 +1042,8 @@ declare function object<T extends {
1040
1042
  * @returns A {@link Parser} that produces an object with the same keys as
1041
1043
  * the input, where each value is the result of the corresponding
1042
1044
  * parser.
1045
+ * @throws {TypeError} If the label is not a string, is empty,
1046
+ * whitespace-only, or contains control characters.
1043
1047
  * @since 0.5.0
1044
1048
  */
1045
1049
  declare function object<T extends {
@@ -1084,6 +1088,8 @@ declare function tuple<const T extends readonly Parser<Mode, unknown, unknown>[]
1084
1088
  * @returns A {@link Parser} that produces a readonly tuple with the same length
1085
1089
  * as the input array, where each element is the result of the
1086
1090
  * corresponding parser.
1091
+ * @throws {TypeError} If the label is not a string, is empty,
1092
+ * whitespace-only, or contains control characters.
1087
1093
  */
1088
1094
  declare function tuple<const T extends readonly Parser<Mode, unknown, unknown>[]>(label: string, parsers: T, options?: TupleOptions): Parser<CombineTupleModes<T>, { readonly [K in keyof T]: T[K]["$valueType"][number] extends (infer U) ? U : never }, { readonly [K in keyof T]: T[K]["$stateType"][number] extends (infer U2) ? U2 : never }>;
1089
1095
  /**
@@ -1152,6 +1158,8 @@ declare function merge<const TParsers extends MergeParsers>(...rest: [...parsers
1152
1158
  * @returns A parser that merges parsed object fields from all parsers.
1153
1159
  * Type inference is precise for tuple calls up to 15 parser arguments.
1154
1160
  * @throws {TypeError} If no parser arguments are provided.
1161
+ * @throws {TypeError} If the label is not a string, is empty,
1162
+ * whitespace-only, or contains control characters.
1155
1163
  * @since 0.4.0
1156
1164
  */
1157
1165
  declare function merge<const TParsers extends MergeParsers>(label: string, ...parsers: EnsureMergeParsers<TParsers> & MergeArityGuard<TParsers>): MergeReturnType<TParsers>;
@@ -1166,6 +1174,8 @@ declare function merge<const TParsers extends MergeParsers>(label: string, ...pa
1166
1174
  * @returns A parser that merges parsed object fields from all parsers.
1167
1175
  * Type inference is precise for tuple calls up to 15 parser arguments.
1168
1176
  * @throws {TypeError} If no parser arguments are provided.
1177
+ * @throws {TypeError} If the label is not a string, is empty,
1178
+ * whitespace-only, or contains control characters.
1169
1179
  * @since 0.7.0
1170
1180
  */
1171
1181
  declare function merge<const TParsers extends MergeParsers>(label: string, ...rest: [...parsers: EnsureMergeParsers<TParsers>, options: MergeTailOptions] & MergeArityGuard<TParsers>): MergeReturnType<TParsers>;
@@ -1271,6 +1281,8 @@ declare function concat<const TParsers extends ConcatParsers>(...parsers: TParse
1271
1281
  * @param options Optional visibility controls for the wrapped parser terms.
1272
1282
  * @returns A new parser that behaves identically to the input parser
1273
1283
  * but generates documentation within a labeled section.
1284
+ * @throws {TypeError} If the label is not a string, is empty,
1285
+ * whitespace-only, or contains control characters.
1274
1286
  * @since 0.4.0
1275
1287
  */
1276
1288
  /**
@@ -2,6 +2,7 @@ import { getAnnotations, inheritAnnotations, injectAnnotations } from "./annotat
2
2
  import { message, optionName, text, values } from "./message.js";
3
3
  import { DependencyRegistry, createDependencySourceState, dependencyId, isDeferredParseState, isDependencySourceState, isPendingDependencySourceState, isWrappedDependencySource, parseWithDependency, wrappedDependencySourceMarker } from "./dependency.js";
4
4
  import { dispatchByMode, dispatchIterableByMode } from "./mode-dispatch.js";
5
+ import { validateLabel } from "./validate.js";
5
6
  import { extractArgumentMetavars, extractCommandNames, extractOptionNames, isDocHidden, mergeHidden } from "./usage.js";
6
7
  import { deduplicateDocFragments } from "./doc.js";
7
8
  import { DEFAULT_FIND_SIMILAR_OPTIONS, createErrorWithSuggestions, createSuggestionMessage, deduplicateSuggestions, findSimilar } from "./suggestion.js";
@@ -1001,6 +1002,7 @@ async function resolveDeferredParseStatesAsync(fieldStates, initialRegistry) {
1001
1002
  }
1002
1003
  function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
1003
1004
  const label = typeof labelOrParsers === "string" ? labelOrParsers : void 0;
1005
+ if (label != null) validateLabel(label);
1004
1006
  let parsers;
1005
1007
  let options = {};
1006
1008
  if (typeof labelOrParsers === "string") {
@@ -1410,6 +1412,7 @@ async function* suggestTupleAsync(context, prefix, parsers) {
1410
1412
  }
1411
1413
  function tuple(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
1412
1414
  const label = typeof labelOrParsers === "string" ? labelOrParsers : void 0;
1415
+ if (label != null) validateLabel(label);
1413
1416
  let parsers;
1414
1417
  let options = {};
1415
1418
  if (typeof labelOrParsers === "string") {
@@ -1723,6 +1726,7 @@ function tuple(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
1723
1726
  }
1724
1727
  function merge(...args) {
1725
1728
  const label = typeof args[0] === "string" ? args[0] : void 0;
1729
+ if (label != null) validateLabel(label);
1726
1730
  const lastArg = args[args.length - 1];
1727
1731
  const hasOptions = lastArg != null && typeof lastArg === "object" && !("$valueType" in lastArg);
1728
1732
  const options = hasOptions ? lastArg : {};
@@ -2481,6 +2485,7 @@ function concat(...parsers) {
2481
2485
  };
2482
2486
  }
2483
2487
  function group(label, parser, options = {}) {
2488
+ validateLabel(label);
2484
2489
  const groupParser = {
2485
2490
  $mode: parser.$mode,
2486
2491
  $valueType: parser.$valueType,
package/dist/doc.cjs CHANGED
@@ -185,8 +185,8 @@ function defaultSectionOrder(a, b) {
185
185
  * @returns A formatted string representation of the documentation page
186
186
  * @throws {TypeError} If `programName` is not a string, is empty,
187
187
  * whitespace-only, or contains control characters, if any non-empty
188
- * section's title is empty, whitespace-only, or contains a CR or LF
189
- * character, or if `maxWidth` is not a finite integer.
188
+ * section's title is not a string, is empty, whitespace-only, or contains
189
+ * control characters, or if `maxWidth` is not a finite integer.
190
190
  * @throws {RangeError} If any entry needs a description column and `maxWidth`
191
191
  * is too small to fit the minimum layout (less than `termIndent + 4`), or if
192
192
  * `showChoices.maxItems` is less than `1`.
@@ -312,7 +312,7 @@ function formatDocPage(programName, page, options = {}) {
312
312
  if (section.entries.length < 1) continue;
313
313
  output += "\n";
314
314
  if (section.title != null) {
315
- if (section.title.trim() === "" || /[\r\n]/.test(section.title)) throw new TypeError("Section title must not be empty, whitespace-only, or contain newlines.");
315
+ require_validate.validateLabel(section.title);
316
316
  const sectionLabel = options.colors ? `\x1b[1;2m${section.title}:\x1b[0m\n` : `${section.title}:\n`;
317
317
  output += sectionLabel;
318
318
  }
package/dist/doc.d.cts CHANGED
@@ -313,8 +313,8 @@ interface DocPageFormatOptions {
313
313
  * @returns A formatted string representation of the documentation page
314
314
  * @throws {TypeError} If `programName` is not a string, is empty,
315
315
  * whitespace-only, or contains control characters, if any non-empty
316
- * section's title is empty, whitespace-only, or contains a CR or LF
317
- * character, or if `maxWidth` is not a finite integer.
316
+ * section's title is not a string, is empty, whitespace-only, or contains
317
+ * control characters, or if `maxWidth` is not a finite integer.
318
318
  * @throws {RangeError} If any entry needs a description column and `maxWidth`
319
319
  * is too small to fit the minimum layout (less than `termIndent + 4`), or if
320
320
  * `showChoices.maxItems` is less than `1`.
package/dist/doc.d.ts CHANGED
@@ -313,8 +313,8 @@ interface DocPageFormatOptions {
313
313
  * @returns A formatted string representation of the documentation page
314
314
  * @throws {TypeError} If `programName` is not a string, is empty,
315
315
  * whitespace-only, or contains control characters, if any non-empty
316
- * section's title is empty, whitespace-only, or contains a CR or LF
317
- * character, or if `maxWidth` is not a finite integer.
316
+ * section's title is not a string, is empty, whitespace-only, or contains
317
+ * control characters, or if `maxWidth` is not a finite integer.
318
318
  * @throws {RangeError} If any entry needs a description column and `maxWidth`
319
319
  * is too small to fit the minimum layout (less than `termIndent + 4`), or if
320
320
  * `showChoices.maxItems` is less than `1`.
package/dist/doc.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { cloneMessage, formatMessage, text } from "./message.js";
2
- import { validateProgramName } from "./validate.js";
2
+ import { validateLabel, validateProgramName } from "./validate.js";
3
3
  import { cloneUsageTerm, formatUsage, formatUsageTerm, isDocHidden, isUsageHidden } from "./usage.js";
4
4
 
5
5
  //#region src/doc.ts
@@ -185,8 +185,8 @@ function defaultSectionOrder(a, b) {
185
185
  * @returns A formatted string representation of the documentation page
186
186
  * @throws {TypeError} If `programName` is not a string, is empty,
187
187
  * whitespace-only, or contains control characters, if any non-empty
188
- * section's title is empty, whitespace-only, or contains a CR or LF
189
- * character, or if `maxWidth` is not a finite integer.
188
+ * section's title is not a string, is empty, whitespace-only, or contains
189
+ * control characters, or if `maxWidth` is not a finite integer.
190
190
  * @throws {RangeError} If any entry needs a description column and `maxWidth`
191
191
  * is too small to fit the minimum layout (less than `termIndent + 4`), or if
192
192
  * `showChoices.maxItems` is less than `1`.
@@ -312,7 +312,7 @@ function formatDocPage(programName, page, options = {}) {
312
312
  if (section.entries.length < 1) continue;
313
313
  output += "\n";
314
314
  if (section.title != null) {
315
- if (section.title.trim() === "" || /[\r\n]/.test(section.title)) throw new TypeError("Section title must not be empty, whitespace-only, or contain newlines.");
315
+ validateLabel(section.title);
316
316
  const sectionLabel = options.colors ? `\x1b[1;2m${section.title}:\x1b[0m\n` : `${section.title}:\n`;
317
317
  output += sectionLabel;
318
318
  }
package/dist/validate.cjs CHANGED
@@ -147,9 +147,28 @@ function validateProgramName(programName) {
147
147
  if (/^\s+$/.test(programName)) throw new TypeError(`Program name must not be whitespace-only: "${escapeControlChars(programName)}".`);
148
148
  if (CONTROL_CHAR_RE.test(programName)) throw new TypeError(`Program name must not contain control characters: "${escapeControlChars(programName)}".`);
149
149
  }
150
+ /**
151
+ * Validates a label at runtime.
152
+ *
153
+ * Labels are used as section titles in documentation output. They may contain
154
+ * spaces (e.g., "Connection options"), but must not be empty, whitespace-only,
155
+ * or contain control characters.
156
+ *
157
+ * @param label The label to validate.
158
+ * @throws {TypeError} If the label is not a string, is empty,
159
+ * whitespace-only, or contains control characters.
160
+ * @since 1.0.0
161
+ */
162
+ function validateLabel(label) {
163
+ if (typeof label !== "string") throw new TypeError("Label must be a string.");
164
+ if (label === "") throw new TypeError("Label must not be empty.");
165
+ if (/^\s+$/.test(label)) throw new TypeError(`Label must not be whitespace-only: "${escapeControlChars(label)}".`);
166
+ if (CONTROL_CHAR_RE.test(label)) throw new TypeError(`Label must not contain control characters: "${escapeControlChars(label)}".`);
167
+ }
150
168
 
151
169
  //#endregion
152
170
  exports.validateCommandNames = validateCommandNames;
171
+ exports.validateLabel = validateLabel;
153
172
  exports.validateMetaNameCollisions = validateMetaNameCollisions;
154
173
  exports.validateOptionNames = validateOptionNames;
155
174
  exports.validateProgramName = validateProgramName;
package/dist/validate.js CHANGED
@@ -146,6 +146,24 @@ function validateProgramName(programName) {
146
146
  if (/^\s+$/.test(programName)) throw new TypeError(`Program name must not be whitespace-only: "${escapeControlChars(programName)}".`);
147
147
  if (CONTROL_CHAR_RE.test(programName)) throw new TypeError(`Program name must not contain control characters: "${escapeControlChars(programName)}".`);
148
148
  }
149
+ /**
150
+ * Validates a label at runtime.
151
+ *
152
+ * Labels are used as section titles in documentation output. They may contain
153
+ * spaces (e.g., "Connection options"), but must not be empty, whitespace-only,
154
+ * or contain control characters.
155
+ *
156
+ * @param label The label to validate.
157
+ * @throws {TypeError} If the label is not a string, is empty,
158
+ * whitespace-only, or contains control characters.
159
+ * @since 1.0.0
160
+ */
161
+ function validateLabel(label) {
162
+ if (typeof label !== "string") throw new TypeError("Label must be a string.");
163
+ if (label === "") throw new TypeError("Label must not be empty.");
164
+ if (/^\s+$/.test(label)) throw new TypeError(`Label must not be whitespace-only: "${escapeControlChars(label)}".`);
165
+ if (CONTROL_CHAR_RE.test(label)) throw new TypeError(`Label must not contain control characters: "${escapeControlChars(label)}".`);
166
+ }
149
167
 
150
168
  //#endregion
151
- export { validateCommandNames, validateMetaNameCollisions, validateOptionNames, validateProgramName };
169
+ export { validateCommandNames, validateLabel, validateMetaNameCollisions, validateOptionNames, validateProgramName };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optique/core",
3
- "version": "1.0.0-dev.1519+797fd62b",
3
+ "version": "1.0.0-dev.1523+edc4d966",
4
4
  "description": "Type-safe combinatorial command-line interface parser",
5
5
  "keywords": [
6
6
  "CLI",