• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import ts from 'typescript';
17import path from 'path';
18
19import {
20  COMPONENT_RENDER_FUNCTION,
21  COMPONENT_CREATE_FUNCTION,
22  COMPONENT_POP_FUNCTION,
23  COMPONENT_BUTTON,
24  COMPONENT_CREATE_LABEL_FUNCTION,
25  COMPONENT_CREATE_CHILD_FUNCTION,
26  COMPONENT_FOREACH,
27  COMPONENT_LAZYFOREACH,
28  IS_RENDERING_IN_PROGRESS,
29  FOREACH_OBSERVED_OBJECT,
30  FOREACH_GET_RAW_OBJECT,
31  COMPONENT_IF,
32  COMPONENT_IF_BRANCH_ID_FUNCTION,
33  COMPONENT_IF_UNDEFINED,
34  ATTRIBUTE_ANIMATION,
35  GLOBAL_CONTEXT,
36  COMPONENT_GESTURE,
37  COMPONENT_GESTURE_GROUP,
38  GESTURE_ATTRIBUTE,
39  PARALLEL_GESTURE_ATTRIBUTE,
40  PRIORITY_GESTURE_ATTRIBUTE,
41  GESTURE_ENUM_KEY,
42  GESTURE_ENUM_VALUE_HIGH,
43  GESTURE_ENUM_VALUE_LOW,
44  GESTURE_ENUM_VALUE_PARALLEL,
45  COMPONENT_TRANSITION_NAME,
46  COMPONENT_DEBUGLINE_FUNCTION,
47  ATTRIBUTE_STATESTYLES,
48  THIS,
49  VISUAL_STATE,
50  VIEW_STACK_PROCESSOR,
51  STYLE_ADD_DOUBLE_DOLLAR,
52  $$_VALUE,
53  $$_CHANGE_EVENT,
54  $$_THIS,
55  $$_NEW_VALUE,
56  BUILDER_ATTR_NAME,
57  BUILDER_ATTR_BIND,
58  CUSTOM_DIALOG_CONTROLLER_BUILDER,
59  BIND_DRAG_SET,
60  BIND_POPUP_SET,
61  BIND_POPUP,
62  CUSTOM_COMPONENT_DEFAULT,
63  $$,
64  PROPERTIES_ADD_DOUBLE_DOLLAR,
65  ATTRIBUTE_ID,
66  RESOURCE,
67  ISINITIALRENDER,
68  ELMTID,
69  VIEWSTACKPROCESSOR,
70  STOPGETACCESSRECORDING,
71  STARTGETACCESSRECORDINGFOR,
72  OBSERVECOMPONENTCREATION,
73  OBSERVECOMPONENTCREATION2,
74  ISLAZYCREATE,
75  DEEPRENDERFUNCTION,
76  ITEMCREATION,
77  OBSERVEDSHALLOWRENDER,
78  OBSERVEDDEEPRENDER,
79  ItemComponents,
80  FOREACHITEMGENFUNCTION,
81  __LAZYFOREACHITEMGENFUNCTION,
82  _ITEM,
83  FOREACHITEMIDFUNC,
84  __LAZYFOREACHITEMIDFUNC,
85  FOREACHUPDATEFUNCTION,
86  COMPONENT_INITIAl_RENDER_FUNCTION,
87  LIST_ITEM,
88  IFELSEBRANCHUPDATEFUNCTION,
89  CARD_ENABLE_COMPONENTS,
90  CARD_LOG_TYPE_COMPONENTS,
91  COMPONENT_CONSTRUCTOR_PARENT,
92  RESOURCE_NAME_TYPE,
93  XCOMPONENT_SINGLE_QUOTATION,
94  XCOMPONENT_DOUBLE_QUOTATION,
95  XCOMPONENTTYPE,
96  XCOMPONENTTYPE_CONTAINER,
97  BIND_OBJECT_PROPERTY,
98  TRUE,
99  FALSE,
100  HEADER,
101  FOOTER,
102  CALL,
103  CREATE_BIND_COMPONENT,
104  TabContentAndNavDestination,
105  START,
106  END,
107  BUILDER_PARAM_PROXY,
108  BUILDER_TYPE,
109  CHECK_COMPONENT_EXTEND_DECORATOR,
110  CHECK_COMPONENT_ANIMATABLE_EXTEND_DECORATOR,
111  RECYCLE_REUSE_ID,
112  UPDATE_FUNC_BY_ELMT_ID,
113  CREATE_SET_METHOD,
114  CAN_RETAKE
115} from './pre_define';
116import {
117  INNER_COMPONENT_NAMES,
118  BUILDIN_CONTAINER_COMPONENT,
119  BUILDIN_STYLE_NAMES,
120  CUSTOM_BUILDER_METHOD,
121  GESTURE_ATTRS,
122  GESTURE_TYPE_NAMES,
123  EXTEND_ATTRIBUTE,
124  NO_DEBUG_LINE_COMPONENT,
125  NEEDPOP_COMPONENT,
126  INNER_STYLE_FUNCTION,
127  GLOBAL_STYLE_FUNCTION,
128  COMMON_ATTRS,
129  CUSTOM_BUILDER_PROPERTIES,
130  CUSTOM_BUILDER_PROPERTIES_WITHOUTKEY,
131  CUSTOM_BUILDER_CONSTRUCTORS,
132  INNER_CUSTOM_BUILDER_METHOD,
133  GLOBAL_CUSTOM_BUILDER_METHOD,
134  ID_ATTRS
135} from './component_map';
136import {
137  componentCollection,
138  builderParamObjectCollection,
139  checkAllNode,
140  enumCollection,
141} from './validate_ui_syntax';
142import {
143  processCustomComponent,
144  createConditionParent,
145  isRecycle,
146} from './process_custom_component';
147import {
148  LogType,
149  LogInfo,
150  componentInfo,
151  storedFileInfo
152} from './utils';
153import {
154  globalProgram,
155  partialUpdateConfig,
156  projectConfig
157} from '../main';
158import {
159  transformLog,
160  contextGlobal,
161  validatorCard,
162  builderTypeParameter
163} from './process_ui_syntax';
164import { props } from './compile_info';
165import { regularCollection } from './validate_ui_syntax';
166
167const checkComponents: Set<string> = new Set([
168  "TextArea", "TextInput", "GridContainer"
169]);
170
171export function processComponentBuild(node: ts.MethodDeclaration,
172  log: LogInfo[]): ts.MethodDeclaration {
173  let newNode: ts.MethodDeclaration;
174  let renderNode: ts.Identifier;
175  if (!partialUpdateConfig.partialUpdateMode) {
176    renderNode = ts.factory.createIdentifier(COMPONENT_RENDER_FUNCTION);
177  } else {
178    renderNode = ts.factory.createIdentifier(COMPONENT_INITIAl_RENDER_FUNCTION);
179  }
180  if (node.body && node.body.statements && node.body.statements.length &&
181    validateRootNode(node, log)) {
182    newNode = ts.factory.updateMethodDeclaration(node, node.decorators, node.modifiers,
183      node.asteriskToken, renderNode, node.questionToken, node.typeParameters, node.parameters,
184      node.type, processComponentBlock(node.body, false, log));
185  } else {
186    newNode = ts.factory.updateMethodDeclaration(node, node.decorators, node.modifiers,
187      node.asteriskToken, renderNode, node.questionToken, node.typeParameters, node.parameters,
188      node.type, node.body);
189  }
190  return newNode;
191}
192
193export function processComponentBlock(node: ts.Block, isLazy: boolean, log: LogInfo[],
194  isTransition: boolean = false, isBuilder: boolean = false, parent: string = undefined,
195  forEachParameters: ts.NodeArray<ts.ParameterDeclaration> = undefined, isGlobalBuilder: boolean = false): ts.Block {
196  const newStatements: ts.Statement[] = [];
197  processComponentChild(node, newStatements, log, {isAcceleratePreview: false, line: 0, column: 0, fileName: ''},
198    isBuilder, parent, forEachParameters, isGlobalBuilder, isTransition);
199  if (isLazy && !partialUpdateConfig.partialUpdateMode) {
200    newStatements.unshift(createRenderingInProgress(true));
201  }
202  if (isTransition) {
203    if (!partialUpdateConfig.partialUpdateMode) {
204      newStatements.unshift(ts.factory.createExpressionStatement(
205        createFunction(ts.factory.createIdentifier(COMPONENT_TRANSITION_NAME),
206          ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION), null)));
207    } else {
208      newStatements.unshift(createComponentCreationStatement(ts.factory.createExpressionStatement(
209        createFunction(ts.factory.createIdentifier(COMPONENT_TRANSITION_NAME),
210          ts.factory.createIdentifier(COMPONENT_POP_FUNCTION), null)), [ts.factory.createExpressionStatement(
211        createFunction(ts.factory.createIdentifier(COMPONENT_TRANSITION_NAME),
212          ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION), null))], COMPONENT_TRANSITION_NAME, false, isTransition));
213    }
214    newStatements.push(ts.factory.createExpressionStatement(
215      createFunction(ts.factory.createIdentifier(COMPONENT_TRANSITION_NAME),
216        ts.factory.createIdentifier(COMPONENT_POP_FUNCTION), null)));
217  }
218  if (isLazy && !partialUpdateConfig.partialUpdateMode) {
219    newStatements.push(createRenderingInProgress(false));
220  }
221  return ts.factory.updateBlock(node, newStatements);
222}
223
224function validateRootNode(node: ts.MethodDeclaration, log: LogInfo[]): boolean {
225  let isValid: boolean = false;
226  if (node.body.statements.length === 1) {
227    const statement: ts.Statement = node.body.statements[0];
228    if (ts.isIfStatement(statement) || validateFirstNode(statement)) {
229      isValid = true;
230    }
231  } else {
232    isValid = false;
233  }
234  if (!isValid) {
235    log.push({
236      type: LogType.ERROR,
237      message: `There should have a root container component.`,
238      pos: node.body.statements.pos
239    });
240  }
241  return isValid;
242}
243
244function validateFirstNode(node: ts.Statement): boolean {
245  const isEntryComponent: boolean =
246    componentCollection.entryComponent === componentCollection.currentClassName;
247  if (isEntryComponent && !validateContainerComponent(node)) {
248    return false;
249  }
250  return true;
251}
252
253function validateContainerComponent(node: ts.Statement): boolean {
254  if (ts.isExpressionStatement(node) && node.expression &&
255    (ts.isEtsComponentExpression(node.expression) || ts.isCallExpression(node.expression))) {
256    const nameResult: NameResult = { name: null, node: null, arguments: [] };
257    validateEtsComponentNode(node.expression, nameResult);
258    if (nameResult.name && checkContainer(nameResult.name, nameResult.node)) {
259      return true;
260    }
261  }
262  return false;
263}
264
265interface supplementType {
266  isAcceleratePreview: boolean,
267  line: number,
268  column: number,
269  fileName: string
270}
271
272let newsupplement: supplementType = {
273  isAcceleratePreview: false,
274  line: 0,
275  column: 0,
276  fileName: ''
277};
278
279type NameResult = {
280  name: string,
281  arguments: ts.NodeArray<ts.Expression> | [],
282  node?: ts.Node
283}
284
285function validateEtsComponentNode(node: ts.CallExpression | ts.EtsComponentExpression, result?: NameResult) {
286  let childNode: ts.Node = node;
287  result.name = null;
288  while (ts.isCallExpression(childNode) && childNode.expression &&
289    ts.isPropertyAccessExpression(childNode.expression) && childNode.expression.expression) {
290    childNode = childNode.expression.expression;
291  }
292  if (ts.isEtsComponentExpression(childNode)) {
293    if (ts.isIdentifier(childNode.expression)) {
294      result.name = childNode.expression.getText();
295      result.node = childNode;
296      result.arguments = childNode.arguments || [];
297    }
298    return true;
299  } else {
300    return false;
301  }
302}
303
304let sourceNode: ts.SourceFile;
305
306export function processComponentChild(node: ts.Block | ts.SourceFile, newStatements: ts.Statement[],
307  log: LogInfo[], supplement: supplementType = {isAcceleratePreview: false, line: 0, column: 0, fileName: ''},
308  isBuilder: boolean = false, parent: string = undefined,
309  forEachParameters: ts.NodeArray<ts.ParameterDeclaration> = undefined, isGlobalBuilder: boolean = false,
310  isTransition: boolean = false): void {
311  if (supplement.isAcceleratePreview) {
312    newsupplement = supplement;
313    const compilerOptions = ts.readConfigFile(
314      path.resolve(__dirname, '../tsconfig.json'), ts.sys.readFile).config.compilerOptions;
315    Object.assign(compilerOptions, {
316      'sourceMap': false
317    });
318    sourceNode = ts.createSourceFile('', node.getText(), ts.ScriptTarget.Latest, true, ts.ScriptKind.ETS, compilerOptions);
319  }
320  if (node.statements.length) {
321    // Save parent component
322    const savedParent: string = parent;
323    node.statements.forEach((item) => {
324      if (ts.isExpressionStatement(item)) {
325        checkEtsComponent(item, log);
326        const name: string = getName(item);
327        if (CARD_ENABLE_COMPONENTS.has(name)) {
328          validatorCard(log, CARD_LOG_TYPE_COMPONENTS, item.getStart(), name);
329        }
330        switch (getComponentType(item, log, name, parent, forEachParameters)) {
331          case ComponentType.innerComponent: {
332            const [etsExpression, idName]: [ts.EtsComponentExpression, ts.Expression] =
333              checkEtsAndIdInIf(item, savedParent);
334            if (ts.isIdentifier(etsExpression.expression)) {
335              parent = etsExpression.expression.escapedText.toString();
336            }
337            processInnerComponent(item, newStatements, log, parent, isBuilder, isGlobalBuilder, isTransition, idName);
338            break;
339          }
340          case ComponentType.customComponent: {
341            const idName: ts.Expression = checkIdInIf(item, savedParent);
342            parent = undefined;
343            if (!newsupplement.isAcceleratePreview) {
344              if (item.expression && ts.isEtsComponentExpression(item.expression) && item.expression.body) {
345                const expressionResult: ts.ExpressionStatement =
346                  processExpressionStatementChange(item, item.expression.body, log);
347                if (expressionResult) {
348                  item = expressionResult;
349                }
350              }
351              processCustomComponent(item as ts.ExpressionStatement, newStatements, log, name,
352                isBuilder, isGlobalBuilder, idName);
353            }
354            break;
355          }
356          case ComponentType.forEachComponent:
357            parent = undefined;
358            if (!partialUpdateConfig.partialUpdateMode) {
359              processForEachComponent(item, newStatements, log, isBuilder, isGlobalBuilder);
360            } else {
361              processForEachComponentNew(item, newStatements, log, isGlobalBuilder);
362            }
363            break;
364          case ComponentType.customBuilderMethod:
365            parent = undefined;
366            if (partialUpdateConfig.partialUpdateMode) {
367              newStatements.push(transferBuilderCall(item, name, isBuilder));
368            } else {
369              newStatements.push(addInnerBuilderParameter(item, isGlobalBuilder));
370            }
371            break;
372          case ComponentType.builderParamMethod:
373            parent = undefined;
374            if (partialUpdateConfig.partialUpdateMode) {
375              newStatements.push(transferBuilderCall(item, name, isBuilder));
376            } else {
377              newStatements.push(addInnerBuilderParameter(item));
378            }
379            break;
380          case ComponentType.builderTypeFunction:
381            parent = undefined;
382            if (partialUpdateConfig.partialUpdateMode) {
383              newStatements.push(transferBuilderCall(item, name, isBuilder));
384            } else {
385              newStatements.push(addInnerBuilderParameter(item));
386            }
387            break;
388          case ComponentType.function:
389            parent = undefined;
390            newStatements.push(item);
391            break;
392        }
393      } else if (ts.isIfStatement(item)) {
394        processIfStatement(item, newStatements, log, isBuilder, isGlobalBuilder);
395      } else if (!ts.isBlock(item)) {
396        log.push({
397          type: LogType.ERROR,
398          message: `Only UI component syntax can be written in build method.`,
399          pos: item.getStart()
400        });
401      }
402    });
403  }
404  if (supplement.isAcceleratePreview) {
405    newsupplement = {
406      isAcceleratePreview: false,
407      line: 0,
408      column: 0,
409      fileName: ''
410    };
411  }
412}
413
414export function transferBuilderCall(node: ts.ExpressionStatement, name: string,
415  isBuilder: boolean = false): ts.ExpressionStatement {
416  if (node.expression && ts.isCallExpression(node.expression) && node.expression.arguments &&
417    node.expression.arguments.length === 1 && ts.isObjectLiteralExpression(node.expression.arguments[0])) {
418    return ts.factory.createExpressionStatement(ts.factory.createCallExpression(
419      ts.factory.createCallExpression(
420        ts.factory.createPropertyAccessExpression(
421          node.expression.expression,
422          ts.factory.createIdentifier(BUILDER_ATTR_BIND)
423        ),
424        undefined,
425        [ts.factory.createThis()]
426      ),
427      undefined,
428      [ts.factory.createCallExpression(
429        ts.factory.createIdentifier(BUILDER_PARAM_PROXY),
430        undefined,
431        [
432          ts.factory.createStringLiteral(name),
433          traverseBuilderParams(node.expression.arguments[0], isBuilder)
434        ]
435      )]
436    ));
437  } else {
438    return ts.factory.createExpressionStatement(ts.factory.createCallExpression(
439      ts.factory.createCallExpression(
440        ts.factory.createPropertyAccessExpression(
441          node.expression.expression,
442          ts.factory.createIdentifier(BUILDER_ATTR_BIND)
443        ),
444        undefined,
445        [ts.factory.createThis()]
446      ),
447      undefined,
448      node.expression.arguments
449    ));
450  }
451}
452
453function traverseBuilderParams(node: ts.ObjectLiteralExpression,
454  isBuilder: boolean): ts.ObjectLiteralExpression {
455  const properties: ts.ObjectLiteralElementLike[] = [];
456  if (node.properties && node.properties.length) {
457    node.properties.forEach(property => {
458      if (ts.isPropertyAssignment(property) && property.initializer &&
459        ts.isPropertyAccessExpression(property.initializer) && property.initializer.expression &&
460        property.initializer.name && ts.isIdentifier(property.initializer.name)) {
461        const name: string = property.initializer.name.escapedText.toString();
462        if (!isBuilder && property.initializer.expression.kind === ts.SyntaxKind.ThisKeyword ||
463          isBuilder && ts.isIdentifier(property.initializer.expression) &&
464          property.initializer.expression.escapedText.toString() === $$) {
465          addProperties(properties, property, name, isBuilder);
466        } else {
467          properties.push(ts.factory.createPropertyAssignment(
468            property.name,
469            ts.factory.createArrowFunction(
470              undefined,
471              undefined,
472              [],
473              undefined,
474              ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
475              property.initializer
476            )
477          ));
478        }
479      } else {
480        properties.push(ts.factory.createPropertyAssignment(
481          property.name,
482          ts.factory.createArrowFunction(
483            undefined,
484            undefined,
485            [],
486            undefined,
487            ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
488            property.initializer
489          )
490        ));
491      }
492    });
493  }
494  return ts.factory.createObjectLiteralExpression(properties);
495}
496
497function addProperties(properties: ts.ObjectLiteralElementLike[], property: ts.ObjectLiteralElementLike,
498  name: string, isBuilder: boolean): void {
499  properties.push(ts.factory.createPropertyAssignment(
500    property.name,
501    ts.factory.createArrowFunction(
502      undefined,
503      undefined,
504      [],
505      undefined,
506      ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
507      ts.factory.createParenthesizedExpression(ts.factory.createConditionalExpression(
508        ts.factory.createElementAccessExpression(
509          isBuilder ? ts.factory.createIdentifier($$) : ts.factory.createThis(),
510          ts.factory.createStringLiteral('__' + name)
511        ),
512        ts.factory.createToken(ts.SyntaxKind.QuestionToken),
513        ts.factory.createElementAccessExpression(
514          isBuilder ? ts.factory.createIdentifier($$) : ts.factory.createThis(),
515          ts.factory.createStringLiteral('__' + name)
516        ),
517        ts.factory.createToken(ts.SyntaxKind.ColonToken),
518        ts.factory.createElementAccessExpression(
519          isBuilder ? ts.factory.createIdentifier($$) : ts.factory.createThis(),
520          ts.factory.createStringLiteral(name)
521        )
522      ))
523    )
524  ));
525}
526
527function addInnerBuilderParameter(node: ts.ExpressionStatement,
528  isGlobalBuilder: boolean = false): ts.ExpressionStatement {
529  if (node.expression && ts.isCallExpression(node.expression) && node.expression.arguments) {
530    node.expression.arguments.push(isGlobalBuilder ? parentConditionalExpression() : ts.factory.createThis());
531    return ts.factory.createExpressionStatement(ts.factory.updateCallExpression(node.expression,
532      node.expression.expression, node.expression.typeArguments, node.expression.arguments));
533  } else {
534    return node;
535  }
536}
537
538function processExpressionStatementChange(node: ts.ExpressionStatement, nextNode: ts.Block,
539  log: LogInfo[]): ts.ExpressionStatement {
540  let name: string;
541  // @ts-ignore
542  if (node.expression.expression && ts.isIdentifier(node.expression.expression)) {
543    name = node.expression.expression.escapedText.toString();
544  }
545  if (builderParamObjectCollection.get(name) &&
546    builderParamObjectCollection.get(name).size === 1) {
547    return processBlockToExpression(node, nextNode, log, name);
548  } else {
549    log.push({
550      type: LogType.ERROR,
551      message: `In the trailing lambda case, '${name}' must have one and only one property decorated with `
552        + `@BuilderParam, and its @BuilderParam expects no parameter.`,
553      pos: node.getStart()
554    });
555    return null;
556  }
557}
558
559function processBlockToExpression(node: ts.ExpressionStatement, nextNode: ts.Block,
560  log: LogInfo[], name: string): ts.ExpressionStatement {
561  const childParam: string = [...builderParamObjectCollection.get(name)].slice(-1)[0];
562  const newBlock: ts.Block = processComponentBlock(nextNode, false, log);
563  const arrowNode: ts.ArrowFunction = ts.factory.createArrowFunction(undefined, undefined,
564    [], undefined, ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), newBlock);
565  const newPropertyAssignment:ts.PropertyAssignment = ts.factory.createPropertyAssignment(
566    ts.factory.createIdentifier(childParam), arrowNode);
567  // @ts-ignore
568  let argumentsArray: ts.ObjectLiteralExpression[] = node.expression.arguments;
569  if (argumentsArray && !argumentsArray.length) {
570    argumentsArray = [ts.factory.createObjectLiteralExpression([newPropertyAssignment], true)];
571  } else {
572    argumentsArray = [ts.factory.createObjectLiteralExpression(
573      // @ts-ignore
574      node.expression.arguments[0].properties.concat([newPropertyAssignment]), true)];
575  }
576  const callNode: ts.CallExpression = ts.factory.updateCallExpression(
577    // @ts-ignore
578    node.expression, node.expression.expression, node.expression.expression.typeArguments,
579    argumentsArray);
580  // @ts-ignore
581  node.expression.expression.parent = callNode;
582  // @ts-ignore
583  callNode.parent = node.expression.parent;
584  node = ts.factory.updateExpressionStatement(node, callNode);
585  return node;
586}
587
588type EtsComponentResult = {
589  etsComponentNode: ts.EtsComponentExpression;
590  hasAttr: boolean;
591}
592function parseEtsComponentExpression(node: ts.ExpressionStatement): EtsComponentResult {
593  let etsComponentNode: ts.EtsComponentExpression;
594  let hasAttr: boolean = false;
595  let temp: any = node.expression;
596  while (temp) {
597    if (ts.isCallExpression(temp) && temp.expression &&
598      ts.isPropertyAccessExpression(temp.expression)) {
599      hasAttr = true;
600    }
601    if (ts.isEtsComponentExpression(temp)) {
602      etsComponentNode = temp;
603      break;
604    }
605    temp = temp.expression;
606  }
607  return { etsComponentNode: etsComponentNode, hasAttr: hasAttr };
608}
609
610function processInnerComponent(node: ts.ExpressionStatement, innerCompStatements: ts.Statement[],
611  log: LogInfo[], parent: string = undefined, isBuilder: boolean = false, isGlobalBuilder: boolean = false,
612  isTransition: boolean = false, idName: ts.Expression = undefined): void {
613  const newStatements: ts.Statement[] = [];
614  const res: CreateResult = createComponent(node, COMPONENT_CREATE_FUNCTION);
615  newStatements.push(res.newNode);
616  const nameResult: NameResult = { name: null, arguments: [] };
617  validateEtsComponentNode(node.expression as ts.EtsComponentExpression, nameResult);
618  if (partialUpdateConfig.partialUpdateMode && ItemComponents.includes(nameResult.name)) {
619    processItemComponent(node, nameResult, innerCompStatements, log, isGlobalBuilder, idName);
620  } else if (partialUpdateConfig.partialUpdateMode && TabContentAndNavDestination.has(nameResult.name)) {
621    processTabAndNav(node, innerCompStatements, nameResult, log, isGlobalBuilder, idName);
622  } else {
623    processNormalComponent(node, nameResult, innerCompStatements, log, parent, isBuilder, isGlobalBuilder,
624      isTransition, idName);
625  }
626}
627
628function processNormalComponent(node: ts.ExpressionStatement, nameResult: NameResult,
629  innerCompStatements: ts.Statement[], log: LogInfo[], parent: string = undefined, isBuilder:boolean = false,
630  isGlobalBuilder: boolean = false, isTransition: boolean = false, idName: ts.Expression = undefined): void {
631  const newStatements: ts.Statement[] = [];
632  const immutableStatements: ts.Statement[] = [];
633  const res: CreateResult = createComponent(node, COMPONENT_CREATE_FUNCTION);
634  newStatements.push(res.newNode);
635  processDebug(node, nameResult, newStatements);
636  const etsComponentResult: EtsComponentResult = parseEtsComponentExpression(node);
637  const componentName: string = res.identifierNode.getText();
638  let judgeIdStart: number;
639  if (partialUpdateConfig.partialUpdateMode && idName) {
640    judgeIdStart = innerCompStatements.length;
641  }
642  if (etsComponentResult.etsComponentNode.body && ts.isBlock(etsComponentResult.etsComponentNode.body)) {
643    if (res.isButton) {
644      checkButtonParamHasLabel(etsComponentResult.etsComponentNode, log);
645      if (projectConfig.isPreview) {
646        newStatements.splice(-2, 1, createComponent(node, COMPONENT_CREATE_CHILD_FUNCTION).newNode);
647      } else {
648        newStatements.splice(-1, 1, createComponent(node, COMPONENT_CREATE_CHILD_FUNCTION).newNode);
649      }
650    }
651    if (etsComponentResult.hasAttr) {
652      bindComponentAttr(node, res.identifierNode, newStatements, log, true, false, immutableStatements);
653    }
654    processInnerCompStatements(innerCompStatements, newStatements, node, isGlobalBuilder,
655      isTransition, undefined, immutableStatements, componentName);
656    processComponentChild(etsComponentResult.etsComponentNode.body, innerCompStatements, log,
657      {isAcceleratePreview: false, line: 0, column: 0, fileName: ''}, isBuilder, parent, undefined, isGlobalBuilder, false);
658  } else {
659    bindComponentAttr(node, res.identifierNode, newStatements, log, true, false, immutableStatements);
660    processInnerCompStatements(innerCompStatements, newStatements, node, isGlobalBuilder,
661      isTransition, undefined, immutableStatements, componentName);
662  }
663  if (res.isContainerComponent || res.needPop) {
664    innerCompStatements.push(createComponent(node, COMPONENT_POP_FUNCTION).newNode);
665  }
666  if (partialUpdateConfig.partialUpdateMode && idName) {
667    innerCompStatements.splice(judgeIdStart, innerCompStatements.length - judgeIdStart,
668      ifRetakeId(innerCompStatements.slice(judgeIdStart), idName));
669  }
670}
671
672export function ifRetakeId(blockContent: ts.Statement[], idName: ts.Expression): ts.IfStatement {
673  return ts.factory.createIfStatement(
674    ts.factory.createPrefixUnaryExpression(
675      ts.SyntaxKind.ExclamationToken,
676      ts.factory.createCallExpression(
677        ts.factory.createPropertyAccessExpression(
678          ts.factory.createIdentifier(COMPONENT_IF),
679          ts.factory.createIdentifier(CAN_RETAKE)
680        ),
681        undefined,
682        [idName]
683      )
684    ),
685    ts.factory.createBlock(
686      blockContent,
687      true
688    ),
689    undefined
690  );
691}
692
693function processDebug(node: ts.Statement, nameResult: NameResult, newStatements: ts.Statement[],
694  getNode: boolean = false): ts.ExpressionStatement {
695  if (projectConfig.isPreview && nameResult.name && !NO_DEBUG_LINE_COMPONENT.has(nameResult.name)) {
696    let posOfNode: ts.LineAndCharacter;
697    let curFileName: string;
698    let line: number = 1;
699    let col: number = 1;
700    if (sourceNode && newsupplement.isAcceleratePreview) {
701      posOfNode = sourceNode.getLineAndCharacterOfPosition(getRealNodePos(node) - 22);
702      curFileName = newsupplement.fileName;
703      if (posOfNode.line === 0) {
704        col = newsupplement.column - 1;
705      }
706      line = newsupplement.line;
707    } else {
708      posOfNode = transformLog.sourceFile.getLineAndCharacterOfPosition(getRealNodePos(node));
709      curFileName = transformLog.sourceFile.fileName.replace(/\.ts$/, '');
710    }
711    let debugInfo: string;
712    if (projectConfig.minAPIVersion >= 10) {
713      debugInfo = `${path.relative(projectConfig.projectRootPath, curFileName).replace(/\\+/g, '/')}` +
714        `(${posOfNode.line + line}:${posOfNode.character + col})`;
715    } else {
716      debugInfo = `${path.relative(projectConfig.projectPath, curFileName).replace(/\\+/g, '/')}` +
717      `(${posOfNode.line + line}:${posOfNode.character + col})`;
718    }
719    const debugNode: ts.ExpressionStatement = ts.factory.createExpressionStatement(
720      createFunction(ts.factory.createIdentifier(nameResult.name),
721        ts.factory.createIdentifier(COMPONENT_DEBUGLINE_FUNCTION),
722        ts.factory.createNodeArray([ts.factory.createStringLiteral(debugInfo)])));
723    if (getNode) {
724      return debugNode;
725    }
726    newStatements.push(debugNode);
727  }
728}
729
730function processInnerCompStatements(innerCompStatements: ts.Statement[],
731  newStatements: ts.Statement[], node: ts.Statement, isGlobalBuilder: boolean, isTransition: boolean,
732  nameResult: NameResult, immutableStatements: ts.Statement[], componentName: string): void {
733  if (!partialUpdateConfig.partialUpdateMode) {
734    innerCompStatements.push(...newStatements);
735  } else {
736    innerCompStatements.push(createComponentCreationStatement(node, newStatements, componentName,
737      isGlobalBuilder, isTransition, nameResult, immutableStatements));
738  }
739}
740
741export function createComponentCreationStatement(node: ts.Statement, innerStatements: ts.Statement[],
742  componentName: string, isGlobalBuilder: boolean = false, isTransition: boolean = false,
743  nameResult: NameResult = undefined, immutableStatements: ts.Statement[] = null): ts.Statement {
744  const blockArr: ts.Statement[] = [...innerStatements];
745  if (nameResult) {
746    blockArr.push(processDebug(node, nameResult, innerStatements, true));
747  }
748  if (!isTransition) {
749    createInitRenderStatement(node, immutableStatements, blockArr);
750  }
751  if (!partialUpdateConfig.optimizeComponent) {
752    blockArr.unshift(createViewStackProcessorStatement(STARTGETACCESSRECORDINGFOR, ELMTID));
753    blockArr.push(createViewStackProcessorStatement(STOPGETACCESSRECORDING));
754  }
755  const creationArgs: ts.Expression[] = [
756    ts.factory.createArrowFunction(undefined, undefined,
757      [
758        ts.factory.createParameterDeclaration(undefined, undefined, undefined,
759          ts.factory.createIdentifier(ELMTID), undefined, undefined, undefined),
760        ts.factory.createParameterDeclaration(undefined, undefined, undefined,
761          ts.factory.createIdentifier(ISINITIALRENDER), undefined, undefined, undefined)
762      ], undefined,
763      ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
764      ts.factory.createBlock(blockArr, true)
765    )
766  ];
767  if (partialUpdateConfig.optimizeComponent) {
768    creationArgs.push(isTransition ? ts.factory.createNull() :
769      ts.factory.createIdentifier(componentName));
770  }
771  return ts.factory.createExpressionStatement(
772    ts.factory.createCallExpression(
773      ts.factory.createPropertyAccessExpression(createConditionParent(isGlobalBuilder),
774        ts.factory.createIdentifier(partialUpdateConfig.optimizeComponent ?
775          OBSERVECOMPONENTCREATION2: OBSERVECOMPONENTCREATION)
776      ), undefined, creationArgs)
777  );
778}
779
780export function createViewStackProcessorStatement(propertyAccessName: string, elmtId?: string): ts.Statement {
781  return ts.factory.createExpressionStatement(
782    ts.factory.createCallExpression(
783      ts.factory.createPropertyAccessExpression(
784        ts.factory.createIdentifier(VIEWSTACKPROCESSOR),
785        ts.factory.createIdentifier(propertyAccessName)
786      ),
787      undefined,
788      elmtId ? [ts.factory.createIdentifier(ELMTID)] : []
789    )
790  );
791}
792
793function createInitRenderStatement(node: ts.Statement,
794  immutableStatements: ts.Statement[], blockArr: ts.Statement[]): void {
795  if (partialUpdateConfig.optimizeComponent) {
796    if (immutableStatements && immutableStatements.length) {
797      blockArr.push(ts.factory.createIfStatement(
798        ts.factory.createIdentifier(ISINITIALRENDER),
799        ts.factory.createBlock(immutableStatements, true)
800      ));
801    }
802  } else {
803    blockArr.push(ts.factory.createIfStatement(
804      ts.factory.createPrefixUnaryExpression(
805        ts.SyntaxKind.ExclamationToken,
806        ts.factory.createIdentifier(ISINITIALRENDER)
807      ),
808      ts.factory.createBlock(
809        [
810          ts.isExpressionStatement(node) ?
811            createComponent(node, COMPONENT_POP_FUNCTION).newNode : createIfPop()
812        ],
813        true
814      ),
815      immutableStatements && immutableStatements.length ?
816        ts.factory.createBlock(immutableStatements, true) : undefined
817    ));
818  }
819}
820
821function processItemComponent(node: ts.ExpressionStatement, nameResult: NameResult, innerCompStatements: ts.Statement[],
822  log: LogInfo[], isGlobalBuilder: boolean = false, idName: ts.Expression = undefined): void {
823  const itemRenderInnerStatements: ts.Statement[] = [];
824  const immutableStatements: ts.Statement[] = [];
825  const deepItemRenderInnerStatements: ts.Statement[] = [];
826  const res: CreateResult = createComponent(node, COMPONENT_CREATE_FUNCTION);
827  const isLazyCreate: boolean = checkLazyCreate(node, nameResult);
828  const itemCreateStatement: ts.Statement = createItemCreate(nameResult, isLazyCreate);
829  itemRenderInnerStatements.push(itemCreateStatement);
830  const etsComponentResult: EtsComponentResult = parseEtsComponentExpression(node);
831  if (etsComponentResult.etsComponentNode.body && ts.isBlock(etsComponentResult.etsComponentNode.body)) {
832    if (etsComponentResult.hasAttr) {
833      bindComponentAttr(node, res.identifierNode, itemRenderInnerStatements, log, true, false, immutableStatements);
834    }
835    processComponentChild(etsComponentResult.etsComponentNode.body, deepItemRenderInnerStatements, log,
836      {isAcceleratePreview: false, line: 0, column: 0, fileName: ''}, false, undefined, undefined, isGlobalBuilder, false);
837  } else {
838    bindComponentAttr(node, res.identifierNode, itemRenderInnerStatements, log, true, false, immutableStatements);
839  }
840  let generateItem: ts.IfStatement | ts.Block;
841  if (idName) {
842    generateItem = ifRetakeId([createItemBlock(
843      node, itemRenderInnerStatements, deepItemRenderInnerStatements, nameResult, isLazyCreate,
844      immutableStatements)], idName);
845  } else {
846    generateItem = createItemBlock(
847      node, itemRenderInnerStatements, deepItemRenderInnerStatements, nameResult, isLazyCreate,
848      immutableStatements);
849  }
850  innerCompStatements.push(generateItem);
851}
852
853function createItemCreate(nameResult: NameResult, isLazyCreate: boolean): ts.Statement {
854  const itemCreateArgs: ts.Expression[] = [];
855  if (isLazyCreate) {
856    itemCreateArgs.push(ts.factory.createIdentifier(DEEPRENDERFUNCTION), ts.factory.createTrue());
857  } else {
858    itemCreateArgs.push(
859      ts.factory.createArrowFunction(undefined, undefined, [], undefined,
860        ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
861        ts.factory.createBlock([], false)),
862      ts.factory.createFalse()
863    );
864  }
865  itemCreateArgs.push(...nameResult.arguments);
866  return ts.factory.createExpressionStatement(ts.factory.createCallExpression(
867    ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(nameResult.name),
868      ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION)), undefined, itemCreateArgs));
869}
870
871function createItemBlock(
872  node: ts.ExpressionStatement,
873  itemRenderInnerStatements: ts.Statement[],
874  deepItemRenderInnerStatements: ts.Statement[],
875  nameResult: NameResult, isLazyCreate: boolean,
876  immutableStatements: ts.Statement[]
877): ts.Block {
878  const blockNode: ts.Statement[] = [
879    createItemCreation(node, itemRenderInnerStatements, nameResult, immutableStatements)
880  ];
881  if (isLazyCreate) {
882    blockNode.push(
883      createDeepRenderFunction(node, deepItemRenderInnerStatements),
884      ts.factory.createExpressionStatement(ts.factory.createCallExpression(
885        ts.factory.createPropertyAccessExpression(
886          ts.factory.createThis(),
887          ts.factory.createIdentifier(OBSERVECOMPONENTCREATION)
888        ),
889        undefined,
890        [ts.factory.createIdentifier(ITEMCREATION)]
891      )),
892      createComponent(node, COMPONENT_POP_FUNCTION).newNode
893    );
894  } else {
895    blockNode.push(
896      createObservedDeepRender(node, deepItemRenderInnerStatements),
897      ts.factory.createExpressionStatement(ts.factory.createCallExpression(
898        ts.factory.createIdentifier(OBSERVEDDEEPRENDER), undefined, []))
899    );
900  }
901  return ts.factory.createBlock(blockNode, true);
902}
903
904function checkLazyCreate(node: ts.ExpressionStatement, nameResult: NameResult): boolean {
905  if (nameResult.name === LIST_ITEM) {
906    if (nameResult.arguments.length && ts.isStringLiteral(nameResult.arguments[0]) &&
907      nameResult.arguments[0].text === 'false') {
908      return false;
909    }
910    if (isLazyForEachChild(node)) {
911      return false;
912    }
913    return true;
914  }
915  return false;
916}
917
918function createItemCreation(
919  node: ts.ExpressionStatement,
920  itemRenderInnerStatements: ts.Statement[],
921  nameResult: NameResult,
922  immutableStatements: ts.Statement[]
923): ts.VariableStatement {
924  return ts.factory.createVariableStatement(
925    undefined,
926    ts.factory.createVariableDeclarationList(
927      [ts.factory.createVariableDeclaration(
928        ts.factory.createIdentifier(ITEMCREATION), undefined, undefined,
929        ts.factory.createArrowFunction(undefined, undefined,
930          [
931            ts.factory.createParameterDeclaration(undefined, undefined, undefined,
932              ts.factory.createIdentifier(ELMTID), undefined, undefined, undefined),
933            ts.factory.createParameterDeclaration(undefined, undefined, undefined,
934              ts.factory.createIdentifier(ISINITIALRENDER), undefined, undefined, undefined)
935          ], undefined,
936          ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
937          ts.factory.createBlock(
938            [
939              createViewStackProcessorStatement(STARTGETACCESSRECORDINGFOR, ELMTID),
940              ...itemRenderInnerStatements,
941              processDebug(node, nameResult, itemRenderInnerStatements, true),
942              ts.factory.createIfStatement(
943                ts.factory.createPrefixUnaryExpression(
944                  ts.SyntaxKind.ExclamationToken,
945                  ts.factory.createIdentifier(ISINITIALRENDER)
946                ),
947                ts.factory.createBlock(
948                  [createComponent(node, COMPONENT_POP_FUNCTION).newNode],
949                  true
950                ),
951                immutableStatements && immutableStatements.length ?
952                  ts.factory.createBlock(immutableStatements, true) : undefined
953              ),
954              createViewStackProcessorStatement(STOPGETACCESSRECORDING)
955            ],
956            true
957          )
958        )
959      )],
960      ts.NodeFlags.Const
961    )
962  );
963}
964
965function createDeepRenderFunction(
966  node: ts.ExpressionStatement,
967  deepItemRenderInnerStatements: ts.Statement[]
968): ts.VariableStatement {
969  return ts.factory.createVariableStatement(
970    undefined,
971    ts.factory.createVariableDeclarationList(
972      [ts.factory.createVariableDeclaration(
973        ts.factory.createIdentifier(DEEPRENDERFUNCTION), undefined, undefined,
974        ts.factory.createArrowFunction(undefined, undefined,
975          [
976            ts.factory.createParameterDeclaration(undefined, undefined, undefined,
977              ts.factory.createIdentifier(ELMTID), undefined, undefined, undefined),
978            ts.factory.createParameterDeclaration(undefined, undefined, undefined,
979              ts.factory.createIdentifier(ISINITIALRENDER), undefined, undefined, undefined)
980          ], undefined,
981          ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
982          ts.factory.createBlock(
983            [
984              ts.factory.createExpressionStatement(ts.factory.createCallExpression(
985                ts.factory.createIdentifier(ITEMCREATION), undefined,
986                [
987                  ts.factory.createIdentifier(ELMTID),
988                  ts.factory.createIdentifier(ISINITIALRENDER)
989                ]
990              )),
991              ts.factory.createExpressionStatement(ts.factory.createCallExpression(
992                ts.factory.createPropertyAccessExpression(
993                  ts.factory.createPropertyAccessExpression(
994                    ts.factory.createThis(),
995                    ts.factory.createIdentifier(UPDATE_FUNC_BY_ELMT_ID)
996                  ),
997                  ts.factory.createIdentifier(CREATE_SET_METHOD)
998                ), undefined,
999                [ts.factory.createIdentifier(ELMTID), ts.factory.createIdentifier(ITEMCREATION)]
1000              )),
1001              ...deepItemRenderInnerStatements,
1002              createComponent(node, COMPONENT_POP_FUNCTION).newNode
1003            ],
1004            true
1005          )
1006        )
1007      )],
1008      ts.NodeFlags.Const
1009    )
1010  );
1011}
1012
1013function createObservedDeepRender(
1014  node: ts.ExpressionStatement,
1015  deepItemRenderInnerStatements: ts.Statement[]
1016): ts.VariableStatement {
1017  return ts.factory.createVariableStatement(
1018    undefined,
1019    ts.factory.createVariableDeclarationList(
1020      [ts.factory.createVariableDeclaration(
1021        ts.factory.createIdentifier(OBSERVEDDEEPRENDER),
1022        undefined,
1023        undefined,
1024        ts.factory.createArrowFunction(
1025          undefined,
1026          undefined,
1027          [],
1028          undefined,
1029          ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
1030          ts.factory.createBlock(
1031            [
1032              ts.factory.createExpressionStatement(ts.factory.createCallExpression(
1033                ts.factory.createPropertyAccessExpression(
1034                  ts.factory.createThis(),
1035                  ts.factory.createIdentifier(OBSERVECOMPONENTCREATION)
1036                ),
1037                undefined,
1038                [ts.factory.createIdentifier(ITEMCREATION)]
1039              )),
1040              ...deepItemRenderInnerStatements,
1041              createComponent(node, COMPONENT_POP_FUNCTION).newNode
1042            ],
1043            true
1044          )
1045        )
1046      )],
1047      ts.NodeFlags.Const
1048    )
1049  );
1050}
1051
1052function processTabAndNav(node: ts.ExpressionStatement, innerCompStatements: ts.Statement[],
1053  nameResult: NameResult, log: LogInfo[], isGlobalBuilder: boolean = false, idName: ts.Expression = undefined): void {
1054  const name: string = nameResult.name;
1055  const TabContentComp: ts.EtsComponentExpression = getEtsComponentExpression(node);
1056  const TabContentBody: ts.Block = TabContentComp.body;
1057  let tabContentCreation: ts.Statement;
1058  const tabContentPop: ts.Statement = ts.factory.createExpressionStatement(ts.factory.createCallExpression(
1059    ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(name),
1060      ts.factory.createIdentifier(COMPONENT_POP_FUNCTION)), undefined, []));
1061  const tabAttrs: ts.Statement[] = [];
1062  const immutableStatements: ts.Statement[] = [];
1063  let judgeIdStart: number;
1064  if (idName) {
1065    judgeIdStart = innerCompStatements.length;
1066  }
1067  if (TabContentBody && TabContentBody.statements.length) {
1068    const newTabContentChildren: ts.Statement[] = [];
1069    processComponentChild(TabContentBody, newTabContentChildren, log);
1070    tabContentCreation = ts.factory.createExpressionStatement(
1071      ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(
1072        ts.factory.createIdentifier(name), ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION)),
1073      undefined, [ts.factory.createArrowFunction(undefined, undefined, [], undefined,
1074        ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
1075        ts.factory.createBlock([...newTabContentChildren], true))]));
1076    bindComponentAttr(node, ts.factory.createIdentifier(name), tabAttrs, log, true, false, immutableStatements);
1077    processInnerCompStatements(
1078      innerCompStatements, [tabContentCreation, ...tabAttrs], node, isGlobalBuilder, false,
1079      nameResult, immutableStatements, name);
1080  } else {
1081    tabContentCreation = ts.factory.createExpressionStatement(ts.factory.createCallExpression(
1082      ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(name),
1083        ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION)), undefined, []));
1084    bindComponentAttr(node, ts.factory.createIdentifier(name), tabAttrs, log, true, false, immutableStatements);
1085    processInnerCompStatements(
1086      innerCompStatements, [tabContentCreation, ...tabAttrs], node, isGlobalBuilder, false,
1087      nameResult, immutableStatements, name);
1088  }
1089  innerCompStatements.push(tabContentPop);
1090  if (idName) {
1091    innerCompStatements.splice(judgeIdStart, innerCompStatements.length - judgeIdStart,
1092      ifRetakeId(innerCompStatements.slice(judgeIdStart), idName));
1093  }
1094}
1095
1096function getRealNodePos(node: ts.Node): number {
1097  // @ts-ignore
1098  if (node.pos === -1 && node.expression) {
1099    // @ts-ignore
1100    return getRealNodePos(node.expression);
1101  } else {
1102    return node.getStart();
1103  }
1104}
1105
1106function processForEachComponent(node: ts.ExpressionStatement, newStatements: ts.Statement[],
1107  log: LogInfo[], isBuilder: boolean = false, isGlobalBuilder: boolean = false): void {
1108  const popNode: ts.ExpressionStatement = ts.factory.createExpressionStatement(createFunction(
1109    // @ts-ignore
1110    node.expression.expression as ts.Identifier,
1111    ts.factory.createIdentifier(COMPONENT_POP_FUNCTION), null));
1112  if (ts.isCallExpression(node.expression)) {
1113    const propertyNode: ts.PropertyAccessExpression = ts.factory.createPropertyAccessExpression(
1114      node.expression.expression as ts.Identifier,
1115      ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION)
1116    );
1117    const argumentsArray: ts.Expression[] = Array.from(node.expression.arguments);
1118    let arrayObserveredObject: ts.CallExpression;
1119    if (argumentsArray.length) {
1120      arrayObserveredObject = ts.factory.createCallExpression(
1121        ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(FOREACH_OBSERVED_OBJECT),
1122          ts.factory.createIdentifier(FOREACH_GET_RAW_OBJECT)), undefined, [argumentsArray[0]]);
1123    }
1124    argumentsArray.splice(0, 1, arrayObserveredObject);
1125    const newArrowNode: ts.ArrowFunction =
1126      processForEachBlock(node.expression, log, isBuilder) as ts.ArrowFunction;
1127    if (newArrowNode) {
1128      argumentsArray.splice(1, 1, newArrowNode);
1129    }
1130    node = addForEachId(ts.factory.updateExpressionStatement(node, ts.factory.updateCallExpression(
1131      node.expression, propertyNode, node.expression.typeArguments, argumentsArray)), isGlobalBuilder);
1132  }
1133  newStatements.push(node, popNode);
1134}
1135
1136function processForEachComponentNew(node: ts.ExpressionStatement, newStatements: ts.Statement[],
1137  log: LogInfo[], isGlobalBuilder: boolean = false): void {
1138  const newForEachStatements: ts.Statement[] = [];
1139  const popNode: ts.ExpressionStatement = ts.factory.createExpressionStatement(createFunction(
1140    (node.expression as ts.CallExpression).expression as ts.Identifier,
1141    ts.factory.createIdentifier(COMPONENT_POP_FUNCTION), null));
1142  if (ts.isCallExpression(node.expression)) {
1143    const argumentsArray: ts.Expression[] = Array.from(node.expression.arguments);
1144    const propertyNode: ts.ExpressionStatement = ts.factory.createExpressionStatement(
1145      ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(
1146        node.expression.expression as ts.Identifier,
1147        ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION)), undefined, []));
1148    const newArrowNode: ts.NodeArray<ts.Statement> =
1149      processForEachBlock(node.expression, log, false, isGlobalBuilder) as ts.NodeArray<ts.Statement>;
1150    const itemGenFunctionStatement: ts.VariableStatement = createItemGenFunctionStatement(node.expression,
1151      argumentsArray, newArrowNode);
1152    const itemIdFuncStatement: ts.VariableStatement = createItemIdFuncStatement(node.expression, argumentsArray);
1153    const updateFunctionStatement: ts.ExpressionStatement = createUpdateFunctionStatement(argumentsArray, isGlobalBuilder);
1154    const lazyForEachStatement: ts.ExpressionStatement = createLazyForEachStatement(argumentsArray);
1155    if (node.expression.expression.getText() === COMPONENT_FOREACH) {
1156      newForEachStatements.push(propertyNode, itemGenFunctionStatement, updateFunctionStatement);
1157      newStatements.push(createComponentCreationStatement(node, newForEachStatements, COMPONENT_FOREACH, isGlobalBuilder), popNode);
1158    } else {
1159      if (argumentsArray[2]) {
1160        newStatements.push(ts.factory.createBlock([itemGenFunctionStatement, itemIdFuncStatement, lazyForEachStatement,
1161          popNode], true));
1162      } else {
1163        newStatements.push(ts.factory.createBlock([itemGenFunctionStatement, lazyForEachStatement, popNode], true));
1164      }
1165    }
1166  }
1167}
1168
1169function createItemGenFunctionStatement(
1170  node: ts.CallExpression,
1171  argumentsArray: ts.Expression[],
1172  newArrowNode: ts.NodeArray<ts.Statement>
1173): ts.VariableStatement {
1174  if (argumentsArray[1] && ts.isArrowFunction(argumentsArray[1])) {
1175    return ts.factory.createVariableStatement(
1176      undefined,
1177      ts.factory.createVariableDeclarationList(
1178        [ts.factory.createVariableDeclaration(
1179          ts.factory.createIdentifier(node.expression.getText() === COMPONENT_FOREACH ?
1180            FOREACHITEMGENFUNCTION : __LAZYFOREACHITEMGENFUNCTION),
1181          undefined, undefined,
1182          ts.factory.createArrowFunction(
1183            undefined, undefined,
1184            argumentsArray[1].parameters && argumentsArray[1].parameters.length >= 1 ?
1185              getParameters(argumentsArray[1]) : [],
1186            undefined, ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
1187            ts.factory.createBlock(
1188              argumentsArray[1].parameters && argumentsArray[1].parameters.length >= 1 ?
1189                isForEachItemGeneratorParam(argumentsArray, newArrowNode) :
1190                newArrowNode ? [...newArrowNode] : undefined,
1191              true
1192            )
1193          )
1194        )
1195        ],
1196        ts.NodeFlags.Const
1197      )
1198    );
1199  }
1200}
1201
1202function isForEachItemGeneratorParam(argumentsArray: ts.Expression[], newArrowNode: ts.NodeArray<ts.Statement>): ts.Statement[] {
1203  return [
1204    ts.factory.createVariableStatement(
1205      undefined,
1206      ts.factory.createVariableDeclarationList(
1207        [ts.factory.createVariableDeclaration(
1208          ts.factory.createIdentifier(
1209            argumentsArray[1].parameters[0] && argumentsArray[1].parameters[0].name.getText()),
1210          undefined,
1211          undefined,
1212          ts.factory.createIdentifier(_ITEM)
1213        )],
1214        ts.NodeFlags.Const
1215      )
1216    ),
1217    ...newArrowNode
1218  ];
1219}
1220
1221function getParameters(node: ts.ArrowFunction): ts.ParameterDeclaration[] {
1222  const parameterArr: ts.ParameterDeclaration[] = [
1223    ts.factory.createParameterDeclaration(
1224      undefined, undefined, undefined, ts.factory.createIdentifier(_ITEM))
1225  ];
1226  if (node.parameters && node.parameters.length > 1) {
1227    parameterArr.push(node.parameters[1]);
1228  }
1229  return parameterArr;
1230}
1231
1232function createItemIdFuncStatement(
1233  node: ts.CallExpression,
1234  argumentsArray: ts.Expression[]
1235): ts.VariableStatement {
1236  if (argumentsArray[2] && ts.isArrowFunction(argumentsArray[2])) {
1237    return ts.factory.createVariableStatement(
1238      undefined,
1239      ts.factory.createVariableDeclarationList(
1240        [ts.factory.createVariableDeclaration(
1241          ts.factory.createIdentifier(node.expression.getText() === COMPONENT_FOREACH ?
1242            FOREACHITEMIDFUNC : __LAZYFOREACHITEMIDFUNC), undefined, undefined,
1243          argumentsArray[2]
1244        )],
1245        ts.NodeFlags.Const
1246      )
1247    );
1248  }
1249}
1250
1251function createUpdateFunctionStatement(argumentsArray: ts.Expression[],
1252  isGlobalBuilder: boolean = false): ts.ExpressionStatement {
1253  return ts.factory.createExpressionStatement(
1254    ts.factory.createCallExpression(
1255      ts.factory.createPropertyAccessExpression(
1256        isGlobalBuilder ? parentConditionalExpression() : ts.factory.createThis(),
1257        ts.factory.createIdentifier(FOREACHUPDATEFUNCTION)
1258      ),
1259      undefined,
1260      addForEachIdFuncParameter(argumentsArray)
1261    )
1262  );
1263}
1264
1265function addForEachIdFuncParameter(argumentsArray: ts.Expression[]): ts.Expression[] {
1266  const addForEachIdFuncParameterArr: ts.Expression[] = [];
1267  addForEachIdFuncParameterArr.push(
1268    ts.factory.createIdentifier(ELMTID),
1269    argumentsArray[0],
1270    ts.factory.createIdentifier(FOREACHITEMGENFUNCTION)
1271  );
1272  // @ts-ignore
1273  if (argumentsArray[1] && argumentsArray[1].parameters && argumentsArray[1].parameters[1]) {
1274    if (!argumentsArray[2]) {
1275      addForEachIdFuncParameterArr.push(...addForEachParameter(ts.factory.createIdentifier(COMPONENT_IF_UNDEFINED), TRUE, FALSE));
1276    } else {
1277      // @ts-ignore
1278      argumentsArray[2].parameters && argumentsArray[2].parameters[1] ?
1279        addForEachIdFuncParameterArr.push(...addForEachParameter(argumentsArray[2], TRUE, TRUE)) :
1280        addForEachIdFuncParameterArr.push(...addForEachParameter(argumentsArray[2], TRUE, FALSE));
1281    }
1282  }
1283  // @ts-ignore
1284  if (argumentsArray[1] && !argumentsArray[1].parameters[1] && argumentsArray[2]) {
1285    // @ts-ignore
1286    argumentsArray[2].parameters && argumentsArray[2].parameters[1] ?
1287      addForEachIdFuncParameterArr.push(...addForEachParameter(argumentsArray[2], FALSE, TRUE)) :
1288      addForEachIdFuncParameterArr.push(...addForEachParameter(argumentsArray[2], FALSE, FALSE));
1289  }
1290  return addForEachIdFuncParameterArr;
1291}
1292
1293function addForEachParameter(forEachItemIdContent: ts.Expression, forEachItemGen: string, forEachItemId: string): ts.Expression[] {
1294  return [forEachItemIdContent, ts.factory.createIdentifier(forEachItemGen),
1295    ts.factory.createIdentifier(forEachItemId)];
1296}
1297
1298function createLazyForEachStatement(argumentsArray: ts.Expression[]): ts.ExpressionStatement {
1299  const parameterList: ts.Expression[] = [
1300    ts.factory.createStringLiteral(componentInfo.id.toString()),
1301    ts.factory.createThis(),
1302    argumentsArray[0],
1303    ts.factory.createIdentifier(__LAZYFOREACHITEMGENFUNCTION)
1304  ];
1305  if (argumentsArray.length >= 3 && argumentsArray[2]) {
1306    parameterList.push(ts.factory.createIdentifier(__LAZYFOREACHITEMIDFUNC));
1307  }
1308  return ts.factory.createExpressionStatement(
1309    ts.factory.createCallExpression(
1310      ts.factory.createPropertyAccessExpression(
1311        ts.factory.createIdentifier(COMPONENT_LAZYFOREACH),
1312        ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION)
1313      ),
1314      undefined,
1315      parameterList
1316    )
1317  );
1318}
1319
1320function addForEachId(node: ts.ExpressionStatement, isGlobalBuilder: boolean = false): ts.ExpressionStatement {
1321  const forEachComponent: ts.CallExpression = node.expression as ts.CallExpression;
1322  return ts.factory.updateExpressionStatement(node, ts.factory.updateCallExpression(
1323    forEachComponent, forEachComponent.expression, forEachComponent.typeArguments,
1324    [ts.factory.createStringLiteral((++componentInfo.id).toString()),
1325      isGlobalBuilder ? parentConditionalExpression() : ts.factory.createThis(),
1326      ...forEachComponent.arguments]));
1327}
1328
1329export function parentConditionalExpression(): ts.ConditionalExpression {
1330  return ts.factory.createConditionalExpression(
1331    ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARENT),
1332    ts.factory.createToken(ts.SyntaxKind.QuestionToken),
1333    ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARENT),
1334    ts.factory.createToken(ts.SyntaxKind.ColonToken),
1335    ts.factory.createThis());
1336}
1337
1338function processForEachBlock(node: ts.CallExpression, log: LogInfo[],
1339  isBuilder: boolean = false, isGlobalBuilder: boolean = false): ts.NodeArray<ts.Statement> | ts.ArrowFunction {
1340  if (node.arguments.length > 1 && ts.isArrowFunction(node.arguments[1])) {
1341    const isLazy: boolean = node.expression.getText() === COMPONENT_LAZYFOREACH;
1342    const arrowNode: ts.ArrowFunction = node.arguments[1] as ts.ArrowFunction;
1343    const body: ts.ConciseBody = arrowNode.body;
1344    if (node.arguments.length > 2 && !ts.isArrowFunction(node.arguments[2])) {
1345      log.push({
1346        type: LogType.ERROR,
1347        message: 'There should be wrapped in curly braces in ForEach.',
1348        pos: body.getStart()
1349      });
1350    } else if (!ts.isBlock(body)) {
1351      const statement: ts.Statement = ts.factory.createExpressionStatement(body);
1352      const blockNode: ts.Block = ts.factory.createBlock([statement], true);
1353      // @ts-ignore
1354      statement.parent = blockNode;
1355      if (!partialUpdateConfig.partialUpdateMode) {
1356        return ts.factory.updateArrowFunction(
1357          arrowNode, arrowNode.modifiers, arrowNode.typeParameters, arrowNode.parameters,
1358          arrowNode.type, arrowNode.equalsGreaterThanToken,
1359          processComponentBlock(blockNode, isLazy, log, false, false, undefined,
1360            arrowNode.parameters, isGlobalBuilder));
1361      } else {
1362        return processComponentBlock(blockNode, isLazy, log, false, false, undefined, arrowNode.parameters).statements;
1363      }
1364    } else {
1365      if (!partialUpdateConfig.partialUpdateMode) {
1366        return ts.factory.updateArrowFunction(
1367          arrowNode, arrowNode.modifiers, arrowNode.typeParameters, arrowNode.parameters,
1368          arrowNode.type, arrowNode.equalsGreaterThanToken,
1369          processComponentBlock(body, isLazy, log, false, isBuilder, undefined, arrowNode.parameters));
1370      } else {
1371        return processComponentBlock(body, isLazy, log, false, false, undefined, arrowNode.parameters, isGlobalBuilder).statements;
1372      }
1373    }
1374  }
1375  return null;
1376}
1377
1378function createRenderingInProgress(isTrue: boolean): ts.ExpressionStatement {
1379  return ts.factory.createExpressionStatement(ts.factory.createBinaryExpression(
1380    ts.factory.createPropertyAccessExpression(
1381      ts.factory.createThis(),
1382      ts.factory.createIdentifier(IS_RENDERING_IN_PROGRESS)
1383    ),
1384    ts.factory.createToken(ts.SyntaxKind.EqualsToken),
1385    isTrue ? ts.factory.createTrue() : ts.factory.createFalse()
1386  ));
1387}
1388
1389function processIfStatement(node: ts.IfStatement, newStatements: ts.Statement[],
1390  log: LogInfo[], isBuilder: boolean = false, isGlobalBuilder: boolean = false): void {
1391  const ifCreate: ts.ExpressionStatement = createIfCreate();
1392  const newIfNode: ts.IfStatement = processInnerIfStatement(node, 0, log, isBuilder, isGlobalBuilder);
1393  const ifPop: ts.ExpressionStatement = createIfPop();
1394  if (!partialUpdateConfig.partialUpdateMode) {
1395    newStatements.push(ifCreate, newIfNode, ifPop);
1396  } else {
1397    newStatements.push(createComponentCreationStatement(node, [ifCreate, newIfNode], COMPONENT_IF, isGlobalBuilder), ifPop);
1398  }
1399}
1400
1401function processInnerIfStatement(node: ts.IfStatement, id: number, log: LogInfo[],
1402  isBuilder: boolean = false, isGlobalBuilder: boolean = false): ts.IfStatement {
1403  if (ts.isIdentifier(node.expression) && node.expression.originalKeywordKind === undefined &&
1404    !node.expression.escapedText) {
1405    log.push({
1406      type: LogType.ERROR,
1407      message: 'Condition expression cannot be null in if statement.',
1408      pos: node.expression.getStart()
1409    });
1410    node = ts.factory.updateIfStatement(node, ts.factory.createIdentifier(COMPONENT_IF_UNDEFINED),
1411      node.thenStatement, node.elseStatement);
1412  }
1413  const newThenStatement: ts.Statement = processThenStatement(node.thenStatement, id, log, isBuilder, isGlobalBuilder);
1414  const newElseStatement: ts.Statement = processElseStatement(node.elseStatement, id, log, isBuilder, isGlobalBuilder);
1415  const newIfNode: ts.IfStatement = ts.factory.updateIfStatement(
1416    node, node.expression, newThenStatement, newElseStatement);
1417  return newIfNode;
1418}
1419
1420function processThenStatement(thenStatement: ts.Statement, id: number,
1421  log: LogInfo[], isBuilder: boolean = false, isGlobalBuilder: boolean = false): ts.Statement {
1422  if (ts.isExpressionStatement(thenStatement) && ts.isIdentifier(thenStatement.expression) &&
1423    thenStatement.expression.originalKeywordKind === undefined &&
1424    !thenStatement.expression.escapedText) {
1425    log.push({
1426      type: LogType.ERROR,
1427      message: 'Then statement cannot be null in if statement.',
1428      pos: thenStatement.expression.getStart()
1429    });
1430  }
1431  if (thenStatement) {
1432    if (ts.isBlock(thenStatement)) {
1433      thenStatement = processIfBlock(thenStatement, id, log, isBuilder, isGlobalBuilder);
1434    } else if (ts.isIfStatement(thenStatement)) {
1435      thenStatement = processInnerIfStatement(thenStatement, 0, log, isBuilder, isGlobalBuilder);
1436      thenStatement = ts.factory.createBlock(
1437        partialUpdateConfig.partialUpdateMode
1438          ? [createIfCreate(), createIfBranchFunc(id, [thenStatement], isGlobalBuilder), createIfPop()]
1439          : [createIfCreate(), createIfBranchId(id), thenStatement, createIfPop()],
1440        true
1441      );
1442    } else {
1443      thenStatement = ts.factory.createBlock([thenStatement], true);
1444      thenStatement = processIfBlock(thenStatement as ts.Block, id, log, isBuilder, isGlobalBuilder);
1445    }
1446  }
1447  return thenStatement;
1448}
1449
1450function processElseStatement(elseStatement: ts.Statement, id: number,
1451  log: LogInfo[], isBuilder: boolean = false, isGlobalBuilder: boolean = false): ts.Statement {
1452  if (elseStatement) {
1453    if (ts.isBlock(elseStatement)) {
1454      elseStatement = processIfBlock(elseStatement, id + 1, log);
1455    } else if (ts.isIfStatement(elseStatement)) {
1456      elseStatement = processInnerIfStatement(elseStatement, id + 1, log, isBuilder, isGlobalBuilder);
1457    } else {
1458      elseStatement = ts.factory.createBlock([elseStatement], true);
1459      elseStatement = processIfBlock(elseStatement as ts.Block, id + 1, log, isBuilder, isGlobalBuilder);
1460    }
1461  } else if (partialUpdateConfig.partialUpdateMode) {
1462    elseStatement = ts.factory.createBlock([
1463      ts.factory.createExpressionStatement(ts.factory.createCallExpression(
1464        ts.factory.createPropertyAccessExpression(
1465          ts.factory.createThis(),
1466          ts.factory.createIdentifier(IFELSEBRANCHUPDATEFUNCTION)
1467        ),
1468        undefined,
1469        [
1470          ts.factory.createNumericLiteral(++id),
1471          ts.factory.createArrowFunction(
1472            undefined,
1473            undefined,
1474            [],
1475            undefined,
1476            ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
1477            ts.factory.createBlock(
1478              [],
1479              true
1480            )
1481          )
1482        ]
1483      ))
1484    ], true);
1485  }
1486  return elseStatement;
1487}
1488
1489function processIfBlock(block: ts.Block, id: number, log: LogInfo[], isBuilder: boolean = false,
1490  isGlobalBuilder: boolean = false): ts.Block {
1491  return addIfBranchId(id, isGlobalBuilder,
1492    processComponentBlock(block, false, log, false, isBuilder, COMPONENT_IF, undefined, isGlobalBuilder));
1493}
1494
1495function addIfBranchId(id: number, isGlobalBuilder: boolean = false, container: ts.Block): ts.Block {
1496  let containerStatements: ts.Statement[];
1497  if (partialUpdateConfig.partialUpdateMode) {
1498    containerStatements = [createIfBranchFunc(id, [...container.statements], isGlobalBuilder)];
1499  } else {
1500    containerStatements = [createIfBranchId(id), ...container.statements];
1501  }
1502  return ts.factory.updateBlock(container, containerStatements);
1503}
1504
1505function createIf(): ts.Identifier {
1506  return ts.factory.createIdentifier(COMPONENT_IF);
1507}
1508
1509function createIfCreate(): ts.ExpressionStatement {
1510  return ts.factory.createExpressionStatement(createFunction(createIf(),
1511    ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION), ts.factory.createNodeArray([])));
1512}
1513
1514function createIfPop(): ts.ExpressionStatement {
1515  return ts.factory.createExpressionStatement(createFunction(createIf(),
1516    ts.factory.createIdentifier(COMPONENT_POP_FUNCTION), null));
1517}
1518
1519function createIfBranchId(id: number): ts.ExpressionStatement {
1520  return ts.factory.createExpressionStatement(createFunction(createIf(),
1521    ts.factory.createIdentifier(COMPONENT_IF_BRANCH_ID_FUNCTION),
1522    ts.factory.createNodeArray([ts.factory.createNumericLiteral(id)])));
1523}
1524
1525function createIfBranchFunc(id: number, innerStatements: ts.Statement[],
1526  isGlobalBuilder: boolean = false): ts.ExpressionStatement {
1527  return ts.factory.createExpressionStatement(ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(
1528    isGlobalBuilder ? parentConditionalExpression() : ts.factory.createThis(),
1529    ts.factory.createIdentifier(IFELSEBRANCHUPDATEFUNCTION)), undefined,
1530  [ts.factory.createNumericLiteral(id), ts.factory.createArrowFunction(undefined, undefined, [], undefined,
1531    ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), ts.factory.createBlock(innerStatements, true))]));
1532}
1533
1534interface CreateResult {
1535  newNode: ts.ExpressionStatement;
1536  identifierNode: ts.Identifier;
1537  isContainerComponent: boolean;
1538  isButton: boolean;
1539  needPop: boolean;
1540}
1541
1542function createComponent(node: ts.ExpressionStatement, type: string): CreateResult {
1543  const res: CreateResult = {
1544    newNode: node,
1545    identifierNode: null,
1546    isContainerComponent: false,
1547    isButton: false,
1548    needPop: false
1549  };
1550  let identifierNode: ts.Identifier = ts.factory.createIdentifier(type);
1551  let temp: any = node.expression;
1552  while (temp && !ts.isIdentifier(temp) && temp.expression) {
1553    temp = temp.expression;
1554  }
1555  if (temp && temp.parent && (ts.isCallExpression(temp.parent) ||
1556    ts.isEtsComponentExpression(temp.parent)) && ts.isIdentifier(temp)) {
1557    if (temp.getText() === COMPONENT_BUTTON && type !== COMPONENT_POP_FUNCTION) {
1558      res.isButton = true;
1559      identifierNode = type === COMPONENT_CREATE_CHILD_FUNCTION
1560        ? ts.factory.createIdentifier(COMPONENT_CREATE_CHILD_FUNCTION)
1561        : ts.factory.createIdentifier(COMPONENT_CREATE_LABEL_FUNCTION);
1562    }
1563    if (NEEDPOP_COMPONENT.has(temp.getText())) {
1564      res.needPop = true;
1565    }
1566    if (checkContainer(temp.getText(), temp.parent)) {
1567      res.isContainerComponent = true;
1568    }
1569    res.newNode = type === COMPONENT_POP_FUNCTION
1570      ? ts.factory.createExpressionStatement(createFunction(temp, identifierNode, null))
1571      : ts.factory.createExpressionStatement(createFunction(temp, identifierNode, checkArguments(temp, type)));
1572    res.identifierNode = temp;
1573  }
1574  return res;
1575}
1576
1577function checkArguments(temp: ts.Identifier, type: string): ts.Expression[] {
1578  const newArguments: ts.Expression[] = [];
1579  if (CUSTOM_BUILDER_CONSTRUCTORS.has(temp.escapedText.toString())) {
1580    temp.parent.arguments.forEach(argument => {
1581      if (ts.isConditionalExpression(argument)) {
1582        newArguments.push(processConditionalBuilder(argument, temp, type));
1583      } else if (isBuilderChangeNode(argument, temp, type)) {
1584        newArguments.push(parseBuilderNode(argument, type));
1585      } else {
1586        newArguments.push(argument);
1587      }
1588    });
1589    return newArguments;
1590  }
1591  return temp.getText() === 'XComponent' && type === COMPONENT_CREATE_FUNCTION &&
1592    projectConfig.moduleName && projectConfig.bundleName ?
1593    // @ts-ignore
1594    temp.parent.arguments.concat([
1595      ts.factory.createStringLiteral(`${projectConfig.bundleName}/${projectConfig.moduleName}`)
1596    ]) : temp.parent.arguments
1597}
1598
1599function checkContainer(name: string, node: ts.Node): boolean {
1600  return BUILDIN_CONTAINER_COMPONENT.has(name) && (name !== 'XComponent' ||
1601    (node && node.arguments && node.arguments.length &&
1602    ts.isObjectLiteralExpression(node.arguments[0]) && node.arguments[0].properties &&
1603    checkComponentType(node.arguments[0].properties)));
1604}
1605
1606function checkComponentType(properties: ts.PropertyAssignment[]): boolean {
1607  let flag: boolean = false;
1608  properties.forEach(item => {
1609    if (isXComponentContainer(item)) {
1610      flag = true;
1611    }
1612  });
1613  return flag;
1614}
1615
1616function isXComponentContainer(item: ts.PropertyAssignment): boolean {
1617  return item.name && ts.isIdentifier(item.name) && item.name.getText() === RESOURCE_NAME_TYPE &&
1618    item.initializer && ((ts.isStringLiteral(item.initializer) &&
1619    // value = 'component'
1620    (item.initializer.getText() === XCOMPONENT_SINGLE_QUOTATION ||
1621    item.initializer.getText() === XCOMPONENT_DOUBLE_QUOTATION)) ||
1622    // value = 1
1623    (ts.isNumericLiteral(item.initializer) && item.initializer.getText() === '1') ||
1624    // value = XComponentType.COMPONENT
1625    (ts.isPropertyAccessExpression(item.initializer) && item.initializer.expression &&
1626    ts.isIdentifier(item.initializer.expression) && item.initializer.name &&
1627    ts.isIdentifier(item.initializer.name) && item.initializer.expression.getText() === XCOMPONENTTYPE) &&
1628    item.initializer.name.getText() === XCOMPONENTTYPE_CONTAINER);
1629}
1630
1631interface AnimationInfo {
1632  statement: ts.Statement,
1633  kind: boolean,
1634  hasAnimationAttr: boolean,
1635}
1636
1637export interface ComponentAttrInfo {
1638  reuseId: ts.Node
1639}
1640
1641export function bindComponentAttr(node: ts.ExpressionStatement, identifierNode: ts.Identifier,
1642  newStatements: ts.Statement[], log: LogInfo[], reverse: boolean = true,
1643  isStylesAttr: boolean = false, newImmutableStatements: ts.Statement[] = null,
1644  isStyleFunction: boolean = false, componentAttrInfo: ComponentAttrInfo = null): void {
1645  let temp: any = node.expression;
1646  const statements: ts.Statement[] = [];
1647  const immutableStatements: ts.Statement[] = [];
1648  const updateStatements: ts.Statement[] = [];
1649  const lastStatement: AnimationInfo = {
1650    statement: null,
1651    kind: false,
1652    hasAnimationAttr: false,
1653  };
1654  const isRecycleComponent: boolean = isRecycle(componentCollection.currentClassName);
1655  if (ts.isPropertyAccessExpression(temp)) {
1656    log.push({
1657      type: LogType.ERROR,
1658      message: `'${node.getText()}' does not meet UI component syntax.`,
1659      pos: node.getStart()
1660    });
1661  }
1662  while (temp && ts.isCallExpression(temp) && temp.expression) {
1663    let flag: boolean = false;
1664    if (temp.expression && (validatePropertyAccessExpressionWithCustomBuilder(temp.expression) ||
1665      validateIdentifierWithCustomBuilder(temp.expression))) {
1666      let propertyName: string = '';
1667      if (ts.isIdentifier(temp.expression)) {
1668        propertyName = temp.expression.escapedText.toString();
1669      } else if (ts.isPropertyAccessExpression(temp.expression)) {
1670        propertyName = temp.expression.name.escapedText.toString();
1671      }
1672      switch (true) {
1673        case BIND_POPUP_SET.has(propertyName):
1674          temp = processBindPopupBuilder(temp);
1675          break;
1676        case BIND_DRAG_SET.has(propertyName):
1677          temp = processDragStartBuilder(temp, propertyName);
1678          break;
1679        default:
1680          temp = processCustomBuilderProperty(temp, identifierNode, propertyName);
1681      }
1682      flag = true;
1683    }
1684    if (ts.isPropertyAccessExpression(temp.expression) &&
1685      temp.expression.name && ts.isIdentifier(temp.expression.name) &&
1686      !componentCollection.customComponents.has(temp.expression.name.getText())) {
1687      parseRecycleId(temp, temp.expression.name, isRecycleComponent, componentAttrInfo);
1688      addComponentAttr(temp, temp.expression.name, lastStatement, statements, identifierNode, log,
1689        isStylesAttr, immutableStatements, updateStatements, newImmutableStatements,
1690        isRecycleComponent, isStyleFunction);
1691      temp = temp.expression.expression;
1692      flag = true;
1693    } else if (ts.isIdentifier(temp.expression)) {
1694      if (!INNER_COMPONENT_NAMES.has(temp.expression.getText()) &&
1695        !GESTURE_TYPE_NAMES.has(temp.expression.getText()) &&
1696        !componentCollection.customComponents.has(temp.expression.getText())) {
1697        parseRecycleId(temp, temp.expression.name, isRecycleComponent, componentAttrInfo);
1698        addComponentAttr(temp, temp.expression, lastStatement, statements, identifierNode, log,
1699          isStylesAttr, immutableStatements, updateStatements, newImmutableStatements,
1700          isRecycleComponent, isStyleFunction);
1701      }
1702      break;
1703    }
1704    if (!flag) {
1705      temp = temp.expression;
1706    }
1707  }
1708  if (lastStatement.statement && lastStatement.kind) {
1709    statements.push(lastStatement.statement);
1710  }
1711  if (!isRecycleComponent || lastStatement.hasAnimationAttr) {
1712    if (statements.length) {
1713      reverse ? newStatements.push(...statements.reverse()) : newStatements.push(...statements);
1714    }
1715  } else {
1716    if (updateStatements.length) {
1717      reverse ? newStatements.push(...updateStatements.reverse()) : newStatements.push(...updateStatements);
1718    }
1719    if (newImmutableStatements && immutableStatements.length) {
1720      reverse ? newImmutableStatements.push(...immutableStatements.reverse()) : newImmutableStatements.push(...immutableStatements);
1721    }
1722  }
1723}
1724
1725function parseRecycleId(node: ts.CallExpression, attr: ts.Identifier, isRecycleComponent: boolean,
1726  componentAttrInfo: ComponentAttrInfo): void {
1727  if (componentAttrInfo && attr.escapedText.toString() === RECYCLE_REUSE_ID) {
1728    componentAttrInfo.reuseId = node.arguments[0];
1729  }
1730}
1731
1732function processCustomBuilderProperty(node: ts.CallExpression, identifierNode: ts.Identifier,
1733  propertyName: string): ts.CallExpression {
1734  const newArguments: ts.Expression[] = [];
1735  node.arguments.forEach((argument: ts.Expression | ts.Identifier, index: number) => {
1736    if (ts.isConditionalExpression(argument)) {
1737      newArguments.push(processConditionalBuilder(argument, identifierNode, propertyName));
1738    } else if (isBuilderChangeNode(argument, identifierNode, propertyName)) {
1739      newArguments.push(parseBuilderNode(argument, propertyName));
1740    } else {
1741      newArguments.push(argument);
1742    }
1743  });
1744  node = ts.factory.updateCallExpression(node, node.expression, node.typeArguments, newArguments);
1745  return node;
1746}
1747
1748function isBuilderChangeNode(argument: ts.Node, identifierNode: ts.Identifier, propertyName: string): boolean {
1749  return ts.isPropertyAccessExpression(argument) && argument.name && ts.isIdentifier(argument.name)
1750    && CUSTOM_BUILDER_METHOD.has(argument.name.getText()) ||
1751    ts.isCallExpression(argument) && argument.expression && argument.expression.name &&
1752    ts.isIdentifier(argument.expression.name) &&
1753    CUSTOM_BUILDER_METHOD.has(argument.expression.name.getText()) || ts.isIdentifier(argument) &&
1754    argument.escapedText && CUSTOM_BUILDER_METHOD.has(argument.escapedText.toString()) ||
1755    ts.isObjectLiteralExpression(argument) && BIND_OBJECT_PROPERTY.get(identifierNode.escapedText.toString()) &&
1756    BIND_OBJECT_PROPERTY.get(identifierNode.escapedText.toString()).has(propertyName) ||
1757    ts.isCallExpression(argument) && argument.expression && ts.isIdentifier(argument.expression) &&
1758    CUSTOM_BUILDER_METHOD.has(argument.expression.escapedText.toString());
1759}
1760
1761function parseBuilderNode(node: ts.Node, propertyName: string):
1762  ts.ObjectLiteralExpression | ts.CallExpression | ts.ArrowFunction {
1763  if (isPropertyAccessExpressionNode(node)) {
1764    if (CUSTOM_BUILDER_PROPERTIES_WITHOUTKEY.has(propertyName)) {
1765      return processPropertyBuilderWithoutKey(node as ts.PropertyAccessExpression);
1766    } else {
1767      return processPropertyBuilder(node as ts.PropertyAccessExpression);
1768    }
1769  } else if (ts.isIdentifier(node) && CUSTOM_BUILDER_METHOD.has(node.escapedText.toString())) {
1770    if (CUSTOM_BUILDER_PROPERTIES_WITHOUTKEY.has(propertyName)) {
1771      return processIdentifierBuilderWithoutKey(node);
1772    } else {
1773      return processIdentifierBuilder(node);
1774    }
1775  } else if (ts.isCallExpression(node)) {
1776    if (CUSTOM_BUILDER_PROPERTIES_WITHOUTKEY.has(propertyName)) {
1777      return getParsedBuilderAttrArgumentWithParamsWithoutKey(node);
1778    } else {
1779      return getParsedBuilderAttrArgumentWithParams(node);
1780    }
1781  } else if (ts.isObjectLiteralExpression(node)) {
1782    return processObjectPropertyBuilder(node);
1783  }
1784}
1785
1786export function processObjectPropertyBuilder(node: ts.ObjectLiteralExpression): ts.ObjectLiteralExpression {
1787  const newProperties: ts.PropertyAssignment[] = [];
1788  node.properties.forEach((property: ts.PropertyAssignment) => {
1789    if (property.name && ts.isIdentifier(property.name) &&
1790      [CUSTOM_DIALOG_CONTROLLER_BUILDER, HEADER, FOOTER, START, END].includes(
1791        property.name.escapedText.toString()) && property.initializer) {
1792      if (isPropertyAccessExpressionNode(property.initializer) || ts.isIdentifier(property.initializer) &&
1793        CUSTOM_BUILDER_METHOD.has(property.initializer.escapedText.toString())) {
1794        newProperties.push(ts.factory.updatePropertyAssignment(property, property.name,
1795          ts.factory.createCallExpression(
1796            ts.factory.createPropertyAccessExpression(
1797              property.initializer,
1798              ts.factory.createIdentifier(BUILDER_ATTR_BIND)
1799            ),
1800            undefined,
1801            [ts.factory.createThis()]
1802          )));
1803      } else if (isGlobalBuilderCallExpressionNode(property.initializer) ||
1804        isInnerBuilderCallExpressionNode(property.initializer)) {
1805        newProperties.push(transformBuilderCallExpression(property));
1806      } else if (ts.isObjectLiteralExpression(property.initializer)) {
1807        newProperties.push(ts.factory.updatePropertyAssignment(property, property.name,
1808          processObjectPropertyBuilder(property.initializer)));
1809      } else {
1810        newProperties.push(property);
1811      }
1812    } else {
1813      newProperties.push(property);
1814    }
1815  });
1816  return ts.factory.updateObjectLiteralExpression(node, newProperties);
1817}
1818
1819function transformBuilderCallExpression(property: ts.PropertyAssignment): ts.PropertyAssignment {
1820  return ts.factory.updatePropertyAssignment(property, property.name,
1821    ts.factory.createCallExpression(
1822      ts.factory.createPropertyAccessExpression(
1823        property.initializer.expression,
1824        ts.factory.createIdentifier(BUILDER_ATTR_BIND)
1825      ),
1826      undefined,
1827      [ts.factory.createThis(), ...(property.initializer.arguments || [])]
1828    ));
1829}
1830
1831function isInnerBuilderCallExpressionNode(node: ts.Node): boolean {
1832  return ts.isCallExpression(node) && node.expression && isPropertyAccessExpressionNode(node.expression);
1833}
1834
1835function isGlobalBuilderCallExpressionNode(node: ts.Node): boolean {
1836  return ts.isCallExpression(node) && node.expression && ts.isIdentifier(node.expression) &&
1837    CUSTOM_BUILDER_METHOD.has(node.expression.escapedText.toString());
1838}
1839
1840function isPropertyAccessExpressionNode(node: ts.Node): boolean {
1841  return ts.isPropertyAccessExpression(node) && node.expression &&
1842    node.expression.kind === ts.SyntaxKind.ThisKeyword && node.name && ts.isIdentifier(node.name) &&
1843    CUSTOM_BUILDER_METHOD.has(node.name.escapedText.toString());
1844}
1845
1846function processBindPopupBuilder(node: ts.CallExpression): ts.CallExpression {
1847  const newArguments: ts.Expression[] = [];
1848  node.arguments.forEach((argument: ts.ObjectLiteralExpression, index: number) => {
1849    if (index === 1) {
1850      // @ts-ignore
1851      newArguments.push(processBindPopupBuilderProperty(argument));
1852    } else {
1853      newArguments.push(argument);
1854    }
1855  });
1856  node = ts.factory.updateCallExpression(node, node.expression, node.typeArguments, newArguments);
1857  return node;
1858}
1859
1860function processDragStartBuilder(node: ts.CallExpression, propertyName: string): ts.CallExpression {
1861  const newStatements: ts.Statement[] = [];
1862  if (isNodeFunction(node)) {
1863    // @ts-ignore
1864    for (let i = 0; i < node.arguments[0].body.statements.length; i++) {
1865      // @ts-ignore
1866      const statement: ts.Statement = node.arguments[0].body.statements[i];
1867      newStatements.push(checkStatement(statement, propertyName));
1868    }
1869    node = ts.factory.updateCallExpression(node, node.expression, node.typeArguments, [ts.factory.updateArrowFunction(
1870      // @ts-ignore
1871      node.arguments[0], undefined, undefined, node.arguments[0].parameters, node.arguments[0].type,
1872      // @ts-ignore
1873      node.arguments[0].equalsGreaterThanToken, ts.factory.updateBlock(node.arguments[0].body, newStatements))]);
1874  }
1875  return node;
1876}
1877
1878function isNodeFunction(node: ts.CallExpression): boolean {
1879  return node.arguments && node.arguments.length && ts.isArrowFunction(node.arguments[0]) && node.arguments[0].body &&
1880    ts.isBlock(node.arguments[0].body);
1881}
1882
1883function checkStatement(statement: ts.Statement, propertyName: string): ts.Statement {
1884  if (ts.isReturnStatement(statement)) {
1885    if (ts.isObjectLiteralExpression(statement.expression)) {
1886      const newProperties: ts.ObjectLiteralElementLike[] = [];
1887      for (let j = 0; j < statement.expression.properties.length; j++) {
1888        let property: ts.ObjectLiteralElementLike = statement.expression.properties[j];
1889        property = checkProperty(property, propertyName);
1890        newProperties.push(property);
1891      }
1892      return ts.factory.createReturnStatement(ts.factory.createObjectLiteralExpression(newProperties));
1893    } else {
1894      let initializer: ts.Expression = statement.expression;
1895      initializer = processInitializer(initializer, propertyName);
1896      return ts.factory.updateReturnStatement(statement, initializer);
1897    }
1898  } else {
1899    return statement;
1900  }
1901}
1902
1903function checkProperty(property: ts.ObjectLiteralElementLike, propertyName: string): ts.ObjectLiteralElementLike {
1904  if (isPropertyFunction(property)) {
1905    let initializer: ts.Expression = property.initializer;
1906    initializer = processInitializer(initializer, propertyName);
1907    property = ts.factory.createPropertyAssignment(property.name, initializer);
1908  }
1909  return property;
1910}
1911
1912function processInitializer(initializer: ts.Expression, propertyName: string): ts.Expression {
1913  if (initializer && ts.isConditionalExpression(initializer)) {
1914    return processConditionalBuilder(initializer, ts.factory.createIdentifier(CUSTOM_COMPONENT_DEFAULT),
1915      propertyName);
1916  } else if (isBuilderChangeNode(initializer, ts.factory.createIdentifier(CUSTOM_COMPONENT_DEFAULT),
1917    propertyName)) {
1918    return parseBuilderNode(initializer, propertyName);
1919  }
1920  return initializer;
1921}
1922
1923function isPropertyFunction(property: ts.ObjectLiteralElementLike): boolean {
1924  return ts.isPropertyAssignment(property) && property.name && ts.isIdentifier(property.name) &&
1925    property.name.escapedText.toString() === BUILDER_ATTR_NAME;
1926}
1927
1928function processBindPopupBuilderProperty(node: ts.ObjectLiteralExpression): ts.ObjectLiteralExpression {
1929  const newProperties: ts.PropertyAssignment[] = [];
1930  node.properties.forEach((property: ts.PropertyAssignment, index: number) => {
1931    if (property.name && ts.isIdentifier(property.name) && property.initializer &&
1932      property.name.escapedText.toString() === CUSTOM_DIALOG_CONTROLLER_BUILDER) {
1933      let initializer: ts.Expression = property.initializer;
1934      initializer = processInitializer(initializer, BIND_POPUP);
1935      newProperties.push(ts.factory.updatePropertyAssignment(property, property.name, initializer));
1936    } else {
1937      newProperties.push(property);
1938    }
1939  });
1940  return ts.factory.updateObjectLiteralExpression(node, newProperties);
1941}
1942
1943function processConditionalBuilder(initializer: ts.ConditionalExpression, identifierNode: ts.Identifier,
1944  propertyName: string): ts.ConditionalExpression {
1945  let whenTrue: ts.Expression = initializer.whenTrue;
1946  let whenFalse: ts.Expression = initializer.whenFalse;
1947  if (isBuilderChangeNode(initializer.whenTrue, identifierNode, propertyName)) {
1948    whenTrue = parseBuilderNode(initializer.whenTrue, propertyName);
1949  }
1950  if (isBuilderChangeNode(initializer.whenFalse, identifierNode, propertyName)) {
1951    whenFalse = parseBuilderNode(initializer.whenFalse, propertyName);
1952  }
1953  return ts.factory.createConditionalExpression(
1954    initializer.condition,
1955    initializer.questionToken,
1956    whenTrue,
1957    initializer.colonToken,
1958    whenFalse
1959  );
1960}
1961
1962function processPropertyBuilder(node: ts.PropertyAccessExpression): ts.ObjectLiteralExpression {
1963  return ts.factory.createObjectLiteralExpression([
1964    ts.factory.createPropertyAssignment(
1965      ts.factory.createIdentifier(BUILDER_ATTR_NAME),
1966      ts.factory.createCallExpression(
1967        ts.factory.createPropertyAccessExpression(
1968          node,
1969          ts.factory.createIdentifier(BUILDER_ATTR_BIND)
1970        ),
1971        undefined,
1972        [ts.factory.createThis()]
1973      )
1974    )
1975  ]);
1976}
1977
1978function processPropertyBuilderWithoutKey(node: ts.PropertyAccessExpression): ts.CallExpression {
1979  return ts.factory.createCallExpression(
1980    ts.factory.createPropertyAccessExpression(
1981      node,
1982      ts.factory.createIdentifier(BUILDER_ATTR_BIND)
1983    ),
1984    undefined,
1985    [ts.factory.createThis()]
1986  );
1987}
1988
1989function processIdentifierBuilder(node: ts.Identifier): ts.ObjectLiteralExpression {
1990  return ts.factory.createObjectLiteralExpression([
1991    ts.factory.createPropertyAssignment(
1992      ts.factory.createIdentifier(BUILDER_ATTR_NAME),
1993      ts.factory.createCallExpression(
1994        ts.factory.createPropertyAccessExpression(node, ts.factory.createIdentifier(BUILDER_ATTR_BIND)),
1995        undefined, [ts.factory.createThis()]
1996      )
1997    )
1998  ]);
1999}
2000
2001function processIdentifierBuilderWithoutKey(node: ts.Identifier): ts.CallExpression {
2002  return ts.factory.createCallExpression(
2003    ts.factory.createPropertyAccessExpression(node, ts.factory.createIdentifier(BUILDER_ATTR_BIND)),
2004    undefined, [ts.factory.createThis()]
2005  );
2006}
2007
2008function getParsedBuilderAttrArgumentWithParams(node: ts.CallExpression):
2009  ts.ObjectLiteralExpression {
2010  return ts.factory.createObjectLiteralExpression([
2011    ts.factory.createPropertyAssignment(
2012      ts.factory.createIdentifier(BUILDER_ATTR_NAME),
2013      ts.factory.createArrowFunction(
2014        undefined,
2015        undefined,
2016        [],
2017        undefined,
2018        ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
2019        ts.factory.createBlock(
2020          [ts.factory.createExpressionStatement(ts.factory.createCallExpression(
2021            ts.factory.createPropertyAccessExpression(node.expression, ts.factory.createIdentifier(CALL)
2022            ), undefined, [ts.factory.createThis(), ...node.arguments]))],
2023          true
2024        )
2025      )
2026    )
2027  ]);
2028}
2029
2030function getParsedBuilderAttrArgumentWithParamsWithoutKey(node: ts.CallExpression):
2031  ts.ArrowFunction {
2032  return ts.factory.createArrowFunction(
2033    undefined,
2034    undefined,
2035    [],
2036    undefined,
2037    ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
2038    ts.factory.createBlock(
2039      [ts.factory.createExpressionStatement(ts.factory.createCallExpression(
2040        ts.factory.createPropertyAccessExpression(node.expression, ts.factory.createIdentifier(CALL)
2041        ), undefined, [ts.factory.createThis(), ...node.arguments]))],
2042      true
2043    )
2044  );
2045}
2046
2047function validatePropertyAccessExpressionWithCustomBuilder(node: ts.Node): boolean {
2048  return ts.isPropertyAccessExpression(node) && node.name &&
2049    ts.isIdentifier(node.name) && CUSTOM_BUILDER_PROPERTIES.has(node.name.escapedText.toString());
2050}
2051
2052function validateIdentifierWithCustomBuilder(node: ts.Node): boolean {
2053  return ts.isIdentifier(node) && CUSTOM_BUILDER_PROPERTIES.has(node.escapedText.toString());
2054}
2055
2056function createArrowFunctionFor$$($$varExp: ts.Expression): ts.ArrowFunction {
2057  return ts.factory.createArrowFunction(
2058    undefined, undefined,
2059    [ts.factory.createParameterDeclaration(
2060      undefined, undefined, undefined,
2061      ts.factory.createIdentifier($$_NEW_VALUE),
2062      undefined, undefined, undefined
2063    )],
2064    undefined,
2065    ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
2066    ts.factory.createBlock(
2067      [ts.factory.createExpressionStatement(ts.factory.createBinaryExpression(
2068        $$varExp,
2069        ts.factory.createToken(ts.SyntaxKind.EqualsToken),
2070        ts.factory.createIdentifier($$_NEW_VALUE)
2071      ))],
2072      false
2073    )
2074  );
2075}
2076
2077function updateArgumentFor$$(argument): ts.Expression {
2078  if (ts.isElementAccessExpression(argument)) {
2079    return ts.factory.updateElementAccessExpression(
2080      argument, updateArgumentFor$$(argument.expression), argument.argumentExpression);
2081  } else if (ts.isIdentifier(argument)) {
2082    props.push(argument.getText());
2083    if (argument.getText() === $$_THIS) {
2084      return ts.factory.createThis();
2085    } else if (argument.getText().match(/^\$\$(.|\n)+/)) {
2086      return ts.factory.createIdentifier(argument.getText().replace(/\$\$/, ''));
2087    }
2088  } else if (ts.isPropertyAccessExpression(argument)) {
2089    return ts.factory.updatePropertyAccessExpression(
2090      argument, updateArgumentFor$$(argument.expression), argument.name);
2091  }
2092  return argument;
2093}
2094
2095function verifyComponentId(temp: any, node: ts.Identifier, propName: string,
2096  log: LogInfo[]): void {
2097  if (!newsupplement.isAcceleratePreview && propName === ATTRIBUTE_ID &&
2098    ts.isStringLiteral(temp.arguments[0])) {
2099    const id: string = temp.arguments[0].text;
2100    const posOfNode: ts.LineAndCharacter = transformLog.sourceFile
2101      .getLineAndCharacterOfPosition(getRealNodePos(node));
2102    const curFileName: string = transformLog.sourceFile.fileName.replace(/\.ts$/, '');
2103    const rPath: string = path.resolve(projectConfig.projectPath, curFileName)
2104      .replace(/\\+/g, '/');
2105    const rLine: number = posOfNode.line + 1;
2106    const rCol: number = posOfNode.character + 1;
2107    if (ID_ATTRS.has(id)) {
2108      const idInfo: Map<string, string | number> = ID_ATTRS.get(id);
2109      if (!(idInfo.get('path') === rPath &&
2110        idInfo.get('line') === rLine &&
2111        idInfo.get('col') === rCol)) {
2112        log.push({
2113          type: LogType.WARN,
2114          message: `The current component id "${id}" is duplicate with ` +
2115            `${idInfo.get('path')}:${idInfo.get('line')}:${idInfo.get('col')}.`,
2116          pos: node.pos
2117        });
2118      }
2119    } else {
2120      ID_ATTRS.set(id, new Map().set('path', rPath)
2121        .set('line', rLine)
2122        .set('col', rCol));
2123    }
2124  }
2125}
2126
2127function addComponentAttr(temp: any, node: ts.Identifier, lastStatement: any,
2128  statements: ts.Statement[], identifierNode: ts.Identifier, log: LogInfo[],
2129  isStylesAttr: boolean, immutableStatements: ts.Statement[], updateStatements: ts.Statement[],
2130  newImmutableStatements: ts.Statement[] = null, isRecycleComponent: boolean = false,
2131  isStyleFunction: boolean = false): void {
2132  const propName: string = node.getText();
2133  verifyComponentId(temp, node, propName, log);
2134  const extendType: ExtendType = {type: ''};
2135  if (propName === ATTRIBUTE_ANIMATION) {
2136    const animationNullNode: ts.ExpressionStatement = ts.factory.createExpressionStatement(
2137      createFunction(ts.factory.createIdentifier(GLOBAL_CONTEXT), node,
2138        // @ts-ignore
2139        [ts.factory.createNull()]));
2140    if (!lastStatement.statement) {
2141      if (!(temp.arguments.length === 1 &&
2142        temp.arguments[0].kind === ts.SyntaxKind.NullKeyword)) {
2143        statements.push(animationNullNode);
2144      }
2145    } else {
2146      statements.push(lastStatement.statement, animationNullNode);
2147    }
2148    lastStatement.statement = ts.factory.createExpressionStatement(createFunction(
2149      ts.factory.createIdentifier(GLOBAL_CONTEXT), node, temp.arguments));
2150    lastStatement.kind = false;
2151    lastStatement.hasAnimationAttr = true;
2152  } else if (GESTURE_ATTRS.has(propName)) {
2153    parseGesture(temp, propName, statements, log, updateStatements);
2154    lastStatement.kind = true;
2155  } else if (isExtendFunctionNode(identifierNode, propName, extendType)) {
2156    if (newsupplement.isAcceleratePreview) {
2157      log.push({
2158        type: LogType.ERROR,
2159        message: `Doesn't support Extend function now`,
2160        pos: temp.getStart()
2161      });
2162    }
2163    let functionName: string = '';
2164    if (extendType.type === CHECK_COMPONENT_EXTEND_DECORATOR) {
2165      functionName = `__${identifierNode.escapedText.toString()}__${propName}`;
2166    } else {
2167      functionName = propName;
2168    }
2169    const extendNode: ts.Statement = ts.factory.createExpressionStatement(
2170      ts.factory.createCallExpression(ts.factory.createIdentifier(functionName), undefined,
2171      extendType.type === CHECK_COMPONENT_EXTEND_DECORATOR
2172        ? temp.arguments
2173        : [
2174            ...temp.arguments, ts.factory.createIdentifier(ELMTID),
2175            ts.factory.createIdentifier(ISINITIALRENDER),
2176            ts.factory.createThis()
2177          ]
2178      ));
2179    statements.push(extendNode);
2180    updateStatements.push(extendNode);
2181    lastStatement.kind = true;
2182  } else if (propName === ATTRIBUTE_STATESTYLES) {
2183    if (temp.arguments.length === 1 && ts.isObjectLiteralExpression(temp.arguments[0])) {
2184      statements.push(createViewStackProcessor(temp, true));
2185      if (isRecycleComponent) {
2186        updateStatements.push(createViewStackProcessor(temp, true));
2187      }
2188      traverseStateStylesAttr(temp, statements, identifierNode, log, updateStatements,
2189        newImmutableStatements, isRecycleComponent);
2190      lastStatement.kind = true;
2191    } else {
2192      validateStateStyleSyntax(temp, log);
2193    }
2194  } else if (GLOBAL_STYLE_FUNCTION.has(propName) || INNER_STYLE_FUNCTION.has(propName)) {
2195    const styleBlock: ts.Block =
2196        INNER_STYLE_FUNCTION.get(propName) || GLOBAL_STYLE_FUNCTION.get(propName);
2197    if (styleBlock.statements.length > 0) {
2198      bindComponentAttr(styleBlock.statements[0] as ts.ExpressionStatement, identifierNode,
2199        statements, log, false, true, newImmutableStatements);
2200      if (isRecycleComponent) {
2201        bindComponentAttr(styleBlock.statements[0] as ts.ExpressionStatement, identifierNode,
2202          updateStatements, log, false, true, newImmutableStatements, true);
2203      }
2204    }
2205    lastStatement.kind = true;
2206  } else if (isDoubleDollarToChange(isStylesAttr, identifierNode, propName, temp)) {
2207    const argumentsArr: ts.Expression[] = [];
2208    classifyArgumentsNum(temp.arguments, argumentsArr, propName, identifierNode);
2209    const doubleDollarNode: ts.Statement = ts.factory.createExpressionStatement(
2210      createFunction(identifierNode, node, argumentsArr));
2211    statements.push(doubleDollarNode);
2212    updateStatements.push(doubleDollarNode);
2213    lastStatement.kind = true;
2214  } else {
2215    if (isStylesAttr) {
2216      if (!COMMON_ATTRS.has(propName)) {
2217        validateStateStyleSyntax(temp, log);
2218      }
2219    }
2220    temp = loopEtscomponent(temp, isStylesAttr);
2221    if (propName !== RECYCLE_REUSE_ID) {
2222      const attrStatement: ts.Statement = ts.factory.createExpressionStatement(
2223        createFunction(identifierNode, node, temp.arguments));
2224      statements.push(attrStatement);
2225      if (isRecycleComponent && (!isStylesAttr || isStyleFunction) &&
2226        !isGestureType(identifierNode) && filterRegularAttrNode(temp.arguments)) {
2227        immutableStatements.push(attrStatement);
2228      } else {
2229        updateStatements.push(attrStatement);
2230      }
2231    }
2232    lastStatement.kind = true;
2233  }
2234}
2235
2236function isGestureType(node: ts.Identifier): boolean {
2237  return GESTURE_TYPE_NAMES.has(node.escapedText.toString());
2238}
2239
2240function filterRegularAttrNode(argumentsNode: ts.NodeArray<ts.Expression>) {
2241  return argumentsNode.every((argument: ts.Expression) => {
2242    return isRegularAttrNode(argument);
2243  });
2244}
2245
2246type AttrResult = { isRegularNode: boolean };
2247function isRegularAttrNode(node: ts.Expression): boolean {
2248  if (ts.isObjectLiteralExpression(node)) {
2249    return node.properties.every((propNode: ts.PropertyAssignment) => {
2250      if (propNode.initializer) {
2251        return isRegularAttrNode(propNode.initializer);
2252      }
2253      return false;
2254    });
2255  }
2256  if (ts.isArrayLiteralExpression(node)) {
2257    return node.elements.every((child: ts.Expression) => {
2258      return isRegularAttrNode(child);
2259    });
2260  }
2261  // literal e.g. 'hello', 1, true, false, () => {}
2262  if (isLiteralNode(node)) {
2263    return true;
2264  }
2265  // enum e.g. Color.Red
2266  if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.expression) &&
2267    ts.isIdentifier(node.name)) {
2268    if (enumCollection.has(node.expression.escapedText.toString())) {
2269      return true;
2270    }
2271    if (globalProgram.checker) {
2272      const type: ts.Type = globalProgram.checker.getTypeAtLocation(node);
2273      /* Enum */
2274      if (type.flags & (32 | 1024)) {
2275        return true;
2276      }
2277    }
2278    return false;
2279  }
2280  // regular variable, e.g. this.regularValue
2281  const result: AttrResult = { isRegularNode: false };
2282  if (ts.isPropertyAccessExpression(node)) {
2283    traversePropNode(node, result);
2284  }
2285  return result.isRegularNode || false;
2286}
2287
2288function isLiteralNode(node: ts.Expression): boolean {
2289  return ts.isStringLiteral(node) || ts.isNumericLiteral(node) || ts.isArrowFunction(node) ||
2290    [ts.SyntaxKind.TrueKeyword, ts.SyntaxKind.FalseKeyword].includes(node.kind);
2291}
2292
2293function traversePropNode(node: ts.PropertyAccessExpression, result: AttrResult): void {
2294  if (node.expression.kind === ts.SyntaxKind.ThisKeyword && ts.isIdentifier(node.name) &&
2295    regularCollection.get(componentCollection.currentClassName).has(node.name.escapedText.toString())) {
2296    result.isRegularNode = true;
2297    return;
2298  }
2299  if (ts.isPropertyAccessExpression(node.expression)) {
2300    traversePropNode(node.expression, result);
2301  }
2302}
2303
2304function isDoubleDollarToChange(isStylesAttr: boolean, identifierNode: ts.Identifier,
2305  propName: string, temp: any): boolean {
2306  return !isStylesAttr &&
2307    PROPERTIES_ADD_DOUBLE_DOLLAR.has(identifierNode.escapedText.toString()) &&
2308    PROPERTIES_ADD_DOUBLE_DOLLAR.get(identifierNode.escapedText.toString()).has(propName) ||
2309    STYLE_ADD_DOUBLE_DOLLAR.has(propName) && temp.arguments.length && temp.arguments[0] ?
2310    temp.arguments[0].getText().match(/^\$\$(.|\n)+/) !== null
2311    : false;
2312}
2313
2314function isHaveDoubleDollar(param: ts.PropertyAssignment, name: string): boolean {
2315  return ts.isPropertyAssignment(param) && param.name && ts.isIdentifier(param.name) &&
2316    PROPERTIES_ADD_DOUBLE_DOLLAR.get(name).has(param.name.getText()) && param.initializer &&
2317    param.initializer.getText().startsWith($$);
2318}
2319
2320function loopEtscomponent(node: any, isStylesAttr: boolean): ts.Node {
2321  node.arguments.forEach((item: ts.Node, index: number) => {
2322    if (ts.isEtsComponentExpression(item)) {
2323      node.arguments[index] = ts.factory.createCallExpression(
2324        item.expression, undefined, item.arguments);
2325    } else if ((ts.isCallExpression(item) || ts.isNewExpression(item)) &&
2326      !newsupplement.isAcceleratePreview) {
2327      node.arguments[index] = ts.visitEachChild(item,
2328        changeEtsComponentKind, contextGlobal);
2329    }
2330  });
2331  return node;
2332}
2333
2334function changeEtsComponentKind(node: ts.Node): ts.Node {
2335  if (ts.isEtsComponentExpression(node)) {
2336    node.kind = 204;
2337    return node;
2338  }
2339  return ts.visitEachChild(node, changeEtsComponentKind, contextGlobal);
2340}
2341
2342function classifyArgumentsNum(args: any, argumentsArr: ts.Expression[], propName: string,
2343  identifierNode: ts.Identifier): void {
2344  if (STYLE_ADD_DOUBLE_DOLLAR.has(propName) && args.length >= 2) {
2345    const varExp: ts.Expression = updateArgumentFor$$(args[0]);
2346    argumentsArr.push(generateObjectFor$$(varExp), ...args.slice(1));
2347  } else if (PROPERTIES_ADD_DOUBLE_DOLLAR.has(identifierNode.getText()) && args.length === 1 &&
2348    PROPERTIES_ADD_DOUBLE_DOLLAR.get(identifierNode.getText()).has(propName) ||
2349    STYLE_ADD_DOUBLE_DOLLAR.has(propName) && args.length === 1) {
2350    const varExp: ts.Expression = updateArgumentFor$$(args[0]);
2351    argumentsArr.push(varExp, createArrowFunctionFor$$(varExp));
2352  }
2353}
2354
2355function generateObjectFor$$(varExp: ts.Expression): ts.ObjectLiteralExpression {
2356  return ts.factory.createObjectLiteralExpression(
2357    [
2358      ts.factory.createPropertyAssignment(
2359        ts.factory.createIdentifier($$_VALUE),
2360        varExp
2361      ),
2362      ts.factory.createPropertyAssignment(
2363        ts.factory.createIdentifier($$_CHANGE_EVENT),
2364        createArrowFunctionFor$$(varExp)
2365      )
2366    ],
2367    false
2368  );
2369}
2370
2371function createViewStackProcessor(item: any, endViewStack: boolean): ts.ExpressionStatement {
2372  const argument: ts.StringLiteral[] = [];
2373  if (!endViewStack && item.name) {
2374    argument.push(ts.factory.createStringLiteral(item.name.getText()));
2375  }
2376  return ts.factory.createExpressionStatement(ts.factory.createCallExpression(
2377    ts.factory.createPropertyAccessExpression(
2378      ts.factory.createIdentifier(VIEW_STACK_PROCESSOR),
2379      ts.factory.createIdentifier(VISUAL_STATE)
2380    ),
2381    undefined,
2382    argument
2383  ));
2384}
2385
2386function traverseStateStylesAttr(temp: any, statements: ts.Statement[],
2387  identifierNode: ts.Identifier, log: LogInfo[], updateStatements: ts.Statement[],
2388  newImmutableStatements: ts.Statement[] = null, isRecycleComponent: boolean = false): void {
2389  temp.arguments[0].properties.reverse().forEach((item: ts.PropertyAssignment) => {
2390    if (ts.isPropertyAccessExpression(item.initializer) &&
2391      item.initializer.expression.getText() === THIS &&
2392      INNER_STYLE_FUNCTION.get(item.initializer.name.getText())) {
2393      const name: string = item.initializer.name.getText();
2394      bindComponentAttr(INNER_STYLE_FUNCTION.get(name).statements[0] as ts.ExpressionStatement,
2395        identifierNode, statements, log, false, true, newImmutableStatements);
2396      if (isRecycleComponent) {
2397        bindComponentAttr(INNER_STYLE_FUNCTION.get(name).statements[0] as ts.ExpressionStatement,
2398          identifierNode, updateStatements, log, false, true, newImmutableStatements);
2399      }
2400    } else if (ts.isIdentifier(item.initializer) &&
2401      GLOBAL_STYLE_FUNCTION.get(item.initializer.getText())) {
2402      const name: string = item.initializer.getText();
2403      bindComponentAttr(GLOBAL_STYLE_FUNCTION.get(name).statements[0] as ts.ExpressionStatement,
2404        identifierNode, statements, log, false, true, newImmutableStatements);
2405      if (isRecycleComponent) {
2406        bindComponentAttr(GLOBAL_STYLE_FUNCTION.get(name).statements[0] as ts.ExpressionStatement,
2407          identifierNode, updateStatements, log, false, true, newImmutableStatements);
2408      }
2409    } else if (ts.isObjectLiteralExpression(item.initializer) &&
2410      item.initializer.properties.length === 1 &&
2411      ts.isPropertyAssignment(item.initializer.properties[0])) {
2412      bindComponentAttr(ts.factory.createExpressionStatement(
2413        item.initializer.properties[0].initializer), identifierNode, statements, log, false, true,
2414        newImmutableStatements);
2415      if (isRecycleComponent) {
2416        bindComponentAttr(ts.factory.createExpressionStatement(
2417          item.initializer.properties[0].initializer), identifierNode, updateStatements, log, false, true,
2418          newImmutableStatements);
2419      }
2420    } else {
2421      if (!(ts.isObjectLiteralExpression(item.initializer) && item.initializer.properties.length === 0)) {
2422        validateStateStyleSyntax(temp, log);
2423      }
2424    }
2425    if (item.name) {
2426      const viewNode: ts.Statement = createViewStackProcessor(item, false);
2427      statements.push(viewNode);
2428      if (isRecycleComponent) {
2429        updateStatements.push(viewNode);
2430      }
2431    }
2432  });
2433}
2434
2435interface ExtendType {
2436  type: string
2437}
2438
2439function isExtendFunctionNode(identifierNode: ts.Identifier, propName: string,
2440  extendType: ExtendType): boolean {
2441  const componentName: string = identifierNode.escapedText.toString();
2442  if (EXTEND_ATTRIBUTE.has(componentName) && [...EXTEND_ATTRIBUTE.get(componentName)].includes(propName)) {
2443    extendType.type = CHECK_COMPONENT_EXTEND_DECORATOR;
2444    return true;
2445  }
2446  const animatableExtendAttribute: Map<string, Set<string>> =
2447    storedFileInfo.getCurrentArkTsFile().animatableExtendAttribute;
2448  if (animatableExtendAttribute.has(componentName) &&
2449    [...animatableExtendAttribute.get(componentName)].includes(propName)) {
2450    extendType.type = CHECK_COMPONENT_ANIMATABLE_EXTEND_DECORATOR;
2451    return true;
2452  }
2453  return false;
2454}
2455
2456const gestureMap: Map<string, string> = new Map([
2457  [PRIORITY_GESTURE_ATTRIBUTE, GESTURE_ENUM_VALUE_HIGH],
2458  [PARALLEL_GESTURE_ATTRIBUTE, GESTURE_ENUM_VALUE_PARALLEL],
2459  [GESTURE_ATTRIBUTE, GESTURE_ENUM_VALUE_LOW]
2460]);
2461
2462function parseGesture(node: ts.CallExpression, propName: string, statements: ts.Statement[],
2463  log: LogInfo[], updateStatements: ts.Statement[]): void {
2464  const popNode: ts.Statement = ts.factory.createExpressionStatement(
2465    createFunction(ts.factory.createIdentifier(COMPONENT_GESTURE),
2466      ts.factory.createIdentifier(COMPONENT_POP_FUNCTION), null));
2467  statements.push(popNode);
2468  updateStatements.push(popNode);
2469  parseGestureInterface(node, statements, log, updateStatements);
2470  const argumentArr: ts.NodeArray<ts.PropertyAccessExpression> = ts.factory.createNodeArray(
2471    [ts.factory.createPropertyAccessExpression(
2472      ts.factory.createIdentifier(GESTURE_ENUM_KEY),
2473      ts.factory.createIdentifier(gestureMap.get(propName)))
2474    ]
2475  );
2476  if (node.arguments && node.arguments.length > 1 &&
2477    ts.isPropertyAccessExpression(node.arguments[1])) {
2478    // @ts-ignore
2479    argumentArr.push(node.arguments[1]);
2480  }
2481  const createNode: ts.Statement = ts.factory.createExpressionStatement(
2482    createFunction(ts.factory.createIdentifier(COMPONENT_GESTURE),
2483      ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION), argumentArr));
2484  statements.push(createNode);
2485  updateStatements.push(createNode);
2486}
2487
2488function processGestureType(node: ts.CallExpression, statements: ts.Statement[], log: LogInfo[],
2489  updateStatements: ts.Statement[], reverse: boolean = false): void {
2490  const newStatements: ts.Statement[] = [];
2491  const newNode: ts.ExpressionStatement = ts.factory.createExpressionStatement(node);
2492  let temp: any = node.expression;
2493  while (temp && !ts.isIdentifier(temp) && temp.expression) {
2494    temp = temp.expression;
2495  }
2496  if (temp && temp.parent && ts.isCallExpression(temp.parent) && ts.isIdentifier(temp) &&
2497    GESTURE_TYPE_NAMES.has(temp.escapedText.toString())) {
2498    newStatements.push(ts.factory.createExpressionStatement(
2499      createFunction(temp, ts.factory.createIdentifier(COMPONENT_POP_FUNCTION), null)));
2500    if (temp.escapedText.toString() === COMPONENT_GESTURE_GROUP) {
2501      const gestureStatements: ts.Statement[] = [];
2502      parseGestureInterface(temp.parent, gestureStatements, log, updateStatements, true);
2503      newStatements.push(...gestureStatements.reverse());
2504      bindComponentAttr(newNode, temp, newStatements, log, false);
2505      let argumentArr: ts.NodeArray<ts.Expression> = null;
2506      if (temp.parent.arguments && temp.parent.arguments.length) {
2507        // @ts-ignore
2508        argumentArr = ts.factory.createNodeArray([temp.parent.arguments[0]]);
2509      }
2510      newStatements.push(ts.factory.createExpressionStatement(
2511        createFunction(temp, ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION), argumentArr)));
2512    } else {
2513      bindComponentAttr(newNode, temp, newStatements, log, false);
2514      newStatements.push(ts.factory.createExpressionStatement(
2515        createFunction(temp, ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION), temp.parent.arguments)));
2516    }
2517  }
2518  if (newStatements.length) {
2519    reverse ? statements.push(...newStatements.reverse()) : statements.push(...newStatements);
2520    reverse ? updateStatements.push(...newStatements.reverse()) : updateStatements.push(...newStatements);
2521  }
2522}
2523
2524function parseGestureInterface(node: ts.CallExpression, statements: ts.Statement[], log: LogInfo[],
2525  updateStatements: ts.Statement[], reverse: boolean = false): void {
2526  if (node.arguments && node.arguments.length) {
2527    node.arguments.forEach((item: ts.Node) => {
2528      if (ts.isCallExpression(item)) {
2529        processGestureType(item, statements, log, updateStatements, reverse);
2530      }
2531    });
2532  }
2533}
2534
2535export function getName(node: ts.ExpressionStatement | ts.Expression): string {
2536  // @ts-ignore
2537  let temp: any = node.expression;
2538  let name: string;
2539  while (temp) {
2540    if (ts.isIdentifier(temp) && temp.parent && (ts.isCallExpression(temp.parent) ||
2541      ts.isEtsComponentExpression(temp.parent))) {
2542      name = temp.escapedText.toString();
2543      break;
2544    } else if (ts.isPropertyAccessExpression(temp) && temp.name && ts.isIdentifier(temp.name) &&
2545      isCustomAttributes(temp)) {
2546      name = temp.name.escapedText.toString();
2547      break;
2548    }
2549    temp = temp.expression;
2550  }
2551  return name;
2552}
2553
2554function isCustomAttributes(temp: ts.PropertyAccessExpression): boolean {
2555  if (temp.expression && temp.expression.getText() === THIS) {
2556    return true;
2557  } else if (temp.expression && ts.isIdentifier(temp.expression) && temp.expression.getText() === $$ &&
2558    builderTypeParameter.params.includes(temp.expression.getText())) {
2559    return true;
2560  } else {
2561    return !BUILDIN_STYLE_NAMES.has(temp.name.escapedText.toString());
2562  }
2563}
2564
2565export function isAttributeNode(node: ts.ExpressionStatement): boolean {
2566  let temp: any = node.expression;
2567  let name: string;
2568  while (temp) {
2569    if (ts.isCallExpression(temp) && temp.expression && ts.isIdentifier(temp.expression)) {
2570      name = temp.expression.escapedText.toString();
2571      break;
2572    }
2573    temp = temp.expression;
2574  }
2575  return BUILDIN_STYLE_NAMES.has(name);
2576}
2577
2578enum ComponentType {
2579  innerComponent,
2580  customComponent,
2581  forEachComponent,
2582  customBuilderMethod,
2583  builderParamMethod,
2584  function,
2585  builderTypeFunction
2586}
2587
2588function isEtsComponent(node: ts.ExpressionStatement): boolean {
2589  let isEtsComponent: boolean = false;
2590  let temp: any = node.expression;
2591  while (temp) {
2592    if (ts.isEtsComponentExpression(temp)) {
2593      isEtsComponent = true;
2594    }
2595    temp = temp.expression;
2596  }
2597  return isEtsComponent;
2598}
2599
2600function isSomeName(forEachParameters: ts.NodeArray<ts.ParameterDeclaration>, name: string): boolean {
2601  return Array.isArray(forEachParameters) &&
2602    forEachParameters.some((item)=>{
2603      return ts.isIdentifier(item.name) ? item.name.escapedText.toString() === name : false;
2604    });
2605}
2606
2607function isParamFunction(node: ts.ExpressionStatement): boolean {
2608  return node.expression && ts.isCallExpression(node.expression) &&
2609    node.expression.expression && ts.isIdentifier(node.expression.expression);
2610}
2611
2612function getComponentType(node: ts.ExpressionStatement, log: LogInfo[], name: string,
2613  parent: string, forEachParameters: ts.NodeArray<ts.ParameterDeclaration> = undefined): ComponentType {
2614  let isBuilderName: boolean = true;
2615  if (forEachParameters && isSomeName(forEachParameters, name) && isParamFunction(node)) {
2616    isBuilderName = false;
2617  }
2618  if (isEtsComponent(node)) {
2619    if (componentCollection.customComponents.has(name)) {
2620      return ComponentType.customComponent;
2621    } else {
2622      return ComponentType.innerComponent;
2623    }
2624  } else if (componentCollection.customComponents.has(name)) {
2625    return ComponentType.customComponent;
2626  } else if (name === COMPONENT_FOREACH || name === COMPONENT_LAZYFOREACH) {
2627    return ComponentType.forEachComponent;
2628  } else if (CUSTOM_BUILDER_METHOD.has(name) && isBuilderName) {
2629    return ComponentType.customBuilderMethod;
2630  } else if (builderParamObjectCollection.get(componentCollection.currentClassName) &&
2631    builderParamObjectCollection.get(componentCollection.currentClassName).has(name)) {
2632    return ComponentType.builderParamMethod;
2633  } else if (!partialUpdateConfig.builderCheck && builderTypeParameter.params.includes(name) &&
2634    judgeBuilderType(node)) {
2635    return ComponentType.builderTypeFunction;
2636  } else if ((['XComponent'].includes(parent) || CUSTOM_BUILDER_METHOD.has(parent)) &&
2637    ts.isCallExpression(node.expression) && ts.isIdentifier(node.expression.expression)) {
2638    return ComponentType.function;
2639  } else if (!isAttributeNode(node)) {
2640    log.push({
2641      type: LogType.ERROR,
2642      message: `'${node.getText()}' does not meet UI component syntax.`,
2643      pos: node.getStart()
2644    });
2645  }
2646  return null;
2647}
2648
2649function judgeBuilderType(node: ts.ExpressionStatement): boolean {
2650  let checker: ts.TypeChecker;
2651  if (globalProgram.program) {
2652    checker = globalProgram.program.getTypeChecker();
2653  } else if (globalProgram.watchProgram) {
2654    checker = globalProgram.watchProgram.getCurrentProgram().getProgram().getTypeChecker();
2655  }
2656  if (node.expression && node.expression.expression && checker) {
2657    const type: ts.Type = checker.getTypeAtLocation(node.expression.expression);
2658    if (type && type.aliasSymbol && type.aliasSymbol.escapedName === BUILDER_TYPE) {
2659      return true;
2660    }
2661  }
2662  return false;
2663}
2664
2665export function validateStateStyleSyntax(temp: any, log: LogInfo[]): void {
2666  log.push({
2667    type: LogType.ERROR,
2668    message: `.stateStyles doesn't conform standard.`,
2669    pos: temp.getStart()
2670  });
2671}
2672
2673function getEtsComponentExpression(node:ts.ExpressionStatement): ts.EtsComponentExpression {
2674  let current: any = node.expression;
2675  while (current) {
2676    if (ts.isEtsComponentExpression(current)) {
2677      return current;
2678    }
2679    current = current.expression;
2680  }
2681  return null;
2682}
2683
2684function checkEtsAndIdInIf(node:ts.ExpressionStatement, parent: string): [ts.EtsComponentExpression, ts.Expression] {
2685  let current: any = node.expression;
2686  let idName: ts.Expression;
2687  while (current) {
2688    if (ts.isEtsComponentExpression(current)) {
2689      break;
2690    }
2691    if (!idName && parent === COMPONENT_IF && ts.isPropertyAccessExpression(current) && current.name &&
2692      ts.isIdentifier(current.name) && current.name.escapedText.toString() === ATTRIBUTE_ID &&
2693      current.parent && current.parent.arguments && current.parent.arguments.length) {
2694      idName = current.parent.arguments[0];
2695    }
2696    current = current.expression;
2697  }
2698  return [current, idName];
2699}
2700
2701function checkIdInIf(node:ts.ExpressionStatement, parent: string): ts.Expression {
2702  let current: any = node.expression;
2703  let idName: ts.Expression;
2704  while (current) {
2705    if (parent === COMPONENT_IF && ts.isPropertyAccessExpression(current) && current.name &&
2706      ts.isIdentifier(current.name) && current.name.escapedText.toString() === ATTRIBUTE_ID &&
2707      current.parent && current.parent.arguments && current.parent.arguments.length) {
2708      idName = current.parent.arguments[0];
2709      break;
2710    }
2711    current = current.expression;
2712  }
2713  return idName;
2714}
2715
2716function checkEtsComponent(node: ts.ExpressionStatement, log: LogInfo[]): void {
2717  const etsComponentExpression: ts.EtsComponentExpression = getEtsComponentExpression(node);
2718  if (etsComponentExpression) {
2719    checkAllNode(
2720      etsComponentExpression,
2721      new Set([...INNER_COMPONENT_NAMES, ...componentCollection.customComponents]),
2722      transformLog.sourceFile,
2723      log
2724    );
2725  }
2726}
2727
2728function checkButtonParamHasLabel(node: ts.EtsComponentExpression, log: LogInfo[]): void {
2729  if (node.arguments && node.arguments.length !== 0) {
2730    for (let i = 0; i < node.arguments.length; i++) {
2731      let argument: ts.Expression = node.arguments[i];
2732      if (ts.isStringLiteral(argument) || (ts.isCallExpression(argument) && ts.isIdentifier(argument.expression) &&
2733        (argument.expression.escapedText.toString() === RESOURCE))) {
2734        log.push({
2735          type: LogType.ERROR,
2736          message: 'The Button component with a label parameter can not have any child.',
2737          pos: node.getStart()
2738        });
2739        return;
2740      }
2741    }
2742  }
2743}
2744
2745function isLazyForEachChild(node: ts.ExpressionStatement): boolean {
2746  let temp: any = node.parent;
2747  while (temp && !ts.isEtsComponentExpression(temp) && !ts.isCallExpression(temp)) {
2748    temp = temp.parent;
2749  }
2750  if (temp && temp.expression && (temp.expression as ts.Identifier).escapedText.toString() === COMPONENT_LAZYFOREACH) {
2751    return true;
2752  }
2753  return false;
2754}
2755
2756function processDollarEtsComponent(argumentsArr: ts.NodeArray<ts.Expression>, name: string): ts.Expression[] {
2757  const arr: ts.Expression[] = [];
2758  argumentsArr.forEach((item: ts.Expression, index: number) => {
2759    if (ts.isObjectLiteralExpression(item) && item.properties && item.properties.length) {
2760      const properties: ts.PropertyAssignment[] = [];
2761      item.properties.forEach((param: ts.PropertyAssignment, paramIndex: number) => {
2762        if (isHaveDoubleDollar(param, name)) {
2763          const varExp: ts.Expression = updateArgumentFor$$(param.initializer);
2764          properties.push(ts.factory.updatePropertyAssignment(param, param.name, generateObjectFor$$(varExp)));
2765        } else {
2766          properties.push(param);
2767        }
2768      });
2769      arr.push(ts.factory.updateObjectLiteralExpression(item, properties));
2770    } else {
2771      arr.push(item);
2772    }
2773  });
2774  return arr;
2775}
2776
2777export function createFunction(node: ts.Identifier, attrNode: ts.Identifier,
2778  argumentsArr: ts.NodeArray<ts.Expression>): ts.CallExpression {
2779  if (argumentsArr && argumentsArr.length) {
2780    const compName: string = node.escapedText.toString();
2781    const type: string = attrNode.escapedText.toString();
2782    if (type === COMPONENT_CREATE_FUNCTION && PROPERTIES_ADD_DOUBLE_DOLLAR.has(compName)) {
2783      // @ts-ignore
2784      argumentsArr = processDollarEtsComponent(argumentsArr, compName);
2785    }
2786    if (checkCreateArgumentBuilder(node, attrNode)) {
2787      argumentsArr = transformBuilder(argumentsArr);
2788    }
2789  } else {
2790    // @ts-ignore
2791    argumentsArr = [];
2792  }
2793  return ts.factory.createCallExpression(
2794    ts.factory.createPropertyAccessExpression(
2795      node,
2796      attrNode
2797    ),
2798    undefined,
2799    argumentsArr
2800  );
2801}
2802
2803function checkCreateArgumentBuilder(node: ts.Identifier, attrNode: ts.Identifier): boolean {
2804  if (attrNode.escapedText.toString() === COMPONENT_CREATE_FUNCTION &&
2805    CREATE_BIND_COMPONENT.has(node.escapedText.toString())) {
2806    return true;
2807  }
2808  return false;
2809}
2810
2811function transformBuilder(argumentsArr: ts.NodeArray<ts.Expression>): ts.NodeArray<ts.Expression> {
2812  const newArguments: ts.Expression[] = [];
2813  argumentsArr.forEach((argument: ts.Expression) => {
2814    newArguments.push(parseCreateParameterBuilder(argument));
2815  });
2816  // @ts-ignore
2817  return newArguments;
2818}
2819
2820function parseCreateParameterBuilder(argument: ts.Expression):ts.Expression {
2821  if (ts.isObjectLiteralExpression(argument)) {
2822    return processObjectPropertyBuilder(argument);
2823  } else {
2824    return argument;
2825  }
2826}
2827