| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189 |
- import { note } from '@clack/prompts';
- import spawn from 'cross-spawn';
- import fs from 'fs-extra';
- import path from 'path';
- import { Project } from 'ts-morph';
- export interface PackageToInstall {
- pkg: string;
- version?: string;
- isDevDependency?: boolean;
- installInRoot?: boolean;
- }
- export class PackageJson {
- private _vendurePackageJsonPath: string | undefined;
- private _rootPackageJsonPath: string | undefined;
- constructor(private readonly project: Project) {}
- get vendurePackageJsonPath() {
- return this.locatePackageJsonWithVendureDependency();
- }
- get rootPackageJsonPath() {
- return this.locateRootPackageJson();
- }
- determineVendureVersion(): string | undefined {
- const packageJson = this.getPackageJsonContent();
- return packageJson.dependencies['@vendure/core'];
- }
- async installPackages(requiredPackages: PackageToInstall[]) {
- const packageJson = this.getPackageJsonContent();
- const packagesToInstall = requiredPackages.filter(({ pkg, version, isDevDependency }) => {
- const hasDependency = isDevDependency
- ? packageJson.devDependencies[pkg]
- : packageJson.dependencies[pkg];
- return !hasDependency;
- });
- const depsToInstall = packagesToInstall
- .filter(p => !p.isDevDependency && packageJson.dependencies?.[p.pkg] === undefined)
- .map(p => `${p.pkg}${p.version ? `@${p.version}` : ''}`);
- const devDepsToInstall = packagesToInstall
- .filter(p => p.isDevDependency && packageJson.devDependencies?.[p.pkg] === undefined)
- .map(p => `${p.pkg}${p.version ? `@${p.version}` : ''}`);
- if (depsToInstall.length) {
- await this.runPackageManagerInstall(depsToInstall, false);
- }
- if (devDepsToInstall.length) {
- await this.runPackageManagerInstall(devDepsToInstall, true);
- }
- }
- getPackageJsonContent() {
- const packageJsonPath = this.locatePackageJsonWithVendureDependency();
- if (!packageJsonPath || !fs.existsSync(packageJsonPath)) {
- note(
- `Could not find a package.json in the current directory. Please run this command from the root of a Vendure project.`,
- );
- return false;
- }
- return fs.readJsonSync(packageJsonPath);
- }
- determinePackageManager(): 'yarn' | 'npm' | 'pnpm' {
- const rootDir = this.getPackageRootDir().getPath();
- const yarnLockPath = path.join(rootDir, 'yarn.lock');
- const npmLockPath = path.join(rootDir, 'package-lock.json');
- const pnpmLockPath = path.join(rootDir, 'pnpm-lock.yaml');
- if (fs.existsSync(yarnLockPath)) {
- return 'yarn';
- }
- if (fs.existsSync(npmLockPath)) {
- return 'npm';
- }
- if (fs.existsSync(pnpmLockPath)) {
- return 'pnpm';
- }
- return 'npm';
- }
- addScript(scriptName: string, script: string) {
- const packageJson = this.getPackageJsonContent();
- packageJson.scripts = packageJson.scripts || {};
- packageJson.scripts[scriptName] = script;
- const packageJsonPath = this.vendurePackageJsonPath;
- if (packageJsonPath) {
- fs.writeJsonSync(packageJsonPath, packageJson, { spaces: 2 });
- }
- }
- getPackageRootDir() {
- const rootDir = this.project.getDirectory('.');
- if (!rootDir) {
- throw new Error('Could not find the root directory of the project');
- }
- return rootDir;
- }
- locateRootPackageJson() {
- if (this._rootPackageJsonPath) {
- return this._rootPackageJsonPath;
- }
- const rootDir = this.getPackageRootDir().getPath();
- const rootPackageJsonPath = path.join(rootDir, 'package.json');
- if (fs.existsSync(rootPackageJsonPath)) {
- this._rootPackageJsonPath = rootPackageJsonPath;
- return rootPackageJsonPath;
- }
- return null;
- }
- locatePackageJsonWithVendureDependency() {
- if (this._vendurePackageJsonPath) {
- return this._vendurePackageJsonPath;
- }
- const rootDir = this.getPackageRootDir().getPath();
- const potentialMonorepoDirs = ['packages', 'apps', 'libs'];
- const rootPackageJsonPath = path.join(this.getPackageRootDir().getPath(), 'package.json');
- if (this.hasVendureDependency(rootPackageJsonPath)) {
- return rootPackageJsonPath;
- }
- for (const dir of potentialMonorepoDirs) {
- const monorepoDir = path.join(rootDir, dir);
- // Check for a package.json in all subdirs
- if (fs.existsSync(monorepoDir)) {
- for (const subDir of fs.readdirSync(monorepoDir)) {
- const packageJsonPath = path.join(monorepoDir, subDir, 'package.json');
- if (this.hasVendureDependency(packageJsonPath)) {
- this._vendurePackageJsonPath = packageJsonPath;
- return packageJsonPath;
- }
- }
- }
- }
- return null;
- }
- private hasVendureDependency(packageJsonPath: string) {
- if (!fs.existsSync(packageJsonPath)) {
- return false;
- }
- const packageJson = fs.readJsonSync(packageJsonPath);
- return !!packageJson.dependencies?.['@vendure/core'];
- }
- private async runPackageManagerInstall(dependencies: string[], isDev: boolean) {
- return new Promise<void>((resolve, reject) => {
- const packageManager = this.determinePackageManager();
- let command = '';
- let args: string[] = [];
- if (packageManager === 'yarn') {
- command = 'yarnpkg';
- args = ['add', '--exact', '--ignore-engines'];
- if (isDev) {
- args.push('--dev');
- }
- args = args.concat(dependencies);
- } else if (packageManager === 'pnpm') {
- command = 'pnpm';
- args = ['add', '--save-exact'].concat(dependencies);
- if (isDev) {
- args.push('--save-dev', '--workspace-root');
- }
- } else {
- command = 'npm';
- args = ['install', '--save', '--save-exact', '--loglevel', 'error'].concat(dependencies);
- if (isDev) {
- args.push('--save-dev');
- }
- }
- const child = spawn(command, args, { stdio: 'ignore' });
- child.on('close', code => {
- if (code !== 0) {
- const message = 'An error occurred when installing dependencies.';
- reject({
- message,
- command: `${command} ${args.join(' ')}`,
- });
- return;
- }
- resolve();
- });
- });
- }
- }
|