@silvery/commander 0.8.0 → 0.8.2
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 +75 -1
- package/dist/index.d.mts +805 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +719 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +18 -8
- package/src/colorize.ts +0 -106
- package/src/command.ts +0 -321
- package/src/index.ts +0 -14
- package/src/plain.ts +0 -22
- package/src/presets.ts +0 -186
- package/src/z.ts +0 -44
package/src/index.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
// Enhanced Commander
|
|
2
|
-
export { Command, type HelpSectionPosition, type HelpSectionContent } from "./command.ts"
|
|
3
|
-
export { colorizeHelp, shouldColorize, type ColorizeHelpOptions, type CommandLike } from "./colorize.ts"
|
|
4
|
-
|
|
5
|
-
// Re-export Commander's other classes
|
|
6
|
-
export { Option, Argument, CommanderError, InvalidArgumentError, Help } from "commander"
|
|
7
|
-
export type { OptionValues } from "commander"
|
|
8
|
-
|
|
9
|
-
// Built-in types and Standard Schema
|
|
10
|
-
export { int, uint, float, port, url, path, csv, json, bool, date, email, regex, intRange } from "./presets.ts"
|
|
11
|
-
export type { CLIType, StandardSchemaV1 } from "./presets.ts"
|
|
12
|
-
|
|
13
|
-
// Tree-shakeable: only evaluated if user imports z
|
|
14
|
-
export { z } from "./z.ts"
|
package/src/plain.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Plain Commander — Standard Schema presets without auto-colorization.
|
|
3
|
-
*
|
|
4
|
-
* Exports the base Commander Command (no auto-colorized help) plus the
|
|
5
|
-
* same typed option presets (int, uint, port, csv, intRange). Does NOT
|
|
6
|
-
* import @silvery/ansi — zero styling overhead.
|
|
7
|
-
*
|
|
8
|
-
* For colorization, import `colorizeHelp` from `@silvery/commander` (main entry).
|
|
9
|
-
*
|
|
10
|
-
* @example
|
|
11
|
-
* ```ts
|
|
12
|
-
* import { Command, port, csv } from "@silvery/commander/plain"
|
|
13
|
-
*
|
|
14
|
-
* const program = new Command("myapp")
|
|
15
|
-
* .option("-p, --port <n>", "Port", port)
|
|
16
|
-
* .option("-e, --env <e>", "Env", ["dev", "staging", "prod"])
|
|
17
|
-
* ```
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
export { Command } from "commander"
|
|
21
|
-
export { int, uint, port, csv, intRange } from "./presets.ts"
|
|
22
|
-
export type { StandardSchemaV1 } from "./presets.ts"
|
package/src/presets.ts
DELETED
|
@@ -1,186 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Built-in CLI types — Standard Schema v1 validators for common CLI argument patterns.
|
|
3
|
-
*
|
|
4
|
-
* Zero dependencies — validation is manual, no Zod/Valibot/ArkType required.
|
|
5
|
-
* Each type implements Standard Schema v1 for interop with any schema library,
|
|
6
|
-
* plus standalone `.parse()` and `.safeParse()` convenience methods.
|
|
7
|
-
*
|
|
8
|
-
* @example
|
|
9
|
-
* ```ts
|
|
10
|
-
* import { Command, port, csv } from "@silvery/commander"
|
|
11
|
-
*
|
|
12
|
-
* new Command("deploy")
|
|
13
|
-
* .option("-p, --port <n>", "Port", port) // number (1-65535)
|
|
14
|
-
* .option("-r, --retries <n>", "Retries", int) // number (integer)
|
|
15
|
-
* .option("--tags <t>", "Tags", csv) // string[]
|
|
16
|
-
* .option("-e, --env <e>", "Env", ["dev", "staging", "prod"])
|
|
17
|
-
*
|
|
18
|
-
* // Standalone usage (outside Commander)
|
|
19
|
-
* port.parse("3000") // 3000
|
|
20
|
-
* port.safeParse("abc") // { success: false, issues: [{ message: "..." }] }
|
|
21
|
-
* ```
|
|
22
|
-
*/
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Standard Schema v1 interface — the universal schema interop protocol.
|
|
26
|
-
* Supports any schema library that implements Standard Schema (Zod >=3.24,
|
|
27
|
-
* Valibot >=1.0, ArkType >=2.0, etc.).
|
|
28
|
-
*
|
|
29
|
-
* Inlined to avoid any dependency on @standard-schema/spec.
|
|
30
|
-
* See: https://github.com/standard-schema/standard-schema
|
|
31
|
-
*/
|
|
32
|
-
export interface StandardSchemaV1<T = unknown> {
|
|
33
|
-
readonly "~standard": {
|
|
34
|
-
readonly version: 1
|
|
35
|
-
readonly vendor: string
|
|
36
|
-
readonly validate: (
|
|
37
|
-
value: unknown,
|
|
38
|
-
) => { value: T } | { issues: ReadonlyArray<{ message: string; path?: ReadonlyArray<unknown> }> }
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/** A Standard Schema v1 CLI type with standalone parse/safeParse methods. */
|
|
43
|
-
export interface CLIType<T> extends StandardSchemaV1<T> {
|
|
44
|
-
/** Parse and validate a value, throwing on failure. */
|
|
45
|
-
parse(value: unknown): T
|
|
46
|
-
/** Parse and validate a value, returning a result object. */
|
|
47
|
-
safeParse(value: unknown): { success: true; value: T } | { success: false; issues: Array<{ message: string }> }
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
function createType<T>(vendor: string, validate: (value: unknown) => T): CLIType<T> {
|
|
51
|
-
const schema: CLIType<T> = {
|
|
52
|
-
"~standard": {
|
|
53
|
-
version: 1,
|
|
54
|
-
vendor,
|
|
55
|
-
validate: (value) => {
|
|
56
|
-
try {
|
|
57
|
-
return { value: validate(value) }
|
|
58
|
-
} catch (e: any) {
|
|
59
|
-
return { issues: [{ message: e.message }] }
|
|
60
|
-
}
|
|
61
|
-
},
|
|
62
|
-
},
|
|
63
|
-
parse(value: unknown): T {
|
|
64
|
-
const result = schema["~standard"].validate(value)
|
|
65
|
-
if ("issues" in result) throw new Error(result.issues[0]?.message ?? "Validation failed")
|
|
66
|
-
return result.value
|
|
67
|
-
},
|
|
68
|
-
safeParse(value: unknown) {
|
|
69
|
-
const result = schema["~standard"].validate(value)
|
|
70
|
-
if ("issues" in result) return { success: false as const, issues: [...result.issues] }
|
|
71
|
-
return { success: true as const, value: result.value }
|
|
72
|
-
},
|
|
73
|
-
}
|
|
74
|
-
return schema
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
const VENDOR = "@silvery/commander"
|
|
78
|
-
|
|
79
|
-
/** Integer (coerced from string). */
|
|
80
|
-
export const int = createType<number>(VENDOR, (v) => {
|
|
81
|
-
const s = String(v).trim()
|
|
82
|
-
if (s === "") throw new Error(`Expected integer, got "${v}"`)
|
|
83
|
-
const n = Number(s)
|
|
84
|
-
if (!Number.isInteger(n)) throw new Error(`Expected integer, got "${v}"`)
|
|
85
|
-
return n
|
|
86
|
-
})
|
|
87
|
-
|
|
88
|
-
/** Unsigned integer (>= 0, coerced from string). */
|
|
89
|
-
export const uint = createType<number>(VENDOR, (v) => {
|
|
90
|
-
const s = String(v).trim()
|
|
91
|
-
if (s === "") throw new Error(`Expected unsigned integer (>= 0), got "${v}"`)
|
|
92
|
-
const n = Number(s)
|
|
93
|
-
if (!Number.isInteger(n) || n < 0) throw new Error(`Expected unsigned integer (>= 0), got "${v}"`)
|
|
94
|
-
return n
|
|
95
|
-
})
|
|
96
|
-
|
|
97
|
-
/** Float (coerced from string). */
|
|
98
|
-
export const float = createType<number>(VENDOR, (v) => {
|
|
99
|
-
const s = String(v).trim()
|
|
100
|
-
if (s === "" || s === "NaN") throw new Error(`Expected number, got "${v}"`)
|
|
101
|
-
const n = Number(s)
|
|
102
|
-
if (Number.isNaN(n)) throw new Error(`Expected number, got "${v}"`)
|
|
103
|
-
return n
|
|
104
|
-
})
|
|
105
|
-
|
|
106
|
-
/** Port number (1-65535). */
|
|
107
|
-
export const port = createType<number>(VENDOR, (v) => {
|
|
108
|
-
const n = Number(v)
|
|
109
|
-
if (!Number.isInteger(n) || n < 1 || n > 65535) throw new Error(`Expected port (1-65535), got "${v}"`)
|
|
110
|
-
return n
|
|
111
|
-
})
|
|
112
|
-
|
|
113
|
-
/** URL (validated via URL constructor). */
|
|
114
|
-
export const url = createType<string>(VENDOR, (v) => {
|
|
115
|
-
const s = String(v)
|
|
116
|
-
try {
|
|
117
|
-
new URL(s)
|
|
118
|
-
return s
|
|
119
|
-
} catch {
|
|
120
|
-
throw new Error(`Expected valid URL, got "${v}"`)
|
|
121
|
-
}
|
|
122
|
-
})
|
|
123
|
-
|
|
124
|
-
/** File path (non-empty string). */
|
|
125
|
-
export const path = createType<string>(VENDOR, (v) => {
|
|
126
|
-
const s = String(v)
|
|
127
|
-
if (!s) throw new Error("Expected non-empty path")
|
|
128
|
-
return s
|
|
129
|
-
})
|
|
130
|
-
|
|
131
|
-
/** Comma-separated values to string[]. */
|
|
132
|
-
export const csv = createType<string[]>(VENDOR, (v) => {
|
|
133
|
-
return String(v)
|
|
134
|
-
.split(",")
|
|
135
|
-
.map((s) => s.trim())
|
|
136
|
-
.filter(Boolean)
|
|
137
|
-
})
|
|
138
|
-
|
|
139
|
-
/** JSON string to parsed value. */
|
|
140
|
-
export const json = createType<unknown>(VENDOR, (v) => {
|
|
141
|
-
try {
|
|
142
|
-
return JSON.parse(String(v))
|
|
143
|
-
} catch {
|
|
144
|
-
throw new Error(`Expected valid JSON, got "${v}"`)
|
|
145
|
-
}
|
|
146
|
-
})
|
|
147
|
-
|
|
148
|
-
/** Boolean string ("true"/"false"/"1"/"0"/"yes"/"no"). */
|
|
149
|
-
export const bool = createType<boolean>(VENDOR, (v) => {
|
|
150
|
-
const s = String(v).toLowerCase()
|
|
151
|
-
if (["true", "1", "yes", "y"].includes(s)) return true
|
|
152
|
-
if (["false", "0", "no", "n"].includes(s)) return false
|
|
153
|
-
throw new Error(`Expected boolean (true/false/yes/no/1/0), got "${v}"`)
|
|
154
|
-
})
|
|
155
|
-
|
|
156
|
-
/** Date string to Date object. */
|
|
157
|
-
export const date = createType<Date>(VENDOR, (v) => {
|
|
158
|
-
const d = new Date(String(v))
|
|
159
|
-
if (isNaN(d.getTime())) throw new Error(`Expected valid date, got "${v}"`)
|
|
160
|
-
return d
|
|
161
|
-
})
|
|
162
|
-
|
|
163
|
-
/** Email address (basic validation). */
|
|
164
|
-
export const email = createType<string>(VENDOR, (v) => {
|
|
165
|
-
const s = String(v)
|
|
166
|
-
if (!s.includes("@") || !s.includes(".")) throw new Error(`Expected email address, got "${v}"`)
|
|
167
|
-
return s
|
|
168
|
-
})
|
|
169
|
-
|
|
170
|
-
/** Regex pattern string to RegExp. */
|
|
171
|
-
export const regex = createType<RegExp>(VENDOR, (v) => {
|
|
172
|
-
try {
|
|
173
|
-
return new RegExp(String(v))
|
|
174
|
-
} catch {
|
|
175
|
-
throw new Error(`Expected valid regex, got "${v}"`)
|
|
176
|
-
}
|
|
177
|
-
})
|
|
178
|
-
|
|
179
|
-
/** Integer with min/max bounds (factory). */
|
|
180
|
-
export function intRange(min: number, max: number): CLIType<number> {
|
|
181
|
-
return createType<number>(VENDOR, (v) => {
|
|
182
|
-
const n = Number(v)
|
|
183
|
-
if (!Number.isInteger(n) || n < min || n > max) throw new Error(`Expected integer ${min}-${max}, got "${v}"`)
|
|
184
|
-
return n
|
|
185
|
-
})
|
|
186
|
-
}
|
package/src/z.ts
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Extended Zod object with CLI types.
|
|
3
|
-
*
|
|
4
|
-
* Spreads all of Zod's exports and adds CLI-specific schemas.
|
|
5
|
-
* Tree-shakeable -- only evaluated if user imports `z`.
|
|
6
|
-
*
|
|
7
|
-
* @example
|
|
8
|
-
* ```ts
|
|
9
|
-
* import { z, Command } from "@silvery/commander"
|
|
10
|
-
*
|
|
11
|
-
* new Command("deploy")
|
|
12
|
-
* .option("-p, --port <n>", "Port", z.port)
|
|
13
|
-
* .option("--tags <t>", "Tags", z.csv)
|
|
14
|
-
* .option("-e, --env <e>", "Env", ["dev", "staging", "prod"])
|
|
15
|
-
*
|
|
16
|
-
* program.parse()
|
|
17
|
-
* ```
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
import * as zod from "zod"
|
|
21
|
-
|
|
22
|
-
export const z = {
|
|
23
|
-
...zod,
|
|
24
|
-
// CLI types (built on Zod schemas)
|
|
25
|
-
port: zod.coerce.number().int().min(1).max(65535),
|
|
26
|
-
int: zod.coerce.number().int(),
|
|
27
|
-
uint: zod.coerce.number().int().min(0),
|
|
28
|
-
float: zod.coerce.number(),
|
|
29
|
-
csv: zod.string().transform((v: string) =>
|
|
30
|
-
v
|
|
31
|
-
.split(",")
|
|
32
|
-
.map((s: string) => s.trim())
|
|
33
|
-
.filter(Boolean),
|
|
34
|
-
),
|
|
35
|
-
url: zod.string().url(),
|
|
36
|
-
path: zod.string().min(1),
|
|
37
|
-
email: zod.string().email(),
|
|
38
|
-
date: zod.coerce.date(),
|
|
39
|
-
json: zod.string().transform((v: string) => JSON.parse(v)),
|
|
40
|
-
bool: zod
|
|
41
|
-
.enum(["true", "false", "1", "0", "yes", "no", "y", "n"] as const)
|
|
42
|
-
.transform((v: string) => ["true", "1", "yes", "y"].includes(v)),
|
|
43
|
-
intRange: (min: number, max: number) => zod.coerce.number().int().min(min).max(max),
|
|
44
|
-
}
|