diff --git a/scripts/postinstall.js b/scripts/postinstall.js new file mode 100644 index 00000000..66ed10fe --- /dev/null +++ b/scripts/postinstall.js @@ -0,0 +1,105 @@ +const fs = require("node:fs") +const path = require("node:path") + +const sharedRootPath = path.resolve(process.cwd(), "shared") +const sharedClassesPath = path.resolve(sharedRootPath, "classes") + +const rootPath = process.cwd() +const packagesPath = path.resolve(rootPath, "packages") + +const excludedPackages = ["comty.js"] + +function filterPackages(packages) { + const gitIgnore = fs.readFileSync(path.resolve(rootPath, ".gitignore"), "utf-8") + + // create a regex to match all packages that are in the gitignore file + const gitIgnoreRegex = gitIgnore.split("\n").map((line) => { + // remove comments + if (line.startsWith("#")) return + + return line.replace(/(\/)/g, "\\/").replace(/(\*)/g, "(.*)") + }).filter((line) => line) + + // filter packages that are in the gitignore file + packages = packages.filter((packageName) => { + // filter excluded packages + if (excludedPackages.includes(packageName)) { + return false + } + + const resolvedPath = path.resolve(packagesPath, packageName) + + return !gitIgnoreRegex.some((regex) => { + return resolvedPath.match(regex) + }) + }) + + packages = packages.filter((packageName) => { + return fs.statSync(path.resolve(packagesPath, packageName)).isDirectory() + }) + + return packages +} + +async function linkSharedClasses(pkgJSON, packagePath) { + if (typeof pkgJSON !== "object") { + throw new Error("Package must be an object") + } + + const { sharedClasses } = pkgJSON + + if (!sharedClasses) { + return + } + + for (const [className, linkPath] of Object.entries(sharedClasses)) { + const originClassPath = path.resolve(sharedClassesPath, className) + const finalLinkPath = path.resolve(packagePath, linkPath, className) + + if (!fs.existsSync(originClassPath)) { + throw new Error(`Class [${className}] does not exist`) + } + if (fs.existsSync(finalLinkPath)) { + console.warn(`⚠️ Class [${className}] already exists in [${finalLinkPath}]`) + continue + } else { + fs.mkdirSync(path.resolve(packagePath, linkPath), { recursive: true }) + } + + // link folder recursively + fs.symlinkSync(originClassPath, finalLinkPath, "dir") + + console.log(`🔗 Linked [${className}] to [${finalLinkPath}]`) + } +} + +async function main() { + console.time("Postinstall tooks:") + + // read dir with absolute paths + let packages = await fs.promises.readdir(packagesPath) + + packages = filterPackages(packages) + + for (const packageName of packages) { + const packagePath = path.resolve(packagesPath, packageName) + + const packageJsonPath = path.resolve(packagePath, "package.json") + + if (!fs.existsSync(packageJsonPath)) { + continue + } + + const packageJson = require(packageJsonPath) + + if (packageJson.sharedClasses) { + console.log(`📦 Package [${packageName}] has shared classes.`) + + await linkSharedClasses(packageJson, packagePath) + } + } + + console.timeEnd("Postinstall tooks:") +} + +main().catch(console.error) \ No newline at end of file