UNPKG

@minecraft/creator-tools

Version:

Minecraft Creator Tools command line and libraries.

283 lines (282 loc) 13.1 kB
"use strict"; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const zod_1 = require("zod"); const Utilities_1 = __importDefault(require("../core/Utilities")); const Database_1 = __importDefault(require("../minecraft/Database")); const IField_1 = require("./IField"); const DataFormUtilities_1 = __importDefault(require("./DataFormUtilities")); class DataFormZod { static getZodSchema(formDefinition) { const cache = new WeakMap(); return DataFormZod.buildZodSchema(formDefinition, cache); } static buildZodSchema(formDefinition, cache) { if (cache.has(formDefinition)) { return cache.get(formDefinition); } const placeholder = zod_1.z.lazy(() => cache.get(formDefinition) ?? zod_1.z.unknown()); cache.set(formDefinition, placeholder); const fieldSchemas = {}; if (Array.isArray(formDefinition.fields)) { for (const field of formDefinition.fields) { if (!field || !field.id || !Utilities_1.default.isUsableAsObjectKey(field.id) || field.id === "__scalar" || field.id.indexOf("<") >= 0 || field.id.indexOf(">") >= 0) { continue; } fieldSchemas[field.id] = DataFormZod.getFieldSchema(field, cache); } } const baseObject = zod_1.z.object(fieldSchemas); const objectSchema = formDefinition.customField ? baseObject.catchall(DataFormZod.getFieldSchema(formDefinition.customField, cache, { skipOptionalWrap: true, })) : baseObject.passthrough(); let finalSchema = objectSchema; if (formDefinition.scalarField && !formDefinition.scalarFieldUpgradeName) { const scalarSchema = DataFormZod.getFieldSchema(formDefinition.scalarField, cache, { skipOptionalWrap: true, }); finalSchema = finalSchema.or(scalarSchema); } cache.set(formDefinition, finalSchema); return finalSchema; } static getFieldSchema(field, cache, options) { const variants = DataFormUtilities_1.default.getFieldAndAlternates(field); const schemas = []; for (const variant of variants) { const schema = DataFormZod.getSingleFieldSchema(variant, cache); if (schema) { schemas.push(schema); } } let combined = DataFormZod.combineSchemas(schemas); if (!options?.skipOptionalWrap) { const isRequired = variants.some((variant) => variant.isRequired); if (!isRequired) { combined = combined.optional(); } } return combined; } static combineSchemas(schemas) { if (!schemas.length) { return zod_1.z.unknown(); } let combined = schemas[0]; for (let i = 1; i < schemas.length; i++) { combined = combined.or(schemas[i]); } return combined; } static getSingleFieldSchema(field, cache) { switch (field.dataType) { case IField_1.FieldDataType.boolean: return zod_1.z.boolean(); case IField_1.FieldDataType.intBoolean: { const booleanNumber = DataFormZod.createNumberSchema(field, { integer: true }).min(0).max(1); return booleanNumber.or(zod_1.z.boolean()); } case IField_1.FieldDataType.int: case IField_1.FieldDataType.intEnum: case IField_1.FieldDataType.intValueLookup: { if (field.dataType === IField_1.FieldDataType.intEnum && field.choices && field.choices.length > 0) { const numericChoices = field.choices .map((choice) => choice.id) .filter((id) => typeof id === "number"); if (numericChoices.length > 0) { let literalSchema = zod_1.z.literal(numericChoices[0]); for (let i = 1; i < numericChoices.length; i++) { literalSchema = literalSchema.or(zod_1.z.literal(numericChoices[i])); } return literalSchema; } } return DataFormZod.createNumberSchema(field, { integer: true }); } case IField_1.FieldDataType.float: case IField_1.FieldDataType.number: case IField_1.FieldDataType.long: return DataFormZod.createNumberSchema(field); case IField_1.FieldDataType.percentRange: return DataFormZod.createRangeSchema(field, { clamp01: true }); case IField_1.FieldDataType.intRange: return DataFormZod.createRangeSchema(field, { integer: true }); case IField_1.FieldDataType.floatRange: return DataFormZod.createRangeSchema(field); case IField_1.FieldDataType.stringEnum: { if (field.choices && field.choices.length > 0) { const stringChoices = field.choices .map((choice) => choice.id) .filter((id) => typeof id === "string"); if (stringChoices.length > 0) { return zod_1.z.enum(stringChoices); } } return DataFormZod.createStringSchema(field); } case IField_1.FieldDataType.string: case IField_1.FieldDataType.stringLookup: case IField_1.FieldDataType.longFormString: case IField_1.FieldDataType.molang: case IField_1.FieldDataType.localizableString: return DataFormZod.createStringSchema(field); case IField_1.FieldDataType.uuid: return DataFormZod.createStringSchema(field).uuid(); case IField_1.FieldDataType.longFormStringArray: case IField_1.FieldDataType.stringArray: case IField_1.FieldDataType.checkboxListAsStringArray: case IField_1.FieldDataType.molangArray: return DataFormZod.createArraySchema(zod_1.z.string(), field); case IField_1.FieldDataType.twoDStringArray: return DataFormZod.createArraySchema(zod_1.z.array(zod_1.z.string()), field); case IField_1.FieldDataType.numberArray: return DataFormZod.createArraySchema(zod_1.z.number(), field); case IField_1.FieldDataType.point2: return DataFormZod.createVectorSchema(2, field); case IField_1.FieldDataType.point3: return DataFormZod.createVectorSchema(3, field); case IField_1.FieldDataType.intPoint3: case IField_1.FieldDataType.location: case IField_1.FieldDataType.locationOffset: return DataFormZod.createVectorSchema(3, field, { integer: field.dataType === IField_1.FieldDataType.intPoint3 }); case IField_1.FieldDataType.keyedStringCollection: return zod_1.z.record(zod_1.z.string()); case IField_1.FieldDataType.keyedBooleanCollection: return zod_1.z.record(zod_1.z.boolean()); case IField_1.FieldDataType.keyedStringArrayCollection: return zod_1.z.record(zod_1.z.array(zod_1.z.string())); case IField_1.FieldDataType.keyedNumberCollection: return zod_1.z.record(zod_1.z.number()); case IField_1.FieldDataType.keyedNumberArrayCollection: return zod_1.z.record(zod_1.z.array(zod_1.z.number())); case IField_1.FieldDataType.arrayOfKeyedStringCollection: return DataFormZod.createArraySchema(zod_1.z.record(zod_1.z.string()), field); case IField_1.FieldDataType.keyedKeyedStringArrayCollection: return zod_1.z.record(zod_1.z.record(zod_1.z.array(zod_1.z.string()))); case IField_1.FieldDataType.keyedObjectCollection: { const subSchema = DataFormZod.getSubFormSchema(field, cache) ?? zod_1.z.record(zod_1.z.unknown()); return zod_1.z.record(subSchema); } case IField_1.FieldDataType.objectArray: { const subSchema = DataFormZod.getSubFormSchema(field, cache) ?? zod_1.z.record(zod_1.z.unknown()); return DataFormZod.createArraySchema(subSchema, field); } case IField_1.FieldDataType.object: { return DataFormZod.getSubFormSchema(field, cache) ?? zod_1.z.record(zod_1.z.unknown()); } case IField_1.FieldDataType.minecraftFilter: case IField_1.FieldDataType.minecraftEventTrigger: return zod_1.z.record(zod_1.z.unknown()); case IField_1.FieldDataType.minecraftEventTriggerArray: return DataFormZod.createArraySchema(zod_1.z.record(zod_1.z.unknown()), field); case IField_1.FieldDataType.minecraftEventReference: return DataFormZod.createStringSchema(field); case IField_1.FieldDataType.version: { const tupleSchema = zod_1.z.tuple([zod_1.z.number().int(), zod_1.z.number().int(), zod_1.z.number().int()]); return zod_1.z.string().or(zod_1.z.number()).or(tupleSchema); } default: return zod_1.z.unknown(); } } static createNumberSchema(field, options) { let schema = options?.integer ? zod_1.z.number().int() : zod_1.z.number(); if (options?.clamp01) { schema = schema.min(0).max(1); } if (field.minValue !== undefined) { schema = schema.min(field.minValue); } if (field.maxValue !== undefined) { schema = schema.max(field.maxValue); } return schema; } static createStringSchema(field) { let schema = zod_1.z.string(); if (field.minLength !== undefined) { schema = schema.min(field.minLength); } if (field.maxLength !== undefined) { schema = schema.max(field.maxLength); } return schema; } static createArraySchema(elementType, field) { let schema = zod_1.z.array(elementType); if (field.fixedLength !== undefined) { schema = schema.length(field.fixedLength); } else { if (field.minLength !== undefined) { schema = schema.min(field.minLength); } if (field.maxLength !== undefined) { schema = schema.max(field.maxLength); } } return schema; } static createRangeSchema(field, options) { const numberSchema = DataFormZod.createNumberSchema(field, options); const tupleSchema = zod_1.z.tuple([numberSchema, numberSchema]); const objectSchema = zod_1.z.object({ min: numberSchema.optional(), max: numberSchema.optional(), }); return numberSchema.or(tupleSchema).or(objectSchema); } static createVectorSchema(dimension, field, options) { const numberFactory = () => DataFormZod.createNumberSchema(field, { integer: options?.integer }); if (dimension === 2) { const tupleSchema = zod_1.z.tuple([numberFactory(), numberFactory()]); const objectSchema = zod_1.z .object({ x: numberFactory(), y: numberFactory(), }) .passthrough(); const altObjectSchema = zod_1.z .object({ a: numberFactory(), b: numberFactory(), }) .passthrough(); return tupleSchema.or(objectSchema).or(altObjectSchema); } if (dimension === 3) { const tupleSchema = zod_1.z.tuple([numberFactory(), numberFactory(), numberFactory()]); const objectSchema = zod_1.z .object({ x: numberFactory(), y: numberFactory(), z: numberFactory(), }) .passthrough(); return tupleSchema.or(objectSchema); } return zod_1.z.array(numberFactory()).length(dimension); } static getSubFormSchema(field, cache) { let subForm = field.subForm; if (!subForm && field.subFormId) { subForm = Database_1.default.getFormByPath(field.subFormId); } if (!subForm) { return undefined; } return DataFormZod.buildZodSchema(subForm, cache); } } exports.default = DataFormZod;