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