From aadded4571f43d7aa5795233e1843976899131cc Mon Sep 17 00:00:00 2001 From: SukkaW Date: Wed, 15 Sep 2021 11:56:55 +0800 Subject: [PATCH 1/2] Feat: add new module normalizeAttributeValues --- lib/modules/normalizeAttributeValues.es6 | 61 ++++++++++++++++++++++++ lib/presets/safe.es6 | 1 + test/modules/normalizeAttributeValues.js | 14 ++++++ 3 files changed, 76 insertions(+) create mode 100644 lib/modules/normalizeAttributeValues.es6 create mode 100644 test/modules/normalizeAttributeValues.js diff --git a/lib/modules/normalizeAttributeValues.es6 b/lib/modules/normalizeAttributeValues.es6 new file mode 100644 index 0000000..2ebf80e --- /dev/null +++ b/lib/modules/normalizeAttributeValues.es6 @@ -0,0 +1,61 @@ +const caseInsensitiveAttributes = { + autocomplete: ['form'], + charset: ['meta', 'script'], + contenteditable: null, + crossorigin: ['audio', 'img', 'link', 'script', 'video'], + dir: null, + draggable: null, + dropzone: null, + formmethod: ['button', 'input'], + inputmode: ['input', 'textarea'], + kind: ['track'], + method: ['form'], + preload: ['audio', 'video'], + referrerpolicy: ['a', 'area', 'iframe', 'img', 'link'], + sandbox: ['iframe'], + spellcheck: null, + scope: ['th'], + shape: ['area'], + sizes: ['link'], + step: ['input'], + translate: null, + type: [ + 'a', + 'link', + 'button', + 'embed', + 'object', + 'script', + 'source', + 'style', + 'input', + 'menu', + 'menuitem' + ], + wrap: ['textarea'] +}; + +export default function normalizeAttributeValues(tree) { + tree.walk(node => { + if (!node.attrs) { + return node; + } + + Object.entries(node.attrs).forEach(([attrName, attrValue]) => { + const attrNameLower = attrName.toLowerCase(); + if ( + Object.hasOwnProperty.call(caseInsensitiveAttributes, attrNameLower) + && ( + caseInsensitiveAttributes[attrNameLower] === null + || caseInsensitiveAttributes[attrNameLower].includes(node.tag) + ) + ) { + node.attrs[attrName] = attrValue.toLowerCase(); + } + }); + + return node; + }); + + return tree; +} diff --git a/lib/presets/safe.es6 b/lib/presets/safe.es6 index 33704d6..50b6b78 100644 --- a/lib/presets/safe.es6 +++ b/lib/presets/safe.es6 @@ -34,6 +34,7 @@ export default { minifyConditionalComments: false, removeEmptyAttributes: true, removeRedundantAttributes: false, + normalizeAttributeValues: true, removeComments: 'safe', removeAttributeQuotes: false, sortAttributesWithLists: 'alphabetical', diff --git a/test/modules/normalizeAttributeValues.js b/test/modules/normalizeAttributeValues.js new file mode 100644 index 0000000..d99d2e9 --- /dev/null +++ b/test/modules/normalizeAttributeValues.js @@ -0,0 +1,14 @@ +import { init } from '../htmlnano'; +import safePreset from '../../lib/presets/safe'; + +describe('normalizeAttributeValues', () => { + const options = safePreset; + + it('default behavior', () => { + return init( + '
', + '
', + options + ); + }); +}); From 596dc7ada6f63eaa3a44756136b2862f4758c38a Mon Sep 17 00:00:00 2001 From: SukkaW Date: Wed, 15 Sep 2021 11:58:53 +0800 Subject: [PATCH 2/2] Docs: add normalizeAttributesValues --- docs/docs/050-modules.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/docs/docs/050-modules.md b/docs/docs/050-modules.md index 85c3904..01e9378 100644 --- a/docs/docs/050-modules.md +++ b/docs/docs/050-modules.md @@ -763,3 +763,24 @@ Due to [the limitation of PostHTML](https://github.com/posthtml/htmlnano/issues/ - `body` - `colgroup` - `tbody` + +### normalizeAttributeValues + +Normalize casing of attribute values. + +The module won't impact the plain-text size of the output. However it will improve the compression ratio of gzip/brotli used in HTTP compression. + +#### Example + +Source: + +```html +
+``` + +Minified: + +```html +
+``` +