cm-spyglass
Version:
A Codemirror extension that provides syntax highlighting, linting, and autocompletion for Minecraft datapacks using SpyglassMC
131 lines (116 loc) • 3.03 kB
JavaScript
import DummyFsWatcher from "./DummyFsWatcher.js";
import {fileUtil} from "@spyglassmc/core";
import Base64 from "../Util/Base64.js";
/**
* @implements {import("@spyglassmc/core").ExternalFileSystem}
*/
export default class LocalStorageFileSystem {
static KEY_PREFIX = 'spyglassmc-browser-fs';
/** @type {Object} */ states;
/** @type {string} */ id;
/**
* @param {string} id
*/
constructor(id) {
this.id = id;
this.states = JSON.parse(localStorage.getItem(this.getKey()) ?? '{}');
}
/**
* Save the states to local storage
*/
saveStates() {
localStorage.setItem(this.getKey(), JSON.stringify(this.states));
}
/**
* Get the key for the states in local storage
*
* @return {string}
*/
getKey() {
return `${this.constructor.KEY_PREFIX}-${this.id}`;
}
/**
* @inheritDoc
*/
async chmod(_location, _mode) {
}
/**
* @inheritDoc
*/
async mkdir(location, _options) {
location = fileUtil.ensureEndingSlash(location.toString());
if (this.states[location]) {
throw new Error(`EEXIST: ${location}`);
}
this.states[location] = { type: 'directory' };
this.saveStates();
}
/**
* @inheritDoc
*/
async readdir(_location) {
// Not implemented
return [];
}
/**
* @inheritDoc
*/
async readFile(location) {
location = location.toString();
let entry = this.states[location];
if (!entry) {
throw new Error(`ENOENT: ${location}`);
}
else if (entry.type === 'directory') {
throw new Error(`EISDIR: ${location}`);
}
return Base64.decode(entry.content);
}
/**
* @inheritDoc
*/
async showFile(_path) {
throw new Error('showFile not supported on browser');
}
/**
* @inheritDoc
*/
async stat(location) {
location = location.toString();
let entry = this.states[location];
if (!entry) {
throw new Error(`ENOENT: ${location}`);
}
return { isDirectory: () => entry.type === 'directory', isFile: () => entry.type === 'file' };
}
/**
* @inheritDoc
*/
async unlink(location) {
location = location.toString();
let entry = this.states[location];
if (!entry) {
throw new Error(`ENOENT: ${location}`);
}
delete this.states[location];
this.saveStates();
}
/**
* @inheritDoc
*/
watch(_locations) {
return new DummyFsWatcher();
}
/**
* @inheritDoc
*/
async writeFile(location, data, _options) {
location = location.toString();
if (typeof data === 'string') {
data = new TextEncoder().encode(data);
}
data = Base64.encode(data);
this.states[location] = { type: 'file', content: data };
this.saveStates();
}
}