Skip to content
This repository was archived by the owner on Aug 9, 2023. It is now read-only.

Commit a00267b

Browse files
committed
Remove broken coercion of prop values
...and add better tests Related to remarkjs/remark-react/issues/41.
1 parent cde0614 commit a00267b

File tree

3 files changed

+119
-57
lines changed

3 files changed

+119
-57
lines changed

index.js

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ function toH(h, node, ctx) {
118118
/* Add `name` and its `value` to `props`. */
119119
function addAttribute(props, name, value, ctx) {
120120
var info = information(name) || {};
121+
var subprop;
121122

122123
/* Ignore nully, `false`, `NaN`, and falsey known
123124
* booleans. */
@@ -133,28 +134,32 @@ function addAttribute(props, name, value, ctx) {
133134

134135
name = info.name || paramCase(name);
135136

136-
if (info.boolean) {
137-
/* Treat `true` and truthy known booleans. */
138-
value = '';
139-
} else if (typeof value === 'object' && 'length' in value) {
137+
if (value !== null && typeof value === 'object' && 'length' in value) {
140138
/* Accept `array`. Most props are space-separater. */
141139
value = (info.commaSeparated ? commas : spaces).stringify(value);
142140
}
143141

144-
value = String(value || '');
142+
/* Treat `true` and truthy known booleans. */
143+
if (info.boolean && ctx.hyperscript) {
144+
value = '';
145+
}
145146

146-
if (
147-
ctx.vdom &&
148-
info.name !== 'class' &&
149-
(info.mustUseAttribute || !info.name)
150-
) {
151-
if (!props.attributes) {
152-
props.attributes = {};
147+
if (info.name !== 'class' && (info.mustUseAttribute || !info.name)) {
148+
if (ctx.vdom) {
149+
subprop = 'attributes';
150+
} else if (ctx.hyperscript) {
151+
subprop = 'attrs';
153152
}
154153

155-
props.attributes[name] = value;
154+
if (subprop) {
155+
if (props[subprop] === undefined) {
156+
props[subprop] = {};
157+
}
156158

157-
return;
159+
props[subprop][name] = value;
160+
161+
return;
162+
}
158163
}
159164

160165
props[info.propertyName || name] = value;

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,17 @@
3333
},
3434
"devDependencies": {
3535
"browserify": "^14.0.0",
36-
"circular.js": "^2.0.3",
3736
"esmangle": "^1.0.0",
3837
"hyperscript": "^2.0.2",
3938
"nyc": "^10.0.0",
4039
"react": "^15.1.0",
40+
"react-dom": "^15.5.4",
41+
"rehype": "^4.0.0",
4142
"remark-cli": "^3.0.0",
4243
"remark-preset-wooorm": "^2.0.0",
4344
"tape": "^4.0.0",
4445
"unist-builder": "^1.0.1",
46+
"vdom-to-html": "^2.3.1",
4547
"virtual-dom": "^2.1.1",
4648
"xo": "^0.18.0"
4749
},

test.js

Lines changed: 97 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
'use strict';
22

3-
/* Dependencies. */
43
var test = require('tape');
54
var u = require('unist-builder');
65
var h = require('hyperscript');
76
var v = require('virtual-dom/h');
87
var r = require('react').createElement;
9-
var circular = require('circular.js');
10-
var toH = require('../hast-to-hyperscript/index.js');
8+
var rehype = require('rehype');
9+
var vToString = require('vdom-to-html');
10+
var rToString = require('react-dom/server').renderToStaticMarkup;
11+
var toH = require('./');
12+
13+
var processor = rehype().data('settings', {fragment: true, position: false});
1114

12-
/* Tests. */
1315
test('hast-to-hyperscript', function (t) {
1416
var hast;
1517

@@ -56,66 +58,120 @@ test('hast-to-hyperscript', function (t) {
5658
// Unknown props are dash-cased.
5759
// Unknown lists are space-separated.
5860
camelCase: ['on', 'off'],
61+
// Data properties.
62+
dataSome: 'yes',
63+
// ARIA props.
64+
ariaValuenow: '1'
65+
}
66+
}, [u('text', 'charlie')]),
67+
u('text', ' delta'),
68+
u('element', {
69+
tagName: 'input',
70+
properties: {
71+
type: 'file',
5972
// Known comma-separated lists:
6073
accept: ['.jpg', '.jpeg']
6174
}
62-
}, [u('text', 'charlie')]),
63-
u('text', ' delta')
75+
}, [])
6476
]);
6577

66-
t.deepEqual(
67-
clean(toH(h, hast)),
68-
clean(h('h1#a.b.c', {hidden: '', height: '2'}, [
78+
var doc = [
79+
'<h1',
80+
' id="a"',
81+
' class="b c"',
82+
' hidden',
83+
' height="2"',
84+
'>bravo ',
85+
'<strong',
86+
' style="color:red;"',
87+
' camel-case="on off"',
88+
' data-some="yes"',
89+
' aria-valuenow="1"',
90+
'>charlie</strong> ',
91+
'delta',
92+
'<input type="file" accept=".jpg, .jpeg">',
93+
'</h1>'
94+
].join('');
95+
96+
t.test('should support `hyperscript`', function (st) {
97+
var actual = toH(h, hast);
98+
var expected = h('h1#a.b.c', {hidden: '', attrs: {height: '2'}}, [
6999
'bravo ',
70100
h('strong', {
71101
style: {color: 'red'},
72-
'camel-case': 'on off',
73-
accept: '.jpg, .jpeg'
102+
'data-some': 'yes',
103+
attrs: {
104+
'camel-case': 'on off',
105+
'aria-valuenow': '1'
106+
}
74107
}, 'charlie'),
75-
' delta'
76-
])),
77-
'should support `hyperscript`'
78-
);
79-
80-
t.deepEqual(
81-
clean(toH(v, hast)),
82-
clean(v('h1#a.b.c', {
83-
key: 'h-1',
84-
attributes: {hidden: '', height: '2'}
85-
}, [
108+
' delta',
109+
h('input', {type: 'file', accept: '.jpg, .jpeg'})
110+
]);
111+
112+
st.deepEqual(html(actual.outerHTML), html(doc), 'equal output');
113+
st.deepEqual(html(expected.outerHTML), html(doc), 'equal output baseline');
114+
st.end();
115+
});
116+
117+
t.test('should support `virtual-dom/h`', function (st) {
118+
var baseline = doc.replace(/color:red;/, 'color: red');
119+
var actual = toH(v, hast);
120+
var expected = v('h1#a.b.c', {key: 'h-1', attributes: {hidden: true, height: 2}}, [
86121
'bravo ',
87122
v('strong', {
88123
key: 'h-2',
89-
accept: '.jpg, .jpeg',
90-
attributes: {style: 'color: red', 'camel-case': 'on off'}
124+
attributes: {
125+
'aria-valuenow': '1',
126+
'camel-case': 'on off',
127+
'data-some': 'yes',
128+
style: 'color: red'
129+
}
91130
}, 'charlie'),
92-
' delta'
93-
])),
94-
'should support `virtual-dom/h`'
95-
);
96-
97-
t.deepEqual(
98-
clean(toH(r, hast)),
99-
clean(r(
131+
' delta',
132+
v('input', {
133+
key: 'h-3',
134+
type: 'file',
135+
accept: '.jpg, .jpeg'
136+
})
137+
]);
138+
139+
st.deepEqual(html(vToString(actual)), html(baseline), 'equal output');
140+
st.deepEqual(html(vToString(expected)), html(baseline), 'equal output baseline');
141+
st.end();
142+
});
143+
144+
t.test('should support `React.createElement`', function (st) {
145+
var baseline = doc.replace(/ camel-case="on off"/, '');
146+
var actual = toH(r, hast);
147+
var expected = r(
100148
'h1',
101149
{
102150
key: 'h-1',
103151
id: 'a',
104152
className: 'b c',
105-
hidden: '',
153+
hidden: true,
106154
height: '2'
107155
},
108156
'bravo ',
109157
r('strong', {
110158
key: 'h-2',
111159
style: {color: 'red'},
112-
'camel-case': 'on off',
113-
accept: '.jpg, .jpeg'
160+
'aria-valuenow': '1',
161+
'data-some': 'yes'
114162
}, ['charlie']),
115-
' delta'
116-
)),
117-
'should support `React.createElement`'
118-
);
163+
' delta',
164+
r('input', {
165+
key: 'h-3',
166+
type: 'file',
167+
accept: '.jpg, .jpeg'
168+
})
169+
);
170+
171+
st.deepEqual(html(rToString(actual)), html(baseline), 'equal output');
172+
st.deepEqual(html(rToString(expected)), html(baseline), 'equal output baseline');
173+
st.end();
174+
});
119175

120176
t.test('should support keys', function (st) {
121177
st.equal(
@@ -179,7 +235,6 @@ test('hast-to-hyperscript', function (t) {
179235
t.end();
180236
});
181237

182-
/** Clean. */
183-
function clean(node) {
184-
return JSON.parse(JSON.stringify(node, circular()));
238+
function html(doc) {
239+
return processor.parse(doc);
185240
}

0 commit comments

Comments
 (0)