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