16a23e08bSopenharmony_ci/*
26a23e08bSopenharmony_ci * Copyright (c) 2021 Huawei Device Co., Ltd.
36a23e08bSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
46a23e08bSopenharmony_ci * you may not use this file except in compliance with the License.
56a23e08bSopenharmony_ci * You may obtain a copy of the License at
66a23e08bSopenharmony_ci *
76a23e08bSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
86a23e08bSopenharmony_ci *
96a23e08bSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
106a23e08bSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
116a23e08bSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
126a23e08bSopenharmony_ci * See the License for the specific language governing permissions and
136a23e08bSopenharmony_ci * limitations under the License.
146a23e08bSopenharmony_ci */
156a23e08bSopenharmony_ci
166a23e08bSopenharmony_civar path = require('path')
176a23e08bSopenharmony_civar fs = require('fs')
186a23e08bSopenharmony_civar shell = require('shelljs');
196a23e08bSopenharmony_ciconst crypto = require("crypto")
206a23e08bSopenharmony_ci
216a23e08bSopenharmony_ciconst red = '\u001b[31m';
226a23e08bSopenharmony_ciconst reset = '\u001b[39m';
236a23e08bSopenharmony_ciconst multiResourceBuild = {};
246a23e08bSopenharmony_ciconst systemModules = [];
256a23e08bSopenharmony_ci
266a23e08bSopenharmony_ci;(function readSystemModules() {
276a23e08bSopenharmony_ci  const systemModulesPath = path.resolve(__dirname,'../../api');
286a23e08bSopenharmony_ci  if (fs.existsSync(systemModulesPath)) {
296a23e08bSopenharmony_ci    systemModules.push(...fs.readdirSync(systemModulesPath));
306a23e08bSopenharmony_ci  }
316a23e08bSopenharmony_ci})();
326a23e08bSopenharmony_ci
336a23e08bSopenharmony_cifunction deleteFolderRecursive(url) {
346a23e08bSopenharmony_ci  let files = [];
356a23e08bSopenharmony_ci  if (fs.existsSync(url)) {
366a23e08bSopenharmony_ci    files = fs.readdirSync(url);
376a23e08bSopenharmony_ci    files.forEach(function(file) {
386a23e08bSopenharmony_ci      const curPath = path.join(url, file);
396a23e08bSopenharmony_ci      if (fs.statSync(curPath).isDirectory()) {
406a23e08bSopenharmony_ci        deleteFolderRecursive(curPath);
416a23e08bSopenharmony_ci      } else {
426a23e08bSopenharmony_ci        fs.unlinkSync(curPath);
436a23e08bSopenharmony_ci      }
446a23e08bSopenharmony_ci    });
456a23e08bSopenharmony_ci    fs.rmdir(url, function(err) {});
466a23e08bSopenharmony_ci  }
476a23e08bSopenharmony_ci}
486a23e08bSopenharmony_ci
496a23e08bSopenharmony_cifunction readManifest(manifestFilePath) {
506a23e08bSopenharmony_ci  let manifest = {};
516a23e08bSopenharmony_ci  try {
526a23e08bSopenharmony_ci    if (fs.existsSync(manifestFilePath)) {
536a23e08bSopenharmony_ci      const jsonString = fs.readFileSync(manifestFilePath).toString();
546a23e08bSopenharmony_ci      manifest = JSON.parse(jsonString);
556a23e08bSopenharmony_ci    }
566a23e08bSopenharmony_ci  } catch (e) {
576a23e08bSopenharmony_ci    throw Error('\u001b[31m' + 'ERROR: the manifest.json file format is invalid.' +
586a23e08bSopenharmony_ci      '\u001b[39m').message;
596a23e08bSopenharmony_ci  }
606a23e08bSopenharmony_ci  return manifest;
616a23e08bSopenharmony_ci}
626a23e08bSopenharmony_ci
636a23e08bSopenharmony_cifunction loadEntryObj(projectPath, device_level, abilityType, manifestFilePath) {
646a23e08bSopenharmony_ci  let entryObj = {};
656a23e08bSopenharmony_ci  switch (abilityType) {
666a23e08bSopenharmony_ci    case 'page':
676a23e08bSopenharmony_ci      const appJSPath = path.resolve(projectPath, 'app.js');
686a23e08bSopenharmony_ci      if (device_level === 'card') {
696a23e08bSopenharmony_ci        entryObj = addPageEntryObj(readManifest(manifestFilePath), projectPath);
706a23e08bSopenharmony_ci      } else {
716a23e08bSopenharmony_ci        if (!fs.existsSync(appJSPath)) {
726a23e08bSopenharmony_ci          throw Error(red + 'ERROR: missing app.js' + reset).message;
736a23e08bSopenharmony_ci        }
746a23e08bSopenharmony_ci        entryObj['./app'] = path.resolve(projectPath, './app.js?entry');
756a23e08bSopenharmony_ci      }
766a23e08bSopenharmony_ci      break;
776a23e08bSopenharmony_ci    case 'form':
786a23e08bSopenharmony_ci      entryObj = addPageEntryObj(readManifest(manifestFilePath), projectPath);
796a23e08bSopenharmony_ci      entryObj[`./${abilityType}`] =  path.resolve(projectPath, `./${abilityType}.js?entry`);
806a23e08bSopenharmony_ci      break;
816a23e08bSopenharmony_ci    case 'testrunner':
826a23e08bSopenharmony_ci      break;
836a23e08bSopenharmony_ci    default:
846a23e08bSopenharmony_ci      entryObj[`./${abilityType}`] =  path.resolve(projectPath, `./${abilityType}.js?entry`);
856a23e08bSopenharmony_ci      break;
866a23e08bSopenharmony_ci  }
876a23e08bSopenharmony_ci  return entryObj;
886a23e08bSopenharmony_ci}
896a23e08bSopenharmony_ci
906a23e08bSopenharmony_cifunction addPageEntryObj(manifest, projectPath) {
916a23e08bSopenharmony_ci  let entryObj = {};
926a23e08bSopenharmony_ci  const pages = manifest.pages;
936a23e08bSopenharmony_ci  if (pages === undefined) {
946a23e08bSopenharmony_ci    throw Error('ERROR: missing pages').message;
956a23e08bSopenharmony_ci  }
966a23e08bSopenharmony_ci  pages.forEach((element) => {
976a23e08bSopenharmony_ci    const sourcePath = element;
986a23e08bSopenharmony_ci    const hmlPath = path.join(projectPath, sourcePath + '.hml');
996a23e08bSopenharmony_ci    const aceSuperVisualPath = process.env.aceSuperVisualPath || '';
1006a23e08bSopenharmony_ci    const visualPath = path.join(aceSuperVisualPath, sourcePath + '.visual');
1016a23e08bSopenharmony_ci    const isHml = fs.existsSync(hmlPath);
1026a23e08bSopenharmony_ci    const isVisual = fs.existsSync(visualPath);
1036a23e08bSopenharmony_ci    if (isHml && isVisual) {
1046a23e08bSopenharmony_ci      throw Error(red + 'ERROR: ' + sourcePath + ' cannot both have hml && visual').message;
1056a23e08bSopenharmony_ci    } else if (isHml) {
1066a23e08bSopenharmony_ci      entryObj['./' + element] = path.resolve(projectPath, './' + sourcePath + '.hml?entry');
1076a23e08bSopenharmony_ci    } else if (isVisual) {
1086a23e08bSopenharmony_ci      entryObj['./' + element] = path.resolve(aceSuperVisualPath, './' + sourcePath +
1096a23e08bSopenharmony_ci        '.visual?entry');
1106a23e08bSopenharmony_ci    }
1116a23e08bSopenharmony_ci  })
1126a23e08bSopenharmony_ci  return entryObj;
1136a23e08bSopenharmony_ci}
1146a23e08bSopenharmony_ci
1156a23e08bSopenharmony_cifunction compileCardModule(env) {
1166a23e08bSopenharmony_ci  if (process.env.aceModuleJsonPath && fs.existsSync(process.env.aceModuleJsonPath)) {
1176a23e08bSopenharmony_ci    const moduleJsonConfig = JSON.parse(fs.readFileSync(process.env.aceModuleJsonPath).toString());
1186a23e08bSopenharmony_ci    if (moduleJsonConfig.module &&
1196a23e08bSopenharmony_ci      (moduleJsonConfig.module.uiSyntax === 'ets' || moduleJsonConfig.module.language === 'ets')) {
1206a23e08bSopenharmony_ci      process.env.DEVICE_LEVEL = 'card';
1216a23e08bSopenharmony_ci    } else if (validateCardModule(moduleJsonConfig) && !process.env.compileCardModule) {
1226a23e08bSopenharmony_ci      process.env.compileCardModule = true;
1236a23e08bSopenharmony_ci      const cmd = `webpack --config webpack.rich.config.js --env compilerType=${env.compilerType} ` +
1246a23e08bSopenharmony_ci        `DEVICE_LEVEL=card aceModuleRoot=${process.env.projectPath} ` +
1256a23e08bSopenharmony_ci        `aceModuleJsonPath=${process.env.aceModuleJsonPath} aceProfilePath=${process.env.aceProfilePath} ` +
1266a23e08bSopenharmony_ci        `watchMode=${process.env.watchMode} cachePath=${process.env.cachePath} ` +
1276a23e08bSopenharmony_ci        `aceModuleBuild=${process.env.buildPath}`;
1286a23e08bSopenharmony_ci      shell.exec(cmd, (err) => {
1296a23e08bSopenharmony_ci        if (err) {
1306a23e08bSopenharmony_ci          throw Error(err).message;
1316a23e08bSopenharmony_ci        }
1326a23e08bSopenharmony_ci      })
1336a23e08bSopenharmony_ci    }
1346a23e08bSopenharmony_ci  }
1356a23e08bSopenharmony_ci}
1366a23e08bSopenharmony_ci
1376a23e08bSopenharmony_cifunction validateCardModule(moduleJsonConfig) {
1386a23e08bSopenharmony_ci  if (moduleJsonConfig.module && moduleJsonConfig.module.extensionAbilities) {
1396a23e08bSopenharmony_ci    for (let i = 0; i < moduleJsonConfig.module.extensionAbilities.length; i++) {
1406a23e08bSopenharmony_ci      const extensionAbility = moduleJsonConfig.module.extensionAbilities[i];
1416a23e08bSopenharmony_ci      if (extensionAbility.type && extensionAbility.type === 'form') {
1426a23e08bSopenharmony_ci        return true;
1436a23e08bSopenharmony_ci      }
1446a23e08bSopenharmony_ci    }
1456a23e08bSopenharmony_ci  }
1466a23e08bSopenharmony_ci  return false;
1476a23e08bSopenharmony_ci}
1486a23e08bSopenharmony_ci
1496a23e08bSopenharmony_cifunction hashProjectPath(projectPath) {
1506a23e08bSopenharmony_ci  const hash = crypto.createHash('sha256')
1516a23e08bSopenharmony_ci  hash.update(projectPath.toString())
1526a23e08bSopenharmony_ci  process.env.hashProjectPath = "_" + hash.digest('hex');
1536a23e08bSopenharmony_ci}
1546a23e08bSopenharmony_ci
1556a23e08bSopenharmony_cifunction checkMultiResourceBuild(aceBuildJson) {
1566a23e08bSopenharmony_ci  if (aceBuildJson && fs.existsSync(aceBuildJson)) {
1576a23e08bSopenharmony_ci    try {
1586a23e08bSopenharmony_ci      const content = JSON.parse(fs.readFileSync(aceBuildJson));
1596a23e08bSopenharmony_ci      if (content["multiResourceBuild"]) {
1606a23e08bSopenharmony_ci        multiResourceBuild.value = content["multiResourceBuild"]
1616a23e08bSopenharmony_ci      }
1626a23e08bSopenharmony_ci      if (content["projectRootPath"]) {
1636a23e08bSopenharmony_ci        process.env.projectRootPath = content["projectRootPath"]
1646a23e08bSopenharmony_ci      }
1656a23e08bSopenharmony_ci    } catch (error) {
1666a23e08bSopenharmony_ci    }
1676a23e08bSopenharmony_ci  }
1686a23e08bSopenharmony_ci}
1696a23e08bSopenharmony_ci
1706a23e08bSopenharmony_cifunction readWorkerFile() {
1716a23e08bSopenharmony_ci  const workerEntryObj = {};
1726a23e08bSopenharmony_ci  if (process.env.aceBuildJson && fs.existsSync(process.env.aceBuildJson)) {
1736a23e08bSopenharmony_ci    const workerConfig = JSON.parse(fs.readFileSync(process.env.aceBuildJson).toString());
1746a23e08bSopenharmony_ci    if(workerConfig.workers) {
1756a23e08bSopenharmony_ci      workerConfig.workers.forEach(worker => {
1766a23e08bSopenharmony_ci        if (!/\.(js)$/.test(worker)) {
1776a23e08bSopenharmony_ci          worker += '.js';
1786a23e08bSopenharmony_ci        }
1796a23e08bSopenharmony_ci        const relativePath = path.relative(process.env.projectPath, worker);
1806a23e08bSopenharmony_ci        if (filterWorker(relativePath)) {
1816a23e08bSopenharmony_ci          workerEntryObj[relativePath.replace(/\.(ts|js)$/,'').replace(/\\/g, '/')] = worker;
1826a23e08bSopenharmony_ci        }
1836a23e08bSopenharmony_ci      })
1846a23e08bSopenharmony_ci      return workerEntryObj;
1856a23e08bSopenharmony_ci    }
1866a23e08bSopenharmony_ci  }
1876a23e08bSopenharmony_ci  return null;
1886a23e08bSopenharmony_ci}
1896a23e08bSopenharmony_ci
1906a23e08bSopenharmony_cifunction filterWorker(workerPath) {
1916a23e08bSopenharmony_ci  return /\.(ts|js)$/.test(workerPath);
1926a23e08bSopenharmony_ci}
1936a23e08bSopenharmony_ci
1946a23e08bSopenharmony_cifunction compareCache(cachePath) {
1956a23e08bSopenharmony_ci  const entryFile = path.join(cachePath, 'entry.json');
1966a23e08bSopenharmony_ci  const cssFile = process.env.watchCSSFiles;
1976a23e08bSopenharmony_ci
1986a23e08bSopenharmony_ci  let files = [];
1996a23e08bSopenharmony_ci  let cssObject = {};
2006a23e08bSopenharmony_ci  if (fs.existsSync(cssFile)) {
2016a23e08bSopenharmony_ci    cssObject = JSON.parse(fs.readFileSync(cssFile));
2026a23e08bSopenharmony_ci    if (cssObject['clear'] === true) {
2036a23e08bSopenharmony_ci      deleteFolderRecursive(cachePath);
2046a23e08bSopenharmony_ci      return;
2056a23e08bSopenharmony_ci    }
2066a23e08bSopenharmony_ci    Object.keys(cssObject).forEach(key => {
2076a23e08bSopenharmony_ci      if (key !== 'entry') {
2086a23e08bSopenharmony_ci        files.push(key);
2096a23e08bSopenharmony_ci      }
2106a23e08bSopenharmony_ci    })
2116a23e08bSopenharmony_ci  }
2126a23e08bSopenharmony_ci
2136a23e08bSopenharmony_ci  if (fs.existsSync(entryFile)) {
2146a23e08bSopenharmony_ci    files = files.concat(JSON.parse(fs.readFileSync(entryFile)));
2156a23e08bSopenharmony_ci  }
2166a23e08bSopenharmony_ci
2176a23e08bSopenharmony_ci  for(let file of files) {
2186a23e08bSopenharmony_ci    if (!fs.existsSync(file)) {
2196a23e08bSopenharmony_ci      deleteFolderRecursive(cachePath);
2206a23e08bSopenharmony_ci      break;
2216a23e08bSopenharmony_ci    } else if (cssObject['atime'] && cssObject['atime'][file]) {
2226a23e08bSopenharmony_ci      if (cssObject['atime'][file] !== fs.statSync(file).atime.toString()) {
2236a23e08bSopenharmony_ci        deleteFolderRecursive(cachePath);
2246a23e08bSopenharmony_ci        break;
2256a23e08bSopenharmony_ci      }
2266a23e08bSopenharmony_ci    }
2276a23e08bSopenharmony_ci  }
2286a23e08bSopenharmony_ci}
2296a23e08bSopenharmony_ci
2306a23e08bSopenharmony_cifunction parseAbilityName(abilityType, projectPath) {
2316a23e08bSopenharmony_ci  if (abilityType === 'page') {
2326a23e08bSopenharmony_ci    return path.resolve(__dirname, projectPath, 'app.js');
2336a23e08bSopenharmony_ci  } else {
2346a23e08bSopenharmony_ci    return path.resolve(__dirname, projectPath, abilityType + '.js');
2356a23e08bSopenharmony_ci  }
2366a23e08bSopenharmony_ci}
2376a23e08bSopenharmony_ci
2386a23e08bSopenharmony_cimodule.exports = {
2396a23e08bSopenharmony_ci  deleteFolderRecursive: deleteFolderRecursive,
2406a23e08bSopenharmony_ci  readManifest: readManifest,
2416a23e08bSopenharmony_ci  loadEntryObj: loadEntryObj,
2426a23e08bSopenharmony_ci  compileCardModule: compileCardModule,
2436a23e08bSopenharmony_ci  hashProjectPath: hashProjectPath,
2446a23e08bSopenharmony_ci  checkMultiResourceBuild: checkMultiResourceBuild,
2456a23e08bSopenharmony_ci  multiResourceBuild: multiResourceBuild,
2466a23e08bSopenharmony_ci  readWorkerFile: readWorkerFile,
2476a23e08bSopenharmony_ci  compareCache: compareCache,
2486a23e08bSopenharmony_ci  systemModules: systemModules,
2496a23e08bSopenharmony_ci  parseAbilityName: parseAbilityName
2506a23e08bSopenharmony_ci};