providence-analytics
Version:
Providence is the 'All Seeing Eye' that measures effectivity and popularity of software. Release management will become highly efficient due to an accurate impact analysis of (breaking) changes
132 lines (120 loc) • 4.55 kB
JavaScript
import path from 'path';
import { hash } from '../utils/hash.js';
import { fsAdapter } from '../utils/fs-adapter.js';
/**
* @typedef {import('../../../types/index.js').AnalyzerQueryResult} AnalyzerQueryResult
* @typedef {import('../../../types/index.js').PathFromSystemRoot} PathFromSystemRoot
* @typedef {import('../../../types/index.js').AnalyzerConfig} AnalyzerConfig
* @typedef {import('../../../types/index.js').AnalyzerName} AnalyzerName
* @typedef {import('../../../types/index.js').ProjectName} ProjectName
* @typedef {import('../../../types/index.js').QueryResult} QueryResult
* @typedef {import('../../../types/index.js').Project} Project
*/
/**
* Should be used to write results to and read results from the file system.
* Creates a unique identifier based on searchP, refP (optional) and an already created
* @param {Project} searchP search target project meta
* @param {AnalyzerConfig} cfg configuration used for analyzer
* @param {Project} [refP] reference project meta
* @returns {string} identifier
*/
function createResultIdentifier(searchP, cfg, refP) {
// why encodeURIComponent: filters out slashes for path names for stuff like @lion/button
const format = (/** @type {Project} */ p) =>
`${encodeURIComponent(p.name)}_${p.version || (p.commitHash && p.commitHash.slice(0, 5))}`;
const cfgHash = hash(cfg);
return `${format(searchP)}${refP ? `_+_${format(refP)}` : ''}__${cfgHash}`;
}
export class ReportService {
/**
* Prints queryResult report to console
* @param {QueryResult} queryResult
*/
static printToConsole(queryResult) {
/* eslint-disable no-console */
console.log('== QUERY: =========');
console.log(JSON.stringify(queryResult.meta, null, 2));
console.log('\n== RESULT: =========');
console.log(JSON.stringify(queryResult.queryOutput, null, 2));
console.log('\n----------------------------------------\n');
/* eslint-enable no-console */
}
/**
* Prints queryResult report as JSON to outputPath
* @param {AnalyzerQueryResult} queryResult
* @param {string} [identifier]
* @param {string} [outputPath]
*/
static writeToJson(
queryResult,
identifier = (new Date().getTime() / 1000).toString(),
outputPath = this.outputPath,
) {
const output = JSON.stringify(queryResult, null, 2);
if (!fsAdapter.fs.existsSync(outputPath)) {
fsAdapter.fs.mkdirSync(outputPath);
}
const { name } = queryResult.meta.analyzerMeta;
const filePath = this._getResultFileNameAndPath(name, identifier);
fsAdapter.fs.writeFileSync(filePath, output, { flag: 'w' });
}
/**
* @type {string}
*/
static get outputPath() {
return this.__outputPath || path.join(process.cwd(), '/providence-output');
}
static set outputPath(p) {
this.__outputPath = p;
}
/**
* @param {{ targetProject: Project; referenceProject: Project; analyzerConfig: AnalyzerConfig }} options
* @returns {string}
*/
static createIdentifier({ targetProject, referenceProject, analyzerConfig }) {
return createResultIdentifier(targetProject, analyzerConfig, referenceProject);
}
/**
* @param {{analyzerName: AnalyzerName; identifier: string}} options
* @returns {QueryResult}
*/
static getCachedResult({ analyzerName, identifier }) {
let cachedResult;
try {
cachedResult = JSON.parse(
fsAdapter.fs.readFileSync(
this._getResultFileNameAndPath(analyzerName, identifier),
'utf-8',
),
);
// eslint-disable-next-line no-empty
} catch (_) {}
return cachedResult;
}
/**
* @param {string} name
* @param {string} identifier
* @returns {PathFromSystemRoot}
*/
static _getResultFileNameAndPath(name, identifier) {
return /** @type {PathFromSystemRoot} */ (
path.join(this.outputPath, `${name || 'query'}_-_${identifier}.json`)
);
}
/**
* @param {ProjectName} depProj
* @param {Project} rootProjectMeta
*/
static writeEntryToSearchTargetDepsFile(depProj, rootProjectMeta) {
const rootProj = `${rootProjectMeta.name}#${rootProjectMeta.version}`;
const filePath = path.join(this.outputPath, 'search-target-deps-file.json');
let file = {};
try {
file = JSON.parse(fsAdapter.fs.readFileSync(filePath, 'utf-8'));
// eslint-disable-next-line no-empty
} catch (_) {}
const deps = [...(file[rootProj] || []), depProj];
file[rootProj] = [...new Set(deps)];
fsAdapter.fs.writeFileSync(filePath, JSON.stringify(file, null, 2), { flag: 'w' });
}
}