Skip to content

Commit

Permalink
feat(core): add set-semver-ranges command
Browse files Browse the repository at this point in the history
  • Loading branch information
JamieMason committed Apr 28, 2018
1 parent 103e6f6 commit 4d206b9
Show file tree
Hide file tree
Showing 9 changed files with 267 additions and 68 deletions.
18 changes: 10 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,17 @@ npm install --global syncpack
```
Usage: syncpack [options] [command]
Options:
Options:
-V, --version output the version number
-h, --help output usage information
-V, --version output the version number
-h, --help output usage information
Commands:
Commands:
fix-mismatches set dependencies used with different versions to the same version
list list every dependency used in your packages
list-mismatches list every dependency used with different versions in your packages
help [cmd] display help for [cmd]
fix-mismatches set dependencies used with different versions to the same version
format sort and shorten properties according to a convention
list list every dependency used in your packages
list-mismatches list every dependency used with different versions in your packages
set-semver-ranges set semver ranges to the given format
help [cmd] display help for [cmd]
```
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@
"author": "Jamie Mason <jamie@foldleft.io> (https://github.com/JamieMason)",
"bin": {
"syncpack": "dist/bin.js",
"syncpack-format": "dist/bin-format.js",
"syncpack-fix-mismatches": "dist/bin-fix-mismatches.js",
"syncpack-format": "dist/bin-format.js",
"syncpack-list-mismatches": "dist/bin-list-mismatches.js",
"syncpack-list": "dist/bin-list.js"
"syncpack-list": "dist/bin-list.js",
"syncpack-set-semver-ranges": "dist/bin-set-semver-ranges.js"
},
"bugs": "https://github.com/JamieMason/syncpack/issues",
"dependencies": {
Expand Down
21 changes: 21 additions & 0 deletions src/bin-set-semver-ranges.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/usr/bin/env node

import chalk from 'chalk';
import * as program from 'commander';
import * as _ from 'lodash';
import { relative } from 'path';
import { DEFAULT_PATTERN, DEFAULT_SEMVER_RANGE, OPTION_PACKAGES, OPTION_SEMVER_RANGE } from './constants';
import { setVersionRange } from './manifests';

program
.option(OPTION_PACKAGES.spec, OPTION_PACKAGES.description)
.option(OPTION_SEMVER_RANGE.spec, OPTION_SEMVER_RANGE.description)
.parse(process.argv);

const { packages = DEFAULT_PATTERN, semverRange = DEFAULT_SEMVER_RANGE } = program;

setVersionRange(semverRange, packages).then((descriptors) => {
_.each(descriptors, (descriptor) => {
console.log(chalk.blue(`./${relative('.', descriptor.path)}`));
});
});
5 changes: 3 additions & 2 deletions src/bin.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
#!/usr/bin/env node

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

program
.version(VERSION)
.command(FIX_MISMATCHES.name, FIX_MISMATCHES.description)
.command(FORMAT.name, FORMAT.description)
.command(LIST.name, LIST.description, { isDefault: true })
.command(LIST_MISMATCHES.name, LIST_MISMATCHES.description);
.command(LIST_MISMATCHES.name, LIST_MISMATCHES.description)
.command(SET_SEMVER_RANGES.name, SET_SEMVER_RANGES.description);

program.parse(process.argv);
50 changes: 41 additions & 9 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,33 @@
import { IManifestKey } from './typings';

export const DEPENDENCY_TYPES: IManifestKey[] = ['dependencies', 'devDependencies', 'peerDependencies'];
export const SORT_AZ = ['dependencies', 'devDependencies', 'files', 'keywords', 'peerDependencies', 'scripts'];
export const SORT_FIRST = ['name', 'description', 'version', 'author'];
export const VERSION = require('../package.json').version;
export const GREATER = 1;
export const LESSER = -1;
export const SAME = 0;
export const RANGE_ANY = '*';
export const RANGE_EXACT = '';
export const RANGE_GT = '>';
export const RANGE_GTE = '>=';
export const RANGE_LOOSE = '.x';
export const RANGE_LT = '<';
export const RANGE_LTE = '<=';
export const RANGE_MINOR = '^';
export const RANGE_PATCH = '~';

export const SEMVER_ORDER = [
RANGE_LT,
RANGE_LTE,
RANGE_EXACT,
RANGE_PATCH,
RANGE_MINOR,
RANGE_GTE,
RANGE_GT,
RANGE_ANY
];

export const FIX_MISMATCHES = {
description: 'set dependencies used with different versions to the same version',
name: 'fix-mismatches'
Expand All @@ -16,16 +44,20 @@ export const LIST_MISMATCHES = {
description: 'list every dependency used with different versions in your packages',
name: 'list-mismatches'
};
export const SET_SEMVER_RANGES = {
description: 'set semver ranges to the given format',
name: 'set-semver-ranges'
};

export const DEFAULT_PATTERN = './packages/*/package.json';
export const DEPENDENCY_TYPES: IManifestKey[] = ['dependencies', 'devDependencies', 'peerDependencies'];
export const GREATER = 1;
export const LESSER = -1;
export const DEFAULT_SEMVER_RANGE = RANGE_EXACT;
export const OPTION_PACKAGES = {
description: `location of packages, defaults to "${DEFAULT_PATTERN}"`,
description: `location of packages. defaults to '${DEFAULT_PATTERN}'`,
spec: '-p, --packages <glob>'
};
export const SAME = 0;
export const SEMVER_ORDER = ['<', '<=', '', '~', '^', '>=', '>', '*'];
export const SORT_AZ = ['dependencies', 'devDependencies', 'files', 'keywords', 'peerDependencies', 'scripts'];
export const SORT_FIRST = ['name', 'description', 'version', 'author'];
export const VERSION = require('../package.json').version;
export const OPTION_SEMVER_RANGE = {
description: `${[RANGE_ANY, RANGE_EXACT, RANGE_GT, RANGE_GTE, RANGE_LOOSE, RANGE_LT, RANGE_LTE, RANGE_MINOR]
.map((value) => `'${value}'`)
.join(', ')}, or '${RANGE_PATCH}'. defaults to '${DEFAULT_SEMVER_RANGE}'`,
spec: '-r, --semver-range <range>'
};
21 changes: 11 additions & 10 deletions src/manifests/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ export type SetVersionsToNewestMismatch = (pattern: string) => Promise<IManifest

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

const writeDescriptors = (descriptors: IManifestDescriptor[]): Promise<IManifestDescriptor[]> =>
Promise.all(descriptors.map((descriptor) => writeJson(descriptor.path, descriptor.data))).then(() => descriptors);

export const format: Format = (pattern) =>
getManifests(pattern)
.then((descriptors) => {
Expand All @@ -22,9 +25,7 @@ export const format: Format = (pattern) =>
path: descriptor.path
}));
})
.then((descriptors) =>
Promise.all(descriptors.map((descriptor) => writeJson(descriptor.path, descriptor.data))).then(() => descriptors)
);
.then(writeDescriptors);

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

export const setVersionRange: SetVersionRange = (range, pattern) =>
getManifests(pattern).then((descriptors) => {
manifestData.setVersionRange(range, unwrap(descriptors));
return descriptors;
});
getManifests(pattern)
.then((descriptors) => {
manifestData.setVersionRange(range, unwrap(descriptors));
return descriptors;
})
.then(writeDescriptors);

export const setVersionsToNewestMismatch: SetVersionsToNewestMismatch = (pattern) =>
getManifests(pattern)
Expand All @@ -58,6 +61,4 @@ export const setVersionsToNewestMismatch: SetVersionsToNewestMismatch = (pattern
path: descriptor.path
}));
})
.then((descriptors) =>
Promise.all(descriptors.map((descriptor) => writeJson(descriptor.path, descriptor.data))).then(() => descriptors)
);
.then(writeDescriptors);
102 changes: 69 additions & 33 deletions src/manifests/manifest-data/index.spec.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,47 @@
import {
getAnyVersionManifests,
getExactVersionManifests,
getGreaterThanOrEqualVersionManifests,
getGreaterThanVersionManifests,
getLessThanOrEqualVersionManifests,
getLessThanVersionManifests,
getLooseVersionManifests,
getMinorVersionManifests,
getPatchVersionManifests
} from '../../../test/fixtures';
import { createManifest } from '../../../test/helpers';
import {
RANGE_ANY,
RANGE_EXACT,
RANGE_GT,
RANGE_GTE,
RANGE_LOOSE,
RANGE_LT,
RANGE_LTE,
RANGE_MINOR,
RANGE_PATCH
} from '../../constants';
import { IManifest } from '../../typings';
import { manifestData } from './index';

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

let mockManifests: IManifest[] = [];

beforeEach(() => {
mockManifests = [
createManifest(
'foo',
{ chalk: '2.3.0', commander: '2.13.0' },
{ jest: '22.1.3', prettier: '1.10.2', rimraf: '2.6.2' },
{ gulp: '3.9.1' }
),
createManifest('bar', { chalk: '1.0.0' }, { jest: '22.1.4' }),
createManifest('baz', null, { npm: 'https://github.com/npm/npm.git', prettier: '1.10.2' }, { gulp: '*' })
];
});

describe('getMismatchedVersions', () => {
it('returns an index of dependencies used with different versions', () => {
expect(getMismatchedVersions(mockManifests)).toEqual({
expect(getMismatchedVersions(getExactVersionManifests())).toEqual({
chalk: ['1.0.0', '2.3.0'],
gulp: ['*', '3.9.1'],
gulp: ['*', '0.9.1'],
jest: ['22.1.3', '22.1.4']
});
});
});

describe('getVersions', () => {
it('returns an index of every unique dependency in use', () => {
expect(getVersions(mockManifests)).toEqual({
expect(getVersions(getExactVersionManifests())).toEqual({
chalk: ['1.0.0', '2.3.0'],
commander: ['2.13.0'],
gulp: ['*', '3.9.1'],
gulp: ['*', '0.9.1'],
jest: ['22.1.3', '22.1.4'],
npm: ['https://github.com/npm/npm.git'],
prettier: ['1.10.2'],
Expand All @@ -45,12 +52,12 @@ describe('getVersions', () => {

describe('setVersion', () => {
it('sets the version of a named dependency when it is found', () => {
expect(setVersion('jest', '25.0.0', mockManifests)).toEqual([
expect(setVersion('jest', '25.0.0', getExactVersionManifests())).toEqual([
createManifest(
'foo',
{ chalk: '2.3.0', commander: '2.13.0' },
{ jest: '25.0.0', prettier: '1.10.2', rimraf: '2.6.2' },
{ gulp: '3.9.1' }
{ gulp: '0.9.1' }
),
createManifest('bar', { chalk: '1.0.0' }, { jest: '25.0.0' }),
createManifest('baz', null, { npm: 'https://github.com/npm/npm.git', prettier: '1.10.2' }, { gulp: '*' })
Expand All @@ -59,23 +66,52 @@ describe('setVersion', () => {
});

describe('setVersionRange', () => {
it('sets the version range of all semver dependencies', () => {
expect(setVersionRange('^', mockManifests)).toEqual([
createManifest(
'foo',
{ chalk: '^2.3.0', commander: '^2.13.0' },
{ jest: '^22.1.3', prettier: '^1.10.2', rimraf: '^2.6.2' },
{ gulp: '^3.9.1' }
),
createManifest('bar', { chalk: '^1.0.0' }, { jest: '^22.1.4' }),
createManifest('baz', null, { npm: 'https://github.com/npm/npm.git', prettier: '^1.10.2' }, { gulp: '*' })
]);
const assertRange = (inputRange: string, expectedManifests: IManifest[]) => {
[
getExactVersionManifests(),
getGreaterThanVersionManifests(),
getGreaterThanOrEqualVersionManifests(),
getLessThanVersionManifests(),
getLessThanOrEqualVersionManifests(),
getMinorVersionManifests(),
getPatchVersionManifests()
].forEach((inputManifests) => {
expect(setVersionRange(inputRange, inputManifests)).toEqual(expectedManifests);
});
};

it(`sets semver ranges to the "${RANGE_ANY}" format`, () => {
assertRange(RANGE_ANY, getAnyVersionManifests());
});
it(`sets semver ranges to the "${RANGE_EXACT}" format`, () => {
assertRange(RANGE_EXACT, getExactVersionManifests());
});
it(`sets semver ranges to the "${RANGE_GT}" format`, () => {
assertRange(RANGE_GT, getGreaterThanVersionManifests());
});
it(`sets semver ranges to the "${RANGE_GTE}" format`, () => {
assertRange(RANGE_GTE, getGreaterThanOrEqualVersionManifests());
});
it(`sets semver ranges to the "${RANGE_LOOSE}" format`, () => {
assertRange(RANGE_LOOSE, getLooseVersionManifests());
});
it(`sets semver ranges to the "${RANGE_LT}" format`, () => {
assertRange(RANGE_LT, getLessThanVersionManifests());
});
it(`sets semver ranges to the "${RANGE_LTE}" format`, () => {
assertRange(RANGE_LTE, getLessThanOrEqualVersionManifests());
});
it(`sets semver ranges to the "${RANGE_MINOR}" format`, () => {
assertRange(RANGE_MINOR, getMinorVersionManifests());
});
it(`sets semver ranges to the "${RANGE_PATCH}" format`, () => {
assertRange(RANGE_PATCH, getPatchVersionManifests());
});
});

describe('setVersionsToNewestMismatch', () => {
it('sets the version of dependencies with different versions to the newest of those versions found', () => {
expect(setVersionsToNewestMismatch(mockManifests)).toEqual([
expect(setVersionsToNewestMismatch(getExactVersionManifests())).toEqual([
createManifest(
'foo',
{ chalk: '2.3.0', commander: '2.13.0' },
Expand Down
18 changes: 14 additions & 4 deletions src/manifests/manifest-data/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import * as _ from 'lodash';
import * as semver from 'semver';
import { DEPENDENCY_TYPES } from '../../constants';
import { DEPENDENCY_TYPES, RANGE_ANY, RANGE_LOOSE } from '../../constants';
import { IDictionary, IManifest } from '../../typings';
import { getNewest, isValid } from '../../version';
import { getNewest, getVersionNumber } from '../../version';
import { format } from './format';

export type GetMismatchedVersions = (manifests: IManifest[]) => IDictionary<string[]>;
Expand Down Expand Up @@ -75,8 +75,18 @@ const setVersionRange: SetVersionRange = (range, manifests) => {
.filter(Boolean)
.each((dependencies) => {
_(dependencies).each((version, name) => {
if (isValid(version)) {
dependencies[name] = `${range}${semver.clean(version)}`;
const versionNumber = getVersionNumber(version);
if (version !== '*' && semver.validRange(version)) {
if (range === RANGE_ANY) {
dependencies[name] = '*';
} else if (range === RANGE_LOOSE) {
dependencies[name] =
semver.major(versionNumber) === 0
? `${semver.major(versionNumber)}.${semver.minor(versionNumber)}.x`
: `${semver.major(versionNumber)}.x.x`;
} else {
dependencies[name] = `${range}${versionNumber}`;
}
}
});
})
Expand Down
Loading

0 comments on commit 4d206b9

Please sign in to comment.