Socket
Socket
Sign inDemoInstall

yarn-deduplicate

Package Overview
Dependencies
Maintainers
1
Versions
20
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

yarn-deduplicate - npm Package Compare versions

Comparing version 1.1.1 to 1.2.0

.history/__tests__/cli_20181030161413.js

14

__tests__/cli.js

@@ -103,2 +103,16 @@ const childProcess = require('child_process');

test('prints fixed yarn.lock when excluding lodash', async () => {
const { stdout, stderr } = await execFile(process.execPath, [
cliFilePath,
'--print',
'--exclude',
'lodash',
yarnLockFilePath,
]);
expect(stdout).toContain('lodash@>=1.0.0:');
expect(stdout).toContain('lodash@>=2.0.0:');
expect(stdout).not.toContain('lodash@>=1.0.0, lodash@>=2.0.0:');
expect(stderr).toBe('');
});
test('edits yarn.lock and replaces its content with the fixed version', async () => {

@@ -105,0 +119,0 @@ const oldFileContent = await readFile(yarnLockFilePath, 'utf8');

@@ -102,2 +102,41 @@ const { fixDuplicates, listDuplicates } = require('../index.js');

test('excludes packages to be de-duplicated', () => {
const yarn_lock = outdent`
a-package@^2.0.0:
version "2.0.0"
resolved "http://example.com/a-package/2.1.0"
a-package@^2.0.1:
version "2.0.1"
resolved "http://example.com/a-package/2.2.0"
other-package@^1.0.0:
version "1.0.11"
resolved "http://example.com/other-package/1.0.0"
other-package@^1.0.1:
version "1.0.12"
resolved "http://example.com/other-package/1.0.0"
`;
const deduped = fixDuplicates(yarn_lock, {
excludePackages: ['a-package'],
});
const json = lockfile.parse(deduped).object;
expect(json['a-package@^2.0.0']['version']).toEqual('2.0.0');
expect(json['a-package@^2.0.1']['version']).toEqual('2.0.1');
expect(json['other-package@^1.0.0']['version']).toEqual('1.0.12');
expect(json['other-package@^1.0.1']['version']).toEqual('1.0.12');
const list = listDuplicates(yarn_lock, {
excludePackages: ['a-package'],
});
expect(list).toHaveLength(1);
expect(list).toContain(
'Package "other-package" wants ^1.0.0 and could get 1.0.12, but got 1.0.11'
);
});
test('should support the integrity field if present', () => {

@@ -104,0 +143,0 @@ const yarn_lock = outdent({ trimTrailingNewline: false })`

@@ -8,2 +8,11 @@ # Changelog

## [1.2.0] - 2020-02-29
### Added
- Typescript definitions (thanks to @bluelovers)
- Info about the source of duplication to README
- CLI option to exclude packages (thanks to @JacobBlomgren)
- Updated a bunch of dependencies
## [1.1.1] - 2019-02-03

@@ -10,0 +19,0 @@

@@ -24,2 +24,5 @@ #!/usr/bin/env node

)
.option('--exclude <exclude>', 'a comma separated list of packages not to deduplicate.', val =>
val.split(',').map(v => v.trim())
)
.option('--print', 'instead of saving the deduplicated yarn.lock, print the result in stdout');

@@ -44,2 +47,3 @@

includePackages: commander.packages,
excludePackages: commander.exclude,
});

@@ -54,2 +58,3 @@ duplicates.forEach(logLine => console.log(logLine));

includePackages: commander.packages,
excludePackages: commander.exclude,
});

@@ -56,0 +61,0 @@

25

index.js

@@ -6,3 +6,3 @@ const lockfile = require('@yarnpkg/lockfile');

const extractPackages = (json, includePackages = []) => {
const extractPackages = (json, includePackages = [], excludePackages = []) => {
const packages = {};

@@ -33,2 +33,4 @@ const re = /^(.*)@([^@]*?)$/;

if (excludePackages.length > 0 && excludePackages.includes(packageName)) return;
packages[packageName] = packages[packageName] || [];

@@ -46,3 +48,3 @@ packages[packageName].push({

const computePackageIntances = (packages, name, useMostCommon) => {
const computePackageInstances = (packages, name, useMostCommon) => {
// Instances of this package in the tree

@@ -67,3 +69,3 @@ const packageInstances = packages[name];

packageInstance.satisfiedBy.add(packageInstance.installedVersion);
// In some cases th requested version is invalid form a semver point of view (for
// In some cases the requested version is invalid form a semver point of view (for
// example `sinon@next`). Just ignore those cases, they won't get deduped.

@@ -106,7 +108,7 @@ if (

const getDuplicatedPackages = (json, { includePackages, useMostCommon }) => {
const packages = extractPackages(json, includePackages);
const getDuplicatedPackages = (json, { includePackages, excludePackages, useMostCommon }) => {
const packages = extractPackages(json, includePackages, excludePackages);
return Object.keys(packages)
.reduce(
(acc, name) => acc.concat(computePackageIntances(packages, name, useMostCommon)),
(acc, name) => acc.concat(computePackageInstances(packages, name, useMostCommon)),
[]

@@ -119,3 +121,3 @@ )

yarnLock,
{ includePackages = [], useMostCommon = false } = {}
{ includePackages = [], excludePackages = [], useMostCommon = false } = {}
) => {

@@ -125,3 +127,3 @@ const json = parseYarnLock(yarnLock);

getDuplicatedPackages(json, { includePackages, useMostCommon }).forEach(
getDuplicatedPackages(json, { includePackages, excludePackages, useMostCommon }).forEach(
({ bestVersion, name, installedVersion, requestedVersion }) => {

@@ -137,6 +139,9 @@ result.push(

module.exports.fixDuplicates = (yarnLock, { includePackages = [], useMostCommon = false } = {}) => {
module.exports.fixDuplicates = (
yarnLock,
{ includePackages = [], excludePackages = [], useMostCommon = false } = {}
) => {
const json = parseYarnLock(yarnLock);
getDuplicatedPackages(json, { includePackages, useMostCommon }).forEach(
getDuplicatedPackages(json, { includePackages, excludePackages, useMostCommon }).forEach(
({ bestVersion, name, versions, requestedVersion }) => {

@@ -143,0 +148,0 @@ json[`${name}@${requestedVersion}`] = versions[bestVersion].pkg;

16

package.json
{
"name": "yarn-deduplicate",
"version": "1.1.1",
"version": "1.2.0",
"bin": "./cli.js",

@@ -34,12 +34,12 @@ "description": "Deduplication tool for yarn.lock files",

"@yarnpkg/lockfile": "^1.1.0",
"commander": "^2.10.0",
"semver": "^5.3.0"
"commander": "^4.1.1",
"semver": "7.1.3"
},
"devDependencies": {
"eslint": "^5.10.0",
"eslint-config-prettier": "^3.3.0",
"eslint-plugin-jest": "^22.1.2",
"eslint": "^6.8.0",
"eslint-config-prettier": "^6.10.0",
"eslint-plugin-jest": "^23.8.0",
"eslint-plugin-prettier": "^3.0.0",
"jest": "^21.2.1",
"outdent": "^0.5.0",
"jest": "^25.1.0",
"outdent": "0.7.0",
"prettier": "^1.15.3"

@@ -46,0 +46,0 @@ },

@@ -53,5 +53,5 @@ Builds: [![CircleCI](https://circleci.com/gh/atlassian/yarn-deduplicate.svg?style=svg)](https://circleci.com/gh/atlassian/yarn-deduplicate)

`yarn.lock` contains a list of all the dependencies required by your project (including transitive
dependencies), and the actual package version installed to satistfy those dependencies.
dependencies), and the actual package version installed to satisfy those dependencies.
For the context of this project, a "duplicated package" is a package that appers on multiple nodes
For the context of this project, a "duplicated package" is a package that appears on multiple nodes
of the dependency tree with overlapping version ranges but resolved to different versions.

@@ -74,2 +74,25 @@

### Why is this necessary?
Yarn documentation seems to suggest this package shouldn't be necessary. For example, in
https://classic.yarnpkg.com/en/docs/cli/dedupe/, it says
> The dedupe command isn’t necessary. `yarn install` will already dedupe.
This is, however, not exactly true. There are cases where yarn will *not* deduplicate existing
packages. For example, this scenario:
- Install `libA`. It depends on `libB ^1.1.0`. At this point, the latest version of `libB` is
`1.1.2`, so it gets installed as a transitive dependency in your repo
- After a few days, install `libC`. It also depends on `libB ^1.1.0`. But this time, the latest
`libB` version is `1.1.3`.
In the above scenario, you'll end up with `libB@1.1.2` and `libB@1.1.3` in your repo.
Find more examples in:
- [yarn-deduplicate — The Hero We Need](https://medium.com/@bnaya/yarn-deduplicate-the-hero-we-need-f4497a362128)
- [De-duplicating yarn.lock](https://medium.com/@scinos/de-duplicating-yarn-lock-ae30be4aa41a)
- https://github.com/yarnpkg/yarn/issues/3778
### Deduplication strategies

@@ -127,2 +150,3 @@

---

@@ -129,0 +153,0 @@ ## Migration guide

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc