diff --git a/lib/htmlhint.js b/lib/htmlhint.js index 9596faaba..ec953e38d 100644 --- a/lib/htmlhint.js +++ b/lib/htmlhint.js @@ -1,3 +1,3 @@ /*! HTMLHint v0.9.1 | (c) 2013 Yanis Wang . MIT Licensed */ -var HTMLHint=function(e){var t=[],a={};return a.version="0.9.1",a.addRule=function(e){t[e.id]=e},a.verify=function(r,n){var i,s=new HTMLParser,o=new a.Reporter(r.split(/\r?\n/),n);for(id in n)i=t[id],i!==e&&i.init(s,o,n[id]);return s.parse(r),o.messages},a}();"object"==typeof exports&&exports&&(exports.HTMLHint=HTMLHint),function(e){var t=function(){var e=this;e._init.apply(e,arguments)};t.prototype={_init:function(e,t){var a=this;a.lines=e,a.ruleset=t,a.messages=[]},error:function(e,t,a,r,n){this.report("error",e,t,a,r,n)},warn:function(e,t,a,r,n){this.report("warning",e,t,a,r,n)},info:function(e,t,a,r,n){this.report("info",e,t,a,r,n)},report:function(e,t,a,r,n,i){var s=this;s.messages.push({type:e,message:t,raw:i,evidence:s.lines[a-1],line:a,col:r,rule:n})}},e.Reporter=t}(HTMLHint);var HTMLParser=function(e){var t=function(){var e=this;e._init.apply(e,arguments)};return t.prototype={_init:function(){var e=this;e._listeners={},e._mapCdataTags=e.makeMap("script,style"),e._arrBlocks=[]},makeMap:function(e){for(var t={},a=e.split(","),r=0;a.length>r;r++)t[a[r]]=!0;return t},parse:function(t){function a(t,a,r,n){var i=r-v+1;n===e&&(n={}),n.raw=a,n.pos=r,n.line=L,n.col=i,b.push(n),u.fire(t,n);for(var s;s=p.exec(a);)L++,v=r+p.lastIndex}var r,n,i,s,o,l,d,u=this,c=u._mapCdataTags,g=/<(?:\/([^\s>]+)|!--([\s\S]*?)--|!([^>]*?)|([\w\-:]+)((?:"[^"]*"|'[^']*'|[^"'<>])*?)\s*(\/?))>/g,m=/\s*([\w\-:]+)(?:\s*=\s*(?:(")([^"]*)"|(')([^']*)'|([^\s]+)))?/g,p=/\r?\n/g,f=0,h=0,v=0,L=1,b=u._arrBlocks;for(u.fire("start",{pos:0,line:1,col:1});r=g.exec(t);)if(n=r.index,n>f&&(d=t.substring(f,n),o?l.push(d):a("text",d,f)),f=g.lastIndex,!(i=r[1])||(o&&i===o&&(d=l.join(""),a("cdata",d,h,{tagName:o}),o=null,l=null),o))if(o)l.push(r[0]);else if(i=r[4]){s=[];for(var w,H=r[5];w=m.exec(H);){var T=w[1],y=w[2]?w[2]:w[4]?w[4]:"",M=w[3]?w[3]:w[5]?w[5]:w[6]?w[6]:"";s.push({name:T,value:M,quote:y,index:w.index,raw:w[0]})}a("tagstart",r[0],n,{tagName:i,attrs:s,close:r[6]}),c[i]&&(o=i,l=[],h=f)}else(r[2]||r[3])&&a("comment",r[0],n,{content:r[2]||r[3],"long":r[2]?!0:!1});else a("tagend",r[0],n,{tagName:i});t.length>f&&(d=t.substring(f,t.length),a("text",d,f)),u.fire("end",{pos:f,line:L,col:f-v+1})},addListener:function(t,a){for(var t,r=this._listeners,n=t.split(/[,\s]/),i=0,s=n.length;s>i;i++)t=n[i],r[t]===e&&(r[t]=[]),r[t].push(a)},fire:function(t,a){a===e&&(a={}),a.type=t;var r=this,n=[],i=r._listeners[t],s=r._listeners.all;i!==e&&(n=n.concat(i)),s!==e&&(n=n.concat(s));for(var o=0,l=n.length;l>o;o++)n[o].call(r,a)},removeListener:function(t,a){var r=this._listeners[t];if(r!==e)for(var n=0,i=r.length;i>n;n++)if(r[n]===a){r.splice(n,1);break}}},t}();"object"==typeof exports&&exports&&(exports.HTMLHint=HTMLHint),HTMLHint.addRule({id:"attr-lowercase",description:"Attribute name must be lowercase.",init:function(e,t){var a=this;e.addListener("tagstart",function(e){for(var r,n=e.attrs,i=e.col+e.tagName.length+1,s=0,o=n.length;o>s;s++){r=n[s];var l=r.name;l!==l.toLowerCase()&&t.error("Attribute name [ "+l+" ] must be lower case.",e.line,i+r.index,a,r.raw)}})}}),HTMLHint.addRule({id:"attr-value-double-quotes",description:"Attribute value must closed by double quotes.",init:function(e,t){var a=this;e.addListener("tagstart",function(e){for(var r,n=e.attrs,i=e.col+e.tagName.length+1,s=0,o=n.length;o>s;s++)r=n[s],""!==r.quote&&'"'!==r.quote&&t.error("The value of attribute [ "+r.name+" ] must closed by double quotes.",e.line,i+r.index,a,r.raw)})}}),HTMLHint.addRule({id:"attr-value-empty",description:"Attribute must set value.",init:function(e,t){var a=this;e.addListener("tagstart",function(e){for(var r,n=e.attrs,i=e.col+e.tagName.length+1,s=0,o=n.length;o>s;s++)r=n[s],""===r.quote&&""===r.value&&t.error("The attribute [ "+r.name+" ] must set value.",e.line,i+r.index,a,r.raw)})}}),HTMLHint.addRule({id:"doctype-first",description:"Doctype must be first.",init:function(e,t){var a=this,r=function(n){"start"===n.type||"text"===n.type&&/^\s*$/.test(n.raw)||(("comment"!==n.type&&n.long===!1||/^DOCTYPE\s+/i.test(n.content)===!1)&&t.error("Doctype must be first.",n.line,n.col,a,n.raw),e.removeListener("all",r))};e.addListener("all",r)}}),HTMLHint.addRule({id:"doctype-html5",description:"Doctype must be html5.",init:function(e,t){function a(e){e.long===!1&&"doctype html"!==e.content.toLowerCase()&&t.error("Doctype must be html5.",e.line,e.col,n,e.raw)}function r(){e.removeListener("comment",a),e.removeListener("tagstart",r)}var n=this;e.addListener("all",a),e.addListener("tagstart",r)}}),HTMLHint.addRule({id:"head-script-disabled",description:"The script tag can not be used in head.",init:function(e,t){function a(e){"script"===e.tagName.toLowerCase()&&t.error("The script tag can not be used in head.",e.line,e.col,n,e.raw)}function r(t){"head"===t.tagName.toLowerCase()&&(e.removeListener("tagstart",a),e.removeListener("tagstart",r))}var n=this;e.addListener("tagstart",a),e.addListener("tagend",r)}}),HTMLHint.addRule({id:"id-class-value",description:"Id and class value must meet some rules.",init:function(e,t,a){var r,n=this,i={underline:{regId:/^[a-z\d]+(_[a-z\d]+)*$/,message:"Id and class value must lower case and split by underline."},dash:{regId:/^[a-z\d]+(-[a-z\d]+)*$/,message:"Id and class value must lower case and split by dash."},hump:{regId:/^[a-z][a-zA-Z\d]*([A-Z][a-zA-Z\d]*)*$/,message:"Id and class value must meet hump style."}};if(r="string"==typeof a?i[a]:a,r&&r.regId){var s=r.regId,o=r.message;e.addListener("tagstart",function(e){for(var a,r=e.attrs,i=0,l=r.length;l>i;i++)if(a=r[i],"id"===a.name.toLowerCase()&&s.test(a.value)===!1&&t.error(o,e.line,e.col,n,a.raw),"class"===a.name.toLowerCase())for(var d,u=a.value.split(/\s+/g),i=0,l=u.length;l>i;i++)d=u[i],d&&s.test(d)===!1&&t.error(o,e.line,e.col,n,d)})}}}),HTMLHint.addRule({id:"img-alt-require",description:"Alt of img tag must be set value.",init:function(e,t){var a=this;e.addListener("tagstart",function(e){if("img"===e.tagName.toLowerCase()){for(var r=e.attrs,n=!1,i=0,s=r.length;s>i;i++)if("alt"===r[i].name.toLowerCase()){n=!0;break}n===!1&&t.error("Alt of img tag must be set value.",e.line,e.col,a,e.raw)}})}}),HTMLHint.addRule({id:"spec-char-escape",description:"Special characters must be escaped.",init:function(e,t){var a=this;e.addListener("text",function(e){var r=e.raw.match(/[<>]/);null!==r&&t.error("Special characters must be escaped [ "+r[0]+" ].",e.line,e.col+r.index,a,e.raw)})}}),HTMLHint.addRule({id:"style-disabled",description:"Style tag can not be use.",init:function(e,t){var a=this;e.addListener("tagstart",function(e){"style"===e.tagName.toLowerCase()&&t.error("Style tag can not be use.",e.line,e.col,a,e.raw)})}}),HTMLHint.addRule({id:"tag-pair",description:"Tag must be paired.",init:function(e,t){var a=this,r=[],n=e.makeMap("area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed");e.addListener("tagstart",function(e){var t=e.tagName.toLowerCase();void 0!==n[t]||e.close||r.push(t)}),e.addListener("tagend",function(e){for(var n=e.tagName.toLowerCase(),i=r.length-1;i>=0&&r[i]!==n;i--);if(i>=0){for(var s=[],o=r.length-1;o>i;o--)s.push("");s.length>0&&t.error("Tag must be paired, Missing: [ "+s.join("")+" ]",e.line,e.col,a,e.raw),r.length=i}else t.error("Tag must be paired, No start tag.",e.line,e.col,a,e.raw)}),e.addListener("end",function(e){for(var n=[],i=r.length-1;i>=0;i--)n.push("");n.length>0&&t.error("Tag must be paired, Missing: [ "+n.join("")+" ]",e.line,e.col,a,e.raw)})}}),HTMLHint.addRule({id:"tag-self-close",description:"The empty tag must closed by self.",init:function(e,t){var a=this,r=e.makeMap("area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed");e.addListener("tagstart",function(e){var n=e.tagName.toLowerCase();void 0!==r[n]&&(e.close||t.error("The empty tag must closed by self.",e.line,e.col,a,e.raw))})}}),HTMLHint.addRule({id:"tagname-lowercase",description:"Tagname must be lowercase.",init:function(e,t){var a=this;e.addListener("tagstart,tagend",function(e){var r=e.tagName;r!==r.toLowerCase()&&t.error("Tagname [ "+r+" ] must be lower case.",e.line,e.col,a,e.raw)})}}); \ No newline at end of file +var HTMLHint=function(e){var t=[],a={};return a.version="0.9.1",a.addRule=function(e){t[e.id]=e},a.verify=function(r,n){var i,s=new HTMLParser,o=new a.Reporter(r.split(/\r?\n/),n);for(id in n)i=t[id],i!==e&&i.init(s,o,n[id]);return s.parse(r),o.messages},a}();"object"==typeof exports&&exports&&(exports.HTMLHint=HTMLHint),function(e){var t=function(){var e=this;e._init.apply(e,arguments)};t.prototype={_init:function(e,t){var a=this;a.lines=e,a.ruleset=t,a.messages=[]},error:function(e,t,a,r,n){this.report("error",e,t,a,r,n)},warn:function(e,t,a,r,n){this.report("warning",e,t,a,r,n)},info:function(e,t,a,r,n){this.report("info",e,t,a,r,n)},report:function(e,t,a,r,n,i){var s=this;s.messages.push({type:e,message:t,raw:i,evidence:s.lines[a-1],line:a,col:r,rule:n})}},e.Reporter=t}(HTMLHint);var HTMLParser=function(e){var t=function(){var e=this;e._init.apply(e,arguments)};return t.prototype={_init:function(){var e=this;e._listeners={},e._mapCdataTags=e.makeMap("script,style"),e._arrBlocks=[]},makeMap:function(e){for(var t={},a=e.split(","),r=0;a.length>r;r++)t[a[r]]=!0;return t},parse:function(t){function a(t,a,r,n){var i=r-v+1;n===e&&(n={}),n.raw=a,n.pos=r,n.line=L,n.col=i,b.push(n),u.fire(t,n);for(var s;s=p.exec(a);)L++,v=r+p.lastIndex}var r,n,i,s,o,l,d,u=this,c=u._mapCdataTags,g=/<(?:\/([^\s>]+)|!--([\s\S]*?)--|!([^>]*?)|([\w\-:]+)((?:"[^"]*"|'[^']*'|[^"'<>])*?)\s*(\/?))>/g,m=/\s*([\w\-:]+)(?:\s*=\s*(?:(")([^"]*)"|(')([^']*)'|([^\s]+)))?/g,p=/\r?\n/g,f=0,h=0,v=0,L=1,b=u._arrBlocks;for(u.fire("start",{pos:0,line:1,col:1});r=g.exec(t);)if(n=r.index,n>f&&(d=t.substring(f,n),o?l.push(d):a("text",d,f)),f=g.lastIndex,!(i=r[1])||(o&&i===o&&(d=l.join(""),a("cdata",d,h,{tagName:o}),o=null,l=null),o))if(o)l.push(r[0]);else if(i=r[4]){s=[];for(var w,H=r[5];w=m.exec(H);){var T=w[1],y=w[2]?w[2]:w[4]?w[4]:"",M=w[3]?w[3]:w[5]?w[5]:w[6]?w[6]:"";s.push({name:T,value:M,quote:y,index:w.index,raw:w[0]})}a("tagstart",r[0],n,{tagName:i,attrs:s,close:r[6]}),c[i]&&(o=i,l=[],h=f)}else(r[2]||r[3])&&a("comment",r[0],n,{content:r[2]||r[3],"long":r[2]?!0:!1});else a("tagend",r[0],n,{tagName:i});t.length>f&&(d=t.substring(f,t.length),a("text",d,f)),u.fire("end",{pos:f,line:L,col:f-v+1})},addListener:function(t,a){for(var t,r=this._listeners,n=t.split(/[,\s]/),i=0,s=n.length;s>i;i++)t=n[i],r[t]===e&&(r[t]=[]),r[t].push(a)},fire:function(t,a){a===e&&(a={}),a.type=t;var r=this,n=[],i=r._listeners[t],s=r._listeners.all;i!==e&&(n=n.concat(i)),s!==e&&(n=n.concat(s));for(var o=0,l=n.length;l>o;o++)n[o].call(r,a)},removeListener:function(t,a){var r=this._listeners[t];if(r!==e)for(var n=0,i=r.length;i>n;n++)if(r[n]===a){r.splice(n,1);break}}},t}();"object"==typeof exports&&exports&&(exports.HTMLHint=HTMLHint),HTMLHint.addRule({id:"attr-lowercase",description:"Attribute name must be lowercase.",init:function(e,t){var a=this;e.addListener("tagstart",function(e){for(var r,n=e.attrs,i=e.col+e.tagName.length+1,s=0,o=n.length;o>s;s++){r=n[s];var l=r.name;l!==l.toLowerCase()&&t.error("Attribute name [ "+l+" ] must be lower case.",e.line,i+r.index,a,r.raw)}})}}),HTMLHint.addRule({id:"attr-value-double-quotes",description:"Attribute value must closed by double quotes.",init:function(e,t){var a=this;e.addListener("tagstart",function(e){for(var r,n=e.attrs,i=e.col+e.tagName.length+1,s=0,o=n.length;o>s;s++)r=n[s],""!==r.quote&&'"'!==r.quote&&t.error("The value of attribute [ "+r.name+" ] must closed by double quotes.",e.line,i+r.index,a,r.raw)})}}),HTMLHint.addRule({id:"attr-value-empty",description:"Attribute must set value.",init:function(e,t){var a=this;e.addListener("tagstart",function(e){for(var r,n=e.attrs,i=e.col+e.tagName.length+1,s=0,o=n.length;o>s;s++)r=n[s],""===r.quote&&""===r.value&&t.error("The attribute [ "+r.name+" ] must set value.",e.line,i+r.index,a,r.raw)})}}),HTMLHint.addRule({id:"doctype-first",description:"Doctype must be first.",init:function(e,t){var a=this,r=function(n){"start"===n.type||"text"===n.type&&/^\s*$/.test(n.raw)||(("comment"!==n.type&&n.long===!1||/^DOCTYPE\s+/i.test(n.content)===!1)&&t.error("Doctype must be first.",n.line,n.col,a,n.raw),e.removeListener("all",r))};e.addListener("all",r)}}),HTMLHint.addRule({id:"doctype-html5",description:"Doctype must be html5.",init:function(e,t){function a(e){e.long===!1&&"doctype html"!==e.content.toLowerCase()&&t.error("Doctype must be html5.",e.line,e.col,n,e.raw)}function r(){e.removeListener("comment",a),e.removeListener("tagstart",r)}var n=this;e.addListener("all",a),e.addListener("tagstart",r)}}),HTMLHint.addRule({id:"head-script-disabled",description:"The script tag can not be used in head.",init:function(e,t){function a(e){"script"===e.tagName.toLowerCase()&&t.error("The script tag can not be used in head.",e.line,e.col,n,e.raw)}function r(t){"head"===t.tagName.toLowerCase()&&(e.removeListener("tagstart",a),e.removeListener("tagstart",r))}var n=this;e.addListener("tagstart",a),e.addListener("tagend",r)}}),HTMLHint.addRule({id:"id-class-value",description:"Id and class value must meet some rules.",init:function(e,t,a){var r,n=this,i={underline:{regId:/^[a-z\d]+(_[a-z\d]+)*$/,message:"Id and class value must lower case and split by underline."},dash:{regId:/^[a-z\d]+(-[a-z\d]+)*$/,message:"Id and class value must lower case and split by dash."},hump:{regId:/^[a-z][a-zA-Z\d]*([A-Z][a-zA-Z\d]*)*$/,message:"Id and class value must meet hump style."}};if(r="string"==typeof a?i[a]:a,r&&r.regId){var s=r.regId,o=r.message;e.addListener("tagstart",function(e){for(var a,r=e.attrs,i=0,l=r.length;l>i;i++)if(a=r[i],"id"===a.name.toLowerCase()&&s.test(a.value)===!1&&t.error(o,e.line,e.col,n,a.raw),"class"===a.name.toLowerCase())for(var d,u=a.value.split(/\s+/g),i=0,l=u.length;l>i;i++)d=u[i],d&&s.test(d)===!1&&t.error(o,e.line,e.col,n,d)})}}}),HTMLHint.addRule({id:"img-alt-require",description:"Alt of img tag must be set value.",init:function(e,t){var a=this;e.addListener("tagstart",function(e){if("img"===e.tagName.toLowerCase()){for(var r=e.attrs,n=!1,i=0,s=r.length;s>i;i++)if("alt"===r[i].name.toLowerCase()){n=!0;break}n===!1&&t.error("Alt of img tag must be set value.",e.line,e.col,a,e.raw)}})}}),HTMLHint.addRule({id:"spec-char-escape",description:"Special characters must be escaped.",init:function(e,t){var a=this;e.addListener("text",function(e){var r=e.raw.match(/[<>]/);null!==r&&t.error("Special characters must be escaped : [ "+r[0]+" ].",e.line,e.col+r.index,a,e.raw)})}}),HTMLHint.addRule({id:"style-disabled",description:"Style tag can not be use.",init:function(e,t){var a=this;e.addListener("tagstart",function(e){"style"===e.tagName.toLowerCase()&&t.error("Style tag can not be use.",e.line,e.col,a,e.raw)})}}),HTMLHint.addRule({id:"tag-pair",description:"Tag must be paired.",init:function(e,t){var a=this,r=[],n=e.makeMap("area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed");e.addListener("tagstart",function(e){var t=e.tagName.toLowerCase();void 0!==n[t]||e.close||r.push(t)}),e.addListener("tagend",function(e){for(var n=e.tagName.toLowerCase(),i=r.length-1;i>=0&&r[i]!==n;i--);if(i>=0){for(var s=[],o=r.length-1;o>i;o--)s.push("");s.length>0&&t.error("Tag must be paired, Missing: [ "+s.join("")+" ]",e.line,e.col,a,e.raw),r.length=i}else t.error("Tag must be paired, No start tag.",e.line,e.col,a,e.raw)}),e.addListener("end",function(e){for(var n=[],i=r.length-1;i>=0;i--)n.push("");n.length>0&&t.error("Tag must be paired, Missing: [ "+n.join("")+" ]",e.line,e.col,a,e.raw)})}}),HTMLHint.addRule({id:"tag-self-close",description:"The empty tag must closed by self.",init:function(e,t){var a=this,r=e.makeMap("area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed");e.addListener("tagstart",function(e){var n=e.tagName.toLowerCase();void 0!==r[n]&&(e.close||t.error("The empty tag must closed by self.",e.line,e.col,a,e.raw))})}}),HTMLHint.addRule({id:"tagname-lowercase",description:"Tagname must be lowercase.",init:function(e,t){var a=this;e.addListener("tagstart,tagend",function(e){var r=e.tagName;r!==r.toLowerCase()&&t.error("Tagname [ "+r+" ] must be lower case.",e.line,e.col,a,e.raw)})}}); \ No newline at end of file diff --git a/src/rules/spec-char-escape.js b/src/rules/spec-char-escape.js index 59170a8a0..96ebca896 100644 --- a/src/rules/spec-char-escape.js +++ b/src/rules/spec-char-escape.js @@ -10,7 +10,7 @@ HTMLHint.addRule({ parser.addListener('text', function(event){ var match = event.raw.match(/[<>]/); if(match !== null){ - reporter.error('Special characters must be escaped [ '+match[0]+' ].', event.line, event.col + match.index, self, event.raw); + reporter.error('Special characters must be escaped : [ '+match[0]+' ].', event.line, event.col + match.index, self, event.raw); } }); }