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