@geekmidas/schema 0.0.3 → 1.0.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 (47) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/{conversion-Civd6bIU.mjs → conversion-BJGLAqtd.mjs} +2 -3
  3. package/dist/conversion-BJGLAqtd.mjs.map +1 -0
  4. package/dist/{conversion-CrSNoSRa.cjs → conversion-CFlFrSru.cjs} +2 -3
  5. package/dist/conversion-CFlFrSru.cjs.map +1 -0
  6. package/dist/conversion-CH_EmflL.d.cts.map +1 -0
  7. package/dist/conversion-DUyZYTWO.d.mts.map +1 -0
  8. package/dist/conversion.cjs +1 -1
  9. package/dist/conversion.mjs +1 -1
  10. package/dist/index.cjs +1 -1
  11. package/dist/index.d.cts +2 -2
  12. package/dist/index.d.mts +2 -2
  13. package/dist/index.mjs +1 -1
  14. package/dist/{openapi-DR4_PG-e.d.cts → openapi-Aeb_1e9T.d.cts} +3 -1
  15. package/dist/openapi-Aeb_1e9T.d.cts.map +1 -0
  16. package/dist/openapi-DH5yCqKh.mjs.map +1 -1
  17. package/dist/openapi-DVvLYx-8.cjs.map +1 -1
  18. package/dist/{openapi-j01kFjpI.d.mts → openapi-Dxc4FuMP.d.mts} +3 -1
  19. package/dist/openapi-Dxc4FuMP.d.mts.map +1 -0
  20. package/dist/openapi.d.cts +1 -1
  21. package/dist/openapi.d.mts +1 -1
  22. package/dist/parser.cjs.map +1 -1
  23. package/dist/parser.d.cts +3 -1
  24. package/dist/parser.d.cts.map +1 -0
  25. package/dist/parser.d.mts +3 -1
  26. package/dist/parser.d.mts.map +1 -0
  27. package/dist/parser.mjs.map +1 -1
  28. package/dist/{types-ByLHeRGs.d.mts → types-D7ZRea_7.d.cts} +3 -1
  29. package/dist/types-D7ZRea_7.d.cts.map +1 -0
  30. package/dist/{types-DfcgE7cO.d.cts → types-o4dOkvCd.d.mts} +3 -1
  31. package/dist/types-o4dOkvCd.d.mts.map +1 -0
  32. package/dist/types.d.cts +1 -1
  33. package/dist/types.d.mts +1 -1
  34. package/package.json +1 -1
  35. package/src/__benchmarks__/conversion.bench.ts +88 -0
  36. package/src/__tests__/conversion.spec.ts +440 -257
  37. package/src/__tests__/openapi.spec.ts +390 -390
  38. package/src/__tests__/parser.spec.ts +202 -202
  39. package/src/conversion.ts +154 -158
  40. package/src/index.ts +8 -9
  41. package/src/openapi.ts +49 -49
  42. package/src/parser.ts +11 -11
  43. package/src/types.ts +16 -16
  44. package/tsconfig.json +9 -0
  45. package/tsdown.config.ts +1 -1
  46. package/dist/conversion-Civd6bIU.mjs.map +0 -1
  47. package/dist/conversion-CrSNoSRa.cjs.map +0 -1
package/src/conversion.ts CHANGED
@@ -1,199 +1,195 @@
1
1
  import type { StandardSchemaV1 } from '@standard-schema/spec';
2
2
 
3
3
  export enum SchemaVendor {
4
- zod = 'zod',
5
- valibot = 'valibot',
4
+ zod = 'zod',
5
+ valibot = 'valibot',
6
6
  }
7
7
 
8
8
  export type VendorConvertor = (schema: any) => Promise<any>;
9
9
  export type VendorConvertors = Record<SchemaVendor, VendorConvertor>;
10
10
 
11
11
  function isSchemaVendor(vendor?: string): vendor is SchemaVendor {
12
- if (!vendor) {
13
- return false;
14
- }
12
+ if (!vendor) {
13
+ return false;
14
+ }
15
15
 
16
- return Object.values(SchemaVendor).includes(vendor as SchemaVendor);
16
+ return Object.values(SchemaVendor).includes(vendor as SchemaVendor);
17
17
  }
18
18
 
19
19
  export const StandardSchemaJsonSchema: VendorConvertors = {
20
- zod: async (schema): Promise<any> => {
21
- try {
22
- const { z } = await import('zod/v4').catch(() => ({ z: {} }));
23
-
24
- if ('toJSONSchema' in z && typeof z.toJSONSchema === 'function') {
25
- return z.toJSONSchema(schema);
26
- }
27
- const { zodToJsonSchema } = await import('zod-to-json-schema');
28
-
29
- const result = zodToJsonSchema(schema, {
30
- removeAdditionalStrategy: 'strict',
31
- });
32
-
33
- return result;
34
- } catch (error) {
35
- // Fallback to basic conversion if zod-to-json-schema is not available
36
- console.warn(
37
- 'zod-to-json-schema not available, using basic conversion',
38
- error,
39
- );
40
- return { type: 'object' };
41
- }
42
- },
43
- valibot: async (schema): Promise<any> => {
44
- const { toJsonSchema } = await import('@valibot/to-json-schema');
45
- return toJsonSchema(schema as any);
46
- },
20
+ zod: async (schema): Promise<any> => {
21
+ try {
22
+ const { z } = await import('zod/v4').catch(() => ({ z: {} }));
23
+
24
+ if ('toJSONSchema' in z && typeof z.toJSONSchema === 'function') {
25
+ return z.toJSONSchema(schema);
26
+ }
27
+ const { zodToJsonSchema } = await import('zod-to-json-schema');
28
+
29
+ const result = zodToJsonSchema(schema, {
30
+ removeAdditionalStrategy: 'strict',
31
+ });
32
+
33
+ return result;
34
+ } catch {
35
+ // Fallback to basic conversion if zod-to-json-schema is not available
36
+ return { type: 'object' };
37
+ }
38
+ },
39
+ valibot: async (schema): Promise<any> => {
40
+ const { toJsonSchema } = await import('@valibot/to-json-schema');
41
+ return toJsonSchema(schema as any);
42
+ },
47
43
  };
48
44
 
49
45
  function extractAndConvertDefs(
50
- jsonSchema: any,
51
- componentCollector?: {
52
- addSchema(id: string, schema: any): void;
53
- getReference(id: string): { $ref: string };
54
- },
46
+ jsonSchema: any,
47
+ componentCollector?: {
48
+ addSchema(id: string, schema: any): void;
49
+ getReference(id: string): { $ref: string };
50
+ },
55
51
  ): any {
56
- if (!jsonSchema || typeof jsonSchema !== 'object') {
57
- return jsonSchema;
58
- }
59
-
60
- // Process the schema recursively to update references
61
- const processSchema = (schema: any): any => {
62
- if (!schema || typeof schema !== 'object') {
63
- return schema;
64
- }
65
-
66
- // Handle $ref
67
- if (schema.$ref && typeof schema.$ref === 'string') {
68
- // Convert #/$defs/X to #/components/schemas/X
69
- if (schema.$ref.startsWith('#/$defs/')) {
70
- const refName = schema.$ref.replace('#/$defs/', '');
71
- return componentCollector
72
- ? componentCollector.getReference(refName)
73
- : schema;
74
- }
75
- return schema;
76
- }
77
-
78
- // Handle arrays
79
- if (Array.isArray(schema)) {
80
- return schema.map(processSchema);
81
- }
82
-
83
- // Process all properties recursively
84
- const processed: any = {};
85
- for (const [key, value] of Object.entries(schema)) {
86
- if (key === '$defs') {
87
- // Skip $defs as they've been extracted
88
- continue;
89
- }
90
- processed[key] = processSchema(value);
91
- }
92
- return processed;
93
- };
94
-
95
- // Extract $defs if present
96
- if (jsonSchema.$defs && componentCollector) {
97
- for (const [defName, defSchema] of Object.entries(jsonSchema.$defs)) {
98
- // Process the definition recursively to handle nested $refs
99
- const processedDefSchema = processSchema(defSchema);
100
- // Add each definition to the component collector
101
- componentCollector.addSchema(defName, processedDefSchema);
102
- }
103
- }
104
-
105
- // Process the schema and remove $defs
106
- const { $defs, ...schemaWithoutDefs } = jsonSchema;
107
- return processSchema(schemaWithoutDefs);
52
+ if (!jsonSchema || typeof jsonSchema !== 'object') {
53
+ return jsonSchema;
54
+ }
55
+
56
+ // Process the schema recursively to update references
57
+ const processSchema = (schema: any): any => {
58
+ if (!schema || typeof schema !== 'object') {
59
+ return schema;
60
+ }
61
+
62
+ // Handle $ref
63
+ if (schema.$ref && typeof schema.$ref === 'string') {
64
+ // Convert #/$defs/X to #/components/schemas/X
65
+ if (schema.$ref.startsWith('#/$defs/')) {
66
+ const refName = schema.$ref.replace('#/$defs/', '');
67
+ return componentCollector
68
+ ? componentCollector.getReference(refName)
69
+ : schema;
70
+ }
71
+ return schema;
72
+ }
73
+
74
+ // Handle arrays
75
+ if (Array.isArray(schema)) {
76
+ return schema.map(processSchema);
77
+ }
78
+
79
+ // Process all properties recursively
80
+ const processed: any = {};
81
+ for (const [key, value] of Object.entries(schema)) {
82
+ if (key === '$defs') {
83
+ // Skip $defs as they've been extracted
84
+ continue;
85
+ }
86
+ processed[key] = processSchema(value);
87
+ }
88
+ return processed;
89
+ };
90
+
91
+ // Extract $defs if present
92
+ if (jsonSchema.$defs && componentCollector) {
93
+ for (const [defName, defSchema] of Object.entries(jsonSchema.$defs)) {
94
+ // Process the definition recursively to handle nested $refs
95
+ const processedDefSchema = processSchema(defSchema);
96
+ // Add each definition to the component collector
97
+ componentCollector.addSchema(defName, processedDefSchema);
98
+ }
99
+ }
100
+
101
+ // Process the schema and remove $defs
102
+ const { $defs, ...schemaWithoutDefs } = jsonSchema;
103
+ return processSchema(schemaWithoutDefs);
108
104
  }
109
105
 
110
106
  export async function convertStandardSchemaToJsonSchema(
111
- schema?: StandardSchemaV1,
112
- componentCollector?: {
113
- addSchema(id: string, schema: any): void;
114
- getReference(id: string): { $ref: string };
115
- },
107
+ schema?: StandardSchemaV1,
108
+ componentCollector?: {
109
+ addSchema(id: string, schema: any): void;
110
+ getReference(id: string): { $ref: string };
111
+ },
116
112
  ): Promise<any> {
117
- if (!schema) {
118
- return undefined;
119
- }
120
-
121
- const vendor = schema['~standard']?.vendor;
122
- if (!isSchemaVendor(vendor)) {
123
- throw new Error(
124
- `Unsupported or missing vendor "${vendor}" for Standard Schema. Supported vendors are: ${Object.keys(StandardSchemaJsonSchema).join(', ')}`,
125
- );
126
- }
127
-
128
- const toJSONSchema = StandardSchemaJsonSchema[vendor];
129
- const jsonSchema = await toJSONSchema(schema);
130
-
131
- // Extract and convert $defs to components
132
- return extractAndConvertDefs(jsonSchema, componentCollector);
113
+ if (!schema) {
114
+ return undefined;
115
+ }
116
+
117
+ const vendor = schema['~standard']?.vendor;
118
+ if (!isSchemaVendor(vendor)) {
119
+ throw new Error(
120
+ `Unsupported or missing vendor "${vendor}" for Standard Schema. Supported vendors are: ${Object.keys(StandardSchemaJsonSchema).join(', ')}`,
121
+ );
122
+ }
123
+
124
+ const toJSONSchema = StandardSchemaJsonSchema[vendor];
125
+ const jsonSchema = await toJSONSchema(schema);
126
+
127
+ // Extract and convert $defs to components
128
+ return extractAndConvertDefs(jsonSchema, componentCollector);
133
129
  }
134
130
 
135
131
  export async function getZodMetadata(
136
- schema: StandardSchemaV1,
132
+ schema: StandardSchemaV1,
137
133
  ): Promise<SchemaMeta | undefined> {
138
- const { ZodObject } = await import('zod/v4');
134
+ const { ZodObject } = await import('zod/v4');
139
135
 
140
- if (schema instanceof ZodObject) {
141
- return schema.meta();
142
- }
136
+ if (schema instanceof ZodObject) {
137
+ return schema.meta();
138
+ }
143
139
 
144
- return undefined;
140
+ return undefined;
145
141
  }
146
142
 
147
143
  export async function getSchemaMetadata(
148
- schema: StandardSchemaV1,
144
+ schema: StandardSchemaV1,
149
145
  ): Promise<SchemaMeta | undefined> {
150
- const vendor = schema['~standard']?.vendor;
146
+ const vendor = schema['~standard']?.vendor;
151
147
 
152
- if (vendor === 'zod') {
153
- return getZodMetadata(schema);
154
- }
148
+ if (vendor === 'zod') {
149
+ return getZodMetadata(schema);
150
+ }
155
151
 
156
- return undefined;
152
+ return undefined;
157
153
  }
158
154
 
159
155
  interface SchemaMeta {
160
- id?: string;
156
+ id?: string;
161
157
  }
162
158
 
163
159
  export async function convertSchemaWithComponents(
164
- schema: StandardSchemaV1 | undefined,
165
- componentCollector?: {
166
- addSchema(id: string, schema: any): void;
167
- getReference(id: string): { $ref: string };
168
- },
160
+ schema: StandardSchemaV1 | undefined,
161
+ componentCollector?: {
162
+ addSchema(id: string, schema: any): void;
163
+ getReference(id: string): { $ref: string };
164
+ },
169
165
  ): Promise<any> {
170
- if (!schema) {
171
- return undefined;
172
- }
173
-
174
- // Convert to JSON Schema with component collector to handle $defs
175
- const jsonSchema = await convertStandardSchemaToJsonSchema(
176
- schema,
177
- componentCollector,
178
- );
179
-
180
- if (!componentCollector) {
181
- return jsonSchema;
182
- }
183
-
184
- // Check if this schema has metadata with an ID
185
- const metadata = await getSchemaMetadata(schema);
186
-
187
- // Also check if the JSON Schema itself has an id field (from Zod's meta)
188
- const schemaId = metadata?.id || jsonSchema?.id;
189
-
190
- if (schemaId) {
191
- // Remove the id from the schema before adding to components
192
- const { id, ...schemaWithoutId } = jsonSchema;
193
- // Add this schema to components and return a reference
194
- componentCollector.addSchema(schemaId, schemaWithoutId);
195
- return componentCollector.getReference(schemaId);
196
- }
197
-
198
- return jsonSchema;
166
+ if (!schema) {
167
+ return undefined;
168
+ }
169
+
170
+ // Convert to JSON Schema with component collector to handle $defs
171
+ const jsonSchema = await convertStandardSchemaToJsonSchema(
172
+ schema,
173
+ componentCollector,
174
+ );
175
+
176
+ if (!componentCollector) {
177
+ return jsonSchema;
178
+ }
179
+
180
+ // Check if this schema has metadata with an ID
181
+ const metadata = await getSchemaMetadata(schema);
182
+
183
+ // Also check if the JSON Schema itself has an id field (from Zod's meta)
184
+ const schemaId = metadata?.id || jsonSchema?.id;
185
+
186
+ if (schemaId) {
187
+ // Remove the id from the schema before adding to components
188
+ const { id, ...schemaWithoutId } = jsonSchema;
189
+ // Add this schema to components and return a reference
190
+ componentCollector.addSchema(schemaId, schemaWithoutId);
191
+ return componentCollector.getReference(schemaId);
192
+ }
193
+
194
+ return jsonSchema;
199
195
  }
package/src/index.ts CHANGED
@@ -1,15 +1,14 @@
1
- export type {
2
- InferStandardSchema,
3
- ComposableStandardSchema,
4
- InferComposableStandardSchema,
5
- } from './types';
6
-
7
1
  // Re-export conversion utilities for convenience
8
2
  export {
9
- convertStandardSchemaToJsonSchema,
10
- convertSchemaWithComponents,
3
+ convertSchemaWithComponents,
4
+ convertStandardSchemaToJsonSchema,
11
5
  } from './conversion';
6
+ export type { ComponentCollector, OpenApiSchemaOptions } from './openapi';
12
7
 
13
8
  // Re-export OpenAPI utilities for convenience
14
9
  export { buildOpenApiSchema, createComponentCollector } from './openapi';
15
- export type { OpenApiSchemaOptions, ComponentCollector } from './openapi';
10
+ export type {
11
+ ComposableStandardSchema,
12
+ InferComposableStandardSchema,
13
+ InferStandardSchema,
14
+ } from './types';
package/src/openapi.ts CHANGED
@@ -1,29 +1,29 @@
1
1
  import type { OpenAPIV3_1 } from 'openapi-types';
2
2
 
3
3
  export interface OpenApiSchemaOptions {
4
- title?: string;
5
- version?: string;
6
- description?: string;
4
+ title?: string;
5
+ version?: string;
6
+ description?: string;
7
7
  }
8
8
 
9
9
  export interface ComponentCollector {
10
- schemas: Record<string, OpenAPIV3_1.SchemaObject>;
11
- addSchema(id: string, schema: OpenAPIV3_1.SchemaObject): void;
12
- getReference(id: string): OpenAPIV3_1.ReferenceObject;
10
+ schemas: Record<string, OpenAPIV3_1.SchemaObject>;
11
+ addSchema(id: string, schema: OpenAPIV3_1.SchemaObject): void;
12
+ getReference(id: string): OpenAPIV3_1.ReferenceObject;
13
13
  }
14
14
 
15
15
  export function createComponentCollector(): ComponentCollector {
16
- const schemas: Record<string, OpenAPIV3_1.SchemaObject> = {};
16
+ const schemas: Record<string, OpenAPIV3_1.SchemaObject> = {};
17
17
 
18
- return {
19
- schemas,
20
- addSchema(id: string, schema: OpenAPIV3_1.SchemaObject) {
21
- schemas[id] = schema;
22
- },
23
- getReference(id: string): OpenAPIV3_1.ReferenceObject {
24
- return { $ref: `#/components/schemas/${id}` };
25
- },
26
- };
18
+ return {
19
+ schemas,
20
+ addSchema(id: string, schema: OpenAPIV3_1.SchemaObject) {
21
+ schemas[id] = schema;
22
+ },
23
+ getReference(id: string): OpenAPIV3_1.ReferenceObject {
24
+ return { $ref: `#/components/schemas/${id}` };
25
+ },
26
+ };
27
27
  }
28
28
 
29
29
  /**
@@ -33,43 +33,43 @@ export function createComponentCollector(): ComponentCollector {
33
33
  * The actual implementation is in @geekmidas/constructs to avoid circular dependencies.
34
34
  */
35
35
  export async function buildOpenApiSchema(
36
- endpoints: Array<{
37
- toOpenApi3Route(collector?: ComponentCollector): Promise<any>;
38
- }>,
39
- options: OpenApiSchemaOptions = {},
36
+ endpoints: Array<{
37
+ toOpenApi3Route(collector?: ComponentCollector): Promise<any>;
38
+ }>,
39
+ options: OpenApiSchemaOptions = {},
40
40
  ): Promise<OpenAPIV3_1.Document> {
41
- const { title = 'API', version = '1.0.0', description } = options;
42
- const paths: OpenAPIV3_1.PathsObject = {};
43
- const componentCollector = createComponentCollector();
41
+ const { title = 'API', version = '1.0.0', description } = options;
42
+ const paths: OpenAPIV3_1.PathsObject = {};
43
+ const componentCollector = createComponentCollector();
44
44
 
45
- for (const endpoint of endpoints) {
46
- const route = await endpoint.toOpenApi3Route(componentCollector);
45
+ for (const endpoint of endpoints) {
46
+ const route = await endpoint.toOpenApi3Route(componentCollector);
47
47
 
48
- // Merge the route into the paths object
49
- for (const [path, methods] of Object.entries(route)) {
50
- if (!paths[path]) {
51
- paths[path] = {};
52
- }
53
- Object.assign(paths[path], methods);
54
- }
55
- }
48
+ // Merge the route into the paths object
49
+ for (const [path, methods] of Object.entries(route)) {
50
+ if (!paths[path]) {
51
+ paths[path] = {};
52
+ }
53
+ Object.assign(paths[path], methods);
54
+ }
55
+ }
56
56
 
57
- const doc: OpenAPIV3_1.Document = {
58
- openapi: '3.0.0',
59
- info: {
60
- title,
61
- version,
62
- ...(description && { description }),
63
- },
64
- paths,
65
- };
57
+ const doc: OpenAPIV3_1.Document = {
58
+ openapi: '3.0.0',
59
+ info: {
60
+ title,
61
+ version,
62
+ ...(description && { description }),
63
+ },
64
+ paths,
65
+ };
66
66
 
67
- // Add components if any schemas were collected
68
- if (Object.keys(componentCollector.schemas).length > 0) {
69
- doc.components = {
70
- schemas: componentCollector.schemas,
71
- };
72
- }
67
+ // Add components if any schemas were collected
68
+ if (Object.keys(componentCollector.schemas).length > 0) {
69
+ doc.components = {
70
+ schemas: componentCollector.schemas,
71
+ };
72
+ }
73
73
 
74
- return doc;
74
+ return doc;
75
75
  }
package/src/parser.ts CHANGED
@@ -9,22 +9,22 @@ import type { InferStandardSchema } from './types';
9
9
  * @returns Validation result with value or issues
10
10
  */
11
11
  export function validate<T extends StandardSchemaV1>(schema: T, data: unknown) {
12
- return schema['~standard'].validate(data);
12
+ return schema['~standard'].validate(data);
13
13
  }
14
14
 
15
15
  export async function parseSchema<T extends StandardSchemaV1>(
16
- schema: T,
17
- data: unknown,
16
+ schema: T,
17
+ data: unknown,
18
18
  ): Promise<InferStandardSchema<T>> {
19
- if (!schema) {
20
- return undefined as InferStandardSchema<T>;
21
- }
19
+ if (!schema) {
20
+ return undefined as InferStandardSchema<T>;
21
+ }
22
22
 
23
- const parsed = await validate(schema as unknown as StandardSchemaV1, data);
23
+ const parsed = await validate(schema as unknown as StandardSchemaV1, data);
24
24
 
25
- if (parsed.issues) {
26
- throw parsed.issues;
27
- }
25
+ if (parsed.issues) {
26
+ throw parsed.issues;
27
+ }
28
28
 
29
- return parsed.value as InferStandardSchema<T>;
29
+ return parsed.value as InferStandardSchema<T>;
30
30
  }
package/src/types.ts CHANGED
@@ -1,23 +1,23 @@
1
1
  import type { StandardSchemaV1 } from '@standard-schema/spec';
2
2
 
3
3
  export type InferStandardSchema<T> = T extends StandardSchemaV1
4
- ? StandardSchemaV1.InferOutput<T>
5
- : never;
4
+ ? StandardSchemaV1.InferOutput<T>
5
+ : never;
6
6
 
7
7
  export type ComposableStandardSchema =
8
- | StandardSchemaV1
9
- | {
10
- [key: string]: StandardSchemaV1 | undefined;
11
- };
8
+ | StandardSchemaV1
9
+ | {
10
+ [key: string]: StandardSchemaV1 | undefined;
11
+ };
12
12
 
13
13
  export type InferComposableStandardSchema<T> = T extends StandardSchemaV1
14
- ? StandardSchemaV1.InferOutput<T>
15
- : T extends { [key: string]: StandardSchemaV1 | undefined }
16
- ? {
17
- [K in keyof T as T[K] extends StandardSchemaV1
18
- ? K
19
- : never]: T[K] extends StandardSchemaV1
20
- ? StandardSchemaV1.InferOutput<T[K]>
21
- : never;
22
- }
23
- : {};
14
+ ? StandardSchemaV1.InferOutput<T>
15
+ : T extends { [key: string]: StandardSchemaV1 | undefined }
16
+ ? {
17
+ [K in keyof T as T[K] extends StandardSchemaV1
18
+ ? K
19
+ : never]: T[K] extends StandardSchemaV1
20
+ ? StandardSchemaV1.InferOutput<T[K]>
21
+ : never;
22
+ }
23
+ : {};
package/tsconfig.json ADDED
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "outDir": "./dist",
5
+ "rootDir": "./src",
6
+ "composite": true
7
+ },
8
+ "include": ["src/**/*"]
9
+ }
package/tsdown.config.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { defineConfig } from 'tsdown';
2
2
 
3
3
  export default defineConfig({
4
- external: ['@valibot/to-json-schema', 'zod', 'zod-to-json-schema'],
4
+ external: ['@valibot/to-json-schema', 'zod', 'zod-to-json-schema'],
5
5
  });
@@ -1 +0,0 @@
1
- {"version":3,"file":"conversion-Civd6bIU.mjs","names":["vendor?: string","StandardSchemaJsonSchema: VendorConvertors","jsonSchema: any","componentCollector?: {\n addSchema(id: string, schema: any): void;\n getReference(id: string): { $ref: string };\n }","schema: any","processed: any","schema?: StandardSchemaV1","schema: StandardSchemaV1","schema: StandardSchemaV1 | undefined"],"sources":["../src/conversion.ts"],"sourcesContent":["import type { StandardSchemaV1 } from '@standard-schema/spec';\n\nexport enum SchemaVendor {\n zod = 'zod',\n valibot = 'valibot',\n}\n\nexport type VendorConvertor = (schema: any) => Promise<any>;\nexport type VendorConvertors = Record<SchemaVendor, VendorConvertor>;\n\nfunction isSchemaVendor(vendor?: string): vendor is SchemaVendor {\n if (!vendor) {\n return false;\n }\n\n return Object.values(SchemaVendor).includes(vendor as SchemaVendor);\n}\n\nexport const StandardSchemaJsonSchema: VendorConvertors = {\n zod: async (schema): Promise<any> => {\n try {\n const { z } = await import('zod/v4').catch(() => ({ z: {} }));\n\n if ('toJSONSchema' in z && typeof z.toJSONSchema === 'function') {\n return z.toJSONSchema(schema);\n }\n const { zodToJsonSchema } = await import('zod-to-json-schema');\n\n const result = zodToJsonSchema(schema, {\n removeAdditionalStrategy: 'strict',\n });\n\n return result;\n } catch (error) {\n // Fallback to basic conversion if zod-to-json-schema is not available\n console.warn(\n 'zod-to-json-schema not available, using basic conversion',\n error,\n );\n return { type: 'object' };\n }\n },\n valibot: async (schema): Promise<any> => {\n const { toJsonSchema } = await import('@valibot/to-json-schema');\n return toJsonSchema(schema as any);\n },\n};\n\nfunction extractAndConvertDefs(\n jsonSchema: any,\n componentCollector?: {\n addSchema(id: string, schema: any): void;\n getReference(id: string): { $ref: string };\n },\n): any {\n if (!jsonSchema || typeof jsonSchema !== 'object') {\n return jsonSchema;\n }\n\n // Process the schema recursively to update references\n const processSchema = (schema: any): any => {\n if (!schema || typeof schema !== 'object') {\n return schema;\n }\n\n // Handle $ref\n if (schema.$ref && typeof schema.$ref === 'string') {\n // Convert #/$defs/X to #/components/schemas/X\n if (schema.$ref.startsWith('#/$defs/')) {\n const refName = schema.$ref.replace('#/$defs/', '');\n return componentCollector\n ? componentCollector.getReference(refName)\n : schema;\n }\n return schema;\n }\n\n // Handle arrays\n if (Array.isArray(schema)) {\n return schema.map(processSchema);\n }\n\n // Process all properties recursively\n const processed: any = {};\n for (const [key, value] of Object.entries(schema)) {\n if (key === '$defs') {\n // Skip $defs as they've been extracted\n continue;\n }\n processed[key] = processSchema(value);\n }\n return processed;\n };\n\n // Extract $defs if present\n if (jsonSchema.$defs && componentCollector) {\n for (const [defName, defSchema] of Object.entries(jsonSchema.$defs)) {\n // Process the definition recursively to handle nested $refs\n const processedDefSchema = processSchema(defSchema);\n // Add each definition to the component collector\n componentCollector.addSchema(defName, processedDefSchema);\n }\n }\n\n // Process the schema and remove $defs\n const { $defs, ...schemaWithoutDefs } = jsonSchema;\n return processSchema(schemaWithoutDefs);\n}\n\nexport async function convertStandardSchemaToJsonSchema(\n schema?: StandardSchemaV1,\n componentCollector?: {\n addSchema(id: string, schema: any): void;\n getReference(id: string): { $ref: string };\n },\n): Promise<any> {\n if (!schema) {\n return undefined;\n }\n\n const vendor = schema['~standard']?.vendor;\n if (!isSchemaVendor(vendor)) {\n throw new Error(\n `Unsupported or missing vendor \"${vendor}\" for Standard Schema. Supported vendors are: ${Object.keys(StandardSchemaJsonSchema).join(', ')}`,\n );\n }\n\n const toJSONSchema = StandardSchemaJsonSchema[vendor];\n const jsonSchema = await toJSONSchema(schema);\n\n // Extract and convert $defs to components\n return extractAndConvertDefs(jsonSchema, componentCollector);\n}\n\nexport async function getZodMetadata(\n schema: StandardSchemaV1,\n): Promise<SchemaMeta | undefined> {\n const { ZodObject } = await import('zod/v4');\n\n if (schema instanceof ZodObject) {\n return schema.meta();\n }\n\n return undefined;\n}\n\nexport async function getSchemaMetadata(\n schema: StandardSchemaV1,\n): Promise<SchemaMeta | undefined> {\n const vendor = schema['~standard']?.vendor;\n\n if (vendor === 'zod') {\n return getZodMetadata(schema);\n }\n\n return undefined;\n}\n\ninterface SchemaMeta {\n id?: string;\n}\n\nexport async function convertSchemaWithComponents(\n schema: StandardSchemaV1 | undefined,\n componentCollector?: {\n addSchema(id: string, schema: any): void;\n getReference(id: string): { $ref: string };\n },\n): Promise<any> {\n if (!schema) {\n return undefined;\n }\n\n // Convert to JSON Schema with component collector to handle $defs\n const jsonSchema = await convertStandardSchemaToJsonSchema(\n schema,\n componentCollector,\n );\n\n if (!componentCollector) {\n return jsonSchema;\n }\n\n // Check if this schema has metadata with an ID\n const metadata = await getSchemaMetadata(schema);\n\n // Also check if the JSON Schema itself has an id field (from Zod's meta)\n const schemaId = metadata?.id || jsonSchema?.id;\n\n if (schemaId) {\n // Remove the id from the schema before adding to components\n const { id, ...schemaWithoutId } = jsonSchema;\n // Add this schema to components and return a reference\n componentCollector.addSchema(schemaId, schemaWithoutId);\n return componentCollector.getReference(schemaId);\n }\n\n return jsonSchema;\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"conversion-CrSNoSRa.cjs","names":["vendor?: string","StandardSchemaJsonSchema: VendorConvertors","jsonSchema: any","componentCollector?: {\n addSchema(id: string, schema: any): void;\n getReference(id: string): { $ref: string };\n }","schema: any","processed: any","schema?: StandardSchemaV1","schema: StandardSchemaV1","schema: StandardSchemaV1 | undefined"],"sources":["../src/conversion.ts"],"sourcesContent":["import type { StandardSchemaV1 } from '@standard-schema/spec';\n\nexport enum SchemaVendor {\n zod = 'zod',\n valibot = 'valibot',\n}\n\nexport type VendorConvertor = (schema: any) => Promise<any>;\nexport type VendorConvertors = Record<SchemaVendor, VendorConvertor>;\n\nfunction isSchemaVendor(vendor?: string): vendor is SchemaVendor {\n if (!vendor) {\n return false;\n }\n\n return Object.values(SchemaVendor).includes(vendor as SchemaVendor);\n}\n\nexport const StandardSchemaJsonSchema: VendorConvertors = {\n zod: async (schema): Promise<any> => {\n try {\n const { z } = await import('zod/v4').catch(() => ({ z: {} }));\n\n if ('toJSONSchema' in z && typeof z.toJSONSchema === 'function') {\n return z.toJSONSchema(schema);\n }\n const { zodToJsonSchema } = await import('zod-to-json-schema');\n\n const result = zodToJsonSchema(schema, {\n removeAdditionalStrategy: 'strict',\n });\n\n return result;\n } catch (error) {\n // Fallback to basic conversion if zod-to-json-schema is not available\n console.warn(\n 'zod-to-json-schema not available, using basic conversion',\n error,\n );\n return { type: 'object' };\n }\n },\n valibot: async (schema): Promise<any> => {\n const { toJsonSchema } = await import('@valibot/to-json-schema');\n return toJsonSchema(schema as any);\n },\n};\n\nfunction extractAndConvertDefs(\n jsonSchema: any,\n componentCollector?: {\n addSchema(id: string, schema: any): void;\n getReference(id: string): { $ref: string };\n },\n): any {\n if (!jsonSchema || typeof jsonSchema !== 'object') {\n return jsonSchema;\n }\n\n // Process the schema recursively to update references\n const processSchema = (schema: any): any => {\n if (!schema || typeof schema !== 'object') {\n return schema;\n }\n\n // Handle $ref\n if (schema.$ref && typeof schema.$ref === 'string') {\n // Convert #/$defs/X to #/components/schemas/X\n if (schema.$ref.startsWith('#/$defs/')) {\n const refName = schema.$ref.replace('#/$defs/', '');\n return componentCollector\n ? componentCollector.getReference(refName)\n : schema;\n }\n return schema;\n }\n\n // Handle arrays\n if (Array.isArray(schema)) {\n return schema.map(processSchema);\n }\n\n // Process all properties recursively\n const processed: any = {};\n for (const [key, value] of Object.entries(schema)) {\n if (key === '$defs') {\n // Skip $defs as they've been extracted\n continue;\n }\n processed[key] = processSchema(value);\n }\n return processed;\n };\n\n // Extract $defs if present\n if (jsonSchema.$defs && componentCollector) {\n for (const [defName, defSchema] of Object.entries(jsonSchema.$defs)) {\n // Process the definition recursively to handle nested $refs\n const processedDefSchema = processSchema(defSchema);\n // Add each definition to the component collector\n componentCollector.addSchema(defName, processedDefSchema);\n }\n }\n\n // Process the schema and remove $defs\n const { $defs, ...schemaWithoutDefs } = jsonSchema;\n return processSchema(schemaWithoutDefs);\n}\n\nexport async function convertStandardSchemaToJsonSchema(\n schema?: StandardSchemaV1,\n componentCollector?: {\n addSchema(id: string, schema: any): void;\n getReference(id: string): { $ref: string };\n },\n): Promise<any> {\n if (!schema) {\n return undefined;\n }\n\n const vendor = schema['~standard']?.vendor;\n if (!isSchemaVendor(vendor)) {\n throw new Error(\n `Unsupported or missing vendor \"${vendor}\" for Standard Schema. Supported vendors are: ${Object.keys(StandardSchemaJsonSchema).join(', ')}`,\n );\n }\n\n const toJSONSchema = StandardSchemaJsonSchema[vendor];\n const jsonSchema = await toJSONSchema(schema);\n\n // Extract and convert $defs to components\n return extractAndConvertDefs(jsonSchema, componentCollector);\n}\n\nexport async function getZodMetadata(\n schema: StandardSchemaV1,\n): Promise<SchemaMeta | undefined> {\n const { ZodObject } = await import('zod/v4');\n\n if (schema instanceof ZodObject) {\n return schema.meta();\n }\n\n return undefined;\n}\n\nexport async function getSchemaMetadata(\n schema: StandardSchemaV1,\n): Promise<SchemaMeta | undefined> {\n const vendor = schema['~standard']?.vendor;\n\n if (vendor === 'zod') {\n return getZodMetadata(schema);\n }\n\n return undefined;\n}\n\ninterface SchemaMeta {\n id?: string;\n}\n\nexport async function convertSchemaWithComponents(\n schema: StandardSchemaV1 | undefined,\n componentCollector?: {\n addSchema(id: string, schema: any): void;\n getReference(id: string): { $ref: string };\n },\n): Promise<any> {\n if (!schema) {\n return undefined;\n }\n\n // Convert to JSON Schema with component collector to handle $defs\n const jsonSchema = await convertStandardSchemaToJsonSchema(\n schema,\n componentCollector,\n );\n\n if (!componentCollector) {\n return jsonSchema;\n }\n\n // Check if this schema has metadata with an ID\n const metadata = await getSchemaMetadata(schema);\n\n // Also check if the JSON Schema itself has an id field (from Zod's meta)\n const schemaId = metadata?.id || jsonSchema?.id;\n\n if (schemaId) {\n // Remove the id from the schema before adding to components\n const { id, ...schemaWithoutId } = jsonSchema;\n // Add this schema to components and return a reference\n componentCollector.addSchema(schemaId, schemaWithoutId);\n return componentCollector.getReference(schemaId);\n }\n\n return jsonSchema;\n}\n"],"mappings":"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"}