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