@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.
- package/dist/annotation-state.cjs +425 -0
- package/dist/annotation-state.d.cts +24 -0
- package/dist/annotation-state.d.ts +24 -0
- package/dist/annotation-state.js +414 -0
- package/dist/annotations.cjs +2 -248
- package/dist/annotations.d.cts +2 -137
- package/dist/annotations.d.ts +2 -137
- package/dist/annotations.js +2 -238
- package/dist/completion.cjs +611 -100
- package/dist/completion.d.cts +1 -1
- package/dist/completion.d.ts +1 -1
- package/dist/completion.js +611 -100
- package/dist/constructs.cjs +3338 -827
- package/dist/constructs.d.cts +48 -7
- package/dist/constructs.d.ts +48 -7
- package/dist/constructs.js +3338 -827
- package/dist/context.cjs +0 -23
- package/dist/context.d.cts +119 -53
- package/dist/context.d.ts +119 -53
- package/dist/context.js +0 -22
- package/dist/dependency-metadata.cjs +139 -0
- package/dist/dependency-metadata.d.cts +112 -0
- package/dist/dependency-metadata.d.ts +112 -0
- package/dist/dependency-metadata.js +138 -0
- package/dist/dependency-runtime.cjs +698 -0
- package/dist/dependency-runtime.d.cts +149 -0
- package/dist/dependency-runtime.d.ts +149 -0
- package/dist/dependency-runtime.js +687 -0
- package/dist/dependency.cjs +7 -928
- package/dist/dependency.d.cts +2 -794
- package/dist/dependency.d.ts +2 -794
- package/dist/dependency.js +2 -899
- package/dist/displaywidth.cjs +44 -0
- package/dist/displaywidth.js +43 -0
- package/dist/doc.cjs +285 -23
- package/dist/doc.d.cts +57 -2
- package/dist/doc.d.ts +57 -2
- package/dist/doc.js +283 -25
- package/dist/execution-context.cjs +56 -0
- package/dist/execution-context.js +53 -0
- package/dist/extension.cjs +87 -0
- package/dist/extension.d.cts +97 -0
- package/dist/extension.d.ts +97 -0
- package/dist/extension.js +76 -0
- package/dist/facade.cjs +718 -523
- package/dist/facade.d.cts +87 -18
- package/dist/facade.d.ts +87 -18
- package/dist/facade.js +718 -523
- package/dist/index.cjs +14 -29
- package/dist/index.d.cts +10 -10
- package/dist/index.d.ts +10 -10
- package/dist/index.js +7 -7
- package/dist/input-trace.cjs +56 -0
- package/dist/input-trace.d.cts +77 -0
- package/dist/input-trace.d.ts +77 -0
- package/dist/input-trace.js +55 -0
- package/dist/internal/annotations.cjs +316 -0
- package/dist/internal/annotations.d.cts +140 -0
- package/dist/internal/annotations.d.ts +140 -0
- package/dist/internal/annotations.js +306 -0
- package/dist/internal/dependency.cjs +984 -0
- package/dist/internal/dependency.d.cts +539 -0
- package/dist/internal/dependency.d.ts +539 -0
- package/dist/internal/dependency.js +964 -0
- package/dist/{mode-dispatch.cjs → internal/mode-dispatch.cjs} +1 -3
- package/dist/{mode-dispatch.d.cts → internal/mode-dispatch.d.cts} +3 -7
- package/dist/{mode-dispatch.d.ts → internal/mode-dispatch.d.ts} +3 -7
- package/dist/{mode-dispatch.js → internal/mode-dispatch.js} +1 -3
- package/dist/internal/parser.cjs +728 -0
- package/dist/internal/parser.d.cts +947 -0
- package/dist/internal/parser.d.ts +947 -0
- package/dist/internal/parser.js +711 -0
- package/dist/message.cjs +84 -26
- package/dist/message.d.cts +49 -9
- package/dist/message.d.ts +49 -9
- package/dist/message.js +84 -27
- package/dist/modifiers.cjs +1023 -240
- package/dist/modifiers.d.cts +42 -1
- package/dist/modifiers.d.ts +42 -1
- package/dist/modifiers.js +1023 -240
- package/dist/parser.cjs +11 -463
- package/dist/parser.d.cts +3 -537
- package/dist/parser.d.ts +3 -537
- package/dist/parser.js +2 -433
- package/dist/phase2-seed.cjs +59 -0
- package/dist/phase2-seed.js +56 -0
- package/dist/primitives.cjs +557 -208
- package/dist/primitives.d.cts +10 -14
- package/dist/primitives.d.ts +10 -14
- package/dist/primitives.js +557 -208
- package/dist/program.cjs +5 -1
- package/dist/program.d.cts +5 -3
- package/dist/program.d.ts +5 -3
- package/dist/program.js +6 -1
- package/dist/suggestion.cjs +22 -8
- package/dist/suggestion.js +22 -8
- package/dist/usage-internals.cjs +3 -2
- package/dist/usage-internals.js +4 -2
- package/dist/usage.cjs +195 -40
- package/dist/usage.d.cts +92 -11
- package/dist/usage.d.ts +92 -11
- package/dist/usage.js +194 -41
- package/dist/validate.cjs +170 -0
- package/dist/validate.js +164 -0
- package/dist/valueparser.cjs +1278 -191
- package/dist/valueparser.d.cts +330 -20
- package/dist/valueparser.d.ts +330 -20
- package/dist/valueparser.js +1277 -192
- package/package.json +9 -9
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
|
|
2
|
+
//#region src/validate.ts
|
|
3
|
+
/**
|
|
4
|
+
* Matches Unicode control characters: C0 (U+0000–U+001F), DEL (U+007F),
|
|
5
|
+
* C1 (U+0080–U+009F), and line separators (U+2028, U+2029).
|
|
6
|
+
*/
|
|
7
|
+
const CONTROL_CHAR_RE = /[\x00-\x1f\x7f-\x9f\u2028\u2029]/;
|
|
8
|
+
const CONTROL_CHAR_RE_GLOBAL = new RegExp(CONTROL_CHAR_RE.source, "g");
|
|
9
|
+
/**
|
|
10
|
+
* Escapes control characters in a string for readable error messages.
|
|
11
|
+
*
|
|
12
|
+
* @param value The string to escape.
|
|
13
|
+
* @returns The escaped string with control characters replaced by escape
|
|
14
|
+
* sequences.
|
|
15
|
+
*/
|
|
16
|
+
function escapeControlChars(value) {
|
|
17
|
+
return value.replace(CONTROL_CHAR_RE_GLOBAL, (ch) => {
|
|
18
|
+
const code = ch.charCodeAt(0);
|
|
19
|
+
switch (code) {
|
|
20
|
+
case 9: return "\\t";
|
|
21
|
+
case 10: return "\\n";
|
|
22
|
+
case 13: return "\\r";
|
|
23
|
+
default: return code > 255 ? `\\u${code.toString(16).padStart(4, "0")}` : `\\x${code.toString(16).padStart(2, "0")}`;
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Validates option names at runtime.
|
|
29
|
+
*
|
|
30
|
+
* @param names The option names to validate.
|
|
31
|
+
* @param label A human-readable label for error messages (e.g.,
|
|
32
|
+
* `"Option"`, `"Flag"`, `"Help option"`).
|
|
33
|
+
* @throws {TypeError} If the names array is empty, or any name is empty,
|
|
34
|
+
* lacks a valid prefix, or contains whitespace or control characters.
|
|
35
|
+
*/
|
|
36
|
+
function validateOptionNames(names, label) {
|
|
37
|
+
if (names.length === 0) throw new TypeError(`Expected at least one ${label.toLowerCase()} name.`);
|
|
38
|
+
for (const name of names) {
|
|
39
|
+
if (name === "") throw new TypeError(`${label} name must not be empty.`);
|
|
40
|
+
if (/^\s+$/.test(name)) throw new TypeError(`${label} name must not be whitespace-only: "${escapeControlChars(name)}".`);
|
|
41
|
+
if (CONTROL_CHAR_RE.test(name)) throw new TypeError(`${label} name must not contain control characters: "${escapeControlChars(name)}".`);
|
|
42
|
+
if (/\s/.test(name)) throw new TypeError(`${label} name must not contain whitespace: "${escapeControlChars(name)}".`);
|
|
43
|
+
if (!/^(--|[-/+])/.test(name)) throw new TypeError(`${label} name must start with "--", "-", "/", or "+": "${name}".`);
|
|
44
|
+
if (name === "--") throw new TypeError(`${label} name must not be the options terminator "--".`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Validates command names at runtime.
|
|
49
|
+
*
|
|
50
|
+
* @param names The command names to validate.
|
|
51
|
+
* @param label A human-readable label for error messages (e.g.,
|
|
52
|
+
* `"Help command"`).
|
|
53
|
+
* @throws {TypeError} If the names array is empty, or any name is empty,
|
|
54
|
+
* whitespace-only, or contains whitespace or control characters.
|
|
55
|
+
*/
|
|
56
|
+
function validateCommandNames(names, label) {
|
|
57
|
+
if (names.length === 0) throw new TypeError(`Expected at least one ${label.toLowerCase()} name.`);
|
|
58
|
+
for (const name of names) {
|
|
59
|
+
if (name === "") throw new TypeError(`${label} name must not be empty.`);
|
|
60
|
+
if (/^\s+$/.test(name)) throw new TypeError(`${label} name must not be whitespace-only: "${escapeControlChars(name)}".`);
|
|
61
|
+
if (CONTROL_CHAR_RE.test(name)) throw new TypeError(`${label} name must not contain control characters: "${escapeControlChars(name)}".`);
|
|
62
|
+
if (/\s/.test(name)) throw new TypeError(`${label} name must not contain whitespace: "${escapeControlChars(name)}".`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Validates that there are no name collisions among active meta features
|
|
67
|
+
* (help, version, completion).
|
|
68
|
+
*
|
|
69
|
+
* User parser names are accepted even when they overlap with meta names.
|
|
70
|
+
* Runtime parsing resolves those cases parser-first so ordinary parser data
|
|
71
|
+
* can shadow built-in meta behavior.
|
|
72
|
+
*
|
|
73
|
+
* Meta-vs-meta collisions are always checked in a unified namespace,
|
|
74
|
+
* because a meta command named `"--help"` and a meta option named
|
|
75
|
+
* `"--help"` both compete for the same token.
|
|
76
|
+
*
|
|
77
|
+
* @param metaEntries Active meta feature entries annotated with their kind.
|
|
78
|
+
* @throws {TypeError} If any meta/meta collision or duplicate is detected.
|
|
79
|
+
* @since 1.0.0
|
|
80
|
+
*/
|
|
81
|
+
function validateMetaNameCollisions(metaEntries) {
|
|
82
|
+
for (const [, label, names] of metaEntries) {
|
|
83
|
+
const seen = /* @__PURE__ */ new Set();
|
|
84
|
+
for (const name of names) {
|
|
85
|
+
if (seen.has(name)) throw new TypeError(`${capitalize(label)} has a duplicate name: "${name}"`);
|
|
86
|
+
seen.add(name);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
const nameToLabel = /* @__PURE__ */ new Map();
|
|
90
|
+
for (const [, label, names] of metaEntries) for (const name of names) {
|
|
91
|
+
const existingLabel = nameToLabel.get(name);
|
|
92
|
+
if (existingLabel != null) throw new TypeError(`Name "${name}" is used by both ${existingLabel} and ${label}.`);
|
|
93
|
+
nameToLabel.set(name, label);
|
|
94
|
+
}
|
|
95
|
+
for (let i = 0; i < metaEntries.length; i++) {
|
|
96
|
+
const [, label, names, prefixMatch] = metaEntries[i];
|
|
97
|
+
if (!prefixMatch) continue;
|
|
98
|
+
for (const name of names) {
|
|
99
|
+
const prefix = name + "=";
|
|
100
|
+
for (let j = 0; j < metaEntries.length; j++) {
|
|
101
|
+
const [, otherLabel, otherNames] = metaEntries[j];
|
|
102
|
+
for (const otherName of otherNames) {
|
|
103
|
+
if (i === j && otherName === name) continue;
|
|
104
|
+
if (!otherName.startsWith(prefix)) continue;
|
|
105
|
+
throw new TypeError("The prefix form of name \"" + name + "\" in " + label + " shadows \"" + otherName + "\" in " + otherLabel + ".");
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
function capitalize(s) {
|
|
112
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Validates a program name at runtime.
|
|
116
|
+
*
|
|
117
|
+
* Program names may contain spaces (e.g., file paths), but must not be empty,
|
|
118
|
+
* whitespace-only, or contain control characters.
|
|
119
|
+
*
|
|
120
|
+
* @param programName The program name to validate.
|
|
121
|
+
* @throws {TypeError} If the value is not a string, is empty,
|
|
122
|
+
* whitespace-only, or contains control characters.
|
|
123
|
+
*/
|
|
124
|
+
function validateProgramName(programName) {
|
|
125
|
+
if (typeof programName !== "string") throw new TypeError("Program name must be a string.");
|
|
126
|
+
if (programName === "") throw new TypeError("Program name must not be empty.");
|
|
127
|
+
if (/^\s+$/.test(programName)) throw new TypeError(`Program name must not be whitespace-only: "${escapeControlChars(programName)}".`);
|
|
128
|
+
if (CONTROL_CHAR_RE.test(programName)) throw new TypeError(`Program name must not contain control characters: "${escapeControlChars(programName)}".`);
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Validates a label at runtime.
|
|
132
|
+
*
|
|
133
|
+
* Labels are used as section titles in documentation output. They may contain
|
|
134
|
+
* spaces (e.g., "Connection options"), but must not be empty, whitespace-only,
|
|
135
|
+
* or contain control characters.
|
|
136
|
+
*
|
|
137
|
+
* @param label The label to validate.
|
|
138
|
+
* @throws {TypeError} If the label is not a string, is empty,
|
|
139
|
+
* whitespace-only, or contains control characters.
|
|
140
|
+
* @since 1.0.0
|
|
141
|
+
*/
|
|
142
|
+
function validateLabel(label) {
|
|
143
|
+
if (typeof label !== "string") throw new TypeError("Label must be a string.");
|
|
144
|
+
if (label === "") throw new TypeError("Label must not be empty.");
|
|
145
|
+
if (/^\s+$/.test(label)) throw new TypeError(`Label must not be whitespace-only: "${escapeControlChars(label)}".`);
|
|
146
|
+
if (CONTROL_CHAR_RE.test(label)) throw new TypeError(`Label must not contain control characters: "${escapeControlChars(label)}".`);
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Validates that all source contexts have unique
|
|
150
|
+
* {@link import("./context.ts").SourceContext.id | id} values.
|
|
151
|
+
*
|
|
152
|
+
* @param contexts The source contexts to validate.
|
|
153
|
+
* @throws {TypeError} If two or more contexts share the same id.
|
|
154
|
+
* @since 1.0.0
|
|
155
|
+
*/
|
|
156
|
+
function validateContextIds(contexts) {
|
|
157
|
+
const seen = /* @__PURE__ */ new Set();
|
|
158
|
+
for (const context of contexts) {
|
|
159
|
+
if (seen.has(context.id)) throw new TypeError(`Duplicate SourceContext id: ${String(context.id)}`);
|
|
160
|
+
seen.add(context.id);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
//#endregion
|
|
165
|
+
exports.validateCommandNames = validateCommandNames;
|
|
166
|
+
exports.validateContextIds = validateContextIds;
|
|
167
|
+
exports.validateLabel = validateLabel;
|
|
168
|
+
exports.validateMetaNameCollisions = validateMetaNameCollisions;
|
|
169
|
+
exports.validateOptionNames = validateOptionNames;
|
|
170
|
+
exports.validateProgramName = validateProgramName;
|
package/dist/validate.js
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
//#region src/validate.ts
|
|
2
|
+
/**
|
|
3
|
+
* Matches Unicode control characters: C0 (U+0000–U+001F), DEL (U+007F),
|
|
4
|
+
* C1 (U+0080–U+009F), and line separators (U+2028, U+2029).
|
|
5
|
+
*/
|
|
6
|
+
const CONTROL_CHAR_RE = /[\x00-\x1f\x7f-\x9f\u2028\u2029]/;
|
|
7
|
+
const CONTROL_CHAR_RE_GLOBAL = new RegExp(CONTROL_CHAR_RE.source, "g");
|
|
8
|
+
/**
|
|
9
|
+
* Escapes control characters in a string for readable error messages.
|
|
10
|
+
*
|
|
11
|
+
* @param value The string to escape.
|
|
12
|
+
* @returns The escaped string with control characters replaced by escape
|
|
13
|
+
* sequences.
|
|
14
|
+
*/
|
|
15
|
+
function escapeControlChars(value) {
|
|
16
|
+
return value.replace(CONTROL_CHAR_RE_GLOBAL, (ch) => {
|
|
17
|
+
const code = ch.charCodeAt(0);
|
|
18
|
+
switch (code) {
|
|
19
|
+
case 9: return "\\t";
|
|
20
|
+
case 10: return "\\n";
|
|
21
|
+
case 13: return "\\r";
|
|
22
|
+
default: return code > 255 ? `\\u${code.toString(16).padStart(4, "0")}` : `\\x${code.toString(16).padStart(2, "0")}`;
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Validates option names at runtime.
|
|
28
|
+
*
|
|
29
|
+
* @param names The option names to validate.
|
|
30
|
+
* @param label A human-readable label for error messages (e.g.,
|
|
31
|
+
* `"Option"`, `"Flag"`, `"Help option"`).
|
|
32
|
+
* @throws {TypeError} If the names array is empty, or any name is empty,
|
|
33
|
+
* lacks a valid prefix, or contains whitespace or control characters.
|
|
34
|
+
*/
|
|
35
|
+
function validateOptionNames(names, label) {
|
|
36
|
+
if (names.length === 0) throw new TypeError(`Expected at least one ${label.toLowerCase()} name.`);
|
|
37
|
+
for (const name of names) {
|
|
38
|
+
if (name === "") throw new TypeError(`${label} name must not be empty.`);
|
|
39
|
+
if (/^\s+$/.test(name)) throw new TypeError(`${label} name must not be whitespace-only: "${escapeControlChars(name)}".`);
|
|
40
|
+
if (CONTROL_CHAR_RE.test(name)) throw new TypeError(`${label} name must not contain control characters: "${escapeControlChars(name)}".`);
|
|
41
|
+
if (/\s/.test(name)) throw new TypeError(`${label} name must not contain whitespace: "${escapeControlChars(name)}".`);
|
|
42
|
+
if (!/^(--|[-/+])/.test(name)) throw new TypeError(`${label} name must start with "--", "-", "/", or "+": "${name}".`);
|
|
43
|
+
if (name === "--") throw new TypeError(`${label} name must not be the options terminator "--".`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Validates command names at runtime.
|
|
48
|
+
*
|
|
49
|
+
* @param names The command names to validate.
|
|
50
|
+
* @param label A human-readable label for error messages (e.g.,
|
|
51
|
+
* `"Help command"`).
|
|
52
|
+
* @throws {TypeError} If the names array is empty, or any name is empty,
|
|
53
|
+
* whitespace-only, or contains whitespace or control characters.
|
|
54
|
+
*/
|
|
55
|
+
function validateCommandNames(names, label) {
|
|
56
|
+
if (names.length === 0) throw new TypeError(`Expected at least one ${label.toLowerCase()} name.`);
|
|
57
|
+
for (const name of names) {
|
|
58
|
+
if (name === "") throw new TypeError(`${label} name must not be empty.`);
|
|
59
|
+
if (/^\s+$/.test(name)) throw new TypeError(`${label} name must not be whitespace-only: "${escapeControlChars(name)}".`);
|
|
60
|
+
if (CONTROL_CHAR_RE.test(name)) throw new TypeError(`${label} name must not contain control characters: "${escapeControlChars(name)}".`);
|
|
61
|
+
if (/\s/.test(name)) throw new TypeError(`${label} name must not contain whitespace: "${escapeControlChars(name)}".`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Validates that there are no name collisions among active meta features
|
|
66
|
+
* (help, version, completion).
|
|
67
|
+
*
|
|
68
|
+
* User parser names are accepted even when they overlap with meta names.
|
|
69
|
+
* Runtime parsing resolves those cases parser-first so ordinary parser data
|
|
70
|
+
* can shadow built-in meta behavior.
|
|
71
|
+
*
|
|
72
|
+
* Meta-vs-meta collisions are always checked in a unified namespace,
|
|
73
|
+
* because a meta command named `"--help"` and a meta option named
|
|
74
|
+
* `"--help"` both compete for the same token.
|
|
75
|
+
*
|
|
76
|
+
* @param metaEntries Active meta feature entries annotated with their kind.
|
|
77
|
+
* @throws {TypeError} If any meta/meta collision or duplicate is detected.
|
|
78
|
+
* @since 1.0.0
|
|
79
|
+
*/
|
|
80
|
+
function validateMetaNameCollisions(metaEntries) {
|
|
81
|
+
for (const [, label, names] of metaEntries) {
|
|
82
|
+
const seen = /* @__PURE__ */ new Set();
|
|
83
|
+
for (const name of names) {
|
|
84
|
+
if (seen.has(name)) throw new TypeError(`${capitalize(label)} has a duplicate name: "${name}"`);
|
|
85
|
+
seen.add(name);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
const nameToLabel = /* @__PURE__ */ new Map();
|
|
89
|
+
for (const [, label, names] of metaEntries) for (const name of names) {
|
|
90
|
+
const existingLabel = nameToLabel.get(name);
|
|
91
|
+
if (existingLabel != null) throw new TypeError(`Name "${name}" is used by both ${existingLabel} and ${label}.`);
|
|
92
|
+
nameToLabel.set(name, label);
|
|
93
|
+
}
|
|
94
|
+
for (let i = 0; i < metaEntries.length; i++) {
|
|
95
|
+
const [, label, names, prefixMatch] = metaEntries[i];
|
|
96
|
+
if (!prefixMatch) continue;
|
|
97
|
+
for (const name of names) {
|
|
98
|
+
const prefix = name + "=";
|
|
99
|
+
for (let j = 0; j < metaEntries.length; j++) {
|
|
100
|
+
const [, otherLabel, otherNames] = metaEntries[j];
|
|
101
|
+
for (const otherName of otherNames) {
|
|
102
|
+
if (i === j && otherName === name) continue;
|
|
103
|
+
if (!otherName.startsWith(prefix)) continue;
|
|
104
|
+
throw new TypeError("The prefix form of name \"" + name + "\" in " + label + " shadows \"" + otherName + "\" in " + otherLabel + ".");
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
function capitalize(s) {
|
|
111
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Validates a program name at runtime.
|
|
115
|
+
*
|
|
116
|
+
* Program names may contain spaces (e.g., file paths), but must not be empty,
|
|
117
|
+
* whitespace-only, or contain control characters.
|
|
118
|
+
*
|
|
119
|
+
* @param programName The program name to validate.
|
|
120
|
+
* @throws {TypeError} If the value is not a string, is empty,
|
|
121
|
+
* whitespace-only, or contains control characters.
|
|
122
|
+
*/
|
|
123
|
+
function validateProgramName(programName) {
|
|
124
|
+
if (typeof programName !== "string") throw new TypeError("Program name must be a string.");
|
|
125
|
+
if (programName === "") throw new TypeError("Program name must not be empty.");
|
|
126
|
+
if (/^\s+$/.test(programName)) throw new TypeError(`Program name must not be whitespace-only: "${escapeControlChars(programName)}".`);
|
|
127
|
+
if (CONTROL_CHAR_RE.test(programName)) throw new TypeError(`Program name must not contain control characters: "${escapeControlChars(programName)}".`);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Validates a label at runtime.
|
|
131
|
+
*
|
|
132
|
+
* Labels are used as section titles in documentation output. They may contain
|
|
133
|
+
* spaces (e.g., "Connection options"), but must not be empty, whitespace-only,
|
|
134
|
+
* or contain control characters.
|
|
135
|
+
*
|
|
136
|
+
* @param label The label to validate.
|
|
137
|
+
* @throws {TypeError} If the label is not a string, is empty,
|
|
138
|
+
* whitespace-only, or contains control characters.
|
|
139
|
+
* @since 1.0.0
|
|
140
|
+
*/
|
|
141
|
+
function validateLabel(label) {
|
|
142
|
+
if (typeof label !== "string") throw new TypeError("Label must be a string.");
|
|
143
|
+
if (label === "") throw new TypeError("Label must not be empty.");
|
|
144
|
+
if (/^\s+$/.test(label)) throw new TypeError(`Label must not be whitespace-only: "${escapeControlChars(label)}".`);
|
|
145
|
+
if (CONTROL_CHAR_RE.test(label)) throw new TypeError(`Label must not contain control characters: "${escapeControlChars(label)}".`);
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Validates that all source contexts have unique
|
|
149
|
+
* {@link import("./context.ts").SourceContext.id | id} values.
|
|
150
|
+
*
|
|
151
|
+
* @param contexts The source contexts to validate.
|
|
152
|
+
* @throws {TypeError} If two or more contexts share the same id.
|
|
153
|
+
* @since 1.0.0
|
|
154
|
+
*/
|
|
155
|
+
function validateContextIds(contexts) {
|
|
156
|
+
const seen = /* @__PURE__ */ new Set();
|
|
157
|
+
for (const context of contexts) {
|
|
158
|
+
if (seen.has(context.id)) throw new TypeError(`Duplicate SourceContext id: ${String(context.id)}`);
|
|
159
|
+
seen.add(context.id);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
//#endregion
|
|
164
|
+
export { validateCommandNames, validateContextIds, validateLabel, validateMetaNameCollisions, validateOptionNames, validateProgramName };
|