From 0c5fee07a7eb7cf0fe4efa4ca87ba3f5aaf10b00 Mon Sep 17 00:00:00 2001 From: anchann Date: Mon, 27 Jul 2015 15:56:10 +0900 Subject: [PATCH 1/2] In rt-scope subsequent aliases should be able to reference preceding ones Rationale: It is typical to want to alias multiple subtrees of a nested structure in a single rt-scope statement, like so:
This was not possible because of the function parameter based implementation of rt-scope. I tweaked it a bit to use var declaration instead, while preserving the parameter-based passing for all child scopes. --- .gitignore | 2 ++ src/reactTemplates.js | 27 ++++++++++++++++----- test/data/scope-variable-references.rt | 11 +++++++++ test/data/scope-variable-references.rt.html | 1 + test/src/test.js | 11 +++++++-- 5 files changed, 44 insertions(+), 8 deletions(-) create mode 100644 test/data/scope-variable-references.rt create mode 100644 test/data/scope-variable-references.rt.html diff --git a/.gitignore b/.gitignore index caf1810..5c04a5b 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,5 @@ npm-debug.log /target /coverage +### generated code output ### +test/data/*.code.js diff --git a/src/reactTemplates.js b/src/reactTemplates.js index 47557d7..fc9c429 100644 --- a/src/reactTemplates.js +++ b/src/reactTemplates.js @@ -287,11 +287,16 @@ function convertHtmlToReact(node, context) { var data = {name: convertTagNameToConstructor(node.name, context)}; if (node.attribs[scopeProp]) { - data.scopeMapping = {}; data.scopeName = ''; + + // these are variables that were already in scope, unrelated to the ones declared in rt-scope + data.outerScopeMapping = {}; _.each(context.boundParams, function (boundParam) { - data.scopeMapping[boundParam] = boundParam; + data.outerScopeMapping[boundParam] = boundParam; }); + + // these are variables declared in the rt-scope attribute + data.innerScopeMapping = {}; _.each(node.attribs[scopeProp].split(';'), function (scopePart) { var scopeSubParts = scopePart.split(' as '); if (scopeSubParts.length < 2) { @@ -299,10 +304,15 @@ function convertHtmlToReact(node, context) { } var scopeName = scopeSubParts[1].trim(); validateJS(scopeName, node, context); + + // this adds both parameters to the list of parameters passed further down + // the scope chain, as well as variables that are locally bound before any + // function call, as with the ones we generate for rt-scope. stringUtils.addIfMissing(context.boundParams, scopeName); + data.scopeName += stringUtils.capitalize(scopeName); - data.scopeMapping[scopeName] = scopeSubParts[0].trim(); - validateJS(data.scopeMapping[scopeName], node, context); + data.innerScopeMapping[scopeName] = scopeSubParts[0].trim(); + validateJS(data.innerScopeMapping[scopeName], node, context); }); } @@ -357,8 +367,13 @@ function convertHtmlToReact(node, context) { data.body = ifTemplate(data); } if (node.attribs[scopeProp]) { - var generatedFuncName = generateInjectedFunc(context, 'scope' + data.scopeName, 'return ' + data.body, _.keys(data.scopeMapping)); - data.body = generatedFuncName + '.apply(this, [' + _.values(data.scopeMapping).join(',') + '])'; + var scopeVarDeclarations = _.reduce(data.innerScopeMapping, function(acc, rightHandSide, leftHandSide) { + var declaration = "var " + leftHandSide + " = " + rightHandSide + ";" + return acc + declaration; + }, ""); + var functionBody = scopeVarDeclarations + 'return ' + data.body; + var generatedFuncName = generateInjectedFunc(context, 'scope' + data.scopeName, functionBody, _.keys(data.outerScopeMapping)); + data.body = generatedFuncName + '.apply(this, [' + _.values(data.outerScopeMapping).join(',') + '])'; } return data.body; } else if (node.type === 'comment') { diff --git a/test/data/scope-variable-references.rt b/test/data/scope-variable-references.rt new file mode 100644 index 0000000..929caaf --- /dev/null +++ b/test/data/scope-variable-references.rt @@ -0,0 +1,11 @@ +
+
+ +
+

{first} {pirate.last}

+
+ {skill} +
+
+
+
diff --git a/test/data/scope-variable-references.rt.html b/test/data/scope-variable-references.rt.html new file mode 100644 index 0000000..8e57fd2 --- /dev/null +++ b/test/data/scope-variable-references.rt.html @@ -0,0 +1 @@ +

Jack Sparrow

talkingfightingcommandeering
diff --git a/test/src/test.js b/test/src/test.js index cfd3865..54734a1 100644 --- a/test/src/test.js +++ b/test/src/test.js @@ -119,12 +119,15 @@ test('conversion test', function (t) { * @param {string} actual * @param {string} expected * @param {string} filename + * @return {boolean} whether actual is equal to expected */ function compareAndWrite(t, actual, expected, filename) { t.equal(actual, expected); if (actual !== expected) { fs.writeFileSync(filename + '.actual.js', actual); + return false; } + return true; } test('convert div with all module types', function (t) { @@ -175,7 +178,7 @@ function normalizeHtml(html) { } test('html tests', function (t) { - var files = ['scope.rt', 'lambda.rt', 'eval.rt', 'props.rt', 'custom-element.rt', 'style.rt', 'concat.rt', 'js-in-attr.rt', 'props-class.rt', 'rt-class.rt']; + var files = ['scope.rt', 'scope-variable-references.rt', 'lambda.rt', 'eval.rt', 'props.rt', 'custom-element.rt', 'style.rt', 'concat.rt', 'js-in-attr.rt', 'props-class.rt', 'rt-class.rt']; t.plan(files.length); files.forEach(check); @@ -202,9 +205,13 @@ test('html tests', function (t) { var actual = React.renderToStaticMarkup(comp()); actual = normalizeHtml(actual); expected = normalizeHtml(expected); - compareAndWrite(t, actual, expected, filename); + var equal = compareAndWrite(t, actual, expected, filename); + if (!equal) { + fs.writeFileSync(filename + '.code.js', code); + } } catch (e) { console.log(testFile, e); + fs.writeFileSync(filename + '.code.js', code); } } }); From accef5fb0f8c20cec079472aded2926e2a2bbfce Mon Sep 17 00:00:00 2001 From: ido Date: Thu, 30 Jul 2015 13:41:55 +0300 Subject: [PATCH 2/2] merge #45 --- src/reactTemplates.js | 6 +++--- test/src/test.js | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/reactTemplates.js b/src/reactTemplates.js index e4a2539..0d01861 100644 --- a/src/reactTemplates.js +++ b/src/reactTemplates.js @@ -383,10 +383,10 @@ function convertHtmlToReact(node, context) { data.body = ifTemplate(data); } if (node.attribs[scopeAttr]) { - var scopeVarDeclarations = _.reduce(data.innerScopeMapping, function(acc, rightHandSide, leftHandSide) { - var declaration = "var " + leftHandSide + " = " + rightHandSide + ";" + var scopeVarDeclarations = _.reduce(data.innerScopeMapping, function (acc, rightHandSide, leftHandSide) { + var declaration = 'var ' + leftHandSide + ' = ' + rightHandSide + ';'; return acc + declaration; - }, ""); + }, ''); var functionBody = scopeVarDeclarations + 'return ' + data.body; var generatedFuncName = generateInjectedFunc(context, 'scope' + data.scopeName, functionBody, _.keys(data.outerScopeMapping)); data.body = generatedFuncName + '.apply(this, [' + _.values(data.outerScopeMapping).join(',') + '])'; diff --git a/test/src/test.js b/test/src/test.js index a3ad045..46a6e21 100644 --- a/test/src/test.js +++ b/test/src/test.js @@ -184,12 +184,13 @@ test('html tests', function (t) { files.forEach(check); function check(testFile) { + var filename = path.join(dataPath, testFile); + var code = ''; try { - var filename = path.join(dataPath, testFile); var html = fs.readFileSync(filename).toString(); var expected = readFileNormalized(filename + '.html'); // var expected = fs.readFileSync(filename.replace(".html", ".js")).toString(); - var code = reactTemplates.convertTemplateToReact(html).replace(/\r/g, ''); + code = reactTemplates.convertTemplateToReact(html).replace(/\r/g, ''); var defineMap = {'react/addons': React, lodash: _}; //noinspection JSUnusedLocalSymbols var define = function (requirementsNames, content) { //eslint-disable-line no-unused-vars,func-style