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