@minecraft/creator-tools
Version:
Minecraft Creator Tools command line and libraries.
292 lines (291 loc) • 11.9 kB
JavaScript
"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 });
const BrowserFile_1 = __importDefault(require("./BrowserFile"));
const BrowserStorage_1 = __importDefault(require("./BrowserStorage"));
const StorageUtilities_1 = __importDefault(require("./StorageUtilities"));
const Utilities_1 = __importDefault(require("./../core/Utilities"));
const Log_1 = __importDefault(require("./../core/Log"));
const localforage_1 = __importDefault(require("localforage"));
const FolderBase_1 = __importDefault(require("./FolderBase"));
class BrowserFolder extends FolderBase_1.default {
_name;
_parentPath;
_lastSavedContent;
_storage;
_parentFolder;
_lastLoadedPath;
get storage() {
return this._storage;
}
get parentFolder() {
return this._parentFolder;
}
folders;
files;
lastSavedFileCount;
modifiedAtLoad;
get name() {
return this._name;
}
get fullPath() {
return this._parentPath + BrowserStorage_1.default.slashFolderDelimiter + StorageUtilities_1.default.canonicalizeName(this.name);
}
constructor(storage, parentFolder, parentPath, folderName) {
super();
this._storage = storage;
this._parentFolder = parentFolder;
this._parentPath = parentPath;
this._name = folderName;
this._lastSavedContent = "";
this.lastSavedFileCount = 0;
this.folders = {};
this.files = {};
}
ensureFile(name) {
const nameCanon = StorageUtilities_1.default.canonicalizeName(name);
let candFile = this.files[nameCanon];
if (candFile == null) {
candFile = new BrowserFile_1.default(this, name);
this.files[nameCanon] = candFile;
this.storage.notifyFileAdded(candFile);
}
return candFile;
}
async exists() {
return true;
}
async ensureExists() {
return true;
}
async deleteThisFolder() {
if (this.storage.readOnly) {
throw new Error("Can't save read-only file.");
}
let result = await this.recursiveDeleteThisFolder();
await localforage_1.default.removeItem(this.fullPath + BrowserStorage_1.default.slashFolderDelimiter);
return result;
}
async deleteAllFolderContents() {
throw new Error("Deletion of all folder contents at " + this.fullPath + " is not supported.");
}
ensureFolder(name) {
const nameCanon = StorageUtilities_1.default.canonicalizeName(name);
let candFolder = this.folders[nameCanon];
if (!candFolder) {
candFolder = new BrowserFolder(this._storage, this, this.fullPath, name);
this.folders[nameCanon] = candFolder;
}
return candFolder;
}
async scanForChanges() {
// no-op for browser storage
}
_removeFile(file) {
const nameCanon = StorageUtilities_1.default.canonicalizeName(file.name);
const candFile = this.files[nameCanon];
Log_1.default.assert(candFile === file, "Files don't match.");
this.files[nameCanon] = undefined;
this.storage.notifyFileRemoved(this.storageRelativePath + file.name);
}
_addExistingFile(file) {
const nameCanon = StorageUtilities_1.default.canonicalizeName(file.name);
if (Utilities_1.default.isUsableAsObjectKey(nameCanon)) {
this.files[nameCanon] = file;
}
}
async moveTo(newStorageRelativePath, ignoreParentSave) {
const newFolderPath = StorageUtilities_1.default.getFolderPath(newStorageRelativePath);
const newFolderName = StorageUtilities_1.default.getLeafName(newStorageRelativePath);
if (newFolderName.length < 2) {
throw new Error("New path is not correct.");
}
if (this.isSameFolder(newStorageRelativePath)) {
return false;
}
if (this.isLoaded) {
await this.load();
}
const oldPath = this._lastLoadedPath;
if (this._parentFolder !== null) {
const newParentFolder = await this._parentFolder.storage.ensureFolderFromStorageRelativePath(newFolderPath);
if (newParentFolder.folders[newFolderName] !== undefined) {
throw new Error("Folder exists at specified path.");
}
this._parentFolder._removeExistingFolderFromParent(this);
this._parentFolder = newParentFolder;
this._name = newFolderName;
newParentFolder._addExistingFolderToParent(this);
}
this._name = newFolderName;
for (const fileName in this.files) {
const file = this.files[fileName];
if (file) {
await file.resaveAfterMove();
}
}
for (const folderName in this.folders) {
const folder = this.folders[folderName];
if (folder) {
await folder.resaveAfterMove(this.fullPath);
}
}
await this.save(true);
if (oldPath) {
await localforage_1.default.removeItem(oldPath);
}
if (this._parentFolder !== null && !ignoreParentSave) {
await this._parentFolder.save(true);
}
if (!ignoreParentSave) {
this.notifyFolderMoved({ previousStoragePath: oldPath, newStoragePath: this.fullPath, folder: this });
}
return true;
}
async createFile(name) {
const file = this.ensureFile(name);
this.storage.notifyFileAdded(file);
return file;
}
async load(force) {
if (this.lastLoadedOrSaved != null && !force) {
return this.lastLoadedOrSaved;
}
this._lastLoadedPath = this.fullPath + BrowserStorage_1.default.slashFolderDelimiter;
const listingContent = await localforage_1.default.getItem(this.fullPath + BrowserStorage_1.default.slashFolderDelimiter);
if (listingContent != null) {
this._lastSavedContent = listingContent;
let folderState;
try {
folderState = JSON.parse(listingContent);
}
catch (e) {
Log_1.default.debugAlert("Failure to parse browser folder content JSON:" + e.toString());
}
if (folderState) {
for (var i = 0; i < folderState.files.length; i++) {
const fileMeta = folderState.files[i];
// JSON.parse doesn't fix up dates produced by JSON.stringify, so do that here.
if (fileMeta.modified != null && !(fileMeta.modified instanceof Date)) {
fileMeta.modified = new Date(fileMeta.modified);
}
const newFile = this.ensureFile(fileMeta.name);
newFile.modifiedAtLoad = fileMeta.modified == null ? null : fileMeta.modified;
if (newFile.sizeAtLoad === undefined) {
newFile.sizeAtLoad = fileMeta.size;
}
}
for (var j = 0; j < folderState.folders.length; j++) {
const folderMeta = folderState.folders[j];
// JSON.parse doesn't fix up dates produced by JSON.stringify, so do that here.
if (folderMeta.modified != null && !(folderMeta.modified instanceof Date)) {
folderMeta.modified = new Date(folderMeta.modified);
}
const newFolder = this.ensureFolder(folderMeta.name);
newFolder.modifiedAtLoad = folderMeta.modified;
newFolder.lastSavedFileCount = folderMeta.fileCount;
}
}
}
this.updateLastLoadedOrSaved();
return this.lastLoadedOrSaved;
}
async resaveAfterMove(newParentPath) {
this._parentPath = newParentPath;
for (const fileName in this.files) {
const file = this.files[fileName];
if (file) {
await file.resaveAfterMove();
}
}
for (const folderName in this.folders) {
const folder = this.folders[folderName];
if (folder) {
await folder.resaveAfterMove(this.fullPath);
}
}
if (this._lastLoadedPath === undefined) {
return;
}
if (this._lastLoadedPath !== StorageUtilities_1.default.ensureEndsWithDelimiter(this.fullPath)) {
const oldPath = this._lastLoadedPath;
await this.save(true);
await localforage_1.default.removeItem(oldPath);
}
}
async save(force) {
// we need to load before we save if the only thing this folder has seen is a bunch of
// /ensures/
if (!this.isLoaded) {
await this.load(false);
}
this.updateLastLoadedOrSaved();
const folderState = {
updated: this.lastLoadedOrSaved,
files: [],
folders: [],
};
for (const fileName in this.files) {
const file = this.files[fileName];
if (file !== undefined) {
const fileState = {
name: file.name,
size: file.size,
modified: file.latestModified == null ? new Date() : file.latestModified,
};
folderState.files.push(fileState);
}
}
for (const folderName in this.folders) {
const childFolder = this.folders[folderName];
if (childFolder !== undefined && !childFolder.errorStatus) {
const childFolderState = {
name: childFolder.name,
fileCount: Utilities_1.default.lengthOfDictionary(childFolder.files),
modified: childFolder.modifiedAtLoad == null ? new Date() : childFolder.modifiedAtLoad,
};
folderState.folders.push(childFolderState);
}
}
const saveContent = JSON.stringify(folderState);
if (this._lastSavedContent !== saveContent || force) {
this._lastSavedContent = saveContent;
this._lastLoadedPath = this.fullPath + BrowserStorage_1.default.slashFolderDelimiter;
await localforage_1.default.setItem(this.fullPath + BrowserStorage_1.default.slashFolderDelimiter, saveContent);
}
return this.lastLoadedOrSaved;
}
async saveAll(force) {
// Log.verbose("Saving all at " + this.storageRelativePath);
if (this.isDisposed) {
Log_1.default.throwIsDisposed();
}
const initialDateTime = new Date().getTime();
let needsContentSave = false;
for (const fileName in this.files) {
const file = this.files[fileName];
if (file !== undefined && (file.needsSave || force)) {
let newContentSaveDate = await file.saveContent(force, true);
if (newContentSaveDate.getTime() > initialDateTime) {
needsContentSave = true;
}
}
}
for (const folderName in this.folders) {
const folder = this.folders[folderName];
if (folder !== undefined && !folder.errorStatus) {
needsContentSave = true;
await folder.saveAll(force);
}
}
if (needsContentSave || this._lastSavedContent === undefined || force === true) {
await this.save(force);
}
return true;
}
}
exports.default = BrowserFolder;