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