@fontoxml/fontoxml-development-tools
Version:
Development tools for Fonto.
243 lines (211 loc) • 6.21 kB
JavaScript
import FileSystemStore from './FileSystemStore.js';
import HistoryStore from './HistoryStore.js';
import MemoryStore from './MemoryStore.js';
import mergeItems from './mergeItems.js';
/** @typedef {import('../../../src/getAppConfig.js').DevCmsConfig} DevCmsConfig */
export default class DevelopmentCms {
/**
* @param {DevCmsConfig} config
*/
constructor(config) {
this._memoryStoreById = Object.create(null);
this._memoryStoreCleanupById = Object.create(null);
this._fileSystem = new FileSystemStore(config);
this._history = new HistoryStore(this);
/** @type {DevCmsConfig['memoryStoreTtl']} */
this._memoryStoreTtl = config.memoryStoreTtl;
/** @type {DevCmsConfig['saveMode']} */
this._saveMode = config.saveMode;
}
_getOrCreateMemoryStore(editSessionToken) {
const memoryStoreId =
this._saveMode === 'shared-memory'
? 'shared-memory-store-id'
: editSessionToken;
let memoryStore = this._memoryStoreById[memoryStoreId];
if (!memoryStore) {
memoryStore = this._memoryStoreById[memoryStoreId] =
new MemoryStore();
}
if (this._memoryStoreTtl < 0) {
return memoryStore;
}
if (this._memoryStoreCleanupById[memoryStoreId]) {
clearTimeout(this._memoryStoreCleanupById[memoryStoreId]);
}
this._memoryStoreCleanupById[memoryStoreId] = setTimeout(() => {
delete this._memoryStoreCleanupById[memoryStoreId];
delete this._memoryStoreById[memoryStoreId];
}, this._memoryStoreTtl);
return memoryStore;
}
/**
* @param {string} documentId path of document relative to dev-cms/files
* @param {string} editSessionToken
* @param {function(Error, string)} callback called with content of document
*/
load(documentId, editSessionToken, callback) {
// Load from memory or the file system
this._getOrCreateMemoryStore(editSessionToken).load(
documentId,
(error, content) => {
if (error) {
this._fileSystem.load(documentId, callback);
return;
}
callback(null, content);
}
);
}
/**
* @param {string} documentId path of document relative to dev-cms/files
* @param {string} editSessionToken
* @param {function(Error, string)} callback called with the revisionId
*/
getLatestRevisionId(documentId, editSessionToken, callback) {
this._history.getLatestRevisionId(
documentId,
editSessionToken,
callback
);
}
/**
* @param {string} documentId
* @param {string} editSessionToken
*
* @return {string} absolute path
*/
getPath(documentId, _editSessionToken) {
return this._fileSystem.getPath(documentId);
}
/**
* @param {string} documentId
* @param {string} editSessionToken
*
* @return {boolean}
*/
existsSync(documentId, editSessionToken) {
return (
this._getOrCreateMemoryStore(editSessionToken).existsSync(
documentId
) || this._fileSystem.existsSync(documentId)
);
}
saveToStore(documentId, content, editSessionToken, callback) {
function handleSaveToStore(error) {
callback(error, documentId);
}
switch (this._saveMode) {
case 'session-memory':
case 'shared-memory':
this._getOrCreateMemoryStore(editSessionToken).save(
documentId,
content,
handleSaveToStore
);
return;
default:
this._fileSystem.save(documentId, content, handleSaveToStore);
}
}
/**
* @param {string} documentId
* @param {string} content
* @param {FontoSession} currentSession
* @param {function(Error)} callback
*/
save(documentId, content, currentSession, callback) {
// If saveMode is off, saving to non-existing documents should not error. Is might be that this document is newly created.
if (!this.existsSync(documentId, currentSession.editSessionToken)) {
const error = new Error('File does not exist.');
error.status = 404;
callback(error);
return;
}
// First save history, then the actual document
this._history.save(documentId, content, currentSession, (error) => {
if (error) {
callback(error);
return;
}
this.saveToStore(
documentId,
content,
currentSession.editSessionToken,
callback
);
});
}
/**
* @param {string} documentId
* @param {string} content
* @param {FontoSession} currentSession
* @param {function(Error)} callback
*/
createNew(documentId, content, currentSession, callback) {
if (this.existsSync(documentId, currentSession.editSessionToken)) {
const error = new Error('File already exists.');
error.status = 409;
callback(error);
return;
}
// First create new history, then the actual document
this._history.createNew(
documentId,
content,
currentSession,
(error, _revisions) => {
if (error) {
callback(error);
return;
}
this.saveToStore(
documentId,
content,
currentSession.editSessionToken,
callback
);
}
);
}
removeSync(documentId, editSessionToken) {
this._getOrCreateMemoryStore(editSessionToken).removeSync(documentId);
this._fileSystem.removeSync(documentId);
}
/**
* @param {string} folderId
* @param {string} editSessionToken
*
* @return {Object[]|null} items in folder, combined from all stores, or null if the folder does not exist.
*/
listSync(folderId, editSessionToken) {
folderId = folderId || '';
const fileSystemItems = this._fileSystem.listSync(folderId);
const memoryItems =
this._getOrCreateMemoryStore(editSessionToken).listSync(folderId);
if (!fileSystemItems && !memoryItems) {
return null;
}
return mergeItems(fileSystemItems, memoryItems);
}
/**
* @param {string} documentId
* @param {function(Error, Object[])} callback
*/
loadHistory(documentId, editSessionToken, callback) {
this._history.loadHistory(documentId, editSessionToken, callback);
}
/**
* @param {string} documentId
* @param {string} revisionId
* @param {function(Error, string)} callback
*/
loadRevision(documentId, revisionId, editSessionToken, callback) {
this._history.loadRevision(
documentId,
revisionId,
editSessionToken,
callback
);
}
}