mc-anvil
Version:
A Typescript library for reading Minecraft Anvil format files and Minecraft NBT format files in the browser.
93 lines • 5.95 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.nbtTagReducer = exports.deleteChild = exports.transformTag = exports.NBTActions = void 0;
const nbt_1 = require("./nbt");
const types_1 = require("./types");
var NBTActions;
(function (NBTActions) {
NBTActions["NBT_DELETE_TAG"] = "NBT_DELETE_TAG";
NBTActions["NBT_ADD_TAG"] = "NBT_ADD_TAG";
NBTActions["NBT_EDIT_TAG"] = "NBT_EDIT_TAG";
NBTActions["NBT_ADD_COMPOUND_LIST_ITEM"] = "NBT_ADD_COMPOUND_LIST_ITEM";
})(NBTActions = exports.NBTActions || (exports.NBTActions = {}));
;
function transformTag(tag, path, transform) {
var _a;
if (path[0] === '/')
path = path.slice(1);
const p = path.split("/");
if (p.length === 1 && p[0] === "")
return transform(tag);
if (tag.type === types_1.TagType.COMPOUND) {
let children = [...tag.data];
if (children[children.length - 1].type === types_1.TagType.END)
children = children.slice(0, children.length - 1);
if (children.find(x => x.name === p[0]) !== undefined)
children.forEach((child, i) => { if (child.name === p[0])
children[i] = transformTag(child, p.slice(1).join("/"), transform); });
else {
const nTag = ((_a = p[1]) === null || _a === void 0 ? void 0 : _a.match(nbt_1.LIST_INDEX)) ? { type: types_1.TagType.LIST, name: p[0], data: { subType: types_1.TagType.COMPOUND, data: [] } }
: { type: types_1.TagType.COMPOUND, name: p[0], data: [{ type: types_1.TagType.END, name: "", data: null }] };
children.push(transformTag(nTag, p.slice(1).join("/"), transform));
}
return Object.assign(Object.assign({}, tag), { data: [...children, { type: types_1.TagType.END, name: "", data: null }] });
}
else if (tag.type === types_1.TagType.LIST && tag.data.subType === types_1.TagType.COMPOUND) {
const index = nbt_1.parseCompoundListIndex(p[0]);
const data = [...tag.data.data];
if (index >= data.length)
for (let i = data.length; i < index; ++i)
data.push([{ type: types_1.TagType.END, name: "", data: null }]);
return Object.assign(Object.assign({}, tag), { data: Object.assign(Object.assign({}, tag.data), { data: [
...data.slice(0, index),
transformTag({ type: types_1.TagType.COMPOUND, name: "", data: data[index] || [{ type: types_1.TagType.END, name: "", data: null }] }, p.slice(1).join("/"), transform).data,
...data.slice(index + 1)
] }) });
}
throw new Error(`${tag.name} is not a compound or list tag, and cannot have children at ${path}.`);
}
exports.transformTag = transformTag;
function deleteChild(tag, name) {
if (tag.type === types_1.TagType.COMPOUND)
return Object.assign(Object.assign({}, tag), { data: tag.data.filter(x => x.name !== name) });
else if (tag.type === types_1.TagType.LIST) {
const index = nbt_1.parseCompoundListIndex(name);
return Object.assign(Object.assign({}, tag), { data: Object.assign(Object.assign({}, tag.data), { data: tag.data.data.filter((_, i) => i !== index) }) });
}
throw new Error(`Cannot delete child ${name} from non-container tag of type ${tag.type}.`);
}
exports.deleteChild = deleteChild;
function ensureEndTag(tags) {
if (tags[tags.length - 1].type === types_1.TagType.END)
return tags;
return [...tags, { type: types_1.TagType.END, name: "", data: null }];
}
function nbtTagReducer(tag, action) {
var _a;
switch (action.type) {
case NBTActions.NBT_DELETE_TAG:
if (nbt_1.findChildTagAtPath(action.path, tag) === undefined)
throw new Error(`Unable to delete ${action.path}: tag not found.`);
else if (!action.recursive && ((_a = nbt_1.findChildTagAtPath(action.path, tag)) === null || _a === void 0 ? void 0 : _a.type) === types_1.TagType.COMPOUND)
throw new Error(`Deletion of compound tag with name ${tag.name} requires the recursive flag.`);
return transformTag(tag, nbt_1.parent(action.path), tag => deleteChild(tag, nbt_1.baseName(action.path)));
case NBTActions.NBT_ADD_TAG:
if (!action.recursive && nbt_1.findChildTagAtPath(action.path, tag) === undefined)
throw new Error(`Unable to add a child to non-existent tag ${action.path} without the recursive flag set.`);
else if (!action.overwrite && nbt_1.findChildTagAtPath(action.path + "/" + action.tag.name, tag) !== undefined)
throw new Error(`A child tag already exists at ${action.path}/${action.tag.name}; use the overwrite flag to replace.`);
return transformTag(tag, `${action.path}/${action.tag.name}`, () => action.tag);
case NBTActions.NBT_ADD_COMPOUND_LIST_ITEM:
if (!action.recursive && nbt_1.findChildTagAtPath(action.path, tag) === undefined)
throw new Error(`Unable to add a child to non-existent tag ${action.path} without the recursive flag set.`);
else if (!action.overwrite && nbt_1.findChildTagAtPath(`${action.path}/[${action.index}]`, tag) !== undefined)
throw new Error(`A child tag already exists at ${action.path}/[${action.index}]; use the overwrite flag to replace.`);
return transformTag(tag, `${action.path}/[${action.index}]`, () => ({ type: types_1.TagType.COMPOUND, name: "", data: ensureEndTag(action.tags) }));
case NBTActions.NBT_EDIT_TAG:
if (nbt_1.findChildTagAtPath(action.path, tag) === undefined)
throw new Error(`Unable to edit non-existent tag ${action.path}.`);
return transformTag(transformTag(tag, nbt_1.parent(action.path), tag => deleteChild(tag, nbt_1.baseName(action.path))), action.path, () => action.tag);
}
}
exports.nbtTagReducer = nbtTagReducer;
//# sourceMappingURL=reducer.js.map