@crustjs/validate 0.0.1 → 0.0.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.
@@ -1,196 +0,0 @@
1
- // @bun
2
- // src/validation.ts
3
- import { CrustError } from "@crustjs/core";
4
- function formatPath(path) {
5
- let result = "";
6
- for (const segment of path) {
7
- if (typeof segment === "number") {
8
- result += `[${String(segment)}]`;
9
- } else {
10
- const str = String(segment);
11
- if (result.length > 0) {
12
- result += `.${str}`;
13
- } else {
14
- result = str;
15
- }
16
- }
17
- }
18
- return result;
19
- }
20
- function normalizeIssue(issue) {
21
- return {
22
- message: issue.message,
23
- path: issue.path ? formatPath(issue.path) : ""
24
- };
25
- }
26
- function normalizeIssues(issues) {
27
- return issues.map(normalizeIssue);
28
- }
29
- function renderIssueLine(issue) {
30
- if (issue.path) {
31
- return ` - ${issue.path}: ${issue.message}`;
32
- }
33
- return ` - ${issue.message}`;
34
- }
35
- function renderBulletList(prefix, issues) {
36
- if (issues.length === 0)
37
- return prefix;
38
- const lines = issues.map(renderIssueLine);
39
- return `${prefix}
40
- ${lines.join(`
41
- `)}`;
42
- }
43
- function throwValidationError(issues, prefix = "Validation failed") {
44
- const message = renderBulletList(prefix, issues);
45
- throw new CrustError("VALIDATION", message, { issues }).withCause(issues);
46
- }
47
-
48
- // src/flagSpec.ts
49
- function isFlagSpec(value) {
50
- return typeof value === "object" && value !== null && "kind" in value && value.kind === "flag";
51
- }
52
- function getFlagSchema(value) {
53
- return isFlagSpec(value) ? value.schema : value;
54
- }
55
-
56
- // src/runner.ts
57
- async function validateArgs(argSpecs, context, issues, validateValue) {
58
- const output = {};
59
- for (const spec of argSpecs) {
60
- const input = context.args[spec.name];
61
- if (spec.variadic) {
62
- const items = Array.isArray(input) ? input : input === undefined ? [] : [input];
63
- const transformed = [];
64
- for (let i = 0;i < items.length; i++) {
65
- const value = items[i];
66
- const validated2 = await validateValue(spec.schema, value, [
67
- "args",
68
- spec.name,
69
- i
70
- ]);
71
- if (!validated2.ok) {
72
- issues.push(...validated2.issues);
73
- continue;
74
- }
75
- transformed.push(validated2.value);
76
- }
77
- output[spec.name] = transformed;
78
- continue;
79
- }
80
- const validated = await validateValue(spec.schema, input, [
81
- "args",
82
- spec.name
83
- ]);
84
- if (!validated.ok) {
85
- issues.push(...validated.issues);
86
- continue;
87
- }
88
- output[spec.name] = validated.value;
89
- }
90
- return output;
91
- }
92
- async function validateFlags(flags, context, issues, validateValue) {
93
- if (!flags) {
94
- return {};
95
- }
96
- const output = {};
97
- for (const [name, rawValue] of Object.entries(flags)) {
98
- const schema = getFlagSchema(rawValue);
99
- const input = context.flags[name];
100
- const validated = await validateValue(schema, input, ["flags", name]);
101
- if (!validated.ok) {
102
- issues.push(...validated.issues);
103
- continue;
104
- }
105
- output[name] = validated.value;
106
- }
107
- return output;
108
- }
109
- function buildRunHandler(argSpecs, flags, userRun, validateValue) {
110
- return async (context) => {
111
- const issues = [];
112
- const validatedArgs = await validateArgs(argSpecs, context, issues, validateValue);
113
- const validatedFlags = await validateFlags(flags, context, issues, validateValue);
114
- if (issues.length > 0) {
115
- throwValidationError(issues);
116
- }
117
- const validatedContext = {
118
- args: validatedArgs,
119
- flags: validatedFlags,
120
- rawArgs: context.rawArgs,
121
- command: context.command,
122
- input: {
123
- args: context.args,
124
- flags: context.flags
125
- }
126
- };
127
- return userRun(validatedContext);
128
- };
129
- }
130
-
131
- // src/definitionBuilders.ts
132
- import { CrustError as CrustError2 } from "@crustjs/core";
133
- function buildArgDefinitions(args, adapter) {
134
- const seen = new Set;
135
- for (let i = 0;i < args.length; i++) {
136
- const spec = args[i];
137
- if (!spec)
138
- continue;
139
- if (seen.has(spec.name)) {
140
- throw new CrustError2("DEFINITION", `${adapter.commandLabel}: duplicate arg name "${spec.name}"`);
141
- }
142
- seen.add(spec.name);
143
- if (spec.variadic && i !== args.length - 1) {
144
- throw new CrustError2("DEFINITION", `${adapter.commandLabel}: only the last arg can be variadic (arg "${spec.name}")`);
145
- }
146
- }
147
- return args.map((spec) => {
148
- const shape = adapter.resolveInputShape(spec.schema, `arg "${spec.name}"`);
149
- if (spec.variadic && shape.multiple) {
150
- throw new CrustError2("DEFINITION", `arg "${spec.name}": variadic args must use a scalar schema; do not wrap the schema in ${adapter.arrayHint}`);
151
- }
152
- if (!spec.variadic && shape.multiple) {
153
- throw new CrustError2("DEFINITION", `arg "${spec.name}": array schema requires { variadic: true }`);
154
- }
155
- const description = adapter.resolveDescription(spec.schema);
156
- const required = !adapter.isOptionalInputSchema(spec.schema);
157
- const def = {
158
- name: spec.name,
159
- type: shape.type,
160
- ...description !== undefined && { description },
161
- ...spec.variadic && { variadic: true },
162
- ...required && { required: true }
163
- };
164
- return def;
165
- });
166
- }
167
- function getFlagMetadata(value) {
168
- if (isFlagSpec(value)) {
169
- return { schema: value.schema, alias: value.alias };
170
- }
171
- return { schema: value };
172
- }
173
- function buildFlagDefinitions(flags, adapter) {
174
- if (!flags) {
175
- return {};
176
- }
177
- const result = {};
178
- for (const [name, value] of Object.entries(flags)) {
179
- const metadata = getFlagMetadata(value);
180
- const { schema } = metadata;
181
- const shape = adapter.resolveInputShape(schema, `flag "--${name}"`);
182
- const required = !adapter.isOptionalInputSchema(schema);
183
- const description = adapter.resolveDescription(schema);
184
- const alias = metadata.alias === undefined ? undefined : typeof metadata.alias === "string" ? metadata.alias : [...metadata.alias];
185
- result[name] = {
186
- type: shape.type,
187
- ...shape.multiple && { multiple: true },
188
- ...alias !== undefined && { alias },
189
- ...description !== undefined && { description },
190
- ...required && { required: true }
191
- };
192
- }
193
- return result;
194
- }
195
-
196
- export { normalizeIssues, buildRunHandler, buildArgDefinitions, buildFlagDefinitions };