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