Skip to content

Commit fdd889c

Browse files
committed
Concatenate mixed static + dynamic attribute values
1 parent c5764b5 commit fdd889c

File tree

2 files changed

+42
-18
lines changed

2 files changed

+42
-18
lines changed

src/index.mjs

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,19 @@
1313

1414
import { MINI } from './constants.mjs';
1515

16-
const TAG_SET = 1;
17-
const PROPS_SET = 2;
18-
const PROPS_ASSIGN = 3;
19-
const CHILD_RECURSE = 4;
20-
const CHILD_APPEND = 0;
21-
2216
const MODE_SLASH = 0;
2317
const MODE_TEXT = 1;
2418
const MODE_WHITESPACE = 2;
2519
const MODE_TAGNAME = 3;
26-
const MODE_ATTRIBUTE = 4;
20+
const MODE_PROP_SET = 4;
21+
const MODE_PROP_APPEND = 5;
22+
23+
const TAG_SET = 1;
24+
const CHILD_APPEND = 0;
25+
const CHILD_RECURSE = 2;
26+
const PROPS_ASSIGN = 3;
27+
const PROP_SET = MODE_PROP_SET;
28+
const PROP_APPEND = MODE_PROP_APPEND;
2729

2830
const evaluate = (h, current, fields, args) => {
2931
for (let i = 1; i < current.length; i++) {
@@ -33,7 +35,10 @@ const evaluate = (h, current, fields, args) => {
3335
if (current[i] === TAG_SET) {
3436
args[0] = value;
3537
}
36-
else if (current[i] === PROPS_SET) {
38+
else if (current[i] === PROP_APPEND) {
39+
args[1][current[++i]] += (value + '');
40+
}
41+
else if (current[i] === PROP_SET) {
3742
(args[1] = args[1] || {})[current[++i]] = value;
3843
}
3944
else if (current[i] === PROPS_ASSIGN) {
@@ -93,17 +98,27 @@ const build = function(statics) {
9398
(current[2] = current[2] || {})[buffer] = true;
9499
}
95100
else {
96-
current.push(true, PROPS_SET, buffer);
101+
current.push(true, PROP_SET, buffer);
97102
}
98103
}
99-
else if (mode === MODE_ATTRIBUTE && propName) {
100-
if (MINI) {
101-
(current[2] = current[2] || {})[propName] = field ? fields[field] : buffer;
104+
else if (MINI && mode === MODE_PROP_SET) {
105+
(current[2] = current[2] || {})[propName] = field ? buffer ? (buffer + fields[field]) : fields[field] : buffer;
106+
mode = MODE_PROP_APPEND;
107+
}
108+
else if (MINI && mode == MODE_PROP_APPEND) {
109+
if (buffer || field) {
110+
current[2][propName] += field ? buffer + fields[field] : buffer;
102111
}
103-
else {
104-
current.push(field || buffer, PROPS_SET, propName);
112+
}
113+
else if (!MINI && mode >= MODE_PROP_SET) {
114+
if (buffer) {
115+
current.push(buffer, mode, propName);
116+
mode = MODE_PROP_APPEND;
117+
}
118+
if (field) {
119+
current.push(field, mode, propName);
105120
}
106-
propName = '';
121+
mode = MODE_PROP_APPEND;
107122
}
108123
buffer = '';
109124
};
@@ -154,9 +169,12 @@ const build = function(statics) {
154169
// Ignore everything until the tag ends
155170
}
156171
else if (char === '=') {
157-
mode = MODE_ATTRIBUTE;
172+
mode = MODE_PROP_SET;
158173
propName = buffer;
159174
buffer = '';
175+
if (!MINI) {
176+
current.push(buffer, mode, propName);
177+
}
160178
}
161179
else if (char === '/') {
162180
commit();

test/index.test.mjs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ describe('htm', () => {
5757
expect(html`<a href="" foo="" />`).toEqual({ tag: 'a', props: { href: '', foo: '' }, children: [] });
5858
});
5959

60+
test('single prop with empty name', () => {
61+
expect(html`<a ""="foo" />`).toEqual({ tag: 'a', props: { '': 'foo' }, children: [] });
62+
});
63+
6064
test('single prop with static value', () => {
6165
expect(html`<a href="/hello" />`).toEqual({ tag: 'a', props: { href: '/hello' }, children: [] });
6266
});
@@ -78,8 +82,10 @@ describe('htm', () => {
7882
expect(html`<a href=${'foo'} onClick=${onClick} />`).toEqual({ tag: 'a', props: { href: 'foo', onClick }, children: [] });
7983
});
8084

81-
test('prop with quoted dynamic value ignores static parts', () => {
82-
expect(html`<a href="before${'foo'}after" a="b" />`).toEqual({ tag: 'a', props: { href: 'foo', a: 'b' }, children: [] });
85+
test('prop with multiple static and dynamic values get concatenated as strings', () => {
86+
expect(html`<a href="before${'foo'}after" />`).toEqual({ tag: 'a', props: { href: 'beforefooafter' }, children: [] });
87+
expect(html`<a href=${1}${1} />`).toEqual({ tag: 'a', props: { href: '11' }, children: [] });
88+
expect(html`<a href=${1}between${1} />`).toEqual({ tag: 'a', props: { href: '1between1' }, children: [] });
8389
});
8490

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

0 commit comments

Comments
 (0)