@minecraft/creator-tools
Version:
Minecraft Creator Tools command line and libraries.
181 lines (180 loc) • 7.71 kB
JavaScript
;
// 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.renameCommand = exports.RenameCommand = void 0;
const IToolCommand_1 = require("../IToolCommand");
const AutocompleteProviders_1 = require("../AutocompleteProviders");
const IProjectItemData_1 = require("../../IProjectItemData");
const EntityTypeDefinition_1 = __importDefault(require("../../../minecraft/EntityTypeDefinition"));
const EntityTypeResourceDefinition_1 = __importDefault(require("../../../minecraft/EntityTypeResourceDefinition"));
const SpawnRulesBehaviorDefinition_1 = __importDefault(require("../../../minecraft/SpawnRulesBehaviorDefinition"));
class RenameCommand extends IToolCommand_1.ToolCommandBase {
metadata = {
name: "rename",
description: "Rename a content item in the project",
aliases: ["mv", "move"],
category: "Content",
requiresProject: true,
arguments: [
{
name: "oldName",
description: "Current name or path of the item",
type: "string",
required: true,
autocompleteProvider: AutocompleteProviders_1.projectItemNameProvider,
},
{
name: "newName",
description: "New name for the item",
type: "string",
required: true,
},
],
isWriteCommand: true,
examples: ["/rename my_old_entity my_new_entity", "/rename old_block cool_block"],
};
async execute(context, args, _flags) {
const oldName = args[0];
const newName = args[1];
if (!context.project) {
return this.error("NO_PROJECT", "No active project");
}
// Validate required args
const validationError = this.validateRequiredArgs(args);
if (validationError)
return validationError;
// Find the item
const items = context.project.items || [];
let item = items.find((i) => i.name.toLowerCase() === oldName.toLowerCase() || i.projectPath?.includes(oldName));
if (!item) {
return this.error("ITEM_NOT_FOUND", `Item '${oldName}' not found in project`);
}
const originalName = item.name;
try {
const renamedFiles = [originalName];
if (item.itemType === IProjectItemData_1.ProjectItemType.entityTypeBehavior) {
await this._cascadeEntityBehaviorRename(context.project, item, newName, renamedFiles);
}
else if (item.itemType === IProjectItemData_1.ProjectItemType.entityTypeResource) {
await this._cascadeEntityResourceRename(item, newName);
}
// Rename the primary item's file
await item.rename(newName);
await context.project.save();
if (renamedFiles.length > 1) {
context.output.success(`Renamed '${originalName}' to '${newName}' (also updated: ${renamedFiles.slice(1).join(", ")})`);
}
else {
context.output.success(`Renamed '${originalName}' to '${newName}'`);
}
return this.success(`Renamed ${originalName} to ${newName}`, {
oldName: originalName,
newName,
renamedFiles,
});
}
catch (error) {
const message = error instanceof Error ? error.message : String(error);
return this.error("RENAME_ERROR", `Failed to rename item: ${message}`);
}
}
/**
* Builds a new entity identifier by replacing the short name portion.
* E.g., "myns:old_mob" + "new_mob" → "myns:new_mob"
*/
_buildNewEntityId(oldId, newShortName) {
const colonIndex = oldId.indexOf(":");
if (colonIndex >= 0) {
return oldId.substring(0, colonIndex + 1) + newShortName;
}
return newShortName;
}
/**
* Cascades a rename from an entity behavior item to its resource entity
* and spawn rules. Updates identifiers in JSON and renames related files.
*/
async _cascadeEntityBehaviorRename(project, behaviorItem, newName, renamedFiles) {
// Load the behavior definition with comment preservation for safe editing
if (!behaviorItem.isContentLoaded) {
await behaviorItem.loadContent();
}
const primaryFile = behaviorItem.primaryFile;
if (!primaryFile) {
return;
}
const etd = await EntityTypeDefinition_1.default.ensureOnFile(primaryFile, undefined, true);
if (!etd || !etd.id) {
return;
}
const oldEntityId = etd.id;
const newEntityId = this._buildNewEntityId(oldEntityId, newName);
// Update the behavior entity's identifier
etd.id = newEntityId;
etd.persist();
// Find and update matching resource entities
const resourceItems = project.getItemsByType(IProjectItemData_1.ProjectItemType.entityTypeResource);
for (const resItem of resourceItems) {
if (!resItem.isContentLoaded) {
await resItem.loadContent();
}
if (resItem.primaryFile) {
const etrd = await EntityTypeResourceDefinition_1.default.ensureOnFile(resItem.primaryFile);
if (etrd && etrd.id === oldEntityId) {
const oldResName = resItem.name;
// Re-load with comment preservation for editing
await etrd.load(true);
etrd.id = newEntityId;
etrd.persist();
await resItem.rename(newName);
renamedFiles.push(oldResName);
}
}
}
// Find and update matching spawn rules
const spawnRuleItems = project.getItemsByType(IProjectItemData_1.ProjectItemType.spawnRuleBehavior);
for (const srItem of spawnRuleItems) {
if (!srItem.isContentLoaded) {
await srItem.loadContent();
}
if (srItem.primaryFile) {
const srb = await SpawnRulesBehaviorDefinition_1.default.ensureOnFile(srItem.primaryFile);
if (srb && srb.id === oldEntityId) {
const oldSrName = srItem.name;
// Re-load with comment preservation for editing
await srb.load(true);
srb.id = newEntityId;
srb.persist();
await srItem.rename(newName);
renamedFiles.push(oldSrName);
}
}
}
}
/**
* Updates the identifier inside an entity resource definition when
* the resource item itself is being renamed directly.
*/
async _cascadeEntityResourceRename(resourceItem, newName) {
if (!resourceItem.isContentLoaded) {
await resourceItem.loadContent();
}
const primaryFile = resourceItem.primaryFile;
if (!primaryFile) {
return;
}
const etrd = await EntityTypeResourceDefinition_1.default.ensureOnFile(primaryFile);
if (!etrd || !etrd.id) {
return;
}
const newEntityId = this._buildNewEntityId(etrd.id, newName);
await etrd.load(true);
etrd.id = newEntityId;
etrd.persist();
}
}
exports.RenameCommand = RenameCommand;
exports.renameCommand = new RenameCommand();