Skip to content

Commit

Permalink
Merge pull request #1344 from alibaba/fix-list
Browse files Browse the repository at this point in the history
fix: render style property in list
  • Loading branch information
ChrisCindy authored Sep 11, 2019
2 parents 4ca992f + 0260527 commit dd6a0ae
Show file tree
Hide file tree
Showing 8 changed files with 115 additions and 70 deletions.
7 changes: 6 additions & 1 deletion packages/jsx-compiler/src/modules/__tests__/jsx-plus.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@ describe('Directives', () => {
<View x-for={val in array}>{val}</View>
`);
_transformList(ast, adapter);
expect(genExpression(ast)).toEqual('<View a:for={array} a:for-item="val">{val}</View>');
expect(genExpression(ast)).toEqual(`<View a:for={array.map((val, index) => {
return {
val: val,
index: index
};
})} a:for-item="val" a:for-index="index">{val}</View>`);
});
});

Expand Down
7 changes: 6 additions & 1 deletion packages/jsx-compiler/src/modules/code.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,12 @@ module.exports = {
];
const callUpdateProps = t.expressionStatement(t.callExpression(updateProps, updatePropsArgs));
if (propMaps.length > 0) {
(parentNode || fnBody).push(callUpdateProps);
const targetNode = parentNode || fnBody;
if (t.isReturnStatement(targetNode[targetNode.length - 1])) {
targetNode.splice(targetNode.length - 1, 0, callUpdateProps);
} else {
targetNode.push(callUpdateProps);
}
} else if ((parentNode || fnBody).length === 0) {
// Remove empty loop exp.
parentNode && parentNode.remove && parentNode.remove();
Expand Down
27 changes: 2 additions & 25 deletions packages/jsx-compiler/src/modules/components.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,31 +45,8 @@ module.exports = {
componentsDependentProps[tagId].tagIdExpression = parentPath.node.__tagIdExpression;

if (parsed.renderFunctionPath) {
const { args, iterValue, loopFnBody } = parentJSXListEl.node.__jsxlist;
const __args = [
args[0] || t.identifier('item'),
args[1] || t.identifier('index'),
];
const callee = t.memberExpression(iterValue, t.identifier('forEach'));
const block = t.blockStatement([]);

const loopArgs = [t.arrowFunctionExpression(__args, block)];
const loopExp = t.expressionStatement(t.callExpression(callee, loopArgs));

const fnBody = parsed.renderFunctionPath.node.body.body;
const grandJSXListEl = parentJSXListEl.findParent(p => p.node.__jsxlist);
const body = grandJSXListEl && grandJSXListEl.node.__jsxlist.loopBlockStatement
? grandJSXListEl.node.__jsxlist.loopBlockStatement.body
: fnBody;

body.push(loopExp);
// Can be removed if not used.
block.body.remove = () => {
const index = body.indexOf(loopExp);
body.splice(index, 1);
};
componentsDependentProps[tagId].parentNode = block.body;
parentJSXListEl.node.__jsxlist.loopBlockStatement = block;
const { loopFnBody } = parentJSXListEl.node.__jsxlist;
componentsDependentProps[tagId].parentNode = loopFnBody.body;
}
}

Expand Down
55 changes: 34 additions & 21 deletions packages/jsx-compiler/src/modules/element.js
Original file line number Diff line number Diff line change
Expand Up @@ -288,9 +288,8 @@ function transformTemplate(ast, scope = null, adapter, sourceCode, componentDepe
if (innerPath.node.__transformed
|| innerPath.parentPath.isMemberExpression()
|| innerPath.parentPath.isObjectProperty()
|| innerPath.node.__xforArgs
|| innerPath.node.__mapArgs
&& !innerPath.node.__mapArgs.item) return;
|| innerPath.node.__listItem
&& !innerPath.node.__listItem.item) return;
const replaceNode = transformIdentifier(innerPath.node, dynamicValues, isDirective);
replaceNode.__transformed = true;
innerPath.replaceWith(replaceNode);
Expand All @@ -304,18 +303,7 @@ function transformTemplate(ast, scope = null, adapter, sourceCode, componentDepe
},
ObjectExpression(innerPath) {
if (innerPath.node.__transformed) return;
const { properties } = innerPath.node;
const replaceProperties = properties.map(property => {
const { key, value } = property;
let replaceNode;
if (t.isIdentifier(value)) {
replaceNode = transformIdentifier(value, dynamicValues, isDirective);
}
if (t.isMemberExpression(value)) {
replaceNode = transformMemberExpression(value, dynamicValues, isDirective);
}
return t.objectProperty(key, replaceNode);
});
const replaceProperties = transformObjectExpression(innerPath.node, dynamicValues, isDirective);
const replaceNode = t.objectExpression(replaceProperties);
replaceNode.__transformed = true;
innerPath.replaceWith(replaceNode);
Expand Down Expand Up @@ -414,7 +402,7 @@ function hasComplexExpression(path) {
const { properties } = innerPath.node;
const checkNested = properties.some(property => {
const { value } = property;
return !t.isIdentifier(value) && !t.isMemberExpression(value);
return !t.isIdentifier(value) && !t.isMemberExpression(value) && !t.isBinaryExpression(value);
});
if (checkNested) {
isComplex(innerPath);
Expand Down Expand Up @@ -452,7 +440,7 @@ function transformMemberExpression(expression, dynamicBinding, isDirective) {
replaceNode.__transformed = true;
return replaceNode;
}
if (t.isIdentifier(object) && !object.__xforArgs) {
if (t.isIdentifier(object)) {
objectReplaceNode = transformIdentifier(object, dynamicBinding, isDirective);
objectReplaceNode.__transformed = true;
}
Expand All @@ -475,13 +463,17 @@ function transformMemberExpression(expression, dynamicBinding, isDirective) {
* */
function transformIdentifier(expression, dynamicBinding, isDirective) {
let replaceNode;
if (expression.__xforArgs
|| expression.__mapArgs && !expression.__mapArgs.item
if (expression.__listItem
&& !expression.__listItem.item
|| expression.__templateVar) {
// The identifier is x-for args or template variable or map's index
replaceNode = expression;
} else if (expression.__mapArgs && expression.__mapArgs.item) {
replaceNode = t.memberExpression(t.identifier(expression.__mapArgs.item), expression);
} else if (expression.__listItem && expression.__listItem.item) {
const itemNode = t.identifier(expression.__listItem.item);
itemNode.__listItem = {
jsxplus: expression.__listItem.jsxplus
};
replaceNode = t.memberExpression(itemNode, expression);
} else {
const name = dynamicBinding.add({
expression,
Expand All @@ -492,6 +484,27 @@ function transformIdentifier(expression, dynamicBinding, isDirective) {
return replaceNode;
}

/**
* Transform ObjectExpression
* */
function transformObjectExpression(expression, dynamicBinding, isDirective) {
const { properties } = expression;
return properties.map(property => {
const { key, value } = property;
let replaceNode = value;
if (t.isIdentifier(value)) {
replaceNode = transformIdentifier(value, dynamicBinding, isDirective);
}
if (t.isMemberExpression(value)) {
replaceNode = transformMemberExpression(value, dynamicBinding, isDirective);
}
if (t.isObjectExpression(value)) {
replaceNode = transformObjectExpression(value, dynamicBinding, isDirective);
}
return t.objectProperty(key, replaceNode);
});
}

function checkMemberHasThis(expression) {
const { object, property } = expression;
let hasThisExpression = false;
Expand Down
4 changes: 2 additions & 2 deletions packages/jsx-compiler/src/modules/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ module.exports = [
require('./style'),
// Handle Rax base components.
require('./components'),
// JSX+ Directives
require('./jsx-plus'),
// Directive a:for
require('./list'),
// Directive a:if
require('./condition'),
// JSX+ Directives
require('./jsx-plus'),
// Handle render function
require('./render-function'),
// Parse and generate template.
Expand Down
31 changes: 27 additions & 4 deletions packages/jsx-compiler/src/modules/jsx-plus.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,12 @@ function transformDirectiveList(ast, adapter) {
path.traverse({
Identifier(innerPath) {
const { node } = innerPath;
if (args.find(arg => arg.name === node.name)) {
node.__xforArgs = true;
if (args.find(arg => arg.name === node.name)
) {
node.__listItem = {
jsxplus: true,
item: args[0].name
};
}
}
});
Expand Down Expand Up @@ -147,17 +151,36 @@ function transformDirectiveList(ast, adapter) {
params = left.expressions;
} else if (t.isIdentifier(left)) {
// x-for={item in value}
params.push(left);
params = [left, t.identifier('index')];
} else {
// x-for={??? in value}
throw new Error('Stynax error of x-for.');
}
} else {
// x-for={value}, x-for={callExp()}, ...
iterValue = expression;
params = [t.identifier('item'), t.identifier('index')];
}
const parentJSXEl = path.findParent(p => p.isJSXElement());
parentJSXEl.node.__jsxlist = { args: params, iterValue, jsxplus: true };
// Transform x-for iterValue to map function
const loopFnBody = t.blockStatement([
t.returnStatement(
t.objectExpression([
t.objectProperty(params[0], params[0]),
t.objectProperty(params[1], params[1])
])
)
]);
parentJSXEl.node.__jsxlist = {
args: params,
iterValue: t.callExpression(
t.memberExpression(iterValue, t.identifier('map')),
[
t.arrowFunctionExpression(params, loopFnBody)
]),
loopFnBody,
jsxplus: true
};
path.remove();
}
}
Expand Down
31 changes: 18 additions & 13 deletions packages/jsx-compiler/src/modules/list.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const findIndex = require('../utils/findIndex');

function transformList(ast, renderItemFunctions, adapter) {
let fnScope;
let useCreateStyle = false;

function traverseFunction(path) {
fnScope = path.scope;
Expand Down Expand Up @@ -86,29 +87,27 @@ function transformList(ast, renderItemFunctions, adapter) {
returnElPath.traverse({
Identifier(innerPath) {
if (innerPath.findParent(p => p.node.__bindEvent)) return;
if (innerPath.node.name === forItem.name) {
innerPath.node.__mapArgs = {
item: forItem.name
};
}

if (innerPath.node.name === forIndex.name) {
innerPath.node.__mapArgs = {};
}

if (
innerPath.scope.hasBinding(innerPath.node.name)
|| innerPath.node.name === forItem.name
|| innerPath.node.name === forIndex.name
&& !(t.isMemberExpression(innerPath.parent) && innerPath.parent.property !== innerPath.node)
) {
innerPath.node.__mapArgs = {
console.log(t.isMemberExpression(innerPath.parent));
innerPath.node.__listItem = {
jsxplus: false,
item: forItem.name
};

// Skip duplicate keys.
if (!properties.some(
pty => pty.key.name === innerPath.node.name)) {
properties.push(t.objectProperty(innerPath.node, innerPath.node));
let value = innerPath.node;
if (innerPath.findParent(p => p.isJSXAttribute() && p.node.name.name === 'style')) {
value = t.callExpression(t.identifier('__create_style__'), [value]);
useCreateStyle = true;
}
properties.push(t.objectProperty(innerPath.node, value));
}
}
},
Expand Down Expand Up @@ -141,6 +140,7 @@ function transformList(ast, renderItemFunctions, adapter) {
iterValue: callee.object,
generated: true,
jsxplus: false,
loopFnBody: body
};

parentPath.replaceWith(listBlock);
Expand All @@ -154,11 +154,16 @@ function transformList(ast, renderItemFunctions, adapter) {
}
}
});
return useCreateStyle;
}

module.exports = {
parse(parsed, code, options) {
transformList(parsed.templateAST, parsed.renderItemFunctions, options.adapter);
const useCreateStyle = transformList(parsed.templateAST, parsed.renderItemFunctions, options.adapter);
// In list item maybe use __create_style__
if (!parsed.useCreateStyle) {
parsed.useCreateStyle = useCreateStyle;
}
},

// For test cases.
Expand Down
23 changes: 20 additions & 3 deletions packages/jsx-compiler/src/modules/style.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ const t = require('@babel/types');
const traverse = require('../utils/traverseNodePath');

const TEMPLATE_AST = 'templateAST';
const DYNAMIC_STYLES = 'dynamicStyles';
const DynamicBinding = require('../utils/DynamicBinding');

/**
Expand All @@ -12,13 +11,13 @@ const DynamicBinding = require('../utils/DynamicBinding');
* var _style0 = { width: 100 };
* return { _style0 };
*/
function transformStyle(ast, dynamicStyles) {
function transformStyle(ast) {
const dynamicValue = new DynamicBinding('_s');

traverse(ast, {
JSXAttribute(path) {
const { node } = path;
if (t.isJSXExpressionContainer(node.value) && node.name.name === 'style') {
if (shouldReplace(path)) {
const styleObjectExpression = node.value.expression;

// <tag style="{{ _s0 }}" />
Expand All @@ -32,6 +31,24 @@ function transformStyle(ast, dynamicStyles) {
return dynamicValue.getStore();
}

function shouldReplace(path) {
const { node } = path;
if (t.isJSXExpressionContainer(node.value) && node.name.name === 'style') {
let shouldReplace = true;
// List item has been replaced in list module
traverse(node.value.expression, {
Identifier(innerPath) {
if (innerPath.node.__listItem) {
shouldReplace = false;
innerPath.stop();
}
}
});
return shouldReplace;
}
return false;
}

module.exports = {
parse(parsed, code, options) {
const dynamicValues = transformStyle(parsed[TEMPLATE_AST]);
Expand Down

0 comments on commit dd6a0ae

Please # to comment.