1/* 2 * Copyright (c) 2020 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 16const fs = require('fs'); 17const path = require('path'); 18const md5 = require('md5'); 19const JSON5 = require('json5'); 20 21const { 22 readFile, 23 writeFileSync 24} = require('./lib/utils'); 25 26const { 27 WORKERS_DIR, 28 TEST_RUNNER_DIR_SET, 29 TS2ABC, 30 FAIL 31} = require('./lib/pre_define'); 32 33const { 34 checkAotConfig 35} = require('./lib/gen_aot'); 36 37const { 38 configure, 39 getLogger 40} = require('log4js'); 41 42configure({ 43 appenders: { 'ETS': {type: 'stderr', layout: {type: 'messagePassThrough'}}}, 44 categories: {'default': {appenders: ['ETS'], level: 'info'}} 45}); 46const logger = getLogger('ETS'); 47 48const staticPreviewPage = process.env.aceStaticPreview; 49const aceCompileMode = process.env.aceCompileMode || 'page'; 50const abilityConfig = { 51 abilityType: process.env.abilityType || 'page', 52 abilityEntryFile: null, 53 projectAbilityPath: [], 54 testRunnerFile: [] 55}; 56const projectConfig = {}; 57const resources = { 58 app: {}, 59 sys: {} 60}; 61const systemModules = []; 62const abilityPagesFullPath = []; 63 64function initProjectConfig(projectConfig) { 65 projectConfig.entryObj = {}; 66 projectConfig.cardObj = {}; 67 projectConfig.projectPath = projectConfig.projectPath || process.env.aceModuleRoot || 68 path.join(process.cwd(), 'sample'); 69 projectConfig.buildPath = projectConfig.buildPath || process.env.aceModuleBuild || 70 path.resolve(projectConfig.projectPath, 'build'); 71 projectConfig.aceModuleBuild = projectConfig.buildPath; // To be compatible with both webpack and rollup 72 projectConfig.manifestFilePath = projectConfig.manifestFilePath || process.env.aceManifestPath || 73 path.join(projectConfig.projectPath, 'manifest.json'); 74 projectConfig.aceProfilePath = projectConfig.aceProfilePath || process.env.aceProfilePath; 75 projectConfig.aceModuleJsonPath = projectConfig.aceModuleJsonPath || process.env.aceModuleJsonPath; 76 projectConfig.aceSuperVisualPath = projectConfig.aceSuperVisualPath || 77 process.env.aceSuperVisualPath; 78 projectConfig.hashProjectPath = projectConfig.hashProjectPath || 79 hashProjectPath(projectConfig.projectPath); 80 projectConfig.aceBuildJson = projectConfig.aceBuildJson || process.env.aceBuildJson; 81 projectConfig.cachePath = projectConfig.cachePath || process.env.cachePath || 82 path.resolve(__dirname, 'node_modules/.cache'); 83 projectConfig.aceSoPath = projectConfig.aceSoPath || process.env.aceSoPath; 84 projectConfig.xtsMode = /ets_loader_ark$/.test(__dirname); 85 projectConfig.localPropertiesPath = projectConfig.localPropertiesPath || process.env.localPropertiesPath; 86 projectConfig.projectProfilePath = projectConfig.projectProfilePath || process.env.projectProfilePath; 87 projectConfig.isPreview = projectConfig.isPreview || process.env.isPreview === 'true'; 88 projectConfig.compileMode = projectConfig.compileMode || 'jsbundle'; 89 projectConfig.runtimeOS = projectConfig.runtimeOS || process.env.runtimeOS || 'default'; 90 projectConfig.sdkInfo = projectConfig.sdkInfo || process.env.sdkInfo || 'default'; 91 projectConfig.splitCommon = false; 92 projectConfig.compileHar = false; 93 projectConfig.compileShared = false; 94 projectConfig.checkEntry = projectConfig.checkEntry || process.env.checkEntry; 95 projectConfig.obfuscateHarType = projectConfig.obfuscateHarType || process.env.obfuscate; 96 projectConfig.packageDir = 'node_modules'; 97 projectConfig.packageJson = 'package.json'; 98 projectConfig.packageManagerType = 'npm'; 99 projectConfig.cardEntryObj = {}; 100} 101 102function loadEntryObj(projectConfig) { 103 let manifest = {}; 104 initProjectConfig(projectConfig); 105 loadBuildJson(); 106 if (process.env.aceManifestPath && aceCompileMode === 'page') { 107 setEntryFile(projectConfig); 108 setFaTestRunnerFile(projectConfig); 109 } 110 if (process.env.aceModuleJsonPath) { 111 setAbilityPages(projectConfig); 112 setStageTestRunnerFile(projectConfig); 113 } 114 115 if (staticPreviewPage) { 116 projectConfig.entryObj['./' + staticPreviewPage] = projectConfig.projectPath + path.sep + 117 staticPreviewPage + '.ets?entry'; 118 } else if (abilityConfig.abilityType === 'page') { 119 if (fs.existsSync(projectConfig.manifestFilePath)) { 120 const jsonString = fs.readFileSync(projectConfig.manifestFilePath).toString(); 121 manifest = JSON.parse(jsonString); 122 if (manifest && manifest.minPlatformVersion) { 123 process.env.minPlatformVersion = manifest.minPlatformVersion; 124 partialUpdateController(manifest.minPlatformVersion); 125 } 126 projectConfig.pagesJsonFileName = 'config.json'; 127 } else if (projectConfig.aceModuleJsonPath && fs.existsSync(projectConfig.aceModuleJsonPath)) { 128 process.env.compileMode = 'moduleJson'; 129 buildManifest(manifest, projectConfig.aceModuleJsonPath); 130 } else { 131 throw Error('\u001b[31m ERROR: the manifest file ' + projectConfig.manifestFilePath.replace(/\\/g, '/') + 132 ' or module.json is lost or format is invalid. \u001b[39m').message; 133 } 134 if (!projectConfig.compileHar) { 135 if (manifest.pages) { 136 const pages = manifest.pages; 137 pages.forEach((element) => { 138 const sourcePath = element.replace(/^\.\/ets\//, ''); 139 const fileName = path.resolve(projectConfig.projectPath, sourcePath + '.ets'); 140 if (fs.existsSync(fileName)) { 141 projectConfig.entryObj['./' + sourcePath] = fileName + '?entry'; 142 } else { 143 throw Error(`\u001b[31m ERROR: page '${fileName.replace(/\\/g, '/')}' does not exist. \u001b[39m`) 144 .message; 145 } 146 }); 147 } else { 148 throw Error('\u001b[31m ERROR: missing pages attribute in ' + 149 projectConfig.manifestFilePath.replace(/\\/g, '/') + 150 '. \u001b[39m').message; 151 } 152 } 153 } 154} 155 156function buildManifest(manifest, aceConfigPath) { 157 try { 158 const moduleConfigJson = JSON.parse(fs.readFileSync(aceConfigPath).toString()); 159 manifest.type = process.env.abilityType; 160 if (moduleConfigJson && moduleConfigJson.app && moduleConfigJson.app.minAPIVersion) { 161 if (moduleConfigJson.module && moduleConfigJson.module.metadata) { 162 partialUpdateController(moduleConfigJson.app.minAPIVersion, moduleConfigJson.module.metadata); 163 stageOptimization(moduleConfigJson.module.metadata); 164 } else { 165 partialUpdateController(moduleConfigJson.app.minAPIVersion); 166 } 167 } 168 if (moduleConfigJson.module) { 169 switch (moduleConfigJson.module.type) { 170 case 'har': 171 projectConfig.compileHar = true; 172 getPackageJsonEntryPath(); 173 break; 174 case 'shared': 175 projectConfig.compileShared = true; 176 getPackageJsonEntryPath(); 177 manifest.pages = getPages(moduleConfigJson); 178 break; 179 default: 180 manifest.pages = getPages(moduleConfigJson); 181 break; 182 } 183 } else { 184 throw Error('\u001b[31m' + 185 'ERROR: the config.json file miss key word module || module[abilities].' + 186 '\u001b[39m').message; 187 } 188 } catch (e) { 189 if (/BUIDERROR/.test(e)) { 190 throw Error(e.replace('BUIDERROR', 'ERROR')).message; 191 } else { 192 throw Error('\x1B[31m' + 'ERROR: the module.json file is lost or format is invalid.' + 193 '\x1B[39m').message; 194 } 195 } 196} 197 198function getPackageJsonEntryPath() { 199 const rootPackageJsonPath = path.resolve(projectConfig.projectPath, '../../../' + projectConfig.packageJson); 200 if (fs.existsSync(rootPackageJsonPath)) { 201 const rootPackageJsonContent = 202 (projectConfig.packageManagerType === 'npm' ? JSON : JSON5).parse(fs.readFileSync(rootPackageJsonPath, 'utf-8')); 203 if (rootPackageJsonContent) { 204 if (rootPackageJsonContent.module) { 205 getEntryPath(rootPackageJsonContent.module, rootPackageJsonPath); 206 } else if (rootPackageJsonContent.main) { 207 getEntryPath(rootPackageJsonContent.main, rootPackageJsonPath); 208 } else { 209 getEntryPath('', rootPackageJsonPath); 210 } 211 } else if (projectConfig.compileHar) { 212 throw Error('\u001b[31m' + 'lack message in ' + projectConfig.packageJson + '.' + '\u001b[39m').message; 213 } 214 } 215} 216 217function supportSuffix(mainEntryPath) { 218 if (fs.existsSync(path.join(mainEntryPath, 'index.ets'))) { 219 mainEntryPath = path.join(mainEntryPath, 'index.ets'); 220 } else if (fs.existsSync(path.join(mainEntryPath, 'index.ts'))) { 221 mainEntryPath = path.join(mainEntryPath, 'index.ts'); 222 } else if (fs.existsSync(path.join(mainEntryPath, 'index.js'))) { 223 mainEntryPath = path.join(mainEntryPath, 'index.js'); 224 } else if (projectConfig.compileHar) { 225 throw Error('\u001b[31m' + 'not find entry file in ' + projectConfig.packageJson + '.' + '\u001b[39m').message; 226 } 227 return mainEntryPath; 228} 229 230function supportExtName(mainEntryPath) { 231 if (path.extname(mainEntryPath) === '') { 232 if (fs.existsSync(mainEntryPath + '.ets')) { 233 mainEntryPath = mainEntryPath + '.ets'; 234 } else if (fs.existsSync(mainEntryPath + '.ts')) { 235 mainEntryPath = mainEntryPath + '.ts'; 236 } else if (fs.existsSync(mainEntryPath + '.js')) { 237 mainEntryPath = mainEntryPath + '.js'; 238 } 239 } 240 return mainEntryPath; 241} 242 243function getEntryPath(entryPath, rootPackageJsonPath) { 244 let mainEntryPath = path.resolve(rootPackageJsonPath, '../', entryPath); 245 if (fs.existsSync(mainEntryPath) && fs.statSync(mainEntryPath).isDirectory()) { 246 mainEntryPath = supportSuffix(mainEntryPath); 247 } else { 248 mainEntryPath = supportExtName(mainEntryPath); 249 } 250 if (fs.existsSync(mainEntryPath) && fs.statSync(mainEntryPath).isFile()) { 251 const entryKey = path.relative(projectConfig.projectPath, mainEntryPath); 252 projectConfig.entryObj[entryKey] = mainEntryPath; 253 abilityPagesFullPath.push(path.resolve(mainEntryPath).toLowerCase()); 254 } else if (projectConfig.compileHar) { 255 throw Error('\u001b[31m' + 'not find entry file in package.json.' + '\u001b[39m').message; 256 } 257} 258 259function stageOptimization(metadata) { 260 if (Array.isArray(metadata) && metadata.length) { 261 metadata.some(item => { 262 if (item.name && item.name === 'USE_COMMON_CHUNK' && 263 item.value && item.value === 'true') { 264 projectConfig.splitCommon = true; 265 return true; 266 } 267 }); 268 } 269} 270 271function getPages(configJson) { 272 const pages = []; 273 let pagesJsonFileName = ''; 274 // pages is not necessary in shared library 275 if (projectConfig.compileShared && configJson.module && configJson.module.pages || !projectConfig.compileShared) { 276 pagesJsonFileName = `${configJson.module.pages.replace(/\$profile\:/, '')}.json`; 277 } else { 278 return pages; 279 } 280 const modulePagePath = path.resolve(projectConfig.aceProfilePath, pagesJsonFileName); 281 if (fs.existsSync(modulePagePath)) { 282 try { 283 const pagesConfig = JSON.parse(fs.readFileSync(modulePagePath, 'utf-8')); 284 if (pagesConfig && pagesConfig.src) { 285 projectConfig.pagesJsonFileName = pagesJsonFileName; 286 return pagesConfig.src; 287 } 288 } catch (e) { 289 throw Error("\x1B[31m" + `BUIDERROR: the ${modulePagePath} file format is invalid.` + 290 "\x1B[39m").message; 291 } 292 } 293 return pages; 294} 295 296function setEntryFile(projectConfig) { 297 const entryFileName = abilityConfig.abilityType === 'page' ? 'app' : abilityConfig.abilityType; 298 const extendFile = entryFileName === 'app' ? '.ets' : '.ts'; 299 const entryFileRealPath = entryFileName + extendFile; 300 const entryFilePath = path.resolve(projectConfig.projectPath, entryFileRealPath); 301 abilityConfig.abilityEntryFile = entryFilePath; 302 if (!fs.existsSync(entryFilePath) && aceCompileMode === 'page') { 303 throw Error(`\u001b[31m ERROR: missing ${entryFilePath.replace(/\\/g, '/')}. \u001b[39m`).message; 304 } 305 projectConfig.entryObj[`./${entryFileName}`] = entryFilePath + '?entry'; 306} 307 308function setAbilityPages(projectConfig) { 309 let abilityPages = []; 310 if (projectConfig.aceModuleJsonPath && fs.existsSync(projectConfig.aceModuleJsonPath)) { 311 const moduleJson = JSON.parse(fs.readFileSync(projectConfig.aceModuleJsonPath).toString()); 312 abilityPages = readAbilityEntrance(moduleJson); 313 setAbilityFile(projectConfig, abilityPages); 314 setBundleModuleInfo(projectConfig, moduleJson); 315 } 316} 317 318function setTestRunnerFile(projectConfig, isStageBased) { 319 const index =projectConfig.projectPath.split(path.sep).join('/').lastIndexOf('\/'); 320 TEST_RUNNER_DIR_SET.forEach((dir) => { 321 let projectPath = isStageBased ? projectConfig.projectPath : projectConfig.projectPath.substring(0,index + 1); 322 const testRunnerPath = path.resolve(projectPath, dir); 323 if (fs.existsSync(testRunnerPath)) { 324 const testRunnerFiles = []; 325 readFile(testRunnerPath, testRunnerFiles); 326 testRunnerFiles.forEach((item) => { 327 if (/\.(ts|js|ets)$/.test(item)) { 328 const relativePath = path.relative(testRunnerPath, item).replace(/\.(ts|js|ets)$/, ''); 329 if (isStageBased) { 330 projectConfig.entryObj[`./${dir}/${relativePath}`] = item; 331 } else { 332 projectConfig.entryObj[`../${dir}/${relativePath}`] = item; 333 } 334 abilityConfig.testRunnerFile.push(item); 335 } 336 }) 337 } 338 }); 339} 340 341function setFaTestRunnerFile(projectConfig) { 342 setTestRunnerFile(projectConfig, false); 343} 344 345function setStageTestRunnerFile(projectConfig) { 346 setTestRunnerFile(projectConfig, true); 347} 348 349function setBundleModuleInfo(projectConfig, moduleJson) { 350 if (moduleJson.module) { 351 projectConfig.moduleName = moduleJson.module.name; 352 } 353 if (moduleJson.app) { 354 projectConfig.bundleName = moduleJson.app.bundleName; 355 } 356} 357 358function setAbilityFile(projectConfig, abilityPages) { 359 abilityPages.forEach(abilityPath => { 360 const projectAbilityPath = path.resolve(projectConfig.projectPath, '../', abilityPath); 361 if (path.isAbsolute(abilityPath)) { 362 abilityPath = '.' + abilityPath.slice(projectConfig.projectPath.length); 363 } 364 const entryPageKey = abilityPath.replace(/^\.\/ets\//, './').replace(/\.ts$/, '').replace(/\.ets$/, ''); 365 if (fs.existsSync(projectAbilityPath)) { 366 abilityConfig.projectAbilityPath.push(projectAbilityPath); 367 projectConfig.entryObj[entryPageKey] = projectAbilityPath + '?entry'; 368 } else { 369 throw Error( 370 `\u001b[31m ERROR: srcEntry file '${projectAbilityPath.replace(/\\/g, '/')}' does not exist. \u001b[39m` 371 ).message; 372 } 373 }); 374} 375 376function readAbilityEntrance(moduleJson) { 377 const abilityPages = []; 378 if (moduleJson.module) { 379 const moduleSrcEntrance = moduleJson.module.srcEntrance; 380 const moduleSrcEntry = moduleJson.module.srcEntry; 381 if (moduleSrcEntry) { 382 abilityPages.push(moduleSrcEntry); 383 abilityPagesFullPath.push(getAbilityFullPath(projectConfig.projectPath, moduleSrcEntry)); 384 } else if (moduleSrcEntrance) { 385 abilityPages.push(moduleSrcEntrance); 386 abilityPagesFullPath.push(getAbilityFullPath(projectConfig.projectPath, moduleSrcEntrance)); 387 } 388 if (moduleJson.module.abilities && moduleJson.module.abilities.length > 0) { 389 setEntrance(moduleJson.module.abilities, abilityPages); 390 } 391 if (moduleJson.module.extensionAbilities && moduleJson.module.extensionAbilities.length > 0) { 392 setEntrance(moduleJson.module.extensionAbilities, abilityPages); 393 setCardPages(moduleJson.module.extensionAbilities); 394 } 395 } 396 return abilityPages; 397} 398 399function setEntrance(abilityConfig, abilityPages) { 400 if (abilityConfig && abilityConfig.length > 0) { 401 abilityConfig.forEach(ability => { 402 if (ability.srcEntry) { 403 abilityPages.push(ability.srcEntry) 404 abilityPagesFullPath.push(getAbilityFullPath(projectConfig.projectPath, ability.srcEntry)) 405 } else if (ability.srcEntrance) { 406 abilityPages.push(ability.srcEntrance); 407 abilityPagesFullPath.push(getAbilityFullPath(projectConfig.projectPath, ability.srcEntrance)); 408 } 409 }); 410 } 411} 412 413function setCardPages(extensionAbilities) { 414 if (extensionAbilities && extensionAbilities.length > 0) { 415 extensionAbilities.forEach(extensionAbility => { 416 if (extensionAbility.metadata) { 417 extensionAbility.metadata.forEach(metadata => { 418 if (metadata.resource) { 419 readCardResource(metadata.resource); 420 } 421 }) 422 } 423 }); 424 } 425} 426 427function readCardResource(resource) { 428 const cardJsonFileName = `${resource.replace(/\$profile\:/, '')}.json`; 429 const modulePagePath = path.resolve(projectConfig.aceProfilePath, cardJsonFileName); 430 if (fs.existsSync(modulePagePath)) { 431 const cardConfig = JSON.parse(fs.readFileSync(modulePagePath, 'utf-8')); 432 if (cardConfig.forms) { 433 cardConfig.forms.forEach(form => { 434 readCardForm(form); 435 }) 436 } 437 } 438} 439 440function readCardForm(form) { 441 if ((form.type && form.type === 'eTS') || 442 (form.uiSyntax && form.uiSyntax === 'arkts')) { 443 const sourcePath = form.src.replace(/\.ets$/, ''); 444 const cardPath = path.resolve(projectConfig.projectPath, '..', sourcePath + '.ets'); 445 if (cardPath && fs.existsSync(cardPath)) { 446 projectConfig.entryObj['../' + sourcePath] = cardPath + '?entry'; 447 projectConfig.cardEntryObj['../' + sourcePath] = cardPath; 448 projectConfig.cardObj[cardPath] = sourcePath.replace(/^\.\//, ''); 449 } 450 } 451} 452 453function getAbilityFullPath(projectPath, abilityPath) { 454 const finalPath = path.resolve(path.resolve(projectPath, '../'), abilityPath); 455 if (fs.existsSync(finalPath)) { 456 return finalPath.toLowerCase(); 457 } else { 458 return path.resolve(abilityPath).toLowerCase(); 459 } 460} 461 462function loadWorker(projectConfig, workerFileEntry) { 463 if (workerFileEntry) { 464 projectConfig.entryObj = Object.assign(projectConfig.entryObj, workerFileEntry); 465 } else { 466 const workerPath = path.resolve(projectConfig.projectPath, WORKERS_DIR); 467 if (fs.existsSync(workerPath)) { 468 const workerFiles = []; 469 readFile(workerPath, workerFiles); 470 workerFiles.forEach((item) => { 471 if (/\.(ts|js)$/.test(item)) { 472 const relativePath = path.relative(workerPath, item) 473 .replace(/\.(ts|js)$/, '').replace(/\\/g, '/'); 474 projectConfig.entryObj[`./${WORKERS_DIR}/` + relativePath] = item; 475 } 476 }); 477 } 478 } 479} 480 481let aceBuildJson = {}; 482function loadBuildJson() { 483 if (projectConfig.aceBuildJson && fs.existsSync(projectConfig.aceBuildJson)) { 484 aceBuildJson = JSON.parse(fs.readFileSync(projectConfig.aceBuildJson).toString()); 485 } 486 if (aceBuildJson.packageManagerType === 'ohpm') { 487 projectConfig.packageManagerType = 'ohpm'; 488 projectConfig.packageDir = 'oh_modules'; 489 projectConfig.packageJson = 'oh-package.json5'; 490 } 491} 492 493function initBuildInfo() { 494 projectConfig.projectRootPath = aceBuildJson.projectRootPath; 495 if (projectConfig.compileHar && aceBuildJson.moduleName && 496 aceBuildJson.modulePathMap[aceBuildJson.moduleName]) { 497 projectConfig.moduleRootPath = aceBuildJson.modulePathMap[aceBuildJson.moduleName]; 498 } 499} 500 501function readWorkerFile() { 502 const workerFileEntry = {}; 503 if (aceBuildJson.workers) { 504 aceBuildJson.workers.forEach(worker => { 505 if (!/\.(ts|js)$/.test(worker)) { 506 worker += '.ts'; 507 } 508 const relativePath = path.relative(projectConfig.projectPath, worker); 509 if (filterWorker(relativePath)) { 510 const workerKey = relativePath.replace(/\.(ts|js)$/, '').replace(/\\/g, '/'); 511 if (workerFileEntry[workerKey]) { 512 throw Error( 513 '\u001b[31m ERROR: The worker file cannot use the same file name: \n' + 514 workerFileEntry[workerKey] + '\n' + worker + '\u001b[39m' 515 ).message; 516 } else { 517 workerFileEntry[workerKey] = worker; 518 } 519 } 520 }); 521 return workerFileEntry; 522 } 523 return null; 524} 525 526function readPatchConfig() { 527 if (aceBuildJson.patchConfig) { 528 projectConfig.hotReload = process.env.watchMode === 'true' && !projectConfig.isPreview; 529 projectConfig.patchAbcPath = aceBuildJson.patchConfig.patchAbcPath; 530 projectConfig.changedFileList = aceBuildJson.patchConfig.changedFileList ? 531 aceBuildJson.patchConfig.changedFileList : path.join(projectConfig.cachePath, 'changedFileList.json'); 532 if (projectConfig.hotReload) { 533 writeFileSync(projectConfig.changedFileList, JSON.stringify({ 534 modifiedFiles: [], 535 removedFiles: [] 536 })); 537 } 538 } 539} 540 541function filterWorker(workerPath) { 542 return /\.(ts|js)$/.test(workerPath); 543} 544 545;(function initSystemResource() { 546 const sysResourcePath = path.resolve(__dirname, './sysResource.js'); 547 if (fs.existsSync(sysResourcePath)) { 548 resources.sys = require(sysResourcePath).sys; 549 } 550})(); 551 552;(function readSystemModules() { 553 const systemModulesPath = path.resolve(__dirname, '../../api'); 554 if (fs.existsSync(systemModulesPath)) { 555 systemModules.push(...fs.readdirSync(systemModulesPath)); 556 } 557})() 558 559function readAppResource(filePath) { 560 if (fs.existsSync(filePath)) { 561 const appResource = fs.readFileSync(filePath, "utf-8"); 562 const resourceArr = appResource.split(/\n/); 563 let resourceMap = new Map(); 564 processResourceArr(resourceArr, resourceMap, filePath); 565 for (let [key, value] of resourceMap) { 566 resources.app[key] = value; 567 } 568 } 569} 570 571function processResourceArr(resourceArr, resourceMap, filePath) { 572 for (let i = 0; i < resourceArr.length; i++) { 573 if (!resourceArr[i].length) { 574 continue; 575 } 576 const resourceData = resourceArr[i].split(/\s/); 577 if (resourceData.length === 3 && !isNaN(Number(resourceData[2])) ) { 578 if (resourceMap.get(resourceData[0])) { 579 const resourceKeys = resourceMap.get(resourceData[0]); 580 if (!resourceKeys[resourceData[1]] || resourceKeys[resourceData[1]] !== Number(resourceData[2])) { 581 resourceKeys[resourceData[1]] = Number(resourceData[2]); 582 } 583 } else { 584 let obj = {}; 585 obj[resourceData[1]] = Number(resourceData[2]); 586 resourceMap.set(resourceData[0], obj); 587 } 588 } else { 589 logger.warn(`\u001b[31m ArkTS:WARN The format of file '${filePath}' is incorrect. \u001b[39m`); 590 break; 591 } 592 } 593} 594 595function hashProjectPath(projectPath) { 596 process.env.hashProjectPath = "_" + md5(projectPath); 597 return process.env.hashProjectPath; 598} 599 600function loadModuleInfo(projectConfig, envArgs) { 601 if (projectConfig.aceBuildJson && fs.existsSync(projectConfig.aceBuildJson)) { 602 const buildJsonInfo = JSON.parse(fs.readFileSync(projectConfig.aceBuildJson).toString()); 603 if (buildJsonInfo.compileMode) { 604 projectConfig.compileMode = buildJsonInfo.compileMode; 605 } 606 projectConfig.projectRootPath = buildJsonInfo.projectRootPath; 607 projectConfig.modulePathMap = buildJsonInfo.modulePathMap; 608 projectConfig.isOhosTest = buildJsonInfo.isOhosTest; 609 let faultHandler = function (error) { 610 // rollup's error will be handled in fast build 611 if (process.env.compileTool === 'rollup') { 612 return; 613 } 614 logger.error(error); 615 process.exit(FAIL); 616 } 617 const compileMode = process.env.compileTool === 'rollup' ? projectConfig.compileMode : buildJsonInfo.compileMode; 618 if (checkAotConfig(compileMode, buildJsonInfo, faultHandler)) { 619 projectConfig.processTs = true; 620 projectConfig.pandaMode = TS2ABC; 621 projectConfig.anBuildOutPut = buildJsonInfo.anBuildOutPut; 622 projectConfig.anBuildMode = buildJsonInfo.anBuildMode; 623 projectConfig.apPath = buildJsonInfo.apPath; 624 } else { 625 projectConfig.processTs = false; 626 projectConfig.pandaMode = buildJsonInfo.pandaMode; 627 } 628 if (envArgs !== undefined) { 629 projectConfig.buildArkMode = envArgs.buildMode; 630 } 631 if (compileMode === 'esmodule') { 632 projectConfig.nodeModulesPath = buildJsonInfo.nodeModulesPath; 633 projectConfig.harNameOhmMap = buildJsonInfo.harNameOhmMap; 634 } 635 if (projectConfig.compileHar && buildJsonInfo.moduleName && 636 buildJsonInfo.modulePathMap[buildJsonInfo.moduleName]) { 637 projectConfig.moduleRootPath = buildJsonInfo.modulePathMap[buildJsonInfo.moduleName]; 638 } 639 } 640} 641 642function checkAppResourcePath(appResourcePath, config) { 643 if (appResourcePath) { 644 readAppResource(appResourcePath); 645 if (fs.existsSync(appResourcePath) && config.cache) { 646 config.cache.buildDependencies.config.push(appResourcePath); 647 } 648 if (!projectConfig.xtsMode) { 649 const appResourcePathSavePath = path.resolve(projectConfig.cachePath, 'resource_path.txt'); 650 saveAppResourcePath(appResourcePath, appResourcePathSavePath); 651 if (fs.existsSync(appResourcePathSavePath) && config.cache) { 652 config.cache.buildDependencies.config.push(appResourcePathSavePath); 653 } 654 } 655 } 656} 657 658function saveAppResourcePath(appResourcePath, appResourcePathSavePath) { 659 let isSave = false; 660 if (fs.existsSync(appResourcePathSavePath)) { 661 const saveContent = fs.readFileSync(appResourcePathSavePath); 662 if (appResourcePath !== saveContent) { 663 isSave = true; 664 } 665 } else { 666 isSave = true; 667 } 668 if (isSave) { 669 fs.writeFileSync(appResourcePathSavePath, appResourcePath); 670 } 671} 672 673function addSDKBuildDependencies(config) { 674 if (projectConfig.localPropertiesPath && 675 fs.existsSync(projectConfig.localPropertiesPath) && config.cache) { 676 config.cache.buildDependencies.config.push(projectConfig.localPropertiesPath) 677 } 678 if (projectConfig.projectProfilePath && 679 fs.existsSync(projectConfig.projectProfilePath) && config.cache) { 680 config.cache.buildDependencies.config.push(projectConfig.projectProfilePath) 681 } 682} 683 684function getCleanConfig(workerFile) { 685 const cleanPath = []; 686 if (projectConfig.compileMode === 'esmodule') { 687 return cleanPath; 688 } 689 cleanPath.push(projectConfig.buildPath); 690 if (workerFile) { 691 const workerFilesPath = Object.keys(workerFile); 692 for (const workerFilePath of workerFilesPath) { 693 cleanPath.push(path.join(projectConfig.buildPath, workerFilePath, '..')); 694 } 695 } 696 return cleanPath; 697} 698 699function isPartialUpdate(metadata) { 700 if (Array.isArray(metadata) && metadata.length) { 701 metadata.some(item => { 702 if (item.name && item.name === 'ArkTSPartialUpdate' && 703 item.value && item.value === 'false') { 704 partialUpdateConfig.partialUpdateMode = false; 705 } 706 if (item.name && item.name === 'ArkTSBuilderCheck' && 707 item.value && item.value === 'false') { 708 partialUpdateConfig.builderCheck = false; 709 } 710 return !partialUpdateConfig.partialUpdateMode && !partialUpdateConfig.builderCheck; 711 }); 712 } 713} 714 715function partialUpdateController(minAPIVersion, metadata = null) { 716 if (minAPIVersion >= 9) { 717 partialUpdateConfig.partialUpdateMode = true; 718 } 719 if (metadata) { 720 isPartialUpdate(metadata); 721 } 722} 723 724const globalProgram = { 725 program: null, 726 watchProgram: null 727}; 728 729const partialUpdateConfig = { 730 partialUpdateMode: false, 731 builderCheck: true 732}; 733 734exports.globalProgram = globalProgram; 735exports.projectConfig = projectConfig; 736exports.loadEntryObj = loadEntryObj; 737exports.readAppResource = readAppResource; 738exports.resources = resources; 739exports.loadWorker = loadWorker; 740exports.abilityConfig = abilityConfig; 741exports.readWorkerFile = readWorkerFile; 742exports.abilityPagesFullPath = abilityPagesFullPath; 743exports.loadModuleInfo = loadModuleInfo; 744exports.systemModules = systemModules; 745exports.checkAppResourcePath = checkAppResourcePath; 746exports.addSDKBuildDependencies = addSDKBuildDependencies; 747exports.partialUpdateConfig = partialUpdateConfig; 748exports.readPatchConfig = readPatchConfig; 749exports.initBuildInfo = initBuildInfo; 750exports.getCleanConfig = getCleanConfig; 751