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