1/* 2 * Copyright (c) 2021 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import ts from 'typescript'; 17 18import { 19 COMPONENT_STATE_DECORATOR, 20 COMPONENT_PROVIDE_DECORATOR, 21 COMPONENT_LINK_DECORATOR, 22 COMPONENT_PROP_DECORATOR, 23 COMPONENT_STORAGE_LINK_DECORATOR, 24 COMPONENT_STORAGE_PROP_DECORATOR, 25 COMPONENT_OBJECT_LINK_DECORATOR, 26 COMPONENT_CONSUME_DECORATOR, 27 SYNCHED_PROPERTY_NESED_OBJECT, 28 SYNCHED_PROPERTY_SIMPLE_TWO_WAY, 29 SYNCHED_PROPERTY_SIMPLE_ONE_WAY, 30 OBSERVED_PROPERTY_OBJECT, 31 OBSERVED_PROPERTY_SIMPLE, 32 COMPONENT_BUILD_FUNCTION, 33 BASE_COMPONENT_NAME, 34 CREATE_CONSTRUCTOR_PARAMS, 35 COMPONENT_CONSTRUCTOR_UPDATE_PARAMS, 36 COMPONENT_CONSTRUCTOR_INITIAL_PARAMS, 37 COMPONENT_CONSTRUCTOR_PURGE_VARIABLE_DEP, 38 COMPONENT_CONSTRUCTOR_DELETE_PARAMS, 39 COMPONENT_DECORATOR_PREVIEW, 40 CREATE_CONSTRUCTOR_SUBSCRIBER_MANAGER, 41 ABOUT_TO_BE_DELETE_FUNCTION_ID, 42 ABOUT_TO_BE_DELETE_FUNCTION_ID__, 43 CREATE_CONSTRUCTOR_GET_FUNCTION, 44 CREATE_CONSTRUCTOR_DELETE_FUNCTION, 45 FOREACH_OBSERVED_OBJECT, 46 FOREACH_GET_RAW_OBJECT, 47 COMPONENT_BUILDER_DECORATOR, 48 COMPONENT_TRANSITION_FUNCTION, 49 COMPONENT_CREATE_FUNCTION, 50 GEOMETRY_VIEW, 51 COMPONENT_STYLES_DECORATOR, 52 STYLES, 53 INTERFACE_NAME_SUFFIX, 54 OBSERVED_PROPERTY_ABSTRACT, 55 COMPONENT_LOCAL_STORAGE_LINK_DECORATOR, 56 COMPONENT_LOCAL_STORAGE_PROP_DECORATOR, 57 COMPONENT_CONSTRUCTOR_LOCALSTORAGE, 58 COMPONENT_SET_AND_LINK, 59 COMPONENT_SET_AND_PROP, 60 COMPONENT_CONSTRUCTOR_UNDEFINED, 61 CUSTOM_COMPONENT, 62 COMPONENT_CONSTRUCTOR_PARENT, 63 NULL, 64 INNER_COMPONENT_MEMBER_DECORATORS, 65 COMPONENT_RERENDER_FUNCTION, 66 RMELMTID, 67 ABOUTTOBEDELETEDINTERNAL, 68 UPDATEDIRTYELEMENTS, 69 BASE_COMPONENT_NAME_PU, 70 OBSERVED_PROPERTY_SIMPLE_PU, 71 OBSERVED_PROPERTY_OBJECT_PU, 72 SYNCHED_PROPERTY_SIMPLE_TWO_WAY_PU, 73 SYNCHED_PROPERTY_SIMPLE_ONE_WAY_PU, 74 SYNCHED_PROPERTY_NESED_OBJECT_PU, 75 OBSERVED_PROPERTY_ABSTRACT_PU, 76 CREATE_LOCAL_STORAGE_LINK, 77 CREATE_LOCAL_STORAGE_PROP, 78 COMPONENT_UPDATE_STATE_VARS, 79 COMPONENT_WATCH_DECORATOR, 80 $$, 81 COMPONENT_UPDATE_ELMT_ID, 82 OLD_ELMT_ID, 83 NEW_ELMT_ID, 84 UPDATE_RECYCLE_ELMT_ID, 85 GET_ENTRYNAME, 86 COMPONENT_PARAMS_FUNCTION, 87 FUNCTION, 88 COMPONENT_PARAMS_LAMBDA_FUNCTION, 89 DECORATOR_COMPONENT_FREEZEWHENINACTIVE, 90 INIT_ALLOW_COMPONENT_FREEZE, 91 FINALIZE_CONSTRUCTION, 92 PROTOTYPE, 93 REFLECT, 94 CREATE_SET_METHOD, 95 COMPONENT_REQUIRE_DECORATOR, 96 CONTEXT_STACK, 97 COMPONENT_IF_UNDEFINED, 98 COMPONENT_POP_FUNCTION, 99 PUSH, 100 PUV2_VIEW_BASE, 101 COMPONENT_LOCAL_BUILDER_DECORATOR, 102 DECORATOR_REUSEABLE 103} from './pre_define'; 104import { 105 BUILDIN_STYLE_NAMES, 106 CUSTOM_BUILDER_METHOD, 107 INNER_STYLE_FUNCTION, 108 INTERFACE_NODE_SET, 109 STYLES_ATTRIBUTE, 110 INNER_CUSTOM_BUILDER_METHOD 111} from './component_map'; 112import { 113 componentCollection, 114 linkCollection, 115 localStorageLinkCollection, 116 localStoragePropCollection, 117 builderParamObjectCollection, 118 methodDecoratorCollect 119} from './validate_ui_syntax'; 120import { 121 addConstructor, 122 getInitConstructor, 123 updateConstructor 124} from './process_component_constructor'; 125import { 126 ControllerType, 127 processMemberVariableDecorators, 128 UpdateResult, 129 stateObjectCollection, 130 PropMapManager, 131 decoratorParamSet, 132 isSimpleType, 133 isSingleKey, 134 findDecoratorIndex 135} from './process_component_member'; 136import { 137 processComponentBuild, 138 processComponentBlock 139} from './process_component_build'; 140import { isRecycle } from './process_custom_component'; 141import { 142 LogType, 143 LogInfo, 144 hasDecorator, 145 getPossibleBuilderTypeParameter, 146 storedFileInfo, 147 removeDecorator 148} from './utils'; 149import { 150 partialUpdateConfig, 151 projectConfig 152} from '../main'; 153import { 154 builderTypeParameter, 155 initializeMYIDS, 156 globalBuilderParamAssignment 157} from './process_ui_syntax'; 158import constantDefine from './constant_define'; 159import processStructComponentV2, { StructInfo } from './process_struct_componentV2'; 160 161export function processComponentClass(node: ts.StructDeclaration, context: ts.TransformationContext, 162 log: LogInfo[], program: ts.Program): ts.ClassDeclaration { 163 const decoratorNode: readonly ts.Decorator[] = ts.getAllDecorators(node); 164 const memberNode: ts.ClassElement[] = 165 processMembers(node.members, node.name, context, decoratorNode, log, program, checkPreview(node)); 166 return ts.factory.createClassDeclaration( 167 ts.getModifiers(node), 168 node.name, 169 node.typeParameters, 170 updateHeritageClauses(node, log), 171 memberNode 172 ); 173} 174 175function checkPreview(node: ts.StructDeclaration): boolean { 176 let hasPreview: boolean = false; 177 const decorators: readonly ts.Decorator[] = ts.getAllDecorators(node); 178 if (node && decorators) { 179 for (let i = 0; i < decorators.length; i++) { 180 const name: string = decorators[i].getText().replace(/\([^\(\)]*\)/, '').trim(); 181 if (name === COMPONENT_DECORATOR_PREVIEW) { 182 hasPreview = true; 183 break; 184 } 185 } 186 } 187 return hasPreview; 188} 189 190export type BuildCount = { 191 count: number; 192}; 193export type FreezeParamType = { 194 componentFreezeParam: ts.Expression; 195}; 196function processMembers(members: ts.NodeArray<ts.ClassElement>, parentComponentName: ts.Identifier, 197 context: ts.TransformationContext, decoratorNode: readonly ts.Decorator[], log: LogInfo[], 198 program: ts.Program, hasPreview: boolean): ts.ClassElement[] { 199 const buildCount: BuildCount = { count: 0 }; 200 let ctorNode: any = getInitConstructor(members, parentComponentName); 201 const newMembers: ts.ClassElement[] = []; 202 const watchMap: Map<string, ts.Node> = new Map(); 203 const updateParamsStatements: ts.Statement[] = []; 204 const stateVarsStatements: ts.Statement[] = []; 205 const purgeVariableDepStatements: ts.Statement[] = []; 206 const rerenderStatements: ts.Statement[] = []; 207 const deleteParamsStatements: ts.PropertyDeclaration[] = []; 208 const checkController: ControllerType = { hasController: !componentCollection.customDialogs.has(parentComponentName.getText()), 209 unassignedControllerSet: new Set() }; 210 const interfaceNode = ts.factory.createInterfaceDeclaration(undefined, 211 parentComponentName.getText() + INTERFACE_NAME_SUFFIX, undefined, undefined, []); 212 members.forEach((item: ts.MethodDeclaration) => { 213 if (hasDecorator(item, COMPONENT_STYLES_DECORATOR)) { 214 methodDecoratorCollect(item); 215 } 216 }); 217 members.forEach((item: ts.ClassElement) => { 218 let updateItem: ts.ClassElement | undefined; 219 if (ts.isPropertyDeclaration(item)) { 220 if (isStaticProperty(item)) { 221 newMembers.push(item); 222 validateDecorators(item, log); 223 } else { 224 addPropertyMember(item, newMembers, program, parentComponentName.getText(), log); 225 const result: UpdateResult = processMemberVariableDecorators(parentComponentName, item, 226 ctorNode, watchMap, checkController, log, program, context, hasPreview, interfaceNode); 227 if (result.isItemUpdate()) { 228 updateItem = result.getProperity(); 229 } else { 230 updateItem = item; 231 } 232 if (result.getVariableGet()) { 233 newMembers.push(result.getVariableGet()); 234 } 235 if (result.getVariableSet()) { 236 newMembers.push(result.getVariableSet()); 237 } 238 if (result.isCtorUpdate()) { 239 ctorNode = result.getCtor(); 240 } 241 if (result.getUpdateParams()) { 242 updateParamsStatements.push(result.getUpdateParams()); 243 } 244 if (result.getStateVarsParams()) { 245 stateVarsStatements.push(result.getStateVarsParams()); 246 } 247 if (result.isDeleteParams()) { 248 deleteParamsStatements.push(item); 249 } 250 if (result.getControllerSet()) { 251 newMembers.push(result.getControllerSet()); 252 } 253 processPropertyUnchanged(result, purgeVariableDepStatements); 254 } 255 } 256 if (ts.isMethodDeclaration(item) && item.name) { 257 updateItem = 258 processComponentMethod(item, context, log, buildCount); 259 } 260 if (updateItem) { 261 newMembers.push(updateItem); 262 } 263 }); 264 INTERFACE_NODE_SET.add(interfaceNode); 265 validateBuildMethodCount(buildCount, parentComponentName, log); 266 validateHasControllerAndControllerCount(parentComponentName, checkController, log); 267 if (storedFileInfo.getCurrentArkTsFile().recycleComponents.has(parentComponentName.getText())) { 268 newMembers.unshift(addDeleteParamsFunc(deleteParamsStatements, true)); 269 } 270 newMembers.unshift(addDeleteParamsFunc(deleteParamsStatements)); 271 addIntoNewMembers(newMembers, parentComponentName, updateParamsStatements, 272 purgeVariableDepStatements, rerenderStatements, stateVarsStatements); 273 if (partialUpdateConfig.partialUpdateMode) { 274 const creezeParam: FreezeParamType = { 275 componentFreezeParam: undefined 276 }; 277 const isFreezeComponent: boolean = decoratorAssignParams(decoratorNode, context, creezeParam); 278 ctorNode = updateConstructor(ctorNode, [], assignParams(parentComponentName.getText()), 279 isFreezeComponent ? decoratorComponentParam(creezeParam) : [], true); 280 } 281 newMembers.unshift(addConstructor(ctorNode, watchMap, parentComponentName)); 282 if (componentCollection.entryComponent === parentComponentName.escapedText.toString() && 283 partialUpdateConfig.partialUpdateMode && projectConfig.minAPIVersion > 10) { 284 newMembers.push(getEntryNameFunction(componentCollection.entryComponent)); 285 } 286 log.push(...Array.from(PropMapManager.logInfoMap.values()).flat()); 287 PropMapManager.reset(); 288 return newMembers; 289} 290 291export function decoratorAssignParams(decoratorNode: readonly ts.Decorator[], context: ts.TransformationContext, 292 creezeParam: FreezeParamType): boolean { 293 if (decoratorNode && Array.isArray(decoratorNode) && decoratorNode.length) { 294 return decoratorNode.some((item: ts.Decorator) => { 295 if (isFreezeComponents(item, context, creezeParam)) { 296 return true; 297 } else { 298 return false; 299 } 300 }); 301 } else { 302 return false; 303 } 304} 305 306function isFreezeComponents(decorator: ts.Decorator, context: ts.TransformationContext, 307 creezeParam: FreezeParamType): boolean { 308 let isComponentAssignParent: boolean = false; 309 ts.visitNode(decorator, visitComponentParament); 310 function visitComponentParament(decorator: ts.Node): ts.Node { 311 if (ts.isPropertyAssignment(decorator) && decorator.name && decorator.name.text && 312 decorator.name.text.toString() === DECORATOR_COMPONENT_FREEZEWHENINACTIVE) { 313 isComponentAssignParent = true; 314 creezeParam.componentFreezeParam = decorator.initializer; 315 return decorator; 316 } 317 return ts.visitEachChild(decorator, visitComponentParament, context); 318 } 319 return isComponentAssignParent; 320} 321 322export function getEntryNameFunction(entryName: string): ts.MethodDeclaration { 323 return ts.factory.createMethodDeclaration( 324 [ts.factory.createToken(ts.SyntaxKind.StaticKeyword)], 325 undefined, 326 ts.factory.createIdentifier(GET_ENTRYNAME), 327 undefined, 328 undefined, 329 [], 330 ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword), 331 ts.factory.createBlock( 332 [ts.factory.createReturnStatement(ts.factory.createStringLiteral(entryName))], 333 true 334 ) 335 ); 336} 337 338function assignParams(parentComponentName: string): ts.Statement[] { 339 return [ts.factory.createIfStatement( 340 ts.factory.createBinaryExpression( 341 ts.factory.createTypeOfExpression(ts.factory.createIdentifier(COMPONENT_PARAMS_LAMBDA_FUNCTION)), 342 ts.factory.createToken(ts.SyntaxKind.EqualsEqualsEqualsToken), 343 ts.factory.createStringLiteral(FUNCTION) 344 ), 345 ts.factory.createBlock( 346 [ts.factory.createExpressionStatement(ts.factory.createBinaryExpression( 347 ts.factory.createPropertyAccessExpression( 348 ts.factory.createThis(), 349 ts.factory.createIdentifier(COMPONENT_PARAMS_FUNCTION) 350 ), 351 ts.factory.createToken(ts.SyntaxKind.EqualsToken), 352 ts.factory.createIdentifier(COMPONENT_PARAMS_LAMBDA_FUNCTION) 353 ))], 354 true 355 ) 356 )]; 357} 358 359function decoratorComponentParam(freezeParam: FreezeParamType): ts.IfStatement[] { 360 return [ts.factory.createIfStatement( 361 ts.factory.createBinaryExpression( 362 ts.factory.createElementAccessExpression( 363 ts.factory.createSuper(), 364 ts.factory.createStringLiteral(INIT_ALLOW_COMPONENT_FREEZE) 365 ), 366 ts.factory.createToken(ts.SyntaxKind.AmpersandAmpersandToken), 367 ts.factory.createBinaryExpression( 368 ts.factory.createTypeOfExpression(ts.factory.createElementAccessExpression( 369 ts.factory.createSuper(), 370 ts.factory.createStringLiteral(INIT_ALLOW_COMPONENT_FREEZE) 371 )), 372 ts.factory.createToken(ts.SyntaxKind.EqualsEqualsEqualsToken), 373 ts.factory.createStringLiteral(FUNCTION) 374 ) 375 ), 376 ts.factory.createBlock( 377 [ts.factory.createExpressionStatement(ts.factory.createCallExpression( 378 ts.factory.createElementAccessExpression( 379 ts.factory.createSuper(), 380 ts.factory.createStringLiteral(INIT_ALLOW_COMPONENT_FREEZE) 381 ), 382 undefined, 383 [freezeParam.componentFreezeParam] 384 ))], 385 true 386 ), 387 undefined 388 )]; 389} 390 391function isStaticProperty(property: ts.PropertyDeclaration): boolean { 392 const modifiers: readonly ts.Modifier[] = 393 ts.canHaveModifiers(property) ? ts.getModifiers(property) : undefined; 394 return modifiers && modifiers.length && modifiers.some(modifier => { 395 return modifier.kind === ts.SyntaxKind.StaticKeyword; 396 }); 397} 398 399function validateDecorators(item: ts.ClassElement, log: LogInfo[]): void { 400 const decorators: readonly ts.Decorator[] = ts.getAllDecorators(item); 401 if (decorators && decorators.length) { 402 decorators.map((decorator: ts.Decorator) => { 403 const decoratorName: string = decorator.getText(); 404 if (INNER_COMPONENT_MEMBER_DECORATORS.has(decoratorName)) { 405 log.push({ 406 type: LogType.ERROR, 407 message: `The static variable of struct cannot be used together with built-in decorators.`, 408 pos: item.getStart(), 409 code: '10905313' 410 }); 411 } 412 }); 413 } 414} 415 416function processPropertyUnchanged( 417 result: UpdateResult, 418 purgeVariableDepStatements: ts.Statement[] 419): void { 420 if (partialUpdateConfig.partialUpdateMode) { 421 if (result.getPurgeVariableDepStatement()) { 422 purgeVariableDepStatements.push(result.getPurgeVariableDepStatement()); 423 } 424 } 425} 426 427function addIntoNewMembers( 428 newMembers: ts.ClassElement[], 429 parentComponentName: ts.Identifier, 430 updateParamsStatements: ts.Statement[], 431 purgeVariableDepStatements: ts.Statement[], 432 rerenderStatements: ts.Statement[], 433 stateVarsStatements: ts.Statement[] 434): void { 435 if (partialUpdateConfig.partialUpdateMode) { 436 newMembers.unshift( 437 addInitialParamsFunc(updateParamsStatements, parentComponentName), 438 addUpdateStateVarsFunc(stateVarsStatements, parentComponentName), 439 addPurgeVariableDepFunc(purgeVariableDepStatements) 440 ); 441 newMembers.push(addRerenderFunc(rerenderStatements)); 442 } else { 443 newMembers.unshift(addUpdateParamsFunc(updateParamsStatements, parentComponentName)); 444 } 445} 446 447export function isRegularProperty(decorators: readonly ts.Decorator[]): boolean { 448 if (decorators && decorators.length) { 449 if (decorators.length === 1 && decorators[0].getText() === COMPONENT_REQUIRE_DECORATOR) { 450 return true; 451 } 452 return false; 453 } 454 return true; 455} 456 457function addPropertyMember(item: ts.ClassElement, newMembers: ts.ClassElement[], 458 program: ts.Program, parentComponentName: string, log: LogInfo[]): void { 459 const propertyItem: ts.PropertyDeclaration = item as ts.PropertyDeclaration; 460 let decoratorName: string; 461 let updatePropertyItem: ts.PropertyDeclaration; 462 const type: ts.TypeNode = propertyItem.type; 463 const decorators: readonly ts.Decorator[] = ts.getAllDecorators(propertyItem); 464 if (isRegularProperty(decorators)) { 465 updatePropertyItem = createPropertyDeclaration(propertyItem, type, true); 466 newMembers.push(updatePropertyItem); 467 } else { 468 for (let i = 0; i < decorators.length; i++) { 469 let newType: ts.TypeNode; 470 decoratorName = decorators[i].getText().replace(/\(.*\)$/, '').trim(); 471 let isLocalStorage: boolean = false; 472 if (!partialUpdateConfig.partialUpdateMode) { 473 newType = createTypeReference(decoratorName, type, log, program); 474 } else { 475 newType = createTypeReferencePU(decoratorName, type, log, program); 476 } 477 if ( 478 decoratorName === COMPONENT_LOCAL_STORAGE_LINK_DECORATOR || 479 decoratorName === COMPONENT_LOCAL_STORAGE_PROP_DECORATOR 480 ) { 481 isLocalStorage = true; 482 } 483 const newUpdatePropertyItem = createPropertyDeclaration( 484 propertyItem, newType, false, isLocalStorage, parentComponentName); 485 if (!updatePropertyItem) { 486 updatePropertyItem = newUpdatePropertyItem; 487 } else if (INNER_COMPONENT_MEMBER_DECORATORS.has(decoratorName) && 488 ![COMPONENT_WATCH_DECORATOR, COMPONENT_REQUIRE_DECORATOR].includes(decoratorName)) { 489 updatePropertyItem = newUpdatePropertyItem; 490 } 491 } 492 if (updatePropertyItem) { 493 newMembers.push(updatePropertyItem); 494 } 495 } 496} 497 498function createPropertyDeclaration(propertyItem: ts.PropertyDeclaration, newType: ts.TypeNode | undefined, 499 normalVar: boolean, isLocalStorage: boolean = false, parentComponentName: string = null): ts.PropertyDeclaration { 500 if (typeof newType === undefined) { 501 return undefined; 502 } 503 let prefix: string = ''; 504 if (!normalVar) { 505 prefix = '__'; 506 } 507 const privateM: ts.ModifierToken<ts.SyntaxKind.PrivateKeyword> = 508 ts.factory.createModifier(ts.SyntaxKind.PrivateKeyword); 509 const modifiers: readonly ts.Modifier[] = 510 ts.canHaveModifiers(propertyItem) ? ts.getModifiers(propertyItem) : undefined; 511 return ts.factory.updatePropertyDeclaration(propertyItem, 512 ts.concatenateDecoratorsAndModifiers(undefined, modifiers || [privateM]), prefix + propertyItem.name.getText(), 513 propertyItem.questionToken, newType, isLocalStorage ? 514 createLocalStroageCallExpression(propertyItem, propertyItem.name.getText(), 515 parentComponentName) : undefined); 516} 517 518function createLocalStroageCallExpression(node: ts.PropertyDeclaration, name: string, 519 parentComponentName: string): ts.CallExpression { 520 const decorators: readonly ts.Decorator[] = ts.getAllDecorators(node); 521 if (isSingleKey(node)) { 522 const localStorageLink: Set<string> = localStorageLinkCollection.get(parentComponentName).get(name); 523 const localStorageProp: Set<string> = localStoragePropCollection.get(parentComponentName).get(name); 524 let localFuncName: string; 525 const index: number = findDecoratorIndex(decorators, 526 [COMPONENT_LOCAL_STORAGE_LINK_DECORATOR, COMPONENT_LOCAL_STORAGE_PROP_DECORATOR]); 527 const localValue: ts.Expression[] = [ 528 decorators[index].expression.arguments[0], 529 node.initializer ? node.initializer : ts.factory.createNumericLiteral(COMPONENT_CONSTRUCTOR_UNDEFINED), 530 ts.factory.createThis(), 531 ts.factory.createStringLiteral(name || COMPONENT_CONSTRUCTOR_UNDEFINED) 532 ]; 533 if (!partialUpdateConfig.partialUpdateMode) { 534 localFuncName = localStorageLink && !localStorageProp ? COMPONENT_SET_AND_LINK : 535 COMPONENT_SET_AND_PROP; 536 } else { 537 localFuncName = localStorageLink && !localStorageProp ? CREATE_LOCAL_STORAGE_LINK : 538 CREATE_LOCAL_STORAGE_PROP; 539 localValue.splice(-2, 1); 540 } 541 return ts.factory.createCallExpression( 542 ts.factory.createPropertyAccessExpression( 543 !partialUpdateConfig.partialUpdateMode ? 544 ts.factory.createPropertyAccessExpression( 545 ts.factory.createThis(), 546 ts.factory.createIdentifier(`${COMPONENT_CONSTRUCTOR_LOCALSTORAGE}_`) 547 ) : ts.factory.createThis(), 548 ts.factory.createIdentifier(localFuncName) 549 ), 550 [node.type], 551 localValue 552 ); 553 } 554 return undefined; 555} 556export interface builderConditionType { 557 isBuilder: boolean, 558 isLocalBuilder: boolean 559} 560export function processComponentMethod(node: ts.MethodDeclaration, context: ts.TransformationContext, 561 log: LogInfo[], buildCount: BuildCount): ts.MethodDeclaration { 562 let updateItem: ts.MethodDeclaration = node; 563 const name: string = node.name.getText(); 564 const customBuilder: ts.Decorator[] = []; 565 const builderCondition: builderConditionType = { 566 isBuilder: false, 567 isLocalBuilder: false 568 }; 569 if (builderParamObjectCollection.get(componentCollection.currentClassName)) { 570 storedFileInfo.builderLikeCollection = 571 new Set([...builderParamObjectCollection.get(componentCollection.currentClassName), ...CUSTOM_BUILDER_METHOD]); 572 } else { 573 storedFileInfo.builderLikeCollection = CUSTOM_BUILDER_METHOD; 574 } 575 if (name === COMPONENT_BUILD_FUNCTION) { 576 storedFileInfo.processBuilder = false; 577 storedFileInfo.processGlobalBuilder = false; 578 buildCount.count = buildCount.count + 1; 579 if (node.parameters.length) { 580 log.push({ 581 type: LogType.ERROR, 582 message: `The 'build' method can not have arguments.`, 583 pos: node.getStart(), 584 code: '10905106' 585 }); 586 } 587 const buildNode: ts.MethodDeclaration = processComponentBuild(node, log); 588 updateItem = processBuildMember(buildNode, context, log); 589 } else if (node.body && ts.isBlock(node.body)) { 590 if (name === COMPONENT_TRANSITION_FUNCTION) { 591 updateItem = ts.factory.updateMethodDeclaration(node, ts.getModifiers(node), 592 node.asteriskToken, node.name, node.questionToken, node.typeParameters, node.parameters, 593 node.type, processComponentBlock(node.body, false, log, true)); 594 } else if (isBuilderOrLocalBuilder(node, builderCondition, customBuilder)) { 595 storedFileInfo.processBuilder = true; 596 storedFileInfo.processGlobalBuilder = false; 597 if (builderCondition.isLocalBuilder) { 598 storedFileInfo.processLocalBuilder = true; 599 } 600 CUSTOM_BUILDER_METHOD.add(name); 601 INNER_CUSTOM_BUILDER_METHOD.add(name); 602 builderTypeParameter.params = getPossibleBuilderTypeParameter(node.parameters); 603 const parameters: ts.NodeArray<ts.ParameterDeclaration> = ts.factory.createNodeArray(Array.from(node.parameters)); 604 if (!builderCondition.isLocalBuilder) { 605 parameters.push(createParentParameter()); 606 } 607 if (projectConfig.optLazyForEach) { 608 parameters.push(initializeMYIDS()); 609 } 610 const modifiers = ts.canHaveModifiers(node) ? ts.getModifiers(node) : undefined; 611 const componentBlock: ts.Block = processComponentBlock(node.body, false, log, false, true); 612 if (partialUpdateConfig.partialUpdateMode && builderCondition.isLocalBuilder && 613 node.body.statements.length) { 614 componentBlock.statements.unshift(globalBuilderParamAssignment()); 615 } 616 let builderNode: ts.MethodDeclaration | ts.PropertyDeclaration = ts.factory.updateMethodDeclaration(node, 617 ts.concatenateDecoratorsAndModifiers(removeDecorator(customBuilder, 'Builder'), modifiers), 618 node.asteriskToken, node.name, node.questionToken, node.typeParameters, 619 parameters, node.type, componentBlock); 620 builderTypeParameter.params = []; 621 updateItem = processBuildMember(builderNode, context, log, true); 622 if (builderCondition.isLocalBuilder) { 623 checkDecoratorMethod(node, modifiers, log); 624 updateItem = localBuilderNode(node, updateItem.body); 625 } 626 storedFileInfo.processBuilder = false; 627 storedFileInfo.processLocalBuilder = false; 628 } else if (hasDecorator(node, COMPONENT_STYLES_DECORATOR)) { 629 if (node.parameters && node.parameters.length === 0) { 630 if (ts.isBlock(node.body) && node.body.statements && node.body.statements.length) { 631 INNER_STYLE_FUNCTION.set(name, node.body); 632 STYLES_ATTRIBUTE.add(name); 633 BUILDIN_STYLE_NAMES.add(name); 634 decoratorParamSet.add(STYLES); 635 } 636 } else { 637 log.push({ 638 type: LogType.ERROR, 639 message: `'@Styles' decorated functions and methods cannot have arguments.`, 640 pos: node.getStart(), 641 code: '10905105' 642 }); 643 } 644 return undefined; 645 } 646 } 647 return updateItem; 648} 649 650function checkDecoratorMethod(node: ts.MethodDeclaration, modifiers: readonly ts.Modifier[], log: LogInfo[]): void { 651 if (modifiers && modifiers.length) { 652 for (let i = 0; i < modifiers.length; i++) { 653 if (modifiers[i].kind && modifiers[i].kind === ts.SyntaxKind.StaticKeyword) { 654 log.push({ 655 type: LogType.ERROR, 656 message: `Static methods in custom components cannot be decorated by '@LocalBuilder'.`, 657 pos: node.getStart(), 658 code: '10905104' 659 }); 660 return; 661 } 662 } 663 } 664} 665 666export function isBuilderOrLocalBuilder(node: ts.MethodDeclaration | ts.FunctionDeclaration, builderCondition: builderConditionType, 667 customBuilder: ts.Decorator[] = undefined): boolean { 668 const decorators: readonly ts.Decorator[] = ts.getAllDecorators(node); 669 if (decorators && decorators.length) { 670 for (let i = 0; i < decorators.length; i++) { 671 const originalDecortor: string = decorators[i].getText().replace(/\(.*\)$/, '').replace(/\s*/g, '').trim(); 672 if ([COMPONENT_LOCAL_BUILDER_DECORATOR, COMPONENT_BUILDER_DECORATOR].includes(originalDecortor)) { 673 if (originalDecortor === COMPONENT_BUILDER_DECORATOR) { 674 builderCondition.isBuilder = true; 675 if (customBuilder) { 676 customBuilder.push(...decorators.slice(i + 1), ...decorators.slice(0, i)); 677 } 678 } else { 679 builderCondition.isLocalBuilder = true; 680 } 681 return true; 682 } 683 } 684 } 685 return false; 686} 687 688function localBuilderNode(node: ts.MethodDeclaration, componentBlock: ts.Block): ts.PropertyDeclaration { 689 return ts.factory.createPropertyDeclaration( 690 undefined, node.name, undefined, undefined, 691 ts.factory.createArrowFunction( 692 undefined, undefined, node.parameters ? node.parameters : [], undefined, 693 ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), 694 componentBlock 695 ) 696 ); 697} 698 699export function createParentParameter(): ts.ParameterDeclaration { 700 return ts.factory.createParameterDeclaration(undefined, undefined, 701 ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARENT), undefined, undefined, 702 ts.factory.createIdentifier(NULL)); 703} 704 705export function processBuildMember(node: ts.MethodDeclaration | ts.FunctionDeclaration, context: ts.TransformationContext, 706 log: LogInfo[], isBuilder = false): ts.MethodDeclaration | ts.FunctionDeclaration { 707 return ts.visitNode(node, visitBuild); 708 function visitBuild(node: ts.Node): ts.Node { 709 if (isGeometryView(node)) { 710 node = processGeometryView(node as ts.ExpressionStatement, log); 711 } 712 if (isProperty(node)) { 713 node = createReference(node as ts.PropertyAssignment, log, isBuilder); 714 } 715 if (isNeedGetRawObject(node)) { 716 return ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression( 717 ts.factory.createIdentifier(FOREACH_OBSERVED_OBJECT), 718 ts.factory.createIdentifier(FOREACH_GET_RAW_OBJECT)), undefined, [node]); 719 } 720 return ts.visitEachChild(node, visitBuild, context); 721 } 722} 723 724function checkStateName(node: ts.PropertyAccessExpression): string { 725 if (node.expression && !node.expression.expression && node.name && ts.isIdentifier(node.name)) { 726 return node.name.escapedText.toString(); 727 } 728 return null; 729} 730 731// EnableV2Compatibility MakeV1Observed Do not generate ObservedObject GetRawObject. 732function isNeedGetRawObject(node: ts.Node): boolean { 733 return !isInComponentV2Context() && !isEnableV2CompatibilityOrMakeV1Observed(node) && ts.isPropertyAccessExpression(node) && 734 ts.isIdentifier(node.name) && stateObjectCollection.has(checkStateName(node)) && node.parent && ts.isCallExpression(node.parent) && 735 ts.isPropertyAccessExpression(node.parent.expression) && node !== node.parent.expression && 736 node.parent.expression.name.escapedText.toString() !== FOREACH_GET_RAW_OBJECT; 737} 738 739function isEnableV2CompatibilityOrMakeV1Observed(node: ts.Node): boolean { 740 if (node.parent && ts.isCallExpression(node.parent) && ts.isPropertyAccessExpression(node.parent.expression) && 741 ts.isIdentifier(node.parent.expression.name) && 742 ['enableV2Compatibility', 'makeV1Observed'].includes(node.parent.expression.name.escapedText.toString())) { 743 return true; 744 } else { 745 return false; 746 } 747} 748 749function isInComponentV2Context(): boolean { 750 if (componentCollection.currentClassName) { 751 const parentStructInfo: StructInfo = 752 processStructComponentV2.getOrCreateStructInfo(componentCollection.currentClassName); 753 return parentStructInfo.isComponentV2; 754 } 755 return false; 756} 757 758function isGeometryView(node: ts.Node): boolean { 759 if (ts.isExpressionStatement(node) && ts.isCallExpression(node.expression)) { 760 const call: ts.CallExpression = node.expression; 761 const exp: ts.Expression = call.expression; 762 const args: ts.NodeArray<ts.Expression> = call.arguments; 763 if (ts.isPropertyAccessExpression(exp) && ts.isIdentifier(exp.expression) && 764 exp.expression.escapedText.toString() === GEOMETRY_VIEW && ts.isIdentifier(exp.name) && 765 exp.name.escapedText.toString() === COMPONENT_CREATE_FUNCTION && args && args.length === 1 && 766 (ts.isArrowFunction(args[0]) || ts.isFunctionExpression(args[0]))) { 767 return true; 768 } 769 } 770 return false; 771} 772 773function processGeometryView(node: ts.ExpressionStatement, 774 log: LogInfo[]): ts.ExpressionStatement { 775 const exp: ts.CallExpression = node.expression as ts.CallExpression; 776 const arg: ts.ArrowFunction | ts.FunctionExpression = 777 exp.arguments[0] as ts.ArrowFunction | ts.FunctionExpression; 778 return ts.factory.updateExpressionStatement(node, ts.factory.updateCallExpression(exp, 779 exp.expression, undefined, [ts.factory.createArrowFunction(undefined, undefined, arg.parameters, 780 undefined, ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), 781 getGeometryReaderFunctionBlock(arg, log))])); 782} 783 784function getGeometryReaderFunctionBlock(node: ts.ArrowFunction | ts.FunctionExpression, 785 log: LogInfo[]): ts.Block { 786 let blockNode: ts.Block; 787 if (ts.isBlock(node.body)) { 788 blockNode = node.body; 789 } else if (ts.isArrowFunction(node) && ts.isCallExpression(node.body)) { 790 blockNode = ts.factory.createBlock([ts.factory.createExpressionStatement(node.body)]); 791 } 792 return processComponentBlock(blockNode, false, log); 793} 794 795export function updateHeritageClauses(node: ts.StructDeclaration, log: LogInfo[], 796 isComponentV2: boolean = false): ts.NodeArray<ts.HeritageClause> { 797 if (node.heritageClauses && !checkHeritageClauses(node)) { 798 log.push({ 799 type: LogType.ERROR, 800 message: 'Structs are not allowed to inherit from classes or implement interfaces.', 801 pos: node.heritageClauses.pos, 802 code: '10905212' 803 }); 804 } 805 const result: ts.HeritageClause[] = []; 806 const heritageClause: ts.HeritageClause = createHeritageClause(isComponentV2); 807 result.push(heritageClause); 808 return ts.factory.createNodeArray(result); 809} 810 811function checkHeritageClauses(node: ts.StructDeclaration): boolean { 812 if (node.heritageClauses.length === 1 && node.heritageClauses[0].types && 813 node.heritageClauses[0].types.length === 1) { 814 const expressionNode: ts.ExpressionWithTypeArguments = node.heritageClauses[0].types[0]; 815 if (expressionNode.expression && ts.isIdentifier(expressionNode.expression) && 816 expressionNode.expression.escapedText.toString() === CUSTOM_COMPONENT) { 817 return true; 818 } 819 } 820 return false; 821} 822 823export function isProperty(node: ts.Node): Boolean { 824 if (judgmentParentType(node)) { 825 if (node.parent.parent.expression && ts.isIdentifier(node.parent.parent.expression) && 826 !BUILDIN_STYLE_NAMES.has(node.parent.parent.expression.escapedText.toString()) && 827 componentCollection.customComponents.has( 828 node.parent.parent.expression.escapedText.toString())) { 829 return true; 830 } else if (ts.isPropertyAccessExpression(node.parent.parent.expression) && 831 ts.isIdentifier(node.parent.parent.expression.expression) && 832 componentCollection.customComponents.has( 833 node.parent.parent.expression.name.escapedText.toString())) { 834 return true; 835 } 836 } 837 return false; 838} 839 840function judgmentParentType(node: ts.Node): boolean { 841 return ts.isPropertyAssignment(node) && node.name && ts.isIdentifier(node.name) && 842 node.parent && ts.isObjectLiteralExpression(node.parent) && node.parent.parent && 843 (ts.isCallExpression(node.parent.parent) || ts.isEtsComponentExpression(node.parent.parent)); 844} 845 846export function createReference(node: ts.PropertyAssignment, log: LogInfo[], isBuilder = false, 847 isParamsLambda: boolean = false, isRecycleComponent: boolean = false): ts.PropertyAssignment { 848 const linkParentComponent: string[] = getParentNode(node, linkCollection).slice(1); 849 const propertyName: ts.Identifier = node.name as ts.Identifier; 850 let initText: string; 851 const LINK_REG: RegExp = /^\$/g; 852 if (isRecycleComponent && ts.isShorthandPropertyAssignment(node)) { 853 return node; 854 } 855 const initExpression: ts.Expression = node.initializer; 856 let is$$: boolean = false; 857 if (ts.isIdentifier(initExpression) && 858 initExpression.escapedText.toString().match(LINK_REG)) { 859 initText = initExpression.escapedText.toString().replace(LINK_REG, ''); 860 } else if (ts.isPropertyAccessExpression(initExpression) && initExpression.expression && 861 initExpression.expression.kind === ts.SyntaxKind.ThisKeyword && 862 ts.isIdentifier(initExpression.name) && initExpression.name.escapedText.toString().match(LINK_REG)) { 863 initText = initExpression.name.escapedText.toString().replace(LINK_REG, ''); 864 } else if (isBuilder && ts.isPropertyAccessExpression(initExpression) && initExpression.expression && 865 ts.isIdentifier(initExpression.expression) && initExpression.expression.escapedText.toString() === $$ && 866 ts.isIdentifier(initExpression.name) && linkParentComponent.includes(propertyName.escapedText.toString())) { 867 is$$ = true; 868 initText = initExpression.name.escapedText.toString(); 869 } else if (isMatchInitExpression(initExpression) && 870 linkParentComponent.includes(propertyName.escapedText.toString())) { 871 initText = initExpression.name.escapedText.toString().replace(LINK_REG, ''); 872 } 873 if (initText) { 874 node = addDoubleUnderline(node, propertyName, initText, is$$, isParamsLambda, isRecycleComponent); 875 } 876 return node; 877} 878 879function isMatchInitExpression(initExpression: ts.Expression): boolean { 880 return ts.isPropertyAccessExpression(initExpression) && 881 initExpression.expression && 882 initExpression.expression.kind === ts.SyntaxKind.ThisKeyword && 883 ts.isIdentifier(initExpression.name); 884} 885 886function addDoubleUnderline(node: ts.PropertyAssignment, propertyName: ts.Identifier, 887 initText: string, is$$ = false, isParamsLambda: boolean, isRecycleComponent: boolean): ts.PropertyAssignment { 888 return ts.factory.updatePropertyAssignment(node, propertyName, 889 ts.factory.createPropertyAccessExpression( 890 is$$ && partialUpdateConfig.partialUpdateMode ? ts.factory.createIdentifier($$) : ts.factory.createThis(), 891 isParamsLambda || isRecycleComponent ? ts.factory.createIdentifier(initText) : ts.factory.createIdentifier(`__${initText}`))); 892} 893 894function getParentNode(node: ts.PropertyAssignment, collection: Map<string, Set<string>>): string[] { 895 const grandparentNode: ts.NewExpression = node.parent.parent as ts.NewExpression; 896 const grandparentExpression: ts.Identifier | ts.PropertyAccessExpression = 897 grandparentNode.expression as ts.Identifier | ts.PropertyAccessExpression; 898 let parentComponent: Set<string> = new Set(); 899 let grandparentName: string; 900 if (ts.isIdentifier(grandparentExpression)) { 901 grandparentName = grandparentExpression.escapedText.toString(); 902 parentComponent = collection.get(grandparentName); 903 } else if (ts.isPropertyAccessExpression(grandparentExpression)) { 904 if (storedFileInfo.isAsPageImport) { 905 grandparentName = grandparentExpression.getText(); 906 } else { 907 grandparentName = grandparentExpression.name.escapedText.toString(); 908 } 909 parentComponent = collection.get(grandparentName); 910 } else { 911 // ignore 912 } 913 if (!parentComponent) { 914 parentComponent = new Set(); 915 } 916 return [grandparentName, ...parentComponent]; 917} 918 919function addUpdateParamsFunc(statements: ts.Statement[], parentComponentName: ts.Identifier): 920 ts.MethodDeclaration { 921 return createParamsInitBlock(COMPONENT_CONSTRUCTOR_UPDATE_PARAMS, statements, parentComponentName); 922} 923 924function addInitialParamsFunc(statements: ts.Statement[], parentComponentName: ts.Identifier): ts.MethodDeclaration { 925 return createParamsInitBlock(COMPONENT_CONSTRUCTOR_INITIAL_PARAMS, statements, parentComponentName); 926} 927 928function addUpdateStateVarsFunc(statements: ts.Statement[], parentComponentName: ts.Identifier): ts.MethodDeclaration { 929 return createParamsInitBlock(COMPONENT_UPDATE_STATE_VARS, statements, parentComponentName); 930} 931 932function addPurgeVariableDepFunc(statements: ts.Statement[]): ts.MethodDeclaration { 933 return ts.factory.createMethodDeclaration( 934 undefined, undefined, 935 ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PURGE_VARIABLE_DEP), 936 undefined, undefined, [ts.factory.createParameterDeclaration(undefined, undefined, 937 ts.factory.createIdentifier(RMELMTID), undefined, undefined, undefined)], undefined, 938 ts.factory.createBlock(statements, true)); 939} 940 941function addDeleteParamsFunc(statements: ts.PropertyDeclaration[], 942 updateRecyle: boolean = false): ts.MethodDeclaration { 943 const deleteStatements: ts.ExpressionStatement[] = []; 944 const updateStatements: ts.ExpressionStatement[] = []; 945 statements.forEach((statement: ts.PropertyDeclaration) => { 946 const name: ts.Identifier = statement.name as ts.Identifier; 947 let paramsStatement: ts.ExpressionStatement; 948 const decorators: readonly ts.Decorator[] = ts.getAllDecorators(statement); 949 const isRegular: boolean = isRegularProperty(decorators); 950 if (!partialUpdateConfig.partialUpdateMode || !isRegular) { 951 paramsStatement = createParamsWithUnderlineStatement(name); 952 } 953 if (partialUpdateConfig.partialUpdateMode && !isRegular) { 954 updateStatements.push(createElmtIdWithUnderlineStatement(name)); 955 } 956 deleteStatements.push(paramsStatement); 957 }); 958 if (partialUpdateConfig.partialUpdateMode && updateRecyle) { 959 return createRecycleElmt(updateStatements); 960 } 961 const defaultStatement: ts.ExpressionStatement = 962 ts.factory.createExpressionStatement(ts.factory.createCallExpression( 963 ts.factory.createPropertyAccessExpression( 964 ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression( 965 ts.factory.createIdentifier(CREATE_CONSTRUCTOR_SUBSCRIBER_MANAGER), 966 ts.factory.createIdentifier(CREATE_CONSTRUCTOR_GET_FUNCTION)), undefined, []), 967 ts.factory.createIdentifier(CREATE_CONSTRUCTOR_DELETE_FUNCTION)), 968 undefined, [ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression( 969 ts.factory.createThis(), ts.factory.createIdentifier( 970 !partialUpdateConfig.partialUpdateMode ? 971 ABOUT_TO_BE_DELETE_FUNCTION_ID : ABOUT_TO_BE_DELETE_FUNCTION_ID__)), 972 undefined, [])])); 973 deleteStatements.push(defaultStatement); 974 if (partialUpdateConfig.partialUpdateMode) { 975 const aboutToBeDeletedInternalStatement: ts.ExpressionStatement = createDeletedInternalStatement(); 976 deleteStatements.push(aboutToBeDeletedInternalStatement); 977 } 978 const deleteParamsMethod: ts.MethodDeclaration = 979 createParamsInitBlock(COMPONENT_CONSTRUCTOR_DELETE_PARAMS, deleteStatements); 980 return deleteParamsMethod; 981} 982 983function createRecycleElmt(statements: ts.Statement[]): ts.MethodDeclaration { 984 return ts.factory.createMethodDeclaration(undefined, undefined, 985 ts.factory.createIdentifier(UPDATE_RECYCLE_ELMT_ID), undefined, undefined, [ 986 ts.factory.createParameterDeclaration(undefined, undefined, 987 ts.factory.createIdentifier(OLD_ELMT_ID)), 988 ts.factory.createParameterDeclaration(undefined, undefined, 989 ts.factory.createIdentifier(NEW_ELMT_ID)) 990 ], undefined, ts.factory.createBlock(statements, true)); 991} 992 993function createParamsWithUnderlineStatement(name: ts.Identifier): ts.ExpressionStatement { 994 return ts.factory.createExpressionStatement( 995 ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression( 996 ts.factory.createPropertyAccessExpression(ts.factory.createThis(), 997 ts.factory.createIdentifier(`__${name.escapedText.toString()}`)), 998 ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_DELETE_PARAMS)), undefined, [])); 999} 1000 1001function createElmtIdWithUnderlineStatement(name: ts.Identifier): ts.ExpressionStatement { 1002 return ts.factory.createExpressionStatement( 1003 ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression( 1004 ts.factory.createPropertyAccessExpression(ts.factory.createThis(), 1005 ts.factory.createIdentifier(`__${name.escapedText.toString()}`)), 1006 ts.factory.createIdentifier(COMPONENT_UPDATE_ELMT_ID)), undefined, [ 1007 ts.factory.createIdentifier(OLD_ELMT_ID), ts.factory.createIdentifier(NEW_ELMT_ID) 1008 ])); 1009} 1010 1011function createDeletedInternalStatement(): ts.ExpressionStatement { 1012 return ts.factory.createExpressionStatement(ts.factory.createCallExpression( 1013 ts.factory.createPropertyAccessExpression(ts.factory.createThis(), 1014 ts.factory.createIdentifier(ABOUTTOBEDELETEDINTERNAL)), undefined, [])); 1015} 1016 1017export function addRerenderFunc(statements: ts.Statement[]): ts.MethodDeclaration { 1018 const updateDirtyElementStatement: ts.Statement = ts.factory.createExpressionStatement( 1019 ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression( 1020 ts.factory.createThis(), ts.factory.createIdentifier(UPDATEDIRTYELEMENTS)), undefined, [])); 1021 statements.push(updateDirtyElementStatement); 1022 if (storedFileInfo.hasLocalBuilderInFile) { 1023 statements.unshift(contextStackPushOrPop(ts.factory.createIdentifier(PUSH), [ts.factory.createThis()])); 1024 statements.push(contextStackPushOrPop(ts.factory.createIdentifier(COMPONENT_POP_FUNCTION), [])); 1025 } 1026 return ts.factory.createMethodDeclaration(undefined, undefined, 1027 ts.factory.createIdentifier(COMPONENT_RERENDER_FUNCTION), undefined, undefined, [], undefined, 1028 ts.factory.createBlock(statements, true)); 1029} 1030 1031function createParamsInitBlock(express: string, statements: ts.Statement[], 1032 parentComponentName?: ts.Identifier): ts.MethodDeclaration { 1033 const methodDeclaration: ts.MethodDeclaration = ts.factory.createMethodDeclaration( 1034 undefined, undefined, ts.factory.createIdentifier(express), undefined, undefined, 1035 [ts.factory.createParameterDeclaration(undefined, undefined, 1036 express === COMPONENT_CONSTRUCTOR_DELETE_PARAMS ? undefined : 1037 ts.factory.createIdentifier(CREATE_CONSTRUCTOR_PARAMS), undefined, 1038 express === COMPONENT_CONSTRUCTOR_DELETE_PARAMS ? undefined : 1039 ts.factory.createTypeReferenceNode( 1040 ts.factory.createIdentifier(parentComponentName.getText() + INTERFACE_NAME_SUFFIX), undefined), 1041 undefined)], undefined, ts.factory.createBlock(statements, true)); 1042 return methodDeclaration; 1043} 1044 1045export function validateBuildMethodCount(buildCount: BuildCount, parentComponentName: ts.Identifier, 1046 log: LogInfo[]): void { 1047 if (buildCount.count !== 1) { 1048 log.push({ 1049 type: LogType.ERROR, 1050 message: `The struct '${parentComponentName.getText()}' must have at least and at most one 'build' method.`, 1051 pos: parentComponentName.getStart(), 1052 code: '10905103', 1053 solutions: [`A structurally modified page must have at least one and no more than one 'build' method.`] 1054 }); 1055 } 1056} 1057 1058function validateHasControllerAndControllerCount(componentName: ts.Identifier, checkController: ControllerType, 1059 log: LogInfo[]): void { 1060 if (!checkController.hasController) { 1061 log.push({ 1062 type: LogType.ERROR, 1063 message: `The '@CustomDialog' decorated custom component must contain a property of the CustomDialogController type.`, 1064 pos: componentName.pos, 1065 code: '10905211' 1066 }); 1067 } 1068 if (checkController.unassignedControllerSet.size >= 2) { 1069 log.push({ 1070 type: LogType.WARN, 1071 message: 'A @CustomDialog component can only have one uninitialized CustomDialogController.', 1072 pos: componentName.pos 1073 }); 1074 } 1075} 1076 1077function createHeritageClause(isComponentV2: boolean = false): ts.HeritageClause { 1078 if (partialUpdateConfig.partialUpdateMode) { 1079 return ts.factory.createHeritageClause( 1080 ts.SyntaxKind.ExtendsKeyword, 1081 [ts.factory.createExpressionWithTypeArguments( 1082 ts.factory.createIdentifier(isComponentV2 ? constantDefine.STRUCT_PARENT : BASE_COMPONENT_NAME_PU), 1083 [])] 1084 ); 1085 } 1086 return ts.factory.createHeritageClause( 1087 ts.SyntaxKind.ExtendsKeyword, 1088 [ts.factory.createExpressionWithTypeArguments(ts.factory.createIdentifier(BASE_COMPONENT_NAME), [])] 1089 ); 1090} 1091 1092function createTypeReference(decoratorName: string, type: ts.TypeNode, log: LogInfo[], 1093 program: ts.Program): ts.TypeNode { 1094 let newType: ts.TypeNode; 1095 switch (decoratorName) { 1096 case COMPONENT_STATE_DECORATOR: 1097 case COMPONENT_PROVIDE_DECORATOR: 1098 newType = ts.factory.createTypeReferenceNode( 1099 isSimpleType(type, program, log) ? 1100 OBSERVED_PROPERTY_SIMPLE : 1101 OBSERVED_PROPERTY_OBJECT, 1102 [type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)] 1103 ); 1104 break; 1105 case COMPONENT_LINK_DECORATOR: 1106 case COMPONENT_CONSUME_DECORATOR: 1107 newType = ts.factory.createTypeReferenceNode( 1108 isSimpleType(type, program, log) ? 1109 SYNCHED_PROPERTY_SIMPLE_TWO_WAY : 1110 SYNCHED_PROPERTY_SIMPLE_ONE_WAY, 1111 [type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)] 1112 ); 1113 break; 1114 case COMPONENT_PROP_DECORATOR: 1115 newType = ts.factory.createTypeReferenceNode( 1116 SYNCHED_PROPERTY_SIMPLE_ONE_WAY, 1117 [type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)] 1118 ); 1119 break; 1120 case COMPONENT_OBJECT_LINK_DECORATOR: 1121 newType = ts.factory.createTypeReferenceNode( 1122 SYNCHED_PROPERTY_NESED_OBJECT, 1123 [type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)] 1124 ); 1125 break; 1126 case COMPONENT_STORAGE_PROP_DECORATOR: 1127 case COMPONENT_STORAGE_LINK_DECORATOR: 1128 newType = ts.factory.createTypeReferenceNode(OBSERVED_PROPERTY_ABSTRACT, [ 1129 type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword) 1130 ]); 1131 break; 1132 case COMPONENT_LOCAL_STORAGE_LINK_DECORATOR: 1133 case COMPONENT_LOCAL_STORAGE_PROP_DECORATOR: 1134 newType = ts.factory.createTypeReferenceNode(OBSERVED_PROPERTY_ABSTRACT, [ 1135 type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword) 1136 ]); 1137 break; 1138 } 1139 return newType; 1140} 1141 1142function createTypeReferencePU(decoratorName: string, type: ts.TypeNode, log: LogInfo[], 1143 program: ts.Program): ts.TypeNode { 1144 let newType: ts.TypeNode; 1145 switch (decoratorName) { 1146 case COMPONENT_STATE_DECORATOR: 1147 case COMPONENT_PROVIDE_DECORATOR: 1148 newType = ts.factory.createTypeReferenceNode( 1149 isSimpleType(type, program, log) ? 1150 OBSERVED_PROPERTY_SIMPLE_PU : 1151 OBSERVED_PROPERTY_OBJECT_PU, 1152 [type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)] 1153 ); 1154 break; 1155 case COMPONENT_LINK_DECORATOR: 1156 newType = ts.factory.createTypeReferenceNode( 1157 isSimpleType(type, program, log) ? 1158 SYNCHED_PROPERTY_SIMPLE_TWO_WAY_PU : 1159 SYNCHED_PROPERTY_SIMPLE_ONE_WAY_PU, 1160 [type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)] 1161 ); 1162 break; 1163 case COMPONENT_PROP_DECORATOR: 1164 newType = ts.factory.createTypeReferenceNode( 1165 SYNCHED_PROPERTY_SIMPLE_ONE_WAY_PU, 1166 [type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)] 1167 ); 1168 break; 1169 case COMPONENT_OBJECT_LINK_DECORATOR: 1170 newType = ts.factory.createTypeReferenceNode( 1171 SYNCHED_PROPERTY_NESED_OBJECT_PU, 1172 [type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)] 1173 ); 1174 break; 1175 case COMPONENT_CONSUME_DECORATOR: 1176 case COMPONENT_STORAGE_PROP_DECORATOR: 1177 case COMPONENT_STORAGE_LINK_DECORATOR: 1178 newType = ts.factory.createTypeReferenceNode(OBSERVED_PROPERTY_ABSTRACT_PU, [ 1179 type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword) 1180 ]); 1181 break; 1182 case COMPONENT_LOCAL_STORAGE_LINK_DECORATOR: 1183 case COMPONENT_LOCAL_STORAGE_PROP_DECORATOR: 1184 newType = ts.factory.createTypeReferenceNode(OBSERVED_PROPERTY_ABSTRACT_PU, [ 1185 type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword) 1186 ]); 1187 break; 1188 } 1189 return newType; 1190} 1191 1192export function checkFinalizeConstruction(): ts.Statement { 1193 return ts.factory.createIfStatement( 1194 ts.factory.createPrefixUnaryExpression(ts.SyntaxKind.ExclamationToken, 1195 ts.factory.createParenthesizedExpression(ts.factory.createBinaryExpression( 1196 ts.factory.createStringLiteral(FINALIZE_CONSTRUCTION), 1197 ts.factory.createToken(ts.SyntaxKind.InKeyword), ts.factory.createPropertyAccessExpression( 1198 ts.factory.createIdentifier(BASE_COMPONENT_NAME_PU), ts.factory.createIdentifier(PROTOTYPE)))) 1199 ), 1200 ts.factory.createBlock( 1201 [ 1202 ts.factory.createExpressionStatement(ts.factory.createCallExpression( 1203 ts.factory.createPropertyAccessExpression( 1204 ts.factory.createIdentifier(REFLECT), ts.factory.createIdentifier(CREATE_SET_METHOD) 1205 ), undefined, 1206 [ 1207 ts.factory.createPropertyAccessExpression( 1208 ts.factory.createIdentifier(BASE_COMPONENT_NAME_PU), ts.factory.createIdentifier(PROTOTYPE) 1209 ), 1210 ts.factory.createStringLiteral(FINALIZE_CONSTRUCTION), 1211 ts.factory.createArrowFunction(undefined, undefined, [], undefined, 1212 ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), 1213 ts.factory.createBlock([], false) 1214 ) 1215 ] 1216 )) 1217 ], true), undefined); 1218} 1219 1220export function checkContextStack(): ts.Statement { 1221 return ts.factory.createIfStatement( 1222 ts.factory.createBinaryExpression( 1223 ts.factory.createPropertyAccessExpression( 1224 ts.factory.createIdentifier(PUV2_VIEW_BASE), 1225 ts.factory.createIdentifier(CONTEXT_STACK) 1226 ), 1227 ts.factory.createToken(ts.SyntaxKind.EqualsEqualsEqualsToken), 1228 ts.factory.createIdentifier(COMPONENT_IF_UNDEFINED) 1229 ), 1230 ts.factory.createBlock( 1231 [ts.factory.createExpressionStatement(ts.factory.createCallExpression( 1232 ts.factory.createPropertyAccessExpression( 1233 ts.factory.createIdentifier(REFLECT), 1234 ts.factory.createIdentifier(CREATE_SET_METHOD) 1235 ), 1236 undefined, 1237 [ 1238 ts.factory.createIdentifier(PUV2_VIEW_BASE), 1239 ts.factory.createStringLiteral(CONTEXT_STACK), 1240 ts.factory.createArrayLiteralExpression( 1241 [], 1242 false 1243 ) 1244 ] 1245 ))], 1246 true 1247 ), 1248 undefined 1249 ); 1250} 1251 1252export function contextStackPushOrPop(pushOrPop: ts.Identifier, param: ts.ThisExpression[] | []): ts.ExpressionStatement { 1253 return ts.factory.createExpressionStatement(ts.factory.createBinaryExpression( 1254 ts.factory.createPropertyAccessExpression( 1255 ts.factory.createIdentifier(PUV2_VIEW_BASE), 1256 ts.factory.createIdentifier(CONTEXT_STACK) 1257 ), 1258 ts.factory.createToken(ts.SyntaxKind.AmpersandAmpersandToken), 1259 ts.factory.createCallExpression( 1260 ts.factory.createPropertyAccessExpression( 1261 ts.factory.createPropertyAccessExpression( 1262 ts.factory.createIdentifier(PUV2_VIEW_BASE), 1263 ts.factory.createIdentifier(CONTEXT_STACK) 1264 ), 1265 pushOrPop 1266 ), 1267 undefined, 1268 param 1269 ) 1270 )); 1271} 1272