UNPKG

@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
"use strict"; 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); }