From 903300f7b9ce009f13ae7a46b47446d521156a1c Mon Sep 17 00:00:00 2001 From: SukkaW Date: Wed, 18 Nov 2020 11:34:24 +0800 Subject: [PATCH 1/4] feat: implement quoteStyle option --- lib/index.js | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/lib/index.js b/lib/index.js index 1b78caa..6cfcf14 100644 --- a/lib/index.js +++ b/lib/index.js @@ -59,12 +59,17 @@ function render(tree, options) { replaceQuote = true; } + let {quoteStyle} = options; + if (quoteStyle === undefined) { + quoteStyle = 2; + } + return html(tree); /** @private */ function isSingleTag(tag) { if (singleRegExp.length > 0) { - return singleRegExp.some(reg => reg.test(tag)) + return singleRegExp.some(reg => reg.test(tag)); } if (!singleTags.includes(tag)) { @@ -87,7 +92,7 @@ function render(tree, options) { attrValue = object[key].replace(/"/g, '"'); } - attr += ' ' + key + '="' + attrValue + '"'; + attr += makeAttr(key, attrValue, quoteStyle); } else if (object[key] === '') { attr += ' ' + key; } else { @@ -96,7 +101,7 @@ function render(tree, options) { } else if (object[key] === true) { attr += ' ' + key; } else if (typeof object[key] === 'number') { - attr += ' ' + key + '="' + object[key] + '"'; + attr += makeAttr(key, object[key], quoteStyle); } } @@ -112,6 +117,26 @@ function render(tree, options) { } } + /** @private */ + function makeAttr(key, attrValue, quoteStyle = 1) { + if (quoteStyle === 1) { + // Single Quote + return ` ${key}='${attrValue}'`; + } + + if (quoteStyle === 2) { + // Double Quote + return ` ${key}="${attrValue}"`; + } + + // Smart Quote + if (attrValue.includes('"')) { + return ` ${key}='${attrValue}'`; + } + + return ` ${key}="${attrValue}"`; + } + /** * HTML Stringifier * @@ -129,10 +154,10 @@ function render(tree, options) { traverse(tree, node => { // Undefined, null, '', [], NaN if (node === undefined || - node === null || - node === false || - node.length === 0 || - Number.isNaN(node)) { + node === null || + node === false || + node.length === 0 || + Number.isNaN(node)) { return; } From 18d31c020dd65501e3c2a0ba098fa79a93bf6cd7 Mon Sep 17 00:00:00 2001 From: SukkaW Date: Wed, 18 Nov 2020 11:42:09 +0800 Subject: [PATCH 2/4] test: quoteStyle option --- test/render.test.js | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/test/render.test.js b/test/render.test.js index c1324ef..c1bddec 100644 --- a/test/render.test.js +++ b/test/render.test.js @@ -371,5 +371,37 @@ describe('PostHTML Render', () => { expect(render(fixture, options)).to.eql(expected); }); }); + + describe('quoteStyle', () => { + it('1 - single quote', () => { + const options = {replaceQuote: false, quoteStyle: 1}; + + const fixture = {tag: 'img', attrs: {src: 'https://example.com/example.png', onload: 'testFunc("test")'}}; + const expected = ''; + + fs.writeFileSync('test.html', render(fixture, options)); + expect(render(fixture, options)).to.eql(expected); + }); + + it('2 - double quote', () => { + const options = {replaceQuote: false, quoteStyle: 2}; + + const fixture = {tag: 'img', attrs: {src: 'https://example.com/example.png', onload: 'testFunc("test")'}}; + const expected = ''; + + fs.writeFileSync('test.html', render(fixture, options)); + expect(render(fixture, options)).to.eql(expected); + }); + + it('0 - smart quote', () => { + const options = {replaceQuote: false, quoteStyle: 0}; + + const fixture = {tag: 'img', attrs: {src: 'https://example.com/example.png', onload: 'testFunc("test")'}}; + const expected = ''; + + fs.writeFileSync('test.html', render(fixture, options)); + expect(render(fixture, options)).to.eql(expected); + }); + }); }); }); From 38b2b0433bc138f91f42f3c2ef6ae41e55455010 Mon Sep 17 00:00:00 2001 From: SukkaW Date: Wed, 18 Nov 2020 11:49:51 +0800 Subject: [PATCH 3/4] docs: add quoteStyle option --- readme.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/readme.md b/readme.md index 936d6e0..23f7c56 100644 --- a/readme.md +++ b/readme.md @@ -89,6 +89,7 @@ const html = render(tree, options) |**[`closingSingleTag`](#closingSingleTag)**|`{String}`|[`>`](#default)|Specify the single tag closing format| |**[`quoteAllAttributes`](#quoteAllAttributes)**|`{Boolean}`|[`true`](#default)|Put double quotes around all tags, even when not necessary.| |**[`replaceQuote`](#replaceQuote)**|`{Boolean}`|[`true`](#default)|Replaces quotes in attribute values with `"e;`.| +|**[`quoteStyle`](#quoteStyle)**|`{0|1|2}`|[`2`](#default)|Specify the style of quote arround the attribute values| ### `singleTags` @@ -200,6 +201,33 @@ Replaces quotes in attribute values with `"e;`. "> ``` +### `quoteStyle` + +##### `2 (Default)` + +Attribute values are wrapped in double quotes: + +```html + +``` + +##### `1` + +Attribute values are wrapped in single quote: + +```html + +``` + +##### `0` + +Quote style is based on attribute values (an alternative for `replaceQuote` option): + +```html + +``` + + [npm]: https://img.shields.io/npm/v/posthtml-render.svg [npm-url]: https://npmjs.com/package/posthtml-render From 3ee8d58698787a782c01eca88da95e39c53bbeb4 Mon Sep 17 00:00:00 2001 From: SukkaW Date: Wed, 18 Nov 2020 11:53:42 +0800 Subject: [PATCH 4/4] feat: add type definition for quoteStyle --- lib/index.d.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lib/index.d.ts b/lib/index.d.ts index 18d4262..a7e8d74 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -24,6 +24,20 @@ declare namespace render { * @default true */ quoteAllAttributes: boolean; + + /** + * Quote style + * + * 0 - Smart quotes + * + * 1 - Single quotes + * + * 2 - double quotes + * + * + * @default 2 + */ + quoteStyle: 0 | 1 | 2 }; // PostHTML Tree