UNPKG

htmlhint

Version:

The Static Code Analysis Tool for your HTML

2 lines (1 loc) 22.1 kB
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e=e||self).HTMLHint={})}(this,(function(e){"use strict";class t{constructor(){this._listeners={},this._mapCdataTags=this.makeMap("script,style"),this._arrBlocks=[],this.lastEvent=null}makeMap(e){for(var t={},a=e.split(","),n=0;n<a.length;n++)t[a[n]]=!0;return t}parse(e){var t,a,n,r,i,s,o,l,u=this,c=u._mapCdataTags,d=/<(?:\/([^\s>]+)\s*|!--([\s\S]*?)--|!([^>]*?)|([\w\-:]+)((?:\s+[^\s"'>\/=\x00-\x0F\x7F\x80-\x9F]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s"'>]*))?)*?)\s*(\/?))>/g,h=/\s*([^\s"'>\/=\x00-\x0F\x7F\x80-\x9F]+)(?:\s*=\s*(?:(")([^"]*)"|(')([^']*)'|([^\s"'>]*)))?/g,f=/\r?\n/g,g=0,m=0,p=0,v=1,b=u._arrBlocks;function w(e,t,a,n){var r=a-p+1;for(void 0===n&&(n={}),n.raw=t,n.pos=a,n.line=v,n.col=r,b.push(n),u.fire(e,n);f.exec(t);)v++,p=a+f.lastIndex}for(u.fire("start",{pos:0,line:1,col:1});t=d.exec(e);)if((a=t.index)>g&&(l=e.substring(g,a),i?o.push(l):w("text",l,g)),g=d.lastIndex,!(n=t[1])||(i&&n===i&&(w("cdata",l=o.join(""),m,{tagName:i,attrs:s}),i=null,s=null,o=null),i))if(i)o.push(t[0]);else if(n=t[4]){r=[];for(var y,L=t[5],x=0;y=h.exec(L);){var T=y[1],N=y[2]?y[2]:y[4]?y[4]:"",A=y[3]?y[3]:y[5]?y[5]:y[6]?y[6]:"";r.push({name:T,value:A,quote:N,index:y.index,raw:y[0]}),x+=y[0].length}x===L.length?(w("tagstart",t[0],a,{tagName:n,attrs:r,close:t[6]}),c[n]&&(i=n,s=r.concat(),o=[],m=g)):w("text",t[0],a)}else(t[2]||t[3])&&w("comment",t[0],a,{content:t[2]||t[3],long:!!t[2]});else w("tagend",t[0],a,{tagName:n});e.length>g&&w("text",l=e.substring(g,e.length),g),u.fire("end",{pos:g,line:v,col:e.length-p+1})}addListener(e,t){for(var a,n=this._listeners,r=e.split(/[,\s]/),i=0,s=r.length;i<s;i++)void 0===n[a=r[i]]&&(n[a]=[]),n[a].push(t)}fire(e,t){void 0===t&&(t={}),t.type=e;var a=[],n=this._listeners[e],r=this._listeners.all;void 0!==n&&(a=a.concat(n)),void 0!==r&&(a=a.concat(r));var i=this.lastEvent;null!==i&&(delete i.lastEvent,t.lastEvent=i),this.lastEvent=t;for(var s=0,o=a.length;s<o;s++)a[s].call(this,t)}removeListener(e,t){var a=this._listeners[e];if(void 0!==a)for(var n=0,r=a.length;n<r;n++)if(a[n]===t){a.splice(n,1);break}}fixPos(e,t){var a,n=e.raw.substr(0,t).split(/\r?\n/),r=n.length-1,i=e.line;return r>0?(i+=r,a=n[r].length+1):a=e.col+t,{line:i,col:a}}getMapAttrs(e){for(var t,a={},n=0,r=e.length;n<r;n++)a[(t=e[n]).name]=t.value;return a}}class a{constructor(e,t){this.html=e,this.lines=e.split(/\r?\n/);var a=e.match(/\r?\n/);this.brLen=null!==a?a[0].length:0,this.ruleset=t,this.messages=[],this.error=this.report.bind(this,"error"),this.warn=this.report.bind(this,"warning"),this.info=this.report.bind(this,"info")}report(e,t,a,n,r,i){for(var s,o,l=this.lines,u=this.brLen,c=a-1,d=l.length;c<d&&(n>(o=(s=l[c]).length)&&a<d);c++)a++,1!==(n-=o)&&(n-=u);this.messages.push({type:e,message:t,raw:i,evidence:s,line:a,col:n,rule:{id:r.id,description:r.description,link:"https://github.com/thedaviddias/HTMLHint/wiki/"+r.id}})}}function n(e,t){if(t instanceof RegExp)return!!t.test(e)&&{match:e,pattern:t};const a=t[0],n=t[t.length-1],r=t[t.length-2],i="/"===a&&("/"===n||"/"===r&&"i"===n);if(i){return i&&"i"===n?new RegExp(t.slice(1,-2),"i").test(e):new RegExp(t.slice(1,-1)).test(e)}return e===t}var r={id:"attr-lowercase",description:"All attribute names must be in lowercase.",init:function(e,t,a){var r=this,i=Array.isArray(a)?a:[];e.addListener("tagstart",(function(e){for(var a,s=e.attrs,o=e.col+e.tagName.length+1,l=0,u=s.length;l<u;l++){var c=(a=s[l]).name;i.find(e=>n(c,e))||c===c.toLowerCase()||t.error("The attribute name of [ "+c+" ] must be in lowercase.",e.line,o+a.index,r,a.raw)}}))}},i={id:"attr-sorted",description:"Attribute tags must be in proper order.",init:function(e,t){for(var a=this,n={},r=["class","id","name","src","for","type","href","value","title","alt","role"],i=0;i<r.length;i++)n[r[i]]=i;e.addListener("tagstart",(function(e){for(var r=e.attrs,i=[],s=0;s<r.length;s++)i.push(r[s].name);var o=JSON.stringify(i);i.sort((function(e,t){return null==n[e]&&null==n[t]?0:null==n[e]?1:null==n[t]?-1:n[e]-n[t]||e.localeCompare(t)})),o!==JSON.stringify(i)&&t.error("Inaccurate order "+o+" should be in hierarchy "+JSON.stringify(i)+" ",e.line,e.col,a)}))}},s={id:"attr-unsafe-chars",description:"Attribute values cannot contain unsafe chars.",init:function(e,t){var a=this;e.addListener("tagstart",(function(e){for(var n,r,i=e.attrs,s=e.col+e.tagName.length+1,o=/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/,l=0,u=i.length;l<u;l++)if(null!==(r=(n=i[l]).value.match(o))){var c=escape(r[0]).replace(/%u/,"\\u").replace(/%/,"\\x");t.warn("The value of attribute [ "+n.name+" ] cannot contain an unsafe char [ "+c+" ].",e.line,s+n.index,a,n.raw)}}))}},o={id:"attr-whitespace",description:"All attributes should be separated by only one space and not have leading/trailing whitespace.",init:function(e,t,a){var n=this,r=Array.isArray(a)?a:[];e.addListener("tagstart",(function(e){var a,i=e.attrs,s=e.col+e.tagName.length+1;i.forEach((function(i){a=i;var o=i.name;-1===r.indexOf(o)&&(i.value.trim(i.value)!==i.value&&t.error("The attributes of [ "+o+" ] must not have trailing whitespace.",e.line,s+a.index,n,a.raw),i.value.replace(/ +(?= )/g,"")!==i.value&&t.error("The attributes of [ "+o+" ] must be separated by only one space.",e.line,s+a.index,n,a.raw))}))}))}},l={id:"id-class-value",description:"The id and class attribute values must meet the specified rules.",init:function(e,t,a){var n,r=this;if((n="string"==typeof a?{underline:{regId:/^[a-z\d]+(_[a-z\d]+)*$/,message:"The id and class attribute values must be in lowercase and split by an underscore."},dash:{regId:/^[a-z\d]+(-[a-z\d]+)*$/,message:"The id and class attribute values must be in lowercase and split by a dash."},hump:{regId:/^[a-z][a-zA-Z\d]*([A-Z][a-zA-Z\d]*)*$/,message:"The id and class attribute values must meet the camelCase style."}}[a]:a)&&n.regId){var i=n.regId,s=n.message;i instanceof RegExp||(i=new RegExp(i)),e.addListener("tagstart",(function(e){for(var a,n=e.attrs,o=e.col+e.tagName.length+1,l=0,u=n.length;l<u;l++)if("id"===(a=n[l]).name.toLowerCase()&&!1===i.test(a.value)&&t.warn(s,e.line,o+a.index,r,a.raw),"class"===a.name.toLowerCase())for(var c,d=a.value.split(/\s+/g),h=0,f=d.length;h<f;h++)(c=d[h])&&!1===i.test(c)&&t.warn(s,e.line,o+a.index,r,c)}))}}},u={id:"id-unique",description:"The value of id attributes must be unique.",init:function(e,t){var a=this,n={};e.addListener("tagstart",(function(e){for(var r,i,s=e.attrs,o=e.col+e.tagName.length+1,l=0,u=s.length;l<u;l++)if("id"===(r=s[l]).name.toLowerCase()){(i=r.value)&&(void 0===n[i]?n[i]=1:n[i]++,n[i]>1&&t.error("The id value [ "+i+" ] must be unique.",e.line,o+r.index,a,r.raw));break}}))}},c={id:"space-tab-mixed-disabled",description:"Do not mix tabs and spaces for indentation.",init:function(e,t,a){var n=this,r="nomix",i=null;if("string"==typeof a){var s=a.match(/^([a-z]+)(\d+)?/);r=s[1],i=s[2]&&parseInt(s[2],10)}e.addListener("text",(function(a){for(var s,o=a.raw,l=/(^|\r?\n)([ \t]+)/g;s=l.exec(o);){var u=e.fixPos(a,s.index+s[1].length);if(1===u.col){var c=s[2];"space"===r?i?!1!==/^ +$/.test(c)&&c.length%i==0||t.warn("Please use space for indentation and keep "+i+" length.",u.line,1,n,a.raw):!1===/^ +$/.test(c)&&t.warn("Please use space for indentation.",u.line,1,n,a.raw):"tab"===r&&!1===/^\t+$/.test(c)?t.warn("Please use tab for indentation.",u.line,1,n,a.raw):!0===/ +\t|\t+ /.test(c)&&t.warn("Do not mix tabs and spaces for indentation.",u.line,1,n,a.raw)}}}))}},d={id:"tag-pair",description:"Tag must be paired.",init:function(e,t){var a=this,n=[],r=e.makeMap("area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed,track,command,source,keygen,wbr");e.addListener("tagstart",(function(e){var t=e.tagName.toLowerCase();void 0!==r[t]||e.close||n.push({tagName:t,line:e.line,raw:e.raw})})),e.addListener("tagend",(function(e){for(var r=e.tagName.toLowerCase(),i=n.length-1;i>=0&&n[i].tagName!==r;i--);if(i>=0){for(var s=[],o=n.length-1;o>i;o--)s.push("</"+n[o].tagName+">");if(s.length>0){var l=n[n.length-1];t.error("Tag must be paired, missing: [ "+s.join("")+" ], start tag match failed [ "+l.raw+" ] on line "+l.line+".",e.line,e.col,a,e.raw)}n.length=i}else t.error("Tag must be paired, no start tag: [ "+e.raw+" ]",e.line,e.col,a,e.raw)})),e.addListener("end",(function(e){for(var r=[],i=n.length-1;i>=0;i--)r.push("</"+n[i].tagName+">");if(r.length>0){var s=n[n.length-1];t.error("Tag must be paired, missing: [ "+r.join("")+" ], open tag match failed [ "+s.raw+" ] on line "+s.line+".",e.line,e.col,a,"")}}))}},h={id:"tag-self-close",description:"Empty tags must be self closed.",init:function(e,t){var a=this,n=e.makeMap("area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed,track,command,source,keygen,wbr");e.addListener("tagstart",(function(e){var r=e.tagName.toLowerCase();void 0!==n[r]&&(e.close||t.warn("The empty tag : [ "+r+" ] must be self closed.",e.line,e.col,a,e.raw))}))}},f={id:"tagname-lowercase",description:"All html element names must be in lowercase.",init:function(e,t,a){var n=this,r=Array.isArray(a)?a:[];e.addListener("tagstart,tagend",(function(e){var a=e.tagName;-1===r.indexOf(a)&&a!==a.toLowerCase()&&t.error("The html element name of [ "+a+" ] must be in lowercase.",e.line,e.col,n,e.raw)}))}},g={a:{selfclosing:!1,attrsRequired:["href","title"],redundantAttrs:["alt"]},div:{selfclosing:!1},main:{selfclosing:!1,redundantAttrs:["role"]},nav:{selfclosing:!1,redundantAttrs:["role"]},script:{attrsOptional:[["async","async"],["defer","defer"]]},img:{selfclosing:!0,attrsRequired:["src","alt","title"]}},m={id:"tags-check",description:"Checks html tags.",init:function(e,t,a){var n=this;"boolean"!=typeof a&&function(e){for(var t,a=1;a<arguments.length;a++)for(var n in t=arguments[a])e[n]=t[n]}(g,a),e.addListener("tagstart",(function(e){var a=e.attrs,r=e.col+e.tagName.length+1,i=e.tagName.toLowerCase();if(g[i]){var s=g[i];!0!==s.selfclosing||e.close?!1===s.selfclosing&&e.close&&t.warn("The <"+i+"> tag must not be selfclosing.",e.line,e.col,n,e.raw):t.warn("The <"+i+"> tag must be selfclosing.",e.line,e.col,n,e.raw),s.attrsRequired&&s.attrsRequired.forEach((function(s){if(Array.isArray(s)){var o=s.map((function(e){return e})),l=o.shift(),u=o;a.some((function(e){return e.name===l}))?a.forEach((function(a){a.name===l&&-1===u.indexOf(a.value)&&t.error("The <"+i+"> tag must have attr '"+l+"' with one value of '"+u.join("' or '")+"'.",e.line,r,n,e.raw)})):t.error("The <"+i+"> tag must have attr '"+l+"'.",e.line,r,n,e.raw)}else a.some((function(e){return-1!==s.split("|").indexOf(e.name)}))||t.error("The <"+i+"> tag must have attr '"+s+"'.",e.line,r,n,e.raw)})),s.attrsOptional&&s.attrsOptional.forEach((function(s){if(Array.isArray(s)){var o=s.map((function(e){return e})),l=o.shift(),u=o;a.some((function(e){return e.name===l}))&&a.forEach((function(a){a.name===l&&-1===u.indexOf(a.value)&&t.error("The <"+i+"> tag must have optional attr '"+l+"' with one value of '"+u.join("' or '")+"'.",e.line,r,n,e.raw)}))}})),s.redundantAttrs&&s.redundantAttrs.forEach((function(s){a.some((function(e){return e.name===s}))&&t.error("The attr '"+s+"' is redundant for <"+i+"> and should be ommited.",e.line,r,n,e.raw)}))}}))}},p={id:"attr-no-unnecessary-whitespace",description:"No spaces between attribute names and values.",init:function(e,t,a){var n=this,r=Array.isArray(a)?a:[];e.addListener("tagstart",(function(e){for(var a=e.attrs,i=e.col+e.tagName.length+1,s=0;s<a.length;s++)-1===r.indexOf(a[s].name)&&/[^=](\s+=\s+|=\s+|\s+=)/g.test(a[s].raw.trim())&&t.error("The attribute '"+a[s].name+"' must not have spaces between the name and value.",e.line,i+a[s].index,n,a[s].raw)}))}},v=Object.freeze({__proto__:null,altRequire:{id:"alt-require",description:"The alt attribute of an <img> element must be present and alt attribute of area[href] and input[type=image] must have a value.",init:function(e,t){var a=this;e.addListener("tagstart",(function(n){var r,i=n.tagName.toLowerCase(),s=e.getMapAttrs(n.attrs),o=n.col+i.length+1;"img"!==i||"alt"in s?("area"===i&&"href"in s||"input"===i&&"image"===s.type)&&("alt"in s&&""!==s.alt||(r="area"===i?"area[href]":"input[type=image]",t.warn("The alt attribute of "+r+" must have a value.",n.line,o,a,n.raw))):t.warn("An alt attribute must be present on <img> elements.",n.line,o,a,n.raw)}))}},attrLowercase:r,attrSort:i,attrNoDuplication:{id:"attr-no-duplication",description:"Elements cannot have duplicate attributes.",init:function(e,t){var a=this;e.addListener("tagstart",(function(e){for(var n,r,i=e.attrs,s=e.col+e.tagName.length+1,o={},l=0,u=i.length;l<u;l++)!0===o[r=(n=i[l]).name]&&t.error("Duplicate of attribute name [ "+n.name+" ] was found.",e.line,s+n.index,a,n.raw),o[r]=!0}))}},attrUnsafeChars:s,attrValueDoubleQuotes:{id:"attr-value-double-quotes",description:"Attribute values must be in double quotes.",init:function(e,t){var a=this;e.addListener("tagstart",(function(e){for(var n,r=e.attrs,i=e.col+e.tagName.length+1,s=0,o=r.length;s<o;s++)(""!==(n=r[s]).value&&'"'!==n.quote||""===n.value&&"'"===n.quote)&&t.error("The value of attribute [ "+n.name+" ] must be in double quotes.",e.line,i+n.index,a,n.raw)}))}},attrValueNotEmpty:{id:"attr-value-not-empty",description:"All attributes must have values.",init:function(e,t){var a=this;e.addListener("tagstart",(function(e){for(var n,r=e.attrs,i=e.col+e.tagName.length+1,s=0,o=r.length;s<o;s++)""===(n=r[s]).quote&&""===n.value&&t.warn("The attribute [ "+n.name+" ] must have a value.",e.line,i+n.index,a,n.raw)}))}},attrValueSingleQuotes:{id:"attr-value-single-quotes",description:"Attribute values must be in single quotes.",init:function(e,t){var a=this;e.addListener("tagstart",(function(e){for(var n,r=e.attrs,i=e.col+e.tagName.length+1,s=0,o=r.length;s<o;s++)(""!==(n=r[s]).value&&"'"!==n.quote||""===n.value&&'"'===n.quote)&&t.error("The value of attribute [ "+n.name+" ] must be in single quotes.",e.line,i+n.index,a,n.raw)}))}},attrWhitespace:o,doctypeFirst:{id:"doctype-first",description:"Doctype must be declared first.",init:function(e,t){var a=this,n=function(r){"start"===r.type||"text"===r.type&&/^\s*$/.test(r.raw)||(("comment"!==r.type&&!1===r.long||!1===/^DOCTYPE\s+/i.test(r.content))&&t.error("Doctype must be declared first.",r.line,r.col,a,r.raw),e.removeListener("all",n))};e.addListener("all",n)}},doctypeHTML5:{id:"doctype-html5",description:'Invalid doctype. Use: "<!DOCTYPE html>"',init:function(e,t){var a=this;function n(e){!1===e.long&&"doctype html"!==e.content.toLowerCase()&&t.warn('Invalid doctype. Use: "<!DOCTYPE html>"',e.line,e.col,a,e.raw)}e.addListener("all",n),e.addListener("tagstart",(function t(){e.removeListener("comment",n),e.removeListener("tagstart",t)}))}},headScriptDisabled:{id:"head-script-disabled",description:"The <script> tag cannot be used in a <head> tag.",init:function(e,t){var a=this,n=/^(text\/javascript|application\/javascript)$/i,r=!1;function i(i){var s=e.getMapAttrs(i.attrs).type,o=i.tagName.toLowerCase();"head"===o&&(r=!0),!0!==r||"script"!==o||s&&!0!==n.test(s)||t.warn("The <script> tag cannot be used in a <head> tag.",i.line,i.col,a,i.raw)}e.addListener("tagstart",i),e.addListener("tagend",(function t(a){"head"===a.tagName.toLowerCase()&&(e.removeListener("tagstart",i),e.removeListener("tagend",t))}))}},hrefAbsOrRel:{id:"href-abs-or-rel",description:"An href attribute must be either absolute or relative.",init:function(e,t,a){var n=this,r="abs"===a?"absolute":"relative";e.addListener("tagstart",(function(e){for(var a,i=e.attrs,s=e.col+e.tagName.length+1,o=0,l=i.length;o<l;o++)if("href"===(a=i[o]).name){("absolute"===r&&!1===/^\w+?:/.test(a.value)||"relative"===r&&!0===/^https?:\/\//.test(a.value))&&t.warn("The value of the href attribute [ "+a.value+" ] must be "+r+".",e.line,s+a.index,n,a.raw);break}}))}},idClsasAdDisabled:{id:"id-class-ad-disabled",description:"The id and class attributes cannot use the ad keyword, it will be blocked by adblock software.",init:function(e,t){var a=this;e.addListener("tagstart",(function(e){for(var n,r,i=e.attrs,s=e.col+e.tagName.length+1,o=0,l=i.length;o<l;o++)r=(n=i[o]).name,/^(id|class)$/i.test(r)&&/(^|[-_])ad([-_]|$)/i.test(n.value)&&t.warn("The value of attribute "+r+" cannot use the ad keyword.",e.line,s+n.index,a,n.raw)}))}},idClassValue:l,idUnique:u,inlineScriptDisabled:{id:"inline-script-disabled",description:"Inline script cannot be used.",init:function(e,t){var a=this;e.addListener("tagstart",(function(e){for(var n,r,i=e.attrs,s=e.col+e.tagName.length+1,o=/^on(unload|message|submit|select|scroll|resize|mouseover|mouseout|mousemove|mouseleave|mouseenter|mousedown|load|keyup|keypress|keydown|focus|dblclick|click|change|blur|error)$/i,l=0,u=i.length;l<u;l++)r=(n=i[l]).name.toLowerCase(),!0===o.test(r)?t.warn("Inline script [ "+n.raw+" ] cannot be used.",e.line,s+n.index,a,n.raw):"src"!==r&&"href"!==r||/^\s*javascript:/i.test(n.value)&&t.warn("Inline script [ "+n.raw+" ] cannot be used.",e.line,s+n.index,a,n.raw)}))}},inlineStyleDisabled:{id:"inline-style-disabled",description:"Inline style cannot be used.",init:function(e,t){var a=this;e.addListener("tagstart",(function(e){for(var n,r=e.attrs,i=e.col+e.tagName.length+1,s=0,o=r.length;s<o;s++)"style"===(n=r[s]).name.toLowerCase()&&t.warn("Inline style [ "+n.raw+" ] cannot be used.",e.line,i+n.index,a,n.raw)}))}},inputRequiresLabel:{id:"input-requires-label",description:"All [ input ] tags must have a corresponding [ label ] tag. ",init:function(e,t){var a=this,n=[],r=[];e.addListener("tagstart",(function(t){var a=t.tagName.toLowerCase(),i=e.getMapAttrs(t.attrs),s=t.col+a.length+1;"input"===a&&r.push({event:t,col:s,id:i.id}),"label"===a&&"for"in i&&""!==i.for&&n.push({event:t,col:s,forValue:i.for})})),e.addListener("end",(function(){r.forEach((function(e){(function(e){var t=!1;return n.forEach((function(a){e.id&&e.id===a.forValue&&(t=!0)})),t})(e)||t.warn("No matching [ label ] tag found.",e.event.line,e.col,a,e.event.raw)}))}))}},scriptDisabled:{id:"script-disabled",description:"The <script> tag cannot be used.",init:function(e,t){var a=this;e.addListener("tagstart",(function(e){"script"===e.tagName.toLowerCase()&&t.error("The <script> tag cannot be used.",e.line,e.col,a,e.raw)}))}},spaceTabMixedDisabled:c,specCharEscape:{id:"spec-char-escape",description:"Special characters must be escaped.",init:function(e,t){var a=this;e.addListener("text",(function(n){for(var r,i=n.raw,s=/([<>])|( \& )/g;r=s.exec(i);){var o=e.fixPos(n,r.index);t.error("Special characters must be escaped : [ "+r[0]+" ].",o.line,o.col,a,n.raw)}}))}},srcNotEmpty:{id:"src-not-empty",description:"The src attribute of an img(script,link) must have a value.",init:function(e,t){var a=this;e.addListener("tagstart",(function(e){for(var n,r=e.tagName,i=e.attrs,s=e.col+r.length+1,o=0,l=i.length;o<l;o++)n=i[o],(!0===/^(img|script|embed|bgsound|iframe)$/.test(r)&&"src"===n.name||"link"===r&&"href"===n.name||"object"===r&&"data"===n.name)&&""===n.value&&t.error("The attribute [ "+n.name+" ] of the tag [ "+r+" ] must have a value.",e.line,s+n.index,a,n.raw)}))}},styleDisabled:{id:"style-disabled",description:"<style> tags cannot be used.",init:function(e,t){var a=this;e.addListener("tagstart",(function(e){"style"===e.tagName.toLowerCase()&&t.warn("The <style> tag cannot be used.",e.line,e.col,a,e.raw)}))}},tagPair:d,tagSelfClose:h,tagnameLowercase:f,tagnameSpecialChars:{id:"tagname-specialchars",description:"All html element names must be in lowercase.",init:function(e,t){var a=this,n=/[^a-zA-Z0-9\-:_]/;e.addListener("tagstart,tagend",(function(e){var r=e.tagName;n.test(r)&&t.error("The html element name of [ "+r+" ] contains special character.",e.line,e.col,a,e.raw)}))}},titleRequire:{id:"title-require",description:"<title> must be present in <head> tag.",init:function(e,t){var a=this,n=!1,r=!1;function i(e){var t=e.tagName.toLowerCase();"head"===t?n=!0:"title"===t&&n&&(r=!0)}e.addListener("tagstart",i),e.addListener("tagend",(function n(s){var o=s.tagName.toLowerCase();if(r&&"title"===o){var l=s.lastEvent;("text"!==l.type||"text"===l.type&&!0===/^\s*$/.test(l.raw))&&t.error("<title></title> must not be empty.",s.line,s.col,a,s.raw)}else"head"===o&&(!1===r&&t.error("<title> must be present in <head> tag.",s.line,s.col,a,s.raw),e.removeListener("tagstart",i),e.removeListener("tagend",n))}))}},tagsCheck:m,attrNoUnnecessaryWhitespace:p});function b(e,t){return new Array(e+1).join(t||" ")}const w=new class{constructor(){this.rules={},this.defaultRuleset={"tagname-lowercase":!0,"attr-lowercase":!0,"attr-value-double-quotes":!0,"doctype-first":!0,"tag-pair":!0,"spec-char-escape":!0,"id-unique":!0,"src-not-empty":!0,"attr-no-duplication":!0,"title-require":!0}}addRule(e){this.rules[e.id]=e}verify(e,n){void 0!==n&&0!==Object.keys(n).length||(n=this.defaultRuleset),e=e.replace(/^\s*<!--\s*htmlhint\s+([^\r\n]+?)\s*-->/i,(function(e,t){return void 0===n&&(n={}),t.replace(/(?:^|,)\s*([^:,]+)\s*(?:\:\s*([^,\s]+))?/g,(function(e,t,a){"false"===a?a=!1:"true"===a&&(a=!0),n[t]=void 0===a||a})),""}));var r,i=new t,s=new a(e,n),o=this.rules;for(var l in n)void 0!==(r=o[l])&&!1!==n[l]&&r.init(i,s,n[l]);return i.parse(e),s.messages}format(e,t){var a=[],n={white:"",grey:"",red:"",reset:""};(t=t||{}).colors&&(n.white="",n.grey="",n.red="",n.reset="");var r=t.indent||0;return e.forEach(e=>{var t=e.evidence,i=e.line,s=e.col,o=t.length,l=s>41?s-40:1,u=t.length>s+60?s+60:o;s<41&&(u+=40-s+1),t=t.replace(/\t/g," ").substring(l-1,u),l>1&&(t="..."+t,l-=3),u<o&&(t+="..."),a.push(n.white+b(r)+"L"+i+" |"+n.grey+t+n.reset);var c=s-l,d=t.substring(0,c).match(/[^\u0000-\u00ff]/g);null!==d&&(c+=d.length),a.push(n.white+b(r)+b(String(i).length+3+c)+"^ "+n.red+e.message+" ("+e.rule.id+")"+n.reset)}),a}};Object.keys(v).forEach(e=>{w.addRule(v[e])}),e.HTMLHint=w,e.HTMLParser=t,e.HTMLRules=v,e.Reporter=a,Object.defineProperty(e,"__esModule",{value:!0})}));