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