support React 0.12 & React 0.10/0.11 syntax and dom elements

This commit is contained in:
avim 2014-12-04 14:40:54 +02:00
parent 39051d8c46
commit 13fffaa55d
7 changed files with 65 additions and 24 deletions

View File

@ -28,7 +28,6 @@
"escodegen": "^1.4.1",
"esprima": "^1.2.2",
"lodash": "^2.4.1",
"react": "^0.12.0",
"text-table": "^0.2.0"
},
"devDependencies": {
@ -39,6 +38,7 @@
"grunt-contrib-watch": "^0.6.1",
"grunt-eslint": "^2.1.0",
"grunt-node-tap": "^0.1.61",
"react": "^0.12.0",
"tape": "^3.0.2"
}
}

19
src/reactDOMSupport.js Normal file
View File

@ -0,0 +1,19 @@
/**
* Created by avim on 12/4/2014.
*/
var ver0_12_0 = ["a","abbr","address","area","article","aside","audio","b","base","bdi","bdo","big","blockquote","body","br","button","canvas","caption","cite","code","col","colgroup","data","datalist","dd","del","details","dfn","dialog","div","dl","dt","em","embed","fieldset","figcaption","figure","footer","form","h1","h2","h3","h4","h5","h6","head","header","hr","html","i","iframe","img","input","ins","kbd","keygen","label","legend","li","link","main","map","mark","menu","menuitem","meta","meter","nav","noscript","object","ol","optgroup","option","output","p","param","picture","pre","progress","q","rp","rt","ruby","s","samp","script","section","select","small","source","span","strong","style","sub","summary","sup","table","tbody","td","textarea","tfoot","th","thead","time","title","tr","track","u","ul","var","video","wbr","circle","defs","ellipse","g","line","linearGradient","mask","path","pattern","polygon","polyline","radialGradient","rect","stop","svg","text","tspan"];
var ver0_11_2 = ["a","abbr","address","area","article","aside","audio","b","base","bdi","bdo","big","blockquote","body","br","button","canvas","caption","cite","code","col","colgroup","data","datalist","dd","del","details","dfn","dialog","div","dl","dt","em","embed","fieldset","figcaption","figure","footer","form","h1","h2","h3","h4","h5","h6","head","header","hr","html","i","iframe","img","input","ins","kbd","keygen","label","legend","li","link","main","map","mark","menu","menuitem","meta","meter","nav","noscript","object","ol","optgroup","option","output","p","param","picture","pre","progress","q","rp","rt","ruby","s","samp","script","section","select","small","source","span","strong","style","sub","summary","sup","table","tbody","td","textarea","tfoot","th","thead","time","title","tr","track","u","ul","var","video","wbr","circle","defs","ellipse","g","line","linearGradient","mask","path","pattern","polygon","polyline","radialGradient","rect","stop","svg","text","tspan","injection"];
var ver0_11_0 = ["a","abbr","address","area","article","aside","audio","b","base","bdi","bdo","big","blockquote","body","br","button","canvas","caption","cite","code","col","colgroup","data","datalist","dd","del","details","dfn","div","dl","dt","em","embed","fieldset","figcaption","figure","footer","form","h1","h2","h3","h4","h5","h6","head","header","hr","html","i","iframe","img","input","ins","kbd","keygen","label","legend","li","link","main","map","mark","menu","menuitem","meta","meter","nav","noscript","object","ol","optgroup","option","output","p","param","pre","progress","q","rp","rt","ruby","s","samp","script","section","select","small","source","span","strong","style","sub","summary","sup","table","tbody","td","textarea","tfoot","th","thead","time","title","tr","track","u","ul","var","video","wbr","circle","defs","ellipse","g","line","linearGradient","mask","path","pattern","polygon","polyline","radialGradient","rect","stop","svg","text","tspan","injection"];
var ver0_10_0 = ["a","abbr","address","area","article","aside","audio","b","base","bdi","bdo","big","blockquote","body","br","button","canvas","caption","cite","code","col","colgroup","data","datalist","dd","del","details","dfn","div","dl","dt","em","embed","fieldset","figcaption","figure","footer","form","h1","h2","h3","h4","h5","h6","head","header","hr","html","i","iframe","img","input","ins","kbd","keygen","label","legend","li","link","main","map","mark","menu","menuitem","meta","meter","nav","noscript","object","ol","optgroup","option","output","p","param","pre","progress","q","rp","rt","ruby","s","samp","script","section","select","small","source","span","strong","style","sub","summary","sup","table","tbody","td","textarea","tfoot","th","thead","time","title","tr","track","u","ul","var","video","wbr","circle","defs","g","line","linearGradient","path","polygon","polyline","radialGradient","rect","stop","svg","text","injection"];
var versions = {
"0.12.1": ver0_12_0,
"0.12.0": ver0_12_0,
"0.11.2": ver0_11_2,
"0.11.1": ver0_11_0,
"0.11.0": ver0_11_0,
"0.10.0": ver0_10_0
};
module.exports = versions;

View File

@ -6,7 +6,7 @@ var cheerio = require('cheerio');
var _ = require('lodash');
var esprima = require('esprima');
var escodegen = require('escodegen');
var React = require('react/addons');
var reactDOMSupport = require('./reactDOMSupport');
var stringUtils = require('./stringUtils');
var repeatTemplate = _.template('_.map(<%= collection %>,<%= repeatFunction %>.bind(<%= repeatBinds %>))');
@ -15,6 +15,8 @@ var propsTemplate = _.template('_.merge({}, <%= generatedProps %>, <%= rtProps %
var classSetTemplate = _.template('React.addons.classSet(<%= classSet %>)');
var simpleTagTemplate = _.template('<%= name %>(<%= props %><%= children %>)');
var tagTemplate = _.template('<%= name %>.apply(this,_.flatten([<%= props %><%= children %>]))');
var simpleTagTemplateCreateElement = _.template('React.createElement(<%= name %>,<%= props %><%= children %>)');
var tagTemplateCreateElement = _.template('React.createElement.apply(this,_.flatten([<%= name %>,<%= props %><%= children %>]))');
var commentTemplate = _.template(' /* <%= data %> */ ');
var templateAMDTemplate = _.template("/*eslint new-cap:0,no-unused-vars:0*/\ndefine([<%= requirePaths %>], function (<%= requireNames %>) {\n'use strict';\n <%= injectedFunctions %>\nreturn function(){ return <%= body %>};\n});");
var templateCommonJSTemplate = _.template("<%= vars %>\n\n'use strict';\n <%= injectedFunctions %>\nmodule.exports = function(){ return <%= body %>};\n");
@ -25,6 +27,20 @@ var classSetProp = 'rt-class';
var scopeProp = 'rt-scope';
var propsProp = 'rt-props';
var defaultOptions = {commonJS: false, version: false, force: false, format: 'stylish', targetVersion: '0.12.1'};
function shouldUseCreateElement(context) {
switch(context.options.targetVersion) {
case "0.11.2":
case "0.11.1":
case "0.11.0":
case "0.10.0":
return false;
default:
return true;
}
}
var reactSupportedAttributes = ['accept', 'acceptCharset', 'accessKey', 'action', 'allowFullScreen', 'allowTransparency', 'alt', 'async', 'autoComplete', 'autoPlay', 'cellPadding', 'cellSpacing', 'charSet', 'checked', 'classID', 'className', 'cols', 'colSpan', 'content', 'contentEditable', 'contextMenu', 'controls', 'coords', 'crossOrigin', 'data', 'dateTime', 'defer', 'dir', 'disabled', 'download', 'draggable', 'encType', 'form', 'formNoValidate', 'frameBorder', 'height', 'hidden', 'href', 'hrefLang', 'htmlFor', 'httpEquiv', 'icon', 'id', 'label', 'lang', 'list', 'loop', 'manifest', 'max', 'maxLength', 'media', 'mediaGroup', 'method', 'min', 'multiple', 'muted', 'name', 'noValidate', 'open', 'pattern', 'placeholder', 'poster', 'preload', 'radioGroup', 'readOnly', 'rel', 'required', 'role', 'rows', 'rowSpan', 'sandbox', 'scope', 'scrolling', 'seamless', 'selected', 'shape', 'size', 'sizes', 'span', 'spellCheck', 'src', 'srcDoc', 'srcSet', 'start', 'step', 'style', 'tabIndex', 'target', 'title', 'type', 'useMap', 'value', 'width', 'wmode'];
var attributesMapping = {'class': 'className', 'rt-class': 'className'};
_.forEach(reactSupportedAttributes, function (attributeReactName) {
@ -210,15 +226,20 @@ function generateProps(node, context) {
}).join(',') + '}';
}
function convertTagNameToConstructor(tagName) {
return React.DOM.hasOwnProperty(tagName) ? 'React.DOM.' + tagName : tagName;
function convertTagNameToConstructor(tagName, context) {
var isHtmlTag = _.contains(reactDOMSupport[context.options.targetVersion], tagName);
if (shouldUseCreateElement(context)) {
return isHtmlTag ? "'"+tagName + "'": tagName;
}
return isHtmlTag ? 'React.DOM.' + tagName : tagName;
}
function defaultContext() {
function defaultContext(html,options) {
return {
boundParams: [],
injectedFunctions: [],
html: ''
html: html,
options: options
};
}
@ -233,10 +254,11 @@ function convertHtmlToReact(node, context) {
context = {
boundParams: _.clone(context.boundParams),
injectedFunctions: context.injectedFunctions,
html: context.html
html: context.html,
options: context.options
};
var data = {name: convertTagNameToConstructor(node.name)};
var data = {name: convertTagNameToConstructor(node.name, context)};
if (node.attribs[scopeProp]) {
data.scopeMapping = {};
data.scopeName = '';
@ -277,9 +299,9 @@ function convertHtmlToReact(node, context) {
}));
if (hasNonSimpleChildren(node)) {
data.body = tagTemplate(data);
data.body = shouldUseCreateElement(context)?tagTemplateCreateElement(data):tagTemplate(data);
} else {
data.body = simpleTagTemplate(data);
data.body = shouldUseCreateElement(context)?simpleTagTemplateCreateElement(data):simpleTagTemplate(data);
}
if (node.attribs[templateProp]) {
@ -331,11 +353,10 @@ function extractDefinesFromJSXTag(html, defines) {
*/
function convertTemplateToReact(html, options) {
var rootNode = cheerio.load(html, {lowerCaseTags: false, lowerCaseAttributeNames: false, xmlMode: true, withStartIndices: true});
options = options || {};
options = _.defaults({},options,defaultOptions);
var defines = {'react/addons': 'React', lodash: '_'};
html = extractDefinesFromJSXTag(html, defines);
var context = defaultContext();
context.html = html;
var context = defaultContext(html, options);
var rootTags = _.filter(rootNode.root()[0].children, function (i) { return i.type === 'tag'; });
if (!rootTags || rootTags.length === 0) {
throw new RTCodeError('Document should have a root element');

View File

@ -5,6 +5,6 @@ define([
], function (React, _) {
'use strict';
return function () {
return React.DOM.div({});
return React.createElement('div', {});
};
});

View File

@ -13,7 +13,7 @@ define([
return false;
}
function repeatItems3(items, itemsIndex) {
return React.DOM.div({}, React.DOM.span({
return React.createElement('div', {}, React.createElement('span', {
'style': {
width: 'auto',
lineHeight: '5px'
@ -23,7 +23,8 @@ define([
}, 'Mock'));
}
return function () {
return React.DOM.p.apply(this, _.flatten([
return React.createElement.apply(this, _.flatten([
'p',
{},
_.map(this.props.things, repeatItems3.bind(this))
]));

View File

@ -5,20 +5,20 @@ define([
], function (React, _) {
'use strict';
return function () {
return React.DOM.div({}, React.DOM.div({
return React.createElement('div', {}, React.createElement('div', {
'style': {
position: 'relative',
textAlign: 'center',
top: this.props.config.previewTop,
height: this.props.config.previewHeight
}
}, React.DOM.div({
}, React.createElement('div', {
'style': {
margin: 'auto',
height: '100%',
width: this.props.config.previewWidth || '100%'
}
}, React.DOM.iframe({
}, React.createElement('iframe', {
'id': 'preview',
'src': 'http://localhost/sites/412?ds=true',
'style': {
@ -26,6 +26,6 @@ define([
height: '100%',
border: '0'
}
}))), React.DOM.div({}, 'editor\n ', !this.props.editorState.previewMode ? React.DOM.div({}, 'left bar') : null));
}))), React.createElement('div', {}, 'editor\n ', !this.props.editorState.previewMode ? React.createElement('div', {}, 'left bar') : null));
};
});

View File

@ -4,7 +4,7 @@ var reactTemplates = require('../../src/reactTemplates');
var fs = require('fs');
var _ = require('lodash');
var path = require('path');
var React = require('react');
var React = require('react/addons');
var cheerio = require('cheerio');
var dataPath = path.resolve(__dirname, '..', 'data');
@ -19,7 +19,7 @@ test('invalid tests', function (t) {
function check(testFile) {
var filename = path.join(dataPath, testFile.file);
var html = fs.readFileSync(filename).toString();
var html = fs.readFileSync(filename).toString().replace(/\r/g, '').trim();
var error = null;
try {
reactTemplates.convertTemplateToReact(html);
@ -47,7 +47,7 @@ test('conversion test', function (t) {
function check(testFile) {
var filename = path.join(dataPath, testFile);
var html = fs.readFileSync(filename).toString();
var html = fs.readFileSync(filename).toString().replace(/\r/g, '').trim();
var expected = fs.readFileSync(filename + '.js').toString().replace(/\r/g, '').trim();
// var expected = fs.readFileSync(filename.replace(".html", ".js")).toString();
var actual = reactTemplates.convertTemplateToReact(html).replace(/\r/g, '').trim();
@ -77,7 +77,7 @@ test('html tests', function (t) {
var expected = fs.readFileSync(filename + '.html').toString().replace(/\r/g, '');
// var expected = fs.readFileSync(filename.replace(".html", ".js")).toString();
var code = reactTemplates.convertTemplateToReact(html).replace(/\r/g, '');
var defineMap = {react: React, lodash: _};
var defineMap = {"react/addons": React, lodash: _};
var define = function (requirementsNames, content) {
var requirements = _.map(requirementsNames, function (reqName) {
return defineMap[reqName];