@minecraft/creator-tools
Version:
Minecraft Creator Tools command line and libraries.
1,035 lines (1,033 loc) • 78.5 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const Utilities_1 = require("../core/Utilities");
const IField_1 = require("../dataform/IField");
const Database_1 = require("../minecraft/Database");
const LegacyDocumentationDefinition_1 = require("../minecraft/docs/LegacyDocumentationDefinition");
const JsonSchemaDefinition_1 = require("../jsonschema/JsonSchemaDefinition");
const StorageUtilities_1 = require("../storage/StorageUtilities");
const ContentIndex_1 = require("../core/ContentIndex");
const DataFormUtilities_1 = require("../dataform/DataFormUtilities");
const EntityTypeDefinition_1 = require("../minecraft/EntityTypeDefinition");
const ICondition_1 = require("../dataform/ICondition");
const FieldUtilities_1 = require("../dataform/FieldUtilities");
const JsonFormExclusionList = ["is_a", "in_the", "_with_"];
const MAX_FORM_DEPTH = 100;
class FormJsonDocumentationGenerator {
constructor() {
this.defsById = {};
this.defsByTitle = {};
this.defRefs = {};
this.defCategories = {};
}
async updateFormSource(folder, isPreview) {
this.defsById = {};
this.defsByTitle = {};
const metadataFolder = isPreview
? await Database_1.default.loadPreviewMetadataFolder()
: await Database_1.default.loadReleaseMetadataFolder();
const schemaFolder = metadataFolder?.ensureFolder("json_schemas");
if (schemaFolder) {
await this.loadSchemas(schemaFolder, "misc");
}
const formJsonFolder = folder.ensureFolder("forms");
await formJsonFolder.ensureExists();
await this.exportJsonSchemaForms(formJsonFolder);
const aiGoalsNode = await LegacyDocumentationDefinition_1.default.loadNode("entities", "/Server Entity Documentation/AI Goals/", isPreview);
if (aiGoalsNode) {
await this.generateFormNodesFromLegacyDocNode(formJsonFolder, aiGoalsNode, "entity");
}
const attributesNode = await LegacyDocumentationDefinition_1.default.loadNode("entities", "/Server Entity Documentation/Attributes/", isPreview);
if (attributesNode) {
await this.generateFormNodesFromLegacyDocNode(formJsonFolder, attributesNode, "entity");
}
const propertiesNode = await LegacyDocumentationDefinition_1.default.loadNode("entities", "/Server Entity Documentation/Properties/", isPreview);
if (propertiesNode) {
await this.generateFormNodesFromLegacyDocNode(formJsonFolder, propertiesNode, "entity");
}
const entityComponentsNode = await LegacyDocumentationDefinition_1.default.loadNode("entities", "/Server Entity Documentation/Components/", isPreview);
if (entityComponentsNode) {
await this.generateFormNodesFromLegacyDocNode(formJsonFolder, entityComponentsNode, "entity");
}
const triggersComponentsNode = await LegacyDocumentationDefinition_1.default.loadNode("entities", "/Server Entity Documentation/Triggers/", isPreview);
if (triggersComponentsNode) {
await this.generateFormNodesFromLegacyDocNode(formJsonFolder, triggersComponentsNode, "entity");
}
const filtersComponentsNode = await LegacyDocumentationDefinition_1.default.loadNode("entities", "/Filters/", isPreview);
if (filtersComponentsNode) {
await this.generateFormNodesFromLegacyDocNode(formJsonFolder, filtersComponentsNode, "entityfilters");
}
const entityEventsComponentsNode = await LegacyDocumentationDefinition_1.default.loadNode("entity-events", "/", isPreview);
if (entityEventsComponentsNode) {
await this.generateFormNodesFromLegacyDocNode(formJsonFolder, entityEventsComponentsNode, "entityevents");
}
const blocksComponentsNode = await LegacyDocumentationDefinition_1.default.loadNode("blocks", "/Blocks/Block Components/", isPreview);
if (blocksComponentsNode) {
await this.generateFormNodesFromLegacyDocNode(formJsonFolder, blocksComponentsNode, "block");
}
const schemasNode = await LegacyDocumentationDefinition_1.default.loadNode("schemas", "/Schemas/", isPreview);
if (schemasNode) {
await this.generateFormNodesFromPseudoSchemaDocs(formJsonFolder, schemasNode, "visual");
}
const fogsNode = await LegacyDocumentationDefinition_1.default.loadNode("fogs", "/Fog Definitions/Fog Schema/", isPreview);
if (fogsNode) {
await this.generateFormNodesFromPseudoSchemaDocs(formJsonFolder, fogsNode, "fogs");
}
/* These come from JSON schema now.
const biomesNode = await LegacyDocumentationDefinition.loadNode("biomes", "/Schema/", isPreview);
if (biomesNode) {
await this.generateFormNodesFromNode(formJsonFolder, biomesNode, "biomes");
}
*/
const featuresNode = await LegacyDocumentationDefinition_1.default.loadNode("features", "/Supported features/", isPreview);
if (featuresNode) {
const resultForms = await this.generateFormNodesFromPseudoSchemaDocs(formJsonFolder, featuresNode, "features");
if (resultForms) {
this.generateSubformsFromFields(formJsonFolder, resultForms, "features");
}
}
}
async generateSubformsFromFields(formJsonFolder, resultForms, prefix) {
const outerForms = [];
for (const form of resultForms) {
if (form && form.fields) {
for (const field of form.fields) {
if (field.subForm) {
const newForm = {
id: field.id,
title: field.title,
fields: field.subForm.fields,
};
outerForms.push(newForm);
}
}
}
}
for (const form of outerForms) {
if (form && form.id) {
const name = this.getFormFileName(form.id, form.dataVersion);
DataFormUtilities_1.default.mergeFields(form);
DataFormUtilities_1.default.fixupFields(form);
await this.annotateFormJson(form, name, prefix);
await this.mergeToFile(formJsonFolder, name, form, prefix);
}
}
return outerForms;
}
async generateFormNodesFromPseudoSchemaDocs(formJsonFolder, node, prefix) {
if (!node.description && !node.examples) {
return undefined;
}
const formStack = [];
let formStackIndex = -1;
const outerForms = [];
const objectSkippedAt = [];
let lastField = [];
let ignoreNextObject = 0;
let integrateNextProperty = false;
let integrateNextNextProperty = false;
let nodeSet = node.description;
if (!nodeSet && node.examples) {
nodeSet = [];
for (const examp of node.examples) {
nodeSet.push(...examp.text);
}
}
for (const docLine of nodeSet) {
let docLineMod = docLine;
let commentStr = undefined;
integrateNextNextProperty = false;
let commentIndex = docLine.indexOf(" //");
if (commentIndex > 0) {
commentStr = docLine.substring(commentIndex + 3);
docLineMod = docLine.substring(0, commentIndex);
}
const docLineTrim = docLineMod.replace(/ /gi, "").trim();
const startQuote = docLineMod.indexOf('"');
let endQuote = docLineMod.lastIndexOf('"');
const endCompare = docLineMod.lastIndexOf(">");
let mainStr = undefined;
let endStr = undefined;
if (startQuote >= 0 && endQuote > startQuote) {
if (endCompare === endQuote + 1) {
endQuote = endCompare;
}
mainStr = docLineMod.substring(startQuote + 1, endQuote);
endStr = docLineMod.substring(endQuote + 1);
}
if (docLineTrim.endsWith(":{") && !mainStr) {
// this is the pattern from schemas.json
const firstColon = docLineTrim.indexOf(":");
if (firstColon >= 0) {
formStackIndex++;
for (let i = formStackIndex; i < MAX_FORM_DEPTH; i++) {
lastField[i] = undefined;
objectSkippedAt[i] = 0;
}
const form = { id: docLineTrim.substring(0, firstColon), fields: [] };
outerForms.push(form);
formStack[formStackIndex] = form;
const secondColon = docLineTrim.indexOf(":", firstColon + 1);
if (secondColon > firstColon) {
const verStr = docLineTrim.substring(firstColon + 1, secondColon);
if (Utilities_1.default.isVersionString(verStr)) {
form.dataVersion = Utilities_1.default.normalizeVersionString(verStr);
}
}
}
}
else if (docLineTrim === "{" && formStackIndex < 0) {
// this is the pattern from fogs.json, features.json (only one form/object, typically) - handle the outer level form
formStackIndex++;
for (let i = formStackIndex; i < MAX_FORM_DEPTH; i++) {
lastField[i] = undefined;
objectSkippedAt[i] = 0;
}
const form = {
id: (prefix ? prefix : "obj") + (outerForms.length > 0 ? outerForms.length + 1 : ""),
fields: [],
};
outerForms.push(form);
formStack[formStackIndex] = form;
}
else if (docLineTrim === "{") {
if (ignoreNextObject > 0) {
ignoreNextObject--;
objectSkippedAt[formStackIndex]++;
}
else {
const lastFieldStack = lastField[formStackIndex];
formStackIndex++;
for (let i = formStackIndex; i < MAX_FORM_DEPTH; i++) {
lastField[i] = undefined;
objectSkippedAt[i] = 0;
}
if (lastFieldStack && !lastFieldStack.subForm) {
const form = { id: undefined, fields: [] };
formStack[formStackIndex] = form;
lastFieldStack.subForm = form;
}
}
}
else if (docLineTrim === "}" && formStackIndex >= 0) {
if (objectSkippedAt[formStackIndex] > 0) {
objectSkippedAt[formStackIndex]--;
}
else {
formStackIndex--;
}
}
if (formStackIndex >= 0 && formStack[formStackIndex] && mainStr) {
let fieldDefinition = undefined;
if (docLineTrim.startsWith('int"')) {
fieldDefinition = {
dataType: IField_1.FieldDataType.int,
id: mainStr,
title: Utilities_1.default.humanifyMinecraftName(mainStr),
};
}
else if (docLineTrim.startsWith('bool"')) {
fieldDefinition = {
dataType: IField_1.FieldDataType.boolean,
id: mainStr,
title: Utilities_1.default.humanifyMinecraftName(mainStr),
};
}
else if (docLineTrim.startsWith('string"')) {
fieldDefinition = {
dataType: IField_1.FieldDataType.string,
id: mainStr,
title: Utilities_1.default.humanifyMinecraftName(mainStr),
};
}
else if (docLineTrim.startsWith('molang"')) {
fieldDefinition = {
dataType: IField_1.FieldDataType.molang,
id: mainStr,
title: Utilities_1.default.humanifyMinecraftName(mainStr),
};
}
else if (docLineTrim.startsWith('array"')) {
fieldDefinition = {
dataType: IField_1.FieldDataType.stringArray,
id: mainStr,
title: Utilities_1.default.humanifyMinecraftName(mainStr),
};
const firstArrow = mainStr.indexOf("<");
const secondArrow = mainStr.indexOf(">");
const lastFieldStack = lastField[formStackIndex - 1];
if (firstArrow >= 0 && secondArrow > firstArrow) {
if (lastFieldStack &&
(lastFieldStack.dataType === IField_1.FieldDataType.object ||
lastFieldStack.dataType === IField_1.FieldDataType.objectArray)) {
lastFieldStack.dataType = IField_1.FieldDataType.keyedObjectCollection;
lastFieldStack.keyDescription = mainStr;
}
}
integrateNextNextProperty = true;
ignoreNextObject++;
}
else if (docLineTrim.startsWith('enumerated_value"')) {
const firstArrow = mainStr.indexOf("<");
const secondArrow = mainStr.indexOf(">");
if (firstArrow >= 0 && secondArrow > firstArrow) {
const fieldId = mainStr.substring(0, firstArrow);
const choiceStr = mainStr.substring(firstArrow + 1, secondArrow);
const choices = choiceStr.split(",");
const choiceSet = [];
for (const choice of choices) {
if (choice.length > 0) {
choiceSet.push({ id: Utilities_1.default.removeQuotes(choice) });
}
}
fieldDefinition = {
dataType: IField_1.FieldDataType.string,
id: fieldId,
choices: choiceSet,
title: Utilities_1.default.humanifyMinecraftName(mainStr),
};
}
else {
fieldDefinition = {
dataType: IField_1.FieldDataType.string,
id: mainStr,
title: Utilities_1.default.humanifyMinecraftName(mainStr),
};
}
}
else if (docLineTrim.startsWith('object"')) {
let fieldDataType = IField_1.FieldDataType.object;
const firstArrow = mainStr.indexOf("<");
const secondArrow = mainStr.indexOf(">");
const lastFieldStack = lastField[formStackIndex - 1];
const curFieldStack = lastField[formStackIndex];
if (firstArrow >= 0 && secondArrow > firstArrow) {
const subStr = mainStr.substring(firstArrow, secondArrow - firstArrow);
if (subStr.indexOf("array") >= 0 && curFieldStack) {
if (!curFieldStack.alternates) {
curFieldStack.alternates = [];
}
const newField = {
id: curFieldStack.id,
dataType: IField_1.FieldDataType.objectArray,
};
curFieldStack.alternates.push(newField);
lastField[formStackIndex] = newField;
}
else {
if (lastFieldStack &&
(lastFieldStack.dataType === IField_1.FieldDataType.object ||
lastFieldStack.dataType === IField_1.FieldDataType.objectArray)) {
lastFieldStack.dataType = IField_1.FieldDataType.keyedObjectCollection;
lastFieldStack.keyDescription = mainStr;
}
ignoreNextObject++;
}
}
else {
fieldDefinition = {
dataType: fieldDataType,
id: mainStr,
title: Utilities_1.default.humanifyMinecraftName(mainStr),
};
}
}
else if (docLineTrim.startsWith('version"')) {
fieldDefinition = {
dataType: IField_1.FieldDataType.version,
id: mainStr,
title: Utilities_1.default.humanifyMinecraftName(mainStr),
};
}
if (fieldDefinition) {
if (integrateNextProperty && fieldDefinition.id.indexOf("<") >= 0) {
if (fieldDefinition.dataType === IField_1.FieldDataType.molang) {
const lastFieldStack = lastField[formStackIndex];
if (lastFieldStack) {
lastFieldStack.dataType = IField_1.FieldDataType.molangArray;
}
}
integrateNextProperty = false;
}
else {
integrateNextProperty = false;
if (commentStr) {
fieldDefinition.description = commentStr.trim();
}
if (docLineTrim.indexOf(":opt") >= 0) {
fieldDefinition.isRequired = false;
}
else {
fieldDefinition.isRequired = true;
}
lastField[formStackIndex] = fieldDefinition;
formStack[formStackIndex].fields.push(fieldDefinition);
}
}
if (integrateNextNextProperty) {
integrateNextProperty = true;
}
}
}
for (const form of outerForms) {
if (form && form.id) {
const name = this.getFormFileName(form.id, form.dataVersion);
DataFormUtilities_1.default.mergeFields(form);
DataFormUtilities_1.default.fixupFields(form);
await this.annotateFormJson(form, name, prefix);
await this.mergeToFile(formJsonFolder, name, form, prefix);
}
}
return outerForms;
}
async generateFormJson(inputFolder, outputFolder) {
await outputFolder.deleteAllFolderContents();
await this.generateFormJsonFromFolder(inputFolder, outputFolder);
}
async generateFormJsonFromFolder(inputFolder, outputFolder) {
await outputFolder.ensureExists();
await inputFolder.load();
const fileList = { files: [], folders: [] };
for (const folderName in inputFolder.folders) {
const folder = inputFolder.folders[folderName];
if (folder) {
await this.generateFormJsonFromFolder(folder, outputFolder.ensureFolder(folderName));
fileList.folders.push(folderName);
}
}
for (const fileName in inputFolder.files) {
const file = inputFolder.files[fileName];
try {
if (file) {
await file.loadContent();
const jsonO = StorageUtilities_1.default.getJsonObject(file);
if (jsonO) {
const outputFile = outputFolder.ensureFile(fileName);
fileList.files.push(fileName);
await this.finalizeJsonForm(jsonO, outputFile);
}
}
}
catch (e) {
console.log("Error processing " + fileName + ": " + e);
}
}
const indexFile = outputFolder.ensureFile("index.json");
indexFile.setContent(JSON.stringify(fileList));
await indexFile.saveContent();
}
async finalizeJsonForm(formObj, outputFile) {
if (!formObj.generated_doNotEdit && !formObj.generatedFromSchema_doNotEdit && formObj.id) {
const id = formObj.id.replace(/\:/gi, "_").replace(/\./gi, "_");
await outputFile.loadContent();
const originalNode = StorageUtilities_1.default.getJsonObject(outputFile);
await this.annotateFormJson(formObj, id, outputFile.parentFolder.name, originalNode);
}
if (formObj.generatedFromSchema_doNotEdit) {
this.mergeOntoForm(formObj, formObj.generatedFromSchema_doNotEdit);
}
if (formObj.generated_doNotEdit) {
this.mergeOntoForm(formObj, formObj.generated_doNotEdit);
}
formObj.generated_doNotEdit = undefined;
formObj.generatedFromSchema_doNotEdit = undefined;
outputFile.setContent(JSON.stringify(formObj, undefined, 2));
await outputFile.saveContent();
}
mergeOntoForm(formObj, genForm) {
if (!formObj.description || formObj.description === "") {
formObj.description = genForm.description;
}
if (!formObj.title || formObj.title === "") {
formObj.title = genForm.title;
}
if (formObj.samples) {
for (const samplePath in genForm.samples) {
formObj.samples[samplePath] = genForm.samples[samplePath];
}
}
else {
formObj.samples = genForm.samples;
}
if (!formObj.id) {
formObj.id = genForm.id;
}
if (!formObj.note) {
formObj.note = genForm.note;
}
if (!formObj.note2) {
formObj.note2 = genForm.note2;
}
if (!formObj.note3) {
formObj.note3 = genForm.note3;
}
if (!formObj.restrictions) {
formObj.restrictions = genForm.restrictions;
}
if (!formObj.requires) {
formObj.requires = genForm.requires;
}
if (!formObj.scalarField) {
formObj.scalarField = genForm.scalarField;
}
if (!formObj.customField) {
formObj.customField = genForm.customField;
}
if (!formObj.scalarFieldUpgradeName) {
formObj.scalarFieldUpgradeName = genForm.scalarFieldUpgradeName;
}
if (!formObj.isDeprecated) {
formObj.isDeprecated = genForm.isDeprecated;
}
if (!formObj.tags) {
formObj.tags = genForm.tags;
}
if (!formObj.isInternal) {
formObj.isInternal = genForm.isInternal;
}
if (!formObj.dataVersion) {
formObj.dataVersion = genForm.dataVersion;
}
if (formObj.fields && formObj.fields.length === 0) {
formObj.id = genForm.id;
formObj.fields = genForm.fields;
}
else {
const formFields = {};
if (!formObj.fields) {
formObj.fields = genForm.fields;
}
else {
for (const targetField of formObj.fields) {
formFields[targetField.id] = targetField;
}
for (const field of genForm.fields) {
const targetField = formFields[field.id];
if (!targetField) {
formObj.fields.push(field);
}
else {
targetField.samples = field.samples;
if (!targetField.defaultValue) {
targetField.defaultValue = field.defaultValue;
}
if (!targetField.alternates) {
targetField.alternates = field.alternates;
}
if (!targetField.description) {
targetField.description = field.description;
}
if (!targetField.title) {
targetField.title = field.title;
}
if (!targetField.humanifyValues) {
targetField.humanifyValues = field.humanifyValues;
}
if (!targetField.tags) {
targetField.tags = field.tags;
}
if (!targetField.minLength) {
targetField.minLength = field.minLength;
}
if (!targetField.maxLength) {
targetField.maxLength = field.maxLength;
}
if (!targetField.minValue) {
targetField.minValue = field.minValue;
}
if (!targetField.maxValue) {
targetField.maxValue = field.maxValue;
}
if (!targetField.suggestedMinValue) {
targetField.suggestedMinValue = field.suggestedMinValue;
}
if (!targetField.suggestedMaxValue) {
targetField.suggestedMaxValue = field.suggestedMaxValue;
}
if (!targetField.isRequired) {
targetField.isRequired = field.isRequired;
}
if (targetField.dataType === undefined) {
targetField.dataType = field.dataType;
}
if (!targetField.choices) {
targetField.choices = field.choices;
}
if (!targetField.validity) {
targetField.validity = field.validity;
}
}
}
}
}
}
async exportJsonSchemaForms(formJsonFolder) {
for (const key in this.defsByTitle) {
if (!this.defRefs[key]) {
await this.processAndExportJsonSchemaNode(formJsonFolder, key);
}
}
}
async processAndExportJsonSchemaNode(formJsonFolder, title) {
const formNode = await this.getJsonFormFromJsonSchemaKey(title);
if (formNode && formNode.fields.length > 0) {
if (title.indexOf("omponents") >= 0) {
if (formNode.fields) {
for (const field of formNode.fields) {
if (field.subForm) {
const name = this.getFormFileNameBase(field.id);
const category = this.defCategories[title];
field.subForm.id = field.id;
await this.annotateFormJson(field.subForm, name, category);
await this.mergeToFile(formJsonFolder, name, field.subForm, category, true);
}
}
}
}
else {
let versionlessTitle = title.substring(title.lastIndexOf(".") + 1);
versionlessTitle = this.getVersionlessString(versionlessTitle);
const name = this.getFormFileNameBase(versionlessTitle);
let matchesExclusion = false;
for (const exclusion of JsonFormExclusionList) {
if (name.indexOf(exclusion) >= 0) {
matchesExclusion = true;
break;
}
}
if (!matchesExclusion) {
const category = this.defCategories[title];
await this.annotateFormJson(formNode, name, category);
await this.mergeToFile(formJsonFolder, name, formNode, category, true);
}
}
}
}
getFormFileNameBase(key) {
key = key.toLowerCase();
if (key.startsWith("struct_") || key.startsWith("struct ")) {
key = key.substring(7);
}
if ((key.startsWith("enum_") || key.startsWith("enum ")) && key.indexOf("num_property") < 0) {
key = key.substring(5);
}
key = key.replace("sharedtypes", "");
key = StorageUtilities_1.default.sanitizePathBasic(key);
return key;
}
getVersionlessString(key) {
let verStart = key.indexOf(" v1.");
if (verStart >= 0) {
const nextSpace = key.indexOf(" ", verStart + 4);
if (nextSpace >= 0) {
key = key.substring(0, verStart) + key.substring(nextSpace + 1);
}
else {
key = key.substring(0, verStart);
}
}
return key;
}
async getJsonFormFromJsonSchemaKey(keyName) {
let rootNodeName = undefined;
let rootNodeNameVersionless = undefined;
let rootNode = undefined;
const keyVersionless = this.getVersionlessString(keyName);
// attempt to get the latest version of a component by sorting on the node name e.g., minecraft:item v1.21.60 should sort later than minecraft:item v1.21.40
// though we should replace this with a more sophisticated sorter for version :-/
for (const candidateKey in this.defsByTitle) {
const candidateKeyVersionless = this.getVersionlessString(candidateKey);
if (candidateKeyVersionless === keyVersionless) {
if (!rootNodeName ||
(candidateKey.localeCompare(rootNodeName) > 0 && candidateKeyVersionless === rootNodeNameVersionless)) {
rootNodeName = candidateKey;
rootNodeNameVersionless = candidateKeyVersionless;
rootNode = this.defsByTitle[candidateKey];
}
}
}
for (const key in this.defsById) {
if (key.indexOf(keyName) >= 0) {
const keyVersionless = this.getVersionlessString(key);
if (!rootNodeName || (key.localeCompare(rootNodeName) > 0 && keyVersionless === rootNodeNameVersionless)) {
rootNodeName = key;
rootNodeNameVersionless = keyVersionless;
rootNode = this.defsByTitle[key];
}
}
}
if (rootNode === undefined) {
return;
}
if (rootNodeName !== keyName) {
return;
}
return await this.getJsonFormFromJsonSchemaDefinition(rootNode, keyName);
}
async getJsonFormFromJsonSchemaDefinition(node, nodeName, fieldList) {
const fields = [];
if (node.properties) {
for (const propName in node.properties) {
const propNode = node.properties[propName];
if (propNode && typeof propNode !== "boolean") {
const field = await this.getFieldFromJsonPropertyNode(propNode, propName, fieldList);
if (field) {
fields.push(field);
}
}
}
}
if (!nodeName) {
if (node.title) {
nodeName = node.title;
}
else {
nodeName = "";
}
}
const docForm = {
title: Utilities_1.default.humanifyMinecraftName(nodeName),
description: node.description ? node.description : Utilities_1.default.humanifyMinecraftName(nodeName),
fields: fields,
};
return docForm;
}
async loadSchemas(schemaFolder, categoryName) {
await schemaFolder.load();
for (const fileName in schemaFolder.files) {
const file = schemaFolder.files[fileName];
if (file && file.type === "json" && file.name !== "index.json") {
const jsonSchema = await JsonSchemaDefinition_1.default.ensureOnFile(file);
if (jsonSchema && jsonSchema.data) {
this.processDef(jsonSchema.data, categoryName);
}
}
}
for (const folderName in schemaFolder.folders) {
const folder = schemaFolder.folders[folderName];
if (folder) {
if (!folder.name.startsWith("v1") && folder.name !== "common" && folder.name !== "components") {
categoryName = folder.name;
}
if (categoryName.startsWith("1.")) {
categoryName = "misc";
}
if ((schemaFolder.parentFolder?.name === "client" ||
schemaFolder.parentFolder?.parentFolder?.name === "client") &&
categoryName.indexOf("client") < 0) {
categoryName = "client_" + categoryName;
}
await this.loadSchemas(folder, categoryName);
}
}
}
processDef(schemaDef, category, depth = 0) {
if (schemaDef["$id"]) {
this.defsById[schemaDef["$id"]] = schemaDef;
if (this.defRefs[schemaDef["$id"]] === undefined) {
this.defRefs[schemaDef["$id"]] = depth ? 1 : 0;
}
if (schemaDef.title && category.indexOf("client") < 0) {
if (schemaDef.title?.indexOf("lient ") >= 0 && category.indexOf("client") < 0) {
category = "client_" + category;
}
}
this.defCategories[schemaDef["$id"]] = category;
}
if (schemaDef.title) {
this.defsByTitle[category + "." + schemaDef.title] = schemaDef;
if (this.defRefs[category + "." + schemaDef.title] === undefined) {
this.defRefs[category + "." + schemaDef.title] = depth ? 1 : 0;
}
this.defCategories[category + "." + schemaDef.title] = category;
}
for (const propName in schemaDef.properties) {
const propNode = schemaDef.properties[propName];
if (propNode && typeof propNode !== "boolean") {
if (propNode.$ref) {
if (this.defRefs[propNode.$ref] === undefined) {
this.defRefs[propNode.$ref] = 1;
}
else {
this.defRefs[propNode.$ref]++;
}
}
}
}
if (schemaDef.definitions) {
for (const defName in schemaDef.definitions) {
const def = schemaDef.definitions[defName];
if (def && typeof def !== "boolean") {
this.defsById[defName.toString()] = def;
this.processDef(def, category, depth + 1);
}
}
}
}
async generateFormNodesFromLegacyDocNode(formJsonFolder, node, prefix) {
for (const childNode of node.nodes) {
if (childNode.name) {
const name = this.getFormFileName(childNode.name);
const formDocNode = this.getFormFromDocNode(childNode, childNode.name);
const genFormDocNode = await this.getOriginalFormDefinition(formJsonFolder, name, prefix);
await this.annotateFormJson(formDocNode, name, prefix, genFormDocNode);
await this.mergeToFile(formJsonFolder, name, formDocNode, prefix);
}
}
}
async getOriginalFormDefinition(formJsonFolder, name, categoryName) {
if (categoryName && categoryName.length > 0) {
formJsonFolder = formJsonFolder.ensureFolder(categoryName);
}
name = name.toLowerCase();
name = name.replace(/ /gi, "_");
const file = formJsonFolder.ensureFile(name + ".form.json");
await file.loadContent();
return StorageUtilities_1.default.getJsonObject(file);
}
async mergeToFile(formJsonFolder, name, formDefNode, categoryName, isSchema) {
if (categoryName && categoryName.length > 0) {
formJsonFolder = formJsonFolder.ensureFolder(categoryName);
}
name = name.toLowerCase();
name = name.replace(/ /gi, "_");
const file = formJsonFolder.ensureFile(name + ".form.json");
await file.loadContent();
let jsonO = StorageUtilities_1.default.getJsonObject(file);
if (isSchema) {
if (jsonO) {
jsonO.generatedFromSchema_doNotEdit = formDefNode;
}
else {
jsonO = {
id: formDefNode.id,
fields: [],
generatedFromSchema_doNotEdit: formDefNode,
};
}
}
else {
if (jsonO) {
jsonO.generated_doNotEdit = formDefNode;
}
else {
jsonO = {
id: formDefNode.id,
fields: [],
generated_doNotEdit: formDefNode,
};
}
}
file.setContent(JSON.stringify(jsonO, undefined, 2));
await file.saveContent();
}
async annotateFormJson(formDefNode, name, prefix, originalNode) {
let canonName = EntityTypeDefinition_1.default.getComponentFromBaseFileName(name);
let isMinecraftComponent = false;
if (name.startsWith("minecraft_")) {
isMinecraftComponent = true;
if (canonName.startsWith("behavior.")) {
let hasPrioNode = false;
for (const field of formDefNode.fields) {
if (field.id === "priority") {
hasPrioNode = true;
}
}
if (!hasPrioNode) {
formDefNode.fields.push({
id: "priority",
title: "Priority",
hideSamples: true,
description: "As priority approaches 0, the priority is increased. The higher the priority, the sooner this behavior will be executed as a goal.",
dataType: 0,
});
}
}
}
if (prefix === "entity" && isMinecraftComponent) {
await this.addVanillaMatches(formDefNode, canonName, [
ContentIndex_1.AnnotationCategory.entityComponentDependent,
ContentIndex_1.AnnotationCategory.entityComponentDependentInGroup,
]);
await this.addSamplesMatches(formDefNode, canonName, [
ContentIndex_1.AnnotationCategory.entityComponentDependent,
ContentIndex_1.AnnotationCategory.entityComponentDependentInGroup,
]);
}
else if (prefix === "item" && isMinecraftComponent) {
await this.addVanillaMatches(formDefNode, canonName, [ContentIndex_1.AnnotationCategory.itemComponentDependent]);
await this.addSamplesMatches(formDefNode, canonName, [ContentIndex_1.AnnotationCategory.itemComponentDependent]);
}
else if (prefix === "block" && isMinecraftComponent) {
await this.addVanillaMatches(formDefNode, canonName, [ContentIndex_1.AnnotationCategory.blockComponentDependent]);
await this.addSamplesMatches(formDefNode, canonName, [ContentIndex_1.AnnotationCategory.blockComponentDependent]);
}
else if (prefix === "entityfilters") {
await this.addVanillaMatches(formDefNode, canonName, [ContentIndex_1.AnnotationCategory.entityFilter]);
await this.addSamplesMatches(formDefNode, canonName, [ContentIndex_1.AnnotationCategory.entityFilter]);
}
else if (prefix === "features") {
await this.addVanillaMatches(formDefNode, canonName, [ContentIndex_1.AnnotationCategory.entityFilter]);
await this.addSamplesMatches(formDefNode, canonName, [ContentIndex_1.AnnotationCategory.entityFilter]);
}
if (formDefNode.samples) {
this.distributeSampleValues(formDefNode.samples, formDefNode, [], originalNode);
}
}
async distributeSampleValues(samplesNode, formDefNode, pathTokens, originalNode) {
if (!formDefNode.fields) {
return;
}
const fieldsById = {};
for (const field of formDefNode.fields) {
fieldsById[field.id] = field;
}
const originalFieldsById = {};
if (originalNode && originalNode.fields) {
for (const field of originalNode.fields) {
originalFieldsById[field.id] = field;
}
}
for (const exampleFilePath in samplesNode) {
const sampleList = samplesNode[exampleFilePath];
if (sampleList) {
for (const sample of sampleList) {
if (sample.content && typeof sample.content === "object") {
let obj = sample.content;
if (obj) {
for (const fieldName in obj) {
const fieldVal = obj[fieldName];
let subForm = undefined;
if (!fieldsById[fieldName] &&
(!originalNode || !originalNode.customField || originalFieldsById[fieldName])) {
let dataType = IField_1.FieldDataType.string;
if (fieldName.startsWith("on_")) {
dataType = IField_1.FieldDataType.minecraftEventTrigger;
}
else {
if (typeof fieldVal === "number") {
dataType = IField_1.FieldDataType.number;
}
else if (Array.isArray(fieldVal)) {
if (fieldVal.length > 0) {
if (typeof fieldVal[0] === "object") {
dataType = IField_1.FieldDataType.objectArray;
subForm = DataFormUtilities_1.default.generateFormFromObject(fieldName, fieldVal[0], exampleFilePath);
}
else if (typeof fieldVal[0] === "string") {
dataType = IField_1.FieldDataType.stringArray;
}
}
}
else if (typeof fieldVal === "object") {
dataType = IField_1.FieldDataType.object;
subForm = DataFormUtilities_1.default.generateFormFromObject(fieldName, fieldVal, exampleFilePath);
}
}
const newField = {
id: fieldName,
title: Utilities_1.default.humanifyMinecraftName(fieldName),
dataType: dataType,
subForm: subForm,
};
fieldsById[fieldName] = newField;
formDefNode.fields.push(newField);
}
}
}
}
}
}
}
for (const field of formDefNode.fields) {
const pathTokensToSearch = pathTokens.slice();
pathTokensToSearch.push(field.id);
for (const exampleFilePath in samplesNode) {
const sampleList = samplesNode[exampleFilePath];
if (sampleList) {
for (const sample of sampleList) {
if (sample.content && typeof sample.content === "object") {
let obj = sample.content;
for (let i = 0; i < pathTokensToSearch.length; i++) {
if (obj && obj[pathTokensToSearch[i]] !== undefined) {
obj = obj[pathTokensToSearch[i]];
}
else {
obj = undefined;
}
}
if (obj) {
let exampleInstanceCount = 0;
if (!field.samples) {
field.samples = {};
}
if (field.subForm) {
let exampleObj = obj;
if (Array.isArray(exampleObj) && exampleObj.length > 0) {
const subSamples = {};
let subSamplesAdded = 0;
const path = exampleFilePath;
for (const subObj of exampleObj) {
if (typeof subObj === "object") {
if (!subSamples[path]) {
subSamples[path] = [];
}
subSamples[path].push({
path: sample.path + "|" + pathTokensToSearch.join(".") + "|" + subSamplesAdded.toString(),
content: subObj,
});
subSamplesAdded++;
}
}
if (subSamplesAdded > 0) {
await this.distributeSampleValues(subSamples, field.subForm, pathTokensToSearch);
}
}
}
const exampleSamp = JSON.stringify(obj);
const path = exampleFilePath;
for (const path in field.samples) {
for (let i = 0; i < field.samples[path].length; i++) {
if (JSON.stringify(field.samples[path][i].content) === exampleSamp) {
exampleInstanceCount++;
}
}
}
if (exampleInstanceCount < 2) {
if (!field.samples[path]) {
field.samples[path] = [];
}
field.samples[path].push({ path: sample.path, content: obj });
}
}
}
}
}
}
}
}
async addVanillaMatches(formDefNode, name, annotations) {
const vanillaMatches = await Database_1.default.getPreviewVanillaMatches(name, true, annotations);
if (vanillaMatches && vanillaMatches.length > 0) {
if (!formDefNode.samples) {
formDefNode.samples = {};
}
const vanillaPreview = await Database_1.default.getPreviewVanillaFolder();
if (!vanillaPreview) {
return;
}
for (const match of vanillaMatches) {
if (match.value.startsWith("/") && match.value.indexOf("metadata") < 0) {
const file = await vanillaPreview.getFileFromRelativePath(match.value);
if (file && (await file.exists())) {
await file.loadContent();
const jsonO = StorageUtilities_1.default.getJsonObject(file);
if (jsonO) {
if (!formDefNode.samples["/vanilla" + match.value]) {
formDefNode.samples["/vanilla" + match.value] = [];
}
this.appendNodesByName(formDefNode.samples["/vanilla" + match.value], "minecraft:" + name, jsonO, "/");
}
}
}
}