@fontoxml/fontoxml-development-tools
Version:
Development tools for Fonto.
201 lines (171 loc) • 4.45 kB
JavaScript
import fs from 'fs-extra';
import path from 'path';
import utf8 from 'to-utf-8';
import mergeItems from './mergeItems.js';
/** @typedef {import('../../../src/getAppConfig.js').DevCmsConfig} DevCmsConfig */
/**
* File extensions to use for specific fileType requests.
* This is used to construct the query string in the browse endpoint to retrieve the correct files from Google Drive.
*
* @type {Object}
*/
const ASSET_TYPE_BY_EXTENSION = {
xml: 'document',
dita: 'document',
ditamap: 'document',
template: 'document-template',
bmp: 'image',
gif: 'image',
jpeg: 'image',
jpg: 'image',
png: 'image',
svg: 'image',
mp3: 'audio',
wav: 'audio',
aac: 'audio',
ogg: 'audio',
};
export default class FileSystemStore {
/**
* @param {DevCmsConfig} config
*/
constructor(config) {
this._filesRootPath = path.join(config.root, 'dev-cms', 'files');
this._uploadsRootPath = path.join(config.root, 'dev-cms', 'uploads');
this._assetTypeByExtension = {
...ASSET_TYPE_BY_EXTENSION,
...config.assetTypeByExtension,
};
this._documentTemplateMetadataByFilename = {};
const documentTemplateMetadataJsonPath = path.join(
config.root,
'dev-cms',
'stubs',
'document-template-metadata.json'
);
if (fs.existsSync(documentTemplateMetadataJsonPath)) {
try {
this._documentTemplateMetadataByFilename = fs.readJsonSync(
documentTemplateMetadataJsonPath
);
} catch (error) {
console.error(
`\nError reading history.json file at "${documentTemplateMetadataJsonPath}"`,
error
);
throw error;
}
}
}
_getPathForFile(fileRelativePath) {
if (!fileRelativePath || fileRelativePath === '.') {
return null;
}
const pathInUploads = path.join(
this._uploadsRootPath,
fileRelativePath
);
if (fs.existsSync(pathInUploads)) {
return pathInUploads;
}
const pathInFiles = path.join(this._filesRootPath, fileRelativePath);
if (fs.existsSync(pathInFiles)) {
return pathInFiles;
}
return null;
}
getPath(documentId) {
return this._getPathForFile(documentId);
}
existsSync(documentId) {
return !!this.getPath(documentId);
}
load(documentId, callback) {
const filePath = this.getPath(documentId);
if (!filePath) {
const error = new Error('File does not exist.');
error.status = 404;
callback(error);
return;
}
const stream = fs.createReadStream(filePath);
let isDone = false;
let data = '';
stream.on('data', (dataPart) => (data += dataPart));
stream.on('end', () => {
if (isDone) {
return;
}
isDone = true;
callback(undefined, data);
});
// Register the `error` event handler before starting the stream:
stream.on('error', (error) => {
if (isDone) {
return;
}
isDone = true;
callback(error)
});
stream.pipe(utf8({ newline: false, detectSize: 10485760 }));
}
save(documentId, content, callback) {
// Save file to disk (in dev-cms/uploads)
const filePath = path.join(this._uploadsRootPath, documentId);
fs.outputFile(filePath, content, callback);
}
removeSync(documentId) {
// Only remove from uploads, files is read-only
fs.removeSync(path.join(this._uploadsRootPath, documentId));
}
_getFileType(filePath) {
if (fs.lstatSync(filePath).isDirectory()) {
return 'folder';
}
const fileExtension = path.extname(filePath).substring(1).toLowerCase();
return this._assetTypeByExtension[fileExtension] || 'unknown';
}
_listPathSync(rootPath, folderId, metadata) {
const folderPath = path.join(rootPath, folderId);
if (!fs.existsSync(folderPath)) {
return null;
}
return fs
.readdirSync(folderPath)
.filter((filename) => !filename.startsWith('.'))
.map((filename) => {
const filePath = path.join(folderPath, filename);
let fileId = path.relative(rootPath, filePath);
if (path.sep === '\\') {
fileId = fileId.replace(/\\/g, '/');
}
return {
id: fileId,
type: this._getFileType(filePath),
label: filename,
metadata: {
...metadata,
...this._documentTemplateMetadataByFilename[filename],
},
};
});
}
listSync(folderId) {
const filesItems = this._listPathSync(
this._filesRootPath,
folderId,
{}
);
const uploadsItems = this._listPathSync(
this._uploadsRootPath,
folderId,
{
isCmsUpload: true,
}
);
if (!filesItems && !uploadsItems) {
return null;
}
return mergeItems(filesItems, uploadsItems);
}
}