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; 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() && ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.name) && 734 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 isInComponentV2Context(): boolean { 740 if (componentCollection.currentClassName) { 741 const parentStructInfo: StructInfo = 742 processStructComponentV2.getOrCreateStructInfo(componentCollection.currentClassName); 743 return parentStructInfo.isComponentV2; 744 } 745 return false; 746} 747 748function isGeometryView(node: ts.Node): boolean { 749 if (ts.isExpressionStatement(node) && ts.isCallExpression(node.expression)) { 750 const call: ts.CallExpression = node.expression; 751 const exp: ts.Expression = call.expression; 752 const args: ts.NodeArray<ts.Expression> = call.arguments; 753 if (ts.isPropertyAccessExpression(exp) && ts.isIdentifier(exp.expression) && 754 exp.expression.escapedText.toString() === GEOMETRY_VIEW && ts.isIdentifier(exp.name) && 755 exp.name.escapedText.toString() === COMPONENT_CREATE_FUNCTION && args && args.length === 1 && 756 (ts.isArrowFunction(args[0]) || ts.isFunctionExpression(args[0]))) { 757 return true; 758 } 759 } 760 return false; 761} 762 763function processGeometryView(node: ts.ExpressionStatement, 764 log: LogInfo[]): ts.ExpressionStatement { 765 const exp: ts.CallExpression = node.expression as ts.CallExpression; 766 const arg: ts.ArrowFunction | ts.FunctionExpression = 767 exp.arguments[0] as ts.ArrowFunction | ts.FunctionExpression; 768 return ts.factory.updateExpressionStatement(node, ts.factory.updateCallExpression(exp, 769 exp.expression, undefined, [ts.factory.createArrowFunction(undefined, undefined, arg.parameters, 770 undefined, ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), 771 getGeometryReaderFunctionBlock(arg, log))])); 772} 773 774function getGeometryReaderFunctionBlock(node: ts.ArrowFunction | ts.FunctionExpression, 775 log: LogInfo[]): ts.Block { 776 let blockNode: ts.Block; 777 if (ts.isBlock(node.body)) { 778 blockNode = node.body; 779 } else if (ts.isArrowFunction(node) && ts.isCallExpression(node.body)) { 780 blockNode = ts.factory.createBlock([ts.factory.createExpressionStatement(node.body)]); 781 } 782 return processComponentBlock(blockNode, false, log); 783} 784 785export function updateHeritageClauses(node: ts.StructDeclaration, log: LogInfo[], 786 isComponentV2: boolean = false): ts.NodeArray<ts.HeritageClause> { 787 if (node.heritageClauses && !checkHeritageClauses(node)) { 788 log.push({ 789 type: LogType.ERROR, 790 message: 'Structs are not allowed to inherit from classes or implement interfaces.', 791 pos: node.heritageClauses.pos, 792 code: '10905212' 793 }); 794 } 795 const result: ts.HeritageClause[] = []; 796 const heritageClause: ts.HeritageClause = createHeritageClause(isComponentV2); 797 result.push(heritageClause); 798 return ts.factory.createNodeArray(result); 799} 800 801function checkHeritageClauses(node: ts.StructDeclaration): boolean { 802 if (node.heritageClauses.length === 1 && node.heritageClauses[0].types && 803 node.heritageClauses[0].types.length === 1) { 804 const expressionNode: ts.ExpressionWithTypeArguments = node.heritageClauses[0].types[0]; 805 if (expressionNode.expression && ts.isIdentifier(expressionNode.expression) && 806 expressionNode.expression.escapedText.toString() === CUSTOM_COMPONENT) { 807 return true; 808 } 809 } 810 return false; 811} 812 813export function isProperty(node: ts.Node): Boolean { 814 if (judgmentParentType(node)) { 815 if (node.parent.parent.expression && ts.isIdentifier(node.parent.parent.expression) && 816 !BUILDIN_STYLE_NAMES.has(node.parent.parent.expression.escapedText.toString()) && 817 componentCollection.customComponents.has( 818 node.parent.parent.expression.escapedText.toString())) { 819 return true; 820 } else if (ts.isPropertyAccessExpression(node.parent.parent.expression) && 821 ts.isIdentifier(node.parent.parent.expression.expression) && 822 componentCollection.customComponents.has( 823 node.parent.parent.expression.name.escapedText.toString())) { 824 return true; 825 } 826 } 827 return false; 828} 829 830function judgmentParentType(node: ts.Node): boolean { 831 return ts.isPropertyAssignment(node) && node.name && ts.isIdentifier(node.name) && 832 node.parent && ts.isObjectLiteralExpression(node.parent) && node.parent.parent && 833 (ts.isCallExpression(node.parent.parent) || ts.isEtsComponentExpression(node.parent.parent)); 834} 835 836export function createReference(node: ts.PropertyAssignment, log: LogInfo[], isBuilder = false, 837 isParamsLambda: boolean = false, isRecycleComponent: boolean = false): ts.PropertyAssignment { 838 const linkParentComponent: string[] = getParentNode(node, linkCollection).slice(1); 839 const propertyName: ts.Identifier = node.name as ts.Identifier; 840 let initText: string; 841 const LINK_REG: RegExp = /^\$/g; 842 if (isRecycleComponent && ts.isShorthandPropertyAssignment(node)) { 843 return node; 844 } 845 const initExpression: ts.Expression = node.initializer; 846 let is$$: boolean = false; 847 if (ts.isIdentifier(initExpression) && 848 initExpression.escapedText.toString().match(LINK_REG)) { 849 initText = initExpression.escapedText.toString().replace(LINK_REG, ''); 850 } else if (ts.isPropertyAccessExpression(initExpression) && initExpression.expression && 851 initExpression.expression.kind === ts.SyntaxKind.ThisKeyword && 852 ts.isIdentifier(initExpression.name) && initExpression.name.escapedText.toString().match(LINK_REG)) { 853 initText = initExpression.name.escapedText.toString().replace(LINK_REG, ''); 854 } else if (isBuilder && ts.isPropertyAccessExpression(initExpression) && initExpression.expression && 855 ts.isIdentifier(initExpression.expression) && initExpression.expression.escapedText.toString() === $$ && 856 ts.isIdentifier(initExpression.name) && linkParentComponent.includes(propertyName.escapedText.toString())) { 857 is$$ = true; 858 initText = initExpression.name.escapedText.toString(); 859 } else if (isMatchInitExpression(initExpression) && 860 linkParentComponent.includes(propertyName.escapedText.toString())) { 861 initText = initExpression.name.escapedText.toString().replace(LINK_REG, ''); 862 } 863 if (initText) { 864 node = addDoubleUnderline(node, propertyName, initText, is$$, isParamsLambda, isRecycleComponent); 865 } 866 return node; 867} 868 869function isMatchInitExpression(initExpression: ts.Expression): boolean { 870 return ts.isPropertyAccessExpression(initExpression) && 871 initExpression.expression && 872 initExpression.expression.kind === ts.SyntaxKind.ThisKeyword && 873 ts.isIdentifier(initExpression.name); 874} 875 876function addDoubleUnderline(node: ts.PropertyAssignment, propertyName: ts.Identifier, 877 initText: string, is$$ = false, isParamsLambda: boolean, isRecycleComponent: boolean): ts.PropertyAssignment { 878 return ts.factory.updatePropertyAssignment(node, propertyName, 879 ts.factory.createPropertyAccessExpression( 880 is$$ && partialUpdateConfig.partialUpdateMode ? ts.factory.createIdentifier($$) : ts.factory.createThis(), 881 isParamsLambda || isRecycleComponent ? ts.factory.createIdentifier(initText) : ts.factory.createIdentifier(`__${initText}`))); 882} 883 884function getParentNode(node: ts.PropertyAssignment, collection: Map<string, Set<string>>): string[] { 885 const grandparentNode: ts.NewExpression = node.parent.parent as ts.NewExpression; 886 const grandparentExpression: ts.Identifier | ts.PropertyAccessExpression = 887 grandparentNode.expression as ts.Identifier | ts.PropertyAccessExpression; 888 let parentComponent: Set<string> = new Set(); 889 let grandparentName: string; 890 if (ts.isIdentifier(grandparentExpression)) { 891 grandparentName = grandparentExpression.escapedText.toString(); 892 parentComponent = collection.get(grandparentName); 893 } else if (ts.isPropertyAccessExpression(grandparentExpression)) { 894 if (storedFileInfo.isAsPageImport) { 895 grandparentName = grandparentExpression.getText(); 896 } else { 897 grandparentName = grandparentExpression.name.escapedText.toString(); 898 } 899 parentComponent = collection.get(grandparentName); 900 } else { 901 // ignore 902 } 903 if (!parentComponent) { 904 parentComponent = new Set(); 905 } 906 return [grandparentName, ...parentComponent]; 907} 908 909function addUpdateParamsFunc(statements: ts.Statement[], parentComponentName: ts.Identifier): 910 ts.MethodDeclaration { 911 return createParamsInitBlock(COMPONENT_CONSTRUCTOR_UPDATE_PARAMS, statements, parentComponentName); 912} 913 914function addInitialParamsFunc(statements: ts.Statement[], parentComponentName: ts.Identifier): ts.MethodDeclaration { 915 return createParamsInitBlock(COMPONENT_CONSTRUCTOR_INITIAL_PARAMS, statements, parentComponentName); 916} 917 918function addUpdateStateVarsFunc(statements: ts.Statement[], parentComponentName: ts.Identifier): ts.MethodDeclaration { 919 return createParamsInitBlock(COMPONENT_UPDATE_STATE_VARS, statements, parentComponentName); 920} 921 922function addPurgeVariableDepFunc(statements: ts.Statement[]): ts.MethodDeclaration { 923 return ts.factory.createMethodDeclaration( 924 undefined, undefined, 925 ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PURGE_VARIABLE_DEP), 926 undefined, undefined, [ts.factory.createParameterDeclaration(undefined, undefined, 927 ts.factory.createIdentifier(RMELMTID), undefined, undefined, undefined)], undefined, 928 ts.factory.createBlock(statements, true)); 929} 930 931function addDeleteParamsFunc(statements: ts.PropertyDeclaration[], 932 updateRecyle: boolean = false): ts.MethodDeclaration { 933 const deleteStatements: ts.ExpressionStatement[] = []; 934 const updateStatements: ts.ExpressionStatement[] = []; 935 statements.forEach((statement: ts.PropertyDeclaration) => { 936 const name: ts.Identifier = statement.name as ts.Identifier; 937 let paramsStatement: ts.ExpressionStatement; 938 const decorators: readonly ts.Decorator[] = ts.getAllDecorators(statement); 939 const isRegular: boolean = isRegularProperty(decorators); 940 if (!partialUpdateConfig.partialUpdateMode || !isRegular) { 941 paramsStatement = createParamsWithUnderlineStatement(name); 942 } 943 if (partialUpdateConfig.partialUpdateMode && !isRegular) { 944 updateStatements.push(createElmtIdWithUnderlineStatement(name)); 945 } 946 deleteStatements.push(paramsStatement); 947 }); 948 if (partialUpdateConfig.partialUpdateMode && updateRecyle) { 949 return createRecycleElmt(updateStatements); 950 } 951 const defaultStatement: ts.ExpressionStatement = 952 ts.factory.createExpressionStatement(ts.factory.createCallExpression( 953 ts.factory.createPropertyAccessExpression( 954 ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression( 955 ts.factory.createIdentifier(CREATE_CONSTRUCTOR_SUBSCRIBER_MANAGER), 956 ts.factory.createIdentifier(CREATE_CONSTRUCTOR_GET_FUNCTION)), undefined, []), 957 ts.factory.createIdentifier(CREATE_CONSTRUCTOR_DELETE_FUNCTION)), 958 undefined, [ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression( 959 ts.factory.createThis(), ts.factory.createIdentifier( 960 !partialUpdateConfig.partialUpdateMode ? 961 ABOUT_TO_BE_DELETE_FUNCTION_ID : ABOUT_TO_BE_DELETE_FUNCTION_ID__)), 962 undefined, [])])); 963 deleteStatements.push(defaultStatement); 964 if (partialUpdateConfig.partialUpdateMode) { 965 const aboutToBeDeletedInternalStatement: ts.ExpressionStatement = createDeletedInternalStatement(); 966 deleteStatements.push(aboutToBeDeletedInternalStatement); 967 } 968 const deleteParamsMethod: ts.MethodDeclaration = 969 createParamsInitBlock(COMPONENT_CONSTRUCTOR_DELETE_PARAMS, deleteStatements); 970 return deleteParamsMethod; 971} 972 973function createRecycleElmt(statements: ts.Statement[]): ts.MethodDeclaration { 974 return ts.factory.createMethodDeclaration(undefined, undefined, 975 ts.factory.createIdentifier(UPDATE_RECYCLE_ELMT_ID), undefined, undefined, [ 976 ts.factory.createParameterDeclaration(undefined, undefined, 977 ts.factory.createIdentifier(OLD_ELMT_ID)), 978 ts.factory.createParameterDeclaration(undefined, undefined, 979 ts.factory.createIdentifier(NEW_ELMT_ID)) 980 ], undefined, ts.factory.createBlock(statements, true)); 981} 982 983function createParamsWithUnderlineStatement(name: ts.Identifier): ts.ExpressionStatement { 984 return ts.factory.createExpressionStatement( 985 ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression( 986 ts.factory.createPropertyAccessExpression(ts.factory.createThis(), 987 ts.factory.createIdentifier(`__${name.escapedText.toString()}`)), 988 ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_DELETE_PARAMS)), undefined, [])); 989} 990 991function createElmtIdWithUnderlineStatement(name: ts.Identifier): ts.ExpressionStatement { 992 return ts.factory.createExpressionStatement( 993 ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression( 994 ts.factory.createPropertyAccessExpression(ts.factory.createThis(), 995 ts.factory.createIdentifier(`__${name.escapedText.toString()}`)), 996 ts.factory.createIdentifier(COMPONENT_UPDATE_ELMT_ID)), undefined, [ 997 ts.factory.createIdentifier(OLD_ELMT_ID), ts.factory.createIdentifier(NEW_ELMT_ID) 998 ])); 999} 1000 1001function createDeletedInternalStatement(): ts.ExpressionStatement { 1002 return ts.factory.createExpressionStatement(ts.factory.createCallExpression( 1003 ts.factory.createPropertyAccessExpression(ts.factory.createThis(), 1004 ts.factory.createIdentifier(ABOUTTOBEDELETEDINTERNAL)), undefined, [])); 1005} 1006 1007export function addRerenderFunc(statements: ts.Statement[]): ts.MethodDeclaration { 1008 const updateDirtyElementStatement: ts.Statement = ts.factory.createExpressionStatement( 1009 ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression( 1010 ts.factory.createThis(), ts.factory.createIdentifier(UPDATEDIRTYELEMENTS)), undefined, [])); 1011 statements.push(updateDirtyElementStatement); 1012 if (storedFileInfo.hasLocalBuilderInFile) { 1013 statements.unshift(contextStackPushOrPop(ts.factory.createIdentifier(PUSH), [ts.factory.createThis()])); 1014 statements.push(contextStackPushOrPop(ts.factory.createIdentifier(COMPONENT_POP_FUNCTION), [])); 1015 } 1016 return ts.factory.createMethodDeclaration(undefined, undefined, 1017 ts.factory.createIdentifier(COMPONENT_RERENDER_FUNCTION), undefined, undefined, [], undefined, 1018 ts.factory.createBlock(statements, true)); 1019} 1020 1021function createParamsInitBlock(express: string, statements: ts.Statement[], 1022 parentComponentName?: ts.Identifier): ts.MethodDeclaration { 1023 const methodDeclaration: ts.MethodDeclaration = ts.factory.createMethodDeclaration( 1024 undefined, undefined, ts.factory.createIdentifier(express), undefined, undefined, 1025 [ts.factory.createParameterDeclaration(undefined, undefined, 1026 express === COMPONENT_CONSTRUCTOR_DELETE_PARAMS ? undefined : 1027 ts.factory.createIdentifier(CREATE_CONSTRUCTOR_PARAMS), undefined, 1028 express === COMPONENT_CONSTRUCTOR_DELETE_PARAMS ? undefined : 1029 ts.factory.createTypeReferenceNode( 1030 ts.factory.createIdentifier(parentComponentName.getText() + INTERFACE_NAME_SUFFIX), undefined), 1031 undefined)], undefined, ts.factory.createBlock(statements, true)); 1032 return methodDeclaration; 1033} 1034 1035export function validateBuildMethodCount(buildCount: BuildCount, parentComponentName: ts.Identifier, 1036 log: LogInfo[]): void { 1037 if (buildCount.count !== 1) { 1038 log.push({ 1039 type: LogType.ERROR, 1040 message: `The struct '${parentComponentName.getText()}' must have at least and at most one 'build' method.`, 1041 pos: parentComponentName.getStart(), 1042 code: '10905103', 1043 solutions: [`A structurally modified page must have at least one and no more than one 'build' method.`] 1044 }); 1045 } 1046} 1047 1048function validateHasControllerAndControllerCount(componentName: ts.Identifier, checkController: ControllerType, 1049 log: LogInfo[]): void { 1050 if (!checkController.hasController) { 1051 log.push({ 1052 type: LogType.ERROR, 1053 message: `The '@CustomDialog' decorated custom component must contain a property of the CustomDialogController type.`, 1054 pos: componentName.pos, 1055 code: '10905211' 1056 }); 1057 } 1058 if (checkController.unassignedControllerSet.size >= 2) { 1059 log.push({ 1060 type: LogType.WARN, 1061 message: 'A @CustomDialog component can only have one uninitialized CustomDialogController.', 1062 pos: componentName.pos 1063 }); 1064 } 1065} 1066 1067function createHeritageClause(isComponentV2: boolean = false): ts.HeritageClause { 1068 if (partialUpdateConfig.partialUpdateMode) { 1069 return ts.factory.createHeritageClause( 1070 ts.SyntaxKind.ExtendsKeyword, 1071 [ts.factory.createExpressionWithTypeArguments( 1072 ts.factory.createIdentifier(isComponentV2 ? constantDefine.STRUCT_PARENT : BASE_COMPONENT_NAME_PU), 1073 [])] 1074 ); 1075 } 1076 return ts.factory.createHeritageClause( 1077 ts.SyntaxKind.ExtendsKeyword, 1078 [ts.factory.createExpressionWithTypeArguments(ts.factory.createIdentifier(BASE_COMPONENT_NAME), [])] 1079 ); 1080} 1081 1082function createTypeReference(decoratorName: string, type: ts.TypeNode, log: LogInfo[], 1083 program: ts.Program): ts.TypeNode { 1084 let newType: ts.TypeNode; 1085 switch (decoratorName) { 1086 case COMPONENT_STATE_DECORATOR: 1087 case COMPONENT_PROVIDE_DECORATOR: 1088 newType = ts.factory.createTypeReferenceNode( 1089 isSimpleType(type, program, log) ? 1090 OBSERVED_PROPERTY_SIMPLE : 1091 OBSERVED_PROPERTY_OBJECT, 1092 [type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)] 1093 ); 1094 break; 1095 case COMPONENT_LINK_DECORATOR: 1096 case COMPONENT_CONSUME_DECORATOR: 1097 newType = ts.factory.createTypeReferenceNode( 1098 isSimpleType(type, program, log) ? 1099 SYNCHED_PROPERTY_SIMPLE_TWO_WAY : 1100 SYNCHED_PROPERTY_SIMPLE_ONE_WAY, 1101 [type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)] 1102 ); 1103 break; 1104 case COMPONENT_PROP_DECORATOR: 1105 newType = ts.factory.createTypeReferenceNode( 1106 SYNCHED_PROPERTY_SIMPLE_ONE_WAY, 1107 [type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)] 1108 ); 1109 break; 1110 case COMPONENT_OBJECT_LINK_DECORATOR: 1111 newType = ts.factory.createTypeReferenceNode( 1112 SYNCHED_PROPERTY_NESED_OBJECT, 1113 [type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)] 1114 ); 1115 break; 1116 case COMPONENT_STORAGE_PROP_DECORATOR: 1117 case COMPONENT_STORAGE_LINK_DECORATOR: 1118 newType = ts.factory.createTypeReferenceNode(OBSERVED_PROPERTY_ABSTRACT, [ 1119 type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword) 1120 ]); 1121 break; 1122 case COMPONENT_LOCAL_STORAGE_LINK_DECORATOR: 1123 case COMPONENT_LOCAL_STORAGE_PROP_DECORATOR: 1124 newType = ts.factory.createTypeReferenceNode(OBSERVED_PROPERTY_ABSTRACT, [ 1125 type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword) 1126 ]); 1127 break; 1128 } 1129 return newType; 1130} 1131 1132function createTypeReferencePU(decoratorName: string, type: ts.TypeNode, log: LogInfo[], 1133 program: ts.Program): ts.TypeNode { 1134 let newType: ts.TypeNode; 1135 switch (decoratorName) { 1136 case COMPONENT_STATE_DECORATOR: 1137 case COMPONENT_PROVIDE_DECORATOR: 1138 newType = ts.factory.createTypeReferenceNode( 1139 isSimpleType(type, program, log) ? 1140 OBSERVED_PROPERTY_SIMPLE_PU : 1141 OBSERVED_PROPERTY_OBJECT_PU, 1142 [type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)] 1143 ); 1144 break; 1145 case COMPONENT_LINK_DECORATOR: 1146 newType = ts.factory.createTypeReferenceNode( 1147 isSimpleType(type, program, log) ? 1148 SYNCHED_PROPERTY_SIMPLE_TWO_WAY_PU : 1149 SYNCHED_PROPERTY_SIMPLE_ONE_WAY_PU, 1150 [type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)] 1151 ); 1152 break; 1153 case COMPONENT_PROP_DECORATOR: 1154 newType = ts.factory.createTypeReferenceNode( 1155 SYNCHED_PROPERTY_SIMPLE_ONE_WAY_PU, 1156 [type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)] 1157 ); 1158 break; 1159 case COMPONENT_OBJECT_LINK_DECORATOR: 1160 newType = ts.factory.createTypeReferenceNode( 1161 SYNCHED_PROPERTY_NESED_OBJECT_PU, 1162 [type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)] 1163 ); 1164 break; 1165 case COMPONENT_CONSUME_DECORATOR: 1166 case COMPONENT_STORAGE_PROP_DECORATOR: 1167 case COMPONENT_STORAGE_LINK_DECORATOR: 1168 newType = ts.factory.createTypeReferenceNode(OBSERVED_PROPERTY_ABSTRACT_PU, [ 1169 type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword) 1170 ]); 1171 break; 1172 case COMPONENT_LOCAL_STORAGE_LINK_DECORATOR: 1173 case COMPONENT_LOCAL_STORAGE_PROP_DECORATOR: 1174 newType = ts.factory.createTypeReferenceNode(OBSERVED_PROPERTY_ABSTRACT_PU, [ 1175 type || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword) 1176 ]); 1177 break; 1178 } 1179 return newType; 1180} 1181 1182export function checkFinalizeConstruction(): ts.Statement { 1183 return ts.factory.createIfStatement( 1184 ts.factory.createPrefixUnaryExpression(ts.SyntaxKind.ExclamationToken, 1185 ts.factory.createParenthesizedExpression(ts.factory.createBinaryExpression( 1186 ts.factory.createStringLiteral(FINALIZE_CONSTRUCTION), 1187 ts.factory.createToken(ts.SyntaxKind.InKeyword), ts.factory.createPropertyAccessExpression( 1188 ts.factory.createIdentifier(BASE_COMPONENT_NAME_PU), ts.factory.createIdentifier(PROTOTYPE)))) 1189 ), 1190 ts.factory.createBlock( 1191 [ 1192 ts.factory.createExpressionStatement(ts.factory.createCallExpression( 1193 ts.factory.createPropertyAccessExpression( 1194 ts.factory.createIdentifier(REFLECT), ts.factory.createIdentifier(CREATE_SET_METHOD) 1195 ), undefined, 1196 [ 1197 ts.factory.createPropertyAccessExpression( 1198 ts.factory.createIdentifier(BASE_COMPONENT_NAME_PU), ts.factory.createIdentifier(PROTOTYPE) 1199 ), 1200 ts.factory.createStringLiteral(FINALIZE_CONSTRUCTION), 1201 ts.factory.createArrowFunction(undefined, undefined, [], undefined, 1202 ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), 1203 ts.factory.createBlock([], false) 1204 ) 1205 ] 1206 )) 1207 ], true), undefined); 1208} 1209 1210export function checkContextStack(): ts.Statement { 1211 return ts.factory.createIfStatement( 1212 ts.factory.createBinaryExpression( 1213 ts.factory.createPropertyAccessExpression( 1214 ts.factory.createIdentifier(PUV2_VIEW_BASE), 1215 ts.factory.createIdentifier(CONTEXT_STACK) 1216 ), 1217 ts.factory.createToken(ts.SyntaxKind.EqualsEqualsEqualsToken), 1218 ts.factory.createIdentifier(COMPONENT_IF_UNDEFINED) 1219 ), 1220 ts.factory.createBlock( 1221 [ts.factory.createExpressionStatement(ts.factory.createCallExpression( 1222 ts.factory.createPropertyAccessExpression( 1223 ts.factory.createIdentifier(REFLECT), 1224 ts.factory.createIdentifier(CREATE_SET_METHOD) 1225 ), 1226 undefined, 1227 [ 1228 ts.factory.createIdentifier(PUV2_VIEW_BASE), 1229 ts.factory.createStringLiteral(CONTEXT_STACK), 1230 ts.factory.createArrayLiteralExpression( 1231 [], 1232 false 1233 ) 1234 ] 1235 ))], 1236 true 1237 ), 1238 undefined 1239 ); 1240} 1241 1242export function contextStackPushOrPop(pushOrPop: ts.Identifier, param: ts.ThisExpression[] | []): ts.ExpressionStatement { 1243 return ts.factory.createExpressionStatement(ts.factory.createBinaryExpression( 1244 ts.factory.createPropertyAccessExpression( 1245 ts.factory.createIdentifier(PUV2_VIEW_BASE), 1246 ts.factory.createIdentifier(CONTEXT_STACK) 1247 ), 1248 ts.factory.createToken(ts.SyntaxKind.AmpersandAmpersandToken), 1249 ts.factory.createCallExpression( 1250 ts.factory.createPropertyAccessExpression( 1251 ts.factory.createPropertyAccessExpression( 1252 ts.factory.createIdentifier(PUV2_VIEW_BASE), 1253 ts.factory.createIdentifier(CONTEXT_STACK) 1254 ), 1255 pushOrPop 1256 ), 1257 undefined, 1258 param 1259 ) 1260 )); 1261} 1262