UNPKG

@minecraft/creator-tools

Version:

Minecraft Creator Tools command line and libraries.

130 lines (129 loc) 6.72 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 }); exports.FormSchemaItemInfoGeneratorTest = void 0; const ProjectInfoItem_1 = __importDefault(require("./ProjectInfoItem")); const CreatorToolsHost_1 = __importDefault(require("../app/CreatorToolsHost")); const axios_1 = __importDefault(require("axios")); const Utilities_1 = __importDefault(require("../core/Utilities")); const Database_1 = __importDefault(require("../minecraft/Database")); const IInfoItemData_1 = require("./IInfoItemData"); const DataFormValidator_1 = __importDefault(require("../dataform/DataFormValidator")); const StorageUtilities_1 = __importDefault(require("../storage/StorageUtilities")); const ProjectItemUtilities_1 = __importDefault(require("../app/ProjectItemUtilities")); const IProjectItemData_1 = require("../app/IProjectItemData"); var FormSchemaItemInfoGeneratorTest; (function (FormSchemaItemInfoGeneratorTest) { FormSchemaItemInfoGeneratorTest[FormSchemaItemInfoGeneratorTest["couldNotParseJson"] = 401] = "couldNotParseJson"; FormSchemaItemInfoGeneratorTest[FormSchemaItemInfoGeneratorTest["couldNotFindForm"] = 402] = "couldNotFindForm"; })(FormSchemaItemInfoGeneratorTest || (exports.FormSchemaItemInfoGeneratorTest = FormSchemaItemInfoGeneratorTest = {})); /** * Validates JSON files against Minecraft documentation-based form schemas. * * @see {@link ../../public/data/forms/mctoolsval/jsonf.form.json} for topic definitions */ class FormSchemaItemInfoGenerator { id = "JSONF"; title = "JSON Structure"; canAlwaysProcess = true; _schemaContentByPath = {}; /** * Cache of loaded form definitions keyed by formPath. * Avoids redundant Database.ensureFormLoadedByPath() calls for items sharing the same form. * * Lifecycle: This generator is instantiated once per validation run by GeneratorRegistrations. * Caches are valid for the duration of a single ProjectInfoSet.generate() call and are * naturally discarded when the generator instance is garbage-collected after the run. */ _formCache = new Map(); /** * Cache of validation contexts keyed by formPath. * Items with the same form share a subForm cache, avoiding repeated async subForm lookups. * * Lifecycle: Same as _formCache — scoped to a single validation run. */ _contextCache = new Map(); uuidRegex = new RegExp("[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}"); constructor() { this.testUuid = this.testUuid.bind(this); this.testUri = this.testUri.bind(this); } summarize(info, infoSet) { } async loadSchema(uri) { const res = await axios_1.default.get(Utilities_1.default.ensureEndsWithSlash(CreatorToolsHost_1.default.contentWebRoot) + uri); return res.data; } async generate(projectItem, contentIndex) { const items = []; // Fast path: skip items that can never have a form. // getFormPathForType returns undefined for most item types (textures, audio, etc.). // Only geometry items need special logic via getFormPath(). if (projectItem.itemType !== IProjectItemData_1.ProjectItemType.modelGeometryJson && ProjectItemUtilities_1.default.getFormPathForType(projectItem.itemType) === undefined) { return items; } if (projectItem.primaryFile && projectItem.primaryFile.content && typeof projectItem.primaryFile.content === "string") { const formPath = projectItem.getFormPath(); if (formPath) { // Use cached form definition to avoid repeated Database lookups let form = this._formCache.get(formPath); if (form === undefined) { const loaded = await Database_1.default.ensureFormLoadedByPath(formPath); form = loaded || null; this._formCache.set(formPath, form); } if (form) { const data = StorageUtilities_1.default.getJsonObject(projectItem.primaryFile); if (!data) { items.push(new ProjectInfoItem_1.default(IInfoItemData_1.InfoItemType.error, this.id, FormSchemaItemInfoGeneratorTest.couldNotParseJson, "Could not parse JSON. " + (projectItem.primaryFile.errorStateMessage ? projectItem.primaryFile.errorStateMessage : ""), projectItem, formPath)); } else { // Share validation context (and its subForm cache) across items // with the same formPath for massive speedup on repeated forms. let context = this._contextCache.get(formPath); if (!context) { context = { depth: 0, subFormCache: new Map(), }; this._contextCache.set(formPath, context); } // Reset depth for each new item (subFormCache is intentionally preserved) const itemContext = { depth: 0, subFormCache: context.subFormCache, }; const results = await DataFormValidator_1.default.validate(data, form, undefined, undefined, itemContext); if (results) { for (const result of results) { items.push(new ProjectInfoItem_1.default(IInfoItemData_1.InfoItemType.warning, this.id, result.type, result.message, projectItem)); } } } } else { items.push(new ProjectInfoItem_1.default(IInfoItemData_1.InfoItemType.internalProcessingError, this.id, FormSchemaItemInfoGeneratorTest.couldNotFindForm, "Could not find expected form", undefined, formPath)); } } } return items; } testUuid(uuidString) { return this.uuidRegex.test(uuidString); } testUnknownFormat(formatString) { return true; } testUri(uriString) { // could get much more sophisticated here... return uriString.indexOf("://") >= 0; } } exports.default = FormSchemaItemInfoGenerator;