@jqassistant/ts-lce
Version:
Tool to extract language concepts from a TypeScript codebase and export them to a JSON file.
115 lines (114 loc) • 5.7 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ProjectUtils = void 0;
const typescript_1 = require("typescript");
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const file_utils_1 = require("./file.utils");
/**
* Utlity class that provides functionality with regard to TypeScript projects and their configurations
*/
class ProjectUtils {
/**
* Normalizes all paths contained within a `LCEProjectInfo` using `FileUtils.normalizePath`
*/
static normalizeProjectInfo(projectInfo) {
return {
rootPath: file_utils_1.FileUtils.normalizePath(projectInfo.rootPath),
configPath: file_utils_1.FileUtils.normalizePath(projectInfo.configPath),
subProjectPaths: projectInfo.subProjectPaths.map(path => file_utils_1.FileUtils.normalizePath(path)),
sourceFilePaths: projectInfo.sourceFilePaths.map(path => file_utils_1.FileUtils.normalizePath(path)),
tsConfig: projectInfo.tsConfig
};
}
/**
* Scans recursively for projects inside a given directory.
* If a project has references (via tsconfig.json) to other projects, they are also scanned (no matter if they are inside or outside the scanRoot).
* All information about scanned projects and referenced subprojects are returned in a flat array.
*/
static async determineProjects(scanRoot) {
const result = [];
const dirsToScan = [path_1.default.resolve(scanRoot)];
while (dirsToScan.length > 0) {
const projectRoot = dirsToScan[0];
const tsConfigPath = path_1.default.join(projectRoot, "tsconfig.json");
if (fs_1.default.existsSync(tsConfigPath)) {
result.push(...this.getProjectInfo(projectRoot, 'tsconfig.json'));
}
else {
// add all subdirectories as potential project candidates
fs_1.default.readdirSync(projectRoot).forEach(file => {
const subdir = path_1.default.join(projectRoot, file);
if (fs_1.default.statSync(subdir).isDirectory() &&
file !== "node_modules") {
dirsToScan.push(subdir);
}
});
}
dirsToScan.splice(0, 1);
}
// filter out duplicates
const seen = [];
return result.filter(pi => {
if (seen.includes(pi.configPath)) {
return false;
}
else {
seen.push(pi.configPath);
return true;
}
});
}
static getConfigFileName(rawConfigPath) {
const pathIsADirectory = fs_1.default.statSync(rawConfigPath).isDirectory();
const defaultConfigFileName = 'tsconfig.json';
return pathIsADirectory ? path_1.default.join(rawConfigPath, defaultConfigFileName) : rawConfigPath;
}
static getProjectInfo(projectPath, configFileName) {
const result = [];
const tsConfig = this.parseTsConfig(projectPath, configFileName);
const subProjectPaths = [];
if (tsConfig.projectReferences) {
for (const ref of tsConfig.projectReferences) {
const referencedConfigFileName = this.getConfigFileName(ref.path);
const subProjectInfos = this.getProjectInfo(path_1.default.dirname(referencedConfigFileName), path_1.default.basename(referencedConfigFileName));
subProjectPaths.push(...subProjectInfos.map(spi => file_utils_1.FileUtils.normalizePath(spi.configPath)));
result.push(...subProjectInfos);
}
}
let rootPath = projectPath;
// if project root is descendant of configured root directory use the configured one
if (path_1.default.resolve(projectPath).startsWith(path_1.default.resolve(projectPath, tsConfig.options.rootDir))) {
rootPath = path_1.default.resolve(projectPath, tsConfig.options.rootDir);
}
result.push({
rootPath: file_utils_1.FileUtils.normalizePath(rootPath),
configPath: file_utils_1.FileUtils.normalizePath(path_1.default.join(projectPath, configFileName)),
subProjectPaths: subProjectPaths,
sourceFilePaths: tsConfig.fileNames.map(fn => file_utils_1.FileUtils.normalizePath(fn)),
tsConfig
});
return result;
}
static parseTsConfig(projectRoot, configFile) {
const tsConfigPath = path_1.default.join(projectRoot, configFile);
const configFileText = fs_1.default.readFileSync(tsConfigPath, 'utf8');
const configFileSourceFile = (0, typescript_1.createSourceFile)(configFile, configFileText, typescript_1.ScriptTarget.JSON);
// Parse the tsconfig.json
const parsedCommandLine = (0, typescript_1.parseJsonSourceFileConfigFileContent)(configFileSourceFile, typescript_1.sys, path_1.default.dirname(tsConfigPath));
// explicitly set rootDir option to default value, if not set manually
if (!parsedCommandLine.options.rootDir) {
if (parsedCommandLine.options.composite || parsedCommandLine.fileNames.length === 0) {
parsedCommandLine.options.rootDir = projectRoot;
}
else {
parsedCommandLine.options.rootDir = file_utils_1.FileUtils.commonDir(parsedCommandLine.fileNames);
}
}
return parsedCommandLine;
}
}
exports.ProjectUtils = ProjectUtils;