UNPKG

@omer-x/typesculptor

Version:

generates interpretable json objects to generate TypeScript types from JSON Schemas

128 lines (122 loc) 3.98 kB
// src/core/handleArrayType.ts function handleArrayType(schema) { if (schema.type !== "array") throw new Error("Schema type must be 'array'"); const dependencies = []; const itemBodies = []; for (const item of [schema.items].flat()) { const itemDefinition = generateTypeDefinition(item); dependencies.push(...itemDefinition.dependencies); itemBodies.push(itemDefinition.body); } if (schema.minItems && schema.maxItems && schema.minItems === schema.maxItems) { return { dependencies, body: `[${itemBodies.join(", ")}]` }; } if (itemBodies.length > 1) { return { dependencies, body: `(${itemBodies.join(", ")})[]` }; } return { dependencies, body: `${itemBodies.join(", ")}[]` }; } // src/utils/generateIndentation.ts function generateIndentation(count, size = 2) { if (count < 1 || size < 1) return ""; return Array(count * size).fill(" ").join(""); } // src/core/handleObjectType.ts function handleObjectType(schema, indentation) { if (schema.type !== "object") throw new Error("Schema type must be 'object'"); const dependencies = []; const propertyBodies = {}; const propertyDescriptions = {}; for (const [propertyName, property] of Object.entries(schema.properties ?? {})) { const propertyDefinition = generateTypeDefinition(property, indentation + 1); dependencies.push(...propertyDefinition.dependencies); propertyBodies[propertyName] = propertyDefinition.body; if (property.description) { propertyDescriptions[propertyName] = property.description; } } const isRequired = (propertyName) => (schema.required ?? []).includes(propertyName); const properties = Object.keys(schema.properties ?? {}).map((propertyName) => [ "/**", ` * ${propertyDescriptions[propertyName] ?? "missing-description"}`, " */", `${propertyName}${isRequired(propertyName) ? "" : "?"}: ${propertyBodies[propertyName]},` ].map((line) => generateIndentation(indentation + 1) + line).join("\n")); return { dependencies, body: ["{", properties.join("\n"), "}"].join("\n") }; } // src/core/handleStringType.ts function handleStringType(schema) { if (schema.type !== "string") throw new Error("Schema type must be 'string'"); if (schema.enum) { return { dependencies: [], body: schema.enum.map((item) => `"${item}"`).join(" | ") }; } return { dependencies: [], body: "string" }; } // src/core/handleUnionType.ts function handleUnionType(schemas) { const dependencies = []; const itemBodies = []; for (const item of schemas) { const itemDefinition = generateTypeDefinition(item); dependencies.push(...itemDefinition.dependencies); itemBodies.push(itemDefinition.body); } if (itemBodies.length > 1) { return { dependencies, body: `(${itemBodies.join(" | ")})` }; } return { dependencies, body: itemBodies.join(" | ") }; } // src/core/generateTypeDefinition.ts function generateTypeDefinition(schema, indentation = 0) { if ("$ref" in schema) { const [_, __, _category, componentName] = schema.$ref.split("/"); if (!componentName) throw new Error("Invalid $ref in schema"); return { dependencies: [componentName], body: componentName }; } if (schema.anyOf) return handleUnionType(schema.anyOf); if (schema.oneOf) return handleUnionType(schema.oneOf); switch (schema.type) { case "null": return { dependencies: [], body: "null" }; case "boolean": return { dependencies: [], body: "boolean" }; case "integer": case "number": return { dependencies: [], body: "number" }; case "string": return handleStringType(schema); case "object": return handleObjectType(schema, indentation); case "array": return handleArrayType(schema); default: return { dependencies: [], body: "unknown" }; } } export { generateTypeDefinition };