optionkit 0.0.3 → 0.0.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/README.md +79 -100
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
# optionkit
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
Optionkit turns a Zod configuration schema into CLI options with useful defaults:
|
|
4
|
+
project-scoped environment variables, conflict-free short flags, structured
|
|
5
|
+
environment parsing, and lazy CLI dependency loading.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
bun add optionkit
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Start with the defaults
|
|
7
14
|
|
|
8
15
|
```ts
|
|
9
16
|
import { createOptionKit } from 'optionkit';
|
|
10
17
|
|
|
11
|
-
const { f, z } = await createOptionKit(
|
|
18
|
+
const { f, z } = await createOptionKit();
|
|
12
19
|
|
|
13
20
|
const appOptionsSchema = z.object({
|
|
14
21
|
port: z.number().default(3000).describe('Port to listen on.'),
|
|
@@ -27,122 +34,94 @@ const serve = f.command({ name: 'serve', description: 'Start the server.' })
|
|
|
27
34
|
await serve.parseAsync(process.argv);
|
|
28
35
|
```
|
|
29
36
|
|
|
30
|
-
|
|
31
|
-
`
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
## Lazy CLI dependencies
|
|
42
|
-
|
|
43
|
-
optionkit first resolves Fireargs and Zod from the consuming CLI package. If
|
|
44
|
-
they are unavailable, it detects the package manager from the invocation
|
|
45
|
-
directory and installs the pinned Fireargs and Zod ranges from the consuming
|
|
46
|
-
package root. `cacheDirectory` opts into an isolated install explicitly; there
|
|
47
|
-
is no default versioned cache. Fireargs' package metadata supplies its remaining
|
|
48
|
-
peer dependencies. Optionkit restores the consuming manifest and lockfile
|
|
49
|
-
byte-for-byte after installation, and installer output stays silent so JSON
|
|
50
|
-
output is not polluted.
|
|
51
|
-
|
|
52
|
-
Only `@antfu/install-pkg` is a runtime dependency of optionkit. Fireargs,
|
|
53
|
-
Zod, and `clean-stack` are development dependencies whose ranges are generated
|
|
54
|
-
into the build from the catalog in `pnpm-workspace.yaml`. A matching root
|
|
55
|
-
catalog keeps Bun compatible, and verification fails if the two catalogs
|
|
56
|
-
diverge. `src/_generated/catalog.ts` is a one-to-one runtime mirror of the root
|
|
57
|
-
catalog. The stack cleaner is installed separately and best-effort: a failure
|
|
58
|
-
never prevents the CLI from starting, and `formatError` falls back to the
|
|
59
|
-
original stack. Fireargs and Zod are also declared as optional peers, so a
|
|
60
|
-
consumer's compatible installation is reused without making either package a
|
|
61
|
-
required install.
|
|
62
|
-
|
|
63
|
-
Use the returned `z` when the consuming package does not otherwise depend on
|
|
64
|
-
Zod. It always comes from the same dependency location as the CLI adapter:
|
|
37
|
+
For a package named `my-app`, this creates `MY_APP_PORT`, `MY_APP_DEBUG`, and
|
|
38
|
+
`MY_APP_LOG_LEVEL`. It also assigns `-p`, `-d`, and `-l`; when option initials
|
|
39
|
+
conflict, Optionkit leaves the ambiguous short flags out.
|
|
40
|
+
|
|
41
|
+
`createOptionKit()` finds the consuming package from the executable at
|
|
42
|
+
`process.argv[1]`, falling back to `process.cwd()`, and walks upward to the nearest
|
|
43
|
+
`package.json`. Pass `moduleUrl` or `packageRoot` only when a host needs to make
|
|
44
|
+
that boundary explicit.
|
|
45
|
+
|
|
46
|
+
Each `.input(schema)` is adapted independently, so subcommands need no special
|
|
47
|
+
setup:
|
|
65
48
|
|
|
66
49
|
```ts
|
|
67
|
-
const
|
|
68
|
-
|
|
50
|
+
const program = f.program({ name: 'app' }).router({ serve, status });
|
|
51
|
+
await program.parseAsync(process.argv);
|
|
69
52
|
```
|
|
70
53
|
|
|
71
|
-
|
|
72
|
-
translation. Per-field `env` and `short` values can be overridden or disabled:
|
|
54
|
+
### Environment values
|
|
73
55
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
moduleUrl: import.meta.url,
|
|
81
|
-
});
|
|
56
|
+
Scalar values keep Fireargs' normal coercion. Array, tuple, object, and record
|
|
57
|
+
environment values try JSON first:
|
|
58
|
+
|
|
59
|
+
```text
|
|
60
|
+
MY_APP_TAGS='["one","two"]'
|
|
61
|
+
MY_APP_ENV='{"PORT":"3000"}'
|
|
82
62
|
```
|
|
83
63
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
forwarded unchanged and takes precedence over this augmentation. Every other
|
|
94
|
-
per-option Fireargs configuration field is forwarded as well; command and program
|
|
95
|
-
configuration remains available through the returned `f` namespace.
|
|
96
|
-
|
|
97
|
-
For wrapper commands, `passThroughArguments: true` supplies Fireargs' pass-through
|
|
98
|
-
settings and adds a typed trailing `args: string[]` input in one place:
|
|
64
|
+
Arrays also accept comma- or whitespace-delimited shell words with quotes and
|
|
65
|
+
backslash escapes. Decoded arrays still use native variadic option handling, so
|
|
66
|
+
repeated CLI flags work normally. If decoding does not apply, Zod receives the
|
|
67
|
+
original value and remains the final validator.
|
|
68
|
+
|
|
69
|
+
### Wrapper commands
|
|
70
|
+
|
|
71
|
+
`passThroughArguments` adds the pass-through command settings and a typed trailing
|
|
72
|
+
`args: string[]` input:
|
|
99
73
|
|
|
100
74
|
```ts
|
|
101
75
|
const run = f.command({ name: 'run', passThroughArguments: true })
|
|
102
|
-
.input(
|
|
76
|
+
.input(appOptionsSchema)
|
|
103
77
|
.output(z.void())
|
|
104
78
|
.handler(async ({ args, ...config }) => runExecutable(config, args));
|
|
105
79
|
```
|
|
106
80
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
shortcut defaults.
|
|
110
|
-
|
|
111
|
-
Fireargs programs currently show help when invoked without a subcommand. Optionkit
|
|
112
|
-
does not override that dispatch: Commander only exposes a clean default-command
|
|
113
|
-
switch while adding a command, whereas Fireargs owns that mounting step. A shim
|
|
114
|
-
would either depend on Commander internals or duplicate Fireargs routing.
|
|
115
|
-
|
|
116
|
-
`resolvePackage` and `importPackageIfAvailable` expose the same resolve-first
|
|
117
|
-
behavior for other optional integrations. They only suppress a genuinely
|
|
118
|
-
missing package; initialization errors from an installed package still surface.
|
|
119
|
-
|
|
120
|
-
## Pyfig migration
|
|
81
|
+
Use `{ description: '...' }` instead of `true` to change the generated positional
|
|
82
|
+
help text.
|
|
121
83
|
|
|
122
|
-
|
|
123
|
-
needs to replace the manual loader; Optionkit adapts every command input:
|
|
84
|
+
## Override only what differs
|
|
124
85
|
|
|
125
86
|
```ts
|
|
126
|
-
const
|
|
127
|
-
|
|
87
|
+
const kit = await createOptionKit({
|
|
88
|
+
environmentPrefix: 'SERVICE',
|
|
89
|
+
fields: {
|
|
90
|
+
debug: { env: false, short: 'x' },
|
|
91
|
+
},
|
|
128
92
|
moduleUrl: import.meta.url,
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
const createInput = (passthrough = false) => pyfigOptionsSchema.unwrap().extend({
|
|
132
|
-
...(passthrough ? { args: f.argument().schema(passthroughArguments) } : {}),
|
|
93
|
+
reservedShortFlags: ['v'],
|
|
133
94
|
});
|
|
134
95
|
```
|
|
135
96
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
97
|
+
Available Optionkit-level controls include `projectName`, `environmentPrefix`,
|
|
98
|
+
`shortFlags`, `reservedShortFlags`, per-field metadata, `invocationDirectory`, and
|
|
99
|
+
an explicit `cacheDirectory`. A parser registered through `f.option({ parse })`
|
|
100
|
+
or the `fields` setting is forwarded unchanged and bypasses automatic structured
|
|
101
|
+
decoding.
|
|
102
|
+
|
|
103
|
+
The returned `f` keeps the underlying command, program, option, and argument
|
|
104
|
+
configuration available. Refer to the [Fireargs package](https://www.npmjs.com/package/fireargs)
|
|
105
|
+
for those builder options instead of learning a second configuration vocabulary.
|
|
106
|
+
|
|
107
|
+
## Dependency loading and errors
|
|
108
|
+
|
|
109
|
+
Optionkit first reuses compatible Fireargs and Zod installations from the
|
|
110
|
+
consuming package. If either is missing, it detects the caller's package manager
|
|
111
|
+
and installs the catalog ranges from the consuming package root without changing
|
|
112
|
+
the manifest or lockfile. `cacheDirectory` explicitly opts into an isolated
|
|
113
|
+
installation; there is no default version cache.
|
|
114
|
+
|
|
115
|
+
`@antfu/install-pkg` is Optionkit's only hard runtime dependency. Fireargs, Zod,
|
|
116
|
+
and `clean-stack` are optional peers and development dependencies. Their ranges
|
|
117
|
+
live in the package catalog and are generated into `src/_generated/catalog.ts` as
|
|
118
|
+
a one-to-one runtime mirror. `clean-stack` is best-effort: failure never blocks a
|
|
119
|
+
CLI, and the returned `formatError(error)` falls back to the original stack.
|
|
120
|
+
|
|
121
|
+
Use the returned `z` when the consumer does not otherwise depend on Zod; it is
|
|
122
|
+
resolved from the same location as the CLI adapter. `resolvePackage` and
|
|
123
|
+
`importPackageIfAvailable` expose the same resolve-first behavior for other
|
|
124
|
+
optional integrations and only suppress a genuinely missing package.
|
|
146
125
|
|
|
147
126
|
## License
|
|
148
127
|
|