diff --git a/src/compiler/Builder.js b/src/compiler/Builder.js index 1278e98bbb..478381451c 100644 --- a/src/compiler/Builder.js +++ b/src/compiler/Builder.js @@ -52,6 +52,7 @@ var CustomTag = require("./ast/CustomTag"); var parseExpression = require("./util/parseExpression"); var parseStatement = require("./util/parseStatement"); var parseJavaScriptArgs = require("./util/parseJavaScriptArgs"); +var parseJavaScriptParams = require("./util/parseJavaScriptParams"); var replacePlaceholderEscapeFuncs = require("./util/replacePlaceholderEscapeFuncs"); var isValidJavaScriptIdentifier = require("./util/isValidJavaScriptIdentifier"); @@ -475,6 +476,11 @@ class Builder { return parseJavaScriptArgs(args, DEFAULT_BUILDER); } + parseJavaScriptParams(params) { + ok(typeof params === "string", '"params" should be a string'); + return parseJavaScriptParams(params, DEFAULT_BUILDER); + } + parseStatement(str) { ok(typeof str === "string", '"str" should be a string expression'); var parsed = parseStatement(str, DEFAULT_BUILDER); diff --git a/src/compiler/Parser.js b/src/compiler/Parser.js index 1f0431251f..1a55e813b1 100644 --- a/src/compiler/Parser.js +++ b/src/compiler/Parser.js @@ -1,6 +1,7 @@ "use strict"; var ok = require("assert").ok; var replacePlaceholderEscapeFuncs = require("./util/replacePlaceholderEscapeFuncs"); +var enableTagParams = require("./util/enableTagParams"); var extend = require("raptor-util/extend"); var COMPILER_ATTRIBUTE_HANDLERS = { @@ -400,7 +401,13 @@ class Parser { } this.prevTextNode = null; - this.stack.pop(); + var { node } = this.stack.pop(); + var tagDef = node.tagDef; + if (tagDef && tagDef.featureFlags) { + if (tagDef.featureFlags.includes("params")) { + enableTagParams(node, this.context.builder); + } + } } handleComment(comment) { diff --git a/src/compiler/ast/CustomTag.js b/src/compiler/ast/CustomTag.js index 159f801138..ca215bdf60 100644 --- a/src/compiler/ast/CustomTag.js +++ b/src/compiler/ast/CustomTag.js @@ -77,8 +77,11 @@ function getNestedVariables(elNode, tagDef, codegen) { } if (elNode.additionalNestedVars.length) { - elNode.additionalNestedVars.forEach(varName => { - variableNames.push(codegen.builder.identifier(varName)); + elNode.additionalNestedVars.forEach(variable => { + if (typeof variable === "string") { + variable = codegen.builder.identifier(variable); + } + variableNames.push(variable); }); } @@ -811,8 +814,12 @@ class CustomTag extends HtmlElement { if ( checkIfNestedTagCanBeAddedDirectlyToInput(this, parentCustomTag) ) { + let params = getNestedVariables(this, this.tagDef, codegen); let renderBody = hasBody - ? builder.renderBodyFunction(body) + ? builder.renderBodyFunction( + body, + [builder.identifier("out")].concat(params) + ) : null; let additionalAttrs = renderBody ? { renderBody } : null; let inputProps = this.buildInputProps(codegen, additionalAttrs); diff --git a/src/compiler/ast/FunctionDeclaration.js b/src/compiler/ast/FunctionDeclaration.js index 884471985c..27e8bf64da 100644 --- a/src/compiler/ast/FunctionDeclaration.js +++ b/src/compiler/ast/FunctionDeclaration.js @@ -45,21 +45,8 @@ class FunctionDeclaration extends Node { if (i !== 0) { writer.write(", "); } - var param = params[i]; - if (typeof param === "string") { - writer.write(param); - } else { - if (param.type !== "Identifier") { - throw new Error( - "Illegal param " + - JSON.stringify(param) + - " for FunctionDeclaration: " + - JSON.stringify(this) - ); - } - writer.write(param); - } + writer.write(params[i]); } } diff --git a/src/compiler/taglib-loader/loadTagFromProps.js b/src/compiler/taglib-loader/loadTagFromProps.js index 339fcfec6c..2f5867678f 100644 --- a/src/compiler/taglib-loader/loadTagFromProps.js +++ b/src/compiler/taglib-loader/loadTagFromProps.js @@ -686,6 +686,10 @@ class TagLoader { htmlType(value) { this.tag.htmlType = value; } + + featureFlags(value) { + this.tag.featureFlags = value; + } } function isSupportedProperty(name) { diff --git a/src/compiler/util/enableTagParams.js b/src/compiler/util/enableTagParams.js new file mode 100644 index 0000000000..cf6b969175 --- /dev/null +++ b/src/compiler/util/enableTagParams.js @@ -0,0 +1,16 @@ +module.exports = function enableTagParams(el, builder) { + if (el.argument) { + el.params = builder.parseJavaScriptParams(el.argument); + el.params.forEach(param => el.addNestedVariable(param)); + delete el.argument; + } + el.forEachChild(childNode => { + if (isNestedTag(childNode)) { + enableTagParams(childNode, builder); + } + }); +}; + +function isNestedTag(node) { + return node.tagName && node.tagName[0] === "@"; +} diff --git a/src/compiler/util/parseJavaScriptParams.js b/src/compiler/util/parseJavaScriptParams.js new file mode 100644 index 0000000000..5fb3129050 --- /dev/null +++ b/src/compiler/util/parseJavaScriptParams.js @@ -0,0 +1,19 @@ +"use strict"; + +var ok = require("assert").ok; +var esprima = require("esprima"); + +function parseJavaScriptParams(params, builder) { + ok(typeof params === "string", '"params" should be a string'); + ok(builder, '"builder" is required'); + + var src = "(" + params + ") => {}"; + var jsAST = esprima.parseScript(src, { range: true }); + var paramNodes = jsAST.body[0].expression.params; + return paramNodes.map(node => { + var nodeSrc = src.slice(node.range[0], node.range[1]); + return builder.expression(nodeSrc); + }); +} + +module.exports = parseJavaScriptParams; diff --git a/test/components-browser/fixtures/tag-params-nested-tags/components/name/index.marko b/test/components-browser/fixtures/tag-params-nested-tags/components/name/index.marko new file mode 100644 index 0000000000..dc56c95749 --- /dev/null +++ b/test/components-browser/fixtures/tag-params-nested-tags/components/name/index.marko @@ -0,0 +1,17 @@ +class { + onCreate() { + this.state = { + name:'Anna' + } + } + changeName() { + this.state.name = 'Vickie'; + } +} + +