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