Compare commits

..

47 Commits
2.4.0 ... 2.1.2

Author SHA1 Message Date
19273a89b6 chore(release): cut the 2.1.2 release 2016-10-27 20:28:13 +02:00
957192db6d docs(changelog): update changelog with changes in v2.1.2 2016-10-27 20:28:00 +02:00
4546f09b0e chore(release): cut the 2.2.0-beta.0 release 2016-10-27 20:16:38 +02:00
c7e4b86bf1 fix: remove double exports of template_ast 2016-10-27 20:15:18 +02:00
3a67339945 docs(reset): change semi-colon to colon in code example
The first code example for the reset function was invalid as it has a semi-colon instead of a colon for the last property in the json object.  Change the semi-colon to a colon.

Closes https://github.com/angular/angular/issues/12531
2016-10-27 20:14:59 +02:00
80fef43334 fix(compiler-cli): fix types 2016-10-27 20:14:51 +02:00
80efa4b26b fix(selectors): use Maps instead of objects 2016-10-27 20:14:46 +02:00
92103606e1 fix(xsrf): overwrite already set xsrf header 2016-10-27 20:14:40 +02:00
487970f6f2 refactor(compiler): move host properties into DirectiveWrapper
Part of #11683
2016-10-27 20:14:29 +02:00
89a493934f refactor(compiler): make arguments in InlineArray optional. 2016-10-27 20:14:23 +02:00
6f54ed01a8 refactor(compiler): extract createCheckBindingStmt into compiler_util
Part of #11683
2016-10-27 20:14:15 +02:00
ef99670343 refactor(compiler): minor cleanups 2016-10-27 20:14:06 +02:00
808e4cf1b6 refactor(compiler): extract expression evaluation and writing to renderer from view_compiler
This is needed to that `DirectiveWrapper`s can also use them later on.

Part of #11683
2016-10-27 20:13:59 +02:00
9cb71fc7c9 refactor(compiler): introduce ClassBuilder.
Part of #11683
2016-10-27 20:13:52 +02:00
6f082f93f5 refactor(compiler): set element attributes via one call
This makes the cost of using directives that have host attributes
smaller.

Part of #11683
2016-10-27 20:13:45 +02:00
0d7124e7cb refactor(compiler): extract BindingParser
Needed so that we can parse directive host bindings independent of templates.

Part of #11683
2016-10-27 20:13:39 +02:00
52896591e6 fix(router): preserve resolve data
Closes #12306
2016-10-27 20:13:26 +02:00
07c44a76f9 tests(router): add a test showing how to handle resovle errors 2016-10-27 20:13:11 +02:00
3b5fc56cc1 fix(router): change router not to deactivate aux routes when navigating from a componentless routes 2016-10-27 20:13:03 +02:00
2c30365496 fix(router): disallow component routes with named outlets
Closes #11208, #11082
2016-10-27 20:12:57 +02:00
8c6b376c07 fix(router): add a test to make sure canDeactivate guards are called for aux routes
Closes #11345
2016-10-27 20:12:48 +02:00
089d4533b3 fix(router): canDeactivate guards are not triggered for componentless routes
Closes #12375
2016-10-27 20:12:37 +02:00
8113a03c21 fix(CompilerCli): assert that all pipes and directives are declared by a module 2016-10-27 20:12:26 +02:00
93854e00e0 docs(common): minor corrections/improvements for NgClass (#12327) 2016-10-27 20:12:20 +02:00
fddf30cfaf doc(compiler-cli): align example with style guide (#12414)
See The Angular Style Guide, [Section 2.2 - Separate File Names with Dots and Dashes](https://angular.io/docs/ts/latest/guide/style-guide.html#!#02-02)
2016-10-27 20:12:12 +02:00
0fd859ca0b fix(compiler): walk third party modules (#12453)
fixes #11889
fixes #12428
2016-10-27 20:12:03 +02:00
f274eeb9fc refactor(i18n): extract Extractor from extract_i18n (#12417)
I put an extractor into your extract so you can extract while you
extract.

This allows integrators to call Extractor as a library. Also refactors
Extractor a bit so that callers need fewer arguments or arguments that
are at the right semantic level.

The refactoring causes no function change.
2016-10-27 20:11:51 +02:00
675e3d4244 refactor: remove most facades (#12399) 2016-10-27 20:08:06 +02:00
767841b434 docs(changelog): fix minor typo (#12429) 2016-10-27 19:48:35 +02:00
7bce0153bb fix(compiler): don't access view local variables nor pipes in host expressions (#12396)
Fixes #12004
Closes #12071
2016-10-27 19:47:51 +02:00
7a1f964201 chore(release): cut the 2.1.1 release 2016-10-20 15:36:02 -07:00
3dffbb6cf1 docs(changelog): add 2.1.1 changelog 2016-10-20 15:34:35 -07:00
79f1798b68 chore(release): cut the 2.2.0-beta.0 release and add changelog 2016-10-20 15:31:47 -07:00
dd08d421a1 fix(router): do not update primary route if only secondary outlet is given (#11797) 2016-10-20 15:31:24 -07:00
a2d4299f2c fix(router): module loader should start compiling modules when stubbedModules are set (#11742) 2016-10-20 15:31:11 -07:00
2598b59de7 cleanup(router): add a test verifying than NavigationEnd is not emitted after NavigationCancel 2016-10-20 15:31:04 -07:00
20b4617289 fix(router): fix lazy loading triggered by redirects from wildcard routes
Closes #12183
2016-10-20 15:30:50 -07:00
958bb0da04 refactor(compiler): introduce directive wrappers to generate less code
- for now only wraps the `@Input` properties and calls
  to `ngOnInit`, `ngDoCheck` and `ngOnChanges` of directives.
- also groups eval sources by NgModule.

Part of #11683
2016-10-20 15:30:27 -07:00
4ba8f1989b refactor(compiler): don’t use the OfflineCompiler in extract_i18n 2016-10-20 15:29:43 -07:00
c04b4d795a refactor(compiler): remove private exports
All of `@angular/compiler` is private, so we can export
everything we need directly.
2016-10-20 15:29:25 -07:00
f1b5ba9231 chore(ci): re-enable browserstack tests in ci 2016-10-20 15:27:39 -07:00
50b524ba1e chore(tslint.json): semicolon rule expects an array 2016-10-20 15:27:25 -07:00
680ceb7d65 refactor: remove some facades (#12335) 2016-10-20 15:25:05 -07:00
ea186d5ccd refactor(forms): remove ListWrapper facades
originally cherry-picked from 445e5922ec
2016-10-20 15:15:32 -07:00
10455044f1 chore(ci): make browserstack tests optional until they are fixed 2016-10-20 14:49:01 -07:00
31150fe6e8 feat(benchmark): add large form benchmark
This benchmark tracks the generated file size for large forms
as well as the time to create and destroy many form fields.
2016-10-20 14:48:02 -07:00
9223066123 fix(benchmarks): fix method name in targetable spec 2016-10-20 14:47:42 -07:00
905 changed files with 19302 additions and 46994 deletions

View File

@ -1,342 +1,5 @@
<a name="2.4.0"></a>
# [2.4.0 stability-interjection](https://github.com/angular/angular/compare/2.3.1...2.4.0) (2016-12-20)
### Bug Fixes
* **animations:** allow players to be destroyed before initialized ([#13346](https://github.com/angular/angular/issues/13346)) ([b36f4bc](https://github.com/angular/angular/commit/b36f4bc)), closes [#13293](https://github.com/angular/angular/issues/13293)
* **build:** use bash string comparison operator ([#13502](https://github.com/angular/angular/issues/13502)) ([50afbe0](https://github.com/angular/angular/commit/50afbe0))
* **compiler:** do not lex `}}` when interpolation is disabled ([#13531](https://github.com/angular/angular/issues/13531)) ([9b87bb6](https://github.com/angular/angular/commit/9b87bb6)), closes [#13525](https://github.com/angular/angular/issues/13525)
* **compiler-cli:** produce metadata for .d.ts files without metadata ([#13526](https://github.com/angular/angular/issues/13526)) ([debb0c9](https://github.com/angular/angular/commit/debb0c9)), closes [#13307](https://github.com/angular/angular/issues/13307) [#13473](https://github.com/angular/angular/issues/13473) [#13521](https://github.com/angular/angular/issues/13521)
* **i18n:** add a default example to xmb placeholders ([#13507](https://github.com/angular/angular/issues/13507)) ([3f17841](https://github.com/angular/angular/commit/3f17841))
* **upgrade:** fix `registerForNg1Tests` ([#13522](https://github.com/angular/angular/issues/13522)) ([c26c24c](https://github.com/angular/angular/commit/c26c24c))
### Features
* update to `rxjs@5.0.1` and unpin the rxjs peerDeps via `^5.0.1` ([#13572](https://github.com/angular/angular/issues/13572)) ([8d5da1e](https://github.com/angular/angular/commit/8d5da1e)), closes [#13561](https://github.com/angular/angular/issues/13561) [#13478](https://github.com/angular/angular/issues/13478)
<a name="2.3.1"></a>
## [2.3.1](https://github.com/angular/angular/compare/2.3.0...2.3.1) (2016-12-15)
### Bug Fixes
* **animations:** always cleanup players after they have finished internally ([#13334](https://github.com/angular/angular/issues/13334)) ([a26e054](https://github.com/angular/angular/commit/a26e054)), closes [#13333](https://github.com/angular/angular/issues/13333)
* **animations:** throw errors and normalize offset beyond the range of [0,1] ([6557bc3](https://github.com/angular/angular/commit/6557bc3)), closes [#13348](https://github.com/angular/angular/issues/13348) [#13440](https://github.com/angular/angular/issues/13440)
* **compiler:** emit quoted object literal keys if the source is quoted ([ecfad46](https://github.com/angular/angular/commit/ecfad46)), closes [#13249](https://github.com/angular/angular/issues/13249) [#13356](https://github.com/angular/angular/issues/13356)
* **compiler:** fix merge error in compiler_host ([69b52eb](https://github.com/angular/angular/commit/69b52eb))
* **compiler:** fix PR 13322 ([#13331](https://github.com/angular/angular/issues/13331)) ([79728b4](https://github.com/angular/angular/commit/79728b4))
* **compiler:** fix simplify a reference without a name ([1c279b3](https://github.com/angular/angular/commit/1c279b3)), closes [#13470](https://github.com/angular/angular/issues/13470)
* **compiler:** fix transpiled ES5 code ([#13322](https://github.com/angular/angular/issues/13322)) ([6c1d790](https://github.com/angular/angular/commit/6c1d790)), closes [#13301](https://github.com/angular/angular/issues/13301)
* **compiler:** generated CSS files suffixed with ngstyle. ([#13353](https://github.com/angular/angular/issues/13353)) ([c8a9b70](https://github.com/angular/angular/commit/c8a9b70)), closes [#13141](https://github.com/angular/angular/issues/13141)
* **compiler:** make sure provider values with `name` property dont break. ([efa2d80](https://github.com/angular/angular/commit/efa2d80)), closes [#13394](https://github.com/angular/angular/issues/13394) [#13445](https://github.com/angular/angular/issues/13445)
* **compiler:** narrow the span reported for invalid pipes ([307d305](https://github.com/angular/angular/commit/307d305)), closes [#13326](https://github.com/angular/angular/issues/13326) [#13411](https://github.com/angular/angular/issues/13411)
* **compiler:** propagate exports when upgrading metadata to v2 ([f6ef7d6](https://github.com/angular/angular/commit/f6ef7d6))
* **compiler:** resolver should merge host bindings and listeners ([#13474](https://github.com/angular/angular/issues/13474)) ([6aeaca3](https://github.com/angular/angular/commit/6aeaca3)), closes [#13327](https://github.com/angular/angular/issues/13327)
* **compiler:** support dotted property binding ([8db184d](https://github.com/angular/angular/commit/8db184d)), closes [angular/flex-layout#34](https://github.com/angular/flex-layout/issues/34)
* **compiler:** update to metadata version 3 ([#13464](https://github.com/angular/angular/issues/13464)) ([b9b557c](https://github.com/angular/angular/commit/b9b557c))
* **core:** detectChanges() doesn't work on detached instance ([4d6ac9d](https://github.com/angular/angular/commit/4d6ac9d)), closes [#13426](https://github.com/angular/angular/issues/13426) [#13472](https://github.com/angular/angular/issues/13472)
* **core:** properly destroy embedded Views attatched to ApplicationRef ([#13459](https://github.com/angular/angular/issues/13459)) ([d40bbf4](https://github.com/angular/angular/commit/d40bbf4)), closes [#13062](https://github.com/angular/angular/issues/13062)
* **core:** remove logError from logGroup ([#12925](https://github.com/angular/angular/issues/12925)) ([5fab871](https://github.com/angular/angular/commit/5fab871))
* **forms:** ensure `select[multiple]` retains selections ([b3dcff0](https://github.com/angular/angular/commit/b3dcff0)), closes [#12527](https://github.com/angular/angular/issues/12527) [#12654](https://github.com/angular/angular/issues/12654)
* **forms:** fix Validators.min/maxLength with FormArray ([#13095](https://github.com/angular/angular/issues/13095)) ([7383e4a](https://github.com/angular/angular/commit/7383e4a)), closes [#13089](https://github.com/angular/angular/issues/13089)
* **forms:** introduce checkbox required validator ([124267c](https://github.com/angular/angular/commit/124267c)), closes [#11459](https://github.com/angular/angular/issues/11459) [#13364](https://github.com/angular/angular/issues/13364)
* **http:** check response body text against undefined ([#13017](https://github.com/angular/angular/issues/13017)) ([f106a18](https://github.com/angular/angular/commit/f106a18))
* **http:** create a copy of headers when merge options ([#13365](https://github.com/angular/angular/issues/13365)) ([65c9b5b](https://github.com/angular/angular/commit/65c9b5b)), closes [#11980](https://github.com/angular/angular/issues/11980)
* **language-service:** correctly type `undefined` ([0a7364f](https://github.com/angular/angular/commit/0a7364f)), closes [#13412](https://github.com/angular/angular/issues/13412) [#13414](https://github.com/angular/angular/issues/13414)
* **compiler**: better error when directive not listed in NgModule.declarations ([b0cd514](https://github.com/angular/angular/commit/b0cd514))
* **language-service:** treat string unions as strings ([#13406](https://github.com/angular/angular/issues/13406)) ([14dd2b3](https://github.com/angular/angular/commit/14dd2b3)), closes [#13403](https://github.com/angular/angular/issues/13403)
* **router:** add support for query params with multiple values ([e4d5a5f](https://github.com/angular/angular/commit/e4d5a5f)), closes [#11373](https://github.com/angular/angular/issues/11373)
* **router:** Use T type in Resolve interface ([#13242](https://github.com/angular/angular/issues/13242)) ([5ee8155](https://github.com/angular/angular/commit/5ee8155))
* **selector:** SelectorMatcher match elements with :not selector ([#12977](https://github.com/angular/angular/issues/12977)) ([392c9ac](https://github.com/angular/angular/commit/392c9ac))
* **tsc-wrapped:** generate metadata for exports without module specifier ([cd03c77](https://github.com/angular/angular/commit/cd03c77)), closes [#13327](https://github.com/angular/angular/issues/13327)
* **upgrade:** fix downgrade content projection and injector inheritance ([86c5098](https://github.com/angular/angular/commit/86c5098)), closes [#6629](https://github.com/angular/angular/issues/6629) [#7727](https://github.com/angular/angular/issues/7727) [#8729](https://github.com/angular/angular/issues/8729) [#9643](https://github.com/angular/angular/issues/9643) [#9649](https://github.com/angular/angular/issues/9649) [#12675](https://github.com/angular/angular/issues/12675)
* **upgrade:** enable Angular 1 unit testing of upgrade module ([2fc0560](https://github.com/angular/angular/commit/2fc0560)), closes [#5462](https://github.com/angular/angular/issues/5462) [#12675](https://github.com/angular/angular/issues/12675)
### Performance Improvements
* **animations:** always run the animation queue outside of zones ([e2622ad](https://github.com/angular/angular/commit/e2622ad)), closes [#13440](https://github.com/angular/angular/issues/13440)
### Note ###
Due to regression in the 2.3.0 release that was fixed by [#13464](https://github.com/angular/angular/pull/13464),
components that have been compiled using 2.3.0 and published to npm will need to be recompiled and republished.
The >=2.3.1 compiler will issue is the following error if it encounters components compiled with 2.3.0:
`Unsupported metadata version 2 for module ${module}. This module should be compiled with a newer version of ngc`.
We are adding more tests to our test suite to catch these kinds of problems before we cut a release.
<a name="2.3.0"></a>
# [2.3.0](https://github.com/angular/angular/compare/2.3.0-rc.0...2.3.0) (2016-12-07)
### Bug Fixes
* **common:** make sure the plural category exists ([#13169](https://github.com/angular/angular/issues/13169)) ([82c81cd](https://github.com/angular/angular/commit/82c81cd)), closes [#12379](https://github.com/angular/angular/issues/12379)
* **compiler:** include the summaries of reexported modules / directives / pipes ([#13196](https://github.com/angular/angular/issues/13196)) ([75d1617](https://github.com/angular/angular/commit/75d1617))
* **compiler:** serialize any `StaticSymbol` correctly, not matter in which context ([5614c4f](https://github.com/angular/angular/commit/5614c4f))
* **compiler:** short-circut expressions with an index ([#13263](https://github.com/angular/angular/issues/13263)) ([f31c947](https://github.com/angular/angular/commit/f31c947)), closes [#13254](https://github.com/angular/angular/issues/13254)
* **core:** display framework version on bootstrapped component ([#13252](https://github.com/angular/angular/issues/13252)) ([16efb13](https://github.com/angular/angular/commit/16efb13))
* **facade:** cache original format string ([#12764](https://github.com/angular/angular/issues/12764)) ([a132287](https://github.com/angular/angular/commit/a132287))
* **http:** set the default Accept header ([#12989](https://github.com/angular/angular/issues/12989)) ([986abbe](https://github.com/angular/angular/commit/986abbe)), closes [#6354](https://github.com/angular/angular/issues/6354)
* **language-service:** avoid throwing for invalid class declarations ([#13257](https://github.com/angular/angular/issues/13257)) ([93556a5](https://github.com/angular/angular/commit/93556a5)), closes [#13253](https://github.com/angular/angular/issues/13253)
* **language-service:** do not throw for invalid metadata ([#13261](https://github.com/angular/angular/issues/13261)) ([4a09c81](https://github.com/angular/angular/commit/4a09c81)), closes [#13255](https://github.com/angular/angular/issues/13255)
* **language-service:** remove incompletely used parameter from `createLanguageServiceFromTypescript()` ([#13278](https://github.com/angular/angular/issues/13278)) ([25c2141](https://github.com/angular/angular/commit/25c2141)), closes [#13277](https://github.com/angular/angular/issues/13277)
* **language-service:** update to use `CompilerHost` from compiler-cli ([#13189](https://github.com/angular/angular/issues/13189)) ([3ff6554](https://github.com/angular/angular/commit/3ff6554))
* **router:** allow specifying a matcher without specifying a path ([bbb7a39](https://github.com/angular/angular/commit/bbb7a39)), closes [#12972](https://github.com/angular/angular/issues/12972)
* **router:** fix replaceUrl on RouterLink directives ([349ad75](https://github.com/angular/angular/commit/349ad75))
* **router:** fix skipLocationChanges on RouterLink directives ([f562cbf](https://github.com/angular/angular/commit/f562cbf)), closes [#13156](https://github.com/angular/angular/issues/13156)
* **router:** make setUpLocationChangeListener idempotent ([25e5b2f](https://github.com/angular/angular/commit/25e5b2f))
* **router:** runs guards every time when unsuccessfully navigating to the same url over and over again ([#13209](https://github.com/angular/angular/issues/13209)) ([d46b8de](https://github.com/angular/angular/commit/d46b8de))
* **router:** throw a better error message when angular 1 is not bootstraped ([c767df0](https://github.com/angular/angular/commit/c767df0))
* **router:** validate nested routes ([#13224](https://github.com/angular/angular/issues/13224)) ([2893c2c](https://github.com/angular/angular/commit/2893c2c)), closes [#12827](https://github.com/angular/angular/issues/12827)
* **tsc-wrapped:** have UserError display the actual error ([393c100](https://github.com/angular/angular/commit/393c100))
### Features
* **compiler:** read and write `.ngsummary.json` files ([614a35d](https://github.com/angular/angular/commit/614a35d)), closes [#12787](https://github.com/angular/angular/issues/12787)
<a name="2.3.0-rc.0"></a>
# [2.3.0-rc.0](https://github.com/angular/angular/compare/2.3.0-beta.0...2.3.0-rc.0) (2016-11-30)
### Bug Fixes
* **animations:** blend in all previously transitioned styles into next animation if interrupted ([#13014](https://github.com/angular/angular/issues/13014)) ([ef96763](https://github.com/angular/angular/commit/ef96763)), closes [#13013](https://github.com/angular/angular/issues/13013)
* **benchmarks:** use sanitized style values ([#12943](https://github.com/angular/angular/issues/12943)) ([fc5ac1e](https://github.com/angular/angular/commit/fc5ac1e))
* **build:** update versions of umd bundles ([#13038](https://github.com/angular/angular/issues/13038)) ([86ffa88](https://github.com/angular/angular/commit/86ffa88)), closes [#13037](https://github.com/angular/angular/issues/13037)
* **changelog:** replace beta.1 with beta.0 ([#12961](https://github.com/angular/angular/issues/12961)) ([07a986d](https://github.com/angular/angular/commit/07a986d))
* **ci:** pin version of npm on CircleCI ([#12954](https://github.com/angular/angular/issues/12954)) ([a3884db](https://github.com/angular/angular/commit/a3884db))
* **closure:** quote date pattern aliases ([#13012](https://github.com/angular/angular/issues/13012)) ([7dcca30](https://github.com/angular/angular/commit/7dcca30))
* **common:** update DatePipe to allow closure compilation ([b2b7219](https://github.com/angular/angular/commit/b2b7219))
* **compiler:** correctly evaluate references to static functions ([#13133](https://github.com/angular/angular/issues/13133)) ([627282d](https://github.com/angular/angular/commit/627282d))
* **compiler:** fix performance regression caused by 5b0f9e2 ([43c0e9a](https://github.com/angular/angular/commit/43c0e9a)), closes [#13146](https://github.com/angular/angular/issues/13146)
* **compiler:** fix versions of `@angular/tsc-wrapped` ([bccf0e6](https://github.com/angular/angular/commit/bccf0e6))
* **compiler-cli:** fix paths in source maps to be relative ([2a3ca7b](https://github.com/angular/angular/commit/2a3ca7b)), closes [#13040](https://github.com/angular/angular/issues/13040)
* **compiler-cli:** pin the version of `tsc-wrapped` ([966bcba](https://github.com/angular/angular/commit/966bcba))
* **language-service:** harden against partial normalization of directives ([2975d89](https://github.com/angular/angular/commit/2975d89))
* **core:** shrinkwrap was out of date with packages. ([e45b7ff](https://github.com/angular/angular/commit/e45b7ff))
* **language-service:** make link check pass ([7194fc2](https://github.com/angular/angular/commit/7194fc2))
* **router:** guards restore an incorrect url when used with skipLocationChange ([ad20d7d](https://github.com/angular/angular/commit/ad20d7d)), closes [#12825](https://github.com/angular/angular/issues/12825)
* **router:** support redirects to named outlets ([602522b](https://github.com/angular/angular/commit/602522b)), closes [#12740](https://github.com/angular/angular/issues/12740) [#9921](https://github.com/angular/angular/issues/9921)
* **tsc-wrapped:** set correct version number ([897555c](https://github.com/angular/angular/commit/897555c))
* **tsc-wrapped:** still emit version 1 metadata to allow use of new components in old setups ([bc69c74](https://github.com/angular/angular/commit/bc69c74))
* **upgrade:** call ng1 lifecycle hooks ([#12875](https://github.com/angular/angular/issues/12875)) ([1ef4696](https://github.com/angular/angular/commit/1ef4696))
* **version:** take all of version string after patch version ([f275f36](https://github.com/angular/angular/commit/f275f36))
### Features
* **core:** update RxJS peer dependency to 5.0.0-rc.4 Please see [this gist](https://gist.github.com/robwormald/19dea0c70a6e01aadced6731aed4f9f7) if you depend on the `cache` operator ([2d6a003](https://github.com/angular/angular/commit/2d6a003)), closes [#13125](https://github.com/angular/angular/issues/13125)
* **core:** upgrade zone.js to v0.7.1 ([c4bbafc](https://github.com/angular/angular/commit/c4bbafc))
* **build:** record angular version in the dom ([#13164](https://github.com/angular/angular/issues/13164)) ([e628b66](https://github.com/angular/angular/commit/e628b66))
* **core:** expose destroy() method on ViewRef ([808275a](https://github.com/angular/angular/commit/808275a))
* **core:** properly support inheritance ([f5c8e09](https://github.com/angular/angular/commit/f5c8e09)), closes [#11606](https://github.com/angular/angular/issues/11606) [#12892](https://github.com/angular/angular/issues/12892)
* **language-service:** add services to support editors ([#12987](https://github.com/angular/angular/issues/12987)) ([519a324](https://github.com/angular/angular/commit/519a324))
* **router:** add support for custom route reuse strategies ([42cf06f](https://github.com/angular/angular/commit/42cf06f))
* **tools:** allow disabling annotation lowering ([c1a62e2](https://github.com/angular/angular/commit/c1a62e2))
<a name="2.2.4"></a>
## [2.2.4](https://github.com/angular/angular/compare/2.2.3...2.2.4) (2016-11-30)
### Bug Fixes
* **common:** update DatePipe to allow closure compilation ([eba53fd](https://github.com/angular/angular/commit/eba53fd))
* **compiler:** fix performance regression caused by 5b0f9e2 ([ee2d6e5](https://github.com/angular/angular/commit/ee2d6e5)), closes [#13146](https://github.com/angular/angular/issues/13146)
* **compiler-cli:** fix paths in source maps to be relative ([eb173bc](https://github.com/angular/angular/commit/eb173bc)), closes [#13040](https://github.com/angular/angular/issues/13040)
<a name="2.2.3"></a>
## [2.2.3](https://github.com/angular/angular/compare/2.2.2...2.2.3) (2016-11-23)
### Bug Fixes
* **compiler:** Revert: fix versions of `@angular/tsc-wrapped` ([015ca47](https://github.com/angular/angular/commit/015ca47))
* **animations:** Revert: blend in all previously transitioned styles into next animation if interrupted ([c12e56e](https://github.com/angular/angular/commit/c12e56e))
<a name="2.2.2"></a>
## [2.2.2](https://github.com/angular/angular/compare/2.2.1...2.2.2) (2016-11-22)
### Bug Fixes
* **animations:** blend in all previously transitioned styles into next animation if interrupted ([#13014](https://github.com/angular/angular/issues/13014)) ([ea4fc9b](https://github.com/angular/angular/commit/ea4fc9b)), closes [#13013](https://github.com/angular/angular/issues/13013)
* **benchmarks:** use sanitized style values ([#12943](https://github.com/angular/angular/issues/12943)) ([33a7902](https://github.com/angular/angular/commit/33a7902))
* **closure:** quote date pattern aliases ([#13012](https://github.com/angular/angular/issues/13012)) ([0956ace](https://github.com/angular/angular/commit/0956ace))
* **compiler:** fix versions of `@angular/tsc-wrapped` ([2fe6fb1](https://github.com/angular/angular/commit/2fe6fb1))
* **router:** add a banner file for the router ([#12919](https://github.com/angular/angular/issues/12919)) ([8df328b](https://github.com/angular/angular/commit/8df328b))
* **router:** add a banner file for the router ([#12919](https://github.com/angular/angular/issues/12919)) ([511cd4d](https://github.com/angular/angular/commit/511cd4d))
* **router:** removes a peer dependency from router to upgrade ([115f18f](https://github.com/angular/angular/commit/115f18f))
* **router:** removes a peer dependency from router to upgrade ([87d5d49](https://github.com/angular/angular/commit/87d5d49))
* **router:** support redirects to named outlets ([09226d9](https://github.com/angular/angular/commit/09226d9)), closes [#12740](https://github.com/angular/angular/issues/12740) [#9921](https://github.com/angular/angular/issues/9921)
* **upgrade:** call ng1 lifecycle hooks ([#12875](https://github.com/angular/angular/issues/12875)) ([462316b](https://github.com/angular/angular/commit/462316b))
<a name="2.3.0-beta.0"></a>
# [2.3.0-beta.0](https://github.com/angular/angular/compare/2.2.0...2.3.0-beta.0) (2016-11-17)
### Bug Fixes
* **compiler:** assert xliff messages have translations ([7908679](https://github.com/angular/angular/commit/7908679)), closes [#12815](https://github.com/angular/angular/issues/12815) [#12604](https://github.com/angular/angular/issues/12604)
* **compiler:** updates hash algo for xmb/xtb files ([2f14415](https://github.com/angular/angular/commit/2f14415))
* **core:** fix placeholders handling in i18n. ([76e4911](https://github.com/angular/angular/commit/76e4911)), closes [#12512](https://github.com/angular/angular/issues/12512)
* **core:** misc i18n fixes ([ed5e98d](https://github.com/angular/angular/commit/ed5e98d))
* **core:** xmb serializer uses decimal messaged IDs ([08c038e](https://github.com/angular/angular/commit/08c038e)), closes [#12511](https://github.com/angular/angular/issues/12511)
* **platform-browser:** enable AOT ([efbbefd](https://github.com/angular/angular/commit/efbbefd)), closes [#12783](https://github.com/angular/angular/issues/12783)
### Features
* **core:** add `attachView` / `detachView` to ApplicationRef ([9f7d32a](https://github.com/angular/angular/commit/9f7d32a)), closes [#9293](https://github.com/angular/angular/issues/9293)
* **core:** expose `ViewRef` as `ChangeDetectorRef` ([1b5384e](https://github.com/angular/angular/commit/1b5384e)), closes [#12722](https://github.com/angular/angular/issues/12722)
* **core:** implements a decimal fingerprint for i18n ([582550a](https://github.com/angular/angular/commit/582550a))
* **router:** register router with ngprobe ([c2fae72](https://github.com/angular/angular/commit/c2fae72))
* **router_link:** add skipLocationChange and replaceUrl inputs ([#12850](https://github.com/angular/angular/issues/12850)) ([46d1502](https://github.com/angular/angular/commit/46d1502))
Note: The 2.3.0-beta.0 release also contains all the changes present in the 2.2.1 release.
<a name="2.2.1"></a>
## [2.2.1](https://github.com/angular/angular/compare/2.2.0...2.2.1) (2016-11-17)
### Bug Fixes
* **animations:** only pass in same typed players as previous players into web-animations ([#12907](https://github.com/angular/angular/issues/12907)) ([583d283](https://github.com/angular/angular/commit/583d283))
* **animations:** retain styling when transition destinations are changed ([#12208](https://github.com/angular/angular/issues/12208)) ([5c46c49](https://github.com/angular/angular/commit/5c46c49)), closes [#9661](https://github.com/angular/angular/issues/9661)
* **core:** support `ngTemplateOutlet` in production mode ([#12921](https://github.com/angular/angular/issues/12921)) ([4628798](https://github.com/angular/angular/commit/4628798)), closes [#12911](https://github.com/angular/angular/issues/12911)
* **http:** correctly handle response body for 204 status code ([21a4de9](https://github.com/angular/angular/commit/21a4de9)), closes [#12830](https://github.com/angular/angular/issues/12830) [#12393](https://github.com/angular/angular/issues/12393)
* **http:** return request url if it cannot be retrieved from response ([845ea23](https://github.com/angular/angular/commit/845ea23)), closes [#12837](https://github.com/angular/angular/issues/12837)
* **upgrade:** make AoT ngUpgrade work with the testability API and resumeBootstrap() ([#12910](https://github.com/angular/angular/issues/12910)) ([dc1662a](https://github.com/angular/angular/commit/dc1662a))
* **platform-browser:** fix disableDebugTools() ([#12918](https://github.com/angular/angular/issues/12918)) ([7b67bad](https://github.com/angular/angular/commit/7b67bad))
* **router:** add a banner file for the router ([#12919](https://github.com/angular/angular/issues/12919)) ([364642d](https://github.com/angular/angular/commit/364642d))
* **router:** removes a peer dependency from router to upgrade ([1dcf1f4](https://github.com/angular/angular/commit/1dcf1f4))
* **forms** allow for null values in HTML select options bound with ngValue ([e0ce545](https://github.com/angular/angular/commit/e0ce545)), closes [#10349](https://github.com/angular/angular/issues/10349)
* **router:** should not create a route state if navigation is canceled ([#12868](https://github.com/angular/angular/issues/12868)) ([dabaf85](https://github.com/angular/angular/commit/dabaf85)), closes [#12776](https://github.com/angular/angular/issues/12776)
* **common:** select should allow for null values in HTML select options bound with ngValue ([e02c180](https://github.com/angular/angular/commit/e02c180)), closes [#12829](https://github.com/angular/angular/issues/12829)
* **compiler-cli:** support ctorParams in function closure ([#12876](https://github.com/angular/angular/issues/12876)) ([6cdc3b5](https://github.com/angular/angular/commit/6cdc3b5))
<a name="2.2.0"></a>
# [2.2.0 upgrade-firebooster](https://github.com/angular/angular/compare/2.2.0-rc.0...2.2.0) (2016-11-14)
### Features (summary of all features from 2.2.0-beta.0 - 2.2.0-rc.0 releases)
* **common:** support narrow forms for month and weekdays in DatePipe ([#12297](https://github.com/angular/angular/issues/12297)) ([f77ab6a](https://github.com/angular/angular/commit/f77ab6a)), closes [#12294](https://github.com/angular/angular/issues/12294)
* **core:** map 'for' attribute to 'htmlFor' property ([#10546](https://github.com/angular/angular/issues/10546)) ([634b3bb](https://github.com/angular/angular/commit/634b3bb)), closes [#7516](https://github.com/angular/angular/issues/7516)
* **core:** add the find method to QueryList ([7c16ef9](https://github.com/angular/angular/commit/7c16ef9))
* **forms:** add hasError and getError to AbstractControlDirective ([#11985](https://github.com/angular/angular/issues/11985)) ([592f40a](https://github.com/angular/angular/commit/592f40a)), closes [#7255](https://github.com/angular/angular/issues/7255)
* **forms:** add ng-pending CSS class during async validation ([#11243](https://github.com/angular/angular/issues/11243)) ([97bc971](https://github.com/angular/angular/commit/97bc971)), closes [#10336](https://github.com/angular/angular/issues/10336)
* **forms:** add emitEvent to AbstractControl methods ([#11949](https://github.com/angular/angular/issues/11949)) ([b9fc090](https://github.com/angular/angular/commit/b9fc090))
* **forms:** make 'parent' a public property of 'AbstractControl' ([#11855](https://github.com/angular/angular/issues/11855)) ([445e592](https://github.com/angular/angular/commit/445e592))
* **forms:** Validator.pattern accepts a RegExp ([#12323](https://github.com/angular/angular/issues/12323)) ([bf60418](https://github.com/angular/angular/commit/bf60418))
* **router:** add a provider making angular1/angular2 integration easier ([#12769](https://github.com/angular/angular/issues/12769)) ([6e35d13](https://github.com/angular/angular/commit/6e35d13))
* **router:** add support for custom url matchers ([7340735](https://github.com/angular/angular/commit/7340735)), closes [#12442](https://github.com/angular/angular/issues/12442) [#12772](https://github.com/angular/angular/issues/12772)
* **router:** export routerLinkActive w/ isActive property ([c9f58cf](https://github.com/angular/angular/commit/c9f58cf))
* **router:** add support for ng1/ng2 migration ([#12160](https://github.com/angular/angular/issues/12160)) ([8b9ab44](https://github.com/angular/angular/commit/8b9ab44))
* **upgrade:** add support for AoT compiled upgrade applications ([d6791ff](https://github.com/angular/angular/commit/d6791ff)), closes [#12239](https://github.com/angular/angular/issues/12239)
* **upgrade:** add support for `require` in UpgradeComponent ([fe1d0e2](https://github.com/angular/angular/commit/fe1d0e2))
* **upgrade:** add/improve support for lifecycle hooks in UpgradeComponent ([469010e](https://github.com/angular/angular/commit/469010e))
### Performance Improvements
* **compiler:** introduce direct rendering ([9c23884](https://github.com/angular/angular/commit/9c23884))
* **core:** dont use `DomAdapter` nor zone for regular events ([648ce59](https://github.com/angular/angular/commit/648ce59))
* **core:** use `array.push` / `array.pop` instead of `splice` if possible ([0fc11a4](https://github.com/angular/angular/commit/0fc11a4))
* **platform-browser:** cache plugin resolution in the EventManager ([73593d4](https://github.com/angular/angular/commit/73593d4)), closes [#12824](https://github.com/angular/angular/issues/12824)
* **platform-browser:** dont use `DomAdapter` any more ([d708a88](https://github.com/angular/angular/commit/d708a88))
### Bug Fixes
* **animations:** allow animations to be destroyed manually ([#12719](https://github.com/angular/angular/issues/12719)) ([fe35bc3](https://github.com/angular/angular/commit/fe35bc3)), closes [#12456](https://github.com/angular/angular/issues/12456)
* **animations:** always normalize style properties and values during compilation ([#12755](https://github.com/angular/angular/issues/12755)) ([a0e9fde](https://github.com/angular/angular/commit/a0e9fde)), closes [#11582](https://github.com/angular/angular/issues/11582) [#12481](https://github.com/angular/angular/issues/12481)
* **animations:** always trigger animations after the change detection check ([#12713](https://github.com/angular/angular/issues/12713)) ([383f23b](https://github.com/angular/angular/commit/383f23b))
* **animations:** ensure animations work with web-workers ([#12656](https://github.com/angular/angular/issues/12656)) ([19e869e](https://github.com/angular/angular/commit/19e869e))
* **animations:** ensure web-animations are caught within the Angular zone ([f80a157](https://github.com/angular/angular/commit/f80a157)), closes [#11881](https://github.com/angular/angular/issues/11881) [#11712](https://github.com/angular/angular/issues/11712) [#12355](https://github.com/angular/angular/issues/12355) [#11881](https://github.com/angular/angular/issues/11881) [#12546](https://github.com/angular/angular/issues/12546) [#12707](https://github.com/angular/angular/issues/12707) [#12774](https://github.com/angular/angular/issues/12774)
* **common:** `NgSwitch` - dont create the default case if another case matches ([#12726](https://github.com/angular/angular/issues/12726)) ([d8f23f4](https://github.com/angular/angular/commit/d8f23f4)), closes [#11297](https://github.com/angular/angular/issues/11297) [#9420](https://github.com/angular/angular/issues/9420)
* **common:** I18nSelectPipe selects other case on default ([4708b24](https://github.com/angular/angular/commit/4708b24))
* **common:** no TZ Offset added by DatePipe for dates without time ([#12380](https://github.com/angular/angular/issues/12380)) ([2aba8b0](https://github.com/angular/angular/commit/2aba8b0))
* **common:** NgClass should throw a descriptive error when CSS class is not a string ([#12662](https://github.com/angular/angular/issues/12662)) ([f3793b5](https://github.com/angular/angular/commit/f3793b5)), closes [#12586](https://github.com/angular/angular/issues/12586)
* **common:** DatePipe should handle empty string ([#12374](https://github.com/angular/angular/issues/12374)) ([3dc6177](https://github.com/angular/angular/commit/3dc6177))
* **compiler:** don't convert undefined to null literals ([#11503](https://github.com/angular/angular/issues/11503)) ([f0cdb42](https://github.com/angular/angular/commit/f0cdb42)), closes [#11493](https://github.com/angular/angular/issues/11493)
* **compiler:** generate safe access strictNullChecks compatible code ([#12800](https://github.com/angular/angular/issues/12800)) ([a965d11](https://github.com/angular/angular/commit/a965d11)), closes [#12795](https://github.com/angular/angular/issues/12795)
* **compiler:** support more than 9 interpolations ([#12710](https://github.com/angular/angular/issues/12710)) ([22c021c](https://github.com/angular/angular/commit/22c021c)), closes [#10253](https://github.com/angular/angular/issues/10253)
* **compiler:** use the other case by default in ICU messages ([55dc0e4](https://github.com/angular/angular/commit/55dc0e4))
* **compiler-cli:** suppress closure compiler suspiciousCode check in codegen ([#12666](https://github.com/angular/angular/issues/12666)) ([7103754](https://github.com/angular/angular/commit/7103754))
* **compiler-cli:** suppress two more closure compiler checks in codegen ([#12698](https://github.com/angular/angular/issues/12698)) ([77cbf7f](https://github.com/angular/angular/commit/77cbf7f))
* **core:** allow to query content of templates that are stamped out at a different place ([f2bbef3](https://github.com/angular/angular/commit/f2bbef3)), closes [#12283](https://github.com/angular/angular/issues/12283) [#12094](https://github.com/angular/angular/issues/12094)
* **core:** apply host attributes to root elements ([#12761](https://github.com/angular/angular/issues/12761)) ([ad3bf6c](https://github.com/angular/angular/commit/ad3bf6c)), closes [#12744](https://github.com/angular/angular/issues/12744)
* **core:** ensure that component views that have no bindings recurse into nested components / view containers. ([051d748](https://github.com/angular/angular/commit/051d748))
* **core:** fix pseudo-selector shimming ([#12754](https://github.com/angular/angular/issues/12754)) ([acbf1d8](https://github.com/angular/angular/commit/acbf1d8)), closes [#12730](https://github.com/angular/angular/issues/12730) [#12354](https://github.com/angular/angular/issues/12354)
* **forms:** check if registerOnValidatorChange exists on validator before trying to invoke it ([#12801](https://github.com/angular/angular/issues/12801)) ([ef88147](https://github.com/angular/angular/commit/ef88147)), closes [#12593](https://github.com/angular/angular/issues/12593)
* **forms:** getRawValue returns any instead of Object ([#12599](https://github.com/angular/angular/issues/12599)) ([09092ac](https://github.com/angular/angular/commit/09092ac))
* **http:** preserve header case when copying headers ([#12697](https://github.com/angular/angular/issues/12697)) ([121e508](https://github.com/angular/angular/commit/121e508))
* **router:** advance a route only after its children have been deactivated ([#12676](https://github.com/angular/angular/issues/12676)) ([9ddf9b3](https://github.com/angular/angular/commit/9ddf9b3)), closes [#11715](https://github.com/angular/angular/issues/11715)
* **router:** avoid router initialization for non root components ([2a4bf9a](https://github.com/angular/angular/commit/2a4bf9a)), closes [#12338](https://github.com/angular/angular/issues/12338) [#12814](https://github.com/angular/angular/issues/12814)
* **router:** check if windows.console exists before using it ([#12348](https://github.com/angular/angular/issues/12348)) ([7886561](https://github.com/angular/angular/commit/7886561))
* **router:** correctly export concatMap operator in es5 ([#12430](https://github.com/angular/angular/issues/12430)) ([e25baa0](https://github.com/angular/angular/commit/e25baa0))
* **router:** do not require the creation of empty-path routes when no url left ([2c11093](https://github.com/angular/angular/commit/2c11093)), closes [#12133](https://github.com/angular/angular/issues/12133)
* **router:** ignore null or undefined query parameters ([#12333](https://github.com/angular/angular/issues/12333)) ([3052fb2](https://github.com/angular/angular/commit/3052fb2))
* **router:** incorrect injector is used when instantiating components loaded lazily ([#12817](https://github.com/angular/angular/issues/12817)) ([52be848](https://github.com/angular/angular/commit/52be848))
* **router:** resolve guard observables on the first emit ([#10412](https://github.com/angular/angular/issues/10412)) ([2e78b76](https://github.com/angular/angular/commit/2e78b76))
* **router:** Route.isActive also compares query params ([#12321](https://github.com/angular/angular/issues/12321)) ([785b7b6](https://github.com/angular/angular/commit/785b7b6))
* **router:** router should not swallow "unhandled" errors ([e5a753e](https://github.com/angular/angular/commit/e5a753e)), closes [#12802](https://github.com/angular/angular/issues/12802)
* **router:** throw an error when encounter undefined route ([#12389](https://github.com/angular/angular/issues/12389)) ([77dc1ab](https://github.com/angular/angular/commit/77dc1ab))
* **platform-browser:** enableDebugTools should create AngularTools by merging into context.ng ([#12003](https://github.com/angular/angular/issues/12003)) ([b2cf379](https://github.com/angular/angular/commit/b2cf379)), closes [#12002](https://github.com/angular/angular/issues/12002)
* **platform-browser:** provide the ability to register global hammer.js events ([768cddb](https://github.com/angular/angular/commit/768cddb)), closes [#12797](https://github.com/angular/angular/issues/12797)
* **tsc-wrapped:** harden collector against invalid asts ([#12793](https://github.com/angular/angular/issues/12793)) ([69f87ca](https://github.com/angular/angular/commit/69f87ca))
<a name="2.2.0-rc.0"></a>
# [2.2.0-rc.0](https://github.com/angular/angular/compare/2.2.0-beta.1...2.2.0-rc.0) (2016-11-02)
### Bug Fixes
* **compiler:** dedupe NgModule declarations, … ([a178bc6](https://github.com/angular/angular/commit/a178bc6))
* **compiler:** dont double bind functions ([e391cac](https://github.com/angular/angular/commit/e391cac))
* **compiler:** Dont throw on empty property bindings ([642c1db](https://github.com/angular/angular/commit/642c1db)), closes [#12583](https://github.com/angular/angular/issues/12583)
* **compiler:** support multiple components in a view container ([6fda972](https://github.com/angular/angular/commit/6fda972))
* **core:** improve error when multiple components match the same element ([e9fd864](https://github.com/angular/angular/commit/e9fd864)), closes [#7067](https://github.com/angular/angular/issues/7067)
* **router:** call data observers when the path changes ([1de04b2](https://github.com/angular/angular/commit/1de04b2))
* **router:** CanDeactivate receives a wrong component ([830a780](https://github.com/angular/angular/commit/830a780)), closes [#12592](https://github.com/angular/angular/issues/12592)
* **router:** rerun resolvers when url changes ([fe47e6b](https://github.com/angular/angular/commit/fe47e6b)), closes [#12603](https://github.com/angular/angular/issues/12603)
* **router:** reset URL to the stable state when a navigation gets canceled ([d509ee0](https://github.com/angular/angular/commit/d509ee0)), closes [#10321](https://github.com/angular/angular/issues/10321)
* **router:** routerLink should not prevent default on non-link elements ([8e221b8](https://github.com/angular/angular/commit/8e221b8))
* **router:** run navigations serially ([091c390](https://github.com/angular/angular/commit/091c390)), closes [#11754](https://github.com/angular/angular/issues/11754)
* **upgrade:** silent bootstrap failures ([fa93fd6](https://github.com/angular/angular/commit/fa93fd6)), closes [#12062](https://github.com/angular/angular/issues/12062)
### Features
* **core:** add the find method to QueryList ([7c16ef9](https://github.com/angular/angular/commit/7c16ef9))
<a name="2.1.2"></a>
# [2.1.2](https://github.com/angular/angular/compare/2.1.1...2.1.2) (2016-10-27)
## [2.1.2](https://github.com/angular/angular/compare/2.1.1...2.1.2) (2016-10-27)
### Bug Fixes
@ -368,7 +31,7 @@ Note: The 2.3.0-beta.0 release also contains all the changes present in the 2.2.
* **router:** export routerLinkActive w/ isActive property ([c9f58cf](https://github.com/angular/angular/commit/c9f58cf))
### BREAKING CHANGES (only for beta version users)
### BREAKING CHANGES
* upgrade: Four newly added APIs in 2.2.0-beta:
downgradeComponent, downgradeInjectable, UpgradeComponent, and UpgradeModule are no longer exported by @angular/upgrade.
@ -1033,7 +696,7 @@ prefix using `animate-` must now be preixed using `bind-animate-`.
* core:
- `ApplicationRef.dispose` is deprecated. Destroy the module that was
created during bootstrap instead by calling `NgModuleRef.destroy`.
- `ApplicationRef.registerDisposeListener` is deprecated.
- `AplicationRef.registerDisposeListener` is deprecated.
Use the `ngOnDestroy` lifecycle hook for providers or
`NgModuleRef.onDestroy` instead.
- `disposePlatform` is deprecated. Use `destroyPlatform` instead.

View File

@ -17,7 +17,7 @@ Help us keep Angular open and inclusive. Please read and follow our [Code of Con
## <a name="question"></a> Got a Question or Problem?
Please, do not open issues for the general support questions as we want to keep GitHub issues for bug reports and feature requests. You've got much better chances of getting your question answered on [StackOverflow](https://stackoverflow.com/questions/tagged/angular) where the questions should be tagged with tag `angular`.
Please, do not open issues for the general support questions as we want to keep GitHub issues for bug reports and feature requests. You've got much better chances of getting your question answered on [StackOverflow](stackoverflow.com/questions/tagged/angular) where the questions should be tagged with tag `angular`.
StackOverflow is a much better place to ask questions since:
@ -57,7 +57,7 @@ We want to fix all the issues as soon as possible, but before fixing a bug we ne
- 3rd-party libraries and their versions
- and most importantly - a use-case that fails
A minimal reproduce scenario using http://plnkr.co/ allows us to quickly confirm a bug (or point out coding problem) as well as confirm that we are fixing the right problem. If plunker is not a suitable way to demonstrate the problem (for example for issues related to our npm packaging), please create a standalone git repository demonstrating the problem.
A minimal reproduce scenario using http://plnkr.co/ allows us to quickly confirm a bug (or point out coding problem) as well as confirm that we are fixing the right problem. If plunker is not a suitable way to demostrate the problem (for example for issues related to our npm packaging), please create a standalone git repository demostrating the problem.
We will be insisting on a minimal reproduce scenario in order to save maintainers time and ultimately be able to fix more bugs. Interestingly, from our experience users often find coding problems themselves while preparing a minimal plunk. We understand that sometimes it might be hard to extract essentials bits of code from a larger code-base but we really need to isolate the problem before we can fix it.
@ -244,7 +244,7 @@ changes to be accepted, the CLA must be signed. It's a quick process, we promise
[github]: https://github.com/angular/angular
[gitter]: https://gitter.im/angular/angular
[individual-cla]: http://code.google.com/legal/individual-cla-v1.0.html
[js-style-guide]: https://google.github.io/styleguide/jsguide.html
[js-style-guide]: https://google.github.io/styleguide/javascriptguide.xml
[jsfiddle]: http://jsfiddle.net
[plunker]: http://plnkr.co/edit
[runnable]: http://runnable.com

View File

@ -1,6 +1,6 @@
# Building and Testing Angular
# Building and Testing Angular 2 for JS
This document describes how to set up your development environment to build and test Angular.
This document describes how to set up your development environment to build and test Angular 2 JS version.
It also explains the basic mechanics of using `git`, `node`, and `npm`.
* [Prerequisite Software](#prerequisite-software)
@ -126,7 +126,7 @@ $ gulp public-api:update
Note: The command `./test.sh tools` fails when the API doesn't match the golden files.
## <a name="clang-format"></a> Formatting your source code
## Formatting your source code
Angular uses [clang-format](http://clang.llvm.org/docs/ClangFormat.html) to format the source code. If the source code
is not properly formatted, the CI will fail and the PR can not be merged.
@ -137,21 +137,4 @@ You can automatically format your code by running:
$ gulp format
```
## Publishing your own personal snapshot build
You may find that your un-merged change needs some validation from external participants.
Rather than requiring them to pull your Pull Request and build Angular locally, you can
publish the `*-builds` snapshots just like our Travis build does.
First time, you need to create the github repositories:
``` shell
$ export TOKEN=[get one from https://github.com/settings/tokens]
$ CREATE_REPOS=1 ./scripts/publish/publish-build-artifacts.sh [github username]
```
For subsequent snapshots, just run
``` shell
$ ./scripts/publish/publish-build-artifacts.sh [github username]
```

View File

@ -24,9 +24,8 @@ with it.
* `comp: forms`: `@kara`
* `comp: http`: `@jeffbcross`
* `comp: i18n`: `@vicb`
* `comp: language service`: `@chuckjaz`
* `comp: metadata-extractor`: `@chuckjaz`
* `comp: router`: `@vicb`
* `comp: router`: `@vsavkin`
* `comp: testing`: `@juliemr`
* `comp: upgrade`: `@mhevery`
* `comp: web-worker`: `@vicb`

View File

@ -36,7 +36,7 @@ var CIconfiguration = {
'iOS7': {unitTest: {target: 'BS', required: true}, e2e: {target: null, required: true}},
'iOS8': {unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
'iOS9': {unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
'iOS10': {unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
'iOS10': {unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
'WindowsPhone': {unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}}
};
@ -44,10 +44,10 @@ var customLaunchers = {
'DartiumWithWebPlatform':
{base: 'Dartium', flags: ['--enable-experimental-web-platform-features']},
'ChromeNoSandbox': {base: 'Chrome', flags: ['--no-sandbox']},
'SL_CHROME': {base: 'SauceLabs', browserName: 'chrome', version: '54'},
'SL_CHROME': {base: 'SauceLabs', browserName: 'chrome', version: '52'},
'SL_CHROMEBETA': {base: 'SauceLabs', browserName: 'chrome', version: 'beta'},
'SL_CHROMEDEV': {base: 'SauceLabs', browserName: 'chrome', version: 'dev'},
'SL_FIREFOX': {base: 'SauceLabs', browserName: 'firefox', version: '50'},
'SL_FIREFOX': {base: 'SauceLabs', browserName: 'firefox', version: '46'},
'SL_FIREFOXBETA': {base: 'SauceLabs', browserName: 'firefox', version: 'beta'},
'SL_FIREFOXDEV': {base: 'SauceLabs', browserName: 'firefox', version: 'dev'},
'SL_SAFARI7': {base: 'SauceLabs', browserName: 'safari', platform: 'OS X 10.9', version: '7.0'},
@ -96,7 +96,7 @@ var customLaunchers = {
'BS_IE10': {
base: 'BrowserStack',
browser: 'ie',
browser_version: '10.1',
browser_version: '10.0',
os: 'Windows',
os_version: '8'
},

View File

@ -14,17 +14,12 @@ PACKAGES=(core
platform-webworker
platform-webworker-dynamic
http
upgrade
router
upgrade
compiler-cli
language-service
benchpress)
BUILD_ALL=true
BUNDLE=true
VERSION_PREFIX=$(node -p "require('./package.json').version")
VERSION_SUFFIX="-$(git log --oneline -1 | awk '{print $1}')"
ROUTER_VERSION_PREFIX=$(node -p "require('./package.json').version.replace(/^2/, '3')")
REMOVE_BENCHPRESS=false
for ARG in "$@"; do
case "$ARG" in
@ -36,10 +31,6 @@ for ARG in "$@"; do
--bundle=*)
BUNDLE=( "${ARG#--bundle=}" )
;;
--publish)
VERSION_SUFFIX=""
REMOVE_BENCHPRESS=true
;;
*)
echo "Unknown option $ARG."
exit 1
@ -47,10 +38,6 @@ for ARG in "$@"; do
esac
done
VERSION="${VERSION_PREFIX}${VERSION_SUFFIX}"
ROUTER_VERSION="${ROUTER_VERSION_PREFIX}${VERSION_SUFFIX}"
echo "====== BUILDING: Version ${VERSION} (Router ${ROUTER_VERSION})"
export NODE_PATH=${NODE_PATH}:$(pwd)/dist/all:$(pwd)/dist/tools
TSC="node --max-old-space-size=3000 dist/tools/@angular/tsc-wrapped/src/main"
UGLIFYJS=`pwd`/node_modules/.bin/uglifyjs
@ -76,11 +63,10 @@ if [[ ${BUILD_ALL} == true ]]; then
ln -s ../../../../node_modules/zone.js/dist/zone.js .
ln -s ../../../../node_modules/zone.js/dist/long-stack-trace-zone.js .
ln -s ../../../../node_modules/systemjs/dist/system.src.js .
ln -s ../../../../node_modules/base64-js .
ln -s ../../../../node_modules/base64-js/lib/b64.js .
ln -s ../../../../node_modules/reflect-metadata/Reflect.js .
ln -s ../../../../node_modules/rxjs .
ln -s ../../../../node_modules/angular/angular.js .
ln -s ../../../../node_modules/hammerjs/hammer.js .
cd -
echo "====== Copying files needed for benchmarks ====="
@ -92,6 +78,7 @@ if [[ ${BUILD_ALL} == true ]]; then
ln -s ../../../../node_modules/zone.js/dist/zone.js .
ln -s ../../../../node_modules/zone.js/dist/long-stack-trace-zone.js .
ln -s ../../../../node_modules/systemjs/dist/system.src.js .
ln -s ../../../../node_modules/base64-js/lib/b64.js .
ln -s ../../../../node_modules/reflect-metadata/Reflect.js .
ln -s ../../../../node_modules/rxjs .
ln -s ../../../../node_modules/angular/angular.js .
@ -114,29 +101,14 @@ do
DESTDIR=${PWD}/dist/packages-dist/${PACKAGE}
UMD_ES5_PATH=${DESTDIR}/bundles/${PACKAGE}.umd.js
UMD_TESTING_ES5_PATH=${DESTDIR}/bundles/${PACKAGE}-testing.umd.js
UMD_STATIC_ES5_PATH=${DESTDIR}/bundles/${PACKAGE}-static.umd.js
UMD_UPGRADE_ES5_PATH=${DESTDIR}/bundles/${PACKAGE}-upgrade.umd.js
UMD_ES5_MIN_PATH=${DESTDIR}/bundles/${PACKAGE}.umd.min.js
UMD_STATIC_ES5_MIN_PATH=${DESTDIR}/bundles/${PACKAGE}-static.umd.min.js
UMD_UPGRADE_ES5_MIN_PATH=${DESTDIR}/bundles/${PACKAGE}-upgrade.umd.min.js
if [[ ${PACKAGE} != router ]]; then
LICENSE_BANNER=${PWD}/modules/@angular/license-banner.txt
fi
if [[ ${PACKAGE} == router ]]; then
LICENSE_BANNER=${PWD}/modules/@angular/router-license-banner.txt
fi
LICENSE_BANNER=${PWD}/modules/@angular/license-banner.txt
rm -rf ${DESTDIR}
echo "====== COMPILING: ${TSC} -p ${SRCDIR}/tsconfig-build.json ====="
$TSC -p ${SRCDIR}/tsconfig-build.json
if [[ -e ${SRCDIR}/tsconfig-upgrade.json ]]; then
echo "====== COMPILING: ${TSC} -p ${SRCDIR}/tsconfig-upgrade.json ====="
$TSC -p ${SRCDIR}/tsconfig-upgrade.json
fi
cp ${SRCDIR}/package.json ${DESTDIR}/
cp ${PWD}/modules/@angular/README.md ${DESTDIR}/
@ -145,11 +117,6 @@ do
$TSC -p ${SRCDIR}/tsconfig-testing.json
fi
if [[ -e ${SRCDIR}/tsconfig-2015.json ]]; then
echo "====== COMPILING ESM: ${TSC} -p ${SRCDIR}/tsconfig-2015.json"
${TSC} -p ${SRCDIR}/tsconfig-2015.json
fi
echo "====== TSC 1.8 d.ts compat for ${DESTDIR} ====="
# safely strips 'readonly' specifier from d.ts files to make them compatible with tsc 1.8
if [ "$(uname)" == "Darwin" ]; then
@ -181,6 +148,7 @@ do
mv ${UMD_ES5_PATH}.tmp ${UMD_ES5_PATH}
$UGLIFYJS -c --screw-ie8 --comments -o ${UMD_ES5_MIN_PATH} ${UMD_ES5_PATH}
if [[ -e rollup-testing.config.js ]]; then
echo "====== Rollup ${PACKAGE} testing"
../../../node_modules/.bin/rollup -c rollup-testing.config.js
@ -189,49 +157,9 @@ do
cat ${UMD_TESTING_ES5_PATH} >> ${UMD_TESTING_ES5_PATH}.tmp
mv ${UMD_TESTING_ES5_PATH}.tmp ${UMD_TESTING_ES5_PATH}
fi
if [[ -e rollup-static.config.js ]]; then
echo "====== Rollup ${PACKAGE} static"
../../../node_modules/.bin/rollup -c rollup-static.config.js
# create dir because it doesn't exist yet, we should move the src code here and remove this line
mkdir ${DESTDIR}/static
echo "{\"main\": \"../bundles/${PACKAGE}-static.umd.js\"}" > ${DESTDIR}/static/package.json
cat ${LICENSE_BANNER} > ${UMD_STATIC_ES5_PATH}.tmp
cat ${UMD_STATIC_ES5_PATH} >> ${UMD_STATIC_ES5_PATH}.tmp
mv ${UMD_STATIC_ES5_PATH}.tmp ${UMD_STATIC_ES5_PATH}
$UGLIFYJS -c --screw-ie8 --comments -o ${UMD_STATIC_ES5_MIN_PATH} ${UMD_STATIC_ES5_PATH}
fi
if [[ -e rollup-upgrade.config.js ]]; then
echo "====== Rollup ${PACKAGE} upgrade"
../../../node_modules/.bin/rollup -c rollup-upgrade.config.js
# create dir because it doesn't exist yet, we should move the src code here and remove this line
mkdir ${DESTDIR}/upgrade
echo "{\"main\": \"../bundles/${PACKAGE}-upgrade.umd.js\"}" > ${DESTDIR}/upgrade/package.json
cat ${LICENSE_BANNER} > ${UMD_UPGRADE_ES5_PATH}.tmp
cat ${UMD_UPGRADE_ES5_PATH} >> ${UMD_UPGRADE_ES5_PATH}.tmp
mv ${UMD_UPGRADE_ES5_PATH}.tmp ${UMD_UPGRADE_ES5_PATH}
$UGLIFYJS -c --screw-ie8 --comments -o ${UMD_UPGRADE_ES5_MIN_PATH} ${UMD_UPGRADE_ES5_PATH}
fi
) 2>&1 | grep -v "as external dependency"
fi
(
echo "====== VERSION: Updating version references"
cd ${DESTDIR}
echo "====== EXECUTE: perl -p -i -e \"s/0\.0\.0\-PLACEHOLDER/${VERSION}/g\" $""(grep -ril 0\.0\.0\-PLACEHOLDER .)"
perl -p -i -e "s/0\.0\.0\-PLACEHOLDER/${VERSION}/g" $(grep -ril 0\.0\.0\-PLACEHOLDER .) < /dev/null 2> /dev/null
echo "====== EXECUTE: perl -p -i -e \"s/0\.0\.0\-ROUTERPLACEHOLDER/${ROUTER_VERSION}/g\" $""(grep -ril 0\.0\.0\-ROUTERPLACEHOLDER .)"
perl -p -i -e "s/0\.0\.0\-ROUTERPLACEHOLDER/${ROUTER_VERSION}/g" $(grep -ril 0\.0\.0\-ROUTERPLACEHOLDER .) < /dev/null 2> /dev/null
)
done
echo ""
echo "====== Building examples: ./modules/@angular/examples/build.sh ====="
./modules/@angular/examples/build.sh
if [[ ${REMOVE_BENCHPRESS} == true ]]; then
echo ""
echo "==== Removing benchpress from publication"
rm -r dist/packages-dist/benchpress
fi

View File

@ -4,7 +4,7 @@ machine:
dependencies:
pre:
- npm install -g npm@3.6.0
- npm install -g npm
test:
override:

View File

@ -58,7 +58,6 @@ const entrypoints = [
//'dist/packages-dist/compiler/index.d.ts',
//'dist/packages-dist/compiler/testing.d.ts',
'dist/packages-dist/upgrade/index.d.ts',
'dist/packages-dist/upgrade/static.d.ts',
'dist/packages-dist/platform-browser/index.d.ts',
'dist/packages-dist/platform-browser/testing/index.d.ts',
'dist/packages-dist/platform-browser-dynamic/index.d.ts',
@ -125,31 +124,38 @@ gulp.task('public-api:update', ['build.sh'], (done) => {
.on('close', done);
});
// Checks tests for presence of ddescribe, fdescribe, fit, iit and fails the build if one of the
// focused tests is found.
// Currently xdescribe and xit are _not_ reported as errors since there are a couple of excluded
// tests in our code base.
gulp.task('check-tests', function() {
const ddescribeIit = require('gulp-ddescribe-iit');
return gulp
.src([
'modules/**/*.spec.ts',
'modules/**/*_spec.ts',
])
.pipe(ddescribeIit({allowDisabledTests: true}));
});
// Check the coding standards and programming errors
gulp.task('lint', ['format:enforce', 'tools:build'], () => {
gulp.task('lint', ['check-tests', 'format:enforce', 'tools:build'], () => {
const tslint = require('gulp-tslint');
// Built-in rules are at
// https://palantir.github.io/tslint/rules/
// https://github.com/palantir/tslint#supported-rules
const tslintConfig = require('./tslint.json');
return gulp
.src([
// todo(vicb): add .js files when supported
// see https://github.com/palantir/tslint/pull/1515
'./modules/**/*.ts',
'./tools/**/*.ts',
'modules/@angular/**/*.ts',
'modules/benchpress/**/*.ts',
'./*.ts',
// Ignore TypeScript mocks because it's not managed by us
'!./tools/@angular/tsc-wrapped/test/typescript.mocks.ts',
// Ignore generated files due to lack of copyright header
// todo(alfaproject): make generated files lintable
'!**/*.d.ts',
'!**/*.ngfactory.ts',
])
.pipe(tslint({
tslint: require('tslint').default,
configuration: tslintConfig,
rulesDirectory: 'dist/tools/tslint',
formatter: 'prose',
}))
.pipe(tslint.report({emitError: true}));

View File

@ -23,26 +23,18 @@ module.exports = function(config) {
'node_modules/core-js/client/core.js',
// include Angular v1 for upgrade module testing
'node_modules/angular/angular.js',
'node_modules/angular-mocks/angular-mocks.js',
'node_modules/angular/angular.min.js',
'node_modules/zone.js/dist/zone.js',
'node_modules/zone.js/dist/long-stack-trace-zone.js',
'node_modules/zone.js/dist/proxy.js',
'node_modules/zone.js/dist/sync-test.js',
'node_modules/zone.js/dist/jasmine-patch.js',
'node_modules/zone.js/dist/async-test.js',
'node_modules/zone.js/dist/zone.js', 'node_modules/zone.js/dist/long-stack-trace-zone.js',
'node_modules/zone.js/dist/proxy.js', 'node_modules/zone.js/dist/sync-test.js',
'node_modules/zone.js/dist/jasmine-patch.js', 'node_modules/zone.js/dist/async-test.js',
'node_modules/zone.js/dist/fake-async-test.js',
// Including systemjs because it defines `__eval`, which produces correct stack traces.
'shims_for_IE.js',
'node_modules/systemjs/dist/system.src.js',
'shims_for_IE.js', 'node_modules/systemjs/dist/system.src.js',
{pattern: 'node_modules/rxjs/**', included: false, watched: false, served: true},
'node_modules/reflect-metadata/Reflect.js',
'tools/build/file2modulename.js',
'test-main.js',
{pattern: 'dist/all/empty.*', included: false, watched: false},
{
'node_modules/reflect-metadata/Reflect.js', 'tools/build/file2modulename.js', 'test-main.js',
{pattern: 'dist/all/empty.*', included: false, watched: false}, {
pattern: 'modules/@angular/platform-browser/test/static_assets/**',
included: false,
watched: false
@ -56,15 +48,11 @@ module.exports = function(config) {
exclude: [
'dist/all/@angular/**/e2e_test/**',
'dist/all/@angular/**/*node_only_spec.js',
'dist/all/@angular/benchpress/**',
'dist/all/@angular/compiler-cli/**',
'dist/all/@angular/compiler/test/aot/**',
'dist/all/@angular/examples/**/e2e_test/*',
'dist/all/@angular/language-service/**',
'dist/all/@angular/router/**',
'dist/all/@angular/platform-browser/testing/e2e_util.js',
'dist/all/@angular/compiler-cli/**',
'dist/all/@angular/benchpress/**',
'dist/all/angular1_router.js',
'dist/all/@angular/platform-browser/testing/e2e_util.js',
'dist/examples/**/e2e_test/**',
],
@ -102,17 +90,17 @@ module.exports = function(config) {
project: 'Angular2',
startTunnel: false,
retryLimit: 3,
timeout: 1800,
timeout: 600,
pollingTimeout: 10000,
},
browsers: ['Chrome'],
port: 9876,
captureTimeout: 180000,
browserDisconnectTimeout: 180000,
captureTimeout: 60000,
browserDisconnectTimeout: 60000,
browserDisconnectTolerance: 3,
browserNoActivityTimeout: 300000,
browserNoActivityTimeout: 60000,
});
if (process.env.TRAVIS) {

View File

@ -7,7 +7,7 @@
"dependencies": {
"@angular/core": "^2.0.0-rc.7",
"reflect-metadata": "^0.1.2",
"rxjs": "^5.0.1",
"rxjs": "5.0.0-beta.12",
"jpm": "1.1.4",
"firefox-profile": "0.4.0",
"selenium-webdriver": "^2.53.3"

View File

@ -10,7 +10,7 @@ declare var exportFunction: any;
declare var unsafeWindow: any;
exportFunction(function() {
const curTime = unsafeWindow.performance.now();
var curTime = unsafeWindow.performance.now();
(<any>self).port.emit('startProfiler', curTime);
}, unsafeWindow, {defineAs: 'startProfiler'});
@ -28,11 +28,11 @@ exportFunction(function() {
}, unsafeWindow, {defineAs: 'forceGC'});
exportFunction(function(name: string) {
const curTime = unsafeWindow.performance.now();
var curTime = unsafeWindow.performance.now();
(<any>self).port.emit('markStart', name, curTime);
}, unsafeWindow, {defineAs: 'markStart'});
exportFunction(function(name: string) {
const curTime = unsafeWindow.performance.now();
var curTime = unsafeWindow.performance.now();
(<any>self).port.emit('markEnd', name, curTime);
}, unsafeWindow, {defineAs: 'markEnd'});

View File

@ -6,9 +6,9 @@
* found in the LICENSE file at https://angular.io/license
*/
const {Cc, Ci, Cu} = require('chrome');
const os = Cc['@mozilla.org/observer-service;1'].getService(Ci.nsIObserverService);
const ParserUtil = require('./parser_util');
var {Cc, Ci, Cu} = require('chrome');
var os = Cc['@mozilla.org/observer-service;1'].getService(Ci.nsIObserverService);
var ParserUtil = require('./parser_util');
class Profiler {
private _profiler: any;
@ -26,8 +26,8 @@ class Profiler {
stop() { this._profiler.StopProfiler(); }
getProfilePerfEvents() {
const profileData = this._profiler.getProfileData();
let perfEvents = ParserUtil.convertPerfProfileToEvents(profileData);
var profileData = this._profiler.getProfileData();
var perfEvents = ParserUtil.convertPerfProfileToEvents(profileData);
perfEvents = this._mergeMarkerEvents(perfEvents);
perfEvents.sort(function(event1: any, event2: any) {
return event1.ts - event2.ts;
@ -55,9 +55,9 @@ function forceGC() {
os.notifyObservers(null, 'child-gc-request', null);
};
const mod = require('sdk/page-mod');
const data = require('sdk/self').data;
const profiler = new Profiler();
var mod = require('sdk/page-mod');
var data = require('sdk/self').data;
var profiler = new Profiler();
mod.PageMod({
include: ['*'],
contentScriptFile: data.url('installed_script.js'),

View File

@ -12,11 +12,11 @@
* within the perf profile.
*/
export function convertPerfProfileToEvents(perfProfile: any): any[] {
const inProgressEvents = new Map(); // map from event name to start time
const finishedEvents: {[key: string]: any}[] = []; // Event[] finished events
const addFinishedEvent = function(eventName: string, startTime: number, endTime: number) {
const categorizedEventName = categorizeEvent(eventName);
let args: {[key: string]: any} = undefined;
var inProgressEvents = new Map(); // map from event name to start time
var finishedEvents: {[key: string]: any}[] = []; // Event[] finished events
var addFinishedEvent = function(eventName: string, startTime: number, endTime: number) {
var categorizedEventName = categorizeEvent(eventName);
var args: {[key: string]: any} = undefined;
if (categorizedEventName == 'gc') {
// TODO: We cannot measure heap size at the moment
args = {usedHeapSize: 0};
@ -31,17 +31,17 @@ export function convertPerfProfileToEvents(perfProfile: any): any[] {
}
};
const samples = perfProfile.threads[0].samples;
var samples = perfProfile.threads[0].samples;
// In perf profile, firefox samples all the frames in set time intervals. Here
// we go through all the samples and construct the start and end time for each
// event.
for (let i = 0; i < samples.length; ++i) {
const sample = samples[i];
const sampleTime = sample.time;
for (var i = 0; i < samples.length; ++i) {
var sample = samples[i];
var sampleTime = sample.time;
// Add all the frames into a set so it's easier/faster to find the set
// differences
const sampleFrames = new Set();
var sampleFrames = new Set();
sample.frames.forEach(function(frame: {[key: string]: any}) {
sampleFrames.add(frame['location']);
});
@ -49,7 +49,7 @@ export function convertPerfProfileToEvents(perfProfile: any): any[] {
// If an event is in the inProgressEvents map, but not in the current sample,
// then it must have just finished. We add this event to the finishedEvents
// array and remove it from the inProgressEvents map.
const previousSampleTime = (i == 0 ? /* not used */ -1 : samples[i - 1].time);
var previousSampleTime = (i == 0 ? /* not used */ -1 : samples[i - 1].time);
inProgressEvents.forEach(function(startTime, eventName) {
if (!(sampleFrames.has(eventName))) {
addFinishedEvent(eventName, startTime, previousSampleTime);
@ -69,7 +69,7 @@ export function convertPerfProfileToEvents(perfProfile: any): any[] {
// If anything is still in progress, we need to included it as a finished event
// since recording ended.
const lastSampleTime = samples[samples.length - 1].time;
var lastSampleTime = samples[samples.length - 1].time;
inProgressEvents.forEach(function(startTime, eventName) {
addFinishedEvent(eventName, startTime, lastSampleTime);
});

View File

@ -6,15 +6,15 @@
* found in the LICENSE file at https://angular.io/license
*/
const q = require('q');
const FirefoxProfile = require('firefox-profile');
const jpm = require('jpm/lib/xpi');
const pathUtil = require('path');
var q = require('q');
var FirefoxProfile = require('firefox-profile');
var jpm = require('jpm/lib/xpi');
var pathUtil = require('path');
const PERF_ADDON_PACKAGE_JSON_DIR = '..';
var PERF_ADDON_PACKAGE_JSON_DIR = '..';
exports.getAbsolutePath = function(path: string) {
const normalizedPath = pathUtil.normalize(path);
var normalizedPath = pathUtil.normalize(path);
if (pathUtil.resolve(normalizedPath) == normalizedPath) {
// Already absolute path
return normalizedPath;
@ -24,12 +24,12 @@ exports.getAbsolutePath = function(path: string) {
};
exports.getFirefoxProfile = function(extensionPath: string) {
const deferred = q.defer();
var deferred = q.defer();
const firefoxProfile = new FirefoxProfile();
var firefoxProfile = new FirefoxProfile();
firefoxProfile.addExtensions([extensionPath], () => {
firefoxProfile.encoded((encodedProfile: any) => {
const multiCapabilities = [{browserName: 'firefox', firefox_profile: encodedProfile}];
var multiCapabilities = [{browserName: 'firefox', firefox_profile: encodedProfile}];
deferred.resolve(multiCapabilities);
});
});
@ -38,10 +38,10 @@ exports.getFirefoxProfile = function(extensionPath: string) {
};
exports.getFirefoxProfileWithExtension = function() {
const absPackageJsonDir = pathUtil.join(__dirname, PERF_ADDON_PACKAGE_JSON_DIR);
const packageJson = require(pathUtil.join(absPackageJsonDir, 'package.json'));
var absPackageJsonDir = pathUtil.join(__dirname, PERF_ADDON_PACKAGE_JSON_DIR);
var packageJson = require(pathUtil.join(absPackageJsonDir, 'package.json'));
const savedCwd = process.cwd();
var savedCwd = process.cwd();
process.chdir(absPackageJsonDir);
return jpm(packageJson).then((xpiPath: string) => {

View File

@ -55,9 +55,9 @@ export class MultiMetric extends Metric {
}
function mergeStringMaps(maps: {[key: string]: string}[]): {[key: string]: string} {
const result: {[key: string]: string} = {};
var result: {[key: string]: string} = {};
maps.forEach(map => { Object.keys(map).forEach(prop => { result[prop] = map[prop]; }); });
return result;
}
const _CHILDREN = new OpaqueToken('MultiMetric.children');
var _CHILDREN = new OpaqueToken('MultiMetric.children');

View File

@ -56,7 +56,7 @@ export class PerflogMetric extends Metric {
}
describe(): {[key: string]: string} {
const res: {[key: string]: any} = {
var res: {[key: string]: any} = {
'scriptTime': 'script execution time in ms, including gc and render',
'pureScriptTime': 'script execution time in ms, without gc nor render'
};
@ -80,7 +80,7 @@ export class PerflogMetric extends Metric {
}
if (this._captureFrames) {
if (!this._perfLogFeatures.frameCapture) {
const warningMsg = 'WARNING: Metric requested, but not supported by driver';
var warningMsg = 'WARNING: Metric requested, but not supported by driver';
// using dot syntax for metric name to keep them grouped together in console reporter
res['frameTime.mean'] = warningMsg;
res['frameTime.worst'] = warningMsg;
@ -93,14 +93,14 @@ export class PerflogMetric extends Metric {
res['frameTime.smooth'] = 'percentage of frames that hit 60fps';
}
}
for (const name in this._microMetrics) {
for (let name in this._microMetrics) {
res[name] = this._microMetrics[name];
}
return res;
}
beginMeasure(): Promise<any> {
let resultPromise = Promise.resolve(null);
var resultPromise = Promise.resolve(null);
if (this._forceGc) {
resultPromise = resultPromise.then((_) => this._driverExtension.gc());
}
@ -119,7 +119,7 @@ export class PerflogMetric extends Metric {
private _endPlainMeasureAndMeasureForceGc(restartMeasure: boolean) {
return this._endMeasure(true).then((measureValues) => {
// disable frame capture for measurements during forced gc
const originalFrameCaptureValue = this._captureFrames;
var originalFrameCaptureValue = this._captureFrames;
this._captureFrames = false;
return this._driverExtension.gc()
.then((_) => this._endMeasure(restartMeasure))
@ -137,8 +137,8 @@ export class PerflogMetric extends Metric {
}
private _endMeasure(restart: boolean): Promise<{[key: string]: number}> {
const markName = this._markName(this._measureCount - 1);
const nextMarkName = restart ? this._markName(this._measureCount++) : null;
var markName = this._markName(this._measureCount - 1);
var nextMarkName = restart ? this._markName(this._measureCount++) : null;
return this._driverExtension.timeEnd(markName, nextMarkName)
.then((_) => this._readUntilEndMark(markName));
}
@ -150,26 +150,26 @@ export class PerflogMetric extends Metric {
}
return this._driverExtension.readPerfLog().then((events) => {
this._addEvents(events);
const result = this._aggregateEvents(this._remainingEvents, markName);
var result = this._aggregateEvents(this._remainingEvents, markName);
if (result) {
this._remainingEvents = events;
return result;
}
let resolve: (result: any) => void;
const promise = new Promise(res => { resolve = res; });
var resolve: (result: any) => void;
var promise = new Promise(res => { resolve = res; });
this._setTimeout(() => resolve(this._readUntilEndMark(markName, loopCount + 1)), 100);
return promise;
});
}
private _addEvents(events: PerfLogEvent[]) {
let needSort = false;
var needSort = false;
events.forEach(event => {
if (event['ph'] === 'X') {
needSort = true;
const startEvent: PerfLogEvent = {};
const endEvent: PerfLogEvent = {};
for (const prop in event) {
var startEvent: PerfLogEvent = {};
var endEvent: PerfLogEvent = {};
for (let prop in event) {
startEvent[prop] = event[prop];
endEvent[prop] = event[prop];
}
@ -185,14 +185,14 @@ export class PerflogMetric extends Metric {
if (needSort) {
// Need to sort because of the ph==='X' events
this._remainingEvents.sort((a, b) => {
const diff = a['ts'] - b['ts'];
var diff = a['ts'] - b['ts'];
return diff > 0 ? 1 : diff < 0 ? -1 : 0;
});
}
}
private _aggregateEvents(events: PerfLogEvent[], markName: string): {[key: string]: number} {
const result: {[key: string]: number} = {'scriptTime': 0, 'pureScriptTime': 0};
var result: {[key: string]: number} = {'scriptTime': 0, 'pureScriptTime': 0};
if (this._perfLogFeatures.gc) {
result['gcTime'] = 0;
result['majorGcTime'] = 0;
@ -207,7 +207,7 @@ export class PerflogMetric extends Metric {
result['frameTime.worst'] = 0;
result['frameTime.smooth'] = 0;
}
for (const name in this._microMetrics) {
for (let name in this._microMetrics) {
result[name] = 0;
}
if (this._receivedData) {
@ -217,11 +217,11 @@ export class PerflogMetric extends Metric {
result['requestCount'] = 0;
}
let markStartEvent: PerfLogEvent = null;
let markEndEvent: PerfLogEvent = null;
var markStartEvent: PerfLogEvent = null;
var markEndEvent: PerfLogEvent = null;
events.forEach((event) => {
const ph = event['ph'];
const name = event['name'];
var ph = event['ph'];
var name = event['name'];
if (ph === 'B' && name === markName) {
markStartEvent = event;
} else if (ph === 'I' && name === 'navigationStart') {
@ -237,23 +237,23 @@ export class PerflogMetric extends Metric {
return null;
}
let gcTimeInScript = 0;
let renderTimeInScript = 0;
var gcTimeInScript = 0;
var renderTimeInScript = 0;
const frameTimestamps: number[] = [];
const frameTimes: number[] = [];
let frameCaptureStartEvent: PerfLogEvent = null;
let frameCaptureEndEvent: PerfLogEvent = null;
var frameTimestamps: number[] = [];
var frameTimes: number[] = [];
var frameCaptureStartEvent: PerfLogEvent = null;
var frameCaptureEndEvent: PerfLogEvent = null;
const intervalStarts: {[key: string]: PerfLogEvent} = {};
const intervalStartCount: {[key: string]: number} = {};
var intervalStarts: {[key: string]: PerfLogEvent} = {};
var intervalStartCount: {[key: string]: number} = {};
let inMeasureRange = false;
var inMeasureRange = false;
events.forEach((event) => {
const ph = event['ph'];
let name = event['name'];
let microIterations = 1;
const microIterationsMatch = name.match(_MICRO_ITERATIONS_REGEX);
var ph = event['ph'];
var name = event['name'];
var microIterations = 1;
var microIterationsMatch = name.match(_MICRO_ITERATIONS_REGEX);
if (microIterationsMatch) {
name = microIterationsMatch[1];
microIterations = parseInt(microIterationsMatch[2], 10);
@ -307,15 +307,15 @@ export class PerflogMetric extends Metric {
} else if ((ph === 'E') && intervalStarts[name]) {
intervalStartCount[name]--;
if (intervalStartCount[name] === 0) {
const startEvent = intervalStarts[name];
const duration = (event['ts'] - startEvent['ts']);
var startEvent = intervalStarts[name];
var duration = (event['ts'] - startEvent['ts']);
intervalStarts[name] = null;
if (name === 'gc') {
result['gcTime'] += duration;
const amount =
var amount =
(startEvent['args']['usedHeapSize'] - event['args']['usedHeapSize']) / 1000;
result['gcAmount'] += amount;
const majorGc = event['args']['majorGc'];
var majorGc = event['args']['majorGc'];
if (majorGc && majorGc) {
result['majorGcTime'] += duration;
}
@ -351,7 +351,7 @@ export class PerflogMetric extends Metric {
private _addFrameMetrics(result: {[key: string]: number}, frameTimes: any[]) {
result['frameTime.mean'] = frameTimes.reduce((a, b) => a + b, 0) / frameTimes.length;
const firstFrame = frameTimes[0];
var firstFrame = frameTimes[0];
result['frameTime.worst'] = frameTimes.reduce((a, b) => a > b ? a : b, firstFrame);
result['frameTime.best'] = frameTimes.reduce((a, b) => a < b ? a : b, firstFrame);
result['frameTime.smooth'] =
@ -361,11 +361,11 @@ export class PerflogMetric extends Metric {
private _markName(index: number) { return `${_MARK_NAME_PREFIX}${index}`; }
}
const _MICRO_ITERATIONS_REGEX = /(.+)\*(\d+)$/;
var _MICRO_ITERATIONS_REGEX = /(.+)\*(\d+)$/;
const _MAX_RETRY_COUNT = 20;
const _MARK_NAME_PREFIX = 'benchpress';
var _MAX_RETRY_COUNT = 20;
var _MARK_NAME_PREFIX = 'benchpress';
const _MARK_NAME_FRAME_CAPUTRE = 'frameCapture';
var _MARK_NAME_FRAME_CAPUTRE = 'frameCapture';
// using 17ms as a somewhat looser threshold, instead of 16.6666ms
const _FRAME_TIME_SMOOTH_THRESHOLD = 17;
var _FRAME_TIME_SMOOTH_THRESHOLD = 17;

View File

@ -33,12 +33,12 @@ export class UserMetric extends Metric {
endMeasure(restart: boolean): Promise<{[key: string]: any}> {
let resolve: (result: any) => void;
let reject: (error: any) => void;
const promise = new Promise((res, rej) => {
let promise = new Promise((res, rej) => {
resolve = res;
reject = rej;
});
const adapter = this._wdAdapter;
const names = Object.keys(this._userMetrics);
let adapter = this._wdAdapter;
let names = Object.keys(this._userMetrics);
function getAndClearValues() {
Promise.all(names.map(name => adapter.executeScript(`return window.${name}`)))
@ -46,7 +46,7 @@ export class UserMetric extends Metric {
if (values.every(v => typeof v === 'number')) {
Promise.all(names.map(name => adapter.executeScript(`delete window.${name}`)))
.then((_: any[]) => {
const map: {[k: string]: any} = {};
let map: {[k: string]: any} = {};
for (let i = 0, n = names.length; i < n; i++) {
map[names[i]] = values[i];
}

View File

@ -28,8 +28,8 @@ export class ConsoleReporter extends Reporter {
];
private static _lpad(value: string, columnWidth: number, fill = ' ') {
let result = '';
for (let i = 0; i < columnWidth - value.length; i++) {
var result = '';
for (var i = 0; i < columnWidth - value.length; i++) {
result += fill;
}
return result + value;
@ -49,7 +49,7 @@ export class ConsoleReporter extends Reporter {
private _printDescription(sampleDescription: SampleDescription) {
this._print(`BENCHMARK ${sampleDescription.id}`);
this._print('Description:');
const props = sortedProps(sampleDescription.description);
var props = sortedProps(sampleDescription.description);
props.forEach((prop) => { this._print(`- ${prop}: ${sampleDescription.description[prop]}`); });
this._print('Metrics:');
this._metricNames.forEach((metricName) => {
@ -61,8 +61,8 @@ export class ConsoleReporter extends Reporter {
}
reportMeasureValues(measureValues: MeasureValues): Promise<any> {
const formattedValues = this._metricNames.map(metricName => {
const value = measureValues.values[metricName];
var formattedValues = this._metricNames.map(metricName => {
var value = measureValues.values[metricName];
return formatNum(value);
});
this._printStringRow(formattedValues);

View File

@ -38,7 +38,7 @@ export class JsonFileReporter extends Reporter {
sortedProps(this._description.metrics).forEach((metricName) => {
stats[metricName] = formatStats(validSample, metricName);
});
const content = JSON.stringify(
var content = JSON.stringify(
{
'description': this._description,
'stats': stats,
@ -46,7 +46,7 @@ export class JsonFileReporter extends Reporter {
'validSample': validSample,
},
null, 2);
const filePath = `${this._path}/${this._description.id}_${this._now().getTime()}.json`;
var filePath = `${this._path}/${this._description.id}_${this._now().getTime()}.json`;
return this._writeFile(filePath, content);
}
}

View File

@ -39,4 +39,4 @@ export class MultiReporter extends Reporter {
}
}
const _CHILDREN = new OpaqueToken('MultiReporter.children');
var _CHILDREN = new OpaqueToken('MultiReporter.children');

View File

@ -18,10 +18,10 @@ export function sortedProps(obj: {[key: string]: any}) {
}
export function formatStats(validSamples: MeasureValues[], metricName: string): string {
const samples = validSamples.map(measureValues => measureValues.values[metricName]);
const mean = Statistic.calculateMean(samples);
const cv = Statistic.calculateCoefficientOfVariation(samples, mean);
const formattedMean = formatNum(mean);
var samples = validSamples.map(measureValues => measureValues.values[metricName]);
var mean = Statistic.calculateMean(samples);
var cv = Statistic.calculateCoefficientOfVariation(samples, mean);
var formattedMean = formatNum(mean);
// Note: Don't use the unicode character for +- as it might cause
// hickups for consoles...
return isNaN(cv) ? formattedMean : `${formattedMean}+-${Math.floor(cv)}%`;

View File

@ -45,7 +45,7 @@ export class Runner {
providers?: Provider[],
userMetrics?: {[key: string]: string}
}): Promise<SampleState> {
const sampleProviders: Provider[] = [
var sampleProviders: Provider[] = [
_DEFAULT_PROVIDERS, this._defaultProviders, {provide: Options.SAMPLE_ID, useValue: id},
{provide: Options.EXECUTE, useValue: execute}
];
@ -62,33 +62,33 @@ export class Runner {
sampleProviders.push(providers);
}
const inj = ReflectiveInjector.resolveAndCreate(sampleProviders);
const adapter: WebDriverAdapter = inj.get(WebDriverAdapter);
var inj = ReflectiveInjector.resolveAndCreate(sampleProviders);
var adapter: WebDriverAdapter = inj.get(WebDriverAdapter);
return Promise
.all([adapter.capabilities(), adapter.executeScript('return window.navigator.userAgent;')])
.then((args) => {
const capabilities = args[0];
const userAgent = args[1];
var capabilities = args[0];
var userAgent = args[1];
// This might still create instances twice. We are creating a new injector with all the
// providers.
// Only WebDriverAdapter is reused.
// TODO vsavkin consider changing it when toAsyncFactory is added back or when child
// injectors are handled better.
const injector = ReflectiveInjector.resolveAndCreate([
var injector = ReflectiveInjector.resolveAndCreate([
sampleProviders, {provide: Options.CAPABILITIES, useValue: capabilities},
{provide: Options.USER_AGENT, useValue: userAgent},
{provide: WebDriverAdapter, useValue: adapter}
]);
const sampler = injector.get(Sampler);
var sampler = injector.get(Sampler);
return sampler.sample();
});
}
}
const _DEFAULT_PROVIDERS = [
var _DEFAULT_PROVIDERS = [
Options.DEFAULT_PROVIDERS,
Sampler.PROVIDERS,
ConsoleReporter.PROVIDERS,

View File

@ -49,7 +49,7 @@ export class Sampler {
}
private _iterate(lastState: SampleState): Promise<SampleState> {
let resultPromise: Promise<SampleState>;
var resultPromise: Promise<SampleState>;
if (this._prepare !== Options.NO_PREPARE) {
resultPromise = this._driver.waitFor(this._prepare);
} else {
@ -64,10 +64,10 @@ export class Sampler {
}
private _report(state: SampleState, metricValues: {[key: string]: any}): Promise<SampleState> {
const measureValues = new MeasureValues(state.completeSample.length, this._now(), metricValues);
const completeSample = state.completeSample.concat([measureValues]);
const validSample = this._validator.validate(completeSample);
let resultPromise = this._reporter.reportMeasureValues(measureValues);
var measureValues = new MeasureValues(state.completeSample.length, this._now(), metricValues);
var completeSample = state.completeSample.concat([measureValues]);
var validSample = this._validator.validate(completeSample);
var resultPromise = this._reporter.reportMeasureValues(measureValues);
if (isPresent(validSample)) {
resultPromise =
resultPromise.then((_) => this._reporter.reportSample(completeSample, validSample));

View File

@ -12,14 +12,14 @@ export class Statistic {
}
static calculateMean(samples: number[]) {
let total = 0;
var total = 0;
// TODO: use reduce
samples.forEach(x => total += x);
return total / samples.length;
}
static calculateStandardDeviation(samples: number[], mean: number) {
let deviation = 0;
var deviation = 0;
// TODO: use reduce
samples.forEach(x => deviation += Math.pow(x - mean, 2));
deviation = deviation / (samples.length);
@ -30,9 +30,9 @@ export class Statistic {
static calculateRegressionSlope(
xValues: number[], xMean: number, yValues: number[], yMean: number) {
// See http://en.wikipedia.org/wiki/Simple_linear_regression
let dividendSum = 0;
let divisorSum = 0;
for (let i = 0; i < xValues.length; i++) {
var dividendSum = 0;
var divisorSum = 0;
for (var i = 0; i < xValues.length; i++) {
dividendSum += (xValues[i] - xMean) * (yValues[i] - yMean);
divisorSum += Math.pow(xValues[i] - xMean, 2);
}

View File

@ -34,7 +34,7 @@ export type PerfLogEvent = {
*/
export abstract class WebDriverExtension {
static provideFirstSupported(childTokens: any[]): any[] {
const res = [
var res = [
{
provide: _CHILDREN,
useFactory: (injector: Injector) => childTokens.map(token => injector.get(token)),
@ -43,7 +43,7 @@ export abstract class WebDriverExtension {
{
provide: WebDriverExtension,
useFactory: (children: WebDriverExtension[], capabilities: {[key: string]: any}) => {
let delegate: WebDriverExtension;
var delegate: WebDriverExtension;
children.forEach(extension => {
if (extension.supports(capabilities)) {
delegate = extension;
@ -101,4 +101,4 @@ export class PerfLogFeatures {
}
}
const _CHILDREN = new OpaqueToken('WebDriverExtension.children');
var _CHILDREN = new OpaqueToken('WebDriverExtension.children');

View File

@ -34,7 +34,7 @@ export class ChromeDriverExtension extends WebDriverExtension {
if (!userAgent) {
return -1;
}
let v = userAgent.split(/Chrom(e|ium)\//g)[2];
var v = userAgent.split(/Chrom(e|ium)\//g)[2];
if (!v) {
return -1;
}
@ -52,7 +52,7 @@ export class ChromeDriverExtension extends WebDriverExtension {
}
timeEnd(name: string, restartName: string = null): Promise<any> {
let script = `console.timeEnd('${name}');`;
var script = `console.timeEnd('${name}');`;
if (restartName) {
script += `console.time('${restartName}');`;
}
@ -67,9 +67,9 @@ export class ChromeDriverExtension extends WebDriverExtension {
return this._driver.executeScript('1+1')
.then((_) => this._driver.logs('performance'))
.then((entries) => {
const events: PerfLogEvent[] = [];
var events: PerfLogEvent[] = [];
entries.forEach(entry => {
const message = JSON.parse(entry['message'])['message'];
var message = JSON.parse(entry['message'])['message'];
if (message['method'] === 'Tracing.dataCollected') {
events.push(message['params']);
}
@ -95,8 +95,8 @@ export class ChromeDriverExtension extends WebDriverExtension {
}
private _convertEvent(event: {[key: string]: any}, categories: string[]) {
const name = event['name'];
const args = event['args'];
var name = event['name'];
var args = event['args'];
if (this._isEvent(categories, name, ['blink.console'])) {
return normalizeEvent(event, {'name': name});
} else if (this._isEvent(
@ -109,7 +109,7 @@ export class ChromeDriverExtension extends WebDriverExtension {
// new surfaces framework (not broadly enabled yet)
// 3rd choice: BenchmarkInstrumentation::ImplThreadRenderingStats - fallback event that is
// always available if something is rendered
const frameCount = event['args']['data']['frame_count'];
var frameCount = event['args']['data']['frame_count'];
if (frameCount > 1) {
throw new Error('multi-frame render stats not supported');
}
@ -122,14 +122,14 @@ export class ChromeDriverExtension extends WebDriverExtension {
categories, name, ['disabled-by-default-devtools.timeline'], 'CompositeLayers')) {
return normalizeEvent(event, {'name': 'render'});
} else if (this._isEvent(categories, name, ['devtools.timeline', 'v8'], 'MajorGC')) {
const normArgs = {
var normArgs = {
'majorGc': true,
'usedHeapSize': args['usedHeapSizeAfter'] !== undefined ? args['usedHeapSizeAfter'] :
args['usedHeapSizeBefore']
};
return normalizeEvent(event, {'name': 'gc', 'args': normArgs});
} else if (this._isEvent(categories, name, ['devtools.timeline', 'v8'], 'MinorGC')) {
const normArgs = {
var normArgs = {
'majorGc': false,
'usedHeapSize': args['usedHeapSizeAfter'] !== undefined ? args['usedHeapSizeAfter'] :
args['usedHeapSizeBefore']
@ -151,11 +151,11 @@ export class ChromeDriverExtension extends WebDriverExtension {
this._isEvent(categories, name, ['devtools.timeline'], 'Paint')) {
return normalizeEvent(event, {'name': 'render'});
} else if (this._isEvent(categories, name, ['devtools.timeline'], 'ResourceReceivedData')) {
const normArgs = {'encodedDataLength': args['data']['encodedDataLength']};
let normArgs = {'encodedDataLength': args['data']['encodedDataLength']};
return normalizeEvent(event, {'name': 'receivedData', 'args': normArgs});
} else if (this._isEvent(categories, name, ['devtools.timeline'], 'ResourceSendRequest')) {
const data = args['data'];
const normArgs = {'url': data['url'], 'method': data['requestMethod']};
let data = args['data'];
let normArgs = {'url': data['url'], 'method': data['requestMethod']};
return normalizeEvent(event, {'name': 'sendRequest', 'args': normArgs});
} else if (this._isEvent(categories, name, ['blink.user_timing'], 'navigationStart')) {
return normalizeEvent(event, {'name': 'navigationStart'});
@ -168,7 +168,7 @@ export class ChromeDriverExtension extends WebDriverExtension {
private _isEvent(
eventCategories: string[], eventName: string, expectedCategories: string[],
expectedName: string = null): boolean {
const hasCategories = expectedCategories.reduce(
var hasCategories = expectedCategories.reduce(
(value, cat) => value && eventCategories.indexOf(cat) !== -1, true);
return !expectedName ? hasCategories : hasCategories && eventName === expectedName;
}
@ -183,7 +183,7 @@ export class ChromeDriverExtension extends WebDriverExtension {
}
function normalizeEvent(chromeEvent: {[key: string]: any}, data: PerfLogEvent): PerfLogEvent {
let ph = chromeEvent['ph'].toUpperCase();
var ph = chromeEvent['ph'].toUpperCase();
if (ph === 'S') {
ph = 'B';
} else if (ph === 'F') {
@ -192,16 +192,16 @@ function normalizeEvent(chromeEvent: {[key: string]: any}, data: PerfLogEvent):
// mark events from navigation timing
ph = 'I';
}
const result: {[key: string]: any} =
var result: {[key: string]: any} =
{'pid': chromeEvent['pid'], 'ph': ph, 'cat': 'timeline', 'ts': chromeEvent['ts'] / 1000};
if (ph === 'X') {
let dur = chromeEvent['dur'];
var dur = chromeEvent['dur'];
if (dur === undefined) {
dur = chromeEvent['tdur'];
}
result['dur'] = !dur ? 0.0 : dur / 1000;
}
for (const prop in data) {
for (let prop in data) {
result[prop] = data[prop];
}
return result;

View File

@ -34,7 +34,7 @@ export class FirefoxDriverExtension extends WebDriverExtension {
}
timeEnd(name: string, restartName: string = null): Promise<any> {
let script = 'window.markEnd("' + name + '");';
var script = 'window.markEnd("' + name + '");';
if (isPresent(restartName)) {
script += 'window.markStart("' + restartName + '");';
}

View File

@ -25,7 +25,7 @@ export class IOsDriverExtension extends WebDriverExtension {
}
timeEnd(name: string, restartName: string = null): Promise<any> {
let script = `console.timeEnd('${name}');`;
var script = `console.timeEnd('${name}');`;
if (isPresent(restartName)) {
script += `console.time('${restartName}');`;
}
@ -39,9 +39,9 @@ export class IOsDriverExtension extends WebDriverExtension {
return this._driver.executeScript('1+1')
.then((_) => this._driver.logs('performance'))
.then((entries) => {
const records: any[] = [];
var records: any[] = [];
entries.forEach(entry => {
const message = JSON.parse(entry['message'])['message'];
var message = JSON.parse(entry['message'])['message'];
if (message['method'] === 'Timeline.eventRecorded') {
records.push(message['params']['record']);
}
@ -56,11 +56,11 @@ export class IOsDriverExtension extends WebDriverExtension {
events = [];
}
records.forEach((record) => {
let endEvent: PerfLogEvent = null;
const type = record['type'];
const data = record['data'];
const startTime = record['startTime'];
const endTime = record['endTime'];
var endEvent: PerfLogEvent = null;
var type = record['type'];
var data = record['data'];
var startTime = record['startTime'];
var endTime = record['endTime'];
if (type === 'FunctionCall' && (data == null || data['scriptName'] !== 'InjectedScript')) {
events.push(createStartEvent('script', startTime));
@ -95,7 +95,7 @@ export class IOsDriverExtension extends WebDriverExtension {
function createEvent(
ph: 'X' | 'B' | 'E' | 'B' | 'E', name: string, time: number, args: any = null) {
const result: PerfLogEvent = {
var result: PerfLogEvent = {
'cat': 'timeline',
'name': name,
'ts': time,

View File

@ -8,7 +8,7 @@
require('core-js');
require('reflect-metadata');
const testHelper = require('../../src/firefox_extension/lib/test_helper.js');
var testHelper = require('../../src/firefox_extension/lib/test_helper.js');
exports.config = {
specs: ['spec.js', 'sample_benchmark.js'],

View File

@ -10,10 +10,10 @@ import {convertPerfProfileToEvents} from '../../src/firefox_extension/lib/parser
function assertEventsEqual(actualEvents: any[], expectedEvents: any[]) {
expect(actualEvents.length == expectedEvents.length);
for (let i = 0; i < actualEvents.length; ++i) {
const actualEvent = actualEvents[i];
const expectedEvent = expectedEvents[i];
for (const key in actualEvent) {
for (var i = 0; i < actualEvents.length; ++i) {
var actualEvent = actualEvents[i];
var expectedEvent = expectedEvents[i];
for (var key in actualEvent) {
expect(actualEvent[key]).toEqual(expectedEvent[key]);
}
}
@ -22,17 +22,17 @@ function assertEventsEqual(actualEvents: any[], expectedEvents: any[]) {
export function main() {
describe('convertPerfProfileToEvents', function() {
it('should convert single instantaneous event', function() {
const profileData = {
var profileData = {
threads: [
{samples: [{time: 1, frames: [{location: 'FirefoxDriver.prototype.executeScript'}]}]}
]
};
const perfEvents = convertPerfProfileToEvents(profileData);
var perfEvents = convertPerfProfileToEvents(profileData);
assertEventsEqual(perfEvents, [{ph: 'X', ts: 1, name: 'script'}]);
});
it('should convert single non-instantaneous event', function() {
const profileData = {
var profileData = {
threads: [{
samples: [
{time: 1, frames: [{location: 'FirefoxDriver.prototype.executeScript'}]},
@ -41,13 +41,13 @@ export function main() {
]
}]
};
const perfEvents = convertPerfProfileToEvents(profileData);
var perfEvents = convertPerfProfileToEvents(profileData);
assertEventsEqual(
perfEvents, [{ph: 'B', ts: 1, name: 'script'}, {ph: 'E', ts: 100, name: 'script'}]);
});
it('should convert multiple instantaneous events', function() {
const profileData = {
var profileData = {
threads: [{
samples: [
{time: 1, frames: [{location: 'FirefoxDriver.prototype.executeScript'}]},
@ -55,13 +55,13 @@ export function main() {
]
}]
};
const perfEvents = convertPerfProfileToEvents(profileData);
var perfEvents = convertPerfProfileToEvents(profileData);
assertEventsEqual(
perfEvents, [{ph: 'X', ts: 1, name: 'script'}, {ph: 'X', ts: 2, name: 'render'}]);
});
it('should convert multiple mixed events', function() {
const profileData = {
var profileData = {
threads: [{
samples: [
{time: 1, frames: [{location: 'FirefoxDriver.prototype.executeScript'}]},
@ -71,7 +71,7 @@ export function main() {
]
}]
};
const perfEvents = convertPerfProfileToEvents(profileData);
var perfEvents = convertPerfProfileToEvents(profileData);
assertEventsEqual(perfEvents, [
{ph: 'X', ts: 1, name: 'script'}, {ph: 'X', ts: 2, name: 'render'},
{ph: 'B', ts: 5, name: 'script'}, {ph: 'E', ts: 10, name: 'script'}
@ -79,13 +79,13 @@ export function main() {
});
it('should add args to gc events', function() {
const profileData = {threads: [{samples: [{time: 1, frames: [{location: 'forceGC'}]}]}]};
const perfEvents = convertPerfProfileToEvents(profileData);
var profileData = {threads: [{samples: [{time: 1, frames: [{location: 'forceGC'}]}]}]};
var perfEvents = convertPerfProfileToEvents(profileData);
assertEventsEqual(perfEvents, [{ph: 'X', ts: 1, name: 'gc', args: {usedHeapSize: 0}}]);
});
it('should skip unknown events', function() {
const profileData = {
var profileData = {
threads: [{
samples: [
{time: 1, frames: [{location: 'FirefoxDriver.prototype.executeScript'}]},
@ -93,7 +93,7 @@ export function main() {
]
}]
};
const perfEvents = convertPerfProfileToEvents(profileData);
var perfEvents = convertPerfProfileToEvents(profileData);
assertEventsEqual(perfEvents, [{ph: 'X', ts: 1, name: 'script'}]);
});
});

View File

@ -6,10 +6,8 @@
* found in the LICENSE file at https://angular.io/license
*/
import {$, browser} from 'protractor';
const benchpress = require('../../index.js');
const runner = new benchpress.Runner([
var benchpress = require('../../index.js');
var runner = new benchpress.Runner([
// use protractor as Webdriver client
benchpress.SeleniumWebDriverAdapter.PROTRACTOR_PROVIDERS,
// use RegressionSlopeValidator to validate samples

View File

@ -6,12 +6,9 @@
* found in the LICENSE file at https://angular.io/license
*/
/* tslint:disable:no-console */
import {browser} from 'protractor';
const assertEventsContainsName = function(events: any[], eventName: string) {
let found = false;
for (let i = 0; i < events.length; ++i) {
var assertEventsContainsName = function(events: any[], eventName: string) {
var found = false;
for (var i = 0; i < events.length; ++i) {
if (events[i].name == eventName) {
found = true;
break;
@ -21,7 +18,7 @@ const assertEventsContainsName = function(events: any[], eventName: string) {
};
describe('firefox extension', function() {
const TEST_URL = 'http://localhost:8001/playground/src/hello_world/index.html';
var TEST_URL = 'http://localhost:8001/playground/src/hello_world/index.html';
it('should measure performance', function() {
browser.sleep(3000); // wait for extension to load

View File

@ -11,12 +11,12 @@ import {Metric, MultiMetric, ReflectiveInjector} from '../../index';
export function main() {
function createMetric(ids: any[]) {
const m = ReflectiveInjector
.resolveAndCreate([
ids.map(id => ({provide: id, useValue: new MockMetric(id)})),
MultiMetric.provideWith(ids)
])
.get(MultiMetric);
var m = ReflectiveInjector
.resolveAndCreate([
ids.map(id => ({provide: id, useValue: new MockMetric(id)})),
MultiMetric.provideWith(ids)
])
.get(MultiMetric);
return Promise.resolve(m);
}
@ -56,13 +56,13 @@ class MockMetric extends Metric {
beginMeasure(): Promise<string> { return Promise.resolve(`${this._id}_beginMeasure`); }
endMeasure(restart: boolean): Promise<{[key: string]: any}> {
const result: {[key: string]: any} = {};
var result: {[key: string]: any} = {};
result[this._id] = {'restart': restart};
return Promise.resolve(result);
}
describe(): {[key: string]: string} {
const result: {[key: string]: string} = {};
var result: {[key: string]: string} = {};
result[this._id] = 'describe';
return result;
}

View File

@ -14,8 +14,8 @@ import {isPresent} from '../../src/facade/lang';
import {TraceEventFactory} from '../trace_event_factory';
export function main() {
let commandLog: any[];
const eventFactory = new TraceEventFactory('timeline', 'pid0');
var commandLog: any[];
var eventFactory = new TraceEventFactory('timeline', 'pid0');
function createMetric(
perfLogs: PerfLogEvent[], perfLogFeatures: PerfLogFeatures,
@ -34,7 +34,7 @@ export function main() {
if (!microMetrics) {
microMetrics = {};
}
const providers: Provider[] = [
var providers: Provider[] = [
Options.DEFAULT_PROVIDERS, PerflogMetric.PROVIDERS,
{provide: Options.MICRO_METRICS, useValue: microMetrics}, {
provide: PerflogMetric.SET_TIMEOUT,
@ -66,7 +66,7 @@ export function main() {
describe('perflog metric', () => {
function sortedKeys(stringMap: {[key: string]: any}) {
const res: string[] = [];
var res: string[] = [];
res.push(...Object.keys(stringMap));
res.sort();
return res;
@ -102,15 +102,15 @@ export function main() {
});
it('should describe itself based on micro metrics', () => {
const description =
var description =
createMetric([[]], null, {microMetrics: {'myMicroMetric': 'someDesc'}}).describe();
expect(description['myMicroMetric']).toEqual('someDesc');
});
it('should describe itself if frame capture is requested and available', () => {
const description = createMetric([[]], new PerfLogFeatures({frameCapture: true}), {
captureFrames: true
}).describe();
var description = createMetric([[]], new PerfLogFeatures({frameCapture: true}), {
captureFrames: true
}).describe();
expect(description['frameTime.mean']).not.toContain('WARNING');
expect(description['frameTime.best']).not.toContain('WARNING');
expect(description['frameTime.worst']).not.toContain('WARNING');
@ -118,9 +118,9 @@ export function main() {
});
it('should describe itself if frame capture is requested and not available', () => {
const description = createMetric([[]], new PerfLogFeatures({frameCapture: false}), {
captureFrames: true
}).describe();
var description = createMetric([[]], new PerfLogFeatures({frameCapture: false}), {
captureFrames: true
}).describe();
expect(description['frameTime.mean']).toContain('WARNING');
expect(description['frameTime.best']).toContain('WARNING');
expect(description['frameTime.worst']).toContain('WARNING');
@ -131,7 +131,7 @@ export function main() {
it('should not force gc and mark the timeline',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
const metric = createMetric([[]], null);
var metric = createMetric([[]], null);
metric.beginMeasure().then((_) => {
expect(commandLog).toEqual([['timeBegin', 'benchpress0']]);
@ -141,7 +141,7 @@ export function main() {
it('should force gc and mark the timeline',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
const metric = createMetric([[]], null, {forceGc: true});
var metric = createMetric([[]], null, {forceGc: true});
metric.beginMeasure().then((_) => {
expect(commandLog).toEqual([['gc'], ['timeBegin', 'benchpress0']]);
@ -155,11 +155,11 @@ export function main() {
it('should mark and aggregate events in between the marks',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
const events = [[
var events = [[
eventFactory.markStart('benchpress0', 0), eventFactory.start('script', 4),
eventFactory.end('script', 6), eventFactory.markEnd('benchpress0', 10)
]];
const metric = createMetric(events, null);
var metric = createMetric(events, null);
metric.beginMeasure().then((_) => metric.endMeasure(false)).then((data) => {
expect(commandLog).toEqual([
['timeBegin', 'benchpress0'], ['timeEnd', 'benchpress0', null], 'readPerfLog'
@ -172,13 +172,13 @@ export function main() {
it('should mark and aggregate events since navigationStart',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
const events = [[
var events = [[
eventFactory.markStart('benchpress0', 0), eventFactory.start('script', 4),
eventFactory.end('script', 6), eventFactory.instant('navigationStart', 7),
eventFactory.start('script', 8), eventFactory.end('script', 9),
eventFactory.markEnd('benchpress0', 10)
]];
const metric = createMetric(events, null);
var metric = createMetric(events, null);
metric.beginMeasure().then((_) => metric.endMeasure(false)).then((data) => {
expect(data['scriptTime']).toBe(1);
@ -187,7 +187,7 @@ export function main() {
}));
it('should restart timing', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
const events = [
var events = [
[
eventFactory.markStart('benchpress0', 0),
eventFactory.markEnd('benchpress0', 1),
@ -195,7 +195,7 @@ export function main() {
],
[eventFactory.markEnd('benchpress1', 3)]
];
const metric = createMetric(events, null);
var metric = createMetric(events, null);
metric.beginMeasure()
.then((_) => metric.endMeasure(true))
.then((_) => metric.endMeasure(true))
@ -211,7 +211,7 @@ export function main() {
it('should loop and aggregate until the end mark is present',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
const events = [
var events = [
[eventFactory.markStart('benchpress0', 0), eventFactory.start('script', 1)],
[eventFactory.end('script', 2)],
[
@ -219,7 +219,7 @@ export function main() {
eventFactory.markEnd('benchpress0', 10)
]
];
const metric = createMetric(events, null);
var metric = createMetric(events, null);
metric.beginMeasure().then((_) => metric.endMeasure(false)).then((data) => {
expect(commandLog).toEqual([
['timeBegin', 'benchpress0'], ['timeEnd', 'benchpress0', null], 'readPerfLog',
@ -233,7 +233,7 @@ export function main() {
it('should store events after the end mark for the next call',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
const events = [
var events = [
[
eventFactory.markStart('benchpress0', 0), eventFactory.markEnd('benchpress0', 1),
eventFactory.markStart('benchpress1', 1), eventFactory.start('script', 1),
@ -244,7 +244,7 @@ export function main() {
eventFactory.markEnd('benchpress1', 6)
]
];
const metric = createMetric(events, null);
var metric = createMetric(events, null);
metric.beginMeasure()
.then((_) => metric.endMeasure(true))
.then((data) => {
@ -263,7 +263,7 @@ export function main() {
}));
describe('with forced gc', () => {
let events: PerfLogEvent[][];
var events: PerfLogEvent[][];
beforeEach(() => {
events = [[
eventFactory.markStart('benchpress0', 0), eventFactory.start('script', 4),
@ -276,7 +276,7 @@ export function main() {
});
it('should measure forced gc', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
const metric = createMetric(events, null, {forceGc: true});
var metric = createMetric(events, null, {forceGc: true});
metric.beginMeasure().then((_) => metric.endMeasure(false)).then((data) => {
expect(commandLog).toEqual([
['gc'], ['timeBegin', 'benchpress0'], ['timeEnd', 'benchpress0', 'benchpress1'],
@ -291,7 +291,7 @@ export function main() {
it('should restart after the forced gc if needed',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
const metric = createMetric(events, null, {forceGc: true});
var metric = createMetric(events, null, {forceGc: true});
metric.beginMeasure().then((_) => metric.endMeasure(true)).then((data) => {
expect(commandLog[5]).toEqual(['timeEnd', 'benchpress1', 'benchpress2']);
@ -313,7 +313,7 @@ export function main() {
} = {}) {
events.unshift(eventFactory.markStart('benchpress0', 0));
events.push(eventFactory.markEnd('benchpress0', 10));
const metric = createMetric([events], null, {
var metric = createMetric([events], null, {
microMetrics: microMetrics,
captureFrames: captureFrames,
receivedData: receivedData,
@ -502,8 +502,8 @@ export function main() {
it('should ignore events from different processed as the start mark',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
const otherProcessEventFactory = new TraceEventFactory('timeline', 'pid1');
const metric = createMetric(
var otherProcessEventFactory = new TraceEventFactory('timeline', 'pid1');
var metric = createMetric(
[[
eventFactory.markStart('benchpress0', 0), eventFactory.start('script', 0, null),
eventFactory.end('script', 5, null),
@ -685,7 +685,7 @@ class MockDriverExtension extends WebDriverExtension {
readPerfLog(): Promise<any> {
this._commandLog.push('readPerfLog');
if (this._perfLogs.length > 0) {
const next = this._perfLogs[0];
var next = this._perfLogs[0];
this._perfLogs.shift();
return Promise.resolve(next);
} else {

View File

@ -12,7 +12,7 @@ import {AsyncTestCompleter, describe, expect, inject, it} from '@angular/core/te
import {Options, PerfLogEvent, PerfLogFeatures, UserMetric, WebDriverAdapter} from '../../index';
export function main() {
let wdAdapter: MockDriverAdapter;
var wdAdapter: MockDriverAdapter;
function createMetric(
perfLogs: PerfLogEvent[], perfLogFeatures: PerfLogFeatures,
@ -25,7 +25,7 @@ export function main() {
userMetrics = {};
}
wdAdapter = new MockDriverAdapter();
const providers: Provider[] = [
var providers: Provider[] = [
Options.DEFAULT_PROVIDERS, UserMetric.PROVIDERS,
{provide: Options.USER_METRICS, useValue: userMetrics},
{provide: WebDriverAdapter, useValue: wdAdapter}
@ -45,7 +45,7 @@ export function main() {
describe('endMeasure', () => {
it('should stop measuring when all properties have numeric values',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
const metric = createMetric(
let metric = createMetric(
[[]], new PerfLogFeatures(),
{userMetrics: {'loadTime': 'time to load', 'content': 'time to see content'}});
metric.beginMeasure()
@ -71,7 +71,7 @@ class MockDriverAdapter extends WebDriverAdapter {
executeScript(script: string): any {
// Just handles `return window.propName` ignores `delete window.propName`.
if (script.indexOf('return window.') == 0) {
const metricName = script.substring('return window.'.length);
let metricName = script.substring('return window.'.length);
return Promise.resolve(this.data[metricName]);
} else if (script.indexOf('delete window.') == 0) {
return Promise.resolve(null);

View File

@ -14,8 +14,8 @@ import {isBlank, isPresent} from '../../src/facade/lang';
export function main() {
describe('console reporter', () => {
let reporter: ConsoleReporter;
let log: string[];
var reporter: ConsoleReporter;
var log: string[];
function createReporter(
{columnWidth = null, sampleId = null, descriptions = null, metrics = null}: {
@ -31,7 +31,7 @@ export function main() {
if (sampleId == null) {
sampleId = 'null';
}
const providers: Provider[] = [
var providers: Provider[] = [
ConsoleReporter.PROVIDERS, {
provide: SampleDescription,
useValue: new SampleDescription(sampleId, descriptions, metrics)

View File

@ -13,7 +13,7 @@ import {isPresent} from '../../src/facade/lang';
export function main() {
describe('file reporter', () => {
let loggedFile: any;
var loggedFile: any;
function createReporter({sampleId, descriptions, metrics, path}: {
sampleId: string,
@ -21,7 +21,7 @@ export function main() {
metrics: {[key: string]: string},
path: string
}) {
const providers = [
var providers = [
JsonFileReporter.PROVIDERS, {
provide: SampleDescription,
useValue: new SampleDescription(sampleId, descriptions, metrics)
@ -49,9 +49,9 @@ export function main() {
.reportSample(
[mv(0, 0, {'a': 3, 'b': 6})],
[mv(0, 0, {'a': 3, 'b': 6}), mv(1, 1, {'a': 5, 'b': 9})]);
const regExp = /somePath\/someId_\d+\.json/;
var regExp = /somePath\/someId_\d+\.json/;
expect(isPresent(loggedFile['filename'].match(regExp))).toBe(true);
const parsedContent = JSON.parse(loggedFile['content']);
var parsedContent = JSON.parse(loggedFile['content']);
expect(parsedContent).toEqual({
'description': {
'id': 'someId',

View File

@ -12,12 +12,12 @@ import {MeasureValues, MultiReporter, ReflectiveInjector, Reporter} from '../../
export function main() {
function createReporters(ids: any[]) {
const r = ReflectiveInjector
.resolveAndCreate([
ids.map(id => ({provide: id, useValue: new MockReporter(id)})),
MultiReporter.provideWith(ids)
])
.get(MultiReporter);
var r = ReflectiveInjector
.resolveAndCreate([
ids.map(id => ({provide: id, useValue: new MockReporter(id)})),
MultiReporter.provideWith(ids)
])
.get(MultiReporter);
return Promise.resolve(r);
}
@ -25,7 +25,7 @@ export function main() {
it('should reportMeasureValues to all',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
const mv = new MeasureValues(0, new Date(), {});
var mv = new MeasureValues(0, new Date(), {});
createReporters(['m1', 'm2']).then((r) => r.reportMeasureValues(mv)).then((values) => {
expect(values).toEqual([{'id': 'm1', 'values': mv}, {'id': 'm2', 'values': mv}]);
@ -34,9 +34,9 @@ export function main() {
}));
it('should reportSample to call', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
const completeSample =
var completeSample =
[new MeasureValues(0, new Date(), {}), new MeasureValues(1, new Date(), {})];
const validSample = [completeSample[1]];
var validSample = [completeSample[1]];
createReporters(['m1', 'm2'])
.then((r) => r.reportSample(completeSample, validSample))

View File

@ -12,8 +12,8 @@ import {Injector, Metric, Options, ReflectiveInjector, Runner, SampleDescription
export function main() {
describe('runner', () => {
let injector: ReflectiveInjector;
let runner: Runner;
var injector: ReflectiveInjector;
var runner: Runner;
function createRunner(defaultProviders: any[] = null): Runner {
if (!defaultProviders) {
@ -76,7 +76,7 @@ export function main() {
it('should provide Options.EXECUTE',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
const execute = () => {};
var execute = () => {};
createRunner().sample({id: 'someId', execute: execute}).then((_) => {
expect(injector.get(Options.EXECUTE)).toEqual(execute);
async.done();
@ -85,7 +85,7 @@ export function main() {
it('should provide Options.PREPARE',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
const prepare = () => {};
var prepare = () => {};
createRunner().sample({id: 'someId', prepare: prepare}).then((_) => {
expect(injector.get(Options.PREPARE)).toEqual(prepare);
async.done();

View File

@ -12,10 +12,10 @@ import {MeasureValues, Metric, Options, ReflectiveInjector, Reporter, Sampler, V
import {isBlank, isPresent} from '../src/facade/lang';
export function main() {
const EMPTY_EXECUTE = () => {};
var EMPTY_EXECUTE = () => {};
describe('sampler', () => {
let sampler: Sampler;
var sampler: Sampler;
function createSampler({driver, metric, reporter, validator, prepare, execute}: {
driver?: any,
@ -25,7 +25,7 @@ export function main() {
prepare?: any,
execute?: any
} = {}) {
let time = 1000;
var time = 1000;
if (!metric) {
metric = new MockMetric([]);
}
@ -35,7 +35,7 @@ export function main() {
if (isBlank(driver)) {
driver = new MockDriverAdapter([]);
}
const providers = [
var providers = [
Options.DEFAULT_PROVIDERS, Sampler.PROVIDERS, {provide: Metric, useValue: metric},
{provide: Reporter, useValue: reporter}, {provide: WebDriverAdapter, useValue: driver},
{provide: Options.EXECUTE, useValue: execute}, {provide: Validator, useValue: validator},
@ -50,10 +50,10 @@ export function main() {
it('should call the prepare and execute callbacks using WebDriverAdapter.waitFor',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
const log: any[] = [];
let count = 0;
const driver = new MockDriverAdapter([], (callback: Function) => {
const result = callback();
var log: any[] = [];
var count = 0;
var driver = new MockDriverAdapter([], (callback: Function) => {
var result = callback();
log.push(result);
return Promise.resolve(result);
});
@ -73,8 +73,8 @@ export function main() {
it('should call prepare, beginMeasure, execute, endMeasure for every iteration',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
let workCount = 0;
const log: any[] = [];
var workCount = 0;
var log: any[] = [];
createSampler({
metric: createCountingMetric(log),
validator: createCountingValidator(2),
@ -98,8 +98,8 @@ export function main() {
it('should call execute, endMeasure for every iteration if there is no prepare callback',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
const log: any[] = [];
let workCount = 0;
var log: any[] = [];
var workCount = 0;
createSampler({
metric: createCountingMetric(log),
validator: createCountingValidator(2),
@ -120,14 +120,14 @@ export function main() {
it('should only collect metrics for execute and ignore metrics from prepare',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
let scriptTime = 0;
let iterationCount = 1;
var scriptTime = 0;
var iterationCount = 1;
createSampler({
validator: createCountingValidator(2),
metric: new MockMetric(
[],
() => {
const result = Promise.resolve({'script': scriptTime});
var result = Promise.resolve({'script': scriptTime});
scriptTime = 0;
return result;
}),
@ -147,8 +147,8 @@ export function main() {
it('should call the validator for every execution and store the valid sample',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
const log: any[] = [];
const validSample = [mv(null, null, {})];
var log: any[] = [];
var validSample = [mv(null, null, {})];
createSampler({
metric: createCountingMetric(),
@ -174,8 +174,8 @@ export function main() {
it('should report the metric values',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
const log: any[] = [];
const validSample = [mv(null, null, {})];
var log: any[] = [];
var validSample = [mv(null, null, {})];
createSampler({
validator: createCountingValidator(2, validSample),
metric: createCountingMetric(),
@ -220,7 +220,7 @@ function createCountingValidator(
}
function createCountingMetric(log: any[] = []) {
let scriptTime = 0;
var scriptTime = 0;
return new MockMetric(log, () => ({'script': scriptTime++}));
}
@ -239,8 +239,7 @@ class MockDriverAdapter extends WebDriverAdapter {
class MockValidator extends Validator {
constructor(private _log: any[] = [], private _validate: Function = null) { super(); }
validate(completeSample: MeasureValues[]): MeasureValues[] {
const stableSample =
isPresent(this._validate) ? this._validate(completeSample) : completeSample;
var stableSample = isPresent(this._validate) ? this._validate(completeSample) : completeSample;
this._log.push(['validate', completeSample, stableSample]);
return stableSample;
}
@ -253,7 +252,7 @@ class MockMetric extends Metric {
return Promise.resolve(null);
}
endMeasure(restart: boolean) {
const measureValues = isPresent(this._endMeasure) ? this._endMeasure() : {};
var measureValues = isPresent(this._endMeasure) ? this._endMeasure() : {};
this._log.push(['endMeasure', restart, measureValues]);
return Promise.resolve(measureValues);
}

View File

@ -13,7 +13,7 @@ export class TraceEventFactory {
constructor(private _cat: string, private _pid: string) {}
create(ph: any, name: string, time: number, args: any = null) {
const res:
var res:
PerfLogEvent = {'name': name, 'cat': this._cat, 'ph': ph, 'ts': time, 'pid': this._pid};
if (isPresent(args)) {
res['args'] = args;
@ -34,7 +34,7 @@ export class TraceEventFactory {
}
complete(name: string, time: number, duration: number, args: any = null) {
const res = this.create('X', name, time, args);
var res = this.create('X', name, time, args);
res['dur'] = duration;
return res;
}

View File

@ -12,7 +12,7 @@ import {MeasureValues, ReflectiveInjector, RegressionSlopeValidator} from '../..
export function main() {
describe('regression slope validator', () => {
let validator: RegressionSlopeValidator;
var validator: RegressionSlopeValidator;
function createValidator({size, metric}: {size: number, metric: string}) {
validator = ReflectiveInjector
@ -42,14 +42,14 @@ export function main() {
it('should return the last sampleSize runs when the regression slope is ==0', () => {
createValidator({size: 2, metric: 'script'});
const sample = [mv(0, 0, {'script': 1}), mv(1, 1, {'script': 1}), mv(2, 2, {'script': 1})];
var sample = [mv(0, 0, {'script': 1}), mv(1, 1, {'script': 1}), mv(2, 2, {'script': 1})];
expect(validator.validate(sample.slice(0, 2))).toEqual(sample.slice(0, 2));
expect(validator.validate(sample)).toEqual(sample.slice(1, 3));
});
it('should return the last sampleSize runs when the regression slope is >0', () => {
createValidator({size: 2, metric: 'script'});
const sample = [mv(0, 0, {'script': 1}), mv(1, 1, {'script': 2}), mv(2, 2, {'script': 3})];
var sample = [mv(0, 0, {'script': 1}), mv(1, 1, {'script': 2}), mv(2, 2, {'script': 3})];
expect(validator.validate(sample.slice(0, 2))).toEqual(sample.slice(0, 2));
expect(validator.validate(sample)).toEqual(sample.slice(1, 3));
});

View File

@ -12,7 +12,7 @@ import {MeasureValues, ReflectiveInjector, SizeValidator} from '../../index';
export function main() {
describe('size validator', () => {
let validator: SizeValidator;
var validator: SizeValidator;
function createValidator(size: number) {
validator =
@ -35,7 +35,7 @@ export function main() {
it('should return the last sampleSize runs when it has at least the given size', () => {
createValidator(2);
const sample = [mv(0, 0, {'a': 1}), mv(1, 1, {'b': 2}), mv(2, 2, {'c': 3})];
var sample = [mv(0, 0, {'a': 1}), mv(1, 1, {'b': 2}), mv(2, 2, {'c': 3})];
expect(validator.validate(sample.slice(0, 2))).toEqual(sample.slice(0, 2));
expect(validator.validate(sample)).toEqual(sample.slice(1, 3));
});

View File

@ -14,23 +14,23 @@ import {TraceEventFactory} from '../trace_event_factory';
export function main() {
describe('chrome driver extension', () => {
const CHROME45_USER_AGENT =
var CHROME45_USER_AGENT =
'"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2499.0 Safari/537.36"';
let log: any[];
let extension: ChromeDriverExtension;
var log: any[];
var extension: ChromeDriverExtension;
const blinkEvents = new TraceEventFactory('blink.console', 'pid0');
const v8Events = new TraceEventFactory('v8', 'pid0');
const v8EventsOtherProcess = new TraceEventFactory('v8', 'pid1');
const chromeTimelineEvents =
var blinkEvents = new TraceEventFactory('blink.console', 'pid0');
var v8Events = new TraceEventFactory('v8', 'pid0');
var v8EventsOtherProcess = new TraceEventFactory('v8', 'pid1');
var chromeTimelineEvents =
new TraceEventFactory('disabled-by-default-devtools.timeline', 'pid0');
const chrome45TimelineEvents = new TraceEventFactory('devtools.timeline', 'pid0');
const chromeTimelineV8Events = new TraceEventFactory('devtools.timeline,v8', 'pid0');
const chromeBlinkTimelineEvents = new TraceEventFactory('blink,devtools.timeline', 'pid0');
const chromeBlinkUserTimingEvents = new TraceEventFactory('blink.user_timing', 'pid0');
const benchmarkEvents = new TraceEventFactory('benchmark', 'pid0');
const normEvents = new TraceEventFactory('timeline', 'pid0');
var chrome45TimelineEvents = new TraceEventFactory('devtools.timeline', 'pid0');
var chromeTimelineV8Events = new TraceEventFactory('devtools.timeline,v8', 'pid0');
var chromeBlinkTimelineEvents = new TraceEventFactory('blink,devtools.timeline', 'pid0');
var chromeBlinkUserTimingEvents = new TraceEventFactory('blink.user_timing', 'pid0');
var benchmarkEvents = new TraceEventFactory('benchmark', 'pid0');
var normEvents = new TraceEventFactory('timeline', 'pid0');
function createExtension(
perfRecords: any[] = null, userAgent: string = null,
@ -101,7 +101,7 @@ export function main() {
it('should normalize "tdur" to "dur"',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
const event: any = chromeTimelineV8Events.create('X', 'FunctionCall', 1100, null);
var event: any = chromeTimelineV8Events.create('X', 'FunctionCall', 1100, null);
event['tdur'] = 5500;
createExtension([event]).readPerfLog().then((events) => {
expect(events).toEqual([

View File

@ -13,10 +13,10 @@ import {TraceEventFactory} from '../trace_event_factory';
export function main() {
describe('ios driver extension', () => {
let log: any[];
let extension: IOsDriverExtension;
var log: any[];
var extension: IOsDriverExtension;
const normEvents = new TraceEventFactory('timeline', 'pid0');
var normEvents = new TraceEventFactory('timeline', 'pid0');
function createExtension(perfRecords: any[] = null): WebDriverExtension {
if (!perfRecords) {

View File

@ -11,6 +11,9 @@
* @description
* Entry point for all public APIs of the common package.
*/
export * from './src/common';
export * from './src/location';
export {NgLocalization} from './src/localization';
export {CommonModule} from './src/common_module';
// This file only reexports content of the `src` folder. Keep it that way.
export {NgClass, NgFor, NgIf, NgPlural, NgPluralCase, NgStyle, NgSwitch, NgSwitchCase, NgSwitchDefault, NgTemplateOutlet} from './src/directives/index';
export {AsyncPipe, DatePipe, I18nPluralPipe, I18nSelectPipe, JsonPipe, LowerCasePipe, CurrencyPipe, DecimalPipe, PercentPipe, SlicePipe, UpperCasePipe} from './src/pipes/index';

View File

@ -1,20 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
/**
* @module
* @description
* Entry point for all public APIs of the common package.
*/
export * from './location/index';
export {NgLocalization} from './localization';
export {CommonModule} from './common_module';
export {NgClass, NgFor, NgIf, NgPlural, NgPluralCase, NgStyle, NgSwitch, NgSwitchCase, NgSwitchDefault, NgTemplateOutlet} from './directives/index';
export {AsyncPipe, DatePipe, I18nPluralPipe, I18nSelectPipe, JsonPipe, LowerCasePipe, CurrencyPipe, DecimalPipe, PercentPipe, SlicePipe, UpperCasePipe} from './pipes/index';
export {VERSION} from './version';
export {Version} from '@angular/core';

View File

@ -9,7 +9,7 @@
import {CollectionChangeRecord, Directive, DoCheck, ElementRef, Input, IterableDiffer, IterableDiffers, KeyValueChangeRecord, KeyValueDiffer, KeyValueDiffers, Renderer} from '@angular/core';
import {isListLikeIterable} from '../facade/collection';
import {isPresent, stringify} from '../facade/lang';
import {isPresent} from '../facade/lang';
/**
* @ngModule CommonModule
@ -108,14 +108,8 @@ export class NgClass implements DoCheck {
}
private _applyIterableChanges(changes: any): void {
changes.forEachAddedItem((record: CollectionChangeRecord) => {
if (typeof record.item === 'string') {
this._toggleClass(record.item, true);
} else {
throw new Error(
`NgClass can only toggle CSS classes expressed as strings, got ${stringify(record.item)}`);
}
});
changes.forEachAddedItem(
(record: CollectionChangeRecord) => this._toggleClass(record.item, true));
changes.forEachRemovedItem(
(record: CollectionChangeRecord) => this._toggleClass(record.item, false));

View File

@ -150,13 +150,13 @@ export class NgFor implements DoCheck, OnChanges {
}
for (let i = 0, ilen = this._viewContainer.length; i < ilen; i++) {
const viewRef = <EmbeddedViewRef<NgForRow>>this._viewContainer.get(i);
let viewRef = <EmbeddedViewRef<NgForRow>>this._viewContainer.get(i);
viewRef.context.index = i;
viewRef.context.count = ilen;
}
changes.forEachIdentityChange((record: any) => {
const viewRef = <EmbeddedViewRef<NgForRow>>this._viewContainer.get(record.currentIndex);
let viewRef = <EmbeddedViewRef<NgForRow>>this._viewContainer.get(record.currentIndex);
viewRef.context.$implicit = record.item;
});
}

View File

@ -25,7 +25,7 @@ import {Directive, DoCheck, ElementRef, Input, KeyValueChangeRecord, KeyValueDif
* @description
*
* The styles are updated according to the value of the expression evaluation:
* - keys are style names with an optional `.<unit>` suffix (ie 'top.px', 'font-style.em'),
* - keys are style names with an option `.<unit>` suffix (ie 'top.px', 'font-style.em'),
* - values are the values assigned to those properties (expressed in the given unit).
*
* @stable

View File

@ -6,31 +6,19 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Directive, DoCheck, Host, Input, TemplateRef, ViewContainerRef} from '@angular/core';
import {Directive, Host, Input, TemplateRef, ViewContainerRef} from '@angular/core';
import {ListWrapper} from '../facade/collection';
const _CASE_DEFAULT = {};
export class SwitchView {
private _created = false;
constructor(
private _viewContainerRef: ViewContainerRef, private _templateRef: TemplateRef<Object>) {}
create(): void {
this._created = true;
this._viewContainerRef.createEmbeddedView(this._templateRef);
}
create(): void { this._viewContainerRef.createEmbeddedView(this._templateRef); }
destroy(): void {
this._created = false;
this._viewContainerRef.clear();
}
enforceState(created: boolean) {
if (created && !this._created) {
this.create();
} else if (!created && this._created) {
this.destroy();
}
}
destroy(): void { this._viewContainerRef.clear(); }
}
/**
@ -76,52 +64,92 @@ export class SwitchView {
*/
@Directive({selector: '[ngSwitch]'})
export class NgSwitch {
private _defaultViews: SwitchView[];
private _defaultUsed = false;
private _caseCount = 0;
private _lastCaseCheckIndex = 0;
private _lastCasesMatched = false;
private _ngSwitch: any;
private _switchValue: any;
private _useDefault: boolean = false;
private _valueViews = new Map<any, SwitchView[]>();
private _activeViews: SwitchView[] = [];
@Input()
set ngSwitch(newValue: any) {
this._ngSwitch = newValue;
if (this._caseCount === 0) {
this._updateDefaultCases(true);
}
}
set ngSwitch(value: any) {
// Set of views to display for this value
let views = this._valueViews.get(value);
/** @internal */
_addCase(): number { return this._caseCount++; }
/** @internal */
_addDefault(view: SwitchView) {
if (!this._defaultViews) {
this._defaultViews = [];
}
this._defaultViews.push(view);
}
/** @internal */
_matchCase(value: any): boolean {
const matched = value == this._ngSwitch;
this._lastCasesMatched = this._lastCasesMatched || matched;
this._lastCaseCheckIndex++;
if (this._lastCaseCheckIndex === this._caseCount) {
this._updateDefaultCases(!this._lastCasesMatched);
this._lastCaseCheckIndex = 0;
this._lastCasesMatched = false;
}
return matched;
}
private _updateDefaultCases(useDefault: boolean) {
if (this._defaultViews && useDefault !== this._defaultUsed) {
this._defaultUsed = useDefault;
for (let i = 0; i < this._defaultViews.length; i++) {
const defaultView = this._defaultViews[i];
defaultView.enforceState(useDefault);
if (views) {
this._useDefault = false;
} else {
// No view to display for the current value -> default case
// Nothing to do if the default case was already active
if (this._useDefault) {
return;
}
this._useDefault = true;
views = this._valueViews.get(_CASE_DEFAULT);
}
this._emptyAllActiveViews();
this._activateViews(views);
this._switchValue = value;
}
/** @internal */
_onCaseValueChanged(oldCase: any, newCase: any, view: SwitchView): void {
this._deregisterView(oldCase, view);
this._registerView(newCase, view);
if (oldCase === this._switchValue) {
view.destroy();
ListWrapper.remove(this._activeViews, view);
} else if (newCase === this._switchValue) {
if (this._useDefault) {
this._useDefault = false;
this._emptyAllActiveViews();
}
view.create();
this._activeViews.push(view);
}
// Switch to default when there is no more active ViewContainers
if (this._activeViews.length === 0 && !this._useDefault) {
this._useDefault = true;
this._activateViews(this._valueViews.get(_CASE_DEFAULT));
}
}
private _emptyAllActiveViews(): void {
const activeContainers = this._activeViews;
for (var i = 0; i < activeContainers.length; i++) {
activeContainers[i].destroy();
}
this._activeViews = [];
}
private _activateViews(views?: SwitchView[]): void {
if (views) {
for (var i = 0; i < views.length; i++) {
views[i].create();
}
this._activeViews = views;
}
}
/** @internal */
_registerView(value: any, view: SwitchView): void {
let views = this._valueViews.get(value);
if (!views) {
views = [];
this._valueViews.set(value, views);
}
views.push(view);
}
private _deregisterView(value: any, view: SwitchView): void {
// `_CASE_DEFAULT` is used a marker for non-registered cases
if (value === _CASE_DEFAULT) return;
const views = this._valueViews.get(value);
if (views.length == 1) {
this._valueViews.delete(value);
} else {
ListWrapper.remove(views, view);
}
}
}
@ -151,20 +179,24 @@ export class NgSwitch {
* @stable
*/
@Directive({selector: '[ngSwitchCase]'})
export class NgSwitchCase implements DoCheck {
export class NgSwitchCase {
// `_CASE_DEFAULT` is used as a marker for a not yet initialized value
private _value: any = _CASE_DEFAULT;
private _view: SwitchView;
@Input()
ngSwitchCase: any;
private _switch: NgSwitch;
constructor(
viewContainer: ViewContainerRef, templateRef: TemplateRef<Object>,
@Host() private ngSwitch: NgSwitch) {
ngSwitch._addCase();
@Host() ngSwitch: NgSwitch) {
this._switch = ngSwitch;
this._view = new SwitchView(viewContainer, templateRef);
}
ngDoCheck() { this._view.enforceState(this.ngSwitch._matchCase(this.ngSwitchCase)); }
@Input()
set ngSwitchCase(value: any) {
this._switch._onCaseValueChanged(this._value, value, this._view);
this._value = value;
}
}
/**
@ -194,7 +226,7 @@ export class NgSwitchCase implements DoCheck {
export class NgSwitchDefault {
constructor(
viewContainer: ViewContainerRef, templateRef: TemplateRef<Object>,
@Host() ngSwitch: NgSwitch) {
ngSwitch._addDefault(new SwitchView(viewContainer, templateRef));
@Host() sswitch: NgSwitch) {
sswitch._registerView(_CASE_DEFAULT, new SwitchView(viewContainer, templateRef));
}
}

View File

@ -23,23 +23,9 @@ export abstract class NgLocalization { abstract getPluralCategory(value: any): s
*/
export function getPluralCategory(
value: number, cases: string[], ngLocalization: NgLocalization): string {
let key = `=${value}`;
const nbCase = `=${value}`;
if (cases.indexOf(key) > -1) {
return key;
}
key = ngLocalization.getPluralCategory(value);
if (cases.indexOf(key) > -1) {
return key;
}
if (cases.indexOf('other') > -1) {
return 'other';
}
throw new Error(`No plural message found for value "${value}"`);
return cases.indexOf(nbCase) > -1 ? nbCase : ngLocalization.getPluralCategory(value);
}
/**

View File

@ -0,0 +1,13 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
export * from './location/platform_location';
export * from './location/location_strategy';
export * from './location/hash_location_strategy';
export * from './location/path_location_strategy';
export * from './location/location';

View File

@ -17,8 +17,6 @@ import {LocationChangeListener, PlatformLocation} from './platform_location';
/**
* @whatItDoes Use URL hash for storing application location data.
* @description
* `HashLocationStrategy` is a {@link LocationStrategy} used to configure the
* {@link Location} service to represent its state in the
* [hash fragment](https://en.wikipedia.org/wiki/Uniform_Resource_Locator#Syntax)
@ -29,7 +27,18 @@ import {LocationChangeListener, PlatformLocation} from './platform_location';
*
* ### Example
*
* {@example common/location/ts/hash_location_component.ts region='LocationComponent'}
* ```
* import {Component, NgModule} from '@angular/core';
* import {
* LocationStrategy,
* HashLocationStrategy
* } from '@angular/common';
*
* @NgModule({
* providers: [{provide: LocationStrategy, useClass: HashLocationStrategy}]
* })
* class AppModule {}
* ```
*
* @stable
*/
@ -55,19 +64,19 @@ export class HashLocationStrategy extends LocationStrategy {
path(includeHash: boolean = false): string {
// the hash value is always prefixed with a `#`
// and if it is empty then it will stay empty
let path = this._platformLocation.hash;
var path = this._platformLocation.hash;
if (!isPresent(path)) path = '#';
return path.length > 0 ? path.substring(1) : path;
}
prepareExternalUrl(internal: string): string {
const url = Location.joinWithSlash(this._baseHref, internal);
var url = Location.joinWithSlash(this._baseHref, internal);
return url.length > 0 ? ('#' + url) : url;
}
pushState(state: any, title: string, path: string, queryParams: string) {
let url = this.prepareExternalUrl(path + Location.normalizeQueryParams(queryParams));
var url = this.prepareExternalUrl(path + Location.normalizeQueryParams(queryParams));
if (url.length == 0) {
url = this._platformLocation.pathname;
}
@ -75,7 +84,7 @@ export class HashLocationStrategy extends LocationStrategy {
}
replaceState(state: any, title: string, path: string, queryParams: string) {
let url = this.prepareExternalUrl(path + Location.normalizeQueryParams(queryParams));
var url = this.prepareExternalUrl(path + Location.normalizeQueryParams(queryParams));
if (url.length == 0) {
url = this._platformLocation.pathname;
}

View File

@ -1,13 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
export * from './platform_location';
export * from './location_strategy';
export * from './hash_location_strategy';
export * from './path_location_strategy';
export * from './location';

View File

@ -12,8 +12,7 @@ import {LocationStrategy} from './location_strategy';
/**
* @whatItDoes `Location` is a service that applications can use to interact with a browser's URL.
* @description
* `Location` is a service that applications can use to interact with a browser's URL.
* Depending on which {@link LocationStrategy} is used, `Location` will either persist
* to the URL's path or the URL's hash segment.
*
@ -29,7 +28,19 @@ import {LocationStrategy} from './location_strategy';
* - `/my/app/user/123/` **is not** normalized
*
* ### Example
* {@example common/location/ts/path_location_component.ts region='LocationComponent'}
*
* ```
* import {Component} from '@angular/core';
* import {Location} from '@angular/common';
*
* @Component({selector: 'app-component'})
* class AppCmp {
* constructor(location: Location) {
* location.go('/foo');
* }
* }
* ```
*
* @stable
*/
@Injectable()
@ -85,7 +96,7 @@ export class Location {
* used, or the `APP_BASE_HREF` if the `PathLocationStrategy` is in use.
*/
prepareExternalUrl(url: string): string {
if (url && url[0] !== '/') {
if (url.length > 0 && !url.startsWith('/')) {
url = '/' + url;
}
return this._platformStrategy.prepareExternalUrl(url);
@ -132,7 +143,7 @@ export class Location {
* is.
*/
public static normalizeQueryParams(params: string): string {
return params && params[0] !== '?' ? '?' + params : params;
return (params.length > 0 && params.substring(0, 1) != '?') ? ('?' + params) : params;
}
/**
@ -145,7 +156,7 @@ export class Location {
if (end.length == 0) {
return start;
}
let slashes = 0;
var slashes = 0;
if (start.endsWith('/')) {
slashes++;
}
@ -164,13 +175,25 @@ export class Location {
/**
* If url has a trailing slash, remove it, otherwise return url as is.
*/
public static stripTrailingSlash(url: string): string { return url.replace(/\/$/, ''); }
public static stripTrailingSlash(url: string): string {
if (/\/$/g.test(url)) {
url = url.substring(0, url.length - 1);
}
return url;
}
}
function _stripBaseHref(baseHref: string, url: string): string {
return baseHref && url.startsWith(baseHref) ? url.substring(baseHref.length) : url;
if (baseHref.length > 0 && url.startsWith(baseHref)) {
return url.substring(baseHref.length);
}
return url;
}
function _stripIndexHtml(url: string): string {
return url.replace(/\/index.html$/, '');
if (/\/index.html$/g.test(url)) {
// '/index.html'.length == 11
return url.substring(0, url.length - 11);
}
return url;
}

View File

@ -12,7 +12,7 @@ import {LocationChangeListener} from './platform_location';
/**
* `LocationStrategy` is responsible for representing and reading route state
* from the browser's URL. Angular provides two strategies:
* {@link HashLocationStrategy} and {@link PathLocationStrategy}.
* {@link HashLocationStrategy} and {@link PathLocationStrategy} (default).
*
* This is used under the hood of the {@link Location} service.
*

View File

@ -17,13 +17,14 @@ import {LocationChangeListener, PlatformLocation} from './platform_location';
/**
* @whatItDoes Use URL for storing application location data.
* @description
* `PathLocationStrategy` is a {@link LocationStrategy} used to configure the
* {@link Location} service to represent its state in the
* [path](https://en.wikipedia.org/wiki/Uniform_Resource_Locator#Syntax) of the
* browser's URL.
*
* `PathLocationStrategy` is the default binding for {@link LocationStrategy}
* provided in {@link ROUTER_PROVIDERS}.
*
* If you're using `PathLocationStrategy`, you must provide a {@link APP_BASE_HREF}
* or add a base element to the document. This URL prefix that will be preserved
* when generating and recognizing URLs.
@ -36,10 +37,6 @@ import {LocationChangeListener, PlatformLocation} from './platform_location';
* `location.go('/foo')`, the browser's URL will become
* `example.com/my/app/foo`.
*
* ### Example
*
* {@example common/location/ts/path_location_component.ts region='LocationComponent'}
*
* @stable
*/
@Injectable()
@ -82,12 +79,12 @@ export class PathLocationStrategy extends LocationStrategy {
}
pushState(state: any, title: string, url: string, queryParams: string) {
const externalUrl = this.prepareExternalUrl(url + Location.normalizeQueryParams(queryParams));
var externalUrl = this.prepareExternalUrl(url + Location.normalizeQueryParams(queryParams));
this._platformLocation.pushState(state, title, externalUrl);
}
replaceState(state: any, title: string, url: string, queryParams: string) {
const externalUrl = this.prepareExternalUrl(url + Location.normalizeQueryParams(queryParams));
var externalUrl = this.prepareExternalUrl(url + Location.normalizeQueryParams(queryParams));
this._platformLocation.replaceState(state, title, externalUrl);
}

View File

@ -6,6 +6,8 @@
* found in the LICENSE file at https://angular.io/license
*/
export class GeneratedFile {
constructor(public srcFileUrl: string, public genFileUrl: string, public source: string) {}
}
/**
* @module
* @description
* This module provides a set of common Pipes.
*/

View File

@ -59,7 +59,7 @@ const _observableStrategy = new ObservableStrategy();
* {@example common/pipes/ts/async_pipe.ts region='AsyncPipePromise'}
*
* It's also possible to use `async` with Observables. The example below binds the `time` Observable
* to the view. The Observable continuously updates the view with the current time.
* to the view. The Observable continuesly updates the view with the current time.
*
* {@example common/pipes/ts/async_pipe.ts region='AsyncPipeObservable'}
*

View File

@ -7,14 +7,11 @@
*/
import {Inject, LOCALE_ID, Pipe, PipeTransform} from '@angular/core';
import {NumberWrapper, isDate} from '../facade/lang';
import {DateFormatter} from './intl';
import {DateFormatter} from '../facade/intl';
import {NumberWrapper, isBlank, isDate} from '../facade/lang';
import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
/**
* @ngModule CommonModule
* @whatItDoes Formats a date according to locale rules.
@ -36,30 +33,27 @@ import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
* - `'shortTime'`: equivalent to `'jm'` (e.g. `12:05 PM` for `en-US`)
*
*
* | Component | Symbol | Narrow | Short Form | Long Form | Numeric | 2-digit |
* |-----------|:------:|--------|--------------|-------------------|-----------|-----------|
* | era | G | G (A) | GGG (AD) | GGGG (Anno Domini)| - | - |
* | year | y | - | - | - | y (2015) | yy (15) |
* | month | M | L (S) | MMM (Sep) | MMMM (September) | M (9) | MM (09) |
* | day | d | - | - | - | d (3) | dd (03) |
* | weekday | E | E (S) | EEE (Sun) | EEEE (Sunday) | - | - |
* | hour | j | - | - | - | j (13) | jj (13) |
* | hour12 | h | - | - | - | h (1 PM) | hh (01 PM)|
* | hour24 | H | - | - | - | H (13) | HH (13) |
* | minute | m | - | - | - | m (5) | mm (05) |
* | second | s | - | - | - | s (9) | ss (09) |
* | timezone | z | - | - | z (Pacific Standard Time)| - | - |
* | timezone | Z | - | Z (GMT-8:00) | - | - | - |
* | timezone | a | - | a (PM) | - | - | - |
* | Component | Symbol | Short Form | Long Form | Numeric | 2-digit |
* |-----------|:------:|--------------|-------------------|-----------|-----------|
* | era | G | G (AD) | GGGG (Anno Domini)| - | - |
* | year | y | - | - | y (2015) | yy (15) |
* | month | M | MMM (Sep) | MMMM (September) | M (9) | MM (09) |
* | day | d | - | - | d (3) | dd (03) |
* | weekday | E | EEE (Sun) | EEEE (Sunday) | - | - |
* | hour | j | - | - | j (13) | jj (13) |
* | hour12 | h | - | - | h (1 PM) | hh (01 PM)|
* | hour24 | H | - | - | H (13) | HH (13) |
* | minute | m | - | - | m (5) | mm (05) |
* | second | s | - | - | s (9) | ss (09) |
* | timezone | z | - | z (Pacific Standard Time)| - | - |
* | timezone | Z | Z (GMT-8:00) | - | - | - |
* | timezone | a | a (PM) | - | - | - |
*
* In javascript, only the components specified will be respected (not the ordering,
* punctuations, ...) and details of the formatting will be dependent on the locale.
*
* Timezone of the formatted text will be the local system timezone of the end-user's machine.
*
* When the expression is a ISO string without time (e.g. 2016-09-19) the time zone offset is not
* applied and the formatted text will have the same day, month and year of the expression.
*
* WARNINGS:
* - this pipe is marked as pure hence it will not be re-evaluated when the input is mutated.
* Instead users should treat the date as an immutable object and change the reference when the
@ -101,42 +95,22 @@ export class DatePipe implements PipeTransform {
constructor(@Inject(LOCALE_ID) private _locale: string) {}
transform(value: any, pattern: string = 'mediumDate'): string {
let date: Date;
if (isBlank(value)) return null;
if (typeof value === 'string') {
value = value.trim();
}
if (isDate(value)) {
date = value;
} else if (NumberWrapper.isNumeric(value)) {
date = new Date(parseFloat(value));
} else if (typeof value === 'string' && /^(\d{4}-\d{1,2}-\d{1,2})$/.test(value)) {
/**
* For ISO Strings without time the day, month and year must be extracted from the ISO String
* before Date creation to avoid time offset and errors in the new Date.
* If we only replace '-' with ',' in the ISO String ("2015,01,01"), and try to create a new
* date, some browsers (e.g. IE 9) will throw an invalid Date error
* If we leave the '-' ("2015-01-01") and try to create a new Date("2015-01-01") the timeoffset
* is applied
* Note: ISO months are 0 for January, 1 for February, ...
*/
const [y, m, d] = value.split('-').map((val: string) => parseInt(val, 10));
date = new Date(y, m - 1, d);
} else {
date = new Date(value);
}
if (!isDate(date)) {
if (!this.supports(value)) {
throw new InvalidPipeArgumentError(DatePipe, value);
}
return DateFormatter.format(date, this._locale, DatePipe._ALIASES[pattern] || pattern);
if (NumberWrapper.isNumeric(value)) {
value = parseFloat(value);
}
return DateFormatter.format(
new Date(value), this._locale, DatePipe._ALIASES[pattern] || pattern);
}
private supports(obj: any): boolean {
return isDate(obj) || NumberWrapper.isNumeric(obj) ||
(typeof obj === 'string' && isDate(new Date(obj)));
}
}
function isBlank(obj: any): boolean {
return obj == null || obj === '';
}

View File

@ -7,6 +7,7 @@
*/
import {Pipe, PipeTransform} from '@angular/core';
import {isBlank} from '../facade/lang';
import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
/**
@ -15,10 +16,9 @@ import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
* @howToUse `expression | i18nSelect:mapping`
* @description
*
* Where `mapping` is an object that indicates the text that should be displayed
* Where:
* - `mapping`: is an object that indicates the text that should be displayed
* for different values of the provided `expression`.
* If none of the keys of the mapping match the value of the `expression`, then the content
* of the `other` key is returned when present, otherwise an empty string is returned.
*
* ## Example
*
@ -29,20 +29,12 @@ import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
@Pipe({name: 'i18nSelect', pure: true})
export class I18nSelectPipe implements PipeTransform {
transform(value: string, mapping: {[key: string]: string}): string {
if (value == null) return '';
if (isBlank(value)) return '';
if (typeof mapping !== 'object' || typeof value !== 'string') {
if (typeof mapping !== 'object' || mapping === null) {
throw new InvalidPipeArgumentError(I18nSelectPipe, mapping);
}
if (mapping.hasOwnProperty(value)) {
return mapping[value];
}
if (mapping.hasOwnProperty('other')) {
return mapping['other'];
}
return '';
return mapping[value] || '';
}
}

View File

@ -1,226 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
export enum NumberFormatStyle {
Decimal,
Percent,
Currency,
}
export class NumberFormatter {
static format(
num: number, locale: string, style: NumberFormatStyle,
{minimumIntegerDigits, minimumFractionDigits, maximumFractionDigits, currency,
currencyAsSymbol = false}: {
minimumIntegerDigits?: number,
minimumFractionDigits?: number,
maximumFractionDigits?: number,
currency?: string,
currencyAsSymbol?: boolean
} = {}): string {
const options: Intl.NumberFormatOptions = {
minimumIntegerDigits,
minimumFractionDigits,
maximumFractionDigits,
style: NumberFormatStyle[style].toLowerCase()
};
if (style == NumberFormatStyle.Currency) {
options.currency = currency;
options.currencyDisplay = currencyAsSymbol ? 'symbol' : 'code';
}
return new Intl.NumberFormat(locale, options).format(num);
}
}
type DateFormatterFn = (date: Date, locale: string) => string;
const DATE_FORMATS_SPLIT =
/((?:[^yMLdHhmsazZEwGjJ']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|L+|d+|H+|h+|J+|j+|m+|s+|a|z|Z|G+|w+))(.*)/;
const PATTERN_ALIASES: {[format: string]: DateFormatterFn} = {
// Keys are quoted so they do not get renamed during closure compilation.
'yMMMdjms': datePartGetterFactory(combine([
digitCondition('year', 1),
nameCondition('month', 3),
digitCondition('day', 1),
digitCondition('hour', 1),
digitCondition('minute', 1),
digitCondition('second', 1),
])),
'yMdjm': datePartGetterFactory(combine([
digitCondition('year', 1), digitCondition('month', 1), digitCondition('day', 1),
digitCondition('hour', 1), digitCondition('minute', 1)
])),
'yMMMMEEEEd': datePartGetterFactory(combine([
digitCondition('year', 1), nameCondition('month', 4), nameCondition('weekday', 4),
digitCondition('day', 1)
])),
'yMMMMd': datePartGetterFactory(
combine([digitCondition('year', 1), nameCondition('month', 4), digitCondition('day', 1)])),
'yMMMd': datePartGetterFactory(
combine([digitCondition('year', 1), nameCondition('month', 3), digitCondition('day', 1)])),
'yMd': datePartGetterFactory(
combine([digitCondition('year', 1), digitCondition('month', 1), digitCondition('day', 1)])),
'jms': datePartGetterFactory(combine(
[digitCondition('hour', 1), digitCondition('second', 1), digitCondition('minute', 1)])),
'jm': datePartGetterFactory(combine([digitCondition('hour', 1), digitCondition('minute', 1)]))
};
const DATE_FORMATS: {[format: string]: DateFormatterFn} = {
// Keys are quoted so they do not get renamed.
'yyyy': datePartGetterFactory(digitCondition('year', 4)),
'yy': datePartGetterFactory(digitCondition('year', 2)),
'y': datePartGetterFactory(digitCondition('year', 1)),
'MMMM': datePartGetterFactory(nameCondition('month', 4)),
'MMM': datePartGetterFactory(nameCondition('month', 3)),
'MM': datePartGetterFactory(digitCondition('month', 2)),
'M': datePartGetterFactory(digitCondition('month', 1)),
'LLLL': datePartGetterFactory(nameCondition('month', 4)),
'L': datePartGetterFactory(nameCondition('month', 1)),
'dd': datePartGetterFactory(digitCondition('day', 2)),
'd': datePartGetterFactory(digitCondition('day', 1)),
'HH': digitModifier(
hourExtractor(datePartGetterFactory(hour12Modify(digitCondition('hour', 2), false)))),
'H': hourExtractor(datePartGetterFactory(hour12Modify(digitCondition('hour', 1), false))),
'hh': digitModifier(
hourExtractor(datePartGetterFactory(hour12Modify(digitCondition('hour', 2), true)))),
'h': hourExtractor(datePartGetterFactory(hour12Modify(digitCondition('hour', 1), true))),
'jj': datePartGetterFactory(digitCondition('hour', 2)),
'j': datePartGetterFactory(digitCondition('hour', 1)),
'mm': digitModifier(datePartGetterFactory(digitCondition('minute', 2))),
'm': datePartGetterFactory(digitCondition('minute', 1)),
'ss': digitModifier(datePartGetterFactory(digitCondition('second', 2))),
's': datePartGetterFactory(digitCondition('second', 1)),
// while ISO 8601 requires fractions to be prefixed with `.` or `,`
// we can be just safely rely on using `sss` since we currently don't support single or two digit
// fractions
'sss': datePartGetterFactory(digitCondition('second', 3)),
'EEEE': datePartGetterFactory(nameCondition('weekday', 4)),
'EEE': datePartGetterFactory(nameCondition('weekday', 3)),
'EE': datePartGetterFactory(nameCondition('weekday', 2)),
'E': datePartGetterFactory(nameCondition('weekday', 1)),
'a': hourClockExtractor(datePartGetterFactory(hour12Modify(digitCondition('hour', 1), true))),
'Z': timeZoneGetter('short'),
'z': timeZoneGetter('long'),
'ww': datePartGetterFactory({}), // Week of year, padded (00-53). Week 01 is the week with the
// first Thursday of the year. not support ?
'w':
datePartGetterFactory({}), // Week of year (0-53). Week 1 is the week with the first Thursday
// of the year not support ?
'G': datePartGetterFactory(nameCondition('era', 1)),
'GG': datePartGetterFactory(nameCondition('era', 2)),
'GGG': datePartGetterFactory(nameCondition('era', 3)),
'GGGG': datePartGetterFactory(nameCondition('era', 4))
};
function digitModifier(inner: DateFormatterFn): DateFormatterFn {
return function(date: Date, locale: string): string {
const result = inner(date, locale);
return result.length == 1 ? '0' + result : result;
};
}
function hourClockExtractor(inner: DateFormatterFn): DateFormatterFn {
return function(date: Date, locale: string): string { return inner(date, locale).split(' ')[1]; };
}
function hourExtractor(inner: DateFormatterFn): DateFormatterFn {
return function(date: Date, locale: string): string { return inner(date, locale).split(' ')[0]; };
}
function intlDateFormat(date: Date, locale: string, options: Intl.DateTimeFormatOptions): string {
return new Intl.DateTimeFormat(locale, options).format(date).replace(/[\u200e\u200f]/g, '');
}
function timeZoneGetter(timezone: string): DateFormatterFn {
// To workaround `Intl` API restriction for single timezone let format with 24 hours
const options = {hour: '2-digit', hour12: false, timeZoneName: timezone};
return function(date: Date, locale: string): string {
const result = intlDateFormat(date, locale, options);
// Then extract first 3 letters that related to hours
return result ? result.substring(3) : '';
};
}
function hour12Modify(
options: Intl.DateTimeFormatOptions, value: boolean): Intl.DateTimeFormatOptions {
options.hour12 = value;
return options;
}
function digitCondition(prop: string, len: number): Intl.DateTimeFormatOptions {
const result: {[k: string]: string} = {};
result[prop] = len === 2 ? '2-digit' : 'numeric';
return result;
}
function nameCondition(prop: string, len: number): Intl.DateTimeFormatOptions {
const result: {[k: string]: string} = {};
if (len < 4) {
result[prop] = len > 1 ? 'short' : 'narrow';
} else {
result[prop] = 'long';
}
return result;
}
function combine(options: Intl.DateTimeFormatOptions[]): Intl.DateTimeFormatOptions {
return (<any>Object).assign({}, ...options);
}
function datePartGetterFactory(ret: Intl.DateTimeFormatOptions): DateFormatterFn {
return (date: Date, locale: string): string => intlDateFormat(date, locale, ret);
}
const DATE_FORMATTER_CACHE = new Map<string, string[]>();
function dateFormatter(format: string, date: Date, locale: string): string {
const fn = PATTERN_ALIASES[format];
if (fn) return fn(date, locale);
const cacheKey = format;
let parts = DATE_FORMATTER_CACHE.get(cacheKey);
if (!parts) {
parts = [];
let match: RegExpExecArray;
DATE_FORMATS_SPLIT.exec(format);
while (format) {
match = DATE_FORMATS_SPLIT.exec(format);
if (match) {
parts = parts.concat(match.slice(1));
format = parts.pop();
} else {
parts.push(format);
format = null;
}
}
DATE_FORMATTER_CACHE.set(cacheKey, parts);
}
return parts.reduce((text, part) => {
const fn = DATE_FORMATS[part];
return text + (fn ? fn(date, locale) : partToTime(part));
}, '');
}
function partToTime(part: string): string {
return part === '\'\'' ? '\'' : part.replace(/(^'|'$)/g, '').replace(/''/g, '\'');
}
export class DateFormatter {
static format(date: Date, locale: string, pattern: string): string {
return dateFormatter(pattern, date, locale);
}
}

View File

@ -17,7 +17,7 @@ import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
* @howToUse `expression | lowercase`
* @description
*
* Converts value into a lowercase string using `String.prototype.toLowerCase()`.
* Converts value into lowercase string using `String.prototype.toLowerCase()`.
*
* ### Example
*

View File

@ -8,9 +8,9 @@
import {Inject, LOCALE_ID, Pipe, PipeTransform, Type} from '@angular/core';
import {NumberFormatStyle, NumberFormatter} from '../facade/intl';
import {NumberWrapper, isBlank, isPresent} from '../facade/lang';
import {NumberFormatStyle, NumberFormatter} from './intl';
import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
const _NUMBER_FORMAT_REGEXP = /^(\d+)?\.((\d+)(-(\d+))?)?$/;
@ -37,7 +37,7 @@ function formatNumber(
}
if (digits) {
const parts = digits.match(_NUMBER_FORMAT_REGEXP);
let parts = digits.match(_NUMBER_FORMAT_REGEXP);
if (parts === null) {
throw new Error(`${digits} is not a valid digit info for number pipes`);
}

View File

@ -16,7 +16,7 @@ import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
* @howToUse `expression | uppercase`
* @description
*
* Converts value into an uppercase string using `String.prototype.toUpperCase()`.
* Converts value into lowercase string using `String.prototype.toUpperCase()`.
*
* ### Example
*

View File

@ -1,19 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
/**
* @module
* @description
* Entry point for all public APIs of the common package.
*/
import {Version} from '@angular/core';
/**
* @stable
*/
export const VERSION = new Version('0.0.0-PLACEHOLDER');

View File

@ -8,6 +8,7 @@
import {Component} from '@angular/core';
import {ComponentFixture, TestBed, async} from '@angular/core/testing';
import {beforeEach, describe, expect, it} from '@angular/core/testing/testing_internal';
export function main() {
describe('binding to CSS class list', () => {
@ -65,7 +66,7 @@ export function main() {
it('should add and remove classes based on changes to the expression object', async(() => {
fixture = createTestComponent('<div [ngClass]="objExpr"></div>');
const objExpr = getComponent().objExpr;
let objExpr = getComponent().objExpr;
detectChangesAndExpectClassName('foo');
@ -134,7 +135,7 @@ export function main() {
it('should add and remove classes based on changes to the expression', async(() => {
fixture = createTestComponent('<div [ngClass]="arrExpr"></div>');
const arrExpr = getComponent().arrExpr;
let arrExpr = getComponent().arrExpr;
detectChangesAndExpectClassName('foo');
arrExpr.push('bar');
@ -186,13 +187,6 @@ export function main() {
getComponent().arrExpr = ['foo bar baz foobar'];
detectChangesAndExpectClassName('foo bar baz foobar');
}));
it('should throw with descriptive error message when CSS class is not a string', () => {
fixture = createTestComponent(`<div [ngClass]="['foo', {}]"></div>`);
expect(() => fixture.detectChanges())
.toThrowError(
/NgClass can only toggle CSS classes expressed as strings, got \[object Object\]/);
});
});
describe('expressions evaluating to sets', () => {
@ -259,7 +253,7 @@ export function main() {
it('should co-operate with the class attribute', async(() => {
fixture = createTestComponent('<div [ngClass]="objExpr" class="init foo"></div>');
const objExpr = getComponent().objExpr;
let objExpr = getComponent().objExpr;
objExpr['bar'] = true;
detectChangesAndExpectClassName('init foo bar');
@ -273,7 +267,7 @@ export function main() {
it('should co-operate with the interpolated class attribute', async(() => {
fixture = createTestComponent(`<div [ngClass]="objExpr" class="{{'init foo'}}"></div>`);
const objExpr = getComponent().objExpr;
let objExpr = getComponent().objExpr;
objExpr['bar'] = true;
detectChangesAndExpectClassName(`init foo bar`);
@ -288,7 +282,7 @@ export function main() {
it('should co-operate with the class attribute and binding to it', async(() => {
fixture =
createTestComponent(`<div [ngClass]="objExpr" class="init" [class]="'foo'"></div>`);
const objExpr = getComponent().objExpr;
let objExpr = getComponent().objExpr;
objExpr['bar'] = true;
detectChangesAndExpectClassName(`init foo bar`);
@ -304,7 +298,7 @@ export function main() {
const template =
'<div class="init foo" [ngClass]="objExpr" [class.baz]="condition"></div>';
fixture = createTestComponent(template);
const objExpr = getComponent().objExpr;
let objExpr = getComponent().objExpr;
detectChangesAndExpectClassName('init foo baz');
@ -322,7 +316,7 @@ export function main() {
async(() => {
const template = '<div class="init" [ngClass]="objExpr" [class]="strExpr"></div>';
fixture = createTestComponent(template);
const cmp = getComponent();
let cmp = getComponent();
detectChangesAndExpectClassName('init foo');
@ -354,4 +348,4 @@ class TestComponent {
function createTestComponent(template: string): ComponentFixture<TestComponent> {
return TestBed.overrideComponent(TestComponent, {set: {template: template}})
.createComponent(TestComponent);
}
}

View File

@ -264,7 +264,7 @@ export function main() {
}));
it('should use a default template if a custom one is null', async(() => {
const testTemplate = `<ul><template ngFor let-item [ngForOf]="items"
const testTemplate = `<ul><template ngFor let-item [ngForOf]="items"
[ngForTemplate]="contentTpl" let-i="index">{{i}}: {{item}};</template></ul>`;
TestBed.overrideComponent(TestComponent, {set: {template: testTemplate}});
const cutTemplate =

View File

@ -7,8 +7,8 @@
*/
import {CommonModule} from '@angular/common';
import {Attribute, Component, Directive} from '@angular/core';
import {ComponentFixture, TestBed} from '@angular/core/testing';
import {Component} from '@angular/core';
import {ComponentFixture, TestBed, async} from '@angular/core/testing';
import {expect} from '@angular/platform-browser/testing/matchers';
export function main() {
@ -32,153 +32,93 @@ export function main() {
});
describe('switch value changes', () => {
it('should switch amongst when values', () => {
const template = '<div>' +
'<ul [ngSwitch]="switchValue">' +
'<template ngSwitchCase="a"><li>when a</li></template>' +
'<template ngSwitchCase="b"><li>when b</li></template>' +
'</ul></div>';
it('should switch amongst when values', async(() => {
const template = '<div>' +
'<ul [ngSwitch]="switchValue">' +
'<template ngSwitchCase="a"><li>when a</li></template>' +
'<template ngSwitchCase="b"><li>when b</li></template>' +
'</ul></div>';
fixture = createTestComponent(template);
fixture = createTestComponent(template);
detectChangesAndExpectText('');
detectChangesAndExpectText('');
getComponent().switchValue = 'a';
detectChangesAndExpectText('when a');
getComponent().switchValue = 'a';
detectChangesAndExpectText('when a');
getComponent().switchValue = 'b';
detectChangesAndExpectText('when b');
});
getComponent().switchValue = 'b';
detectChangesAndExpectText('when b');
}));
it('should switch amongst when values with fallback to default', () => {
const template = '<div>' +
'<ul [ngSwitch]="switchValue">' +
'<li template="ngSwitchCase \'a\'">when a</li>' +
'<li template="ngSwitchDefault">when default</li>' +
'</ul></div>';
it('should switch amongst when values with fallback to default', async(() => {
const template = '<div>' +
'<ul [ngSwitch]="switchValue">' +
'<li template="ngSwitchCase \'a\'">when a</li>' +
'<li template="ngSwitchDefault">when default</li>' +
'</ul></div>';
fixture = createTestComponent(template);
detectChangesAndExpectText('when default');
fixture = createTestComponent(template);
detectChangesAndExpectText('when default');
getComponent().switchValue = 'a';
detectChangesAndExpectText('when a');
getComponent().switchValue = 'a';
detectChangesAndExpectText('when a');
getComponent().switchValue = 'b';
detectChangesAndExpectText('when default');
getComponent().switchValue = 'b';
detectChangesAndExpectText('when default');
getComponent().switchValue = 'c';
detectChangesAndExpectText('when default');
});
getComponent().switchValue = 'c';
detectChangesAndExpectText('when default');
}));
it('should support multiple whens with the same value', () => {
const template = '<div>' +
'<ul [ngSwitch]="switchValue">' +
'<template ngSwitchCase="a"><li>when a1;</li></template>' +
'<template ngSwitchCase="b"><li>when b1;</li></template>' +
'<template ngSwitchCase="a"><li>when a2;</li></template>' +
'<template ngSwitchCase="b"><li>when b2;</li></template>' +
'<template ngSwitchDefault><li>when default1;</li></template>' +
'<template ngSwitchDefault><li>when default2;</li></template>' +
'</ul></div>';
it('should support multiple whens with the same value', async(() => {
const template = '<div>' +
'<ul [ngSwitch]="switchValue">' +
'<template ngSwitchCase="a"><li>when a1;</li></template>' +
'<template ngSwitchCase="b"><li>when b1;</li></template>' +
'<template ngSwitchCase="a"><li>when a2;</li></template>' +
'<template ngSwitchCase="b"><li>when b2;</li></template>' +
'<template ngSwitchDefault><li>when default1;</li></template>' +
'<template ngSwitchDefault><li>when default2;</li></template>' +
'</ul></div>';
fixture = createTestComponent(template);
detectChangesAndExpectText('when default1;when default2;');
fixture = createTestComponent(template);
detectChangesAndExpectText('when default1;when default2;');
getComponent().switchValue = 'a';
detectChangesAndExpectText('when a1;when a2;');
getComponent().switchValue = 'a';
detectChangesAndExpectText('when a1;when a2;');
getComponent().switchValue = 'b';
detectChangesAndExpectText('when b1;when b2;');
});
getComponent().switchValue = 'b';
detectChangesAndExpectText('when b1;when b2;');
}));
});
describe('when values changes', () => {
it('should switch amongst when values', () => {
const template = '<div>' +
'<ul [ngSwitch]="switchValue">' +
'<template [ngSwitchCase]="when1"><li>when 1;</li></template>' +
'<template [ngSwitchCase]="when2"><li>when 2;</li></template>' +
'<template ngSwitchDefault><li>when default;</li></template>' +
'</ul></div>';
it('should switch amongst when values', async(() => {
const template = '<div>' +
'<ul [ngSwitch]="switchValue">' +
'<template [ngSwitchCase]="when1"><li>when 1;</li></template>' +
'<template [ngSwitchCase]="when2"><li>when 2;</li></template>' +
'<template ngSwitchDefault><li>when default;</li></template>' +
'</ul></div>';
fixture = createTestComponent(template);
getComponent().when1 = 'a';
getComponent().when2 = 'b';
getComponent().switchValue = 'a';
detectChangesAndExpectText('when 1;');
fixture = createTestComponent(template);
getComponent().when1 = 'a';
getComponent().when2 = 'b';
getComponent().switchValue = 'a';
detectChangesAndExpectText('when 1;');
getComponent().switchValue = 'b';
detectChangesAndExpectText('when 2;');
getComponent().switchValue = 'b';
detectChangesAndExpectText('when 2;');
getComponent().switchValue = 'c';
detectChangesAndExpectText('when default;');
getComponent().switchValue = 'c';
detectChangesAndExpectText('when default;');
getComponent().when1 = 'c';
detectChangesAndExpectText('when 1;');
getComponent().when1 = 'c';
detectChangesAndExpectText('when 1;');
getComponent().when1 = 'd';
detectChangesAndExpectText('when default;');
});
});
describe('corner cases', () => {
it('should not create the default case if another case matches', () => {
const log: string[] = [];
@Directive({selector: '[test]'})
class TestDirective {
constructor(@Attribute('test') test: string) { log.push(test); }
}
const template = '<div [ngSwitch]="switchValue">' +
'<div *ngSwitchCase="\'a\'" test="aCase"></div>' +
'<div *ngSwitchDefault test="defaultCase"></div>' +
'</div>';
TestBed.configureTestingModule({declarations: [TestDirective]});
TestBed.overrideComponent(TestComponent, {set: {template: template}})
.createComponent(TestComponent);
const fixture = TestBed.createComponent(TestComponent);
fixture.componentInstance.switchValue = 'a';
fixture.detectChanges();
expect(log).toEqual(['aCase']);
});
it('should create the default case if there is no other case', () => {
const template = '<div>' +
'<ul [ngSwitch]="switchValue">' +
'<template ngSwitchDefault><li>when default1;</li></template>' +
'<template ngSwitchDefault><li>when default2;</li></template>' +
'</ul></div>';
fixture = createTestComponent(template);
detectChangesAndExpectText('when default1;when default2;');
});
it('should allow defaults before cases', () => {
const template = '<div>' +
'<ul [ngSwitch]="switchValue">' +
'<template ngSwitchDefault><li>when default1;</li></template>' +
'<template ngSwitchDefault><li>when default2;</li></template>' +
'<template ngSwitchCase="a"><li>when a1;</li></template>' +
'<template ngSwitchCase="b"><li>when b1;</li></template>' +
'<template ngSwitchCase="a"><li>when a2;</li></template>' +
'<template ngSwitchCase="b"><li>when b2;</li></template>' +
'</ul></div>';
fixture = createTestComponent(template);
detectChangesAndExpectText('when default1;when default2;');
getComponent().switchValue = 'a';
detectChangesAndExpectText('when a1;when a2;');
getComponent().switchValue = 'b';
detectChangesAndExpectText('when b1;when b2;');
});
getComponent().when1 = 'd';
detectChangesAndExpectText('when default;');
}));
});
});
}

View File

@ -7,10 +7,13 @@
*/
import {LOCALE_ID} from '@angular/core';
import {TestBed, inject} from '@angular/core/testing';
import {TestBed} from '@angular/core/testing';
import {beforeEach, describe, inject, it} from '@angular/core/testing/testing_internal';
import {expect} from '@angular/platform-browser/testing/matchers';
import {NgLocaleLocalization, NgLocalization, getPluralCategory} from '../src/localization';
export function main() {
describe('l10n', () => {
@ -138,23 +141,6 @@ export function main() {
expect(getPluralCategory(5, ['one', 'other', '=5'], l10n)).toEqual('=5');
expect(getPluralCategory(6, ['one', 'other', '=5'], l10n)).toEqual('other');
});
it('should fallback to other when the case is not present', () => {
const l10n = new NgLocaleLocalization('ro');
expect(getPluralCategory(1, ['one', 'other'], l10n)).toEqual('one');
// 2 -> 'few'
expect(getPluralCategory(2, ['one', 'other'], l10n)).toEqual('other');
});
describe('errors', () => {
it('should report an error when the "other" category is not present', () => {
expect(() => {
const l10n = new NgLocaleLocalization('ro');
// 2 -> 'few'
getPluralCategory(2, ['one'], l10n);
}).toThrowError('No plural message found for value "2"');
});
});
});
});
}

View File

@ -19,10 +19,10 @@ export function main() {
describe('AsyncPipe', () => {
describe('Observable', () => {
let emitter: EventEmitter<any>;
let pipe: AsyncPipe;
let ref: any;
const message = {};
var emitter: EventEmitter<any>;
var pipe: AsyncPipe;
var ref: any;
var message = {};
beforeEach(() => {
emitter = new EventEmitter();
@ -62,7 +62,7 @@ export function main() {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
pipe.transform(emitter);
const newEmitter = new EventEmitter();
var newEmitter = new EventEmitter();
expect(pipe.transform(newEmitter)).toBe(null);
emitter.emit(message);
@ -104,14 +104,14 @@ export function main() {
});
describe('Promise', () => {
const message = new Object();
let pipe: AsyncPipe;
let resolve: (result: any) => void;
let reject: (error: any) => void;
let promise: Promise<any>;
let ref: SpyChangeDetectorRef;
var message = new Object();
var pipe: AsyncPipe;
var resolve: (result: any) => void;
var reject: (error: any) => void;
var promise: Promise<any>;
var ref: SpyChangeDetectorRef;
// adds longer timers for passing tests in IE
const timer = (getDOM() && browserDetection.isIE) ? 50 : 10;
var timer = (getDOM() && browserDetection.isIE) ? 50 : 10;
beforeEach(() => {
promise = new Promise((res, rej) => {
@ -154,7 +154,7 @@ export function main() {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
pipe.transform(promise);
promise = new Promise<any>(() => {});
var promise = new Promise<any>(() => {});
expect(pipe.transform(promise)).toBe(null);
// this should not affect the pipe, so it should return WrappedValue
@ -168,7 +168,7 @@ export function main() {
it('should request a change detection check upon receiving a new value',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
const markForCheck = ref.spy('markForCheck');
var markForCheck = ref.spy('markForCheck');
pipe.transform(promise);
resolve(message);
@ -202,14 +202,14 @@ export function main() {
describe('null', () => {
it('should return null when given null', () => {
const pipe = new AsyncPipe(null);
var pipe = new AsyncPipe(null);
expect(pipe.transform(null)).toEqual(null);
});
});
describe('other types', () => {
it('should throw when given an invalid object', () => {
const pipe = new AsyncPipe(null);
var pipe = new AsyncPipe(null);
expect(() => pipe.transform(<any>'some bogus object')).toThrowError();
});
});

View File

@ -8,18 +8,13 @@
import {DatePipe} from '@angular/common';
import {PipeResolver} from '@angular/compiler/src/pipe_resolver';
import {beforeEach, describe, expect, it} from '@angular/core/testing/testing_internal';
import {browserDetection} from '@angular/platform-browser/testing/browser_util';
export function main() {
describe('DatePipe', () => {
let date: Date;
const isoStringWithoutTime = '2015-01-01';
let pipe: DatePipe;
// Check the transformation of a date into a pattern
function expectDateFormatAs(date: Date | string, pattern: any, output: string): void {
expect(pipe.transform(date, pattern)).toEqual(output);
}
var date: Date;
var pipe: DatePipe;
// TODO: reactivate the disabled expectations once emulators are fixed in SauceLabs
// In some old versions of Chrome in Android emulators, time formatting returns dates in the
@ -39,9 +34,7 @@ export function main() {
describe('supports', () => {
it('should support date', () => { expect(() => pipe.transform(date)).not.toThrow(); });
it('should support int', () => { expect(() => pipe.transform(123456789)).not.toThrow(); });
it('should support numeric strings',
() => { expect(() => pipe.transform('123456789')).not.toThrow(); });
@ -49,143 +42,85 @@ export function main() {
() => { expect(() => pipe.transform('123456789.11')).not.toThrow(); });
it('should support ISO string',
() => expect(() => pipe.transform('2015-06-15T21:43:11Z')).not.toThrow());
() => { expect(() => pipe.transform('2015-06-15T21:43:11Z')).not.toThrow(); });
it('should return null for empty string', () => expect(pipe.transform('')).toEqual(null));
it('should support ISO string without time',
() => { expect(() => pipe.transform(isoStringWithoutTime)).not.toThrow(); });
it('should not support other objects',
() => { expect(() => pipe.transform({})).toThrowError(); });
it('should not support other objects', () => {
expect(() => pipe.transform({})).toThrow();
expect(() => pipe.transform('')).toThrow();
});
});
describe('transform', () => {
it('should format each component correctly', () => {
const dateFixtures: any = {
'y': '2015',
'yy': '15',
'M': '6',
'MM': '06',
'MMM': 'Jun',
'MMMM': 'June',
'd': '15',
'dd': '15',
'EEE': 'Mon',
'EEEE': 'Monday'
};
const isoStringWithoutTimeFixtures: any = {
'y': '2015',
'yy': '15',
'M': '1',
'MM': '01',
'MMM': 'Jan',
'MMMM': 'January',
'd': '1',
'dd': '01',
'EEE': 'Thu',
'EEEE': 'Thursday'
};
expect(pipe.transform(date, 'y')).toEqual('2015');
expect(pipe.transform(date, 'yy')).toEqual('15');
expect(pipe.transform(date, 'M')).toEqual('6');
expect(pipe.transform(date, 'MM')).toEqual('06');
expect(pipe.transform(date, 'MMM')).toEqual('Jun');
expect(pipe.transform(date, 'MMMM')).toEqual('June');
expect(pipe.transform(date, 'd')).toEqual('15');
expect(pipe.transform(date, 'E')).toEqual('Mon');
expect(pipe.transform(date, 'EEEE')).toEqual('Monday');
if (!browserDetection.isOldChrome) {
dateFixtures['h'] = '9';
dateFixtures['hh'] = '09';
dateFixtures['j'] = '9 AM';
isoStringWithoutTimeFixtures['h'] = '12';
isoStringWithoutTimeFixtures['hh'] = '12';
isoStringWithoutTimeFixtures['j'] = '12 AM';
expect(pipe.transform(date, 'h')).toEqual('9');
expect(pipe.transform(date, 'hh')).toEqual('09');
expect(pipe.transform(date, 'j')).toEqual('9 AM');
}
// IE and Edge can't format a date to minutes and seconds without hours
if (!browserDetection.isEdge && !browserDetection.isIE ||
!browserDetection.supportsNativeIntlApi) {
if (!browserDetection.isOldChrome) {
dateFixtures['HH'] = '09';
isoStringWithoutTimeFixtures['HH'] = '00';
expect(pipe.transform(date, 'HH')).toEqual('09');
}
dateFixtures['E'] = 'M';
dateFixtures['L'] = 'J';
dateFixtures['m'] = '3';
dateFixtures['s'] = '1';
dateFixtures['mm'] = '03';
dateFixtures['ss'] = '01';
isoStringWithoutTimeFixtures['m'] = '0';
isoStringWithoutTimeFixtures['s'] = '0';
isoStringWithoutTimeFixtures['mm'] = '00';
isoStringWithoutTimeFixtures['ss'] = '00';
expect(pipe.transform(date, 'm')).toEqual('3');
expect(pipe.transform(date, 's')).toEqual('1');
expect(pipe.transform(date, 'mm')).toEqual('03');
expect(pipe.transform(date, 'ss')).toEqual('01');
}
Object.keys(dateFixtures).forEach((pattern: string) => {
expectDateFormatAs(date, pattern, dateFixtures[pattern]);
});
Object.keys(isoStringWithoutTimeFixtures).forEach((pattern: string) => {
expectDateFormatAs(isoStringWithoutTime, pattern, isoStringWithoutTimeFixtures[pattern]);
});
expect(pipe.transform(date, 'Z')).toBeDefined();
});
it('should format common multi component patterns', () => {
const dateFixtures: any = {
'EEE, M/d/y': 'Mon, 6/15/2015',
'EEE, M/d': 'Mon, 6/15',
'MMM d': 'Jun 15',
'dd/MM/yyyy': '15/06/2015',
'MM/dd/yyyy': '06/15/2015',
'yMEEEd': '20156Mon15',
'MEEEd': '6Mon15',
'MMMd': 'Jun15',
'yMMMMEEEEd': 'Monday, June 15, 2015'
};
expect(pipe.transform(date, 'E, M/d/y')).toEqual('Mon, 6/15/2015');
expect(pipe.transform(date, 'E, M/d')).toEqual('Mon, 6/15');
expect(pipe.transform(date, 'MMM d')).toEqual('Jun 15');
expect(pipe.transform(date, 'dd/MM/yyyy')).toEqual('15/06/2015');
expect(pipe.transform(date, 'MM/dd/yyyy')).toEqual('06/15/2015');
expect(pipe.transform(date, 'yMEd')).toEqual('20156Mon15');
expect(pipe.transform(date, 'MEd')).toEqual('6Mon15');
expect(pipe.transform(date, 'MMMd')).toEqual('Jun15');
expect(pipe.transform(date, 'yMMMMEEEEd')).toEqual('Monday, June 15, 2015');
// IE and Edge can't format a date to minutes and seconds without hours
if (!browserDetection.isEdge && !browserDetection.isIE ||
!browserDetection.supportsNativeIntlApi) {
dateFixtures['ms'] = '31';
expect(pipe.transform(date, 'ms')).toEqual('31');
}
if (!browserDetection.isOldChrome) {
dateFixtures['jm'] = '9:03 AM';
expect(pipe.transform(date, 'jm')).toEqual('9:03 AM');
}
Object.keys(dateFixtures).forEach((pattern: string) => {
expectDateFormatAs(date, pattern, dateFixtures[pattern]);
});
});
it('should format with pattern aliases', () => {
const dateFixtures: any = {
'MM/dd/yyyy': '06/15/2015',
'fullDate': 'Monday, June 15, 2015',
'longDate': 'June 15, 2015',
'mediumDate': 'Jun 15, 2015',
'shortDate': '6/15/2015'
};
if (!browserDetection.isOldChrome) {
// IE and Edge do not add a coma after the year in these 2 cases
if ((browserDetection.isEdge || browserDetection.isIE) &&
browserDetection.supportsNativeIntlApi) {
dateFixtures['medium'] = 'Jun 15, 2015 9:03:01 AM';
dateFixtures['short'] = '6/15/2015 9:03 AM';
expect(pipe.transform(date, 'medium')).toEqual('Jun 15, 2015 9:03:01 AM');
expect(pipe.transform(date, 'short')).toEqual('6/15/2015 9:03 AM');
} else {
dateFixtures['medium'] = 'Jun 15, 2015, 9:03:01 AM';
dateFixtures['short'] = '6/15/2015, 9:03 AM';
expect(pipe.transform(date, 'medium')).toEqual('Jun 15, 2015, 9:03:01 AM');
expect(pipe.transform(date, 'short')).toEqual('6/15/2015, 9:03 AM');
}
}
expect(pipe.transform(date, 'MM/dd/yyyy')).toEqual('06/15/2015');
expect(pipe.transform(date, 'fullDate')).toEqual('Monday, June 15, 2015');
expect(pipe.transform(date, 'longDate')).toEqual('June 15, 2015');
expect(pipe.transform(date, 'mediumDate')).toEqual('Jun 15, 2015');
expect(pipe.transform(date, 'shortDate')).toEqual('6/15/2015');
if (!browserDetection.isOldChrome) {
dateFixtures['mediumTime'] = '9:03:01 AM';
dateFixtures['shortTime'] = '9:03 AM';
expect(pipe.transform(date, 'mediumTime')).toEqual('9:03:01 AM');
expect(pipe.transform(date, 'shortTime')).toEqual('9:03 AM');
}
Object.keys(dateFixtures).forEach((pattern: string) => {
expectDateFormatAs(date, pattern, dateFixtures[pattern]);
});
});
it('should remove bidi control characters',

View File

@ -12,10 +12,10 @@ import {beforeEach, describe, expect, it} from '@angular/core/testing/testing_in
export function main() {
describe('I18nPluralPipe', () => {
let localization: NgLocalization;
let pipe: I18nPluralPipe;
var localization: NgLocalization;
var pipe: I18nPluralPipe;
const mapping = {
var mapping = {
'=0': 'No messages.',
'=1': 'One message.',
'many': 'Many messages.',
@ -32,27 +32,27 @@ export function main() {
describe('transform', () => {
it('should return 0 text if value is 0', () => {
const val = pipe.transform(0, mapping);
var val = pipe.transform(0, mapping);
expect(val).toEqual('No messages.');
});
it('should return 1 text if value is 1', () => {
const val = pipe.transform(1, mapping);
var val = pipe.transform(1, mapping);
expect(val).toEqual('One message.');
});
it('should return category messages', () => {
const val = pipe.transform(4, mapping);
var val = pipe.transform(4, mapping);
expect(val).toEqual('Many messages.');
});
it('should interpolate the value into the text where indicated', () => {
const val = pipe.transform(6, mapping);
var val = pipe.transform(6, mapping);
expect(val).toEqual('There are 6 messages, that is 6.');
});
it('should use "" if value is undefined', () => {
const val = pipe.transform(void(0), mapping);
var val = pipe.transform(void(0), mapping);
expect(val).toEqual('');
});

View File

@ -8,35 +8,40 @@
import {I18nSelectPipe} from '@angular/common';
import {PipeResolver} from '@angular/compiler/src/pipe_resolver';
import {beforeEach, describe, expect, it} from '@angular/core/testing/testing_internal';
export function main() {
describe('I18nSelectPipe', () => {
const pipe: I18nSelectPipe = new I18nSelectPipe();
const mapping = {'male': 'Invite him.', 'female': 'Invite her.', 'other': 'Invite them.'};
var pipe: I18nSelectPipe;
var mapping = {'male': 'Invite him.', 'female': 'Invite her.', 'other': 'Invite them.'};
beforeEach(() => { pipe = new I18nSelectPipe(); });
it('should be marked as pure',
() => { expect(new PipeResolver().resolve(I18nSelectPipe).pure).toEqual(true); });
describe('transform', () => {
it('should return the "male" text if value is "male"', () => {
const val = pipe.transform('male', mapping);
it('should return male text if value is male', () => {
var val = pipe.transform('male', mapping);
expect(val).toEqual('Invite him.');
});
it('should return the "female" text if value is "female"', () => {
const val = pipe.transform('female', mapping);
it('should return female text if value is female', () => {
var val = pipe.transform('female', mapping);
expect(val).toEqual('Invite her.');
});
it('should return the "other" text if value is neither "male" nor "female"',
() => { expect(pipe.transform('Anything else', mapping)).toEqual('Invite them.'); });
it('should return an empty text if value is null or undefined', () => {
expect(pipe.transform(null, mapping)).toEqual('');
expect(pipe.transform(void 0, mapping)).toEqual('');
it('should return "" if value is anything other than male or female', () => {
var val = pipe.transform('Anything else', mapping);
expect(val).toEqual('');
});
it('should throw on bad arguments',
it('should use "" if value is undefined', () => {
var val = pipe.transform(void(0), mapping);
expect(val).toEqual('');
});
it('should not support bad arguments',
() => { expect(() => pipe.transform('male', <any>'hey')).toThrowError(); });
});

View File

@ -13,10 +13,10 @@ import {expect} from '@angular/platform-browser/testing/matchers';
export function main() {
describe('JsonPipe', () => {
const regNewLine = '\n';
let inceptionObj: any;
let inceptionObjString: string;
let pipe: JsonPipe;
var regNewLine = '\n';
var inceptionObj: any;
var inceptionObjString: string;
var pipe: JsonPipe;
function normalize(obj: string): string { return obj.replace(regNewLine, ''); }
@ -39,14 +39,14 @@ export function main() {
() => { expect(pipe.transform(inceptionObj)).toEqual(inceptionObjString); });
it('should return JSON-formatted string even when normalized', () => {
const dream1 = normalize(pipe.transform(inceptionObj));
const dream2 = normalize(inceptionObjString);
var dream1 = normalize(pipe.transform(inceptionObj));
var dream2 = normalize(inceptionObjString);
expect(dream1).toEqual(dream2);
});
it('should return JSON-formatted string similar to Json.stringify', () => {
const dream1 = normalize(pipe.transform(inceptionObj));
const dream2 = normalize(JSON.stringify(inceptionObj, null, 2));
var dream1 = normalize(pipe.transform(inceptionObj));
var dream2 = normalize(JSON.stringify(inceptionObj, null, 2));
expect(dream1).toEqual(dream2);
});
});
@ -63,8 +63,8 @@ export function main() {
});
it('should work with mutable objects', async(() => {
const fixture = TestBed.createComponent(TestComp);
const mutable: number[] = [1];
let fixture = TestBed.createComponent(TestComp);
let mutable: number[] = [1];
fixture.componentInstance.data = mutable;
fixture.detectChanges();
expect(fixture.nativeElement).toHaveText('[\n 1\n]');

View File

@ -11,9 +11,9 @@ import {beforeEach, describe, expect, it} from '@angular/core/testing/testing_in
export function main() {
describe('LowerCasePipe', () => {
let upper: string;
let lower: string;
let pipe: LowerCasePipe;
var upper: string;
var lower: string;
var pipe: LowerCasePipe;
beforeEach(() => {
lower = 'something';
@ -23,14 +23,14 @@ export function main() {
describe('transform', () => {
it('should return lowercase', () => {
const val = pipe.transform(upper);
var val = pipe.transform(upper);
expect(val).toEqual(lower);
});
it('should lowercase when there is a new value', () => {
const val = pipe.transform(upper);
var val = pipe.transform(upper);
expect(val).toEqual(lower);
const val2 = pipe.transform('WAT');
var val2 = pipe.transform('WAT');
expect(val2).toEqual('wat');
});

View File

@ -13,7 +13,7 @@ import {browserDetection} from '@angular/platform-browser/testing/browser_util';
export function main() {
describe('Number pipes', () => {
describe('DecimalPipe', () => {
let pipe: DecimalPipe;
var pipe: DecimalPipe;
beforeEach(() => { pipe = new DecimalPipe('en-US'); });
@ -44,7 +44,7 @@ export function main() {
});
describe('PercentPipe', () => {
let pipe: PercentPipe;
var pipe: PercentPipe;
beforeEach(() => { pipe = new PercentPipe('en-US'); });
@ -60,7 +60,7 @@ export function main() {
});
describe('CurrencyPipe', () => {
let pipe: CurrencyPipe;
var pipe: CurrencyPipe;
beforeEach(() => { pipe = new CurrencyPipe('en-US'); });

View File

@ -13,9 +13,9 @@ import {expect} from '@angular/platform-browser/testing/matchers';
export function main() {
describe('SlicePipe', () => {
let list: number[];
let str: string;
let pipe: SlicePipe;
var list: number[];
var str: string;
var pipe: SlicePipe;
beforeEach(() => {
list = [1, 2, 3, 4, 5];
@ -93,8 +93,8 @@ export function main() {
});
it('should work with mutable arrays', async(() => {
const fixture = TestBed.createComponent(TestComp);
const mutable: number[] = [1, 2];
let fixture = TestBed.createComponent(TestComp);
let mutable: number[] = [1, 2];
fixture.componentInstance.data = mutable;
fixture.detectChanges();
expect(fixture.nativeElement).toHaveText('2');

View File

@ -11,9 +11,9 @@ import {beforeEach, describe, expect, it} from '@angular/core/testing/testing_in
export function main() {
describe('UpperCasePipe', () => {
let upper: string;
let lower: string;
let pipe: UpperCasePipe;
var upper: string;
var lower: string;
var pipe: UpperCasePipe;
beforeEach(() => {
lower = 'something';
@ -24,14 +24,14 @@ export function main() {
describe('transform', () => {
it('should return uppercase', () => {
const val = pipe.transform(lower);
var val = pipe.transform(lower);
expect(val).toEqual(upper);
});
it('should uppercase when there is a new value', () => {
const val = pipe.transform(lower);
var val = pipe.transform(lower);
expect(val).toEqual(upper);
const val2 = pipe.transform('wat');
var val2 = pipe.transform('wat');
expect(val2).toEqual('WAT');
});

View File

@ -34,8 +34,8 @@ export class SpyLocation implements Location {
path(): string { return this._history[this._historyIndex].path; }
isCurrentPathEqualTo(path: string, query: string = ''): boolean {
const givenPath = path.endsWith('/') ? path.substring(0, path.length - 1) : path;
const currPath =
var givenPath = path.endsWith('/') ? path.substring(0, path.length - 1) : path;
var currPath =
this.path().endsWith('/') ? this.path().substring(0, this.path().length - 1) : this.path();
return currPath == givenPath + (query.length > 0 ? ('?' + query) : '');
@ -66,12 +66,12 @@ export class SpyLocation implements Location {
this._history.push(new LocationState(path, query));
this._historyIndex = this._history.length - 1;
const locationState = this._history[this._historyIndex - 1];
var locationState = this._history[this._historyIndex - 1];
if (locationState.path == path && locationState.query == query) {
return;
}
const url = path + (query.length > 0 ? ('?' + query) : '');
var url = path + (query.length > 0 ? ('?' + query) : '');
this.urlChanges.push(url);
this._subject.emit({'url': url, 'pop': false});
}
@ -79,7 +79,7 @@ export class SpyLocation implements Location {
replaceState(path: string, query: string = '') {
path = this.prepareExternalUrl(path);
const history = this._history[this._historyIndex];
var history = this._history[this._historyIndex];
if (history.path == path && history.query == query) {
return;
}
@ -87,7 +87,7 @@ export class SpyLocation implements Location {
history.path = path;
history.query = query;
const url = path + (query.length > 0 ? ('?' + query) : '');
var url = path + (query.length > 0 ? ('?' + query) : '');
this.urlChanges.push('replace: ' + url);
}

View File

@ -44,20 +44,20 @@ export class MockLocationStrategy extends LocationStrategy {
pushState(ctx: any, title: string, path: string, query: string): void {
this.internalTitle = title;
const url = path + (query.length > 0 ? ('?' + query) : '');
var url = path + (query.length > 0 ? ('?' + query) : '');
this.internalPath = url;
const externalUrl = this.prepareExternalUrl(url);
var externalUrl = this.prepareExternalUrl(url);
this.urlChanges.push(externalUrl);
}
replaceState(ctx: any, title: string, path: string, query: string): void {
this.internalTitle = title;
const url = path + (query.length > 0 ? ('?' + query) : '');
var url = path + (query.length > 0 ? ('?' + query) : '');
this.internalPath = url;
const externalUrl = this.prepareExternalUrl(url);
var externalUrl = this.prepareExternalUrl(url);
this.urlChanges.push('replace: ' + externalUrl);
}
@ -68,7 +68,7 @@ export class MockLocationStrategy extends LocationStrategy {
back(): void {
if (this.urlChanges.length > 0) {
this.urlChanges.pop();
const nextUrl = this.urlChanges.length > 0 ? this.urlChanges[this.urlChanges.length - 1] : '';
var nextUrl = this.urlChanges.length > 0 ? this.urlChanges[this.urlChanges.length - 1] : '';
this.simulatePopState(nextUrl);
}
}

View File

@ -22,7 +22,6 @@
"../../../node_modules/zone.js/dist/zone.js.d.ts"
],
"angularCompilerOptions": {
"annotateForClosureCompiler": true,
"strictMetadataEmit": true
}
}

View File

@ -5,13 +5,10 @@
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
export {AotCompilerHost, AotCompilerHost as StaticReflectorHost, StaticReflector, StaticSymbol} from '@angular/compiler';
export {CodeGenerator} from './src/codegen';
export {CompilerHost, CompilerHostContext, ModuleResolutionHostAdapter, NodeCompilerHostContext} from './src/compiler_host';
export {Extractor} from './src/extractor';
export {NodeReflectorHostContext, ReflectorHost, ReflectorHostContext} from './src/reflector_host';
export {StaticReflector, StaticReflectorHost, StaticSymbol} from './src/static_reflector';
export * from '@angular/tsc-wrapped';
export {VERSION} from './src/version';
// TODO(hansl): moving to Angular 4 need to update this API.
export {NgTools_InternalApi_NG_2 as __NGTOOLS_PRIVATE_API_2} from './src/ngtools_api'

View File

@ -1,3 +0,0 @@
:host {
background-color: blue;
}

View File

@ -1,5 +0,0 @@
<div>
<h1 i18n>hello world</h1>
<a [routerLink]="['lazy']">lazy</a>
<router-outlet></router-outlet>
</div>

View File

@ -1,19 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Component, ViewEncapsulation} from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: 'app.component.html',
styleUrls: ['app.component.css'],
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
}

View File

@ -1,32 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Component, NgModule} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import {RouterModule} from '@angular/router';
import {AppComponent} from './app.component';
@Component({selector: 'home-view', template: 'home!'})
export class HomeView {
}
@NgModule({
declarations: [AppComponent, HomeView],
imports: [
BrowserModule, RouterModule.forRoot([
{path: 'lazy', loadChildren: './lazy.module#LazyModule'},
{path: 'feature2', loadChildren: 'feature2/feature2.module#Feature2Module'},
{path: '', component: HomeView}
])
],
bootstrap: [AppComponent]
})
export class AppModule {
}

View File

@ -1,21 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Component, NgModule} from '@angular/core';
import {RouterModule} from '@angular/router';
@Component({selector: 'feature-component', template: 'foo.html'})
export class FeatureComponent {
}
@NgModule({
declarations: [FeatureComponent],
imports: [RouterModule.forChild([{path: '', component: FeatureComponent}])]
})
export class FeatureModule {
}

View File

@ -1,24 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Component, NgModule} from '@angular/core';
import {RouterModule} from '@angular/router';
@Component({selector: 'lazy-feature-comp', template: 'lazy feature!'})
export class LazyFeatureComponent {
}
@NgModule({
imports: [RouterModule.forChild([
{path: '', component: LazyFeatureComponent, pathMatch: 'full'},
{path: 'feature', loadChildren: './feature.module#FeatureModule'}
])],
declarations: [LazyFeatureComponent]
})
export class LazyFeatureModule {
}

View File

@ -1,23 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Component, NgModule} from '@angular/core';
import {RouterModule} from '@angular/router';
@Component({selector: 'feature-component', template: 'foo.html'})
export class FeatureComponent {
}
@NgModule({
declarations: [FeatureComponent],
imports: [RouterModule.forChild([
{path: '', component: FeatureComponent},
])]
})
export default class DefaultModule {
}

View File

@ -1,26 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Component, NgModule} from '@angular/core';
import {RouterModule} from '@angular/router';
@Component({selector: 'feature-component', template: 'foo.html'})
export class FeatureComponent {
}
@NgModule({
declarations: [FeatureComponent],
imports: [RouterModule.forChild([
{path: '', component: FeatureComponent}, {path: 'd', loadChildren: './default.module'} {
path: 'e',
loadChildren: 'feature/feature.module#FeatureModule'
}
])]
})
export class Feature2Module {
}

View File

@ -1,27 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Component, NgModule} from '@angular/core';
import {RouterModule} from '@angular/router';
@Component({selector: 'lazy-comp', template: 'lazy!'})
export class LazyComponent {
}
@NgModule({
imports: [RouterModule.forChild([
{path: '', component: LazyComponent, pathMatch: 'full'},
{path: 'feature', loadChildren: './feature/feature.module#FeatureModule'},
{path: 'lazy-feature', loadChildren: './feature/lazy-feature.module#LazyFeatureModule'}
])],
declarations: [LazyComponent]
})
export class LazyModule {
}
export class SecondModule {}

View File

@ -1,19 +0,0 @@
{
"angularCompilerOptions": {
// For TypeScript 1.8, we have to lay out generated files
// in the same source directory with your code.
"genDir": ".",
"debug": true
},
"compilerOptions": {
"target": "es5",
"experimentalDecorators": true,
"noImplicitAny": true,
"moduleResolution": "node",
"rootDir": "",
"declaration": true,
"lib": ["es6", "dom"],
"baseUrl": "."
}
}

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE translationbundle [<!ELEMENT translationbundle (translation)*>
<!ATTLIST translationbundle lang CDATA #REQUIRED>
<!ELEMENT translation (#PCDATA|ph)*>
<!ATTLIST translation id CDATA #REQUIRED>
<!ELEMENT ph EMPTY>
<!ATTLIST ph name CDATA #REQUIRED>
]>
<translationbundle>
<translation id="76e1eccb1b772fa9f294ef9c146ea6d0efa8a2d4">käännä teksti</translation>
<translation id="65cc4ab3b4c438e07c89be2b677d08369fb62da2">tervetuloa</translation>
<translation id="63a85808f03b8181e36a952e0fa38202c2304862">other-3rdP-component</translation>
</translationbundle>

View File

@ -8,12 +8,10 @@
import {ApplicationRef, NgModule} from '@angular/core';
import {FormsModule} from '@angular/forms';
import {ServerModule} from '@angular/platform-server';
import {BrowserModule} from '@angular/platform-browser';
import {MdButtonModule} from '@angular2-material/button';
// Note: don't refer to third_party_src as we want to test that
// we can compile components from node_modules!
import {ThirdpartyModule} from 'third_party/module';
import {ThirdpartyModule} from '../third_party_src/module';
import {MultipleComponentsMyComp, NextComp} from './a/multiple_components';
import {AnimateCmp} from './animate';
@ -21,7 +19,7 @@ import {BasicComp} from './basic';
import {ComponentUsingThirdParty} from './comp_using_3rdp';
import {CompWithAnalyzeEntryComponentsProvider, CompWithEntryComponents} from './entry_components';
import {CompConsumingEvents, CompUsingPipes, CompWithProviders, CompWithReferences, DirPublishingEvents, ModuleUsingCustomElements} from './features';
import {CompUsingRootModuleDirectiveAndPipe, SomeDirectiveInRootModule, SomeLibModule, SomePipeInRootModule, SomeService} from './module_fixtures';
import {CompUsingRootModuleDirectiveAndPipe, SomeDirectiveInRootModule, SomePipeInRootModule, SomeService, someLibModuleWithProviders} from './module_fixtures';
import {CompWithNgContent, ProjectingComp} from './projection';
import {CompForChildQuery, CompWithChildQuery, CompWithDirectiveChild, DirectiveForQuery} from './queries';
@ -50,11 +48,11 @@ import {CompForChildQuery, CompWithChildQuery, CompWithDirectiveChild, Directive
ComponentUsingThirdParty,
],
imports: [
ServerModule,
BrowserModule,
FormsModule,
MdButtonModule,
ModuleUsingCustomElements,
SomeLibModule.withProviders(),
someLibModuleWithProviders(),
ThirdpartyModule,
],
providers: [SomeService],

View File

@ -8,6 +8,7 @@
import {LowerCasePipe, NgIf} from '@angular/common';
import {ANALYZE_FOR_ENTRY_COMPONENTS, Component, ComponentFactoryResolver, Directive, Inject, Injectable, Input, ModuleWithProviders, NgModule, OpaqueToken, Pipe} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
@Injectable()
export class SomeService {
@ -63,13 +64,17 @@ export function provideValueWithEntryComponents(value: any) {
entryComponents: [CompUsingLibModuleDirectiveAndPipe],
})
export class SomeLibModule {
static withProviders() {
return {
ngModule: SomeLibModule,
providers: [
ServiceUsingLibModule, provideValueWithEntryComponents(
[{a: 'b', component: CompUsingLibModuleDirectiveAndPipe}])
]
};
}
}
// TODO(tbosch): Make this a static method in `SomeLibModule` once
// our static reflector supports it.
// See https://github.com/angular/angular/issues/10266.
export function someLibModuleWithProviders(): ModuleWithProviders {
return {
ngModule: SomeLibModule,
providers: [
ServiceUsingLibModule,
provideValueWithEntryComponents([{a: 'b', component: CompUsingLibModuleDirectiveAndPipe}])
]
};
}

View File

@ -19,9 +19,9 @@ describe('template codegen output', () => {
it('should apply the animate states to the element', (done) => {
const compFixture = createComponent(AnimateCmp);
const debugElement = compFixture.debugElement;
var debugElement = compFixture.debugElement;
const targetDebugElement = findTargetElement(<DebugElement>debugElement);
var targetDebugElement = findTargetElement(<DebugElement>debugElement);
compFixture.componentInstance.setAsOpen();
compFixture.detectChanges();
@ -45,9 +45,9 @@ describe('template codegen output', () => {
it('should apply the default animate state to the element', (done) => {
const compFixture = createComponent(AnimateCmp);
const debugElement = compFixture.debugElement;
var debugElement = compFixture.debugElement;
const targetDebugElement = findTargetElement(<DebugElement>debugElement);
var targetDebugElement = findTargetElement(<DebugElement>debugElement);
compFixture.componentInstance.setAsSomethingElse();
compFixture.detectChanges();

View File

@ -15,8 +15,8 @@ import {createComponent} from './util';
describe('content projection', () => {
it('should support entryComponents in components', () => {
const compFixture = createComponent(CompWithEntryComponents);
const cf = compFixture.componentInstance.cfr.resolveComponentFactory(BasicComp);
var compFixture = createComponent(CompWithEntryComponents);
var cf = compFixture.componentInstance.cfr.resolveComponentFactory(BasicComp);
expect(cf.componentType).toBe(BasicComp);
});

View File

@ -34,9 +34,9 @@ const EXPECTED_XMB = `<?xml version="1.0" encoding="UTF-8" ?>
<!ELEMENT ex (#PCDATA)>
]>
<messagebundle>
<msg id="8136548302122759730" desc="desc" meaning="meaning">translate me</msg>
<msg id="3492007542396725315">Welcome</msg>
<msg id="3772663375917578720">other-3rdP-component</msg>
<msg id="63a85808f03b8181e36a952e0fa38202c2304862">other-3rdP-component</msg>
<msg id="76e1eccb1b772fa9f294ef9c146ea6d0efa8a2d4" desc="desc" meaning="meaning">translate me</msg>
<msg id="65cc4ab3b4c438e07c89be2b677d08369fb62da2">Welcome</msg>
</messagebundle>
`;
@ -44,6 +44,10 @@ const EXPECTED_XLIFF = `<?xml version="1.0" encoding="UTF-8" ?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
<file source-language="en" datatype="plaintext" original="ng2.template">
<body>
<trans-unit id="63a85808f03b8181e36a952e0fa38202c2304862" datatype="html">
<source>other-3rdP-component</source>
<target/>
</trans-unit>
<trans-unit id="76e1eccb1b772fa9f294ef9c146ea6d0efa8a2d4" datatype="html">
<source>translate me</source>
<target/>
@ -54,10 +58,6 @@ const EXPECTED_XLIFF = `<?xml version="1.0" encoding="UTF-8" ?>
<source>Welcome</source>
<target/>
</trans-unit>
<trans-unit id="63a85808f03b8181e36a952e0fa38202c2304862" datatype="html">
<source>other-3rdP-component</source>
<target/>
</trans-unit>
</body>
</file>
</xliff>
@ -79,4 +79,5 @@ describe('template i18n extraction output', () => {
const xlf = fs.readFileSync(xlfOutput, {encoding: 'utf-8'});
expect(xlf).toEqual(EXPECTED_XLIFF);
});
});

Some files were not shown because too many files have changed in this diff Show More