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