diff --git a/README.md b/README.md index 0df2453..524329b 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,7 @@ const html = render(tree, options) |:--:|:--:|:-----:|:----------| |**[`singleTags`](#singletags)**|`{Array}`|`[]`|Specify custom single tags (self closing)| |**[`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.| ### `singleTags` @@ -166,6 +167,21 @@ const html = render(tree) ``` +### `quoteAllAttributes` + +Specify if all attributes should be quoted. + +##### `true (Default)` + +```html + +``` + +##### `false` + +```html + +``` [npm]: https://img.shields.io/npm/v/posthtml-render.svg [npm-url]: https://npmjs.com/package/posthtml-render diff --git a/lib/index.js b/lib/index.js index e31ef13..f959e17 100644 --- a/lib/index.js +++ b/lib/index.js @@ -22,22 +22,23 @@ var SINGLE_TAGS = [ 'extend' ] -/** - * Render PostHTML Tree to HTML +var ATTRIBUTE_QUOTES_REQUIRED = /[\t\n\f\r " '`=<>]/ + +/** Render PostHTML Tree to HTML * - * @param {Array|Object} tree PostHTML Tree - * @param {Object} options Options + * @param {Array|Object} tree PostHTML Tree @param {Object} options Options * * @return {String} HTML */ function render (tree, options) { - /** - * Options + /** Options * * @type {Object} * * @prop {Array} singleTags Custom single tags (selfClosing) - * @prop {String} closingSingleTag Closing format for single tag + * @prop {String} closingSingleTag Closing format for single tag @prop + * @prop {Boolean} quoteAllAttributes If all attributes should be quoted. + * Otherwise attributes will be unquoted when allowed. * * Formats: * @@ -51,6 +52,10 @@ function render (tree, options) { }) var closingSingleTag = options.closingSingleTag + var quoteAllAttributes = options.quoteAllAttributes + if (typeof quoteAllAttributes === 'undefined') { + quoteAllAttributes = true + } return html(tree) @@ -75,7 +80,11 @@ function render (tree, options) { for (var key in obj) { if (typeof obj[key] === 'string') { - attr += ' ' + key + '="' + obj[key].replace(/"/g, '"') + '"' + if (quoteAllAttributes || obj[key].match(ATTRIBUTE_QUOTES_REQUIRED)) { + attr += ' ' + key + '="' + obj[key].replace(/"/g, '"') + '"' + } else { + attr += ' ' + key + '=' + obj[key] + } } else if (obj[key] === true) { attr += ' ' + key } else if (typeof obj[key] === 'number') { diff --git a/test/render.test.js b/test/render.test.js index a3407a5..25153f7 100644 --- a/test/render.test.js +++ b/test/render.test.js @@ -289,5 +289,58 @@ describe('PostHTML Render', function () { expect(render(fixture, options)).to.eql(expected) }) }) + + describe('quoteAllAttributes', function () { + it('True', function () { + var options = { quoteAllAttributes: true } + + var fixture = { tag: 'a', attrs: { href: '/about/me/' } } + var expected = '' + + expect(render(fixture, options)).to.eql(expected) + }) + + it('False', function () { + var options = { quoteAllAttributes: false } + + var fixture = { tag: 'a', attrs: { href: '/about/me/' } } + var expected = '' + + expect(render(fixture, options)).to.eql(expected) + }) + + it('Required Space', function () { + var options = { quoteAllAttributes: false } + + var fixture = { 'tag': 'p', 'attrs': { 'id': 'asd adsasd' } } + var expected = '

' + + expect(render(fixture, options)).to.eql(expected) + }) + + it('Required Tab', function () { + var options = { quoteAllAttributes: false } + + var fixture = { tag: 'a', attrs: { href: '/about-\t-characters' } } + var expected = '' + + expect(render(fixture, options)).to.eql(expected) + }) + + it('Closing slash', function () { + var options = { + closingSingleTag: 'slash', + quoteAllAttributes: false + } + + // Note that is incorrect as that is parsed as + // . + + var fixture = { tag: 'area', attrs: { href: 'foobar' } } + var expected = '' + + expect(render(fixture, options)).to.eql(expected) + }) + }) }) })