Skip to content

Commit 4d206b9

Browse files
committed
feat(core): add set-semver-ranges command
1 parent 103e6f6 commit 4d206b9

9 files changed

Lines changed: 267 additions & 68 deletions

File tree

README.md

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,17 @@ npm install --global syncpack
2222
```
2323
Usage: syncpack [options] [command]
2424
25-
Options:
25+
Options:
2626
27-
-V, --version output the version number
28-
-h, --help output usage information
27+
-V, --version output the version number
28+
-h, --help output usage information
2929
30-
Commands:
30+
Commands:
3131
32-
fix-mismatches set dependencies used with different versions to the same version
33-
list list every dependency used in your packages
34-
list-mismatches list every dependency used with different versions in your packages
35-
help [cmd] display help for [cmd]
32+
fix-mismatches set dependencies used with different versions to the same version
33+
format sort and shorten properties according to a convention
34+
list list every dependency used in your packages
35+
list-mismatches list every dependency used with different versions in your packages
36+
set-semver-ranges set semver ranges to the given format
37+
help [cmd] display help for [cmd]
3638
```

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@
55
"author": "Jamie Mason <jamie@foldleft.io> (https://github.com/JamieMason)",
66
"bin": {
77
"syncpack": "dist/bin.js",
8-
"syncpack-format": "dist/bin-format.js",
98
"syncpack-fix-mismatches": "dist/bin-fix-mismatches.js",
9+
"syncpack-format": "dist/bin-format.js",
1010
"syncpack-list-mismatches": "dist/bin-list-mismatches.js",
11-
"syncpack-list": "dist/bin-list.js"
11+
"syncpack-list": "dist/bin-list.js",
12+
"syncpack-set-semver-ranges": "dist/bin-set-semver-ranges.js"
1213
},
1314
"bugs": "https://github.com/JamieMason/syncpack/issues",
1415
"dependencies": {

src/bin-set-semver-ranges.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#!/usr/bin/env node
2+
3+
import chalk from 'chalk';
4+
import * as program from 'commander';
5+
import * as _ from 'lodash';
6+
import { relative } from 'path';
7+
import { DEFAULT_PATTERN, DEFAULT_SEMVER_RANGE, OPTION_PACKAGES, OPTION_SEMVER_RANGE } from './constants';
8+
import { setVersionRange } from './manifests';
9+
10+
program
11+
.option(OPTION_PACKAGES.spec, OPTION_PACKAGES.description)
12+
.option(OPTION_SEMVER_RANGE.spec, OPTION_SEMVER_RANGE.description)
13+
.parse(process.argv);
14+
15+
const { packages = DEFAULT_PATTERN, semverRange = DEFAULT_SEMVER_RANGE } = program;
16+
17+
setVersionRange(semverRange, packages).then((descriptors) => {
18+
_.each(descriptors, (descriptor) => {
19+
console.log(chalk.blue(`./${relative('.', descriptor.path)}`));
20+
});
21+
});

src/bin.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
#!/usr/bin/env node
22

33
import * as program from 'commander';
4-
import { FIX_MISMATCHES, FORMAT, LIST, LIST_MISMATCHES, VERSION } from './constants';
4+
import { FIX_MISMATCHES, FORMAT, LIST, LIST_MISMATCHES, SET_SEMVER_RANGES, VERSION } from './constants';
55

66
program
77
.version(VERSION)
88
.command(FIX_MISMATCHES.name, FIX_MISMATCHES.description)
99
.command(FORMAT.name, FORMAT.description)
1010
.command(LIST.name, LIST.description, { isDefault: true })
11-
.command(LIST_MISMATCHES.name, LIST_MISMATCHES.description);
11+
.command(LIST_MISMATCHES.name, LIST_MISMATCHES.description)
12+
.command(SET_SEMVER_RANGES.name, SET_SEMVER_RANGES.description);
1213

1314
program.parse(process.argv);

src/constants.ts

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,33 @@
11
import { IManifestKey } from './typings';
22

3+
export const DEPENDENCY_TYPES: IManifestKey[] = ['dependencies', 'devDependencies', 'peerDependencies'];
4+
export const SORT_AZ = ['dependencies', 'devDependencies', 'files', 'keywords', 'peerDependencies', 'scripts'];
5+
export const SORT_FIRST = ['name', 'description', 'version', 'author'];
6+
export const VERSION = require('../package.json').version;
7+
export const GREATER = 1;
8+
export const LESSER = -1;
9+
export const SAME = 0;
10+
export const RANGE_ANY = '*';
11+
export const RANGE_EXACT = '';
12+
export const RANGE_GT = '>';
13+
export const RANGE_GTE = '>=';
14+
export const RANGE_LOOSE = '.x';
15+
export const RANGE_LT = '<';
16+
export const RANGE_LTE = '<=';
17+
export const RANGE_MINOR = '^';
18+
export const RANGE_PATCH = '~';
19+
20+
export const SEMVER_ORDER = [
21+
RANGE_LT,
22+
RANGE_LTE,
23+
RANGE_EXACT,
24+
RANGE_PATCH,
25+
RANGE_MINOR,
26+
RANGE_GTE,
27+
RANGE_GT,
28+
RANGE_ANY
29+
];
30+
331
export const FIX_MISMATCHES = {
432
description: 'set dependencies used with different versions to the same version',
533
name: 'fix-mismatches'
@@ -16,16 +44,20 @@ export const LIST_MISMATCHES = {
1644
description: 'list every dependency used with different versions in your packages',
1745
name: 'list-mismatches'
1846
};
47+
export const SET_SEMVER_RANGES = {
48+
description: 'set semver ranges to the given format',
49+
name: 'set-semver-ranges'
50+
};
51+
1952
export const DEFAULT_PATTERN = './packages/*/package.json';
20-
export const DEPENDENCY_TYPES: IManifestKey[] = ['dependencies', 'devDependencies', 'peerDependencies'];
21-
export const GREATER = 1;
22-
export const LESSER = -1;
53+
export const DEFAULT_SEMVER_RANGE = RANGE_EXACT;
2354
export const OPTION_PACKAGES = {
24-
description: `location of packages, defaults to "${DEFAULT_PATTERN}"`,
55+
description: `location of packages. defaults to '${DEFAULT_PATTERN}'`,
2556
spec: '-p, --packages <glob>'
2657
};
27-
export const SAME = 0;
28-
export const SEMVER_ORDER = ['<', '<=', '', '~', '^', '>=', '>', '*'];
29-
export const SORT_AZ = ['dependencies', 'devDependencies', 'files', 'keywords', 'peerDependencies', 'scripts'];
30-
export const SORT_FIRST = ['name', 'description', 'version', 'author'];
31-
export const VERSION = require('../package.json').version;
58+
export const OPTION_SEMVER_RANGE = {
59+
description: `${[RANGE_ANY, RANGE_EXACT, RANGE_GT, RANGE_GTE, RANGE_LOOSE, RANGE_LT, RANGE_LTE, RANGE_MINOR]
60+
.map((value) => `'${value}'`)
61+
.join(', ')}, or '${RANGE_PATCH}'. defaults to '${DEFAULT_SEMVER_RANGE}'`,
62+
spec: '-r, --semver-range <range>'
63+
};

src/manifests/index.ts

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ export type SetVersionsToNewestMismatch = (pattern: string) => Promise<IManifest
1212

1313
const unwrap = (descriptors: IManifestDescriptor[]) => descriptors.map((descriptor) => descriptor.data);
1414

15+
const writeDescriptors = (descriptors: IManifestDescriptor[]): Promise<IManifestDescriptor[]> =>
16+
Promise.all(descriptors.map((descriptor) => writeJson(descriptor.path, descriptor.data))).then(() => descriptors);
17+
1518
export const format: Format = (pattern) =>
1619
getManifests(pattern)
1720
.then((descriptors) => {
@@ -22,9 +25,7 @@ export const format: Format = (pattern) =>
2225
path: descriptor.path
2326
}));
2427
})
25-
.then((descriptors) =>
26-
Promise.all(descriptors.map((descriptor) => writeJson(descriptor.path, descriptor.data))).then(() => descriptors)
27-
);
28+
.then(writeDescriptors);
2829

2930
export const getMismatchedVersions: GetMismatchedVersions = (pattern) =>
3031
getManifests(pattern)
@@ -43,10 +44,12 @@ export const setVersion: SetVersion = (name, version, pattern) =>
4344
});
4445

4546
export const setVersionRange: SetVersionRange = (range, pattern) =>
46-
getManifests(pattern).then((descriptors) => {
47-
manifestData.setVersionRange(range, unwrap(descriptors));
48-
return descriptors;
49-
});
47+
getManifests(pattern)
48+
.then((descriptors) => {
49+
manifestData.setVersionRange(range, unwrap(descriptors));
50+
return descriptors;
51+
})
52+
.then(writeDescriptors);
5053

5154
export const setVersionsToNewestMismatch: SetVersionsToNewestMismatch = (pattern) =>
5255
getManifests(pattern)
@@ -58,6 +61,4 @@ export const setVersionsToNewestMismatch: SetVersionsToNewestMismatch = (pattern
5861
path: descriptor.path
5962
}));
6063
})
61-
.then((descriptors) =>
62-
Promise.all(descriptors.map((descriptor) => writeJson(descriptor.path, descriptor.data))).then(() => descriptors)
63-
);
64+
.then(writeDescriptors);

src/manifests/manifest-data/index.spec.ts

Lines changed: 69 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,47 @@
1+
import {
2+
getAnyVersionManifests,
3+
getExactVersionManifests,
4+
getGreaterThanOrEqualVersionManifests,
5+
getGreaterThanVersionManifests,
6+
getLessThanOrEqualVersionManifests,
7+
getLessThanVersionManifests,
8+
getLooseVersionManifests,
9+
getMinorVersionManifests,
10+
getPatchVersionManifests
11+
} from '../../../test/fixtures';
112
import { createManifest } from '../../../test/helpers';
13+
import {
14+
RANGE_ANY,
15+
RANGE_EXACT,
16+
RANGE_GT,
17+
RANGE_GTE,
18+
RANGE_LOOSE,
19+
RANGE_LT,
20+
RANGE_LTE,
21+
RANGE_MINOR,
22+
RANGE_PATCH
23+
} from '../../constants';
224
import { IManifest } from '../../typings';
325
import { manifestData } from './index';
426

527
const { getMismatchedVersions, getVersions, setVersion, setVersionRange, setVersionsToNewestMismatch } = manifestData;
628

7-
let mockManifests: IManifest[] = [];
8-
9-
beforeEach(() => {
10-
mockManifests = [
11-
createManifest(
12-
'foo',
13-
{ chalk: '2.3.0', commander: '2.13.0' },
14-
{ jest: '22.1.3', prettier: '1.10.2', rimraf: '2.6.2' },
15-
{ gulp: '3.9.1' }
16-
),
17-
createManifest('bar', { chalk: '1.0.0' }, { jest: '22.1.4' }),
18-
createManifest('baz', null, { npm: 'https://github.com/npm/npm.git', prettier: '1.10.2' }, { gulp: '*' })
19-
];
20-
});
21-
2229
describe('getMismatchedVersions', () => {
2330
it('returns an index of dependencies used with different versions', () => {
24-
expect(getMismatchedVersions(mockManifests)).toEqual({
31+
expect(getMismatchedVersions(getExactVersionManifests())).toEqual({
2532
chalk: ['1.0.0', '2.3.0'],
26-
gulp: ['*', '3.9.1'],
33+
gulp: ['*', '0.9.1'],
2734
jest: ['22.1.3', '22.1.4']
2835
});
2936
});
3037
});
3138

3239
describe('getVersions', () => {
3340
it('returns an index of every unique dependency in use', () => {
34-
expect(getVersions(mockManifests)).toEqual({
41+
expect(getVersions(getExactVersionManifests())).toEqual({
3542
chalk: ['1.0.0', '2.3.0'],
3643
commander: ['2.13.0'],
37-
gulp: ['*', '3.9.1'],
44+
gulp: ['*', '0.9.1'],
3845
jest: ['22.1.3', '22.1.4'],
3946
npm: ['https://github.com/npm/npm.git'],
4047
prettier: ['1.10.2'],
@@ -45,12 +52,12 @@ describe('getVersions', () => {
4552

4653
describe('setVersion', () => {
4754
it('sets the version of a named dependency when it is found', () => {
48-
expect(setVersion('jest', '25.0.0', mockManifests)).toEqual([
55+
expect(setVersion('jest', '25.0.0', getExactVersionManifests())).toEqual([
4956
createManifest(
5057
'foo',
5158
{ chalk: '2.3.0', commander: '2.13.0' },
5259
{ jest: '25.0.0', prettier: '1.10.2', rimraf: '2.6.2' },
53-
{ gulp: '3.9.1' }
60+
{ gulp: '0.9.1' }
5461
),
5562
createManifest('bar', { chalk: '1.0.0' }, { jest: '25.0.0' }),
5663
createManifest('baz', null, { npm: 'https://github.com/npm/npm.git', prettier: '1.10.2' }, { gulp: '*' })
@@ -59,23 +66,52 @@ describe('setVersion', () => {
5966
});
6067

6168
describe('setVersionRange', () => {
62-
it('sets the version range of all semver dependencies', () => {
63-
expect(setVersionRange('^', mockManifests)).toEqual([
64-
createManifest(
65-
'foo',
66-
{ chalk: '^2.3.0', commander: '^2.13.0' },
67-
{ jest: '^22.1.3', prettier: '^1.10.2', rimraf: '^2.6.2' },
68-
{ gulp: '^3.9.1' }
69-
),
70-
createManifest('bar', { chalk: '^1.0.0' }, { jest: '^22.1.4' }),
71-
createManifest('baz', null, { npm: 'https://github.com/npm/npm.git', prettier: '^1.10.2' }, { gulp: '*' })
72-
]);
69+
const assertRange = (inputRange: string, expectedManifests: IManifest[]) => {
70+
[
71+
getExactVersionManifests(),
72+
getGreaterThanVersionManifests(),
73+
getGreaterThanOrEqualVersionManifests(),
74+
getLessThanVersionManifests(),
75+
getLessThanOrEqualVersionManifests(),
76+
getMinorVersionManifests(),
77+
getPatchVersionManifests()
78+
].forEach((inputManifests) => {
79+
expect(setVersionRange(inputRange, inputManifests)).toEqual(expectedManifests);
80+
});
81+
};
82+
83+
it(`sets semver ranges to the "${RANGE_ANY}" format`, () => {
84+
assertRange(RANGE_ANY, getAnyVersionManifests());
85+
});
86+
it(`sets semver ranges to the "${RANGE_EXACT}" format`, () => {
87+
assertRange(RANGE_EXACT, getExactVersionManifests());
88+
});
89+
it(`sets semver ranges to the "${RANGE_GT}" format`, () => {
90+
assertRange(RANGE_GT, getGreaterThanVersionManifests());
91+
});
92+
it(`sets semver ranges to the "${RANGE_GTE}" format`, () => {
93+
assertRange(RANGE_GTE, getGreaterThanOrEqualVersionManifests());
94+
});
95+
it(`sets semver ranges to the "${RANGE_LOOSE}" format`, () => {
96+
assertRange(RANGE_LOOSE, getLooseVersionManifests());
97+
});
98+
it(`sets semver ranges to the "${RANGE_LT}" format`, () => {
99+
assertRange(RANGE_LT, getLessThanVersionManifests());
100+
});
101+
it(`sets semver ranges to the "${RANGE_LTE}" format`, () => {
102+
assertRange(RANGE_LTE, getLessThanOrEqualVersionManifests());
103+
});
104+
it(`sets semver ranges to the "${RANGE_MINOR}" format`, () => {
105+
assertRange(RANGE_MINOR, getMinorVersionManifests());
106+
});
107+
it(`sets semver ranges to the "${RANGE_PATCH}" format`, () => {
108+
assertRange(RANGE_PATCH, getPatchVersionManifests());
73109
});
74110
});
75111

76112
describe('setVersionsToNewestMismatch', () => {
77113
it('sets the version of dependencies with different versions to the newest of those versions found', () => {
78-
expect(setVersionsToNewestMismatch(mockManifests)).toEqual([
114+
expect(setVersionsToNewestMismatch(getExactVersionManifests())).toEqual([
79115
createManifest(
80116
'foo',
81117
{ chalk: '2.3.0', commander: '2.13.0' },

src/manifests/manifest-data/index.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import * as _ from 'lodash';
22
import * as semver from 'semver';
3-
import { DEPENDENCY_TYPES } from '../../constants';
3+
import { DEPENDENCY_TYPES, RANGE_ANY, RANGE_LOOSE } from '../../constants';
44
import { IDictionary, IManifest } from '../../typings';
5-
import { getNewest, isValid } from '../../version';
5+
import { getNewest, getVersionNumber } from '../../version';
66
import { format } from './format';
77

88
export type GetMismatchedVersions = (manifests: IManifest[]) => IDictionary<string[]>;
@@ -75,8 +75,18 @@ const setVersionRange: SetVersionRange = (range, manifests) => {
7575
.filter(Boolean)
7676
.each((dependencies) => {
7777
_(dependencies).each((version, name) => {
78-
if (isValid(version)) {
79-
dependencies[name] = `${range}${semver.clean(version)}`;
78+
const versionNumber = getVersionNumber(version);
79+
if (version !== '*' && semver.validRange(version)) {
80+
if (range === RANGE_ANY) {
81+
dependencies[name] = '*';
82+
} else if (range === RANGE_LOOSE) {
83+
dependencies[name] =
84+
semver.major(versionNumber) === 0
85+
? `${semver.major(versionNumber)}.${semver.minor(versionNumber)}.x`
86+
: `${semver.major(versionNumber)}.x.x`;
87+
} else {
88+
dependencies[name] = `${range}${versionNumber}`;
89+
}
8090
}
8191
});
8292
})

0 commit comments

Comments
 (0)