@fontoxml/fontoxml-development-tools
Version:
Development tools for Fonto.
162 lines (136 loc) • 4.03 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 */
export default class FileSystemStore {
/**
* @param {DevCmsConfig} config
* @param {{[ extension: string]: string }} assetTypeByExtension
*/
constructor(config, assetTypeByExtension) {
this._filesRootPath = path.join(config.root, 'dev-cms', 'files');
this._uploadsRootPath = path.join(config.root, 'dev-cms', 'uploads');
this._assetTypeByExtension = 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 document-template-metadata.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;
}
getPathSync(filePath) {
return this._getPathForFile(filePath);
}
existsSync(filePath) {
return !!this.getPathSync(filePath);
}
load(filePath) {
return new Promise((resolve, reject) => {
const absoluteFilePath = this.getPathSync(filePath);
if (!absoluteFilePath) {
resolve(null);
return;
}
const stream = fs.createReadStream(absoluteFilePath);
let isDone = false;
let data = '';
stream.on('data', (dataPart) => (data += dataPart));
stream.on('end', () => {
if (isDone) {
return;
}
isDone = true;
resolve(data);
});
// Register the `error` event handler before starting the stream:
stream.on('error', (error) => {
if (isDone) {
return;
}
isDone = true;
reject(error);
});
stream.pipe(utf8({ newline: false, detectSize: 10485760 }));
});
}
async save(filePath, content) {
// Save file to disk (in dev-cms/uploads)
const filePathInUploads = path.join(this._uploadsRootPath, filePath);
await fs.outputFile(filePathInUploads, content);
}
removeSync(filePath) {
// Only remove from uploads, files is read-only
fs.removeSync(path.join(this._uploadsRootPath, filePath));
}
_getFileType(filePath) {
if (fs.lstatSync(filePath).isDirectory()) {
return 'folder';
}
const fileExtension = path.extname(filePath).substring(1).toLowerCase();
return this._assetTypeByExtension[fileExtension] || 'unknown';
}
_listPathSync(rootPath, folderPath, metadata) {
const folderPathInRoot = path.join(rootPath, folderPath);
if (!fs.existsSync(folderPathInRoot)) {
return null;
}
return fs
.readdirSync(folderPathInRoot)
.filter((filename) => !filename.startsWith('.'))
.map((filename) => {
const filePath = path.join(folderPathInRoot, 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(folderPath) {
const filesItems = this._listPathSync(this._filesRootPath, folderPath, {});
const uploadsItems = this._listPathSync(this._uploadsRootPath, folderPath, {
isCmsUpload: true,
});
if (!filesItems && !uploadsItems) {
return null;
}
return mergeItems(filesItems, uploadsItems);
}
}