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