1/* 2 * Copyright (c) 2021 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 16var path = require('path') 17var fs = require('fs') 18var shell = require('shelljs'); 19const md5 = require('md5'); 20 21const red = '\u001b[31m'; 22const reset = '\u001b[39m'; 23const multiResourceBuild = {}; 24const systemModules = []; 25 26;(function readSystemModules() { 27 const systemModulesPath = path.resolve(__dirname,'../../api'); 28 if (fs.existsSync(systemModulesPath)) { 29 systemModules.push(...fs.readdirSync(systemModulesPath)); 30 } 31})(); 32 33function deleteFolderRecursive(url) { 34 let files = []; 35 if (fs.existsSync(url)) { 36 files = fs.readdirSync(url); 37 files.forEach(function(file) { 38 const curPath = path.join(url, file); 39 if (fs.statSync(curPath).isDirectory()) { 40 deleteFolderRecursive(curPath); 41 } else { 42 fs.unlinkSync(curPath); 43 } 44 }); 45 fs.rmdir(url, function(err) {}); 46 } 47} 48 49function readManifest(manifestFilePath) { 50 let manifest = {}; 51 try { 52 if (fs.existsSync(manifestFilePath)) { 53 const jsonString = fs.readFileSync(manifestFilePath).toString(); 54 manifest = JSON.parse(jsonString); 55 } 56 } catch (e) { 57 throw Error('\u001b[31m' + 'ERROR: the manifest.json file format is invalid.' + 58 '\u001b[39m').message; 59 } 60 return manifest; 61} 62 63function loadEntryObj(projectPath, device_level, abilityType, manifestFilePath) { 64 let entryObj = {}; 65 switch (abilityType) { 66 case 'page': 67 const appJSPath = path.resolve(projectPath, 'app.js'); 68 if (device_level === 'card') { 69 entryObj = addPageEntryObj(readManifest(manifestFilePath), projectPath); 70 } else { 71 if (!fs.existsSync(appJSPath)) { 72 throw Error(red + 'ERROR: missing app.js' + reset).message; 73 } 74 entryObj['./app'] = path.resolve(projectPath, './app.js?entry'); 75 } 76 break; 77 case 'form': 78 entryObj = addPageEntryObj(readManifest(manifestFilePath), projectPath); 79 entryObj[`./${abilityType}`] = path.resolve(projectPath, `./${abilityType}.js?entry`); 80 break; 81 case 'testrunner': 82 break; 83 default: 84 entryObj[`./${abilityType}`] = path.resolve(projectPath, `./${abilityType}.js?entry`); 85 break; 86 } 87 return entryObj; 88} 89 90function addPageEntryObj(manifest, projectPath) { 91 let entryObj = {}; 92 const pages = manifest.pages; 93 if (pages === undefined) { 94 throw Error('ERROR: missing pages').message; 95 } 96 pages.forEach((element) => { 97 const sourcePath = element; 98 const hmlPath = path.join(projectPath, sourcePath + '.hml'); 99 const aceSuperVisualPath = process.env.aceSuperVisualPath || ''; 100 const visualPath = path.join(aceSuperVisualPath, sourcePath + '.visual'); 101 const isHml = fs.existsSync(hmlPath); 102 const isVisual = fs.existsSync(visualPath); 103 if (isHml && isVisual) { 104 throw Error(red + 'ERROR: ' + sourcePath + ' cannot both have hml && visual').message; 105 } else if (isHml) { 106 entryObj['./' + element] = path.resolve(projectPath, './' + sourcePath + '.hml?entry'); 107 } else if (isVisual) { 108 entryObj['./' + element] = path.resolve(aceSuperVisualPath, './' + sourcePath + 109 '.visual?entry'); 110 } 111 }) 112 return entryObj; 113} 114 115function compileCardModule(env) { 116 if (process.env.aceModuleJsonPath && fs.existsSync(process.env.aceModuleJsonPath)) { 117 const moduleJsonConfig = JSON.parse(fs.readFileSync(process.env.aceModuleJsonPath).toString()); 118 if (moduleJsonConfig.module && 119 (moduleJsonConfig.module.uiSyntax === 'ets' || moduleJsonConfig.module.language === 'ets')) { 120 process.env.DEVICE_LEVEL = 'card'; 121 } else if (validateCardModule(moduleJsonConfig) && !process.env.compileCardModule) { 122 process.env.compileCardModule = true; 123 const cmd = `webpack --config webpack.rich.config.js --env compilerType=${env.compilerType} ` + 124 `DEVICE_LEVEL=card aceModuleRoot=${process.env.projectPath} ` + 125 `aceModuleJsonPath=${process.env.aceModuleJsonPath} aceProfilePath=${process.env.aceProfilePath} ` + 126 `watchMode=${process.env.watchMode} cachePath=${process.env.cachePath} ` + 127 `aceModuleBuild=${process.env.buildPath}`; 128 shell.exec(cmd, (err) => { 129 if (err) { 130 throw Error(err).message; 131 } 132 }) 133 } 134 } 135} 136 137function validateCardModule(moduleJsonConfig) { 138 if (moduleJsonConfig.module && moduleJsonConfig.module.extensionAbilities) { 139 for (let i = 0; i < moduleJsonConfig.module.extensionAbilities.length; i++) { 140 const extensionAbility = moduleJsonConfig.module.extensionAbilities[i]; 141 if (extensionAbility.type && extensionAbility.type === 'form') { 142 return true; 143 } 144 } 145 } 146 return false; 147} 148 149function hashProjectPath(projectPath) { 150 process.env.hashProjectPath = "_" + md5(projectPath); 151} 152 153function checkMultiResourceBuild(aceBuildJson) { 154 if (aceBuildJson && fs.existsSync(aceBuildJson)) { 155 try { 156 const content = JSON.parse(fs.readFileSync(aceBuildJson)); 157 if (content["multiResourceBuild"]) { 158 multiResourceBuild.value = content["multiResourceBuild"] 159 } 160 if (content["projectRootPath"]) { 161 process.env.projectRootPath = content["projectRootPath"] 162 } 163 } catch (error) { 164 } 165 } 166} 167 168function readWorkerFile() { 169 const workerEntryObj = {}; 170 if (process.env.aceBuildJson && fs.existsSync(process.env.aceBuildJson)) { 171 const workerConfig = JSON.parse(fs.readFileSync(process.env.aceBuildJson).toString()); 172 if(workerConfig.workers) { 173 workerConfig.workers.forEach(worker => { 174 if (!/\.(js)$/.test(worker)) { 175 worker += '.js'; 176 } 177 const relativePath = path.relative(process.env.projectPath, worker); 178 if (filterWorker(relativePath)) { 179 workerEntryObj[relativePath.replace(/\.(ts|js)$/,'').replace(/\\/g, '/')] = worker; 180 } 181 }) 182 return workerEntryObj; 183 } 184 } 185 return null; 186} 187 188function filterWorker(workerPath) { 189 return /\.(ts|js)$/.test(workerPath); 190} 191 192function compareCache(cachePath) { 193 const entryFile = path.join(cachePath, 'entry.json'); 194 const cssFile = process.env.watchCSSFiles; 195 196 let files = []; 197 let cssObject = {}; 198 if (fs.existsSync(cssFile)) { 199 cssObject = JSON.parse(fs.readFileSync(cssFile)); 200 if (cssObject['clear'] === true) { 201 deleteFolderRecursive(cachePath); 202 return; 203 } 204 Object.keys(cssObject).forEach(key => { 205 if (key !== 'entry') { 206 files.push(key); 207 } 208 }) 209 } 210 211 if (fs.existsSync(entryFile)) { 212 files = files.concat(JSON.parse(fs.readFileSync(entryFile))); 213 } 214 215 for(let file of files) { 216 if (!fs.existsSync(file)) { 217 deleteFolderRecursive(cachePath); 218 break; 219 } else if (cssObject['atime'] && cssObject['atime'][file]) { 220 if (cssObject['atime'][file] !== fs.statSync(file).atime.toString()) { 221 deleteFolderRecursive(cachePath); 222 break; 223 } 224 } 225 } 226} 227 228function parseAbilityName(abilityType, projectPath) { 229 if (abilityType === 'page') { 230 return path.resolve(__dirname, projectPath, 'app.js'); 231 } else { 232 return path.resolve(__dirname, projectPath, abilityType + '.js'); 233 } 234} 235 236module.exports = { 237 deleteFolderRecursive: deleteFolderRecursive, 238 readManifest: readManifest, 239 loadEntryObj: loadEntryObj, 240 compileCardModule: compileCardModule, 241 hashProjectPath: hashProjectPath, 242 checkMultiResourceBuild: checkMultiResourceBuild, 243 multiResourceBuild: multiResourceBuild, 244 readWorkerFile: readWorkerFile, 245 compareCache: compareCache, 246 systemModules: systemModules, 247 parseAbilityName: parseAbilityName 248};