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