@avijs/cli 0.1.2 → 0.2.1

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.
@@ -0,0 +1,85 @@
1
+ /** Validation libraries generated code can use. `none` keeps handwritten checks. */
2
+ export type Validator = 'valibot' | 'zod' | 'none';
3
+
4
+ export const VALIDATORS: readonly Validator[] = ['valibot', 'zod', 'none'];
5
+
6
+ /** Version ranges added to a new project's dependencies. */
7
+ export const VALIDATOR_VERSIONS: Record<Exclude<Validator, 'none'>, string> = {
8
+ valibot: '^1.5.0',
9
+ zod: '^4.6.0',
10
+ };
11
+
12
+ /** How each library spells the few schemas the templates and generators need. */
13
+ export interface SchemaSyntax {
14
+ readonly import: string;
15
+ /** Params `{ id }`: digits in, a number out. */
16
+ readonly id: string;
17
+ readonly number: string;
18
+ readonly string: string;
19
+ /** An optional `PORT` variable: digits, as a number, default 3000. */
20
+ readonly port: string;
21
+ /** A trimmed, required string of at most `max` characters. */
22
+ text(max: number, required: string): string;
23
+ object(fields: readonly (readonly [string, string])[]): string;
24
+ array(item: string): string;
25
+ /** Every field of `schema` optional, but at least one present. */
26
+ partialNonEmpty(schema: string): string;
27
+ /** The output type of `schema`. */
28
+ infer(schema: string): string;
29
+ }
30
+
31
+ const fields = (entries: readonly (readonly [string, string])[]) =>
32
+ entries.map(([key, value]) => ` ${key}: ${value},\n`).join('');
33
+
34
+ export const SYNTAX: Record<Exclude<Validator, 'none'>, SchemaSyntax> = {
35
+ valibot: {
36
+ import: "import * as v from 'valibot';",
37
+ id: `v.object({
38
+ id: v.pipe(v.string(), v.regex(/^\\d+$/, 'id must be a number'), v.transform(Number)),
39
+ })`,
40
+ number: 'v.number()',
41
+ string: 'v.string()',
42
+ port: `v.optional(
43
+ v.pipe(v.string(), v.regex(/^\\d+$/, 'PORT must be a number'), v.transform(Number)),
44
+ '3000',
45
+ )`,
46
+ text: (max, required) =>
47
+ `v.pipe(v.string(), v.trim(), v.minLength(1, '${required}'), v.maxLength(${String(max)}))`,
48
+ object: (entries) => `v.object({\n${fields(entries)}})`,
49
+ array: (item) => `v.array(${item})`,
50
+ partialNonEmpty: (schema) => `v.pipe(
51
+ v.partial(${schema}),
52
+ v.check((input) => Object.keys(input).length > 0, 'nothing to update'),
53
+ )`,
54
+ infer: (schema) => `v.InferOutput<typeof ${schema}>`,
55
+ },
56
+ zod: {
57
+ import: "import { z } from 'zod';",
58
+ id: `z.object({
59
+ id: z.string().regex(/^\\d+$/, 'id must be a number').transform(Number),
60
+ })`,
61
+ number: 'z.number()',
62
+ string: 'z.string()',
63
+ port: "z.string().regex(/^\\d+$/, 'PORT must be a number').default('3000').transform(Number)",
64
+ text: (max, required) => `z.string().trim().min(1, '${required}').max(${String(max)})`,
65
+ object: (entries) => `z.object({\n${fields(entries)}})`,
66
+ array: (item) => `z.array(${item})`,
67
+ partialNonEmpty: (schema) => `${schema}
68
+ .partial()
69
+ .refine((input) => Object.keys(input).length > 0, 'nothing to update')`,
70
+ infer: (schema) => `z.infer<typeof ${schema}>`,
71
+ },
72
+ };
73
+
74
+ /** The validator a project already uses, from its package.json; Valibot wins over Zod. */
75
+ export function detectValidator(packageJson: unknown): Validator {
76
+ const pkg = packageJson as {
77
+ dependencies?: Record<string, unknown>;
78
+ devDependencies?: Record<string, unknown>;
79
+ } | null;
80
+ const has = (name: string) =>
81
+ pkg?.dependencies?.[name] !== undefined || pkg?.devDependencies?.[name] !== undefined;
82
+ if (has('valibot')) return 'valibot';
83
+ if (has('zod')) return 'zod';
84
+ return 'none';
85
+ }