@rexeus/typeweaver-types 0.10.0 → 0.10.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,185 +1,198 @@
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
+ */
1
7
  import z from "zod";
2
8
  import { $ZodArray, $ZodOptional } from "zod/v4/core";
3
9
  /**
4
- * Abstract base class for HTTP validation.
5
- *
6
- * This class provides the foundation for request and response validators that:
7
- * - Analyze Zod schemas for correct single/multi value handling of headers and query parameters
8
- * - Coerce objects to match schema expectations
9
- */
10
+ * Abstract base class for HTTP validation.
11
+ *
12
+ * This class provides the foundation for request and response validators that:
13
+ * - Analyze Zod schemas for correct single/multi value handling of headers and query parameters
14
+ * - Coerce objects to match schema expectations
15
+ */
10
16
  export class Validator {
11
- static schemaCacheCaseSensitive = new WeakMap();
12
- static schemaCacheCaseInsensitive = new WeakMap();
13
- /**
14
- * Analyzes a Zod schema shape to create an efficient lookup map.
15
- * Results are cached using WeakMap for optimal performance.
16
- *
17
- * @param shape - The Zod schema shape to analyze
18
- * @param caseSensitive - Whether to preserve key casing (true) or normalize to lowercase (false)
19
- * @returns Map with lookup keys pointing to original key and array type information
20
- */
21
- analyzeSchema(shape, caseSensitive) {
22
- const cache = caseSensitive ? Validator.schemaCacheCaseSensitive : Validator.schemaCacheCaseInsensitive;
23
- const cached = cache.get(shape);
24
- if (cached) {
25
- return cached;
26
- }
27
- const schemaMap = this.buildSchemaMap(shape, caseSensitive);
28
- cache.set(shape, schemaMap);
29
- return schemaMap;
30
- }
31
- /**
32
- *
33
- * Extracts a Zod schema shape from header or query schemas.
34
- * This is used to support schema coercion and analysis.
35
- *
36
- * @param headerSchema
37
- * @returns
38
- */
39
- getSchema(headerSchema) {
40
- if (headerSchema instanceof z.ZodObject) {
41
- return headerSchema.shape;
42
- }
43
- if (headerSchema instanceof z.ZodOptional) {
44
- const unwrapped = headerSchema.unwrap();
45
- if (unwrapped instanceof z.ZodObject) {
46
- return unwrapped.shape;
47
- }
48
- }
49
- return {};
50
- }
51
- /**
52
- * Builds a schema map by analyzing the Zod shape structure.
53
- * Extracts type information for each field to support proper coercion.
54
- */
55
- buildSchemaMap(shape, caseSensitive) {
56
- const schemaMap = new Map();
57
- for (const [key, zodType] of Object.entries(shape)) {
58
- if (!zodType) continue;
59
- const isArray = zodType instanceof $ZodArray || zodType instanceof $ZodOptional && zodType._zod.def.innerType instanceof $ZodArray;
60
- const lookupKey = caseSensitive ? key : key.toLowerCase();
61
- schemaMap.set(lookupKey, {
62
- originalKey: key,
63
- isArray
64
- });
65
- }
66
- return schemaMap;
67
- }
68
- /**
69
- * Coerces objects to match schema expectations with configurable case sensitivity.
70
- * Values not in the schema are ignored.
71
- *
72
- * @param data - The data object to coerce
73
- * @param shape - The Zod schema shape to match against
74
- * @param caseSensitive - Whether keys should match exactly (true) or case-insensitively (false)
75
- * @returns Coerced data object with proper key casing and array coercion
76
- */
77
- coerceToSchema(data, shape, caseSensitive) {
78
- if (typeof data !== "object" || data === null) {
79
- return data;
80
- }
81
- const schemaMap = this.analyzeSchema(shape, caseSensitive);
82
- const coerced = {};
83
- for (const [key, value] of Object.entries(data)) {
84
- const normalizedKey = caseSensitive ? key : key.toLowerCase();
85
- const schemaInfo = schemaMap.get(normalizedKey);
86
- if (schemaInfo) {
87
- this.addValueToCoerced(coerced, normalizedKey, value, schemaInfo.isArray);
88
- }
89
- }
90
- // If case-sensitive, return coerced object as is
91
- if (caseSensitive) {
92
- return coerced;
93
- }
94
- // If case-insensitive, map back to original keys from schema
95
- return this.mapToOriginalKeys(coerced, schemaMap);
96
- }
97
- /**
98
- * Adds a value to the coerced object, handling collisions when multiple
99
- * values exist for the same key (e.g., duplicate headers with different casing).
100
- * Preserves all values as arrays when collisions occur to prevent data loss.
101
- */
102
- addValueToCoerced(coerced, key, value, expectsArray) {
103
- const existing = coerced[key];
104
- const newValue = this.coerceValueStructure(value, expectsArray);
105
- if (existing === undefined) {
106
- coerced[key] = newValue;
107
- return;
108
- }
109
- // Merge existing and new values
110
- const existingArray = Array.isArray(existing) ? existing : [existing];
111
- const newArray = Array.isArray(newValue) ? newValue : [newValue];
112
- const merged = [...existingArray, ...newArray];
113
- // If schema expects a single value but we have multiple, preserve as array
114
- // to avoid data loss (validation will catch this later)
115
- coerced[key] = expectsArray || merged.length > 1 ? merged : merged[0];
116
- }
117
- /**
118
- * Coerces a value's structure to match schema expectations.
119
- * Wraps single values in arrays when schema expects array type,
120
- * unwraps single-element arrays when schema expects single value.
121
- */
122
- coerceValueStructure(value, expectsArray) {
123
- if (expectsArray && !Array.isArray(value)) {
124
- return [value];
125
- }
126
- if (!expectsArray && Array.isArray(value) && value.length === 1) {
127
- return value[0];
128
- }
129
- return value;
130
- }
131
- /**
132
- * Maps normalized (lowercase) keys back to their original casing as defined in the schema.
133
- * Used for case-insensitive matching where the output should preserve schema-defined casing.
134
- */
135
- mapToOriginalKeys(coerced, schemaMap) {
136
- const withOriginalKeys = {};
137
- for (const [key, value] of Object.entries(coerced)) {
138
- const originalKey = schemaMap.get(key)?.originalKey ?? key;
139
- withOriginalKeys[originalKey] = value;
140
- }
141
- return withOriginalKeys;
142
- }
143
- /**
144
- * Coerces header data to match schema expectations with case-insensitive matching.
145
- *
146
- * @param header - The header object to coerce
147
- * @param shape - The Zod schema shape for headers
148
- * @returns Coerced header object
149
- */
150
- coerceHeaderToSchema(header, shape) {
151
- if (typeof header !== "object" || header === null) {
152
- return this.coerceToSchema(header ?? {}, shape, false);
153
- }
154
- const preprocessed = this.splitCommaDelimitedValues(header, shape);
155
- return this.coerceToSchema(preprocessed, shape, false);
156
- }
157
- /**
158
- * Splits comma-separated header strings into arrays per RFC 7230.
159
- * Only applies to fields where the schema expects an array type.
160
- * Values that are already arrays pass through unchanged.
161
- */
162
- splitCommaDelimitedValues(header, shape) {
163
- const schemaMap = this.analyzeSchema(shape, false);
164
- const result = {};
165
- for (const [key, value] of Object.entries(header)) {
166
- const schemaInfo = schemaMap.get(key.toLowerCase());
167
- if (schemaInfo?.isArray && typeof value === "string") {
168
- result[key] = value.split(",").map((v) => v.trim()).filter((v) => v !== "");
169
- } else {
170
- result[key] = value;
171
- }
172
- }
173
- return result;
174
- }
175
- /**
176
- * Coerces query data to match schema expectations with case-sensitive matching.
177
- *
178
- * @param query - The query object to coerce
179
- * @param shape - The Zod schema shape for query parameters
180
- * @returns Coerced query object
181
- */
182
- coerceQueryToSchema(query, shape) {
183
- return this.coerceToSchema(query ?? {}, shape, true);
184
- }
17
+ static schemaCacheCaseSensitive = new WeakMap();
18
+ static schemaCacheCaseInsensitive = new WeakMap();
19
+ /**
20
+ * Analyzes a Zod schema shape to create an efficient lookup map.
21
+ * Results are cached using WeakMap for optimal performance.
22
+ *
23
+ * @param shape - The Zod schema shape to analyze
24
+ * @param caseSensitive - Whether to preserve key casing (true) or normalize to lowercase (false)
25
+ * @returns Map with lookup keys pointing to original key and array type information
26
+ */
27
+ analyzeSchema(shape, caseSensitive) {
28
+ const cache = caseSensitive
29
+ ? Validator.schemaCacheCaseSensitive
30
+ : Validator.schemaCacheCaseInsensitive;
31
+ const cached = cache.get(shape);
32
+ if (cached) {
33
+ return cached;
34
+ }
35
+ const schemaMap = this.buildSchemaMap(shape, caseSensitive);
36
+ cache.set(shape, schemaMap);
37
+ return schemaMap;
38
+ }
39
+ /**
40
+ *
41
+ * Extracts a Zod schema shape from header or query schemas.
42
+ * This is used to support schema coercion and analysis.
43
+ *
44
+ * @param headerSchema
45
+ * @returns
46
+ */
47
+ getSchema(headerSchema) {
48
+ if (headerSchema instanceof z.ZodObject) {
49
+ return headerSchema.shape;
50
+ }
51
+ if (headerSchema instanceof z.ZodOptional) {
52
+ const unwrapped = headerSchema.unwrap();
53
+ if (unwrapped instanceof z.ZodObject) {
54
+ return unwrapped.shape;
55
+ }
56
+ }
57
+ return {};
58
+ }
59
+ /**
60
+ * Builds a schema map by analyzing the Zod shape structure.
61
+ * Extracts type information for each field to support proper coercion.
62
+ */
63
+ buildSchemaMap(shape, caseSensitive) {
64
+ const schemaMap = new Map();
65
+ for (const [key, zodType] of Object.entries(shape)) {
66
+ if (!zodType)
67
+ continue;
68
+ const isArray = zodType instanceof $ZodArray ||
69
+ (zodType instanceof $ZodOptional &&
70
+ zodType._zod.def.innerType instanceof $ZodArray);
71
+ const lookupKey = caseSensitive ? key : key.toLowerCase();
72
+ schemaMap.set(lookupKey, { originalKey: key, isArray });
73
+ }
74
+ return schemaMap;
75
+ }
76
+ /**
77
+ * Coerces objects to match schema expectations with configurable case sensitivity.
78
+ * Values not in the schema are ignored.
79
+ *
80
+ * @param data - The data object to coerce
81
+ * @param shape - The Zod schema shape to match against
82
+ * @param caseSensitive - Whether keys should match exactly (true) or case-insensitively (false)
83
+ * @returns Coerced data object with proper key casing and array coercion
84
+ */
85
+ coerceToSchema(data, shape, caseSensitive) {
86
+ if (typeof data !== "object" || data === null) {
87
+ return data;
88
+ }
89
+ const schemaMap = this.analyzeSchema(shape, caseSensitive);
90
+ const coerced = {};
91
+ for (const [key, value] of Object.entries(data)) {
92
+ const normalizedKey = caseSensitive ? key : key.toLowerCase();
93
+ const schemaInfo = schemaMap.get(normalizedKey);
94
+ if (schemaInfo) {
95
+ this.addValueToCoerced(coerced, normalizedKey, value, schemaInfo.isArray);
96
+ }
97
+ // Headers/params not in schema are ignored (strict validation)
98
+ }
99
+ // If case-sensitive, return coerced object as is
100
+ if (caseSensitive) {
101
+ return coerced;
102
+ }
103
+ // If case-insensitive, map back to original keys from schema
104
+ return this.mapToOriginalKeys(coerced, schemaMap);
105
+ }
106
+ /**
107
+ * Adds a value to the coerced object, handling collisions when multiple
108
+ * values exist for the same key (e.g., duplicate headers with different casing).
109
+ * Preserves all values as arrays when collisions occur to prevent data loss.
110
+ */
111
+ addValueToCoerced(coerced, key, value, expectsArray) {
112
+ const existing = coerced[key];
113
+ const newValue = this.coerceValueStructure(value, expectsArray);
114
+ if (existing === undefined) {
115
+ coerced[key] = newValue;
116
+ return;
117
+ }
118
+ // Merge existing and new values
119
+ const existingArray = Array.isArray(existing) ? existing : [existing];
120
+ const newArray = Array.isArray(newValue) ? newValue : [newValue];
121
+ const merged = [...existingArray, ...newArray];
122
+ // If schema expects a single value but we have multiple, preserve as array
123
+ // to avoid data loss (validation will catch this later)
124
+ coerced[key] = expectsArray || merged.length > 1 ? merged : merged[0];
125
+ }
126
+ /**
127
+ * Coerces a value's structure to match schema expectations.
128
+ * Wraps single values in arrays when schema expects array type,
129
+ * unwraps single-element arrays when schema expects single value.
130
+ */
131
+ coerceValueStructure(value, expectsArray) {
132
+ if (expectsArray && !Array.isArray(value)) {
133
+ return [value];
134
+ }
135
+ if (!expectsArray && Array.isArray(value) && value.length === 1) {
136
+ return value[0];
137
+ }
138
+ return value;
139
+ }
140
+ /**
141
+ * Maps normalized (lowercase) keys back to their original casing as defined in the schema.
142
+ * Used for case-insensitive matching where the output should preserve schema-defined casing.
143
+ */
144
+ mapToOriginalKeys(coerced, schemaMap) {
145
+ const withOriginalKeys = {};
146
+ for (const [key, value] of Object.entries(coerced)) {
147
+ const originalKey = schemaMap.get(key)?.originalKey ?? key;
148
+ withOriginalKeys[originalKey] = value;
149
+ }
150
+ return withOriginalKeys;
151
+ }
152
+ /**
153
+ * Coerces header data to match schema expectations with case-insensitive matching.
154
+ *
155
+ * @param header - The header object to coerce
156
+ * @param shape - The Zod schema shape for headers
157
+ * @returns Coerced header object
158
+ */
159
+ coerceHeaderToSchema(header, shape) {
160
+ if (typeof header !== "object" || header === null) {
161
+ return this.coerceToSchema(header ?? {}, shape, false);
162
+ }
163
+ const preprocessed = this.splitCommaDelimitedValues(header, shape);
164
+ return this.coerceToSchema(preprocessed, shape, false);
165
+ }
166
+ /**
167
+ * Splits comma-separated header strings into arrays per RFC 7230.
168
+ * Only applies to fields where the schema expects an array type.
169
+ * Values that are already arrays pass through unchanged.
170
+ */
171
+ splitCommaDelimitedValues(header, shape) {
172
+ const schemaMap = this.analyzeSchema(shape, false);
173
+ const result = {};
174
+ for (const [key, value] of Object.entries(header)) {
175
+ const schemaInfo = schemaMap.get(key.toLowerCase());
176
+ if (schemaInfo?.isArray && typeof value === "string") {
177
+ result[key] = value
178
+ .split(",")
179
+ .map(v => v.trim())
180
+ .filter(v => v !== "");
181
+ }
182
+ else {
183
+ result[key] = value;
184
+ }
185
+ }
186
+ return result;
187
+ }
188
+ /**
189
+ * Coerces query data to match schema expectations with case-sensitive matching.
190
+ *
191
+ * @param query - The query object to coerce
192
+ * @param shape - The Zod schema shape for query parameters
193
+ * @returns Coerced query object
194
+ */
195
+ coerceQueryToSchema(query, shape) {
196
+ return this.coerceToSchema(query ?? {}, shape, true); // case-sensitive
197
+ }
185
198
  }
@@ -1,14 +1,20 @@
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
+ */
1
7
  export const getOperationDefinition = (spec, resourceName, operationId) => {
2
- const operation = spec.resources[resourceName]?.operations.find((candidate) => candidate.operationId === operationId);
3
- if (operation === undefined) {
4
- throw new Error(`Missing operation definition '${String(resourceName)}.${String(operationId)}'.`);
5
- }
6
- return operation;
8
+ const operation = spec.resources[resourceName]?.operations.find(candidate => candidate.operationId === operationId);
9
+ if (operation === undefined) {
10
+ throw new Error(`Missing operation definition '${String(resourceName)}.${String(operationId)}'.`);
11
+ }
12
+ return operation;
7
13
  };
8
14
  export const getResponseDefinition = (responses, responseName) => {
9
- const response = responses.find((candidate) => candidate.name === responseName);
10
- if (response === undefined) {
11
- throw new Error(`Missing response definition '${String(responseName)}'.`);
12
- }
13
- return response;
15
+ const response = responses.find(candidate => candidate.name === responseName);
16
+ if (response === undefined) {
17
+ throw new Error(`Missing response definition '${String(responseName)}'.`);
18
+ }
19
+ return response;
14
20
  };
package/dist/lib/index.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  * @generated by @rexeus/typeweaver
6
6
  */
7
7
 
8
- export * from "./definitionLookup";
9
- export * from "./RequestValidator";
10
- export * from "./ResponseValidator";
11
- export * from "./Validator";
8
+ export * from "./definitionLookup.js";
9
+ export * from "./RequestValidator.js";
10
+ export * from "./ResponseValidator.js";
11
+ export * from "./Validator.js";
@@ -12,7 +12,7 @@ import {
12
12
  type SafeRequestValidationResult,
13
13
  RequestValidationError
14
14
  } from "@rexeus/typeweaver-core";
15
- import { getOperationDefinition, RequestValidator } from "../lib/types";
15
+ import { getOperationDefinition, RequestValidator } from "../lib/types/index.js";
16
16
  import type { I<%= pascalCaseOperationId %>Request } from "<%= requestFile %>";
17
17
 
18
18
  const definition = getOperationDefinition(spec, "<%= resourceName %>", "<%= operationId %>");
@@ -12,7 +12,7 @@ import {
12
12
  getResponseDefinition,
13
13
  type ResponseEntry,
14
14
  ResponseValidator,
15
- } from "../lib/types";
15
+ } from "../lib/types/index.js";
16
16
  import type { <%= pascalCaseOperationId %>Response } from "<%= responseFile %>";
17
17
 
18
18
  const definition = getOperationDefinition(spec, "<%= resourceName %>", "<%= operationId %>");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rexeus/typeweaver-types",
3
- "version": "0.10.0",
3
+ "version": "0.10.2",
4
4
  "description": "Generates request and response types plus validators aligned with your API contract. Powered by Typeweaver 🧵✨",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -47,22 +47,21 @@
47
47
  },
48
48
  "homepage": "https://github.com/rexeus/typeweaver#readme",
49
49
  "peerDependencies": {
50
- "@rexeus/typeweaver-core": "^0.10.0",
51
- "@rexeus/typeweaver-gen": "^0.10.0"
50
+ "@rexeus/typeweaver-core": "^0.10.2",
51
+ "@rexeus/typeweaver-gen": "^0.10.2"
52
52
  },
53
53
  "devDependencies": {
54
- "oxc-transform": "^0.121.0",
55
54
  "test-utils": "file:../test-utils",
56
- "@rexeus/typeweaver-core": "^0.10.0",
57
- "@rexeus/typeweaver-gen": "^0.10.0"
55
+ "@rexeus/typeweaver-core": "^0.10.2",
56
+ "@rexeus/typeweaver-gen": "^0.10.2"
58
57
  },
59
58
  "dependencies": {
60
- "@rexeus/typeweaver-zod-to-ts": "^0.10.0"
59
+ "@rexeus/typeweaver-zod-to-ts": "^0.10.2"
61
60
  },
62
61
  "scripts": {
63
62
  "typecheck": "tsc --noEmit -p tsconfig.typecheck.json",
64
63
  "format": "oxfmt",
65
- "build": "tsdown && mkdir -p ./dist/templates ./dist/lib && cp -r ./src/templates/* ./dist/templates/ && node scripts/compile-lib.mjs && cp src/lib-declarations/*.d.ts dist/lib/ && cp src/lib/index.ts dist/lib/ && cp ../../LICENSE ../../NOTICE ./dist/",
64
+ "build": "tsdown",
66
65
  "test": "vitest --run",
67
66
  "preversion": "npm run build"
68
67
  }