diff --git a/src/reactTemplates.js b/src/reactTemplates.js index 31102fe..e840a60 100644 --- a/src/reactTemplates.js +++ b/src/reactTemplates.js @@ -366,7 +366,7 @@ function convertHtmlToReact(node, context) { if (node.attribs[ifAttr]) { validateIfAttribute(node, context, data); data.condition = node.attribs[ifAttr].trim(); - if (!node.attribs.key) { + if (!node.attribs.key && node.name !== virtualNode) { _.set(node, ['attribs', 'key'], `${node.startIndex}`); } } @@ -384,14 +384,23 @@ function convertHtmlToReact(node, context) { } } } + + if (node.name === virtualNode) { + const invalidAttributes = _.without(_.keys(node.attribs), scopeAttr, ifAttr, repeatAttr); + if (invalidAttributes.length > 0) { + throw RTCodeError.build(context, node, " may not contain attributes other than 'rt-scope', 'rt-if' and 'rt-repeat'"); + } - // 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}`); - }); + // provide a key to virtual node children if missing + if (node.children.length > 1) { + _(node.children) + .reject('attribs.key') + .forEach((child, i) => { + if (child.type === 'tag' && child.name !== virtualNode) { + _.set(child, ['attribs', 'key'], `${node.startIndex}${i}`); + } + }); + } } const children = _.map(node.children, child => { diff --git a/test/data/invalid/invalid-virtual.rt b/test/data/invalid/invalid-virtual-1.rt similarity index 100% rename from test/data/invalid/invalid-virtual.rt rename to test/data/invalid/invalid-virtual-1.rt diff --git a/test/data/invalid/invalid-virtual-2.rt b/test/data/invalid/invalid-virtual-2.rt new file mode 100644 index 0000000..a855992 --- /dev/null +++ b/test/data/invalid/invalid-virtual-2.rt @@ -0,0 +1,5 @@ +
+ + The answer is {fortytwo} + +
\ No newline at end of file diff --git a/test/src/rt.invalid.spec.js b/test/src/rt.invalid.spec.js index 34eea09..3a6b6bb 100644 --- a/test/src/rt.invalid.spec.js +++ b/test/src/rt.invalid.spec.js @@ -34,15 +34,14 @@ module.exports = { {file: 'invalid-brace.rt', issue: new RTCodeError('Unexpected end of input', 128, 163, 5, 11)}, {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 as root element', 0, 60, 1, 1)} + {file: 'invalid-virtual-1.rt', issue: new RTCodeError('Document should not have as root element', 0, 60, 1, 1)}, + {file: 'invalid-virtual-2.rt', issue: new RTCodeError(" may not contain attributes other than 'rt-scope', 'rt-if' and 'rt-repeat'", 9, 119, 2, 4)} ]; test('invalid tests', t => { t.plan(invalidFiles.length); - invalidFiles.forEach(check); - - function check(testFile) { + invalidFiles.forEach(testFile => { const filename = path.join(dataPath, testFile.file); const html = testUtils.readFileNormalized(filename); let error = null; @@ -52,7 +51,7 @@ module.exports = { error = e; } t.deepEqual(omitStack(error), omitStack(testFile.issue), 'Expect convertTemplateToReact to throw an error'); - } + }); }); /**