@reliverse/rempts-core 2.3.2 → 2.3.4

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/parser.js CHANGED
@@ -1,4 +1,7 @@
1
1
  import { RemptsValidationError } from "./types.js";
2
+ function kebabToCamel(str) {
3
+ return str.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
4
+ }
2
5
  export async function parseArgs(args, options, commandName = "unknown") {
3
6
  const flags = {};
4
7
  const positional = [];
@@ -24,22 +27,27 @@ export async function parseArgs(args, options, commandName = "unknown") {
24
27
  }
25
28
  if (arg.startsWith("--")) {
26
29
  const eqIndex = arg.indexOf("=");
27
- const name = eqIndex > 0 ? arg.slice(2, eqIndex) : arg.slice(2);
30
+ const kebabName = eqIndex > 0 ? arg.slice(2, eqIndex) : arg.slice(2);
31
+ const name = kebabToCamel(kebabName);
28
32
  const inlineValue = eqIndex > 0 ? arg.slice(eqIndex + 1) : void 0;
29
33
  if (!(name && options[name])) {
30
34
  continue;
31
35
  }
32
36
  let value = inlineValue;
33
- if (value === void 0 && i + 1 < args.length && !args[i + 1]?.startsWith("-")) {
34
- value = args[++i];
37
+ if (value === void 0) {
38
+ const isStrictBooleanFlag = await isStrictBooleanOption(options[name]?.schema);
39
+ if (!isStrictBooleanFlag && i + 1 < args.length && !args[i + 1]?.startsWith("-")) {
40
+ value = args[++i];
41
+ }
35
42
  }
36
43
  flags[name] = await validateOption(name, value ?? "true", options[name]?.schema, commandName);
37
44
  } else if (arg.startsWith("-") && arg.length > 1) {
38
45
  const short = arg.slice(1);
39
46
  const name = shortToName.get(short);
40
47
  if (name && options[name]) {
48
+ const isStrictBooleanFlag = await isStrictBooleanOption(options[name]?.schema);
41
49
  let value;
42
- if (i + 1 < args.length && !args[i + 1]?.startsWith("-")) {
50
+ if (!isStrictBooleanFlag && i + 1 < args.length && !args[i + 1]?.startsWith("-")) {
43
51
  value = args[++i];
44
52
  }
45
53
  flags[name] = await validateOption(
@@ -119,6 +127,12 @@ function extractSchemaType(schema) {
119
127
  }
120
128
  return "unknown";
121
129
  }
130
+ async function isStrictBooleanOption(schema) {
131
+ const trueResult = await schema["~standard"].validate(true);
132
+ const falseResult = await schema["~standard"].validate(false);
133
+ const stringResult = await schema["~standard"].validate("true");
134
+ return !(trueResult.issues || falseResult.issues) && !!stringResult.issues;
135
+ }
122
136
  function generateHint(schema, value) {
123
137
  const type = extractSchemaType(schema);
124
138
  if (type === "boolean" && typeof value === "string") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reliverse/rempts-core",
3
- "version": "2.3.2",
3
+ "version": "2.3.4",
4
4
  "description": "Minimal, type-safe CLI framework for Bun",
5
5
  "keywords": [
6
6
  "bun",
@@ -29,7 +29,7 @@
29
29
  ],
30
30
  "type": "module",
31
31
  "module": "./dist/mod.js",
32
- "types": "./dist/mod.d.ts",
32
+ "types": "./dist/mod.d.d.d.ts",
33
33
  "exports": {
34
34
  ".": {
35
35
  "types": "./dist/mod.d.ts",
@@ -48,12 +48,13 @@
48
48
  "access": "public"
49
49
  },
50
50
  "dependencies": {
51
- "@reliverse/relico": "2.3.2",
52
- "@reliverse/rempts-utils": "2.3.2",
51
+ "@reliverse/relico": "2.3.4",
52
+ "@reliverse/rempts-utils": "2.3.4",
53
53
  "@standard-schema/spec": "^1.1.0",
54
54
  "@standard-schema/utils": "^0.3.0",
55
55
  "arktype": "^2.1.29",
56
- "zustand": "^5.0.9"
56
+ "zustand": "^5.0.9",
57
+ "left-pad": "^1.3.0"
57
58
  },
58
59
  "engines": {
59
60
  "bun": ">=1.3.5"
package/src/parser.ts CHANGED
@@ -6,6 +6,13 @@ export interface ParsedArgs<TOptions extends Options = Options> {
6
6
  positional: string[];
7
7
  }
8
8
 
9
+ /**
10
+ * Convert kebab-case string to camelCase
11
+ */
12
+ function kebabToCamel(str: string): string {
13
+ return str.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
14
+ }
15
+
9
16
  export async function parseArgs<TOptions extends Options = Options>(
10
17
  args: string[],
11
18
  options: TOptions,
@@ -45,7 +52,8 @@ export async function parseArgs<TOptions extends Options = Options>(
45
52
  if (arg.startsWith("--")) {
46
53
  // Long flag: --name or --name=value
47
54
  const eqIndex = arg.indexOf("=");
48
- const name = eqIndex > 0 ? arg.slice(2, eqIndex) : arg.slice(2);
55
+ const kebabName = eqIndex > 0 ? arg.slice(2, eqIndex) : arg.slice(2);
56
+ const name = kebabToCamel(kebabName);
49
57
  const inlineValue = eqIndex > 0 ? arg.slice(eqIndex + 1) : undefined;
50
58
 
51
59
  if (!(name && options[name])) {
@@ -54,8 +62,12 @@ export async function parseArgs<TOptions extends Options = Options>(
54
62
 
55
63
  // Get the value (inline, next arg, or 'true' for boolean-like flags)
56
64
  let value: string | undefined = inlineValue;
57
- if (value === undefined && i + 1 < args.length && !args[i + 1]?.startsWith("-")) {
58
- value = args[++i];
65
+ if (value === undefined) {
66
+ // Check if this option only accepts boolean values
67
+ const isStrictBooleanFlag = await isStrictBooleanOption(options[name]?.schema);
68
+ if (!isStrictBooleanFlag && i + 1 < args.length && !args[i + 1]?.startsWith("-")) {
69
+ value = args[++i];
70
+ }
59
71
  }
60
72
 
61
73
  // Pass the value to the schema for validation
@@ -66,9 +78,12 @@ export async function parseArgs<TOptions extends Options = Options>(
66
78
  const name = shortToName.get(short);
67
79
 
68
80
  if (name && options[name]) {
69
- // Get the next argument as value if available
81
+ // Check if this option only accepts boolean values (not boolean|string)
82
+ const isStrictBooleanFlag = await isStrictBooleanOption(options[name]?.schema);
83
+
84
+ // Get the next argument as value only if it's not a strict boolean flag
70
85
  let value: string | undefined;
71
- if (i + 1 < args.length && !args[i + 1]?.startsWith("-")) {
86
+ if (!isStrictBooleanFlag && i + 1 < args.length && !args[i + 1]?.startsWith("-")) {
72
87
  value = args[++i];
73
88
  }
74
89
 
@@ -190,6 +205,21 @@ function extractSchemaType(schema: StandardSchemaV1): string {
190
205
  return "unknown";
191
206
  }
192
207
 
208
+ /**
209
+ * Check if a schema ONLY accepts boolean values (not boolean|string etc.)
210
+ */
211
+ async function isStrictBooleanOption(schema: StandardSchemaV1): Promise<boolean> {
212
+ // Check if it accepts boolean values
213
+ const trueResult = await schema["~standard"].validate(true);
214
+ const falseResult = await schema["~standard"].validate(false);
215
+
216
+ // Check if it rejects non-boolean values
217
+ const stringResult = await schema["~standard"].validate("true");
218
+
219
+ // It's a strict boolean if it accepts true/false but rejects strings
220
+ return !(trueResult.issues || falseResult.issues) && !!stringResult.issues;
221
+ }
222
+
193
223
  /**
194
224
  * Generate a helpful hint based on the schema and value
195
225
  */