From df4bf05323ccf9bdda85325bd8431f9a0b134fcc Mon Sep 17 00:00:00 2001 From: Dhiaeddine SAIDI Date: Tue, 10 Jul 2018 10:44:52 +0100 Subject: [PATCH] Adding option to prevent tagnames from beeing lowercase. Example << Angular components html templates >> need to preserve the case of the components tags(selectors) --- src/format.js | 2 +- src/index.js | 3 ++- src/lexer.js | 8 ++++---- src/parser.js | 2 +- src/stringify.js | 7 ++++--- test/lexer.js | 10 +++++----- test/parser.js | 5 +++-- 7 files changed, 20 insertions(+), 17 deletions(-) diff --git a/src/format.js b/src/format.js index ffbb47b..118d8c4 100644 --- a/src/format.js +++ b/src/format.js @@ -20,7 +20,7 @@ export function format (nodes, options) { const outputNode = type === 'element' ? { type, - tagName: node.tagName.toLowerCase(), + tagName: options.tagNameToLowerCase ? node.tagName.toLowerCase() : node.tagName, attributes: formatAttributes(node.attributes), children: format(node.children, options) } diff --git a/src/index.js b/src/index.js index 0e4cc84..9f7f27f 100644 --- a/src/index.js +++ b/src/index.js @@ -14,7 +14,8 @@ export const parseDefaults = { closingTags, childlessTags, closingTagAncestorBreakers, - includePositions: false + includePositions: false, + tagNameToLowerCase: true } export function parse (str, options = parseDefaults) { diff --git a/src/lexer.js b/src/lexer.js index b0b39ac..3e7a36f 100644 --- a/src/lexer.js +++ b/src/lexer.js @@ -63,7 +63,7 @@ export function lex (state) { lexComment(state) } else { const tagName = lexTag(state) - const safeTag = tagName.toLowerCase() + const safeTag = state.options.tagNameToLowerCase ? tagName.toLowerCase() : tagName if (arrayIncludes(childlessTags, safeTag)) { lexSkipTag(tagName, state) } @@ -273,7 +273,7 @@ const push = [].push export function lexSkipTag (tagName, state) { const {str, position, tokens} = state - const safeTagName = tagName.toLowerCase() + const safeTagName = state.options.tagNameToLowerCase ? tagName.toLowerCase() : tagName const len = str.length let index = position.index while (index < len) { @@ -286,8 +286,8 @@ export function lexSkipTag (tagName, state) { const tagStartPosition = copyPosition(position) jumpPosition(tagStartPosition, str, nextTag) const tagState = {str, position: tagStartPosition, tokens: []} - const name = lexTag(tagState) - if (safeTagName !== name.toLowerCase()) { + const name = state.options.tagNameToLowerCase ? lexTag(tagState).toLowerCase() : lexTag(tagState) + if (safeTagName !== name) { index = tagState.position.index continue } diff --git a/src/parser.js b/src/parser.js index 1101719..07e0072 100644 --- a/src/parser.js +++ b/src/parser.js @@ -49,7 +49,7 @@ export function parse (state) { const tagToken = tokens[++cursor] cursor++ - const tagName = tagToken.content.toLowerCase() + const tagName = state.options.tagNameToLowerCase ? tagToken.content.toLowerCase() : tagToken.content if (token.close) { let index = stack.length let shouldRewind = false diff --git a/src/stringify.js b/src/stringify.js index b3a57de..086c617 100644 --- a/src/stringify.js +++ b/src/stringify.js @@ -21,10 +21,11 @@ export function toHTML (tree, options) { return `` } const {tagName, attributes, children} = node - const isSelfClosing = arrayIncludes(options.voidTags, tagName.toLowerCase()) + const safeTagName = options.tagNameToLowerCase ? tagName.toLowerCase() : tagName + const isSelfClosing = arrayIncludes(options.voidTags, safeTagName) return isSelfClosing - ? `<${tagName}${formatAttributes(attributes)}>` - : `<${tagName}${formatAttributes(attributes)}>${toHTML(children, options)}` + ? `<${safeTagName}${formatAttributes(attributes)}>` + : `<${safeTagName}${formatAttributes(attributes)}>${toHTML(children, options)}` }).join('') } diff --git a/test/lexer.js b/test/lexer.js index c990a26..8c4c04c 100644 --- a/test/lexer.js +++ b/test/lexer.js @@ -344,7 +344,7 @@ test('lexTagAttributes should handle incomplete attributes', t => { test('lexSkipTag should tokenize as text until the matching tag name', t => { const str = 'abcd

Test case

' const finish = str.indexOf('') - const state = {str, position: ps(10), tokens: []} + const state = {str, position: ps(10), tokens: [], options: {tagNameToLowerCase: false}} lexSkipTag('test', state) t.is(state.position.index, finish) t.deepEqual(state.tokens, [ @@ -358,7 +358,7 @@ test('lexSkipTag should tokenize as text until the matching tag name', t => { test('lexSkipTag should stop at the case-insensitive matching tag name', t => { const str = 'proving the point' const finish = str.indexOf('') - const state = {str, position: ps(6), tokens: []} + const state = {str, position: ps(6), tokens: [], options: {tagNameToLowerCase: true}} lexSkipTag('tEsT', state) t.is(state.position.index, finish) t.deepEqual(state.tokens, [ @@ -371,7 +371,7 @@ test('lexSkipTag should stop at the case-insensitive matching tag name', t => { test('lexSkipTag should auto-close if the end tag is not found', t => { const str = '' - const state = {str, position: ps(8), tokens: []} + const state = {str, position: ps(8), tokens: [], options: {tagNameToLowerCase: true}} lexSkipTag('script', state) t.is(state.position.index, str.length) t.deepEqual(state.tokens, [ @@ -394,7 +394,7 @@ test('lexSkipTag should handle finding a stray " { test('lexSkipTag should not add an empty inner text node', t => { const str = '' - const state = {str, position: ps(8), tokens: []} + const state = {str, position: ps(8), tokens: [], options: {tagNameToLowerCase: true}} lexSkipTag('script', state) t.is(state.position.index, str.length) t.deepEqual(state.tokens, [ diff --git a/test/parser.js b/test/parser.js index 6ceebde..b939a82 100644 --- a/test/parser.js +++ b/test/parser.js @@ -6,11 +6,12 @@ function ps (index) { return { index, line: 0, column: index } } -const lexerOptions = { childlessTags: [] } +const lexerOptions = { childlessTags: [], tagNameToLowerCase: true } const parserOptions = { voidTags: [], closingTags: [], - closingTagAncestorBreakers: {} + closingTagAncestorBreakers: {}, + tagNameToLowerCase: true } test('parser() should return nodes', t => {