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