• 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;
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() && ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.name) &&
734    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 isInComponentV2Context(): boolean {
740  if (componentCollection.currentClassName) {
741    const parentStructInfo: StructInfo =
742      processStructComponentV2.getOrCreateStructInfo(componentCollection.currentClassName);
743    return parentStructInfo.isComponentV2;
744  }
745  return false;
746}
747
748function isGeometryView(node: ts.Node): boolean {
749  if (ts.isExpressionStatement(node) && ts.isCallExpression(node.expression)) {
750    const call: ts.CallExpression = node.expression;
751    const exp: ts.Expression = call.expression;
752    const args: ts.NodeArray<ts.Expression> = call.arguments;
753    if (ts.isPropertyAccessExpression(exp) && ts.isIdentifier(exp.expression) &&
754      exp.expression.escapedText.toString() === GEOMETRY_VIEW && ts.isIdentifier(exp.name) &&
755      exp.name.escapedText.toString() === COMPONENT_CREATE_FUNCTION && args && args.length === 1 &&
756      (ts.isArrowFunction(args[0]) || ts.isFunctionExpression(args[0]))) {
757      return true;
758    }
759  }
760  return false;
761}
762
763function processGeometryView(node: ts.ExpressionStatement,
764  log: LogInfo[]): ts.ExpressionStatement {
765  const exp: ts.CallExpression = node.expression as ts.CallExpression;
766  const arg: ts.ArrowFunction | ts.FunctionExpression =
767    exp.arguments[0] as ts.ArrowFunction | ts.FunctionExpression;
768  return ts.factory.updateExpressionStatement(node, ts.factory.updateCallExpression(exp,
769    exp.expression, undefined, [ts.factory.createArrowFunction(undefined, undefined, arg.parameters,
770      undefined, ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
771      getGeometryReaderFunctionBlock(arg, log))]));
772}
773
774function getGeometryReaderFunctionBlock(node: ts.ArrowFunction | ts.FunctionExpression,
775  log: LogInfo[]): ts.Block {
776  let blockNode: ts.Block;
777  if (ts.isBlock(node.body)) {
778    blockNode = node.body;
779  } else if (ts.isArrowFunction(node) && ts.isCallExpression(node.body)) {
780    blockNode = ts.factory.createBlock([ts.factory.createExpressionStatement(node.body)]);
781  }
782  return processComponentBlock(blockNode, false, log);
783}
784
785export function updateHeritageClauses(node: ts.StructDeclaration, log: LogInfo[],
786  isComponentV2: boolean = false): ts.NodeArray<ts.HeritageClause> {
787  if (node.heritageClauses && !checkHeritageClauses(node)) {
788    log.push({
789      type: LogType.ERROR,
790      message: 'Structs are not allowed to inherit from classes or implement interfaces.',
791      pos: node.heritageClauses.pos,
792      code: '10905212'
793    });
794  }
795  const result: ts.HeritageClause[] = [];
796  const heritageClause: ts.HeritageClause = createHeritageClause(isComponentV2);
797  result.push(heritageClause);
798  return ts.factory.createNodeArray(result);
799}
800
801function checkHeritageClauses(node: ts.StructDeclaration): boolean {
802  if (node.heritageClauses.length === 1 && node.heritageClauses[0].types &&
803    node.heritageClauses[0].types.length === 1) {
804    const expressionNode: ts.ExpressionWithTypeArguments = node.heritageClauses[0].types[0];
805    if (expressionNode.expression && ts.isIdentifier(expressionNode.expression) &&
806      expressionNode.expression.escapedText.toString() === CUSTOM_COMPONENT) {
807      return true;
808    }
809  }
810  return false;
811}
812
813export function isProperty(node: ts.Node): Boolean {
814  if (judgmentParentType(node)) {
815    if (node.parent.parent.expression && ts.isIdentifier(node.parent.parent.expression) &&
816      !BUILDIN_STYLE_NAMES.has(node.parent.parent.expression.escapedText.toString()) &&
817      componentCollection.customComponents.has(
818        node.parent.parent.expression.escapedText.toString())) {
819      return true;
820    } else if (ts.isPropertyAccessExpression(node.parent.parent.expression) &&
821      ts.isIdentifier(node.parent.parent.expression.expression) &&
822      componentCollection.customComponents.has(
823        node.parent.parent.expression.name.escapedText.toString())) {
824      return true;
825    }
826  }
827  return false;
828}
829
830function judgmentParentType(node: ts.Node): boolean {
831  return ts.isPropertyAssignment(node) && node.name && ts.isIdentifier(node.name) &&
832    node.parent && ts.isObjectLiteralExpression(node.parent) && node.parent.parent &&
833    (ts.isCallExpression(node.parent.parent) || ts.isEtsComponentExpression(node.parent.parent));
834}
835
836export function createReference(node: ts.PropertyAssignment, log: LogInfo[], isBuilder = false,
837  isParamsLambda: boolean = false, isRecycleComponent: boolean = false): ts.PropertyAssignment {
838  const linkParentComponent: string[] = getParentNode(node, linkCollection).slice(1);
839  const propertyName: ts.Identifier = node.name as ts.Identifier;
840  let initText: string;
841  const LINK_REG: RegExp = /^\$/g;
842  if (isRecycleComponent && ts.isShorthandPropertyAssignment(node)) {
843    return node;
844  }
845  const initExpression: ts.Expression = node.initializer;
846  let is$$: boolean = false;
847  if (ts.isIdentifier(initExpression) &&
848    initExpression.escapedText.toString().match(LINK_REG)) {
849    initText = initExpression.escapedText.toString().replace(LINK_REG, '');
850  } else if (ts.isPropertyAccessExpression(initExpression) && initExpression.expression &&
851    initExpression.expression.kind === ts.SyntaxKind.ThisKeyword &&
852    ts.isIdentifier(initExpression.name) && initExpression.name.escapedText.toString().match(LINK_REG)) {
853    initText = initExpression.name.escapedText.toString().replace(LINK_REG, '');
854  } else if (isBuilder && ts.isPropertyAccessExpression(initExpression) && initExpression.expression &&
855    ts.isIdentifier(initExpression.expression) && initExpression.expression.escapedText.toString() === $$ &&
856    ts.isIdentifier(initExpression.name) && linkParentComponent.includes(propertyName.escapedText.toString())) {
857    is$$ = true;
858    initText = initExpression.name.escapedText.toString();
859  } else if (isMatchInitExpression(initExpression) &&
860    linkParentComponent.includes(propertyName.escapedText.toString())) {
861    initText = initExpression.name.escapedText.toString().replace(LINK_REG, '');
862  }
863  if (initText) {
864    node = addDoubleUnderline(node, propertyName, initText, is$$, isParamsLambda, isRecycleComponent);
865  }
866  return node;
867}
868
869function isMatchInitExpression(initExpression: ts.Expression): boolean {
870  return ts.isPropertyAccessExpression(initExpression) &&
871    initExpression.expression &&
872    initExpression.expression.kind === ts.SyntaxKind.ThisKeyword &&
873    ts.isIdentifier(initExpression.name);
874}
875
876function addDoubleUnderline(node: ts.PropertyAssignment, propertyName: ts.Identifier,
877  initText: string, is$$ = false, isParamsLambda: boolean, isRecycleComponent: boolean): ts.PropertyAssignment {
878  return ts.factory.updatePropertyAssignment(node, propertyName,
879    ts.factory.createPropertyAccessExpression(
880      is$$ && partialUpdateConfig.partialUpdateMode ? ts.factory.createIdentifier($$) : ts.factory.createThis(),
881      isParamsLambda || isRecycleComponent ? ts.factory.createIdentifier(initText) : ts.factory.createIdentifier(`__${initText}`)));
882}
883
884function getParentNode(node: ts.PropertyAssignment, collection: Map<string, Set<string>>): string[] {
885  const grandparentNode: ts.NewExpression = node.parent.parent as ts.NewExpression;
886  const grandparentExpression: ts.Identifier | ts.PropertyAccessExpression =
887    grandparentNode.expression as ts.Identifier | ts.PropertyAccessExpression;
888  let parentComponent: Set<string> = new Set();
889  let grandparentName: string;
890  if (ts.isIdentifier(grandparentExpression)) {
891    grandparentName = grandparentExpression.escapedText.toString();
892    parentComponent = collection.get(grandparentName);
893  } else if (ts.isPropertyAccessExpression(grandparentExpression)) {
894    if (storedFileInfo.isAsPageImport) {
895      grandparentName = grandparentExpression.getText();
896    } else {
897      grandparentName = grandparentExpression.name.escapedText.toString();
898    }
899    parentComponent = collection.get(grandparentName);
900  } else {
901    // ignore
902  }
903  if (!parentComponent) {
904    parentComponent = new Set();
905  }
906  return [grandparentName, ...parentComponent];
907}
908
909function addUpdateParamsFunc(statements: ts.Statement[], parentComponentName: ts.Identifier):
910  ts.MethodDeclaration {
911  return createParamsInitBlock(COMPONENT_CONSTRUCTOR_UPDATE_PARAMS, statements, parentComponentName);
912}
913
914function addInitialParamsFunc(statements: ts.Statement[], parentComponentName: ts.Identifier): ts.MethodDeclaration {
915  return createParamsInitBlock(COMPONENT_CONSTRUCTOR_INITIAL_PARAMS, statements, parentComponentName);
916}
917
918function addUpdateStateVarsFunc(statements: ts.Statement[], parentComponentName: ts.Identifier): ts.MethodDeclaration {
919  return createParamsInitBlock(COMPONENT_UPDATE_STATE_VARS, statements, parentComponentName);
920}
921
922function addPurgeVariableDepFunc(statements: ts.Statement[]): ts.MethodDeclaration {
923  return ts.factory.createMethodDeclaration(
924    undefined, undefined,
925    ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PURGE_VARIABLE_DEP),
926    undefined, undefined, [ts.factory.createParameterDeclaration(undefined, undefined,
927      ts.factory.createIdentifier(RMELMTID), undefined, undefined, undefined)], undefined,
928    ts.factory.createBlock(statements, true));
929}
930
931function addDeleteParamsFunc(statements: ts.PropertyDeclaration[],
932  updateRecyle: boolean = false): ts.MethodDeclaration {
933  const deleteStatements: ts.ExpressionStatement[] = [];
934  const updateStatements: ts.ExpressionStatement[] = [];
935  statements.forEach((statement: ts.PropertyDeclaration) => {
936    const name: ts.Identifier = statement.name as ts.Identifier;
937    let paramsStatement: ts.ExpressionStatement;
938    const decorators: readonly ts.Decorator[] = ts.getAllDecorators(statement);
939    const isRegular: boolean = isRegularProperty(decorators);
940    if (!partialUpdateConfig.partialUpdateMode || !isRegular) {
941      paramsStatement = createParamsWithUnderlineStatement(name);
942    }
943    if (partialUpdateConfig.partialUpdateMode && !isRegular) {
944      updateStatements.push(createElmtIdWithUnderlineStatement(name));
945    }
946    deleteStatements.push(paramsStatement);
947  });
948  if (partialUpdateConfig.partialUpdateMode && updateRecyle) {
949    return createRecycleElmt(updateStatements);
950  }
951  const defaultStatement: ts.ExpressionStatement =
952    ts.factory.createExpressionStatement(ts.factory.createCallExpression(
953      ts.factory.createPropertyAccessExpression(
954        ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(
955          ts.factory.createIdentifier(CREATE_CONSTRUCTOR_SUBSCRIBER_MANAGER),
956          ts.factory.createIdentifier(CREATE_CONSTRUCTOR_GET_FUNCTION)), undefined, []),
957        ts.factory.createIdentifier(CREATE_CONSTRUCTOR_DELETE_FUNCTION)),
958      undefined, [ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(
959        ts.factory.createThis(), ts.factory.createIdentifier(
960          !partialUpdateConfig.partialUpdateMode ?
961            ABOUT_TO_BE_DELETE_FUNCTION_ID : ABOUT_TO_BE_DELETE_FUNCTION_ID__)),
962      undefined, [])]));
963  deleteStatements.push(defaultStatement);
964  if (partialUpdateConfig.partialUpdateMode) {
965    const aboutToBeDeletedInternalStatement: ts.ExpressionStatement = createDeletedInternalStatement();
966    deleteStatements.push(aboutToBeDeletedInternalStatement);
967  }
968  const deleteParamsMethod: ts.MethodDeclaration =
969    createParamsInitBlock(COMPONENT_CONSTRUCTOR_DELETE_PARAMS, deleteStatements);
970  return deleteParamsMethod;
971}
972
973function createRecycleElmt(statements: ts.Statement[]): ts.MethodDeclaration {
974  return ts.factory.createMethodDeclaration(undefined, undefined,
975    ts.factory.createIdentifier(UPDATE_RECYCLE_ELMT_ID), undefined, undefined, [
976      ts.factory.createParameterDeclaration(undefined, undefined,
977        ts.factory.createIdentifier(OLD_ELMT_ID)),
978      ts.factory.createParameterDeclaration(undefined, undefined,
979        ts.factory.createIdentifier(NEW_ELMT_ID))
980    ], undefined, ts.factory.createBlock(statements, true));
981}
982
983function createParamsWithUnderlineStatement(name: ts.Identifier): ts.ExpressionStatement {
984  return ts.factory.createExpressionStatement(
985    ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(
986      ts.factory.createPropertyAccessExpression(ts.factory.createThis(),
987        ts.factory.createIdentifier(`__${name.escapedText.toString()}`)),
988      ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_DELETE_PARAMS)), undefined, []));
989}
990
991function createElmtIdWithUnderlineStatement(name: ts.Identifier): ts.ExpressionStatement {
992  return ts.factory.createExpressionStatement(
993    ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(
994      ts.factory.createPropertyAccessExpression(ts.factory.createThis(),
995        ts.factory.createIdentifier(`__${name.escapedText.toString()}`)),
996      ts.factory.createIdentifier(COMPONENT_UPDATE_ELMT_ID)), undefined, [
997      ts.factory.createIdentifier(OLD_ELMT_ID), ts.factory.createIdentifier(NEW_ELMT_ID)
998    ]));
999}
1000
1001function createDeletedInternalStatement(): ts.ExpressionStatement {
1002  return ts.factory.createExpressionStatement(ts.factory.createCallExpression(
1003    ts.factory.createPropertyAccessExpression(ts.factory.createThis(),
1004      ts.factory.createIdentifier(ABOUTTOBEDELETEDINTERNAL)), undefined, []));
1005}
1006
1007export function addRerenderFunc(statements: ts.Statement[]): ts.MethodDeclaration {
1008  const updateDirtyElementStatement: ts.Statement = ts.factory.createExpressionStatement(
1009    ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(
1010      ts.factory.createThis(), ts.factory.createIdentifier(UPDATEDIRTYELEMENTS)), undefined, []));
1011  statements.push(updateDirtyElementStatement);
1012  if (storedFileInfo.hasLocalBuilderInFile) {
1013    statements.unshift(contextStackPushOrPop(ts.factory.createIdentifier(PUSH), [ts.factory.createThis()]));
1014    statements.push(contextStackPushOrPop(ts.factory.createIdentifier(COMPONENT_POP_FUNCTION), []));
1015  }
1016  return ts.factory.createMethodDeclaration(undefined, undefined,
1017    ts.factory.createIdentifier(COMPONENT_RERENDER_FUNCTION), undefined, undefined, [], undefined,
1018    ts.factory.createBlock(statements, true));
1019}
1020
1021function createParamsInitBlock(express: string, statements: ts.Statement[],
1022  parentComponentName?: ts.Identifier): ts.MethodDeclaration {
1023  const methodDeclaration: ts.MethodDeclaration = ts.factory.createMethodDeclaration(
1024    undefined, undefined, ts.factory.createIdentifier(express), undefined, undefined,
1025    [ts.factory.createParameterDeclaration(undefined, undefined,
1026      express === COMPONENT_CONSTRUCTOR_DELETE_PARAMS ? undefined :
1027        ts.factory.createIdentifier(CREATE_CONSTRUCTOR_PARAMS), undefined,
1028      express === COMPONENT_CONSTRUCTOR_DELETE_PARAMS ? undefined :
1029        ts.factory.createTypeReferenceNode(
1030          ts.factory.createIdentifier(parentComponentName.getText() + INTERFACE_NAME_SUFFIX), undefined),
1031      undefined)], undefined, ts.factory.createBlock(statements, true));
1032  return methodDeclaration;
1033}
1034
1035export function validateBuildMethodCount(buildCount: BuildCount, parentComponentName: ts.Identifier,
1036  log: LogInfo[]): void {
1037  if (buildCount.count !== 1) {
1038    log.push({
1039      type: LogType.ERROR,
1040      message: `The struct '${parentComponentName.getText()}' must have at least and at most one 'build' method.`,
1041      pos: parentComponentName.getStart(),
1042      code: '10905103',
1043      solutions: [`A structurally modified page must have at least one and no more than one 'build' method.`]
1044    });
1045  }
1046}
1047
1048function validateHasControllerAndControllerCount(componentName: ts.Identifier, checkController: ControllerType,
1049  log: LogInfo[]): void {
1050  if (!checkController.hasController) {
1051    log.push({
1052      type: LogType.ERROR,
1053      message: `The '@CustomDialog' decorated custom component must contain a property of the CustomDialogController type.`,
1054      pos: componentName.pos,
1055      code: '10905211'
1056    });
1057  }
1058  if (checkController.unassignedControllerSet.size >= 2) {
1059    log.push({
1060      type: LogType.WARN,
1061      message: 'A @CustomDialog component can only have one uninitialized CustomDialogController.',
1062      pos: componentName.pos
1063    });
1064  }
1065}
1066
1067function createHeritageClause(isComponentV2: boolean = false): ts.HeritageClause {
1068  if (partialUpdateConfig.partialUpdateMode) {
1069    return ts.factory.createHeritageClause(
1070      ts.SyntaxKind.ExtendsKeyword,
1071      [ts.factory.createExpressionWithTypeArguments(
1072        ts.factory.createIdentifier(isComponentV2 ? constantDefine.STRUCT_PARENT : BASE_COMPONENT_NAME_PU),
1073        [])]
1074    );
1075  }
1076  return ts.factory.createHeritageClause(
1077    ts.SyntaxKind.ExtendsKeyword,
1078    [ts.factory.createExpressionWithTypeArguments(ts.factory.createIdentifier(BASE_COMPONENT_NAME), [])]
1079  );
1080}
1081
1082function createTypeReference(decoratorName: string, type: ts.TypeNode, log: LogInfo[],
1083  program: ts.Program): ts.TypeNode {
1084  let newType: ts.TypeNode;
1085  switch (decoratorName) {
1086    case COMPONENT_STATE_DECORATOR:
1087    case COMPONENT_PROVIDE_DECORATOR:
1088      newType = ts.factory.createTypeReferenceNode(
1089        isSimpleType(type, program, log) ?
1090          OBSERVED_PROPERTY_SIMPLE :
1091          OBSERVED_PROPERTY_OBJECT,
1092        [type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)]
1093      );
1094      break;
1095    case COMPONENT_LINK_DECORATOR:
1096    case COMPONENT_CONSUME_DECORATOR:
1097      newType = ts.factory.createTypeReferenceNode(
1098        isSimpleType(type, program, log) ?
1099          SYNCHED_PROPERTY_SIMPLE_TWO_WAY :
1100          SYNCHED_PROPERTY_SIMPLE_ONE_WAY,
1101        [type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)]
1102      );
1103      break;
1104    case COMPONENT_PROP_DECORATOR:
1105      newType = ts.factory.createTypeReferenceNode(
1106        SYNCHED_PROPERTY_SIMPLE_ONE_WAY,
1107        [type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)]
1108      );
1109      break;
1110    case COMPONENT_OBJECT_LINK_DECORATOR:
1111      newType = ts.factory.createTypeReferenceNode(
1112        SYNCHED_PROPERTY_NESED_OBJECT,
1113        [type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)]
1114      );
1115      break;
1116    case COMPONENT_STORAGE_PROP_DECORATOR:
1117    case COMPONENT_STORAGE_LINK_DECORATOR:
1118      newType = ts.factory.createTypeReferenceNode(OBSERVED_PROPERTY_ABSTRACT, [
1119        type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)
1120      ]);
1121      break;
1122    case COMPONENT_LOCAL_STORAGE_LINK_DECORATOR:
1123    case COMPONENT_LOCAL_STORAGE_PROP_DECORATOR:
1124      newType = ts.factory.createTypeReferenceNode(OBSERVED_PROPERTY_ABSTRACT, [
1125        type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)
1126      ]);
1127      break;
1128  }
1129  return newType;
1130}
1131
1132function createTypeReferencePU(decoratorName: string, type: ts.TypeNode, log: LogInfo[],
1133  program: ts.Program): ts.TypeNode {
1134  let newType: ts.TypeNode;
1135  switch (decoratorName) {
1136    case COMPONENT_STATE_DECORATOR:
1137    case COMPONENT_PROVIDE_DECORATOR:
1138      newType = ts.factory.createTypeReferenceNode(
1139        isSimpleType(type, program, log) ?
1140          OBSERVED_PROPERTY_SIMPLE_PU :
1141          OBSERVED_PROPERTY_OBJECT_PU,
1142        [type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)]
1143      );
1144      break;
1145    case COMPONENT_LINK_DECORATOR:
1146      newType = ts.factory.createTypeReferenceNode(
1147        isSimpleType(type, program, log) ?
1148          SYNCHED_PROPERTY_SIMPLE_TWO_WAY_PU :
1149          SYNCHED_PROPERTY_SIMPLE_ONE_WAY_PU,
1150        [type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)]
1151      );
1152      break;
1153    case COMPONENT_PROP_DECORATOR:
1154      newType = ts.factory.createTypeReferenceNode(
1155        SYNCHED_PROPERTY_SIMPLE_ONE_WAY_PU,
1156        [type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)]
1157      );
1158      break;
1159    case COMPONENT_OBJECT_LINK_DECORATOR:
1160      newType = ts.factory.createTypeReferenceNode(
1161        SYNCHED_PROPERTY_NESED_OBJECT_PU,
1162        [type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)]
1163      );
1164      break;
1165    case COMPONENT_CONSUME_DECORATOR:
1166    case COMPONENT_STORAGE_PROP_DECORATOR:
1167    case COMPONENT_STORAGE_LINK_DECORATOR:
1168      newType = ts.factory.createTypeReferenceNode(OBSERVED_PROPERTY_ABSTRACT_PU, [
1169        type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)
1170      ]);
1171      break;
1172    case COMPONENT_LOCAL_STORAGE_LINK_DECORATOR:
1173    case COMPONENT_LOCAL_STORAGE_PROP_DECORATOR:
1174      newType = ts.factory.createTypeReferenceNode(OBSERVED_PROPERTY_ABSTRACT_PU, [
1175        type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)
1176      ]);
1177      break;
1178  }
1179  return newType;
1180}
1181
1182export function checkFinalizeConstruction(): ts.Statement {
1183  return ts.factory.createIfStatement(
1184    ts.factory.createPrefixUnaryExpression(ts.SyntaxKind.ExclamationToken,
1185      ts.factory.createParenthesizedExpression(ts.factory.createBinaryExpression(
1186        ts.factory.createStringLiteral(FINALIZE_CONSTRUCTION),
1187        ts.factory.createToken(ts.SyntaxKind.InKeyword), ts.factory.createPropertyAccessExpression(
1188          ts.factory.createIdentifier(BASE_COMPONENT_NAME_PU), ts.factory.createIdentifier(PROTOTYPE))))
1189    ),
1190    ts.factory.createBlock(
1191      [
1192        ts.factory.createExpressionStatement(ts.factory.createCallExpression(
1193          ts.factory.createPropertyAccessExpression(
1194            ts.factory.createIdentifier(REFLECT), ts.factory.createIdentifier(CREATE_SET_METHOD)
1195          ), undefined,
1196          [
1197            ts.factory.createPropertyAccessExpression(
1198              ts.factory.createIdentifier(BASE_COMPONENT_NAME_PU), ts.factory.createIdentifier(PROTOTYPE)
1199            ),
1200            ts.factory.createStringLiteral(FINALIZE_CONSTRUCTION),
1201            ts.factory.createArrowFunction(undefined, undefined, [], undefined,
1202              ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
1203              ts.factory.createBlock([], false)
1204            )
1205          ]
1206        ))
1207      ], true), undefined);
1208}
1209
1210export function checkContextStack(): ts.Statement {
1211  return ts.factory.createIfStatement(
1212    ts.factory.createBinaryExpression(
1213      ts.factory.createPropertyAccessExpression(
1214        ts.factory.createIdentifier(PUV2_VIEW_BASE),
1215        ts.factory.createIdentifier(CONTEXT_STACK)
1216      ),
1217      ts.factory.createToken(ts.SyntaxKind.EqualsEqualsEqualsToken),
1218      ts.factory.createIdentifier(COMPONENT_IF_UNDEFINED)
1219    ),
1220    ts.factory.createBlock(
1221      [ts.factory.createExpressionStatement(ts.factory.createCallExpression(
1222        ts.factory.createPropertyAccessExpression(
1223          ts.factory.createIdentifier(REFLECT),
1224          ts.factory.createIdentifier(CREATE_SET_METHOD)
1225        ),
1226        undefined,
1227        [
1228          ts.factory.createIdentifier(PUV2_VIEW_BASE),
1229          ts.factory.createStringLiteral(CONTEXT_STACK),
1230          ts.factory.createArrayLiteralExpression(
1231            [],
1232            false
1233          )
1234        ]
1235      ))],
1236      true
1237    ),
1238    undefined
1239  );
1240}
1241
1242export function contextStackPushOrPop(pushOrPop: ts.Identifier, param: ts.ThisExpression[] | []): ts.ExpressionStatement {
1243  return ts.factory.createExpressionStatement(ts.factory.createBinaryExpression(
1244    ts.factory.createPropertyAccessExpression(
1245      ts.factory.createIdentifier(PUV2_VIEW_BASE),
1246      ts.factory.createIdentifier(CONTEXT_STACK)
1247    ),
1248    ts.factory.createToken(ts.SyntaxKind.AmpersandAmpersandToken),
1249    ts.factory.createCallExpression(
1250      ts.factory.createPropertyAccessExpression(
1251        ts.factory.createPropertyAccessExpression(
1252          ts.factory.createIdentifier(PUV2_VIEW_BASE),
1253          ts.factory.createIdentifier(CONTEXT_STACK)
1254        ),
1255        pushOrPop
1256      ),
1257      undefined,
1258      param
1259    )
1260  ));
1261}
1262