• 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';
17const path = require('path');
18
19import {
20  INNER_COMPONENT_MEMBER_DECORATORS,
21  COMPONENT_NON_DECORATOR,
22  COMPONENT_STATE_DECORATOR,
23  COMPONENT_PROP_DECORATOR,
24  COMPONENT_LINK_DECORATOR,
25  COMPONENT_STORAGE_PROP_DECORATOR,
26  COMPONENT_STORAGE_LINK_DECORATOR,
27  COMPONENT_PROVIDE_DECORATOR,
28  COMPONENT_CONSUME_DECORATOR,
29  COMPONENT_OBJECT_LINK_DECORATOR,
30  COMPONENT_WATCH_DECORATOR,
31  COMPONENT_OBSERVED_DECORATOR,
32  OBSERVED_PROPERTY_SIMPLE,
33  OBSERVED_PROPERTY_OBJECT,
34  SYNCHED_PROPERTY_SIMPLE_ONE_WAY,
35  SYNCHED_PROPERTY_SIMPLE_TWO_WAY,
36  SYNCHED_PROPERTY_OBJECT_TWO_WAY,
37  SYNCHED_PROPERTY_NESED_OBJECT,
38  CREATE_GET_METHOD,
39  CREATE_SET_METHOD,
40  CREATE_NEWVALUE_IDENTIFIER,
41  CREATE_CONSTRUCTOR_PARAMS,
42  ADD_PROVIDED_VAR,
43  INITIALIZE_CONSUME_FUNCTION,
44  APP_STORAGE,
45  APP_STORAGE_SET_AND_PROP,
46  APP_STORAGE_SET_AND_LINK,
47  COMPONENT_CONSTRUCTOR_UNDEFINED,
48  SET_CONTROLLER_METHOD,
49  SET_CONTROLLER_CTR,
50  SET_CONTROLLER_CTR_TYPE,
51  BASE_COMPONENT_NAME,
52  COMPONENT_CREATE_FUNCTION,
53  COMPONENT_BUILDERPARAM_DECORATOR,
54  COMPONENT_LOCAL_STORAGE_LINK_DECORATOR,
55  COMPONENT_LOCAL_STORAGE_PROP_DECORATOR,
56  COMPONENT_CONSTRUCTOR_PARENT,
57  EXTNAME_ETS,
58  _GENERATE_ID,
59  RMELMTID,
60  PURGEDEPENDENCYONELMTID,
61  BASICDECORATORS,
62  BASE_COMPONENT_NAME_PU,
63  OBSERVED_PROPERTY_SIMPLE_PU,
64  OBSERVED_PROPERTY_OBJECT_PU,
65  SYNCHED_PROPERTY_SIMPLE_TWO_WAY_PU,
66  SYNCHED_PROPERTY_OBJECT_TWO_WAY_PU,
67  SYNCHED_PROPERTY_SIMPLE_ONE_WAY_PU,
68  SYNCHED_PROPERTY_OBJECT_ONE_WAY_PU,
69  SYNCHED_PROPERTY_NESED_OBJECT_PU,
70  COMPONENT_CUSTOM_DECORATOR,
71  THIS,
72  CREATE_STORAGE_LINK,
73  CREATE_STORAGE_PROP,
74  ELMTID,
75  COMPONENT_CONSTRUCTOR_PARAMS,
76  RESERT
77} from './pre_define';
78import {
79  forbiddenUseStateType,
80  BUILDIN_STYLE_NAMES
81} from './component_map';
82import {
83  observedClassCollection,
84  enumCollection,
85  componentCollection,
86  classMethodCollection
87} from './validate_ui_syntax';
88import { updateConstructor } from './process_component_constructor';
89import {
90  LogType,
91  LogInfo,
92  componentInfo
93} from './utils';
94import {
95  createReference,
96  isProperty
97} from './process_component_class';
98import { transformLog } from './process_ui_syntax';
99import {
100  globalProgram,
101  projectConfig,
102  partialUpdateConfig
103} from '../main';
104import {
105  parentConditionalExpression,
106  createFunction
107} from './process_component_build';
108import { CUSTOM_BUILDER_METHOD } from './component_map';
109
110export type ControllerType = {
111  hasController: boolean
112}
113
114export const observedPropertyDecorators: Set<string> =
115  new Set([COMPONENT_STATE_DECORATOR, COMPONENT_PROVIDE_DECORATOR]);
116
117export const propAndLinkDecorators: Set<string> =
118  new Set([COMPONENT_PROP_DECORATOR, COMPONENT_LINK_DECORATOR]);
119
120export const appStorageDecorators: Set<string> =
121  new Set([COMPONENT_STORAGE_PROP_DECORATOR, COMPONENT_STORAGE_LINK_DECORATOR,
122    COMPONENT_LOCAL_STORAGE_LINK_DECORATOR, COMPONENT_LOCAL_STORAGE_PROP_DECORATOR]);
123
124export const mandatorySpecifyDefaultValueDecorators: Set<string> =
125  new Set([...observedPropertyDecorators, ...appStorageDecorators]);
126
127export const forbiddenSpecifyDefaultValueDecorators: Set<string> =
128  new Set([COMPONENT_LINK_DECORATOR, COMPONENT_CONSUME_DECORATOR, COMPONENT_OBJECT_LINK_DECORATOR]);
129
130export const mandatoryToInitViaParamDecorators: Set<string> =
131  new Set([...propAndLinkDecorators, COMPONENT_OBJECT_LINK_DECORATOR]);
132
133export const setUpdateParamsDecorators: Set<string> =
134  new Set([...observedPropertyDecorators, COMPONENT_PROP_DECORATOR, COMPONENT_OBJECT_LINK_DECORATOR,
135    COMPONENT_BUILDERPARAM_DECORATOR
136  ]);
137
138export const setStateVarsDecorators: Set<string> = new Set([COMPONENT_OBJECT_LINK_DECORATOR]);
139
140export const immutableDecorators: Set<string> =
141  new Set([COMPONENT_OBJECT_LINK_DECORATOR, COMPONENT_BUILDERPARAM_DECORATOR]);
142
143export const simpleTypes: Set<ts.SyntaxKind> = new Set([ts.SyntaxKind.StringKeyword,
144  ts.SyntaxKind.NumberKeyword, ts.SyntaxKind.BooleanKeyword, ts.SyntaxKind.EnumDeclaration]);
145
146export const decoratorParamSet: Set<string> = new Set();
147
148export const stateObjectCollection: Set<string> = new Set();
149
150export class UpdateResult {
151  private itemUpdate: boolean = false;
152  private ctorUpdate: boolean = false;
153  private properity: ts.PropertyDeclaration;
154  private ctor: ts.ConstructorDeclaration;
155  private variableGet: ts.GetAccessorDeclaration;
156  private variableSet: ts.SetAccessorDeclaration;
157  private updateParams: ts.Statement;
158  private deleteParams: boolean = false;
159  private controllerSet: ts.MethodDeclaration;
160  private purgeVariableDepStatement: ts.Statement;
161  private decoratorName: string;
162  private stateVarsParams: ts.Statement;
163
164  public setProperity(updateItem: ts.PropertyDeclaration) {
165    this.itemUpdate = true;
166    this.properity = updateItem;
167  }
168
169  public setCtor(updateCtor: ts.ConstructorDeclaration) {
170    this.ctorUpdate = true;
171    this.ctor = updateCtor;
172  }
173
174  public setControllerSet(updateControllerSet: ts.MethodDeclaration) {
175    this.controllerSet = updateControllerSet;
176  }
177
178  public getControllerSet(): ts.MethodDeclaration {
179    return this.controllerSet;
180  }
181
182  public setVariableGet(updateVariableGet: ts.GetAccessorDeclaration) {
183    this.variableGet = updateVariableGet;
184  }
185
186  public setVariableSet(updateVariableSet: ts.SetAccessorDeclaration) {
187    this.variableSet = updateVariableSet;
188  }
189
190  public setUpdateParams(updateParams: ts.Statement) {
191    this.updateParams = updateParams;
192  }
193
194  public setStateVarsParams(stateVarsParams: ts.Statement) {
195    this.stateVarsParams = stateVarsParams;
196  }
197
198  public setDeleteParams(deleteParams: boolean) {
199    this.deleteParams = deleteParams;
200  }
201
202  public setPurgeVariableDepStatement(purgeVariableDepStatement: ts.Statement) {
203    this.purgeVariableDepStatement = purgeVariableDepStatement;
204  }
205
206  public setDecoratorName(decoratorName: string) {
207    this.decoratorName = decoratorName;
208  }
209
210  public isItemUpdate(): boolean {
211    return this.itemUpdate;
212  }
213
214  public isCtorUpdate(): boolean {
215    return this.ctorUpdate;
216  }
217
218  public getProperity(): ts.PropertyDeclaration {
219    return this.properity;
220  }
221
222  public getCtor(): ts.ConstructorDeclaration {
223    return this.ctor;
224  }
225
226  public getUpdateParams(): ts.Statement {
227    return this.updateParams;
228  }
229
230  public getStateVarsParams(): ts.Statement {
231    return this.stateVarsParams;
232  }
233
234  public getPurgeVariableDepStatement(): ts.Statement {
235    return this.purgeVariableDepStatement;
236  }
237
238  public getVariableGet(): ts.GetAccessorDeclaration {
239    return this.variableGet;
240  }
241
242  public getVariableSet(): ts.SetAccessorDeclaration {
243    return this.variableSet;
244  }
245
246  public getDecoratorName(): string {
247    return this.decoratorName;
248  }
249
250  public isDeleteParams(): boolean {
251    return this.deleteParams;
252  }
253}
254
255export const curPropMap: Map<string, string> = new Map();
256
257export function processMemberVariableDecorators(parentName: ts.Identifier,
258  item: ts.PropertyDeclaration, ctorNode: ts.ConstructorDeclaration, watchMap: Map<string, ts.Node>,
259  checkController: ControllerType, log: LogInfo[], program: ts.Program, context: ts.TransformationContext,
260  hasPreview: boolean, interfaceNode: ts.InterfaceDeclaration): UpdateResult {
261  const updateResult: UpdateResult = new UpdateResult();
262  const name: ts.Identifier = item.name as ts.Identifier;
263  if (!item.decorators || !item.decorators.length) {
264    curPropMap.set(name.escapedText.toString(), COMPONENT_NON_DECORATOR);
265    updateResult.setProperity(undefined);
266    updateResult.setUpdateParams(createUpdateParams(name, COMPONENT_NON_DECORATOR));
267    updateResult.setCtor(updateConstructor(ctorNode, [], [
268      createVariableInitStatement(item, COMPONENT_NON_DECORATOR, log, program, context, hasPreview,
269        interfaceNode)]));
270    updateResult.setControllerSet(createControllerSet(item, parentName, name, checkController));
271    if (partialUpdateConfig.partialUpdateMode) {
272      updateResult.setDeleteParams(true);
273    }
274  } else if (!item.type) {
275    validatePropertyNonType(name, log);
276    return updateResult;
277  } else if (validateCustomDecorator(item.decorators, log)) {
278    updateResult.setUpdateParams(createUpdateParams(name, COMPONENT_CUSTOM_DECORATOR));
279  } else {
280    processPropertyNodeDecorator(parentName, item, updateResult, ctorNode, name, watchMap,
281      log, program, context, hasPreview, interfaceNode);
282  }
283  if (item.decorators && item.decorators.length && validatePropDecorator(item.decorators)) {
284    updateResult.setStateVarsParams(createStateVarsBody(name));
285  }
286  return updateResult;
287}
288
289function createStateVarsBody(name: ts.Identifier): ts.ExpressionStatement {
290  return ts.factory.createExpressionStatement(ts.factory.createCallExpression(
291    ts.factory.createPropertyAccessExpression(
292      ts.factory.createPropertyAccessExpression(
293        ts.factory.createThis(),
294        ts.factory.createIdentifier("__"+name.escapedText.toString())
295      ),
296      ts.factory.createIdentifier(RESERT)
297    ),
298    undefined,
299    [ts.factory.createPropertyAccessExpression(
300      ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARAMS),
301      name
302    )]
303  ))
304}
305
306function createControllerSet(node: ts.PropertyDeclaration, componentName: ts.Identifier,
307  name: ts.Identifier, checkController: ControllerType): ts.MethodDeclaration {
308  if (componentCollection.customDialogs.has(componentName.getText()) && node.type &&
309    node.type.getText() === SET_CONTROLLER_CTR_TYPE) {
310    checkController.hasController = true;
311    return ts.factory.createMethodDeclaration(undefined, undefined, undefined,
312      ts.factory.createIdentifier(SET_CONTROLLER_METHOD), undefined, undefined,
313      [ts.factory.createParameterDeclaration(undefined, undefined, undefined,
314        ts.factory.createIdentifier(SET_CONTROLLER_CTR), undefined,
315        ts.factory.createTypeReferenceNode(ts.factory.createIdentifier(SET_CONTROLLER_CTR_TYPE),
316          undefined), undefined)], undefined, ts.factory.createBlock(
317        [ts.factory.createExpressionStatement(ts.factory.createBinaryExpression(
318          ts.factory.createPropertyAccessExpression(ts.factory.createThis(), name),
319          ts.factory.createToken(ts.SyntaxKind.EqualsToken),
320          ts.factory.createIdentifier(SET_CONTROLLER_CTR)))], true));
321  }
322}
323
324function processPropertyNodeDecorator(parentName: ts.Identifier, node: ts.PropertyDeclaration,
325  updateResult: UpdateResult, ctorNode: ts.ConstructorDeclaration, name: ts.Identifier,
326  watchMap: Map<string, ts.Node>, log: LogInfo[], program: ts.Program,
327  context: ts.TransformationContext, hasPreview: boolean, interfaceNode: ts.InterfaceDeclaration):
328  void {
329  let stateManagementDecoratorCount: number = 0;
330  for (let i = 0; i < node.decorators.length; i++) {
331    const decoratorName: string = node.decorators[i].getText().replace(/\(.*\)$/, '').trim();
332    if (decoratorName !== COMPONENT_WATCH_DECORATOR) {
333      curPropMap.set(name.escapedText.toString(), decoratorName);
334    }
335    if (BUILDIN_STYLE_NAMES.has(decoratorName.replace('@', ''))) {
336      validateDuplicateDecorator(node.decorators[i], log);
337    }
338    if (decoratorName !== COMPONENT_WATCH_DECORATOR && isForbiddenUseStateType(node.type)) {
339      // @ts-ignore
340      validateForbiddenUseStateType(name, decoratorName, node.type.typeName.getText(), log);
341      return;
342    }
343    if (parentName.getText() === componentCollection.entryComponent &&
344      mandatoryToInitViaParamDecorators.has(decoratorName)) {
345      validateHasIllegalDecoratorInEntry(parentName, name, decoratorName, log);
346    }
347    if (node.initializer && forbiddenSpecifyDefaultValueDecorators.has(decoratorName)) {
348      validatePropertyDefaultValue(name, decoratorName, log);
349      return;
350    } else if (!node.initializer && mandatorySpecifyDefaultValueDecorators.has(decoratorName)) {
351      validatePropertyNonDefaultValue(name, decoratorName, log);
352      return;
353    }
354    if (node.questionToken && mandatoryToInitViaParamDecorators.has(decoratorName)) {
355      validateHasIllegalQuestionToken(name, decoratorName, log);
356    }
357    if (!isSimpleType(node.type, program) &&
358      decoratorName !== COMPONENT_BUILDERPARAM_DECORATOR) {
359      stateObjectCollection.add(name.escapedText.toString());
360    }
361    if (decoratorName === COMPONENT_WATCH_DECORATOR &&
362      validateWatchDecorator(name, node.decorators.length, log)) {
363      processWatch(node, node.decorators[i], watchMap, log);
364    } else if (INNER_COMPONENT_MEMBER_DECORATORS.has(decoratorName)) {
365      stateManagementDecoratorCount += 1;
366      processStateDecorators(node, decoratorName, updateResult, ctorNode, log, program, context,
367        hasPreview, interfaceNode);
368    }
369  }
370  if (stateManagementDecoratorCount > 1) {
371    validateMultiDecorators(name, log);
372    return;
373  }
374}
375
376function processStateDecorators(node: ts.PropertyDeclaration, decorator: string,
377  updateResult: UpdateResult, ctorNode: ts.ConstructorDeclaration, log: LogInfo[],
378  program: ts.Program, context: ts.TransformationContext, hasPreview:boolean,
379  interfaceNode: ts.InterfaceDeclaration): void {
380  const name: ts.Identifier = node.name as ts.Identifier;
381  updateResult.setProperity(undefined);
382  const updateState: ts.Statement[] = [];
383  const variableInitStatement: ts.Statement =
384    createVariableInitStatement(node, decorator, log, program, context, hasPreview, interfaceNode);
385  if (variableInitStatement) {
386    updateState.push(variableInitStatement);
387  }
388  addAddProvidedVar(node, name, decorator, updateState);
389  updateResult.setCtor(updateConstructor(ctorNode, [], [...updateState], false));
390  if (decorator !== COMPONENT_BUILDERPARAM_DECORATOR) {
391    updateResult.setVariableGet(createGetAccessor(name, CREATE_GET_METHOD));
392    updateResult.setDeleteParams(true);
393  }
394  if (!immutableDecorators.has(decorator)) {
395    updateResult.setVariableSet(createSetAccessor(name, CREATE_SET_METHOD, node.type));
396  }
397  if (setUpdateParamsDecorators.has(decorator)) {
398    updateResult.setUpdateParams(createUpdateParams(name, decorator, node));
399  }
400  if (setStateVarsDecorators.has(decorator)) {
401    updateResult.setStateVarsParams(createStateVarsParams(name, decorator));
402  }
403  if (partialUpdateConfig.partialUpdateMode && BASICDECORATORS.has(decorator)) {
404    const variableWithUnderLink: string = '__' + name.escapedText.toString();
405    updateResult.setDecoratorName(decorator);
406    updateResult.setPurgeVariableDepStatement(createPurgeVariableDepStatement(variableWithUnderLink));
407  }
408}
409
410function createPurgeVariableDepStatement(variableWithUnderLink: string): ts.Statement {
411  return ts.factory.createExpressionStatement(
412    ts.factory.createCallExpression(
413      ts.factory.createPropertyAccessExpression(
414        ts.factory.createPropertyAccessExpression(
415          ts.factory.createThis(),
416          ts.factory.createIdentifier(variableWithUnderLink)
417        ),
418        ts.factory.createIdentifier(PURGEDEPENDENCYONELMTID)
419      ),
420      undefined,
421      [ts.factory.createIdentifier(RMELMTID)]
422    )
423  );
424}
425
426function processWatch(node: ts.PropertyDeclaration, decorator: ts.Decorator,
427  watchMap: Map<string, ts.Node>, log: LogInfo[]): void {
428  if (node.name) {
429    const propertyName: string = node.name.getText();
430    if (decorator.expression && ts.isCallExpression(decorator.expression) &&
431      decorator.expression.arguments && decorator.expression.arguments.length === 1) {
432      const currentClassMethod: Set<string> = classMethodCollection.get(node.parent.name.getText());
433      const argument: ts.Node = decorator.expression.arguments[0];
434      if (ts.isStringLiteral(argument)) {
435        if (currentClassMethod.has(argument.text)) {
436          watchMap.set(propertyName, argument);
437        } else {
438          log.push({
439            type: LogType.ERROR,
440            message: `Cannot find name ${argument.getText()} in struct '${node.parent.name.getText()}'.`,
441            pos: argument.getStart()
442          });
443        }
444      } else if (ts.isIdentifier(decorator.expression.arguments[0])) {
445        const content: string = decorator.expression.arguments[0].getText();
446        const propertyNode: ts.PropertyAccessExpression = createPropertyAccessExpressionWithThis(content);
447        watchMap.set(propertyName, propertyNode);
448        decoratorParamSet.add(content);
449        validateWatchParam(LogType.WARN, argument.getStart(), log);
450      } else if (ts.isPropertyAccessExpression(decorator.expression.arguments[0])) {
451        watchMap.set(propertyName, decorator.expression.arguments[0]);
452        validateWatchParam(LogType.WARN, argument.getStart(), log);
453      } else {
454        validateWatchParam(LogType.ERROR, argument.getStart(), log);
455      }
456    }
457  }
458}
459
460function createVariableInitStatement(node: ts.PropertyDeclaration, decorator: string,
461  log: LogInfo[], program: ts.Program, context: ts.TransformationContext, hasPreview: boolean,
462  interfaceNode: ts.InterfaceDeclaration): ts.Statement {
463  const name: ts.Identifier = node.name as ts.Identifier;
464  let type: ts.TypeNode;
465  let updateState: ts.ExpressionStatement;
466  if (node.type) {
467    type = node.type;
468  }
469  switch (decorator) {
470    case COMPONENT_NON_DECORATOR:
471      updateState = updateNormalProperty(node, name, log, context);
472      break;
473    case COMPONENT_STATE_DECORATOR:
474    case COMPONENT_PROVIDE_DECORATOR:
475      updateState = !partialUpdateConfig.partialUpdateMode ?
476        updateObservedProperty(node, name, type, program) : updateObservedPropertyPU(node, name, type, program);
477      break;
478    case COMPONENT_LINK_DECORATOR:
479      wrongDecoratorInPreview(node, COMPONENT_LINK_DECORATOR, hasPreview, log);
480      updateState = !partialUpdateConfig.partialUpdateMode ?
481        updateSynchedPropertyTwoWay(name, type, program) : updateSynchedPropertyTwoWayPU(name, type, program);
482      break;
483    case COMPONENT_PROP_DECORATOR:
484      wrongDecoratorInPreview(node, COMPONENT_PROP_DECORATOR, hasPreview, log);
485      updateState = !partialUpdateConfig.partialUpdateMode
486        ? updateSynchedPropertyOneWay(name, type, decorator, log, program)
487        : updateSynchedPropertyOneWayPU(name, type, decorator, log, program);
488      break;
489    case COMPONENT_STORAGE_PROP_DECORATOR:
490    case COMPONENT_STORAGE_LINK_DECORATOR:
491      updateState = updateStoragePropAndLinkProperty(node, name, decorator, log);
492      break;
493    case COMPONENT_OBJECT_LINK_DECORATOR:
494      updateState = !partialUpdateConfig.partialUpdateMode
495        ? updateSynchedPropertyNesedObject(name, type, decorator, log)
496        : updateSynchedPropertyNesedObjectPU(name, type, decorator, log);
497      break;
498    case COMPONENT_CONSUME_DECORATOR:
499      wrongDecoratorInPreview(node, COMPONENT_CONSUME_DECORATOR, hasPreview, log);
500      updateState = updateConsumeProperty(node, name);
501      break;
502    case COMPONENT_BUILDERPARAM_DECORATOR:
503      updateState = updateBuilderParamProperty(node, name, log);
504  }
505  const members = interfaceNode.members;
506  members.push(ts.factory.createPropertySignature(undefined, name,
507    ts.factory.createToken(ts.SyntaxKind.QuestionToken), type));
508  interfaceNode = ts.factory.updateInterfaceDeclaration(interfaceNode, undefined,
509    interfaceNode.modifiers, interfaceNode.name, interfaceNode.typeParameters,
510    interfaceNode.heritageClauses, members);
511  return updateState;
512}
513
514function wrongDecoratorInPreview(node: ts.PropertyDeclaration, decorator: string,
515  hasPreview: boolean, log: LogInfo[]) {
516  if (hasPreview && projectConfig.isPreview) {
517    log.push({
518      type: LogType.WARN,
519      message: `The variable with ${decorator} in component with @Preview may ` +
520        `cause error in component preview mode`,
521      pos: node.getStart()
522    });
523  }
524}
525
526function createUpdateParams(name: ts.Identifier, decorator: string,
527  localInitializationNode: ts.PropertyDeclaration = undefined): ts.Statement {
528  let updateParamsNode: ts.Statement;
529  switch (decorator) {
530    case COMPONENT_NON_DECORATOR:
531    case COMPONENT_STATE_DECORATOR:
532    case COMPONENT_PROVIDE_DECORATOR:
533    case COMPONENT_CUSTOM_DECORATOR:
534      updateParamsNode = createUpdateParamsWithIf(name);
535      break;
536    case COMPONENT_PROP_DECORATOR:
537      if (!partialUpdateConfig.partialUpdateMode) {
538        updateParamsNode = createUpdateParamsWithoutIf(name);
539      } else {
540        if (localInitializationNode && localInitializationNode.initializer) {
541          updateParamsNode = createUpdateParamsWithIf(name, true,
542            localInitializationNode.initializer);
543        }
544      }
545      break;
546    case COMPONENT_BUILDERPARAM_DECORATOR:
547      updateParamsNode = createUpdateParamsWithIf(name);
548      break;
549    case COMPONENT_OBJECT_LINK_DECORATOR:
550      updateParamsNode = createUpdateParamsWithSet(name);
551      break;
552  }
553  return updateParamsNode;
554}
555
556function createStateVarsParams(name: ts.Identifier, decorator: string): ts.Statement {
557  let updateParamsNode: ts.Statement;
558  switch (decorator) {
559    case COMPONENT_OBJECT_LINK_DECORATOR:
560      updateParamsNode = createUpdateParamsWithSet(name);
561      break;
562  }
563  return updateParamsNode;
564}
565
566function createUpdateParamsWithIf(name: ts.Identifier, isSet: boolean = false,
567  initializeNode: ts.Expression = undefined): ts.IfStatement {
568  return ts.factory.createIfStatement(ts.factory.createBinaryExpression(
569    ts.factory.createPropertyAccessExpression(
570      ts.factory.createIdentifier(CREATE_CONSTRUCTOR_PARAMS),
571      ts.factory.createIdentifier(name.escapedText.toString())),
572    ts.factory.createToken(ts.SyntaxKind.ExclamationEqualsEqualsToken),
573    ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UNDEFINED)), ts.factory.createBlock([
574    isSet ? createUpdateParamsWithSet(name) : createUpdateParamsWithoutIf(name)], true),
575    isSet ? ts.factory.createBlock([createUpdateParamsWithSet(name, true, initializeNode)]) : undefined);
576}
577
578function createUpdateParamsWithoutIf(name: ts.Identifier): ts.ExpressionStatement {
579  return ts.factory.createExpressionStatement(ts.factory.createBinaryExpression(
580    createPropertyAccessExpressionWithThis(name.getText()),
581    ts.factory.createToken(ts.SyntaxKind.EqualsToken),
582    createPropertyAccessExpressionWithParams(name.getText())));
583}
584
585function createUpdateParamsWithSet(name: ts.Identifier, hasElse: boolean = false,
586  initializeNode: ts.Expression = undefined): ts.ExpressionStatement {
587  return ts.factory.createExpressionStatement(ts.factory.createCallExpression(
588    ts.factory.createPropertyAccessExpression(createPropertyAccessExpressionWithThis(`__${name.getText()}`),
589      ts.factory.createIdentifier(CREATE_SET_METHOD)), undefined,
590    [hasElse ? initializeNode : createPropertyAccessExpressionWithParams(name.getText())]));
591}
592
593function updateNormalProperty(node: ts.PropertyDeclaration, name: ts.Identifier,
594  log: LogInfo[], context: ts.TransformationContext): ts.ExpressionStatement {
595  const init: ts.Expression =
596    ts.visitNode(node.initializer, visitDialogController);
597  function visitDialogController(node: ts.Node): ts.Node {
598    if (isProperty(node)) {
599      node = createReference(node as ts.PropertyAssignment, log);
600    }
601    return ts.visitEachChild(node, visitDialogController, context);
602  }
603  return ts.factory.createExpressionStatement(ts.factory.createBinaryExpression(
604    createPropertyAccessExpressionWithThis(name.getText()),
605    ts.factory.createToken(ts.SyntaxKind.EqualsToken), init ||
606    ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UNDEFINED)));
607}
608
609function updateObservedProperty(item: ts.PropertyDeclaration, name: ts.Identifier,
610  type: ts.TypeNode, program: ts.Program): ts.ExpressionStatement {
611  return ts.factory.createExpressionStatement(ts.factory.createBinaryExpression(
612    createPropertyAccessExpressionWithThis(`__${name.getText()}`),
613    ts.factory.createToken(ts.SyntaxKind.EqualsToken), ts.factory.createNewExpression(
614      ts.factory.createIdentifier(isSimpleType(type, program) ? OBSERVED_PROPERTY_SIMPLE :
615        OBSERVED_PROPERTY_OBJECT), undefined, [item.initializer, ts.factory.createThis(),
616        ts.factory.createStringLiteral(name.escapedText.toString())])));
617}
618
619function updateSynchedPropertyTwoWay(nameIdentifier: ts.Identifier, type: ts.TypeNode,
620  program: ts.Program): ts.ExpressionStatement {
621  const name: string = nameIdentifier.escapedText.toString();
622  const functionName: string = isSimpleType(type, program) ?
623    SYNCHED_PROPERTY_SIMPLE_TWO_WAY : SYNCHED_PROPERTY_OBJECT_TWO_WAY;
624  return createInitExpressionStatementForDecorator(name, functionName,
625    createPropertyAccessExpressionWithParams(name));
626}
627
628function updateSynchedPropertyOneWay(nameIdentifier: ts.Identifier, type: ts.TypeNode,
629  decoractor: string, log: LogInfo[], program: ts.Program): ts.ExpressionStatement {
630  const name: string = nameIdentifier.escapedText.toString();
631  if (isSimpleType(type, program)) {
632    return createInitExpressionStatementForDecorator(name, SYNCHED_PROPERTY_SIMPLE_ONE_WAY,
633      createPropertyAccessExpressionWithParams(name));
634  } else {
635    validateNonSimpleType(nameIdentifier, decoractor, log);
636  }
637}
638
639function updateStoragePropAndLinkProperty(node: ts.PropertyDeclaration, name: ts.Identifier,
640  decorator: string, log: LogInfo[]): ts.ExpressionStatement {
641  if (isSingleKey(node)) {
642    let setFuncName: string;
643    let storageFuncName: string;
644    const storageValue: ts.Expression[] = [
645      node.decorators[0].expression.arguments[0],
646      node.initializer,
647      ts.factory.createThis(),
648      ts.factory.createStringLiteral(name.getText())
649    ];
650    if (!partialUpdateConfig.partialUpdateMode) {
651      setFuncName = decorator === COMPONENT_STORAGE_PROP_DECORATOR ?
652        APP_STORAGE_SET_AND_PROP : APP_STORAGE_SET_AND_LINK;
653      storageFuncName = APP_STORAGE;
654    } else {
655      setFuncName = decorator === COMPONENT_STORAGE_PROP_DECORATOR ?
656        CREATE_STORAGE_PROP : CREATE_STORAGE_LINK;
657      storageFuncName = THIS;
658      storageValue.splice(2, 1);
659    }
660    return ts.factory.createExpressionStatement(ts.factory.createBinaryExpression(
661      createPropertyAccessExpressionWithThis(`__${name.getText()}`),
662      ts.factory.createToken(ts.SyntaxKind.EqualsToken), ts.factory.createCallExpression(
663        ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(storageFuncName),
664          ts.factory.createIdentifier(setFuncName)), undefined, storageValue)));
665  } else {
666    validateAppStorageDecoractorsNonSingleKey(node, log);
667  }
668}
669
670function getDecoratorKey(node: ts.PropertyDeclaration): string {
671  let key: string;
672  // @ts-ignore
673  const keyNameNode: ts.Node = node.decorators[0].expression.arguments[0];
674  if (ts.isIdentifier(keyNameNode)) {
675    key = keyNameNode.getText();
676    decoratorParamSet.add(key);
677  } else if (ts.isStringLiteral(keyNameNode)) {
678    key = keyNameNode.text;
679  }
680  return key;
681}
682
683function updateSynchedPropertyNesedObject(nameIdentifier: ts.Identifier,
684  type: ts.TypeNode, decoractor: string, log: LogInfo[]): ts.ExpressionStatement {
685  if (isObservedClassType(type)) {
686    return createInitExpressionStatementForDecorator(nameIdentifier.getText(), SYNCHED_PROPERTY_NESED_OBJECT,
687      createPropertyAccessExpressionWithParams(nameIdentifier.getText()));
688  } else {
689    validateNonObservedClassType(nameIdentifier, decoractor, log);
690  }
691}
692
693function updateConsumeProperty(node: ts.PropertyDeclaration,
694  nameIdentifier: ts.Identifier): ts.ExpressionStatement {
695  const name: string = nameIdentifier.getText();
696  let propertyOrAliasName: string;
697  if (isSingleKey(node)) {
698    propertyOrAliasName = getDecoratorKey(node);
699  } else {
700    propertyOrAliasName = name;
701  }
702  return ts.factory.createExpressionStatement(ts.factory.createBinaryExpression(
703    createPropertyAccessExpressionWithThis(`__${name}`),
704    ts.factory.createToken(ts.SyntaxKind.EqualsToken), ts.factory.createCallExpression(
705      createPropertyAccessExpressionWithThis(INITIALIZE_CONSUME_FUNCTION), undefined, [
706        ts.factory.createStringLiteral(propertyOrAliasName), ts.factory.createStringLiteral(name)])));
707}
708
709function updateBuilderParamProperty(node: ts.PropertyDeclaration,
710  nameIdentifier: ts.Identifier, log: LogInfo[]): ts.ExpressionStatement {
711  const name: string = nameIdentifier.getText();
712  if (judgeBuilderParamAssignedByBuilder(node)) {
713    log.push({
714      type: LogType.WARN,
715      message: `BuilderParam property can only initialized by Builder function`,
716      pos: node.getStart()
717    });
718  }
719  return ts.factory.createExpressionStatement(ts.factory.createBinaryExpression(
720    createPropertyAccessExpressionWithThis(name), ts.factory.createToken(ts.SyntaxKind.EqualsToken),
721    node.initializer || ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UNDEFINED)
722  ));
723}
724
725function judgeBuilderParamAssignedByBuilder(node: ts.PropertyDeclaration): boolean {
726  return node.initializer && !(node.initializer && (ts.isIdentifier(node.initializer) &&
727    CUSTOM_BUILDER_METHOD.has(node.initializer.escapedText.toString()) ||
728    ts.isPropertyAccessExpression(node.initializer) && node.initializer.name &&
729    ts.isIdentifier(node.initializer.name) &&
730    CUSTOM_BUILDER_METHOD.has(node.initializer.name.escapedText.toString())));
731}
732
733function createCustomComponentBuilderArrowFunction(parent: ts.PropertyDeclaration,
734  jsDialog: ts.Identifier, newExp: ts.Expression): ts.ArrowFunction {
735  return ts.factory.createArrowFunction(undefined, undefined, [], undefined,
736    ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), ts.factory.createBlock([
737      ts.factory.createVariableStatement(undefined, ts.factory.createVariableDeclarationList(
738        [ts.factory.createVariableDeclaration(jsDialog, undefined, undefined, newExp)],
739        ts.NodeFlags.Let)), ts.factory.createExpressionStatement(ts.factory.createCallExpression(
740        ts.factory.createPropertyAccessExpression(jsDialog,
741          ts.factory.createIdentifier(SET_CONTROLLER_METHOD)), undefined,
742        [ts.factory.createPropertyAccessExpression(ts.factory.createThis(),
743            parent.name as ts.Identifier)])), ts.factory.createExpressionStatement(
744        createViewCreate(jsDialog))], true));
745}
746
747export function createViewCreate(node: ts.NewExpression | ts.Identifier): ts.CallExpression {
748  if (partialUpdateConfig.partialUpdateMode) {
749    return createFunction(ts.factory.createIdentifier(BASE_COMPONENT_NAME_PU),
750      ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION), ts.factory.createNodeArray([node]));
751  }
752  return createFunction(ts.factory.createIdentifier(BASE_COMPONENT_NAME),
753    ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION), ts.factory.createNodeArray([node]));
754}
755
756export function createCustomComponentNewExpression(node: ts.CallExpression, name: string,
757  isBuilder: boolean = false, isGlobalBuilder: boolean = false,
758  isCutomDialog: boolean = false): ts.NewExpression {
759  const newNode: ts.NewExpression = ts.factory.createNewExpression(node.expression,
760    node.typeArguments, node.arguments.length ? node.arguments : []);
761  return addCustomComponentId(newNode, name, isBuilder, isGlobalBuilder, isCutomDialog);
762}
763
764function addCustomComponentId(node: ts.NewExpression, componentName: string,
765  isBuilder: boolean = false, isGlobalBuilder: boolean = false,
766  isCutomDialog: boolean = false): ts.NewExpression {
767  for (const item of componentCollection.customComponents) {
768    componentInfo.componentNames.add(item);
769  }
770  componentInfo.componentNames.forEach((name: string) => {
771    let argumentsArray: ts.Expression[];
772    if (node.arguments && node.arguments.length) {
773      argumentsArray = Array.from(node.arguments);
774    }
775    if (componentName === name) {
776      if (!argumentsArray) {
777        argumentsArray = [ts.factory.createObjectLiteralExpression([], true)];
778      }
779      if (!partialUpdateConfig.partialUpdateMode) {
780        ++componentInfo.id;
781        argumentsArray.unshift(isBuilder ? ts.factory.createBinaryExpression(
782          ts.factory.createStringLiteral(path.basename(transformLog.sourceFile.fileName, EXTNAME_ETS) + '_'),
783          ts.factory.createToken(ts.SyntaxKind.PlusToken), ts.factory.createIdentifier(_GENERATE_ID)) :
784          ts.factory.createStringLiteral(componentInfo.id.toString()),
785        isBuilder ? parentConditionalExpression() : ts.factory.createThis());
786      } else {
787        argumentsArray.unshift(isGlobalBuilder ? parentConditionalExpression() : ts.factory.createThis());
788        if (!isCutomDialog) {
789          argumentsArray.push(ts.factory.createIdentifier('undefined'), ts.factory.createIdentifier(ELMTID));
790        }
791      }
792      node =
793        ts.factory.updateNewExpression(node, node.expression, node.typeArguments, argumentsArray);
794    } else if (argumentsArray) {
795      node =
796        ts.factory.updateNewExpression(node, node.expression, node.typeArguments, argumentsArray);
797    }
798  });
799  return node;
800}
801
802function createInitExpressionStatementForDecorator(propertyName: string, functionName: string,
803  parameterNode: ts.Expression): ts.ExpressionStatement {
804  return ts.factory.createExpressionStatement(ts.factory.createBinaryExpression(
805    createPropertyAccessExpressionWithThis(`__${propertyName}`),
806    ts.factory.createToken(ts.SyntaxKind.EqualsToken), ts.factory.createNewExpression(
807      ts.factory.createIdentifier(functionName), undefined, [parameterNode, ts.factory.createThis(),
808        ts.factory.createStringLiteral(propertyName)])));
809}
810
811function createPropertyAccessExpressionWithParams(propertyName: string): ts.PropertyAccessExpression {
812  return ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(CREATE_CONSTRUCTOR_PARAMS),
813    ts.factory.createIdentifier(propertyName));
814}
815
816function createPropertyAccessExpressionWithThis(propertyName: string): ts.PropertyAccessExpression {
817  return ts.factory.createPropertyAccessExpression(ts.factory.createThis(),
818    ts.factory.createIdentifier(propertyName));
819}
820
821function addAddProvidedVar(node: ts.PropertyDeclaration, name: ts.Identifier,
822  decoratorName: string, updateState: ts.Statement[]): void {
823  if (decoratorName === COMPONENT_PROVIDE_DECORATOR) {
824    let parameterName: string;
825    if (isSingleKey(node)) {
826      parameterName = getDecoratorKey(node);
827      updateState.push(createAddProvidedVar(parameterName, name));
828    }
829    if (parameterName !== name.getText()) {
830      updateState.push(createAddProvidedVar(name.getText(), name));
831    }
832  }
833}
834
835function createAddProvidedVar(propertyOrAliasName: string,
836  name: ts.Identifier): ts.ExpressionStatement {
837  return ts.factory.createExpressionStatement(ts.factory.createCallExpression(
838    createPropertyAccessExpressionWithThis(ADD_PROVIDED_VAR), undefined, [
839      ts.factory.createStringLiteral(propertyOrAliasName),
840      createPropertyAccessExpressionWithThis(`__${name.getText()}`)]));
841}
842
843function createGetAccessor(item: ts.Identifier, express: string): ts.GetAccessorDeclaration {
844  const getAccessorStatement: ts.GetAccessorDeclaration =
845    ts.factory.createGetAccessorDeclaration(undefined, undefined, item, [], undefined,
846      ts.factory.createBlock([ts.factory.createReturnStatement(
847        ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(
848          createPropertyAccessExpressionWithThis(`__${item.getText()}`),
849          ts.factory.createIdentifier(express)), undefined, []))], true));
850  return getAccessorStatement;
851}
852
853function createSetAccessor(item: ts.Identifier, express: string, type: ts.TypeNode):
854  ts.SetAccessorDeclaration {
855  const setAccessorStatement: ts.SetAccessorDeclaration =
856    ts.factory.createSetAccessorDeclaration(undefined, undefined, item,
857      [ts.factory.createParameterDeclaration(undefined, undefined, undefined,
858        ts.factory.createIdentifier(CREATE_NEWVALUE_IDENTIFIER), undefined, type,
859        undefined)], ts.factory.createBlock([ts.factory.createExpressionStatement(
860        ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(
861          createPropertyAccessExpressionWithThis(`__${item.getText()}`),
862          ts.factory.createIdentifier(express)), undefined,
863        [ts.factory.createIdentifier(CREATE_NEWVALUE_IDENTIFIER)]))], true));
864  return setAccessorStatement;
865}
866
867function isForbiddenUseStateType(typeNode: ts.TypeNode): boolean {
868  if (ts.isTypeReferenceNode(typeNode) && ts.isIdentifier(typeNode.typeName) &&
869    forbiddenUseStateType.has(typeNode.typeName.getText())) {
870    return true;
871  }
872  return false;
873}
874
875export function isSimpleType(typeNode: ts.TypeNode, program: ts.Program, log?: LogInfo[]): boolean {
876  if (!typeNode) {
877    return false;
878  }
879  let checker: ts.TypeChecker;
880  if (globalProgram.program) {
881    checker = globalProgram.program.getTypeChecker();
882  } else if (globalProgram.watchProgram) {
883    checker = globalProgram.watchProgram.getCurrentProgram().getProgram().getTypeChecker();
884  } else if (program) {
885    checker = program.getTypeChecker();
886  }
887  return getDeclarationType(typeNode, checker, log);
888}
889
890function getDeclarationType(typeNode: ts.TypeNode, checker: ts.TypeChecker, log: LogInfo[]): boolean {
891  if (simpleTypes.has(typeNode.kind)) {
892    return true;
893  }
894  if (ts.isTypeReferenceNode(typeNode) && typeNode.typeName && ts.isIdentifier(typeNode.typeName) &&
895    enumCollection.has(typeNode.typeName.escapedText.toString())) {
896    return true;
897  }
898  if (checker) {
899    const type: ts.Type = checker.getTypeFromTypeNode(typeNode);
900    /* Enum */
901    if (type.flags & (32 | 1024)) {
902      return true;
903    }
904    // @ts-ignore
905    if (type.types && type.types.length) {
906      // @ts-ignore
907      const types = type.types;
908      let basicType: boolean = false;
909      let referenceType: boolean = false;
910      for (let i = 0; i < types.length; i++) {
911        if (isBasicType(types[i].flags)) {
912          basicType = true;
913        } else {
914          referenceType = true;
915        }
916      }
917      if (basicType && referenceType && log) {
918        validateVariableType(typeNode, log);
919        return false;
920      }
921      if (!referenceType) {
922        return true;
923      }
924    }
925  }
926  if (typeNode.kind === ts.SyntaxKind.AnyKeyword && log) {
927    log.push({
928      type: LogType.WARN,
929      message: `Please define an explicit type, not any.`,
930      pos: typeNode.getStart()
931    });
932  }
933  return false;
934}
935
936function isBasicType(flags: number): boolean {
937  if (flags & (4 | /* String */ 8 | /* Number */ 16 | /* Boolean */ 32 | /* Enum */ 64 | /* BigInt */
938    128 | /* StringLiteral */ 256 | /* NumberLiteral */ 512 /* BooleanLiteral */| 1024 /* EnumLiteral */|
939    2048 /* BigIntLiteral */)) {
940    return true;
941  }
942  return false;
943}
944
945function isObservedClassType(type: ts.TypeNode): boolean {
946  if (judgmentTypedeclaration(type) && observedClassCollection.has(type.typeName.escapedText.toString())) {
947    return true;
948  } else if (ts.isUnionTypeNode(type) && type.types) {
949    const types: ts.NodeArray<ts.TypeNode> = type.types;
950    for (let i = 0; i < types.length; i++) {
951      if (judgmentTypedeclaration(types[i]) && !observedClassCollection.has(types[i].typeName.escapedText.toString())) {
952        return false;
953      }
954    }
955    return true;
956  }
957  return false;
958}
959
960function judgmentTypedeclaration(type: ts.TypeNode): boolean {
961  return ts.isTypeReferenceNode(type) && type.typeName && ts.isIdentifier(type.typeName);
962}
963
964function validateAppStorageDecoractorsNonSingleKey(node: ts.PropertyDeclaration,
965  log: LogInfo[]): void {
966  if (ts.isIdentifier(node.decorators[0].expression)) {
967    validateDecoratorNonSingleKey(node.decorators[0].expression, log);
968  } else if (ts.isCallExpression(node.decorators[0].expression) &&
969    ts.isIdentifier(node.decorators[0].expression.expression)) {
970    validateDecoratorNonSingleKey(node.decorators[0].expression.expression, log);
971  }
972}
973
974function isSingleKey(node: ts.PropertyDeclaration): boolean {
975  if (ts.isCallExpression(node.decorators[0].expression) &&
976  node.decorators[0].expression.arguments &&
977  node.decorators[0].expression.arguments.length === 1 &&
978  (ts.isIdentifier(node.decorators[0].expression.arguments[0]) ||
979  ts.isStringLiteral(node.decorators[0].expression.arguments[0]))) {
980    return true;
981  }
982}
983
984function validateMultiDecorators(name: ts.Identifier, log: LogInfo[]): void {
985  log.push({
986    type: LogType.ERROR,
987    message: `The property '${name.escapedText.toString()}' cannot have mutilate state management decorators.`,
988    pos: name.getStart()
989  });
990}
991
992function validateDecoratorNonSingleKey(decoratorsIdentifier: ts.Identifier,
993  log: LogInfo[]): void {
994  log.push({
995    type: LogType.ERROR,
996    message: `The decorator ${decoratorsIdentifier.escapedText.toString()} should have a single key.`,
997    pos: decoratorsIdentifier.getStart()
998  });
999}
1000
1001function validatePropertyNonDefaultValue(propertyName: ts.Identifier, decorator: string,
1002  log: LogInfo[]): void {
1003  log.push({
1004    type: LogType.ERROR,
1005    message: `The ${decorator} property '${propertyName.getText()}' must be specified a default value.`,
1006    pos: propertyName.getStart()
1007  });
1008}
1009
1010function validatePropertyDefaultValue(propertyName: ts.Identifier, decorator: string,
1011  log: LogInfo[]): void {
1012  log.push({
1013    type: LogType.ERROR,
1014    message: `The ${decorator} property '${propertyName.getText()}' cannot be specified a default value.`,
1015    pos: propertyName.getStart()
1016  });
1017}
1018
1019function validatePropertyNonType(propertyName: ts.Identifier, log: LogInfo[]): void {
1020  log.push({
1021    type: LogType.ERROR,
1022    message: `The property '${propertyName.getText()}' must specify a type.`,
1023    pos: propertyName.getStart()
1024  });
1025}
1026
1027function validateNonSimpleType(propertyName: ts.Identifier, decorator: string,
1028  log: LogInfo[]): void {
1029  log.push({
1030    type: LogType.ERROR,
1031    message: `The type of the ${decorator} property '${propertyName.getText()}' ` +
1032      `can only be string, number or boolean.`,
1033    pos: propertyName.getStart()
1034  });
1035}
1036
1037function validateNonObservedClassType(propertyName: ts.Identifier, decorator: string,
1038  log: LogInfo[]): void {
1039  log.push({
1040    type: LogType.ERROR,
1041    message: `The type of the ${decorator} property '${propertyName.getText()}' can only be ` +
1042      `objects of classes decorated with ${COMPONENT_OBSERVED_DECORATOR} class decorator in ets (not ts).`,
1043    pos: propertyName.getStart()
1044  });
1045}
1046
1047function validateHasIllegalQuestionToken(propertyName: ts.Identifier, decorator: string,
1048  log: LogInfo[]): void {
1049  log.push({
1050    type: LogType.WARN,
1051    message: `The ${decorator} property '${propertyName.getText()}' cannot be an optional parameter.`,
1052    pos: propertyName.getStart()
1053  });
1054}
1055
1056function validateHasIllegalDecoratorInEntry(parentName: ts.Identifier, propertyName: ts.Identifier,
1057  decorator: string, log: LogInfo[]): void {
1058  log.push({
1059    type: LogType.WARN,
1060    message: `The @Entry component '${parentName.getText()}' cannot have the ` +
1061      `${decorator} property '${propertyName.getText()}'.`,
1062    pos: propertyName.getStart()
1063  });
1064}
1065
1066function validateForbiddenUseStateType(propertyName: ts.Identifier, decorator: string, type: string,
1067  log: LogInfo[]): void {
1068  log.push({
1069    type: LogType.ERROR,
1070    message: `The ${decorator} property '${propertyName.getText()}' cannot be a '${type}' object.`,
1071    pos: propertyName.getStart()
1072  });
1073}
1074
1075function validateDuplicateDecorator(decorator: ts.Decorator, log: LogInfo[]): void {
1076  log.push({
1077    type: LogType.ERROR,
1078    message: `The decorator '${decorator.getText()}' cannot have the same name as the built-in ` +
1079      `style attribute '${decorator.getText().replace('@', '')}'.`,
1080    pos: decorator.getStart()
1081  });
1082}
1083
1084function validateWatchDecorator(propertyName: ts.Identifier, length: number, log: LogInfo[]): boolean {
1085  if (length === 1) {
1086    log.push({
1087      type: LogType.ERROR,
1088      message: `Regular variable '${propertyName.escapedText.toString()}' can not be decorated with @Watch.`,
1089      pos: propertyName.getStart()
1090    });
1091    return false;
1092  }
1093  return true;
1094}
1095
1096function validateWatchParam(type: LogType, pos: number, log: LogInfo[]): void {
1097  log.push({
1098    type: type,
1099    message: 'The parameter should be a string.',
1100    pos: pos
1101  });
1102}
1103
1104function validateVariableType(typeNode: ts.TypeNode, log: LogInfo[]): void {
1105  log.push({
1106    type: LogType.ERROR,
1107    message: `The state variable type here is '${typeNode.getText()}', ` +
1108      `it contains both a simple type and an object type,\n ` +
1109      `which are not allowed to be defined for state variable of a struct.`,
1110    pos: typeNode.getStart()
1111  });
1112}
1113
1114function updateObservedPropertyPU(item: ts.PropertyDeclaration, name: ts.Identifier,
1115  type: ts.TypeNode, program: ts.Program): ts.ExpressionStatement {
1116  return ts.factory.createExpressionStatement(ts.factory.createBinaryExpression(
1117    createPropertyAccessExpressionWithThis(`__${name.getText()}`),
1118    ts.factory.createToken(ts.SyntaxKind.EqualsToken), ts.factory.createNewExpression(
1119      ts.factory.createIdentifier(isSimpleType(type, program) ? OBSERVED_PROPERTY_SIMPLE_PU :
1120        OBSERVED_PROPERTY_OBJECT_PU), undefined, [item.initializer, ts.factory.createThis(),
1121        ts.factory.createStringLiteral(name.escapedText.toString())])));
1122}
1123
1124function updateSynchedPropertyTwoWayPU(nameIdentifier: ts.Identifier, type: ts.TypeNode,
1125  program: ts.Program): ts.ExpressionStatement {
1126  const name: string = nameIdentifier.escapedText.toString();
1127  const functionName: string = isSimpleType(type, program) ?
1128    SYNCHED_PROPERTY_SIMPLE_TWO_WAY_PU : SYNCHED_PROPERTY_OBJECT_TWO_WAY_PU;
1129  return createInitExpressionStatementForDecorator(name, functionName,
1130    createPropertyAccessExpressionWithParams(name));
1131}
1132
1133function updateSynchedPropertyOneWayPU(nameIdentifier: ts.Identifier, type: ts.TypeNode,
1134  decoractor: string, log: LogInfo[], program: ts.Program): ts.ExpressionStatement {
1135  const name: string = nameIdentifier.escapedText.toString();
1136  if (isSimpleType(type, program, log)) {
1137    return createInitExpressionStatementForDecorator(name, SYNCHED_PROPERTY_SIMPLE_ONE_WAY_PU,
1138      createPropertyAccessExpressionWithParams(name));
1139  } else {
1140    return createInitExpressionStatementForDecorator(name, SYNCHED_PROPERTY_OBJECT_ONE_WAY_PU,
1141      createPropertyAccessExpressionWithParams(name));
1142  }
1143}
1144
1145function updateSynchedPropertyNesedObjectPU(nameIdentifier: ts.Identifier,
1146  type: ts.TypeNode, decoractor: string, log: LogInfo[]): ts.ExpressionStatement {
1147  if (isObservedClassType(type)) {
1148    return createInitExpressionStatementForDecorator(nameIdentifier.getText(), SYNCHED_PROPERTY_NESED_OBJECT_PU,
1149      createPropertyAccessExpressionWithParams(nameIdentifier.getText()));
1150  } else {
1151    validateNonObservedClassType(nameIdentifier, decoractor, log);
1152  }
1153}
1154
1155function validateCustomDecorator(decorators: ts.NodeArray<ts.Decorator>, log: LogInfo[]): boolean {
1156  let hasInnerDecorator: boolean = false;
1157  let hasCustomDecorator: boolean = false;
1158  let innerDecorator: ts.Decorator;
1159  for(let i = 0; i < decorators.length; i++) {
1160    let decorator: ts.Decorator = decorators[i];
1161    const decoratorName: string = decorator.getText().replace(/\(.*\)$/, '').trim();
1162    if (INNER_COMPONENT_MEMBER_DECORATORS.has(decoratorName)) {
1163      hasInnerDecorator = true;
1164      innerDecorator = innerDecorator ? innerDecorator : decorator;
1165    } else {
1166      hasCustomDecorator = true;
1167    }
1168  }
1169  if (hasCustomDecorator && hasInnerDecorator) {
1170    log.push({
1171      type: LogType.ERROR,
1172      message: `The inner decorator ${innerDecorator.getText()} cannot be used together with custom decorator.`,
1173      pos: innerDecorator.getStart()
1174    });
1175  } else if(!hasInnerDecorator) {
1176    return true;
1177  }
1178  return false;
1179}
1180
1181function validatePropDecorator(decorators: ts.NodeArray<ts.Decorator>): boolean {
1182  for(let i = 0; i < decorators.length; i++) {
1183    let decorator: ts.Decorator = decorators[i];
1184    const decoratorName: string = decorator.getText().replace(/\(.*\)$/, '').trim();
1185    if (COMPONENT_PROP_DECORATOR === decoratorName) {
1186      return true;
1187    }
1188  }
1189  return false;
1190}
1191