gengojs-default-memory
Version:
The default memory backend plugin for gengojs
171 lines (170 loc) • 5.86 kB
JavaScript
/*Imports*/
import yaml from 'js-yaml';
import path from 'path';
import glob from 'glob';
import globwatch from 'globwatcher';
import json from 'read-json';
import fs from 'fs';
import _ from 'lodash';
import debug from 'gengojs-debug';
import toml from 'toml';
const log = debug('backend');
/**
* This class manages the backend for gengojs.
* @class Memory
*/
class Memory {
constructor(options) {
// Set directory
this.directory = (() => {
var directory = path.normalize(options.directory);
if (directory[directory.length - 1] !== path.sep)
return directory + path.sep;
else return directory;
})();
// Set extension
this.extension = options.extension;
// Set prefix
this.prefix = options.prefix;
// Set cache
this.cache = options.cache;
// Check that the extension has a '.'
if (!/\./.test(this.extension))
this.extension = '.' + this.extension.replace('.yml', '.yaml');
// Set path
this.path = this.directory + '*' + this.extension;
log.debug('directory:', this.directory);
this.data = {};
// Check cache and read all files
if (this.cache) this.read();
else {
var watcher = globwatch.globwatcher(this.path);
watcher.on('changed', () => this.read());
watcher.on('added', () => this.read());
watcher.on('deleted', () => this.read());
watcher.ready.then(() => {
this.read();
log.info('Memory is actively watching ' + this.directory);
});
}
}
/**
* Loads the dictionary asyncronously
* and calls the callback when all is done.
* @param {Function} callback The callback function
* @return {Object} The dictionary
*/
read(callback) {
var dictionary = {};
// Pass the context as 'this' and
//read all the files with respect to its extension.
glob(this.path, (() => {
return (error, files) => {
log.debug('files:', files, 'errors:', error);
// Read if this is a JSON file.
if (/.json/.test(this.extension))
files.forEach(file => json(file, (error, data) => {
try {
if (error || !data)
throw new Error('Whoops! Is your JSON file in proper format?');
else {
dictionary[this.normalize(file.split('/').pop())] = data;
this.data = dictionary;
if (_.isFunction(callback)) callback(dictionary);
}
} catch (error) {
log.error(error.stack || String(error));
}
}));
// Read if this is a TOML file.
if (/.toml/.test(this.extension))
files.forEach(file => fs.readFile(file, (error, data) => {
try {
if (error || !data)
throw new Error('Whoops! Is your YAML file in proper format?');
else {
dictionary[
this.normalize(file.split('/').pop())
] = toml.parse(data);
this.data = dictionary;
if (_.isFunction(callback)) callback(dictionary);
}
} catch (error) {
log.error(error.stack || String(error));
}
}));
// Read if this is a YAML file.
if (/.yaml/.test(this.extension))
files.forEach(file => fs.readFile(file, (error, data) => {
try {
if (error || !data)
throw new Error('Whoops! Is your YAML file in proper format?');
else {
dictionary[
this.normalize(file.split('/').pop())
] = yaml.safeLoad(data);
this.data = dictionary;
if (_.isFunction(callback)) callback(dictionary);
}
} catch (error) {
log.error(error.stack || String(error));
}
}));
// Read if this is a Javascript file.
if (!/.json/.test(this.extension) && /.js/.test(this.extension))
files.forEach(file => {
dictionary[this.normalize(file.split('/').pop())] = require(file);
if (_.isFunction(callback)) callback(dictionary);
});
};
})());
}
/**
* Returns the entire dictionary
* @param {String} locale The key to the dictionary.
* @return {Object} The dictionary
*/
catalog(locale) {
return locale ? this.find(locale) : this.data;
}
/**
* Searches for the dictionary
* @param {String} locale The key to the dictionary.
* @return {Object} The dictionary for the specified locale.
*/
find(locale) {
return this.data[locale] || this.data[locale.toLowerCase()];
}
/**
* Determines whether the dictionary exists
* @param {String} locale The key to the dictionary.
* @return {Boolean} True if the locale exists.
*/
has(locale) {
return (this.data[locale] || this.data[locale.toLowerCase()]) ? true : false;
}
/**
* Normalizes the files
* @param {String} file The file path.
* @return {String} The normalized file path.
* @private
*/
normalize(file) {
file = file.toLowerCase().replace(this.extension, '').replace('_', '-');
if (file.indexOf(this.prefix) > -1) file = file.replace(this.prefix, '');
return file;
}
}
// Export
export default () => {
'use strict';
return {
main: function() {
this.backend = new Memory(this.options.backend);
},
package: _.merge({
type: 'backend'
}, require('../package')),
defaults: require('../defaults')
};
};