Skip to content

Commit

Permalink
feat(build): Upgrade to TypeScript 2.9 and rxjs6 (angular#1122)
Browse files Browse the repository at this point in the history
This includes a migration to TS2.9, and a migration to RxJS 6 (which is required for TS2.9 support).
  • Loading branch information
JiaLiPassion authored and mhevery committed Sep 6, 2018
1 parent 9c96904 commit 31fc127
Show file tree
Hide file tree
Showing 52 changed files with 669 additions and 734 deletions.
1 change: 1 addition & 0 deletions karma-base.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ module.exports = function(config) {
{pattern: 'node_modules/rxjs/**/**/*.js.map', included: false, watched: false},
{pattern: 'node_modules/rxjs/**/*.js', included: false, watched: false},
{pattern: 'node_modules/es6-promise/**/*.js', included: false, watched: false},
{pattern: 'node_modules/core-js/**/*.js', included: false, watched: false},
{pattern: 'node_modules/rxjs/**/*.js.map', included: false, watched: false},
{pattern: 'test/assets/**/*.*', watched: true, served: true, included: false},
{pattern: 'build/**/*.js.map', watched: true, served: true, included: false},
Expand Down
8 changes: 3 additions & 5 deletions lib/rxjs/rxjs-fake-async.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,16 @@
* found in the LICENSE file at https://angular.io/license
*/

import {Scheduler} from 'rxjs/Scheduler';
import {asap} from 'rxjs/scheduler/asap';
import {async} from 'rxjs/scheduler/async';
import {asapScheduler, asyncScheduler, Scheduler} from 'rxjs';

Zone.__load_patch('rxjs.Scheduler.now', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
api.patchMethod(Scheduler, 'now', (delegate: Function) => (self: any, args: any[]) => {
return Date.now.apply(self, args);
});
api.patchMethod(async, 'now', (delegate: Function) => (self: any, args: any[]) => {
api.patchMethod(asyncScheduler, 'now', (delegate: Function) => (self: any, args: any[]) => {
return Date.now.apply(self, args);
});
api.patchMethod(asap, 'now', (delegate: Function) => (self: any, args: any[]) => {
api.patchMethod(asapScheduler, 'now', (delegate: Function) => (self: any, args: any[]) => {
return Date.now.apply(self, args);
});
});
278 changes: 52 additions & 226 deletions lib/rxjs/rxjs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,61 +6,20 @@
* found in the LICENSE file at https://angular.io/license
*/

import 'rxjs/add/observable/bindCallback';
import 'rxjs/add/observable/bindNodeCallback';
import 'rxjs/add/observable/defer';
import 'rxjs/add/observable/forkJoin';
import 'rxjs/add/observable/fromEventPattern';
import 'rxjs/add/operator/multicast';
import {Observable, Subscriber, Subscription} from 'rxjs';

import {Observable} from 'rxjs/Observable';
import {asap} from 'rxjs/scheduler/asap';
import {Subscriber} from 'rxjs/Subscriber';
import {Subscription} from 'rxjs/Subscription';
import {rxSubscriber} from 'rxjs/symbol/rxSubscriber';

(Zone as any).__load_patch('rxjs', (global: any, Zone: ZoneType) => {
(Zone as any).__load_patch('rxjs', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
const symbol: (symbolString: string) => string = (Zone as any).__symbol__;
const nextSource = 'rxjs.Subscriber.next';
const errorSource = 'rxjs.Subscriber.error';
const completeSource = 'rxjs.Subscriber.complete';

const ObjectDefineProperties = Object.defineProperties;

const empty = {
closed: true,
next(value: any): void{},
error(err: any): void {
throw err;
},
complete(): void {}
};

function toSubscriber<T>(
nextOrObserver?: any, error?: (error: any) => void, complete?: () => void): Subscriber<T> {
if (nextOrObserver) {
if (nextOrObserver instanceof Subscriber) {
return (<Subscriber<T>>nextOrObserver);
}

if (nextOrObserver[rxSubscriber]) {
return nextOrObserver[rxSubscriber]();
}
}

if (!nextOrObserver && !error && !complete) {
return new Subscriber(empty);
}

return new Subscriber(nextOrObserver, error, complete);
}

const patchObservable = function() {
const ObservablePrototype: any = Observable.prototype;
const symbolSubscribe = symbol('subscribe');
const _symbolSubscribe = symbol('_subscribe');
const _subscribe = ObservablePrototype[_symbolSubscribe] = ObservablePrototype._subscribe;
const subscribe = ObservablePrototype[symbolSubscribe] = ObservablePrototype.subscribe;

ObjectDefineProperties(Observable.prototype, {
_zone: {value: null, writable: true, configurable: true},
Expand Down Expand Up @@ -89,30 +48,58 @@ import {rxSubscriber} from 'rxjs/symbol/rxSubscriber';
},
set: function(this: Observable<any>, subscribe: any) {
(this as any)._zone = Zone.current;
(this as any)._zoneSubscribe = subscribe;
(this as any)._zoneSubscribe = function() {
if (this._zone && this._zone !== Zone.current) {
const tearDown = this._zone.run(subscribe, this, arguments);
if (tearDown && typeof tearDown === 'function') {
const zone = this._zone;
return function() {
if (zone !== Zone.current) {
return zone.run(tearDown, this, arguments);
}
return tearDown.apply(this, arguments);
};
}
return tearDown;
}
return subscribe.apply(this, arguments);
};
}
},
subscribe: {
writable: true,
configurable: true,
value: function(this: Observable<any>, observerOrNext: any, error: any, complete: any) {
// Only grab a zone if we Zone exists and it is different from the current zone.
const _zone = (this as any)._zone;
if (_zone && _zone !== Zone.current) {
// Current Zone is different from the intended zone.
// Restore the zone before invoking the subscribe callback.
return _zone.run(subscribe, this, [toSubscriber(observerOrNext, error, complete)]);
}
return subscribe.call(this, observerOrNext, error, complete);
subjectFactory: {
get: function() {
return (this as any)._zoneSubjectFactory;
},
set: function(factory: any) {
const zone = this._zone;
this._zoneSubjectFactory = function() {
if (zone && zone !== Zone.current) {
return zone.run(factory, this, arguments);
}
return factory.apply(this, arguments);
};
}
}
});
};

api.patchMethod(Observable.prototype, 'lift', (delegate: any) => (self: any, args: any[]) => {
const observable: any = delegate.apply(self, args);
if (observable.operator) {
observable.operator._zone = Zone.current;
api.patchMethod(
observable.operator, 'call',
(operatorDelegate: any) => (operatorSelf: any, operatorArgs: any[]) => {
if (operatorSelf._zone && operatorSelf._zone !== Zone.current) {
return operatorSelf._zone.run(operatorDelegate, operatorSelf, operatorArgs);
}
return operatorDelegate.apply(operatorSelf, operatorArgs);
});
}
return observable;
});

const patchSubscription = function() {
const unsubscribeSymbol = symbol('unsubscribe');
const unsubscribe = (Subscription.prototype as any)[unsubscribeSymbol] =
Subscription.prototype.unsubscribe;
ObjectDefineProperties(Subscription.prototype, {
_zone: {value: null, writable: true, configurable: true},
_zoneUnsubscribe: {value: null, writable: true, configurable: true},
Expand All @@ -126,22 +113,12 @@ import {rxSubscriber} from 'rxjs/symbol/rxSubscriber';
},
set: function(this: Subscription, unsubscribe: any) {
(this as any)._zone = Zone.current;
(this as any)._zoneUnsubscribe = unsubscribe;
}
},
unsubscribe: {
writable: true,
configurable: true,
value: function(this: Subscription) {
// Only grab a zone if we Zone exists and it is different from the current zone.
const _zone: Zone = (this as any)._zone;
if (_zone && _zone !== Zone.current) {
// Current Zone is different from the intended zone.
// Restore the zone before invoking the subscribe callback.
_zone.run(unsubscribe, this);
} else {
unsubscribe.apply(this);
}
(this as any)._zoneUnsubscribe = function() {
if (this._zone && this._zone !== Zone.current) {
return this._zone.run(unsubscribe, this, arguments);
}
return unsubscribe.apply(this, arguments);
};
}
}
});
Expand Down Expand Up @@ -205,158 +182,7 @@ import {rxSubscriber} from 'rxjs/symbol/rxSubscriber';
};
};

const patchObservableInstance = function(observable: any) {
observable._zone = Zone.current;
};

const patchObservableFactoryCreator = function(obj: any, factoryName: string) {
const symbolFactory: string = symbol(factoryName);
if (obj[symbolFactory]) {
return;
}
const factoryCreator: any = obj[symbolFactory] = obj[factoryName];
if (!factoryCreator) {
return;
}
obj[factoryName] = function() {
const factory: any = factoryCreator.apply(this, arguments);
return function() {
const observable = factory.apply(this, arguments);
patchObservableInstance(observable);
return observable;
};
};
};

const patchObservableFactory = function(obj: any, factoryName: string) {
const symbolFactory: string = symbol(factoryName);
if (obj[symbolFactory]) {
return;
}
const factory: any = obj[symbolFactory] = obj[factoryName];
if (!factory) {
return;
}
obj[factoryName] = function() {
const observable = factory.apply(this, arguments);
patchObservableInstance(observable);
return observable;
};
};

const patchObservableFactoryArgs = function(obj: any, factoryName: string) {
const symbolFactory: string = symbol(factoryName);
if (obj[symbolFactory]) {
return;
}
const factory: any = obj[symbolFactory] = obj[factoryName];
if (!factory) {
return;
}
obj[factoryName] = function() {
const initZone = Zone.current;
const args = Array.prototype.slice.call(arguments);
for (let i = 0; i < args.length; i++) {
const arg = args[i];
if (typeof arg === 'function') {
args[i] = function() {
const argArgs = Array.prototype.slice.call(arguments);
const runningZone = Zone.current;
if (initZone && runningZone && initZone !== runningZone) {
return initZone.run(arg, this, argArgs);
} else {
return arg.apply(this, argArgs);
}
};
}
}

const observable = factory.apply(this, args);
patchObservableInstance(observable);
return observable;
};
};

const patchMulticast = function() {
const obj: any = Observable.prototype;
const factoryName: string = 'multicast';
const symbolFactory: string = symbol(factoryName);
if (obj[symbolFactory]) {
return;
}
const factory: any = obj[symbolFactory] = obj[factoryName];
if (!factory) {
return;
}
obj[factoryName] = function() {
const _zone: any = Zone.current;
const args = Array.prototype.slice.call(arguments);
let subjectOrSubjectFactory: any = args.length > 0 ? args[0] : undefined;
if (typeof subjectOrSubjectFactory !== 'function') {
const originalFactory: any = subjectOrSubjectFactory;
subjectOrSubjectFactory = function() {
return originalFactory;
};
}
args[0] = function() {
let subject: any;
if (_zone && _zone !== Zone.current) {
subject = _zone.run(subjectOrSubjectFactory, this, arguments);
} else {
subject = subjectOrSubjectFactory.apply(this, arguments);
}
if (subject && _zone) {
subject._zone = _zone;
}
return subject;
};
const observable = factory.apply(this, args);
patchObservableInstance(observable);
return observable;
};
};

const patchImmediate = function(asap: any) {
if (!asap) {
return;
}

const scheduleSymbol = symbol('scheduleSymbol');
const zoneSymbol = symbol('zone');
if (asap[scheduleSymbol]) {
return;
}

const schedule = asap[scheduleSymbol] = asap.schedule;
asap.schedule = function() {
const args = Array.prototype.slice.call(arguments);
const work = args.length > 0 ? args[0] : undefined;
const delay = args.length > 1 ? args[1] : 0;
const state = (args.length > 2 ? args[2] : undefined) || {};
state[zoneSymbol] = Zone.current;

const patchedWork = function() {
const workArgs = Array.prototype.slice.call(arguments);
const action = workArgs.length > 0 ? workArgs[0] : undefined;
const scheduleZone = action && action[zoneSymbol];
if (scheduleZone && scheduleZone !== Zone.current) {
return scheduleZone.runGuarded(work, this, arguments);
} else {
return work.apply(this, arguments);
}
};
return schedule.call(this, patchedWork, delay, state);
};
};

patchObservable();
patchSubscription();
patchSubscriber();
patchObservableFactoryCreator(Observable, 'bindCallback');
patchObservableFactoryCreator(Observable, 'bindNodeCallback');
patchObservableFactory(Observable, 'defer');
patchObservableFactory(Observable, 'forkJoin');
patchObservableFactoryArgs(Observable, 'fromEventPattern');
patchMulticast();
patchImmediate(asap);
});
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
"clang-format": "^1.2.3",
"concurrently": "^2.2.0",
"conventional-changelog": "^1.1.7",
"core-js": "^2.5.7",
"es6-promise": "^3.0.2",
"google-closure-compiler": "^20170409.0.0",
"gulp": "^3.8.11",
Expand Down Expand Up @@ -93,13 +94,13 @@
"phantomjs": "^2.1.7",
"promises-aplus-tests": "^2.1.2",
"pump": "^1.0.1",
"rxjs": "^5.5.3",
"rxjs": "^6.2.1",
"selenium-webdriver": "^3.4.0",
"systemjs": "^0.19.37",
"ts-loader": "^0.6.0",
"tslint": "^4.1.1",
"tslint-eslint-rules": "^3.1.0",
"typescript": "2.5.2",
"typescript": "2.9.2",
"vrsource-tslint-rules": "^4.0.0",
"webdriver-manager": "^12.0.6",
"webdriverio": "^4.8.0",
Expand Down
2 changes: 2 additions & 0 deletions test/browser_entry_point.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
* found in the LICENSE file at https://angular.io/license
*/

import 'core-js/features/set';
import 'core-js/features/map';
// List all tests here:
import './common_tests';
import './browser/browser.spec';
Expand Down
Loading

0 comments on commit 31fc127

Please sign in to comment.