'use strict';
'use strict';
Loads a config file from a given path. Generates an API based on permissions requested.
/**
* Supplies the root menu for program opperation,
* if commandline arguments supplied, moves user to the correct jump point.
* @author Jon L-W
* @module json-config-interface
* @requires module:fs
* @requires module:bluebird
*/
var fs = require('fs')
, Q = require('q')
configCache
Object that stores loaded JSON config files indexed by path,
Anywhere a config file is required, the same data object is returned to act upon,
ensuring data integrity across a project.
, configCache = {}
base path used to prepend path
param provided to get()
, configBasePath = '';
setDir
- specify base directory to load configs fromget
- get a configuration files data and methods to act upon itpurge
- cache clearing operations/**
* Sets the base working directory to load JSON config files from.
* @param {string} basePath=false - the path to the directory to load config files in
* @returns {bool} true on good directory, false on bad directory
* @throws {badParam} basePath param not provided, or not string
* @throws {nonDir} basePath does not point to a directory
*/
module.exports.setDir = function(basePath = false){
if not a good parameter
if(!basePath || typeof basePath !== 'string'){
throw badParam
throw new Error('badParam');
return false;
}
try {
Query provided path string
var stats = fs.lstatSync(basePath);
if it is a directory
if (stats.isDirectory()) {
set basePath to module var for usage during exports.get
configBasePath = basePath;
return true;
}
else{
throw nonDir
throw new Error('nonDir')
}
}
throw any lstatSync errors up to caller
catch (err) {
throw err;
return false;
}
}
/**
* @typedef ConfigAPI
* @type Object
* @property {object} data - the parsed JSON config file
* @property {function} [save] - method to save any changes back to JSON config file
* @property {function} [revert] - rollback any changes made in .data to state when it was loaded
*/
/**
* Request a config file be loaded, assign API methods based on permision arg.
* @param {string} path - The location of the config file.
* @param {string} [permision='read'] - If `"write"` the config api will be returned with save and revert methods
* @param {boolean} [noCache=false] - If `true` will ignore cached instances of config file
* @return {Promise<ConfigAPI|Error>}
* @throws {badParam} path param undefined or not a string
* @throws {fs.stat.err} any errors during fs.stat
* @throws {fs.readFileSync.err} any errors during fs.readFileSync
*/
module.exports.get = function(path, permision='read', noCache=false){
var deferred = Q.defer()
configAPI
object to be returned containing the JSON object .data
and if permision=='write'
the save()
& revert()
methods that act upon the
, configAPI = {};
build full path string using configBasePath and path
if(path!==undefined && typeof path === 'string'){
if path name supplied without .json
extension, add it
if(path.indexOf('.json')===-1){
path += '.json';
}
if path contains ./
at it’s begining, don’t add base class, as this is a relative path
else
var configPath = (/^\.\//.exec(path)!==null ? path : (path[0] === '/' ? configBasePath + path : configBasePath + '/' + path))
}
else{
deferred.reject(new Error('badParam'));
return deferred.promise;
}
console.log(configPath)
define configAPI.data
with false
configAPI.data = false;
if write permmision set, attach the save method to configAPI
if(permision==='write'){
setup write API
var original = false
save()
, save = function(){
var saveDeferred = Q.defer();
Stringify to JSON with indentation of 2 spaces and write to config file
fs.writeFile(configPath, JSON.stringify(configAPI.data, null, 2), function(err){
if(err){
if write error, reject promise with err
object
saveDeferred.reject(err);
}
else{
if write success, resolve with true
val
saveDeferred.resolve(true);
}
});
return saveDeferred.promise;
}
revert()
, revert = function(){
configAPI.data = original;
return configAPI;
}
assign save and revert to configAPI
configAPI.save = save;
configAPI.revert = revert;
}
if(configCache[configPath]!==undefined && !noCache){
set property configAPI.data
as the previously parsed JSON object
configAPI.data = configCache[configPath];
original = function(){ return JSON.parse(JSON.stringify(configCache[configPath])); }();
return resolved
return Q(configAPI);
}
fs.stat(configPath, function(err, stat){
if no error in file stat
if(err == null) {
try to read file and parse JSON to var
try{
var jsonContents = fs.readFileSync(configPath, 'utf8');
var parsedJSONdata = JSON.parse(jsonContents);
}
catch any errors during read or parse, if so reject with error
catch(err) {
deferred.reject(err);
}
if good load and parse
if(parsedJSONdata!==undefined){
add loaded config to cache
if(!noCache){
configCache[configPath] = parsedJSONdata;
}
assign fileData to property data of the config object
configAPI.data = parsedJSONdata;
make clone of config file to be used if revert method is called of API
configAPI.original = JSON.parse(JSON.stringify(parsedJSONdata));
resolve with the built configAPI
deferred.resolve(configAPI);
}
}
catch all for errors in reading config
else{
deferred.reject(err);
}
});
return deferred.promise;
}
/**
* Cleans entire cache or cleans cache of specific file if path provided
* @param {string} [path] The location of the config file to purge from cache. If not provided, cleans entire cache
* @return {boolean} true for successful purges, false if path supplied and not found in cache
*/
module.exports.purge = function(path){
if no path
then clean entire cache
if(path===undefined){
configCache = {};
return true;
}
if path given and index in the object not undefined.
if(configCache[path]!==undefined){
set the cache for path to undefined
configCache[path] = undefined;
return true;
}
return false;
}