Skip to content

Commit 8df7cca

Browse files
committed
checking peer dependencies with yarn
1 parent d77fe2e commit 8df7cca

File tree

3 files changed

+1138
-65
lines changed

3 files changed

+1138
-65
lines changed

packages/cli-tools/src/resolveTransitiveDeps.ts

+88-3
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ export function isUsingYarn(root: string) {
2121
return fs.existsSync(path.join(root, 'yarn.lock'));
2222
}
2323

24+
function writeFile(filePath: string, content: string) {
25+
fs.writeFileSync(filePath, content, {encoding: 'utf8'});
26+
}
27+
2428
async function fetchAvailableVersions(packageName: string): Promise<string[]> {
2529
const response = await fetch.json(`/${packageName}`);
2630

@@ -170,6 +174,74 @@ function filterInstalledPeers(
170174
return data;
171175
}
172176

177+
function findPeerDepsToInstall(
178+
root: string,
179+
dependencies: Map<string, DependencyData>,
180+
) {
181+
const rootPackageJson = require(path.join(root, 'package.json'));
182+
const dependencyList = {
183+
...rootPackageJson.dependencies,
184+
...rootPackageJson.devDependencies,
185+
};
186+
const peerDependencies = new Set<string>();
187+
dependencies.forEach((value) => {
188+
if (value.peerDependencies) {
189+
Object.keys(value.peerDependencies).forEach((name) => {
190+
if (!Object.keys(dependencyList).includes(name)) {
191+
peerDependencies.add(name);
192+
}
193+
});
194+
}
195+
});
196+
197+
return peerDependencies;
198+
}
199+
async function getMissingPeerDepsForYarn(root: string) {
200+
const dependencies = collectDependencies(root);
201+
const depsToInstall = findPeerDepsToInstall(root, dependencies);
202+
203+
return depsToInstall;
204+
}
205+
206+
// install peer deps with yarn without making any changes to package.json and yarn.lock
207+
async function yarnSilentInstallPeerDeps(root: string) {
208+
const dependenciesToInstall = await getMissingPeerDepsForYarn(root);
209+
const packageJsonPath = path.join(root, 'package.json');
210+
const lockfilePath = path.join(root, 'yarn.lock');
211+
212+
if (dependenciesToInstall.size > 0) {
213+
const binPackageJson = fs.readFileSync(packageJsonPath, {
214+
encoding: 'utf8',
215+
});
216+
const binLockfile = fs.readFileSync(lockfilePath, {
217+
encoding: 'utf8',
218+
});
219+
220+
if (!binPackageJson) {
221+
logger.error('package.json is missing');
222+
return;
223+
}
224+
225+
if (!binLockfile) {
226+
logger.error('yarn.lock is missing');
227+
return;
228+
}
229+
const loader = getLoader({text: 'Verifying dependencies...'});
230+
231+
loader.start();
232+
try {
233+
execa.sync('yarn', ['add', ...dependenciesToInstall]);
234+
loader.succeed();
235+
} catch {
236+
loader.fail('Failed to verify peer dependencies');
237+
return;
238+
}
239+
240+
writeFile(packageJsonPath, binPackageJson);
241+
writeFile(lockfilePath, binLockfile);
242+
}
243+
}
244+
173245
export default async function findPeerDepsForAutolinking(root: string) {
174246
const deps = collectDependencies(root);
175247
const nonEmptyPeers = filterNativeDependencies(root, deps);
@@ -240,7 +312,10 @@ async function getPackagesVersion(
240312
return workingVersions;
241313
}
242314

243-
function installMissingPackages(packages: Record<string, string | null>) {
315+
function installMissingPackages(
316+
packages: Record<string, string | null>,
317+
yarn = true,
318+
) {
244319
const packageVersions = Object.entries(packages).map(
245320
([name, version]) => `${name}@^${version}`,
246321
);
@@ -249,7 +324,12 @@ function installMissingPackages(packages: Record<string, string | null>) {
249324
const loader = getLoader({text: 'Installing peer dependencies...'});
250325
loader.start();
251326
try {
252-
execa.sync('npm', ['install', ...flattenList.map((dep) => dep)]);
327+
const deps = flattenList.map((dep) => dep);
328+
if (yarn) {
329+
execa.sync('yarn', ['add', ...deps]);
330+
} else {
331+
execa.sync('npm', ['install', ...deps]);
332+
}
253333
loader.succeed();
254334

255335
return true;
@@ -262,6 +342,11 @@ function installMissingPackages(packages: Record<string, string | null>) {
262342

263343
export async function resolveTransitiveDeps() {
264344
const root = process.cwd();
345+
const isYarn = isUsingYarn(root);
346+
347+
if (isYarn) {
348+
await yarnSilentInstallPeerDeps(root);
349+
}
265350

266351
const missingPeerDependencies = await findPeerDepsForAutolinking(root);
267352

@@ -275,7 +360,7 @@ export async function resolveTransitiveDeps() {
275360
missingPeerDependencies,
276361
);
277362

278-
return installMissingPackages(packagesVersions);
363+
return installMissingPackages(packagesVersions, isYarn);
279364
}
280365
}
281366

packages/cli/src/index.ts

+1-3
Original file line numberDiff line numberDiff line change
@@ -175,9 +175,7 @@ async function setupAndRun() {
175175
}
176176
}
177177

178-
if (!transitiveDeps.isUsingYarn(process.cwd())) {
179-
await transitiveDeps.checkTransitiveDeps();
180-
}
178+
await transitiveDeps.checkTransitiveDeps();
181179

182180
let config: Config | undefined;
183181

0 commit comments

Comments
 (0)