@korautils/alias-fixer
Version:
A development utility to automatically fix relative imports by replacing them with path aliases defined in your tsconfig.json. Ideal for streamlining large codebases with consistent import paths.
1 lines • 13.9 kB
Source Map (JSON)
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import fs from 'fs'\nimport path from 'path'\nimport figlet from 'figlet'\nimport * as jsonc from 'jsonc-parser'\n\nconst init = (header?: string) => {\n console.log('-----------------------------------------------')\n console.log(header)\n console.log('-----------------------------------------------')\n console.log('*********** @korautils/alias-fixer ************')\n console.log('-----------------------------------------------')\n // console.log('-----------------------------------------------')\n console.log('🔍 Finding tsconfig file...')\n // console.log('-----------------------------------------------')\n const tsconfig = getTsConfig()\n // valido si tiene paths configurados, si no pues no hay nada que hacer...\n if (!checkPaths(tsconfig)) {\n console.log(\n 'ERROR: No se encontró el archivo tsconfig.json o no se encontró una configuración válida'\n )\n console.log('Se finaliza la operación.')\n return\n }\n\n const dir = path.resolve(process.cwd(), getArgument('--dir', './'))\n const types = getArgument('--types', 'ts,tsx,jsx,js').split(',')\n const exclude = getProp(tsconfig, 'exclude', ['node_modules'])\n console.log('🗂️ dir:', dir)\n console.log('⚪️ types:', types)\n console.log('🚫 exclude:', exclude)\n const files = listFilesByTypes(dir, types, exclude)\n // console.log(files)\n replaceImportsWithAliases(files, tsconfig)\n console.log('-----------------------------------------------')\n console.log('✅ Process completed successfully.')\n console.log('-----------------------------------------------')\n}\n\n/**\n * Replaces relative imports in files with aliases from tsconfig.\n * @param {string[]} files - List of file paths to process.\n * @param {any} tsconfig - The loaded tsconfig.json object.\n */\nfunction replaceImportsWithAliases(files: string[], tsconfig: any) {\n const paths = tsconfig.compilerOptions?.paths || {}\n const dir = path.resolve(\n process.cwd(),\n tsconfig.compilerOptions?.baseUrl || './'\n )\n\n const computedPaths: { alias: string; folders: string[] }[] = []\n for (const alias in paths) {\n if (Object.prototype.hasOwnProperty.call(paths, alias)) {\n const folderPaths = paths[alias]\n computedPaths.push({\n alias: alias.replace(/\\/\\*{1,2}(\\*)?$/, ''),\n folders: folderPaths.map((folder: string) =>\n path.join(process.cwd(), folder.replace(/\\/\\*{1,2}(\\*)?$/, ''))\n ),\n })\n }\n }\n\n files.forEach((file) => {\n const content = fs.readFileSync(file, 'utf-8')\n\n // Replace relative imports with alias\n const updatedContent = content.replace(\n /(import\\s+.*?['\"])(\\.{1,2}\\/.*?)(['\"])/g,\n (fullMatch, prefix, relativePath, suffix) => {\n // Calculate the absolute path of the imported file\n const importedFilePath = path.resolve(path.dirname(file), relativePath)\n\n // Navigate back specified number of folders\n const backFoldersTo = countRelativePaths(relativePath)\n let currentDir = path.dirname(file)\n for (let i = 0; i < backFoldersTo; i++) {\n currentDir = path.dirname(currentDir)\n }\n\n // If not within the base directory, return original path\n if (!currentDir.startsWith(dir)) {\n return fullMatch\n }\n\n // Check if the imported file is outside ALL configured path folders\n const isOutsideAllPaths = computedPaths.every(\n (aliasPath) =>\n !aliasPath.folders.some((folderPath) =>\n importedFilePath.startsWith(folderPath)\n )\n )\n\n // If outside all paths, return original path\n if (isOutsideAllPaths) {\n return fullMatch\n }\n\n // Try to match and replace with the most specific alias\n let bestMatch: { alias: string; relativeImportPath: string } | null =\n null\n\n computedPaths.forEach((aliasPath) => {\n aliasPath.folders.forEach((folderPath) => {\n // Check if the imported file is within this alias's folder path\n if (importedFilePath.startsWith(folderPath)) {\n // Calculate the relative path within the alias folder\n const relativeImportPath = path.relative(\n folderPath,\n importedFilePath\n )\n const newPathCandidate = path.join(\n aliasPath.alias,\n relativeImportPath\n )\n\n // Choose the most specific (longest) match\n if (\n !bestMatch ||\n newPathCandidate.length > bestMatch.relativeImportPath.length\n ) {\n bestMatch = {\n alias: aliasPath.alias,\n relativeImportPath: newPathCandidate,\n }\n }\n }\n })\n })\n\n // Return the best matching path or original if no match found\n return bestMatch\n ? `${prefix}${getProp(bestMatch, 'relativeImportPath')}${suffix}`\n : fullMatch\n }\n )\n\n if (content !== updatedContent) {\n console.log('Updated import in:', file)\n fs.writeFileSync(file, updatedContent, 'utf-8')\n }\n })\n}\n\nfunction countRelativePaths(path: string) {\n // Expresión regular para buscar apariciones de ../\n const regex = /\\.\\.\\//g\n // Usa match para encontrar todas las coincidencias\n const matches = path.match(regex)\n // Devuelve la cantidad de coincidencias o 0 si no hay ninguna\n return matches ? matches.length : 0\n}\n\n/**\n * Recursively lists files in a directory that match the specified extensions,\n * excluding certain directories or files.\n * @param {string} dir - The directory to search.\n * @param {string[]} types - The file extensions to include.\n * @param {string[]} exclude - The directories or files to exclude.\n * @returns {string[]} - An array of file paths that match the extensions.\n */\nfunction listFilesByTypes(\n dir: string,\n types: string[],\n exclude: string[] = []\n) {\n const matchedFiles: any = []\n\n function recursiveRead(currentDir: string) {\n const entries = fs.readdirSync(currentDir, { withFileTypes: true })\n const excludedFiles = exclude.map((item) => {\n const file = path.join(currentDir, item.trim())\n if (fs.existsSync(file)) {\n return file\n }\n return item.trim()\n })\n\n for (const entry of entries) {\n const fullPath = path.join(currentDir, entry.name)\n\n // Skip excluded directories or files\n if (excludedFiles.some((excluded) => fullPath.includes(excluded))) {\n continue\n }\n\n if (entry.isDirectory()) {\n recursiveRead(fullPath)\n } else if (entry.isFile()) {\n const ext = path.extname(entry.name).slice(1) // Remove the leading dot\n if (types.includes(ext)) {\n matchedFiles.push(fullPath)\n }\n }\n }\n }\n\n recursiveRead(dir)\n return matchedFiles\n}\n\nfunction getArgument(key: string, defaultValue: string = './') {\n const args = process.argv.slice(2) // Ignorar node y script\n const prefix = `${key}=`\n\n // Buscar el argumento que comienza con el prefix\n const arg = args.find((arg) => arg.startsWith(prefix))\n\n if (arg) {\n return arg.slice(prefix.length)\n } else {\n return defaultValue\n }\n}\n\nconst checkPaths = (tsconfig: any) => {\n const baseUrl = getProp(tsconfig, 'compilerOptions.baseUrl')\n const paths = getProp(tsconfig, 'compilerOptions.paths')\n\n if (!tsconfig || !baseUrl || !paths) {\n return false\n }\n\n const aliasList = Object.keys(paths).filter((alias) => alias.startsWith('@/'))\n if (aliasList.length == 0) {\n return false\n }\n\n return true\n}\n\nconst getTsConfig = () => {\n const tsconfigPath = path.resolve(process.cwd(), 'tsconfig.json')\n if (!fs.existsSync(tsconfigPath)) {\n return\n }\n\n const tsconfigContent = fs.readFileSync(tsconfigPath, 'utf-8')\n const parsedTsconfig = jsonc.parse(tsconfigContent)\n return parsedTsconfig\n}\n\nfiglet('kora-utils', (err, data) => {\n if (err) {\n console.log('Algo salió mal...', err)\n return\n }\n\n init(data)\n})\n\n/**\n * Obtiene una propiedad anidada de un objeto dado un path.\n *\n * @param obj - El objeto del cual obtener la propiedad.\n * @param path - La ruta a la propiedad, separada por puntos (e.g., \"a.b.c\").\n * @param defaultValue - Valor predeterminado si la propiedad no existe.\n * @returns El valor de la propiedad o el valor predeterminado.\n */\nfunction getProp<T>(\n obj: Record<string, any>,\n path: string,\n defaultValue?: T\n): T | undefined {\n if (!obj || typeof path !== 'string') {\n return defaultValue\n }\n\n const keys = path.split('.') // Divide el path en claves\n let current = obj\n\n for (const key of keys) {\n if (current && typeof current === 'object' && key in current) {\n current = current[key] // Avanza al siguiente nivel del objeto\n } else {\n return defaultValue // Retorna el valor predeterminado si no existe\n }\n }\n\n return current as T // Retorna el valor final encontrado\n}\n"],"mappings":"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","names":["import_fs","import_path","import_figlet","jsonc","init","header","tsconfig","getTsConfig","checkPaths","dir","path","getArgument","types","exclude","getProp","files","listFilesByTypes","replaceImportsWithAliases","paths","computedPaths","alias","folderPaths","folder","file","content","fs","updatedContent","fullMatch","prefix","relativePath","suffix","importedFilePath","backFoldersTo","countRelativePaths","currentDir","i","aliasPath","folderPath","bestMatch","relativeImportPath","newPathCandidate","regex","matches","matchedFiles","recursiveRead","entries","excludedFiles","item","entry","fullPath","excluded","ext","key","defaultValue","args","arg","baseUrl","tsconfigPath","tsconfigContent","figlet","err","data","obj","keys","current"]}