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 TS2ABC, 29 FAIL 30} = require('./lib/pre_define'); 31 32const { 33 checkAotConfig 34} = require('./lib/gen_aot'); 35 36const { 37 configure, 38 getLogger 39} = require('log4js'); 40 41configure({ 42 appenders: { 'ETS': {type: 'stderr', layout: {type: 'messagePassThrough'}}}, 43 categories: {'default': {appenders: ['ETS'], level: 'info'}} 44}); 45const logger = getLogger('ETS'); 46 47const staticPreviewPage = process.env.aceStaticPreview; 48const aceCompileMode = process.env.aceCompileMode || 'page'; 49const abilityConfig = { 50 abilityType: process.env.abilityType || 'page', 51 abilityEntryFile: null, 52 projectAbilityPath: [], 53 testRunnerFile: [] 54}; 55const projectConfig = {}; 56const resources = { 57 app: {}, 58 sys: {} 59}; 60const systemModules = []; 61const abilityPagesFullPath = []; 62 63function initProjectConfig(projectConfig) { 64 projectConfig.entryObj = {}; 65 projectConfig.cardObj = {}; 66 projectConfig.projectPath = projectConfig.projectPath || process.env.aceModuleRoot || 67 path.join(process.cwd(), 'sample'); 68 projectConfig.buildPath = projectConfig.buildPath || process.env.aceModuleBuild || 69 path.resolve(projectConfig.projectPath, 'build'); 70 projectConfig.aceModuleBuild = projectConfig.buildPath; // To be compatible with both webpack and rollup 71 projectConfig.manifestFilePath = projectConfig.manifestFilePath || process.env.aceManifestPath || 72 path.join(projectConfig.projectPath, 'manifest.json'); 73 projectConfig.aceProfilePath = projectConfig.aceProfilePath || process.env.aceProfilePath; 74 projectConfig.aceModuleJsonPath = projectConfig.aceModuleJsonPath || process.env.aceModuleJsonPath; 75 projectConfig.aceSuperVisualPath = projectConfig.aceSuperVisualPath || 76 process.env.aceSuperVisualPath; 77 projectConfig.hashProjectPath = projectConfig.hashProjectPath || 78 hashProjectPath(projectConfig.projectPath); 79 projectConfig.aceBuildJson = projectConfig.aceBuildJson || process.env.aceBuildJson; 80 projectConfig.cachePath = projectConfig.cachePath || process.env.cachePath || 81 path.resolve(__dirname, 'node_modules/.cache'); 82 projectConfig.aceSoPath = projectConfig.aceSoPath || process.env.aceSoPath; 83 projectConfig.xtsMode = /ets_loader_ark$/.test(__dirname); 84 projectConfig.localPropertiesPath = projectConfig.localPropertiesPath || process.env.localPropertiesPath; 85 projectConfig.projectProfilePath = projectConfig.projectProfilePath || process.env.projectProfilePath; 86 projectConfig.isPreview = projectConfig.isPreview || process.env.isPreview === 'true'; 87 projectConfig.compileMode = projectConfig.compileMode || 'jsbundle'; 88 projectConfig.runtimeOS = projectConfig.runtimeOS || process.env.runtimeOS || 'default'; 89 projectConfig.sdkInfo = projectConfig.sdkInfo || process.env.sdkInfo || 'default'; 90 projectConfig.splitCommon = false; 91 projectConfig.compileHar = false; 92 projectConfig.compileShared = false; 93 projectConfig.checkEntry = projectConfig.checkEntry || process.env.checkEntry; 94 projectConfig.obfuscateHarType = projectConfig.obfuscateHarType || process.env.obfuscate; 95 projectConfig.packageDir = 'node_modules'; 96 projectConfig.packageJson = 'package.json'; 97 projectConfig.packageManagerType = 'npm'; 98 projectConfig.cardEntryObj = {}; 99} 100 101function loadEntryObj(projectConfig) { 102 let manifest = {}; 103 initProjectConfig(projectConfig); 104 loadBuildJson(); 105 if (process.env.aceManifestPath && aceCompileMode === 'page') { 106 setEntryFile(projectConfig); 107 setFaTestRunnerFile(projectConfig); 108 } 109 if (process.env.aceModuleJsonPath) { 110 setAbilityPages(projectConfig); 111 setStageTestRunnerFile(projectConfig); 112 } 113 114 if (staticPreviewPage) { 115 projectConfig.entryObj['./' + staticPreviewPage] = projectConfig.projectPath + path.sep + 116 staticPreviewPage + '.ets?entry'; 117 } else if (abilityConfig.abilityType === 'page') { 118 if (fs.existsSync(projectConfig.manifestFilePath)) { 119 const jsonString = fs.readFileSync(projectConfig.manifestFilePath).toString(); 120 manifest = JSON.parse(jsonString); 121 if (manifest && manifest.minPlatformVersion) { 122 process.env.minPlatformVersion = manifest.minPlatformVersion; 123 partialUpdateController(manifest.minPlatformVersion); 124 } 125 projectConfig.pagesJsonFileName = 'config.json'; 126 } else if (projectConfig.aceModuleJsonPath && fs.existsSync(projectConfig.aceModuleJsonPath)) { 127 process.env.compileMode = 'moduleJson'; 128 buildManifest(manifest, projectConfig.aceModuleJsonPath); 129 } else { 130 throw Error('\u001b[31m ERROR: the manifest file ' + projectConfig.manifestFilePath.replace(/\\/g, '/') + 131 ' or module.json is lost or format is invalid. \u001b[39m').message; 132 } 133 if (!projectConfig.compileHar) { 134 if (manifest.pages) { 135 const pages = manifest.pages; 136 pages.forEach((element) => { 137 const sourcePath = element.replace(/^\.\/ets\//, ''); 138 const fileName = path.resolve(projectConfig.projectPath, sourcePath + '.ets'); 139 if (fs.existsSync(fileName)) { 140 projectConfig.entryObj['./' + sourcePath] = fileName + '?entry'; 141 } else { 142 throw Error(`\u001b[31m ERROR: page '${fileName.replace(/\\/g, '/')}' does not exist. \u001b[39m`) 143 .message; 144 } 145 }); 146 } else { 147 throw Error('\u001b[31m ERROR: missing pages attribute in ' + 148 projectConfig.manifestFilePath.replace(/\\/g, '/') + 149 '. \u001b[39m').message; 150 } 151 } 152 } 153} 154 155function buildManifest(manifest, aceConfigPath) { 156 try { 157 const moduleConfigJson = JSON.parse(fs.readFileSync(aceConfigPath).toString()); 158 manifest.type = process.env.abilityType; 159 if (moduleConfigJson && moduleConfigJson.app && moduleConfigJson.app.minAPIVersion) { 160 if (moduleConfigJson.module && moduleConfigJson.module.metadata) { 161 partialUpdateController(moduleConfigJson.app.minAPIVersion, moduleConfigJson.module.metadata); 162 stageOptimization(moduleConfigJson.module.metadata); 163 } else { 164 partialUpdateController(moduleConfigJson.app.minAPIVersion); 165 } 166 } 167 if (moduleConfigJson.module) { 168 switch (moduleConfigJson.module.type) { 169 case 'har': 170 projectConfig.compileHar = true; 171 getPackageJsonEntryPath(); 172 break; 173 case 'shared': 174 projectConfig.compileShared = true; 175 getPackageJsonEntryPath(); 176 manifest.pages = getPages(moduleConfigJson); 177 break; 178 default: 179 manifest.pages = getPages(moduleConfigJson); 180 break; 181 } 182 } else { 183 throw Error('\u001b[31m' + 184 'ERROR: the config.json file miss key word module || module[abilities].' + 185 '\u001b[39m').message; 186 } 187 } catch (e) { 188 if (/BUIDERROR/.test(e)) { 189 throw Error(e.replace('BUIDERROR', 'ERROR')).message; 190 } else { 191 throw Error('\x1B[31m' + 'ERROR: the module.json file is lost or format is invalid.' + 192 '\x1B[39m').message; 193 } 194 } 195} 196 197function getPackageJsonEntryPath() { 198 const rootPackageJsonPath = path.resolve(projectConfig.projectPath, '../../../' + projectConfig.packageJson); 199 if (fs.existsSync(rootPackageJsonPath)) { 200 const rootPackageJsonContent = 201 (projectConfig.packageManagerType === 'npm' ? JSON : JSON5).parse(fs.readFileSync(rootPackageJsonPath, 'utf-8')); 202 if (rootPackageJsonContent) { 203 if (rootPackageJsonContent.module) { 204 getEntryPath(rootPackageJsonContent.module, rootPackageJsonPath); 205 } else if (rootPackageJsonContent.main) { 206 getEntryPath(rootPackageJsonContent.main, rootPackageJsonPath); 207 } else { 208 getEntryPath('', rootPackageJsonPath); 209 } 210 } else if (projectConfig.compileHar) { 211 throw Error('\u001b[31m' + 'lack message in ' + projectConfig.packageJson + '.' + '\u001b[39m').message; 212 } 213 } 214} 215 216function supportSuffix(mainEntryPath) { 217 if (fs.existsSync(path.join(mainEntryPath, 'index.ets'))) { 218 mainEntryPath = path.join(mainEntryPath, 'index.ets'); 219 } else if (fs.existsSync(path.join(mainEntryPath, 'index.ts'))) { 220 mainEntryPath = path.join(mainEntryPath, 'index.ts'); 221 } else if (fs.existsSync(path.join(mainEntryPath, 'index.js'))) { 222 mainEntryPath = path.join(mainEntryPath, 'index.js'); 223 } else if (projectConfig.compileHar) { 224 throw Error('\u001b[31m' + 'not find entry file in ' + projectConfig.packageJson + '.' + '\u001b[39m').message; 225 } 226 return mainEntryPath; 227} 228 229function supportExtName(mainEntryPath) { 230 if (path.extname(mainEntryPath) === '') { 231 if (fs.existsSync(mainEntryPath + '.ets')) { 232 mainEntryPath = mainEntryPath + '.ets'; 233 } else if (fs.existsSync(mainEntryPath + '.ts')) { 234 mainEntryPath = mainEntryPath + '.ts'; 235 } else if (fs.existsSync(mainEntryPath + '.js')) { 236 mainEntryPath = mainEntryPath + '.js'; 237 } 238 } 239 return mainEntryPath; 240} 241 242function getEntryPath(entryPath, rootPackageJsonPath) { 243 let mainEntryPath = path.resolve(rootPackageJsonPath, '../', entryPath); 244 if (fs.existsSync(mainEntryPath) && fs.statSync(mainEntryPath).isDirectory()) { 245 mainEntryPath = supportSuffix(mainEntryPath); 246 } else { 247 mainEntryPath = supportExtName(mainEntryPath); 248 } 249 if (fs.existsSync(mainEntryPath) && fs.statSync(mainEntryPath).isFile()) { 250 const entryKey = path.relative(projectConfig.projectPath, mainEntryPath); 251 projectConfig.entryObj[entryKey] = mainEntryPath; 252 abilityPagesFullPath.push(path.resolve(mainEntryPath).toLowerCase()); 253 } else if (projectConfig.compileHar) { 254 throw Error('\u001b[31m' + 'not find entry file in package.json.' + '\u001b[39m').message; 255 } 256} 257 258function stageOptimization(metadata) { 259 if (Array.isArray(metadata) && metadata.length) { 260 metadata.some(item => { 261 if (item.name && item.name === 'USE_COMMON_CHUNK' && 262 item.value && item.value === 'true') { 263 projectConfig.splitCommon = true; 264 return true; 265 } 266 }); 267 } 268} 269 270function getPages(configJson) { 271 const pages = []; 272 let pagesJsonFileName = ''; 273 // pages is not necessary in shared library 274 if (projectConfig.compileShared && configJson.module && configJson.module.pages || !projectConfig.compileShared) { 275 pagesJsonFileName = `${configJson.module.pages.replace(/\$profile\:/, '')}.json`; 276 } else { 277 return pages; 278 } 279 const modulePagePath = path.resolve(projectConfig.aceProfilePath, pagesJsonFileName); 280 if (fs.existsSync(modulePagePath)) { 281 try { 282 const pagesConfig = JSON.parse(fs.readFileSync(modulePagePath, 'utf-8')); 283 if (pagesConfig && pagesConfig.src) { 284 projectConfig.pagesJsonFileName = pagesJsonFileName; 285 return pagesConfig.src; 286 } 287 } catch (e) { 288 throw Error("\x1B[31m" + `BUIDERROR: the ${modulePagePath} file format is invalid.` + 289 "\x1B[39m").message; 290 } 291 } 292 return pages; 293} 294 295function setEntryFile(projectConfig) { 296 const entryFileName = abilityConfig.abilityType === 'page' ? 'app' : abilityConfig.abilityType; 297 const extendFile = entryFileName === 'app' ? '.ets' : '.ts'; 298 const entryFileRealPath = entryFileName + extendFile; 299 const entryFilePath = path.resolve(projectConfig.projectPath, entryFileRealPath); 300 abilityConfig.abilityEntryFile = entryFilePath; 301 if (!fs.existsSync(entryFilePath) && aceCompileMode === 'page') { 302 throw Error(`\u001b[31m ERROR: missing ${entryFilePath.replace(/\\/g, '/')}. \u001b[39m`).message; 303 } 304 projectConfig.entryObj[`./${entryFileName}`] = entryFilePath + '?entry'; 305} 306 307function setAbilityPages(projectConfig) { 308 let abilityPages = []; 309 if (projectConfig.aceModuleJsonPath && fs.existsSync(projectConfig.aceModuleJsonPath)) { 310 const moduleJson = JSON.parse(fs.readFileSync(projectConfig.aceModuleJsonPath).toString()); 311 abilityPages = readAbilityEntrance(moduleJson); 312 setAbilityFile(projectConfig, abilityPages); 313 setBundleModuleInfo(projectConfig, moduleJson); 314 } 315} 316 317function setFaTestRunnerFile(projectConfig) { 318 const index =projectConfig.projectPath.split(path.sep).join('/').lastIndexOf('\/'); 319 const testRunnerPath = path.resolve(projectConfig.projectPath.substring(0,index + 1), "TestRunner"); 320 if (fs.existsSync(testRunnerPath)) { 321 const testRunnerFiles = []; 322 readFile(testRunnerPath, testRunnerFiles); 323 testRunnerFiles.forEach((item) => { 324 if (/\.(ts|js|ets)$/.test(item)) { 325 const relativePath = path.relative(testRunnerPath, item).replace(/\.(ts|js|ets)$/, ''); 326 projectConfig.entryObj["../TestRunner/" + relativePath] = item; 327 abilityConfig.testRunnerFile.push(item); 328 } 329 }); 330 } 331} 332 333function setStageTestRunnerFile(projectConfig) { 334 const index =projectConfig.projectPath.split(path.sep).join('/').lastIndexOf('\/'); 335 const testRunnerPath = path.resolve(projectConfig.projectPath, "TestRunner"); 336 if (fs.existsSync(testRunnerPath)) { 337 const testRunnerFiles = []; 338 readFile(testRunnerPath, testRunnerFiles); 339 testRunnerFiles.forEach((item) => { 340 if (/\.(ts|js|ets)$/.test(item)) { 341 const relativePath = path.relative(testRunnerPath, item).replace(/\.(ts|js|ets)$/, ''); 342 projectConfig.entryObj["./TestRunner/" + relativePath] = item; 343 abilityConfig.testRunnerFile.push(item); 344 } 345 }); 346 } 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