Socket
Socket
Sign inDemoInstall

minimize

Package Overview
Dependencies
Maintainers
1
Versions
65
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

minimize - npm Package Compare versions

Comparing version 0.5.14 to 0.6.0

lib/list.js

121

lib/helpers.js

@@ -6,3 +6,4 @@ 'use strict';

//
var util = require('utile');
var util = require('utile')
, list = require('./list');

@@ -12,31 +13,6 @@ //

//
var flow = /<\/[^>]+>$|\w+$/
, conditional = /\[if.+IE[\s\d]*\]>.+<\!\[endif\]/g
, inline = [
'a', 'abbr', 'b', 'bdo', 'br', 'cite',
'code', 'dfn', 'em', 'i', 'img', 'kbd',
'q', 'samp', 'small', 'span', 'strong',
'sub', 'sup', 'textarea', 'var',
]
, singular = [
'area', 'base', 'br', 'col', 'command', 'embed', 'hr',
'img', 'input', 'link', 'meta', 'param', 'source',
]
, redundant = [
'autofocus', 'disabled', 'multiple', 'required', 'readonly', 'hidden',
'async', 'defer', 'formnovalidate', 'checked', 'scoped', 'reversed',
'selected', 'autoplay', 'controls', 'loop', 'muted', 'seamless',
'default', 'ismap', 'novalidate', 'open', 'typemustmatch', 'truespeed',
'itemscope'
]
, node = [ 'tag', 'script', 'style' ]
, structural = [ 'pre', 'textarea', 'code' ]
var conditional = /\[if.+IE[\s\d]*\]>.+<\!\[endif\]/g
, retain = /data|itemscope/
, cdata = {
start: /\/*<!\[CDATA\[/g,
end: /\/*\]\]>/g
}
, interpunction = '.,!%;:?$'
, start = new RegExp('^[' + interpunction + ']')
, end = new RegExp('[-' + interpunction + ']$');
, cdataStart = /\/*<!\[CDATA\[/g
, cdataEnd = /\/*\]\]>/g;

@@ -62,3 +38,3 @@ //

*/
function Helpers (options) {
function Helpers(options) {
this.config = util.mixin(util.clone(config), options || {});

@@ -76,7 +52,11 @@

*/
Helpers.prototype.quote = function quote (value) {
Helpers.prototype.quote = function quote(value) {
//
// Quote is only called if required so it's safe to return quotes on no value.
//
if (!value) return '""';
//
// Always quote attributes having spaces or ending in a slash.
//
return value.slice(-1) === '/' || (/[\s=]+/).test(value) || this.config.quotes

@@ -94,4 +74,4 @@ ? '"' + value + '"'

*/
Helpers.prototype.isInline = function isInline (element) {
return !!~inline.indexOf(element.name);
Helpers.prototype.isInline = function isInline(element) {
return !!~list.inline.indexOf(element.name);
};

@@ -107,9 +87,9 @@

*/
Helpers.prototype.tag = function tag (element, data) {
Helpers.prototype.tag = function tag(element, data) {
//
// Check if the current element requires structure, store for later reference.
//
if (this.structure(element)) this.ancestor.push(element);
return (this.isInline(element) && (flow.test(data) || end.test(data))
? ' <'
: '<') + element.name + this.attributes(element) + '>';
return '<' + element.name + this.attributes(element) + '>';
};

@@ -125,3 +105,3 @@

*/
Helpers.prototype.attributes = function attributes (element) {
Helpers.prototype.attributes = function attributes(element) {
var attr = element.attribs

@@ -135,9 +115,15 @@ , self = this

value = attr[key];
bool = ~redundant.indexOf(key);
bool = ~list.redundant.indexOf(key);
//
// Remove attributes that are empty, not boolean and no semantic value.
//
if (!self.config.empty && !retain.test(key) && !bool && !value) return result;
//
// Boolean attributes should be added sparse.
//
if (!self.config.spare && bool) return result + ' ' + key;
//
// Return full attribute with value.
//
return result + ' ' + key + '=' + self.quote(value);

@@ -154,6 +140,6 @@ }, '');

*/
Helpers.prototype.close = function close (element) {
Helpers.prototype.close = function close(element) {
if (this.structure(element)) this.ancestor.pop();
return ~node.indexOf(element.type) && !~singular.indexOf(element.name)
return ~list.node.indexOf(element.type) && !~list.singular.indexOf(element.name)
? '</' + element.name + '>'

@@ -171,3 +157,3 @@ : '';

*/
Helpers.prototype.isJS = function isJS (element) {
Helpers.prototype.isJS = function isJS(element) {
return (element.type === 'script' && (!element.attribs || !element.attribs.type))

@@ -196,5 +182,5 @@ || (element.type === 'script' && element.attribs.type === 'text/javascript');

*/
Helpers.prototype.structure = function structure (element) {
Helpers.prototype.structure = function structure(element) {
return element.type !== 'text'
? !!~structural.indexOf(element.name) || this.isJS(element) || this.isStyle(element)
? !!~list.structural.indexOf(element.name) || this.isJS(element) || this.isStyle(element)
: false;

@@ -205,4 +191,4 @@ };

* Return trimmed text, if text requires no structure new lines and spaces will
* be replaced with a single white space. If the element is preluded by an inline
* element a white space is added.
* be replaced with a single white space. Any white space adjacent to an inline
* element is replaced with a single space.
*

@@ -214,19 +200,28 @@ * @param {Object} element

*/
Helpers.prototype.text = function text (element, data) {
var ancestors = this.ancestor.length;
Helpers.prototype.text = function text(element, data) {
var ancestors = this.ancestor.length
, content = element.data
, next = element.next
, prev = element.prev;
element = element.data.trim();
//
// Collapse space between text and inline elements, clobber space without
// inline elements.
//
content = content.replace(/^\s+/, prev && this.isInline(prev) ? ' ' : '');
content = content.replace(/\s+$/, next && this.isInline(next) ? ' ' : '');
//
// If we have ancestors stored do not remove structure.
if (!ancestors) element = element.replace(/\n/g, ' ').replace(/\s+/g, ' ');
//
if (!ancestors) content = content.replace(/\n/g, ' ').replace(/\s+/g, ' ');
//
// Remove CDATA from scripts.
//
if (!this.config.cdata && ancestors && this.isJS(this.ancestor[ancestors - 1])) {
element = element.replace(cdata.start, '').replace(cdata.end, '');
content = content.replace(cdataStart, '').replace(cdataEnd, '');
}
// Check if the text requires flowing based on last output and interpunction.
if (element.length && flow.test(data) && !start.test(element)) element = ' ' + element;
return element;
return content;
};

@@ -241,3 +236,3 @@

*/
Helpers.prototype.comment = function comment (element) {
Helpers.prototype.comment = function comment(element) {
if (this.config.conditionals && conditional.test(element.data)) {

@@ -257,3 +252,3 @@ return '<!--' + element.data + '-->';

*/
Helpers.prototype.directive = function directive (element) {
Helpers.prototype.directive = function directive(element) {
return '<' + element.data + '>';

@@ -272,13 +267,5 @@ };

if (process.env.NODE_ENV === 'test') {
Helpers.prototype.flow = flow;
Helpers.prototype.node = node;
Helpers.prototype.structural = structural;
Helpers.prototype.retain = retain;
Helpers.prototype.redundant = redundant;
Helpers.prototype.inline = inline;
Helpers.prototype.singular = singular;
Helpers.prototype.interpunction = interpunction;
Helpers.prototype.start = start;
Helpers.prototype.end = end;
Helpers.prototype.cdata = cdata;
Helpers.prototype.cdataStart = cdataStart;
Helpers.prototype.cdataEnd = cdataEnd;
}

@@ -285,0 +272,0 @@

@@ -17,7 +17,10 @@ 'use strict';

*/
function Minimize (options) {
function Minimize(options) {
// Pass options to helpers.
//
this.helpers = new Helpers(options || {});
//
// Prepare the parser.
//
this.htmlparser = new parser.Parser(

@@ -43,6 +46,10 @@ new parser.DefaultHandler(this.minifier.bind(this))

// Listen to dom parsing as the
//
// Listen to DOM parsing, so the htmlparser callback can trigger it.
//
this.once('parsed', callback);
// Parse the HTML.
//
// Initiate parsing of HTML.
//
this.htmlparser.parseComplete(content);

@@ -58,6 +65,8 @@ };

*/
Minimize.prototype.minifier = function minifier (error, dom) {
Minimize.prototype.minifier = function minifier(error, dom) {
if (error) throw new Error('Minifier failed to parse DOM', error);
//
// DOM has been completely parsed, emit the results.
//
this.emit('parsed', error, this.traverse(dom, ''));

@@ -74,3 +83,3 @@ };

*/
Minimize.prototype.traverse = function traverse (data, html) {
Minimize.prototype.traverse = function traverse(data, html) {
return data.reduce(this.walk.bind(this), html);

@@ -87,3 +96,3 @@ };

*/
Minimize.prototype.walk = function walk (html, element) {
Minimize.prototype.walk = function walk(html, element) {
html += this.helpers[element.type](element, html);

@@ -90,0 +99,0 @@

{
"name": "minimize",
"version": "0.5.14",
"version": "0.6.0",
"description": "Minimize HTML",

@@ -5,0 +5,0 @@ "main": "./lib/minimize",

@@ -15,2 +15,3 @@ {

"styles": "<style> .test { color: #FFF }</style><style>.test { color: black }</style>",
"br": "<p class=\"slide\">\n <span>\n <em>Does your organization have security or licensing restrictions?</em>\n </span>\n\n <br/><br/>\n <span>\n Your private npm registry makes managing them simple by giving you the power\n to work with a blacklist and a whitelist of public npm packages.\n </span>\n </p>",
"doctype": {

@@ -17,0 +18,0 @@ "data": "!doctype html",

@@ -9,2 +9,3 @@ /*global beforeEach, afterEach*/

, Helpers = require('../lib/helpers')
, list = require('../lib/list')
, helpers = new Helpers()

@@ -53,10 +54,5 @@ , html = require('./fixtures/html.json');

it('which has a regular expression named flow', function () {
expect(helpers).to.have.property('flow');
expect(helpers.flow).to.be.a('regexp');
});
it('which has an array named node', function () {
expect(helpers).to.have.property('node');
expect(helpers.node).to.be.an('array');
expect(list).to.have.property('node');
expect(list.node).to.be.an('array');
});

@@ -70,42 +66,26 @@

it('which has an named redundant', function () {
expect(helpers).to.have.property('redundant');
expect(helpers.redundant).to.be.an('array');
expect(list).to.have.property('redundant');
expect(list.redundant).to.be.an('array');
});
it('which has a regular expression named structural', function () {
expect(helpers).to.have.property('structural');
expect(helpers.structural).to.be.an('array');
expect(list).to.have.property('structural');
expect(list.structural).to.be.an('array');
});
it('which has a regular expression named cdata', function () {
expect(helpers).to.have.property('cdata');
expect(helpers.cdata).to.be.a('object');
expect(helpers.cdata.start).to.be.a('regexp');
expect(helpers.cdata.end).to.be.a('regexp');
it('which has regular expressions for cdata', function () {
expect(helpers).to.have.property('cdataStart');
expect(helpers).to.have.property('cdataEnd');
expect(helpers.cdataStart).to.be.a('regexp');
expect(helpers.cdataEnd).to.be.a('regexp');
});
it('which has a string with interpunction listed', function () {
expect(helpers).to.have.property('interpunction');
expect(helpers.interpunction).to.be.a('string');
expect(helpers.interpunction).to.be.equal('.,!%;:?$');
});
it('which has a regexp named start which triggers on interpunction', function () {
expect(helpers).to.have.property('start');
expect(helpers.start).to.be.a('regexp');
});
it('which has a regexp named end which has dashes appended', function () {
expect(helpers).to.have.property('end');
expect(helpers.end).to.be.a('regexp');
});
it('which has an inline element reference', function () {
expect(helpers).to.have.property('inline');
expect(helpers.inline).to.be.an('array');
expect(list).to.have.property('inline');
expect(list.inline).to.be.an('array');
});
it('which has an singular element reference', function () {
expect(helpers).to.have.property('singular');
expect(helpers.singular).to.be.an('array');
expect(list).to.have.property('singular');
expect(list.singular).to.be.an('array');
});

@@ -236,28 +216,2 @@

});
describe('prepends a space if the element', function () {
it('is inline and prepended by text', function () {
expect(helpers.tag(html.inline, 'text')).to.be.equal(
' <' + html.inline.name + '>'
);
expect(structure).to.be.calledOnce;
});
it('is inline and prepended by interpunction', function () {
expect(helpers.tag(html.inline, 'text.')).to.be.equal(
' <' + html.inline.name + '>'
);
expect(structure).to.be.calledOnce;
});
it('is inline and prepended by closing tag', function () {
expect(helpers.tag(html.inline, 'text</b>')).to.be.equal(
' <' + html.inline.name + '>'
);
expect(structure).to.be.calledOnce;
});
});
});

@@ -388,2 +342,4 @@

afterEach(function () {
delete html.text.next;
delete html.text.prev;
html.text.data = text;

@@ -416,10 +372,14 @@ helpers.ancestor = [];

it('prepends space if current HTML ends with closing tag', function () {
var result = helpers.text(html.text, 'some HTML</strong>');
it('removes whitespace after block elements', function () {
html.text.prev = html.block;
html.text.data = ' \n\n ' + html.text.data;
var result = helpers.text(html.text, '');
expect(result).to.be.equal(' ' + text);
expect(result).to.be.equal(text);
});
it('prepends space if current HTML ends with word boundary', function () {
var result = helpers.text(html.text, 'some HTML');
it('collapses whitespace after inline elements', function () {
html.text.prev = html.inline;
html.text.data = ' \n\n ' + html.text.data;
var result = helpers.text(html.text, '');

@@ -429,14 +389,16 @@ expect(result).to.be.equal(' ' + text);

it('prepends no whitespace if text starts with interpunction', function () {
html.text.data = '. ' + html.text.data;
var result = helpers.text(html.text, 'some HTML');
it('removes whitespace before block elements', function () {
html.text.next = html.block;
html.text.data = html.text.data + ' \n\n ';
var result = helpers.text(html.text, '');
expect(result).to.be.equal(html.text.data);
expect(result).to.be.equal(text);
});
it('prepends whitespace if text starts with a dash', function () {
html.text.data = '- ' + html.text.data;
var result = helpers.text(html.text, 'some HTML');
it('collapses whitespace before inline elements', function () {
html.text.next = html.inline;
html.text.data = html.text.data + ' \n\n ';
var result = helpers.text(html.text, '');
expect(result).to.be.equal(' ' + html.text.data);
expect(result).to.be.equal(text + ' ');
});

@@ -447,7 +409,7 @@ });

it('is an array', function () {
expect(helpers.inline).to.be.an('array');
expect(list.inline).to.be.an('array');
});
it('has all required elements', function () {
expect(helpers.inline.length).to.be.equal(21);
expect(list.inline.length).to.be.equal(21);
});

@@ -458,7 +420,7 @@ });

it('is an array', function () {
expect(helpers.singular).to.be.an('array');
expect(list.singular).to.be.an('array');
});
it('has all required elements', function () {
expect(helpers.singular.length).to.be.equal(13);
expect(list.singular.length).to.be.equal(13);
});

@@ -469,5 +431,5 @@ });

it('matches pre or textarea', function () {
expect(!!~helpers.structural.indexOf('pre')).to.be.true;
expect(!!~helpers.structural.indexOf('textarea')).to.be.true;
expect(!!~helpers.structural.indexOf('code')).to.be.true;
expect(!!~list.structural.indexOf('pre')).to.be.true;
expect(!!~list.structural.indexOf('textarea')).to.be.true;
expect(!!~list.structural.indexOf('code')).to.be.true;
});

@@ -478,5 +440,5 @@ });

it('matches tag, style or script', function () {
expect(!!~helpers.node.indexOf('tag')).to.be.true;
expect(!!~helpers.node.indexOf('script')).to.be.true;
expect(!!~helpers.node.indexOf('style')).to.be.true;
expect(!!~list.node.indexOf('tag')).to.be.true;
expect(!!~list.node.indexOf('script')).to.be.true;
expect(!!~list.node.indexOf('style')).to.be.true;
});

@@ -487,21 +449,9 @@ });

it('matches boolean attributes', function () {
expect(!!~helpers.redundant.indexOf('disabled')).to.be.true;
expect(!!~helpers.redundant.indexOf('multiple')).to.be.true;
expect(!!~helpers.redundant.indexOf('muted')).to.be.true;
expect(!!~helpers.redundant.indexOf('class')).to.be.false;
expect(!!~list.redundant.indexOf('disabled')).to.be.true;
expect(!!~list.redundant.indexOf('multiple')).to.be.true;
expect(!!~list.redundant.indexOf('muted')).to.be.true;
expect(!!~list.redundant.indexOf('class')).to.be.false;
});
});
describe('regular expression start', function () {
it('is a valid regular expression', function () {
function regexp () { return new RegExp(helpers.start); }
expect(regexp).to.not.throw(Error);
});
it('matches interpunction without dashes', function () {
expect(helpers.start.test('-')).to.be.false;
expect(helpers.start.test('.')).to.be.true;
});
});
describe('regular expression retain', function () {

@@ -513,3 +463,3 @@ it('is a valid regular expression', function () {

it('matches interpunction without dashes', function () {
it('matches data and itemscope', function () {
expect(helpers.retain.test('data')).to.be.true;

@@ -520,19 +470,7 @@ expect(helpers.retain.test('itemscope')).to.be.true;

describe('regular expression end', function () {
it('is a valid regular expression', function () {
function regexp () { return new RegExp(helpers.end); }
expect(regexp).to.not.throw(Error);
});
it('matches interpunction with dashes', function () {
expect(helpers.end.test('-')).to.be.true;
expect(helpers.end.test('.')).to.be.true;
});
});
describe('regular expression cdata', function () {
it('is a valid regular expression', function () {
function regexp () {
new RegExp(helpers.cdata.start);
new RegExp(helpers.cdata.end);
new RegExp(helpers.cdataStart);
new RegExp(helpers.cdataEnd);
}

@@ -544,26 +482,7 @@

it('matches closing and ending parts of CDATA', function () {
expect(helpers.cdata.start.test('//<![CDATA[')).to.be.true;
expect(helpers.cdata.end.test('//]]>')).to.be.true;
expect(helpers.cdataStart.test('//<![CDATA[')).to.be.true;
expect(helpers.cdataEnd.test('//]]>')).to.be.true;
});
});
describe('regular expression flow', function () {
it('is a valid regular expression', function () {
function regexp () { return new RegExp(helpers.flow); }
expect(regexp).to.not.throw(Error);
});
it('can detect if last part of string is closing tag', function () {
var match = 'test string</b>'.match(helpers.flow);
expect(match).to.be.an('array');
expect(match[0]).to.be.equal('</b>');
});
it('can detect if last part of string is text', function () {
var match = '</b>test'.match(helpers.flow);
expect(match).to.be.an('array');
expect(match[0]).to.be.equal('test');
});
});
describe('has options', function () {

@@ -570,0 +489,0 @@ it('which are all false by default', function () {

@@ -111,3 +111,3 @@ 'use strict';

minimize.parse(html.code, function (error, result) {
expect(result).to.equal("<code class=copy><span>var http = require('http');\nhttp.createServer(function (req, res) {\n res.writeHead(200, {'Content-Type': 'text/plain'});\n res.end('hello, i know nodejitsu');\n})listen(8080);</span> <a href=#><s class=ss-layers role=presentation></s> copy</a></code>");
expect(result).to.equal("<code class=copy><span>var http = require('http');\nhttp.createServer(function (req, res) {\n res.writeHead(200, {'Content-Type': 'text/plain'});\n res.end('hello, i know nodejitsu');\n})listen(8080);</span><a href=#><s class=ss-layers role=presentation></s> copy</a></code>");
done();

@@ -140,3 +140,3 @@ });

minimize.parse(html.spacing, function (error, result) {
expect(result).to.equal("<strong>npm</strong>. You don't have to worry about installing npm since it comes bundled with Node.js.<pre class=copy>$ <span>npm install jitsu -g</span> <a href=#><s class=ss-layers role=presentation></s> copy</a></pre>");
expect(result).to.equal("<strong>npm</strong>. You don't have to worry about installing npm since it comes bundled with Node.js.<pre class=copy>$ <span>npm install jitsu -g</span><a href=#><s class=ss-layers role=presentation></s> copy</a></pre>");
done();

@@ -155,3 +155,3 @@ });

minimize.parse(html.full, function (error, result) {
expect(result).to.equal("<!doctype html><html class=no-js><head></head><body class=container><section class=navigation id=navigation><nav class=row><h1><a href=\"/\" class=logo title=\"Back to the homepage\">Nodejitsu</a></h1> <a href=#navigation class=\"mobile btn ss-rows\"></a> <a href=/paas>Cloud</a> <a href=/enterprise/private-cloud>Enterprise</a></nav></section><input type=text name=temp></body></html>");
expect(result).to.equal("<!doctype html><html class=no-js><head></head><body class=container><section class=navigation id=navigation><nav class=row><h1><a href=\"/\" class=logo title=\"Back to the homepage\">Nodejitsu</a></h1><a href=#navigation class=\"mobile btn ss-rows\"></a> <a href=/paas>Cloud</a> <a href=/enterprise/private-cloud>Enterprise</a></nav></section><input type=text name=temp></body></html>");
done();

@@ -204,2 +204,10 @@ });

});
it('should clobber space around <br> elements', function (done) {
var quote = new Minimize;
quote.parse(html.br, function (error, result) {
expect(result).to.equal("<p class=slide><span><em>Does your organization have security or licensing restrictions?</em></span><br><br><span>Your private npm registry makes managing them simple by giving you the power to work with a blacklist and a whitelist of public npm packages.</span></p>");
done();
});
});
});

@@ -206,0 +214,0 @@

SocketSocket SOC 2 Logo

Product

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

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc