From 79b7f74e9685a8d9c71cc6322a691f5756b7080e Mon Sep 17 00:00:00 2001 From: evilebottnawi Date: Wed, 6 Mar 2019 19:11:22 +0300 Subject: [PATCH] fix: parsing and stringify empty attribute value --- src/__tests__/attributes.js | 15 +++++++++++++++ src/parser.js | 6 +++--- src/selectors/attribute.js | 3 ++- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/__tests__/attributes.js b/src/__tests__/attributes.js index 5d5b94c..59c28e7 100644 --- a/src/__tests__/attributes.js +++ b/src/__tests__/attributes.js @@ -63,6 +63,13 @@ test('namespace with escapes', '[\\31 \\#\\32 |href]', (t, tree) => { t.deepEqual(attr.raws.namespace, '\\31'); }); +test('attribute selector with a empty value', '[href=""]', (t, tree) => { + t.deepEqual(tree.nodes[0].nodes[0].attribute, 'href'); + t.deepEqual(tree.nodes[0].nodes[0].operator, '='); + t.deepEqual(tree.nodes[0].nodes[0].value, ''); + t.true(tree.nodes[0].nodes[0].quoted); +}); + test('attribute selector with a value', '[name=james]', (t, tree) => { t.deepEqual(tree.nodes[0].nodes[0].attribute, 'name'); t.deepEqual(tree.nodes[0].nodes[0].operator, '='); @@ -327,6 +334,14 @@ test('insensitive attribute selector 1', '[href="test" i]', (t, tree) => { t.deepEqual(tree.nodes[0].nodes[0].insensitive, true); }); +test('insensitive attribute selector with a empty value', '[href="" i]', (t, tree) => { + t.deepEqual(tree.nodes[0].nodes[0].attribute, 'href'); + t.deepEqual(tree.nodes[0].nodes[0].operator, '='); + t.deepEqual(tree.nodes[0].nodes[0].value, ''); + t.deepEqual(tree.nodes[0].nodes[0].insensitive, true); + t.true(tree.nodes[0].nodes[0].quoted); +}); + test('insensitive attribute selector 2', '[href=TEsT i ]', (t, tree) => { t.deepEqual(tree.nodes[0].nodes[0].value, 'TEsT'); t.deepEqual(tree.nodes[0].nodes[0].insensitive, true); diff --git a/src/parser.js b/src/parser.js index 5bfd799..cc7be3a 100644 --- a/src/parser.js +++ b/src/parser.js @@ -287,7 +287,7 @@ export default class Parser { node.raws.attribute += content; } lastAdded = 'attribute'; - } else if (!node.value || (lastAdded === "value" && !spaceAfterMeaningfulToken)) { + } else if ((!node.value && node.value !== "") || (lastAdded === "value" && !spaceAfterMeaningfulToken)) { let unescaped = unesc(content); let oldRawValue = getProp(node, 'raws', 'value') || ''; let oldValue = node.value || ''; @@ -300,7 +300,7 @@ export default class Parser { lastAdded = 'value'; } else { let insensitive = (content === 'i' || content === "I"); - if (node.value && (node.quoteMark || spaceAfterMeaningfulToken)) { + if ((node.value || node.value === '') && (node.quoteMark || spaceAfterMeaningfulToken)) { node.insensitive = insensitive; if (!insensitive || content === "I") { ensureObject(node, 'raws'); @@ -318,7 +318,7 @@ export default class Parser { node.raws.spaces.insensitive.before = commentBefore; commentBefore = ''; } - } else if (node.value) { + } else if (node.value || node.value === '') { lastAdded = 'value'; node.value += content; if (node.raws.value) { diff --git a/src/selectors/attribute.js b/src/selectors/attribute.js index 6f08ad4..0b29bd0 100644 --- a/src/selectors/attribute.js +++ b/src/selectors/attribute.js @@ -372,7 +372,7 @@ export default class Attribute extends Namespace { selector.push(this._stringFor('qualifiedAttribute', 'attribute')); - if (this.operator && this.value) { + if (this.operator && (this.value || this.value === '')) { selector.push(this._stringFor('operator')); selector.push(this._stringFor('value')); selector.push(this._stringFor('insensitiveFlag', 'insensitive', (attrValue, attrSpaces) => { @@ -380,6 +380,7 @@ export default class Attribute extends Namespace { && !this.quoted && attrSpaces.before.length === 0 && !(this.spaces.value && this.spaces.value.after)) { + attrSpaces.before = " "; } return defaultAttrConcat(attrValue, attrSpaces);