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