decomment = function (str) {
var i,
curChar, nextChar,
inString = false,
inComment = false,
newStr = '';
for (i = 0; i < str.length; ++i) {
curChar = str.charAt(i);
nextChar = str.charAt(i + 1);
// it's either closing or opening inString and it is not escaped
if (!inComment && curChar === '"' && str.charAt(i - 1) !== '\\') {
inString = !inString;
}
// we are not inside of a string
if (!inString) {
// singleline comment start
if (!inComment && curChar + nextChar === '//') {
++i;
inComment = 1;
// singleline comment end
} else if (inComment === 1 && curChar === '\n') {
inComment = false;
// multiline comment start
} else if (!inComment && curChar + nextChar === '/*') {
++i;
inComment = 2;
curChar = '';
// multiline comment end
} else if (inComment === 2 && curChar + nextChar === '*/') {
++i;
inComment = false;
curChar = '';
}
if (inComment) {
curChar = '';
}
}
newStr += curChar;
}
return newStr;
}...
*
* @param {String} json.
* @param {Function} [reviver] will be called for every key and value at every
* level of the final result.
* @return {Object} parsed json object.
*/
exports.parse = function(str, reviver) {
return exports.options.parse(exports.decomment(str), reviver);
};
/**
* Replace templates with data. {{toReplace}}
*
* @param {String} json.
* @param {Object} data data hash.
...function extend(deep, obj1, obj2) {
// take first argument, if its not a boolean
var args = arguments,
i = deep === true ? 1 : 0,
key,
target = args[i];
for (++i; i < args.length; ++i) {
for (key in args[i]) {
if (deep === true &&
target[key] &&
// if not doing this check you may end in
// endless loop if using deep option
toString.call(args[i][key]) === obj &&
toString.call(target[key]) === obj) {
// create a copy of target object to avoid subobjects changes
target[key] = extend(deep, {}, target[key]);
extend(deep, target[key], args[i][key]);
} else {
target[key] = args[i][key];
}
}
}
return target;
}...
exports.load = function load(path, options) {
var data, paths, conf;
if (options === true) {
options = {merge: true};
}
options = exports.extend({}, exports.options, options);
if (Array.isArray(path)) {
conf = {};
path.forEach(function(path) {
if (fs.existsSync(path)) {
var data = load(path, options),
filename;
...function freeze(obj) {
var key;
if (obj instanceof Object) {
for (key in obj) {
freeze(obj[key]);
}
Object.freeze(obj);
}
}...
var key;
if (obj instanceof Object) {
for (key in obj) {
freeze(obj[key]);
}
Object.freeze(obj);
}
};
/**
* Load and parse a config file/files.
*
* @param {String|Array} path absolute path/paths to the file/files or dir.
...function load(path, options) {
var data, paths, conf;
if (options === true) {
options = {merge: true};
}
options = exports.extend({}, exports.options, options);
if (Array.isArray(path)) {
conf = {};
path.forEach(function(path) {
if (fs.existsSync(path)) {
var data = load(path, options),
filename;
if (options.merge) {
exports.extend(true, conf, data);
} else {
filename = Path.basename(path, options.ext);
conf[filename] = data;
}
}
});
return conf;
}
if (fs.statSync(path).isDirectory()) {
paths = [];
fs.readdirSync(path).forEach(function(filename) {
var file = Path.join(path, filename);
if (Path.extname(file) == options.ext && fs.statSync(file).isFile()) {
paths.push(file);
}
});
return load(paths, options);
}
data = fs.readFileSync(path, 'utf-8');
// replace BOM Character
data = data.replace(/\ufeff/g, '');
if (options.replace) {
data = exports.replace(data, options.replace);
}
try {
data = exports.parse(data);
} catch(err) {
err.message += '\nFile: "' + path + '"';
throw err;
}
if (options.freeze) {
exports.freeze(data);
}
return data;
}...
```
## API
### load the module
var cjson = require('cjson');
### cjson.load(path, [options]);
Load config file from given path, array of paths or directory. Second parameter is optional and can be a boolean or object.
- `path` {String|Array} absolute path to the file, array of paths or directory
- `options` {Boolean|Object} optional options. If you pass `true` as second param, its the same like ` {merge: true}` and will
merge all configs together.
...parse = function (str, reviver) {
return exports.options.parse(exports.decomment(str), reviver);
}...
*
* @param {String} json.
* @param {Function} [reviver] will be called for every key and value at every
* level of the final result.
* @return {Object} parsed json object.
*/
exports.parse = function(str, reviver) {
return exports.options.parse(exports.decomment(str), reviver);
};
/**
* Replace templates with data. {{toReplace}}
*
* @param {String} json.
* @param {Object} data data hash.
...replace = function (str, data) {
return str.replace(/\{\{([^}]+)\}\}/g, function(match, search) {
if (data.hasOwnProperty(search)) {
// If the variable is an object, stringify it before replacement.
// The false positive of "null" is fine in this case.
if (typeof data[search] === 'object') {
return JSON.stringify(data[search]);
}
return data[search];
}
return match;
});
}...
* Replace templates with data. {{toReplace}}
*
* @param {String} json.
* @param {Object} data data hash.
* @return {String} json string with replaced data.
*/
exports.replace = function(str, data) {
return str.replace(/\{\{([^}]+)\}\}/g, function(match, search) {
if (data.hasOwnProperty(search)) {
// If the variable is an object, stringify it before replacement.
// The false positive of "null" is fine in this case.
if (typeof data[search] === 'object') {
return JSON.stringify(data[search]);
}
return data[search];
...function parse(text, reviver) {
try {
return JSON.parse(text, reviver);
} catch (err) {
// we expect this to throw with a more informative message
jju.parse(text, {
mode: 'json',
reviver: reviver
});
// backup if jju is not as strict as JSON.parse; re-throw error
// data-dependent code path, I do not know how to cover it
throw err;
}
}...
*
* @param {String} json.
* @param {Function} [reviver] will be called for every key and value at every
* level of the final result.
* @return {Object} parsed json object.
*/
exports.parse = function(str, reviver) {
return exports.options.parse(exports.decomment(str), reviver);
};
/**
* Replace templates with data. {{toReplace}}
*
* @param {String} json.
* @param {Object} data data hash.
...