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