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