import path from 'path'; import fs from 'fs'; import { glob, globSync } from 'glob'; import { askForText } from './askForText'; const PEER_DEPS = ['@dpa/react-grid', '@dpa/rtm-intro']; const TYPOGRAPHY_ICONS = '@dpa/react-typography-icons'; /** Функция проверки зависимостей */ export async function checkDependencies(project: string) { const projectDir = path.join(__dirname, '../../packages/react', project); const externalDependencies = await findExternalDependencies(projectDir); /** Все package.json */ const packageJsonFiles = await getPackageJsonFiles(projectDir); const filteredExternalDependencies: string[] = []; for (const externalDep of externalDependencies) { const alreadyUsedVersion = isAlreadyUsed(packageJsonFiles, externalDep); if (!alreadyUsedVersion && externalDep === TYPOGRAPHY_ICONS) { if ( !( (await askForText( `Нужно ли зашить иконки ${TYPOGRAPHY_ICONS} в пакет? y/n` )) === 'y' ) ) filteredExternalDependencies.push(externalDep); } else filteredExternalDependencies.push(externalDep); } await updateViteConfig(projectDir, filteredExternalDependencies); await updatePackageJSON(projectDir, filteredExternalDependencies); console.log('Зависимости обновлены'); } async function findExternalDependencies(projectDir: string) { const projectSrcDir = path.join(projectDir, 'src'); const files = await glob('**/*.ts?(x)', { cwd: projectSrcDir, ignore: ['node_modules/**', '**/*.d.ts', '**/*.spec.ts?(x)'], }); const dependencies = new Set(); for (const file of files) { const content = fs.readFileSync(path.join(projectSrcDir, file), 'utf8'); const regex = /(?:import)(?:[\s\S]*?from\s*)?["']([^"']+)["']|\)/g; let match; while ((match = regex.exec(content)) !== null) { const dep = match[1] || match[2]; if (dep && !isRelativePath(dep)) { if (dep.startsWith('@')) { dependencies.add(dep); } else { dependencies.add(dep.split('/')[0]); } } } } return Array.from(dependencies).sort() as string[]; } function isRelativePath(dep) { return dep.startsWith('./') || dep.startsWith('../') || dep.startsWith('/'); } async function updateViteConfig( projectDir: string, externalDependencies: string[] ) { try { const viteConfigPath = path.join(projectDir, 'vite.config.ts'); const fileContent = fs.readFileSync(viteConfigPath, 'utf-8'); const externalBlockRegex = /external:\s*\[([\s\S]*?)\]/s; const match = fileContent.match(externalBlockRegex); if (match) { const content = match[1].trim(); const isMultiline = content.includes('\n'); const currentExternals = content .split(',') .map((item) => item.trim().replace(/['"`]/g, '')) .filter(Boolean); const newExternals = [...currentExternals]; externalDependencies.forEach((dep) => { if (!newExternals.includes(dep)) { newExternals.push(dep); } }); let newArrayContent; if (isMultiline) { const entries = newExternals .map((dep) => ` '${dep}',`) .join('\n'); newArrayContent = `[\n${entries}\n ]`; } else { const entries = newExternals.map((dep) => `'${dep}'`).join(', '); newArrayContent = `[${entries}]`; } const newContent = fileContent.replace( externalBlockRegex, `external: ${newArrayContent}` ); if (newContent !== fileContent) { fs.writeFileSync(viteConfigPath, newContent, 'utf-8'); console.log('Внешние зависимоти добавлены в vite.config.ts'); } } else console.log('Добавьте поле external в vite.config.ts'); } catch (error) { console.error( 'Ошибка при добавлении внешних зависимостей в vite.config.ts:', error ); } } async function updatePackageJSON( projectDir: string, externalDependencies: string[] ) { try { const packageJSONPath = path.join(projectDir, 'package.json'); const fileContent = fs.readFileSync(packageJSONPath, 'utf-8'); const rootPackage = JSON.parse(fileContent); const rootVersion = rootPackage.version; const dependencies = {}; const peerDependencies = { ...(rootPackage['peerDependencies'] || {}) }; /** Все package.json */ const packageJsonFiles = await getPackageJsonFiles(projectDir); console.log('packageJsonFiles', packageJsonFiles); console.log('externalDependencies', externalDependencies); for (const externalDep of externalDependencies) { /** Пропустить */ if (externalDep === 'react') { return; } /** Если зависимость проставлена */ if ( rootPackage?.dependencies?.[externalDep] || rootPackage?.peerDependencies?.[externalDep] ) { return; } /** Пакет уже был где-то использован */ const alreadyUsedVersion = isAlreadyUsed(packageJsonFiles, externalDep); if (alreadyUsedVersion) { if (PEER_DEPS.includes(externalDep)) { peerDependencies[externalDep] = alreadyUsedVersion; } else { dependencies[externalDep] = alreadyUsedVersion; } } else { console.error(`Добавьте зависимость ${externalDep} в package.json`); } } rootPackage.dependencies = dependencies; rootPackage.peerDependencies = peerDependencies; fs.writeFileSync( packageJSONPath, JSON.stringify(rootPackage, null, 2) + '\n' ); } catch (error) { console.error( 'Ошибка при добавлении внешних зависимостей в package.json:', error ); } } function getPackageJsonFiles(projectDir: string) { return globSync('**/package.json', { cwd: path.join(projectDir, '..'), absolute: true, ignore: ['**/node_modules/**'], }); } function isAlreadyUsed(packageJsonFiles: string[], externalDep: string) { return packageJsonFiles.reduce((acc, filePath) => { if (acc) { return acc; } const fileContent = JSON.parse(fs.readFileSync(filePath, 'utf-8')); return fileContent?.dependencies?.[externalDep] || null; }, null); }