Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ Most of the options are disabled by default.
| `collapseInlineTagWhitespace` | Don't leave any spaces between `display:inline;` elements when collapsing. Must be used in conjunction with `collapseWhitespace=true` | `false` |
| `collapseWhitespace` | [Collapse white space that contributes to text nodes in a document tree](http://perfectionkills.com/experimenting-with-html-minifier/#collapse_whitespace) | `false` |
| `conservativeCollapse` | Always collapse to 1 space (never remove it entirely). Must be used in conjunction with `collapseWhitespace=true` | `false` |
| `continueOnParseError` | [Handle parse errors](https://html.spec.whatwg.org/multipage/parsing.html#parse-errors) instead of aborting. | `false` |
| `customAttrAssign` | Arrays of regex'es that allow to support custom attribute assign expressions (e.g. `'<div flex?="{{mode != cover}}"></div>'`) | `[ ]` |
| `customAttrCollapse` | Regex that specifies custom attribute to strip newlines from (e.g. `/ng-class/`) | |
| `customAttrSurround` | Arrays of regex'es that allow to support custom attribute surround expressions (e.g. `<input {{#if value}}checked="checked"{{/if}}>`) | `[ ]` |
Expand Down
1 change: 1 addition & 0 deletions cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ var mainOptions = {
collapseInlineTagWhitespace: 'Collapse white space around inline tag',
collapseWhitespace: 'Collapse white space that contributes to text nodes in a document tree.',
conservativeCollapse: 'Always collapse to 1 space (never remove it entirely)',
continueOnParseError: 'Handle parse errors instead of aborting',
customAttrAssign: ['Arrays of regex\'es that allow to support custom attribute assign expressions (e.g. \'<div flex?="{{mode != cover}}"></div>\')', parseJSONRegExpArray],
customAttrCollapse: ['Regex that specifies custom attribute to strip newlines from (e.g. /ng-class/)', parseRegExp],
customAttrSurround: ['Arrays of regex\'es that allow to support custom attribute surround expressions (e.g. <input {{#if value}}checked="checked"{{/if}}>)', parseJSONRegExpArray],
Expand Down
1 change: 1 addition & 0 deletions sample-cli-config-file.conf
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"collapseInlineTagWhitespace": false,
"collapseWhitespace": true,
"conservativeCollapse": false,
"continueOnParseError": true,
"customAttrCollapse": ".*",
"decodeEntities": true,
"html5": true,
Expand Down
7 changes: 4 additions & 3 deletions src/htmlminifier.js
Original file line number Diff line number Diff line change
Expand Up @@ -965,6 +965,9 @@ function minify(value, options, partialMarkup) {

new HTMLParser(value, {
partialMarkup: partialMarkup,
continueOnParseError: options.continueOnParseError,
customAttrAssign: options.customAttrAssign,
customAttrSurround: options.customAttrSurround,
html5: options.html5,

start: function(tag, attrs, unary, unarySlash, autoGenerated) {
Expand Down Expand Up @@ -1241,9 +1244,7 @@ function minify(value, options, partialMarkup) {
buffer.push(options.useShortDoctype ? '<!doctype' +
(options.removeTagWhitespace ? '' : ' ') + 'html>' :
collapseWhitespaceAll(doctype));
},
customAttrAssign: options.customAttrAssign,
customAttrSurround: options.customAttrSurround
}
});

if (options.removeOptionalTags) {
Expand Down
6 changes: 5 additions & 1 deletion src/htmlparser.js
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,11 @@ function HTMLParser(html, handler) {
prevTag = startTagMatch.tagName.toLowerCase();
continue;
}

// Treat `<` as text
if (handler.continueOnParseError) {
textEnd = html.indexOf('<', 1);
}
}

var text;
Expand Down Expand Up @@ -213,7 +218,6 @@ function HTMLParser(html, handler) {
handler.chars(text, prevTag, nextTag);
}
prevTag = '';

}
else {
var stackedTag = lastTag.toLowerCase();
Expand Down
40 changes: 29 additions & 11 deletions tests/minifier.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ QUnit.test('parsing non-trivial markup', function(assert) {
assert.throws(function() {
minify(input);
}, 'Invalid tag name');
assert.equal(minify(input, {
continueOnParseError: true,
}), input);

input = '<begriffs.pagination ng-init="perPage=20" collection="logs" url="\'/api/logs?user=-1\'" per-page="perPage" per-page-presets="[10,20,50,100]" template-url="/assets/paginate-anything.html"></begriffs.pagination>';
assert.equal(minify(input), input);
Expand Down Expand Up @@ -93,9 +96,13 @@ QUnit.test('parsing non-trivial markup', function(assert) {
// https://github.com/kangax/html-minifier/issues/507
input = '<tag v-ref:vm_pv :imgs=" objpicsurl_ "></tag>';
assert.equal(minify(input), input);
input = '<tag v-ref:vm_pv :imgs=" objpicsurl_ " ss"123>';
assert.throws(function() {
minify('<tag v-ref:vm_pv :imgs=" objpicsurl_ " ss"123></tag>');
minify(input);
}, 'invalid attribute name');
assert.equal(minify(input, {
continueOnParseError: true,
}), input);

// https://github.com/kangax/html-minifier/issues/512
input = '<input class="form-control" type="text" style="" id="{{vm.formInputName}}" name="{{vm.formInputName}}"' +
Expand All @@ -106,18 +113,29 @@ QUnit.test('parsing non-trivial markup', function(assert) {
' data-ng-pattern="vm.options.format"' +
' data-options="vm.datepickerOptions">';
assert.equal(minify(input), input);
input = '<input class="form-control" type="text" style="" id="{{vm.formInputName}}" name="{{vm.formInputName}}"' +
' <!--FIXME hardcoded placeholder - dates may not be used for service required fields yet. -->' +
' placeholder="YYYY-MM-DD"' +
' date-range-picker' +
' data-ng-model="vm.value"' +
' data-ng-model-options="{ debounce: 1000 }"' +
' data-ng-pattern="vm.options.format"' +
' data-options="vm.datepickerOptions">';
assert.throws(function() {
minify(
'<input class="form-control" type="text" style="" id="{{vm.formInputName}}" name="{{vm.formInputName}}"' +
' <!--FIXME hardcoded placeholder - dates may not be used for service required fields yet. -->' +
' placeholder="YYYY-MM-DD"' +
' date-range-picker' +
' data-ng-model="vm.value"' +
' data-ng-model-options="{ debounce: 1000 }"' +
' data-ng-pattern="vm.options.format"' +
' data-options="vm.datepickerOptions">'
);
minify(input);
}, 'HTML comment inside tag');
assert.equal(minify(input, {
continueOnParseError: true,
}), input);

// https://github.com/kangax/html-minifier/issues/974
input = '<!–– Failing New York Times Comment -->';
assert.throws(function() {
minify(input);
}, 'invalid HTML comment');
assert.equal(minify(input, {
continueOnParseError: true,
}), input);

input = '<br a=\u00A0 b="&nbsp;" c="\u00A0">';
output = '<br a="\u00A0" b="&nbsp;" c="\u00A0">';
Expand Down