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