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