diff --git a/lib/htmllint.js b/lib/htmllint.js
index 8f81f24..34cfcb2 100644
--- a/lib/htmllint.js
+++ b/lib/htmllint.js
@@ -1,17 +1,16 @@
+
+var util = require('util');
+var fs = require("fs");
module.exports = function(grunt, files, done) {
var jar = __dirname + '/../vnu.jar';
grunt.util.spawn({
cmd: 'java',
- args: ['-Dnu.validator.client.quiet=yes', '-jar', jar].concat(files)
+ args: ['-Dnu.validator.client.out=json','-jar', jar].concat(files)
}, function(error, output) {
if (error) {
done(error);
return;
}
- var result = [];
- if (output.stdout) {
- result = output.stdout.split('\n');
- }
- done(null, result);
+ done(null, JSON.parse("[" + output.toString().replace(/\n/g, ",") + "]"));
});
};
\ No newline at end of file
diff --git a/tasks/html.js b/tasks/html.js
index 0da7fea..107afa1 100644
--- a/tasks/html.js
+++ b/tasks/html.js
@@ -1,104 +1,145 @@
-/*
- * grunt-html
- * https://github.com/jzaefferer/grunnt-html
- *
- * Copyright (c) 2012 Jörn Zaefferer
- * Licensed under the MIT license.
- */
-
-var htmllint = require('../lib/htmllint');
-
-module.exports = function (grunt) {
- "use strict";
-
- var defaultLintSettings = {
- customAttributes: true, // Validate custom attributes
- selfClosingTags: true, // Validate self closing tags,
- documentEncoding: true, // Validates for whether or not the document has a character encoding declared,
- requiredChildren: true, // Validates that elements have the required children,
- startTagBeforeDocType: true, // Validates that start tags are not before doctypes,
- strayEndTag: true, // Validates for stray end tags,
- forLabelControl: true, // Validates that the for attribute on the label points to a control
- imgAlt: true, // Validates that img tags have an alt attribute,
- invalidValue: true, // Validates for invalid values for attributes
- unclosedElement: true, // Validates for unclosed elements
- invalidChildElements: true, // Validates that elements have valid child elements
- openElements: true // Validates that there are open elements before a parents close tag
- };
-
- var filters = {
- customAttributes: /Attribute "[^"]+" not allowed/,
- selfClosingTags: /Self-closing syntax \("\/>"\) used on a non-void HTML element/,
- documentEncoding: /The character encoding of the document was not declared/,
- requiredChildren: /Element "[^"]+" is missing a required instance of child element "[^"]+"/,
- startTagBeforeDocType: /Start tag seen without seeing a doctype first/,
- strayEndTag: /Stray end tag "[^"]+"/,
- forLabelControl: /The "for" attribute of the "label" element must refer to a form control/,
- imgAlt: /An "img" element must have an "alt" attribute/,
- invalidValue: /Bad value "[^"]+" for attribute "[^"]+" on element "[^"]+"/,
- unclosedElement: /Unclosed element "[^"]+"/,
- invalidChildElements: /Element "[^"]+" not allowed as child of element "[^"]+" in this context/,
- openElements: /End tag "[^"]+" seen, but there were open elements/
- };
-
- function extend (target, source) {
- target = target || {};
- for (var prop in source) {
- if (typeof source[prop] === 'object') {
- target[prop] = extend(target[prop], source[prop]);
- } else {
- target[prop] = source[prop];
- }
- }
- return target;
- }
-
- function returnTrueFn() {
- return true;
- }
-
- function addResults(filter, validationFilter, sourceResults, destResults) {
- for (var i = 0; i < sourceResults.length; i++) {
- if (sourceResults[i].match(filter) && validationFilter(sourceResults[i])) {
- destResults.push(sourceResults[i]);
- }
- }
- }
-
- grunt.registerMultiTask('htmllint', 'Validate html files', function () {
- var done = this.async(),
- files = grunt.file.expand(this.filesSrc),
- options = this.options();
-
- htmllint(grunt, files, function (error, result) {
- if (error) {
- grunt.log.error(error);
- done(false);
- return;
- }
-
- var lintOptions = extend(extend({}, defaultLintSettings), options);
- var validationFilters = options.validationFilters || {};
- var actualResult = [];
- var filter;
- var validationFilter;
-
- for (var lintOption in lintOptions) {
- filter = filters[lintOption];
- validationFilter = validationFilters[lintOption] || returnTrueFn;
- if (lintOptions.hasOwnProperty(lintOption) && lintOptions[lintOption] && filter) {
- addResults(filter, validationFilter, result, actualResult);
- }
- }
-
- if (!actualResult.length) {
- grunt.log.writeln(files.length + ' file(s) valid');
- done();
- return;
- }
- grunt.log.writeln(actualResult.join('\n'));
- done(false);
- });
- });
-
-};
+/*
+ * grunt-html
+ * https://github.com/jzaefferer/grunnt-html
+ *
+ * Copyright (c) 2012 Jörn Zaefferer
+ * Licensed under the MIT license.
+ */
+
+var htmllint = require('../lib/htmllint');
+
+module.exports = function (grunt) {
+ "use strict";
+
+ var defaultLintSettings = {
+ customAttributes: true, // Validate custom attributes
+ selfClosingTags: true, // Validate self closing tags,
+ documentEncoding: true, // Validates for whether or not the document has a character encoding declared,
+ requiredChildren: true, // Validates that elements have the required children,
+ startTagBeforeDocType: true, // Validates that start tags are not before doctypes,
+ strayEndTag: true, // Validates for stray end tags,
+ forLabelControl: true, // Validates that the for attribute on the label points to a control
+ imgAlt: true, // Validates that img tags have an alt attribute,
+ invalidValue: true, // Validates for invalid values for attributes
+ unclosedElement: true, // Validates for unclosed elements
+ invalidChildElements: true, // Validates that elements have valid child elements
+ openElements: true // Validates that there are open elements before a parents close tag
+ };
+
+ var filters = {
+ customAttributes: /Attribute ["“][^"”]+["”] not allowed/,
+ selfClosingTags: /Self-closing syntax \(["“]\/>["”]\) used on a non-void HTML element/,
+ documentEncoding: /The character encoding of the document was not declared/,
+ requiredChildren: /Element ["“][^"”]+["”] is missing a required instance of child element ["“][^"”]+["”]/,
+ startTagBeforeDocType: /Start tag seen without seeing a doctype first/,
+ strayEndTag: /Stray end tag ["“][^"”]+["”]/,
+ forLabelControl: /The "for" attribute of the "label" element must refer to a form control/,
+ imgAlt: /An "img" element must have an "alt" attribute/,
+ invalidValue: /Bad value ["“][^"”]+["”] for attribute ["“][^"”]+["”] on element ["“][^"”]+["”]/,
+ unclosedElement: /Unclosed element ["“][^"”]+["”]/,
+ invalidChildElements: /Element ["“][^"”]+["”] not allowed as child of element ["“][^"”]+["”] in this context/,
+ openElements: /End tag ["“][^"”]+["”] seen, but there were open elements/
+ };
+
+ /**
+ * Quick function to mixin source into target
+ * @param target The target object
+ * @param source The source object
+ * @returns {*}
+ */
+ function extend (target, source) {
+ target = target || {};
+ for (var prop in source) {
+ if (typeof source[prop] === 'object') {
+ target[prop] = extend(target[prop], source[prop]);
+ } else {
+ target[prop] = source[prop];
+ }
+ }
+ return target;
+ }
+
+ /**
+ * Simple function to just return true
+ * @returns {boolean}
+ */
+ function returnTrueFn() {
+ return true;
+ }
+
+ /**
+ * Formats the result into a user readable format
+ * @param result The actual result
+ * @returns {string}
+ */
+ function formatResult(result) {
+ return "\t" + ((result.firstLine || result.lastLine) + "." + result.firstColumn + "-" + result.lastLine + "." + result.lastColumn) + ": " + result.type + ": " + result.message;
+ }
+
+ /**
+ * Filters the current file result against the lint options/validation filters
+ * @param fileResult The validation result from the validator
+ * @param fileUrl The source url
+ * @param lintOptions The lint options to filter against
+ * @param validationFilters The functions which indicate whether or not a lint validation error is truly an error
+ * @param results The results array to add the result to if the validation fails
+ */
+ function filterAndAddResult(fileResult, fileUrl, lintOptions, validationFilters, results) {
+ var filter;
+ var validationFilter;
+ for (var lintOption in lintOptions) {
+ filter = filters[lintOption];
+ validationFilter = validationFilters[lintOption] || returnTrueFn;
+ if (lintOptions.hasOwnProperty(lintOption) &&
+ lintOptions[lintOption] &&
+ filter &&
+ fileResult.message.match(filter) &&
+ validationFilter(fileUrl, fileResult)) {
+ results.push(formatResult(fileResult));
+ }
+ }
+ }
+
+ grunt.registerMultiTask('htmllint', 'Validate html files', function () {
+ var done = this.async(),
+ files = grunt.file.expand(this.filesSrc),
+ options = this.options();
+
+ htmllint(grunt, files, function (error, result) {
+ if (error) {
+ grunt.log.error(error);
+ done(false);
+ return;
+ }
+
+ var lintOptions = extend(extend({}, defaultLintSettings), options);
+ var validationFilters = options.validationFilters || {};
+ var actualResult = [];
+
+ for (var i = 0; i < result.length; i++) {
+ var fileUrl = result[i].url;
+ var fileResults = result[i].messages;
+ var fileActualResults = [];
+ for (var j = 0; j < fileResults.length; j++) {
+ var fileResult = fileResults[j];
+ if (fileResult.type !== "info") {
+ filterAndAddResult(fileResult, fileUrl, lintOptions, validationFilters, fileActualResults);
+ }
+ }
+ if (fileActualResults.length) {
+ actualResult.push(fileUrl + ":");
+ actualResult = actualResult.concat(fileActualResults);
+ }
+ }
+
+ if (!actualResult.length) {
+ grunt.log.writeln(files.length + ' file(s) valid');
+ done();
+ return;
+ }
+ grunt.log.writeln(actualResult.join('\n'));
+ done(false);
+ });
+ });
+
+};