@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 +18 -4
- package/package.json +6 -5
- package/src/parser.ts +35 -5
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
|
|
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
|
|
34
|
-
|
|
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.
|
|
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.
|
|
52
|
-
"@reliverse/rempts-utils": "2.3.
|
|
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
|
|
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
|
|
58
|
-
|
|
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
|
-
//
|
|
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
|
*/
|