• 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';
17
18import {
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  BASE_COMPONENT_NAME_PU,
70  OBSERVED_PROPERTY_SIMPLE_PU,
71  OBSERVED_PROPERTY_OBJECT_PU,
72  SYNCHED_PROPERTY_SIMPLE_TWO_WAY_PU,
73  SYNCHED_PROPERTY_SIMPLE_ONE_WAY_PU,
74  SYNCHED_PROPERTY_NESED_OBJECT_PU,
75  OBSERVED_PROPERTY_ABSTRACT_PU,
76  CREATE_LOCAL_STORAGE_LINK,
77  CREATE_LOCAL_STORAGE_PROP,
78  COMPONENT_UPDATE_STATE_VARS,
79  COMPONENT_WATCH_DECORATOR,
80  $$,
81  COMPONENT_UPDATE_ELMT_ID,
82  OLD_ELMT_ID,
83  NEW_ELMT_ID,
84  UPDATE_RECYCLE_ELMT_ID,
85  GET_ENTRYNAME,
86  COMPONENT_PARAMS_FUNCTION,
87  FUNCTION,
88  COMPONENT_PARAMS_LAMBDA_FUNCTION,
89  DECORATOR_COMPONENT_FREEZEWHENINACTIVE,
90  INIT_ALLOW_COMPONENT_FREEZE,
91  FINALIZE_CONSTRUCTION,
92  PROTOTYPE,
93  REFLECT,
94  CREATE_SET_METHOD,
95  COMPONENT_REQUIRE_DECORATOR,
96  CONTEXT_STACK,
97  COMPONENT_IF_UNDEFINED,
98  COMPONENT_POP_FUNCTION,
99  PUSH,
100  PUV2_VIEW_BASE,
101  COMPONENT_LOCAL_BUILDER_DECORATOR
102} from './pre_define';
103import {
104  BUILDIN_STYLE_NAMES,
105  CUSTOM_BUILDER_METHOD,
106  INNER_STYLE_FUNCTION,
107  INTERFACE_NODE_SET,
108  STYLES_ATTRIBUTE,
109  INNER_CUSTOM_BUILDER_METHOD
110} from './component_map';
111import {
112  componentCollection,
113  linkCollection,
114  localStorageLinkCollection,
115  localStoragePropCollection,
116  builderParamObjectCollection
117} from './validate_ui_syntax';
118import {
119  addConstructor,
120  getInitConstructor,
121  updateConstructor
122} from './process_component_constructor';
123import {
124  ControllerType,
125  processMemberVariableDecorators,
126  UpdateResult,
127  stateObjectCollection,
128  curPropMap,
129  decoratorParamSet,
130  isSimpleType,
131  isSingleKey,
132  findDecoratorIndex
133} from './process_component_member';
134import {
135  processComponentBuild,
136  processComponentBlock
137} from './process_component_build';
138import {
139  LogType,
140  LogInfo,
141  hasDecorator,
142  getPossibleBuilderTypeParameter,
143  storedFileInfo,
144  removeDecorator
145} from './utils';
146import {
147  partialUpdateConfig,
148  projectConfig
149} from '../main';
150import {
151  builderTypeParameter,
152  initializeMYIDS,
153  globalBuilderParamAssignment
154} from './process_ui_syntax';
155import constantDefine from './constant_define';
156
157export function processComponentClass(node: ts.StructDeclaration, context: ts.TransformationContext,
158  log: LogInfo[], program: ts.Program): ts.ClassDeclaration {
159  const decoratorNode: readonly ts.Decorator[] = ts.getAllDecorators(node);
160  const memberNode: ts.ClassElement[] =
161    processMembers(node.members, node.name, context, decoratorNode, log, program, checkPreview(node));
162  return ts.factory.createClassDeclaration(ts.getModifiers(node), node.name,
163    node.typeParameters, updateHeritageClauses(node, log), memberNode);
164}
165
166function checkPreview(node: ts.StructDeclaration): boolean {
167  let hasPreview: boolean = false;
168  const decorators: readonly ts.Decorator[] = ts.getAllDecorators(node);
169  if (node && decorators) {
170    for (let i = 0; i < decorators.length; i++) {
171      const name: string = decorators[i].getText().replace(/\([^\(\)]*\)/, '').trim();
172      if (name === COMPONENT_DECORATOR_PREVIEW) {
173        hasPreview = true;
174        break;
175      }
176    }
177  }
178  return hasPreview;
179}
180
181export type BuildCount = {
182  count: number;
183};
184export type FreezeParamType = {
185  componentFreezeParam: ts.Expression;
186};
187function processMembers(members: ts.NodeArray<ts.ClassElement>, parentComponentName: ts.Identifier,
188  context: ts.TransformationContext, decoratorNode: readonly ts.Decorator[], log: LogInfo[],
189  program: ts.Program, hasPreview: boolean): ts.ClassElement[] {
190  const buildCount: BuildCount = { count: 0 };
191  let ctorNode: any = getInitConstructor(members, parentComponentName);
192  const newMembers: ts.ClassElement[] = [];
193  const watchMap: Map<string, ts.Node> = new Map();
194  const updateParamsStatements: ts.Statement[] = [];
195  const stateVarsStatements: ts.Statement[] = [];
196  const purgeVariableDepStatements: ts.Statement[] = [];
197  const rerenderStatements: ts.Statement[] = [];
198  const deleteParamsStatements: ts.PropertyDeclaration[] = [];
199  const checkController: ControllerType =
200    { hasController: !componentCollection.customDialogs.has(parentComponentName.getText()) };
201  const interfaceNode = ts.factory.createInterfaceDeclaration(undefined,
202    parentComponentName.getText() + INTERFACE_NAME_SUFFIX, undefined, undefined, []);
203  members.forEach((item: ts.ClassElement) => {
204    let updateItem: ts.ClassElement;
205    if (ts.isPropertyDeclaration(item)) {
206      if (isStaticProperty(item)) {
207        newMembers.push(item);
208        validateDecorators(item, log);
209      } else {
210        addPropertyMember(item, newMembers, program, parentComponentName.getText(), log);
211        const result: UpdateResult = processMemberVariableDecorators(parentComponentName, item,
212          ctorNode, watchMap, checkController, log, program, context, hasPreview, interfaceNode);
213        if (result.isItemUpdate()) {
214          updateItem = result.getProperity();
215        } else {
216          updateItem = item;
217        }
218        if (result.getVariableGet()) {
219          newMembers.push(result.getVariableGet());
220        }
221        if (result.getVariableSet()) {
222          newMembers.push(result.getVariableSet());
223        }
224        if (result.isCtorUpdate()) {
225          ctorNode = result.getCtor();
226        }
227        if (result.getUpdateParams()) {
228          updateParamsStatements.push(result.getUpdateParams());
229        }
230        if (result.getStateVarsParams()) {
231          stateVarsStatements.push(result.getStateVarsParams());
232        }
233        if (result.isDeleteParams()) {
234          deleteParamsStatements.push(item);
235        }
236        if (result.getControllerSet()) {
237          newMembers.push(result.getControllerSet());
238        }
239        processPropertyUnchanged(result, purgeVariableDepStatements);
240      }
241    }
242    if (ts.isMethodDeclaration(item) && item.name) {
243      updateItem =
244        processComponentMethod(item, context, log, buildCount);
245    }
246    if (updateItem) {
247      newMembers.push(updateItem);
248    }
249  });
250  INTERFACE_NODE_SET.add(interfaceNode);
251  validateBuildMethodCount(buildCount, parentComponentName, log);
252  validateHasController(parentComponentName, checkController, log);
253  if (storedFileInfo.getCurrentArkTsFile().recycleComponents.has(parentComponentName.getText())) {
254    newMembers.unshift(addDeleteParamsFunc(deleteParamsStatements, true));
255  }
256  newMembers.unshift(addDeleteParamsFunc(deleteParamsStatements));
257  addIntoNewMembers(newMembers, parentComponentName, updateParamsStatements,
258    purgeVariableDepStatements, rerenderStatements, stateVarsStatements);
259  if (partialUpdateConfig.partialUpdateMode) {
260    const creezeParam: FreezeParamType = {
261      componentFreezeParam: undefined
262    };
263    const isFreezeComponent: boolean = decoratorAssignParams(decoratorNode, context, creezeParam);
264    ctorNode = updateConstructor(ctorNode, [], assignParams(parentComponentName.getText()),
265      isFreezeComponent ? decoratorComponentParam(creezeParam) : [], true);
266  }
267  newMembers.unshift(addConstructor(ctorNode, watchMap, parentComponentName));
268  if (componentCollection.entryComponent === parentComponentName.escapedText.toString() &&
269    partialUpdateConfig.partialUpdateMode && projectConfig.minAPIVersion > 10) {
270    newMembers.push(getEntryNameFunction(componentCollection.entryComponent));
271  }
272  curPropMap.clear();
273  return newMembers;
274}
275
276export function decoratorAssignParams(decoratorNode: readonly ts.Decorator[], context: ts.TransformationContext,
277  creezeParam: FreezeParamType): boolean {
278  if (decoratorNode && Array.isArray(decoratorNode) && decoratorNode.length) {
279    return decoratorNode.some((item: ts.Decorator) => {
280      if (isFreezeComponents(item, context, creezeParam)) {
281        return true;
282      } else {
283        return false;
284      }
285    });
286  } else {
287    return false;
288  }
289}
290
291function isFreezeComponents(decorator: ts.Decorator, context: ts.TransformationContext,
292  creezeParam: FreezeParamType): boolean {
293  let isComponentAssignParent: boolean = false;
294  ts.visitNode(decorator, visitComponentParament);
295  function visitComponentParament(decorator: ts.Node): ts.Node {
296    if (ts.isPropertyAssignment(decorator) && decorator.name && decorator.name.text &&
297      decorator.name.text.toString() === DECORATOR_COMPONENT_FREEZEWHENINACTIVE) {
298      isComponentAssignParent = true;
299      creezeParam.componentFreezeParam = decorator.initializer;
300      return decorator;
301    }
302    return ts.visitEachChild(decorator, visitComponentParament, context);
303  }
304  return isComponentAssignParent;
305}
306
307export function getEntryNameFunction(entryName: string): ts.MethodDeclaration {
308  return ts.factory.createMethodDeclaration(
309    [ts.factory.createToken(ts.SyntaxKind.StaticKeyword)],
310    undefined,
311    ts.factory.createIdentifier(GET_ENTRYNAME),
312    undefined,
313    undefined,
314    [],
315    ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
316    ts.factory.createBlock(
317      [ts.factory.createReturnStatement(ts.factory.createStringLiteral(entryName))],
318      true
319    )
320  );
321}
322
323function assignParams(parentComponentName: string): ts.Statement[] {
324  return [ts.factory.createIfStatement(
325    ts.factory.createBinaryExpression(
326      ts.factory.createTypeOfExpression(ts.factory.createIdentifier(COMPONENT_PARAMS_LAMBDA_FUNCTION)),
327      ts.factory.createToken(ts.SyntaxKind.EqualsEqualsEqualsToken),
328      ts.factory.createStringLiteral(FUNCTION)
329    ),
330    ts.factory.createBlock(
331      [ts.factory.createExpressionStatement(ts.factory.createBinaryExpression(
332        ts.factory.createPropertyAccessExpression(
333          ts.factory.createThis(),
334          ts.factory.createIdentifier(COMPONENT_PARAMS_FUNCTION)
335        ),
336        ts.factory.createToken(ts.SyntaxKind.EqualsToken),
337        ts.factory.createIdentifier(COMPONENT_PARAMS_LAMBDA_FUNCTION)
338      ))],
339      true
340    )
341  )];
342}
343
344function decoratorComponentParam(freezeParam: FreezeParamType): ts.IfStatement[] {
345  return [ts.factory.createIfStatement(
346    ts.factory.createBinaryExpression(
347      ts.factory.createElementAccessExpression(
348        ts.factory.createSuper(),
349        ts.factory.createStringLiteral(INIT_ALLOW_COMPONENT_FREEZE)
350      ),
351      ts.factory.createToken(ts.SyntaxKind.AmpersandAmpersandToken),
352      ts.factory.createBinaryExpression(
353        ts.factory.createTypeOfExpression(ts.factory.createElementAccessExpression(
354          ts.factory.createSuper(),
355          ts.factory.createStringLiteral(INIT_ALLOW_COMPONENT_FREEZE)
356        )),
357        ts.factory.createToken(ts.SyntaxKind.EqualsEqualsEqualsToken),
358        ts.factory.createStringLiteral(FUNCTION)
359      )
360    ),
361    ts.factory.createBlock(
362      [ts.factory.createExpressionStatement(ts.factory.createCallExpression(
363        ts.factory.createElementAccessExpression(
364          ts.factory.createSuper(),
365          ts.factory.createStringLiteral(INIT_ALLOW_COMPONENT_FREEZE)
366        ),
367        undefined,
368        [freezeParam.componentFreezeParam]
369      ))],
370      true
371    ),
372    undefined
373  )];
374}
375
376function isStaticProperty(property: ts.PropertyDeclaration): boolean {
377  const modifiers: readonly ts.Modifier[] =
378    ts.canHaveModifiers(property) ? ts.getModifiers(property) : undefined;
379  return modifiers && modifiers.length && modifiers.some(modifier => {
380    return modifier.kind === ts.SyntaxKind.StaticKeyword;
381  });
382}
383
384function validateDecorators(item: ts.ClassElement, log: LogInfo[]): void {
385  const decorators: readonly ts.Decorator[] = ts.getAllDecorators(item);
386  if (decorators && decorators.length) {
387    decorators.map((decorator: ts.Decorator) => {
388      const decoratorName: string = decorator.getText();
389      if (INNER_COMPONENT_MEMBER_DECORATORS.has(decoratorName)) {
390        log.push({
391          type: LogType.ERROR,
392          message: `The static variable of struct cannot be used together with built-in decorators.`,
393          pos: item.getStart()
394        });
395      }
396    });
397  }
398}
399
400function processPropertyUnchanged(
401  result: UpdateResult,
402  purgeVariableDepStatements: ts.Statement[]
403): void {
404  if (partialUpdateConfig.partialUpdateMode) {
405    if (result.getPurgeVariableDepStatement()) {
406      purgeVariableDepStatements.push(result.getPurgeVariableDepStatement());
407    }
408  }
409}
410
411function addIntoNewMembers(
412  newMembers: ts.ClassElement[],
413  parentComponentName: ts.Identifier,
414  updateParamsStatements: ts.Statement[],
415  purgeVariableDepStatements: ts.Statement[],
416  rerenderStatements: ts.Statement[],
417  stateVarsStatements: ts.Statement[]
418): void {
419  if (partialUpdateConfig.partialUpdateMode) {
420    newMembers.unshift(
421      addInitialParamsFunc(updateParamsStatements, parentComponentName),
422      addUpdateStateVarsFunc(stateVarsStatements, parentComponentName),
423      addPurgeVariableDepFunc(purgeVariableDepStatements)
424    );
425    newMembers.push(addRerenderFunc(rerenderStatements));
426  } else {
427    newMembers.unshift(addUpdateParamsFunc(updateParamsStatements, parentComponentName));
428  }
429}
430
431export function isRegularProperty(decorators: readonly ts.Decorator[]): boolean {
432  if (decorators && decorators.length) {
433    if (decorators.length === 1 && decorators[0].getText() === COMPONENT_REQUIRE_DECORATOR) {
434      return true;
435    }
436    return false;
437  }
438  return true;
439}
440
441function addPropertyMember(item: ts.ClassElement, newMembers: ts.ClassElement[],
442  program: ts.Program, parentComponentName: string, log: LogInfo[]): void {
443  const propertyItem: ts.PropertyDeclaration = item as ts.PropertyDeclaration;
444  let decoratorName: string;
445  let updatePropertyItem: ts.PropertyDeclaration;
446  const type: ts.TypeNode = propertyItem.type;
447  const decorators: readonly ts.Decorator[] = ts.getAllDecorators(propertyItem);
448  if (isRegularProperty(decorators)) {
449    updatePropertyItem = createPropertyDeclaration(propertyItem, type, true);
450    newMembers.push(updatePropertyItem);
451  } else {
452    for (let i = 0; i < decorators.length; i++) {
453      let newType: ts.TypeNode;
454      decoratorName = decorators[i].getText().replace(/\(.*\)$/, '').trim();
455      let isLocalStorage: boolean = false;
456      if (!partialUpdateConfig.partialUpdateMode) {
457        newType = createTypeReference(decoratorName, type, log, program);
458      } else {
459        newType = createTypeReferencePU(decoratorName, type, log, program);
460      }
461      if (
462        decoratorName === COMPONENT_LOCAL_STORAGE_LINK_DECORATOR ||
463        decoratorName === COMPONENT_LOCAL_STORAGE_PROP_DECORATOR
464      ) {
465        isLocalStorage = true;
466      }
467      const newUpdatePropertyItem = createPropertyDeclaration(
468        propertyItem, newType, false, isLocalStorage, parentComponentName);
469      if (!updatePropertyItem) {
470        updatePropertyItem = newUpdatePropertyItem;
471      } else if (INNER_COMPONENT_MEMBER_DECORATORS.has(decoratorName) &&
472        ![COMPONENT_WATCH_DECORATOR, COMPONENT_REQUIRE_DECORATOR].includes(decoratorName)) {
473        updatePropertyItem = newUpdatePropertyItem;
474      }
475    }
476    if (updatePropertyItem) {
477      newMembers.push(updatePropertyItem);
478    }
479  }
480}
481
482function createPropertyDeclaration(propertyItem: ts.PropertyDeclaration, newType: ts.TypeNode | undefined,
483  normalVar: boolean, isLocalStorage: boolean = false, parentComponentName: string = null): ts.PropertyDeclaration {
484  if (typeof newType === undefined) {
485    return undefined;
486  }
487  let prefix: string = '';
488  if (!normalVar) {
489    prefix = '__';
490  }
491  const privateM: ts.ModifierToken<ts.SyntaxKind.PrivateKeyword> =
492    ts.factory.createModifier(ts.SyntaxKind.PrivateKeyword);
493  const modifiers: readonly ts.Modifier[] =
494    ts.canHaveModifiers(propertyItem) ? ts.getModifiers(propertyItem) : undefined;
495  return ts.factory.updatePropertyDeclaration(propertyItem,
496    ts.concatenateDecoratorsAndModifiers(undefined, modifiers || [privateM]), prefix + propertyItem.name.getText(),
497    propertyItem.questionToken, newType, isLocalStorage ?
498      createLocalStroageCallExpression(propertyItem, propertyItem.name.getText(),
499        parentComponentName) : undefined);
500}
501
502function createLocalStroageCallExpression(node: ts.PropertyDeclaration, name: string,
503  parentComponentName: string): ts.CallExpression {
504  const decorators: readonly ts.Decorator[] = ts.getAllDecorators(node);
505  if (isSingleKey(node)) {
506    const localStorageLink: Set<string> = localStorageLinkCollection.get(parentComponentName).get(name);
507    const localStorageProp: Set<string> = localStoragePropCollection.get(parentComponentName).get(name);
508    let localFuncName: string;
509    const index: number = findDecoratorIndex(decorators,
510      [COMPONENT_LOCAL_STORAGE_LINK_DECORATOR, COMPONENT_LOCAL_STORAGE_PROP_DECORATOR]);
511    const localValue: ts.Expression[] = [
512      decorators[index].expression.arguments[0],
513      node.initializer ? node.initializer : ts.factory.createNumericLiteral(COMPONENT_CONSTRUCTOR_UNDEFINED),
514      ts.factory.createThis(),
515      ts.factory.createStringLiteral(name || COMPONENT_CONSTRUCTOR_UNDEFINED)
516    ];
517    if (!partialUpdateConfig.partialUpdateMode) {
518      localFuncName = localStorageLink && !localStorageProp ? COMPONENT_SET_AND_LINK :
519        COMPONENT_SET_AND_PROP;
520    } else {
521      localFuncName = localStorageLink && !localStorageProp ? CREATE_LOCAL_STORAGE_LINK :
522        CREATE_LOCAL_STORAGE_PROP;
523      localValue.splice(-2, 1);
524    }
525    return ts.factory.createCallExpression(
526      ts.factory.createPropertyAccessExpression(
527        !partialUpdateConfig.partialUpdateMode ?
528          ts.factory.createPropertyAccessExpression(
529            ts.factory.createThis(),
530            ts.factory.createIdentifier(`${COMPONENT_CONSTRUCTOR_LOCALSTORAGE}_`)
531          ) : ts.factory.createThis(),
532        ts.factory.createIdentifier(localFuncName)
533      ),
534      [node.type],
535      localValue
536    );
537  }
538  return undefined;
539}
540export interface builderConditionType {
541  isBuilder: boolean,
542  isLocalBuilder: boolean
543}
544export function processComponentMethod(node: ts.MethodDeclaration, context: ts.TransformationContext,
545  log: LogInfo[], buildCount: BuildCount): ts.MethodDeclaration {
546  let updateItem: ts.MethodDeclaration = node;
547  const name: string = node.name.getText();
548  const customBuilder: ts.Decorator[] = [];
549  const builderCondition: builderConditionType = {
550    isBuilder: false,
551    isLocalBuilder: false
552  };
553  if (builderParamObjectCollection.get(componentCollection.currentClassName)) {
554    storedFileInfo.builderLikeCollection =
555      new Set([...builderParamObjectCollection.get(componentCollection.currentClassName), ...CUSTOM_BUILDER_METHOD]);
556  } else {
557    storedFileInfo.builderLikeCollection = CUSTOM_BUILDER_METHOD;
558  }
559  if (name === COMPONENT_BUILD_FUNCTION) {
560    storedFileInfo.processBuilder = false;
561    storedFileInfo.processGlobalBuilder = false;
562    buildCount.count = buildCount.count + 1;
563    if (node.parameters.length) {
564      log.push({
565        type: LogType.ERROR,
566        message: `The 'build' method can not have arguments.`,
567        pos: node.getStart()
568      });
569    }
570    const buildNode: ts.MethodDeclaration = processComponentBuild(node, log);
571    updateItem = processBuildMember(buildNode, context, log);
572  } else if (node.body && ts.isBlock(node.body)) {
573    if (name === COMPONENT_TRANSITION_FUNCTION) {
574      updateItem = ts.factory.updateMethodDeclaration(node, ts.getModifiers(node),
575        node.asteriskToken, node.name, node.questionToken, node.typeParameters, node.parameters,
576        node.type, processComponentBlock(node.body, false, log, true));
577    } else if (isBuilderOrLocalBuilder(node, builderCondition, customBuilder)) {
578      storedFileInfo.processBuilder = true;
579      storedFileInfo.processGlobalBuilder = false;
580      if (builderCondition.isLocalBuilder) {
581        storedFileInfo.processLocalBuilder = true;
582      }
583      CUSTOM_BUILDER_METHOD.add(name);
584      INNER_CUSTOM_BUILDER_METHOD.add(name);
585      builderTypeParameter.params = getPossibleBuilderTypeParameter(node.parameters);
586      const parameters: ts.NodeArray<ts.ParameterDeclaration> = ts.factory.createNodeArray(Array.from(node.parameters));
587      if (!builderCondition.isLocalBuilder) {
588        parameters.push(createParentParameter());
589      }
590      if (projectConfig.optLazyForEach) {
591        parameters.push(initializeMYIDS());
592      }
593      const modifiers = ts.canHaveModifiers(node) ? ts.getModifiers(node) : undefined;
594      const componentBlock: ts.Block = processComponentBlock(node.body, false, log, false, true);
595      if (partialUpdateConfig.partialUpdateMode && builderCondition.isLocalBuilder &&
596        node.body.statements.length) {
597        componentBlock.statements.unshift(globalBuilderParamAssignment());
598      }
599      let builderNode: ts.MethodDeclaration | ts.PropertyDeclaration = ts.factory.updateMethodDeclaration(node,
600        ts.concatenateDecoratorsAndModifiers(removeDecorator(customBuilder, 'Builder'), modifiers),
601        node.asteriskToken, node.name, node.questionToken, node.typeParameters,
602        parameters, node.type, componentBlock);
603      builderTypeParameter.params = [];
604      updateItem = processBuildMember(builderNode, context, log, true);
605      if (builderCondition.isLocalBuilder) {
606        checkDecoratorMethod(node, modifiers, log);
607        updateItem = localBuilderNode(node, updateItem.body);
608      }
609      storedFileInfo.processBuilder = false;
610      storedFileInfo.processLocalBuilder = false;
611    } else if (hasDecorator(node, COMPONENT_STYLES_DECORATOR)) {
612      if (node.parameters && node.parameters.length === 0) {
613        if (ts.isBlock(node.body) && node.body.statements && node.body.statements.length) {
614          INNER_STYLE_FUNCTION.set(name, node.body);
615          STYLES_ATTRIBUTE.add(name);
616          BUILDIN_STYLE_NAMES.add(name);
617          decoratorParamSet.add(STYLES);
618        }
619      } else {
620        log.push({
621          type: LogType.ERROR,
622          message: `@Styles can't have parameters.`,
623          pos: node.getStart()
624        });
625      }
626      return undefined;
627    }
628  }
629  return updateItem;
630}
631
632function checkDecoratorMethod(node: ts.MethodDeclaration, modifiers: readonly ts.Modifier[], log: LogInfo[]): void {
633  if (modifiers && modifiers.length) {
634    for (let i = 0; i < modifiers.length; i++) {
635      if (modifiers[i].kind && modifiers[i].kind === ts.SyntaxKind.StaticKeyword) {
636        log.push({
637          type: LogType.ERROR,
638          message: `Static methods in custom components cannot be decorated by @LocalBuilder.`,
639          pos: node.getStart()
640        });
641        return;
642      }
643    }
644  }
645}
646
647export function isBuilderOrLocalBuilder(node: ts.MethodDeclaration | ts.FunctionDeclaration, builderCondition: builderConditionType,
648  customBuilder: ts.Decorator[] = undefined): boolean {
649  const decorators: readonly ts.Decorator[] = ts.getAllDecorators(node);
650  if (decorators && decorators.length) {
651    for (let i = 0; i < decorators.length; i++) {
652      const originalDecortor: string = decorators[i].getText().replace(/\(.*\)$/, '').replace(/\s*/g, '').trim();
653      if ([COMPONENT_LOCAL_BUILDER_DECORATOR, COMPONENT_BUILDER_DECORATOR].includes(originalDecortor)) {
654        if (originalDecortor === COMPONENT_BUILDER_DECORATOR) {
655          builderCondition.isBuilder = true;
656          if (customBuilder) {
657            customBuilder.push(...decorators.slice(i + 1), ...decorators.slice(0, i));
658          }
659        } else {
660          builderCondition.isLocalBuilder = true;
661        }
662        return true;
663      }
664    }
665  }
666  return false;
667}
668
669function localBuilderNode(node: ts.MethodDeclaration, componentBlock: ts.Block): ts.PropertyDeclaration {
670  return ts.factory.createPropertyDeclaration(
671    undefined, node.name, undefined, undefined,
672    ts.factory.createArrowFunction(
673      undefined, undefined, node.parameters ? node.parameters : [], undefined,
674      ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
675      componentBlock
676    )
677  );
678}
679
680export function createParentParameter(): ts.ParameterDeclaration {
681  return ts.factory.createParameterDeclaration(undefined, undefined,
682    ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARENT), undefined, undefined,
683    ts.factory.createIdentifier(NULL));
684}
685
686export function processBuildMember(node: ts.MethodDeclaration | ts.FunctionDeclaration, context: ts.TransformationContext,
687  log: LogInfo[], isBuilder = false): ts.MethodDeclaration | ts.FunctionDeclaration {
688  return ts.visitNode(node, visitBuild);
689  function visitBuild(node: ts.Node): ts.Node {
690    if (isGeometryView(node)) {
691      node = processGeometryView(node as ts.ExpressionStatement, log);
692    }
693    if (isProperty(node)) {
694      node = createReference(node as ts.PropertyAssignment, log, isBuilder);
695    }
696    if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.name) &&
697      stateObjectCollection.has(checkStateName(node)) && node.parent && ts.isCallExpression(node.parent) &&
698      ts.isPropertyAccessExpression(node.parent.expression) && node !== node.parent.expression &&
699      node.parent.expression.name.escapedText.toString() !== FOREACH_GET_RAW_OBJECT) {
700      return ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(
701        ts.factory.createIdentifier(FOREACH_OBSERVED_OBJECT),
702        ts.factory.createIdentifier(FOREACH_GET_RAW_OBJECT)), undefined, [node]);
703    }
704    return ts.visitEachChild(node, visitBuild, context);
705  }
706  function checkStateName(node: ts.PropertyAccessExpression): string {
707    if (node.expression && !node.expression.expression && node.name && ts.isIdentifier(node.name)) {
708      return node.name.escapedText.toString();
709    }
710    return null;
711  }
712}
713
714function isGeometryView(node: ts.Node): boolean {
715  if (ts.isExpressionStatement(node) && ts.isCallExpression(node.expression)) {
716    const call: ts.CallExpression = node.expression;
717    const exp: ts.Expression = call.expression;
718    const args: ts.NodeArray<ts.Expression> = call.arguments;
719    if (ts.isPropertyAccessExpression(exp) && ts.isIdentifier(exp.expression) &&
720      exp.expression.escapedText.toString() === GEOMETRY_VIEW && ts.isIdentifier(exp.name) &&
721      exp.name.escapedText.toString() === COMPONENT_CREATE_FUNCTION && args && args.length === 1 &&
722      (ts.isArrowFunction(args[0]) || ts.isFunctionExpression(args[0]))) {
723      return true;
724    }
725  }
726  return false;
727}
728
729function processGeometryView(node: ts.ExpressionStatement,
730  log: LogInfo[]): ts.ExpressionStatement {
731  const exp: ts.CallExpression = node.expression as ts.CallExpression;
732  const arg: ts.ArrowFunction | ts.FunctionExpression =
733    exp.arguments[0] as ts.ArrowFunction | ts.FunctionExpression;
734  return ts.factory.updateExpressionStatement(node, ts.factory.updateCallExpression(exp,
735    exp.expression, undefined, [ts.factory.createArrowFunction(undefined, undefined, arg.parameters,
736      undefined, ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
737      getGeometryReaderFunctionBlock(arg, log))]));
738}
739
740function getGeometryReaderFunctionBlock(node: ts.ArrowFunction | ts.FunctionExpression,
741  log: LogInfo[]): ts.Block {
742  let blockNode: ts.Block;
743  if (ts.isBlock(node.body)) {
744    blockNode = node.body;
745  } else if (ts.isArrowFunction(node) && ts.isCallExpression(node.body)) {
746    blockNode = ts.factory.createBlock([ts.factory.createExpressionStatement(node.body)]);
747  }
748  return processComponentBlock(blockNode, false, log);
749}
750
751export function updateHeritageClauses(node: ts.StructDeclaration, log: LogInfo[],
752  isComponentV2: boolean = false): ts.NodeArray<ts.HeritageClause> {
753  if (node.heritageClauses && !checkHeritageClauses(node)) {
754    log.push({
755      type: LogType.ERROR,
756      message: 'The struct component is not allowed to extends other class or implements other interface.',
757      pos: node.heritageClauses.pos
758    });
759  }
760  const result: ts.HeritageClause[] = [];
761  const heritageClause: ts.HeritageClause = createHeritageClause(isComponentV2);
762  result.push(heritageClause);
763  return ts.factory.createNodeArray(result);
764}
765
766function checkHeritageClauses(node: ts.StructDeclaration): boolean {
767  if (node.heritageClauses.length === 1 && node.heritageClauses[0].types &&
768    node.heritageClauses[0].types.length === 1) {
769    const expressionNode: ts.ExpressionWithTypeArguments = node.heritageClauses[0].types[0];
770    if (expressionNode.expression && ts.isIdentifier(expressionNode.expression) &&
771      expressionNode.expression.escapedText.toString() === CUSTOM_COMPONENT) {
772      return true;
773    }
774  }
775  return false;
776}
777
778export function isProperty(node: ts.Node): Boolean {
779  if (judgmentParentType(node)) {
780    if (node.parent.parent.expression && ts.isIdentifier(node.parent.parent.expression) &&
781      !BUILDIN_STYLE_NAMES.has(node.parent.parent.expression.escapedText.toString()) &&
782      componentCollection.customComponents.has(
783        node.parent.parent.expression.escapedText.toString())) {
784      return true;
785    } else if (ts.isPropertyAccessExpression(node.parent.parent.expression) &&
786      ts.isIdentifier(node.parent.parent.expression.expression) &&
787      componentCollection.customComponents.has(
788        node.parent.parent.expression.name.escapedText.toString())) {
789      return true;
790    }
791  }
792  return false;
793}
794
795function judgmentParentType(node: ts.Node): boolean {
796  return ts.isPropertyAssignment(node) && node.name && ts.isIdentifier(node.name) &&
797    node.parent && ts.isObjectLiteralExpression(node.parent) && node.parent.parent &&
798    (ts.isCallExpression(node.parent.parent) || ts.isEtsComponentExpression(node.parent.parent));
799}
800
801export function createReference(node: ts.PropertyAssignment, log: LogInfo[], isBuilder = false,
802  isParamsLambda: boolean = false, isRecycleComponent: boolean = false): ts.PropertyAssignment {
803  const linkParentComponent: string[] = getParentNode(node, linkCollection).slice(1);
804  const propertyName: ts.Identifier = node.name as ts.Identifier;
805  let initText: string;
806  const LINK_REG: RegExp = /^\$/g;
807  if (isRecycleComponent && ts.isShorthandPropertyAssignment(node)) {
808    return node;
809  }
810  const initExpression: ts.Expression = node.initializer;
811  let is$$: boolean = false;
812  if (ts.isIdentifier(initExpression) &&
813    initExpression.escapedText.toString().match(LINK_REG)) {
814    initText = initExpression.escapedText.toString().replace(LINK_REG, '');
815  } else if (ts.isPropertyAccessExpression(initExpression) && initExpression.expression &&
816    initExpression.expression.kind === ts.SyntaxKind.ThisKeyword &&
817    ts.isIdentifier(initExpression.name) && initExpression.name.escapedText.toString().match(LINK_REG)) {
818    initText = initExpression.name.escapedText.toString().replace(LINK_REG, '');
819  } else if (isBuilder && ts.isPropertyAccessExpression(initExpression) && initExpression.expression &&
820    ts.isIdentifier(initExpression.expression) && initExpression.expression.escapedText.toString() === $$ &&
821    ts.isIdentifier(initExpression.name) && linkParentComponent.includes(propertyName.escapedText.toString())) {
822    is$$ = true;
823    initText = initExpression.name.escapedText.toString();
824  } else if (isMatchInitExpression(initExpression) &&
825    linkParentComponent.includes(propertyName.escapedText.toString())) {
826    initText = initExpression.name.escapedText.toString().replace(LINK_REG, '');
827  }
828  if (initText) {
829    node = addDoubleUnderline(node, propertyName, initText, is$$, isParamsLambda, isRecycleComponent);
830  }
831  return node;
832}
833
834function isMatchInitExpression(initExpression: ts.Expression): boolean {
835  return ts.isPropertyAccessExpression(initExpression) &&
836    initExpression.expression &&
837    initExpression.expression.kind === ts.SyntaxKind.ThisKeyword &&
838    ts.isIdentifier(initExpression.name);
839}
840
841function addDoubleUnderline(node: ts.PropertyAssignment, propertyName: ts.Identifier,
842  initText: string, is$$ = false, isParamsLambda: boolean, isRecycleComponent: boolean): ts.PropertyAssignment {
843  return ts.factory.updatePropertyAssignment(node, propertyName,
844    ts.factory.createPropertyAccessExpression(
845      is$$ && partialUpdateConfig.partialUpdateMode ? ts.factory.createIdentifier($$) : ts.factory.createThis(),
846      isParamsLambda || isRecycleComponent ? ts.factory.createIdentifier(initText) : ts.factory.createIdentifier(`__${initText}`)));
847}
848
849function getParentNode(node: ts.PropertyAssignment, collection: Map<string, Set<string>>): string[] {
850  const grandparentNode: ts.NewExpression = node.parent.parent as ts.NewExpression;
851  const grandparentExpression: ts.Identifier | ts.PropertyAccessExpression =
852    grandparentNode.expression as ts.Identifier | ts.PropertyAccessExpression;
853  let parentComponent: Set<string> = new Set();
854  let grandparentName: string;
855  if (ts.isIdentifier(grandparentExpression)) {
856    grandparentName = grandparentExpression.escapedText.toString();
857    parentComponent = collection.get(grandparentName);
858  } else if (ts.isPropertyAccessExpression(grandparentExpression)) {
859    if (storedFileInfo.isAsPageImport) {
860      grandparentName = grandparentExpression.getText();
861    } else {
862      grandparentName = grandparentExpression.name.escapedText.toString();
863    }
864    parentComponent = collection.get(grandparentName);
865  } else {
866    // ignore
867  }
868  if (!parentComponent) {
869    parentComponent = new Set();
870  }
871  return [grandparentName, ...parentComponent];
872}
873
874function addUpdateParamsFunc(statements: ts.Statement[], parentComponentName: ts.Identifier):
875  ts.MethodDeclaration {
876  return createParamsInitBlock(COMPONENT_CONSTRUCTOR_UPDATE_PARAMS, statements, parentComponentName);
877}
878
879function addInitialParamsFunc(statements: ts.Statement[], parentComponentName: ts.Identifier): ts.MethodDeclaration {
880  return createParamsInitBlock(COMPONENT_CONSTRUCTOR_INITIAL_PARAMS, statements, parentComponentName);
881}
882
883function addUpdateStateVarsFunc(statements: ts.Statement[], parentComponentName: ts.Identifier): ts.MethodDeclaration {
884  return createParamsInitBlock(COMPONENT_UPDATE_STATE_VARS, statements, parentComponentName);
885}
886
887function addPurgeVariableDepFunc(statements: ts.Statement[]): ts.MethodDeclaration {
888  return ts.factory.createMethodDeclaration(
889    undefined, undefined,
890    ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PURGE_VARIABLE_DEP),
891    undefined, undefined, [ts.factory.createParameterDeclaration(undefined, undefined,
892      ts.factory.createIdentifier(RMELMTID), undefined, undefined, undefined)], undefined,
893    ts.factory.createBlock(statements, true));
894}
895
896function addDeleteParamsFunc(statements: ts.PropertyDeclaration[],
897  updateRecyle: boolean = false): ts.MethodDeclaration {
898  const deleteStatements: ts.ExpressionStatement[] = [];
899  const updateStatements: ts.ExpressionStatement[] = [];
900  statements.forEach((statement: ts.PropertyDeclaration) => {
901    const name: ts.Identifier = statement.name as ts.Identifier;
902    let paramsStatement: ts.ExpressionStatement;
903    const decorators: readonly ts.Decorator[] = ts.getAllDecorators(statement);
904    const isRegular: boolean = isRegularProperty(decorators);
905    if (!partialUpdateConfig.partialUpdateMode || !isRegular) {
906      paramsStatement = createParamsWithUnderlineStatement(name);
907    }
908    if (partialUpdateConfig.partialUpdateMode && !isRegular) {
909      updateStatements.push(createElmtIdWithUnderlineStatement(name));
910    }
911    deleteStatements.push(paramsStatement);
912  });
913  if (partialUpdateConfig.partialUpdateMode && updateRecyle) {
914    return createRecycleElmt(updateStatements);
915  }
916  const defaultStatement: ts.ExpressionStatement =
917    ts.factory.createExpressionStatement(ts.factory.createCallExpression(
918      ts.factory.createPropertyAccessExpression(
919        ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(
920          ts.factory.createIdentifier(CREATE_CONSTRUCTOR_SUBSCRIBER_MANAGER),
921          ts.factory.createIdentifier(CREATE_CONSTRUCTOR_GET_FUNCTION)), undefined, []),
922        ts.factory.createIdentifier(CREATE_CONSTRUCTOR_DELETE_FUNCTION)),
923      undefined, [ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(
924        ts.factory.createThis(), ts.factory.createIdentifier(
925          !partialUpdateConfig.partialUpdateMode ?
926            ABOUT_TO_BE_DELETE_FUNCTION_ID : ABOUT_TO_BE_DELETE_FUNCTION_ID__)),
927      undefined, [])]));
928  deleteStatements.push(defaultStatement);
929  if (partialUpdateConfig.partialUpdateMode) {
930    const aboutToBeDeletedInternalStatement: ts.ExpressionStatement = createDeletedInternalStatement();
931    deleteStatements.push(aboutToBeDeletedInternalStatement);
932  }
933  const deleteParamsMethod: ts.MethodDeclaration =
934    createParamsInitBlock(COMPONENT_CONSTRUCTOR_DELETE_PARAMS, deleteStatements);
935  return deleteParamsMethod;
936}
937
938function createRecycleElmt(statements: ts.Statement[]): ts.MethodDeclaration {
939  return ts.factory.createMethodDeclaration(undefined, undefined,
940    ts.factory.createIdentifier(UPDATE_RECYCLE_ELMT_ID), undefined, undefined, [
941      ts.factory.createParameterDeclaration(undefined, undefined,
942        ts.factory.createIdentifier(OLD_ELMT_ID)),
943      ts.factory.createParameterDeclaration(undefined, undefined,
944        ts.factory.createIdentifier(NEW_ELMT_ID))
945    ], undefined, ts.factory.createBlock(statements, true));
946}
947
948function createParamsWithUnderlineStatement(name: ts.Identifier): ts.ExpressionStatement {
949  return ts.factory.createExpressionStatement(
950    ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(
951      ts.factory.createPropertyAccessExpression(ts.factory.createThis(),
952        ts.factory.createIdentifier(`__${name.escapedText.toString()}`)),
953      ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_DELETE_PARAMS)), undefined, []));
954}
955
956function createElmtIdWithUnderlineStatement(name: ts.Identifier): ts.ExpressionStatement {
957  return ts.factory.createExpressionStatement(
958    ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(
959      ts.factory.createPropertyAccessExpression(ts.factory.createThis(),
960        ts.factory.createIdentifier(`__${name.escapedText.toString()}`)),
961      ts.factory.createIdentifier(COMPONENT_UPDATE_ELMT_ID)), undefined, [
962      ts.factory.createIdentifier(OLD_ELMT_ID), ts.factory.createIdentifier(NEW_ELMT_ID)
963    ]));
964}
965
966function createDeletedInternalStatement(): ts.ExpressionStatement {
967  return ts.factory.createExpressionStatement(ts.factory.createCallExpression(
968    ts.factory.createPropertyAccessExpression(ts.factory.createThis(),
969      ts.factory.createIdentifier(ABOUTTOBEDELETEDINTERNAL)), undefined, []));
970}
971
972export function addRerenderFunc(statements: ts.Statement[]): ts.MethodDeclaration {
973  const updateDirtyElementStatement: ts.Statement = ts.factory.createExpressionStatement(
974    ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(
975      ts.factory.createThis(), ts.factory.createIdentifier(UPDATEDIRTYELEMENTS)), undefined, []));
976  statements.push(updateDirtyElementStatement);
977  if (storedFileInfo.hasLocalBuilderInFile) {
978    statements.unshift(contextStackPushOrPop(ts.factory.createIdentifier(PUSH), [ts.factory.createThis()]));
979    statements.push(contextStackPushOrPop(ts.factory.createIdentifier(COMPONENT_POP_FUNCTION), []));
980  }
981  return ts.factory.createMethodDeclaration(undefined, undefined,
982    ts.factory.createIdentifier(COMPONENT_RERENDER_FUNCTION), undefined, undefined, [], undefined,
983    ts.factory.createBlock(statements, true));
984}
985
986function createParamsInitBlock(express: string, statements: ts.Statement[],
987  parentComponentName?: ts.Identifier): ts.MethodDeclaration {
988  const methodDeclaration: ts.MethodDeclaration = ts.factory.createMethodDeclaration(
989    undefined, undefined, ts.factory.createIdentifier(express), undefined, undefined,
990    [ts.factory.createParameterDeclaration(undefined, undefined,
991      express === COMPONENT_CONSTRUCTOR_DELETE_PARAMS ? undefined :
992        ts.factory.createIdentifier(CREATE_CONSTRUCTOR_PARAMS), undefined,
993      express === COMPONENT_CONSTRUCTOR_DELETE_PARAMS ? undefined :
994        ts.factory.createTypeReferenceNode(
995          ts.factory.createIdentifier(parentComponentName.getText() + INTERFACE_NAME_SUFFIX), undefined),
996      undefined)], undefined, ts.factory.createBlock(statements, true));
997  return methodDeclaration;
998}
999
1000export function validateBuildMethodCount(buildCount: BuildCount, parentComponentName: ts.Identifier,
1001  log: LogInfo[]): void {
1002  if (buildCount.count !== 1) {
1003    log.push({
1004      type: LogType.ERROR,
1005      message: `struct '${parentComponentName.getText()}' must be at least or at most one 'build' method.` +
1006        `Solutions:>A structurally modified page must have at least one and no more than one'build' method.`,
1007      pos: parentComponentName.getStart()
1008    });
1009  }
1010}
1011
1012function validateHasController(componentName: ts.Identifier, checkController: ControllerType,
1013  log: LogInfo[]): void {
1014  if (!checkController.hasController) {
1015    log.push({
1016      type: LogType.ERROR,
1017      message: '@CustomDialog component should have a property of the CustomDialogController type.',
1018      pos: componentName.pos
1019    });
1020  }
1021}
1022
1023function createHeritageClause(isComponentV2: boolean = false): ts.HeritageClause {
1024  if (partialUpdateConfig.partialUpdateMode) {
1025    return ts.factory.createHeritageClause(
1026      ts.SyntaxKind.ExtendsKeyword,
1027      [ts.factory.createExpressionWithTypeArguments(
1028        ts.factory.createIdentifier(isComponentV2 ? constantDefine.STRUCT_PARENT : BASE_COMPONENT_NAME_PU),
1029        [])]
1030    );
1031  }
1032  return ts.factory.createHeritageClause(
1033    ts.SyntaxKind.ExtendsKeyword,
1034    [ts.factory.createExpressionWithTypeArguments(ts.factory.createIdentifier(BASE_COMPONENT_NAME), [])]
1035  );
1036}
1037
1038function createTypeReference(decoratorName: string, type: ts.TypeNode, log: LogInfo[],
1039  program: ts.Program): ts.TypeNode {
1040  let newType: ts.TypeNode;
1041  switch (decoratorName) {
1042    case COMPONENT_STATE_DECORATOR:
1043    case COMPONENT_PROVIDE_DECORATOR:
1044      newType = ts.factory.createTypeReferenceNode(
1045        isSimpleType(type, program, log) ?
1046          OBSERVED_PROPERTY_SIMPLE :
1047          OBSERVED_PROPERTY_OBJECT,
1048        [type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)]
1049      );
1050      break;
1051    case COMPONENT_LINK_DECORATOR:
1052    case COMPONENT_CONSUME_DECORATOR:
1053      newType = ts.factory.createTypeReferenceNode(
1054        isSimpleType(type, program, log) ?
1055          SYNCHED_PROPERTY_SIMPLE_TWO_WAY :
1056          SYNCHED_PROPERTY_SIMPLE_ONE_WAY,
1057        [type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)]
1058      );
1059      break;
1060    case COMPONENT_PROP_DECORATOR:
1061      newType = ts.factory.createTypeReferenceNode(
1062        SYNCHED_PROPERTY_SIMPLE_ONE_WAY,
1063        [type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)]
1064      );
1065      break;
1066    case COMPONENT_OBJECT_LINK_DECORATOR:
1067      newType = ts.factory.createTypeReferenceNode(
1068        SYNCHED_PROPERTY_NESED_OBJECT,
1069        [type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)]
1070      );
1071      break;
1072    case COMPONENT_STORAGE_PROP_DECORATOR:
1073    case COMPONENT_STORAGE_LINK_DECORATOR:
1074      newType = ts.factory.createTypeReferenceNode(OBSERVED_PROPERTY_ABSTRACT, [
1075        type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)
1076      ]);
1077      break;
1078    case COMPONENT_LOCAL_STORAGE_LINK_DECORATOR:
1079    case COMPONENT_LOCAL_STORAGE_PROP_DECORATOR:
1080      newType = ts.factory.createTypeReferenceNode(OBSERVED_PROPERTY_ABSTRACT, [
1081        type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)
1082      ]);
1083      break;
1084  }
1085  return newType;
1086}
1087
1088function createTypeReferencePU(decoratorName: string, type: ts.TypeNode, log: LogInfo[],
1089  program: ts.Program): ts.TypeNode {
1090  let newType: ts.TypeNode;
1091  switch (decoratorName) {
1092    case COMPONENT_STATE_DECORATOR:
1093    case COMPONENT_PROVIDE_DECORATOR:
1094      newType = ts.factory.createTypeReferenceNode(
1095        isSimpleType(type, program, log) ?
1096          OBSERVED_PROPERTY_SIMPLE_PU :
1097          OBSERVED_PROPERTY_OBJECT_PU,
1098        [type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)]
1099      );
1100      break;
1101    case COMPONENT_LINK_DECORATOR:
1102      newType = ts.factory.createTypeReferenceNode(
1103        isSimpleType(type, program, log) ?
1104          SYNCHED_PROPERTY_SIMPLE_TWO_WAY_PU :
1105          SYNCHED_PROPERTY_SIMPLE_ONE_WAY_PU,
1106        [type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)]
1107      );
1108      break;
1109    case COMPONENT_PROP_DECORATOR:
1110      newType = ts.factory.createTypeReferenceNode(
1111        SYNCHED_PROPERTY_SIMPLE_ONE_WAY_PU,
1112        [type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)]
1113      );
1114      break;
1115    case COMPONENT_OBJECT_LINK_DECORATOR:
1116      newType = ts.factory.createTypeReferenceNode(
1117        SYNCHED_PROPERTY_NESED_OBJECT_PU,
1118        [type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)]
1119      );
1120      break;
1121    case COMPONENT_CONSUME_DECORATOR:
1122    case COMPONENT_STORAGE_PROP_DECORATOR:
1123    case COMPONENT_STORAGE_LINK_DECORATOR:
1124      newType = ts.factory.createTypeReferenceNode(OBSERVED_PROPERTY_ABSTRACT_PU, [
1125        type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)
1126      ]);
1127      break;
1128    case COMPONENT_LOCAL_STORAGE_LINK_DECORATOR:
1129    case COMPONENT_LOCAL_STORAGE_PROP_DECORATOR:
1130      newType = ts.factory.createTypeReferenceNode(OBSERVED_PROPERTY_ABSTRACT_PU, [
1131        type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)
1132      ]);
1133      break;
1134  }
1135  return newType;
1136}
1137
1138export function checkFinalizeConstruction(): ts.Statement {
1139  return ts.factory.createIfStatement(
1140    ts.factory.createPrefixUnaryExpression(ts.SyntaxKind.ExclamationToken,
1141      ts.factory.createParenthesizedExpression(ts.factory.createBinaryExpression(
1142        ts.factory.createStringLiteral(FINALIZE_CONSTRUCTION),
1143        ts.factory.createToken(ts.SyntaxKind.InKeyword), ts.factory.createPropertyAccessExpression(
1144          ts.factory.createIdentifier(BASE_COMPONENT_NAME_PU), ts.factory.createIdentifier(PROTOTYPE))))
1145    ),
1146    ts.factory.createBlock(
1147      [
1148        ts.factory.createExpressionStatement(ts.factory.createCallExpression(
1149          ts.factory.createPropertyAccessExpression(
1150            ts.factory.createIdentifier(REFLECT), ts.factory.createIdentifier(CREATE_SET_METHOD)
1151          ), undefined,
1152          [
1153            ts.factory.createPropertyAccessExpression(
1154              ts.factory.createIdentifier(BASE_COMPONENT_NAME_PU), ts.factory.createIdentifier(PROTOTYPE)
1155            ),
1156            ts.factory.createStringLiteral(FINALIZE_CONSTRUCTION),
1157            ts.factory.createArrowFunction(undefined, undefined, [], undefined,
1158              ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
1159              ts.factory.createBlock([], false)
1160            )
1161          ]
1162        ))
1163      ], true), undefined);
1164}
1165
1166export function checkContextStack(): ts.Statement {
1167  return ts.factory.createIfStatement(
1168    ts.factory.createBinaryExpression(
1169      ts.factory.createPropertyAccessExpression(
1170        ts.factory.createIdentifier(PUV2_VIEW_BASE),
1171        ts.factory.createIdentifier(CONTEXT_STACK)
1172      ),
1173      ts.factory.createToken(ts.SyntaxKind.EqualsEqualsEqualsToken),
1174      ts.factory.createIdentifier(COMPONENT_IF_UNDEFINED)
1175    ),
1176    ts.factory.createBlock(
1177      [ts.factory.createExpressionStatement(ts.factory.createCallExpression(
1178        ts.factory.createPropertyAccessExpression(
1179          ts.factory.createIdentifier(REFLECT),
1180          ts.factory.createIdentifier(CREATE_SET_METHOD)
1181        ),
1182        undefined,
1183        [
1184          ts.factory.createIdentifier(PUV2_VIEW_BASE),
1185          ts.factory.createStringLiteral(CONTEXT_STACK),
1186          ts.factory.createArrayLiteralExpression(
1187            [],
1188            false
1189          )
1190        ]
1191      ))],
1192      true
1193    ),
1194    undefined
1195  );
1196}
1197
1198export function contextStackPushOrPop(pushOrPop: ts.Identifier, param: ts.ThisExpression[] | []): ts.ExpressionStatement {
1199  return ts.factory.createExpressionStatement(ts.factory.createBinaryExpression(
1200    ts.factory.createPropertyAccessExpression(
1201      ts.factory.createIdentifier(PUV2_VIEW_BASE),
1202      ts.factory.createIdentifier(CONTEXT_STACK)
1203    ),
1204    ts.factory.createToken(ts.SyntaxKind.AmpersandAmpersandToken),
1205    ts.factory.createCallExpression(
1206      ts.factory.createPropertyAccessExpression(
1207        ts.factory.createPropertyAccessExpression(
1208          ts.factory.createIdentifier(PUV2_VIEW_BASE),
1209          ts.factory.createIdentifier(CONTEXT_STACK)
1210        ),
1211        pushOrPop
1212      ),
1213      undefined,
1214      param
1215    )
1216  ));
1217}
1218