Skip to content

Commit

Permalink
Fixed yaml loader bug
Browse files Browse the repository at this point in the history
  • Loading branch information
pmendelski committed Feb 21, 2015
1 parent f202c54 commit 86f0a6e
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 10 deletions.
54 changes: 48 additions & 6 deletions lib/load/merge-parents.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
'use strict';

var mergeConfigs = require('./merge-configs'),
path = require('path'),
parse = require('./parse'),
resolvePath = require('./resolve-path'),
path = require('path');
resolvePath = require('./resolve-path');

module.exports.async = function(configPath, opts, callback) {
opts = opts || {};
Expand Down Expand Up @@ -35,7 +35,7 @@ function mergeParentsAsync(configPath, opts, callback) {
var parentField = opts.parentField;
callback = callback || opts;

parse.load(configPath, function(err, config) {
loadAsync(configPath, opts, function(err, config) {
if (err) return callback(err);
var parentPathValue = parentField ? config[parentField] : null,
mergeParentsAsyncCallback = function(err, flatParent) {
Expand All @@ -58,26 +58,68 @@ function mergeParentsAsync(configPath, opts, callback) {

function mergeParentsSync(configPath, opts) {
var parentField = opts ? opts.parentField : null,
config = parse.loadSync(configPath),
config = loadSync(configPath, opts),
parentPathValue = parentField ? config[parentField] : null,
parentPath = resolvePath.sync(parentPathValue, [path.dirname(configPath), opts ? opts.basedir : null]),
parentConfig, result;
if (!parentPathValue) return config;
if (!parentPath) {
if (!isOptional(parentPathValue, opts)) throw parentConfigNotFound(parentPathValue, configPath);
parentConfig = {};
result = config;
} else {
parentConfig = mergeParentsSync(parentPath, opts);
result = mergeConfigs([parentConfig, config]);
}
result = mergeConfigs([parentConfig, config]);
if (parentField) delete result[parentField];
return result;
}

function loadAsync(configPath, opts, callback) {
resolvePath.async(configPath, [opts.basedir], function(configResolvedPath) {
if (!configResolvedPath) {
if (isOptional(configPath, opts)) return callback(null, {});
return callback(configNotFound(configPath));
}
parse.load(configResolvedPath, function(err, config) {
return callback(err, config);
});
});
}

function loadSync(configPath, opts) {
opts = opts || {};
var configResolvedPath = resolvePath.sync(configPath, [opts.basedir]);
if (!configResolvedPath) {
if (isOptional(configPath, opts)) return {};
throw configNotFound(configPath);
}
return parse.loadSync(configPath);
}

function isOptional(configPath, opts) {
var optional = opts.optional;
if (!optional) return false;
if (!Array.isArray(optional)) optional = [optional];
if (optional.indexOf(configPath) >= 0) return true;
return optional.some(function(optional) {
if (optional.indexOf('*') >= 0) {
// regex
optional = escapeRegExp(optional);
optional = optional.replace(/\\\*\\\*/, '.|').replace(/\\\*/, '[^/]*');
return new RegExp(optional).test(configPath);
}
return false;
});
}

function configNotFound(configPath) {
return new Error('Config file not found \'' + configPath);
}

function parentConfigNotFound(parentPath, configPath) {
return new Error('Parent config file not found \'' + parentPath + '\' for ' + configPath);
}

function escapeRegExp(str) {
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
}
6 changes: 3 additions & 3 deletions lib/load/parse/yaml.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,22 +31,22 @@ function loadSync(filePath) {

function parse(content, callback) {
process.nextTick(function() {
var result = '';
var result;
if (!content || !content.trim().length) return callback(null, {});
content = normalizeContent(content);
try {
result = yaml.safeLoad(content);
} catch(e) {
return callback(e);
}
callback(null, result);
callback(null, result || {});
});
}

function parseSync(content) {
if (content && !content.trim().length) return {};
content = normalizeContent(content);
return yaml.safeLoad(content);
return yaml.safeLoad(content) || {};
}

function normalizeContent(content) {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"author": "Paweł Mendelski <pawel.mendelski@coditorium.com>",
"name": "read-config",
"version": "1.0.1",
"version": "1.1.1",
"description": "JSON configuration loader",
"main": "index.js",
"license": "MIT",
Expand Down
34 changes: 34 additions & 0 deletions test/load/merge-parents/merge-parents.unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,40 @@ function cases(name, mergeParents) {
});
});

it('should not return an error on not existing optional parent', function(done) {
var configPath = path.resolve(__dirname, 'configs', 'config-error.json'),
opts = {
parentField: '__parent',
optional: 'xxx',
basedir: path.resolve(__dirname, 'configs', 'basedir')
};
mergeParents(configPath, opts, function(err, config) {
expect(err).to.not.exist;
expect(config).to.be.eql({
b: 22,
c: 33
});
done();
});
});

it('should not return an error on not existing optional parent - defined with regex', function(done) {
var configPath = path.resolve(__dirname, 'configs', 'config-error.json'),
opts = {
parentField: '__parent',
optional: '*',
basedir: path.resolve(__dirname, 'configs', 'basedir')
};
mergeParents(configPath, opts, function(err, config) {
expect(err).to.not.exist;
expect(config).to.be.eql({
b: 22,
c: 33
});
done();
});
});

it('should not return error on optional not existing parent', function(done) {
var configPath = path.resolve(__dirname, 'configs', 'config-error.json'),
opts = {
Expand Down
Empty file added test/load/parse/yaml/empty.yml
Empty file.
16 changes: 16 additions & 0 deletions test/load/parse/yaml/load.unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ describe("YAML.load test:", function() {

var validYamlFile = path.resolve(__dirname, './valid.yml'),
validYaml = { x: 'a' },
emptyYamlFile = path.resolve(__dirname, './empty.yml'),
invalidYamlFile = path.resolve(__dirname, './invalid.yml');

describe("should loadSync yaml document", function() {
Expand All @@ -24,6 +25,12 @@ describe("YAML.load test:", function() {
}).to.throw();
});

it("and return empty object", function() {
var result = yaml.loadSync(emptyYamlFile);
expect(result).to.exist;
expect(result).to.be.eql({});
});

});

describe("should loadAsync yaml document", function() {
Expand All @@ -45,6 +52,15 @@ describe("YAML.load test:", function() {
});
});

it("and return empty object", function(done) {
yaml.load(emptyYamlFile, function(err, result) {
if (err) return done(err);
expect(result).to.exist;
expect(result).to.be.eql({});
done();
});
});

});

});
6 changes: 6 additions & 0 deletions test/load/parse/yaml/parse.unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ describe("YAML.parse module test:", function() {
}).to.throw();
});

it("and return empty object on empty json", function() {
var result = yaml.parseSync('');
expect(result).to.exist;
expect(result).to.be.eql({});
});

});

describe("should parse yaml document", function() {
Expand Down

0 comments on commit 86f0a6e

Please sign in to comment.