Skip to content

Commit 1a67546

Browse files
hanslfilipesilva
authored andcommitted
fix(@schematics/update): allow beta versions to be valid peer
Before this fix, the beta would not satisfy the updated range. Since Angular released a beta today it uncovered this issue.
1 parent f441a48 commit 1a67546

File tree

2 files changed

+53
-22
lines changed

2 files changed

+53
-22
lines changed

packages/schematics/update/update/index.ts

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -25,29 +25,39 @@ import { UpdateSchema } from './schema';
2525
type VersionRange = string & { __VERSION_RANGE: void; };
2626
type PeerVersionTransform = string | ((range: string) => string);
2727

28-
// This is a map of packageGroupName to range extending function. If it isn't found, the range is
29-
// kept the same.
28+
3029
// Angular guarantees that a major is compatible with its following major (so packages that depend
3130
// on Angular 5 are also compatible with Angular 6). This is, in code, represented by verifying
3231
// that all other packages that have a peer dependency of `"@angular/core": "^5.0.0"` actually
3332
// supports 6.0, by adding that compatibility to the range, so it is `^5.0.0 || ^6.0.0`.
34-
const peerCompatibleWhitelist: { [name: string]: PeerVersionTransform } = {
35-
'@angular/core': (range: string) => {
36-
range = semver.validRange(range);
37-
let major = 1;
38-
while (!semver.gtr(major + '.0.0', range)) {
39-
major++;
40-
if (major >= 99) {
41-
// Use original range if it supports a major this high
42-
// Range is most likely unbounded (e.g., >=5.0.0)
43-
return range;
44-
}
33+
// We export it to allow for testing.
34+
export function angularMajorCompatGuarantee(range: string) {
35+
range = semver.validRange(range);
36+
let major = 1;
37+
while (!semver.gtr(major + '.0.0', range)) {
38+
major++;
39+
if (major >= 99) {
40+
// Use original range if it supports a major this high
41+
// Range is most likely unbounded (e.g., >=5.0.0)
42+
return range;
4543
}
44+
}
45+
46+
// Add the major version as compatible with the angular compatible, with all minors. This is
47+
// already one major above the greatest supported, because we increment `major` before checking.
48+
let newRange = range;
49+
for (let minor = 0; minor < 20; minor++) {
50+
newRange += ` || ^${major}.${minor}.0-alpha.0`;
51+
}
52+
53+
return semver.validRange(newRange) || range;
54+
}
55+
4656

47-
// Add the major version as compatible with the angular compatible. This is already one
48-
// major above the greatest supported, because we increment `major` before checking.
49-
return semver.validRange(`^${major}.0.0-rc.0 || ${range}`) || range;
50-
},
57+
// This is a map of packageGroupName to range extending function. If it isn't found, the range is
58+
// kept the same.
59+
const peerCompatibleWhitelist: { [name: string]: PeerVersionTransform } = {
60+
'@angular/core': angularMajorCompatGuarantee,
5161
};
5262

5363
interface PackageVersionInfo {
@@ -143,20 +153,21 @@ function _validateReversePeerDependencies(
143153
installedLogger.debug(`${installed}...`);
144154
const peers = (installedInfo.target || installedInfo.installed).packageJson.peerDependencies;
145155

146-
for (let [peer, range] of Object.entries(peers || {})) {
156+
for (const [peer, range] of Object.entries(peers || {})) {
147157
if (peer != name) {
148158
// Only check peers to the packages we're updating. We don't care about peers
149159
// that are unmet but we have no effect on.
150160
continue;
151161
}
152162

153163
// Override the peer version range if it's whitelisted.
154-
range = _updatePeerVersion(infoMap, peer, range);
164+
const extendedRange = _updatePeerVersion(infoMap, peer, range);
155165

156-
if (!semver.satisfies(version, range)) {
166+
if (!semver.satisfies(version, extendedRange)) {
157167
logger.error([
158168
`Package ${JSON.stringify(installed)} has an incompatible peer dependency to`,
159-
`${JSON.stringify(name)} (requires ${JSON.stringify(range)},`,
169+
`${JSON.stringify(name)} (requires`,
170+
`${JSON.stringify(range)}${extendedRange == range ? '' : ' (extended)'},`,
160171
`would install ${JSON.stringify(version)}).`,
161172
].join(' '));
162173

packages/schematics/update/update/index_spec.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,28 @@ import { normalize, virtualFs } from '@angular-devkit/core';
99
import { HostTree, VirtualTree } from '@angular-devkit/schematics';
1010
import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing';
1111
import { map } from 'rxjs/operators';
12+
import * as semver from 'semver';
13+
import { angularMajorCompatGuarantee } from './index';
1214

1315

16+
describe('angularMajorCompatGuarantee', () => {
17+
[
18+
'5.0.0',
19+
'5.1.0',
20+
'5.20.0',
21+
'6.0.0',
22+
'6.0.0-rc.0',
23+
'6.0.0-beta.0',
24+
'6.1.0-beta.0',
25+
'6.1.0-rc.0',
26+
'6.10.11',
27+
].forEach(golden => {
28+
it('works with ' + JSON.stringify(golden), () => {
29+
expect(semver.satisfies(golden, angularMajorCompatGuarantee('^5.0.0'))).toBeTruthy();
30+
});
31+
});
32+
});
33+
1434
describe('@schematics/update', () => {
1535
const schematicRunner = new SchematicTestRunner(
1636
'@schematics/update', __dirname + '/../collection.json',
@@ -180,7 +200,7 @@ describe('@schematics/update', () => {
180200
expect(packageJson['dependencies']['@angular/core'][0]).toBe('6');
181201
expect(packageJson['dependencies']['rxjs'][0]).toBe('6');
182202
expect(packageJson['dependencies']['typescript'][0]).toBe('2');
183-
expect(packageJson['dependencies']['typescript'][2]).toBe('7');
203+
expect(packageJson['dependencies']['typescript'][2]).not.toBe('4');
184204

185205
// Check install task.
186206
expect(schematicRunner.tasks).toEqual([

0 commit comments

Comments
 (0)