Skip to content

Commit 790771c

Browse files
committed
Allow slashes in prop values (unless followed by >)
1 parent 08fe9d0 commit 790771c

File tree

2 files changed

+22
-8
lines changed

2 files changed

+22
-8
lines changed

src/build.mjs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -73,22 +73,23 @@ export const treeify = (built, fields) => {
7373

7474
export const evaluate = (h, built, fields, args) => {
7575
for (let i = 1; i < built.length; i++) {
76-
const field = built[i++];
76+
const field = built[i];
7777
const value = typeof field === 'number' ? fields[field] : field;
78+
const type = built[++i];
7879

79-
if (built[i] === TAG_SET) {
80+
if (type === TAG_SET) {
8081
args[0] = value;
8182
}
82-
else if (built[i] === PROPS_ASSIGN) {
83+
else if (type === PROPS_ASSIGN) {
8384
args[1] = Object.assign(args[1] || {}, value);
8485
}
85-
else if (built[i] === PROP_SET) {
86+
else if (type === PROP_SET) {
8687
(args[1] = args[1] || {})[built[++i]] = value;
8788
}
88-
else if (built[i] === PROP_APPEND) {
89+
else if (type === PROP_APPEND) {
8990
args[1][built[++i]] += (value + '');
9091
}
91-
else if (built[i]) {
92+
else if (type) {
9293
// code === CHILD_RECURSE
9394
args.push(h.apply(null, evaluate(h, value, fields, ['', null])));
9495
}
@@ -178,7 +179,7 @@ export const build = function(statics) {
178179
commit(i);
179180
}
180181

181-
for (let j=0; j<statics[i].length; j++) {
182+
for (let j=0; j<statics[i].length;j++) {
182183
char = statics[i][j];
183184

184185
if (mode === MODE_TEXT) {
@@ -230,7 +231,7 @@ export const build = function(statics) {
230231
propName = buffer;
231232
buffer = '';
232233
}
233-
else if (char === '/') {
234+
else if (char === '/' && (mode < MODE_PROP_SET || statics[i][j+1] === '>')) {
234235
commit();
235236
if (mode === MODE_TAGNAME) {
236237
current = current[0];

test/index.test.mjs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,17 @@ describe('htm', () => {
7777
expect(html`<a href=${'foo'} />`).toEqual({ tag: 'a', props: { href: 'foo' }, children: [] });
7878
});
7979

80+
test('slash in the middle of tag name or property name self-closes the element', () => {
81+
expect(html`<ab/ba prop=value>`).toEqual({ tag: 'ab', props: null, children: [] });
82+
expect(html`<abba pr/op=value>`).toEqual({ tag: 'abba', props: { pr: true }, children: [] });
83+
});
84+
85+
test('slash in a property value does not self-closes the element, unless followed by >', () => {
86+
expect(html`<abba prop=val/ue><//>`).toEqual({ tag: 'abba', props: { prop: 'val/ue' }, children: [] });
87+
expect(html`<abba prop=value/>`).toEqual({ tag: 'abba', props: { prop: 'value' }, children: [] });
88+
expect(html`<abba prop=value/ ><//>`).toEqual({ tag: 'abba', props: { prop: 'value/' }, children: [] });
89+
});
90+
8091
test('two props with dynamic values', () => {
8192
function onClick(e) { }
8293
expect(html`<a href=${'foo'} onClick=${onClick} />`).toEqual({ tag: 'a', props: { href: 'foo', onClick }, children: [] });
@@ -86,6 +97,8 @@ describe('htm', () => {
8697
expect(html`<a href="before${'foo'}after" />`).toEqual({ tag: 'a', props: { href: 'beforefooafter' }, children: [] });
8798
expect(html`<a href=${1}${1} />`).toEqual({ tag: 'a', props: { href: '11' }, children: [] });
8899
expect(html`<a href=${1}between${1} />`).toEqual({ tag: 'a', props: { href: '1between1' }, children: [] });
100+
expect(html`<a href=/before/${'foo'}/after />`).toEqual({ tag: 'a', props: { href: '/before/foo/after' }, children: [] });
101+
expect(html`<a href=/before/${'foo'}/>`).toEqual({ tag: 'a', props: { href: '/before/foo' }, children: [] });
89102
});
90103

91104
test('spread props', () => {

0 commit comments

Comments
 (0)