Skip to content

Commit d354c61

Browse files
author
Sergii.Kliuchnyk
committed
instead comment with annotation, using string with annotation. More tests
1 parent 6f2855c commit d354c61

File tree

7 files changed

+103
-28
lines changed

7 files changed

+103
-28
lines changed

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,14 +110,15 @@ var MenuExample = React.createClass({
110110
style = 'focused';
111111
}
112112

113-
return /* @jsx-tpl item */;
113+
return "@jsx-tpl item";
114114
})
115115
}
116116
};
117117
}
118118
});
119119
```
120-
Lets call attribute with this unique id just like annotation
120+
Annotation not in comment because it is a value, not just some meta information.
121+
Lets call attribute with this unique id just like annotation.
121122
```html
122123
<div>
123124
<ul>

conv.js

Lines changed: 57 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@ var htmlParser = require('htmlparser2'),
55

66
module.exports = convert;
77

8-
var tplAnnotations = /\/\*+\s*@jsx\-tpl\s+([\w\-]+)\s*\*\//g,
8+
var tplAnnotations = /["']\s*@jsx\-tpl\s+([\w\-]+)\s*['"]/g,
99
tplAttr = 'jsx-tpl',
10-
renderAnnotations = /<!--\s*@render\s+([\w\-]+)\s*-->/g,
10+
renderAnnotation = /@render\s+([\w\-]+)/,
11+
renderAnnotationComments = /<!--\s*@render\s+([\w\-]+)\s*-->/g,
1112
spreadAttr = /jsx\-spread="([\$\w]+)"/g,
1213
renderReturnSelector =
1314
'call[callee.object.name="React"][callee.property.name="createClass"]'+
@@ -19,45 +20,55 @@ function convert(js, html, callback) {
1920
return callback(err);
2021
}
2122

22-
var templates = {};
23-
2423
prepareAttr(body);
2524

26-
domUtils.findAll(function (node) {
27-
return domUtils.hasAttrib(node, tplAttr);
28-
}, body.children).forEach(function (node) {
25+
removeComments(body);
26+
27+
var tplList = findNodesByAttr(body, tplAttr);
28+
29+
var templates = {};
30+
tplList.forEach(function (node) {
2931
var name = node.attribs[tplAttr];
3032
delete node.attribs[tplAttr];
31-
3233
templates[name] = clearAttrQuotes(domUtils.getOuterHTML(node));
33-
34-
domUtils.removeElement(node);
3534
});
3635

36+
removeNodes(tplList);
37+
3738
var _return = search(renderReturnSelector, js),
3839
_props = search(renderReturnSelector + ' > obj > prop', js),
3940
props = {};
4041

41-
_props.forEach(function (prop) {
42-
var name = prop.key.name,
43-
body = prop.value.body,
44-
value = js.slice(body.start, body.end);
42+
try {
43+
_props.forEach(function (prop) {
44+
var name = prop.key.name,
45+
body = prop.value.body,
46+
value = js.slice(body.start, body.end);
47+
48+
value = value.replace(tplAnnotations, function (x, name) {
49+
if (!templates.hasOwnProperty(name)) {
50+
throw new Error('JSX template "' + name + '" not exists');
51+
}
4552

46-
value = value.replace(tplAnnotations, function (x, name) {
47-
return format('(%s)', templates[name]);
48-
});
53+
return format('(%s)', templates[name]);
54+
});
4955

50-
props[name] = value;
51-
});
56+
props[name] = value;
57+
});
58+
}
59+
catch (e) {
60+
return callback(e);
61+
}
5262

5363
var template = clearAttrQuotes(domUtils.getOuterHTML(body));
5464

5565
try {
5666
template = template
57-
.replace(renderAnnotations, function (x, name) {
67+
.replace(renderAnnotationComments, function (x, name) {
5868
if (!props.hasOwnProperty(name)) {
59-
throw new Error('Template "' + name + '" not exists');
69+
throw new Error('Render template "' + name + '" not exists');
6070
}
71+
6172
return props[name];
6273
})
6374
;
@@ -69,8 +80,8 @@ function convert(js, html, callback) {
6980
if (_return.length === 0) {
7081
return callback(new Error('React.createClass return: option not found'));
7182
}
72-
else if (_return.length > 2) {
73-
return callback(new Error('More then one React.createClass return: option'));
83+
else if (_return.length > 1) {
84+
return callback(new Error('More then one React.createClass return: option found, should be only one'));
7485
}
7586
else {
7687
js = insert(js, _return[0].start, _return[0].end, format('return (%s);', template));
@@ -199,4 +210,27 @@ function clearAttrQuotes(html) {
199210
.replace(/="~~~\{/g, '={').replace(/}~~~"/g, '}')
200211
.replace(spreadAttr, '{...$1}')
201212
;
213+
}
214+
215+
function findNodesByAttr(body, attrName) {
216+
return domUtils.findAll(function (node) {
217+
return domUtils.hasAttrib(node, attrName);
218+
}, body.children);
219+
}
220+
221+
function removeNodes(nodeArray) {
222+
nodeArray.forEach(function (node) {
223+
domUtils.removeElement(node);
224+
});
225+
}
226+
227+
function removeComments(node) {
228+
if (node.type === 'comment' && !renderAnnotation.test(node.data)) {
229+
domUtils.removeElement(node);
230+
}
231+
else if (node.type === 'tag' && node.children) {
232+
for (var i = 0; i < node.children.length; i++) {
233+
removeComments(node.children[i]);
234+
}
235+
}
202236
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-st",
3-
"version": "0.6.4",
3+
"version": "0.7.0",
44
"description": "React separate template",
55
"main": "conv.js",
66
"dependencies": {

test/conv.js

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,50 @@ function file(path) {
77
}
88

99
describe('convert function', function () {
10+
var js = file('menu.js'),
11+
html = file('menu.html');
1012

1113
it ('should convert js + html to jsx', function (done) {
12-
conv(file('menu.js'), file('menu.html'), function (err, jsx) {
14+
conv(js, html, function (err, jsx) {
1315
expect(jsx).to.equal(file('menu.jsx'));
1416
done();
1517
});
1618
});
1719

20+
it ('should throw error: "Render not found"', function (done) {
21+
var badHtml = html.replace('@render list', '@render test');
22+
23+
conv(js, badHtml, function (err, jsx) {
24+
expect(err).not.to.be.null;
25+
done();
26+
});
27+
});
28+
29+
it ('should throw error: "JSX template not found"', function (done) {
30+
var badJs = js.replace('@jsx-tpl item', '@jsx-tpl test');
31+
32+
conv(badJs, html, function (err, jsx) {
33+
expect(err).not.to.be.null;
34+
done();
35+
});
36+
});
37+
38+
it ('should throw error: "Too many render:"', function (done) {
39+
var badJs = js + js;
40+
41+
conv(badJs, html, function (err, jsx) {
42+
expect(err).not.to.be.null;
43+
done();
44+
});
45+
});
46+
47+
it ('should throw error: "No render:"', function (done) {
48+
var badJs = js.replace('render:', 'list:');
49+
50+
conv(badJs, html, function (err, jsx) {
51+
expect(err).not.to.be.null;
52+
done();
53+
});
54+
});
55+
1856
});

test/menu.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<!-- Regular comment -->
22
<ul>
33
<!-- @render list -->
4+
<!-- inline comment -->
45
<Item jsx-tpl="item" class="item {style}" jsx-spread="attr" title="Item">{m}</Item>
56
</ul>

test/menu.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ var List = React.createClass({
1717

1818
var attr = {name: 'value'};
1919

20-
return /* @jsx-tpl item */;
20+
return "@jsx-tpl item";
2121
})
2222
},
2323
foo: function () {

test/menu.jsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ var List = React.createClass({
2121
})
2222
}
2323

24+
2425
</ul>);
2526
}
2627
});

0 commit comments

Comments
 (0)