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