const fs = require('fs'); const pathLib = require('path'); const { createConfig, startServer } = require('es-dev-server'); const { ReportService } = require('../../src/program/services/ReportService.js'); const { LogService } = require('../../src/program/services/LogService.js'); // eslint-disable-next-line import/no-dynamic-require const providenceConf = require(`${pathLib.join(process.cwd(), 'providence.conf.js')}`); let outputFilePaths; try { outputFilePaths = fs.readdirSync(ReportService.outputPath); } catch (_) { LogService.error( `Please make sure providence results can be found in ${ReportService.outputPath}`, ); process.exit(1); } const resultFiles = {}; let searchTargetDeps; const supportedAnalyzers = ['match-imports', 'match-subclasses']; outputFilePaths.forEach(fileName => { const content = JSON.parse( fs.readFileSync(pathLib.join(ReportService.outputPath, fileName), 'utf-8'), ); if (fileName === 'search-target-deps-file.json') { searchTargetDeps = content; } else { const analyzerName = fileName.split('_-_')[0]; if (!supportedAnalyzers.includes(analyzerName)) { return; } if (!resultFiles[analyzerName]) { resultFiles[analyzerName] = []; } resultFiles[analyzerName].push({ fileName, content }); } }); function getPackageJson(projectPath) { let pkgJson; try { const file = pathLib.resolve(projectPath, 'package.json'); pkgJson = JSON.parse(fs.readFileSync(file, 'utf8')); } catch (_) { // eslint-disable-next-line no-empty } return pkgJson; } function transformToProjectNames(collections) { const res = {}; // eslint-disable-next-line array-callback-return Object.entries(collections).map(([key, val]) => { res[key] = val.map(c => { const pkg = getPackageJson(c); return pkg && pkg.name; }); }); return res; } const pathFromServerRootToHere = `/${pathLib.relative(process.cwd(), __dirname)}`; // Needed for dev purposes (we call it from ./packages/providence-analytics/ instead of ./) // Allows es-dev-server to find the right moduleDirs const fromPackageRoot = process.argv.includes('--serve-from-package-root'); const moduleRoot = fromPackageRoot ? pathLib.resolve(process.cwd(), '../../') : process.cwd(); const config = createConfig({ port: 8080, appIndex: pathLib.resolve(__dirname, 'index.html'), rootDir: moduleRoot, nodeResolve: true, moduleDirs: pathLib.resolve(moduleRoot, 'node_modules'), watch: false, open: true, middlewares: [ // eslint-disable-next-line consistent-return async (ctx, next) => { // TODO: Quick and dirty solution: refactor in a nicer way if (ctx.url.startsWith('/app')) { ctx.url = `${pathFromServerRootToHere}/${ctx.url}`; return next(); } if (ctx.url === '/') { ctx.url = `${pathFromServerRootToHere}/index.html`; return next(); } if (ctx.url === '/results') { ctx.body = resultFiles; } else if (ctx.url === '/menu-data') { // Gathers all data that are relevant to create a configuration menu // at the top of the dashboard: // - referenceCollections as defined in providence.conf.js // - searchTargetCollections (aka programs) as defined in providence.conf.js // - searchTargetDeps as found in search-target-deps-file.json // Also do some processing on the presentation of a project, so that it can be easily // outputted in frontend let searchTargetCollections; if (providenceConf.searchTargetCollections) { searchTargetCollections = transformToProjectNames(providenceConf.searchTargetCollections); } else { searchTargetCollections = Object.keys(searchTargetDeps).map(d => d.split('#')[0]); } const menuData = { // N.B. theoratically there can be a mismatch between basename and pkgJson.name, // but we assume folder names and pkgJson.names to be similar searchTargetCollections, referenceCollections: transformToProjectNames(providenceConf.referenceCollections), searchTargetDeps, }; ctx.body = menuData; } else if (ctx.url === '/providence.conf.js') { // We need to fetch it via server, since it's CommonJS vs es modules... // require("@babel/core").transform("code", { // plugins: ["@babel/plugin-transform-modules-commonjs"] // }); // Gives back categories from providence.conf ctx.body = providenceConf.metaConfig; } else { await next(); } }, ], }); (async () => { await startServer(config); })();