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