zodline 0.2.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/LICENSE +21 -0
- package/README.md +258 -0
- package/dist/config.d.ts +11 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +10 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +507 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +29 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +7 -0
- package/dist/types.js.map +1 -0
- package/example.js +65 -0
- package/package.json +67 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Robin Genz
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
# zodline
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/zodline)
|
|
4
|
+
[](https://www.npmjs.com/package/zodline)
|
|
5
|
+
[](https://github.com/robingenz/zodline/blob/main/LICENSE)
|
|
6
|
+
|
|
7
|
+
A powerful CLI parser built with TypeScript and Zod for type-safe command-line interfaces.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- 🛡️ **Type-safe**: Built with TypeScript and Zod for runtime validation.
|
|
12
|
+
- 📋 **Declarative**: Define commands, options, and arguments with simple schemas.
|
|
13
|
+
- 🔄 **Flexible parsing**: Support for long flags, short flags, and flag clustering.
|
|
14
|
+
- 🔀 **Smart conversion**: Automatic kebab-case to camelCase conversion.
|
|
15
|
+
- 🏷️ **Alias support**: Define short aliases for any option.
|
|
16
|
+
- 📦 **Array handling**: Automatic normalization of single values to arrays.
|
|
17
|
+
- 🎯 **Default commands**: Set a default command to run when no command is specified.
|
|
18
|
+
- ❓ **Help message**: Automatic help generation for commands and options.
|
|
19
|
+
- ⚠️ **Error handling**: Clear, actionable error messages.
|
|
20
|
+
- 🚀 **Zero dependencies**: Only requires Zod as a peer dependency.
|
|
21
|
+
- 📦 **ESM support**: Modern ES modules with full TypeScript support.
|
|
22
|
+
|
|
23
|
+
## Installation
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm install zodline zod
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Migration from `@robingenz/zli`
|
|
30
|
+
|
|
31
|
+
`zodline` was previously published as `@robingenz/zli`. To migrate:
|
|
32
|
+
|
|
33
|
+
1. Replace the dependency:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npm uninstall @robingenz/zli
|
|
37
|
+
npm install zodline
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
2. Update import specifiers:
|
|
41
|
+
|
|
42
|
+
```diff
|
|
43
|
+
- import { ... } from '@robingenz/zli';
|
|
44
|
+
+ import { ... } from 'zodline';
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
3. Rename the `ZliError` export to `ZodlineError` (the public API is otherwise unchanged):
|
|
48
|
+
|
|
49
|
+
```diff
|
|
50
|
+
- import { ZliError } from '@robingenz/zli';
|
|
51
|
+
+ import { ZodlineError } from 'zodline';
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Usage
|
|
55
|
+
|
|
56
|
+
### Basic Example
|
|
57
|
+
|
|
58
|
+
```javascript
|
|
59
|
+
import { z } from 'zod';
|
|
60
|
+
import { defineConfig, defineCommand, defineOptions, processConfig } from 'zodline';
|
|
61
|
+
|
|
62
|
+
// Define a simple command
|
|
63
|
+
const greetCommand = defineCommand({
|
|
64
|
+
description: 'Greet someone',
|
|
65
|
+
options: defineOptions(
|
|
66
|
+
z.object({
|
|
67
|
+
name: z.string().describe('Name to greet'),
|
|
68
|
+
loud: z.boolean().default(false).describe('Use uppercase'),
|
|
69
|
+
}),
|
|
70
|
+
{ n: 'name', l: 'loud' } // Short aliases
|
|
71
|
+
),
|
|
72
|
+
action: async (options) => {
|
|
73
|
+
const greeting = `Hello, ${options.name}!`;
|
|
74
|
+
console.log(options.loud ? greeting.toUpperCase() : greeting);
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// Configure the CLI
|
|
79
|
+
const config = defineConfig({
|
|
80
|
+
meta: {
|
|
81
|
+
name: 'my-cli',
|
|
82
|
+
version: '1.0.0',
|
|
83
|
+
description: 'A simple CLI example',
|
|
84
|
+
},
|
|
85
|
+
commands: {
|
|
86
|
+
greet: greetCommand,
|
|
87
|
+
},
|
|
88
|
+
defaultCommand: greetCommand,
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// Process command line arguments
|
|
92
|
+
try {
|
|
93
|
+
const result = processConfig(config, process.argv.slice(2));
|
|
94
|
+
await result.command.action(result.options, result.args);
|
|
95
|
+
} catch (error) {
|
|
96
|
+
console.error('Error:', error.message);
|
|
97
|
+
process.exit(1);
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Command Usage
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
# Show help
|
|
105
|
+
my-cli --help
|
|
106
|
+
my-cli greet --help
|
|
107
|
+
|
|
108
|
+
# Run commands
|
|
109
|
+
my-cli greet --name Alice
|
|
110
|
+
my-cli greet -n Bob --loud
|
|
111
|
+
|
|
112
|
+
# Run default command
|
|
113
|
+
my-cli --name Alice
|
|
114
|
+
my-cli greet --name Alice
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Advanced Features
|
|
118
|
+
|
|
119
|
+
#### Default Commands
|
|
120
|
+
|
|
121
|
+
You can specify a default command that will be executed when no command is provided:
|
|
122
|
+
|
|
123
|
+
```javascript
|
|
124
|
+
const config = defineConfig({
|
|
125
|
+
meta: {
|
|
126
|
+
name: 'my-app',
|
|
127
|
+
version: '1.0.0',
|
|
128
|
+
},
|
|
129
|
+
commands: {
|
|
130
|
+
start: startCommand,
|
|
131
|
+
build: buildCommand,
|
|
132
|
+
},
|
|
133
|
+
defaultCommand: startCommand,
|
|
134
|
+
});
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
With this configuration:
|
|
138
|
+
- `my-app` will run the `startCommand`
|
|
139
|
+
- `my-app --help` will still show the help message
|
|
140
|
+
- `my-app build` will run the `build` command
|
|
141
|
+
|
|
142
|
+
#### Commands with Arguments
|
|
143
|
+
|
|
144
|
+
```javascript
|
|
145
|
+
const copyCommand = defineCommand({
|
|
146
|
+
description: 'Copy a file',
|
|
147
|
+
args: z.tuple([
|
|
148
|
+
z.string().describe('Source file'),
|
|
149
|
+
z.string().describe('Destination file'),
|
|
150
|
+
]),
|
|
151
|
+
options: defineOptions(
|
|
152
|
+
z.object({
|
|
153
|
+
verbose: z.boolean().default(false).describe('Verbose output'),
|
|
154
|
+
}),
|
|
155
|
+
{ v: 'verbose' }
|
|
156
|
+
),
|
|
157
|
+
action: async (options, args) => {
|
|
158
|
+
const [source, dest] = args;
|
|
159
|
+
console.log(`Copying ${source} to ${dest}`);
|
|
160
|
+
},
|
|
161
|
+
});
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
#### Array Options
|
|
165
|
+
|
|
166
|
+
```javascript
|
|
167
|
+
const options = defineOptions(
|
|
168
|
+
z.object({
|
|
169
|
+
files: z.array(z.string()).describe('Input files'),
|
|
170
|
+
tags: z.array(z.string()).optional().describe('Tags to apply'),
|
|
171
|
+
})
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
// Usage: --files file1.txt --files file2.txt
|
|
175
|
+
// Single values are automatically converted to arrays
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
#### Type Transformations
|
|
179
|
+
|
|
180
|
+
```javascript
|
|
181
|
+
const options = defineOptions(
|
|
182
|
+
z.object({
|
|
183
|
+
port: z.coerce.number().min(1).max(65535).describe('Port number'),
|
|
184
|
+
count: z.coerce.number().min(1).describe('Count'),
|
|
185
|
+
})
|
|
186
|
+
);
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### Flag Parsing
|
|
190
|
+
|
|
191
|
+
`zodline` supports various flag formats:
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
# Long flags
|
|
195
|
+
--verbose --name=value --port 3000
|
|
196
|
+
|
|
197
|
+
# Short flags
|
|
198
|
+
-v -n value -p 3000
|
|
199
|
+
|
|
200
|
+
# Flag clustering
|
|
201
|
+
-abc # equivalent to -a -b -c
|
|
202
|
+
|
|
203
|
+
# Kebab-case conversion
|
|
204
|
+
--my-option # becomes myOption in your code
|
|
205
|
+
|
|
206
|
+
# Multiple values
|
|
207
|
+
--file a.txt --file b.txt # becomes ['a.txt', 'b.txt']
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### API Reference
|
|
211
|
+
|
|
212
|
+
#### `defineOptions(schema, aliases?)`
|
|
213
|
+
|
|
214
|
+
Define options for a command with optional aliases.
|
|
215
|
+
|
|
216
|
+
- `schema`: Zod object schema defining the options
|
|
217
|
+
- `aliases`: Optional object mapping short aliases to option names
|
|
218
|
+
|
|
219
|
+
#### `defineCommand(config)`
|
|
220
|
+
|
|
221
|
+
Define a command with options, arguments, and action.
|
|
222
|
+
|
|
223
|
+
- `description`: Command description for help
|
|
224
|
+
- `options`: Options definition (optional)
|
|
225
|
+
- `args`: Zod schema for arguments (optional)
|
|
226
|
+
- `action`: Function to execute when command is run
|
|
227
|
+
|
|
228
|
+
#### `defineConfig(config)`
|
|
229
|
+
|
|
230
|
+
Define the CLI configuration.
|
|
231
|
+
|
|
232
|
+
- `meta`: CLI metadata (name, version, description)
|
|
233
|
+
- `commands`: Object mapping command names to definitions
|
|
234
|
+
- `defaultCommand`: Optional default command definition to run when no command is specified
|
|
235
|
+
|
|
236
|
+
#### `processConfig(config, args)`
|
|
237
|
+
|
|
238
|
+
Process command line arguments and return the result.
|
|
239
|
+
|
|
240
|
+
- `config`: CLI configuration
|
|
241
|
+
- `args`: Command line arguments (typically `process.argv.slice(2)`)
|
|
242
|
+
|
|
243
|
+
Returns an object with:
|
|
244
|
+
- `command`: The matched command definition
|
|
245
|
+
- `options`: Parsed and validated options
|
|
246
|
+
- `args`: Parsed and validated arguments
|
|
247
|
+
|
|
248
|
+
## Used By
|
|
249
|
+
|
|
250
|
+
- [Capawesome Team CLI](https://github.com/capawesome-team/cli) - The Capawesome Cloud CLI to manage Live Updates and more.
|
|
251
|
+
|
|
252
|
+
## Changelog
|
|
253
|
+
|
|
254
|
+
See [CHANGELOG.md](./CHANGELOG.md).
|
|
255
|
+
|
|
256
|
+
## License
|
|
257
|
+
|
|
258
|
+
See [LICENSE](./LICENSE).
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { OptionsDefinition, CommandDefinition, DefineConfig } from './types.js';
|
|
3
|
+
export declare function defineOptions<T extends z.ZodObject<any> = z.ZodObject<any>>(schema: T, aliases?: Record<string, string>): OptionsDefinition<T>;
|
|
4
|
+
export declare function defineCommand<TOptions extends OptionsDefinition<any> | undefined = undefined, TArgs extends z.ZodType | undefined = undefined>(config: {
|
|
5
|
+
description?: string;
|
|
6
|
+
options?: TOptions;
|
|
7
|
+
args?: TArgs;
|
|
8
|
+
action: (options: TOptions extends OptionsDefinition<infer U> ? z.infer<U> : {}, args: TArgs extends z.ZodType ? z.infer<TArgs> : undefined) => void | Promise<void>;
|
|
9
|
+
}): CommandDefinition<TOptions extends OptionsDefinition<infer U> ? U : z.ZodObject<any>, TArgs>;
|
|
10
|
+
export declare function defineConfig<TCommands extends Record<string, CommandDefinition<any, any>> = {}>(config: DefineConfig<TCommands>): DefineConfig<TCommands>;
|
|
11
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAErF,wBAAgB,aAAa,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,EACzE,MAAM,EAAE,CAAC,EACT,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC/B,iBAAiB,CAAC,CAAC,CAAC,CAEtB;AAED,wBAAgB,aAAa,CAC3B,QAAQ,SAAS,iBAAiB,CAAC,GAAG,CAAC,GAAG,SAAS,GAAG,SAAS,EAC/D,KAAK,SAAS,CAAC,CAAC,OAAO,GAAG,SAAS,GAAG,SAAS,EAC/C,MAAM,EAAE;IACR,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,QAAQ,CAAC;IACnB,IAAI,CAAC,EAAE,KAAK,CAAC;IACb,MAAM,EAAE,CACN,OAAO,EAAE,QAAQ,SAAS,iBAAiB,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,EAAE,EACtE,IAAI,EAAE,KAAK,SAAS,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,SAAS,KACvD,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B,GAAG,iBAAiB,CAAC,QAAQ,SAAS,iBAAiB,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAE/F;AAED,wBAAgB,YAAY,CAAC,SAAS,SAAS,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,GAAG,EAAE,EAC7F,MAAM,EAAE,YAAY,CAAC,SAAS,CAAC,GAC9B,YAAY,CAAC,SAAS,CAAC,CAEzB"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,aAAa,CAC3B,MAAS,EACT,OAAgC;IAEhC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,aAAa,CAG3B,MAQD;IACC,OAAO,MAAa,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,MAA+B;IAE/B,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { CommandDefinition, DefineConfig, ProcessResult } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Main entry point for processing CLI configuration and arguments.
|
|
4
|
+
* Parses command line arguments, validates options, and returns the processed result.
|
|
5
|
+
* Handles help display, command validation, and option processing.
|
|
6
|
+
*
|
|
7
|
+
* @param config - CLI configuration with commands
|
|
8
|
+
* @param args - Command line arguments (typically process.argv.slice(2))
|
|
9
|
+
* @returns Processed result containing command, options, and arguments
|
|
10
|
+
* @throws Error for invalid commands or validation failures
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* processConfig(config, ['apps:bundles:create', '--android-max', '10'])
|
|
14
|
+
* // Returns: { command: ..., options: { androidMax: '10' }, args: [] }
|
|
15
|
+
*/
|
|
16
|
+
export declare function processConfig<TCommands extends Record<string, CommandDefinition<any, any>> = {}>(config: DefineConfig<TCommands>, args: string[]): ProcessResult<CommandDefinition<any, any>>;
|
|
17
|
+
export { defineOptions, defineCommand, defineConfig } from './config.js';
|
|
18
|
+
export { ZodlineError } from './types.js';
|
|
19
|
+
export type { OptionsDefinition, CommandDefinition, DefineConfig, ProcessResult } from './types.js';
|
|
20
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,YAAY,EAAqB,aAAa,EAAE,MAAM,YAAY,CAAC;AAggBpG;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAAC,SAAS,SAAS,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,GAAG,EAAE,EAC9F,MAAM,EAAE,YAAY,CAAC,SAAS,CAAC,EAC/B,IAAI,EAAE,MAAM,EAAE,GACb,aAAa,CAAC,iBAAiB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CA0C5C;AAGD,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACzE,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,507 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { ZodlineError } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Parses command line arguments into flags and non-flag arguments.
|
|
5
|
+
* Handles both long flags (--flag) and short flags (-f), including flag clustering (-abc).
|
|
6
|
+
* Supports flags with values (--flag=value or --flag value) and boolean flags.
|
|
7
|
+
* When the same flag is specified multiple times, values are collected into an array.
|
|
8
|
+
*
|
|
9
|
+
* @param args - Array of command line arguments to parse
|
|
10
|
+
* @returns Object containing parsed flags and non-flag arguments under '_' key
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* parseFlags(['--verbose', '--count', '5', 'file.txt'])
|
|
14
|
+
* // Returns: { verbose: true, count: '5', _: ['file.txt'] }
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* parseFlags(['--custom-property', 'key1=value1', '--custom-property', 'key2=value2'])
|
|
18
|
+
* // Returns: { 'custom-property': ['key1=value1', 'key2=value2'], _: [] }
|
|
19
|
+
*/
|
|
20
|
+
function parseFlags(args) {
|
|
21
|
+
const flags = {};
|
|
22
|
+
const nonFlags = [];
|
|
23
|
+
const addFlag = (key, value) => {
|
|
24
|
+
if (key in flags) {
|
|
25
|
+
const existing = flags[key];
|
|
26
|
+
if (Array.isArray(existing)) {
|
|
27
|
+
existing.push(value);
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
flags[key] = [existing, value];
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
flags[key] = value;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
for (let i = 0; i < args.length; i++) {
|
|
38
|
+
const arg = args[i];
|
|
39
|
+
if (!arg)
|
|
40
|
+
continue;
|
|
41
|
+
if (arg.startsWith('--')) {
|
|
42
|
+
const key = arg.slice(2);
|
|
43
|
+
if (key.includes('=')) {
|
|
44
|
+
const [flagName, ...valueParts] = key.split('=');
|
|
45
|
+
if (flagName) {
|
|
46
|
+
addFlag(flagName, valueParts.join('='));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
const nextArg = args[i + 1];
|
|
51
|
+
if (nextArg && !nextArg.startsWith('-')) {
|
|
52
|
+
addFlag(key, nextArg);
|
|
53
|
+
i++;
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
addFlag(key, true);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
else if (arg.startsWith('-') && arg.length > 1) {
|
|
61
|
+
const key = arg.slice(1);
|
|
62
|
+
if (key.length === 1) {
|
|
63
|
+
const nextArg = args[i + 1];
|
|
64
|
+
if (nextArg && !nextArg.startsWith('-')) {
|
|
65
|
+
addFlag(key, nextArg);
|
|
66
|
+
i++;
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
addFlag(key, true);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
for (const char of key) {
|
|
74
|
+
addFlag(char, true);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
nonFlags.push(arg);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return { ...flags, _: nonFlags };
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Resolves flag aliases by replacing alias keys with their target keys.
|
|
86
|
+
* If both alias and target exist, the alias value takes precedence.
|
|
87
|
+
*
|
|
88
|
+
* @param flags - Object containing parsed flags
|
|
89
|
+
* @param aliases - Optional mapping of alias keys to target keys
|
|
90
|
+
* @returns New flags object with aliases resolved to their target keys
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* resolveAliases({ v: true, verbose: false }, { v: 'verbose' })
|
|
94
|
+
* // Returns: { verbose: true }
|
|
95
|
+
*/
|
|
96
|
+
function resolveAliases(flags, aliases) {
|
|
97
|
+
if (!aliases)
|
|
98
|
+
return flags;
|
|
99
|
+
const resolved = { ...flags };
|
|
100
|
+
for (const [alias, target] of Object.entries(aliases)) {
|
|
101
|
+
if (alias in resolved) {
|
|
102
|
+
resolved[target] = resolved[alias];
|
|
103
|
+
delete resolved[alias];
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return resolved;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Converts a camelCase string to kebab-case.
|
|
110
|
+
*
|
|
111
|
+
* @param str - The camelCase string to convert
|
|
112
|
+
* @returns The kebab-case version of the input string
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* camelToKebab('androidMax') // Returns: 'android-max'
|
|
116
|
+
* camelToKebab('expiresInDays') // Returns: 'expires-in-days'
|
|
117
|
+
*/
|
|
118
|
+
function camelToKebab(str) {
|
|
119
|
+
return str.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Resolves kebab-case flags to their camelCase equivalents based on the schema.
|
|
123
|
+
* Only converts kebab-case flags when the camelCase version is not already present.
|
|
124
|
+
* This allows users to pass --android-max instead of --androidMax.
|
|
125
|
+
*
|
|
126
|
+
* @param flags - Object containing parsed flags
|
|
127
|
+
* @param schema - Zod schema object defining the expected camelCase keys
|
|
128
|
+
* @returns New flags object with kebab-case flags converted to camelCase
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* resolveKebabCase({ 'android-max': '10' }, schema)
|
|
132
|
+
* // Returns: { androidMax: '10' } (if androidMax is in schema)
|
|
133
|
+
*/
|
|
134
|
+
function resolveKebabCase(flags, schema) {
|
|
135
|
+
const resolved = { ...flags };
|
|
136
|
+
const schemaKeys = Object.keys(schema.shape);
|
|
137
|
+
for (const camelKey of schemaKeys) {
|
|
138
|
+
if (!(camelKey in resolved)) {
|
|
139
|
+
const kebabKey = camelToKebab(camelKey);
|
|
140
|
+
if (kebabKey in resolved) {
|
|
141
|
+
resolved[camelKey] = resolved[kebabKey];
|
|
142
|
+
delete resolved[kebabKey];
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return resolved;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Builds and displays a header line with description and meta information.
|
|
150
|
+
*
|
|
151
|
+
* @param options - Header display options
|
|
152
|
+
*/
|
|
153
|
+
function displayHeader(options) {
|
|
154
|
+
const parts = [];
|
|
155
|
+
if (options.description)
|
|
156
|
+
parts.push(options.description);
|
|
157
|
+
const metaParts = [];
|
|
158
|
+
if (options.packageName)
|
|
159
|
+
metaParts.push(options.packageName);
|
|
160
|
+
if (options.commandName)
|
|
161
|
+
metaParts.push(options.commandName);
|
|
162
|
+
if (options.version)
|
|
163
|
+
metaParts.push(`v${options.version}`);
|
|
164
|
+
if (metaParts.length > 0) {
|
|
165
|
+
parts.push(`(${metaParts.join(' ')})`);
|
|
166
|
+
}
|
|
167
|
+
if (parts.length > 0) {
|
|
168
|
+
console.log(`\x1b[90m${parts.join(' ')}\x1b[0m\n`);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Displays the main help screen with all available commands.
|
|
173
|
+
* Shows CLI version, usage instructions, and a formatted list of commands with descriptions.
|
|
174
|
+
*
|
|
175
|
+
* @param commands - Object mapping command names to their definitions
|
|
176
|
+
* @param meta - Meta information about the CLI
|
|
177
|
+
*/
|
|
178
|
+
function displayHelp(commands, meta) {
|
|
179
|
+
displayHeader({
|
|
180
|
+
description: meta?.description,
|
|
181
|
+
packageName: meta?.name,
|
|
182
|
+
version: meta?.version,
|
|
183
|
+
});
|
|
184
|
+
const commandNames = Object.keys(commands).join('|');
|
|
185
|
+
const usageName = meta?.name || 'cli';
|
|
186
|
+
console.log(`\x1b[1mUSAGE\x1b[0m \x1b[36m${usageName} ${commandNames}\x1b[0m\n`);
|
|
187
|
+
console.log('\x1b[1mCOMMANDS\x1b[0m\n');
|
|
188
|
+
// Find the maximum command name length for alignment
|
|
189
|
+
const maxLength = Math.max(...Object.keys(commands).map((name) => name.length));
|
|
190
|
+
for (const [name, command] of Object.entries(commands)) {
|
|
191
|
+
const description = command.description || '';
|
|
192
|
+
const padding = ' '.repeat(Math.max(2, maxLength - name.length + 4));
|
|
193
|
+
console.log(` \x1b[36m${name}\x1b[0m${padding}${description}`);
|
|
194
|
+
}
|
|
195
|
+
if (meta?.name) {
|
|
196
|
+
console.log(`\nUse \x1b[36m${meta.name} <command> --help\x1b[0m for more information about a command.`);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Displays help information for a specific command.
|
|
201
|
+
* Shows command description, usage, and available options with their descriptions.
|
|
202
|
+
*
|
|
203
|
+
* @param commandName - Name of the command to show help for
|
|
204
|
+
* @param command - Command definition containing options and description
|
|
205
|
+
* @param meta - Meta information about the CLI
|
|
206
|
+
*/
|
|
207
|
+
function displayCommandHelp(commandName, command, meta) {
|
|
208
|
+
displayHeader({
|
|
209
|
+
commandName,
|
|
210
|
+
description: command.description,
|
|
211
|
+
packageName: meta?.name,
|
|
212
|
+
version: meta?.version,
|
|
213
|
+
});
|
|
214
|
+
// Build usage line
|
|
215
|
+
const usageName = meta?.name || 'cli';
|
|
216
|
+
let usageLine = `\x1b[1mUSAGE\x1b[0m \x1b[36m${usageName} ${commandName}`;
|
|
217
|
+
// Add [OPTIONS] if the command has options
|
|
218
|
+
if (command.options) {
|
|
219
|
+
usageLine += ' [OPTIONS]';
|
|
220
|
+
}
|
|
221
|
+
// Add args placeholder if the command expects args
|
|
222
|
+
if (command.args) {
|
|
223
|
+
usageLine += ' [ARGS]';
|
|
224
|
+
}
|
|
225
|
+
console.log(`${usageLine}\x1b[0m\n`);
|
|
226
|
+
// Display options if they exist
|
|
227
|
+
if (command.options?.schema) {
|
|
228
|
+
console.log('\x1b[1mOPTIONS\x1b[0m\n');
|
|
229
|
+
const shape = command.options.schema.shape;
|
|
230
|
+
const aliases = command.options.aliases || {};
|
|
231
|
+
// Calculate the maximum length for consistent padding
|
|
232
|
+
let maxLength = 0;
|
|
233
|
+
for (const [key] of Object.entries(shape)) {
|
|
234
|
+
const alias = Object.keys(aliases).find((alias) => aliases[alias] === key);
|
|
235
|
+
const kebabKey = camelToKebab(key);
|
|
236
|
+
const visibleLength = ` --${kebabKey}${alias ? `, -${alias}` : ''}`.length;
|
|
237
|
+
maxLength = Math.max(maxLength, visibleLength);
|
|
238
|
+
}
|
|
239
|
+
for (const [key, zodType] of Object.entries(shape)) {
|
|
240
|
+
const description = zodType.description || '';
|
|
241
|
+
const alias = Object.keys(aliases).find((alias) => aliases[alias] === key);
|
|
242
|
+
const kebabKey = camelToKebab(key);
|
|
243
|
+
let optionLine = ` \x1b[36m--${kebabKey}\x1b[0m`;
|
|
244
|
+
if (alias) {
|
|
245
|
+
optionLine += `, \x1b[36m-${alias}\x1b[0m`;
|
|
246
|
+
}
|
|
247
|
+
// Extract default value if present
|
|
248
|
+
const defaultValue = extractDefaultValue(zodType);
|
|
249
|
+
let finalDescription = description;
|
|
250
|
+
if (defaultValue !== undefined) {
|
|
251
|
+
finalDescription = description + (description ? ' ' : '') + `(default: ${defaultValue})`;
|
|
252
|
+
}
|
|
253
|
+
// Add padding and description (accounting for color codes)
|
|
254
|
+
const visibleLength = ` --${kebabKey}${alias ? `, -${alias}` : ''}`.length;
|
|
255
|
+
const padding = ' '.repeat(Math.max(2, maxLength - visibleLength + 4));
|
|
256
|
+
console.log(`${optionLine}${padding}${finalDescription}`);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Normalizes single values to arrays for fields that are defined as arrays in the schema.
|
|
262
|
+
* This ensures that when a user provides a single value for an array field,
|
|
263
|
+
* it gets wrapped in an array before validation.
|
|
264
|
+
*
|
|
265
|
+
* @param options - Object containing parsed options
|
|
266
|
+
* @param schema - Zod schema object defining the expected field types
|
|
267
|
+
* @returns New options object with single values normalized to arrays where needed
|
|
268
|
+
*
|
|
269
|
+
* @example
|
|
270
|
+
* normalizeArrayFields({ customProperty: 'key=value' }, schema)
|
|
271
|
+
* // Returns: { customProperty: ['key=value'] } (if customProperty is defined as array in schema)
|
|
272
|
+
*/
|
|
273
|
+
function normalizeArrayFields(options, schema) {
|
|
274
|
+
const normalized = { ...options };
|
|
275
|
+
const shape = schema.shape;
|
|
276
|
+
for (const [key, zodType] of Object.entries(shape)) {
|
|
277
|
+
if (key in normalized) {
|
|
278
|
+
// Check if this field is defined as an array (including optional arrays)
|
|
279
|
+
const isArrayField = isZodArrayType(zodType);
|
|
280
|
+
if (isArrayField && !Array.isArray(normalized[key])) {
|
|
281
|
+
// Convert single value to array
|
|
282
|
+
normalized[key] = [normalized[key]];
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
return normalized;
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Checks if a Zod type is an array type, handling optional and default wrappers.
|
|
290
|
+
*
|
|
291
|
+
* @param zodType - The Zod type to check
|
|
292
|
+
* @returns True if the type is an array type
|
|
293
|
+
*/
|
|
294
|
+
function isZodArrayType(zodType) {
|
|
295
|
+
// Handle ZodOptional and ZodDefault wrappers, but stop when we find the actual type
|
|
296
|
+
let innerType = zodType;
|
|
297
|
+
// Only unwrap wrapper types like ZodOptional and ZodDefault, not the content types
|
|
298
|
+
while (innerType._def && (innerType._def.innerType || innerType._def.type)) {
|
|
299
|
+
const next = innerType._def.innerType || innerType._def.type;
|
|
300
|
+
// Stop unwrapping if we reach a content type (like ZodArray, ZodString, etc.)
|
|
301
|
+
if (innerType.constructor.name === 'ZodOptional' || innerType.constructor.name === 'ZodDefault') {
|
|
302
|
+
innerType = next;
|
|
303
|
+
}
|
|
304
|
+
else {
|
|
305
|
+
break;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
// Check for ZodArray type name as instanceof might not work with different zod instances
|
|
309
|
+
return innerType instanceof z.ZodArray || (innerType._def && innerType._def.typeName === 'ZodArray');
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Creates an error for unknown options with proper flag prefix and display name.
|
|
313
|
+
*
|
|
314
|
+
* @param optionName - The unknown option name
|
|
315
|
+
* @returns ZodlineError with formatted error message
|
|
316
|
+
*/
|
|
317
|
+
function createUnknownOptionError(optionName) {
|
|
318
|
+
const flagPrefix = optionName.length === 1 ? '-' : '--';
|
|
319
|
+
const displayName = optionName.length === 1 ? optionName : camelToKebab(optionName);
|
|
320
|
+
return new ZodlineError(`Unknown option: \x1b[36m${flagPrefix}${displayName}\x1b[0m`);
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Extracts the default value from a Zod type, handling nested optional and default wrappers.
|
|
324
|
+
*
|
|
325
|
+
* @param zodType - The Zod type to extract default value from
|
|
326
|
+
* @returns The formatted default value if present, undefined otherwise
|
|
327
|
+
*/
|
|
328
|
+
function extractDefaultValue(zodType) {
|
|
329
|
+
// Traverse through the type definition to find default value
|
|
330
|
+
let currentType = zodType;
|
|
331
|
+
while (currentType && currentType._def) {
|
|
332
|
+
// Check if this is a ZodDefault type
|
|
333
|
+
if (currentType.constructor.name === 'ZodDefault' || currentType._def.typeName === 'ZodDefault') {
|
|
334
|
+
// Handle both function and direct value defaults
|
|
335
|
+
const defaultValue = currentType._def.defaultValue;
|
|
336
|
+
const value = typeof defaultValue === 'function' ? defaultValue() : defaultValue;
|
|
337
|
+
// Format the value based on its type
|
|
338
|
+
if (typeof value === 'string') {
|
|
339
|
+
return `"${value}"`;
|
|
340
|
+
}
|
|
341
|
+
return String(value);
|
|
342
|
+
}
|
|
343
|
+
// Move to the inner type if it exists
|
|
344
|
+
if (currentType._def.innerType) {
|
|
345
|
+
currentType = currentType._def.innerType;
|
|
346
|
+
}
|
|
347
|
+
else if (currentType._def.type) {
|
|
348
|
+
currentType = currentType._def.type;
|
|
349
|
+
}
|
|
350
|
+
else {
|
|
351
|
+
break;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
return undefined;
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* Validates and transforms command options using Zod schema validation.
|
|
358
|
+
* Processes aliases and kebab-case conversion before validation.
|
|
359
|
+
* Ensures that single values for array fields are converted to arrays.
|
|
360
|
+
* Throws an error if any unknown options are provided.
|
|
361
|
+
*
|
|
362
|
+
* @param flags - Raw parsed flags from command line
|
|
363
|
+
* @param optionsDef - Optional options definition with schema and aliases
|
|
364
|
+
* @returns Validated options object matching the schema
|
|
365
|
+
* @throws Error if validation fails or unknown options are provided
|
|
366
|
+
*
|
|
367
|
+
* @example
|
|
368
|
+
* validateOptions({ 'android-max': '10' }, { schema: z.object({ androidMax: z.string() }) })
|
|
369
|
+
* // Returns: { androidMax: '10' }
|
|
370
|
+
*
|
|
371
|
+
* @example
|
|
372
|
+
* validateOptions({ 'custom-property': 'key=value' }, { schema: z.object({ customProperty: z.array(z.string()) }) })
|
|
373
|
+
* // Returns: { customProperty: ['key=value'] }
|
|
374
|
+
*/
|
|
375
|
+
function validateOptions(flags, optionsDef) {
|
|
376
|
+
if (!optionsDef) {
|
|
377
|
+
// Check for unknown options when no schema is defined
|
|
378
|
+
const { _, ...options } = flags;
|
|
379
|
+
const unknownOptions = Object.keys(options);
|
|
380
|
+
if (unknownOptions.length > 0) {
|
|
381
|
+
// Find the first unknown option that looks like a flag
|
|
382
|
+
const firstUnknown = unknownOptions.find((key) => key !== 'help' && key !== 'version');
|
|
383
|
+
if (firstUnknown) {
|
|
384
|
+
throw createUnknownOptionError(firstUnknown);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
return {};
|
|
388
|
+
}
|
|
389
|
+
// Get valid option names from schema
|
|
390
|
+
const schemaKeys = Object.keys(optionsDef.schema.shape);
|
|
391
|
+
const validNames = new Set();
|
|
392
|
+
// Add camelCase names
|
|
393
|
+
schemaKeys.forEach((key) => validNames.add(key));
|
|
394
|
+
// Add kebab-case versions
|
|
395
|
+
schemaKeys.forEach((key) => validNames.add(camelToKebab(key)));
|
|
396
|
+
// Add aliases
|
|
397
|
+
if (optionsDef.aliases) {
|
|
398
|
+
Object.keys(optionsDef.aliases).forEach((alias) => validNames.add(alias));
|
|
399
|
+
}
|
|
400
|
+
// Add standard help and version flags
|
|
401
|
+
validNames.add('help');
|
|
402
|
+
validNames.add('version');
|
|
403
|
+
// Check for unknown options before processing
|
|
404
|
+
const { _, ...options } = flags;
|
|
405
|
+
for (const optionName of Object.keys(options)) {
|
|
406
|
+
if (!validNames.has(optionName)) {
|
|
407
|
+
throw createUnknownOptionError(optionName);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
const resolvedAliases = resolveAliases(flags, optionsDef.aliases);
|
|
411
|
+
const resolvedKebab = resolveKebabCase(resolvedAliases, optionsDef.schema);
|
|
412
|
+
const { _: resolvedUnderscore, ...resolvedOptions } = resolvedKebab;
|
|
413
|
+
// Normalize single values to arrays for fields that expect arrays
|
|
414
|
+
const normalizedOptions = normalizeArrayFields(resolvedOptions, optionsDef.schema);
|
|
415
|
+
return optionsDef.schema.parse(normalizedOptions);
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* Processes a command with its options and arguments.
|
|
419
|
+
* Validates options using the command's schema and parses arguments if provided.
|
|
420
|
+
*
|
|
421
|
+
* @param command - The command definition to process
|
|
422
|
+
* @param parsedFlags - Parsed flags from command line
|
|
423
|
+
* @param args - Arguments to validate and process
|
|
424
|
+
* @returns Processed result containing command, options, and arguments
|
|
425
|
+
* @throws Error for validation failures
|
|
426
|
+
*/
|
|
427
|
+
function processCommandExecution(command, parsedFlags, args) {
|
|
428
|
+
// Process command options
|
|
429
|
+
const options = validateOptions(parsedFlags, command.options);
|
|
430
|
+
// Validate args if schema is provided
|
|
431
|
+
let validatedArgs = args;
|
|
432
|
+
if (command.args) {
|
|
433
|
+
try {
|
|
434
|
+
validatedArgs = command.args.parse(args);
|
|
435
|
+
}
|
|
436
|
+
catch (error) {
|
|
437
|
+
if (error instanceof z.ZodError) {
|
|
438
|
+
const issues = error.issues.map((issue) => `${issue.path.join('.')}: ${issue.message}`).join(', ');
|
|
439
|
+
throw new Error(`Argument validation failed: ${issues}`);
|
|
440
|
+
}
|
|
441
|
+
throw error;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
return {
|
|
445
|
+
command,
|
|
446
|
+
options,
|
|
447
|
+
args: validatedArgs,
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* Main entry point for processing CLI configuration and arguments.
|
|
452
|
+
* Parses command line arguments, validates options, and returns the processed result.
|
|
453
|
+
* Handles help display, command validation, and option processing.
|
|
454
|
+
*
|
|
455
|
+
* @param config - CLI configuration with commands
|
|
456
|
+
* @param args - Command line arguments (typically process.argv.slice(2))
|
|
457
|
+
* @returns Processed result containing command, options, and arguments
|
|
458
|
+
* @throws Error for invalid commands or validation failures
|
|
459
|
+
*
|
|
460
|
+
* @example
|
|
461
|
+
* processConfig(config, ['apps:bundles:create', '--android-max', '10'])
|
|
462
|
+
* // Returns: { command: ..., options: { androidMax: '10' }, args: [] }
|
|
463
|
+
*/
|
|
464
|
+
export function processConfig(config, args) {
|
|
465
|
+
const parsedFlags = parseFlags(args);
|
|
466
|
+
const commandArgs = parsedFlags._ || [];
|
|
467
|
+
// Find the command
|
|
468
|
+
const commandName = commandArgs[0];
|
|
469
|
+
if (!commandName) {
|
|
470
|
+
if (parsedFlags.version === true && config.meta?.version) {
|
|
471
|
+
// Show version and exit successfully
|
|
472
|
+
console.log(config.meta.version);
|
|
473
|
+
process.exit(0);
|
|
474
|
+
}
|
|
475
|
+
else if (parsedFlags.help === true) {
|
|
476
|
+
// Show help and exit successfully
|
|
477
|
+
displayHelp(config.commands, config.meta);
|
|
478
|
+
process.exit(0);
|
|
479
|
+
}
|
|
480
|
+
else if (config.defaultCommand) {
|
|
481
|
+
// Use default command when no command is specified
|
|
482
|
+
return processCommandExecution(config.defaultCommand, parsedFlags, commandArgs);
|
|
483
|
+
}
|
|
484
|
+
else {
|
|
485
|
+
// Show help and throw error
|
|
486
|
+
displayHelp(config.commands, config.meta);
|
|
487
|
+
throw new ZodlineError('No command specified.');
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
const command = config.commands[commandName];
|
|
491
|
+
if (!command) {
|
|
492
|
+
displayHelp(config.commands, config.meta);
|
|
493
|
+
throw new ZodlineError(`Unknown command: \x1b[36m${commandName}\x1b[0m`);
|
|
494
|
+
}
|
|
495
|
+
const remainingArgs = commandArgs.slice(1);
|
|
496
|
+
// Check for help flag for the specific command
|
|
497
|
+
if (parsedFlags.help === true) {
|
|
498
|
+
displayCommandHelp(commandName, command, config.meta);
|
|
499
|
+
process.exit(0);
|
|
500
|
+
}
|
|
501
|
+
// Process the command
|
|
502
|
+
return processCommandExecution(command, parsedFlags, remainingArgs);
|
|
503
|
+
}
|
|
504
|
+
// Export main functions and types from config
|
|
505
|
+
export { defineOptions, defineCommand, defineConfig } from './config.js';
|
|
506
|
+
export { ZodlineError } from './types.js';
|
|
507
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare class ZodlineError extends Error {
|
|
3
|
+
constructor(message: string);
|
|
4
|
+
}
|
|
5
|
+
export interface OptionsDefinition<T extends z.ZodObject<any> = z.ZodObject<any>> {
|
|
6
|
+
schema: T;
|
|
7
|
+
aliases?: Record<string, string> | undefined;
|
|
8
|
+
}
|
|
9
|
+
export interface CommandDefinition<TOptions extends z.ZodObject<any> = z.ZodObject<any>, TArgs extends z.ZodType | undefined = undefined> {
|
|
10
|
+
description?: string;
|
|
11
|
+
options?: OptionsDefinition<TOptions>;
|
|
12
|
+
args?: TArgs;
|
|
13
|
+
action: (options: TOptions extends z.ZodObject<any> ? z.infer<TOptions> : {}, args: TArgs extends z.ZodType ? z.infer<TArgs> : undefined) => void | Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
export interface DefineConfig<TCommands extends Record<string, CommandDefinition<any, any>> = {}> {
|
|
16
|
+
meta?: {
|
|
17
|
+
name?: string;
|
|
18
|
+
version?: string;
|
|
19
|
+
description?: string;
|
|
20
|
+
};
|
|
21
|
+
commands: TCommands;
|
|
22
|
+
defaultCommand?: CommandDefinition<any, any>;
|
|
23
|
+
}
|
|
24
|
+
export interface ProcessResult<TCommand extends CommandDefinition<any, any> = CommandDefinition<any, any>> {
|
|
25
|
+
command: TCommand;
|
|
26
|
+
options: TCommand extends CommandDefinition<infer TOptions, any> ? TOptions extends z.ZodObject<any> ? z.infer<TOptions> : {} : any;
|
|
27
|
+
args: TCommand extends CommandDefinition<any, infer TArgs> ? TArgs extends z.ZodType ? z.infer<TArgs> : undefined : any;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,qBAAa,YAAa,SAAQ,KAAK;gBACzB,OAAO,EAAE,MAAM;CAI5B;AAED,MAAM,WAAW,iBAAiB,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC;IAC9E,MAAM,EAAE,CAAC,CAAC;IACV,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC;CAC9C;AAED,MAAM,WAAW,iBAAiB,CAChC,QAAQ,SAAS,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,EACpD,KAAK,SAAS,CAAC,CAAC,OAAO,GAAG,SAAS,GAAG,SAAS;IAE/C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IACtC,IAAI,CAAC,EAAE,KAAK,CAAC;IACb,MAAM,EAAE,CACN,OAAO,EAAE,QAAQ,SAAS,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,EAAE,EACnE,IAAI,EAAE,KAAK,SAAS,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,SAAS,KACvD,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B;AAED,MAAM,WAAW,YAAY,CAAC,SAAS,SAAS,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,GAAG,EAAE;IAC9F,IAAI,CAAC,EAAE;QACL,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,QAAQ,EAAE,SAAS,CAAC;IACpB,cAAc,CAAC,EAAE,iBAAiB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;CAC9C;AAED,MAAM,WAAW,aAAa,CAAC,QAAQ,SAAS,iBAAiB,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,iBAAiB,CAAC,GAAG,EAAE,GAAG,CAAC;IACvG,OAAO,EAAE,QAAQ,CAAC;IAClB,OAAO,EAAE,QAAQ,SAAS,iBAAiB,CAAC,MAAM,QAAQ,EAAE,GAAG,CAAC,GAC5D,QAAQ,SAAS,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,GAC/B,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,GACjB,EAAE,GACJ,GAAG,CAAC;IACR,IAAI,EAAE,QAAQ,SAAS,iBAAiB,CAAC,GAAG,EAAE,MAAM,KAAK,CAAC,GACtD,KAAK,SAAS,CAAC,CAAC,OAAO,GACrB,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,GACd,SAAS,GACX,GAAG,CAAC;CACT"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,YAAa,SAAQ,KAAK;IACrC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC;IAC7B,CAAC;CACF"}
|
package/example.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { defineConfig, defineCommand, defineOptions, processConfig } from './dist/index.js';
|
|
4
|
+
|
|
5
|
+
// Define a simple command to greet someone
|
|
6
|
+
const greetCommand = defineCommand({
|
|
7
|
+
description: 'Greet someone',
|
|
8
|
+
options: defineOptions(
|
|
9
|
+
z.object({
|
|
10
|
+
name: z.string().describe('Name to greet'),
|
|
11
|
+
loud: z.boolean().default(false).describe('Use uppercase'),
|
|
12
|
+
}),
|
|
13
|
+
{ n: 'name', l: 'loud' } // Short aliases
|
|
14
|
+
),
|
|
15
|
+
action: async (options) => {
|
|
16
|
+
const greeting = `Hello, ${options.name}!`;
|
|
17
|
+
console.log(options.loud ? greeting.toUpperCase() : greeting);
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
// Define a command that copies a file
|
|
22
|
+
const copyCommand = defineCommand({
|
|
23
|
+
description: 'Copy a file to another location',
|
|
24
|
+
args: z.tuple([
|
|
25
|
+
z.string().describe('Source file'),
|
|
26
|
+
z.string().describe('Destination file'),
|
|
27
|
+
]),
|
|
28
|
+
options: defineOptions(
|
|
29
|
+
z.object({
|
|
30
|
+
verbose: z.boolean().default(false).describe('Show detailed output'),
|
|
31
|
+
}),
|
|
32
|
+
{ v: 'verbose' }
|
|
33
|
+
),
|
|
34
|
+
action: async (options, args) => {
|
|
35
|
+
const [source, dest] = args;
|
|
36
|
+
|
|
37
|
+
if (options.verbose) {
|
|
38
|
+
console.log(`Copying ${source} to ${dest}...`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
console.log(`✅ Copied ${source} to ${dest}`);
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// Configure the CLI
|
|
46
|
+
const config = defineConfig({
|
|
47
|
+
meta: {
|
|
48
|
+
name: 'simple-cli',
|
|
49
|
+
version: '1.0.0',
|
|
50
|
+
description: 'A simple example CLI',
|
|
51
|
+
},
|
|
52
|
+
commands: {
|
|
53
|
+
greet: greetCommand,
|
|
54
|
+
copy: copyCommand,
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// Process and run
|
|
59
|
+
try {
|
|
60
|
+
const result = processConfig(config, process.argv.slice(2));
|
|
61
|
+
await result.command.action(result.options, result.args);
|
|
62
|
+
} catch (error) {
|
|
63
|
+
console.error('Error:', error.message);
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "zodline",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "A CLI parser built with Zod.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"zodline-example": "./example.js"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist"
|
|
13
|
+
],
|
|
14
|
+
"exports": {
|
|
15
|
+
".": {
|
|
16
|
+
"import": "./dist/index.js",
|
|
17
|
+
"types": "./dist/index.d.ts"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/robingenz/zodline.git"
|
|
23
|
+
},
|
|
24
|
+
"bugs": {
|
|
25
|
+
"url": "https://github.com/robingenz/zodline/issues"
|
|
26
|
+
},
|
|
27
|
+
"scripts": {
|
|
28
|
+
"build": "tsc",
|
|
29
|
+
"dev": "tsc --watch",
|
|
30
|
+
"clean": "rimraf dist",
|
|
31
|
+
"fmt": "prettier --write \"src/**/*.{ts,js,json}\"",
|
|
32
|
+
"lint": "prettier --check \"src/**/*.{ts,js,json}\"",
|
|
33
|
+
"test": "vitest run",
|
|
34
|
+
"test:run": "vitest run",
|
|
35
|
+
"test:ui": "vitest --ui",
|
|
36
|
+
"test:coverage": "vitest run --coverage",
|
|
37
|
+
"release": "commit-and-tag-version",
|
|
38
|
+
"release:dry-run": "npm run release -- --dry-run",
|
|
39
|
+
"prepublishOnly": "npm run clean && npm run build"
|
|
40
|
+
},
|
|
41
|
+
"peerDependencies": {
|
|
42
|
+
"zod": "^4.0.0"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@types/node": "^20.10.0",
|
|
46
|
+
"@vitest/coverage-v8": "^3.2.4",
|
|
47
|
+
"@vitest/ui": "^3.2.4",
|
|
48
|
+
"commit-and-tag-version": "^12.5.2",
|
|
49
|
+
"prettier": "^3.1.1",
|
|
50
|
+
"rimraf": "^5.0.5",
|
|
51
|
+
"typescript": "^5.3.3",
|
|
52
|
+
"vitest": "^3.2.4",
|
|
53
|
+
"zod": "^4.0.17"
|
|
54
|
+
},
|
|
55
|
+
"engines": {
|
|
56
|
+
"node": ">=16.0.0"
|
|
57
|
+
},
|
|
58
|
+
"keywords": [
|
|
59
|
+
"cli",
|
|
60
|
+
"parser",
|
|
61
|
+
"zod",
|
|
62
|
+
"typescript",
|
|
63
|
+
"command-line"
|
|
64
|
+
],
|
|
65
|
+
"author": "Robin Genz <mail@robingenz.dev>",
|
|
66
|
+
"license": "MIT"
|
|
67
|
+
}
|