pdc-hyperdrift
Version:
Smart dependency compatibility checker that prevents peer dependency conflicts before you upgrade
286 lines (231 loc) โข 9 kB
JavaScript
/**
* Quick setup script for external developers
* Usage: npx @hyperdrift-io/peer-dependency-checker setup
*/
const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');
// Import chalk with fallback for better compatibility
let chalk;
try {
chalk = require('chalk');
} catch (error) {
// Fallback if chalk is not available
chalk = {
blue: { bold: (text) => text },
green: { bold: (text) => text },
yellow: { bold: (text) => text },
red: { bold: (text) => text },
gray: (text) => text
};
}
// Check if being run with --help flag first
if (process.argv.includes('--help') || process.argv.includes('-h')) {
console.log(`
peer-dependency-checker setup
USAGE:
npx @hyperdrift-io/peer-dependency-checker setup [options]
DESCRIPTION:
Sets up peer-dependency-checker in your project with automatic
package manager detection and sensible defaults.
OPTIONS:
--help, -h Show this help message
--pm <manager> Force specific package manager (npm|yarn|pnpm|bun)
--skip-hooks Don't add preinstall/postinstall hooks
--skip-config Don't create .pdcrc.json configuration file
--dry-run Show what would be done without making changes
EXAMPLES:
npx @hyperdrift-io/peer-dependency-checker setup
npx @hyperdrift-io/peer-dependency-checker setup --pm yarn
npx @hyperdrift-io/peer-dependency-checker setup --dry-run
For more information: https://github.com/hyperdrift-io/peer-dependency-checker
`);
process.exit(0);
}
console.log(chalk.blue.bold('๐ peer-dependency-checker setup'));
console.log(chalk.gray('Adding safe dependency checking to your project...\n'));
async function main() {
try {
const cwd = process.cwd();
const packageJsonPath = path.join(cwd, 'package.json');
// 1. Check if we're in a valid project
if (!fs.existsSync(packageJsonPath)) {
console.error(chalk.red('โ No package.json found. Please run this in a Node.js project root.'));
process.exit(1);
}
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
console.log(chalk.green(`๐ฆ Found project: ${packageJson.name || 'unnamed'}`));
// 2. Detect package manager
const packageManager = detectPackageManager(cwd);
console.log(chalk.blue(`๐ง Detected package manager: ${packageManager}`));
// 3. Install peer-dependency-checker as devDependency (if not already global)
await installPeerDependencyChecker(packageManager);
// 4. Add scripts to package.json
await setupPackageScripts(packageJsonPath, packageManager);
// 5. Create config file
await createConfig(cwd, packageManager);
// 6. Test the setup
await testSetup();
console.log(chalk.green.bold('\n๐ Setup complete!'));
console.log(chalk.yellow('\n๐ What was added to your project:'));
console.log(chalk.gray(' โข pre/post-install scripts in package.json'));
console.log(chalk.gray(' โข .pdcrc.json configuration file'));
console.log(chalk.gray(' โข @hyperdrift-io/peer-dependency-checker as devDependency'));
console.log(chalk.blue('\n๐ Try it now:'));
console.log(chalk.gray(` ${packageManager} install react@19 # Will check compatibility first`));
console.log(chalk.gray(' pdc scan # Manual project scan'));
} catch (error) {
console.error(chalk.red('โ Setup failed:'), error.message);
process.exit(1);
}
}
function detectPackageManager(projectPath) {
// Check for lock files to determine package manager
if (fs.existsSync(path.join(projectPath, 'bun.lockb'))) return 'bun';
if (fs.existsSync(path.join(projectPath, 'pnpm-lock.yaml'))) return 'pnpm';
if (fs.existsSync(path.join(projectPath, 'yarn.lock'))) return 'yarn';
if (fs.existsSync(path.join(projectPath, 'package-lock.json'))) return 'npm';
// Check which package manager is available
try {
execSync('bun --version', { stdio: 'pipe' });
return 'bun';
} catch {}
try {
execSync('pnpm --version', { stdio: 'pipe' });
return 'pnpm';
} catch {}
try {
execSync('yarn --version', { stdio: 'pipe' });
return 'yarn';
} catch {}
return 'npm'; // fallback
}
async function installPeerDependencyChecker(packageManager) {
console.log(chalk.yellow('๐ฅ Installing peer-dependency-checker...'));
try {
// Check if already installed globally
execSync('pdc --version', { stdio: 'pipe' });
console.log(chalk.green(' โ
Already installed globally'));
return;
} catch {
// Not global, install as devDependency
}
const installCommands = {
npm: 'npm install --save-dev @hyperdrift-io/peer-dependency-checker',
yarn: 'yarn add --dev @hyperdrift-io/peer-dependency-checker',
pnpm: 'pnpm add --save-dev @hyperdrift-io/peer-dependency-checker',
bun: 'bun add --dev @hyperdrift-io/peer-dependency-checker'
};
const command = installCommands[packageManager];
console.log(chalk.gray(` Running: ${command}`));
execSync(command, { stdio: 'inherit' });
console.log(chalk.green(' โ
Installed as devDependency'));
}
async function setupPackageScripts(packageJsonPath, packageManager) {
console.log(chalk.yellow('๐ Setting up package.json scripts...'));
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
if (!packageJson.scripts) {
packageJson.scripts = {};
}
// Add appropriate scripts based on package manager
const scripts = getScriptsForPackageManager(packageManager);
// Merge scripts, avoiding overwrites
Object.entries(scripts).forEach(([key, value]) => {
if (!packageJson.scripts[key]) {
packageJson.scripts[key] = value;
console.log(chalk.green(` โ
Added script: ${key}`));
} else {
console.log(chalk.yellow(` โ ๏ธ Script '${key}' already exists, skipping`));
}
});
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
console.log(chalk.green(' โ
Package.json updated'));
}
function getScriptsForPackageManager(pm) {
const commonScripts = {
'pdc:scan': 'pdc scan',
'pdc:check': 'pdc scan --quick || true',
'pdc:analyze': 'pdc analyze --brief || true'
};
// Different package managers handle pre/post hooks differently
switch (pm) {
case 'yarn':
return {
...commonScripts,
'preinstall': 'pdc scan --quick || true',
'postinstall': 'pdc analyze --brief || true'
};
case 'bun':
return {
...commonScripts,
'preinstall': 'pdc scan --quick || true',
'postinstall': 'pdc analyze --brief || true'
};
case 'pnpm':
return {
...commonScripts,
'preinstall': 'pdc scan --quick || true',
'postinstall': 'pdc analyze --brief || true'
};
default: // npm
return {
...commonScripts,
'preinstall': 'pdc scan --quick || true',
'postinstall': 'pdc analyze --brief || true'
};
}
}
async function createConfig(projectPath, packageManager) {
console.log(chalk.yellow('โ๏ธ Creating configuration file...'));
const configPath = path.join(projectPath, '.pdcrc.json');
if (fs.existsSync(configPath)) {
console.log(chalk.yellow(' โ ๏ธ .pdcrc.json already exists, skipping'));
return;
}
const config = {
packageManager,
riskTolerance: 'medium',
autoCheck: true,
checkOnInstall: true,
checkOnUpgrade: true,
excludePackages: [],
includeDevDependencies: true,
outputFormat: 'colored'
};
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
console.log(chalk.green(' โ
Created .pdcrc.json'));
}
async function testSetup() {
console.log(chalk.yellow('๐งช Testing setup...'));
try {
execSync('pdc --version', { stdio: 'pipe' });
console.log(chalk.green(' โ
CLI accessible'));
} catch {
try {
execSync('npx pdc --version', { stdio: 'pipe' });
console.log(chalk.green(' โ
CLI accessible via npx'));
} catch {
console.log(chalk.red(' โ CLI not accessible'));
throw new Error('peer-dependency-checker CLI not accessible');
}
}
}
// Show help if needed
if (process.argv.includes('--help') || process.argv.includes('-h')) {
console.log(`
${chalk.blue.bold('peer-dependency-checker setup')}
Automatically integrates peer dependency checking into your project.
Usage:
npx @hyperdrift-io/peer-dependency-checker setup
What it does:
โข Detects your package manager (npm/yarn/pnpm/bun)
โข Installs peer-dependency-checker as devDependency
โข Adds pre/post-install hooks to package.json
โข Creates .pdcrc.json configuration
โข Sets up automatic dependency checking
After setup, all dependency installations will be checked for peer dependency conflicts automatically.
`);
process.exit(0);
}
main().catch(console.error);