diff --git a/src/json.ts b/src/json.ts new file mode 100644 index 0000000..4019b26 --- /dev/null +++ b/src/json.ts @@ -0,0 +1,53 @@ +export type ObjectType = { [key: string]: Schema }; +export type PrimitiveType = "null" | "boolean" | "number" | "string"; +export type Schema = PrimitiveType | ObjectType | Array; + +export function validate(json: any, schema: Schema): T { + if (typeof schema === "string") { + return validatePrimitive(json, schema) as T; + } + + if (Array.isArray(schema)) { + if (schema.length !== 1) { + throw new SyntaxError("Invalid schema: Array types must only contain one element"); + } + const type = schema[0]; + + if (!Array.isArray(json)) { + throw new TypeError(`Expected array, got ${typeof json} instead`); + } + + const a = []; + for (let e of json) { + a.push(validate(e, type)); + } + return a as T; + } + + const o: any = {}; + for (let prop in schema) { + if (schema.hasOwnProperty(prop)) { + if (!json.hasOwnProperty(prop)) { + throw new TypeError(`Property ${schema[prop]} is missing`); + } + o[prop] = validate(json[prop], schema[prop]) as any; + } + } + return o; +} + +function validatePrimitive(json: any, type: T): +PrimitiveToJSType { + if (typeof json === type) { + return json; + } else { + throw new TypeError(`Expected type ${type}, got ${typeof json} instead`); + } +} + +type PrimitiveToJSType = + T extends "null" ? null : + T extends "boolean" ? boolean : + T extends "number" ? number : + T extends "string" ? string : + never;