@jqassistant/ts-lce
Version:
Tool to extract language concepts from a TypeScript codebase and export them to a JSON file.
162 lines (161 loc) • 7.31 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.processProjectsAndOutputResult = processProjectsAndOutputResult;
exports.processProjects = processProjects;
exports.processProject = processProject;
const typescript_estree_1 = require("@typescript-eslint/typescript-estree");
const fs = __importStar(require("fs"));
const path_1 = __importDefault(require("path"));
const cli_progress_1 = require("cli-progress");
const concept_1 = require("./concept");
const modulepath_utils_1 = require("./utils/modulepath.utils");
const ast_traverser_1 = require("./traversers/ast.traverser");
const file_utils_1 = require("./utils/file.utils");
const features_1 = require("./features");
const project_utils_1 = require("./utils/project.utils");
const project_1 = require("./project");
const log_utils_1 = require("./utils/log.utils");
async function processProjectsAndOutputResult(scanRoot, options) {
const processedProjects = await processProjects(scanRoot);
// output JSON file
const json = JSON.stringify(processedProjects.map((p) => p.toJSON()), (_, value) => {
if (typeof value === "bigint") {
return value.toString();
}
else if (typeof value === "object" && value instanceof Map) {
return Object.fromEntries(Array.from(value.entries()));
}
else {
return value;
}
}, options.prettyPrint ? 2 : undefined);
const dirPath = path_1.default.join(scanRoot, ".reports", "jqa");
const filePath = path_1.default.join(dirPath, "ts-output.json");
fs.mkdir(dirPath, { recursive: true }, (errDir) => {
if (errDir) {
console.log("Could not create directory: " + dirPath);
}
else {
fs.writeFile(filePath, json, (err) => {
if (err) {
console.log("Error writing JSON: " + err);
}
else {
console.log("JSON result successfully written to " + filePath);
}
});
}
});
}
async function processProjects(scanRoot) {
// determine projects to scan
const projects = await project_utils_1.ProjectUtils.determineProjects(scanRoot);
// process projects
const processedProjects = [];
for (let i = 0; i < projects.length; i++) {
const project = projects[i];
console.log("Processing project " + (i + 1) + " of " + projects.length);
processedProjects.push(await processProject(project));
}
// post-processing projects
console.log("Post-Processing Results...");
for (const postProcessor of features_1.POST_PROCESSORS) {
postProcessor.postProcess(processedProjects);
}
return processedProjects;
}
async function processProject(project) {
const projectNorm = project_utils_1.ProjectUtils.normalizeProjectInfo(project);
const projectRoot = project.rootPath;
const fileList = project.sourceFilePaths;
// maps filenames to the extracted concepts from these files
let concepts = new Map();
console.log("Analyzing " + fileList.length + " project files...");
const startTime = process.hrtime();
let fileReadingTime = 0;
const progressBar = new cli_progress_1.SingleBar({}, cli_progress_1.Presets.shades_classic);
if (!log_utils_1.DEBUG_LOGGING)
progressBar.start(fileList.length, 0);
// Traverse and process all individual project files
const traverser = new ast_traverser_1.AstTraverser();
for (let i = 0; i < fileList.length; i++) {
if (!log_utils_1.DEBUG_LOGGING)
progressBar.update(i + 1);
const file = fileList[i];
const frStartTime = process.hrtime();
const code = fs.readFileSync(file, "utf8");
const frEndTime = process.hrtime();
fileReadingTime += frEndTime[0] + frEndTime[1] / 10 ** 9 - (frStartTime[0] + frStartTime[1] / 10 ** 9);
try {
(0, log_utils_1.debug)(`Processing file [${i + 1}/${fileList.length}]: ${file_utils_1.FileUtils.normalizePath(modulepath_utils_1.ModulePathUtils.normalize(projectRoot, file))}`);
const { ast, services } = (0, typescript_estree_1.parseAndGenerateServices)(code, {
loc: true,
range: true,
tokens: false,
filePath: file,
project: project.configPath,
});
if (!services.program) {
continue;
}
const typeChecker = services.program.getTypeChecker();
const globalContext = {
projectInfo: projectNorm,
sourceFilePathAbsolute: file_utils_1.FileUtils.normalizePath(file),
sourceFilePathRelative: file_utils_1.FileUtils.normalizePath(modulepath_utils_1.ModulePathUtils.normalize(projectRoot, file)),
ast: ast,
services: services,
typeChecker: typeChecker,
};
concepts = (0, concept_1.mergeConceptMaps)(concepts, (0, concept_1.unifyConceptMap)(traverser.traverse(globalContext), globalContext.sourceFilePathAbsolute));
}
catch (e) {
console.log("Error occurred while processing file: " + file);
console.log(e);
}
}
if (!log_utils_1.DEBUG_LOGGING)
progressBar.stop();
const normalizedConcepts = (0, concept_1.unifyConceptMap)(concepts, "").get("") ?? new Map();
const endTime = process.hrtime();
const diffTime = endTime[0] + endTime[1] / 10 ** 9 - (startTime[0] + startTime[1] / 10 ** 9);
console.log("Finished analyzing project files.");
console.log("Runtime: " + diffTime.toFixed(3) + "s (" + fileReadingTime.toFixed(3) + "s reading files)");
return new project_1.LCEProject(project, normalizedConcepts);
}