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'; 18import fs from 'fs'; 19 20import { 21 PAGE_ENTRY_FUNCTION_NAME, 22 PREVIEW_COMPONENT_FUNCTION_NAME, 23 STORE_PREVIEW_COMPONENTS, 24 GET_PREVIEW_FLAG_FUNCTION_NAME, 25 COMPONENT_CONSTRUCTOR_UNDEFINED, 26 BUILD_ON, 27 COMPONENT_BUILDER_DECORATOR, 28 COMPONENT_CONCURRENT_DECORATOR, 29 COMPONENT_SENDABLE_DECORATOR, 30 COMPONENT_EXTEND_DECORATOR, 31 COMPONENT_STYLES_DECORATOR, 32 RESOURCE, 33 RESOURCE_TYPE, 34 WORKER_OBJECT, 35 RESOURCE_NAME_ID, 36 RESOURCE_NAME_TYPE, 37 RESOURCE_NAME_PARAMS, 38 RESOURCE_RAWFILE, 39 RESOURCE_NAME_BUNDLE, 40 RESOURCE_NAME_MODULE, 41 ATTRIBUTE_ANIMATETO_SET, 42 GLOBAL_CONTEXT, 43 INSTANCE, 44 SET_CONTROLLER_CTR_TYPE, 45 SET_CONTROLLER_METHOD, 46 JS_DIALOG, 47 CUSTOM_DIALOG_CONTROLLER_BUILDER, 48 ESMODULE, 49 EXTNAME_ETS, 50 GENERATE_ID, 51 _GENERATE_ID, 52 VIEWSTACKPROCESSOR, 53 STARTGETACCESSRECORDINGFOR, 54 ALLOCATENEWELMETIDFORNEXTCOMPONENT, 55 STOPGETACCESSRECORDING, 56 CARD_ENTRY_FUNCTION_NAME, 57 CARD_LOG_TYPE_COMPONENTS, 58 CARD_LOG_TYPE_DECORATORS, 59 CARD_LOG_TYPE_IMPORT, 60 COMPONENT_ANIMATABLE_EXTEND_DECORATOR, 61 CHECK_EXTEND_DECORATORS, 62 ELMTID, 63 ROUTENAME_NODE, 64 STORAGE_NODE, 65 STORAGE, 66 REGISTER_NAMED_ROUTE, 67 ROUTE_NAME, 68 PAGE_PATH, 69 ISINITIALRENDER, 70 CREATE_ANIMATABLE_PROPERTY, 71 UPDATE_ANIMATABLE_PROPERTY, 72 MY_IDS, 73 VIEW_STACK_PROCESSOR, 74 GET_AND_PUSH_FRAME_NODE, 75 COMPONENT_CONSTRUCTOR_PARENT, 76 WRAPBUILDER_FUNCTION, 77 FINISH_UPDATE_FUNC, 78 INTEGRATED_HSP, 79 FUNCTION, 80 PAGE_FULL_PATH, 81 LENGTH, 82 PUV2_VIEW_BASE, 83 CONTEXT_STACK 84} from './pre_define'; 85import { 86 componentInfo, 87 LogInfo, 88 LogType, 89 hasDecorator, 90 IFileLog, 91 getPossibleBuilderTypeParameter, 92 storedFileInfo, 93 ExtendResult, 94 startTimeStatisticsLocation, 95 stopTimeStatisticsLocation, 96 CompilationTimeStatistics, 97 getStoredFileInfo, 98 ProcessFileInfo, 99 RouterInfo, 100 EntryOptionValue, 101 judgeUseSharedStorageForExpresion, 102 createGetSharedForVariable, 103 createGetShared 104} from './utils'; 105import { writeFileSyncByNode } from './process_module_files'; 106import { 107 componentCollection, 108 localStorageLinkCollection, 109 localStoragePropCollection 110} from './validate_ui_syntax'; 111import { 112 processComponentClass, 113 createParentParameter, 114 processBuildMember, 115 checkFinalizeConstruction, 116 checkContextStack 117} from './process_component_class'; 118import processImport, { 119 processImportModule 120} from './process_import'; 121import { 122 processComponentBlock, 123 bindComponentAttr, 124 getName, 125 createViewStackProcessorStatement, 126 parseGlobalBuilderParams, 127 BuilderParamsResult 128} from './process_component_build'; 129import { 130 BUILDIN_STYLE_NAMES, 131 CUSTOM_BUILDER_METHOD, 132 EXTEND_ATTRIBUTE, 133 INNER_STYLE_FUNCTION, 134 GLOBAL_STYLE_FUNCTION, 135 INTERFACE_NODE_SET, 136 ID_ATTRS, 137 GLOBAL_CUSTOM_BUILDER_METHOD 138} from './component_map'; 139import { 140 resources, 141 projectConfig, 142 partialUpdateConfig 143} from '../main'; 144import { 145 createCustomComponentNewExpression, 146 createViewCreate 147} from './process_component_member'; 148import { 149 assignComponentParams, 150 assignmentFunction 151} from './process_custom_component'; 152import { processDecorator } from './fast_build/ark_compiler/process_decorator'; 153import { hasArkDecorator } from './fast_build/ark_compiler/utils'; 154import { 155 checkTypeReference, 156 validateModuleSpecifier 157} from './fast_build/system_api/api_check_utils'; 158import constantDefine from './constant_define'; 159import processStructComponentV2 from './process_struct_componentV2'; 160import createAstNodeUtils from './create_ast_node_utils'; 161import { 162 processSendableClass, 163 processSendableFunction, 164 processSendableType 165} from './process_sendable'; 166import { 167 routerOrNavPathWrite, 168 integratedHspType, 169 routerModuleType, 170 routerBundleOrModule 171} from './process_module_package'; 172 173export let transformLog: IFileLog = new createAstNodeUtils.FileLog(); 174export let contextGlobal: ts.TransformationContext; 175export let resourceFileName: string = ''; 176export const builderTypeParameter: { params: string[] } = { params: [] }; 177 178export function processUISyntax(program: ts.Program, ut = false, 179 compilationTime: CompilationTimeStatistics = null, filePath: string = ''): Function { 180 let entryNodeKey: ts.Expression; 181 return (context: ts.TransformationContext) => { 182 contextGlobal = context; 183 let pagesDir: string; 184 let pageFile: string; 185 let hasUseResource: boolean = false; 186 let hasStruct: boolean = false; 187 return (node: ts.SourceFile) => { 188 startTimeStatisticsLocation(compilationTime ? compilationTime.processUISyntaxTime : undefined); 189 pagesDir = path.resolve(path.dirname(node.fileName)); 190 resourceFileName = path.resolve(node.fileName); 191 pageFile = path.resolve(filePath !== '' ? filePath : node.fileName); 192 if (process.env.compiler === BUILD_ON || process.env.compileTool === 'rollup') { 193 storedFileInfo.transformCacheFiles[pageFile] = { 194 mtimeMs: fs.existsSync(pageFile) ? fs.statSync(pageFile).mtimeMs : 0, 195 children: [] 196 }; 197 transformLog.sourceFile = node; 198 preprocessIdAttrs(node.fileName); 199 if (!ut && (process.env.compileMode !== 'moduleJson' && 200 path.resolve(node.fileName) === path.resolve(projectConfig.projectPath, 'app.ets') || 201 /\.ts$/.test(node.fileName))) { 202 node = ts.visitEachChild(node, processResourceNode, context); 203 node = ts.factory.updateSourceFile(node, 204 insertImportModuleNode(Array.from(node.statements), hasUseResource)); 205 if (projectConfig.compileMode === ESMODULE && projectConfig.processTs === true) { 206 if (process.env.compileTool !== 'rollup') { 207 const processedNode: ts.SourceFile = ts.getTypeExportImportAndConstEnumTransformer(context)(node); 208 writeFileSyncByNode(processedNode, projectConfig, undefined); 209 } 210 } 211 const visitEachChildNode: ts.SourceFile = ts.visitEachChild(node, visitor, context); 212 stopTimeStatisticsLocation(compilationTime ? compilationTime.processUISyntaxTime : undefined); 213 return visitEachChildNode; 214 } 215 const id: number = ++componentInfo.id; 216 node = ts.visitEachChild(node, processAllNodes, context); 217 node = createEntryNode(node, context, entryNodeKey, id); 218 GLOBAL_STYLE_FUNCTION.forEach((block, styleName) => { 219 BUILDIN_STYLE_NAMES.delete(styleName); 220 }); 221 GLOBAL_STYLE_FUNCTION.clear(); 222 const statements: ts.Statement[] = Array.from(node.statements); 223 if (!partialUpdateConfig.partialUpdateMode) { 224 generateId(statements, node); 225 } 226 INTERFACE_NODE_SET.forEach(item => { 227 statements.unshift(item); 228 }); 229 if (partialUpdateConfig.partialUpdateMode && hasStruct) { 230 if (storedFileInfo.hasLocalBuilderInFile) { 231 statements.unshift(checkContextStack()); 232 } 233 statements.unshift(checkFinalizeConstruction()); 234 } 235 createNavigationInit(resourceFileName, statements); 236 insertImportModuleNode(statements, hasUseResource); 237 node = ts.factory.updateSourceFile(node, statements); 238 INTERFACE_NODE_SET.clear(); 239 if (projectConfig.compileMode === ESMODULE && projectConfig.processTs === true) { 240 if (process.env.compileTool !== 'rollup') { 241 const processedNode: ts.SourceFile = ts.getTypeExportImportAndConstEnumTransformer(context)(node); 242 writeFileSyncByNode(processedNode, projectConfig, undefined); 243 } 244 } 245 const visitEachChildNode: ts.SourceFile = ts.visitEachChild(node, visitor, context); 246 stopTimeStatisticsLocation(compilationTime ? compilationTime.processUISyntaxTime : undefined); 247 return visitEachChildNode; 248 } else { 249 stopTimeStatisticsLocation(compilationTime ? compilationTime.processUISyntaxTime : undefined); 250 return node; 251 } 252 }; 253 254 function entryKeyNode(node: ts.Node): ts.Expression { 255 const decorators: readonly ts.Decorator[] = ts.getAllDecorators(node); 256 if (node && decorators && decorators.length) { 257 decorators.forEach(item => { 258 if (item.expression && ts.isCallExpression(item.expression) && ts.isIdentifier(item.expression.expression) && 259 item.expression.expression.escapedText.toString() === 'Entry' && item.expression.arguments && 260 item.expression.arguments.length && ts.isIdentifier(item.expression.arguments[0])) { 261 entryNodeKey = item.expression.arguments[0]; 262 } 263 }); 264 } 265 return entryNodeKey; 266 } 267 268 function isESObjectNode(node: ts.Node): boolean { 269 if (node.kind === ts.SyntaxKind.TypeReference) { 270 const n: TypeReferenceNode = node as TypeReferenceNode; 271 if (n.typeName?.kind === ts.SyntaxKind.Identifier && (n.typeName as ts.Identifier).escapedText === 'ESObject') { 272 return true; 273 } 274 } 275 return false; 276 } 277 278 function processAllNodes(node: ts.Node): ts.Node { 279 if (projectConfig.compileMode === 'esmodule' && process.env.compileTool === 'rollup' && 280 ts.isImportDeclaration(node)) { 281 startTimeStatisticsLocation(compilationTime ? compilationTime.processImportTime : undefined); 282 processImportModule(node, pageFile, transformLog.errors); 283 stopTimeStatisticsLocation(compilationTime ? compilationTime.processImportTime : undefined); 284 } else if ((projectConfig.compileMode !== 'esmodule' || process.env.compileTool !== 'rollup') && 285 (ts.isImportDeclaration(node) || ts.isImportEqualsDeclaration(node) || 286 ts.isExportDeclaration(node) && node.moduleSpecifier && ts.isStringLiteral(node.moduleSpecifier))) { 287 processImport(node, pagesDir, transformLog.errors); 288 } 289 if (ts.isStructDeclaration(node)) { 290 hasStruct = true; 291 componentCollection.currentClassName = node.name.getText(); 292 componentCollection.entryComponent === componentCollection.currentClassName && entryKeyNode(node); 293 startTimeStatisticsLocation(compilationTime ? compilationTime.processComponentClassTime : undefined); 294 node = processStructComponentV2.getOrCreateStructInfo(componentCollection.currentClassName).isComponentV2 ? 295 processStructComponentV2.processStructComponentV2(node, transformLog.errors, context) : 296 processComponentClass(node, context, transformLog.errors, program); 297 stopTimeStatisticsLocation(compilationTime ? compilationTime.processComponentClassTime : undefined); 298 componentCollection.currentClassName = null; 299 INNER_STYLE_FUNCTION.forEach((block, styleName) => { 300 BUILDIN_STYLE_NAMES.delete(styleName); 301 }); 302 INNER_STYLE_FUNCTION.clear(); 303 } else if (ts.isFunctionDeclaration(node)) { 304 if (hasDecorator(node, COMPONENT_EXTEND_DECORATOR, null, transformLog.errors)) { 305 node = processExtend(node, transformLog.errors, COMPONENT_EXTEND_DECORATOR); 306 // @ts-ignore 307 if (node && node.illegalDecorators) { 308 // @ts-ignore 309 node.illegalDecorators = undefined; 310 } 311 } else if (hasDecorator(node, COMPONENT_BUILDER_DECORATOR) && node.name && node.body && 312 ts.isBlock(node.body)) { 313 storedFileInfo.processBuilder = true; 314 storedFileInfo.processGlobalBuilder = true; 315 CUSTOM_BUILDER_METHOD.add(node.name.getText()); 316 builderTypeParameter.params = getPossibleBuilderTypeParameter(node.parameters); 317 const parameters: ts.NodeArray<ts.ParameterDeclaration> = 318 ts.factory.createNodeArray(Array.from(node.parameters)); 319 parameters.push(createParentParameter()); 320 if (projectConfig.optLazyForEach) { 321 parameters.push(initializeMYIDS()); 322 } 323 storedFileInfo.builderLikeCollection = CUSTOM_BUILDER_METHOD; 324 const builderParamsResult: BuilderParamsResult = { firstParam: null }; 325 parseGlobalBuilderParams(node.parameters, builderParamsResult); 326 const componentBlock: ts.Block = processComponentBlock(node.body, false, transformLog.errors, false, true, 327 node.name.getText(), undefined, true, builderParamsResult, true); 328 node = ts.factory.updateFunctionDeclaration(node, ts.getModifiers(node), 329 node.asteriskToken, node.name, node.typeParameters, parameters, node.type, 330 componentBlock); 331 builderParamsResult.firstParam = null; 332 // @ts-ignore 333 if (node && node.illegalDecorators) { 334 // @ts-ignore 335 node.illegalDecorators = undefined; 336 } 337 builderTypeParameter.params = []; 338 node = processBuildMember(node, context, transformLog.errors, true); 339 storedFileInfo.processBuilder = false; 340 storedFileInfo.processGlobalBuilder = false; 341 } else if (hasDecorator(node, COMPONENT_STYLES_DECORATOR)) { 342 if (node.parameters.length === 0) { 343 node = undefined; 344 } else { 345 transformLog.errors.push({ 346 type: LogType.ERROR, 347 message: `@Styles can't have parameters.`, 348 pos: node.getStart() 349 }); 350 } 351 } else if (hasDecorator(node, COMPONENT_CONCURRENT_DECORATOR)) { 352 // ark compiler's feature 353 node = processConcurrent(node); 354 if (node && node.illegalDecorators) { 355 // @ts-ignore 356 node.illegalDecorators = undefined; 357 } 358 } else if (hasArkDecorator(node, COMPONENT_SENDABLE_DECORATOR)) { 359 // ark compiler's feature 360 node = processSendableFunction(node); 361 if (node && node.illegalDecorators) { 362 node.illegalDecorators = undefined; 363 } 364 } else if (hasDecorator(node, COMPONENT_ANIMATABLE_EXTEND_DECORATOR, null, transformLog.errors)) { 365 node = processExtend(node, transformLog.errors, COMPONENT_ANIMATABLE_EXTEND_DECORATOR); 366 // @ts-ignore 367 if (node && node.illegalDecorators) { 368 // @ts-ignore 369 node.illegalDecorators = undefined; 370 } 371 } 372 } else if (isResource(node)) { 373 hasUseResource = true; 374 node = processResourceData(node as ts.CallExpression, filePath); 375 } else if (isWorker(node)) { 376 node = processWorker(node as ts.NewExpression); 377 } else if (isAnimateToOrImmediately(node)) { 378 node = processAnimateToOrImmediately(node as ts.CallExpression); 379 } else if (isCustomDialogController(node)) { 380 node = createCustomDialogController(node.parent, node, transformLog.errors); 381 } else if (isESObjectNode(node)) { 382 node = ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword); 383 } else if (ts.isDecorator(node)) { 384 // This processing is for mock instead of ui transformation 385 node = processDecorator(node); 386 } else if (isWrapBuilderFunction(node)) { 387 if (node.arguments && node.arguments[0] && (!ts.isIdentifier(node.arguments[0]) || 388 ts.isIdentifier(node.arguments[0]) && 389 !CUSTOM_BUILDER_METHOD.has(node.arguments[0].escapedText.toString()))) { 390 transformLog.errors.push({ 391 type: LogType.ERROR, 392 message: `wrapBuilder's parameter should be @Builder function.`, 393 pos: node.getStart() 394 }); 395 } 396 } else if (ts.isClassDeclaration(node)) { 397 if (hasDecorator(node, COMPONENT_SENDABLE_DECORATOR)) { 398 if (projectConfig.compileHar && !projectConfig.useTsHar) { 399 let warnMessage: string = 'If you use @Sendable in js har, an exception will occur during runtime.\n' + 400 'Please use @Sendable in ts har. You can configure {"name": "UseTsHar", ' + 401 '"value": "true"} in the "metadata" in the module.json5 file in har.'; 402 transformLog.errors.push({ 403 type: LogType.WARN, 404 message: warnMessage, 405 pos: node.getStart() 406 }); 407 } 408 node = processSendableClass(node); 409 } 410 } else if (ts.isTypeAliasDeclaration(node) && hasArkDecorator(node, COMPONENT_SENDABLE_DECORATOR)) { 411 node = processSendableType(node); 412 if (node && node.illegalDecorators) { 413 node.illegalDecorators = undefined; 414 } 415 } 416 return ts.visitEachChild(node, processAllNodes, context); 417 } 418 419 function processResourceNode(node: ts.Node): ts.Node { 420 if (ts.isImportDeclaration(node)) { 421 validateModuleSpecifier(node.moduleSpecifier, transformLog.errors); 422 } else if (isResource(node)) { 423 hasUseResource = true; 424 node = processResourceData(node as ts.CallExpression, filePath); 425 } else if (ts.isTypeReferenceNode(node)) { 426 checkTypeReference(node, transformLog); 427 } 428 return ts.visitEachChild(node, processResourceNode, context); 429 } 430 431 function isWrapBuilderFunction(node: ts.Node): boolean { 432 if (ts.isCallExpression(node) && node.expression && ts.isIdentifier(node.expression) && 433 node.expression.escapedText.toString() === WRAPBUILDER_FUNCTION) { 434 return true; 435 } 436 return false; 437 } 438 439 function visitor(node: ts.Node): ts.VisitResult<ts.Node> { 440 return ts.visitEachChild(node, visitor, context); 441 } 442 }; 443} 444 445export function globalBuilderParamAssignment(): ts.VariableStatement { 446 const contextStackCondition: ts.PropertyAccessExpression = ts.factory.createPropertyAccessExpression( 447 ts.factory.createIdentifier(PUV2_VIEW_BASE), 448 ts.factory.createIdentifier(CONTEXT_STACK) 449 ); 450 return ts.factory.createVariableStatement( 451 undefined, 452 ts.factory.createVariableDeclarationList( 453 [ts.factory.createVariableDeclaration( 454 ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARENT), 455 undefined, 456 undefined, 457 ts.factory.createConditionalExpression( 458 ts.factory.createBinaryExpression( 459 contextStackCondition, 460 ts.factory.createToken(ts.SyntaxKind.AmpersandAmpersandToken), 461 ts.factory.createPropertyAccessExpression( 462 contextStackCondition, 463 ts.factory.createIdentifier(LENGTH) 464 ) 465 ), 466 ts.factory.createToken(ts.SyntaxKind.QuestionToken), 467 ts.factory.createElementAccessExpression( 468 contextStackCondition, 469 ts.factory.createBinaryExpression( 470 ts.factory.createPropertyAccessExpression( 471 contextStackCondition, 472 ts.factory.createIdentifier(LENGTH) 473 ), 474 ts.factory.createToken(ts.SyntaxKind.MinusToken), 475 ts.factory.createNumericLiteral('1') 476 ) 477 ), 478 ts.factory.createToken(ts.SyntaxKind.ColonToken), 479 ts.factory.createNull() 480 ) 481 )], 482 ts.NodeFlags.Const 483 )); 484} 485 486function createNavigationInit(fileName: string, statements: ts.Statement[]): void { 487 const newStoredFileInfo: ProcessFileInfo = getStoredFileInfo(); 488 if (newStoredFileInfo.routerInfo.has(fileName)) { 489 const routerInfoArr: Array<RouterInfo> = newStoredFileInfo.routerInfo.get(fileName); 490 const builderStatements: ts.Statement[] = []; 491 routerInfoArr.forEach((item) => { 492 if (GLOBAL_CUSTOM_BUILDER_METHOD.has(item.buildFunction)) { 493 builderStatements.push(createNavigationRegister(item)); 494 } else { 495 transformLog.errors.push({ 496 type: LogType.ERROR, 497 message: `The buildFunction '${item.buildFunction}' configured in the routerMap json file does not exist.` 498 }); 499 } 500 }); 501 statements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( 502 ts.factory.createParenthesizedExpression(ts.factory.createFunctionExpression( 503 undefined, undefined, undefined, undefined, [], undefined, 504 ts.factory.createBlock( 505 [ts.factory.createIfStatement(ts.factory.createBinaryExpression( 506 ts.factory.createTypeOfExpression(ts.factory.createIdentifier(constantDefine.NAVIGATION_BUILDER_REGISTER)), 507 ts.factory.createToken(ts.SyntaxKind.EqualsEqualsEqualsToken), ts.factory.createStringLiteral(FUNCTION)), 508 ts.factory.createBlock(builderStatements, true), undefined)], true) 509 )), undefined, [] 510 ))); 511 } 512} 513 514function createNavigationRegister(routerInfo: RouterInfo): ts.Statement { 515 return ts.factory.createExpressionStatement(ts.factory.createCallExpression( 516 ts.factory.createIdentifier(constantDefine.NAVIGATION_BUILDER_REGISTER), 517 undefined, 518 [ 519 ts.factory.createStringLiteral(routerInfo.name), 520 ts.factory.createCallExpression( 521 ts.factory.createIdentifier(WRAPBUILDER_FUNCTION), 522 undefined, 523 [ts.factory.createIdentifier(routerInfo.buildFunction)] 524 ) 525 ] 526 )); 527} 528 529export function initializeMYIDS(): ts.ParameterDeclaration { 530 return ts.factory.createParameterDeclaration( 531 undefined, 532 undefined, 533 ts.factory.createIdentifier(MY_IDS), 534 undefined, 535 undefined, 536 ts.factory.createArrayLiteralExpression( 537 [], 538 false 539 ) 540 ); 541} 542 543function generateId(statements: ts.Statement[], node: ts.SourceFile): void { 544 statements.unshift( 545 ts.factory.createVariableStatement( 546 undefined, 547 ts.factory.createVariableDeclarationList( 548 [ts.factory.createVariableDeclaration( 549 ts.factory.createIdentifier(_GENERATE_ID), 550 undefined, 551 ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword), 552 ts.factory.createNumericLiteral('0') 553 )], 554 ts.NodeFlags.Let 555 ) 556 ), 557 ts.factory.createFunctionDeclaration( 558 undefined, 559 undefined, 560 ts.factory.createIdentifier(GENERATE_ID), 561 undefined, 562 [], 563 ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword), 564 ts.factory.createBlock( 565 [ts.factory.createReturnStatement(ts.factory.createBinaryExpression( 566 ts.factory.createStringLiteral(path.basename(node.fileName, EXTNAME_ETS) + '_'), 567 ts.factory.createToken(ts.SyntaxKind.PlusToken), ts.factory.createPrefixUnaryExpression( 568 ts.SyntaxKind.PlusPlusToken, 569 ts.factory.createIdentifier(_GENERATE_ID) 570 )))], 571 true 572 ) 573 ) 574 ); 575} 576 577function preprocessIdAttrs(fileName: string): void { 578 for (const [id, idInfo] of ID_ATTRS) { 579 if (fileName === idInfo.get('path')) { 580 ID_ATTRS.delete(id); 581 } 582 } 583} 584 585function isCustomDialogController(node: ts.Expression) { 586 const tempParent: ts.Node = node.parent; 587 // @ts-ignore 588 if (!node.parent && node.original) { 589 // @ts-ignore 590 node.parent = node.original.parent; 591 } 592 if (ts.isNewExpression(node) && node.expression && ts.isIdentifier(node.expression) && 593 node.expression.escapedText.toString() === SET_CONTROLLER_CTR_TYPE) { 594 return true; 595 } else { 596 // @ts-ignore 597 node.parent = tempParent; 598 return false; 599 } 600} 601 602function createCustomDialogController(parent: ts.Expression, node: ts.NewExpression, 603 log: LogInfo[]): ts.NewExpression { 604 if (node.arguments && node.arguments.length === 1 && 605 ts.isObjectLiteralExpression(node.arguments[0]) && node.arguments[0].properties) { 606 const newproperties: ts.ObjectLiteralElementLike[] = node.arguments[0].properties.map((item) => { 607 const componentName: string = isCustomDialogControllerPropertyAssignment(item, log); 608 if (componentName !== null) { 609 item = processCustomDialogControllerPropertyAssignment(parent, 610 item as ts.PropertyAssignment, componentName); 611 } 612 return item; 613 }); 614 return ts.factory.createNewExpression(node.expression, node.typeArguments, 615 [ts.factory.createObjectLiteralExpression(newproperties, true), ts.factory.createThis()]); 616 } else { 617 return node; 618 } 619} 620 621function isCustomDialogControllerPropertyAssignment(node: ts.ObjectLiteralElementLike, 622 log: LogInfo[]): string { 623 if (ts.isPropertyAssignment(node) && ts.isIdentifier(node.name) && 624 node.name.getText() === CUSTOM_DIALOG_CONTROLLER_BUILDER) { 625 if (node.initializer) { 626 const componentName: string = getName(node.initializer); 627 if (componentCollection.customDialogs.has(componentName)) { 628 return componentName; 629 } 630 } else { 631 validateCustomDialogControllerBuilderInit(node, log); 632 } 633 } 634 return null; 635} 636 637function validateCustomDialogControllerBuilderInit(node: ts.ObjectLiteralElementLike, 638 log: LogInfo[]): void { 639 log.push({ 640 type: LogType.ERROR, 641 message: 'The builder should be initialized with a @CustomDialog Component.', 642 pos: node.getStart() 643 }); 644} 645 646function processCustomDialogControllerPropertyAssignment(parent: ts.Expression, 647 node: ts.PropertyAssignment, componentName: string): ts.PropertyAssignment { 648 if (ts.isCallExpression(node.initializer)) { 649 return ts.factory.updatePropertyAssignment(node, node.name, 650 processCustomDialogControllerBuilder(parent, node.initializer, componentName)); 651 } 652 return undefined; 653} 654 655function processCustomDialogControllerBuilder(parent: ts.Expression, 656 node: ts.CallExpression, componentName: string): ts.ArrowFunction { 657 const newExp: ts.Expression = createCustomComponentNewExpression(node, componentName, false, false, true); 658 const jsDialog: ts.Identifier = ts.factory.createIdentifier(JS_DIALOG); 659 return createCustomComponentBuilderArrowFunction(node, parent, jsDialog, newExp); 660} 661 662function createCustomComponentBuilderArrowFunction(node: ts.CallExpression, parent: ts.Expression, 663 jsDialog: ts.Identifier, newExp: ts.Expression): ts.ArrowFunction { 664 let mountNodde: ts.PropertyAccessExpression; 665 if (ts.isBinaryExpression(parent)) { 666 mountNodde = parent.left; 667 } else if (ts.isVariableDeclaration(parent) || ts.isPropertyDeclaration(parent)) { 668 mountNodde = ts.factory.createPropertyAccessExpression(ts.factory.createThis(), 669 parent.name as ts.Identifier); 670 } 671 return ts.factory.createArrowFunction( 672 undefined, 673 undefined, 674 [], 675 undefined, 676 ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), 677 ts.factory.createBlock( 678 [ 679 ts.factory.createVariableStatement( 680 undefined, 681 ts.factory.createVariableDeclarationList( 682 [ts.factory.createVariableDeclaration(jsDialog, undefined, undefined, newExp)], 683 ts.NodeFlags.Let 684 ) 685 ), 686 ts.factory.createExpressionStatement( 687 ts.factory.createCallExpression( 688 ts.factory.createPropertyAccessExpression( 689 jsDialog, 690 ts.factory.createIdentifier(SET_CONTROLLER_METHOD) 691 ), 692 undefined, 693 mountNodde ? [mountNodde] : undefined 694 ) 695 ), 696 ts.factory.createExpressionStatement(createViewCreate(jsDialog)), 697 partialUpdateConfig.partialUpdateMode ? assignComponentParams(node) : undefined, 698 partialUpdateConfig.partialUpdateMode ? assignmentFunction(jsDialog.escapedText.toString()) : undefined 699 ], 700 true 701 ) 702 ); 703} 704 705export function isResource(node: ts.Node): boolean { 706 return ts.isCallExpression(node) && ts.isIdentifier(node.expression) && 707 (node.expression.escapedText.toString() === RESOURCE || 708 node.expression.escapedText.toString() === RESOURCE_RAWFILE) && node.arguments.length > 0; 709} 710 711export function isAnimateToOrImmediately(node: ts.Node): boolean { 712 return ts.isCallExpression(node) && ts.isIdentifier(node.expression) && 713 ATTRIBUTE_ANIMATETO_SET.has(node.expression.escapedText.toString()); 714} 715 716export function processResourceData(node: ts.CallExpression, filePath: string, 717 previewLog: {isAcceleratePreview: boolean, log: LogInfo[]} = {isAcceleratePreview: false, log: []}): ts.Node { 718 if (ts.isStringLiteral(node.arguments[0])) { 719 const resourceData: string[] = (node.arguments[0] as ts.StringLiteral).text.trim().split('.'); 720 const isResourceModule: boolean = resourceData.length && /^\[.*\]$/g.test(resourceData[0]); 721 if (node.expression.getText() === RESOURCE_RAWFILE) { 722 isResourcefile(node, previewLog, isResourceModule); 723 if (resourceData && resourceData[0] && isResourceModule) { 724 return createResourceParam(-1, RESOURCE_TYPE.rawfile, [node.arguments[0]], resourceData[0], true); 725 } else { 726 return createResourceParam(0, RESOURCE_TYPE.rawfile, [node.arguments[0]], '', false); 727 } 728 } else { 729 return getResourceDataNode(node, previewLog, resourceData, isResourceModule, filePath); 730 } 731 } else if (node.expression.getText() === RESOURCE && node.arguments && node.arguments.length) { 732 resourcePreviewMessage(previewLog); 733 return createResourceParamWithVariable(node, -1, -1); 734 } else if (node.expression.getText() === RESOURCE_RAWFILE && node.arguments && node.arguments.length) { 735 resourcePreviewMessage(previewLog); 736 return createResourceParamWithVariable(node, -1, RESOURCE_TYPE.rawfile); 737 } 738 return node; 739} 740 741function resourcePreviewMessage(previewLog: {isAcceleratePreview: boolean, log: LogInfo[]}): void { 742 if (previewLog.isAcceleratePreview) { 743 previewLog.log.push({ 744 type: LogType.ERROR, 745 message: 'not support AcceleratePreview' 746 }); 747 } 748} 749 750function getResourceDataNode(node: ts.CallExpression, 751 previewLog: {isAcceleratePreview: boolean, log: LogInfo[]}, resourceData: string[], isResourceModule: boolean, filePath: string): ts.Node { 752 let resourceValue: number; 753 if (preCheckResourceData(resourceData, resources, node.arguments[0].getStart(), previewLog, isResourceModule, filePath)) { 754 let resourceType: number = RESOURCE_TYPE[resourceData[1]]; 755 if (resourceType === undefined && !previewLog.isAcceleratePreview) { 756 transformLog.errors.push({ 757 type: LogType.ERROR, 758 message: `The resource type ${resourceData[1]} is not supported.`, 759 pos: node.getStart() 760 }); 761 return node; 762 } 763 if (isResourceModule) { 764 resourceValue = -1; 765 resourceType = -1; 766 } else { 767 resourceValue = resources[resourceData[0]][resourceData[1]][resourceData[2]]; 768 } 769 return createResourceParam(resourceValue, resourceType, 770 projectConfig.compileHar || isResourceModule ? Array.from(node.arguments) : Array.from(node.arguments).slice(1), 771 resourceData.length && resourceData[0], isResourceModule); 772 } 773 return node; 774} 775 776function isResourcefile(node: ts.CallExpression, previewLog: {isAcceleratePreview: boolean, log: LogInfo[]}, isResourceModule: boolean): void { 777 if (!isResourceModule && process.env.rawFileResource && !storedFileInfo.resourcesArr.has(node.arguments[0].text) && 778 !previewLog.isAcceleratePreview && process.env.compileMode === 'moduleJson') { 779 transformLog.errors.push({ 780 type: LogType.ERROR, 781 message: `No such '${node.arguments[0].text}' resource in current module.`, 782 pos: node.getStart() 783 }); 784 } 785} 786 787function addBundleAndModuleParam(propertyArray: Array<ts.PropertyAssignment>, resourceModuleName: string, isResourceModule: boolean): void { 788 if (projectConfig.compileHar) { 789 projectConfig.bundleName = '__harDefaultBundleName__'; 790 projectConfig.moduleName = '__harDefaultModuleName__'; 791 } 792 const isByteCodeHar: boolean = projectConfig.compileHar && projectConfig.byteCodeHar; 793 const moduleNameNode: ts.Expression = createResourceModuleNode(resourceModuleName, isResourceModule, isByteCodeHar); 794 if (projectConfig.bundleName || projectConfig.bundleName === '') { 795 propertyArray.push(ts.factory.createPropertyAssignment( 796 ts.factory.createStringLiteral(RESOURCE_NAME_BUNDLE), 797 projectConfig.resetBundleName ? ts.factory.createStringLiteral('') : 798 createBundleOrModuleNode(isByteCodeHar, 'bundleName') 799 )); 800 } 801 if (projectConfig.moduleName || projectConfig.moduleName === '' || moduleNameNode) { 802 propertyArray.push(ts.factory.createPropertyAssignment( 803 ts.factory.createStringLiteral(RESOURCE_NAME_MODULE), 804 isResourceModule ? moduleNameNode : createBundleOrModuleNode(isByteCodeHar, 'moduleName') 805 )); 806 } 807} 808 809function createResourceModuleNode(resourceModuleName: string, isResourceModule: boolean, 810 isByteCodeHar: boolean): ts.Expression { 811 if (isResourceModule) { 812 if (resourceModuleName) { 813 const moduleName: string = resourceModuleName.replace(/^\[|\]$/g, ''); 814 return ts.factory.createStringLiteral(moduleName); 815 } 816 if (isByteCodeHar) { 817 return ts.factory.createIdentifier('__MODULE_NAME__'); 818 } 819 return projectConfig.moduleName ? ts.factory.createStringLiteral(projectConfig.moduleName) : undefined; 820 } 821 return undefined; 822} 823 824function createBundleOrModuleNode(isByteCodeHar: boolean, type: string): ts.Expression { 825 if (isByteCodeHar) { 826 return ts.factory.createIdentifier(type === 'bundleName' ? '__BUNDLE_NAME__' : '__MODULE_NAME__'); 827 } 828 return ts.factory.createStringLiteral(type === 'bundleName' ? projectConfig.bundleName : 829 projectConfig.moduleName); 830} 831 832function createResourceParamWithVariable(node: ts.CallExpression, resourceValue: number, resourceType: number): ts.ObjectLiteralExpression { 833 const propertyArray: Array<ts.PropertyAssignment> = [ 834 ts.factory.createPropertyAssignment( 835 ts.factory.createStringLiteral(RESOURCE_NAME_ID), 836 ts.factory.createNumericLiteral(resourceValue) 837 ), 838 ts.factory.createPropertyAssignment( 839 ts.factory.createStringLiteral(RESOURCE_NAME_TYPE), 840 ts.factory.createNumericLiteral(resourceType) 841 ), 842 ts.factory.createPropertyAssignment( 843 ts.factory.createIdentifier(RESOURCE_NAME_PARAMS), 844 ts.factory.createArrayLiteralExpression(Array.from(node.arguments), false) 845 ) 846 ]; 847 848 addBundleAndModuleParam(propertyArray, '', true); 849 850 const resourceParams: ts.ObjectLiteralExpression = ts.factory.createObjectLiteralExpression( 851 propertyArray, false); 852 return resourceParams; 853} 854 855function createResourceParam(resourceValue: number, resourceType: number, argsArr: ts.Expression[], 856 resourceModuleName: string, isResourceModule: boolean): 857 ts.ObjectLiteralExpression { 858 if (projectConfig.compileHar) { 859 resourceValue = -1; 860 } 861 862 const propertyArray: Array<ts.PropertyAssignment> = [ 863 ts.factory.createPropertyAssignment( 864 ts.factory.createStringLiteral(RESOURCE_NAME_ID), 865 ts.factory.createNumericLiteral(resourceValue) 866 ), 867 ts.factory.createPropertyAssignment( 868 ts.factory.createStringLiteral(RESOURCE_NAME_TYPE), 869 ts.factory.createNumericLiteral(resourceType) 870 ), 871 ts.factory.createPropertyAssignment( 872 ts.factory.createIdentifier(RESOURCE_NAME_PARAMS), 873 ts.factory.createArrayLiteralExpression(argsArr, false) 874 ) 875 ]; 876 877 addBundleAndModuleParam(propertyArray, resourceModuleName, isResourceModule); 878 879 const resourceParams: ts.ObjectLiteralExpression = ts.factory.createObjectLiteralExpression( 880 propertyArray, false); 881 return resourceParams; 882} 883 884function preCheckResourceData(resourceData: string[], resources: object, pos: number, 885 previewLog: {isAcceleratePreview: boolean, log: LogInfo[]}, isResourceModule: boolean, filePath: string): boolean { 886 if (previewLog.isAcceleratePreview) { 887 return validateResourceData(resourceData, resources, pos, previewLog.log, true, isResourceModule, filePath); 888 } else { 889 return validateResourceData(resourceData, resources, pos, transformLog.errors, false, isResourceModule, filePath); 890 } 891} 892 893function validateResourceData(resourceData: string[], resources: object, pos: number, log: LogInfo[], isAcceleratePreview: boolean, 894 isResourceModule: boolean, filePath: string): boolean { 895 if (resourceData.length !== 3) { 896 log.push({ 897 type: LogType.ERROR, 898 message: 'The input parameter is not supported.', 899 pos: pos 900 }); 901 } else { 902 if (!isAcceleratePreview && process.env.compileTool === 'rollup' && process.env.compileMode === 'moduleJson') { 903 storedFileInfo.collectResourceInFile(resourceData[1] + '_' + resourceData[2], path.resolve(filePath)); 904 } 905 if (isResourceModule) { 906 if (/^\[.*\]$/.test(resourceData[0]) && projectConfig.hspResourcesMap) { 907 const resourceDataFirst: string = resourceData[0].replace(/^\[/, '').replace(/\]$/, '').trim(); 908 return resourceCheck(resourceData, resources, pos, log, true, resourceDataFirst, false); 909 } else { 910 return resourceCheck(resourceData, resources, pos, log, false, resourceData[0], true); 911 } 912 } else { 913 return resourceCheck(resourceData, resources, pos, log, false, resourceData[0], false); 914 } 915 } 916 return false; 917} 918 919function resourceCheck(resourceData: string[], resources: object, pos: number, log: LogInfo[], isHspResourceModule: boolean, 920 resourceDataFirst: string, faOrNoHspResourcesMap: boolean): boolean { 921 const logType: LogType = isHspResourceModule ? LogType.WARN : LogType.ERROR; 922 if (!faOrNoHspResourcesMap && !resources[resourceDataFirst]) { 923 log.push({ 924 type: logType, 925 message: `Unknown resource source '${resourceDataFirst}'.`, 926 pos: pos 927 }); 928 } else if (!faOrNoHspResourcesMap && !resources[resourceDataFirst][resourceData[1]]) { 929 log.push({ 930 type: logType, 931 message: `Unknown resource type '${resourceData[1]}'.`, 932 pos: pos 933 }); 934 } else if (!faOrNoHspResourcesMap && !resources[resourceDataFirst][resourceData[1]][resourceData[2]]) { 935 log.push({ 936 type: logType, 937 message: `Unknown resource name '${resourceData[2]}'.`, 938 pos: pos 939 }); 940 } else { 941 return true; 942 } 943 return false; 944} 945 946function isWorker(node: ts.Node): boolean { 947 return ts.isNewExpression(node) && ts.isPropertyAccessExpression(node.expression) && 948 ts.isIdentifier(node.expression.name) && 949 node.expression.name.escapedText.toString() === WORKER_OBJECT; 950} 951 952function processWorker(node: ts.NewExpression): ts.Node { 953 if (node.arguments.length && ts.isStringLiteral(node.arguments[0])) { 954 const args: ts.Expression[] = Array.from(node.arguments); 955 // @ts-ignore 956 const workerPath: string = node.arguments[0].text; 957 const stringNode: ts.StringLiteral = ts.factory.createStringLiteral( 958 workerPath.replace(/\.ts$/, '.js')); 959 args.splice(0, 1, stringNode); 960 return ts.factory.updateNewExpression(node, node.expression, node.typeArguments, args); 961 } 962 return node; 963} 964 965export function processAnimateToOrImmediately(node: ts.CallExpression): ts.CallExpression { 966 return ts.factory.updateCallExpression(node, ts.factory.createPropertyAccessExpression( 967 ts.factory.createIdentifier(GLOBAL_CONTEXT), 968 ts.factory.createIdentifier(node.expression.escapedText.toString())), 969 node.typeArguments, node.arguments); 970} 971 972function processExtend(node: ts.FunctionDeclaration, log: LogInfo[], 973 decoratorName: string): ts.FunctionDeclaration { 974 const componentName: string = isExtendFunction(node, { decoratorName: '', componentName: '' }, true); 975 if (componentName && node.body && node.body.statements.length) { 976 const statementArray: ts.Statement[] = []; 977 let bodynode: ts.Block; 978 if (decoratorName === COMPONENT_EXTEND_DECORATOR) { 979 const attrSet: ts.CallExpression = node.body.statements[0].expression; 980 if (isOriginalExtend(node.body)) { 981 const changeCompName: ts.ExpressionStatement = ts.factory.createExpressionStatement(processExtendBody(attrSet)); 982 bindComponentAttr(changeCompName as ts.ExpressionStatement, 983 ts.factory.createIdentifier(componentName), statementArray, log); 984 } else { 985 bodynode = ts.visitEachChild(node.body, traverseExtendExpression, contextGlobal); 986 } 987 let extendFunctionName: string; 988 if (node.name.getText().startsWith('__' + componentName + '__')) { 989 extendFunctionName = node.name.getText(); 990 } else { 991 extendFunctionName = '__' + componentName + '__' + node.name.getText(); 992 collectExtend(EXTEND_ATTRIBUTE, componentName, node.name.escapedText.toString()); 993 } 994 return ts.factory.updateFunctionDeclaration(node, ts.getModifiers(node), node.asteriskToken, 995 ts.factory.createIdentifier(extendFunctionName), node.typeParameters, 996 node.parameters, ts.factory.createToken(ts.SyntaxKind.VoidKeyword), isOriginalExtend(node.body) ? 997 ts.factory.updateBlock(node.body, statementArray) : bodynode); 998 } 999 if (decoratorName === COMPONENT_ANIMATABLE_EXTEND_DECORATOR) { 1000 bindComponentAttr(node.body.statements[0], 1001 ts.factory.createIdentifier(componentName), statementArray, log); 1002 return ts.factory.updateFunctionDeclaration(node, ts.getModifiers(node), node.asteriskToken, 1003 node.name, node.typeParameters, 1004 [...node.parameters, ...createAnimatableParameterNode()], ts.factory.createToken(ts.SyntaxKind.VoidKeyword), 1005 ts.factory.updateBlock(node.body, createAnimatableBody(componentName, node.name, 1006 node.parameters, statementArray))); 1007 } 1008 } 1009 function traverseExtendExpression(node: ts.Node): ts.Node { 1010 if (ts.isExpressionStatement(node) && isDollarNode(node, componentName)) { 1011 const changeCompName: ts.ExpressionStatement = 1012 ts.factory.createExpressionStatement(processExtendBody(node.expression, componentName)); 1013 const statementArray: ts.Statement[] = []; 1014 bindComponentAttr(changeCompName, ts.factory.createIdentifier(componentName), statementArray, []); 1015 return ts.factory.createBlock(statementArray, true); 1016 } 1017 return ts.visitEachChild(node, traverseExtendExpression, contextGlobal); 1018 } 1019 return undefined; 1020} 1021 1022function createAnimatableParameterNode(): ts.ParameterDeclaration[] { 1023 return [ 1024 ts.factory.createParameterDeclaration( 1025 undefined, undefined, ts.factory.createIdentifier(ELMTID)), 1026 ts.factory.createParameterDeclaration( 1027 undefined, undefined, ts.factory.createIdentifier(ISINITIALRENDER)), 1028 ts.factory.createParameterDeclaration( 1029 undefined, undefined, ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARENT)) 1030 ]; 1031} 1032 1033function createAnimatableBody(componentName: string, funcName: ts.Identifier, 1034 parameters: ts.NodeArray<ts.ParameterDeclaration>, attrArray: ts.Statement[]): ts.Statement[] { 1035 const paramNode: ts.Identifier[] = []; 1036 parameters.forEach((item: ts.ParameterDeclaration) => { 1037 if (item.name && ts.isIdentifier(item.name)) { 1038 paramNode.push(item.name); 1039 } 1040 }); 1041 return [ 1042 ts.factory.createIfStatement( 1043 ts.factory.createIdentifier(ISINITIALRENDER), 1044 ts.factory.createBlock([ 1045 createAnimatableProperty(componentName, funcName, parameters, paramNode, attrArray), 1046 ...attrArray 1047 ], true), 1048 ts.factory.createBlock([ 1049 ts.factory.createExpressionStatement(ts.factory.createCallExpression( 1050 ts.factory.createPropertyAccessExpression( 1051 ts.factory.createIdentifier(componentName), 1052 ts.factory.createIdentifier(UPDATE_ANIMATABLE_PROPERTY) 1053 ), undefined, 1054 [ts.factory.createStringLiteral(funcName.escapedText.toString()), ...paramNode] 1055 )) 1056 ]) 1057 ) 1058 ]; 1059} 1060 1061function createAnimatableProperty(componentName: string, funcName: ts.Identifier, 1062 parameters: ts.NodeArray<ts.ParameterDeclaration>, 1063 paramNode: ts.Identifier[], attrArray: ts.Statement[]) { 1064 const componentIdentifier: ts.Identifier = ts.factory.createIdentifier(componentName); 1065 return ts.factory.createExpressionStatement( 1066 ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression( 1067 componentIdentifier, 1068 ts.factory.createIdentifier(CREATE_ANIMATABLE_PROPERTY)), 1069 undefined, [ 1070 ts.factory.createStringLiteral(funcName.escapedText.toString()), 1071 ...paramNode, 1072 ts.factory.createArrowFunction(undefined, undefined, parameters, undefined, 1073 ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), 1074 ts.factory.createBlock([ 1075 createViewStackProcessorStatement(STARTGETACCESSRECORDINGFOR, ELMTID), 1076 createAnimatableFrameNode(componentName), 1077 ...attrArray, 1078 createViewStackProcessorStatement(STOPGETACCESSRECORDING), 1079 createAnimatableUpdateFunc() 1080 ], true)) 1081 ] 1082 ) 1083 ); 1084} 1085 1086function createAnimatableFrameNode(componentName: string): ts.ExpressionStatement { 1087 return ts.factory.createExpressionStatement(ts.factory.createCallExpression( 1088 ts.factory.createPropertyAccessExpression( 1089 ts.factory.createIdentifier(VIEW_STACK_PROCESSOR), 1090 ts.factory.createIdentifier(GET_AND_PUSH_FRAME_NODE) 1091 ), undefined, 1092 [ 1093 ts.factory.createStringLiteral(componentName), 1094 ts.factory.createIdentifier(ELMTID) 1095 ] 1096 )); 1097} 1098 1099function createAnimatableUpdateFunc(): ts.ExpressionStatement { 1100 return ts.factory.createExpressionStatement(ts.factory.createCallExpression( 1101 ts.factory.createPropertyAccessExpression( 1102 ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARENT), 1103 ts.factory.createIdentifier(FINISH_UPDATE_FUNC) 1104 ), undefined, [ts.factory.createIdentifier(ELMTID)] 1105 )); 1106} 1107 1108function processConcurrent(node: ts.FunctionDeclaration): ts.FunctionDeclaration { 1109 if (node.body) { 1110 const statementArray: ts.Statement[] = 1111 [ts.factory.createExpressionStatement(ts.factory.createStringLiteral('use concurrent')), 1112 ...node.body.statements]; 1113 return ts.factory.updateFunctionDeclaration(node, ts.getModifiers(node), node.asteriskToken, node.name, 1114 node.typeParameters, node.parameters, node.type, ts.factory.updateBlock(node.body, statementArray)); 1115 } 1116 return node; 1117} 1118 1119export function isOriginalExtend(node: ts.Block): boolean { 1120 let innerNode: ts.Node = node.statements[0]; 1121 if (node.statements.length === 1 && ts.isExpressionStatement(innerNode)) { 1122 while (innerNode.expression) { 1123 innerNode = innerNode.expression; 1124 } 1125 if (ts.isIdentifier(innerNode) && innerNode.pos && innerNode.end && innerNode.pos === innerNode.end && 1126 innerNode.escapedText.toString().match(/Instance$/)) { 1127 return true; 1128 } 1129 } 1130 return false; 1131} 1132 1133function isDollarNode(node: ts.ExpressionStatement, componentName: string): boolean { 1134 let innerNode: ts.Node = node; 1135 while (innerNode.expression) { 1136 innerNode = innerNode.expression; 1137 } 1138 let changedIdentifier: string = '$'; 1139 if (process.env.compileTool === 'rollup' && storedFileInfo.reUseProgram) { 1140 changedIdentifier = `${componentName}Instance`; 1141 } 1142 if (ts.isIdentifier(innerNode) && innerNode.getText() === changedIdentifier) { 1143 return true; 1144 } else { 1145 return false; 1146 } 1147} 1148 1149function processExtendBody(node: ts.Node, componentName?: string): ts.Expression { 1150 switch (node.kind) { 1151 case ts.SyntaxKind.CallExpression: 1152 return ts.factory.createCallExpression(processExtendBody(node.expression, componentName), 1153 undefined, node.arguments); 1154 case ts.SyntaxKind.PropertyAccessExpression: 1155 return ts.factory.createPropertyAccessExpression( 1156 processExtendBody(node.expression, componentName), node.name); 1157 case ts.SyntaxKind.Identifier: 1158 if (!componentName) { 1159 return ts.factory.createIdentifier(node.escapedText.toString().replace(INSTANCE, '')); 1160 } else { 1161 return ts.factory.createIdentifier(componentName); 1162 } 1163 } 1164 return undefined; 1165} 1166 1167export function collectExtend(collectionSet: Map<string, Set<string>>, component: string, attribute: string): void { 1168 if (collectionSet.has(component)) { 1169 collectionSet.get(component).add(attribute); 1170 } else { 1171 collectionSet.set(component, new Set([attribute])); 1172 } 1173} 1174 1175export function isExtendFunction(node: ts.FunctionDeclaration, extendResult: ExtendResult, 1176 checkArguments: boolean = false): string { 1177 const decorators: readonly ts.Decorator[] = ts.getAllDecorators(node); 1178 if (decorators && decorators.length) { 1179 for (let i = 0, len = decorators.length; i < len; i++) { 1180 if (ts.isCallExpression(decorators[i].expression)) { 1181 parseExtendNode(decorators[i].expression as ts.CallExpression, extendResult, checkArguments); 1182 if (CHECK_EXTEND_DECORATORS.includes(extendResult.decoratorName) && extendResult.componentName) { 1183 return extendResult.componentName; 1184 } 1185 } 1186 } 1187 } 1188 return null; 1189} 1190 1191function parseExtendNode(node: ts.CallExpression, extendResult: ExtendResult, checkArguments: boolean): void { 1192 if (ts.isIdentifier(node.expression)) { 1193 extendResult.decoratorName = node.expression.escapedText.toString(); 1194 if (checkArguments && CHECK_EXTEND_DECORATORS.includes(extendResult.decoratorName) && 1195 node.arguments && node.arguments.length !== 1) { 1196 transformLog.errors.push({ 1197 type: LogType.ERROR, 1198 message: `@${extendResult.decoratorName} should have one and only one parameter`, 1199 pos: node.getStart() 1200 }); 1201 } 1202 } 1203 if (node.arguments.length && ts.isIdentifier(node.arguments[0])) { 1204 extendResult.componentName = node.arguments[0].escapedText.toString(); 1205 } 1206} 1207 1208function createEntryNode(node: ts.SourceFile, context: ts.TransformationContext, 1209 entryNodeKey: ts.Expression, id: number): ts.SourceFile { 1210 let cardRelativePath: string; 1211 if (projectConfig && projectConfig.cardObj) { 1212 cardRelativePath = projectConfig.cardObj[resourceFileName]; 1213 } 1214 if (componentCollection.previewComponent.length === 0 || !projectConfig.isPreview) { 1215 if (componentCollection.entryComponent) { 1216 if (!partialUpdateConfig.partialUpdateMode) { 1217 const entryNode: ts.ExpressionStatement = 1218 createEntryFunction(componentCollection.entryComponent, context, 1219 cardRelativePath, entryNodeKey, id) as ts.ExpressionStatement; 1220 return context.factory.updateSourceFile(node, [...node.statements, entryNode]); 1221 } else { 1222 const entryNodes: ts.ExpressionStatement[] = 1223 createEntryFunction(componentCollection.entryComponent, context, 1224 cardRelativePath, entryNodeKey, id) as ts.ExpressionStatement[]; 1225 return entryNodes ? 1226 context.factory.updateSourceFile(node, [...node.statements, ...entryNodes]) : 1227 context.factory.updateSourceFile(node, [...node.statements]); 1228 } 1229 } else { 1230 return node; 1231 } 1232 } else { 1233 const statementsArray: ts.Statement = 1234 createPreviewComponentFunction(componentCollection.entryComponent, context, cardRelativePath, entryNodeKey, id); 1235 return context.factory.updateSourceFile(node, [...node.statements, statementsArray]); 1236 } 1237} 1238 1239function createEntryFunction(name: string, context: ts.TransformationContext, cardRelativePath: string, 1240 entryNodeKey: ts.Expression, id: number): ts.ExpressionStatement | (ts.Statement | ts.Block)[] { 1241 const newArray: ts.Expression[] = [ 1242 context.factory.createStringLiteral(id.toString()), 1243 context.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UNDEFINED), 1244 context.factory.createObjectLiteralExpression([], false) 1245 ]; 1246 const [localStorageName, entryOptionNode]: [string, ts.Expression] = addStorageParam(name); 1247 if (localStorageName && entryNodeKey) { 1248 newArray.push(entryNodeKey); 1249 } 1250 const newExpressionParams: any[] = [ 1251 context.factory.createNewExpression( 1252 context.factory.createIdentifier(name), undefined, newArray)]; 1253 addCardStringliteral(newExpressionParams, context, cardRelativePath); 1254 if (!partialUpdateConfig.partialUpdateMode) { 1255 const newExpressionStatement: ts.ExpressionStatement = 1256 context.factory.createExpressionStatement(context.factory.createCallExpression( 1257 context.factory.createIdentifier(cardRelativePath ? CARD_ENTRY_FUNCTION_NAME : 1258 PAGE_ENTRY_FUNCTION_NAME), undefined, newExpressionParams)); 1259 return newExpressionStatement; 1260 } else { 1261 if (cardRelativePath) { 1262 if (entryOptionNode && ts.isObjectLiteralExpression(entryOptionNode)) { 1263 transformLog.errors.push({ 1264 type: LogType.ERROR, 1265 message: `@Entry doesn't support {} parameter in card`, 1266 pos: componentCollection.entryComponentPos 1267 }); 1268 } 1269 return [ 1270 createStartGetAccessRecording(context), 1271 createLoadDocument(context, name, cardRelativePath, localStorageName, entryNodeKey), 1272 createStopGetAccessRecording(context) 1273 ]; 1274 } else { 1275 return createLoadPageConditionalJudgMent(context, name, cardRelativePath, localStorageName, entryOptionNode); 1276 } 1277 } 1278} 1279 1280function createLoadPageConditionalJudgMent(context: ts.TransformationContext, name: string, 1281 cardRelativePath: string, localStorageName: string, entryOptionNode: ts.Expression, 1282 argsArr: ts.Expression[] = undefined, isComponentPreview: boolean = false): (ts.Statement | ts.Block)[] { 1283 let isObject: boolean = false; 1284 const entryOptionValue: EntryOptionValue = new EntryOptionValue(); 1285 if (!entryOptionNode) { 1286 let originArray: ts.ExpressionStatement[]; 1287 if (projectConfig.minAPIVersion > 10) { 1288 if (componentCollection.entryComponent === name && componentCollection.localSharedStorage) { 1289 return [judgeRouteNameAndStorageForIdentifier(context, name, 1290 cardRelativePath, isObject, componentCollection.localSharedStorage, undefined, undefined, argsArr)]; 1291 } 1292 const newArray: ts.Expression[] = [ 1293 context.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UNDEFINED), 1294 context.factory.createObjectLiteralExpression([], false) 1295 ]; 1296 const newExpressionParams: any[] = [ 1297 context.factory.createNewExpression(context.factory.createIdentifier(name), undefined, newArray)]; 1298 originArray = [ 1299 createRegisterNamedRoute(context, newExpressionParams, false, undefined, false) 1300 ]; 1301 } else { 1302 originArray = [ 1303 createStartGetAccessRecording(context), 1304 createLoadDocument(context, name, cardRelativePath, localStorageName, entryOptionNode), 1305 createStopGetAccessRecording(context) 1306 ]; 1307 } 1308 return originArray; 1309 } 1310 if (ts.isObjectLiteralExpression(entryOptionNode)) { 1311 isObject = true; 1312 if (entryOptionNode.properties) { 1313 entryOptionNode.properties.forEach((property) => { 1314 if (ts.isPropertyAssignment(property) && property.name && ts.isIdentifier(property.name)) { 1315 entryOptionValue[property.name.escapedText.toString()] = property.initializer; 1316 } 1317 }); 1318 if (entryOptionValue.useSharedStorage) { 1319 entryOptionValue.storage = createGetShared(entryOptionValue); 1320 } 1321 } 1322 } else { 1323 isObject = false; 1324 } 1325 return generateLoadDocumentEntrance(isObject, entryOptionValue.routeName, entryOptionValue.storage, 1326 isComponentPreview, context, name, cardRelativePath, entryOptionNode, argsArr); 1327} 1328 1329function generateLoadDocumentEntrance(isObject: boolean, routeNameNode: ts.Expression, 1330 storageNode: ts.Expression, isComponentPreview: boolean, context: ts.TransformationContext, 1331 name: string, cardRelativePath: string, entryOptionNode: ts.Expression, 1332 argsArr: ts.Expression[]): (ts.ExpressionStatement | ts.Block | ts.IfStatement)[] { 1333 if (isObject) { 1334 if (routeNameNode && !storageNode) { 1335 return isComponentPreview ? [ 1336 ...assignRouteNameAndStorage(routeNameNode), 1337 ...createLoadDocumentWithRoute(context, name, cardRelativePath, isObject, entryOptionNode, 1338 routeNameNode, storageNode, true, false, false, argsArr) 1339 ] : [ts.factory.createBlock([ 1340 ...assignRouteNameAndStorage(routeNameNode), 1341 ...createLoadDocumentWithRoute(context, name, cardRelativePath, isObject, entryOptionNode, 1342 routeNameNode, storageNode, true, false, false, argsArr) 1343 ])]; 1344 } else if (!routeNameNode && !storageNode) { 1345 return isComponentPreview ? [ 1346 ...assignRouteNameAndStorage(routeNameNode), 1347 ...createLoadDocumentWithRoute(context, name, cardRelativePath, isObject, entryOptionNode, 1348 routeNameNode, storageNode, false, false, true, argsArr) 1349 ] : [ts.factory.createBlock([ 1350 ...assignRouteNameAndStorage(routeNameNode), 1351 ...createLoadDocumentWithRoute(context, name, cardRelativePath, isObject, entryOptionNode, 1352 routeNameNode, storageNode, false, false, true, argsArr) 1353 ])]; 1354 } else if (!routeNameNode && storageNode) { 1355 return isComponentPreview ? [ 1356 ...assignRouteNameAndStorage(routeNameNode), 1357 ...createLoadDocumentWithRoute(context, name, cardRelativePath, isObject, entryOptionNode, 1358 routeNameNode, storageNode, false, true, true, argsArr) 1359 ] : [ts.factory.createBlock([ 1360 ...assignRouteNameAndStorage(routeNameNode), 1361 ...createLoadDocumentWithRoute(context, name, cardRelativePath, isObject, entryOptionNode, 1362 routeNameNode, storageNode, false, true, true, argsArr) 1363 ])]; 1364 } else { 1365 return isComponentPreview ? [ 1366 ...assignRouteNameAndStorage(routeNameNode), 1367 judgeRouteNameAndStorage(context, name, cardRelativePath, isObject, entryOptionNode, routeNameNode, storageNode, argsArr) 1368 ] : [ts.factory.createBlock([ 1369 ...assignRouteNameAndStorage(routeNameNode), 1370 judgeRouteNameAndStorage(context, name, cardRelativePath, isObject, entryOptionNode, routeNameNode, storageNode, argsArr) 1371 ])]; 1372 } 1373 } else { 1374 return [ 1375 judgeRouteNameAndStorage(context, name, cardRelativePath, isObject, entryOptionNode, routeNameNode, storageNode, argsArr)]; 1376 } 1377} 1378 1379function judgeRouteNameAndStorage(context: ts.TransformationContext, name: string, 1380 cardRelativePath: string, isObject: boolean, entryOptionNode: ts.Expression, routeNameNode: ts.Expression, 1381 storageNode: ts.Expression, argsArr: ts.Expression[] = undefined): ts.IfStatement { 1382 return isObject ? judgeRouteNameAndStorageForObj(context, name, cardRelativePath, isObject, entryOptionNode, 1383 routeNameNode, storageNode, argsArr) : judgeRouteNameAndStorageForIdentifier(context, name, 1384 cardRelativePath, isObject, entryOptionNode, routeNameNode, storageNode, argsArr); 1385} 1386 1387function judgeRouteNameAndStorageForObj(context: ts.TransformationContext, name: string, 1388 cardRelativePath: string, isObject: boolean, entryOptionNode: ts.Expression, routeNameNode: ts.Expression, 1389 storageNode: ts.Expression, argsArr: ts.Expression[] = undefined): ts.IfStatement { 1390 return ts.factory.createIfStatement( 1391 judgeRouteAndStorageForObject(true), 1392 ts.factory.createBlock( 1393 [ 1394 ...createLoadDocumentWithRoute(context, name, cardRelativePath, isObject, entryOptionNode, 1395 routeNameNode, storageNode, true, true, false, argsArr) 1396 ], 1397 true 1398 ), ts.factory.createBlock( 1399 [ 1400 ...createLoadDocumentWithRoute(context, name, cardRelativePath, isObject, entryOptionNode, 1401 routeNameNode, storageNode, false, false, true, argsArr) 1402 ], 1403 true 1404 )); 1405} 1406 1407function judgeRouteNameAndStorageForIdentifier(context: ts.TransformationContext, name: string, 1408 cardRelativePath: string, isObject: boolean, entryOptionNode: ts.Expression, routeNameNode: ts.Expression, 1409 storageNode: ts.Expression, argsArr: ts.Expression[] = undefined): ts.IfStatement { 1410 return ts.factory.createIfStatement( 1411 judgeRouteAndStorageForIdentifier(entryOptionNode as ts.Identifier, true, true), 1412 ts.factory.createBlock( 1413 [ 1414 ...createLoadDocumentWithRoute(context, name, cardRelativePath, isObject, entryOptionNode, 1415 routeNameNode, storageNode, true, true, false, argsArr) 1416 ], 1417 true 1418 ), 1419 ts.factory.createIfStatement( 1420 judgeRouteAndStorageForIdentifier(entryOptionNode as ts.Identifier, true, false), 1421 ts.factory.createBlock( 1422 [ 1423 ...createLoadDocumentWithRoute(context, name, cardRelativePath, isObject, entryOptionNode, 1424 routeNameNode, storageNode, true, false, false, argsArr) 1425 ], 1426 true 1427 ), 1428 ts.factory.createIfStatement( 1429 judgeRouteAndStorageForIdentifier(entryOptionNode as ts.Identifier, false, true), 1430 ts.factory.createBlock( 1431 [ 1432 ...createLoadDocumentWithRoute(context, name, cardRelativePath, isObject, entryOptionNode, 1433 routeNameNode, storageNode, false, true, true, argsArr) 1434 ], 1435 true 1436 ), 1437 ts.factory.createIfStatement( 1438 judgeUseSharedStorageForExpresion(entryOptionNode), 1439 ts.factory.createBlock( 1440 [...createSharedStorageWithRoute(context, name, cardRelativePath, entryOptionNode, true, argsArr)], true), 1441 ts.factory.createBlock( 1442 [...createLoadDocumentWithRoute(context, name, cardRelativePath, false, entryOptionNode, 1443 null, null, false, false, true, argsArr) 1444 ], true) 1445 ) 1446 ) 1447 ) 1448 ); 1449} 1450 1451function judgeRouteAndStorageForObject(hasRouteName: boolean): ts.BinaryExpression { 1452 return ts.factory.createBinaryExpression( 1453 ts.factory.createIdentifier(ROUTENAME_NODE), 1454 ts.factory.createToken(hasRouteName ? ts.SyntaxKind.ExclamationEqualsToken : ts.SyntaxKind.EqualsEqualsToken), 1455 ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UNDEFINED) 1456 ); 1457} 1458 1459function judgeRouteAndStorageForIdentifier(entryOptionNode: ts.Identifier, hasRouteName: boolean, 1460 hasStorage: boolean): ts.BinaryExpression { 1461 return ts.factory.createBinaryExpression( 1462 ts.factory.createBinaryExpression( 1463 entryOptionNode, 1464 ts.factory.createToken(ts.SyntaxKind.AmpersandAmpersandToken), 1465 ts.factory.createBinaryExpression( 1466 ts.factory.createPropertyAccessExpression( 1467 entryOptionNode, 1468 ts.factory.createIdentifier(ROUTE_NAME) 1469 ), 1470 ts.factory.createToken(hasRouteName ? ts.SyntaxKind.ExclamationEqualsToken : ts.SyntaxKind.EqualsEqualsToken), 1471 ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UNDEFINED) 1472 ) 1473 ), 1474 ts.factory.createToken(ts.SyntaxKind.AmpersandAmpersandToken), 1475 ts.factory.createBinaryExpression( 1476 ts.factory.createPropertyAccessExpression( 1477 entryOptionNode, 1478 ts.factory.createIdentifier(STORAGE) 1479 ), 1480 ts.factory.createToken(hasStorage ? ts.SyntaxKind.ExclamationEqualsToken : ts.SyntaxKind.EqualsEqualsToken), 1481 ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UNDEFINED) 1482 ) 1483 ); 1484} 1485 1486function assignRouteNameAndStorage(routeNameNode): ts.ExpressionStatement[] { 1487 const assignOperation: ts.VariableStatement[] = []; 1488 if (routeNameNode) { 1489 assignOperation.push(ts.factory.createVariableStatement( 1490 undefined, 1491 ts.factory.createVariableDeclarationList( 1492 [ts.factory.createVariableDeclaration( 1493 ts.factory.createIdentifier(ROUTENAME_NODE), 1494 undefined, 1495 undefined, 1496 routeNameNode 1497 )], 1498 ts.NodeFlags.Let 1499 ) 1500 )); 1501 } 1502 return assignOperation; 1503} 1504 1505function createLoadDocumentWithRoute(context: ts.TransformationContext, name: string, 1506 cardRelativePath: string, isObject: boolean, entryOptionNode: ts.Expression, 1507 routeNameNode: ts.Node, storageNode: ts.Node, hasRouteName: boolean, hasStorage: boolean, 1508 shouldCreateAccsessRecording: boolean, argsArr: ts.Expression[]): ts.ExpressionStatement[] { 1509 const newArray: ts.Expression[] = [ 1510 context.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UNDEFINED), 1511 context.factory.createObjectLiteralExpression([], false) 1512 ]; 1513 if (entryOptionNode) { 1514 if (!isObject) { 1515 if (routeNameNode === null && storageNode === null) { 1516 newArray.push(entryOptionNode); 1517 } else { 1518 newArray.push(createGetSharedForVariable(entryOptionNode)); 1519 } 1520 } else if (storageNode) { 1521 newArray.push(storageNode as ts.Expression); 1522 } 1523 } 1524 return loadDocumentWithRoute(context, name, newArray, argsArr, hasRouteName, shouldCreateAccsessRecording, 1525 isObject, entryOptionNode, cardRelativePath); 1526} 1527 1528function loadDocumentWithRoute(context: ts.TransformationContext, name: string, newArray: ts.Expression[], 1529 argsArr: ts.Expression[], hasRouteName: boolean, shouldCreateAccsessRecording: boolean, 1530 isObject: boolean, entryOptionNode: ts.Expression, cardRelativePath: string): ts.ExpressionStatement[] { 1531 const newExpressionParams = [context.factory.createNewExpression( 1532 context.factory.createIdentifier(name), undefined, newArray)]; 1533 if (argsArr) { 1534 argsArr = []; 1535 componentCollection.previewComponent.forEach((componentName: string) => { 1536 const newExpression: ts.Expression = context.factory.createNewExpression( 1537 context.factory.createIdentifier(componentName), undefined, 1538 componentName === name ? newArray : newArray.slice(0, newArray.length - 1) 1539 ); 1540 argsArr.push(context.factory.createStringLiteral(componentName), newExpression); 1541 }); 1542 } 1543 if (hasRouteName) { 1544 return [ 1545 shouldCreateAccsessRecording ? createStartGetAccessRecording(context) : undefined, 1546 createRegisterNamedRoute(context, newExpressionParams, isObject, entryOptionNode, hasRouteName), 1547 shouldCreateAccsessRecording ? createStopGetAccessRecording(context) : undefined]; 1548 } else { 1549 if (projectConfig.minAPIVersion > 10) { 1550 return [createRegisterNamedRoute(context, newExpressionParams, isObject, entryOptionNode, hasRouteName)]; 1551 } else { 1552 return [shouldCreateAccsessRecording ? createStartGetAccessRecording(context) : undefined, 1553 context.factory.createExpressionStatement(context.factory.createCallExpression( 1554 context.factory.createIdentifier(cardRelativePath ? CARD_ENTRY_FUNCTION_NAME : 1555 PAGE_ENTRY_FUNCTION_NAME), undefined, newExpressionParams)), 1556 shouldCreateAccsessRecording ? createStopGetAccessRecording(context) : undefined]; 1557 } 1558 } 1559} 1560 1561function createRegisterNamedRoute(context: ts.TransformationContext, newExpressionParams: ts.NewExpression[], 1562 isObject: boolean, entryOptionNode: ts.Expression, hasRouteName: boolean): ts.ExpressionStatement { 1563 const isByteCodeHar: boolean = projectConfig.compileHar && projectConfig.byteCodeHar; 1564 return context.factory.createExpressionStatement(context.factory.createCallExpression( 1565 context.factory.createIdentifier(REGISTER_NAMED_ROUTE), 1566 undefined, 1567 [ 1568 context.factory.createArrowFunction( 1569 undefined, 1570 undefined, 1571 [], 1572 undefined, 1573 context.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), 1574 newExpressionParams[0] 1575 ), 1576 hasRouteName ? isObject ? ts.factory.createIdentifier(ROUTENAME_NODE) : context.factory.createPropertyAccessExpression( 1577 entryOptionNode, 1578 context.factory.createIdentifier(ROUTE_NAME) 1579 ) : ts.factory.createStringLiteral(''), 1580 context.factory.createObjectLiteralExpression( 1581 [ 1582 routerBundleOrModule(context, isByteCodeHar, RESOURCE_NAME_BUNDLE), 1583 routerBundleOrModule(context, isByteCodeHar, RESOURCE_NAME_MODULE), 1584 routerOrNavPathWrite(context, PAGE_PATH, projectConfig.projectPath, projectConfig.projectRootPath), 1585 routerOrNavPathWrite(context, PAGE_FULL_PATH, projectConfig.projectRootPath), 1586 context.factory.createPropertyAssignment( 1587 context.factory.createIdentifier(INTEGRATED_HSP), 1588 context.factory.createStringLiteral(integratedHspType()) 1589 ), 1590 routerModuleType(context) 1591 ], 1592 false 1593 ) 1594 ] 1595 )); 1596} 1597 1598export function createStartGetAccessRecording(context: ts.TransformationContext): ts.ExpressionStatement { 1599 return context.factory.createExpressionStatement( 1600 context.factory.createCallExpression( 1601 context.factory.createPropertyAccessExpression( 1602 context.factory.createIdentifier(VIEWSTACKPROCESSOR), 1603 context.factory.createIdentifier(STARTGETACCESSRECORDINGFOR) 1604 ), 1605 undefined, 1606 [context.factory.createCallExpression( 1607 context.factory.createPropertyAccessExpression( 1608 context.factory.createIdentifier(VIEWSTACKPROCESSOR), 1609 context.factory.createIdentifier(ALLOCATENEWELMETIDFORNEXTCOMPONENT) 1610 ), 1611 undefined, 1612 [] 1613 )] 1614 ) 1615 ); 1616} 1617 1618function createLoadDocument(context: ts.TransformationContext, name: string, 1619 cardRelativePath: string, localStorageName: string, entryNodeKey: ts.Expression): ts.ExpressionStatement { 1620 const newArray: ts.Expression[] = [ 1621 context.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UNDEFINED), 1622 context.factory.createObjectLiteralExpression([], false) 1623 ]; 1624 if (localStorageName && entryNodeKey) { 1625 newArray.push(entryNodeKey); 1626 } 1627 const newExpressionParams: any[] = [ 1628 context.factory.createNewExpression( 1629 context.factory.createIdentifier(name), 1630 undefined, newArray)]; 1631 addCardStringliteral(newExpressionParams, context, cardRelativePath); 1632 return context.factory.createExpressionStatement( 1633 context.factory.createCallExpression( 1634 context.factory.createIdentifier(cardRelativePath ? CARD_ENTRY_FUNCTION_NAME : 1635 PAGE_ENTRY_FUNCTION_NAME), undefined, newExpressionParams) 1636 ); 1637} 1638 1639function createStopGetAccessRecording(context: ts.TransformationContext): ts.ExpressionStatement { 1640 return context.factory.createExpressionStatement( 1641 context.factory.createCallExpression( 1642 context.factory.createPropertyAccessExpression( 1643 context.factory.createIdentifier(VIEWSTACKPROCESSOR), 1644 context.factory.createIdentifier(STOPGETACCESSRECORDING) 1645 ), 1646 undefined, 1647 [] 1648 ) 1649 ); 1650} 1651 1652function addStorageParam(name: string): [string, ts.Expression] { 1653 let localStorageName: string; 1654 let localStorageNode: ts.Identifier | ts.ObjectLiteralExpression; 1655 const localStorageNum: number = (localStorageLinkCollection.get(name) || new Set()).size + 1656 (localStoragePropCollection.get(name) || new Set()).size; 1657 if (componentCollection.entryComponent === name) { 1658 if (componentCollection.localStorageNode) { 1659 localStorageNode = componentCollection.localStorageNode; 1660 } 1661 if (componentCollection.localStorageName) { 1662 localStorageName = componentCollection.localStorageName; 1663 } 1664 if (!hasStorage() && localStorageNum) { 1665 transformLog.errors.push({ 1666 type: LogType.WARN, 1667 message: `@Entry should have a parameter, like '@Entry (storage)'.`, 1668 pos: componentCollection.entryComponentPos 1669 }); 1670 } 1671 } 1672 return [localStorageName, localStorageNode]; 1673} 1674 1675function hasStorage(): boolean { 1676 if (componentCollection.localStorageName || componentCollection.localStorageNode || 1677 componentCollection.localSharedStorage) { 1678 return true; 1679 } 1680 return false; 1681} 1682 1683function createPreviewComponentFunction(name: string, context: ts.TransformationContext, 1684 cardRelativePath: string, entryNodeKey: ts.Expression, id: number): ts.Statement { 1685 const newArray: ts.Expression[] = partialUpdateConfig.partialUpdateMode ? 1686 [ 1687 context.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UNDEFINED), 1688 context.factory.createObjectLiteralExpression([], false) 1689 ] : 1690 [ 1691 context.factory.createStringLiteral(id.toString()), 1692 context.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UNDEFINED), 1693 context.factory.createObjectLiteralExpression([], false) 1694 ]; 1695 const [localStorageName, entryOptionNode]: [string, ts.Expression] = addStorageParam(name); 1696 if (entryOptionNode) { 1697 newArray.push(entryOptionNode); 1698 } 1699 const argsArr: ts.Expression[] = []; 1700 componentCollection.previewComponent.forEach(componentName => { 1701 const newExpression: ts.Expression = context.factory.createNewExpression( 1702 context.factory.createIdentifier(componentName), 1703 undefined, 1704 newArray 1705 ); 1706 argsArr.push(context.factory.createStringLiteral(componentName)); 1707 argsArr.push(newExpression); 1708 }); 1709 const newExpressionParams: any[] = name ? [context.factory.createNewExpression( 1710 context.factory.createIdentifier(name), undefined, newArray)] : []; 1711 addCardStringliteral(newExpressionParams, context, cardRelativePath); 1712 const ifStatement: ts.Statement = context.factory.createIfStatement( 1713 context.factory.createCallExpression( 1714 context.factory.createIdentifier(GET_PREVIEW_FLAG_FUNCTION_NAME), 1715 undefined, 1716 [] 1717 ), 1718 context.factory.createBlock( 1719 [...storePreviewComponents(name, entryOptionNode, argsArr), 1720 context.factory.createExpressionStatement(context.factory.createCallExpression( 1721 context.factory.createIdentifier(PREVIEW_COMPONENT_FUNCTION_NAME), 1722 undefined, 1723 [] 1724 ))], 1725 true 1726 ), 1727 context.factory.createBlock( 1728 createPreviewElseBlock(name, context, cardRelativePath, localStorageName, entryOptionNode, 1729 newExpressionParams, argsArr), 1730 true 1731 ) 1732 ); 1733 return ifStatement; 1734} 1735 1736function storePreviewComponents(name: string, entryOptionNode: ts.Expression, argsArr: ts.Expression[]): 1737 (ts.ExpressionStatement | ts.VariableStatement | ts.IfStatement)[] { 1738 let isObject: boolean = false; 1739 let storageNode: ts.Expression; 1740 if (!entryOptionNode) { 1741 return [ts.factory.createExpressionStatement(ts.factory.createCallExpression( 1742 ts.factory.createIdentifier(STORE_PREVIEW_COMPONENTS), 1743 undefined, 1744 [ 1745 ts.factory.createNumericLiteral(componentCollection.previewComponent.length), 1746 ...argsArr 1747 ] 1748 ))]; 1749 } 1750 if (ts.isObjectLiteralExpression(entryOptionNode)) { 1751 isObject = true; 1752 if (entryOptionNode.properties) { 1753 entryOptionNode.properties.forEach((property) => { 1754 if (ts.isPropertyAssignment(property) && property.name && ts.isIdentifier(property.name) && 1755 property.name.escapedText.toString() === STORAGE) { 1756 storageNode = property.initializer; 1757 } 1758 }); 1759 } 1760 } else { 1761 isObject = false; 1762 } 1763 const newArray: ts.Expression[] = [ 1764 ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UNDEFINED), 1765 ts.factory.createObjectLiteralExpression([], false) 1766 ]; 1767 const newArgsArr: ts.Expression[] = []; 1768 if (isObject) { 1769 return processObjectStorage(storageNode, newArray, name, newArgsArr); 1770 } else { 1771 return [ts.factory.createIfStatement( 1772 ts.factory.createBinaryExpression( 1773 entryOptionNode, 1774 ts.factory.createToken(ts.SyntaxKind.AmpersandAmpersandToken), 1775 ts.factory.createBinaryExpression( 1776 ts.factory.createPropertyAccessExpression( 1777 entryOptionNode, 1778 ts.factory.createIdentifier(STORAGE) 1779 ), 1780 ts.factory.createToken(ts.SyntaxKind.ExclamationEqualsToken), 1781 ts.factory.createIdentifier('undefined') 1782 ) 1783 ), 1784 ts.factory.createBlock( 1785 [returnStorePreview(entryOptionNode, true, name)], 1786 true 1787 ), 1788 ts.factory.createBlock( 1789 [returnStorePreview(entryOptionNode, false, name)], 1790 true 1791 ) 1792 )]; 1793 } 1794} 1795 1796function processObjectStorage(storageNode: ts.Expression, newArray: ts.Expression[], name: string, 1797 newArgsArr: ts.Expression[]): (ts.ExpressionStatement | ts.VariableStatement)[] { 1798 if (storageNode) { 1799 newArray.push(ts.factory.createIdentifier(STORAGE_NODE)); 1800 componentCollection.previewComponent.forEach(componentName => { 1801 const newExpression: ts.Expression = ts.factory.createNewExpression( 1802 ts.factory.createIdentifier(componentName), 1803 undefined, 1804 componentName === name ? newArray : newArray.slice(0, newArray.length - 1) 1805 ); 1806 newArgsArr.push(ts.factory.createStringLiteral(componentName)); 1807 newArgsArr.push(newExpression); 1808 }); 1809 return [ts.factory.createVariableStatement( 1810 undefined, 1811 ts.factory.createVariableDeclarationList( 1812 [ts.factory.createVariableDeclaration( 1813 ts.factory.createIdentifier(STORAGE_NODE), 1814 undefined, 1815 undefined, 1816 storageNode 1817 )], 1818 ts.NodeFlags.Let 1819 ) 1820 ), ts.factory.createExpressionStatement(ts.factory.createCallExpression( 1821 ts.factory.createIdentifier(STORE_PREVIEW_COMPONENTS), 1822 undefined, 1823 [ 1824 ts.factory.createNumericLiteral(componentCollection.previewComponent.length), 1825 ...newArgsArr 1826 ] 1827 ))]; 1828 } else { 1829 componentCollection.previewComponent.forEach(componentName => { 1830 const newExpression: ts.Expression = ts.factory.createNewExpression( 1831 ts.factory.createIdentifier(componentName), 1832 undefined, 1833 newArray 1834 ); 1835 newArgsArr.push(ts.factory.createStringLiteral(componentName)); 1836 newArgsArr.push(newExpression); 1837 }); 1838 return [ts.factory.createExpressionStatement(ts.factory.createCallExpression( 1839 ts.factory.createIdentifier(STORE_PREVIEW_COMPONENTS), 1840 undefined, 1841 [ 1842 ts.factory.createNumericLiteral(componentCollection.previewComponent.length), 1843 ...newArgsArr 1844 ] 1845 ))]; 1846 } 1847} 1848 1849function returnStorePreview(entryOptionNode: ts.Expression, hasStorage: boolean, name: string): ts.ExpressionStatement { 1850 const newArray: ts.Expression[] = [ 1851 ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UNDEFINED), 1852 ts.factory.createObjectLiteralExpression([], false) 1853 ]; 1854 const newArgsArr: ts.Expression[] = []; 1855 newArray.push(hasStorage ? ts.factory.createPropertyAccessExpression( 1856 entryOptionNode, 1857 ts.factory.createIdentifier(STORAGE) 1858 ) : entryOptionNode); 1859 componentCollection.previewComponent.forEach(componentName => { 1860 const newExpression: ts.Expression = ts.factory.createNewExpression( 1861 ts.factory.createIdentifier(componentName), 1862 undefined, 1863 componentName === name ? newArray : newArray.slice(0, newArray.length - 1) 1864 ); 1865 newArgsArr.push(ts.factory.createStringLiteral(componentName)); 1866 newArgsArr.push(newExpression); 1867 }); 1868 return ts.factory.createExpressionStatement(ts.factory.createCallExpression( 1869 ts.factory.createIdentifier(STORE_PREVIEW_COMPONENTS), 1870 undefined, 1871 [ 1872 ts.factory.createNumericLiteral(componentCollection.previewComponent.length), 1873 ...newArgsArr 1874 ] 1875 )); 1876} 1877 1878function createPreviewElseBlock(name: string, context: ts.TransformationContext, cardRelativePath: string, 1879 localStorageName: string, entryOptionNode: ts.Expression, newExpressionParams: ts.Expression[], 1880 argsArr: ts.Expression[]): (ts.ExpressionStatement | ts.IfStatement | ts.Block | ts.Statement)[] { 1881 if (name) { 1882 if (!partialUpdateConfig.partialUpdateMode) { 1883 return [context.factory.createExpressionStatement(context.factory.createCallExpression( 1884 context.factory.createIdentifier(STORE_PREVIEW_COMPONENTS), 1885 undefined, 1886 [ 1887 context.factory.createNumericLiteral(componentCollection.previewComponent.length), 1888 ...argsArr 1889 ] 1890 )), 1891 context.factory.createExpressionStatement(context.factory.createCallExpression( 1892 context.factory.createIdentifier(cardRelativePath ? CARD_ENTRY_FUNCTION_NAME : 1893 PAGE_ENTRY_FUNCTION_NAME), undefined, newExpressionParams 1894 ))]; 1895 } else { 1896 if (cardRelativePath) { 1897 if (entryOptionNode && ts.isObjectLiteralExpression(entryOptionNode)) { 1898 transformLog.errors.push({ 1899 type: LogType.ERROR, 1900 message: `@Entry doesn't support {} parameter in card`, 1901 pos: componentCollection.entryComponentPos 1902 }); 1903 } 1904 return [ 1905 name ? createStartGetAccessRecording(context) : undefined, 1906 name ? context.factory.createExpressionStatement(context.factory.createCallExpression( 1907 context.factory.createIdentifier(cardRelativePath ? CARD_ENTRY_FUNCTION_NAME : 1908 PAGE_ENTRY_FUNCTION_NAME), undefined, newExpressionParams 1909 )) : undefined, 1910 name ? createStopGetAccessRecording(context) : undefined 1911 ]; 1912 } 1913 return createLoadPageConditionalJudgMent(context, name, cardRelativePath, localStorageName, 1914 entryOptionNode, argsArr, true); 1915 } 1916 } 1917 return undefined; 1918} 1919 1920export function resetLog(): void { 1921 transformLog.errors = []; 1922} 1923 1924function addCardStringliteral(newExpressionParams: any[], context: ts.TransformationContext, 1925 cardRelativePath: string): void { 1926 if (cardRelativePath) { 1927 newExpressionParams.push(context.factory.createStringLiteral( 1928 projectConfig.bundleName + '/' + projectConfig.moduleName + '/' + 1929 cardRelativePath)); 1930 } 1931} 1932 1933export function validatorCard(log: any[], type: number, pos: number, 1934 name: string = ''): void { 1935 if (projectConfig && projectConfig.cardObj && resourceFileName && 1936 projectConfig.cardObj[resourceFileName]) { 1937 const logInfo: object = { 1938 type: LogType.ERROR, 1939 message: '', 1940 pos: pos 1941 }; 1942 switch (type) { 1943 case CARD_LOG_TYPE_COMPONENTS: 1944 logInfo.message = `Card page cannot use the component ${name}.`; 1945 break; 1946 case CARD_LOG_TYPE_DECORATORS: 1947 logInfo.message = `Card page cannot use ${name}`; 1948 break; 1949 case CARD_LOG_TYPE_IMPORT: 1950 logInfo.message = `Card page cannot use import.`; 1951 break; 1952 } 1953 log.push(logInfo); 1954 } 1955} 1956 1957export function resetProcessUiSyntax(): void { 1958 transformLog = new createAstNodeUtils.FileLog(); 1959 contextGlobal = undefined; 1960} 1961 1962function createSharedStorageWithRoute(context: ts.TransformationContext, name: string, cardRelativePath: string, 1963 entryOptionNode: ts.Expression, shouldCreateAccsessRecording: boolean, argsArr: ts.Expression[]): ts.Statement[] { 1964 const newArray: ts.Expression[] = [ 1965 ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UNDEFINED), 1966 ts.factory.createObjectLiteralExpression([], false), 1967 createGetSharedForVariable(entryOptionNode, false) 1968 ]; 1969 return loadDocumentWithRoute(context, name, newArray, argsArr, false, shouldCreateAccsessRecording, 1970 false, entryOptionNode, cardRelativePath); 1971} 1972 1973function insertImportModuleNode(statements: ts.Statement[], hasUseResource: boolean): ts.Statement[] { 1974 if (projectConfig.compileHar && projectConfig.byteCodeHar && (hasUseResource || componentCollection.entryComponent)) { 1975 statements.unshift(createAstNodeUtils.createImportNodeForModuleInfo()); 1976 } 1977 return statements; 1978} 1979