grunt-yaml-validator
Advanced tools
Comparing version 0.4.0 to 0.5.0
{ | ||
"name": "grunt-yaml-validator", | ||
"description": "Validate Yaml files and enforce a given structure", | ||
"version": "0.4.0", | ||
"version": "0.5.0", | ||
"homepage": "https://github.com/paazmaya/grunt-yaml-validator", | ||
@@ -6,0 +6,0 @@ "author": { |
@@ -67,5 +67,7 @@ # grunt-yaml-validator | ||
All options are `false` by default which disables their use. | ||
#### options.log | ||
Type: `string|boolean` | ||
Type: `string` | ||
@@ -84,3 +86,3 @@ Default value: `false` | ||
Default value: `[]` | ||
Default value: `false` | ||
@@ -91,5 +93,5 @@ An array to list the property structure which the Yaml files should contain. | ||
Type: `Object` | ||
Type: `object` | ||
Default value: `null` | ||
Default value: `false` | ||
@@ -107,3 +109,3 @@ Options passed to [`safeload` method of `js-yaml`](https://github.com/nodeca/js-yaml#safeload-string---options-). | ||
Default: `'null'` | ||
Default: `false` | ||
@@ -123,7 +125,2 @@ The given object, when not null, is passed directly to [the `matches()` method](https://github.com/alistairjcbrown/check-type#example-checking-object-properties-using-matches). | ||
defaults: { | ||
options: { | ||
log: false, | ||
keys: [], | ||
yaml: null | ||
}, | ||
src: ['configuration/*.yml', 'other/important/*_stuff.yml'] | ||
@@ -256,2 +253,3 @@ } | ||
* v0.4.0 (2014-10-30) Added type checking configuration option | ||
* v0.5.0 (2014-10-31) Default option values unified to be false. Multitasking fixed. | ||
@@ -258,0 +256,0 @@ ## License |
@@ -12,108 +12,160 @@ /** | ||
var yaml = require('js-yaml'), | ||
check = require('check-type').init(); | ||
check = require('check-type').init(), | ||
grunt = require('grunt'); | ||
module.exports = function(grunt) { | ||
var options, | ||
logs = [], | ||
mismatchedTypes = [], // list of filepaths | ||
missingKeys = 0; | ||
var YamlValidatore = function(files, options) { | ||
this.files = files; | ||
this.options = options; | ||
this.logs = []; | ||
this.mismatchedTypes = []; // list of filepaths | ||
this.missingKeys = 0; | ||
}; | ||
/** | ||
* Wrapper to call Grunt API and store message for | ||
* possible later use by writing a log file. | ||
* @param {string} msg Error message | ||
*/ | ||
var errored = function (msg) { | ||
logs.push(msg); | ||
grunt.log.error(msg); | ||
}; | ||
/** | ||
* Check that the given object matches the given key structure. | ||
* @param {Object} doc Object loaded from Yaml file | ||
* @param {string|Array} keys List of required keys | ||
* @returns {Array} List of missing keys | ||
*/ | ||
var checkKeys = function checkKeys(doc, keys) { | ||
var missing = []; | ||
/** | ||
* Wrapper to call Grunt API and store message for | ||
* possible later use by writing a log file. | ||
* @param {string} msg Error message | ||
*/ | ||
YamlValidatore.prototype.errored = function errored(msg) { | ||
this.logs.push(msg); | ||
grunt.log.error(msg); | ||
}; | ||
if (typeof keys === 'string') { | ||
keys = [keys]; | ||
/** | ||
* Check that the given object matches the given key structure. | ||
* @param {Object} doc Object loaded from Yaml file | ||
* @param {string|Array} keys List of required keys | ||
* @returns {Array} List of missing keys | ||
*/ | ||
YamlValidatore.prototype.checkKeys = function checkKeys(doc, keys) { | ||
var missing = []; | ||
if (typeof keys === 'string') { | ||
keys = [keys]; | ||
} | ||
keys.forEach(function (key) { | ||
var has = check(doc).has(key); | ||
if (!has) { | ||
missing.push(key); | ||
} | ||
keys.forEach(function (key) { | ||
var has = check(doc).has(key); | ||
if (!has) { | ||
missing.push(key); | ||
} | ||
}); | ||
}); | ||
return missing; | ||
}; | ||
return missing; | ||
}; | ||
/** | ||
* | ||
* @param {Object} doc Object loaded from Yaml file | ||
* @param types | ||
*/ | ||
var checkTypes = function checkTypes(doc, types) { | ||
return check(doc).matches(types); | ||
}; | ||
/** | ||
* | ||
* @param {Object} doc Object loaded from Yaml file | ||
* @param types | ||
*/ | ||
YamlValidatore.prototype.checkTypes = function checkTypes(doc, types) { | ||
var checked = check(doc).matches(types); | ||
return checked; | ||
}; | ||
/** | ||
* Read the given Yaml file, load and check its structure. | ||
* @param {string} filepath Yaml file path | ||
* @returns {number} 0 when no errors, 1 when errors. | ||
*/ | ||
var checkFile = function checkFile(filepath) { | ||
/** | ||
* Read the given Yaml file, load and check its structure. | ||
* @param {string} filepath Yaml file path | ||
* @returns {number} 0 when no errors, 1 when errors. | ||
*/ | ||
YamlValidatore.prototype.checkFile = function checkFile(filepath) { | ||
// Verbose output will tell which file is being read | ||
var data = grunt.file.read(filepath), | ||
hadError = 0; | ||
// Verbose output will tell which file is being read | ||
var data = grunt.file.read(filepath), | ||
hadError = 0; | ||
var doc = yaml.safeLoad(data, { | ||
onWarning: function (error) { | ||
hadError = 1; | ||
errored(error); | ||
if (options.yaml !== null && | ||
typeof options.yaml.onWarning === 'function') { | ||
options.yaml.onWarning.call(this, error, filepath); | ||
} | ||
var doc = yaml.safeLoad(data, { | ||
onWarning: function (error) { | ||
hadError = 1; | ||
this.errored(error); | ||
if (this.options.yaml && | ||
typeof this.options.yaml.onWarning === 'function') { | ||
this.options.yaml.onWarning.call(this, error, filepath); | ||
} | ||
}); | ||
} | ||
}); | ||
if (options.keys !== null) { | ||
var missing = checkKeys(doc, options.keys); | ||
var len = missing.length; | ||
if (this.options.keys) { | ||
var missing = this.checkKeys(doc, this.options.keys); | ||
var len = missing.length; | ||
if (len > 0) { | ||
hadError = 1; | ||
errored(filepath + ' is missing the following keys: '); | ||
errored(grunt.log.wordlist(missing, {color: 'grey'})); | ||
} | ||
// Increment the number of keys that were not according to the requirement | ||
missingKeys += len; | ||
if (len > 0) { | ||
hadError = 1; | ||
this.errored(filepath + ' is missing the following keys: '); | ||
this.errored(grunt.log.wordlist(missing, {color: 'grey'})); | ||
} | ||
if (options.types !== null) { | ||
var mismatching = checkTypes(doc, options.types); | ||
if (!mismatching) { | ||
hadError = 1; | ||
errored(filepath + ' is not matching the type requirements'); | ||
mismatchedTypes.push(filepath); | ||
} | ||
// Increment the number of keys that were not according to the requirement | ||
this.missingKeys += len; | ||
} | ||
if (this.options.types) { | ||
var mismatching = this.checkTypes(doc, this.options.types); | ||
if (!mismatching) { | ||
hadError = 1; | ||
this.errored(filepath + ' is not matching the type requirements'); | ||
this.mismatchedTypes.push(filepath); | ||
} | ||
} | ||
return hadError; | ||
}; | ||
return hadError; | ||
}; | ||
/** | ||
* Create a report out of this, but in reality also run. | ||
*/ | ||
YamlValidatore.prototype.validate = function validate() { | ||
var _self = this; | ||
this.haveErrors = this.files.map(function (filepath) { | ||
return _self.checkFile(filepath); | ||
}).reduce(function (prev, curr) { | ||
return prev + curr; | ||
}); | ||
}; | ||
/** | ||
* Create a report out of this, but in reality also run. | ||
*/ | ||
YamlValidatore.prototype.report = function report() { | ||
var msg; | ||
if (this.mismatchedTypes.length > 0) { | ||
this.errored('Type mismatching found in total of ' + this.mismatchedTypes.length + ' files'); | ||
} | ||
else { | ||
msg = 'No mismatching type requirements found.'; | ||
this.logs.push(msg); | ||
grunt.verbose.writeln(msg); | ||
} | ||
if (this.missingKeys === 0) { | ||
msg = 'All done. No missing keys found. Thank you.'; | ||
this.logs.push(msg); | ||
grunt.verbose.writeln(msg); | ||
} | ||
else { | ||
this.errored('Found missing keys, total of: ' + this.missingKeys); | ||
} | ||
grunt.verbose.writeln('Out of ' + this.files.length + ' files, ' + this.haveErrors + ' have validation errors'); | ||
if (typeof this.options.log === 'string') { | ||
grunt.file.write(this.options.log, grunt.log.uncolor(this.logs.join('\n'))); | ||
} | ||
}; | ||
module.exports = function yamlValidator(grunt) { | ||
grunt.registerMultiTask('yaml_validator', 'Validate Yaml files and enforce a given structure', function() { | ||
var msg; | ||
// Default options | ||
options = this.options({ | ||
var options = this.options({ | ||
log: false, | ||
keys: [], | ||
types: null, | ||
yaml: null | ||
keys: false, | ||
types: false, | ||
yaml: false | ||
}); | ||
@@ -123,5 +175,3 @@ | ||
if (!grunt.file.exists(filepath)) { | ||
var msg = 'Source file "' + filepath + '" not found.'; | ||
logs.push(msg); | ||
grunt.log.warn(msg); | ||
grunt.log.warn('Source file "' + filepath + '" not found.'); | ||
return false; | ||
@@ -132,31 +182,8 @@ } | ||
var haveErrors = files.map(checkFile).reduce(function (prev, curr) { | ||
return prev + curr; | ||
}); | ||
var validator = new YamlValidatore(files, options); | ||
validator.validate(); | ||
validator.report(); | ||
grunt.verbose.writeln('Out of ' + files.length + ' files, ' + haveErrors + ' have validation errors'); | ||
if (mismatchedTypes.length > 0) { | ||
errored('Type mismatching found in total of ' + mismatchedTypes.length + ' files'); | ||
} | ||
else { | ||
msg = 'No mismatching type requirements found.'; | ||
logs.push(msg); | ||
grunt.verbose.writeln(msg); | ||
} | ||
if (missingKeys === 0) { | ||
msg = 'All done. No missing keys found. Thank you.'; | ||
logs.push(msg); | ||
grunt.verbose.writeln(msg); | ||
} | ||
else { | ||
errored('Found missing keys, total of: ' + missingKeys); | ||
} | ||
if (typeof options.log === 'string') { | ||
grunt.file.write(options.log, grunt.log.uncolor(logs.join('\n'))); | ||
} | ||
}); | ||
}; |
13541
153
253