@rexeus/typeweaver-types 0.6.4 → 0.6.5

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,268 +0,0 @@
1
- /**
2
- * This file was automatically generated by typeweaver.
3
- * DO NOT EDIT. Instead, modify the source definition file and generate again.
4
- *
5
- * @generated by @rexeus/typeweaver
6
- */
7
-
8
- import type {
9
- HttpHeaderSchema,
10
- HttpQuerySchema,
11
- } from "@rexeus/typeweaver-core";
12
- import z from "zod";
13
- import { $ZodArray, $ZodOptional } from "zod/v4/core";
14
- import type { $ZodShape } from "zod/v4/core";
15
-
16
- type SchemaInfo = { readonly originalKey: string; readonly isArray: boolean };
17
-
18
- /**
19
- * Abstract base class for HTTP validation.
20
- *
21
- * This class provides the foundation for request and response validators that:
22
- * - Analyze Zod schemas for correct single/multi value handling of headers and query parameters
23
- * - Coerce objects to match schema expectations
24
- */
25
- export abstract class Validator {
26
- private static readonly schemaCacheCaseSensitive = new WeakMap<
27
- $ZodShape,
28
- Map<string, SchemaInfo>
29
- >();
30
- private static readonly schemaCacheCaseInsensitive = new WeakMap<
31
- $ZodShape,
32
- Map<string, SchemaInfo>
33
- >();
34
- /**
35
- * Analyzes a Zod schema shape to create an efficient lookup map.
36
- * Results are cached using WeakMap for optimal performance.
37
- *
38
- * @param shape - The Zod schema shape to analyze
39
- * @param caseSensitive - Whether to preserve key casing (true) or normalize to lowercase (false)
40
- * @returns Map with lookup keys pointing to original key and array type information
41
- */
42
- protected analyzeSchema(
43
- shape: $ZodShape,
44
- caseSensitive: boolean
45
- ): Map<string, SchemaInfo> {
46
- const cache = caseSensitive
47
- ? Validator.schemaCacheCaseSensitive
48
- : Validator.schemaCacheCaseInsensitive;
49
-
50
- const cached = cache.get(shape);
51
- if (cached) {
52
- return cached;
53
- }
54
-
55
- const schemaMap = this.buildSchemaMap(shape, caseSensitive);
56
- cache.set(shape, schemaMap);
57
- return schemaMap;
58
- }
59
-
60
- /**
61
- *
62
- * Extracts a Zod schema shape from header or query schemas.
63
- * This is used to support schema coercion and analysis.
64
- *
65
- * @param headerSchema
66
- * @returns
67
- */
68
- protected getSchema(
69
- headerSchema: HttpHeaderSchema | HttpQuerySchema
70
- ): $ZodShape {
71
- if (headerSchema instanceof z.ZodObject) {
72
- return headerSchema.shape;
73
- }
74
- if (headerSchema instanceof z.ZodOptional) {
75
- const unwrapped = headerSchema.unwrap();
76
- if (unwrapped instanceof z.ZodObject) {
77
- return unwrapped.shape;
78
- }
79
- }
80
- return {};
81
- }
82
-
83
- /**
84
- * Builds a schema map by analyzing the Zod shape structure.
85
- * Extracts type information for each field to support proper coercion.
86
- */
87
- private buildSchemaMap(
88
- shape: $ZodShape,
89
- caseSensitive: boolean
90
- ): Map<string, SchemaInfo> {
91
- const schemaMap = new Map<string, SchemaInfo>();
92
- for (const [key, zodType] of Object.entries(shape)) {
93
- if (!zodType) continue;
94
-
95
- const isArray =
96
- zodType instanceof $ZodArray ||
97
- (zodType instanceof $ZodOptional &&
98
- zodType._zod.def.innerType instanceof $ZodArray);
99
-
100
- const lookupKey = caseSensitive ? key : key.toLowerCase();
101
- schemaMap.set(lookupKey, { originalKey: key, isArray });
102
- }
103
- return schemaMap;
104
- }
105
-
106
- /**
107
- * Coerces objects to match schema expectations with configurable case sensitivity.
108
- * Values not in the schema are ignored.
109
- *
110
- * @param data - The data object to coerce
111
- * @param shape - The Zod schema shape to match against
112
- * @param caseSensitive - Whether keys should match exactly (true) or case-insensitively (false)
113
- * @returns Coerced data object with proper key casing and array coercion
114
- */
115
- protected coerceToSchema(
116
- data: unknown,
117
- shape: $ZodShape,
118
- caseSensitive: boolean
119
- ): unknown {
120
- if (typeof data !== "object" || data === null) {
121
- return data;
122
- }
123
-
124
- const schemaMap = this.analyzeSchema(shape, caseSensitive);
125
- const coerced: Record<string, unknown | unknown[]> = {};
126
-
127
- for (const [key, value] of Object.entries(data)) {
128
- const normalizedKey = caseSensitive ? key : key.toLowerCase();
129
- const schemaInfo = schemaMap.get(normalizedKey);
130
-
131
- if (schemaInfo) {
132
- this.addValueToCoerced(
133
- coerced,
134
- normalizedKey,
135
- value,
136
- schemaInfo.isArray
137
- );
138
- }
139
- // Headers/params not in schema are ignored (strict validation)
140
- }
141
-
142
- // If case-sensitive, return coerced object as is
143
- if (caseSensitive) {
144
- return coerced;
145
- }
146
-
147
- // If case-insensitive, map back to original keys from schema
148
- return this.mapToOriginalKeys(coerced, schemaMap);
149
- }
150
-
151
- /**
152
- * Adds a value to the coerced object, handling collisions when multiple
153
- * values exist for the same key (e.g., duplicate headers with different casing).
154
- * Preserves all values as arrays when collisions occur to prevent data loss.
155
- */
156
- private addValueToCoerced(
157
- coerced: Record<string, unknown | unknown[]>,
158
- key: string,
159
- value: unknown,
160
- expectsArray: boolean
161
- ): void {
162
- const existing = coerced[key];
163
- const newValue = this.coerceValueStructure(value, expectsArray);
164
-
165
- if (existing === undefined) {
166
- coerced[key] = newValue;
167
- return;
168
- }
169
-
170
- // Merge existing and new values
171
- const existingArray = Array.isArray(existing) ? existing : [existing];
172
- const newArray = Array.isArray(newValue) ? newValue : [newValue];
173
- const merged = [...existingArray, ...newArray];
174
-
175
- // If schema expects a single value but we have multiple, preserve as array
176
- // to avoid data loss (validation will catch this later)
177
- coerced[key] = expectsArray || merged.length > 1 ? merged : merged[0];
178
- }
179
-
180
- /**
181
- * Coerces a value's structure to match schema expectations.
182
- * Wraps single values in arrays when schema expects array type,
183
- * unwraps single-element arrays when schema expects single value.
184
- */
185
- private coerceValueStructure(
186
- value: unknown,
187
- expectsArray: boolean
188
- ): unknown | unknown[] {
189
- if (expectsArray && !Array.isArray(value)) {
190
- return [value];
191
- }
192
- if (!expectsArray && Array.isArray(value) && value.length === 1) {
193
- return value[0];
194
- }
195
- return value;
196
- }
197
-
198
- /**
199
- * Maps normalized (lowercase) keys back to their original casing as defined in the schema.
200
- * Used for case-insensitive matching where the output should preserve schema-defined casing.
201
- */
202
- private mapToOriginalKeys(
203
- coerced: Record<string, unknown | unknown[]>,
204
- schemaMap: Map<string, SchemaInfo>
205
- ): Record<string, unknown | unknown[]> {
206
- const withOriginalKeys: Record<string, unknown | unknown[]> = {};
207
- for (const [key, value] of Object.entries(coerced)) {
208
- const originalKey = schemaMap.get(key)?.originalKey ?? key;
209
- withOriginalKeys[originalKey] = value;
210
- }
211
- return withOriginalKeys;
212
- }
213
-
214
- /**
215
- * Coerces header data to match schema expectations with case-insensitive matching.
216
- *
217
- * @param header - The header object to coerce
218
- * @param shape - The Zod schema shape for headers
219
- * @returns Coerced header object
220
- */
221
- protected coerceHeaderToSchema(header: unknown, shape: $ZodShape): unknown {
222
- if (typeof header !== "object" || header === null) {
223
- return this.coerceToSchema(header ?? {}, shape, false);
224
- }
225
-
226
- const preprocessed = this.splitCommaDelimitedValues(header, shape);
227
- return this.coerceToSchema(preprocessed, shape, false);
228
- }
229
-
230
- /**
231
- * Splits comma-separated header strings into arrays per RFC 7230.
232
- * Only applies to fields where the schema expects an array type.
233
- * Values that are already arrays pass through unchanged.
234
- */
235
- private splitCommaDelimitedValues(
236
- header: object,
237
- shape: $ZodShape
238
- ): Record<string, unknown> {
239
- const schemaMap = this.analyzeSchema(shape, false);
240
- const result: Record<string, unknown> = {};
241
-
242
- for (const [key, value] of Object.entries(header)) {
243
- const schemaInfo = schemaMap.get(key.toLowerCase());
244
-
245
- if (schemaInfo?.isArray && typeof value === "string") {
246
- result[key] = value
247
- .split(",")
248
- .map(v => v.trim())
249
- .filter(v => v !== "");
250
- } else {
251
- result[key] = value;
252
- }
253
- }
254
-
255
- return result;
256
- }
257
-
258
- /**
259
- * Coerces query data to match schema expectations with case-sensitive matching.
260
- *
261
- * @param query - The query object to coerce
262
- * @param shape - The Zod schema shape for query parameters
263
- * @returns Coerced query object
264
- */
265
- protected coerceQueryToSchema(query: unknown, shape: $ZodShape): unknown {
266
- return this.coerceToSchema(query ?? {}, shape, true); // case-sensitive
267
- }
268
- }
@@ -1,12 +0,0 @@
1
- /**
2
- * This file was automatically generated by typeweaver.
3
- * DO NOT EDIT. Instead, modify the source definition file and generate again.
4
- *
5
- * @generated by @rexeus/typeweaver
6
- */
7
-
8
- export function assert(value: any, message?: string): asserts value {
9
- if (!value) {
10
- throw new Error(message || "Assertion failed");
11
- }
12
- }