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  STYLE_ADD_DOUBLE_EXCLAMATION,
53  $$_VALUE,
54  $$_CHANGE_EVENT,
55  $$_THIS,
56  $$_NEW_VALUE,
57  $_VALUE,
58  BUILDER_ATTR_NAME,
59  BUILDER_ATTR_BIND,
60  CUSTOM_DIALOG_CONTROLLER_BUILDER,
61  BIND_DRAG_SET,
62  BIND_POPUP_SET,
63  BIND_POPUP,
64  CUSTOM_COMPONENT_DEFAULT,
65  $$,
66  PROPERTIES_ADD_DOUBLE_DOLLAR,
67  ATTRIBUTE_ID,
68  RESOURCE,
69  ISINITIALRENDER,
70  ELMTID,
71  VIEWSTACKPROCESSOR,
72  STOPGETACCESSRECORDING,
73  STARTGETACCESSRECORDINGFOR,
74  OBSERVECOMPONENTCREATION,
75  OBSERVECOMPONENTCREATION2,
76  DEEPRENDERFUNCTION,
77  ITEMCREATION,
78  ITEMCREATION2,
79  OBSERVEDDEEPRENDER,
80  ItemComponents,
81  FOREACHITEMGENFUNCTION,
82  __LAZYFOREACHITEMGENFUNCTION,
83  _ITEM,
84  FOREACHITEMIDFUNC,
85  __LAZYFOREACHITEMIDFUNC,
86  FOREACHUPDATEFUNCTION,
87  COMPONENT_INITIAL_RENDER_FUNCTION,
88  COMPONENT_REPEAT,
89  REPEAT_EACH,
90  REPEAT_TEMPLATE,
91  LIST_ITEM,
92  IFELSEBRANCHUPDATEFUNCTION,
93  CARD_ENABLE_COMPONENTS,
94  CARD_LOG_TYPE_COMPONENTS,
95  COMPONENT_CONSTRUCTOR_PARENT,
96  RESOURCE_NAME_TYPE,
97  XCOMPONENT_SINGLE_QUOTATION,
98  XCOMPONENT_DOUBLE_QUOTATION,
99  XCOMPONENTTYPE,
100  XCOMPONENTTYPE_CONTAINER,
101  BIND_OBJECT_PROPERTY,
102  TRUE,
103  FALSE,
104  HEADER,
105  INDICATORBUILDER,
106  FOOTER,
107  CALL,
108  CREATE_BIND_COMPONENT,
109  TabContentAndNavDestination,
110  START,
111  END,
112  BUILDER_PARAM_PROXY,
113  BUILDER_TYPE,
114  CHECK_COMPONENT_EXTEND_DECORATOR,
115  CHECK_COMPONENT_ANIMATABLE_EXTEND_DECORATOR,
116  RECYCLE_REUSE_ID,
117  UPDATE_FUNC_BY_ELMT_ID,
118  CREATE_SET_METHOD,
119  CAN_RETAKE,
120  PREVIEW,
121  IDS,
122  PUSH,
123  UPDATE_LAZY_FOREACH_ELEMENTS,
124  INDEX,
125  IS_INITIAL_ITEM,
126  MY_IDS,
127  WRAPBUILDER_BUILDERPROP,
128  WRAPPEDBUILDER_CLASS,
129  ALL_COMPONENTS,
130  ATTRIBUTE_ATTRIBUTE_MODIFIER,
131  ATTRIBUTE_CONTENT_MODIFIER,
132  ATTRIBUTE_MENUITEM_CONTENT_MODIFIER,
133  TITLE,
134  PAGE_PATH,
135  RESOURCE_NAME_MODULE,
136  NAV_DESTINATION,
137  NAVIGATION,
138  CREATE_ROUTER_COMPONENT_COLLECT,
139  NAV_PATH_STACK,
140  IS_USER_CREATE_STACK
141} from './pre_define';
142import {
143  INNER_COMPONENT_NAMES,
144  BUILDIN_CONTAINER_COMPONENT,
145  BUILDIN_STYLE_NAMES,
146  CUSTOM_BUILDER_METHOD,
147  GESTURE_ATTRS,
148  GESTURE_TYPE_NAMES,
149  EXTEND_ATTRIBUTE,
150  NO_DEBUG_LINE_COMPONENT,
151  NEEDPOP_COMPONENT,
152  INNER_STYLE_FUNCTION,
153  GLOBAL_STYLE_FUNCTION,
154  CUSTOM_BUILDER_PROPERTIES,
155  CUSTOM_BUILDER_PROPERTIES_WITHOUTKEY,
156  CUSTOM_BUILDER_CONSTRUCTORS,
157  ID_ATTRS,
158  SPECIFIC_PARENT_COMPONENT,
159  STYLES_ATTRIBUTE
160} from './component_map';
161import {
162  componentCollection,
163  builderParamObjectCollection,
164  checkAllNode,
165  enumCollection
166} from './validate_ui_syntax';
167import {
168  processCustomComponent,
169  createConditionParent,
170  isRecycle
171} from './process_custom_component';
172import {
173  LogType,
174  LogInfo,
175  componentInfo,
176  storedFileInfo
177} from './utils';
178import {
179  globalProgram,
180  partialUpdateConfig,
181  projectConfig
182} from '../main';
183import {
184  transformLog,
185  contextGlobal,
186  validatorCard,
187  builderTypeParameter,
188  resourceFileName
189} from './process_ui_syntax';
190import { regularCollection } from './validate_ui_syntax';
191import { contextStackPushOrPop } from './process_component_class';
192
193export function processComponentBuild(node: ts.MethodDeclaration,
194  log: LogInfo[]): ts.MethodDeclaration {
195  let newNode: ts.MethodDeclaration;
196  let renderNode: ts.Identifier;
197  if (!partialUpdateConfig.partialUpdateMode) {
198    renderNode = ts.factory.createIdentifier(COMPONENT_RENDER_FUNCTION);
199  } else {
200    renderNode = ts.factory.createIdentifier(COMPONENT_INITIAL_RENDER_FUNCTION);
201  }
202  if (node.body && node.body.statements && node.body.statements.length &&
203    validateRootNode(node, log)) {
204    const componentBlock: ts.Block = processComponentBlock(node.body, false, log);
205    newNode = ts.factory.updateMethodDeclaration(node, ts.getModifiers(node),
206      node.asteriskToken, renderNode, node.questionToken, node.typeParameters, node.parameters,
207      node.type, componentBlock);
208    if (partialUpdateConfig.partialUpdateMode && storedFileInfo.hasLocalBuilderInFile) {
209      componentBlock.statements.unshift(contextStackPushOrPop(ts.factory.createIdentifier(PUSH), [ts.factory.createThis()]));
210      componentBlock.statements.push(contextStackPushOrPop(ts.factory.createIdentifier(COMPONENT_POP_FUNCTION), [])); 
211    }
212  } else {
213    newNode = ts.factory.updateMethodDeclaration(node, ts.getModifiers(node),
214      node.asteriskToken, renderNode, node.questionToken, node.typeParameters, node.parameters,
215      node.type, node.body);
216  }
217  return newNode;
218}
219
220function createLazyForEachBlockNode(newStatements: ts.Statement[]): ts.IfStatement {
221  return ts.factory.createIfStatement(
222    ts.factory.createBinaryExpression(
223      ts.factory.createBinaryExpression(
224        ts.factory.createIdentifier(IS_INITIAL_ITEM),
225        ts.factory.createToken(ts.SyntaxKind.EqualsEqualsEqualsToken),
226        ts.factory.createIdentifier(COMPONENT_IF_UNDEFINED)
227      ),
228      ts.factory.createToken(ts.SyntaxKind.BarBarToken),
229      ts.factory.createIdentifier(IS_INITIAL_ITEM)
230    ),
231    ts.factory.createBlock(newStatements, true),
232    ts.factory.createBlock([
233      ts.factory.createExpressionStatement(ts.factory.createCallExpression(
234        ts.factory.createPropertyAccessExpression(
235          ts.factory.createThis(),
236          ts.factory.createIdentifier(UPDATE_LAZY_FOREACH_ELEMENTS)
237        ), undefined, [
238          ts.factory.createIdentifier(IDS),
239          storedFileInfo.lazyForEachInfo.forEachParameters.name as ts.Identifier
240        ]
241      ))
242    ], true)
243  );
244}
245
246export type BuilderParamsResult = {
247  firstParam: ts.ParameterDeclaration;
248};
249
250export function parseGlobalBuilderParams(parameters: ts.NodeArray<ts.ParameterDeclaration>,
251  builderParamsResult: BuilderParamsResult) : void {
252  if (partialUpdateConfig.partialUpdateMode && parameters.length && parameters.length === 1 &&
253    ts.isIdentifier(parameters[0].name)) {
254    builderParamsResult.firstParam = parameters[0];
255  }
256}
257
258export function processComponentBlock(node: ts.Block, isLazy: boolean, log: LogInfo[],
259  isTransition: boolean = false, isBuilder: boolean = false, parent: string = undefined,
260  forEachParameters: ts.NodeArray<ts.ParameterDeclaration> = undefined,
261  isGlobalBuilder: boolean = false, builderParamsResult: BuilderParamsResult = null,
262  rootGlobalBuilder: boolean = false): ts.Block {
263  const newStatements: ts.Statement[] = [];
264  processComponentChild(node, newStatements, log, {isAcceleratePreview: false, line: 0, column: 0, fileName: ''},
265    isBuilder, parent, forEachParameters, isGlobalBuilder, isTransition, builderParamsResult);
266  if (isLazy && !partialUpdateConfig.partialUpdateMode) {
267    newStatements.unshift(createRenderingInProgress(true));
268  }
269  if (isTransition) {
270    if (!partialUpdateConfig.partialUpdateMode) {
271      newStatements.unshift(ts.factory.createExpressionStatement(
272        createFunction(ts.factory.createIdentifier(COMPONENT_TRANSITION_NAME),
273          ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION), null)));
274    } else {
275      newStatements.unshift(createComponentCreationStatement(ts.factory.createExpressionStatement(
276        createFunction(ts.factory.createIdentifier(COMPONENT_TRANSITION_NAME),
277          ts.factory.createIdentifier(COMPONENT_POP_FUNCTION), null)), [ts.factory.createExpressionStatement(
278        createFunction(ts.factory.createIdentifier(COMPONENT_TRANSITION_NAME),
279          ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION), null))], COMPONENT_TRANSITION_NAME, false, isTransition));
280    }
281    newStatements.push(ts.factory.createExpressionStatement(
282      createFunction(ts.factory.createIdentifier(COMPONENT_TRANSITION_NAME),
283        ts.factory.createIdentifier(COMPONENT_POP_FUNCTION), null)));
284  }
285  if (isLazy && !partialUpdateConfig.partialUpdateMode) {
286    newStatements.push(createRenderingInProgress(false));
287  }
288  if (rootGlobalBuilder && isGlobalBuilder && builderParamsResult && builderParamsResult.firstParam) {
289    newStatements.unshift(forkBuilderParamNode(builderParamsResult.firstParam));
290  }
291  if (isLazy && projectConfig.optLazyForEach && storedFileInfo.processLazyForEach &&
292    storedFileInfo.lazyForEachInfo.forEachParameters) {
293    return ts.factory.updateBlock(node, [
294      createMyIdsNode(),
295      createLazyForEachBlockNode(newStatements),
296      ts.factory.createReturnStatement(ts.factory.createIdentifier(MY_IDS))
297    ]);
298  }
299  return ts.factory.updateBlock(node, newStatements);
300}
301
302function createMyIdsNode(): ts.Statement {
303  return ts.factory.createVariableStatement(
304    undefined,
305    ts.factory.createVariableDeclarationList(
306      [ts.factory.createVariableDeclaration(
307        ts.factory.createIdentifier(MY_IDS),
308        undefined,
309        undefined,
310        ts.factory.createArrayLiteralExpression(
311          [],
312          false
313        )
314      )],
315      ts.NodeFlags.Const
316    )
317  );
318}
319
320function visitComponent(node: ts.Node): void {
321  if (storedFileInfo.lazyForEachInfo && !ts.isBlock(node)) {
322    ts.forEachChild(node, (child: ts.Node) => {
323      if (storedFileInfo.lazyForEachInfo.isDependItem) {
324        return;
325      }
326      if (ts.isIdentifier(child)) {
327        const symbol: ts.Symbol = globalProgram.checker.getSymbolAtLocation(child);
328        if (symbol && symbol.valueDeclaration === storedFileInfo.lazyForEachInfo.forEachParameters) {
329          storedFileInfo.lazyForEachInfo.isDependItem = true;
330          return;
331        }
332      }
333      visitComponent(child);
334    });
335  }
336}
337
338function forkBuilderParamNode(node: ts.ParameterDeclaration): ts.Statement {
339  const paramNode: ts.Identifier = node.name as ts.Identifier;
340  return ts.factory.createVariableStatement(
341    undefined,
342    ts.factory.createVariableDeclarationList(
343      [ts.factory.createVariableDeclaration(
344        ts.factory.createIdentifier(`__${paramNode.escapedText.toString()}__`),
345        undefined,
346        undefined,
347        paramNode
348      )],
349      ts.NodeFlags.Const
350    )
351  );
352}
353
354function validateRootNode(node: ts.MethodDeclaration, log: LogInfo[]): boolean {
355  let isValid: boolean = false;
356  if (node.body.statements.length === 1) {
357    const statement: ts.Statement = node.body.statements[0];
358    if (ts.isIfStatement(statement) || validateFirstNode(statement)) {
359      isValid = true;
360    }
361  } else {
362    isValid = false;
363  }
364  if (!isValid) {
365    log.push({
366      type: LogType.ERROR,
367      message: `There should have a root container component.`,
368      pos: node.body.statements.pos
369    });
370  }
371  return isValid;
372}
373
374function validateFirstNode(node: ts.Statement): boolean {
375  const isEntryComponent: boolean =
376    componentCollection.entryComponent === componentCollection.currentClassName;
377  if (isEntryComponent && !validateContainerComponent(node)) {
378    return false;
379  }
380  return true;
381}
382
383function validateContainerComponent(node: ts.Statement): boolean {
384  if (ts.isExpressionStatement(node) && node.expression &&
385    (ts.isEtsComponentExpression(node.expression) || ts.isCallExpression(node.expression))) {
386    const nameResult: NameResult = { name: null, node: null, arguments: [] };
387    validateEtsComponentNode(node.expression, nameResult);
388    if (nameResult.name && checkContainer(nameResult.name, nameResult.node)) {
389      return true;
390    }
391  }
392  return false;
393}
394
395interface supplementType {
396  isAcceleratePreview: boolean,
397  line: number,
398  column: number,
399  fileName: string
400}
401
402let newsupplement: supplementType = {
403  isAcceleratePreview: false,
404  line: 0,
405  column: 0,
406  fileName: ''
407};
408
409type NameResult = {
410  name: string,
411  arguments: ts.NodeArray<ts.Expression> | [],
412  node?: ts.Node
413};
414
415function validateEtsComponentNode(node: ts.CallExpression | ts.EtsComponentExpression, result?: NameResult) {
416  let childNode: ts.Node = node;
417  result.name = null;
418  while (ts.isCallExpression(childNode) && childNode.expression &&
419    ts.isPropertyAccessExpression(childNode.expression) && childNode.expression.expression) {
420    childNode = childNode.expression.expression;
421  }
422  if (ts.isEtsComponentExpression(childNode)) {
423    if (ts.isIdentifier(childNode.expression)) {
424      result.name = childNode.expression.getText();
425      result.node = childNode;
426      result.arguments = childNode.arguments || [];
427    }
428    return true;
429  } else {
430    return false;
431  }
432}
433
434let sourceNode: ts.SourceFile;
435
436export function processComponentChild(node: ts.Block | ts.SourceFile, newStatements: ts.Statement[],
437  log: LogInfo[], supplement: supplementType = {isAcceleratePreview: false, line: 0, column: 0, fileName: ''},
438  isBuilder: boolean = false, parent: string = undefined,
439  forEachParameters: ts.NodeArray<ts.ParameterDeclaration> = undefined, isGlobalBuilder: boolean = false,
440  isTransition: boolean = false, builderParamsResult: BuilderParamsResult = null): void {
441  if (supplement.isAcceleratePreview) {
442    newsupplement = supplement;
443    const compilerOptions = ts.readConfigFile(
444      path.resolve(__dirname, '../tsconfig.json'), ts.sys.readFile).config.compilerOptions;
445    Object.assign(compilerOptions, {
446      'sourceMap': false
447    });
448    sourceNode = ts.createSourceFile('', node.getText(), ts.ScriptTarget.Latest, true, ts.ScriptKind.ETS, compilerOptions);
449  }
450  if (node.statements.length) {
451    // Save parent component
452    const savedParent: string = parent;
453    node.statements.forEach((item) => {
454      if (ts.isExpressionStatement(item)) {
455        assignParameter(forEachParameters, item);
456        checkEtsComponent(item, log);
457        const name: string = getName(item);
458        if (CARD_ENABLE_COMPONENTS.has(name)) {
459          validatorCard(log, CARD_LOG_TYPE_COMPONENTS, item.getStart(), name);
460        }
461        switch (getComponentType(item, log, name, parent, forEachParameters)) {
462          case ComponentType.innerComponent: {
463            const [etsExpression, idName]: [ts.EtsComponentExpression, ts.Expression] =
464              checkEtsAndIdInIf(item, savedParent);
465            if (ts.isIdentifier(etsExpression.expression)) {
466              parent = etsExpression.expression.escapedText.toString();
467            }
468            processInnerComponent(item, newStatements, log, parent, isBuilder, isGlobalBuilder,
469              isTransition, idName, savedParent, builderParamsResult);
470            break;
471          }
472          case ComponentType.customComponent: {
473            const idName: ts.Expression = checkIdInIf(item, savedParent);
474            parent = undefined;
475            if (!newsupplement.isAcceleratePreview) {
476              if (item.expression && ts.isEtsComponentExpression(item.expression) && item.expression.body) {
477                const expressionResult: ts.ExpressionStatement =
478                  processExpressionStatementChange(item, item.expression.body, log);
479                if (expressionResult) {
480                  item = expressionResult;
481                }
482              }
483              processCustomComponent(item as ts.ExpressionStatement, newStatements, log, name,
484                isBuilder, isGlobalBuilder, idName, builderParamsResult);
485            }
486            break;
487          }
488          case ComponentType.forEachComponent:
489            parent = undefined;
490            if (!partialUpdateConfig.partialUpdateMode) {
491              processForEachComponent(item, newStatements, log, isBuilder, isGlobalBuilder);
492            } else {
493              processForEachComponentNew(item, newStatements, log, name, isGlobalBuilder, builderParamsResult);
494            }
495            break;
496          case ComponentType.repeatComponent:
497            parent = undefined;
498            processRepeatComponent(item, newStatements, log, isBuilder, isGlobalBuilder, isTransition, builderParamsResult);
499            break;
500          case ComponentType.customBuilderMethod:
501            parent = undefined;
502            if (partialUpdateConfig.partialUpdateMode) {
503              newStatements.push(transferBuilderCall(item, name, isBuilder));
504            } else {
505              newStatements.push(addInnerBuilderParameter(item, isGlobalBuilder));
506            }
507            break;
508          case ComponentType.builderParamMethod:
509            parent = undefined;
510            if (partialUpdateConfig.partialUpdateMode) {
511              newStatements.push(transferBuilderCall(item, name, isBuilder));
512            } else {
513              newStatements.push(addInnerBuilderParameter(item));
514            }
515            break;
516          case ComponentType.builderTypeFunction:
517            parent = undefined;
518            if (partialUpdateConfig.partialUpdateMode) {
519              newStatements.push(transferBuilderCall(item, name, isBuilder));
520            } else {
521              newStatements.push(addInnerBuilderParameter(item));
522            }
523            break;
524          case ComponentType.function:
525            parent = undefined;
526            newStatements.push(item);
527            break;
528        }
529      } else if (ts.isIfStatement(item)) {
530        assignParameter(forEachParameters, item);
531        processIfStatement(item, newStatements, log, isBuilder, isGlobalBuilder, builderParamsResult);
532      } else if (!ts.isBlock(item)) {
533        log.push({
534          type: LogType.ERROR,
535          message: `Only UI component syntax can be written in build method.`,
536          pos: item.getStart()
537        });
538      }
539      storedFileInfo.lazyForEachInfo.isDependItem = false;
540    });
541  }
542  if (supplement.isAcceleratePreview) {
543    newsupplement = {
544      isAcceleratePreview: false,
545      line: 0,
546      column: 0,
547      fileName: ''
548    };
549  }
550}
551
552function assignParameter(forEachParameters: ts.NodeArray<ts.ParameterDeclaration>, item: ts.Node): void {
553  if (partialUpdateConfig.partialUpdateMode && projectConfig.optLazyForEach &&
554    storedFileInfo.processLazyForEach) {
555    if (forEachParameters && forEachParameters[0]) {
556      storedFileInfo.lazyForEachInfo.forEachParameters = forEachParameters[0];
557    }
558    if (storedFileInfo.lazyForEachInfo.forEachParameters) {
559      visitComponent(item);
560    }
561  }
562}
563
564export function transferBuilderCall(node: ts.ExpressionStatement, name: string,
565  isBuilder: boolean = false): ts.ExpressionStatement {
566  if (node.expression && ts.isCallExpression(node.expression)) {
567    let newNode: ts.Expression = builderCallNode(node.expression);
568    newNode.expression.questionDotToken = node.expression.questionDotToken;
569    if (node.expression.arguments && node.expression.arguments.length === 1 && ts.isObjectLiteralExpression(node.expression.arguments[0])) {
570      return ts.factory.createExpressionStatement(ts.factory.updateCallExpression(
571        node.expression,
572        newNode,
573        undefined,
574        [ts.factory.createCallExpression(
575          ts.factory.createIdentifier(BUILDER_PARAM_PROXY),
576          undefined,
577          [
578            ts.factory.createStringLiteral(name),
579            traverseBuilderParams(node.expression.arguments[0], isBuilder)
580          ]
581        )]
582      ));
583    } else {
584      return ts.factory.createExpressionStatement(ts.factory.updateCallExpression(
585        node.expression,
586        newNode,
587        undefined,
588        !(projectConfig.optLazyForEach && (storedFileInfo.processLazyForEach &&
589          storedFileInfo.lazyForEachInfo.forEachParameters || isBuilder)) ? node.expression.arguments :
590          [...node.expression.arguments, ts.factory.createNull(), ts.factory.createIdentifier(MY_IDS)]
591      ));
592    }
593  }
594  return undefined;
595}
596
597function builderCallNode(node: ts.CallExpression): ts.Expression {
598  let newNode: ts.Expression;
599  if (node.expression && ts.isPropertyAccessExpression(node.expression) &&
600    node.expression.questionDotToken && node.expression.questionDotToken.kind === ts.SyntaxKind.QuestionDotToken) {
601    newNode = ts.factory.createCallChain(
602      ts.factory.createPropertyAccessChain(
603        node.expression,
604        node.questionDotToken,
605        ts.factory.createIdentifier(BUILDER_ATTR_BIND)
606      ),
607      undefined,
608      undefined,
609      [ts.factory.createThis()]
610    );
611  } else {
612    newNode = ts.factory.createCallExpression(
613      ts.factory.createPropertyAccessExpression(
614        node.expression,
615        ts.factory.createIdentifier(BUILDER_ATTR_BIND)
616      ),
617      undefined,
618      [ts.factory.createThis()]
619    );
620  }
621  return newNode;
622}
623
624function traverseBuilderParams(node: ts.ObjectLiteralExpression,
625  isBuilder: boolean): ts.ObjectLiteralExpression {
626  const properties: ts.ObjectLiteralElementLike[] = [];
627  if (node.properties && node.properties.length) {
628    node.properties.forEach(property => {
629      if (ts.isPropertyAssignment(property) && property.initializer &&
630        ts.isPropertyAccessExpression(property.initializer) && property.initializer.expression &&
631        property.initializer.name && ts.isIdentifier(property.initializer.name)) {
632        const name: string = property.initializer.name.escapedText.toString();
633        if (!storedFileInfo.processGlobalBuilder && property.initializer.expression.kind === ts.SyntaxKind.ThisKeyword ||
634          isBuilder && ts.isIdentifier(property.initializer.expression) &&
635          property.initializer.expression.escapedText.toString() === $$) {
636          const useThis: boolean = property.initializer.expression.kind === ts.SyntaxKind.ThisKeyword;
637          addProperties(properties, property, name, isBuilder, useThis);
638        } else {
639          addBuilderParamsProperties(properties, property);
640        }
641      } else {
642        addBuilderParamsProperties(properties, property);
643      }
644    });
645  }
646  return ts.factory.createObjectLiteralExpression(properties);
647}
648
649function addBuilderParamsProperties(properties: ts.ObjectLiteralElementLike[],
650  property: ts.ObjectLiteralElementLike): void {
651  const initializer: ts.Expression = ts.isShorthandPropertyAssignment(property) ?
652    property.name : property.initializer;
653  properties.push(ts.factory.createPropertyAssignment(
654    property.name,
655    ts.factory.createArrowFunction(
656      undefined,
657      undefined,
658      [],
659      undefined,
660      ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
661      initializer
662    )
663  ));
664}
665
666function addProperties(properties: ts.ObjectLiteralElementLike[], property: ts.ObjectLiteralElementLike,
667  name: string, isBuilder: boolean, useThis: boolean): void {
668  properties.push(ts.factory.createPropertyAssignment(
669    property.name,
670    ts.factory.createArrowFunction(
671      undefined,
672      undefined,
673      [],
674      undefined,
675      ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
676      ts.factory.createParenthesizedExpression(ts.factory.createConditionalExpression(
677        ts.factory.createElementAccessExpression(
678          (isBuilder && !useThis) ? ts.factory.createIdentifier($$) : ts.factory.createThis(),
679          ts.factory.createStringLiteral('__' + name)
680        ),
681        ts.factory.createToken(ts.SyntaxKind.QuestionToken),
682        ts.factory.createElementAccessExpression(
683          (isBuilder && !useThis) ? ts.factory.createIdentifier($$) : ts.factory.createThis(),
684          ts.factory.createStringLiteral('__' + name)
685        ),
686        ts.factory.createToken(ts.SyntaxKind.ColonToken),
687        ts.factory.createElementAccessExpression(
688          (isBuilder && !useThis) ? ts.factory.createIdentifier($$) : ts.factory.createThis(),
689          ts.factory.createStringLiteral(name)
690        )
691      ))
692    )
693  ));
694}
695
696function addInnerBuilderParameter(node: ts.ExpressionStatement,
697  isGlobalBuilder: boolean = false): ts.ExpressionStatement {
698  if (node.expression && ts.isCallExpression(node.expression) && node.expression.arguments) {
699    node.expression.arguments.push(isGlobalBuilder ? parentConditionalExpression() : ts.factory.createThis());
700    return ts.factory.createExpressionStatement(ts.factory.updateCallExpression(node.expression,
701      node.expression.expression, node.expression.typeArguments, node.expression.arguments));
702  } else {
703    return node;
704  }
705}
706
707function processExpressionStatementChange(node: ts.ExpressionStatement, nextNode: ts.Block,
708  log: LogInfo[]): ts.ExpressionStatement {
709  let name: string;
710  // @ts-ignore
711  if (node.expression.expression && ts.isIdentifier(node.expression.expression)) {
712    name = node.expression.expression.escapedText.toString();
713  } else if (node.expression.expression && ts.isPropertyAccessExpression(node.expression.expression)) {
714    name = node.expression.expression.getText();
715  }
716  if (builderParamObjectCollection.get(name) &&
717    builderParamObjectCollection.get(name).size === 1) {
718    return processBlockToExpression(node, nextNode, log, name, false);
719  } else if (projectConfig.compileMode === 'esmodule' && process.env.compileTool === 'rollup' &&
720    storedFileInfo.overallBuilderParamCollection.get(name) &&
721    storedFileInfo.overallBuilderParamCollection.get(name).size === 1
722  ) {
723    return processBlockToExpression(node, nextNode, log, name, true);
724  } else {
725    log.push({
726      type: LogType.ERROR,
727      message: `In the trailing lambda case, '${name}' must have one and only one property decorated with ` +
728        '@BuilderParam, and its @BuilderParam expects no parameter.',
729      pos: node.getStart()
730    });
731    return null;
732  }
733}
734
735function processBlockToExpression(node: ts.ExpressionStatement, nextNode: ts.Block,
736  log: LogInfo[], name: string, isPropertyAccessExpressionNode: boolean): ts.ExpressionStatement {
737  const childParam: string = isPropertyAccessExpressionNode ? [...storedFileInfo.overallBuilderParamCollection.get(name)].slice(-1)[0] :
738    [...builderParamObjectCollection.get(name)].slice(-1)[0];
739  const newBlock: ts.Block = processComponentBlock(nextNode, false, log);
740  const arrowNode: ts.ArrowFunction = ts.factory.createArrowFunction(undefined, undefined,
741    [], undefined, ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), newBlock);
742  const newPropertyAssignment:ts.PropertyAssignment = ts.factory.createPropertyAssignment(
743    ts.factory.createIdentifier(childParam), arrowNode);
744  // @ts-ignore
745  let argumentsArray: ts.ObjectLiteralExpression[] = node.expression.arguments;
746  if (argumentsArray && !argumentsArray.length) {
747    argumentsArray = [ts.factory.createObjectLiteralExpression([newPropertyAssignment], true)];
748  } else if (ts.isObjectLiteralExpression(argumentsArray[0]) && argumentsArray.length === 1) {
749    argumentsArray = [ts.factory.createObjectLiteralExpression(
750      // @ts-ignore
751      node.expression.arguments[0].properties.concat([newPropertyAssignment]), true)];
752  } else if (ts.isObjectLiteralExpression(argumentsArray[0]) && argumentsArray.length === 2) {
753    argumentsArray = [ts.factory.createObjectLiteralExpression(
754      // @ts-ignore
755      node.expression.arguments[0].properties.concat([newPropertyAssignment]), true), argumentsArray[1]];
756  }
757  const callNode: ts.CallExpression = ts.factory.updateCallExpression(
758    // @ts-ignore
759    node.expression, node.expression.expression, node.expression.expression.typeArguments,
760    argumentsArray);
761  // @ts-ignore
762  node.expression.expression.parent = callNode;
763  // @ts-ignore
764  callNode.parent = node.expression.parent;
765  node = ts.factory.updateExpressionStatement(node, callNode);
766  return node;
767}
768
769type EtsComponentResult = {
770  etsComponentNode: ts.EtsComponentExpression;
771  hasAttr: boolean;
772};
773function parseEtsComponentExpression(node: ts.ExpressionStatement): EtsComponentResult {
774  let etsComponentNode: ts.EtsComponentExpression;
775  let hasAttr: boolean = false;
776  let temp: any = node.expression;
777  while (temp) {
778    if (ts.isCallExpression(temp) && temp.expression &&
779      ts.isPropertyAccessExpression(temp.expression)) {
780      hasAttr = true;
781    }
782    if (ts.isEtsComponentExpression(temp)) {
783      etsComponentNode = temp;
784      break;
785    }
786    temp = temp.expression;
787  }
788  return { etsComponentNode: etsComponentNode, hasAttr: hasAttr };
789}
790
791export function createCollectElmtIdNode(): ts.ExpressionStatement {
792  return ts.factory.createExpressionStatement(ts.factory.createCallExpression(
793    ts.factory.createPropertyAccessExpression(
794      ts.factory.createIdentifier(MY_IDS),
795      ts.factory.createIdentifier(PUSH)
796    ),
797    undefined,
798    [ts.factory.createIdentifier(ELMTID)]
799  ));
800}
801
802function processInnerComponent(node: ts.ExpressionStatement, innerCompStatements: ts.Statement[],
803  log: LogInfo[], parent: string = undefined, isBuilder: boolean = false, isGlobalBuilder: boolean = false,
804  isTransition: boolean = false, idName: ts.Expression = undefined, savedParent: string = undefined,
805  builderParamsResult: BuilderParamsResult = null): void {
806  const newStatements: ts.Statement[] = [];
807  const res: CreateResult = createComponent(node, COMPONENT_CREATE_FUNCTION);
808  newStatements.push(res.newNode);
809  const nameResult: NameResult = { name: null, arguments: [] };
810  validateEtsComponentNode(node.expression as ts.EtsComponentExpression, nameResult);
811  if (savedParent && nameResult.name) {
812    checkNonspecificParents(node, nameResult.name, savedParent, log);
813  }
814  if (partialUpdateConfig.partialUpdateMode && ItemComponents.includes(nameResult.name)) {
815    processItemComponent(node, nameResult, innerCompStatements, log, parent, isGlobalBuilder, idName, builderParamsResult);
816  } else if (partialUpdateConfig.partialUpdateMode && TabContentAndNavDestination.has(nameResult.name)) {
817    processTabAndNav(node, innerCompStatements, nameResult, log, parent, isGlobalBuilder, idName, builderParamsResult);
818  } else {
819    processNormalComponent(node, nameResult, innerCompStatements, log, parent, isBuilder, isGlobalBuilder,
820      isTransition, idName, builderParamsResult);
821  }
822}
823
824function processNormalComponent(node: ts.ExpressionStatement, nameResult: NameResult,
825  innerCompStatements: ts.Statement[], log: LogInfo[], parent: string = undefined, isBuilder: boolean = false,
826  isGlobalBuilder: boolean = false, isTransition: boolean = false, idName: ts.Expression = undefined,
827  builderParamsResult: BuilderParamsResult = null): void {
828  const newStatements: ts.Statement[] = [];
829  if (addElmtIdNode()) {
830    newStatements.push(createCollectElmtIdNode());
831  }
832  const immutableStatements: ts.Statement[] = [];
833  const res: CreateResult = createComponent(node, COMPONENT_CREATE_FUNCTION);
834  newStatements.push(res.newNode);
835  processDebug(node, nameResult, newStatements);
836  const etsComponentResult: EtsComponentResult = parseEtsComponentExpression(node);
837  const componentName: string = res.identifierNode.getText();
838  let judgeIdStart: number;
839  if (partialUpdateConfig.partialUpdateMode && idName) {
840    judgeIdStart = innerCompStatements.length;
841  }
842  if (etsComponentResult.etsComponentNode.body && ts.isBlock(etsComponentResult.etsComponentNode.body)) {
843    if (res.isButton) {
844      checkButtonParamHasLabel(etsComponentResult.etsComponentNode, log);
845      if (projectConfig.isPreview || projectConfig.enableDebugLine) {
846        newStatements.splice(-2, 1, createComponent(node, COMPONENT_CREATE_CHILD_FUNCTION).newNode);
847      } else {
848        newStatements.splice(-1, 1, createComponent(node, COMPONENT_CREATE_CHILD_FUNCTION).newNode);
849      }
850    }
851    if (etsComponentResult.hasAttr) {
852      bindComponentAttr(node, res.identifierNode, newStatements, log, true, false, immutableStatements);
853    }
854    processInnerCompStatements(innerCompStatements, newStatements, node, isGlobalBuilder,
855      isTransition, undefined, immutableStatements, componentName, builderParamsResult);
856    storedFileInfo.lazyForEachInfo.isDependItem = false;
857    processComponentChild(etsComponentResult.etsComponentNode.body, innerCompStatements, log,
858      {isAcceleratePreview: false, line: 0, column: 0, fileName: ''}, isBuilder, parent, undefined,
859      isGlobalBuilder, false, builderParamsResult);
860  } else {
861    bindComponentAttr(node, res.identifierNode, newStatements, log, true, false, immutableStatements);
862    processInnerCompStatements(innerCompStatements, newStatements, node, isGlobalBuilder,
863      isTransition, undefined, immutableStatements, componentName, builderParamsResult);
864  }
865  if (res.isContainerComponent || res.needPop) {
866    innerCompStatements.push(createComponent(node, COMPONENT_POP_FUNCTION).newNode);
867  }
868  if (partialUpdateConfig.partialUpdateMode && idName) {
869    innerCompStatements.splice(judgeIdStart, innerCompStatements.length - judgeIdStart,
870      ifRetakeId(innerCompStatements.slice(judgeIdStart), idName));
871  }
872}
873
874export function ifRetakeId(blockContent: ts.Statement[], idName: ts.Expression): ts.IfStatement {
875  return ts.factory.createIfStatement(
876    ts.factory.createPrefixUnaryExpression(
877      ts.SyntaxKind.ExclamationToken,
878      ts.factory.createCallExpression(
879        ts.factory.createPropertyAccessExpression(
880          ts.factory.createIdentifier(COMPONENT_IF),
881          ts.factory.createIdentifier(CAN_RETAKE)
882        ),
883        undefined,
884        [idName]
885      )
886    ),
887    ts.factory.createBlock(
888      blockContent,
889      true
890    ),
891    undefined
892  );
893}
894
895function processRepeatComponent(node: ts.ExpressionStatement, innerCompStatements: ts.Statement[],
896  log: LogInfo[], isBuilder: boolean = false, isGlobalBuilder: boolean = false,
897  isTransition: boolean = false, builderParamsResult: BuilderParamsResult = null): void {
898  const chainCallTransform: ts.CallExpression =
899    recurseRepeatExpression(node.expression as ts.CallExpression, log, isBuilder, isGlobalBuilder, isTransition) as ts.CallExpression;
900  innerCompStatements.push(createComponentCreationStatement(node,
901    [ts.factory.createExpressionStatement(ts.factory.createCallExpression(
902      ts.factory.createPropertyAccessExpression(
903        chainCallTransform,
904        ts.factory.createIdentifier(COMPONENT_RENDER_FUNCTION)
905      ),
906      undefined,
907      [ts.factory.createIdentifier(ISINITIALRENDER)]
908    ))], COMPONENT_REPEAT, isGlobalBuilder, isTransition, undefined, null, builderParamsResult));
909}
910
911function recurseRepeatExpression(node: ts.CallExpression | ts.PropertyAccessExpression,
912  log: LogInfo[], isBuilder: boolean = false, isGlobalBuilder: boolean = false, isTransition: boolean = false):
913  ts.PropertyAccessExpression | ts.CallExpression {
914  if (ts.isCallExpression(node) && node.expression && ts.isIdentifier(node.expression) &&
915    node.expression.getText() === COMPONENT_REPEAT) {
916    return ts.factory.createCallExpression(node.expression, node.typeArguments, [...node.arguments, ts.factory.createThis()]);
917  } else if (ts.isPropertyAccessExpression(node)) {
918    return ts.factory.updatePropertyAccessExpression(node,
919      recurseRepeatExpression(node.expression, log, isBuilder, isGlobalBuilder, isTransition), node.name);
920  } else {
921    let repeatPropArgs: ts.ArrowFunction[] = processRepeatAttributeArrowNode(node.arguments);
922    storedFileInfo.processRepeat = true;
923    repeatPropArgs = processRepeatPropWithChild(node, repeatPropArgs, log, isBuilder, isGlobalBuilder, isTransition);
924    storedFileInfo.processRepeat = false;
925    return ts.factory.updateCallExpression(node,
926      recurseRepeatExpression(node.expression as ts.PropertyAccessExpression, log, isBuilder,
927        isGlobalBuilder, isTransition) as ts.PropertyAccessExpression, undefined, repeatPropArgs);
928  }
929}
930
931function processRepeatPropWithChild(node: ts.CallExpression, repeatPropArgs: ts.ArrowFunction[],
932  log: LogInfo[], isBuilder: boolean = false, isGlobalBuilder: boolean = false, isTransition: boolean = false): ts.ArrowFunction[] {
933  if (ts.isPropertyAccessExpression(node.expression) && ts.isIdentifier(node.expression.name) &&
934    node.expression.name.getText() === REPEAT_EACH && repeatPropArgs.length > 0 && repeatPropArgs[0].body) {
935    // transfer args for each property
936    return [
937      ts.factory.updateArrowFunction(repeatPropArgs[0], repeatPropArgs[0].modifiers, repeatPropArgs[0].typeParameters,
938        repeatPropArgs[0].parameters, repeatPropArgs[0].type, repeatPropArgs[0].equalsGreaterThanToken,
939        processComponentBlock(processRepeatCallBackBlock(repeatPropArgs[0]), false, log, isTransition, isBuilder, undefined, undefined, isGlobalBuilder)),
940      ...repeatPropArgs.slice(1)
941    ];
942  } else if (ts.isPropertyAccessExpression(node.expression) && ts.isIdentifier(node.expression.name) &&
943    node.expression.name.getText() === REPEAT_TEMPLATE && repeatPropArgs.length > 1 && repeatPropArgs[1].body) {
944    // transfer args for template property
945    return [
946      repeatPropArgs[0], ts.factory.updateArrowFunction(repeatPropArgs[1], repeatPropArgs[1].modifiers, repeatPropArgs[1].typeParameters,
947        repeatPropArgs[1].parameters, repeatPropArgs[1].type, repeatPropArgs[1].equalsGreaterThanToken,
948        processComponentBlock(processRepeatCallBackBlock(repeatPropArgs[1]), false, log, isTransition, isBuilder, undefined, undefined, isGlobalBuilder)),
949      ...repeatPropArgs.slice(2)
950    ];
951  }
952  return repeatPropArgs;
953}
954
955function processRepeatCallBackBlock(repeatPropArg: ts.ArrowFunction): ts.Block {
956  if (ts.isBlock(repeatPropArg.body)) {
957    return repeatPropArg.body;
958  } else {
959    return ts.factory.updateArrowFunction(repeatPropArg, ts.getModifiers(repeatPropArg), repeatPropArg.typeParameters,
960      repeatPropArg.parameters, repeatPropArg.type, repeatPropArg.equalsGreaterThanToken,
961      ts.factory.createBlock([ts.factory.createExpressionStatement(repeatPropArg.body)], true)).body as ts.Block;
962  }
963}
964
965function processRepeatAttributeArrowNode(argumentsNode: ts.ArrowFunction[]): ts.ArrowFunction[] {
966  for (let i = 0; i < argumentsNode.length; i++) {
967    while (ts.isParenthesizedExpression(argumentsNode[i])) {
968      if (ts.isArrowFunction(argumentsNode[i].expression)) {
969        argumentsNode.splice(i, 1, argumentsNode[i].expression);
970        break;
971      } else {
972        if (argumentsNode[i].expression) {
973          argumentsNode[i] = argumentsNode[i].expression;
974        } else {
975          break;
976        }
977      }
978    }
979  }
980  return argumentsNode;
981}
982
983function processDebug(node: ts.Statement, nameResult: NameResult, newStatements: ts.Statement[],
984  getNode: boolean = false): ts.ExpressionStatement {
985  if ((projectConfig.isPreview || projectConfig.enableDebugLine) && nameResult.name &&
986    !NO_DEBUG_LINE_COMPONENT.has(nameResult.name)) {
987    let posOfNode: ts.LineAndCharacter;
988    let curFileName: string;
989    let line: number = 1;
990    let col: number = 1;
991    if (sourceNode && newsupplement.isAcceleratePreview) {
992      posOfNode = sourceNode.getLineAndCharacterOfPosition(getRealNodePos(node) - 22);
993      curFileName = newsupplement.fileName;
994      if (posOfNode.line === 0) {
995        col = newsupplement.column - 1;
996      }
997      line = newsupplement.line;
998    } else {
999      posOfNode = transformLog.sourceFile.getLineAndCharacterOfPosition(getRealNodePos(node));
1000      curFileName = transformLog.sourceFile.fileName.replace(/\.ts$/, '');
1001    }
1002    let debugInfo: string;
1003    if (projectConfig.isPreview) {
1004      if (projectConfig.minAPIVersion >= 11) {
1005        debugInfo = `${path.relative(projectConfig.projectRootPath, curFileName).replace(/\\+/g, '/')}` +
1006          `(${posOfNode.line + line}:${posOfNode.character + col})`;
1007      } else {
1008        debugInfo = `${path.relative(projectConfig.projectPath, curFileName).replace(/\\+/g, '/')}` +
1009          `(${posOfNode.line + line}:${posOfNode.character + col})`;
1010      }
1011    } else if (projectConfig.enableDebugLine) {
1012      debugInfo = `${path.relative(projectConfig.projectRootPath, curFileName)}` +
1013        `(${posOfNode.line + line}:${posOfNode.character + col})`;
1014    }
1015    const debugNode: ts.ExpressionStatement = ts.factory.createExpressionStatement(
1016      createFunction(ts.factory.createIdentifier(nameResult.name),
1017        ts.factory.createIdentifier(COMPONENT_DEBUGLINE_FUNCTION),
1018        createDebugLineArgs(debugInfo)));
1019    if (getNode) {
1020      return debugNode;
1021    }
1022    newStatements.push(debugNode);
1023  }
1024  return undefined;
1025}
1026
1027function createDebugLineArgs(debugInfo: string): ts.NodeArray {
1028  const argsArr: ts.Node[] = [ts.factory.createStringLiteral(debugInfo)];
1029  const pkgName: string = storedFileInfo.getCurrentArkTsFile().pkgName;
1030  if (pkgName) {
1031    argsArr.push(ts.factory.createStringLiteral(pkgName));
1032  }
1033  return ts.factory.createNodeArray(argsArr);
1034}
1035
1036function processInnerCompStatements(innerCompStatements: ts.Statement[],
1037  newStatements: ts.Statement[], node: ts.Statement, isGlobalBuilder: boolean, isTransition: boolean,
1038  nameResult: NameResult, immutableStatements: ts.Statement[], componentName: string,
1039  builderParamsResult: BuilderParamsResult): void {
1040  if (!partialUpdateConfig.partialUpdateMode) {
1041    innerCompStatements.push(...newStatements);
1042  } else {
1043    innerCompStatements.push(createComponentCreationStatement(node, newStatements, componentName,
1044      isGlobalBuilder, isTransition, nameResult, immutableStatements, builderParamsResult));
1045  }
1046}
1047
1048function createComponentCreationArrowParams(isGlobalBuilder: boolean,
1049  builderParamsResult: BuilderParamsResult, isRecycleComponent: boolean = false): ts.ParameterDeclaration[] {
1050  const arrowNodes: ts.ParameterDeclaration[] = [
1051    ts.factory.createParameterDeclaration(undefined, undefined,
1052      ts.factory.createIdentifier(ELMTID), undefined, undefined, undefined),
1053    ts.factory.createParameterDeclaration(undefined, undefined,
1054      ts.factory.createIdentifier(ISINITIALRENDER), undefined, undefined, undefined)
1055  ];
1056  if (!isRecycleComponent && partialUpdateConfig.optimizeComponent && isGlobalBuilder &&
1057    builderParamsResult && builderParamsResult.firstParam) {
1058    const paramName: ts.Identifier = builderParamsResult.firstParam.name as ts.Identifier;
1059    arrowNodes.push(ts.factory.createParameterDeclaration(undefined, undefined,
1060      paramName, undefined, undefined, ts.factory.createIdentifier(`__${paramName.escapedText.toString()}__`)
1061    ));
1062  }
1063  return arrowNodes;
1064}
1065
1066export function createComponentCreationStatement(node: ts.Statement, innerStatements: ts.Statement[],
1067  componentName: string, isGlobalBuilder: boolean = false, isTransition: boolean = false,
1068  nameResult: NameResult = undefined, immutableStatements: ts.Statement[] = null,
1069  builderParamsResult: BuilderParamsResult = null, isRecycleComponent: boolean = false): ts.Statement {
1070  const blockArr: ts.Statement[] = [...innerStatements];
1071  if (nameResult) {
1072    blockArr.push(processDebug(node, nameResult, innerStatements, true));
1073  }
1074  if (!isTransition) {
1075    createInitRenderStatement(node, immutableStatements, blockArr);
1076  }
1077  if (!partialUpdateConfig.optimizeComponent) {
1078    blockArr.unshift(createViewStackProcessorStatement(STARTGETACCESSRECORDINGFOR, ELMTID));
1079    blockArr.push(createViewStackProcessorStatement(STOPGETACCESSRECORDING));
1080  }
1081  const creationArgs: ts.Expression[] = [
1082    ts.factory.createArrowFunction(undefined, undefined,
1083      createComponentCreationArrowParams(isGlobalBuilder, builderParamsResult, isRecycleComponent),
1084      undefined, ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
1085      ts.factory.createBlock(blockArr, true)
1086    )
1087  ];
1088  if (partialUpdateConfig.optimizeComponent) {
1089    creationArgs.push(isTransition ? ts.factory.createNull() :
1090      ts.factory.createIdentifier(componentName));
1091  }
1092  return ts.factory.createExpressionStatement(
1093    ts.factory.createCallExpression(
1094      ts.factory.createPropertyAccessExpression(createConditionParent(isGlobalBuilder),
1095        ts.factory.createIdentifier(partialUpdateConfig.optimizeComponent ?
1096          OBSERVECOMPONENTCREATION2 : OBSERVECOMPONENTCREATION)
1097      ), undefined, creationArgs)
1098  );
1099}
1100
1101export function createViewStackProcessorStatement(propertyAccessName: string, elmtId?: string): ts.Statement {
1102  return ts.factory.createExpressionStatement(
1103    ts.factory.createCallExpression(
1104      ts.factory.createPropertyAccessExpression(
1105        ts.factory.createIdentifier(VIEWSTACKPROCESSOR),
1106        ts.factory.createIdentifier(propertyAccessName)
1107      ),
1108      undefined,
1109      elmtId ? [ts.factory.createIdentifier(ELMTID)] : []
1110    )
1111  );
1112}
1113
1114function createInitRenderStatement(node: ts.Statement,
1115  immutableStatements: ts.Statement[], blockArr: ts.Statement[]): void {
1116  if (partialUpdateConfig.optimizeComponent) {
1117    if (immutableStatements && immutableStatements.length) {
1118      blockArr.push(ts.factory.createIfStatement(
1119        ts.factory.createIdentifier(ISINITIALRENDER),
1120        ts.factory.createBlock(immutableStatements, true)
1121      ));
1122    }
1123  } else {
1124    blockArr.push(ts.factory.createIfStatement(
1125      ts.factory.createPrefixUnaryExpression(
1126        ts.SyntaxKind.ExclamationToken,
1127        ts.factory.createIdentifier(ISINITIALRENDER)
1128      ),
1129      ts.factory.createBlock(
1130        [
1131          ts.isExpressionStatement(node) ?
1132            createComponent(node, COMPONENT_POP_FUNCTION).newNode : createIfPop()
1133        ],
1134        true
1135      ),
1136      immutableStatements && immutableStatements.length ?
1137        ts.factory.createBlock(immutableStatements, true) : undefined
1138    ));
1139  }
1140}
1141
1142function processItemComponent(node: ts.ExpressionStatement, nameResult: NameResult, innerCompStatements: ts.Statement[],
1143  log: LogInfo[], parent: string = undefined, isGlobalBuilder: boolean = false, idName: ts.Expression = undefined,
1144  builderParamsResult: BuilderParamsResult = null): void {
1145  const itemRenderInnerStatements: ts.Statement[] = [];
1146  const immutableStatements: ts.Statement[] = [];
1147  const deepItemRenderInnerStatements: ts.Statement[] = [];
1148  if (addElmtIdNode()) {
1149    itemRenderInnerStatements.push(createCollectElmtIdNode());
1150  }
1151  const res: CreateResult = createComponent(node, COMPONENT_CREATE_FUNCTION);
1152  const isLazyCreate: boolean = checkLazyCreate(node, nameResult);
1153  const itemCreateStatement: ts.Statement = createItemCreate(nameResult, isLazyCreate);
1154  itemRenderInnerStatements.push(itemCreateStatement);
1155  const etsComponentResult: EtsComponentResult = parseEtsComponentExpression(node);
1156  if (etsComponentResult.etsComponentNode.body && ts.isBlock(etsComponentResult.etsComponentNode.body)) {
1157    if (etsComponentResult.hasAttr) {
1158      bindComponentAttr(node, res.identifierNode, itemRenderInnerStatements, log, true, false, immutableStatements);
1159    }
1160    storedFileInfo.lazyForEachInfo.isDependItem = false;
1161    processComponentChild(etsComponentResult.etsComponentNode.body, deepItemRenderInnerStatements, log,
1162      {isAcceleratePreview: false, line: 0, column: 0, fileName: ''}, false, parent, undefined, isGlobalBuilder, false,
1163      builderParamsResult);
1164  } else {
1165    bindComponentAttr(node, res.identifierNode, itemRenderInnerStatements, log, true, false, immutableStatements);
1166  }
1167  let generateItem: ts.IfStatement | ts.Block;
1168  if (idName) {
1169    generateItem = ifRetakeId([createItemBlock(
1170      node, itemRenderInnerStatements, deepItemRenderInnerStatements, nameResult, isLazyCreate,
1171      immutableStatements, isGlobalBuilder, builderParamsResult)], idName);
1172  } else {
1173    generateItem = createItemBlock(
1174      node, itemRenderInnerStatements, deepItemRenderInnerStatements, nameResult, isLazyCreate,
1175      immutableStatements, isGlobalBuilder, builderParamsResult);
1176  }
1177  innerCompStatements.push(generateItem);
1178}
1179
1180function createItemCreate(nameResult: NameResult, isLazyCreate: boolean): ts.Statement {
1181  const itemCreateArgs: ts.Expression[] = [];
1182  if (isLazyCreate) {
1183    itemCreateArgs.push(ts.factory.createIdentifier(DEEPRENDERFUNCTION), ts.factory.createTrue());
1184  } else {
1185    itemCreateArgs.push(
1186      ts.factory.createArrowFunction(undefined, undefined, [], undefined,
1187        ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
1188        ts.factory.createBlock([], false)),
1189      ts.factory.createFalse()
1190    );
1191  }
1192  itemCreateArgs.push(...nameResult.arguments);
1193  return ts.factory.createExpressionStatement(ts.factory.createCallExpression(
1194    ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(nameResult.name),
1195      ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION)), undefined, itemCreateArgs));
1196}
1197
1198type ItemCreation = {
1199  creationArgs: ts.Expression[],
1200  creationName: string,
1201};
1202
1203function getItemCreation(nameResult: NameResult): ItemCreation {
1204  const creationArgs: ts.Expression[] = [];
1205  let creationName: string = OBSERVECOMPONENTCREATION;
1206  if (partialUpdateConfig.optimizeComponent) {
1207    creationArgs.push(
1208      ts.factory.createIdentifier(ITEMCREATION2),
1209      ts.factory.createIdentifier(nameResult.name));
1210    creationName = OBSERVECOMPONENTCREATION2;
1211  } else {
1212    creationArgs.push(ts.factory.createIdentifier(ITEMCREATION));
1213  }
1214  return { creationArgs, creationName };
1215}
1216
1217function createItemBlock(
1218  node: ts.ExpressionStatement,
1219  itemRenderInnerStatements: ts.Statement[],
1220  deepItemRenderInnerStatements: ts.Statement[],
1221  nameResult: NameResult, isLazyCreate: boolean,
1222  immutableStatements: ts.Statement[],
1223  isGlobalBuilder: boolean,
1224  builderParamsResult: BuilderParamsResult
1225): ts.Block {
1226  const blockNode: ts.Statement[] = [
1227    createItemCreation2(node, itemRenderInnerStatements, nameResult, immutableStatements,
1228      isGlobalBuilder, builderParamsResult)
1229  ];
1230  const itemCreation: ItemCreation = getItemCreation(nameResult);
1231  if (isLazyCreate) {
1232    blockNode.unshift(createItemCreation(node, isGlobalBuilder, builderParamsResult));
1233    blockNode.push(
1234      createDeepRenderFunction(node, deepItemRenderInnerStatements, isGlobalBuilder, builderParamsResult),
1235      ts.factory.createExpressionStatement(ts.factory.createCallExpression(
1236        ts.factory.createPropertyAccessExpression(
1237          ts.factory.createThis(),
1238          ts.factory.createIdentifier(itemCreation.creationName)
1239        ), undefined, itemCreation.creationArgs
1240      )),
1241      createComponent(node, COMPONENT_POP_FUNCTION).newNode
1242    );
1243  } else {
1244    if (!partialUpdateConfig.optimizeComponent) {
1245      blockNode.unshift(createItemCreation(node, isGlobalBuilder, builderParamsResult));
1246    }
1247    blockNode.push(
1248      createObservedDeepRender(node, deepItemRenderInnerStatements, itemCreation),
1249      ts.factory.createExpressionStatement(ts.factory.createCallExpression(
1250        ts.factory.createIdentifier(OBSERVEDDEEPRENDER), undefined, []))
1251    );
1252  }
1253  return ts.factory.createBlock(blockNode, true);
1254}
1255
1256function checkLazyCreate(node: ts.ExpressionStatement, nameResult: NameResult): boolean {
1257  if (nameResult.name === LIST_ITEM) {
1258    if (nameResult.arguments.length && ts.isStringLiteral(nameResult.arguments[0]) &&
1259      nameResult.arguments[0].text === 'false') {
1260      return false;
1261    }
1262    if (storedFileInfo.processRepeat) {
1263      return false;
1264    }
1265    if (isLazyForEachChild(node)) {
1266      return false;
1267    }
1268    return true;
1269  }
1270  return false;
1271}
1272
1273function createItemCreation(node: ts.ExpressionStatement, isGlobalBuilder: boolean,
1274  builderParamsResult: BuilderParamsResult): ts.VariableStatement {
1275  return ts.factory.createVariableStatement(
1276    undefined,
1277    ts.factory.createVariableDeclarationList(
1278      [ts.factory.createVariableDeclaration(
1279        ts.factory.createIdentifier(ITEMCREATION), undefined, undefined,
1280        ts.factory.createArrowFunction(undefined, undefined,
1281          createComponentCreationArrowParams(isGlobalBuilder, builderParamsResult), undefined,
1282          ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
1283          ts.factory.createBlock(
1284            [
1285              createViewStackProcessorStatement(STARTGETACCESSRECORDINGFOR, ELMTID),
1286              ts.factory.createExpressionStatement(ts.factory.createCallExpression(
1287                ts.factory.createIdentifier(ITEMCREATION2),
1288                undefined, createItemCreationArgs(isGlobalBuilder, builderParamsResult)
1289              )),
1290              ts.factory.createIfStatement(
1291                ts.factory.createPrefixUnaryExpression(
1292                  ts.SyntaxKind.ExclamationToken,
1293                  ts.factory.createIdentifier(ISINITIALRENDER)
1294                ),
1295                ts.factory.createBlock(
1296                  [createComponent(node, COMPONENT_POP_FUNCTION).newNode],
1297                  true
1298                )
1299              ),
1300              createViewStackProcessorStatement(STOPGETACCESSRECORDING)
1301            ],
1302            true
1303          )
1304        )
1305      )],
1306      ts.NodeFlags.Const
1307    )
1308  );
1309}
1310
1311function createItemCreation2(
1312  node: ts.ExpressionStatement,
1313  itemRenderInnerStatements: ts.Statement[],
1314  nameResult: NameResult,
1315  immutableStatements: ts.Statement[],
1316  isGlobalBuilder: boolean,
1317  builderParamsResult: BuilderParamsResult
1318): ts.VariableStatement {
1319  const itemBlock: ts.Statement[] = [
1320    ...itemRenderInnerStatements,
1321    processDebug(node, nameResult, itemRenderInnerStatements, true)
1322  ];
1323  if (immutableStatements && immutableStatements.length) {
1324    itemBlock.push(ts.factory.createIfStatement(
1325      ts.factory.createIdentifier(ISINITIALRENDER),
1326      ts.factory.createBlock(immutableStatements, true)
1327    ));
1328  }
1329  return ts.factory.createVariableStatement(
1330    undefined,
1331    ts.factory.createVariableDeclarationList(
1332      [ts.factory.createVariableDeclaration(
1333        ts.factory.createIdentifier(ITEMCREATION2), undefined, undefined,
1334        ts.factory.createArrowFunction(undefined, undefined,
1335          createComponentCreationArrowParams(isGlobalBuilder, builderParamsResult), undefined,
1336          ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
1337          ts.factory.createBlock(itemBlock, true)
1338        )
1339      )],
1340      ts.NodeFlags.Const
1341    )
1342  );
1343}
1344
1345function createItemCreationArgs(isGlobalBuilder: boolean,
1346  builderParamsResult: BuilderParamsResult): ts.Expression[] {
1347  const itemCreationArgs: ts.Expression[] = [
1348    ts.factory.createIdentifier(ELMTID), ts.factory.createIdentifier(ISINITIALRENDER)];
1349  if (partialUpdateConfig.optimizeComponent && isGlobalBuilder && builderParamsResult &&
1350    builderParamsResult.firstParam) {
1351    itemCreationArgs.push(builderParamsResult.firstParam.name as ts.Identifier);
1352  }
1353  return itemCreationArgs;
1354}
1355
1356function createDeepRenderFunction(
1357  node: ts.ExpressionStatement,
1358  deepItemRenderInnerStatements: ts.Statement[],
1359  isGlobalBuilder: boolean,
1360  builderParamsResult: BuilderParamsResult
1361): ts.VariableStatement {
1362  const blockNode: ts.Statement[] = [
1363    ts.factory.createExpressionStatement(ts.factory.createCallExpression(
1364      ts.factory.createIdentifier(ITEMCREATION), undefined,
1365      createItemCreationArgs(isGlobalBuilder, builderParamsResult)
1366    )),
1367    ts.factory.createExpressionStatement(ts.factory.createCallExpression(
1368      ts.factory.createPropertyAccessExpression(
1369        ts.factory.createPropertyAccessExpression(
1370          ts.factory.createThis(),
1371          ts.factory.createIdentifier(UPDATE_FUNC_BY_ELMT_ID)
1372        ),
1373        ts.factory.createIdentifier(CREATE_SET_METHOD)
1374      ), undefined,
1375      [ts.factory.createIdentifier(ELMTID), ts.factory.createIdentifier(ITEMCREATION)]
1376    )),
1377    ...deepItemRenderInnerStatements,
1378    createComponent(node, COMPONENT_POP_FUNCTION).newNode
1379  ];
1380  if (partialUpdateConfig.optimizeComponent) {
1381    blockNode.splice(1, 1);
1382  }
1383  return ts.factory.createVariableStatement(
1384    undefined,
1385    ts.factory.createVariableDeclarationList(
1386      [ts.factory.createVariableDeclaration(
1387        ts.factory.createIdentifier(DEEPRENDERFUNCTION), undefined, undefined,
1388        ts.factory.createArrowFunction(undefined, undefined,
1389          createComponentCreationArrowParams(isGlobalBuilder, builderParamsResult), undefined,
1390          ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
1391          ts.factory.createBlock(blockNode, true)
1392        )
1393      )],
1394      ts.NodeFlags.Const
1395    )
1396  );
1397}
1398
1399function createObservedDeepRender(
1400  node: ts.ExpressionStatement,
1401  deepItemRenderInnerStatements: ts.Statement[],
1402  itemCreation: ItemCreation
1403): ts.VariableStatement {
1404  return ts.factory.createVariableStatement(
1405    undefined,
1406    ts.factory.createVariableDeclarationList(
1407      [ts.factory.createVariableDeclaration(
1408        ts.factory.createIdentifier(OBSERVEDDEEPRENDER),
1409        undefined,
1410        undefined,
1411        ts.factory.createArrowFunction(
1412          undefined,
1413          undefined,
1414          [],
1415          undefined,
1416          ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
1417          ts.factory.createBlock(
1418            [
1419              ts.factory.createExpressionStatement(ts.factory.createCallExpression(
1420                ts.factory.createPropertyAccessExpression(
1421                  ts.factory.createThis(),
1422                  ts.factory.createIdentifier(itemCreation.creationName)
1423                ), undefined, itemCreation.creationArgs
1424              )),
1425              ...deepItemRenderInnerStatements,
1426              createComponent(node, COMPONENT_POP_FUNCTION).newNode
1427            ],
1428            true
1429          )
1430        )
1431      )],
1432      ts.NodeFlags.Const
1433    )
1434  );
1435}
1436
1437function processTabAndNav(node: ts.ExpressionStatement, innerCompStatements: ts.Statement[],
1438  nameResult: NameResult, log: LogInfo[], parent: string = undefined, isGlobalBuilder: boolean = false,
1439  idName: ts.Expression = undefined, builderParamsResult: BuilderParamsResult = null): void {
1440  const name: string = nameResult.name;
1441  const tabContentComp: ts.EtsComponentExpression = getEtsComponentExpression(node);
1442  const tabContentBody: ts.Block = tabContentComp.body;
1443  let tabContentCreation: ts.Statement;
1444  const tabContentPop: ts.Statement = ts.factory.createExpressionStatement(ts.factory.createCallExpression(
1445    ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(name),
1446      ts.factory.createIdentifier(COMPONENT_POP_FUNCTION)), undefined, []));
1447  const tabAttrs: ts.Statement[] = [];
1448  if (addElmtIdNode()) {
1449    tabAttrs.push(createCollectElmtIdNode());
1450  }
1451  const immutableStatements: ts.Statement[] = [];
1452  let judgeIdStart: number;
1453  if (idName) {
1454    judgeIdStart = innerCompStatements.length;
1455  }
1456  if (tabContentBody && tabContentBody.statements.length) {
1457    const newTabContentChildren: ts.Statement[] = [];
1458    processComponentChild(tabContentBody, newTabContentChildren, log, {isAcceleratePreview: false, line: 0, column: 0, fileName: ''},
1459      false, parent, undefined, isGlobalBuilder, false, builderParamsResult);
1460    const navDestinationCallback: (ts.ArrowFunction | ts.NewExpression | ts.ObjectLiteralExpression)[] =
1461      [ts.factory.createArrowFunction(undefined, undefined, [], undefined,
1462      ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
1463      ts.factory.createBlock([...newTabContentChildren], true))];
1464    if (name === NAV_DESTINATION) {
1465      navDestinationCallback.push(...navigationCreateParam(NAV_DESTINATION, COMPONENT_CREATE_FUNCTION, undefined, true));
1466    }
1467    tabContentCreation = ts.factory.createExpressionStatement(
1468      ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(
1469        ts.factory.createIdentifier(name), ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION)),
1470      undefined, navDestinationCallback));
1471    bindComponentAttr(node, ts.factory.createIdentifier(name), tabAttrs, log, true, false, immutableStatements);
1472    processInnerCompStatements(
1473      innerCompStatements, [tabContentCreation, ...tabAttrs], node, isGlobalBuilder, false,
1474      nameResult, immutableStatements, name, builderParamsResult);
1475    storedFileInfo.lazyForEachInfo.isDependItem = false;
1476  } else {
1477    tabContentCreation = ts.factory.createExpressionStatement(ts.factory.createCallExpression(
1478      ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(name),
1479        ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION)), undefined,
1480        name === NAV_DESTINATION ? navigationCreateParam(NAV_DESTINATION, COMPONENT_CREATE_FUNCTION) : []));
1481    bindComponentAttr(node, ts.factory.createIdentifier(name), tabAttrs, log, true, false, immutableStatements);
1482    processInnerCompStatements(
1483      innerCompStatements, [tabContentCreation, ...tabAttrs], node, isGlobalBuilder, false,
1484      nameResult, immutableStatements, name, builderParamsResult);
1485  }
1486  innerCompStatements.push(tabContentPop);
1487  if (idName) {
1488    innerCompStatements.splice(judgeIdStart, innerCompStatements.length - judgeIdStart,
1489      ifRetakeId(innerCompStatements.slice(judgeIdStart), idName));
1490  }
1491}
1492
1493export function getRealNodePos(node: ts.Node): number {
1494  // @ts-ignore
1495  if (node.pos === -1 && node.expression) {
1496    // @ts-ignore
1497    return getRealNodePos(node.expression);
1498  } else {
1499    return node.getStart();
1500  }
1501}
1502
1503function processForEachComponent(node: ts.ExpressionStatement, newStatements: ts.Statement[],
1504  log: LogInfo[], isBuilder: boolean = false, isGlobalBuilder: boolean = false): void {
1505  const popNode: ts.ExpressionStatement = ts.factory.createExpressionStatement(createFunction(
1506    // @ts-ignore
1507    node.expression.expression as ts.Identifier,
1508    ts.factory.createIdentifier(COMPONENT_POP_FUNCTION), null));
1509  if (ts.isCallExpression(node.expression)) {
1510    const propertyNode: ts.PropertyAccessExpression = ts.factory.createPropertyAccessExpression(
1511      node.expression.expression as ts.Identifier,
1512      ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION)
1513    );
1514    const argumentsArray: ts.Expression[] = Array.from(node.expression.arguments);
1515    let arrayObserveredObject: ts.CallExpression;
1516    if (argumentsArray.length) {
1517      arrayObserveredObject = ts.factory.createCallExpression(
1518        ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(FOREACH_OBSERVED_OBJECT),
1519          ts.factory.createIdentifier(FOREACH_GET_RAW_OBJECT)), undefined, [argumentsArray[0]]);
1520    }
1521    argumentsArray.splice(0, 1, arrayObserveredObject);
1522    const newForEachArrowFunc: ts.ArrowFunction = processForEachFunctionBlock(node.expression);
1523    const newArrowNode: ts.ArrowFunction =
1524      processForEachBlock(node.expression, log, newForEachArrowFunc, isBuilder) as ts.ArrowFunction;
1525    if (newArrowNode) {
1526      argumentsArray.splice(1, 1, newArrowNode);
1527    }
1528    node = addForEachId(ts.factory.updateExpressionStatement(node, ts.factory.updateCallExpression(
1529      node.expression, propertyNode, node.expression.typeArguments, argumentsArray)), isGlobalBuilder);
1530  }
1531  newStatements.push(node, popNode);
1532}
1533
1534function collectForEachAttribute(node: ts.ExpressionStatement,
1535  attributeList: ts.ExpressionStatement[], name: string): ts.ExpressionStatement {
1536  let tempNode = node.expression;
1537  while (tempNode && ts.isCallExpression(tempNode)) {
1538    if (tempNode.expression && ts.isPropertyAccessExpression(tempNode.expression)) {
1539      attributeList.unshift(generateForEachAttribute(tempNode, name));
1540    } else if (tempNode.expression && ts.isIdentifier(tempNode.expression)) {
1541      return ts.factory.updateExpressionStatement(node, tempNode);
1542    }
1543    tempNode = tempNode.expression?.expression;
1544  }
1545  return node;
1546}
1547
1548function generateForEachAttribute(tempNode: ts.CallExpression, name: string): ts.ExpressionStatement {
1549  return ts.factory.createExpressionStatement(ts.factory.createCallExpression(
1550    ts.factory.createPropertyAccessExpression(
1551      ts.factory.createIdentifier(name),
1552      tempNode.expression.name
1553    ),
1554    undefined,
1555    tempNode.arguments
1556  ));
1557}
1558
1559function processForEachComponentNew(node: ts.ExpressionStatement, newStatements: ts.Statement[],
1560  log: LogInfo[], name: string, isGlobalBuilder: boolean = false, builderParamsResult: BuilderParamsResult = null): void {
1561  const attributeList: ts.ExpressionStatement[] = [];
1562  const newNode = collectForEachAttribute(node, attributeList, name);
1563  const newForEachStatements: ts.Statement[] = [];
1564  const popNode: ts.ExpressionStatement = ts.factory.createExpressionStatement(createFunction(
1565    (newNode.expression as ts.CallExpression).expression as ts.Identifier,
1566    ts.factory.createIdentifier(COMPONENT_POP_FUNCTION), null));
1567  if (ts.isCallExpression(newNode.expression)) {
1568    if (checkForEachComponent(newNode)) {
1569      storedFileInfo.processForEach += 1;
1570    } else {
1571      storedFileInfo.processLazyForEach += 1;
1572    }
1573    const argumentsArray: ts.Expression[] = Array.from(newNode.expression.arguments);
1574    const propertyNode: ts.ExpressionStatement = ts.factory.createExpressionStatement(
1575      ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(
1576        newNode.expression.expression as ts.Identifier,
1577        ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION)), undefined, []));
1578    const newForEachArrowFunc: ts.ArrowFunction = processForEachFunctionBlock(newNode.expression);
1579    const newArrowNode: ts.NodeArray<ts.Statement> =
1580      processForEachBlock(newNode.expression, log, newForEachArrowFunc, false, isGlobalBuilder,
1581        builderParamsResult) as ts.NodeArray<ts.Statement>;
1582    const itemGenFunctionStatement: ts.VariableStatement = createItemGenFunctionStatement(newNode.expression, newArrowNode, newForEachArrowFunc);
1583    const itemIdFuncStatement: ts.VariableStatement = createItemIdFuncStatement(newNode.expression, argumentsArray);
1584    const updateFunctionStatement: ts.ExpressionStatement = createUpdateFunctionStatement(argumentsArray, newForEachArrowFunc, isGlobalBuilder);
1585    const lazyForEachStatement: ts.ExpressionStatement = createLazyForEachStatement(argumentsArray);
1586    if (newNode.expression.expression.getText() === COMPONENT_FOREACH) {
1587      newForEachStatements.push(propertyNode, ...attributeList, itemGenFunctionStatement, updateFunctionStatement);
1588      newStatements.push(createComponentCreationStatement(newNode, newForEachStatements, COMPONENT_FOREACH,
1589        isGlobalBuilder, false, undefined, null, builderParamsResult), popNode);
1590    } else {
1591      if (argumentsArray[2]) {
1592        newStatements.push(ts.factory.createBlock([itemGenFunctionStatement, itemIdFuncStatement, lazyForEachStatement,
1593          ...attributeList, popNode], true));
1594      } else {
1595        newStatements.push(ts.factory.createBlock([itemGenFunctionStatement, lazyForEachStatement, popNode, ...attributeList], true));
1596      }
1597    }
1598    if (checkForEachComponent(newNode)) {
1599      storedFileInfo.processForEach -= 1;
1600    } else {
1601      storedFileInfo.processLazyForEach -= 1;
1602    }
1603  }
1604}
1605
1606function checkForEachComponent(node: ts.ExpressionStatement): boolean {
1607  return node.expression.expression && ts.isIdentifier(node.expression.expression) &&
1608    node.expression.expression.getText() === COMPONENT_FOREACH;
1609}
1610
1611function createItemGenFunctionStatement(
1612  node: ts.CallExpression,
1613  newArrowNode: ts.NodeArray<ts.Statement>,
1614  newForEachArrowFunc: ts.ArrowFunction
1615): ts.VariableStatement {
1616  if (newForEachArrowFunc && ts.isArrowFunction(newForEachArrowFunc)) {
1617    return ts.factory.createVariableStatement(
1618      undefined,
1619      ts.factory.createVariableDeclarationList(
1620        [ts.factory.createVariableDeclaration(
1621          ts.factory.createIdentifier(node.expression.getText() === COMPONENT_FOREACH ?
1622            FOREACHITEMGENFUNCTION : __LAZYFOREACHITEMGENFUNCTION),
1623          undefined, undefined,
1624          ts.factory.createArrowFunction(
1625            undefined, undefined,
1626            newForEachArrowFunc.parameters && newForEachArrowFunc.parameters.length >= 1 ?
1627              getParameters(newForEachArrowFunc) : [],
1628            undefined, ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
1629            ts.factory.createBlock(
1630              newForEachArrowFunc.parameters && newForEachArrowFunc.parameters.length >= 1 ?
1631                isForEachItemGeneratorParam(newForEachArrowFunc, newArrowNode) :
1632                newArrowNode ? [...newArrowNode] : undefined,
1633              true
1634            )
1635          )
1636        )
1637        ],
1638        ts.NodeFlags.Const
1639      )
1640    );
1641  }
1642  return undefined;
1643}
1644
1645function isForEachItemGeneratorParam(argumentsArray: ts.Expression, newArrowNode: ts.NodeArray<ts.Statement>): ts.Statement[] {
1646  const createVariableStatementNode: ts.Statement[] = [];
1647  createVariableStatementNode.push(ts.factory.createVariableStatement(
1648    undefined,
1649    ts.factory.createVariableDeclarationList(
1650      [ts.factory.createVariableDeclaration(
1651        ts.factory.createIdentifier(
1652          argumentsArray.parameters[0] && argumentsArray.parameters[0].name.getText()),
1653        undefined,
1654        undefined,
1655        ts.factory.createIdentifier(_ITEM)
1656      )],
1657      ts.NodeFlags.Const
1658    )
1659  ));
1660  if (newArrowNode) {
1661    createVariableStatementNode.push(...newArrowNode);
1662  }
1663  return createVariableStatementNode;
1664}
1665
1666function getParameters(node: ts.ArrowFunction): ts.ParameterDeclaration[] {
1667  const parameterArr: ts.ParameterDeclaration[] = [
1668    ts.factory.createParameterDeclaration(
1669      undefined, undefined, ts.factory.createIdentifier(_ITEM))
1670  ];
1671  if (node.parameters && node.parameters.length > 1) {
1672    parameterArr.push(node.parameters[1]);
1673  }
1674  if (projectConfig.optLazyForEach && storedFileInfo.processLazyForEach) {
1675    if (node.parameters.length === 1) {
1676      parameterArr.push(ts.factory.createParameterDeclaration(
1677        undefined, undefined, ts.factory.createIdentifier(INDEX)));
1678    }
1679    parameterArr.push(
1680      ts.factory.createParameterDeclaration(
1681        undefined, undefined, ts.factory.createIdentifier(IS_INITIAL_ITEM)),
1682      ts.factory.createParameterDeclaration(
1683        undefined, undefined, ts.factory.createIdentifier(IDS))
1684    );
1685  }
1686  return parameterArr;
1687}
1688
1689function createItemIdFuncStatement(
1690  node: ts.CallExpression,
1691  argumentsArray: ts.Expression[]
1692): ts.VariableStatement {
1693  if (argumentsArray[2]) {
1694    return ts.factory.createVariableStatement(
1695      undefined,
1696      ts.factory.createVariableDeclarationList(
1697        [ts.factory.createVariableDeclaration(
1698          ts.factory.createIdentifier(node.expression.getText() === COMPONENT_FOREACH ?
1699            FOREACHITEMIDFUNC : __LAZYFOREACHITEMIDFUNC), undefined, undefined,
1700          argumentsArray[2]
1701        )],
1702        ts.NodeFlags.Const
1703      )
1704    );
1705  }
1706  return undefined;
1707}
1708
1709function createUpdateFunctionStatement(argumentsArray: ts.Expression[],
1710  newForEachArrowFunc: ts.ArrowFunction, isGlobalBuilder: boolean = false): ts.ExpressionStatement {
1711  return ts.factory.createExpressionStatement(
1712    ts.factory.createCallExpression(
1713      ts.factory.createPropertyAccessExpression(
1714        isGlobalBuilder ? parentConditionalExpression() : ts.factory.createThis(),
1715        ts.factory.createIdentifier(FOREACHUPDATEFUNCTION)
1716      ),
1717      undefined,
1718      addForEachIdFuncParameter(argumentsArray, newForEachArrowFunc)
1719    )
1720  );
1721}
1722
1723function addForEachIdFuncParameter(argumentsArray: ts.Expression[], newForEachArrowFunc: ts.ArrowFunction): ts.Expression[] {
1724  const addForEachIdFuncParameterArr: ts.Expression[] = [];
1725  addForEachIdFuncParameterArr.push(
1726    ts.factory.createIdentifier(ELMTID),
1727    argumentsArray[0],
1728    ts.factory.createIdentifier(FOREACHITEMGENFUNCTION)
1729  );
1730  // @ts-ignore
1731  if (newForEachArrowFunc && newForEachArrowFunc.parameters && newForEachArrowFunc.parameters[1]) {
1732    if (!argumentsArray[2]) {
1733      addForEachIdFuncParameterArr.push(...addForEachParameter(ts.factory.createIdentifier(COMPONENT_IF_UNDEFINED), TRUE, FALSE));
1734    } else {
1735      // @ts-ignore
1736      argumentsArray[2].parameters && argumentsArray[2].parameters[1] ?
1737        addForEachIdFuncParameterArr.push(...addForEachParameter(argumentsArray[2], TRUE, TRUE)) :
1738        addForEachIdFuncParameterArr.push(...addForEachParameter(argumentsArray[2], TRUE, FALSE));
1739    }
1740  }
1741  // @ts-ignore
1742  if (newForEachArrowFunc && newForEachArrowFunc.parameters && newForEachArrowFunc.parameters.length < 2 && newForEachArrowFunc.parameters[0] &&
1743    argumentsArray && argumentsArray.length > 2 && argumentsArray[2]) {
1744    // @ts-ignore
1745    argumentsArray[2].parameters && argumentsArray[2].parameters[1] ?
1746      addForEachIdFuncParameterArr.push(...addForEachParameter(argumentsArray[2], FALSE, TRUE)) :
1747      addForEachIdFuncParameterArr.push(...addForEachParameter(argumentsArray[2], FALSE, FALSE));
1748  }
1749  return addForEachIdFuncParameterArr;
1750}
1751
1752function addForEachParameter(forEachItemIdContent: ts.Expression, forEachItemGen: string, forEachItemId: string): ts.Expression[] {
1753  return [forEachItemIdContent, ts.factory.createIdentifier(forEachItemGen),
1754    ts.factory.createIdentifier(forEachItemId)];
1755}
1756
1757function createLazyForEachStatement(argumentsArray: ts.Expression[]): ts.ExpressionStatement {
1758  const parameterList: ts.Expression[] = [
1759    ts.factory.createStringLiteral(componentInfo.id.toString()),
1760    ts.factory.createThis(),
1761    argumentsArray[0],
1762    ts.factory.createIdentifier(__LAZYFOREACHITEMGENFUNCTION)
1763  ];
1764  if (argumentsArray.length >= 3 && argumentsArray[2]) {
1765    parameterList.push(ts.factory.createIdentifier(__LAZYFOREACHITEMIDFUNC));
1766  }
1767  if (projectConfig.optLazyForEach) {
1768    parameterList.push(ts.factory.createTrue());
1769  }
1770  return ts.factory.createExpressionStatement(
1771    ts.factory.createCallExpression(
1772      ts.factory.createPropertyAccessExpression(
1773        ts.factory.createIdentifier(COMPONENT_LAZYFOREACH),
1774        ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION)
1775      ),
1776      undefined,
1777      parameterList
1778    )
1779  );
1780}
1781
1782function addForEachId(node: ts.ExpressionStatement, isGlobalBuilder: boolean = false): ts.ExpressionStatement {
1783  const forEachComponent: ts.CallExpression = node.expression as ts.CallExpression;
1784  return ts.factory.updateExpressionStatement(node, ts.factory.updateCallExpression(
1785    forEachComponent, forEachComponent.expression, forEachComponent.typeArguments,
1786    [ts.factory.createStringLiteral((++componentInfo.id).toString()),
1787      isGlobalBuilder ? parentConditionalExpression() : ts.factory.createThis(),
1788      ...forEachComponent.arguments]));
1789}
1790
1791export function parentConditionalExpression(): ts.ConditionalExpression {
1792  return ts.factory.createConditionalExpression(
1793    ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARENT),
1794    ts.factory.createToken(ts.SyntaxKind.QuestionToken),
1795    ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARENT),
1796    ts.factory.createToken(ts.SyntaxKind.ColonToken),
1797    ts.factory.createThis());
1798}
1799function processForEachFunctionBlock(node: ts.CallExpression): ts.ArrowFunction {
1800  if (ts.isArrowFunction(node.arguments[1])) {
1801    return node.arguments[1];
1802  } else if (ts.isParenthesizedExpression(node.arguments[1]) && ts.isArrowFunction(node.arguments[1].expression)) {
1803    return node.arguments[1].expression;
1804  } else {
1805    return null;
1806  }
1807}
1808function processForEachBlock(node: ts.CallExpression, log: LogInfo[],
1809  arrowNode: ts.ArrowFunction, isBuilder: boolean = false, isGlobalBuilder: boolean = false,
1810  builderParamsResult: BuilderParamsResult = null): ts.NodeArray<ts.Statement> | ts.ArrowFunction {
1811  if (node.arguments.length > 1 && ts.isArrowFunction(arrowNode)) {
1812    const isLazy: boolean = node.expression.getText() === COMPONENT_LAZYFOREACH;
1813    const body: ts.ConciseBody = arrowNode.body;
1814    if (!ts.isBlock(body)) {
1815      const statement: ts.Statement = ts.factory.createExpressionStatement(body);
1816      const blockNode: ts.Block = ts.factory.createBlock([statement], true);
1817      // @ts-ignore
1818      statement.parent = blockNode;
1819      if (!partialUpdateConfig.partialUpdateMode) {
1820        return ts.factory.updateArrowFunction(
1821          arrowNode, ts.getModifiers(arrowNode), arrowNode.typeParameters, arrowNode.parameters,
1822          arrowNode.type, arrowNode.equalsGreaterThanToken,
1823          processComponentBlock(blockNode, isLazy, log, false, false, undefined,
1824            arrowNode.parameters, isGlobalBuilder));
1825      } else {
1826        return processComponentBlock(blockNode, isLazy, log, false, false, undefined,
1827          arrowNode.parameters, isGlobalBuilder, builderParamsResult).statements;
1828      }
1829    } else {
1830      if (!partialUpdateConfig.partialUpdateMode) {
1831        return ts.factory.updateArrowFunction(
1832          arrowNode, ts.getModifiers(arrowNode), arrowNode.typeParameters, arrowNode.parameters,
1833          arrowNode.type, arrowNode.equalsGreaterThanToken,
1834          processComponentBlock(body, isLazy, log, false, isBuilder, undefined, arrowNode.parameters));
1835      } else {
1836        return processComponentBlock(body, isLazy, log, false, false, undefined, arrowNode.parameters,
1837          isGlobalBuilder, builderParamsResult).statements;
1838      }
1839    }
1840  }
1841  return null;
1842}
1843
1844function createRenderingInProgress(isTrue: boolean): ts.ExpressionStatement {
1845  return ts.factory.createExpressionStatement(ts.factory.createBinaryExpression(
1846    ts.factory.createPropertyAccessExpression(
1847      ts.factory.createThis(),
1848      ts.factory.createIdentifier(IS_RENDERING_IN_PROGRESS)
1849    ),
1850    ts.factory.createToken(ts.SyntaxKind.EqualsToken),
1851    isTrue ? ts.factory.createTrue() : ts.factory.createFalse()
1852  ));
1853}
1854
1855function addElmtIdNode(): boolean {
1856  return partialUpdateConfig.partialUpdateMode && projectConfig.optLazyForEach &&
1857    ((storedFileInfo.processLazyForEach && storedFileInfo.lazyForEachInfo.isDependItem) || storedFileInfo.processBuilder);
1858}
1859
1860function processIfStatement(node: ts.IfStatement, newStatements: ts.Statement[],
1861  log: LogInfo[], isBuilder: boolean = false, isGlobalBuilder: boolean = false,
1862  builderParamsResult: BuilderParamsResult = null): void {
1863  const ifStatements: ts.Statement[] = [];
1864  if (addElmtIdNode()) {
1865    ifStatements.push(createCollectElmtIdNode());
1866    storedFileInfo.lazyForEachInfo.isDependItem = false;
1867  }
1868  const ifCreate: ts.ExpressionStatement = createIfCreate();
1869  const newIfNode: ts.IfStatement = processInnerIfStatement(node, 0, log, isBuilder, isGlobalBuilder, builderParamsResult);
1870  ifStatements.push(ifCreate, newIfNode);
1871  const ifPop: ts.ExpressionStatement = createIfPop();
1872  if (!partialUpdateConfig.partialUpdateMode) {
1873    newStatements.push(ifCreate, newIfNode, ifPop);
1874  } else {
1875    newStatements.push(createComponentCreationStatement(node, ifStatements, COMPONENT_IF,
1876      isGlobalBuilder, false, undefined, null, builderParamsResult), ifPop);
1877  }
1878}
1879
1880function processInnerIfStatement(node: ts.IfStatement, id: number, log: LogInfo[],
1881  isBuilder: boolean = false, isGlobalBuilder: boolean = false,
1882  builderParamsResult: BuilderParamsResult = null): ts.IfStatement {
1883  if (ts.isIdentifier(node.expression) && node.expression.originalKeywordKind === undefined &&
1884    !node.expression.escapedText) {
1885    log.push({
1886      type: LogType.ERROR,
1887      message: 'Condition expression cannot be null in if statement.',
1888      pos: node.expression.getStart()
1889    });
1890    node = ts.factory.updateIfStatement(node, ts.factory.createIdentifier(COMPONENT_IF_UNDEFINED),
1891      node.thenStatement, node.elseStatement);
1892  }
1893  const newThenStatement: ts.Statement = processThenStatement(node.thenStatement, id, log, isBuilder, isGlobalBuilder, builderParamsResult);
1894  const newElseStatement: ts.Statement = processElseStatement(node.elseStatement, id, log, isBuilder, isGlobalBuilder, builderParamsResult);
1895  const newIfNode: ts.IfStatement = ts.factory.updateIfStatement(
1896    node, node.expression, newThenStatement, newElseStatement);
1897  return newIfNode;
1898}
1899
1900function processThenStatement(thenStatement: ts.Statement, id: number,
1901  log: LogInfo[], isBuilder: boolean = false, isGlobalBuilder: boolean = false,
1902  builderParamsResult: BuilderParamsResult = null): ts.Statement {
1903  if (ts.isExpressionStatement(thenStatement) && ts.isIdentifier(thenStatement.expression) &&
1904    thenStatement.expression.originalKeywordKind === undefined &&
1905    !thenStatement.expression.escapedText) {
1906    log.push({
1907      type: LogType.ERROR,
1908      message: 'Then statement cannot be null in if statement.',
1909      pos: thenStatement.expression.getStart()
1910    });
1911  }
1912  if (thenStatement) {
1913    if (ts.isBlock(thenStatement)) {
1914      thenStatement = processIfBlock(thenStatement, id, log, isBuilder, isGlobalBuilder, builderParamsResult);
1915    } else if (ts.isIfStatement(thenStatement)) {
1916      thenStatement = processInnerIfStatement(thenStatement, 0, log, isBuilder, isGlobalBuilder, builderParamsResult);
1917      thenStatement = ts.factory.createBlock(
1918        partialUpdateConfig.partialUpdateMode ?
1919          [createIfCreate(), createIfBranchFunc(id, [thenStatement], isGlobalBuilder), createIfPop()] :
1920          [createIfCreate(), createIfBranchId(id), thenStatement, createIfPop()],
1921        true
1922      );
1923    } else {
1924      thenStatement = ts.factory.createBlock([thenStatement], true);
1925      thenStatement = processIfBlock(thenStatement as ts.Block, id, log, isBuilder, isGlobalBuilder, builderParamsResult);
1926    }
1927  }
1928  return thenStatement;
1929}
1930
1931function processElseStatement(elseStatement: ts.Statement, id: number,
1932  log: LogInfo[], isBuilder: boolean = false, isGlobalBuilder: boolean = false,
1933  builderParamsResult: BuilderParamsResult = null): ts.Statement {
1934  if (elseStatement) {
1935    if (ts.isBlock(elseStatement)) {
1936      elseStatement = processIfBlock(elseStatement, id + 1, log, isBuilder, isGlobalBuilder, builderParamsResult);
1937    } else if (ts.isIfStatement(elseStatement)) {
1938      elseStatement = processInnerIfStatement(elseStatement, id + 1, log, isBuilder, isGlobalBuilder, builderParamsResult);
1939    } else {
1940      elseStatement = ts.factory.createBlock([elseStatement], true);
1941      elseStatement = processIfBlock(elseStatement as ts.Block, id + 1, log, isBuilder, isGlobalBuilder, builderParamsResult);
1942    }
1943  } else if (partialUpdateConfig.partialUpdateMode) {
1944    elseStatement = ts.factory.createBlock([
1945      ts.factory.createExpressionStatement(ts.factory.createCallExpression(
1946        ts.factory.createPropertyAccessExpression(
1947          ts.factory.createThis(),
1948          ts.factory.createIdentifier(IFELSEBRANCHUPDATEFUNCTION)
1949        ),
1950        undefined,
1951        [
1952          ts.factory.createNumericLiteral(++id),
1953          ts.factory.createArrowFunction(
1954            undefined,
1955            undefined,
1956            [],
1957            undefined,
1958            ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
1959            ts.factory.createBlock(
1960              [],
1961              true
1962            )
1963          )
1964        ]
1965      ))
1966    ], true);
1967  }
1968  return elseStatement;
1969}
1970
1971function processIfBlock(block: ts.Block, id: number, log: LogInfo[], isBuilder: boolean = false,
1972  isGlobalBuilder: boolean = false, builderParamsResult: BuilderParamsResult = null): ts.Block {
1973  return addIfBranchId(id, isGlobalBuilder,
1974    processComponentBlock(block, false, log, false, isBuilder, COMPONENT_IF, undefined, isGlobalBuilder, builderParamsResult));
1975}
1976
1977function addIfBranchId(id: number, isGlobalBuilder: boolean = false, container: ts.Block): ts.Block {
1978  let containerStatements: ts.Statement[];
1979  if (partialUpdateConfig.partialUpdateMode) {
1980    containerStatements = [createIfBranchFunc(id, [...container.statements], isGlobalBuilder)];
1981  } else {
1982    containerStatements = [createIfBranchId(id), ...container.statements];
1983  }
1984  return ts.factory.updateBlock(container, containerStatements);
1985}
1986
1987function createIf(): ts.Identifier {
1988  return ts.factory.createIdentifier(COMPONENT_IF);
1989}
1990
1991function createIfCreate(): ts.ExpressionStatement {
1992  return ts.factory.createExpressionStatement(createFunction(createIf(),
1993    ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION), ts.factory.createNodeArray([])));
1994}
1995
1996function createIfPop(): ts.ExpressionStatement {
1997  return ts.factory.createExpressionStatement(createFunction(createIf(),
1998    ts.factory.createIdentifier(COMPONENT_POP_FUNCTION), null));
1999}
2000
2001function createIfBranchId(id: number): ts.ExpressionStatement {
2002  return ts.factory.createExpressionStatement(createFunction(createIf(),
2003    ts.factory.createIdentifier(COMPONENT_IF_BRANCH_ID_FUNCTION),
2004    ts.factory.createNodeArray([ts.factory.createNumericLiteral(id)])));
2005}
2006
2007function createIfBranchFunc(id: number, innerStatements: ts.Statement[],
2008  isGlobalBuilder: boolean = false): ts.ExpressionStatement {
2009  return ts.factory.createExpressionStatement(ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(
2010    isGlobalBuilder ? parentConditionalExpression() : ts.factory.createThis(),
2011    ts.factory.createIdentifier(IFELSEBRANCHUPDATEFUNCTION)), undefined,
2012  [ts.factory.createNumericLiteral(id), ts.factory.createArrowFunction(undefined, undefined, [], undefined,
2013    ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), ts.factory.createBlock(innerStatements, true))]));
2014}
2015
2016interface CreateResult {
2017  newNode: ts.ExpressionStatement;
2018  identifierNode: ts.Identifier;
2019  isContainerComponent: boolean;
2020  isButton: boolean;
2021  needPop: boolean;
2022}
2023
2024function createComponent(node: ts.ExpressionStatement, type: string): CreateResult {
2025  const res: CreateResult = {
2026    newNode: node,
2027    identifierNode: null,
2028    isContainerComponent: false,
2029    isButton: false,
2030    needPop: false
2031  };
2032  let identifierNode: ts.Identifier = ts.factory.createIdentifier(type);
2033  let temp: any = node.expression;
2034  while (temp && !ts.isIdentifier(temp) && temp.expression) {
2035    temp = temp.expression;
2036  }
2037  if (temp && temp.parent && (ts.isCallExpression(temp.parent) ||
2038    ts.isEtsComponentExpression(temp.parent)) && ts.isIdentifier(temp)) {
2039    if (temp.getText() === COMPONENT_BUTTON && type !== COMPONENT_POP_FUNCTION) {
2040      res.isButton = true;
2041      identifierNode = type === COMPONENT_CREATE_CHILD_FUNCTION ?
2042        ts.factory.createIdentifier(COMPONENT_CREATE_CHILD_FUNCTION) :
2043        ts.factory.createIdentifier(COMPONENT_CREATE_LABEL_FUNCTION);
2044    }
2045    if (NEEDPOP_COMPONENT.has(temp.getText())) {
2046      res.needPop = true;
2047    }
2048    if (checkContainer(temp.getText(), temp.parent)) {
2049      res.isContainerComponent = true;
2050    }
2051    res.newNode = type === COMPONENT_POP_FUNCTION ?
2052      ts.factory.createExpressionStatement(createFunction(temp, identifierNode, null)) :
2053      ts.factory.createExpressionStatement(createFunction(temp, identifierNode, checkArguments(temp, type)));
2054    res.identifierNode = temp;
2055  }
2056  return res;
2057}
2058
2059function checkArguments(temp: ts.Identifier, type: string): ts.Expression[] {
2060  const newArguments: ts.Expression[] = [];
2061  if (CUSTOM_BUILDER_CONSTRUCTORS.has(temp.escapedText.toString())) {
2062    temp.parent.arguments.forEach(argument => {
2063      if (ts.isConditionalExpression(argument)) {
2064        newArguments.push(processConditionalBuilder(argument, temp, type));
2065      } else if (isBuilderChangeNode(argument, temp, type)) {
2066        newArguments.push(parseBuilderNode(argument, type));
2067      } else {
2068        newArguments.push(argument);
2069      }
2070    });
2071    return newArguments;
2072  }
2073  return temp.getText() === 'XComponent' && type === COMPONENT_CREATE_FUNCTION &&
2074    projectConfig.moduleName && projectConfig.bundleName ?
2075    // @ts-ignore
2076    temp.parent.arguments.concat([
2077      ts.factory.createStringLiteral(`${projectConfig.bundleName}/${projectConfig.moduleName}`)
2078    ]) : temp.parent.arguments;
2079}
2080
2081function checkContainer(name: string, node: ts.Node): boolean {
2082  return BUILDIN_CONTAINER_COMPONENT.has(name) && (name !== 'XComponent' ||
2083    (node && node.arguments && node.arguments.length &&
2084    ts.isObjectLiteralExpression(node.arguments[0]) && node.arguments[0].properties &&
2085    checkComponentType(node.arguments[0].properties)));
2086}
2087
2088function checkComponentType(properties: ts.PropertyAssignment[]): boolean {
2089  let flag: boolean = false;
2090  properties.forEach(item => {
2091    if (isXComponentContainer(item)) {
2092      flag = true;
2093    }
2094  });
2095  return flag;
2096}
2097
2098function isXComponentContainer(item: ts.PropertyAssignment): boolean {
2099  return item.name && ts.isIdentifier(item.name) && item.name.getText() === RESOURCE_NAME_TYPE &&
2100    item.initializer && ((ts.isStringLiteral(item.initializer) &&
2101    // value = 'component'
2102    (item.initializer.getText() === XCOMPONENT_SINGLE_QUOTATION ||
2103    item.initializer.getText() === XCOMPONENT_DOUBLE_QUOTATION)) ||
2104    // value = 1
2105    (ts.isNumericLiteral(item.initializer) && item.initializer.getText() === '1') ||
2106    // value = XComponentType.COMPONENT
2107    (ts.isPropertyAccessExpression(item.initializer) && item.initializer.expression &&
2108    ts.isIdentifier(item.initializer.expression) && item.initializer.name &&
2109    ts.isIdentifier(item.initializer.name) && item.initializer.expression.getText() === XCOMPONENTTYPE) &&
2110    item.initializer.name.getText() === XCOMPONENTTYPE_CONTAINER);
2111}
2112
2113interface AnimationInfo {
2114  statement: ts.Statement,
2115  kind: boolean,
2116  hasAnimationAttr: boolean,
2117}
2118
2119export interface ComponentAttrInfo {
2120  reuseId: ts.Node,
2121  hasIdAttr: boolean,
2122  attrCount: number,
2123}
2124
2125export function bindComponentAttr(node: ts.ExpressionStatement, identifierNode: ts.Identifier,
2126  newStatements: ts.Statement[], log: LogInfo[], reverse: boolean = true,
2127  isStylesAttr: boolean = false, newImmutableStatements: ts.Statement[] = null,
2128  isStyleFunction: boolean = false, componentAttrInfo: ComponentAttrInfo = null): void {
2129  let temp = node.expression;
2130  const statements: ts.Statement[] = [];
2131  const immutableStatements: ts.Statement[] = [];
2132  const updateStatements: ts.Statement[] = [];
2133  const lastStatement: AnimationInfo = {
2134    statement: null,
2135    kind: false,
2136    hasAnimationAttr: false
2137  };
2138  const isRecycleComponent: boolean = isRecycle(componentCollection.currentClassName);
2139  if (ts.isPropertyAccessExpression(temp)) {
2140    log.push({
2141      type: LogType.ERROR,
2142      message: `'${node.getText()}' does not meet UI component syntax.`,
2143      pos: node.getStart()
2144    });
2145  }
2146  while (temp && ts.isCallExpression(temp) && temp.expression) {
2147    let flag: boolean = false;
2148    if (temp.expression && (validatePropertyAccessExpressionWithCustomBuilder(temp.expression) ||
2149      validateIdentifierWithCustomBuilder(temp.expression))) {
2150      let propertyName: string = '';
2151      if (ts.isIdentifier(temp.expression)) {
2152        propertyName = temp.expression.escapedText.toString();
2153      } else if (ts.isPropertyAccessExpression(temp.expression)) {
2154        propertyName = temp.expression.name.escapedText.toString();
2155      }
2156      switch (true) {
2157        case BIND_POPUP_SET.has(propertyName):
2158          temp = processBindPopupBuilder(temp);
2159          break;
2160        case BIND_DRAG_SET.has(propertyName):
2161          temp = processDragStartBuilder(temp, propertyName);
2162          break;
2163        default:
2164          temp = processCustomBuilderProperty(temp, identifierNode, propertyName);
2165      }
2166    }
2167    if (ts.isPropertyAccessExpression(temp.expression) &&
2168      temp.expression.name && ts.isIdentifier(temp.expression.name) &&
2169      (!componentCollection.customComponents.has(temp.expression.name.getText()) || STYLES_ATTRIBUTE.has(temp.expression.name.getText()))) {
2170      parseRecycleId(temp, temp.expression.name, isRecycleComponent, componentAttrInfo);
2171      addComponentAttr(temp, temp.expression.name, lastStatement, statements, identifierNode, log,
2172        isStylesAttr, immutableStatements, updateStatements, newImmutableStatements,
2173        isRecycleComponent, isStyleFunction);
2174      temp = temp.expression.expression;
2175      flag = true;
2176    } else if (ts.isIdentifier(temp.expression)) {
2177      if (!INNER_COMPONENT_NAMES.has(temp.expression.getText()) &&
2178        !GESTURE_TYPE_NAMES.has(temp.expression.getText()) &&
2179        !componentCollection.customComponents.has(temp.expression.getText())) {
2180        parseRecycleId(temp, temp.expression.name, isRecycleComponent, componentAttrInfo);
2181        addComponentAttr(temp, temp.expression, lastStatement, statements, identifierNode, log,
2182          isStylesAttr, immutableStatements, updateStatements, newImmutableStatements,
2183          isRecycleComponent, isStyleFunction);
2184      }
2185      break;
2186    }
2187    if (!flag) {
2188      temp = temp.expression;
2189    }
2190  }
2191  if (lastStatement.statement && lastStatement.kind) {
2192    statements.push(lastStatement.statement);
2193  }
2194  if (!isRecycleComponent || lastStatement.hasAnimationAttr) {
2195    if (statements.length) {
2196      reverse ? newStatements.push(...statements.reverse()) : newStatements.push(...statements);
2197    }
2198  } else {
2199    if (updateStatements.length) {
2200      reverse ? newStatements.push(...updateStatements.reverse()) : newStatements.push(...updateStatements);
2201    }
2202    if (newImmutableStatements && immutableStatements.length) {
2203      reverse ? newImmutableStatements.push(...immutableStatements.reverse()) : newImmutableStatements.push(...immutableStatements);
2204    }
2205  }
2206}
2207
2208function parseRecycleId(node: ts.CallExpression, attr: ts.Identifier, isRecycleComponent: boolean,
2209  componentAttrInfo: ComponentAttrInfo): void {
2210  if (componentAttrInfo) {
2211    const attrName: string = attr.escapedText.toString();
2212    if (attrName === RECYCLE_REUSE_ID) {
2213      componentAttrInfo.reuseId = node.arguments[0];
2214    } else if (attrName === ATTRIBUTE_ID) {
2215      componentAttrInfo.hasIdAttr = true;
2216    }
2217    componentAttrInfo.attrCount++;
2218  }
2219}
2220
2221function processCustomBuilderProperty(node: ts.CallExpression, identifierNode: ts.Identifier,
2222  propertyName: string): ts.CallExpression {
2223  const newArguments: ts.Expression[] = [];
2224  node.arguments.forEach((argument: ts.Expression | ts.Identifier, index: number) => {
2225    if (ts.isConditionalExpression(argument)) {
2226      newArguments.push(processConditionalBuilder(argument, identifierNode, propertyName));
2227    } else if (isBuilderChangeNode(argument, identifierNode, propertyName)) {
2228      newArguments.push(parseBuilderNode(argument, propertyName));
2229    } else {
2230      newArguments.push(argument);
2231    }
2232  });
2233  node = ts.factory.updateCallExpression(node, node.expression, node.typeArguments, newArguments);
2234  return node;
2235}
2236
2237function isBuilderChangeNode(argument: ts.Node, identifierNode: ts.Identifier, propertyName: string): boolean {
2238  return ts.isPropertyAccessExpression(argument) && argument.name && ts.isIdentifier(argument.name) &&
2239    storedFileInfo.builderLikeCollection.has(argument.name.getText()) ||
2240    ts.isCallExpression(argument) && argument.expression && argument.expression.name &&
2241    ts.isIdentifier(argument.expression.name) &&
2242    storedFileInfo.builderLikeCollection.has(argument.expression.name.getText()) || ts.isIdentifier(argument) &&
2243    argument.escapedText && storedFileInfo.builderLikeCollection.has(argument.escapedText.toString()) ||
2244    ts.isObjectLiteralExpression(argument) && (BIND_OBJECT_PROPERTY.get(identifierNode.escapedText.toString()) &&
2245    BIND_OBJECT_PROPERTY.get(identifierNode.escapedText.toString()).has(propertyName) ||
2246    BIND_OBJECT_PROPERTY.get(ALL_COMPONENTS).has(propertyName)) ||
2247    ts.isCallExpression(argument) && argument.expression && ts.isIdentifier(argument.expression) &&
2248    storedFileInfo.builderLikeCollection.has(argument.expression.escapedText.toString()) ||
2249    isWrappedBuilder(argument as ts.PropertyAccessExpression) || isWrappedBuilderCallExpression(argument as ts.CallExpression);
2250}
2251
2252export function isWrappedBuilder(node: ts.PropertyAccessExpression): boolean {
2253  if (projectConfig.minAPIVersion >= 11 && ts.isPropertyAccessExpression(node) &&
2254    node.name && ts.isIdentifier(node.name) && node.name.escapedText.toString() === WRAPBUILDER_BUILDERPROP &&
2255    globalProgram.checker.getTypeAtLocation(node.expression) &&
2256    globalProgram.checker.getTypeAtLocation(node.expression).symbol &&
2257    globalProgram.checker.getTypeAtLocation(node.expression).symbol.escapedName === WRAPPEDBUILDER_CLASS) {
2258    return true;
2259  }
2260  return false;
2261}
2262
2263function isWrappedBuilderCallExpression(node: ts.CallExpression): boolean {
2264  if (projectConfig.minAPIVersion >= 11 && ts.isCallExpression(node) && node.expression &&
2265    isWrappedBuilder(node.expression as ts.PropertyAccessExpression)) {
2266    return true;
2267  }
2268  return false;
2269}
2270
2271function parseBuilderNode(node: ts.Node, propertyName: string):
2272  ts.ObjectLiteralExpression | ts.CallExpression | ts.ArrowFunction {
2273  if (isWrappedBuilder(node as ts.PropertyAccessExpression) || isPropertyAccessExpressionNode(node)) {
2274    if (CUSTOM_BUILDER_PROPERTIES_WITHOUTKEY.has(propertyName)) {
2275      return processPropertyBuilderWithoutKey(node as ts.PropertyAccessExpression);
2276    } else {
2277      return processPropertyBuilder(node as ts.PropertyAccessExpression);
2278    }
2279  } else if (ts.isIdentifier(node) && storedFileInfo.builderLikeCollection.has(node.escapedText.toString())) {
2280    if (CUSTOM_BUILDER_PROPERTIES_WITHOUTKEY.has(propertyName)) {
2281      return processIdentifierBuilderWithoutKey(node);
2282    } else {
2283      return processIdentifierBuilder(node);
2284    }
2285  } else if (isWrappedBuilderCallExpression(node as ts.CallExpression) || ts.isCallExpression(node)) {
2286    if (CUSTOM_BUILDER_PROPERTIES_WITHOUTKEY.has(propertyName)) {
2287      return getParsedBuilderAttrArgumentWithParamsWithoutKey(node);
2288    } else {
2289      return getParsedBuilderAttrArgumentWithParams(node);
2290    }
2291  } else if (ts.isObjectLiteralExpression(node)) {
2292    return processObjectPropertyBuilder(node);
2293  }
2294  return undefined;
2295}
2296
2297export function processObjectPropertyBuilder(node: ts.ObjectLiteralExpression): ts.ObjectLiteralExpression {
2298  const newProperties: ts.PropertyAssignment[] = [];
2299  node.properties.forEach((property: ts.PropertyAssignment) => {
2300    if (property.name && ts.isIdentifier(property.name) &&
2301      [CUSTOM_DIALOG_CONTROLLER_BUILDER, HEADER, INDICATORBUILDER, FOOTER, START, END, PREVIEW, TITLE].includes(
2302        property.name.escapedText.toString()) && property.initializer) {
2303      if (isPropertyAccessExpressionNode(property.initializer) || ts.isIdentifier(property.initializer) &&
2304        storedFileInfo.builderLikeCollection.has(property.initializer.escapedText.toString())) {
2305        newProperties.push(ts.factory.updatePropertyAssignment(property, property.name,
2306          ts.factory.createCallExpression(
2307            ts.factory.createPropertyAccessExpression(
2308              property.initializer,
2309              ts.factory.createIdentifier(BUILDER_ATTR_BIND)
2310            ),
2311            undefined,
2312            [ts.factory.createThis()]
2313          )));
2314      } else if (isGlobalBuilderCallExpressionNode(property.initializer) ||
2315        isInnerBuilderCallExpressionNode(property.initializer)) {
2316        newProperties.push(transformBuilderCallExpression(property));
2317      } else if (ts.isObjectLiteralExpression(property.initializer)) {
2318        newProperties.push(ts.factory.updatePropertyAssignment(property, property.name,
2319          processObjectPropertyBuilder(property.initializer)));
2320      } else {
2321        newProperties.push(property);
2322      }
2323    } else {
2324      newProperties.push(property);
2325    }
2326  });
2327  return ts.factory.updateObjectLiteralExpression(node, newProperties);
2328}
2329
2330function transDoubleDollarInCustomBuilder(node: ts.CallExpression): ts.Expression[] {
2331  let name: string = '';
2332  if (node.expression && ts.isIdentifier(node.expression)) {
2333    name = node.expression.escapedText.toString();
2334  } else if (node.expression && ts.isPropertyAccessExpression(node.expression) &&
2335    node.expression.name && ts.isIdentifier(node.expression.name)) {
2336    name = node.expression.name.escapedText.toString();
2337  }
2338  if (node.arguments.length === 1 && ts.isObjectLiteralExpression(node.arguments[0])) {
2339    return [ts.factory.createCallExpression(
2340      ts.factory.createIdentifier(BUILDER_PARAM_PROXY),
2341      undefined,
2342      [
2343        ts.factory.createStringLiteral(name),
2344        traverseBuilderParams(node.arguments[0], storedFileInfo.processBuilder)
2345      ]
2346    )];
2347  } else {
2348    return node.arguments;
2349  }
2350}
2351
2352function transformBuilderCallExpression(property: ts.PropertyAssignment): ts.PropertyAssignment {
2353  const newArguments: ts.Expression[] = transDoubleDollarInCustomBuilder(property.initializer as ts.CallExpression);
2354  return ts.factory.updatePropertyAssignment(property, property.name,
2355    ts.factory.createCallExpression(
2356      ts.factory.createPropertyAccessExpression(
2357        property.initializer.expression,
2358        ts.factory.createIdentifier(BUILDER_ATTR_BIND)
2359      ),
2360      undefined,
2361      [ts.factory.createThis(), ...(newArguments || [])]
2362    ));
2363}
2364
2365function isInnerBuilderCallExpressionNode(node: ts.Node): boolean {
2366  return ts.isCallExpression(node) && node.expression && isPropertyAccessExpressionNode(node.expression);
2367}
2368
2369function isGlobalBuilderCallExpressionNode(node: ts.Node): boolean {
2370  return ts.isCallExpression(node) && node.expression && ts.isIdentifier(node.expression) &&
2371    CUSTOM_BUILDER_METHOD.has(node.expression.escapedText.toString());
2372}
2373
2374function isPropertyAccessExpressionNode(node: ts.Node): boolean {
2375  return ts.isPropertyAccessExpression(node) && node.expression &&
2376    node.expression.kind === ts.SyntaxKind.ThisKeyword && node.name && ts.isIdentifier(node.name) &&
2377    storedFileInfo.builderLikeCollection.has(node.name.escapedText.toString());
2378}
2379
2380function processBindPopupBuilder(node: ts.CallExpression): ts.CallExpression {
2381  const newArguments: ts.Expression[] = [];
2382  node.arguments.forEach((argument: ts.ObjectLiteralExpression, index: number) => {
2383    if (index === 1 && ts.isObjectLiteralExpression(argument)) {
2384      // @ts-ignore
2385      newArguments.push(processBindPopupBuilderProperty(argument));
2386    } else {
2387      newArguments.push(argument);
2388    }
2389  });
2390  node = ts.factory.updateCallExpression(node, node.expression, node.typeArguments, newArguments);
2391  return node;
2392}
2393
2394function processDragStartBuilder(node: ts.CallExpression, propertyName: string): ts.CallExpression {
2395  const newStatements: ts.Statement[] = [];
2396  if (isNodeFunction(node)) {
2397    // @ts-ignore
2398    for (let i = 0; i < node.arguments[0].body.statements.length; i++) {
2399      // @ts-ignore
2400      const statement: ts.Statement = node.arguments[0].body.statements[i];
2401      newStatements.push(checkStatement(statement, propertyName));
2402    }
2403    node = ts.factory.updateCallExpression(node, node.expression, node.typeArguments, [ts.factory.updateArrowFunction(
2404      // @ts-ignore
2405      node.arguments[0], undefined, undefined, node.arguments[0].parameters, node.arguments[0].type,
2406      // @ts-ignore
2407      node.arguments[0].equalsGreaterThanToken, ts.factory.updateBlock(node.arguments[0].body, newStatements))]);
2408  }
2409  return node;
2410}
2411
2412function isNodeFunction(node: ts.CallExpression): boolean {
2413  return node.arguments && node.arguments.length && ts.isArrowFunction(node.arguments[0]) && node.arguments[0].body &&
2414    ts.isBlock(node.arguments[0].body);
2415}
2416
2417function checkStatement(statement: ts.Statement, propertyName: string): ts.Statement {
2418  if (ts.isReturnStatement(statement)) {
2419    if (ts.isObjectLiteralExpression(statement.expression)) {
2420      const newProperties: ts.ObjectLiteralElementLike[] = [];
2421      for (let j = 0; j < statement.expression.properties.length; j++) {
2422        let property: ts.ObjectLiteralElementLike = statement.expression.properties[j];
2423        property = checkProperty(property, propertyName);
2424        newProperties.push(property);
2425      }
2426      return ts.factory.createReturnStatement(ts.factory.createObjectLiteralExpression(newProperties));
2427    } else {
2428      let initializer: ts.Expression = statement.expression;
2429      initializer = processInitializer(initializer, propertyName);
2430      return ts.factory.updateReturnStatement(statement, initializer);
2431    }
2432  } else {
2433    return statement;
2434  }
2435}
2436
2437function checkProperty(property: ts.ObjectLiteralElementLike, propertyName: string): ts.ObjectLiteralElementLike {
2438  if (isPropertyFunction(property)) {
2439    let initializer: ts.Expression = property.initializer;
2440    initializer = processInitializer(initializer, propertyName);
2441    property = ts.factory.createPropertyAssignment(property.name, initializer);
2442  }
2443  return property;
2444}
2445
2446function processInitializer(initializer: ts.Expression, propertyName: string): ts.Expression {
2447  if (initializer && ts.isConditionalExpression(initializer)) {
2448    return processConditionalBuilder(initializer, ts.factory.createIdentifier(CUSTOM_COMPONENT_DEFAULT),
2449      propertyName);
2450  } else if (isBuilderChangeNode(initializer, ts.factory.createIdentifier(CUSTOM_COMPONENT_DEFAULT),
2451    propertyName)) {
2452    return parseBuilderNode(initializer, propertyName);
2453  }
2454  return initializer;
2455}
2456
2457function isPropertyFunction(property: ts.ObjectLiteralElementLike): boolean {
2458  return ts.isPropertyAssignment(property) && property.name && ts.isIdentifier(property.name) &&
2459    property.name.escapedText.toString() === BUILDER_ATTR_NAME;
2460}
2461
2462function processBindPopupBuilderProperty(node: ts.ObjectLiteralExpression): ts.ObjectLiteralExpression {
2463  const newProperties: ts.PropertyAssignment[] = [];
2464  node.properties.forEach((property: ts.PropertyAssignment, index: number) => {
2465    if (property.name && ts.isIdentifier(property.name) && property.initializer &&
2466      property.name.escapedText.toString() === CUSTOM_DIALOG_CONTROLLER_BUILDER) {
2467      let initializer: ts.Expression = property.initializer;
2468      initializer = processInitializer(initializer, BIND_POPUP);
2469      newProperties.push(ts.factory.updatePropertyAssignment(property, property.name, initializer));
2470    } else {
2471      newProperties.push(property);
2472    }
2473  });
2474  return ts.factory.updateObjectLiteralExpression(node, newProperties);
2475}
2476
2477function processConditionalBuilder(initializer: ts.ConditionalExpression, identifierNode: ts.Identifier,
2478  propertyName: string): ts.ConditionalExpression {
2479  let whenTrue: ts.Expression = initializer.whenTrue;
2480  let whenFalse: ts.Expression = initializer.whenFalse;
2481  if (isBuilderChangeNode(initializer.whenTrue, identifierNode, propertyName)) {
2482    whenTrue = parseBuilderNode(initializer.whenTrue, propertyName);
2483  }
2484  if (isBuilderChangeNode(initializer.whenFalse, identifierNode, propertyName)) {
2485    whenFalse = parseBuilderNode(initializer.whenFalse, propertyName);
2486  }
2487  return ts.factory.createConditionalExpression(
2488    initializer.condition,
2489    initializer.questionToken,
2490    whenTrue,
2491    initializer.colonToken,
2492    whenFalse
2493  );
2494}
2495
2496function processPropertyBuilder(node: ts.PropertyAccessExpression): ts.ObjectLiteralExpression {
2497  return ts.factory.createObjectLiteralExpression([
2498    ts.factory.createPropertyAssignment(
2499      ts.factory.createIdentifier(BUILDER_ATTR_NAME),
2500      ts.factory.createCallExpression(
2501        ts.factory.createPropertyAccessExpression(
2502          node,
2503          ts.factory.createIdentifier(BUILDER_ATTR_BIND)
2504        ),
2505        undefined,
2506        [ts.factory.createThis()]
2507      )
2508    )
2509  ]);
2510}
2511
2512function processPropertyBuilderWithoutKey(node: ts.PropertyAccessExpression): ts.CallExpression {
2513  return ts.factory.createCallExpression(
2514    ts.factory.createPropertyAccessExpression(
2515      node,
2516      ts.factory.createIdentifier(BUILDER_ATTR_BIND)
2517    ),
2518    undefined,
2519    [ts.factory.createThis()]
2520  );
2521}
2522
2523function processIdentifierBuilder(node: ts.Identifier): ts.ObjectLiteralExpression {
2524  return ts.factory.createObjectLiteralExpression([
2525    ts.factory.createPropertyAssignment(
2526      ts.factory.createIdentifier(BUILDER_ATTR_NAME),
2527      ts.factory.createCallExpression(
2528        ts.factory.createPropertyAccessExpression(node, ts.factory.createIdentifier(BUILDER_ATTR_BIND)),
2529        undefined, [ts.factory.createThis()]
2530      )
2531    )
2532  ]);
2533}
2534
2535function processIdentifierBuilderWithoutKey(node: ts.Identifier): ts.CallExpression {
2536  return ts.factory.createCallExpression(
2537    ts.factory.createPropertyAccessExpression(node, ts.factory.createIdentifier(BUILDER_ATTR_BIND)),
2538    undefined, [ts.factory.createThis()]
2539  );
2540}
2541
2542function getParsedBuilderAttrArgumentWithParams(node: ts.CallExpression):
2543  ts.ObjectLiteralExpression {
2544  const newArguments: ts.Expression[] = transDoubleDollarInCustomBuilder(node);
2545  return ts.factory.createObjectLiteralExpression([
2546    ts.factory.createPropertyAssignment(
2547      ts.factory.createIdentifier(BUILDER_ATTR_NAME),
2548      ts.factory.createArrowFunction(
2549        undefined,
2550        undefined,
2551        [],
2552        undefined,
2553        ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
2554        ts.factory.createBlock(
2555          [ts.factory.createExpressionStatement(ts.factory.createCallExpression(
2556            ts.factory.createPropertyAccessExpression(node.expression, ts.factory.createIdentifier(CALL)
2557            ), undefined, [ts.factory.createThis(), ...newArguments]))],
2558          true
2559        )
2560      )
2561    )
2562  ]);
2563}
2564
2565function getParsedBuilderAttrArgumentWithParamsWithoutKey(node: ts.CallExpression):
2566  ts.ArrowFunction {
2567  const newArguments: ts.Expression[] = transDoubleDollarInCustomBuilder(node);
2568  return ts.factory.createArrowFunction(
2569    undefined,
2570    undefined,
2571    [],
2572    undefined,
2573    ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
2574    ts.factory.createBlock(
2575      [ts.factory.createExpressionStatement(ts.factory.createCallExpression(
2576        ts.factory.createPropertyAccessExpression(node.expression, ts.factory.createIdentifier(CALL)
2577        ), undefined, [ts.factory.createThis(), ...newArguments]))],
2578      true
2579    )
2580  );
2581}
2582
2583function validatePropertyAccessExpressionWithCustomBuilder(node: ts.Node): boolean {
2584  return ts.isPropertyAccessExpression(node) && node.name &&
2585    ts.isIdentifier(node.name) && CUSTOM_BUILDER_PROPERTIES.has(node.name.escapedText.toString());
2586}
2587
2588function validateIdentifierWithCustomBuilder(node: ts.Node): boolean {
2589  return ts.isIdentifier(node) && CUSTOM_BUILDER_PROPERTIES.has(node.escapedText.toString());
2590}
2591
2592function createArrowFunctionForDollar($$varExp: ts.Expression): ts.ArrowFunction {
2593  return ts.factory.createArrowFunction(
2594    undefined, undefined,
2595    [ts.factory.createParameterDeclaration(
2596      undefined, undefined,
2597      ts.factory.createIdentifier($$_NEW_VALUE),
2598      undefined, undefined, undefined
2599    )],
2600    undefined,
2601    ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
2602    ts.factory.createBlock(
2603      [ts.factory.createExpressionStatement(ts.factory.createBinaryExpression(
2604        $$varExp,
2605        ts.factory.createToken(ts.SyntaxKind.EqualsToken),
2606        ts.factory.createIdentifier($$_NEW_VALUE)
2607      ))],
2608      false
2609    )
2610  );
2611}
2612
2613function updateArgumentForExclamation(argument): ts.Expression {
2614  if (ts.isNonNullExpression(argument) && ts.isNonNullExpression(argument.expression)) {
2615    return argument.expression.expression;
2616  }
2617  return argument;
2618}
2619
2620function updateArgumentForDollar(argument): ts.Expression {
2621  if (ts.isElementAccessExpression(argument)) {
2622    return ts.factory.updateElementAccessExpression(
2623      argument, updateArgumentForDollar(argument.expression), argument.argumentExpression);
2624  } else if (ts.isIdentifier(argument)) {
2625    if (argument.getText() === $$_THIS) {
2626      return ts.factory.createThis();
2627    } else if (argument.getText().match(/^\$\$(.|\n)+/)) {
2628      return ts.factory.createIdentifier(argument.getText().replace(/\$\$/, ''));
2629    }
2630  } else if (ts.isPropertyAccessExpression(argument)) {
2631    return ts.factory.updatePropertyAccessExpression(
2632      argument, updateArgumentForDollar(argument.expression), argument.name);
2633  }
2634  return argument;
2635}
2636
2637function verifyComponentId(temp: any, node: ts.Identifier, propName: string,
2638  log: LogInfo[]): void {
2639  if (!newsupplement.isAcceleratePreview && propName === ATTRIBUTE_ID &&
2640    ts.isStringLiteral(temp.arguments[0])) {
2641    const id: string = temp.arguments[0].text;
2642    const posOfNode: ts.LineAndCharacter = transformLog.sourceFile
2643      .getLineAndCharacterOfPosition(getRealNodePos(node));
2644    const curFileName: string = transformLog.sourceFile.fileName.replace(/\.ts$/, '');
2645    const rPath: string = path.resolve(projectConfig.projectPath, curFileName)
2646      .replace(/\\+/g, '/');
2647    const rLine: number = posOfNode.line + 1;
2648    const rCol: number = posOfNode.character + 1;
2649    if (ID_ATTRS.has(id)) {
2650      const idInfo: Map<string, string | number> = ID_ATTRS.get(id);
2651      if (!(idInfo.get('path') === rPath &&
2652        idInfo.get('line') === rLine &&
2653        idInfo.get('col') === rCol)) {
2654        log.push({
2655          type: LogType.WARN,
2656          message: `The current component id "${id}" is duplicate with ` +
2657            `${idInfo.get('path')}:${idInfo.get('line')}:${idInfo.get('col')}.`,
2658          pos: node.pos
2659        });
2660      }
2661    } else {
2662      ID_ATTRS.set(id, new Map().set('path', rPath)
2663        .set('line', rLine)
2664        .set('col', rCol));
2665    }
2666  }
2667}
2668
2669class StyleResult {
2670  doubleDollar: boolean = false;
2671  doubleExclamation: boolean = false;
2672}
2673
2674function isDoubleBind(styleResult: StyleResult, isStylesAttr: boolean, identifierNode: ts.Identifier,
2675  propName: string, temp: any): boolean {
2676  if (isDoubleDollarToChange(isStylesAttr, identifierNode, propName, temp)) {
2677    styleResult.doubleDollar = true;
2678    return true;
2679  } else if (isDoubleExclamationToChange(isStylesAttr, propName, temp)) {
2680    styleResult.doubleExclamation = true;
2681    return true;
2682  }
2683  return false;
2684}
2685
2686function addComponentAttr(temp, node: ts.Identifier, lastStatement,
2687  statements: ts.Statement[], identifierNode: ts.Identifier, log: LogInfo[],
2688  isStylesAttr: boolean, immutableStatements: ts.Statement[], updateStatements: ts.Statement[],
2689  newImmutableStatements: ts.Statement[] = null, isRecycleComponent: boolean = false,
2690  isStyleFunction: boolean = false): void {
2691  const styleResult: StyleResult = new StyleResult();
2692  const propName: string = node.getText();
2693  verifyComponentId(temp, node, propName, log);
2694  const extendType: ExtendType = {type: ''};
2695  if (propName === ATTRIBUTE_ANIMATION) {
2696    const animationNullNode: ts.ExpressionStatement = ts.factory.createExpressionStatement(
2697      createFunction(ts.factory.createIdentifier(GLOBAL_CONTEXT), node,
2698        // @ts-ignore
2699        [ts.factory.createNull()]));
2700    if (!lastStatement.statement) {
2701      if (!(temp.arguments.length === 1 &&
2702        temp.arguments[0].kind === ts.SyntaxKind.NullKeyword)) {
2703        statements.push(animationNullNode);
2704      }
2705    } else {
2706      statements.push(lastStatement.statement, animationNullNode);
2707    }
2708    lastStatement.statement = ts.factory.createExpressionStatement(createFunction(
2709      ts.factory.createIdentifier(GLOBAL_CONTEXT), node, temp.arguments));
2710    lastStatement.kind = false;
2711    lastStatement.hasAnimationAttr = true;
2712  } else if (GESTURE_ATTRS.has(propName)) {
2713    parseGesture(temp, propName, statements, log, updateStatements);
2714    lastStatement.kind = true;
2715  } else if (isExtendFunctionNode(identifierNode, propName, extendType)) {
2716    if (newsupplement.isAcceleratePreview) {
2717      log.push({
2718        type: LogType.ERROR,
2719        message: `Doesn't support Extend function now`,
2720        pos: temp.getStart()
2721      });
2722    }
2723    let functionName: string = '';
2724    if (extendType.type === CHECK_COMPONENT_EXTEND_DECORATOR) {
2725      functionName = `__${identifierNode.escapedText.toString()}__${propName}`;
2726    } else {
2727      functionName = propName;
2728    }
2729    const extendNode: ts.Statement = ts.factory.createExpressionStatement(
2730      ts.factory.createCallExpression(ts.factory.createIdentifier(functionName), undefined,
2731        extendType.type === CHECK_COMPONENT_EXTEND_DECORATOR ?
2732          temp.arguments :
2733          [
2734            ...temp.arguments, ts.factory.createIdentifier(ELMTID),
2735            ts.factory.createIdentifier(ISINITIALRENDER),
2736            ts.factory.createThis()
2737          ]
2738      ));
2739    statements.push(extendNode);
2740    updateStatements.push(extendNode);
2741    lastStatement.kind = true;
2742  } else if (propName === ATTRIBUTE_STATESTYLES) {
2743    if (temp.arguments.length === 1 && ts.isObjectLiteralExpression(temp.arguments[0])) {
2744      statements.push(createViewStackProcessor(temp, true));
2745      if (isRecycleComponent) {
2746        updateStatements.push(createViewStackProcessor(temp, true));
2747      }
2748      traverseStateStylesAttr(temp, statements, identifierNode, log, updateStatements,
2749        newImmutableStatements, isRecycleComponent);
2750      lastStatement.kind = true;
2751    } else {
2752      validateStateStyleSyntax(temp, log);
2753    }
2754  } else if (GLOBAL_STYLE_FUNCTION.has(propName) || INNER_STYLE_FUNCTION.has(propName)) {
2755    const styleBlock: ts.Block =
2756        INNER_STYLE_FUNCTION.get(propName) || GLOBAL_STYLE_FUNCTION.get(propName);
2757    if (styleBlock.statements.length > 0) {
2758      bindComponentAttr(styleBlock.statements[0] as ts.ExpressionStatement, identifierNode,
2759        statements, log, false, true, newImmutableStatements);
2760      if (isRecycleComponent) {
2761        bindComponentAttr(styleBlock.statements[0] as ts.ExpressionStatement, identifierNode,
2762          updateStatements, log, false, true, newImmutableStatements, true);
2763      }
2764    }
2765    lastStatement.kind = true;
2766  } else if (isDoubleBind(styleResult, isStylesAttr, identifierNode, propName, temp)) {
2767    const argumentsArr: ts.Expression[] = [];
2768    styleResult.doubleDollar ? classifyArgumentsNum(temp.arguments, argumentsArr, propName, identifierNode) :
2769      classifyArgumentsNumV2(temp.arguments, argumentsArr, propName);
2770    const doubleDollarNode: ts.Statement = ts.factory.createExpressionStatement(
2771      createFunction(identifierNode, node, argumentsArr));
2772    statements.push(doubleDollarNode);
2773    updateStatements.push(doubleDollarNode);
2774    lastStatement.kind = true;
2775  } else {
2776    temp = loopEtscomponent(temp, isStylesAttr);
2777    if (propName !== RECYCLE_REUSE_ID) {
2778      let isAttributeModifier: boolean = false;
2779      if ([ATTRIBUTE_ATTRIBUTE_MODIFIER, ATTRIBUTE_CONTENT_MODIFIER,
2780        ATTRIBUTE_MENUITEM_CONTENT_MODIFIER].includes(propName)) {
2781        isAttributeModifier = true;
2782      }
2783      const attrStatement: ts.Statement = ts.factory.createExpressionStatement(
2784        createFunction(identifierNode, node, temp.arguments, isAttributeModifier));
2785      statements.push(attrStatement);
2786      if (isRecycleComponent && (!isStylesAttr || isStyleFunction) &&
2787        !isGestureType(identifierNode) && filterRegularAttrNode(temp.arguments)) {
2788        immutableStatements.push(attrStatement);
2789      } else {
2790        updateStatements.push(attrStatement);
2791      }
2792    }
2793    lastStatement.kind = true;
2794  }
2795}
2796
2797function isGestureType(node: ts.Identifier): boolean {
2798  return GESTURE_TYPE_NAMES.has(node.escapedText.toString());
2799}
2800
2801function filterRegularAttrNode(argumentsNode: ts.NodeArray<ts.Expression>): boolean {
2802  return argumentsNode.every((argument: ts.Expression) => {
2803    return isRegularAttrNode(argument);
2804  });
2805}
2806
2807type AttrResult = { isRegularNode: boolean };
2808function isRegularAttrNode(node: ts.Expression): boolean {
2809  if (ts.isObjectLiteralExpression(node)) {
2810    return node.properties.every((propNode: ts.PropertyAssignment) => {
2811      if (propNode.initializer) {
2812        return isRegularAttrNode(propNode.initializer);
2813      }
2814      return false;
2815    });
2816  }
2817  if (ts.isArrayLiteralExpression(node)) {
2818    return node.elements.every((child: ts.Expression) => {
2819      return isRegularAttrNode(child);
2820    });
2821  }
2822  // literal e.g. 'hello', 1, true, false, () => {}
2823  if (isLiteralNode(node)) {
2824    return true;
2825  }
2826  // enum e.g. Color.Red
2827  if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.expression) &&
2828    ts.isIdentifier(node.name)) {
2829    if (enumCollection.has(node.expression.escapedText.toString())) {
2830      return true;
2831    }
2832    if (globalProgram.checker) {
2833      const type: ts.Type = globalProgram.checker.getTypeAtLocation(node);
2834      /* Enum */
2835      if (type.flags & (32 | 1024)) {
2836        return true;
2837      }
2838    }
2839    return false;
2840  }
2841  // regular variable, e.g. this.regularValue
2842  const result: AttrResult = { isRegularNode: false };
2843  if (ts.isPropertyAccessExpression(node)) {
2844    traversePropNode(node, result);
2845  }
2846  return result.isRegularNode || false;
2847}
2848
2849function isLiteralNode(node: ts.Expression): boolean {
2850  return ts.isStringLiteral(node) || ts.isNumericLiteral(node) || ts.isArrowFunction(node) ||
2851    [ts.SyntaxKind.TrueKeyword, ts.SyntaxKind.FalseKeyword].includes(node.kind);
2852}
2853
2854function traversePropNode(node: ts.PropertyAccessExpression, result: AttrResult): void {
2855  if (node.expression.kind === ts.SyntaxKind.ThisKeyword && ts.isIdentifier(node.name) &&
2856    regularCollection.get(componentCollection.currentClassName).has(node.name.escapedText.toString())) {
2857    result.isRegularNode = true;
2858    return;
2859  }
2860  if (ts.isPropertyAccessExpression(node.expression)) {
2861    traversePropNode(node.expression, result);
2862  }
2863}
2864
2865function isDoubleDollarToChange(isStylesAttr: boolean, identifierNode: ts.Identifier,
2866  propName: string, temp): boolean {
2867  return !isStylesAttr &&
2868    PROPERTIES_ADD_DOUBLE_DOLLAR.has(identifierNode.escapedText.toString()) &&
2869    PROPERTIES_ADD_DOUBLE_DOLLAR.get(identifierNode.escapedText.toString()).has(propName) ||
2870    STYLE_ADD_DOUBLE_DOLLAR.has(propName) && temp.arguments.length && temp.arguments[0] ?
2871    temp.arguments[0].getText().match(/^(?!\$\$\.)\$\$(.|\n)+/) !== null :
2872    false;
2873}
2874
2875function isDoubleExclamationToChange(isStylesAttr: boolean, propName: string, temp): boolean {
2876  return !isStylesAttr &&
2877    STYLE_ADD_DOUBLE_EXCLAMATION.has(propName) && temp.arguments.length && temp.arguments[0] &&
2878    ts.isNonNullExpression(temp.arguments[0]) && ts.isNonNullExpression(temp.arguments[0].expression) &&
2879    !ts.isNonNullExpression(temp.arguments[0].expression.expression);
2880}
2881
2882function isHaveDoubleDollar(param: ts.PropertyAssignment, name: string): boolean {
2883  return ts.isPropertyAssignment(param) && param.name && ts.isIdentifier(param.name) &&
2884    PROPERTIES_ADD_DOUBLE_DOLLAR.get(name).has(param.name.getText()) && param.initializer &&
2885    param.initializer.getText().match(/^(?!\$\$\.)\$\$(.|\n)+/) !== null;
2886}
2887
2888function loopEtscomponent(node: any, isStylesAttr: boolean): ts.Node {
2889  node.arguments.forEach((item: ts.Node, index: number) => {
2890    if (ts.isEtsComponentExpression(item)) {
2891      node.arguments[index] = ts.factory.createCallExpression(
2892        item.expression, undefined, item.arguments);
2893    } else if ((ts.isCallExpression(item) || ts.isNewExpression(item)) &&
2894      !newsupplement.isAcceleratePreview) {
2895      node.arguments[index] = ts.visitEachChild(item,
2896        changeEtsComponentKind, contextGlobal);
2897    }
2898  });
2899  return node;
2900}
2901
2902function changeEtsComponentKind(node: ts.Node): ts.Node {
2903  if (ts.isEtsComponentExpression(node)) {
2904    node.kind = 204;
2905    return node;
2906  }
2907  return ts.visitEachChild(node, changeEtsComponentKind, contextGlobal);
2908}
2909
2910function classifyArgumentsNum(args, argumentsArr: ts.Expression[], propName: string,
2911  identifierNode: ts.Identifier): void {
2912  if (STYLE_ADD_DOUBLE_DOLLAR.has(propName) && args.length >= 2) {
2913    const varExp: ts.Expression = updateArgumentForDollar(args[0]);
2914    argumentsArr.push(generateObjectForDollar(varExp), ...args.slice(1));
2915  } else if (STYLE_ADD_DOUBLE_EXCLAMATION.has(propName) && args.length >= 2) {
2916    const varExp: ts.Expression = updateArgumentForExclamation(args[0]);
2917    argumentsArr.push(generateObjectForExclamation(varExp), ...args.slice(1));
2918  } else if (PROPERTIES_ADD_DOUBLE_DOLLAR.has(identifierNode.escapedText.toString()) && args.length === 1 &&
2919    PROPERTIES_ADD_DOUBLE_DOLLAR.get(identifierNode.escapedText.toString()).has(propName) ||
2920    STYLE_ADD_DOUBLE_DOLLAR.has(propName) && args.length === 1) {
2921    const varExp: ts.Expression = updateArgumentForDollar(args[0]);
2922    argumentsArr.push(varExp, createArrowFunctionForDollar(varExp));
2923  }
2924}
2925
2926function classifyArgumentsNumV2(args, argumentsArr: ts.Expression[], propName: string): void {
2927  if (STYLE_ADD_DOUBLE_EXCLAMATION.has(propName) && args.length >= 2) {
2928    const varExp: ts.Expression = updateArgumentForExclamation(args[0]);
2929    argumentsArr.push(generateObjectForExclamation(varExp), ...args.slice(1));
2930  }
2931}
2932
2933function generateObjectForExclamation(varExp: ts.Expression): ts.ObjectLiteralExpression {
2934  return ts.factory.createObjectLiteralExpression([
2935      ts.factory.createPropertyAssignment(
2936        ts.factory.createIdentifier($$_VALUE),
2937        varExp),
2938      ts.factory.createPropertyAssignment(
2939        ts.factory.createIdentifier($_VALUE),
2940        ts.factory.createArrowFunction(
2941          undefined, undefined,
2942          [ts.factory.createParameterDeclaration(
2943            undefined, undefined,
2944            ts.factory.createIdentifier($$_NEW_VALUE),
2945            undefined, undefined, undefined
2946          )],
2947          undefined,
2948          ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
2949          ts.factory.createBlock(
2950            [ts.factory.createExpressionStatement(ts.factory.createBinaryExpression(
2951              varExp,
2952              ts.factory.createToken(ts.SyntaxKind.EqualsToken),
2953              ts.factory.createIdentifier($$_NEW_VALUE)
2954            ))], false)
2955        ))], false);
2956}
2957
2958function generateObjectForDollar(varExp: ts.Expression): ts.ObjectLiteralExpression {
2959  return ts.factory.createObjectLiteralExpression(
2960    [
2961      ts.factory.createPropertyAssignment(
2962        ts.factory.createIdentifier($$_VALUE),
2963        varExp
2964      ),
2965      ts.factory.createPropertyAssignment(
2966        ts.factory.createIdentifier($$_CHANGE_EVENT),
2967        createArrowFunctionForDollar(varExp)
2968      )
2969    ],
2970    false
2971  );
2972}
2973
2974function createViewStackProcessor(item, endViewStack: boolean): ts.ExpressionStatement {
2975  const argument: ts.StringLiteral[] = [];
2976  if (!endViewStack && item.name) {
2977    argument.push(ts.factory.createStringLiteral(item.name.getText()));
2978  }
2979  return ts.factory.createExpressionStatement(ts.factory.createCallExpression(
2980    ts.factory.createPropertyAccessExpression(
2981      ts.factory.createIdentifier(VIEW_STACK_PROCESSOR),
2982      ts.factory.createIdentifier(VISUAL_STATE)
2983    ),
2984    undefined,
2985    argument
2986  ));
2987}
2988
2989function traverseStateStylesAttr(temp, statements: ts.Statement[],
2990  identifierNode: ts.Identifier, log: LogInfo[], updateStatements: ts.Statement[],
2991  newImmutableStatements: ts.Statement[] = null, isRecycleComponent: boolean = false): void {
2992  temp.arguments[0].properties.reverse().forEach((item: ts.PropertyAssignment) => {
2993    if (ts.isPropertyAccessExpression(item.initializer) &&
2994      item.initializer.expression.getText() === THIS &&
2995      INNER_STYLE_FUNCTION.get(item.initializer.name.getText())) {
2996      const name: string = item.initializer.name.getText();
2997      bindComponentAttr(INNER_STYLE_FUNCTION.get(name).statements[0] as ts.ExpressionStatement,
2998        identifierNode, statements, log, false, true, newImmutableStatements);
2999      if (isRecycleComponent) {
3000        bindComponentAttr(INNER_STYLE_FUNCTION.get(name).statements[0] as ts.ExpressionStatement,
3001          identifierNode, updateStatements, log, false, true, newImmutableStatements);
3002      }
3003    } else if (ts.isIdentifier(item.initializer) &&
3004      GLOBAL_STYLE_FUNCTION.get(item.initializer.getText())) {
3005      const name: string = item.initializer.getText();
3006      bindComponentAttr(GLOBAL_STYLE_FUNCTION.get(name).statements[0] as ts.ExpressionStatement,
3007        identifierNode, statements, log, false, true, newImmutableStatements);
3008      if (isRecycleComponent) {
3009        bindComponentAttr(GLOBAL_STYLE_FUNCTION.get(name).statements[0] as ts.ExpressionStatement,
3010          identifierNode, updateStatements, log, false, true, newImmutableStatements);
3011      }
3012    } else if (ts.isObjectLiteralExpression(item.initializer) &&
3013      item.initializer.properties.length === 1 &&
3014      ts.isPropertyAssignment(item.initializer.properties[0])) {
3015      bindComponentAttr(ts.factory.createExpressionStatement(
3016        item.initializer.properties[0].initializer), identifierNode, statements, log, false, true,
3017      newImmutableStatements);
3018      if (isRecycleComponent) {
3019        bindComponentAttr(ts.factory.createExpressionStatement(
3020          item.initializer.properties[0].initializer), identifierNode, updateStatements, log, false, true,
3021        newImmutableStatements);
3022      }
3023    } else {
3024      if (!(ts.isObjectLiteralExpression(item.initializer) && item.initializer.properties.length === 0)) {
3025        validateStateStyleSyntax(temp, log);
3026      }
3027    }
3028    if (item.name) {
3029      const viewNode: ts.Statement = createViewStackProcessor(item, false);
3030      statements.push(viewNode);
3031      if (isRecycleComponent) {
3032        updateStatements.push(viewNode);
3033      }
3034    }
3035  });
3036}
3037
3038interface ExtendType {
3039  type: string
3040}
3041
3042function isExtendFunctionNode(identifierNode: ts.Identifier, propName: string,
3043  extendType: ExtendType): boolean {
3044  const componentName: string = identifierNode.escapedText.toString();
3045  if (EXTEND_ATTRIBUTE.has(componentName) && [...EXTEND_ATTRIBUTE.get(componentName)].includes(propName)) {
3046    extendType.type = CHECK_COMPONENT_EXTEND_DECORATOR;
3047    return true;
3048  }
3049  const animatableExtendAttribute: Map<string, Set<string>> =
3050    storedFileInfo.getCurrentArkTsFile().animatableExtendAttribute;
3051  if (animatableExtendAttribute.has(componentName) &&
3052    [...animatableExtendAttribute.get(componentName)].includes(propName)) {
3053    extendType.type = CHECK_COMPONENT_ANIMATABLE_EXTEND_DECORATOR;
3054    return true;
3055  }
3056  return false;
3057}
3058
3059const gestureMap: Map<string, string> = new Map([
3060  [PRIORITY_GESTURE_ATTRIBUTE, GESTURE_ENUM_VALUE_HIGH],
3061  [PARALLEL_GESTURE_ATTRIBUTE, GESTURE_ENUM_VALUE_PARALLEL],
3062  [GESTURE_ATTRIBUTE, GESTURE_ENUM_VALUE_LOW]
3063]);
3064
3065function parseGesture(node: ts.CallExpression, propName: string, statements: ts.Statement[],
3066  log: LogInfo[], updateStatements: ts.Statement[]): void {
3067  const popNode: ts.Statement = ts.factory.createExpressionStatement(
3068    createFunction(ts.factory.createIdentifier(COMPONENT_GESTURE),
3069      ts.factory.createIdentifier(COMPONENT_POP_FUNCTION), null));
3070  statements.push(popNode);
3071  updateStatements.push(popNode);
3072  parseGestureInterface(node, statements, log, updateStatements);
3073  const argumentArr: ts.NodeArray<ts.PropertyAccessExpression> = ts.factory.createNodeArray(
3074    [ts.factory.createPropertyAccessExpression(
3075      ts.factory.createIdentifier(GESTURE_ENUM_KEY),
3076      ts.factory.createIdentifier(gestureMap.get(propName)))
3077    ]
3078  );
3079  if (node.arguments && node.arguments.length > 1 &&
3080    ts.isPropertyAccessExpression(node.arguments[1])) {
3081    // @ts-ignore
3082    argumentArr.push(node.arguments[1]);
3083  }
3084  const createNode: ts.Statement = ts.factory.createExpressionStatement(
3085    createFunction(ts.factory.createIdentifier(COMPONENT_GESTURE),
3086      ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION), argumentArr));
3087  statements.push(createNode);
3088  updateStatements.push(createNode);
3089}
3090
3091function processGestureType(node: ts.CallExpression, statements: ts.Statement[], log: LogInfo[],
3092  updateStatements: ts.Statement[], reverse: boolean = false): void {
3093  const newStatements: ts.Statement[] = [];
3094  const newNode: ts.ExpressionStatement = ts.factory.createExpressionStatement(node);
3095  let temp = node.expression;
3096  while (temp && !ts.isIdentifier(temp) && temp.expression) {
3097    temp = temp.expression;
3098  }
3099  if (temp && temp.parent && ts.isCallExpression(temp.parent) && ts.isIdentifier(temp) &&
3100    GESTURE_TYPE_NAMES.has(temp.escapedText.toString())) {
3101    newStatements.push(ts.factory.createExpressionStatement(
3102      createFunction(temp, ts.factory.createIdentifier(COMPONENT_POP_FUNCTION), null)));
3103    if (temp.escapedText.toString() === COMPONENT_GESTURE_GROUP) {
3104      const gestureStatements: ts.Statement[] = [];
3105      parseGestureInterface(temp.parent, gestureStatements, log, [], true);
3106      newStatements.push(...gestureStatements.reverse());
3107      bindComponentAttr(newNode, temp, newStatements, log, false);
3108      let argumentArr: ts.NodeArray<ts.Expression> = null;
3109      if (temp.parent.arguments && temp.parent.arguments.length) {
3110        // @ts-ignore
3111        argumentArr = ts.factory.createNodeArray([temp.parent.arguments[0]]);
3112      }
3113      newStatements.push(ts.factory.createExpressionStatement(
3114        createFunction(temp, ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION), argumentArr)));
3115    } else {
3116      bindComponentAttr(newNode, temp, newStatements, log, false);
3117      newStatements.push(ts.factory.createExpressionStatement(
3118        createFunction(temp, ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION), temp.parent.arguments)));
3119    }
3120  }
3121  if (newStatements.length) {
3122    reverse ? statements.push(...newStatements.reverse()) : statements.push(...newStatements);
3123    reverse ? updateStatements.push(...newStatements.reverse()) : updateStatements.push(...newStatements);
3124  }
3125}
3126
3127function parseGestureInterface(node: ts.CallExpression, statements: ts.Statement[], log: LogInfo[],
3128  updateStatements: ts.Statement[], reverse: boolean = false): void {
3129  if (node.arguments && node.arguments.length) {
3130    node.arguments.forEach((item: ts.Node) => {
3131      if (ts.isCallExpression(item)) {
3132        processGestureType(item, statements, log, updateStatements, reverse);
3133      }
3134    });
3135  }
3136}
3137
3138export function getName(node: ts.ExpressionStatement | ts.Expression): string {
3139  // @ts-ignore
3140  let temp = node.expression;
3141  let name: string;
3142  while (temp) {
3143    if (ts.isIdentifier(temp) && temp.parent && (ts.isCallExpression(temp.parent) ||
3144      ts.isEtsComponentExpression(temp.parent))) {
3145      name = temp.escapedText.toString();
3146      break;
3147    } else if (ts.isPropertyAccessExpression(temp) && temp.name && ts.isIdentifier(temp.name) &&
3148      isCustomAttributes(temp)) {
3149      name = temp.name.escapedText.toString();
3150      break;
3151    }
3152    temp = temp.expression;
3153  }
3154  return name;
3155}
3156
3157function isCustomAttributes(temp: ts.PropertyAccessExpression): boolean {
3158  if (temp.expression && temp.expression.getText() === THIS) {
3159    return true;
3160  } else if (temp.expression && ts.isIdentifier(temp.expression) && temp.expression.getText() === $$ &&
3161    builderTypeParameter.params.includes(temp.expression.getText())) {
3162    return true;
3163  } else {
3164    return !BUILDIN_STYLE_NAMES.has(temp.name.escapedText.toString());
3165  }
3166}
3167
3168export function isAttributeNode(node: ts.ExpressionStatement): boolean {
3169  let temp: any = node.expression;
3170  let name: string;
3171  while (temp) {
3172    if (ts.isCallExpression(temp) && temp.expression && ts.isIdentifier(temp.expression)) {
3173      name = temp.expression.escapedText.toString();
3174      break;
3175    }
3176    temp = temp.expression;
3177  }
3178  return BUILDIN_STYLE_NAMES.has(name);
3179}
3180
3181enum ComponentType {
3182  innerComponent,
3183  customComponent,
3184  forEachComponent,
3185  customBuilderMethod,
3186  builderParamMethod,
3187  function,
3188  builderTypeFunction,
3189  repeatComponent
3190}
3191
3192function isEtsComponent(node: ts.ExpressionStatement): boolean {
3193  let isEtsComponent: boolean = false;
3194  let temp: any = node.expression;
3195  while (temp) {
3196    if (ts.isEtsComponentExpression(temp)) {
3197      isEtsComponent = true;
3198    }
3199    temp = temp.expression;
3200  }
3201  return isEtsComponent;
3202}
3203
3204function isSomeName(forEachParameters: ts.NodeArray<ts.ParameterDeclaration>, name: string): boolean {
3205  return Array.isArray(forEachParameters) &&
3206    forEachParameters.some((item) => {
3207      return ts.isIdentifier(item.name) ? item.name.escapedText.toString() === name : false;
3208    });
3209}
3210
3211function isParamFunction(node: ts.ExpressionStatement): boolean {
3212  return node.expression && ts.isCallExpression(node.expression) &&
3213    node.expression.expression && ts.isIdentifier(node.expression.expression);
3214}
3215
3216function getComponentType(node: ts.ExpressionStatement, log: LogInfo[], name: string,
3217  parent: string, forEachParameters: ts.NodeArray<ts.ParameterDeclaration> = undefined): ComponentType {
3218  let isBuilderName: boolean = true;
3219  if (forEachParameters && isSomeName(forEachParameters, name) && isParamFunction(node)) {
3220    isBuilderName = false;
3221  }
3222  if (isEtsComponent(node)) {
3223    if (componentCollection.customComponents.has(name)) {
3224      return ComponentType.customComponent;
3225    } else {
3226      return ComponentType.innerComponent;
3227    }
3228  } else if (!isPartMethod(node) && componentCollection.customComponents.has(name)) {
3229    return ComponentType.customComponent;
3230  } else if (name === COMPONENT_FOREACH || name === COMPONENT_LAZYFOREACH) {
3231    return ComponentType.forEachComponent;
3232  } else if (name === COMPONENT_REPEAT) {
3233    return ComponentType.repeatComponent;
3234  } else if (CUSTOM_BUILDER_METHOD.has(name) && isBuilderName || isWrappedBuilderExpression(node)) {
3235    return ComponentType.customBuilderMethod;
3236  } else if (builderParamObjectCollection.get(componentCollection.currentClassName) &&
3237    builderParamObjectCollection.get(componentCollection.currentClassName).has(name)) {
3238    return ComponentType.builderParamMethod;
3239  } else if (!partialUpdateConfig.builderCheck && builderTypeParameter.params.includes(name) &&
3240    judgeBuilderType(node)) {
3241    return ComponentType.builderTypeFunction;
3242  } else if ((['XComponent'].includes(parent) || CUSTOM_BUILDER_METHOD.has(parent)) &&
3243    ts.isCallExpression(node.expression) && ts.isIdentifier(node.expression.expression)) {
3244    return ComponentType.function;
3245  } else if (!isAttributeNode(node)) {
3246    log.push({
3247      type: LogType.ERROR,
3248      message: `'${node.getText()}' does not meet UI component syntax.`,
3249      pos: node.getStart()
3250    });
3251  }
3252  return null;
3253}
3254
3255function isPartMethod(node: ts.ExpressionStatement): boolean {
3256  if (ts.isCallExpression(node.expression) && ts.isPropertyAccessExpression(node.expression.expression) &&
3257    node.expression.expression.expression && node.expression.expression.expression.kind &&
3258    node.expression.expression.expression.kind === ts.SyntaxKind.ThisKeyword) {
3259    return true;
3260  } else {
3261    return false;
3262  }
3263}
3264
3265function isWrappedBuilderExpression(node: ts.ExpressionStatement): boolean {
3266  if (projectConfig.minAPIVersion >= 11 && node.expression &&
3267    isWrappedBuilderCallExpression(node.expression as ts.CallExpression)) {
3268    return true;
3269  }
3270  return false;
3271}
3272
3273function judgeBuilderType(node: ts.ExpressionStatement): boolean {
3274  let checker: ts.TypeChecker;
3275  if (globalProgram.program) {
3276    checker = globalProgram.program.getTypeChecker();
3277  } else if (globalProgram.watchProgram) {
3278    checker = globalProgram.watchProgram.getCurrentProgram().getProgram().getTypeChecker();
3279  }
3280  if (node.expression && node.expression.expression && checker) {
3281    const type: ts.Type = checker.getTypeAtLocation(node.expression.expression);
3282    if (type && type.aliasSymbol && type.aliasSymbol.escapedName === BUILDER_TYPE) {
3283      return true;
3284    }
3285  }
3286  return false;
3287}
3288
3289export function validateStateStyleSyntax(temp, log: LogInfo[]): void {
3290  log.push({
3291    type: LogType.ERROR,
3292    message: `.stateStyles doesn't conform standard.`,
3293    pos: temp.getStart()
3294  });
3295}
3296
3297function getEtsComponentExpression(node:ts.ExpressionStatement): ts.EtsComponentExpression {
3298  let current = node.expression;
3299  while (current) {
3300    if (ts.isEtsComponentExpression(current)) {
3301      return current;
3302    }
3303    current = current.expression;
3304  }
3305  return null;
3306}
3307
3308function checkEtsAndIdInIf(node:ts.ExpressionStatement, parent: string): [ts.EtsComponentExpression, ts.Expression] {
3309  let current = node.expression;
3310  let idName: ts.Expression;
3311  while (current) {
3312    if (ts.isEtsComponentExpression(current)) {
3313      break;
3314    }
3315    if (!idName && parent === COMPONENT_IF && ts.isPropertyAccessExpression(current) && current.name &&
3316      ts.isIdentifier(current.name) && current.name.escapedText.toString() === ATTRIBUTE_ID &&
3317      current.parent && current.parent.arguments && current.parent.arguments.length) {
3318      idName = current.parent.arguments[0];
3319    }
3320    current = current.expression;
3321  }
3322  return [current, idName];
3323}
3324
3325function checkIdInIf(node:ts.ExpressionStatement, parent: string): ts.Expression {
3326  let current: any = node.expression;
3327  let idName: ts.Expression;
3328  while (current) {
3329    if (parent === COMPONENT_IF && ts.isPropertyAccessExpression(current) && current.name &&
3330      ts.isIdentifier(current.name) && current.name.escapedText.toString() === ATTRIBUTE_ID &&
3331      current.parent && current.parent.arguments && current.parent.arguments.length) {
3332      idName = current.parent.arguments[0];
3333      break;
3334    }
3335    current = current.expression;
3336  }
3337  return idName;
3338}
3339
3340function checkEtsComponent(node: ts.ExpressionStatement, log: LogInfo[]): void {
3341  const etsComponentExpression: ts.EtsComponentExpression = getEtsComponentExpression(node);
3342  if (etsComponentExpression) {
3343    checkAllNode(
3344      etsComponentExpression,
3345      new Set([...INNER_COMPONENT_NAMES, ...componentCollection.customComponents]),
3346      transformLog.sourceFile,
3347      log
3348    );
3349  }
3350}
3351
3352function checkButtonParamHasLabel(node: ts.EtsComponentExpression, log: LogInfo[]): void {
3353  if (node.arguments && node.arguments.length !== 0) {
3354    for (let i = 0; i < node.arguments.length; i++) {
3355      const argument: ts.Expression = node.arguments[i];
3356      if (ts.isStringLiteral(argument) || (ts.isCallExpression(argument) && ts.isIdentifier(argument.expression) &&
3357        (argument.expression.escapedText.toString() === RESOURCE))) {
3358        log.push({
3359          type: LogType.ERROR,
3360          message: 'The Button component with a label parameter can not have any child.',
3361          pos: node.getStart()
3362        });
3363        return;
3364      }
3365    }
3366  }
3367}
3368
3369function isLazyForEachChild(node: ts.ExpressionStatement): boolean {
3370  let temp = node.parent;
3371  while (temp && !ts.isEtsComponentExpression(temp) && !ts.isCallExpression(temp)) {
3372    temp = temp.parent;
3373  }
3374  if (temp && temp.expression && (temp.expression as ts.Identifier).escapedText?.toString() === COMPONENT_LAZYFOREACH) {
3375    return true;
3376  }
3377  return false;
3378}
3379
3380function processDollarEtsComponent(argumentsArr: ts.NodeArray<ts.Expression>, name: string): ts.Expression[] {
3381  const arr: ts.Expression[] = [];
3382  argumentsArr.forEach((item: ts.Expression, index: number) => {
3383    if (ts.isObjectLiteralExpression(item) && item.properties && item.properties.length) {
3384      const properties: ts.PropertyAssignment[] = [];
3385      item.properties.forEach((param: ts.PropertyAssignment, paramIndex: number) => {
3386        if (isHaveDoubleDollar(param, name)) {
3387          const varExp: ts.Expression = updateArgumentForDollar(param.initializer);
3388          properties.push(ts.factory.updatePropertyAssignment(param, param.name, generateObjectForDollar(varExp)));
3389        } else {
3390          properties.push(param);
3391        }
3392      });
3393      arr.push(ts.factory.updateObjectLiteralExpression(item, properties));
3394    } else {
3395      arr.push(item);
3396    }
3397  });
3398  return arr;
3399}
3400
3401export function createFunction(node: ts.Identifier, attrNode: ts.Identifier,
3402  argumentsArr: ts.NodeArray<ts.Expression>, isAttributeModifier: boolean = false): ts.CallExpression {
3403    const compName: string = node.escapedText.toString();
3404    const type: string = attrNode.escapedText.toString();
3405  if (argumentsArr && argumentsArr.length) {
3406    if (type === COMPONENT_CREATE_FUNCTION && PROPERTIES_ADD_DOUBLE_DOLLAR.has(compName)) {
3407      // @ts-ignore
3408      argumentsArr = processDollarEtsComponent(argumentsArr, compName);
3409    }
3410    if (checkCreateArgumentBuilder(node, attrNode)) {
3411      argumentsArr = transformBuilder(argumentsArr);
3412    }
3413    if (compName === NAVIGATION && type === COMPONENT_CREATE_FUNCTION && partialUpdateConfig.partialUpdateMode) {
3414      // @ts-ignore
3415      argumentsArr = navigationCreateParam(compName, type, argumentsArr);
3416    }
3417  } else {
3418    // @ts-ignore
3419    argumentsArr = navigationCreateParam(compName, type);
3420  }
3421  return ts.factory.createCallExpression(
3422    isAttributeModifier ? ts.factory.createCallExpression(
3423      ts.factory.createPropertyAccessExpression(
3424        ts.factory.createPropertyAccessExpression(
3425          node,
3426          attrNode
3427        ),
3428        ts.factory.createIdentifier(BUILDER_ATTR_BIND)
3429      ),
3430      undefined,
3431      [ts.factory.createThis()]
3432    ) : 
3433      ts.factory.createPropertyAccessExpression(
3434        node,
3435        attrNode
3436      ),
3437    undefined,
3438    argumentsArr
3439  );
3440}
3441
3442function navigationCreateParam(compName: string, type: string,
3443  argumentsArr: ts.NodeArray<ts.Expression> = undefined, isNavDestinationCallback: boolean = false):
3444  (ts.ObjectLiteralExpression | ts.NewExpression | ts.ArrowFunction)[] | [] {
3445  const navigationOrNavDestination: (ts.ObjectLiteralExpression | ts.NewExpression | ts.ArrowFunction)[] = [];
3446  const isCreate: boolean = type === COMPONENT_CREATE_FUNCTION;
3447  const partialUpdateMode: boolean = partialUpdateConfig.partialUpdateMode;
3448  let isHaveParam: boolean = true;
3449  if (argumentsArr && argumentsArr.length) {
3450    // @ts-ignore
3451    navigationOrNavDestination.push(...argumentsArr);
3452  } else if (partialUpdateMode && isCreate) {
3453    if (compName === NAVIGATION) {
3454      isHaveParam = false;
3455      navigationOrNavDestination.push(ts.factory.createNewExpression(
3456        ts.factory.createIdentifier(NAV_PATH_STACK), undefined, []
3457      ));
3458    } else if (compName === NAV_DESTINATION && !isNavDestinationCallback) {
3459      navigationOrNavDestination.push(ts.factory.createArrowFunction(
3460        undefined, undefined, [], undefined,
3461        ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
3462        ts.factory.createBlock(
3463          [],
3464          false
3465        )
3466      ));
3467    } 
3468  }
3469  if (CREATE_ROUTER_COMPONENT_COLLECT.has(compName) && isCreate && partialUpdateMode) {
3470    navigationOrNavDestination.push(ts.factory.createObjectLiteralExpression(
3471      navigationOrNavDestinationCreateContent(compName, isHaveParam),
3472      false
3473    ));
3474  }
3475  return navigationOrNavDestination;
3476}
3477
3478function navigationOrNavDestinationCreateContent(compName: string, isHaveParam: boolean): ts.PropertyAssignment[] {
3479  const navigationOrNavDestinationContent: ts.PropertyAssignment[] = [];
3480  navigationOrNavDestinationContent.push(ts.factory.createPropertyAssignment(
3481    ts.factory.createIdentifier(RESOURCE_NAME_MODULE),
3482    ts.factory.createStringLiteral(projectConfig.moduleName || '')
3483  ),
3484    ts.factory.createPropertyAssignment(
3485      ts.factory.createIdentifier(PAGE_PATH),
3486      ts.factory.createStringLiteral(
3487        projectConfig.compileHar ? '' :
3488          path.relative(projectConfig.projectRootPath || '', resourceFileName).replace(/\\/g, '/').replace(/\.ets$/, '')
3489      )
3490  ));
3491  if (compName === NAVIGATION) {
3492    navigationOrNavDestinationContent.push(ts.factory.createPropertyAssignment(
3493      ts.factory.createIdentifier(IS_USER_CREATE_STACK),
3494      isHaveParam ? ts.factory.createTrue() : ts.factory.createFalse()
3495    ));
3496  }
3497  return navigationOrNavDestinationContent;
3498}
3499
3500function checkCreateArgumentBuilder(node: ts.Identifier, attrNode: ts.Identifier): boolean {
3501  if (attrNode.escapedText.toString() === COMPONENT_CREATE_FUNCTION &&
3502    CREATE_BIND_COMPONENT.has(node.escapedText.toString())) {
3503    return true;
3504  }
3505  return false;
3506}
3507
3508function transformBuilder(argumentsArr: ts.NodeArray<ts.Expression>): ts.NodeArray<ts.Expression> {
3509  const newArguments: ts.Expression[] = [];
3510  argumentsArr.forEach((argument: ts.Expression) => {
3511    newArguments.push(parseCreateParameterBuilder(argument));
3512  });
3513  // @ts-ignore
3514  return newArguments;
3515}
3516
3517function parseCreateParameterBuilder(argument: ts.Expression):ts.Expression {
3518  if (ts.isObjectLiteralExpression(argument)) {
3519    return processObjectPropertyBuilder(argument);
3520  } else {
3521    return argument;
3522  }
3523}
3524
3525function checkNonspecificParents(node: ts.ExpressionStatement, name: string, savedParent: string, log: LogInfo[]): void {
3526  if (SPECIFIC_PARENT_COMPONENT.has(name)) {
3527    const specificParemtsSet: Set<string> = SPECIFIC_PARENT_COMPONENT.get(name);
3528    if (!specificParemtsSet.has(savedParent) && INNER_COMPONENT_NAMES.has(savedParent)) {
3529      const specificParentArray: string =
3530        Array.from(SPECIFIC_PARENT_COMPONENT.get(name)).join(',');
3531      log.push({
3532        type: LogType.ERROR,
3533        message: `The '${name}' component can only be nested in the '${specificParentArray}' parent component.`,
3534        pos: node.expression.getStart()
3535      });
3536    }
3537  }
3538}
3539