@contractspec/lib.contracts-transformers 0.0.0-canary-20260113162409
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.
- package/LICENSE +21 -0
- package/README.md +95 -0
- package/dist/common/index.d.ts +3 -0
- package/dist/common/index.js +3 -0
- package/dist/common/types.d.ts +159 -0
- package/dist/common/types.d.ts.map +1 -0
- package/dist/common/utils.d.ts +52 -0
- package/dist/common/utils.d.ts.map +1 -0
- package/dist/common/utils.js +103 -0
- package/dist/common/utils.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +18 -0
- package/dist/openapi/differ.d.ts +42 -0
- package/dist/openapi/differ.d.ts.map +1 -0
- package/dist/openapi/differ.js +222 -0
- package/dist/openapi/differ.js.map +1 -0
- package/dist/openapi/exporter/data-views.d.ts +38 -0
- package/dist/openapi/exporter/data-views.d.ts.map +1 -0
- package/dist/openapi/exporter/data-views.js +47 -0
- package/dist/openapi/exporter/data-views.js.map +1 -0
- package/dist/openapi/exporter/events.d.ts +28 -0
- package/dist/openapi/exporter/events.d.ts.map +1 -0
- package/dist/openapi/exporter/events.js +39 -0
- package/dist/openapi/exporter/events.js.map +1 -0
- package/dist/openapi/exporter/features.d.ts +37 -0
- package/dist/openapi/exporter/features.d.ts.map +1 -0
- package/dist/openapi/exporter/features.js +46 -0
- package/dist/openapi/exporter/features.js.map +1 -0
- package/dist/openapi/exporter/forms.d.ts +30 -0
- package/dist/openapi/exporter/forms.d.ts.map +1 -0
- package/dist/openapi/exporter/forms.js +49 -0
- package/dist/openapi/exporter/forms.js.map +1 -0
- package/dist/openapi/exporter/index.js +8 -0
- package/dist/openapi/exporter/operations.d.ts +65 -0
- package/dist/openapi/exporter/operations.d.ts.map +1 -0
- package/dist/openapi/exporter/operations.js +143 -0
- package/dist/openapi/exporter/operations.js.map +1 -0
- package/dist/openapi/exporter/presentations.d.ts +32 -0
- package/dist/openapi/exporter/presentations.d.ts.map +1 -0
- package/dist/openapi/exporter/presentations.js +60 -0
- package/dist/openapi/exporter/presentations.js.map +1 -0
- package/dist/openapi/exporter/registries.d.ts +23 -0
- package/dist/openapi/exporter/registries.d.ts.map +1 -0
- package/dist/openapi/exporter/registries.js +29 -0
- package/dist/openapi/exporter/registries.js.map +1 -0
- package/dist/openapi/exporter/workflows.d.ts +36 -0
- package/dist/openapi/exporter/workflows.d.ts.map +1 -0
- package/dist/openapi/exporter/workflows.js +54 -0
- package/dist/openapi/exporter/workflows.js.map +1 -0
- package/dist/openapi/exporter.d.ts +48 -0
- package/dist/openapi/exporter.d.ts.map +1 -0
- package/dist/openapi/exporter.js +122 -0
- package/dist/openapi/exporter.js.map +1 -0
- package/dist/openapi/importer/analyzer.js +28 -0
- package/dist/openapi/importer/analyzer.js.map +1 -0
- package/dist/openapi/importer/events.js +40 -0
- package/dist/openapi/importer/events.js.map +1 -0
- package/dist/openapi/importer/generator.js +105 -0
- package/dist/openapi/importer/generator.js.map +1 -0
- package/dist/openapi/importer/grouping.js +73 -0
- package/dist/openapi/importer/grouping.js.map +1 -0
- package/dist/openapi/importer/index.d.ts +17 -0
- package/dist/openapi/importer/index.d.ts.map +1 -0
- package/dist/openapi/importer/index.js +175 -0
- package/dist/openapi/importer/index.js.map +1 -0
- package/dist/openapi/importer/models.js +22 -0
- package/dist/openapi/importer/models.js.map +1 -0
- package/dist/openapi/importer/schemas.js +60 -0
- package/dist/openapi/importer/schemas.js.map +1 -0
- package/dist/openapi/index.d.ts +16 -0
- package/dist/openapi/index.js +18 -0
- package/dist/openapi/parser/document.d.ts +20 -0
- package/dist/openapi/parser/document.d.ts.map +1 -0
- package/dist/openapi/parser/document.js +95 -0
- package/dist/openapi/parser/document.js.map +1 -0
- package/dist/openapi/parser/index.js +5 -0
- package/dist/openapi/parser/operation.js +59 -0
- package/dist/openapi/parser/operation.js.map +1 -0
- package/dist/openapi/parser/parameters.js +37 -0
- package/dist/openapi/parser/parameters.js.map +1 -0
- package/dist/openapi/parser/resolvers.js +63 -0
- package/dist/openapi/parser/resolvers.js.map +1 -0
- package/dist/openapi/parser/utils.d.ts +19 -0
- package/dist/openapi/parser/utils.d.ts.map +1 -0
- package/dist/openapi/parser/utils.js +48 -0
- package/dist/openapi/parser/utils.js.map +1 -0
- package/dist/openapi/parser.js +6 -0
- package/dist/openapi/schema-converter.d.ts +71 -0
- package/dist/openapi/schema-converter.d.ts.map +1 -0
- package/dist/openapi/schema-converter.js +161 -0
- package/dist/openapi/schema-converter.js.map +1 -0
- package/dist/openapi/schema-generators/index.js +462 -0
- package/dist/openapi/schema-generators/index.js.map +1 -0
- package/dist/openapi/types.d.ts +277 -0
- package/dist/openapi/types.d.ts.map +1 -0
- package/package.json +69 -0
|
@@ -0,0 +1,462 @@
|
|
|
1
|
+
import { toKebabCase, toPascalCase, toValidIdentifier } from "../../common/utils.js";
|
|
2
|
+
import { generateImports, getScalarType, jsonSchemaToType } from "../schema-converter.js";
|
|
3
|
+
|
|
4
|
+
//#region src/openapi/schema-generators/index.ts
|
|
5
|
+
const JSON_SCHEMA_TO_SCALAR = {
|
|
6
|
+
string: "ScalarTypeEnum.String_unsecure",
|
|
7
|
+
integer: "ScalarTypeEnum.Int_unsecure",
|
|
8
|
+
number: "ScalarTypeEnum.Float_unsecure",
|
|
9
|
+
boolean: "ScalarTypeEnum.Boolean",
|
|
10
|
+
"string:date": "ScalarTypeEnum.Date",
|
|
11
|
+
"string:date-time": "ScalarTypeEnum.DateTime",
|
|
12
|
+
"string:email": "ScalarTypeEnum.EmailAddress",
|
|
13
|
+
"string:uri": "ScalarTypeEnum.URL",
|
|
14
|
+
"string:uuid": "ScalarTypeEnum.ID"
|
|
15
|
+
};
|
|
16
|
+
function isReference(schema) {
|
|
17
|
+
return typeof schema === "object" && schema !== null && "$ref" in schema;
|
|
18
|
+
}
|
|
19
|
+
function typeNameFromRef(ref) {
|
|
20
|
+
const parts = ref.split("/");
|
|
21
|
+
return parts[parts.length - 1] ?? "Unknown";
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Factory function to create a format-specific schema generator.
|
|
25
|
+
*
|
|
26
|
+
* @param format - The target output format
|
|
27
|
+
* @param config - ContractSpec configuration
|
|
28
|
+
* @returns A schema generator for the specified format
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```typescript
|
|
32
|
+
* const generator = createSchemaGenerator('zod', config);
|
|
33
|
+
* const model = generator.generateModel(openApiSchema, 'User');
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
function createSchemaGenerator(format, config) {
|
|
37
|
+
switch (format) {
|
|
38
|
+
case "zod": return new ZodSchemaGenerator(config);
|
|
39
|
+
case "json-schema": return new JsonSchemaGenerator(config);
|
|
40
|
+
case "graphql": return new GraphQLSchemaGenerator(config);
|
|
41
|
+
case "contractspec":
|
|
42
|
+
default: return new ContractSpecSchemaGenerator(config);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
var ContractSpecSchemaGenerator = class {
|
|
46
|
+
format = "contractspec";
|
|
47
|
+
config;
|
|
48
|
+
constructor(config) {
|
|
49
|
+
this.config = config;
|
|
50
|
+
}
|
|
51
|
+
generateModel(schema, name) {
|
|
52
|
+
const model = this.generateContractSpecSchema(schema, name);
|
|
53
|
+
const dependencyImports = this.config ? generateImports(model.fields, this.config, false).split("\n").filter(Boolean) : [];
|
|
54
|
+
return {
|
|
55
|
+
code: model.code,
|
|
56
|
+
fileName: toKebabCase(name) + ".ts",
|
|
57
|
+
imports: [...this.getBaseImports(), ...dependencyImports],
|
|
58
|
+
name: model.name
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
generateField(schema, fieldName, required) {
|
|
62
|
+
const field = this.convertField(schema, fieldName, required);
|
|
63
|
+
return {
|
|
64
|
+
code: field.scalarType ? `${field.scalarType}()` : "ScalarTypeEnum.String_unsecure()",
|
|
65
|
+
typeRef: field.type.type,
|
|
66
|
+
isOptional: field.type.optional,
|
|
67
|
+
isArray: field.type.array
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
getBaseImports() {
|
|
71
|
+
return ["import { defineSchemaModel, ScalarTypeEnum, EnumType } from '@contractspec/lib.schema';"];
|
|
72
|
+
}
|
|
73
|
+
generateContractSpecSchema(schema, modelName, indent = 0) {
|
|
74
|
+
const spaces = " ".repeat(indent);
|
|
75
|
+
const fields = [];
|
|
76
|
+
if (isReference(schema)) return {
|
|
77
|
+
name: toPascalCase(typeNameFromRef(schema.$ref)),
|
|
78
|
+
fields: [],
|
|
79
|
+
code: `// Reference to ${schema.$ref}`
|
|
80
|
+
};
|
|
81
|
+
const schemaObj = schema;
|
|
82
|
+
const description = schemaObj["description"];
|
|
83
|
+
const properties = schemaObj["properties"];
|
|
84
|
+
const required = schemaObj["required"] ?? [];
|
|
85
|
+
const enumValues = schemaObj["enum"];
|
|
86
|
+
if (enumValues && enumValues.length > 0) {
|
|
87
|
+
const safeModelName$1 = toPascalCase(toValidIdentifier(modelName));
|
|
88
|
+
return {
|
|
89
|
+
name: safeModelName$1,
|
|
90
|
+
description,
|
|
91
|
+
fields: [],
|
|
92
|
+
code: [
|
|
93
|
+
`${spaces}/**`,
|
|
94
|
+
`${spaces} * Enum type: ${safeModelName$1}`,
|
|
95
|
+
description ? `${spaces} * ${description}` : null,
|
|
96
|
+
`${spaces} */`,
|
|
97
|
+
`${spaces}export const ${safeModelName$1} = new EnumType('${safeModelName$1}', [${enumValues.map((v) => `'${String(v)}'`).join(", ")}]);`
|
|
98
|
+
].filter((line) => line !== null).join("\n")
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
const schemaType = schemaObj["type"];
|
|
102
|
+
if (schemaType && !properties && !enumValues) {
|
|
103
|
+
const safeModelName$1 = toPascalCase(toValidIdentifier(modelName));
|
|
104
|
+
const format = schemaObj["format"];
|
|
105
|
+
const scalarType = JSON_SCHEMA_TO_SCALAR[format ? `${schemaType}:${format}` : schemaType] ?? JSON_SCHEMA_TO_SCALAR[schemaType];
|
|
106
|
+
if (scalarType) return {
|
|
107
|
+
name: safeModelName$1,
|
|
108
|
+
description,
|
|
109
|
+
fields: [],
|
|
110
|
+
code: [
|
|
111
|
+
`${spaces}/**`,
|
|
112
|
+
`${spaces} * Type alias: ${safeModelName$1}`,
|
|
113
|
+
description ? `${spaces} * ${description}` : null,
|
|
114
|
+
`${spaces} * Underlying type: ${scalarType}`,
|
|
115
|
+
`${spaces} */`,
|
|
116
|
+
`${spaces}export const ${safeModelName$1} = defineSchemaModel({`,
|
|
117
|
+
`${spaces} name: '${safeModelName$1}',`,
|
|
118
|
+
description ? `${spaces} description: ${JSON.stringify(description)},` : null,
|
|
119
|
+
`${spaces} fields: {`,
|
|
120
|
+
`${spaces} value: {`,
|
|
121
|
+
`${spaces} type: ${scalarType}(),`,
|
|
122
|
+
`${spaces} isOptional: false,`,
|
|
123
|
+
`${spaces} },`,
|
|
124
|
+
`${spaces} },`,
|
|
125
|
+
`${spaces}});`
|
|
126
|
+
].filter((line) => line !== null).join("\n")
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
if (schemaObj["additionalProperties"] && !properties) {
|
|
130
|
+
const safeModelName$1 = toPascalCase(toValidIdentifier(modelName));
|
|
131
|
+
return {
|
|
132
|
+
name: safeModelName$1,
|
|
133
|
+
description,
|
|
134
|
+
fields: [],
|
|
135
|
+
code: [
|
|
136
|
+
`${spaces}/**`,
|
|
137
|
+
`${spaces} * Dictionary/Record type: ${safeModelName$1}`,
|
|
138
|
+
description ? `${spaces} * ${description}` : null,
|
|
139
|
+
`${spaces} * Use as: Record<string, unknown> - access via record[key]`,
|
|
140
|
+
`${spaces} */`,
|
|
141
|
+
`${spaces}export const ${safeModelName$1} = ScalarTypeEnum.JSONObject();`
|
|
142
|
+
].filter((line) => line !== null).join("\n")
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
if (!properties) {
|
|
146
|
+
const safeModelName$1 = toPascalCase(toValidIdentifier(modelName));
|
|
147
|
+
return {
|
|
148
|
+
name: safeModelName$1,
|
|
149
|
+
description,
|
|
150
|
+
fields: [],
|
|
151
|
+
code: [
|
|
152
|
+
`${spaces}export const ${safeModelName$1} = defineSchemaModel({`,
|
|
153
|
+
`${spaces} name: '${safeModelName$1}',`,
|
|
154
|
+
description ? `${spaces} description: ${JSON.stringify(description)},` : null,
|
|
155
|
+
`${spaces} fields: {},`,
|
|
156
|
+
`${spaces}});`
|
|
157
|
+
].filter((line) => line !== null).join("\n")
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
const safeModelName = toPascalCase(toValidIdentifier(modelName));
|
|
161
|
+
for (const [propName, propSchema] of Object.entries(properties)) {
|
|
162
|
+
const isRequired = required.includes(propName);
|
|
163
|
+
fields.push(this.convertField(propSchema, propName, isRequired, safeModelName));
|
|
164
|
+
}
|
|
165
|
+
const lines = [];
|
|
166
|
+
for (const field of fields) if (field.nestedModel) {
|
|
167
|
+
lines.push(field.nestedModel.code);
|
|
168
|
+
lines.push("");
|
|
169
|
+
}
|
|
170
|
+
lines.push(`${spaces}export const ${safeModelName} = defineSchemaModel({`);
|
|
171
|
+
lines.push(`${spaces} name: '${safeModelName}',`);
|
|
172
|
+
if (description) lines.push(`${spaces} description: ${JSON.stringify(description)},`);
|
|
173
|
+
lines.push(`${spaces} fields: {`);
|
|
174
|
+
for (const field of fields) {
|
|
175
|
+
const fieldLines = this.generateFieldCodeHelper(field, indent + 2);
|
|
176
|
+
lines.push(fieldLines);
|
|
177
|
+
}
|
|
178
|
+
lines.push(`${spaces} },`);
|
|
179
|
+
lines.push(`${spaces}});`);
|
|
180
|
+
return {
|
|
181
|
+
name: safeModelName,
|
|
182
|
+
description,
|
|
183
|
+
fields,
|
|
184
|
+
code: lines.join("\n"),
|
|
185
|
+
imports: []
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
convertField(schema, fieldName, required, parentName) {
|
|
189
|
+
const type = jsonSchemaToType(schema, fieldName);
|
|
190
|
+
const scalarType = getScalarType(schema);
|
|
191
|
+
let enumValues;
|
|
192
|
+
let nestedModel;
|
|
193
|
+
if (!isReference(schema)) {
|
|
194
|
+
const schemaObj = schema;
|
|
195
|
+
const enumArr = schemaObj["enum"];
|
|
196
|
+
if (enumArr) enumValues = enumArr.map(String);
|
|
197
|
+
if (schemaObj["type"] === "object" && !scalarType && schemaObj["properties"] && !enumValues) {
|
|
198
|
+
const nestedName = (parentName ? parentName : "") + toPascalCase(fieldName);
|
|
199
|
+
nestedModel = this.generateContractSpecSchema(schema, nestedName);
|
|
200
|
+
type.type = nestedModel.name;
|
|
201
|
+
type.isReference = true;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return {
|
|
205
|
+
name: fieldName,
|
|
206
|
+
type: {
|
|
207
|
+
...type,
|
|
208
|
+
optional: !required || type.optional,
|
|
209
|
+
description: !isReference(schema) ? schema["description"] : void 0
|
|
210
|
+
},
|
|
211
|
+
scalarType,
|
|
212
|
+
enumValues,
|
|
213
|
+
nestedModel
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
generateFieldCodeHelper(field, indent) {
|
|
217
|
+
const spaces = " ".repeat(indent);
|
|
218
|
+
const lines = [];
|
|
219
|
+
const safeKey = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(field.name) ? field.name : `'${field.name}'`;
|
|
220
|
+
lines.push(`${spaces}${safeKey}: {`);
|
|
221
|
+
if (field.enumValues) {
|
|
222
|
+
const enumName = toPascalCase(field.name) + "Enum";
|
|
223
|
+
lines.push(`${spaces} type: new EnumType('${enumName}', [${field.enumValues.map((v) => `'${v}'`).join(", ")}]),`);
|
|
224
|
+
} else if (field.scalarType) lines.push(`${spaces} type: ${field.scalarType}(),`);
|
|
225
|
+
else if (field.nestedModel) lines.push(`${spaces} type: ${field.nestedModel.name},`);
|
|
226
|
+
else if (field.type.primitive) {
|
|
227
|
+
const fallbackScalar = field.type.type === "number" ? "ScalarTypeEnum.Float_unsecure" : field.type.type === "boolean" ? "ScalarTypeEnum.Boolean_unsecure" : "ScalarTypeEnum.String_unsecure";
|
|
228
|
+
lines.push(`${spaces} type: ${fallbackScalar}(),`);
|
|
229
|
+
} else if (field.type.isReference) lines.push(`${spaces} type: ${field.type.type},`);
|
|
230
|
+
else lines.push(`${spaces} type: ScalarTypeEnum.JSONObject(), // TODO: Define nested model for ${field.type.type}`);
|
|
231
|
+
lines.push(`${spaces} isOptional: ${field.type.optional},`);
|
|
232
|
+
if (field.type.array) lines.push(`${spaces} isArray: true,`);
|
|
233
|
+
lines.push(`${spaces}},`);
|
|
234
|
+
return lines.join("\n");
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
var ZodSchemaGenerator = class {
|
|
238
|
+
format = "zod";
|
|
239
|
+
config;
|
|
240
|
+
constructor(config) {
|
|
241
|
+
this.config = config;
|
|
242
|
+
}
|
|
243
|
+
generateModel(schema, name, options) {
|
|
244
|
+
const schemaObj = schema;
|
|
245
|
+
const properties = schemaObj["properties"];
|
|
246
|
+
schemaObj["required"];
|
|
247
|
+
const description = options?.description ?? schemaObj["description"];
|
|
248
|
+
const lines = [];
|
|
249
|
+
if (description) {
|
|
250
|
+
lines.push(`/**`);
|
|
251
|
+
lines.push(` * ${description}`);
|
|
252
|
+
lines.push(` */`);
|
|
253
|
+
}
|
|
254
|
+
const schemaName = `${name}Schema`;
|
|
255
|
+
let schemaCode;
|
|
256
|
+
if (properties) schemaCode = this.generateZodObject(schemaObj);
|
|
257
|
+
else schemaCode = "z.object({})";
|
|
258
|
+
lines.push(`export const ${schemaName} = ${schemaCode};`);
|
|
259
|
+
lines.push(``);
|
|
260
|
+
lines.push(`export const ${name} = new ZodSchemaType(${schemaName}, { name: '${name}', description: ${JSON.stringify(description)} });`);
|
|
261
|
+
lines.push(``);
|
|
262
|
+
lines.push(`export type ${name} = z.infer<typeof ${schemaName}>;`);
|
|
263
|
+
return {
|
|
264
|
+
code: lines.join("\n"),
|
|
265
|
+
fileName: toKebabCase(name) + ".ts",
|
|
266
|
+
imports: this.getBaseImports(),
|
|
267
|
+
name
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
generateField(schema, _fieldName, required) {
|
|
271
|
+
const schemaObj = schema;
|
|
272
|
+
const type = schemaObj["type"];
|
|
273
|
+
const format = schemaObj["format"];
|
|
274
|
+
const nullable = schemaObj["nullable"];
|
|
275
|
+
let zodType;
|
|
276
|
+
if (type === "object" && schemaObj["properties"]) zodType = this.generateZodObject(schemaObj);
|
|
277
|
+
else {
|
|
278
|
+
zodType = this.mapTypeToZod(type, format);
|
|
279
|
+
if (schemaObj["enum"]) zodType = `z.enum([${schemaObj["enum"].map((v) => `'${v}'`).join(", ")}])`;
|
|
280
|
+
if (type === "array") {
|
|
281
|
+
const items = schemaObj["items"];
|
|
282
|
+
if (items) zodType = `z.array(${this.generateField(items, "item", true).code.replace(".optional()", "")})`;
|
|
283
|
+
else zodType = "z.array(z.unknown())";
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
if (type === "string") {
|
|
287
|
+
if (schemaObj["minLength"] !== void 0) zodType += `.min(${schemaObj["minLength"]})`;
|
|
288
|
+
if (schemaObj["maxLength"] !== void 0) zodType += `.max(${schemaObj["maxLength"]})`;
|
|
289
|
+
if (schemaObj["pattern"] !== void 0) zodType += `.regex(/${schemaObj["pattern"]}/)`;
|
|
290
|
+
} else if (type === "integer" || type === "number") {
|
|
291
|
+
if (schemaObj["minimum"] !== void 0) zodType += schemaObj["exclusiveMinimum"] === true ? `.gt(${schemaObj["minimum"]})` : `.min(${schemaObj["minimum"]})`;
|
|
292
|
+
else if (typeof schemaObj["exclusiveMinimum"] === "number") zodType += `.gt(${schemaObj["exclusiveMinimum"]})`;
|
|
293
|
+
if (schemaObj["maximum"] !== void 0) zodType += schemaObj["exclusiveMaximum"] === true ? `.lt(${schemaObj["maximum"]})` : `.max(${schemaObj["maximum"]})`;
|
|
294
|
+
else if (typeof schemaObj["exclusiveMaximum"] === "number") zodType += `.lt(${schemaObj["exclusiveMaximum"]})`;
|
|
295
|
+
if (schemaObj["multipleOf"] !== void 0) zodType += `.step(${schemaObj["multipleOf"]})`;
|
|
296
|
+
} else if (type === "array") {
|
|
297
|
+
if (schemaObj["minItems"] !== void 0) zodType += `.min(${schemaObj["minItems"]})`;
|
|
298
|
+
if (schemaObj["maxItems"] !== void 0) zodType += `.max(${schemaObj["maxItems"]})`;
|
|
299
|
+
}
|
|
300
|
+
if (schemaObj["default"] !== void 0) zodType += `.default(${JSON.stringify(schemaObj["default"])})`;
|
|
301
|
+
if (!required || nullable) zodType = `${zodType}.optional()`;
|
|
302
|
+
return {
|
|
303
|
+
code: zodType,
|
|
304
|
+
typeRef: type ?? "unknown",
|
|
305
|
+
isOptional: !required || Boolean(nullable),
|
|
306
|
+
isArray: type === "array"
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
getBaseImports() {
|
|
310
|
+
return ["import * as z from 'zod';", "import { ZodSchemaType } from '@contractspec/lib.schema';"];
|
|
311
|
+
}
|
|
312
|
+
generateZodObject(schemaObj) {
|
|
313
|
+
const required = schemaObj["required"] ?? [];
|
|
314
|
+
const properties = schemaObj["properties"];
|
|
315
|
+
const lines = ["z.object({"];
|
|
316
|
+
for (const [propName, propSchema] of Object.entries(properties)) {
|
|
317
|
+
const isRequired = required.includes(propName);
|
|
318
|
+
const field = this.generateField(propSchema, propName, isRequired);
|
|
319
|
+
const safeName = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(propName) ? propName : `'${propName}'`;
|
|
320
|
+
lines.push(` ${safeName}: ${field.code},`);
|
|
321
|
+
}
|
|
322
|
+
lines.push("})");
|
|
323
|
+
return lines.join("\n");
|
|
324
|
+
}
|
|
325
|
+
mapTypeToZod(type, format) {
|
|
326
|
+
if (format === "date-time") return "z.string().datetime()";
|
|
327
|
+
if (format === "date") return "z.string().date()";
|
|
328
|
+
if (format === "email") return "z.string().email()";
|
|
329
|
+
if (format === "uri" || format === "url") return "z.string().url()";
|
|
330
|
+
if (format === "uuid") return "z.string().uuid()";
|
|
331
|
+
switch (type) {
|
|
332
|
+
case "string": return "z.string()";
|
|
333
|
+
case "integer": return "z.number().int()";
|
|
334
|
+
case "number": return "z.number()";
|
|
335
|
+
case "boolean": return "z.boolean()";
|
|
336
|
+
case "object": return "z.record(z.string(), z.unknown())";
|
|
337
|
+
case "null": return "z.null()";
|
|
338
|
+
default: return "z.unknown()";
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
};
|
|
342
|
+
var JsonSchemaGenerator = class {
|
|
343
|
+
format = "json-schema";
|
|
344
|
+
config;
|
|
345
|
+
constructor(config) {
|
|
346
|
+
this.config = config;
|
|
347
|
+
}
|
|
348
|
+
generateModel(schema, name, options) {
|
|
349
|
+
const schemaObj = schema;
|
|
350
|
+
const description = options?.description ?? schemaObj["description"];
|
|
351
|
+
const jsonSchema = {
|
|
352
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
353
|
+
title: name,
|
|
354
|
+
...schemaObj
|
|
355
|
+
};
|
|
356
|
+
if (description) jsonSchema["description"] = description;
|
|
357
|
+
const lines = [];
|
|
358
|
+
lines.push(`/**`);
|
|
359
|
+
lines.push(` * JSON Schema: ${name}`);
|
|
360
|
+
if (description) lines.push(` * ${description}`);
|
|
361
|
+
lines.push(` */`);
|
|
362
|
+
const schemaName = `${name}Schema`;
|
|
363
|
+
lines.push(`export const ${schemaName} = ${JSON.stringify(jsonSchema, null, 2)} as const;`);
|
|
364
|
+
lines.push(``);
|
|
365
|
+
lines.push(`export const ${name} = new JsonSchemaType(${schemaName});`);
|
|
366
|
+
lines.push(``);
|
|
367
|
+
lines.push(`export type ${name} = unknown; // JSON Schema type inference not fully supported`);
|
|
368
|
+
return {
|
|
369
|
+
code: lines.join("\n"),
|
|
370
|
+
fileName: toKebabCase(name) + ".ts",
|
|
371
|
+
imports: this.getBaseImports(),
|
|
372
|
+
name
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
generateField(schema, _fieldName, required) {
|
|
376
|
+
const schemaObj = schema;
|
|
377
|
+
const type = schemaObj["type"];
|
|
378
|
+
const nullable = schemaObj["nullable"];
|
|
379
|
+
return {
|
|
380
|
+
code: JSON.stringify(schemaObj),
|
|
381
|
+
typeRef: type ?? "unknown",
|
|
382
|
+
isOptional: !required || Boolean(nullable),
|
|
383
|
+
isArray: type === "array"
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
getBaseImports() {
|
|
387
|
+
return ["import { JsonSchemaType } from '@contractspec/lib.schema';"];
|
|
388
|
+
}
|
|
389
|
+
};
|
|
390
|
+
var GraphQLSchemaGenerator = class {
|
|
391
|
+
format = "graphql";
|
|
392
|
+
config;
|
|
393
|
+
constructor(config) {
|
|
394
|
+
this.config = config;
|
|
395
|
+
}
|
|
396
|
+
generateModel(schema, name, options) {
|
|
397
|
+
const schemaObj = schema;
|
|
398
|
+
const properties = schemaObj["properties"];
|
|
399
|
+
const required = schemaObj["required"] ?? [];
|
|
400
|
+
const description = options?.description ?? schemaObj["description"];
|
|
401
|
+
const lines = [];
|
|
402
|
+
if (description) lines.push(`"""${description}"""`);
|
|
403
|
+
lines.push(`type ${name} {`);
|
|
404
|
+
if (properties) for (const [propName, propSchema] of Object.entries(properties)) {
|
|
405
|
+
const isRequired = required.includes(propName);
|
|
406
|
+
const field = this.generateField(propSchema, propName, isRequired);
|
|
407
|
+
const nullMarker = isRequired ? "!" : "";
|
|
408
|
+
lines.push(` ${propName}: ${field.typeRef}${nullMarker}`);
|
|
409
|
+
}
|
|
410
|
+
lines.push(`}`);
|
|
411
|
+
const sdl = lines.join("\n");
|
|
412
|
+
const tsLines = [];
|
|
413
|
+
tsLines.push(`/**`);
|
|
414
|
+
tsLines.push(` * GraphQL type definition: ${name}`);
|
|
415
|
+
tsLines.push(` */`);
|
|
416
|
+
tsLines.push(`export const ${name}TypeDef = \`${sdl}\`;`);
|
|
417
|
+
tsLines.push(``);
|
|
418
|
+
tsLines.push(`export const ${name} = new GraphQLSchemaType(${name}TypeDef, '${name}');`);
|
|
419
|
+
return {
|
|
420
|
+
code: tsLines.join("\n"),
|
|
421
|
+
fileName: toKebabCase(name) + ".ts",
|
|
422
|
+
imports: this.getBaseImports(),
|
|
423
|
+
name
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
generateField(schema, _fieldName, required) {
|
|
427
|
+
const schemaObj = schema;
|
|
428
|
+
const type = schemaObj["type"];
|
|
429
|
+
const format = schemaObj["format"];
|
|
430
|
+
const nullable = schemaObj["nullable"];
|
|
431
|
+
const gqlType = this.mapTypeToGraphQL(type, format);
|
|
432
|
+
return {
|
|
433
|
+
code: gqlType,
|
|
434
|
+
typeRef: gqlType,
|
|
435
|
+
isOptional: !required || Boolean(nullable),
|
|
436
|
+
isArray: type === "array"
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
getBaseImports() {
|
|
440
|
+
return ["import { GraphQLSchemaType } from '@contractspec/lib.schema';"];
|
|
441
|
+
}
|
|
442
|
+
mapTypeToGraphQL(type, format) {
|
|
443
|
+
if (format === "date-time") return "DateTime";
|
|
444
|
+
if (format === "date") return "Date";
|
|
445
|
+
if (format === "email") return "String";
|
|
446
|
+
if (format === "uri" || format === "url") return "String";
|
|
447
|
+
if (format === "uuid") return "ID";
|
|
448
|
+
switch (type) {
|
|
449
|
+
case "string": return "String";
|
|
450
|
+
case "integer": return "Int";
|
|
451
|
+
case "number": return "Float";
|
|
452
|
+
case "boolean": return "Boolean";
|
|
453
|
+
case "object": return "JSON";
|
|
454
|
+
case "array": return "[JSON]";
|
|
455
|
+
default: return "JSON";
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
};
|
|
459
|
+
|
|
460
|
+
//#endregion
|
|
461
|
+
export { createSchemaGenerator };
|
|
462
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["safeModelName"],"sources":["../../../src/openapi/schema-generators/index.ts"],"sourcesContent":["/**\n * Schema generator factory for multi-format code generation.\n *\n * Provides format-specific generators for OpenAPI to ContractSpec conversion.\n *\n * @module schema-generators\n */\n\nimport type {\n ContractsrcConfig,\n SchemaFormat,\n} from '@contractspec/lib.contracts';\nimport type { OpenApiSchema } from '../types';\nimport {\n type GeneratedModel,\n generateImports,\n getScalarType,\n jsonSchemaToType,\n type SchemaField,\n} from '../schema-converter';\nimport {\n toKebabCase,\n toPascalCase,\n toValidIdentifier,\n} from '../../common/utils';\n\nconst JSON_SCHEMA_TO_SCALAR: Record<string, string> = {\n string: 'ScalarTypeEnum.String_unsecure',\n integer: 'ScalarTypeEnum.Int_unsecure',\n number: 'ScalarTypeEnum.Float_unsecure',\n boolean: 'ScalarTypeEnum.Boolean',\n 'string:date': 'ScalarTypeEnum.Date',\n 'string:date-time': 'ScalarTypeEnum.DateTime',\n 'string:email': 'ScalarTypeEnum.EmailAddress',\n 'string:uri': 'ScalarTypeEnum.URL',\n 'string:uuid': 'ScalarTypeEnum.ID',\n};\n\nfunction isReference(schema: OpenApiSchema): schema is { $ref: string } {\n return typeof schema === 'object' && schema !== null && '$ref' in schema;\n}\n\nfunction typeNameFromRef(ref: string): string {\n const parts = ref.split('/');\n return parts[parts.length - 1] ?? 'Unknown';\n}\n\n/**\n * Generated code output for a model.\n */\nexport interface GeneratedCode {\n /** The generated TypeScript/JSON code */\n code: string;\n /** File name for the generated code */\n fileName: string;\n /** Required imports */\n imports: string[];\n /** The name of the exported symbol */\n name: string;\n}\n\n/**\n * Generated code output for a field.\n */\nexport interface GeneratedFieldCode {\n /** The field code snippet */\n code: string;\n /** Type reference for the field */\n typeRef: string;\n /** Whether this is an optional field */\n isOptional: boolean;\n /** Whether this is an array field */\n isArray: boolean;\n}\n\n/**\n * Interface for format-specific schema generators.\n */\nexport interface SchemaGenerator {\n /** Format this generator produces */\n format: SchemaFormat;\n\n /**\n * Generate code for a complete model/schema.\n */\n generateModel(\n schema: OpenApiSchema,\n name: string,\n options?: { description?: string }\n ): GeneratedCode;\n\n /**\n * Generate code for a single field.\n */\n generateField(\n schema: OpenApiSchema,\n fieldName: string,\n required: boolean\n ): GeneratedFieldCode;\n\n /**\n * Get import statements needed for this generator's output.\n */\n getBaseImports(): string[];\n}\n\n/**\n * Factory function to create a format-specific schema generator.\n *\n * @param format - The target output format\n * @param config - ContractSpec configuration\n * @returns A schema generator for the specified format\n *\n * @example\n * ```typescript\n * const generator = createSchemaGenerator('zod', config);\n * const model = generator.generateModel(openApiSchema, 'User');\n * ```\n */\nexport function createSchemaGenerator(\n format: SchemaFormat,\n config?: ContractsrcConfig\n): SchemaGenerator {\n switch (format) {\n case 'zod':\n return new ZodSchemaGenerator(config);\n case 'json-schema':\n return new JsonSchemaGenerator(config);\n case 'graphql':\n return new GraphQLSchemaGenerator(config);\n case 'contractspec':\n default:\n return new ContractSpecSchemaGenerator(config);\n }\n}\n\n// ============================================================================\n// ContractSpec Generator (default)\n// ============================================================================\n\nexport class ContractSpecSchemaGenerator implements SchemaGenerator {\n format: SchemaFormat = 'contractspec';\n config?: ContractsrcConfig;\n\n constructor(config?: ContractsrcConfig) {\n this.config = config;\n }\n\n generateModel(schema: OpenApiSchema, name: string): GeneratedCode {\n const model = this.generateContractSpecSchema(schema, name);\n\n // Calculate imports for dependencies\n const dependencyImports = this.config\n ? generateImports(model.fields, this.config, false)\n .split('\\n')\n .filter(Boolean)\n : [];\n\n // Add nested model imports?\n // Nested models are inlined in code, but might have refs.\n // generateImports handles fields recursively? No, generateImports iterates top-level fields.\n // But nested models are hoisted, so their fields are not in 'fields' array of parent directly?\n // Wait, GeneratedModel.fields contains 'nestedModel'.\n // generateImports should traverse nested models?\n // The original generateImports does NOT traverse nested models.\n // However, the original code worked, so maybe simple traversal is enough.\n\n return {\n code: model.code,\n fileName: toKebabCase(name) + '.ts',\n imports: [...this.getBaseImports(), ...dependencyImports],\n name: model.name,\n };\n }\n\n generateField(\n schema: OpenApiSchema,\n fieldName: string,\n required: boolean\n ): GeneratedFieldCode {\n const field = this.convertField(schema, fieldName, required);\n\n return {\n code: field.scalarType\n ? `${field.scalarType}()`\n : 'ScalarTypeEnum.String_unsecure()',\n typeRef: field.type.type,\n isOptional: field.type.optional,\n isArray: field.type.array,\n };\n }\n\n getBaseImports(): string[] {\n return [\n \"import { defineSchemaModel, ScalarTypeEnum, EnumType } from '@contractspec/lib.schema';\",\n ];\n }\n\n // Ported logic\n private generateContractSpecSchema(\n schema: OpenApiSchema,\n modelName: string,\n indent = 0\n ): GeneratedModel {\n const spaces = ' '.repeat(indent);\n const fields: SchemaField[] = [];\n\n if (isReference(schema)) {\n return {\n name: toPascalCase(typeNameFromRef(schema.$ref)),\n fields: [],\n code: `// Reference to ${schema.$ref}`,\n };\n }\n\n const schemaObj = schema as Record<string, unknown>;\n const description = schemaObj['description'] as string | undefined;\n const properties = schemaObj['properties'] as\n | Record<string, OpenApiSchema>\n | undefined;\n const required = (schemaObj['required'] as string[]) ?? [];\n\n // Handle enum types\n const enumValues = schemaObj['enum'] as unknown[] | undefined;\n if (enumValues && enumValues.length > 0) {\n const safeModelName = toPascalCase(toValidIdentifier(modelName));\n const enumCode = [\n `${spaces}/**`,\n `${spaces} * Enum type: ${safeModelName}`,\n description ? `${spaces} * ${description}` : null,\n `${spaces} */`,\n `${spaces}export const ${safeModelName} = new EnumType('${safeModelName}', [${enumValues.map((v) => `'${String(v)}'`).join(', ')}]);`,\n ]\n .filter((line) => line !== null)\n .join('\\n');\n\n return {\n name: safeModelName,\n description,\n fields: [],\n code: enumCode,\n };\n }\n\n // Handle primitive types alias\n const schemaType = schemaObj['type'] as string | undefined;\n if (schemaType && !properties && !enumValues) {\n const safeModelName = toPascalCase(toValidIdentifier(modelName));\n const format = schemaObj['format'] as string | undefined;\n const scalarKey = format ? `${schemaType}:${format}` : schemaType;\n const scalarType =\n JSON_SCHEMA_TO_SCALAR[scalarKey] ?? JSON_SCHEMA_TO_SCALAR[schemaType];\n\n if (scalarType) {\n const aliasCode = [\n `${spaces}/**`,\n `${spaces} * Type alias: ${safeModelName}`,\n description ? `${spaces} * ${description}` : null,\n `${spaces} * Underlying type: ${scalarType}`,\n `${spaces} */`,\n `${spaces}export const ${safeModelName} = defineSchemaModel({`,\n `${spaces} name: '${safeModelName}',`,\n description\n ? `${spaces} description: ${JSON.stringify(description)},`\n : null,\n `${spaces} fields: {`,\n `${spaces} value: {`,\n `${spaces} type: ${scalarType}(),`,\n `${spaces} isOptional: false,`,\n `${spaces} },`,\n `${spaces} },`,\n `${spaces}});`,\n ]\n .filter((line) => line !== null)\n .join('\\n');\n\n return {\n name: safeModelName,\n description,\n fields: [],\n code: aliasCode,\n };\n }\n }\n\n // Handle additionalProperties (dictionary)\n const additionalProperties = schemaObj['additionalProperties'];\n if (additionalProperties && !properties) {\n const safeModelName = toPascalCase(toValidIdentifier(modelName));\n\n const dictCode = [\n `${spaces}/**`,\n `${spaces} * Dictionary/Record type: ${safeModelName}`,\n description ? `${spaces} * ${description}` : null,\n `${spaces} * Use as: Record<string, unknown> - access via record[key]`,\n `${spaces} */`,\n `${spaces}export const ${safeModelName} = ScalarTypeEnum.JSONObject();`,\n ]\n .filter((line) => line !== null)\n .join('\\n');\n\n return {\n name: safeModelName,\n description,\n fields: [],\n code: dictCode,\n };\n }\n\n if (!properties) {\n const safeModelName = toPascalCase(toValidIdentifier(modelName));\n const emptyModelCode = [\n `${spaces}export const ${safeModelName} = defineSchemaModel({`,\n `${spaces} name: '${safeModelName}',`,\n description\n ? `${spaces} description: ${JSON.stringify(description)},`\n : null,\n `${spaces} fields: {},`,\n `${spaces}});`,\n ]\n .filter((line) => line !== null)\n .join('\\n');\n\n return {\n name: safeModelName,\n description,\n fields: [],\n code: emptyModelCode,\n };\n }\n\n // Generate fields\n const safeModelName = toPascalCase(toValidIdentifier(modelName));\n for (const [propName, propSchema] of Object.entries(properties)) {\n const isRequired = required.includes(propName);\n fields.push(\n this.convertField(propSchema, propName, isRequired, safeModelName)\n );\n }\n\n // Generate code\n const lines: string[] = [];\n\n // Prepend nested models\n for (const field of fields) {\n if (field.nestedModel) {\n lines.push(field.nestedModel.code);\n lines.push('');\n }\n }\n\n // Model definition\n lines.push(`${spaces}export const ${safeModelName} = defineSchemaModel({`);\n lines.push(`${spaces} name: '${safeModelName}',`);\n if (description) {\n lines.push(`${spaces} description: ${JSON.stringify(description)},`);\n }\n lines.push(`${spaces} fields: {`);\n\n for (const field of fields) {\n const fieldLines = this.generateFieldCodeHelper(field, indent + 2);\n lines.push(fieldLines);\n }\n\n lines.push(`${spaces} },`);\n lines.push(`${spaces}});`);\n\n return {\n name: safeModelName,\n description,\n fields,\n code: lines.join('\\n'),\n imports: [],\n };\n }\n\n private convertField(\n schema: OpenApiSchema,\n fieldName: string,\n required: boolean,\n parentName?: string\n ): SchemaField {\n const type = jsonSchemaToType(schema, fieldName);\n const scalarType = getScalarType(schema);\n\n let enumValues: string[] | undefined;\n let nestedModel: GeneratedModel | undefined;\n\n if (!isReference(schema)) {\n const schemaObj = schema as Record<string, unknown>;\n const enumArr = schemaObj['enum'] as unknown[] | undefined;\n if (enumArr) {\n enumValues = enumArr.map(String);\n }\n\n // Handle nested objects\n if (\n schemaObj['type'] === 'object' &&\n !scalarType &&\n schemaObj['properties'] &&\n !enumValues\n ) {\n const nestedName =\n (parentName ? parentName : '') + toPascalCase(fieldName);\n nestedModel = this.generateContractSpecSchema(schema, nestedName);\n\n type.type = nestedModel.name;\n type.isReference = true;\n }\n }\n\n return {\n name: fieldName,\n type: {\n ...type,\n optional: !required || type.optional,\n description: !isReference(schema)\n ? ((schema as Record<string, unknown>)['description'] as string)\n : undefined,\n },\n scalarType,\n enumValues,\n nestedModel,\n };\n }\n\n private generateFieldCodeHelper(field: SchemaField, indent: number): string {\n const spaces = ' '.repeat(indent);\n const lines: string[] = [];\n\n const isIdentifier = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(field.name);\n const safeKey = isIdentifier ? field.name : `'${field.name}'`;\n lines.push(`${spaces}${safeKey}: {`);\n\n if (field.enumValues) {\n const enumName = toPascalCase(field.name) + 'Enum';\n lines.push(\n `${spaces} type: new EnumType('${enumName}', [${field.enumValues.map((v) => `'${v}'`).join(', ')}]),`\n );\n } else if (field.scalarType) {\n lines.push(`${spaces} type: ${field.scalarType}(),`);\n } else if (field.nestedModel) {\n lines.push(`${spaces} type: ${field.nestedModel.name},`);\n } else if (field.type.primitive) {\n const fallbackScalar =\n field.type.type === 'number'\n ? 'ScalarTypeEnum.Float_unsecure'\n : field.type.type === 'boolean'\n ? 'ScalarTypeEnum.Boolean_unsecure'\n : 'ScalarTypeEnum.String_unsecure';\n lines.push(`${spaces} type: ${fallbackScalar}(),`);\n } else if (field.type.isReference) {\n lines.push(`${spaces} type: ${field.type.type},`);\n } else {\n lines.push(\n `${spaces} type: ScalarTypeEnum.JSONObject(), // TODO: Define nested model for ${field.type.type}`\n );\n }\n\n lines.push(`${spaces} isOptional: ${field.type.optional},`);\n\n if (field.type.array) {\n lines.push(`${spaces} isArray: true,`);\n }\n\n lines.push(`${spaces}},`);\n\n return lines.join('\\n');\n }\n}\n\n// ============================================================================\n// Zod Generator\n// ============================================================================\n\nexport class ZodSchemaGenerator implements SchemaGenerator {\n format: SchemaFormat = 'zod';\n config?: ContractsrcConfig;\n\n constructor(config?: ContractsrcConfig) {\n this.config = config;\n }\n\n generateModel(\n schema: OpenApiSchema,\n name: string,\n options?: { description?: string }\n ): GeneratedCode {\n const schemaObj = schema as Record<string, unknown>;\n const properties = schemaObj['properties'] as\n | Record<string, OpenApiSchema>\n | undefined;\n const _required = (schemaObj['required'] as string[]) ?? [];\n const description = options?.description ?? schemaObj['description'];\n\n const lines: string[] = [];\n\n if (description) {\n lines.push(`/**`);\n lines.push(` * ${description}`);\n lines.push(` */`);\n }\n\n // Generate Zod Schema\n const schemaName = `${name}Schema`;\n let schemaCode;\n\n if (properties) {\n schemaCode = this.generateZodObject(schemaObj);\n } else {\n schemaCode = 'z.object({})';\n }\n\n lines.push(`export const ${schemaName} = ${schemaCode};`);\n lines.push(``);\n\n // Generate ZodSchemaType wrapper for ContractSpec compatibility\n lines.push(\n `export const ${name} = new ZodSchemaType(${schemaName}, { name: '${name}', description: ${JSON.stringify(description)} });`\n );\n lines.push(``);\n\n // Generate Type\n lines.push(`export type ${name} = z.infer<typeof ${schemaName}>;`);\n\n // Dependencies?\n // Zod generator doesn't currently resolve references recursively or import them\n // This is a limitation: if prop is ref, use z.lazy(() => RefSchema) or similar?\n // For now assuming shallow/primitive or using z.unknown/record for complex stuff\n // Or if Contracts-transformers logic for references is ported.\n // Simplifying: Zod generator relies on primitive mapping for now.\n\n return {\n code: lines.join('\\n'),\n fileName: toKebabCase(name) + '.ts',\n imports: this.getBaseImports(), // Todo: Add dependency imports if references used\n name: name,\n };\n }\n\n generateField(\n schema: OpenApiSchema,\n _fieldName: string,\n required: boolean\n ): GeneratedFieldCode {\n const schemaObj = schema as Record<string, unknown>;\n const type = schemaObj['type'] as string | undefined;\n const format = schemaObj['format'] as string | undefined;\n const nullable = schemaObj['nullable'] as boolean | undefined;\n\n let zodType: string;\n\n if (type === 'object' && schemaObj['properties']) {\n zodType = this.generateZodObject(schemaObj);\n } else {\n zodType = this.mapTypeToZod(type, format);\n\n if (schemaObj['enum']) {\n const enumValues = schemaObj['enum'] as string[];\n zodType = `z.enum([${enumValues.map((v) => `'${v}'`).join(', ')}])`;\n }\n\n if (type === 'array') {\n const items = schemaObj['items'] as OpenApiSchema | undefined;\n if (items) {\n const itemField = this.generateField(items, 'item', true);\n zodType = `z.array(${itemField.code.replace('.optional()', '')})`;\n } else {\n zodType = 'z.array(z.unknown())';\n }\n }\n }\n\n // Add constraints\n if (type === 'string') {\n if (schemaObj['minLength'] !== undefined)\n zodType += `.min(${schemaObj['minLength']})`;\n if (schemaObj['maxLength'] !== undefined)\n zodType += `.max(${schemaObj['maxLength']})`;\n if (schemaObj['pattern'] !== undefined)\n zodType += `.regex(/${schemaObj['pattern']}/)`;\n } else if (type === 'integer' || type === 'number') {\n if (schemaObj['minimum'] !== undefined) {\n zodType +=\n schemaObj['exclusiveMinimum'] === true\n ? `.gt(${schemaObj['minimum']})`\n : `.min(${schemaObj['minimum']})`;\n } else if (typeof schemaObj['exclusiveMinimum'] === 'number') {\n zodType += `.gt(${schemaObj['exclusiveMinimum']})`;\n }\n\n if (schemaObj['maximum'] !== undefined) {\n zodType +=\n schemaObj['exclusiveMaximum'] === true\n ? `.lt(${schemaObj['maximum']})`\n : `.max(${schemaObj['maximum']})`;\n } else if (typeof schemaObj['exclusiveMaximum'] === 'number') {\n zodType += `.lt(${schemaObj['exclusiveMaximum']})`;\n }\n\n if (schemaObj['multipleOf'] !== undefined) {\n zodType += `.step(${schemaObj['multipleOf']})`;\n }\n } else if (type === 'array') {\n if (schemaObj['minItems'] !== undefined)\n zodType += `.min(${schemaObj['minItems']})`;\n if (schemaObj['maxItems'] !== undefined)\n zodType += `.max(${schemaObj['maxItems']})`;\n }\n\n if (schemaObj['default'] !== undefined) {\n zodType += `.default(${JSON.stringify(schemaObj['default'])})`;\n }\n\n if (!required || nullable) {\n zodType = `${zodType}.optional()`;\n }\n\n return {\n code: zodType,\n typeRef: type ?? 'unknown',\n isOptional: !required || Boolean(nullable),\n isArray: type === 'array',\n };\n }\n\n getBaseImports(): string[] {\n return [\n \"import * as z from 'zod';\",\n \"import { ZodSchemaType } from '@contractspec/lib.schema';\",\n ];\n }\n\n private generateZodObject(schemaObj: Record<string, unknown>): string {\n const required = (schemaObj['required'] as string[]) ?? [];\n const properties = schemaObj['properties'] as Record<string, OpenApiSchema>;\n const lines: string[] = ['z.object({'];\n\n for (const [propName, propSchema] of Object.entries(properties)) {\n const isRequired = required.includes(propName);\n const field = this.generateField(propSchema, propName, isRequired);\n // If name is not a valid identifier, quote it\n const safeName = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(propName)\n ? propName\n : `'${propName}'`;\n\n lines.push(` ${safeName}: ${field.code},`);\n }\n\n lines.push('})');\n return lines.join('\\n');\n }\n\n private mapTypeToZod(type?: string, format?: string): string {\n if (format === 'date-time') return 'z.string().datetime()';\n if (format === 'date') return 'z.string().date()';\n if (format === 'email') return 'z.string().email()';\n if (format === 'uri' || format === 'url') return 'z.string().url()';\n if (format === 'uuid') return 'z.string().uuid()';\n\n switch (type) {\n case 'string':\n return 'z.string()';\n case 'integer':\n return 'z.number().int()';\n case 'number':\n return 'z.number()';\n case 'boolean':\n return 'z.boolean()';\n case 'object':\n return 'z.record(z.string(), z.unknown())';\n case 'null':\n return 'z.null()';\n default:\n return 'z.unknown()';\n }\n }\n}\n\n// ============================================================================\n// JSON Schema Generator\n// ============================================================================\n\nexport class JsonSchemaGenerator implements SchemaGenerator {\n format: SchemaFormat = 'json-schema';\n config?: ContractsrcConfig;\n\n constructor(config?: ContractsrcConfig) {\n this.config = config;\n }\n\n generateModel(\n schema: OpenApiSchema,\n name: string,\n options?: { description?: string }\n ): GeneratedCode {\n const schemaObj = schema as Record<string, unknown>;\n const description = options?.description ?? schemaObj['description'];\n\n // Create a clean JSON Schema object\n const jsonSchema: Record<string, unknown> = {\n $schema: 'https://json-schema.org/draft/2020-12/schema',\n title: name,\n ...schemaObj,\n };\n\n if (description) {\n jsonSchema['description'] = description;\n }\n\n const lines: string[] = [];\n lines.push(`/**`);\n lines.push(` * JSON Schema: ${name}`);\n if (description) {\n lines.push(` * ${description}`);\n }\n lines.push(` */`);\n\n const schemaName = `${name}Schema`;\n lines.push(\n `export const ${schemaName} = ${JSON.stringify(jsonSchema, null, 2)} as const;`\n );\n lines.push(``);\n\n // Generate wrapper\n lines.push(`export const ${name} = new JsonSchemaType(${schemaName});`);\n lines.push(``);\n\n // Type derived from JsonSchemaType or similar?\n // Actually JsonSchemaType doesn't strictly infer TS type from JSON schema at compile time easily without other tools.\n // For now, export type as unknown or rely on library.\n lines.push(\n `export type ${name} = unknown; // JSON Schema type inference not fully supported`\n );\n\n return {\n code: lines.join('\\n'),\n fileName: toKebabCase(name) + '.ts',\n imports: this.getBaseImports(), // dependency imports?\n name: name,\n };\n }\n\n generateField(\n schema: OpenApiSchema,\n _fieldName: string,\n required: boolean\n ): GeneratedFieldCode {\n const schemaObj = schema as Record<string, unknown>;\n const type = schemaObj['type'] as string | undefined;\n const nullable = schemaObj['nullable'] as boolean | undefined;\n\n return {\n code: JSON.stringify(schemaObj),\n typeRef: type ?? 'unknown',\n isOptional: !required || Boolean(nullable),\n isArray: type === 'array',\n };\n }\n\n getBaseImports(): string[] {\n return [\"import { JsonSchemaType } from '@contractspec/lib.schema';\"];\n }\n}\n\n// ============================================================================\n// GraphQL Generator\n// ============================================================================\n\nexport class GraphQLSchemaGenerator implements SchemaGenerator {\n format: SchemaFormat = 'graphql';\n config?: ContractsrcConfig;\n\n constructor(config?: ContractsrcConfig) {\n this.config = config;\n }\n\n generateModel(\n schema: OpenApiSchema,\n name: string,\n options?: { description?: string }\n ): GeneratedCode {\n const schemaObj = schema as Record<string, unknown>;\n const properties = schemaObj['properties'] as\n | Record<string, OpenApiSchema>\n | undefined;\n const required = (schemaObj['required'] as string[]) ?? [];\n const description = options?.description ?? schemaObj['description'];\n\n const lines: string[] = [];\n\n if (description) {\n lines.push(`\"\"\"${description}\"\"\"`);\n }\n\n lines.push(`type ${name} {`);\n\n if (properties) {\n for (const [propName, propSchema] of Object.entries(properties)) {\n const isRequired = required.includes(propName);\n const field = this.generateField(propSchema, propName, isRequired);\n const nullMarker = isRequired ? '!' : '';\n lines.push(` ${propName}: ${field.typeRef}${nullMarker}`);\n }\n }\n\n lines.push(`}`);\n\n // Also generate SDL as a string constant\n const sdl = lines.join('\\n');\n const tsLines: string[] = [];\n tsLines.push(`/**`);\n tsLines.push(` * GraphQL type definition: ${name}`);\n tsLines.push(` */`);\n tsLines.push(`export const ${name}TypeDef = \\`${sdl}\\`;`);\n tsLines.push(``);\n tsLines.push(\n `export const ${name} = new GraphQLSchemaType(${name}TypeDef, '${name}');`\n );\n\n return {\n code: tsLines.join('\\n'),\n fileName: toKebabCase(name) + '.ts',\n imports: this.getBaseImports(),\n name: name,\n };\n }\n\n generateField(\n schema: OpenApiSchema,\n _fieldName: string,\n required: boolean\n ): GeneratedFieldCode {\n const schemaObj = schema as Record<string, unknown>;\n const type = schemaObj['type'] as string | undefined;\n const format = schemaObj['format'] as string | undefined;\n const nullable = schemaObj['nullable'] as boolean | undefined;\n\n const gqlType = this.mapTypeToGraphQL(type, format);\n\n return {\n code: gqlType,\n typeRef: gqlType,\n isOptional: !required || Boolean(nullable),\n isArray: type === 'array',\n };\n }\n\n getBaseImports(): string[] {\n return [\"import { GraphQLSchemaType } from '@contractspec/lib.schema';\"];\n }\n\n private mapTypeToGraphQL(type?: string, format?: string): string {\n if (format === 'date-time') return 'DateTime';\n if (format === 'date') return 'Date';\n if (format === 'email') return 'String';\n if (format === 'uri' || format === 'url') return 'String';\n if (format === 'uuid') return 'ID';\n\n switch (type) {\n case 'string':\n return 'String';\n case 'integer':\n return 'Int';\n case 'number':\n return 'Float';\n case 'boolean':\n return 'Boolean';\n case 'object':\n return 'JSON';\n case 'array':\n return '[JSON]';\n default:\n return 'JSON';\n }\n }\n}\n"],"mappings":"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"}
|