@specs-feup/kadabra
Version:
A Java source-to-source compiler written in Typescript
155 lines • 4.3 kB
JavaScript
import Query from "@specs-feup/lara/api/weaver/Query.js";
import { object2string } from "@specs-feup/lara/api/core/output.js";
import { Body, Case, Field, If, Method, Statement, Type, } from "../Joinpoints.js";
/**
* Main function to extract metrics and print the report.
*/
export default function main() {
const metrics = extract();
console.log(object2string(metrics));
}
/**
* Extracts metrics for the given packages and classes.
*
* @returns The extracted metrics report.
*/
function extract() {
const report = {
types: {},
numOf: {
classes: 0,
interfaces: 0,
enums: 0,
methods: 0,
fields: 0,
},
};
// Iterate over all types and process their metrics
for (const type of Query.search(Type)) {
mergeReports(report, reportType(type));
}
return report;
}
/**
* Merges two metrics reports.
*
* @param mainReport - The main report to merge into.
* @param typeReport - The type report to merge.
*/
function mergeReports(mainReport, typeReport) {
mainReport.types[typeReport.qualifiedName] = typeReport;
mainReport.numOf.methods += typeReport.numOf.methods;
mainReport.numOf.fields += typeReport.numOf.fields;
switch (typeReport.type) {
case "class":
mainReport.numOf.classes++;
break;
case "interface":
mainReport.numOf.interfaces++;
break;
case "enum":
mainReport.numOf.enums++;
break;
default:
console.warn(`Unknown type: ${typeReport.type}`);
break;
}
}
/**
* Generates a report for a specific type.
*
* @param type - The type join point.
* @returns The type report.
*/
function reportType(type) {
const report = {
type: type.joinPointType,
name: type.name,
qualifiedName: type.qualifiedName,
numOf: {
methods: 0,
fields: 0,
},
methods: [],
};
// Count fields
report.numOf.fields += Query.searchFrom(type, Field).get().length;
// Count methods and generate method reports
for (const method of Query.searchFrom(type, Method)) {
report.numOf.methods++;
report.methods.push(reportMethod(method));
}
return report;
}
/**
* Generates a report for a specific method.
*
* @param method - The method join point.
* @returns The method report.
*/
function reportMethod(method) {
const report = {
type: method.returnType,
name: method.name,
qualifiedName: method.toQualifiedReference,
numOf: {
statements: 0,
},
};
// Process the method body
for (const body of Query.searchFrom(method, Body)) {
processBody(body, () => {
report.numOf.statements++;
});
}
return report;
}
/**
* Processes a body join point and applies a function to each statement.
*
* @param body - The body join point.
* @param func - The function to apply to each statement.
*/
function processBody(body, func) {
for (const statement of Query.searchFrom(body, Statement)) {
processStatement(statement, func);
}
}
/**
* Processes a statement join point and applies a function to it.
*
* @param stmt - The statement join point.
* @param func - The function to apply to the statement.
*/
function processStatement(stmt, func) {
func();
switch (stmt.kind) {
case "for":
case "forEach":
for (const body of Query.searchFrom(stmt, Body)) {
processBody(body, func);
}
break;
case "if":
for (const ifStmt of Query.searchFrom(stmt, If)) {
if (ifStmt.then) {
processBody(ifStmt.then, func);
}
if (ifStmt.else) {
processBody(ifStmt.else, func);
}
}
break;
case "switch":
for (const caseStmt of Query.searchFrom(stmt, Case)) {
processStatement(caseStmt, func);
}
break;
case "case":
processBody(stmt, func);
break;
default:
break;
}
}
//# sourceMappingURL=Metrics.js.map