Skip to content

Commit

Permalink
feat(groups): add support to ignore dependencies
Browse files Browse the repository at this point in the history
  • Loading branch information
JamieMason committed Nov 23, 2022
1 parent b7c0308 commit f96df8f
Show file tree
Hide file tree
Showing 31 changed files with 491 additions and 212 deletions.
32 changes: 26 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,22 @@ Remove dependencies which you've decided should never be allowed.
}
```

#### `versionGroup.isIgnored`

Have syncpack ignore these dependencies completely.

```json
{
"versionGroups": [
{
"dependencies": ["**"],
"isIgnored": true,
"packages": ["oops-moment", "workaround"]
}
]
}
```

#### `versionGroup.pinVersion`

Pin the version of all dependencies in this group to match this specific version
Expand Down Expand Up @@ -631,15 +647,20 @@ Which of the [Supported Ranges](#supported-ranges) this group should use.

#### `semverGroup.dependencies`

Works the same as [`semverGroup.dependencies`](#semvergroupdependencies).
Works the same as [`versionGroup.dependencies`](#versiongroupdependencies).

#### `semverGroup.isIgnored`

Works the same as [`versionGroup.isIgnored`](#versiongroupisignored).

#### `semverGroup.packages`

Works the same as [`semverGroup.packages`](#semvergrouppackages).
Works the same as [`versionGroup.packages`](#versiongrouppackages).

#### `semverGroup.dependencyTypes`

Works the same as [`semverGroup.dependencyTypes`](#semvergroupdependencytypes).
Works the same as
[`versionGroup.dependencyTypes`](#versiongroupdependencytypes).

## 🕵🏾‍♀️ Resolving Packages

Expand All @@ -656,7 +677,8 @@ package.json files are resolved in this order of precendence:
`./pnpm-workspace.yaml`.
5. Default to `'package.json'` and `'packages/*/package.json'`.

> 👋 Always add quotes around your `--source` patterns [[more info](https://github.com/JamieMason/syncpack/issues/66#issuecomment-1146011769)].
> 👋 Always add quotes around your `--source` patterns
> [[more info](https://github.com/JamieMason/syncpack/issues/66#issuecomment-1146011769)].
## 🙋🏿‍♀️ Getting Help

Expand All @@ -674,8 +696,6 @@ If you find my Open Source projects useful, please share them ❤️

- [**eslint-formatter-git-log**](https://github.com/JamieMason/eslint-formatter-git-log)<br>ESLint
Formatter featuring Git Author, Date, and Hash
- [**eslint-plugin-move-files**](https://github.com/JamieMason/eslint-plugin-move-files)<br>Move
and rename files while keeping imports up to date
- [**eslint-plugin-prefer-arrow-functions**](https://github.com/JamieMason/eslint-plugin-prefer-arrow-functions)<br>Convert
functions to arrow functions
- [**ImageOptim-CLI**](https://github.com/JamieMason/ImageOptim-CLI)<br>Automates
Expand Down
12 changes: 12 additions & 0 deletions src/bin-fix-mismatches/fix-mismatches.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ describe('fixMismatches', () => {
]);
});
});

describe('when using nested workspaces', () => {
it('warns about the workspace version', () => {
const scenario =
Expand Down Expand Up @@ -83,6 +84,17 @@ describe('fixMismatches', () => {
]);
});

it('does not consider versions of ignored dependencies', () => {
const scenario = scenarios.versionIsIgnored();
fixMismatches(getInput(scenario.disk, scenario.config), scenario.disk);
expect(scenario.disk.writeFileSync).not.toHaveBeenCalled();
expect(scenario.log.mock.calls).toEqual([
[expect.stringMatching(/Version Group 1/)],
scenario.files['packages/a/package.json'].logEntryWhenUnchanged,
scenario.files['packages/b/package.json'].logEntryWhenUnchanged,
]);
});

it('replaces mismatching npm overrides', () => {
const scenario = scenarios.dependentDoesNotMatchNpmOverrideVersion();
fixMismatches(getInput(scenario.disk, scenario.config), scenario.disk);
Expand Down
4 changes: 2 additions & 2 deletions src/bin-fix-mismatches/fix-mismatches.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ export function fixMismatches(input: ProgramInput, disk: Disk): void {
console.log(chalk`{dim = Version Group ${i} ${'='.repeat(63)}}`);
}

groups.forEach(({ hasMismatches, instances, name }) => {
if (hasMismatches) {
groups.forEach(({ hasMismatches, instances, isIgnored, name }) => {
if (hasMismatches && !isIgnored) {
const nextVersion = getExpectedVersion(name, versionGroup, input);
instances.forEach(({ dependencyType, version, wrapper }) => {
const root: any = wrapper.contents;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { IndexedVersionGroup } from '../../lib/get-input/get-instances';
import type { PinnedVersionGroup } from '../../types/version-group';

export function getPinnedVersion(
versionGroup: Pick<IndexedVersionGroup, 'pinVersion'>,
versionGroup: Pick<PinnedVersionGroup, 'pinVersion'>,
): string {
return versionGroup.pinVersion || '';
}
41 changes: 25 additions & 16 deletions src/bin-fix-mismatches/get-expected-version/index.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,35 @@
import type { ProgramInput } from '../../lib/get-input';
import type { IndexedVersionGroup } from '../../lib/get-input/get-instances';
import type {
IndexedBannedVersionGroup,
IndexedPinnedVersionGroup,
IndexedVersionGroup,
} from '../../lib/get-input/get-instances';
import { getHighestVersion } from './get-highest-version';
import { getPinnedVersion } from './get-pinned-version';
import { getWorkspaceVersion } from './get-workspace-version';

export function getExpectedVersion(
name: string,
versionGroup: Pick<
IndexedVersionGroup,
'isBanned' | 'instances' | 'pinVersion'
>,
versionGroup:
| Pick<IndexedBannedVersionGroup, 'isBanned' | 'instances'>
| Pick<IndexedPinnedVersionGroup, 'instances' | 'pinVersion'>
| Pick<IndexedVersionGroup, 'instances'>,
input: Pick<ProgramInput, 'workspace' | 'wrappers'>,
): string | undefined {
return versionGroup.isBanned === true
? // remove this dependency
undefined
: getPinnedVersion(versionGroup) ||
(input.workspace === true &&
getWorkspaceVersion(name, input.wrappers)) ||
getHighestVersion(
versionGroup.instances
.filter((instance) => instance.name === name)
.map(({ version }) => version),
);
if ('isBanned' in versionGroup && versionGroup.isBanned === true) {
// remove this dependency
return undefined;
}
if ('pinVersion' in versionGroup && versionGroup.pinVersion) {
return getPinnedVersion(versionGroup);
}
if (input.workspace === true) {
const workspaceVersion = getWorkspaceVersion(name, input.wrappers);
if (workspaceVersion) return workspaceVersion;
}
return getHighestVersion(
versionGroup.instances
.filter((instance) => instance.name === name)
.map(({ version }) => version),
);
}
8 changes: 8 additions & 0 deletions src/bin-lint-semver-ranges/lint-semver-ranges.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,12 @@ describe('lintSemverRanges', () => {
['✕ f 0.1.0 in resolutions of a should be *'],
]);
});

it('does not include ignored dependencies in its output', () => {
const scenario = scenarios.semverIsIgnored();
lintSemverRanges(getInput(scenario.disk, scenario.config), scenario.disk);
expect(scenario.log.mock.calls).toEqual([
['✕ foo 0.1.0 in dependencies of a should be ~0.1.0'],
]);
});
});
2 changes: 2 additions & 0 deletions src/bin-lint-semver-ranges/lint-semver-ranges.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ export function lintSemverRanges(input: ProgramInput, disk: Disk): void {
* will then start from index 1.
*/
input.instances.semverGroups.reverse().forEach((semverGroup, i) => {
if (!('range' in semverGroup && semverGroup.range)) return;

const isSemverGroup = i > 0;
const mismatches = listSemverGroupMismatches(semverGroup);

Expand Down
7 changes: 7 additions & 0 deletions src/bin-list-mismatches/list-mismatches.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,5 +85,12 @@ describe('listMismatches', () => {
]);
expect(scenario.disk.process.exit).toHaveBeenCalledWith(1);
});

it('does not mention ignored dependencies', () => {
const scenario = scenarios.versionIsIgnored();
listMismatches(getInput(scenario.disk, scenario.config), scenario.disk);
expect(scenario.log.mock.calls).toBeEmptyArray();
expect(scenario.disk.process.exit).not.toHaveBeenCalled();
});
});
});
2 changes: 1 addition & 1 deletion src/bin-list-mismatches/list-mismatches.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export function listMismatches(input: ProgramInput, disk: Disk): void {
input.instances.versionGroups.reverse().forEach((versionGroup, i) => {
const isVersionGroup = i > 0;
const groups = listVersionGroups(versionGroup).filter(
({ hasMismatches }) => hasMismatches,
(group) => !group.isIgnored && group.hasMismatches,
);

if (groups.length > 0) {
Expand Down
3 changes: 3 additions & 0 deletions src/bin-list/list-version-groups.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@ describe('listVersionGroups', () => {
hasMismatches: false,
instances: [{ name: 'bar', version: '0.5.0' }],
isBanned: false,
isIgnored: false,
name: 'bar',
uniques: ['0.5.0'],
},
{
hasMismatches: false,
instances: [{ name: 'foo', version: '1.0.0' }],
isBanned: false,
isIgnored: false,
name: 'foo',
uniques: ['1.0.0'],
},
Expand All @@ -43,6 +45,7 @@ describe('listVersionGroups', () => {
{ name: 'foo', version: '1.1.0' },
],
isBanned: false,
isIgnored: false,
name: 'foo',
uniques: ['1.0.0', '1.1.0'],
},
Expand Down
14 changes: 10 additions & 4 deletions src/bin-list/list-version-groups.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { isNonEmptyString } from 'expect-more';
import type {
IndexedVersionGroup,
AnyIndexedVersionGroup,
Instance,
} from '../lib/get-input/get-instances';
import { groupBy } from '../lib/group-by';
Expand All @@ -10,21 +10,26 @@ export interface ListItem {
hasMismatches: boolean;
instances: Instance[];
isBanned: boolean;
isIgnored: boolean;
name: string;
uniques: string[];
}

export function listVersionGroups(
versionGroup: IndexedVersionGroup,
versionGroup: AnyIndexedVersionGroup,
): ListItem[] {
const instances = versionGroup.instances;
const instancesByName = groupBy<Instance>('name', instances.sort(sortByName));
return Object.entries(instancesByName).map(([name, instances]) => {
const pinnedVersion = versionGroup.pinVersion;
const pinnedVersion =
'pinVersion' in versionGroup ? versionGroup.pinVersion : '';
const hasPinnedVersion = isNonEmptyString(pinnedVersion);
const versions = instances.map(({ version }) => version);
const uniques = Array.from(new Set(versions));
const isBanned = versionGroup.isBanned === true;
const isBanned =
'isBanned' in versionGroup && versionGroup.isBanned === true;
const isIgnored =
'isIgnored' in versionGroup && versionGroup.isIgnored === true;
const hasMismatches =
isBanned ||
versions.some(
Expand All @@ -36,6 +41,7 @@ export function listVersionGroups(
hasMismatches,
instances,
isBanned,
isIgnored,
name,
uniques,
};
Expand Down
11 changes: 11 additions & 0 deletions src/bin-list/list.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,5 +68,16 @@ describe('list', () => {
]);
expect(scenario.disk.process.exit).toHaveBeenCalledWith(1);
});

it('mentions ignored dependencies', () => {
const scenario = scenarios.versionIsIgnored();
list(getInput(scenario.disk, scenario.config), scenario.disk);
expect(scenario.log.mock.calls).toEqual([
['- foo 0.1.0'],
[expect.stringMatching(/Version Group 1/)],
['- bar is ignored in this version group'],
]);
expect(scenario.disk.process.exit).not.toHaveBeenCalled();
});
});
});
6 changes: 4 additions & 2 deletions src/bin-list/list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,14 @@ export function list(input: ProgramInput, disk: Disk): void {
console.log(chalk`{dim = Version Group ${i} ${'='.repeat(63)}}`);
}

groups.forEach(({ hasMismatches, isBanned, name, uniques }) => {
groups.forEach(({ hasMismatches, isBanned, isIgnored, name, uniques }) => {
const versionList = uniques.sort();
const expected = getExpectedVersion(name, versionGroup, input);
console.log(
isBanned
? chalk`{red ${ICON.cross} ${name}} {dim.red is defined in this version group as banned from use}`
: isIgnored
? chalk`{dim ${ICON.skip} ${name}} is ignored in this version group`
: hasMismatches
? chalk`{red ${ICON.cross} ${name}} ${versionList
.map((version) =>
Expand All @@ -39,7 +41,7 @@ export function list(input: ProgramInput, disk: Disk): void {
);
});

if (groups.some(({ hasMismatches }) => hasMismatches)) {
if (groups.some((group) => !group.isIgnored && group.hasMismatches)) {
isInvalid = true;
}
});
Expand Down
12 changes: 12 additions & 0 deletions src/bin-set-semver-ranges/set-semver-ranges.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,18 @@ describe('setSemverRanges', () => {
]);
});

it('leaves ignored dependencies unchanged', () => {
const scenario = scenarios.semverIsIgnored();
setSemverRanges(getInput(scenario.disk, scenario.config), scenario.disk);
expect(scenario.disk.writeFileSync.mock.calls).toEqual([
scenario.files['packages/a/package.json'].diskWriteWhenChanged,
]);
expect(scenario.log.mock.calls).toEqual([
scenario.files['packages/a/package.json'].logEntryWhenChanged,
scenario.files['packages/b/package.json'].logEntryWhenUnchanged,
]);
});

it('fixes issue 84', () => {
const scenario = scenarios.issue84Reproduction();
setSemverRanges(getInput(scenario.disk, scenario.config), scenario.disk);
Expand Down
24 changes: 13 additions & 11 deletions src/bin-set-semver-ranges/set-semver-ranges.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,19 @@ import { writeIfChanged } from '../lib/write-if-changed';

export const setSemverRanges = (input: ProgramInput, disk: Disk): void => {
input.instances.semverGroups.reverse().forEach((semverGroup) => {
const mismatches = listSemverGroupMismatches(semverGroup);
mismatches.forEach(({ dependencyType, name, version, wrapper }) => {
if (dependencyType === 'workspace') return;
const root: any = wrapper.contents;
const nextVersion = setSemverRange(semverGroup.range, version);
if (dependencyType === 'pnpmOverrides') {
root.pnpm.overrides[name] = nextVersion;
} else {
root[dependencyType][name] = nextVersion;
}
});
if ('range' in semverGroup && semverGroup.range) {
const mismatches = listSemverGroupMismatches(semverGroup);
mismatches.forEach(({ dependencyType, name, version, wrapper }) => {
if (dependencyType === 'workspace') return;
const root: any = wrapper.contents;
const nextVersion = setSemverRange(semverGroup.range, version);
if (dependencyType === 'pnpmOverrides') {
root.pnpm.overrides[name] = nextVersion;
} else {
root[dependencyType][name] = nextVersion;
}
});
}
});

input.wrappers.forEach((wrapper) => {
Expand Down
Loading

0 comments on commit f96df8f

Please sign in to comment.