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