Created
July 25, 2023 07:20
-
-
Save Moizsohail/98603b810107036e03369068884a14a1 to your computer and use it in GitHub Desktop.
This is a utilitly program allowing you to swap relative paths to the shortest tailwind alias by reading the tsconfig.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* eslint-disable no-console */ | |
/* | |
Alias Absolute Resolver | |
This is a utilitly program allowing you to swap relative paths to the shortest tailwind alias. | |
How to run? | |
npx ts-node aliasAbsolver.ts | |
*/ | |
const fs = require('fs'); | |
const { exit } = require('process'); | |
// import config from './tsconfig.json'; | |
const tsconfig = require('./tsconfig.json'); | |
const packagejson = require('./package.json'); | |
function getArgs() { | |
const args = {}; | |
process.argv.slice(2, process.argv.length).forEach((arg) => { | |
if (arg.slice(0, 2) === '--') { | |
const longArg = arg.split('='); | |
const longArgFlag = longArg[0].slice(2, longArg[0].length); | |
const longArgValue = longArg.length > 1 ? longArg[1] : true; | |
args[longArgFlag] = longArgValue; | |
} | |
}); | |
return args; | |
} | |
const getAllTsFilesFromFolder = (dir) => { | |
let results: string[] = []; | |
fs.readdirSync(dir).forEach((file) => { | |
const filePath = `${dir}/${file}`; | |
const stat = fs.statSync(filePath); | |
if (stat && stat.isDirectory()) { | |
results = results.concat(getAllTsFilesFromFolder(filePath)); | |
} else results.push(filePath); | |
}); | |
return results.filter((filePath) => filePath.endsWith('.ts')); | |
}; | |
interface ExpectedArgs { | |
pattern?: string; | |
} | |
interface ValidatedArgs { | |
pattern: string | null; | |
} | |
const argHelper = ` | |
Invalid Arguments | |
Allowed Args are:\n | |
--pattern={string} : Matches a list of file to resolve. The program performs a search on the text. This should not be a magic or regex expression. | |
`; | |
const validateArgs = (args: ExpectedArgs): ValidatedArgs => { | |
const pattern = args.pattern ?? null; | |
if (typeof pattern !== 'string') throw Error(argHelper); | |
return { pattern }; | |
}; | |
const args: ExpectedArgs = getArgs(); | |
const { pattern } = validateArgs(args); | |
const getAliases = () => { | |
const aliases = tsconfig?.compilerOptions?.paths ?? {}; | |
const updatedAliases: { [alias: string]: string[] } = {}; | |
Object.entries(aliases).forEach((entry) => { | |
const [alias, aliasPath]: any = entry; | |
const cleanAlias = alias.replace(/\*$/, ''); | |
updatedAliases[cleanAlias] = aliasPath[0].replace(/^.\//, '').replace(/\*$/, ''); | |
}); | |
return updatedAliases; | |
}; | |
const availableAliases = getAliases(); | |
if (Object.keys(availableAliases).length === 0) { | |
exit(); | |
} | |
const tsAliases = new Set(Object.keys(availableAliases).map((path) => path.replace('*', ''))); | |
let allFiles = getAllTsFilesFromFolder('./src'); | |
if (pattern) allFiles = allFiles.filter((filePath) => filePath.includes(pattern)); | |
const importRegex = /^import\s+\{[\s\w,]+\}\s+from\s+['"][@\w/.-]+['"];$/gm; | |
const importPathRegex = /['"](.+)['"]/; | |
interface ImportDetails { | |
path: string; | |
fullImport: string; | |
index: number; | |
} | |
const parseImport = (data: string) => { | |
// const matches = importRegex.exec(data); | |
let match; | |
const results: ImportDetails[] = []; | |
// eslint-disable-next-line no-cond-assign | |
while ((match = importRegex.exec(data))) { | |
const importPath = match[0].match(importPathRegex); | |
results.push({ | |
path: importPath[1], | |
fullImport: match[0], | |
index: match.index, | |
}); | |
} | |
return results; | |
}; | |
const resolveRelativeFromAbsolute = (relativePath: string, absolutePath, split = '/') => { | |
const replace = /[/|\\]/g; | |
const relativePieces = relativePath.replace(replace, split).split(split); | |
const absolutePieces = absolutePath.replace(replace, split).split(split); | |
if (absolutePieces[1] === relativePieces[0]) { | |
return relativePath; | |
} | |
const numberOfBacks = relativePieces.filter((file) => file === '..').length; | |
return [...absolutePieces.slice(0, -(numberOfBacks + 1)), ...relativePieces.filter((file) => file !== '..' && file !== '.')].join(split).replace(/.\//, ''); | |
}; | |
const deps = new Set([...Object.keys(packagejson.dependencies), ...Object.keys(packagejson.devDependencies)].map((depName) => depName.split('/')[0])); | |
const absolver = (importPath, filePath) => { | |
const importPrefix = importPath.split('/')[0]; | |
if (deps.has(importPrefix) || tsAliases.has(importPrefix)) return null; | |
const absPath = resolveRelativeFromAbsolute(importPath, filePath); | |
let found: string = ''; | |
let respectiveAliasPath: string = ''; | |
Object.entries(availableAliases).forEach((entry) => { | |
const [alias, aliasPath]: any[] = entry; | |
// console.log(aliasPath); | |
if (absPath.startsWith(aliasPath)) { | |
if (respectiveAliasPath.length < aliasPath.length) { | |
found = alias; | |
respectiveAliasPath = aliasPath; | |
} | |
} | |
}); | |
if (!found) return null; | |
const newPath = absPath.replace(respectiveAliasPath, found); | |
return { importPath, newPath }; | |
}; | |
function escapeRegExp(string) { | |
return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); | |
} | |
const processFileContent = (data, filePath) => { | |
const importData = parseImport(data); | |
let newData = data; | |
const replacements = importData.map(({ path: importPath }) => absolver(importPath, filePath)).filter((replacement) => replacement !== null); | |
if (replacements.length === 0) return null; | |
replacements.forEach(({ newPath, importPath }:any) => { | |
const excapedImportPath = escapeRegExp(importPath); | |
const regexString = `^(import\\s+\\{[\\s\\w,]+\\}\\s+from\\s+['"])${excapedImportPath}(['"];?)$`; | |
const regex = new RegExp(regexString, 'm'); | |
newData = newData.replace(regex, `$1${newPath}$2`); | |
}); | |
return newData; | |
// data.replace(new RegExp()) | |
}; | |
const processFile = (filePath) => { | |
fs.readFile(filePath, 'utf8', (err, data) => { | |
if (err) { | |
console.error(`File Parsing Failed for ${filePath}`); | |
console.error(`Error:${err}`); | |
return; | |
} | |
const newData = processFileContent(data, filePath); | |
if (!newData) { console.error('No update', filePath); } | |
fs.writeFile(filePath, newData, (error) => { | |
if (err) { console.error('Update failed', error); } else { | |
console.log('Updated: ', filePath); | |
} | |
}); | |
}); | |
}; | |
processFile(allFiles[1]); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment