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