args-tokens 0.18.0 → 0.19.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/lib/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { ArgToken, ParserOptions, parseArgs$1 as parseArgs } from "./parser-Bx112mWZ.js";
2
- import { ArgResolveError$1 as ArgResolveError, ArgResolveErrorType, ArgSchema, ArgValues, Args, ResolveArgs, resolveArgs$1 as resolveArgs } from "./resolver-D_oOCXlX.js";
2
+ import { ArgResolveError$1 as ArgResolveError, ArgResolveErrorType, ArgSchema, ArgValues, Args, ResolveArgs, resolveArgs$1 as resolveArgs } from "./resolver-COGeGqd3.js";
3
3
 
4
4
  //#region src/parse.d.ts
5
5
  /**
package/lib/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { parseArgs } from "./parser-Dr4iAGaX.js";
2
- import { ArgResolveError, resolveArgs } from "./resolver-_BCsM-y_.js";
2
+ import { ArgResolveError, resolveArgs } from "./resolver-Df1uPA8Z.js";
3
3
 
4
4
  //#region src/parse.ts
5
5
  const DEFAULT_OPTIONS = {
@@ -6,7 +6,7 @@ import { ArgToken } from "./parser-Bx112mWZ.js";
6
6
  * This schema is similar to the schema of the `node:utils`.
7
7
  * difference is that:
8
8
  * - `required` property and `description` property are added
9
- * - `type` is not only 'string' and 'boolean', but also 'number', 'enum' and 'positional' too.
9
+ * - `type` is not only 'string' and 'boolean', but also 'number', 'enum', 'positional', 'custom' too.
10
10
  * - `default` property type, not support multiple types
11
11
  */
12
12
  /**
@@ -14,16 +14,16 @@ import { ArgToken } from "./parser-Bx112mWZ.js";
14
14
  * This schema is similar to the schema of the `node:utils`.
15
15
  * difference is that:
16
16
  * - `required` property and `description` property are added
17
- * - `type` is not only 'string' and 'boolean', but also 'number', 'enum' and 'positional' too.
17
+ * - `type` is not only 'string' and 'boolean', but also 'number', 'enum', 'positional', 'custom' too.
18
18
  * - `default` property type, not support multiple types
19
19
  */
20
20
  interface ArgSchema {
21
21
  /**
22
22
  * Type of argument.
23
23
  */
24
- type: "string" | "boolean" | "number" | "enum" | "positional";
24
+ type: "string" | "boolean" | "number" | "enum" | "positional" | "custom";
25
25
  /**
26
- * A single character alias for the option.
26
+ * A single character alias for the argument.
27
27
  */
28
28
  short?: string;
29
29
  /**
@@ -51,6 +51,19 @@ interface ArgSchema {
51
51
  * if the type is 'enum', the default value must be one of the allowed values.
52
52
  */
53
53
  default?: string | boolean | number;
54
+ /**
55
+ * Whether to convert the argument name to kebab-case.
56
+ */
57
+ toKebab?: true;
58
+ /**
59
+ * A function to parse the value of the argument. if the type is 'custom', this function is required.
60
+ * If argument value will be invalid, this function have to throw an error.
61
+ * @param value
62
+ * @returns Parsed value
63
+ * @throws An Error, If the value is invalid. Error type should be `Error` or extends it
64
+ */
65
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
66
+ parse?: (value: string) => any;
54
67
  }
55
68
  /**
56
69
  * An object that contains {@link ArgSchema | argument schema}.
@@ -64,10 +77,12 @@ interface Args {
64
77
  type ArgValues<T> = T extends Args ? ResolveArgValues<T, { [Arg in keyof T]: ExtractOptionValue<T[Arg]> }> : {
65
78
  [option: string]: string | boolean | number | (string | boolean | number)[] | undefined;
66
79
  };
80
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
81
+ type IsFunction<T> = T extends ((...args: any[]) => any) ? true : false;
67
82
  /**
68
83
  * @internal
69
84
  */
70
- type ExtractOptionValue<A extends ArgSchema> = A["type"] extends "string" ? ResolveOptionValue<A, string> : A["type"] extends "boolean" ? ResolveOptionValue<A, boolean> : A["type"] extends "number" ? ResolveOptionValue<A, number> : A["type"] extends "positional" ? ResolveOptionValue<A, string> : A["type"] extends "enum" ? A["choices"] extends string[] | readonly string[] ? ResolveOptionValue<A, A["choices"][number]> : never : ResolveOptionValue<A, string | boolean | number>;
85
+ type ExtractOptionValue<A extends ArgSchema> = A["type"] extends "string" ? ResolveOptionValue<A, string> : A["type"] extends "boolean" ? ResolveOptionValue<A, boolean> : A["type"] extends "number" ? ResolveOptionValue<A, number> : A["type"] extends "positional" ? ResolveOptionValue<A, string> : A["type"] extends "enum" ? A["choices"] extends string[] | readonly string[] ? ResolveOptionValue<A, A["choices"][number]> : never : A["type"] extends "custom" ? IsFunction<A["parse"]> extends true ? ResolveOptionValue<A, ReturnType<NonNullable<A["parse"]>>> : never : ResolveOptionValue<A, string | boolean | number>;
71
86
  type ResolveOptionValue<A extends ArgSchema, T> = A["multiple"] extends true ? T[] : T;
72
87
  /**
73
88
  * @internal
@@ -82,16 +97,21 @@ type FilterArgs<A extends Args, V extends Record<keyof A, unknown>, K extends ke
82
97
  */
83
98
  interface ResolveArgs {
84
99
  /**
85
- * Whether to group short options.
100
+ * Whether to group short arguments.
86
101
  * @default false
87
102
  * @see guideline 5 in https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap12.html
88
103
  */
89
- optionGrouping?: boolean;
104
+ shortGrouping?: boolean;
90
105
  /**
91
106
  * Skip positional arguments index.
92
107
  * @default -1
93
108
  */
94
109
  skipPositional?: number;
110
+ /**
111
+ * Whether to convert the argument name to kebab-case. This option is applied to all arguments as `toKebab: true`, if set to `true`.
112
+ * @default false
113
+ */
114
+ toKebab?: boolean;
95
115
  }
96
116
  /**
97
117
  * Resolve command line arguments.
@@ -101,8 +121,9 @@ interface ResolveArgs {
101
121
  * @returns An object that contains the values of the arguments, positional arguments, rest arguments, and {@link AggregateError | validation errors}.
102
122
  */
103
123
  declare function resolveArgs<A extends Args>(args: A, tokens: ArgToken[], {
104
- optionGrouping,
105
- skipPositional
124
+ shortGrouping,
125
+ skipPositional,
126
+ toKebab
106
127
  }?: ResolveArgs): {
107
128
  values: ArgValues<A>;
108
129
  positionals: string[];
@@ -2,6 +2,9 @@ import { hasLongOptionPrefix, isShortOption } from "./parser-Dr4iAGaX.js";
2
2
 
3
3
  //#region src/resolver.ts
4
4
  const SKIP_POSITIONAL_DEFAULT = -1;
5
+ function kebabnize(str) {
6
+ return str.replace(/[A-Z]/g, (match, offset) => (offset > 0 ? "-" : "") + match.toLowerCase());
7
+ }
5
8
  /**
6
9
  * Resolve command line arguments.
7
10
  * @param args - An arguments that contains {@link ArgSchema | arguments schema}.
@@ -9,7 +12,7 @@ const SKIP_POSITIONAL_DEFAULT = -1;
9
12
  * @param resolveArgs - An arguments that contains {@link ResolveArgs | resolve arguments}.
10
13
  * @returns An object that contains the values of the arguments, positional arguments, rest arguments, and {@link AggregateError | validation errors}.
11
14
  */
12
- function resolveArgs(args, tokens, { optionGrouping = false, skipPositional = SKIP_POSITIONAL_DEFAULT } = {}) {
15
+ function resolveArgs(args, tokens, { shortGrouping = false, skipPositional = SKIP_POSITIONAL_DEFAULT, toKebab = false } = {}) {
13
16
  const skipPositionalIndex = typeof skipPositional === "number" ? Math.max(skipPositional, SKIP_POSITIONAL_DEFAULT) : SKIP_POSITIONAL_DEFAULT;
14
17
  const rest = [];
15
18
  const optionTokens = [];
@@ -68,7 +71,7 @@ function resolveArgs(args, tokens, { optionGrouping = false, skipPositional = SK
68
71
  else currentLongOption = { ...token };
69
72
  applyShortOptionValue();
70
73
  } else if (isShortOption(token.rawName)) if (currentShortOption) {
71
- if (currentShortOption.index === token.index) if (optionGrouping) {
74
+ if (currentShortOption.index === token.index) if (shortGrouping) {
72
75
  currentShortOption.value = token.value;
73
76
  optionTokens.push({ ...currentShortOption });
74
77
  currentShortOption = { ...token };
@@ -115,48 +118,43 @@ function resolveArgs(args, tokens, { optionGrouping = false, skipPositional = SK
115
118
  return Math.min(skipPositionalIndex, positionalItemCount);
116
119
  }
117
120
  let positionalsCount = 0;
118
- for (const [option, schema] of Object.entries(args)) {
121
+ for (const [rawArg, schema] of Object.entries(args)) {
122
+ const arg = toKebab || schema.toKebab ? kebabnize(rawArg) : rawArg;
119
123
  if (schema.required) {
120
124
  const found = optionTokens.find((token) => {
121
- return schema.short && token.name === schema.short || token.rawName && hasLongOptionPrefix(token.rawName) && token.name === option;
125
+ return schema.short && token.name === schema.short || token.rawName && hasLongOptionPrefix(token.rawName) && token.name === arg;
122
126
  });
123
127
  if (!found) {
124
- errors.push(createRequireError(option, schema));
128
+ errors.push(createRequireError(arg, schema));
125
129
  continue;
126
130
  }
127
131
  }
128
132
  if (schema.type === "positional") {
129
133
  if (skipPositionalIndex > SKIP_POSITIONAL_DEFAULT) while (positionalsCount <= getPositionalSkipIndex()) positionalsCount++;
130
134
  const positional = positionalTokens[positionalsCount];
131
- if (positional != null) values[option] = positional.value;
132
- else errors.push(createRequireError(option, schema));
135
+ if (positional != null) values[rawArg] = positional.value;
136
+ else errors.push(createRequireError(arg, schema));
133
137
  positionalsCount++;
134
138
  continue;
135
139
  }
136
140
  for (let i = 0; i < optionTokens.length; i++) {
137
141
  const token = optionTokens[i];
138
- if (checkTokenName(option, schema, token) && token.rawName != void 0 && hasLongOptionPrefix(token.rawName) || schema.short === token.name && token.rawName != void 0 && isShortOption(token.rawName)) {
139
- const invalid = validateRequire(token, option, schema);
142
+ if (checkTokenName(arg, schema, token) && token.rawName != void 0 && hasLongOptionPrefix(token.rawName) || schema.short === token.name && token.rawName != void 0 && isShortOption(token.rawName)) {
143
+ const invalid = validateRequire(token, arg, schema);
140
144
  if (invalid) {
141
145
  errors.push(invalid);
142
146
  continue;
143
147
  }
144
148
  if (schema.type === "boolean") token.value = void 0;
145
- else {
146
- const invalid$1 = validateValue(token, option, schema);
147
- if (invalid$1) {
148
- errors.push(invalid$1);
149
- continue;
150
- }
151
- }
152
- if (schema.multiple) {
153
- values[option] ||= [];
154
- values[option].push(resolveArgumentValue(token, schema));
155
- } else values[option] = resolveArgumentValue(token, schema);
156
- continue;
149
+ const [parsedValue, error] = parse(token, arg, schema);
150
+ if (error) errors.push(error);
151
+ else if (schema.multiple) {
152
+ values[rawArg] ||= [];
153
+ values[rawArg].push(parsedValue);
154
+ } else values[rawArg] = parsedValue;
157
155
  }
158
156
  }
159
- if (values[option] == null && schema.default != null) values[option] = schema.default;
157
+ if (values[rawArg] == null && schema.default != null) values[rawArg] = schema.default;
160
158
  }
161
159
  return {
162
160
  values,
@@ -165,6 +163,29 @@ function resolveArgs(args, tokens, { optionGrouping = false, skipPositional = SK
165
163
  error: errors.length > 0 ? new AggregateError(errors) : void 0
166
164
  };
167
165
  }
166
+ function parse(token, option, schema) {
167
+ switch (schema.type) {
168
+ case "string": return typeof token.value === "string" ? [token.value || schema.default, void 0] : [void 0, createTypeError(option, schema)];
169
+ case "boolean": return token.value ? [token.value || schema.default, void 0] : [!(schema.negatable && token.name.startsWith("no-")), void 0];
170
+ case "number": {
171
+ if (!isNumeric(token.value)) return [void 0, createTypeError(option, schema)];
172
+ return token.value ? [+token.value, void 0] : [+(schema.default || ""), void 0];
173
+ }
174
+ case "enum": {
175
+ 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)];
176
+ return [token.value || schema.default, void 0];
177
+ }
178
+ case "custom": {
179
+ if (typeof schema.parse !== "function") throw new TypeError(`argument '${option}' should have a 'parse' function`);
180
+ try {
181
+ return [schema.parse(token.value || String(schema.default || "")), void 0];
182
+ } catch (error) {
183
+ return [void 0, error];
184
+ }
185
+ }
186
+ default: throw new Error(`Unsupported argument type '${schema.type}' for option '${option}'`);
187
+ }
188
+ }
168
189
  function createRequireError(option, schema) {
169
190
  const message = schema.type === "positional" ? `Positional argument '${option}' is required` : `Optional argument '--${option}' ${schema.short ? `or '-${schema.short}' ` : ""}is required`;
170
191
  return new ArgResolveError(message, option, "required", schema);
@@ -187,33 +208,12 @@ var ArgResolveError = class extends Error {
187
208
  function validateRequire(token, option, schema) {
188
209
  if (schema.required && schema.type !== "boolean" && !token.value) return createRequireError(option, schema);
189
210
  }
190
- function validateValue(token, option, schema) {
191
- switch (schema.type) {
192
- case "number": {
193
- if (!isNumeric(token.value)) return createTypeError(option, schema);
194
- break;
195
- }
196
- case "string": {
197
- if (typeof token.value !== "string") return createTypeError(option, schema);
198
- break;
199
- }
200
- case "enum": {
201
- if (schema.choices && !schema.choices.includes(token.value)) return 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);
202
- break;
203
- }
204
- }
205
- }
206
211
  function isNumeric(str) {
207
212
  return str.trim() !== "" && !isNaN(str);
208
213
  }
209
214
  function createTypeError(option, schema) {
210
215
  return new ArgResolveError(`Optional argument '--${option}' ${schema.short ? `or '-${schema.short}' ` : ""}should be '${schema.type}'`, option, "type", schema);
211
216
  }
212
- function resolveArgumentValue(token, schema) {
213
- if (token.value) return schema.type === "number" ? +token.value : token.value;
214
- if (schema.type === "boolean") return schema.negatable && token.name.startsWith("no-") ? false : true;
215
- return schema.type === "number" ? +(schema.default || "") : schema.default;
216
- }
217
217
 
218
218
  //#endregion
219
219
  export { ArgResolveError, resolveArgs };
package/lib/resolver.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  import "./parser-Bx112mWZ.js";
2
- import { ArgResolveError$1 as ArgResolveError, ArgResolveErrorType, ArgSchema, ArgValues, Args, ExtractOptionValue, FilterArgs, ResolveArgValues, ResolveArgs, resolveArgs$1 as resolveArgs } from "./resolver-D_oOCXlX.js";
2
+ import { ArgResolveError$1 as ArgResolveError, ArgResolveErrorType, ArgSchema, ArgValues, Args, ExtractOptionValue, FilterArgs, ResolveArgValues, ResolveArgs, resolveArgs$1 as resolveArgs } from "./resolver-COGeGqd3.js";
3
3
  export { ArgResolveError, ArgResolveErrorType, ArgSchema, ArgValues, Args, ExtractOptionValue, FilterArgs, ResolveArgValues, ResolveArgs, resolveArgs };
package/lib/resolver.js CHANGED
@@ -1,4 +1,4 @@
1
1
  import "./parser-Dr4iAGaX.js";
2
- import { ArgResolveError, resolveArgs } from "./resolver-_BCsM-y_.js";
2
+ import { ArgResolveError, resolveArgs } from "./resolver-Df1uPA8Z.js";
3
3
 
4
4
  export { ArgResolveError, resolveArgs };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "args-tokens",
3
3
  "description": "parseArgs tokens compatibility and more high-performance parser",
4
- "version": "0.18.0",
4
+ "version": "0.19.0",
5
5
  "author": {
6
6
  "name": "kazuya kawaguchi",
7
7
  "email": "kawakazu80@gmail.com"
@@ -69,7 +69,7 @@
69
69
  "@kazupon/eslint-config": "^0.29.0",
70
70
  "@kazupon/prettier-config": "^0.1.1",
71
71
  "@types/node": "^22.15.21",
72
- "@typescript/native-preview": "7.0.0-dev.20250522.2",
72
+ "@typescript/native-preview": "7.0.0-dev.20250525.1",
73
73
  "@vitest/eslint-plugin": "^1.2.0",
74
74
  "bumpp": "^10.1.1",
75
75
  "deno": "^2.3.3",
@@ -91,7 +91,8 @@
91
91
  "tsdown": "^0.12.1",
92
92
  "typescript": "^5.8.3",
93
93
  "typescript-eslint": "^8.32.1",
94
- "vitest": "^3.1.4"
94
+ "vitest": "^3.1.4",
95
+ "zod": "^3.25.28"
95
96
  },
96
97
  "prettier": "@kazupon/prettier-config",
97
98
  "lint-staged": {
@@ -124,7 +125,7 @@
124
125
  "lint:knip": "knip",
125
126
  "lint:prettier": "prettier . --check",
126
127
  "release": "bumpp --commit \"release: v%s\" --all --push --tag",
127
- "test": "vitest run",
128
+ "test": "vitest run --typecheck",
128
129
  "typecheck": "pnpm run --parallel --color \"/^typecheck:/\"",
129
130
  "typecheck:deno": "deno check src",
130
131
  "typecheck:tsc": "tsgo --noEmit"