This is a tool that converts JSON schemas into TypeScript utility classes for use in Deno.
It currently only supports a subset of JSON schema features. I'll eventually expand it to support more features.
📝 This is an experimental project that I made for my own use to compress JSON schemas and data for processing through large language models and to validate the output received and save on token cost. There are most likely bugs. Any feedback is much appreciated!
- Automatic Type Generation: Typescript interfaces for the compressed and uncompressed versions of your data.
- Compression & Decompression: Compress and decompress your data.
- Validation: Built-in data validation using Ajv ensures your data adheres to the schema.
- Reusability: Once generated, the utility classes can be used in other Deno projects.
- Ensure Deno is installed.
- Clone this repository.
- Create a folder in the schemas directory with the same name as the $id property of your schema.
- Add your schema to the folder. It must be called schema.json.
- Run:
This will then generate/regenerate all the utility classes for your schemas.
{ "$id": "PizzaOrderItem", "type": "object", "description": "A pizza order item.", "properties": { "size": { "type": "string", "description": "The size of the pizza.", "enum": ["small", "medium", "large"], "default": "medium" }, "sauce": { "type": "string", "description": "The type of sauce on the pizza.", "enum": ["tomato", "white", "bbq"], "default": "tomato" }, "toppings": { "type": "array", "description": "The list of toppings on the pizza.", "items": { "type": "string" }, "default": [] }, "quantity": { "type": "number", "description": "The quantity of the pizza.", "default": 1, "minimum": 1 }, "instructions": { "type": "string", "description": "Special instructions for the pizza.", "default": "" } }, "required": [ "size", "sauce", "toppings", "quantity", "instructions" ] }
/** * AUTO-GENERATED FILE - DO NOT EDIT. * This file was automatically generated. * Any changes made to this file will be overwritten. */ import Ajv from "https://esm.sh/ajv@8.12.0"; import addFormats from "https://esm.sh/ajv-formats@2.1.1"; export interface PizzaOrderItem { size: "small" | "medium" | "large"; sauce: "tomato" | "white" | "bbq"; toppings: string[]; quantity: number; instructions: string; } export interface PizzaOrderItemCompressed { 1: 0 | 1 | 2; 2: 0 | 1 | 2; 3: string[]; 4: number; 5: string; } export class PizzaOrderItemUtil { private static ajv = (() => { const ajv = new Ajv({ allErrors: true, allowUnionTypes: true }); addFormats(ajv); return ajv; })(); static readonly SIZE_ENUM = ["small", "medium", "large"] as const; static readonly SAUCE_ENUM = ["tomato", "white", "bbq"] as const; static readonly schema = Object.freeze( { "$id": "PizzaOrderItem", "type": "object", "description": "A pizza order item.", "properties": { "size": { "type": "string", "description": "The size of the pizza.", "enum": [ "small", "medium", "large", ], "default": "medium", }, "sauce": { "type": "string", "description": "The type of sauce on the pizza.", "enum": [ "tomato", "white", "bbq", ], "default": "tomato", }, "toppings": { "type": "array", "description": "The list of toppings on the pizza.", "items": { "type": "string", }, "default": [], }, "quantity": { "type": "number", "description": "The quantity of the pizza.", "default": 1, "minimum": 1, }, "instructions": { "type": "string", "description": "Special instructions for the pizza.", "default": "", }, }, "required": [ "size", "sauce", "toppings", "quantity", "instructions", ], } as const, ); static readonly compressedSchema = Object.freeze( { "$id": "PizzaOrderItemCompressed", "type": "object", "description": "A pizza order item.", "properties": { "1": { "type": "number", "description": "The size of the pizza. Enum mapping: 0 = small, 1 = medium, 2 = large.", "enum": [ 0, 1, 2, ], "default": 1, }, "2": { "type": "number", "description": "The type of sauce on the pizza. Enum mapping: 0 = tomato, 1 = white, 2 = bbq.", "enum": [ 0, 1, 2, ], "default": 0, }, "3": { "type": "array", "description": "The list of toppings on the pizza.", "items": { "type": "string", }, "default": [], }, "4": { "type": "number", "description": "The quantity of the pizza.", "default": 1, "minimum": 1, }, "5": { "type": "string", "description": "Special instructions for the pizza.", "default": "", }, }, "required": [ "1", "2", "3", "4", "5", ], "additionalProperties": false, } as const, ); static readonly schemaString = '{"$id":"PizzaOrderItem","type":"object","description":"A pizza order item.","properties":{"size":{"type":"string","description":"The size of the pizza.","enum":["small","medium","large"],"default":"medium"},"sauce":{"type":"string","description":"The type of sauce on the pizza.","enum":["tomato","white","bbq"],"default":"tomato"},"toppings":{"type":"array","description":"The list of toppings on the pizza.","items":{"type":"string"},"default":[]},"quantity":{"type":"number","description":"The quantity of the pizza.","default":1,"minimum":1},"instructions":{"type":"string","description":"Special instructions for the pizza.","default":""}},"required":["size","sauce","toppings","quantity","instructions"]}' as const; static readonly compressedSchemaString = '{"$id":"PizzaOrderItemCompressed","type":"object","description":"A pizza order item.","properties":{"1":{"type":"number","description":"The size of the pizza. Enum mapping: 0 = small, 1 = medium, 2 = large.","enum":[0,1,2],"default":1},"2":{"type":"number","description":"The type of sauce on the pizza. Enum mapping: 0 = tomato, 1 = white, 2 = bbq.","enum":[0,1,2],"default":0},"3":{"type":"array","description":"The list of toppings on the pizza.","items":{"type":"string"},"default":[]},"4":{"type":"number","description":"The quantity of the pizza.","default":1,"minimum":1},"5":{"type":"string","description":"Special instructions for the pizza.","default":""}},"required":["1","2","3","4","5"],"additionalProperties":false}' as const; static validate = this.ajv.compile(this.schema); static validateCompressed = this.ajv.compile(this.compressedSchema); static decompress(compressedData: PizzaOrderItemCompressed): PizzaOrderItem { if (!this.validateCompressed(compressedData)) { throw new Error( "Validation failed: " + this.ajv.errorsText(this.validateCompressed.errors), ); } return { size: this.SIZE_ENUM[compressedData["1"]], sauce: this.SAUCE_ENUM[compressedData["2"]], toppings: compressedData["3"], quantity: compressedData["4"], instructions: compressedData["5"], }; } static compress(originalData: PizzaOrderItem): PizzaOrderItemCompressed { if (!this.validate(originalData)) { throw new Error( "Validation failed: " + this.ajv.errorsText(this.validate.errors), ); } return { "1": this.SIZE_ENUM.indexOf(originalData.size) as 0 | 1 | 2, "2": this.SAUCE_ENUM.indexOf(originalData.sauce) as 0 | 1 | 2, "3": originalData.toppings, "4": originalData.quantity, "5": originalData.instructions, }; } }
The PizzaOrderItemUtil
class serves as a utility in TypeScript for managing pizza orders in two formats: a standard representation and a compressed representation.
- The class imports Ajv, a popular JSON schema validator.
- Additionally, it imports
addFormats
to extend Ajv with additional format support.
- PizzaOrderItem: Describes the structure of a standard pizza order with attributes like
size
,sauce
,toppings
,quantity
, andinstructions
. - PizzaOrderItemCompressed: A compact representation of
PizzaOrderItem
. It optimizes space by using numerical keys and represents attributes likesize
andsauce
with numbers.
- Initializes the Ajv library with specific configurations for validation purposes.
SIZE_ENUM
andSAUCE_ENUM
: Enumerations that define the possible values for the size and sauce of the pizza.schema
andcompressedSchema
: JSON schemas that define the expected structure for the standard and compressed data formats.schemaString
andcompressedSchemaString
: Stringified representations of the above schemas.
- decompress: Converts a compressed pizza order into its standard format. Before decompressing, it ensures the compressed data is valid.
- compress: Converts a standard pizza order into its compressed format. It validates the original data before starting the compression.
validate
andvalidateCompressed
: Functions generated by Ajv to validate objects against their respective schemas, ensuring data integrity and consistency.
import { PizzaOrderItem, PizzaOrderItemCompressed, PizzaOrderItemUtil, } from "./schemas/PizzaOrderItem/PizzaOrderItem.ts"; // Creating an original PizzaOrderItem const originalOrder: PizzaOrderItem = { size: "large", sauce: "bbq", toppings: ["pepperoni", "mushrooms", "onions"], quantity: 2, instructions: "Extra crispy crust, please!", }; // Printing the original order console.log("Original Order:", originalOrder); // Compressing the order const compressedOrder: PizzaOrderItemCompressed = PizzaOrderItemUtil.compress( originalOrder, ); console.log("Compressed Order:", compressedOrder); // Decompressing the order back to its original form const decompressedOrder: PizzaOrderItem = PizzaOrderItemUtil.decompress( compressedOrder, ); console.log("Decompressed Order:", decompressedOrder); // Validation of the original order const isValidOriginal = PizzaOrderItemUtil.validate(originalOrder); console.log("Is Original Order Valid?", isValidOriginal ? "Yes" : "No"); // Validation of the compressed order const isValidCompressed = PizzaOrderItemUtil.validateCompressed( compressedOrder, ); console.log("Is Compressed Order Valid?", isValidCompressed ? "Yes" : "No"); // Example of a compressed order const predefinedCompressedOrder: PizzaOrderItemCompressed = { "1": 1, "2": 1, "3": ["olives", "spinach", "feta cheese"], "4": 1, "5": "Well done with extra cheese on top.", }; console.log("Compressed:", predefinedCompressedOrder); // Decompressing the predefined compressed order should output: // { // "size": "medium", // "sauce": "white", // "toppings": ["olives", "spinach", "feta cheese"], // "quantity": 1, // "instructions": "Well done with extra cheese on top." // } const decompressedPredefinedOrder: PizzaOrderItem = PizzaOrderItemUtil .decompress(predefinedCompressedOrder); console.log("Decompressed:", decompressedPredefinedOrder); // Get original JSON schema string const originalSchemaString = PizzaOrderItemUtil.schemaString; console.log("Original Schema:", originalSchemaString); // Get compressed JSON schema string const compressedSchemaString = PizzaOrderItemUtil.compressedSchemaString; console.log("Compressed Schema:", compressedSchemaString);
📝 Note: Your input schemas must validate against this meta JSON schema otherwise the tool will throw an error:
{ "$schema": "http://json-schema.org/draft-07/schema#", "$id": "MetaSchema", "description": "Meta-Schema for validating schemas", "type": "object", "properties": { "$id": { "type": "string" }, "$schema": { "type": "string" }, "type": { "type": "string", "enum": ["object"] }, "description": { "type": "string" }, "properties": { "type": "object", "patternProperties": { ".*": { "type": "object", "properties": { "type": { "type": "string", "enum": ["string", "number", "array"] }, "description": { "type": "string" }, "default": { "type": ["string", "number", "array"] }, "enum": { "type": "array", "items": { "type": ["string", "number"] } }, "items": { "type": "object", "properties": { "type": { "type": "string", "enum": ["string", "number"] } }, "required": ["type"] }, "minimum": { "type": "number" } }, "required": ["type", "description", "default"], "additionalProperties": false } } }, "required": { "type": "array", "items": { "type": "string" } } }, "required": ["$id", "type", "description", "properties", "required"], "additionalProperties": false }
Feel free to open issues or pull requests if you have suggestions or find any bugs. Any feedback is appreciated!
This project is licensed under the MIT License.
from Hacker News https://ift.tt/VOPUn4D
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.