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_EXTEND_DECORATOR, 30 COMPONENT_STYLES_DECORATOR, 31 RESOURCE, 32 RESOURCE_TYPE, 33 WORKER_OBJECT, 34 RESOURCE_NAME_ID, 35 RESOURCE_NAME_TYPE, 36 RESOURCE_NAME_PARAMS, 37 RESOURCE_RAWFILE, 38 RESOURCE_NAME_BUNDLE, 39 RESOURCE_NAME_MODULE, 40 ATTRIBUTE_ANIMATETO, 41 GLOBAL_CONTEXT, 42 CHECK_COMPONENT_EXTEND_DECORATOR, 43 INSTANCE, 44 SET_CONTROLLER_CTR_TYPE, 45 SET_CONTROLLER_METHOD, 46 JS_DIALOG, 47 CUSTOM_DIALOG_CONTROLLER_BUILDER, 48 ESMODULE, 49 ARK, 50 EXTNAME_ETS, 51 GENERATE_ID, 52 _GENERATE_ID, 53 VIEWSTACKPROCESSOR, 54 STARTGETACCESSRECORDINGFOR, 55 ALLOCATENEWELMETIDFORNEXTCOMPONENT, 56 STOPGETACCESSRECORDING, 57 CARD_ENTRY_FUNCTION_NAME, 58 CARD_LOG_TYPE_COMPONENTS, 59 CARD_LOG_TYPE_DECORATORS, 60 CARD_LOG_TYPE_IMPORT, 61 COMPONENT_ANIMATABLE_EXTEND_DECORATOR, 62 CHECK_EXTEND_DECORATORS, 63 ELMTID, 64 ROUTENAME_NODE, 65 STORAGE_NODE, 66 STORAGE, 67 REGISTER_NAMED_ROUTE, 68 ROUTE_NAME, 69 PAGE_PATH, 70 ISINITIALRENDER, 71 CREATE_ANIMATABLE_PROPERTY, 72 COMPONENT_CREATE_FUNCTION, 73 COMPONENT_POP_FUNCTION, 74 UPDATE_ANIMATABLE_PROPERTY, 75 VIEW_STACK_PROCESSOR, 76 GET_AND_PUSH_FRAME_NODE, 77 COMPONENT_CONSTRUCTOR_PARENT, 78 FINISH_UPDATE_FUNC, 79} from './pre_define'; 80import { 81 componentInfo, 82 LogInfo, 83 LogType, 84 hasDecorator, 85 FileLog, 86 getPossibleBuilderTypeParameter, 87 storedFileInfo, 88 ExtendResult 89} from './utils'; 90import { writeFileSyncByNode } from './process_module_files'; 91import { 92 componentCollection, 93 localStorageLinkCollection, 94 localStoragePropCollection, 95} from './validate_ui_syntax'; 96import { 97 processComponentClass, 98 createParentParameter, 99 processBuildMember 100} from './process_component_class'; 101import processImport, { 102 processImportModule 103} from './process_import'; 104import { 105 processComponentBlock, 106 bindComponentAttr, 107 getName, 108 createViewStackProcessorStatement, 109 createFunction 110} from './process_component_build'; 111import { 112 BUILDIN_STYLE_NAMES, 113 CUSTOM_BUILDER_METHOD, 114 EXTEND_ATTRIBUTE, 115 INNER_STYLE_FUNCTION, 116 GLOBAL_STYLE_FUNCTION, 117 INTERFACE_NODE_SET, 118 ID_ATTRS 119} from './component_map'; 120import { 121 resources, 122 projectConfig, 123 partialUpdateConfig 124} from '../main'; 125import { createCustomComponentNewExpression, createViewCreate } from './process_component_member'; 126import { assignComponentParams } from './process_custom_component'; 127import { ModuleSourceFile } from './fast_build/ark_compiler/module/module_source_file'; 128 129export const transformLog: FileLog = new FileLog(); 130export let contextGlobal: ts.TransformationContext; 131export let resourceFileName: string = ''; 132export const builderTypeParameter: {params: string[]} = {params: []}; 133 134export let hasTsNoCheckOrTsIgnoreFiles: string[] = []; 135export let compilingEtsOrTsFiles: string[] = []; 136 137export function processUISyntax(program: ts.Program, ut = false): Function { 138 let entryNodeKey: ts.Expression; 139 return (context: ts.TransformationContext) => { 140 contextGlobal = context; 141 let pagesDir: string; 142 return (node: ts.SourceFile) => { 143 const hasTsNoCheckOrTsIgnore = ts.hasTsNoCheckOrTsIgnoreFlag(node); 144 compilingEtsOrTsFiles.push(path.normalize(node.fileName)); 145 pagesDir = path.resolve(path.dirname(node.fileName)); 146 resourceFileName = path.resolve(node.fileName); 147 if (process.env.compiler === BUILD_ON || process.env.compileTool === 'rollup') { 148 storedFileInfo.transformCacheFiles[node.fileName] = { 149 mtimeMs: fs.existsSync(node.fileName) ? fs.statSync(node.fileName).mtimeMs : 0, 150 children: [] 151 } 152 transformLog.sourceFile = node; 153 preprocessIdAttrs(node.fileName); 154 if (!ut && (process.env.compileMode !== 'moduleJson' && 155 path.resolve(node.fileName) === path.resolve(projectConfig.projectPath, 'app.ets') || 156 /\.ts$/.test(node.fileName))) { 157 node = ts.visitEachChild(node, processResourceNode, context); 158 if (projectConfig.compileMode === ESMODULE) { 159 if (projectConfig.processTs === true) { 160 const processedNode: ts.SourceFile = ts.getTypeExportImportAndConstEnumTransformer(context)(node); 161 if (process.env.compileTool === 'rollup') { 162 hasTsNoCheckOrTsIgnore ? hasTsNoCheckOrTsIgnoreFiles.push(path.normalize(processedNode.fileName)) : 163 ModuleSourceFile.newSourceFile(path.normalize(processedNode.fileName), processedNode); 164 } else { 165 writeFileSyncByNode(processedNode, projectConfig); 166 } 167 } 168 } 169 return node; 170 } 171 const id: number = ++componentInfo.id; 172 node = ts.visitEachChild(node, processAllNodes, context); 173 node = createEntryNode(node, context, entryNodeKey, id); 174 GLOBAL_STYLE_FUNCTION.forEach((block, styleName) => { 175 BUILDIN_STYLE_NAMES.delete(styleName); 176 }); 177 GLOBAL_STYLE_FUNCTION.clear(); 178 const statements: ts.Statement[] = Array.from(node.statements); 179 if (!partialUpdateConfig.partialUpdateMode) { 180 generateId(statements, node); 181 } 182 INTERFACE_NODE_SET.forEach(item => { 183 statements.unshift(item); 184 }); 185 node = ts.factory.updateSourceFile(node, statements); 186 INTERFACE_NODE_SET.clear(); 187 if (projectConfig.compileMode === ESMODULE && projectConfig.processTs === true) { 188 const processedNode: ts.SourceFile = ts.getTypeExportImportAndConstEnumTransformer(context)(node); 189 if (process.env.compileTool === 'rollup') { 190 hasTsNoCheckOrTsIgnore ? hasTsNoCheckOrTsIgnoreFiles.push(path.normalize(processedNode.fileName)) : 191 ModuleSourceFile.newSourceFile(path.normalize(processedNode.fileName), processedNode); 192 } else { 193 writeFileSyncByNode(processedNode, projectConfig); 194 } 195 } 196 return node; 197 } else { 198 return node; 199 } 200 }; 201 202 function entryKeyNode(node: ts.Node): ts.Expression { 203 if (node && node.decorators && node.decorators.length) { 204 node.decorators.forEach(item => { 205 if (item.expression && ts.isCallExpression(item.expression) && ts.isIdentifier(item.expression.expression) && 206 item.expression.expression.escapedText.toString() === 'Entry' && item.expression.arguments && 207 item.expression.arguments.length && ts.isIdentifier(item.expression.arguments[0])) { 208 entryNodeKey = item.expression.arguments[0]; 209 } 210 }); 211 } 212 return entryNodeKey; 213 } 214 215 function isESObjectNode(node: ts.Node): boolean { 216 if (node.kind === ts.SyntaxKind.TypeReference) { 217 const n: TypeReferenceNode = node as TypeReferenceNode; 218 if (n.typeName?.kind === ts.SyntaxKind.Identifier && (n.typeName as ts.Identifier).escapedText === 'ESObject') { 219 return true; 220 } 221 } 222 return false; 223 } 224 225 function processAllNodes(node: ts.Node): ts.Node { 226 if (projectConfig.compileMode === 'esmodule' && process.env.compileTool === 'rollup' && 227 ts.isImportDeclaration(node)) { 228 processImportModule(node); 229 } else if ((projectConfig.compileMode !== 'esmodule' || process.env.compileTool !== 'rollup') && 230 (ts.isImportDeclaration(node) || ts.isImportEqualsDeclaration(node) || 231 ts.isExportDeclaration(node) && node.moduleSpecifier && ts.isStringLiteral(node.moduleSpecifier))) { 232 processImport(node, pagesDir, transformLog.errors); 233 } 234 if (ts.isStructDeclaration(node)) { 235 componentCollection.currentClassName = node.name.getText(); 236 componentCollection.entryComponent === componentCollection.currentClassName && entryKeyNode(node); 237 node = processComponentClass(node, context, transformLog.errors, program); 238 componentCollection.currentClassName = null; 239 INNER_STYLE_FUNCTION.forEach((block, styleName) => { 240 BUILDIN_STYLE_NAMES.delete(styleName); 241 }); 242 INNER_STYLE_FUNCTION.clear(); 243 } else if (ts.isFunctionDeclaration(node)) { 244 if (hasDecorator(node, COMPONENT_EXTEND_DECORATOR, null, transformLog.errors)) { 245 node = processExtend(node, transformLog.errors, COMPONENT_EXTEND_DECORATOR); 246 } else if (hasDecorator(node, COMPONENT_BUILDER_DECORATOR) && node.name && node.body && 247 ts.isBlock(node.body)) { 248 CUSTOM_BUILDER_METHOD.add(node.name.getText()); 249 builderTypeParameter.params = getPossibleBuilderTypeParameter(node.parameters); 250 let parameters: ts.NodeArray<ts.ParameterDeclaration> = 251 ts.factory.createNodeArray(Array.from(node.parameters)); 252 parameters.push(createParentParameter()); 253 node = ts.factory.updateFunctionDeclaration(node, undefined, node.modifiers, 254 node.asteriskToken, node.name, node.typeParameters, parameters, node.type, 255 processComponentBlock(node.body, false, transformLog.errors, false, true, 256 node.name.getText(), undefined, true)); 257 builderTypeParameter.params = []; 258 node = processBuildMember(node, context, transformLog.errors, true); 259 } else if (hasDecorator(node, COMPONENT_STYLES_DECORATOR)) { 260 if (node.parameters.length === 0) { 261 node = undefined; 262 } else { 263 transformLog.errors.push({ 264 type: LogType.ERROR, 265 message: `@Styles can't have parameters.`, 266 pos: node.getStart() 267 }); 268 } 269 } else if (hasDecorator(node, COMPONENT_CONCURRENT_DECORATOR)) { 270 // ark compiler's feature 271 node = processConcurrent(node); 272 } else if (hasDecorator(node, COMPONENT_ANIMATABLE_EXTEND_DECORATOR, null, transformLog.errors)) { 273 node = processExtend(node, transformLog.errors, COMPONENT_ANIMATABLE_EXTEND_DECORATOR); 274 } 275 } else if (isResource(node)) { 276 node = processResourceData(node as ts.CallExpression); 277 } else if (isWorker(node)) { 278 node = processWorker(node as ts.NewExpression); 279 } else if (isAnimateTo(node)) { 280 node = processAnimateTo(node as ts.CallExpression); 281 } else if (isCustomDialogController(node)) { 282 node = createCustomDialogController(node.parent, node, transformLog.errors); 283 } else if (isESObjectNode(node)) { 284 node = ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword); 285 } 286 return ts.visitEachChild(node, processAllNodes, context); 287 } 288 function processResourceNode(node: ts.Node): ts.Node { 289 if (isResource(node)) { 290 node = processResourceData(node as ts.CallExpression); 291 } 292 return ts.visitEachChild(node, processResourceNode, context); 293 } 294 }; 295} 296 297function generateId(statements: ts.Statement[], node: ts.SourceFile): void { 298 statements.unshift( 299 ts.factory.createVariableStatement( 300 undefined, 301 ts.factory.createVariableDeclarationList( 302 [ts.factory.createVariableDeclaration( 303 ts.factory.createIdentifier(_GENERATE_ID), 304 undefined, 305 ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword), 306 ts.factory.createNumericLiteral('0') 307 )], 308 ts.NodeFlags.Let 309 ) 310 ), 311 ts.factory.createFunctionDeclaration( 312 undefined, 313 undefined, 314 undefined, 315 ts.factory.createIdentifier(GENERATE_ID), 316 undefined, 317 [], 318 ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword), 319 ts.factory.createBlock( 320 [ts.factory.createReturnStatement(ts.factory.createBinaryExpression( 321 ts.factory.createStringLiteral(path.basename(node.fileName, EXTNAME_ETS) + '_'), 322 ts.factory.createToken(ts.SyntaxKind.PlusToken), ts.factory.createPrefixUnaryExpression( 323 ts.SyntaxKind.PlusPlusToken, 324 ts.factory.createIdentifier(_GENERATE_ID) 325 )))], 326 true 327 ) 328 ) 329 ); 330} 331 332function preprocessIdAttrs(fileName: string): void { 333 for (const [id, idInfo] of ID_ATTRS) { 334 if (fileName === idInfo.get('path')) { 335 ID_ATTRS.delete(id); 336 } 337 } 338} 339 340function isCustomDialogController(node: ts.Expression) { 341 const tempParent: ts.Node = node.parent; 342 // @ts-ignore 343 if (!node.parent && node.original) { 344 // @ts-ignore 345 node.parent = node.original.parent; 346 } 347 if (ts.isNewExpression(node) && node.expression && ts.isIdentifier(node.expression) && 348 node.expression.escapedText.toString() === SET_CONTROLLER_CTR_TYPE) { 349 return true; 350 } else { 351 // @ts-ignore 352 node.parent = tempParent; 353 return false; 354 } 355} 356 357function createCustomDialogController(parent: ts.Expression, node: ts.NewExpression, 358 log: LogInfo[]): ts.NewExpression { 359 if (node.arguments && node.arguments.length === 1 && 360 ts.isObjectLiteralExpression(node.arguments[0]) && node.arguments[0].properties) { 361 const newproperties: ts.ObjectLiteralElementLike[] = node.arguments[0].properties.map((item) => { 362 const componentName: string = isCustomDialogControllerPropertyAssignment(item, log); 363 if (componentName !== null) { 364 item = processCustomDialogControllerPropertyAssignment(parent, 365 item as ts.PropertyAssignment, componentName); 366 } 367 return item; 368 }); 369 return ts.factory.createNewExpression(node.expression, node.typeArguments, 370 [ts.factory.createObjectLiteralExpression(newproperties, true), ts.factory.createThis()]); 371 } else { 372 return node; 373 } 374} 375 376function isCustomDialogControllerPropertyAssignment(node: ts.ObjectLiteralElementLike, 377 log: LogInfo[]): string { 378 if (ts.isPropertyAssignment(node) && ts.isIdentifier(node.name) && 379 node.name.getText() === CUSTOM_DIALOG_CONTROLLER_BUILDER) { 380 if (node.initializer) { 381 const componentName: string = getName(node.initializer); 382 if (componentCollection.customDialogs.has(componentName)) { 383 return componentName; 384 } 385 } else { 386 validateCustomDialogControllerBuilderInit(node, log); 387 } 388 } 389 return null; 390} 391 392function validateCustomDialogControllerBuilderInit(node: ts.ObjectLiteralElementLike, 393 log: LogInfo[]): void { 394 log.push({ 395 type: LogType.ERROR, 396 message: 'The builder should be initialized with a @CustomDialog Component.', 397 pos: node.getStart() 398 }); 399} 400 401function processCustomDialogControllerPropertyAssignment(parent: ts.Expression, 402 node: ts.PropertyAssignment, componentName: string): ts.PropertyAssignment { 403 if (ts.isCallExpression(node.initializer)) { 404 return ts.factory.updatePropertyAssignment(node, node.name, 405 processCustomDialogControllerBuilder(parent, node.initializer, componentName)); 406 } 407} 408 409function processCustomDialogControllerBuilder(parent: ts.Expression, 410 node: ts.CallExpression, componentName: string): ts.ArrowFunction { 411 const newExp: ts.Expression = createCustomComponentNewExpression(node, componentName, false, false, true); 412 const jsDialog: ts.Identifier = ts.factory.createIdentifier(JS_DIALOG); 413 return createCustomComponentBuilderArrowFunction(node, parent, jsDialog, newExp); 414} 415 416function createCustomComponentBuilderArrowFunction(node: ts.CallExpression, parent: ts.Expression, 417 jsDialog: ts.Identifier, newExp: ts.Expression): ts.ArrowFunction { 418 let mountNodde: ts.PropertyAccessExpression; 419 if (ts.isBinaryExpression(parent)) { 420 mountNodde = parent.left; 421 } else if (ts.isVariableDeclaration(parent) || ts.isPropertyDeclaration(parent)) { 422 mountNodde = ts.factory.createPropertyAccessExpression(ts.factory.createThis(), 423 parent.name as ts.Identifier); 424 } 425 return ts.factory.createArrowFunction( 426 undefined, 427 undefined, 428 [], 429 undefined, 430 ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), 431 ts.factory.createBlock( 432 [ 433 partialUpdateConfig.partialUpdateMode ? assignComponentParams(node) : undefined, 434 ts.factory.createVariableStatement( 435 undefined, 436 ts.factory.createVariableDeclarationList( 437 [ts.factory.createVariableDeclaration(jsDialog, undefined, undefined, newExp)], 438 ts.NodeFlags.Let 439 ) 440 ), 441 ts.factory.createExpressionStatement( 442 ts.factory.createCallExpression( 443 ts.factory.createPropertyAccessExpression( 444 jsDialog, 445 ts.factory.createIdentifier(SET_CONTROLLER_METHOD) 446 ), 447 undefined, 448 mountNodde ? [mountNodde] : undefined 449 ) 450 ), 451 ts.factory.createExpressionStatement(createViewCreate(jsDialog)) 452 ], 453 true 454 ) 455 ); 456} 457 458export function isResource(node: ts.Node): boolean { 459 return ts.isCallExpression(node) && ts.isIdentifier(node.expression) && 460 (node.expression.escapedText.toString() === RESOURCE || 461 node.expression.escapedText.toString() === RESOURCE_RAWFILE) && node.arguments.length > 0; 462} 463 464export function isAnimateTo(node: ts.Node): boolean { 465 return ts.isCallExpression(node) && ts.isIdentifier(node.expression) && 466 node.expression.escapedText.toString() === ATTRIBUTE_ANIMATETO; 467} 468 469export function processResourceData(node: ts.CallExpression, 470 previewLog: {isAcceleratePreview: boolean, log: LogInfo[]} = {isAcceleratePreview: false, log: []}): ts.Node { 471 if (ts.isStringLiteral(node.arguments[0])) { 472 if (node.expression.getText() === RESOURCE_RAWFILE) { 473 isResourcefile(node, previewLog); 474 return createResourceParam(0, RESOURCE_TYPE.rawfile, [node.arguments[0]]); 475 } else { 476 return getResourceDataNode(node, previewLog); 477 } 478 } 479 return node; 480} 481 482function getResourceDataNode(node: ts.CallExpression, 483 previewLog: {isAcceleratePreview: boolean, log: LogInfo[]}): ts.Node { 484 const resourceData: string[] = (node.arguments[0] as ts.StringLiteral).text.trim().split('.'); 485 if (preCheckResourceData(resourceData, resources, node.arguments[0].getStart(), previewLog)) { 486 const resourceType: number = RESOURCE_TYPE[resourceData[1]]; 487 if (resourceType === undefined) { 488 transformLog.errors.push({ 489 type: LogType.ERROR, 490 message: `The resource type ${resourceData[1]} is not supported.`, 491 pos: node.getStart() 492 }); 493 return node; 494 } 495 const resourceValue: number = resources[resourceData[0]][resourceData[1]][resourceData[2]]; 496 return createResourceParam(resourceValue, resourceType, 497 projectConfig.compileHar ? Array.from(node.arguments) : Array.from(node.arguments).slice(1)); 498 } 499 return node; 500} 501 502function isResourcefile(node: ts.CallExpression, previewLog: {isAcceleratePreview: boolean, log: LogInfo[]}): void { 503 if (process.env.rawFileResource && !storedFileInfo.resourcesArr.has(node.arguments[0].text) && 504 !previewLog.isAcceleratePreview && process.env.compileMode === 'moduleJson') { 505 transformLog.errors.push({ 506 type: LogType.WARN, 507 message: `No such '${node.arguments[0].text}' resource in current module.`, 508 pos: node.getStart() 509 }); 510 } 511} 512 513function createResourceParam(resourceValue: number, resourceType: number, argsArr: ts.Expression[]): 514 ts.ObjectLiteralExpression { 515 if (projectConfig.compileHar) { 516 projectConfig.bundleName = ''; 517 projectConfig.moduleName = ''; 518 resourceValue = -1; 519 } 520 521 const propertyArray: Array<ts.PropertyAssignment> = [ 522 ts.factory.createPropertyAssignment( 523 ts.factory.createStringLiteral(RESOURCE_NAME_ID), 524 ts.factory.createNumericLiteral(resourceValue) 525 ), 526 ts.factory.createPropertyAssignment( 527 ts.factory.createStringLiteral(RESOURCE_NAME_TYPE), 528 ts.factory.createNumericLiteral(resourceType) 529 ), 530 ts.factory.createPropertyAssignment( 531 ts.factory.createIdentifier(RESOURCE_NAME_PARAMS), 532 ts.factory.createArrayLiteralExpression(argsArr, false) 533 ) 534 ]; 535 536 if (projectConfig.bundleName || projectConfig.bundleName === '') { 537 propertyArray.push(ts.factory.createPropertyAssignment( 538 ts.factory.createStringLiteral(RESOURCE_NAME_BUNDLE), 539 ts.factory.createStringLiteral(projectConfig.bundleName) 540 )); 541 } 542 543 if (projectConfig.moduleName || projectConfig.moduleName === '') { 544 propertyArray.push(ts.factory.createPropertyAssignment( 545 ts.factory.createStringLiteral(RESOURCE_NAME_MODULE), 546 ts.factory.createStringLiteral(projectConfig.moduleName) 547 )); 548 } 549 550 const resourceParams: ts.ObjectLiteralExpression = ts.factory.createObjectLiteralExpression( 551 propertyArray, false); 552 return resourceParams; 553} 554 555function preCheckResourceData(resourceData: string[], resources: object, pos: number, 556 previewLog: {isAcceleratePreview: boolean, log: LogInfo[]}): boolean { 557 if (previewLog.isAcceleratePreview) { 558 return validateResourceData(resourceData, resources, pos, previewLog.log, true); 559 } else { 560 return validateResourceData(resourceData, resources, pos, transformLog.errors, false); 561 } 562} 563 564function validateResourceData(resourceData: string[], resources: object, pos: number, log: LogInfo[], isAcceleratePreview: boolean): boolean { 565 if (resourceData.length !== 3) { 566 log.push({ 567 type: LogType.ERROR, 568 message: 'The input parameter is not supported.', 569 pos: pos 570 }); 571 } else { 572 if (!isAcceleratePreview && process.env.compileTool === 'rollup' && process.env.compileMode === 'moduleJson') { 573 storedFileInfo.collectResourceInFile(resourceData[1] + '_' + resourceData[2], path.resolve(resourceFileName)); 574 } 575 if (!resources[resourceData[0]]) { 576 log.push({ 577 type: LogType.ERROR, 578 message: `Unknown resource source '${resourceData[0]}'.`, 579 pos: pos 580 }); 581 } else if (!resources[resourceData[0]][resourceData[1]]) { 582 log.push({ 583 type: LogType.ERROR, 584 message: `Unknown resource type '${resourceData[1]}'.`, 585 pos: pos 586 }); 587 } else if (!resources[resourceData[0]][resourceData[1]][resourceData[2]]) { 588 log.push({ 589 type: LogType.ERROR, 590 message: `Unknown resource name '${resourceData[2]}'.`, 591 pos: pos 592 }); 593 } else { 594 return true; 595 } 596 } 597 return false; 598} 599 600function isWorker(node: ts.Node): boolean { 601 return ts.isNewExpression(node) && ts.isPropertyAccessExpression(node.expression) && 602 ts.isIdentifier(node.expression.name) && 603 node.expression.name.escapedText.toString() === WORKER_OBJECT; 604} 605 606function processWorker(node: ts.NewExpression): ts.Node { 607 if (node.arguments.length && ts.isStringLiteral(node.arguments[0])) { 608 const args: ts.Expression[] = Array.from(node.arguments); 609 // @ts-ignore 610 const workerPath: string = node.arguments[0].text; 611 const stringNode: ts.StringLiteral = ts.factory.createStringLiteral( 612 workerPath.replace(/\.ts$/, '.js')); 613 args.splice(0, 1, stringNode); 614 return ts.factory.updateNewExpression(node, node.expression, node.typeArguments, args); 615 } 616 return node; 617} 618 619export function processAnimateTo(node: ts.CallExpression): ts.CallExpression { 620 return ts.factory.updateCallExpression(node, ts.factory.createPropertyAccessExpression( 621 ts.factory.createIdentifier(GLOBAL_CONTEXT), ts.factory.createIdentifier(ATTRIBUTE_ANIMATETO)), 622 node.typeArguments, node.arguments); 623} 624 625function processExtend(node: ts.FunctionDeclaration, log: LogInfo[], 626 decoratorName: string): ts.FunctionDeclaration { 627 const componentName: string = isExtendFunction(node, { decoratorName: '', componentName: '' }, true); 628 if (componentName && node.body && node.body.statements.length) { 629 const statementArray: ts.Statement[] = []; 630 let bodynode: ts.Block; 631 if (decoratorName === COMPONENT_EXTEND_DECORATOR) { 632 const attrSet: ts.CallExpression = node.body.statements[0].expression; 633 if (isOriginalExtend(node.body)) { 634 const changeCompName: ts.ExpressionStatement = ts.factory.createExpressionStatement(processExtendBody(attrSet)); 635 bindComponentAttr(changeCompName as ts.ExpressionStatement, 636 ts.factory.createIdentifier(componentName), statementArray, log); 637 } else { 638 bodynode = ts.visitEachChild(node.body, traverseExtendExpression, contextGlobal); 639 } 640 let extendFunctionName: string; 641 if (node.name.getText().startsWith('__' + componentName + '__')) { 642 extendFunctionName = node.name.getText(); 643 } else { 644 extendFunctionName = '__' + componentName + '__' + node.name.getText(); 645 collectExtend(EXTEND_ATTRIBUTE, componentName, node.name.escapedText.toString()); 646 } 647 return ts.factory.updateFunctionDeclaration(node, undefined, node.modifiers, node.asteriskToken, 648 ts.factory.createIdentifier(extendFunctionName), node.typeParameters, 649 node.parameters, ts.factory.createToken(ts.SyntaxKind.VoidKeyword), isOriginalExtend(node.body) ? 650 ts.factory.updateBlock(node.body, statementArray) : bodynode); 651 } 652 if (decoratorName === COMPONENT_ANIMATABLE_EXTEND_DECORATOR) { 653 bindComponentAttr(node.body.statements[0], 654 ts.factory.createIdentifier(componentName), statementArray, log); 655 return ts.factory.updateFunctionDeclaration(node, undefined, node.modifiers, node.asteriskToken, 656 node.name, node.typeParameters, 657 [...node.parameters, ...createAnimatableParameterNode()], ts.factory.createToken(ts.SyntaxKind.VoidKeyword), 658 ts.factory.updateBlock(node.body, createAnimatableBody(componentName, node.name, 659 node.parameters, statementArray))); 660 } 661 } 662 function traverseExtendExpression(node: ts.Node): ts.Node { 663 if (ts.isExpressionStatement(node) && isDollarNode(node, componentName)) { 664 const changeCompName: ts.ExpressionStatement = 665 ts.factory.createExpressionStatement(processExtendBody(node.expression, componentName)); 666 const statementArray: ts.Statement[] = []; 667 bindComponentAttr(changeCompName, ts.factory.createIdentifier(componentName), statementArray, []); 668 return ts.factory.createBlock(statementArray, true); 669 } 670 return ts.visitEachChild(node, traverseExtendExpression, contextGlobal); 671 } 672} 673 674function createAnimatableParameterNode(): ts.ParameterDeclaration[] { 675 return [ 676 ts.factory.createParameterDeclaration( 677 undefined, undefined, undefined, ts.factory.createIdentifier(ELMTID)), 678 ts.factory.createParameterDeclaration( 679 undefined, undefined, undefined, ts.factory.createIdentifier(ISINITIALRENDER)), 680 ts.factory.createParameterDeclaration( 681 undefined, undefined, undefined, ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARENT)) 682 ]; 683} 684 685function createAnimatableBody(componentName: string, funcName: ts.Identifier, 686 parameters: ts.NodeArray<ts.ParameterDeclaration>, attrArray: ts.Statement[]): ts.Statement[] { 687 const paramNode: ts.Identifier[] = []; 688 parameters.forEach((item: ts.ParameterDeclaration) => { 689 if (item.name && ts.isIdentifier(item.name)) { 690 paramNode.push(item.name); 691 } 692 }); 693 return [ 694 ts.factory.createIfStatement( 695 ts.factory.createIdentifier(ISINITIALRENDER), 696 ts.factory.createBlock([ 697 createAnimatableProperty(componentName, funcName, parameters, paramNode, attrArray), 698 ...attrArray 699 ], true), 700 ts.factory.createBlock([ 701 ts.factory.createExpressionStatement(ts.factory.createCallExpression( 702 ts.factory.createPropertyAccessExpression( 703 ts.factory.createIdentifier(componentName), 704 ts.factory.createIdentifier(UPDATE_ANIMATABLE_PROPERTY) 705 ), undefined, 706 [ ts.factory.createStringLiteral(funcName.escapedText.toString()), ...paramNode ] 707 )) 708 ]) 709 ) 710 ]; 711} 712 713function createAnimatableProperty(componentName: string, funcName: ts.Identifier, 714 parameters: ts.NodeArray<ts.ParameterDeclaration>, 715 paramNode: ts.Identifier[], attrArray: ts.Statement[]) { 716 const componentIdentifier: ts.Identifier = ts.factory.createIdentifier(componentName); 717 return ts.factory.createExpressionStatement( 718 ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression( 719 componentIdentifier, 720 ts.factory.createIdentifier(CREATE_ANIMATABLE_PROPERTY)), 721 undefined, [ 722 ts.factory.createStringLiteral(funcName.escapedText.toString()), 723 ...paramNode, 724 ts.factory.createArrowFunction(undefined, undefined, parameters, undefined, 725 ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), 726 ts.factory.createBlock([ 727 createViewStackProcessorStatement(STARTGETACCESSRECORDINGFOR, ELMTID), 728 createAnimatableFrameNode(componentName), 729 ...attrArray, 730 createViewStackProcessorStatement(STOPGETACCESSRECORDING), 731 createAnimatableUpdateFunc() 732 ], true)) 733 ] 734 ) 735 ); 736} 737 738function createAnimatableFrameNode(componentName: string): ts.ExpressionStatement { 739 return ts.factory.createExpressionStatement(ts.factory.createCallExpression( 740 ts.factory.createPropertyAccessExpression( 741 ts.factory.createIdentifier(VIEW_STACK_PROCESSOR), 742 ts.factory.createIdentifier(GET_AND_PUSH_FRAME_NODE), 743 ), undefined, 744 [ 745 ts.factory.createStringLiteral(componentName), 746 ts.factory.createIdentifier(ELMTID) 747 ] 748 )); 749} 750 751function createAnimatableUpdateFunc(): ts.ExpressionStatement { 752 return ts.factory.createExpressionStatement(ts.factory.createCallExpression( 753 ts.factory.createPropertyAccessExpression( 754 ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARENT), 755 ts.factory.createIdentifier(FINISH_UPDATE_FUNC), 756 ), undefined, [ts.factory.createIdentifier(ELMTID)] 757 )); 758} 759 760function processConcurrent(node: ts.FunctionDeclaration): ts.FunctionDeclaration { 761 if (node.body) { 762 const statementArray: ts.Statement[] 763 = [ts.factory.createExpressionStatement(ts.factory.createStringLiteral('use concurrent')), 764 ...node.body.statements]; 765 return ts.factory.updateFunctionDeclaration(node, undefined, node.modifiers, node.asteriskToken, node.name, 766 node.typeParameters, node.parameters, node.type, ts.factory.updateBlock(node.body, statementArray)); 767 } 768 return node; 769} 770 771export function isOriginalExtend(node: ts.Block): boolean { 772 let innerNode: ts.Node = node.statements[0]; 773 if (node.statements.length === 1 && ts.isExpressionStatement(innerNode)) { 774 while (innerNode.expression) { 775 innerNode = innerNode.expression; 776 } 777 if (ts.isIdentifier(innerNode) && innerNode.pos && innerNode.end && innerNode.pos === innerNode.end && 778 innerNode.escapedText.toString().match(/Instance$/)) { 779 return true; 780 } 781 } 782 return false; 783} 784 785function isDollarNode(node: ts.ExpressionStatement, componentName: string): boolean { 786 let innerNode: ts.Node = node; 787 while (innerNode.expression) { 788 innerNode = innerNode.expression; 789 } 790 let changedIdentifier: string = '$'; 791 if (process.env.compileTool === 'rollup' && storedFileInfo.reUseProgram) { 792 changedIdentifier = `${componentName}Instance`; 793 } 794 if (ts.isIdentifier(innerNode) && innerNode.getText() === changedIdentifier) { 795 return true; 796 } else { 797 return false; 798 } 799} 800 801function processExtendBody(node: ts.Node, componentName?: string): ts.Expression { 802 switch (node.kind) { 803 case ts.SyntaxKind.CallExpression: 804 return ts.factory.createCallExpression(processExtendBody(node.expression, componentName), 805 undefined, node.arguments); 806 case ts.SyntaxKind.PropertyAccessExpression: 807 return ts.factory.createPropertyAccessExpression( 808 processExtendBody(node.expression, componentName), node.name); 809 case ts.SyntaxKind.Identifier: 810 if (!componentName) { 811 return ts.factory.createIdentifier(node.escapedText.toString().replace(INSTANCE, '')); 812 } else { 813 return ts.factory.createIdentifier(componentName); 814 } 815 } 816} 817 818export function collectExtend(collectionSet: Map<string, Set<string>>, component: string, attribute: string): void { 819 if (collectionSet.has(component)) { 820 collectionSet.get(component).add(attribute); 821 } else { 822 collectionSet.set(component, new Set([attribute])); 823 } 824} 825 826export function isExtendFunction(node: ts.FunctionDeclaration, extendResult: ExtendResult, 827 checkArguments: boolean = false): string { 828 if (node.decorators && node.decorators.length) { 829 for (let i = 0, len = node.decorators.length; i < len; i++) { 830 if (ts.isCallExpression(node.decorators[i].expression)) { 831 parseExtendNode(node.decorators[i].expression as ts.CallExpression, extendResult, checkArguments); 832 if (CHECK_EXTEND_DECORATORS.includes(extendResult.decoratorName) && extendResult.componentName) { 833 return extendResult.componentName; 834 } 835 } 836 } 837 } 838 return null; 839} 840 841function parseExtendNode(node: ts.CallExpression, extendResult: ExtendResult, checkArguments: boolean): void { 842 if (ts.isIdentifier(node.expression)) { 843 extendResult.decoratorName = node.expression.escapedText.toString(); 844 if (checkArguments && CHECK_EXTEND_DECORATORS.includes(extendResult.decoratorName) && 845 node.arguments && node.arguments.length !== 1) { 846 transformLog.errors.push({ 847 type: LogType.ERROR, 848 message: `@${extendResult.decoratorName} should have one and only one parameter`, 849 pos: node.getStart() 850 }); 851 } 852 } 853 if (node.arguments.length && ts.isIdentifier(node.arguments[0])) { 854 extendResult.componentName = node.arguments[0].escapedText.toString(); 855 } 856} 857 858function createEntryNode(node: ts.SourceFile, context: ts.TransformationContext, 859 entryNodeKey: ts.Expression, id: number): ts.SourceFile { 860 let cardRelativePath: string; 861 if (projectConfig && projectConfig.cardObj) { 862 cardRelativePath = projectConfig.cardObj[resourceFileName]; 863 } 864 if (componentCollection.previewComponent.length === 0 || !projectConfig.isPreview) { 865 if (componentCollection.entryComponent) { 866 if (!partialUpdateConfig.partialUpdateMode) { 867 const entryNode: ts.ExpressionStatement = 868 createEntryFunction(componentCollection.entryComponent, context, 869 cardRelativePath, entryNodeKey, id) as ts.ExpressionStatement; 870 return context.factory.updateSourceFile(node, [...node.statements, entryNode]); 871 } else { 872 const entryNodes: ts.ExpressionStatement[] = 873 createEntryFunction(componentCollection.entryComponent, context, 874 cardRelativePath, entryNodeKey, id) as ts.ExpressionStatement[]; 875 return entryNodes ? 876 context.factory.updateSourceFile(node, [...node.statements, ...entryNodes]) : 877 context.factory.updateSourceFile(node, [...node.statements]); 878 } 879 } else { 880 return node; 881 } 882 } else { 883 const statementsArray: ts.Statement = 884 createPreviewComponentFunction(componentCollection.entryComponent, context, cardRelativePath, entryNodeKey, id); 885 return context.factory.updateSourceFile(node, [...node.statements, statementsArray]); 886 } 887} 888 889function createEntryFunction(name: string, context: ts.TransformationContext, cardRelativePath: string, 890 entryNodeKey: ts.Expression, id: number): ts.ExpressionStatement | (ts.ExpressionStatement | ts.Block | ts.IfStatement)[] { 891 const newArray: ts.Expression[] = [ 892 context.factory.createStringLiteral(id.toString()), 893 context.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UNDEFINED), 894 context.factory.createObjectLiteralExpression([], false) 895 ]; 896 const [localStorageName, entryOptionNode]: [string, ts.Expression] = addStorageParam(name); 897 if (localStorageName && entryNodeKey) { 898 newArray.push(entryNodeKey); 899 } 900 const newExpressionParams: any[] = [ 901 context.factory.createNewExpression( 902 context.factory.createIdentifier(name), undefined, newArray)]; 903 addCardStringliteral(newExpressionParams, context, cardRelativePath); 904 if (!partialUpdateConfig.partialUpdateMode) { 905 const newExpressionStatement: ts.ExpressionStatement = 906 context.factory.createExpressionStatement(context.factory.createCallExpression( 907 context.factory.createIdentifier(cardRelativePath ? CARD_ENTRY_FUNCTION_NAME : 908 PAGE_ENTRY_FUNCTION_NAME), undefined, newExpressionParams)); 909 return newExpressionStatement; 910 } else { 911 if (cardRelativePath) { 912 if (entryOptionNode && ts.isObjectLiteralExpression(entryOptionNode)) { 913 transformLog.errors.push({ 914 type: LogType.ERROR, 915 message: `@Entry doesn't support {} parameter in card`, 916 pos: componentCollection.entryComponentPos 917 }); 918 } 919 return [ 920 createStartGetAccessRecording(context), 921 createLoadDocument(context, name, cardRelativePath, localStorageName, entryNodeKey), 922 createStopGetAccessRecording(context) 923 ]; 924 } else { 925 return createLoadPageConditionalJudgMent(context, name, cardRelativePath, localStorageName, entryOptionNode); 926 } 927 } 928} 929 930function createLoadPageConditionalJudgMent(context: ts.TransformationContext, name: string, 931 cardRelativePath: string, localStorageName: string, entryOptionNode: ts.Expression, 932 argsArr: ts.Expression[] = undefined, isComponentPreview: boolean = false) 933 : (ts.ExpressionStatement | ts.Block | ts.IfStatement)[] { 934 let isObject: boolean = false; 935 let routeNameNode: ts.Expression; 936 let storageNode: ts.Expression; 937 if (!entryOptionNode) { 938 const originArray: ts.ExpressionStatement[] = [ 939 createStartGetAccessRecording(context), 940 createLoadDocument(context, name, cardRelativePath, localStorageName, entryOptionNode), 941 createStopGetAccessRecording(context) 942 ]; 943 return originArray; 944 } 945 if (ts.isObjectLiteralExpression(entryOptionNode)) { 946 isObject = true; 947 if (entryOptionNode.properties) { 948 entryOptionNode.properties.forEach((property) => { 949 if (ts.isPropertyAssignment(property) && property.name && ts.isIdentifier(property.name)) { 950 if (property.name.escapedText.toString() === ROUTE_NAME) { 951 routeNameNode = property.initializer; 952 } else if (property.name.escapedText.toString() === STORAGE) { 953 storageNode = property.initializer; 954 } 955 } 956 }); 957 } 958 } else { 959 isObject = false; 960 } 961 if (isObject) { 962 if (routeNameNode && !storageNode) { 963 return isComponentPreview ? [ 964 ...assignRouteNameAndStorage(routeNameNode, storageNode, true, false), 965 ...createLoadDocumentWithRoute(context, name, cardRelativePath, isObject, entryOptionNode, 966 routeNameNode, storageNode, true, false, false, argsArr) 967 ] : [ts.factory.createBlock([ 968 ...assignRouteNameAndStorage(routeNameNode, storageNode, true, false), 969 ...createLoadDocumentWithRoute(context, name, cardRelativePath, isObject, entryOptionNode, 970 routeNameNode, storageNode, true, false, false, argsArr) 971 ])]; 972 } else if (!routeNameNode && !storageNode) { 973 return isComponentPreview ? [ 974 ...assignRouteNameAndStorage(routeNameNode, storageNode, false, false), 975 ...createLoadDocumentWithRoute(context, name, cardRelativePath, isObject, entryOptionNode, 976 routeNameNode, storageNode, false, false, true, argsArr) 977 ] : [ts.factory.createBlock([ 978 ...assignRouteNameAndStorage(routeNameNode, storageNode, false, false), 979 ...createLoadDocumentWithRoute(context, name, cardRelativePath, isObject, entryOptionNode, 980 routeNameNode, storageNode, false, false, true, argsArr) 981 ])]; 982 } else if (!routeNameNode && storageNode) { 983 return isComponentPreview ? [ 984 ...assignRouteNameAndStorage(routeNameNode, storageNode, false, true), 985 ...createLoadDocumentWithRoute(context, name, cardRelativePath, isObject, entryOptionNode, 986 routeNameNode, storageNode, false, true, true, argsArr) 987 ] : [ts.factory.createBlock([ 988 ...assignRouteNameAndStorage(routeNameNode, storageNode, false, true), 989 ...createLoadDocumentWithRoute(context, name, cardRelativePath, isObject, entryOptionNode, 990 routeNameNode, storageNode, false, true, true, argsArr) 991 ])]; 992 } else { 993 return isComponentPreview ? [ 994 ...assignRouteNameAndStorage(routeNameNode, storageNode, true, true), 995 judgeRouteNameAndStorage(context, name, cardRelativePath, isObject, entryOptionNode, routeNameNode, 996 storageNode, argsArr) 997 ] : [ts.factory.createBlock([ 998 ...assignRouteNameAndStorage(routeNameNode, storageNode, true, true), 999 judgeRouteNameAndStorage(context, name, cardRelativePath, isObject, entryOptionNode, routeNameNode, 1000 storageNode, argsArr) 1001 ])]; 1002 } 1003 } else { 1004 return [ 1005 judgeRouteNameAndStorage(context, name, cardRelativePath, isObject, entryOptionNode, routeNameNode, 1006 storageNode, argsArr)]; 1007 } 1008} 1009 1010function judgeRouteNameAndStorage(context: ts.TransformationContext, name: string, 1011 cardRelativePath: string, isObject: boolean, entryOptionNode: ts.Expression, routeNameNode: ts.Expression, 1012 storageNode: ts.Expression, argsArr: ts.Expression[] = undefined): ts.IfStatement { 1013 return ts.factory.createIfStatement( 1014 isObject ? judgeRouteAndStorageForObject(true, true) : 1015 judgeRouteAndStorageForIdentifier(entryOptionNode as ts.Identifier, true, true), 1016 ts.factory.createBlock( 1017 [ 1018 ...createLoadDocumentWithRoute(context, name, cardRelativePath, isObject, entryOptionNode, 1019 routeNameNode, storageNode, true, true, false, argsArr) 1020 ], 1021 true 1022 ), 1023 ts.factory.createIfStatement( 1024 isObject ? judgeRouteAndStorageForObject(true, false) : 1025 judgeRouteAndStorageForIdentifier(entryOptionNode as ts.Identifier, true, false), 1026 ts.factory.createBlock( 1027 [ 1028 ...createLoadDocumentWithRoute(context, name, cardRelativePath, isObject, entryOptionNode, 1029 routeNameNode, storageNode, true, false, false, argsArr) 1030 ], 1031 true 1032 ), 1033 ts.factory.createIfStatement( 1034 isObject ? judgeRouteAndStorageForObject(false, true) : 1035 judgeRouteAndStorageForIdentifier(entryOptionNode as ts.Identifier, false, true), 1036 ts.factory.createBlock( 1037 [ 1038 ...createLoadDocumentWithRoute(context, name, cardRelativePath, isObject, entryOptionNode, 1039 routeNameNode, storageNode, false, true, true, argsArr) 1040 ], 1041 true 1042 ), 1043 ts.factory.createBlock( 1044 [ 1045 ...createLoadDocumentWithRoute(context, name, cardRelativePath, isObject, entryOptionNode, 1046 routeNameNode, storageNode, false, false, true, argsArr) 1047 ], 1048 true 1049 ) 1050 ) 1051 ) 1052 ); 1053} 1054 1055function judgeRouteAndStorageForObject(hasRouteName: boolean, hasStorage: boolean): ts.BinaryExpression { 1056 return ts.factory.createBinaryExpression( 1057 ts.factory.createBinaryExpression( 1058 ts.factory.createIdentifier(ROUTENAME_NODE), 1059 ts.factory.createToken(hasRouteName ? ts.SyntaxKind.ExclamationEqualsToken : ts.SyntaxKind.EqualsEqualsToken), 1060 ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UNDEFINED) 1061 ), 1062 ts.factory.createToken(ts.SyntaxKind.AmpersandAmpersandToken), 1063 ts.factory.createBinaryExpression( 1064 ts.factory.createIdentifier(STORAGE_NODE), 1065 ts.factory.createToken(hasStorage ? ts.SyntaxKind.ExclamationEqualsToken : ts.SyntaxKind.EqualsEqualsToken), 1066 ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UNDEFINED) 1067 ) 1068 ); 1069} 1070 1071function judgeRouteAndStorageForIdentifier(entryOptionNode: ts.Identifier, hasRouteName: boolean, 1072 hasStorage: boolean): ts.BinaryExpression { 1073 return ts.factory.createBinaryExpression( 1074 ts.factory.createBinaryExpression( 1075 entryOptionNode, 1076 ts.factory.createToken(ts.SyntaxKind.AmpersandAmpersandToken), 1077 ts.factory.createBinaryExpression( 1078 ts.factory.createPropertyAccessExpression( 1079 entryOptionNode, 1080 ts.factory.createIdentifier(ROUTE_NAME) 1081 ), 1082 ts.factory.createToken(hasRouteName ? ts.SyntaxKind.ExclamationEqualsToken : ts.SyntaxKind.EqualsEqualsToken), 1083 ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UNDEFINED) 1084 ) 1085 ), 1086 ts.factory.createToken(ts.SyntaxKind.AmpersandAmpersandToken), 1087 ts.factory.createBinaryExpression( 1088 ts.factory.createPropertyAccessExpression( 1089 entryOptionNode, 1090 ts.factory.createIdentifier(STORAGE) 1091 ), 1092 ts.factory.createToken(hasStorage ? ts.SyntaxKind.ExclamationEqualsToken : ts.SyntaxKind.EqualsEqualsToken), 1093 ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UNDEFINED) 1094 ) 1095 ); 1096} 1097 1098function assignRouteNameAndStorage(routeNameNode, storageNode, hasRouteName, hasStorage): ts.ExpressionStatement[] { 1099 const assignOperation: ts.VariableStatement[] = []; 1100 if (hasRouteName) { 1101 assignOperation.push(ts.factory.createVariableStatement( 1102 undefined, 1103 ts.factory.createVariableDeclarationList( 1104 [ts.factory.createVariableDeclaration( 1105 ts.factory.createIdentifier(ROUTENAME_NODE), 1106 undefined, 1107 undefined, 1108 routeNameNode 1109 )], 1110 ts.NodeFlags.Let 1111 ) 1112 )); 1113 } 1114 if (hasStorage) { 1115 assignOperation.push(ts.factory.createVariableStatement( 1116 undefined, 1117 ts.factory.createVariableDeclarationList( 1118 [ts.factory.createVariableDeclaration( 1119 ts.factory.createIdentifier(STORAGE_NODE), 1120 undefined, 1121 undefined, 1122 storageNode 1123 )], 1124 ts.NodeFlags.Let 1125 ) 1126 )); 1127 } 1128 return assignOperation; 1129} 1130 1131function createLoadDocumentWithRoute(context: ts.TransformationContext, name: string, 1132 cardRelativePath: string, isObject: boolean, entryOptionNode: ts.Expression, 1133 routeNameNode: ts.Node, storageNode: ts.Node, hasRouteName: boolean, hasStorage: boolean, 1134 shouldCreateAccsessRecording: boolean, argsArr: ts.Expression[]): ts.ExpressionStatement[] { 1135 const newArray: ts.Expression[] = [ 1136 context.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UNDEFINED), 1137 context.factory.createObjectLiteralExpression([], false) 1138 ]; 1139 if (entryOptionNode) { 1140 if (!isObject) { 1141 if (hasStorage) { 1142 newArray.push(ts.factory.createPropertyAccessExpression( 1143 entryOptionNode, 1144 ts.factory.createIdentifier(STORAGE) 1145 )); 1146 } else if (!hasRouteName) { 1147 newArray.push(entryOptionNode); 1148 } 1149 } else if (storageNode && hasStorage) { 1150 newArray.push(ts.factory.createIdentifier(STORAGE_NODE)); 1151 } 1152 } 1153 const newExpressionParams: any[] = [ 1154 context.factory.createNewExpression( 1155 context.factory.createIdentifier(name), 1156 undefined, newArray)]; 1157 if (argsArr) { 1158 argsArr = []; 1159 componentCollection.previewComponent.forEach((componentName: string) => { 1160 const newExpression: ts.Expression = context.factory.createNewExpression( 1161 context.factory.createIdentifier(componentName), 1162 undefined, 1163 componentName === name ? newArray : newArray.slice(0, newArray.length - 1) 1164 ); 1165 argsArr.push(context.factory.createStringLiteral(componentName), newExpression); 1166 }); 1167 } 1168 if (hasRouteName) { 1169 return [ 1170 shouldCreateAccsessRecording ? createStartGetAccessRecording(context) : undefined, 1171 context.factory.createExpressionStatement(context.factory.createCallExpression( 1172 context.factory.createIdentifier(REGISTER_NAMED_ROUTE), 1173 undefined, 1174 [ 1175 context.factory.createArrowFunction( 1176 undefined, 1177 undefined, 1178 [], 1179 undefined, 1180 context.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), 1181 newExpressionParams[0] 1182 ), 1183 isObject ? ts.factory.createIdentifier(ROUTENAME_NODE) : context.factory.createPropertyAccessExpression( 1184 entryOptionNode, 1185 context.factory.createIdentifier(ROUTE_NAME) 1186 ), 1187 context.factory.createObjectLiteralExpression( 1188 [ 1189 context.factory.createPropertyAssignment( 1190 context.factory.createIdentifier(RESOURCE_NAME_BUNDLE), 1191 context.factory.createStringLiteral(projectConfig.bundleName || '') 1192 ), 1193 context.factory.createPropertyAssignment( 1194 context.factory.createIdentifier(RESOURCE_NAME_MODULE), 1195 context.factory.createStringLiteral(projectConfig.moduleName || '') 1196 ), 1197 context.factory.createPropertyAssignment( 1198 context.factory.createIdentifier(PAGE_PATH), 1199 context.factory.createStringLiteral( 1200 projectConfig.compileHar ? '' : 1201 path.relative(projectConfig.projectPath || '', resourceFileName).replace(/\\/g, '/').replace(/\.ets$/, '') 1202 ) 1203 ) 1204 ], 1205 false 1206 ) 1207 ] 1208 )), 1209 shouldCreateAccsessRecording ? createStopGetAccessRecording(context) : undefined]; 1210 } else { 1211 return [ 1212 shouldCreateAccsessRecording ? createStartGetAccessRecording(context) : undefined, 1213 context.factory.createExpressionStatement( 1214 context.factory.createCallExpression( 1215 context.factory.createIdentifier(cardRelativePath ? CARD_ENTRY_FUNCTION_NAME : 1216 PAGE_ENTRY_FUNCTION_NAME), undefined, newExpressionParams)), 1217 shouldCreateAccsessRecording ? createStopGetAccessRecording(context) : undefined]; 1218 } 1219} 1220 1221function createStartGetAccessRecording(context: ts.TransformationContext): ts.ExpressionStatement { 1222 return context.factory.createExpressionStatement( 1223 context.factory.createCallExpression( 1224 context.factory.createPropertyAccessExpression( 1225 context.factory.createIdentifier(VIEWSTACKPROCESSOR), 1226 context.factory.createIdentifier(STARTGETACCESSRECORDINGFOR) 1227 ), 1228 undefined, 1229 [context.factory.createCallExpression( 1230 context.factory.createPropertyAccessExpression( 1231 context.factory.createIdentifier(VIEWSTACKPROCESSOR), 1232 context.factory.createIdentifier(ALLOCATENEWELMETIDFORNEXTCOMPONENT) 1233 ), 1234 undefined, 1235 [] 1236 )] 1237 ) 1238 ); 1239} 1240 1241function createLoadDocument(context: ts.TransformationContext, name: string, 1242 cardRelativePath: string, localStorageName: string, entryNodeKey: ts.Expression): ts.ExpressionStatement { 1243 const newArray: ts.Expression[] = [ 1244 context.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UNDEFINED), 1245 context.factory.createObjectLiteralExpression([], false) 1246 ]; 1247 if (localStorageName && entryNodeKey) { 1248 newArray.push(entryNodeKey); 1249 } 1250 const newExpressionParams: any[] = [ 1251 context.factory.createNewExpression( 1252 context.factory.createIdentifier(name), 1253 undefined, newArray)]; 1254 addCardStringliteral(newExpressionParams, context, cardRelativePath); 1255 return context.factory.createExpressionStatement( 1256 context.factory.createCallExpression( 1257 context.factory.createIdentifier(cardRelativePath ? CARD_ENTRY_FUNCTION_NAME : 1258 PAGE_ENTRY_FUNCTION_NAME), undefined, newExpressionParams) 1259 ); 1260} 1261 1262function createStopGetAccessRecording(context: ts.TransformationContext): ts.ExpressionStatement { 1263 return context.factory.createExpressionStatement( 1264 context.factory.createCallExpression( 1265 context.factory.createPropertyAccessExpression( 1266 context.factory.createIdentifier(VIEWSTACKPROCESSOR), 1267 context.factory.createIdentifier(STOPGETACCESSRECORDING) 1268 ), 1269 undefined, 1270 [] 1271 ) 1272 ); 1273} 1274 1275function addStorageParam(name: string): [string, ts.Expression] { 1276 let localStorageName: string; 1277 let localStorageNode: ts.Identifier | ts.ObjectLiteralExpression; 1278 const localStorageNum: number = (localStorageLinkCollection.get(name) || new Set()).size + 1279 (localStoragePropCollection.get(name) || new Set()).size; 1280 if (componentCollection.entryComponent === name && componentCollection.localStorageNode) { 1281 localStorageNode = componentCollection.localStorageNode; 1282 } 1283 if (componentCollection.entryComponent === name && componentCollection.localStorageName) { 1284 localStorageName = componentCollection.localStorageName; 1285 } else if (componentCollection.entryComponent === name && !componentCollection.localStorageName && 1286 !componentCollection.localStorageNode && localStorageNum) { 1287 transformLog.errors.push({ 1288 type: LogType.WARN, 1289 message: `@Entry should have a parameter, like '@Entry (storage)'.`, 1290 pos: componentCollection.entryComponentPos 1291 }); 1292 } 1293 return [localStorageName, localStorageNode]; 1294} 1295 1296function createPreviewComponentFunction(name: string, context: ts.TransformationContext, 1297 cardRelativePath: string, entryNodeKey: ts.Expression, id: number): ts.Statement { 1298 const newArray: ts.Expression[] = partialUpdateConfig.partialUpdateMode ? 1299 [ 1300 context.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UNDEFINED), 1301 context.factory.createObjectLiteralExpression([], false) 1302 ] : 1303 [ 1304 context.factory.createStringLiteral(id.toString()), 1305 context.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UNDEFINED), 1306 context.factory.createObjectLiteralExpression([], false) 1307 ]; 1308 const [localStorageName, entryOptionNode]: [string, ts.Expression] = addStorageParam(name); 1309 if (entryOptionNode) { 1310 newArray.push(entryOptionNode); 1311 } 1312 const argsArr: ts.Expression[] = []; 1313 componentCollection.previewComponent.forEach(componentName => { 1314 const newExpression: ts.Expression = context.factory.createNewExpression( 1315 context.factory.createIdentifier(componentName), 1316 undefined, 1317 newArray 1318 ); 1319 argsArr.push(context.factory.createStringLiteral(componentName)); 1320 argsArr.push(newExpression); 1321 }); 1322 const newExpressionParams: any[] = name ? [context.factory.createNewExpression( 1323 context.factory.createIdentifier(name), undefined, newArray)] : []; 1324 addCardStringliteral(newExpressionParams, context, cardRelativePath); 1325 const ifStatement: ts.Statement = context.factory.createIfStatement( 1326 context.factory.createCallExpression( 1327 context.factory.createIdentifier(GET_PREVIEW_FLAG_FUNCTION_NAME), 1328 undefined, 1329 [] 1330 ), 1331 context.factory.createBlock( 1332 [...storePreviewComponents(name, entryOptionNode, argsArr), 1333 context.factory.createExpressionStatement(context.factory.createCallExpression( 1334 context.factory.createIdentifier(PREVIEW_COMPONENT_FUNCTION_NAME), 1335 undefined, 1336 [] 1337 ))], 1338 true 1339 ), 1340 context.factory.createBlock( 1341 createPreviewElseBlock(name, context, cardRelativePath, localStorageName, entryOptionNode, 1342 newExpressionParams, argsArr), 1343 true 1344 ) 1345 ); 1346 return ifStatement; 1347} 1348 1349function storePreviewComponents(name: string, entryOptionNode: ts.Expression, argsArr: ts.Expression[]): 1350 (ts.ExpressionStatement|ts.VariableStatement|ts.IfStatement)[] { 1351 let isObject: boolean = false; 1352 let storageNode: ts.Expression; 1353 if (!entryOptionNode) { 1354 return [ts.factory.createExpressionStatement(ts.factory.createCallExpression( 1355 ts.factory.createIdentifier(STORE_PREVIEW_COMPONENTS), 1356 undefined, 1357 [ 1358 ts.factory.createNumericLiteral(componentCollection.previewComponent.length), 1359 ...argsArr 1360 ] 1361 ))]; 1362 } 1363 if (ts.isObjectLiteralExpression(entryOptionNode)) { 1364 isObject = true; 1365 if (entryOptionNode.properties) { 1366 entryOptionNode.properties.forEach((property) => { 1367 if (ts.isPropertyAssignment(property) && property.name && ts.isIdentifier(property.name) && 1368 property.name.escapedText.toString() === STORAGE) { 1369 storageNode = property.initializer; 1370 } 1371 }); 1372 } 1373 } else { 1374 isObject = false; 1375 } 1376 const newArray: ts.Expression[] = [ 1377 ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UNDEFINED), 1378 ts.factory.createObjectLiteralExpression([], false) 1379 ]; 1380 const newArgsArr: ts.Expression[] = []; 1381 if (isObject) { 1382 return processObjectStorage(storageNode, newArray, name, newArgsArr); 1383 } else { 1384 return [ts.factory.createIfStatement( 1385 ts.factory.createBinaryExpression( 1386 entryOptionNode, 1387 ts.factory.createToken(ts.SyntaxKind.AmpersandAmpersandToken), 1388 ts.factory.createBinaryExpression( 1389 ts.factory.createPropertyAccessExpression( 1390 entryOptionNode, 1391 ts.factory.createIdentifier(STORAGE) 1392 ), 1393 ts.factory.createToken(ts.SyntaxKind.ExclamationEqualsToken), 1394 ts.factory.createIdentifier('undefined') 1395 ) 1396 ), 1397 ts.factory.createBlock( 1398 [returnStorePreview(entryOptionNode, true, name)], 1399 true 1400 ), 1401 ts.factory.createBlock( 1402 [returnStorePreview(entryOptionNode, false, name)], 1403 true 1404 ) 1405 )]; 1406 } 1407} 1408 1409function processObjectStorage(storageNode: ts.Expression, newArray: ts.Expression[], name: string, 1410 newArgsArr: ts.Expression[]): (ts.ExpressionStatement|ts.VariableStatement)[] { 1411 if (storageNode) { 1412 newArray.push(ts.factory.createIdentifier(STORAGE_NODE)); 1413 componentCollection.previewComponent.forEach(componentName => { 1414 const newExpression: ts.Expression = ts.factory.createNewExpression( 1415 ts.factory.createIdentifier(componentName), 1416 undefined, 1417 componentName === name ? newArray : newArray.slice(0, newArray.length - 1) 1418 ); 1419 newArgsArr.push(ts.factory.createStringLiteral(componentName)); 1420 newArgsArr.push(newExpression); 1421 }); 1422 return [ts.factory.createVariableStatement( 1423 undefined, 1424 ts.factory.createVariableDeclarationList( 1425 [ts.factory.createVariableDeclaration( 1426 ts.factory.createIdentifier(STORAGE_NODE), 1427 undefined, 1428 undefined, 1429 storageNode 1430 )], 1431 ts.NodeFlags.Let 1432 ) 1433 ), ts.factory.createExpressionStatement(ts.factory.createCallExpression( 1434 ts.factory.createIdentifier(STORE_PREVIEW_COMPONENTS), 1435 undefined, 1436 [ 1437 ts.factory.createNumericLiteral(componentCollection.previewComponent.length), 1438 ...newArgsArr 1439 ] 1440 ))]; 1441 } else { 1442 componentCollection.previewComponent.forEach(componentName => { 1443 const newExpression: ts.Expression = ts.factory.createNewExpression( 1444 ts.factory.createIdentifier(componentName), 1445 undefined, 1446 newArray 1447 ); 1448 newArgsArr.push(ts.factory.createStringLiteral(componentName)); 1449 newArgsArr.push(newExpression); 1450 }); 1451 return [ts.factory.createExpressionStatement(ts.factory.createCallExpression( 1452 ts.factory.createIdentifier(STORE_PREVIEW_COMPONENTS), 1453 undefined, 1454 [ 1455 ts.factory.createNumericLiteral(componentCollection.previewComponent.length), 1456 ...newArgsArr 1457 ] 1458 ))]; 1459 } 1460} 1461 1462function returnStorePreview(entryOptionNode: ts.Expression, hasStorage: boolean, name: string): ts.ExpressionStatement { 1463 const newArray: ts.Expression[] = [ 1464 ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UNDEFINED), 1465 ts.factory.createObjectLiteralExpression([], false) 1466 ]; 1467 const newArgsArr: ts.Expression[] = []; 1468 newArray.push(hasStorage ? ts.factory.createPropertyAccessExpression( 1469 entryOptionNode, 1470 ts.factory.createIdentifier(STORAGE) 1471 ) : entryOptionNode); 1472 componentCollection.previewComponent.forEach(componentName => { 1473 const newExpression: ts.Expression = ts.factory.createNewExpression( 1474 ts.factory.createIdentifier(componentName), 1475 undefined, 1476 componentName === name ? newArray : newArray.slice(0, newArray.length - 1) 1477 ); 1478 newArgsArr.push(ts.factory.createStringLiteral(componentName)); 1479 newArgsArr.push(newExpression); 1480 }); 1481 return ts.factory.createExpressionStatement(ts.factory.createCallExpression( 1482 ts.factory.createIdentifier(STORE_PREVIEW_COMPONENTS), 1483 undefined, 1484 [ 1485 ts.factory.createNumericLiteral(componentCollection.previewComponent.length), 1486 ...newArgsArr 1487 ] 1488 )); 1489} 1490 1491function createPreviewElseBlock(name: string, context: ts.TransformationContext, cardRelativePath: string, 1492 localStorageName: string, entryOptionNode: ts.Expression, newExpressionParams: ts.Expression[], 1493 argsArr: ts.Expression[]): (ts.ExpressionStatement | ts.IfStatement | ts.Block)[] { 1494 if (name) { 1495 if (!partialUpdateConfig.partialUpdateMode) { 1496 return [context.factory.createExpressionStatement(context.factory.createCallExpression( 1497 context.factory.createIdentifier(STORE_PREVIEW_COMPONENTS), 1498 undefined, 1499 [ 1500 context.factory.createNumericLiteral(componentCollection.previewComponent.length), 1501 ...argsArr 1502 ] 1503 )), 1504 context.factory.createExpressionStatement(context.factory.createCallExpression( 1505 context.factory.createIdentifier(cardRelativePath ? CARD_ENTRY_FUNCTION_NAME : 1506 PAGE_ENTRY_FUNCTION_NAME), undefined, newExpressionParams 1507 ))]; 1508 } else { 1509 if (cardRelativePath) { 1510 if (entryOptionNode && ts.isObjectLiteralExpression(entryOptionNode)) { 1511 transformLog.errors.push({ 1512 type: LogType.ERROR, 1513 message: `@Entry doesn't support {} parameter in card`, 1514 pos: componentCollection.entryComponentPos 1515 }); 1516 } 1517 return [ 1518 name ? createStartGetAccessRecording(context) : undefined, 1519 name ? context.factory.createExpressionStatement(context.factory.createCallExpression( 1520 context.factory.createIdentifier(cardRelativePath ? CARD_ENTRY_FUNCTION_NAME : 1521 PAGE_ENTRY_FUNCTION_NAME), undefined, newExpressionParams 1522 )) : undefined, 1523 name ? createStopGetAccessRecording(context) : undefined 1524 ]; 1525 } 1526 return createLoadPageConditionalJudgMent(context, name, cardRelativePath, localStorageName, 1527 entryOptionNode, argsArr, true); 1528 } 1529 } 1530} 1531 1532export function resetLog(): void { 1533 transformLog.errors = []; 1534} 1535 1536function addCardStringliteral(newExpressionParams: any[], context: ts.TransformationContext, 1537 cardRelativePath: string): void { 1538 if (cardRelativePath) { 1539 newExpressionParams.push(context.factory.createStringLiteral( 1540 projectConfig.bundleName + '/' + projectConfig.moduleName + '/' + 1541 cardRelativePath)); 1542 } 1543} 1544 1545export function validatorCard(log: any[], type: number, pos: number, 1546 name: string = ''): void { 1547 if (projectConfig && projectConfig.cardObj && resourceFileName 1548 && projectConfig.cardObj[resourceFileName]) { 1549 const logInfo: object = { 1550 type: LogType.ERROR, 1551 message: '', 1552 pos: pos 1553 }; 1554 switch (type) { 1555 case CARD_LOG_TYPE_COMPONENTS: 1556 logInfo.message = `Card page cannot use the component ${name}.`; 1557 break; 1558 case CARD_LOG_TYPE_DECORATORS: 1559 logInfo.message = `Card page cannot use ${name}`; 1560 break; 1561 case CARD_LOG_TYPE_IMPORT: 1562 logInfo.message = `Card page cannot use import.`; 1563 break; 1564 } 1565 log.push(logInfo); 1566 } 1567} 1568