From eeeb59d1db33c71c8d984bf76229d75dc6734646 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Sat, 23 Nov 2019 18:45:54 +0100 Subject: [PATCH] Collapse whitespace in `class` attributes --- .../hbs-minifier-plugin.test.js.snap | 909 +++++++++++++++++- hbs-minifier-plugin.js | 26 + hbs-minifier-plugin.test.js | 30 + 3 files changed, 962 insertions(+), 3 deletions(-) diff --git a/__snapshots__/hbs-minifier-plugin.test.js.snap b/__snapshots__/hbs-minifier-plugin.test.js.snap index 3db7e698..c0f12dfc 100644 --- a/__snapshots__/hbs-minifier-plugin.test.js.snap +++ b/__snapshots__/hbs-minifier-plugin.test.js.snap @@ -1,5 +1,306 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`HBS Minifier plugin (with @glimmer/syntax v0.35.11) collapses whitespace in concatenated \`class\` attributes 1`] = ` +Program { + "blockParams": Array [], + "body": Array [ + ElementNode { + "attributes": Array [ + AttrNode { + "name": "class", + "value": ConcatStatement { + "parts": Array [ + TextNode { + "chars": "btn ", + }, + MustacheStatement { + "escaped": true, + "hash": Hash { + "pairs": Array [], + }, + "params": Array [ + PathExpression { + "data": false, + "original": "this.isPrimary", + "parts": Array [ + "isPrimary", + ], + "this": true, + }, + StringLiteral { + "original": "btn--primary", + "value": "btn--primary", + }, + ], + "path": PathExpression { + "data": false, + "original": "if", + "parts": Array [ + "if", + ], + "this": false, + }, + }, + TextNode { + "chars": " ", + }, + MustacheStatement { + "escaped": true, + "hash": Hash { + "pairs": Array [], + }, + "params": Array [ + PathExpression { + "data": true, + "original": "@stretch", + "parts": Array [ + "stretch", + ], + "this": false, + }, + StringLiteral { + "original": "btn--stretch", + "value": "btn--stretch", + }, + ], + "path": PathExpression { + "data": false, + "original": "if", + "parts": Array [ + "if", + ], + "this": false, + }, + }, + ], + }, + }, + ], + "blockParams": Array [], + "children": Array [], + "comments": Array [], + "modifiers": Array [], + "selfClosing": true, + "tag": "button", + }, + ], +} +`; + +exports[`HBS Minifier plugin (with @glimmer/syntax v0.35.11) collapses whitespace in concatenated \`class\` attributes 2`] = ` +" + " +`; + +exports[`HBS Minifier plugin (with @glimmer/syntax v0.35.11) collapses whitespace in concatenated \`class\` attributes 3`] = ` +Program { + "blockParams": Array [], + "body": Array [ + ElementNode { + "attributes": Array [ + AttrNode { + "name": "class", + "value": ConcatStatement { + "parts": Array [ + TextNode { + "chars": "foo ", + }, + MustacheStatement { + "escaped": true, + "hash": Hash { + "pairs": Array [], + }, + "params": Array [], + "path": PathExpression { + "data": true, + "original": "@bar", + "parts": Array [ + "bar", + ], + "this": false, + }, + }, + TextNode { + "chars": " baz", + }, + ], + }, + }, + ], + "blockParams": Array [], + "children": Array [], + "comments": Array [], + "modifiers": Array [], + "selfClosing": true, + "tag": "button", + }, + ], +} +`; + +exports[`HBS Minifier plugin (with @glimmer/syntax v0.35.11) collapses whitespace in concatenated \`class\` attributes 4`] = ` +"" +`; + +exports[`HBS Minifier plugin (with @glimmer/syntax v0.35.11) collapses whitespace in concatenated \`class\` attributes 5`] = ` +Program { + "blockParams": Array [], + "body": Array [ + ElementNode { + "attributes": Array [ + AttrNode { + "name": "class", + "value": ConcatStatement { + "parts": Array [ + MustacheStatement { + "escaped": true, + "hash": Hash { + "pairs": Array [], + }, + "params": Array [], + "path": PathExpression { + "data": true, + "original": "@foo", + "parts": Array [ + "foo", + ], + "this": false, + }, + }, + TextNode { + "chars": " bar ", + }, + MustacheStatement { + "escaped": true, + "hash": Hash { + "pairs": Array [], + }, + "params": Array [], + "path": PathExpression { + "data": true, + "original": "@baz", + "parts": Array [ + "baz", + ], + "this": false, + }, + }, + ], + }, + }, + ], + "blockParams": Array [], + "children": Array [], + "comments": Array [], + "modifiers": Array [], + "selfClosing": true, + "tag": "button", + }, + ], +} +`; + +exports[`HBS Minifier plugin (with @glimmer/syntax v0.35.11) collapses whitespace in concatenated \`class\` attributes 6`] = ` +"" +`; + +exports[`HBS Minifier plugin (with @glimmer/syntax v0.35.11) collapses whitespace in concatenated \`class\` attributes 7`] = ` +Program { + "blockParams": Array [], + "body": Array [ + ElementNode { + "attributes": Array [ + AttrNode { + "name": "class", + "value": ConcatStatement { + "parts": Array [ + MustacheStatement { + "escaped": true, + "hash": Hash { + "pairs": Array [], + }, + "params": Array [], + "path": PathExpression { + "data": true, + "original": "@foo", + "parts": Array [ + "foo", + ], + "this": false, + }, + }, + ], + }, + }, + ], + "blockParams": Array [], + "children": Array [], + "comments": Array [], + "modifiers": Array [], + "selfClosing": true, + "tag": "button", + }, + ], +} +`; + +exports[`HBS Minifier plugin (with @glimmer/syntax v0.35.11) collapses whitespace in concatenated \`class\` attributes 8`] = ` +"" +`; + +exports[`HBS Minifier plugin (with @glimmer/syntax v0.35.11) collapses whitespace in regular \`class\` attributes 1`] = ` +Program { + "blockParams": Array [], + "body": Array [ + ElementNode { + "attributes": Array [ + AttrNode { + "name": "class", + "value": TextNode { + "chars": "btn btn--primary btn--blue", + }, + }, + ], + "blockParams": Array [], + "children": Array [], + "comments": Array [], + "modifiers": Array [], + "selfClosing": true, + "tag": "button", + }, + ], +} +`; + +exports[`HBS Minifier plugin (with @glimmer/syntax v0.35.11) collapses whitespace in regular \`class\` attributes 2`] = ` +" + " +`; + exports[`HBS Minifier plugin (with @glimmer/syntax v0.35.11) collapses whitespace into single space character 1`] = ` Program { "blockParams": Array [], @@ -981,10 +1282,311 @@ Program { } `; -exports[`HBS Minifier plugin (with @glimmer/syntax v0.35.11) strips leading and trailing whitespace from Program nodes 2`] = ` -" {{foo}} +exports[`HBS Minifier plugin (with @glimmer/syntax v0.35.11) strips leading and trailing whitespace from Program nodes 2`] = ` +" {{foo}} +--- +{{foo}}" +`; + +exports[`HBS Minifier plugin (with @glimmer/syntax v0.37.1) collapses whitespace in concatenated \`class\` attributes 1`] = ` +Program { + "blockParams": Array [], + "body": Array [ + ElementNode { + "attributes": Array [ + AttrNode { + "name": "class", + "value": ConcatStatement { + "parts": Array [ + TextNode { + "chars": "btn ", + }, + MustacheStatement { + "escaped": true, + "hash": Hash { + "pairs": Array [], + }, + "params": Array [ + PathExpression { + "data": false, + "original": "this.isPrimary", + "parts": Array [ + "isPrimary", + ], + "this": true, + }, + StringLiteral { + "original": "btn--primary", + "value": "btn--primary", + }, + ], + "path": PathExpression { + "data": false, + "original": "if", + "parts": Array [ + "if", + ], + "this": false, + }, + }, + TextNode { + "chars": " ", + }, + MustacheStatement { + "escaped": true, + "hash": Hash { + "pairs": Array [], + }, + "params": Array [ + PathExpression { + "data": true, + "original": "@stretch", + "parts": Array [ + "stretch", + ], + "this": false, + }, + StringLiteral { + "original": "btn--stretch", + "value": "btn--stretch", + }, + ], + "path": PathExpression { + "data": false, + "original": "if", + "parts": Array [ + "if", + ], + "this": false, + }, + }, + ], + }, + }, + ], + "blockParams": Array [], + "children": Array [], + "comments": Array [], + "modifiers": Array [], + "selfClosing": true, + "tag": "button", + }, + ], +} +`; + +exports[`HBS Minifier plugin (with @glimmer/syntax v0.37.1) collapses whitespace in concatenated \`class\` attributes 2`] = ` +" + " +`; + +exports[`HBS Minifier plugin (with @glimmer/syntax v0.37.1) collapses whitespace in concatenated \`class\` attributes 3`] = ` +Program { + "blockParams": Array [], + "body": Array [ + ElementNode { + "attributes": Array [ + AttrNode { + "name": "class", + "value": ConcatStatement { + "parts": Array [ + TextNode { + "chars": "foo ", + }, + MustacheStatement { + "escaped": true, + "hash": Hash { + "pairs": Array [], + }, + "params": Array [], + "path": PathExpression { + "data": true, + "original": "@bar", + "parts": Array [ + "bar", + ], + "this": false, + }, + }, + TextNode { + "chars": " baz", + }, + ], + }, + }, + ], + "blockParams": Array [], + "children": Array [], + "comments": Array [], + "modifiers": Array [], + "selfClosing": true, + "tag": "button", + }, + ], +} +`; + +exports[`HBS Minifier plugin (with @glimmer/syntax v0.37.1) collapses whitespace in concatenated \`class\` attributes 4`] = ` +"" +`; + +exports[`HBS Minifier plugin (with @glimmer/syntax v0.37.1) collapses whitespace in concatenated \`class\` attributes 5`] = ` +Program { + "blockParams": Array [], + "body": Array [ + ElementNode { + "attributes": Array [ + AttrNode { + "name": "class", + "value": ConcatStatement { + "parts": Array [ + MustacheStatement { + "escaped": true, + "hash": Hash { + "pairs": Array [], + }, + "params": Array [], + "path": PathExpression { + "data": true, + "original": "@foo", + "parts": Array [ + "foo", + ], + "this": false, + }, + }, + TextNode { + "chars": " bar ", + }, + MustacheStatement { + "escaped": true, + "hash": Hash { + "pairs": Array [], + }, + "params": Array [], + "path": PathExpression { + "data": true, + "original": "@baz", + "parts": Array [ + "baz", + ], + "this": false, + }, + }, + ], + }, + }, + ], + "blockParams": Array [], + "children": Array [], + "comments": Array [], + "modifiers": Array [], + "selfClosing": true, + "tag": "button", + }, + ], +} +`; + +exports[`HBS Minifier plugin (with @glimmer/syntax v0.37.1) collapses whitespace in concatenated \`class\` attributes 6`] = ` +"" +`; + +exports[`HBS Minifier plugin (with @glimmer/syntax v0.37.1) collapses whitespace in concatenated \`class\` attributes 7`] = ` +Program { + "blockParams": Array [], + "body": Array [ + ElementNode { + "attributes": Array [ + AttrNode { + "name": "class", + "value": ConcatStatement { + "parts": Array [ + MustacheStatement { + "escaped": true, + "hash": Hash { + "pairs": Array [], + }, + "params": Array [], + "path": PathExpression { + "data": true, + "original": "@foo", + "parts": Array [ + "foo", + ], + "this": false, + }, + }, + ], + }, + }, + ], + "blockParams": Array [], + "children": Array [], + "comments": Array [], + "modifiers": Array [], + "selfClosing": true, + "tag": "button", + }, + ], +} +`; + +exports[`HBS Minifier plugin (with @glimmer/syntax v0.37.1) collapses whitespace in concatenated \`class\` attributes 8`] = ` +"" +`; + +exports[`HBS Minifier plugin (with @glimmer/syntax v0.37.1) collapses whitespace in regular \`class\` attributes 1`] = ` +Program { + "blockParams": Array [], + "body": Array [ + ElementNode { + "attributes": Array [ + AttrNode { + "name": "class", + "value": TextNode { + "chars": "btn btn--primary btn--blue", + }, + }, + ], + "blockParams": Array [], + "children": Array [], + "comments": Array [], + "modifiers": Array [], + "selfClosing": true, + "tag": "button", + }, + ], +} +`; + +exports[`HBS Minifier plugin (with @glimmer/syntax v0.37.1) collapses whitespace in regular \`class\` attributes 2`] = ` +" + " `; exports[`HBS Minifier plugin (with @glimmer/syntax v0.37.1) collapses whitespace into single space character 1`] = ` @@ -1974,6 +2576,307 @@ exports[`HBS Minifier plugin (with @glimmer/syntax v0.37.1) strips leading and t {{foo}}" `; +exports[`HBS Minifier plugin collapses whitespace in concatenated \`class\` attributes 1`] = ` +Template { + "blockParams": Array [], + "body": Array [ + ElementNode { + "attributes": Array [ + AttrNode { + "name": "class", + "value": ConcatStatement { + "parts": Array [ + TextNode { + "chars": "btn ", + }, + MustacheStatement { + "escaped": true, + "hash": Hash { + "pairs": Array [], + }, + "params": Array [ + PathExpression { + "data": false, + "original": "this.isPrimary", + "parts": Array [ + "isPrimary", + ], + "this": true, + }, + StringLiteral { + "original": "btn--primary", + "value": "btn--primary", + }, + ], + "path": PathExpression { + "data": false, + "original": "if", + "parts": Array [ + "if", + ], + "this": false, + }, + }, + TextNode { + "chars": " ", + }, + MustacheStatement { + "escaped": true, + "hash": Hash { + "pairs": Array [], + }, + "params": Array [ + PathExpression { + "data": true, + "original": "@stretch", + "parts": Array [ + "stretch", + ], + "this": false, + }, + StringLiteral { + "original": "btn--stretch", + "value": "btn--stretch", + }, + ], + "path": PathExpression { + "data": false, + "original": "if", + "parts": Array [ + "if", + ], + "this": false, + }, + }, + ], + }, + }, + ], + "blockParams": Array [], + "children": Array [], + "comments": Array [], + "modifiers": Array [], + "selfClosing": true, + "tag": "button", + }, + ], +} +`; + +exports[`HBS Minifier plugin collapses whitespace in concatenated \`class\` attributes 2`] = ` +" + " +`; + +exports[`HBS Minifier plugin collapses whitespace in concatenated \`class\` attributes 3`] = ` +Template { + "blockParams": Array [], + "body": Array [ + ElementNode { + "attributes": Array [ + AttrNode { + "name": "class", + "value": ConcatStatement { + "parts": Array [ + TextNode { + "chars": "foo ", + }, + MustacheStatement { + "escaped": true, + "hash": Hash { + "pairs": Array [], + }, + "params": Array [], + "path": PathExpression { + "data": true, + "original": "@bar", + "parts": Array [ + "bar", + ], + "this": false, + }, + }, + TextNode { + "chars": " baz", + }, + ], + }, + }, + ], + "blockParams": Array [], + "children": Array [], + "comments": Array [], + "modifiers": Array [], + "selfClosing": true, + "tag": "button", + }, + ], +} +`; + +exports[`HBS Minifier plugin collapses whitespace in concatenated \`class\` attributes 4`] = ` +"" +`; + +exports[`HBS Minifier plugin collapses whitespace in concatenated \`class\` attributes 5`] = ` +Template { + "blockParams": Array [], + "body": Array [ + ElementNode { + "attributes": Array [ + AttrNode { + "name": "class", + "value": ConcatStatement { + "parts": Array [ + MustacheStatement { + "escaped": true, + "hash": Hash { + "pairs": Array [], + }, + "params": Array [], + "path": PathExpression { + "data": true, + "original": "@foo", + "parts": Array [ + "foo", + ], + "this": false, + }, + }, + TextNode { + "chars": " bar ", + }, + MustacheStatement { + "escaped": true, + "hash": Hash { + "pairs": Array [], + }, + "params": Array [], + "path": PathExpression { + "data": true, + "original": "@baz", + "parts": Array [ + "baz", + ], + "this": false, + }, + }, + ], + }, + }, + ], + "blockParams": Array [], + "children": Array [], + "comments": Array [], + "modifiers": Array [], + "selfClosing": true, + "tag": "button", + }, + ], +} +`; + +exports[`HBS Minifier plugin collapses whitespace in concatenated \`class\` attributes 6`] = ` +"" +`; + +exports[`HBS Minifier plugin collapses whitespace in concatenated \`class\` attributes 7`] = ` +Template { + "blockParams": Array [], + "body": Array [ + ElementNode { + "attributes": Array [ + AttrNode { + "name": "class", + "value": ConcatStatement { + "parts": Array [ + MustacheStatement { + "escaped": true, + "hash": Hash { + "pairs": Array [], + }, + "params": Array [], + "path": PathExpression { + "data": true, + "original": "@foo", + "parts": Array [ + "foo", + ], + "this": false, + }, + }, + ], + }, + }, + ], + "blockParams": Array [], + "children": Array [], + "comments": Array [], + "modifiers": Array [], + "selfClosing": true, + "tag": "button", + }, + ], +} +`; + +exports[`HBS Minifier plugin collapses whitespace in concatenated \`class\` attributes 8`] = ` +"" +`; + +exports[`HBS Minifier plugin collapses whitespace in regular \`class\` attributes 1`] = ` +Template { + "blockParams": Array [], + "body": Array [ + ElementNode { + "attributes": Array [ + AttrNode { + "name": "class", + "value": TextNode { + "chars": "btn btn--primary btn--blue", + }, + }, + ], + "blockParams": Array [], + "children": Array [], + "comments": Array [], + "modifiers": Array [], + "selfClosing": true, + "tag": "button", + }, + ], +} +`; + +exports[`HBS Minifier plugin collapses whitespace in regular \`class\` attributes 2`] = ` +" + " +`; + exports[`HBS Minifier plugin collapses whitespace into single space character 1`] = ` Template { "blockParams": Array [], diff --git a/hbs-minifier-plugin.js b/hbs-minifier-plugin.js index d1807e16..2bb725e7 100644 --- a/hbs-minifier-plugin.js +++ b/hbs-minifier-plugin.js @@ -32,6 +32,32 @@ function createGlimmerPlugin(config) { AttrNode: { enter(node) { skipStack.push(node); + + if (node.name === 'class') { + if (node.value.type === 'TextNode') { + node.value.chars = node.value.chars + .replace(leadingWhiteSpace, '') + .replace(trailingWhiteSpace, '') + .replace(/[ \t\r\n]+/g, ' '); + } else if (node.value.type === 'ConcatStatement') { + let { parts } = node.value; + + parts.forEach((part, i) => { + if (part.type === 'TextNode') { + let isFirst = i === 0; + let isLast = i === parts.length - 1; + + part.chars = part.chars + .replace(leadingWhiteSpace, isFirst ? '' : ' ') + .replace(trailingWhiteSpace, isLast ? '' : ' ') + .replace(/[ \t\r\n]+/g, ' '); + } + }); + + node.value.parts = node.value.parts + .filter(part => part.type !== 'TextNode' || part.chars !== ''); + } + } }, exit(node) { diff --git a/hbs-minifier-plugin.test.js b/hbs-minifier-plugin.test.js index 237b5836..a7648b50 100644 --- a/hbs-minifier-plugin.test.js +++ b/hbs-minifier-plugin.test.js @@ -164,6 +164,36 @@ for (let version of versions) { assert(`
`); }); + it('collapses whitespace in regular `class` attributes', function() { + assert(` +