• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2024 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';
17
18import {
19  LogInfo,
20  LogType,
21  addLog,
22  removeDecorator
23} from './utils';
24import {
25  COMPONENT_CONSTRUCTOR_PARENT,
26  COMPONENT_CONSTRUCTOR_PARAMS,
27  COMPONENT_CONSTRUCTOR_LOCALSTORAGE_PU,
28  ELMTID,
29  COMPONENT_PARAMS_LAMBDA_FUNCTION,
30  CUSTOM_COMPONENT_EXTRAINFO,
31  COMPONENT_CONSTRUCTOR_UNDEFINED,
32  REUSABLE_V2_INNER_DECORATOR,
33  REFLECT,
34  DEFINE_PROPERTY,
35  BASE_CLASS,
36  PROTOTYPE,
37  IS_REUSABLE_,
38  GET_ATTRIBUTE,
39} from './pre_define';
40import constantDefine from './constant_define';
41import createAstNodeUtils from './create_ast_node_utils';
42import {
43  updateHeritageClauses,
44  processComponentMethod,
45  BuildCount,
46  addRerenderFunc,
47  validateBuildMethodCount,
48  getEntryNameFunction,
49  FreezeParamType,
50  decoratorAssignParams
51} from './process_component_class';
52import { isReuseInV2 } from './process_custom_component';
53import { judgeBuilderParamAssignedByBuilder } from './process_component_member';
54import {
55  componentCollection,
56  builderParamObjectCollection
57} from './validate_ui_syntax';
58import logMessageCollection from './log_message_collection';
59import { globalProgram } from '../main';
60
61export class ParamDecoratorInfo {
62  initializer: ts.Expression;
63  hasRequire: boolean = false;
64}
65
66export class StructInfo {
67  isComponentV1: boolean = false;
68  isComponentV2: boolean = false;
69  isCustomDialog: boolean = false;
70  isReusable: boolean = false;
71  isReusableV2: boolean = false;
72  structName: string = '';
73  updatePropsDecoratorsV1: string[] = [];
74  linkDecoratorsV1: string[] = [];
75  paramDecoratorMap: Map<string, ParamDecoratorInfo> = new Map();
76  eventDecoratorMap: Map<string, ts.PropertyDeclaration> = new Map();
77  localDecoratorSet: Set<string> = new Set();
78  providerDecoratorSet: Set<string> = new Set();
79  consumerDecoratorSet: Set<string> = new Set();
80  builderParamDecoratorSet: Set<string> = new Set();
81  regularSet: Set<string> = new Set();
82  propertiesMap: Map<string, ts.Expression> = new Map();
83  staticPropertySet: Set<string> = new Set();
84  computedDecoratorSet: Set<string> = new Set();
85  monitorDecoratorSet: Set<string> = new Set();
86}
87
88const structMapInEts: Map<string, StructInfo> = new Map();
89
90function getOrCreateStructInfo(key: string): StructInfo {
91  let structInfo: StructInfo = structMapInEts.get(key);
92  if (!structInfo) {
93    structInfo = new StructInfo();
94    structInfo.structName = key;
95    structMapInEts.set(key, structInfo);
96  }
97  return structInfo;
98}
99
100/**
101 * import * as a from './common'
102 * a.struct()
103 */
104function getAliasStructInfo(node: ts.CallExpression): StructInfo {
105  let aliasStructInfo: StructInfo;
106  if (node.expression && structMapInEts.has(node.expression.getText())) {
107    aliasStructInfo = structMapInEts.get(node.expression.getText());
108  }
109  return aliasStructInfo;
110}
111
112function processStructComponentV2(node: ts.StructDeclaration, log: LogInfo[],
113  context: ts.TransformationContext, StateManagementV2: { hasReusableV2: boolean }): ts.ClassDeclaration {
114  const isReusableV2: boolean = node.name && ts.isIdentifier(node.name) && isReuseInV2(node.name.getText());
115  if (isReusableV2) {
116    StateManagementV2.hasReusableV2 = true;
117  }
118  return ts.factory.createClassDeclaration(isReusableV2 ?
119    ts.concatenateDecoratorsAndModifiers(
120      [ts.factory.createDecorator(ts.factory.createIdentifier(REUSABLE_V2_INNER_DECORATOR))],
121      ts.getModifiers(node)
122    ) :
123    ts.getModifiers(node),
124    node.name,
125    node.typeParameters,
126    updateHeritageClauses(node, log, true),
127    processStructMembersV2(node, context, log)
128  );
129}
130
131function createReusableV2ReflectFunction(): ts.FunctionDeclaration {
132  const reflectStatement: ts.ExpressionStatement = ts.factory.createExpressionStatement(
133    ts.factory.createCallExpression(
134      ts.factory.createPropertyAccessExpression(
135        ts.factory.createIdentifier(REFLECT), ts.factory.createIdentifier(DEFINE_PROPERTY)
136      ), undefined,
137      [
138        ts.factory.createPropertyAccessExpression(
139          ts.factory.createIdentifier(BASE_CLASS), ts.factory.createIdentifier(PROTOTYPE)
140        ),
141        ts.factory.createStringLiteral(IS_REUSABLE_),
142        ts.factory.createObjectLiteralExpression([
143          ts.factory.createPropertyAssignment(
144            ts.factory.createIdentifier(GET_ATTRIBUTE),
145            ts.factory.createArrowFunction(
146              undefined,
147              undefined,
148              [],
149              undefined,
150              ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
151              ts.factory.createTrue()
152            )
153          )],
154          false
155        )
156      ]
157    )
158  );
159  const parameter: ts.ParameterDeclaration = ts.factory.createParameterDeclaration(
160    undefined,
161    undefined,
162    ts.factory.createIdentifier(BASE_CLASS),
163    undefined,
164    undefined,
165    undefined
166  );
167  return ts.factory.createFunctionDeclaration(
168    undefined,
169    undefined,
170    ts.factory.createIdentifier(REUSABLE_V2_INNER_DECORATOR),
171    undefined,
172    [parameter],
173    undefined,
174    ts.factory.createBlock([reflectStatement])
175  );
176}
177
178function processStructMembersV2(node: ts.StructDeclaration, context: ts.TransformationContext,
179  log: LogInfo[]): ts.ClassElement[] {
180  const structName: string = node.name.getText();
181  const newMembers: ts.ClassElement[] = [];
182  const buildCount: BuildCount = { count: 0 };
183  const structInfo: StructInfo = getOrCreateStructInfo(structName);
184  const addStatementsInConstructor: ts.Statement[] = [];
185  const addStatementsInResetOnReuse: ts.Statement[] = [];
186  const paramStatementsInStateVarsMethod: ts.Statement[] = [];
187  const structDecorators: readonly ts.Decorator[] = ts.getAllDecorators(node);
188  const freezeParam: FreezeParamType = { componentFreezeParam: undefined };
189  decoratorAssignParams(structDecorators, context, freezeParam);
190  traverseStructInfo(structInfo, addStatementsInConstructor, paramStatementsInStateVarsMethod, addStatementsInResetOnReuse);
191  node.members.forEach((member: ts.ClassElement) => {
192    if (ts.isGetAccessor(member) && member.modifiers?.some(isComputedDecorator) && member.name &&
193      ts.isIdentifier(member.name)) {
194      const symbol: ts.Symbol = globalProgram.checker?.getSymbolAtLocation(member.name);
195      validateComputedGetter(symbol, log);
196    }
197    if (ts.isConstructorDeclaration(member)) {
198      processStructConstructorV2(node.members, newMembers, addStatementsInConstructor, freezeParam);
199      createResetStateVarsOnReuse(structInfo, newMembers, addStatementsInResetOnReuse);
200      return;
201    } else if (ts.isPropertyDeclaration(member)) {
202      newMembers.push(processComponentProperty(member, structInfo, log));
203      return;
204    } else if (ts.isMethodDeclaration(member) && member.name) {
205      const newMethodNode: ts.MethodDeclaration = processComponentMethod(member, context, log, buildCount);
206      if (newMethodNode) {
207        newMembers.push(newMethodNode);
208      }
209      return;
210    }
211    newMembers.push(member);
212  });
213  validateBuildMethodCount(buildCount, node.name, log);
214  updateStateVarsMethodNode(paramStatementsInStateVarsMethod, newMembers);
215  newMembers.push(addRerenderFunc([]));
216  if (componentCollection.entryComponent === structName) {
217    newMembers.push(getEntryNameFunction(componentCollection.entryComponent));
218  }
219  return newMembers;
220}
221
222function isComputedDecorator(decorator: ts.Decorator): boolean {
223  return ts.isDecorator(decorator) && ts.isIdentifier(decorator.expression) &&
224    decorator.expression.escapedText.toString() === constantDefine.COMPUTED;
225}
226
227function validateComputedGetter(symbol: ts.Symbol, log: LogInfo[]): void {
228  if (symbol && symbol.declarations) {
229    symbol.declarations.forEach((declaration: ts.Declaration) => {
230      logMessageCollection.checkComputedGetter(symbol, declaration, log);
231    });
232  }
233}
234
235function traverseStructInfo(structInfo: StructInfo,
236  addStatementsInConstructor: ts.Statement[], paramStatementsInStateVarsMethod: ts.Statement[],
237  addStatementsInResetOnReuse: ts.Statement[]): void {
238  const needInitFromParams: string[] = [...structInfo.builderParamDecoratorSet,
239    ...structInfo.eventDecoratorMap.keys()];
240  for (const property of structInfo.propertiesMap) {
241    if (!structInfo.staticPropertySet.has(property[0])) {
242      setPropertyStatement(structInfo, addStatementsInConstructor, property[0], property[1],
243        needInitFromParams, addStatementsInResetOnReuse);
244    }
245  }
246  for (const param of structInfo.paramDecoratorMap) {
247    if (!structInfo.staticPropertySet.has(param[0])) {
248      paramStatementsInStateVarsMethod.push(updateParamNode(param[0]));
249    }
250  }
251}
252
253function setPropertyStatement(structInfo: StructInfo, addStatementsInConstructor: ts.Statement[],
254  propName: string, initializer: ts.Expression, needInitFromParams: string[],
255  addStatementsInResetOnReuse: ts.Statement[]): void {
256  if (needInitFromParams.includes(propName)) {
257    if (structInfo.eventDecoratorMap.has(propName)) {
258      const eventDeclaration: ts.PropertyDeclaration = structInfo.eventDecoratorMap.get(propName);
259      addStatementsInConstructor.push(
260        createPropertyAssignNode(propName, initializer || getDefaultValueForEvent(eventDeclaration, false), true));
261      addStatementsInResetOnReuse.push(
262        createPropertyAssignNode(propName, initializer || getDefaultValueForEvent(eventDeclaration, true), true));
263    } else {
264      const builderParamExpression: ts.ExpressionStatement = createPropertyAssignNode(propName, initializer, true);
265      addStatementsInConstructor.push(builderParamExpression);
266      addStatementsInResetOnReuse.push(builderParamExpression);
267    }
268  } else if (structInfo.paramDecoratorMap.has(propName)) {
269    const paramProperty: ParamDecoratorInfo = structInfo.paramDecoratorMap.get(propName);
270    addStatementsInConstructor.push(createInitOrUpdateParam(propName, paramProperty.initializer, true));
271    addStatementsInResetOnReuse.push(createInitOrUpdateParam(propName, paramProperty.initializer, false));
272  } else if (structInfo.consumerDecoratorSet.has(propName)) {
273    addStatementsInConstructor.push(createPropertyAssignNode(propName, initializer, false));
274    addStatementsInResetOnReuse.push(createResetNode(propName, constantDefine.RESET_CONSUMER, initializer));
275  } else if (structInfo.regularSet.has(propName)) {
276    addStatementsInConstructor.push(createPropertyAssignNode(propName, initializer, false));
277  } else if (structInfo.computedDecoratorSet.has(propName)) {
278    addStatementsInResetOnReuse.push(createResetNode(propName, constantDefine.RESET_COMPUTED));
279  } else {
280    const propertyAssignNode: ts.ExpressionStatement = createPropertyAssignNode(propName, initializer, false);
281    addStatementsInConstructor.push(propertyAssignNode);
282    addStatementsInResetOnReuse.push(propertyAssignNode);
283  }
284}
285
286function getDefaultValueForEvent(node: ts.PropertyDeclaration, isResetOnReuse: boolean = false): ts.Expression {
287  let param: ts.NodeArray<ts.ParameterDeclaration>;
288  if (node.type && ts.isFunctionTypeNode(node.type) && node.type.parameters && node.type.parameters.length) {
289    param = node.type.parameters;
290  }
291  return ts.factory.createArrowFunction(undefined, undefined, isResetOnReuse && param ? param : [], undefined,
292    ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
293    ts.factory.createBlock([], false));
294}
295
296function createPropertyAssignNode(propName: string, initializer: ts.Expression,
297  initFromParams: boolean): ts.ExpressionStatement {
298  return ts.factory.createExpressionStatement(ts.factory.createBinaryExpression(
299    ts.factory.createPropertyAccessExpression(
300      ts.factory.createThis(),
301      ts.factory.createIdentifier(propName)
302    ),
303    ts.factory.createToken(ts.SyntaxKind.EqualsToken),
304    setInitValue(propName, initializer, initFromParams)
305  ));
306}
307
308function createResetNode(propName: string, type: string, initializer: ts.Expression = null): ts.ExpressionStatement {
309  return ts.factory.createExpressionStatement(ts.factory.createCallExpression(
310    ts.factory.createPropertyAccessExpression(
311      ts.factory.createThis(),
312      ts.factory.createIdentifier(type)
313    ),
314    undefined,
315    type === constantDefine.RESET_CONSUMER ?
316    [
317      ts.factory.createStringLiteral(propName),
318      initializer ? initializer : ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UNDEFINED)
319    ] : [
320      ts.factory.createStringLiteral(propName)
321    ]
322  ));
323}
324
325function processComponentProperty(member: ts.PropertyDeclaration, structInfo: StructInfo,
326  log: LogInfo[]): ts.PropertyDeclaration {
327  const propName: string = member.name.getText();
328  const decorators: readonly ts.Decorator[] = ts.getAllDecorators(member);
329  let initializer: ts.Expression;
330  if (!structInfo.regularSet.has(propName) && !member.type) {
331    checkV2ComponentMemberType(member.name, propName, log);
332  }
333  if (structInfo.staticPropertySet.has(propName)) {
334    initializer = member.initializer;
335  }
336  if (structInfo.paramDecoratorMap.has(propName) && structInfo.builderParamDecoratorSet.has(propName)) {
337    return processRequireBuilderParamProperty(member, decorators, initializer);
338  }
339  if (structInfo.paramDecoratorMap.has(propName)) {
340    return processParamProperty(member, decorators, initializer);
341  }
342  if (structInfo.builderParamDecoratorSet.has(propName)) {
343    return processBuilderParamProperty(member, log, decorators, initializer);
344  }
345  return ts.factory.updatePropertyDeclaration(member,
346    ts.concatenateDecoratorsAndModifiers(decorators, ts.getModifiers(member)),
347    member.name, member.questionToken, member.type, initializer);
348}
349
350function checkV2ComponentMemberType(node: ts.Node, propName: string, log: LogInfo[]): void {
351  log.push({
352    type: LogType.ERROR,
353    message: `The property '${propName}' must specify a type.`,
354    pos: node.getStart(),
355    code: '10905328'
356  });
357}
358
359function processParamProperty(member: ts.PropertyDeclaration,
360  decorators: readonly ts.Decorator[], initializer: ts.Expression): ts.PropertyDeclaration {
361  const newDecorators: readonly ts.Decorator[] = removeDecorator(decorators, constantDefine.REQUIRE);
362  return ts.factory.updatePropertyDeclaration(member,
363    ts.concatenateDecoratorsAndModifiers(newDecorators, ts.getModifiers(member)),
364    member.name, member.questionToken, member.type, initializer);
365}
366
367function processRequireBuilderParamProperty(member: ts.PropertyDeclaration,
368  decorators: readonly ts.Decorator[], initializer: ts.Expression): ts.PropertyDeclaration {
369  const tempDecorators: readonly ts.Decorator[] = removeDecorator(decorators, constantDefine.REQUIRE);
370  const newDecorators: readonly ts.Decorator[] = removeDecorator(tempDecorators, constantDefine.BUILDER_PARAM);
371  return ts.factory.updatePropertyDeclaration(member,
372    ts.concatenateDecoratorsAndModifiers(newDecorators, ts.getModifiers(member)),
373    member.name, member.questionToken, member.type, initializer);
374}
375
376function processBuilderParamProperty(member: ts.PropertyDeclaration, log: LogInfo[],
377  decorators: readonly ts.Decorator[], initializer: ts.Expression): ts.PropertyDeclaration {
378  if (judgeBuilderParamAssignedByBuilder(member)) {
379    log.push({
380      type: LogType.ERROR,
381      message: `'@BuilderParam' property can only initialized by '@Builder' function.`,
382      pos: member.getStart(),
383      code: '10905107'
384    });
385  }
386  const newDecorators: readonly ts.Decorator[] = removeDecorator(decorators, constantDefine.BUILDER_PARAM);
387  return ts.factory.updatePropertyDeclaration(member,
388    ts.concatenateDecoratorsAndModifiers(newDecorators, ts.getModifiers(member)),
389    member.name, member.questionToken, member.type, initializer);
390}
391
392function setInitValue(propName: string, initializer: ts.Expression,
393  initFromParams: boolean): ts.Expression {
394  let initNode: ts.Expression = initializer ||
395    ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UNDEFINED);
396  if (initFromParams) {
397    initNode = createInitNode(propName, initNode);
398  }
399  return initNode;
400}
401
402function createInitNode(propName: string, defaultValue: ts.Expression): ts.Expression {
403  return ts.factory.createConditionalExpression(
404    ts.factory.createBinaryExpression(
405      ts.factory.createStringLiteral(propName),
406      ts.factory.createToken(ts.SyntaxKind.InKeyword),
407      ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARAMS)
408    ),
409    ts.factory.createToken(ts.SyntaxKind.QuestionToken),
410    ts.factory.createPropertyAccessExpression(
411      ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARAMS),
412      ts.factory.createIdentifier(propName)
413    ),
414    ts.factory.createToken(ts.SyntaxKind.ColonToken),
415    defaultValue
416  );
417}
418
419function parseComponentProperty(node: ts.StructDeclaration, structInfo: StructInfo, log: LogInfo[],
420  sourceFileNode: ts.SourceFile): void {
421  node.members.forEach((member: ts.ClassElement) => {
422    if (ts.isPropertyDeclaration(member)) {
423      const decorators: readonly ts.Decorator[] = ts.getAllDecorators(member);
424      const modifiers: readonly ts.Modifier[] = ts.getModifiers(member);
425      structInfo.propertiesMap.set(member.name.getText(), member.initializer);
426      parsePropertyDecorator(member, decorators, structInfo, log, sourceFileNode);
427      parsePropertyModifiers(member.name.getText(), structInfo, modifiers);
428    } else if (ts.isGetAccessor(member)) {
429      const decorators: readonly ts.Decorator[] = ts.getAllDecorators(member);
430      parseGetAccessor(member, decorators, structInfo);
431    } else if (ts.isMethodDeclaration(member)) {
432      const decorators: readonly ts.Decorator[] = ts.getAllDecorators(member);
433      parseMethodDeclaration(member, decorators, structInfo);
434    }
435  });
436}
437
438function parseGetAccessor(member: ts.GetAccessorDeclaration, decorators: readonly ts.Decorator[],
439  structInfo: StructInfo): void {
440  if (decorators.length && decorators.some((value: ts.Decorator) => getDecoratorName(value) === constantDefine.COMPUTED_DECORATOR)) {
441    structInfo.propertiesMap.set(member.name.getText(), undefined);
442    structInfo.computedDecoratorSet.add(member.name.getText());
443  }
444}
445
446function parseMethodDeclaration(member: ts.MethodDeclaration, decorators: readonly ts.Decorator[],
447  structInfo: StructInfo): void {
448  if (decorators.length && decorators.some((value: ts.Decorator) => getDecoratorName(value) === constantDefine.MONITOR_DECORATOR)) {
449    structInfo.monitorDecoratorSet.add(member.name.getText());
450  }
451}
452
453function getDecoratorName(decorator: ts.Decorator): string {
454  return decorator.getText().replace(/\([^\(\)]*\)/, '').trim();
455}
456
457function parsePropertyModifiers(propName: string, structInfo: StructInfo,
458  modifiers: readonly ts.Modifier[]): void {
459  if (modifiers && modifiers.length) {
460    const isStatic: boolean = modifiers.some((item: ts.Modifier) => {
461      return item.kind === ts.SyntaxKind.StaticKeyword;
462    });
463    if (isStatic) {
464      structInfo.staticPropertySet.add(propName);
465    }
466  }
467}
468
469class PropertyDecorator {
470  hasParam: boolean = false;
471  hasRequire: boolean = false;
472  hasOnce: boolean = false;
473  hasEvent: boolean = false;
474}
475
476const decoratorsFunc: Record<string, Function> = {
477  'Param': parseParamDecorator,
478  'Event': parseEventDecorator,
479  'Require': parseRequireDecorator,
480  'Once': parseOnceDecorator,
481  'Local': parseLocalDecorator,
482  'BuilderParam': parseBuilderParamDecorator,
483  'Provider': parseProviderDecorator,
484  'Consumer': parseConsumerDecorator
485};
486
487function parsePropertyDecorator(member: ts.PropertyDeclaration, decorators: readonly ts.Decorator[],
488  structInfo: StructInfo, log: LogInfo[], sourceFileNode: ts.SourceFile): void {
489  const propertyDecorator: PropertyDecorator = new PropertyDecorator();
490  let isRegular: boolean = true;
491  for (let i = 0; i < decorators.length; i++) {
492    const originalName: string = getDecoratorName(decorators[i]);
493    const name: string = originalName.replace('@', '').trim();
494    if (decoratorsFunc[name]) {
495      decoratorsFunc[name](propertyDecorator, member, structInfo);
496    }
497    if (constantDefine.COMPONENT_MEMBER_DECORATOR_V2.includes(originalName) ||
498      originalName === constantDefine.DECORATOR_BUILDER_PARAM) {
499      isRegular = false;
500    }
501  }
502  if (isRegular) {
503    structInfo.regularSet.add(member.name.getText());
504  }
505  checkPropertyDecorator(propertyDecorator, member, log, sourceFileNode, structInfo);
506}
507
508function checkPropertyDecorator(propertyDecorator: PropertyDecorator,
509  member: ts.PropertyDeclaration, log: LogInfo[], sourceFileNode: ts.SourceFile,
510  structInfo: StructInfo): void {
511  if (log && sourceFileNode) {
512    checkParamDecorator(propertyDecorator, member, log, sourceFileNode, structInfo);
513  }
514}
515
516function parseParamDecorator(propertyDecorator: PropertyDecorator, member: ts.PropertyDeclaration,
517  structInfo: StructInfo): void {
518  propertyDecorator.hasParam = true;
519  let paramDecoratorInfo: ParamDecoratorInfo = structInfo.paramDecoratorMap.get(member.name.getText());
520  if (!paramDecoratorInfo) {
521    paramDecoratorInfo = new ParamDecoratorInfo();
522  }
523  paramDecoratorInfo.initializer = member.initializer;
524  structInfo.paramDecoratorMap.set(member.name.getText(), paramDecoratorInfo);
525}
526
527function parseEventDecorator(propertyDecorator: PropertyDecorator, member: ts.PropertyDeclaration,
528  structInfo: StructInfo): void {
529  propertyDecorator.hasEvent = true;
530  structInfo.eventDecoratorMap.set(member.name.getText(), member);
531}
532
533function parseRequireDecorator(propertyDecorator: PropertyDecorator, member: ts.PropertyDeclaration,
534  structInfo: StructInfo): void {
535  propertyDecorator.hasRequire = true;
536  let paramDecoratorInfo: ParamDecoratorInfo = structInfo.paramDecoratorMap.get(member.name.getText());
537  if (!paramDecoratorInfo) {
538    paramDecoratorInfo = new ParamDecoratorInfo();
539  }
540  paramDecoratorInfo.hasRequire = true;
541  structInfo.paramDecoratorMap.set(member.name.getText(), paramDecoratorInfo);
542}
543
544function parseOnceDecorator(propertyDecorator: PropertyDecorator): void {
545  propertyDecorator.hasOnce = true;
546}
547
548function parseLocalDecorator(propertyDecorator: PropertyDecorator, member: ts.PropertyDeclaration,
549  structInfo: StructInfo): void {
550  structInfo.localDecoratorSet.add(member.name.getText());
551}
552
553function parseProviderDecorator(propertyDecorator: PropertyDecorator, member: ts.PropertyDeclaration,
554  structInfo: StructInfo): void {
555  structInfo.providerDecoratorSet.add(member.name.getText());
556}
557
558function parseConsumerDecorator(propertyDecorator: PropertyDecorator, member: ts.PropertyDeclaration,
559  structInfo: StructInfo): void {
560  structInfo.consumerDecoratorSet.add(member.name.getText());
561}
562
563function parseBuilderParamDecorator(propertyDecorator: PropertyDecorator, member: ts.PropertyDeclaration,
564  structInfo: StructInfo): void {
565  let builderParamSet: Set<string> = builderParamObjectCollection.get(structInfo.structName);
566  if (!builderParamSet) {
567    builderParamSet = new Set();
568  }
569  builderParamSet.add(member.name.getText());
570  builderParamObjectCollection.set(structInfo.structName, builderParamSet);
571  structInfo.builderParamDecoratorSet.add(member.name.getText());
572}
573
574function checkHasBuilderParamDecorator(propertyDecorator: PropertyDecorator, member: ts.PropertyDeclaration,
575  sourceFileNode: ts.SourceFile, structInfo: StructInfo): boolean {
576  let checkResult: boolean = false;
577  if (StructInfo) {
578    checkResult = structInfo.builderParamDecoratorSet.has(member.name.getText());
579  }
580  return checkResult;
581}
582
583function checkParamDecorator(propertyDecorator: PropertyDecorator, member: ts.PropertyDeclaration, log: LogInfo[],
584  sourceFileNode: ts.SourceFile, structInfo: StructInfo): void {
585  if (propertyDecorator.hasParam && !member.initializer && !propertyDecorator.hasRequire) {
586    const message: string = 'When a variable decorated with \'@Param\' is not assigned a default value, ' +
587      'it must also be decorated with \'@Require\'.';
588    addLog(LogType.ERROR, message, member.getStart(), log, sourceFileNode, { code: '10905327' });
589  }
590  if (propertyDecorator.hasOnce && !propertyDecorator.hasParam) {
591    const message: string = 'When a variable decorated with \'@Once\', it must also be decorated with \'@Param\'.';
592    addLog(LogType.ERROR, message, member.getStart(), log, sourceFileNode, { code: '10905326' });
593  }
594  if (propertyDecorator.hasRequire && !propertyDecorator.hasParam && !checkHasBuilderParamDecorator(propertyDecorator,
595    member, sourceFileNode, structInfo)) {
596    const message: string = 'In a struct decorated with \'@ComponentV2\', \'@Require\' can only be used with \'@Param\'.';
597    addLog(LogType.ERROR, message, member.getStart(), log, sourceFileNode, { code: '10905325' });
598  }
599}
600
601function processStructConstructorV2(members: ts.NodeArray<ts.ClassElement>, newMembers: ts.ClassElement[],
602  paramStatements: ts.Statement[], freezeParam: FreezeParamType): void {
603  const freezeParamNode: ts.Expression = freezeParam.componentFreezeParam ?
604    freezeParam.componentFreezeParam : undefined;
605  const constructorIndex: number = members.findIndex((item: ts.ClassElement) => {
606    return ts.isConstructorDeclaration(item);
607  });
608  if (constructorIndex !== -1) {
609    const constructorNode: ts.ConstructorDeclaration = members[constructorIndex] as ts.ConstructorDeclaration;
610    newMembers.splice(constructorIndex, 0, ts.factory.updateConstructorDeclaration(constructorNode, ts.getModifiers(constructorNode),
611      createConstructorParams(), updateConstructorBody(constructorNode.body, paramStatements, freezeParamNode)));
612  }
613}
614
615function createConstructorParams(): ts.ParameterDeclaration[] {
616  const paramNames: string[] = [COMPONENT_CONSTRUCTOR_PARENT, COMPONENT_CONSTRUCTOR_PARAMS,
617    COMPONENT_CONSTRUCTOR_LOCALSTORAGE_PU, ELMTID, COMPONENT_PARAMS_LAMBDA_FUNCTION,
618    CUSTOM_COMPONENT_EXTRAINFO];
619  return paramNames.map((name: string) => {
620    return createAstNodeUtils.createParameterDeclaration(name);
621  });
622}
623
624function updateConstructorBody(node: ts.Block, paramStatements: ts.Statement[],
625  freezeParamNode: ts.Expression): ts.Block {
626  const body: ts.Statement[] = [createSuperV2()];
627  if (node.statements) {
628    body.push(...node.statements);
629  }
630  body.push(...paramStatements, createAstNodeUtils.createFinalizeConstruction(freezeParamNode));
631  return ts.factory.createBlock(body, true);
632}
633
634function createResetStateVarsOnReuse(structInfo: StructInfo, newMembers: ts.ClassElement[],
635  addStatementsInResetOnReuse: ts.Statement[]): void {
636  if (structInfo.monitorDecoratorSet.size) {
637    addStatementsInResetOnReuse.push(generateResetMonitor());
638  }
639  const resetOnReuseNode: ts.MethodDeclaration = ts.factory.createMethodDeclaration(
640    [ts.factory.createToken(ts.SyntaxKind.PublicKeyword)],
641    undefined,
642    ts.factory.createIdentifier(constantDefine.RESET_STATE_VARS_METHOD),
643    undefined,
644    undefined,
645    [ts.factory.createParameterDeclaration(
646      undefined,
647      undefined,
648      ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARAMS),
649      undefined,
650      ts.factory.createTypeReferenceNode(
651        ts.factory.createIdentifier(constantDefine.OBJECT_TYPE),
652        undefined
653      ),
654      undefined
655    )],
656    ts.factory.createKeywordTypeNode(ts.SyntaxKind.VoidKeyword),
657    ts.factory.createBlock(
658      addStatementsInResetOnReuse,
659      true
660    )
661  );
662  newMembers.push(resetOnReuseNode);
663}
664
665function generateResetMonitor(): ts.ExpressionStatement {
666  return ts.factory.createExpressionStatement(ts.factory.createCallExpression(
667    ts.factory.createPropertyAccessExpression(
668      ts.factory.createThis(),
669      ts.factory.createIdentifier(constantDefine.RESET_MONITORS_ON_REUSE)
670    ),
671    undefined,
672    []
673  ));
674}
675
676function createSuperV2(): ts.Statement {
677  const paramNames: string[] = [COMPONENT_CONSTRUCTOR_PARENT, ELMTID, CUSTOM_COMPONENT_EXTRAINFO];
678  return ts.factory.createExpressionStatement(ts.factory.createCallExpression(
679    ts.factory.createSuper(), undefined, paramNames.map((name: string) => {
680      return ts.factory.createIdentifier(name);
681    })));
682}
683
684function createInitOrUpdateParam(propName: string, initializer: ts.Expression, isInit: boolean): ts.ExpressionStatement {
685  return ts.factory.createExpressionStatement(ts.factory.createCallExpression(
686    ts.factory.createPropertyAccessExpression(ts.factory.createThis(),
687      ts.factory.createIdentifier(isInit ? constantDefine.INIT_PARAM : constantDefine.RESET_PARAM)),
688    undefined,
689    [
690      ts.factory.createStringLiteral(propName),
691      ts.factory.createConditionalExpression(ts.factory.createParenthesizedExpression(
692        ts.factory.createBinaryExpression(ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARAMS),
693          ts.factory.createToken(ts.SyntaxKind.AmpersandAmpersandToken),
694          createParamBinaryNode(propName)
695        )),
696      ts.factory.createToken(ts.SyntaxKind.QuestionToken),
697      ts.factory.createPropertyAccessExpression(
698        ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARAMS), ts.factory.createIdentifier(propName)
699      ),
700      ts.factory.createToken(ts.SyntaxKind.ColonToken),
701      initializer || ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UNDEFINED)
702      )
703    ]));
704}
705
706function updateParamNode(propName: string): ts.IfStatement {
707  return ts.factory.createIfStatement(createParamBinaryNode(propName),
708    ts.factory.createBlock([
709      ts.factory.createExpressionStatement(ts.factory.createCallExpression(
710        ts.factory.createPropertyAccessExpression(ts.factory.createThis(),
711          ts.factory.createIdentifier(constantDefine.UPDATE_PARAM)),
712        undefined,
713        [
714          ts.factory.createStringLiteral(propName),
715          ts.factory.createPropertyAccessExpression(
716            ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARAMS), ts.factory.createIdentifier(propName)
717          )
718        ]))], true));
719}
720
721function createParamBinaryNode(propName: string): ts.BinaryExpression {
722  return ts.factory.createBinaryExpression(
723    ts.factory.createStringLiteral(propName),
724    ts.factory.createToken(ts.SyntaxKind.InKeyword),
725    ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARAMS)
726  );
727}
728
729function updateStateVarsMethodNode(paramStatements: ts.Statement[], newMembers: ts.ClassElement[]): void {
730  if (paramStatements.length) {
731    newMembers.push(ts.factory.createMethodDeclaration([ts.factory.createToken(ts.SyntaxKind.PublicKeyword)],
732      undefined, ts.factory.createIdentifier(constantDefine.UPDATE_STATE_VARS), undefined, undefined,
733      [createAstNodeUtils.createParameterDeclaration(COMPONENT_CONSTRUCTOR_PARAMS)], undefined,
734      ts.factory.createBlock([emptyJudgeForParamsNode(), ...paramStatements], true)));
735  }
736}
737
738function emptyJudgeForParamsNode(): ts.IfStatement {
739  return ts.factory.createIfStatement(ts.factory.createBinaryExpression(
740    ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARAMS),
741    ts.factory.createToken(ts.SyntaxKind.EqualsEqualsEqualsToken),
742    ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UNDEFINED)
743  ), ts.factory.createBlock([ts.factory.createReturnStatement(undefined)], true), undefined);
744}
745
746function resetStructMapInEts(): void {
747  structMapInEts.clear();
748}
749
750export default {
751  getOrCreateStructInfo: getOrCreateStructInfo,
752  processStructComponentV2: processStructComponentV2,
753  parseComponentProperty: parseComponentProperty,
754  resetStructMapInEts: resetStructMapInEts,
755  getAliasStructInfo: getAliasStructInfo,
756  createReusableV2ReflectFunction: createReusableV2ReflectFunction
757};
758