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