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