args-tokens 0.23.0 → 0.23.1

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.
@@ -1,283 +0,0 @@
1
- import { hasLongOptionPrefix, isShortOption } from "./parser-M-ayhS1h.js";
2
- import { kebabnize } from "./utils-1LQrGCWG.js";
3
-
4
- //#region src/resolver.ts
5
- const SKIP_POSITIONAL_DEFAULT = -1;
6
- /**
7
- * Resolve command line arguments.
8
- *
9
- * @typeParam A - {@link Args | Arguments}, which is an object that defines the command line arguments.
10
- *
11
- * @param args - An arguments that contains {@link ArgSchema | arguments schema}.
12
- * @param tokens - An array of {@link ArgToken | tokens}.
13
- * @param resolveArgs - An arguments that contains {@link ResolveArgs | resolve arguments}.
14
- * @returns An object that contains the values of the arguments, positional arguments, rest arguments, {@link AggregateError | validation errors}, and explicit provision status.
15
- *
16
- * @example
17
- * ```typescript
18
- * // passed tokens: --port 3000
19
- *
20
- * const { values, explicit } = resolveArgs({
21
- * port: {
22
- * type: 'number',
23
- * default: 8080
24
- * },
25
- * host: {
26
- * type: 'string',
27
- * default: 'localhost'
28
- * }
29
- * }, parsedTokens)
30
- *
31
- * values.port // 3000
32
- * values.host // 'localhost'
33
- *
34
- * explicit.port // true (explicitly provided)
35
- * explicit.host // false (not provided, fallback to default)
36
- * ```
37
- */
38
- function resolveArgs(args, tokens, { shortGrouping = false, skipPositional = SKIP_POSITIONAL_DEFAULT, toKebab = false } = {}) {
39
- const skipPositionalIndex = typeof skipPositional === "number" ? Math.max(skipPositional, SKIP_POSITIONAL_DEFAULT) : SKIP_POSITIONAL_DEFAULT;
40
- const rest = [];
41
- const optionTokens = [];
42
- const positionalTokens = [];
43
- let currentLongOption;
44
- let currentShortOption;
45
- const expandableShortOptions = [];
46
- function toShortValue() {
47
- if (expandableShortOptions.length === 0) return void 0;
48
- else {
49
- const value = expandableShortOptions.map((token) => token.name).join("");
50
- expandableShortOptions.length = 0;
51
- return value;
52
- }
53
- }
54
- function applyLongOptionValue(value = void 0) {
55
- if (currentLongOption) {
56
- currentLongOption.value = value;
57
- optionTokens.push({ ...currentLongOption });
58
- currentLongOption = void 0;
59
- }
60
- }
61
- function applyShortOptionValue(value = void 0) {
62
- if (currentShortOption) {
63
- currentShortOption.value = value || toShortValue();
64
- optionTokens.push({ ...currentShortOption });
65
- currentShortOption = void 0;
66
- }
67
- }
68
- /**
69
- * analyze phase to resolve value
70
- * separate tokens into positionals, long and short options, after that resolve values
71
- */
72
- const schemas = Object.values(args);
73
- let terminated = false;
74
- for (let i = 0; i < tokens.length; i++) {
75
- const token = tokens[i];
76
- if (token.kind === "positional") {
77
- if (terminated && token.value) {
78
- rest.push(token.value);
79
- continue;
80
- }
81
- if (currentShortOption) {
82
- const found = schemas.find((schema) => schema.short === currentShortOption.name && schema.type === "boolean");
83
- if (found) positionalTokens.push({ ...token });
84
- } else if (currentLongOption) {
85
- const found = args[currentLongOption.name]?.type === "boolean";
86
- if (found) positionalTokens.push({ ...token });
87
- } else positionalTokens.push({ ...token });
88
- applyLongOptionValue(token.value);
89
- applyShortOptionValue(token.value);
90
- } else if (token.kind === "option") if (token.rawName) {
91
- if (hasLongOptionPrefix(token.rawName)) {
92
- applyLongOptionValue();
93
- if (token.inlineValue) optionTokens.push({ ...token });
94
- else currentLongOption = { ...token };
95
- applyShortOptionValue();
96
- } else if (isShortOption(token.rawName)) if (currentShortOption) {
97
- if (currentShortOption.index === token.index) if (shortGrouping) {
98
- currentShortOption.value = token.value;
99
- optionTokens.push({ ...currentShortOption });
100
- currentShortOption = { ...token };
101
- } else expandableShortOptions.push({ ...token });
102
- else {
103
- currentShortOption.value = toShortValue();
104
- optionTokens.push({ ...currentShortOption });
105
- currentShortOption = { ...token };
106
- }
107
- applyLongOptionValue();
108
- } else {
109
- currentShortOption = { ...token };
110
- applyLongOptionValue();
111
- }
112
- } else {
113
- if (currentShortOption && currentShortOption.index == token.index && token.inlineValue) {
114
- currentShortOption.value = token.value;
115
- optionTokens.push({ ...currentShortOption });
116
- currentShortOption = void 0;
117
- }
118
- applyLongOptionValue();
119
- }
120
- else {
121
- if (token.kind === "option-terminator") terminated = true;
122
- applyLongOptionValue();
123
- applyShortOptionValue();
124
- }
125
- }
126
- /**
127
- * check if the last long or short option is not resolved
128
- */
129
- applyLongOptionValue();
130
- applyShortOptionValue();
131
- /**
132
- * resolve values
133
- */
134
- const values = Object.create(null);
135
- const errors = [];
136
- const explicit = Object.create(null);
137
- const actualInputNames = /* @__PURE__ */ new Map();
138
- function checkTokenName(option, schema, token) {
139
- return token.name === (schema.type === "boolean" ? schema.negatable && token.name?.startsWith("no-") ? `no-${option}` : option : option);
140
- }
141
- const positionalItemCount = tokens.filter((token) => token.kind === "positional").length;
142
- function getPositionalSkipIndex() {
143
- return Math.min(skipPositionalIndex, positionalItemCount);
144
- }
145
- let positionalsCount = 0;
146
- for (const [rawArg, schema] of Object.entries(args)) {
147
- const arg = toKebab || schema.toKebab ? kebabnize(rawArg) : rawArg;
148
- explicit[rawArg] = false;
149
- if (schema.type === "positional") {
150
- if (skipPositionalIndex > SKIP_POSITIONAL_DEFAULT) while (positionalsCount <= getPositionalSkipIndex()) positionalsCount++;
151
- if (schema.multiple) {
152
- const remainingPositionals = positionalTokens.slice(positionalsCount);
153
- if (remainingPositionals.length > 0) {
154
- values[rawArg] = remainingPositionals.map((p) => p.value);
155
- positionalsCount += remainingPositionals.length;
156
- } else if (schema.required) errors.push(createRequireError(arg, schema));
157
- } else {
158
- const positional = positionalTokens[positionalsCount];
159
- if (positional != null) values[rawArg] = positional.value;
160
- else errors.push(createRequireError(arg, schema));
161
- positionalsCount++;
162
- }
163
- continue;
164
- }
165
- if (schema.required) {
166
- const found = optionTokens.find((token) => {
167
- return schema.short && token.name === schema.short || token.rawName && hasLongOptionPrefix(token.rawName) && token.name === arg;
168
- });
169
- if (!found) {
170
- errors.push(createRequireError(arg, schema));
171
- continue;
172
- }
173
- }
174
- for (let i = 0; i < optionTokens.length; i++) {
175
- const token = optionTokens[i];
176
- if (checkTokenName(arg, schema, token) && token.rawName != void 0 && hasLongOptionPrefix(token.rawName) || schema.short === token.name && token.rawName != void 0 && isShortOption(token.rawName)) {
177
- const invalid = validateRequire(token, arg, schema);
178
- if (invalid) {
179
- errors.push(invalid);
180
- continue;
181
- }
182
- explicit[rawArg] = true;
183
- const actualInputName = isShortOption(token.rawName) ? `-${token.name}` : `--${arg}`;
184
- actualInputNames.set(rawArg, actualInputName);
185
- if (schema.type === "boolean") token.value = void 0;
186
- const [parsedValue, error] = parse(token, arg, schema);
187
- if (error) errors.push(error);
188
- else if (schema.multiple) {
189
- values[rawArg] ||= [];
190
- values[rawArg].push(parsedValue);
191
- } else values[rawArg] = parsedValue;
192
- }
193
- }
194
- if (values[rawArg] == null && schema.default != null) values[rawArg] = schema.default;
195
- }
196
- const conflictErrors = checkConflicts(args, explicit, toKebab, actualInputNames);
197
- errors.push(...conflictErrors);
198
- return {
199
- values,
200
- positionals: positionalTokens.map((token) => token.value),
201
- rest,
202
- error: errors.length > 0 ? new AggregateError(errors) : void 0,
203
- explicit
204
- };
205
- }
206
- function parse(token, option, schema) {
207
- switch (schema.type) {
208
- case "string": return typeof token.value === "string" ? [token.value || schema.default, void 0] : [void 0, createTypeError(option, schema)];
209
- case "boolean": return token.value ? [token.value || schema.default, void 0] : [!(schema.negatable && token.name.startsWith("no-")), void 0];
210
- case "number":
211
- if (!isNumeric(token.value)) return [void 0, createTypeError(option, schema)];
212
- return token.value ? [+token.value, void 0] : [+(schema.default || ""), void 0];
213
- case "enum":
214
- if (schema.choices && !schema.choices.includes(token.value)) return [void 0, new ArgResolveError(`Optional argument '--${option}' ${schema.short ? `or '-${schema.short}' ` : ""}should be chosen from '${schema.type}' [${schema.choices.map((c) => JSON.stringify(c)).join(", ")}] values`, option, "type", schema)];
215
- return [token.value || schema.default, void 0];
216
- case "custom":
217
- if (typeof schema.parse !== "function") throw new TypeError(`argument '${option}' should have a 'parse' function`);
218
- try {
219
- return [schema.parse(token.value || String(schema.default || "")), void 0];
220
- } catch (error) {
221
- return [void 0, error];
222
- }
223
- default: throw new Error(`Unsupported argument type '${schema.type}' for option '${option}'`);
224
- }
225
- }
226
- function createRequireError(option, schema) {
227
- const message = schema.type === "positional" ? `Positional argument '${option}' is required` : `Optional argument '--${option}' ${schema.short ? `or '-${schema.short}' ` : ""}is required`;
228
- return new ArgResolveError(message, option, "required", schema);
229
- }
230
- /**
231
- * An error that occurs when resolving arguments.
232
- * This error is thrown when the argument is not valid.
233
- */
234
- var ArgResolveError = class extends Error {
235
- name;
236
- schema;
237
- type;
238
- /**
239
- * Create an `ArgResolveError` instance.
240
- *
241
- * @param message - the error message
242
- * @param name - the name of the argument
243
- * @param type - the type of the error, either 'type' or 'required'
244
- * @param schema - the argument schema that caused the error
245
- */
246
- constructor(message, name, type, schema) {
247
- super(message);
248
- this.name = name;
249
- this.type = type;
250
- this.schema = schema;
251
- }
252
- };
253
- function validateRequire(token, option, schema) {
254
- if (schema.required && schema.type !== "boolean" && !token.value) return createRequireError(option, schema);
255
- }
256
- function isNumeric(str) {
257
- return str.trim() !== "" && !isNaN(str);
258
- }
259
- function createTypeError(option, schema) {
260
- return new ArgResolveError(`Optional argument '--${option}' ${schema.short ? `or '-${schema.short}' ` : ""}should be '${schema.type}'`, option, "type", schema);
261
- }
262
- function checkConflicts(args, explicit, toKebab, actualInputNames) {
263
- for (const rawArg in args) {
264
- const schema = args[rawArg];
265
- if (!explicit[rawArg]) continue;
266
- if (!schema.conflicts) continue;
267
- const conflicts = Array.isArray(schema.conflicts) ? schema.conflicts : [schema.conflicts];
268
- for (let i = 0; i < conflicts.length; i++) {
269
- const conflictingArg = conflicts[i];
270
- if (!explicit[conflictingArg]) continue;
271
- const arg = toKebab || schema.toKebab ? kebabnize(rawArg) : rawArg;
272
- const conflictingArgKebab = toKebab || args[conflictingArg]?.toKebab ? kebabnize(conflictingArg) : conflictingArg;
273
- const optionActualName = actualInputNames.get(rawArg) || `--${arg}`;
274
- const conflictingActualName = actualInputNames.get(conflictingArg) || `--${conflictingArgKebab}`;
275
- const message = `Optional argument '${optionActualName}' conflicts with '${conflictingActualName}'`;
276
- return [new ArgResolveError(message, rawArg, "conflict", schema)];
277
- }
278
- }
279
- return [];
280
- }
281
-
282
- //#endregion
283
- export { ArgResolveError, resolveArgs };