UNPKG

@ts-dev-tools/core

Version:
172 lines (171 loc) 8.14 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.PeerDependenciesService = void 0; const node_fs_1 = require("node:fs"); const node_path_1 = require("node:path"); const PackageJson_1 = require("./PackageJson"); const PluginService_1 = require("./PluginService"); class PeerDependenciesService { constructor() { } static DEPENDENCIES_FOLDER = "node_modules"; static async executeResolution(absoluteProjectDir) { console.info(`Resolving peer dependencies...`); const installedPlugins = PluginService_1.PluginService.getInstalledPlugins(absoluteProjectDir); const missingPeers = []; const packagesToInspect = PeerDependenciesService.getPackagesToInspect(absoluteProjectDir, installedPlugins); for (const packageToInspect of packagesToInspect) { const peers = PeerDependenciesService.getPackagePeerDependencies(packageToInspect.path); for (const peer of peers) { const isResolvable = PeerDependenciesService.canResolveFromConsumerRoot(absoluteProjectDir, peer.name); if (!isResolvable) { const sourcePath = PeerDependenciesService.resolvePeerSourcePath(absoluteProjectDir, packageToInspect.path, peer.name); if (peer.optional && !(0, node_fs_1.existsSync)(sourcePath)) { continue; } missingPeers.push({ ...peer, requiredBy: packageToInspect.name, sourcePath, }); } } } if (missingPeers.length > 0) { PeerDependenciesService.symlinkMissingPeers(absoluteProjectDir, missingPeers); } console.info(`Resolving peer dependencies done!`); } static getPackagePeerDependencies(packageDirPath) { const packageJson = PackageJson_1.PackageJson.fromDirPath(packageDirPath); const content = packageJson.getContent(); const peerDependencies = content.peerDependencies || {}; const peerDependenciesMeta = content.peerDependenciesMeta || {}; return Object.keys(peerDependencies).map((name) => ({ name, optional: peerDependenciesMeta[name]?.optional || false, })); } static getPackagesToInspect(absoluteProjectDir, installedPlugins) { const packages = new Map(); for (const plugin of installedPlugins) { packages.set(plugin.fullname, { name: plugin.fullname, path: plugin.path, }); const pluginDependencies = PackageJson_1.PackageJson.fromDirPath(plugin.path).getDependenciesPackageNames(); for (const dependencyName of pluginDependencies) { const dependencyPath = PeerDependenciesService.resolveDependencyPath(absoluteProjectDir, plugin.path, dependencyName); if (!dependencyPath) { continue; } if (!packages.has(dependencyName)) { packages.set(dependencyName, { name: dependencyName, path: dependencyPath, }); } } } return Array.from(packages.values()); } static resolveDependencyPath(absoluteProjectDir, pluginPath, dependencyName) { const candidatePaths = [ (0, node_path_1.join)(absoluteProjectDir, PeerDependenciesService.DEPENDENCIES_FOLDER, dependencyName), (0, node_path_1.join)(pluginPath, PeerDependenciesService.DEPENDENCIES_FOLDER, dependencyName), ]; for (const candidatePath of candidatePaths) { if ((0, node_fs_1.existsSync)((0, node_path_1.join)(candidatePath, "package.json"))) { return candidatePath; } } return undefined; } static resolvePeerSourcePath(absoluteProjectDir, requiredByPath, peerName) { const projectNodeModulesPath = (0, node_path_1.join)(absoluteProjectDir, PeerDependenciesService.DEPENDENCIES_FOLDER); const directResolution = PeerDependenciesService.resolvePackagePathFrom(requiredByPath, peerName); if (directResolution) { return directResolution; } const projectResolution = PeerDependenciesService.resolvePackagePathFrom(projectNodeModulesPath, peerName); if (projectResolution) { return projectResolution; } const nestedResolution = PeerDependenciesService.resolveFromNestedNodeModules(projectNodeModulesPath, peerName); if (nestedResolution) { return nestedResolution; } return (0, node_path_1.join)(projectNodeModulesPath, peerName); } static resolveFromNestedNodeModules(projectNodeModulesPath, peerName) { const packageDirs = PeerDependenciesService.getTopLevelPackageDirs(projectNodeModulesPath); for (const packageDir of packageDirs) { const resolvedPath = PeerDependenciesService.resolvePackagePathFrom(packageDir, peerName); if (resolvedPath) { return resolvedPath; } } return undefined; } static getTopLevelPackageDirs(nodeModulesPath) { if (!(0, node_fs_1.existsSync)(nodeModulesPath)) { return []; } const packageDirs = []; const entries = (0, node_fs_1.readdirSync)(nodeModulesPath); for (const entry of entries) { const entryPath = (0, node_path_1.join)(nodeModulesPath, entry); if (!entry.startsWith("@")) { packageDirs.push(entryPath); continue; } const scopedEntries = (0, node_fs_1.readdirSync)(entryPath); for (const scopedEntry of scopedEntries) { packageDirs.push((0, node_path_1.join)(entryPath, scopedEntry)); } } return packageDirs; } static resolvePackagePathFrom(fromPath, packageName) { try { const packageJsonPath = require.resolve((0, node_path_1.join)(packageName, "package.json"), { paths: [fromPath], }); return (0, node_path_1.dirname)(packageJsonPath); } catch { return undefined; } } static canResolveFromConsumerRoot(absoluteProjectDir, packageName) { const packagePath = (0, node_path_1.join)(absoluteProjectDir, PeerDependenciesService.DEPENDENCIES_FOLDER, packageName); return (0, node_fs_1.existsSync)(packagePath); } static symlinkMissingPeers(absoluteProjectDir, missingPeers) { const projectDependencyPath = (0, node_path_1.join)(absoluteProjectDir, PeerDependenciesService.DEPENDENCIES_FOLDER); const uniqueMissingPeers = new Map(); for (const peer of missingPeers) { if (!uniqueMissingPeers.has(peer.name)) { uniqueMissingPeers.set(peer.name, peer); } } for (const peer of Array.from(uniqueMissingPeers.values())) { const peerSourcePath = peer.sourcePath; if (!(0, node_fs_1.existsSync)(peerSourcePath)) { console.warn(`- Peer dependency "${peer.name}" required by "${peer.requiredBy}" not found in plugin node_modules`); continue; } const peerTargetPath = (0, node_path_1.join)(projectDependencyPath, peer.name); console.info(`- Symlinking peer dependency "${peer.name}" required by "${peer.requiredBy}"`); PeerDependenciesService.symlinkPeer(peerSourcePath, peerTargetPath); } } static symlinkPeer(sourcePath, targetPath) { const targetParentFolder = (0, node_path_1.join)(targetPath, ".."); if (!(0, node_fs_1.existsSync)(targetParentFolder)) { (0, node_fs_1.mkdirSync)(targetParentFolder, { recursive: true }); } (0, node_fs_1.symlinkSync)(sourcePath, targetPath); } } exports.PeerDependenciesService = PeerDependenciesService;