• 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_DELETE_PARAMS,
37  COMPONENT_DECORATOR_PREVIEW,
38  CREATE_CONSTRUCTOR_SUBSCRIBER_MANAGER,
39  ABOUT_TO_BE_DELETE_FUNCTION_ID,
40  CREATE_CONSTRUCTOR_GET_FUNCTION,
41  CREATE_CONSTRUCTOR_DELETE_FUNCTION,
42  FOREACH_OBSERVED_OBJECT,
43  FOREACH_GET_RAW_OBJECT,
44  COMPONENT_BUILDER_DECORATOR,
45  COMPONENT_TRANSITION_FUNCTION,
46  COMPONENT_CREATE_FUNCTION,
47  GEOMETRY_VIEW,
48  COMPONENT_STYLES_DECORATOR,
49  STYLES,
50  INTERFACE_NAME_SUFFIX,
51  OBSERVED_PROPERTY_ABSTRACT,
52  COMPONENT_LOCAL_STORAGE_LINK_DECORATOR,
53  COMPONENT_LOCAL_STORAGE_PROP_DECORATOR,
54  COMPONENT_CONSTRUCTOR_LOCALSTORAGE,
55  COMPONENT_SET_AND_LINK,
56  COMPONENT_SET_AND_PROP,
57  COMPONENT_CONSTRUCTOR_UNDEFINED
58} from './pre_define';
59import {
60  BUILDIN_STYLE_NAMES,
61  CUSTOM_BUILDER_METHOD,
62  INNER_STYLE_FUNCTION,
63  INTERFACE_NODE_SET,
64  STYLES_ATTRIBUTE
65} from './component_map';
66import {
67  componentCollection,
68  linkCollection,
69  localStorageLinkCollection,
70  localStoragePropCollection
71} from './validate_ui_syntax';
72import {
73  addConstructor,
74  getInitConstructor
75} from './process_component_constructor';
76import {
77  ControllerType,
78  processMemberVariableDecorators,
79  UpdateResult,
80  stateObjectCollection,
81  curPropMap,
82  decoratorParamSet,
83  isSimpleType
84} from './process_component_member';
85import {
86  processComponentBuild,
87  processComponentBlock
88} from './process_component_build';
89import {
90  LogType,
91  LogInfo,
92  hasDecorator
93} from './utils';
94
95export function processComponentClass(node: ts.StructDeclaration, context: ts.TransformationContext,
96  log: LogInfo[], program: ts.Program): ts.ClassDeclaration {
97  validateInheritClass(node, log);
98  const memberNode: ts.ClassElement[] =
99    processMembers(node.members, node.name, context, log, program, checkPreview(node));
100  return ts.factory.createClassDeclaration(undefined, node.modifiers, node.name,
101    node.typeParameters, updateHeritageClauses(node), memberNode);
102}
103
104function checkPreview(node: ts.ClassDeclaration) {
105  let hasPreview: boolean = false;
106  if (node && node.decorators) {
107    for (let i = 0; i < node.decorators.length; i++) {
108      const name: string = node.decorators[i].getText().replace(/\([^\(\)]*\)/, '').trim();
109      if (name === COMPONENT_DECORATOR_PREVIEW) {
110        hasPreview = true;
111        break;
112      }
113    }
114  }
115  return hasPreview;
116}
117
118type BuildCount = {
119  count: number;
120}
121
122function processMembers(members: ts.NodeArray<ts.ClassElement>, parentComponentName: ts.Identifier,
123  context: ts.TransformationContext, log: LogInfo[], program: ts.Program, hasPreview: boolean): ts.ClassElement[] {
124  const buildCount: BuildCount = { count: 0 };
125  let ctorNode: any = getInitConstructor(members, parentComponentName);
126  const newMembers: ts.ClassElement[] = [];
127  const watchMap: Map<string, ts.Node> = new Map();
128  const updateParamsStatements: ts.Statement[] = [];
129  const deleteParamsStatements: ts.PropertyDeclaration[] = [];
130  const checkController: ControllerType =
131    { hasController: !componentCollection.customDialogs.has(parentComponentName.getText()) };
132  const interfaceNode = ts.factory.createInterfaceDeclaration(undefined, undefined,
133    parentComponentName.getText() + INTERFACE_NAME_SUFFIX, undefined, undefined, []);
134  members.forEach((item: ts.ClassElement) => {
135    let updateItem: ts.ClassElement;
136    if (ts.isPropertyDeclaration(item)) {
137      addPropertyMember(item, newMembers, program, parentComponentName.getText(), log);
138      const result: UpdateResult = processMemberVariableDecorators(parentComponentName, item,
139        ctorNode, watchMap, checkController, log, program, context, hasPreview, interfaceNode);
140      if (result.isItemUpdate()) {
141        updateItem = result.getProperity();
142      } else {
143        updateItem = item;
144      }
145      if (result.getVariableGet()) {
146        newMembers.push(result.getVariableGet());
147      }
148      if (result.getVariableSet()) {
149        newMembers.push(result.getVariableSet());
150      }
151      if (result.isCtorUpdate()) {
152        ctorNode = result.getCtor();
153      }
154      if (result.getUpdateParams()) {
155        updateParamsStatements.push(result.getUpdateParams());
156      }
157      if (result.isDeleteParams()) {
158        deleteParamsStatements.push(item);
159      }
160      if (result.getControllerSet()) {
161        newMembers.push(result.getControllerSet());
162      }
163    }
164    if (ts.isMethodDeclaration(item) && item.name) {
165      updateItem =
166        processComponentMethod(item, parentComponentName, context, log, buildCount);
167    }
168    if (updateItem) {
169      newMembers.push(updateItem);
170    }
171  });
172  INTERFACE_NODE_SET.add(interfaceNode);
173  validateBuildMethodCount(buildCount, parentComponentName, log);
174  validateHasController(parentComponentName, checkController, log);
175  newMembers.unshift(addDeleteParamsFunc(deleteParamsStatements));
176  newMembers.unshift(addUpdateParamsFunc(updateParamsStatements, parentComponentName));
177  newMembers.unshift(addConstructor(ctorNode, watchMap, parentComponentName));
178  return newMembers;
179}
180
181function addPropertyMember(item: ts.ClassElement, newMembers: ts.ClassElement[],
182  program: ts.Program, parentComponentName: string, log: LogInfo[]): void {
183  const propertyItem: ts.PropertyDeclaration = item as ts.PropertyDeclaration;
184  let decoratorName: string;
185  let updatePropertyItem: ts.PropertyDeclaration;
186  const type: ts.TypeNode = propertyItem.type;
187  if (!propertyItem.decorators || propertyItem.decorators.length === 0) {
188    updatePropertyItem = createPropertyDeclaration(propertyItem, type, true);
189    newMembers.push(updatePropertyItem);
190  } else if (propertyItem.decorators) {
191    for (let i = 0; i < propertyItem.decorators.length; i++) {
192      let newType: ts.TypeNode;
193      decoratorName = propertyItem.decorators[i].getText().replace(/\(.*\)$/, '').trim();
194      let isLocalStorage: boolean = false;
195      switch (decoratorName) {
196        case COMPONENT_STATE_DECORATOR:
197        case COMPONENT_PROVIDE_DECORATOR:
198          newType = ts.factory.createTypeReferenceNode(isSimpleType(type, program, log) ?
199            OBSERVED_PROPERTY_SIMPLE : OBSERVED_PROPERTY_OBJECT, [type ||
200              ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)]);
201          break;
202        case COMPONENT_LINK_DECORATOR:
203        case COMPONENT_CONSUME_DECORATOR:
204          newType = ts.factory.createTypeReferenceNode(isSimpleType(type, program, log) ?
205            SYNCHED_PROPERTY_SIMPLE_TWO_WAY : SYNCHED_PROPERTY_SIMPLE_ONE_WAY, [type ||
206              ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)]);
207          break;
208        case COMPONENT_PROP_DECORATOR:
209          newType = ts.factory.createTypeReferenceNode(SYNCHED_PROPERTY_SIMPLE_ONE_WAY, [type ||
210            ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)]);
211          break;
212        case COMPONENT_OBJECT_LINK_DECORATOR:
213          newType = ts.factory.createTypeReferenceNode(SYNCHED_PROPERTY_NESED_OBJECT, [type ||
214            ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)]);
215          break;
216        case COMPONENT_STORAGE_PROP_DECORATOR:
217        case COMPONENT_STORAGE_LINK_DECORATOR:
218          newType = ts.factory.createTypeReferenceNode(OBSERVED_PROPERTY_ABSTRACT, [type ||
219            ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)]);
220          break;
221        case COMPONENT_LOCAL_STORAGE_LINK_DECORATOR:
222        case COMPONENT_LOCAL_STORAGE_PROP_DECORATOR:
223          newType = ts.factory.createTypeReferenceNode(OBSERVED_PROPERTY_ABSTRACT, [type ||
224            ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)]);
225          isLocalStorage = true;
226          break;
227      }
228      updatePropertyItem = createPropertyDeclaration(propertyItem, newType, false,
229        isLocalStorage, parentComponentName);
230      if (updatePropertyItem) {
231        newMembers.push(updatePropertyItem);
232      }
233    }
234  }
235}
236
237function createPropertyDeclaration(propertyItem: ts.PropertyDeclaration, newType: ts.TypeNode | undefined,
238  normalVar: boolean, isLocalStorage: boolean = false, parentComponentName: string = null): ts.PropertyDeclaration {
239  if (typeof newType === undefined) {
240    return undefined;
241  }
242  let prefix: string = '';
243  if (!normalVar) {
244    prefix = '__';
245  }
246  const privateM: ts.ModifierToken<ts.SyntaxKind.PrivateKeyword> =
247    ts.factory.createModifier(ts.SyntaxKind.PrivateKeyword);
248  return ts.factory.updatePropertyDeclaration(propertyItem, undefined,
249    propertyItem.modifiers || [privateM], prefix + propertyItem.name.getText(),
250    propertyItem.questionToken, newType, isLocalStorage ?
251      createLocalStroageCallExpression(propertyItem, propertyItem.name.getText(),
252        parentComponentName) : undefined);
253}
254
255function createLocalStroageCallExpression(node: ts.PropertyDeclaration, name: string,
256  parentComponentName: string): ts.CallExpression {
257  const localStorageLink: Set<string> = localStorageLinkCollection.get(parentComponentName).get(name);
258  const localStorageProp: Set<string> = localStoragePropCollection.get(parentComponentName).get(name);
259  return ts.factory.createCallExpression(
260    ts.factory.createPropertyAccessExpression(
261      ts.factory.createPropertyAccessExpression(
262        ts.factory.createThis(),
263        ts.factory.createIdentifier(`${COMPONENT_CONSTRUCTOR_LOCALSTORAGE}_`)
264      ),
265      ts.factory.createIdentifier(localStorageLink && !localStorageProp ? COMPONENT_SET_AND_LINK :
266        COMPONENT_SET_AND_PROP)
267    ),
268    [node.type],
269    [
270      ts.factory.createStringLiteral(localStorageLink && !localStorageProp ?
271        Array.from(localStorageLink)[0] : !localStorageLink && localStorageProp ?
272        Array.from(localStorageProp)[0] : COMPONENT_CONSTRUCTOR_UNDEFINED),
273      ts.factory.createNumericLiteral(node.initializer ? node.initializer.getText() :
274        COMPONENT_CONSTRUCTOR_UNDEFINED), ts.factory.createThis(),
275      ts.factory.createStringLiteral(name || COMPONENT_CONSTRUCTOR_UNDEFINED)
276    ]
277  );
278}
279
280function processComponentMethod(node: ts.MethodDeclaration, parentComponentName: ts.Identifier,
281  context: ts.TransformationContext, log: LogInfo[], buildCount: BuildCount): ts.MethodDeclaration {
282  let updateItem: ts.MethodDeclaration = node;
283  const name: string = node.name.getText();
284  if (name === COMPONENT_BUILD_FUNCTION) {
285    buildCount.count = buildCount.count + 1;
286    updateItem = processBuildMember(node, context, log);
287    curPropMap.clear();
288  } else if (node.body && ts.isBlock(node.body)) {
289    if (name === COMPONENT_TRANSITION_FUNCTION) {
290      updateItem = ts.factory.updateMethodDeclaration(node, node.decorators, node.modifiers,
291        node.asteriskToken, node.name, node.questionToken, node.typeParameters, node.parameters,
292        node.type, processComponentBlock(node.body, false, log, true));
293    } else if (hasDecorator(node, COMPONENT_BUILDER_DECORATOR)) {
294      CUSTOM_BUILDER_METHOD.add(name);
295      updateItem = ts.factory.updateMethodDeclaration(node, undefined, node.modifiers,
296        node.asteriskToken, node.name, node.questionToken, node.typeParameters, node.parameters,
297        node.type, processComponentBlock(node.body, false, log));
298    } else if (hasDecorator(node, COMPONENT_STYLES_DECORATOR)) {
299      if (node.parameters && node.parameters.length === 0) {
300        if (ts.isBlock(node.body) && node.body.statements && node.body.statements.length) {
301          INNER_STYLE_FUNCTION.set(name, node.body);
302          STYLES_ATTRIBUTE.add(name);
303          BUILDIN_STYLE_NAMES.add(name);
304          decoratorParamSet.add(STYLES);
305        }
306      } else {
307        log.push({
308          type: LogType.ERROR,
309          message: `@Styles can't have parameters.`,
310          pos: node.getStart()
311        });
312      }
313      return;
314    }
315  }
316  return updateItem;
317}
318
319function processBuildMember(node: ts.MethodDeclaration, context: ts.TransformationContext,
320  log: LogInfo[]): ts.MethodDeclaration {
321  if (node.parameters.length) {
322    log.push({
323      type: LogType.ERROR,
324      message: `The 'build' method can not have arguments.`,
325      pos: node.getStart()
326    });
327  }
328  const buildNode: ts.MethodDeclaration = processComponentBuild(node, log);
329  return ts.visitNode(buildNode, visitBuild);
330  function visitBuild(node: ts.Node): ts.Node {
331    if (isGeometryView(node)) {
332      node = processGeometryView(node as ts.ExpressionStatement, log);
333    }
334    if (isProperty(node)) {
335      node = createReference(node as ts.PropertyAssignment);
336    }
337    if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.name) &&
338      stateObjectCollection.has(node.name.escapedText.toString()) && node.parent &&
339      ts.isCallExpression(node.parent) && ts.isPropertyAccessExpression(node.parent.expression) &&
340      node.parent.expression.name.escapedText.toString() !== FOREACH_GET_RAW_OBJECT) {
341      return ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(
342        ts.factory.createIdentifier(FOREACH_OBSERVED_OBJECT),
343        ts.factory.createIdentifier(FOREACH_GET_RAW_OBJECT)), undefined, [node]);
344    }
345    return ts.visitEachChild(node, visitBuild, context);
346  }
347}
348
349function isGeometryView(node: ts.Node): boolean {
350  if (ts.isExpressionStatement(node) && ts.isCallExpression(node.expression)) {
351    const call: ts.CallExpression = node.expression;
352    const exp: ts.Expression = call.expression;
353    const args: ts.NodeArray<ts.Expression> = call.arguments;
354    if (ts.isPropertyAccessExpression(exp) && ts.isIdentifier(exp.expression) &&
355      exp.expression.escapedText.toString() === GEOMETRY_VIEW && ts.isIdentifier(exp.name) &&
356      exp.name.escapedText.toString() === COMPONENT_CREATE_FUNCTION && args && args.length === 1 &&
357      (ts.isArrowFunction(args[0]) || ts.isFunctionExpression(args[0]))) {
358      return true;
359    }
360  }
361  return false;
362}
363
364function processGeometryView(node: ts.ExpressionStatement,
365  log: LogInfo[]): ts.ExpressionStatement {
366  const exp: ts.CallExpression = node.expression as ts.CallExpression;
367  const arg: ts.ArrowFunction | ts.FunctionExpression =
368    exp.arguments[0] as ts.ArrowFunction | ts.FunctionExpression;
369  return ts.factory.updateExpressionStatement(node, ts.factory.updateCallExpression(exp,
370    exp.expression, undefined, [ts.factory.createArrowFunction(undefined, undefined, arg.parameters,
371      undefined, ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
372      getGeometryReaderFunctionBlock(arg, log))]));
373}
374
375function getGeometryReaderFunctionBlock(node: ts.ArrowFunction | ts.FunctionExpression,
376  log: LogInfo[]): ts.Block {
377  let blockNode: ts.Block;
378  if (ts.isBlock(node.body)) {
379    blockNode = node.body;
380  } else if (ts.isArrowFunction(node) && ts.isCallExpression(node.body)) {
381    blockNode = ts.factory.createBlock([ts.factory.createExpressionStatement(node.body)]);
382  }
383  return processComponentBlock(blockNode, false, log);
384}
385
386function updateHeritageClauses(node: ts.StructDeclaration): ts.NodeArray<ts.HeritageClause> {
387  const result:ts.HeritageClause[] = [];
388  const heritageClause:ts.HeritageClause = ts.factory.createHeritageClause(
389    ts.SyntaxKind.ExtendsKeyword,
390    [ts.factory.createExpressionWithTypeArguments(
391      ts.factory.createIdentifier(BASE_COMPONENT_NAME), [])]);
392
393  if (node.heritageClauses) {
394    result.push(...node.heritageClauses);
395  }
396  result.push(heritageClause);
397
398  return ts.factory.createNodeArray(result);
399}
400
401export function isProperty(node: ts.Node): Boolean {
402  if (judgmentParentType(node)) {
403    if (node.parent.parent.expression && ts.isIdentifier(node.parent.parent.expression) &&
404      !BUILDIN_STYLE_NAMES.has(node.parent.parent.expression.escapedText.toString()) &&
405      componentCollection.customComponents.has(
406        node.parent.parent.expression.escapedText.toString())) {
407      return true;
408    } else if (ts.isPropertyAccessExpression(node.parent.parent.expression) &&
409      ts.isIdentifier(node.parent.parent.expression.expression) &&
410      componentCollection.customComponents.has(
411        node.parent.parent.expression.name.escapedText.toString())) {
412      return true;
413    }
414  }
415  return false;
416}
417
418function judgmentParentType(node: ts.Node): boolean {
419  return ts.isPropertyAssignment(node) && node.name && ts.isIdentifier(node.name) &&
420    node.parent && ts.isObjectLiteralExpression(node.parent) && node.parent.parent &&
421    (ts.isCallExpression(node.parent.parent) || ts.isEtsComponentExpression(node.parent.parent));
422}
423
424export function createReference(node: ts.PropertyAssignment): ts.PropertyAssignment {
425  const linkParentComponent: string[] = getParentNode(node, linkCollection).slice(1);
426  const propertyName: ts.Identifier = node.name as ts.Identifier;
427  let initText: string;
428  const LINK_REG: RegExp = /^\$/g;
429  const initExpression: ts.Expression = node.initializer;
430  if (ts.isIdentifier(initExpression) &&
431    initExpression.escapedText.toString().match(LINK_REG)) {
432    initText = initExpression.escapedText.toString().replace(LINK_REG, '');
433  } else if (ts.isPropertyAccessExpression(initExpression) && initExpression.expression &&
434    initExpression.expression.kind === ts.SyntaxKind.ThisKeyword &&
435    ts.isIdentifier(initExpression.name) && initExpression.name.escapedText.toString().match(LINK_REG)) {
436    initText = initExpression.name.escapedText.toString().replace(LINK_REG, '');
437  } else if (isMatchInitExpression(initExpression) &&
438    initExpression.name.escapedText.toString().match(LINK_REG) &&
439    linkParentComponent.includes(propertyName.escapedText.toString())) {
440    initText = initExpression.name.escapedText.toString().replace(LINK_REG, '');
441  }
442  if (initText) {
443    node = addDoubleUnderline(node, propertyName, initText);
444  }
445  return node;
446}
447
448function isMatchInitExpression(initExpression: ts.Expression): boolean {
449  return ts.isPropertyAccessExpression(initExpression) &&
450    initExpression.expression &&
451    initExpression.expression.kind === ts.SyntaxKind.ThisKeyword &&
452    ts.isIdentifier(initExpression.name);
453}
454
455function addDoubleUnderline(node: ts.PropertyAssignment, propertyName: ts.Identifier,
456  initText: string): ts.PropertyAssignment {
457  return ts.factory.updatePropertyAssignment(node, propertyName,
458    ts.factory.createPropertyAccessExpression(ts.factory.createThis(),
459      ts.factory.createIdentifier(`__${initText}`)));
460}
461
462function getParentNode(node: ts.PropertyAssignment, collection: Map<string, Set<string>>): string[] {
463  const grandparentNode: ts.NewExpression = node.parent.parent as ts.NewExpression;
464  const grandparentExpression: ts.Identifier | ts.PropertyAccessExpression =
465    grandparentNode.expression as ts.Identifier | ts.PropertyAccessExpression;
466  let parentComponent: Set<string> = new Set();
467  let grandparentName: string;
468  if (ts.isIdentifier(grandparentExpression)) {
469    grandparentName = grandparentExpression.escapedText.toString();
470    parentComponent = collection.get(grandparentName);
471  } else if (ts.isPropertyAccessExpression(grandparentExpression)) {
472    grandparentName = grandparentExpression.name.escapedText.toString();
473    parentComponent = collection.get(grandparentName);
474  } else {
475    // ignore
476  }
477  if (!parentComponent) {
478    parentComponent = new Set();
479  }
480  return [grandparentName, ...parentComponent];
481}
482
483function addUpdateParamsFunc(statements: ts.Statement[], parentComponentName: ts.Identifier):
484  ts.MethodDeclaration {
485  return createParamsInitBlock(COMPONENT_CONSTRUCTOR_UPDATE_PARAMS, statements, parentComponentName);
486}
487
488function addDeleteParamsFunc(statements: ts.PropertyDeclaration[]): ts.MethodDeclaration {
489  const deleteStatements: ts.ExpressionStatement[] = [];
490  statements.forEach((statement: ts.PropertyDeclaration) => {
491    const name: ts.Identifier = statement.name as ts.Identifier;
492    const paramsStatement: ts.ExpressionStatement = ts.factory.createExpressionStatement(
493      ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(
494        ts.factory.createPropertyAccessExpression(ts.factory.createThis(),
495          ts.factory.createIdentifier(`__${name.escapedText.toString()}`)),
496        ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_DELETE_PARAMS)), undefined, []));
497    deleteStatements.push(paramsStatement);
498  });
499  const defaultStatement: ts.ExpressionStatement =
500    ts.factory.createExpressionStatement(ts.factory.createCallExpression(
501      ts.factory.createPropertyAccessExpression(
502        ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(
503          ts.factory.createIdentifier(CREATE_CONSTRUCTOR_SUBSCRIBER_MANAGER),
504          ts.factory.createIdentifier(CREATE_CONSTRUCTOR_GET_FUNCTION)), undefined, []),
505        ts.factory.createIdentifier(CREATE_CONSTRUCTOR_DELETE_FUNCTION)),
506      undefined, [ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(
507        ts.factory.createThis(), ts.factory.createIdentifier(ABOUT_TO_BE_DELETE_FUNCTION_ID)),
508      undefined, [])]));
509  deleteStatements.push(defaultStatement);
510  const deleteParamsMethod: ts.MethodDeclaration =
511    createParamsInitBlock(COMPONENT_CONSTRUCTOR_DELETE_PARAMS, deleteStatements);
512  return deleteParamsMethod;
513}
514
515function createParamsInitBlock(express: string, statements: ts.Statement[],
516  parentComponentName?: ts.Identifier): ts.MethodDeclaration {
517  const methodDeclaration: ts.MethodDeclaration = ts.factory.createMethodDeclaration(undefined,
518    undefined, undefined, ts.factory.createIdentifier(express), undefined, undefined,
519    [ts.factory.createParameterDeclaration(undefined, undefined, undefined,
520      express === COMPONENT_CONSTRUCTOR_DELETE_PARAMS ? undefined :
521        ts.factory.createIdentifier(CREATE_CONSTRUCTOR_PARAMS), undefined,
522      express === COMPONENT_CONSTRUCTOR_DELETE_PARAMS ? undefined :
523        ts.factory.createTypeReferenceNode(
524          ts.factory.createIdentifier(parentComponentName.getText() + INTERFACE_NAME_SUFFIX), undefined),
525      undefined)], undefined, ts.factory.createBlock(statements, true));
526  return methodDeclaration;
527}
528
529function validateBuildMethodCount(buildCount: BuildCount, parentComponentName: ts.Identifier,
530  log: LogInfo[]): void {
531  if (buildCount.count !== 1) {
532    log.push({
533      type: LogType.ERROR,
534      message: `struct '${parentComponentName.getText()}' must be at least or at most one 'build' method.`,
535      pos: parentComponentName.getStart()
536    });
537  }
538}
539
540function validateInheritClass(node: ts.StructDeclaration, log: LogInfo[]): void {
541  if (node.heritageClauses) {
542    log.push({
543      type: LogType.ERROR,
544      message: '@Component should not be inherit other Classes.',
545      pos: node.heritageClauses.pos
546    });
547  }
548}
549
550function validateHasController(componentName: ts.Identifier, checkController: ControllerType,
551  log: LogInfo[]): void {
552  if (!checkController.hasController) {
553    log.push({
554      type: LogType.ERROR,
555      message: '@CustomDialog component should have a property of the CustomDialogController type.',
556      pos: componentName.pos
557    });
558  }
559}
560