diff --git a/src/reactTemplates.js b/src/reactTemplates.js index b002b7f..453a17a 100644 --- a/src/reactTemplates.js +++ b/src/reactTemplates.js @@ -346,6 +346,15 @@ function convertHtmlToReact(node, context) { } } + // provide a key to virtual node children if missing + if (node.name === virtualNode && node.children.length > 1) { + _(node.children) + .reject('attribs.key') + .forEach((child, i) => { + _.set(child, ['attribs', 'key'], `${node.startIndex}${i}`); + }); + } + const children = _.map(node.children, child => { const code = convertHtmlToReact(child, context); validateJS(code, child, context); @@ -459,7 +468,12 @@ function convertTemplateToReact(html, options) { } function parseAndConvertHtmlToReact(html, context) { - const rootNode = cheerio.load(html, {lowerCaseTags: false, lowerCaseAttributeNames: false, xmlMode: true, withStartIndices: true}); + const rootNode = cheerio.load(html, { + lowerCaseTags: false, + lowerCaseAttributeNames: false, + xmlMode: true, + withStartIndices: true + }); utils.validate(context.options, context, context.reportContext, rootNode.root()[0]); let rootTags = _.filter(rootNode.root()[0].children, isTag); rootTags = handleSelfClosingHtmlTags(rootTags); @@ -515,7 +529,14 @@ function convertRT(html, reportContext, options) { } const header = options.flow ? '/* @flow */\n' : ''; const vars = header + _(context.defines).map(buildImport).join('\n'); - const data = {body, injectedFunctions: context.injectedFunctions.join('\n'), requireNames: _.values(context.defines).join(','), requirePaths, vars, name: options.name}; + const data = { + body, + injectedFunctions: context.injectedFunctions.join('\n'), + requireNames: _.values(context.defines).join(','), + requirePaths, + vars, + name: options.name + }; let code = generate(data, options); if (options.modules !== 'typescript' && options.modules !== 'jsrt') { code = parseJS(code); diff --git a/test/data/virtual.rt.js b/test/data/virtual.rt.js new file mode 100644 index 0000000..3cf3122 --- /dev/null +++ b/test/data/virtual.rt.js @@ -0,0 +1,26 @@ +define([ + 'react/addons', + '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 () { + return React.createElement('div', {}, scopeVerb2.apply(this, [])); + }; +}); \ No newline at end of file diff --git a/test/src/rt.valid.spec.js b/test/src/rt.valid.spec.js index bc11e99..30503e5 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', 'inputs.rt', 'require.rt']; + const files = ['div.rt', 'test.rt', 'repeat.rt', 'inputs.rt', 'require.rt', 'virtual.rt']; testFiles(t, files); });