Compare commits

...

420 Commits
2.1.1 ... 2.4.0

Author SHA1 Message Date
6efdf84d3e docs(changelog): add changelog for 2.4.0 2016-12-19 17:42:17 -08:00
e61bfc8b24 chore(release): cut the 2.4.0 release 2016-12-19 17:19:25 -08:00
070f9d0644 refactor: formatting fixes 2016-12-19 17:18:33 -08:00
8d5da1e57a feat: update to rxjs@5.0.1 and unpin the rxjs peerDeps via ^5.0.1 (#13572)
Now that rxjs is stable and the rxjs team follows semver, we can update and unpin the dependency safely.

From now on the Angular application/library developers are in charge of controlling the rxjs version as long as it's newer than 5.0.1.

closes #13561
closes #13478
closes #13572
2016-12-19 17:09:41 -08:00
b6406191c7 build(npm): update angular version in shrinkwrap files 2016-12-19 17:09:41 -08:00
124face441 refactor(compiler-cli): support extracting the mesage bundle without writing a file (#13580) 2016-12-19 17:09:41 -08:00
de4ace77fe feat(compiler-cli): private i18n API for the CLI (#13536)
Also change the Extractor API to align with the Codegen API (internal APIs)
2016-12-19 17:09:41 -08:00
debb0c9798 fix(compiler-cli): produce metadata for .d.ts files without metadata (#13526)
Fixes #13307
Fixes #13473
Fixes #13521
2016-12-19 17:09:40 -08:00
9b87bb6d7f fix(compiler): do not lex }} when interpolation is disabled (#13531)
* doc(compiler): fix the ICU expander API docs

* test(compiler): add lexer and parser specs

* fix(compiler): do not lex `}}` when interpolation is disabled

fix #13525
2016-12-19 17:09:40 -08:00
71e88a8c3c refactor(core): fix typo (#13515)
Closes #13512
2016-12-19 17:09:40 -08:00
c26c24c544 fix(upgrade): fix registerForNg1Tests (#13522)
Fix an issue in `registerForNg1Tests`, where it passes a `null` as
`ng1Injector` to `_bootstrapDone`. This causes a "TypeError: Cannot
read property 'get' of null" to be thrown from `_bootstrapDone`.
2016-12-19 17:09:40 -08:00
3f178410c3 fix(i18n): add a default example to xmb placeholders (#13507)
Otherwise the TC would not be able to load the message
2016-12-19 17:09:40 -08:00
b36f4bc00d fix(animations): allow players to be destroyed before initialized (#13346)
Closes #13293
Closes #13346
2016-12-19 17:09:40 -08:00
355c537883 refactor(compiler): format update (#13506) 2016-12-19 17:09:39 -08:00
f277303ca3 refactor(compiler): don't print stack trace on template parse errors (#13390) 2016-12-19 17:09:39 -08:00
50afbe094f fix(build): use bash string comparison operator (#13502) 2016-12-19 17:09:39 -08:00
15ea758d01 feature(DEVELOPER.md): add easy way to publish personal snapshot builds (#13469) 2016-12-19 17:09:39 -08:00
1f0f429f2a refactor(compiler): store metadata of top level symbols also in summaries (#13289)
This allows a build using summaries to not need .metadata.json files at all
any more.

Part of #12787
2016-12-19 17:09:39 -08:00
dbb364e23a docs(changelog): minor updates to 2.3.1 changelog 2016-12-14 21:57:56 -08:00
540b1197a6 fix(form): fix merge errors 2016-12-14 18:22:03 -08:00
d30cc8461b docs(changelog): add changelog for 2.3.1 2016-12-14 18:14:34 -08:00
f27954e62c build: bump angular to 2.3.1 & tsc-wrapped to 0.5.0 2016-12-14 18:11:35 -08:00
69b52eb2b3 fix(compiler): fix merge error in compiler_host 2016-12-14 18:08:54 -08:00
b9b557cdb0 fix(compiler): update to metadata version 3 (#13464)
This change retracts support for metadata version 2.

The collector used to produce version 2 metadata was incomplete
and can cause the AOT compiler to fail to resolve symbols or
produce other spurious errors.

All libraries compiled and published with 2.3.0 ngc will need
to be recompiled and updated with this change.
2016-12-14 18:08:48 -08:00
a72a002a8d refactor: format & lint 2016-12-14 18:08:43 -08:00
a0437f8c9d chore(animations/aot): always export NoOpAnimationDriver (#13480) 2016-12-14 18:08:36 -08:00
1c279b3264 fix(compiler): fix simplify a reference without a name
closes #13470
2016-12-14 18:08:32 -08:00
cd03c77364 fix(tsc-wrapped): generate metadata for exports without module specifier
fixes #13327
2016-12-14 18:08:29 -08:00
f6ef7d6e5a fix(compiler): propagate exports when upgrading metadata to v2 2016-12-14 18:08:25 -08:00
6aeaca3fb4 fix(compiler): resolver should merge host bindings and listeners (#13474)
fixes #13327
2016-12-14 18:07:41 -08:00
af62050729 docs(upgrade): fix UpgradeAdapter examples
closes #12675
2016-12-14 18:02:26 -08:00
cb69656b56 docs(upgrade/upgrade_adapter): fix up references to AngularJS and Angular 2 2016-12-14 18:02:14 -08:00
2fc0560988 feat(upgrade): enable Angular 1 unit testing of upgrade module
- New method `UpgradeAdapter.registerForNg1Tests(modules)` declares the
  Angular 1 upgrade module and provides it to the `angular.mock.module()`
  helper.
  This prevents the need to bootstrap the entire hybrid for every test.

Closes #5462, #12675
2016-12-14 18:02:05 -08:00
86c50983d7 fix(upgrade): fix downgrade content projection and injector inheritance
- Full support for content projection in downgraded Angular 2
  components. In particular, this enables multi-slot projection and
  other features on <ng-content>.
- Correctly wire up hierarchical injectors for downgraded Angular 2
  components: downgraded components inherit the injector of the first
  other downgraded Angular 2 component they find up the DOM tree.

Closes #6629, #7727, #8729, #9643, #9649, #12675
2016-12-14 17:56:20 -08:00
21976446e0 refactor(upgrade/upgrade_adapter): use Deferred helper
Making Angular 1's `$compile` asynchronous by chaining injector promises
in linking functions can cause flickering views in applications.
2016-12-14 17:56:16 -08:00
998ce9ad7e refactor(upgrade/util): remove unused stringify() method 2016-12-14 17:56:11 -08:00
111523677c refactor(compiler/template_parser): export createElementCssSelector
This is needed in `ngUpgrade`.
2016-12-14 17:56:06 -08:00
2d74a224d0 refactor(upgrade): add missing Angular 1 type info 2016-12-14 17:55:56 -08:00
4d6ac9d414 fix(core): detectChanges() doesn't work on detached instance
Closes #13426
Closes #13472
2016-12-14 17:55:38 -08:00
6557bc34f6 fix(animations): throw errors and normalize offset beyond the range of [0,1]
Closes #13348
Closes #13440
2016-12-14 17:55:34 -08:00
e2622add07 perf(animations): always run the animation queue outside of zones
Related #12732
Closes #13440
2016-12-14 17:55:27 -08:00
ecfad467a1 fix(compiler): emit quoted object literal keys if the source is quoted
feat(tsc-wrapped): recored when to quote a object literal key

Collecting quoted literals is off by default as it introduces
a breaking change in the .metadata.json file. A follow-up commit
will address this.

Fixes #13249
Closes #13356
2016-12-14 17:55:22 -08:00
5918133784 Revert "fix(compiler): xmb <ph> tags should not self close (#13413)"
This reverts commit 4b3d135193.
closes #13463
2016-12-14 17:55:18 -08:00
700bce9ec1 Revert "test(i18n): fix a typo in the reference xmb (#13441)"
This reverts commit a8d237581d.
2016-12-14 17:55:14 -08:00
a64a35a8c1 refactor(facade): don't expect super() to return a new Error object in BaseError (#12600)
Related to #12575
2016-12-14 17:55:10 -08:00
b3dcff0cc1 fix(forms): ensure select[multiple] retains selections
If you bound an array to select[multiple] via ngModel and subsequently
changed the options to select from, the UI would drop any selections
made since by the user. This was due to
SelectMultipleControlValueAccessor not keeping a reference to the new
model arrays it generated when users interacted with the select control.
Update code to keep the reference.

Closes #12527
Closes #12654
2016-12-14 17:55:02 -08:00
124267c87a fix(forms): introduce checkbox required validator
Closes #11459
Closes #13364
2016-12-14 17:52:53 -08:00
547bfa92ef fix (forms): clear selected options when model is not an array (#12519)
When an invalid model value (eg empty string) was preset ngModel on
select[multiple] would throw an error, which is inconsistent with how it
works on other user input elements. Setting the model value to null or
undefined would also have no effect on what was already selected in the
UI. Fix this by clearing selected options when model set to null,
undefined or a type other than Array.

Closes #11926
2016-12-14 17:52:02 -08:00
d40bbf4d5c fix(core): properly destroy embedded Views attatched to ApplicationRef (#13459)
Fixes #13062
2016-12-14 17:51:56 -08:00
94b7031fe9 refactor: format & lint 2016-12-14 17:51:48 -08:00
df0bf1dd74 chore(internal API): introduce an internal API for ngtools. (#13415) 2016-12-14 17:51:40 -08:00
c8a9b70890 fix(compiler): generated CSS files suffixed with ngstyle. (#13353)
Mirrors factories which ends in `ngfactory`.

Closes #13141.
2016-12-14 17:50:29 -08:00
efa2d80df8 fix(compiler): make sure provider values with name property don’t break.
Fixes #13394
Closes #13445
2016-12-14 17:50:22 -08:00
a58e5efd09 test(i18n): fix a typo in the reference xmb (#13441) 2016-12-14 17:50:12 -08:00
86cf0ef892 refactor: remove intl from facades (#13404)
The existing intl.ts file is not a facade but
rather a set of utils used by i18n-related pipes only.
As such moving it back to common module so those utils
are not used accidently from other places.
2016-12-14 17:50:02 -08:00
5c568fab86 test(upgrade): fix failing test in browsers which do not support RAF
closes #13399
2016-12-14 17:49:52 -08:00
566104504c ci(browser providers): update browsers in SL and BS (#13431) 2016-12-14 17:49:37 -08:00
307d305b2d fix(compiler): narrow the span reported for invalid pipes
fixes #13326
closes #13411
2016-12-14 17:49:05 -08:00
0a7364feea fix(language-service): correctly type undefined
fixes #13412
closes #13414
2016-12-14 17:40:58 -08:00
4544b1d7a6 fix(compiler): xmb <ph> tags should not self close (#13413) 2016-12-14 17:39:51 -08:00
9e0e6b59d1 docs(core): update OnDestroy description (#13369)
Closes #11228
2016-12-14 17:39:45 -08:00
14dd2b367a fix(language-service): treat string unions as strings (#13406)
Fixes #13403
2016-12-14 17:39:36 -08:00
91eb8914dd build: update the package list of the symlinks scripts for Windows (#13408) 2016-12-14 17:39:30 -08:00
77823d721f refactor: format and lint code 2016-12-14 17:38:31 -08:00
2afe2d107f docs(Location): updating Location docs and adding example
closes #11500
2016-12-14 17:38:22 -08:00
17f40fb75f chore: Add @types/systemjs 2016-12-14 17:37:43 -08:00
98936fdf16 chore: convert hash_location_strategy example to a tested spec 2016-12-14 17:37:33 -08:00
7383e4a801 fix(forms): fix Validators.min/maxLength with FormArray (#13095)
Fixes #13089
2016-12-14 17:37:18 -08:00
65c9b5b6aa fix(http): create a copy of headers when merge options (#13365)
Closes #11980
2016-12-14 17:36:48 -08:00
5fab8710cb fix(dom_adapter): remove logError from logGroup (#12925) 2016-12-14 17:35:12 -08:00
f106a18b96 fix(http): check response body text against undefined (#13017) 2016-12-14 17:35:05 -08:00
8db184d349 fix(compiler): support dotted property binding
fixes angular/flex-layout#34
2016-12-14 17:31:08 -08:00
c18eb298eb test(Selector): add a test for dotted attribute names 2016-12-14 17:31:00 -08:00
3f4aa59cfa refactor(Compiler): cleanup 2016-12-14 17:30:50 -08:00
79728b4c41 fix(compiler): fix PR 13322 (#13331) 2016-12-14 17:30:40 -08:00
413167ab1b style: clang-format the code 2016-12-14 17:26:52 -08:00
203cc7e1f1 fix: Better instructions on running examples and their tests 2016-12-14 17:23:11 -08:00
b0cd514709 fix: Better error when directive not listed in NgModule.declarations 2016-12-14 17:22:58 -08:00
392c9ac214 fix(selector): SelectorMatcher match elements with :not selector (#12977) 2016-12-14 17:21:34 -08:00
a26e054857 fix(animations): always cleanup players after they have finished internally (#13334)
Closes #13333
Closes #13334
2016-12-14 17:21:23 -08:00
c0b001a6af refactor(router): misc refactoring (#13330) 2016-12-14 17:21:09 -08:00
c8c1f22f9c refactor(router): simplify regexp
closes #11373
closes #13329
2016-12-14 17:20:47 -08:00
e4d5a5f003 fix(router): add support for query params with mulitple values
closes #11373
2016-12-14 17:20:22 -08:00
03d9de33a1 Revert "fix(compiler): fix transpiled ES5 code (#13322)"
This reverts commit 4398056146.
2016-12-14 17:20:14 -08:00
a8a80cf523 doc: update triage owners for language service and router (#13325) 2016-12-14 17:19:50 -08:00
6c1d7908d5 fix(compiler): fix transpiled ES5 code (#13322)
fixes #13301

The inner class would transpile to a nested function declaration which is not
allowed in ES5.

See http://eslint.org/docs/rules/no-inner-declarations
2016-12-14 17:18:12 -08:00
9aab6d24eb build(tslint): enable no-inner-declarations (#13316) 2016-12-14 17:18:02 -08:00
5ee8155e4e fix(router): Use T type in Resolve interface (#13242) 2016-12-14 17:17:45 -08:00
21de0f239d docs(changelog): fix a typo (#13298) 2016-12-14 17:16:49 -08:00
13b41bd631 chore(release): update version of tsc-wrapped to 0.4.2 2016-12-07 13:54:22 -08:00
f3524af68f docs(changelog): add changelog for 2.3.0 2016-12-07 11:21:13 -08:00
0a56f4ea82 chore(release): cut the 2.3.0 release 2016-12-07 10:58:29 -08:00
cf52284ac3 docs(changelog): fix typo AplicationRef => ApplicationRef (#13284)
docs(changelog): fix typo AplicationRef => ApplicationRef
2016-12-07 10:06:40 -08:00
4a09c81724 fix(language-service): do not throw for invalid metadata (#13261)
Fixes #13255
2016-12-06 17:11:09 -08:00
16efb13dd1 fix: display framework version on bootstrapped component (#13252) 2016-12-06 16:21:07 -08:00
986abbe0b2 fix(http): set the default Accept header (#12989)
Fixes #6354
2016-12-06 16:20:43 -08:00
25c2141991 fix(language-service): remove incompletely used parameter from createLanguageServiceFromTypescript() (#13278)
Fixes #13277
2016-12-06 16:19:39 -08:00
2893c2c0a2 fix(router): validate nested routes (#13224)
Fixes #12827
2016-12-06 10:41:01 -08:00
393c1007a8 fix(tsc-wrapped): have UserError display the actual error 2016-12-06 10:40:38 -08:00
66b6fc010d refactor(common): unify export structure 2016-12-06 10:40:38 -08:00
f31c9470fa fix(compiler): short-circut expressions with an index (#13263)
Fixes #13254
2016-12-06 10:40:15 -08:00
4bd8f58552 FIX typo (#13267) 2016-12-06 10:40:01 -08:00
93556a5720 fix(language-service): avoid throwing for invalid class declarations (#13257)
Fixes #13253
2016-12-06 09:56:30 -08:00
5614c4ff0f fix(compiler): serialize any StaticSymbol correctly, not matter in which context. 2016-12-05 14:20:01 -08:00
c3065aac7a refactor(compiler): replace isStaticSymbol with instanceof StaticSymbol 2016-12-05 14:20:01 -08:00
c767df0e4e fix(router): throw a better error message when angular 1 is not bootstraped 2016-12-05 10:57:24 -08:00
25e5b2fdf0 fix(router): make setUpLocationChangeListener idempotent 2016-12-05 10:57:24 -08:00
307c4693dc refactor(router): code cleanup 2016-12-05 10:54:10 -08:00
349ad75de3 fix(router): fix replaceUrl on RouterLink directives 2016-12-05 10:54:10 -08:00
f562cbf86c fix(router): fix skipLocationChanges on RouterLink directives
fixes #13156
2016-12-05 10:54:10 -08:00
804943c9b1 refactor(router): cleanup RouterLink 2016-12-05 10:54:10 -08:00
dea59165de docs(developer): add anchor to source code formatting (#13199)
In CONTRIBUTING.md#rules has reference to DEVELOPER.md#clang-format
but anchor to #clang-format is not present
2016-12-05 10:27:20 -08:00
a1322873c8 fix(facade): cache original format string (#12764) 2016-12-05 10:26:59 -08:00
b8c839bd51 docs(cheatsheet): correct HostBinding decorator example (#13206) 2016-12-05 10:25:40 -08:00
d2e5198b93 docs(contributing): fix styleguide link and typos (#13198) 2016-12-05 10:25:20 -08:00
6cf7a1bf84 refactor(build): fix build location of compiler-cli esm module (#13212) 2016-12-02 15:19:52 -08:00
d46b8deeea fix(router): runs guards every time when unsuccessfully navigating to the same url over and over again (#13209) 2016-12-02 15:19:00 -08:00
bbb7a39414 fix(router): allow specifying a matcher wihtout specifying a path
fixes #12972
2016-12-02 15:03:59 -08:00
d7d8fab211 refactor(router): cleanup config 2016-12-02 15:03:59 -08:00
51b06924bd docs(core): correct HostListener typo (#13203) 2016-12-02 14:45:47 -08:00
aa4bd14b3f docs(changelog): add instructions for people that depend on the cache operator (#13191) 2016-12-02 14:43:05 -08:00
3ff6554cbc fix(language-service): update to use CompilerHost from compiler-cli (#13189) 2016-12-02 14:34:16 -08:00
dfd8140084 Fix format 2016-12-02 14:31:55 -08:00
6ea3ab7e14 Fix exit code. Give a specific type. Add test cases. 2016-12-02 14:31:55 -08:00
9761db5ac2 refactor(compiler): change ngc error handling
Do not print stack trace for user errors
Print stack trace for compiler internal errors
2016-12-02 14:31:55 -08:00
75d1617b63 fix(compiler): include the summaries of reexported modules / directives / pipes (#13196)
Only if these are not part of the sources.
2016-12-02 10:08:46 -08:00
614a35d539 feat(compiler): read and write .ngsummary.json files
When compiling libraries, this feature extracts the minimal information
from the directives/pipes/modules of the library into `.ngsummary.json` files,
so that applications that use this library only need to be recompiled
if one of the summary files change, but not on every change
of the libraries (e.g. one of the templates).

Only works if individual codegen for libraries is enabled,
see the `generateCodeForLibraries: false` option.

Closes #12787
2016-12-01 14:49:52 -08:00
9ab401f4d3 refactor(compiler): simplify NgModuleSymmaryMetadata
- merge `NgModuleInjectorSummary` and `NgModuleDirectiveSummary`
- remove `directiveLoaders` from the summary
2016-12-01 14:49:52 -08:00
82c81cd0d2 fix(common): make sure the plural category exists (#13169)
fixes #12379
2016-12-01 13:26:24 -08:00
12959f444c refactor(router):remove unused parameter pathIndex (#13180) 2016-12-01 13:25:53 -08:00
25a6da244c refactor(compiler-cli): refactor compiler host parameters (#13147) 2016-12-01 13:24:51 -08:00
5908b66ae9 docs(changelog): move 2.2.2 to its place in the chronological order 2016-12-01 10:21:23 -08:00
480ef20eb1 docs(changelog): add changelog for 2.2.2 2016-12-01 09:59:23 -08:00
c066281bad docs(changelog): add changelog for 2.3.0-rc.0 2016-11-30 15:42:56 -08:00
1b9493f725 chore(release): cut the 2.3.0-rc.0 release 2016-11-30 15:42:56 -08:00
ae26504e84 fix(core): update peer dep on zone.js to ^0.7.2 2016-11-30 15:42:56 -08:00
d420080b3b docs(changelog): add changelog for 2.2.4 2016-11-30 15:19:09 -08:00
2975d8933c fix(language-service): harden against partial normalization of directives 2016-11-30 14:55:56 -08:00
43c0e9a6bb fix(compiler): fix performance regression caused by 5b0f9e2
Fixes #13146
2016-11-30 14:55:56 -08:00
f275f36081 fix(version): take all of version string after patch version 2016-11-30 14:25:11 -08:00
e628b66cca feat(build): record angular version in the dom (#13164) 2016-11-30 13:52:08 -08:00
3e73bea3e7 refactor(compiler): convert metadata classes used in summaries into interfaces (#13123)
Part of #12787
2016-11-30 10:52:51 -08:00
42cf06fa12 feat(router): add support for custom route reuse strategies 2016-11-29 23:21:41 -08:00
c4bbafc291 feat: upgrade zone.js to v0.7.1 2016-11-29 17:24:00 -08:00
2d6a003dba feat: update RxJS peer dependency to 5.0.0-rc.4
Closes #13125

RxJS from beta-12 to rc.4, has removed the `cache`
operator. (See https://github.com/ReactiveX/rxjs/blob/master/CHANGELOG.md#breaking-changes-1)
If your application relies on it, then we suggest 
that you use the one from this gist:
https://gist.github.com/robwormald/19dea0c70a6e01aadced6731aed4f9f7
2016-11-29 16:27:33 -08:00
e45b7ffcd9 fix: shrinkwrap was out of date with packages.
Rerun shrinkwrap on a clean workspace
2016-11-29 16:27:33 -08:00
627282d2c8 fix(compiler): correctly evaluate references to static functions (#13133) 2016-11-29 12:02:50 -08:00
2f7492c986 refactor(compiler): remove unneeded fields from metadata
Removes `CompileIdentifierMetadata.name` / `.moduleUrl`,
as well as `CompileTypeMetadata.name / moduleUrl` and
`CompileFactoryMetadata.name / moduleUrl`.
2016-11-28 15:19:23 -08:00
2452cd14e0 refactor(compiler): drop old codegen tests that run inside of test.sh
These tests were hard to maintain and only yielded little value,
now that we have the full integration with TypeScript.
2016-11-28 15:19:23 -08:00
bc69c74be0 fix(tsc-wrapped): still emit version 1 metadata to allow to use new components in old setups 2016-11-28 15:18:57 -08:00
897555ca78 fix(tsc-wrapped): set correct version number 2016-11-28 15:18:56 -08:00
966bcbad5a fix(compiler-cli): pin the version of tsc-wrapped 2016-11-28 15:18:56 -08:00
94b8612e4e Fix(http): invalidStateError response body
Check on null value failed with last version of mozilla.
Check on undefined type instead.
2016-11-28 14:36:32 -08:00
b2b72190f8 fix(common): update DatePipe to allow closure compilation
Quote the date formats to prevent closure renaming.  These are specified as strings in templates using DatePipes and also need to be quoted here.
2016-11-28 14:36:12 -08:00
f5c8e0989d feat(core): properly support inheritance
## Inheritance Semantics:

Decorators:
1) list the decorators of the class and its parents in the ancestor first order
2) only use the last decorator of each kind (e.g. @Component / ...)

Constructor parameters:
If a class inherits from a parent class and does not declare
a constructor, it inherits the parent class constructor,
and with it the parameter metadata of that parent class.

Lifecycle hooks:
Follow the normal class inheritance model,
i.e. lifecycle hooks of parent classes will be called
even if the method is not overwritten in the child class.

## Example

E.g. the following is a valid use of inheritance and it will
also inherit all metadata:

```
@Directive({selector: 'someDir'})
class ParentDirective {
  constructor(someDep: SomeDep) {}

  ngOnInit() {}
}

class ChildDirective extends ParentDirective {}
```

Closes #11606
Closes #12892
2016-11-28 14:12:12 -08:00
4a09251921 doc(common): fix a typo in async pipe 2016-11-28 14:11:45 -08:00
36caaaa8e4 refactor(core): remove unused import
APP_ID  was removed after 2.2.x
2016-11-28 14:11:25 -08:00
808275a9d5 feat(core): expose destroy() method on ViewRef 2016-11-28 14:10:42 -08:00
be3784c957 revert: fix(animations): blend in all previously transitioned styles into next animation if interrupted
This reverts commit ef96763fa4.
2016-11-28 13:23:52 -08:00
555301ce3a docs(changelog): add changelog for 2.2.3
original SHA: 380377139b
2016-11-27 22:11:04 -08:00
7194fc2b9e fix(language-service): make link check pass 2016-11-23 16:21:06 -08:00
2a3ca7bfcf fix(compiler-cli): fix paths in source maps to be relative
The change looks bigger than it really is because I reordered the properties to match other tsconfigs we have.

The only real change is removal of sourceRoot property.

Fixes #13040
2016-11-23 15:48:24 -08:00
4cbf8ccf05 Keep console.log that are not called during compilation. 2016-11-23 15:47:02 -08:00
a6c4490fce Check if console.error is defined 2016-11-23 15:47:02 -08:00
2c02d34c05 refactor(lint): Don't allow console.log
Enable tslint check for `console.log` as a follow-up to
https://github.com/angular/angular/issues/13018
2016-11-23 15:47:01 -08:00
6c2d931744 chore: make test.sh work again
Previously, `test.sh` relied on calling `build.sh` first
2016-11-23 14:23:05 -08:00
86ffa884b7 fix(build): update versions of umd bundles (#13038)
Fixes #13037
2016-11-22 13:39:41 -08:00
3e548de99d Revert "fix(router): guards restor an incorrect url when used with skipLocationChange"
This reverts commit ad20d7d260.
2016-11-22 13:31:33 -08:00
909268036b test(upgrade): remove setTimeout from lifecycle hook tests (#13027)
* test(upgrade): remove unnecessary NO_ERRORS_SCHEMA

* test(upgrade): remove `setTimeout` from lifecycle hook tests

Closes #13019
2016-11-22 09:21:03 -08:00
519a324454 feat(language-service): add services to support editors (#12987) 2016-11-22 09:10:23 -08:00
ef96763fa4 fix(animations): blend in all previously transitioned styles into next animation if interrupted (#13014)
Closes #13013
Closes #13014
2016-11-21 15:46:59 -08:00
7dcca307d9 fix(closure): quote date pattern aliases (#13012)
Quota the pattern aliases to prevent closure renaming. These are quoted in DatePipe and also need to be quoted here.
2016-11-21 11:45:48 -08:00
491d5a22a9 refactor(compiler): allow control of StaticSymbol lifetime (#12986) 2016-11-18 16:58:14 -08:00
44572f114f refactor(ngUpgrade): Small cleanup with Testability API and resumeBootstrap (#12926)
* With non-static ngUpgrade apps, callbacks to `whenStable` were being invoked with the wrong
  context
* With non-static ngUpgrade apps, `resumeBootstrap` was being run outside the NgZone
* Remove redundent `whenStableContext` variable

Neither of the first two problems were actually causing bugs (as far as I know), but they *might*
have caused problems in the future.

Inspired by https://github.com/angular/angular/pull/12910, but for non-static apps.
2016-11-18 14:30:47 -08:00
1ef4696cb7 fix(upgrade): call ng1 lifecycle hooks (#12875) 2016-11-18 13:46:49 -08:00
07a986d330 fix(changelog): replace beta.1 with beta.0 (#12961) 2016-11-18 12:37:26 -08:00
59d2b4c831 refactor(compiler): further minor fixes 2016-11-18 10:04:14 -08:00
2a5bd2f345 refactor(compiler): Reintroduce ReflectorHost and move Extractor into @angular/compiler 2016-11-18 10:04:14 -08:00
3c06a5dc25 refactor(comiler): various cleanups 2016-11-18 10:04:14 -08:00
adeea5d86a refactor(compiler): renames
- `NgHost` to `CompilerHost`
- `AotCompilerHost.resolveFileToImport` to `AotCompilerHost.fileNameToModuleName`
- `AotCompilerHoset.resolveImportToFile` to `AotCompilerHost.moduleNameToFileName`
2016-11-18 10:04:14 -08:00
dddbb1c1cb refactor(tsc-wrapped): collect all exported functions and classes and bump metadata version from 1 to 2
This is needed to resolve symbols without `.d.ts` files.
This bumps the version of the metadata from 1 to 2.
This adds logic into `ng_host.ts` to automatically upgrade
version 1 to version 2 metadata by adding the exported symbols
from the `.d.ts` file.
2016-11-18 10:04:14 -08:00
bccf0e69dc fix(compiler): fix versions of @angular/tsc-wrapped 2016-11-18 10:04:14 -08:00
b15039d228 refactor(compiler): move symbol extraction to AotCompiler 2016-11-18 10:04:14 -08:00
2235048432 refactor(compiler): add createAotCompiler factory
Also adds 2 more methods to the `AotCompilerHost`:
- `loadResource`
- `resolveFileToImport`
2016-11-18 10:04:14 -08:00
484119e59f refactor(compiler): remove asset: urls
These urls were just relicts from Dart.
2016-11-18 10:04:14 -08:00
24099bdbd2 refactor(compiler): move findDeclaration into the StaticReflector
Previously, this was part of the `AotCompilerHost`.
The `AotCompilerHost` is now also greatly simplified.
2016-11-18 10:04:14 -08:00
912ca44979 refactor(compiler): move static_reflector into @angular/compiler and rename files
- `src/runtime_compiler.ts` -> `src/jit/compiler.ts`
- `src/compiler.ts` -> `src/jit/compiler_factory.ts`
- `src/offline_compiler` -> `src/aot/compiler.ts`

Part of #12867
2016-11-18 10:04:14 -08:00
664a6273e1 feature(tsc-wrapped): add option for closure compiler JSDoc annotations 2016-11-18 09:37:40 -08:00
c1a62e2154 feat(tools): allow disabling annotation lowering 2016-11-18 09:37:40 -08:00
aac37bedc0 chore(build): update package.json versions during build (#12957) 2016-11-18 09:24:57 -08:00
a3884db87c fix(ci): pin version of npm on CircleCI (#12954) 2016-11-17 17:27:51 -08:00
fc5ac1ebc4 fix(benchmarks): use sanitized style values (#12943) 2016-11-17 15:18:10 -08:00
ad20d7d260 fix(router): guards restor an incorrect url when used with skipLocationChange
Closes #12825
2016-11-17 14:10:59 -08:00
602522beb2 fix(router): support redirects to named outlets
Closes #12740, #9921
2016-11-17 14:10:59 -08:00
4e047302f2 chore(release): cut the 2.3.0-beta.0 realse and add change log 2016-11-17 11:59:03 -08:00
419a812f04 chore(release): cut angular 2.2.1 2016-11-17 11:51:25 -08:00
f340e1a414 fix(tools): fix error when running test.sh (#12927) 2016-11-16 13:35:31 -08:00
481c9b3258 refactor(compiler): allows synchronous retrieving of metadata (#12908)
Allows non-normalized metadata to be retrieved synchronously.

Related to #7482
2016-11-16 10:22:11 -08:00
8b2dfb2eca fix(core): support ngTemplateOutlet in production mode (#12921)
Fixes #12911
2016-11-16 10:00:18 -08:00
824ea8406c docs(upgrade/static): improve API docs with examples
Closes #12717
2016-11-16 09:18:17 -08:00
1f96a93f59 chore(public_api): remove Angular 1 types from upgrade/static API 2016-11-16 09:18:10 -08:00
009d545787 chore(examples): add upgrade/static example 2016-11-16 09:18:10 -08:00
53c25210a6 chore(examples): support upgrade/static examples 2016-11-16 09:18:10 -08:00
927aa69726 fix(router): add a banner file for the router (#12919) 2016-11-16 09:17:19 -08:00
ce89039036 fix(platform_browser): fix disableDebugTools() (#12918) 2016-11-16 09:16:40 -08:00
42198cd7d5 fix(ngUpgrade): make AoT ngUpgrade work with the testability API and resumeBootstrap() (#12910) 2016-11-16 01:04:56 -08:00
d6ba092a27 build(build.sh): echo before building examples 2016-11-15 20:59:37 -08:00
773b31de8f fix(router): should not create a route state if navigation is canceled (#12868)
Closes #12776
2016-11-15 19:00:20 -08:00
f79b320fc4 refactor(forms): remove facade (#12558) 2016-11-15 18:48:34 -08:00
6a212fd561 fix(router): removes a peer dependency from router to upgrade 2016-11-15 18:37:08 -08:00
be010a292a fix(animations): only pass in same typed players as previous players into web-animations (#12907)
Closes #12907
2016-11-15 17:47:21 -08:00
7c36e7f956 chore(router): remove @angular/upgrade peer dep (#12896) 2016-11-15 14:00:11 -08:00
13ba2f90b9 refactor(http): remove all facade methods from http module (#12870) 2016-11-15 09:19:14 -08:00
75277cd94b fix(tsickle): support ctorParams in function closure (#12876)
See https://github.com/angular/tsickle/issues/261 for context.
2016-11-15 09:19:00 -08:00
46d150266b feat(router_link): add skipLocationChange and replaceUrl inputs (#12850) 2016-11-14 18:30:13 -08:00
1b5384ee54 feat(core): expose ViewRef as ChangeDetectorRef
closes #12722

This is helpful when manually dirty checking embedded views.
2016-11-14 17:01:41 -08:00
9f7d32a326 feat(core): add attachView / detachView to ApplicationRef
This feature is useful to allow components / embedded views
to be dirty checked if they are not placed in any `ViewContainer`.

Closes #9293
2016-11-14 17:01:35 -08:00
9de76ebfa5 fix(animations): retain styling when transition destinations are changed (#12208)
Closes #9661
Closes #12208
2016-11-14 16:59:06 -08:00
46023e4792 fix(select): allow for null values in HTML select options bound with ngValue
closes #12829
2016-11-14 16:47:14 -08:00
b55aaf094f fix: allow for null values in HTML select options bound with ngValue
This corrects the case of <option [ngValue]="null"> binding a string like "{0: null}" to the model instead of an actual null object.

Closes #10349
2016-11-14 16:47:09 -08:00
d90b622fa4 fix: allow for null values in HTML select options bound with ngValue
This corrects the case of <option [ngValue]="null"> binding a string like "{0: null}" to the model instead of an actual null object.

Closes #10349
2016-11-14 16:47:09 -08:00
79e2bb9291 refactor(core): remove dead code (#12871) 2016-11-14 16:44:25 -08:00
efbbefd353 fix(platform-browser): enable AOT
closes #12783
2016-11-14 12:57:11 -08:00
c2fae72bc6 feat(router): register router with ngprobe 2016-11-14 12:57:05 -08:00
7908679c4b fix(compiler): assert xliff messages have translations
fixes #12815
closes #12604
2016-11-14 12:55:56 -08:00
9ed9ff40b3 test(compiler): improve xliff tests 2016-11-14 12:55:48 -08:00
2f14415836 fix(compiler): updates hash algo for xmb/xtb files 2016-11-14 12:55:48 -08:00
76e4911e8b fix(core): fix placeholders handling in i18n.
Prior to this commit, translations were built in the serializers. This
could not work as a single translation can be used for different source
messages having different placeholder content.

Serializers do not try to replace the placeholders any more.
Placeholders are replaced by the translation bundle and the source
message is given as parameter so that the content of the placeholders is
taken into account.

Also XMB ids are now independent of the expression which is replaced by
a placeholder in the extracted file.
fixes #12512
2016-11-14 12:55:48 -08:00
ed5e98d0df fix(core): misc i18n fixes 2016-11-14 12:55:48 -08:00
146af1fed9 refactor(core): simplify i18n serializers code 2016-11-14 12:55:48 -08:00
c60ba7a72f refactor(core): remove ListWrapper from i18n 2016-11-14 12:55:48 -08:00
05beffe0d0 test(core): fix a typo in the i18n integration spec 2016-11-14 12:55:48 -08:00
08c038ebd9 fix(core): xmb serializer uses decimal messaged IDs
fixes #12511
2016-11-14 12:55:48 -08:00
582550a90d feat(core): implements a decimal fingerprint for i18n 2016-11-14 12:55:48 -08:00
1d53a870dd fix(http): return request url if it cannot be retrieved from response
closes #12837
2016-11-14 12:54:43 -08:00
a0c58a6b5c fix(http): correctly handle response body for 204 status code
closes #12830
fixes #12393
2016-11-14 12:36:22 -08:00
d3eff6c483 refactor(xhr_backend): remove facade 2016-11-14 12:36:16 -08:00
2524d510bc chore(release): cut the 2.2.0 upgrade-firebooster release 2016-11-14 11:26:03 -08:00
8f5dd1f11e chore(lint): enforce no var keyword rule 2016-11-12 16:40:17 -08:00
77ee27c59e refactor(): use const and let instead of var 2016-11-12 16:40:17 -08:00
73593d4bf3 perf(platform-browser): cache plugin resolution in the EventManager
closes #12824
2016-11-11 17:19:47 -08:00
a965d11cce fix(compiler): generate safe access strictNullChecks compatible code (#12800)
fixes #12795
2016-11-11 17:12:17 -08:00
52be848f94 fix(router): incorrect injector is used when instantiating components loaded lazily (#12817) 2016-11-11 17:12:00 -08:00
69dfcf7385 docs(forms): add inline docs why ngModel runs a 2nd change detection run (#12821)
Related to #11895
2016-11-11 15:24:11 -08:00
785b7b640e fix(router): Route.isActive also compares query params (#12321) 2016-11-11 13:23:47 -08:00
e5a753e111 fix(router): router should not swallow "unhandled" errors
closes #12802
2016-11-11 13:22:19 -08:00
768cddbe62 fix(events): provide the ability to register global hammer.js events
closes #12797
2016-11-11 11:15:49 -08:00
92f244aa26 refactor(events): remove facade and clean up 2016-11-11 11:15:43 -08:00
2a4bf9a0df fix(router): avoid router initialization for non root components
closes #12338
closes #12814
2016-11-11 11:15:17 -08:00
45ddd6ba78 cleanup(forms): remove facade (#12804) 2016-11-11 10:47:34 -08:00
7886561997 fix(router): check if windows.console exists before using it (#12348) 2016-11-11 10:46:53 -08:00
752edca81b test(core): ngOnDestroy called before output events are detached (#9946)
closes #6984
closes #5436
2016-11-11 10:27:32 -08:00
1bd858fb43 build(examples): upgrade to protractor 4.0.9 (#12803)
closes #12798
2016-11-10 18:13:11 -08:00
fcb4e66493 refactor(compiler): introduce summaries for metadata (#12799)
This does not yet introduce loading / serialization of summaries.

Part of #12787
2016-11-10 16:27:53 -08:00
ef881475e9 fix(forms): check if registerOnValidatorChange exists on validator before trying to invoke it (#12801)
closes #12593
2016-11-10 16:20:59 -08:00
458ca7112a build(publish): remove unneeded add-license-to-rx (#12734) 2016-11-10 15:56:14 -08:00
2aba8b0ff2 fix(common): no TZ Offset added by DatePipe for dates without time (#12380) 2016-11-10 14:57:04 -08:00
77dc1ab675 fix(router): throw an error when encounter undefined route (#12389) 2016-11-10 14:55:10 -08:00
3052fb234f fix(router): ignore null or undefined query parameters (#12333) 2016-11-10 14:41:19 -08:00
79383ce150 refactor(compiler): never create CompileDirectiveMetadata with not loaded resources (#12788)
Part of #12787
2016-11-10 14:07:30 -08:00
c3c0e2e2a2 refactor(compiler): add span to TemplateBinding (#12792)
fix(compiler): corrected error location for implicit templates expressions
2016-11-10 13:15:09 -08:00
44a142fc02 chore(playground): use base64-js from npm
closes #12471
2016-11-10 12:08:04 -08:00
3d9d839c6c refactor(playground): make playground great again 2016-11-10 12:07:51 -08:00
69f87ca075 fix(tools): harden colletor against invalid asts (#12793) 2016-11-10 11:58:55 -08:00
f224ca1461 ci(BrowserStack): increase timeout to avoid failures (#12786)
relates to #12578
2016-11-10 11:58:06 -08:00
19e869e7c9 fix(animations): ensure animations work with web-workers (#12656) 2016-11-10 11:53:50 -08:00
7cab30f85d refactor(compiler-cli): add position data to static reflector errors (#12782) 2016-11-09 16:29:22 -08:00
73407351e7 feat(router): add support for custom url matchers
Closes #12442
Closes #12772
2016-11-09 16:24:58 -08:00
2c110931f8 fix(router): do not require the creation of empty-path routes when no url left
Closes #12133
2016-11-09 16:24:49 -08:00
2ced2a8a5a refactor(compiler): misc updates (#12773) 2016-11-09 16:23:41 -08:00
634b3bb88b feat(core): map 'for' attribute to 'htmlFor' property (#10546)
This improves ergonomics a bit by allowing people to write:
`<label [for]="ctxProp"></label>`.
This is similar to the existing class -> className mapping.

Closes #7516
2016-11-09 15:21:27 -08:00
4595a61aeb refactor(compiler-cli): refactor imports in codegen to enable rollup (#12781) 2016-11-09 15:17:24 -08:00
f80a157b65 fix(animations): ensure web-animations are caught within the Angular zone
Closes #11881
Closes #11712
Closes #12355
Closes #11881
Closes #12546
Closes #12707
Closes #12774
2016-11-09 15:16:34 -08:00
6e35d13fbc feat(router): add a provider making angular1/angular2 integration easier (#12769) 2016-11-09 13:33:33 -08:00
fe35bc34f6 fix(animations): allow animations to be destroyed manually (#12719)
Closes #12456
Closes #12719
2016-11-08 16:21:28 -08:00
ad3bf6c54f fix(core): apply host attributes to root elements (#12761)
Fixes #12744
2016-11-08 15:46:55 -08:00
a0e9fde653 fix(animations): always normalize style properties and values during compilation (#12755)
Closes #11582
Closes #12481
Closes #12755
2016-11-08 15:45:30 -08:00
3dc61779f0 fix(DatePipe): handle empty string (#12374) 2016-11-08 15:45:12 -08:00
09092ac3c2 fix(forms): getRawValue returns any instead of Object (#12599) 2016-11-08 15:44:36 -08:00
778e6ad3b4 refactor: cleanup ICU message syntax 2016-11-08 15:44:18 -08:00
55dc0e4a5f fix(compiler): use the other case by default in ICU messages 2016-11-08 15:44:18 -08:00
4708b248d5 fix(common): I18nSelectPipe selects other case on default 2016-11-08 15:44:18 -08:00
7694f974af refactor: remove some facades (#12731) 2016-11-08 15:43:24 -08:00
acbf1d859c fix(core): fix pseudo-selector shimming (#12754)
fixes #12730
fixes #12354
2016-11-07 13:56:04 -08:00
f3793b5953 fix(NgClass): throw a descriptive error when CSS class is not a string (#12662)
Fixes #12586
2016-11-07 12:23:31 -08:00
22c021c57f fix(compiler): support more than 9 interpolations (#12710)
Fixes #10253
2016-11-07 12:23:03 -08:00
d8f23f4b7f fix(common): NgSwitch - don’t create the default case if another case matches (#12726)
This also simplifies the implementation of `NgSwitch`.

Closes #11297
Closes #9420
2016-11-07 12:22:36 -08:00
32fcec9fcb chore(npm): remove dependency on minimatch 2016-11-07 10:32:00 -08:00
78039b41d6 chore(build): remove unused build/util 2016-11-07 10:32:00 -08:00
89fd54e8e3 docs(url_tree):fix typo(UrlSegment path property's comment part -> path) (#12728) 2016-11-07 10:27:47 -08:00
77cbf7f2bb fix(closure): suppress two more closure compiler checks in codegen (#12698) 2016-11-04 15:18:05 -07:00
383f23b578 fix(animations): always trigger animations after the change detection check (#12713)
This patch ensures that animations are run outside of change detection
thus allowing for start and done callbacks to modify application data
without causing a cycle loop.

Closes #12713
2016-11-04 15:15:27 -07:00
2a3f4d7b17 refactor: kill MapWrapper 2016-11-04 13:27:38 -07:00
ec92f4b198 refactor: remove keys() and values() from MapWrapper 2016-11-04 13:27:38 -07:00
121e5080aa fix(http): preserve header case when copying headers (#12697) 2016-11-04 13:26:38 -07:00
fe1d0e29c5 feat(UpgradeComponent): add support for require
This commit also adds/improves/fixes some `UpgradeComponent` tests.
2016-11-04 11:16:28 -07:00
469010ea8e feat(UpgradeComponent): add/improve support for lifecycle hooks
Add support for the `$postDigest()` and `$onDestroy()` lifecycle hooks.
Better align the behavior of the `$onChanges()` and `$onInit()` lifecycle hooks
with Angular 1.x:

- Call `$onInit()` before pre-linking.
- Always instantiate the controller before calling `$onChanges()`.
2016-11-04 11:16:28 -07:00
f0cdb428f5 fix(compiler): don't convert undefined to null literals (#11503)
Fixes #11493
2016-11-04 10:55:21 -07:00
051d74802a fix(core): ensure that component views that have no bindings recurse into nested components / view containers. 2016-11-04 10:50:27 -07:00
f2bbef3e33 fix(core): allow to query content of templates that are stamped out at a different place
Previously, if a `TemplateRef` was created in a `ViewContainerRef`
at a different place, the content was not query able at all.

With this change, the content of the template can be queried
as if it was stamped out at the declaration place of the template.

E.g. in the following example, the `QueryList<ChildCmp>` will
be filled once the button is clicked.

```
@Component({
  selector: ‘my-comp’,
  template: ‘<button #vc (click)=“createView()”></button>’
})
class MyComp {
  @ContentChildren(ChildCmp)
  children: QueryList<ChildCmp>;

  @ContentChildren(TemplateRef)
  template: TemplateRef;

  @ViewChild(‘vc’, {read: ViewContainerRef})
  vc: ViewContainerRef;

  createView() {
    this.vc.createEmbeddedView(this.template);
  }
}

@Component({
  template: `
<my-comp>
  <template><child-cmp></child-cmp></template>
</my-comp>
`
})
class App {}
```

Closes #12283
Closes #12094
2016-11-04 10:50:27 -07:00
80d36b8db4 docs(CONTRIBUTING.md): fix stackoverflow broken link url (#12705) 2016-11-04 10:21:11 -07:00
e3687706c7 refactor(compiler): minor cleanup 2016-11-03 16:29:51 -07:00
648ce5981b perf(core): don’t use DomAdapter nor zone for regular events 2016-11-03 16:29:51 -07:00
9c23884da4 perf(compiler): introduce direct rendering
This allows to attach / detach embedded views and projected nodes
in a faster way.
2016-11-03 16:29:51 -07:00
d708a8859c perf(platform-browser): don’t use DomAdapter any more
But use the DOM apis directly.
This also creates a separate `ServerRenderer` implementation
for `platform-server` as it previously reused the `BrowserRenderer`.
2016-11-03 16:29:51 -07:00
9ddf9b3d3d fix(router): advance a route only after its children have been deactivated (#12676)
Closes #11715
2016-11-03 16:26:10 -07:00
69f006cd89 docs(change_detection): fix typo(ChangeDetectorStatus enum comment CheckedOnce -> CheckOnce) (#12683) 2016-11-03 11:23:20 -07:00
4aaae3eada docs(common): fix a typo in ngStyle API docs 2016-11-03 10:27:05 -07:00
2e78b76fcf fix(router): resolve guard observables on the first emit (#10412) 2016-11-02 21:56:04 -07:00
b2cf379d1c fix(enableDebugTools): create AngularTools by merging into context.ng (#12003)
When using `enableDebugTools` the tools are merged into `context.ng` to prevent `ng.probe` and `ng.coreTokens` from being clobbered.

Fixes #12002
2016-11-02 21:55:49 -07:00
e25baa08b3 fix(router): correctly export concatMap operator in es5 (#12430) 2016-11-02 21:55:02 -07:00
7103754178 fix(closure): suppress closure compiler suspiciousCode check in codegen (#12666) 2016-11-02 21:11:30 -07:00
1a069e8372 refactor(compiler): cleanups 2016-11-02 20:58:48 -07:00
0fc11a43f1 perf(core): use array.push / array.pop instead of splice if possible 2016-11-02 20:58:48 -07:00
0e3d655220 refactor(compiler): remove view factories, use view classes directly 2016-11-02 20:58:48 -07:00
7c5cc9bc41 refactor(compiler): initialize RenderComponentType eagerly
This moves the usage of `APP_ID` into the `DomRenderer`.
2016-11-02 20:58:48 -07:00
5f1dddc5d0 refactor(compiler): cleanups 2016-11-02 17:06:27 -07:00
20a4f9923f refactor(compiler): remove view.parentInjector 2016-11-02 17:06:27 -07:00
e7c00be19d refactor(compiler): rename AppElement into ViewContainer 2016-11-02 17:06:27 -07:00
74ede9aa9b refactor(core): don’t store view factory in TemplateRef
Instead, generate `createEmbeddedView`.
2016-11-02 17:06:27 -07:00
d1035da85c refactor(compiler): don’t use AppElements for creating component views 2016-11-02 17:06:27 -07:00
13533d2a30 refactor(compiler): remove AppElement.initComponent 2016-11-02 17:06:27 -07:00
953cb50fa5 chore(release): cut v2.2.0-rc.0 2016-11-03 00:28:29 +01:00
3fffcf6645 chore: update changelog 2016-11-02 12:34:21 -07:00
d509ee078b fix(router): reset URL to the stable state when a navigation gets canceled
Closes #10321
2016-11-02 12:25:23 -07:00
8e221b826f fix(router): routerLink should not prevent default on non-link elements 2016-11-02 12:25:23 -07:00
830a780cb3 fix(router): CanDeactivate receives a wrong component
Closes #12592
2016-11-02 12:25:23 -07:00
6fda97287e fix(compiler): support multiple components in a view container 2016-11-01 14:21:40 -07:00
234c5599f1 refactor(compiler): remove unused constructor query support 2016-11-01 11:29:15 -07:00
f6710fefeb refactor(compiler): make view.disposable array null if empty 2016-11-01 11:29:15 -07:00
bda1909ede refactor(compiler): remove view.rootNodes and view.projectableNodes
They are replaced by generated visitor functions `view.visitRootNodes` / `view.visitProjectableNodes`.
2016-11-01 11:29:15 -07:00
b3e3cd3add refactor(compiler): inline view.contentChildren 2016-11-01 11:29:14 -07:00
e5fdf4c70a refactor(compiler): inline view.viewChildren in generated code 2016-11-01 11:29:14 -07:00
97471d74b6 refactor(compiler): remove unused subscriptions in view 2016-11-01 11:29:14 -07:00
1de04b23b1 fix(router): call data observers when the path changes 2016-11-01 11:28:43 -07:00
a178bc6c83 fix(compiler): dedupe NgModule declarations, …
This is important so that we don’t generate things multiple times.
2016-10-31 14:43:50 -07:00
642c1db9ef fix(compiler): Don’t throw on empty property bindings
Closes #12583
2016-10-31 14:43:50 -07:00
579deeb9c5 style(platform-browser): clean up hammer gestures 2016-10-31 14:43:05 -07:00
bad58824a0 refactor(playground): update gestures playground to use latest hammer.js 2016-10-31 14:43:04 -07:00
5494169fb4 style: make internal members accessibility explicit 2016-10-31 14:25:53 -07:00
5a3d7a62a2 style: merge imports from the same modules 2016-10-31 14:25:53 -07:00
a382d6dd20 style: add missing semicolons 2016-10-31 14:25:53 -07:00
52bf188b8f style: add missing copyright headers 2016-10-31 14:25:53 -07:00
6f412bb449 chore(lint): extend linting to all modules and tools 2016-10-31 14:24:27 -07:00
e9fd8645ed fix(core): improve error when multiple components match the same element
Closes #7067
2016-10-31 11:28:03 -07:00
a0aecac0e5 chore(lint): replace enforce-copyright-header rule with the native equivalent 2016-10-31 11:27:35 -07:00
938ed1c76d chore(lint): deduplicate tslint dependency 2016-10-31 11:27:34 -07:00
eb8288f76c chore(package): remove unused lodash and sorted-object 2016-10-31 11:26:59 -07:00
0936ceeab4 chore(npm): clean up clean-shrinkwrap script 2016-10-31 11:26:59 -07:00
e0ad413a8e style(tests): clean up testing_public_spec (#11452) 2016-10-31 11:26:38 -07:00
3045d02b9a docs(pipes): minor fix and improvements 2016-10-31 12:39:21 +01:00
e86573bac8 chore(lint): replace gulp check-task with tslint no-jasmine-focus rule
fixes #11800
2016-10-28 15:53:15 -07:00
0a94845435 chore(lint): replace duplicate-module-import rule with no-duplicate-imports 2016-10-28 15:53:15 -07:00
262bd23b84 chore(lint): add vrsource tslint rules dependency 2016-10-28 15:53:15 -07:00
7b8dae19af refactor(facade): cleanup Intl facade 2016-10-28 15:52:52 -07:00
7c16ef942e feat(core): add the find method to QueryList 2016-10-28 15:34:47 -07:00
a318b57257 refactor(core): removed extraneous interface from QueryList test 2016-10-28 15:34:47 -07:00
fe47e6b783 fix(router): rerun resolvers when url changes
Closes #12603
2016-10-28 15:17:00 -07:00
091c390032 fix(router): run navigations serialy
Closes #11754
2016-10-28 14:56:08 -07:00
e391cacdf9 fix(compiler): don’t double bind functions
This fixes a performance regressions introduced by 178fb79b5c.

Also makes properties in the directive wrapper private
so that closure compiler can minify them better.
2016-10-28 11:17:12 -07:00
32feb8a532 refactor(compiler): generate host listeners in DirectiveWrappers
Part of #11683
2016-10-27 16:09:01 -07:00
a664aba2c9 build: ensure necessary symlinks created on windows
Bash scripts create and tear down symlinks on Windows. These use the
packages.txt file as input to identify the symlink locations. The
scripts ignored the last line in packages.txt if it didn't end with a
newline. Also, one location was missing. Resolve both issues.

Closes #12422
2016-10-27 12:13:39 -07:00
d520fae70e refactor(upgrade): spec cleanup 2016-10-27 12:12:55 -07:00
fa93fd672e fix(upgrade): silent bootstrap failures
fixes #12062
2016-10-27 12:12:54 -07:00
f4be2f907d docs(changelog): fix changelog title 2016-10-27 20:38:56 +02:00
2ea27a76d3 docs(changelog): update changelog with changes in v2.1.2 2016-10-27 20:30:48 +02:00
ec0acf9a1b chore(release): cut the 2.2.0-beta.0 release 2016-10-27 18:28:07 +02:00
a26dd28bdb refactor(upgrade): re-export the new static upgrade APIs on new entry
Add upgrade-static.umd.js bundles
This allows depending on it without getting a transitive dependency on compiler.

BREAKING CHANGE:

Four newly added APIs in 2.2.0-beta:
downgradeComponent, downgradeInjectable, UpgradeComponent, and UpgradeModule
are no longer exported by @angular/upgrade.
Import these from @angular/upgrade/static instead.
2016-10-26 15:14:22 -07:00
7742ec00e7 fix: remove double exports of template_ast 2016-10-26 15:14:00 -07:00
2b5c983c13 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-26 14:56:57 -07:00
ef153649b3 fix(compiler-cli): fix types 2016-10-26 14:56:27 -07:00
d321b0ebf5 fix(selectors): use Maps instead of objects 2016-10-26 14:55:59 -07:00
b4265e0685 fix(xsrf): overwrite already set xsrf header 2016-10-26 14:55:24 -07:00
178fb79b5c refactor(compiler): move host properties into DirectiveWrapper
Part of #11683
2016-10-26 14:32:24 -07:00
5a7a58b1e0 refactor(compiler): make arguments in InlineArray optional. 2016-10-26 14:32:24 -07:00
f66ac821a2 refactor(compiler): extract createCheckBindingStmt into compiler_util
Part of #11683
2016-10-26 14:32:24 -07:00
fe299f4dfc refactor(compiler): minor cleanups 2016-10-26 14:32:24 -07:00
4cac650675 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-26 14:32:24 -07:00
cb7643ccea refactor(compiler): introduce ClassBuilder.
Part of #11683
2016-10-26 14:32:23 -07:00
faa3478514 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-26 14:32:23 -07:00
bc3f4bc816 refactor(compiler): extract BindingParser
Needed so that we can parse directive host bindings independent of templates.

Part of #11683
2016-10-26 14:32:23 -07:00
c9f58cf78c feat(router): export routerLinkActive w/ isActive property 2016-10-26 14:08:22 -07:00
6ccbfd41dd fix(router): preserve resolve data
Closes #12306
2016-10-26 13:53:00 -07:00
7d2554baa1 tests(router): add a test showing how to handle resovle errors 2016-10-26 13:52:59 -07:00
52a853e257 fix(router): change router not to deactivate aux routes when navigating from a componentless routes 2016-10-26 13:52:59 -07:00
8f2fa0f766 fix(router): disallow component routes with named outlets
Closes #11208, #11082
2016-10-26 13:52:59 -07:00
fc60fa790c fix(router): add a test to make sure canDeactivate guards are called for aux routes
Closes #11345
2016-10-26 13:52:58 -07:00
b74185369f fix(router): canDeactivate guards are not triggered for componentless routes
Closes #12375
2016-10-26 13:52:58 -07:00
7221632228 fix(CompilerCli): assert that all pipes and directives are declared by a module 2016-10-25 18:17:18 -07:00
02f1222a8d docs(common): minor corrections/improvements for NgClass (#12327) 2016-10-25 00:12:09 +02:00
c27ce7318f 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-25 00:10:03 +02:00
a838aba756 fix(compiler): walk third party modules (#12453)
fixes #11889
fixes #12428
2016-10-24 22:28:23 +02:00
bfc97ff2cd 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-21 15:17:57 -07:00
57051f01ce refactor: remove most facades (#12399) 2016-10-21 15:14:44 -07:00
e319cfefc3 docs(changelog): fix minor typo (#12429) 2016-10-21 14:27:07 -07:00
444014ad96 docs(changelog): add 2.1.1 changelog 2016-10-20 15:49:59 -07:00
867494a060 fix(compiler): don't access view local variables nor pipes in host expressions (#12396)
Fixes #12004
Closes #12071
2016-10-20 15:24:58 -07:00
69ad99dca6 chore(release): cut the 2.2.0-beta.0 release and add changelog 2016-10-20 14:36:46 -07:00
da5fc696bb fix(router): do not update primary route if only secondary outlet is given (#11797) 2016-10-20 10:59:08 -07:00
b44b6ef8f5 fix(router): module loader should start compiling modules when stubbedModules are set (#11742) 2016-10-20 10:58:53 -07:00
0f21a5823b cleanup(router): add a test verifying than NavigationEnd is not emitted after NavigationCancel 2016-10-20 10:56:12 -07:00
5ae6915600 fix(router): fix lazy loading triggered by redirects from wildcard routes
Closes #12183
2016-10-20 10:56:12 -07:00
8b9ab44eee feat(router): add support for ng1/ng2 migration (#12160) 2016-10-20 10:44:44 -07:00
b0a03fcab3 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 10:41:43 -07:00
c951822c35 refactor(compiler): don’t use the OfflineCompiler in extract_i18n 2016-10-20 10:41:43 -07:00
acda82c1ed refactor(compiler): remove private exports
All of `@angular/compiler` is private, so we can export
everything we need directly.
2016-10-20 10:41:43 -07:00
a8815d6b08 chore(ci): re-enable browserstack tests in ci 2016-10-20 10:01:51 -07:00
d6791ff0e0 feat(ngUpgrade): add support for AoT compiled upgrade applications
This commit introduces a new API to the ngUpgrade module, which is compatible
with AoT compilation. Primarily, it removes the dependency on reflection
over the Angular 2 metadata by introducing an API where this information
is explicitly defined, in the source code, in a way that is not lost through
AoT compilation.

This commit is a collaboration between @mhevery (who provided the original
design of the API); @gkalpak & @petebacondarwin (who implemented the
API and migrated the specs from the original ngUpgrade tests) and @alexeagle
(who provided input and review).

This commit is an starting point, there is still work to be done:

* add more documentation
* validate the API via internal projects
* align the ngUpgrade compilation of A1 directives closer to the real A1
  compiler
* add more unit tests
* consider support for async `templateUrl` A1 upgraded components

Closes #12239
2016-10-19 15:27:49 -07:00
a2d35641e3 chore(tslint.json): semicolon rule expects an array 2016-10-19 22:38:14 +01:00
76dd026447 refactor: remove some facades (#12335) 2016-10-19 13:42:39 -07:00
0ecd9b2df0 chore(ci): make browserstack tests optional until they are fixed 2016-10-19 10:41:00 -07:00
0e9503b500 feat(forms) range values need to be numbers instead of strings (#11792) 2016-10-19 10:12:13 -07:00
f77ab6a2d2 feat(datePipe): support narrow forms for month and weekdays (#12297)
Closes #12294
2016-10-19 10:05:13 -07:00
97bc97153b feat(forms): add ng-pending CSS class during async validation (#11243)
Closes #10336
2016-10-19 09:56:31 -07:00
445e5922ec feat(forms): make 'parent' a public property of 'AbstractControl' (#11855) 2016-10-19 09:55:50 -07:00
b9fc090143 feat(forms): Added emitEvent to AbstractControl methods (#11949)
* feat(forms): Added emitEvent to AbstractControl methods

* style(forms): unified named parameter
2016-10-19 09:54:54 -07:00
592f40aa9c feat(forms): add hasError and getError to AbstractControlDirective (#11985)
Allows cleaner expressions in template-driven forms.

Before:

    <label>Username</label><input name="username" ngModel required #username="ngModel">
    <div *ngIf="username.dirty && username.control.hasError('required')">Username is required</div>

After:

    <label>Username</label><input name="username" ngModel required #username="ngModel">
    <div *ngIf="username.dirty && username.hasError('required')">Username is required</div>

Fixes #7255
2016-10-19 09:49:02 -07:00
24facdea2d 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-19 09:39:16 -07:00
aa2d3372a5 fix(benchmarks): fix method name in targetable spec 2016-10-19 09:39:16 -07:00
bf60418fdc feat(forms): Validator.pattern accepts a RegExp (#12323) 2016-10-19 09:37:54 -07:00
936 changed files with 50768 additions and 21709 deletions

View File

@ -1,3 +1,423 @@
<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)
### Bug Fixes
* **compiler:** don't access view local variables nor pipes in host expressions ([#12396](https://github.com/angular/angular/issues/12396)) ([867494a](https://github.com/angular/angular/commit/867494a)), closes [#12004](https://github.com/angular/angular/issues/12004) [#12071](https://github.com/angular/angular/issues/12071)
* **compiler:** walk third party modules ([#12453](https://github.com/angular/angular/issues/12453)) ([a838aba](https://github.com/angular/angular/commit/a838aba)), closes [#11889](https://github.com/angular/angular/issues/11889) [#12428](https://github.com/angular/angular/issues/12428)
* **compiler:** remove double exports of template_ast ([7742ec0](https://github.com/angular/angular/commit/7742ec0))
* **compiler:** use Maps instead of objects in selector implementation ([d321b0e](https://github.com/angular/angular/commit/d321b0e))
* **compiler-cli:** fix types ([ef15364](https://github.com/angular/angular/commit/ef15364))
* **compiler-cli:** assert that all pipes and directives are declared by a module ([7221632](https://github.com/angular/angular/commit/7221632))
* **http:** overwrite already set xsrf header ([b4265e0](https://github.com/angular/angular/commit/b4265e0))
* **router:** add a test to make sure canDeactivate guards are called for aux routes ([fc60fa7](https://github.com/angular/angular/commit/fc60fa7)), closes [#11345](https://github.com/angular/angular/issues/11345)
* **router:** canDeactivate guards are not triggered for componentless routes ([b741853](https://github.com/angular/angular/commit/b741853)), closes [#12375](https://github.com/angular/angular/issues/12375)
* **router:** change router not to deactivate aux routes when navigating from a componentless routes ([52a853e](https://github.com/angular/angular/commit/52a853e))
* **router:** disallow component routes with named outlets ([8f2fa0f](https://github.com/angular/angular/commit/8f2fa0f)), closes [#11208](https://github.com/angular/angular/issues/11208) [#11082](https://github.com/angular/angular/issues/11082)
* **router:** preserve resolve data ([6ccbfd4](https://github.com/angular/angular/commit/6ccbfd4)), closes [#12306](https://github.com/angular/angular/issues/12306)
<a name="2.2.0-beta.1"></a>
# [2.2.0-beta.1](https://github.com/angular/angular/compare/2.2.0-beta.0...2.2.0-beta.1) (2016-10-27)
### Code Refactoring
* **upgrade:** re-export the new static upgrade APIs on new entry ([a26dd28](https://github.com/angular/angular/commit/a26dd28))
### Features
* **router:** export routerLinkActive w/ isActive property ([c9f58cf](https://github.com/angular/angular/commit/c9f58cf))
### BREAKING CHANGES (only for beta version users)
* upgrade: Four newly added APIs in 2.2.0-beta:
downgradeComponent, downgradeInjectable, UpgradeComponent, and UpgradeModule are no longer exported by @angular/upgrade.
Import these from @angular/upgrade/static instead.
Note: The 2.2.0-beta.1 release also contains all the changes present in the 2.1.2 release.
# [2.1.1](https://github.com/angular/angular/compare/2.1.0...2.1.1) (2016-10-20)
### Bug Fixes
* **compiler:** generate aot code for animation trigger output events ([#12291](https://github.com/angular/angular/issues/12291)) ([6e5f8b5](https://github.com/angular/angular/commit/6e5f8b5)), closes [#11707](https://github.com/angular/angular/issues/11707)
* **compiler:** don't redeclare a var in the same scope ([#12386](https://github.com/angular/angular/issues/12386)) ([cca4a5c](https://github.com/angular/angular/commit/cca4a5c))
* **core:** fix decorator default values ([bd1dcb5](https://github.com/angular/angular/commit/bd1dcb5))
* **core:** fix property decorators ([3993279](https://github.com/angular/angular/commit/3993279)), closes [#12224](https://github.com/angular/angular/issues/12224)
* **http:** make normalizeMethodName optimizer-compatible. ([#12370](https://github.com/angular/angular/issues/12370)) ([8409b65](https://github.com/angular/angular/commit/8409b65))
* **router:** correctly export filter operator in es5 ([#12286](https://github.com/angular/angular/issues/12286)) ([27d7677](https://github.com/angular/angular/commit/27d7677))
* **router:** do not update primary route if only secondary outlet is given ([#11797](https://github.com/angular/angular/issues/11797)) ([da5fc69](https://github.com/angular/angular/commit/da5fc69))
* **router:** fix lazy loading triggered by redirects from wildcard routes ([5ae6915](https://github.com/angular/angular/commit/5ae6915)), closes [#12183](https://github.com/angular/angular/issues/12183)
* **router:** module loader should start compiling modules when stubbedModules are set ([#11742](https://github.com/angular/angular/issues/11742)) ([b44b6ef](https://github.com/angular/angular/commit/b44b6ef))
### Performance Improvements
* **common:** optimize NgSwitch default case ([fdf4309](https://github.com/angular/angular/commit/fdf4309))
<a name="2.2.0-beta.0"></a>
# [2.2.0-beta.0](https://github.com/angular/angular/compare/2.1.0...2.2.0-beta.0) (2016-10-20)
### Features
* **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)
* **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:** Added 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))
* **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)
* **router:** add support for ng1/ng2 migration ([#12160](https://github.com/angular/angular/issues/12160)) ([8b9ab44](https://github.com/angular/angular/commit/8b9ab44))
Note: The 2.2.0-beta.0 release also contains all the changes present in the 2.1.1 release.
<a name="2.1.0"></a>
# [2.1.0 incremental-metamorphosis](https://github.com/angular/angular/compare/2.1.0-rc.0...2.1.0) (2016-10-12)
@ -613,7 +1033,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`.
- `AplicationRef.registerDisposeListener` is deprecated.
- `ApplicationRef.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](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](https://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 demostrate the problem (for example for issues related to our npm packaging), please create a standalone git repository demostrating 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 demonstrate the problem (for example for issues related to our npm packaging), please create a standalone git repository demonstrating 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/javascriptguide.xml
[js-style-guide]: https://google.github.io/styleguide/jsguide.html
[jsfiddle]: http://jsfiddle.net
[plunker]: http://plnkr.co/edit
[runnable]: http://runnable.com

View File

@ -1,6 +1,6 @@
# Building and Testing Angular 2 for JS
# Building and Testing Angular
This document describes how to set up your development environment to build and test Angular 2 JS version.
This document describes how to set up your development environment to build and test Angular.
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.
## Formatting your source code
## <a name="clang-format"></a> 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,4 +137,21 @@ 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,8 +24,9 @@ with it.
* `comp: forms`: `@kara`
* `comp: http`: `@jeffbcross`
* `comp: i18n`: `@vicb`
* `comp: language service`: `@chuckjaz`
* `comp: metadata-extractor`: `@chuckjaz`
* `comp: router`: `@vsavkin`
* `comp: router`: `@vicb`
* `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: 'BS', required: false}, e2e: {target: null, required: true}},
'iOS10': {unitTest: {target: 'SL', 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: '52'},
'SL_CHROME': {base: 'SauceLabs', browserName: 'chrome', version: '54'},
'SL_CHROMEBETA': {base: 'SauceLabs', browserName: 'chrome', version: 'beta'},
'SL_CHROMEDEV': {base: 'SauceLabs', browserName: 'chrome', version: 'dev'},
'SL_FIREFOX': {base: 'SauceLabs', browserName: 'firefox', version: '46'},
'SL_FIREFOX': {base: 'SauceLabs', browserName: 'firefox', version: '50'},
'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.0',
browser_version: '10.1',
os: 'Windows',
os_version: '8'
},

View File

@ -14,12 +14,17 @@ PACKAGES=(core
platform-webworker
platform-webworker-dynamic
http
router
upgrade
router
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
@ -31,6 +36,10 @@ for ARG in "$@"; do
--bundle=*)
BUNDLE=( "${ARG#--bundle=}" )
;;
--publish)
VERSION_SUFFIX=""
REMOVE_BENCHPRESS=true
;;
*)
echo "Unknown option $ARG."
exit 1
@ -38,6 +47,10 @@ 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
@ -63,10 +76,11 @@ 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/base64-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 ====="
@ -78,7 +92,6 @@ 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 .
@ -101,14 +114,29 @@ 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
LICENSE_BANNER=${PWD}/modules/@angular/license-banner.txt
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
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}/
@ -117,6 +145,11 @@ 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
@ -148,7 +181,6 @@ 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
@ -157,9 +189,49 @@ do
cat ${UMD_TESTING_ES5_PATH} >> ${UMD_TESTING_ES5_PATH}.tmp
mv ${UMD_TESTING_ES5_PATH}.tmp ${UMD_TESTING_ES5_PATH}
fi
) 2>&1 | grep -v "as external dependency"
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
- npm install -g npm@3.6.0
test:
override:

View File

@ -58,6 +58,7 @@ 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',
@ -124,38 +125,31 @@ 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', ['check-tests', 'format:enforce', 'tools:build'], () => {
gulp.task('lint', ['format:enforce', 'tools:build'], () => {
const tslint = require('gulp-tslint');
// Built-in rules are at
// https://github.com/palantir/tslint#supported-rules
// https://palantir.github.io/tslint/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/@angular/**/*.ts',
'modules/benchpress/**/*.ts',
'./modules/**/*.ts',
'./tools/**/*.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,18 +23,26 @@ module.exports = function(config) {
'node_modules/core-js/client/core.js',
// include Angular v1 for upgrade module testing
'node_modules/angular/angular.min.js',
'node_modules/angular/angular.js',
'node_modules/angular-mocks/angular-mocks.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
@ -48,11 +56,15 @@ module.exports = function(config) {
exclude: [
'dist/all/@angular/**/e2e_test/**',
'dist/all/@angular/router/**',
'dist/all/@angular/compiler-cli/**',
'dist/all/@angular/**/*node_only_spec.js',
'dist/all/@angular/benchpress/**',
'dist/all/angular1_router.js',
'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/angular1_router.js',
'dist/examples/**/e2e_test/**',
],
@ -90,17 +102,17 @@ module.exports = function(config) {
project: 'Angular2',
startTunnel: false,
retryLimit: 3,
timeout: 600,
timeout: 1800,
pollingTimeout: 10000,
},
browsers: ['Chrome'],
port: 9876,
captureTimeout: 60000,
browserDisconnectTimeout: 60000,
captureTimeout: 180000,
browserDisconnectTimeout: 180000,
browserDisconnectTolerance: 3,
browserNoActivityTimeout: 60000,
browserNoActivityTimeout: 300000,
});
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.0-beta.12",
"rxjs": "^5.0.1",
"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() {
var curTime = unsafeWindow.performance.now();
const 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) {
var curTime = unsafeWindow.performance.now();
const curTime = unsafeWindow.performance.now();
(<any>self).port.emit('markStart', name, curTime);
}, unsafeWindow, {defineAs: 'markStart'});
exportFunction(function(name: string) {
var curTime = unsafeWindow.performance.now();
const 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
*/
var {Cc, Ci, Cu} = require('chrome');
var os = Cc['@mozilla.org/observer-service;1'].getService(Ci.nsIObserverService);
var ParserUtil = require('./parser_util');
const {Cc, Ci, Cu} = require('chrome');
const os = Cc['@mozilla.org/observer-service;1'].getService(Ci.nsIObserverService);
const ParserUtil = require('./parser_util');
class Profiler {
private _profiler: any;
@ -26,8 +26,8 @@ class Profiler {
stop() { this._profiler.StopProfiler(); }
getProfilePerfEvents() {
var profileData = this._profiler.getProfileData();
var perfEvents = ParserUtil.convertPerfProfileToEvents(profileData);
const profileData = this._profiler.getProfileData();
let 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);
};
var mod = require('sdk/page-mod');
var data = require('sdk/self').data;
var profiler = new Profiler();
const mod = require('sdk/page-mod');
const data = require('sdk/self').data;
const 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[] {
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;
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;
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[] {
}
};
var samples = perfProfile.threads[0].samples;
const 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 (var i = 0; i < samples.length; ++i) {
var sample = samples[i];
var sampleTime = sample.time;
for (let i = 0; i < samples.length; ++i) {
const sample = samples[i];
const sampleTime = sample.time;
// Add all the frames into a set so it's easier/faster to find the set
// differences
var sampleFrames = new Set();
const 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.
var previousSampleTime = (i == 0 ? /* not used */ -1 : samples[i - 1].time);
const 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.
var lastSampleTime = samples[samples.length - 1].time;
const 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
*/
var q = require('q');
var FirefoxProfile = require('firefox-profile');
var jpm = require('jpm/lib/xpi');
var pathUtil = require('path');
const q = require('q');
const FirefoxProfile = require('firefox-profile');
const jpm = require('jpm/lib/xpi');
const pathUtil = require('path');
var PERF_ADDON_PACKAGE_JSON_DIR = '..';
const PERF_ADDON_PACKAGE_JSON_DIR = '..';
exports.getAbsolutePath = function(path: string) {
var normalizedPath = pathUtil.normalize(path);
const 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) {
var deferred = q.defer();
const deferred = q.defer();
var firefoxProfile = new FirefoxProfile();
const firefoxProfile = new FirefoxProfile();
firefoxProfile.addExtensions([extensionPath], () => {
firefoxProfile.encoded((encodedProfile: any) => {
var multiCapabilities = [{browserName: 'firefox', firefox_profile: encodedProfile}];
const multiCapabilities = [{browserName: 'firefox', firefox_profile: encodedProfile}];
deferred.resolve(multiCapabilities);
});
});
@ -38,10 +38,10 @@ exports.getFirefoxProfile = function(extensionPath: string) {
};
exports.getFirefoxProfileWithExtension = function() {
var absPackageJsonDir = pathUtil.join(__dirname, PERF_ADDON_PACKAGE_JSON_DIR);
var packageJson = require(pathUtil.join(absPackageJsonDir, 'package.json'));
const absPackageJsonDir = pathUtil.join(__dirname, PERF_ADDON_PACKAGE_JSON_DIR);
const packageJson = require(pathUtil.join(absPackageJsonDir, 'package.json'));
var savedCwd = process.cwd();
const 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} {
var result: {[key: string]: string} = {};
const result: {[key: string]: string} = {};
maps.forEach(map => { Object.keys(map).forEach(prop => { result[prop] = map[prop]; }); });
return result;
}
var _CHILDREN = new OpaqueToken('MultiMetric.children');
const _CHILDREN = new OpaqueToken('MultiMetric.children');

View File

@ -56,7 +56,7 @@ export class PerflogMetric extends Metric {
}
describe(): {[key: string]: string} {
var res: {[key: string]: any} = {
const 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) {
var warningMsg = 'WARNING: Metric requested, but not supported by driver';
const 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 (let name in this._microMetrics) {
for (const name in this._microMetrics) {
res[name] = this._microMetrics[name];
}
return res;
}
beginMeasure(): Promise<any> {
var resultPromise = Promise.resolve(null);
let 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
var originalFrameCaptureValue = this._captureFrames;
const 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}> {
var markName = this._markName(this._measureCount - 1);
var nextMarkName = restart ? this._markName(this._measureCount++) : null;
const markName = this._markName(this._measureCount - 1);
const 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);
var result = this._aggregateEvents(this._remainingEvents, markName);
const result = this._aggregateEvents(this._remainingEvents, markName);
if (result) {
this._remainingEvents = events;
return result;
}
var resolve: (result: any) => void;
var promise = new Promise(res => { resolve = res; });
let resolve: (result: any) => void;
const promise = new Promise(res => { resolve = res; });
this._setTimeout(() => resolve(this._readUntilEndMark(markName, loopCount + 1)), 100);
return promise;
});
}
private _addEvents(events: PerfLogEvent[]) {
var needSort = false;
let needSort = false;
events.forEach(event => {
if (event['ph'] === 'X') {
needSort = true;
var startEvent: PerfLogEvent = {};
var endEvent: PerfLogEvent = {};
for (let prop in event) {
const startEvent: PerfLogEvent = {};
const endEvent: PerfLogEvent = {};
for (const 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) => {
var diff = a['ts'] - b['ts'];
const diff = a['ts'] - b['ts'];
return diff > 0 ? 1 : diff < 0 ? -1 : 0;
});
}
}
private _aggregateEvents(events: PerfLogEvent[], markName: string): {[key: string]: number} {
var result: {[key: string]: number} = {'scriptTime': 0, 'pureScriptTime': 0};
const 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 (let name in this._microMetrics) {
for (const name in this._microMetrics) {
result[name] = 0;
}
if (this._receivedData) {
@ -217,11 +217,11 @@ export class PerflogMetric extends Metric {
result['requestCount'] = 0;
}
var markStartEvent: PerfLogEvent = null;
var markEndEvent: PerfLogEvent = null;
let markStartEvent: PerfLogEvent = null;
let markEndEvent: PerfLogEvent = null;
events.forEach((event) => {
var ph = event['ph'];
var name = event['name'];
const ph = event['ph'];
const 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;
}
var gcTimeInScript = 0;
var renderTimeInScript = 0;
let gcTimeInScript = 0;
let renderTimeInScript = 0;
var frameTimestamps: number[] = [];
var frameTimes: number[] = [];
var frameCaptureStartEvent: PerfLogEvent = null;
var frameCaptureEndEvent: PerfLogEvent = null;
const frameTimestamps: number[] = [];
const frameTimes: number[] = [];
let frameCaptureStartEvent: PerfLogEvent = null;
let frameCaptureEndEvent: PerfLogEvent = null;
var intervalStarts: {[key: string]: PerfLogEvent} = {};
var intervalStartCount: {[key: string]: number} = {};
const intervalStarts: {[key: string]: PerfLogEvent} = {};
const intervalStartCount: {[key: string]: number} = {};
var inMeasureRange = false;
let inMeasureRange = false;
events.forEach((event) => {
var ph = event['ph'];
var name = event['name'];
var microIterations = 1;
var microIterationsMatch = name.match(_MICRO_ITERATIONS_REGEX);
const ph = event['ph'];
let name = event['name'];
let microIterations = 1;
const 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) {
var startEvent = intervalStarts[name];
var duration = (event['ts'] - startEvent['ts']);
const startEvent = intervalStarts[name];
const duration = (event['ts'] - startEvent['ts']);
intervalStarts[name] = null;
if (name === 'gc') {
result['gcTime'] += duration;
var amount =
const amount =
(startEvent['args']['usedHeapSize'] - event['args']['usedHeapSize']) / 1000;
result['gcAmount'] += amount;
var majorGc = event['args']['majorGc'];
const 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;
var firstFrame = frameTimes[0];
const 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}`; }
}
var _MICRO_ITERATIONS_REGEX = /(.+)\*(\d+)$/;
const _MICRO_ITERATIONS_REGEX = /(.+)\*(\d+)$/;
var _MAX_RETRY_COUNT = 20;
var _MARK_NAME_PREFIX = 'benchpress';
const _MAX_RETRY_COUNT = 20;
const _MARK_NAME_PREFIX = 'benchpress';
var _MARK_NAME_FRAME_CAPUTRE = 'frameCapture';
const _MARK_NAME_FRAME_CAPUTRE = 'frameCapture';
// using 17ms as a somewhat looser threshold, instead of 16.6666ms
var _FRAME_TIME_SMOOTH_THRESHOLD = 17;
const _FRAME_TIME_SMOOTH_THRESHOLD = 17;

View File

@ -9,7 +9,6 @@
import {Inject, Injectable} from '@angular/core';
import {Options} from '../common_options';
import {isNumber} from '../facade/lang';
import {Metric} from '../metric';
import {WebDriverAdapter} from '../web_driver_adapter';
@ -34,20 +33,20 @@ export class UserMetric extends Metric {
endMeasure(restart: boolean): Promise<{[key: string]: any}> {
let resolve: (result: any) => void;
let reject: (error: any) => void;
let promise = new Promise((res, rej) => {
const promise = new Promise((res, rej) => {
resolve = res;
reject = rej;
});
let adapter = this._wdAdapter;
let names = Object.keys(this._userMetrics);
const adapter = this._wdAdapter;
const names = Object.keys(this._userMetrics);
function getAndClearValues() {
Promise.all(names.map(name => adapter.executeScript(`return window.${name}`)))
.then((values: any[]) => {
if (values.every(isNumber)) {
if (values.every(v => typeof v === 'number')) {
Promise.all(names.map(name => adapter.executeScript(`delete window.${name}`)))
.then((_: any[]) => {
let map: {[k: string]: any} = {};
const 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 = ' ') {
var result = '';
for (var i = 0; i < columnWidth - value.length; i++) {
let result = '';
for (let 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:');
var props = sortedProps(sampleDescription.description);
const 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> {
var formattedValues = this._metricNames.map(metricName => {
var value = measureValues.values[metricName];
const formattedValues = this._metricNames.map(metricName => {
const value = measureValues.values[metricName];
return formatNum(value);
});
this._printStringRow(formattedValues);

View File

@ -9,7 +9,6 @@
import {Inject, Injectable, OpaqueToken} from '@angular/core';
import {Options} from '../common_options';
import {Json} from '../facade/lang';
import {MeasureValues} from '../measure_values';
import {Reporter} from '../reporter';
import {SampleDescription} from '../sample_description';
@ -39,13 +38,15 @@ export class JsonFileReporter extends Reporter {
sortedProps(this._description.metrics).forEach((metricName) => {
stats[metricName] = formatStats(validSample, metricName);
});
var content = Json.stringify({
'description': this._description,
'stats': stats,
'completeSample': completeSample,
'validSample': validSample,
});
var filePath = `${this._path}/${this._description.id}_${this._now().getTime()}.json`;
const content = JSON.stringify(
{
'description': this._description,
'stats': stats,
'completeSample': completeSample,
'validSample': validSample,
},
null, 2);
const 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 {
}
}
var _CHILDREN = new OpaqueToken('MultiReporter.children');
const _CHILDREN = new OpaqueToken('MultiReporter.children');

View File

@ -6,28 +6,23 @@
* found in the LICENSE file at https://angular.io/license
*/
import {NumberWrapper} from '../facade/lang';
import {MeasureValues} from '../measure_values';
import {Statistic} from '../statistic';
export function formatNum(n: number) {
return NumberWrapper.toFixed(n, 2);
return n.toFixed(2);
}
export function sortedProps(obj: {[key: string]: any}) {
var props: string[] = [];
props.push(...Object.keys(obj));
props.sort();
return props;
return Object.keys(obj).sort();
}
export function formatStats(validSamples: MeasureValues[], metricName: string): string {
var samples = validSamples.map(measureValues => measureValues.values[metricName]);
var mean = Statistic.calculateMean(samples);
var cv = Statistic.calculateCoefficientOfVariation(samples, mean);
var formattedMean = formatNum(mean);
const samples = validSamples.map(measureValues => measureValues.values[metricName]);
const mean = Statistic.calculateMean(samples);
const cv = Statistic.calculateCoefficientOfVariation(samples, mean);
const formattedMean = formatNum(mean);
// Note: Don't use the unicode character for +- as it might cause
// hickups for consoles...
return NumberWrapper.isNaN(cv) ? formattedMean : `${formattedMean}+-${Math.floor(cv)}%`;
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> {
var sampleProviders: Provider[] = [
const 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);
}
var inj = ReflectiveInjector.resolveAndCreate(sampleProviders);
var adapter: WebDriverAdapter = inj.get(WebDriverAdapter);
const inj = ReflectiveInjector.resolveAndCreate(sampleProviders);
const adapter: WebDriverAdapter = inj.get(WebDriverAdapter);
return Promise
.all([adapter.capabilities(), adapter.executeScript('return window.navigator.userAgent;')])
.then((args) => {
var capabilities = args[0];
var userAgent = args[1];
const capabilities = args[0];
const 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.
var injector = ReflectiveInjector.resolveAndCreate([
const injector = ReflectiveInjector.resolveAndCreate([
sampleProviders, {provide: Options.CAPABILITIES, useValue: capabilities},
{provide: Options.USER_AGENT, useValue: userAgent},
{provide: WebDriverAdapter, useValue: adapter}
]);
var sampler = injector.get(Sampler);
const sampler = injector.get(Sampler);
return sampler.sample();
});
}
}
var _DEFAULT_PROVIDERS = [
const _DEFAULT_PROVIDERS = [
Options.DEFAULT_PROVIDERS,
Sampler.PROVIDERS,
ConsoleReporter.PROVIDERS,

View File

@ -49,7 +49,7 @@ export class Sampler {
}
private _iterate(lastState: SampleState): Promise<SampleState> {
var resultPromise: Promise<SampleState>;
let 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> {
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);
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);
if (isPresent(validSample)) {
resultPromise =
resultPromise.then((_) => this._reporter.reportSample(completeSample, validSample));

View File

@ -6,22 +6,20 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Math} from './facade/math';
export class Statistic {
static calculateCoefficientOfVariation(sample: number[], mean: number) {
return Statistic.calculateStandardDeviation(sample, mean) / mean * 100;
}
static calculateMean(samples: number[]) {
var total = 0;
let total = 0;
// TODO: use reduce
samples.forEach(x => total += x);
return total / samples.length;
}
static calculateStandardDeviation(samples: number[], mean: number) {
var deviation = 0;
let deviation = 0;
// TODO: use reduce
samples.forEach(x => deviation += Math.pow(x - mean, 2));
deviation = deviation / (samples.length);
@ -32,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
var dividendSum = 0;
var divisorSum = 0;
for (var i = 0; i < xValues.length; i++) {
let dividendSum = 0;
let divisorSum = 0;
for (let i = 0; i < xValues.length; i++) {
dividendSum += (xValues[i] - xMean) * (yValues[i] - yMean);
divisorSum += Math.pow(xValues[i] - xMean, 2);
}

View File

@ -8,13 +8,10 @@
import {Inject, Injectable, OpaqueToken} from '@angular/core';
import {ListWrapper} from '../facade/collection';
import {MeasureValues} from '../measure_values';
import {Statistic} from '../statistic';
import {Validator} from '../validator';
/**
* A validator that checks the regression slope of a specific metric.
* Waits for the regression slope to be >=0.
@ -40,17 +37,17 @@ export class RegressionSlopeValidator extends Validator {
validate(completeSample: MeasureValues[]): MeasureValues[] {
if (completeSample.length >= this._sampleSize) {
var latestSample = ListWrapper.slice(
completeSample, completeSample.length - this._sampleSize, completeSample.length);
var xValues: number[] = [];
var yValues: number[] = [];
for (var i = 0; i < latestSample.length; i++) {
const latestSample =
completeSample.slice(completeSample.length - this._sampleSize, completeSample.length);
const xValues: number[] = [];
const yValues: number[] = [];
for (let i = 0; i < latestSample.length; i++) {
// For now, we only use the array index as x value.
// TODO(tbosch): think about whether we should use time here instead
xValues.push(i);
yValues.push(latestSample[i].values[this._metric]);
}
var regressionSlope = Statistic.calculateRegressionSlope(
const regressionSlope = Statistic.calculateRegressionSlope(
xValues, Statistic.calculateMean(xValues), yValues, Statistic.calculateMean(yValues));
return regressionSlope >= 0 ? latestSample : null;
} else {

View File

@ -8,12 +8,9 @@
import {Inject, Injectable, OpaqueToken} from '@angular/core';
import {ListWrapper} from '../facade/collection';
import {MeasureValues} from '../measure_values';
import {Validator} from '../validator';
/**
* A validator that waits for the sample to have a certain size.
*/
@ -28,8 +25,7 @@ export class SizeValidator extends Validator {
validate(completeSample: MeasureValues[]): MeasureValues[] {
if (completeSample.length >= this._sampleSize) {
return ListWrapper.slice(
completeSample, completeSample.length - this._sampleSize, completeSample.length);
return completeSample.slice(completeSample.length - this._sampleSize, completeSample.length);
} else {
return null;
}

View File

@ -34,7 +34,7 @@ export type PerfLogEvent = {
*/
export abstract class WebDriverExtension {
static provideFirstSupported(childTokens: any[]): any[] {
var res = [
const 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}) => {
var delegate: WebDriverExtension;
let delegate: WebDriverExtension;
children.forEach(extension => {
if (extension.supports(capabilities)) {
delegate = extension;
@ -101,4 +101,4 @@ export class PerfLogFeatures {
}
}
var _CHILDREN = new OpaqueToken('WebDriverExtension.children');
const _CHILDREN = new OpaqueToken('WebDriverExtension.children');

View File

@ -34,7 +34,7 @@ export class ChromeDriverExtension extends WebDriverExtension {
if (!userAgent) {
return -1;
}
var v = userAgent.split(/Chrom(e|ium)\//g)[2];
let 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> {
var script = `console.timeEnd('${name}');`;
let 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) => {
var events: PerfLogEvent[] = [];
const events: PerfLogEvent[] = [];
entries.forEach(entry => {
var message = JSON.parse(entry['message'])['message'];
const 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[]) {
var name = event['name'];
var args = event['args'];
const name = event['name'];
const 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
var frameCount = event['args']['data']['frame_count'];
const 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')) {
var normArgs = {
const 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')) {
var normArgs = {
const 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')) {
let normArgs = {'encodedDataLength': args['data']['encodedDataLength']};
const normArgs = {'encodedDataLength': args['data']['encodedDataLength']};
return normalizeEvent(event, {'name': 'receivedData', 'args': normArgs});
} else if (this._isEvent(categories, name, ['devtools.timeline'], 'ResourceSendRequest')) {
let data = args['data'];
let normArgs = {'url': data['url'], 'method': data['requestMethod']};
const data = args['data'];
const 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 {
var hasCategories = expectedCategories.reduce(
const 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 {
var ph = chromeEvent['ph'].toUpperCase();
let 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';
}
var result: {[key: string]: any} =
const result: {[key: string]: any} =
{'pid': chromeEvent['pid'], 'ph': ph, 'cat': 'timeline', 'ts': chromeEvent['ts'] / 1000};
if (ph === 'X') {
var dur = chromeEvent['dur'];
let dur = chromeEvent['dur'];
if (dur === undefined) {
dur = chromeEvent['tdur'];
}
result['dur'] = !dur ? 0.0 : dur / 1000;
}
for (let prop in data) {
for (const 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> {
var script = 'window.markEnd("' + name + '");';
let 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> {
var script = `console.timeEnd('${name}');`;
let 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) => {
var records: any[] = [];
const records: any[] = [];
entries.forEach(entry => {
var message = JSON.parse(entry['message'])['message'];
const message = JSON.parse(entry['message'])['message'];
if (message['method'] === 'Timeline.eventRecorded') {
records.push(message['params']['record']);
}
@ -56,13 +56,13 @@ export class IOsDriverExtension extends WebDriverExtension {
events = [];
}
records.forEach((record) => {
var endEvent: PerfLogEvent = null;
var type = record['type'];
var data = record['data'];
var startTime = record['startTime'];
var endTime = record['endTime'];
let endEvent: PerfLogEvent = null;
const type = record['type'];
const data = record['data'];
const startTime = record['startTime'];
const endTime = record['endTime'];
if (type === 'FunctionCall' && (isBlank(data) || data['scriptName'] !== 'InjectedScript')) {
if (type === 'FunctionCall' && (data == null || data['scriptName'] !== 'InjectedScript')) {
events.push(createStartEvent('script', startTime));
endEvent = createEndEvent('script', endTime);
} else if (type === 'Time') {
@ -95,7 +95,7 @@ export class IOsDriverExtension extends WebDriverExtension {
function createEvent(
ph: 'X' | 'B' | 'E' | 'B' | 'E', name: string, time: number, args: any = null) {
var result: PerfLogEvent = {
const result: PerfLogEvent = {
'cat': 'timeline',
'name': name,
'ts': time,

View File

@ -8,7 +8,7 @@
require('core-js');
require('reflect-metadata');
var testHelper = require('../../src/firefox_extension/lib/test_helper.js');
const 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 (var i = 0; i < actualEvents.length; ++i) {
var actualEvent = actualEvents[i];
var expectedEvent = expectedEvents[i];
for (var key in actualEvent) {
for (let i = 0; i < actualEvents.length; ++i) {
const actualEvent = actualEvents[i];
const expectedEvent = expectedEvents[i];
for (const 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() {
var profileData = {
const profileData = {
threads: [
{samples: [{time: 1, frames: [{location: 'FirefoxDriver.prototype.executeScript'}]}]}
]
};
var perfEvents = convertPerfProfileToEvents(profileData);
const perfEvents = convertPerfProfileToEvents(profileData);
assertEventsEqual(perfEvents, [{ph: 'X', ts: 1, name: 'script'}]);
});
it('should convert single non-instantaneous event', function() {
var profileData = {
const profileData = {
threads: [{
samples: [
{time: 1, frames: [{location: 'FirefoxDriver.prototype.executeScript'}]},
@ -41,13 +41,13 @@ export function main() {
]
}]
};
var perfEvents = convertPerfProfileToEvents(profileData);
const perfEvents = convertPerfProfileToEvents(profileData);
assertEventsEqual(
perfEvents, [{ph: 'B', ts: 1, name: 'script'}, {ph: 'E', ts: 100, name: 'script'}]);
});
it('should convert multiple instantaneous events', function() {
var profileData = {
const profileData = {
threads: [{
samples: [
{time: 1, frames: [{location: 'FirefoxDriver.prototype.executeScript'}]},
@ -55,13 +55,13 @@ export function main() {
]
}]
};
var perfEvents = convertPerfProfileToEvents(profileData);
const perfEvents = convertPerfProfileToEvents(profileData);
assertEventsEqual(
perfEvents, [{ph: 'X', ts: 1, name: 'script'}, {ph: 'X', ts: 2, name: 'render'}]);
});
it('should convert multiple mixed events', function() {
var profileData = {
const profileData = {
threads: [{
samples: [
{time: 1, frames: [{location: 'FirefoxDriver.prototype.executeScript'}]},
@ -71,7 +71,7 @@ export function main() {
]
}]
};
var perfEvents = convertPerfProfileToEvents(profileData);
const 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() {
var profileData = {threads: [{samples: [{time: 1, frames: [{location: 'forceGC'}]}]}]};
var perfEvents = convertPerfProfileToEvents(profileData);
const profileData = {threads: [{samples: [{time: 1, frames: [{location: 'forceGC'}]}]}]};
const perfEvents = convertPerfProfileToEvents(profileData);
assertEventsEqual(perfEvents, [{ph: 'X', ts: 1, name: 'gc', args: {usedHeapSize: 0}}]);
});
it('should skip unknown events', function() {
var profileData = {
const profileData = {
threads: [{
samples: [
{time: 1, frames: [{location: 'FirefoxDriver.prototype.executeScript'}]},
@ -93,7 +93,7 @@ export function main() {
]
}]
};
var perfEvents = convertPerfProfileToEvents(profileData);
const perfEvents = convertPerfProfileToEvents(profileData);
assertEventsEqual(perfEvents, [{ph: 'X', ts: 1, name: 'script'}]);
});
});

View File

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

View File

@ -6,9 +6,12 @@
* found in the LICENSE file at https://angular.io/license
*/
var assertEventsContainsName = function(events: any[], eventName: string) {
var found = false;
for (var i = 0; i < events.length; ++i) {
/* 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) {
if (events[i].name == eventName) {
found = true;
break;
@ -18,7 +21,7 @@ var assertEventsContainsName = function(events: any[], eventName: string) {
};
describe('firefox extension', function() {
var TEST_URL = 'http://localhost:8001/playground/src/hello_world/index.html';
const 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[]) {
var m = ReflectiveInjector
.resolveAndCreate([
ids.map(id => ({provide: id, useValue: new MockMetric(id)})),
MultiMetric.provideWith(ids)
])
.get(MultiMetric);
const 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}> {
var result: {[key: string]: any} = {};
const result: {[key: string]: any} = {};
result[this._id] = {'restart': restart};
return Promise.resolve(result);
}
describe(): {[key: string]: string} {
var result: {[key: string]: string} = {};
const 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() {
var commandLog: any[];
var eventFactory = new TraceEventFactory('timeline', 'pid0');
let commandLog: any[];
const eventFactory = new TraceEventFactory('timeline', 'pid0');
function createMetric(
perfLogs: PerfLogEvent[], perfLogFeatures: PerfLogFeatures,
@ -34,7 +34,7 @@ export function main() {
if (!microMetrics) {
microMetrics = {};
}
var providers: Provider[] = [
const 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}) {
var res: string[] = [];
const 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', () => {
var description =
const description =
createMetric([[]], null, {microMetrics: {'myMicroMetric': 'someDesc'}}).describe();
expect(description['myMicroMetric']).toEqual('someDesc');
});
it('should describe itself if frame capture is requested and available', () => {
var description = createMetric([[]], new PerfLogFeatures({frameCapture: true}), {
captureFrames: true
}).describe();
const 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', () => {
var description = createMetric([[]], new PerfLogFeatures({frameCapture: false}), {
captureFrames: true
}).describe();
const 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) => {
var metric = createMetric([[]], null);
const 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) => {
var metric = createMetric([[]], null, {forceGc: true});
const 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) => {
var events = [[
const events = [[
eventFactory.markStart('benchpress0', 0), eventFactory.start('script', 4),
eventFactory.end('script', 6), eventFactory.markEnd('benchpress0', 10)
]];
var metric = createMetric(events, null);
const 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) => {
var events = [[
const 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)
]];
var metric = createMetric(events, null);
const 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) => {
var events = [
const events = [
[
eventFactory.markStart('benchpress0', 0),
eventFactory.markEnd('benchpress0', 1),
@ -195,7 +195,7 @@ export function main() {
],
[eventFactory.markEnd('benchpress1', 3)]
];
var metric = createMetric(events, null);
const 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) => {
var events = [
const events = [
[eventFactory.markStart('benchpress0', 0), eventFactory.start('script', 1)],
[eventFactory.end('script', 2)],
[
@ -219,7 +219,7 @@ export function main() {
eventFactory.markEnd('benchpress0', 10)
]
];
var metric = createMetric(events, null);
const 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) => {
var events = [
const 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)
]
];
var metric = createMetric(events, null);
const metric = createMetric(events, null);
metric.beginMeasure()
.then((_) => metric.endMeasure(true))
.then((data) => {
@ -263,7 +263,7 @@ export function main() {
}));
describe('with forced gc', () => {
var events: PerfLogEvent[][];
let 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) => {
var metric = createMetric(events, null, {forceGc: true});
const 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) => {
var metric = createMetric(events, null, {forceGc: true});
const 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));
var metric = createMetric([events], null, {
const 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) => {
var otherProcessEventFactory = new TraceEventFactory('timeline', 'pid1');
var metric = createMetric(
const otherProcessEventFactory = new TraceEventFactory('timeline', 'pid1');
const 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) {
var next = this._perfLogs[0];
const 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() {
var wdAdapter: MockDriverAdapter;
let wdAdapter: MockDriverAdapter;
function createMetric(
perfLogs: PerfLogEvent[], perfLogFeatures: PerfLogFeatures,
@ -25,7 +25,7 @@ export function main() {
userMetrics = {};
}
wdAdapter = new MockDriverAdapter();
var providers: Provider[] = [
const 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) => {
let metric = createMetric(
const 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) {
let metricName = script.substring('return window.'.length);
const 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', () => {
var reporter: ConsoleReporter;
var log: string[];
let reporter: ConsoleReporter;
let log: string[];
function createReporter(
{columnWidth = null, sampleId = null, descriptions = null, metrics = null}: {
@ -28,10 +28,10 @@ export function main() {
if (!descriptions) {
descriptions = [];
}
if (isBlank(sampleId)) {
if (sampleId == null) {
sampleId = 'null';
}
var providers: Provider[] = [
const providers: Provider[] = [
ConsoleReporter.PROVIDERS, {
provide: SampleDescription,
useValue: new SampleDescription(sampleId, descriptions, metrics)

View File

@ -9,11 +9,11 @@
import {AsyncTestCompleter, describe, expect, inject, it} from '@angular/core/testing/testing_internal';
import {JsonFileReporter, MeasureValues, Options, ReflectiveInjector, SampleDescription} from '../../index';
import {Json, isPresent} from '../../src/facade/lang';
import {isPresent} from '../../src/facade/lang';
export function main() {
describe('file reporter', () => {
var loggedFile: any;
let loggedFile: any;
function createReporter({sampleId, descriptions, metrics, path}: {
sampleId: string,
@ -21,7 +21,7 @@ export function main() {
metrics: {[key: string]: string},
path: string
}) {
var providers = [
const 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})]);
var regExp = /somePath\/someId_\d+\.json/;
const regExp = /somePath\/someId_\d+\.json/;
expect(isPresent(loggedFile['filename'].match(regExp))).toBe(true);
var parsedContent = Json.parse(loggedFile['content']);
const 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[]) {
var r = ReflectiveInjector
.resolveAndCreate([
ids.map(id => ({provide: id, useValue: new MockReporter(id)})),
MultiReporter.provideWith(ids)
])
.get(MultiReporter);
const 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) => {
var mv = new MeasureValues(0, new Date(), {});
const 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) => {
var completeSample =
const completeSample =
[new MeasureValues(0, new Date(), {}), new MeasureValues(1, new Date(), {})];
var validSample = [completeSample[1]];
const 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', () => {
var injector: ReflectiveInjector;
var runner: Runner;
let injector: ReflectiveInjector;
let 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) => {
var execute = () => {};
const 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) => {
var prepare = () => {};
const 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() {
var EMPTY_EXECUTE = () => {};
const EMPTY_EXECUTE = () => {};
describe('sampler', () => {
var sampler: Sampler;
let sampler: Sampler;
function createSampler({driver, metric, reporter, validator, prepare, execute}: {
driver?: any,
@ -25,7 +25,7 @@ export function main() {
prepare?: any,
execute?: any
} = {}) {
var time = 1000;
let time = 1000;
if (!metric) {
metric = new MockMetric([]);
}
@ -35,7 +35,7 @@ export function main() {
if (isBlank(driver)) {
driver = new MockDriverAdapter([]);
}
var providers = [
const 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) => {
var log: any[] = [];
var count = 0;
var driver = new MockDriverAdapter([], (callback: Function) => {
var result = callback();
const log: any[] = [];
let count = 0;
const driver = new MockDriverAdapter([], (callback: Function) => {
const 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) => {
var workCount = 0;
var log: any[] = [];
let workCount = 0;
const 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) => {
var log: any[] = [];
var workCount = 0;
const log: any[] = [];
let 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) => {
var scriptTime = 0;
var iterationCount = 1;
let scriptTime = 0;
let iterationCount = 1;
createSampler({
validator: createCountingValidator(2),
metric: new MockMetric(
[],
() => {
var result = Promise.resolve({'script': scriptTime});
const 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) => {
var log: any[] = [];
var validSample = [mv(null, null, {})];
const log: any[] = [];
const validSample = [mv(null, null, {})];
createSampler({
metric: createCountingMetric(),
@ -174,8 +174,8 @@ export function main() {
it('should report the metric values',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var log: any[] = [];
var validSample = [mv(null, null, {})];
const log: any[] = [];
const validSample = [mv(null, null, {})];
createSampler({
validator: createCountingValidator(2, validSample),
metric: createCountingMetric(),
@ -220,7 +220,7 @@ function createCountingValidator(
}
function createCountingMetric(log: any[] = []) {
var scriptTime = 0;
let scriptTime = 0;
return new MockMetric(log, () => ({'script': scriptTime++}));
}
@ -239,7 +239,8 @@ class MockDriverAdapter extends WebDriverAdapter {
class MockValidator extends Validator {
constructor(private _log: any[] = [], private _validate: Function = null) { super(); }
validate(completeSample: MeasureValues[]): MeasureValues[] {
var stableSample = isPresent(this._validate) ? this._validate(completeSample) : completeSample;
const stableSample =
isPresent(this._validate) ? this._validate(completeSample) : completeSample;
this._log.push(['validate', completeSample, stableSample]);
return stableSample;
}
@ -252,7 +253,7 @@ class MockMetric extends Metric {
return Promise.resolve(null);
}
endMeasure(restart: boolean) {
var measureValues = isPresent(this._endMeasure) ? this._endMeasure() : {};
const 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) {
var res:
const 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) {
var res = this.create('X', name, time, args);
const res = this.create('X', name, time, args);
res['dur'] = duration;
return res;
}

View File

@ -9,11 +9,10 @@
import {describe, expect, it} from '@angular/core/testing/testing_internal';
import {MeasureValues, ReflectiveInjector, RegressionSlopeValidator} from '../../index';
import {ListWrapper} from '../../src/facade/collection';
export function main() {
describe('regression slope validator', () => {
var validator: RegressionSlopeValidator;
let validator: RegressionSlopeValidator;
function createValidator({size, metric}: {size: number, metric: string}) {
validator = ReflectiveInjector
@ -43,18 +42,16 @@ export function main() {
it('should return the last sampleSize runs when the regression slope is ==0', () => {
createValidator({size: 2, metric: 'script'});
var sample = [mv(0, 0, {'script': 1}), mv(1, 1, {'script': 1}), mv(2, 2, {'script': 1})];
expect(validator.validate(ListWrapper.slice(sample, 0, 2)))
.toEqual(ListWrapper.slice(sample, 0, 2));
expect(validator.validate(sample)).toEqual(ListWrapper.slice(sample, 1, 3));
const 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'});
var sample = [mv(0, 0, {'script': 1}), mv(1, 1, {'script': 2}), mv(2, 2, {'script': 3})];
expect(validator.validate(ListWrapper.slice(sample, 0, 2)))
.toEqual(ListWrapper.slice(sample, 0, 2));
expect(validator.validate(sample)).toEqual(ListWrapper.slice(sample, 1, 3));
const 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

@ -9,11 +9,10 @@
import {describe, expect, it} from '@angular/core/testing/testing_internal';
import {MeasureValues, ReflectiveInjector, SizeValidator} from '../../index';
import {ListWrapper} from '../../src/facade/collection';
export function main() {
describe('size validator', () => {
var validator: SizeValidator;
let validator: SizeValidator;
function createValidator(size: number) {
validator =
@ -36,10 +35,9 @@ export function main() {
it('should return the last sampleSize runs when it has at least the given size', () => {
createValidator(2);
var sample = [mv(0, 0, {'a': 1}), mv(1, 1, {'b': 2}), mv(2, 2, {'c': 3})];
expect(validator.validate(ListWrapper.slice(sample, 0, 2)))
.toEqual(ListWrapper.slice(sample, 0, 2));
expect(validator.validate(sample)).toEqual(ListWrapper.slice(sample, 1, 3));
const 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

@ -9,28 +9,28 @@
import {AsyncTestCompleter, describe, expect, inject, it} from '@angular/core/testing/testing_internal';
import {ChromeDriverExtension, Options, ReflectiveInjector, WebDriverAdapter, WebDriverExtension} from '../../index';
import {Json, isBlank} from '../../src/facade/lang';
import {isBlank} from '../../src/facade/lang';
import {TraceEventFactory} from '../trace_event_factory';
export function main() {
describe('chrome driver extension', () => {
var CHROME45_USER_AGENT =
const 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"';
var log: any[];
var extension: ChromeDriverExtension;
let log: any[];
let extension: ChromeDriverExtension;
var blinkEvents = new TraceEventFactory('blink.console', 'pid0');
var v8Events = new TraceEventFactory('v8', 'pid0');
var v8EventsOtherProcess = new TraceEventFactory('v8', 'pid1');
var chromeTimelineEvents =
const blinkEvents = new TraceEventFactory('blink.console', 'pid0');
const v8Events = new TraceEventFactory('v8', 'pid0');
const v8EventsOtherProcess = new TraceEventFactory('v8', 'pid1');
const chromeTimelineEvents =
new TraceEventFactory('disabled-by-default-devtools.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');
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');
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) => {
var event: any = chromeTimelineV8Events.create('X', 'FunctionCall', 1100, null);
const event: any = chromeTimelineV8Events.create('X', 'FunctionCall', 1100, null);
event['tdur'] = 5500;
createExtension([event]).readPerfLog().then((events) => {
expect(events).toEqual([
@ -398,8 +398,8 @@ class MockDriverAdapter extends WebDriverAdapter {
if (type === 'performance') {
return Promise.resolve(this._events.map(
(event) => ({
'message':
Json.stringify({'message': {'method': this._messageMethod, 'params': event}})
'message': JSON.stringify(
{'message': {'method': this._messageMethod, 'params': event}}, null, 2)
})));
} else {
return null;

View File

@ -9,15 +9,14 @@
import {AsyncTestCompleter, describe, expect, inject, it} from '@angular/core/testing/testing_internal';
import {IOsDriverExtension, ReflectiveInjector, WebDriverAdapter, WebDriverExtension} from '../../index';
import {Json} from '../../src/facade/lang';
import {TraceEventFactory} from '../trace_event_factory';
export function main() {
describe('ios driver extension', () => {
var log: any[];
var extension: IOsDriverExtension;
let log: any[];
let extension: IOsDriverExtension;
var normEvents = new TraceEventFactory('timeline', 'pid0');
const normEvents = new TraceEventFactory('timeline', 'pid0');
function createExtension(perfRecords: any[] = null): WebDriverExtension {
if (!perfRecords) {
@ -184,8 +183,9 @@ class MockDriverAdapter extends WebDriverAdapter {
if (type === 'performance') {
return Promise.resolve(this._perfRecords.map(function(record) {
return {
'message': Json.stringify(
{'message': {'method': 'Timeline.eventRecorded', 'params': {'record': record}}})
'message': JSON.stringify(
{'message': {'method': 'Timeline.eventRecorded', 'params': {'record': record}}}, null,
2)
};
}));
} else {

View File

@ -11,9 +11,6 @@
* @description
* Entry point for all public APIs of the common package.
*/
export * from './src/location';
export {NgLocalization} from './src/localization';
export {CommonModule} from './src/common_module';
export * from './src/common';
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';
// This file only reexports content of the `src` folder. Keep it that way.

View File

@ -0,0 +1,20 @@
/**
* @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,9 +9,7 @@
import {CollectionChangeRecord, Directive, DoCheck, ElementRef, Input, IterableDiffer, IterableDiffers, KeyValueChangeRecord, KeyValueDiffer, KeyValueDiffers, Renderer} from '@angular/core';
import {isListLikeIterable} from '../facade/collection';
import {isPresent} from '../facade/lang';
import {isPresent, stringify} from '../facade/lang';
/**
* @ngModule CommonModule
@ -31,11 +29,11 @@ import {isPresent} from '../facade/lang';
*
* @description
*
* The CSS classes are updated as follow depending on the type of the expression evaluation:
* - `string` - the CSS classes listed in a string (space delimited) are added,
* - `Array` - the CSS classes (Array elements) are added,
* - `Object` - keys are CSS class names that get added when the expression given in the value
* evaluates to a truthy value, otherwise class are removed.
* The CSS classes are updated as follows, depending on the type of the expression evaluation:
* - `string` - the CSS classes listed in the string (space delimited) are added,
* - `Array` - the CSS classes declared as Array elements are added,
* - `Object` - keys are CSS classes that get added when the expression given in the value
* evaluates to a truthy value, otherwise they are removed.
*
* @stable
*/
@ -50,7 +48,6 @@ export class NgClass implements DoCheck {
private _iterableDiffers: IterableDiffers, private _keyValueDiffers: KeyValueDiffers,
private _ngEl: ElementRef, private _renderer: Renderer) {}
@Input('class')
set klass(v: string) {
this._applyInitialClasses(true);
@ -111,8 +108,14 @@ export class NgClass implements DoCheck {
}
private _applyIterableChanges(changes: any): void {
changes.forEachAddedItem(
(record: CollectionChangeRecord) => this._toggleClass(record.item, true));
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.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++) {
let viewRef = <EmbeddedViewRef<NgForRow>>this._viewContainer.get(i);
const viewRef = <EmbeddedViewRef<NgForRow>>this._viewContainer.get(i);
viewRef.context.index = i;
viewRef.context.count = ilen;
}
changes.forEachIdentityChange((record: any) => {
let viewRef = <EmbeddedViewRef<NgForRow>>this._viewContainer.get(record.currentIndex);
const 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 option `.<unit>` suffix (ie 'top.px', 'font-style.em'),
* - keys are style names with an optional `.<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,19 +6,31 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Directive, Host, Input, TemplateRef, ViewContainerRef} from '@angular/core';
import {ListWrapper} from '../facade/collection';
const _CASE_DEFAULT = {};
import {Directive, DoCheck, Host, Input, TemplateRef, ViewContainerRef} from '@angular/core';
export class SwitchView {
private _created = false;
constructor(
private _viewContainerRef: ViewContainerRef, private _templateRef: TemplateRef<Object>) {}
create(): void { this._viewContainerRef.createEmbeddedView(this._templateRef); }
create(): void {
this._created = true;
this._viewContainerRef.createEmbeddedView(this._templateRef);
}
destroy(): void { this._viewContainerRef.clear(); }
destroy(): void {
this._created = false;
this._viewContainerRef.clear();
}
enforceState(created: boolean) {
if (created && !this._created) {
this.create();
} else if (!created && this._created) {
this.destroy();
}
}
}
/**
@ -64,92 +76,52 @@ export class SwitchView {
*/
@Directive({selector: '[ngSwitch]'})
export class NgSwitch {
private _switchValue: any;
private _useDefault: boolean = false;
private _valueViews = new Map<any, SwitchView[]>();
private _activeViews: SwitchView[] = [];
private _defaultViews: SwitchView[];
private _defaultUsed = false;
private _caseCount = 0;
private _lastCaseCheckIndex = 0;
private _lastCasesMatched = false;
private _ngSwitch: any;
@Input()
set ngSwitch(value: any) {
// Set of views to display for this value
let views = this._valueViews.get(value);
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;
set ngSwitch(newValue: any) {
this._ngSwitch = newValue;
if (this._caseCount === 0) {
this._updateDefaultCases(true);
}
}
/** @internal */
_registerView(value: any, view: SwitchView): void {
let views = this._valueViews.get(value);
if (!views) {
views = [];
this._valueViews.set(value, views);
_addCase(): number { return this._caseCount++; }
/** @internal */
_addDefault(view: SwitchView) {
if (!this._defaultViews) {
this._defaultViews = [];
}
views.push(view);
this._defaultViews.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);
/** @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);
}
}
}
}
@ -179,24 +151,20 @@ export class NgSwitch {
* @stable
*/
@Directive({selector: '[ngSwitchCase]'})
export class NgSwitchCase {
// `_CASE_DEFAULT` is used as a marker for a not yet initialized value
private _value: any = _CASE_DEFAULT;
export class NgSwitchCase implements DoCheck {
private _view: SwitchView;
private _switch: NgSwitch;
@Input()
ngSwitchCase: any;
constructor(
viewContainer: ViewContainerRef, templateRef: TemplateRef<Object>,
@Host() ngSwitch: NgSwitch) {
this._switch = ngSwitch;
@Host() private ngSwitch: NgSwitch) {
ngSwitch._addCase();
this._view = new SwitchView(viewContainer, templateRef);
}
@Input()
set ngSwitchCase(value: any) {
this._switch._onCaseValueChanged(this._value, value, this._view);
this._value = value;
}
ngDoCheck() { this._view.enforceState(this.ngSwitch._matchCase(this.ngSwitchCase)); }
}
/**
@ -226,7 +194,7 @@ export class NgSwitchCase {
export class NgSwitchDefault {
constructor(
viewContainer: ViewContainerRef, templateRef: TemplateRef<Object>,
@Host() sswitch: NgSwitch) {
sswitch._registerView(_CASE_DEFAULT, new SwitchView(viewContainer, templateRef));
@Host() ngSwitch: NgSwitch) {
ngSwitch._addDefault(new SwitchView(viewContainer, templateRef));
}
}

View File

@ -23,9 +23,23 @@ export abstract class NgLocalization { abstract getPluralCategory(value: any): s
*/
export function getPluralCategory(
value: number, cases: string[], ngLocalization: NgLocalization): string {
const nbCase = `=${value}`;
let key = `=${value}`;
return cases.indexOf(nbCase) > -1 ? nbCase : ngLocalization.getPluralCategory(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}"`);
}
/**

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 './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,6 +17,8 @@ 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)
@ -27,18 +29,7 @@ import {LocationChangeListener, PlatformLocation} from './platform_location';
*
* ### Example
*
* ```
* import {Component, NgModule} from '@angular/core';
* import {
* LocationStrategy,
* HashLocationStrategy
* } from '@angular/common';
*
* @NgModule({
* providers: [{provide: LocationStrategy, useClass: HashLocationStrategy}]
* })
* class AppModule {}
* ```
* {@example common/location/ts/hash_location_component.ts region='LocationComponent'}
*
* @stable
*/
@ -64,19 +55,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
var path = this._platformLocation.hash;
let path = this._platformLocation.hash;
if (!isPresent(path)) path = '#';
return path.length > 0 ? path.substring(1) : path;
}
prepareExternalUrl(internal: string): string {
var url = Location.joinWithSlash(this._baseHref, internal);
const url = Location.joinWithSlash(this._baseHref, internal);
return url.length > 0 ? ('#' + url) : url;
}
pushState(state: any, title: string, path: string, queryParams: string) {
var url = this.prepareExternalUrl(path + Location.normalizeQueryParams(queryParams));
let url = this.prepareExternalUrl(path + Location.normalizeQueryParams(queryParams));
if (url.length == 0) {
url = this._platformLocation.pathname;
}
@ -84,7 +75,7 @@ export class HashLocationStrategy extends LocationStrategy {
}
replaceState(state: any, title: string, path: string, queryParams: string) {
var url = this.prepareExternalUrl(path + Location.normalizeQueryParams(queryParams));
let url = this.prepareExternalUrl(path + Location.normalizeQueryParams(queryParams));
if (url.length == 0) {
url = this._platformLocation.pathname;
}

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 './platform_location';
export * from './location_strategy';
export * from './hash_location_strategy';
export * from './path_location_strategy';
export * from './location';

View File

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

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} (default).
* {@link HashLocationStrategy} and {@link PathLocationStrategy}.
*
* This is used under the hood of the {@link Location} service.
*

View File

@ -17,14 +17,13 @@ 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.
@ -37,6 +36,10 @@ 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()
@ -79,12 +82,12 @@ export class PathLocationStrategy extends LocationStrategy {
}
pushState(state: any, title: string, url: string, queryParams: string) {
var externalUrl = this.prepareExternalUrl(url + Location.normalizeQueryParams(queryParams));
const externalUrl = this.prepareExternalUrl(url + Location.normalizeQueryParams(queryParams));
this._platformLocation.pushState(state, title, externalUrl);
}
replaceState(state: any, title: string, url: string, queryParams: string) {
var externalUrl = this.prepareExternalUrl(url + Location.normalizeQueryParams(queryParams));
const externalUrl = this.prepareExternalUrl(url + Location.normalizeQueryParams(queryParams));
this._platformLocation.replaceState(state, title, externalUrl);
}

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 continuesly updates the view with the current time.
* to the view. The Observable continuously updates the view with the current time.
*
* {@example common/pipes/ts/async_pipe.ts region='AsyncPipeObservable'}
*

View File

@ -7,11 +7,14 @@
*/
import {Inject, LOCALE_ID, Pipe, PipeTransform} from '@angular/core';
import {DateFormatter} from '../facade/intl';
import {NumberWrapper, isBlank, isDate} from '../facade/lang';
import {NumberWrapper, isDate} from '../facade/lang';
import {DateFormatter} from './intl';
import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
/**
* @ngModule CommonModule
* @whatItDoes Formats a date according to locale rules.
@ -33,27 +36,30 @@ import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
* - `'shortTime'`: equivalent to `'jm'` (e.g. `12:05 PM` for `en-US`)
*
*
* | 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) | - | - | - |
* | 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) | - | - | - |
*
* 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
@ -95,22 +101,42 @@ 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 (!this.supports(value)) {
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)) {
throw new InvalidPipeArgumentError(DatePipe, value);
}
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)));
return DateFormatter.format(date, this._locale, DatePipe._ALIASES[pattern] || pattern);
}
}
function isBlank(obj: any): boolean {
return obj == null || obj === '';
}

View File

@ -7,7 +7,7 @@
*/
import {Pipe, PipeTransform} from '@angular/core';
import {isBlank, isStringMap} from '../facade/lang';
import {isBlank} from '../facade/lang';
import {NgLocalization, getPluralCategory} from '../localization';
import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
@ -37,7 +37,7 @@ export class I18nPluralPipe implements PipeTransform {
transform(value: number, pluralMap: {[count: string]: string}): string {
if (isBlank(value)) return '';
if (!isStringMap(pluralMap)) {
if (typeof pluralMap !== 'object' || pluralMap === null) {
throw new InvalidPipeArgumentError(I18nPluralPipe, pluralMap);
}

View File

@ -7,7 +7,6 @@
*/
import {Pipe, PipeTransform} from '@angular/core';
import {isBlank, isStringMap} from '../facade/lang';
import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
/**
@ -16,9 +15,10 @@ 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,12 +29,20 @@ 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 (isBlank(value)) return '';
if (value == null) return '';
if (!isStringMap(mapping)) {
if (typeof mapping !== 'object' || typeof value !== 'string') {
throw new InvalidPipeArgumentError(I18nSelectPipe, mapping);
}
return mapping.hasOwnProperty(value) ? mapping[value] : '';
if (mapping.hasOwnProperty(value)) {
return mapping[value];
}
if (mapping.hasOwnProperty('other')) {
return mapping['other'];
}
return '';
}
}

View File

@ -0,0 +1,226 @@
/**
* @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

@ -8,10 +8,6 @@
import {Pipe, PipeTransform} from '@angular/core';
import {Json} from '../facade/lang';
/**
* @ngModule CommonModule
* @whatItDoes Converts value into JSON string.
@ -27,5 +23,5 @@ import {Json} from '../facade/lang';
*/
@Pipe({name: 'json', pure: false})
export class JsonPipe implements PipeTransform {
transform(value: any): string { return Json.stringify(value); }
transform(value: any): string { return JSON.stringify(value, null, 2); }
}

View File

@ -17,7 +17,7 @@ import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
* @howToUse `expression | lowercase`
* @description
*
* Converts value into lowercase string using `String.prototype.toLowerCase()`.
* Converts value into a 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) {
let parts = digits.match(_NUMBER_FORMAT_REGEXP);
const 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 lowercase string using `String.prototype.toUpperCase()`.
* Converts value into an uppercase string using `String.prototype.toUpperCase()`.
*
* ### Example
*

View File

@ -0,0 +1,19 @@
/**
* @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,7 +8,6 @@
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', () => {
@ -66,7 +65,7 @@ export function main() {
it('should add and remove classes based on changes to the expression object', async(() => {
fixture = createTestComponent('<div [ngClass]="objExpr"></div>');
let objExpr = getComponent().objExpr;
const objExpr = getComponent().objExpr;
detectChangesAndExpectClassName('foo');
@ -135,7 +134,7 @@ export function main() {
it('should add and remove classes based on changes to the expression', async(() => {
fixture = createTestComponent('<div [ngClass]="arrExpr"></div>');
let arrExpr = getComponent().arrExpr;
const arrExpr = getComponent().arrExpr;
detectChangesAndExpectClassName('foo');
arrExpr.push('bar');
@ -187,6 +186,13 @@ 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', () => {
@ -253,7 +259,7 @@ export function main() {
it('should co-operate with the class attribute', async(() => {
fixture = createTestComponent('<div [ngClass]="objExpr" class="init foo"></div>');
let objExpr = getComponent().objExpr;
const objExpr = getComponent().objExpr;
objExpr['bar'] = true;
detectChangesAndExpectClassName('init foo bar');
@ -267,7 +273,7 @@ export function main() {
it('should co-operate with the interpolated class attribute', async(() => {
fixture = createTestComponent(`<div [ngClass]="objExpr" class="{{'init foo'}}"></div>`);
let objExpr = getComponent().objExpr;
const objExpr = getComponent().objExpr;
objExpr['bar'] = true;
detectChangesAndExpectClassName(`init foo bar`);
@ -282,7 +288,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>`);
let objExpr = getComponent().objExpr;
const objExpr = getComponent().objExpr;
objExpr['bar'] = true;
detectChangesAndExpectClassName(`init foo bar`);
@ -298,7 +304,7 @@ export function main() {
const template =
'<div class="init foo" [ngClass]="objExpr" [class.baz]="condition"></div>';
fixture = createTestComponent(template);
let objExpr = getComponent().objExpr;
const objExpr = getComponent().objExpr;
detectChangesAndExpectClassName('init foo baz');
@ -316,7 +322,7 @@ export function main() {
async(() => {
const template = '<div class="init" [ngClass]="objExpr" [class]="strExpr"></div>';
fixture = createTestComponent(template);
let cmp = getComponent();
const cmp = getComponent();
detectChangesAndExpectClassName('init foo');
@ -348,4 +354,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 {Component} from '@angular/core';
import {ComponentFixture, TestBed, async} from '@angular/core/testing';
import {Attribute, Component, Directive} from '@angular/core';
import {ComponentFixture, TestBed} from '@angular/core/testing';
import {expect} from '@angular/platform-browser/testing/matchers';
export function main() {
@ -32,93 +32,153 @@ export function main() {
});
describe('switch value changes', () => {
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>';
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>';
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', async(() => {
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', () => {
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', 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>';
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>';
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', 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>';
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>';
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;');
}));
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;');
});
});
});
}

View File

@ -7,13 +7,10 @@
*/
import {LOCALE_ID} from '@angular/core';
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 {TestBed, inject} from '@angular/core/testing';
import {NgLocaleLocalization, NgLocalization, getPluralCategory} from '../src/localization';
export function main() {
describe('l10n', () => {
@ -141,6 +138,23 @@ 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', () => {
var emitter: EventEmitter<any>;
var pipe: AsyncPipe;
var ref: any;
var message = {};
let emitter: EventEmitter<any>;
let pipe: AsyncPipe;
let ref: any;
const message = {};
beforeEach(() => {
emitter = new EventEmitter();
@ -62,7 +62,7 @@ export function main() {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
pipe.transform(emitter);
var newEmitter = new EventEmitter();
const newEmitter = new EventEmitter();
expect(pipe.transform(newEmitter)).toBe(null);
emitter.emit(message);
@ -104,14 +104,14 @@ export function main() {
});
describe('Promise', () => {
var message = new Object();
var pipe: AsyncPipe;
var resolve: (result: any) => void;
var reject: (error: any) => void;
var promise: Promise<any>;
var ref: SpyChangeDetectorRef;
const message = new Object();
let pipe: AsyncPipe;
let resolve: (result: any) => void;
let reject: (error: any) => void;
let promise: Promise<any>;
let ref: SpyChangeDetectorRef;
// adds longer timers for passing tests in IE
var timer = (getDOM() && browserDetection.isIE) ? 50 : 10;
const 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);
var promise = new Promise<any>(() => {});
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) => {
var markForCheck = ref.spy('markForCheck');
const 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', () => {
var pipe = new AsyncPipe(null);
const pipe = new AsyncPipe(null);
expect(pipe.transform(null)).toEqual(null);
});
});
describe('other types', () => {
it('should throw when given an invalid object', () => {
var pipe = new AsyncPipe(null);
const pipe = new AsyncPipe(null);
expect(() => pipe.transform(<any>'some bogus object')).toThrowError();
});
});

View File

@ -8,13 +8,18 @@
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', () => {
var date: Date;
var pipe: 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);
}
// 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
@ -34,7 +39,9 @@ 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(); });
@ -42,85 +49,143 @@ 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 not support other objects', () => {
expect(() => pipe.transform({})).toThrow();
expect(() => pipe.transform('')).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(); });
});
describe('transform', () => {
it('should format each component correctly', () => {
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');
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'
};
if (!browserDetection.isOldChrome) {
expect(pipe.transform(date, 'h')).toEqual('9');
expect(pipe.transform(date, 'hh')).toEqual('09');
expect(pipe.transform(date, 'j')).toEqual('9 AM');
dateFixtures['h'] = '9';
dateFixtures['hh'] = '09';
dateFixtures['j'] = '9 AM';
isoStringWithoutTimeFixtures['h'] = '12';
isoStringWithoutTimeFixtures['hh'] = '12';
isoStringWithoutTimeFixtures['j'] = '12 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) {
expect(pipe.transform(date, 'HH')).toEqual('09');
dateFixtures['HH'] = '09';
isoStringWithoutTimeFixtures['HH'] = '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');
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';
}
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', () => {
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');
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'
};
// IE and Edge can't format a date to minutes and seconds without hours
if (!browserDetection.isEdge && !browserDetection.isIE ||
!browserDetection.supportsNativeIntlApi) {
expect(pipe.transform(date, 'ms')).toEqual('31');
dateFixtures['ms'] = '31';
}
if (!browserDetection.isOldChrome) {
expect(pipe.transform(date, 'jm')).toEqual('9:03 AM');
dateFixtures['jm'] = '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) {
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');
dateFixtures['medium'] = 'Jun 15, 2015 9:03:01 AM';
dateFixtures['short'] = '6/15/2015 9:03 AM';
} else {
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');
dateFixtures['medium'] = 'Jun 15, 2015, 9:03:01 AM';
dateFixtures['short'] = '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) {
expect(pipe.transform(date, 'mediumTime')).toEqual('9:03:01 AM');
expect(pipe.transform(date, 'shortTime')).toEqual('9:03 AM');
dateFixtures['mediumTime'] = '9:03:01 AM';
dateFixtures['shortTime'] = '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', () => {
var localization: NgLocalization;
var pipe: I18nPluralPipe;
let localization: NgLocalization;
let pipe: I18nPluralPipe;
var mapping = {
const 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', () => {
var val = pipe.transform(0, mapping);
const val = pipe.transform(0, mapping);
expect(val).toEqual('No messages.');
});
it('should return 1 text if value is 1', () => {
var val = pipe.transform(1, mapping);
const val = pipe.transform(1, mapping);
expect(val).toEqual('One message.');
});
it('should return category messages', () => {
var val = pipe.transform(4, mapping);
const val = pipe.transform(4, mapping);
expect(val).toEqual('Many messages.');
});
it('should interpolate the value into the text where indicated', () => {
var val = pipe.transform(6, mapping);
const val = pipe.transform(6, mapping);
expect(val).toEqual('There are 6 messages, that is 6.');
});
it('should use "" if value is undefined', () => {
var val = pipe.transform(void(0), mapping);
const val = pipe.transform(void(0), mapping);
expect(val).toEqual('');
});

View File

@ -8,40 +8,35 @@
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', () => {
var pipe: I18nSelectPipe;
var mapping = {'male': 'Invite him.', 'female': 'Invite her.', 'other': 'Invite them.'};
beforeEach(() => { pipe = new I18nSelectPipe(); });
const pipe: I18nSelectPipe = new I18nSelectPipe();
const mapping = {'male': 'Invite him.', 'female': 'Invite her.', 'other': 'Invite them.'};
it('should be marked as pure',
() => { expect(new PipeResolver().resolve(I18nSelectPipe).pure).toEqual(true); });
describe('transform', () => {
it('should return male text if value is male', () => {
var val = pipe.transform('male', mapping);
it('should return the "male" text if value is "male"', () => {
const val = pipe.transform('male', mapping);
expect(val).toEqual('Invite him.');
});
it('should return female text if value is female', () => {
var val = pipe.transform('female', mapping);
it('should return the "female" text if value is "female"', () => {
const val = pipe.transform('female', mapping);
expect(val).toEqual('Invite her.');
});
it('should return "" if value is anything other than male or female', () => {
var val = pipe.transform('Anything else', mapping);
expect(val).toEqual('');
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 use "" if value is undefined', () => {
var val = pipe.transform(void(0), mapping);
expect(val).toEqual('');
});
it('should not support bad arguments',
it('should throw on bad arguments',
() => { expect(() => pipe.transform('male', <any>'hey')).toThrowError(); });
});

View File

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

View File

@ -11,9 +11,9 @@ import {beforeEach, describe, expect, it} from '@angular/core/testing/testing_in
export function main() {
describe('LowerCasePipe', () => {
var upper: string;
var lower: string;
var pipe: LowerCasePipe;
let upper: string;
let lower: string;
let pipe: LowerCasePipe;
beforeEach(() => {
lower = 'something';
@ -23,14 +23,14 @@ export function main() {
describe('transform', () => {
it('should return lowercase', () => {
var val = pipe.transform(upper);
const val = pipe.transform(upper);
expect(val).toEqual(lower);
});
it('should lowercase when there is a new value', () => {
var val = pipe.transform(upper);
const val = pipe.transform(upper);
expect(val).toEqual(lower);
var val2 = pipe.transform('WAT');
const 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', () => {
var pipe: DecimalPipe;
let pipe: DecimalPipe;
beforeEach(() => { pipe = new DecimalPipe('en-US'); });
@ -44,7 +44,7 @@ export function main() {
});
describe('PercentPipe', () => {
var pipe: PercentPipe;
let pipe: PercentPipe;
beforeEach(() => { pipe = new PercentPipe('en-US'); });
@ -60,7 +60,7 @@ export function main() {
});
describe('CurrencyPipe', () => {
var pipe: CurrencyPipe;
let 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', () => {
var list: number[];
var str: string;
var pipe: SlicePipe;
let list: number[];
let str: string;
let pipe: SlicePipe;
beforeEach(() => {
list = [1, 2, 3, 4, 5];
@ -93,8 +93,8 @@ export function main() {
});
it('should work with mutable arrays', async(() => {
let fixture = TestBed.createComponent(TestComp);
let mutable: number[] = [1, 2];
const fixture = TestBed.createComponent(TestComp);
const 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', () => {
var upper: string;
var lower: string;
var pipe: UpperCasePipe;
let upper: string;
let lower: string;
let pipe: UpperCasePipe;
beforeEach(() => {
lower = 'something';
@ -24,14 +24,14 @@ export function main() {
describe('transform', () => {
it('should return uppercase', () => {
var val = pipe.transform(lower);
const val = pipe.transform(lower);
expect(val).toEqual(upper);
});
it('should uppercase when there is a new value', () => {
var val = pipe.transform(lower);
const val = pipe.transform(lower);
expect(val).toEqual(upper);
var val2 = pipe.transform('wat');
const 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 {
var givenPath = path.endsWith('/') ? path.substring(0, path.length - 1) : path;
var currPath =
const givenPath = path.endsWith('/') ? path.substring(0, path.length - 1) : path;
const 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;
var locationState = this._history[this._historyIndex - 1];
const locationState = this._history[this._historyIndex - 1];
if (locationState.path == path && locationState.query == query) {
return;
}
var url = path + (query.length > 0 ? ('?' + query) : '');
const 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);
var history = this._history[this._historyIndex];
const 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;
var url = path + (query.length > 0 ? ('?' + query) : '');
const 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;
var url = path + (query.length > 0 ? ('?' + query) : '');
const url = path + (query.length > 0 ? ('?' + query) : '');
this.internalPath = url;
var externalUrl = this.prepareExternalUrl(url);
const externalUrl = this.prepareExternalUrl(url);
this.urlChanges.push(externalUrl);
}
replaceState(ctx: any, title: string, path: string, query: string): void {
this.internalTitle = title;
var url = path + (query.length > 0 ? ('?' + query) : '');
const url = path + (query.length > 0 ? ('?' + query) : '');
this.internalPath = url;
var externalUrl = this.prepareExternalUrl(url);
const 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();
var nextUrl = this.urlChanges.length > 0 ? this.urlChanges[this.urlChanges.length - 1] : '';
const nextUrl = this.urlChanges.length > 0 ? this.urlChanges[this.urlChanges.length - 1] : '';
this.simulatePopState(nextUrl);
}
}

View File

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

View File

@ -27,7 +27,7 @@ Then you can add an import statement in the `bootstrap` allowing you to bootstra
generated code:
```typescript
main_module.ts
main.module.ts
-------------
import {BrowserModule} from '@angular/platform-browser';
import {Component, NgModule, ApplicationRef} from '@angular/core';
@ -49,7 +49,7 @@ export class MainModule {
bootstrap.ts
-------------
import {MainModuleNgFactory} from './main_module.ngfactory';
import {MainModuleNgFactory} from './main.module.ngfactory';
import {platformBrowser} from '@angular/platform-browser';
platformBrowser().bootstrapModuleFactory(MainModuleNgFactory);

View File

@ -5,9 +5,13 @@
* 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 {NodeReflectorHostContext, ReflectorHost, ReflectorHostContext} from './src/reflector_host';
export {StaticReflector, StaticReflectorHost, StaticSymbol} from './src/static_reflector';
export {CompilerHost, CompilerHostContext, ModuleResolutionHostAdapter, NodeCompilerHostContext} from './src/compiler_host';
export {Extractor} from './src/extractor';
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

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

View File

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

View File

@ -0,0 +1,19 @@
/**
* @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

@ -0,0 +1,32 @@
/**
* @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

@ -0,0 +1,21 @@
/**
* @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

@ -0,0 +1,24 @@
/**
* @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

@ -0,0 +1,23 @@
/**
* @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

@ -0,0 +1,26 @@
/**
* @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

@ -0,0 +1,27 @@
/**
* @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

@ -0,0 +1,19 @@
{
"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,18 @@
/**
* @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} from '@angular/core';
@Component({
selector: 'use-third-party',
template: '<third-party-comp [thirdParty]="title"></third-party-comp>' +
'<another-third-party-comp></another-third-party-comp>',
})
export class ComponentUsingThirdParty {
title: string = 'from 3rd party';
}

View File

@ -12,6 +12,10 @@
<source>Welcome</source>
<target>tervetuloa</target>
</trans-unit>
<trans-unit id="63a85808f03b8181e36a952e0fa38202c2304862" datatype="html">
<source>other-3rdP-component</source>
<target>other-3rdP-component</target>
</trans-unit>
</body>
</file>
</xliff>

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