Tag params (#1076)

This commit is contained in:
Michael Rawlings 2018-07-10 13:04:46 -07:00 committed by GitHub
parent 63b0aeb58a
commit f5ebda8f2a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 136 additions and 18 deletions

View File

@ -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);

View File

@ -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) {

View File

@ -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);

View File

@ -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]);
}
}

View File

@ -686,6 +686,10 @@ class TagLoader {
htmlType(value) {
this.tag.htmlType = value;
}
featureFlags(value) {
this.tag.featureFlags = value;
}
}
function isSupportedProperty(name) {

View File

@ -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] === "@";
}

View File

@ -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;

View File

@ -0,0 +1,17 @@
class {
onCreate() {
this.state = {
name:'Anna'
}
}
changeName() {
this.state.name = 'Vickie';
}
}
<div>
<${input.first} name=state.name/>
<button on-click('changeName')>
Change
</button>
</div>

View File

@ -0,0 +1,3 @@
{
"featureFlags": ["params"]
}

View File

@ -0,0 +1,7 @@
class {}
<name key="name">
<@first({ name })>
Hello, ${name}!
</@first>
</name>

View File

@ -0,0 +1,10 @@
var expect = require("chai").expect;
module.exports = function(helpers) {
var component = helpers.mount(require.resolve("./index"), {});
expect(helpers.targetEl.innerHTML).to.contain("Hello, Anna!");
var nameComponent = component.getComponent("name");
nameComponent.changeName();
nameComponent.update();
expect(helpers.targetEl.innerHTML).to.contain("Hello, Vickie!");
};

View File

@ -0,0 +1,17 @@
class {
onCreate() {
this.state = {
name:'Anna'
}
}
changeName() {
this.state.name = 'Vickie';
}
}
<div>
<${input} name=state.name/>
<button on-click('changeName')>
Change
</button>
</div>

View File

@ -0,0 +1,3 @@
{
"featureFlags": ["params"]
}

View File

@ -0,0 +1,5 @@
class {}
<name({ name }) key="name">
Hello, ${name}!
</name>

View File

@ -0,0 +1,10 @@
var expect = require("chai").expect;
module.exports = function(helpers) {
var component = helpers.mount(require.resolve("./index"), {});
expect(helpers.targetEl.innerHTML).to.contain("Hello, Anna!");
var nameComponent = component.getComponent("name");
nameComponent.changeName();
nameComponent.update();
expect(helpers.targetEl.innerHTML).to.contain("Hello, Vickie!");
};