Skip to content

Commit ea0e54c

Browse files
alexander-akaitjonathantneal
authored andcommitted
fix: parsing and stringify empty attribute value
1 parent 5b02220 commit ea0e54c

File tree

3 files changed

+20
-4
lines changed

3 files changed

+20
-4
lines changed

src/__tests__/attributes.js

+15
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,13 @@ test('namespace with escapes', '[\\31 \\#\\32 |href]', (t, tree) => {
6363
t.deepEqual(attr.raws.namespace, '\\31');
6464
});
6565

66+
test('attribute selector with a empty value', '[href=""]', (t, tree) => {
67+
t.deepEqual(tree.nodes[0].nodes[0].attribute, 'href');
68+
t.deepEqual(tree.nodes[0].nodes[0].operator, '=');
69+
t.deepEqual(tree.nodes[0].nodes[0].value, '');
70+
t.true(tree.nodes[0].nodes[0].quoted);
71+
});
72+
6673
test('attribute selector with a value', '[name=james]', (t, tree) => {
6774
t.deepEqual(tree.nodes[0].nodes[0].attribute, 'name');
6875
t.deepEqual(tree.nodes[0].nodes[0].operator, '=');
@@ -327,6 +334,14 @@ test('insensitive attribute selector 1', '[href="test" i]', (t, tree) => {
327334
t.deepEqual(tree.nodes[0].nodes[0].insensitive, true);
328335
});
329336

337+
test('insensitive attribute selector with a empty value', '[href="" i]', (t, tree) => {
338+
t.deepEqual(tree.nodes[0].nodes[0].attribute, 'href');
339+
t.deepEqual(tree.nodes[0].nodes[0].operator, '=');
340+
t.deepEqual(tree.nodes[0].nodes[0].value, '');
341+
t.deepEqual(tree.nodes[0].nodes[0].insensitive, true);
342+
t.true(tree.nodes[0].nodes[0].quoted);
343+
});
344+
330345
test('insensitive attribute selector 2', '[href=TEsT i ]', (t, tree) => {
331346
t.deepEqual(tree.nodes[0].nodes[0].value, 'TEsT');
332347
t.deepEqual(tree.nodes[0].nodes[0].insensitive, true);

src/parser.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ export default class Parser {
287287
node.raws.attribute += content;
288288
}
289289
lastAdded = 'attribute';
290-
} else if (!node.value || (lastAdded === "value" && !spaceAfterMeaningfulToken)) {
290+
} else if ((!node.value && node.value !== "") || (lastAdded === "value" && !spaceAfterMeaningfulToken)) {
291291
let unescaped = unesc(content);
292292
let oldRawValue = getProp(node, 'raws', 'value') || '';
293293
let oldValue = node.value || '';
@@ -300,7 +300,7 @@ export default class Parser {
300300
lastAdded = 'value';
301301
} else {
302302
let insensitive = (content === 'i' || content === "I");
303-
if (node.value && (node.quoteMark || spaceAfterMeaningfulToken)) {
303+
if ((node.value || node.value === '') && (node.quoteMark || spaceAfterMeaningfulToken)) {
304304
node.insensitive = insensitive;
305305
if (!insensitive || content === "I") {
306306
ensureObject(node, 'raws');
@@ -318,7 +318,7 @@ export default class Parser {
318318
node.raws.spaces.insensitive.before = commentBefore;
319319
commentBefore = '';
320320
}
321-
} else if (node.value) {
321+
} else if (node.value || node.value === '') {
322322
lastAdded = 'value';
323323
node.value += content;
324324
if (node.raws.value) {

src/selectors/attribute.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -372,14 +372,15 @@ export default class Attribute extends Namespace {
372372

373373
selector.push(this._stringFor('qualifiedAttribute', 'attribute'));
374374

375-
if (this.operator && this.value) {
375+
if (this.operator && (this.value || this.value === '')) {
376376
selector.push(this._stringFor('operator'));
377377
selector.push(this._stringFor('value'));
378378
selector.push(this._stringFor('insensitiveFlag', 'insensitive', (attrValue, attrSpaces) => {
379379
if (attrValue.length > 0
380380
&& !this.quoted
381381
&& attrSpaces.before.length === 0
382382
&& !(this.spaces.value && this.spaces.value.after)) {
383+
383384
attrSpaces.before = " ";
384385
}
385386
return defaultAttrConcat(attrValue, attrSpaces);

0 commit comments

Comments
 (0)