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