@nexica/nestjs-trpc
Version:
NestJS TRPC Bridge
261 lines • 12.7 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.FileScanner = void 0;
const fs = require("fs");
const path = require("path");
const glob = require("glob");
const ts_morph_1 = require("ts-morph");
const error_handler_1 = require("./error-handler");
class FileScanner {
static findFiles(directory, pattern) {
return glob.sync(pattern, { cwd: directory, absolute: true });
}
static findTypeScriptFiles(directory) {
return this.findFiles(directory, '**/*.{ts,tsx}');
}
static findTsConfigFile(directory) {
let currentDir = directory;
while (currentDir !== path.parse(currentDir).root) {
const tsConfigPath = path.join(currentDir, 'tsconfig.json');
if (fs.existsSync(tsConfigPath)) {
return tsConfigPath;
}
currentDir = path.dirname(currentDir);
}
return null;
}
static getCallerFilePath() {
var _a, _b;
const originalStackPrepareStackTrace = (_a = Error.prepareStackTrace) === null || _a === void 0 ? void 0 : _a.bind(Error);
Error.prepareStackTrace = (_, stack) => stack;
const stack = new Error().stack;
Error.prepareStackTrace = originalStackPrepareStackTrace;
const callerFile = ((_b = stack[2]) === null || _b === void 0 ? void 0 : _b.getFileName()) || '';
return callerFile;
}
static findProjectRoot(startDir = process.cwd()) {
let dir = startDir;
const maxIterations = 10;
let iterations = 0;
while (dir !== path.parse(dir).root && iterations < maxIterations) {
if (fs.existsSync(path.join(dir, 'package.json')) || fs.existsSync(path.join(dir, 'tsconfig.json'))) {
return dir;
}
const parentDir = path.dirname(dir);
if (parentDir === dir) {
break;
}
dir = parentDir;
iterations++;
}
error_handler_1.ErrorHandler.logWarning('FileScanner', `Could not find project root, using ${startDir} as fallback`);
return startDir;
}
static getTsEquivalentPath(filePath) {
return filePath.replace('\\dist\\', '\\src\\').replace('.js', '.ts');
}
static getInputAndOutputNamesFromDecorator(filePath, methodName) {
var _a, _b, _c;
const tsPath = this.getTsEquivalentPath(filePath);
if (!fs.existsSync(tsPath)) {
return { input: undefined, output: undefined };
}
const project = new ts_morph_1.Project({
compilerOptions: {
target: ts_morph_1.ts.ScriptTarget.ES2019,
module: ts_morph_1.ts.ModuleKind.CommonJS,
emitDecoratorMetadata: true,
experimentalDecorators: true,
},
});
const sourceFile = project.addSourceFileAtPath(tsPath);
const classes = sourceFile.getClasses();
for (const classDeclaration of classes) {
const method = classDeclaration.getMethod(methodName);
if (!method)
continue;
let queryDecorator = method.getDecorator('Query');
if (!queryDecorator)
queryDecorator = method.getDecorator('Mutation');
if (!queryDecorator)
continue;
const args = queryDecorator.getArguments();
if (args.length === 0)
continue;
const objLiteral = args[0];
if (!objLiteral || !objLiteral.asKind(ts_morph_1.ts.SyntaxKind.ObjectLiteralExpression))
continue;
const properties = (_a = objLiteral.asKind(ts_morph_1.ts.SyntaxKind.ObjectLiteralExpression)) === null || _a === void 0 ? void 0 : _a.getProperties();
if (!properties)
continue;
let inputName;
let outputName;
for (const prop of properties) {
const propName = (_b = prop.getChildrenOfKind(ts_morph_1.ts.SyntaxKind.Identifier)[0]) === null || _b === void 0 ? void 0 : _b.getText();
if (propName === 'input') {
inputName = (_c = prop.getChildrenOfKind(ts_morph_1.ts.SyntaxKind.Identifier)[1]) === null || _c === void 0 ? void 0 : _c.getText();
}
else if (propName === 'output') {
const initializer = prop.getLastChild();
outputName = initializer === null || initializer === void 0 ? void 0 : initializer.getText();
}
}
return { input: inputName, output: outputName };
}
return { input: undefined, output: undefined };
}
static resolvePathWithAliases(filePath, pathAliases, tsConfigDir, moduleCallerFilePath) {
if (path.isAbsolute(filePath) || filePath.startsWith('./') || filePath.startsWith('../')) {
const resolvedPath = path.resolve(tsConfigDir, filePath);
return resolvedPath;
}
if (filePath.startsWith('@/')) {
for (const [alias, targets] of Object.entries(pathAliases)) {
if ((alias === '@/*' || alias === '@*') && targets.length > 0) {
const target = targets[0].replace(/\*/g, '');
const modulePath = filePath.replace('@/', '');
const resolvedPath = path.resolve(tsConfigDir, target, modulePath);
if (fs.existsSync(resolvedPath)) {
return resolvedPath;
}
}
}
if (moduleCallerFilePath) {
const commonSourceFolders = [
moduleCallerFilePath,
path.join(moduleCallerFilePath, 'src'),
path.join(moduleCallerFilePath, 'app'),
path.join(moduleCallerFilePath, 'lib'),
];
for (const srcFolder of commonSourceFolders) {
if (fs.existsSync(srcFolder)) {
const modulePath = filePath.replace('@/', '');
const resolvedPath = path.resolve(srcFolder, modulePath);
if (fs.existsSync(resolvedPath)) {
return resolvedPath;
}
}
}
}
}
for (const [alias, targets] of Object.entries(pathAliases)) {
const aliasPattern = alias.replace(/\*/g, '(.+)');
const aliasRegex = new RegExp(`^${aliasPattern}$`);
if (aliasRegex.test(filePath)) {
if (targets.length > 0) {
const target = targets[0];
const processed = filePath.replace(aliasRegex, (_, capture) => {
return target.replace(/\*/g, capture);
});
const resolvedPath = path.resolve(tsConfigDir, processed);
return resolvedPath;
}
}
}
if (!filePath.includes('/') && !filePath.includes('\\')) {
try {
const resolvedPath = require.resolve(filePath, { paths: [process.cwd(), tsConfigDir] });
return resolvedPath;
}
catch (e) {
error_handler_1.ErrorHandler.logWarning('FileScanner', `Could not resolve module: ${filePath}`);
}
}
if (filePath.endsWith('.ts') || filePath.endsWith('.js')) {
const projectRootPath = path.resolve(process.cwd(), filePath);
if (fs.existsSync(projectRootPath)) {
return projectRootPath;
}
const tsConfigRelativePath = path.resolve(tsConfigDir, filePath);
if (fs.existsSync(tsConfigRelativePath)) {
return tsConfigRelativePath;
}
const srcPath = path.resolve(process.cwd(), 'src', filePath);
if (fs.existsSync(srcPath)) {
return srcPath;
}
}
error_handler_1.ErrorHandler.logWarning('FileScanner', `Could not resolve path with aliases, returning as is: ${filePath}`);
return filePath;
}
static injectFilesContent(filePaths, sourceFile, moduleCallerFilePath) {
var _a;
try {
const tsConfigFilePath = FileScanner.findTsConfigFile(moduleCallerFilePath);
if (tsConfigFilePath) {
const tsConfigContent = fs.readFileSync(tsConfigFilePath, 'utf8');
try {
const tsConfigObj = JSON.parse(tsConfigContent);
const pathAliases = ((_a = tsConfigObj.compilerOptions) === null || _a === void 0 ? void 0 : _a.paths) || {};
const tsConfigDir = path.dirname(tsConfigFilePath);
const expandedFilePaths = [];
for (const filePath of filePaths) {
let resolvedBasePath = moduleCallerFilePath;
let effectivePattern = filePath;
if (filePath.startsWith('@/')) {
let aliasBaseResolved = false;
for (const [alias, targets] of Object.entries(pathAliases)) {
if ((alias === '@/*' || alias === '@*') && targets.length > 0) {
const target = targets[0].replace(/\*/g, '');
resolvedBasePath = path.resolve(tsConfigDir, target);
effectivePattern = filePath.replace('@/', '');
aliasBaseResolved = true;
break;
}
}
if (!aliasBaseResolved) {
error_handler_1.ErrorHandler.logWarning('FileScanner', `Could not resolve base path for alias pattern: ${filePath}`);
continue;
}
}
const isGlob = filePath.includes('*') || filePath.includes('?') || filePath.includes('[');
if (isGlob) {
try {
const globMatches = glob.sync(effectivePattern, {
cwd: resolvedBasePath,
absolute: true,
});
const filteredMatches = globMatches.filter((match) => match.endsWith('.ts') || match.endsWith('.js'));
expandedFilePaths.push(...filteredMatches);
}
catch (error) {
error_handler_1.ErrorHandler.logWarning('FileScanner', `Error expanding glob pattern ${filePath}`, error);
}
}
else {
const resolvedPath = this.resolvePathWithAliases(filePath, pathAliases, tsConfigDir, moduleCallerFilePath);
if (resolvedPath) {
expandedFilePaths.push(resolvedPath);
}
}
}
for (const resolvedPath of expandedFilePaths) {
if (fs.existsSync(resolvedPath)) {
try {
const content = fs.readFileSync(resolvedPath, 'utf8');
sourceFile.addStatements(content);
}
catch (error) {
error_handler_1.ErrorHandler.logWarning('FileScanner', `Error injecting file ${resolvedPath}`, error);
}
}
else {
error_handler_1.ErrorHandler.logWarning('FileScanner', `Could not resolve path for ${resolvedPath} or file doesn't exist`);
}
}
}
catch (parseError) {
error_handler_1.ErrorHandler.logWarning('FileScanner', `Error parsing tsconfig.json`, parseError);
}
}
else {
error_handler_1.ErrorHandler.logWarning('FileScanner', 'Could not find tsconfig.json file');
}
}
catch (error) {
error_handler_1.ErrorHandler.logWarning('FileScanner', `Error injecting files`, error);
}
}
}
exports.FileScanner = FileScanner;
//# sourceMappingURL=file-scanner.js.map