@minecraft/creator-tools
Version:
Minecraft Creator Tools command line and libraries.
370 lines (369 loc) • 14.3 kB
JavaScript
"use strict";
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const IFile_1 = require("./IFile");
const StorageUtilities_1 = __importDefault(require("./StorageUtilities"));
const md5 = __importStar(require("js-md5"));
const Log_1 = __importDefault(require("../core/Log"));
const ste_events_1 = require("ste-events");
const Utilities_1 = __importDefault(require("../core/Utilities"));
const JsonUtilities_1 = __importDefault(require("../core/JsonUtilities"));
class FileBase {
priorVersions = [];
isDisposed = false;
isInErrorState;
errorStateMessage;
/**
* Cache for comment-json parsed object.
* When set, contains the parsed JSON with comment metadata preserved as Symbol properties.
*/
commentJsonCache;
_content;
#fileContainerStorage = null;
#onFileContentUpdated = new ste_events_1.EventDispatcher();
get fileContainerStorage() {
return this.#fileContainerStorage;
}
get onFileContentUpdated() {
return this.#onFileContentUpdated.asEvent();
}
set fileContainerStorage(newStorage) {
this.#fileContainerStorage = newStorage;
}
get isString() {
return this._content !== null && typeof this._content === "string";
}
get canIgnore() {
return StorageUtilities_1.default.canIgnoreFileName(this.name) || StorageUtilities_1.default.canIgnoreFileExtension(this.type);
}
get isBinary() {
if (this._content === undefined) {
return false;
}
if (this._content instanceof Uint8Array) {
return true;
}
return false;
}
get content() {
return this._content;
}
get latestModified() {
if (this.modified == null) {
return this.modifiedAtLoad;
}
if (this.modifiedAtLoad == null) {
return null;
}
if (this.modified.getTime() > this.modifiedAtLoad.getTime()) {
return this.modified;
}
return this.modifiedAtLoad;
}
modified;
modifiedAtLoad;
lastLoadedOrSaved;
manager;
tag;
get type() {
return StorageUtilities_1.default.getTypeFromName(this.name);
}
get needsSave() {
if (this.isDisposed) {
Log_1.default.throwIsDisposed();
}
return this.modified != null && (this.lastLoadedOrSaved == null || this.modified >= this.lastLoadedOrSaved);
}
get fullPath() {
return this.storageRelativePath;
}
get extendedPath() {
let start = "";
if (this.parentFolder.storage.storagePath) {
start = this.parentFolder.storage.storagePath;
}
return start + this.fullPath;
}
get storageRelativePath() {
return this.parentFolder.storageRelativePath + this.name;
}
getRootRelativePath() {
if (this.isDisposed) {
Log_1.default.throwIsDisposed();
}
return this.getFolderRelativePath(this.parentFolder.storage.rootFolder);
}
getFolderRelativePath(toFolder) {
if (this.isDisposed) {
Log_1.default.throwIsDisposed();
}
let result = this.parentFolder.getFolderRelativePath(toFolder);
if (result === undefined) {
return undefined;
}
return result + this.name;
}
get coreContentLength() {
if (!this.content) {
return 0;
}
if (this.isBinary || typeof this.content !== "string") {
return this.content.length;
}
return this.content.replace(/\s/g, "").length;
}
constructor() {
this.modified = null;
this.modifiedAtLoad = null;
this.lastLoadedOrSaved = null;
this._content = null;
}
contentWasModified(oldContent, updateType, sourceId) {
if (this.isDisposed) {
Log_1.default.throwIsDisposed();
}
let oldVersionContent = undefined;
if (updateType !== IFile_1.FileUpdateType.versionRestoration && updateType !== IFile_1.FileUpdateType.versionlessEdit) {
let oldModified = this.modified;
if (oldModified === null) {
oldModified = this.lastLoadedOrSaved;
}
oldVersionContent = {
id: Utilities_1.default.createRandomId(10),
content: oldContent,
file: this,
versionTime: oldModified,
};
this.parentFolder.storage.addVersion(oldVersionContent, updateType ? updateType : IFile_1.FileUpdateType.regularEdit);
}
this.modified = new Date();
this.notifyFileContentUpdated();
if (this.parentFolder.storage) {
this.parentFolder.storage.notifyFileContentsUpdated({
file: this,
updateType: updateType ? updateType : IFile_1.FileUpdateType.regularEdit,
sourceId: sourceId,
priorVersion: oldVersionContent,
});
}
}
notifyFileContentUpdated() {
this.#onFileContentUpdated.dispatch(this, this);
}
async getHash() {
if (!this.isContentLoaded) {
await this.loadContent(false);
}
if (this._content === undefined || this._content === null) {
return undefined;
}
return md5.md5(this._content);
}
unload() {
this._content = null;
this.lastLoadedOrSaved = null;
// Also clear the manager (typically a Definition object with parsed JSON) to fully release memory
this.manager = undefined;
// Clear cached parsed JSON to release memory
this.commentJsonCache = undefined;
}
dispose() {
this.manager = undefined;
this._content = null;
this.lastLoadedOrSaved = null;
this.commentJsonCache = undefined;
this.isDisposed = true;
}
async exists() {
if (this.isDisposed) {
Log_1.default.throwIsDisposed();
}
await this.loadContent(false);
return this._content !== null;
}
getRelativePathFor(file) {
if (file.parentFolder.storage !== this.parentFolder.storage) {
return undefined;
}
const foldersByPath = {};
let targetParentFolder = file.parentFolder;
while (targetParentFolder) {
foldersByPath[targetParentFolder.storageRelativePath] = targetParentFolder;
targetParentFolder = targetParentFolder.parentFolder;
}
let myParentFolder = this.parentFolder;
let relativePath = "." + myParentFolder.storage.folderDelimiter;
while (myParentFolder && foldersByPath[myParentFolder.storageRelativePath] === undefined) {
relativePath += ".." + myParentFolder.storage.folderDelimiter;
myParentFolder = myParentFolder.parentFolder;
}
if (!myParentFolder) {
return undefined;
}
const folderRelativePath = file.getFolderRelativePath(myParentFolder);
if (!folderRelativePath) {
return undefined;
}
return relativePath + StorageUtilities_1.default.ensureNotStartsWithDelimiter(folderRelativePath);
}
setObjectContentIfSemanticallyDifferent(value, updateType, sourceId) {
if (value === null || value === undefined) {
if (this._content !== null) {
this.setContent(null, updateType, sourceId);
this.commentJsonCache = undefined;
return true;
}
return false;
}
if (!(typeof this._content === "string")) {
// No existing content - check if the new value has comment metadata
if (JsonUtilities_1.default.hasCommentMetadata(value)) {
this.setContent(JsonUtilities_1.default.stringifyJsonWithComments(value), updateType, sourceId);
this.commentJsonCache = value;
}
else {
this.setContent(JSON.stringify(value, null, 2), updateType, sourceId);
}
return true;
}
try {
// If the value has comment metadata, use comment-preserving comparison and stringify
if (JsonUtilities_1.default.hasCommentMetadata(value)) {
const currentObj = this.commentJsonCache ?? JsonUtilities_1.default.parseJsonWithComments(this._content);
if (!JsonUtilities_1.default.jsonObjectsSemanticallyEqual(currentObj, value)) {
this.setContent(JsonUtilities_1.default.stringifyJsonWithComments(value), updateType, sourceId);
this.commentJsonCache = value;
return true;
}
return false;
}
// Standard path for objects without comment metadata
const currentObj = JSON.parse(this._content);
if (Utilities_1.default.consistentStringify(currentObj) !== Utilities_1.default.consistentStringify(value)) {
this.setContent(JSON.stringify(value, null, 2), updateType, sourceId);
return true;
}
}
catch (e) {
// JSON.parse failed — current content may have comments or trailing commas.
// Try comment-aware parsing before unconditionally overwriting (prevents phantom edits).
try {
const currentObj = JSON.parse(Utilities_1.default.fixJsonContent(this._content));
if (Utilities_1.default.consistentStringify(currentObj) === Utilities_1.default.consistentStringify(value)) {
return false;
}
}
catch {
// Both parses failed — content is truly unparseable, proceed with overwrite
}
if (JsonUtilities_1.default.hasCommentMetadata(value)) {
this.setContent(JsonUtilities_1.default.stringifyJsonWithComments(value), updateType, sourceId);
this.commentJsonCache = value;
}
else {
this.setContent(JSON.stringify(value, null, 2), updateType, sourceId);
}
return true;
}
return false;
}
async reloadAfterExternalUpdate() {
let existingContent = this._content;
await this.loadContent(true);
if (this._content !== existingContent) {
this.contentWasModified(existingContent, IFile_1.FileUpdateType.externalChange);
}
}
setContentIfSemanticallyDifferent(value, updateType, sourceId) {
if (value === null) {
if (this._content !== null) {
this.setContent(null, updateType, sourceId);
return true;
}
return false;
}
if (value instanceof Uint8Array) {
if (!(this._content instanceof Uint8Array) || this._content.length !== value.length) {
this.setContent(value, updateType, sourceId);
return true;
}
else {
for (let i = 0; i < value.length; i++) {
if (this._content[i] !== value[i]) {
this.setContent(value, updateType, sourceId);
return true;
}
}
}
}
else if (typeof value === "string") {
if (!(typeof this._content === "string")) {
this.setContent(value, updateType, sourceId);
return true;
}
else {
if (this.type === "json") {
try {
const currentObj = JSON.parse(this._content);
const newObj = JSON.parse(value);
if (Utilities_1.default.consistentStringify(currentObj) !== Utilities_1.default.consistentStringify(newObj)) {
return this.setContent(value, updateType, sourceId);
}
}
catch (e) {
return this.setContent(value);
}
}
else {
if (this._content.length !== value.length) {
return this.setContent(value, updateType, sourceId);
}
for (let i = 0; i < value.length; i++) {
if (this._content[i] !== value[i]) {
return this.setContent(value, updateType, sourceId);
}
}
}
}
}
return false;
}
}
exports.default = FileBase;