UNPKG

apiful

Version:
206 lines (200 loc) 5.85 kB
import { C as CODE_HEADER_DIRECTIVES } from '../shared/apiful.B_nvMJ_g.mjs'; async function jsonToTypeDefinition(data, options = {}) { const { compile } = await import('json-schema-to-typescript-lite').catch(() => { throw new Error('Missing dependency "json-schema-to-typescript-lite", please install it'); }); const resolvedOptions = resolveOptions(options); const schema = createJsonSchema(data, resolvedOptions); const output = await compile(schema, resolvedOptions.typeName); return ` ${CODE_HEADER_DIRECTIVES} ${output} `.trimStart(); } function createJsonSchema(data, options) { if (Array.isArray(data)) { if (data.length === 0) { return { type: "array" }; } const itemSchemas = data.map((item) => createJsonSchema(item, options)); return { type: "array", items: mergeSchemas(itemSchemas) }; } else if (typeof data === "object" && data !== null) { const properties = Object.fromEntries( Object.entries(data).map(([key, value]) => [ key, createJsonSchema(value, options) ]) ); return { type: "object", properties, required: options.strictProperties ? Object.keys(properties) : false, additionalProperties: Object.keys(data).length === 0 }; } else if (data == null) { return { type: "any" }; } else { return { type: typeof data }; } } function mergeSchemas(schemas, options) { if (schemas.length === 0) return {}; if (schemas.length === 1) return schemas[0]; const types = new Set(schemas.map((schema) => schema.type)); if (types.size !== 1) { return { anyOf: schemas.map((schema) => ({ ...schema, additionalProperties: schema.type === "object" ? schema.additionalProperties : void 0 })) }; } const type = schemas[0].type; if (type === "object") { const propertySchemas = /* @__PURE__ */ new Map(); const requiredProperties = /* @__PURE__ */ new Set(); for (const schema of schemas) { if (!schema.properties) continue; for (const [key, value] of Object.entries(schema.properties)) { if (!propertySchemas.has(key)) propertySchemas.set(key, []); propertySchemas.get(key).push(value); } if (Array.isArray(schema.required)) { for (const key of schema.required) requiredProperties.add(key); } } return { type: "object", properties: Object.fromEntries( Array.from(propertySchemas.entries()).map(([key, propertySchemas2]) => [ key, mergeSchemas(propertySchemas2) ]) ), required: requiredProperties.size > 0 ? Array.from(requiredProperties) : void 0, additionalProperties: propertySchemas.size === 0 }; } else if (type === "array") { const itemSchemas = schemas.map((schema) => schema.items).filter((items) => Boolean(items)); return { type: "array", items: mergeSchemas(itemSchemas) }; } else { return schemas[0]; } } function resolveOptions(options) { return { typeName: options.typeName || "Root", strictProperties: options.strictProperties ?? false }; } const validatorSymbol = Symbol.for("apiful.validator"); class TypeValidationError extends Error { value; cause; constructor({ value, cause }) { super( `Type validation failed with value: ${JSON.stringify(value)} Error message: ${getErrorMessage(cause)}` ); this.value = value; this.cause = cause; } } function validator(validate) { return { [validatorSymbol]: true, validate }; } function validateTypes({ value, schema: inputSchema }) { const result = safeValidateTypes({ value, schema: inputSchema }); if (!result.success) { throw new TypeValidationError({ value, cause: result.error }); } return result.value; } function safeValidateTypes({ value, schema }) { try { if (schema.validate == null) { return { success: true, value }; } const result = schema.validate(value); if (result.success) { return result; } return { success: false, error: new TypeValidationError({ value, cause: result.error }) }; } catch (error) { return { success: false, error: new TypeValidationError({ value, cause: error }) }; } } function isValidator(value) { return typeof value === "object" && value !== null && validatorSymbol in value && value[validatorSymbol] === true && "validate" in value; } function getErrorMessage(error) { if (error == null) { return "unknown error"; } if (typeof error === "string") { return error; } if (error instanceof Error) { return error.message; } return JSON.stringify(error); } const schemaSymbol = Symbol.for("apiful.schema"); function jsonSchema(jsonSchema2, { validate } = {}) { return { [schemaSymbol]: true, _type: void 0, // Should never be used directly [validatorSymbol]: true, jsonSchema: jsonSchema2, validate }; } function isSchema(value) { return typeof value === "object" && value !== null && schemaSymbol in value && value[schemaSymbol] === true && "jsonSchema" in value && "validate" in value; } function base64ToUint8Array(base64String) { const base64Url = base64String.replaceAll("-", "+").replaceAll("_", "/"); const latin1String = globalThis.atob(base64Url); return Uint8Array.from(latin1String, (byte) => byte.charCodeAt(0)); } function uint8ArrayToBase64(array) { let latin1String = ""; for (const byte of array) { latin1String += String.fromCharCode(byte); } return globalThis.btoa(latin1String); } export { TypeValidationError, base64ToUint8Array, isSchema, isValidator, jsonSchema, jsonToTypeDefinition, safeValidateTypes, uint8ArrayToBase64, validateTypes, validator, validatorSymbol };