Skip to content

Commit 32a4daf

Browse files
committed
correctly handle attributes with dots in names
1 parent d903da2 commit 32a4daf

File tree

2 files changed

+61
-15
lines changed

2 files changed

+61
-15
lines changed

src/nodes/html.ts

+17-15
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,11 @@ export default class HTMLElement extends Node {
159159
return 'null';
160160
}
161161

162-
return JSON.stringify(attr.replace(/"/g, '"')).replace(/\\t/g, '\t').replace(/\\n/g, '\n').replace(/\\r/g, '\r').replace(/\\/g, '');
162+
return JSON.stringify(attr.replace(/"/g, '"'))
163+
.replace(/\\t/g, '\t')
164+
.replace(/\\n/g, '\n')
165+
.replace(/\\r/g, '\r')
166+
.replace(/\\/g, '');
163167
}
164168

165169
/**
@@ -373,11 +377,7 @@ export default class HTMLElement extends Node {
373377
return child === this;
374378
});
375379
resetParent([this], null);
376-
parent.childNodes = [
377-
...parent.childNodes.slice(0, idx),
378-
...resetParent(content, parent),
379-
...parent.childNodes.slice(idx + 1),
380-
];
380+
parent.childNodes = [...parent.childNodes.slice(0, idx), ...resetParent(content, parent), ...parent.childNodes.slice(idx + 1)];
381381
return this;
382382
}
383383

@@ -456,10 +456,12 @@ export default class HTMLElement extends Node {
456456
this.childNodes.length = o;
457457

458458
// remove whitespace between attributes
459-
const attrs = Object.keys( this.rawAttributes).map((key) => {
460-
const val = this.rawAttributes[key];
461-
return `${key}=${ JSON.stringify(val)}`;
462-
}).join(' ');
459+
const attrs = Object.keys(this.rawAttributes)
460+
.map((key) => {
461+
const val = this.rawAttributes[key];
462+
return `${key}=${JSON.stringify(val)}`;
463+
})
464+
.join(' ');
463465
this.rawAttrs = attrs;
464466
delete this._rawAttrs;
465467
return this;
@@ -565,7 +567,7 @@ export default class HTMLElement extends Node {
565567
if (child.nodeType === NodeType.ELEMENT_NODE) {
566568
if (child.id === id) {
567569
return child;
568-
};
570+
}
569571

570572
// if children are existing push the current status to the stack and keep searching for elements in the level below
571573
if (child.childNodes.length > 0) {
@@ -686,7 +688,7 @@ export default class HTMLElement extends Node {
686688
}
687689
const attrs = {} as RawAttributes;
688690
if (this.rawAttrs) {
689-
const re = /([a-zA-Z()[\]#@$.?:][a-zA-Z0-9-_:()[\]#]*)(?:\s*=\s*((?:'[^']*')|(?:"[^"]*")|\S+))?/g;
691+
const re = /([a-zA-Z()\[\]#@$.?:][a-zA-Z0-9-._:()[\]#]*)(?:\s*=\s*((?:'[^']*')|(?:"[^"]*")|\S+))?/g;
690692
let match: RegExpExecArray;
691693
while ((match = re.exec(this.rawAttrs))) {
692694
const key = match[1];
@@ -1023,7 +1025,7 @@ export interface Options {
10231025
* void tag serialisation, add a final slash <br/>
10241026
*/
10251027
closingSlash?: boolean;
1026-
}
1028+
};
10271029
}
10281030

10291031
const frameflag = 'documentfragmentcontainer';
@@ -1109,7 +1111,7 @@ export function base_parse(data: string, options = {} as Partial<Options>) {
11091111
if (!leadingSlash) {
11101112
/* Populate attributes */
11111113
const attrs = {} as Record<string, string>;
1112-
for (let attMatch; (attMatch = kAttributePattern.exec(attributes));) {
1114+
for (let attMatch; (attMatch = kAttributePattern.exec(attributes)); ) {
11131115
const { 1: key, 2: val } = attMatch;
11141116
const isQuoted = val[0] === `'` || val[0] === `"`;
11151117
attrs[key.toLowerCase()] = isQuoted ? val.slice(1, val.length - 1) : val;
@@ -1247,7 +1249,7 @@ export function parse(data: string, options = {} as Partial<Options>) {
12471249
* and removes nodes from any potential parent.
12481250
*/
12491251
function resolveInsertable(insertable: NodeInsertable[]): Node[] {
1250-
return insertable.map(val => {
1252+
return insertable.map((val) => {
12511253
if (typeof val === 'string') {
12521254
return new TextNode(val);
12531255
}

test/tests/attributes-with-dots.js

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
const { parse } = require('@test/test-target');
2+
3+
describe('funky attributes', function () {
4+
it('x-transition.duration.500ms', function () {
5+
const root = parse('<div x-transition.duration.500ms></div>');
6+
const div = root.firstChild;
7+
div.getAttribute('x-transition.duration.500ms').should.eql('');
8+
div.toString().should.eql('<div x-transition.duration.500ms></div>');
9+
});
10+
11+
it('x-transition:enter.duration.500ms and x-transition:leave.duration.400ms', function () {
12+
const root = parse('<div x-transition:enter.duration.500ms x-transition:leave.duration.400ms></div>');
13+
const div = root.firstChild;
14+
div.getAttribute('x-transition:enter.duration.500ms').should.eql('');
15+
div.getAttribute('x-transition:leave.duration.400ms').should.eql('');
16+
div.toString().should.eql('<div x-transition:enter.duration.500ms x-transition:leave.duration.400ms></div>');
17+
});
18+
19+
it('@click="open = ! open"', function () {
20+
const root = parse('<button @click="open = ! open">Toggle</button>');
21+
const div = root.firstChild;
22+
div.getAttribute('@click').should.eql('open = ! open');
23+
div.toString().should.eql('<button @click="open = ! open">Toggle</button>');
24+
});
25+
26+
it('a bunch of stuff at the same time', function () {
27+
const root = parse(
28+
'<div x-show="open" x-transition:enter="transition ease-out duration-300" x-transition:enter-start="opacity-0 scale-90" x-transition:enter-end="opacity-100 scale-100" x-transition:leave="transition ease-in duration-300" x-transition:leave-start="opacity-100 scale-100" x-transition:leave-end="opacity-0 scale-90">Hello 👋</div>'
29+
);
30+
const div = root.firstChild;
31+
32+
div.getAttribute('x-show').should.eql('open');
33+
div.getAttribute('x-transition:enter').should.eql('transition ease-out duration-300');
34+
div.getAttribute('x-transition:enter-start').should.eql('opacity-0 scale-90');
35+
div.getAttribute('x-transition:enter-end').should.eql('opacity-100 scale-100');
36+
div.getAttribute('x-transition:leave').should.eql('transition ease-in duration-300');
37+
div.getAttribute('x-transition:leave-start').should.eql('opacity-100 scale-100');
38+
div.getAttribute('x-transition:leave-end').should.eql('opacity-0 scale-90');
39+
40+
div.toString().should.eql(
41+
'<div x-show="open" x-transition:enter="transition ease-out duration-300" x-transition:enter-start="opacity-0 scale-90" x-transition:enter-end="opacity-100 scale-100" x-transition:leave="transition ease-in duration-300" x-transition:leave-start="opacity-100 scale-100" x-transition:leave-end="opacity-0 scale-90">Hello 👋</div>'
42+
);
43+
});
44+
});

0 commit comments

Comments
 (0)