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 'BUIDERROR: 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 let rootPackageJsonContent; 202 try { 203 rootPackageJsonContent = (projectConfig.packageManagerType === 'npm' ? 204 JSON : JSON5).parse(fs.readFileSync(rootPackageJsonPath, 'utf-8')); 205 } catch (e) { 206 throw Error('\u001b[31m' + 'BUIDERROR: ' + rootPackageJsonPath + ' format is invalid.' + '\u001b[39m').message; 207 } 208 if (rootPackageJsonContent) { 209 if (rootPackageJsonContent.module) { 210 getEntryPath(rootPackageJsonContent.module, rootPackageJsonPath); 211 } else if (rootPackageJsonContent.main) { 212 getEntryPath(rootPackageJsonContent.main, rootPackageJsonPath); 213 } else { 214 getEntryPath('', rootPackageJsonPath); 215 } 216 } else if (projectConfig.compileHar) { 217 throw Error('\u001b[31m' + 'BUIDERROR: lack message in ' + projectConfig.packageJson + '.' + 218 '\u001b[39m').message; 219 } 220 } 221} 222 223function supportSuffix(mainEntryPath) { 224 if (fs.existsSync(path.join(mainEntryPath, 'index.ets'))) { 225 mainEntryPath = path.join(mainEntryPath, 'index.ets'); 226 } else if (fs.existsSync(path.join(mainEntryPath, 'index.ts'))) { 227 mainEntryPath = path.join(mainEntryPath, 'index.ts'); 228 } else if (fs.existsSync(path.join(mainEntryPath, 'index.js'))) { 229 mainEntryPath = path.join(mainEntryPath, 'index.js'); 230 } else if (projectConfig.compileHar) { 231 throw Error('\u001b[31m' + 'BUIDERROR: not find entry file in ' + projectConfig.packageJson + 232 '.' + '\u001b[39m').message; 233 } 234 return mainEntryPath; 235} 236 237function supportExtName(mainEntryPath) { 238 if (path.extname(mainEntryPath) === '') { 239 if (fs.existsSync(mainEntryPath + '.ets')) { 240 mainEntryPath = mainEntryPath + '.ets'; 241 } else if (fs.existsSync(mainEntryPath + '.ts')) { 242 mainEntryPath = mainEntryPath + '.ts'; 243 } else if (fs.existsSync(mainEntryPath + '.js')) { 244 mainEntryPath = mainEntryPath + '.js'; 245 } 246 } 247 return mainEntryPath; 248} 249 250function getEntryPath(entryPath, rootPackageJsonPath) { 251 let mainEntryPath = path.resolve(rootPackageJsonPath, '../', entryPath); 252 if (fs.existsSync(mainEntryPath) && fs.statSync(mainEntryPath).isDirectory()) { 253 mainEntryPath = supportSuffix(mainEntryPath); 254 } else { 255 mainEntryPath = supportExtName(mainEntryPath); 256 } 257 if (fs.existsSync(mainEntryPath) && fs.statSync(mainEntryPath).isFile()) { 258 const entryKey = path.relative(projectConfig.projectPath, mainEntryPath); 259 projectConfig.entryObj[entryKey] = mainEntryPath; 260 abilityPagesFullPath.push(path.resolve(mainEntryPath).toLowerCase()); 261 } else if (projectConfig.compileHar) { 262 throw Error('\u001b[31m' + `BUIDERROR: not find entry file in ${rootPackageJsonPath}.` + '\u001b[39m').message; 263 } 264} 265 266function stageOptimization(metadata) { 267 if (Array.isArray(metadata) && metadata.length) { 268 metadata.some(item => { 269 if (item.name && item.name === 'USE_COMMON_CHUNK' && 270 item.value && item.value === 'true') { 271 projectConfig.splitCommon = true; 272 return true; 273 } 274 }); 275 } 276} 277 278function getPages(configJson) { 279 const pages = []; 280 let pagesJsonFileName = ''; 281 // pages is not necessary in shared library 282 if (projectConfig.compileShared && configJson.module && configJson.module.pages || !projectConfig.compileShared) { 283 pagesJsonFileName = `${configJson.module.pages.replace(/\$profile\:/, '')}.json`; 284 } else { 285 return pages; 286 } 287 const modulePagePath = path.resolve(projectConfig.aceProfilePath, pagesJsonFileName); 288 if (fs.existsSync(modulePagePath)) { 289 try { 290 const pagesConfig = JSON.parse(fs.readFileSync(modulePagePath, 'utf-8')); 291 if (pagesConfig && pagesConfig.src) { 292 projectConfig.pagesJsonFileName = pagesJsonFileName; 293 return pagesConfig.src; 294 } 295 } catch (e) { 296 throw Error("\x1B[31m" + `BUIDERROR: the ${modulePagePath} file format is invalid.` + 297 "\x1B[39m").message; 298 } 299 } 300 return pages; 301} 302 303function setEntryFile(projectConfig) { 304 const entryFileName = abilityConfig.abilityType === 'page' ? 'app' : abilityConfig.abilityType; 305 const extendFile = entryFileName === 'app' ? '.ets' : '.ts'; 306 const entryFileRealPath = entryFileName + extendFile; 307 const entryFilePath = path.resolve(projectConfig.projectPath, entryFileRealPath); 308 abilityConfig.abilityEntryFile = entryFilePath; 309 if (!fs.existsSync(entryFilePath) && aceCompileMode === 'page') { 310 throw Error(`\u001b[31m ERROR: missing ${entryFilePath.replace(/\\/g, '/')}. \u001b[39m`).message; 311 } 312 projectConfig.entryObj[`./${entryFileName}`] = entryFilePath + '?entry'; 313} 314 315function setAbilityPages(projectConfig) { 316 let abilityPages = []; 317 if (projectConfig.aceModuleJsonPath && fs.existsSync(projectConfig.aceModuleJsonPath)) { 318 const moduleJson = JSON.parse(fs.readFileSync(projectConfig.aceModuleJsonPath).toString()); 319 abilityPages = readAbilityEntrance(moduleJson); 320 setAbilityFile(projectConfig, abilityPages); 321 setBundleModuleInfo(projectConfig, moduleJson); 322 } 323} 324 325function setTestRunnerFile(projectConfig, isStageBased) { 326 const index =projectConfig.projectPath.split(path.sep).join('/').lastIndexOf('\/'); 327 TEST_RUNNER_DIR_SET.forEach((dir) => { 328 let projectPath = isStageBased ? projectConfig.projectPath : projectConfig.projectPath.substring(0,index + 1); 329 const testRunnerPath = path.resolve(projectPath, dir); 330 if (fs.existsSync(testRunnerPath)) { 331 const testRunnerFiles = []; 332 readFile(testRunnerPath, testRunnerFiles); 333 testRunnerFiles.forEach((item) => { 334 if (/\.(ts|js|ets)$/.test(item)) { 335 const relativePath = path.relative(testRunnerPath, item).replace(/\.(ts|js|ets)$/, ''); 336 if (isStageBased) { 337 projectConfig.entryObj[`./${dir}/${relativePath}`] = item; 338 } else { 339 projectConfig.entryObj[`../${dir}/${relativePath}`] = item; 340 } 341 abilityConfig.testRunnerFile.push(item); 342 } 343 }) 344 } 345 }); 346} 347 348function setFaTestRunnerFile(projectConfig) { 349 setTestRunnerFile(projectConfig, false); 350} 351 352function setStageTestRunnerFile(projectConfig) { 353 setTestRunnerFile(projectConfig, true); 354} 355 356function setBundleModuleInfo(projectConfig, moduleJson) { 357 if (moduleJson.module) { 358 projectConfig.moduleName = moduleJson.module.name; 359 } 360 if (moduleJson.app) { 361 projectConfig.bundleName = moduleJson.app.bundleName; 362 } 363} 364 365function setAbilityFile(projectConfig, abilityPages) { 366 abilityPages.forEach(abilityPath => { 367 const projectAbilityPath = path.resolve(projectConfig.projectPath, '../', abilityPath); 368 if (path.isAbsolute(abilityPath)) { 369 abilityPath = '.' + abilityPath.slice(projectConfig.projectPath.length); 370 } 371 const entryPageKey = abilityPath.replace(/^\.\/ets\//, './').replace(/\.ts$/, '').replace(/\.ets$/, ''); 372 if (fs.existsSync(projectAbilityPath)) { 373 abilityConfig.projectAbilityPath.push(projectAbilityPath); 374 projectConfig.entryObj[entryPageKey] = projectAbilityPath + '?entry'; 375 } else { 376 throw Error( 377 `\u001b[31m ERROR: srcEntry file '${projectAbilityPath.replace(/\\/g, '/')}' does not exist. \u001b[39m` 378 ).message; 379 } 380 }); 381} 382 383function readAbilityEntrance(moduleJson) { 384 const abilityPages = []; 385 if (moduleJson.module) { 386 const moduleSrcEntrance = moduleJson.module.srcEntrance; 387 const moduleSrcEntry = moduleJson.module.srcEntry; 388 if (moduleSrcEntry) { 389 abilityPages.push(moduleSrcEntry); 390 abilityPagesFullPath.push(getAbilityFullPath(projectConfig.projectPath, moduleSrcEntry)); 391 } else if (moduleSrcEntrance) { 392 abilityPages.push(moduleSrcEntrance); 393 abilityPagesFullPath.push(getAbilityFullPath(projectConfig.projectPath, moduleSrcEntrance)); 394 } 395 if (moduleJson.module.abilities && moduleJson.module.abilities.length > 0) { 396 setEntrance(moduleJson.module.abilities, abilityPages); 397 } 398 if (moduleJson.module.extensionAbilities && moduleJson.module.extensionAbilities.length > 0) { 399 setEntrance(moduleJson.module.extensionAbilities, abilityPages); 400 setCardPages(moduleJson.module.extensionAbilities); 401 } 402 } 403 return abilityPages; 404} 405 406function setEntrance(abilityConfig, abilityPages) { 407 if (abilityConfig && abilityConfig.length > 0) { 408 abilityConfig.forEach(ability => { 409 if (ability.srcEntry) { 410 abilityPages.push(ability.srcEntry) 411 abilityPagesFullPath.push(getAbilityFullPath(projectConfig.projectPath, ability.srcEntry)) 412 } else if (ability.srcEntrance) { 413 abilityPages.push(ability.srcEntrance); 414 abilityPagesFullPath.push(getAbilityFullPath(projectConfig.projectPath, ability.srcEntrance)); 415 } 416 }); 417 } 418} 419 420function setCardPages(extensionAbilities) { 421 if (extensionAbilities && extensionAbilities.length > 0) { 422 extensionAbilities.forEach(extensionAbility => { 423 if (extensionAbility.metadata) { 424 extensionAbility.metadata.forEach(metadata => { 425 if (metadata.resource) { 426 readCardResource(metadata.resource); 427 } 428 }) 429 } 430 }); 431 } 432} 433 434function readCardResource(resource) { 435 const cardJsonFileName = `${resource.replace(/\$profile\:/, '')}.json`; 436 const modulePagePath = path.resolve(projectConfig.aceProfilePath, cardJsonFileName); 437 if (fs.existsSync(modulePagePath)) { 438 const cardConfig = JSON.parse(fs.readFileSync(modulePagePath, 'utf-8')); 439 if (cardConfig.forms) { 440 cardConfig.forms.forEach(form => { 441 readCardForm(form); 442 }) 443 } 444 } 445} 446 447function readCardForm(form) { 448 if ((form.type && form.type === 'eTS') || 449 (form.uiSyntax && form.uiSyntax === 'arkts')) { 450 const sourcePath = form.src.replace(/\.ets$/, ''); 451 const cardPath = path.resolve(projectConfig.projectPath, '..', sourcePath + '.ets'); 452 if (cardPath && fs.existsSync(cardPath)) { 453 projectConfig.entryObj['../' + sourcePath] = cardPath + '?entry'; 454 projectConfig.cardEntryObj['../' + sourcePath] = cardPath; 455 projectConfig.cardObj[cardPath] = sourcePath.replace(/^\.\//, ''); 456 } 457 } 458} 459 460function getAbilityFullPath(projectPath, abilityPath) { 461 const finalPath = path.resolve(path.resolve(projectPath, '../'), abilityPath); 462 if (fs.existsSync(finalPath)) { 463 return finalPath.toLowerCase(); 464 } else { 465 return path.resolve(abilityPath).toLowerCase(); 466 } 467} 468 469function loadWorker(projectConfig, workerFileEntry) { 470 if (workerFileEntry) { 471 projectConfig.entryObj = Object.assign(projectConfig.entryObj, workerFileEntry); 472 } else { 473 const workerPath = path.resolve(projectConfig.projectPath, WORKERS_DIR); 474 if (fs.existsSync(workerPath)) { 475 const workerFiles = []; 476 readFile(workerPath, workerFiles); 477 workerFiles.forEach((item) => { 478 if (/\.(ts|js)$/.test(item)) { 479 const relativePath = path.relative(workerPath, item) 480 .replace(/\.(ts|js)$/, '').replace(/\\/g, '/'); 481 projectConfig.entryObj[`./${WORKERS_DIR}/` + relativePath] = item; 482 } 483 }); 484 } 485 } 486} 487 488let aceBuildJson = {}; 489function loadBuildJson() { 490 if (projectConfig.aceBuildJson && fs.existsSync(projectConfig.aceBuildJson)) { 491 aceBuildJson = JSON.parse(fs.readFileSync(projectConfig.aceBuildJson).toString()); 492 } 493 if (aceBuildJson.packageManagerType === 'ohpm') { 494 projectConfig.packageManagerType = 'ohpm'; 495 projectConfig.packageDir = 'oh_modules'; 496 projectConfig.packageJson = 'oh-package.json5'; 497 } 498} 499 500function initBuildInfo() { 501 projectConfig.projectRootPath = aceBuildJson.projectRootPath; 502 if (projectConfig.compileHar && aceBuildJson.moduleName && 503 aceBuildJson.modulePathMap[aceBuildJson.moduleName]) { 504 projectConfig.moduleRootPath = aceBuildJson.modulePathMap[aceBuildJson.moduleName]; 505 } 506} 507 508function readWorkerFile() { 509 const workerFileEntry = {}; 510 if (aceBuildJson.workers) { 511 aceBuildJson.workers.forEach(worker => { 512 if (!/\.(ts|js)$/.test(worker)) { 513 worker += '.ts'; 514 } 515 const relativePath = path.relative(projectConfig.projectPath, worker); 516 if (filterWorker(relativePath)) { 517 const workerKey = relativePath.replace(/\.(ts|js)$/, '').replace(/\\/g, '/'); 518 if (workerFileEntry[workerKey]) { 519 throw Error( 520 '\u001b[31m ERROR: The worker file cannot use the same file name: \n' + 521 workerFileEntry[workerKey] + '\n' + worker + '\u001b[39m' 522 ).message; 523 } else { 524 workerFileEntry[workerKey] = worker; 525 } 526 } 527 }); 528 return workerFileEntry; 529 } 530 return null; 531} 532 533function readPatchConfig() { 534 if (aceBuildJson.patchConfig) { 535 projectConfig.hotReload = process.env.watchMode === 'true' && !projectConfig.isPreview; 536 projectConfig.patchAbcPath = aceBuildJson.patchConfig.patchAbcPath; 537 projectConfig.changedFileList = aceBuildJson.patchConfig.changedFileList ? 538 aceBuildJson.patchConfig.changedFileList : path.join(projectConfig.cachePath, 'changedFileList.json'); 539 if (projectConfig.hotReload) { 540 writeFileSync(projectConfig.changedFileList, JSON.stringify({ 541 modifiedFiles: [], 542 removedFiles: [] 543 })); 544 } 545 } 546} 547 548function filterWorker(workerPath) { 549 return /\.(ts|js)$/.test(workerPath); 550} 551 552;(function initSystemResource() { 553 const sysResourcePath = path.resolve(__dirname, './sysResource.js'); 554 if (fs.existsSync(sysResourcePath)) { 555 resources.sys = require(sysResourcePath).sys; 556 } 557})(); 558 559;(function readSystemModules() { 560 const systemModulesPath = path.resolve(__dirname, '../../api'); 561 if (fs.existsSync(systemModulesPath)) { 562 systemModules.push(...fs.readdirSync(systemModulesPath)); 563 } 564})() 565 566function readAppResource(filePath) { 567 if (fs.existsSync(filePath)) { 568 const appResource = fs.readFileSync(filePath, "utf-8"); 569 const resourceArr = appResource.split(/\n/); 570 let resourceMap = new Map(); 571 processResourceArr(resourceArr, resourceMap, filePath); 572 for (let [key, value] of resourceMap) { 573 resources.app[key] = value; 574 } 575 } 576} 577 578function processResourceArr(resourceArr, resourceMap, filePath) { 579 for (let i = 0; i < resourceArr.length; i++) { 580 if (!resourceArr[i].length) { 581 continue; 582 } 583 const resourceData = resourceArr[i].split(/\s/); 584 if (resourceData.length === 3 && !isNaN(Number(resourceData[2])) ) { 585 if (resourceMap.get(resourceData[0])) { 586 const resourceKeys = resourceMap.get(resourceData[0]); 587 if (!resourceKeys[resourceData[1]] || resourceKeys[resourceData[1]] !== Number(resourceData[2])) { 588 resourceKeys[resourceData[1]] = Number(resourceData[2]); 589 } 590 } else { 591 let obj = {}; 592 obj[resourceData[1]] = Number(resourceData[2]); 593 resourceMap.set(resourceData[0], obj); 594 } 595 } else { 596 logger.warn(`\u001b[31m ArkTS:WARN The format of file '${filePath}' is incorrect. \u001b[39m`); 597 break; 598 } 599 } 600} 601 602function hashProjectPath(projectPath) { 603 process.env.hashProjectPath = "_" + md5(projectPath); 604 return process.env.hashProjectPath; 605} 606 607function loadModuleInfo(projectConfig, envArgs) { 608 if (projectConfig.aceBuildJson && fs.existsSync(projectConfig.aceBuildJson)) { 609 const buildJsonInfo = JSON.parse(fs.readFileSync(projectConfig.aceBuildJson).toString()); 610 if (buildJsonInfo.compileMode) { 611 projectConfig.compileMode = buildJsonInfo.compileMode; 612 } 613 projectConfig.projectRootPath = buildJsonInfo.projectRootPath; 614 projectConfig.modulePathMap = buildJsonInfo.modulePathMap; 615 projectConfig.isOhosTest = buildJsonInfo.isOhosTest; 616 let faultHandler = function (error) { 617 // rollup's error will be handled in fast build 618 if (process.env.compileTool === 'rollup') { 619 return; 620 } 621 logger.error(error); 622 process.exit(FAIL); 623 } 624 const compileMode = process.env.compileTool === 'rollup' ? projectConfig.compileMode : buildJsonInfo.compileMode; 625 if (checkAotConfig(compileMode, buildJsonInfo, faultHandler)) { 626 projectConfig.processTs = true; 627 projectConfig.pandaMode = TS2ABC; 628 projectConfig.anBuildOutPut = buildJsonInfo.anBuildOutPut; 629 projectConfig.anBuildMode = buildJsonInfo.anBuildMode; 630 projectConfig.apPath = buildJsonInfo.apPath; 631 } else { 632 projectConfig.processTs = false; 633 projectConfig.pandaMode = buildJsonInfo.pandaMode; 634 } 635 if (envArgs !== undefined) { 636 projectConfig.buildArkMode = envArgs.buildMode; 637 } 638 if (compileMode === 'esmodule') { 639 projectConfig.nodeModulesPath = buildJsonInfo.nodeModulesPath; 640 projectConfig.harNameOhmMap = buildJsonInfo.harNameOhmMap; 641 } 642 if (projectConfig.compileHar && buildJsonInfo.moduleName && 643 buildJsonInfo.modulePathMap[buildJsonInfo.moduleName]) { 644 projectConfig.moduleRootPath = buildJsonInfo.modulePathMap[buildJsonInfo.moduleName]; 645 } 646 } 647} 648 649function checkAppResourcePath(appResourcePath, config) { 650 if (appResourcePath) { 651 readAppResource(appResourcePath); 652 if (fs.existsSync(appResourcePath) && config.cache) { 653 config.cache.buildDependencies.config.push(appResourcePath); 654 } 655 if (!projectConfig.xtsMode) { 656 const appResourcePathSavePath = path.resolve(projectConfig.cachePath, 'resource_path.txt'); 657 saveAppResourcePath(appResourcePath, appResourcePathSavePath); 658 if (fs.existsSync(appResourcePathSavePath) && config.cache) { 659 config.cache.buildDependencies.config.push(appResourcePathSavePath); 660 } 661 } 662 } 663} 664 665function saveAppResourcePath(appResourcePath, appResourcePathSavePath) { 666 let isSave = false; 667 if (fs.existsSync(appResourcePathSavePath)) { 668 const saveContent = fs.readFileSync(appResourcePathSavePath); 669 if (appResourcePath !== saveContent) { 670 isSave = true; 671 } 672 } else { 673 isSave = true; 674 } 675 if (isSave) { 676 fs.writeFileSync(appResourcePathSavePath, appResourcePath); 677 } 678} 679 680function addSDKBuildDependencies(config) { 681 if (projectConfig.localPropertiesPath && 682 fs.existsSync(projectConfig.localPropertiesPath) && config.cache) { 683 config.cache.buildDependencies.config.push(projectConfig.localPropertiesPath) 684 } 685 if (projectConfig.projectProfilePath && 686 fs.existsSync(projectConfig.projectProfilePath) && config.cache) { 687 config.cache.buildDependencies.config.push(projectConfig.projectProfilePath) 688 } 689} 690 691function getCleanConfig(workerFile) { 692 const cleanPath = []; 693 if (projectConfig.compileMode === 'esmodule') { 694 return cleanPath; 695 } 696 cleanPath.push(projectConfig.buildPath); 697 if (workerFile) { 698 const workerFilesPath = Object.keys(workerFile); 699 for (const workerFilePath of workerFilesPath) { 700 cleanPath.push(path.join(projectConfig.buildPath, workerFilePath, '..')); 701 } 702 } 703 return cleanPath; 704} 705 706function isPartialUpdate(metadata) { 707 if (Array.isArray(metadata) && metadata.length) { 708 metadata.some(item => { 709 if (item.name && item.name === 'ArkTSPartialUpdate' && 710 item.value && item.value === 'false') { 711 partialUpdateConfig.partialUpdateMode = false; 712 } 713 if (item.name && item.name === 'ArkTSBuilderCheck' && 714 item.value && item.value === 'false') { 715 partialUpdateConfig.builderCheck = false; 716 } 717 return !partialUpdateConfig.partialUpdateMode && !partialUpdateConfig.builderCheck; 718 }); 719 } 720} 721 722function partialUpdateController(minAPIVersion, metadata = null) { 723 if (minAPIVersion >= 9) { 724 partialUpdateConfig.partialUpdateMode = true; 725 } 726 if (metadata) { 727 isPartialUpdate(metadata); 728 } 729} 730 731const globalProgram = { 732 program: null, 733 watchProgram: null 734}; 735 736const partialUpdateConfig = { 737 partialUpdateMode: false, 738 builderCheck: true 739}; 740 741exports.globalProgram = globalProgram; 742exports.projectConfig = projectConfig; 743exports.loadEntryObj = loadEntryObj; 744exports.readAppResource = readAppResource; 745exports.resources = resources; 746exports.loadWorker = loadWorker; 747exports.abilityConfig = abilityConfig; 748exports.readWorkerFile = readWorkerFile; 749exports.abilityPagesFullPath = abilityPagesFullPath; 750exports.loadModuleInfo = loadModuleInfo; 751exports.systemModules = systemModules; 752exports.checkAppResourcePath = checkAppResourcePath; 753exports.addSDKBuildDependencies = addSDKBuildDependencies; 754exports.partialUpdateConfig = partialUpdateConfig; 755exports.readPatchConfig = readPatchConfig; 756exports.initBuildInfo = initBuildInfo; 757exports.getCleanConfig = getCleanConfig; 758