diff --git a/README.md b/README.md index 4e7d07e..ef50635 100644 --- a/README.md +++ b/README.md @@ -44,9 +44,9 @@ http://plugins.jetbrains.com/plugin/7648 * [rt-scope](#rt-scope) * [rt-props](#rt-props) * [rt-class](#rt-class) - * [rt-import](#using-other-components-in-the-template) + * [rt-import](#rt-import) * ~~rt-require~~ (deprecated, use rt-import) - * [rt-template](#rt-template-and-defining-properties-template-functions) + * [rt-template](#rt-template) * [rt-include](#rt-include) * [styles](#styles) * [event handlers](#event-handlers) @@ -379,7 +379,7 @@ define([ ## stateless components Since React v0.14, [React allows defining a component as a pure function of its props](https://facebook.github.io/react/docs/reusable-components.html#stateless-functions). To enable creating a stateless component using react templates, add the `rt-stateless` attribute to the template's root element. -Using `rt-stateless` generates a stateless functional component instead of a render function. +Using `rt-stateless` generates a stateless functional component instead of a render function. The resulting function receives `props` and `context` parameters to be used in the template instead of `this.props`. ###### Sample: @@ -472,14 +472,17 @@ export default function () { ###### Compiled (AMD): ```javascript define('div', [ - 'react/addons', + 'react', 'lodash', 'module-name', 'module-name', 'module-name', 'module-name' -], function (React, _, member, alias2, alias3, alias4) { +], function (React, _, $2, $3, alias3, $5) { 'use strict'; + var member = $2.member; + var alias2 = $3.member; + var alias4 = $5.default; return function () { return React.createElement('div', {}); }; diff --git a/src/reactSupport.js b/src/reactSupport.js index bcc08f4..1ead764 100644 --- a/src/reactSupport.js +++ b/src/reactSupport.js @@ -34,17 +34,12 @@ _.forEach(reactSupportedAttributes, attributeReactName => { const htmlSelfClosingTags = ['area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr']; - -const templateAMDTemplate = _.template("define(<%= name ? '\"'+name + '\", ' : '' %>[<%= requirePaths %>], function (<%= requireNames %>) {\n'use strict';\n <%= injectedFunctions %>\nreturn function(<%= statelessParams %>){ return <%= body %>};\n});"); -const templateCommonJSTemplate = _.template("'use strict';\n<%= vars %>\n\n<%= injectedFunctions %>\nmodule.exports = function(<%= statelessParams %>){ return <%= body %>};\n"); -const templateES6Template = _.template('<%= vars %>\n\n<%= injectedFunctions %>\nexport default function(<%= statelessParams %>){ return <%= body %>}\n'); -const templatePJSTemplate = _.template(`var <%= name %> = function (<%= statelessParams %>) { -<%= injectedFunctions %> -return <%= body %> -}; -`); -const templateTypescriptTemplate = _.template('<%= vars %>\n\n<%= injectedFunctions %>\nvar fn = function() { return <%= body %> };\nexport = fn\n'); -const templateJSRTTemplate = _.template('(function () {\n <%= injectedFunctions %>\n return function(){\nreturn <%= body %>}}\n)()'); +const templateAMDTemplate = _.template("define(<%= name ? '\"'+name + '\", ' : '' %>[<%= requirePaths %>], function (<%= AMDArguments %>) {\n'use strict';\n<%= AMDSubstitutions %>return <%= renderFunction %>;\n});"); +const templateCommonJSTemplate = _.template("'use strict';\n<%= vars %>\nmodule.exports = <%= renderFunction %>;\n"); +const templateES6Template = _.template('<%= vars %>\nexport default <%= renderFunction %>\n'); +const templatePJSTemplate = _.template('var <%= name %> = <%= renderFunction %>'); +const templateTypescriptTemplate = _.template('<%= vars %>\nexport = <%= renderFunction %>;\n'); +const templateJSRTTemplate = _.template('<%= renderFunction %>'); const templates = { amd: templateAMDTemplate, @@ -60,7 +55,8 @@ const defaultCase = _.constant(true); const buildImportTypeScript = _.cond([ [isImportAsterisk, d => `import ${d.alias} = require('${d.moduleName}');`], - [defaultCase, d => `import ${d.alias} = require('${d.moduleName}').${d.member};`] + [_.matches({member: 'default'}), d => `import ${d.alias} from '${d.moduleName}';`], + [defaultCase, d => `import { ${d.member} as ${d.alias} } from '${d.moduleName}';`] ]); const buildImportES6 = _.cond([ diff --git a/src/reactTemplates.js b/src/reactTemplates.js index 6fec433..6772d6f 100644 --- a/src/reactTemplates.js +++ b/src/reactTemplates.js @@ -123,6 +123,9 @@ function generateTemplateProps(node, context) { if (!_.has(child.attribs, 'prop')) { throw RTCodeError.build(context, child, 'rt-template must have a prop attribute'); } + if (_.filter(child.children, {type: 'tag'}).length !== 1) { + throw RTCodeError.build(context, child, "'rt-template' should have a single non-text element as direct child"); + } const childTemplate = _.find(context.options.propTemplates, {prop: child.attribs.prop}) || {arguments: []}; templateProp = { @@ -225,9 +228,13 @@ function handleStyleProp(val, node, context) { .filter(i => _.includes(i, ':')) .map(i => { const pair = i.split(':'); - + const key = pair[0].trim(); + if (/\{|\}/g.test(key)) { + throw RTCodeError.build(context, node, 'style attribute keys cannot contain { } expressions'); + } const value = pair.slice(1).join(':').trim(); - return _.camelCase(pair[0].trim()) + ' : ' + utils.convertText(node, context, value.trim()); + const parsedKey = /(^-moz-)|(^-o-)|(^-webkit-)/ig.test(key) ? _.upperFirst(_.camelCase(key)) : _.camelCase(key); + return parsedKey + ' : ' + utils.convertText(node, context, value.trim()); }) .join(','); return `{${styleStr}}`; @@ -290,6 +297,10 @@ function convertHtmlToReact(node, context) { boundParams: _.clone(context.boundParams) }, context); + if (node.type === 'tag' && node.name === importAttr) { + throw RTCodeError.build(context, node, "'rt-import' must be a toplevel node"); + } + if (node.type === 'tag' && node.name === includeNode) { const srcFile = node.attribs[includeSrcAttr]; if (!srcFile) { @@ -391,7 +402,7 @@ function convertHtmlToReact(node, context) { // the scope variables are evaluated in context of the current iteration. if (node.attribs[repeatAttr]) { data.repeatFunction = generateInjectedFunc(context, 'repeat' + _.upperFirst(data.item), 'return ' + data.body); - data.repeatBinds = ['this'].concat(_.reject(context.boundParams, p => p === data.item || p === data.item + 'Index' || data.innerScope && p in data.innerScope.innerMapping)); + data.repeatBinds = ['this'].concat(_.reject(context.boundParams, p => p === data.item || p === data.index || data.innerScope && p in data.innerScope.innerMapping)); data.body = repeatTemplate(data); } if (node.attribs[ifAttr]) { @@ -399,7 +410,8 @@ function convertHtmlToReact(node, context) { } return data.body; } else if (node.type === 'comment') { - return commentTemplate(node); + const sanitizedComment = node.data.split('*/').join('* /'); + return commentTemplate({data: sanitizedComment}); } else if (node.type === 'text') { return node.data.trim() ? utils.convertText(node, context, node.data) : ''; } @@ -562,33 +574,44 @@ function convertRT(html, reportContext, options) { const context = defaultContext(html, options, reportContext); const body = parseAndConvertHtmlToReact(html, context); + const injectedFunctions = context.injectedFunctions.join('\n'); + const statelessParams = context.stateless ? 'props, context' : ''; + const renderFunction = `function(${statelessParams}) { ${injectedFunctions}return ${body} }`; const requirePaths = _.map(context.defines, d => `"${d.moduleName}"`).join(','); const requireNames = _.map(context.defines, d => `${d.alias}`).join(','); + const AMDArguments = _.map(context.defines, (d, i) => (d.member === '*' ? `${d.alias}` : `$${i}`)).join(','); //eslint-disable-line + const AMDSubstitutions = _.map(context.defines, (d, i) => (d.member === '*' ? null : `var ${d.alias} = $${i}.${d.member};`)).join('\n'); //eslint-disable-line const buildImport = reactSupport.buildImport[options.modules] || reactSupport.buildImport.commonjs; const requires = _.map(context.defines, buildImport).join('\n'); const header = options.flow ? '/* @flow */\n' : ''; const vars = header + requires; const data = { - body, - injectedFunctions: context.injectedFunctions.join('\n'), + renderFunction, requireNames, requirePaths, + AMDArguments, + AMDSubstitutions, vars, - name: options.name, - statelessParams: context.stateless ? 'props, context' : '' + name: options.name }; let code = templates[options.modules](data); if (options.modules !== 'typescript' && options.modules !== 'jsrt') { - code = parseJS(code); + code = parseJS(code, options); } return code; } -function parseJS(code) { +function parseJS(code, options) { try { let tree = esprima.parse(code, {range: true, tokens: true, comment: true, sourceType: 'module'}); - tree = escodegen.attachComments(tree, tree.comments, tree.tokens); + // fix for https://github.com/wix/react-templates/issues/157 + // do not include comments for es6 modules due to bug in dependency "escodegen" + // to be removed when https://github.com/estools/escodegen/issues/263 will be fixed + // remove also its test case "test/data/comment.rt.es6.js" + if (options.modules !== 'es6') { + tree = escodegen.attachComments(tree, tree.comments, tree.tokens); + } return escodegen.generate(tree, {comment: true}); } catch (e) { throw new RTCodeError(e.message, e.index, -1); @@ -601,7 +624,7 @@ function convertJSRTToJS(text, reportContext, options) { const templateMatcherJSRT = /<template>([^]*?)<\/template>/gm; const code = text.replace(templateMatcherJSRT, (template, html) => convertRT(html, reportContext, options).replace(/;$/, '')); - return parseJS(code); + return parseJS(code, options); } module.exports = { diff --git a/test/data/comment.rt b/test/data/comment.rt new file mode 100644 index 0000000..c46e980 --- /dev/null +++ b/test/data/comment.rt @@ -0,0 +1,6 @@ +<div> + <!-- this is a comment --> + <div>hello</div> + <!-- /* this is another comment */ --> + <div>hello</div> +</div> diff --git a/test/data/comment.rt.amd.js b/test/data/comment.rt.amd.js new file mode 100644 index 0000000..10930ae --- /dev/null +++ b/test/data/comment.rt.amd.js @@ -0,0 +1,9 @@ +define([ + 'react', + 'lodash' +], function (React, _) { + 'use strict'; + return function () { + return React.createElement('div', {} /* this is a comment */, React.createElement('div', {}, 'hello') /* /* this is another comment * / */, React.createElement('div', {}, 'hello')); + }; +}); \ No newline at end of file diff --git a/test/data/comment.rt.es6.js b/test/data/comment.rt.es6.js new file mode 100644 index 0000000..9754846 --- /dev/null +++ b/test/data/comment.rt.es6.js @@ -0,0 +1,5 @@ +import * as React from 'react'; +import * as _ from 'lodash'; +export default function () { + return React.createElement('div', {}, React.createElement('div', {}, 'hello'), React.createElement('div', {}, 'hello')); +} \ No newline at end of file diff --git a/test/data/div.rt.typescript.ts b/test/data/div.rt.typescript.ts index 0a81cf2..436ad5d 100644 --- a/test/data/div.rt.typescript.ts +++ b/test/data/div.rt.typescript.ts @@ -1,6 +1,4 @@ import React = require('react'); import _ = require('lodash'); +export = function() { return React.createElement('div',{}) }; - -var fn = function() { return React.createElement('div',{}) }; -export = fn diff --git a/test/data/if-with-scope/valid-if-scope.rt.js b/test/data/if-with-scope/valid-if-scope.rt.js index f4fa052..5e0666f 100644 --- a/test/data/if-with-scope/valid-if-scope.rt.js +++ b/test/data/if-with-scope/valid-if-scope.rt.js @@ -3,11 +3,11 @@ define([ 'lodash' ], function (React, _) { 'use strict'; - function scopeActiveUsers1() { - var activeUsers = this.activeUsers; - return React.createElement('div', { 'key': 'active-users' }, React.createElement('span', {}, 'some text')); - } return function () { + function scopeActiveUsers1() { + var activeUsers = this.activeUsers; + return React.createElement('div', { 'key': 'active-users' }, React.createElement('span', {}, 'some text')); + } return this.activeUsers ? scopeActiveUsers1.apply(this, []) : null; }; }); diff --git a/test/data/import.rt.amd.js b/test/data/import.rt.amd.js index c049d4a..5a7b69f 100644 --- a/test/data/import.rt.amd.js +++ b/test/data/import.rt.amd.js @@ -5,8 +5,11 @@ define('div', [ 'module-name', 'module-name', 'module-name' -], function (React, _, member, alias2, alias3, alias4) { +], function (React, _, $2, $3, alias3, $5) { 'use strict'; + var member = $2.member; + var alias2 = $3.member; + var alias4 = $5.default; return function () { return React.createElement('div', {}); }; diff --git a/test/data/import.rt.typescript.ts b/test/data/import.rt.typescript.ts index 68bb063..ad39a5e 100644 --- a/test/data/import.rt.typescript.ts +++ b/test/data/import.rt.typescript.ts @@ -1,10 +1,8 @@ import React = require('react'); import _ = require('lodash'); -import member = require('module-name').member; -import alias2 = require('module-name').member; +import { member as member } from 'module-name'; +import { member as alias2 } from 'module-name'; import alias3 = require('module-name'); -import alias4 = require('module-name').default; +import alias4 from 'module-name'; +export = function() { return React.createElement('div',{}) }; - -var fn = function() { return React.createElement('div',{}) }; -export = fn diff --git a/test/data/invalid/invalid-rt-import-4.rt b/test/data/invalid/invalid-rt-import-4.rt new file mode 100644 index 0000000..f51dcfb --- /dev/null +++ b/test/data/invalid/invalid-rt-import-4.rt @@ -0,0 +1,3 @@ +<div> + <rt-import name="*" as="React" from="react"/> +</div> diff --git a/test/data/invalid/invalid-rt-template-1.rt b/test/data/invalid/invalid-rt-template-1.rt new file mode 100644 index 0000000..857d109 --- /dev/null +++ b/test/data/invalid/invalid-rt-template-1.rt @@ -0,0 +1,5 @@ +<div> + <rt-template prop="some"> + text children are not allowed + </rt-template> +</div> diff --git a/test/data/invalid/invalid-rt-template-2.rt b/test/data/invalid/invalid-rt-template-2.rt new file mode 100644 index 0000000..d0e8d82 --- /dev/null +++ b/test/data/invalid/invalid-rt-template-2.rt @@ -0,0 +1,6 @@ +<div> + <rt-template prop="some"> + <div>1</div> + <div>2</div> + </rt-template> +</div> diff --git a/test/data/invalid/invalid-style.rt b/test/data/invalid/invalid-style-1.rt similarity index 100% rename from test/data/invalid/invalid-style.rt rename to test/data/invalid/invalid-style-1.rt diff --git a/test/data/invalid/invalid-style-2.rt b/test/data/invalid/invalid-style-2.rt new file mode 100644 index 0000000..b4cda6c --- /dev/null +++ b/test/data/invalid/invalid-style-2.rt @@ -0,0 +1,3 @@ +<div rt-scope="'ground' as g"> + <span style="back{g}:red"></span> +</div> \ No newline at end of file diff --git a/test/data/invalid/invalid-style-2.rt.js b/test/data/invalid/invalid-style-2.rt.js new file mode 100644 index 0000000..dcd5685 --- /dev/null +++ b/test/data/invalid/invalid-style-2.rt.js @@ -0,0 +1,13 @@ +define([ + 'react', + 'lodash' +], function (React, _) { + 'use strict'; + return function () { + function scopeG1() { + var g = 'ground'; + return React.createElement('div', {}, React.createElement('span', { 'style': { backG: 'red' } })); + } + return scopeG1.apply(this, []); + }; +}); \ No newline at end of file diff --git a/test/data/native/listViewAndCustomTemplate.rt.js b/test/data/native/listViewAndCustomTemplate.rt.js index 397f356..1fb714d 100644 --- a/test/data/native/listViewAndCustomTemplate.rt.js +++ b/test/data/native/listViewAndCustomTemplate.rt.js @@ -1,13 +1,13 @@ 'use strict'; var React = require('react-native'); var _ = require('lodash'); -function renderRow1(rowData) { - return React.createElement(React.Text, {}, rowData); -} -function renderRow2(item) { - return React.createElement(React.Text, {}, item); -} module.exports = function () { + function renderRow1(rowData) { + return React.createElement(React.Text, {}, rowData); + } + function renderRow2(item) { + return React.createElement(React.Text, {}, item); + } return React.createElement(React.View, {}, React.createElement(React.ListView, { 'dataSource': this.state.dataSource, 'renderRow': renderRow1.bind(this) diff --git a/test/data/native/listViewTemplate.rt.js b/test/data/native/listViewTemplate.rt.js index 37c7c7b..037dff5 100644 --- a/test/data/native/listViewTemplate.rt.js +++ b/test/data/native/listViewTemplate.rt.js @@ -1,10 +1,10 @@ 'use strict'; var React = require('react-native'); var _ = require('lodash'); -function renderRow1(rowData) { - return React.createElement(React.Text, {}, rowData); -} module.exports = function () { + function renderRow1(rowData) { + return React.createElement(React.Text, {}, rowData); + } return React.createElement(React.View, {}, React.createElement(React.ListView, { 'dataSource': this.state.dataSource, 'renderRow': renderRow1.bind(this) diff --git a/test/data/propTemplates/implicitTemplate.rt.js b/test/data/propTemplates/implicitTemplate.rt.js index 1d32a9e..bf6b317 100644 --- a/test/data/propTemplates/implicitTemplate.rt.js +++ b/test/data/propTemplates/implicitTemplate.rt.js @@ -3,10 +3,10 @@ define([ 'lodash' ], function (React, _) { 'use strict'; - function renderRow1(rowData) { - return React.createElement('div', {}, rowData); - } return function () { + function renderRow1(rowData) { + return React.createElement('div', {}, rowData); + } return React.createElement('div', {}, React.createElement(List, { 'data': [ 1, diff --git a/test/data/propTemplates/simpleTemplate.rt.js b/test/data/propTemplates/simpleTemplate.rt.js index 2299438..5eb19be 100644 --- a/test/data/propTemplates/simpleTemplate.rt.js +++ b/test/data/propTemplates/simpleTemplate.rt.js @@ -3,10 +3,10 @@ define([ 'lodash' ], function (React, _) { 'use strict'; - function templateProp1(arg1) { - return React.createElement('div', {}, arg1); - } return function () { + function templateProp1(arg1) { + return React.createElement('div', {}, arg1); + } return React.createElement('div', { 'templateProp': templateProp1.bind(this) }); }; }); diff --git a/test/data/propTemplates/templateInScope.rt.js b/test/data/propTemplates/templateInScope.rt.js index 5474f7c..bad8843 100644 --- a/test/data/propTemplates/templateInScope.rt.js +++ b/test/data/propTemplates/templateInScope.rt.js @@ -3,14 +3,14 @@ define([ 'lodash' ], function (React, _) { 'use strict'; - function templateProp1(name, arg1) { - return React.createElement('div', {}, 'Name: ', name, ' ', arg1); - } - function scopeName2() { - var name = 'boten'; - return React.createElement('div', { 'templateProp': templateProp1.bind(this, name) }); - } return function () { + function templateProp1(name, arg1) { + return React.createElement('div', {}, 'Name: ', name, ' ', arg1); + } + function scopeName2() { + var name = 'boten'; + return React.createElement('div', { 'templateProp': templateProp1.bind(this, name) }); + } return scopeName2.apply(this, []); }; }); diff --git a/test/data/propTemplates/twoTemplates.rt.js b/test/data/propTemplates/twoTemplates.rt.js index 6c2a457..1b3bf14 100644 --- a/test/data/propTemplates/twoTemplates.rt.js +++ b/test/data/propTemplates/twoTemplates.rt.js @@ -3,13 +3,13 @@ define([ 'lodash' ], function (React, _) { 'use strict'; - function templateProp21(arg1, inner1, inner2) { - return React.createElement('div', {}, arg1 + inner1 + inner2); - } - function templateProp2(arg1) { - return React.createElement('div', { 'templateProp2': templateProp21.bind(this, arg1) }, React.createElement('div', {}, arg1)); - } return function () { + function templateProp21(arg1, inner1, inner2) { + return React.createElement('div', {}, arg1 + inner1 + inner2); + } + function templateProp2(arg1) { + return React.createElement('div', { 'templateProp2': templateProp21.bind(this, arg1) }, React.createElement('div', {}, arg1)); + } return React.createElement('div', { 'templateProp': templateProp2.bind(this) }); }; }); diff --git a/test/data/repeat-with-index.rt.js b/test/data/repeat-with-index.rt.js index a18eb2e..6080681 100644 --- a/test/data/repeat-with-index.rt.js +++ b/test/data/repeat-with-index.rt.js @@ -3,14 +3,14 @@ define([ 'lodash' ], function (React, _) { 'use strict'; - function repeatItem1(item, customIndex) { - return React.createElement('li', {}, item, ' is number ', customIndex); - } return function () { + function repeatItem1(item, customIndex) { + return React.createElement('li', {}, item, ' is number ', customIndex); + } return React.createElement.apply(this, [ 'ul', {}, - _.map(this.props.collection, repeatItem1.bind(this, customIndex)) + _.map(this.props.collection, repeatItem1.bind(this)) ]); }; }); diff --git a/test/data/repeat.rt.js b/test/data/repeat.rt.js index 5ed9875..11ed109 100644 --- a/test/data/repeat.rt.js +++ b/test/data/repeat.rt.js @@ -3,25 +3,25 @@ define([ 'lodash' ], function (React, _) { 'use strict'; - function onClick1(items, itemsIndex, evt) { - this.happend(evt); - return false; - } - function onMouseDown2(items, itemsIndex) { - this.happend(); - return false; - } - function repeatItems3(items, itemsIndex) { - return React.createElement('div', {}, React.createElement('span', { - 'style': { - width: 'auto', - lineHeight: '5px' - }, - 'onClick': onClick1.bind(this, items, itemsIndex), - 'onMouseDown': onMouseDown2.bind(this, items, itemsIndex) - }, 'Mock')); - } return function () { + function onClick1(items, itemsIndex, evt) { + this.happend(evt); + return false; + } + function onMouseDown2(items, itemsIndex) { + this.happend(); + return false; + } + function repeatItems3(items, itemsIndex) { + return React.createElement('div', {}, React.createElement('span', { + 'style': { + width: 'auto', + lineHeight: '5px' + }, + 'onClick': onClick1.bind(this, items, itemsIndex), + 'onMouseDown': onMouseDown2.bind(this, items, itemsIndex) + }, 'Mock')); + } return React.createElement.apply(this, [ 'p', {}, diff --git a/test/data/require.rt.typescript.ts b/test/data/require.rt.typescript.ts index ade57b0..ba3e6d8 100644 --- a/test/data/require.rt.typescript.ts +++ b/test/data/require.rt.typescript.ts @@ -2,7 +2,5 @@ import React = require('react'); import _ = require('lodash'); import myComp = require('comps/myComp'); import utils = require('utils/utils'); +export = function() { return React.createElement(myComp,{},"\n",(utils.translate('Hello','es')),"\n") }; - -var fn = function() { return React.createElement(myComp,{},"\n",(utils.translate('Hello','es')),"\n") }; -export = fn diff --git a/test/data/simple.js b/test/data/simple.js index 1c3af57..a3a9475 100644 --- a/test/data/simple.js +++ b/test/data/simple.js @@ -4,10 +4,8 @@ define([ ], function (React, _) { var comp = React.createClass({ render: function () { - return function () { - return React.createElement('div', {}, 'hello world'); - }; - }() + return React.createElement('div', {}, 'hello world'); + } }); return comp; }); \ No newline at end of file diff --git a/test/data/style-vendor-prefix.rt b/test/data/style-vendor-prefix.rt new file mode 100644 index 0000000..299b21e --- /dev/null +++ b/test/data/style-vendor-prefix.rt @@ -0,0 +1,4 @@ +<div> + <span style="-moz-transform:2;-ms-transform:2;-o-transform:2;-webkit-transform:2;transform:2"></span> + <span style="-Moz-transform:2;-Ms-transform:2;-O-transform:2;-Webkit-transform:2;Transform:2"></span> +</div> \ No newline at end of file diff --git a/test/data/style-vendor-prefix.rt.js b/test/data/style-vendor-prefix.rt.js new file mode 100644 index 0000000..9b214ae --- /dev/null +++ b/test/data/style-vendor-prefix.rt.js @@ -0,0 +1,25 @@ +define([ + 'react', + 'lodash' +], function (React, _) { + 'use strict'; + return function () { + return React.createElement('div', {}, React.createElement('span', { + 'style': { + MozTransform: '2', + msTransform: '2', + OTransform: '2', + WebkitTransform: '2', + transform: '2' + } + }), React.createElement('span', { + 'style': { + MozTransform: '2', + msTransform: '2', + OTransform: '2', + WebkitTransform: '2', + transform: '2' + } + })); + }; +}); \ No newline at end of file diff --git a/test/data/virtual.rt.js b/test/data/virtual.rt.js index 8ddb654..b7e4e3e 100644 --- a/test/data/virtual.rt.js +++ b/test/data/virtual.rt.js @@ -3,24 +3,24 @@ define([ 'lodash' ], function (React, _) { 'use strict'; - function repeatN1(verb, n, nIndex) { - return [ - React.createElement('div', { 'key': '2211' }, verb, ' ', n, '-a'), - React.createElement('div', { 'key': '2213' }, verb, ' ', n, '-b') - ]; - } - function scopeVerb2() { - var verb = 'rendered'; - return [ - 1 < 0 ? [React.createElement('div', { 'key': '551' }, 'this is not ', verb)] : null, - 1 > 0 ? [React.createElement('div', { 'key': '1401' }, 'this is ', verb)] : null, - _.map([ - 1, - 2 - ], repeatN1.bind(this, verb)) - ]; - } return function () { + function repeatN1(verb, n, nIndex) { + return [ + React.createElement('div', { 'key': '2211' }, verb, ' ', n, '-a'), + React.createElement('div', { 'key': '2213' }, verb, ' ', n, '-b') + ]; + } + function scopeVerb2() { + var verb = 'rendered'; + return [ + 1 < 0 ? [React.createElement('div', { 'key': '551' }, 'this is not ', verb)] : null, + 1 > 0 ? [React.createElement('div', { 'key': '1401' }, 'this is ', verb)] : null, + _.map([ + 1, + 2 + ], repeatN1.bind(this, verb)) + ]; + } return React.createElement('div', {}, scopeVerb2.apply(this, [])); }; }); diff --git a/test/src/rt.invalid.spec.js b/test/src/rt.invalid.spec.js index 4ffa7d0..34eea09 100644 --- a/test/src/rt.invalid.spec.js +++ b/test/src/rt.invalid.spec.js @@ -28,8 +28,12 @@ module.exports = { {file: 'invalid-rt-import-1.rt', issue: new RTCodeError("'*' imports must have an 'as' attribute", 0, 36, 1, 1)}, {file: 'invalid-rt-import-2.rt', issue: new RTCodeError("default imports must have an 'as' attribute", 0, 42, 1, 1)}, {file: 'invalid-rt-import-3.rt', issue: new RTCodeError("'rt-import' needs 'name' and 'from' attributes", 0, 13, 1, 1)}, + {file: 'invalid-rt-import-4.rt', issue: new RTCodeError("'rt-import' must be a toplevel node", 9, 54, 2, 4)}, + {file: 'invalid-rt-template-1.rt', issue: new RTCodeError("'rt-template' should have a single non-text element as direct child", 9, 88, 2, 4)}, + {file: 'invalid-rt-template-2.rt', issue: new RTCodeError("'rt-template' should have a single non-text element as direct child", 9, 90, 2, 4)}, {file: 'invalid-brace.rt', issue: new RTCodeError('Unexpected end of input', 128, 163, 5, 11)}, - {file: 'invalid-style.rt', issue: new RTCodeError('Unexpected token ILLEGAL', 10, 39, 2, 5)}, + {file: 'invalid-style-1.rt', issue: new RTCodeError('Unexpected token ILLEGAL', 10, 39, 2, 5)}, + {file: 'invalid-style-2.rt', issue: new RTCodeError('style attribute keys cannot contain { } expressions', 35, 68, 2, 5)}, {file: 'invalid-virtual.rt', issue: new RTCodeError('Document should not have <rt-virtual> as root element', 0, 60, 1, 1)} ]; diff --git a/test/src/rt.valid.spec.js b/test/src/rt.valid.spec.js index 165bfd5..4f5a441 100644 --- a/test/src/rt.valid.spec.js +++ b/test/src/rt.valid.spec.js @@ -29,7 +29,7 @@ module.exports = { }); test('conversion test', t => { - const files = ['div.rt', 'test.rt', 'repeat.rt', 'repeat-with-index.rt', 'inputs.rt', 'virtual.rt', 'stateless.rt']; + const files = ['div.rt', 'test.rt', 'repeat.rt', 'repeat-with-index.rt', 'inputs.rt', 'virtual.rt', 'stateless.rt', 'style-vendor-prefix.rt']; testFiles(t, files); }); @@ -78,6 +78,23 @@ module.exports = { } }); + test('convert comment with AMD and ES6 modules', t => { + const files = [ + {source: 'comment.rt', expected: 'comment.rt.amd.js', options: {modules: 'amd'}}, + {source: 'comment.rt', expected: 'comment.rt.es6.js', options: {modules: 'es6'}} + ]; + t.plan(files.length); + files.forEach(check); + + function check(testData) { + const filename = path.join(dataPath, testData.source); + const html = readFileNormalized(filename); + const expected = readFileNormalized(path.join(dataPath, testData.expected)); + const actual = reactTemplates.convertTemplateToReact(html, testData.options).replace(/\r/g, '').trim(); + compareAndWrite(t, actual, expected, filename); + } + }); + test('rt-require with all module types', t => { const files = [ {source: 'require.rt', expected: 'require.rt.commonjs.js', options: {modules: 'commonjs'}},