diff --git a/packages/taro-transformer-wx/__tests__/loop.spec.ts b/packages/taro-transformer-wx/__tests__/loop.spec.ts index f0560a4cab02..c80191d82c28 100644 --- a/packages/taro-transformer-wx/__tests__/loop.spec.ts +++ b/packages/taro-transformer-wx/__tests__/loop.spec.ts @@ -996,14 +996,14 @@ describe('loop', () => { ...baseOptions, isRoot: true, code: buildComponent(` - const array = [{ list: [{}] }] + const array = [{ list: [] }] const b1 = true const b2 = true const b3 = true const b4 = true return ( {array.map(arr => { - return + return {arr.list.map(item => { return b1 ? {b2 ? : null} @@ -1019,6 +1019,9 @@ describe('loop', () => { `, `handleClick = () => ({})`) }) + console.log(code) + console.log(template) + const instance = evalClass(ast) removeShadowData(instance.state) expect(Object.keys(instance.state).length).toBe(5) diff --git a/packages/taro-transformer-wx/src/constant.ts b/packages/taro-transformer-wx/src/constant.ts index 452202c8ff71..edf906e31adf 100644 --- a/packages/taro-transformer-wx/src/constant.ts +++ b/packages/taro-transformer-wx/src/constant.ts @@ -88,6 +88,8 @@ export const INTERNAL_INLINE_STYLE = 'internal_inline_style' export const LOOP_STATE = '$loopState' +export const LOOP_ORIGINAL = '$$original' + export const LOOP_CALLEE = '$anonymousCallee_' export const SPECIAL_COMPONENT_PROPS = new Map>() diff --git a/packages/taro-transformer-wx/src/render.ts b/packages/taro-transformer-wx/src/render.ts index 452e570f7169..7f23ec8a817d 100644 --- a/packages/taro-transformer-wx/src/render.ts +++ b/packages/taro-transformer-wx/src/render.ts @@ -19,13 +19,13 @@ import { findMethodName, isVarName } from './utils' -import { difference } from 'lodash' +import { difference, set as setObject, cloneDeep } from 'lodash' import { setJSXAttr, buildBlockElement, parseJSXElement } from './jsx' -import { DEFAULT_Component_SET, MAP_CALL_ITERATOR, LOOP_STATE, LOOP_CALLEE, THIRD_PARTY_COMPONENTS } from './constant' +import { DEFAULT_Component_SET, MAP_CALL_ITERATOR, LOOP_STATE, LOOP_CALLEE, THIRD_PARTY_COMPONENTS, LOOP_ORIGINAL } from './constant' import generate from 'babel-generator' const template = require('babel-template') @@ -95,6 +95,7 @@ export class RenderParser { private topLevelIfStatement = new Set>() private usedEvents = new Set() private customComponentNames: Set + private originalCallee = new Map() private renderPath: NodePath private methods: ClassMethodsMap @@ -316,6 +317,8 @@ export class RenderParser { } } setJSXAttr(jsxElementPath.node, 'wx:for', t.jSXExpressionContainer(ary)) + this.originalCallee.set(ary, jsxElementPath.node) + const [func] = callExpr.node.arguments if ( t.isFunctionExpression(func) || @@ -865,9 +868,11 @@ export class RenderParser { } stateToBeAssign.forEach(s => this.loopRefIdentifiers.set(s, callee)) const properties = Array.from(stateToBeAssign).map(state => t.objectProperty(t.identifier(state), t.identifier(state))) + const self = this component.traverse({ Identifier (path) { const name = path.node.name + const parent = path.parent if (stateToBeAssign.has(name) && path.isReferencedIdentifier()) { path.replaceWith( t.memberExpression( @@ -875,16 +880,43 @@ export class RenderParser { path.node ) ) + hasOriginalRef = true } if ( - path.parentPath.isJSXExpressionContainer() && path.isReferencedIdentifier() && - name === item.name + name === item.name && + !(t.isMemberExpression(parent) && t.isIdentifier(parent.property, { name: LOOP_ORIGINAL })) && + !(t.isMemberExpression(parent) && t.isIdentifier(parent.property) && (parent.property.name.startsWith(LOOP_STATE) || parent.property.name.startsWith(LOOP_CALLEE))) ) { + const parentCallExpr = path.findParent(c => isArrayMapCallExpression(c)) + if (isArrayMapCallExpression(parentCallExpr)) { + const { object } = parentCallExpr.node.callee as t.MemberExpression + const isCallee = path.findParent(c => c.node === object) + if (isCallee) { + if (self.originalCallee.has(object)) { + const jsx = self.originalCallee.get(object)! + if (t.isMemberExpression(object)) { + const arr: string[] = ['object'] + let obj = object.object as any + while (true) { + if (t.identifier(obj) && !t.isMemberExpression(obj)) { + break + } + obj = obj.object + arr.push('object') + } + const objectCopy = cloneDeep(object) + setObject(objectCopy, arr, t.memberExpression(t.identifier(item.name), t.identifier(LOOP_ORIGINAL))) + setJSXAttr(jsx, 'wx:for', t.jSXExpressionContainer(objectCopy)) + } + } + return + } + } path.replaceWith(t.memberExpression( t.identifier(item.name), - t.identifier('$$original') + t.identifier(LOOP_ORIGINAL) )) hasOriginalRef = true } @@ -898,13 +930,11 @@ export class RenderParser { }) if (hasOriginalRef) { properties.push(t.objectProperty( - t.identifier('$$original'), + t.identifier(LOOP_ORIGINAL), t.identifier(item.name) )) } - const returnStatement = t.returnStatement(t.objectExpression( - [t.spreadProperty(t.identifier(item.name)), ...properties] - )) + const returnStatement = t.returnStatement(properties.length ? t.objectExpression(properties) : item) const parentCallee = callee.findParent(c => isArrayMapCallExpression(c)) if (isArrayMapCallExpression(parentCallee)) { const [ func ] = parentCallee.node.arguments diff --git a/packages/taro-transformer-wx/src/utils.ts b/packages/taro-transformer-wx/src/utils.ts index 4ea9bec9d267..5788cb41f8c5 100644 --- a/packages/taro-transformer-wx/src/utils.ts +++ b/packages/taro-transformer-wx/src/utils.ts @@ -353,12 +353,15 @@ export function hasComplexExpression (path: NodePath) { return matched } -export function findFirstIdentifierFromMemberExpression (node: t.MemberExpression): t.Identifier { +export function findFirstIdentifierFromMemberExpression (node: t.MemberExpression, member?): t.Identifier { let id let object = node.object as any while (true) { if (t.identifier(object) && !t.isMemberExpression(object)) { id = object + if (member) { + object = member + } break } object = object.object