/*

 * Copyright (c) 2021-2024 Huawei Device Co., Ltd.

 * Licensed under the Apache License, Version 2.0 (the "License");

 * you may not use this file except in compliance with the License.

 * You may obtain a copy of the License at

 *

 *     http://www.apache.org/licenses/LICENSE-2.0

 *

 * Unless required by applicable law or agreed to in writing, software

 * distributed under the License is distributed on an "AS IS" BASIS,

 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

 * See the License for the specific language governing permissions and

 * limitations under the License.

 */



import ts from 'typescript';

import path from 'path';

import fs from 'fs';

import {

  COMPONENT_RENDER_FUNCTION,

  COMPONENT_CREATE_FUNCTION,

  COMPONENT_POP_FUNCTION,

  COMPONENT_BUTTON,

  COMPONENT_CREATE_LABEL_FUNCTION,

  COMPONENT_CREATE_CHILD_FUNCTION,

  COMPONENT_FOREACH,

  COMPONENT_LAZYFOREACH,

  IS_RENDERING_IN_PROGRESS,

  FOREACH_OBSERVED_OBJECT,

  FOREACH_GET_RAW_OBJECT,

  COMPONENT_IF,

  COMPONENT_IF_BRANCH_ID_FUNCTION,

  COMPONENT_IF_UNDEFINED,

  ATTRIBUTE_ANIMATION,

  GLOBAL_CONTEXT,

  COMPONENT_GESTURE,

  COMPONENT_GESTURE_GROUP,

  GESTURE_ATTRIBUTE,

  PARALLEL_GESTURE_ATTRIBUTE,

  PRIORITY_GESTURE_ATTRIBUTE,

  GESTURE_ENUM_KEY,

  GESTURE_ENUM_VALUE_HIGH,

  GESTURE_ENUM_VALUE_LOW,

  GESTURE_ENUM_VALUE_PARALLEL,

  COMPONENT_TRANSITION_NAME,

  COMPONENT_DEBUGLINE_FUNCTION,

  ATTRIBUTE_STATESTYLES,

  THIS,

  VISUAL_STATE,

  VIEW_STACK_PROCESSOR,

  STYLE_ADD_DOUBLE_DOLLAR,

  STYLE_ADD_DOUBLE_EXCLAMATION,

  $$_VALUE,

  $$_CHANGE_EVENT,

  $$_THIS,

  $$_NEW_VALUE,

  $_VALUE,

  BUILDER_ATTR_NAME,

  BUILDER_ATTR_BIND,

  CUSTOM_DIALOG_CONTROLLER_BUILDER,

  BIND_DRAG_SET,

  BIND_POPUP_SET,

  BIND_POPUP,

  CUSTOM_COMPONENT_DEFAULT,

  $$,

  PROPERTIES_ADD_DOUBLE_DOLLAR,

  PROPERTIES_ADD_DOUBLE_EXCLAMATION,

  ATTRIBUTE_ID,

  RESOURCE,

  ISINITIALRENDER,

  ELMTID,

  VIEWSTACKPROCESSOR,

  STOPGETACCESSRECORDING,

  STARTGETACCESSRECORDINGFOR,

  OBSERVECOMPONENTCREATION,

  OBSERVECOMPONENTCREATION2,

  DEEPRENDERFUNCTION,

  ITEMCREATION,

  ITEMCREATION2,

  OBSERVEDDEEPRENDER,

  ItemComponents,

  FOREACHITEMGENFUNCTION,

  __LAZYFOREACHITEMGENFUNCTION,

  _ITEM,

  FOREACHITEMIDFUNC,

  __LAZYFOREACHITEMIDFUNC,

  FOREACHUPDATEFUNCTION,

  COMPONENT_INITIAL_RENDER_FUNCTION,

  COMPONENT_REPEAT,

  REPEAT_EACH,

  REPEAT_TEMPLATE,

  LIST_ITEM,

  IFELSEBRANCHUPDATEFUNCTION,

  CARD_ENABLE_COMPONENTS,

  CARD_LOG_TYPE_COMPONENTS,

  COMPONENT_CONSTRUCTOR_PARENT,

  RESOURCE_NAME_TYPE,

  XCOMPONENT_SINGLE_QUOTATION,

  XCOMPONENT_DOUBLE_QUOTATION,

  XCOMPONENTTYPE,

  XCOMPONENTTYPE_CONTAINER,

  BIND_OBJECT_PROPERTY,

  TRUE,

  FALSE,

  HEADER,

  INDICATORBUILDER,

  FOOTER,

  CALL,

  CREATE_BIND_COMPONENT,

  TabContentAndNavDestination,

  START,

  END,

  BUILDER_PARAM_PROXY,

  BUILDER_TYPE,

  CHECK_COMPONENT_EXTEND_DECORATOR,

  CHECK_COMPONENT_ANIMATABLE_EXTEND_DECORATOR,

  RECYCLE_REUSE_ID,

  UPDATE_FUNC_BY_ELMT_ID,

  CREATE_SET_METHOD,

  CAN_RETAKE,

  PREVIEW,

  IDS,

  PUSH,

  UPDATE_LAZY_FOREACH_ELEMENTS,

  INDEX,

  IS_INITIAL_ITEM,

  MY_IDS,

  WRAPBUILDER_BUILDERPROP,

  WRAPPEDBUILDER_CLASS,

  ALL_COMPONENTS,

  ATTRIBUTE_ATTRIBUTE_MODIFIER,

  ATTRIBUTE_CONTENT_MODIFIER,

  ATTRIBUTE_MENUITEM_CONTENT_MODIFIER,

  TITLE,

  PAGE_PATH,

  RESOURCE_NAME_MODULE,

  NAV_DESTINATION,

  NAVIGATION,

  CREATE_ROUTER_COMPONENT_COLLECT,

  NAV_PATH_STACK,

  IS_USER_CREATE_STACK,

  REUSE_ATTRIBUTE,

  MUTABLEBUILDER_BUILDERPROP,

  MUTABLEBUILDER_CLASS,

  MUTABLEBUILDER_DISPATCHBUILDER,

  GLOBAL_THIS,

  APIVERSION,

  HDSNAVIGATION,

  HDSNAVDESTINATION,

  _CONTAINER_READER,

  HOVERED,

  HOVER

} from './pre_define';

import {

  INNER_COMPONENT_NAMES,

  BUILDIN_CONTAINER_COMPONENT,

  BUILDIN_STYLE_NAMES,

  CUSTOM_BUILDER_METHOD,

  GESTURE_ATTRS,

  GESTURE_TYPE_NAMES,

  EXTEND_ATTRIBUTE,

  NO_DEBUG_LINE_COMPONENT,

  NEEDPOP_COMPONENT,

  INNER_STYLE_FUNCTION,

  GLOBAL_STYLE_FUNCTION,

  CUSTOM_BUILDER_PROPERTIES,

  CUSTOM_BUILDER_PROPERTIES_WITHOUTKEY,

  CUSTOM_BUILDER_CONSTRUCTORS,

  ID_ATTRS,

  SPECIFIC_PARENT_COMPONENT,

  STYLES_ATTRIBUTE,

  INNER_CUSTOM_LOCALBUILDER_METHOD,

  COMMON_ATTRS,

  EXT_WHITE_LIST

} from './component_map';

import {

  componentCollection,

  builderParamObjectCollection,

  checkAllNode,

  enumCollection

} from './validate_ui_syntax';

import {

  processCustomComponent,

  createConditionParent,

  isRecycle,

  isReuseInV2,

  isCompatibleVersionOverTarget

} from './process_custom_component';

import {

  LogType,

  LogInfo,

  componentInfo,

  storedFileInfo,

  findNonNullType,

  CurrentProcessFile,

  hasInitialRenderCondition

} from './utils';

import {

  globalProgram,

  partialUpdateConfig,

  projectConfig

} from '../main';

import {

  transformLog,

  contextGlobal,

  validatorCard,

  builderTypeParameter,

  resourceFileName

} from './process_ui_syntax';

import { regularCollection, getSymbolIfAliased } from './validate_ui_syntax';

import { contextStackPushOrPop } from './process_component_class';

import processStructComponentV2, { StructInfo } from './process_struct_componentV2';

import logMessageCollection from './log_message_collection';

import {

  concatenateEtsOptions,

  getExternalComponentPaths

} from './external_component_map';



export function processComponentBuild(node: ts.MethodDeclaration,

  log: LogInfo[]): ts.MethodDeclaration {

  let newNode: ts.MethodDeclaration;

  let renderNode: ts.Identifier;

  if (!partialUpdateConfig.partialUpdateMode) {

    renderNode = ts.factory.createIdentifier(COMPONENT_RENDER_FUNCTION);

  } else {

    renderNode = ts.factory.createIdentifier(COMPONENT_INITIAL_RENDER_FUNCTION);

  }

  if (node.body && node.body.statements && node.body.statements.length &&

    validateRootNode(node, log)) {

    const componentBlock: ts.Block = processComponentBlock(node.body, false, log);

    newNode = ts.factory.updateMethodDeclaration(node, ts.getModifiers(node),

      node.asteriskToken, renderNode, node.questionToken, node.typeParameters, node.parameters,

      node.type, componentBlock);

    if (partialUpdateConfig.partialUpdateMode && storedFileInfo.hasLocalBuilderInFile) {

      componentBlock.statements.unshift(contextStackPushOrPop(ts.factory.createIdentifier(PUSH), [ts.factory.createThis()]));

      componentBlock.statements.push(contextStackPushOrPop(ts.factory.createIdentifier(COMPONENT_POP_FUNCTION), [])); 

    }

  } else {

    newNode = ts.factory.updateMethodDeclaration(node, ts.getModifiers(node),

      node.asteriskToken, renderNode, node.questionToken, node.typeParameters, node.parameters,

      node.type, node.body);

  }

  return newNode;

}



function createLazyForEachBlockNode(newStatements: ts.Statement[]): ts.IfStatement {

  return ts.factory.createIfStatement(

    ts.factory.createBinaryExpression(

      ts.factory.createBinaryExpression(

        ts.factory.createIdentifier(IS_INITIAL_ITEM),

        ts.factory.createToken(ts.SyntaxKind.EqualsEqualsEqualsToken),

        ts.factory.createIdentifier(COMPONENT_IF_UNDEFINED)

      ),

      ts.factory.createToken(ts.SyntaxKind.BarBarToken),

      ts.factory.createIdentifier(IS_INITIAL_ITEM)

    ),

    ts.factory.createBlock(newStatements, true),

    ts.factory.createBlock([

      ts.factory.createExpressionStatement(ts.factory.createCallExpression(

        ts.factory.createPropertyAccessExpression(

          ts.factory.createThis(),

          ts.factory.createIdentifier(UPDATE_LAZY_FOREACH_ELEMENTS)

        ), undefined, [

          ts.factory.createIdentifier(IDS),

          storedFileInfo.lazyForEachInfo.forEachParameters.name as ts.Identifier

        ]

      ))

    ], true)

  );

}



export type BuilderParamsResult = {

  firstParam: ts.ParameterDeclaration;

};



export function parseGlobalBuilderParams(parameters: ts.NodeArray<ts.ParameterDeclaration>,

  builderParamsResult: BuilderParamsResult) : void {

  if (partialUpdateConfig.partialUpdateMode && parameters.length && parameters.length === 1 &&

    ts.isIdentifier(parameters[0].name)) {

    builderParamsResult.firstParam = parameters[0];

  }

}



export function processComponentBlock(node: ts.Block, isLazy: boolean, log: LogInfo[],

  isTransition: boolean = false, isBuilder: boolean = false, parent: string = undefined,

  forEachParameters: ts.NodeArray<ts.ParameterDeclaration> = undefined,

  isGlobalBuilder: boolean = false, builderParamsResult: BuilderParamsResult = null,

  rootGlobalBuilder: boolean = false, isInRepeatTemplate: boolean = false): ts.Block {

  const newStatements: ts.Statement[] = [];

  processComponentChild(node, newStatements, log, {isAcceleratePreview: false, line: 0, column: 0, fileName: ''},

    isBuilder, parent, forEachParameters, isGlobalBuilder, isTransition, builderParamsResult, isInRepeatTemplate);

  if (isLazy && !partialUpdateConfig.partialUpdateMode) {

    newStatements.unshift(createRenderingInProgress(true));

  }

  if (isTransition) {

    if (!partialUpdateConfig.partialUpdateMode) {

      newStatements.unshift(ts.factory.createExpressionStatement(

        createFunction(ts.factory.createIdentifier(COMPONENT_TRANSITION_NAME),

          ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION), null)));

    } else {

      newStatements.unshift(createComponentCreationStatement(ts.factory.createExpressionStatement(

        createFunction(ts.factory.createIdentifier(COMPONENT_TRANSITION_NAME),

          ts.factory.createIdentifier(COMPONENT_POP_FUNCTION), null)), [ts.factory.createExpressionStatement(

        createFunction(ts.factory.createIdentifier(COMPONENT_TRANSITION_NAME),

          ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION), null))], COMPONENT_TRANSITION_NAME, false, isTransition));

    }

    newStatements.push(ts.factory.createExpressionStatement(

      createFunction(ts.factory.createIdentifier(COMPONENT_TRANSITION_NAME),

        ts.factory.createIdentifier(COMPONENT_POP_FUNCTION), null)));

  }

  if (isLazy && !partialUpdateConfig.partialUpdateMode) {

    newStatements.push(createRenderingInProgress(false));

  }

  if (rootGlobalBuilder && isGlobalBuilder && builderParamsResult && builderParamsResult.firstParam) {

    newStatements.unshift(forkBuilderParamNode(builderParamsResult.firstParam));

  }

  if (isLazy && projectConfig.optLazyForEach && storedFileInfo.processLazyForEach &&

    storedFileInfo.lazyForEachInfo.forEachParameters) {

    return ts.factory.updateBlock(node, [

      createMyIdsNode(),

      createLazyForEachBlockNode(newStatements),

      ts.factory.createReturnStatement(ts.factory.createIdentifier(MY_IDS))

    ]);

  }

  return ts.factory.updateBlock(node, newStatements);

}



function createMyIdsNode(): ts.Statement {

  return ts.factory.createVariableStatement(

    undefined,

    ts.factory.createVariableDeclarationList(

      [ts.factory.createVariableDeclaration(

        ts.factory.createIdentifier(MY_IDS),

        undefined,

        undefined,

        ts.factory.createArrayLiteralExpression(

          [],

          false

        )

      )],

      ts.NodeFlags.Const

    )

  );

}



function visitComponent(node: ts.Node): void {

  if (storedFileInfo.lazyForEachInfo && !ts.isBlock(node)) {

    ts.forEachChild(node, (child: ts.Node) => {

      if (storedFileInfo.lazyForEachInfo.isDependItem) {

        return;

      }

      if (ts.isIdentifier(child)) {

        const symbol: ts.Symbol = CurrentProcessFile.getChecker()?.getSymbolAtLocation(child);

        if (symbol && symbol.valueDeclaration === storedFileInfo.lazyForEachInfo.forEachParameters) {

          storedFileInfo.lazyForEachInfo.isDependItem = true;

          return;

        }

      }

      visitComponent(child);

    });

  }

}



function forkBuilderParamNode(node: ts.ParameterDeclaration): ts.Statement {

  const paramNode: ts.Identifier = node.name as ts.Identifier;

  return ts.factory.createVariableStatement(

    undefined,

    ts.factory.createVariableDeclarationList(

      [ts.factory.createVariableDeclaration(

        ts.factory.createIdentifier(`__${paramNode.escapedText.toString()}__`),

        undefined,

        undefined,

        paramNode

      )],

      ts.NodeFlags.Const

    )

  );

}



function validateRootNode(node: ts.MethodDeclaration, log: LogInfo[]): boolean {

  let isValid: boolean = false;

  if (node.body.statements.length === 1) {

    const statement: ts.Statement = node.body.statements[0];

    if (ts.isIfStatement(statement) || validateFirstNode(statement)) {

      isValid = true;

    }

  } else {

    isValid = false;

  }

  if (!isValid) {

    log.push({

      type: LogType.ERROR,

      message: `In an '@Entry' decorated component, the 'build' method can have only one root node,` +

        ` which must be a container component.`,

      pos: node.body.statements.pos,

      code: '10905210'

    });

  }

  return isValid;

}



function validateFirstNode(node: ts.Statement): boolean {

  const isEntryComponent: boolean =

    componentCollection.entryComponent === componentCollection.currentClassName;

  if (isEntryComponent && !validateContainerComponent(node)) {

    return false;

  }

  return true;

}



function validateContainerComponent(node: ts.Statement): boolean {

  if (ts.isExpressionStatement(node) && node.expression &&

    (ts.isEtsComponentExpression(node.expression) || ts.isCallExpression(node.expression))) {

    const nameResult: NameResult = { name: null, node: null, arguments: [] };

    validateEtsComponentNode(node.expression, nameResult);

    if (nameResult.name && checkContainer(nameResult.name, nameResult.node)) {

      return true;

    }

  }

  return false;

}



interface supplementType {

  isAcceleratePreview: boolean,

  line: number,

  column: number,

  fileName: string

}



let newsupplement: supplementType = {

  isAcceleratePreview: false,

  line: 0,

  column: 0,

  fileName: ''

};



type NameResult = {

  name: string,

  arguments: ts.NodeArray<ts.Expression> | [],

  node?: ts.Node

};



function validateEtsComponentNode(node: ts.CallExpression | ts.EtsComponentExpression, result?: NameResult): boolean {

  let childNode: ts.Node = node;

  result.name = null;

  while (ts.isCallExpression(childNode) && childNode.expression &&

    ts.isPropertyAccessExpression(childNode.expression) && childNode.expression.expression) {

    childNode = childNode.expression.expression;

  }

  if (ts.isEtsComponentExpression(childNode)) {

    if (ts.isIdentifier(childNode.expression)) {

      result.name = childNode.expression.getText();

      result.node = childNode;

      result.arguments = childNode.arguments || [];

    }

    return true;

  } else {

    return false;

  }

}



let sourceNode: ts.SourceFile;



export function processComponentChild(node: ts.Block | ts.SourceFile, newStatements: ts.Statement[],

  log: LogInfo[], supplement: supplementType = {isAcceleratePreview: false, line: 0, column: 0, fileName: ''},

  isBuilder: boolean = false, parent: string = undefined,

  forEachParameters: ts.NodeArray<ts.ParameterDeclaration> = undefined, isGlobalBuilder: boolean = false,

  isTransition: boolean = false, builderParamsResult: BuilderParamsResult = null,

  isInRepeatTemplate: boolean = false): void {

  if (supplement.isAcceleratePreview) {

    newsupplement = supplement;

    let compilerOptions = ts.readConfigFile(

      path.resolve(__dirname, '../tsconfig.json'), ts.sys.readFile).config.compilerOptions;

    const componentPaths: string[] | undefined = getExternalComponentPaths();

    if (componentPaths) {

      for (const componentPath of componentPaths) {

        if (!fs.existsSync(componentPath)) {

          continue;

        }

        const externalCompilerOptions: ts.CompilerOptions = ts.readConfigFile(

          path.resolve(componentPath, 'externalconfig.json'), ts.sys.readFile

        ).config.compilerOptions;

        concatenateEtsOptions(compilerOptions, externalCompilerOptions);

      }

    }

    Object.assign(compilerOptions, {

      'sourceMap': false

    });

    sourceNode = ts.createSourceFile('', node.getText(), ts.ScriptTarget.Latest, true, ts.ScriptKind.ETS, compilerOptions);

  }

  if (node.statements.length) {

    // Save parent component

    const savedParent: string = parent;

    node.statements.forEach((item) => {

      if (ts.isExpressionStatement(item)) {

        assignParameter(forEachParameters, item);

        checkEtsComponent(item, log);

        const name: string = getName(item);

        if (CARD_ENABLE_COMPONENTS.has(name)) {

          validatorCard(log, CARD_LOG_TYPE_COMPONENTS, item.getStart(), name);

        }

        switch (getComponentType(item, log, name, parent, forEachParameters)) {

          case ComponentType.innerComponent: {

            const [etsExpression, idName]: [ts.EtsComponentExpression, ts.Expression] =

              checkEtsAndIdInIf(item, savedParent);

            if (ts.isIdentifier(etsExpression.expression)) {

              parent = etsExpression.expression.escapedText.toString();

            }

            processInnerComponent(item, newStatements, log, parent, isBuilder, isGlobalBuilder,

              isTransition, idName, savedParent, builderParamsResult, isInRepeatTemplate);

            break;

          }

          case ComponentType.customComponent: {

            const idName: ts.Expression = checkIdInIf(item, savedParent);

            parent = undefined;

            if (!newsupplement.isAcceleratePreview) {

              if (item.expression && ts.isEtsComponentExpression(item.expression) && item.expression.body) {

                const expressionResult: ts.ExpressionStatement =

                  processExpressionStatementChange(item, item.expression.body, log);

                if (expressionResult) {

                  item = expressionResult;

                }

              }

              processCustomComponent(item as ts.ExpressionStatement, newStatements, log, name,

                isBuilder, isGlobalBuilder, idName, builderParamsResult, isInRepeatTemplate);

            }

            break;

          }

          case ComponentType.forEachComponent:

            parent = undefined;

            if (!partialUpdateConfig.partialUpdateMode) {

              processForEachComponent(item, newStatements, log, isBuilder, isGlobalBuilder);

            } else {

              processForEachComponentNew(item, newStatements, log, name, isGlobalBuilder, builderParamsResult, isInRepeatTemplate);

            }

            break;

          case ComponentType.repeatComponent:

            parent = undefined;

            processRepeatComponent(item, newStatements, log, isBuilder, isGlobalBuilder, isTransition, builderParamsResult, isInRepeatTemplate);

            break;

          case ComponentType.customBuilderMethod:

            parent = undefined;

            if (partialUpdateConfig.partialUpdateMode) {

              newStatements.push(transferBuilderCall(item, name, isBuilder));

            } else {

              newStatements.push(addInnerBuilderParameter(item, isGlobalBuilder));

            }

            break;

          case ComponentType.mutableBuilderMethod:

            parent = undefined;

            if (partialUpdateConfig.partialUpdateMode) {

              newStatements.push(transferMutableBuilderCall(item, name));

            }

            break;

          case ComponentType.builderParamMethod:

            parent = undefined;

            if (partialUpdateConfig.partialUpdateMode) {

              newStatements.push(transferBuilderCall(item, name, isBuilder));

            } else {

              newStatements.push(addInnerBuilderParameter(item));

            }

            break;

          case ComponentType.builderTypeFunction:

            parent = undefined;

            if (partialUpdateConfig.partialUpdateMode) {

              newStatements.push(transferBuilderCall(item, name, isBuilder));

            } else {

              newStatements.push(addInnerBuilderParameter(item));

            }

            break;

          case ComponentType.function:

            parent = undefined;

            newStatements.push(item);

            break;

        }

      } else if (ts.isIfStatement(item)) {

        assignParameter(forEachParameters, item);

        processIfStatement(item, newStatements, log, isBuilder, isGlobalBuilder, builderParamsResult, isInRepeatTemplate);

      } else if (!ts.isBlock(item)) {

        log.push({

          type: LogType.ERROR,  

          message: `Only UI component syntax can be written here.`,

          pos: item.getStart(),

          code: '10905209'

        });

      }

      storedFileInfo.lazyForEachInfo.isDependItem = false;

    });

  }

  if (supplement.isAcceleratePreview) {

    newsupplement = {

      isAcceleratePreview: false,

      line: 0,

      column: 0,

      fileName: ''

    };

  }

}



function assignParameter(forEachParameters: ts.NodeArray<ts.ParameterDeclaration>, item: ts.Node): void {

  if (partialUpdateConfig.partialUpdateMode && projectConfig.optLazyForEach &&

    storedFileInfo.processLazyForEach) {

    if (forEachParameters && forEachParameters[0]) {

      storedFileInfo.lazyForEachInfo.forEachParameters = forEachParameters[0];

    }

    if (storedFileInfo.lazyForEachInfo.forEachParameters) {

      visitComponent(item);

    }

  }

}



export function transferBuilderCall(node: ts.ExpressionStatement, name: string,

  isBuilder: boolean = false): ts.ExpressionStatement {

  if (node.expression && ts.isCallExpression(node.expression)) {

    let newNode: ts.Expression = builderCallNode(node.expression);

    newNode.expression.questionDotToken = node.expression.questionDotToken;

    if (node.expression.arguments && node.expression.arguments.length === 1 && ts.isObjectLiteralExpression(node.expression.arguments[0])) {

      return ts.factory.createExpressionStatement(ts.factory.updateCallExpression(

        node.expression,

        newNode,

        undefined,

        [ts.factory.createCallExpression(

          ts.factory.createIdentifier(BUILDER_PARAM_PROXY),

          undefined,

          [

            ts.factory.createStringLiteral(name),

            traverseBuilderParams(node.expression.arguments[0], isBuilder)

          ]

        )]

      ));

    } else {

      return ts.factory.createExpressionStatement(ts.factory.updateCallExpression(

        node.expression,

        newNode,

        undefined,

        !(projectConfig.optLazyForEach && (storedFileInfo.processLazyForEach &&

          storedFileInfo.lazyForEachInfo.forEachParameters || isBuilder)) ? node.expression.arguments :

          [...node.expression.arguments, ts.factory.createNull(), ts.factory.createIdentifier(MY_IDS)]

      ));

    }

  }

  return undefined;

}



function builderCallNode(node: ts.CallExpression): ts.Expression {

  let newNode: ts.Expression;

  if (node.expression && ts.isPropertyAccessExpression(node.expression) &&

    node.expression.questionDotToken && node.expression.questionDotToken.kind === ts.SyntaxKind.QuestionDotToken) {

    newNode = ts.factory.createCallChain(

      ts.factory.createPropertyAccessChain(

        node.expression,

        node.questionDotToken,

        ts.factory.createIdentifier(BUILDER_ATTR_BIND)

      ),

      undefined,

      undefined,

      [ts.factory.createThis()]

    );

  } else {

    newNode = ts.factory.createCallExpression(

      ts.factory.createPropertyAccessExpression(

        node.expression,

        ts.factory.createIdentifier(BUILDER_ATTR_BIND)

      ),

      undefined,

      [ts.factory.createThis()]

    );

  }

  return newNode;

}



function traverseBuilderParams(node: ts.ObjectLiteralExpression,

  isBuilder: boolean): ts.ObjectLiteralExpression {

  const properties: ts.ObjectLiteralElementLike[] = [];

  if (node.properties && node.properties.length) {

    node.properties.forEach(property => {

      if (ts.isPropertyAssignment(property) && property.initializer &&

        ts.isPropertyAccessExpression(property.initializer) && property.initializer.expression &&

        property.initializer.name && ts.isIdentifier(property.initializer.name)) {

        const name: string = property.initializer.name.escapedText.toString();

        if (!storedFileInfo.processGlobalBuilder && property.initializer.expression.kind === ts.SyntaxKind.ThisKeyword ||

          isBuilder && ts.isIdentifier(property.initializer.expression) &&

          property.initializer.expression.escapedText.toString() === $$) {

          const useThis: boolean = property.initializer.expression.kind === ts.SyntaxKind.ThisKeyword;

          addProperties(properties, property, name, isBuilder, useThis);

        } else {

          addBuilderParamsProperties(properties, property);

        }

      } else {

        addBuilderParamsProperties(properties, property);

      }

    });

  }

  return ts.factory.createObjectLiteralExpression(properties);

}



function addBuilderParamsProperties(properties: ts.ObjectLiteralElementLike[],

  property: ts.ObjectLiteralElementLike): void {

  const initializer: ts.Expression = ts.isShorthandPropertyAssignment(property) ?

    property.name : property.initializer;

  properties.push(ts.factory.createPropertyAssignment(

    property.name,

    ts.factory.createArrowFunction(

      undefined,

      undefined,

      [],

      undefined,

      ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),

      initializer

    )

  ));

}



function addProperties(properties: ts.ObjectLiteralElementLike[], property: ts.ObjectLiteralElementLike,

  name: string, isBuilder: boolean, useThis: boolean): void {

  properties.push(ts.factory.createPropertyAssignment(

    property.name,

    ts.factory.createArrowFunction(

      undefined,

      undefined,

      [],

      undefined,

      ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),

      ts.factory.createParenthesizedExpression(ts.factory.createConditionalExpression(

        ts.factory.createElementAccessExpression(

          (isBuilder && !useThis) ? ts.factory.createIdentifier($$) : ts.factory.createThis(),

          ts.factory.createStringLiteral('__' + name)

        ),

        ts.factory.createToken(ts.SyntaxKind.QuestionToken),

        ts.factory.createElementAccessExpression(

          (isBuilder && !useThis) ? ts.factory.createIdentifier($$) : ts.factory.createThis(),

          ts.factory.createStringLiteral('__' + name)

        ),

        ts.factory.createToken(ts.SyntaxKind.ColonToken),

        ts.factory.createElementAccessExpression(

          (isBuilder && !useThis) ? ts.factory.createIdentifier($$) : ts.factory.createThis(),

          ts.factory.createStringLiteral(name)

        )

      ))

    )

  ));

}



function addInnerBuilderParameter(node: ts.ExpressionStatement,

  isGlobalBuilder: boolean = false): ts.ExpressionStatement {

  if (node.expression && ts.isCallExpression(node.expression) && node.expression.arguments) {

    node.expression.arguments.push(isGlobalBuilder ? parentConditionalExpression() : ts.factory.createThis());

    return ts.factory.createExpressionStatement(ts.factory.updateCallExpression(node.expression,

      node.expression.expression, node.expression.typeArguments, node.expression.arguments));

  } else {

    return node;

  }

}



function processExpressionStatementChange(node: ts.ExpressionStatement, nextNode: ts.Block,

  log: LogInfo[]): ts.ExpressionStatement {

  let name: string;

  // @ts-ignore

  if (node.expression.expression && ts.isIdentifier(node.expression.expression)) {

    name = node.expression.expression.escapedText.toString();

  } else if (node.expression.expression && ts.isPropertyAccessExpression(node.expression.expression)) {

    name = node.expression.expression.getText();

  }

  if (builderParamObjectCollection.get(name) &&

    builderParamObjectCollection.get(name).size === 1) {

    return processBlockToExpression(node, nextNode, log, name, false);

  } else if (projectConfig.compileMode === 'esmodule' && process.env.compileTool === 'rollup' &&

    storedFileInfo.overallBuilderParamCollection.get(name) &&

    storedFileInfo.overallBuilderParamCollection.get(name).size === 1

  ) {

    return processBlockToExpression(node, nextNode, log, name, true);

  } else {

    log.push({

      type: LogType.ERROR,

      message: `In the trailing lambda case, '${name}' must have one and only one property decorated with ` +

        `'@BuilderParam'.`,

      pos: node.getStart(),

      code: '10905102'

    });

    return null;

  }

}



function processBlockToExpression(node: ts.ExpressionStatement, nextNode: ts.Block,

  log: LogInfo[], name: string, isPropertyAccessExpressionNode: boolean): ts.ExpressionStatement {

  const childParam: string = isPropertyAccessExpressionNode ? [...storedFileInfo.overallBuilderParamCollection.get(name)].slice(-1)[0] :

    [...builderParamObjectCollection.get(name)].slice(-1)[0];

  const newBlock: ts.Block = processComponentBlock(nextNode, false, log);

  const arrowNode: ts.ArrowFunction = ts.factory.createArrowFunction(undefined, undefined,

    [], undefined, ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), newBlock);

  const newPropertyAssignment:ts.PropertyAssignment = ts.factory.createPropertyAssignment(

    ts.factory.createIdentifier(childParam), arrowNode);

  // @ts-ignore

  let argumentsArray: ts.ObjectLiteralExpression[] = node.expression.arguments;

  if (argumentsArray && !argumentsArray.length) {

    argumentsArray = [ts.factory.createObjectLiteralExpression([newPropertyAssignment], true)];

  } else if (ts.isObjectLiteralExpression(argumentsArray[0]) && argumentsArray.length === 1) {

    argumentsArray = [ts.factory.createObjectLiteralExpression(

      // @ts-ignore

      node.expression.arguments[0].properties.concat([newPropertyAssignment]), true)];

  } else if (ts.isObjectLiteralExpression(argumentsArray[0]) && argumentsArray.length === 2) {

    argumentsArray = [ts.factory.createObjectLiteralExpression(

      // @ts-ignore

      node.expression.arguments[0].properties.concat([newPropertyAssignment]), true), argumentsArray[1]];

  }

  const callNode: ts.CallExpression = ts.factory.updateCallExpression(

    // @ts-ignore

    node.expression, node.expression.expression, node.expression.expression.typeArguments,

    argumentsArray);

  // @ts-ignore

  node.expression.expression.parent = callNode;

  // @ts-ignore

  callNode.parent = node.expression.parent;

  node = ts.factory.updateExpressionStatement(node, callNode);

  return node;

}



type EtsComponentResult = {

  etsComponentNode: ts.EtsComponentExpression;

  hasAttr: boolean;

};

function parseEtsComponentExpression(node: ts.ExpressionStatement): EtsComponentResult {

  let etsComponentNode: ts.EtsComponentExpression;

  let hasAttr: boolean = false;

  let temp: any = node.expression;

  while (temp) {

    if (ts.isCallExpression(temp) && temp.expression &&

      ts.isPropertyAccessExpression(temp.expression)) {

      hasAttr = true;

    }

    if (ts.isEtsComponentExpression(temp)) {

      etsComponentNode = temp;

      break;

    }

    temp = temp.expression;

  }

  return { etsComponentNode: etsComponentNode, hasAttr: hasAttr };

}



export function createCollectElmtIdNode(): ts.ExpressionStatement {

  return ts.factory.createExpressionStatement(ts.factory.createCallExpression(

    ts.factory.createPropertyAccessExpression(

      ts.factory.createIdentifier(MY_IDS),

      ts.factory.createIdentifier(PUSH)

    ),

    undefined,

    [ts.factory.createIdentifier(ELMTID)]

  ));

}



function processInnerComponent(node: ts.ExpressionStatement, innerCompStatements: ts.Statement[],

  log: LogInfo[], parent: string = undefined, isBuilder: boolean = false, isGlobalBuilder: boolean = false,

  isTransition: boolean = false, idName: ts.Expression = undefined, savedParent: string = undefined,

  builderParamsResult: BuilderParamsResult = null, isInRepeatTemplate: boolean = false): void {

  const newStatements: ts.Statement[] = [];

  const res: CreateResult = createComponent(node, COMPONENT_CREATE_FUNCTION);

  newStatements.push(res.newNode);

  const nameResult: NameResult = { name: null, arguments: [] };

  validateEtsComponentNode(node.expression as ts.EtsComponentExpression, nameResult);

  if (savedParent && nameResult.name) {

    checkNonspecificParents(node, nameResult.name, savedParent, log);

  }

  if (partialUpdateConfig.partialUpdateMode && ItemComponents.includes(nameResult.name)) {

    processItemComponent(node, nameResult, innerCompStatements, log, parent, isGlobalBuilder, idName, builderParamsResult, isInRepeatTemplate);

  } else if (partialUpdateConfig.partialUpdateMode && TabContentAndNavDestination.has(nameResult.name)) {

    processTabAndNav(node, innerCompStatements, nameResult, log, parent, isGlobalBuilder, idName, builderParamsResult, isInRepeatTemplate);

  } else {

    processNormalComponent(node, nameResult, innerCompStatements, log, parent, isBuilder, isGlobalBuilder,

      isTransition, idName, builderParamsResult, isInRepeatTemplate);

  }

}



function processNormalComponent(node: ts.ExpressionStatement, nameResult: NameResult,

  innerCompStatements: ts.Statement[], log: LogInfo[], parent: string = undefined, isBuilder: boolean = false,

  isGlobalBuilder: boolean = false, isTransition: boolean = false, idName: ts.Expression = undefined,

  builderParamsResult: BuilderParamsResult = null, isInRepeatTemplate: boolean = false): void {

  const newStatements: ts.Statement[] = [];

  if (addElmtIdNode()) {

    newStatements.push(createCollectElmtIdNode());

  }

  const immutableStatements: ts.Statement[] = [];

  const res: CreateResult = createComponent(node, COMPONENT_CREATE_FUNCTION);

  if (nameResult.name !== _CONTAINER_READER) {

    newStatements.push(res.newNode);

    processDebug(node, nameResult, newStatements);

  }

  const etsComponentResult: EtsComponentResult = parseEtsComponentExpression(node);

  const componentName: string = res.identifierNode.getText();

  let judgeIdStart: number;

  if (partialUpdateConfig.partialUpdateMode && idName) {

    judgeIdStart = innerCompStatements.length;

  }

  if (etsComponentResult.etsComponentNode.body && ts.isBlock(etsComponentResult.etsComponentNode.body)) {

    processNormalComponentBlock(

      node, res, etsComponentResult, log, newStatements, componentName,

      immutableStatements, innerCompStatements, isGlobalBuilder, isTransition,

      builderParamsResult, isBuilder, parent, isInRepeatTemplate, nameResult

    );

  } else {

    if (componentName !== _CONTAINER_READER) {

      bindComponentAttr(node, res.identifierNode, newStatements, log, true, false, immutableStatements);

      processInnerCompStatements(innerCompStatements, newStatements, node, isGlobalBuilder,

      isTransition, undefined, immutableStatements, componentName, builderParamsResult);

    } else {

      const containerReaderRes: CreateResult = createComponent(node, COMPONENT_CREATE_FUNCTION);

      newStatements.push(containerReaderRes.newNode);

      processDebug(node, nameResult, newStatements);

      bindComponentAttr(node, res.identifierNode, newStatements, log, true, false, immutableStatements);

      processInnerCompStatements(innerCompStatements, newStatements, node, isGlobalBuilder,

      isTransition, undefined, immutableStatements, componentName, builderParamsResult);

    }

  }

  if (res.isContainerComponent || res.needPop) {

    innerCompStatements.push(createComponent(node, COMPONENT_POP_FUNCTION).newNode);

  }

  if (partialUpdateConfig.partialUpdateMode && idName) {

    innerCompStatements.splice(judgeIdStart, innerCompStatements.length - judgeIdStart,

      ifRetakeId(innerCompStatements.slice(judgeIdStart), idName));

  }

}



function processNormalComponentBlock(

  node: ts.ExpressionStatement,

  res: CreateResult,

  etsComponentResult: EtsComponentResult,

  log: LogInfo[],

  newStatements: ts.Statement[],

  componentName: string,

  immutableStatements: ts.Statement[],

  innerCompStatements: ts.Statement[],

  isGlobalBuilder: boolean,

  isTransition: boolean,

  builderParamsResult: BuilderParamsResult,

  isBuilder: boolean,

  parent: string,

  isInRepeatTemplate: boolean,

  nameResult: NameResult

): void {

  if (res.isButton) {

    checkButtonParamHasLabel(etsComponentResult.etsComponentNode, log);

    if (projectConfig.isPreview || projectConfig.enableDebugLine) {

      newStatements.splice(-2, 1, createComponent(node, COMPONENT_CREATE_CHILD_FUNCTION).newNode);

    } else {

      newStatements.splice(-1, 1, createComponent(node, COMPONENT_CREATE_CHILD_FUNCTION).newNode);

    }

  }

  if (etsComponentResult.hasAttr && componentName !== _CONTAINER_READER) {

    bindComponentAttr(node, res.identifierNode, newStatements, log, true, false, immutableStatements);

  }

  if (componentName !== _CONTAINER_READER) {

    processInnerCompStatements(innerCompStatements, newStatements, node, isGlobalBuilder,

      isTransition, undefined, immutableStatements, componentName, builderParamsResult);

    storedFileInfo.lazyForEachInfo.isDependItem = false;

    processComponentChild(etsComponentResult.etsComponentNode.body, innerCompStatements, log,

      { isAcceleratePreview: false, line: 0, column: 0, fileName: '' }, isBuilder, parent, undefined,

      isGlobalBuilder, false, builderParamsResult, isInRepeatTemplate);

    return;

  }

  const containerReaderStatements: ts.Statement[] = [];

  processComponentChild(etsComponentResult.etsComponentNode.body, containerReaderStatements, log,

    { isAcceleratePreview: false, line: 0, column: 0, fileName: '' }, isBuilder, parent, undefined,

    isGlobalBuilder, false, builderParamsResult, isInRepeatTemplate);

  const containerReaderRes: CreateResult = createComponent(node, COMPONENT_CREATE_FUNCTION,

    containerReaderStatements);

  newStatements.push(containerReaderRes.newNode);

  processDebug(node, nameResult, newStatements);

  if (etsComponentResult.hasAttr) {

    bindComponentAttr(node, res.identifierNode, newStatements, log, true, false, immutableStatements);

  }

  processInnerCompStatements(innerCompStatements, newStatements, node, isGlobalBuilder,

    isTransition, undefined, immutableStatements, componentName, builderParamsResult);

  storedFileInfo.lazyForEachInfo.isDependItem = false;

}



export function ifRetakeId(blockContent: ts.Statement[], idName: ts.Expression): ts.IfStatement {

  return ts.factory.createIfStatement(

    ts.factory.createPrefixUnaryExpression(

      ts.SyntaxKind.ExclamationToken,

      ts.factory.createCallExpression(

        ts.factory.createPropertyAccessExpression(

          ts.factory.createIdentifier(COMPONENT_IF),

          ts.factory.createIdentifier(CAN_RETAKE)

        ),

        undefined,

        [idName]

      )

    ),

    ts.factory.createBlock(

      blockContent,

      true

    ),

    undefined

  );

}



function processRepeatComponent(node: ts.ExpressionStatement, innerCompStatements: ts.Statement[],

  log: LogInfo[], isBuilder: boolean = false, isGlobalBuilder: boolean = false,

  isTransition: boolean = false, builderParamsResult: BuilderParamsResult = null,

  isInRepeatTemplate: boolean = false): void {

  const chainCallTransform: ts.CallExpression =

    recurseRepeatExpression(node.expression as ts.CallExpression, log, isBuilder, isGlobalBuilder,

      isTransition, isInRepeatTemplate) as ts.CallExpression;

  innerCompStatements.push(createComponentCreationStatement(node,

    [ts.factory.createExpressionStatement(ts.factory.createCallExpression(

      ts.factory.createPropertyAccessExpression(

        chainCallTransform,

        ts.factory.createIdentifier(COMPONENT_RENDER_FUNCTION)

      ),

      undefined,

      [ts.factory.createIdentifier(ISINITIALRENDER)]

    ))], COMPONENT_REPEAT, isGlobalBuilder, isTransition, undefined, null, builderParamsResult));

}



function recurseRepeatExpression(node: ts.CallExpression | ts.PropertyAccessExpression,

  log: LogInfo[], isBuilder: boolean = false, isGlobalBuilder: boolean = false, isTransition: boolean = false, isInRepeatTemplate: boolean = false):

  ts.PropertyAccessExpression | ts.CallExpression {

  if (ts.isCallExpression(node) && node.expression && ts.isIdentifier(node.expression) &&

    node.expression.getText() === COMPONENT_REPEAT) {

    return ts.factory.createCallExpression(node.expression, node.typeArguments, [...node.arguments, ts.factory.createThis()]);

  } else if (ts.isPropertyAccessExpression(node)) {

    return ts.factory.updatePropertyAccessExpression(node,

      recurseRepeatExpression(node.expression, log, isBuilder, isGlobalBuilder, isTransition, isInRepeatTemplate), node.name);

  } else {

    let repeatPropArgs: ts.ArrowFunction[] = processRepeatAttributeArrowNode(node.arguments);

    storedFileInfo.processRepeat = true;

    repeatPropArgs = processRepeatPropWithChild(node, repeatPropArgs, log, isBuilder, isGlobalBuilder, isTransition, isInRepeatTemplate);

    storedFileInfo.processRepeat = false;

    return ts.factory.updateCallExpression(node,

      recurseRepeatExpression(node.expression as ts.PropertyAccessExpression, log, isBuilder,

        isGlobalBuilder, isTransition, isInRepeatTemplate) as ts.PropertyAccessExpression, undefined, repeatPropArgs);

  }

}



function processRepeatPropWithChild(node: ts.CallExpression, repeatPropArgs: ts.ArrowFunction[],

  log: LogInfo[], isBuilder: boolean = false, isGlobalBuilder: boolean = false, isTransition: boolean = false,

  isInRepeatTemplate: boolean = false): ts.ArrowFunction[] {

  if (ts.isPropertyAccessExpression(node.expression) && ts.isIdentifier(node.expression.name) &&

    node.expression.name.getText() === REPEAT_EACH && repeatPropArgs.length > 0 && repeatPropArgs[0].body) {

    // transfer args for each property

    return [

      ts.factory.updateArrowFunction(repeatPropArgs[0], repeatPropArgs[0].modifiers, repeatPropArgs[0].typeParameters,

        repeatPropArgs[0].parameters, repeatPropArgs[0].type, repeatPropArgs[0].equalsGreaterThanToken,

        processComponentBlock(processRepeatCallBackBlock(repeatPropArgs[0]), false, log, isTransition,

          isBuilder, undefined, undefined, isGlobalBuilder, null, false, isInRepeatTemplate)),

      ...repeatPropArgs.slice(1)

    ];

  } else if (ts.isPropertyAccessExpression(node.expression) && ts.isIdentifier(node.expression.name) &&

    node.expression.name.getText() === REPEAT_TEMPLATE && repeatPropArgs.length > 1 && repeatPropArgs[1].body) {

    // transfer args for template property

    return [

      repeatPropArgs[0], ts.factory.updateArrowFunction(repeatPropArgs[1], repeatPropArgs[1].modifiers, repeatPropArgs[1].typeParameters,

        repeatPropArgs[1].parameters, repeatPropArgs[1].type, repeatPropArgs[1].equalsGreaterThanToken,

        processComponentBlock(processRepeatCallBackBlock(repeatPropArgs[1]), false, log, isTransition, isBuilder, undefined, undefined,

          isGlobalBuilder, null, false, true)),

      ...repeatPropArgs.slice(2)

    ];

  }

  return repeatPropArgs;

}



function processRepeatCallBackBlock(repeatPropArg: ts.ArrowFunction): ts.Block {

  if (ts.isBlock(repeatPropArg.body)) {

    return repeatPropArg.body;

  } else {

    return ts.factory.updateArrowFunction(repeatPropArg, ts.getModifiers(repeatPropArg), repeatPropArg.typeParameters,

      repeatPropArg.parameters, repeatPropArg.type, repeatPropArg.equalsGreaterThanToken,

      ts.factory.createBlock([ts.factory.createExpressionStatement(repeatPropArg.body)], true)).body as ts.Block;

  }

}



function processRepeatAttributeArrowNode(argumentsNode: ts.ArrowFunction[]): ts.ArrowFunction[] {

  for (let i = 0; i < argumentsNode.length; i++) {

    while (ts.isParenthesizedExpression(argumentsNode[i])) {

      if (ts.isArrowFunction(argumentsNode[i].expression)) {

        argumentsNode.splice(i, 1, argumentsNode[i].expression);

        break;

      } else {

        if (argumentsNode[i].expression) {

          argumentsNode[i] = argumentsNode[i].expression;

        } else {

          break;

        }

      }

    }

  }

  return argumentsNode;

}



function processDebug(node: ts.Statement, nameResult: NameResult, newStatements: ts.Statement[],

  getNode: boolean = false): ts.ExpressionStatement {

  if ((projectConfig.isPreview || projectConfig.enableDebugLine) && nameResult.name &&

    !NO_DEBUG_LINE_COMPONENT.has(nameResult.name)) {

    let posOfNode: ts.LineAndCharacter;

    let curFileName: string;

    let line: number = 1;

    let col: number = 1;

    if (sourceNode && newsupplement.isAcceleratePreview) {

      posOfNode = sourceNode.getLineAndCharacterOfPosition(getRealNodePos(node) - 22);

      curFileName = newsupplement.fileName;

      if (posOfNode.line === 0) {

        col = newsupplement.column - 1;

      }

      line = newsupplement.line;

    } else {

      posOfNode = transformLog.sourceFile.getLineAndCharacterOfPosition(getRealNodePos(node));

      curFileName = transformLog.sourceFile.fileName.replace(/\.ts$/, '');

    }

    let debugInfo: string;

    if (projectConfig.isPreview) {

      if (projectConfig.minAPIVersion >= APIVERSION.apiVersionEleven) {

        debugInfo = `${path.relative(projectConfig.projectRootPath, curFileName).replace(/\\+/g, '/')}` +

          `(${posOfNode.line + line}:${posOfNode.character + col})`;

      } else {

        debugInfo = `${path.relative(projectConfig.projectPath, curFileName).replace(/\\+/g, '/')}` +

          `(${posOfNode.line + line}:${posOfNode.character + col})`;

      }

    } else if (projectConfig.enableDebugLine) {

      debugInfo = `${path.relative(projectConfig.projectRootPath, curFileName)}` +

        `(${posOfNode.line + line}:${posOfNode.character + col})`;

    }

    const debugNode: ts.ExpressionStatement = ts.factory.createExpressionStatement(

      createFunction(ts.factory.createIdentifier(nameResult.name),

        ts.factory.createIdentifier(COMPONENT_DEBUGLINE_FUNCTION),

        createDebugLineArgs(debugInfo)));

    if (getNode) {

      return debugNode;

    }

    newStatements.push(debugNode);

  }

  return undefined;

}



function createDebugLineArgs(debugInfo: string): ts.NodeArray {

  const argsArr: ts.Node[] = [ts.factory.createStringLiteral(debugInfo)];

  const pkgName: string = storedFileInfo.getCurrentArkTsFile().pkgName;

  if (pkgName) {

    argsArr.push(ts.factory.createStringLiteral(pkgName));

  }

  return ts.factory.createNodeArray(argsArr);

}



function processInnerCompStatements(innerCompStatements: ts.Statement[],

  newStatements: ts.Statement[], node: ts.Statement, isGlobalBuilder: boolean, isTransition: boolean,

  nameResult: NameResult, immutableStatements: ts.Statement[], componentName: string,

  builderParamsResult: BuilderParamsResult): void {

  if (!partialUpdateConfig.partialUpdateMode) {

    innerCompStatements.push(...newStatements);

  } else {

    innerCompStatements.push(createComponentCreationStatement(node, newStatements, componentName,

      isGlobalBuilder, isTransition, nameResult, immutableStatements, builderParamsResult));

  }

}



function createComponentCreationArrowParams(isGlobalBuilder: boolean,

  builderParamsResult: BuilderParamsResult, isRecycleComponent: boolean = false): ts.ParameterDeclaration[] {

  const arrowNodes: ts.ParameterDeclaration[] = [

    ts.factory.createParameterDeclaration(undefined, undefined,

      ts.factory.createIdentifier(ELMTID), undefined, undefined, undefined),

    ts.factory.createParameterDeclaration(undefined, undefined,

      ts.factory.createIdentifier(ISINITIALRENDER), undefined, undefined, undefined)

  ];

  if (!isRecycleComponent && partialUpdateConfig.optimizeComponent && isGlobalBuilder &&

    builderParamsResult && builderParamsResult.firstParam) {

    const paramName: ts.Identifier = builderParamsResult.firstParam.name as ts.Identifier;

    arrowNodes.push(ts.factory.createParameterDeclaration(undefined, undefined,

      paramName, undefined, undefined, ts.factory.createIdentifier(`__${paramName.escapedText.toString()}__`)

    ));

  }

  return arrowNodes;

}



export function createComponentCreationStatement(node: ts.Statement, innerStatements: ts.Statement[],

  componentName: string, isGlobalBuilder: boolean = false, isTransition: boolean = false,

  nameResult: NameResult = undefined, immutableStatements: ts.Statement[] = null,

  builderParamsResult: BuilderParamsResult = null, isRecycleComponent: boolean = false): ts.Statement {

  const blockArr: ts.Statement[] = [...innerStatements];

  if (nameResult) {

    blockArr.push(processDebug(node, nameResult, innerStatements, true));

  }

  if (!isTransition) {

    createInitRenderStatement(node, immutableStatements, blockArr);

  }

  if (!partialUpdateConfig.optimizeComponent) {

    blockArr.unshift(createViewStackProcessorStatement(STARTGETACCESSRECORDINGFOR, ELMTID));

    blockArr.push(createViewStackProcessorStatement(STOPGETACCESSRECORDING));

  }

  const creationArgs: ts.Expression[] = [

    ts.factory.createArrowFunction(undefined, undefined,

      createComponentCreationArrowParams(isGlobalBuilder, builderParamsResult, isRecycleComponent),

      undefined, ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),

      ts.factory.createBlock(blockArr, true)

    )

  ];

  if (partialUpdateConfig.optimizeComponent) {

    creationArgs.push(isTransition ? ts.factory.createNull() :

      ts.factory.createIdentifier(componentName));

  }

  return ts.factory.createExpressionStatement(

    ts.factory.createCallExpression(

      ts.factory.createPropertyAccessExpression(createConditionParent(isGlobalBuilder),

        ts.factory.createIdentifier(partialUpdateConfig.optimizeComponent ?

          OBSERVECOMPONENTCREATION2 : OBSERVECOMPONENTCREATION)

      ), undefined, creationArgs)

  );

}



export function createViewStackProcessorStatement(propertyAccessName: string, elmtId?: string): ts.Statement {

  return ts.factory.createExpressionStatement(

    ts.factory.createCallExpression(

      ts.factory.createPropertyAccessExpression(

        ts.factory.createIdentifier(VIEWSTACKPROCESSOR),

        ts.factory.createIdentifier(propertyAccessName)

      ),

      undefined,

      elmtId ? [ts.factory.createIdentifier(ELMTID)] : []

    )

  );

}



function createInitRenderStatement(node: ts.Statement,

  immutableStatements: ts.Statement[], blockArr: ts.Statement[]): void {

  if (partialUpdateConfig.optimizeComponent) {

    if (immutableStatements && immutableStatements.length) {

      blockArr.push(ts.factory.createIfStatement(

        ts.factory.createIdentifier(ISINITIALRENDER),

        ts.factory.createBlock(immutableStatements, true)

      ));

    }

  } else {

    blockArr.push(ts.factory.createIfStatement(

      ts.factory.createPrefixUnaryExpression(

        ts.SyntaxKind.ExclamationToken,

        ts.factory.createIdentifier(ISINITIALRENDER)

      ),

      ts.factory.createBlock(

        [

          ts.isExpressionStatement(node) ?

            createComponent(node, COMPONENT_POP_FUNCTION).newNode : createIfPop()

        ],

        true

      ),

      immutableStatements && immutableStatements.length ?

        ts.factory.createBlock(immutableStatements, true) : undefined

    ));

  }

}



function processItemComponent(node: ts.ExpressionStatement, nameResult: NameResult, innerCompStatements: ts.Statement[],

  log: LogInfo[], parent: string = undefined, isGlobalBuilder: boolean = false, idName: ts.Expression = undefined,

  builderParamsResult: BuilderParamsResult = null, isInRepeatTemplate: boolean = false): void {

  const itemRenderInnerStatements: ts.Statement[] = [];

  const immutableStatements: ts.Statement[] = [];

  const deepItemRenderInnerStatements: ts.Statement[] = [];

  if (addElmtIdNode()) {

    itemRenderInnerStatements.push(createCollectElmtIdNode());

  }

  const res: CreateResult = createComponent(node, COMPONENT_CREATE_FUNCTION);

  const isLazyCreate: boolean = checkLazyCreate(node, nameResult);

  const itemCreateStatement: ts.Statement = createItemCreate(nameResult, isLazyCreate);

  itemRenderInnerStatements.push(itemCreateStatement);

  const etsComponentResult: EtsComponentResult = parseEtsComponentExpression(node);

  if (etsComponentResult.etsComponentNode.body && ts.isBlock(etsComponentResult.etsComponentNode.body)) {

    if (etsComponentResult.hasAttr) {

      bindComponentAttr(node, res.identifierNode, itemRenderInnerStatements, log, true, false, immutableStatements);

    }

    storedFileInfo.lazyForEachInfo.isDependItem = false;

    processComponentChild(etsComponentResult.etsComponentNode.body, deepItemRenderInnerStatements, log,

      {isAcceleratePreview: false, line: 0, column: 0, fileName: ''}, false, parent, undefined, isGlobalBuilder, false,

      builderParamsResult, isInRepeatTemplate);

  } else {

    bindComponentAttr(node, res.identifierNode, itemRenderInnerStatements, log, true, false, immutableStatements);

  }

  let generateItem: ts.IfStatement | ts.Block;

  if (idName) {

    generateItem = ifRetakeId([createItemBlock(

      node, itemRenderInnerStatements, deepItemRenderInnerStatements, nameResult, isLazyCreate,

      immutableStatements, isGlobalBuilder, builderParamsResult, itemCreateStatement)], idName);

  } else {

    generateItem = createItemBlock(

      node, itemRenderInnerStatements, deepItemRenderInnerStatements, nameResult, isLazyCreate,

      immutableStatements, isGlobalBuilder, builderParamsResult, itemCreateStatement);

  }

  innerCompStatements.push(generateItem);

}



function createItemCreate(nameResult: NameResult, isLazyCreate: boolean): ts.Statement {

  const itemCreateArgs: ts.Expression[] = [];

  if (isLazyCreate) {

    itemCreateArgs.push(ts.factory.createIdentifier(DEEPRENDERFUNCTION), ts.factory.createTrue());

  } else {

    itemCreateArgs.push(

      ts.factory.createArrowFunction(undefined, undefined, [], undefined,

        ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),

        ts.factory.createBlock([], false)),

      ts.factory.createFalse()

    );

  }

  itemCreateArgs.push(...nameResult.arguments);

  return ts.factory.createExpressionStatement(ts.factory.createCallExpression(

    ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(nameResult.name),

      ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION)), undefined, itemCreateArgs));

}



type ItemCreation = {

  creationArgs: ts.Expression[],

  creationName: string,

};



function getItemCreation(nameResult: NameResult): ItemCreation {

  const creationArgs: ts.Expression[] = [];

  let creationName: string = OBSERVECOMPONENTCREATION;

  if (partialUpdateConfig.optimizeComponent) {

    creationArgs.push(

      ts.factory.createIdentifier(ITEMCREATION2),

      ts.factory.createIdentifier(nameResult.name));

    creationName = OBSERVECOMPONENTCREATION2;

  } else {

    creationArgs.push(ts.factory.createIdentifier(ITEMCREATION));

  }

  return { creationArgs, creationName };

}



function createItemBlock(

  node: ts.ExpressionStatement,

  itemRenderInnerStatements: ts.Statement[],

  deepItemRenderInnerStatements: ts.Statement[],

  nameResult: NameResult, isLazyCreate: boolean,

  immutableStatements: ts.Statement[],

  isGlobalBuilder: boolean,

  builderParamsResult: BuilderParamsResult,

  itemCreateStatement: ts.Statement

): ts.Block {

  const blockNode: ts.Statement[] = [

    createItemCreation2(node, itemRenderInnerStatements, nameResult, immutableStatements,

      isGlobalBuilder, builderParamsResult)

  ];

  const itemCreation: ItemCreation = getItemCreation(nameResult);

  if (isLazyCreate) {

    blockNode.unshift(createItemCreation(node, isGlobalBuilder, builderParamsResult, itemCreateStatement));

    blockNode.push(

      createDeepRenderFunction(node, deepItemRenderInnerStatements, isGlobalBuilder, builderParamsResult),

      ts.factory.createExpressionStatement(ts.factory.createCallExpression(

        ts.factory.createPropertyAccessExpression(

          ts.factory.createThis(),

          ts.factory.createIdentifier(itemCreation.creationName)

        ), undefined, itemCreation.creationArgs

      )),

      createComponent(node, COMPONENT_POP_FUNCTION).newNode

    );

  } else {

    if (!partialUpdateConfig.optimizeComponent) {

      blockNode.unshift(createItemCreation(node, isGlobalBuilder, builderParamsResult));

    }

    blockNode.push(

      createObservedDeepRender(node, deepItemRenderInnerStatements, itemCreation),

      ts.factory.createExpressionStatement(ts.factory.createCallExpression(

        ts.factory.createIdentifier(OBSERVEDDEEPRENDER), undefined, []))

    );

  }

  return ts.factory.createBlock(blockNode, true);

}



function checkLazyCreate(node: ts.ExpressionStatement, nameResult: NameResult): boolean {

  if (nameResult.name === LIST_ITEM) {

    if (nameResult.arguments.length && ts.isStringLiteral(nameResult.arguments[0]) &&

      nameResult.arguments[0].text === 'false') {

      return false;

    }

    if (storedFileInfo.processRepeat) {

      return false;

    }

    if (isLazyForEachChild(node)) {

      return false;

    }

    return true;

  }

  return false;

}



function createItemCreation(node: ts.ExpressionStatement, isGlobalBuilder: boolean,

  builderParamsResult: BuilderParamsResult, itemCreateStatement: ts.Statement = undefined): ts.VariableStatement {

  if (!partialUpdateConfig.optimizeComponent) {

    itemCreateStatement = ts.factory.createExpressionStatement(ts.factory.createCallExpression(

      ts.factory.createIdentifier(ITEMCREATION2),

      undefined, createItemCreationArgs(isGlobalBuilder, builderParamsResult)));

  }

  return ts.factory.createVariableStatement(

    undefined,

    ts.factory.createVariableDeclarationList(

      [ts.factory.createVariableDeclaration(

        ts.factory.createIdentifier(ITEMCREATION), undefined, undefined,

        ts.factory.createArrowFunction(undefined, undefined,

          createComponentCreationArrowParams(isGlobalBuilder, builderParamsResult), undefined,

          ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),

          ts.factory.createBlock(

            [

              createViewStackProcessorStatement(STARTGETACCESSRECORDINGFOR, ELMTID),

              itemCreateStatement,

              ts.factory.createIfStatement(

                ts.factory.createPrefixUnaryExpression(

                  ts.SyntaxKind.ExclamationToken,

                  ts.factory.createIdentifier(ISINITIALRENDER)

                ),

                ts.factory.createBlock(

                  [createComponent(node, COMPONENT_POP_FUNCTION).newNode],

                  true

                )

              ),

              createViewStackProcessorStatement(STOPGETACCESSRECORDING)

            ],

            true

          )

        )

      )],

      ts.NodeFlags.Const

    )

  );

}



function createItemCreation2(

  node: ts.ExpressionStatement,

  itemRenderInnerStatements: ts.Statement[],

  nameResult: NameResult,

  immutableStatements: ts.Statement[],

  isGlobalBuilder: boolean,

  builderParamsResult: BuilderParamsResult

): ts.VariableStatement {

  const itemBlock: ts.Statement[] = [

    ...itemRenderInnerStatements,

    processDebug(node, nameResult, itemRenderInnerStatements, true)

  ];

  if (immutableStatements && immutableStatements.length) {

    itemBlock.push(ts.factory.createIfStatement(

      ts.factory.createIdentifier(ISINITIALRENDER),

      ts.factory.createBlock(immutableStatements, true)

    ));

  }

  return ts.factory.createVariableStatement(

    undefined,

    ts.factory.createVariableDeclarationList(

      [ts.factory.createVariableDeclaration(

        ts.factory.createIdentifier(ITEMCREATION2), undefined, undefined,

        ts.factory.createArrowFunction(undefined, undefined,

          createComponentCreationArrowParams(isGlobalBuilder, builderParamsResult), undefined,

          ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),

          ts.factory.createBlock(itemBlock, true)

        )

      )],

      ts.NodeFlags.Const

    )

  );

}



function createItemCreationArgs(isGlobalBuilder: boolean,

  builderParamsResult: BuilderParamsResult): ts.Expression[] {

  const itemCreationArgs: ts.Expression[] = [

    ts.factory.createIdentifier(ELMTID), ts.factory.createIdentifier(ISINITIALRENDER)];

  if (partialUpdateConfig.optimizeComponent && isGlobalBuilder && builderParamsResult &&

    builderParamsResult.firstParam) {

    itemCreationArgs.push(builderParamsResult.firstParam.name as ts.Identifier);

  }

  return itemCreationArgs;

}



function createDeepRenderFunction(

  node: ts.ExpressionStatement,

  deepItemRenderInnerStatements: ts.Statement[],

  isGlobalBuilder: boolean,

  builderParamsResult: BuilderParamsResult

): ts.VariableStatement {

  const blockNode: ts.Statement[] = [

    ts.factory.createExpressionStatement(ts.factory.createCallExpression(

      ts.factory.createIdentifier(ITEMCREATION), undefined,

      createItemCreationArgs(isGlobalBuilder, builderParamsResult)

    )),

    ts.factory.createExpressionStatement(ts.factory.createCallExpression(

      ts.factory.createPropertyAccessExpression(

        ts.factory.createPropertyAccessExpression(

          ts.factory.createThis(),

          ts.factory.createIdentifier(UPDATE_FUNC_BY_ELMT_ID)

        ),

        ts.factory.createIdentifier(CREATE_SET_METHOD)

      ), undefined,

      [ts.factory.createIdentifier(ELMTID), ts.factory.createIdentifier(ITEMCREATION)]

    )),

    ...deepItemRenderInnerStatements,

    createComponent(node, COMPONENT_POP_FUNCTION).newNode

  ];

  if (partialUpdateConfig.optimizeComponent) {

    blockNode.splice(1, 1);

  }

  return ts.factory.createVariableStatement(

    undefined,

    ts.factory.createVariableDeclarationList(

      [ts.factory.createVariableDeclaration(

        ts.factory.createIdentifier(DEEPRENDERFUNCTION), undefined, undefined,

        ts.factory.createArrowFunction(undefined, undefined,

          createComponentCreationArrowParams(isGlobalBuilder, builderParamsResult), undefined,

          ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),

          ts.factory.createBlock(blockNode, true)

        )

      )],

      ts.NodeFlags.Const

    )

  );

}



function createObservedDeepRender(

  node: ts.ExpressionStatement,

  deepItemRenderInnerStatements: ts.Statement[],

  itemCreation: ItemCreation

): ts.VariableStatement {

  return ts.factory.createVariableStatement(

    undefined,

    ts.factory.createVariableDeclarationList(

      [ts.factory.createVariableDeclaration(

        ts.factory.createIdentifier(OBSERVEDDEEPRENDER),

        undefined,

        undefined,

        ts.factory.createArrowFunction(

          undefined,

          undefined,

          [],

          undefined,

          ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),

          ts.factory.createBlock(

            [

              ts.factory.createExpressionStatement(ts.factory.createCallExpression(

                ts.factory.createPropertyAccessExpression(

                  ts.factory.createThis(),

                  ts.factory.createIdentifier(itemCreation.creationName)

                ), undefined, itemCreation.creationArgs

              )),

              ...deepItemRenderInnerStatements,

              createComponent(node, COMPONENT_POP_FUNCTION).newNode

            ],

            true

          )

        )

      )],

      ts.NodeFlags.Const

    )

  );

}



function processTabAndNav(node: ts.ExpressionStatement, innerCompStatements: ts.Statement[],

  nameResult: NameResult, log: LogInfo[], parent: string = undefined, isGlobalBuilder: boolean = false,

  idName: ts.Expression = undefined, builderParamsResult: BuilderParamsResult = null,

  isInRepeatTemplate: boolean = false): void {

  const name: string = nameResult.name;

  const tabContentComp: ts.EtsComponentExpression = getEtsComponentExpression(node);

  const tabContentBody: ts.Block = tabContentComp.body;

  let tabContentCreation: ts.Statement;

  const tabContentPop: ts.Statement = ts.factory.createExpressionStatement(ts.factory.createCallExpression(

    ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(name),

      ts.factory.createIdentifier(COMPONENT_POP_FUNCTION)), undefined, []));

  const tabAttrs: ts.Statement[] = [];

  if (addElmtIdNode()) {

    tabAttrs.push(createCollectElmtIdNode());

  }

  const immutableStatements: ts.Statement[] = [];

  let judgeIdStart: number;

  if (idName) {

    judgeIdStart = innerCompStatements.length;

  }

  if (tabContentBody && tabContentBody.statements.length) {

    const newTabContentChildren: ts.Statement[] = [];

    processComponentChild(tabContentBody, newTabContentChildren, log, {isAcceleratePreview: false, line: 0, column: 0, fileName: ''},

      false, parent, undefined, isGlobalBuilder, false, builderParamsResult, isInRepeatTemplate);

    const navDestinationCallback: (ts.ArrowFunction | ts.NewExpression | ts.ObjectLiteralExpression)[] =

      [ts.factory.createArrowFunction(undefined, undefined, [], undefined,

        ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),

        ts.factory.createBlock([...newTabContentChildren], true))];

    if (name === NAV_DESTINATION) {

      navDestinationCallback.push(...navigationCreateParam(NAV_DESTINATION, COMPONENT_CREATE_FUNCTION, undefined, true));

    }

    if (equalToHiddenNavDes(name)) {

      navDestinationCallback.push(...navigationCreateParam(EXT_WHITE_LIST[1], COMPONENT_CREATE_FUNCTION, undefined, true));

    }

    tabContentCreation = ts.factory.createExpressionStatement(

      ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(

        ts.factory.createIdentifier(name), ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION)),

        undefined, navDestinationCallback));

    bindComponentAttr(node, ts.factory.createIdentifier(name), tabAttrs, log, true, false, immutableStatements);

    processInnerCompStatements(

      innerCompStatements, [tabContentCreation, ...tabAttrs], node, isGlobalBuilder, false,

      nameResult, immutableStatements, name, builderParamsResult);

    storedFileInfo.lazyForEachInfo.isDependItem = false;

  } else {

    tabContentCreation = ts.factory.createExpressionStatement(ts.factory.createCallExpression(

      ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(name),

        ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION)), undefined,

      name === NAV_DESTINATION ? navigationCreateParam(NAV_DESTINATION, COMPONENT_CREATE_FUNCTION) :

        (equalToHiddenNavDes(name) ? navigationCreateParam(EXT_WHITE_LIST[1], COMPONENT_CREATE_FUNCTION) : [])));

    bindComponentAttr(node, ts.factory.createIdentifier(name), tabAttrs, log, true, false, immutableStatements);

    processInnerCompStatements(

      innerCompStatements, [tabContentCreation, ...tabAttrs], node, isGlobalBuilder, false,

      nameResult, immutableStatements, name, builderParamsResult);

  }

  innerCompStatements.push(tabContentPop);

  if (idName) {

    innerCompStatements.splice(judgeIdStart, innerCompStatements.length - judgeIdStart,

      ifRetakeId(innerCompStatements.slice(judgeIdStart), idName));

  }

}



export function getRealNodePos(node: ts.Node): number {

  // @ts-ignore

  if (node.pos === -1 && node.expression) {

    // @ts-ignore

    return getRealNodePos(node.expression);

  } else {

    return node.getStart();

  }

}



function processForEachComponent(node: ts.ExpressionStatement, newStatements: ts.Statement[],

  log: LogInfo[], isBuilder: boolean = false, isGlobalBuilder: boolean = false): void {

  const popNode: ts.ExpressionStatement = ts.factory.createExpressionStatement(createFunction(

    // @ts-ignore

    node.expression.expression as ts.Identifier,

    ts.factory.createIdentifier(COMPONENT_POP_FUNCTION), null));

  if (ts.isCallExpression(node.expression)) {

    const propertyNode: ts.PropertyAccessExpression = ts.factory.createPropertyAccessExpression(

      node.expression.expression as ts.Identifier,

      ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION)

    );

    const argumentsArray: ts.Expression[] = Array.from(node.expression.arguments);

    let arrayObserveredObject: ts.CallExpression;

    if (argumentsArray.length) {

      arrayObserveredObject = ts.factory.createCallExpression(

        ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(FOREACH_OBSERVED_OBJECT),

          ts.factory.createIdentifier(FOREACH_GET_RAW_OBJECT)), undefined, [argumentsArray[0]]);

    }

    argumentsArray.splice(0, 1, arrayObserveredObject);

    const newForEachArrowFunc: ts.ArrowFunction = processForEachFunctionBlock(node.expression);

    const newArrowNode: ts.ArrowFunction =

      processForEachBlock(node.expression, log, newForEachArrowFunc, isBuilder) as ts.ArrowFunction;

    if (newArrowNode) {

      argumentsArray.splice(1, 1, newArrowNode);

    }

    node = addForEachId(ts.factory.updateExpressionStatement(node, ts.factory.updateCallExpression(

      node.expression, propertyNode, node.expression.typeArguments, argumentsArray)), isGlobalBuilder);

  }

  newStatements.push(node, popNode);

}



function collectForEachAttribute(node: ts.ExpressionStatement,

  attributeList: ts.ExpressionStatement[], name: string): ts.ExpressionStatement {

  let tempNode = node.expression;

  while (tempNode && ts.isCallExpression(tempNode)) {

    if (tempNode.expression && ts.isPropertyAccessExpression(tempNode.expression)) {

      attributeList.unshift(generateForEachAttribute(tempNode, name));

    } else if (tempNode.expression && ts.isIdentifier(tempNode.expression)) {

      return ts.factory.updateExpressionStatement(node, tempNode);

    }

    tempNode = tempNode.expression?.expression;

  }

  return node;

}



function generateForEachAttribute(tempNode: ts.CallExpression, name: string): ts.ExpressionStatement {

  return ts.factory.createExpressionStatement(ts.factory.createCallExpression(

    ts.factory.createPropertyAccessExpression(

      ts.factory.createIdentifier(name),

      tempNode.expression.name

    ),

    undefined,

    tempNode.arguments

  ));

}



function processForEachComponentNew(node: ts.ExpressionStatement, newStatements: ts.Statement[],

  log: LogInfo[], name: string, isGlobalBuilder: boolean = false, builderParamsResult: BuilderParamsResult = null,

  isInRepeatTemplate: boolean = false): void {

  const attributeList: ts.ExpressionStatement[] = [];

  const newNode = collectForEachAttribute(node, attributeList, name);

  const newForEachStatements: ts.Statement[] = [];

  const popNode: ts.ExpressionStatement = ts.factory.createExpressionStatement(createFunction(

    (newNode.expression as ts.CallExpression).expression as ts.Identifier,

    ts.factory.createIdentifier(COMPONENT_POP_FUNCTION), null));

  if (ts.isCallExpression(newNode.expression)) {

    if (checkForEachComponent(newNode)) {

      storedFileInfo.processForEach += 1;

    } else {

      storedFileInfo.processLazyForEach += 1;

    }

    const argumentsArray: ts.Expression[] = Array.from(newNode.expression.arguments);

    const propertyNode: ts.ExpressionStatement = ts.factory.createExpressionStatement(

      ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(

        newNode.expression.expression as ts.Identifier,

        ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION)), undefined, []));

    const newForEachArrowFunc: ts.ArrowFunction = processForEachFunctionBlock(newNode.expression);

    const newArrowNode: ts.NodeArray<ts.Statement> =

      processForEachBlock(newNode.expression, log, newForEachArrowFunc, false, isGlobalBuilder,

        builderParamsResult, isInRepeatTemplate) as ts.NodeArray<ts.Statement>;

    const itemGenFunctionStatement: ts.VariableStatement = createItemGenFunctionStatement(newNode.expression, newArrowNode, newForEachArrowFunc);

    const itemIdFuncStatement: ts.VariableStatement = createItemIdFuncStatement(newNode.expression, argumentsArray);

    const updateFunctionStatement: ts.ExpressionStatement = createUpdateFunctionStatement(argumentsArray, newForEachArrowFunc, isGlobalBuilder);

    const lazyForEachStatement: ts.ExpressionStatement = createLazyForEachStatement(argumentsArray);

    if (newNode.expression.expression.getText() === COMPONENT_FOREACH) {

      newForEachStatements.push(propertyNode, ...attributeList, itemGenFunctionStatement, updateFunctionStatement);

      newStatements.push(createComponentCreationStatement(newNode, newForEachStatements, COMPONENT_FOREACH,

        isGlobalBuilder, false, undefined, null, builderParamsResult), popNode);

    } else {

      if (argumentsArray[2]) {

        newStatements.push(ts.factory.createBlock([itemGenFunctionStatement, itemIdFuncStatement, lazyForEachStatement,

          ...attributeList, popNode], true));

      } else {

        newStatements.push(ts.factory.createBlock([itemGenFunctionStatement, lazyForEachStatement, popNode, ...attributeList], true));

      }

    }

    if (checkForEachComponent(newNode)) {

      storedFileInfo.processForEach -= 1;

    } else {

      storedFileInfo.processLazyForEach -= 1;

    }

  }

}



function checkForEachComponent(node: ts.ExpressionStatement): boolean {

  return node.expression.expression && ts.isIdentifier(node.expression.expression) &&

    node.expression.expression.getText() === COMPONENT_FOREACH;

}



function createItemGenFunctionStatement(

  node: ts.CallExpression,

  newArrowNode: ts.NodeArray<ts.Statement>,

  newForEachArrowFunc: ts.ArrowFunction

): ts.VariableStatement {

  if (newForEachArrowFunc && ts.isArrowFunction(newForEachArrowFunc)) {

    return ts.factory.createVariableStatement(

      undefined,

      ts.factory.createVariableDeclarationList(

        [ts.factory.createVariableDeclaration(

          ts.factory.createIdentifier(node.expression.getText() === COMPONENT_FOREACH ?

            FOREACHITEMGENFUNCTION : __LAZYFOREACHITEMGENFUNCTION),

          undefined, undefined,

          ts.factory.createArrowFunction(

            undefined, undefined,

            newForEachArrowFunc.parameters && newForEachArrowFunc.parameters.length >= 1 ?

              getParameters(newForEachArrowFunc) : [],

            undefined, ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),

            ts.factory.createBlock(

              newForEachArrowFunc.parameters && newForEachArrowFunc.parameters.length >= 1 ?

                isForEachItemGeneratorParam(newForEachArrowFunc, newArrowNode) :

                newArrowNode ? [...newArrowNode] : undefined,

              true

            )

          )

        )

        ],

        ts.NodeFlags.Const

      )

    );

  }

  return undefined;

}



function isForEachItemGeneratorParam(argumentsArray: ts.Expression, newArrowNode: ts.NodeArray<ts.Statement>): ts.Statement[] {

  const createVariableStatementNode: ts.Statement[] = [];

  createVariableStatementNode.push(ts.factory.createVariableStatement(

    undefined,

    ts.factory.createVariableDeclarationList(

      [ts.factory.createVariableDeclaration(

        ts.factory.createIdentifier(

          argumentsArray.parameters[0] && argumentsArray.parameters[0].name.getText()),

        undefined,

        undefined,

        ts.factory.createIdentifier(_ITEM)

      )],

      ts.NodeFlags.Const

    )

  ));

  if (newArrowNode) {

    createVariableStatementNode.push(...newArrowNode);

  }

  return createVariableStatementNode;

}



function getParameters(node: ts.ArrowFunction): ts.ParameterDeclaration[] {

  const parameterArr: ts.ParameterDeclaration[] = [

    ts.factory.createParameterDeclaration(

      undefined, undefined, ts.factory.createIdentifier(_ITEM))

  ];

  if (node.parameters && node.parameters.length > 1) {

    parameterArr.push(node.parameters[1]);

  }

  if (projectConfig.optLazyForEach && storedFileInfo.processLazyForEach) {

    if (node.parameters.length === 1) {

      parameterArr.push(ts.factory.createParameterDeclaration(

        undefined, undefined, ts.factory.createIdentifier(INDEX)));

    }

    parameterArr.push(

      ts.factory.createParameterDeclaration(

        undefined, undefined, ts.factory.createIdentifier(IS_INITIAL_ITEM)),

      ts.factory.createParameterDeclaration(

        undefined, undefined, ts.factory.createIdentifier(IDS))

    );

  }

  return parameterArr;

}



function createItemIdFuncStatement(

  node: ts.CallExpression,

  argumentsArray: ts.Expression[]

): ts.VariableStatement {

  if (argumentsArray[2]) {

    return ts.factory.createVariableStatement(

      undefined,

      ts.factory.createVariableDeclarationList(

        [ts.factory.createVariableDeclaration(

          ts.factory.createIdentifier(node.expression.getText() === COMPONENT_FOREACH ?

            FOREACHITEMIDFUNC : __LAZYFOREACHITEMIDFUNC), undefined, undefined,

          argumentsArray[2]

        )],

        ts.NodeFlags.Const

      )

    );

  }

  return undefined;

}



function createUpdateFunctionStatement(argumentsArray: ts.Expression[],

  newForEachArrowFunc: ts.ArrowFunction, isGlobalBuilder: boolean = false): ts.ExpressionStatement {

  return ts.factory.createExpressionStatement(

    ts.factory.createCallExpression(

      ts.factory.createPropertyAccessExpression(

        isGlobalBuilder ? parentConditionalExpression() : ts.factory.createThis(),

        ts.factory.createIdentifier(FOREACHUPDATEFUNCTION)

      ),

      undefined,

      addForEachIdFuncParameter(argumentsArray, newForEachArrowFunc)

    )

  );

}



function addForEachIdFuncParameter(argumentsArray: ts.Expression[], newForEachArrowFunc: ts.ArrowFunction): ts.Expression[] {

  const addForEachIdFuncParameterArr: ts.Expression[] = [];

  addForEachIdFuncParameterArr.push(

    ts.factory.createIdentifier(ELMTID),

    argumentsArray[0],

    ts.factory.createIdentifier(FOREACHITEMGENFUNCTION)

  );

  // @ts-ignore

  if (newForEachArrowFunc && newForEachArrowFunc.parameters && newForEachArrowFunc.parameters[1]) {

    if (!argumentsArray[2]) {

      addForEachIdFuncParameterArr.push(...addForEachParameter(ts.factory.createIdentifier(COMPONENT_IF_UNDEFINED), TRUE, FALSE));

    } else {

      // @ts-ignore

      argumentsArray[2].parameters && argumentsArray[2].parameters[1] ?

        addForEachIdFuncParameterArr.push(...addForEachParameter(argumentsArray[2], TRUE, TRUE)) :

        addForEachIdFuncParameterArr.push(...addForEachParameter(argumentsArray[2], TRUE, FALSE));

    }

  }

  // @ts-ignore

  if (newForEachArrowFunc && newForEachArrowFunc.parameters && newForEachArrowFunc.parameters.length < 2 && newForEachArrowFunc.parameters[0] &&

    argumentsArray && argumentsArray.length > 2 && argumentsArray[2]) {

    // @ts-ignore

    argumentsArray[2].parameters && argumentsArray[2].parameters[1] ?

      addForEachIdFuncParameterArr.push(...addForEachParameter(argumentsArray[2], FALSE, TRUE)) :

      addForEachIdFuncParameterArr.push(...addForEachParameter(argumentsArray[2], FALSE, FALSE));

  }

  return addForEachIdFuncParameterArr;

}



function addForEachParameter(forEachItemIdContent: ts.Expression, forEachItemGen: string, forEachItemId: string): ts.Expression[] {

  return [forEachItemIdContent, ts.factory.createIdentifier(forEachItemGen),

    ts.factory.createIdentifier(forEachItemId)];

}



function createLazyForEachStatement(argumentsArray: ts.Expression[]): ts.ExpressionStatement {

  const parameterList: ts.Expression[] = [

    ts.factory.createStringLiteral(componentInfo.id.toString()),

    ts.factory.createThis(),

    argumentsArray[0],

    ts.factory.createIdentifier(__LAZYFOREACHITEMGENFUNCTION)

  ];

  if (argumentsArray.length >= 3 && argumentsArray[2]) {

    parameterList.push(ts.factory.createIdentifier(__LAZYFOREACHITEMIDFUNC));

    if (argumentsArray.length >= 4 && ts.isObjectLiteralExpression(argumentsArray[3])) {

      parameterList.push(argumentsArray[3]);

    }

  }

  if (projectConfig.optLazyForEach) {

    parameterList.push(ts.factory.createTrue());

  }

  return ts.factory.createExpressionStatement(

    ts.factory.createCallExpression(

      ts.factory.createPropertyAccessExpression(

        ts.factory.createIdentifier(COMPONENT_LAZYFOREACH),

        ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION)

      ),

      undefined,

      parameterList

    )

  );

}



function addForEachId(node: ts.ExpressionStatement, isGlobalBuilder: boolean = false): ts.ExpressionStatement {

  const forEachComponent: ts.CallExpression = node.expression as ts.CallExpression;

  return ts.factory.updateExpressionStatement(node, ts.factory.updateCallExpression(

    forEachComponent, forEachComponent.expression, forEachComponent.typeArguments,

    [ts.factory.createStringLiteral((++componentInfo.id).toString()),

      isGlobalBuilder ? parentConditionalExpression() : ts.factory.createThis(),

      ...forEachComponent.arguments]));

}



export function parentConditionalExpression(): ts.ConditionalExpression {

  return ts.factory.createConditionalExpression(

    ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARENT),

    ts.factory.createToken(ts.SyntaxKind.QuestionToken),

    ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARENT),

    ts.factory.createToken(ts.SyntaxKind.ColonToken),

    ts.factory.createThis());

}

function processForEachFunctionBlock(node: ts.CallExpression): ts.ArrowFunction {

  if (ts.isArrowFunction(node.arguments[1])) {

    return node.arguments[1];

  } else if (ts.isParenthesizedExpression(node.arguments[1]) && ts.isArrowFunction(node.arguments[1].expression)) {

    return node.arguments[1].expression;

  } else {

    return null;

  }

}

function processForEachBlock(node: ts.CallExpression, log: LogInfo[],

  arrowNode: ts.ArrowFunction, isBuilder: boolean = false, isGlobalBuilder: boolean = false,

  builderParamsResult: BuilderParamsResult = null, isInRepeatTemplate: boolean = false): ts.NodeArray<ts.Statement> | ts.ArrowFunction {

  if (node.arguments.length > 1 && ts.isArrowFunction(arrowNode)) {

    const isLazy: boolean = node.expression.getText() === COMPONENT_LAZYFOREACH;

    const body: ts.ConciseBody = arrowNode.body;

    if (!ts.isBlock(body)) {

      const statement: ts.Statement = ts.factory.createExpressionStatement(body);

      const blockNode: ts.Block = ts.factory.createBlock([statement], true);

      // @ts-ignore

      statement.parent = blockNode;

      if (!partialUpdateConfig.partialUpdateMode) {

        return ts.factory.updateArrowFunction(

          arrowNode, ts.getModifiers(arrowNode), arrowNode.typeParameters, arrowNode.parameters,

          arrowNode.type, arrowNode.equalsGreaterThanToken,

          processComponentBlock(blockNode, isLazy, log, false, false, undefined,

            arrowNode.parameters, isGlobalBuilder));

      } else {

        return processComponentBlock(blockNode, isLazy, log, false, false, undefined,

          arrowNode.parameters, isGlobalBuilder, builderParamsResult, false, isInRepeatTemplate).statements;

      }

    } else {

      if (!partialUpdateConfig.partialUpdateMode) {

        return ts.factory.updateArrowFunction(

          arrowNode, ts.getModifiers(arrowNode), arrowNode.typeParameters, arrowNode.parameters,

          arrowNode.type, arrowNode.equalsGreaterThanToken,

          processComponentBlock(body, isLazy, log, false, isBuilder, undefined, arrowNode.parameters));

      } else {

        return processComponentBlock(body, isLazy, log, false, false, undefined, arrowNode.parameters,

          isGlobalBuilder, builderParamsResult, false, isInRepeatTemplate).statements;

      }

    }

  }

  return null;

}



function createRenderingInProgress(isTrue: boolean): ts.ExpressionStatement {

  return ts.factory.createExpressionStatement(ts.factory.createBinaryExpression(

    ts.factory.createPropertyAccessExpression(

      ts.factory.createThis(),

      ts.factory.createIdentifier(IS_RENDERING_IN_PROGRESS)

    ),

    ts.factory.createToken(ts.SyntaxKind.EqualsToken),

    isTrue ? ts.factory.createTrue() : ts.factory.createFalse()

  ));

}



function addElmtIdNode(): boolean {

  return partialUpdateConfig.partialUpdateMode && projectConfig.optLazyForEach &&

    ((storedFileInfo.processLazyForEach && storedFileInfo.lazyForEachInfo.isDependItem) || storedFileInfo.processBuilder);

}



function processIfStatement(node: ts.IfStatement, newStatements: ts.Statement[],

  log: LogInfo[], isBuilder: boolean = false, isGlobalBuilder: boolean = false,

  builderParamsResult: BuilderParamsResult = null, isInRepeatTemplate: boolean = false): void {

  const ifStatements: ts.Statement[] = [];

  if (addElmtIdNode()) {

    ifStatements.push(createCollectElmtIdNode());

    storedFileInfo.lazyForEachInfo.isDependItem = false;

  }

  const ifCreate: ts.ExpressionStatement = createIfCreate();

  const newIfNode: ts.IfStatement = processInnerIfStatement(node, 0, log, isBuilder, isGlobalBuilder, builderParamsResult, isInRepeatTemplate);

  ifStatements.push(ifCreate, newIfNode);

  const ifPop: ts.ExpressionStatement = createIfPop();

  if (!partialUpdateConfig.partialUpdateMode) {

    newStatements.push(ifCreate, newIfNode, ifPop);

  } else {

    newStatements.push(createComponentCreationStatement(node, ifStatements, COMPONENT_IF,

      isGlobalBuilder, false, undefined, null, builderParamsResult), ifPop);

  }

}



function processInnerIfStatement(node: ts.IfStatement, id: number, log: LogInfo[],

  isBuilder: boolean = false, isGlobalBuilder: boolean = false,

  builderParamsResult: BuilderParamsResult = null, isInRepeatTemplate: boolean = false): ts.IfStatement {

  if (ts.isIdentifier(node.expression) && node.expression.originalKeywordKind === undefined &&

    !node.expression.escapedText) {

    log.push({

      type: LogType.ERROR,

      message: 'Condition expression cannot be null in if statement.',

      pos: node.expression.getStart(),

      code: '10905208'

    });

    node = ts.factory.updateIfStatement(node, ts.factory.createIdentifier(COMPONENT_IF_UNDEFINED),

      node.thenStatement, node.elseStatement);

  }

  const newThenStatement: ts.Statement = processThenStatement(

    node.thenStatement, id, log, isBuilder, isGlobalBuilder, builderParamsResult, isInRepeatTemplate);

  const newElseStatement: ts.Statement = processElseStatement(

    node.elseStatement, id, log, isBuilder, isGlobalBuilder, builderParamsResult, isInRepeatTemplate);

  const newIfNode: ts.IfStatement = ts.factory.updateIfStatement(

    node, node.expression, newThenStatement, newElseStatement);

  return newIfNode;

}



function processThenStatement(thenStatement: ts.Statement, id: number,

  log: LogInfo[], isBuilder: boolean = false, isGlobalBuilder: boolean = false,

  builderParamsResult: BuilderParamsResult = null, isInRepeatTemplate: boolean = false): ts.Statement {

  if (ts.isExpressionStatement(thenStatement) && ts.isIdentifier(thenStatement.expression) &&

    thenStatement.expression.originalKeywordKind === undefined &&

    !thenStatement.expression.escapedText) {

    log.push({

      type: LogType.ERROR,

      message: 'Then statement cannot be null in if statement.',

      pos: thenStatement.expression.getStart(),

      code: '10905207'

    });

  }

  if (thenStatement) {

    if (ts.isBlock(thenStatement)) {

      thenStatement = processIfBlock(thenStatement, id, log, isBuilder, isGlobalBuilder, builderParamsResult, isInRepeatTemplate);

    } else if (ts.isIfStatement(thenStatement)) {

      thenStatement = processInnerIfStatement(thenStatement, 0, log, isBuilder, isGlobalBuilder, builderParamsResult, isInRepeatTemplate);

      thenStatement = ts.factory.createBlock(

        partialUpdateConfig.partialUpdateMode ?

          [createIfCreate(), createIfBranchFunc(id, [thenStatement], isGlobalBuilder), createIfPop()] :

          [createIfCreate(), createIfBranchId(id), thenStatement, createIfPop()],

        true

      );

    } else {

      thenStatement = ts.factory.createBlock([thenStatement], true);

      thenStatement = processIfBlock(thenStatement as ts.Block, id, log, isBuilder, isGlobalBuilder, builderParamsResult, isInRepeatTemplate);

    }

  }

  return thenStatement;

}



function processElseStatement(elseStatement: ts.Statement, id: number,

  log: LogInfo[], isBuilder: boolean = false, isGlobalBuilder: boolean = false,

  builderParamsResult: BuilderParamsResult = null, isInRepeatTemplate: boolean = false): ts.Statement {

  if (elseStatement) {

    if (ts.isBlock(elseStatement)) {

      elseStatement = processIfBlock(elseStatement, id + 1, log, isBuilder, isGlobalBuilder, builderParamsResult, isInRepeatTemplate);

    } else if (ts.isIfStatement(elseStatement)) {

      elseStatement = processInnerIfStatement(elseStatement, id + 1, log, isBuilder, isGlobalBuilder, builderParamsResult, isInRepeatTemplate);

    } else {

      elseStatement = ts.factory.createBlock([elseStatement], true);

      elseStatement = processIfBlock(elseStatement as ts.Block, id + 1, log, isBuilder, isGlobalBuilder, builderParamsResult, isInRepeatTemplate);

    }

  } else if (partialUpdateConfig.partialUpdateMode) {

    elseStatement = ts.factory.createBlock([

      ts.factory.createExpressionStatement(ts.factory.createCallExpression(

        ts.factory.createPropertyAccessExpression(

          ts.factory.createThis(),

          ts.factory.createIdentifier(IFELSEBRANCHUPDATEFUNCTION)

        ),

        undefined,

        [

          ts.factory.createNumericLiteral(++id),

          ts.factory.createArrowFunction(

            undefined,

            undefined,

            [],

            undefined,

            ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),

            ts.factory.createBlock(

              [],

              true

            )

          )

        ]

      ))

    ], true);

  }

  return elseStatement;

}



function processIfBlock(block: ts.Block, id: number, log: LogInfo[], isBuilder: boolean = false,

  isGlobalBuilder: boolean = false, builderParamsResult: BuilderParamsResult = null, isInRepeatTemplate: boolean = false): ts.Block {

  return addIfBranchId(id, isGlobalBuilder,

    processComponentBlock(block, false, log, false, isBuilder, COMPONENT_IF, undefined, isGlobalBuilder, builderParamsResult, false, isInRepeatTemplate));

}



function addIfBranchId(id: number, isGlobalBuilder: boolean = false, container: ts.Block): ts.Block {

  let containerStatements: ts.Statement[];

  if (partialUpdateConfig.partialUpdateMode) {

    containerStatements = [createIfBranchFunc(id, [...container.statements], isGlobalBuilder)];

  } else {

    containerStatements = [createIfBranchId(id), ...container.statements];

  }

  return ts.factory.updateBlock(container, containerStatements);

}



function createIf(): ts.Identifier {

  return ts.factory.createIdentifier(COMPONENT_IF);

}



function createIfCreate(): ts.ExpressionStatement {

  return ts.factory.createExpressionStatement(createFunction(createIf(),

    ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION), ts.factory.createNodeArray([])));

}



function createIfPop(): ts.ExpressionStatement {

  return ts.factory.createExpressionStatement(createFunction(createIf(),

    ts.factory.createIdentifier(COMPONENT_POP_FUNCTION), null));

}



function createIfBranchId(id: number): ts.ExpressionStatement {

  return ts.factory.createExpressionStatement(createFunction(createIf(),

    ts.factory.createIdentifier(COMPONENT_IF_BRANCH_ID_FUNCTION),

    ts.factory.createNodeArray([ts.factory.createNumericLiteral(id)])));

}



function createIfBranchFunc(id: number, innerStatements: ts.Statement[],

  isGlobalBuilder: boolean = false): ts.ExpressionStatement {

  return ts.factory.createExpressionStatement(ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(

    isGlobalBuilder ? parentConditionalExpression() : ts.factory.createThis(),

    ts.factory.createIdentifier(IFELSEBRANCHUPDATEFUNCTION)), undefined,

  [ts.factory.createNumericLiteral(id), ts.factory.createArrowFunction(undefined, undefined, [], undefined,

    ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), ts.factory.createBlock(innerStatements, true))]));

}



interface CreateResult {

  newNode: ts.ExpressionStatement;

  identifierNode: ts.Identifier;

  isContainerComponent: boolean;

  isButton: boolean;

  needPop: boolean;

}



function createComponent(node: ts.ExpressionStatement, type: string,

  TrailingStatements?: ts.Statement[]): CreateResult {

  const res: CreateResult = {

    newNode: node,

    identifierNode: null,

    isContainerComponent: false,

    isButton: false,

    needPop: false

  };

  let identifierNode: ts.Identifier = ts.factory.createIdentifier(type);

  let temp: any = node.expression;

  while (temp && !ts.isIdentifier(temp) && temp.expression) {

    temp = temp.expression;

  }

  if (temp && temp.parent && (ts.isCallExpression(temp.parent) ||

    ts.isEtsComponentExpression(temp.parent)) && ts.isIdentifier(temp)) {

    if (temp.getText() === COMPONENT_BUTTON && type !== COMPONENT_POP_FUNCTION) {

      res.isButton = true;

      identifierNode = type === COMPONENT_CREATE_CHILD_FUNCTION ?

        ts.factory.createIdentifier(COMPONENT_CREATE_CHILD_FUNCTION) :

        ts.factory.createIdentifier(COMPONENT_CREATE_LABEL_FUNCTION);

    }

    if (NEEDPOP_COMPONENT.has(temp.getText())) {

      res.needPop = true;

    }

    if (checkContainer(temp.getText(), temp.parent)) {

      res.isContainerComponent = true;

    }

    res.newNode = type === COMPONENT_POP_FUNCTION ?

      ts.factory.createExpressionStatement(createFunction(temp, identifierNode, null)) :

      (temp.getText() === _CONTAINER_READER) ?

      ts.factory.createExpressionStatement(createTrailingFunction(temp, identifierNode,

        checkArguments(temp, type), TrailingStatements)) :

      ts.factory.createExpressionStatement(createFunction(temp, identifierNode, checkArguments(temp, type)));

    res.identifierNode = temp;

  }

  return res;

}



function checkArguments(temp: ts.Identifier, type: string): ts.Expression[] {

  const newArguments: ts.Expression[] = [];

  if (CUSTOM_BUILDER_CONSTRUCTORS.has(temp.escapedText.toString())) {

    temp.parent.arguments.forEach(argument => {

      if (ts.isConditionalExpression(argument)) {

        newArguments.push(processConditionalBuilder(argument, temp, type));

      } else if (isBuilderChangeNode(argument, temp, type)) {

        newArguments.push(parseBuilderNode(argument, type));

      } else {

        newArguments.push(argument);

      }

    });

    return newArguments;

  }

  return temp.getText() === 'XComponent' && type === COMPONENT_CREATE_FUNCTION &&

    projectConfig.moduleName && projectConfig.bundleName ?

    // @ts-ignore

    temp.parent.arguments.concat([

      ts.factory.createStringLiteral(`${projectConfig.bundleName}/${projectConfig.moduleName}`)

    ]) : temp.parent.arguments;

}



function checkContainer(name: string, node: ts.Node): boolean {

  return BUILDIN_CONTAINER_COMPONENT.has(name) && (name !== 'XComponent' ||

    (node && node.arguments && node.arguments.length &&

    ts.isObjectLiteralExpression(node.arguments[0]) && node.arguments[0].properties &&

    checkComponentType(node.arguments[0].properties)));

}



function checkComponentType(properties: ts.PropertyAssignment[]): boolean {

  let flag: boolean = false;

  properties.forEach(item => {

    if (isXComponentContainer(item)) {

      flag = true;

    }

  });

  return flag;

}



function isXComponentContainer(item: ts.PropertyAssignment): boolean {

  return item.name && ts.isIdentifier(item.name) && item.name.getText() === RESOURCE_NAME_TYPE &&

    item.initializer && ((ts.isStringLiteral(item.initializer) &&

    // value = 'component'

    (item.initializer.getText() === XCOMPONENT_SINGLE_QUOTATION ||

    item.initializer.getText() === XCOMPONENT_DOUBLE_QUOTATION)) ||

    // value = 1

    (ts.isNumericLiteral(item.initializer) && item.initializer.getText() === '1') ||

    // value = XComponentType.COMPONENT

    (ts.isPropertyAccessExpression(item.initializer) && item.initializer.expression &&

    ts.isIdentifier(item.initializer.expression) && item.initializer.name &&

    ts.isIdentifier(item.initializer.name) && item.initializer.expression.getText() === XCOMPONENTTYPE) &&

    item.initializer.name.getText() === XCOMPONENTTYPE_CONTAINER);

}



interface AnimationInfo {

  statement: ts.Statement,

  kind: boolean,

  hasAnimationAttr: boolean,

}



export interface ComponentAttrInfo {

  reuseId: ts.Node,

  hasIdAttr: boolean,

  attrCount: number,

  reuse: string,

  reuseAttribute?: ts.Expression,

}



export function bindComponentAttr(node: ts.ExpressionStatement, identifierNode: ts.Identifier,

  newStatements: ts.Statement[], log: LogInfo[], reverse: boolean = true,

  isStylesAttr: boolean = false, newImmutableStatements: ts.Statement[] = null,

  isStyleFunction: boolean = false, componentAttrInfo: ComponentAttrInfo = null,

  isReusableV2NodeAttr: boolean = false,

  permitInitialRender: boolean = true): void {

  if (!node) {

    return;

  }

  const isStylesUIComponent: boolean = validateStylesUIComponent(node, isStylesAttr);

  let temp = node.expression;

  const statements: ts.Statement[] = [];

  const immutableStatements: ts.Statement[] = [];

  const updateStatements: ts.Statement[] = [];

  const lastStatement: AnimationInfo = {

    statement: null,

    kind: false,

    hasAnimationAttr: false

  };

  const isRecycleComponent: boolean = isRecycle(componentCollection.currentClassName);

  const isReuseComponentInV2: boolean = isReuseInV2(componentCollection.currentClassName);

  if (ts.isPropertyAccessExpression(temp) || isStylesUIComponent) {

    log.push({

      type: isStylesUIComponent ? LogType.WARN : LogType.ERROR,

      message: `'${node.getText()}' does not meet UI component syntax.`,

      pos: node.getStart(),

      code: '10905206'

    });

  }

  while (temp && ts.isCallExpression(temp) && temp.expression) {

    let flag: boolean = false;

    if (temp.expression && (validatePropertyAccessExpressionWithCustomBuilder(temp.expression) ||

      validateIdentifierWithCustomBuilder(temp.expression))) {

      let propertyName: string = '';

      if (ts.isIdentifier(temp.expression)) {

        propertyName = temp.expression.escapedText.toString();

      } else if (ts.isPropertyAccessExpression(temp.expression)) {

        propertyName = temp.expression.name.escapedText.toString();

      }

      switch (true) {

        case BIND_POPUP_SET.has(propertyName):

          temp = processBindPopupBuilder(temp);

          break;

        case BIND_DRAG_SET.has(propertyName):

          temp = processDragStartBuilder(temp, propertyName);

          break;

        default:

          temp = processCustomBuilderProperty(temp, identifierNode, propertyName);

      }

    }

    if (ts.isPropertyAccessExpression(temp.expression) &&

      temp.expression.name && ts.isIdentifier(temp.expression.name) &&

      (!componentCollection.customComponents.has(temp.expression.name.getText()) || STYLES_ATTRIBUTE.has(temp.expression.name.getText()))) {

      parseRecycleId(temp, temp.expression.name, componentAttrInfo, log, isReusableV2NodeAttr);

      addComponentAttr(temp, temp.expression.name, lastStatement, statements, identifierNode, log,

        isStylesAttr, immutableStatements, updateStatements, newImmutableStatements,

        isRecycleComponent, isReuseComponentInV2, isStyleFunction, permitInitialRender);

      temp = temp.expression.expression;

      flag = true;

    } else if (ts.isIdentifier(temp.expression)) {

      if (!INNER_COMPONENT_NAMES.has(temp.expression.getText()) &&

        !GESTURE_TYPE_NAMES.has(temp.expression.getText()) &&

        !componentCollection.customComponents.has(temp.expression.getText())) {

        parseRecycleId(temp, temp.expression.name, componentAttrInfo, log, isReusableV2NodeAttr);

        addComponentAttr(temp, temp.expression, lastStatement, statements, identifierNode, log,

          isStylesAttr, immutableStatements, updateStatements, newImmutableStatements,

          isRecycleComponent, isReuseComponentInV2, isStyleFunction, permitInitialRender);

      }

      break;

    }

    if (!flag) {

      temp = temp.expression;

    }

  }

  if (lastStatement.statement && lastStatement.kind) {

    statements.push(lastStatement.statement);

  }

  if ((!isRecycleComponent && !isReuseComponentInV2 && (!hasInitialRenderCondition() || !permitInitialRender)) ||

    lastStatement.hasAnimationAttr) {

    if (statements.length) {

      reverse ? newStatements.push(...statements.reverse()) : newStatements.push(...statements);

    }

  } else {

    if (updateStatements.length) {

      reverse ? newStatements.push(...updateStatements.reverse()) : newStatements.push(...updateStatements);

    }

    if (newImmutableStatements && immutableStatements.length) {

      reverse ? newImmutableStatements.push(...immutableStatements.reverse()) : newImmutableStatements.push(...immutableStatements);

    }

  }

}  



function validateStylesUIComponent(node: ts.ExpressionStatement, isStylesAttr: boolean): boolean {

  return (ts.isIfStatement(node) || ts.isSwitchStatement(node)) && isStylesAttr;

}



function parseRecycleId(node: ts.CallExpression, attr: ts.Identifier, componentAttrInfo: ComponentAttrInfo, log: LogInfo[],

  isReusableV2NodeAttr: boolean = false): void {

  if (componentAttrInfo && node.arguments.length > 0) {

    const param: ts.Expression = node.arguments[0];

    const attrName: string = attr.escapedText.toString();

    if (attrName === RECYCLE_REUSE_ID) {

      logMessageCollection.checkUsageOfReuseIdAttribute(node, isReusableV2NodeAttr, log);

      componentAttrInfo.reuseId = param;

    } else if (attrName === ATTRIBUTE_ID) {

      componentAttrInfo.hasIdAttr = true;

    } else if (attrName === REUSE_ATTRIBUTE) {

      logMessageCollection.checkUsageOfReuseAttribute(node, isReusableV2NodeAttr, log);

      setReuseAttributeInfo(componentAttrInfo, param);

    }

    componentAttrInfo.attrCount++;

  }

}



function setReuseAttributeInfo(componentAttrInfo: ComponentAttrInfo, param: ts.Expression): void {

  componentAttrInfo.reuse = '';

  componentAttrInfo.reuseAttribute = undefined;

  if (!ts.isObjectLiteralExpression(param)) {

    return;

  }

  const reuseIdProperty = getReuseIdProperty(param);

  if (reuseIdProperty) {

    componentAttrInfo.reuse = getReuseIdInReuse(reuseIdProperty);

    componentAttrInfo.reuseAttribute = reuseIdProperty;

  }

}



function getReuseIdProperty(

  node: ts.ObjectLiteralExpression

): ts.Expression | undefined {

  if (!node.properties || node.properties.length <= 0) {

    return undefined;

  }

  const reuseIdProperty: ts.PropertyAssignment | undefined =

    node.properties.find(

      (item: ts.ObjectLiteralElementLike) =>

        ts.isPropertyAssignment(item) &&

        item.name &&

        ts.isIdentifier(item.name) &&

        item.name.getText() === RECYCLE_REUSE_ID

    ) as ts.PropertyAssignment | undefined;

  return reuseIdProperty?.initializer;

}



function getReuseIdInReuse(node: ts.Expression): string {

  if (ts.isArrowFunction(node) && node.body && ts.isStringLiteral(node.body)) {

    return node.body.text;

  }

  return '';

}



function processCustomBuilderProperty(node: ts.CallExpression, identifierNode: ts.Identifier,

  propertyName: string): ts.CallExpression {

  const newArguments: ts.Expression[] = [];

  node.arguments.forEach((argument: ts.Expression | ts.Identifier, index: number) => {

    if (ts.isConditionalExpression(argument)) {

      newArguments.push(processConditionalBuilder(argument, identifierNode, propertyName));

    } else if (isBuilderChangeNode(argument, identifierNode, propertyName)) {

      newArguments.push(parseBuilderNode(argument, propertyName));

    } else {

      newArguments.push(argument);

    }

  });

  node = ts.factory.updateCallExpression(node, node.expression, node.typeArguments, newArguments);

  return node;

}



function isBuilderChangeNode(argument: ts.Node, identifierNode: ts.Identifier, propertyName: string): boolean {

  return ts.isPropertyAccessExpression(argument) && argument.name && ts.isIdentifier(argument.name) &&

    storedFileInfo.builderLikeCollection.has(argument.name.getText()) ||

    ts.isCallExpression(argument) && argument.expression && argument.expression.name &&

    ts.isIdentifier(argument.expression.name) &&

    storedFileInfo.builderLikeCollection.has(argument.expression.name.getText()) || ts.isIdentifier(argument) &&

    argument.escapedText && storedFileInfo.builderLikeCollection.has(argument.escapedText.toString()) ||

    ts.isObjectLiteralExpression(argument) && (BIND_OBJECT_PROPERTY.get(identifierNode.escapedText.toString()) &&

      BIND_OBJECT_PROPERTY.get(identifierNode.escapedText.toString()).has(propertyName) ||

      BIND_OBJECT_PROPERTY.get(ALL_COMPONENTS).has(propertyName)) ||

    ts.isCallExpression(argument) && argument.expression && ts.isIdentifier(argument.expression) &&

    storedFileInfo.builderLikeCollection.has(argument.expression.escapedText.toString()) ||

    (isWrappedBuilder(argument as ts.PropertyAccessExpression) || isMutableBuilder(argument as ts.PropertyAccessExpression)) ||

    (isWrappedBuilderCallExpression(argument as ts.CallExpression) || isMutableBuilderCallExpression(argument as ts.CallExpression));

}



export function isWrappedBuilder(node: ts.PropertyAccessExpression): boolean {

  if (!(

    projectConfig.minAPIVersion >= APIVERSION.apiVersionEleven &&

    ts.isPropertyAccessExpression(node) &&

    node.name && ts.isIdentifier(node.name) &&

    node.name.escapedText.toString() === WRAPBUILDER_BUILDERPROP

  )) {

    return false;

  }

  const checker: ts.TypeChecker | undefined = CurrentProcessFile.getChecker();

  if (checker) {

    const type: ts.Type | ts.Type[] =

      findNonNullType(checker.getTypeAtLocation(node.expression));

    if (Array.isArray(type)) {

      return false;

    }

    return type.symbol && type.symbol.escapedName === WRAPPEDBUILDER_CLASS;

  }

  return false;

}



function isWrappedBuilderCallExpression(node: ts.CallExpression): boolean {

  if (projectConfig.minAPIVersion >= APIVERSION.apiVersionEleven &&

    ts.isCallExpression(node) && node.expression &&

    isWrappedBuilder(node.expression as ts.PropertyAccessExpression)) {

    return true;

  }

  return false;

}



function parseBuilderNode(node: ts.Node, propertyName: string):

  ts.ObjectLiteralExpression | ts.CallExpression | ts.ArrowFunction | ts.PropertyAccessExpression {

  if (isWrappedBuilder(node as ts.PropertyAccessExpression) ||

    isMutableBuilder(node as ts.PropertyAccessExpression) ||

    isPropertyAccessExpressionNode(node)) {

    if (CUSTOM_BUILDER_PROPERTIES_WITHOUTKEY.has(propertyName)) {

      return processPropertyBuilderWithoutKey(node as ts.PropertyAccessExpression);

    } else {

      return processPropertyBuilder(node as ts.PropertyAccessExpression);

    }

  } else if (ts.isIdentifier(node) && storedFileInfo.builderLikeCollection.has(node.escapedText.toString())) {

    if (CUSTOM_BUILDER_PROPERTIES_WITHOUTKEY.has(propertyName)) {

      return processIdentifierBuilderWithoutKey(node);

    } else {

      return processIdentifierBuilder(node);

    }

  } else if (isWrappedBuilderCallExpression(node as ts.CallExpression) ||

    isMutableBuilderCallExpression(node as ts.CallExpression) ||

    ts.isCallExpression(node)) {

    if (CUSTOM_BUILDER_PROPERTIES_WITHOUTKEY.has(propertyName)) {

      return getParsedBuilderAttrArgumentWithParamsWithoutKey(node);

    } else {

      return getParsedBuilderAttrArgumentWithParams(node);

    }

  } else if (ts.isObjectLiteralExpression(node)) {

    return processObjectPropertyBuilder(node);

  } else if (ts.isPropertyAccessExpression(node)) {

    return node;

  }

  return undefined;

}



export function processObjectPropertyBuilder(node: ts.ObjectLiteralExpression): ts.ObjectLiteralExpression {

  const newProperties: ts.PropertyAssignment[] = [];

  node.properties.forEach((property: ts.PropertyAssignment) => {

    if (property.name && ts.isIdentifier(property.name) &&

      [CUSTOM_DIALOG_CONTROLLER_BUILDER, HEADER, INDICATORBUILDER, FOOTER, START, END, PREVIEW, TITLE].includes(

        property.name.escapedText.toString()) && property.initializer) {

      if (isPropertyAccessExpressionNode(property.initializer) || ts.isIdentifier(property.initializer) &&

        storedFileInfo.builderLikeCollection.has(property.initializer.escapedText.toString())) {

        newProperties.push(ts.factory.updatePropertyAssignment(property, property.name,

          ts.factory.createCallExpression(

            ts.factory.createPropertyAccessExpression(

              property.initializer,

              ts.factory.createIdentifier(BUILDER_ATTR_BIND)

            ),

            undefined,

            [ts.factory.createThis()]

          )));

      } else if (isGlobalBuilderCallExpressionNode(property.initializer) ||

        isInnerBuilderCallExpressionNode(property.initializer)) {

        newProperties.push(transformBuilderCallExpression(property));

      } else if (ts.isObjectLiteralExpression(property.initializer)) {

        newProperties.push(ts.factory.updatePropertyAssignment(property, property.name,

          processObjectPropertyBuilder(property.initializer)));

      } else {

        newProperties.push(property);

      }

    } else {

      newProperties.push(property);

    }

  });

  return ts.factory.updateObjectLiteralExpression(node, newProperties);

}



function transDoubleDollarInCustomBuilder(node: ts.CallExpression): ts.Expression[] {

  let name: string = '';

  if (node.expression && ts.isIdentifier(node.expression)) {

    name = node.expression.escapedText.toString();

  } else if (node.expression && ts.isPropertyAccessExpression(node.expression) &&

    node.expression.name && ts.isIdentifier(node.expression.name)) {

    name = node.expression.name.escapedText.toString();

  }

  if (node.arguments.length === 1 && ts.isObjectLiteralExpression(node.arguments[0])) {

    return [ts.factory.createCallExpression(

      ts.factory.createIdentifier(BUILDER_PARAM_PROXY),

      undefined,

      [

        ts.factory.createStringLiteral(name),

        traverseBuilderParams(node.arguments[0], storedFileInfo.processBuilder)

      ]

    )];

  } else {

    return node.arguments;

  }

}



function transformBuilderCallExpression(property: ts.PropertyAssignment): ts.PropertyAssignment {

  const newArguments: ts.Expression[] = transDoubleDollarInCustomBuilder(property.initializer as ts.CallExpression);

  return ts.factory.updatePropertyAssignment(property, property.name,

    ts.factory.createCallExpression(

      ts.factory.createPropertyAccessExpression(

        property.initializer.expression,

        ts.factory.createIdentifier(BUILDER_ATTR_BIND)

      ),

      undefined,

      [ts.factory.createThis(), ...(newArguments || [])]

    ));

}



function isInnerBuilderCallExpressionNode(node: ts.Node): boolean {

  return ts.isCallExpression(node) && node.expression && isPropertyAccessExpressionNode(node.expression);

}



function isGlobalBuilderCallExpressionNode(node: ts.Node): boolean {

  return ts.isCallExpression(node) && node.expression && ts.isIdentifier(node.expression) &&

    CUSTOM_BUILDER_METHOD.has(node.expression.escapedText.toString());

}



function isPropertyAccessExpressionNode(node: ts.Node): boolean {

  return ts.isPropertyAccessExpression(node) && node.expression &&

    node.expression.kind === ts.SyntaxKind.ThisKeyword && node.name && ts.isIdentifier(node.name) &&

    storedFileInfo.builderLikeCollection.has(node.name.escapedText.toString());

}



function processBindPopupBuilder(node: ts.CallExpression): ts.CallExpression {

  const newArguments: ts.Expression[] = [];

  node.arguments.forEach((argument: ts.ObjectLiteralExpression, index: number) => {

    if (index === 1 && ts.isObjectLiteralExpression(argument)) {

      // @ts-ignore

      newArguments.push(processBindPopupBuilderProperty(argument));

    } else {

      newArguments.push(argument);

    }

  });

  node = ts.factory.updateCallExpression(node, node.expression, node.typeArguments, newArguments);

  return node;

}



function processDragStartBuilder(node: ts.CallExpression, propertyName: string): ts.CallExpression {

  const newStatements: ts.Statement[] = [];

  if (isNodeFunction(node)) {

    // @ts-ignore

    for (let i = 0; i < node.arguments[0].body.statements.length; i++) {

      // @ts-ignore

      const statement: ts.Statement = node.arguments[0].body.statements[i];

      newStatements.push(checkStatement(statement, propertyName));

    }

    node = ts.factory.updateCallExpression(node, node.expression, node.typeArguments, [ts.factory.updateArrowFunction(

      // @ts-ignore

      node.arguments[0], undefined, undefined, node.arguments[0].parameters, node.arguments[0].type,

      // @ts-ignore

      node.arguments[0].equalsGreaterThanToken, ts.factory.updateBlock(node.arguments[0].body, newStatements))]);

  }

  return node;

}



function isNodeFunction(node: ts.CallExpression): boolean {

  return node.arguments && node.arguments.length && ts.isArrowFunction(node.arguments[0]) && node.arguments[0].body &&

    ts.isBlock(node.arguments[0].body);

}



function checkStatement(statement: ts.Statement, propertyName: string): ts.Statement {

  if (ts.isReturnStatement(statement)) {

    if (!statement.expression) {

      transformLog.errors.push({

        type: LogType.WARN,

        message: `The return statement needs to have content.`,

        pos: statement.pos

      });

      return ts.factory.createReturnStatement(undefined);

    }

    if (ts.isObjectLiteralExpression(statement.expression)) {

      const newProperties: ts.ObjectLiteralElementLike[] = [];

      for (let j = 0; j < statement.expression.properties.length; j++) {

        let property: ts.ObjectLiteralElementLike = statement.expression.properties[j];

        property = checkProperty(property, propertyName);

        newProperties.push(property);

      }

      return ts.factory.createReturnStatement(ts.factory.createObjectLiteralExpression(newProperties));

    } else {

      let initializer: ts.Expression = statement.expression;

      initializer = processInitializer(initializer, propertyName);

      return ts.factory.updateReturnStatement(statement, initializer);

    }

  } else {

    return statement;

  }

}



function checkProperty(property: ts.ObjectLiteralElementLike, propertyName: string): ts.ObjectLiteralElementLike {

  if (isPropertyFunction(property)) {

    let initializer: ts.Expression = property.initializer;

    initializer = processInitializer(initializer, propertyName);

    property = ts.factory.createPropertyAssignment(property.name, initializer);

  }

  return property;

}



function processInitializer(initializer: ts.Expression, propertyName: string): ts.Expression {

  if (initializer && ts.isConditionalExpression(initializer)) {

    return processConditionalBuilder(initializer, ts.factory.createIdentifier(CUSTOM_COMPONENT_DEFAULT),

      propertyName);

  } else if (isBuilderChangeNode(initializer, ts.factory.createIdentifier(CUSTOM_COMPONENT_DEFAULT),

    propertyName)) {

    return parseBuilderNode(initializer, propertyName);

  }

  return initializer;

}



function isPropertyFunction(property: ts.ObjectLiteralElementLike): boolean {

  return ts.isPropertyAssignment(property) && property.name && ts.isIdentifier(property.name) &&

    property.name.escapedText.toString() === BUILDER_ATTR_NAME;

}



function processBindPopupBuilderProperty(node: ts.ObjectLiteralExpression): ts.ObjectLiteralExpression {

  const newProperties: ts.PropertyAssignment[] = [];

  node.properties.forEach((property: ts.PropertyAssignment, index: number) => {

    if (property.name && ts.isIdentifier(property.name) && property.initializer &&

      property.name.escapedText.toString() === CUSTOM_DIALOG_CONTROLLER_BUILDER) {

      let initializer: ts.Expression = property.initializer;

      initializer = processInitializer(initializer, BIND_POPUP);

      newProperties.push(ts.factory.updatePropertyAssignment(property, property.name, initializer));

    } else {

      newProperties.push(property);

    }

  });

  return ts.factory.updateObjectLiteralExpression(node, newProperties);

}



function processConditionalBuilder(initializer: ts.ConditionalExpression, identifierNode: ts.Identifier,

  propertyName: string): ts.ConditionalExpression {

  let whenTrue: ts.Expression = initializer.whenTrue;

  let whenFalse: ts.Expression = initializer.whenFalse;

  if (isBuilderChangeNode(initializer.whenTrue, identifierNode, propertyName)) {

    whenTrue = parseBuilderNode(initializer.whenTrue, propertyName);

  }

  if (isBuilderChangeNode(initializer.whenFalse, identifierNode, propertyName)) {

    whenFalse = parseBuilderNode(initializer.whenFalse, propertyName);

  }

  return ts.factory.updateConditionalExpression(

    initializer,

    initializer.condition,

    initializer.questionToken,

    whenTrue,

    initializer.colonToken,

    whenFalse

  );

}



function processPropertyBuilder(node: ts.PropertyAccessExpression): ts.ObjectLiteralExpression {

  return ts.factory.createObjectLiteralExpression([

    ts.factory.createPropertyAssignment(

      ts.factory.createIdentifier(BUILDER_ATTR_NAME),

      ts.factory.createCallExpression(

        ts.factory.createPropertyAccessExpression(

          node,

          ts.factory.createIdentifier(BUILDER_ATTR_BIND)

        ),

        undefined,

        [ts.factory.createThis()]

      )

    )

  ]);

}



function processPropertyBuilderWithoutKey(node: ts.PropertyAccessExpression): ts.CallExpression {

  return ts.factory.createCallExpression(

    ts.factory.createPropertyAccessExpression(

      node,

      ts.factory.createIdentifier(BUILDER_ATTR_BIND)

    ),

    undefined,

    [ts.factory.createThis()]

  );

}



function processIdentifierBuilder(node: ts.Identifier): ts.ObjectLiteralExpression {

  return ts.factory.createObjectLiteralExpression([

    ts.factory.createPropertyAssignment(

      ts.factory.createIdentifier(BUILDER_ATTR_NAME),

      ts.factory.createCallExpression(

        ts.factory.createPropertyAccessExpression(node, ts.factory.createIdentifier(BUILDER_ATTR_BIND)),

        undefined, [ts.factory.createThis()]

      )

    )

  ]);

}



function processIdentifierBuilderWithoutKey(node: ts.Identifier): ts.CallExpression {

  return ts.factory.createCallExpression(

    ts.factory.createPropertyAccessExpression(node, ts.factory.createIdentifier(BUILDER_ATTR_BIND)),

    undefined, [ts.factory.createThis()]

  );

}



function getParsedBuilderAttrArgumentWithParams(node: ts.CallExpression):

  ts.ObjectLiteralExpression {

  const newArguments: ts.Expression[] = transDoubleDollarInCustomBuilder(node);

  return ts.factory.createObjectLiteralExpression([

    ts.factory.createPropertyAssignment(

      ts.factory.createIdentifier(BUILDER_ATTR_NAME),

      ts.factory.createArrowFunction(

        undefined,

        undefined,

        [],

        undefined,

        ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),

        ts.factory.createBlock(

          [ts.factory.createExpressionStatement(ts.factory.createCallExpression(

            ts.factory.createPropertyAccessExpression(node.expression, ts.factory.createIdentifier(CALL)

            ), undefined, [ts.factory.createThis(), ...newArguments]))],

          true

        )

      )

    )

  ]);

}



function getParsedBuilderAttrArgumentWithParamsWithoutKey(node: ts.CallExpression):

  ts.ArrowFunction {

  const newArguments: ts.Expression[] = transDoubleDollarInCustomBuilder(node);

  return ts.factory.createArrowFunction(

    undefined,

    undefined,

    [],

    undefined,

    ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),

    ts.factory.createBlock(

      [ts.factory.createExpressionStatement(ts.factory.createCallExpression(

        ts.factory.createPropertyAccessExpression(node.expression, ts.factory.createIdentifier(CALL)

        ), undefined, [ts.factory.createThis(), ...newArguments]))],

      true

    )

  );

}



function validatePropertyAccessExpressionWithCustomBuilder(node: ts.Node): boolean {

  return ts.isPropertyAccessExpression(node) && node.name &&

    ts.isIdentifier(node.name) && CUSTOM_BUILDER_PROPERTIES.has(node.name.escapedText.toString());

}



function validateIdentifierWithCustomBuilder(node: ts.Node): boolean {

  return ts.isIdentifier(node) && CUSTOM_BUILDER_PROPERTIES.has(node.escapedText.toString());

}



function createArrowFunctionForDollar($$varExp: ts.Expression): ts.ArrowFunction {

  let varExp: ts.ConditionalExpression | ts.BinaryExpression;

  if (ts.isConditionalExpression($$varExp)) {

    varExp = ts.factory.updateConditionalExpression(

      $$varExp, $$varExp.condition, ts.factory.createToken(ts.SyntaxKind.QuestionToken), $$varExp.whenTrue,

      ts.factory.createToken(ts.SyntaxKind.ColonToken), ts.factory.createBinaryExpression(

        $$varExp.whenFalse, ts.factory.createToken(ts.SyntaxKind.EqualsToken), ts.factory.createIdentifier($$_NEW_VALUE))); 

  } else {

    varExp = ts.factory.createBinaryExpression(

      $$varExp, ts.factory.createToken(ts.SyntaxKind.EqualsToken), ts.factory.createIdentifier($$_NEW_VALUE)

    );

  }

    return ts.factory.createArrowFunction(

      undefined, undefined,

      [ts.factory.createParameterDeclaration(

        undefined, undefined,

        ts.factory.createIdentifier($$_NEW_VALUE),

        undefined, undefined, undefined

      )],

      undefined,

      ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),

      ts.factory.createBlock(

        [ts.factory.createExpressionStatement(varExp)],

        false

      )

    );

}



function updateArgumentForExclamation(argument): ts.Expression {

  if (ts.isNonNullExpression(argument) && ts.isNonNullExpression(argument.expression)) {

    return argument.expression.expression;

  }

  return argument;

}



function updateArgumentForDollar(argument): ts.Expression {

  if (ts.isElementAccessExpression(argument)) {

    return ts.factory.updateElementAccessExpression(

      argument, updateArgumentForDollar(argument.expression), argument.argumentExpression);

  } else if (ts.isIdentifier(argument)) {

    if (argument.getText() === $$_THIS) {

      return ts.factory.createThis();

    } else if (argument.getText().match(/^\$\$(.|\n)+/)) {

      return ts.factory.createIdentifier(argument.getText().replace(/\$\$/, ''));

    }

  } else if (ts.isPropertyAccessExpression(argument)) {

    return ts.factory.updatePropertyAccessExpression(

      argument, updateArgumentForDollar(argument.expression), argument.name);

  }

  return argument;

}



function verifyComponentId(temp: any, node: ts.Identifier, propName: string,

  log: LogInfo[]): void {

  if (!newsupplement.isAcceleratePreview && propName === ATTRIBUTE_ID &&

    ts.isStringLiteral(temp.arguments[0])) {

    const id: string = temp.arguments[0].text;

    const posOfNode: ts.LineAndCharacter = transformLog.sourceFile

      .getLineAndCharacterOfPosition(getRealNodePos(node));

    const curFileName: string = transformLog.sourceFile.fileName.replace(/\.ts$/, '');

    const rPath: string = path.resolve(projectConfig.projectPath, curFileName)

      .replace(/\\+/g, '/');

    const rLine: number = posOfNode.line + 1;

    const rCol: number = posOfNode.character + 1;

    if (ID_ATTRS.has(id)) {

      const idInfo: Map<string, string | number> = ID_ATTRS.get(id);

      if (!(idInfo.get('path') === rPath &&

        idInfo.get('line') === rLine &&

        idInfo.get('col') === rCol)) {

        log.push({

          type: LogType.WARN,

          message: `The current component id "${id}" is duplicate with ` +

            `${idInfo.get('path')}:${idInfo.get('line')}:${idInfo.get('col')}.`,

          pos: node.pos

        });

      }

    } else {

      ID_ATTRS.set(id, new Map().set('path', rPath)

        .set('line', rLine)

        .set('col', rCol));

    }

  }

}



class StyleResult {

  doubleDollar: boolean = false;

  doubleExclamation: boolean = false;

}



function isDoubleBind(styleResult: StyleResult, isStylesAttr: boolean, identifierNode: ts.Identifier,

  propName: string, temp: ts.CallExpression): boolean {

  if (isDoubleDollarToChange(isStylesAttr, identifierNode, propName, temp)) {

    styleResult.doubleDollar = true;

    return true;

  } else if (isDoubleExclamationToChange(isStylesAttr, identifierNode, propName, temp)) {

    styleResult.doubleExclamation = true;

    return true;

  }

  return false;

}



function addComponentAttr(temp, node: ts.Identifier, lastStatement,

  statements: ts.Statement[], identifierNode: ts.Identifier, log: LogInfo[],

  isStylesAttr: boolean, immutableStatements: ts.Statement[], updateStatements: ts.Statement[],

  newImmutableStatements: ts.Statement[] = null, isRecycleComponent: boolean = false,

  isReuseComponentInV2: boolean = false, isStyleFunction: boolean = false,

  permitInitialRender: boolean = true): void {

  const styleResult: StyleResult = new StyleResult();

  const propName: string = node.getText();

  verifyComponentId(temp, node, propName, log);

  const extendType: ExtendType = {type: ''};

  if (propName === ATTRIBUTE_ANIMATION) {

    const animationNullNode: ts.ExpressionStatement = ts.factory.createExpressionStatement(

      createFunction(ts.factory.createIdentifier(GLOBAL_CONTEXT), node,

        // @ts-ignore

        [ts.factory.createNull()]));

    if (!lastStatement.statement) {

      if (!(temp.arguments.length === 1 &&

        temp.arguments[0].kind === ts.SyntaxKind.NullKeyword)) {

        statements.push(animationNullNode);

      }

    } else {

      statements.push(lastStatement.statement, animationNullNode);

    }

    lastStatement.statement = ts.factory.createExpressionStatement(createFunction(

      ts.factory.createIdentifier(GLOBAL_CONTEXT), node, temp.arguments));

    lastStatement.kind = false;

    lastStatement.hasAnimationAttr = true;

  } else if (GESTURE_ATTRS.has(propName)) {

    if (hasInitialRenderCondition() && permitInitialRender) {

      (!isStylesAttr || isStyleFunction) &&

        parseGestureInitialRender(temp, propName, statements, log, immutableStatements,

          isStylesAttr, isStyleFunction);

    } else {

      parseGesture(temp, propName, statements, log, updateStatements);

    }

    lastStatement.kind = true;

  } else if (isExtendFunctionNode(identifierNode, propName, extendType)) {

    if (newsupplement.isAcceleratePreview) {

      log.push({

        type: LogType.ERROR,

        message: `Doesn't support '@Extend' function now.`,

        pos: temp.getStart(),

        code: '10906205'

      });

    }

    let functionName: string = '';

    if (extendType.type === CHECK_COMPONENT_EXTEND_DECORATOR) {

      functionName = `__${identifierNode.escapedText.toString()}__${propName}`;

    } else {

      functionName = propName;

    }

    const extendNode: ts.Statement = ts.factory.createExpressionStatement(

      ts.factory.createCallExpression(ts.factory.createIdentifier(functionName), undefined,

        extendType.type === CHECK_COMPONENT_EXTEND_DECORATOR ?

          temp.arguments :

          [

            ...temp.arguments, ts.factory.createIdentifier(ELMTID),

            ts.factory.createIdentifier(ISINITIALRENDER),

            ts.factory.createThis()

          ]

      ));

    statements.push(extendNode);

    updateStatements.push(extendNode);

    lastStatement.kind = true;

  } else if (propName === ATTRIBUTE_STATESTYLES) {

    if (temp.arguments.length === 1 && ts.isObjectLiteralExpression(temp.arguments[0])) {

      statements.push(createViewStackProcessor(temp, true));

      if (isRecycleComponent || (hasInitialRenderCondition() && permitInitialRender)) {

        updateStatements.push(createViewStackProcessor(temp, true));

      }

      traverseStateStylesAttr(temp, statements, identifierNode, log, updateStatements,

        newImmutableStatements, isRecycleComponent, permitInitialRender);

      lastStatement.kind = true;

    } else {

      validateStateStyleSyntax(temp, log);

    }

  } else if (GLOBAL_STYLE_FUNCTION.has(propName) || INNER_STYLE_FUNCTION.has(propName)) {

    const styleBlock: ts.Block =

        INNER_STYLE_FUNCTION.get(propName) || GLOBAL_STYLE_FUNCTION.get(propName);

    if (styleBlock.statements.length > 0) {

      bindComponentAttr(styleBlock.statements[0] as ts.ExpressionStatement, identifierNode,

        statements, log, false, true, newImmutableStatements);

      if (isRecycleComponent || (hasInitialRenderCondition() && permitInitialRender)) {

        bindComponentAttr(styleBlock.statements[0] as ts.ExpressionStatement, identifierNode,

          updateStatements, log, false, true, newImmutableStatements, true);

      }

    }

    lastStatement.kind = true;

  } else if (isDoubleBind(styleResult, isStylesAttr, identifierNode, propName, temp)) {

    const argumentsArr: ts.Expression[] = [];

    styleResult.doubleDollar ? classifyArgumentsNum(temp.arguments, argumentsArr, propName, identifierNode) :

      classifyArgumentsNumV2(temp.arguments, argumentsArr, propName, identifierNode);

    const doubleDollarNode: ts.Statement = ts.factory.createExpressionStatement(

      createFunction(identifierNode, node, argumentsArr));

    statements.push(doubleDollarNode);

    updateStatements.push(doubleDollarNode);

    lastStatement.kind = true;

  } else {

    temp = loopEtscomponent(temp, isStylesAttr);

    if (propName !== RECYCLE_REUSE_ID && propName !== REUSE_ATTRIBUTE) {

      let isAttributeModifier: boolean = false;

      if ([ATTRIBUTE_ATTRIBUTE_MODIFIER, ATTRIBUTE_CONTENT_MODIFIER,

        ATTRIBUTE_MENUITEM_CONTENT_MODIFIER].includes(propName)) {

        isAttributeModifier = true;

      }

      const attrStatement: ts.Statement = ts.factory.createExpressionStatement(

        createFunction(identifierNode, node, temp.arguments, isAttributeModifier));

      statements.push(attrStatement);

      if (((isRecycleComponent || isReuseComponentInV2) ||

        (hasInitialRenderCondition() && permitInitialRender)) &&

        (!isStylesAttr || isStyleFunction) &&

        !isGestureType(identifierNode) && filterRegularAttrNode(temp.arguments, permitInitialRender)) {

        immutableStatements.push(attrStatement);

      } else {

        updateStatements.push(attrStatement);

      }

    }

    lastStatement.kind = true;

  }

}



function isGestureType(node: ts.Identifier): boolean {

  return GESTURE_TYPE_NAMES.has(node.escapedText.toString());

}



function filterRegularAttrNode(

  argumentsNode: ts.NodeArray<ts.Expression>,

  permitInitialRender: boolean = false

): boolean {

  return argumentsNode.every((argument: ts.Expression) => {

    return isRegularAttrNode(argument, permitInitialRender);

  });

}



type AttrResult = { isRegularNode: boolean };

function isRegularAttrNode(

  node: ts.Expression,

  permitInitialRender: boolean = false

): boolean {

  if (hasInitialRenderCondition() &&

    permitInitialRender &&

    ts.isIdentifier(node)) {

    return isIdentifierConstVariable(node);

  }

  if (ts.isObjectLiteralExpression(node)) {

    return node.properties.every((propNode: ts.PropertyAssignment) => {

      if (propNode.initializer) {

        return isRegularAttrNode(propNode.initializer);

      }

      return false;

    });

  }

  if (ts.isArrayLiteralExpression(node)) {

    return node.elements.every((child: ts.Expression) => {

      return isRegularAttrNode(child);

    });

  }

  // literal e.g. 'hello', 1, true, false, () => {}

  if (isLiteralNode(node)) {

    return true;

  }

  // enum e.g. Color.Red

  if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.expression) &&

    ts.isIdentifier(node.name)) {

    if (enumCollection.has(node.expression.escapedText.toString())) {

      return true;

    }

    const checker: ts.TypeChecker | undefined = CurrentProcessFile.getChecker();

    if (checker) {

      const type: ts.Type = checker.getTypeAtLocation(node);

      /* Enum */

      if (type.flags & (32 | 1024)) {

        return true;

      }

    }

    return false;

  }

  // regular variable, e.g. this.regularValue

  const result: AttrResult = { isRegularNode: false };

  if (ts.isPropertyAccessExpression(node)) {

    traversePropNode(node, result);

  }

  return result.isRegularNode || false;

}



function isIdentifierConstVariable(

  identifier: ts.Identifier

): boolean {

  const checker: ts.TypeChecker | undefined = CurrentProcessFile.getChecker();

  if (!checker) {

    return false;

  }

  let symbol: ts.Symbol | undefined = checker.getSymbolAtLocation(identifier);

  if (!symbol) {

    return false;

  }

  if (symbol && symbol.getFlags() && (symbol.getFlags() & ts.SymbolFlags.Alias)) {

    symbol = checker.getAliasedSymbol(symbol);

  }

  const declarations: ts.Declaration[] | undefined = symbol.getDeclarations();

  if (!declarations || !declarations.length) {

    return false;

  }

  const decl: ts.Declaration = declarations[0];

  if (ts.isVariableDeclaration(decl) && decl.parent &&

    ts.isVariableDeclarationList(decl.parent) && decl.parent.flags &&

    (decl.parent.flags & ts.NodeFlags.Const) !== 0) {

    return true;

  }

  return false;

}



function isLiteralNode(node: ts.Expression): boolean {

  return ts.isStringLiteral(node) || ts.isNumericLiteral(node) || ts.isArrowFunction(node) ||

    [ts.SyntaxKind.TrueKeyword, ts.SyntaxKind.FalseKeyword].includes(node.kind);

}



function isSimpleType(node: ts.PropertyAccessExpression): boolean {

  const symbol: ts.Symbol = getSymbolIfAliased(node);

  const simpleTypeCollection: ts.SyntaxKind[] = [ts.SyntaxKind.StringKeyword, ts.SyntaxKind.NumberKeyword, 

    ts.SyntaxKind.BooleanKeyword];

  if (symbol && symbol.declarations && symbol.declarations.length === 1 && ts.isPropertyDeclaration(symbol.declarations[0]) &&

    symbol.declarations[0].type && symbol.declarations[0].type.kind && simpleTypeCollection.includes(symbol.declarations[0].type.kind)) {

    return true;

  }

  return false;

}



function traversePropNode(node: ts.PropertyAccessExpression, result: AttrResult): void {

  const structInfo: StructInfo = processStructComponentV2.getOrCreateStructInfo(componentCollection.currentClassName);

  if (structInfo.isComponentV2 && node.expression.kind === ts.SyntaxKind.ThisKeyword && ts.isIdentifier(node.name) &&

    structInfo.regularSet.has(node.name.escapedText.toString()) && isSimpleType(node)) {

    result.isRegularNode = true;

    return;

  }

  if (!structInfo.isComponentV2 && node.expression.kind === ts.SyntaxKind.ThisKeyword && ts.isIdentifier(node.name) &&

    regularCollection.get(componentCollection.currentClassName).has(node.name.escapedText.toString())) {

    result.isRegularNode = true;

    return;

  }

  if (ts.isPropertyAccessExpression(node.expression)) {

    traversePropNode(node.expression, result);

  }

}



function isDoubleDollarToChange(isStylesAttr: boolean, identifierNode: ts.Identifier,

  propName: string, temp): boolean {

  return !isStylesAttr &&

    PROPERTIES_ADD_DOUBLE_DOLLAR.has(identifierNode.escapedText.toString()) &&

    PROPERTIES_ADD_DOUBLE_DOLLAR.get(identifierNode.escapedText.toString()).has(propName) ||

    STYLE_ADD_DOUBLE_DOLLAR.has(propName) && temp.arguments.length && temp.arguments[0] ?

    temp.arguments[0].getText().match(/^(?!\$\$\.)\$\$(.|\n)+/) !== null :

    false;

}



function isDoubleExclamationToChange(isStylesAttr: boolean, identifierNode: ts.Identifier, propName: string, temp: ts.CallExpression): boolean {

  return !isStylesAttr &&

    (STYLE_ADD_DOUBLE_EXCLAMATION.has(propName) && temp.arguments.length && temp.arguments[0] || 

    PROPERTIES_ADD_DOUBLE_EXCLAMATION.has(identifierNode.escapedText.toString()) &&

    PROPERTIES_ADD_DOUBLE_EXCLAMATION.get(identifierNode.escapedText.toString()).has(propName)) &&

    ts.isNonNullExpression(temp.arguments[0]) && ts.isNonNullExpression(temp.arguments[0].expression) &&

    !ts.isNonNullExpression(temp.arguments[0].expression.expression);

}



function isHaveDoubleDollar(param: ts.PropertyAssignment, name: string): boolean {

  return ts.isPropertyAssignment(param) && param.name && ts.isIdentifier(param.name) &&

    PROPERTIES_ADD_DOUBLE_DOLLAR.get(name).has(param.name.getText()) && param.initializer &&

    param.initializer.getText().match(/^(?!\$\$\.)\$\$(.|\n)+/) !== null;

}



function isHaveDoubleExclamation(param: ts.PropertyAssignment, name: string): boolean {

  return ts.isPropertyAssignment(param) && param.name && ts.isIdentifier(param.name) &&

    PROPERTIES_ADD_DOUBLE_EXCLAMATION.has(name) && PROPERTIES_ADD_DOUBLE_EXCLAMATION.get(name).has(param.name.getText()) &&

    param.initializer && ts.isNonNullExpression(param.initializer) && ts.isNonNullExpression(param.initializer.expression) &&

    !ts.isNonNullExpression(param.initializer.expression.expression);

}



function loopEtscomponent(node: any, isStylesAttr: boolean): ts.Node {

  node.arguments.forEach((item: ts.Node, index: number) => {

    if (ts.isEtsComponentExpression(item)) {

      node.arguments[index] = ts.factory.createCallExpression(

        item.expression, undefined, item.arguments);

    } else if ((ts.isCallExpression(item) || ts.isNewExpression(item)) &&

      !newsupplement.isAcceleratePreview) {

      node.arguments[index] = ts.visitEachChild(item,

        changeEtsComponentKind, contextGlobal);

    }

  });

  return node;

}



function changeEtsComponentKind(node: ts.Node): ts.Node {

  if (ts.isEtsComponentExpression(node)) {

    node.kind = 204;

    return node;

  }

  return ts.visitEachChild(node, changeEtsComponentKind, contextGlobal);

}



function classifyArgumentsNum(args, argumentsArr: ts.Expression[], propName: string,

  identifierNode: ts.Identifier): void {

  if (STYLE_ADD_DOUBLE_DOLLAR.has(propName) && args.length >= 2) {

    const varExp: ts.Expression = updateArgumentForDollar(args[0]);

    argumentsArr.push(generateObjectForDollar(varExp), ...args.slice(1));

  } else if (STYLE_ADD_DOUBLE_EXCLAMATION.has(propName) && args.length >= 2) {

    const varExp: ts.Expression = updateArgumentForExclamation(args[0]);

    argumentsArr.push(generateObjectForExclamation(varExp), ...args.slice(1));

  } else if (PROPERTIES_ADD_DOUBLE_DOLLAR.has(identifierNode.escapedText.toString()) && args.length === 1 &&

    PROPERTIES_ADD_DOUBLE_DOLLAR.get(identifierNode.escapedText.toString()).has(propName) ||

    STYLE_ADD_DOUBLE_DOLLAR.has(propName) && args.length === 1) {

    const varExp: ts.Expression = updateArgumentForDollar(args[0]);

    argumentsArr.push(varExp, createArrowFunctionForDollar(varExp));

  }

}



function classifyArgumentsNumV2(args: ts.Expression[], argumentsArr: ts.Expression[], propName: string, 

  identifierNode: ts.Identifier): void {

  const componentName: string = identifierNode.escapedText.toString();

  if (STYLE_ADD_DOUBLE_EXCLAMATION.has(propName) && args.length || 

  PROPERTIES_ADD_DOUBLE_EXCLAMATION.has(componentName) && args.length === 1 &&

  PROPERTIES_ADD_DOUBLE_EXCLAMATION.get(componentName).has(propName)) {

    const varExp: ts.Expression = updateArgumentForExclamation(args[0]);

    argumentsArr.push(generateObjectForExclamation(varExp), ...args.slice(1));

  }

}



function generateObjectForExclamation(varExp: ts.Expression): ts.ObjectLiteralExpression {

  return ts.factory.createObjectLiteralExpression([

      ts.factory.createPropertyAssignment(

        ts.factory.createIdentifier($$_VALUE),

        varExp),

      ts.factory.createPropertyAssignment(

        ts.factory.createIdentifier($_VALUE),

        ts.factory.createArrowFunction(

          undefined, undefined,

          [ts.factory.createParameterDeclaration(

            undefined, undefined,

            ts.factory.createIdentifier($$_NEW_VALUE),

            undefined, undefined, undefined

          )],

          undefined,

          ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),

          ts.factory.createBlock(

            [ts.factory.createExpressionStatement(ts.factory.createBinaryExpression(

              varExp,

              ts.factory.createToken(ts.SyntaxKind.EqualsToken),

              ts.factory.createIdentifier($$_NEW_VALUE)

            ))], false)

        ))], false);

}



function generateObjectForDollar(varExp: ts.Expression): ts.ObjectLiteralExpression {

  return ts.factory.createObjectLiteralExpression(

    [

      ts.factory.createPropertyAssignment(

        ts.factory.createIdentifier($$_VALUE),

        varExp

      ),

      ts.factory.createPropertyAssignment(

        ts.factory.createIdentifier($$_CHANGE_EVENT),

        createArrowFunctionForDollar(varExp)

      )

    ],

    false

  );

}



function generateFunctionPropertyAssignmentForExclamation(name: string, varExp: ts.Expression): ts.PropertyAssignment {

  return ts.factory.createPropertyAssignment(

    ts.factory.createIdentifier('$' + name),

    createArrowFunctionForDollar(varExp)

  );

}



function createViewStackProcessor(item, endViewStack: boolean): ts.ExpressionStatement {

  const argument: ts.StringLiteral[] = [];

  if (!endViewStack && item.name) {

    const tempString: string = (item.name.getText() === HOVERED) ? HOVER : item.name.getText();

    argument.push(ts.factory.createStringLiteral(tempString));

  }

  return ts.factory.createExpressionStatement(ts.factory.createCallExpression(

    ts.factory.createPropertyAccessExpression(

      ts.factory.createIdentifier(VIEW_STACK_PROCESSOR),

      ts.factory.createIdentifier(VISUAL_STATE)

    ),

    undefined,

    argument

  ));

}



function traverseStateStylesAttr(temp, statements: ts.Statement[],

  identifierNode: ts.Identifier, log: LogInfo[], updateStatements: ts.Statement[],

  newImmutableStatements: ts.Statement[] = null, isRecycleComponent: boolean = false,

  permitInitialRender: boolean = true): void {

  temp.arguments[0].properties.reverse().forEach((item: ts.PropertyAssignment) => {

    if (item.name && item.name.getText && item.name.getText() === HOVERED &&

      !isCompatibleVersionOverTarget(26)) {

      return;

    }

    if (ts.isPropertyAccessExpression(item.initializer) &&

      item.initializer.expression.getText() === THIS &&

      INNER_STYLE_FUNCTION.get(item.initializer.name.getText())) {

      const name: string = item.initializer.name.getText();

      bindComponentAttr(INNER_STYLE_FUNCTION.get(name).statements[0] as ts.ExpressionStatement,

        identifierNode, statements, log, false, true, newImmutableStatements);

      if (isRecycleComponent || (hasInitialRenderCondition() && permitInitialRender)) {

        bindComponentAttr(INNER_STYLE_FUNCTION.get(name).statements[0] as ts.ExpressionStatement,

          identifierNode, updateStatements, log, false, true, newImmutableStatements);

      }

    } else if (ts.isIdentifier(item.initializer) &&

      GLOBAL_STYLE_FUNCTION.get(item.initializer.getText())) {

      const name: string = item.initializer.getText();

      bindComponentAttr(GLOBAL_STYLE_FUNCTION.get(name).statements[0] as ts.ExpressionStatement,

        identifierNode, statements, log, false, true, newImmutableStatements);

      if (isRecycleComponent || (hasInitialRenderCondition() && permitInitialRender)) {

        bindComponentAttr(GLOBAL_STYLE_FUNCTION.get(name).statements[0] as ts.ExpressionStatement,

          identifierNode, updateStatements, log, false, true, newImmutableStatements);

      }

    } else if (ts.isObjectLiteralExpression(item.initializer) &&

      item.initializer.properties.length === 1 &&

      ts.isPropertyAssignment(item.initializer.properties[0])) {

      bindComponentAttr(ts.factory.createExpressionStatement(

        item.initializer.properties[0].initializer), identifierNode, statements, log, false, true,

      newImmutableStatements);

      if (isRecycleComponent || (hasInitialRenderCondition() && permitInitialRender)) {

        bindComponentAttr(ts.factory.createExpressionStatement(

          item.initializer.properties[0].initializer), identifierNode, updateStatements, log, false, true,

        newImmutableStatements);

      }

    } else {

      if (!(ts.isObjectLiteralExpression(item.initializer) && item.initializer.properties.length === 0)) {

        validateStateStyleSyntax(temp, log);

      }

    }

    if (item.name) {

      const viewNode: ts.Statement = createViewStackProcessor(item, false);

      statements.push(viewNode);

      if (isRecycleComponent || (hasInitialRenderCondition() && permitInitialRender)) {

        updateStatements.push(viewNode);

      }

    }

  });

}



interface ExtendType {

  type: string

}



function isExtendFunctionNode(identifierNode: ts.Identifier, propName: string,

  extendType: ExtendType): boolean {

  const componentName: string = identifierNode.escapedText.toString();

  if (EXTEND_ATTRIBUTE.has(componentName) && [...EXTEND_ATTRIBUTE.get(componentName)].includes(propName)) {

    extendType.type = CHECK_COMPONENT_EXTEND_DECORATOR;

    return true;

  }

  const animatableExtendAttribute: Map<string, Set<string>> =

    storedFileInfo.getCurrentArkTsFile().animatableExtendAttribute;

  if (animatableExtendAttribute.has(componentName) &&

    [...animatableExtendAttribute.get(componentName)].includes(propName)) {

    extendType.type = CHECK_COMPONENT_ANIMATABLE_EXTEND_DECORATOR;

    return true;

  }

  return false;

}



const gestureMap: Map<string, string> = new Map([

  [PRIORITY_GESTURE_ATTRIBUTE, GESTURE_ENUM_VALUE_HIGH],

  [PARALLEL_GESTURE_ATTRIBUTE, GESTURE_ENUM_VALUE_PARALLEL],

  [GESTURE_ATTRIBUTE, GESTURE_ENUM_VALUE_LOW]

]);



function parseGesture(node: ts.CallExpression, propName: string, statements: ts.Statement[],

  log: LogInfo[], updateStatements: ts.Statement[]): void {

  const popNode: ts.Statement = ts.factory.createExpressionStatement(

    createFunction(ts.factory.createIdentifier(COMPONENT_GESTURE),

      ts.factory.createIdentifier(COMPONENT_POP_FUNCTION), null));

  statements.push(popNode);

  updateStatements.push(popNode);

  parseGestureInterface(node, statements, log, updateStatements);

  const argumentArr: ts.NodeArray<ts.PropertyAccessExpression> = ts.factory.createNodeArray(

    [ts.factory.createPropertyAccessExpression(

      ts.factory.createIdentifier(GESTURE_ENUM_KEY),

      ts.factory.createIdentifier(gestureMap.get(propName)))

    ]

  );

  if (node.arguments && node.arguments.length > 1 &&

    ts.isPropertyAccessExpression(node.arguments[1])) {

    // @ts-ignore

    argumentArr.push(node.arguments[1]);

  }

  const createNode: ts.Statement = ts.factory.createExpressionStatement(

    createFunction(ts.factory.createIdentifier(COMPONENT_GESTURE),

      ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION), argumentArr));

  statements.push(createNode);

  updateStatements.push(createNode);

}



function parseGestureInitialRender(node: ts.CallExpression, propName: string, statements: ts.Statement[],

  log: LogInfo[], immutableStatements: ts.Statement[], isStylesAttr: boolean = false,

  isStyleFunction: boolean = false): void {

  const newCollectImmutableStatements: ts.Statement[] = [];

  const isStyleCondition: boolean = isStylesAttr && isStyleFunction;

  const popNode: ts.Statement = ts.factory.createExpressionStatement(

    createFunction(ts.factory.createIdentifier(COMPONENT_GESTURE),

      ts.factory.createIdentifier(COMPONENT_POP_FUNCTION), null));

  statements.push(popNode);

  isStyleCondition ? newCollectImmutableStatements.push(popNode) : immutableStatements.push(popNode);

  parseGestureInterface(node, statements, log,

    isStyleCondition ? newCollectImmutableStatements : immutableStatements);

  const argumentArr: ts.NodeArray<ts.PropertyAccessExpression> = ts.factory.createNodeArray(

    [ts.factory.createPropertyAccessExpression(

      ts.factory.createIdentifier(GESTURE_ENUM_KEY),

      ts.factory.createIdentifier(gestureMap.get(propName)))

    ]

  );

  if (node.arguments && node.arguments.length > 1 &&

    ts.isPropertyAccessExpression(node.arguments[1])) {

    // @ts-ignore

    argumentArr.push(node.arguments[1]);

  }

  const createNode: ts.Statement = ts.factory.createExpressionStatement(

    createFunction(ts.factory.createIdentifier(COMPONENT_GESTURE),

      ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION), argumentArr));

  statements.push(createNode);

  isStyleCondition ? newCollectImmutableStatements.push(createNode) :

    immutableStatements.push(createNode);

  isStyleCondition &&

    immutableStatements.push(...newCollectImmutableStatements.reverse());

}



function processGestureType(node: ts.CallExpression, statements: ts.Statement[], log: LogInfo[],

  updateStatements: ts.Statement[], reverse: boolean = false): void {

  const newStatements: ts.Statement[] = [];

  const newNode: ts.ExpressionStatement = ts.factory.createExpressionStatement(node);

  let temp = node.expression;

  while (temp && !ts.isIdentifier(temp) && temp.expression) {

    temp = temp.expression;

  }

  if (temp && temp.parent && ts.isCallExpression(temp.parent) && ts.isIdentifier(temp) &&

    GESTURE_TYPE_NAMES.has(temp.escapedText.toString())) {

    newStatements.push(ts.factory.createExpressionStatement(

      createFunction(temp, ts.factory.createIdentifier(COMPONENT_POP_FUNCTION), null)));

    if (temp.escapedText.toString() === COMPONENT_GESTURE_GROUP) {

      const gestureStatements: ts.Statement[] = [];

      parseGestureInterface(temp.parent, gestureStatements, log, [], true);

      newStatements.push(...gestureStatements.reverse());

      bindComponentAttr(newNode, temp, newStatements, log, false);

      let argumentArr: ts.NodeArray<ts.Expression> = null;

      if (temp.parent.arguments && temp.parent.arguments.length) {

        // @ts-ignore

        argumentArr = ts.factory.createNodeArray([temp.parent.arguments[0]]);

      }

      newStatements.push(ts.factory.createExpressionStatement(

        createFunction(temp, ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION), argumentArr)));

    } else {

      bindComponentAttr(newNode, temp, newStatements, log, false);

      newStatements.push(ts.factory.createExpressionStatement(

        createFunction(temp, ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION), temp.parent.arguments)));

    }

  }

  if (newStatements.length) {

    reverse ? statements.push(...newStatements.reverse()) : statements.push(...newStatements);

    reverse ? updateStatements.push(...newStatements.reverse()) : updateStatements.push(...newStatements);

  }

}



function parseGestureInterface(node: ts.CallExpression, statements: ts.Statement[], log: LogInfo[],

  updateStatements: ts.Statement[], reverse: boolean = false): void {

  if (node.arguments && node.arguments.length) {

    node.arguments.forEach((item: ts.Node) => {

      if (ts.isCallExpression(item)) {

        processGestureType(item, statements, log, updateStatements, reverse);

      }

    });

  }

}



export function getName(node: ts.ExpressionStatement | ts.Expression): string {

  // @ts-ignore

  let temp = node.expression;

  let name: string;

  while (temp) {

    if (ts.isIdentifier(temp) && temp.parent && (ts.isCallExpression(temp.parent) ||

      ts.isEtsComponentExpression(temp.parent))) {

      name = temp.escapedText.toString();

      break;

    } else if (ts.isPropertyAccessExpression(temp) && temp.name && ts.isIdentifier(temp.name) &&

      isCustomAttributes(temp)) {

      name = temp.name.escapedText.toString();

      break;

    }

    temp = temp.expression;

  }

  return name;

}



function isCustomAttributes(temp: ts.PropertyAccessExpression): boolean {

  if (temp.expression && temp.expression.getText() === THIS) {

    return true;

  } else if (temp.expression && ts.isIdentifier(temp.expression) && temp.expression.getText() === $$ &&

    builderTypeParameter.params.includes(temp.expression.getText())) {

    return true;

  } else {

    return !BUILDIN_STYLE_NAMES.has(temp.name.escapedText.toString());

  }

}



export function isAttributeNode(node: ts.ExpressionStatement): boolean {

  let temp: any = node.expression;

  let name: string;

  while (temp) {

    if (ts.isCallExpression(temp) && temp.expression && ts.isIdentifier(temp.expression)) {

      name = temp.expression.escapedText.toString();

      break;

    }

    temp = temp.expression;

  }

  return BUILDIN_STYLE_NAMES.has(name);

}



enum ComponentType {

  innerComponent,

  customComponent,

  forEachComponent,

  customBuilderMethod,

  builderParamMethod,

  function,

  builderTypeFunction,

  repeatComponent,

  mutableBuilderMethod

}



function isEtsComponent(node: ts.ExpressionStatement): boolean {

  let isEtsComponent: boolean = false;

  let temp: any = node.expression;

  while (temp) {

    if (ts.isEtsComponentExpression(temp)) {

      isEtsComponent = true;

    }

    temp = temp.expression;

  }

  return isEtsComponent;

}



function isSomeName(forEachParameters: ts.NodeArray<ts.ParameterDeclaration>, name: string): boolean {

  return Array.isArray(forEachParameters) &&

    forEachParameters.some((item) => {

      return ts.isIdentifier(item.name) ? item.name.escapedText.toString() === name : false;

    });

}



function isParamFunction(node: ts.ExpressionStatement): boolean {

  return node.expression && ts.isCallExpression(node.expression) &&

    node.expression.expression && ts.isIdentifier(node.expression.expression);

}



function getComponentType(node: ts.ExpressionStatement, log: LogInfo[], name: string,

  parent: string, forEachParameters: ts.NodeArray<ts.ParameterDeclaration> = undefined): ComponentType {

  let isBuilderName: boolean = true;

  let isLocalBuilderName: boolean = true;

  if (forEachParameters && isSomeName(forEachParameters, name) && isParamFunction(node)) {

    isBuilderName = false;

    isLocalBuilderName = false;

  }

  if (isEtsComponent(node)) {

    if (componentCollection.customComponents.has(name)) {

      isCustomComponentAttributes(node, log);

      return ComponentType.customComponent;

    } else {

      return ComponentType.innerComponent;

    }

  } else if (!isPartMethod(node) && componentCollection.customComponents.has(name)) {

    isCustomComponentAttributes(node, log);

    return ComponentType.customComponent;

  } else if (name === COMPONENT_FOREACH || name === COMPONENT_LAZYFOREACH) {

    return ComponentType.forEachComponent;

  } else if (name === COMPONENT_REPEAT) {

    return ComponentType.repeatComponent;

  } else if (isLocalBuilderOrBuilderMethod(CUSTOM_BUILDER_METHOD, isBuilderName, name) || isWrappedBuilderExpression(node) ||

    isLocalBuilderOrBuilderMethod(INNER_CUSTOM_LOCALBUILDER_METHOD, isLocalBuilderName, name)) {

    return ComponentType.customBuilderMethod;

  } else if (isMutableBuilderExpression(node)) {

    return ComponentType.mutableBuilderMethod;

  } else if (builderParamObjectCollection.get(componentCollection.currentClassName) &&

    builderParamObjectCollection.get(componentCollection.currentClassName).has(name)) {

    return ComponentType.builderParamMethod;

  } else if (!partialUpdateConfig.builderCheck && builderTypeParameter.params.includes(name) &&

    judgeBuilderType(node)) {

    return ComponentType.builderTypeFunction;

  } else if ((['XComponent'].includes(parent) || CUSTOM_BUILDER_METHOD.has(parent)) &&

    ts.isCallExpression(node.expression) && ts.isIdentifier(node.expression.expression)) {

    return ComponentType.function;

  } else if (!isAttributeNode(node)) {

    log.push({

      type: LogType.ERROR,

      message: `'${node.getText()}' does not meet UI component syntax.`,

      pos: node.getStart(),

      code: '10905204'

    });

  }

  return null;

}



function isCustomComponentAttributes(node: ts.ExpressionStatement, log: LogInfo[]): void {

  if (node.expression && ts.isCallExpression(node.expression) && ts.isPropertyAccessExpression(node.expression.expression) &&

    !ts.isIdentifier(node.expression.expression.expression) && ts.isIdentifier(node.expression.expression.name) &&

    !COMMON_ATTRS.has(node.expression.expression.name.escapedText.toString())) {

      log.push({

        type: LogType.ERROR,

        message: `'${node.getText()}' does not meet UI component syntax.`,

        pos: node.getStart()

      });

  }

}



function isLocalBuilderOrBuilderMethod(LocalBuilderOrBuilderSet: Set<string>,

  isLocalBuilderOrBuilderName: boolean, name: string): boolean {

  return LocalBuilderOrBuilderSet.has(name) && isLocalBuilderOrBuilderName;

}



function isPartMethod(node: ts.ExpressionStatement): boolean {

  if (ts.isCallExpression(node.expression) && ts.isPropertyAccessExpression(node.expression.expression) &&

    node.expression.expression.expression && node.expression.expression.expression.kind &&

    node.expression.expression.expression.kind === ts.SyntaxKind.ThisKeyword) {

    return true;

  } else {

    return false;

  }

}



function isWrappedBuilderExpression(node: ts.ExpressionStatement): boolean {

  if (projectConfig.minAPIVersion >= APIVERSION.apiVersionEleven && node.expression &&

    isWrappedBuilderCallExpression(node.expression as ts.CallExpression)) {

    return true;

  }

  return false;

}



function judgeBuilderType(node: ts.ExpressionStatement): boolean {

  let checker: ts.TypeChecker;

  if (globalProgram.program) {

    checker = CurrentProcessFile.getChecker(globalProgram.program);

  } else if (globalProgram.watchProgram) {

    checker = globalProgram.watchProgram.getCurrentProgram().getProgram().getTypeChecker();

  }

  if (node.expression && node.expression.expression && checker) {

    const type: ts.Type = checker.getTypeAtLocation(node.expression.expression);

    if (type && type.aliasSymbol && type.aliasSymbol.escapedName === BUILDER_TYPE) {

      return true;

    }

  }

  return false;

}



export function validateStateStyleSyntax(temp, log: LogInfo[]): void {

  log.push({

    type: LogType.ERROR,

    message: `'.stateStyles' doesn't conform standard.`,

    pos: temp.getStart(),

    code: '10905203'

  });

}



function getEtsComponentExpression(node:ts.ExpressionStatement): ts.EtsComponentExpression {

  let current = node.expression;

  while (current) {

    if (ts.isEtsComponentExpression(current)) {

      return current;

    }

    current = current.expression;

  }

  return null;

}



function checkEtsAndIdInIf(node:ts.ExpressionStatement, parent: string): [ts.EtsComponentExpression, ts.Expression] {

  let current = node.expression;

  let idName: ts.Expression;

  while (current) {

    if (ts.isEtsComponentExpression(current)) {

      break;

    }

    if (!idName && parent === COMPONENT_IF && ts.isPropertyAccessExpression(current) && current.name &&

      ts.isIdentifier(current.name) && current.name.escapedText.toString() === ATTRIBUTE_ID &&

      current.parent && current.parent.arguments && current.parent.arguments.length) {

      idName = current.parent.arguments[0];

    }

    current = current.expression;

  }

  return [current, idName];

}



function checkIdInIf(node:ts.ExpressionStatement, parent: string): ts.Expression {

  let current: any = node.expression;

  let idName: ts.Expression;

  while (current) {

    if (parent === COMPONENT_IF && ts.isPropertyAccessExpression(current) && current.name &&

      ts.isIdentifier(current.name) && current.name.escapedText.toString() === ATTRIBUTE_ID &&

      current.parent && current.parent.arguments && current.parent.arguments.length) {

      idName = current.parent.arguments[0];

      break;

    }

    current = current.expression;

  }

  return idName;

}



function checkEtsComponent(node: ts.ExpressionStatement, log: LogInfo[]): void {

  const etsComponentExpression: ts.EtsComponentExpression = getEtsComponentExpression(node);

  if (etsComponentExpression) {

    checkAllNode(

      etsComponentExpression,

      new Set([...INNER_COMPONENT_NAMES, ...componentCollection.customComponents]),

      transformLog.sourceFile,

      log

    );

  }

}



function checkButtonParamHasLabel(node: ts.EtsComponentExpression, log: LogInfo[]): void {

  if (node.arguments && node.arguments.length !== 0) {

    for (let i = 0; i < node.arguments.length; i++) {

      const argument: ts.Expression = node.arguments[i];

      if (ts.isStringLiteral(argument) || (ts.isCallExpression(argument) && ts.isIdentifier(argument.expression) &&

        (argument.expression.escapedText.toString() === RESOURCE))) {

        log.push({

          type: LogType.ERROR,

          message: 'The Button component with a label parameter can not have any child.',

          pos: node.getStart(),

          code: '10905202'

        });

        return;

      }

    }

  }

}



function isLazyForEachChild(node: ts.ExpressionStatement): boolean {

  let temp = node.parent;

  while (temp && !ts.isEtsComponentExpression(temp) && !ts.isCallExpression(temp)) {

    temp = temp.parent;

  }

  if (temp && temp.expression && (temp.expression as ts.Identifier).escapedText?.toString() === COMPONENT_LAZYFOREACH) {

    return true;

  }

  return false;

}



function processDollarEtsComponent(argumentsArr: ts.NodeArray<ts.Expression>, name: string): ts.Expression[] {

  const arr: ts.Expression[] = [];

  argumentsArr.forEach((item: ts.Expression, index: number) => {

    if (ts.isObjectLiteralExpression(item) && item.properties && item.properties.length) {

      const properties: ts.PropertyAssignment[] = [];

      item.properties.forEach((param: ts.PropertyAssignment, paramIndex: number) => {

        if (isHaveDoubleDollar(param, name)) {

          const varExp: ts.Expression = updateArgumentForDollar(param.initializer);

          properties.push(ts.factory.updatePropertyAssignment(param, param.name, generateObjectForDollar(varExp)));

        } else {

          properties.push(param);

        }

      });

      arr.push(ts.factory.updateObjectLiteralExpression(item, properties));

    } else {

      arr.push(item);

    }

  });

  return arr;

}



function processExclamationEtsComponent(argumentsArr: ts.NodeArray<ts.Expression>, name: string): ts.Expression[] {

  const arr: ts.Expression[] = [];

  argumentsArr.forEach((item: ts.Expression, index: number) => {

    if (ts.isObjectLiteralExpression(item) && item.properties && item.properties.length) {

      const properties: ts.PropertyAssignment[] = [];

      item.properties.forEach((param: ts.PropertyAssignment, paramIndex: number) => {

        if (isHaveDoubleExclamation(param, name) && param.initializer && param.name) {

          const varExp: ts.Expression = updateArgumentForExclamation(param.initializer);

          properties.push(ts.factory.updatePropertyAssignment(param, param.name, varExp));

          properties.push(generateFunctionPropertyAssignmentForExclamation(param.name.getText(), varExp));

        } else {

          properties.push(param);

        }

      });

      arr.push(ts.factory.updateObjectLiteralExpression(item, properties));

    } else {

      arr.push(item);

    }

  });

  return arr;

}



function createTrailingFunction(

  node: ts.Identifier,

  attrNode: ts.Identifier,

  argumentsArr: ts.NodeArray<ts.Expression>,

  arrowFunctionStatements?: ts.Statement[]

): ts.CallExpression {

  const compName: string = node.escapedText.toString();

  const type: string = attrNode.escapedText.toString();

  if (argumentsArr && argumentsArr.length) {

    if (type === COMPONENT_CREATE_FUNCTION && PROPERTIES_ADD_DOUBLE_DOLLAR.has(compName)) {

      // @ts-ignore

      argumentsArr = processDollarEtsComponent(argumentsArr, compName);

    }

    if (type === COMPONENT_CREATE_FUNCTION && PROPERTIES_ADD_DOUBLE_EXCLAMATION.has(compName)) {

      argumentsArr = processExclamationEtsComponent(argumentsArr, compName) as unknown as ts.NodeArray<ts.Expression>;

    }

    if (checkCreateArgumentBuilder(node, attrNode)) {

      argumentsArr = transformBuilder(argumentsArr);

    }

  } else {

    // @ts-ignore

    argumentsArr = navigationCreateParam(compName, type);

  }

  return ts.factory.createCallExpression(

    ts.factory.createPropertyAccessExpression(

      node,

      attrNode

    ),

    undefined,

    [

      ...argumentsArr,

      arrowFunctionStatements ?

        ts.factory.createArrowFunction(

          undefined,

          undefined,

          [],

          undefined,

          ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),

          ts.factory.createBlock(

            arrowFunctionStatements,

            true

          )

        ) :

        ts.factory.createIdentifier('undefined')

    ]

  );

}



export function createFunction(node: ts.Identifier, attrNode: ts.Identifier,

  argumentsArr: ts.NodeArray<ts.Expression>, isAttributeModifier: boolean = false): ts.CallExpression {

  const compName: string = node.escapedText.toString();

  const type: string = attrNode.escapedText.toString();

  const globalThisArr: string[] = [COMPONENT_GESTURE, GLOBAL_CONTEXT];

  if (argumentsArr && argumentsArr.length) {

    if (type === COMPONENT_CREATE_FUNCTION && PROPERTIES_ADD_DOUBLE_DOLLAR.has(compName)) {

      // @ts-ignore

      argumentsArr = processDollarEtsComponent(argumentsArr, compName);

    }

    if (type === COMPONENT_CREATE_FUNCTION && PROPERTIES_ADD_DOUBLE_EXCLAMATION.has(compName)) {

      argumentsArr = processExclamationEtsComponent(argumentsArr, compName) as unknown as ts.NodeArray<ts.Expression>;

    }

    if (checkCreateArgumentBuilder(node, attrNode)) {

      argumentsArr = transformBuilder(argumentsArr);

    }

    if (((compName === NAVIGATION) || equalToHiddenNav(compName)) &&

      type === COMPONENT_CREATE_FUNCTION && partialUpdateConfig.partialUpdateMode) {

      // @ts-ignore

      argumentsArr = navigationCreateParam(compName, type, argumentsArr);

    }

  } else {

    // @ts-ignore

    argumentsArr = navigationCreateParam(compName, type);

  }

  return ts.factory.createCallExpression(

    isAttributeModifier ? ts.factory.createCallExpression(

      ts.factory.createPropertyAccessExpression(

        ts.factory.createPropertyAccessExpression(

          node,

          attrNode

        ),

        ts.factory.createIdentifier(BUILDER_ATTR_BIND)

      ),

      undefined,

      [ts.factory.createThis()]

    ) : 

      ts.factory.createPropertyAccessExpression(

        globalThisArr.includes(compName) ? ts.factory.createPropertyAccessExpression(

          ts.factory.createIdentifier(GLOBAL_THIS), node) : node,

        attrNode

      ),

    undefined,

    argumentsArr

  );

}



function navigationCreateParam(compName: string, type: string,

  argumentsArr: ts.NodeArray<ts.Expression> = undefined, isNavDestinationCallback: boolean = false):

  (ts.ObjectLiteralExpression | ts.NewExpression | ts.ArrowFunction)[] | [] {

  const navigationOrNavDestination: (ts.ObjectLiteralExpression | ts.NewExpression | ts.ArrowFunction)[] = [];

  const isCreate: boolean = type === COMPONENT_CREATE_FUNCTION;

  const partialUpdateMode: boolean = partialUpdateConfig.partialUpdateMode;

  let isHaveParam: boolean = true;

  if (argumentsArr && argumentsArr.length) {

    // @ts-ignore

    navigationOrNavDestination.push(...argumentsArr);

  } else if (partialUpdateMode && isCreate) {

    if ((compName === NAVIGATION) || equalToHiddenNav(compName)) {

      isHaveParam = false;

      navigationOrNavDestination.push(ts.factory.createNewExpression(

        ts.factory.createIdentifier(NAV_PATH_STACK), undefined, []

      ));

    } else if (((compName === NAV_DESTINATION) || equalToHiddenNavDes(compName)) &&

      !isNavDestinationCallback) {

      navigationOrNavDestination.push(ts.factory.createArrowFunction(

        undefined, undefined, [], undefined,

        ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),

        ts.factory.createBlock(

          [],

          false

        )

      ));

    }

  }

  if (CREATE_ROUTER_COMPONENT_COLLECT.has(compName) && isCreate && partialUpdateMode) {

    navigationOrNavDestination.push(ts.factory.createObjectLiteralExpression(

      navigationOrNavDestinationCreateContent(compName, isHaveParam),

      false

    ));

  }

  return navigationOrNavDestination;

}



function navigationOrNavDestinationCreateContent(compName: string, isHaveParam: boolean): ts.PropertyAssignment[] {

  const navigationOrNavDestinationContent: ts.PropertyAssignment[] = [];

  navigationOrNavDestinationContent.push(ts.factory.createPropertyAssignment(

    ts.factory.createIdentifier(RESOURCE_NAME_MODULE),

    ts.factory.createStringLiteral(projectConfig.moduleName || '')

  ),

    ts.factory.createPropertyAssignment(

      ts.factory.createIdentifier(PAGE_PATH),

      ts.factory.createStringLiteral(

        projectConfig.compileHar ? '' :

          path.relative(projectConfig.projectRootPath || '', resourceFileName).replace(/\\/g, '/').replace(/\.ets$/, '')

      )

    ));

  if ((compName === NAVIGATION) || equalToHiddenNav(compName)) {

    navigationOrNavDestinationContent.push(ts.factory.createPropertyAssignment(

      ts.factory.createIdentifier(IS_USER_CREATE_STACK),

      isHaveParam ? ts.factory.createTrue() : ts.factory.createFalse()

    ));

  }

  return navigationOrNavDestinationContent;

}



function checkCreateArgumentBuilder(node: ts.Identifier, attrNode: ts.Identifier): boolean {

  if (attrNode.escapedText.toString() === COMPONENT_CREATE_FUNCTION &&

    CREATE_BIND_COMPONENT.has(node.escapedText.toString())) {

    return true;

  }

  return false;

}



function transformBuilder(argumentsArr: ts.NodeArray<ts.Expression>): ts.NodeArray<ts.Expression> {

  const newArguments: ts.Expression[] = [];

  argumentsArr.forEach((argument: ts.Expression) => {

    newArguments.push(parseCreateParameterBuilder(argument));

  });

  // @ts-ignore

  return newArguments;

}



function parseCreateParameterBuilder(argument: ts.Expression):ts.Expression {

  if (ts.isObjectLiteralExpression(argument)) {

    return processObjectPropertyBuilder(argument);

  } else {

    return argument;

  }

}



function checkNonspecificParents(node: ts.ExpressionStatement, name: string, savedParent: string, log: LogInfo[]): void {

  if (SPECIFIC_PARENT_COMPONENT.has(name)) {

    const specificParemtsSet: Set<string> = SPECIFIC_PARENT_COMPONENT.get(name);

    if (!specificParemtsSet.has(savedParent) && INNER_COMPONENT_NAMES.has(savedParent)) {

      const specificParentArray: string =

        Array.from(SPECIFIC_PARENT_COMPONENT.get(name)).join(',');

      log.push({

        type: LogType.ERROR,

        message: `The '${name}' component can only be nested in the '${specificParentArray}' parent component.`,

        pos: node.expression.getStart(),

        code: '10905201'

      });

    }

  }

}



function equalToHiddenNav(componentName: string): boolean {

  return (EXT_WHITE_LIST.length >= 2) && (componentName === EXT_WHITE_LIST[0]) || (componentName === HDSNAVIGATION);

}



function equalToHiddenNavDes(componentName: string): boolean {

  return (EXT_WHITE_LIST.length >= 2) && (componentName === EXT_WHITE_LIST[1]) || (componentName === HDSNAVDESTINATION);

}



export function transferMutableBuilderCall(node: ts.ExpressionStatement, name: string): ts.ExpressionStatement {

  if (node.expression && ts.isCallExpression(node.expression)) {

    let newNode: ts.Expression = mutableBuilderCallNode(node.expression);

    if (node.expression.arguments && node.expression.arguments.length === 1 && ts.isObjectLiteralExpression(node.expression.arguments[0]) &&

      ts.isPropertyAccessExpression(node.expression.expression)) {

      return ts.factory.createExpressionStatement(ts.factory.updateCallExpression(

        node.expression,

        newNode,

        undefined,

        [ts.factory.createArrowFunction(undefined,

          undefined,

          [],

          undefined,

          ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),

          node.expression.expression.expression),

        ts.factory.createCallExpression(

          ts.factory.createIdentifier(BUILDER_PARAM_PROXY),

          undefined,

          [

            ts.factory.createStringLiteral(name),

            traverseBuilderParams(node.expression.arguments[0], true)

          ]

        )]

      ));

    } else if (ts.isPropertyAccessExpression(node.expression.expression)) {

      return ts.factory.createExpressionStatement(ts.factory.updateCallExpression(

        node.expression,

        newNode,

        undefined,

        !(projectConfig.optLazyForEach && (storedFileInfo.processLazyForEach &&

          storedFileInfo.lazyForEachInfo.forEachParameters || true)) ?

          [ts.factory.createArrowFunction(undefined,

            undefined,

            [],

            undefined,

            ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),

            node.expression.expression.expression),

          ...node.expression.arguments] :

          [...node.expression.arguments, ts.factory.createNull(), ts.factory.createIdentifier(MY_IDS)]

      ));

    }

  }

  return undefined;

}



function mutableBuilderCallNode(node: ts.CallExpression): ts.Expression {

  let newNode: ts.Expression;

  if (node.expression && ts.isPropertyAccessExpression(node.expression)) {

    newNode = ts.factory.createCallExpression(

      ts.factory.createPropertyAccessExpression(

        ts.factory.createPropertyAccessExpression(

          node.expression.expression,

          ts.factory.createIdentifier(MUTABLEBUILDER_DISPATCHBUILDER)

        ),

        ts.factory.createIdentifier(BUILDER_ATTR_BIND)

      ),

      undefined,

      [ts.factory.createThis()]

    );

  }

  return newNode;

}



export function isMutableBuilder(node: ts.PropertyAccessExpression): boolean {

  if (!(

    ts.isPropertyAccessExpression(node) &&

    node.name && ts.isIdentifier(node.name) &&

    node.name.escapedText.toString() === MUTABLEBUILDER_BUILDERPROP

  )) {

    return false;

  }

  const checker: ts.TypeChecker | undefined = CurrentProcessFile.getChecker();

  if (checker) {

    const type: ts.Type | ts.Type[] =

      findNonNullType(checker.getTypeAtLocation(node.expression));

    if (Array.isArray(type)) {

      return false;

    }

    return type.symbol && type.symbol.escapedName === MUTABLEBUILDER_CLASS;

  }

  return false;

}



function isMutableBuilderCallExpression(node: ts.CallExpression): boolean {

  if (ts.isCallExpression(node) && node.expression &&

    isMutableBuilder(node.expression as ts.PropertyAccessExpression)) {

    return true;

  }

  return false;

}



function isMutableBuilderExpression(node: ts.ExpressionStatement): boolean {

  if (node.expression &&

    isMutableBuilderCallExpression(node.expression as ts.CallExpression)) {

    return true;

  }

  return false;

}