Socket
Socket
Sign inDemoInstall

html-minifier

Package Overview
Dependencies
6
Maintainers
1
Versions
80
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 1.1.1 to 1.2.0

27

cli.js

@@ -68,2 +68,3 @@ #!/usr/bin/env node

collapseBooleanAttributes: [[false, 'Omit attribute values from boolean attributes']],
removeTagWhitespace: [[false, 'Remove space between attributes whenever possible.']],
removeAttributeQuotes: [[false, 'Remove quotes around attributes when possible.']],

@@ -83,6 +84,8 @@ removeRedundantAttributes: [[false, 'Remove attributes when value matches default.']],

minifyCSS: [[false, 'Minify CSS in style elements and style attributes (uses clean-css)']],
minifyURLs: [[false, 'Minify URLs in various attributes (uses relateurl)']],
minifyURLs: [[false, 'Minify URLs in various attributes (uses relateurl)', 'string'], 'site-url'],
ignoreCustomComments: [[false, 'Array of regex\'es that allow to ignore certain comments, when matched', 'string'], 'json-regex'],
processScripts: [[false, 'Array of strings corresponding to types of script elements to process through minifier (e.g. "text/ng-template", "text/x-handlebars-template", etc.)', 'string'], 'json-regex'],
ignoreCustomFragments: [[false, 'Array of regex\'es that allow to ignore certain fragments, when matched (e.g. <?php ... ?>, {{ ... }})', 'string'], 'json-regex'],
processScripts: [[false, 'Array of strings corresponding to types of script elements to process through minifier (e.g. "text/ng-template", "text/x-handlebars-template", etc.)', 'string'], 'json'],
maxLineLength: [[false, 'Max line length', 'number'], true],
customEventAttributes: [[false, 'Arrays of regex\'es that allow to support custom event attributes for minifyJS (e.g. ng-click)', 'string'], 'json-regex'],
customAttrAssign: [[false, 'Arrays of regex\'es that allow to support custom attribute assign expressions (e.g. \'<div flex?="{{mode != cover}}"></div>\')', 'string'], 'json-regex'],

@@ -170,3 +173,3 @@ customAttrSurround: [[false, 'Arrays of regex\'es that allow to support custom attribute surround expressions (e.g. <input {{#if value}}checked="checked"{{/if}}>)', 'string'], 'json-regex'],

cli.error('Minification error');
process.stderr.write(e);
process.stderr.write((e.stack || e).toString());
}

@@ -181,3 +184,3 @@

try {
if (output !== null) {
if (output != null) {
fs.writeFileSync(path.resolve(output), minified);

@@ -196,3 +199,3 @@ }

cli.exit(status);
return status;
}

@@ -216,2 +219,3 @@

var fileList = fs.readdirSync(inputDir);
var status = 0;

@@ -229,4 +233,6 @@ fileList.forEach(function(fileName) {

var originalContent = fs.readFileSync(inputFilePath, 'utf8');
runMinify(originalContent, outputFilePath);
status = runMinify(originalContent, outputFilePath);
});
cli.exit(status);
}

@@ -243,3 +249,3 @@

try {
fs.accessSync(fileOptionsPath, fs.R_OK);
fileOptions = fs.readFileSync(fileOptionsPath, { encoding: 'utf8' });
}

@@ -250,3 +256,3 @@ catch (e) {

try {
fileOptions = JSON.parse(fs.readFileSync(fileOptionsPath), 'utf8');
fileOptions = JSON.parse(fileOptions);
}

@@ -280,2 +286,5 @@ catch (je) {

break;
case 'site-url':
minifyOptions[key] = { site: value };
break;
case true:

@@ -352,3 +361,3 @@ minifyOptions[key] = value;

runMinify(original, output);
cli.exit(runMinify(original, output));

@@ -355,0 +364,0 @@ }

/*!
* HTMLMinifier v1.1.1 (http://kangax.github.io/html-minifier/)
* HTMLMinifier v1.2.0 (http://kangax.github.io/html-minifier/)
* Copyright 2010-2016 Juriy "kangax" Zaytsev

@@ -59,9 +59,6 @@ * Licensed under the MIT license

// Empty Elements - HTML 4.01
var empty = makeMap('area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed,wbr');
// Empty Elements
var empty = makeMap('area,base,basefont,br,col,embed,frame,hr,img,input,isindex,keygen,link,meta,param,source,track,wbr');
// Block Elements - HTML 4.01
// var block = makeMap('address,applet,blockquote,button,center,dd,del,dir,div,dl,dt,fieldset,form,frameset,hr,iframe,ins,isindex,li,map,menu,noframes,noscript,object,ol,p,pre,script,table,tbody,td,tfoot,th,thead,tr,ul');
// Inline Elements - HTML 4.01
// Inline Elements
var inline = makeMap('a,abbr,acronym,applet,b,basefont,bdo,big,br,button,cite,code,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,noscript,object,q,s,samp,script,select,small,span,strike,strong,sub,sup,svg,textarea,tt,u,var');

@@ -100,3 +97,5 @@

+ handler.customAttrSurround[i][0].source
+ '\\s*'
+ startTagAttrs.source
+ '\\s*'
+ handler.customAttrSurround[i][1].source

@@ -135,5 +134,5 @@ + ')';

attrClauses[i] = '(?:'
+ '(' + handler.customAttrSurround[i][0].source + ')'
+ '(' + handler.customAttrSurround[i][0].source + ')\\s*'
+ singleAttr.source
+ '(' + handler.customAttrSurround[i][1].source + ')'
+ '\\s*(' + handler.customAttrSurround[i][1].source + ')'
+ ')';

@@ -159,3 +158,3 @@ }

var HTMLParser = global.HTMLParser = function( html, handler ) {
var index, chars, match, stack = [], last = html, prevTag, nextTag;
var index, match, stack = [], last = html, prevTag, nextTag;
stack.last = function() {

@@ -170,4 +169,2 @@ var last = this[ this.length - 1 ];

while ( html ) {
chars = true;
// Make sure we're not in a script or style element

@@ -185,3 +182,4 @@ if ( !stack.last() || !special[ stack.last() ] ) {

html = html.substring( index + 3 );
chars = false;
prevTag = '';
continue;
}

@@ -199,29 +197,9 @@ }

html = html.substring( index + 2 );
chars = false;
prevTag = '';
continue;
}
}
// Ignored elements?
else if ( /^<\?/.test( html ) ) {
index = html.indexOf( '?>', 2 );
if ( index >= 0 ) {
if ( handler.chars ) {
handler.chars( html.substring( 0, index + 2 ) );
}
html = html.substring( index + 2 );
}
}
else if ( /^<%/.test( html ) ) {
index = html.indexOf( '%>', 2 );
if ( index >= 0 ) {
if ( handler.chars ) {
handler.chars(html.substring( 0, index + 2) );
}
html = html.substring( index + 2 );
}
}
// Doctype:
else if ( (match = doctype.exec( html )) ) {
if ( (match = doctype.exec( html )) ) {
if ( handler.doctype ) {

@@ -231,9 +209,9 @@ handler.doctype( match[0] );

html = html.substring( match[0].length );
chars = false;
prevTag = '';
continue;
}
// End tag:
else if ( /^<\//.test( html ) ) {
if ( /^<\//.test( html ) ) {
match = html.match( endTag );
if ( match ) {

@@ -243,3 +221,3 @@ html = html.substring( match[0].length );

prevTag = '/' + match[1].toLowerCase();
chars = false;
continue;
}

@@ -249,3 +227,3 @@

// Start tag:
else if ( /^</.test( html ) ) {
if ( /^</.test( html ) ) {
match = html.match( startTag );

@@ -256,32 +234,30 @@ if ( match ) {

prevTag = match[1].toLowerCase();
chars = false;
continue;
}
}
if ( chars ) {
index = html.indexOf('<');
index = html.indexOf('<');
var text = index < 0 ? html : html.substring( 0, index );
html = index < 0 ? '' : html.substring( index );
var text = index < 0 ? html : html.substring( 0, index );
html = index < 0 ? '' : html.substring( index );
// next tag
tagMatch = html.match( startTag );
// next tag
tagMatch = html.match( startTag );
if (tagMatch) {
nextTag = tagMatch[1];
}
else {
tagMatch = html.match( endTag );
if (tagMatch) {
nextTag = tagMatch[1];
nextTag = '/' + tagMatch[1];
}
else {
tagMatch = html.match( endTag );
if (tagMatch) {
nextTag = '/' + tagMatch[1];
}
else {
nextTag = '';
}
nextTag = '';
}
}
if ( handler.chars ) {
handler.chars(text, prevTag, nextTag);
}
if ( handler.chars ) {
handler.chars(text, prevTag, nextTag);
}
prevTag = '';

@@ -381,5 +357,2 @@ }

value: value,
escaped: value && value.replace(/(^|.)("+)/g, function(match) {
return match.replace(/"/g, '&quot;');
}),
customAssign: customAssign || '=',

@@ -444,3 +417,3 @@ customOpen: customOpen || '',

for ( var i = 0; i < attrs.length; i++ ) {
results += ' ' + attrs[i].name + '="' + attrs[i].escaped + '"';
results += ' ' + attrs[i].name + '="' + (attrs[i].value || '').replace(/"/g, '&#34;') + '"';
}

@@ -618,47 +591,61 @@

function collapseWhitespace(str) {
function collapseWhitespaceAll(str) {
return str ? str.replace(/[\t\n\r ]+/g, ' ') : str;
}
function collapseWhitespaceSmart(str, prevTag, nextTag, options) {
function createMap(values) {
var map = {};
values.forEach(function(value) {
map[value] = 1;
});
return function(value) {
return map[value] === 1;
};
}
// array of non-empty element tags that will maintain a single space outside of them
var tags = [
'a', 'abbr', 'acronym', 'b', 'bdi', 'bdo', 'big', 'button', 'cite',
'code', 'del', 'dfn', 'em', 'font', 'i', 'ins', 'kbd', 'mark', 'q',
'rt', 'rp', 's', 'samp', 'small', 'span', 'strike', 'strong',
'sub', 'sup', 'svg', 'time', 'tt', 'u', 'var'
],
lineBreakBefore = /^[\t ]*[\n\r]+[\t\n\r ]*/,
lineBreakAfter = /[\t\n\r ]*[\n\r]+[\t ]*$/,
preserveBefore = lineBreakBefore.test(str) ? '\n' : ' ',
preserveAfter = lineBreakAfter.test(str) ? '\n' : ' ',
lineBreakStamp = 'htmlmincollapsedlinebreak';
function createMapFromString(values) {
return createMap(values.split(/,/));
}
if (prevTag && prevTag !== 'img' && prevTag !== 'input' && (prevTag.substr(0, 1) !== '/'
|| (prevTag.substr(0, 1) === '/' && (options.collapseInlineTagWhitespace || tags.indexOf(prevTag.substr(1)) === -1)))) {
str = str.replace(/^\s+/, options.conservativeCollapse ? ' ' : options.preserveLineBreaks ? preserveBefore : '');
function collapseWhitespace(str, options, trimLeft, trimRight, collapseAll) {
var lineBreakBefore = '', lineBreakAfter = '';
if (options.preserveLineBreaks) {
str = str.replace(/^[\t ]*[\n\r]+[\t\n\r ]*/, function() {
lineBreakBefore = '\n';
return '';
}).replace(/[\t\n\r ]*[\n\r]+[\t ]*$/, function() {
lineBreakAfter = '\n';
return '';
});
}
if (nextTag && nextTag !== 'img' && nextTag !== 'input' && (nextTag.substr(0, 1) === '/'
|| (nextTag.substr(0, 1) !== '/' && (options.collapseInlineTagWhitespace || tags.indexOf(nextTag) === -1)))) {
str = str.replace(/\s+$/, options.conservativeCollapse ? ' ' : options.preserveLineBreaks ? preserveAfter : '');
if (trimLeft) {
str = str.replace(/^\s+/, !lineBreakBefore && options.conservativeCollapse ? ' ' : '');
}
if (prevTag && nextTag) {
if (trimRight) {
str = str.replace(/\s+$/, !lineBreakAfter && options.conservativeCollapse ? ' ' : '');
}
if (options.preserveLineBreaks) {
str = str
.replace(lineBreakBefore, lineBreakStamp)
.replace(lineBreakAfter, lineBreakStamp);
}
if (collapseAll) {
// strip non space whitespace then compress spaces to one
return str
.replace(/[\t\n\r]+/g, ' ').replace(/[ ]+/g, ' ')
.replace(new RegExp(lineBreakStamp, 'g'), '\n');
str = collapseWhitespaceAll(str);
}
return str;
return lineBreakBefore + str + lineBreakAfter;
}
// array of non-empty element tags that will maintain a single space outside of them
var inlineTags = createMapFromString('a,abbr,acronym,b,bdi,bdo,big,button,cite,code,del,dfn,em,font,i,ins,kbd,mark,math,q,rt,rp,s,samp,small,span,strike,strong,sub,sup,svg,time,tt,u,var');
var selfClosingInlineTags = createMapFromString('comment,img,input');
function collapseWhitespaceSmart(str, prevTag, nextTag, options) {
var trimLeft = prevTag && !selfClosingInlineTags(prevTag) &&
(options.collapseInlineTagWhitespace || prevTag.charAt(0) !== '/' || !inlineTags(prevTag.substr(1)));
var trimRight = nextTag && !selfClosingInlineTags(nextTag) &&
(options.collapseInlineTagWhitespace || nextTag.charAt(0) === '/' || !inlineTags(nextTag));
return collapseWhitespace(str, options, trimLeft, trimRight, prevTag && nextTag);
}
function isConditionalComment(text) {

@@ -669,3 +656,3 @@ return ((/\[if[^\]]+\]/).test(text) || (/\s*((?:<!)?\[endif\])$/).test(text));

function isIgnoredComment(text, options) {
if ((/^!/).test(text) || /\s*htmlmin:temp/.test(text)) {
if (/^!/.test(text)) {
return true;

@@ -685,11 +672,20 @@ }

function isEventAttribute(attrName) {
return (/^on[a-z]+/).test(attrName);
function isEventAttribute(attrName, options) {
var patterns = options.customEventAttributes;
if (patterns) {
for (var i = patterns.length; i--;) {
if (patterns[i].test(attrName)) {
return true;
}
}
return false;
}
else {
return (/^on[a-z]{3,}$/).test(attrName);
}
}
function canRemoveAttributeQuotes(value, isLast) {
function canRemoveAttributeQuotes(value) {
// http://mathiasbynens.be/notes/unquoted-attribute-values
return (/^[^\x20\t\n\f\r"'`=<>]+$/).test(value) &&
// make sure trailing slash is not interpreted as HTML self-closing tag
!(isLast && (/\/$/).test(value));
return (/^[^\x20\t\n\f\r"'`=<>]+$/).test(value);
}

@@ -746,10 +742,10 @@

// https://developer.mozilla.org/en/docs/Web/HTML/Element/script#attr-type
var executableScriptsMimetypes = {
'text/javascript': 1,
'text/ecmascript': 1,
'text/jscript': 1,
'application/javascript': 1,
'application/x-javascript': 1,
'application/ecmascript': 1
};
var executableScriptsMimetypes = createMap([
'text/javascript',
'text/ecmascript',
'text/jscript',
'application/javascript',
'application/x-javascript',
'application/ecmascript'
]);

@@ -763,4 +759,4 @@ function isExecutableScript(tag, attrs) {

if (attrName === 'type') {
return attrs[i].value === '' ||
executableScriptsMimetypes[attrs[i].value] === 1;
var attrValue = trimWhitespace(attrs[i].value).split(/;/, 2)[0].toLowerCase();
return attrValue === '' || executableScriptsMimetypes(attrValue);
}

@@ -784,3 +780,3 @@ }

function isBooleanAttribute(attrName, attrValue) {
var isSimpleBoolean = (/^(?:allowfullscreen|async|autofocus|autoplay|checked|compact|controls|declare|default|defaultchecked|defaultmuted|defaultselected|defer|disabled|enabled|formnovalidate|hidden|indeterminate|inert|ismap|itemscope|loop|multiple|muted|nohref|noresize|noshade|novalidate|nowrap|open|pauseonexit|readonly|required|reversed|scoped|seamless|selected|sortable|spellcheck|truespeed|typemustmatch|visible)$/i).test(attrName);
var isSimpleBoolean = (/^(?:allowfullscreen|async|autofocus|autoplay|checked|compact|controls|declare|default|defaultchecked|defaultmuted|defaultselected|defer|disabled|enabled|formnovalidate|hidden|indeterminate|inert|ismap|itemscope|loop|multiple|muted|nohref|noresize|noshade|novalidate|nowrap|open|pauseonexit|readonly|required|reversed|scoped|seamless|selected|sortable|truespeed|typemustmatch|visible)$/i).test(attrName);
if (isSimpleBoolean) {

@@ -826,9 +822,22 @@ return true;

function isCanonicalURL(tag, attrs) {
if (tag !== 'link') {
return false;
}
for (var i = 0, len = attrs.length; i < len; i++) {
if (attrs[i].name === 'rel' && attrs[i].value === 'canonical') {
return true;
}
}
}
var fnPrefix = '!function(){';
var fnSuffix = '}();';
function cleanAttributeValue(tag, attrName, attrValue, options, attrs) {
if (attrValue && isEventAttribute(attrName)) {
if (attrValue && isEventAttribute(attrName, options)) {
attrValue = trimWhitespace(attrValue).replace(/^javascript:\s*/i, '').replace(/\s*;$/, '');
if (options.minifyJS) {
var wrappedCode = '(function(){' + attrValue + '})()';
var minified = minifyJS(wrappedCode, options.minifyJS);
return minified.slice(12, minified.length - 4).replace(/"/g, '&quot;');
var minified = minifyJS(fnPrefix + attrValue + fnSuffix, options.minifyJS);
return minified.slice(fnPrefix.length, -fnSuffix.length);
}

@@ -838,7 +847,7 @@ return attrValue;

else if (attrName === 'class') {
return collapseWhitespace(trimWhitespace(attrValue));
return collapseWhitespaceAll(trimWhitespace(attrValue));
}
else if (isUriTypeAttribute(attrName, tag)) {
attrValue = trimWhitespace(attrValue);
if (options.minifyURLs) {
if (options.minifyURLs && !isCanonicalURL(tag, attrs)) {
return minifyURLs(attrValue, options.minifyURLs);

@@ -862,3 +871,8 @@ }

else if (isMetaViewport(tag, attrs) && attrName === 'content') {
attrValue = attrValue.replace(/1\.0/g, '1').replace(/\s+/g, '');
attrValue = attrValue.replace(/\s+/g, '').replace(/[0-9]+\.[0-9]+/g, function(numString) {
// "0.90000" -> "0.9"
// "1.0" -> "1"
// "1.0001" -> "1.0001" (unchanged)
return (+numString).toString();
});
}

@@ -935,6 +949,84 @@ else if (attrValue && options.customAttrCollapse && options.customAttrCollapse.test(attrName)) {

function isOptionalTag(tag) {
return (/^(?:html|t?body|t?head|tfoot|tr|td|th|dt|dd|option|colgroup|source|track)$/).test(tag);
// Tag omission rules from https://html.spec.whatwg.org/multipage/syntax.html#optional-tags
// with the following deviations:
// - retain <body> if followed by <noscript>
// - </rb>, </rt>, </rtc>, </rp> & </tfoot> follow http://www.w3.org/TR/html5/syntax.html#optional-tags
var optionalStartTags = createMapFromString('html,head,body,colgroup,tbody');
var optionalEndTags = createMapFromString('html,head,body,li,dt,dd,p,rb,rt,rtc,rp,optgroup,option,colgroup,caption,thead,tbody,tfoot,tr,td,th');
var headerTags = createMapFromString('meta,link,script,style,template,noscript');
var descriptionTags = createMapFromString('dt,dd');
var pBlockTags = createMapFromString('address,article,aside,blockquote,details,div,dl,fieldset,figcaption,figure,footer,form,h1,h2,h3,h4,h5,h6,header,hgroup,hr,main,menu,nav,ol,p,pre,section,table,ul');
var pInlineTags = createMapFromString('a,audio,del,ins,map,noscript,video');
var rubyTags = createMapFromString('rb,rt,rtc,rp');
var rtcTag = createMapFromString('rb,rtc,rp');
var optionTag = createMapFromString('option,optgroup');
var tableContentTags = createMapFromString('tbody,tfoot');
var tableSectionTags = createMapFromString('thead,tbody,tfoot');
var cellTags = createMapFromString('td,th');
var topLevelTags = createMapFromString('html,head,body');
var compactTags = createMapFromString('html,body');
var looseTags = createMapFromString('head,colgroup,caption');
function canRemoveParentTag(optionalStartTag, tag) {
switch (optionalStartTag) {
case 'html':
case 'head':
return true;
case 'body':
return !headerTags(tag);
case 'colgroup':
return tag === 'col';
case 'tbody':
return tag === 'tr';
}
return false;
}
function isStartTagMandatory(optionalEndTag, tag) {
switch (tag) {
case 'colgroup':
return optionalEndTag === 'colgroup';
case 'tbody':
return tableSectionTags(optionalEndTag);
}
return false;
}
function canRemovePrecedingTag(optionalEndTag, tag) {
switch (optionalEndTag) {
case 'html':
case 'head':
case 'body':
case 'colgroup':
case 'caption':
return true;
case 'li':
case 'optgroup':
case 'tr':
return tag === optionalEndTag;
case 'dt':
case 'dd':
return descriptionTags(tag);
case 'p':
return pBlockTags(tag);
case 'rb':
case 'rt':
case 'rp':
return rubyTags(tag);
case 'rtc':
return rtcTag(tag);
case 'option':
return optionTag(tag);
case 'thead':
case 'tbody':
return tableContentTags(tag);
case 'tfoot':
return tag === 'tbody';
case 'td':
case 'th':
return cellTags(tag);
}
return false;
}
var reEmptyAttribute = new RegExp(

@@ -978,10 +1070,9 @@ '^(?:class|id|style|title|lang|dir|on(?:focus|blur|change|click|dblclick|mouse(' +

function normalizeAttribute(attr, attrs, tag, unarySlash, index, options, isLast) {
function normalizeAttribute(attr, attrs, tag, hasUnarySlash, index, options, isLast) {
var attrName = options.caseSensitive ? attr.name : attr.name.toLowerCase(),
attrValue = options.preventAttributesEscaping ? attr.value : attr.escaped,
attrQuote = options.preventAttributesEscaping ? attr.quote : (options.quoteCharacter === '\'' ? '\'' : '"'),
attrValue = attr.value,
attrQuote = attr.quote,
attrFragment,
emittedAttrValue,
isTerminalOfUnarySlash = unarySlash && index === attrs.length - 1;
emittedAttrValue;

@@ -1001,13 +1092,36 @@ if ((options.removeRedundantAttributes &&

if (options.removeEmptyAttributes &&
canDeleteEmptyAttribute(tag, attrName, attrValue)) {
return '';
}
if (attrValue !== undefined && !options.removeAttributeQuotes ||
!canRemoveAttributeQuotes(attrValue, isLast) || isTerminalOfUnarySlash) {
!canRemoveAttributeQuotes(attrValue)) {
if (!options.preventAttributesEscaping) {
if (options.quoteCharacter !== undefined) {
attrQuote = options.quoteCharacter === '\'' ? '\'' : '"';
}
else {
var apos = (attrValue.match(/'/g) || []).length;
var quot = (attrValue.match(/"/g) || []).length;
attrQuote = apos < quot ? '\'' : '"';
}
if (attrQuote === '"') {
attrValue = attrValue.replace(/"/g, '&#34;');
}
else {
attrValue = attrValue.replace(/'/g, '&#39;');
}
}
emittedAttrValue = attrQuote + attrValue + attrQuote;
if (!isLast && !options.removeTagWhitespace) {
emittedAttrValue += ' ';
}
}
else {
// make sure trailing slash is not interpreted as HTML self-closing tag
else if (isLast && !hasUnarySlash && !/\/$/.test(attrValue)) {
emittedAttrValue = attrValue;
}
if (options.removeEmptyAttributes &&
canDeleteEmptyAttribute(tag, attrName, attrValue)) {
return '';
else {
emittedAttrValue = attrValue + ' ';
}

@@ -1018,2 +1132,5 @@

attrFragment = attrName;
if (!isLast) {
attrFragment += ' ';
}
}

@@ -1024,3 +1141,3 @@ else {

return (' ' + attr.customOpen + attrFragment + attr.customClose);
return attr.customOpen + attrFragment + attr.customClose;
}

@@ -1157,2 +1274,10 @@

function uniqueId(value) {
var id;
do {
id = Math.random().toString(36).slice(2);
} while (~value.indexOf(id));
return id;
}
function minify(value, options) {

@@ -1168,2 +1293,3 @@

buffer = [ ],
charsPrevTag,
currentChars = '',

@@ -1174,34 +1300,41 @@ currentTag = '',

stackNoCollapseWhitespace = [],
optionalStartTag = '',
optionalEndTag = '',
lint = options.lint,
t = new Date(),
t = Date.now(),
ignoredMarkupChunks = [ ],
ignoredCustomMarkupChunks = [ ],
reIgnore = /<!-- htmlmin:ignore -->([\s\S]*?)<!-- htmlmin:ignore -->/g,
uidAttr = ' htmlmin' + (Math.random() + '').slice(2) + ' ',
reCustomIgnore,
customFragments;
uidIgnore,
uidAttr;
if (options.ignoreCustomFragments) {
customFragments = options.ignoreCustomFragments.map(function(re) {
return re.source;
if (~value.indexOf('<!-- htmlmin:ignore -->')) {
uidIgnore = '<!--!' + uniqueId(value) + '-->';
// temporarily replace ignored chunks with comments,
// so that we don't have to worry what's there.
// for all we care there might be
// completely-horribly-broken-alien-non-html-emoj-cthulhu-filled content
value = value.replace(/<!-- htmlmin:ignore -->([\s\S]*?)<!-- htmlmin:ignore -->/g, function(match, group1) {
ignoredMarkupChunks.push(group1);
return uidIgnore;
});
reCustomIgnore = new RegExp('(?:' + customFragments.join('|') + ')', 'g');
}
var customFragments = (options.ignoreCustomFragments || [
/<%[\s\S]*?%>/,
/<\?[\s\S]*?\?>/
]).map(function(re) {
return re.source;
});
if (customFragments.length) {
var reCustomIgnore = new RegExp('\\s*(?:' + customFragments.join('|') + ')\\s*', 'g');
// temporarily replace custom ignored fragments with unique attributes
value = value.replace(reCustomIgnore, function(match) {
if (!uidAttr) {
uidAttr = uniqueId(value);
}
ignoredCustomMarkupChunks.push(match);
return uidAttr;
return ' ' + uidAttr + ' ';
});
}
// temporarily replace ignored chunks with comments,
// so that we don't have to worry what's there.
// for all we care there might be
// completely-horribly-broken-alien-non-html-emoj-cthulhu-filled content
value = value.replace(reIgnore, function(match, group1) {
ignoredMarkupChunks.push(group1);
return '<!-- htmlmin:temp -->';
});
function _canCollapseWhitespace(tag, attrs) {

@@ -1215,2 +1348,18 @@ return canCollapseWhitespace(tag) || options.canCollapseWhitespace(tag, attrs);

function removeStartTag() {
var index = buffer.length - 1;
while (index > 0 && !/^<[^/!]/.test(buffer[index])) {
index--;
}
buffer.length = Math.max(0, index);
}
function removeEndTag() {
var index = buffer.length - 1;
while (index > 0 && !/^<\//.test(buffer[index])) {
index--;
}
buffer.length = index;
}
new HTMLParser(value, {

@@ -1220,3 +1369,2 @@ html5: typeof options.html5 !== 'undefined' ? options.html5 : true,

start: function(tag, attrs, unary, unarySlash) {
var lowerTag = tag.toLowerCase();

@@ -1238,5 +1386,27 @@

currentTag = tag;
charsPrevTag = tag;
currentChars = '';
currentAttrs = attrs;
var optional = options.removeOptionalTags;
if (optional) {
// <html> may be omitted if first thing inside is not comment
// <head> may be omitted if first thing inside is an element
// <body> may be omitted if first thing inside is not space, comment, <meta>, <link>, <script>, <style> or <template>
// <colgroup> may be omitted if first thing inside is <col>
// <tbody> may be omitted if first thing inside is <tr>
if (canRemoveParentTag(optionalStartTag, tag)) {
removeStartTag();
}
optionalStartTag = '';
// end-tag-followed-by-start-tag omission rules
if (canRemovePrecedingTag(optionalEndTag, tag)) {
removeEndTag();
// <colgroup> cannot be omitted if preceding </colgroup> is omitted
// <tbody> cannot be omitted if preceding </tbody>, </thead> or </tfoot> is omitted
optional = !isStartTagMandatory(optionalEndTag, tag);
}
optionalEndTag = '';
}
// set whitespace flags for nested tags (eg. <code> within a <pre>)

@@ -1253,6 +1423,3 @@ if (options.collapseWhitespace) {

var openTag = '<' + tag;
var closeTag = ((unarySlash && options.keepClosingSlash) ? '/' : '') + '>';
if (attrs.length === 0) {
openTag += closeTag;
}
var hasUnarySlash = unarySlash && options.keepClosingSlash;

@@ -1265,17 +1432,26 @@ buffer.push(openTag);

var token, isLast;
for (var i = 0, len = attrs.length; i < len; i++) {
isLast = i === len - 1;
var parts = [ ];
var token, isLast = true;
for (var i = attrs.length; --i >= 0; ) {
if (lint) {
lint.testAttribute(tag, attrs[i].name.toLowerCase(), attrs[i].escaped);
lint.testAttribute(tag, attrs[i].name.toLowerCase(), attrs[i].value);
}
token = normalizeAttribute(attrs[i], attrs, tag, unarySlash, i, options, isLast);
if (isLast) {
token += closeTag;
token = normalizeAttribute(attrs[i], attrs, tag, hasUnarySlash, i, options, isLast);
if (token) {
isLast = false;
parts.unshift(token);
}
buffer.push(token);
}
if (parts.length > 0) {
buffer.push(' ');
buffer.push.apply(buffer, parts);
}
// start tag must never be omitted if it has any attributes
else if (optional && optionalStartTags(tag)) {
optionalStartTag = tag;
}
buffer.push(buffer.pop() + (hasUnarySlash ? '/' : '') + '>');
},
end: function(tag, attrs) {
var lowerTag = tag.toLowerCase();

@@ -1286,8 +1462,36 @@ if (lowerTag === 'svg') {

tag = options.caseSensitive ? tag : lowerTag;
if (options.removeOptionalTags) {
// </html> or </body> may be omitted if not followed by comment
// </head> may be omitted if not followed by space or comment
// </p> may be omitted if no more content in non-</a> parent
// except for </dt> or </thead>, end tags may be omitted if no more content in parent element
if (optionalEndTag && optionalEndTag !== 'dt' && optionalEndTag !== 'thead' && (optionalEndTag !== 'p' || !pInlineTags(tag))) {
removeEndTag();
}
optionalEndTag = optionalEndTags(tag) ? tag : '';
}
// check if current tag is in a whitespace stack
if (options.collapseWhitespace) {
if (stackNoTrimWhitespace.length &&
tag === stackNoTrimWhitespace[stackNoTrimWhitespace.length - 1]) {
stackNoTrimWhitespace.pop();
if (stackNoTrimWhitespace.length) {
if (tag === stackNoTrimWhitespace[stackNoTrimWhitespace.length - 1]) {
stackNoTrimWhitespace.pop();
}
}
else {
var charsIndex;
if (buffer.length > 1 && buffer[buffer.length - 1] === '' && /\s+$/.test(buffer[buffer.length - 2])) {
charsIndex = buffer.length - 2;
}
else if (buffer.length > 0 && /\s+$/.test(buffer[buffer.length - 1])) {
charsIndex = buffer.length - 1;
}
if (charsIndex > 0) {
buffer[charsIndex] = buffer[charsIndex].replace(/\s+$/, function(text) {
return collapseWhitespaceSmart(text, 'comment', '/' + tag, options);
});
}
}
if (stackNoCollapseWhitespace.length &&

@@ -1299,25 +1503,20 @@ tag === stackNoCollapseWhitespace[stackNoCollapseWhitespace.length - 1]) {

var isElementEmpty = currentChars === '' && tag === currentTag;
if ((options.removeEmptyElements && isElementEmpty && canRemoveElement(tag, attrs))) {
// remove last "element" from buffer, return
for (var i = buffer.length - 1; i >= 0; i--) {
if (/^<[^\/!]/.test(buffer[i])) {
buffer.splice(i);
break;
}
}
return;
var isElementEmpty = false;
if (tag === currentTag) {
currentTag = '';
isElementEmpty = currentChars === '';
}
else if (options.removeOptionalTags && isOptionalTag(tag)) {
// noop, leave start tag in buffer
return;
if (options.removeEmptyElements && isElementEmpty && canRemoveElement(tag, attrs)) {
// remove last "element" from buffer
removeStartTag();
optionalStartTag = '';
optionalEndTag = '';
}
else {
// push end tag to buffer
buffer.push('</' + (options.caseSensitive ? tag : lowerTag) + '>');
// push out everything but the end tag
results.push.apply(results, buffer);
buffer = ['</' + tag + '>'];
charsPrevTag = '/' + tag;
currentChars = '';
}
// flush buffer
buffer.length = 0;
currentChars = '';
},

@@ -1327,3 +1526,23 @@ chars: function(text, prevTag, nextTag) {

nextTag = nextTag === '' ? 'comment' : nextTag;
if (options.collapseWhitespace) {
if (!stackNoTrimWhitespace.length) {
if (prevTag === 'comment') {
var removed = buffer[buffer.length - 1] === '';
if (removed) {
prevTag = charsPrevTag;
}
if (buffer.length > 1 && (removed || currentChars.charAt(currentChars.length - 1) === ' ')) {
var charsIndex = buffer.length - 2;
buffer[charsIndex] = buffer[charsIndex].replace(/\s+$/, function(trailingSpaces) {
text = trailingSpaces + text;
return '';
});
}
}
text = prevTag || nextTag ? collapseWhitespaceSmart(text, prevTag, nextTag, options) : trimWhitespace(text);
}
if (!stackNoCollapseWhitespace.length) {
text = prevTag && nextTag || nextTag === 'html' ? text : collapseWhitespaceAll(text);
}
}
if (currentTag === 'script' || currentTag === 'style') {

@@ -1342,2 +1561,5 @@ if (options.removeCommentsFromCDATA) {

text = minifyJS(text, options.minifyJS);
if (text.charAt(text.length - 1) === ';') {
text = text.slice(0, -1);
}
}

@@ -1347,13 +1569,18 @@ if (currentTag === 'style' && options.minifyCSS) {

}
if (options.collapseWhitespace) {
if (!stackNoTrimWhitespace.length) {
text = ((prevTag && prevTag !== 'comment') || (nextTag && nextTag !== 'comment')) ?
collapseWhitespaceSmart(text, prevTag, nextTag, options)
: trimWhitespace(text);
if (options.removeOptionalTags && text) {
// <html> may be omitted if first thing inside is not comment
// <body> may be omitted if first thing inside is not space, comment, <meta>, <link>, <script>, <style> or <template>
if (optionalStartTag === 'html' || optionalStartTag === 'body' && !/^\s/.test(text)) {
removeStartTag();
}
if (!stackNoCollapseWhitespace.length) {
text = !(prevTag && nextTag || nextTag === 'html') ? collapseWhitespace(text) : text;
optionalStartTag = '';
// </html> or </body> may be omitted if not followed by comment
// </head>, </colgroup> or </caption> may be omitted if not followed by space or comment
if (compactTags(optionalEndTag) || looseTags(optionalEndTag) && !/^\s/.test(text)) {
removeEndTag();
}
optionalEndTag = '';
}
currentChars = text;
charsPrevTag = /^\s*$/.test(text) ? prevTag : 'comment';
currentChars += text;
if (lint) {

@@ -1365,6 +1592,4 @@ lint.testChars(text);

comment: function(text, nonStandard) {
var prefix = nonStandard ? '<!' : '<!--';
var suffix = nonStandard ? '>' : '-->';
if (options.removeComments) {

@@ -1384,6 +1609,11 @@ if (isConditionalComment(text)) {

}
if (options.removeOptionalTags && text) {
// preceding comments suppress tag omissions
optionalStartTag = '';
optionalEndTag = '';
}
buffer.push(text);
},
doctype: function(doctype) {
buffer.push(options.useShortDoctype ? '<!DOCTYPE html>' : collapseWhitespace(doctype));
buffer.push(options.useShortDoctype ? '<!DOCTYPE html>' : collapseWhitespaceAll(doctype));
},

@@ -1394,15 +1624,33 @@ customAttrAssign: options.customAttrAssign,

if (options.removeOptionalTags) {
// <html> may be omitted if first thing inside is not comment
// <head> or <body> may be omitted if empty
if (topLevelTags(optionalStartTag)) {
removeStartTag();
}
// except for </dt> or </thead>, end tags may be omitted if no more content in parent element
if (optionalEndTag && optionalEndTag !== 'dt' && optionalEndTag !== 'thead') {
removeEndTag();
}
}
results.push.apply(results, buffer);
var str = joinResultSegments(results, options);
var customIgnoreRe = new RegExp('\\s*' + trimWhitespace(uidAttr) + '\\s*', 'g');
if (uidAttr) {
str = str.replace(new RegExp('(\\s*)' + uidAttr + '(\\s*)', 'g'), function(match, prefix, suffix) {
var chunk = ignoredCustomMarkupChunks.shift();
return options.collapseWhitespace ? collapseWhitespace(prefix + chunk + suffix, {
preserveLineBreaks: options.preserveLineBreaks,
conservativeCollapse: true
}, true, true) : chunk;
});
}
if (uidIgnore) {
str = str.replace(new RegExp(uidIgnore, 'g'), function() {
return ignoredMarkupChunks.shift();
});
}
str = str.replace(customIgnoreRe, function() {
return ignoredCustomMarkupChunks.shift();
});
str = str.replace(/<!-- htmlmin:temp -->/g, function() {
return ignoredMarkupChunks.shift();
});
log('minified in: ' + (new Date() - t) + 'ms');
log('minified in: ' + (Date.now() - t) + 'ms');
return str;

@@ -1436,3 +1684,3 @@ }

return str;
return trimWhitespace(str);
}

@@ -1439,0 +1687,0 @@

/*!
* HTMLMinifier v1.1.1 (http://kangax.github.io/html-minifier/)
* HTMLMinifier v1.2.0 (http://kangax.github.io/html-minifier/)
* Copyright 2010-2016 Juriy "kangax" Zaytsev
* Licensed under the MIT license
*/
!function(a){"use strict";function b(a){var b,c=new RegExp("(?:\\s*[\\w:\\.-]+(?:\\s*(?:"+d(a)+")\\s*(?:(?:\"[^\"]*\")|(?:'[^']*')|[^>\\s]+))?)*");if(a.customAttrSurround){for(var e=[],f=a.customAttrSurround.length-1;f>=0;f--)e[f]="(?:\\s*"+a.customAttrSurround[f][0].source+c.source+a.customAttrSurround[f][1].source+")";e.unshift(c.source),b=new RegExp("((?:"+e.join("|")+")*)")}else b=new RegExp("("+c.source+")");return new RegExp(j.source+b.source+k.source)}function c(a){var b=new RegExp(f.source+"(?:\\s*("+d(a)+")\\s*(?:"+i.join("|")+"))?");if(a.customAttrSurround){for(var c=[],e=a.customAttrSurround.length-1;e>=0;e--)c[e]="(?:("+a.customAttrSurround[e][0].source+")"+b.source+"("+a.customAttrSurround[e][1].source+"))";return c.unshift("(?:"+b.source+")"),new RegExp(c.join("|"),"g")}return new RegExp(b.source,"g")}function d(a){return h.concat(a.customAttrAssign||[]).map(function(a){return"(?:"+a.source+")"}).join("|")}function e(a){for(var b={},c=a.split(","),d=0;d<c.length;d++)b[c[d]]=!0,b[c[d].toUpperCase()]=!0;return b}var f=/([\w:\.-]+)/,g=/=/,h=[g],i=[/"((?:\\.|[^"])*)"/.source,/'((?:\\.|[^'])*)'/.source,/([^>\s]+)/.source],j=/^<([\w:-]+)/,k=/\s*(\/?)>/,l=/^<\/([\w:-]+)[^>]*>/,m=/\/>$/,n=/^<!DOCTYPE [^>]+>/i,o=!1;"x".replace(/x(.)?/g,function(a,b){o=""===b});var p,q,r,s=e("area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed,wbr"),t=e("a,abbr,acronym,applet,b,basefont,bdo,big,br,button,cite,code,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,noscript,object,q,s,samp,script,select,small,span,strike,strong,sub,sup,svg,textarea,tt,u,var"),u=e("colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr,source"),v=e("checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected"),w=e("script,style"),x={},y=a.HTMLParser=function(a,d){function e(a,b,c,e){for(var g=!1;!d.html5&&y.last()&&t[y.last()];)f("",y.last());u[b]&&y.last()===b&&f("",b),e=s[b]||!!e;var h=[];c.replace(B,function(){var a,b,c,e,f,g,i,j=7;if(o&&-1===arguments[0].indexOf('""')&&(""===arguments[3]&&(arguments[3]=void 0),""===arguments[4]&&(arguments[4]=void 0),""===arguments[5]&&(arguments[5]=void 0)),a=arguments[1])g=arguments[2],c=arguments[3],b=c||arguments[4]||arguments[5],g&&(i=arguments[0].charAt(a.length+g.length),i="'"===i||'"'===i?i:"");else if(d.customAttrSurround)for(var k=d.customAttrSurround.length-1;k>=0;k--)if(a=arguments[k*j+7],g=arguments[k*j+8],a){c=arguments[k*j+9],b=c||arguments[k*j+10]||arguments[k*j+11],e=arguments[k*j+6],f=arguments[k*j+12];break}void 0===b&&(b=v[a]?a:c),h.push({name:a,value:b,escaped:b&&b.replace(/(^|.)("+)/g,function(a){return a.replace(/"/g,"&quot;")}),customAssign:g||"=",customOpen:e||"",customClose:f||"",quote:i||""})}),e?g=a.match(m):y.push({tag:b,attrs:h}),d.start&&d.start(b,h,e,g)}function f(a,b){var c;if(b){var e=b.toLowerCase();for(c=y.length-1;c>=0&&y[c].tag.toLowerCase()!==e;c--);}else c=0;if(c>=0){for(var f=y.length-1;f>=c;f--)d.end&&d.end(y[f].tag,y[f].attrs);y.length=c}}var g,h,i,j,k,y=[],z=a;y.last=function(){var a=this[this.length-1];return a&&a.tag};for(var A=b(d),B=c(d);a;){if(h=!0,y.last()&&w[y.last()])p=y.last().toLowerCase(),q=x[p]||(x[p]=new RegExp("([\\s\\S]*?)</"+p+"[^>]*>","i")),a=a.replace(q,function(a,b){return"script"!==p&&"style"!==p&&"noscript"!==p&&(b=b.replace(/<!--([\s\S]*?)-->/g,"$1").replace(/<!\[CDATA\[([\s\S]*?)\]\]>/g,"$1")),d.chars&&d.chars(b),""}),f("",p);else if(/^<!--/.test(a)&&(g=a.indexOf("-->"),g>=0&&(d.comment&&d.comment(a.substring(4,g)),a=a.substring(g+3),h=!1)),/^<!\[/.test(a)?(g=a.indexOf("]>"),g>=0&&(d.comment&&d.comment(a.substring(2,g+1),!0),a=a.substring(g+2),h=!1)):/^<\?/.test(a)?(g=a.indexOf("?>",2),g>=0&&(d.chars&&d.chars(a.substring(0,g+2)),a=a.substring(g+2))):/^<%/.test(a)?(g=a.indexOf("%>",2),g>=0&&(d.chars&&d.chars(a.substring(0,g+2)),a=a.substring(g+2))):(i=n.exec(a))?(d.doctype&&d.doctype(i[0]),a=a.substring(i[0].length),h=!1):/^<\//.test(a)?(i=a.match(l),i&&(a=a.substring(i[0].length),i[0].replace(l,f),j="/"+i[1].toLowerCase(),h=!1)):/^</.test(a)&&(i=a.match(A),i&&(a=a.substring(i[0].length),i[0].replace(A,e),j=i[1].toLowerCase(),h=!1)),h){g=a.indexOf("<");var C=0>g?a:a.substring(0,g);a=0>g?"":a.substring(g),r=a.match(A),r?k=r[1]:(r=a.match(l),k=r?"/"+r[1]:""),d.chars&&d.chars(C,j,k)}if(a===z)throw"Parse Error: "+a;z=a}f()};a.HTMLtoXML=function(a){var b="";return new y(a,{start:function(a,c,d){b+="<"+a;for(var e=0;e<c.length;e++)b+=" "+c[e].name+'="'+c[e].escaped+'"';b+=(d?"/":"")+">"},end:function(a){b+="</"+a+">"},chars:function(a){b+=a},comment:function(a){b+="<!--"+a+"-->"},ignore:function(a){b+=a}}),b},a.HTMLtoDOM=function(a,b){var c=e("html,head,body,title"),d={link:"head",base:"head"};b?b=b.ownerDocument||b.getOwnerDocument&&b.getOwnerDocument()||b:"undefined"!=typeof DOMDocument?b=new DOMDocument:"undefined"!=typeof document&&document.implementation&&document.implementation.createDocument?b=document.implementation.createDocument("","",null):"undefined"!=typeof ActiveX&&(b=new ActiveXObject("Msxml.DOMDocument"));var f=[],g=b.documentElement||b.getDocumentElement&&b.getDocumentElement();if(!g&&b.createElement&&!function(){var a=b.createElement("html"),c=b.createElement("head");c.appendChild(b.createElement("title")),a.appendChild(c),a.appendChild(b.createElement("body")),b.appendChild(a)}(),b.getElementsByTagName)for(var h in c)c[h]=b.getElementsByTagName(h)[0];var i=c.body;return new y(a,{start:function(a,e,g){if(c[a])return void(i=c[a]);var h=b.createElement(a);for(var j in e)h.setAttribute(e[j].name,e[j].value);d[a]&&"boolean"!=typeof c[d[a]]?c[d[a]].appendChild(h):i&&i.appendChild&&i.appendChild(h),g||(f.push(h),i=h)},end:function(){f.length-=1,i=f[f.length-1]},chars:function(a){i.appendChild(b.createTextNode(a))},comment:function(){},ignore:function(){}}),b}}("undefined"==typeof exports?this:exports),function(a){"use strict";function b(a){return a?a.replace(/[\t\n\r ]+/g," "):a}function c(a,b,c,d){var e=["a","abbr","acronym","b","bdi","bdo","big","button","cite","code","del","dfn","em","font","i","ins","kbd","mark","q","rt","rp","s","samp","small","span","strike","strong","sub","sup","svg","time","tt","u","var"],f=/^[\t ]*[\n\r]+[\t\n\r ]*/,g=/[\t\n\r ]*[\n\r]+[\t ]*$/,h=f.test(a)?"\n":" ",i=g.test(a)?"\n":" ",j="htmlmincollapsedlinebreak";return b&&"img"!==b&&"input"!==b&&("/"!==b.substr(0,1)||"/"===b.substr(0,1)&&(d.collapseInlineTagWhitespace||-1===e.indexOf(b.substr(1))))&&(a=a.replace(/^\s+/,d.conservativeCollapse?" ":d.preserveLineBreaks?h:"")),c&&"img"!==c&&"input"!==c&&("/"===c.substr(0,1)||"/"!==c.substr(0,1)&&(d.collapseInlineTagWhitespace||-1===e.indexOf(c)))&&(a=a.replace(/\s+$/,d.conservativeCollapse?" ":d.preserveLineBreaks?i:"")),b&&c?(d.preserveLineBreaks&&(a=a.replace(f,j).replace(g,j)),a.replace(/[\t\n\r]+/g," ").replace(/[ ]+/g," ").replace(new RegExp(j,"g"),"\n")):a}function d(a){return/\[if[^\]]+\]/.test(a)||/\s*((?:<!)?\[endif\])$/.test(a)}function e(a,b){if(/^!/.test(a)||/\s*htmlmin:temp/.test(a))return!0;if(b.ignoreCustomComments)for(var c=0,d=b.ignoreCustomComments.length;d>c;c++)if(b.ignoreCustomComments[c].test(a))return!0;return!1}function f(a){return/^on[a-z]+/.test(a)}function g(a,b){return/^[^\x20\t\n\f\r"'`=<>]+$/.test(a)&&!(b&&/\/$/.test(a))}function h(a,b){for(var c=a.length;c--;)if(a[c].name.toLowerCase()===b)return!0;return!1}function i(a,b,c,d){return c=c?L(c.toLowerCase()):"","script"===a&&"language"===b&&"javascript"===c||"form"===a&&"method"===b&&"get"===c||"input"===a&&"type"===b&&"text"===c||"script"===a&&"charset"===b&&!h(d,"src")||"a"===a&&"name"===b&&h(d,"id")||"area"===a&&"shape"===b&&"rect"===c}function j(a,b,c){return"script"===a&&"type"===b&&"text/javascript"===L(c.toLowerCase())}function k(a,b){if("script"!==a)return!1;for(var c=0,d=b.length;d>c;c++){var e=b[c].name.toLowerCase();if("type"===e)return""===b[c].value||1===M[b[c].value]}return!0}function l(a,b,c){return("style"===a||"link"===a)&&"type"===b&&"text/css"===L(c.toLowerCase())}function m(a,b){var c=/^(?:allowfullscreen|async|autofocus|autoplay|checked|compact|controls|declare|default|defaultchecked|defaultmuted|defaultselected|defer|disabled|enabled|formnovalidate|hidden|indeterminate|inert|ismap|itemscope|loop|multiple|muted|nohref|noresize|noshade|novalidate|nowrap|open|pauseonexit|readonly|required|reversed|scoped|seamless|selected|sortable|spellcheck|truespeed|typemustmatch|visible)$/i.test(a);if(c)return!0;var d=N[a.toLowerCase()];return d?-1===d.indexOf(b.toLowerCase()):!1}function n(a,b){return/^(?:a|area|link|base)$/.test(b)&&"href"===a||"img"===b&&/^(?:src|longdesc|usemap)$/.test(a)||"object"===b&&/^(?:classid|codebase|data|usemap)$/.test(a)||"q"===b&&"cite"===a||"blockquote"===b&&"cite"===a||("ins"===b||"del"===b)&&"cite"===a||"form"===b&&"action"===a||"input"===b&&("src"===a||"usemap"===a)||"head"===b&&"profile"===a||"script"===b&&("src"===a||"for"===a)}function o(a,b){return/^(?:a|area|object|button)$/.test(b)&&"tabindex"===a||"input"===b&&("maxlength"===a||"tabindex"===a)||"select"===b&&("size"===a||"tabindex"===a)||"textarea"===b&&/^(?:rows|cols|tabindex)$/.test(a)||"colgroup"===b&&"span"===a||"col"===b&&"span"===a||("th"===b||"td"===b)&&("rowspan"===a||"colspan"===a)}function p(a,c,d,e,g){if(d&&f(c)){if(d=L(d).replace(/^javascript:\s*/i,"").replace(/\s*;$/,""),e.minifyJS){var h="(function(){"+d+"})()",i=F(h,e.minifyJS);return i.slice(12,i.length-4).replace(/"/g,"&quot;")}return d}return"class"===c?b(L(d)):n(c,a)?(d=L(d),e.minifyURLs?E(d,e.minifyURLs):d):o(c,a)?L(d):"style"===c?(d=L(d),d&&(d=d.replace(/\s*;\s*$/,"")),e.minifyCSS?G(d,e.minifyCSS,!0):d):(q(a,g)&&"content"===c?d=d.replace(/1\.0/g,"1").replace(/\s+/g,""):d&&e.customAttrCollapse&&e.customAttrCollapse.test(c)&&(d=d.replace(/\n+|\r+|\s{2,}/g,"")),d)}function q(a,b){if("meta"!==a)return!1;for(var c=0,d=b.length;d>c;c++)if("name"===b[c].name&&"viewport"===b[c].value)return!0}function r(a){return"*{"+a+"}"}function s(a){var b=a.match(/^\*\{([\s\S]*)\}$/m);return b&&b[1]?b[1]:a}function t(a){return a.replace(/^(\[[^\]]+\]>)\s*/,"$1").replace(/\s*(<!\[endif\])$/,"$1")}function u(a){return a.replace(/^(?:\s*\/\*\s*<!\[CDATA\[\s*\*\/|\s*\/\/\s*<!\[CDATA\[.*)/,"").replace(/(?:\/\*\s*\]\]>\s*\*\/|\/\/\s*\]\]>)\s*$/,"")}function v(a,b,c){for(var d=0,e=c.length;e>d;d++)if("type"===c[d].name.toLowerCase()&&b.processScripts.indexOf(c[d].value)>-1)return H(a,b);return a}function w(a,b){return a.replace(O[b],"").replace(P[b],"")}function x(a){return/^(?:html|t?body|t?head|tfoot|tr|td|th|dt|dd|option|colgroup|source|track)$/.test(a)}function y(a,b,c){var d=!c||/^\s*$/.test(c);return d?"input"===a&&"value"===b||Q.test(b):!1}function z(a,b){if("textarea"===a)return!1;if("script"===a)for(var c=b.length-1;c>=0;c--)if("src"===b[c].name)return!1;return!0}function A(a){return!/^(?:script|style|pre|textarea)$/.test(a)}function B(a){return!/^(?:pre|textarea)$/.test(a)}function C(a,b,c,d,e,f,h){var k,n,o=f.caseSensitive?a.name:a.name.toLowerCase(),q=f.preventAttributesEscaping?a.value:a.escaped,r=f.preventAttributesEscaping?a.quote:"'"===f.quoteCharacter?"'":'"',s=d&&e===b.length-1;return f.removeRedundantAttributes&&i(c,o,q,b)||f.removeScriptTypeAttributes&&j(c,o,q)||f.removeStyleLinkTypeAttributes&&l(c,o,q)?"":(q=p(c,o,q,f,b),n=void 0!==q&&!f.removeAttributeQuotes||!g(q,h)||s?r+q+r:q,f.removeEmptyAttributes&&y(c,o,q)?"":(k=void 0===q||f.collapseBooleanAttributes&&m(o,q)?o:o+a.customAssign+n," "+a.customOpen+k+a.customClose))}function D(a){for(var b=["canCollapseWhitespace","canTrimWhitespace"],c=0,d=b.length;d>c;c++)a[b[c]]||(a[b[c]]=function(){return!1})}function E(b,c){"object"!=typeof c&&(c={});try{var d=a.RelateUrl;return"undefined"==typeof d&&"function"==typeof require&&(d=require("relateurl")),d&&d.relate?d.relate(b,c):b}catch(e){J(e)}return b}function F(b,c){"object"!=typeof c&&(c={}),c.fromString=!0;var d=c.output||{};d.inline_script=!0,c.output=d;try{var e=a.UglifyJS;if("undefined"==typeof e&&"function"==typeof require&&(e=require("uglify-js")),!e)return b;if(e.minify)return e.minify(b,c).code;if(e.parse){var f=e.parse(b);f.figure_out_scope();var g=e.Compressor(),h=f.transform(g);h.figure_out_scope(),h.compute_char_frequency(),c.mangle!==!1&&h.mangle_names();var i=e.OutputStream(c.output);return h.print(i),i.toString()}return b}catch(j){J(j)}return b}function G(a,b,c){"object"!=typeof b&&(b={}),"undefined"==typeof b.advanced&&(b.advanced=!1);try{var d;if("undefined"!=typeof CleanCSS)d=new CleanCSS(b);else if("function"==typeof require){var e=require("clean-css");d=new e(b)}return c?s(d.minify(r(a)).styles):d.minify(a).styles}catch(f){J(f)}return a}function H(a,f){function g(a,b){return A(a)||f.canCollapseWhitespace(a,b)}function h(a,b){return B(a)||f.canTrimWhitespace(a,b)}f=f||{};var i=[];a=L(a),D(f);var j,l,m=[],n=[],o="",p="",q=[],r=[],s=[],y=f.lint,E=new Date,H=[],M=[],N=/<!-- htmlmin:ignore -->([\s\S]*?)<!-- htmlmin:ignore -->/g,O=" htmlmin"+(Math.random()+"").slice(2)+" ";f.ignoreCustomFragments&&(l=f.ignoreCustomFragments.map(function(a){return a.source}),j=new RegExp("(?:"+l.join("|")+")","g"),a=a.replace(j,function(a){return M.push(a),O})),a=a.replace(N,function(a,b){return H.push(b),"<!-- htmlmin:temp -->"}),new K(a,{html5:"undefined"!=typeof f.html5?f.html5:!0,start:function(a,b,c,d){var e=a.toLowerCase();if("svg"===e){i.push(f);var j={};for(var k in f)j[k]=f[k];j.keepClosingSlash=!0,j.caseSensitive=!0,f=j}a=f.caseSensitive?a:e,p=a,o="",q=b,f.collapseWhitespace&&(h(a,b)||r.push(a),g(a,b)||s.push(a));var l="<"+a,m=(d&&f.keepClosingSlash?"/":"")+">";0===b.length&&(l+=m),n.push(l),y&&y.testElement(a);for(var t,u,v=0,w=b.length;w>v;v++)u=v===w-1,y&&y.testAttribute(a,b[v].name.toLowerCase(),b[v].escaped),t=C(b[v],b,a,d,v,f,u),u&&(t+=m),n.push(t)},end:function(a,b){var c=a.toLowerCase();"svg"===c&&(f=i.pop()),f.collapseWhitespace&&(r.length&&a===r[r.length-1]&&r.pop(),s.length&&a===s[s.length-1]&&s.pop());var d=""===o&&a===p;if(f.removeEmptyElements&&d&&z(a,b)){for(var e=n.length-1;e>=0;e--)if(/^<[^\/!]/.test(n[e])){n.splice(e);break}}else f.removeOptionalTags&&x(a)||(n.push("</"+(f.caseSensitive?a:c)+">"),m.push.apply(m,n),n.length=0,o="")},chars:function(a,d,e){d=""===d?"comment":d,e=""===e?"comment":e,("script"===p||"style"===p)&&(f.removeCommentsFromCDATA&&(a=w(a,p)),f.removeCDATASectionsFromCDATA&&(a=u(a)),f.processScripts&&(a=v(a,f,q))),f.minifyJS&&k(p,q)&&(a=F(a,f.minifyJS)),"style"===p&&f.minifyCSS&&(a=G(a,f.minifyCSS)),f.collapseWhitespace&&(r.length||(a=d&&"comment"!==d||e&&"comment"!==e?c(a,d,e,f):L(a)),s.length||(a=d&&e||"html"===e?a:b(a))),o=a,y&&y.testChars(a),n.push(a)},comment:function(a,b){var c=b?"<!":"<!--",g=b?">":"-->";a=f.removeComments?d(a)?c+t(a)+g:e(a,f)?"<!--"+a+"-->":"":c+a+g,n.push(a)},doctype:function(a){n.push(f.useShortDoctype?"<!DOCTYPE html>":b(a))},customAttrAssign:f.customAttrAssign,customAttrSurround:f.customAttrSurround}),m.push.apply(m,n);var P=I(m,f),Q=new RegExp("\\s*"+L(O)+"\\s*","g");return P=P.replace(Q,function(){return M.shift()}),P=P.replace(/<!-- htmlmin:temp -->/g,function(){return H.shift()}),J("minified in: "+(new Date-E)+"ms"),P}function I(a,b){var c,d=b.maxLineLength;if(d){for(var e,f=[],g="",h=0,i=a.length;i>h;h++)e=a[h],g.length+e.length<d?g+=e:(f.push(g.replace(/^\n/,"")),g=e);f.push(g),c=f.join("\n")}else c=a.join("");return c}var J,K;J=a.console&&a.console.log?function(b){a.console.log(b)}:function(){},a.HTMLParser?K=a.HTMLParser:"function"==typeof require&&(K=require("./htmlparser").HTMLParser);var L=function(a){return"string"!=typeof a?a:a.replace(/^\s+/,"").replace(/\s+$/,"")};String.prototype.trim&&(L=function(a){return"string"!=typeof a?a:a.trim()});var M={"text/javascript":1,"text/ecmascript":1,"text/jscript":1,"application/javascript":1,"application/x-javascript":1,"application/ecmascript":1},N={draggable:["true","false"]},O={script:/^\s*(?:\/\/)?\s*<!--.*\n?/,style:/^\s*<!--\s*/},P={script:/\s*(?:\/\/)?\s*-->\s*$/,style:/\s*-->\s*$/},Q=new RegExp("^(?:class|id|style|title|lang|dir|on(?:focus|blur|change|click|dblclick|mouse(?:down|up|over|move|out)|key(?:press|down|up)))$");"undefined"!=typeof exports?exports.minify=H:a.minify=H}("undefined"==typeof exports?this:exports),function(a){"use strict";function b(a){return/^(?:big|small|hr|blink|marquee)$/.test(a)}function c(a){return/^(?:applet|basefont|center|dir|font|isindex|strike)$/.test(a)}function d(a){return/^on[a-z]+/.test(a)}function e(a){return"style"===a.toLowerCase()}function f(a,b){return"align"===b&&/^(?:caption|applet|iframe|img|imput|object|legend|table|hr|div|h[1-6]|p)$/.test(a)||"alink"===b&&"body"===a||"alt"===b&&"applet"===a||"archive"===b&&"applet"===a||"background"===b&&"body"===a||"bgcolor"===b&&/^(?:table|t[rdh]|body)$/.test(a)||"border"===b&&/^(?:img|object)$/.test(a)||"clear"===b&&"br"===a||"code"===b&&"applet"===a||"codebase"===b&&"applet"===a||"color"===b&&/^(?:base(?:font)?)$/.test(a)||"compact"===b&&/^(?:dir|[dou]l|menu)$/.test(a)||"face"===b&&/^base(?:font)?$/.test(a)||"height"===b&&/^(?:t[dh]|applet)$/.test(a)||"hspace"===b&&/^(?:applet|img|object)$/.test(a)||"language"===b&&"script"===a||"link"===b&&"body"===a||"name"===b&&"applet"===a||"noshade"===b&&"hr"===a||"nowrap"===b&&/^t[dh]$/.test(a)||"object"===b&&"applet"===a||"prompt"===b&&"isindex"===a||"size"===b&&/^(?:hr|font|basefont)$/.test(a)||"start"===b&&"ol"===a||"text"===b&&"body"===a||"type"===b&&/^(?:li|ol|ul)$/.test(a)||"value"===b&&"li"===a||"version"===b&&"html"===a||"vlink"===b&&"body"===a||"vspace"===b&&/^(?:applet|img|object)$/.test(a)||"width"===b&&/^(?:hr|td|th|applet|pre)$/.test(a)}function g(a,b){return"href"===a&&/^\s*javascript\s*:\s*void\s*(\s+0|\(\s*0\s*\))\s*$/i.test(b)}function h(){this.log=[],this._lastElement=null,this._isElementRepeated=!1}h.prototype.testElement=function(a){c(a)?this.log.push('Found <span class="deprecated-element">deprecated</span> <strong><code>&lt;'+a+"&gt;</code></strong> element"):b(a)?this.log.push('Found <span class="presentational-element">presentational</span> <strong><code>&lt;'+a+"&gt;</code></strong> element"):this.checkRepeatingElement(a)},h.prototype.checkRepeatingElement=function(a){"br"===a&&"br"===this._lastElement?this._isElementRepeated=!0:this._isElementRepeated&&(this._reportRepeatingElement(),this._isElementRepeated=!1),this._lastElement=a},h.prototype._reportRepeatingElement=function(){this.log.push("Found <code>&lt;br></code> sequence. Try replacing it with styling.")},h.prototype.testAttribute=function(a,b,c){d(b)?this.log.push('Found <span class="event-attribute">event attribute</span> (<strong>'+b+"</strong>) on <strong><code>&lt;"+a+"&gt;</code></strong> element."):f(a,b)?this.log.push('Found <span class="deprecated-attribute">deprecated</span> <strong>'+b+"</strong> attribute on <strong><code>&lt;"+a+"&gt;</code></strong> element."):e(b)?this.log.push('Found <span class="style-attribute">style attribute</span> on <strong><code>&lt;'+a+"&gt;</code></strong> element."):g(b,c)&&this.log.push('Found <span class="inaccessible-attribute">inaccessible attribute</span> (on <strong><code>&lt;'+a+"&gt;</code></strong> element).")},h.prototype.testChars=function(a){this._lastElement="",/(&nbsp;\s*){2,}/.test(a)&&this.log.push("Found repeating <strong><code>&amp;nbsp;</code></strong> sequence. Try replacing it with styling.")},h.prototype.test=function(a,b,c){this.testElement(a),this.testAttribute(a,b,c)},h.prototype.populate=function(a){if(this._isElementRepeated&&this._reportRepeatingElement(),this.log.length)if(a)a.innerHTML="<ol><li>"+this.log.join("<li>")+"</ol>";else{var b=" - "+this.log.join("\n - ").replace(/(<([^>]+)>)/gi,"").replace(/&lt;/g,"<").replace(/&gt;/g,">");console.log(b)}},a.HTMLLint=h}("undefined"==typeof exports?this:exports);
!function(a){"use strict";function b(a){var b,c=new RegExp("(?:\\s*[\\w:\\.-]+(?:\\s*(?:"+d(a)+")\\s*(?:(?:\"[^\"]*\")|(?:'[^']*')|[^>\\s]+))?)*");if(a.customAttrSurround){for(var e=[],f=a.customAttrSurround.length-1;f>=0;f--)e[f]="(?:\\s*"+a.customAttrSurround[f][0].source+"\\s*"+c.source+"\\s*"+a.customAttrSurround[f][1].source+")";e.unshift(c.source),b=new RegExp("((?:"+e.join("|")+")*)")}else b=new RegExp("("+c.source+")");return new RegExp(j.source+b.source+k.source)}function c(a){var b=new RegExp(f.source+"(?:\\s*("+d(a)+")\\s*(?:"+i.join("|")+"))?");if(a.customAttrSurround){for(var c=[],e=a.customAttrSurround.length-1;e>=0;e--)c[e]="(?:("+a.customAttrSurround[e][0].source+")\\s*"+b.source+"\\s*("+a.customAttrSurround[e][1].source+"))";return c.unshift("(?:"+b.source+")"),new RegExp(c.join("|"),"g")}return new RegExp(b.source,"g")}function d(a){return h.concat(a.customAttrAssign||[]).map(function(a){return"(?:"+a.source+")"}).join("|")}function e(a){for(var b={},c=a.split(","),d=0;d<c.length;d++)b[c[d]]=!0,b[c[d].toUpperCase()]=!0;return b}var f=/([\w:\.-]+)/,g=/=/,h=[g],i=[/"((?:\\.|[^"])*)"/.source,/'((?:\\.|[^'])*)'/.source,/([^>\s]+)/.source],j=/^<([\w:-]+)/,k=/\s*(\/?)>/,l=/^<\/([\w:-]+)[^>]*>/,m=/\/>$/,n=/^<!DOCTYPE [^>]+>/i,o=!1;"x".replace(/x(.)?/g,function(a,b){o=""===b});var p,q,r,s=e("area,base,basefont,br,col,embed,frame,hr,img,input,isindex,keygen,link,meta,param,source,track,wbr"),t=e("a,abbr,acronym,applet,b,basefont,bdo,big,br,button,cite,code,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,noscript,object,q,s,samp,script,select,small,span,strike,strong,sub,sup,svg,textarea,tt,u,var"),u=e("colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr,source"),v=e("checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected"),w=e("script,style"),x={},y=a.HTMLParser=function(a,d){function e(a,b,c,e){for(var g=!1;!d.html5&&k.last()&&t[k.last()];)f("",k.last());u[b]&&k.last()===b&&f("",b),e=s[b]||!!e;var h=[];c.replace(A,function(){var a,b,c,e,f,g,i,j=7;if(o&&-1===arguments[0].indexOf('""')&&(""===arguments[3]&&(arguments[3]=void 0),""===arguments[4]&&(arguments[4]=void 0),""===arguments[5]&&(arguments[5]=void 0)),a=arguments[1])g=arguments[2],c=arguments[3],b=c||arguments[4]||arguments[5],g&&(i=arguments[0].charAt(a.length+g.length),i="'"===i||'"'===i?i:"");else if(d.customAttrSurround)for(var k=d.customAttrSurround.length-1;k>=0;k--)if(a=arguments[k*j+7],g=arguments[k*j+8],a){c=arguments[k*j+9],b=c||arguments[k*j+10]||arguments[k*j+11],e=arguments[k*j+6],f=arguments[k*j+12];break}void 0===b&&(b=v[a]?a:c),h.push({name:a,value:b,customAssign:g||"=",customOpen:e||"",customClose:f||"",quote:i||""})}),e?g=a.match(m):k.push({tag:b,attrs:h}),d.start&&d.start(b,h,e,g)}function f(a,b){var c;if(b){var e=b.toLowerCase();for(c=k.length-1;c>=0&&k[c].tag.toLowerCase()!==e;c--);}else c=0;if(c>=0){for(var f=k.length-1;f>=c;f--)d.end&&d.end(k[f].tag,k[f].attrs);k.length=c}}var g,h,i,j,k=[],y=a;k.last=function(){var a=this[this.length-1];return a&&a.tag};for(var z=b(d),A=c(d);a;){if(k.last()&&w[k.last()])p=k.last().toLowerCase(),q=x[p]||(x[p]=new RegExp("([\\s\\S]*?)</"+p+"[^>]*>","i")),a=a.replace(q,function(a,b){return"script"!==p&&"style"!==p&&"noscript"!==p&&(b=b.replace(/<!--([\s\S]*?)-->/g,"$1").replace(/<!\[CDATA\[([\s\S]*?)\]\]>/g,"$1")),d.chars&&d.chars(b),""}),f("",p);else{if(/^<!--/.test(a)&&(g=a.indexOf("-->"),g>=0)){d.comment&&d.comment(a.substring(4,g)),a=a.substring(g+3),i="";continue}if(/^<!\[/.test(a)&&(g=a.indexOf("]>"),g>=0)){d.comment&&d.comment(a.substring(2,g+1),!0),a=a.substring(g+2),i="";continue}if(h=n.exec(a)){d.doctype&&d.doctype(h[0]),a=a.substring(h[0].length),i="";continue}if(/^<\//.test(a)&&(h=a.match(l))){a=a.substring(h[0].length),h[0].replace(l,f),i="/"+h[1].toLowerCase();continue}if(/^</.test(a)&&(h=a.match(z))){a=a.substring(h[0].length),h[0].replace(z,e),i=h[1].toLowerCase();continue}g=a.indexOf("<");var B=0>g?a:a.substring(0,g);a=0>g?"":a.substring(g),r=a.match(z),r?j=r[1]:(r=a.match(l),j=r?"/"+r[1]:""),d.chars&&d.chars(B,i,j),i=""}if(a===y)throw"Parse Error: "+a;y=a}f()};a.HTMLtoXML=function(a){var b="";return new y(a,{start:function(a,c,d){b+="<"+a;for(var e=0;e<c.length;e++)b+=" "+c[e].name+'="'+(c[e].value||"").replace(/"/g,"&#34;")+'"';b+=(d?"/":"")+">"},end:function(a){b+="</"+a+">"},chars:function(a){b+=a},comment:function(a){b+="<!--"+a+"-->"},ignore:function(a){b+=a}}),b},a.HTMLtoDOM=function(a,b){var c=e("html,head,body,title"),d={link:"head",base:"head"};b?b=b.ownerDocument||b.getOwnerDocument&&b.getOwnerDocument()||b:"undefined"!=typeof DOMDocument?b=new DOMDocument:"undefined"!=typeof document&&document.implementation&&document.implementation.createDocument?b=document.implementation.createDocument("","",null):"undefined"!=typeof ActiveX&&(b=new ActiveXObject("Msxml.DOMDocument"));var f=[],g=b.documentElement||b.getDocumentElement&&b.getDocumentElement();if(!g&&b.createElement&&!function(){var a=b.createElement("html"),c=b.createElement("head");c.appendChild(b.createElement("title")),a.appendChild(c),a.appendChild(b.createElement("body")),b.appendChild(a)}(),b.getElementsByTagName)for(var h in c)c[h]=b.getElementsByTagName(h)[0];var i=c.body;return new y(a,{start:function(a,e,g){if(c[a])return void(i=c[a]);var h=b.createElement(a);for(var j in e)h.setAttribute(e[j].name,e[j].value);d[a]&&"boolean"!=typeof c[d[a]]?c[d[a]].appendChild(h):i&&i.appendChild&&i.appendChild(h),g||(f.push(h),i=h)},end:function(){f.length-=1,i=f[f.length-1]},chars:function(a){i.appendChild(b.createTextNode(a))},comment:function(){},ignore:function(){}}),b}}("undefined"==typeof exports?this:exports),function(a){"use strict";function b(a){return a?a.replace(/[\t\n\r ]+/g," "):a}function c(a){var b={};return a.forEach(function(a){b[a]=1}),function(a){return 1===b[a]}}function d(a){return c(a.split(/,/))}function e(a,c,d,e,f){var g="",h="";return c.preserveLineBreaks&&(a=a.replace(/^[\t ]*[\n\r]+[\t\n\r ]*/,function(){return g="\n",""}).replace(/[\t\n\r ]*[\n\r]+[\t ]*$/,function(){return h="\n",""})),d&&(a=a.replace(/^\s+/,!g&&c.conservativeCollapse?" ":"")),e&&(a=a.replace(/\s+$/,!h&&c.conservativeCollapse?" ":"")),f&&(a=b(a)),g+a+h}function f(a,b,c,d){var f=b&&!U(b)&&(d.collapseInlineTagWhitespace||"/"!==b.charAt(0)||!T(b.substr(1))),g=c&&!U(c)&&(d.collapseInlineTagWhitespace||"/"===c.charAt(0)||!T(c));return e(a,d,f,g,b&&c)}function g(a){return/\[if[^\]]+\]/.test(a)||/\s*((?:<!)?\[endif\])$/.test(a)}function h(a,b){if(/^!/.test(a))return!0;if(b.ignoreCustomComments)for(var c=0,d=b.ignoreCustomComments.length;d>c;c++)if(b.ignoreCustomComments[c].test(a))return!0;return!1}function i(a,b){var c=b.customEventAttributes;if(c){for(var d=c.length;d--;)if(c[d].test(a))return!0;return!1}return/^on[a-z]{3,}$/.test(a)}function j(a){return/^[^\x20\t\n\f\r"'`=<>]+$/.test(a)}function k(a,b){for(var c=a.length;c--;)if(a[c].name.toLowerCase()===b)return!0;return!1}function l(a,b,c,d){return c=c?S(c.toLowerCase()):"","script"===a&&"language"===b&&"javascript"===c||"form"===a&&"method"===b&&"get"===c||"input"===a&&"type"===b&&"text"===c||"script"===a&&"charset"===b&&!k(d,"src")||"a"===a&&"name"===b&&k(d,"id")||"area"===a&&"shape"===b&&"rect"===c}function m(a,b,c){return"script"===a&&"type"===b&&"text/javascript"===S(c.toLowerCase())}function n(a,b){if("script"!==a)return!1;for(var c=0,d=b.length;d>c;c++){var e=b[c].name.toLowerCase();if("type"===e){var f=S(b[c].value).split(/;/,2)[0].toLowerCase();return""===f||V(f)}}return!0}function o(a,b,c){return("style"===a||"link"===a)&&"type"===b&&"text/css"===S(c.toLowerCase())}function p(a,b){var c=/^(?:allowfullscreen|async|autofocus|autoplay|checked|compact|controls|declare|default|defaultchecked|defaultmuted|defaultselected|defer|disabled|enabled|formnovalidate|hidden|indeterminate|inert|ismap|itemscope|loop|multiple|muted|nohref|noresize|noshade|novalidate|nowrap|open|pauseonexit|readonly|required|reversed|scoped|seamless|selected|sortable|truespeed|typemustmatch|visible)$/i.test(a);if(c)return!0;var d=W[a.toLowerCase()];return d?-1===d.indexOf(b.toLowerCase()):!1}function q(a,b){return/^(?:a|area|link|base)$/.test(b)&&"href"===a||"img"===b&&/^(?:src|longdesc|usemap)$/.test(a)||"object"===b&&/^(?:classid|codebase|data|usemap)$/.test(a)||"q"===b&&"cite"===a||"blockquote"===b&&"cite"===a||("ins"===b||"del"===b)&&"cite"===a||"form"===b&&"action"===a||"input"===b&&("src"===a||"usemap"===a)||"head"===b&&"profile"===a||"script"===b&&("src"===a||"for"===a)}function r(a,b){return/^(?:a|area|object|button)$/.test(b)&&"tabindex"===a||"input"===b&&("maxlength"===a||"tabindex"===a)||"select"===b&&("size"===a||"tabindex"===a)||"textarea"===b&&/^(?:rows|cols|tabindex)$/.test(a)||"colgroup"===b&&"span"===a||"col"===b&&"span"===a||("th"===b||"td"===b)&&("rowspan"===a||"colspan"===a)}function s(a,b){if("link"!==a)return!1;for(var c=0,d=b.length;d>c;c++)if("rel"===b[c].name&&"canonical"===b[c].value)return!0}function t(a,c,d,e,f){if(d&&i(c,e)){if(d=S(d).replace(/^javascript:\s*/i,"").replace(/\s*;$/,""),e.minifyJS){var g=L(X+d+Y,e.minifyJS);return g.slice(X.length,-Y.length)}return d}return"class"===c?b(S(d)):q(c,a)?(d=S(d),e.minifyURLs&&!s(a,f)?K(d,e.minifyURLs):d):r(c,a)?S(d):"style"===c?(d=S(d),d&&(d=d.replace(/\s*;\s*$/,"")),e.minifyCSS?M(d,e.minifyCSS,!0):d):(u(a,f)&&"content"===c?d=d.replace(/\s+/g,"").replace(/[0-9]+\.[0-9]+/g,function(a){return(+a).toString()}):d&&e.customAttrCollapse&&e.customAttrCollapse.test(c)&&(d=d.replace(/\n+|\r+|\s{2,}/g,"")),d)}function u(a,b){if("meta"!==a)return!1;for(var c=0,d=b.length;d>c;c++)if("name"===b[c].name&&"viewport"===b[c].value)return!0}function v(a){return"*{"+a+"}"}function w(a){var b=a.match(/^\*\{([\s\S]*)\}$/m);return b&&b[1]?b[1]:a}function x(a){return a.replace(/^(\[[^\]]+\]>)\s*/,"$1").replace(/\s*(<!\[endif\])$/,"$1")}function y(a){return a.replace(/^(?:\s*\/\*\s*<!\[CDATA\[\s*\*\/|\s*\/\/\s*<!\[CDATA\[.*)/,"").replace(/(?:\/\*\s*\]\]>\s*\*\/|\/\/\s*\]\]>)\s*$/,"")}function z(a,b,c){for(var d=0,e=c.length;e>d;d++)if("type"===c[d].name.toLowerCase()&&b.processScripts.indexOf(c[d].value)>-1)return O(a,b);return a}function A(a,b){return a.replace(Z[b],"").replace($[b],"")}function B(a,b){switch(a){case"html":case"head":return!0;case"body":return!ba(b);case"colgroup":return"col"===b;case"tbody":return"tr"===b}return!1}function C(a,b){switch(b){case"colgroup":return"colgroup"===a;case"tbody":return ja(a)}return!1}function D(a,b){switch(a){case"html":case"head":case"body":case"colgroup":case"caption":return!0;case"li":case"optgroup":case"tr":return b===a;case"dt":case"dd":return ca(b);case"p":return da(b);case"rb":case"rt":case"rp":return fa(b);case"rtc":return ga(b);case"option":return ha(b);case"thead":case"tbody":return ia(b);case"tfoot":return"tbody"===b;case"td":case"th":return ka(b)}return!1}function E(a,b,c){var d=!c||/^\s*$/.test(c);return d?"input"===a&&"value"===b||oa.test(b):!1}function F(a,b){if("textarea"===a)return!1;if("script"===a)for(var c=b.length-1;c>=0;c--)if("src"===b[c].name)return!1;return!0}function G(a){return!/^(?:script|style|pre|textarea)$/.test(a)}function H(a){return!/^(?:pre|textarea)$/.test(a)}function I(a,b,c,d,e,f,g){var h,i,k=f.caseSensitive?a.name:a.name.toLowerCase(),n=a.value,q=a.quote;if(f.removeRedundantAttributes&&l(c,k,n,b)||f.removeScriptTypeAttributes&&m(c,k,n)||f.removeStyleLinkTypeAttributes&&o(c,k,n))return"";if(n=t(c,k,n,f,b),f.removeEmptyAttributes&&E(c,k,n))return"";if(void 0!==n&&!f.removeAttributeQuotes||!j(n)){if(!f.preventAttributesEscaping){if(void 0!==f.quoteCharacter)q="'"===f.quoteCharacter?"'":'"';else{var r=(n.match(/'/g)||[]).length,s=(n.match(/"/g)||[]).length;q=s>r?"'":'"'}n='"'===q?n.replace(/"/g,"&#34;"):n.replace(/'/g,"&#39;")}i=q+n+q,g||f.removeTagWhitespace||(i+=" ")}else i=!g||d||/\/$/.test(n)?n+" ":n;return void 0===n||f.collapseBooleanAttributes&&p(k,n)?(h=k,g||(h+=" ")):h=k+a.customAssign+i,a.customOpen+h+a.customClose}function J(a){for(var b=["canCollapseWhitespace","canTrimWhitespace"],c=0,d=b.length;d>c;c++)a[b[c]]||(a[b[c]]=function(){return!1})}function K(b,c){"object"!=typeof c&&(c={});try{var d=a.RelateUrl;return"undefined"==typeof d&&"function"==typeof require&&(d=require("relateurl")),d&&d.relate?d.relate(b,c):b}catch(e){Q(e)}return b}function L(b,c){"object"!=typeof c&&(c={}),c.fromString=!0;var d=c.output||{};d.inline_script=!0,c.output=d;try{var e=a.UglifyJS;if("undefined"==typeof e&&"function"==typeof require&&(e=require("uglify-js")),!e)return b;if(e.minify)return e.minify(b,c).code;if(e.parse){var f=e.parse(b);f.figure_out_scope();var g=e.Compressor(),h=f.transform(g);h.figure_out_scope(),h.compute_char_frequency(),c.mangle!==!1&&h.mangle_names();var i=e.OutputStream(c.output);return h.print(i),i.toString()}return b}catch(j){Q(j)}return b}function M(a,b,c){"object"!=typeof b&&(b={}),"undefined"==typeof b.advanced&&(b.advanced=!1);try{var d;if("undefined"!=typeof CleanCSS)d=new CleanCSS(b);else if("function"==typeof require){var e=require("clean-css");d=new e(b)}return c?w(d.minify(v(a)).styles):d.minify(a).styles}catch(f){Q(f)}return a}function N(a){var b;do b=Math.random().toString(36).slice(2);while(~a.indexOf(b));return b}function O(a,c){function d(a,b){return G(a)||c.canCollapseWhitespace(a,b)}function i(a,b){return H(a)||c.canTrimWhitespace(a,b)}function j(){for(var a=r.length-1;a>0&&!/^<[^\/!]/.test(r[a]);)a--;r.length=Math.max(0,a)}function k(){for(var a=r.length-1;a>0&&!/^<\//.test(r[a]);)a--;r.length=a}c=c||{};var l=[];a=S(a),J(c);var m,o,p,q=[],r=[],s="",t="",u=[],v=[],w=[],E="",K="",O=c.lint,T=Date.now(),U=[],V=[];~a.indexOf("<!-- htmlmin:ignore -->")&&(o="<!--!"+N(a)+"-->",a=a.replace(/<!-- htmlmin:ignore -->([\s\S]*?)<!-- htmlmin:ignore -->/g,function(a,b){return U.push(b),o}));var W=(c.ignoreCustomFragments||[/<%[\s\S]*?%>/,/<\?[\s\S]*?\?>/]).map(function(a){return a.source});if(W.length){var X=new RegExp("\\s*(?:"+W.join("|")+")\\s*","g");a=a.replace(X,function(b){return p||(p=N(a)),V.push(b)," "+p+" "})}new R(a,{html5:"undefined"!=typeof c.html5?c.html5:!0,start:function(a,b,e,f){var g=a.toLowerCase();if("svg"===g){l.push(c);var h={};for(var n in c)h[n]=c[n];h.keepClosingSlash=!0,h.caseSensitive=!0,c=h}a=c.caseSensitive?a:g,t=a,m=a,s="",u=b;var o=c.removeOptionalTags;o&&(B(E,a)&&j(),E="",D(K,a)&&(k(),o=!C(K,a)),K=""),c.collapseWhitespace&&(i(a,b)||v.push(a),d(a,b)||w.push(a));var p="<"+a,q=f&&c.keepClosingSlash;r.push(p),O&&O.testElement(a);for(var x,y=[],z=!0,A=b.length;--A>=0;)O&&O.testAttribute(a,b[A].name.toLowerCase(),b[A].value),x=I(b[A],b,a,q,A,c,z),x&&(z=!1,y.unshift(x));y.length>0?(r.push(" "),r.push.apply(r,y)):o&&_(a)&&(E=a),r.push(r.pop()+(q?"/":"")+">")},end:function(a,b){var d=a.toLowerCase();if("svg"===d&&(c=l.pop()),a=c.caseSensitive?a:d,c.removeOptionalTags&&(!K||"dt"===K||"thead"===K||"p"===K&&ea(a)||k(),K=aa(a)?a:""),c.collapseWhitespace){if(v.length)a===v[v.length-1]&&v.pop();else{var e;r.length>1&&""===r[r.length-1]&&/\s+$/.test(r[r.length-2])?e=r.length-2:r.length>0&&/\s+$/.test(r[r.length-1])&&(e=r.length-1),e>0&&(r[e]=r[e].replace(/\s+$/,function(b){return f(b,"comment","/"+a,c)}))}w.length&&a===w[w.length-1]&&w.pop()}var g=!1;a===t&&(t="",g=""===s),c.removeEmptyElements&&g&&F(a,b)?(j(),E="",K=""):(q.push.apply(q,r),r=["</"+a+">"],m="/"+a,s="")},chars:function(a,d,e){if(d=""===d?"comment":d,e=""===e?"comment":e,c.collapseWhitespace){if(!v.length){if("comment"===d){var g=""===r[r.length-1];if(g&&(d=m),r.length>1&&(g||" "===s.charAt(s.length-1))){var h=r.length-2;r[h]=r[h].replace(/\s+$/,function(b){return a=b+a,""})}}a=d||e?f(a,d,e,c):S(a)}w.length||(a=d&&e||"html"===e?a:b(a))}("script"===t||"style"===t)&&(c.removeCommentsFromCDATA&&(a=A(a,t)),c.removeCDATASectionsFromCDATA&&(a=y(a)),c.processScripts&&(a=z(a,c,u))),c.minifyJS&&n(t,u)&&(a=L(a,c.minifyJS),";"===a.charAt(a.length-1)&&(a=a.slice(0,-1))),"style"===t&&c.minifyCSS&&(a=M(a,c.minifyCSS)),c.removeOptionalTags&&a&&(("html"===E||"body"===E&&!/^\s/.test(a))&&j(),E="",(ma(K)||na(K)&&!/^\s/.test(a))&&k(),K=""),m=/^\s*$/.test(a)?d:"comment",s+=a,O&&O.testChars(a),r.push(a)},comment:function(a,b){var d=b?"<!":"<!--",e=b?">":"-->";a=c.removeComments?g(a)?d+x(a)+e:h(a,c)?"<!--"+a+"-->":"":d+a+e,c.removeOptionalTags&&a&&(E="",K=""),r.push(a)},doctype:function(a){r.push(c.useShortDoctype?"<!DOCTYPE html>":b(a))},customAttrAssign:c.customAttrAssign,customAttrSurround:c.customAttrSurround}),c.removeOptionalTags&&(la(E)&&j(),K&&"dt"!==K&&"thead"!==K&&k()),q.push.apply(q,r);var Y=P(q,c);return p&&(Y=Y.replace(new RegExp("(\\s*)"+p+"(\\s*)","g"),function(a,b,d){var f=V.shift();return c.collapseWhitespace?e(b+f+d,{preserveLineBreaks:c.preserveLineBreaks,conservativeCollapse:!0},!0,!0):f})),o&&(Y=Y.replace(new RegExp(o,"g"),function(){return U.shift()})),Q("minified in: "+(Date.now()-T)+"ms"),Y}function P(a,b){var c,d=b.maxLineLength;if(d){for(var e,f=[],g="",h=0,i=a.length;i>h;h++)e=a[h],g.length+e.length<d?g+=e:(f.push(g.replace(/^\n/,"")),g=e);f.push(g),c=f.join("\n")}else c=a.join("");return S(c)}var Q,R;Q=a.console&&a.console.log?function(b){a.console.log(b)}:function(){},a.HTMLParser?R=a.HTMLParser:"function"==typeof require&&(R=require("./htmlparser").HTMLParser);var S=function(a){return"string"!=typeof a?a:a.replace(/^\s+/,"").replace(/\s+$/,"")};String.prototype.trim&&(S=function(a){return"string"!=typeof a?a:a.trim()});var T=d("a,abbr,acronym,b,bdi,bdo,big,button,cite,code,del,dfn,em,font,i,ins,kbd,mark,math,q,rt,rp,s,samp,small,span,strike,strong,sub,sup,svg,time,tt,u,var"),U=d("comment,img,input"),V=c(["text/javascript","text/ecmascript","text/jscript","application/javascript","application/x-javascript","application/ecmascript"]),W={draggable:["true","false"]},X="!function(){",Y="}();",Z={script:/^\s*(?:\/\/)?\s*<!--.*\n?/,style:/^\s*<!--\s*/},$={script:/\s*(?:\/\/)?\s*-->\s*$/,style:/\s*-->\s*$/},_=d("html,head,body,colgroup,tbody"),aa=d("html,head,body,li,dt,dd,p,rb,rt,rtc,rp,optgroup,option,colgroup,caption,thead,tbody,tfoot,tr,td,th"),ba=d("meta,link,script,style,template,noscript"),ca=d("dt,dd"),da=d("address,article,aside,blockquote,details,div,dl,fieldset,figcaption,figure,footer,form,h1,h2,h3,h4,h5,h6,header,hgroup,hr,main,menu,nav,ol,p,pre,section,table,ul"),ea=d("a,audio,del,ins,map,noscript,video"),fa=d("rb,rt,rtc,rp"),ga=d("rb,rtc,rp"),ha=d("option,optgroup"),ia=d("tbody,tfoot"),ja=d("thead,tbody,tfoot"),ka=d("td,th"),la=d("html,head,body"),ma=d("html,body"),na=d("head,colgroup,caption"),oa=new RegExp("^(?:class|id|style|title|lang|dir|on(?:focus|blur|change|click|dblclick|mouse(?:down|up|over|move|out)|key(?:press|down|up)))$");"undefined"!=typeof exports?exports.minify=O:a.minify=O}("undefined"==typeof exports?this:exports),function(a){"use strict";function b(a){return/^(?:big|small|hr|blink|marquee)$/.test(a)}function c(a){return/^(?:applet|basefont|center|dir|font|isindex|strike)$/.test(a)}function d(a){return/^on[a-z]+/.test(a)}function e(a){return"style"===a.toLowerCase()}function f(a,b){return"align"===b&&/^(?:caption|applet|iframe|img|imput|object|legend|table|hr|div|h[1-6]|p)$/.test(a)||"alink"===b&&"body"===a||"alt"===b&&"applet"===a||"archive"===b&&"applet"===a||"background"===b&&"body"===a||"bgcolor"===b&&/^(?:table|t[rdh]|body)$/.test(a)||"border"===b&&/^(?:img|object)$/.test(a)||"clear"===b&&"br"===a||"code"===b&&"applet"===a||"codebase"===b&&"applet"===a||"color"===b&&/^(?:base(?:font)?)$/.test(a)||"compact"===b&&/^(?:dir|[dou]l|menu)$/.test(a)||"face"===b&&/^base(?:font)?$/.test(a)||"height"===b&&/^(?:t[dh]|applet)$/.test(a)||"hspace"===b&&/^(?:applet|img|object)$/.test(a)||"language"===b&&"script"===a||"link"===b&&"body"===a||"name"===b&&"applet"===a||"noshade"===b&&"hr"===a||"nowrap"===b&&/^t[dh]$/.test(a)||"object"===b&&"applet"===a||"prompt"===b&&"isindex"===a||"size"===b&&/^(?:hr|font|basefont)$/.test(a)||"start"===b&&"ol"===a||"text"===b&&"body"===a||"type"===b&&/^(?:li|ol|ul)$/.test(a)||"value"===b&&"li"===a||"version"===b&&"html"===a||"vlink"===b&&"body"===a||"vspace"===b&&/^(?:applet|img|object)$/.test(a)||"width"===b&&/^(?:hr|td|th|applet|pre)$/.test(a)}function g(a,b){return"href"===a&&/^\s*javascript\s*:\s*void\s*(\s+0|\(\s*0\s*\))\s*$/i.test(b)}function h(){this.log=[],this._lastElement=null,this._isElementRepeated=!1}h.prototype.testElement=function(a){c(a)?this.log.push('Found <span class="deprecated-element">deprecated</span> <strong><code>&lt;'+a+"&gt;</code></strong> element"):b(a)?this.log.push('Found <span class="presentational-element">presentational</span> <strong><code>&lt;'+a+"&gt;</code></strong> element"):this.checkRepeatingElement(a)},h.prototype.checkRepeatingElement=function(a){"br"===a&&"br"===this._lastElement?this._isElementRepeated=!0:this._isElementRepeated&&(this._reportRepeatingElement(),this._isElementRepeated=!1),this._lastElement=a},h.prototype._reportRepeatingElement=function(){this.log.push("Found <code>&lt;br></code> sequence. Try replacing it with styling.")},h.prototype.testAttribute=function(a,b,c){d(b)?this.log.push('Found <span class="event-attribute">event attribute</span> (<strong>'+b+"</strong>) on <strong><code>&lt;"+a+"&gt;</code></strong> element."):f(a,b)?this.log.push('Found <span class="deprecated-attribute">deprecated</span> <strong>'+b+"</strong> attribute on <strong><code>&lt;"+a+"&gt;</code></strong> element."):e(b)?this.log.push('Found <span class="style-attribute">style attribute</span> on <strong><code>&lt;'+a+"&gt;</code></strong> element."):g(b,c)&&this.log.push('Found <span class="inaccessible-attribute">inaccessible attribute</span> (on <strong><code>&lt;'+a+"&gt;</code></strong> element).")},h.prototype.testChars=function(a){this._lastElement="",/(&nbsp;\s*){2,}/.test(a)&&this.log.push("Found repeating <strong><code>&amp;nbsp;</code></strong> sequence. Try replacing it with styling.")},h.prototype.test=function(a,b,c){this.testElement(a),this.testAttribute(a,b,c)},h.prototype.populate=function(a){if(this._isElementRepeated&&this._reportRepeatingElement(),this.log.length)if(a)a.innerHTML="<ol><li>"+this.log.join("<li>")+"</ol>";else{var b=" - "+this.log.join("\n - ").replace(/(<([^>]+)>)/gi,"").replace(/&lt;/g,"<").replace(/&gt;/g,">");console.log(b)}},a.HTMLLint=h}("undefined"==typeof exports?this:exports);
{
"name": "html-minifier",
"description": "HTML minifier with lint-like capabilities.",
"version": "1.1.1",
"version": "1.2.0",
"keywords": [

@@ -47,2 +47,3 @@ "html",

"devDependencies": {
"brotli": "1.1.x",
"chalk": "1.1.x",

@@ -52,9 +53,12 @@ "cli-table": "0.3.x",

"grunt-contrib-concat": "0.5.x",
"grunt-contrib-jshint": "0.11.x",
"grunt-contrib-qunit": "0.7.x",
"grunt-contrib-jshint": "1.0.x",
"grunt-contrib-qunit": "1.0.x",
"grunt-contrib-uglify": "0.11.x",
"grunt-exec": "0.4.x",
"grunt-jscs": "2.5.x",
"grunt-jscs": "2.7.x",
"load-grunt-tasks": "3.4.x",
"qunit": "0.7.x",
"lzma": "2.2.x",
"minimize": "1.8.x",
"progress": "1.1.x",
"qunit": "0.9.x",
"time-grunt": "1.3.x"

@@ -61,0 +65,0 @@ },

@@ -18,11 +18,15 @@ [![NPM version](https://img.shields.io/npm/v/html-minifier.svg)](https://www.npmjs.com/package/html-minifier)

| Site | Original size _(KB)_ | HTMLMinifier | minimize | Will Peavy | htmlcompressor.com |
| --------------------------------------------------------------------------- |:-----------:| ----------------:| ----------------:| ------------:| ----------------:|
| [HTMLMinifier page](https://github.com/kangax/html-minifier) | 48.8 | <b>37.3</b> | 41.8 | 43.3 | 41.9 |
| [ES6 table](http://kangax.github.io/es5-compat-table/es6/) | 117.9 | <b>79.9</b> | 94.1 | 92 | 91.9 |
| [MSN](http://msn.com) | 156.6 | <b>133</b> | 137.7 | 145 | 138.3 |
| [Stackoverflow](http://stackoverflow.com) | 200.4 | <b>159.5</b> | 165.1 | 168.3 | 163.3 |
| [Amazon](http://amazon.com) | 245.9 | <b>206.3</b> | 234.1 | 225 | 218.5 |
| [Wikipedia](http://en.wikipedia.org/wiki/President_of_the_United_States) | 401.4 | <b>380.6</b> | 386.6 | 396.3 | n/a |
| [Eloquent Javascript](http://eloquentjavascript.net/print.html) | 869.5 | <b>830</b> | 838 | 872 | n/a |
| Site | Original size _(KB)_ | HTMLMinifier | minimize | Will Peavy | htmlcompressor.com |
| --------------------------------------------------------------------------- |:--------------------:| ------------:| --------:| ----------:| ------------------:|
| [HTMLMinifier page](https://github.com/kangax/html-minifier) | 49 | <b>37</b> | 42 | 44 | 43 |
| [NBC](http://www.nbc.com) | 91 | <b>74</b> | 84 | 86 | 85 |
| [ES6 table](http://kangax.github.io/es5-compat-table/es6/) | 118 | <b>80</b> | 93 | 95 | 94 |
| [New York Times](http://www.nytimes.com/) | 131 | <b>101</b> | 122 | 125 | 120 |
| [Google](http://www.google.com/) | 133 | <b>128</b> | 132 | 135 | 131 |
| [MSN](http://msn.com) | 157 | <b>130</b> | 138 | 145 | 138 |
| [Stackoverflow](http://stackoverflow.com) | 200 | <b>159</b> | 165 | 174 | 166 |
| [Amazon](http://amazon.com) | 246 | <b>204</b> | 234 | 230 | 219 |
| [Wikipedia](http://en.wikipedia.org/wiki/President_of_the_United_States) | 401 | <b>367</b> | 388 | 400 | n/a |
| [Eloquent Javascript](http://eloquentjavascript.net/print.html) | 870 | <b>826</b> | 840 | 864 | n/a |
| [ES6 draft](https://people.mozilla.org/~jorendorff/es6-draft.html) | 3678 | <b>2991</b> | 3079 | 3204 | n/a |

@@ -40,4 +44,6 @@

| `conservativeCollapse` | Always collapse to 1 space (never remove it entirely). Must be used in conjunction with `collapseWhitespace=true` | `false` |
| `collapseInlineTagWhitespace` | Don't leave any spaces between `display:inline;` elements when collapsing. Must be used in conjunction with `collapseWhitespace=true` | `false` |
| `preserveLineBreaks` | Always collapse to 1 line break (never remove it entirely) when whitespace between tags include a line break. Must be used in conjunction with `collapseWhitespace=true` | `false` |
| `collapseBooleanAttributes` | [Omit attribute values from boolean attributes](http://perfectionkills.com/experimenting-with-html-minifier/#collapse_boolean_attributes) | `false` |
| `removeTagWhitespace` | Remove space between attributes whenever possible. | `false` |
| `removeAttributeQuotes` | [Remove quotes around attributes when possible.](http://perfectionkills.com/experimenting-with-html-minifier/#remove_attribute_quotes) | `false` |

@@ -55,13 +61,14 @@ | `removeRedundantAttributes` | [Remove attributes when value matches default.](http://perfectionkills.com/experimenting-with-html-minifier/#remove_redundant_attributes) | `false` |

| `caseSensitive` | Treat attributes in case sensitive manner (useful for custom HTML tags.) | `false` |
| `minifyJS` | Minify Javascript in script elements and on* attributes (uses [UglifyJS](https://github.com/mishoo/UglifyJS2)) | `false` (could be `true`, `false`, `Object` (options)) |
| `minifyJS` | Minify Javascript in script elements and event attributes (uses [UglifyJS](https://github.com/mishoo/UglifyJS2)) | `false` (could be `true`, `false`, `Object` (options)) |
| `minifyCSS` | Minify CSS in style elements and style attributes (uses [clean-css](https://github.com/GoalSmashers/clean-css)) | `false` (could be `true`, `false`, `Object` (options)) |
| `minifyURLs` | Minify URLs in various attributes (uses [relateurl](https://github.com/stevenvachon/relateurl)) | `false` (could be `Object` (options)) |
| `ignoreCustomComments` | Array of regex'es that allow to ignore certain comments, when matched | `[ ]` |
| `ignoreCustomFragments` | Array of regex'es that allow to ignore certain fragments, when matched (e.g. `<?php ... ?>`, `{{ ... }}`, etc.) | `[ ]` |
| `ignoreCustomFragments` | Array of regex'es that allow to ignore certain fragments, when matched (e.g. `<?php ... ?>`, `{{ ... }}`, etc.) | `[ /<%[\s\S]*?%>/, /<\?[\s\S]*?\?>/ ]` |
| `processScripts` | Array of strings corresponding to types of script elements to process through minifier (e.g. `text/ng-template`, `text/x-handlebars-template`, etc.) | `[ ]` |
| `maxLineLength` | Specify a maximum line length. Compressed output will be split by newlines at valid HTML split-points. |
| `customEventAttributes` | Arrays of regex'es that allow to support custom event attributes for `minifyJS` (e.g. `ng-click`) | `[ /^on[a-z]{3,}$/ ]` |
| `customAttrAssign` | Arrays of regex'es that allow to support custom attribute assign expressions (e.g. `'<div flex?="{{mode != cover}}"></div>'`) | `[ ]` |
| `customAttrSurround` | Arrays of regex'es that allow to support custom attribute surround expressions (e.g. `<input {{#if value}}checked="checked"{{/if}}>`) | `[ ]` |
| `customAttrCollapse` | Regex that specifies custom attribute to strip newlines from (e.g. `/ng\-class/`) | |
| `quoteCharacter` | Type of quote to use for attribute values (' or ") | " |
| `quoteCharacter` | Type of quote to use for attribute values (' or ") | |

@@ -68,0 +75,0 @@ ## Special cases

@@ -39,47 +39,61 @@ /* global CleanCSS */

function collapseWhitespace(str) {
function collapseWhitespaceAll(str) {
return str ? str.replace(/[\t\n\r ]+/g, ' ') : str;
}
function collapseWhitespaceSmart(str, prevTag, nextTag, options) {
function createMap(values) {
var map = {};
values.forEach(function(value) {
map[value] = 1;
});
return function(value) {
return map[value] === 1;
};
}
// array of non-empty element tags that will maintain a single space outside of them
var tags = [
'a', 'abbr', 'acronym', 'b', 'bdi', 'bdo', 'big', 'button', 'cite',
'code', 'del', 'dfn', 'em', 'font', 'i', 'ins', 'kbd', 'mark', 'q',
'rt', 'rp', 's', 'samp', 'small', 'span', 'strike', 'strong',
'sub', 'sup', 'svg', 'time', 'tt', 'u', 'var'
],
lineBreakBefore = /^[\t ]*[\n\r]+[\t\n\r ]*/,
lineBreakAfter = /[\t\n\r ]*[\n\r]+[\t ]*$/,
preserveBefore = lineBreakBefore.test(str) ? '\n' : ' ',
preserveAfter = lineBreakAfter.test(str) ? '\n' : ' ',
lineBreakStamp = 'htmlmincollapsedlinebreak';
function createMapFromString(values) {
return createMap(values.split(/,/));
}
if (prevTag && prevTag !== 'img' && prevTag !== 'input' && (prevTag.substr(0, 1) !== '/'
|| (prevTag.substr(0, 1) === '/' && (options.collapseInlineTagWhitespace || tags.indexOf(prevTag.substr(1)) === -1)))) {
str = str.replace(/^\s+/, options.conservativeCollapse ? ' ' : options.preserveLineBreaks ? preserveBefore : '');
function collapseWhitespace(str, options, trimLeft, trimRight, collapseAll) {
var lineBreakBefore = '', lineBreakAfter = '';
if (options.preserveLineBreaks) {
str = str.replace(/^[\t ]*[\n\r]+[\t\n\r ]*/, function() {
lineBreakBefore = '\n';
return '';
}).replace(/[\t\n\r ]*[\n\r]+[\t ]*$/, function() {
lineBreakAfter = '\n';
return '';
});
}
if (nextTag && nextTag !== 'img' && nextTag !== 'input' && (nextTag.substr(0, 1) === '/'
|| (nextTag.substr(0, 1) !== '/' && (options.collapseInlineTagWhitespace || tags.indexOf(nextTag) === -1)))) {
str = str.replace(/\s+$/, options.conservativeCollapse ? ' ' : options.preserveLineBreaks ? preserveAfter : '');
if (trimLeft) {
str = str.replace(/^\s+/, !lineBreakBefore && options.conservativeCollapse ? ' ' : '');
}
if (prevTag && nextTag) {
if (trimRight) {
str = str.replace(/\s+$/, !lineBreakAfter && options.conservativeCollapse ? ' ' : '');
}
if (options.preserveLineBreaks) {
str = str
.replace(lineBreakBefore, lineBreakStamp)
.replace(lineBreakAfter, lineBreakStamp);
}
if (collapseAll) {
// strip non space whitespace then compress spaces to one
return str
.replace(/[\t\n\r]+/g, ' ').replace(/[ ]+/g, ' ')
.replace(new RegExp(lineBreakStamp, 'g'), '\n');
str = collapseWhitespaceAll(str);
}
return str;
return lineBreakBefore + str + lineBreakAfter;
}
// array of non-empty element tags that will maintain a single space outside of them
var inlineTags = createMapFromString('a,abbr,acronym,b,bdi,bdo,big,button,cite,code,del,dfn,em,font,i,ins,kbd,mark,math,q,rt,rp,s,samp,small,span,strike,strong,sub,sup,svg,time,tt,u,var');
var selfClosingInlineTags = createMapFromString('comment,img,input');
function collapseWhitespaceSmart(str, prevTag, nextTag, options) {
var trimLeft = prevTag && !selfClosingInlineTags(prevTag) &&
(options.collapseInlineTagWhitespace || prevTag.charAt(0) !== '/' || !inlineTags(prevTag.substr(1)));
var trimRight = nextTag && !selfClosingInlineTags(nextTag) &&
(options.collapseInlineTagWhitespace || nextTag.charAt(0) === '/' || !inlineTags(nextTag));
return collapseWhitespace(str, options, trimLeft, trimRight, prevTag && nextTag);
}
function isConditionalComment(text) {

@@ -90,3 +104,3 @@ return ((/\[if[^\]]+\]/).test(text) || (/\s*((?:<!)?\[endif\])$/).test(text));

function isIgnoredComment(text, options) {
if ((/^!/).test(text) || /\s*htmlmin:temp/.test(text)) {
if (/^!/.test(text)) {
return true;

@@ -106,11 +120,20 @@ }

function isEventAttribute(attrName) {
return (/^on[a-z]+/).test(attrName);
function isEventAttribute(attrName, options) {
var patterns = options.customEventAttributes;
if (patterns) {
for (var i = patterns.length; i--;) {
if (patterns[i].test(attrName)) {
return true;
}
}
return false;
}
else {
return (/^on[a-z]{3,}$/).test(attrName);
}
}
function canRemoveAttributeQuotes(value, isLast) {
function canRemoveAttributeQuotes(value) {
// http://mathiasbynens.be/notes/unquoted-attribute-values
return (/^[^\x20\t\n\f\r"'`=<>]+$/).test(value) &&
// make sure trailing slash is not interpreted as HTML self-closing tag
!(isLast && (/\/$/).test(value));
return (/^[^\x20\t\n\f\r"'`=<>]+$/).test(value);
}

@@ -167,10 +190,10 @@

// https://developer.mozilla.org/en/docs/Web/HTML/Element/script#attr-type
var executableScriptsMimetypes = {
'text/javascript': 1,
'text/ecmascript': 1,
'text/jscript': 1,
'application/javascript': 1,
'application/x-javascript': 1,
'application/ecmascript': 1
};
var executableScriptsMimetypes = createMap([
'text/javascript',
'text/ecmascript',
'text/jscript',
'application/javascript',
'application/x-javascript',
'application/ecmascript'
]);

@@ -184,4 +207,4 @@ function isExecutableScript(tag, attrs) {

if (attrName === 'type') {
return attrs[i].value === '' ||
executableScriptsMimetypes[attrs[i].value] === 1;
var attrValue = trimWhitespace(attrs[i].value).split(/;/, 2)[0].toLowerCase();
return attrValue === '' || executableScriptsMimetypes(attrValue);
}

@@ -205,3 +228,3 @@ }

function isBooleanAttribute(attrName, attrValue) {
var isSimpleBoolean = (/^(?:allowfullscreen|async|autofocus|autoplay|checked|compact|controls|declare|default|defaultchecked|defaultmuted|defaultselected|defer|disabled|enabled|formnovalidate|hidden|indeterminate|inert|ismap|itemscope|loop|multiple|muted|nohref|noresize|noshade|novalidate|nowrap|open|pauseonexit|readonly|required|reversed|scoped|seamless|selected|sortable|spellcheck|truespeed|typemustmatch|visible)$/i).test(attrName);
var isSimpleBoolean = (/^(?:allowfullscreen|async|autofocus|autoplay|checked|compact|controls|declare|default|defaultchecked|defaultmuted|defaultselected|defer|disabled|enabled|formnovalidate|hidden|indeterminate|inert|ismap|itemscope|loop|multiple|muted|nohref|noresize|noshade|novalidate|nowrap|open|pauseonexit|readonly|required|reversed|scoped|seamless|selected|sortable|truespeed|typemustmatch|visible)$/i).test(attrName);
if (isSimpleBoolean) {

@@ -247,9 +270,22 @@ return true;

function isCanonicalURL(tag, attrs) {
if (tag !== 'link') {
return false;
}
for (var i = 0, len = attrs.length; i < len; i++) {
if (attrs[i].name === 'rel' && attrs[i].value === 'canonical') {
return true;
}
}
}
var fnPrefix = '!function(){';
var fnSuffix = '}();';
function cleanAttributeValue(tag, attrName, attrValue, options, attrs) {
if (attrValue && isEventAttribute(attrName)) {
if (attrValue && isEventAttribute(attrName, options)) {
attrValue = trimWhitespace(attrValue).replace(/^javascript:\s*/i, '').replace(/\s*;$/, '');
if (options.minifyJS) {
var wrappedCode = '(function(){' + attrValue + '})()';
var minified = minifyJS(wrappedCode, options.minifyJS);
return minified.slice(12, minified.length - 4).replace(/"/g, '&quot;');
var minified = minifyJS(fnPrefix + attrValue + fnSuffix, options.minifyJS);
return minified.slice(fnPrefix.length, -fnSuffix.length);
}

@@ -259,7 +295,7 @@ return attrValue;

else if (attrName === 'class') {
return collapseWhitespace(trimWhitespace(attrValue));
return collapseWhitespaceAll(trimWhitespace(attrValue));
}
else if (isUriTypeAttribute(attrName, tag)) {
attrValue = trimWhitespace(attrValue);
if (options.minifyURLs) {
if (options.minifyURLs && !isCanonicalURL(tag, attrs)) {
return minifyURLs(attrValue, options.minifyURLs);

@@ -283,3 +319,8 @@ }

else if (isMetaViewport(tag, attrs) && attrName === 'content') {
attrValue = attrValue.replace(/1\.0/g, '1').replace(/\s+/g, '');
attrValue = attrValue.replace(/\s+/g, '').replace(/[0-9]+\.[0-9]+/g, function(numString) {
// "0.90000" -> "0.9"
// "1.0" -> "1"
// "1.0001" -> "1.0001" (unchanged)
return (+numString).toString();
});
}

@@ -356,6 +397,84 @@ else if (attrValue && options.customAttrCollapse && options.customAttrCollapse.test(attrName)) {

function isOptionalTag(tag) {
return (/^(?:html|t?body|t?head|tfoot|tr|td|th|dt|dd|option|colgroup|source|track)$/).test(tag);
// Tag omission rules from https://html.spec.whatwg.org/multipage/syntax.html#optional-tags
// with the following deviations:
// - retain <body> if followed by <noscript>
// - </rb>, </rt>, </rtc>, </rp> & </tfoot> follow http://www.w3.org/TR/html5/syntax.html#optional-tags
var optionalStartTags = createMapFromString('html,head,body,colgroup,tbody');
var optionalEndTags = createMapFromString('html,head,body,li,dt,dd,p,rb,rt,rtc,rp,optgroup,option,colgroup,caption,thead,tbody,tfoot,tr,td,th');
var headerTags = createMapFromString('meta,link,script,style,template,noscript');
var descriptionTags = createMapFromString('dt,dd');
var pBlockTags = createMapFromString('address,article,aside,blockquote,details,div,dl,fieldset,figcaption,figure,footer,form,h1,h2,h3,h4,h5,h6,header,hgroup,hr,main,menu,nav,ol,p,pre,section,table,ul');
var pInlineTags = createMapFromString('a,audio,del,ins,map,noscript,video');
var rubyTags = createMapFromString('rb,rt,rtc,rp');
var rtcTag = createMapFromString('rb,rtc,rp');
var optionTag = createMapFromString('option,optgroup');
var tableContentTags = createMapFromString('tbody,tfoot');
var tableSectionTags = createMapFromString('thead,tbody,tfoot');
var cellTags = createMapFromString('td,th');
var topLevelTags = createMapFromString('html,head,body');
var compactTags = createMapFromString('html,body');
var looseTags = createMapFromString('head,colgroup,caption');
function canRemoveParentTag(optionalStartTag, tag) {
switch (optionalStartTag) {
case 'html':
case 'head':
return true;
case 'body':
return !headerTags(tag);
case 'colgroup':
return tag === 'col';
case 'tbody':
return tag === 'tr';
}
return false;
}
function isStartTagMandatory(optionalEndTag, tag) {
switch (tag) {
case 'colgroup':
return optionalEndTag === 'colgroup';
case 'tbody':
return tableSectionTags(optionalEndTag);
}
return false;
}
function canRemovePrecedingTag(optionalEndTag, tag) {
switch (optionalEndTag) {
case 'html':
case 'head':
case 'body':
case 'colgroup':
case 'caption':
return true;
case 'li':
case 'optgroup':
case 'tr':
return tag === optionalEndTag;
case 'dt':
case 'dd':
return descriptionTags(tag);
case 'p':
return pBlockTags(tag);
case 'rb':
case 'rt':
case 'rp':
return rubyTags(tag);
case 'rtc':
return rtcTag(tag);
case 'option':
return optionTag(tag);
case 'thead':
case 'tbody':
return tableContentTags(tag);
case 'tfoot':
return tag === 'tbody';
case 'td':
case 'th':
return cellTags(tag);
}
return false;
}
var reEmptyAttribute = new RegExp(

@@ -399,10 +518,9 @@ '^(?:class|id|style|title|lang|dir|on(?:focus|blur|change|click|dblclick|mouse(' +

function normalizeAttribute(attr, attrs, tag, unarySlash, index, options, isLast) {
function normalizeAttribute(attr, attrs, tag, hasUnarySlash, index, options, isLast) {
var attrName = options.caseSensitive ? attr.name : attr.name.toLowerCase(),
attrValue = options.preventAttributesEscaping ? attr.value : attr.escaped,
attrQuote = options.preventAttributesEscaping ? attr.quote : (options.quoteCharacter === '\'' ? '\'' : '"'),
attrValue = attr.value,
attrQuote = attr.quote,
attrFragment,
emittedAttrValue,
isTerminalOfUnarySlash = unarySlash && index === attrs.length - 1;
emittedAttrValue;

@@ -422,13 +540,36 @@ if ((options.removeRedundantAttributes &&

if (options.removeEmptyAttributes &&
canDeleteEmptyAttribute(tag, attrName, attrValue)) {
return '';
}
if (attrValue !== undefined && !options.removeAttributeQuotes ||
!canRemoveAttributeQuotes(attrValue, isLast) || isTerminalOfUnarySlash) {
!canRemoveAttributeQuotes(attrValue)) {
if (!options.preventAttributesEscaping) {
if (options.quoteCharacter !== undefined) {
attrQuote = options.quoteCharacter === '\'' ? '\'' : '"';
}
else {
var apos = (attrValue.match(/'/g) || []).length;
var quot = (attrValue.match(/"/g) || []).length;
attrQuote = apos < quot ? '\'' : '"';
}
if (attrQuote === '"') {
attrValue = attrValue.replace(/"/g, '&#34;');
}
else {
attrValue = attrValue.replace(/'/g, '&#39;');
}
}
emittedAttrValue = attrQuote + attrValue + attrQuote;
if (!isLast && !options.removeTagWhitespace) {
emittedAttrValue += ' ';
}
}
else {
// make sure trailing slash is not interpreted as HTML self-closing tag
else if (isLast && !hasUnarySlash && !/\/$/.test(attrValue)) {
emittedAttrValue = attrValue;
}
if (options.removeEmptyAttributes &&
canDeleteEmptyAttribute(tag, attrName, attrValue)) {
return '';
else {
emittedAttrValue = attrValue + ' ';
}

@@ -439,2 +580,5 @@

attrFragment = attrName;
if (!isLast) {
attrFragment += ' ';
}
}

@@ -445,3 +589,3 @@ else {

return (' ' + attr.customOpen + attrFragment + attr.customClose);
return attr.customOpen + attrFragment + attr.customClose;
}

@@ -578,2 +722,10 @@

function uniqueId(value) {
var id;
do {
id = Math.random().toString(36).slice(2);
} while (~value.indexOf(id));
return id;
}
function minify(value, options) {

@@ -589,2 +741,3 @@

buffer = [ ],
charsPrevTag,
currentChars = '',

@@ -595,34 +748,41 @@ currentTag = '',

stackNoCollapseWhitespace = [],
optionalStartTag = '',
optionalEndTag = '',
lint = options.lint,
t = new Date(),
t = Date.now(),
ignoredMarkupChunks = [ ],
ignoredCustomMarkupChunks = [ ],
reIgnore = /<!-- htmlmin:ignore -->([\s\S]*?)<!-- htmlmin:ignore -->/g,
uidAttr = ' htmlmin' + (Math.random() + '').slice(2) + ' ',
reCustomIgnore,
customFragments;
uidIgnore,
uidAttr;
if (options.ignoreCustomFragments) {
customFragments = options.ignoreCustomFragments.map(function(re) {
return re.source;
if (~value.indexOf('<!-- htmlmin:ignore -->')) {
uidIgnore = '<!--!' + uniqueId(value) + '-->';
// temporarily replace ignored chunks with comments,
// so that we don't have to worry what's there.
// for all we care there might be
// completely-horribly-broken-alien-non-html-emoj-cthulhu-filled content
value = value.replace(/<!-- htmlmin:ignore -->([\s\S]*?)<!-- htmlmin:ignore -->/g, function(match, group1) {
ignoredMarkupChunks.push(group1);
return uidIgnore;
});
reCustomIgnore = new RegExp('(?:' + customFragments.join('|') + ')', 'g');
}
var customFragments = (options.ignoreCustomFragments || [
/<%[\s\S]*?%>/,
/<\?[\s\S]*?\?>/
]).map(function(re) {
return re.source;
});
if (customFragments.length) {
var reCustomIgnore = new RegExp('\\s*(?:' + customFragments.join('|') + ')\\s*', 'g');
// temporarily replace custom ignored fragments with unique attributes
value = value.replace(reCustomIgnore, function(match) {
if (!uidAttr) {
uidAttr = uniqueId(value);
}
ignoredCustomMarkupChunks.push(match);
return uidAttr;
return ' ' + uidAttr + ' ';
});
}
// temporarily replace ignored chunks with comments,
// so that we don't have to worry what's there.
// for all we care there might be
// completely-horribly-broken-alien-non-html-emoj-cthulhu-filled content
value = value.replace(reIgnore, function(match, group1) {
ignoredMarkupChunks.push(group1);
return '<!-- htmlmin:temp -->';
});
function _canCollapseWhitespace(tag, attrs) {

@@ -636,2 +796,18 @@ return canCollapseWhitespace(tag) || options.canCollapseWhitespace(tag, attrs);

function removeStartTag() {
var index = buffer.length - 1;
while (index > 0 && !/^<[^/!]/.test(buffer[index])) {
index--;
}
buffer.length = Math.max(0, index);
}
function removeEndTag() {
var index = buffer.length - 1;
while (index > 0 && !/^<\//.test(buffer[index])) {
index--;
}
buffer.length = index;
}
new HTMLParser(value, {

@@ -641,3 +817,2 @@ html5: typeof options.html5 !== 'undefined' ? options.html5 : true,

start: function(tag, attrs, unary, unarySlash) {
var lowerTag = tag.toLowerCase();

@@ -659,5 +834,27 @@

currentTag = tag;
charsPrevTag = tag;
currentChars = '';
currentAttrs = attrs;
var optional = options.removeOptionalTags;
if (optional) {
// <html> may be omitted if first thing inside is not comment
// <head> may be omitted if first thing inside is an element
// <body> may be omitted if first thing inside is not space, comment, <meta>, <link>, <script>, <style> or <template>
// <colgroup> may be omitted if first thing inside is <col>
// <tbody> may be omitted if first thing inside is <tr>
if (canRemoveParentTag(optionalStartTag, tag)) {
removeStartTag();
}
optionalStartTag = '';
// end-tag-followed-by-start-tag omission rules
if (canRemovePrecedingTag(optionalEndTag, tag)) {
removeEndTag();
// <colgroup> cannot be omitted if preceding </colgroup> is omitted
// <tbody> cannot be omitted if preceding </tbody>, </thead> or </tfoot> is omitted
optional = !isStartTagMandatory(optionalEndTag, tag);
}
optionalEndTag = '';
}
// set whitespace flags for nested tags (eg. <code> within a <pre>)

@@ -674,6 +871,3 @@ if (options.collapseWhitespace) {

var openTag = '<' + tag;
var closeTag = ((unarySlash && options.keepClosingSlash) ? '/' : '') + '>';
if (attrs.length === 0) {
openTag += closeTag;
}
var hasUnarySlash = unarySlash && options.keepClosingSlash;

@@ -686,17 +880,26 @@ buffer.push(openTag);

var token, isLast;
for (var i = 0, len = attrs.length; i < len; i++) {
isLast = i === len - 1;
var parts = [ ];
var token, isLast = true;
for (var i = attrs.length; --i >= 0; ) {
if (lint) {
lint.testAttribute(tag, attrs[i].name.toLowerCase(), attrs[i].escaped);
lint.testAttribute(tag, attrs[i].name.toLowerCase(), attrs[i].value);
}
token = normalizeAttribute(attrs[i], attrs, tag, unarySlash, i, options, isLast);
if (isLast) {
token += closeTag;
token = normalizeAttribute(attrs[i], attrs, tag, hasUnarySlash, i, options, isLast);
if (token) {
isLast = false;
parts.unshift(token);
}
buffer.push(token);
}
if (parts.length > 0) {
buffer.push(' ');
buffer.push.apply(buffer, parts);
}
// start tag must never be omitted if it has any attributes
else if (optional && optionalStartTags(tag)) {
optionalStartTag = tag;
}
buffer.push(buffer.pop() + (hasUnarySlash ? '/' : '') + '>');
},
end: function(tag, attrs) {
var lowerTag = tag.toLowerCase();

@@ -707,8 +910,36 @@ if (lowerTag === 'svg') {

tag = options.caseSensitive ? tag : lowerTag;
if (options.removeOptionalTags) {
// </html> or </body> may be omitted if not followed by comment
// </head> may be omitted if not followed by space or comment
// </p> may be omitted if no more content in non-</a> parent
// except for </dt> or </thead>, end tags may be omitted if no more content in parent element
if (optionalEndTag && optionalEndTag !== 'dt' && optionalEndTag !== 'thead' && (optionalEndTag !== 'p' || !pInlineTags(tag))) {
removeEndTag();
}
optionalEndTag = optionalEndTags(tag) ? tag : '';
}
// check if current tag is in a whitespace stack
if (options.collapseWhitespace) {
if (stackNoTrimWhitespace.length &&
tag === stackNoTrimWhitespace[stackNoTrimWhitespace.length - 1]) {
stackNoTrimWhitespace.pop();
if (stackNoTrimWhitespace.length) {
if (tag === stackNoTrimWhitespace[stackNoTrimWhitespace.length - 1]) {
stackNoTrimWhitespace.pop();
}
}
else {
var charsIndex;
if (buffer.length > 1 && buffer[buffer.length - 1] === '' && /\s+$/.test(buffer[buffer.length - 2])) {
charsIndex = buffer.length - 2;
}
else if (buffer.length > 0 && /\s+$/.test(buffer[buffer.length - 1])) {
charsIndex = buffer.length - 1;
}
if (charsIndex > 0) {
buffer[charsIndex] = buffer[charsIndex].replace(/\s+$/, function(text) {
return collapseWhitespaceSmart(text, 'comment', '/' + tag, options);
});
}
}
if (stackNoCollapseWhitespace.length &&

@@ -720,25 +951,20 @@ tag === stackNoCollapseWhitespace[stackNoCollapseWhitespace.length - 1]) {

var isElementEmpty = currentChars === '' && tag === currentTag;
if ((options.removeEmptyElements && isElementEmpty && canRemoveElement(tag, attrs))) {
// remove last "element" from buffer, return
for (var i = buffer.length - 1; i >= 0; i--) {
if (/^<[^\/!]/.test(buffer[i])) {
buffer.splice(i);
break;
}
}
return;
var isElementEmpty = false;
if (tag === currentTag) {
currentTag = '';
isElementEmpty = currentChars === '';
}
else if (options.removeOptionalTags && isOptionalTag(tag)) {
// noop, leave start tag in buffer
return;
if (options.removeEmptyElements && isElementEmpty && canRemoveElement(tag, attrs)) {
// remove last "element" from buffer
removeStartTag();
optionalStartTag = '';
optionalEndTag = '';
}
else {
// push end tag to buffer
buffer.push('</' + (options.caseSensitive ? tag : lowerTag) + '>');
// push out everything but the end tag
results.push.apply(results, buffer);
buffer = ['</' + tag + '>'];
charsPrevTag = '/' + tag;
currentChars = '';
}
// flush buffer
buffer.length = 0;
currentChars = '';
},

@@ -748,3 +974,23 @@ chars: function(text, prevTag, nextTag) {

nextTag = nextTag === '' ? 'comment' : nextTag;
if (options.collapseWhitespace) {
if (!stackNoTrimWhitespace.length) {
if (prevTag === 'comment') {
var removed = buffer[buffer.length - 1] === '';
if (removed) {
prevTag = charsPrevTag;
}
if (buffer.length > 1 && (removed || currentChars.charAt(currentChars.length - 1) === ' ')) {
var charsIndex = buffer.length - 2;
buffer[charsIndex] = buffer[charsIndex].replace(/\s+$/, function(trailingSpaces) {
text = trailingSpaces + text;
return '';
});
}
}
text = prevTag || nextTag ? collapseWhitespaceSmart(text, prevTag, nextTag, options) : trimWhitespace(text);
}
if (!stackNoCollapseWhitespace.length) {
text = prevTag && nextTag || nextTag === 'html' ? text : collapseWhitespaceAll(text);
}
}
if (currentTag === 'script' || currentTag === 'style') {

@@ -763,2 +1009,5 @@ if (options.removeCommentsFromCDATA) {

text = minifyJS(text, options.minifyJS);
if (text.charAt(text.length - 1) === ';') {
text = text.slice(0, -1);
}
}

@@ -768,13 +1017,18 @@ if (currentTag === 'style' && options.minifyCSS) {

}
if (options.collapseWhitespace) {
if (!stackNoTrimWhitespace.length) {
text = ((prevTag && prevTag !== 'comment') || (nextTag && nextTag !== 'comment')) ?
collapseWhitespaceSmart(text, prevTag, nextTag, options)
: trimWhitespace(text);
if (options.removeOptionalTags && text) {
// <html> may be omitted if first thing inside is not comment
// <body> may be omitted if first thing inside is not space, comment, <meta>, <link>, <script>, <style> or <template>
if (optionalStartTag === 'html' || optionalStartTag === 'body' && !/^\s/.test(text)) {
removeStartTag();
}
if (!stackNoCollapseWhitespace.length) {
text = !(prevTag && nextTag || nextTag === 'html') ? collapseWhitespace(text) : text;
optionalStartTag = '';
// </html> or </body> may be omitted if not followed by comment
// </head>, </colgroup> or </caption> may be omitted if not followed by space or comment
if (compactTags(optionalEndTag) || looseTags(optionalEndTag) && !/^\s/.test(text)) {
removeEndTag();
}
optionalEndTag = '';
}
currentChars = text;
charsPrevTag = /^\s*$/.test(text) ? prevTag : 'comment';
currentChars += text;
if (lint) {

@@ -786,6 +1040,4 @@ lint.testChars(text);

comment: function(text, nonStandard) {
var prefix = nonStandard ? '<!' : '<!--';
var suffix = nonStandard ? '>' : '-->';
if (options.removeComments) {

@@ -805,6 +1057,11 @@ if (isConditionalComment(text)) {

}
if (options.removeOptionalTags && text) {
// preceding comments suppress tag omissions
optionalStartTag = '';
optionalEndTag = '';
}
buffer.push(text);
},
doctype: function(doctype) {
buffer.push(options.useShortDoctype ? '<!DOCTYPE html>' : collapseWhitespace(doctype));
buffer.push(options.useShortDoctype ? '<!DOCTYPE html>' : collapseWhitespaceAll(doctype));
},

@@ -815,15 +1072,33 @@ customAttrAssign: options.customAttrAssign,

if (options.removeOptionalTags) {
// <html> may be omitted if first thing inside is not comment
// <head> or <body> may be omitted if empty
if (topLevelTags(optionalStartTag)) {
removeStartTag();
}
// except for </dt> or </thead>, end tags may be omitted if no more content in parent element
if (optionalEndTag && optionalEndTag !== 'dt' && optionalEndTag !== 'thead') {
removeEndTag();
}
}
results.push.apply(results, buffer);
var str = joinResultSegments(results, options);
var customIgnoreRe = new RegExp('\\s*' + trimWhitespace(uidAttr) + '\\s*', 'g');
if (uidAttr) {
str = str.replace(new RegExp('(\\s*)' + uidAttr + '(\\s*)', 'g'), function(match, prefix, suffix) {
var chunk = ignoredCustomMarkupChunks.shift();
return options.collapseWhitespace ? collapseWhitespace(prefix + chunk + suffix, {
preserveLineBreaks: options.preserveLineBreaks,
conservativeCollapse: true
}, true, true) : chunk;
});
}
if (uidIgnore) {
str = str.replace(new RegExp(uidIgnore, 'g'), function() {
return ignoredMarkupChunks.shift();
});
}
str = str.replace(customIgnoreRe, function() {
return ignoredCustomMarkupChunks.shift();
});
str = str.replace(/<!-- htmlmin:temp -->/g, function() {
return ignoredMarkupChunks.shift();
});
log('minified in: ' + (new Date() - t) + 'ms');
log('minified in: ' + (Date.now() - t) + 'ms');
return str;

@@ -857,3 +1132,3 @@ }

return str;
return trimWhitespace(str);
}

@@ -860,0 +1135,0 @@

@@ -54,9 +54,6 @@ /*!

// Empty Elements - HTML 4.01
var empty = makeMap('area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed,wbr');
// Empty Elements
var empty = makeMap('area,base,basefont,br,col,embed,frame,hr,img,input,isindex,keygen,link,meta,param,source,track,wbr');
// Block Elements - HTML 4.01
// var block = makeMap('address,applet,blockquote,button,center,dd,del,dir,div,dl,dt,fieldset,form,frameset,hr,iframe,ins,isindex,li,map,menu,noframes,noscript,object,ol,p,pre,script,table,tbody,td,tfoot,th,thead,tr,ul');
// Inline Elements - HTML 4.01
// Inline Elements
var inline = makeMap('a,abbr,acronym,applet,b,basefont,bdo,big,br,button,cite,code,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,noscript,object,q,s,samp,script,select,small,span,strike,strong,sub,sup,svg,textarea,tt,u,var');

@@ -95,3 +92,5 @@

+ handler.customAttrSurround[i][0].source
+ '\\s*'
+ startTagAttrs.source
+ '\\s*'
+ handler.customAttrSurround[i][1].source

@@ -130,5 +129,5 @@ + ')';

attrClauses[i] = '(?:'
+ '(' + handler.customAttrSurround[i][0].source + ')'
+ '(' + handler.customAttrSurround[i][0].source + ')\\s*'
+ singleAttr.source
+ '(' + handler.customAttrSurround[i][1].source + ')'
+ '\\s*(' + handler.customAttrSurround[i][1].source + ')'
+ ')';

@@ -154,3 +153,3 @@ }

var HTMLParser = global.HTMLParser = function( html, handler ) {
var index, chars, match, stack = [], last = html, prevTag, nextTag;
var index, match, stack = [], last = html, prevTag, nextTag;
stack.last = function() {

@@ -165,4 +164,2 @@ var last = this[ this.length - 1 ];

while ( html ) {
chars = true;
// Make sure we're not in a script or style element

@@ -180,3 +177,4 @@ if ( !stack.last() || !special[ stack.last() ] ) {

html = html.substring( index + 3 );
chars = false;
prevTag = '';
continue;
}

@@ -194,29 +192,9 @@ }

html = html.substring( index + 2 );
chars = false;
prevTag = '';
continue;
}
}
// Ignored elements?
else if ( /^<\?/.test( html ) ) {
index = html.indexOf( '?>', 2 );
if ( index >= 0 ) {
if ( handler.chars ) {
handler.chars( html.substring( 0, index + 2 ) );
}
html = html.substring( index + 2 );
}
}
else if ( /^<%/.test( html ) ) {
index = html.indexOf( '%>', 2 );
if ( index >= 0 ) {
if ( handler.chars ) {
handler.chars(html.substring( 0, index + 2) );
}
html = html.substring( index + 2 );
}
}
// Doctype:
else if ( (match = doctype.exec( html )) ) {
if ( (match = doctype.exec( html )) ) {
if ( handler.doctype ) {

@@ -226,9 +204,9 @@ handler.doctype( match[0] );

html = html.substring( match[0].length );
chars = false;
prevTag = '';
continue;
}
// End tag:
else if ( /^<\//.test( html ) ) {
if ( /^<\//.test( html ) ) {
match = html.match( endTag );
if ( match ) {

@@ -238,3 +216,3 @@ html = html.substring( match[0].length );

prevTag = '/' + match[1].toLowerCase();
chars = false;
continue;
}

@@ -244,3 +222,3 @@

// Start tag:
else if ( /^</.test( html ) ) {
if ( /^</.test( html ) ) {
match = html.match( startTag );

@@ -251,32 +229,30 @@ if ( match ) {

prevTag = match[1].toLowerCase();
chars = false;
continue;
}
}
if ( chars ) {
index = html.indexOf('<');
index = html.indexOf('<');
var text = index < 0 ? html : html.substring( 0, index );
html = index < 0 ? '' : html.substring( index );
var text = index < 0 ? html : html.substring( 0, index );
html = index < 0 ? '' : html.substring( index );
// next tag
tagMatch = html.match( startTag );
// next tag
tagMatch = html.match( startTag );
if (tagMatch) {
nextTag = tagMatch[1];
}
else {
tagMatch = html.match( endTag );
if (tagMatch) {
nextTag = tagMatch[1];
nextTag = '/' + tagMatch[1];
}
else {
tagMatch = html.match( endTag );
if (tagMatch) {
nextTag = '/' + tagMatch[1];
}
else {
nextTag = '';
}
nextTag = '';
}
}
if ( handler.chars ) {
handler.chars(text, prevTag, nextTag);
}
if ( handler.chars ) {
handler.chars(text, prevTag, nextTag);
}
prevTag = '';

@@ -376,5 +352,2 @@ }

value: value,
escaped: value && value.replace(/(^|.)("+)/g, function(match) {
return match.replace(/"/g, '&quot;');
}),
customAssign: customAssign || '=',

@@ -439,3 +412,3 @@ customOpen: customOpen || '',

for ( var i = 0; i < attrs.length; i++ ) {
results += ' ' + attrs[i].name + '="' + attrs[i].escaped + '"';
results += ' ' + attrs[i].name + '="' + (attrs[i].value || '').replace(/"/g, '&#34;') + '"';
}

@@ -442,0 +415,0 @@

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc