• 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 
16 import ts from 'typescript';
17 
18 import {
19   COMPONENT_STATE_DECORATOR,
20   COMPONENT_PROVIDE_DECORATOR,
21   COMPONENT_LINK_DECORATOR,
22   COMPONENT_PROP_DECORATOR,
23   COMPONENT_STORAGE_LINK_DECORATOR,
24   COMPONENT_STORAGE_PROP_DECORATOR,
25   COMPONENT_OBJECT_LINK_DECORATOR,
26   COMPONENT_CONSUME_DECORATOR,
27   SYNCHED_PROPERTY_NESED_OBJECT,
28   SYNCHED_PROPERTY_SIMPLE_TWO_WAY,
29   SYNCHED_PROPERTY_SIMPLE_ONE_WAY,
30   OBSERVED_PROPERTY_OBJECT,
31   OBSERVED_PROPERTY_SIMPLE,
32   COMPONENT_BUILD_FUNCTION,
33   BASE_COMPONENT_NAME,
34   CREATE_CONSTRUCTOR_PARAMS,
35   COMPONENT_CONSTRUCTOR_UPDATE_PARAMS,
36   COMPONENT_CONSTRUCTOR_INITIAL_PARAMS,
37   COMPONENT_CONSTRUCTOR_PURGE_VARIABLE_DEP,
38   COMPONENT_CONSTRUCTOR_DELETE_PARAMS,
39   COMPONENT_DECORATOR_PREVIEW,
40   CREATE_CONSTRUCTOR_SUBSCRIBER_MANAGER,
41   ABOUT_TO_BE_DELETE_FUNCTION_ID,
42   ABOUT_TO_BE_DELETE_FUNCTION_ID__,
43   CREATE_CONSTRUCTOR_GET_FUNCTION,
44   CREATE_CONSTRUCTOR_DELETE_FUNCTION,
45   FOREACH_OBSERVED_OBJECT,
46   FOREACH_GET_RAW_OBJECT,
47   COMPONENT_BUILDER_DECORATOR,
48   COMPONENT_TRANSITION_FUNCTION,
49   COMPONENT_CREATE_FUNCTION,
50   GEOMETRY_VIEW,
51   COMPONENT_STYLES_DECORATOR,
52   STYLES,
53   INTERFACE_NAME_SUFFIX,
54   OBSERVED_PROPERTY_ABSTRACT,
55   COMPONENT_LOCAL_STORAGE_LINK_DECORATOR,
56   COMPONENT_LOCAL_STORAGE_PROP_DECORATOR,
57   COMPONENT_CONSTRUCTOR_LOCALSTORAGE,
58   COMPONENT_SET_AND_LINK,
59   COMPONENT_SET_AND_PROP,
60   COMPONENT_CONSTRUCTOR_UNDEFINED,
61   CUSTOM_COMPONENT,
62   COMPONENT_CONSTRUCTOR_PARENT,
63   NULL,
64   INNER_COMPONENT_MEMBER_DECORATORS,
65   COMPONENT_RERENDER_FUNCTION,
66   RMELMTID,
67   ABOUTTOBEDELETEDINTERNAL,
68   UPDATEDIRTYELEMENTS,
69   LINKS_DECORATORS,
70   BASE_COMPONENT_NAME_PU,
71   OBSERVED_PROPERTY_SIMPLE_PU,
72   OBSERVED_PROPERTY_OBJECT_PU,
73   SYNCHED_PROPERTY_SIMPLE_TWO_WAY_PU,
74   SYNCHED_PROPERTY_SIMPLE_ONE_WAY_PU,
75   SYNCHED_PROPERTY_NESED_OBJECT_PU,
76   OBSERVED_PROPERTY_ABSTRACT_PU,
77   CREATE_LOCAL_STORAGE_LINK,
78   CREATE_LOCAL_STORAGE_PROP,
79   COMPONENT_UPDATE_STATE_VARS,
80   COMPONENT_WATCH_DECORATOR,
81   $$,
82   COMPONENT_UPDATE_ELMT_ID,
83   OLD_ELMT_ID,
84   NEW_ELMT_ID,
85   UPDATE_RECYCLE_ELMT_ID,
86   DECORATOR_TYPE_ANY,
87   COMPONENT_CONSTRUCTOR_PARAMS,
88   COMPONENT_PARAMS_FUNCTION,
89   FUNCTION,
90   COMPONENT_PARAMS_LAMBDA_FUNCTION
91 } from './pre_define';
92 import {
93   BUILDIN_STYLE_NAMES,
94   CUSTOM_BUILDER_METHOD,
95   INNER_STYLE_FUNCTION,
96   INTERFACE_NODE_SET,
97   STYLES_ATTRIBUTE,
98   INNER_CUSTOM_BUILDER_METHOD
99 } from './component_map';
100 import {
101   componentCollection,
102   linkCollection,
103   localStorageLinkCollection,
104   localStoragePropCollection,
105   propCollection
106 } from './validate_ui_syntax';
107 import {
108   addConstructor,
109   getInitConstructor,
110   updateConstructor
111 } from './process_component_constructor';
112 import {
113   ControllerType,
114   processMemberVariableDecorators,
115   UpdateResult,
116   stateObjectCollection,
117   curPropMap,
118   decoratorParamSet,
119   isSimpleType,
120 } from './process_component_member';
121 import {
122   processComponentBuild,
123   processComponentBlock
124 } from './process_component_build';
125 import {
126   LogType,
127   LogInfo,
128   hasDecorator,
129   getPossibleBuilderTypeParameter,
130   storedFileInfo,
131 } from './utils';
132 import {
133   partialUpdateConfig,
134   globalProgram
135 } from '../main';
136 import { builderTypeParameter } from './process_ui_syntax';
137 import { isRecycle } from './process_custom_component';
138 
139 export function processComponentClass(node: ts.StructDeclaration, context: ts.TransformationContext,
140   log: LogInfo[], program: ts.Program): ts.ClassDeclaration {
141   const memberNode: ts.ClassElement[] =
142     processMembers(node.members, node.name, context, log, program, checkPreview(node));
143   return ts.factory.createClassDeclaration(undefined, node.modifiers, node.name,
144     node.typeParameters, updateHeritageClauses(node, log), memberNode);
145 }
146 
147 function checkPreview(node: ts.ClassDeclaration) {
148   let hasPreview: boolean = false;
149   if (node && node.decorators) {
150     for (let i = 0; i < node.decorators.length; i++) {
151       const name: string = node.decorators[i].getText().replace(/\([^\(\)]*\)/, '').trim();
152       if (name === COMPONENT_DECORATOR_PREVIEW) {
153         hasPreview = true;
154         break;
155       }
156     }
157   }
158   return hasPreview;
159 }
160 
161 type BuildCount = {
162   count: number;
163 }
164 
165 function processMembers(members: ts.NodeArray<ts.ClassElement>, parentComponentName: ts.Identifier,
166   context: ts.TransformationContext, log: LogInfo[], program: ts.Program, hasPreview: boolean): ts.ClassElement[] {
167   const buildCount: BuildCount = { count: 0 };
168   let ctorNode: any = getInitConstructor(members, parentComponentName);
169   const newMembers: ts.ClassElement[] = [];
170   const watchMap: Map<string, ts.Node> = new Map();
171   const updateParamsStatements: ts.Statement[] = [];
172   const stateVarsStatements: ts.Statement[] = [];
173   const purgeVariableDepStatements: ts.Statement[] = [];
174   const rerenderStatements: ts.Statement[] = [];
175   const deleteParamsStatements: ts.PropertyDeclaration[] = [];
176   const checkController: ControllerType =
177     { hasController: !componentCollection.customDialogs.has(parentComponentName.getText()) };
178   const interfaceNode = ts.factory.createInterfaceDeclaration(undefined, undefined,
179     parentComponentName.getText() + INTERFACE_NAME_SUFFIX, undefined, undefined, []);
180   members.forEach((item: ts.ClassElement) => {
181     let updateItem: ts.ClassElement;
182     if (ts.isPropertyDeclaration(item)) {
183       if (isStaticProperty(item)) {
184         newMembers.push(item);
185         validateDecorators(item, log);
186       } else {
187         addPropertyMember(item, newMembers, program, parentComponentName.getText(), log);
188         const result: UpdateResult = processMemberVariableDecorators(parentComponentName, item,
189           ctorNode, watchMap, checkController, log, program, context, hasPreview, interfaceNode);
190         if (result.isItemUpdate()) {
191           updateItem = result.getProperity();
192         } else {
193           updateItem = item;
194         }
195         if (result.getVariableGet()) {
196           newMembers.push(result.getVariableGet());
197         }
198         if (result.getVariableSet()) {
199           newMembers.push(result.getVariableSet());
200         }
201         if (result.isCtorUpdate()) {
202           ctorNode = result.getCtor();
203         }
204         if (result.getUpdateParams()) {
205           updateParamsStatements.push(result.getUpdateParams());
206         }
207         if (result.getStateVarsParams()) {
208           stateVarsStatements.push(result.getStateVarsParams());
209         }
210         if (result.isDeleteParams()) {
211           deleteParamsStatements.push(item);
212         }
213         if (result.getControllerSet()) {
214           newMembers.push(result.getControllerSet());
215         }
216         processPropertyUnchanged(result, purgeVariableDepStatements);
217       }
218     }
219     if (ts.isMethodDeclaration(item) && item.name) {
220       updateItem =
221         processComponentMethod(item, parentComponentName, context, log, buildCount);
222     }
223     if (updateItem) {
224       newMembers.push(updateItem);
225     }
226   });
227   INTERFACE_NODE_SET.add(interfaceNode);
228   validateBuildMethodCount(buildCount, parentComponentName, log);
229   validateHasController(parentComponentName, checkController, log);
230   if (storedFileInfo.getCurrentArkTsFile().recycleComponents.has(parentComponentName.getText())) {
231     newMembers.unshift(addDeleteParamsFunc(deleteParamsStatements, true));
232   }
233   newMembers.unshift(addDeleteParamsFunc(deleteParamsStatements));
234   addIntoNewMembers(newMembers, parentComponentName, updateParamsStatements,
235     purgeVariableDepStatements, rerenderStatements, stateVarsStatements);
236   if (partialUpdateConfig.partialUpdateMode) {
237     ctorNode = updateConstructor(ctorNode, [], assignParams(parentComponentName.getText()), true);
238   }
239   newMembers.unshift(addConstructor(ctorNode, watchMap, parentComponentName));
240   curPropMap.clear();
241   return newMembers;
242 }
243 
244 function assignParams(parentComponentName: string): ts.Statement[] {
245   return [ts.factory.createIfStatement(
246     ts.factory.createBinaryExpression(
247       ts.factory.createTypeOfExpression(ts.factory.createIdentifier(COMPONENT_PARAMS_LAMBDA_FUNCTION)),
248       ts.factory.createToken(ts.SyntaxKind.EqualsEqualsEqualsToken),
249       ts.factory.createStringLiteral(FUNCTION)
250     ),
251     ts.factory.createBlock(
252       [ts.factory.createExpressionStatement(ts.factory.createBinaryExpression(
253         ts.factory.createPropertyAccessExpression(
254           ts.factory.createThis(),
255           ts.factory.createIdentifier(COMPONENT_PARAMS_FUNCTION)
256         ),
257         ts.factory.createToken(ts.SyntaxKind.EqualsToken),
258         ts.factory.createIdentifier(COMPONENT_PARAMS_LAMBDA_FUNCTION)
259       ))],
260       true
261     )
262   )];
263 }
264 
265 function isStaticProperty(property: ts.PropertyDeclaration): boolean {
266   return property.modifiers && property.modifiers.length && property.modifiers.some(modifier => {
267     return modifier.kind === ts.SyntaxKind.StaticKeyword;
268   });
269 }
270 
271 function validateDecorators(item: ts.ClassElement, log: LogInfo[]): void {
272   if (item.decorators && item.decorators.length) {
273     item.decorators.map((decorator: ts.Decorator) => {
274       const decoratorName: string = decorator.getText();
275       if (INNER_COMPONENT_MEMBER_DECORATORS.has(decoratorName)) {
276         log.push({
277           type: LogType.ERROR,
278           message: `The static variable of struct cannot be used together with built-in decorators.`,
279           pos: item.getStart()
280         });
281       }
282     });
283   }
284 }
285 
286 function processPropertyUnchanged(
287   result: UpdateResult,
288   purgeVariableDepStatements: ts.Statement[]
289 ): void {
290   if (partialUpdateConfig.partialUpdateMode) {
291     if (result.getPurgeVariableDepStatement()) {
292       purgeVariableDepStatements.push(result.getPurgeVariableDepStatement());
293     }
294   }
295 }
296 
297 function addIntoNewMembers(
298   newMembers: ts.ClassElement[],
299   parentComponentName: ts.Identifier,
300   updateParamsStatements: ts.Statement[],
301   purgeVariableDepStatements: ts.Statement[],
302   rerenderStatements: ts.Statement[],
303   stateVarsStatements: ts.Statement[]
304 ): void {
305   if (partialUpdateConfig.partialUpdateMode) {
306     newMembers.unshift(
307       addInitialParamsFunc(updateParamsStatements, parentComponentName),
308       addUpdateStateVarsFunc(stateVarsStatements, parentComponentName),
309       addPurgeVariableDepFunc(purgeVariableDepStatements)
310     );
311     newMembers.push(addRerenderFunc(rerenderStatements));
312   } else {
313     newMembers.unshift(addUpdateParamsFunc(updateParamsStatements, parentComponentName));
314   }
315 }
316 
317 function addPropertyMember(item: ts.ClassElement, newMembers: ts.ClassElement[],
318   program: ts.Program, parentComponentName: string, log: LogInfo[]): void {
319   const propertyItem: ts.PropertyDeclaration = item as ts.PropertyDeclaration;
320   let decoratorName: string;
321   let updatePropertyItem: ts.PropertyDeclaration;
322   const type: ts.TypeNode = propertyItem.type;
323   if (!propertyItem.decorators || propertyItem.decorators.length === 0) {
324     updatePropertyItem = createPropertyDeclaration(propertyItem, type, true);
325     newMembers.push(updatePropertyItem);
326   } else if (propertyItem.decorators) {
327     for (let i = 0; i < propertyItem.decorators.length; i++) {
328       let newType: ts.TypeNode;
329       decoratorName = propertyItem.decorators[i].getText().replace(/\(.*\)$/, '').trim();
330       let isLocalStorage: boolean = false;
331       if (!partialUpdateConfig.partialUpdateMode) {
332         newType = createTypeReference(decoratorName, type, log, program);
333       } else {
334         newType = createTypeReferencePU(decoratorName, type, log, program);
335       }
336       if (
337         decoratorName === COMPONENT_LOCAL_STORAGE_LINK_DECORATOR ||
338         decoratorName === COMPONENT_LOCAL_STORAGE_PROP_DECORATOR
339       ) {
340         isLocalStorage = true;
341       }
342       const newUpdatePropertyItem = createPropertyDeclaration(
343         propertyItem, newType, false, isLocalStorage, parentComponentName);
344       if (!updatePropertyItem) {
345         updatePropertyItem = newUpdatePropertyItem;
346       } else if (INNER_COMPONENT_MEMBER_DECORATORS.has(decoratorName) &&
347         decoratorName !== COMPONENT_WATCH_DECORATOR) {
348         updatePropertyItem = newUpdatePropertyItem;
349       }
350     }
351     if (updatePropertyItem) {
352       newMembers.push(updatePropertyItem);
353     }
354   }
355 }
356 
357 function createPropertyDeclaration(propertyItem: ts.PropertyDeclaration, newType: ts.TypeNode | undefined,
358   normalVar: boolean, isLocalStorage: boolean = false, parentComponentName: string = null): ts.PropertyDeclaration {
359   if (typeof newType === undefined) {
360     return undefined;
361   }
362   let prefix: string = '';
363   if (!normalVar) {
364     prefix = '__';
365   }
366   const privateM: ts.ModifierToken<ts.SyntaxKind.PrivateKeyword> =
367     ts.factory.createModifier(ts.SyntaxKind.PrivateKeyword);
368   return ts.factory.updatePropertyDeclaration(propertyItem, undefined,
369     propertyItem.modifiers || [privateM], prefix + propertyItem.name.getText(),
370     propertyItem.questionToken, newType, isLocalStorage ?
371       createLocalStroageCallExpression(propertyItem, propertyItem.name.getText(),
372         parentComponentName) : undefined);
373 }
374 
375 function createLocalStroageCallExpression(node: ts.PropertyDeclaration, name: string,
376   parentComponentName: string): ts.CallExpression {
377   const localStorageLink: Set<string> = localStorageLinkCollection.get(parentComponentName).get(name);
378   const localStorageProp: Set<string> = localStoragePropCollection.get(parentComponentName).get(name);
379   let localFuncName: string;
380   const localValue: ts.Expression[] = [
381     ts.factory.createStringLiteral(localStorageLink && !localStorageProp ?
382       Array.from(localStorageLink)[0] : !localStorageLink && localStorageProp ?
383         Array.from(localStorageProp)[0] : COMPONENT_CONSTRUCTOR_UNDEFINED),
384     node.initializer ? node.initializer : ts.factory.createNumericLiteral(COMPONENT_CONSTRUCTOR_UNDEFINED),
385     ts.factory.createThis(), ts.factory.createStringLiteral(name || COMPONENT_CONSTRUCTOR_UNDEFINED)
386   ];
387   if (!partialUpdateConfig.partialUpdateMode) {
388     localFuncName = localStorageLink && !localStorageProp ? COMPONENT_SET_AND_LINK :
389       COMPONENT_SET_AND_PROP;
390   } else {
391     localFuncName = localStorageLink && !localStorageProp ? CREATE_LOCAL_STORAGE_LINK :
392       CREATE_LOCAL_STORAGE_PROP;
393     localValue.splice(-2, 1);
394   }
395   return ts.factory.createCallExpression(
396     ts.factory.createPropertyAccessExpression(
397       !partialUpdateConfig.partialUpdateMode ?
398         ts.factory.createPropertyAccessExpression(
399           ts.factory.createThis(),
400           ts.factory.createIdentifier(`${COMPONENT_CONSTRUCTOR_LOCALSTORAGE}_`)
401         ) : ts.factory.createThis(),
402       ts.factory.createIdentifier(localFuncName)
403     ),
404     [node.type],
405     localValue
406   );
407 }
408 
409 function processComponentMethod(node: ts.MethodDeclaration, parentComponentName: ts.Identifier,
410   context: ts.TransformationContext, log: LogInfo[], buildCount: BuildCount): ts.MethodDeclaration {
411   let updateItem: ts.MethodDeclaration = node;
412   const name: string = node.name.getText();
413   const customBuilder: ts.Decorator[] = [];
414   if (name === COMPONENT_BUILD_FUNCTION) {
415     buildCount.count = buildCount.count + 1;
416     if (node.parameters.length) {
417       log.push({
418         type: LogType.ERROR,
419         message: `The 'build' method can not have arguments.`,
420         pos: node.getStart()
421       });
422     }
423     const buildNode: ts.MethodDeclaration = processComponentBuild(node, log);
424     updateItem = processBuildMember(buildNode, context, log);
425   } else if (node.body && ts.isBlock(node.body)) {
426     if (name === COMPONENT_TRANSITION_FUNCTION) {
427       updateItem = ts.factory.updateMethodDeclaration(node, node.decorators, node.modifiers,
428         node.asteriskToken, node.name, node.questionToken, node.typeParameters, node.parameters,
429         node.type, processComponentBlock(node.body, false, log, true));
430     } else if (hasDecorator(node, COMPONENT_BUILDER_DECORATOR, customBuilder)) {
431       CUSTOM_BUILDER_METHOD.add(name);
432       INNER_CUSTOM_BUILDER_METHOD.add(name);
433       builderTypeParameter.params = getPossibleBuilderTypeParameter(node.parameters);
434       let parameters: ts.NodeArray<ts.ParameterDeclaration> = ts.factory.createNodeArray(Array.from(node.parameters));
435       parameters.push(createParentParameter());
436       const builderNode: ts.MethodDeclaration = ts.factory.updateMethodDeclaration(node, customBuilder,
437         node.modifiers, node.asteriskToken, node.name, node.questionToken, node.typeParameters,
438         parameters, node.type, processComponentBlock(node.body, false, log, false, true));
439       builderTypeParameter.params = [];
440       updateItem = processBuildMember(builderNode, context, log, true);
441     } else if (hasDecorator(node, COMPONENT_STYLES_DECORATOR)) {
442       if (node.parameters && node.parameters.length === 0) {
443         if (ts.isBlock(node.body) && node.body.statements && node.body.statements.length) {
444           INNER_STYLE_FUNCTION.set(name, node.body);
445           STYLES_ATTRIBUTE.add(name);
446           BUILDIN_STYLE_NAMES.add(name);
447           decoratorParamSet.add(STYLES);
448         }
449       } else {
450         log.push({
451           type: LogType.ERROR,
452           message: `@Styles can't have parameters.`,
453           pos: node.getStart()
454         });
455       }
456       return;
457     }
458   }
459   return updateItem;
460 }
461 
462 export function createParentParameter(): ts.ParameterDeclaration {
463   return ts.factory.createParameterDeclaration(undefined, undefined, undefined,
464     ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARENT), undefined, undefined,
465     ts.factory.createIdentifier(NULL));
466 }
467 
468 export function processBuildMember(node: ts.MethodDeclaration | ts.FunctionDeclaration, context: ts.TransformationContext,
469   log: LogInfo[], isBuilder = false): ts.MethodDeclaration | ts.FunctionDeclaration {
470   return ts.visitNode(node, visitBuild);
471   function visitBuild(node: ts.Node): ts.Node {
472     if (isGeometryView(node)) {
473       node = processGeometryView(node as ts.ExpressionStatement, log);
474     }
475     if (isProperty(node)) {
476       node = createReference(node as ts.PropertyAssignment, log, isBuilder);
477     }
478     if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.name) &&
479       stateObjectCollection.has(checkStateName(node)) && node.parent && ts.isCallExpression(node.parent) &&
480       ts.isPropertyAccessExpression(node.parent.expression) && node !== node.parent.expression &&
481       node.parent.expression.name.escapedText.toString() !== FOREACH_GET_RAW_OBJECT) {
482       return ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(
483         ts.factory.createIdentifier(FOREACH_OBSERVED_OBJECT),
484         ts.factory.createIdentifier(FOREACH_GET_RAW_OBJECT)), undefined, [node]);
485     }
486     return ts.visitEachChild(node, visitBuild, context);
487   }
488   function checkStateName(node: ts.PropertyAccessExpression): string {
489     if (node.expression && !node.expression.expression && node.name && ts.isIdentifier(node.name)) {
490       return node.name.escapedText.toString();
491     }
492     return null;
493   }
494 }
495 
496 function isGeometryView(node: ts.Node): boolean {
497   if (ts.isExpressionStatement(node) && ts.isCallExpression(node.expression)) {
498     const call: ts.CallExpression = node.expression;
499     const exp: ts.Expression = call.expression;
500     const args: ts.NodeArray<ts.Expression> = call.arguments;
501     if (ts.isPropertyAccessExpression(exp) && ts.isIdentifier(exp.expression) &&
502       exp.expression.escapedText.toString() === GEOMETRY_VIEW && ts.isIdentifier(exp.name) &&
503       exp.name.escapedText.toString() === COMPONENT_CREATE_FUNCTION && args && args.length === 1 &&
504       (ts.isArrowFunction(args[0]) || ts.isFunctionExpression(args[0]))) {
505       return true;
506     }
507   }
508   return false;
509 }
510 
511 function processGeometryView(node: ts.ExpressionStatement,
512   log: LogInfo[]): ts.ExpressionStatement {
513   const exp: ts.CallExpression = node.expression as ts.CallExpression;
514   const arg: ts.ArrowFunction | ts.FunctionExpression =
515     exp.arguments[0] as ts.ArrowFunction | ts.FunctionExpression;
516   return ts.factory.updateExpressionStatement(node, ts.factory.updateCallExpression(exp,
517     exp.expression, undefined, [ts.factory.createArrowFunction(undefined, undefined, arg.parameters,
518       undefined, ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
519       getGeometryReaderFunctionBlock(arg, log))]));
520 }
521 
522 function getGeometryReaderFunctionBlock(node: ts.ArrowFunction | ts.FunctionExpression,
523   log: LogInfo[]): ts.Block {
524   let blockNode: ts.Block;
525   if (ts.isBlock(node.body)) {
526     blockNode = node.body;
527   } else if (ts.isArrowFunction(node) && ts.isCallExpression(node.body)) {
528     blockNode = ts.factory.createBlock([ts.factory.createExpressionStatement(node.body)]);
529   }
530   return processComponentBlock(blockNode, false, log);
531 }
532 
533 function updateHeritageClauses(node: ts.StructDeclaration, log: LogInfo[])
534   : ts.NodeArray<ts.HeritageClause> {
535   if (node.heritageClauses && !checkHeritageClauses(node)) {
536     log.push({
537       type: LogType.ERROR,
538       message: 'The struct component is not allowed to extends other class or implements other interface.',
539       pos: node.heritageClauses.pos
540     });
541   }
542   const result:ts.HeritageClause[] = [];
543   const heritageClause:ts.HeritageClause = createHeritageClause();
544   result.push(heritageClause);
545   return ts.factory.createNodeArray(result);
546 }
547 
548 function checkHeritageClauses(node: ts.StructDeclaration): boolean {
549   if (node.heritageClauses.length === 1 && node.heritageClauses[0].types &&
550     node.heritageClauses[0].types.length === 1) {
551     const expressionNode: ts.ExpressionWithTypeArguments = node.heritageClauses[0].types[0];
552     if (expressionNode.expression && ts.isIdentifier(expressionNode.expression) &&
553       expressionNode.expression.escapedText.toString() === CUSTOM_COMPONENT) {
554       return true;
555     }
556   }
557   return false;
558 }
559 
560 export function isProperty(node: ts.Node): Boolean {
561   if (judgmentParentType(node)) {
562     if (node.parent.parent.expression && ts.isIdentifier(node.parent.parent.expression) &&
563       !BUILDIN_STYLE_NAMES.has(node.parent.parent.expression.escapedText.toString()) &&
564       componentCollection.customComponents.has(
565         node.parent.parent.expression.escapedText.toString())) {
566       return true;
567     } else if (ts.isPropertyAccessExpression(node.parent.parent.expression) &&
568       ts.isIdentifier(node.parent.parent.expression.expression) &&
569       componentCollection.customComponents.has(
570         node.parent.parent.expression.name.escapedText.toString())) {
571       return true;
572     }
573   }
574   return false;
575 }
576 
577 function judgmentParentType(node: ts.Node): boolean {
578   return ts.isPropertyAssignment(node) && node.name && ts.isIdentifier(node.name) &&
579     node.parent && ts.isObjectLiteralExpression(node.parent) && node.parent.parent &&
580     (ts.isCallExpression(node.parent.parent) || ts.isEtsComponentExpression(node.parent.parent));
581 }
582 
583 export function createReference(node: ts.PropertyAssignment, log: LogInfo[], isBuilder = false,
584   isParamsLambda: boolean = false, isRecycleComponent: boolean = false): ts.PropertyAssignment {
585   const linkParentComponent: string[] = getParentNode(node, linkCollection).slice(1);
586   const propParentComponent: string[] = getParentNode(node, propCollection).slice(1);
587   const propertyName: ts.Identifier = node.name as ts.Identifier;
588   let initText: string;
589   const LINK_REG: RegExp = /^\$/g;
590   if (isRecycleComponent && ts.isShorthandPropertyAssignment(node)) {
591     return node;
592   }
593   const initExpression: ts.Expression = node.initializer;
594   let is$$: boolean = false;
595   if (ts.isIdentifier(initExpression) &&
596     initExpression.escapedText.toString().match(LINK_REG)) {
597     initText = initExpression.escapedText.toString().replace(LINK_REG, '');
598   } else if (ts.isPropertyAccessExpression(initExpression) && initExpression.expression &&
599     initExpression.expression.kind === ts.SyntaxKind.ThisKeyword &&
600     ts.isIdentifier(initExpression.name) && initExpression.name.escapedText.toString().match(LINK_REG)) {
601     initText = initExpression.name.escapedText.toString().replace(LINK_REG, '');
602   } else if (isBuilder && ts.isPropertyAccessExpression(initExpression) && initExpression.expression &&
603     ts.isIdentifier(initExpression.expression) && initExpression.expression.escapedText.toString() === $$ &&
604     ts.isIdentifier(initExpression.name) && linkParentComponent.includes(propertyName.escapedText.toString())) {
605     is$$ = true;
606     initText = initExpression.name.escapedText.toString();
607   } else if (isMatchInitExpression(initExpression) &&
608     linkParentComponent.includes(propertyName.escapedText.toString())) {
609     initText = initExpression.name.escapedText.toString().replace(LINK_REG, '');
610   }
611   if (initText) {
612     node = addDoubleUnderline(node, propertyName, initText, is$$, isParamsLambda, isRecycleComponent);
613   }
614   return node;
615 }
616 
617 function isMatchInitExpression(initExpression: ts.Expression): boolean {
618   return ts.isPropertyAccessExpression(initExpression) &&
619     initExpression.expression &&
620     initExpression.expression.kind === ts.SyntaxKind.ThisKeyword &&
621     ts.isIdentifier(initExpression.name);
622 }
623 
624 function addDoubleUnderline(node: ts.PropertyAssignment, propertyName: ts.Identifier,
625   initText: string, is$$ = false, isParamsLambda: boolean, isRecycleComponent: boolean): ts.PropertyAssignment {
626   return ts.factory.updatePropertyAssignment(node, propertyName,
627     ts.factory.createPropertyAccessExpression(
628       is$$ && partialUpdateConfig.partialUpdateMode ? ts.factory.createIdentifier($$) : ts.factory.createThis(),
629       isParamsLambda || isRecycleComponent ? ts.factory.createIdentifier(initText) : ts.factory.createIdentifier(`__${initText}`)));
630 }
631 
632 function getParentNode(node: ts.PropertyAssignment, collection: Map<string, Set<string>>): string[] {
633   const grandparentNode: ts.NewExpression = node.parent.parent as ts.NewExpression;
634   const grandparentExpression: ts.Identifier | ts.PropertyAccessExpression =
635     grandparentNode.expression as ts.Identifier | ts.PropertyAccessExpression;
636   let parentComponent: Set<string> = new Set();
637   let grandparentName: string;
638   if (ts.isIdentifier(grandparentExpression)) {
639     grandparentName = grandparentExpression.escapedText.toString();
640     parentComponent = collection.get(grandparentName);
641   } else if (ts.isPropertyAccessExpression(grandparentExpression)) {
642     grandparentName = grandparentExpression.name.escapedText.toString();
643     parentComponent = collection.get(grandparentName);
644   } else {
645     // ignore
646   }
647   if (!parentComponent) {
648     parentComponent = new Set();
649   }
650   return [grandparentName, ...parentComponent];
651 }
652 
653 function addUpdateParamsFunc(statements: ts.Statement[], parentComponentName: ts.Identifier):
654   ts.MethodDeclaration {
655   return createParamsInitBlock(COMPONENT_CONSTRUCTOR_UPDATE_PARAMS, statements, parentComponentName);
656 }
657 
658 function addInitialParamsFunc(statements: ts.Statement[], parentComponentName: ts.Identifier): ts.MethodDeclaration {
659   return createParamsInitBlock(COMPONENT_CONSTRUCTOR_INITIAL_PARAMS, statements, parentComponentName);
660 }
661 
662 function addUpdateStateVarsFunc(statements: ts.Statement[], parentComponentName: ts.Identifier): ts.MethodDeclaration {
663   return createParamsInitBlock(COMPONENT_UPDATE_STATE_VARS, statements, parentComponentName);
664 }
665 
666 function addPurgeVariableDepFunc(statements: ts.Statement[]): ts.MethodDeclaration {
667   return ts.factory.createMethodDeclaration(
668     undefined, undefined, undefined,
669     ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PURGE_VARIABLE_DEP),
670     undefined, undefined, [ts.factory.createParameterDeclaration(undefined, undefined, undefined,
671       ts.factory.createIdentifier(RMELMTID), undefined, undefined, undefined)], undefined,
672       ts.factory.createBlock(statements, true));
673 }
674 
675 function addDeleteParamsFunc(statements: ts.PropertyDeclaration[],
676   updateRecyle: boolean = false): ts.MethodDeclaration {
677   const deleteStatements: ts.ExpressionStatement[] = [];
678   const updateStatements: ts.ExpressionStatement[] = [];
679   statements.forEach((statement: ts.PropertyDeclaration) => {
680     const name: ts.Identifier = statement.name as ts.Identifier;
681     let paramsStatement: ts.ExpressionStatement;
682     if (!partialUpdateConfig.partialUpdateMode || statement.decorators) {
683       paramsStatement = createParamsWithUnderlineStatement(name);
684     }
685     if (partialUpdateConfig.partialUpdateMode && statement.decorators) {
686       updateStatements.push(createElmtIdWithUnderlineStatement(name));
687     }
688     deleteStatements.push(paramsStatement);
689   });
690   if (partialUpdateConfig.partialUpdateMode && updateRecyle) {
691     return createRecycleElmt(updateStatements);
692   }
693   const defaultStatement: ts.ExpressionStatement =
694     ts.factory.createExpressionStatement(ts.factory.createCallExpression(
695       ts.factory.createPropertyAccessExpression(
696         ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(
697           ts.factory.createIdentifier(CREATE_CONSTRUCTOR_SUBSCRIBER_MANAGER),
698           ts.factory.createIdentifier(CREATE_CONSTRUCTOR_GET_FUNCTION)), undefined, []),
699         ts.factory.createIdentifier(CREATE_CONSTRUCTOR_DELETE_FUNCTION)),
700       undefined, [ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(
701         ts.factory.createThis(), ts.factory.createIdentifier(
702             !partialUpdateConfig.partialUpdateMode ?
703               ABOUT_TO_BE_DELETE_FUNCTION_ID : ABOUT_TO_BE_DELETE_FUNCTION_ID__)),
704       undefined, [])]));
705   deleteStatements.push(defaultStatement);
706   if (partialUpdateConfig.partialUpdateMode) {
707     const aboutToBeDeletedInternalStatement: ts.ExpressionStatement = createDeletedInternalStatement();
708     deleteStatements.push(aboutToBeDeletedInternalStatement);
709   }
710   const deleteParamsMethod: ts.MethodDeclaration =
711     createParamsInitBlock(COMPONENT_CONSTRUCTOR_DELETE_PARAMS, deleteStatements);
712   return deleteParamsMethod;
713 }
714 
715 function createRecycleElmt(statements: ts.Statement[]): ts.MethodDeclaration {
716   return ts.factory.createMethodDeclaration(undefined, undefined, undefined,
717     ts.factory.createIdentifier(UPDATE_RECYCLE_ELMT_ID), undefined, undefined, [
718       ts.factory.createParameterDeclaration(undefined, undefined, undefined,
719         ts.factory.createIdentifier(OLD_ELMT_ID)),
720       ts.factory.createParameterDeclaration(undefined, undefined, undefined,
721         ts.factory.createIdentifier(NEW_ELMT_ID))
722     ], undefined, ts.factory.createBlock(statements, true));
723 }
724 
725 function createParamsWithUnderlineStatement(name: ts.Identifier): ts.ExpressionStatement {
726   return ts.factory.createExpressionStatement(
727     ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(
728       ts.factory.createPropertyAccessExpression(ts.factory.createThis(),
729         ts.factory.createIdentifier(`__${name.escapedText.toString()}`)),
730       ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_DELETE_PARAMS)), undefined, []));
731 }
732 
733 function createElmtIdWithUnderlineStatement(name: ts.Identifier): ts.ExpressionStatement {
734   return ts.factory.createExpressionStatement(
735     ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(
736       ts.factory.createPropertyAccessExpression(ts.factory.createThis(),
737         ts.factory.createIdentifier(`__${name.escapedText.toString()}`)),
738       ts.factory.createIdentifier(COMPONENT_UPDATE_ELMT_ID)), undefined, [
739         ts.factory.createIdentifier(OLD_ELMT_ID), ts.factory.createIdentifier(NEW_ELMT_ID)
740       ]));
741 }
742 
743 function createDeletedInternalStatement(): ts.ExpressionStatement {
744   return ts.factory.createExpressionStatement(ts.factory.createCallExpression(
745     ts.factory.createPropertyAccessExpression(ts.factory.createThis(),
746       ts.factory.createIdentifier(ABOUTTOBEDELETEDINTERNAL)), undefined, []));
747 }
748 
749 function addRerenderFunc(statements: ts.Statement[]): ts.MethodDeclaration {
750   let updateDirtyElementStatement: ts.Statement = ts.factory.createExpressionStatement(
751     ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(
752         ts.factory.createThis(), ts.factory.createIdentifier(UPDATEDIRTYELEMENTS)), undefined, []));
753   statements.push(updateDirtyElementStatement);
754   return ts.factory.createMethodDeclaration(undefined, undefined, undefined,
755     ts.factory.createIdentifier(COMPONENT_RERENDER_FUNCTION), undefined, undefined, [], undefined,
756     ts.factory.createBlock(statements, true));
757 }
758 
759 function createParamsInitBlock(express: string, statements: ts.Statement[],
760   parentComponentName?: ts.Identifier): ts.MethodDeclaration {
761   const methodDeclaration: ts.MethodDeclaration = ts.factory.createMethodDeclaration(undefined,
762     undefined, undefined, ts.factory.createIdentifier(express), undefined, undefined,
763     [ts.factory.createParameterDeclaration(undefined, undefined, undefined,
764       express === COMPONENT_CONSTRUCTOR_DELETE_PARAMS ? undefined :
765         ts.factory.createIdentifier(CREATE_CONSTRUCTOR_PARAMS), undefined,
766       express === COMPONENT_CONSTRUCTOR_DELETE_PARAMS ? undefined :
767         ts.factory.createTypeReferenceNode(
768           ts.factory.createIdentifier(parentComponentName.getText() + INTERFACE_NAME_SUFFIX), undefined),
769       undefined)], undefined, ts.factory.createBlock(statements, true));
770   return methodDeclaration;
771 }
772 
773 function validateBuildMethodCount(buildCount: BuildCount, parentComponentName: ts.Identifier,
774   log: LogInfo[]): void {
775   if (buildCount.count !== 1) {
776     log.push({
777       type: LogType.ERROR,
778       message: `struct '${parentComponentName.getText()}' must be at least or at most one 'build' method.`,
779       pos: parentComponentName.getStart()
780     });
781   }
782 }
783 
784 function validateHasController(componentName: ts.Identifier, checkController: ControllerType,
785   log: LogInfo[]): void {
786   if (!checkController.hasController) {
787     log.push({
788       type: LogType.ERROR,
789       message: '@CustomDialog component should have a property of the CustomDialogController type.',
790       pos: componentName.pos
791     });
792   }
793 }
794 
795 function createHeritageClause(): ts.HeritageClause {
796   if (partialUpdateConfig.partialUpdateMode) {
797     return ts.factory.createHeritageClause(
798       ts.SyntaxKind.ExtendsKeyword,
799       [ts.factory.createExpressionWithTypeArguments(ts.factory.createIdentifier(BASE_COMPONENT_NAME_PU), [])]
800     );
801   }
802   return ts.factory.createHeritageClause(
803     ts.SyntaxKind.ExtendsKeyword,
804     [ts.factory.createExpressionWithTypeArguments(ts.factory.createIdentifier(BASE_COMPONENT_NAME), [])]
805   );
806 }
807 
808 function createTypeReference(decoratorName: string, type: ts.TypeNode, log: LogInfo[],
809   program: ts.Program): ts.TypeNode {
810   let newType: ts.TypeNode;
811   switch (decoratorName) {
812     case COMPONENT_STATE_DECORATOR:
813     case COMPONENT_PROVIDE_DECORATOR:
814       newType = ts.factory.createTypeReferenceNode(
815         isSimpleType(type, program, log)
816           ? OBSERVED_PROPERTY_SIMPLE
817           : OBSERVED_PROPERTY_OBJECT,
818         [type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)]
819       );
820       break;
821     case COMPONENT_LINK_DECORATOR:
822     case COMPONENT_CONSUME_DECORATOR:
823       newType = ts.factory.createTypeReferenceNode(
824         isSimpleType(type, program, log)
825           ? SYNCHED_PROPERTY_SIMPLE_TWO_WAY
826           : SYNCHED_PROPERTY_SIMPLE_ONE_WAY,
827         [type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)]
828       );
829       break;
830     case COMPONENT_PROP_DECORATOR:
831       newType = ts.factory.createTypeReferenceNode(
832         SYNCHED_PROPERTY_SIMPLE_ONE_WAY,
833         [type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)]
834       );
835       break;
836     case COMPONENT_OBJECT_LINK_DECORATOR:
837       newType = ts.factory.createTypeReferenceNode(
838         SYNCHED_PROPERTY_NESED_OBJECT,
839         [type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)]
840       );
841       break;
842     case COMPONENT_STORAGE_PROP_DECORATOR:
843     case COMPONENT_STORAGE_LINK_DECORATOR:
844       newType = ts.factory.createTypeReferenceNode(OBSERVED_PROPERTY_ABSTRACT, [
845         type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword),
846       ]);
847       break;
848     case COMPONENT_LOCAL_STORAGE_LINK_DECORATOR:
849     case COMPONENT_LOCAL_STORAGE_PROP_DECORATOR:
850       newType = ts.factory.createTypeReferenceNode(OBSERVED_PROPERTY_ABSTRACT, [
851         type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword),
852       ]);
853       break;
854   }
855   return newType;
856 }
857 
858 function createTypeReferencePU(decoratorName: string, type: ts.TypeNode, log: LogInfo[],
859   program: ts.Program): ts.TypeNode {
860   let newType: ts.TypeNode;
861   switch (decoratorName) {
862     case COMPONENT_STATE_DECORATOR:
863     case COMPONENT_PROVIDE_DECORATOR:
864       newType = ts.factory.createTypeReferenceNode(
865         isSimpleType(type, program, log)
866           ? OBSERVED_PROPERTY_SIMPLE_PU
867           : OBSERVED_PROPERTY_OBJECT_PU,
868         [type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)]
869       );
870       break;
871     case COMPONENT_LINK_DECORATOR:
872       newType = ts.factory.createTypeReferenceNode(
873         isSimpleType(type, program, log)
874           ? SYNCHED_PROPERTY_SIMPLE_TWO_WAY_PU
875           : SYNCHED_PROPERTY_SIMPLE_ONE_WAY_PU,
876         [type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)]
877       );
878       break;
879     case COMPONENT_PROP_DECORATOR:
880       newType = ts.factory.createTypeReferenceNode(
881         SYNCHED_PROPERTY_SIMPLE_ONE_WAY_PU,
882         [type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)]
883       );
884       break;
885     case COMPONENT_OBJECT_LINK_DECORATOR:
886       newType = ts.factory.createTypeReferenceNode(
887         SYNCHED_PROPERTY_NESED_OBJECT_PU,
888         [type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)]
889       );
890       break;
891     case COMPONENT_CONSUME_DECORATOR:
892     case COMPONENT_STORAGE_PROP_DECORATOR:
893     case COMPONENT_STORAGE_LINK_DECORATOR:
894       newType = ts.factory.createTypeReferenceNode(OBSERVED_PROPERTY_ABSTRACT_PU, [
895         type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword),
896       ]);
897       break;
898     case COMPONENT_LOCAL_STORAGE_LINK_DECORATOR:
899     case COMPONENT_LOCAL_STORAGE_PROP_DECORATOR:
900       newType = ts.factory.createTypeReferenceNode(OBSERVED_PROPERTY_ABSTRACT_PU, [
901         type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword),
902       ]);
903       break;
904   }
905   return newType;
906 }
907