@specs-feup/kadabra
Version:
A Java source-to-source compiler written in Typescript
218 lines (199 loc) • 5.17 kB
text/typescript
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(): void {
const metrics = extract();
console.log(object2string(metrics));
}
/**
* Extracts metrics for the given packages and classes.
*
* @returns The extracted metrics report.
*/
function extract(): MetricsReport {
const report: MetricsReport = {
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: MetricsReport, typeReport: TypeReport): void {
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: Type): TypeReport {
const report: TypeReport = {
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: Method): MethodReport {
const report: MethodReport = {
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: Body, func: () => void): void {
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: Statement, func: () => void): void {
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 as Body, func);
break;
default:
break;
}
}
/**
* Metrics report type definition.
*/
interface MetricsReport {
types: Record<string, TypeReport>;
numOf: {
classes: number;
interfaces: number;
enums: number;
methods: number;
fields: number;
};
}
/**
* Type report type definition.
*/
interface TypeReport {
type: string;
name: string;
qualifiedName: string;
numOf: {
methods: number;
fields: number;
};
methods: MethodReport[];
}
/**
* Method report type definition.
*/
interface MethodReport {
type: string;
name: string;
qualifiedName: string;
numOf: {
statements: number;
};
}