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