Skip to content

Commit

Permalink
correctly handle attributes with dots in names
Browse files Browse the repository at this point in the history
  • Loading branch information
callmephilip committed Nov 14, 2024
1 parent d903da2 commit 32a4daf
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 15 deletions.
32 changes: 17 additions & 15 deletions src/nodes/html.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,11 @@ export default class HTMLElement extends Node {
return 'null';
}

return JSON.stringify(attr.replace(/"/g, '"')).replace(/\\t/g, '\t').replace(/\\n/g, '\n').replace(/\\r/g, '\r').replace(/\\/g, '');
return JSON.stringify(attr.replace(/"/g, '"'))
.replace(/\\t/g, '\t')
.replace(/\\n/g, '\n')
.replace(/\\r/g, '\r')
.replace(/\\/g, '');
}

/**
Expand Down Expand Up @@ -373,11 +377,7 @@ export default class HTMLElement extends Node {
return child === this;
});
resetParent([this], null);
parent.childNodes = [
...parent.childNodes.slice(0, idx),
...resetParent(content, parent),
...parent.childNodes.slice(idx + 1),
];
parent.childNodes = [...parent.childNodes.slice(0, idx), ...resetParent(content, parent), ...parent.childNodes.slice(idx + 1)];
return this;
}

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

// remove whitespace between attributes
const attrs = Object.keys( this.rawAttributes).map((key) => {
const val = this.rawAttributes[key];
return `${key}=${ JSON.stringify(val)}`;
}).join(' ');
const attrs = Object.keys(this.rawAttributes)
.map((key) => {
const val = this.rawAttributes[key];
return `${key}=${JSON.stringify(val)}`;
})
.join(' ');
this.rawAttrs = attrs;
delete this._rawAttrs;
return this;
Expand Down Expand Up @@ -565,7 +567,7 @@ export default class HTMLElement extends Node {
if (child.nodeType === NodeType.ELEMENT_NODE) {
if (child.id === id) {
return child;
};
}

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

const frameflag = 'documentfragmentcontainer';
Expand Down Expand Up @@ -1109,7 +1111,7 @@ export function base_parse(data: string, options = {} as Partial<Options>) {
if (!leadingSlash) {
/* Populate attributes */
const attrs = {} as Record<string, string>;
for (let attMatch; (attMatch = kAttributePattern.exec(attributes));) {
for (let attMatch; (attMatch = kAttributePattern.exec(attributes)); ) {
const { 1: key, 2: val } = attMatch;
const isQuoted = val[0] === `'` || val[0] === `"`;
attrs[key.toLowerCase()] = isQuoted ? val.slice(1, val.length - 1) : val;
Expand Down Expand Up @@ -1247,7 +1249,7 @@ export function parse(data: string, options = {} as Partial<Options>) {
* and removes nodes from any potential parent.
*/
function resolveInsertable(insertable: NodeInsertable[]): Node[] {
return insertable.map(val => {
return insertable.map((val) => {
if (typeof val === 'string') {
return new TextNode(val);
}
Expand Down
44 changes: 44 additions & 0 deletions test/tests/attributes-with-dots.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
const { parse } = require('@test/test-target');

describe('funky attributes', function () {
it('x-transition.duration.500ms', function () {
const root = parse('<div x-transition.duration.500ms></div>');
const div = root.firstChild;
div.getAttribute('x-transition.duration.500ms').should.eql('');
div.toString().should.eql('<div x-transition.duration.500ms></div>');
});

it('x-transition:enter.duration.500ms and x-transition:leave.duration.400ms', function () {
const root = parse('<div x-transition:enter.duration.500ms x-transition:leave.duration.400ms></div>');
const div = root.firstChild;
div.getAttribute('x-transition:enter.duration.500ms').should.eql('');
div.getAttribute('x-transition:leave.duration.400ms').should.eql('');
div.toString().should.eql('<div x-transition:enter.duration.500ms x-transition:leave.duration.400ms></div>');
});

it('@click="open = ! open"', function () {
const root = parse('<button @click="open = ! open">Toggle</button>');
const div = root.firstChild;
div.getAttribute('@click').should.eql('open = ! open');
div.toString().should.eql('<button @click="open = ! open">Toggle</button>');
});

it('a bunch of stuff at the same time', function () {
const root = parse(
'<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>'
);
const div = root.firstChild;

div.getAttribute('x-show').should.eql('open');
div.getAttribute('x-transition:enter').should.eql('transition ease-out duration-300');
div.getAttribute('x-transition:enter-start').should.eql('opacity-0 scale-90');
div.getAttribute('x-transition:enter-end').should.eql('opacity-100 scale-100');
div.getAttribute('x-transition:leave').should.eql('transition ease-in duration-300');
div.getAttribute('x-transition:leave-start').should.eql('opacity-100 scale-100');
div.getAttribute('x-transition:leave-end').should.eql('opacity-0 scale-90');

div.toString().should.eql(
'<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>'
);
});
});

0 comments on commit 32a4daf

Please # to comment.