@hpx7/delta-pack
Version:
A TypeScript code generator and runtime for binary serialization based on schemas.
78 lines (77 loc) • 3.15 kB
JavaScript
import yaml from "yaml";
import { ArrayType, BooleanType, EnumType, FloatType, IntType, ObjectType, OptionalType, RecordType, ReferenceType, StringType, UIntType, UnionType, } from "./schema";
import { mapValues } from "./helpers";
export function parseSchemaYml(yamlContent) {
// the yaml schema is a mapping from type names to type definitions
const schema = yaml.parse(yamlContent);
// recursive function to parse a type definition
function parseType(value) {
if (Array.isArray(value)) {
// could be a union type or an enum type
const values = value;
// it's a union type if all values are references to other types in the schema
if (values.every((v) => v in schema)) {
return UnionType(values.map((v) => ReferenceType(v)));
}
// otherwise, it's an enum type
return EnumType(values);
}
if (typeof value === "object") {
// object type
const properties = {};
for (const [propKey, propValue] of Object.entries(value)) {
properties[propKey] = parseType(propValue);
}
return ObjectType(properties);
}
if (typeof value === "string") {
// map type, array type, optional type, reference type, or primitive type
if (value.includes(",")) {
// map type
const parts = value.split(",").map((s) => s.trim());
if (parts.length !== 2) {
throw new Error(`Map type must have exactly 2 types, got: ${value}`);
}
const [keyTypeStr, valueTypeStr] = parts;
const keyType = parseType(keyTypeStr);
const valueType = parseType(valueTypeStr);
return RecordType(keyType, valueType);
}
if (value.endsWith("[]")) {
// array type
const itemTypeStr = value.slice(0, -2);
const childType = parseType(itemTypeStr);
return ArrayType(childType);
}
if (value.endsWith("?")) {
// optional type
const itemTypeStr = value.slice(0, -1);
const childType = parseType(itemTypeStr);
return OptionalType(childType);
}
if (value in schema) {
// reference type
return ReferenceType(value);
}
// primitive type
if (value === "string") {
return StringType();
}
else if (value === "int") {
return IntType();
}
else if (value === "uint") {
return UIntType();
}
else if (value === "float") {
return FloatType();
}
else if (value === "boolean") {
return BooleanType();
}
}
throw new Error(`Unsupported type format: ${value}`);
}
// parse the type definitions
return mapValues(schema, (value) => parseType(value));
}