1/* 2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import ts from 'typescript'; 17import path from 'path'; 18 19import { 20 COMPONENT_RENDER_FUNCTION, 21 COMPONENT_CREATE_FUNCTION, 22 COMPONENT_POP_FUNCTION, 23 COMPONENT_BUTTON, 24 COMPONENT_CREATE_LABEL_FUNCTION, 25 COMPONENT_CREATE_CHILD_FUNCTION, 26 COMPONENT_FOREACH, 27 COMPONENT_LAZYFOREACH, 28 IS_RENDERING_IN_PROGRESS, 29 FOREACH_OBSERVED_OBJECT, 30 FOREACH_GET_RAW_OBJECT, 31 COMPONENT_IF, 32 COMPONENT_IF_BRANCH_ID_FUNCTION, 33 COMPONENT_IF_UNDEFINED, 34 ATTRIBUTE_ANIMATION, 35 GLOBAL_CONTEXT, 36 COMPONENT_GESTURE, 37 COMPONENT_GESTURE_GROUP, 38 GESTURE_ATTRIBUTE, 39 PARALLEL_GESTURE_ATTRIBUTE, 40 PRIORITY_GESTURE_ATTRIBUTE, 41 GESTURE_ENUM_KEY, 42 GESTURE_ENUM_VALUE_HIGH, 43 GESTURE_ENUM_VALUE_LOW, 44 GESTURE_ENUM_VALUE_PARALLEL, 45 COMPONENT_TRANSITION_NAME, 46 COMPONENT_DEBUGLINE_FUNCTION, 47 ATTRIBUTE_STATESTYLES, 48 THIS, 49 VISUAL_STATE, 50 VIEW_STACK_PROCESSOR, 51 STYLE_ADD_DOUBLE_DOLLAR, 52 STYLE_ADD_DOUBLE_EXCLAMATION, 53 $$_VALUE, 54 $$_CHANGE_EVENT, 55 $$_THIS, 56 $$_NEW_VALUE, 57 $_VALUE, 58 BUILDER_ATTR_NAME, 59 BUILDER_ATTR_BIND, 60 CUSTOM_DIALOG_CONTROLLER_BUILDER, 61 BIND_DRAG_SET, 62 BIND_POPUP_SET, 63 BIND_POPUP, 64 CUSTOM_COMPONENT_DEFAULT, 65 $$, 66 PROPERTIES_ADD_DOUBLE_DOLLAR, 67 PROPERTIES_ADD_DOUBLE_EXCLAMATION, 68 ATTRIBUTE_ID, 69 RESOURCE, 70 ISINITIALRENDER, 71 ELMTID, 72 VIEWSTACKPROCESSOR, 73 STOPGETACCESSRECORDING, 74 STARTGETACCESSRECORDINGFOR, 75 OBSERVECOMPONENTCREATION, 76 OBSERVECOMPONENTCREATION2, 77 DEEPRENDERFUNCTION, 78 ITEMCREATION, 79 ITEMCREATION2, 80 OBSERVEDDEEPRENDER, 81 ItemComponents, 82 FOREACHITEMGENFUNCTION, 83 __LAZYFOREACHITEMGENFUNCTION, 84 _ITEM, 85 FOREACHITEMIDFUNC, 86 __LAZYFOREACHITEMIDFUNC, 87 FOREACHUPDATEFUNCTION, 88 COMPONENT_INITIAL_RENDER_FUNCTION, 89 COMPONENT_REPEAT, 90 REPEAT_EACH, 91 REPEAT_TEMPLATE, 92 LIST_ITEM, 93 IFELSEBRANCHUPDATEFUNCTION, 94 CARD_ENABLE_COMPONENTS, 95 CARD_LOG_TYPE_COMPONENTS, 96 COMPONENT_CONSTRUCTOR_PARENT, 97 RESOURCE_NAME_TYPE, 98 XCOMPONENT_SINGLE_QUOTATION, 99 XCOMPONENT_DOUBLE_QUOTATION, 100 XCOMPONENTTYPE, 101 XCOMPONENTTYPE_CONTAINER, 102 BIND_OBJECT_PROPERTY, 103 TRUE, 104 FALSE, 105 HEADER, 106 INDICATORBUILDER, 107 FOOTER, 108 CALL, 109 CREATE_BIND_COMPONENT, 110 TabContentAndNavDestination, 111 START, 112 END, 113 BUILDER_PARAM_PROXY, 114 BUILDER_TYPE, 115 CHECK_COMPONENT_EXTEND_DECORATOR, 116 CHECK_COMPONENT_ANIMATABLE_EXTEND_DECORATOR, 117 RECYCLE_REUSE_ID, 118 UPDATE_FUNC_BY_ELMT_ID, 119 CREATE_SET_METHOD, 120 CAN_RETAKE, 121 PREVIEW, 122 IDS, 123 PUSH, 124 UPDATE_LAZY_FOREACH_ELEMENTS, 125 INDEX, 126 IS_INITIAL_ITEM, 127 MY_IDS, 128 WRAPBUILDER_BUILDERPROP, 129 WRAPPEDBUILDER_CLASS, 130 ALL_COMPONENTS, 131 ATTRIBUTE_ATTRIBUTE_MODIFIER, 132 ATTRIBUTE_CONTENT_MODIFIER, 133 ATTRIBUTE_MENUITEM_CONTENT_MODIFIER, 134 TITLE, 135 PAGE_PATH, 136 RESOURCE_NAME_MODULE, 137 NAV_DESTINATION, 138 NAVIGATION, 139 CREATE_ROUTER_COMPONENT_COLLECT, 140 NAV_PATH_STACK, 141 IS_USER_CREATE_STACK, 142 REUSE_ATTRIBUTE 143} from './pre_define'; 144import { 145 INNER_COMPONENT_NAMES, 146 BUILDIN_CONTAINER_COMPONENT, 147 BUILDIN_STYLE_NAMES, 148 CUSTOM_BUILDER_METHOD, 149 GESTURE_ATTRS, 150 GESTURE_TYPE_NAMES, 151 EXTEND_ATTRIBUTE, 152 NO_DEBUG_LINE_COMPONENT, 153 NEEDPOP_COMPONENT, 154 INNER_STYLE_FUNCTION, 155 GLOBAL_STYLE_FUNCTION, 156 CUSTOM_BUILDER_PROPERTIES, 157 CUSTOM_BUILDER_PROPERTIES_WITHOUTKEY, 158 CUSTOM_BUILDER_CONSTRUCTORS, 159 ID_ATTRS, 160 SPECIFIC_PARENT_COMPONENT, 161 STYLES_ATTRIBUTE, 162 INNER_CUSTOM_LOCALBUILDER_METHOD, 163 COMMON_ATTRS 164} from './component_map'; 165import { 166 componentCollection, 167 builderParamObjectCollection, 168 checkAllNode, 169 enumCollection 170} from './validate_ui_syntax'; 171import { 172 processCustomComponent, 173 createConditionParent, 174 isRecycle, 175 isReuseInV2 176} from './process_custom_component'; 177import { 178 LogType, 179 LogInfo, 180 componentInfo, 181 storedFileInfo 182} from './utils'; 183import { 184 globalProgram, 185 partialUpdateConfig, 186 projectConfig 187} from '../main'; 188import { 189 transformLog, 190 contextGlobal, 191 validatorCard, 192 builderTypeParameter, 193 resourceFileName 194} from './process_ui_syntax'; 195import { regularCollection, getSymbolIfAliased } from './validate_ui_syntax'; 196import { contextStackPushOrPop } from './process_component_class'; 197import processStructComponentV2, { StructInfo } from './process_struct_componentV2'; 198import logMessageCollection from './log_message_collection'; 199 200export function processComponentBuild(node: ts.MethodDeclaration, 201 log: LogInfo[]): ts.MethodDeclaration { 202 let newNode: ts.MethodDeclaration; 203 let renderNode: ts.Identifier; 204 if (!partialUpdateConfig.partialUpdateMode) { 205 renderNode = ts.factory.createIdentifier(COMPONENT_RENDER_FUNCTION); 206 } else { 207 renderNode = ts.factory.createIdentifier(COMPONENT_INITIAL_RENDER_FUNCTION); 208 } 209 if (node.body && node.body.statements && node.body.statements.length && 210 validateRootNode(node, log)) { 211 const componentBlock: ts.Block = processComponentBlock(node.body, false, log); 212 newNode = ts.factory.updateMethodDeclaration(node, ts.getModifiers(node), 213 node.asteriskToken, renderNode, node.questionToken, node.typeParameters, node.parameters, 214 node.type, componentBlock); 215 if (partialUpdateConfig.partialUpdateMode && storedFileInfo.hasLocalBuilderInFile) { 216 componentBlock.statements.unshift(contextStackPushOrPop(ts.factory.createIdentifier(PUSH), [ts.factory.createThis()])); 217 componentBlock.statements.push(contextStackPushOrPop(ts.factory.createIdentifier(COMPONENT_POP_FUNCTION), [])); 218 } 219 } else { 220 newNode = ts.factory.updateMethodDeclaration(node, ts.getModifiers(node), 221 node.asteriskToken, renderNode, node.questionToken, node.typeParameters, node.parameters, 222 node.type, node.body); 223 } 224 return newNode; 225} 226 227function createLazyForEachBlockNode(newStatements: ts.Statement[]): ts.IfStatement { 228 return ts.factory.createIfStatement( 229 ts.factory.createBinaryExpression( 230 ts.factory.createBinaryExpression( 231 ts.factory.createIdentifier(IS_INITIAL_ITEM), 232 ts.factory.createToken(ts.SyntaxKind.EqualsEqualsEqualsToken), 233 ts.factory.createIdentifier(COMPONENT_IF_UNDEFINED) 234 ), 235 ts.factory.createToken(ts.SyntaxKind.BarBarToken), 236 ts.factory.createIdentifier(IS_INITIAL_ITEM) 237 ), 238 ts.factory.createBlock(newStatements, true), 239 ts.factory.createBlock([ 240 ts.factory.createExpressionStatement(ts.factory.createCallExpression( 241 ts.factory.createPropertyAccessExpression( 242 ts.factory.createThis(), 243 ts.factory.createIdentifier(UPDATE_LAZY_FOREACH_ELEMENTS) 244 ), undefined, [ 245 ts.factory.createIdentifier(IDS), 246 storedFileInfo.lazyForEachInfo.forEachParameters.name as ts.Identifier 247 ] 248 )) 249 ], true) 250 ); 251} 252 253export type BuilderParamsResult = { 254 firstParam: ts.ParameterDeclaration; 255}; 256 257export function parseGlobalBuilderParams(parameters: ts.NodeArray<ts.ParameterDeclaration>, 258 builderParamsResult: BuilderParamsResult) : void { 259 if (partialUpdateConfig.partialUpdateMode && parameters.length && parameters.length === 1 && 260 ts.isIdentifier(parameters[0].name)) { 261 builderParamsResult.firstParam = parameters[0]; 262 } 263} 264 265export function processComponentBlock(node: ts.Block, isLazy: boolean, log: LogInfo[], 266 isTransition: boolean = false, isBuilder: boolean = false, parent: string = undefined, 267 forEachParameters: ts.NodeArray<ts.ParameterDeclaration> = undefined, 268 isGlobalBuilder: boolean = false, builderParamsResult: BuilderParamsResult = null, 269 rootGlobalBuilder: boolean = false, isInRepeatTemplate: boolean = false): ts.Block { 270 const newStatements: ts.Statement[] = []; 271 processComponentChild(node, newStatements, log, {isAcceleratePreview: false, line: 0, column: 0, fileName: ''}, 272 isBuilder, parent, forEachParameters, isGlobalBuilder, isTransition, builderParamsResult, isInRepeatTemplate); 273 if (isLazy && !partialUpdateConfig.partialUpdateMode) { 274 newStatements.unshift(createRenderingInProgress(true)); 275 } 276 if (isTransition) { 277 if (!partialUpdateConfig.partialUpdateMode) { 278 newStatements.unshift(ts.factory.createExpressionStatement( 279 createFunction(ts.factory.createIdentifier(COMPONENT_TRANSITION_NAME), 280 ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION), null))); 281 } else { 282 newStatements.unshift(createComponentCreationStatement(ts.factory.createExpressionStatement( 283 createFunction(ts.factory.createIdentifier(COMPONENT_TRANSITION_NAME), 284 ts.factory.createIdentifier(COMPONENT_POP_FUNCTION), null)), [ts.factory.createExpressionStatement( 285 createFunction(ts.factory.createIdentifier(COMPONENT_TRANSITION_NAME), 286 ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION), null))], COMPONENT_TRANSITION_NAME, false, isTransition)); 287 } 288 newStatements.push(ts.factory.createExpressionStatement( 289 createFunction(ts.factory.createIdentifier(COMPONENT_TRANSITION_NAME), 290 ts.factory.createIdentifier(COMPONENT_POP_FUNCTION), null))); 291 } 292 if (isLazy && !partialUpdateConfig.partialUpdateMode) { 293 newStatements.push(createRenderingInProgress(false)); 294 } 295 if (rootGlobalBuilder && isGlobalBuilder && builderParamsResult && builderParamsResult.firstParam) { 296 newStatements.unshift(forkBuilderParamNode(builderParamsResult.firstParam)); 297 } 298 if (isLazy && projectConfig.optLazyForEach && storedFileInfo.processLazyForEach && 299 storedFileInfo.lazyForEachInfo.forEachParameters) { 300 return ts.factory.updateBlock(node, [ 301 createMyIdsNode(), 302 createLazyForEachBlockNode(newStatements), 303 ts.factory.createReturnStatement(ts.factory.createIdentifier(MY_IDS)) 304 ]); 305 } 306 return ts.factory.updateBlock(node, newStatements); 307} 308 309function createMyIdsNode(): ts.Statement { 310 return ts.factory.createVariableStatement( 311 undefined, 312 ts.factory.createVariableDeclarationList( 313 [ts.factory.createVariableDeclaration( 314 ts.factory.createIdentifier(MY_IDS), 315 undefined, 316 undefined, 317 ts.factory.createArrayLiteralExpression( 318 [], 319 false 320 ) 321 )], 322 ts.NodeFlags.Const 323 ) 324 ); 325} 326 327function visitComponent(node: ts.Node): void { 328 if (storedFileInfo.lazyForEachInfo && !ts.isBlock(node)) { 329 ts.forEachChild(node, (child: ts.Node) => { 330 if (storedFileInfo.lazyForEachInfo.isDependItem) { 331 return; 332 } 333 if (ts.isIdentifier(child)) { 334 const symbol: ts.Symbol = globalProgram.checker.getSymbolAtLocation(child); 335 if (symbol && symbol.valueDeclaration === storedFileInfo.lazyForEachInfo.forEachParameters) { 336 storedFileInfo.lazyForEachInfo.isDependItem = true; 337 return; 338 } 339 } 340 visitComponent(child); 341 }); 342 } 343} 344 345function forkBuilderParamNode(node: ts.ParameterDeclaration): ts.Statement { 346 const paramNode: ts.Identifier = node.name as ts.Identifier; 347 return ts.factory.createVariableStatement( 348 undefined, 349 ts.factory.createVariableDeclarationList( 350 [ts.factory.createVariableDeclaration( 351 ts.factory.createIdentifier(`__${paramNode.escapedText.toString()}__`), 352 undefined, 353 undefined, 354 paramNode 355 )], 356 ts.NodeFlags.Const 357 ) 358 ); 359} 360 361function validateRootNode(node: ts.MethodDeclaration, log: LogInfo[]): boolean { 362 let isValid: boolean = false; 363 if (node.body.statements.length === 1) { 364 const statement: ts.Statement = node.body.statements[0]; 365 if (ts.isIfStatement(statement) || validateFirstNode(statement)) { 366 isValid = true; 367 } 368 } else { 369 isValid = false; 370 } 371 if (!isValid) { 372 log.push({ 373 type: LogType.ERROR, 374 message: `In an '@Entry' decorated component, the 'build' method can have only one root node,` + 375 ` which must be a container component.`, 376 pos: node.body.statements.pos, 377 code: '10905210' 378 }); 379 } 380 return isValid; 381} 382 383function validateFirstNode(node: ts.Statement): boolean { 384 const isEntryComponent: boolean = 385 componentCollection.entryComponent === componentCollection.currentClassName; 386 if (isEntryComponent && !validateContainerComponent(node)) { 387 return false; 388 } 389 return true; 390} 391 392function validateContainerComponent(node: ts.Statement): boolean { 393 if (ts.isExpressionStatement(node) && node.expression && 394 (ts.isEtsComponentExpression(node.expression) || ts.isCallExpression(node.expression))) { 395 const nameResult: NameResult = { name: null, node: null, arguments: [] }; 396 validateEtsComponentNode(node.expression, nameResult); 397 if (nameResult.name && checkContainer(nameResult.name, nameResult.node)) { 398 return true; 399 } 400 } 401 return false; 402} 403 404interface supplementType { 405 isAcceleratePreview: boolean, 406 line: number, 407 column: number, 408 fileName: string 409} 410 411let newsupplement: supplementType = { 412 isAcceleratePreview: false, 413 line: 0, 414 column: 0, 415 fileName: '' 416}; 417 418type NameResult = { 419 name: string, 420 arguments: ts.NodeArray<ts.Expression> | [], 421 node?: ts.Node 422}; 423 424function validateEtsComponentNode(node: ts.CallExpression | ts.EtsComponentExpression, result?: NameResult): boolean { 425 let childNode: ts.Node = node; 426 result.name = null; 427 while (ts.isCallExpression(childNode) && childNode.expression && 428 ts.isPropertyAccessExpression(childNode.expression) && childNode.expression.expression) { 429 childNode = childNode.expression.expression; 430 } 431 if (ts.isEtsComponentExpression(childNode)) { 432 if (ts.isIdentifier(childNode.expression)) { 433 result.name = childNode.expression.getText(); 434 result.node = childNode; 435 result.arguments = childNode.arguments || []; 436 } 437 return true; 438 } else { 439 return false; 440 } 441} 442 443let sourceNode: ts.SourceFile; 444 445export function processComponentChild(node: ts.Block | ts.SourceFile, newStatements: ts.Statement[], 446 log: LogInfo[], supplement: supplementType = {isAcceleratePreview: false, line: 0, column: 0, fileName: ''}, 447 isBuilder: boolean = false, parent: string = undefined, 448 forEachParameters: ts.NodeArray<ts.ParameterDeclaration> = undefined, isGlobalBuilder: boolean = false, 449 isTransition: boolean = false, builderParamsResult: BuilderParamsResult = null, 450 isInRepeatTemplate: boolean = false): void { 451 if (supplement.isAcceleratePreview) { 452 newsupplement = supplement; 453 const compilerOptions = ts.readConfigFile( 454 path.resolve(__dirname, '../tsconfig.json'), ts.sys.readFile).config.compilerOptions; 455 Object.assign(compilerOptions, { 456 'sourceMap': false 457 }); 458 sourceNode = ts.createSourceFile('', node.getText(), ts.ScriptTarget.Latest, true, ts.ScriptKind.ETS, compilerOptions); 459 } 460 if (node.statements.length) { 461 // Save parent component 462 const savedParent: string = parent; 463 node.statements.forEach((item) => { 464 if (ts.isExpressionStatement(item)) { 465 assignParameter(forEachParameters, item); 466 checkEtsComponent(item, log); 467 const name: string = getName(item); 468 if (CARD_ENABLE_COMPONENTS.has(name)) { 469 validatorCard(log, CARD_LOG_TYPE_COMPONENTS, item.getStart(), name); 470 } 471 switch (getComponentType(item, log, name, parent, forEachParameters)) { 472 case ComponentType.innerComponent: { 473 const [etsExpression, idName]: [ts.EtsComponentExpression, ts.Expression] = 474 checkEtsAndIdInIf(item, savedParent); 475 if (ts.isIdentifier(etsExpression.expression)) { 476 parent = etsExpression.expression.escapedText.toString(); 477 } 478 processInnerComponent(item, newStatements, log, parent, isBuilder, isGlobalBuilder, 479 isTransition, idName, savedParent, builderParamsResult, isInRepeatTemplate); 480 break; 481 } 482 case ComponentType.customComponent: { 483 const idName: ts.Expression = checkIdInIf(item, savedParent); 484 parent = undefined; 485 if (!newsupplement.isAcceleratePreview) { 486 if (item.expression && ts.isEtsComponentExpression(item.expression) && item.expression.body) { 487 const expressionResult: ts.ExpressionStatement = 488 processExpressionStatementChange(item, item.expression.body, log); 489 if (expressionResult) { 490 item = expressionResult; 491 } 492 } 493 processCustomComponent(item as ts.ExpressionStatement, newStatements, log, name, 494 isBuilder, isGlobalBuilder, idName, builderParamsResult, isInRepeatTemplate); 495 } 496 break; 497 } 498 case ComponentType.forEachComponent: 499 parent = undefined; 500 if (!partialUpdateConfig.partialUpdateMode) { 501 processForEachComponent(item, newStatements, log, isBuilder, isGlobalBuilder); 502 } else { 503 processForEachComponentNew(item, newStatements, log, name, isGlobalBuilder, builderParamsResult, isInRepeatTemplate); 504 } 505 break; 506 case ComponentType.repeatComponent: 507 parent = undefined; 508 processRepeatComponent(item, newStatements, log, isBuilder, isGlobalBuilder, isTransition, builderParamsResult, isInRepeatTemplate); 509 break; 510 case ComponentType.customBuilderMethod: 511 parent = undefined; 512 if (partialUpdateConfig.partialUpdateMode) { 513 newStatements.push(transferBuilderCall(item, name, isBuilder)); 514 } else { 515 newStatements.push(addInnerBuilderParameter(item, isGlobalBuilder)); 516 } 517 break; 518 case ComponentType.builderParamMethod: 519 parent = undefined; 520 if (partialUpdateConfig.partialUpdateMode) { 521 newStatements.push(transferBuilderCall(item, name, isBuilder)); 522 } else { 523 newStatements.push(addInnerBuilderParameter(item)); 524 } 525 break; 526 case ComponentType.builderTypeFunction: 527 parent = undefined; 528 if (partialUpdateConfig.partialUpdateMode) { 529 newStatements.push(transferBuilderCall(item, name, isBuilder)); 530 } else { 531 newStatements.push(addInnerBuilderParameter(item)); 532 } 533 break; 534 case ComponentType.function: 535 parent = undefined; 536 newStatements.push(item); 537 break; 538 } 539 } else if (ts.isIfStatement(item)) { 540 assignParameter(forEachParameters, item); 541 processIfStatement(item, newStatements, log, isBuilder, isGlobalBuilder, builderParamsResult, isInRepeatTemplate); 542 } else if (!ts.isBlock(item)) { 543 log.push({ 544 type: LogType.ERROR, 545 message: `Only UI component syntax can be written here.`, 546 pos: item.getStart(), 547 code: '10905209' 548 }); 549 } 550 storedFileInfo.lazyForEachInfo.isDependItem = false; 551 }); 552 } 553 if (supplement.isAcceleratePreview) { 554 newsupplement = { 555 isAcceleratePreview: false, 556 line: 0, 557 column: 0, 558 fileName: '' 559 }; 560 } 561} 562 563function assignParameter(forEachParameters: ts.NodeArray<ts.ParameterDeclaration>, item: ts.Node): void { 564 if (partialUpdateConfig.partialUpdateMode && projectConfig.optLazyForEach && 565 storedFileInfo.processLazyForEach) { 566 if (forEachParameters && forEachParameters[0]) { 567 storedFileInfo.lazyForEachInfo.forEachParameters = forEachParameters[0]; 568 } 569 if (storedFileInfo.lazyForEachInfo.forEachParameters) { 570 visitComponent(item); 571 } 572 } 573} 574 575export function transferBuilderCall(node: ts.ExpressionStatement, name: string, 576 isBuilder: boolean = false): ts.ExpressionStatement { 577 if (node.expression && ts.isCallExpression(node.expression)) { 578 let newNode: ts.Expression = builderCallNode(node.expression); 579 newNode.expression.questionDotToken = node.expression.questionDotToken; 580 if (node.expression.arguments && node.expression.arguments.length === 1 && ts.isObjectLiteralExpression(node.expression.arguments[0])) { 581 return ts.factory.createExpressionStatement(ts.factory.updateCallExpression( 582 node.expression, 583 newNode, 584 undefined, 585 [ts.factory.createCallExpression( 586 ts.factory.createIdentifier(BUILDER_PARAM_PROXY), 587 undefined, 588 [ 589 ts.factory.createStringLiteral(name), 590 traverseBuilderParams(node.expression.arguments[0], isBuilder) 591 ] 592 )] 593 )); 594 } else { 595 return ts.factory.createExpressionStatement(ts.factory.updateCallExpression( 596 node.expression, 597 newNode, 598 undefined, 599 !(projectConfig.optLazyForEach && (storedFileInfo.processLazyForEach && 600 storedFileInfo.lazyForEachInfo.forEachParameters || isBuilder)) ? node.expression.arguments : 601 [...node.expression.arguments, ts.factory.createNull(), ts.factory.createIdentifier(MY_IDS)] 602 )); 603 } 604 } 605 return undefined; 606} 607 608function builderCallNode(node: ts.CallExpression): ts.Expression { 609 let newNode: ts.Expression; 610 if (node.expression && ts.isPropertyAccessExpression(node.expression) && 611 node.expression.questionDotToken && node.expression.questionDotToken.kind === ts.SyntaxKind.QuestionDotToken) { 612 newNode = ts.factory.createCallChain( 613 ts.factory.createPropertyAccessChain( 614 node.expression, 615 node.questionDotToken, 616 ts.factory.createIdentifier(BUILDER_ATTR_BIND) 617 ), 618 undefined, 619 undefined, 620 [ts.factory.createThis()] 621 ); 622 } else { 623 newNode = ts.factory.createCallExpression( 624 ts.factory.createPropertyAccessExpression( 625 node.expression, 626 ts.factory.createIdentifier(BUILDER_ATTR_BIND) 627 ), 628 undefined, 629 [ts.factory.createThis()] 630 ); 631 } 632 return newNode; 633} 634 635function traverseBuilderParams(node: ts.ObjectLiteralExpression, 636 isBuilder: boolean): ts.ObjectLiteralExpression { 637 const properties: ts.ObjectLiteralElementLike[] = []; 638 if (node.properties && node.properties.length) { 639 node.properties.forEach(property => { 640 if (ts.isPropertyAssignment(property) && property.initializer && 641 ts.isPropertyAccessExpression(property.initializer) && property.initializer.expression && 642 property.initializer.name && ts.isIdentifier(property.initializer.name)) { 643 const name: string = property.initializer.name.escapedText.toString(); 644 if (!storedFileInfo.processGlobalBuilder && property.initializer.expression.kind === ts.SyntaxKind.ThisKeyword || 645 isBuilder && ts.isIdentifier(property.initializer.expression) && 646 property.initializer.expression.escapedText.toString() === $$) { 647 const useThis: boolean = property.initializer.expression.kind === ts.SyntaxKind.ThisKeyword; 648 addProperties(properties, property, name, isBuilder, useThis); 649 } else { 650 addBuilderParamsProperties(properties, property); 651 } 652 } else { 653 addBuilderParamsProperties(properties, property); 654 } 655 }); 656 } 657 return ts.factory.createObjectLiteralExpression(properties); 658} 659 660function addBuilderParamsProperties(properties: ts.ObjectLiteralElementLike[], 661 property: ts.ObjectLiteralElementLike): void { 662 const initializer: ts.Expression = ts.isShorthandPropertyAssignment(property) ? 663 property.name : property.initializer; 664 properties.push(ts.factory.createPropertyAssignment( 665 property.name, 666 ts.factory.createArrowFunction( 667 undefined, 668 undefined, 669 [], 670 undefined, 671 ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), 672 initializer 673 ) 674 )); 675} 676 677function addProperties(properties: ts.ObjectLiteralElementLike[], property: ts.ObjectLiteralElementLike, 678 name: string, isBuilder: boolean, useThis: boolean): void { 679 properties.push(ts.factory.createPropertyAssignment( 680 property.name, 681 ts.factory.createArrowFunction( 682 undefined, 683 undefined, 684 [], 685 undefined, 686 ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), 687 ts.factory.createParenthesizedExpression(ts.factory.createConditionalExpression( 688 ts.factory.createElementAccessExpression( 689 (isBuilder && !useThis) ? ts.factory.createIdentifier($$) : ts.factory.createThis(), 690 ts.factory.createStringLiteral('__' + name) 691 ), 692 ts.factory.createToken(ts.SyntaxKind.QuestionToken), 693 ts.factory.createElementAccessExpression( 694 (isBuilder && !useThis) ? ts.factory.createIdentifier($$) : ts.factory.createThis(), 695 ts.factory.createStringLiteral('__' + name) 696 ), 697 ts.factory.createToken(ts.SyntaxKind.ColonToken), 698 ts.factory.createElementAccessExpression( 699 (isBuilder && !useThis) ? ts.factory.createIdentifier($$) : ts.factory.createThis(), 700 ts.factory.createStringLiteral(name) 701 ) 702 )) 703 ) 704 )); 705} 706 707function addInnerBuilderParameter(node: ts.ExpressionStatement, 708 isGlobalBuilder: boolean = false): ts.ExpressionStatement { 709 if (node.expression && ts.isCallExpression(node.expression) && node.expression.arguments) { 710 node.expression.arguments.push(isGlobalBuilder ? parentConditionalExpression() : ts.factory.createThis()); 711 return ts.factory.createExpressionStatement(ts.factory.updateCallExpression(node.expression, 712 node.expression.expression, node.expression.typeArguments, node.expression.arguments)); 713 } else { 714 return node; 715 } 716} 717 718function processExpressionStatementChange(node: ts.ExpressionStatement, nextNode: ts.Block, 719 log: LogInfo[]): ts.ExpressionStatement { 720 let name: string; 721 // @ts-ignore 722 if (node.expression.expression && ts.isIdentifier(node.expression.expression)) { 723 name = node.expression.expression.escapedText.toString(); 724 } else if (node.expression.expression && ts.isPropertyAccessExpression(node.expression.expression)) { 725 name = node.expression.expression.getText(); 726 } 727 if (builderParamObjectCollection.get(name) && 728 builderParamObjectCollection.get(name).size === 1) { 729 return processBlockToExpression(node, nextNode, log, name, false); 730 } else if (projectConfig.compileMode === 'esmodule' && process.env.compileTool === 'rollup' && 731 storedFileInfo.overallBuilderParamCollection.get(name) && 732 storedFileInfo.overallBuilderParamCollection.get(name).size === 1 733 ) { 734 return processBlockToExpression(node, nextNode, log, name, true); 735 } else { 736 log.push({ 737 type: LogType.ERROR, 738 message: `In the trailing lambda case, '${name}' must have one and only one property decorated with ` + 739 `'@BuilderParam', and its '@BuilderParam' expects no parameter.`, 740 pos: node.getStart(), 741 code: '10905102' 742 }); 743 return null; 744 } 745} 746 747function processBlockToExpression(node: ts.ExpressionStatement, nextNode: ts.Block, 748 log: LogInfo[], name: string, isPropertyAccessExpressionNode: boolean): ts.ExpressionStatement { 749 const childParam: string = isPropertyAccessExpressionNode ? [...storedFileInfo.overallBuilderParamCollection.get(name)].slice(-1)[0] : 750 [...builderParamObjectCollection.get(name)].slice(-1)[0]; 751 const newBlock: ts.Block = processComponentBlock(nextNode, false, log); 752 const arrowNode: ts.ArrowFunction = ts.factory.createArrowFunction(undefined, undefined, 753 [], undefined, ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), newBlock); 754 const newPropertyAssignment:ts.PropertyAssignment = ts.factory.createPropertyAssignment( 755 ts.factory.createIdentifier(childParam), arrowNode); 756 // @ts-ignore 757 let argumentsArray: ts.ObjectLiteralExpression[] = node.expression.arguments; 758 if (argumentsArray && !argumentsArray.length) { 759 argumentsArray = [ts.factory.createObjectLiteralExpression([newPropertyAssignment], true)]; 760 } else if (ts.isObjectLiteralExpression(argumentsArray[0]) && argumentsArray.length === 1) { 761 argumentsArray = [ts.factory.createObjectLiteralExpression( 762 // @ts-ignore 763 node.expression.arguments[0].properties.concat([newPropertyAssignment]), true)]; 764 } else if (ts.isObjectLiteralExpression(argumentsArray[0]) && argumentsArray.length === 2) { 765 argumentsArray = [ts.factory.createObjectLiteralExpression( 766 // @ts-ignore 767 node.expression.arguments[0].properties.concat([newPropertyAssignment]), true), argumentsArray[1]]; 768 } 769 const callNode: ts.CallExpression = ts.factory.updateCallExpression( 770 // @ts-ignore 771 node.expression, node.expression.expression, node.expression.expression.typeArguments, 772 argumentsArray); 773 // @ts-ignore 774 node.expression.expression.parent = callNode; 775 // @ts-ignore 776 callNode.parent = node.expression.parent; 777 node = ts.factory.updateExpressionStatement(node, callNode); 778 return node; 779} 780 781type EtsComponentResult = { 782 etsComponentNode: ts.EtsComponentExpression; 783 hasAttr: boolean; 784}; 785function parseEtsComponentExpression(node: ts.ExpressionStatement): EtsComponentResult { 786 let etsComponentNode: ts.EtsComponentExpression; 787 let hasAttr: boolean = false; 788 let temp: any = node.expression; 789 while (temp) { 790 if (ts.isCallExpression(temp) && temp.expression && 791 ts.isPropertyAccessExpression(temp.expression)) { 792 hasAttr = true; 793 } 794 if (ts.isEtsComponentExpression(temp)) { 795 etsComponentNode = temp; 796 break; 797 } 798 temp = temp.expression; 799 } 800 return { etsComponentNode: etsComponentNode, hasAttr: hasAttr }; 801} 802 803export function createCollectElmtIdNode(): ts.ExpressionStatement { 804 return ts.factory.createExpressionStatement(ts.factory.createCallExpression( 805 ts.factory.createPropertyAccessExpression( 806 ts.factory.createIdentifier(MY_IDS), 807 ts.factory.createIdentifier(PUSH) 808 ), 809 undefined, 810 [ts.factory.createIdentifier(ELMTID)] 811 )); 812} 813 814function processInnerComponent(node: ts.ExpressionStatement, innerCompStatements: ts.Statement[], 815 log: LogInfo[], parent: string = undefined, isBuilder: boolean = false, isGlobalBuilder: boolean = false, 816 isTransition: boolean = false, idName: ts.Expression = undefined, savedParent: string = undefined, 817 builderParamsResult: BuilderParamsResult = null, isInRepeatTemplate: boolean = false): void { 818 const newStatements: ts.Statement[] = []; 819 const res: CreateResult = createComponent(node, COMPONENT_CREATE_FUNCTION); 820 newStatements.push(res.newNode); 821 const nameResult: NameResult = { name: null, arguments: [] }; 822 validateEtsComponentNode(node.expression as ts.EtsComponentExpression, nameResult); 823 if (savedParent && nameResult.name) { 824 checkNonspecificParents(node, nameResult.name, savedParent, log); 825 } 826 if (partialUpdateConfig.partialUpdateMode && ItemComponents.includes(nameResult.name)) { 827 processItemComponent(node, nameResult, innerCompStatements, log, parent, isGlobalBuilder, idName, builderParamsResult, isInRepeatTemplate); 828 } else if (partialUpdateConfig.partialUpdateMode && TabContentAndNavDestination.has(nameResult.name)) { 829 processTabAndNav(node, innerCompStatements, nameResult, log, parent, isGlobalBuilder, idName, builderParamsResult, isInRepeatTemplate); 830 } else { 831 processNormalComponent(node, nameResult, innerCompStatements, log, parent, isBuilder, isGlobalBuilder, 832 isTransition, idName, builderParamsResult, isInRepeatTemplate); 833 } 834} 835 836function processNormalComponent(node: ts.ExpressionStatement, nameResult: NameResult, 837 innerCompStatements: ts.Statement[], log: LogInfo[], parent: string = undefined, isBuilder: boolean = false, 838 isGlobalBuilder: boolean = false, isTransition: boolean = false, idName: ts.Expression = undefined, 839 builderParamsResult: BuilderParamsResult = null, isInRepeatTemplate: boolean = false): void { 840 const newStatements: ts.Statement[] = []; 841 if (addElmtIdNode()) { 842 newStatements.push(createCollectElmtIdNode()); 843 } 844 const immutableStatements: ts.Statement[] = []; 845 const res: CreateResult = createComponent(node, COMPONENT_CREATE_FUNCTION); 846 newStatements.push(res.newNode); 847 processDebug(node, nameResult, newStatements); 848 const etsComponentResult: EtsComponentResult = parseEtsComponentExpression(node); 849 const componentName: string = res.identifierNode.getText(); 850 let judgeIdStart: number; 851 if (partialUpdateConfig.partialUpdateMode && idName) { 852 judgeIdStart = innerCompStatements.length; 853 } 854 if (etsComponentResult.etsComponentNode.body && ts.isBlock(etsComponentResult.etsComponentNode.body)) { 855 if (res.isButton) { 856 checkButtonParamHasLabel(etsComponentResult.etsComponentNode, log); 857 if (projectConfig.isPreview || projectConfig.enableDebugLine) { 858 newStatements.splice(-2, 1, createComponent(node, COMPONENT_CREATE_CHILD_FUNCTION).newNode); 859 } else { 860 newStatements.splice(-1, 1, createComponent(node, COMPONENT_CREATE_CHILD_FUNCTION).newNode); 861 } 862 } 863 if (etsComponentResult.hasAttr) { 864 bindComponentAttr(node, res.identifierNode, newStatements, log, true, false, immutableStatements); 865 } 866 processInnerCompStatements(innerCompStatements, newStatements, node, isGlobalBuilder, 867 isTransition, undefined, immutableStatements, componentName, builderParamsResult); 868 storedFileInfo.lazyForEachInfo.isDependItem = false; 869 processComponentChild(etsComponentResult.etsComponentNode.body, innerCompStatements, log, 870 {isAcceleratePreview: false, line: 0, column: 0, fileName: ''}, isBuilder, parent, undefined, 871 isGlobalBuilder, false, builderParamsResult, isInRepeatTemplate); 872 } else { 873 bindComponentAttr(node, res.identifierNode, newStatements, log, true, false, immutableStatements); 874 processInnerCompStatements(innerCompStatements, newStatements, node, isGlobalBuilder, 875 isTransition, undefined, immutableStatements, componentName, builderParamsResult); 876 } 877 if (res.isContainerComponent || res.needPop) { 878 innerCompStatements.push(createComponent(node, COMPONENT_POP_FUNCTION).newNode); 879 } 880 if (partialUpdateConfig.partialUpdateMode && idName) { 881 innerCompStatements.splice(judgeIdStart, innerCompStatements.length - judgeIdStart, 882 ifRetakeId(innerCompStatements.slice(judgeIdStart), idName)); 883 } 884} 885 886export function ifRetakeId(blockContent: ts.Statement[], idName: ts.Expression): ts.IfStatement { 887 return ts.factory.createIfStatement( 888 ts.factory.createPrefixUnaryExpression( 889 ts.SyntaxKind.ExclamationToken, 890 ts.factory.createCallExpression( 891 ts.factory.createPropertyAccessExpression( 892 ts.factory.createIdentifier(COMPONENT_IF), 893 ts.factory.createIdentifier(CAN_RETAKE) 894 ), 895 undefined, 896 [idName] 897 ) 898 ), 899 ts.factory.createBlock( 900 blockContent, 901 true 902 ), 903 undefined 904 ); 905} 906 907function processRepeatComponent(node: ts.ExpressionStatement, innerCompStatements: ts.Statement[], 908 log: LogInfo[], isBuilder: boolean = false, isGlobalBuilder: boolean = false, 909 isTransition: boolean = false, builderParamsResult: BuilderParamsResult = null, 910 isInRepeatTemplate: boolean = false): void { 911 const chainCallTransform: ts.CallExpression = 912 recurseRepeatExpression(node.expression as ts.CallExpression, log, isBuilder, isGlobalBuilder, 913 isTransition, isInRepeatTemplate) as ts.CallExpression; 914 innerCompStatements.push(createComponentCreationStatement(node, 915 [ts.factory.createExpressionStatement(ts.factory.createCallExpression( 916 ts.factory.createPropertyAccessExpression( 917 chainCallTransform, 918 ts.factory.createIdentifier(COMPONENT_RENDER_FUNCTION) 919 ), 920 undefined, 921 [ts.factory.createIdentifier(ISINITIALRENDER)] 922 ))], COMPONENT_REPEAT, isGlobalBuilder, isTransition, undefined, null, builderParamsResult)); 923} 924 925function recurseRepeatExpression(node: ts.CallExpression | ts.PropertyAccessExpression, 926 log: LogInfo[], isBuilder: boolean = false, isGlobalBuilder: boolean = false, isTransition: boolean = false, isInRepeatTemplate: boolean = false): 927 ts.PropertyAccessExpression | ts.CallExpression { 928 if (ts.isCallExpression(node) && node.expression && ts.isIdentifier(node.expression) && 929 node.expression.getText() === COMPONENT_REPEAT) { 930 return ts.factory.createCallExpression(node.expression, node.typeArguments, [...node.arguments, ts.factory.createThis()]); 931 } else if (ts.isPropertyAccessExpression(node)) { 932 return ts.factory.updatePropertyAccessExpression(node, 933 recurseRepeatExpression(node.expression, log, isBuilder, isGlobalBuilder, isTransition, isInRepeatTemplate), node.name); 934 } else { 935 let repeatPropArgs: ts.ArrowFunction[] = processRepeatAttributeArrowNode(node.arguments); 936 storedFileInfo.processRepeat = true; 937 repeatPropArgs = processRepeatPropWithChild(node, repeatPropArgs, log, isBuilder, isGlobalBuilder, isTransition, isInRepeatTemplate); 938 storedFileInfo.processRepeat = false; 939 return ts.factory.updateCallExpression(node, 940 recurseRepeatExpression(node.expression as ts.PropertyAccessExpression, log, isBuilder, 941 isGlobalBuilder, isTransition, isInRepeatTemplate) as ts.PropertyAccessExpression, undefined, repeatPropArgs); 942 } 943} 944 945function processRepeatPropWithChild(node: ts.CallExpression, repeatPropArgs: ts.ArrowFunction[], 946 log: LogInfo[], isBuilder: boolean = false, isGlobalBuilder: boolean = false, isTransition: boolean = false, 947 isInRepeatTemplate: boolean = false): ts.ArrowFunction[] { 948 if (ts.isPropertyAccessExpression(node.expression) && ts.isIdentifier(node.expression.name) && 949 node.expression.name.getText() === REPEAT_EACH && repeatPropArgs.length > 0 && repeatPropArgs[0].body) { 950 // transfer args for each property 951 return [ 952 ts.factory.updateArrowFunction(repeatPropArgs[0], repeatPropArgs[0].modifiers, repeatPropArgs[0].typeParameters, 953 repeatPropArgs[0].parameters, repeatPropArgs[0].type, repeatPropArgs[0].equalsGreaterThanToken, 954 processComponentBlock(processRepeatCallBackBlock(repeatPropArgs[0]), false, log, isTransition, 955 isBuilder, undefined, undefined, isGlobalBuilder, null, false, isInRepeatTemplate)), 956 ...repeatPropArgs.slice(1) 957 ]; 958 } else if (ts.isPropertyAccessExpression(node.expression) && ts.isIdentifier(node.expression.name) && 959 node.expression.name.getText() === REPEAT_TEMPLATE && repeatPropArgs.length > 1 && repeatPropArgs[1].body) { 960 // transfer args for template property 961 return [ 962 repeatPropArgs[0], ts.factory.updateArrowFunction(repeatPropArgs[1], repeatPropArgs[1].modifiers, repeatPropArgs[1].typeParameters, 963 repeatPropArgs[1].parameters, repeatPropArgs[1].type, repeatPropArgs[1].equalsGreaterThanToken, 964 processComponentBlock(processRepeatCallBackBlock(repeatPropArgs[1]), false, log, isTransition, isBuilder, undefined, undefined, 965 isGlobalBuilder, null, false, true)), 966 ...repeatPropArgs.slice(2) 967 ]; 968 } 969 return repeatPropArgs; 970} 971 972function processRepeatCallBackBlock(repeatPropArg: ts.ArrowFunction): ts.Block { 973 if (ts.isBlock(repeatPropArg.body)) { 974 return repeatPropArg.body; 975 } else { 976 return ts.factory.updateArrowFunction(repeatPropArg, ts.getModifiers(repeatPropArg), repeatPropArg.typeParameters, 977 repeatPropArg.parameters, repeatPropArg.type, repeatPropArg.equalsGreaterThanToken, 978 ts.factory.createBlock([ts.factory.createExpressionStatement(repeatPropArg.body)], true)).body as ts.Block; 979 } 980} 981 982function processRepeatAttributeArrowNode(argumentsNode: ts.ArrowFunction[]): ts.ArrowFunction[] { 983 for (let i = 0; i < argumentsNode.length; i++) { 984 while (ts.isParenthesizedExpression(argumentsNode[i])) { 985 if (ts.isArrowFunction(argumentsNode[i].expression)) { 986 argumentsNode.splice(i, 1, argumentsNode[i].expression); 987 break; 988 } else { 989 if (argumentsNode[i].expression) { 990 argumentsNode[i] = argumentsNode[i].expression; 991 } else { 992 break; 993 } 994 } 995 } 996 } 997 return argumentsNode; 998} 999 1000function processDebug(node: ts.Statement, nameResult: NameResult, newStatements: ts.Statement[], 1001 getNode: boolean = false): ts.ExpressionStatement { 1002 if ((projectConfig.isPreview || projectConfig.enableDebugLine) && nameResult.name && 1003 !NO_DEBUG_LINE_COMPONENT.has(nameResult.name)) { 1004 let posOfNode: ts.LineAndCharacter; 1005 let curFileName: string; 1006 let line: number = 1; 1007 let col: number = 1; 1008 if (sourceNode && newsupplement.isAcceleratePreview) { 1009 posOfNode = sourceNode.getLineAndCharacterOfPosition(getRealNodePos(node) - 22); 1010 curFileName = newsupplement.fileName; 1011 if (posOfNode.line === 0) { 1012 col = newsupplement.column - 1; 1013 } 1014 line = newsupplement.line; 1015 } else { 1016 posOfNode = transformLog.sourceFile.getLineAndCharacterOfPosition(getRealNodePos(node)); 1017 curFileName = transformLog.sourceFile.fileName.replace(/\.ts$/, ''); 1018 } 1019 let debugInfo: string; 1020 if (projectConfig.isPreview) { 1021 if (projectConfig.minAPIVersion >= 11) { 1022 debugInfo = `${path.relative(projectConfig.projectRootPath, curFileName).replace(/\\+/g, '/')}` + 1023 `(${posOfNode.line + line}:${posOfNode.character + col})`; 1024 } else { 1025 debugInfo = `${path.relative(projectConfig.projectPath, curFileName).replace(/\\+/g, '/')}` + 1026 `(${posOfNode.line + line}:${posOfNode.character + col})`; 1027 } 1028 } else if (projectConfig.enableDebugLine) { 1029 debugInfo = `${path.relative(projectConfig.projectRootPath, curFileName)}` + 1030 `(${posOfNode.line + line}:${posOfNode.character + col})`; 1031 } 1032 const debugNode: ts.ExpressionStatement = ts.factory.createExpressionStatement( 1033 createFunction(ts.factory.createIdentifier(nameResult.name), 1034 ts.factory.createIdentifier(COMPONENT_DEBUGLINE_FUNCTION), 1035 createDebugLineArgs(debugInfo))); 1036 if (getNode) { 1037 return debugNode; 1038 } 1039 newStatements.push(debugNode); 1040 } 1041 return undefined; 1042} 1043 1044function createDebugLineArgs(debugInfo: string): ts.NodeArray { 1045 const argsArr: ts.Node[] = [ts.factory.createStringLiteral(debugInfo)]; 1046 const pkgName: string = storedFileInfo.getCurrentArkTsFile().pkgName; 1047 if (pkgName) { 1048 argsArr.push(ts.factory.createStringLiteral(pkgName)); 1049 } 1050 return ts.factory.createNodeArray(argsArr); 1051} 1052 1053function processInnerCompStatements(innerCompStatements: ts.Statement[], 1054 newStatements: ts.Statement[], node: ts.Statement, isGlobalBuilder: boolean, isTransition: boolean, 1055 nameResult: NameResult, immutableStatements: ts.Statement[], componentName: string, 1056 builderParamsResult: BuilderParamsResult): void { 1057 if (!partialUpdateConfig.partialUpdateMode) { 1058 innerCompStatements.push(...newStatements); 1059 } else { 1060 innerCompStatements.push(createComponentCreationStatement(node, newStatements, componentName, 1061 isGlobalBuilder, isTransition, nameResult, immutableStatements, builderParamsResult)); 1062 } 1063} 1064 1065function createComponentCreationArrowParams(isGlobalBuilder: boolean, 1066 builderParamsResult: BuilderParamsResult, isRecycleComponent: boolean = false): ts.ParameterDeclaration[] { 1067 const arrowNodes: ts.ParameterDeclaration[] = [ 1068 ts.factory.createParameterDeclaration(undefined, undefined, 1069 ts.factory.createIdentifier(ELMTID), undefined, undefined, undefined), 1070 ts.factory.createParameterDeclaration(undefined, undefined, 1071 ts.factory.createIdentifier(ISINITIALRENDER), undefined, undefined, undefined) 1072 ]; 1073 if (!isRecycleComponent && partialUpdateConfig.optimizeComponent && isGlobalBuilder && 1074 builderParamsResult && builderParamsResult.firstParam) { 1075 const paramName: ts.Identifier = builderParamsResult.firstParam.name as ts.Identifier; 1076 arrowNodes.push(ts.factory.createParameterDeclaration(undefined, undefined, 1077 paramName, undefined, undefined, ts.factory.createIdentifier(`__${paramName.escapedText.toString()}__`) 1078 )); 1079 } 1080 return arrowNodes; 1081} 1082 1083export function createComponentCreationStatement(node: ts.Statement, innerStatements: ts.Statement[], 1084 componentName: string, isGlobalBuilder: boolean = false, isTransition: boolean = false, 1085 nameResult: NameResult = undefined, immutableStatements: ts.Statement[] = null, 1086 builderParamsResult: BuilderParamsResult = null, isRecycleComponent: boolean = false): ts.Statement { 1087 const blockArr: ts.Statement[] = [...innerStatements]; 1088 if (nameResult) { 1089 blockArr.push(processDebug(node, nameResult, innerStatements, true)); 1090 } 1091 if (!isTransition) { 1092 createInitRenderStatement(node, immutableStatements, blockArr); 1093 } 1094 if (!partialUpdateConfig.optimizeComponent) { 1095 blockArr.unshift(createViewStackProcessorStatement(STARTGETACCESSRECORDINGFOR, ELMTID)); 1096 blockArr.push(createViewStackProcessorStatement(STOPGETACCESSRECORDING)); 1097 } 1098 const creationArgs: ts.Expression[] = [ 1099 ts.factory.createArrowFunction(undefined, undefined, 1100 createComponentCreationArrowParams(isGlobalBuilder, builderParamsResult, isRecycleComponent), 1101 undefined, ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), 1102 ts.factory.createBlock(blockArr, true) 1103 ) 1104 ]; 1105 if (partialUpdateConfig.optimizeComponent) { 1106 creationArgs.push(isTransition ? ts.factory.createNull() : 1107 ts.factory.createIdentifier(componentName)); 1108 } 1109 return ts.factory.createExpressionStatement( 1110 ts.factory.createCallExpression( 1111 ts.factory.createPropertyAccessExpression(createConditionParent(isGlobalBuilder), 1112 ts.factory.createIdentifier(partialUpdateConfig.optimizeComponent ? 1113 OBSERVECOMPONENTCREATION2 : OBSERVECOMPONENTCREATION) 1114 ), undefined, creationArgs) 1115 ); 1116} 1117 1118export function createViewStackProcessorStatement(propertyAccessName: string, elmtId?: string): ts.Statement { 1119 return ts.factory.createExpressionStatement( 1120 ts.factory.createCallExpression( 1121 ts.factory.createPropertyAccessExpression( 1122 ts.factory.createIdentifier(VIEWSTACKPROCESSOR), 1123 ts.factory.createIdentifier(propertyAccessName) 1124 ), 1125 undefined, 1126 elmtId ? [ts.factory.createIdentifier(ELMTID)] : [] 1127 ) 1128 ); 1129} 1130 1131function createInitRenderStatement(node: ts.Statement, 1132 immutableStatements: ts.Statement[], blockArr: ts.Statement[]): void { 1133 if (partialUpdateConfig.optimizeComponent) { 1134 if (immutableStatements && immutableStatements.length) { 1135 blockArr.push(ts.factory.createIfStatement( 1136 ts.factory.createIdentifier(ISINITIALRENDER), 1137 ts.factory.createBlock(immutableStatements, true) 1138 )); 1139 } 1140 } else { 1141 blockArr.push(ts.factory.createIfStatement( 1142 ts.factory.createPrefixUnaryExpression( 1143 ts.SyntaxKind.ExclamationToken, 1144 ts.factory.createIdentifier(ISINITIALRENDER) 1145 ), 1146 ts.factory.createBlock( 1147 [ 1148 ts.isExpressionStatement(node) ? 1149 createComponent(node, COMPONENT_POP_FUNCTION).newNode : createIfPop() 1150 ], 1151 true 1152 ), 1153 immutableStatements && immutableStatements.length ? 1154 ts.factory.createBlock(immutableStatements, true) : undefined 1155 )); 1156 } 1157} 1158 1159function processItemComponent(node: ts.ExpressionStatement, nameResult: NameResult, innerCompStatements: ts.Statement[], 1160 log: LogInfo[], parent: string = undefined, isGlobalBuilder: boolean = false, idName: ts.Expression = undefined, 1161 builderParamsResult: BuilderParamsResult = null, isInRepeatTemplate: boolean = false): void { 1162 const itemRenderInnerStatements: ts.Statement[] = []; 1163 const immutableStatements: ts.Statement[] = []; 1164 const deepItemRenderInnerStatements: ts.Statement[] = []; 1165 if (addElmtIdNode()) { 1166 itemRenderInnerStatements.push(createCollectElmtIdNode()); 1167 } 1168 const res: CreateResult = createComponent(node, COMPONENT_CREATE_FUNCTION); 1169 const isLazyCreate: boolean = checkLazyCreate(node, nameResult); 1170 const itemCreateStatement: ts.Statement = createItemCreate(nameResult, isLazyCreate); 1171 itemRenderInnerStatements.push(itemCreateStatement); 1172 const etsComponentResult: EtsComponentResult = parseEtsComponentExpression(node); 1173 if (etsComponentResult.etsComponentNode.body && ts.isBlock(etsComponentResult.etsComponentNode.body)) { 1174 if (etsComponentResult.hasAttr) { 1175 bindComponentAttr(node, res.identifierNode, itemRenderInnerStatements, log, true, false, immutableStatements); 1176 } 1177 storedFileInfo.lazyForEachInfo.isDependItem = false; 1178 processComponentChild(etsComponentResult.etsComponentNode.body, deepItemRenderInnerStatements, log, 1179 {isAcceleratePreview: false, line: 0, column: 0, fileName: ''}, false, parent, undefined, isGlobalBuilder, false, 1180 builderParamsResult, isInRepeatTemplate); 1181 } else { 1182 bindComponentAttr(node, res.identifierNode, itemRenderInnerStatements, log, true, false, immutableStatements); 1183 } 1184 let generateItem: ts.IfStatement | ts.Block; 1185 if (idName) { 1186 generateItem = ifRetakeId([createItemBlock( 1187 node, itemRenderInnerStatements, deepItemRenderInnerStatements, nameResult, isLazyCreate, 1188 immutableStatements, isGlobalBuilder, builderParamsResult)], idName); 1189 } else { 1190 generateItem = createItemBlock( 1191 node, itemRenderInnerStatements, deepItemRenderInnerStatements, nameResult, isLazyCreate, 1192 immutableStatements, isGlobalBuilder, builderParamsResult); 1193 } 1194 innerCompStatements.push(generateItem); 1195} 1196 1197function createItemCreate(nameResult: NameResult, isLazyCreate: boolean): ts.Statement { 1198 const itemCreateArgs: ts.Expression[] = []; 1199 if (isLazyCreate) { 1200 itemCreateArgs.push(ts.factory.createIdentifier(DEEPRENDERFUNCTION), ts.factory.createTrue()); 1201 } else { 1202 itemCreateArgs.push( 1203 ts.factory.createArrowFunction(undefined, undefined, [], undefined, 1204 ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), 1205 ts.factory.createBlock([], false)), 1206 ts.factory.createFalse() 1207 ); 1208 } 1209 itemCreateArgs.push(...nameResult.arguments); 1210 return ts.factory.createExpressionStatement(ts.factory.createCallExpression( 1211 ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(nameResult.name), 1212 ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION)), undefined, itemCreateArgs)); 1213} 1214 1215type ItemCreation = { 1216 creationArgs: ts.Expression[], 1217 creationName: string, 1218}; 1219 1220function getItemCreation(nameResult: NameResult): ItemCreation { 1221 const creationArgs: ts.Expression[] = []; 1222 let creationName: string = OBSERVECOMPONENTCREATION; 1223 if (partialUpdateConfig.optimizeComponent) { 1224 creationArgs.push( 1225 ts.factory.createIdentifier(ITEMCREATION2), 1226 ts.factory.createIdentifier(nameResult.name)); 1227 creationName = OBSERVECOMPONENTCREATION2; 1228 } else { 1229 creationArgs.push(ts.factory.createIdentifier(ITEMCREATION)); 1230 } 1231 return { creationArgs, creationName }; 1232} 1233 1234function createItemBlock( 1235 node: ts.ExpressionStatement, 1236 itemRenderInnerStatements: ts.Statement[], 1237 deepItemRenderInnerStatements: ts.Statement[], 1238 nameResult: NameResult, isLazyCreate: boolean, 1239 immutableStatements: ts.Statement[], 1240 isGlobalBuilder: boolean, 1241 builderParamsResult: BuilderParamsResult 1242): ts.Block { 1243 const blockNode: ts.Statement[] = [ 1244 createItemCreation2(node, itemRenderInnerStatements, nameResult, immutableStatements, 1245 isGlobalBuilder, builderParamsResult) 1246 ]; 1247 const itemCreation: ItemCreation = getItemCreation(nameResult); 1248 if (isLazyCreate) { 1249 blockNode.unshift(createItemCreation(node, isGlobalBuilder, builderParamsResult)); 1250 blockNode.push( 1251 createDeepRenderFunction(node, deepItemRenderInnerStatements, isGlobalBuilder, builderParamsResult), 1252 ts.factory.createExpressionStatement(ts.factory.createCallExpression( 1253 ts.factory.createPropertyAccessExpression( 1254 ts.factory.createThis(), 1255 ts.factory.createIdentifier(itemCreation.creationName) 1256 ), undefined, itemCreation.creationArgs 1257 )), 1258 createComponent(node, COMPONENT_POP_FUNCTION).newNode 1259 ); 1260 } else { 1261 if (!partialUpdateConfig.optimizeComponent) { 1262 blockNode.unshift(createItemCreation(node, isGlobalBuilder, builderParamsResult)); 1263 } 1264 blockNode.push( 1265 createObservedDeepRender(node, deepItemRenderInnerStatements, itemCreation), 1266 ts.factory.createExpressionStatement(ts.factory.createCallExpression( 1267 ts.factory.createIdentifier(OBSERVEDDEEPRENDER), undefined, [])) 1268 ); 1269 } 1270 return ts.factory.createBlock(blockNode, true); 1271} 1272 1273function checkLazyCreate(node: ts.ExpressionStatement, nameResult: NameResult): boolean { 1274 if (nameResult.name === LIST_ITEM) { 1275 if (nameResult.arguments.length && ts.isStringLiteral(nameResult.arguments[0]) && 1276 nameResult.arguments[0].text === 'false') { 1277 return false; 1278 } 1279 if (storedFileInfo.processRepeat) { 1280 return false; 1281 } 1282 if (isLazyForEachChild(node)) { 1283 return false; 1284 } 1285 return true; 1286 } 1287 return false; 1288} 1289 1290function createItemCreation(node: ts.ExpressionStatement, isGlobalBuilder: boolean, 1291 builderParamsResult: BuilderParamsResult): ts.VariableStatement { 1292 return ts.factory.createVariableStatement( 1293 undefined, 1294 ts.factory.createVariableDeclarationList( 1295 [ts.factory.createVariableDeclaration( 1296 ts.factory.createIdentifier(ITEMCREATION), undefined, undefined, 1297 ts.factory.createArrowFunction(undefined, undefined, 1298 createComponentCreationArrowParams(isGlobalBuilder, builderParamsResult), undefined, 1299 ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), 1300 ts.factory.createBlock( 1301 [ 1302 createViewStackProcessorStatement(STARTGETACCESSRECORDINGFOR, ELMTID), 1303 ts.factory.createExpressionStatement(ts.factory.createCallExpression( 1304 ts.factory.createIdentifier(ITEMCREATION2), 1305 undefined, createItemCreationArgs(isGlobalBuilder, builderParamsResult) 1306 )), 1307 ts.factory.createIfStatement( 1308 ts.factory.createPrefixUnaryExpression( 1309 ts.SyntaxKind.ExclamationToken, 1310 ts.factory.createIdentifier(ISINITIALRENDER) 1311 ), 1312 ts.factory.createBlock( 1313 [createComponent(node, COMPONENT_POP_FUNCTION).newNode], 1314 true 1315 ) 1316 ), 1317 createViewStackProcessorStatement(STOPGETACCESSRECORDING) 1318 ], 1319 true 1320 ) 1321 ) 1322 )], 1323 ts.NodeFlags.Const 1324 ) 1325 ); 1326} 1327 1328function createItemCreation2( 1329 node: ts.ExpressionStatement, 1330 itemRenderInnerStatements: ts.Statement[], 1331 nameResult: NameResult, 1332 immutableStatements: ts.Statement[], 1333 isGlobalBuilder: boolean, 1334 builderParamsResult: BuilderParamsResult 1335): ts.VariableStatement { 1336 const itemBlock: ts.Statement[] = [ 1337 ...itemRenderInnerStatements, 1338 processDebug(node, nameResult, itemRenderInnerStatements, true) 1339 ]; 1340 if (immutableStatements && immutableStatements.length) { 1341 itemBlock.push(ts.factory.createIfStatement( 1342 ts.factory.createIdentifier(ISINITIALRENDER), 1343 ts.factory.createBlock(immutableStatements, true) 1344 )); 1345 } 1346 return ts.factory.createVariableStatement( 1347 undefined, 1348 ts.factory.createVariableDeclarationList( 1349 [ts.factory.createVariableDeclaration( 1350 ts.factory.createIdentifier(ITEMCREATION2), undefined, undefined, 1351 ts.factory.createArrowFunction(undefined, undefined, 1352 createComponentCreationArrowParams(isGlobalBuilder, builderParamsResult), undefined, 1353 ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), 1354 ts.factory.createBlock(itemBlock, true) 1355 ) 1356 )], 1357 ts.NodeFlags.Const 1358 ) 1359 ); 1360} 1361 1362function createItemCreationArgs(isGlobalBuilder: boolean, 1363 builderParamsResult: BuilderParamsResult): ts.Expression[] { 1364 const itemCreationArgs: ts.Expression[] = [ 1365 ts.factory.createIdentifier(ELMTID), ts.factory.createIdentifier(ISINITIALRENDER)]; 1366 if (partialUpdateConfig.optimizeComponent && isGlobalBuilder && builderParamsResult && 1367 builderParamsResult.firstParam) { 1368 itemCreationArgs.push(builderParamsResult.firstParam.name as ts.Identifier); 1369 } 1370 return itemCreationArgs; 1371} 1372 1373function createDeepRenderFunction( 1374 node: ts.ExpressionStatement, 1375 deepItemRenderInnerStatements: ts.Statement[], 1376 isGlobalBuilder: boolean, 1377 builderParamsResult: BuilderParamsResult 1378): ts.VariableStatement { 1379 const blockNode: ts.Statement[] = [ 1380 ts.factory.createExpressionStatement(ts.factory.createCallExpression( 1381 ts.factory.createIdentifier(ITEMCREATION), undefined, 1382 createItemCreationArgs(isGlobalBuilder, builderParamsResult) 1383 )), 1384 ts.factory.createExpressionStatement(ts.factory.createCallExpression( 1385 ts.factory.createPropertyAccessExpression( 1386 ts.factory.createPropertyAccessExpression( 1387 ts.factory.createThis(), 1388 ts.factory.createIdentifier(UPDATE_FUNC_BY_ELMT_ID) 1389 ), 1390 ts.factory.createIdentifier(CREATE_SET_METHOD) 1391 ), undefined, 1392 [ts.factory.createIdentifier(ELMTID), ts.factory.createIdentifier(ITEMCREATION)] 1393 )), 1394 ...deepItemRenderInnerStatements, 1395 createComponent(node, COMPONENT_POP_FUNCTION).newNode 1396 ]; 1397 if (partialUpdateConfig.optimizeComponent) { 1398 blockNode.splice(1, 1); 1399 } 1400 return ts.factory.createVariableStatement( 1401 undefined, 1402 ts.factory.createVariableDeclarationList( 1403 [ts.factory.createVariableDeclaration( 1404 ts.factory.createIdentifier(DEEPRENDERFUNCTION), undefined, undefined, 1405 ts.factory.createArrowFunction(undefined, undefined, 1406 createComponentCreationArrowParams(isGlobalBuilder, builderParamsResult), undefined, 1407 ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), 1408 ts.factory.createBlock(blockNode, true) 1409 ) 1410 )], 1411 ts.NodeFlags.Const 1412 ) 1413 ); 1414} 1415 1416function createObservedDeepRender( 1417 node: ts.ExpressionStatement, 1418 deepItemRenderInnerStatements: ts.Statement[], 1419 itemCreation: ItemCreation 1420): ts.VariableStatement { 1421 return ts.factory.createVariableStatement( 1422 undefined, 1423 ts.factory.createVariableDeclarationList( 1424 [ts.factory.createVariableDeclaration( 1425 ts.factory.createIdentifier(OBSERVEDDEEPRENDER), 1426 undefined, 1427 undefined, 1428 ts.factory.createArrowFunction( 1429 undefined, 1430 undefined, 1431 [], 1432 undefined, 1433 ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), 1434 ts.factory.createBlock( 1435 [ 1436 ts.factory.createExpressionStatement(ts.factory.createCallExpression( 1437 ts.factory.createPropertyAccessExpression( 1438 ts.factory.createThis(), 1439 ts.factory.createIdentifier(itemCreation.creationName) 1440 ), undefined, itemCreation.creationArgs 1441 )), 1442 ...deepItemRenderInnerStatements, 1443 createComponent(node, COMPONENT_POP_FUNCTION).newNode 1444 ], 1445 true 1446 ) 1447 ) 1448 )], 1449 ts.NodeFlags.Const 1450 ) 1451 ); 1452} 1453 1454function processTabAndNav(node: ts.ExpressionStatement, innerCompStatements: ts.Statement[], 1455 nameResult: NameResult, log: LogInfo[], parent: string = undefined, isGlobalBuilder: boolean = false, 1456 idName: ts.Expression = undefined, builderParamsResult: BuilderParamsResult = null, 1457 isInRepeatTemplate: boolean = false): void { 1458 const name: string = nameResult.name; 1459 const tabContentComp: ts.EtsComponentExpression = getEtsComponentExpression(node); 1460 const tabContentBody: ts.Block = tabContentComp.body; 1461 let tabContentCreation: ts.Statement; 1462 const tabContentPop: ts.Statement = ts.factory.createExpressionStatement(ts.factory.createCallExpression( 1463 ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(name), 1464 ts.factory.createIdentifier(COMPONENT_POP_FUNCTION)), undefined, [])); 1465 const tabAttrs: ts.Statement[] = []; 1466 if (addElmtIdNode()) { 1467 tabAttrs.push(createCollectElmtIdNode()); 1468 } 1469 const immutableStatements: ts.Statement[] = []; 1470 let judgeIdStart: number; 1471 if (idName) { 1472 judgeIdStart = innerCompStatements.length; 1473 } 1474 if (tabContentBody && tabContentBody.statements.length) { 1475 const newTabContentChildren: ts.Statement[] = []; 1476 processComponentChild(tabContentBody, newTabContentChildren, log, {isAcceleratePreview: false, line: 0, column: 0, fileName: ''}, 1477 false, parent, undefined, isGlobalBuilder, false, builderParamsResult, isInRepeatTemplate); 1478 const navDestinationCallback: (ts.ArrowFunction | ts.NewExpression | ts.ObjectLiteralExpression)[] = 1479 [ts.factory.createArrowFunction(undefined, undefined, [], undefined, 1480 ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), 1481 ts.factory.createBlock([...newTabContentChildren], true))]; 1482 if (name === NAV_DESTINATION) { 1483 navDestinationCallback.push(...navigationCreateParam(NAV_DESTINATION, COMPONENT_CREATE_FUNCTION, undefined, true)); 1484 } 1485 tabContentCreation = ts.factory.createExpressionStatement( 1486 ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression( 1487 ts.factory.createIdentifier(name), ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION)), 1488 undefined, navDestinationCallback)); 1489 bindComponentAttr(node, ts.factory.createIdentifier(name), tabAttrs, log, true, false, immutableStatements); 1490 processInnerCompStatements( 1491 innerCompStatements, [tabContentCreation, ...tabAttrs], node, isGlobalBuilder, false, 1492 nameResult, immutableStatements, name, builderParamsResult); 1493 storedFileInfo.lazyForEachInfo.isDependItem = false; 1494 } else { 1495 tabContentCreation = ts.factory.createExpressionStatement(ts.factory.createCallExpression( 1496 ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(name), 1497 ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION)), undefined, 1498 name === NAV_DESTINATION ? navigationCreateParam(NAV_DESTINATION, COMPONENT_CREATE_FUNCTION) : [])); 1499 bindComponentAttr(node, ts.factory.createIdentifier(name), tabAttrs, log, true, false, immutableStatements); 1500 processInnerCompStatements( 1501 innerCompStatements, [tabContentCreation, ...tabAttrs], node, isGlobalBuilder, false, 1502 nameResult, immutableStatements, name, builderParamsResult); 1503 } 1504 innerCompStatements.push(tabContentPop); 1505 if (idName) { 1506 innerCompStatements.splice(judgeIdStart, innerCompStatements.length - judgeIdStart, 1507 ifRetakeId(innerCompStatements.slice(judgeIdStart), idName)); 1508 } 1509} 1510 1511export function getRealNodePos(node: ts.Node): number { 1512 // @ts-ignore 1513 if (node.pos === -1 && node.expression) { 1514 // @ts-ignore 1515 return getRealNodePos(node.expression); 1516 } else { 1517 return node.getStart(); 1518 } 1519} 1520 1521function processForEachComponent(node: ts.ExpressionStatement, newStatements: ts.Statement[], 1522 log: LogInfo[], isBuilder: boolean = false, isGlobalBuilder: boolean = false): void { 1523 const popNode: ts.ExpressionStatement = ts.factory.createExpressionStatement(createFunction( 1524 // @ts-ignore 1525 node.expression.expression as ts.Identifier, 1526 ts.factory.createIdentifier(COMPONENT_POP_FUNCTION), null)); 1527 if (ts.isCallExpression(node.expression)) { 1528 const propertyNode: ts.PropertyAccessExpression = ts.factory.createPropertyAccessExpression( 1529 node.expression.expression as ts.Identifier, 1530 ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION) 1531 ); 1532 const argumentsArray: ts.Expression[] = Array.from(node.expression.arguments); 1533 let arrayObserveredObject: ts.CallExpression; 1534 if (argumentsArray.length) { 1535 arrayObserveredObject = ts.factory.createCallExpression( 1536 ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(FOREACH_OBSERVED_OBJECT), 1537 ts.factory.createIdentifier(FOREACH_GET_RAW_OBJECT)), undefined, [argumentsArray[0]]); 1538 } 1539 argumentsArray.splice(0, 1, arrayObserveredObject); 1540 const newForEachArrowFunc: ts.ArrowFunction = processForEachFunctionBlock(node.expression); 1541 const newArrowNode: ts.ArrowFunction = 1542 processForEachBlock(node.expression, log, newForEachArrowFunc, isBuilder) as ts.ArrowFunction; 1543 if (newArrowNode) { 1544 argumentsArray.splice(1, 1, newArrowNode); 1545 } 1546 node = addForEachId(ts.factory.updateExpressionStatement(node, ts.factory.updateCallExpression( 1547 node.expression, propertyNode, node.expression.typeArguments, argumentsArray)), isGlobalBuilder); 1548 } 1549 newStatements.push(node, popNode); 1550} 1551 1552function collectForEachAttribute(node: ts.ExpressionStatement, 1553 attributeList: ts.ExpressionStatement[], name: string): ts.ExpressionStatement { 1554 let tempNode = node.expression; 1555 while (tempNode && ts.isCallExpression(tempNode)) { 1556 if (tempNode.expression && ts.isPropertyAccessExpression(tempNode.expression)) { 1557 attributeList.unshift(generateForEachAttribute(tempNode, name)); 1558 } else if (tempNode.expression && ts.isIdentifier(tempNode.expression)) { 1559 return ts.factory.updateExpressionStatement(node, tempNode); 1560 } 1561 tempNode = tempNode.expression?.expression; 1562 } 1563 return node; 1564} 1565 1566function generateForEachAttribute(tempNode: ts.CallExpression, name: string): ts.ExpressionStatement { 1567 return ts.factory.createExpressionStatement(ts.factory.createCallExpression( 1568 ts.factory.createPropertyAccessExpression( 1569 ts.factory.createIdentifier(name), 1570 tempNode.expression.name 1571 ), 1572 undefined, 1573 tempNode.arguments 1574 )); 1575} 1576 1577function processForEachComponentNew(node: ts.ExpressionStatement, newStatements: ts.Statement[], 1578 log: LogInfo[], name: string, isGlobalBuilder: boolean = false, builderParamsResult: BuilderParamsResult = null, 1579 isInRepeatTemplate: boolean = false): void { 1580 const attributeList: ts.ExpressionStatement[] = []; 1581 const newNode = collectForEachAttribute(node, attributeList, name); 1582 const newForEachStatements: ts.Statement[] = []; 1583 const popNode: ts.ExpressionStatement = ts.factory.createExpressionStatement(createFunction( 1584 (newNode.expression as ts.CallExpression).expression as ts.Identifier, 1585 ts.factory.createIdentifier(COMPONENT_POP_FUNCTION), null)); 1586 if (ts.isCallExpression(newNode.expression)) { 1587 if (checkForEachComponent(newNode)) { 1588 storedFileInfo.processForEach += 1; 1589 } else { 1590 storedFileInfo.processLazyForEach += 1; 1591 } 1592 const argumentsArray: ts.Expression[] = Array.from(newNode.expression.arguments); 1593 const propertyNode: ts.ExpressionStatement = ts.factory.createExpressionStatement( 1594 ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression( 1595 newNode.expression.expression as ts.Identifier, 1596 ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION)), undefined, [])); 1597 const newForEachArrowFunc: ts.ArrowFunction = processForEachFunctionBlock(newNode.expression); 1598 const newArrowNode: ts.NodeArray<ts.Statement> = 1599 processForEachBlock(newNode.expression, log, newForEachArrowFunc, false, isGlobalBuilder, 1600 builderParamsResult, isInRepeatTemplate) as ts.NodeArray<ts.Statement>; 1601 const itemGenFunctionStatement: ts.VariableStatement = createItemGenFunctionStatement(newNode.expression, newArrowNode, newForEachArrowFunc); 1602 const itemIdFuncStatement: ts.VariableStatement = createItemIdFuncStatement(newNode.expression, argumentsArray); 1603 const updateFunctionStatement: ts.ExpressionStatement = createUpdateFunctionStatement(argumentsArray, newForEachArrowFunc, isGlobalBuilder); 1604 const lazyForEachStatement: ts.ExpressionStatement = createLazyForEachStatement(argumentsArray); 1605 if (newNode.expression.expression.getText() === COMPONENT_FOREACH) { 1606 newForEachStatements.push(propertyNode, ...attributeList, itemGenFunctionStatement, updateFunctionStatement); 1607 newStatements.push(createComponentCreationStatement(newNode, newForEachStatements, COMPONENT_FOREACH, 1608 isGlobalBuilder, false, undefined, null, builderParamsResult), popNode); 1609 } else { 1610 if (argumentsArray[2]) { 1611 newStatements.push(ts.factory.createBlock([itemGenFunctionStatement, itemIdFuncStatement, lazyForEachStatement, 1612 ...attributeList, popNode], true)); 1613 } else { 1614 newStatements.push(ts.factory.createBlock([itemGenFunctionStatement, lazyForEachStatement, popNode, ...attributeList], true)); 1615 } 1616 } 1617 if (checkForEachComponent(newNode)) { 1618 storedFileInfo.processForEach -= 1; 1619 } else { 1620 storedFileInfo.processLazyForEach -= 1; 1621 } 1622 } 1623} 1624 1625function checkForEachComponent(node: ts.ExpressionStatement): boolean { 1626 return node.expression.expression && ts.isIdentifier(node.expression.expression) && 1627 node.expression.expression.getText() === COMPONENT_FOREACH; 1628} 1629 1630function createItemGenFunctionStatement( 1631 node: ts.CallExpression, 1632 newArrowNode: ts.NodeArray<ts.Statement>, 1633 newForEachArrowFunc: ts.ArrowFunction 1634): ts.VariableStatement { 1635 if (newForEachArrowFunc && ts.isArrowFunction(newForEachArrowFunc)) { 1636 return ts.factory.createVariableStatement( 1637 undefined, 1638 ts.factory.createVariableDeclarationList( 1639 [ts.factory.createVariableDeclaration( 1640 ts.factory.createIdentifier(node.expression.getText() === COMPONENT_FOREACH ? 1641 FOREACHITEMGENFUNCTION : __LAZYFOREACHITEMGENFUNCTION), 1642 undefined, undefined, 1643 ts.factory.createArrowFunction( 1644 undefined, undefined, 1645 newForEachArrowFunc.parameters && newForEachArrowFunc.parameters.length >= 1 ? 1646 getParameters(newForEachArrowFunc) : [], 1647 undefined, ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), 1648 ts.factory.createBlock( 1649 newForEachArrowFunc.parameters && newForEachArrowFunc.parameters.length >= 1 ? 1650 isForEachItemGeneratorParam(newForEachArrowFunc, newArrowNode) : 1651 newArrowNode ? [...newArrowNode] : undefined, 1652 true 1653 ) 1654 ) 1655 ) 1656 ], 1657 ts.NodeFlags.Const 1658 ) 1659 ); 1660 } 1661 return undefined; 1662} 1663 1664function isForEachItemGeneratorParam(argumentsArray: ts.Expression, newArrowNode: ts.NodeArray<ts.Statement>): ts.Statement[] { 1665 const createVariableStatementNode: ts.Statement[] = []; 1666 createVariableStatementNode.push(ts.factory.createVariableStatement( 1667 undefined, 1668 ts.factory.createVariableDeclarationList( 1669 [ts.factory.createVariableDeclaration( 1670 ts.factory.createIdentifier( 1671 argumentsArray.parameters[0] && argumentsArray.parameters[0].name.getText()), 1672 undefined, 1673 undefined, 1674 ts.factory.createIdentifier(_ITEM) 1675 )], 1676 ts.NodeFlags.Const 1677 ) 1678 )); 1679 if (newArrowNode) { 1680 createVariableStatementNode.push(...newArrowNode); 1681 } 1682 return createVariableStatementNode; 1683} 1684 1685function getParameters(node: ts.ArrowFunction): ts.ParameterDeclaration[] { 1686 const parameterArr: ts.ParameterDeclaration[] = [ 1687 ts.factory.createParameterDeclaration( 1688 undefined, undefined, ts.factory.createIdentifier(_ITEM)) 1689 ]; 1690 if (node.parameters && node.parameters.length > 1) { 1691 parameterArr.push(node.parameters[1]); 1692 } 1693 if (projectConfig.optLazyForEach && storedFileInfo.processLazyForEach) { 1694 if (node.parameters.length === 1) { 1695 parameterArr.push(ts.factory.createParameterDeclaration( 1696 undefined, undefined, ts.factory.createIdentifier(INDEX))); 1697 } 1698 parameterArr.push( 1699 ts.factory.createParameterDeclaration( 1700 undefined, undefined, ts.factory.createIdentifier(IS_INITIAL_ITEM)), 1701 ts.factory.createParameterDeclaration( 1702 undefined, undefined, ts.factory.createIdentifier(IDS)) 1703 ); 1704 } 1705 return parameterArr; 1706} 1707 1708function createItemIdFuncStatement( 1709 node: ts.CallExpression, 1710 argumentsArray: ts.Expression[] 1711): ts.VariableStatement { 1712 if (argumentsArray[2]) { 1713 return ts.factory.createVariableStatement( 1714 undefined, 1715 ts.factory.createVariableDeclarationList( 1716 [ts.factory.createVariableDeclaration( 1717 ts.factory.createIdentifier(node.expression.getText() === COMPONENT_FOREACH ? 1718 FOREACHITEMIDFUNC : __LAZYFOREACHITEMIDFUNC), undefined, undefined, 1719 argumentsArray[2] 1720 )], 1721 ts.NodeFlags.Const 1722 ) 1723 ); 1724 } 1725 return undefined; 1726} 1727 1728function createUpdateFunctionStatement(argumentsArray: ts.Expression[], 1729 newForEachArrowFunc: ts.ArrowFunction, isGlobalBuilder: boolean = false): ts.ExpressionStatement { 1730 return ts.factory.createExpressionStatement( 1731 ts.factory.createCallExpression( 1732 ts.factory.createPropertyAccessExpression( 1733 isGlobalBuilder ? parentConditionalExpression() : ts.factory.createThis(), 1734 ts.factory.createIdentifier(FOREACHUPDATEFUNCTION) 1735 ), 1736 undefined, 1737 addForEachIdFuncParameter(argumentsArray, newForEachArrowFunc) 1738 ) 1739 ); 1740} 1741 1742function addForEachIdFuncParameter(argumentsArray: ts.Expression[], newForEachArrowFunc: ts.ArrowFunction): ts.Expression[] { 1743 const addForEachIdFuncParameterArr: ts.Expression[] = []; 1744 addForEachIdFuncParameterArr.push( 1745 ts.factory.createIdentifier(ELMTID), 1746 argumentsArray[0], 1747 ts.factory.createIdentifier(FOREACHITEMGENFUNCTION) 1748 ); 1749 // @ts-ignore 1750 if (newForEachArrowFunc && newForEachArrowFunc.parameters && newForEachArrowFunc.parameters[1]) { 1751 if (!argumentsArray[2]) { 1752 addForEachIdFuncParameterArr.push(...addForEachParameter(ts.factory.createIdentifier(COMPONENT_IF_UNDEFINED), TRUE, FALSE)); 1753 } else { 1754 // @ts-ignore 1755 argumentsArray[2].parameters && argumentsArray[2].parameters[1] ? 1756 addForEachIdFuncParameterArr.push(...addForEachParameter(argumentsArray[2], TRUE, TRUE)) : 1757 addForEachIdFuncParameterArr.push(...addForEachParameter(argumentsArray[2], TRUE, FALSE)); 1758 } 1759 } 1760 // @ts-ignore 1761 if (newForEachArrowFunc && newForEachArrowFunc.parameters && newForEachArrowFunc.parameters.length < 2 && newForEachArrowFunc.parameters[0] && 1762 argumentsArray && argumentsArray.length > 2 && argumentsArray[2]) { 1763 // @ts-ignore 1764 argumentsArray[2].parameters && argumentsArray[2].parameters[1] ? 1765 addForEachIdFuncParameterArr.push(...addForEachParameter(argumentsArray[2], FALSE, TRUE)) : 1766 addForEachIdFuncParameterArr.push(...addForEachParameter(argumentsArray[2], FALSE, FALSE)); 1767 } 1768 return addForEachIdFuncParameterArr; 1769} 1770 1771function addForEachParameter(forEachItemIdContent: ts.Expression, forEachItemGen: string, forEachItemId: string): ts.Expression[] { 1772 return [forEachItemIdContent, ts.factory.createIdentifier(forEachItemGen), 1773 ts.factory.createIdentifier(forEachItemId)]; 1774} 1775 1776function createLazyForEachStatement(argumentsArray: ts.Expression[]): ts.ExpressionStatement { 1777 const parameterList: ts.Expression[] = [ 1778 ts.factory.createStringLiteral(componentInfo.id.toString()), 1779 ts.factory.createThis(), 1780 argumentsArray[0], 1781 ts.factory.createIdentifier(__LAZYFOREACHITEMGENFUNCTION) 1782 ]; 1783 if (argumentsArray.length >= 3 && argumentsArray[2]) { 1784 parameterList.push(ts.factory.createIdentifier(__LAZYFOREACHITEMIDFUNC)); 1785 } 1786 if (projectConfig.optLazyForEach) { 1787 parameterList.push(ts.factory.createTrue()); 1788 } 1789 return ts.factory.createExpressionStatement( 1790 ts.factory.createCallExpression( 1791 ts.factory.createPropertyAccessExpression( 1792 ts.factory.createIdentifier(COMPONENT_LAZYFOREACH), 1793 ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION) 1794 ), 1795 undefined, 1796 parameterList 1797 ) 1798 ); 1799} 1800 1801function addForEachId(node: ts.ExpressionStatement, isGlobalBuilder: boolean = false): ts.ExpressionStatement { 1802 const forEachComponent: ts.CallExpression = node.expression as ts.CallExpression; 1803 return ts.factory.updateExpressionStatement(node, ts.factory.updateCallExpression( 1804 forEachComponent, forEachComponent.expression, forEachComponent.typeArguments, 1805 [ts.factory.createStringLiteral((++componentInfo.id).toString()), 1806 isGlobalBuilder ? parentConditionalExpression() : ts.factory.createThis(), 1807 ...forEachComponent.arguments])); 1808} 1809 1810export function parentConditionalExpression(): ts.ConditionalExpression { 1811 return ts.factory.createConditionalExpression( 1812 ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARENT), 1813 ts.factory.createToken(ts.SyntaxKind.QuestionToken), 1814 ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARENT), 1815 ts.factory.createToken(ts.SyntaxKind.ColonToken), 1816 ts.factory.createThis()); 1817} 1818function processForEachFunctionBlock(node: ts.CallExpression): ts.ArrowFunction { 1819 if (ts.isArrowFunction(node.arguments[1])) { 1820 return node.arguments[1]; 1821 } else if (ts.isParenthesizedExpression(node.arguments[1]) && ts.isArrowFunction(node.arguments[1].expression)) { 1822 return node.arguments[1].expression; 1823 } else { 1824 return null; 1825 } 1826} 1827function processForEachBlock(node: ts.CallExpression, log: LogInfo[], 1828 arrowNode: ts.ArrowFunction, isBuilder: boolean = false, isGlobalBuilder: boolean = false, 1829 builderParamsResult: BuilderParamsResult = null, isInRepeatTemplate: boolean = false): ts.NodeArray<ts.Statement> | ts.ArrowFunction { 1830 if (node.arguments.length > 1 && ts.isArrowFunction(arrowNode)) { 1831 const isLazy: boolean = node.expression.getText() === COMPONENT_LAZYFOREACH; 1832 const body: ts.ConciseBody = arrowNode.body; 1833 if (!ts.isBlock(body)) { 1834 const statement: ts.Statement = ts.factory.createExpressionStatement(body); 1835 const blockNode: ts.Block = ts.factory.createBlock([statement], true); 1836 // @ts-ignore 1837 statement.parent = blockNode; 1838 if (!partialUpdateConfig.partialUpdateMode) { 1839 return ts.factory.updateArrowFunction( 1840 arrowNode, ts.getModifiers(arrowNode), arrowNode.typeParameters, arrowNode.parameters, 1841 arrowNode.type, arrowNode.equalsGreaterThanToken, 1842 processComponentBlock(blockNode, isLazy, log, false, false, undefined, 1843 arrowNode.parameters, isGlobalBuilder)); 1844 } else { 1845 return processComponentBlock(blockNode, isLazy, log, false, false, undefined, 1846 arrowNode.parameters, isGlobalBuilder, builderParamsResult, false, isInRepeatTemplate).statements; 1847 } 1848 } else { 1849 if (!partialUpdateConfig.partialUpdateMode) { 1850 return ts.factory.updateArrowFunction( 1851 arrowNode, ts.getModifiers(arrowNode), arrowNode.typeParameters, arrowNode.parameters, 1852 arrowNode.type, arrowNode.equalsGreaterThanToken, 1853 processComponentBlock(body, isLazy, log, false, isBuilder, undefined, arrowNode.parameters)); 1854 } else { 1855 return processComponentBlock(body, isLazy, log, false, false, undefined, arrowNode.parameters, 1856 isGlobalBuilder, builderParamsResult, false, isInRepeatTemplate).statements; 1857 } 1858 } 1859 } 1860 return null; 1861} 1862 1863function createRenderingInProgress(isTrue: boolean): ts.ExpressionStatement { 1864 return ts.factory.createExpressionStatement(ts.factory.createBinaryExpression( 1865 ts.factory.createPropertyAccessExpression( 1866 ts.factory.createThis(), 1867 ts.factory.createIdentifier(IS_RENDERING_IN_PROGRESS) 1868 ), 1869 ts.factory.createToken(ts.SyntaxKind.EqualsToken), 1870 isTrue ? ts.factory.createTrue() : ts.factory.createFalse() 1871 )); 1872} 1873 1874function addElmtIdNode(): boolean { 1875 return partialUpdateConfig.partialUpdateMode && projectConfig.optLazyForEach && 1876 ((storedFileInfo.processLazyForEach && storedFileInfo.lazyForEachInfo.isDependItem) || storedFileInfo.processBuilder); 1877} 1878 1879function processIfStatement(node: ts.IfStatement, newStatements: ts.Statement[], 1880 log: LogInfo[], isBuilder: boolean = false, isGlobalBuilder: boolean = false, 1881 builderParamsResult: BuilderParamsResult = null, isInRepeatTemplate: boolean = false): void { 1882 const ifStatements: ts.Statement[] = []; 1883 if (addElmtIdNode()) { 1884 ifStatements.push(createCollectElmtIdNode()); 1885 storedFileInfo.lazyForEachInfo.isDependItem = false; 1886 } 1887 const ifCreate: ts.ExpressionStatement = createIfCreate(); 1888 const newIfNode: ts.IfStatement = processInnerIfStatement(node, 0, log, isBuilder, isGlobalBuilder, builderParamsResult, isInRepeatTemplate); 1889 ifStatements.push(ifCreate, newIfNode); 1890 const ifPop: ts.ExpressionStatement = createIfPop(); 1891 if (!partialUpdateConfig.partialUpdateMode) { 1892 newStatements.push(ifCreate, newIfNode, ifPop); 1893 } else { 1894 newStatements.push(createComponentCreationStatement(node, ifStatements, COMPONENT_IF, 1895 isGlobalBuilder, false, undefined, null, builderParamsResult), ifPop); 1896 } 1897} 1898 1899function processInnerIfStatement(node: ts.IfStatement, id: number, log: LogInfo[], 1900 isBuilder: boolean = false, isGlobalBuilder: boolean = false, 1901 builderParamsResult: BuilderParamsResult = null, isInRepeatTemplate: boolean = false): ts.IfStatement { 1902 if (ts.isIdentifier(node.expression) && node.expression.originalKeywordKind === undefined && 1903 !node.expression.escapedText) { 1904 log.push({ 1905 type: LogType.ERROR, 1906 message: 'Condition expression cannot be null in if statement.', 1907 pos: node.expression.getStart(), 1908 code: '10905208' 1909 }); 1910 node = ts.factory.updateIfStatement(node, ts.factory.createIdentifier(COMPONENT_IF_UNDEFINED), 1911 node.thenStatement, node.elseStatement); 1912 } 1913 const newThenStatement: ts.Statement = processThenStatement( 1914 node.thenStatement, id, log, isBuilder, isGlobalBuilder, builderParamsResult, isInRepeatTemplate); 1915 const newElseStatement: ts.Statement = processElseStatement( 1916 node.elseStatement, id, log, isBuilder, isGlobalBuilder, builderParamsResult, isInRepeatTemplate); 1917 const newIfNode: ts.IfStatement = ts.factory.updateIfStatement( 1918 node, node.expression, newThenStatement, newElseStatement); 1919 return newIfNode; 1920} 1921 1922function processThenStatement(thenStatement: ts.Statement, id: number, 1923 log: LogInfo[], isBuilder: boolean = false, isGlobalBuilder: boolean = false, 1924 builderParamsResult: BuilderParamsResult = null, isInRepeatTemplate: boolean = false): ts.Statement { 1925 if (ts.isExpressionStatement(thenStatement) && ts.isIdentifier(thenStatement.expression) && 1926 thenStatement.expression.originalKeywordKind === undefined && 1927 !thenStatement.expression.escapedText) { 1928 log.push({ 1929 type: LogType.ERROR, 1930 message: 'Then statement cannot be null in if statement.', 1931 pos: thenStatement.expression.getStart(), 1932 code: '10905207' 1933 }); 1934 } 1935 if (thenStatement) { 1936 if (ts.isBlock(thenStatement)) { 1937 thenStatement = processIfBlock(thenStatement, id, log, isBuilder, isGlobalBuilder, builderParamsResult, isInRepeatTemplate); 1938 } else if (ts.isIfStatement(thenStatement)) { 1939 thenStatement = processInnerIfStatement(thenStatement, 0, log, isBuilder, isGlobalBuilder, builderParamsResult, isInRepeatTemplate); 1940 thenStatement = ts.factory.createBlock( 1941 partialUpdateConfig.partialUpdateMode ? 1942 [createIfCreate(), createIfBranchFunc(id, [thenStatement], isGlobalBuilder), createIfPop()] : 1943 [createIfCreate(), createIfBranchId(id), thenStatement, createIfPop()], 1944 true 1945 ); 1946 } else { 1947 thenStatement = ts.factory.createBlock([thenStatement], true); 1948 thenStatement = processIfBlock(thenStatement as ts.Block, id, log, isBuilder, isGlobalBuilder, builderParamsResult, isInRepeatTemplate); 1949 } 1950 } 1951 return thenStatement; 1952} 1953 1954function processElseStatement(elseStatement: ts.Statement, id: number, 1955 log: LogInfo[], isBuilder: boolean = false, isGlobalBuilder: boolean = false, 1956 builderParamsResult: BuilderParamsResult = null, isInRepeatTemplate: boolean = false): ts.Statement { 1957 if (elseStatement) { 1958 if (ts.isBlock(elseStatement)) { 1959 elseStatement = processIfBlock(elseStatement, id + 1, log, isBuilder, isGlobalBuilder, builderParamsResult, isInRepeatTemplate); 1960 } else if (ts.isIfStatement(elseStatement)) { 1961 elseStatement = processInnerIfStatement(elseStatement, id + 1, log, isBuilder, isGlobalBuilder, builderParamsResult, isInRepeatTemplate); 1962 } else { 1963 elseStatement = ts.factory.createBlock([elseStatement], true); 1964 elseStatement = processIfBlock(elseStatement as ts.Block, id + 1, log, isBuilder, isGlobalBuilder, builderParamsResult, isInRepeatTemplate); 1965 } 1966 } else if (partialUpdateConfig.partialUpdateMode) { 1967 elseStatement = ts.factory.createBlock([ 1968 ts.factory.createExpressionStatement(ts.factory.createCallExpression( 1969 ts.factory.createPropertyAccessExpression( 1970 ts.factory.createThis(), 1971 ts.factory.createIdentifier(IFELSEBRANCHUPDATEFUNCTION) 1972 ), 1973 undefined, 1974 [ 1975 ts.factory.createNumericLiteral(++id), 1976 ts.factory.createArrowFunction( 1977 undefined, 1978 undefined, 1979 [], 1980 undefined, 1981 ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), 1982 ts.factory.createBlock( 1983 [], 1984 true 1985 ) 1986 ) 1987 ] 1988 )) 1989 ], true); 1990 } 1991 return elseStatement; 1992} 1993 1994function processIfBlock(block: ts.Block, id: number, log: LogInfo[], isBuilder: boolean = false, 1995 isGlobalBuilder: boolean = false, builderParamsResult: BuilderParamsResult = null, isInRepeatTemplate: boolean = false): ts.Block { 1996 return addIfBranchId(id, isGlobalBuilder, 1997 processComponentBlock(block, false, log, false, isBuilder, COMPONENT_IF, undefined, isGlobalBuilder, builderParamsResult, false, isInRepeatTemplate)); 1998} 1999 2000function addIfBranchId(id: number, isGlobalBuilder: boolean = false, container: ts.Block): ts.Block { 2001 let containerStatements: ts.Statement[]; 2002 if (partialUpdateConfig.partialUpdateMode) { 2003 containerStatements = [createIfBranchFunc(id, [...container.statements], isGlobalBuilder)]; 2004 } else { 2005 containerStatements = [createIfBranchId(id), ...container.statements]; 2006 } 2007 return ts.factory.updateBlock(container, containerStatements); 2008} 2009 2010function createIf(): ts.Identifier { 2011 return ts.factory.createIdentifier(COMPONENT_IF); 2012} 2013 2014function createIfCreate(): ts.ExpressionStatement { 2015 return ts.factory.createExpressionStatement(createFunction(createIf(), 2016 ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION), ts.factory.createNodeArray([]))); 2017} 2018 2019function createIfPop(): ts.ExpressionStatement { 2020 return ts.factory.createExpressionStatement(createFunction(createIf(), 2021 ts.factory.createIdentifier(COMPONENT_POP_FUNCTION), null)); 2022} 2023 2024function createIfBranchId(id: number): ts.ExpressionStatement { 2025 return ts.factory.createExpressionStatement(createFunction(createIf(), 2026 ts.factory.createIdentifier(COMPONENT_IF_BRANCH_ID_FUNCTION), 2027 ts.factory.createNodeArray([ts.factory.createNumericLiteral(id)]))); 2028} 2029 2030function createIfBranchFunc(id: number, innerStatements: ts.Statement[], 2031 isGlobalBuilder: boolean = false): ts.ExpressionStatement { 2032 return ts.factory.createExpressionStatement(ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression( 2033 isGlobalBuilder ? parentConditionalExpression() : ts.factory.createThis(), 2034 ts.factory.createIdentifier(IFELSEBRANCHUPDATEFUNCTION)), undefined, 2035 [ts.factory.createNumericLiteral(id), ts.factory.createArrowFunction(undefined, undefined, [], undefined, 2036 ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), ts.factory.createBlock(innerStatements, true))])); 2037} 2038 2039interface CreateResult { 2040 newNode: ts.ExpressionStatement; 2041 identifierNode: ts.Identifier; 2042 isContainerComponent: boolean; 2043 isButton: boolean; 2044 needPop: boolean; 2045} 2046 2047function createComponent(node: ts.ExpressionStatement, type: string): CreateResult { 2048 const res: CreateResult = { 2049 newNode: node, 2050 identifierNode: null, 2051 isContainerComponent: false, 2052 isButton: false, 2053 needPop: false 2054 }; 2055 let identifierNode: ts.Identifier = ts.factory.createIdentifier(type); 2056 let temp: any = node.expression; 2057 while (temp && !ts.isIdentifier(temp) && temp.expression) { 2058 temp = temp.expression; 2059 } 2060 if (temp && temp.parent && (ts.isCallExpression(temp.parent) || 2061 ts.isEtsComponentExpression(temp.parent)) && ts.isIdentifier(temp)) { 2062 if (temp.getText() === COMPONENT_BUTTON && type !== COMPONENT_POP_FUNCTION) { 2063 res.isButton = true; 2064 identifierNode = type === COMPONENT_CREATE_CHILD_FUNCTION ? 2065 ts.factory.createIdentifier(COMPONENT_CREATE_CHILD_FUNCTION) : 2066 ts.factory.createIdentifier(COMPONENT_CREATE_LABEL_FUNCTION); 2067 } 2068 if (NEEDPOP_COMPONENT.has(temp.getText())) { 2069 res.needPop = true; 2070 } 2071 if (checkContainer(temp.getText(), temp.parent)) { 2072 res.isContainerComponent = true; 2073 } 2074 res.newNode = type === COMPONENT_POP_FUNCTION ? 2075 ts.factory.createExpressionStatement(createFunction(temp, identifierNode, null)) : 2076 ts.factory.createExpressionStatement(createFunction(temp, identifierNode, checkArguments(temp, type))); 2077 res.identifierNode = temp; 2078 } 2079 return res; 2080} 2081 2082function checkArguments(temp: ts.Identifier, type: string): ts.Expression[] { 2083 const newArguments: ts.Expression[] = []; 2084 if (CUSTOM_BUILDER_CONSTRUCTORS.has(temp.escapedText.toString())) { 2085 temp.parent.arguments.forEach(argument => { 2086 if (ts.isConditionalExpression(argument)) { 2087 newArguments.push(processConditionalBuilder(argument, temp, type)); 2088 } else if (isBuilderChangeNode(argument, temp, type)) { 2089 newArguments.push(parseBuilderNode(argument, type)); 2090 } else { 2091 newArguments.push(argument); 2092 } 2093 }); 2094 return newArguments; 2095 } 2096 return temp.getText() === 'XComponent' && type === COMPONENT_CREATE_FUNCTION && 2097 projectConfig.moduleName && projectConfig.bundleName ? 2098 // @ts-ignore 2099 temp.parent.arguments.concat([ 2100 ts.factory.createStringLiteral(`${projectConfig.bundleName}/${projectConfig.moduleName}`) 2101 ]) : temp.parent.arguments; 2102} 2103 2104function checkContainer(name: string, node: ts.Node): boolean { 2105 return BUILDIN_CONTAINER_COMPONENT.has(name) && (name !== 'XComponent' || 2106 (node && node.arguments && node.arguments.length && 2107 ts.isObjectLiteralExpression(node.arguments[0]) && node.arguments[0].properties && 2108 checkComponentType(node.arguments[0].properties))); 2109} 2110 2111function checkComponentType(properties: ts.PropertyAssignment[]): boolean { 2112 let flag: boolean = false; 2113 properties.forEach(item => { 2114 if (isXComponentContainer(item)) { 2115 flag = true; 2116 } 2117 }); 2118 return flag; 2119} 2120 2121function isXComponentContainer(item: ts.PropertyAssignment): boolean { 2122 return item.name && ts.isIdentifier(item.name) && item.name.getText() === RESOURCE_NAME_TYPE && 2123 item.initializer && ((ts.isStringLiteral(item.initializer) && 2124 // value = 'component' 2125 (item.initializer.getText() === XCOMPONENT_SINGLE_QUOTATION || 2126 item.initializer.getText() === XCOMPONENT_DOUBLE_QUOTATION)) || 2127 // value = 1 2128 (ts.isNumericLiteral(item.initializer) && item.initializer.getText() === '1') || 2129 // value = XComponentType.COMPONENT 2130 (ts.isPropertyAccessExpression(item.initializer) && item.initializer.expression && 2131 ts.isIdentifier(item.initializer.expression) && item.initializer.name && 2132 ts.isIdentifier(item.initializer.name) && item.initializer.expression.getText() === XCOMPONENTTYPE) && 2133 item.initializer.name.getText() === XCOMPONENTTYPE_CONTAINER); 2134} 2135 2136interface AnimationInfo { 2137 statement: ts.Statement, 2138 kind: boolean, 2139 hasAnimationAttr: boolean, 2140} 2141 2142export interface ComponentAttrInfo { 2143 reuseId: ts.Node, 2144 hasIdAttr: boolean, 2145 attrCount: number, 2146 reuse: string, 2147} 2148 2149export function bindComponentAttr(node: ts.ExpressionStatement, identifierNode: ts.Identifier, 2150 newStatements: ts.Statement[], log: LogInfo[], reverse: boolean = true, 2151 isStylesAttr: boolean = false, newImmutableStatements: ts.Statement[] = null, 2152 isStyleFunction: boolean = false, componentAttrInfo: ComponentAttrInfo = null, 2153 isReusableV2NodeAttr: boolean = false): void { 2154 const isStylesUIComponent: boolean = validateStylesUIComponent(node, isStylesAttr); 2155 let temp = node.expression; 2156 const statements: ts.Statement[] = []; 2157 const immutableStatements: ts.Statement[] = []; 2158 const updateStatements: ts.Statement[] = []; 2159 const lastStatement: AnimationInfo = { 2160 statement: null, 2161 kind: false, 2162 hasAnimationAttr: false 2163 }; 2164 const isRecycleComponent: boolean = isRecycle(componentCollection.currentClassName); 2165 const isReuseComponentInV2: boolean = isReuseInV2(componentCollection.currentClassName); 2166 if (ts.isPropertyAccessExpression(temp) || isStylesUIComponent) { 2167 log.push({ 2168 type: isStylesUIComponent ? LogType.WARN : LogType.ERROR, 2169 message: `'${node.getText()}' does not meet UI component syntax.`, 2170 pos: node.getStart(), 2171 code: '10905206' 2172 }); 2173 } 2174 while (temp && ts.isCallExpression(temp) && temp.expression) { 2175 let flag: boolean = false; 2176 if (temp.expression && (validatePropertyAccessExpressionWithCustomBuilder(temp.expression) || 2177 validateIdentifierWithCustomBuilder(temp.expression))) { 2178 let propertyName: string = ''; 2179 if (ts.isIdentifier(temp.expression)) { 2180 propertyName = temp.expression.escapedText.toString(); 2181 } else if (ts.isPropertyAccessExpression(temp.expression)) { 2182 propertyName = temp.expression.name.escapedText.toString(); 2183 } 2184 switch (true) { 2185 case BIND_POPUP_SET.has(propertyName): 2186 temp = processBindPopupBuilder(temp); 2187 break; 2188 case BIND_DRAG_SET.has(propertyName): 2189 temp = processDragStartBuilder(temp, propertyName); 2190 break; 2191 default: 2192 temp = processCustomBuilderProperty(temp, identifierNode, propertyName); 2193 } 2194 } 2195 if (ts.isPropertyAccessExpression(temp.expression) && 2196 temp.expression.name && ts.isIdentifier(temp.expression.name) && 2197 (!componentCollection.customComponents.has(temp.expression.name.getText()) || STYLES_ATTRIBUTE.has(temp.expression.name.getText()))) { 2198 parseRecycleId(temp, temp.expression.name, componentAttrInfo, log, isReusableV2NodeAttr); 2199 addComponentAttr(temp, temp.expression.name, lastStatement, statements, identifierNode, log, 2200 isStylesAttr, immutableStatements, updateStatements, newImmutableStatements, 2201 isRecycleComponent, isReuseComponentInV2, isStyleFunction); 2202 temp = temp.expression.expression; 2203 flag = true; 2204 } else if (ts.isIdentifier(temp.expression)) { 2205 if (!INNER_COMPONENT_NAMES.has(temp.expression.getText()) && 2206 !GESTURE_TYPE_NAMES.has(temp.expression.getText()) && 2207 !componentCollection.customComponents.has(temp.expression.getText())) { 2208 parseRecycleId(temp, temp.expression.name, componentAttrInfo, log, isReusableV2NodeAttr); 2209 addComponentAttr(temp, temp.expression, lastStatement, statements, identifierNode, log, 2210 isStylesAttr, immutableStatements, updateStatements, newImmutableStatements, 2211 isRecycleComponent, isReuseComponentInV2, isStyleFunction); 2212 } 2213 break; 2214 } 2215 if (!flag) { 2216 temp = temp.expression; 2217 } 2218 } 2219 if (lastStatement.statement && lastStatement.kind) { 2220 statements.push(lastStatement.statement); 2221 } 2222 if ((!isRecycleComponent && !isReuseComponentInV2) || lastStatement.hasAnimationAttr) { 2223 if (statements.length) { 2224 reverse ? newStatements.push(...statements.reverse()) : newStatements.push(...statements); 2225 } 2226 } else { 2227 if (updateStatements.length) { 2228 reverse ? newStatements.push(...updateStatements.reverse()) : newStatements.push(...updateStatements); 2229 } 2230 if (newImmutableStatements && immutableStatements.length) { 2231 reverse ? newImmutableStatements.push(...immutableStatements.reverse()) : newImmutableStatements.push(...immutableStatements); 2232 } 2233 } 2234} 2235 2236function validateStylesUIComponent(node: ts.ExpressionStatement, isStylesAttr: boolean): boolean { 2237 return (ts.isIfStatement(node) || ts.isSwitchStatement(node)) && isStylesAttr; 2238} 2239 2240function parseRecycleId(node: ts.CallExpression, attr: ts.Identifier, componentAttrInfo: ComponentAttrInfo, log: LogInfo[], 2241 isReusableV2NodeAttr: boolean = false): void { 2242 if (componentAttrInfo) { 2243 const attrName: string = attr.escapedText.toString(); 2244 if (attrName === RECYCLE_REUSE_ID) { 2245 logMessageCollection.checkUsageOfReuseIdAttribute(node, isReusableV2NodeAttr, log); 2246 componentAttrInfo.reuseId = node.arguments[0]; 2247 } else if (attrName === ATTRIBUTE_ID) { 2248 componentAttrInfo.hasIdAttr = true; 2249 } else if (attrName === REUSE_ATTRIBUTE) { 2250 logMessageCollection.checkUsageOfReuseAttribute(node, isReusableV2NodeAttr, log); 2251 if (ts.isObjectLiteralExpression(node.arguments[0]) && !!getReuseIdInReuse(node.arguments[0])) { 2252 componentAttrInfo.reuse = getReuseIdInReuse(node.arguments[0]); 2253 } else { 2254 componentAttrInfo.reuse = ''; 2255 } 2256 } 2257 componentAttrInfo.attrCount++; 2258 } 2259} 2260 2261function getReuseIdInReuse(node: ts.ObjectLiteralExpression): string { 2262 let reuse: string = ''; 2263 if (node.properties && node.properties.length) { 2264 node.properties.forEach((item: ts.ObjectLiteralElementLike) => { 2265 if (ts.isPropertyAssignment(item) && item.name && ts.isIdentifier(item.name) && 2266 item.name.getText() === RECYCLE_REUSE_ID && item.initializer && 2267 ts.isArrowFunction(item.initializer) && item.initializer.body && 2268 ts.isStringLiteral(item.initializer.body)) { 2269 reuse = item.initializer.body.text; 2270 } 2271 }); 2272 } 2273 return reuse; 2274} 2275 2276function processCustomBuilderProperty(node: ts.CallExpression, identifierNode: ts.Identifier, 2277 propertyName: string): ts.CallExpression { 2278 const newArguments: ts.Expression[] = []; 2279 node.arguments.forEach((argument: ts.Expression | ts.Identifier, index: number) => { 2280 if (ts.isConditionalExpression(argument)) { 2281 newArguments.push(processConditionalBuilder(argument, identifierNode, propertyName)); 2282 } else if (isBuilderChangeNode(argument, identifierNode, propertyName)) { 2283 newArguments.push(parseBuilderNode(argument, propertyName)); 2284 } else { 2285 newArguments.push(argument); 2286 } 2287 }); 2288 node = ts.factory.updateCallExpression(node, node.expression, node.typeArguments, newArguments); 2289 return node; 2290} 2291 2292function isBuilderChangeNode(argument: ts.Node, identifierNode: ts.Identifier, propertyName: string): boolean { 2293 return ts.isPropertyAccessExpression(argument) && argument.name && ts.isIdentifier(argument.name) && 2294 storedFileInfo.builderLikeCollection.has(argument.name.getText()) || 2295 ts.isCallExpression(argument) && argument.expression && argument.expression.name && 2296 ts.isIdentifier(argument.expression.name) && 2297 storedFileInfo.builderLikeCollection.has(argument.expression.name.getText()) || ts.isIdentifier(argument) && 2298 argument.escapedText && storedFileInfo.builderLikeCollection.has(argument.escapedText.toString()) || 2299 ts.isObjectLiteralExpression(argument) && (BIND_OBJECT_PROPERTY.get(identifierNode.escapedText.toString()) && 2300 BIND_OBJECT_PROPERTY.get(identifierNode.escapedText.toString()).has(propertyName) || 2301 BIND_OBJECT_PROPERTY.get(ALL_COMPONENTS).has(propertyName)) || 2302 ts.isCallExpression(argument) && argument.expression && ts.isIdentifier(argument.expression) && 2303 storedFileInfo.builderLikeCollection.has(argument.expression.escapedText.toString()) || 2304 isWrappedBuilder(argument as ts.PropertyAccessExpression) || isWrappedBuilderCallExpression(argument as ts.CallExpression); 2305} 2306 2307export function isWrappedBuilder(node: ts.PropertyAccessExpression): boolean { 2308 if (projectConfig.minAPIVersion >= 11 && ts.isPropertyAccessExpression(node) && 2309 node.name && ts.isIdentifier(node.name) && node.name.escapedText.toString() === WRAPBUILDER_BUILDERPROP && 2310 globalProgram.checker.getTypeAtLocation(node.expression) && 2311 globalProgram.checker.getTypeAtLocation(node.expression).symbol && 2312 globalProgram.checker.getTypeAtLocation(node.expression).symbol.escapedName === WRAPPEDBUILDER_CLASS) { 2313 return true; 2314 } 2315 return false; 2316} 2317 2318function isWrappedBuilderCallExpression(node: ts.CallExpression): boolean { 2319 if (projectConfig.minAPIVersion >= 11 && ts.isCallExpression(node) && node.expression && 2320 isWrappedBuilder(node.expression as ts.PropertyAccessExpression)) { 2321 return true; 2322 } 2323 return false; 2324} 2325 2326function parseBuilderNode(node: ts.Node, propertyName: string): 2327 ts.ObjectLiteralExpression | ts.CallExpression | ts.ArrowFunction { 2328 if (isWrappedBuilder(node as ts.PropertyAccessExpression) || isPropertyAccessExpressionNode(node)) { 2329 if (CUSTOM_BUILDER_PROPERTIES_WITHOUTKEY.has(propertyName)) { 2330 return processPropertyBuilderWithoutKey(node as ts.PropertyAccessExpression); 2331 } else { 2332 return processPropertyBuilder(node as ts.PropertyAccessExpression); 2333 } 2334 } else if (ts.isIdentifier(node) && storedFileInfo.builderLikeCollection.has(node.escapedText.toString())) { 2335 if (CUSTOM_BUILDER_PROPERTIES_WITHOUTKEY.has(propertyName)) { 2336 return processIdentifierBuilderWithoutKey(node); 2337 } else { 2338 return processIdentifierBuilder(node); 2339 } 2340 } else if (isWrappedBuilderCallExpression(node as ts.CallExpression) || ts.isCallExpression(node)) { 2341 if (CUSTOM_BUILDER_PROPERTIES_WITHOUTKEY.has(propertyName)) { 2342 return getParsedBuilderAttrArgumentWithParamsWithoutKey(node); 2343 } else { 2344 return getParsedBuilderAttrArgumentWithParams(node); 2345 } 2346 } else if (ts.isObjectLiteralExpression(node)) { 2347 return processObjectPropertyBuilder(node); 2348 } 2349 return undefined; 2350} 2351 2352export function processObjectPropertyBuilder(node: ts.ObjectLiteralExpression): ts.ObjectLiteralExpression { 2353 const newProperties: ts.PropertyAssignment[] = []; 2354 node.properties.forEach((property: ts.PropertyAssignment) => { 2355 if (property.name && ts.isIdentifier(property.name) && 2356 [CUSTOM_DIALOG_CONTROLLER_BUILDER, HEADER, INDICATORBUILDER, FOOTER, START, END, PREVIEW, TITLE].includes( 2357 property.name.escapedText.toString()) && property.initializer) { 2358 if (isPropertyAccessExpressionNode(property.initializer) || ts.isIdentifier(property.initializer) && 2359 storedFileInfo.builderLikeCollection.has(property.initializer.escapedText.toString())) { 2360 newProperties.push(ts.factory.updatePropertyAssignment(property, property.name, 2361 ts.factory.createCallExpression( 2362 ts.factory.createPropertyAccessExpression( 2363 property.initializer, 2364 ts.factory.createIdentifier(BUILDER_ATTR_BIND) 2365 ), 2366 undefined, 2367 [ts.factory.createThis()] 2368 ))); 2369 } else if (isGlobalBuilderCallExpressionNode(property.initializer) || 2370 isInnerBuilderCallExpressionNode(property.initializer)) { 2371 newProperties.push(transformBuilderCallExpression(property)); 2372 } else if (ts.isObjectLiteralExpression(property.initializer)) { 2373 newProperties.push(ts.factory.updatePropertyAssignment(property, property.name, 2374 processObjectPropertyBuilder(property.initializer))); 2375 } else { 2376 newProperties.push(property); 2377 } 2378 } else { 2379 newProperties.push(property); 2380 } 2381 }); 2382 return ts.factory.updateObjectLiteralExpression(node, newProperties); 2383} 2384 2385function transDoubleDollarInCustomBuilder(node: ts.CallExpression): ts.Expression[] { 2386 let name: string = ''; 2387 if (node.expression && ts.isIdentifier(node.expression)) { 2388 name = node.expression.escapedText.toString(); 2389 } else if (node.expression && ts.isPropertyAccessExpression(node.expression) && 2390 node.expression.name && ts.isIdentifier(node.expression.name)) { 2391 name = node.expression.name.escapedText.toString(); 2392 } 2393 if (node.arguments.length === 1 && ts.isObjectLiteralExpression(node.arguments[0])) { 2394 return [ts.factory.createCallExpression( 2395 ts.factory.createIdentifier(BUILDER_PARAM_PROXY), 2396 undefined, 2397 [ 2398 ts.factory.createStringLiteral(name), 2399 traverseBuilderParams(node.arguments[0], storedFileInfo.processBuilder) 2400 ] 2401 )]; 2402 } else { 2403 return node.arguments; 2404 } 2405} 2406 2407function transformBuilderCallExpression(property: ts.PropertyAssignment): ts.PropertyAssignment { 2408 const newArguments: ts.Expression[] = transDoubleDollarInCustomBuilder(property.initializer as ts.CallExpression); 2409 return ts.factory.updatePropertyAssignment(property, property.name, 2410 ts.factory.createCallExpression( 2411 ts.factory.createPropertyAccessExpression( 2412 property.initializer.expression, 2413 ts.factory.createIdentifier(BUILDER_ATTR_BIND) 2414 ), 2415 undefined, 2416 [ts.factory.createThis(), ...(newArguments || [])] 2417 )); 2418} 2419 2420function isInnerBuilderCallExpressionNode(node: ts.Node): boolean { 2421 return ts.isCallExpression(node) && node.expression && isPropertyAccessExpressionNode(node.expression); 2422} 2423 2424function isGlobalBuilderCallExpressionNode(node: ts.Node): boolean { 2425 return ts.isCallExpression(node) && node.expression && ts.isIdentifier(node.expression) && 2426 CUSTOM_BUILDER_METHOD.has(node.expression.escapedText.toString()); 2427} 2428 2429function isPropertyAccessExpressionNode(node: ts.Node): boolean { 2430 return ts.isPropertyAccessExpression(node) && node.expression && 2431 node.expression.kind === ts.SyntaxKind.ThisKeyword && node.name && ts.isIdentifier(node.name) && 2432 storedFileInfo.builderLikeCollection.has(node.name.escapedText.toString()); 2433} 2434 2435function processBindPopupBuilder(node: ts.CallExpression): ts.CallExpression { 2436 const newArguments: ts.Expression[] = []; 2437 node.arguments.forEach((argument: ts.ObjectLiteralExpression, index: number) => { 2438 if (index === 1 && ts.isObjectLiteralExpression(argument)) { 2439 // @ts-ignore 2440 newArguments.push(processBindPopupBuilderProperty(argument)); 2441 } else { 2442 newArguments.push(argument); 2443 } 2444 }); 2445 node = ts.factory.updateCallExpression(node, node.expression, node.typeArguments, newArguments); 2446 return node; 2447} 2448 2449function processDragStartBuilder(node: ts.CallExpression, propertyName: string): ts.CallExpression { 2450 const newStatements: ts.Statement[] = []; 2451 if (isNodeFunction(node)) { 2452 // @ts-ignore 2453 for (let i = 0; i < node.arguments[0].body.statements.length; i++) { 2454 // @ts-ignore 2455 const statement: ts.Statement = node.arguments[0].body.statements[i]; 2456 newStatements.push(checkStatement(statement, propertyName)); 2457 } 2458 node = ts.factory.updateCallExpression(node, node.expression, node.typeArguments, [ts.factory.updateArrowFunction( 2459 // @ts-ignore 2460 node.arguments[0], undefined, undefined, node.arguments[0].parameters, node.arguments[0].type, 2461 // @ts-ignore 2462 node.arguments[0].equalsGreaterThanToken, ts.factory.updateBlock(node.arguments[0].body, newStatements))]); 2463 } 2464 return node; 2465} 2466 2467function isNodeFunction(node: ts.CallExpression): boolean { 2468 return node.arguments && node.arguments.length && ts.isArrowFunction(node.arguments[0]) && node.arguments[0].body && 2469 ts.isBlock(node.arguments[0].body); 2470} 2471 2472function checkStatement(statement: ts.Statement, propertyName: string): ts.Statement { 2473 if (ts.isReturnStatement(statement)) { 2474 if (ts.isObjectLiteralExpression(statement.expression)) { 2475 const newProperties: ts.ObjectLiteralElementLike[] = []; 2476 for (let j = 0; j < statement.expression.properties.length; j++) { 2477 let property: ts.ObjectLiteralElementLike = statement.expression.properties[j]; 2478 property = checkProperty(property, propertyName); 2479 newProperties.push(property); 2480 } 2481 return ts.factory.createReturnStatement(ts.factory.createObjectLiteralExpression(newProperties)); 2482 } else { 2483 let initializer: ts.Expression = statement.expression; 2484 initializer = processInitializer(initializer, propertyName); 2485 return ts.factory.updateReturnStatement(statement, initializer); 2486 } 2487 } else { 2488 return statement; 2489 } 2490} 2491 2492function checkProperty(property: ts.ObjectLiteralElementLike, propertyName: string): ts.ObjectLiteralElementLike { 2493 if (isPropertyFunction(property)) { 2494 let initializer: ts.Expression = property.initializer; 2495 initializer = processInitializer(initializer, propertyName); 2496 property = ts.factory.createPropertyAssignment(property.name, initializer); 2497 } 2498 return property; 2499} 2500 2501function processInitializer(initializer: ts.Expression, propertyName: string): ts.Expression { 2502 if (initializer && ts.isConditionalExpression(initializer)) { 2503 return processConditionalBuilder(initializer, ts.factory.createIdentifier(CUSTOM_COMPONENT_DEFAULT), 2504 propertyName); 2505 } else if (isBuilderChangeNode(initializer, ts.factory.createIdentifier(CUSTOM_COMPONENT_DEFAULT), 2506 propertyName)) { 2507 return parseBuilderNode(initializer, propertyName); 2508 } 2509 return initializer; 2510} 2511 2512function isPropertyFunction(property: ts.ObjectLiteralElementLike): boolean { 2513 return ts.isPropertyAssignment(property) && property.name && ts.isIdentifier(property.name) && 2514 property.name.escapedText.toString() === BUILDER_ATTR_NAME; 2515} 2516 2517function processBindPopupBuilderProperty(node: ts.ObjectLiteralExpression): ts.ObjectLiteralExpression { 2518 const newProperties: ts.PropertyAssignment[] = []; 2519 node.properties.forEach((property: ts.PropertyAssignment, index: number) => { 2520 if (property.name && ts.isIdentifier(property.name) && property.initializer && 2521 property.name.escapedText.toString() === CUSTOM_DIALOG_CONTROLLER_BUILDER) { 2522 let initializer: ts.Expression = property.initializer; 2523 initializer = processInitializer(initializer, BIND_POPUP); 2524 newProperties.push(ts.factory.updatePropertyAssignment(property, property.name, initializer)); 2525 } else { 2526 newProperties.push(property); 2527 } 2528 }); 2529 return ts.factory.updateObjectLiteralExpression(node, newProperties); 2530} 2531 2532function processConditionalBuilder(initializer: ts.ConditionalExpression, identifierNode: ts.Identifier, 2533 propertyName: string): ts.ConditionalExpression { 2534 let whenTrue: ts.Expression = initializer.whenTrue; 2535 let whenFalse: ts.Expression = initializer.whenFalse; 2536 if (isBuilderChangeNode(initializer.whenTrue, identifierNode, propertyName)) { 2537 whenTrue = parseBuilderNode(initializer.whenTrue, propertyName); 2538 } 2539 if (isBuilderChangeNode(initializer.whenFalse, identifierNode, propertyName)) { 2540 whenFalse = parseBuilderNode(initializer.whenFalse, propertyName); 2541 } 2542 return ts.factory.createConditionalExpression( 2543 initializer.condition, 2544 initializer.questionToken, 2545 whenTrue, 2546 initializer.colonToken, 2547 whenFalse 2548 ); 2549} 2550 2551function processPropertyBuilder(node: ts.PropertyAccessExpression): ts.ObjectLiteralExpression { 2552 return ts.factory.createObjectLiteralExpression([ 2553 ts.factory.createPropertyAssignment( 2554 ts.factory.createIdentifier(BUILDER_ATTR_NAME), 2555 ts.factory.createCallExpression( 2556 ts.factory.createPropertyAccessExpression( 2557 node, 2558 ts.factory.createIdentifier(BUILDER_ATTR_BIND) 2559 ), 2560 undefined, 2561 [ts.factory.createThis()] 2562 ) 2563 ) 2564 ]); 2565} 2566 2567function processPropertyBuilderWithoutKey(node: ts.PropertyAccessExpression): ts.CallExpression { 2568 return ts.factory.createCallExpression( 2569 ts.factory.createPropertyAccessExpression( 2570 node, 2571 ts.factory.createIdentifier(BUILDER_ATTR_BIND) 2572 ), 2573 undefined, 2574 [ts.factory.createThis()] 2575 ); 2576} 2577 2578function processIdentifierBuilder(node: ts.Identifier): ts.ObjectLiteralExpression { 2579 return ts.factory.createObjectLiteralExpression([ 2580 ts.factory.createPropertyAssignment( 2581 ts.factory.createIdentifier(BUILDER_ATTR_NAME), 2582 ts.factory.createCallExpression( 2583 ts.factory.createPropertyAccessExpression(node, ts.factory.createIdentifier(BUILDER_ATTR_BIND)), 2584 undefined, [ts.factory.createThis()] 2585 ) 2586 ) 2587 ]); 2588} 2589 2590function processIdentifierBuilderWithoutKey(node: ts.Identifier): ts.CallExpression { 2591 return ts.factory.createCallExpression( 2592 ts.factory.createPropertyAccessExpression(node, ts.factory.createIdentifier(BUILDER_ATTR_BIND)), 2593 undefined, [ts.factory.createThis()] 2594 ); 2595} 2596 2597function getParsedBuilderAttrArgumentWithParams(node: ts.CallExpression): 2598 ts.ObjectLiteralExpression { 2599 const newArguments: ts.Expression[] = transDoubleDollarInCustomBuilder(node); 2600 return ts.factory.createObjectLiteralExpression([ 2601 ts.factory.createPropertyAssignment( 2602 ts.factory.createIdentifier(BUILDER_ATTR_NAME), 2603 ts.factory.createArrowFunction( 2604 undefined, 2605 undefined, 2606 [], 2607 undefined, 2608 ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), 2609 ts.factory.createBlock( 2610 [ts.factory.createExpressionStatement(ts.factory.createCallExpression( 2611 ts.factory.createPropertyAccessExpression(node.expression, ts.factory.createIdentifier(CALL) 2612 ), undefined, [ts.factory.createThis(), ...newArguments]))], 2613 true 2614 ) 2615 ) 2616 ) 2617 ]); 2618} 2619 2620function getParsedBuilderAttrArgumentWithParamsWithoutKey(node: ts.CallExpression): 2621 ts.ArrowFunction { 2622 const newArguments: ts.Expression[] = transDoubleDollarInCustomBuilder(node); 2623 return ts.factory.createArrowFunction( 2624 undefined, 2625 undefined, 2626 [], 2627 undefined, 2628 ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), 2629 ts.factory.createBlock( 2630 [ts.factory.createExpressionStatement(ts.factory.createCallExpression( 2631 ts.factory.createPropertyAccessExpression(node.expression, ts.factory.createIdentifier(CALL) 2632 ), undefined, [ts.factory.createThis(), ...newArguments]))], 2633 true 2634 ) 2635 ); 2636} 2637 2638function validatePropertyAccessExpressionWithCustomBuilder(node: ts.Node): boolean { 2639 return ts.isPropertyAccessExpression(node) && node.name && 2640 ts.isIdentifier(node.name) && CUSTOM_BUILDER_PROPERTIES.has(node.name.escapedText.toString()); 2641} 2642 2643function validateIdentifierWithCustomBuilder(node: ts.Node): boolean { 2644 return ts.isIdentifier(node) && CUSTOM_BUILDER_PROPERTIES.has(node.escapedText.toString()); 2645} 2646 2647function createArrowFunctionForDollar($$varExp: ts.Expression): ts.ArrowFunction { 2648 return ts.factory.createArrowFunction( 2649 undefined, undefined, 2650 [ts.factory.createParameterDeclaration( 2651 undefined, undefined, 2652 ts.factory.createIdentifier($$_NEW_VALUE), 2653 undefined, undefined, undefined 2654 )], 2655 undefined, 2656 ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), 2657 ts.factory.createBlock( 2658 [ts.factory.createExpressionStatement(ts.factory.createBinaryExpression( 2659 $$varExp, 2660 ts.factory.createToken(ts.SyntaxKind.EqualsToken), 2661 ts.factory.createIdentifier($$_NEW_VALUE) 2662 ))], 2663 false 2664 ) 2665 ); 2666} 2667 2668function updateArgumentForExclamation(argument): ts.Expression { 2669 if (ts.isNonNullExpression(argument) && ts.isNonNullExpression(argument.expression)) { 2670 return argument.expression.expression; 2671 } 2672 return argument; 2673} 2674 2675function updateArgumentForDollar(argument): ts.Expression { 2676 if (ts.isElementAccessExpression(argument)) { 2677 return ts.factory.updateElementAccessExpression( 2678 argument, updateArgumentForDollar(argument.expression), argument.argumentExpression); 2679 } else if (ts.isIdentifier(argument)) { 2680 if (argument.getText() === $$_THIS) { 2681 return ts.factory.createThis(); 2682 } else if (argument.getText().match(/^\$\$(.|\n)+/)) { 2683 return ts.factory.createIdentifier(argument.getText().replace(/\$\$/, '')); 2684 } 2685 } else if (ts.isPropertyAccessExpression(argument)) { 2686 return ts.factory.updatePropertyAccessExpression( 2687 argument, updateArgumentForDollar(argument.expression), argument.name); 2688 } 2689 return argument; 2690} 2691 2692function verifyComponentId(temp: any, node: ts.Identifier, propName: string, 2693 log: LogInfo[]): void { 2694 if (!newsupplement.isAcceleratePreview && propName === ATTRIBUTE_ID && 2695 ts.isStringLiteral(temp.arguments[0])) { 2696 const id: string = temp.arguments[0].text; 2697 const posOfNode: ts.LineAndCharacter = transformLog.sourceFile 2698 .getLineAndCharacterOfPosition(getRealNodePos(node)); 2699 const curFileName: string = transformLog.sourceFile.fileName.replace(/\.ts$/, ''); 2700 const rPath: string = path.resolve(projectConfig.projectPath, curFileName) 2701 .replace(/\\+/g, '/'); 2702 const rLine: number = posOfNode.line + 1; 2703 const rCol: number = posOfNode.character + 1; 2704 if (ID_ATTRS.has(id)) { 2705 const idInfo: Map<string, string | number> = ID_ATTRS.get(id); 2706 if (!(idInfo.get('path') === rPath && 2707 idInfo.get('line') === rLine && 2708 idInfo.get('col') === rCol)) { 2709 log.push({ 2710 type: LogType.WARN, 2711 message: `The current component id "${id}" is duplicate with ` + 2712 `${idInfo.get('path')}:${idInfo.get('line')}:${idInfo.get('col')}.`, 2713 pos: node.pos 2714 }); 2715 } 2716 } else { 2717 ID_ATTRS.set(id, new Map().set('path', rPath) 2718 .set('line', rLine) 2719 .set('col', rCol)); 2720 } 2721 } 2722} 2723 2724class StyleResult { 2725 doubleDollar: boolean = false; 2726 doubleExclamation: boolean = false; 2727} 2728 2729function isDoubleBind(styleResult: StyleResult, isStylesAttr: boolean, identifierNode: ts.Identifier, 2730 propName: string, temp: any): boolean { 2731 if (isDoubleDollarToChange(isStylesAttr, identifierNode, propName, temp)) { 2732 styleResult.doubleDollar = true; 2733 return true; 2734 } else if (isDoubleExclamationToChange(isStylesAttr, identifierNode, propName, temp)) { 2735 styleResult.doubleExclamation = true; 2736 return true; 2737 } 2738 return false; 2739} 2740 2741function addComponentAttr(temp, node: ts.Identifier, lastStatement, 2742 statements: ts.Statement[], identifierNode: ts.Identifier, log: LogInfo[], 2743 isStylesAttr: boolean, immutableStatements: ts.Statement[], updateStatements: ts.Statement[], 2744 newImmutableStatements: ts.Statement[] = null, isRecycleComponent: boolean = false, 2745 isReuseComponentInV2: boolean = false, isStyleFunction: boolean = false): void { 2746 const styleResult: StyleResult = new StyleResult(); 2747 const propName: string = node.getText(); 2748 verifyComponentId(temp, node, propName, log); 2749 const extendType: ExtendType = {type: ''}; 2750 if (propName === ATTRIBUTE_ANIMATION) { 2751 const animationNullNode: ts.ExpressionStatement = ts.factory.createExpressionStatement( 2752 createFunction(ts.factory.createIdentifier(GLOBAL_CONTEXT), node, 2753 // @ts-ignore 2754 [ts.factory.createNull()])); 2755 if (!lastStatement.statement) { 2756 if (!(temp.arguments.length === 1 && 2757 temp.arguments[0].kind === ts.SyntaxKind.NullKeyword)) { 2758 statements.push(animationNullNode); 2759 } 2760 } else { 2761 statements.push(lastStatement.statement, animationNullNode); 2762 } 2763 lastStatement.statement = ts.factory.createExpressionStatement(createFunction( 2764 ts.factory.createIdentifier(GLOBAL_CONTEXT), node, temp.arguments)); 2765 lastStatement.kind = false; 2766 lastStatement.hasAnimationAttr = true; 2767 } else if (GESTURE_ATTRS.has(propName)) { 2768 parseGesture(temp, propName, statements, log, updateStatements); 2769 lastStatement.kind = true; 2770 } else if (isExtendFunctionNode(identifierNode, propName, extendType)) { 2771 if (newsupplement.isAcceleratePreview) { 2772 log.push({ 2773 type: LogType.ERROR, 2774 message: `Doesn't support '@Extend' function now.`, 2775 pos: temp.getStart(), 2776 code: '10906205' 2777 }); 2778 } 2779 let functionName: string = ''; 2780 if (extendType.type === CHECK_COMPONENT_EXTEND_DECORATOR) { 2781 functionName = `__${identifierNode.escapedText.toString()}__${propName}`; 2782 } else { 2783 functionName = propName; 2784 } 2785 const extendNode: ts.Statement = ts.factory.createExpressionStatement( 2786 ts.factory.createCallExpression(ts.factory.createIdentifier(functionName), undefined, 2787 extendType.type === CHECK_COMPONENT_EXTEND_DECORATOR ? 2788 temp.arguments : 2789 [ 2790 ...temp.arguments, ts.factory.createIdentifier(ELMTID), 2791 ts.factory.createIdentifier(ISINITIALRENDER), 2792 ts.factory.createThis() 2793 ] 2794 )); 2795 statements.push(extendNode); 2796 updateStatements.push(extendNode); 2797 lastStatement.kind = true; 2798 } else if (propName === ATTRIBUTE_STATESTYLES) { 2799 if (temp.arguments.length === 1 && ts.isObjectLiteralExpression(temp.arguments[0])) { 2800 statements.push(createViewStackProcessor(temp, true)); 2801 if (isRecycleComponent) { 2802 updateStatements.push(createViewStackProcessor(temp, true)); 2803 } 2804 traverseStateStylesAttr(temp, statements, identifierNode, log, updateStatements, 2805 newImmutableStatements, isRecycleComponent); 2806 lastStatement.kind = true; 2807 } else { 2808 validateStateStyleSyntax(temp, log); 2809 } 2810 } else if (GLOBAL_STYLE_FUNCTION.has(propName) || INNER_STYLE_FUNCTION.has(propName)) { 2811 const styleBlock: ts.Block = 2812 INNER_STYLE_FUNCTION.get(propName) || GLOBAL_STYLE_FUNCTION.get(propName); 2813 if (styleBlock.statements.length > 0) { 2814 bindComponentAttr(styleBlock.statements[0] as ts.ExpressionStatement, identifierNode, 2815 statements, log, false, true, newImmutableStatements); 2816 if (isRecycleComponent) { 2817 bindComponentAttr(styleBlock.statements[0] as ts.ExpressionStatement, identifierNode, 2818 updateStatements, log, false, true, newImmutableStatements, true); 2819 } 2820 } 2821 lastStatement.kind = true; 2822 } else if (isDoubleBind(styleResult, isStylesAttr, identifierNode, propName, temp)) { 2823 const argumentsArr: ts.Expression[] = []; 2824 styleResult.doubleDollar ? classifyArgumentsNum(temp.arguments, argumentsArr, propName, identifierNode) : 2825 classifyArgumentsNumV2(temp.arguments, argumentsArr, propName, identifierNode); 2826 const doubleDollarNode: ts.Statement = ts.factory.createExpressionStatement( 2827 createFunction(identifierNode, node, argumentsArr)); 2828 statements.push(doubleDollarNode); 2829 updateStatements.push(doubleDollarNode); 2830 lastStatement.kind = true; 2831 } else { 2832 temp = loopEtscomponent(temp, isStylesAttr); 2833 if (propName !== RECYCLE_REUSE_ID && propName !== REUSE_ATTRIBUTE) { 2834 let isAttributeModifier: boolean = false; 2835 if ([ATTRIBUTE_ATTRIBUTE_MODIFIER, ATTRIBUTE_CONTENT_MODIFIER, 2836 ATTRIBUTE_MENUITEM_CONTENT_MODIFIER].includes(propName)) { 2837 isAttributeModifier = true; 2838 } 2839 const attrStatement: ts.Statement = ts.factory.createExpressionStatement( 2840 createFunction(identifierNode, node, temp.arguments, isAttributeModifier)); 2841 statements.push(attrStatement); 2842 if ((isRecycleComponent || isReuseComponentInV2) && (!isStylesAttr || isStyleFunction) && 2843 !isGestureType(identifierNode) && filterRegularAttrNode(temp.arguments)) { 2844 immutableStatements.push(attrStatement); 2845 } else { 2846 updateStatements.push(attrStatement); 2847 } 2848 } 2849 lastStatement.kind = true; 2850 } 2851} 2852 2853function isGestureType(node: ts.Identifier): boolean { 2854 return GESTURE_TYPE_NAMES.has(node.escapedText.toString()); 2855} 2856 2857function filterRegularAttrNode(argumentsNode: ts.NodeArray<ts.Expression>): boolean { 2858 return argumentsNode.every((argument: ts.Expression) => { 2859 return isRegularAttrNode(argument); 2860 }); 2861} 2862 2863type AttrResult = { isRegularNode: boolean }; 2864function isRegularAttrNode(node: ts.Expression): boolean { 2865 if (ts.isObjectLiteralExpression(node)) { 2866 return node.properties.every((propNode: ts.PropertyAssignment) => { 2867 if (propNode.initializer) { 2868 return isRegularAttrNode(propNode.initializer); 2869 } 2870 return false; 2871 }); 2872 } 2873 if (ts.isArrayLiteralExpression(node)) { 2874 return node.elements.every((child: ts.Expression) => { 2875 return isRegularAttrNode(child); 2876 }); 2877 } 2878 // literal e.g. 'hello', 1, true, false, () => {} 2879 if (isLiteralNode(node)) { 2880 return true; 2881 } 2882 // enum e.g. Color.Red 2883 if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.expression) && 2884 ts.isIdentifier(node.name)) { 2885 if (enumCollection.has(node.expression.escapedText.toString())) { 2886 return true; 2887 } 2888 if (globalProgram.checker) { 2889 const type: ts.Type = globalProgram.checker.getTypeAtLocation(node); 2890 /* Enum */ 2891 if (type.flags & (32 | 1024)) { 2892 return true; 2893 } 2894 } 2895 return false; 2896 } 2897 // regular variable, e.g. this.regularValue 2898 const result: AttrResult = { isRegularNode: false }; 2899 if (ts.isPropertyAccessExpression(node)) { 2900 traversePropNode(node, result); 2901 } 2902 return result.isRegularNode || false; 2903} 2904 2905function isLiteralNode(node: ts.Expression): boolean { 2906 return ts.isStringLiteral(node) || ts.isNumericLiteral(node) || ts.isArrowFunction(node) || 2907 [ts.SyntaxKind.TrueKeyword, ts.SyntaxKind.FalseKeyword].includes(node.kind); 2908} 2909 2910function isSimpleType(node: ts.PropertyAccessExpression): boolean { 2911 const symbol: ts.Symbol = getSymbolIfAliased(node); 2912 const simpleTypeCollection: ts.SyntaxKind[] = [ts.SyntaxKind.StringKeyword, ts.SyntaxKind.NumberKeyword, 2913 ts.SyntaxKind.BooleanKeyword]; 2914 if (symbol && symbol.declarations && symbol.declarations.length === 1 && ts.isPropertyDeclaration(symbol.declarations[0]) && 2915 symbol.declarations[0].type && symbol.declarations[0].type.kind && simpleTypeCollection.includes(symbol.declarations[0].type.kind)) { 2916 return true; 2917 } 2918 return false; 2919} 2920 2921function traversePropNode(node: ts.PropertyAccessExpression, result: AttrResult): void { 2922 const structInfo: StructInfo = processStructComponentV2.getOrCreateStructInfo(componentCollection.currentClassName); 2923 if (structInfo.isComponentV2 && node.expression.kind === ts.SyntaxKind.ThisKeyword && ts.isIdentifier(node.name) && 2924 structInfo.regularSet.has(node.name.escapedText.toString()) && isSimpleType(node)) { 2925 result.isRegularNode = true; 2926 return; 2927 } 2928 if (!structInfo.isComponentV2 && node.expression.kind === ts.SyntaxKind.ThisKeyword && ts.isIdentifier(node.name) && 2929 regularCollection.get(componentCollection.currentClassName).has(node.name.escapedText.toString())) { 2930 result.isRegularNode = true; 2931 return; 2932 } 2933 if (ts.isPropertyAccessExpression(node.expression)) { 2934 traversePropNode(node.expression, result); 2935 } 2936} 2937 2938function isDoubleDollarToChange(isStylesAttr: boolean, identifierNode: ts.Identifier, 2939 propName: string, temp): boolean { 2940 return !isStylesAttr && 2941 PROPERTIES_ADD_DOUBLE_DOLLAR.has(identifierNode.escapedText.toString()) && 2942 PROPERTIES_ADD_DOUBLE_DOLLAR.get(identifierNode.escapedText.toString()).has(propName) || 2943 STYLE_ADD_DOUBLE_DOLLAR.has(propName) && temp.arguments.length && temp.arguments[0] ? 2944 temp.arguments[0].getText().match(/^(?!\$\$\.)\$\$(.|\n)+/) !== null : 2945 false; 2946} 2947 2948function isDoubleExclamationToChange(isStylesAttr: boolean, identifierNode: ts.Identifier, propName: string, temp: ts.CallExpression): boolean { 2949 return !isStylesAttr && 2950 (STYLE_ADD_DOUBLE_EXCLAMATION.has(propName) && temp.arguments.length && temp.arguments[0] || 2951 PROPERTIES_ADD_DOUBLE_EXCLAMATION.has(identifierNode.escapedText.toString()) && 2952 PROPERTIES_ADD_DOUBLE_EXCLAMATION.get(identifierNode.escapedText.toString()).has(propName)) && 2953 ts.isNonNullExpression(temp.arguments[0]) && ts.isNonNullExpression(temp.arguments[0].expression) && 2954 !ts.isNonNullExpression(temp.arguments[0].expression.expression); 2955} 2956 2957function isHaveDoubleDollar(param: ts.PropertyAssignment, name: string): boolean { 2958 return ts.isPropertyAssignment(param) && param.name && ts.isIdentifier(param.name) && 2959 PROPERTIES_ADD_DOUBLE_DOLLAR.get(name).has(param.name.getText()) && param.initializer && 2960 param.initializer.getText().match(/^(?!\$\$\.)\$\$(.|\n)+/) !== null; 2961} 2962 2963function isHaveDoubleExclamation(param: ts.PropertyAssignment, name: string): boolean { 2964 return ts.isPropertyAssignment(param) && param.name && ts.isIdentifier(param.name) && 2965 PROPERTIES_ADD_DOUBLE_EXCLAMATION.has(name) && PROPERTIES_ADD_DOUBLE_EXCLAMATION.get(name).has(param.name.getText()) && 2966 param.initializer && ts.isNonNullExpression(param.initializer) && ts.isNonNullExpression(param.initializer.expression) && 2967 !ts.isNonNullExpression(param.initializer.expression.expression); 2968} 2969 2970function loopEtscomponent(node: any, isStylesAttr: boolean): ts.Node { 2971 node.arguments.forEach((item: ts.Node, index: number) => { 2972 if (ts.isEtsComponentExpression(item)) { 2973 node.arguments[index] = ts.factory.createCallExpression( 2974 item.expression, undefined, item.arguments); 2975 } else if ((ts.isCallExpression(item) || ts.isNewExpression(item)) && 2976 !newsupplement.isAcceleratePreview) { 2977 node.arguments[index] = ts.visitEachChild(item, 2978 changeEtsComponentKind, contextGlobal); 2979 } 2980 }); 2981 return node; 2982} 2983 2984function changeEtsComponentKind(node: ts.Node): ts.Node { 2985 if (ts.isEtsComponentExpression(node)) { 2986 node.kind = 204; 2987 return node; 2988 } 2989 return ts.visitEachChild(node, changeEtsComponentKind, contextGlobal); 2990} 2991 2992function classifyArgumentsNum(args, argumentsArr: ts.Expression[], propName: string, 2993 identifierNode: ts.Identifier): void { 2994 if (STYLE_ADD_DOUBLE_DOLLAR.has(propName) && args.length >= 2) { 2995 const varExp: ts.Expression = updateArgumentForDollar(args[0]); 2996 argumentsArr.push(generateObjectForDollar(varExp), ...args.slice(1)); 2997 } else if (STYLE_ADD_DOUBLE_EXCLAMATION.has(propName) && args.length >= 2) { 2998 const varExp: ts.Expression = updateArgumentForExclamation(args[0]); 2999 argumentsArr.push(generateObjectForExclamation(varExp), ...args.slice(1)); 3000 } else if (PROPERTIES_ADD_DOUBLE_DOLLAR.has(identifierNode.escapedText.toString()) && args.length === 1 && 3001 PROPERTIES_ADD_DOUBLE_DOLLAR.get(identifierNode.escapedText.toString()).has(propName) || 3002 STYLE_ADD_DOUBLE_DOLLAR.has(propName) && args.length === 1) { 3003 const varExp: ts.Expression = updateArgumentForDollar(args[0]); 3004 argumentsArr.push(varExp, createArrowFunctionForDollar(varExp)); 3005 } 3006} 3007 3008function classifyArgumentsNumV2(args: any, argumentsArr: ts.Expression[], propName: string, 3009 identifierNode: ts.Identifier): void { 3010 const componentName: string = identifierNode.escapedText.toString(); 3011 if (STYLE_ADD_DOUBLE_EXCLAMATION.has(propName) && args.length || 3012 PROPERTIES_ADD_DOUBLE_EXCLAMATION.has(componentName) && args.length === 1 && 3013 PROPERTIES_ADD_DOUBLE_EXCLAMATION.get(componentName).has(propName)) { 3014 const varExp: ts.Expression = updateArgumentForExclamation(args[0]); 3015 argumentsArr.push(generateObjectForExclamation(varExp), ...args.slice(1)); 3016 } 3017} 3018 3019function generateObjectForExclamation(varExp: ts.Expression): ts.ObjectLiteralExpression { 3020 return ts.factory.createObjectLiteralExpression([ 3021 ts.factory.createPropertyAssignment( 3022 ts.factory.createIdentifier($$_VALUE), 3023 varExp), 3024 ts.factory.createPropertyAssignment( 3025 ts.factory.createIdentifier($_VALUE), 3026 ts.factory.createArrowFunction( 3027 undefined, undefined, 3028 [ts.factory.createParameterDeclaration( 3029 undefined, undefined, 3030 ts.factory.createIdentifier($$_NEW_VALUE), 3031 undefined, undefined, undefined 3032 )], 3033 undefined, 3034 ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), 3035 ts.factory.createBlock( 3036 [ts.factory.createExpressionStatement(ts.factory.createBinaryExpression( 3037 varExp, 3038 ts.factory.createToken(ts.SyntaxKind.EqualsToken), 3039 ts.factory.createIdentifier($$_NEW_VALUE) 3040 ))], false) 3041 ))], false); 3042} 3043 3044function generateObjectForDollar(varExp: ts.Expression): ts.ObjectLiteralExpression { 3045 return ts.factory.createObjectLiteralExpression( 3046 [ 3047 ts.factory.createPropertyAssignment( 3048 ts.factory.createIdentifier($$_VALUE), 3049 varExp 3050 ), 3051 ts.factory.createPropertyAssignment( 3052 ts.factory.createIdentifier($$_CHANGE_EVENT), 3053 createArrowFunctionForDollar(varExp) 3054 ) 3055 ], 3056 false 3057 ); 3058} 3059 3060function generateFunctionPropertyAssignmentForExclamation(name: string, varExp: ts.Expression): ts.PropertyAssignment { 3061 return ts.factory.createPropertyAssignment( 3062 ts.factory.createIdentifier('$' + name), 3063 createArrowFunctionForDollar(varExp) 3064 ); 3065} 3066 3067function createViewStackProcessor(item, endViewStack: boolean): ts.ExpressionStatement { 3068 const argument: ts.StringLiteral[] = []; 3069 if (!endViewStack && item.name) { 3070 argument.push(ts.factory.createStringLiteral(item.name.getText())); 3071 } 3072 return ts.factory.createExpressionStatement(ts.factory.createCallExpression( 3073 ts.factory.createPropertyAccessExpression( 3074 ts.factory.createIdentifier(VIEW_STACK_PROCESSOR), 3075 ts.factory.createIdentifier(VISUAL_STATE) 3076 ), 3077 undefined, 3078 argument 3079 )); 3080} 3081 3082function traverseStateStylesAttr(temp, statements: ts.Statement[], 3083 identifierNode: ts.Identifier, log: LogInfo[], updateStatements: ts.Statement[], 3084 newImmutableStatements: ts.Statement[] = null, isRecycleComponent: boolean = false): void { 3085 temp.arguments[0].properties.reverse().forEach((item: ts.PropertyAssignment) => { 3086 if (ts.isPropertyAccessExpression(item.initializer) && 3087 item.initializer.expression.getText() === THIS && 3088 INNER_STYLE_FUNCTION.get(item.initializer.name.getText())) { 3089 const name: string = item.initializer.name.getText(); 3090 bindComponentAttr(INNER_STYLE_FUNCTION.get(name).statements[0] as ts.ExpressionStatement, 3091 identifierNode, statements, log, false, true, newImmutableStatements); 3092 if (isRecycleComponent) { 3093 bindComponentAttr(INNER_STYLE_FUNCTION.get(name).statements[0] as ts.ExpressionStatement, 3094 identifierNode, updateStatements, log, false, true, newImmutableStatements); 3095 } 3096 } else if (ts.isIdentifier(item.initializer) && 3097 GLOBAL_STYLE_FUNCTION.get(item.initializer.getText())) { 3098 const name: string = item.initializer.getText(); 3099 bindComponentAttr(GLOBAL_STYLE_FUNCTION.get(name).statements[0] as ts.ExpressionStatement, 3100 identifierNode, statements, log, false, true, newImmutableStatements); 3101 if (isRecycleComponent) { 3102 bindComponentAttr(GLOBAL_STYLE_FUNCTION.get(name).statements[0] as ts.ExpressionStatement, 3103 identifierNode, updateStatements, log, false, true, newImmutableStatements); 3104 } 3105 } else if (ts.isObjectLiteralExpression(item.initializer) && 3106 item.initializer.properties.length === 1 && 3107 ts.isPropertyAssignment(item.initializer.properties[0])) { 3108 bindComponentAttr(ts.factory.createExpressionStatement( 3109 item.initializer.properties[0].initializer), identifierNode, statements, log, false, true, 3110 newImmutableStatements); 3111 if (isRecycleComponent) { 3112 bindComponentAttr(ts.factory.createExpressionStatement( 3113 item.initializer.properties[0].initializer), identifierNode, updateStatements, log, false, true, 3114 newImmutableStatements); 3115 } 3116 } else { 3117 if (!(ts.isObjectLiteralExpression(item.initializer) && item.initializer.properties.length === 0)) { 3118 validateStateStyleSyntax(temp, log); 3119 } 3120 } 3121 if (item.name) { 3122 const viewNode: ts.Statement = createViewStackProcessor(item, false); 3123 statements.push(viewNode); 3124 if (isRecycleComponent) { 3125 updateStatements.push(viewNode); 3126 } 3127 } 3128 }); 3129} 3130 3131interface ExtendType { 3132 type: string 3133} 3134 3135function isExtendFunctionNode(identifierNode: ts.Identifier, propName: string, 3136 extendType: ExtendType): boolean { 3137 const componentName: string = identifierNode.escapedText.toString(); 3138 if (EXTEND_ATTRIBUTE.has(componentName) && [...EXTEND_ATTRIBUTE.get(componentName)].includes(propName)) { 3139 extendType.type = CHECK_COMPONENT_EXTEND_DECORATOR; 3140 return true; 3141 } 3142 const animatableExtendAttribute: Map<string, Set<string>> = 3143 storedFileInfo.getCurrentArkTsFile().animatableExtendAttribute; 3144 if (animatableExtendAttribute.has(componentName) && 3145 [...animatableExtendAttribute.get(componentName)].includes(propName)) { 3146 extendType.type = CHECK_COMPONENT_ANIMATABLE_EXTEND_DECORATOR; 3147 return true; 3148 } 3149 return false; 3150} 3151 3152const gestureMap: Map<string, string> = new Map([ 3153 [PRIORITY_GESTURE_ATTRIBUTE, GESTURE_ENUM_VALUE_HIGH], 3154 [PARALLEL_GESTURE_ATTRIBUTE, GESTURE_ENUM_VALUE_PARALLEL], 3155 [GESTURE_ATTRIBUTE, GESTURE_ENUM_VALUE_LOW] 3156]); 3157 3158function parseGesture(node: ts.CallExpression, propName: string, statements: ts.Statement[], 3159 log: LogInfo[], updateStatements: ts.Statement[]): void { 3160 const popNode: ts.Statement = ts.factory.createExpressionStatement( 3161 createFunction(ts.factory.createIdentifier(COMPONENT_GESTURE), 3162 ts.factory.createIdentifier(COMPONENT_POP_FUNCTION), null)); 3163 statements.push(popNode); 3164 updateStatements.push(popNode); 3165 parseGestureInterface(node, statements, log, updateStatements); 3166 const argumentArr: ts.NodeArray<ts.PropertyAccessExpression> = ts.factory.createNodeArray( 3167 [ts.factory.createPropertyAccessExpression( 3168 ts.factory.createIdentifier(GESTURE_ENUM_KEY), 3169 ts.factory.createIdentifier(gestureMap.get(propName))) 3170 ] 3171 ); 3172 if (node.arguments && node.arguments.length > 1 && 3173 ts.isPropertyAccessExpression(node.arguments[1])) { 3174 // @ts-ignore 3175 argumentArr.push(node.arguments[1]); 3176 } 3177 const createNode: ts.Statement = ts.factory.createExpressionStatement( 3178 createFunction(ts.factory.createIdentifier(COMPONENT_GESTURE), 3179 ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION), argumentArr)); 3180 statements.push(createNode); 3181 updateStatements.push(createNode); 3182} 3183 3184function processGestureType(node: ts.CallExpression, statements: ts.Statement[], log: LogInfo[], 3185 updateStatements: ts.Statement[], reverse: boolean = false): void { 3186 const newStatements: ts.Statement[] = []; 3187 const newNode: ts.ExpressionStatement = ts.factory.createExpressionStatement(node); 3188 let temp = node.expression; 3189 while (temp && !ts.isIdentifier(temp) && temp.expression) { 3190 temp = temp.expression; 3191 } 3192 if (temp && temp.parent && ts.isCallExpression(temp.parent) && ts.isIdentifier(temp) && 3193 GESTURE_TYPE_NAMES.has(temp.escapedText.toString())) { 3194 newStatements.push(ts.factory.createExpressionStatement( 3195 createFunction(temp, ts.factory.createIdentifier(COMPONENT_POP_FUNCTION), null))); 3196 if (temp.escapedText.toString() === COMPONENT_GESTURE_GROUP) { 3197 const gestureStatements: ts.Statement[] = []; 3198 parseGestureInterface(temp.parent, gestureStatements, log, [], true); 3199 newStatements.push(...gestureStatements.reverse()); 3200 bindComponentAttr(newNode, temp, newStatements, log, false); 3201 let argumentArr: ts.NodeArray<ts.Expression> = null; 3202 if (temp.parent.arguments && temp.parent.arguments.length) { 3203 // @ts-ignore 3204 argumentArr = ts.factory.createNodeArray([temp.parent.arguments[0]]); 3205 } 3206 newStatements.push(ts.factory.createExpressionStatement( 3207 createFunction(temp, ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION), argumentArr))); 3208 } else { 3209 bindComponentAttr(newNode, temp, newStatements, log, false); 3210 newStatements.push(ts.factory.createExpressionStatement( 3211 createFunction(temp, ts.factory.createIdentifier(COMPONENT_CREATE_FUNCTION), temp.parent.arguments))); 3212 } 3213 } 3214 if (newStatements.length) { 3215 reverse ? statements.push(...newStatements.reverse()) : statements.push(...newStatements); 3216 reverse ? updateStatements.push(...newStatements.reverse()) : updateStatements.push(...newStatements); 3217 } 3218} 3219 3220function parseGestureInterface(node: ts.CallExpression, statements: ts.Statement[], log: LogInfo[], 3221 updateStatements: ts.Statement[], reverse: boolean = false): void { 3222 if (node.arguments && node.arguments.length) { 3223 node.arguments.forEach((item: ts.Node) => { 3224 if (ts.isCallExpression(item)) { 3225 processGestureType(item, statements, log, updateStatements, reverse); 3226 } 3227 }); 3228 } 3229} 3230 3231export function getName(node: ts.ExpressionStatement | ts.Expression): string { 3232 // @ts-ignore 3233 let temp = node.expression; 3234 let name: string; 3235 while (temp) { 3236 if (ts.isIdentifier(temp) && temp.parent && (ts.isCallExpression(temp.parent) || 3237 ts.isEtsComponentExpression(temp.parent))) { 3238 name = temp.escapedText.toString(); 3239 break; 3240 } else if (ts.isPropertyAccessExpression(temp) && temp.name && ts.isIdentifier(temp.name) && 3241 isCustomAttributes(temp)) { 3242 name = temp.name.escapedText.toString(); 3243 break; 3244 } 3245 temp = temp.expression; 3246 } 3247 return name; 3248} 3249 3250function isCustomAttributes(temp: ts.PropertyAccessExpression): boolean { 3251 if (temp.expression && temp.expression.getText() === THIS) { 3252 return true; 3253 } else if (temp.expression && ts.isIdentifier(temp.expression) && temp.expression.getText() === $$ && 3254 builderTypeParameter.params.includes(temp.expression.getText())) { 3255 return true; 3256 } else { 3257 return !BUILDIN_STYLE_NAMES.has(temp.name.escapedText.toString()); 3258 } 3259} 3260 3261export function isAttributeNode(node: ts.ExpressionStatement): boolean { 3262 let temp: any = node.expression; 3263 let name: string; 3264 while (temp) { 3265 if (ts.isCallExpression(temp) && temp.expression && ts.isIdentifier(temp.expression)) { 3266 name = temp.expression.escapedText.toString(); 3267 break; 3268 } 3269 temp = temp.expression; 3270 } 3271 return BUILDIN_STYLE_NAMES.has(name); 3272} 3273 3274enum ComponentType { 3275 innerComponent, 3276 customComponent, 3277 forEachComponent, 3278 customBuilderMethod, 3279 builderParamMethod, 3280 function, 3281 builderTypeFunction, 3282 repeatComponent 3283} 3284 3285function isEtsComponent(node: ts.ExpressionStatement): boolean { 3286 let isEtsComponent: boolean = false; 3287 let temp: any = node.expression; 3288 while (temp) { 3289 if (ts.isEtsComponentExpression(temp)) { 3290 isEtsComponent = true; 3291 } 3292 temp = temp.expression; 3293 } 3294 return isEtsComponent; 3295} 3296 3297function isSomeName(forEachParameters: ts.NodeArray<ts.ParameterDeclaration>, name: string): boolean { 3298 return Array.isArray(forEachParameters) && 3299 forEachParameters.some((item) => { 3300 return ts.isIdentifier(item.name) ? item.name.escapedText.toString() === name : false; 3301 }); 3302} 3303 3304function isParamFunction(node: ts.ExpressionStatement): boolean { 3305 return node.expression && ts.isCallExpression(node.expression) && 3306 node.expression.expression && ts.isIdentifier(node.expression.expression); 3307} 3308 3309function getComponentType(node: ts.ExpressionStatement, log: LogInfo[], name: string, 3310 parent: string, forEachParameters: ts.NodeArray<ts.ParameterDeclaration> = undefined): ComponentType { 3311 let isBuilderName: boolean = true; 3312 let isLocalBuilderName: boolean = true; 3313 if (forEachParameters && isSomeName(forEachParameters, name) && isParamFunction(node)) { 3314 isBuilderName = false; 3315 isLocalBuilderName = false; 3316 } 3317 if (isEtsComponent(node)) { 3318 if (componentCollection.customComponents.has(name)) { 3319 isCustomComponentAttributes(node, log); 3320 return ComponentType.customComponent; 3321 } else { 3322 return ComponentType.innerComponent; 3323 } 3324 } else if (!isPartMethod(node) && componentCollection.customComponents.has(name)) { 3325 isCustomComponentAttributes(node, log); 3326 return ComponentType.customComponent; 3327 } else if (name === COMPONENT_FOREACH || name === COMPONENT_LAZYFOREACH) { 3328 return ComponentType.forEachComponent; 3329 } else if (name === COMPONENT_REPEAT) { 3330 return ComponentType.repeatComponent; 3331 } else if (isLocalBuilderOrBuilderMethod(CUSTOM_BUILDER_METHOD, isBuilderName, name) || isWrappedBuilderExpression(node) || 3332 isLocalBuilderOrBuilderMethod(INNER_CUSTOM_LOCALBUILDER_METHOD, isLocalBuilderName, name)) { 3333 return ComponentType.customBuilderMethod; 3334 } else if (builderParamObjectCollection.get(componentCollection.currentClassName) && 3335 builderParamObjectCollection.get(componentCollection.currentClassName).has(name)) { 3336 return ComponentType.builderParamMethod; 3337 } else if (!partialUpdateConfig.builderCheck && builderTypeParameter.params.includes(name) && 3338 judgeBuilderType(node)) { 3339 return ComponentType.builderTypeFunction; 3340 } else if ((['XComponent'].includes(parent) || CUSTOM_BUILDER_METHOD.has(parent)) && 3341 ts.isCallExpression(node.expression) && ts.isIdentifier(node.expression.expression)) { 3342 return ComponentType.function; 3343 } else if (!isAttributeNode(node)) { 3344 log.push({ 3345 type: LogType.ERROR, 3346 message: `'${node.getText()}' does not meet UI component syntax.`, 3347 pos: node.getStart(), 3348 code: '10905204' 3349 }); 3350 } 3351 return null; 3352} 3353 3354function isCustomComponentAttributes(node: ts.ExpressionStatement, log: LogInfo[]): void { 3355 if (node.expression && ts.isCallExpression(node.expression) && ts.isPropertyAccessExpression(node.expression.expression) && 3356 ts.isIdentifier(node.expression.expression.name) && !COMMON_ATTRS.has(node.expression.expression.name.escapedText.toString())) { 3357 log.push({ 3358 type: LogType.ERROR, 3359 message: `'${node.getText()}' does not meet UI component syntax.`, 3360 pos: node.getStart() 3361 }); 3362 } 3363} 3364 3365function isLocalBuilderOrBuilderMethod(LocalBuilderOrBuilderSet: Set<string>, 3366 isLocalBuilderOrBuilderName: boolean, name: string): boolean { 3367 return LocalBuilderOrBuilderSet.has(name) && isLocalBuilderOrBuilderName; 3368} 3369 3370function isPartMethod(node: ts.ExpressionStatement): boolean { 3371 if (ts.isCallExpression(node.expression) && ts.isPropertyAccessExpression(node.expression.expression) && 3372 node.expression.expression.expression && node.expression.expression.expression.kind && 3373 node.expression.expression.expression.kind === ts.SyntaxKind.ThisKeyword) { 3374 return true; 3375 } else { 3376 return false; 3377 } 3378} 3379 3380function isWrappedBuilderExpression(node: ts.ExpressionStatement): boolean { 3381 if (projectConfig.minAPIVersion >= 11 && node.expression && 3382 isWrappedBuilderCallExpression(node.expression as ts.CallExpression)) { 3383 return true; 3384 } 3385 return false; 3386} 3387 3388function judgeBuilderType(node: ts.ExpressionStatement): boolean { 3389 let checker: ts.TypeChecker; 3390 if (globalProgram.program) { 3391 checker = globalProgram.program.getTypeChecker(); 3392 } else if (globalProgram.watchProgram) { 3393 checker = globalProgram.watchProgram.getCurrentProgram().getProgram().getTypeChecker(); 3394 } 3395 if (node.expression && node.expression.expression && checker) { 3396 const type: ts.Type = checker.getTypeAtLocation(node.expression.expression); 3397 if (type && type.aliasSymbol && type.aliasSymbol.escapedName === BUILDER_TYPE) { 3398 return true; 3399 } 3400 } 3401 return false; 3402} 3403 3404export function validateStateStyleSyntax(temp, log: LogInfo[]): void { 3405 log.push({ 3406 type: LogType.ERROR, 3407 message: `'.stateStyles' doesn't conform standard.`, 3408 pos: temp.getStart(), 3409 code: '10905203' 3410 }); 3411} 3412 3413function getEtsComponentExpression(node:ts.ExpressionStatement): ts.EtsComponentExpression { 3414 let current = node.expression; 3415 while (current) { 3416 if (ts.isEtsComponentExpression(current)) { 3417 return current; 3418 } 3419 current = current.expression; 3420 } 3421 return null; 3422} 3423 3424function checkEtsAndIdInIf(node:ts.ExpressionStatement, parent: string): [ts.EtsComponentExpression, ts.Expression] { 3425 let current = node.expression; 3426 let idName: ts.Expression; 3427 while (current) { 3428 if (ts.isEtsComponentExpression(current)) { 3429 break; 3430 } 3431 if (!idName && parent === COMPONENT_IF && ts.isPropertyAccessExpression(current) && current.name && 3432 ts.isIdentifier(current.name) && current.name.escapedText.toString() === ATTRIBUTE_ID && 3433 current.parent && current.parent.arguments && current.parent.arguments.length) { 3434 idName = current.parent.arguments[0]; 3435 } 3436 current = current.expression; 3437 } 3438 return [current, idName]; 3439} 3440 3441function checkIdInIf(node:ts.ExpressionStatement, parent: string): ts.Expression { 3442 let current: any = node.expression; 3443 let idName: ts.Expression; 3444 while (current) { 3445 if (parent === COMPONENT_IF && ts.isPropertyAccessExpression(current) && current.name && 3446 ts.isIdentifier(current.name) && current.name.escapedText.toString() === ATTRIBUTE_ID && 3447 current.parent && current.parent.arguments && current.parent.arguments.length) { 3448 idName = current.parent.arguments[0]; 3449 break; 3450 } 3451 current = current.expression; 3452 } 3453 return idName; 3454} 3455 3456function checkEtsComponent(node: ts.ExpressionStatement, log: LogInfo[]): void { 3457 const etsComponentExpression: ts.EtsComponentExpression = getEtsComponentExpression(node); 3458 if (etsComponentExpression) { 3459 checkAllNode( 3460 etsComponentExpression, 3461 new Set([...INNER_COMPONENT_NAMES, ...componentCollection.customComponents]), 3462 transformLog.sourceFile, 3463 log 3464 ); 3465 } 3466} 3467 3468function checkButtonParamHasLabel(node: ts.EtsComponentExpression, log: LogInfo[]): void { 3469 if (node.arguments && node.arguments.length !== 0) { 3470 for (let i = 0; i < node.arguments.length; i++) { 3471 const argument: ts.Expression = node.arguments[i]; 3472 if (ts.isStringLiteral(argument) || (ts.isCallExpression(argument) && ts.isIdentifier(argument.expression) && 3473 (argument.expression.escapedText.toString() === RESOURCE))) { 3474 log.push({ 3475 type: LogType.ERROR, 3476 message: 'The Button component with a label parameter can not have any child.', 3477 pos: node.getStart(), 3478 code: '10905202' 3479 }); 3480 return; 3481 } 3482 } 3483 } 3484} 3485 3486function isLazyForEachChild(node: ts.ExpressionStatement): boolean { 3487 let temp = node.parent; 3488 while (temp && !ts.isEtsComponentExpression(temp) && !ts.isCallExpression(temp)) { 3489 temp = temp.parent; 3490 } 3491 if (temp && temp.expression && (temp.expression as ts.Identifier).escapedText?.toString() === COMPONENT_LAZYFOREACH) { 3492 return true; 3493 } 3494 return false; 3495} 3496 3497function processDollarEtsComponent(argumentsArr: ts.NodeArray<ts.Expression>, name: string): ts.Expression[] { 3498 const arr: ts.Expression[] = []; 3499 argumentsArr.forEach((item: ts.Expression, index: number) => { 3500 if (ts.isObjectLiteralExpression(item) && item.properties && item.properties.length) { 3501 const properties: ts.PropertyAssignment[] = []; 3502 item.properties.forEach((param: ts.PropertyAssignment, paramIndex: number) => { 3503 if (isHaveDoubleDollar(param, name)) { 3504 const varExp: ts.Expression = updateArgumentForDollar(param.initializer); 3505 properties.push(ts.factory.updatePropertyAssignment(param, param.name, generateObjectForDollar(varExp))); 3506 } else { 3507 properties.push(param); 3508 } 3509 }); 3510 arr.push(ts.factory.updateObjectLiteralExpression(item, properties)); 3511 } else { 3512 arr.push(item); 3513 } 3514 }); 3515 return arr; 3516} 3517 3518function processExclamationEtsComponent(argumentsArr: ts.NodeArray<ts.Expression>, name: string): ts.Expression[] { 3519 const arr: ts.Expression[] = []; 3520 argumentsArr.forEach((item: ts.Expression, index: number) => { 3521 if (ts.isObjectLiteralExpression(item) && item.properties && item.properties.length) { 3522 const properties: ts.PropertyAssignment[] = []; 3523 item.properties.forEach((param: ts.PropertyAssignment, paramIndex: number) => { 3524 if (isHaveDoubleExclamation(param, name) && param.initializer && param.name) { 3525 const varExp: ts.Expression = updateArgumentForExclamation(param.initializer); 3526 properties.push(ts.factory.updatePropertyAssignment(param, param.name, varExp)); 3527 properties.push(generateFunctionPropertyAssignmentForExclamation(param.name.getText(), varExp)); 3528 } else { 3529 properties.push(param); 3530 } 3531 }); 3532 arr.push(ts.factory.updateObjectLiteralExpression(item, properties)); 3533 } else { 3534 arr.push(item); 3535 } 3536 }); 3537 return arr; 3538} 3539 3540export function createFunction(node: ts.Identifier, attrNode: ts.Identifier, 3541 argumentsArr: ts.NodeArray<ts.Expression>, isAttributeModifier: boolean = false): ts.CallExpression { 3542 const compName: string = node.escapedText.toString(); 3543 const type: string = attrNode.escapedText.toString(); 3544 if (argumentsArr && argumentsArr.length) { 3545 if (type === COMPONENT_CREATE_FUNCTION && PROPERTIES_ADD_DOUBLE_DOLLAR.has(compName)) { 3546 // @ts-ignore 3547 argumentsArr = processDollarEtsComponent(argumentsArr, compName); 3548 } 3549 if (type === COMPONENT_CREATE_FUNCTION && PROPERTIES_ADD_DOUBLE_EXCLAMATION.has(compName)) { 3550 argumentsArr = processExclamationEtsComponent(argumentsArr, compName) as unknown as ts.NodeArray<ts.Expression>; 3551 } 3552 if (checkCreateArgumentBuilder(node, attrNode)) { 3553 argumentsArr = transformBuilder(argumentsArr); 3554 } 3555 if (compName === NAVIGATION && type === COMPONENT_CREATE_FUNCTION && partialUpdateConfig.partialUpdateMode) { 3556 // @ts-ignore 3557 argumentsArr = navigationCreateParam(compName, type, argumentsArr); 3558 } 3559 } else { 3560 // @ts-ignore 3561 argumentsArr = navigationCreateParam(compName, type); 3562 } 3563 return ts.factory.createCallExpression( 3564 isAttributeModifier ? ts.factory.createCallExpression( 3565 ts.factory.createPropertyAccessExpression( 3566 ts.factory.createPropertyAccessExpression( 3567 node, 3568 attrNode 3569 ), 3570 ts.factory.createIdentifier(BUILDER_ATTR_BIND) 3571 ), 3572 undefined, 3573 [ts.factory.createThis()] 3574 ) : 3575 ts.factory.createPropertyAccessExpression( 3576 node, 3577 attrNode 3578 ), 3579 undefined, 3580 argumentsArr 3581 ); 3582} 3583 3584function navigationCreateParam(compName: string, type: string, 3585 argumentsArr: ts.NodeArray<ts.Expression> = undefined, isNavDestinationCallback: boolean = false): 3586 (ts.ObjectLiteralExpression | ts.NewExpression | ts.ArrowFunction)[] | [] { 3587 const navigationOrNavDestination: (ts.ObjectLiteralExpression | ts.NewExpression | ts.ArrowFunction)[] = []; 3588 const isCreate: boolean = type === COMPONENT_CREATE_FUNCTION; 3589 const partialUpdateMode: boolean = partialUpdateConfig.partialUpdateMode; 3590 let isHaveParam: boolean = true; 3591 if (argumentsArr && argumentsArr.length) { 3592 // @ts-ignore 3593 navigationOrNavDestination.push(...argumentsArr); 3594 } else if (partialUpdateMode && isCreate) { 3595 if (compName === NAVIGATION) { 3596 isHaveParam = false; 3597 navigationOrNavDestination.push(ts.factory.createNewExpression( 3598 ts.factory.createIdentifier(NAV_PATH_STACK), undefined, [] 3599 )); 3600 } else if (compName === NAV_DESTINATION && !isNavDestinationCallback) { 3601 navigationOrNavDestination.push(ts.factory.createArrowFunction( 3602 undefined, undefined, [], undefined, 3603 ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), 3604 ts.factory.createBlock( 3605 [], 3606 false 3607 ) 3608 )); 3609 } 3610 } 3611 if (CREATE_ROUTER_COMPONENT_COLLECT.has(compName) && isCreate && partialUpdateMode) { 3612 navigationOrNavDestination.push(ts.factory.createObjectLiteralExpression( 3613 navigationOrNavDestinationCreateContent(compName, isHaveParam), 3614 false 3615 )); 3616 } 3617 return navigationOrNavDestination; 3618} 3619 3620function navigationOrNavDestinationCreateContent(compName: string, isHaveParam: boolean): ts.PropertyAssignment[] { 3621 const navigationOrNavDestinationContent: ts.PropertyAssignment[] = []; 3622 navigationOrNavDestinationContent.push(ts.factory.createPropertyAssignment( 3623 ts.factory.createIdentifier(RESOURCE_NAME_MODULE), 3624 ts.factory.createStringLiteral(projectConfig.moduleName || '') 3625 ), 3626 ts.factory.createPropertyAssignment( 3627 ts.factory.createIdentifier(PAGE_PATH), 3628 ts.factory.createStringLiteral( 3629 projectConfig.compileHar ? '' : 3630 path.relative(projectConfig.projectRootPath || '', resourceFileName).replace(/\\/g, '/').replace(/\.ets$/, '') 3631 ) 3632 )); 3633 if (compName === NAVIGATION) { 3634 navigationOrNavDestinationContent.push(ts.factory.createPropertyAssignment( 3635 ts.factory.createIdentifier(IS_USER_CREATE_STACK), 3636 isHaveParam ? ts.factory.createTrue() : ts.factory.createFalse() 3637 )); 3638 } 3639 return navigationOrNavDestinationContent; 3640} 3641 3642function checkCreateArgumentBuilder(node: ts.Identifier, attrNode: ts.Identifier): boolean { 3643 if (attrNode.escapedText.toString() === COMPONENT_CREATE_FUNCTION && 3644 CREATE_BIND_COMPONENT.has(node.escapedText.toString())) { 3645 return true; 3646 } 3647 return false; 3648} 3649 3650function transformBuilder(argumentsArr: ts.NodeArray<ts.Expression>): ts.NodeArray<ts.Expression> { 3651 const newArguments: ts.Expression[] = []; 3652 argumentsArr.forEach((argument: ts.Expression) => { 3653 newArguments.push(parseCreateParameterBuilder(argument)); 3654 }); 3655 // @ts-ignore 3656 return newArguments; 3657} 3658 3659function parseCreateParameterBuilder(argument: ts.Expression):ts.Expression { 3660 if (ts.isObjectLiteralExpression(argument)) { 3661 return processObjectPropertyBuilder(argument); 3662 } else { 3663 return argument; 3664 } 3665} 3666 3667function checkNonspecificParents(node: ts.ExpressionStatement, name: string, savedParent: string, log: LogInfo[]): void { 3668 if (SPECIFIC_PARENT_COMPONENT.has(name)) { 3669 const specificParemtsSet: Set<string> = SPECIFIC_PARENT_COMPONENT.get(name); 3670 if (!specificParemtsSet.has(savedParent) && INNER_COMPONENT_NAMES.has(savedParent)) { 3671 const specificParentArray: string = 3672 Array.from(SPECIFIC_PARENT_COMPONENT.get(name)).join(','); 3673 log.push({ 3674 type: LogType.ERROR, 3675 message: `The '${name}' component can only be nested in the '${specificParentArray}' parent component.`, 3676 pos: node.expression.getStart(), 3677 code: '10905201' 3678 }); 3679 } 3680 } 3681} 3682