schemantic 0.1.0

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.
Files changed (131) hide show
  1. package/CHANGELOG.md +92 -0
  2. package/LICENSE +21 -0
  3. package/README.md +827 -0
  4. package/dist/__tests__/setup.d.ts +6 -0
  5. package/dist/__tests__/setup.d.ts.map +1 -0
  6. package/dist/__tests__/setup.js +30 -0
  7. package/dist/__tests__/setup.js.map +1 -0
  8. package/dist/__tests__/test-config.d.ts +36 -0
  9. package/dist/__tests__/test-config.d.ts.map +1 -0
  10. package/dist/__tests__/test-config.js +563 -0
  11. package/dist/__tests__/test-config.js.map +1 -0
  12. package/dist/cli/index.d.ts +118 -0
  13. package/dist/cli/index.d.ts.map +1 -0
  14. package/dist/cli/index.js +657 -0
  15. package/dist/cli/index.js.map +1 -0
  16. package/dist/core/index.d.ts +5 -0
  17. package/dist/core/index.d.ts.map +1 -0
  18. package/dist/core/index.js +21 -0
  19. package/dist/core/index.js.map +1 -0
  20. package/dist/core/schemantic.d.ts +95 -0
  21. package/dist/core/schemantic.d.ts.map +1 -0
  22. package/dist/core/schemantic.js +543 -0
  23. package/dist/core/schemantic.js.map +1 -0
  24. package/dist/generators/api-client-generator.d.ts +145 -0
  25. package/dist/generators/api-client-generator.d.ts.map +1 -0
  26. package/dist/generators/api-client-generator.js +856 -0
  27. package/dist/generators/api-client-generator.js.map +1 -0
  28. package/dist/generators/base.d.ts +117 -0
  29. package/dist/generators/base.d.ts.map +1 -0
  30. package/dist/generators/base.js +232 -0
  31. package/dist/generators/base.js.map +1 -0
  32. package/dist/generators/enum-generator.d.ts +52 -0
  33. package/dist/generators/enum-generator.d.ts.map +1 -0
  34. package/dist/generators/enum-generator.js +178 -0
  35. package/dist/generators/enum-generator.js.map +1 -0
  36. package/dist/generators/factory.d.ts +59 -0
  37. package/dist/generators/factory.d.ts.map +1 -0
  38. package/dist/generators/factory.js +127 -0
  39. package/dist/generators/factory.js.map +1 -0
  40. package/dist/generators/hook-generator.d.ts +36 -0
  41. package/dist/generators/hook-generator.d.ts.map +1 -0
  42. package/dist/generators/hook-generator.js +495 -0
  43. package/dist/generators/hook-generator.js.map +1 -0
  44. package/dist/generators/index.d.ts +10 -0
  45. package/dist/generators/index.d.ts.map +1 -0
  46. package/dist/generators/index.js +26 -0
  47. package/dist/generators/index.js.map +1 -0
  48. package/dist/generators/object-generator.d.ts +48 -0
  49. package/dist/generators/object-generator.d.ts.map +1 -0
  50. package/dist/generators/object-generator.js +280 -0
  51. package/dist/generators/object-generator.js.map +1 -0
  52. package/dist/generators/primitive-generator.d.ts +40 -0
  53. package/dist/generators/primitive-generator.d.ts.map +1 -0
  54. package/dist/generators/primitive-generator.js +150 -0
  55. package/dist/generators/primitive-generator.js.map +1 -0
  56. package/dist/index.d.ts +17 -0
  57. package/dist/index.d.ts.map +1 -0
  58. package/dist/index.js +42 -0
  59. package/dist/index.js.map +1 -0
  60. package/dist/parsers/base.d.ts +101 -0
  61. package/dist/parsers/base.d.ts.map +1 -0
  62. package/dist/parsers/base.js +77 -0
  63. package/dist/parsers/base.js.map +1 -0
  64. package/dist/parsers/factory.d.ts +64 -0
  65. package/dist/parsers/factory.d.ts.map +1 -0
  66. package/dist/parsers/factory.js +116 -0
  67. package/dist/parsers/factory.js.map +1 -0
  68. package/dist/parsers/index.d.ts +7 -0
  69. package/dist/parsers/index.d.ts.map +1 -0
  70. package/dist/parsers/index.js +23 -0
  71. package/dist/parsers/index.js.map +1 -0
  72. package/dist/parsers/openapi.d.ts +52 -0
  73. package/dist/parsers/openapi.d.ts.map +1 -0
  74. package/dist/parsers/openapi.js +396 -0
  75. package/dist/parsers/openapi.js.map +1 -0
  76. package/dist/plugins/branded-types.d.ts +28 -0
  77. package/dist/plugins/branded-types.d.ts.map +1 -0
  78. package/dist/plugins/branded-types.js +568 -0
  79. package/dist/plugins/branded-types.js.map +1 -0
  80. package/dist/plugins/builtin.d.ts +38 -0
  81. package/dist/plugins/builtin.d.ts.map +1 -0
  82. package/dist/plugins/builtin.js +283 -0
  83. package/dist/plugins/builtin.js.map +1 -0
  84. package/dist/plugins/index.d.ts +7 -0
  85. package/dist/plugins/index.d.ts.map +1 -0
  86. package/dist/plugins/index.js +23 -0
  87. package/dist/plugins/index.js.map +1 -0
  88. package/dist/plugins/loader.d.ts +92 -0
  89. package/dist/plugins/loader.d.ts.map +1 -0
  90. package/dist/plugins/loader.js +245 -0
  91. package/dist/plugins/loader.js.map +1 -0
  92. package/dist/plugins/manager.d.ts +99 -0
  93. package/dist/plugins/manager.d.ts.map +1 -0
  94. package/dist/plugins/manager.js +233 -0
  95. package/dist/plugins/manager.js.map +1 -0
  96. package/dist/plugins/performance-monitoring.d.ts +98 -0
  97. package/dist/plugins/performance-monitoring.d.ts.map +1 -0
  98. package/dist/plugins/performance-monitoring.js +596 -0
  99. package/dist/plugins/performance-monitoring.js.map +1 -0
  100. package/dist/plugins/request-deduplication.d.ts +27 -0
  101. package/dist/plugins/request-deduplication.d.ts.map +1 -0
  102. package/dist/plugins/request-deduplication.js +650 -0
  103. package/dist/plugins/request-deduplication.js.map +1 -0
  104. package/dist/plugins/zod-validation.d.ts +63 -0
  105. package/dist/plugins/zod-validation.d.ts.map +1 -0
  106. package/dist/plugins/zod-validation.js +743 -0
  107. package/dist/plugins/zod-validation.js.map +1 -0
  108. package/dist/types/core.d.ts +203 -0
  109. package/dist/types/core.d.ts.map +1 -0
  110. package/dist/types/core.js +24 -0
  111. package/dist/types/core.js.map +1 -0
  112. package/dist/types/index.d.ts +7 -0
  113. package/dist/types/index.d.ts.map +1 -0
  114. package/dist/types/index.js +23 -0
  115. package/dist/types/index.js.map +1 -0
  116. package/dist/types/openapi.d.ts +250 -0
  117. package/dist/types/openapi.d.ts.map +1 -0
  118. package/dist/types/openapi.js +8 -0
  119. package/dist/types/openapi.js.map +1 -0
  120. package/dist/types/schema.d.ts +68 -0
  121. package/dist/types/schema.d.ts.map +1 -0
  122. package/dist/types/schema.js +22 -0
  123. package/dist/types/schema.js.map +1 -0
  124. package/docs/ADVANCED_PLUGINS_IMPLEMENTATION.md +355 -0
  125. package/docs/ADVANCED_PLUGIN_DEVELOPMENT.md +309 -0
  126. package/docs/API.md +600 -0
  127. package/docs/CONFIGURATION.md +722 -0
  128. package/docs/FASTAPI_TUTORIAL.md +1497 -0
  129. package/docs/PLUGINS.md +683 -0
  130. package/docs/PLUGIN_DEVELOPMENT.md +720 -0
  131. package/package.json +90 -0
@@ -0,0 +1,743 @@
1
+ "use strict";
2
+ /**
3
+ * Advanced Zod Validation Plugin
4
+ *
5
+ * Generates Zod schemas from OpenAPI specifications for runtime validation.
6
+ * Implements sophisticated type-level validation mapping with performance optimizations.
7
+ *
8
+ * Key Features:
9
+ * - Type-safe request/response validation pipelines
10
+ * - Performance-optimized validation caching
11
+ * - Branded type integration for compile-time safety
12
+ * - Runtime type guard generation
13
+ *
14
+ * Architecture:
15
+ * - Schema transformation with memoization
16
+ * - Lazy evaluation for expensive operations
17
+ * - Memory-efficient validation cache management
18
+ */
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ exports.zodValidationPlugin = void 0;
21
+ exports.memoizedValidation = memoizedValidation;
22
+ exports.getZodValidationPerformanceStats = getZodValidationPerformanceStats;
23
+ exports.clearZodValidationCaches = clearZodValidationCaches;
24
+ exports.getValidationCacheStats = getValidationCacheStats;
25
+ const schema_1 = require("../types/schema");
26
+ /**
27
+ * Schema cache for performance optimization
28
+ */
29
+ const schemaCache = new Map();
30
+ /**
31
+ * Memoized schema transformation for performance
32
+ */
33
+ const memoizedSchemaTransform = new Map();
34
+ /**
35
+ * Performance metric recording
36
+ */
37
+ const performanceMetrics = new Map();
38
+ function recordPerformanceMetric(operation, duration) {
39
+ if (!performanceMetrics.has(operation)) {
40
+ performanceMetrics.set(operation, []);
41
+ }
42
+ performanceMetrics.get(operation).push(duration);
43
+ // Keep only last 100 measurements
44
+ const measurements = performanceMetrics.get(operation);
45
+ if (measurements.length > 100) {
46
+ measurements.splice(0, measurements.length - 100);
47
+ }
48
+ }
49
+ /**
50
+ * Advanced Zod Validation Plugin Implementation
51
+ */
52
+ exports.zodValidationPlugin = {
53
+ name: "zod-validation",
54
+ version: "2.0.0",
55
+ description: "Advanced Zod schema generation with performance optimizations and type safety enhancements",
56
+ /**
57
+ * Transform schema to include Zod validation metadata
58
+ */
59
+ transformSchema: (schema, context) => {
60
+ const startTime = performance.now();
61
+ try {
62
+ const options = getPluginOptions(context);
63
+ const schemaKey = generateSchemaKey(schema);
64
+ // Use memoized transformation for performance
65
+ if (options.cacheSchemas && memoizedSchemaTransform.has(schemaKey)) {
66
+ return memoizedSchemaTransform.get(schemaKey);
67
+ }
68
+ const transformedSchema = transformSchemaForZod(schema, options);
69
+ if (options.cacheSchemas) {
70
+ memoizedSchemaTransform.set(schemaKey, transformedSchema);
71
+ }
72
+ return transformedSchema;
73
+ }
74
+ catch (error) {
75
+ console.warn(`Zod validation plugin transformSchema failed:`, error);
76
+ return schema;
77
+ }
78
+ finally {
79
+ const endTime = performance.now();
80
+ recordPerformanceMetric("transformSchema", endTime - startTime);
81
+ }
82
+ },
83
+ /**
84
+ * Enhance type generation with Zod schemas
85
+ */
86
+ afterTypeGeneration: async (typeName, generatedType, context) => {
87
+ const startTime = performance.now();
88
+ try {
89
+ const options = getPluginOptions(context);
90
+ // Build schema using core builder that handles unions/objects/primitives
91
+ const srcSchema = generatedType.sourceSchema;
92
+ const zodSchema = await generateZodSchema(typeName, srcSchema, options, context);
93
+ // Generate branded type if enabled
94
+ const brandedType = options.generateBrandedTypes
95
+ ? generateBrandedType(typeName, generatedType)
96
+ : "";
97
+ // Generate type guard if enabled
98
+ const typeGuard = options.generateTypeGuards
99
+ ? generateTypeGuard(typeName, zodSchema)
100
+ : "";
101
+ // Add Zod imports and schemas
102
+ const zodImports = generateZodImports(options);
103
+ const validationModule = generateValidationModule(typeName, zodSchema, brandedType, typeGuard, options);
104
+ // Update generated type content
105
+ generatedType.content = [
106
+ zodImports,
107
+ generatedType.content,
108
+ validationModule,
109
+ ]
110
+ .filter(Boolean)
111
+ .join("\n\n");
112
+ // Update dependencies
113
+ generatedType.dependencies.push("zod");
114
+ // Add branded type exports if enabled
115
+ if (options.generateBrandedTypes) {
116
+ generatedType.exports.push(`Branded${typeName}`);
117
+ }
118
+ // Add validation exports
119
+ generatedType.exports.push(`${typeName}Schema`, `validate${typeName}`, `parse${typeName}`);
120
+ if (options.generateTypeGuards) {
121
+ generatedType.exports.push(`is${typeName}`);
122
+ }
123
+ }
124
+ catch (error) {
125
+ console.warn(`Zod validation plugin afterTypeGeneration failed for ${typeName}:`, error);
126
+ }
127
+ finally {
128
+ const endTime = performance.now();
129
+ recordPerformanceMetric("afterTypeGeneration", endTime - startTime);
130
+ }
131
+ },
132
+ /**
133
+ * Enhance API client with validation integration
134
+ */
135
+ afterClientGeneration: async (generatedClient, context) => {
136
+ const startTime = performance.now();
137
+ try {
138
+ const options = getPluginOptions(context);
139
+ // Add validation middleware to client
140
+ const validationMiddleware = generateValidationMiddleware(generatedClient, context, options);
141
+ // Add request/response validation helpers
142
+ const validationHelpers = generateValidationHelpers(options);
143
+ // Update client content with validation integration
144
+ generatedClient.content = [
145
+ generatedClient.content,
146
+ validationMiddleware,
147
+ validationHelpers,
148
+ ]
149
+ .filter(Boolean)
150
+ .join("\n\n");
151
+ // Update dependencies
152
+ if (!generatedClient.dependencies.includes("zod")) {
153
+ generatedClient.dependencies.push("zod");
154
+ }
155
+ // Add validation exports
156
+ generatedClient.exports.push("validateRequest", "validateResponse", "ValidationError");
157
+ }
158
+ catch (error) {
159
+ console.warn(`Zod validation plugin afterClientGeneration failed:`, error);
160
+ }
161
+ finally {
162
+ const endTime = performance.now();
163
+ recordPerformanceMetric("afterClientGeneration", endTime - startTime);
164
+ }
165
+ },
166
+ };
167
+ /**
168
+ * Get plugin options from generation context
169
+ */
170
+ function getPluginOptions(context) {
171
+ const pluginConfig = context.config.plugins?.find((p) => p.name === "zod-validation");
172
+ return {
173
+ strictMode: true,
174
+ cacheSchemas: true,
175
+ generateBrandedTypes: true,
176
+ generateTypeGuards: true,
177
+ optimizeBundle: true,
178
+ customErrorMessages: {},
179
+ ...(pluginConfig?.options || {}),
180
+ };
181
+ }
182
+ /**
183
+ * Generate a unique key for schema caching
184
+ */
185
+ function generateSchemaKey(schema) {
186
+ return JSON.stringify(schema);
187
+ }
188
+ /**
189
+ * Transform schema to include Zod validation metadata
190
+ */
191
+ function transformSchemaForZod(schema, options) {
192
+ if (!(0, schema_1.isOpenAPISchemaObject)(schema)) {
193
+ return schema;
194
+ }
195
+ const transformedSchema = { ...schema };
196
+ // Add Zod validation metadata
197
+ transformedSchema._zodValidation = {
198
+ strictMode: options.strictMode,
199
+ customMessages: options.customErrorMessages,
200
+ generated: true,
201
+ };
202
+ // Process properties recursively
203
+ if (schema.properties) {
204
+ transformedSchema.properties = {};
205
+ for (const [propName, propSchema] of Object.entries(schema.properties)) {
206
+ if (typeof propSchema === "object" && propSchema !== null) {
207
+ transformedSchema.properties[propName] = transformSchemaForZod(propSchema, options);
208
+ }
209
+ else {
210
+ transformedSchema.properties[propName] = propSchema;
211
+ }
212
+ }
213
+ }
214
+ return transformedSchema;
215
+ }
216
+ /**
217
+ * Generate Zod schema for a type
218
+ */
219
+ async function generateZodSchema(typeName, schema, options, context) {
220
+ const cacheKey = `${typeName}-${generateSchemaKey(schema)}`;
221
+ if (options.cacheSchemas && schemaCache.has(cacheKey)) {
222
+ return schemaCache.get(cacheKey);
223
+ }
224
+ const zodSchema = buildZodSchema(schema, options, 0, context);
225
+ if (options.cacheSchemas) {
226
+ schemaCache.set(cacheKey, zodSchema);
227
+ }
228
+ return zodSchema;
229
+ }
230
+ /**
231
+ * Build Zod schema from OpenAPI schema
232
+ */
233
+ function buildZodSchema(schema, options, depth = 0, context) {
234
+ // Handle oneOf/discriminated unions early
235
+ if ((0, schema_1.isOpenAPISchemaObject)(schema)) {
236
+ const obj = schema;
237
+ if (Array.isArray(obj.oneOf) && obj.oneOf.length > 0) {
238
+ return buildOneOfSchema(obj, options, context);
239
+ }
240
+ }
241
+ // Handle schema references first
242
+ if (typeof schema === "object" &&
243
+ schema !== null &&
244
+ "$ref" in schema &&
245
+ schema.$ref) {
246
+ // Extract type name from reference and generate schema reference
247
+ const refPath = schema.$ref;
248
+ const typeName = refPath.split("/").pop();
249
+ // Try to resolve and inline if it's a union (oneOf)
250
+ if (context?.schemaResolver) {
251
+ const resolved = context.schemaResolver(refPath);
252
+ if (resolved && (0, schema_1.isOpenAPISchemaObject)(resolved)) {
253
+ const obj = resolved;
254
+ if (Array.isArray(obj.oneOf) && obj.oneOf.length > 0) {
255
+ return buildOneOfSchema(obj, options, context);
256
+ }
257
+ }
258
+ }
259
+ if (typeName) {
260
+ const formattedTypeName = formatTypeName(typeName);
261
+ return `${formattedTypeName}Schema`;
262
+ }
263
+ }
264
+ if (!(0, schema_1.isOpenAPISchemaObject)(schema)) {
265
+ return "z.unknown()";
266
+ }
267
+ // Prevent infinite recursion
268
+ if (depth > 10) {
269
+ return "z.unknown()";
270
+ }
271
+ switch (schema.type) {
272
+ case "string":
273
+ return buildStringSchema(schema, options);
274
+ case "number":
275
+ case "integer":
276
+ return buildNumberSchema(schema, options);
277
+ case "boolean":
278
+ return "z.boolean()";
279
+ case "array": {
280
+ const itemSchema = schema.items
281
+ ? buildZodSchema(schema.items, options, depth + 1, context)
282
+ : "z.unknown()";
283
+ return `z.array(${itemSchema})`;
284
+ }
285
+ case "object":
286
+ return buildObjectSchema(schema, options, depth, context);
287
+ default:
288
+ return "z.unknown()";
289
+ }
290
+ }
291
+ /**
292
+ * Helper function to format type names consistently
293
+ */
294
+ function formatTypeName(name) {
295
+ // Convert to PascalCase and add API prefix if not present.
296
+ // Preserve internal capitalization (e.g., UserRole -> UserRole).
297
+ const tokens = name.split(/[-_\s]+/).filter(Boolean);
298
+ const pascalCase = tokens
299
+ .map((word) => (word ? word.charAt(0).toUpperCase() + word.slice(1) : ""))
300
+ .join("");
301
+ return pascalCase.startsWith("API") ? pascalCase : `API${pascalCase}`;
302
+ }
303
+ /**
304
+ * Build Zod string schema with validation rules
305
+ */
306
+ function buildStringSchema(schema, _options) {
307
+ let zodSchema = "z.string()";
308
+ if (schema.minLength !== undefined) {
309
+ zodSchema += `.min(${schema.minLength})`;
310
+ }
311
+ if (schema.maxLength !== undefined) {
312
+ zodSchema += `.max(${schema.maxLength})`;
313
+ }
314
+ if (schema.pattern) {
315
+ zodSchema += `.regex(/${schema.pattern}/)`;
316
+ }
317
+ if (schema.format) {
318
+ switch (schema.format) {
319
+ case "email":
320
+ zodSchema += ".email()";
321
+ break;
322
+ case "uri":
323
+ case "url":
324
+ zodSchema += ".url()";
325
+ break;
326
+ case "uuid":
327
+ zodSchema += ".uuid()";
328
+ break;
329
+ case "date-time":
330
+ zodSchema += ".datetime()";
331
+ break;
332
+ }
333
+ }
334
+ if (schema.enum && Array.isArray(schema.enum)) {
335
+ if (schema.enum.length === 1) {
336
+ zodSchema = `z.literal(${JSON.stringify(schema.enum[0])})`;
337
+ }
338
+ else {
339
+ const enumValues = schema.enum
340
+ .map((val) => JSON.stringify(val))
341
+ .join(", ");
342
+ zodSchema = `z.enum([${enumValues}])`;
343
+ }
344
+ }
345
+ // Add custom error messages if configured
346
+ if (_options.customErrorMessages && schema.description) {
347
+ const customMessage = _options.customErrorMessages[schema.description];
348
+ if (customMessage) {
349
+ zodSchema += `.describe("${customMessage}")`;
350
+ }
351
+ }
352
+ return zodSchema;
353
+ }
354
+ /**
355
+ * Build Zod number schema with validation rules
356
+ */
357
+ function buildNumberSchema(schema, _options) {
358
+ let zodSchema = schema.type === "integer" ? "z.number().int()" : "z.number()";
359
+ if (schema.minimum !== undefined) {
360
+ zodSchema += `.min(${schema.minimum})`;
361
+ }
362
+ if (schema.maximum !== undefined) {
363
+ zodSchema += `.max(${schema.maximum})`;
364
+ }
365
+ if (schema.multipleOf !== undefined) {
366
+ zodSchema += `.multipleOf(${schema.multipleOf})`;
367
+ }
368
+ return zodSchema;
369
+ }
370
+ /**
371
+ * Build Zod object schema
372
+ */
373
+ function buildObjectSchema(schema, options, depth, context) {
374
+ if (!schema.properties) {
375
+ return "z.object({})";
376
+ }
377
+ const properties = [];
378
+ const required = schema.required || [];
379
+ const transformPairs = [];
380
+ const wantsCamel = context?.config?.namingConvention === "camelCase";
381
+ // Helper: convert prop name to camelCase similar to generator
382
+ const toCamel = (str) => {
383
+ if (!str)
384
+ return str;
385
+ // sanitize: collapse non-alnum into underscore, trim
386
+ const sanitized = str
387
+ .replace(/[^A-Za-z0-9]+/g, "_")
388
+ .replace(/^_+|_+$/g, "")
389
+ .replace(/_+/g, "_");
390
+ const parts = sanitized.split(/_+/).filter(Boolean);
391
+ if (parts.length === 0)
392
+ return "";
393
+ const head = parts[0] ?? "";
394
+ const tail = parts.slice(1);
395
+ const camelHead = head ? head.charAt(0).toLowerCase() + head.slice(1) : "";
396
+ const camelTail = tail.map((p) => p ? p.charAt(0).toUpperCase() + p.slice(1) : "");
397
+ return camelHead + camelTail.join("");
398
+ };
399
+ for (const [propName, propSchema] of Object.entries(schema.properties)) {
400
+ if (typeof propSchema === "object" && propSchema !== null) {
401
+ let propZodSchema = buildZodSchema(propSchema, options, depth + 1, context);
402
+ if (!required.includes(propName)) {
403
+ propZodSchema += ".optional()";
404
+ }
405
+ properties.push(` ${propName}: ${propZodSchema}`);
406
+ if (wantsCamel) {
407
+ const camel = toCamel(propName);
408
+ if (camel !== propName) {
409
+ transformPairs.push(` ${camel}: val[${JSON.stringify(propName)}]`);
410
+ }
411
+ }
412
+ }
413
+ }
414
+ const strictMode = options.strictMode ? ".strict()" : "";
415
+ const base = `z.object({\n${properties.join(",\n")}\n})${strictMode}`;
416
+ if (wantsCamel && transformPairs.length > 0) {
417
+ return `${base}.transform((val) => ({\n${transformPairs.join(",\n")}\n}))`;
418
+ }
419
+ return base;
420
+ }
421
+ /**
422
+ * Build Zod union/discriminatedUnion schema for oneOf
423
+ */
424
+ function buildOneOfSchema(schema, options, context) {
425
+ const variants = (schema.oneOf || []).map((variant) => {
426
+ if (typeof variant === "object" &&
427
+ variant !== null &&
428
+ "$ref" in variant) {
429
+ const refPath = variant["$ref"];
430
+ const name = refPath.split("/").pop() || "Unknown";
431
+ return `${formatTypeName(name)}Schema`;
432
+ }
433
+ return buildZodSchema(variant, options, 0, context);
434
+ });
435
+ const discriminator = schema.discriminator?.propertyName;
436
+ if (discriminator) {
437
+ return `z.discriminatedUnion(${JSON.stringify(discriminator)}, [${variants.join(", ")}])`;
438
+ }
439
+ return `z.union([${variants.join(", ")}])`;
440
+ }
441
+ /**
442
+ * Generate branded type for compile-time safety
443
+ */
444
+ function generateBrandedType(typeName, _generatedType) {
445
+ return `
446
+ /**
447
+ * Branded type for ${typeName} with compile-time guarantees
448
+ */
449
+ export type Branded${typeName} = ${typeName} & { __brand: '${typeName}' };
450
+
451
+ /**
452
+ * Create a branded ${typeName} instance
453
+ */
454
+ export function createBranded${typeName}(data: ${typeName}): Branded${typeName} {
455
+ return data as Branded${typeName};
456
+ }`;
457
+ }
458
+ /**
459
+ * Generate runtime type guard
460
+ */
461
+ function generateTypeGuard(typeName, _zodSchema) {
462
+ return `
463
+ /**
464
+ * Runtime type guard for ${typeName}
465
+ */
466
+ export function is${typeName}(value: unknown): value is ${typeName} {
467
+ return ${typeName}Schema.safeParse(value).success;
468
+ }`;
469
+ }
470
+ /**
471
+ * Generate Zod imports based on options
472
+ */
473
+ function generateZodImports(options) {
474
+ const imports = ["z"];
475
+ if (options.generateBrandedTypes) {
476
+ imports.push("ZodType");
477
+ }
478
+ return `import { ${imports.join(", ")} } from 'zod';`;
479
+ }
480
+ /**
481
+ * Generate validation module for a type
482
+ */
483
+ function generateValidationModule(typeName, zodSchema, brandedType, typeGuard, _options) {
484
+ return `
485
+ /**
486
+ * Zod validation schema for ${typeName}
487
+ */
488
+ export const ${typeName}Schema = ${zodSchema};
489
+
490
+ /**
491
+ * Validate ${typeName} data with detailed error reporting
492
+ */
493
+ export function validate${typeName}(data: unknown): { success: true; data: ${typeName} } | { success: false; errors: string[] } {
494
+ const result = ${typeName}Schema.safeParse(data);
495
+
496
+ if (result.success) {
497
+ return { success: true, data: result.data };
498
+ }
499
+
500
+ return {
501
+ success: false,
502
+ errors: result.error.errors.map(err => \`\${err.path.join('.')}: \${err.message}\`)
503
+ };
504
+ }
505
+
506
+ /**
507
+ * Parse ${typeName} data with exception on validation failure
508
+ */
509
+ export function parse${typeName}(data: unknown): ${typeName} {
510
+ return ${typeName}Schema.parse(data);
511
+ }${brandedType}${typeGuard}`;
512
+ }
513
+ /**
514
+ * Generate validation middleware for API client
515
+ */
516
+ function generateValidationMiddleware(_generatedClient, _context, options) {
517
+ // Ensure z/ZodType import is present in client content
518
+ if (!_generatedClient.content.includes("from 'zod'")) {
519
+ _generatedClient.content =
520
+ `import { z, ZodType } from 'zod';\n` + _generatedClient.content;
521
+ }
522
+ else if (!_generatedClient.content.includes("ZodType")) {
523
+ // Append ZodType to existing import if only z is imported
524
+ _generatedClient.content = _generatedClient.content.replace(/import\s*\{([^}]*)\}\s*from\s*['"]zod['"];?/, (_m, p1) => {
525
+ const names = p1
526
+ .split(",")
527
+ .map((s) => s.trim())
528
+ .filter(Boolean);
529
+ if (!names.includes("ZodType"))
530
+ names.push("ZodType");
531
+ return `import { ${names.join(", ")} } from 'zod';`;
532
+ });
533
+ }
534
+ const strictModeCode = options.strictMode
535
+ ? 'throw new ValidationError(result.error.errors.map(err => `${err.path.join(".")}: ${err.message}`), data);'
536
+ : "// In non-strict mode, return data as-is";
537
+ return `
538
+ /**
539
+ * Validation middleware for API requests and responses
540
+ */
541
+ export class ValidationError extends Error {
542
+ constructor(public errors: string[], public data: unknown) {
543
+ super(\`Validation failed: \${errors.join(', ')}\`);
544
+ this.name = 'ValidationError';
545
+ }
546
+ }
547
+
548
+ /**
549
+ * Validate request data before sending
550
+ */
551
+ export function validateRequest<T>(data: unknown, schema: ZodType<T>): T {
552
+ const result = schema.safeParse(data);
553
+
554
+ if (!result.success) {
555
+ throw new ValidationError(
556
+ result.error.errors.map(err => \`\${err.path.join('.')}: \${err.message}\`),
557
+ data
558
+ );
559
+ }
560
+
561
+ return result.data;
562
+ }
563
+
564
+ /**
565
+ * Validate response data after receiving
566
+ */
567
+ export function validateResponse<T>(data: unknown, schema: ZodType<T>): T {
568
+ const result = schema.safeParse(data);
569
+
570
+ if (!result.success) {
571
+ console.warn('Response validation failed:', result.error.errors);
572
+ ${strictModeCode}
573
+ }
574
+
575
+ return result.data;
576
+ }`;
577
+ }
578
+ /**
579
+ * Generate validation helper functions
580
+ */
581
+ function generateValidationHelpers(_options) {
582
+ return `
583
+ /**
584
+ * Utility functions for validation operations
585
+ */
586
+
587
+ /**
588
+ * Create a validation pipeline for multiple schemas
589
+ */
590
+ export function createValidationPipeline<T>(...schemas: ZodType<unknown>[]): ZodType<T> {
591
+ return schemas.reduce((acc, schema) => acc.pipe(schema)) as ZodType<T>;
592
+ }
593
+
594
+ /**
595
+ * Lazy validation for performance optimization
596
+ */
597
+ export function createLazyValidator<T>(schemaFactory: () => ZodType<T>) {
598
+ let schema: ZodType<T> | null = null;
599
+
600
+ return (data: unknown): T => {
601
+ if (!schema) {
602
+ schema = schemaFactory();
603
+ }
604
+ return schema.parse(data);
605
+ };
606
+ }`;
607
+ }
608
+ /**
609
+ * Memory-bounded validation cache with LRU eviction
610
+ */
611
+ class BoundedValidationCache {
612
+ constructor(maxSize = 1000, ttl = 5 * 60 * 1000) {
613
+ this.cache = new Map();
614
+ this.accessOrder = [];
615
+ this.maxSize = maxSize;
616
+ this.ttl = ttl;
617
+ }
618
+ get(key) {
619
+ const entry = this.cache.get(key);
620
+ if (!entry)
621
+ return undefined;
622
+ const now = Date.now();
623
+ if (now - entry.timestamp > this.ttl) {
624
+ this.cache.delete(key);
625
+ this.removeFromAccessOrder(key);
626
+ return undefined;
627
+ }
628
+ // Update access time and move to end (most recently used)
629
+ entry.accessTime = now;
630
+ this.moveToEnd(key);
631
+ return entry;
632
+ }
633
+ set(key, value) {
634
+ const now = Date.now();
635
+ if (this.cache.has(key)) {
636
+ // Update existing entry
637
+ this.cache.set(key, { ...value, accessTime: now });
638
+ this.moveToEnd(key);
639
+ }
640
+ else {
641
+ // Add new entry
642
+ if (this.cache.size >= this.maxSize) {
643
+ this.evictLRU();
644
+ }
645
+ this.cache.set(key, { ...value, accessTime: now });
646
+ this.accessOrder.push(key);
647
+ }
648
+ }
649
+ evictLRU() {
650
+ if (this.accessOrder.length === 0)
651
+ return;
652
+ const lruKey = this.accessOrder.shift();
653
+ this.cache.delete(lruKey);
654
+ }
655
+ moveToEnd(key) {
656
+ this.removeFromAccessOrder(key);
657
+ this.accessOrder.push(key);
658
+ }
659
+ removeFromAccessOrder(key) {
660
+ const index = this.accessOrder.indexOf(key);
661
+ if (index > -1) {
662
+ this.accessOrder.splice(index, 1);
663
+ }
664
+ }
665
+ clear() {
666
+ this.cache.clear();
667
+ this.accessOrder = [];
668
+ }
669
+ size() {
670
+ return this.cache.size;
671
+ }
672
+ cleanup() {
673
+ const now = Date.now();
674
+ const expiredKeys = [];
675
+ for (const [key, entry] of this.cache) {
676
+ if (now - entry.timestamp > this.ttl) {
677
+ expiredKeys.push(key);
678
+ }
679
+ }
680
+ for (const key of expiredKeys) {
681
+ this.cache.delete(key);
682
+ this.removeFromAccessOrder(key);
683
+ }
684
+ }
685
+ }
686
+ const validationCache = new BoundedValidationCache();
687
+ function memoizedValidation(data, schema, cacheKey, schemaVersion = "1.0") {
688
+ if (!cacheKey) {
689
+ return schema.parse(data);
690
+ }
691
+ const cached = validationCache.get(cacheKey);
692
+ if (cached && cached.schemaVersion === schemaVersion) {
693
+ return cached.result;
694
+ }
695
+ const result = schema.parse(data);
696
+ validationCache.set(cacheKey, {
697
+ result,
698
+ timestamp: Date.now(),
699
+ schemaVersion,
700
+ });
701
+ return result;
702
+ }
703
+ /**
704
+ * Get performance statistics for the plugin
705
+ */
706
+ function getZodValidationPerformanceStats() {
707
+ const stats = {};
708
+ for (const [operation, measurements] of performanceMetrics) {
709
+ if (measurements.length > 0) {
710
+ stats[operation] = {
711
+ avg: measurements.reduce((sum, val) => sum + val, 0) / measurements.length,
712
+ min: Math.min(...measurements),
713
+ max: Math.max(...measurements),
714
+ count: measurements.length,
715
+ };
716
+ }
717
+ }
718
+ return stats;
719
+ }
720
+ /**
721
+ * Clear performance metrics and caches
722
+ */
723
+ function clearZodValidationCaches() {
724
+ schemaCache.clear();
725
+ memoizedSchemaTransform.clear();
726
+ performanceMetrics.clear();
727
+ validationCache.clear();
728
+ // Optional: Trigger cleanup to remove expired entries
729
+ validationCache.cleanup();
730
+ }
731
+ /**
732
+ * Get validation cache statistics for monitoring
733
+ */
734
+ function getValidationCacheStats() {
735
+ return {
736
+ size: validationCache.size(),
737
+ maxSize: 1000, // TODO: Make configurable
738
+ // Additional metrics could be added with cache hit/miss tracking
739
+ };
740
+ }
741
+ // Export plugin for registration
742
+ exports.default = exports.zodValidationPlugin;
743
+ //# sourceMappingURL=zod-validation.js.map