Compare commits

..

50 Commits

Author SHA1 Message Date
185c679563 docs(changelog): update change log to beta.5 2016-02-10 16:16:05 -08:00
b3f4e05b57 chore(release): bump version to beta.5 2016-02-10 16:14:21 -08:00
abd1e6e680 fix(release): need to depend on latest rxjs and zone.js
The version in our package.json gets copied to the one we publish, and users need the latest of these.
2016-02-10 16:13:02 -08:00
f1f5b45361 feat(typings): install es6-shim typings to a location users can reference.
This makes the upgrade to beta.4 as simple as adding one reference tag, only when --target=es5
Implements option 3 from https://docs.google.com/document/d/1vgepQPkuHS4P3rzANQpoMIDIXe0Rl9Z2QyTtb8dpMoI/edit
2016-02-10 14:13:27 -08:00
50548fb565 fix(forms): use strict runtimeType checks instead of instanceof
Currently, validators extending built-in validators are treated as built-in.
This can result in an error when both a real built-in validator and a custom one are applied to the same element.

Closes #6981
2016-02-10 09:23:59 -08:00
8f47aa3530 fix(forms): add RadioButtonValueAccessor to the list of default value accessors 2016-02-09 15:28:08 -08:00
df7885c9f5 fix(router): Added route data to normalized async route
Closes #6802
2016-02-09 22:08:45 +00:00
0f10624b08 fix(ngFor): update view locals if identity changes
Closes #6923
2016-02-09 22:06:06 +00:00
6f1ef33e32 fix(router): fix url path for star segment in path recognizer
Url path of star segments should equal the original path.

If you register the route `/app/*location` and invoke a url like `/app/foo/bar`
the PathRecognizer should return a url path equal to the invoked url.

Before this patch, everything after `foo` was ignored, which resulted in a
redirect to `/app/foo` which was probably not intended (at least in the angular
1.5 component router).

Closes #6976
2016-02-09 21:45:06 +00:00
231773ea76 fix(compiler): use event names for matching directives
Closes #6870
2016-02-09 13:16:08 -08:00
e725542703 fix(forms): add support for radio buttons
Closes #6877
2016-02-09 19:47:50 +00:00
2337469753 style(angular1_router): license year updated
Closes #6219
2016-02-08 17:21:00 -08:00
55122cd57a fix(angular1-router): add missing wrapper methods
Closes #6763
Closes #6861
Closes #6861
2016-02-08 17:19:50 -08:00
7e0f02f96e fix(upgrade): fix infinite $rootScope.$digest()
Fixes #6385
Closes #6386
2016-02-08 17:18:52 -08:00
e7ad03cba6 fix(core): add detail to dehydrated detector exception
- at least I know what component is causing the error with this. without it the exception is so generic that it's not useful.

Closes #6939
2016-02-08 17:17:37 -08:00
74be3d3fde fix(core): mute mode printing in console in prod mode
Closes #6873
2016-02-08 17:16:19 -08:00
a15ca23469 refactor(mock): update variable names in directive_resolver_mock.ts
Closes #5056
2016-02-08 17:11:43 -08:00
de77700da0 fix(di): throw if a token uses more than 20 dependencies.
Fixes #6690
Closes #6869
2016-02-08 16:21:57 -08:00
e73fee7156 fix(router): fixed the location wrapper for angular1
In angular2 `Location.path()` returns the complete path including query string. In angular1 the query parameters are missing. Similar to this `Location.go` does accept two parameters (path *and query*).

Closes #6943
2016-02-08 16:18:26 -08:00
72ab35bceb test(angular1_router): test that location handles query strings
See 6698
2016-02-08 16:18:13 -08:00
0f22dce036 feat(angular1_router): allow component to bind to router 2016-02-08 16:18:13 -08:00
c6036435f0 fix(router): don't prepend / unnecessarily to Location paths
Closes #6729
Closes #5502
2016-02-08 16:18:13 -08:00
d86be245b8 fix(angular1-router): add support for using the component helper
In Angular 1.5 there is a new helper method for creating component directives.
See https://docs.angularjs.org/guide/component for more information about components.

These kind of directives only match the `E` element form and the previously component
router only created HTML that matched directives that matched the `A` attribute form.

This commit changes the `<ng-outlet>` directive so that it generates custom HTML
elements rather divs with custom attributes to trigger the relevant component to
appear in the DOM.

Going forward, Angular 1.5 users are encouraged to create their router components
using the following style:

```
myModule.componnet('component-name', {
  // component definition object
});
```

Closes angular/angular.js#13860
Closes #6076
Closes #5278

BREAKING CHANGE:

The component router now creates custom element HTML rather than custom attribute
HTML, in order to create a new component. So rather than

```html
<div custom-component></div>
```

it now creates

```html
<custom-component></custom-component>
```

If you defined you router components using the `directive()` helper and
specified the `restrict` properties such that element matching was not allowed,
e.g. `restrict: 'A'` then these components will no longer be instantiated
by the component router and the outlet will be empty.

The fix is to include `E` in the `restrict` property.

`restrict: 'EA'`

Note that this does not affect directives that did not specify the `restrict`
property as the default for this property is already `EA`.
2016-02-08 16:18:13 -08:00
a26053d3ff docs(cheatsheet): fix Dart cheatsheet
Also deletes an extraneous period from the JS cheatsheet.

Closes #5936
2016-02-08 15:58:22 -08:00
24d5b665e1 docs(HostBindingMetadata): Removed brackets from host bindings in HostBindingsMetadata example
Closes #6941
2016-02-08 15:55:49 -08:00
aa98fad338 docs: fix typo in 01_templates.md
Replace `an` with `a`

Closes #6842
2016-02-08 15:52:30 -08:00
9cb6dbbbab docs: fixed typo in documentation
Closes #6842
2016-02-08 15:30:15 -08:00
e21718faa9 docs(router): Updated inconsistencies in router docs
Closes #6805
2016-02-08 22:31:04 +00:00
b0f7d59e64 revert: chore: update the version of ts2dart
This reverts commit 22929a1671.

This commits makes our build red without the other commit that was already reverted.

More info at: https://github.com/angular/angular/pull/6825#issuecomment-181592303
2016-02-08 14:13:00 -08:00
b86829f492 revert: feat(transformers): collect information about di dependencies and providers
This reverts commit 86c40f8474.

Reason: new issues were discovered during the g3sync. @vsavkin is working on fixing them.
2016-02-08 12:15:03 -08:00
22929a1671 chore: update the version of ts2dart
Closes #6804
2016-02-05 21:56:33 +00:00
86c40f8474 feat(transformers): collect information about di dependencies and providers 2016-02-05 21:56:33 +00:00
16b521794c fix(build): don't try to copy .d.ts files into the npm distro
Fixes #6921
2016-02-05 11:53:15 -08:00
2a70f4e4c7 fix(typings): Don't expose typing dependencies to users.
This resolves Duplicate Identifier issues seen by many users,
at the expense of more typings installation required in some
cases.

Removes the quickstart hack of placing all needed dependencies
typings files in our distribution. Removes dependencies on
nodejs from angular2/core.

Fixes #5973
Fixes #5807
Fixes #6266

Angular now depends on es6-promise and es6-collections
(and a handful of manual typings) rather than all of es6-shim.

Fixes #5242

We previously had an undocumented breaking change, this is now
documented in this commit.

Fixes #6817

BREAKING CHANGE:

Transitive typings are no longer included in the distribution.
You may need to install typings in your project using
http://github.com/typings/typings

Users now must rely on getting typings from:
- one of the peerDependencies, such as rxjs, which exposes
  typings via the moduleResolution=node mechanism.
  (see https://github.com/Microsoft/TypeScript/wiki/Typings-for-npm-packages)
  This happens automatically.
- Using --target ES5 now requires manual installation of
  es6-promise and es6-collections typings.
- Using some angular APIs may introduce a dependency on eg. nodejs
  or jasmine, and those typings need manual installation as well.

Closes #6267
2016-02-04 22:42:40 +00:00
2f31c4c1c5 chore(typings): use mainline DefinitelyTyped repo rather than a fork.
The upstream Jasmine typings don't define a type for the global
object with Jasmine methods polluting it, so just use any.

Also zone.js has a different name upstream.
2016-02-04 22:42:40 +00:00
1435763383 chore(deps): update ts2dart and zone.js 2016-02-04 22:42:40 +00:00
05238df89b docs(changelog): add missing breaking change for beta.3 2016-02-03 11:43:17 -08:00
772d60d9fe docs(changelog): changelog for beta.3 2016-02-03 10:36:06 -08:00
24086bf0bb chore(release): bump version to beta.3 2016-02-03 10:36:06 -08:00
9b0e10e9a7 fix(compiler): fix interpolation regexp
- Fix the interpolation regexp to match newline characters (i.e. `\n` and `\r`)

Closes #6056
2016-02-03 15:21:55 +00:00
995a9e0cf8 fix(router): fix incorrect url param value coercion of 1 to true
seriliazeParams is coercing a value of 1 to true, which causes the value to be completey dropped.
Change the test from double equals to triple equals to prevent this from happening.

Closes #5346

Closes #6286
2016-02-03 15:00:24 +00:00
b55f1764b5 fix(Headers): serializable toJSON
fixes #6073

Closes #6714
2016-02-03 14:03:01 +00:00
5e9daed2e8 docs(http.ts): Fix MockBackend examples using backend.connections observer
Properly format observer examples.
2016-02-03 05:58:40 -08:00
aa8c5aa2e2 docs(http): fix example usage of MockBackend 2016-02-03 05:57:08 -08:00
f2c7946cca chore(http): make all typings explicit 2016-02-03 05:31:40 -08:00
da1fcfd820 fix(WebWorkers): Fix flaky WebWorker test
Closes #6851
2016-02-03 05:30:11 -08:00
dbeff6f548 style(ReflectionCapabilities) _zipTypesAndAnnotations, not _zipTypesAndAnnotaions
I was stepping through the Reflector and came across this little guy.

Closes #6535
2016-02-03 03:57:06 +00:00
26e60d658a fix(async): handle synchronous initial value in async pipe
Closes #5996
2016-02-03 03:56:52 +00:00
c2ceb7fba4 fix(Validators): fix Validators.required marking number zero as invalid
Closes #6617
2016-02-03 03:34:42 +00:00
4bfe49cd42 docs(core): update QueryList's onChange to changes.subscribe 2016-02-02 19:23:03 -08:00
99 changed files with 1378 additions and 495 deletions

View File

@ -1,3 +1,60 @@
<a name="2.0.0-beta.5"></a>
# 2.0.0-beta.5 (2016-02-10)
### Bug Fixes
* **angular1-router:** add missing wrapper methods ([55122cd](https://github.com/angular/angular/commit/55122cd)), closes [#6763](https://github.com/angular/angular/issues/6763) [#6861](https://github.com/angular/angular/issues/6861) [#6861](https://github.com/angular/angular/issues/6861)
* **angular1-router:** add support for using the component helper ([d86be24](https://github.com/angular/angular/commit/d86be24)), closes [angular/angular.js#13860](https://github.com/angular/angular.js/issues/13860) [#6076](https://github.com/angular/angular/issues/6076) [#5278](https://github.com/angular/angular/issues/5278)
* **async:** handle synchronous initial value in async pipe ([26e60d6](https://github.com/angular/angular/commit/26e60d6)), closes [#5996](https://github.com/angular/angular/issues/5996)
* **build:** don't try to copy .d.ts files into the npm distro ([16b5217](https://github.com/angular/angular/commit/16b5217)), closes [#6921](https://github.com/angular/angular/issues/6921)
* **compiler:** fix interpolation regexp ([9b0e10e](https://github.com/angular/angular/commit/9b0e10e)), closes [#6056](https://github.com/angular/angular/issues/6056)
* **compiler:** use event names for matching directives ([231773e](https://github.com/angular/angular/commit/231773e)), closes [#6870](https://github.com/angular/angular/issues/6870)
* **core:** add detail to dehydrated detector exception ([e7ad03c](https://github.com/angular/angular/commit/e7ad03c)), closes [#6939](https://github.com/angular/angular/issues/6939)
* **core:** mute mode printing in console in prod mode ([74be3d3](https://github.com/angular/angular/commit/74be3d3)), closes [#6873](https://github.com/angular/angular/issues/6873)
* **di:** throw if a token uses more than 20 dependencies. ([de77700](https://github.com/angular/angular/commit/de77700)), closes [#6690](https://github.com/angular/angular/issues/6690) [#6869](https://github.com/angular/angular/issues/6869)
* **forms:** add RadioButtonValueAccessor to the list of default value accessors ([8f47aa3](https://github.com/angular/angular/commit/8f47aa3))
* **forms:** add support for radio buttons ([e725542](https://github.com/angular/angular/commit/e725542)), closes [#6877](https://github.com/angular/angular/issues/6877)
* **forms:** use strict runtimeType checks instead of instanceof ([50548fb](https://github.com/angular/angular/commit/50548fb)), closes [#6981](https://github.com/angular/angular/issues/6981)
* **Headers:** serializable toJSON ([b55f176](https://github.com/angular/angular/commit/b55f176)), closes [#6073](https://github.com/angular/angular/issues/6073) [#6714](https://github.com/angular/angular/issues/6714)
* **ngFor:** update view locals if identity changes ([0f10624](https://github.com/angular/angular/commit/0f10624)), closes [#6923](https://github.com/angular/angular/issues/6923)
* **router:** Added route data to normalized async route ([df7885c](https://github.com/angular/angular/commit/df7885c)), closes [#6802](https://github.com/angular/angular/issues/6802)
* **router:** don't prepend `/` unnecessarily to Location paths ([c603643](https://github.com/angular/angular/commit/c603643)), closes [#6729](https://github.com/angular/angular/issues/6729) [#5502](https://github.com/angular/angular/issues/5502)
* **router:** fix incorrect url param value coercion of 1 to true ([995a9e0](https://github.com/angular/angular/commit/995a9e0)), closes [#5346](https://github.com/angular/angular/issues/5346) [#6286](https://github.com/angular/angular/issues/6286)
* **router:** fix url path for star segment in path recognizer ([6f1ef33](https://github.com/angular/angular/commit/6f1ef33)), closes [#6976](https://github.com/angular/angular/issues/6976)
* **router:** fixed the location wrapper for angular1 ([e73fee7](https://github.com/angular/angular/commit/e73fee7)), closes [#6943](https://github.com/angular/angular/issues/6943)
* **typings:** Don't expose typing dependencies to users. ([2a70f4e](https://github.com/angular/angular/commit/2a70f4e)), closes [#5973](https://github.com/angular/angular/issues/5973) [#5807](https://github.com/angular/angular/issues/5807) [#6266](https://github.com/angular/angular/issues/6266) [#5242](https://github.com/angular/angular/issues/5242) [#6817](https://github.com/angular/angular/issues/6817) [#6267](https://github.com/angular/angular/issues/6267)
* **upgrade:** fix infinite $rootScope.$digest() ([7e0f02f](https://github.com/angular/angular/commit/7e0f02f)), closes [#6385](https://github.com/angular/angular/issues/6385) [#6386](https://github.com/angular/angular/issues/6386)
* **Validators:** fix Validators.required marking number zero as invalid ([c2ceb7f](https://github.com/angular/angular/commit/c2ceb7f)), closes [#6617](https://github.com/angular/angular/issues/6617)
* **WebWorkers:** Fix flaky WebWorker test ([da1fcfd](https://github.com/angular/angular/commit/da1fcfd)), closes [#6851](https://github.com/angular/angular/issues/6851)
### Features
* **angular1_router:** allow component to bind to router ([0f22dce](https://github.com/angular/angular/commit/0f22dce))
* **typings:** install es6-shim typings to a location users can reference. ([f1f5b45](https://github.com/angular/angular/commit/f1f5b45))
### BREAKING CHANGES
Transitive typings are no longer included in the distribution.
If you use `--target=es5`, you will need to add a line somewhere in your
application (for example, at the top of the `.ts` file where you call `bootstrap`):
```
///<reference path="node_modules/angular2/typings/browser.d.ts"/>
```
(Note that if your file is not in the same directory as `node_modules`, you'll
need to add one or more `../` to the start of that path.)
If you have unit tests, you need to install typings in your project using
http://github.com/typings/typings
And install typings such as `jasmine`, `angular-protractor`, or `selenium-webdriver`
to satisfy the type-checker.
<a name="2.0.0-beta.4"></a>
# 2.0.0-beta.4 (2016-02-10)
This release was incorrect; replaced with beta.5.
<a name="2.0.0-beta.3"></a>
# 2.0.0-beta.3 (2016-02-03)
@ -27,6 +84,52 @@
* **dart/transform:** Only process deferred libs when necessary ([f56df65](https://github.com/angular/angular/commit/f56df65)), closes [#6745](https://github.com/angular/angular/issues/6745)
### BREAKING CHANGES
This is a breaking change for unit tests. The API for the DebugElement
has changed. Now, there is a DebugElement or DebugNode for every node
in the DOM, not only nodes with an ElementRef. `componentViewChildren` is
removed, and `childNodes` is a list of ElementNodes corresponding to every
child in the DOM. `query` no longer takes a scope parameter, since
the entire rendered DOM is included in the `childNodes`.
Before:
```
componentFixture.debugElement.componentViewChildren[0];
```
After
```
// Depending on the DOM structure of your component, the
// index may have changed or the first component child
// may be a sub-child.
componentFixture.debugElement.children[0];
```
Before:
```
debugElement.query(By.css('div'), Scope.all());
```
After:
```
debugElement.query(By.css('div'));
```
Before:
```
componentFixture.debugElement.elementRef;
```
After:
```
componentFixture.elementRef;
```
<a name="2.0.0-beta.2"></a>
# 2.0.0-beta.2 (2016-01-28)

View File

@ -981,15 +981,16 @@ gulp.task('!pre.test.typings.layoutNodeModule', ['build.js.cjs'], function() {
.pipe(gulp.dest(path.join(tmpdir, 'node_modules')));
});
gulp.task('!pre.test.typings.copyTypingsSpec', function() {
return gulp.src(['typing_spec/*.ts'], {base: 'typing_spec'}).pipe(gulp.dest(path.join(tmpdir)));
return gulp.src(['typing_spec/*.ts'], {base: 'typing_spec'}).pipe(gulp.dest(tmpdir));
});
gulp.task('test.typings',
['!pre.test.typings.layoutNodeModule', '!pre.test.typings.copyTypingsSpec'], function() {
var tsc = require('gulp-typescript');
return gulp.src([tmpdir + '/**'])
return gulp.src([tmpdir + '/*.ts'])
.pipe(tsc({
target: 'ES5',
target: 'ES6',
module: 'commonjs',
experimentalDecorators: true,
noImplicitAny: true,

View File

@ -173,6 +173,10 @@ var StringMapWrapper = {
var List = Array;
var ListWrapper = {
toJSON: function(l) {
return JSON.stringify(l);
},
clear: function (l) {
l.length = 0;
},
@ -247,6 +251,10 @@ var ListWrapper = {
};
var StringWrapper = {
charCodeAt: function(s, i) {
return s.charCodeAt(i);
},
equals: function (s1, s2) {
return s1 === s2;
},
@ -303,8 +311,8 @@ Location.prototype.subscribe = function () {
//TODO: implement
};
Location.prototype.path = function () {
return $location.path();
return $location.url();
};
Location.prototype.go = function (url) {
return $location.path(url);
Location.prototype.go = function (path, query) {
return $location.url(path + query);
};

View File

@ -57,7 +57,7 @@ function routerFactory($q, $location, $$directiveIntrospector, $browser, $rootSc
});
var router = new RootRouter(registry, location, $routerRootComponent);
$rootScope.$watch(function () { return $location.path(); }, function (path) {
$rootScope.$watch(function () { return $location.url(); }, function (path) {
if (router.lastNavigationAttempt !== path) {
router.navigateByUrl(path);
}

View File

@ -155,10 +155,12 @@ function ngOutletDirective($animate, $q: ng.IQService, $router) {
}
this.controller.$$routeParams = instruction.params;
this.controller.$$template = '<div ' + dashCase(componentName) + '></div>';
this.controller.$$template =
'<' + dashCase(componentName) + ' router="$$router"></' + dashCase(componentName) + '>';
this.controller.$$router = this.router.childRouter(instruction.componentType);
let newScope = scope.$new();
newScope.$$router = this.controller.$$router;
let clone = $transclude(newScope, clone => {
$animate.enter(clone, null, this.currentElement || element);

View File

@ -1,4 +1,4 @@
/** @license Copyright 2014-2015 Google, Inc. http://github.com/angular/angular/LICENSE */
/** @license Copyright 2014-2016 Google, Inc. http://github.com/angular/angular/LICENSE */
(function () {
'use strict';

View File

@ -21,17 +21,29 @@ describe('navigation', function () {
$router = _$router_;
});
registerComponent('userCmp', {
registerDirective('userCmp', {
template: '<div>hello {{userCmp.$routeParams.name}}</div>'
});
registerComponent('oneCmp', {
registerDirective('oneCmp', {
template: '<div>{{oneCmp.number}}</div>',
controller: function () {this.number = 'one'}
});
registerComponent('twoCmp', {
registerDirective('twoCmp', {
template: '<div>{{twoCmp.number}}</div>',
controller: function () {this.number = 'two'}
});
registerComponent('threeCmp', {
template: '<div>{{$ctrl.number}}</div>',
controller: function () {this.number = 'three'}
});
registerComponent('getParams', {
template: '<div>{{$ctrl.params.x}}</div>',
controller: function () {
this.$routerOnActivate = function(next) {
this.params = next.params;
};
}
})
});
it('should work in a simple case', function () {
@ -47,6 +59,21 @@ describe('navigation', function () {
expect(elt.text()).toBe('one');
});
it('should work with components created by the `mod.component()` helper', function () {
compile('<ng-outlet></ng-outlet>');
$router.config([
{ path: '/', component: 'threeCmp' }
]);
$router.navigateByUrl('/');
$rootScope.$digest();
expect(elt.text()).toBe('three');
});
it('should navigate between components with different parameters', function () {
$router.config([
{ path: '/user/:name', component: 'userCmp' }
@ -68,7 +95,7 @@ describe('navigation', function () {
function ParentController() {
instanceCount += 1;
}
registerComponent('parentCmp', {
registerDirective('parentCmp', {
template: 'parent { <ng-outlet></ng-outlet> }',
$routeConfig: [
{ path: '/user/:name', component: 'userCmp' }
@ -94,7 +121,7 @@ describe('navigation', function () {
it('should work with nested outlets', function () {
registerComponent('childCmp', {
registerDirective('childCmp', {
template: '<div>inner { <div ng-outlet></div> }</div>',
$routeConfig: [
{ path: '/b', component: 'oneCmp' }
@ -112,9 +139,29 @@ describe('navigation', function () {
expect(elt.text()).toBe('outer { inner { one } }');
});
it('should work when parent route has empty path', inject(function ($location) {
registerComponent('childCmp', {
template: '<div>inner { <div ng-outlet></div> }</div>',
$routeConfig: [
{ path: '/b', component: 'oneCmp' }
]
});
$router.config([
{ path: '/...', component: 'childCmp' }
]);
compile('<div>outer { <div ng-outlet></div> }</div>');
$router.navigateByUrl('/b');
$rootScope.$digest();
expect(elt.text()).toBe('outer { inner { one } }');
expect($location.path()).toBe('/b');
}));
it('should work with recursive nested outlets', function () {
registerComponent('recurCmp', {
registerDirective('recurCmp', {
template: '<div>recur { <div ng-outlet></div> }</div>',
$routeConfig: [
{ path: '/recur', component: 'recurCmp' },
@ -147,6 +194,21 @@ describe('navigation', function () {
}));
it('should pass through query terms to the location', inject(function ($location) {
$router.config([
{ path: '/user', component: 'userCmp' }
]);
compile('<div ng-outlet></div>');
$router.navigateByUrl('/user?x=y');
$rootScope.$digest();
expect($location.path()).toBe('/user');
expect($location.search()).toEqual({ x: 'y'});
}));
it('should change location to the canonical route', inject(function ($location) {
compile('<div ng-outlet></div>');
@ -163,7 +225,7 @@ describe('navigation', function () {
it('should change location to the canonical route with nested components', inject(function ($location) {
registerComponent('childRouter', {
registerDirective('childRouter', {
template: '<div>inner { <div ng-outlet></div> }</div>',
$routeConfig: [
{ path: '/new-child', component: 'oneCmp', name: 'NewChild'},
@ -206,9 +268,22 @@ describe('navigation', function () {
}));
it('should navigate when the location query changes', inject(function ($location) {
$router.config([
{ path: '/get/params', component: 'getParams' }
]);
compile('<div ng-outlet></div>');
$location.url('/get/params?x=y');
$rootScope.$digest();
expect(elt.text()).toBe('y');
}));
it('should expose a "navigating" property on $router', inject(function ($q) {
var defer;
registerComponent('pendingActivate', {
registerDirective('pendingActivate', {
$canActivate: function () {
defer = $q.defer();
return defer.promise;
@ -227,36 +302,54 @@ describe('navigation', function () {
expect($router.navigating).toBe(false);
}));
function registerComponent(name, options) {
var controller = options.controller || function () {};
['$routerOnActivate', '$routerOnDeactivate', '$routerOnReuse', '$routerCanReuse', '$routerCanDeactivate'].forEach(function (hookName) {
if (options[hookName]) {
controller.prototype[hookName] = options[hookName];
}
});
function registerDirective(name, options) {
function factory() {
return {
template: options.template || '',
controllerAs: name,
controller: controller
controller: getController(options)
};
}
if (options.$canActivate) {
factory.$canActivate = options.$canActivate;
}
if (options.$routeConfig) {
factory.$routeConfig = options.$routeConfig;
}
applyStaticProperties(factory, options);
$compileProvider.directive(name, factory);
}
function registerComponent(name, options) {
var definition = {
template: options.template || '',
controller: getController(options),
}
applyStaticProperties(definition, options);
$compileProvider.component(name, definition);
}
function compile(template) {
elt = $compile('<div>' + template + '</div>')($rootScope);
$rootScope.$digest();
return elt;
}
function getController(options) {
var controller = options.controller || function () {};
[
'$routerOnActivate', '$routerOnDeactivate',
'$routerOnReuse', '$routerCanReuse',
'$routerCanDeactivate'
].forEach(function (hookName) {
if (options[hookName]) {
controller.prototype[hookName] = options[hookName];
}
});
return controller;
}
function applyStaticProperties(target, options) {
['$canActivate', '$routeConfig'].forEach(function(property) {
if (options[property]) {
target[property] = options[property];
}
});
}
});

View File

@ -44,36 +44,105 @@ describe('router', function () {
expect(elt.text()).toBe('Home');
}));
function registerComponent(name, options) {
var controller = options.controller || function () {};
it('should bind the component to the current router', inject(function($location) {
var router;
registerComponent('homeCmp', {
bindings: { router: '=' },
controller: function($scope, $element) {
this.$routerOnActivate = function() {
router = this.router;
};
},
template: 'Home'
});
['$onActivate', '$onDeactivate', '$onReuse', '$canReuse', '$canDeactivate'].forEach(function (hookName) {
if (options[hookName]) {
controller.prototype[hookName] = options[hookName];
registerComponent('app', {
template: '<div ng-outlet></div>',
$routeConfig: [
{ path: '/', component: 'homeCmp' }
]
});
compile('<app></app>');
$location.path('/');
$rootScope.$digest();
var homeElement = elt.find('home-cmp');
expect(homeElement.text()).toBe('Home');
expect(homeElement.isolateScope().$ctrl.router).toBeDefined();
expect(router).toBeDefined();
}));
it('should work when an async route is provided route data', inject(function($location, $q) {
registerDirective('homeCmp', {
template: 'Home ({{homeCmp.isAdmin}})',
$routerOnActivate: function(next, prev) {
this.isAdmin = next.routeData.data.isAdmin;
}
});
registerDirective('app', {
template: '<div ng-outlet></div>',
$routeConfig: [
{ path: '/', loader: function() { return $q.when('homeCmp'); }, data: { isAdmin: true } }
]
});
compile('<app></app>');
$location.path('/');
$rootScope.$digest();
expect(elt.text()).toBe('Home (true)');
}));
function registerDirective(name, options) {
function factory() {
return {
template: options.template || '',
controllerAs: name,
controller: controller
controller: getController(options)
};
}
if (options.$canActivate) {
factory.$canActivate = options.$canActivate;
}
if (options.$routeConfig) {
factory.$routeConfig = options.$routeConfig;
}
applyStaticProperties(factory, options);
$compileProvider.directive(name, factory);
}
function registerComponent(name, options) {
var definition = {
bindings: options.bindings,
template: options.template || '',
controller: getController(options),
}
applyStaticProperties(definition, options);
$compileProvider.component(name, definition);
}
function compile(template) {
elt = $compile('<div>' + template + '</div>')($rootScope);
$rootScope.$digest();
return elt;
}
function getController(options) {
var controller = options.controller || function () {};
[
'$routerOnActivate', '$routerOnDeactivate',
'$routerOnReuse', '$routerCanReuse',
'$routerCanDeactivate'
].forEach(function (hookName) {
if (options[hookName]) {
controller.prototype[hookName] = options[hookName];
}
});
return controller;
}
function applyStaticProperties(target, options) {
['$canActivate', '$routeConfig'].forEach(function(property) {
if (options[property]) {
target[property] = options[property];
}
});
}
});

View File

@ -1,12 +1,12 @@
{
"version": "v4",
"repo": "angular/DefinitelyTyped",
"repo": "DefinitelyTyped/DefinitelyTyped",
"ref": "master",
"path": "typings",
"bundle": "typings/tsd.d.ts",
"installed": {
"angularjs/angular.d.ts": {
"commit": "746b9a892629060bc853e792afff536e0ec4655e"
"commit": "6eebd5e90a1cbd6b47b0705ba72dbcd5baf846f3"
}
}
}

View File

@ -3,7 +3,7 @@ Bootstrapping
@cheatsheetIndex 0
@description
{@target ts}`import {bootstrap} from 'angular2/platform/browser';`{@endtarget}
{@target js}Available from the `ng.platform.browser` namespace.{@endtarget}
{@target js}Available from the `ng.platform.browser` namespace{@endtarget}
{@target dart}`import 'package:angular2/bootstrap.dart';`{@endtarget}
@cheatsheetItem

View File

@ -4,7 +4,7 @@ Built-in directives
@description
{@target ts}`import {NgIf, ...} from 'angular2/common';`{@endtarget}
{@target js}Available from the `ng.common` namespace{@endtarget}
{@target dart}`import 'package:angular2/common.dart';`{@endtarget}
{@target dart}Available using `platform_directives` in pubspec{@endtarget}
@cheatsheetItem
syntax:

View File

@ -4,7 +4,7 @@ Class decorators
@description
{@target ts}`import {Directive, ...} from 'angular2/core';`{@endtarget}
{@target js}Available from the `ng.core` namespace{@endtarget}
{@target dart}`import 'package:angular2/core.dart';`{@endtarget}
{@target dart}`import 'package:angular2/angular2.dart';`{@endtarget}
@cheatsheetItem
syntax(ts):

View File

@ -4,7 +4,7 @@ Dependency injection configuration
@description
{@target ts}`import {provide} from 'angular2/core';`{@endtarget}
{@target js}Available from the `ng.core` namespace{@endtarget}
{@target dart}`import 'package:angular2/core.dart';`{@endtarget}
{@target dart}`import 'package:angular2/angular2.dart';`{@endtarget}
@cheatsheetItem
syntax(ts dart):

View File

@ -4,7 +4,7 @@ Class field decorators for directives and components
@description
{@target ts}`import {Input, ...} from 'angular2/core';`{@endtarget}
{@target js}Available from the `ng.core` namespace{@endtarget}
{@target dart}`import 'package:angular2/core.dart';`{@endtarget}
{@target dart}`import 'package:angular2/angular2.dart';`{@endtarget}
@cheatsheetItem
syntax(ts dart):

View File

@ -4,7 +4,7 @@ Forms
@description
{@target ts}`import {FORM_DIRECTIVES} from 'angular2/common';`{@endtarget}
{@target js}Available from `ng.common.FORM_DIRECTIVES`{@endtarget}
{@target dart}`import 'package:angular2/common.dart';`{@endtarget}
{@target dart}Available using `platform_directives` in pubspec{@endtarget}
@cheatsheetItem
syntax:

View File

@ -4,7 +4,7 @@ Routing and navigation
@description
{@target ts}`import {RouteConfig, ROUTER_DIRECTIVES, ROUTER_PROVIDERS, ...} from 'angular2/router';`{@endtarget}
{@target js}Available from the `ng.router` namespace{@endtarget}
{@target dart}`import 'package:angular2/router.dart';`{@endtarget}
{@target dart}`import 'package:angular2/angular2.dart';`{@endtarget}
@cheatsheetItem

View File

@ -456,7 +456,7 @@ Where
* `local` is a local identifier for local variables.
* `internal` is an internal variable which the directive exports for binding.
* `key` is an attribute name usually only used to trigger a specific directive.
* `keyExpression` is an property name to which the expression will be bound to.
* `keyExpression` is a property name to which the expression will be bound to.
* `varExport` allows exporting of directive internal state as variables for further binding. If no `internal` name
is specified, the exporting is to an implicit variable.
* `microsyntax` allows you to build a simple microsyntax which can still clearly identify which expressions bind to

View File

@ -141,6 +141,7 @@ export {URLSearchParams} from './src/http/url_search_params';
* // Send a response to the request
* connection.mockRespond(response);
* });
* }
* });
*
* http.get('people.json').observer({
@ -156,7 +157,8 @@ export const HTTP_PROVIDERS: any[] = [
// issue: https://github.com/angular/angular/issues/3183
provide(Http,
{
useFactory: (xhrBackend, requestOptions) => new Http(xhrBackend, requestOptions),
useFactory: (xhrBackend: XHRBackend, requestOptions: RequestOptions) =>
new Http(xhrBackend, requestOptions),
deps: [XHRBackend, RequestOptions]
}),
BrowserXhr,
@ -268,6 +270,7 @@ export const HTTP_BINDINGS = HTTP_PROVIDERS;
* // Send a response to the request
* connection.mockRespond(response);
* });
* }
* });
* jsonp.get('people.json').observer({
@ -283,7 +286,8 @@ export const JSONP_PROVIDERS: any[] = [
// issue: https://github.com/angular/angular/issues/3183
provide(Jsonp,
{
useFactory: (jsonpBackend, requestOptions) => new Jsonp(jsonpBackend, requestOptions),
useFactory: (jsonpBackend: JSONPBackend, requestOptions: RequestOptions) =>
new Jsonp(jsonpBackend, requestOptions),
deps: [JSONPBackend, RequestOptions]
}),
BrowserJsonp,

View File

@ -1,36 +0,0 @@
/**
* Declarations angular depends on for compilation to ES6.
* This file is also used to propagate our transitive typings
* to users.
*/
/// <reference path="../typings/zone/zone.d.ts"/>
/// <reference path="../typings/hammerjs/hammerjs.d.ts"/>
// TODO: ideally the node.d.ts reference should be scoped only for files that need and not to all
// the code including client code
/// <reference path="../typings/node/node.d.ts" />
declare var assert: any;
interface BrowserNodeGlobal {
Object: typeof Object;
Array: typeof Array;
Map: typeof Map;
Set: typeof Set;
Date: typeof Date;
RegExp: typeof RegExp;
JSON: typeof JSON;
Math: typeof Math;
assert(condition: any): void;
Reflect: any;
zone: Zone;
getAngularTestability: Function;
getAllAngularTestabilities: Function;
frameworkStabilizers: Array<Function>;
setTimeout: Function;
clearTimeout: Function;
setInterval: Function;
clearInterval: Function;
}

View File

@ -1,7 +1,52 @@
/**
* Declarations angular depends on for compilation to ES6.
* This file is also used to propagate our transitive typings
* to users.
* Subset of es6-shim typings.
* Angular should not require use of ES6 runtime but some API usages are already present.
* See https://github.com/angular/angular/issues/5242
* TODO(alexeagle): remove methods below which may not be present in targeted browser
*/
/// <reference path="../typings/es6-shim/es6-shim.d.ts"/>
/// <reference path="./globals-es6.d.ts"/>
declare type PromiseConstructor = typeof Promise;
interface String {
/**
* Returns true if the sequence of elements of searchString converted to a String is the
* same as the corresponding elements of this object (converted to a String) starting at
* position. Otherwise returns false.
*/
startsWith(searchString: string, position?: number): boolean;
/**
* Returns true if the sequence of elements of searchString converted to a String is the
* same as the corresponding elements of this object (converted to a String) starting at
* endPosition length(this). Otherwise returns false.
*/
endsWith(searchString: string, endPosition?: number): boolean;
}
interface Array<T> {
/**
* Returns the value of the first element in the array where predicate is true, and undefined
* otherwise.
* @param predicate find calls predicate once for each element of the array, in ascending
* order, until it finds one where predicate returns true. If such an element is found, find
* immediately returns that element value. Otherwise, find returns undefined.
* @param thisArg If provided, it will be used as the this value for each invocation of
* predicate. If it is not provided, undefined is used instead.
*/
find(predicate: (value: T, index: number, obj: Array<T>) => boolean, thisArg?: any): T;
/**
* Returns the this object after filling the section identified by start and end with value
* @param value value to fill array section with
* @param start index to start filling the array at. If start is negative, it is treated as
* length+start where length is the length of the array.
* @param end index to stop filling the array at. If end is negative, it is treated as
* length+end.
*/
fill(value: T, start?: number, end?: number): T[];
}
interface NumberConstructor {
/**
* Returns true if the value passed is an integer, false otherwise.
* @param number A numeric value.
*/
isInteger(number: number): boolean;
}

View File

@ -8,6 +8,12 @@
"license": "<%= packageJson.license %>",
"repository": <%= JSON.stringify(packageJson.repository) %>,
"devDependencies": <%= JSON.stringify(packageJson.defaultDevDependencies) %>,
"dependencies": {
"typings": "0.6.6"
},
"scripts": {
"postinstall": "typings install --ambient --name es6-promise github:DefinitelyTyped/DefinitelyTyped/es6-promise/es6-promise.d.ts#830e8ebd9ef137d039d5c7ede24a421f08595f83; typings install --ambient --name es6-collections github:DefinitelyTyped/DefinitelyTyped/es6-collections/es6-collections.d.ts#9f97e2a2bc1f502550c9b4fcaad1c48df5521d37"
},
"peerDependencies": {
"es6-promise": "<%= packageJson.dependencies['es6-promise'] %>",
"es6-shim": "<%= packageJson.dependencies['es6-shim'] %>",

View File

@ -117,6 +117,11 @@ export class NgFor implements DoCheck {
var viewRef = <EmbeddedViewRef>this._viewContainer.get(i);
viewRef.setLocal('last', i === ilen - 1);
}
changes.forEachIdentityChange((record) => {
var viewRef = <EmbeddedViewRef>this._viewContainer.get(record.currentIndex);
viewRef.setLocal('\$implicit', record.item);
});
}
private _perViewChange(view, record) {

View File

@ -31,7 +31,7 @@ export {
NgSelectOption,
SelectControlValueAccessor
} from './forms/directives/select_control_value_accessor';
export {FORM_DIRECTIVES} from './forms/directives';
export {FORM_DIRECTIVES, RadioButtonState} from './forms/directives';
export {NG_VALIDATORS, NG_ASYNC_VALIDATORS, Validators} from './forms/validators';
export {
RequiredValidator,
@ -39,4 +39,25 @@ export {
MaxLengthValidator,
Validator
} from './forms/directives/validators';
export {FormBuilder, FORM_PROVIDERS, FORM_BINDINGS} from './forms/form_builder';
export {FormBuilder} from './forms/form_builder';
import {FormBuilder} from './forms/form_builder';
import {RadioControlRegistry} from './forms/directives/radio_control_value_accessor';
import {Type, CONST_EXPR} from 'angular2/src/facade/lang';
/**
* Shorthand set of providers used for building Angular forms.
*
* ### Example
*
* ```typescript
* bootstrap(MyApp, [FORM_PROVIDERS]);
* ```
*/
export const FORM_PROVIDERS: Type[] = CONST_EXPR([FormBuilder, RadioControlRegistry]);
/**
* See {@link FORM_PROVIDERS} instead.
*
* @deprecated
*/
export const FORM_BINDINGS = FORM_PROVIDERS;

View File

@ -8,6 +8,7 @@ import {NgForm} from './directives/ng_form';
import {DefaultValueAccessor} from './directives/default_value_accessor';
import {CheckboxControlValueAccessor} from './directives/checkbox_value_accessor';
import {NumberValueAccessor} from './directives/number_value_accessor';
import {RadioControlValueAccessor} from './directives/radio_control_value_accessor';
import {NgControlStatus} from './directives/ng_control_status';
import {
SelectControlValueAccessor,
@ -23,6 +24,10 @@ export {NgFormModel} from './directives/ng_form_model';
export {NgForm} from './directives/ng_form';
export {DefaultValueAccessor} from './directives/default_value_accessor';
export {CheckboxControlValueAccessor} from './directives/checkbox_value_accessor';
export {
RadioControlValueAccessor,
RadioButtonState
} from './directives/radio_control_value_accessor';
export {NumberValueAccessor} from './directives/number_value_accessor';
export {NgControlStatus} from './directives/ng_control_status';
export {
@ -63,6 +68,7 @@ export const FORM_DIRECTIVES: Type[] = CONST_EXPR([
NumberValueAccessor,
CheckboxControlValueAccessor,
SelectControlValueAccessor,
RadioControlValueAccessor,
NgControlStatus,
RequiredValidator,

View File

@ -18,7 +18,7 @@ const CHECKBOX_VALUE_ACCESSOR = CONST_EXPR(new Provider(
selector:
'input[type=checkbox][ngControl],input[type=checkbox][ngFormControl],input[type=checkbox][ngModel]',
host: {'(change)': 'onChange($event.target.checked)', '(blur)': 'onTouched()'},
bindings: [CHECKBOX_VALUE_ACCESSOR]
providers: [CHECKBOX_VALUE_ACCESSOR]
})
export class CheckboxControlValueAccessor implements ControlValueAccessor {
onChange = (_) => {};

View File

@ -0,0 +1,126 @@
import {
Directive,
ElementRef,
Renderer,
Self,
forwardRef,
Provider,
Attribute,
Input,
OnInit,
OnDestroy,
Injector,
Injectable
} from 'angular2/core';
import {
NG_VALUE_ACCESSOR,
ControlValueAccessor
} from 'angular2/src/common/forms/directives/control_value_accessor';
import {NgControl} from 'angular2/src/common/forms/directives/ng_control';
import {CONST_EXPR, looseIdentical, isPresent} from 'angular2/src/facade/lang';
import {ListWrapper} from 'angular2/src/facade/collection';
const RADIO_VALUE_ACCESSOR = CONST_EXPR(new Provider(
NG_VALUE_ACCESSOR, {useExisting: forwardRef(() => RadioControlValueAccessor), multi: true}));
/**
* Internal class used by Angular to uncheck radio buttons with the matching name.
*/
@Injectable()
export class RadioControlRegistry {
private _accessors: any[] = [];
add(control: NgControl, accessor: RadioControlValueAccessor) {
this._accessors.push([control, accessor]);
}
remove(accessor: RadioControlValueAccessor) {
var indexToRemove = -1;
for (var i = 0; i < this._accessors.length; ++i) {
if (this._accessors[i][1] === accessor) {
indexToRemove = i;
}
}
ListWrapper.removeAt(this._accessors, indexToRemove);
}
select(accessor: RadioControlValueAccessor) {
this._accessors.forEach((c) => {
if (c[0].control.root === accessor._control.control.root && c[1] !== accessor) {
c[1].fireUncheck();
}
});
}
}
/**
* The value provided by the forms API for radio buttons.
*/
export class RadioButtonState {
constructor(public checked: boolean, public value: string) {}
}
/**
* The accessor for writing a radio control value and listening to changes that is used by the
* {@link NgModel}, {@link NgFormControl}, and {@link NgControlName} directives.
*
* ### Example
* ```
* @Component({
* template: `
* <input type="radio" name="food" [(ngModel)]="foodChicken">
* <input type="radio" name="food" [(ngModel)]="foodFish">
* `
* })
* class FoodCmp {
* foodChicken = new RadioButtonState(true, "chicken");
* foodFish = new RadioButtonState(false, "fish");
* }
* ```
*/
@Directive({
selector:
'input[type=radio][ngControl],input[type=radio][ngFormControl],input[type=radio][ngModel]',
host: {'(change)': 'onChange()', '(blur)': 'onTouched()'},
providers: [RADIO_VALUE_ACCESSOR]
})
export class RadioControlValueAccessor implements ControlValueAccessor,
OnDestroy, OnInit {
_state: RadioButtonState;
_control: NgControl;
@Input() name: string;
_fn: Function;
onChange = () => {};
onTouched = () => {};
constructor(private _renderer: Renderer, private _elementRef: ElementRef,
private _registry: RadioControlRegistry, private _injector: Injector) {}
ngOnInit(): void {
this._control = this._injector.get(NgControl);
this._registry.add(this._control, this);
}
ngOnDestroy(): void { this._registry.remove(this); }
writeValue(value: any): void {
this._state = value;
if (isPresent(value) && value.checked) {
this._renderer.setElementProperty(this._elementRef.nativeElement, 'checked', true);
}
}
registerOnChange(fn: (_: any) => {}): void {
this._fn = fn;
this.onChange = () => {
fn(new RadioButtonState(true, this._state.value));
this._registry.select(this);
};
}
fireUncheck(): void { this._fn(new RadioButtonState(false, this._state.value)); }
registerOnTouched(fn: () => {}): void { this.onTouched = fn; }
}

View File

@ -1,5 +1,5 @@
import {ListWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
import {isBlank, isPresent, looseIdentical} from 'angular2/src/facade/lang';
import {isBlank, isPresent, looseIdentical, hasConstructor} from 'angular2/src/facade/lang';
import {BaseException, WrappedException} from 'angular2/src/facade/exceptions';
import {ControlContainer} from './control_container';
@ -13,6 +13,7 @@ import {DefaultValueAccessor} from './default_value_accessor';
import {NumberValueAccessor} from './number_value_accessor';
import {CheckboxControlValueAccessor} from './checkbox_value_accessor';
import {SelectControlValueAccessor} from './select_control_value_accessor';
import {RadioControlValueAccessor} from './radio_control_value_accessor';
import {normalizeValidator} from './normalize_validator';
@ -81,11 +82,13 @@ export function selectValueAccessor(dir: NgControl,
var builtinAccessor;
var customAccessor;
valueAccessors.forEach(v => {
if (v instanceof DefaultValueAccessor) {
if (hasConstructor(v, DefaultValueAccessor)) {
defaultAccessor = v;
} else if (v instanceof CheckboxControlValueAccessor || v instanceof NumberValueAccessor ||
v instanceof SelectControlValueAccessor) {
} else if (hasConstructor(v, CheckboxControlValueAccessor) ||
hasConstructor(v, NumberValueAccessor) ||
hasConstructor(v, SelectControlValueAccessor) ||
hasConstructor(v, RadioControlValueAccessor)) {
if (isPresent(builtinAccessor))
_throwError(dir, "More than one built-in value accessor matches");
builtinAccessor = v;

View File

@ -106,21 +106,3 @@ export class FormBuilder {
}
}
}
/**
* Shorthand set of providers used for building Angular forms.
*
* ### Example
*
* ```typescript
* bootstrap(MyApp, [FORM_PROVIDERS]);
* ```
*/
export const FORM_PROVIDERS: Type[] = CONST_EXPR([FormBuilder]);
/**
* See {@link FORM_PROVIDERS} instead.
*
* @deprecated
*/
export const FORM_BINDINGS = FORM_PROVIDERS;

View File

@ -208,6 +208,16 @@ export abstract class AbstractControl {
return isPresent(this.getError(errorCode, path));
}
get root(): AbstractControl {
let x: AbstractControl = this;
while (isPresent(x._parent)) {
x = x._parent;
}
return x;
}
/** @internal */
_updateControlsErrors(): void {
this._status = this._calculateStatus();

View File

@ -1,4 +1,4 @@
import {isBlank, isPresent, CONST_EXPR} from 'angular2/src/facade/lang';
import {isBlank, isPresent, CONST_EXPR, isString} from 'angular2/src/facade/lang';
import {PromiseWrapper} from 'angular2/src/facade/promise';
import {ObservableWrapper} from 'angular2/src/facade/async';
import {ListWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
@ -44,7 +44,9 @@ export class Validators {
* Validator that requires controls to have a non-empty value.
*/
static required(control: modelModule.Control): {[key: string]: boolean} {
return isBlank(control.value) || control.value == "" ? {"required": true} : null;
return isBlank(control.value) || (isString(control.value) && control.value == "") ?
{"required": true} :
null;
}
/**

View File

@ -81,6 +81,7 @@ export class AsyncPipe implements PipeTransform, OnDestroy {
if (isPresent(obj)) {
this._subscribe(obj);
}
this._latestReturnedValue = this._latestValue;
return this._latestValue;
}

View File

@ -433,8 +433,9 @@ class TemplateParseVisitor implements HtmlAstVisitor {
var parts = splitAtColon(name, [null, name]);
var target = parts[0];
var eventName = parts[1];
targetEvents.push(new BoundEventAst(eventName, target,
this._parseAction(expression, sourceSpan), sourceSpan));
var ast = this._parseAction(expression, sourceSpan);
targetMatchableAttrs.push([name, ast.source]);
targetEvents.push(new BoundEventAst(eventName, target, ast, sourceSpan));
// Don't detect directives for event names for now,
// so don't add the event name to the matchableAttrs
}

View File

@ -456,11 +456,10 @@ export class ApplicationRef_ extends ApplicationRef {
});
return completer.promise.then(_ => {
let c = this._injector.get(Console);
let modeDescription =
assertionsEnabled() ?
"in the development mode. Call enableProdMode() to enable the production mode." :
"in the production mode. Call enableDevMode() to enable the development mode.";
c.log(`Angular 2 is running ${modeDescription}`);
if (assertionsEnabled()) {
c.log(
"Angular 2 is running in the development mode. Call enableProdMode() to enable the production mode.");
}
return _;
});
}

View File

@ -73,7 +73,7 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
handleEvent(eventName: string, elIndex: number, event: any): boolean {
if (!this.hydrated()) {
this.throwDehydratedError();
this.throwDehydratedError(`${this.id} -> ${eventName}`);
}
try {
var locals = new Map<string, any>();
@ -130,7 +130,7 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
// facilitate error reporting.
detectChangesInRecords(throwOnChange: boolean): void {
if (!this.hydrated()) {
this.throwDehydratedError();
this.throwDehydratedError(this.id);
}
try {
this.detectChangesInRecordsInternal(throwOnChange);
@ -362,7 +362,7 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
oldValue, newValue, null);
}
throwDehydratedError(): void { throw new DehydratedException(); }
throwDehydratedError(detail: string): void { throw new DehydratedException(detail); }
private _currentBinding(): BindingTarget {
return this.bindingTargets[this.propertyBindingIndex];

View File

@ -40,6 +40,9 @@ export class DefaultIterableDiffer implements IterableDiffer {
private _movesTail: CollectionChangeRecord = null;
private _removalsHead: CollectionChangeRecord = null;
private _removalsTail: CollectionChangeRecord = null;
// Keeps track of records where custom track by is the same, but item identity has changed
private _identityChangesHead: CollectionChangeRecord = null;
private _identityChangesTail: CollectionChangeRecord = null;
constructor(private _trackByFn?: TrackByFn) {
this._trackByFn = isPresent(this._trackByFn) ? this._trackByFn : trackByIdentity;
@ -84,6 +87,13 @@ export class DefaultIterableDiffer implements IterableDiffer {
}
}
forEachIdentityChange(fn: Function) {
var record: CollectionChangeRecord;
for (record = this._identityChangesHead; record !== null; record = record._nextIdentityChange) {
fn(record);
}
}
diff(collection: any): DefaultIterableDiffer {
if (isBlank(collection)) collection = [];
if (!isListLikeIterable(collection)) {
@ -123,7 +133,7 @@ export class DefaultIterableDiffer implements IterableDiffer {
// TODO(misko): can we limit this to duplicates only?
record = this._verifyReinsertion(record, item, itemTrackBy, index);
}
record.item = item;
if (!looseIdentical(record.item, item)) this._addIdentityChange(record, item);
}
record = record._next;
@ -135,10 +145,13 @@ export class DefaultIterableDiffer implements IterableDiffer {
if (record === null || !looseIdentical(record.trackById, itemTrackBy)) {
record = this._mismatch(record, item, itemTrackBy, index);
mayBeDirty = true;
} else if (mayBeDirty) {
} else {
if (mayBeDirty) {
// TODO(misko): can we limit this to duplicates only?
record = this._verifyReinsertion(record, item, itemTrackBy, index);
}
if (!looseIdentical(record.item, item)) this._addIdentityChange(record, item);
}
record = record._next;
index++;
});
@ -150,9 +163,12 @@ export class DefaultIterableDiffer implements IterableDiffer {
return this.isDirty;
}
// CollectionChanges is considered dirty if it has any additions, moves or removals.
/* CollectionChanges is considered dirty if it has any additions, moves, removals, or identity
* changes.
*/
get isDirty(): boolean {
return this._additionsHead !== null || this._movesHead !== null || this._removalsHead !== null;
return this._additionsHead !== null || this._movesHead !== null ||
this._removalsHead !== null || this._identityChangesHead !== null;
}
/**
@ -183,6 +199,7 @@ export class DefaultIterableDiffer implements IterableDiffer {
}
this._movesHead = this._movesTail = null;
this._removalsHead = this._removalsTail = null;
this._identityChangesHead = this._identityChangesTail = null;
// todo(vicb) when assert gets supported
// assert(!this.isDirty);
@ -216,12 +233,18 @@ export class DefaultIterableDiffer implements IterableDiffer {
record = this._linkedRecords === null ? null : this._linkedRecords.get(itemTrackBy, index);
if (record !== null) {
// We have seen this before, we need to move it forward in the collection.
// But first we need to check if identity changed, so we can update in view if necessary
if (!looseIdentical(record.item, item)) this._addIdentityChange(record, item);
this._moveAfter(record, previousRecord, index);
} else {
// Never seen it, check evicted list.
record = this._unlinkedRecords === null ? null : this._unlinkedRecords.get(itemTrackBy);
if (record !== null) {
// It is an item which we have evicted earlier: reinsert it back into the list.
// But first we need to check if identity changed, so we can update in view if necessary
if (!looseIdentical(record.item, item)) this._addIdentityChange(record, item);
this._reinsertAfter(record, previousRecord, index);
} else {
// It is a new item: add it.
@ -269,7 +292,6 @@ export class DefaultIterableDiffer implements IterableDiffer {
record.currentIndex = index;
this._addToMoves(record, index);
}
record.item = item;
return record;
}
@ -469,6 +491,18 @@ export class DefaultIterableDiffer implements IterableDiffer {
return record;
}
/** @internal */
_addIdentityChange(record: CollectionChangeRecord, item: any) {
record.item = item;
if (this._identityChangesTail === null) {
this._identityChangesTail = this._identityChangesHead = record;
} else {
this._identityChangesTail = this._identityChangesTail._nextIdentityChange = record;
}
return record;
}
toString(): string {
var list = [];
this.forEachItem((record) => list.push(record));
@ -485,9 +519,13 @@ export class DefaultIterableDiffer implements IterableDiffer {
var removals = [];
this.forEachRemovedItem((record) => removals.push(record));
var identityChanges = [];
this.forEachIdentityChange((record) => identityChanges.push(record));
return "collection: " + list.join(', ') + "\n" + "previous: " + previous.join(', ') + "\n" +
"additions: " + additions.join(', ') + "\n" + "moves: " + moves.join(', ') + "\n" +
"removals: " + removals.join(', ') + "\n";
"removals: " + removals.join(', ') + "\n" + "identityChanges: " +
identityChanges.join(', ') + "\n";
}
}
@ -513,6 +551,9 @@ export class CollectionChangeRecord {
_nextAdded: CollectionChangeRecord = null;
/** @internal */
_nextMoved: CollectionChangeRecord = null;
/** @internal */
_nextIdentityChange: CollectionChangeRecord = null;
constructor(public item: any, public trackById: any) {}

View File

@ -91,7 +91,7 @@ export class ChangeDetectionError extends WrappedException {
* This is an internal Angular error.
*/
export class DehydratedException extends BaseException {
constructor() { super('Attempt to use a dehydrated detector.'); }
constructor(details: string) { super(`Attempt to use a dehydrated detector: ${details}`); }
}
/**

View File

@ -248,15 +248,12 @@ class _Scanner {
}
scanCharacter(start: number, code: number): Token {
assert(this.peek == code);
this.advance();
return newCharacterToken(start, code);
}
scanOperator(start: number, str: string): Token {
assert(this.peek == StringWrapper.charCodeAt(str, 0));
assert(SetWrapper.has(OPERATORS, str));
this.advance();
return newOperatorToken(start, str);
}
@ -274,7 +271,6 @@ class _Scanner {
*/
scanComplexOperator(start: number, one: string, twoCode: number, two: string, threeCode?: number,
three?: string): Token {
assert(this.peek == StringWrapper.charCodeAt(one, 0));
this.advance();
var str: string = one;
if (this.peek == twoCode) {
@ -285,12 +281,10 @@ class _Scanner {
this.advance();
str += three;
}
assert(SetWrapper.has(OPERATORS, str));
return newOperatorToken(start, str);
}
scanIdentifier(): Token {
assert(isIdentifierStart(this.peek));
var start: number = this.index;
this.advance();
while (isIdentifierPart(this.peek)) this.advance();
@ -303,7 +297,6 @@ class _Scanner {
}
scanNumber(start: number): Token {
assert(isDigit(this.peek));
var simple: boolean = (this.index === start);
this.advance(); // Skip initial digit.
while (true) {
@ -329,7 +322,6 @@ class _Scanner {
}
scanString(): Token {
assert(this.peek == $SQ || this.peek == $DQ);
var start: number = this.index;
var quote: number = this.peek;
this.advance(); // Skip initial quote.

View File

@ -49,7 +49,7 @@ import {
var _implicitReceiver = new ImplicitReceiver();
// TODO(tbosch): Cannot make this const/final right now because of the transpiler...
var INTERPOLATION_REGEXP = /\{\{(.*?)\}\}/g;
var INTERPOLATION_REGEXP = /\{\{([\s\S]*?)\}\}/g;
class ParseException extends BaseException {
constructor(message: string, input: string, errLocation: string, ctxLocation?: any) {

View File

@ -17,6 +17,7 @@ import {
OutOfBoundsError
} from './exceptions';
import {FunctionWrapper, Type, isPresent, isBlank, CONST_EXPR} from 'angular2/src/facade/lang';
import {BaseException} from 'angular2/src/facade/exceptions';
import {Key} from './key';
import {SelfMetadata, HostMetadata, SkipSelfMetadata} from './metadata';
@ -874,6 +875,9 @@ export class Injector {
obj = factory(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13, d14, d15, d16,
d17, d18, d19);
break;
default:
throw new BaseException(
`Cannot instantiate '${provider.key.displayName}' because it has more than 20 dependencies`);
}
} catch (e) {
throw new InstantiationError(this, e, e.stack, provider.key);

View File

@ -9,7 +9,7 @@ import {CONST} from 'angular2/src/facade/lang';
* var t = new OpaqueToken("value");
*
* var injector = Injector.resolveAndCreate([
* provide(t, {useValue: "providedValue"})
* provide(t, {useValue: "bindingValue"})
* ]);
*
* expect(injector.get(t)).toEqual("bindingValue");

View File

@ -1166,7 +1166,7 @@ export var ViewChild: ViewChildFactory = makePropDecorator(ViewChildMetadata);
* shown: boolean;
*
* constructor(private @Query(Item) items:QueryList<Item>) {
* items.onChange(() => console.log(items.length));
* items.changes.subscribe(() => console.log(items.length));
* }
* }
* ```

View File

@ -254,7 +254,7 @@ export class ContentChildMetadata extends QueryMetadata {
* shown: boolean;
*
* constructor(private @Query(Item) items:QueryList<Item>) {
* items.onChange(() => console.log(items.length));
* items.changes.subscribe(() => console.log(items.length));
* }
* }
* ```

View File

@ -1071,8 +1071,8 @@ export class OutputMetadata {
* @Directive({selector: '[ngModel]'})
* class NgModelStatus {
* constructor(public control:NgModel) {}
* @HostBinding('[class.valid]') get valid { return this.control.valid; }
* @HostBinding('[class.invalid]') get invalid { return this.control.invalid; }
* @HostBinding('class.valid') get valid { return this.control.valid; }
* @HostBinding('class.invalid') get invalid { return this.control.invalid; }
* }
*
* @Component({

View File

@ -83,7 +83,7 @@ export class ReflectionCapabilities implements PlatformReflectionCapabilities {
}
/** @internal */
_zipTypesAndAnnotaions(paramTypes, paramAnnotations): any[][] {
_zipTypesAndAnnotations(paramTypes, paramAnnotations): any[][] {
var result;
if (typeof paramTypes === 'undefined') {
@ -119,7 +119,7 @@ export class ReflectionCapabilities implements PlatformReflectionCapabilities {
var paramAnnotations = this._reflect.getMetadata('parameters', typeOrFunc);
var paramTypes = this._reflect.getMetadata('design:paramtypes', typeOrFunc);
if (isPresent(paramTypes) || isPresent(paramAnnotations)) {
return this._zipTypesAndAnnotaions(paramTypes, paramAnnotations);
return this._zipTypesAndAnnotations(paramTypes, paramAnnotations);
}
}
// The array has to be filled with `undefined` because holes would be skipped by `some`

View File

@ -1,9 +1,9 @@
import {ListWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
import {normalizeBlank, isPresent, global} from 'angular2/src/facade/lang';
import {normalizeBlank, isPresent, global, ZoneLike} from 'angular2/src/facade/lang';
import {ObservableWrapper, EventEmitter} from 'angular2/src/facade/async';
import {wtfLeave, wtfCreateScope, WtfScopeFn} from '../profile/profile';
export interface NgZoneZone extends Zone {
export interface NgZoneZone extends ZoneLike {
/** @internal */
_innerZone: boolean;
}
@ -348,8 +348,9 @@ export class NgZone {
var errorHandling;
if (enableLongStackTrace) {
errorHandling = StringMapWrapper.merge(
Zone.longStackTraceZone, {onError: function(e) { ngZone._notifyOnError(this, e); }});
errorHandling =
StringMapWrapper.merge(global.Zone.longStackTraceZone,
{onError: function(e) { ngZone._notifyOnError(this, e); }});
} else {
errorHandling = {onError: function(e) { ngZone._notifyOnError(this, e); }};
}

View File

@ -15,20 +15,16 @@ import {toPromise} from 'rxjs/operator/toPromise';
export {Observable} from 'rxjs/Observable';
export {Subject} from 'rxjs/Subject';
export namespace NodeJS {
export interface Timer {}
}
export class TimerWrapper {
static setTimeout(fn: (...args: any[]) => void, millis: number): NodeJS.Timer {
static setTimeout(fn: (...args: any[]) => void, millis: number): number {
return global.setTimeout(fn, millis);
}
static clearTimeout(id: NodeJS.Timer): void { global.clearTimeout(id); }
static clearTimeout(id: number): void { global.clearTimeout(id); }
static setInterval(fn: (...args: any[]) => void, millis: number): NodeJS.Timer {
static setInterval(fn: (...args: any[]) => void, millis: number): number {
return global.setInterval(fn, millis);
}
static clearInterval(id: NodeJS.Timer): void { global.clearInterval(id); }
static clearInterval(id: number): void { global.clearInterval(id); }
}
export class ObservableWrapper {

View File

@ -353,3 +353,7 @@ var global = null;
dynamic evalExpression(String sourceUrl, String expr, String declarations, Map<String, String> vars) {
throw "Dart does not support evaluating expression during runtime!";
}
bool hasConstructor(Object value, Type type) {
return value.runtimeType == type;
}

View File

@ -1,3 +1,36 @@
// Zones are TC-39 standards-track so users could choose a different implementation
// Rather than import {Zone} from 'zone.js' we define an interface
// so that any library that structurally matches may be used with Angular 2.
export interface ZoneLike {
fork(locals?: any): ZoneLike;
run(fn: any, applyTo?: any, applyWith?: any): any;
}
export interface ZoneLikeConstructor {
longStackTraceZone: { [key: string]: any; };
}
export interface BrowserNodeGlobal {
Object: typeof Object;
Array: typeof Array;
Map: typeof Map;
Set: typeof Set;
Date: DateConstructor;
RegExp: RegExpConstructor;
JSON: typeof JSON;
Math: any; // typeof Math;
assert(condition: any): void;
Reflect: any;
zone: ZoneLike;
Zone: ZoneLikeConstructor;
getAngularTestability: Function;
getAllAngularTestabilities: Function;
frameworkStabilizers: Array<Function>;
setTimeout: Function;
clearTimeout: Function;
setInterval: Function;
clearInterval: Function;
}
// TODO(jteplitz602): Load WorkerGlobalScope from lib.webworker.d.ts file #3492
declare var WorkerGlobalScope;
var globalScope: BrowserNodeGlobal;
@ -10,7 +43,7 @@ if (typeof window === 'undefined') {
}
} else {
globalScope = <any>window;
};
}
export const IS_DART = false;
@ -431,3 +464,7 @@ export function evalExpression(sourceUrl: string, expr: string, declarations: st
export function isPrimitive(obj: any): boolean {
return !isJsObject(obj);
}
export function hasConstructor(value: Object, type: Type): boolean {
return value.constructor === type;
}

View File

@ -3,11 +3,11 @@ import {global} from 'angular2/src/facade/lang';
let _nextRequestId = 0;
export const JSONP_HOME = '__ng_jsonp__';
var _jsonpConnections = null;
var _jsonpConnections: {[key: string]: any} = null;
function _getJsonpConnections(): {[key: string]: any} {
if (_jsonpConnections === null) {
_jsonpConnections = global[JSONP_HOME] = {};
_jsonpConnections = (<{[key: string]: any}>global)[JSONP_HOME] = {};
}
return _jsonpConnections;
}

View File

@ -8,6 +8,7 @@ import {BrowserJsonp} from './browser_jsonp';
import {makeTypeError} from 'angular2/src/facade/exceptions';
import {StringWrapper, isPresent} from 'angular2/src/facade/lang';
import {Observable} from 'rxjs/Observable';
import {Observer} from 'rxjs/Observer';
const JSONP_ERR_NO_CALLBACK = 'JSONP injected script did not invoke callback.';
const JSONP_ERR_WRONG_METHOD = 'JSONP requests must use GET request method.';
@ -51,7 +52,7 @@ export class JSONPConnection_ extends JSONPConnection {
throw makeTypeError(JSONP_ERR_WRONG_METHOD);
}
this.request = req;
this.response = new Observable(responseObserver => {
this.response = new Observable((responseObserver: Observer<Response>) => {
this.readyState = ReadyState.Loading;
let id = this._id = _dom.nextRequestID();
@ -70,7 +71,7 @@ export class JSONPConnection_ extends JSONPConnection {
let script = this._script = _dom.build(url);
let onLoad = event => {
let onLoad = (event: Event) => {
if (this.readyState === ReadyState.Cancelled) return;
this.readyState = ReadyState.Done;
_dom.cleanup(script);
@ -93,7 +94,7 @@ export class JSONPConnection_ extends JSONPConnection {
responseObserver.complete();
};
let onError = error => {
let onError = (error: Error) => {
if (this.readyState === ReadyState.Cancelled) return;
this.readyState = ReadyState.Done;
_dom.cleanup(script);

View File

@ -32,7 +32,7 @@ export class MockConnection implements Connection {
* {@link EventEmitter} of {@link Response}. Can be subscribed to in order to be notified when a
* response is available.
*/
response: any; // Subject<Response>
response: ReplaySubject<Response>;
constructor(req: Request) {
this.response = take.call(new ReplaySubject(1), 1);
@ -131,7 +131,8 @@ export class MockBackend implements ConnectionBackend {
* ### Example
*
* ```
* import {MockBackend, Http, BaseRequestOptions} from 'angular2/http';
* import {Http, BaseRequestOptions} from 'angular2/http';
* import {MockBackend} from 'angular2/http/testing';
* import {Injector} from 'angular2/core';
*
* it('should get a response', () => {
@ -139,7 +140,7 @@ export class MockBackend implements ConnectionBackend {
* var text; //this will be set from mock response
* var injector = Injector.resolveAndCreate([
* MockBackend,
* provide(Http, {useFactory: (backend, options) {
* provide(Http, {useFactory: (backend, options) => {
* return new Http(backend, options);
* }, deps: [MockBackend, BaseRequestOptions]}]);
* var backend = injector.get(MockBackend);
@ -176,7 +177,8 @@ export class MockBackend implements ConnectionBackend {
constructor() {
this.connectionsArray = [];
this.connections = new Subject();
this.connections.subscribe(connection => this.connectionsArray.push(connection));
this.connections.subscribe((connection: MockConnection) =>
this.connectionsArray.push(connection));
this.pendingConnections = new Subject();
}
@ -187,7 +189,7 @@ export class MockBackend implements ConnectionBackend {
*/
verifyNoPendingRequests() {
let pending = 0;
this.pendingConnections.subscribe(c => pending++);
this.pendingConnections.subscribe((c: MockConnection) => pending++);
if (pending > 0) throw new BaseException(`${pending} pending connections to be resolved`);
}
@ -197,7 +199,7 @@ export class MockBackend implements ConnectionBackend {
*
* This method only exists in the mock implementation, not in real Backends.
*/
resolveAllConnections() { this.connections.subscribe(c => c.readyState = 4); }
resolveAllConnections() { this.connections.subscribe((c: MockConnection) => c.readyState = 4); }
/**
* Creates a new {@link MockConnection}. This is equivalent to calling `new
@ -205,7 +207,7 @@ export class MockBackend implements ConnectionBackend {
* emitter of this `MockBackend` instance. This method will usually only be used by tests
* against the framework itself, not by end-users.
*/
createConnection(req: Request): Connection {
createConnection(req: Request): MockConnection {
if (!isPresent(req) || !(req instanceof Request)) {
throw new BaseException(`createConnection requires an instance of Request, got ${req}`);
}

View File

@ -8,7 +8,9 @@ import {Injectable} from 'angular2/core';
import {BrowserXhr} from './browser_xhr';
import {isPresent} from 'angular2/src/facade/lang';
import {Observable} from 'rxjs/Observable';
import {Observer} from 'rxjs/Observer';
import {isSuccess, getResponseURL} from '../http_utils';
/**
* Creates connections using `XMLHttpRequest`. Given a fully-qualified
* request, an `XHRConnection` will immediately create an `XMLHttpRequest` object and send the
@ -27,7 +29,7 @@ export class XHRConnection implements Connection {
readyState: ReadyState;
constructor(req: Request, browserXHR: BrowserXhr, baseResponseOptions?: ResponseOptions) {
this.request = req;
this.response = new Observable(responseObserver => {
this.response = new Observable((responseObserver: Observer<Response>) => {
let _xhr: XMLHttpRequest = browserXHR.build();
_xhr.open(RequestMethod[req.method].toUpperCase(), req.url);
// load event handler
@ -64,7 +66,7 @@ export class XHRConnection implements Connection {
responseObserver.error(response);
};
// error event handler
let onError = (err) => {
let onError = (err: any) => {
var responseOptions = new ResponseOptions({body: err, type: ResponseType.Error});
if (isPresent(baseResponseOptions)) {
responseOptions = baseResponseOptions.merge(responseOptions);

View File

@ -9,6 +9,7 @@ import {
import {BaseException, WrappedException} from 'angular2/src/facade/exceptions';
import {
isListLikeIterable,
iterateListLike,
Map,
MapWrapper,
StringMapWrapper,
@ -57,8 +58,9 @@ export class Headers {
}
// headers instanceof StringMap
StringMapWrapper.forEach(
headers, (v, k) => { this._headersMap.set(k, isListLikeIterable(v) ? v : [v]); });
StringMapWrapper.forEach(headers, (v: any, k: string) => {
this._headersMap.set(k, isListLikeIterable(v) ? v : [v]);
});
}
/**
@ -110,13 +112,13 @@ export class Headers {
* Sets or overrides header value for given name.
*/
set(header: string, value: string | string[]): void {
var list = [];
var list: string[] = [];
if (isListLikeIterable(value)) {
var pushValue = (<string[]>value).join(',');
list.push(pushValue);
} else {
list.push(value);
list.push(<string>value);
}
this._headersMap.set(header, list);
@ -130,7 +132,17 @@ export class Headers {
/**
* Returns string of all headers.
*/
toJSON(): string { return Json.stringify(this.values()); }
toJSON(): {[key: string]: any} {
let serializableHeaders = {};
this._headersMap.forEach((values: string[], name: string) => {
let list = [];
iterateListLike(values, val => list = ListWrapper.concat(list, val.split(',')));
serializableHeaders[name] = list;
});
return serializableHeaders;
}
/**
* Returns list of header values for a given name.

View File

@ -12,7 +12,8 @@ function httpRequest(backend: ConnectionBackend, request: Request): Observable<R
return backend.createConnection(request).response;
}
function mergeOptions(defaultOpts, providedOpts, method, url): RequestOptions {
function mergeOptions(defaultOpts: BaseRequestOptions, providedOpts: RequestOptionsArgs,
method: RequestMethod, url: string): RequestOptions {
var newOptions = defaultOpts;
if (isPresent(providedOpts)) {
// Hack so Dart can used named parameters
@ -104,7 +105,7 @@ export class Http {
if (isString(url)) {
responseObservable = httpRequest(
this._backend,
new Request(mergeOptions(this._defaultOptions, options, RequestMethod.Get, url)));
new Request(mergeOptions(this._defaultOptions, options, RequestMethod.Get, <string>url)));
} else if (url instanceof Request) {
responseObservable = httpRequest(this._backend, url);
} else {
@ -183,7 +184,8 @@ export class Jsonp extends Http {
request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> {
var responseObservable: any;
if (isString(url)) {
url = new Request(mergeOptions(this._defaultOptions, options, RequestMethod.Get, url));
url =
new Request(mergeOptions(this._defaultOptions, options, RequestMethod.Get, <string>url));
}
if (url instanceof Request) {
if (url.method !== RequestMethod.Get) {

View File

@ -3,16 +3,18 @@ import {RequestMethod} from './enums';
import {makeTypeError} from 'angular2/src/facade/exceptions';
import {Response} from './static_response';
export function normalizeMethodName(method): RequestMethod {
export function normalizeMethodName(method: string | RequestMethod): RequestMethod {
if (isString(method)) {
var originalMethod = method;
method = method.replace(/(\w)(\w*)/g, (g0, g1, g2) => g1.toUpperCase() + g2.toLowerCase());
method = RequestMethod[method];
method = (<string>method)
.replace(/(\w)(\w*)/g, (g0: string, g1: string, g2: string) =>
g1.toUpperCase() + g2.toLowerCase());
method = <number>(<{[key: string]: any}>RequestMethod)[method];
if (typeof method !== 'number')
throw makeTypeError(
`Invalid request method. The method "${originalMethod}" is not supported.`);
}
return method;
return <RequestMethod>method;
}
export const isSuccess = (status: number): boolean => (status >= 200 && status < 300);

View File

@ -92,7 +92,7 @@ export class Response {
* Attempts to return body as parsed `JSON` object, or raises an exception.
*/
json(): any {
var jsonResponse;
var jsonResponse: string | Object;
if (isJsObject(this._body)) {
jsonResponse = this._body;
} else if (isString(this._body)) {

View File

@ -121,7 +121,7 @@ export class URLSearchParams {
}
toString(): string {
var paramsList = [];
var paramsList: string[] = [];
this.paramsMap.forEach((values, k) => { values.forEach(v => paramsList.push(k + '=' + v)); });
return paramsList.join('&');
}

View File

@ -69,11 +69,11 @@ export class MockDirectiveResolver extends DirectiveResolver {
this.viewProviderOverrides.set(type, viewBindings);
}
setProvidersOverride(type: Type, bindings: any[]): void {
this._providerOverrides.set(type, bindings);
setProvidersOverride(type: Type, providers: any[]): void {
this._providerOverrides.set(type, providers);
}
setViewProvidersOverride(type: Type, viewBindings: any[]): void {
this.viewProviderOverrides.set(type, viewBindings);
setViewProvidersOverride(type: Type, viewProviders: any[]): void {
this.viewProviderOverrides.set(type, viewProviders);
}
}

View File

@ -14,11 +14,12 @@ import {Promise, PromiseWrapper} from 'angular2/src/facade/async';
* ```
* import {Component} from 'angular2/core';
* import {bootstrap} from 'angular2/platform/browser';
* import {Router, ROUTER_DIRECTIVES, ROUTER_PROVIDERS, RouteConfig} from 'angular2/router';
* import {Router, ROUTER_DIRECTIVES, ROUTER_PROVIDERS, RouteConfig, RouteParams} from
* 'angular2/router';
*
* @Component({directives: [ROUTER_DIRECTIVES]})
* @RouteConfig([
* {path: '/user/:id', component: UserCmp, as: 'UserCmp'},
* {path: '/user/:id', component: UserCmp, name: 'UserCmp'},
* ])
* class AppCmp {}
*
@ -47,14 +48,14 @@ export class RouteParams {
* ### Example
*
* ```
* import {Component, View} from 'angular2/core';
* import {Component} from 'angular2/core';
* import {bootstrap} from 'angular2/platform/browser';
* import {Router, ROUTER_DIRECTIVES, routerBindings, RouteConfig} from 'angular2/router';
* import {Router, ROUTER_DIRECTIVES, ROUTER_PROVIDERS, RouteConfig, RouteData} from
* 'angular2/router';
*
* @Component({...})
* @View({directives: [ROUTER_DIRECTIVES]})
* @Component({directives: [ROUTER_DIRECTIVES]})
* @RouteConfig([
* {path: '/user/:id', component: UserCmp, as: 'UserCmp', data: {isAdmin: true}},
* {path: '/user/:id', component: UserCmp, name: 'UserCmp', data: {isAdmin: true}},
* ])
* class AppCmp {}
*
@ -67,7 +68,7 @@ export class RouteParams {
* }
* }
*
* bootstrap(AppCmp, routerBindings(AppCmp));
* bootstrap(AppCmp, ROUTER_PROVIDERS);
* ```
*/
export class RouteData {

View File

@ -5,7 +5,7 @@ import {UrlChangeListener} from './platform_location';
/**
* `LocationStrategy` is responsible for representing and reading route state
* from the browser's URL. Angular provides two strategies:
* {@link HashLocationStrategy} (default) and {@link PathLocationStrategy}.
* {@link HashLocationStrategy} and {@link PathLocationStrategy} (default).
*
* This is used under the hood of the {@link Location} service.
*
@ -54,7 +54,6 @@ export abstract class LocationStrategy {
*
* bootstrap(AppCmp, [
* ROUTER_PROVIDERS,
* PathLocationStrategy,
* provide(APP_BASE_HREF, {useValue: '/my/app'})
* ]);
* ```

View File

@ -208,15 +208,16 @@ export class PathRecognizer {
}
if (isPresent(currentSegment)) {
captured.push(currentSegment.path);
// the star segment consumes all of the remaining URL, including matrix params
if (segment instanceof StarSegment) {
positionalParams[segment.name] = currentSegment.toString();
captured.push(currentSegment.toString());
nextSegment = null;
break;
}
captured.push(currentSegment.path);
if (segment instanceof DynamicSegment) {
positionalParams[segment.name] = currentSegment.path;
} else if (!segment.match(currentSegment.path)) {

View File

@ -26,10 +26,10 @@ export class RouteConfig {
*
* ### Example
* ```
* import {RouteConfig} from 'angular2/router';
* import {RouteConfig, Route} from 'angular2/router';
*
* @RouteConfig([
* {path: '/home', component: HomeCmp, name: 'HomeCmp' }
* new Route({path: '/home', component: HomeCmp, name: 'HomeCmp' })
* ])
* class MyApp {}
* ```
@ -110,10 +110,11 @@ export class AuxRoute implements RouteDefinition {
*
* ### Example
* ```
* import {RouteConfig} from 'angular2/router';
* import {RouteConfig, AsyncRoute} from 'angular2/router';
*
* @RouteConfig([
* {path: '/home', loader: () => Promise.resolve(MyLoadedCmp), name: 'MyLoadedCmp'}
* new AsyncRoute({path: '/home', loader: () => Promise.resolve(MyLoadedCmp), name:
* 'MyLoadedCmp'})
* ])
* class MyApp {}
* ```
@ -150,11 +151,11 @@ export class AsyncRoute implements RouteDefinition {
*
* ### Example
* ```
* import {RouteConfig} from 'angular2/router';
* import {RouteConfig, Route, Redirect} from 'angular2/router';
*
* @RouteConfig([
* {path: '/', redirectTo: ['/Home'] },
* {path: '/home', component: HomeCmp, name: 'Home'}
* new Redirect({path: '/', redirectTo: ['/Home'] }),
* new Route({path: '/home', component: HomeCmp, name: 'Home'})
* ])
* class MyApp {}
* ```

View File

@ -44,6 +44,7 @@ export function normalizeRouteConfig(config: RouteDefinition,
path: config.path,
loader: wrappedLoader,
name: config.name,
data: config.data,
useAsDefault: config.useAsDefault
});
}
@ -66,6 +67,7 @@ export function normalizeRouteConfig(config: RouteDefinition,
path: config.path,
loader: componentDefinitionObject.loader,
name: config.name,
data: config.data,
useAsDefault: config.useAsDefault
});
} else {

View File

@ -438,7 +438,7 @@ export class RootRouter extends Router {
}
var emitPath = instruction.toUrlPath();
var emitQuery = instruction.toUrlQuery();
if (emitPath.length > 0) {
if (emitPath.length > 0 && emitPath[0] != '/') {
emitPath = '/' + emitPath;
}
@ -465,7 +465,7 @@ export class RootRouter extends Router {
commit(instruction: Instruction, _skipLocationChange: boolean = false): Promise<any> {
var emitPath = instruction.toUrlPath();
var emitQuery = instruction.toUrlQuery();
if (emitPath.length > 0) {
if (emitPath.length > 0 && emitPath[0] != '/') {
emitPath = '/' + emitPath;
}
var promise = super.commit(instruction);

View File

@ -206,7 +206,7 @@ export function serializeParams(paramMap: {[key: string]: any}): string[] {
var params = [];
if (isPresent(paramMap)) {
StringMapWrapper.forEach(paramMap, (value, key) => {
if (value == true) {
if (value === true) {
params.push(key);
} else {
params.push(key + '=' + value);

View File

@ -84,7 +84,7 @@ export interface NgMatchers extends jasmine.Matchers {
not: NgMatchers;
}
var _global: jasmine.GlobalPolluter = <any>(typeof window === 'undefined' ? global : window);
var _global = <any>(typeof window === 'undefined' ? global : window);
/**
* Jasmine matching function with Angular matchers mixed in.

View File

@ -18,7 +18,7 @@ export {inject, injectAsync} from './test_injector';
export {expect, NgMatchers} from './matchers';
var _global: jasmine.GlobalPolluter = <any>(typeof window === 'undefined' ? global : window);
var _global = <any>(typeof window === 'undefined' ? global : window);
/**
* Run a function (with an optional asynchronous callback) after each test case.

View File

@ -14,7 +14,7 @@ export {expect, NgMatchers} from './matchers';
export var proxy: ClassDecorator = (t) => t;
var _global: jasmine.GlobalPolluter = <any>(typeof window === 'undefined' ? global : window);
var _global = <any>(typeof window === 'undefined' ? global : window);
export var afterEach: Function = _global.afterEach;

View File

@ -339,7 +339,7 @@ export class UpgradeAdapter {
(injector: angular.IInjectorService, rootScope: angular.IRootScopeService) => {
ng1Injector = injector;
ObservableWrapper.subscribe(ngZone.onTurnDone,
(_) => { ngZone.run(() => rootScope.$apply()); });
(_) => ngZone.runOutsideAngular(() => rootScope.$apply()));
ng1compilePromise =
UpgradeNg1ComponentAdapterBuilder.resolve(this.downgradedComponents, injector);
}

View File

@ -361,7 +361,8 @@ export function main() {
});
}));
it('should use custom track by if function is provided',
describe('track by', function() {
it('should not replace tracked items',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template =
`<template ngFor #item [ngForOf]="items" [ngForTrackBy]="customTrackBy" #i="index">
@ -383,8 +384,41 @@ export function main() {
async.done();
});
}));
it('should update implicit local variable on view',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template =
`<div><template ngFor #item [ngForOf]="items" [ngForTrackBy]="customTrackBy">{{item['color']}}</template></div>`;
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((fixture) => {
fixture.debugElement.componentInstance.items = [{'id': 'a', 'color': 'blue'}];
fixture.detectChanges();
expect(fixture.debugElement.nativeElement).toHaveText('blue');
fixture.debugElement.componentInstance.items = [{'id': 'a', 'color': 'red'}];
fixture.detectChanges();
expect(fixture.debugElement.nativeElement).toHaveText('red');
async.done();
});
}));
it('should move items around and keep them updated ',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template =
`<div><template ngFor #item [ngForOf]="items" [ngForTrackBy]="customTrackBy">{{item['color']}}</template></div>`;
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((fixture) => {
fixture.debugElement.componentInstance.items =
[{'id': 'a', 'color': 'blue'}, {'id': 'b', 'color': 'yellow'}];
fixture.detectChanges();
expect(fixture.debugElement.nativeElement).toHaveText('blueyellow');
fixture.debugElement.componentInstance.items =
[{'id': 'b', 'color': 'orange'}, {'id': 'a', 'color': 'red'}];
fixture.detectChanges();
expect(fixture.debugElement.nativeElement).toHaveText('orangered');
async.done();
});
}));
});
});
}

View File

@ -10,6 +10,7 @@ import {
dispatchEvent,
fakeAsync,
tick,
flushMicrotasks,
expect,
it,
inject,
@ -31,7 +32,8 @@ import {
NgFor,
NgForm,
Validators,
Validator
Validator,
RadioButtonState
} from 'angular2/common';
import {Provider, forwardRef, Input} from 'angular2/core';
import {By} from 'angular2/platform/browser';
@ -328,6 +330,33 @@ export function main() {
});
}));
it("should support <type=radio>",
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var t = `<form [ngFormModel]="form">
<input type="radio" ngControl="foodChicken" name="food">
<input type="radio" ngControl="foodFish" name="food">
</form>`;
tcb.overrideTemplate(MyComp, t).createAsync(MyComp).then((fixture) => {
fixture.debugElement.componentInstance.form = new ControlGroup({
"foodChicken": new Control(new RadioButtonState(false, 'chicken')),
"foodFish": new Control(new RadioButtonState(true, 'fish'))
});
fixture.detectChanges();
var input = fixture.debugElement.query(By.css("input"));
expect(input.nativeElement.checked).toEqual(false);
dispatchEvent(input.nativeElement, "change");
fixture.detectChanges();
let value = fixture.debugElement.componentInstance.form.value;
expect(value['foodChicken'].checked).toEqual(true);
expect(value['foodFish'].checked).toEqual(false);
async.done();
});
}));
it("should support <select>",
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var t = `<div [ngFormModel]="form">
@ -812,9 +841,50 @@ export function main() {
expect(fixture.debugElement.componentInstance.name).toEqual("updatedValue");
})));
});
it("should support <type=radio>",
inject([TestComponentBuilder], fakeAsync((tcb: TestComponentBuilder) => {
var t = `<form>
<input type="radio" name="food" ngControl="chicken" [(ngModel)]="data['chicken1']">
<input type="radio" name="food" ngControl="fish" [(ngModel)]="data['fish1']">
</form>
<form>
<input type="radio" name="food" ngControl="chicken" [(ngModel)]="data['chicken2']">
<input type="radio" name="food" ngControl="fish" [(ngModel)]="data['fish2']">
</form>`;
var fixture: ComponentFixture;
tcb.overrideTemplate(MyComp, t).createAsync(MyComp).then((f) => { fixture = f; });
tick();
fixture.debugElement.componentInstance.data = {
'chicken1': new RadioButtonState(false, 'chicken'),
'fish1': new RadioButtonState(true, 'fish'),
'chicken2': new RadioButtonState(false, 'chicken'),
'fish2': new RadioButtonState(true, 'fish')
};
fixture.detectChanges();
tick();
var input = fixture.debugElement.query(By.css("input"));
expect(input.nativeElement.checked).toEqual(false);
dispatchEvent(input.nativeElement, "change");
tick();
let data = fixture.debugElement.componentInstance.data;
expect(data['chicken1']).toEqual(new RadioButtonState(true, 'chicken'));
expect(data['fish1']).toEqual(new RadioButtonState(false, 'fish'));
expect(data['chicken2']).toEqual(new RadioButtonState(false, 'chicken'));
expect(data['fish2']).toEqual(new RadioButtonState(true, 'fish'));
})));
});
describe("setting status classes", () => {
it("should work with single fields",
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {

View File

@ -35,6 +35,9 @@ export function main() {
it("should not error on a non-empty string",
() => { expect(Validators.required(new Control("not empty"))).toEqual(null); });
it("should accept zero as valid",
() => { expect(Validators.required(new Control(0))).toEqual(null); });
});
describe("minLength", () => {

View File

@ -327,6 +327,15 @@ export function main() {
]);
});
it('should locate directives in event bindings', () => {
var dirA = CompileDirectiveMetadata.create(
{selector: '[a]', type: new CompileTypeMetadata({name: 'DirB'})});
expect(humanizeTplAst(parse('<div (a)="b">', [dirA])))
.toEqual(
[[ElementAst, 'div'], [BoundEventAst, 'a', null, 'b'], [DirectiveAst, dirA]]);
});
it('should parse directive host properties', () => {
var dirA = CompileDirectiveMetadata.create({
selector: 'div',

View File

@ -25,6 +25,12 @@ class ItemWithId {
toString() { return `{id: ${this.id}}` }
}
class ComplexItem {
constructor(private id: string, private color: string) {}
toString() { return `{id: ${this.id}, color: ${this.color}}` }
}
// todo(vicb): UnmodifiableListView / frozen object when implemented
export function main() {
describe('iterable differ', function() {
@ -342,8 +348,12 @@ export function main() {
beforeEach(() => { differ = new DefaultIterableDiffer(trackByItemId); });
it('should not treat maps as new with track by function', () => {
it('should treat the collection as dirty if identity changes', () => {
differ.diff(buildItemList(['a']));
expect(differ.diff(buildItemList(['a']))).toBe(differ);
});
it('should treat seen records as identity changes, not additions', () => {
let l = buildItemList(['a', 'b', 'c']);
differ.check(l);
expect(differ.toString())
@ -357,11 +367,26 @@ export function main() {
expect(differ.toString())
.toEqual(iterableChangesAsString({
collection: [`{id: a}`, `{id: b}`, `{id: c}`],
identityChanges: [`{id: a}`, `{id: b}`, `{id: c}`],
previous: [`{id: a}`, `{id: b}`, `{id: c}`]
}));
});
it('should track moves normally with track by function', () => {
it('should have updated properties in identity change collection', () => {
let l = [new ComplexItem('a', 'blue'), new ComplexItem('b', 'yellow')];
differ.check(l);
l = [new ComplexItem('a', 'orange'), new ComplexItem('b', 'red')];
differ.check(l);
expect(differ.toString())
.toEqual(iterableChangesAsString({
collection: [`{id: a, color: orange}`, `{id: b, color: red}`],
identityChanges: [`{id: a, color: orange}`, `{id: b, color: red}`],
previous: [`{id: a, color: orange}`, `{id: b, color: red}`]
}));
});
it('should track moves normally', () => {
let l = buildItemList(['a', 'b', 'c']);
differ.check(l);
@ -370,13 +395,14 @@ export function main() {
expect(differ.toString())
.toEqual(iterableChangesAsString({
collection: ['{id: b}[1->0]', '{id: a}[0->1]', '{id: c}'],
identityChanges: ['{id: b}[1->0]', '{id: a}[0->1]', '{id: c}'],
previous: ['{id: a}[0->1]', '{id: b}[1->0]', '{id: c}'],
moves: ['{id: b}[1->0]', '{id: a}[0->1]']
}));
});
it('should track duplicate reinsertion normally with track by function', () => {
it('should track duplicate reinsertion normally', () => {
let l = buildItemList(['a', 'a']);
differ.check(l);
@ -385,6 +411,7 @@ export function main() {
expect(differ.toString())
.toEqual(iterableChangesAsString({
collection: ['{id: b}[null->0]', '{id: a}[0->1]', '{id: a}[1->2]'],
identityChanges: ['{id: a}[0->1]', '{id: a}[1->2]'],
previous: ['{id: a}[0->1]', '{id: a}[1->2]'],
moves: ['{id: a}[0->1]', '{id: a}[1->2]'],
additions: ['{id: b}[null->0]']
@ -392,7 +419,7 @@ export function main() {
});
it('should track removals normally with track by function', () => {
it('should track removals normally', () => {
let l = buildItemList(['a', 'b', 'c']);
differ.check(l);

View File

@ -421,6 +421,10 @@ export function main() {
it('should parse conditional expression',
() => { checkInterpolation('{{ a < b ? a : b }}'); });
it('should parse expression with newline characters', () => {
checkInterpolation(`{{ 'foo' +\n 'bar' +\r 'baz' }}`, `{{ "foo" + "bar" + "baz" }}`);
});
});
describe("parseSimpleBinding", () => {

View File

@ -1,11 +1,12 @@
import {isBlank, CONST_EXPR} from 'angular2/src/facade/lang';
export function iterableChangesAsString({collection = CONST_EXPR([]), previous = CONST_EXPR([]),
additions = CONST_EXPR([]), moves = CONST_EXPR([]),
removals = CONST_EXPR([])}) {
export function iterableChangesAsString(
{collection = CONST_EXPR([]), previous = CONST_EXPR([]), additions = CONST_EXPR([]),
moves = CONST_EXPR([]), removals = CONST_EXPR([]), identityChanges = CONST_EXPR([])}) {
return "collection: " + collection.join(', ') + "\n" + "previous: " + previous.join(', ') + "\n" +
"additions: " + additions.join(', ') + "\n" + "moves: " + moves.join(', ') + "\n" +
"removals: " + removals.join(', ') + "\n";
"removals: " + removals.join(', ') + "\n" + "identityChanges: " +
identityChanges.join(', ') + "\n";
}
export function kvChangesAsString(

View File

@ -189,6 +189,49 @@ export function main() {
expect(car.engine).toBeAnInstanceOf(Engine);
});
it('should throw when using a factory with more than 20 dependencies', () => {
function factoryWithTooManyArgs() { return new Car(null); }
var injector = createInjector([
Engine,
provide(Car,
{
useFactory: factoryWithTooManyArgs,
deps: [
Engine,
Engine,
Engine,
Engine,
Engine,
Engine,
Engine,
Engine,
Engine,
Engine,
Engine,
Engine,
Engine,
Engine,
Engine,
Engine,
Engine,
Engine,
Engine,
Engine,
Engine
]
})
]);
try {
injector.get(Car);
throw "Must throw";
} catch (e) {
expect(e.message)
.toContain(`Cannot instantiate 'Car' because it has more than 20 dependencies`);
}
});
it('should supporting provider to null', () => {
var injector = createInjector([provide(Engine, {useValue: null})]);
var engine = injector.get(Engine);

View File

@ -448,6 +448,21 @@ function declareTests() {
});
}));
it('should support directives where a selector matches event binding',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
tcb.overrideView(
MyComp,
new ViewMetadata(
{template: '<p (customEvent)="doNothing()"></p>', directives: [EventDir]}))
.createAsync(MyComp)
.then((fixture) => {
var tc = fixture.debugElement.children[0];
expect(tc.inject(EventDir)).not.toBe(null);
async.done();
});
}));
it('should read directives metadata from their binding token',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
tcb.overrideView(MyComp, new ViewMetadata({
@ -2133,6 +2148,13 @@ class IdDir {
id: string;
}
@Directive({selector: '[customEvent]'})
@Injectable()
class EventDir {
@Output() customEvent = new EventEmitter();
doSomething() {}
}
@Directive({selector: '[static]'})
@Injectable()
class NeedsAttribute {

View File

@ -4,9 +4,13 @@ import {
RegExpWrapper,
RegExpMatcherWrapper,
StringWrapper,
CONST_EXPR
CONST_EXPR,
hasConstructor
} from 'angular2/src/facade/lang';
class MySuperclass {}
class MySubclass extends MySuperclass {}
export function main() {
describe('RegExp', () => {
it('should expose the index for each match', () => {
@ -119,5 +123,13 @@ export function main() {
expect(StringWrapper.stripRight(null, "S")).toEqual(null);
});
});
describe('hasConstructor', () => {
it("should be true when the type matches",
() => { expect(hasConstructor(new MySuperclass(), MySuperclass)).toEqual(true); });
it("should be false for subtypes",
() => { expect(hasConstructor(new MySubclass(), MySuperclass)).toEqual(false); });
});
});
}

View File

@ -29,8 +29,8 @@ import {RequestOptions, BaseRequestOptions} from 'angular2/src/http/base_request
import {BaseResponseOptions, ResponseOptions} from 'angular2/src/http/base_response_options';
import {ResponseType, ReadyState, RequestMethod} from 'angular2/src/http/enums';
var addEventListenerSpy;
var existingScripts = [];
var addEventListenerSpy: any;
var existingScripts: MockBrowserJsonp[] = [];
var unused: Response;
class MockBrowserJsonp extends BrowserJsonp {
@ -67,8 +67,8 @@ class MockBrowserJsonp extends BrowserJsonp {
export function main() {
describe('JSONPBackend', () => {
let backend;
let sampleRequest;
let backend: JSONPBackend_;
let sampleRequest: Request;
beforeEach(() => {
let injector = Injector.resolveAndCreate([
@ -84,7 +84,7 @@ export function main() {
afterEach(() => { existingScripts = []; });
it('should create a connection', () => {
var instance;
var instance: JSONPConnection;
expect(() => instance = backend.createConnection(sampleRequest)).not.toThrow();
expect(instance).toBeAnInstanceOf(JSONPConnection);
});
@ -92,7 +92,7 @@ export function main() {
describe('JSONPConnection', () => {
it('should use the injected BaseResponseOptions to create the response',
inject([AsyncTestCompleter], async => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
let connection = new JSONPConnection_(sampleRequest, new MockBrowserJsonp(),
new ResponseOptions({type: ResponseType.Error}));
connection.response.subscribe(res => {
@ -103,7 +103,8 @@ export function main() {
existingScripts[0].dispatchEvent('load');
}));
it('should ignore load/callback when disposed', inject([AsyncTestCompleter], async => {
it('should ignore load/callback when disposed',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var connection = new JSONPConnection_(sampleRequest, new MockBrowserJsonp());
let spy = new SpyObject();
let loadSpy = spy.spy('load');
@ -126,7 +127,7 @@ export function main() {
}));
it('should report error if loaded without invoking callback',
inject([AsyncTestCompleter], async => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
let connection = new JSONPConnection_(sampleRequest, new MockBrowserJsonp());
connection.response.subscribe(
res => {
@ -141,7 +142,8 @@ export function main() {
existingScripts[0].dispatchEvent('load');
}));
it('should report error if script contains error', inject([AsyncTestCompleter], async => {
it('should report error if script contains error',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
let connection = new JSONPConnection_(sampleRequest, new MockBrowserJsonp());
connection.response.subscribe(
@ -169,7 +171,8 @@ export function main() {
});
});
it('should respond with data passed to callback', inject([AsyncTestCompleter], async => {
it('should respond with data passed to callback',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
let connection = new JSONPConnection_(sampleRequest, new MockBrowserJsonp());
connection.response.subscribe(res => {

View File

@ -22,16 +22,16 @@ import {Map} from 'angular2/src/facade/collection';
import {RequestOptions, BaseRequestOptions} from 'angular2/src/http/base_request_options';
import {BaseResponseOptions, ResponseOptions} from 'angular2/src/http/base_response_options';
import {ResponseType} from 'angular2/src/http/enums';
import {ReplaySubject} from 'rxjs/subject/ReplaySubject';
export function main() {
describe('MockBackend', () => {
var backend;
var sampleRequest1;
var sampleResponse1;
var sampleRequest2;
var sampleResponse2;
var connection;
var backend: MockBackend;
var sampleRequest1: Request;
var sampleResponse1: Response;
var sampleRequest2: Request;
var sampleResponse2: Response;
beforeEach(() => {
var injector = Injector.resolveAndCreate(
@ -50,47 +50,50 @@ export function main() {
() => {expect(backend.createConnection(sampleRequest1)).toBeAnInstanceOf(MockConnection)});
it('should create a new connection and allow subscription', () => {
let connection = backend.createConnection(sampleRequest1);
let connection: MockConnection = backend.createConnection(sampleRequest1);
connection.response.subscribe(() => {});
});
it('should allow responding after subscription', inject([AsyncTestCompleter], async => {
let connection = backend.createConnection(sampleRequest1);
connection.response.subscribe((res) => { async.done(); });
it('should allow responding after subscription',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
let connection: MockConnection = backend.createConnection(sampleRequest1);
connection.response.subscribe(() => { async.done(); });
connection.mockRespond(sampleResponse1);
}));
it('should allow subscribing after responding', inject([AsyncTestCompleter], async => {
let connection = backend.createConnection(sampleRequest1);
it('should allow subscribing after responding',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
let connection: MockConnection = backend.createConnection(sampleRequest1);
connection.mockRespond(sampleResponse1);
connection.response.subscribe((res) => { async.done(); });
connection.response.subscribe(() => { async.done(); });
}));
it('should allow responding after subscription with an error',
inject([AsyncTestCompleter], async => {
let connection = backend.createConnection(sampleRequest1);
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
let connection: MockConnection = backend.createConnection(sampleRequest1);
connection.response.subscribe(null, () => { async.done(); });
connection.mockError(new Error('nope'));
}));
it('should not throw when there are no unresolved requests',
inject([AsyncTestCompleter], async => {
let connection = backend.createConnection(sampleRequest1);
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
let connection: MockConnection = backend.createConnection(sampleRequest1);
connection.response.subscribe(() => { async.done(); });
connection.mockRespond(sampleResponse1);
backend.verifyNoPendingRequests();
}));
xit('should throw when there are unresolved requests', inject([AsyncTestCompleter], async => {
let connection = backend.createConnection(sampleRequest1);
xit('should throw when there are unresolved requests',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
let connection: MockConnection = backend.createConnection(sampleRequest1);
connection.response.subscribe(() => { async.done(); });
backend.verifyNoPendingRequests();
}));
it('should work when requests are resolved out of order',
inject([AsyncTestCompleter], async => {
let connection1 = backend.createConnection(sampleRequest1);
let connection2 = backend.createConnection(sampleRequest1);
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
let connection1: MockConnection = backend.createConnection(sampleRequest1);
let connection2: MockConnection = backend.createConnection(sampleRequest1);
connection1.response.subscribe(() => { async.done(); });
connection2.response.subscribe(() => {});
connection2.mockRespond(sampleResponse1);
@ -98,10 +101,12 @@ export function main() {
backend.verifyNoPendingRequests();
}));
xit('should allow double subscribing', inject([AsyncTestCompleter], async => {
let responses = [sampleResponse1, sampleResponse2];
backend.connections.subscribe(c => c.mockRespond(responses.shift()));
let responseObservable = backend.createConnection(sampleRequest1).response;
xit('should allow double subscribing',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
let responses: Response[] = [sampleResponse1, sampleResponse2];
backend.connections.subscribe((c: MockConnection) => c.mockRespond(responses.shift()));
let responseObservable: ReplaySubject<Response> =
backend.createConnection(sampleRequest1).response;
responseObservable.subscribe(res => expect(res.text()).toBe('response1'));
responseObservable.subscribe(res => expect(res.text()).toBe('response2'), null,
async.done);

View File

@ -23,12 +23,12 @@ import {RequestOptions, BaseRequestOptions} from 'angular2/src/http/base_request
import {BaseResponseOptions, ResponseOptions} from 'angular2/src/http/base_response_options';
import {ResponseType} from 'angular2/src/http/enums';
var abortSpy;
var sendSpy;
var openSpy;
var setRequestHeaderSpy;
var addEventListenerSpy;
var existingXHRs = [];
var abortSpy: any;
var sendSpy: any;
var openSpy: any;
var setRequestHeaderSpy: any;
var addEventListenerSpy: any;
var existingXHRs: MockBrowserXHR[] = [];
var unused: Response;
class MockBrowserXHR extends BrowserXhr {
@ -51,19 +51,21 @@ class MockBrowserXHR extends BrowserXhr {
this.setRequestHeader = setRequestHeaderSpy = spy.spy('setRequestHeader');
}
setStatusCode(status) { this.status = status; }
setStatusCode(status: number) { this.status = status; }
setResponse(value) { this.response = value; }
setResponse(value: string) { this.response = value; }
setResponseText(value) { this.responseText = value; }
setResponseText(value: string) { this.responseText = value; }
setResponseURL(value) { this.responseURL = value; }
setResponseURL(value: string) { this.responseURL = value; }
setResponseHeaders(value) { this.responseHeaders = value; }
setResponseHeaders(value: string) { this.responseHeaders = value; }
getAllResponseHeaders() { return this.responseHeaders || ''; }
getResponseHeader(key) { return Headers.fromResponseHeaderString(this.responseHeaders).get(key); }
getResponseHeader(key: string) {
return Headers.fromResponseHeaderString(this.responseHeaders).get(key);
}
addEventListener(type: string, cb: Function) { this.callbacks.set(type, cb); }
@ -80,8 +82,8 @@ class MockBrowserXHR extends BrowserXhr {
export function main() {
describe('XHRBackend', () => {
var backend;
var sampleRequest;
var backend: XHRBackend;
var sampleRequest: Request;
beforeEach(() => {
var injector = Injector.resolveAndCreate([
@ -102,10 +104,10 @@ export function main() {
describe('XHRConnection', () => {
it('should use the injected BaseResponseOptions to create the response',
inject([AsyncTestCompleter], async => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var connection = new XHRConnection(sampleRequest, new MockBrowserXHR(),
new ResponseOptions({type: ResponseType.Error}));
connection.response.subscribe(res => {
connection.response.subscribe((res: Response) => {
expect(res.type).toBe(ResponseType.Error);
async.done();
});
@ -113,11 +115,12 @@ export function main() {
existingXHRs[0].dispatchEvent('load');
}));
it('should complete a request', inject([AsyncTestCompleter], async => {
it('should complete a request', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var connection = new XHRConnection(sampleRequest, new MockBrowserXHR(),
new ResponseOptions({type: ResponseType.Error}));
connection.response.subscribe(res => { expect(res.type).toBe(ResponseType.Error); },
null, () => { async.done(); });
connection.response.subscribe((res: Response) => {
expect(res.type).toBe(ResponseType.Error);
}, null, () => { async.done(); });
existingXHRs[0].setStatusCode(200);
existingXHRs[0].dispatchEvent('load');
}));
@ -129,10 +132,11 @@ export function main() {
expect(abortSpy).toHaveBeenCalled();
});
it('should create an error Response on error', inject([AsyncTestCompleter], async => {
it('should create an error Response on error',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var connection = new XHRConnection(sampleRequest, new MockBrowserXHR(),
new ResponseOptions({type: ResponseType.Error}));
connection.response.subscribe(null, res => {
connection.response.subscribe(null, (res: Response) => {
expect(res.type).toBe(ResponseType.Error);
async.done();
});
@ -170,13 +174,14 @@ export function main() {
expect(setRequestHeaderSpy).toHaveBeenCalledWith('X-Multi', 'a,b');
});
it('should return the correct status code', inject([AsyncTestCompleter], async => {
it('should return the correct status code',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var statusCode = 418;
var connection = new XHRConnection(sampleRequest, new MockBrowserXHR(),
new ResponseOptions({status: statusCode}));
connection.response.subscribe(
res => {
(res: Response) => {
},
errRes => {
@ -188,7 +193,8 @@ export function main() {
existingXHRs[0].dispatchEvent('load');
}));
it('should call next and complete on 200 codes', inject([AsyncTestCompleter], async => {
it('should call next and complete on 200 codes',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var nextCalled = false;
var errorCalled = false;
var statusCode = 200;
@ -196,7 +202,7 @@ export function main() {
new ResponseOptions({status: statusCode}));
connection.response.subscribe(
res => {
(res: Response) => {
nextCalled = true;
expect(res.status).toBe(statusCode);
},
@ -210,14 +216,15 @@ export function main() {
existingXHRs[0].dispatchEvent('load');
}));
it('should call error and not complete on 300+ codes', inject([AsyncTestCompleter], async => {
it('should call error and not complete on 300+ codes',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var nextCalled = false;
var errorCalled = false;
var statusCode = 301;
var connection = new XHRConnection(sampleRequest, new MockBrowserXHR(),
new ResponseOptions({status: statusCode}));
connection.response.subscribe(res => { nextCalled = true; }, errRes => {
connection.response.subscribe((res: Response) => { nextCalled = true; }, errRes => {
expect(errRes.status).toBe(statusCode);
expect(nextCalled).toBe(false);
async.done();
@ -226,13 +233,14 @@ export function main() {
existingXHRs[0].setStatusCode(statusCode);
existingXHRs[0].dispatchEvent('load');
}));
it('should normalize IE\'s 1223 status code into 204', inject([AsyncTestCompleter], async => {
it('should normalize IE\'s 1223 status code into 204',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var statusCode = 1223;
var normalizedCode = 204;
var connection = new XHRConnection(sampleRequest, new MockBrowserXHR(),
new ResponseOptions({status: statusCode}));
connection.response.subscribe(res => {
connection.response.subscribe((res: Response) => {
expect(res.status).toBe(normalizedCode);
async.done();
});
@ -241,7 +249,8 @@ export function main() {
existingXHRs[0].dispatchEvent('load');
}));
it('should normalize responseText and response', inject([AsyncTestCompleter], async => {
it('should normalize responseText and response',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var responseBody = 'Doge';
var connection1 =
@ -250,7 +259,7 @@ export function main() {
var connection2 =
new XHRConnection(sampleRequest, new MockBrowserXHR(), new ResponseOptions());
connection1.response.subscribe(res => {
connection1.response.subscribe((res: Response) => {
expect(res.text()).toBe(responseBody);
connection2.response.subscribe(ress => {
@ -267,7 +276,7 @@ export function main() {
}));
it('should parse response headers and add them to the response',
inject([AsyncTestCompleter], async => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var statusCode = 200;
var connection = new XHRConnection(sampleRequest, new MockBrowserXHR(),
new ResponseOptions({status: statusCode}));
@ -278,7 +287,7 @@ export function main() {
Transfer-Encoding: chunked
Connection: keep-alive`
connection.response.subscribe(res => {
connection.response.subscribe((res: Response) => {
expect(res.headers.get('Date')).toEqual('Fri, 20 Nov 2015 01:45:26 GMT');
expect(res.headers.get('Content-Type')).toEqual('application/json; charset=utf-8');
expect(res.headers.get('Transfer-Encoding')).toEqual('chunked');
@ -291,12 +300,13 @@ export function main() {
existingXHRs[0].dispatchEvent('load');
}));
it('should add the responseURL to the response', inject([AsyncTestCompleter], async => {
it('should add the responseURL to the response',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var statusCode = 200;
var connection = new XHRConnection(sampleRequest, new MockBrowserXHR(),
new ResponseOptions({status: statusCode}));
connection.response.subscribe(res => {
connection.response.subscribe((res: Response) => {
expect(res.url).toEqual('http://google.com');
async.done();
});
@ -307,14 +317,14 @@ export function main() {
}));
it('should add use the X-Request-URL in CORS situations',
inject([AsyncTestCompleter], async => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var statusCode = 200;
var connection = new XHRConnection(sampleRequest, new MockBrowserXHR(),
new ResponseOptions({status: statusCode}));
var responseHeaders = `X-Request-URL: http://somedomain.com
Foo: Bar`
connection.response.subscribe(res => {
connection.response.subscribe((res: Response) => {
expect(res.url).toEqual('http://somedomain.com');
async.done();
});

View File

@ -1,4 +1,5 @@
import {Headers} from 'angular2/src/http/headers';
import {Json} from 'angular2/src/facade/lang';
import {Map, StringMapWrapper} from 'angular2/src/facade/collection';
import {
AsyncTestCompleter,
@ -62,6 +63,42 @@ export function main() {
expect(/bar, ?baz/g.test(headers.getAll('foo')[0])).toBe(true);
});
});
describe('.toJSON()', () => {
let headers = null;
let inputArr = null;
let obj = null;
beforeEach(() => {
headers = new Headers();
inputArr = ['application/jeisen', 'application/jason', 'application/patrickjs'];
obj = {'Accept': inputArr};
headers.set('Accept', inputArr);
});
it('should be serializable with toJSON', () => {
let stringifed = Json.stringify(obj);
let serializedHeaders = Json.stringify(headers);
expect(serializedHeaders).toEqual(stringifed);
});
it('should be able to parse serialized header', () => {
let stringifed = Json.stringify(obj);
let serializedHeaders = Json.stringify(headers);
expect(Json.parse(serializedHeaders)).toEqual(Json.parse(stringifed));
});
it('should be able to recreate serializedHeaders', () => {
let serializedHeaders = Json.stringify(headers);
let parsedHeaders = Json.parse(serializedHeaders);
let recreatedHeaders = new Headers(parsedHeaders);
expect(Json.stringify(parsedHeaders)).toEqual(Json.stringify(recreatedHeaders));
});
});
});
describe('.fromResponseHeaderString()', () => {

View File

@ -42,7 +42,7 @@ export function main() {
var jsonp: Jsonp;
it('should allow using jsonpInjectables and httpInjectables in same injector',
inject([AsyncTestCompleter], (async) => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
parentInjector = Injector.resolveAndCreate([
provide(XHRBackend, {useClass: MockBackend}),
provide(JSONPBackend, {useClass: MockBackend})
@ -91,7 +91,7 @@ export function main() {
var http: Http;
var injector: Injector;
var backend: MockBackend;
var baseResponse;
var baseResponse: Response;
var jsonp: Jsonp;
beforeEach(() => {
injector = Injector.resolveAndCreate([
@ -129,19 +129,19 @@ export function main() {
it('should accept a fully-qualified request as its only parameter',
inject([AsyncTestCompleter], (async) => {
backend.connections.subscribe(c => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
backend.connections.subscribe((c: MockConnection) => {
expect(c.request.url).toBe('https://google.com');
c.mockRespond(new Response(new ResponseOptions({body: 'Thank you'})));
async.done();
});
http.request(new Request(new RequestOptions({url: 'https://google.com'})))
.subscribe((res) => {});
.subscribe((res: Response) => {});
}));
it('should accept a fully-qualified request as its only parameter',
inject([AsyncTestCompleter], (async) => {
backend.connections.subscribe(c => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
backend.connections.subscribe((c: MockConnection) => {
expect(c.request.url).toBe('https://google.com');
expect(c.request.method).toBe(RequestMethod.Post);
c.mockRespond(new Response(new ResponseOptions({body: 'Thank you'})));
@ -149,64 +149,64 @@ export function main() {
});
http.request(new Request(new RequestOptions(
{url: 'https://google.com', method: RequestMethod.Post})))
.subscribe((res) => {});
.subscribe((res: Response) => {});
}));
it('should perform a get request for given url if only passed a string',
inject([AsyncTestCompleter], (async) => {
backend.connections.subscribe(c => c.mockRespond(baseResponse));
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
backend.connections.subscribe((c: MockConnection) => c.mockRespond(baseResponse));
http.request('http://basic.connection')
.subscribe(res => {
.subscribe((res: Response) => {
expect(res.text()).toBe('base response');
async.done();
});
}));
it('should perform a post request for given url if options include a method',
inject([AsyncTestCompleter], (async) => {
backend.connections.subscribe(c => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
backend.connections.subscribe((c: MockConnection) => {
expect(c.request.method).toEqual(RequestMethod.Post);
c.mockRespond(baseResponse);
});
let requestOptions = new RequestOptions({method: RequestMethod.Post});
http.request('http://basic.connection', requestOptions)
.subscribe(res => {
.subscribe((res: Response) => {
expect(res.text()).toBe('base response');
async.done();
});
}));
it('should perform a post request for given url if options include a method',
inject([AsyncTestCompleter], (async) => {
backend.connections.subscribe(c => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
backend.connections.subscribe((c: MockConnection) => {
expect(c.request.method).toEqual(RequestMethod.Post);
c.mockRespond(baseResponse);
});
let requestOptions = {method: RequestMethod.Post};
http.request('http://basic.connection', requestOptions)
.subscribe(res => {
.subscribe((res: Response) => {
expect(res.text()).toBe('base response');
async.done();
});
}));
it('should perform a get request and complete the response',
inject([AsyncTestCompleter], (async) => {
backend.connections.subscribe(c => c.mockRespond(baseResponse));
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
backend.connections.subscribe((c: MockConnection) => c.mockRespond(baseResponse));
http.request('http://basic.connection')
.subscribe(res => { expect(res.text()).toBe('base response'); }, null,
.subscribe((res: Response) => { expect(res.text()).toBe('base response'); }, null,
() => { async.done(); });
}));
it('should perform multiple get requests and complete the responses',
inject([AsyncTestCompleter], (async) => {
backend.connections.subscribe(c => c.mockRespond(baseResponse));
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
backend.connections.subscribe((c: MockConnection) => c.mockRespond(baseResponse));
http.request('http://basic.connection')
.subscribe(res => { expect(res.text()).toBe('base response'); });
.subscribe((res: Response) => { expect(res.text()).toBe('base response'); });
http.request('http://basic.connection')
.subscribe(res => { expect(res.text()).toBe('base response'); }, null,
.subscribe((res: Response) => { expect(res.text()).toBe('base response'); }, null,
() => { async.done(); });
}));
@ -219,149 +219,160 @@ export function main() {
describe('.get()', () => {
it('should perform a get request for given url', inject([AsyncTestCompleter], async => {
backend.connections.subscribe(c => {
it('should perform a get request for given url',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
backend.connections.subscribe((c: MockConnection) => {
expect(c.request.method).toBe(RequestMethod.Get);
backend.resolveAllConnections();
async.done();
});
http.get(url).subscribe(res => {});
http.get(url).subscribe((res: Response) => {});
}));
});
describe('.post()', () => {
it('should perform a post request for given url', inject([AsyncTestCompleter], async => {
backend.connections.subscribe(c => {
it('should perform a post request for given url',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
backend.connections.subscribe((c: MockConnection) => {
expect(c.request.method).toBe(RequestMethod.Post);
backend.resolveAllConnections();
async.done();
});
http.post(url, 'post me').subscribe(res => {});
http.post(url, 'post me').subscribe((res: Response) => {});
}));
it('should attach the provided body to the request', inject([AsyncTestCompleter], async => {
it('should attach the provided body to the request',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var body = 'this is my post body';
backend.connections.subscribe(c => {
backend.connections.subscribe((c: MockConnection) => {
expect(c.request.text()).toBe(body);
backend.resolveAllConnections();
async.done();
});
http.post(url, body).subscribe(res => {});
http.post(url, body).subscribe((res: Response) => {});
}));
});
describe('.put()', () => {
it('should perform a put request for given url', inject([AsyncTestCompleter], async => {
backend.connections.subscribe(c => {
it('should perform a put request for given url',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
backend.connections.subscribe((c: MockConnection) => {
expect(c.request.method).toBe(RequestMethod.Put);
backend.resolveAllConnections();
async.done();
});
http.put(url, 'put me').subscribe(res => {});
http.put(url, 'put me').subscribe((res: Response) => {});
}));
it('should attach the provided body to the request', inject([AsyncTestCompleter], async => {
it('should attach the provided body to the request',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var body = 'this is my put body';
backend.connections.subscribe(c => {
backend.connections.subscribe((c: MockConnection) => {
expect(c.request.text()).toBe(body);
backend.resolveAllConnections();
async.done();
});
http.put(url, body).subscribe(res => {});
http.put(url, body).subscribe((res: Response) => {});
}));
});
describe('.delete()', () => {
it('should perform a delete request for given url', inject([AsyncTestCompleter], async => {
backend.connections.subscribe(c => {
it('should perform a delete request for given url',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
backend.connections.subscribe((c: MockConnection) => {
expect(c.request.method).toBe(RequestMethod.Delete);
backend.resolveAllConnections();
async.done();
});
http.delete(url).subscribe(res => {});
http.delete(url).subscribe((res: Response) => {});
}));
});
describe('.patch()', () => {
it('should perform a patch request for given url', inject([AsyncTestCompleter], async => {
backend.connections.subscribe(c => {
it('should perform a patch request for given url',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
backend.connections.subscribe((c: MockConnection) => {
expect(c.request.method).toBe(RequestMethod.Patch);
backend.resolveAllConnections();
async.done();
});
http.patch(url, 'this is my patch body').subscribe(res => {});
http.patch(url, 'this is my patch body').subscribe((res: Response) => {});
}));
it('should attach the provided body to the request', inject([AsyncTestCompleter], async => {
it('should attach the provided body to the request',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var body = 'this is my patch body';
backend.connections.subscribe(c => {
backend.connections.subscribe((c: MockConnection) => {
expect(c.request.text()).toBe(body);
backend.resolveAllConnections();
async.done();
});
http.patch(url, body).subscribe(res => {});
http.patch(url, body).subscribe((res: Response) => {});
}));
});
describe('.head()', () => {
it('should perform a head request for given url', inject([AsyncTestCompleter], async => {
backend.connections.subscribe(c => {
it('should perform a head request for given url',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
backend.connections.subscribe((c: MockConnection) => {
expect(c.request.method).toBe(RequestMethod.Head);
backend.resolveAllConnections();
async.done();
});
http.head(url).subscribe(res => {});
http.head(url).subscribe((res: Response) => {});
}));
});
describe('searchParams', () => {
it('should append search params to url', inject([AsyncTestCompleter], async => {
it('should append search params to url',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var params = new URLSearchParams();
params.append('q', 'puppies');
backend.connections.subscribe(c => {
backend.connections.subscribe((c: MockConnection) => {
expect(c.request.url).toEqual('https://www.google.com?q=puppies');
backend.resolveAllConnections();
async.done();
});
http.get('https://www.google.com', new RequestOptions({search: params}))
.subscribe(res => {});
.subscribe((res: Response) => {});
}));
it('should append string search params to url', inject([AsyncTestCompleter], async => {
backend.connections.subscribe(c => {
it('should append string search params to url',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
backend.connections.subscribe((c: MockConnection) => {
expect(c.request.url).toEqual('https://www.google.com?q=piggies');
backend.resolveAllConnections();
async.done();
});
http.get('https://www.google.com', new RequestOptions({search: 'q=piggies'}))
.subscribe(res => {});
.subscribe((res: Response) => {});
}));
it('should produce valid url when url already contains a query',
inject([AsyncTestCompleter], async => {
backend.connections.subscribe(c => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
backend.connections.subscribe((c: MockConnection) => {
expect(c.request.url).toEqual('https://www.google.com?q=angular&as_eq=1.x');
backend.resolveAllConnections();
async.done();
});
http.get('https://www.google.com?q=angular', new RequestOptions({search: 'as_eq=1.x'}))
.subscribe(res => {});
.subscribe((res: Response) => {});
}));
});
describe('string method names', () => {
it('should allow case insensitive strings for method names', () => {
inject([AsyncTestCompleter], (async) => {
backend.connections.subscribe(c => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
backend.connections.subscribe((c: MockConnection) => {
expect(c.request.method)
.toBe(RequestMethod.Post)
c.mockRespond(new Response(new ResponseOptions({body: 'Thank you'})));
@ -369,7 +380,7 @@ export function main() {
});
http.request(
new Request(new RequestOptions({url: 'https://google.com', method: 'PosT'})))
.subscribe((res) => {});
.subscribe((res: Response) => {});
});
});

View File

@ -51,6 +51,7 @@ var NG_COMMON = [
'AbstractControl.validator',
'AbstractControl.validator=',
'AbstractControl.value',
'AbstractControl.root',
'AbstractControl.valueChanges',
'AbstractControlDirective',
'AbstractControlDirective.control',
@ -102,6 +103,7 @@ var NG_COMMON = [
'Control.validator',
'Control.validator=',
'Control.value',
'Control.root',
'Control.valueChanges',
'ControlArray',
'ControlArray.asyncValidator',
@ -134,6 +136,7 @@ var NG_COMMON = [
'ControlArray.validator',
'ControlArray.validator=',
'ControlArray.value',
'ControlArray.root',
'ControlArray.valueChanges',
'ControlContainer',
'ControlContainer.control',
@ -179,6 +182,7 @@ var NG_COMMON = [
'ControlGroup.validator',
'ControlGroup.validator=',
'ControlGroup.value',
'ControlGroup.root',
'ControlGroup.valueChanges',
'ControlValueAccessor:dart',
'CurrencyPipe',
@ -415,6 +419,7 @@ var NG_COMMON = [
'ObservableListDiff.forEachMovedItem():dart',
'ObservableListDiff.forEachPreviousItem():dart',
'ObservableListDiff.forEachRemovedItem():dart',
'ObservableListDiff.forEachIdentityChange():dart',
'ObservableListDiff.isDirty:dart',
'ObservableListDiff.length:dart',
'ObservableListDiff.onDestroy():dart',
@ -447,7 +452,12 @@ var NG_COMMON = [
'Validators#maxLength()',
'Validators#minLength()',
'Validators#nullValidator()',
'Validators#required()'
'Validators#required()',
'RadioButtonState',
'RadioButtonState.checked',
'RadioButtonState.checked=',
'RadioButtonState.value',
'RadioButtonState.value='
];
var NG_COMPILER = [

View File

@ -105,6 +105,20 @@ export function main() {
});
}));
it('should navigate to child routes when the root component has an empty path',
inject([AsyncTestCompleter, Location], (async, location) => {
compile(tcb, 'outer { <router-outlet></router-outlet> }')
.then((rtc) => {fixture = rtc})
.then((_) => rtr.config([new Route({path: '/...', component: ParentCmp})]))
.then((_) => rtr.navigateByUrl('/b'))
.then((_) => {
fixture.detectChanges();
expect(fixture.debugElement.nativeElement).toHaveText('outer { inner { hello } }');
expect(location.urlChanges).toEqual(['/b']);
async.done();
});
}));
it('should navigate to child routes of async routes', inject([AsyncTestCompleter], (async) => {
compile(tcb, 'outer { <router-outlet></router-outlet> }')
.then((rtc) => {fixture = rtc})

View File

@ -90,5 +90,14 @@ export function main() {
expect(match['allParams']).toEqual({'c': '3'});
});
});
describe('wildcard segment', () => {
it('should return a url path which matches the original url path', () => {
var rec = new PathRecognizer('/wild/*everything');
var url = parser.parse('/wild/super;variable=value/anotherPartAfterSlash');
var match = rec.recognize(url);
expect(match['urlPath']).toEqual('wild/super;variable=value/anotherPartAfterSlash');
});
});
});
}

View File

@ -220,6 +220,15 @@ export function main() {
expect(path).toEqual('hi/how/are/you?name=brad');
});
it('should preserve the number 1 as a query string value', () => {
router.config(
[new Route({path: '/hi/how/are/you', component: DummyComponent, name: 'GreetingUrl'})]);
var instruction = router.generate(['/GreetingUrl', {'name': 1}]);
var path = stringifyInstruction(instruction);
expect(path).toEqual('hi/how/are/you?name=1');
});
it('should serialize parameters that are not part of the route definition as query string params',
() => {
router.config([

View File

@ -1,30 +1,33 @@
{
"version": "v4",
"repo": "angular/DefinitelyTyped",
"repo": "DefinitelyTyped/DefinitelyTyped",
"ref": "master",
"path": "typings",
"bundle": "typings/tsd.d.ts",
"installed": {
"es6-shim/es6-shim.d.ts": {
"commit": "4b36b94d5910aa8a4d20bdcd5bd1f9ae6ad18d3c"
"es6-promise/es6-promise.d.ts": {
"commit": "6eebd5e90a1cbd6b47b0705ba72dbcd5baf846f3"
},
"es6-collections/es6-collections.d.ts": {
"commit": "6eebd5e90a1cbd6b47b0705ba72dbcd5baf846f3"
},
"hammerjs/hammerjs.d.ts": {
"commit": "22c44d95912a07f81c103a694330b15b92f7cb40"
"commit": "6eebd5e90a1cbd6b47b0705ba72dbcd5baf846f3"
},
"jasmine/jasmine.d.ts": {
"commit": "4b36b94d5910aa8a4d20bdcd5bd1f9ae6ad18d3c"
"commit": "6eebd5e90a1cbd6b47b0705ba72dbcd5baf846f3"
},
"node/node.d.ts": {
"commit": "51738fdf1643d269067861b405e87503b7479236"
"commit": "6eebd5e90a1cbd6b47b0705ba72dbcd5baf846f3"
},
"selenium-webdriver/selenium-webdriver.d.ts": {
"commit": "be0b6b394f77a59e192ad7cfec18078706e44db5"
"commit": "6eebd5e90a1cbd6b47b0705ba72dbcd5baf846f3"
},
"zone/zone.d.ts": {
"commit": "31e7317c9a0793857109236ef7c7f223305a8aa9"
"zone.js/zone.js.d.ts": {
"commit": "6eebd5e90a1cbd6b47b0705ba72dbcd5baf846f3"
},
"angular-protractor/angular-protractor.d.ts": {
"commit": "4207593c012565a7ea800ed861ffbe5011e7a501"
"commit": "6eebd5e90a1cbd6b47b0705ba72dbcd5baf846f3"
}
}
}

View File

@ -11,7 +11,8 @@ describe('md-progress-linear', function() {
var incrementButton = element(by.id('increment'));
var decrementButton = element(by.id('decrement'));
var initialValue = progressBar.getAttribute('aria-valuenow');
// Really a Promise<string> but can be coerced to a number after resolving
var initialValue: any = progressBar.getAttribute('aria-valuenow');
incrementButton.click();
expect(progressBar.getAttribute('aria-valuenow')).toBeGreaterThan(initialValue);

View File

@ -23,9 +23,10 @@ describe('WebWorkers Kitchen Sink', function() {
// This test can't wait for Angular 2 as Testability is not available when using WebWorker
browser.ignoreSynchronization = true;
browser.get(URL);
let changeButtonSelector = 'hello-app .changeButton';
browser.wait(protractor.until.elementLocated(by.css(selector)), 15000);
element(by.css("hello-app .changeButton")).click();
browser.wait(protractor.until.elementLocated(by.css(changeButtonSelector)), 15000);
element(by.css(changeButtonSelector)).click();
var elem = element(by.css(selector));
browser.wait(protractor.until.elementTextIs(elem, "howdy world!"), 5000);
expect(elem.getText()).toEqual("howdy world!");

View File

@ -46,13 +46,13 @@
"version": "1.0.0"
},
"angular": {
"version": "1.4.8"
"version": "1.5.0"
},
"angular-animate": {
"version": "1.4.8"
"version": "1.5.0"
},
"angular-mocks": {
"version": "1.4.8"
"version": "1.5.0"
},
"ansi": {
"version": "0.3.0"
@ -5345,7 +5345,7 @@
}
},
"ts2dart": {
"version": "0.7.19",
"version": "0.7.22",
"dependencies": {
"source-map": {
"version": "0.4.4"
@ -5824,9 +5824,9 @@
}
},
"zone.js": {
"version": "0.5.11"
"version": "0.5.13"
}
},
"name": "angular-srcs",
"version": "2.0.0-beta.1"
"version": "2.0.0-beta.3"
}

40
npm-shrinkwrap.json generated
View File

@ -1,6 +1,6 @@
{
"name": "angular-srcs",
"version": "2.0.0-beta.1",
"version": "2.0.0-beta.3",
"dependencies": {
"abbrev": {
"version": "1.0.7",
@ -74,19 +74,19 @@
"resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.0.tgz"
},
"angular": {
"version": "1.4.8",
"from": "angular@>=1.4.7 <2.0.0",
"resolved": "https://registry.npmjs.org/angular/-/angular-1.4.8.tgz"
"version": "1.5.0",
"from": "angular@1.5.0",
"resolved": "https://registry.npmjs.org/angular/-/angular-1.5.0.tgz"
},
"angular-animate": {
"version": "1.4.8",
"from": "angular-animate@>=1.4.7 <2.0.0",
"resolved": "https://registry.npmjs.org/angular-animate/-/angular-animate-1.4.8.tgz"
"version": "1.5.0",
"from": "angular-animate@1.5.0",
"resolved": "https://registry.npmjs.org/angular-animate/-/angular-animate-1.5.0.tgz"
},
"angular-mocks": {
"version": "1.4.8",
"from": "angular-mocks@>=1.4.7 <2.0.0",
"resolved": "https://registry.npmjs.org/angular-mocks/-/angular-mocks-1.4.8.tgz"
"version": "1.5.0",
"from": "angular-mocks@1.5.0",
"resolved": "https://registry.npmjs.org/angular-mocks/-/angular-mocks-1.5.0.tgz"
},
"ansi": {
"version": "0.3.0",
@ -8518,30 +8518,30 @@
}
},
"ts2dart": {
"version": "0.7.19",
"from": "ts2dart@>=0.7.18 <0.8.0",
"resolved": "https://registry.npmjs.org/ts2dart/-/ts2dart-0.7.19.tgz",
"version": "0.7.22",
"from": "https://registry.npmjs.org/ts2dart/-/ts2dart-0.7.22.tgz",
"resolved": "https://registry.npmjs.org/ts2dart/-/ts2dart-0.7.22.tgz",
"dependencies": {
"source-map": {
"version": "0.4.4",
"from": "source-map@>=0.4.2 <0.5.0",
"from": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz"
},
"source-map-support": {
"version": "0.3.3",
"from": "source-map-support@>=0.3.1 <0.4.0",
"from": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.3.3.tgz",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.3.3.tgz",
"dependencies": {
"source-map": {
"version": "0.1.32",
"from": "source-map@0.1.32",
"from": "https://registry.npmjs.org/source-map/-/source-map-0.1.32.tgz",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.32.tgz"
}
}
},
"typescript": {
"version": "1.7.3",
"from": "typescript@1.7.3",
"from": "https://registry.npmjs.org/typescript/-/typescript-1.7.3.tgz",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-1.7.3.tgz"
}
}
@ -9291,9 +9291,9 @@
}
},
"zone.js": {
"version": "0.5.11",
"from": "zone.js@0.5.11",
"resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.5.11.tgz"
"version": "0.5.13",
"from": "https://registry.npmjs.org/zone.js/-/zone.js-0.5.13.tgz",
"resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.5.13.tgz"
}
}
}

View File

@ -1,6 +1,6 @@
{
"name": "angular-srcs",
"version": "2.0.0-beta.3",
"version": "2.0.0-beta.5",
"branchPattern": "2.0.*",
"description": "Angular 2 - a web framework for modern web apps",
"homepage": "https://github.com/angular/angular",
@ -35,13 +35,13 @@
"es6-promise": "^3.0.2",
"es6-shim": "^0.33.3",
"reflect-metadata": "0.1.2",
"rxjs": "5.0.0-beta.0",
"zone.js": "0.5.11"
"rxjs": "^5.0.0-beta.2",
"zone.js": "^0.5.14"
},
"devDependencies": {
"angular": "^1.4.7",
"angular-animate": "^1.4.7",
"angular-mocks": "^1.4.7",
"angular": "^1.5.0",
"angular-animate": "^1.5.0",
"angular-mocks": "^1.5.0",
"base64-js": "^0.0.8",
"bower": "^1.3.12",
"broccoli": "^0.16.9",
@ -111,7 +111,7 @@
"systemjs": "0.18.10",
"systemjs-builder": "^0.10.3",
"through2": "^0.6.5",
"ts2dart": "^0.7.19",
"ts2dart": "^0.7.22",
"ts-api-guardian": "0.0.2",
"tsd": "^0.6.5-beta",
"tslint": "^3.2.1",

View File

@ -15,7 +15,6 @@ cd $ROOT_DIR
NPM_DIR=$ROOT_DIR/dist/npm
FILES='!(test|e2e_test|docs)'
DTS_FILES='*.d.ts'
PUBLISH_DIR=$NPM_DIR/$NAME
rm -fr $PUBLISH_DIR
@ -29,14 +28,9 @@ mkdir -p $PUBLISH_DIR/ts
cp -r $ROOT_DIR/modules/$NAME/$FILES $PUBLISH_DIR/ts
if [ $NAME = "angular2" ]; then
# Publish bundles and typings
mkdir -p $PUBLISH_DIR/bundles/typings/es6-shim
mkdir -p $PUBLISH_DIR/bundles/typings/jasmine
# Copy Bundles
mkdir -p $PUBLISH_DIR/bundles
cp -r $ROOT_DIR/dist/js/bundle/$FILES $PUBLISH_DIR/bundles
# Copy Typings
cp -r $ROOT_DIR/modules/angular2/typings/es6-shim/$DTS_FILES $PUBLISH_DIR/bundles/typings/es6-shim
cp -r $ROOT_DIR/modules/angular2/typings/jasmine/$DTS_FILES $PUBLISH_DIR/bundles/typings/jasmine
fi
if [ $NAME = "benchpress" ]; then

View File

@ -171,6 +171,14 @@ module.exports = function makeBrowserTree(options, destinationPath) {
patterns: [{match: /\$SCRIPTS\$/, replacement: jsReplace('SCRIPTS')}]
});
let ambientTypings = [
'angular2/typings/hammerjs/hammerjs.d.ts',
'angular2/typings/node/node.d.ts',
'angular2/manual_typings/globals.d.ts',
'angular2/typings/es6-collections/es6-collections.d.ts',
'angular2/typings/es6-promise/es6-promise.d.ts'
];
// Use TypeScript to transpile the *.ts files to ES5
var es5Tree = compileWithTypescript(es5ModulesTree, {
declaration: false,
@ -180,7 +188,7 @@ module.exports = function makeBrowserTree(options, destinationPath) {
moduleResolution: 'classic',
noEmitOnError: !noTypeChecks,
rootDir: './',
rootFilePaths: ['angular2/manual_typings/globals.d.ts'],
rootFilePaths: ambientTypings,
inlineSourceMap: sourceMaps,
inlineSources: sourceMaps,
target: 'es5'
@ -311,7 +319,11 @@ module.exports = function makeBrowserTree(options, destinationPath) {
experimentalDecorators: true,
noEmitOnError: false,
rootDir: './',
rootFilePaths: ['angular2/manual_typings/globals-es6.d.ts'],
rootFilePaths: [
'angular2/typings/zone.js/zone.js.d.ts',
'angular2/typings/hammerjs/hammerjs.d.ts',
'angular2/typings/node/node.d.ts',
],
inlineSourceMap: sourceMaps,
inlineSources: sourceMaps,
target: 'es6'

View File

@ -32,9 +32,16 @@ module.exports = function makeNodeTree(projects, destinationPath) {
]
});
let ambientTypings = [
'angular2/typings/hammerjs/hammerjs.d.ts',
'angular2/typings/node/node.d.ts',
'angular2/manual_typings/globals.d.ts',
'angular2/typings/es6-collections/es6-collections.d.ts',
'angular2/typings/es6-promise/es6-promise.d.ts'
];
// Compile the sources and generate the @internal .d.ts
let compiledSrcTreeWithInternals =
compileTree(srcTree, true, ['angular2/manual_typings/globals.d.ts']);
let compiledSrcTreeWithInternals = compileTree(srcTree, true, ambientTypings);
var testTree = new Funnel('modules', {
include: [
@ -85,11 +92,10 @@ module.exports = function makeNodeTree(projects, destinationPath) {
testTree = mergeTrees([testTree, srcPrivateDeclarations]);
let compiledTestTree = compileTree(testTree, false, [
let compiledTestTree = compileTree(testTree, false, ambientTypings.concat([
'angular2/typings/jasmine/jasmine.d.ts',
'angular2/typings/angular-protractor/angular-protractor.d.ts',
'angular2/manual_typings/globals.d.ts'
]);
]));
// Merge the compiled sources and tests
let compiledSrcTree =
@ -112,12 +118,7 @@ module.exports = function makeNodeTree(projects, destinationPath) {
var srcPkgJsons = extractPkgJsons(srcTree, BASE_PACKAGE_JSON);
var testPkgJsons = extractPkgJsons(testTree, BASE_PACKAGE_JSON);
var typingsTree = new Funnel(
'modules',
{include: ['angular2/typings/**/*.d.ts', 'angular2/manual_typings/*.d.ts'], destDir: '/'});
var nodeTree =
mergeTrees([compiledTree, srcDocs, testDocs, srcPkgJsons, testPkgJsons, typingsTree]);
var nodeTree = mergeTrees([compiledTree, srcDocs, testDocs, srcPkgJsons, testPkgJsons]);
// Transform all tests to make them runnable in node
nodeTree = replace(nodeTree, {
@ -139,22 +140,6 @@ module.exports = function makeNodeTree(projects, destinationPath) {
nodeTree = replace(
nodeTree, {files: ['**/*.js'], patterns: [{match: /^/, replacement: () => `'use strict';`}]});
// Add a line to the end of our top-level .d.ts file.
// This HACK for transitive typings is a workaround for
// https://github.com/Microsoft/TypeScript/issues/5097
//
// This allows users to get our top-level dependencies like zone.d.ts
// to appear when they compile against angular2.
//
// This carries the risk that the user brings their own copy of that file
// (or any other symbols exported here) and they will get a compiler error
// because of the duplicate definitions.
// TODO(alexeagle): remove this when typescript releases a fix
nodeTree = replace(nodeTree, {
files: ['angular2/core.d.ts'],
patterns: [{match: /$/, replacement: 'import "./manual_typings/globals-es6.d.ts";\r\n'}]
});
return destCopy(nodeTree, destinationPath);
};

View File

@ -566,6 +566,7 @@ const COMMON = [
'AbstractControl.updateValueAndValidity({onlySelf,emitEvent}:{onlySelf?:boolean, emitEvent?:boolean}):void',
'AbstractControl.valid:boolean',
'AbstractControl.value:any',
'AbstractControl.root:AbstractControl',
'AbstractControl.valueChanges:Observable<any>',
'AbstractControlDirective',
'AbstractControlDirective.control:AbstractControl',
@ -794,6 +795,8 @@ const COMMON = [
'Validators.minLength(minLength:number):Function',
'Validators.nullValidator(c:any):{[key:string]:boolean}',
'Validators.required(control:Control):{[key:string]:boolean}',
'RadioButtonState',
'RadioButtonState.constructor(checked:boolean, value:string)',
'const COMMON_DIRECTIVES:Type[][]',
'const COMMON_PIPES:any',
'const CORE_DIRECTIVES:Type[]',

View File

@ -1,21 +1,21 @@
{
"version": "v4",
"repo": "angular/DefinitelyTyped",
"repo": "DefinitelyTyped/DefinitelyTyped",
"ref": "master",
"path": "typings",
"bundle": "typings/tsd.d.ts",
"installed": {
"fs-extra/fs-extra.d.ts": {
"commit": "fa52db59121913b35e9641a0f73ccc3ffba58840"
"commit": "6eebd5e90a1cbd6b47b0705ba72dbcd5baf846f3"
},
"node/node.d.ts": {
"commit": "285e6b692a5898ccc1dc19475187429deafb69d7"
"commit": "6eebd5e90a1cbd6b47b0705ba72dbcd5baf846f3"
},
"es6-promise/es6-promise.d.ts": {
"commit": "d5f92f93bdb49f332fa662ff1d0cc8700f02e4dc"
"commit": "6eebd5e90a1cbd6b47b0705ba72dbcd5baf846f3"
},
"jasmine/jasmine.d.ts": {
"commit": "5996649b8eecebbd6dd2e25a6a254de1b169a65c"
"commit": "6eebd5e90a1cbd6b47b0705ba72dbcd5baf846f3"
}
}
}