Compare commits

...

440 Commits

Author SHA1 Message Date
712d1a7c37 chore(release): v2.0.1 2016-09-23 11:28:36 -07:00
16601f9359 docs(changelog): add changelog for 2.0.1 2016-09-23 10:50:42 -07:00
b81e2e7a31 fix(upgrade): allow attribute selectors for components in ng2 which are not part of upgrade (#11808)
fixes #11280
2016-09-23 10:48:47 -07:00
98fac36706 docs(Component): API docs for .encapsulation and .interpolation 2016-09-23 10:22:24 -07:00
3e780c032e refactor: misc cleanup 2016-09-23 10:22:05 -07:00
e09882180e refactor(common): cleanup (#11668) 2016-09-23 10:21:58 -07:00
0e18c57a17 docs(core): mark TestBed as stable api and add preliminary docs (#11767)
TestBed was accidentaly ommited from the 'stable' api list during the API sweep before final. We do consider it to be stable.
2016-09-23 10:21:50 -07:00
51e2b9c073 docs(contributing): remove preview references (#11795) 2016-09-23 10:21:44 -07:00
f218e240d3 ci(BrowserStack): add Safari 10 (#11796) 2016-09-23 10:21:31 -07:00
af6b219f8e refactor(TemplateParser): clearer error message for on* binding (#11802)
fixes #11756
2016-09-23 10:21:15 -07:00
20addf5f9f chore(ISSUE_TEMPLATE): update Angular version field (#11821) 2016-09-23 10:21:02 -07:00
2860418a3c fix(forms): disable all radios with disable() 2016-09-23 10:19:58 -07:00
39e251eea7 fix(forms): support unbound disabled in ngModel (#11736) 2016-09-23 10:19:46 -07:00
d7d716d5db chore(zone.js): update to 0.6.25 (#11725) 2016-09-23 10:19:30 -07:00
a95d65241c fix(compiler): Safe property access expressions work in event bindings (#11724) 2016-09-23 10:19:24 -07:00
fdb22bd185 refactor: misc cleanup (#11654) 2016-09-23 10:18:38 -07:00
51d73d3e4e fix(forms): make setDisabledState optional for reactive form directives (#11731)
Closes #11719
2016-09-19 16:26:33 -07:00
bf81b06a28 docs(forms): add select control examples (#11728) 2016-09-19 16:25:33 -07:00
0621f07a2c refactor: misc cleanup 2016-09-19 16:24:31 -07:00
1225ecfb14 chore(node): allow current node version
node current is 6.6.0
see https://github.com/nodejs/LTS#lts_schedule
2016-09-19 16:24:31 -07:00
5509453e72 refactor(common): pipe code cleanup 2016-09-19 16:19:28 -07:00
70488ed382 fix(OfflineCompiler): support older TS versions (#11734) 2016-09-19 15:36:25 -07:00
03aedbe54b fix(OfflineCompiler): Do not provide I18N values when they're not specified
fixes #11643
2016-09-19 10:44:33 -07:00
8395aab25d refactor(OfflineCompiler): cleanup 2016-09-19 10:44:33 -07:00
0dc15eb64a fix(ContentChild): query descendants by default
fixes #1645
2016-09-19 10:42:46 -07:00
cba885a1fb refactor: code cleanup 2016-09-19 10:42:46 -07:00
fa4723a208 docs(forms): add radio button examples (#11676) 2016-09-19 10:41:20 -07:00
5bf08b886f build(npm): update fsevents to 1.0.14 (#11686)
fixes #11685
2016-09-18 16:04:46 -07:00
89802316b9 docs(injector): API docs - remove lone code-block backticks (#11653)
The triple backticks in the markdown of the API entry are unbalanced.
2016-09-18 16:04:04 -07:00
2300c23332 fix(docs): Fixed wording for NgModule schemas (#11620) 2016-09-18 16:03:43 -07:00
fa39965a37 build(gulp): fail on ddescribe / iit left in tests
Closes #10524
2016-09-18 16:01:50 -07:00
115f0fa842 refactor(gulpfile): cleanup, add comments 2016-09-18 16:01:50 -07:00
734b8b8c13 fix(compiler): [attribute~=value] selector (#11696)
Change the seperator regular expression to ignore tildes which are followed by an equal sign.

Closes #9644
2016-09-18 15:58:19 -07:00
54b41f57be docs(Host): fix the API example (#11684)
fixes #11681
2016-09-18 15:56:13 -07:00
df4254ae89 refactor(facade): move isPromise to core private (#10573) 2016-09-18 15:55:08 -07:00
14ee75924b fix(common): fix ngOnChanges signature of NgTemplateOutlet directive 2016-09-15 11:00:30 -07:00
bd4045b6e7 fix(MetadataResolver): throw Component.moduleId is not a string
fixes #11590
2016-09-15 10:57:37 -07:00
255099aa61 refactor(MetadataResolver): cleanup 2016-09-15 10:57:37 -07:00
1c24096650 refactor(benchpress): add more types 2016-09-15 10:17:10 -07:00
32aeb1052d refactor(benchpress): normalize phase b into B and e into E
This simplifies the perflog metrics and prevents future errors.
2016-09-15 10:17:10 -07:00
838d4bbf6c fix(benchpress): support measuring scriptTime and other metrics of page reload.
E.g. for benchmarks that measure page start time
2016-09-15 10:17:10 -07:00
c4114c2f66 finished refactoring 2016-09-15 10:17:10 -07:00
37b8691c8c refactor(benchpress): remove chrome < v44 support 2016-09-15 10:17:10 -07:00
93054d4e3d refactor(benchpress): remove facades from chrome_driver_extension 2016-09-15 10:17:10 -07:00
cfc12c6539 docs(api): changes to correct jade errors in API doc gen (#11619) 2016-09-15 09:09:00 -07:00
c0bdd89b5d docs(readme): update the note about RC 2016-09-14 19:37:19 -07:00
d5515473bf docs: update README.md for npm packages 2016-09-14 17:14:02 -07:00
ffe5c49c3e chore(release): v2.0.0 proprioception-reinforcement 2016-09-14 16:49:10 -07:00
ae1dd5bfd0 docs(changelog): add changelog for bug fixes that landed between rc.7 and 2.0.0 2016-09-14 16:45:16 -07:00
cb657c4b55 docs: update descriptions in package.jsons 2016-09-14 16:44:39 -07:00
42f60ca303 docs(core): update dts file 2016-09-14 15:27:33 -07:00
e33037a2f1 docs(core): docs for Directive and Component 2016-09-14 15:27:33 -07:00
9cee8bcc83 docs(common): add directives docs
Closes #11581
2016-09-14 15:24:01 -07:00
003294d5df docs(core): fix examples 2016-09-14 14:53:30 -07:00
785292f44f chore(core): reexport query metadata decorators 2016-09-14 14:53:30 -07:00
15c2912527 chore(core): update public api file 2016-09-14 14:53:30 -07:00
096ae7c404 docs(core): updates query decorator docs 2016-09-14 14:53:30 -07:00
5972fdc817 docs(core): extract how to examples 2016-09-14 14:53:30 -07:00
2c42a50fc3 docs(pipes): updated pipe documentation 2016-09-14 14:32:09 -07:00
caa1cd2470 docs(pipes): move pipe examples to the common folder 2016-09-14 14:26:00 -07:00
5fad37df69 Revert "chore(core): update public api file"
This reverts commit 727c2b38a4.

Revert "docs(core): updates query decorator docs"

This reverts commit b6287ccc51.

Revert "docs(core): extract how to examples"

This reverts commit 69e8ace884.
2016-09-14 13:34:25 -07:00
727c2b38a4 chore(core): update public api file 2016-09-14 13:22:09 -07:00
b6287ccc51 docs(core): updates query decorator docs 2016-09-14 13:22:09 -07:00
69e8ace884 docs(core): extract how to examples 2016-09-14 13:22:09 -07:00
85d9db6bc4 fix(platform-browser): provide Title service as part of the module (#11605)
Fixes #11600
2016-09-14 13:21:23 -07:00
0a2132ef10 docs(di): update docs on di 2016-09-14 11:57:31 -07:00
d299ce4bcf docs(lifecycle): update docs for lifecycle hooks 2016-09-14 11:51:03 -07:00
0b9425bbb4 fix(examples): make them work with noImplicitAny and declarations:true 2016-09-14 11:29:31 -07:00
1a035a0dc7 build(examples): include in main tsconfig.json
Also rename `examples/tsconfig.json` into `examples/tsconfig-build.json`
so that it does not shadow the main `tsconfig.json` in editors

Also adds `noImplicitAny` and `declarations`
`examples/tsconfig.json`.
2016-09-14 11:29:31 -07:00
84b4338ab5 build(example): fix tsconfig (#11593) 2016-09-14 07:40:58 -07:00
b847257b16 refactor(ShadowCss): remove a comment that trigger an issue with webpack (#11587)
fixes #11584
2016-09-13 21:59:11 -07:00
c65d139081 build: remove JS suffix from the license banner 2016-09-13 21:48:58 -07:00
57f0269491 build(examples): fail build.sh if errors are found 2016-09-13 21:48:58 -07:00
4e6c41b3a1 build(examples): work around protractor typings issues and fix existing type errors
This works around the typings issues until we have a build of protractor with typings that don't
polute global types via ambient type definitions
2016-09-13 21:48:58 -07:00
7105021c41 docs(forms): add docs for FormArray 2016-09-13 14:00:52 -07:00
f7313db0be docs(forms): add docs for FormGroup 2016-09-13 14:00:52 -07:00
1d2e70e3a4 docs(forms): add docs for FormControl 2016-09-13 14:00:52 -07:00
21516c32e6 docs(forms): add docs for AbstractControl 2016-09-13 14:00:52 -07:00
00a24b63da build(npm): roll back jasmine 2.5 upgrade due to console reporter issues (#11573)
2.5.1 no longer prints dots in the './test.sh node' mode
2016-09-13 13:32:58 -07:00
e71558ba89 docs(forms): update docs for FormBuilder (#11548) 2016-09-13 13:23:31 -07:00
7ac47acc1c docs(core): updates docs for query metadata 2016-09-13 11:28:12 -07:00
60e49a7e4b docs(core): add an example of using ViewChildren 2016-09-13 11:28:12 -07:00
c71e35cbf5 docs(core): add an example of using ViewChild 2016-09-13 11:28:12 -07:00
1348c65b0c docs(core): add an example of using ContentChildren 2016-09-13 11:28:12 -07:00
ff03d87cdd docs(core): add an example of using ContentChild 2016-09-13 11:28:12 -07:00
a2bf334e6e chore(benchpress): update package.json and add publish script 2016-09-13 10:49:16 -07:00
f8690caa98 chore: refactor build script to allow to build individual packages 2016-09-13 10:49:16 -07:00
aa713d1dd9 docs(readme): fixed visual of browserstack link (#11552)
Instead of using a variable for the link of browserstack it was using the direct https link.
That caused to show the text and the link (incorrect markdown).
Moved the https link to the bottom with the other link assignments. It will now only show the blue text with the link to the browserstack.
2016-09-13 10:06:02 -07:00
a2519c6164 fix(upgrade): correct the main entry path in package.json 2016-09-13 10:03:45 -07:00
fa994810d5 chore(release): v2.0.0-rc.7 2016-09-12 23:25:28 -07:00
c54580a4af docs(changelog): add release notes for 2.0.0-rc.7 2016-09-12 23:25:05 -07:00
730415e048 build: temporarily disable building and testing of documentation examples
This is due to protractor typings issue that breaks the compilation.
2016-09-12 23:06:38 -07:00
42a287fabf fix(core): make name in Pipe non optional 2016-09-12 22:47:54 -07:00
42d442dcd5 refactor(core): add a name to all decorators and other fixes 2016-09-12 22:47:54 -07:00
cc2873a94d chore: update typings
Note that the typings don’t reflect the shape of the metadata
due to a bug in the public-api-guard
2016-09-12 22:47:54 -07:00
63e15ffaec refactor(core): remove …Metadata for all decorators and use the decorator directly.
BREAKING CHANGE:
- all `…Metadata` classes have been removed. Use the corresponding decorator
  as constructor or for `instanceof` checks instead.
- Example:
  * Before: `new ComponentMetadata(…)`
  * After: `new Component(…)`
- Note: `new Component(…)` worked before as well.
2016-09-12 22:47:54 -07:00
1b15170c89 refactor(core): simplify decorators
Every decorator now is made of the following:
- a function that can be used
as a decorator or as a constructor. This function
also can be used for `instanceof` checks.
- a type for this function (callable and newable)
- a type that describes the shape of the data
  that the user needs to pass to the decorator
  as well as the instance of the metadata

The docs for decorators live at the followig places
so that IDEs can discover them correctly:
- General description of the decorator is placed on the
  `...Decorator` interface on the callable function
  definition
- Property descriptions are placed on the interface
  that describes the metadata produces by the decorator
2016-09-12 22:47:54 -07:00
26d1423ae9 docs(forms): update docs for NgForm (#11547) 2016-09-12 17:01:04 -07:00
61aad7925f fix(forms): fix resetting radios (#11546)
Closes #11516
2016-09-12 15:15:58 -07:00
79055f727b fix(forms): support dots in control names in contains (#11542)
Closes #11535
2016-09-12 15:15:50 -07:00
220d8377fe build(npm): update to jasmine@2.5.1
Closes #11390
2016-09-12 12:54:52 -07:00
cc7780adf7 build(npm): update to rxjs@5.0.0-beta.12
Fixes #11300
2016-09-12 12:05:00 -07:00
051a6ebe12 feat(zone): upgrade to zone.js@0.6.21 2016-09-12 11:48:24 -07:00
c9513b713a docs(forms): add example apps for ngModelGroup (#11525) 2016-09-12 11:45:48 -07:00
66e38b6754 docs(forms): add example apps for ngModel (#11524) 2016-09-12 11:27:29 -07:00
7b82877ee5 fix(Localization): BCP47 uses hyphens as separator (#11514)
https://tools.ietf.org/html/bcp47
2016-09-12 11:27:15 -07:00
c9ad5e46d6 docs(forms): add example app for formArrayName (#11512) 2016-09-12 11:26:43 -07:00
2cdd051109 docs(forms): update example for formGroupName (#11510) 2016-09-12 11:26:18 -07:00
57cb82052b docs(forms): add example app for formControlDirective (#11508) 2016-09-12 11:24:09 -07:00
dd8204a655 docs(forms): update example for formGroupDirective 2016-09-12 11:22:51 -07:00
cdda4082de docs(forms): add example app for formControlName 2016-09-12 11:22:51 -07:00
0614c8c99d chore(router): update publicapi 2016-09-12 10:02:48 -07:00
a343a8e1c2 docs(router): fix typos 2016-09-12 09:47:44 -07:00
a41c1bbdf4 docs(router): update docs of the router lifecycle interfaces 2016-09-10 16:55:14 -07:00
f2c6157e74 docs(router): update docs of RouteModule and RouterTestingModule 2016-09-10 16:55:13 -07:00
32564ece27 docs(router): update RouterState docs 2016-09-10 16:55:13 -07:00
3eee62fa71 docs(router): update router configuration docs 2016-09-10 16:55:13 -07:00
617475005f docs(router): update docs of the Router service 2016-09-10 16:55:13 -07:00
0822066175 docs(router): update docs for router directives 2016-09-10 16:55:13 -07:00
82f30e09f0 refactor(common): cleanup directive tests 2016-09-09 14:30:18 -07:00
c649a5c5ab refactor(common): cleanup directives 2016-09-09 14:30:18 -07:00
53f0c2206d fix(forms): rename validator change fn due to conflict (#11492)
Closes #11479
2016-09-09 14:09:11 -07:00
0bce3907b8 fix(tests): add missing import (#11490) 2016-09-09 14:08:47 -07:00
2170379251 refactor(common): cleanup, strip deprecated doc (#11469) 2016-09-09 12:05:06 -07:00
5a4e46db20 refactor(tests): simplify code (#11485) 2016-09-09 12:04:38 -07:00
f5d44a42c9 refactor(NgClass): cleanup, readability (#11467) 2016-09-09 12:03:51 -07:00
673de004d2 fix(forms): clear errors on disable (#11463)
Closes #11287
2016-09-09 12:00:38 -07:00
f386cb4ba9 Fix benchpress for newest protractor and selenium (#11451)
* chore: update protractor and selenium-webdriver packages

As `karma-jasmine` has a peer dependency on `jasmine-core@2.3`, but `jasmine` and `protractor` are using `jasmine-core@2.4` we need to add `jasmine-core@2.3` explicitly. Previously, the peer dependency was
satisfied by accident because npm deduped the dependency
for `jasmine-core@2.3` as top level dependency.

Note that the shrink-wrap files changes quite a bit because
of the deduping mechanism of npm.

* fix(benchpress): make it work with latest protractor and seleniuv-webdriver

* fix(e2e_tests): make them work with latest protractor
2016-09-09 10:37:47 -07:00
71e9cae1d0 chore(github): update issue template to hide comments (#11473)
Wrap additional descriptions in comments so that they are hidden in created issues (only visible during editing)
2016-09-09 09:36:53 -07:00
df6762a170 docs(TestBed): Fix to current packageing (#11472) 2016-09-09 09:36:38 -07:00
d296298282 fix(build): prevent package tsconfigs from shadowing main tsconfig (#11454) 2016-09-08 15:01:22 -07:00
077e0be1e7 fix(CssSelector): fix getMatchingElementTemplate() for void tags
fixes #11407
2016-09-08 13:55:41 -07:00
a52d076912 refactor(CssSelector): misc 2016-09-08 13:55:41 -07:00
dae7cfc454 chore(github): update pull request template fix link (#11449)
Fix the link to the contribution guildelines -  commit message guidlines
2016-09-08 13:54:30 -07:00
436af15d63 refactor: remove parseFloat from facades (#11446) 2016-09-08 13:54:10 -07:00
7b24028437 fix(forms): fix disabled support for empty form containers (#11427)
Closes #11386
2016-09-08 12:21:48 -07:00
6a2bbffe10 fix(animations): allow group() to be used as entry point for an animation trigger (#11419)
Closes #11312
Closes #11419
2016-09-08 12:20:07 -07:00
f78e184822 docs(FactoryProvider): add missing backtick (#11444) 2016-09-08 09:18:37 -07:00
78ad9adc1a fix(ShadowCss): fix perf regression (#11420)
fixes #11371
2016-09-07 16:48:10 -07:00
9e2ec7a1aa fix(ngc): use the compilerHost to detect file existence (#11418) 2016-09-07 16:24:52 -07:00
643afa4b15 docs(cheatsheet): fix typo NgModule definition (#11377)
`.Class` and not `.class` in js approach for NgModule definition.
2016-09-07 16:05:05 -07:00
ed2ebeb52a fix(build): test example directories with unit and e2e tests (#11296) 2016-09-07 16:04:33 -07:00
567900e550 chore(github): update issue template (#11415) 2016-09-07 14:10:47 -07:00
cc958c74ad docs(router): Fix typo of segment name and odd quote (#11409) 2016-09-07 14:10:19 -07:00
62af613741 chore: update triage and labels process (#11403) 2016-09-07 14:10:01 -07:00
3ff816afa6 style(CompileMetadataResolver): better error message (#11401) 2016-09-07 14:09:25 -07:00
dd03bf12e1 docs: misc fixes.
docs(common_module): Fix macro format
docs(number_pipe): Add missing period sign
docs(date_pipe): Fix suffix consistency
docs(date_pipe): Fix missing quote
docs(number_pipe): Fix incorrect article

Looks like the word "Polyfill" does not start with a vowel pronunciation.

docs(location_strategy): Fix code format

Add missing \`\`\` at start.

docs(i18n_plural_pipe): Fix code format
docs(location): Add missing period sign
refactor(ngSwitch): fix typo on parameter
docs(di): Add missing quote
docs(compiler): Fix typo
docs(compiler): Add missing period sign
docs(directives): Fix description for styles parameter
docs(location_strategy): Add code language

Revert for misunderstanding.
2016-09-06 15:45:37 -07:00
645108f25b test: cleanup playground/src/bootstrap.ts file 2016-09-06 15:35:10 -07:00
882efd125e build: remove obsolete presubmit.sh script 2016-09-06 15:35:10 -07:00
d91e92c2f5 build(test.sh): clear dist directory when the script starts
This is to prevent stale files causing the tests to fail when we run them locally after checking out a new revision.
2016-09-06 15:35:10 -07:00
8858ebc4ab ci: update SauceLabs badge when running CI on master (#11352) 2016-09-06 12:07:48 -07:00
df4c0a3d1f refactor(benchmarks): align tree benchmark with largetable benchmark
- add ng2_switch benchmark to track `ngFor` over `ngSwitch`
- measure create only, createDestroy and update
- simplify the created dom
- always add a style binding
2016-09-06 12:07:12 -07:00
b4363bc8af feat(benchmarks): add targetable benchmarks back 2016-09-06 12:07:12 -07:00
d26a827494 fix(lazy-loading): fix an issue with webpack and lazy loader. (#11387)
The issue was introduced in PR#11049.
2016-09-06 12:06:18 -07:00
ea95c391c1 fix(compiler): error when NgModule.bootstrap contains undefined or null 2016-09-06 11:44:56 -07:00
aa9b617c9d fix(compiler): correctly type event handler proxy functions 2016-09-06 11:44:56 -07:00
7192fec841 refactor(EventManager): remove ListWrapper (#11363) 2016-09-06 11:23:00 -07:00
ee88c3c976 fix typo (#11265)
meesage => message
2016-09-06 10:26:51 -07:00
1ff0add29e docs(CHANGELOG): fix provider syntax (#11258)
fixes #11256
2016-09-06 10:26:20 -07:00
5ee0f09b92 build: update the symlinks scripts for Windows to new packaging (#11192) 2016-09-06 10:25:59 -07:00
70b0ab457b style(dom_renderer): use const (#11229) 2016-09-06 10:25:16 -07:00
c25d1f7ecc test: reactivate the remaining disabled tests in Edge (#11188)
Fixes #4756
2016-09-06 10:24:48 -07:00
a45769a0a2 test(offline_compiler_test.sh): lock down npm dependencies 2016-09-02 15:58:46 -07:00
109dc99d32 build(npm): remove obsolete npm dependencies
I also removed an obsolete bundling script which depended on systemjs-builder that I removed.
2016-09-02 15:58:46 -07:00
2371d22d49 chore: remove obsolete dart related files 2016-09-02 15:58:46 -07:00
6f4b6edfea chore(git): cleanup .gitignore
all obsolete paths have been removed
2016-09-02 15:58:46 -07:00
8c09933803 fix(forms): support rebinding nested controls (#11210) 2016-09-02 15:57:35 -07:00
d309f7799c fix(DomSchema): add missing elements
fixes #11219
2016-09-02 15:35:36 -07:00
93deff6c33 refactor(DomSchema): improve readability by making the schema more explicit using interface names 2016-09-02 15:35:36 -07:00
c31535982c fix(ngc): prepend a rootDir when assuming a file exists (#11291)
Otherwise we'll later try to resolve the file under one of the rootDirs and won't find it.
2016-09-02 14:52:14 -07:00
f5101782d9 docs(router): Fixed examples for router.navigate (#11263) 2016-09-02 13:42:51 -07:00
5e5ae3cde6 fix(ngc): propagate errors to main (#11214) 2016-09-01 16:54:37 -07:00
53cf71430f build(publish): shallow fetch to improve perfs (depth=1) 2016-09-01 16:53:51 -07:00
04d02b55d1 build(publish): replace version placeholders in .min.js files 2016-09-01 16:53:51 -07:00
043493cb62 fix(forms): disabled controls should never be invalid (#11257)
Closes #11253
2016-09-01 16:51:42 -07:00
2581c0851a feat(benchmarks): add incremental-dom version of deep tree benchmark 2016-09-01 14:13:33 -07:00
27d72e87c3 feat(benchmarks): add baseline for deep tree that only used createElement 2016-09-01 14:13:33 -07:00
eef4c22e87 feat(benchmarks): add static tree benchmark 2016-09-01 14:13:33 -07:00
4287f1716d chore: add incremental-dom as dev dependency 2016-09-01 14:13:33 -07:00
ebc8e808a9 feat(router): register NgModuleFactory objects. (#11211)
When lazily loading code, users need to be able to get hold of the
NgModuleFactory. For SystemJS environments, the SystemJS registry serves
this purpose. However other environments, such as modules compiled with
Closure compiler, do not expose exports object or a path based registry.

For these environments, `@NgModule` objects can include an identifier, and
the loading code can then pass `loadModule(id).then(() =>
getNgModule(id))` to the router.
2016-09-01 13:46:08 -07:00
c9e5b599e4 fix(animations): ensure parent animations are triggered before children (#11201) 2016-09-01 13:24:26 -07:00
e42a057048 docs(cheatsheet): complete the copy edit (#11215)
…and general cleanup of the cheatsheet.
2016-09-01 12:06:42 -07:00
0bb94df1da docs(core): docs fixes (#11212) 2016-09-01 11:45:59 -07:00
50e171c09b docs(CHANGELOG): add missing animation feature for RC6 (#11216) 2016-09-01 11:40:36 -07:00
96697029c9 docs(changelog): small fixes 2016-08-31 22:26:31 -07:00
7c3b1367bc docs(changelog): add notes about required SystemJS and Karma config changes 2016-08-31 22:23:54 -07:00
18be339ee9 chore: upgrade chrome to v53 (#11213) 2016-08-31 16:59:17 -07:00
ddda62b1f2 docs(router): add changelog for 3.0.0-rc.2 2016-08-31 16:55:18 -07:00
0ddae9b727 chore(release): bump Angular version to 2.0.0-rc.6 in package.json 2016-08-31 16:49:14 -07:00
625b105d3a docs(changelog): add changelog for 2.0.0-rc.6 2016-08-31 16:49:14 -07:00
f9eb1f33f4 fix(platform-webworker): remove trailing comma in package.json 2016-08-31 16:49:14 -07:00
046c1a8a25 fix(compiler-cli): update package.json to tsc-wrapped@0.3.0 2016-08-31 16:49:14 -07:00
08e48c8f73 fix(router): correct peerDependencies info in package.json 2016-08-31 16:49:14 -07:00
1b5e2b5129 test: add Intl polyfill and run Intl tests in all browsers (#10471) 2016-08-31 15:55:13 -07:00
562c8263dc fix(animations): ensure animation callbacks are fired for embedded views 2016-08-31 15:46:23 -07:00
99c0a7fae2 fix(tsc-wrapped): correct the tsickle dependency in package.json 2016-08-31 15:10:09 -07:00
f4f6f4b4d8 fix(core): don't require reflect-metadata shim when in AOT mode 2016-08-31 15:10:09 -07:00
cc89ef6c8c fix(core): report errors for missing di tokens correctly (#11209) 2016-08-31 14:47:56 -07:00
6ea5b05e7c refactor(benchmarks): make setup nicer
- simplify and correct systemjs config
- remove deep imports into Ng2 packages to work with bundles
- have separate Ng2 and Polymer bootstrap files
2016-08-31 11:24:22 -07:00
f7b5478e9f feat(benchmarks): add polymer_leaves benchmark 2016-08-31 08:24:11 -07:00
873233e825 feat(benchpress): also report the statistics in the generated file 2016-08-31 08:24:11 -07:00
942104d9ac fix(benchpress): support chrome 52
Without this fix, the `scriptTime` was always 0.
2016-08-31 08:24:10 -07:00
6dceaf209d fix(benchmarks): recreate setup for running benchmarks 2016-08-31 08:24:10 -07:00
2ab07d9418 chore: cleanup stale protractor files 2016-08-31 08:24:10 -07:00
1ef122988e fix(benchpress): make code compile and unit tests green again 2016-08-31 08:24:10 -07:00
db280fc67e chore: move benchpress to @angular/benchpress 2016-08-31 08:24:09 -07:00
ef0f29c372 fix: merge artifact 2016-08-30 21:37:28 -07:00
1818056912 fix(TemplateParser): disallow event-property binding even with the NO_ERRORS_SCHEMA
closes #11026
2016-08-30 21:32:24 -07:00
1df69cb4d2 fix(DomSchemaRegistry): detect invalid elements 2016-08-30 21:32:03 -07:00
2b20db6c5a chore: update to typescript@2.0.2 - the currect 2.0 rc 2016-08-30 21:07:45 -07:00
174c016104 fix(bundles): correct RxJS mapping in rollup config for umd/es5 bundles 2016-08-30 21:07:45 -07:00
71ae2c4525 refactor(webworkers): move webworkers to separate @angular/platform-webworker and @angular/platform-webworker-dynamic packages
BREAKING CHANGE: web worker platform is now exported via separate packages.

Please use @angular/platform-webworker and @angular/platform-webworker-dynamic
2016-08-30 21:07:45 -07:00
0f68351979 fix(Router): fix type (#11181) 2016-08-30 21:06:38 -07:00
c74a438f0c docs(router): fix up the exampesd 2016-08-30 20:37:35 -07:00
c350ba29f6 fix(router): do not use rx/add/operator 2016-08-30 20:37:35 -07:00
6e40ef0f6d refactor: remove requestAnimationFrame from polyfills and platforms (#10528) 2016-08-30 19:58:22 -07:00
24e046fd6a ci(publish): fix multiples umd files (#11179) 2016-08-30 19:58:07 -07:00
979657989b fix(packages): use ES modules for primary build (#11120) 2016-08-30 18:07:40 -07:00
8cb1046ce9 docs(cheatsheet): copy edit bootstrapping.md (#11149)
Also remove Dart-specific code, since the Dart cheatsheet is produced
from dart-lang/angular2.
2016-08-30 08:32:51 -07:00
d53a898f46 edit dependency-injection.md (#11156)
No copy edits to this one, but I removed Dart-specific code, since the
Dart cheatsheet is produced from dart-lang/angular2.

Part of a group of cheatsheet PRs (see #11149).

cc @Foxandxss & @IgorMinar
2016-08-29 18:13:35 -07:00
f9f80003c8 docs(cheatsheet): copy edit class-decorators.md (#11154)
No copy edits to this one, but I removed Dart-specific code, since the
Dart cheatsheet is produced
from dart-lang/angular2.
2016-08-29 18:13:10 -07:00
d59ee3caaa docs(cheatsheet): copy edit component-configuration.md (#11155)
Also remove Dart-specific code, since the Dart cheatsheet is produced
from dart-lang/angular2.

Part of a group of cheatsheet PRs (see #11149).

cc @Foxandxss & @IgorMinar
2016-08-29 18:12:51 -07:00
b8ea71afb6 docs(cheatsheet): copy edit built-in-directives.md (#11153)
Also remove Dart-specific code, since the Dart cheatsheet is produced
from dart-lang/angular2.
2016-08-29 18:12:42 -07:00
e2241a2f92 fix(router): support guards navigating synchronously (#11150) 2016-08-29 17:51:38 -07:00
e8a1566065 fix(forms): support radio buttons with same name but diff parent (#11152)
Closes #10065
2016-08-29 17:49:42 -07:00
d2ad871279 fix(forms): update validity when validator dir changes
closes #11116
2016-08-29 13:12:46 -07:00
0b665c0ece feat(validations): add support to bind validation attributes
This change enables to bind the validations attributes `required`,
`minlength`, `maxlength` and `pattern`.

Closes: #10505, #7393
2016-08-29 13:12:20 -07:00
875e66409c fix(closure): prevent closure renaming of testability interface (#11146) 2016-08-29 13:08:28 -07:00
d7de5c4f8e refactor(compiler): replace CompileIdentifierMap with regular Map
closes #11145

Also rename `CompileIdentifierMetadata.runtime` into `CompileIdentifierMetadata.reference`.

Also remove `CompileIdentifierMetadata.equalsTo` as
now it is enough to just check the `reference` fields for equality.
2016-08-29 12:45:27 -07:00
51877ef4ed fix(compiler): no longer uses assetCacheKey for token identity.
Fixes #10545, Fixes #10538
2016-08-29 12:45:02 -07:00
c377e80670 chore: format benchmarks
closes #11112
2016-08-29 12:43:25 -07:00
61002733bc refactor(benchmarks): make tree benchmark work again 2016-08-29 12:42:57 -07:00
5ff14de1f3 chore: force lf EOL for ts files (#11143) 2016-08-29 12:41:58 -07:00
38069aba35 fix(compiler): make ShadowCSS shim work on Android browser (#11139)
Fixes #11123
2016-08-29 08:18:55 -07:00
7dee1ee4cf test(core): update ErrorHandler tests to handle browsers without stack (#11141)
Fixes #11114
2016-08-29 08:17:45 -07:00
af63378fa0 fix(ShadowCss): properly shim selectors after :host and :host-context (#10997)
fixes #5390

Before the change:

    // original CSS
    :host .foo .bar {...}
    .foo .bar {...}

    // translated to 
    [_nghost-shh-2] .foo .bar {...}
    .foo[_ngcontent-shh-2] .bar[_ngcontent-shh-2] {...}

Note that `.foo` and `.bar` where not scoped and would then apply to nested components.

With this change those selectors are scoped (as they are without  `:host`).

You can explicitly apply the style to inner component by using `>>>` or `/deep/`: `:host >>> .foo`
2016-08-26 16:11:57 -07:00
abad6673e6 fix(ngc): don't quote properties in literal maps (#11110)
Closure compiler treats quoted properties specially, and doesn't rename them.

Fixes #11050
2016-08-26 15:54:34 -07:00
75553200c0 fix(http): encode correct value for %3D (#9790) 2016-08-26 15:47:29 -07:00
6c77d7182a fix(compiler-cli): make ngc to work on Windows (#10919)
Fixes #10792
2016-08-26 15:41:50 -07:00
4a44832114 fix(UrlParser) stop setting default value 'true' (matrix params) (#10946)
This was already fixed recently for query params in #10399.
2016-08-26 15:41:32 -07:00
27539c8b80 refactor(example): refactor forward_ref example into a spec and unignore example specs (#11088) 2016-08-26 15:40:46 -07:00
e220a80093 feat(codegen): Add an error message when the locale is not provided (#11104) 2016-08-26 15:38:48 -07:00
3dd85cb7f1 test(tools): make the test suite to pass on Windows (#10926) 2016-08-26 15:36:04 -07:00
511fe3d9f8 chore(contributing): remove documentation note (#11108) 2016-08-26 15:35:33 -07:00
9ce8ef76bf fix(ErrorHandler): make rethrowError internal so that the interface can be implemented (#11109) 2016-08-26 14:43:42 -07:00
7c07bfff97 fix(errors): [2/2] Rename Exception to Error; remove from public API
BREAKING CHANGE:

Exceptions are no longer part of the public API. We don't expect that anyone should be referring to the Exception types.

ExceptionHandler.call(exception: any, stackTrace?: any, reason?: string): void;
change to:
ErrorHandler.handleError(error: any): void;
2016-08-26 10:37:17 -07:00
86ba072758 fix(errors): [1/2] Rename Exception to Error; remove from public API 2016-08-26 10:37:17 -07:00
fc1e45db92 fix(Router): merge artifacts
closes #11063
closes #11102
2016-08-26 10:32:35 -07:00
a2deafc50f fix(router): add an option to disable initial navigation 2016-08-26 10:32:35 -07:00
2fc5c57b31 feat(router): add support for custom error handlers 2016-08-26 10:32:35 -07:00
93f323cfa2 refactor(router): make RouterLink and RouterLinkWithHref create url in a similar way 2016-08-26 10:32:35 -07:00
bb9dfbc578 fix(router): use encodeUri/decodeUri to encode fragment 2016-08-26 10:32:35 -07:00
0bb516fae2 fix(router): fix the order of guards, so canActivateChild runs before canActivate 2016-08-26 10:32:35 -07:00
2ffecc0e14 fix(router): update the location before activating components 2016-08-26 10:32:35 -07:00
b9647b7347 fix(i18n): change default locale from en_US to en-US (#11103) 2016-08-26 10:30:10 -07:00
f25c97671a fix(compiler): handle invalid host bindings and events (#11101) 2016-08-26 10:29:53 -07:00
0a053a4cd5 fix(i18n): Currency/Date/Number pipe use injected locale (#11093) 2016-08-26 09:16:01 -07:00
4d7d2a2daa refactor: remove various leftover unused or deprecated code (#11091) 2016-08-26 09:12:27 -07:00
0cf5ece7f8 build: workaround to run presubmit.sh on Windows (#11096) 2016-08-26 09:12:10 -07:00
66df335998 chore(dependencies): switch from es6-shim to core-js (#10884) 2016-08-25 17:28:36 -07:00
fc2fe00d16 fix(compiler): allow tsc-wrapped to be compile with TypeScript 2.0 (#11086) 2016-08-25 17:28:20 -07:00
811962b2bb refactor: rename SanitizationService to Sanitizer and DomSanitizationService to DomSanitizer (#11085)
BREAKING CHANGE: Previously inconsistently named APIs SanitizationService and DomSanitizationService were renamed to Sanitizer and DomSanitizer
2016-08-25 15:41:19 -07:00
b867764b0d refactor(template): remove supporter deprecated var / # (#11084)
BREAKING CHANGES:

- `#` and `var` are not supported any more in expressions, use `let`,
- `var-<name>` could not be used any more on templates, use `let-<name>`,
- `var-<name>` could not be used any more to create a reference, use `ref-<name>`.
2016-08-25 15:21:33 -07:00
ce08982f78 fix(forms): fix conflicting getter name (#11081) 2016-08-25 14:56:31 -07:00
cbe0976426 test: improve perfs by removing unneeded TestBed.compileComponents() calls (#11083) 2016-08-25 14:56:14 -07:00
515ff61fcb fix(forms): fully support rebinding form group directive (#11051) 2016-08-25 14:37:57 -07:00
d7c82f5c0f test: fix memory leak when running test campaign (#11072) 2016-08-25 14:37:46 -07:00
566d4361e2 refactor: remove obsolete analyzeAppProvidersForDeprecatedConfiguration
closes #11028
2016-08-25 13:29:43 -07:00
ea2e5521e8 refactor: replace any[] with Provider[] where possible 2016-08-25 13:29:03 -07:00
eb7d8c702c fix(core): FactoryProvider's deps property should be optional 2016-08-25 13:29:03 -07:00
5d294624fa docs(core): update stability markers for core apis 2016-08-25 13:29:03 -07:00
3aaf064d11 refactor(router): remove ROUTER_DIRECTIVES which were replaced by RouterModule 2016-08-25 13:29:03 -07:00
f38a700e35 docs(upgrade): mark upgrade apis as stable 2016-08-25 13:29:03 -07:00
501b83441d refactor(forms): remove FORM_PROVIDERS, FORM_DIRECTIVES, REACTIVE_FORM_PROVIDERS, REACTIVE_DIRECTIVES
All of these have been replaced by FormsModule and ReactiveFormsModule.
2016-08-25 13:29:03 -07:00
c03e25a7b7 docs(common): mark platform-browser and platform-browser-dynamic apis stable 2016-08-25 13:29:03 -07:00
1f5a5895e5 refactor(common): rename UrlChangeEvent and UrlChangeListener to LocationChangeEvent and LocationChangeListener
These apis are not expected to be used anyone, hence I'm not documenting this change as a breaking.
2016-08-25 13:29:03 -07:00
8a2324f86a docs(common): mark all common apis except for i18n as stable 2016-08-25 13:29:03 -07:00
6335b31702 refactor(common): remove COMMON_DIRECTIVES, COMMON_PIPES, CORE_DIRECTIVES that were replace with CommonModule 2016-08-25 13:29:03 -07:00
6ef7a76e39 doc(form): updating example to avoid "TypeError: Converting circular structure to JSON" (#10184) 2016-08-25 11:14:40 -07:00
cc79dcac7f docs(cheatsheet): update javascript sections (#11070) 2016-08-25 11:12:23 -07:00
dc6f72e963 fix(closure): replace property accesses (#11078)
Accessing a property on the window object must be done with square brackets.
Otherwise closure compiler may collide the symbol's alias between the property
and variable mappings.
Also, accessing the 'provide' property must be done with dot syntax, so that
it can be renamed along with the code that declares such a property.
2016-08-25 11:12:06 -07:00
2b313e4979 feat(forms): add support for disabled controls (#10994) 2016-08-24 16:58:43 -07:00
4f8f8cfc66 feat(animations): make sure animation callback reports the totalTime (#11022)
Closes #11022
2016-08-24 16:55:00 -07:00
8b782818f5 feat(linker): Allow configurable module prefixes and suffixes. (#11049) 2016-08-24 16:54:42 -07:00
bd510ccdbb fix(core): assigns an overriden name to constructor named constructor (#11043)
Fixes #10545
2016-08-24 10:21:13 -07:00
f1ce7607a6 fix(router): canLoad should cancel a navigation instead of failing it (#11001) 2016-08-24 10:20:44 -07:00
7dfcaac730 fix(http): restructure exports so that we don't leak private factory functions (#11016)
Ref #10615
2016-08-23 16:34:57 -07:00
c7a874dd2f feature(ngc): allow codegen to skip over .d.ts inputs (#11021) 2016-08-23 16:26:35 -07:00
aa5c8ca61f fix(compiler): throw descriptive error meesage for invalid NgModule providers (#10947)
Fixes #10714
2016-08-23 16:18:41 -07:00
5c93a8800a fix(core): Share private types through an exported interface. (#11009)
Instead of using declare namespace to share the types. This allows the generated code to be compiled with closure with full optimizations.
2016-08-23 16:18:11 -07:00
05bbb8efcf fix(platform-browser): remove export for private symbol _WORKER_UI_PLATFORM_PROVIDERS. (#11018) 2016-08-23 16:16:40 -07:00
14a30f3ca0 fix(compiler): Correctly handles references to static methods (#11013)
Fixes: #10975
2016-08-23 11:58:12 -07:00
5ddecb18a7 feat(router): throw a helpful error when misusing forRoot() from a lazy module. (#10996) 2016-08-23 11:57:58 -07:00
c02325dd06 docs(DatePipe): add AM/PM designator in description #10998 2016-08-23 11:57:41 -07:00
4a740f23a4 refactor(core): remove deprecated @Component.directives and @Component.pipes
BREAKING CHANGE: previously deprecated @Component.directives and @Component.pipes support was removed.

All the components and pipes now must be declarated via an NgModule. NgModule is the basic
compilation block passed into the Angular compiler via Compiler#compileModuleSync or #compileModuleAsync.

Because of this change, the Compiler#compileComponentAsync and #compileComponentSync were removed as well -
any code doing compilation should compile module instead using the apis mentioned above.

Lastly, since modules are the basic compilation unit, the ngUpgrade module was modified to always require
an NgModule to be passed into the UpgradeAdapter's constructor - previously this was optional.
2016-08-23 09:59:00 -07:00
a782232ca3 refactor(core): fix typo in private property name 2016-08-23 09:59:00 -07:00
a29f9f3ab8 refactor(core/testing): remove deprecated TestComponentBuilder
BREAKING CHANGE: deprecated TestComponentBuilder was removed, please use TestBed instead
2016-08-23 09:59:00 -07:00
3c2b2ff332 test: fix existing tests by removing usage of obsolete stuff like component level directives, AsyncCompleter and TestComponentBuilder 2016-08-23 09:59:00 -07:00
939d318242 refactor(platform-browser-dynamic): Removed TestComponentBuilder from ResourceLoaderCache specs (#10890) 2016-08-23 09:22:33 -07:00
39a2c39cef feat(compiler): Added "strictMetadataEmit" option to ngc (#10951)
ngc can now validate metadata before emitting to verify it doesn't
contain an error symbol that will result in a runtime error if
it is used by the StaticReflector.

To enable this add the section,

  "angularCompilerOptions": {
    "strictMetadataEmit": true
  }

to the top level of the tsconfig.json file passed to ngc.

Enabled metadata validation for packages that are intended to be
used statically.
2016-08-22 17:37:48 -07:00
45e8e73670 refactor(animations): deport TCB away from animation-land forever (#10892)
* feat(animations): support animation trigger template callbacks

* refactor(animations): deport TCB away from animation-land forever
2016-08-22 17:18:25 -07:00
ca41b4f5ff feature(core): update RxJS to 5.0.0-beta.11 (#10648) 2016-08-22 17:17:23 -07:00
3c561475c8 refactor(animations): add an onStart handler for AnimationPlayer (#10360) 2016-08-22 16:39:52 -07:00
23a27776e2 chore: upgrade zone.js to v0.6.17 (#10989) 2016-08-22 16:24:21 -07:00
01111b04ff fix(ngc): codegen allows --strictNullChecks (#10991) 2016-08-22 15:30:18 -07:00
8560e1e4bf fix(ngc): comment out a private keyword in codegen. (#10949)
Workaround for b/30775898
2016-08-22 14:28:09 -07:00
e0fbca9fb0 feat(ngc): support pathmapping using a separate reflector (#10985)
Until we have comprehensive E2E tests, it's too risky to change the
reflector_host Misko wrote before final. But google3 uses path mapping
and needs all imports to be  and all paths to be canonicalized to
the longest rootDir.

This change introduces a subclass of ReflectorHost with overrides for methods
that differ. After final (or when we have good tests), we'll refactor
them back into one class.
2016-08-22 11:48:33 -07:00
a7b76826a0 fix(compiler): Only emit metadata for exported enums (#10957)
Closes: #10955
2016-08-22 10:26:22 -07:00
ece7985b8a chore(formatting): fix formatting for component fixture spec (#10986) 2016-08-22 10:20:21 -07:00
9883e19e2e fix(tests): remove fit in component_fixture_spec (#10961) 2016-08-19 17:12:58 -07:00
c631cfc2fd feat(core): add NO_ERRORS_SCHEMA that allows any properties to be set on any element (#10956)
Often it is useful to test a component without rendering certain directives/components
in its template because these directives require some complicated setup.

You can do that by using NO_ERRORS_SCHEMA.

TestBed.configureTestingModule({
  schemas: [NO_ERRORS_SCHEMA]
});

This would disable all schema checks in your tests.
2016-08-19 16:05:34 -07:00
53c99cfc95 feat(router): add syntax sugar for confuguring RouterTestingModule (#10906) 2016-08-19 16:01:59 -07:00
c56f3f2246 fix(compiler): do not autoinclude components declared as entry points (#10898) 2016-08-19 15:59:50 -07:00
cc0e3d2296 docs(router): Added additional router documentation including cheatsheet updates (#10802) 2016-08-19 15:48:09 -07:00
917d43e108 refactor(tests): add ComponentFixture tests (#10910)
Remove old TestComponentBuilder tests, and keep relevant
ComponentFixture tests as component_fixture_spec.
2016-08-19 15:46:40 -07:00
bb7d55244d fix(zones): bump zone version to 0.6.15 (#10953)
This fixes issues with microtasks being called too early
in certain tests.
2016-08-19 14:35:26 -07:00
8a5eb08672 fix(fakeAsync): have fakeAsync use Proxy zone. (#10797)
Closes #10503

It is possible for code in `beforeEach` to capture and fork a zone
(for example creating `NgZone` in `beforeEach`). Subsequently the code
in `it` may chose to do `fakeAsync`. The issue is that because the
code in `it` can use `NgZone` from the `beforeEach`. it effectively can
escape the `fakeAsync` zone. A solution is to run all of the test in
`ProxyZone` which allows a test to dynamically replace the rules at any
time. This allows the `beforeEach` to fork a zone, and then `it` to
retroactively became `fakeAsync` zone.
2016-08-19 12:10:53 -07:00
477e425f57 fix(http): inline HTTP_PROVIDERS and JSONP_PROVIDERS until the metadata collector can do it automatically. (#10928) 2016-08-18 15:01:07 -07:00
654ff6115a fix(http): deep copy for constructor using existing Headers (#10679)
When creating a new Headers object using an existing Headers object
the existing Headers map is copied by reference. Therefore adding a
new Header value to the new Headers object also added this value to
the existing Headers object which is not in accordance with the
spec.
This commit alters the constructor to create a deep copy of existing
Headers maps and therefore unlink existing Headers from new Headers.

Closes #6845

BREAKING CHANGE: 

any code which relies on the fact that a newly
created Headers object is referencing an existing Headers map is
now broken, but that should normally not be the case since this
behavior is not documented and not in accordance with the spec.
2016-08-18 15:00:44 -07:00
628d06c17c feat(core): Throw a descriptive error when BrowserModule is installed a second time (via lazy loading). (#10899)
Such a configuration is unsupported and causes all kinds of problems.
2016-08-18 13:34:28 -07:00
91980382e8 fix(pipes): remove bidi control chars (#10870)
Fix inconsistent results in Edge vs. other browsers.

Closes #10080.
2016-08-18 13:31:33 -07:00
2f41b5c8a0 refactor(core): Removed test deprecated references from runtime_compiler (#10927)
Removed reference to TestComponentBuilder from runtime_compiler_spec.ts
2016-08-18 11:20:02 -07:00
cd8cbd3762 fix(ngc): don't codegen foo.d.ngfactory.ts from foo.d.ts (#10833) 2016-08-18 10:11:06 -07:00
292ccf882a test(forms): update reactive form integration tests to use TestBed (#10908) 2016-08-17 17:10:56 -07:00
a0e13b9797 refactor(core): remove deprecated functions ReflectiveInjector.fromResolvedBindings and ResolvedReflectiveBinding (#10819) 2016-08-17 16:53:09 -07:00
a5c0349d88 refactor(core): Removed linker test references to TestComponentBuilder (#10903)
Removed references to TestComponentBuilder from:
  query_integration_spec.ts
  regression_integration_spec.ts
  security_integration_spec.ts
  view_injector_integration_spec.ts
2016-08-17 16:52:39 -07:00
c48021ab97 refactor(compiler): move test/test_bindings to testing/test_bindings (#10081)
`test_bindings` is used in core test cases too, but `test` should be
private to the package, so it should live in `testing`.
2016-08-17 16:37:31 -07:00
beb79e75bf refactor(various): remove a few lingering but unused deprecated apis (#10896)
Removes deprecated APPLICATION_COMMON_PROVIDERS, as well as some
internal apis that were deprecated.
2016-08-17 16:36:10 -07:00
0b62b6f783 refactor(debug): switch tests from TCB to use TestBed (#10756) 2016-08-17 16:27:54 -07:00
895c542a20 refactor(directiveLifecycle): switch test from TCB to use TestBed (#10768) 2016-08-17 16:17:07 -07:00
c4fd862e15 fix(metadata): throw better errors when components are passed to imports or modules are passed to declarations. (#10888)
Closes #10823
2016-08-17 15:57:02 -07:00
6f18bd18bb refactor(core): Removed linker test reference to TestComponentBuilder (#10867)
Removed TestComponentBuilder references from ng_container_integration_spect.ts
2016-08-17 15:45:29 -07:00
00e157dc3b refactor(router): update stability labels (#10902) 2016-08-17 15:35:30 -07:00
4be863c223 Remove TCB (#10900)
* refactor(webworker): change tests not to use TestComponentBuilder

* refactor(core): change tests not to use TestComponentBuilder
2016-08-17 15:05:22 -07:00
3009be8d6e docs(security): mark the various DomAdapters as unsafe. (#10868)
Part of #8511.
2016-08-17 13:42:18 -07:00
4829fbb95c refactor(core): Remove linker test references to TestComponentBuilder (#10869)
Removed TestComponentBuilder references from projection_integration_spec.ts
2016-08-17 11:19:38 -07:00
40e160c22c fix(platform-browser-dynamic): Rename CACHED_TEMPLATE_PROVIDER to RESOURCE_CACHE_PROVIDER (#10866)
* fix(platform-browser-dynamic): Rename CACHED_TEMPLATE_PROVIDER to RESOURCE_CACHE_PROVIDER

Closes #9741

BREAKING CHANGE:

`CACHED_TEMPLATE_PROVIDER` is now renamed to `RESOURCE_CACHE_PROVIDER`

Before:

```js
import {CACHED_TEMPLATE_PROVIDER} from '@angular/platform-browser-dynamic';
```

After:

```js
import {RESOURCE_CACHE_PROVIDER} from '@angular/platform-browser-dynamic';
```

* Rename XHR -> ResourceLoader
2016-08-17 09:24:44 -07:00
951ecb4d90 feat(core): update public api 2016-08-17 08:06:32 -07:00
9318033294 refactor(router): update router spec not to use TestComponentBuilder 2016-08-17 08:06:32 -07:00
4648b3e5de feat(testing): add TestBed.get 2016-08-17 08:06:32 -07:00
740e80492d refactor(core): update entry_components_integration_spec not to use TestComponentBuilder 2016-08-17 08:06:32 -07:00
cc22b051e3 refactor(core): update change_detection_integration_spec not to use TestComponentBuilder 2016-08-17 08:06:32 -07:00
75405ae0f5 refactor(core): update forward_ref_integration_spec not to use TestComponentBuilder 2016-08-17 08:06:32 -07:00
f12d51992d fix(animations): report errors for missing host-level referenced animations (#10650)
Closes #10650
2016-08-17 08:00:49 -07:00
6fd5bc075d chore(forms): update forms labels (#10873) 2016-08-17 07:44:39 -07:00
675e582ffd refactor(http): Removed deprecated HTTP_PROVIDERS and JSONP_PROVIDERS (#10864)
BREAKING CHANGE: previously deprecated HTTP_PROVIDERS and JSONP_PROVIDERS were removed; see deprecation notice for migration instructions.
2016-08-17 07:43:31 -07:00
0a22e8eefd refactor(core): Removing linker test references to TestComponentBuilder (#10865)
Removed references to TestComponentBuilder from integration_spec.ts
2016-08-17 07:15:35 -07:00
44a4814766 Update package.json (#10609)
Update compiler-cli dependencies to increment tsc-wrapped to 0.2.2. It appears this was missed in the rc5 release.
2016-08-16 19:40:25 -07:00
3c23238129 docs(ngFor): add documentation for ngForTrackBy (#10780)
* docs(ngFor): add documentation for ngForTrackBy

* wo/ prefix
2016-08-16 19:39:22 -07:00
916ed55d82 chore(docs): remove sentences for dart (#10781) 2016-08-16 19:38:49 -07:00
2451eb9ded docs(router): Explanation in code should be comment (#10790) 2016-08-16 19:38:23 -07:00
ed639784d4 docs(router): Fix mismatching of code and comment (#10791) 2016-08-16 19:37:53 -07:00
b77a3794b8 docs(changelog): added missing closing parenthesis (#10783) 2016-08-16 19:37:24 -07:00
73a9ee4a05 Remove component resolver (#10858)
* refactor(core): remove deprecated ComponentResolver

BREAKING CHANGE: deprecated ComponentResolver was removed

Please follow deprecation instruction and migrate your code to use ComponentFactoryResolver.

* refactor(common): remove deprecated NgSwitchWhen directive

BREAKING CHANGE: previously deprecated NgSwitchWhen directive was removed, use NgSwitchCase instead
2016-08-16 16:48:32 -07:00
9adf80385b fix(animations): remove deprecated trigger APIs (#10825)
BREAKING CHANGE: Animations defined using an at-symbol prefix that are
not property bound are now invalid.

```html
<!-- this is now invalid -->
<div @flip="flipState"></div>

<!-- change that to -->
<div [@flip]="flipState"></div>
```

BREAKING CHANGE: Animations that are not bound using the at-symbol
prefix using `animate-` must now be preixed using `bind-animate-`.

```html
<!-- this is now invalid -->
<div animate-flip="flipState"></div>

<!-- is valid now -->
<div bind-animate-flip="flipState"></div>
```

Closes #10825
2016-08-16 14:09:21 -07:00
a86c554a8e refactor(core/testing): remove deprecated ViewMetadata (#10837)
Note that this doesn't actually remove all uses, but makes them
private.
2016-08-16 13:59:06 -07:00
62078eee45 chore(tsconfig): emit decorator metadata so that tsc watch works with demos (#10863) 2016-08-16 13:53:04 -07:00
24e280a21a refactor(router): remove deprecated apis (#10658) 2016-08-16 13:40:28 -07:00
f7ff6c5a12 refactor(core): remove deprecated 'bootstrap' (#10831) 2016-08-16 11:15:01 -07:00
f6a7d6504c feat(i18n): xliff integration 2016-08-15 22:28:38 -07:00
96bf42261b fix(XmlHelper): declaration 2016-08-15 22:21:40 -07:00
72bb38f83b feat(i18n): xliff 2016-08-15 22:21:40 -07:00
4c9900dc3a refactor(testing): remove deprecated testing functions (#10832)
Remove TestComponentBuilder, addProviders, and withProviders. These
were deprecated in rc5 - see the changelog for update information.

Note - this does not actually remove the functions, but makes them
internal only. They will be removed from the codebase entirely
at a later time.
2016-08-15 21:40:37 -07:00
6b26102931 feat(router): extend support for lazy loading children (#10705) 2016-08-15 21:11:09 -07:00
bec5c5fdad refactor(Provider): remove deprecated provider/bind API (#10652)
Closes #9751

BREAKING CHANGE:

These forms of providers are no longer accepted:
  bind(MyClass).toFactory(...)
  new Provider(MyClass, toFactory: ...)

We now only accept:
  {provider: MyClass, toFactory: ...}
2016-08-15 19:37:42 -07:00
04c11bb749 test(forms): update template-driven form tests to use testbed (#10830) 2016-08-15 16:37:59 -07:00
3f5331be9d refactor(chore): remove deprecated NgZoneError (#10822)
BREAKING CHANGE: previously deprecated NgZoneError has been removed
2016-08-15 16:10:30 -07:00
48751cceae refactor(core): Removed deprecated Query and ViewQuery (#10820)
BREAKING CHANGE: previously deprecated Query and ViewQuery  were removed; see deprecation notice for migration instructions.
2016-08-15 16:07:55 -07:00
4a9745ef78 refactor(core): Remove deprecated DynamicComponentLoader (#10759)
BREAKING CHANGE: previously deprecated DynamicComponentLoader was removed; see deprecation notice for migration instructions.
2016-08-15 16:07:19 -07:00
acc0fe6cf9 refactor(TestBed): remove deprecated TestBed.reset 2016-08-15 14:07:54 -07:00
b238414984 refactor(core): remove previously deprecated SystemJsComponentResolver and SystemJsCmpFactoryResolver
BREAKING CHANGE: previously deprecated SystemJsComponentResolver and SystemJsCmpFactoryResolver have been removed.

Please follow deprecation instructions to migrate your code.
2016-08-15 14:07:54 -07:00
231ed69507 refactor(common): Remove uses of deprecated TestComponentBuilder. (#10754)
* ng_class_spec

* Working through ng_for_spec.

* Finishing up ng_for_spec.

* Finish the rest of the specs.

* Convert pipes tests.
2016-08-15 13:52:57 -07:00
60b10134df cleanup(platform): removed webworker and server deprecated apis (#10745) 2016-08-15 13:44:01 -07:00
73c0a9daaf fix(router): make routerLinkActiveOptions public (#10758) 2016-08-15 00:39:59 -07:00
398bbb6aa9 refactor(core): replace some for statements with map/reduce 2016-08-14 10:10:07 -07:00
05d1312306 refactor(core): Replace all var with const and let 2016-08-14 10:10:07 -07:00
bc6d1c87a6 fix(core): don't strip sourceMappingURL (#9664)
fix #9664
2016-08-14 10:10:07 -07:00
712c7d5c3b fix(datePipe): allow float for date pipe input (#10687) 2016-08-14 10:05:21 -07:00
e9479b30e8 refactor(OutputAst): BuiltinMethod.bind renamed to Bind (#10739) 2016-08-14 10:04:37 -07:00
7f6685e451 test(forms): refactor form model tests to three files (#10774) 2016-08-13 17:26:08 -07:00
ce4eae65a7 feat(i18n): provide LOCALE_ID and NgLocalization 2016-08-13 06:18:25 -07:00
4df48b202c fix(i18n): update NgLocalLocalization (#10771)
ref https://github.com/papandreou/node-cldr/issues/31
2016-08-13 05:43:36 -07:00
33ced7088f refactor(common): remove deprecated ReplacePipe (#10772)
BREAKING CHANGE: previously deprecated ReplacePipe was removed
2016-08-12 21:50:57 -07:00
3329977ec9 refactor(core): remove deprecated coreBootstrap and coreLoadAndBootstrap
BREAKING CHANGE: previously deprecated coreBootstrap and coreLoadAndBootstrap have been removed.

Please follow deprecation instructions to migrate your code.
2016-08-12 18:07:58 -07:00
f84c3fdc5f refactor(ApplicationRef): remove all previously deprecated ApplicationRef apis
BREAKING CHANGE: All previously deprecated ApplicationRef apis have been removed.

Please follow the deprecation instructions to migrate your code.
2016-08-12 17:59:30 -07:00
44e1b23813 refactor(PlatformRef): remove deprecated PlatformRef#registerDisposeListener, #disposed, #dispose()
BREAKING CHANGE: previously deprecated PlatformRef#registerDisposeListener, #disposed, #dispose() - follow deprecation instructions to upgrade
2016-08-12 17:59:30 -07:00
12b0a3d0e5 refactor(NgUpgrade): remove deprecated addProvider
BREAKING CHANGE: previously deprecated UpgradeAdapter#addProvider was removed, see deprecation notice for migration instructions.
2016-08-12 17:59:30 -07:00
d2825077b1 fix(core): Removed depricated disposePlatform
BREAKING CHANGE: previously deprecated disposePlatform was removed; see deprecation notice for migration instructions.
2016-08-12 17:52:13 -07:00
156a52e390 refactor(core): Removed deprecated properties and events from metadata (#10753)
BREAKING CHANGE: previously deprecated DirectiveMetadataType#properties and DirectiveMetadataType#events were removed; see deprecation notice for migration instructions.
2016-08-12 17:44:44 -07:00
bb7221f922 refactor(facade): Removed unnecessary override and deprecation. (#10761) 2016-08-12 17:41:12 -07:00
2eb4ee8393 refactor(core): Removed depricated lockRunMode (#10763)
BREAKING CHANGE: previously deprecated lockRunMode was removed; see deprecation notice for migration instructions.
2016-08-12 17:40:22 -07:00
87fe47737a fix(testing): override metadata subclasses properly (#10767)
This fixes an issue where `TestBed.overrideComponent(MyComp, {})`
would remove some properties including `providers` from the component.

This was due to the override not properly dealing with getter fields
on subclasses.
2016-08-12 17:39:33 -07:00
9317056138 fix(ngc): Revert "fix(ngc): add an option to produce TS1.9-pathMapping imports (#10602)" (#10765)
This reverts commit beadf6167a.
2016-08-12 17:38:29 -07:00
a235ae16ed refactor(core): Removed deprecated DebugNode.inject() (#10751)
BREAKING CHANGE: previously deprecated DebugNode#inject was removed, see deprecation notice for migration instructions.
2016-08-12 15:57:23 -07:00
79afcf0766 fix(forms): remove deprecated form provider functions (#10741)
BREAKING CHANGE:

The deprecated `provideForms()` and `disableDeprecatedForms()` functions have been removed. Please import the `FormsModule` or the `ReactiveFormsModule` from @angular/forms instead.
2016-08-12 15:32:47 -07:00
161a4dd15f feat(i18n): Add NgLocaleLocalization which returns plural cases given a locale (#10744) 2016-08-12 14:46:06 -07:00
6580d67875 feat(i18n): pass translation config directly into ngc (#10622) 2016-08-12 14:45:36 -07:00
04c6b2fe85 fix(router): location changes and redirects break the back button (#10742) 2016-08-12 14:30:51 -07:00
203b2ba637 fix(http): expose jsonpFactory for AoT compilation (#10730) 2016-08-12 11:30:12 -07:00
5b99b8c18a test: add Blob and FormData polyfills for testing in IE9 (#10563) 2016-08-12 10:35:19 -07:00
6a011f4e8e test(security): work around an escaping bug in IE9 (#10493) 2016-08-12 10:34:55 -07:00
f0c1f9ef39 docs(GH): you never know... (#10740) 2016-08-12 10:33:39 -07:00
97f35714f7 feat(forms): add NgForm method that resets submit state (#10715) 2016-08-11 23:27:33 -07:00
00e5b7d30a refactor(SharedStylesHost): remove SetWrapper facade (#10598) 2016-08-11 23:26:57 -07:00
39c0f9ebb3 fix(ExtractorMerger): returns errors together with nodes (as a ParseTreeResult) 2016-08-11 23:24:22 -07:00
e60c765280 refactor: remove unused imports 2016-08-11 23:24:22 -07:00
91dd672aa4 style(xmb): add a space after ICU message cases 2016-08-11 23:24:22 -07:00
a5d2aadecb ci(travis): enable fast finish mode for optional modes. (#10588)
* Travis CI runs the optional tasks in "waiting" mode, which means that the whole build is only ready once the optional tasks are also ready.
   e.g https://travis-ci.org/angular/angular/builds/150844963 - This build lost about 48 minutes just from an optional mode.

* The Travis Fast Finish mode will mark the build as finished, once all "required" tasks have finished.
   https://blog.travis-ci.com/2013-11-27-fast-finishing-builds/
2016-08-11 23:03:28 -07:00
cc6749c158 fix(router): lazy loading keeps refetching modules (#10707) 2016-08-11 22:59:53 -07:00
f48142e679 feat(core): make ngprobe tokens pluggable 2016-08-11 22:56:10 -07:00
947f9c3f56 feat(router): make router.config public 2016-08-11 22:56:10 -07:00
7cd4741fcb fix(http): return empty string if no body is present (#10668) 2016-08-11 21:40:18 -07:00
2d520ae7e7 fix(compiler): Generate temporary variables for guarded expressions (#10657)
Fixes: #10639
2016-08-11 21:20:54 -07:00
5d59c6e80f docs(forms): fix reactive forms api examples (#10701) 2016-08-11 21:20:39 -07:00
50345b8c36 feat(i18n): add an HtmlParser decorator (#10645)
* fix(i18n): merge retains attributes w/o value

* feat(i18n): allow attributes on ng-container (i.e. i18n)

* feat(i18n): add an HtmlParser decorator

* style: clang format
2016-08-11 21:00:35 -07:00
7606c96c80 fix(forms): remove deprecated forms APIs (#10624)
BREAKING CHANGE:

The deprecated forms APIs in @angular/common have been removed. Please update to the new forms API in @angular/forms. See angular.io for more information.
2016-08-11 20:40:46 -07:00
3466232f8b fix(build): Remove duplicate System declarations (#10713)
Add it to a common .d.ts. Prevents closure from complaining of duplicate declarations when compiled using tsickle to generate externs.
2016-08-11 19:37:01 -07:00
6e842fc5bf feat(ngc): allow ngc implementations to provide XHR (#10708) 2016-08-11 15:04:00 -07:00
50c795280f fix: use a global System.import() instead of using a property of the global facade (#10696) 2016-08-11 14:17:44 -07:00
51b22cf14f chore: Fix typos in changelog for rc5 (#10688) 2016-08-11 09:02:12 -07:00
2291929a15 feat(forms): add control status classes to form groups (#10667) 2016-08-11 09:01:09 -07:00
7fac4efede chore(facades): missed a couple places in #10620 (#10661)
This lets us skip src/facade/exception* when compiling modules other than core
2016-08-11 08:39:13 -07:00
b96869afd2 refactor(Type): merge Type and ConcreType<?> into Type<?> (#10616)
Closes #9729

BREAKING CHANGE:

`Type` is now `Type<T>` which means that in most cases you have to
use `Type<any>` in place of `Type`.

We don't expect that any user applications use the `Type` type.
2016-08-10 18:21:28 -07:00
6f4ee6101c chore(imports): don't import ExceptionHandler from facade (#10620)
This lets us skip src/facade/exception* when compiling modules other than core.
It prevents having many conflicting declarations
2016-08-10 15:55:18 -07:00
6db27153ef Router Fixes (#10579)
* fix(router): copy over data during data resolution
* fix(router): components instantiated in lazy-loaded modules should use location's injector
2016-08-10 15:53:57 -07:00
9a11ec2624 fix(metadata): treat empty array of metadata like absent file (#10610) 2016-08-10 11:52:56 -07:00
aff1bc9f2d refactor(tests): move public test APIs to TestBed (#10621)
Completely remove deprecated TestComponentBuilder and friends.
2016-08-10 11:51:40 -07:00
43512aa5eb fix(i18n): ICU placeholders are replaced by their translations (#10586)
They were replaced by the original message.
2016-08-09 21:05:04 -07:00
c7f3aa71fb fix(router): support relative param-only navigation (#10613) 2016-08-09 17:03:17 -07:00
f9da3c98d6 chore: remove deprecated router 2/2 2016-08-09 15:24:14 -07:00
a20a420be6 chore: remove deprecated router 1/2 2016-08-09 15:24:14 -07:00
beadf6167a fix(ngc): add an option to produce TS1.9-pathMapping imports (#10602)
This fixes a regression in #10486
2016-08-09 14:58:19 -07:00
c8da7e995f test(router): Android browser does not support element.click() 2016-08-09 13:25:20 -07:00
8be6b12c2b test(router): use Object.isFrozen instead of relying on an exception 2016-08-09 13:25:20 -07:00
4728f29f67 test(router): increase Karma timers and add polyfills for old browsers 2016-08-09 13:25:20 -07:00
2a942e49ac chore(changelog): update convetional-changelog (#10594)
conventional-changelog-angular@1.3.0 makes breaking changes message detection more forgiving
2016-08-09 11:53:23 -07:00
e3aa19049f chore(router): update changelog 2016-08-09 11:02:04 -07:00
ef1eadadcd chore(router): bump up version number 2016-08-09 11:01:17 -07:00
f444c11d21 docs(changelog): add the ngModel is now fully async note 2016-08-09 10:54:54 -07:00
d75502eeee refactor(testing): remove deprecated test setup functions (#10600)
Remove test setup functions which were deprecated in rc5. See the
changelog for rc5 for how to update. In brief, instead of
`setBaseTestProviders`, use `TestBed.initTestEnvironment`.
2016-08-09 10:46:28 -07:00
1217 changed files with 41366 additions and 62297 deletions

3
.gitattributes vendored
View File

@ -1,8 +1,9 @@
# Auto detect text files and perform LF normalization
* text=auto
# JS files must always use LF for tools to work
# JS and TS files must always use LF for tools to work
*.js eol=lf
*.ts eol=lf
# Must keep Windows line ending to be parsed correctly
scripts/windows/packages.txt eol=crlf

View File

@ -1,33 +1,31 @@
**I'm submitting a ...** (check one with "x")
```
[ ] bug report
[ ] bug report => search github for a similar issue or PR before submitting
[ ] feature request
[ ] support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question
```
**Current behavior**
**Expected/desired behavior**
**Current behavior**
<!-- Describe how the bug manifests. -->
**Expected behavior**
<!-- Describe what the behavior would be without the bug. -->
**Reproduction of the problem**
If the current behavior is a bug or you can illustrate your feature request better with an example, please provide the steps to reproduce and if possible a minimal demo of the problem via https://plnkr.co or similar (you can use this template as a starting point: http://plnkr.co/edit/tpl:AvJOMERrnz94ekVua0u5).
**What is the expected behavior?**
<!-- If the current behavior is a bug or you can illustrate your feature request better with an example, please provide the steps to reproduce and if possible a minimal demo of the problem via https://plnkr.co or similar (you can use this template as a starting point: http://plnkr.co/edit/tpl:AvJOMERrnz94ekVua0u5). -->
**What is the motivation / use case for changing the behavior?**
<!-- Describe the motivation or the concrete use case -->
**Please tell us about your environment:**
<!-- Operating system, IDE, package manager, HTTP server, ... -->
* **Angular version:** 2.0.X
<!-- Check whether this is still an issue in the most recent Angular version -->
* **Angular version:** 2.0.0-rc.X
* **Browser:** [all | Chrome XX | Firefox XX | IE XX | Safari XX | Mobile Chrome XX | Android X.X Web Browser | iOS XX Safari | iOS XX UIWebView | iOS XX WKWebView ]
<!-- All browsers where this could be reproduced -->
* **Language:** [all | TypeScript X.X | ES6/7 | ES5]
* **Language:** [all | TypeScript X.X | ES6/7 | ES5]
* **Node (for AoT issues):** `node --version` =

View File

@ -1,5 +1,5 @@
**Please check if the PR fulfills these requirements**
- [ ] The commit message follows our guidelines: https://github.com/angular/angular/blob/master/CONTRIBUTING.md#commit-message-format
- [ ] The commit message follows our guidelines: https://github.com/angular/angular/blob/master/CONTRIBUTING.md#commit
- [ ] Tests for the changes have been added (for bug fixes / features)
- [ ] Docs have been added / updated (for bug fixes / features)

22
.gitignore vendored
View File

@ -1,26 +1,9 @@
.DS_STORE
# Dont commit the following directories created by pub.
packages
pubspec.lock
.pub
.packages
/dist/
.buildlog
node_modules
bower_components
# Or broccoli working directory
tmp
# Or the files created by dart2js.
*.dart.js
*.dart.precompiled.js
*.js_
*.js.deps
*.js.map
# Include when developing application packages.
pubspec.lock
.c9
@ -37,13 +20,8 @@ modules/.vscode
# Ignore npm debug log
npm-debug.log
/docs/bower_components/
# build-analytics
.build-analytics
# built dart payload tests
/modules_dart/payload/**/build
# rollup-test output
/modules/rollup-test/dist/

2
.nvmrc
View File

@ -1 +1 @@
5.4.1
6.6.0

View File

@ -1,7 +1,7 @@
language: node_js
sudo: false
node_js:
- '5.4.1'
- '6.6.0'
addons:
# firefox: "38.0"
@ -20,20 +20,9 @@ cache:
directories:
- ./node_modules
- ./.chrome/chromium
# - $HOME/.pub-cache
#before_cache:
# # Undo the pollution of the typescript_next build before the cache is primed for future use
# - if [[ "$MODE" == "typescript_next" ]]; then npm install typescript; fi
env:
global:
# - KARMA_JS_BROWSERS=ChromeNoSandbox
# - E2E_BROWSERS=ChromeOnTravis
# - LOGS_DIR=/tmp/angular-build/logs
# - ARCH=linux-x64
# GITHUB_TOKEN_ANGULAR
# This is needed for the e2e Travis matrix task to publish packages to github for continuous packages delivery.
- secure: "fq/U7VDMWO8O8SnAQkdbkoSe2X92PVqg4d044HmRYVmcf6YbO48+xeGJ8yOk0pCBwl3ISO4Q2ot0x546kxfiYBuHkZetlngZxZCtQiFT9kyId8ZKcYdXaIW9OVdw3Gh3tQyUwDucfkVhqcs52D6NZjyE2aWZ4/d1V4kWRO/LMgo="
@ -47,150 +36,16 @@ env:
- CI_MODE=browserstack_optional
matrix:
fast_finish: true
allow_failures:
- env: "CI_MODE=saucelabs_optional"
- env: "CI_MODE=browserstack_optional"
install:
- ./scripts/ci-lite/install.sh
before_script:
script:
- ./scripts/ci-lite/build.sh && ./scripts/ci-lite/test.sh
after_script:
- ./scripts/ci-lite/cleanup.sh
#branches:
# except:
# - g3_v2_0
#
#cache:
# directories:
# - $HOME/.pub-cache
# - $HOME/.chrome/chromium
#
#before_cache:
# # Undo the pollution of the typescript_next build before the cache is primed for future use
# - if [[ "$MODE" == "typescript_next" ]]; then npm install typescript; fi
#
#env:
# global:
# # Use newer verison of GCC to that is required to compile native npm modules for Node v4+ on Ubuntu Precise
# # more info: https://docs.travis-ci.com/user/languages/javascript-with-nodejs#Node.js-v4-(or-io.js-v3)-compiler-requirements
# - CXX=g++-4.8
# - KARMA_DART_BROWSERS=DartiumWithWebPlatform
# # No sandbox mode is needed for Chromium in Travis, it crashes otherwise: https://sites.google.com/a/chromium.org/chromedriver/help/chrome-doesn-t-start
# - KARMA_JS_BROWSERS=ChromeNoSandbox
# - E2E_BROWSERS=ChromeOnTravis
# - LOGS_DIR=/tmp/angular-build/logs
# - SAUCE_USERNAME=angular-ci
# - SAUCE_ACCESS_KEY=9b988f434ff8-fbca-8aa4-4ae3-35442987
# - BROWSER_STACK_USERNAME=angularteam1
# - BROWSER_STACK_ACCESS_KEY=BWCd4SynLzdDcv8xtzsB
# - ARCH=linux-x64
# - DART_DEV_VERSION=latest
# - DART_STABLE_VERSION=latest
# - DART_CHANNEL=stable
# - DART_VERSION=$DART_STABLE_VERSION
# # Token for tsd to increase github rate limit
# # See https://github.com/DefinitelyTyped/tsd#tsdrc
# # This does not use http://docs.travis-ci.com/user/environment-variables/#Secure-Variables
# # because those are not visible for pull requests, and those should also be reliable.
# # This SSO token belongs to github account angular-github-ratelimit-token which has no access
# # (password is in Valentine)
# - TSDRC='{"token":"ef474500309daea53d5991b3079159a29520a40b"}'
# # GITHUB_TOKEN_ANGULAR
# - secure: "fq/U7VDMWO8O8SnAQkdbkoSe2X92PVqg4d044HmRYVmcf6YbO48+xeGJ8yOk0pCBwl3ISO4Q2ot0x546kxfiYBuHkZetlngZxZCtQiFT9kyId8ZKcYdXaIW9OVdw3Gh3tQyUwDucfkVhqcs52D6NZjyE2aWZ4/d1V4kWRO/LMgo="
# matrix:
# # Order: a slower build first, so that we don't occupy an idle travis worker waiting for others to complete.
# - MODE=dart
# - MODE=dart DART_CHANNEL=dev
# - MODE=saucelabs_required
# - MODE=browserstack_required
# - MODE=saucelabs_optional
# - MODE=browserstack_optional
# - MODE=dart_ddc
# - MODE=js
# - MODE=router
# - MODE=build_only
# - MODE=typescript_next
# - MODE=lint
#
#matrix:
# allow_failures:
# - env: "MODE=saucelabs_optional"
# - env: "MODE=browserstack_optional"
#
#addons:
# firefox: "38.0"
# apt:
# sources:
# - ubuntu-toolchain-r-test
# packages:
# - g++-4.8
#
#before_install:
# - node tools/analytics/build-analytics start ci job
# - node tools/analytics/build-analytics start ci before_install
# - echo ${TSDRC} > .tsdrc
# - export CHROME_BIN=$HOME/.chrome/chromium/chrome-linux/chrome
# - export DISPLAY=:99.0
# - export GIT_SHA=$(git rev-parse HEAD)
# - ./scripts/ci/init_android.sh
# - sh -e /etc/init.d/xvfb start
# # Use a separate SauseLabs account for upstream/master builds in order for Sauce to create a badge representing the status of just upstream/master
# - '[ "${TRAVIS_PULL_REQUEST}" = "false" ] && [ "${TRAVIS_BRANCH}" = "master" ] && SAUCE_USERNAME="angular2-ci" && SAUCE_ACCESS_KEY="693ebc16208a-0b5b-1614-8d66-a2662f4e" || true'
# - node tools/analytics/build-analytics success ci before_install
#
#install:
# - node tools/analytics/build-analytics start ci install
# # Install version of npm that we are locked against
# - npm install -g npm@3.5.3
# # Install version of Chromium that we are locked against
# - ./scripts/ci/install_chromium.sh
# # Install version of Dart based on the matrix build variables
# - ./scripts/ci/install_dart.sh ${DART_CHANNEL} ${DART_VERSION} ${ARCH}
# # Print the size of caches to ease debugging
# - du -sh ./node_modules || true
# # Install npm dependecies
# # check-node-modules will exit(1) if we don't need to install
# # we need to manually kick off the postinstall script if check-node-modules exit(0)s
# - node tools/npm/check-node-modules --purge && npm install || npm run postinstall
# - node tools/analytics/build-analytics success ci install
#
#before_script:
# - node tools/analytics/build-analytics start ci before_script
# - mkdir -p $LOGS_DIR
# - ./scripts/ci/presubmit-queue-setup.sh
# - node tools/analytics/build-analytics success ci before_script
#
#script:
# - node tools/analytics/build-analytics start ci script
# - ./scripts/ci/build_and_test.sh ${MODE}
# - node tools/analytics/build-analytics success ci script
#
#after_script:
# - node tools/analytics/build-analytics start ci after_script
# - ./scripts/ci/print-logs.sh
# - ./scripts/ci/after-script.sh
# - ./scripts/publish/publish-build-artifacts.sh
# - node tools/analytics/build-analytics success ci after_script
# - tools/analytics/build-analytics $TRAVIS_TEST_RESULT ci job
#
#notifications:
# webhooks:
# urls:
# - https://webhooks.gitter.im/e/1ef62e23078036f9cee4
# # trigger Buildtime Trend Service to parse Travis CI log
# - https://buildtimetrend.herokuapp.com/travis
# - http://104.197.9.155:8484/hubot/travis/activity
# on_success: always # options: [always|never|change] default: always
# on_failure: always # options: [always|never|change] default: always
# on_start: never # default: never
# slack:
# secure: EP4MzZ8JMyNQJ4S3cd5LEPWSMjC7ZRdzt3veelDiOeorJ6GwZfCDHncR+4BahDzQAuqyE/yNpZqaLbwRWloDi15qIUsm09vgl/1IyNky1Sqc6lEknhzIXpWSalo4/T9ZP8w870EoDvM/UO+LCV99R3wS8Nm9o99eLoWVb2HIUu0=

View File

@ -1,3 +1,353 @@
<a name="2.0.1"></a>
## [2.0.1](https://github.com/angular/angular/compare/2.0.0...2.0.1) (2016-09-23)
### Bug Fixes
* **common:** fix ngOnChanges signature of NgTemplateOutlet directive ([14ee759](https://github.com/angular/angular/commit/14ee759))
* **compiler:** `[attribute~=value]` selector ([#11696](https://github.com/angular/angular/issues/11696)) ([734b8b8](https://github.com/angular/angular/commit/734b8b8)), closes [#9644](https://github.com/angular/angular/issues/9644)
* **compiler:** safe property access expressions work in event bindings ([#11724](https://github.com/angular/angular/issues/11724)) ([a95d652](https://github.com/angular/angular/commit/a95d652))
* **compiler:** throw when Component.moduleId is not a string ([bd4045b](https://github.com/angular/angular/commit/bd4045b)), closes [#11590](https://github.com/angular/angular/issues/11590)
* **compiler:** do not provide I18N values when they're not specified ([03aedbe](https://github.com/angular/angular/commit/03aedbe)), closes [#11643](https://github.com/angular/angular/issues/11643)
* **core:** ContentChild descendants should be queried by default ([0dc15eb](https://github.com/angular/angular/commit/0dc15eb)), closes [#1645](https://github.com/angular/angular/issues/1645)
* **forms:** disable all radios with disable() ([2860418](https://github.com/angular/angular/commit/2860418))
* **forms:** make setDisabledState optional for reactive form directives ([#11731](https://github.com/angular/angular/issues/11731)) ([51d73d3](https://github.com/angular/angular/commit/51d73d3)), closes [#11719](https://github.com/angular/angular/issues/11719)
* **forms:** support unbound disabled in ngModel ([#11736](https://github.com/angular/angular/issues/11736)) ([39e251e](https://github.com/angular/angular/commit/39e251e))
* **upgrade:** allow attribute selectors for components in ng2 which are not part of upgrade ([#11808](https://github.com/angular/angular/issues/11808)) ([b81e2e7](https://github.com/angular/angular/commit/b81e2e7)), closes [#11280](https://github.com/angular/angular/issues/11280)
<a name="2.0.0"></a>
# [2.0.0](https://github.com/angular/angular/compare/2.0.0-rc.7...2.0.0) (2016-09-14)
### Bug Fixes
* **platform-browser:** provide Title service as part of the module ([#11605](https://github.com/angular/angular/issues/11605)) ([85d9db6](https://github.com/angular/angular/commit/85d9db6)), closes [#11600](https://github.com/angular/angular/issues/11600)
* **upgrade:** correct the main entry path in package.json ([a2519c6](https://github.com/angular/angular/commit/a2519c6))
<a name="2.0.0-rc.7"></a>
# [2.0.0-rc.7](https://github.com/angular/angular/compare/2.0.0-rc.6...2.0.0-rc.7) (2016-09-13)
### Bug Fixes
* **core:** allow `group()` to be used as entry point for an animation trigger ([#11419](https://github.com/angular/angular/issues/11419)) ([6a2bbff](https://github.com/angular/angular/commit/6a2bbff)), closes [#11312](https://github.com/angular/angular/issues/11312)
* **core:** ensure parent animations are triggered before children ([#11201](https://github.com/angular/angular/issues/11201)) ([c9e5b59](https://github.com/angular/angular/commit/c9e5b59))
* **core:** correctly type event handler proxy functions ([aa9b617](https://github.com/angular/angular/commit/aa9b617))
* **core:** fix error when `NgModule.bootstrap` contains `undefined` or `null` ([ea95c39](https://github.com/angular/angular/commit/ea95c39))
* **core:** fix an issue with webpack and lazy loader. ([#11387](https://github.com/angular/angular/issues/11387)) ([d26a827](https://github.com/angular/angular/commit/d26a827))
* **core:** BCP47 uses hyphens as separator ([#11514](https://github.com/angular/angular/issues/11514)) ([7b82877](https://github.com/angular/angular/commit/7b82877))
* **compiler:** fix `CssSelector#getMatchingElementTemplate()` for void tags ([077e0be](https://github.com/angular/angular/commit/077e0be)), closes [#11407](https://github.com/angular/angular/issues/11407)
* **compiler:** add missing elements to DOMSchema ([d309f77](https://github.com/angular/angular/commit/d309f77)), closes [#11219](https://github.com/angular/angular/issues/11219)
* **compiler:** fix perf regression in ShadowCss ([#11420](https://github.com/angular/angular/issues/11420)) ([78ad9ad](https://github.com/angular/angular/commit/78ad9ad)), closes [#11371](https://github.com/angular/angular/issues/11371)
* **compiler-cli:** prepend a rootDir when assuming a file exists ([#11291](https://github.com/angular/angular/issues/11291)) ([c315359](https://github.com/angular/angular/commit/c315359))
* **compiler-cli:** propagate errors to main ([#11214](https://github.com/angular/angular/issues/11214)) ([5e5ae3c](https://github.com/angular/angular/commit/5e5ae3c))
* **compiler-cli:** use the compilerHost to detect file existence ([#11418](https://github.com/angular/angular/issues/11418)) ([9e2ec7a](https://github.com/angular/angular/commit/9e2ec7a))
* **forms:** clear errors on disable ([#11463](https://github.com/angular/angular/issues/11463)) ([673de00](https://github.com/angular/angular/commit/673de00)), closes [#11287](https://github.com/angular/angular/issues/11287)
* **forms:** disabled controls should never be invalid ([#11257](https://github.com/angular/angular/issues/11257)) ([043493c](https://github.com/angular/angular/commit/043493c)), closes [#11253](https://github.com/angular/angular/issues/11253)
* **forms:** fix disabled support for empty form containers ([#11427](https://github.com/angular/angular/issues/11427)) ([7b24028](https://github.com/angular/angular/commit/7b24028)), closes [#11386](https://github.com/angular/angular/issues/11386)
* **forms:** fix resetting radios ([#11546](https://github.com/angular/angular/issues/11546)) ([61aad79](https://github.com/angular/angular/commit/61aad79)), closes [#11516](https://github.com/angular/angular/issues/11516)
* **forms:** rename validator change fn due to conflict ([#11492](https://github.com/angular/angular/issues/11492)) ([53f0c22](https://github.com/angular/angular/commit/53f0c22)), closes [#11479](https://github.com/angular/angular/issues/11479)
* **forms:** support dots in control names in contains ([#11542](https://github.com/angular/angular/issues/11542)) ([79055f7](https://github.com/angular/angular/commit/79055f7)), closes [#11535](https://github.com/angular/angular/issues/11535)
* **forms:** support rebinding nested controls ([#11210](https://github.com/angular/angular/issues/11210)) ([8c09933](https://github.com/angular/angular/commit/8c09933))
### Code Refactoring
* **core:** remove `…Metadata` for all decorators and use the decorator directly. ([63e15ff](https://github.com/angular/angular/commit/63e15ff))
### PEER-DEPENDENCY UPDATES ###
* **core**: zone.js@0.6.21
* **core**: rxjs@5.0.0-beta.12
### BREAKING CHANGES
* core: - all `…Metadata` classes have been removed. Use the corresponding decorator
as constructor or for `instanceof` checks instead.
- Example:
* Before: `new ComponentMetadata(…)`
* After: `new Component(…)`
- Note: `new Component(…)` worked before as well.
<a name="2.0.0-rc.6"></a>
# [2.0.0-rc.6](https://github.com/angular/angular/compare/2.0.0-rc.5...2.0.0-rc.6) (2016-08-31)
### Bug Fixes
* **compiler:** allow tsc-wrapped to be compile with TypeScript 2.0 ([#11086](https://github.com/angular/angular/issues/11086)) ([fc2fe00](https://github.com/angular/angular/commit/fc2fe00))
* **compiler:** correctly handles references to static methods ([#11013](https://github.com/angular/angular/issues/11013)) ([14a30f3](https://github.com/angular/angular/commit/14a30f3))
* **compiler:** do not autoinclude components declared as entry points ([#10898](https://github.com/angular/angular/issues/10898)) ([c56f3f2](https://github.com/angular/angular/commit/c56f3f2))
* **compiler:** generate temporary variables for guarded expressions ([#10657](https://github.com/angular/angular/issues/10657)) ([2d520ae](https://github.com/angular/angular/commit/2d520ae))
* **compiler:** handle invalid host bindings and events ([#11101](https://github.com/angular/angular/issues/11101)) ([f25c976](https://github.com/angular/angular/commit/f25c976))
* **compiler:** make ShadowCSS shim work on Android browser ([#11139](https://github.com/angular/angular/issues/11139)) ([38069ab](https://github.com/angular/angular/commit/38069ab)), closes [#11123](https://github.com/angular/angular/issues/11123)
* **compiler:** no longer use assetCacheKey and Function#name for token identity. ([51877ef](https://github.com/angular/angular/commit/51877ef)), closes [#10545](https://github.com/angular/angular/issues/10545) [#10538](https://github.com/angular/angular/issues/10538)
* **compiler:** only emit metadata for exported enums ([#10957](https://github.com/angular/angular/issues/10957)) ([a7b7682](https://github.com/angular/angular/commit/a7b7682))
* **compiler:** throw descriptive error message for invalid NgModule providers ([#10947](https://github.com/angular/angular/issues/10947)) ([aa5c8ca](https://github.com/angular/angular/commit/aa5c8ca)), closes [#10714](https://github.com/angular/angular/issues/10714)
* **compiler:** detect invalid elements in templates via DomSchemaRegistry ([1df69cb](https://github.com/angular/angular/commit/1df69cb))
* **compiler:** ExtractorMerger returns return errors together with nodes (as a ParseTreeResult) ([39c0f9e](https://github.com/angular/angular/commit/39c0f9e))
* **compiler:** throw better errors when components are passed to imports or modules are passed to declarations. ([#10888](https://github.com/angular/angular/issues/10888)) ([c4fd862](https://github.com/angular/angular/commit/c4fd862)), closes [#10823](https://github.com/angular/angular/issues/10823)
* **compiler:** properly shim selectors after :host and :host-context ([#10997](https://github.com/angular/angular/issues/10997)) ([af63378](https://github.com/angular/angular/commit/af63378)), closes [#5390](https://github.com/angular/angular/issues/5390)
* **compiler:** disallow event-property binding even with the NO_ERRORS_SCHEMA ([1818056](https://github.com/angular/angular/commit/1818056)), closes [#11026](https://github.com/angular/angular/issues/11026)
* **compiler-cli:** make ngc to work on Windows ([#10919](https://github.com/angular/angular/issues/10919)) ([6c77d71](https://github.com/angular/angular/commit/6c77d71)), closes [#10792](https://github.com/angular/angular/issues/10792)
* **compiler-cli:** treat empty array of metadata like absent file ([#10610](https://github.com/angular/angular/issues/10610)) ([9a11ec2](https://github.com/angular/angular/commit/9a11ec2))
* **compiler-cli:** codegen allows --strictNullChecks ([#10991](https://github.com/angular/angular/issues/10991)) ([01111b0](https://github.com/angular/angular/commit/01111b0))
* **compiler-cli:** comment out a private keyword in codegen. ([#10949](https://github.com/angular/angular/issues/10949)) ([8560e1e](https://github.com/angular/angular/commit/8560e1e))
* **compiler-cli:** don't codegen foo.d.ngfactory.ts from foo.d.ts ([#10833](https://github.com/angular/angular/issues/10833)) ([cd8cbd3](https://github.com/angular/angular/commit/cd8cbd3))
* **compiler-cli:** don't quote properties in literal maps ([#11110](https://github.com/angular/angular/issues/11110)) ([abad667](https://github.com/angular/angular/commit/abad667)), closes [#11050](https://github.com/angular/angular/issues/11050)
* **common:** allow float for DatePipe input ([#10687](https://github.com/angular/angular/issues/10687)) ([712c7d5](https://github.com/angular/angular/commit/712c7d5))
* **common:** remove bidi control chars in DatePipe output ([#10870](https://github.com/angular/angular/issues/10870)) ([9198038](https://github.com/angular/angular/commit/9198038)), closes [#10080](https://github.com/angular/angular/issues/10080)
* **core:** report errors for missing host-level referenced animations ([#10650](https://github.com/angular/angular/issues/10650)) ([f12d519](https://github.com/angular/angular/commit/f12d519))
* **core:** assign an overriden name to constructor named constructor ([#11043](https://github.com/angular/angular/issues/11043)) ([bd510cc](https://github.com/angular/angular/commit/bd510cc)), closes [#10545](https://github.com/angular/angular/issues/10545)
* **core:** don't strip sourceMappingURL in shimmed stylesheets ([#9664](https://github.com/angular/angular/issues/9664)) ([bc6d1c8](https://github.com/angular/angular/commit/bc6d1c8))
* **core:** FactoryProvider's deps property should be optional ([eb7d8c7](https://github.com/angular/angular/commit/eb7d8c7))
* **core/testing:** have fakeAsync use Proxy zone. ([#10797](https://github.com/angular/angular/issues/10797)) ([8a5eb08](https://github.com/angular/angular/commit/8a5eb08)), closes [#10503](https://github.com/angular/angular/issues/10503)
* **forms:** fix conflicting getter name ([#11081](https://github.com/angular/angular/issues/11081)) ([ce08982](https://github.com/angular/angular/commit/ce08982))
* **forms:** fully support rebinding form group directive ([#11051](https://github.com/angular/angular/issues/11051)) ([515ff61](https://github.com/angular/angular/commit/515ff61))
* **forms:** remove deprecated form provider functions ([#10741](https://github.com/angular/angular/issues/10741)) ([79afcf0](https://github.com/angular/angular/commit/79afcf0))
* **forms:** remove deprecated forms APIs ([#10624](https://github.com/angular/angular/issues/10624)) ([7606c96](https://github.com/angular/angular/commit/7606c96))
* **forms:** support radio buttons with same name but diff parent ([#11152](https://github.com/angular/angular/issues/11152)) ([e8a1566](https://github.com/angular/angular/commit/e8a1566)), closes [#10065](https://github.com/angular/angular/issues/10065)
* **forms:** update validity when validator dir changes ([d2ad871](https://github.com/angular/angular/commit/d2ad871)), closes [#11116](https://github.com/angular/angular/issues/11116)
* **http:** deep copy for constructor using existing Headers ([#10679](https://github.com/angular/angular/issues/10679)) ([654ff61](https://github.com/angular/angular/commit/654ff61)), closes [#6845](https://github.com/angular/angular/issues/6845)
* **http:** encode correct value for %3D ([#9790](https://github.com/angular/angular/issues/9790)) ([7555320](https://github.com/angular/angular/commit/7555320))
* **http:** expose jsonpFactory for AoT compilation ([#10730](https://github.com/angular/angular/issues/10730)) ([203b2ba](https://github.com/angular/angular/commit/203b2ba))
* **http:** inline HTTP_PROVIDERS and JSONP_PROVIDERS until the metadata collector can do it automatically. ([#10928](https://github.com/angular/angular/issues/10928)) ([477e425](https://github.com/angular/angular/commit/477e425))
* **http:** restructure exports so that we don't leak private factory functions ([#11016](https://github.com/angular/angular/issues/11016)) ([7dfcaac](https://github.com/angular/angular/commit/7dfcaac))
* **http:** return empty string if no body is present ([#10668](https://github.com/angular/angular/issues/10668)) ([7cd4741](https://github.com/angular/angular/commit/7cd4741))
* **i18n:** change default locale from `en_US` to `en-US` ([#11103](https://github.com/angular/angular/issues/11103)) ([b9647b7](https://github.com/angular/angular/commit/b9647b7))
* **i18n:** Currency/Date/Number pipe use injected locale ([#11093](https://github.com/angular/angular/issues/11093)) ([0a053a4](https://github.com/angular/angular/commit/0a053a4))
* **i18n:** ICU placeholders are replaced by their translations ([#10586](https://github.com/angular/angular/issues/10586)) ([43512aa](https://github.com/angular/angular/commit/43512aa))
* **i18n:** update NgLocalLocalization ([#10771](https://github.com/angular/angular/issues/10771)) ([4df48b2](https://github.com/angular/angular/commit/4df48b2))
* **platform-browser:** remove export for private symbol _WORKER_UI_PLATFORM_PROVIDERS. ([#11018](https://github.com/angular/angular/issues/11018)) ([05bbb8e](https://github.com/angular/angular/commit/05bbb8e))
* **router:** use encodeUri/decodeUri to encode fragment ([bb9dfbc](https://github.com/angular/angular/commit/bb9dfbc))
* **router:** add an option to disable initial navigation ([a2deafc](https://github.com/angular/angular/commit/a2deafc))
* **router:** canLoad should cancel a navigation instead of failing it ([#11001](https://github.com/angular/angular/issues/11001)) ([f1ce760](https://github.com/angular/angular/commit/f1ce760))
* **router:** do not use rx/add/operator ([c350ba2](https://github.com/angular/angular/commit/c350ba2))
* **router:** fix the order of guards, so canActivateChild runs before canActivate ([0bb516f](https://github.com/angular/angular/commit/0bb516f))
* **router:** lazy loading keeps refetching modules ([#10707](https://github.com/angular/angular/issues/10707)) ([cc6749c](https://github.com/angular/angular/commit/cc6749c))
* **router:** location changes and redirects break the back button ([#10742](https://github.com/angular/angular/issues/10742)) ([04c6b2f](https://github.com/angular/angular/commit/04c6b2f))
* **router:** make routerLinkActiveOptions public ([#10758](https://github.com/angular/angular/issues/10758)) ([73c0a9d](https://github.com/angular/angular/commit/73c0a9d))
* **router:** support guards navigating synchronously ([#11150](https://github.com/angular/angular/issues/11150)) ([e2241a2](https://github.com/angular/angular/commit/e2241a2))
* **router:** support relative param-only navigation ([#10613](https://github.com/angular/angular/issues/10613)) ([c7f3aa7](https://github.com/angular/angular/commit/c7f3aa7))
* **router:** update the location before activating components ([2ffecc0](https://github.com/angular/angular/commit/2ffecc0))
* **router:** fix type ([#11181](https://github.com/angular/angular/issues/11181)) ([0f68351](https://github.com/angular/angular/commit/0f68351))
* **router:** merge artifacts ([fc1e45d](https://github.com/angular/angular/commit/fc1e45d)), closes [#11063](https://github.com/angular/angular/issues/11063) [#11102](https://github.com/angular/angular/issues/11102)
* **compiler/testing:** override metadata subclasses properly ([#10767](https://github.com/angular/angular/issues/10767)) ([87fe477](https://github.com/angular/angular/commit/87fe477))
* **bundles:** correct RxJS mapping in rollup config for umd/es5 bundles ([174c016](https://github.com/angular/angular/commit/174c016))
* **closure:** prevent closure renaming of testability interface ([#11146](https://github.com/angular/angular/issues/11146)) ([875e664](https://github.com/angular/angular/commit/875e664))
* **closure:** replace property accesses ([#11078](https://github.com/angular/angular/issues/11078)) ([dc6f72e](https://github.com/angular/angular/commit/dc6f72e))
### Code Refactoring
* **common:** remove deprecated ReplacePipe ([#10772](https://github.com/angular/angular/issues/10772)) ([33ced70](https://github.com/angular/angular/commit/33ced70))
* **core:** remove all previously deprecated ApplicationRef apis ([f84c3fd](https://github.com/angular/angular/commit/f84c3fd))
* **core:** remove deprecated NgZoneError ([#10822](https://github.com/angular/angular/issues/10822)) ([3f5331b](https://github.com/angular/angular/commit/3f5331b))
* **core:** remove deprecated @Component.directives and @Component.pipes ([4a740f2](https://github.com/angular/angular/commit/4a740f2))
* **core:** remove deprecated coreBootstrap and coreLoadAndBootstrap ([3329977](https://github.com/angular/angular/commit/3329977))
* **core:** remove deprecated DynamicComponentLoader ([#10759](https://github.com/angular/angular/issues/10759)) ([4a9745e](https://github.com/angular/angular/commit/4a9745e))
* **core:** remove deprecated SystemJsComponentResolver and SystemJsCmpFactoryResolver ([b238414](https://github.com/angular/angular/commit/b238414))
* **core:** remove deprecated DebugNode.inject() ([#10751](https://github.com/angular/angular/issues/10751)) ([a235ae1](https://github.com/angular/angular/commit/a235ae1))
* **core:** remove deprecated properties and events from metadata ([#10753](https://github.com/angular/angular/issues/10753)) ([156a52e](https://github.com/angular/angular/commit/156a52e))
* **core:** remove deprecated Query and ViewQuery ([#10820](https://github.com/angular/angular/issues/10820)) ([48751cc](https://github.com/angular/angular/commit/48751cc))
* **core:** remove deprecated lockRunMode ([#10763](https://github.com/angular/angular/issues/10763)) ([2eb4ee8](https://github.com/angular/angular/commit/2eb4ee8))
* **core:** remove deprecated ComponentResolver (#10858) ([73a9ee4](https://github.com/angular/angular/commit/73a9ee4))
* **core:** remove deprecated PlatformRef#registerDisposeListener, #disposed, #dispose() ([44e1b23](https://github.com/angular/angular/commit/44e1b23))
* **core:** remove deprecated provider/bind API ([#10652](https://github.com/angular/angular/issues/10652)) ([bec5c5f](https://github.com/angular/angular/commit/bec5c5f)), closes [#9751](https://github.com/angular/angular/issues/9751)
* **core:** remove supporter deprecated `var` / `#` ([#11084](https://github.com/angular/angular/issues/11084)) ([b867764](https://github.com/angular/angular/commit/b867764))
* **core:** removed deprecated disposePlatform ([d282507](https://github.com/angular/angular/commit/d282507))
* **core:** merge Type and ConcreteType<?> into Type<?> ([#10616](https://github.com/angular/angular/issues/10616)) ([b96869a](https://github.com/angular/angular/commit/b96869a)), closes [#9729](https://github.com/angular/angular/issues/9729)
* **core:** remove deprecated animations trigger APIs ([#10825](https://github.com/angular/angular/issues/10825)) ([9adf803](https://github.com/angular/angular/commit/9adf803))
* **core:** rename Exception to Error; remove from public API ([86ba072](https://github.com/angular/angular/commit/86ba072)), ([7c07bff](https://github.com/angular/angular/commit/7c07bff))
* **core/testing:** remove deprecated TestComponentBuilder ([a29f9f3](https://github.com/angular/angular/commit/a29f9f3))
* **http:** remove deprecated HTTP_PROVIDERS and JSONP_PROVIDERS ([#10864](https://github.com/angular/angular/issues/10864)) ([675e582](https://github.com/angular/angular/commit/675e582))
* **platform-browser-dynamic:** Rename CACHED_TEMPLATE_PROVIDER to RESOURCE_CACHE_PROVIDER ([#10866](https://github.com/angular/angular/issues/10866)) ([40e160c](https://github.com/angular/angular/commit/40e160c)), closes [#9741](https://github.com/angular/angular/issues/9741)
* **upgrade:** remove deprecated addProvider ([12b0a3d](https://github.com/angular/angular/commit/12b0a3d))
* **webworkers:** move webworkers to separate @angular/platform-webworker and @angular/platform-webworker-dynamic packages ([71ae2c4](https://github.com/angular/angular/commit/71ae2c4))
* **core & platform-browser:** rename SanitizationService to Sanitizer and DomSanitizationService to DomSanitizer ([#11085](https://github.com/angular/angular/issues/11085)) ([811962b](https://github.com/angular/angular/commit/811962b))
### Features
* **npm packages:** use ES modules for primary build ([#11120](https://github.com/angular/angular/issues/11120)) ([9796579](https://github.com/angular/angular/commit/9796579))
* **compiler:** Add an error message when the locale is not provided ([#11104](https://github.com/angular/angular/issues/11104)) ([e220a80](https://github.com/angular/angular/commit/e220a80))
* **compiler:** Added "strictMetadataEmit" option to ngc ([#10951](https://github.com/angular/angular/issues/10951)) ([39a2c39](https://github.com/angular/angular/commit/39a2c39))
* **compiler-cli:** allow ngc implementations to provide XHR ([#10708](https://github.com/angular/angular/issues/10708)) ([6e842fc](https://github.com/angular/angular/commit/6e842fc))
* **compiler-cli:** support pathmapping using a separate reflector ([#10985](https://github.com/angular/angular/issues/10985)) ([e0fbca9](https://github.com/angular/angular/commit/e0fbca9))
* **core:** support animation trigger template callbacks ([45e8e73](https://github.com/angular/angular/commit/45e8e73670b96387fc109921fad299742d3f7cbf))
* **core:** make sure animation callback reports the totalTime ([#11022](https://github.com/angular/angular/issues/11022)) ([4f8f8cf](https://github.com/angular/angular/commit/4f8f8cf))
* **core:** add NO_ERRORS_SCHEMA that allows any properties to be set on any element ([#10956](https://github.com/angular/angular/issues/10956)) ([c631cfc](https://github.com/angular/angular/commit/c631cfc))
* **core:** make ngprobe tokens pluggable ([f48142e](https://github.com/angular/angular/commit/f48142e))
* **core:** throw a descriptive error when BrowserModule is installed a second time (via lazy loading). ([#10899](https://github.com/angular/angular/issues/10899)) ([628d06c](https://github.com/angular/angular/commit/628d06c))
* **core:** update public api ([951ecb4](https://github.com/angular/angular/commit/951ecb4))
* **core:** allow configurable module prefixes and suffixes. ([#11049](https://github.com/angular/angular/issues/11049)) ([8b78281](https://github.com/angular/angular/commit/8b78281))
* **core/testing:** add TestBed.get ([4648b3e](https://github.com/angular/angular/commit/4648b3e))
* **forms:** add control status classes to form groups ([#10667](https://github.com/angular/angular/issues/10667)) ([2291929](https://github.com/angular/angular/commit/2291929))
* **forms:** add NgForm method that resets submit state ([#10715](https://github.com/angular/angular/issues/10715)) ([97f3571](https://github.com/angular/angular/commit/97f3571))
* **forms:** add support for disabled controls ([#10994](https://github.com/angular/angular/issues/10994)) ([2b313e4](https://github.com/angular/angular/commit/2b313e4))
* **forms:** add support to bind validation attributes ([0b665c0](https://github.com/angular/angular/commit/0b665c0))
* **i18n:** add an HtmlParser decorator ([#10645](https://github.com/angular/angular/issues/10645)) ([50345b8](https://github.com/angular/angular/commit/50345b8))
* **i18n:** Add NgLocaleLocalization which returns plural cases given a locale ([#10744](https://github.com/angular/angular/issues/10744)) ([161a4dd](https://github.com/angular/angular/commit/161a4dd))
* **i18n:** pass translation config directly into ngc ([#10622](https://github.com/angular/angular/issues/10622)) ([6580d67](https://github.com/angular/angular/commit/6580d67))
* **i18n:** provide LOCALE_ID and NgLocalization ([ce4eae6](https://github.com/angular/angular/commit/ce4eae6))
* **i18n:** xliff ([72bb38f](https://github.com/angular/angular/commit/72bb38f))
* **i18n:** xliff integration ([f6a7d65](https://github.com/angular/angular/commit/f6a7d65))
* **router:** add support for custom error handlers ([2fc5c57](https://github.com/angular/angular/commit/2fc5c57))
* **router:** add syntax sugar for confuguring RouterTestingModule ([#10906](https://github.com/angular/angular/issues/10906)) ([53c99cf](https://github.com/angular/angular/commit/53c99cf))
* **router:** extend support for lazy loading children ([#10705](https://github.com/angular/angular/issues/10705)) ([6b26102](https://github.com/angular/angular/commit/6b26102))
* **router:** make router.config public ([947f9c3](https://github.com/angular/angular/commit/947f9c3))
* **router:** throw a helpful error when misusing forRoot() from a lazy module. ([#10996](https://github.com/angular/angular/issues/10996)) ([5ddecb1](https://github.com/angular/angular/commit/5ddecb1))
### PEER-DEPENDENCY UPDATES ###
* **core**: zone.js@0.6.17
* **core**: rxjs@5.0.0-beta.11
* **core**: reflect-metadata dependency is now optional when in AOT mode
* **compiler-cli**: typescript@2.0.2
### BREAKING CHANGES
* npm packages: code in ESM (ES6 Modules) format is now published at the default location in the npm package with `package.json`'s `main` entry pointing to an UMD bundle (primarily for node, and webpack 1 users).
If you are using SystemJS to load Angular, you should adjust your SystemJS configuration to point to the UMD bundles (present in the npm package).
Please see this [example SystemJS config](https://github.com/angular/quickstart/blob/3b7452cc444c49c139ea39523ced0468c2362c16/systemjs.config.js#L17-L34).
* testing config: due to zone.js peer-dependency upgrade, the order in which various zone specs are loaded has changed.
Please see this [example Karma config](https://github.com/angular/quickstart/blob/3b7452cc444c49c139ea39523ced0468c2362c16/karma.conf.js#L31-L38).
* core: `Type` is now `Type<T>` which means that in most cases you have to
use `Type<any>` in place of `Type`.
We don't expect that any user applications use the `Type` type directly.
* core: Previously inconsistently named APIs SanitizationService and DomSanitizationService were renamed to Sanitizer and DomSanitizer
* core: previously deprecated @Component.directives and @Component.pipes support was removed.
All the components and pipes now must be declared via an NgModule. NgModule is the basic compilation block passed into the Angular compiler via Compiler#compileModuleSync or #compileModuleAsync.
Because of this change, the Compiler#compileComponentAsync and #compileComponentSync were removed as well - any code doing compilation should compile module instead using the APIs mentioned above.
Lastly, since modules are the basic compilation unit, the ngUpgrade module was modified to always require an NgModule to be passed into the UpgradeAdapter's constructor - previously this was optional.
* core: deprecated ComponentResolver was removed. Please use ComponentFactoryResolver instead.
* core: animations defined using an at-symbol prefix that are not property bound are now invalid.
```html
<!-- this is now invalid -->
<div @flip="flipState"></div>
<!-- change that to -->
<div [@flip]="flipState"></div>
```
* core: Animations that are not bound using the at-symbol
prefix using `animate-` must now be preixed using `bind-animate-`.
```html
<!-- this is now invalid -->
<div animate-flip="flipState"></div>
<!-- is valid now -->
<div bind-animate-flip="flipState"></div>
```
* core: These forms of providers are no longer accepted:
```
bind(MyClass).toFactory(...)
new Provider(MyClass, toFactory: ...)
```
We now only accept:
```
{provide: MyClass, useFactory: ...}
```
* core: previously deprecated NgZoneError has been removed
* core: Exceptions are no longer part of the public API. We don't expect that anyone should be referring to the Exception types.
```
ExceptionHandler.call(exception: any, stackTrace?: any, reason?: string): void;
```
change to:
```
ErrorHandler.handleError(error: any): void;
```
* core: deprecated DynamicComponentLoader was removed; see deprecation notice for migration instructions.
* core: deprecated SystemJsComponentResolver and SystemJsCmpFactoryResolver have been removed.
* core: previously deprecated coreBootstrap and coreLoadAndBootstrap have been removed.
* core: all previously deprecated ApplicationRef apis have been removed.
* core: deprecated PlatformRef#registerDisposeListener, #disposed, #dispose() - follow deprecation instructions to upgrade
* core: deprecated disposePlatform was removed; see deprecation notice for migration instructions.
* core: deprecated DirectiveMetadataType#properties and DirectiveMetadataType#events were removed; see deprecation notice for migration instructions.
* core: deprecated lockRunMode was removed; see deprecation notice for migration instructions.
* core: deprecated DebugNode#inject was removed, see deprecation notice for migration instructions.
* core: deprecated Query and ViewQuery were removed; see deprecation notice for migration instructions.
* core/testing: deprecated TestComponentBuilder was removed, please use TestBed instead
* compiler: Previously deprecated`#` and `var` are not supported any more in expressions within templates, use `let`:
- `var-<name>` cannot be used any more on templates, use `let-<name>`
- `var-<name>` cannot be used any more to create a reference, use `ref-<name>`
* http: any code which relies on the fact that a newly created Headers object is referencing an existing Headers map is now broken, but that should normally not be the case since this behavior is not documented and not in accordance with the spec.
* http: previously deprecated HTTP_PROVIDERS and JSONP_PROVIDERS were removed; see deprecation notice for migration instructions.
* platform-browser-dynamic: `CACHED_TEMPLATE_PROVIDER` is now renamed to `RESOURCE_CACHE_PROVIDER`
Before:
```js
import {CACHED_TEMPLATE_PROVIDER} from '@angular/platform-browser-dynamic';
```
After:
```js
import {RESOURCE_CACHE_PROVIDER} from '@angular/platform-browser-dynamic';
```
* common: previously deprecated NgSwitchWhen directive was removed, use NgSwitchCase instead
* common: previously deprecated ReplacePipe was removed
* upgrade: deprecated UpgradeAdapter#addProvider was removed, see deprecation notice for migration instructions.
* forms: deprecated `provideForms()` and `disableDeprecatedForms()` functions have been removed. Please import the `FormsModule` or the `ReactiveFormsModule` from @angular/forms instead.
* forms: deprecated forms APIs in @angular/common have been removed. Please update to the new forms API in @angular/forms. See angular.io for more information.
* webworkers: web worker platform is now exported via separate packages.
Please use @angular/platform-webworker and @angular/platform-webworker-dynamic
<a name="2.0.0-rc.5"></a>
# [2.0.0-rc.5](https://github.com/angular/angular/compare/2.0.0-rc.4...2.0.0-rc.5) (2016-08-09)
@ -70,49 +420,6 @@
* **platform-browser:** remove testing_e2e target ([#10029](https://github.com/angular/angular/issues/10029)) ([4a96505](https://github.com/angular/angular/commit/4a96505))
* **platform-browser:** throw useful error on missing platform module. ([73f02c7](https://github.com/angular/angular/commit/73f02c7))
* **platform-browser-dynamic:** Add [@Injectable](https://github.com/Injectable)() annotation to XHRImpl. ([7b31178](https://github.com/angular/angular/commit/7b31178))
* **router:** absolute redirects should work with lazy loading ([3a307c2](https://github.com/angular/angular/commit/3a307c2))
* **router:** add segmentPath to the link DSL ([4f17dbc](https://github.com/angular/angular/commit/4f17dbc))
* **router:** advance query params and fragment after advanced routes ([06e4ca4](https://github.com/angular/angular/commit/06e4ca4))
* **router:** back button does not work in IE11 and Safari ([f08060b](https://github.com/angular/angular/commit/f08060b))
* **router:** configure DI correctly when using the old `provideRouter` function ([93ade74](https://github.com/angular/angular/commit/93ade74))
* **router:** disallow root segments with matrix params ([34b3c53](https://github.com/angular/angular/commit/34b3c53))
* **router:** do not fire events on 'duplicate' location events ([0b54e3c](https://github.com/angular/angular/commit/0b54e3c))
* **router:** encode/decode params and path segments ([46e105f](https://github.com/angular/angular/commit/46e105f))
* **router:** export navigation extras ([51e661e](https://github.com/angular/angular/commit/51e661e))
* **router:** expose initalNavigation and dispose so they can be used with webworkers ([b77a4a4](https://github.com/angular/angular/commit/b77a4a4))
* **router:** fix matrix params check to handle 'special' objects ([d2d36c6](https://github.com/angular/angular/commit/d2d36c6))
* **router:** fix offline compilation by exporting provideLocationStrategy ([8dc82a0](https://github.com/angular/angular/commit/8dc82a0))
* **router:** fix rollup config to properly set up rxjs ([1803ed2](https://github.com/angular/angular/commit/1803ed2))
* **router:** fix RouterLinKActive to work with RouterLink ([f7a0e9e](https://github.com/angular/angular/commit/f7a0e9e))
* **router:** fix type definition ([c586656](https://github.com/angular/angular/commit/c586656))
* **router:** freeze params and queryParams to prevent common source of bugs ([0668ba5](https://github.com/angular/angular/commit/0668ba5))
* **router:** handle lastPathIndex of empty-path routes ([7a4f662](https://github.com/angular/angular/commit/7a4f662))
* **router:** handle router outlets in ngIf ([0c65d5c](https://github.com/angular/angular/commit/0c65d5c))
* **router:** handle url fragments when no url segments present ([43437c1](https://github.com/angular/angular/commit/43437c1))
* **router:** handle urls with only secondary top-level segments ([44709e0](https://github.com/angular/angular/commit/44709e0))
* **router:** handle when both primary and secondary are empty-path and primary has a child ([2b63330](https://github.com/angular/angular/commit/2b63330))
* **router:** lazily-loaded modules should use loaded injectors instead of the root one ([85be729](https://github.com/angular/angular/commit/85be729))
* **router:** lazy loaded components should use loaded injector ([921a179](https://github.com/angular/angular/commit/921a179))
* **router:** make an outlet to unregister itself when it is removed from the dom ([3e377f5](https://github.com/angular/angular/commit/3e377f5))
* **router:** make router provides work with cli and offline compilation ([d15a1d6](https://github.com/angular/angular/commit/d15a1d6))
* **router:** merge SystemJsAppModuleFactoryLoader and SystemJsAllModuleLoader ([0426325](https://github.com/angular/angular/commit/0426325))
* **router:** navigation should not preserve query params and fragment by default ([23ee29b](https://github.com/angular/angular/commit/23ee29b))
* **router:** provideRouter should use provideRoutes ([#10488](https://github.com/angular/angular/issues/10488)) ([2eda7a5](https://github.com/angular/angular/commit/2eda7a5))
* **router:** relax type defintion of Route to improve dev ergonomics ([bb8b82b](https://github.com/angular/angular/commit/bb8b82b))
* **router:** remove a circular dep ([6bfd514](https://github.com/angular/angular/commit/6bfd514))
* **router:** remove private and internal annotations ([#9745](https://github.com/angular/angular/issues/9745)) ([dabf214](https://github.com/angular/angular/commit/dabf214))
* **router:** remove private and internal annotations ([#9753](https://github.com/angular/angular/issues/9753)) ([137fff9](https://github.com/angular/angular/commit/137fff9))
* **router:** remove the precompile warning ([fb2539e](https://github.com/angular/angular/commit/fb2539e))
* **router:** route.parent should work for secondary children ([5a99393](https://github.com/angular/angular/commit/5a99393))
* **router:** router link active should take all descendants into account ([8d90a5a](https://github.com/angular/angular/commit/8d90a5a))
* **router:** routerLinkActive should only set classes after the router has successfully navigated ([db54a84](https://github.com/angular/angular/commit/db54a84))
* **router:** support outlets in non-absolute positions ([afcb3c0](https://github.com/angular/angular/commit/afcb3c0))
* **router:** throw when cannot parse a url ([27b87ef](https://github.com/angular/angular/commit/27b87ef))
* **router:** update current state and url before activating components ([5cf5897](https://github.com/angular/angular/commit/5cf5897))
* **router:** update dts files ([81d27da](https://github.com/angular/angular/commit/81d27da))
* **router:** update dts files ([a415613](https://github.com/angular/angular/commit/a415613))
* **router:** update links when query params change ([f65ebec](https://github.com/angular/angular/commit/f65ebec))
* **router:** updates router module to be offline-compilation friendly ([72da547](https://github.com/angular/angular/commit/72da547))
* **static_reflector:** report methods with decorators in `propMetadata` as well ([367f0fd](https://github.com/angular/angular/commit/367f0fd)), closes [#10308](https://github.com/angular/angular/issues/10308) [#10318](https://github.com/angular/angular/issues/10318)
* **static_reflector:** resolve values of functions in the function context ([d6b65db](https://github.com/angular/angular/commit/d6b65db))
* **SyncAsyncResult:** fix default async value ([#10013](https://github.com/angular/angular/issues/10013)) ([6d02d2f](https://github.com/angular/angular/commit/6d02d2f)), closes [#10013](https://github.com/angular/angular/issues/10013)
@ -186,26 +493,6 @@
* **NgStyle:** add support for the style.unit notation ([#10496](https://github.com/angular/angular/issues/10496)) ([8b18ef4](https://github.com/angular/angular/commit/8b18ef4)), closes [#10326](https://github.com/angular/angular/issues/10326)
* **ngUpgrade:** add support for NgModules ([6b564ec](https://github.com/angular/angular/commit/6b564ec))
* **NumberPipe:** add string support ([#10163](https://github.com/angular/angular/issues/10163)) ([f3dd91e](https://github.com/angular/angular/commit/f3dd91e)), closes [#10159](https://github.com/angular/angular/issues/10159)
* **router:** activateroute should expose its route config ([2fdb39e](https://github.com/angular/angular/commit/2fdb39e))
* **router:** add a validation to make sure pathMatch is set correctly ([3c3e9dd](https://github.com/angular/angular/commit/3c3e9dd))
* **router:** add activate and deactivate events to RouterOutlet ([245b091](https://github.com/angular/angular/commit/245b091))
* **router:** add isActive to router ([5162fb6](https://github.com/angular/angular/commit/5162fb6))
* **router:** add parent, children, firstChild to ActivatedRoute ([550ab31](https://github.com/angular/angular/commit/550ab31))
* **router:** add queryParams and fragment to every activated route ([422d380](https://github.com/angular/angular/commit/422d380))
* **router:** add RouterAppModule ([8aa2a0c](https://github.com/angular/angular/commit/8aa2a0c))
* **router:** add RouterTestModule ([72544ba](https://github.com/angular/angular/commit/72544ba))
* **router:** add support for canActivateChild ([9e3d13f](https://github.com/angular/angular/commit/9e3d13f))
* **router:** add support for lazily loaded modules ([8ebb8e4](https://github.com/angular/angular/commit/8ebb8e4))
* **router:** add the ANALYZE_FOR_PRECOMPILE provider to make dev ergonomics better ([96a9e66](https://github.com/angular/angular/commit/96a9e66))
* **router:** Allow navigation without updating the URL ([#9608](https://github.com/angular/angular/issues/9608)) ([63b82cd](https://github.com/angular/angular/commit/63b82cd))
* **router:** empty-path routes should inherit matrix params ([a77db44](https://github.com/angular/angular/commit/a77db44))
* **router:** guards and data resolvers can now return promises ([a5dc570](https://github.com/angular/angular/commit/a5dc570))
* **router:** implement canLoad ([62e7c0f](https://github.com/angular/angular/commit/62e7c0f))
* **router:** rename UrlPathWithParams into UrlSegment ([6f68330](https://github.com/angular/angular/commit/6f68330))
* **router:** support sibling modules providing routes ([29caa37](https://github.com/angular/angular/commit/29caa37))
* **router:** update routerLink DSL to handle aux routes ([ded518d](https://github.com/angular/angular/commit/ded518d))
* **router:** update the example app to use lazily-loaded modules ([6fbe56d](https://github.com/angular/angular/commit/6fbe56d))
* **Router:** add extra validation for when route was passed as Array ([#9942](https://github.com/angular/angular/issues/9942)) ([aa88438](https://github.com/angular/angular/commit/aa88438))
* **security:** categorize <track src> as a regular URL. ([a441b5b](https://github.com/angular/angular/commit/a441b5b)), closes [#10089](https://github.com/angular/angular/issues/10089)
* **security:** only warn when actually sanitizing HTML. ([#10272](https://github.com/angular/angular/issues/10272)) ([482c019](https://github.com/angular/angular/commit/482c019)), closes [#10206](https://github.com/angular/angular/issues/10206)
* **security:** trust resource URLs as URLs. ([#10220](https://github.com/angular/angular/issues/10220)) ([51f3d22](https://github.com/angular/angular/commit/51f3d22))
@ -215,7 +502,7 @@
### BREAKING CHANGES
* core:
* core:
## Bootstrap changes
```
@ -225,7 +512,7 @@
declarations: […], // directives, components, and pipes owned by this NgModule
imports: [BrowserModule],
providers: […], // additional providers
boostrap: [MainComponent],
bootstrap: [MainComponent],
})
class MyAppModule {}
@ -241,15 +528,15 @@
```
* browser:
- short form bootstrap does no longer allow
to inject compiler internals (i.e. everything
to inject compiler internals (i.e. everything
from `@angular/compiler`). Inject `Compiler` instead.
* core:
- `ApplicationRef.waitForAsyncInitializers` is deprecated. Use
* core:
- `ApplicationRef.waitForAsyncInitializers` is deprecated. Use
`AppInitStatus.donePromise` / `AppInitStatus.done` instead.
* core:
* core:
- `ApplicationRef.registerBootstrapListener` is deprecated. Provide a multi
provider for the new token `APP_BOOTSTRAP_LISTENER` instead.
* core:
* core:
- `ApplicationRef.dispose` is deprecated. Destroy the module that was
created during bootstrap instead by calling `NgModuleRef.destroy`.
- `AplicationRef.registerDisposeListener` is deprecated.
@ -262,17 +549,17 @@
`PlatformRef.onDestroy` instead.
- `PlaformRef.diposed` is deprecated. Use `PlatformRef.destroyed`
instead.
* testing:
* testing:
* `withProviders`, use `TestBed.withModule` instead
* `addProviders`, use `TestBed.configureTestingModule` instead
* `TestComponentBuilder`, use `TestBed.configureTestModule` / `TestBed.override...` / `TestBed.createComponent` instead.
* core:
* core:
- ES5 users can no longer use the `View(…)` function to provide `ViewMetadata`.
This mirrors the removal of the `@View` decorator a while ago.
* core:
- `bootstrapModule` and `bootstrapModuleFactory` have been moved to be members of `PlaformRef`.
E.g. `platformBrowserDynamic().bootstrapModule(MyModule)`.
* core:
* core:
- By default, Angular will error during parsing
on unknown properties,
even if they are on elements with a `-` in their name
@ -286,19 +573,16 @@
declarations: [MyComponentThatUsesAWebComponent],
imports: [BrowserModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
boostrap: [MyComponentThatUsesAWebComponent],
bootstrap: [MyComponentThatUsesAWebComponent],
})
export class MyAppModule{}
```
* core:
* core:
- `coreLoadAndBootstrap` and `coreBootstrap` can't be used any more (without migration support).
Use `bootstrapModule` / `bootstrapModuleFactory` instead.
- All Components listed in routes have to be part of the `declarations` of an NgModule.
Either directly on the bootstrap module / lazy loaded module, or in an NgModule imported by them.
* router:
`UrlPathWithParams` => `UrlSegment`
`UrlSegment` => `UrlSegmentGroup`
* core:
* core:
- `ApplicationRef.run` is deprecated. Use `NgZone.run` directly
- `ApplicationRef.injector` is deprecated. Inject an `Injector` or
use `NgModuleRef.injector` instead
@ -350,9 +634,9 @@
- use `NgModuleFactoryLoader` for lazy loading.
- Instead of `SystemJsComponentResolver`, create an `@NgModule` and use `SystemJsNgModuleLoader`.
- Instead of `SystemJsCmpFactoryResolver`, create an `@NgModule` and use `SystemJsNgModuleFactoryLoader`
* core:
* core:
- `lockRunMode` is deprecated and no more needed.
* animations:
* animations:
- animation trigger expressions within the template that are assigned as
an element attribute (e.g. `@prop`) are deprecated. Please use the
Angular2 property binding syntax (e.g. `[@prop]`) when assigning
@ -366,8 +650,8 @@
<div [@trigger]="expression"></div>
```
* forms:
* forms:
We have removed the deprecated form directives from the built-in platform directive list, so apps are not required to package forms with their app. This also makes forms friendly to offline compilation.
Instead, we have exposed three modules:
@ -399,11 +683,11 @@
@NgModule({
declarations: [MyComponent],
imports: [BrowserModule, DeprecatedFormsModule],
boostrap: [MyComponent],
bootstrap: [MyComponent],
})
export class MyAppModule{}
```
* testing:
* testing:
- Application providers can no longer inject compiler internals (i.e. everything
from `@angular/compiler`). Inject `Compiler` instead. This reflects the
changes to `bootstrap` for module support (3f55aa609f60f130f1d69188ed057214b1267cb3).
@ -412,26 +696,26 @@
- Platform directives / pipes need to be provided via
`configureModule` and can no longer be provided via the
`PLATFORM_PIPES` / `PLATFORM_DIRECTIVES` tokens.
- `setBaseTestProviders()` was renamed into `initTestEnvironment` and
- `setBaseTestProviders()` was renamed into `initTestEnvironment` and
now takes a `PlatformRef` and a factory for a
`Compiler`.
- E.g. for the browser platform:
BEFORE:
```
import {setBaseTestProviders} from @angular/core/testing;
import {TEST_BROWSER_DYNAMIC_PLATFORM_PROVIDERS,
TEST_BROWSER_DYNAMIC_APPLICATION_PROVIDERS} from @angular/platform-browser-dynamic/testing;
setBaseTestProviders(TEST_BROWSER_DYNAMIC_PLATFORM_PROVIDERS,
TEST_BROWSER_DYNAMIC_APPLICATION_PROVIDERS);
TEST_BROWSER_DYNAMIC_APPLICATION_PROVIDERS);
```
AFTER:
```
import {TestBed} from @angular/core/testing;
import {BrowserDynamicTestingModule, platformBrowserDynamicTesting} from @angular/platform-browser-dynamic/testing;
TestBed.initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting()
@ -439,22 +723,22 @@
```
- E.g. for the server platform:
BEFORE:
```
import {setBaseTestProviders} from @angular/core/testing;
import {TEST_SERVER_PLATFORM_PROVIDERS,
TEST_SERVER_APPLICATION_PROVIDERS} from @angular/platform-server/testing/server;
setBaseTestProviders(TEST_SERVER_PLATFORM_PROVIDERS,
TEST_SERVER_APPLICATION_PROVIDERS);
TEST_SERVER_APPLICATION_PROVIDERS);
```
AFTER:
```
import {TestBed} from @angular/core/testing;
import {ServerTestingModule, serverTestingPlatform} from @angular/platform-browser-dynamic/testing;
TestBed.initTestEnvironment(
ServerTestingModule,
serverTestingPlatform()
@ -462,15 +746,6 @@
```
Related to #9726
* router: Previously both imperative (router.navigate) and declarative (routerLink) navigations
would preserve the current query params and fragment. This behavior turned out to
be confusing. This commit changes it.
Now, neither is preserved by default. To preserve them, you need to do the following:
`router.naviage("newUrl", {preserveQueryParams: true, preserveFragment: true})`
`<a routerLink="newUrl" preserveQueryParams preserveFragment></a>`
* ngUpgrade: UpgradeAdapter.addProvider are now deprecated in favor of passing in an NgModule into the adapter's constructor
Before:
@ -491,7 +766,30 @@
let upgradeAdapter = new UpgradeAdapter(MyModule);
```
* ngModel: `ngModel` is now always asynchronous when updating. This means that in tests, instead of calling `ComponentFixture.detectChanges`, you'll need to use `ComponentFixture.whenStable`, which is asynchronous.
Before:
```js
let fixture = TestBed.createComponent(InputComp);
fixture.detectChanges();
let inputBox = <HTMLInputElement> fixture.debugElement.query(By.css('input')).nativeElement;
expect(inputBox.value).toEqual('Original Name');
```
After:
```js
let fixture = TedBed.createComponent(InputComp);
fixture.whenStable().then(() => {
let inputBox = <HTMLInputElement> fixture.debugElement.query(By.css('input')).nativeElement;
expect(inputBox.value).toEqual('Original Name');
});
```
### ROUTER CHANGE LOG
[You can find the router changelog here.](https://github.com/angular/angular/blob/master/modules/@angular/router/CHANGELOG.md)
<a name="2.0.0-rc.4"></a>
# [2.0.0-rc.4](https://github.com/angular/angular/compare/2.0.0-rc.3...2.0.0-rc.4) (2016-06-30)
@ -557,7 +855,7 @@
### BREAKING CHANGES
* http: The changes to Http's URLSearchParams serialization now
* http: The changes to Http's URLSearchParams serialization now
prevent encoding of these characters inside query parameters
which were previously converted to percent-encoded values `@ : $ , ; + ; ? /`
@ -619,8 +917,8 @@
stringifyElement,
expect (and custom matchers for Jasmine)
```
* testing:
* testing:
Before:
expect(...).toThrowErrorWith(msg);
@ -671,7 +969,7 @@
it('does stuff', inject([MyService], (service) => {
// actual test
});
}));
});
```
@ -898,7 +1196,7 @@ The likelihood of anyone actually depending on this property is very low.
* HTML, style values, and URLs are now automatically sanitized. Values that do not match are escaped
or ignored. When binding a URL or style property that would get ignored, bind to a value
explicitly marked as safe instead by injection the DOM sanitization service:
```
class MyComponent {
constructor(sanitizer: DomSanitizationService) {
@ -909,7 +1207,7 @@ The likelihood of anyone actually depending on this property is very low.
}
```
* `PLATFORM_PIPES` and `PLATFORM_DIRECTIVES` now are fields on `CompilerConfig`.
* `PLATFORM_PIPES` and `PLATFORM_DIRECTIVES` now are fields on `CompilerConfig`.
Instead of providing a binding to these tokens, provide a binding for `CompilerConfig` instead.
* `CompilerConfig` used to take positional arguments and now takes named arguments.

View File

@ -18,18 +18,17 @@ Help us keep Angular open and inclusive. Please read and follow our [Code of Con
## <a name="question"></a> Got a Question or Problem?
If you have questions about how to *use* Angular, please direct them to the [Google Group][angular-group]
discussion list or [StackOverflow][stackoverflow]. Please note that Angular 2 is still in early developer preview, and the core team's capacity to answer usage questions is limited. We are also available on [Gitter][gitter].
discussion list or [StackOverflow][stackoverflow]. Please note that the Angular team's capacity to answer usage questions is limited. We are also available on [Gitter][gitter].
## <a name="issue"></a> Found an Issue?
If you find a bug in the source code or a mistake in the documentation, you can help us by
If you find a bug in the source code, you can help us by
[submitting an issue](#submit-issue) to our [GitHub Repository][github]. Even better, you can
[submit a Pull Request](#submit-pr) with a fix.
## <a name="feature"></a> Want a Feature?
You can *request* a new feature by [submitting an issue](#submit-issue) to our [GitHub
Repository][github]. If you would like to *implement* a new feature, please submit an issue with
a proposal for your work first, to be sure that we can use it. Angular 2 is in developer preview
and we are not ready to accept major contributions ahead of the full release.
a proposal for your work first, to be sure that we can use it.
Please consider what kind of change it is:
* For a **Major Feature**, first open an issue and outline your proposal so that it can be

View File

@ -1,7 +1,7 @@
# Building and Testing Angular 2 for JS and Dart
# Building and Testing Angular 2 for JS
This document describes how to set up your development environment to build and test Angular, both
JS and Dart versions. It also explains the basic mechanics of using `git`, `node`, and `npm`.
This document describes how to set up your development environment to build and test Angular 2 JS version.
It also explains the basic mechanics of using `git`, `node`, and `npm`.
* [Prerequisite Software](#prerequisite-software)
* [Getting the Sources](#getting-the-sources)
@ -52,7 +52,7 @@ git remote add upstream https://github.com/angular/angular.git
```
## Installing NPM Modules
Next, install the JavaScript modules and Dart packages needed to build and test Angular:
Next, install the JavaScript modules needed to build and test Angular:
```shell
# Install Angular project dependencies (package.json)

View File

@ -6,7 +6,8 @@
[![npm version](https://badge.fury.io/js/%40angular%2Fcore.svg)](https://badge.fury.io/js/%40angular%2Fcore)
[![Downloads](http://img.shields.io/npm/dm/angular2.svg)](https://npmjs.org/package/angular2)
[![Sauce Test Status](https://saucelabs.com/browser-matrix/angular2-ci.svg)](https://saucelabs.com/u/angular2-ci)
[![Sauce Test Status](https://saucelabs.com/browser-matrix/angular2-ci.svg)](https://saucelabs.com/u/angular2-ci)
*Safari (7+), iOS (7+), Edge (14) and IE mobile (11) are tested on [BrowserStack][browserstack].*
Angular
=========
@ -16,7 +17,6 @@ repository for [Angular 2][ng2] Typescript/JavaScript (JS).
Angular2 for [Dart][dart] can be found at [dart-lang/angular2][ng2dart].
Angular 2 is currently in **Release Candidate**.
## Quickstart
@ -28,10 +28,9 @@ Angular 2 is currently in **Release Candidate**.
Want to file a bug, contribute some code, or improve documentation? Excellent! Read up on our
guidelines for [contributing][contributing] and then check out one of our issues in the [hotlist: community-help](https://github.com/angular/angular/labels/hotlist%3A%20community-help).
[browserstack]: https://www.browserstack.com/
[contributing]: http://github.com/angular/angular/blob/master/CONTRIBUTING.md
[dart]: http://www.dartlang.org
[dartium]: http://www.dartlang.org/tools/dartium
[quickstart]: https://angular.io/docs/ts/latest/quickstart.html
[ng2]: http://angular.io
[ngDart]: http://angulardart.org

140
TOOLS.md
View File

@ -1,4 +1,140 @@
# Developer Tools for Angular 2
- [JavaScript](TOOLS_JS.md)
- [Dart](TOOLS_DART.md)
Here you will find a collection of tools and tips for keeping your application
perform well and contain fewer bugs.
## Angular debug tools in the dev console
Angular provides a set of debug tools that are accessible from any browser's
developer console. In Chrome the dev console can be accessed by pressing
Ctrl + Shift + j.
### Enabling debug tools
By default the debug tools are disabled. You can enable debug tools as follows:
```typescript
import {enableDebugTools} from '@angular/platform-browser';
bootstrap(Application).then((appRef) => {
enableDebugTools(appRef);
});
```
### Using debug tools
In the browser open the developer console (Ctrl + Shift + j in Chrome). The
top level object is called `ng` and contains more specific tools inside it.
Example:
```javascript
ng.profiler.timeChangeDetection();
```
## Performance
### Change detection profiler
If your application is janky (it misses frames) or is slow according to other
metrics it is important to find the root cause of the issue. Change detection
is a phase in Angular's lifecycle that detects changes in values that are
bound to UI, and if it finds a change it performs the corresponding UI update.
However, sometimes it is hard to tell if the slowness is due to the act of
computing the changes being slow, or due to the act of applying those changes
to the UI. For your application to be performant it is important that the
process of computing changes is very fast. For best results it should be under
3 milliseconds in order to leave room for the application logic, the UI updates
and browser's rendering pipeline to fit withing the 16 millisecond frame
(assuming the 60 FPS target frame rate).
Change detection profiler repeatedly performs change detection without invoking
any user actions, such as clicking buttons or entering text in input fields. It
then computes the average amount of time it took to perform a single cycle of
change detection in milliseconds and prints it to the console. This number
depends on the current state of the UI. You will likely see different numbers
as you go from one screen in your application to another.
#### Running the profiler
Enable debug tools (see above), then in the dev console enter the following:
```javascript
ng.profiler.timeChangeDetection();
```
The results will be printed to the console.
#### Recording CPU profile
Pass `{record: true}` an argument:
```javascript
ng.profiler.timeChangeDetection({record: true});
```
Then open the "Profiles" tab. You will see the recorded profile titled
"Change Detection". In Chrome, if you record the profile repeatedly, all the
profiles will be nested under "Change Detection".
#### Interpreting the numbers
In a properly-designed application repeated attempts to detect changes without
any user actions should result in no changes to be applied on the UI. It is
also desirable to have the cost of a user action be proportional to the amount
of UI changes required. For example, popping up a menu with 5 items should be
vastly faster than rendering a table of 500 rows and 10 columns. Therefore,
change detection with no UI updates should be as fast as possible. Ideally the
number printed by the profiler should be well below the length of a single
animation frame (16ms). A good rule of thumb is to keep it under 3ms.
#### Investigating slow change detection
So you found a screen in your application on which the profiler reports a very
high number (i.e. >3ms). This is where a recorded CPU profile can help. Enable
recording while profiling:
```javascript
ng.profiler.timeChangeDetection({record: true});
```
Then look for hot spots using
[Chrome CPU profiler](https://developer.chrome.com/devtools/docs/cpu-profiling).
#### Reducing change detection cost
There are many reasons for slow change detection. To gain intuition about
possible causes it would help to understand how change detection works. Such a
discussion is outside the scope of this document (TODO link to docs), but here
are some key concepts in brief.
By default Angular uses "dirty checking" mechanism for finding model changes.
This mechanism involves evaluating every bound expression that's active on the
UI. These usually include text interpolation via `{{expression}}` and property
bindings via `[prop]="expression"`. If any of the evaluated expressions are
costly to compute they could contribute to slow change detection. A good way to
speed things up is to use plain class fields in your expressions and avoid any
kinds of computation. Example:
```typescript
@Component({
template: '<button [enabled]="isEnabled">{{title}}</button>'
})
class FancyButton {
// GOOD: no computation, just return the value
isEnabled: boolean;
// BAD: computes the final value upon request
_title: String;
get title(): String { return this._title.trim().toUpperCase(); }
}
```
Most cases like these could be solved by precomputing the value and storing the
final value in a field.
Angular also supports a second type of change detection - the "push" model. In
this model Angular does not poll your component for changes. Instead, the
component "tells" Angular when it changes and only then does Angular perform
the update. This model is suitable in situations when your data model uses
observable or immutable objects (also a discussion for another time).

View File

@ -1,140 +0,0 @@
# Developer Tools for JavaScript
Here you will find a collection of tools and tips for keeping your application
perform well and contain fewer bugs.
## Angular debug tools in the dev console
Angular provides a set of debug tools that are accessible from any browser's
developer console. In Chrome the dev console can be accessed by pressing
Ctrl + Shift + j.
### Enabling debug tools
By default the debug tools are disabled. You can enable debug tools as follows:
```typescript
import {enableDebugTools} from '@angular/platform-browser';
bootstrap(Application).then((appRef) => {
enableDebugTools(appRef);
});
```
### Using debug tools
In the browser open the developer console (Ctrl + Shift + j in Chrome). The
top level object is called `ng` and contains more specific tools inside it.
Example:
```javascript
ng.profiler.timeChangeDetection();
```
## Performance
### Change detection profiler
If your application is janky (it misses frames) or is slow according to other
metrics it is important to find the root cause of the issue. Change detection
is a phase in Angular's lifecycle that detects changes in values that are
bound to UI, and if it finds a change it performs the corresponding UI update.
However, sometimes it is hard to tell if the slowness is due to the act of
computing the changes being slow, or due to the act of applying those changes
to the UI. For your application to be performant it is important that the
process of computing changes is very fast. For best results it should be under
3 milliseconds in order to leave room for the application logic, the UI updates
and browser's rendering pipeline to fit withing the 16 millisecond frame
(assuming the 60 FPS target frame rate).
Change detection profiler repeatedly performs change detection without invoking
any user actions, such as clicking buttons or entering text in input fields. It
then computes the average amount of time it took to perform a single cycle of
change detection in milliseconds and prints it to the console. This number
depends on the current state of the UI. You will likely see different numbers
as you go from one screen in your application to another.
#### Running the profiler
Enable debug tools (see above), then in the dev console enter the following:
```javascript
ng.profiler.timeChangeDetection();
```
The results will be printed to the console.
#### Recording CPU profile
Pass `{record: true}` an argument:
```javascript
ng.profiler.timeChangeDetection({record: true});
```
Then open the "Profiles" tab. You will see the recorded profile titled
"Change Detection". In Chrome, if you record the profile repeatedly, all the
profiles will be nested under "Change Detection".
#### Interpreting the numbers
In a properly-designed application repeated attempts to detect changes without
any user actions should result in no changes to be applied on the UI. It is
also desirable to have the cost of a user action be proportional to the amount
of UI changes required. For example, popping up a menu with 5 items should be
vastly faster than rendering a table of 500 rows and 10 columns. Therefore,
change detection with no UI updates should be as fast as possible. Ideally the
number printed by the profiler should be well below the length of a single
animation frame (16ms). A good rule of thumb is to keep it under 3ms.
#### Investigating slow change detection
So you found a screen in your application on which the profiler reports a very
high number (i.e. >3ms). This is where a recorded CPU profile can help. Enable
recording while profiling:
```javascript
ng.profiler.timeChangeDetection({record: true});
```
Then look for hot spots using
[Chrome CPU profiler](https://developer.chrome.com/devtools/docs/cpu-profiling).
#### Reducing change detection cost
There are many reasons for slow change detection. To gain intuition about
possible causes it would help to understand how change detection works. Such a
discussion is outside the scope of this document (TODO link to docs), but here
are some key concepts in brief.
By default Angular uses "dirty checking" mechanism for finding model changes.
This mechanism involves evaluating every bound expression that's active on the
UI. These usually include text interpolation via `{{expression}}` and property
bindings via `[prop]="expression"`. If any of the evaluated expressions are
costly to compute they could contribute to slow change detection. A good way to
speed things up is to use plain class fields in your expressions and avoid any
kinds of computation. Example:
```typescript
@Component({
template: '<button [enabled]="isEnabled">{{title}}</button>'
})
class FancyButton {
// GOOD: no computation, just return the value
isEnabled: boolean;
// BAD: computes the final value upon request
_title: String;
get title(): String { return this._title.trim().toUpperCase(); }
}
```
Most cases like these could be solved by precomputing the value and storing the
final value in a field.
Angular also supports a second type of change detection - the "push" model. In
this model Angular does not poll your component for changes. Instead, the
component "tells" Angular when it changes and only then does Angular perform
the update. This model is suitable in situations when your data model uses
observable or immutable objects (also a discussion for another time).

View File

@ -1,25 +1,72 @@
# Triage Process and Github Labels for Angular 2
This document describes how the Angular team uses labels and milestones to triage issues on github.
This document describes how the Angular team uses labels and milestones
to triage issues on github. The basic idea of the new process is that
caretaker only assigns a component and type (bug, feature) label. The
owner of the component than is in full control of how the issues should
be triaged further.
# Issues and PRs
## Triaged vs Untriaged Issues
Once this process is implemented and in use, we will revisit it to see
if further labeling is needed.
Every triaged issue must have four attributes assigned to it:
## Components
* `priority` -- P0 through P4. P0 issues are "drop everything and do this now". P4 are nice to have.
* `component` -- Which area of Angular knowledge this relates to.
* `effort` -- Rough assessment of how much work this issue is. E.g. `effort: easy` means
"probably a few hours of work".
* `type` -- Whether this issue is a bug, feature, or other kind of task.
A caretaker should be able to determine which component the issue
belongs to. The components have a clear piece of source code associated
with it.
Untriaged issues are any issues in the queue that don't yet have these four attributes.
* `comp: animations`: `@matsko`
* `comp: benchpress`: `@tbosch`
* `comp: build/ci`: `@IgorMinar` -- All build and CI scripts
* `comp: common`: `@mhevery` -- This includes core components / pipes.
* `comp: core/compiler`: `@tbosch` -- Because core and compiler are very
intertwined, we will be treating them as one.
* `comp: forms`: `@kara`
* `comp: http`: `@jeffbcross`
* `comp: i18n`: `@vicb`
* `comp: metadata-extractor`: `@chuckjaz`
* `comp: router`: `@vsavkin`
* `comp: testing`: `@juliemr`
* `comp: upgrade`: `@mhevery`
* `comp: web-worker`: `@vicb`
* `comp: zone`: `@mhevery`
You can view a report of untriaged issues here, in our
[Angular Triage Dashboard](http://mhevery.github.io/github_issues/).
There are few components which are cross-cutting. They don't have
a clear location in the source tree. We will treat them as a component
even thought no specific source tree is associated with them.
Issues should also have a clear action to complete that can be addressed or resolved within the
scope of Angular 2. We'll close issues that don't meet these criteria.
* `comp: documentation`: `@naomiblack`
* `comp: packaging`: `@mhevery`
* `comp: performance`: `@tbosch`
* `comp: security`: `@IgorMinar`
## Type
What kind of problem is this?
* `type: RFC / discussion / question`
* `type: bug`
* `type: chore`
* `type: feature`
* `type: performance`
* `type: refactor`
## Caretaker Triage Process
It is the caretaker's responsibility to assign `comp: *` and `type: *`
to each new issue as they come in. The reason why we limit the
responsibility of the caretaker to these two labels is that it is
unlikely that without domain knowledge the caretaker could add any
additional labels of value.
## Component's owner Triage Process
At this point we are leaving each component owner to determine their own
process for their component.
It will be up to the component owner to determine the order in which the
issues within the component will be resolved.
### Assigning Issues to Milestones
@ -37,7 +84,10 @@ We aim to only have at most three milestones open at a time:
The [backlog](https://github.com/angular/angular/issues?q=is%3Aopen+is%3Aissue+no%3Amilestone)
consists of all issues that have been triaged but do not have an assignee or milestone.
## Triaged vs Untriaged PRs
## Triaged vs Untrained PRs
PRs should also be label with a `comp: *` so that it is clear which
primary area the PR effects.
Because of the cumulative pain associated with rebasing PRs, we triage PRs daily, and
closing or reviewing PRs is a top priority ahead of other ongoing work.
@ -63,90 +113,6 @@ uncontroversial change.
PRs do not need to be assigned to milestones, unless a milestone release should be held for that
PR to land.
Victor (`vsavkin`) and Tobias (`tbosch`) are owners of the PR queue. Here is a list of [current
untriaged PRs](https://github.com/angular/angular/pulls?utf8=%E2%9C%93&q=is%3Aopen+no%3Amilestone+is%3Apr+-label%3A%22pr_action%3A+cleanup%22+-label%3A%22pr_action%3A+merge%22+-label%3A%22pr_action%3A+review%22+-label%3A%22pr_action%3A+discuss%22+-label%3A%22pr_state%3A+blocked%22+-label%3A%22pr_state%3A+WIP%22+).
# Prioritization of Work
What should you be working on?
1. Any PRs that are assigned to you that don't have `pr_state: WIP` or `pr_state: blocked`
1. Any issues that are assigned to you in the lowest-numbered Milestone
1. Any issues that are assigned to you in any Milestone
If there are no issues assigned to you in any Milestone, pick an issue, self-assign it, and add
it to the most appropriate Milestone based on effort.
Here are some suggestions for what to work on next:
* Filter for issues in a component that you are knowledgeable about, and pick something that has a
high priority.
* Filter for any small effort task that has the special `cust: GT` or `cust:Ionic` tags,
and priority > P3.
* Add a new task that's really important, add `component`, `priority`, `effort`, `type` and
assign it to yourself and the most appropriate milestone.
# Labels Used in Triage
## Priority
How urgent is this issue? We use priority to determine what should be worked on in each new
milestone.
* `P0: critical` -- drop everything to work on this
* `P1: urgent` -- resolve quickly in the current milestone. people are blocked
* `P2: required` -- needed for development but not urgent yet. workaround exists, or e.g. new API
* `P3: important` -- must complete before Angular 2 is ready for release
* `P4: nice to have` -- a good idea, but maybe not until after release
## Effort
Rough, non-binding estimate of how much work this issue represents. Please change this assessment
for anything you're working on to better reflect reality.
* `effort: easy` -- straightforward issue that can be resolved in a few hours, e.g. < 1 day of work.
* `effort: medium` -- issue that will be a few days of work. Can be completed within a single
milestone.
* `effort: tough` -- issue that will likely take more than 1 milestone to complete.
<!-- We don't like these label names as
they're not absolute (what is one developer-hour, really?) but decided it wasn't worth arguing
over terms. -->
## Component
Which area of Angular knowledge is this issue most closely related to? Helpful when deciding what
to work on next.
* `comp: benchpress` -- benchmarks and performance testing &rarr; *tbosch*, *crossj*
* `comp: build/dev-productivity` -- build process, e.g. CLI and related tasks &rarr; *iminar*, *caitp*
* `comp: build/pipeline` -- build pipeline, e.g. ts2dart &rarr; *mprobst*, *alexeagle*
* `comp: core` -- general core Angular issues, not related to a sub-category (see below) &rarr;
*mhevery*
* `comp: core/animations` -- animations framework &rarr; *matsko*
* `comp: core/change_detection` -- change detection &rarr; *vsavkin*
* `comp: core/di` -- dependency injection &rarr; *vicb*, *rkirov*
* `comp: core/directives` -- directives
* `comp: core/forms` -- forms &rarr; *vsavkin*
* `comp: core/pipes` -- pipes
* `comp: core/view` -- runtime processing of the `View`s
* `comp: core/view/compiler` -- static analysis of the templates which generate `ProtoView`s.
* `comp: core/testbed` -- e2e tests and support for them
* `comp: core/webworker` -- core web worker infrastructure
* `comp: dart-transformer` -- Dart transforms &rarr; *kegluneq*, *jakemac*
* `comp: data-access` -- &rarr; *jeffbcross*
* `comp: docs` -- API docs and doc generation &rarr; *naomiblack*, *petebacondarwin*
* `comp: material-components` -- Angular Material components built in Angular 2 &rarr; *jelbourn*
* `comp: router` -- Component Router &rarr; *btford*, *igorminar*, *matsko*
* `comp: wrenchjs`
## Type
What kind of problem is this?
* `type RFC / discussion / question`
* `type bug`
* `type chore`
* `type feature`
* `type performance`
* `type refactor`
## Special Labels
@ -160,9 +126,6 @@ More active discussion is needed before the issue can be worked on further. Typi
Managed by googlebot. Indicates whether a PR has a CLA on file for its author(s). Only issues with
`cla:yes` should be merged into master.
### cust
This is an issue causing user pain for early adopter customers `cust: GT` or `cust: Ionic`.
### WORKS_AS_INTENDED
Only used on closed issues, to indicate to the reporter why we closed it.

View File

@ -1,6 +1,6 @@
{
"name": "angular2",
"dependencies": {
"polymer": "Polymer/polymer"
"polymer": "Polymer/polymer#^1.6.0"
}
}

View File

@ -22,9 +22,11 @@ var CIconfiguration = {
'Safari7': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
'Safari8': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
'Safari9': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
'Safari10': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
'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}},
'WindowsPhone': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}}
};
@ -83,6 +85,12 @@ var customLaunchers = {
platform: 'OS X 10.11',
version: '9.0'
},
'SL_SAFARI10': {
base: 'SauceLabs',
browserName: 'safari',
platform: 'OS X 10.12',
version: '10.0'
},
'SL_IOS7': {
base: 'SauceLabs',
browserName: 'iphone',
@ -101,6 +109,12 @@ var customLaunchers = {
platform: 'OS X 10.10',
version: '9.3'
},
'SL_IOS10': {
base: 'SauceLabs',
browserName: 'iphone',
platform: 'OS X 10.10',
version: '10.0'
},
'SL_IE9': {
base: 'SauceLabs',
browserName: 'internet explorer',
@ -186,6 +200,12 @@ var customLaunchers = {
os: 'OS X',
os_version: 'El Capitan'
},
'BS_SAFARI10': {
base: 'BrowserStack',
browser: 'safari',
os: 'OS X',
os_version: 'Sierra'
},
'BS_IOS7': {
base: 'BrowserStack',
device: 'iPhone 5S',
@ -204,6 +224,12 @@ var customLaunchers = {
os: 'ios',
os_version: '9.1'
},
'BS_IOS10': {
base: 'BrowserStack',
device: 'iPhone SE',
os: 'ios',
os_version: '10.0'
},
'BS_IE9': {
base: 'BrowserStack',
browser: 'ie',
@ -271,12 +297,12 @@ var customLaunchers = {
var sauceAliases = {
'ALL': Object.keys(customLaunchers).filter(function(item) {return customLaunchers[item].base == 'SauceLabs';}),
'DESKTOP': ['SL_CHROME', 'SL_FIREFOX', 'SL_IE9', 'SL_IE10', 'SL_IE11', 'SL_EDGE', 'SL_SAFARI7', 'SL_SAFARI8', 'SL_SAFARI9'],
'MOBILE': ['SL_ANDROID4.1', 'SL_ANDROID4.2', 'SL_ANDROID4.3', 'SL_ANDROID4.4', 'SL_ANDROID5', 'SL_IOS7', 'SL_IOS8', 'SL_IOS9'],
'DESKTOP': ['SL_CHROME', 'SL_FIREFOX', 'SL_IE9', 'SL_IE10', 'SL_IE11', 'SL_EDGE', 'SL_SAFARI7', 'SL_SAFARI8', 'SL_SAFARI9', 'SL_SAFARI10'],
'MOBILE': ['SL_ANDROID4.1', 'SL_ANDROID4.2', 'SL_ANDROID4.3', 'SL_ANDROID4.4', 'SL_ANDROID5', 'SL_IOS7', 'SL_IOS8', 'SL_IOS9', 'SL_IOS10'],
'ANDROID': ['SL_ANDROID4.1', 'SL_ANDROID4.2', 'SL_ANDROID4.3', 'SL_ANDROID4.4', 'SL_ANDROID5'],
'IE': ['SL_IE9', 'SL_IE10', 'SL_IE11'],
'IOS': ['SL_IOS7', 'SL_IOS8', 'SL_IOS9'],
'SAFARI': ['SL_SAFARI7', 'SL_SAFARI8', 'SL_SAFARI9'],
'IOS': ['SL_IOS7', 'SL_IOS8', 'SL_IOS9', 'SL_IOS10'],
'SAFARI': ['SL_SAFARI7', 'SL_SAFARI8', 'SL_SAFARI9', 'SL_SAFARI10'],
'BETA': ['SL_CHROMEBETA', 'SL_FIREFOXBETA'],
'DEV': ['SL_CHROMEDEV', 'SL_FIREFOXDEV'],
'CI_REQUIRED': buildConfiguration('unitTest', 'SL', true),
@ -285,12 +311,12 @@ var sauceAliases = {
var browserstackAliases = {
'ALL': Object.keys(customLaunchers).filter(function(item) {return customLaunchers[item].base == 'BrowserStack';}),
'DESKTOP': ['BS_CHROME', 'BS_FIREFOX', 'BS_IE9', 'BS_IE10', 'BS_IE11', 'BS_EDGE', 'BS_SAFARI7', 'BS_SAFARI8', 'BS_SAFARI9'],
'MOBILE': ['BS_ANDROID4.3', 'BS_ANDROID4.4', 'BS_IOS7', 'BS_IOS8', 'BS_IOS9', 'BS_WINDOWSPHONE'],
'DESKTOP': ['BS_CHROME', 'BS_FIREFOX', 'BS_IE9', 'BS_IE10', 'BS_IE11', 'BS_EDGE', 'BS_SAFARI7', 'BS_SAFARI8', 'BS_SAFARI9', 'BS_SAFARI10'],
'MOBILE': ['BS_ANDROID4.3', 'BS_ANDROID4.4', 'BS_IOS7', 'BS_IOS8', 'BS_IOS9', 'BS_IOS10', 'BS_WINDOWSPHONE'],
'ANDROID': ['BS_ANDROID4.3', 'BS_ANDROID4.4'],
'IE': ['BS_IE9', 'BS_IE10', 'BS_IE11'],
'IOS': ['BS_IOS7', 'BS_IOS8', 'BS_IOS9'],
'SAFARI': ['BS_SAFARI7', 'BS_SAFARI8', 'BS_SAFARI9'],
'IOS': ['BS_IOS7', 'BS_IOS8', 'BS_IOS9', 'BS_IOS10'],
'SAFARI': ['BS_SAFARI7', 'BS_SAFARI8', 'BS_SAFARI9', 'BS_SAFARI10'],
'CI_REQUIRED': buildConfiguration('unitTest', 'BS', true),
'CI_OPTIONAL': buildConfiguration('unitTest', 'BS', false)
};

198
build.sh
View File

@ -4,118 +4,162 @@ set -e -o pipefail
cd `dirname $0`
PACKAGES=(core
compiler
common
forms
platform-browser
platform-browser-dynamic
platform-server
platform-webworker
platform-webworker-dynamic
http
router
upgrade
compiler-cli
benchpress)
BUILD_ALL=true
BUNDLE=true
for ARG in "$@"; do
case "$ARG" in
--packages=*)
PACKAGES_STR=${ARG#--packages=}
PACKAGES=( ${PACKAGES_STR//,/ } )
BUILD_ALL=false
;;
--bundle=*)
BUNDLE=( "${ARG#--bundle=}" )
;;
*)
echo "Unknown option $ARG."
exit 1
;;
esac
done
export NODE_PATH=${NODE_PATH}:$(pwd)/dist/all:$(pwd)/dist/tools
rm -rf ./dist/all/
mkdir -p ./dist/all/
TSC="node --max-old-space-size=3000 dist/tools/@angular/tsc-wrapped/src/main"
UGLIFYJS=`pwd`/node_modules/.bin/uglifyjs
TSCONFIG=./tools/tsconfig.json
echo "====== (all)COMPILING: \$(npm bin)/tsc -p ${TSCONFIG} ====="
echo "====== (tools)COMPILING: \$(npm bin)/tsc -p ${TSCONFIG} ====="
rm -rf ./dist/tools/
mkdir -p ./dist/tools/
$(npm bin)/tsc -p ${TSCONFIG}
cp ./tools/@angular/tsc-wrapped/package.json ./dist/tools/@angular/tsc-wrapped
echo "====== Copying files needed for e2e tests ====="
cp -r ./modules/playground ./dist/all/
cp -r ./modules/playground/favicon.ico ./dist/
#rsync -aP ./modules/playground/* ./dist/all/playground/
mkdir ./dist/all/playground/vendor
cd ./dist/all/playground/vendor
ln -s ../../../../node_modules/es6-shim/es6-shim.js .
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 .
cd -
if [[ ${BUILD_ALL} == true ]]; then
rm -rf ./dist/all/
mkdir -p ./dist/all/
echo "====== Copying files needed for e2e tests ====="
cp -r ./modules/playground ./dist/all/
cp -r ./modules/playground/favicon.ico ./dist/
#rsync -aP ./modules/playground/* ./dist/all/playground/
mkdir ./dist/all/playground/vendor
cd ./dist/all/playground/vendor
ln -s ../../../../node_modules/core-js/client/core.js .
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 .
cd -
TSCONFIG=./modules/tsconfig.json
echo "====== (all)COMPILING: \$(npm bin)/tsc -p ${TSCONFIG} ====="
# compile ts code
TSC="node --max-old-space-size=3000 dist/tools/@angular/tsc-wrapped/src/main"
$TSC -p modules/tsconfig.json
echo "====== Copying files needed for benchmarks ====="
cp -r ./modules/benchmarks ./dist/all/
cp -r ./modules/benchmarks/favicon.ico ./dist/
mkdir ./dist/all/benchmarks/vendor
cd ./dist/all/benchmarks/vendor
ln -s ../../../../node_modules/core-js/client/core.js .
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 .
ln -s ../../../../bower_components/polymer .
ln -s ../../../../node_modules/incremental-dom/dist/incremental-dom-cjs.js
cd -
rm -rf ./dist/packages-dist
TSCONFIG=./modules/tsconfig.json
echo "====== (all)COMPILING: \$(npm bin)/tsc -p ${TSCONFIG} ====="
# compile ts code
$TSC -p modules/tsconfig.json
for PACKAGE in \
core \
compiler \
common \
forms \
platform-browser \
platform-browser-dynamic \
platform-server \
http \
router \
router-deprecated \
upgrade \
compiler-cli
rm -rf ./dist/packages-dist
fi
for PACKAGE in ${PACKAGES[@]}
do
SRCDIR=./modules/@angular/${PACKAGE}
DESTDIR=./dist/packages-dist/${PACKAGE}
UMD_ES6_PATH=${DESTDIR}/esm/${PACKAGE}.umd.js
PWD=`pwd`
SRCDIR=${PWD}/modules/@angular/${PACKAGE}
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_ES5_MIN_PATH=${DESTDIR}/bundles/${PACKAGE}.umd.min.js
LICENSE_BANNER=${PWD}/modules/@angular/license-banner.txt
if [[ ${PACKAGE} == "router-deprecated" ]]; then
echo "====== COMPILING: \$(npm bin)/tsc -p ${SRCDIR}/tsconfig-es5.json ====="
$(npm bin)/tsc -p ${SRCDIR}/tsconfig-es5.json
else
echo "====== COMPILING: ${TSC} -p ${SRCDIR}/tsconfig-es5.json ====="
$TSC -p ${SRCDIR}/tsconfig-es5.json
fi
rm -rf ${DESTDIR}
echo "====== COMPILING: ${TSC} -p ${SRCDIR}/tsconfig-build.json ====="
$TSC -p ${SRCDIR}/tsconfig-build.json
cp ${SRCDIR}/package.json ${DESTDIR}/
cp ${PWD}/modules/@angular/README.md ${DESTDIR}/
if [[ -e ${SRCDIR}/tsconfig-testing.json ]]; then
echo "====== COMPILING TESTING: ${TSC} -p ${SRCDIR}/tsconfig-testing.json"
$TSC -p ${SRCDIR}/tsconfig-testing.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
find ${DESTDIR} -type f -name '*.d.ts' -print0 | xargs -0 sed -i '' -e 's/\(^ *(static |private )*\)*readonly */\1/g'
find ${DESTDIR} -type f -name '*.d.ts' -print0 | xargs -0 sed -i '' -E 's/^( +)abstract ([[:alnum:]]+\:)/\1\2/g'
find ${DESTDIR} -type f -name '*.d.ts' -print0 | xargs -0 sed -i '' -e 's/\(^ *(static |private )*\)*readonly */\1/g'
find ${DESTDIR} -type f -name '*.d.ts' -print0 | xargs -0 sed -i '' -e 's/\/\/\/ <reference types="node" \/>//g'
find ${DESTDIR} -type f -name '*.d.ts' -print0 | xargs -0 sed -i '' -E 's/^( +)abstract ([[:alnum:]]+\:)/\1\2/g'
else
find ${DESTDIR} -type f -name '*.d.ts' -print0 | xargs -0 sed -i -e 's/\(^ *(static |private )*\)*readonly */\1/g'
find ${DESTDIR} -type f -name '*.d.ts' -print0 | xargs -0 sed -i -e 's/\/\/\/ <reference types="node" \/>//g'
find ${DESTDIR} -type f -name '*.d.ts' -print0 | xargs -0 sed -i -E 's/^( +)abstract ([[:alnum:]]+\:)/\1\2/g'
fi
if [[ ${PACKAGE} != compiler-cli ]]; then
if [[ ${PACKAGE} == benchpress ]]; then
cp ${SRCDIR}/*.md ${DESTDIR}
cp -r ${SRCDIR}/docs ${DESTDIR}
fi
if [[ ${PACKAGE} == "router-deprecated" ]]; then
echo "====== (esm)COMPILING: \$(npm bin)/tsc -p ${SRCDIR}/tsconfig-es2015.json ====="
$(npm bin)/tsc --emitDecoratorMetadata -p ${SRCDIR}/tsconfig-es2015.json
else
echo "====== (esm)COMPILING: $TSC -p ${SRCDIR}/tsconfig-es2015.json ====="
$TSC -p ${SRCDIR}/tsconfig-es2015.json
fi
if [[ ${BUNDLE} == true && ${PACKAGE} != compiler-cli && ${PACKAGE} != benchpress ]]; then
echo "====== BUNDLING: ${SRCDIR} ====="
mkdir ${DESTDIR}/bundles
(
cd ${SRCDIR}
echo "..." # here just to have grep match something and not exit with 1
echo "====== Rollup ${PACKAGE} index"
../../../node_modules/.bin/rollup -c rollup.config.js
cat ${LICENSE_BANNER} > ${UMD_ES5_PATH}.tmp
cat ${UMD_ES5_PATH} >> ${UMD_ES5_PATH}.tmp
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
echo "{\"main\": \"../bundles/${PACKAGE}-testing.umd.js\"}" > ${DESTDIR}/testing/package.json
cat ${LICENSE_BANNER} > ${UMD_TESTING_ES5_PATH}.tmp
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"
$(npm bin)/tsc \
--out ${UMD_ES5_PATH} \
--target es5 \
--lib "es6,dom" \
--allowJs \
${UMD_ES6_PATH}
rm ${UMD_ES6_PATH}
cat ./modules/@angular/license-banner.txt > ${UMD_ES5_PATH}.tmp
cat ${UMD_ES5_PATH} >> ${UMD_ES5_PATH}.tmp
mv ${UMD_ES5_PATH}.tmp ${UMD_ES5_PATH}
$(npm bin)/uglifyjs -c --screw-ie8 -o ${UMD_ES5_MIN_PATH} ${UMD_ES5_PATH}
fi
done
echo "====== COMPILING: \$(npm bin)/tsc -p benchpress/tsconfig.json ====="
$(npm bin)/tsc -p ./modules/benchpress/tsconfig.json
./modules/@angular/examples/build.sh

View File

@ -2,18 +2,26 @@
// THIS CHECK SHOULD BE THE FIRST THING IN THIS FILE
// This is to ensure that we catch env issues before we error while requiring other dependencies.
require('./tools/check-environment')(
{requiredNpmVersion: '>=3.5.3 <4.0.0', requiredNodeVersion: '>=5.4.1 <6.0.0'});
require('./tools/check-environment')({
requiredNpmVersion: '>=3.5.3 <4.0.0',
requiredNodeVersion: '>=5.4.1 <7.0.0',
});
const gulp = require('gulp');
const path = require('path');
const os = require('os');
const srcsToFmt =
['tools/**/*.ts', 'modules/@angular/**/*.ts', '!tools/public_api_guard/**/*.d.ts',
'modules/benchpress/**/*.ts', 'modules/playground/**/*.ts'];
// clang-format entry points
const srcsToFmt = [
'modules/@angular/**/*.ts',
'modules/benchmarks/**/*.ts',
'modules/e2e_util/**/*.ts',
'modules/playground/**/*.ts',
'tools/**/*.ts',
'!tools/public_api_guard/**/*.d.ts',
];
// Check source code for formatting errors (clang-format)
gulp.task('format:enforce', () => {
const format = require('gulp-clang-format');
const clangFormat = require('clang-format');
@ -21,6 +29,7 @@ gulp.task('format:enforce', () => {
format.checkFormat('file', clangFormat, {verbose: true, fail: true}));
});
// Format the source code with clang-format (see .clang-format)
gulp.task('format', () => {
const format = require('gulp-clang-format');
const clangFormat = require('clang-format');
@ -30,24 +39,26 @@ gulp.task('format', () => {
const entrypoints = [
'dist/packages-dist/core/index.d.ts',
'dist/packages-dist/core/testing.d.ts',
'dist/packages-dist/core/testing/index.d.ts',
'dist/packages-dist/common/index.d.ts',
'dist/packages-dist/common/testing.d.ts',
'dist/packages-dist/common/testing/index.d.ts',
// The API surface of the compiler is currently unstable - all of the important APIs are exposed
// via @angular/core, @angular/platform-browser or @angular/platform-browser-dynamic instead.
//'dist/packages-dist/compiler/index.d.ts',
//'dist/packages-dist/compiler/testing.d.ts',
'dist/packages-dist/upgrade/index.d.ts',
'dist/packages-dist/platform-browser/index.d.ts',
'dist/packages-dist/platform-browser/testing.d.ts',
'dist/packages-dist/platform-browser/testing/index.d.ts',
'dist/packages-dist/platform-browser-dynamic/index.d.ts',
'dist/packages-dist/platform-browser-dynamic/testing.d.ts',
'dist/packages-dist/platform-browser-dynamic/testing/index.d.ts',
'dist/packages-dist/platform-webworker/index.d.ts',
'dist/packages-dist/platform-webworker-dynamic/index.d.ts',
'dist/packages-dist/platform-server/index.d.ts',
'dist/packages-dist/platform-server/testing.d.ts',
'dist/packages-dist/platform-server/testing/index.d.ts',
'dist/packages-dist/http/index.d.ts',
'dist/packages-dist/http/testing.d.ts',
'dist/packages-dist/http/testing/index.d.ts',
'dist/packages-dist/forms/index.d.ts',
'dist/packages-dist/router/index.d.ts'
'dist/packages-dist/router/index.d.ts',
];
const publicApiDir = path.normalize('tools/public_api_guard');
const publicApiArgs = [
@ -56,22 +67,24 @@ const publicApiArgs = [
'--allowModuleIdentifiers', 'jasmine',
'--allowModuleIdentifiers', 'protractor',
'--allowModuleIdentifiers', 'angular',
'--onStabilityMissing', 'error'
'--onStabilityMissing', 'error',
].concat(entrypoints);
// Build angular
gulp.task('build.sh', (done) => {
const childProcess = require('child_process');
childProcess.exec(path.join(__dirname, 'build.sh'), error => done(error));
childProcess.exec(path.join(__dirname, 'build.sh'), done);
});
// Enforce that the public API matches the golden files
// Note that these two commands work on built d.ts files instead of the source
gulp.task('public-api:enforce', (done) => {
const childProcess = require('child_process');
childProcess
.spawn(
path.join(__dirname, `/node_modules/.bin/ts-api-guardian${/^win/.test(os.platform()) ? '.cmd' : ''}`),
path.join(__dirname, platformScriptPath(`/node_modules/.bin/ts-api-guardian`)),
['--verifyDir', publicApiDir].concat(publicApiArgs), {stdio: 'inherit'})
.on('close', (errorCode) => {
if (errorCode !== 0) {
@ -83,17 +96,29 @@ gulp.task('public-api:enforce', (done) => {
});
});
// Generate the public API golden files
gulp.task('public-api:update', ['build.sh'], (done) => {
const childProcess = require('child_process');
childProcess
.spawn(
path.join(__dirname, `/node_modules/.bin/ts-api-guardian${/^win/.test(os.platform()) ? '.cmd' : ''}`),
path.join(__dirname, platformScriptPath(`/node_modules/.bin/ts-api-guardian`)),
['--outDir', publicApiDir].concat(publicApiArgs), {stdio: 'inherit'})
.on('close', (errorCode) => done(errorCode));
.on('close', done);
});
gulp.task('lint', ['format:enforce', 'tools:build'], () => {
// 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'], () => {
const tslint = require('gulp-tslint');
// Built-in rules are at
// https://github.com/palantir/tslint#supported-rules
@ -102,22 +127,24 @@ gulp.task('lint', ['format:enforce', 'tools:build'], () => {
.pipe(tslint({
tslint: require('tslint').default,
configuration: tslintConfig,
rulesDirectory: 'dist/tools/tslint'
rulesDirectory: 'dist/tools/tslint',
formatter: 'prose',
}))
.pipe(tslint.report('prose', {emitError: true}));
.pipe(tslint.report({emitError: true}));
});
gulp.task('tools:build', (done) => { tsc('tools/', done); });
// Check for circular dependency in the source code
gulp.task('check-cycle', (done) => {
const madge = require('madge');
var dependencyObject = madge(['dist/all/'], {
const dependencyObject = madge(['dist/all/'], {
format: 'cjs',
extensions: ['.js'],
onParseFile: function(data) { data.src = data.src.replace(/\/\* circular \*\//g, "//"); }
});
var circularDependencies = dependencyObject.circular().getArray();
const circularDependencies = dependencyObject.circular().getArray();
if (circularDependencies.length > 0) {
console.log('Found circular dependencies!');
console.log(circularDependencies);
@ -126,20 +153,36 @@ gulp.task('check-cycle', (done) => {
done();
});
// Serve the built files
gulp.task('serve', () => {
let connect = require('gulp-connect');
let cors = require('cors');
const connect = require('gulp-connect');
const cors = require('cors');
connect.server({
root: `${__dirname}/dist`,
port: 8000,
livereload: false,
open: false,
middleware: (connect, opt) => [cors()]
middleware: (connect, opt) => [cors()],
});
});
// Serve the examples
gulp.task('serve-examples', () => {
const connect = require('gulp-connect');
const cors = require('cors');
connect.server({
root: `${__dirname}/dist/examples`,
port: 8001,
livereload: false,
open: false,
middleware: (connect, opt) => [cors()],
});
});
// Update the changelog with the latest changes
gulp.task('changelog', () => {
const conventionalChangelog = require('gulp-conventional-changelog');
@ -161,8 +204,13 @@ function tsc(projectPath, done) {
childProcess
.spawn(
path.normalize(`${__dirname}/node_modules/.bin/tsc`) + (/^win/.test(os.platform()) ? '.cmd' : ''),
path.normalize(platformScriptPath(`${__dirname}/node_modules/.bin/tsc`)),
['-p', path.join(__dirname, projectPath)],
{stdio: 'inherit'})
.on('close', (errorCode) => done(errorCode));
.on('close', done);
}
// returns the script path for the current platform
function platformScriptPath(path) {
return /^win/.test(os.platform()) ? `${path}.cmd` : path;
}

View File

@ -13,12 +13,14 @@ module.exports = function(config) {
// Loaded through the System loader, in `test-main.js`.
{pattern: 'dist/all/@angular/**/*.js', included: false, watched: true},
'node_modules/es6-shim/es6-shim.js',
'node_modules/core-js/client/core.js',
// include Angular v1 for upgrade module testing
'node_modules/angular/angular.min.js',
'node_modules/zone.js/dist/zone.js',
'node_modules/zone.js/dist/long-stack-trace-zone.js',
'node_modules/zone.js/dist/proxy.js',
'node_modules/zone.js/dist/sync-test.js',
'node_modules/zone.js/dist/jasmine-patch.js',
'node_modules/zone.js/dist/async-test.js',
'node_modules/zone.js/dist/fake-async-test.js',
@ -37,11 +39,12 @@ module.exports = function(config) {
exclude: [
'dist/all/@angular/**/e2e_test/**',
'dist/all/@angular/examples/**',
'dist/all/@angular/router/**',
'dist/all/@angular/compiler-cli/**',
'dist/all/@angular/benchpress/**',
'dist/all/angular1_router.js',
'dist/all/@angular/platform-browser/testing/e2e_util.js'
'dist/all/@angular/platform-browser/testing/e2e_util.js',
'dist/examples/**/e2e_test/**'
],
customLaunchers: browserProvidersConf.customLaunchers,

View File

@ -1,15 +0,0 @@
Angular2
=========
The sources for this package are in the main [Angular2](https://github.com/angular/angular) repo. Please file issues and pull requests against that repo. This is the repository for the upcoming 2.0 version. If you're looking for the current official version of Angular you should go to [angular/angular.js](https://github.com/angular/angular.js)
This package contains different sources for different users:
1. The files located in the root folder can be consumed using CommonJS.
2. The files under `/es6` are es6 compatible files that can be transpiled to
es5 using any transpiler. This contains:
* `dev/`: a development version that includes runtime type assertions
* `prod/`: a production version that does not include runtime type assertions
3. The files under `/ts` are the TypeScript source files.
License: Apache MIT 2.0

View File

@ -0,0 +1,6 @@
Angular
=======
The sources for this package are in the main [Angular](https://github.com/angular/angular) repo. Please file issues and pull requests against that repo.
License: MIT

View File

@ -3,6 +3,10 @@
Benchpress is a framework for e2e performance tests.
See [here for an example project](https://github.com/angular/benchpress-tree).
The sources for this package are in the main [Angular2](https://github.com/angular/angular) repo. Please file issues and pull requests against that repo.
License: Apache MIT 2.0
# Why?
There are so called "micro benchmarks" that essentially use a stop watch in the browser to measure time
@ -158,7 +162,7 @@ runner.sample({
````
When looking into the DevTools Timeline, we see a marker as well:
![Marked Timeline](marked_timeline.png)
![Marked Timeline](docs/marked_timeline.png)
### Custom Metrics Without Using `console.time`
@ -185,8 +189,8 @@ describe('home page load', function() {
userMetrics: {
timeToBootstrap: 'The time in milliseconds to bootstrap'
},
bindings: [
bind(RegressionSlopeValidator.METRIC).toValue('timeToBootstrap')
providers: [
{provide: RegressionSlopeValidator.METRIC, useValue: 'timeToBootstrap'}
]
}).then(done);
});
@ -208,9 +212,9 @@ Benchpress can also measure the "smoothness" of scrolling and animations. In ord
To collect these metrics, you need to execute `console.time('frameCapture')` and `console.timeEnd('frameCapture')` either in your benchmark application or in you benchmark driver via webdriver. The metrics mentioned above will only be collected between those two calls and it is recommended to wrap the time/timeEnd calls as closely as possible around the action you want to evaluate to get accurate measurements.
In addition to that, one extra binding needs to be passed to benchpress in tests that want to collect these metrics:
In addition to that, one extra provider needs to be passed to benchpress in tests that want to collect these metrics:
benchpress.sample(providers: [bp.bind(bp.Options.CAPTURE_FRAMES).toValue(true)], ... )
benchpress.sample(providers: [{provide: bp.Options.CAPTURE_FRAMES, useValue: true}], ... )
# Requests Metrics
@ -222,8 +226,8 @@ Benchpress can also record the number of requests sent and count the received "e
To collect these metrics, you need the following corresponding extra providers:
benchpress.sample(providers: [
bp.bind(bp.Options.RECEIVED_DATA).toValue(true),
bp.bind(bp.Options.REQUEST_COUNT).toValue(true)
{provide: bp.Options.RECEIVED_DATA, useValue: true},
{provide: bp.Options.REQUEST_COUNT, useValue: true}
], ... )
# Best practices
@ -256,7 +260,7 @@ To collect these metrics, you need the following corresponding extra providers:
# Detailed overview
![Overview](overview.png)
![Overview](docs/overview.png)
Definitions:

View File

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View File

@ -6,7 +6,10 @@
* found in the LICENSE file at https://angular.io/license
*/
export {Injector, OpaqueToken, ReflectiveInjector, bind, provide} from '@angular/core/src/di';
// Must be imported first, because angular2 decorators throws on load.
import 'reflect-metadata';
export {Injector, OpaqueToken, Provider, ReflectiveInjector} from '@angular/core';
export {Options} from './src/common_options';
export {MeasureValues} from './src/measure_values';
export {Metric} from './src/metric';
@ -24,7 +27,8 @@ export {Validator} from './src/validator';
export {RegressionSlopeValidator} from './src/validator/regression_slope_validator';
export {SizeValidator} from './src/validator/size_validator';
export {WebDriverAdapter} from './src/web_driver_adapter';
export {PerfLogFeatures, WebDriverExtension} from './src/web_driver_extension';
export {PerfLogEvent, PerfLogFeatures, WebDriverExtension} from './src/web_driver_extension';
export {ChromeDriverExtension} from './src/webdriver/chrome_driver_extension';
export {FirefoxDriverExtension} from './src/webdriver/firefox_driver_extension';
export {IOsDriverExtension} from './src/webdriver/ios_driver_extension';
export {SeleniumWebDriverAdapter} from './src/webdriver/selenium_webdriver_adapter';

View File

@ -0,0 +1,31 @@
{
"name": "@angular/benchpress",
"version": "0.1.0",
"description": "Benchpress - a framework for e2e performance tests",
"main": "index.js",
"typings": "index.d.ts",
"dependencies": {
"@angular/core": "^2.0.0-rc.7",
"reflect-metadata": "^0.1.2",
"rxjs": "5.0.0-beta.12",
"jpm": "1.1.4",
"firefox-profile": "0.4.0",
"selenium-webdriver": "^2.53.3"
},
"repository": {
"type": "git",
"url": "https://github.com/angular/angular.git"
},
"keywords": [
"angular",
"benchmarks"
],
"contributors": [
"Tobias Bosch <tbosch@google.com> (https://angular.io/)"
],
"license": "MIT",
"bugs": {
"url": "https://github.com/angular/angular/issues"
},
"homepage": "https://github.com/angular/angular/tree/master/modules/@angular/compiler-cli"
}

View File

@ -0,0 +1,16 @@
#!/usr/bin/env bash
set -ex
cd $(dirname $0)/../../..
ROOTDIR=$(pwd)
SRCDIR=${ROOTDIR}/modules/@angular/benchpress
DESTDIR=${ROOTDIR}/dist/packages-dist/benchpress
rm -fr ${DESTDIR}
echo "====== BUILDING... ====="
./build.sh --packages=core,benchpress --bundle=false
echo "====== PUBLISHING: ${DESTDIR} ====="
npm publish ${DESTDIR} --access public

View File

@ -0,0 +1,55 @@
/**
* @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 {OpaqueToken} from '@angular/core';
import * as fs from 'fs';
import {DateWrapper} from './facade/lang';
export class Options {
static SAMPLE_ID = new OpaqueToken('Options.sampleId');
static DEFAULT_DESCRIPTION = new OpaqueToken('Options.defaultDescription');
static SAMPLE_DESCRIPTION = new OpaqueToken('Options.sampleDescription');
static FORCE_GC = new OpaqueToken('Options.forceGc');
static NO_PREPARE = () => true;
static PREPARE = new OpaqueToken('Options.prepare');
static EXECUTE = new OpaqueToken('Options.execute');
static CAPABILITIES = new OpaqueToken('Options.capabilities');
static USER_AGENT = new OpaqueToken('Options.userAgent');
static MICRO_METRICS = new OpaqueToken('Options.microMetrics');
static USER_METRICS = new OpaqueToken('Options.userMetrics');
static NOW = new OpaqueToken('Options.now');
static WRITE_FILE = new OpaqueToken('Options.writeFile');
static RECEIVED_DATA = new OpaqueToken('Options.receivedData');
static REQUEST_COUNT = new OpaqueToken('Options.requestCount');
static CAPTURE_FRAMES = new OpaqueToken('Options.frameCapture');
static DEFAULT_PROVIDERS = [
{provide: Options.DEFAULT_DESCRIPTION, useValue: {}},
{provide: Options.SAMPLE_DESCRIPTION, useValue: {}},
{provide: Options.FORCE_GC, useValue: false},
{provide: Options.PREPARE, useValue: Options.NO_PREPARE},
{provide: Options.MICRO_METRICS, useValue: {}}, {provide: Options.USER_METRICS, useValue: {}},
{provide: Options.NOW, useValue: () => DateWrapper.now()},
{provide: Options.RECEIVED_DATA, useValue: false},
{provide: Options.REQUEST_COUNT, useValue: false},
{provide: Options.CAPTURE_FRAMES, useValue: false},
{provide: Options.WRITE_FILE, useValue: writeFile}
];
}
function writeFile(filename: string, content: string): Promise<any> {
return new Promise(function(resolve, reject) {
fs.writeFile(filename, content, (error) => {
if (error) {
reject(error);
} else {
resolve();
}
});
});
}

View File

@ -6,8 +6,8 @@
* found in the LICENSE file at https://angular.io/license
*/
declare var exportFunction;
declare var unsafeWindow;
declare var exportFunction: any;
declare var unsafeWindow: any;
exportFunction(function() {
var curTime = unsafeWindow.performance.now();
@ -18,7 +18,7 @@ exportFunction(function() {
(<any>self).port.emit('stopProfiler');
}, unsafeWindow, {defineAs: 'stopProfiler'});
exportFunction(function(cb) {
exportFunction(function(cb: Function) {
(<any>self).port.once('perfProfile', cb);
(<any>self).port.emit('getProfile');
}, unsafeWindow, {defineAs: 'getProfile'});
@ -27,12 +27,12 @@ exportFunction(function() {
(<any>self).port.emit('forceGC');
}, unsafeWindow, {defineAs: 'forceGC'});
exportFunction(function(name) {
exportFunction(function(name: string) {
var curTime = unsafeWindow.performance.now();
(<any>self).port.emit('markStart', name, curTime);
}, unsafeWindow, {defineAs: 'markStart'});
exportFunction(function(name) {
exportFunction(function(name: string) {
var curTime = unsafeWindow.performance.now();
(<any>self).port.emit('markEnd', name, curTime);
}, unsafeWindow, {defineAs: 'markEnd'});

View File

@ -11,13 +11,13 @@ var os = Cc['@mozilla.org/observer-service;1'].getService(Ci.nsIObserverService)
var ParserUtil = require('./parser_util');
class Profiler {
private _profiler;
private _profiler: any;
private _markerEvents: any[];
private _profilerStartTime: number;
constructor() { this._profiler = Cc['@mozilla.org/tools/profiler;1'].getService(Ci.nsIProfiler); }
start(entries, interval, features, timeStarted) {
start(entries: any, interval: any, features: any, timeStarted: any) {
this._profiler.StartProfiler(entries, interval, features, features.length);
this._profilerStartTime = timeStarted;
this._markerEvents = [];
@ -29,7 +29,9 @@ class Profiler {
var profileData = this._profiler.getProfileData();
var perfEvents = ParserUtil.convertPerfProfileToEvents(profileData);
perfEvents = this._mergeMarkerEvents(perfEvents);
perfEvents.sort(function(event1, event2) { return event1.ts - event2.ts; }); // Sort by ts
perfEvents.sort(function(event1: any, event2: any) {
return event1.ts - event2.ts;
}); // Sort by ts
return perfEvents;
}
@ -40,11 +42,11 @@ class Profiler {
}
addStartEvent(name: string, timeStarted: number) {
this._markerEvents.push({ph: 'b', ts: timeStarted - this._profilerStartTime, name: name});
this._markerEvents.push({ph: 'B', ts: timeStarted - this._profilerStartTime, name: name});
}
addEndEvent(name: string, timeEnded: number) {
this._markerEvents.push({ph: 'e', ts: timeEnded - this._profilerStartTime, name: name});
this._markerEvents.push({ph: 'E', ts: timeEnded - this._profilerStartTime, name: name});
}
}
@ -59,16 +61,18 @@ var profiler = new Profiler();
mod.PageMod({
include: ['*'],
contentScriptFile: data.url('installed_script.js'),
onAttach: worker => {
onAttach: (worker: any) => {
worker.port.on(
'startProfiler',
(timeStarted) => profiler.start(
(timeStarted: any) => profiler.start(
/* = profiler memory */ 3000000, 0.1, ['leaf', 'js', 'stackwalk', 'gc'], timeStarted));
worker.port.on('stopProfiler', () => profiler.stop());
worker.port.on(
'getProfile', () => worker.port.emit('perfProfile', profiler.getProfilePerfEvents()));
worker.port.on('forceGC', forceGC);
worker.port.on('markStart', (name, timeStarted) => profiler.addStartEvent(name, timeStarted));
worker.port.on('markEnd', (name, timeEnded) => profiler.addEndEvent(name, timeEnded));
worker.port.on(
'markStart', (name: string, timeStarted: any) => profiler.addStartEvent(name, timeStarted));
worker.port.on(
'markEnd', (name: string, timeEnded: any) => profiler.addEndEvent(name, timeEnded));
}
});

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 = []; // Event[] finished events
var addFinishedEvent = function(eventName, startTime, endTime) {
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 = undefined;
var args: {[key: string]: any} = undefined;
if (categorizedEventName == 'gc') {
// TODO: We cannot measure heap size at the moment
args = {usedHeapSize: 0};
@ -42,7 +42,9 @@ export function convertPerfProfileToEvents(perfProfile: any): any[] {
// Add all the frames into a set so it's easier/faster to find the set
// differences
var sampleFrames = new Set();
sample.frames.forEach(function(frame) { sampleFrames.add(frame.location); });
sample.frames.forEach(function(frame: {[key: string]: any}) {
sampleFrames.add(frame['location']);
});
// 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
@ -73,7 +75,7 @@ export function convertPerfProfileToEvents(perfProfile: any): any[] {
});
// Remove all the unknown categories.
return finishedEvents.filter(function(event) { return event.name != 'unknown'; });
return finishedEvents.filter(function(event) { return event['name'] != 'unknown'; });
}
// TODO: this is most likely not exhaustive.

View File

@ -13,7 +13,7 @@ var pathUtil = require('path');
var PERF_ADDON_PACKAGE_JSON_DIR = '..';
exports.getAbsolutePath = function(path) {
exports.getAbsolutePath = function(path: string) {
var normalizedPath = pathUtil.normalize(path);
if (pathUtil.resolve(normalizedPath) == normalizedPath) {
// Already absolute path
@ -23,12 +23,12 @@ exports.getAbsolutePath = function(path) {
}
};
exports.getFirefoxProfile = function(extensionPath) {
exports.getFirefoxProfile = function(extensionPath: string) {
var deferred = q.defer();
var firefoxProfile = new FirefoxProfile();
firefoxProfile.addExtensions([extensionPath], () => {
firefoxProfile.encoded(encodedProfile => {
firefoxProfile.encoded((encodedProfile: any) => {
var multiCapabilities = [{browserName: 'firefox', firefox_profile: encodedProfile}];
deferred.resolve(multiCapabilities);
});
@ -44,7 +44,7 @@ exports.getFirefoxProfileWithExtension = function() {
var savedCwd = process.cwd();
process.chdir(absPackageJsonDir);
return jpm(packageJson).then(xpiPath => {
return jpm(packageJson).then((xpiPath: string) => {
process.chdir(savedCwd);
return exports.getFirefoxProfile(xpiPath);
});

View File

@ -6,18 +6,15 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Map} from '@angular/facade/src/collection';
import {Date, DateWrapper} from '@angular/facade/src/lang';
export class MeasureValues {
constructor(
public runIndex: number, public timeStamp: Date, public values: {[key: string]: any}) {}
toJson() {
return {
'timeStamp': DateWrapper.toJson(this.timeStamp),
'timeStamp': this.timeStamp.toJSON(),
'runIndex': this.runIndex,
'values': this.values
'values': this.values,
};
}
}

View File

@ -6,31 +6,26 @@
* found in the LICENSE file at https://angular.io/license
*/
import {BaseException, WrappedException} from '@angular/facade/src/exceptions';
/**
* A metric is measures values
*/
export abstract class Metric {
static bindTo(delegateToken): any[] {
return [{provide: Metric, useFactory: (delegate) => delegate, deps: [delegateToken]}];
}
/**
* Starts measuring
*/
beginMeasure(): Promise<any> { throw new BaseException('NYI'); }
beginMeasure(): Promise<any> { throw new Error('NYI'); }
/**
* Ends measuring and reports the data
* since the begin call.
* @param restart: Whether to restart right after this.
*/
endMeasure(restart: boolean): Promise<{[key: string]: any}> { throw new BaseException('NYI'); }
endMeasure(restart: boolean): Promise<{[key: string]: any}> { throw new Error('NYI'); }
/**
* Describes the metrics provided by this metric implementation.
* (e.g. units, ...)
*/
describe(): {[key: string]: any} { throw new BaseException('NYI'); }
describe(): {[key: string]: string} { throw new Error('NYI'); }
}

View File

@ -6,20 +6,24 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Injector, OpaqueToken} from '@angular/core/src/di';
import {StringMapWrapper} from '@angular/facade/src/collection';
import {Injector, OpaqueToken} from '@angular/core';
import {StringMapWrapper} from '../facade/collection';
import {Metric} from '../metric';
export class MultiMetric extends Metric {
static createBindings(childTokens: any[]): any[] {
static provideWith(childTokens: any[]): any[] {
return [
{
provide: _CHILDREN,
useFactory: (injector: Injector) => childTokens.map(token => injector.get(token)),
deps: [Injector]
},
{provide: MultiMetric, useFactory: children => new MultiMetric(children), deps: [_CHILDREN]}
{
provide: MultiMetric,
useFactory: (children: Metric[]) => new MultiMetric(children),
deps: [_CHILDREN]
}
];
}
@ -52,7 +56,7 @@ export class MultiMetric extends Metric {
}
function mergeStringMaps(maps: {[key: string]: string}[]): {[key: string]: string} {
var result = {};
var result: {[key: string]: string} = {};
maps.forEach(
map => { StringMapWrapper.forEach(map, (value, prop) => { result[prop] = value; }); });
return result;

View File

@ -0,0 +1,371 @@
/**
* @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 {Inject, Injectable, OpaqueToken} from '@angular/core';
import {Options} from '../common_options';
import {Metric} from '../metric';
import {PerfLogEvent, PerfLogFeatures, WebDriverExtension} from '../web_driver_extension';
/**
* A metric that reads out the performance log
*/
@Injectable()
export class PerflogMetric extends Metric {
static SET_TIMEOUT = new OpaqueToken('PerflogMetric.setTimeout');
static PROVIDERS = [
PerflogMetric, {
provide: PerflogMetric.SET_TIMEOUT,
useValue: (fn: Function, millis: number) => <any>setTimeout(fn, millis)
}
];
private _remainingEvents: PerfLogEvent[];
private _measureCount: number;
private _perfLogFeatures: PerfLogFeatures;
/**
* @param driverExtension
* @param setTimeout
* @param microMetrics Name and description of metrics provided via console.time / console.timeEnd
**/
constructor(
private _driverExtension: WebDriverExtension,
@Inject(PerflogMetric.SET_TIMEOUT) private _setTimeout: Function,
@Inject(Options.MICRO_METRICS) private _microMetrics: {[key: string]: string},
@Inject(Options.FORCE_GC) private _forceGc: boolean,
@Inject(Options.CAPTURE_FRAMES) private _captureFrames: boolean,
@Inject(Options.RECEIVED_DATA) private _receivedData: boolean,
@Inject(Options.REQUEST_COUNT) private _requestCount: boolean) {
super();
this._remainingEvents = [];
this._measureCount = 0;
this._perfLogFeatures = _driverExtension.perfLogFeatures();
if (!this._perfLogFeatures.userTiming) {
// User timing is needed for navigationStart.
this._receivedData = false;
this._requestCount = false;
}
}
describe(): {[key: string]: string} {
var res: {[key: string]: any} = {
'scriptTime': 'script execution time in ms, including gc and render',
'pureScriptTime': 'script execution time in ms, without gc nor render'
};
if (this._perfLogFeatures.render) {
res['renderTime'] = 'render time in ms';
}
if (this._perfLogFeatures.gc) {
res['gcTime'] = 'gc time in ms';
res['gcAmount'] = 'gc amount in kbytes';
res['majorGcTime'] = 'time of major gcs in ms';
if (this._forceGc) {
res['forcedGcTime'] = 'forced gc time in ms';
res['forcedGcAmount'] = 'forced gc amount in kbytes';
}
}
if (this._receivedData) {
res['receivedData'] = 'encoded bytes received since navigationStart';
}
if (this._requestCount) {
res['requestCount'] = 'count of requests sent since navigationStart';
}
if (this._captureFrames) {
if (!this._perfLogFeatures.frameCapture) {
var warningMsg = 'WARNING: Metric requested, but not supported by driver';
// using dot syntax for metric name to keep them grouped together in console reporter
res['frameTime.mean'] = warningMsg;
res['frameTime.worst'] = warningMsg;
res['frameTime.best'] = warningMsg;
res['frameTime.smooth'] = warningMsg;
} else {
res['frameTime.mean'] = 'mean frame time in ms (target: 16.6ms for 60fps)';
res['frameTime.worst'] = 'worst frame time in ms';
res['frameTime.best'] = 'best frame time in ms';
res['frameTime.smooth'] = 'percentage of frames that hit 60fps';
}
}
for (let name in this._microMetrics) {
res[name] = this._microMetrics[name];
}
return res;
}
beginMeasure(): Promise<any> {
var resultPromise = Promise.resolve(null);
if (this._forceGc) {
resultPromise = resultPromise.then((_) => this._driverExtension.gc());
}
return resultPromise.then((_) => this._beginMeasure());
}
endMeasure(restart: boolean): Promise<{[key: string]: number}> {
if (this._forceGc) {
return this._endPlainMeasureAndMeasureForceGc(restart);
} else {
return this._endMeasure(restart);
}
}
/** @internal */
private _endPlainMeasureAndMeasureForceGc(restartMeasure: boolean) {
return this._endMeasure(true).then((measureValues) => {
// disable frame capture for measurements during forced gc
var originalFrameCaptureValue = this._captureFrames;
this._captureFrames = false;
return this._driverExtension.gc()
.then((_) => this._endMeasure(restartMeasure))
.then((forceGcMeasureValues) => {
this._captureFrames = originalFrameCaptureValue;
measureValues['forcedGcTime'] = forceGcMeasureValues['gcTime'];
measureValues['forcedGcAmount'] = forceGcMeasureValues['gcAmount'];
return measureValues;
});
});
}
private _beginMeasure(): Promise<any> {
return this._driverExtension.timeBegin(this._markName(this._measureCount++));
}
private _endMeasure(restart: boolean): Promise<{[key: string]: number}> {
var markName = this._markName(this._measureCount - 1);
var nextMarkName = restart ? this._markName(this._measureCount++) : null;
return this._driverExtension.timeEnd(markName, nextMarkName)
.then((_) => this._readUntilEndMark(markName));
}
private _readUntilEndMark(
markName: string, loopCount: number = 0, startEvent: PerfLogEvent = null) {
if (loopCount > _MAX_RETRY_COUNT) {
throw new Error(`Tried too often to get the ending mark: ${loopCount}`);
}
return this._driverExtension.readPerfLog().then((events) => {
this._addEvents(events);
var 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; });
this._setTimeout(() => resolve(this._readUntilEndMark(markName, loopCount + 1)), 100);
return promise;
});
}
private _addEvents(events: PerfLogEvent[]) {
var needSort = false;
events.forEach(event => {
if (event['ph'] === 'X') {
needSort = true;
var startEvent: PerfLogEvent = {};
var endEvent: PerfLogEvent = {};
for (let prop in event) {
startEvent[prop] = event[prop];
endEvent[prop] = event[prop];
}
startEvent['ph'] = 'B';
endEvent['ph'] = 'E';
endEvent['ts'] = startEvent['ts'] + startEvent['dur'];
this._remainingEvents.push(startEvent);
this._remainingEvents.push(endEvent);
} else {
this._remainingEvents.push(event);
}
});
if (needSort) {
// Need to sort because of the ph==='X' events
this._remainingEvents.sort((a, b) => {
var 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};
if (this._perfLogFeatures.gc) {
result['gcTime'] = 0;
result['majorGcTime'] = 0;
result['gcAmount'] = 0;
}
if (this._perfLogFeatures.render) {
result['renderTime'] = 0;
}
if (this._captureFrames) {
result['frameTime.mean'] = 0;
result['frameTime.best'] = 0;
result['frameTime.worst'] = 0;
result['frameTime.smooth'] = 0;
}
for (let name in this._microMetrics) {
result[name] = 0;
}
if (this._receivedData) {
result['receivedData'] = 0;
}
if (this._requestCount) {
result['requestCount'] = 0;
}
var markStartEvent: PerfLogEvent = null;
var markEndEvent: PerfLogEvent = null;
events.forEach((event) => {
var ph = event['ph'];
var name = event['name'];
if (ph === 'B' && name === markName) {
markStartEvent = event;
} else if (ph === 'I' && name === 'navigationStart') {
// if a benchmark measures reload of a page, use the last
// navigationStart as begin event
markStartEvent = event;
} else if (ph === 'E' && name === markName) {
markEndEvent = event;
}
});
if (!markStartEvent || !markEndEvent) {
// not all events have been received, no further processing for now
return null;
}
var gcTimeInScript = 0;
var renderTimeInScript = 0;
var frameTimestamps: number[] = [];
var frameTimes: number[] = [];
var frameCaptureStartEvent: PerfLogEvent = null;
var frameCaptureEndEvent: PerfLogEvent = null;
var intervalStarts: {[key: string]: PerfLogEvent} = {};
var intervalStartCount: {[key: string]: number} = {};
var inMeasureRange = false;
events.forEach((event) => {
var ph = event['ph'];
var name = event['name'];
var microIterations = 1;
var microIterationsMatch = name.match(_MICRO_ITERATIONS_REGEX);
if (microIterationsMatch) {
name = microIterationsMatch[1];
microIterations = parseInt(microIterationsMatch[2], 10);
}
if (event === markStartEvent) {
inMeasureRange = true;
} else if (event === markEndEvent) {
inMeasureRange = false;
}
if (!inMeasureRange || event['pid'] !== markStartEvent['pid']) {
return;
}
if (this._requestCount && name === 'sendRequest') {
result['requestCount'] += 1;
} else if (this._receivedData && name === 'receivedData' && ph === 'I') {
result['receivedData'] += event['args']['encodedDataLength'];
}
if (ph === 'B' && name === _MARK_NAME_FRAME_CAPUTRE) {
if (frameCaptureStartEvent) {
throw new Error('can capture frames only once per benchmark run');
}
if (!this._captureFrames) {
throw new Error(
'found start event for frame capture, but frame capture was not requested in benchpress');
}
frameCaptureStartEvent = event;
} else if (ph === 'E' && name === _MARK_NAME_FRAME_CAPUTRE) {
if (!frameCaptureStartEvent) {
throw new Error('missing start event for frame capture');
}
frameCaptureEndEvent = event;
}
if (ph === 'I' && frameCaptureStartEvent && !frameCaptureEndEvent && name === 'frame') {
frameTimestamps.push(event['ts']);
if (frameTimestamps.length >= 2) {
frameTimes.push(
frameTimestamps[frameTimestamps.length - 1] -
frameTimestamps[frameTimestamps.length - 2]);
}
}
if (ph === 'B') {
if (!intervalStarts[name]) {
intervalStartCount[name] = 1;
intervalStarts[name] = event;
} else {
intervalStartCount[name]++;
}
} else if ((ph === 'E') && intervalStarts[name]) {
intervalStartCount[name]--;
if (intervalStartCount[name] === 0) {
var startEvent = intervalStarts[name];
var duration = (event['ts'] - startEvent['ts']);
intervalStarts[name] = null;
if (name === 'gc') {
result['gcTime'] += duration;
var amount =
(startEvent['args']['usedHeapSize'] - event['args']['usedHeapSize']) / 1000;
result['gcAmount'] += amount;
var majorGc = event['args']['majorGc'];
if (majorGc && majorGc) {
result['majorGcTime'] += duration;
}
if (intervalStarts['script']) {
gcTimeInScript += duration;
}
} else if (name === 'render') {
result['renderTime'] += duration;
if (intervalStarts['script']) {
renderTimeInScript += duration;
}
} else if (name === 'script') {
result['scriptTime'] += duration;
} else if (this._microMetrics[name]) {
(<any>result)[name] += duration / microIterations;
}
}
}
});
if (frameCaptureStartEvent && !frameCaptureEndEvent) {
throw new Error('missing end event for frame capture');
}
if (this._captureFrames && !frameCaptureStartEvent) {
throw new Error('frame capture requested in benchpress, but no start event was found');
}
if (frameTimes.length > 0) {
this._addFrameMetrics(result, frameTimes);
}
result['pureScriptTime'] = result['scriptTime'] - gcTimeInScript - renderTimeInScript;
return result;
}
private _addFrameMetrics(result: {[key: string]: number}, frameTimes: any[]) {
result['frameTime.mean'] = frameTimes.reduce((a, b) => a + b, 0) / frameTimes.length;
var firstFrame = frameTimes[0];
result['frameTime.worst'] = frameTimes.reduce((a, b) => a > b ? a : b, firstFrame);
result['frameTime.best'] = frameTimes.reduce((a, b) => a < b ? a : b, firstFrame);
result['frameTime.smooth'] =
frameTimes.filter(t => t < _FRAME_TIME_SMOOTH_THRESHOLD).length / frameTimes.length;
}
private _markName(index: number) { return `${_MARK_NAME_PREFIX}${index}`; }
}
var _MICRO_ITERATIONS_REGEX = /(.+)\*(\d+)$/;
var _MAX_RETRY_COUNT = 20;
var _MARK_NAME_PREFIX = 'benchpress';
var _MARK_NAME_FRAME_CAPUTRE = 'frameCapture';
// using 17ms as a somewhat looser threshold, instead of 16.6666ms
var _FRAME_TIME_SMOOTH_THRESHOLD = 17;

View File

@ -6,19 +6,21 @@
* found in the LICENSE file at https://angular.io/license
*/
import {OpaqueToken, Provider, bind} from '@angular/core';
import {StringMapWrapper} from '@angular/facade/src/collection';
import {isNumber} from '@angular/facade/src/lang';
import {Inject, Injectable} from '@angular/core';
import {Options} from '../common_options';
import {StringMapWrapper} from '../facade/collection';
import {isNumber} from '../facade/lang';
import {Metric} from '../metric';
import {WebDriverAdapter} from '../web_driver_adapter';
@Injectable()
export class UserMetric extends Metric {
// TODO(tbosch): use static values when our transpiler supports them
static get PROVIDERS(): Provider[] { return _PROVIDERS; }
static PROVIDERS = [UserMetric];
constructor(private _userMetrics: {[key: string]: string}, private _wdAdapter: WebDriverAdapter) {
constructor(
@Inject(Options.USER_METRICS) private _userMetrics: {[key: string]: string},
private _wdAdapter: WebDriverAdapter) {
super();
}
@ -46,9 +48,9 @@ export class UserMetric extends Metric {
if (values.every(isNumber)) {
Promise.all(names.map(name => adapter.executeScript(`delete window.${name}`)))
.then((_: any[]) => {
let map = StringMapWrapper.create();
let map: {[k: string]: any} = {};
for (let i = 0, n = names.length; i < n; i++) {
StringMapWrapper.set(map, names[i], values[i]);
map[names[i]] = values[i];
}
resolve(map);
}, reject);
@ -67,8 +69,3 @@ export class UserMetric extends Metric {
*/
describe(): {[key: string]: any} { return this._userMetrics; }
}
var _PROVIDERS = [bind(UserMetric)
.toFactory(
(userMetrics, wdAdapter) => new UserMetric(userMetrics, wdAdapter),
[Options.USER_METRICS, WebDriverAdapter])];

View File

@ -6,20 +6,15 @@
* found in the LICENSE file at https://angular.io/license
*/
import {BaseException, WrappedException} from '@angular/facade/src/exceptions';
import {MeasureValues} from './measure_values';
/**
* A reporter reports measure values and the valid sample.
*/
export abstract class Reporter {
static bindTo(delegateToken): any[] {
return [{provide: Reporter, useFactory: (delegate) => delegate, deps: [delegateToken]}];
}
reportMeasureValues(values: MeasureValues): Promise<any> { throw new BaseException('NYI'); }
reportMeasureValues(values: MeasureValues): Promise<any> { throw new Error('NYI'); }
reportSample(completeSample: MeasureValues[], validSample: MeasureValues[]): Promise<any> {
throw new BaseException('NYI');
throw new Error('NYI');
}
}

View File

@ -0,0 +1,86 @@
/**
* @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 {Inject, Injectable, OpaqueToken} from '@angular/core';
import {ListWrapper, StringMapWrapper} from '../facade/collection';
import {NumberWrapper, isBlank, isPresent, print} from '../facade/lang';
import {Math} from '../facade/math';
import {MeasureValues} from '../measure_values';
import {Reporter} from '../reporter';
import {SampleDescription} from '../sample_description';
import {formatNum, formatStats, sortedProps} from './util';
/**
* A reporter for the console
*/
@Injectable()
export class ConsoleReporter extends Reporter {
static PRINT = new OpaqueToken('ConsoleReporter.print');
static COLUMN_WIDTH = new OpaqueToken('ConsoleReporter.columnWidth');
static PROVIDERS = [
ConsoleReporter, {provide: ConsoleReporter.COLUMN_WIDTH, useValue: 18},
{provide: ConsoleReporter.PRINT, useValue: print}
];
private static _lpad(value: string, columnWidth: number, fill = ' ') {
var result = '';
for (var i = 0; i < columnWidth - value.length; i++) {
result += fill;
}
return result + value;
}
private _metricNames: string[];
constructor(
@Inject(ConsoleReporter.COLUMN_WIDTH) private _columnWidth: number,
sampleDescription: SampleDescription,
@Inject(ConsoleReporter.PRINT) private _print: Function) {
super();
this._metricNames = sortedProps(sampleDescription.metrics);
this._printDescription(sampleDescription);
}
private _printDescription(sampleDescription: SampleDescription) {
this._print(`BENCHMARK ${sampleDescription.id}`);
this._print('Description:');
var props = sortedProps(sampleDescription.description);
props.forEach((prop) => { this._print(`- ${prop}: ${sampleDescription.description[prop]}`); });
this._print('Metrics:');
this._metricNames.forEach((metricName) => {
this._print(`- ${metricName}: ${sampleDescription.metrics[metricName]}`);
});
this._print('');
this._printStringRow(this._metricNames);
this._printStringRow(this._metricNames.map((_) => ''), '-');
}
reportMeasureValues(measureValues: MeasureValues): Promise<any> {
var formattedValues = this._metricNames.map(metricName => {
var value = measureValues.values[metricName];
return formatNum(value);
});
this._printStringRow(formattedValues);
return Promise.resolve(null);
}
reportSample(completeSample: MeasureValues[], validSamples: MeasureValues[]): Promise<any> {
this._printStringRow(this._metricNames.map((_) => ''), '=');
this._printStringRow(
this._metricNames.map(metricName => formatStats(validSamples, metricName)));
return Promise.resolve(null);
}
private _printStringRow(parts: any[], fill = ' ') {
this._print(
parts.map(part => ConsoleReporter._lpad(part, this._columnWidth, fill)).join(' | '));
}
}

View File

@ -0,0 +1,52 @@
/**
* @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 {Inject, Injectable, OpaqueToken} from '@angular/core';
import {Options} from '../common_options';
import {DateWrapper, Json, isBlank, isPresent} from '../facade/lang';
import {MeasureValues} from '../measure_values';
import {Reporter} from '../reporter';
import {SampleDescription} from '../sample_description';
import {formatStats, sortedProps} from './util';
/**
* A reporter that writes results into a json file.
*/
@Injectable()
export class JsonFileReporter extends Reporter {
static PATH = new OpaqueToken('JsonFileReporter.path');
static PROVIDERS = [JsonFileReporter, {provide: JsonFileReporter.PATH, useValue: '.'}];
constructor(
private _description: SampleDescription, @Inject(JsonFileReporter.PATH) private _path: string,
@Inject(Options.WRITE_FILE) private _writeFile: Function,
@Inject(Options.NOW) private _now: Function) {
super();
}
reportMeasureValues(measureValues: MeasureValues): Promise<any> { return Promise.resolve(null); }
reportSample(completeSample: MeasureValues[], validSample: MeasureValues[]): Promise<any> {
const stats: {[key: string]: string} = {};
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}_${DateWrapper.toMillis(this._now())}.json`;
return this._writeFile(filePath, content);
}
}

View File

@ -6,13 +6,13 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Injector, OpaqueToken} from '@angular/core/src/di';
import {Injector, OpaqueToken} from '@angular/core';
import {MeasureValues} from '../measure_values';
import {Reporter} from '../reporter';
export class MultiReporter extends Reporter {
static createBindings(childTokens: any[]): any[] {
static provideWith(childTokens: any[]): any[] {
return [
{
provide: _CHILDREN,
@ -21,19 +21,13 @@ export class MultiReporter extends Reporter {
},
{
provide: MultiReporter,
useFactory: children => new MultiReporter(children),
useFactory: (children: Reporter[]) => new MultiReporter(children),
deps: [_CHILDREN]
}
];
}
/** @internal */
private _reporters: Reporter[];
constructor(reporters) {
super();
this._reporters = reporters;
}
constructor(private _reporters: Reporter[]) { super(); }
reportMeasureValues(values: MeasureValues): Promise<any[]> {
return Promise.all(this._reporters.map(reporter => reporter.reportMeasureValues(values)));

View File

@ -0,0 +1,33 @@
/**
* @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 {StringMapWrapper} from '../facade/collection';
import {NumberWrapper} from '../facade/lang';
import {MeasureValues} from '../measure_values';
import {Statistic} from '../statistic';
export function formatNum(n: number) {
return NumberWrapper.toFixed(n, 2);
}
export function sortedProps(obj: {[key: string]: any}) {
var props: string[] = [];
StringMapWrapper.forEach(obj, (value, prop) => props.push(prop));
props.sort();
return props;
}
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);
// Note: Don't use the unicode character for +- as it might cause
// hickups for consoles...
return NumberWrapper.isNaN(cv) ? formattedMean : `${formattedMean}+-${Math.floor(cv)}%`;
}

View File

@ -6,10 +6,10 @@
* found in the LICENSE file at https://angular.io/license
*/
import {ReflectiveInjector} from '@angular/core';
import {isBlank, isPresent} from '@angular/facade/src/lang';
import {Provider, ReflectiveInjector} from '@angular/core';
import {Options} from './common_options';
import {isBlank, isPresent} from './facade/lang';
import {Metric} from './metric';
import {MultiMetric} from './metric/multi_metric';
import {PerflogMetric} from './metric/perflog_metric';
@ -29,28 +29,23 @@ import {FirefoxDriverExtension} from './webdriver/firefox_driver_extension';
import {IOsDriverExtension} from './webdriver/ios_driver_extension';
/**
* The Runner is the main entry point for executing a sample run.
* It provides defaults, creates the injector and calls the sampler.
*/
export class Runner {
private _defaultProviders: any[];
constructor(defaultProviders: any[] = null) {
if (isBlank(defaultProviders)) {
defaultProviders = [];
}
this._defaultProviders = defaultProviders;
}
constructor(private _defaultProviders: Provider[] = []) {}
sample({id, execute, prepare, microMetrics, providers, userMetrics}: {
id: string,
execute?: any,
prepare?: any,
microMetrics?: any,
providers?: any,
userMetrics?: any
execute?: Function,
prepare?: Function,
microMetrics?: {[key: string]: string},
providers?: Provider[],
userMetrics?: {[key: string]: string}
}): Promise<SampleState> {
var sampleProviders = [
var sampleProviders: Provider[] = [
_DEFAULT_PROVIDERS, this._defaultProviders, {provide: Options.SAMPLE_ID, useValue: id},
{provide: Options.EXECUTE, useValue: execute}
];
@ -68,7 +63,7 @@ export class Runner {
}
var inj = ReflectiveInjector.resolveAndCreate(sampleProviders);
var adapter = inj.get(WebDriverAdapter);
var adapter: WebDriverAdapter = inj.get(WebDriverAdapter);
return Promise
.all([adapter.capabilities(), adapter.executeScript('return window.navigator.userAgent;')])
@ -105,10 +100,11 @@ var _DEFAULT_PROVIDERS = [
PerflogMetric.PROVIDERS,
UserMetric.PROVIDERS,
SampleDescription.PROVIDERS,
MultiReporter.createBindings([ConsoleReporter]),
MultiMetric.createBindings([PerflogMetric, UserMetric]),
Reporter.bindTo(MultiReporter),
Validator.bindTo(RegressionSlopeValidator),
WebDriverExtension.bindTo([ChromeDriverExtension, FirefoxDriverExtension, IOsDriverExtension]),
Metric.bindTo(MultiMetric),
MultiReporter.provideWith([ConsoleReporter]),
MultiMetric.provideWith([PerflogMetric, UserMetric]),
{provide: Reporter, useExisting: MultiReporter},
{provide: Validator, useExisting: RegressionSlopeValidator},
WebDriverExtension.provideFirstSupported(
[ChromeDriverExtension, FirefoxDriverExtension, IOsDriverExtension]),
{provide: Metric, useExisting: MultiMetric},
];

View File

@ -6,9 +6,10 @@
* found in the LICENSE file at https://angular.io/license
*/
import {StringMapWrapper} from '@angular/facade/src/collection';
import {OpaqueToken} from '@angular/core';
import {Options} from './common_options';
import {StringMapWrapper} from './facade/collection';
import {Metric} from './metric';
import {Validator} from './validator';
@ -17,8 +18,23 @@ import {Validator} from './validator';
* SampleDescription merges all available descriptions about a sample
*/
export class SampleDescription {
// TODO(tbosch): use static values when our transpiler supports them
static get PROVIDERS(): any[] { return _PROVIDERS; }
static PROVIDERS = [{
provide: SampleDescription,
useFactory:
(metric: Metric, id: string, forceGc: boolean, userAgent: string, validator: Validator,
defaultDesc: {[key: string]: string}, userDesc: {[key: string]: string}) =>
new SampleDescription(
id,
[
{'forceGc': forceGc, 'userAgent': userAgent}, validator.describe(), defaultDesc,
userDesc
],
metric.describe()),
deps: [
Metric, Options.SAMPLE_ID, Options.FORCE_GC, Options.USER_AGENT, Validator,
Options.DEFAULT_DESCRIPTION, Options.SAMPLE_DESCRIPTION
]
}];
description: {[key: string]: any};
constructor(
@ -32,19 +48,3 @@ export class SampleDescription {
toJson() { return {'id': this.id, 'description': this.description, 'metrics': this.metrics}; }
}
var _PROVIDERS = [{
provide: SampleDescription,
useFactory: (metric, id, forceGc, userAgent, validator, defaultDesc, userDesc) =>
new SampleDescription(
id,
[
{'forceGc': forceGc, 'userAgent': userAgent}, validator.describe(),
defaultDesc, userDesc
],
metric.describe()),
deps: [
Metric, Options.SAMPLE_ID, Options.FORCE_GC, Options.USER_AGENT, Validator,
Options.DEFAULT_DESCRIPTION, Options.SAMPLE_DESCRIPTION
]
}];

View File

@ -0,0 +1,81 @@
/**
* @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 {Inject, Injectable, OpaqueToken} from '@angular/core';
import {Options} from './common_options';
import {Date, DateWrapper, isBlank, isPresent} from './facade/lang';
import {MeasureValues} from './measure_values';
import {Metric} from './metric';
import {Reporter} from './reporter';
import {Validator} from './validator';
import {WebDriverAdapter} from './web_driver_adapter';
/**
* The Sampler owns the sample loop:
* 1. calls the prepare/execute callbacks,
* 2. gets data from the metric
* 3. asks the validator for a valid sample
* 4. reports the new data to the reporter
* 5. loop until there is a valid sample
*/
@Injectable()
export class Sampler {
static PROVIDERS = [Sampler];
constructor(
private _driver: WebDriverAdapter, private _metric: Metric, private _reporter: Reporter,
private _validator: Validator, @Inject(Options.PREPARE) private _prepare: Function,
@Inject(Options.EXECUTE) private _execute: Function,
@Inject(Options.NOW) private _now: Function) {}
sample(): Promise<SampleState> {
const loop = (lastState: SampleState): Promise<SampleState> => {
return this._iterate(lastState).then((newState) => {
if (isPresent(newState.validSample)) {
return newState;
} else {
return loop(newState);
}
});
};
return loop(new SampleState([], null));
}
private _iterate(lastState: SampleState): Promise<SampleState> {
var resultPromise: Promise<SampleState>;
if (this._prepare !== Options.NO_PREPARE) {
resultPromise = this._driver.waitFor(this._prepare);
} else {
resultPromise = Promise.resolve(null);
}
if (this._prepare !== Options.NO_PREPARE || lastState.completeSample.length === 0) {
resultPromise = resultPromise.then((_) => this._metric.beginMeasure());
}
return resultPromise.then((_) => this._driver.waitFor(this._execute))
.then((_) => this._metric.endMeasure(this._prepare === Options.NO_PREPARE))
.then((measureValues) => this._report(lastState, measureValues));
}
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);
if (isPresent(validSample)) {
resultPromise =
resultPromise.then((_) => this._reporter.reportSample(completeSample, validSample));
}
return resultPromise.then((_) => new SampleState(completeSample, validSample));
}
}
export class SampleState {
constructor(public completeSample: MeasureValues[], public validSample: MeasureValues[]) {}
}

View File

@ -6,10 +6,10 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Math} from '@angular/facade/src/math';
import {Math} from './facade/math';
export class Statistic {
static calculateCoefficientOfVariation(sample, mean) {
static calculateCoefficientOfVariation(sample: number[], mean: number) {
return Statistic.calculateStandardDeviation(sample, mean) / mean * 100;
}
@ -20,7 +20,7 @@ export class Statistic {
return total / samples.length;
}
static calculateStandardDeviation(samples: number[], mean) {
static calculateStandardDeviation(samples: number[], mean: number) {
var deviation = 0;
// TODO: use reduce
samples.forEach(x => deviation += Math.pow(x - mean, 2));

View File

@ -6,8 +6,6 @@
* found in the LICENSE file at https://angular.io/license
*/
import {BaseException, WrappedException} from '@angular/facade/src/exceptions';
import {MeasureValues} from './measure_values';
/**
@ -16,18 +14,14 @@ import {MeasureValues} from './measure_values';
* in the correct way.
*/
export abstract class Validator {
static bindTo(delegateToken): any[] {
return [{provide: Validator, useFactory: (delegate) => delegate, deps: [delegateToken]}];
}
/**
* Calculates a valid sample out of the complete sample
*/
validate(completeSample: MeasureValues[]): MeasureValues[] { throw new BaseException('NYI'); }
validate(completeSample: MeasureValues[]): MeasureValues[] { throw new Error('NYI'); }
/**
* Returns a Map that describes the properties of the validator
* (e.g. sample size, ...)
*/
describe(): {[key: string]: any} { throw new BaseException('NYI'); }
describe(): {[key: string]: any} { throw new Error('NYI'); }
}

View File

@ -6,35 +6,32 @@
* found in the LICENSE file at https://angular.io/license
*/
import {OpaqueToken} from '@angular/core/src/di';
import {ListWrapper} from '@angular/facade/src/collection';
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.
*/
@Injectable()
export class RegressionSlopeValidator extends Validator {
// TODO(tbosch): use static values when our transpiler supports them
static get SAMPLE_SIZE(): OpaqueToken { return _SAMPLE_SIZE; }
// TODO(tbosch): use static values when our transpiler supports them
static get METRIC(): OpaqueToken { return _METRIC; }
// TODO(tbosch): use static values when our transpiler supports them
static get PROVIDERS(): any[] { return _PROVIDERS; }
static SAMPLE_SIZE = new OpaqueToken('RegressionSlopeValidator.sampleSize');
static METRIC = new OpaqueToken('RegressionSlopeValidator.metric');
static PROVIDERS = [
RegressionSlopeValidator, {provide: RegressionSlopeValidator.SAMPLE_SIZE, useValue: 10},
{provide: RegressionSlopeValidator.METRIC, useValue: 'scriptTime'}
];
/** @internal */
private _sampleSize: number;
/** @internal */
private _metric: string;
constructor(sampleSize, metric) {
constructor(
@Inject(RegressionSlopeValidator.SAMPLE_SIZE) private _sampleSize: number,
@Inject(RegressionSlopeValidator.METRIC) private _metric: string) {
super();
this._sampleSize = sampleSize;
this._metric = metric;
}
describe(): {[key: string]: any} {
@ -45,8 +42,8 @@ export class RegressionSlopeValidator extends Validator {
if (completeSample.length >= this._sampleSize) {
var latestSample = ListWrapper.slice(
completeSample, completeSample.length - this._sampleSize, completeSample.length);
var xValues = [];
var yValues = [];
var xValues: number[] = [];
var yValues: number[] = [];
for (var 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
@ -61,14 +58,3 @@ export class RegressionSlopeValidator extends Validator {
}
}
}
var _SAMPLE_SIZE = new OpaqueToken('RegressionSlopeValidator.sampleSize');
var _METRIC = new OpaqueToken('RegressionSlopeValidator.metric');
var _PROVIDERS = [
{
provide: RegressionSlopeValidator,
useFactory: (sampleSize, metric) => new RegressionSlopeValidator(sampleSize, metric),
deps: [_SAMPLE_SIZE, _METRIC]
},
{provide: _SAMPLE_SIZE, useValue: 10}, {provide: _METRIC, useValue: 'scriptTime'}
];

View File

@ -6,29 +6,23 @@
* found in the LICENSE file at https://angular.io/license
*/
import {OpaqueToken} from '@angular/core/src/di';
import {ListWrapper} from '@angular/facade/src/collection';
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.
*/
@Injectable()
export class SizeValidator extends Validator {
// TODO(tbosch): use static values when our transpiler supports them
static get PROVIDERS(): any[] { return _PROVIDERS; }
// TODO(tbosch): use static values when our transpiler supports them
static get SAMPLE_SIZE() { return _SAMPLE_SIZE; }
static SAMPLE_SIZE = new OpaqueToken('SizeValidator.sampleSize');
static PROVIDERS = [SizeValidator, {provide: SizeValidator.SAMPLE_SIZE, useValue: 10}];
/** @internal */
private _sampleSize: number;
constructor(size) {
super();
this._sampleSize = size;
}
constructor(@Inject(SizeValidator.SAMPLE_SIZE) private _sampleSize: number) { super(); }
describe(): {[key: string]: any} { return {'sampleSize': this._sampleSize}; }
@ -41,9 +35,3 @@ export class SizeValidator extends Validator {
}
}
}
var _SAMPLE_SIZE = new OpaqueToken('SizeValidator.sampleSize');
var _PROVIDERS = [
{provide: SizeValidator, useFactory: (size) => new SizeValidator(size), deps: [_SAMPLE_SIZE]},
{provide: _SAMPLE_SIZE, useValue: 10}
];

View File

@ -0,0 +1,22 @@
/**
* @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
*/
/**
* A WebDriverAdapter bridges API differences between different WebDriver clients,
* e.g. JS vs Dart Async vs Dart Sync webdriver.
* Needs one implementation for every supported WebDriver client.
*/
export abstract class WebDriverAdapter {
waitFor(callback: Function): Promise<any> { throw new Error('NYI'); }
executeScript(script: string): Promise<any> { throw new Error('NYI'); }
executeAsyncScript(script: string): Promise<any> { throw new Error('NYI'); }
capabilities(): Promise<{[key: string]: any}> { throw new Error('NYI'); }
logs(type: string): Promise<any[]> { throw new Error('NYI'); }
}

View File

@ -6,12 +6,27 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Injector, OpaqueToken} from '@angular/core/src/di';
import {BaseException, WrappedException} from '@angular/facade/src/exceptions';
import {isBlank, isPresent} from '@angular/facade/src/lang';
import {Injector, OpaqueToken} from '@angular/core';
import {Options} from './common_options';
import {isBlank, isPresent} from './facade/lang';
export type PerfLogEvent = {
[key: string]: any
} & {
ph?: 'X' | 'B' | 'E' | 'I',
ts?: number,
dur?: number,
name?: string,
pid?: string,
args?: {
encodedDataLength?: number,
usedHeapSize?: number,
majorGc?: boolean,
url?: string,
method?: string
}
};
/**
* A WebDriverExtension implements extended commands of the webdriver protocol
@ -19,7 +34,7 @@ import {Options} from './common_options';
* Needs one implementation for every supported Browser.
*/
export abstract class WebDriverExtension {
static bindTo(childTokens: any[]): any[] {
static provideFirstSupported(childTokens: any[]): any[] {
var res = [
{
provide: _CHILDREN,
@ -28,15 +43,15 @@ export abstract class WebDriverExtension {
},
{
provide: WebDriverExtension,
useFactory: (children: WebDriverExtension[], capabilities) => {
var delegate;
useFactory: (children: WebDriverExtension[], capabilities: {[key: string]: any}) => {
var delegate: WebDriverExtension;
children.forEach(extension => {
if (extension.supports(capabilities)) {
delegate = extension;
}
});
if (isBlank(delegate)) {
throw new BaseException('Could not find a delegate for given capabilities!');
throw new Error('Could not find a delegate for given capabilities!');
}
return delegate;
},
@ -46,18 +61,17 @@ export abstract class WebDriverExtension {
return res;
}
gc(): Promise<any> { throw new BaseException('NYI'); }
gc(): Promise<any> { throw new Error('NYI'); }
timeBegin(name: string): Promise<any> { throw new BaseException('NYI'); }
timeBegin(name: string): Promise<any> { throw new Error('NYI'); }
timeEnd(name: string, restartName: string): Promise<any> { throw new BaseException('NYI'); }
timeEnd(name: string, restartName: string): Promise<any> { throw new Error('NYI'); }
/**
* Format:
* - cat: category of the event
* - name: event name: 'script', 'gc', 'render', ...
* - ph: phase: 'B' (begin), 'E' (end), 'b' (nestable start), 'e' (nestable end), 'X' (Complete
*event)
* - ph: phase: 'B' (begin), 'E' (end), 'X' (Complete event), 'I' (Instant event)
* - ts: timestamp in ms, e.g. 12345
* - pid: process id
* - args: arguments, e.g. {heapSize: 1234}
@ -65,9 +79,9 @@ export abstract class WebDriverExtension {
* Based on [Chrome Trace Event
*Format](https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/edit)
**/
readPerfLog(): Promise<any[]> { throw new BaseException('NYI'); }
readPerfLog(): Promise<PerfLogEvent[]> { throw new Error('NYI'); }
perfLogFeatures(): PerfLogFeatures { throw new BaseException('NYI'); }
perfLogFeatures(): PerfLogFeatures { throw new Error('NYI'); }
supports(capabilities: {[key: string]: any}): boolean { return true; }
}

View File

@ -0,0 +1,208 @@
/**
* @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 {Inject, Injectable} from '@angular/core';
import {Options} from '../common_options';
import {WebDriverAdapter} from '../web_driver_adapter';
import {PerfLogEvent, PerfLogFeatures, WebDriverExtension} from '../web_driver_extension';
/**
* Set the following 'traceCategories' to collect metrics in Chrome:
* 'v8,blink.console,disabled-by-default-devtools.timeline,devtools.timeline,blink.user_timing'
*
* In order to collect the frame rate related metrics, add 'benchmark'
* to the list above.
*/
@Injectable()
export class ChromeDriverExtension extends WebDriverExtension {
static PROVIDERS = [ChromeDriverExtension];
private _majorChromeVersion: number;
constructor(private _driver: WebDriverAdapter, @Inject(Options.USER_AGENT) userAgent: string) {
super();
this._majorChromeVersion = this._parseChromeVersion(userAgent);
}
private _parseChromeVersion(userAgent: string): number {
if (!userAgent) {
return -1;
}
var v = userAgent.split(/Chrom(e|ium)\//g)[2];
if (!v) {
return -1;
}
v = v.split('.')[0];
if (!v) {
return -1;
}
return parseInt(v, 10);
}
gc() { return this._driver.executeScript('window.gc()'); }
timeBegin(name: string): Promise<any> {
return this._driver.executeScript(`console.time('${name}');`);
}
timeEnd(name: string, restartName: string = null): Promise<any> {
var script = `console.timeEnd('${name}');`;
if (restartName) {
script += `console.time('${restartName}');`;
}
return this._driver.executeScript(script);
}
// See [Chrome Trace Event
// Format](https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/edit)
readPerfLog(): Promise<PerfLogEvent[]> {
// TODO(tbosch): Chromedriver bug https://code.google.com/p/chromedriver/issues/detail?id=1098
// Need to execute at least one command so that the browser logs can be read out!
return this._driver.executeScript('1+1')
.then((_) => this._driver.logs('performance'))
.then((entries) => {
var events: PerfLogEvent[] = [];
entries.forEach(entry => {
var message = JSON.parse(entry['message'])['message'];
if (message['method'] === 'Tracing.dataCollected') {
events.push(message['params']);
}
if (message['method'] === 'Tracing.bufferUsage') {
throw new Error('The DevTools trace buffer filled during the test!');
}
});
return this._convertPerfRecordsToEvents(events);
});
}
private _convertPerfRecordsToEvents(
chromeEvents: Array<{[key: string]: any}>, normalizedEvents: PerfLogEvent[] = null) {
if (!normalizedEvents) {
normalizedEvents = [];
}
chromeEvents.forEach((event) => {
const categories = this._parseCategories(event['cat']);
const normalizedEvent = this._convertEvent(event, categories);
if (normalizedEvent != null) normalizedEvents.push(normalizedEvent);
});
return normalizedEvents;
}
private _convertEvent(event: {[key: string]: any}, categories: string[]) {
var name = event['name'];
var args = event['args'];
if (this._isEvent(categories, name, ['blink.console'])) {
return normalizeEvent(event, {'name': name});
} else if (this._isEvent(
categories, name, ['benchmark'],
'BenchmarkInstrumentation::ImplThreadRenderingStats')) {
// TODO(goderbauer): Instead of BenchmarkInstrumentation::ImplThreadRenderingStats the
// following events should be used (if available) for more accurate measurments:
// 1st choice: vsync_before - ground truth on Android
// 2nd choice: BenchmarkInstrumentation::DisplayRenderingStats - available on systems with
// 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'];
if (frameCount > 1) {
throw new Error('multi-frame render stats not supported');
}
if (frameCount == 1) {
return normalizeEvent(event, {'name': 'frame'});
}
} else if (
this._isEvent(categories, name, ['disabled-by-default-devtools.timeline'], 'Rasterize') ||
this._isEvent(
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 = {
'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 = {
'majorGc': false,
'usedHeapSize': args['usedHeapSizeAfter'] !== undefined ? args['usedHeapSizeAfter'] :
args['usedHeapSizeBefore']
};
return normalizeEvent(event, {'name': 'gc', 'args': normArgs});
} else if (
this._isEvent(categories, name, ['devtools.timeline'], 'FunctionCall') &&
(!args || !args['data'] ||
(args['data']['scriptName'] !== 'InjectedScript' && args['data']['scriptName'] !== ''))) {
return normalizeEvent(event, {'name': 'script'});
} else if (this._isEvent(categories, name, ['devtools.timeline'], 'EvaluateScript')) {
return normalizeEvent(event, {'name': 'script'});
} else if (this._isEvent(
categories, name, ['devtools.timeline', 'blink'], 'UpdateLayoutTree')) {
return normalizeEvent(event, {'name': 'render'});
} else if (
this._isEvent(categories, name, ['devtools.timeline'], 'UpdateLayerTree') ||
this._isEvent(categories, name, ['devtools.timeline'], 'Layout') ||
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']};
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']};
return normalizeEvent(event, {'name': 'sendRequest', 'args': normArgs});
} else if (this._isEvent(categories, name, ['blink.user_timing'], 'navigationStart')) {
return normalizeEvent(event, {'name': 'navigationStart'});
}
return null; // nothing useful in this event
}
private _parseCategories(categories: string): string[] { return categories.split(','); }
private _isEvent(
eventCategories: string[], eventName: string, expectedCategories: string[],
expectedName: string = null): boolean {
var hasCategories = expectedCategories.reduce(
(value, cat) => { return value && eventCategories.indexOf(cat) !== -1; }, true);
return !expectedName ? hasCategories : hasCategories && eventName === expectedName;
}
perfLogFeatures(): PerfLogFeatures {
return new PerfLogFeatures({render: true, gc: true, frameCapture: true, userTiming: true});
}
supports(capabilities: {[key: string]: any}): boolean {
return this._majorChromeVersion >= 44 && capabilities['browserName'].toLowerCase() === 'chrome';
}
}
function normalizeEvent(chromeEvent: {[key: string]: any}, data: PerfLogEvent): PerfLogEvent {
var ph = chromeEvent['ph'].toUpperCase();
if (ph === 'S') {
ph = 'B';
} else if (ph === 'F') {
ph = 'E';
} else if (ph === 'R') {
// mark events from navigation timing
ph = 'I';
}
var result: {[key: string]: any} =
{'pid': chromeEvent['pid'], 'ph': ph, 'cat': 'timeline', 'ts': chromeEvent['ts'] / 1000};
if (ph === 'X') {
var dur = chromeEvent['dur'];
if (dur === undefined) {
dur = chromeEvent['tdur'];
}
result['dur'] = !dur ? 0.0 : dur / 1000;
}
for (let prop in data) {
result[prop] = data[prop];
}
return result;
}

View File

@ -6,13 +6,15 @@
* found in the LICENSE file at https://angular.io/license
*/
import {StringWrapper, isPresent} from '@angular/facade/src/lang';
import {Injectable} from '@angular/core';
import {StringWrapper, isPresent} from '../facade/lang';
import {WebDriverAdapter} from '../web_driver_adapter';
import {PerfLogFeatures, WebDriverExtension} from '../web_driver_extension';
import {PerfLogEvent, PerfLogFeatures, WebDriverExtension} from '../web_driver_extension';
@Injectable()
export class FirefoxDriverExtension extends WebDriverExtension {
static get PROVIDERS(): any[] { return _PROVIDERS; }
static PROVIDERS = [FirefoxDriverExtension];
private _profilerStarted: boolean;
@ -39,7 +41,7 @@ export class FirefoxDriverExtension extends WebDriverExtension {
return this._driver.executeScript(script);
}
readPerfLog(): Promise<any> {
readPerfLog(): Promise<PerfLogEvent> {
return this._driver.executeAsyncScript('var cb = arguments[0]; window.getProfile(cb);');
}
@ -49,9 +51,3 @@ export class FirefoxDriverExtension extends WebDriverExtension {
return StringWrapper.equals(capabilities['browserName'].toLowerCase(), 'firefox');
}
}
var _PROVIDERS = [{
provide: FirefoxDriverExtension,
useFactory: (driver) => new FirefoxDriverExtension(driver),
deps: [WebDriverAdapter]
}];

View File

@ -6,19 +6,19 @@
* found in the LICENSE file at https://angular.io/license
*/
import {BaseException, WrappedException} from '@angular/facade/src/exceptions';
import {Json, StringWrapper, isBlank, isPresent} from '@angular/facade/src/lang';
import {Injectable} from '@angular/core';
import {StringWrapper, isBlank, isPresent} from '../facade/lang';
import {WebDriverAdapter} from '../web_driver_adapter';
import {PerfLogFeatures, WebDriverExtension} from '../web_driver_extension';
import {PerfLogEvent, PerfLogFeatures, WebDriverExtension} from '../web_driver_extension';
@Injectable()
export class IOsDriverExtension extends WebDriverExtension {
// TODO(tbosch): use static values when our transpiler supports them
static get PROVIDERS(): any[] { return _PROVIDERS; }
static PROVIDERS = [IOsDriverExtension];
constructor(private _driver: WebDriverAdapter) { super(); }
gc(): Promise<any> { throw new BaseException('Force GC is not supported on iOS'); }
gc(): Promise<any> { throw new Error('Force GC is not supported on iOS'); }
timeBegin(name: string): Promise<any> {
return this._driver.executeScript(`console.time('${name}');`);
@ -39,9 +39,9 @@ export class IOsDriverExtension extends WebDriverExtension {
return this._driver.executeScript('1+1')
.then((_) => this._driver.logs('performance'))
.then((entries) => {
var records = [];
var records: any[] = [];
entries.forEach(entry => {
var message = Json.parse(entry['message'])['message'];
var message = JSON.parse(entry['message'])['message'];
if (StringWrapper.equals(message['method'], 'Timeline.eventRecorded')) {
records.push(message['params']['record']);
}
@ -51,12 +51,12 @@ export class IOsDriverExtension extends WebDriverExtension {
}
/** @internal */
private _convertPerfRecordsToEvents(records: any[], events: any[] = null) {
private _convertPerfRecordsToEvents(records: any[], events: PerfLogEvent[] = null) {
if (isBlank(events)) {
events = [];
}
records.forEach((record) => {
var endEvent = null;
var endEvent: PerfLogEvent = null;
var type = record['type'];
var data = record['data'];
var startTime = record['startTime'];
@ -96,8 +96,9 @@ export class IOsDriverExtension extends WebDriverExtension {
}
}
function createEvent(ph, name, time, args = null) {
var result = {
function createEvent(
ph: 'X' | 'B' | 'E' | 'B' | 'E', name: string, time: number, args: any = null) {
var result: PerfLogEvent = {
'cat': 'timeline',
'name': name,
'ts': time,
@ -112,24 +113,18 @@ function createEvent(ph, name, time, args = null) {
return result;
}
function createStartEvent(name, time, args = null) {
function createStartEvent(name: string, time: number, args: any = null) {
return createEvent('B', name, time, args);
}
function createEndEvent(name, time, args = null) {
function createEndEvent(name: string, time: number, args: any = null) {
return createEvent('E', name, time, args);
}
function createMarkStartEvent(name, time) {
return createEvent('b', name, time);
function createMarkStartEvent(name: string, time: number) {
return createEvent('B', name, time);
}
function createMarkEndEvent(name, time) {
return createEvent('e', name, time);
function createMarkEndEvent(name: string, time: number) {
return createEvent('E', name, time);
}
var _PROVIDERS = [{
provide: IOsDriverExtension,
useFactory: (driver) => new IOsDriverExtension(driver),
deps: [WebDriverAdapter]
}];

View File

@ -0,0 +1,70 @@
/**
* @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 {WebDriverAdapter} from '../web_driver_adapter';
/**
* Adapter for the selenium-webdriver.
*/
export class SeleniumWebDriverAdapter extends WebDriverAdapter {
static PROTRACTOR_PROVIDERS = [{
provide: WebDriverAdapter,
useFactory: () => new SeleniumWebDriverAdapter((<any>global).browser)
}];
constructor(private _driver: any) { super(); }
waitFor(callback: () => any): Promise<any> { return this._driver.call(callback); }
executeScript(script: string): Promise<any> { return this._driver.executeScript(script); }
executeAsyncScript(script: string): Promise<any> {
return this._driver.executeAsyncScript(script);
}
capabilities(): Promise<{[key: string]: any}> {
return this._driver.getCapabilities().then((capsObject: any) => {
const localData: {[key: string]: any} = {};
capsObject.forEach((value: any, key: string) => { localData[key] = value; });
return localData;
});
}
logs(type: string): Promise<any> {
// Needed as selenium-webdriver does not forward
// performance logs in the correct way via manage().logs
return this._driver.schedule(
new Command('getLog').setParameter('type', type),
'WebDriver.manage().logs().get(' + type + ')');
}
}
/**
* Copy of the `Command` class of webdriver as
* it is not exposed via index.js in selenium-webdriver.
*/
class Command {
private parameters_: {[key: string]: any} = {};
constructor(private name_: string) {}
getName() { return this.name_; }
setParameter(name: string, value: any) {
this.parameters_[name] = value;
return this;
}
setParameters(parameters: {[key: string]: any}) {
this.parameters_ = parameters;
return this;
}
getParameter(key: string) { return this.parameters_[key]; }
getParameters() { return this.parameters_; }
}

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
require('es6-shim/es6-shim.js');
require('core-js');
require('reflect-metadata');
var testHelper = require('../../src/firefox_extension/lib/test_helper.js');

View File

@ -6,9 +6,9 @@
* found in the LICENSE file at https://angular.io/license
*/
import {convertPerfProfileToEvents} from 'benchpress/src/firefox_extension/lib/parser_util';
import {convertPerfProfileToEvents} from '../../src/firefox_extension/lib/parser_util';
function assertEventsEqual(actualEvents, expectedEvents) {
function assertEventsEqual(actualEvents: any[], expectedEvents: any[]) {
expect(actualEvents.length == expectedEvents.length);
for (var i = 0; i < actualEvents.length; ++i) {
var actualEvent = actualEvents[i];

View File

@ -9,7 +9,7 @@
var benchpress = require('../../index.js');
var runner = new benchpress.Runner([
// use protractor as Webdriver client
benchpress.SeleniumWebDriverAdapter.PROTRACTOR_BINDINGS,
benchpress.SeleniumWebDriverAdapter.PROTRACTOR_PROVIDERS,
// use RegressionSlopeValidator to validate samples
benchpress.Validator.bindTo(benchpress.RegressionSlopeValidator),
// use 10 samples to calculate slope regression

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
var assertEventsContainsName = function(events, eventName) {
var assertEventsContainsName = function(events: any[], eventName: string) {
var found = false;
for (var i = 0; i < events.length; ++i) {
if (events[i].name == eventName) {
@ -33,7 +33,7 @@ describe('firefox extension', function() {
browser.executeScript('window.forceGC()');
browser.executeAsyncScript('var cb = arguments[0]; window.getProfile(cb);')
.then(function(profile) {
.then(function(profile: any) {
assertEventsContainsName(profile, 'gc');
assertEventsContainsName(profile, 'script');
});

View File

@ -7,28 +7,29 @@
*/
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {Metric, MultiMetric, ReflectiveInjector} from 'benchpress/common';
import {Metric, MultiMetric, ReflectiveInjector} from '../../index';
export function main() {
function createMetric(ids: any[]) {
var m = ReflectiveInjector
.resolveAndCreate([
ids.map(id => { return {provide: id, useValue: new MockMetric(id)}; }),
MultiMetric.createBindings(ids)
MultiMetric.provideWith(ids)
])
.get(MultiMetric);
return Promise.resolve(m);
}
describe('multi metric', () => {
it('should merge descriptions', inject([AsyncTestCompleter], (async) => {
it('should merge descriptions', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createMetric(['m1', 'm2']).then((m) => {
expect(m.describe()).toEqual({'m1': 'describe', 'm2': 'describe'});
async.done();
});
}));
it('should merge all beginMeasure calls', inject([AsyncTestCompleter], (async) => {
it('should merge all beginMeasure calls',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createMetric(['m1', 'm2']).then((m) => m.beginMeasure()).then((values) => {
expect(values).toEqual(['m1_beginMeasure', 'm2_beginMeasure']);
async.done();
@ -37,7 +38,7 @@ export function main() {
[false, true].forEach((restartFlag) => {
it(`should merge all endMeasure calls for restart=${restartFlag}`,
inject([AsyncTestCompleter], (async) => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createMetric(['m1', 'm2']).then((m) => m.endMeasure(restartFlag)).then((values) => {
expect(values).toEqual(
{'m1': {'restart': restartFlag}, 'm2': {'restart': restartFlag}});
@ -50,18 +51,12 @@ export function main() {
}
class MockMetric extends Metric {
/** @internal */
private _id: string;
constructor(id) {
super();
this._id = id;
}
constructor(private _id: string) { super(); }
beginMeasure(): Promise<string> { return Promise.resolve(`${this._id}_beginMeasure`); }
endMeasure(restart: boolean): Promise<{[key: string]: any}> {
var result = {};
var result: {[key: string]: any} = {};
result[this._id] = {'restart': restart};
return Promise.resolve(result);
}

View File

@ -6,11 +6,12 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Provider} from '@angular/core';
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {StringMapWrapper} from '@angular/facade/src/collection';
import {isBlank, isPresent} from '@angular/facade/src/lang';
import {Metric, Options, PerfLogFeatures, PerflogMetric, ReflectiveInjector, WebDriverExtension} from 'benchpress/common';
import {Metric, Options, PerfLogEvent, PerfLogFeatures, PerflogMetric, ReflectiveInjector, WebDriverExtension} from '../../index';
import {StringMapWrapper} from '../../src/facade/collection';
import {isBlank, isPresent} from '../../src/facade/lang';
import {TraceEventFactory} from '../trace_event_factory';
export function main() {
@ -18,7 +19,7 @@ export function main() {
var eventFactory = new TraceEventFactory('timeline', 'pid0');
function createMetric(
perfLogs, perfLogFeatures,
perfLogs: PerfLogEvent[], perfLogFeatures: PerfLogFeatures,
{microMetrics, forceGc, captureFrames, receivedData, requestCount}: {
microMetrics?: {[key: string]: string},
forceGc?: boolean,
@ -32,13 +33,13 @@ export function main() {
new PerfLogFeatures({render: true, gc: true, frameCapture: true, userTiming: true});
}
if (isBlank(microMetrics)) {
microMetrics = StringMapWrapper.create();
microMetrics = {};
}
var providers: any[] = [
var providers: Provider[] = [
Options.DEFAULT_PROVIDERS, PerflogMetric.PROVIDERS,
{provide: Options.MICRO_METRICS, useValue: microMetrics}, {
provide: PerflogMetric.SET_TIMEOUT,
useValue: (fn, millis) => {
useValue: (fn: Function, millis: number) => {
commandLog.push(['setTimeout', millis]);
fn();
},
@ -65,8 +66,8 @@ export function main() {
describe('perflog metric', () => {
function sortedKeys(stringMap) {
var res = [];
function sortedKeys(stringMap: {[key: string]: any}) {
var res: string[] = [];
StringMapWrapper.forEach(stringMap, (_, key) => { res.push(key); });
res.sort();
return res;
@ -129,7 +130,8 @@ export function main() {
describe('beginMeasure', () => {
it('should not force gc and mark the timeline', inject([AsyncTestCompleter], (async) => {
it('should not force gc and mark the timeline',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var metric = createMetric([[]], null);
metric.beginMeasure().then((_) => {
expect(commandLog).toEqual([['timeBegin', 'benchpress0']]);
@ -138,7 +140,8 @@ export function main() {
});
}));
it('should force gc and mark the timeline', inject([AsyncTestCompleter], (async) => {
it('should force gc and mark the timeline',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var metric = createMetric([[]], null, {forceGc: true});
metric.beginMeasure().then((_) => {
expect(commandLog).toEqual([['gc'], ['timeBegin', 'benchpress0']]);
@ -152,7 +155,7 @@ export function main() {
describe('endMeasure', () => {
it('should mark and aggregate events in between the marks',
inject([AsyncTestCompleter], (async) => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var events = [[
eventFactory.markStart('benchpress0', 0), eventFactory.start('script', 4),
eventFactory.end('script', 6), eventFactory.markEnd('benchpress0', 10)
@ -168,7 +171,23 @@ export function main() {
});
}));
it('should restart timing', inject([AsyncTestCompleter], (async) => {
it('should mark and aggregate events since navigationStart',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var events = [[
eventFactory.markStart('benchpress0', 0), eventFactory.start('script', 4),
eventFactory.end('script', 6), eventFactory.instant('navigationStart', 7),
eventFactory.start('script', 8), eventFactory.end('script', 9),
eventFactory.markEnd('benchpress0', 10)
]];
var metric = createMetric(events, null);
metric.beginMeasure().then((_) => metric.endMeasure(false)).then((data) => {
expect(data['scriptTime']).toBe(1);
async.done();
});
}));
it('should restart timing', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var events = [
[
eventFactory.markStart('benchpress0', 0),
@ -192,7 +211,7 @@ export function main() {
}));
it('should loop and aggregate until the end mark is present',
inject([AsyncTestCompleter], (async) => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var events = [
[eventFactory.markStart('benchpress0', 0), eventFactory.start('script', 1)],
[eventFactory.end('script', 2)],
@ -214,7 +233,7 @@ export function main() {
}));
it('should store events after the end mark for the next call',
inject([AsyncTestCompleter], (async) => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var events = [
[
eventFactory.markStart('benchpress0', 0), eventFactory.markEnd('benchpress0', 1),
@ -245,7 +264,7 @@ export function main() {
}));
describe('with forced gc', () => {
var events;
var events: PerfLogEvent[][];
beforeEach(() => {
events = [[
eventFactory.markStart('benchpress0', 0), eventFactory.start('script', 4),
@ -257,7 +276,7 @@ export function main() {
]];
});
it('should measure forced gc', inject([AsyncTestCompleter], (async) => {
it('should measure forced gc', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var metric = createMetric(events, null, {forceGc: true});
metric.beginMeasure().then((_) => metric.endMeasure(false)).then((data) => {
expect(commandLog).toEqual([
@ -271,7 +290,8 @@ export function main() {
});
}));
it('should restart after the forced gc if needed', inject([AsyncTestCompleter], (async) => {
it('should restart after the forced gc if needed',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var metric = createMetric(events, null, {forceGc: true});
metric.beginMeasure().then((_) => metric.endMeasure(true)).then((data) => {
expect(commandLog[5]).toEqual(['timeEnd', 'benchpress1', 'benchpress2']);
@ -304,7 +324,8 @@ export function main() {
}
describe('frame metrics', () => {
it('should calculate mean frame time', inject([AsyncTestCompleter], (async) => {
it('should calculate mean frame time',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate(
[
eventFactory.markStart('frameCapture', 0), eventFactory.instant('frame', 1),
@ -318,7 +339,8 @@ export function main() {
});
}));
it('should throw if no start event', inject([AsyncTestCompleter], (async) => {
it('should throw if no start event',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate(
[eventFactory.instant('frame', 4), eventFactory.markEnd('frameCapture', 5)],
@ -331,7 +353,8 @@ export function main() {
});
}));
it('should throw if no end event', inject([AsyncTestCompleter], (async) => {
it('should throw if no end event',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate(
[eventFactory.markStart('frameCapture', 3), eventFactory.instant('frame', 4)],
@ -342,7 +365,8 @@ export function main() {
});
}));
it('should throw if trying to capture twice', inject([AsyncTestCompleter], (async) => {
it('should throw if trying to capture twice',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate(
[
@ -359,7 +383,7 @@ export function main() {
}));
it('should throw if trying to capture when frame capture is disabled',
inject([AsyncTestCompleter], (async) => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate([eventFactory.markStart('frameCapture', 3)]).catch((err) => {
expect(() => { throw err; })
.toThrowError(
@ -370,7 +394,7 @@ export function main() {
}));
it('should throw if frame capture is enabled, but nothing is captured',
inject([AsyncTestCompleter], (async) => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate([], {captureFrames: true}).catch((err): any => {
expect(() => { throw err; })
.toThrowError(
@ -379,7 +403,8 @@ export function main() {
});
}));
it('should calculate best and worst frame time', inject([AsyncTestCompleter], (async) => {
it('should calculate best and worst frame time',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate(
[
eventFactory.markStart('frameCapture', 0), eventFactory.instant('frame', 1),
@ -396,7 +421,7 @@ export function main() {
}));
it('should calculate percentage of smoothness to be good',
inject([AsyncTestCompleter], (async) => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate(
[
eventFactory.markStart('frameCapture', 0), eventFactory.instant('frame', 1),
@ -411,7 +436,7 @@ export function main() {
}));
it('should calculate percentage of smoothness to be bad',
inject([AsyncTestCompleter], (async) => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate(
[
eventFactory.markStart('frameCapture', 0), eventFactory.instant('frame', 1),
@ -428,7 +453,8 @@ export function main() {
});
it('should report a single interval', inject([AsyncTestCompleter], (async) => {
it('should report a single interval',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate([
eventFactory.start('script', 0), eventFactory.end('script', 5)
]).then((data) => {
@ -437,7 +463,8 @@ export function main() {
});
}));
it('should sum up multiple intervals', inject([AsyncTestCompleter], (async) => {
it('should sum up multiple intervals',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate([
eventFactory.start('script', 0), eventFactory.end('script', 5),
eventFactory.start('script', 10), eventFactory.end('script', 17)
@ -447,21 +474,24 @@ export function main() {
});
}));
it('should ignore not started intervals', inject([AsyncTestCompleter], (async) => {
it('should ignore not started intervals',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate([eventFactory.end('script', 10)]).then((data) => {
expect(data['scriptTime']).toBe(0);
async.done();
});
}));
it('should ignore not ended intervals', inject([AsyncTestCompleter], (async) => {
it('should ignore not ended intervals',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate([eventFactory.start('script', 10)]).then((data) => {
expect(data['scriptTime']).toBe(0);
async.done();
});
}));
it('should ignore nested intervals', inject([AsyncTestCompleter], (async) => {
it('should ignore nested intervals',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate([
eventFactory.start('script', 0), eventFactory.start('script', 5),
eventFactory.end('script', 10), eventFactory.end('script', 17)
@ -472,7 +502,7 @@ export function main() {
}));
it('should ignore events from different processed as the start mark',
inject([AsyncTestCompleter], (async) => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var otherProcessEventFactory = new TraceEventFactory('timeline', 'pid1');
var metric = createMetric(
[[
@ -489,7 +519,8 @@ export function main() {
});
}));
it('should support scriptTime metric', inject([AsyncTestCompleter], (async) => {
it('should support scriptTime metric',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate([
eventFactory.start('script', 0), eventFactory.end('script', 5)
]).then((data) => {
@ -498,7 +529,8 @@ export function main() {
});
}));
it('should support renderTime metric', inject([AsyncTestCompleter], (async) => {
it('should support renderTime metric',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate([
eventFactory.start('render', 0), eventFactory.end('render', 5)
]).then((data) => {
@ -507,7 +539,8 @@ export function main() {
});
}));
it('should support gcTime/gcAmount metric', inject([AsyncTestCompleter], (async) => {
it('should support gcTime/gcAmount metric',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate([
eventFactory.start('gc', 0, {'usedHeapSize': 2500}),
eventFactory.end('gc', 5, {'usedHeapSize': 1000})
@ -519,7 +552,8 @@ export function main() {
});
}));
it('should support majorGcTime metric', inject([AsyncTestCompleter], (async) => {
it('should support majorGcTime metric',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate([
eventFactory.start('gc', 0, {'usedHeapSize': 2500}),
eventFactory.end('gc', 5, {'usedHeapSize': 1000, 'majorGc': true})
@ -531,7 +565,7 @@ export function main() {
}));
it('should support pureScriptTime = scriptTime-gcTime-renderTime',
inject([AsyncTestCompleter], (async) => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate([
eventFactory.start('script', 0), eventFactory.start('gc', 1, {'usedHeapSize': 1000}),
eventFactory.end('gc', 4, {'usedHeapSize': 0}), eventFactory.start('render', 4),
@ -545,7 +579,7 @@ export function main() {
describe('receivedData', () => {
it('should report received data since last navigationStart',
inject([AsyncTestCompleter], (async) => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate(
[
eventFactory.instant('receivedData', 0, {'encodedDataLength': 1}),
@ -565,7 +599,7 @@ export function main() {
describe('requestCount', () => {
it('should report count of requests sent since last navigationStart',
inject([AsyncTestCompleter], (async) => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate(
[
eventFactory.instant('sendRequest', 0),
@ -584,7 +618,8 @@ export function main() {
describe('microMetrics', () => {
it('should report micro metrics', inject([AsyncTestCompleter], (async) => {
it('should report micro metrics',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate(
[
eventFactory.markStart('mm1', 0),
@ -598,7 +633,7 @@ export function main() {
}));
it('should ignore micro metrics that were not specified',
inject([AsyncTestCompleter], (async) => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate([
eventFactory.markStart('mm1', 0),
eventFactory.markEnd('mm1', 5),
@ -608,7 +643,8 @@ export function main() {
});
}));
it('should report micro metric averages', inject([AsyncTestCompleter], (async) => {
it('should report micro metric averages',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate(
[
eventFactory.markStart('mm1*20', 0),
@ -635,12 +671,12 @@ class MockDriverExtension extends WebDriverExtension {
super();
}
timeBegin(name): Promise<any> {
timeBegin(name: string): Promise<any> {
this._commandLog.push(['timeBegin', name]);
return Promise.resolve(null);
}
timeEnd(name, restartName): Promise<any> {
timeEnd(name: string, restartName: string): Promise<any> {
this._commandLog.push(['timeEnd', name, restartName]);
return Promise.resolve(null);
}

View File

@ -6,32 +6,33 @@
* found in the LICENSE file at https://angular.io/license
*/
import {ReflectiveInjector} from '@angular/core';
import {Provider, ReflectiveInjector} from '@angular/core';
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {StringMapWrapper} from '@angular/facade/src/collection';
import {Json, isBlank, isPresent} from '@angular/facade/src/lang';
import {Injector, Metric, MultiMetric, Options, PerfLogFeatures, PerflogMetric, UserMetric, WebDriverAdapter, WebDriverExtension, bind, provide} from 'benchpress/common';
import {Injector, Metric, MultiMetric, Options, PerfLogEvent, PerfLogFeatures, PerflogMetric, UserMetric, WebDriverAdapter, WebDriverExtension} from '../../index';
import {StringMapWrapper} from '../../src/facade/collection';
import {Json, isBlank, isPresent} from '../../src/facade/lang';
export function main() {
var wdAdapter: MockDriverAdapter;
function createMetric(
perfLogs, perfLogFeatures,
perfLogs: PerfLogEvent[], perfLogFeatures: PerfLogFeatures,
{userMetrics}: {userMetrics?: {[key: string]: string}} = {}): UserMetric {
if (isBlank(perfLogFeatures)) {
perfLogFeatures =
new PerfLogFeatures({render: true, gc: true, frameCapture: true, userTiming: true});
}
if (isBlank(userMetrics)) {
userMetrics = StringMapWrapper.create();
userMetrics = {};
}
wdAdapter = new MockDriverAdapter();
var bindings = [
var providers: Provider[] = [
Options.DEFAULT_PROVIDERS, UserMetric.PROVIDERS,
bind(Options.USER_METRICS).toValue(userMetrics),
provide(WebDriverAdapter, {useValue: wdAdapter})
{provide: Options.USER_METRICS, useValue: userMetrics},
{provide: WebDriverAdapter, useValue: wdAdapter}
];
return ReflectiveInjector.resolveAndCreate(bindings).get(UserMetric);
return ReflectiveInjector.resolveAndCreate(providers).get(UserMetric);
}
describe('user metric', () => {
@ -45,7 +46,7 @@ export function main() {
describe('endMeasure', () => {
it('should stop measuring when all properties have numeric values',
inject([AsyncTestCompleter], (async) => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
let metric = createMetric(
[[]], new PerfLogFeatures(),
{userMetrics: {'loadTime': 'time to load', 'content': 'time to see content'}});

View File

@ -6,17 +6,24 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Provider} from '@angular/core';
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {Date, DateWrapper, isBlank, isPresent} from '@angular/facade/src/lang';
import {ConsoleReporter, MeasureValues, ReflectiveInjector, Reporter, SampleDescription, SampleState} from 'benchpress/common';
import {ConsoleReporter, MeasureValues, ReflectiveInjector, Reporter, SampleDescription, SampleState} from '../../index';
import {Date, DateWrapper, isBlank, isPresent} from '../../src/facade/lang';
export function main() {
describe('console reporter', () => {
var reporter;
var reporter: ConsoleReporter;
var log: string[];
function createReporter({columnWidth = null, sampleId = null, descriptions = null,
metrics = null}: {columnWidth?, sampleId?, descriptions?, metrics?}) {
function createReporter(
{columnWidth = null, sampleId = null, descriptions = null, metrics = null}: {
columnWidth?: number,
sampleId?: string,
descriptions?: {[key: string]: any}[],
metrics?: {[key: string]: any}
}) {
log = [];
if (isBlank(descriptions)) {
descriptions = [];
@ -24,17 +31,17 @@ export function main() {
if (isBlank(sampleId)) {
sampleId = 'null';
}
var bindings = [
var providers: Provider[] = [
ConsoleReporter.PROVIDERS, {
provide: SampleDescription,
useValue: new SampleDescription(sampleId, descriptions, metrics)
},
{provide: ConsoleReporter.PRINT, useValue: (line) => log.push(line)}
{provide: ConsoleReporter.PRINT, useValue: (line: string) => log.push(line)}
];
if (isPresent(columnWidth)) {
bindings.push({provide: ConsoleReporter.COLUMN_WIDTH, useValue: columnWidth});
providers.push({provide: ConsoleReporter.COLUMN_WIDTH, useValue: columnWidth});
}
reporter = ReflectiveInjector.resolveAndCreate(bindings).get(ConsoleReporter);
reporter = ReflectiveInjector.resolveAndCreate(providers).get(ConsoleReporter);
}
it('should print the sample id, description and table header', () => {
@ -82,6 +89,6 @@ export function main() {
});
}
function mv(runIndex, time, values) {
function mv(runIndex: number, time: number, values: {[key: string]: number}) {
return new MeasureValues(runIndex, DateWrapper.fromMillis(time), values);
}

View File

@ -7,16 +7,21 @@
*/
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {DateWrapper, Json, isPresent} from '@angular/facade/src/lang';
import {MeasureValues, Options, ReflectiveInjector, SampleDescription} from 'benchpress/common';
import {JsonFileReporter} from 'benchpress/src/reporter/json_file_reporter';
import {JsonFileReporter, MeasureValues, Options, ReflectiveInjector, SampleDescription} from '../../index';
import {DateWrapper, Json, isPresent} from '../../src/facade/lang';
export function main() {
describe('file reporter', () => {
var loggedFile;
var loggedFile: any;
function createReporter({sampleId, descriptions, metrics, path}) {
var bindings = [
function createReporter({sampleId, descriptions, metrics, path}: {
sampleId: string,
descriptions: {[key: string]: any}[],
metrics: {[key: string]: string},
path: string
}) {
var providers = [
JsonFileReporter.PROVIDERS, {
provide: SampleDescription,
useValue: new SampleDescription(sampleId, descriptions, metrics)
@ -24,21 +29,22 @@ export function main() {
{provide: JsonFileReporter.PATH, useValue: path},
{provide: Options.NOW, useValue: () => DateWrapper.fromMillis(1234)}, {
provide: Options.WRITE_FILE,
useValue: (filename, content) => {
useValue: (filename: string, content: string) => {
loggedFile = {'filename': filename, 'content': content};
return Promise.resolve(null);
}
}
];
return ReflectiveInjector.resolveAndCreate(bindings).get(JsonFileReporter);
return ReflectiveInjector.resolveAndCreate(providers).get(JsonFileReporter);
}
it('should write all data into a file', inject([AsyncTestCompleter], (async) => {
it('should write all data into a file',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createReporter({
sampleId: 'someId',
descriptions: [{'a': 2}],
path: 'somePath',
metrics: {'script': 'script time'}
metrics: {'a': 'script time', 'b': 'render time'}
})
.reportSample(
[mv(0, 0, {'a': 3, 'b': 6})],
@ -47,8 +53,12 @@ export function main() {
expect(isPresent(loggedFile['filename'].match(regExp))).toBe(true);
var parsedContent = Json.parse(loggedFile['content']);
expect(parsedContent).toEqual({
'description':
{'id': 'someId', 'description': {'a': 2}, 'metrics': {'script': 'script time'}},
'description': {
'id': 'someId',
'description': {'a': 2},
'metrics': {'a': 'script time', 'b': 'render time'}
},
'stats': {'a': '4.00+-25%', 'b': '7.50+-20%'},
'completeSample': [
{'timeStamp': '1970-01-01T00:00:00.000Z', 'runIndex': 0, 'values': {'a': 3, 'b': 6}}
],
@ -66,6 +76,6 @@ export function main() {
});
}
function mv(runIndex, time, values) {
function mv(runIndex: number, time: number, values: {[key: string]: number}) {
return new MeasureValues(runIndex, DateWrapper.fromMillis(time), values);
}

View File

@ -7,15 +7,16 @@
*/
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {DateWrapper} from '@angular/facade/src/lang';
import {MeasureValues, MultiReporter, ReflectiveInjector, Reporter} from 'benchpress/common';
import {MeasureValues, MultiReporter, ReflectiveInjector, Reporter} from '../../index';
import {DateWrapper} from '../../src/facade/lang';
export function main() {
function createReporters(ids: any[]) {
var r = ReflectiveInjector
.resolveAndCreate([
ids.map(id => { return {provide: id, useValue: new MockReporter(id)}; }),
MultiReporter.createBindings(ids)
MultiReporter.provideWith(ids)
])
.get(MultiReporter);
return Promise.resolve(r);
@ -23,7 +24,8 @@ export function main() {
describe('multi reporter', () => {
it('should reportMeasureValues to all', inject([AsyncTestCompleter], (async) => {
it('should reportMeasureValues to all',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var mv = new MeasureValues(0, DateWrapper.now(), {});
createReporters(['m1', 'm2']).then((r) => r.reportMeasureValues(mv)).then((values) => {
@ -32,7 +34,7 @@ export function main() {
});
}));
it('should reportSample to call', inject([AsyncTestCompleter], (async) => {
it('should reportSample to call', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var completeSample = [
new MeasureValues(0, DateWrapper.now(), {}), new MeasureValues(1, DateWrapper.now(), {})
];

View File

@ -7,22 +7,23 @@
*/
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {isBlank} from '@angular/facade/src/lang';
import {Injector, Metric, Options, ReflectiveInjector, Runner, SampleDescription, SampleState, Sampler, Validator, WebDriverAdapter} from 'benchpress/common';
import {Injector, Metric, Options, ReflectiveInjector, Runner, SampleDescription, SampleState, Sampler, Validator, WebDriverAdapter} from '../index';
import {isBlank} from '../src/facade/lang';
export function main() {
describe('runner', () => {
var injector: ReflectiveInjector;
var runner;
var runner: Runner;
function createRunner(defaultBindings = null): Runner {
if (isBlank(defaultBindings)) {
defaultBindings = [];
function createRunner(defaultProviders: any[] = null): Runner {
if (isBlank(defaultProviders)) {
defaultProviders = [];
}
runner = new Runner([
defaultBindings, {
defaultProviders, {
provide: Sampler,
useFactory: (_injector) => {
useFactory: (_injector: ReflectiveInjector) => {
injector = _injector;
return new MockSampler();
},
@ -35,7 +36,8 @@ export function main() {
return runner;
}
it('should set SampleDescription.id', inject([AsyncTestCompleter], (async) => {
it('should set SampleDescription.id',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createRunner()
.sample({id: 'someId'})
.then((_) => injector.get(SampleDescription))
@ -45,7 +47,8 @@ export function main() {
});
}));
it('should merge SampleDescription.description', inject([AsyncTestCompleter], (async) => {
it('should merge SampleDescription.description',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createRunner([{provide: Options.DEFAULT_DESCRIPTION, useValue: {'a': 1}}])
.sample({
id: 'someId',
@ -61,7 +64,7 @@ export function main() {
}));
it('should fill SampleDescription.metrics from the Metric',
inject([AsyncTestCompleter], (async) => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createRunner()
.sample({id: 'someId'})
.then((_) => injector.get(SampleDescription))
@ -72,7 +75,8 @@ export function main() {
});
}));
it('should bind Options.EXECUTE', inject([AsyncTestCompleter], (async) => {
it('should provide Options.EXECUTE',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var execute = () => {};
createRunner().sample({id: 'someId', execute: execute}).then((_) => {
expect(injector.get(Options.EXECUTE)).toEqual(execute);
@ -80,7 +84,8 @@ export function main() {
});
}));
it('should bind Options.PREPARE', inject([AsyncTestCompleter], (async) => {
it('should provide Options.PREPARE',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var prepare = () => {};
createRunner().sample({id: 'someId', prepare: prepare}).then((_) => {
expect(injector.get(Options.PREPARE)).toEqual(prepare);
@ -88,14 +93,16 @@ export function main() {
});
}));
it('should bind Options.MICRO_METRICS', inject([AsyncTestCompleter], (async) => {
it('should provide Options.MICRO_METRICS',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createRunner().sample({id: 'someId', microMetrics: {'a': 'b'}}).then((_) => {
expect(injector.get(Options.MICRO_METRICS)).toEqual({'a': 'b'});
async.done();
});
}));
it('should overwrite bindings per sample call', inject([AsyncTestCompleter], (async) => {
it('should overwrite providers per sample call',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createRunner([{provide: Options.DEFAULT_DESCRIPTION, useValue: {'a': 1}}])
.sample({
id: 'someId',
@ -114,8 +121,8 @@ export function main() {
}
class MockWebDriverAdapter extends WebDriverAdapter {
executeScript(script): Promise<string> { return Promise.resolve('someUserAgent'); }
capabilities() { return null; }
executeScript(script: string): Promise<string> { return Promise.resolve('someUserAgent'); }
capabilities(): Promise<Map<string, any>> { return null; }
}
class MockValidator extends Validator {
@ -129,6 +136,6 @@ class MockMetric extends Metric {
}
class MockSampler extends Sampler {
constructor() { super(); }
constructor() { super(null, null, null, null, null, null, null); }
sample(): Promise<SampleState> { return Promise.resolve(new SampleState([], [])); }
}

View File

@ -7,8 +7,9 @@
*/
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {Date, DateWrapper, isBlank, isPresent, stringify} from '@angular/facade/src/lang';
import {MeasureValues, Metric, Options, ReflectiveInjector, Reporter, Sampler, Validator, WebDriverAdapter} from 'benchpress/common';
import {MeasureValues, Metric, Options, ReflectiveInjector, Reporter, Sampler, Validator, WebDriverAdapter} from '../index';
import {Date, DateWrapper, isBlank, isPresent, stringify} from '../src/facade/lang';
export function main() {
var EMPTY_EXECUTE = () => {};
@ -48,10 +49,10 @@ export function main() {
}
it('should call the prepare and execute callbacks using WebDriverAdapter.waitFor',
inject([AsyncTestCompleter], (async) => {
var log = [];
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var log: any[] = [];
var count = 0;
var driver = new MockDriverAdapter([], (callback) => {
var driver = new MockDriverAdapter([], (callback: Function) => {
var result = callback();
log.push(result);
return Promise.resolve(result);
@ -71,9 +72,9 @@ export function main() {
}));
it('should call prepare, beginMeasure, execute, endMeasure for every iteration',
inject([AsyncTestCompleter], (async) => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var workCount = 0;
var log = [];
var log: any[] = [];
createSampler({
metric: createCountingMetric(log),
validator: createCountingValidator(2),
@ -96,8 +97,8 @@ export function main() {
}));
it('should call execute, endMeasure for every iteration if there is no prepare callback',
inject([AsyncTestCompleter], (async) => {
var log = [];
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var log: any[] = [];
var workCount = 0;
createSampler({
metric: createCountingMetric(log),
@ -118,7 +119,7 @@ export function main() {
}));
it('should only collect metrics for execute and ignore metrics from prepare',
inject([AsyncTestCompleter], (async) => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var scriptTime = 0;
var iterationCount = 1;
createSampler({
@ -145,9 +146,9 @@ export function main() {
}));
it('should call the validator for every execution and store the valid sample',
inject([AsyncTestCompleter], (async) => {
var log = [];
var validSample = [{}];
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var log: any[] = [];
var validSample = [mv(null, null, {})];
createSampler({
metric: createCountingMetric(),
@ -171,9 +172,10 @@ export function main() {
});
}));
it('should report the metric values', inject([AsyncTestCompleter], (async) => {
var log = [];
var validSample = [{}];
it('should report the metric values',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var log: any[] = [];
var validSample = [mv(null, null, {})];
createSampler({
validator: createCountingValidator(2, validSample),
metric: createCountingMetric(),
@ -201,12 +203,13 @@ export function main() {
});
}
function mv(runIndex, time, values) {
function mv(runIndex: number, time: number, values: {[key: string]: number}) {
return new MeasureValues(runIndex, DateWrapper.fromMillis(time), values);
}
function createCountingValidator(count, validSample = null, log = null) {
return new MockValidator(log, (completeSample) => {
function createCountingValidator(
count: number, validSample: MeasureValues[] = null, log: any[] = []) {
return new MockValidator(log, (completeSample: MeasureValues[]) => {
count--;
if (count === 0) {
return isPresent(validSample) ? validSample : completeSample;
@ -216,23 +219,13 @@ function createCountingValidator(count, validSample = null, log = null) {
});
}
function createCountingMetric(log = null) {
function createCountingMetric(log: any[] = []) {
var scriptTime = 0;
return new MockMetric(log, () => { return {'script': scriptTime++}; });
}
class MockDriverAdapter extends WebDriverAdapter {
/** @internal */
private _log: any[];
private _waitFor: Function;
constructor(log = null, waitFor = null) {
super();
if (isBlank(log)) {
log = [];
}
this._log = log;
this._waitFor = waitFor;
}
constructor(private _log: any[] = [], private _waitFor: Function = null) { super(); }
waitFor(callback: Function): Promise<any> {
if (isPresent(this._waitFor)) {
return this._waitFor(callback);
@ -244,15 +237,7 @@ class MockDriverAdapter extends WebDriverAdapter {
class MockValidator extends Validator {
/** @internal */
private _log: any[];
constructor(log = null, private _validate: Function = null) {
super();
if (isBlank(log)) {
log = [];
}
this._log = log;
}
constructor(private _log: any[] = [], private _validate: Function = null) { super(); }
validate(completeSample: MeasureValues[]): MeasureValues[] {
var stableSample = isPresent(this._validate) ? this._validate(completeSample) : completeSample;
this._log.push(['validate', completeSample, stableSample]);
@ -261,20 +246,12 @@ class MockValidator extends Validator {
}
class MockMetric extends Metric {
/** @internal */
private _log: any[];
constructor(log = null, private _endMeasure: Function = null) {
super();
if (isBlank(log)) {
log = [];
}
this._log = log;
}
constructor(private _log: any[] = [], private _endMeasure: Function = null) { super(); }
beginMeasure() {
this._log.push(['beginMeasure']);
return Promise.resolve(null);
}
endMeasure(restart) {
endMeasure(restart: boolean) {
var measureValues = isPresent(this._endMeasure) ? this._endMeasure() : {};
this._log.push(['endMeasure', restart, measureValues]);
return Promise.resolve(measureValues);
@ -282,20 +259,12 @@ class MockMetric extends Metric {
}
class MockReporter extends Reporter {
/** @internal */
private _log: any[];
constructor(log = null) {
super();
if (isBlank(log)) {
log = [];
}
this._log = log;
}
reportMeasureValues(values): Promise<any> {
constructor(private _log: any[] = []) { super(); }
reportMeasureValues(values: MeasureValues): Promise<any> {
this._log.push(['reportMeasureValues', values]);
return Promise.resolve(null);
}
reportSample(completeSample, validSample): Promise<any> {
reportSample(completeSample: MeasureValues[], validSample: MeasureValues[]): Promise<any> {
this._log.push(['reportSample', completeSample, validSample]);
return Promise.resolve(null);
}

View File

@ -7,7 +7,7 @@
*/
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {Statistic} from 'benchpress/src/statistic';
import {Statistic} from '../src/statistic';
export function main() {
describe('statistic', () => {

View File

@ -0,0 +1,41 @@
/**
* @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 {PerfLogEvent} from '../index';
import {isPresent} from '../src/facade/lang';
export class TraceEventFactory {
constructor(private _cat: string, private _pid: string) {}
create(ph: any, name: string, time: number, args: any = null) {
var res:
PerfLogEvent = {'name': name, 'cat': this._cat, 'ph': ph, 'ts': time, 'pid': this._pid};
if (isPresent(args)) {
res['args'] = args;
}
return res;
}
markStart(name: string, time: number) { return this.create('B', name, time); }
markEnd(name: string, time: number) { return this.create('E', name, time); }
start(name: string, time: number, args: any = null) { return this.create('B', name, time, args); }
end(name: string, time: number, args: any = null) { return this.create('E', name, time, args); }
instant(name: string, time: number, args: any = null) {
return this.create('I', name, time, args);
}
complete(name: string, time: number, duration: number, args: any = null) {
var res = this.create('X', name, time, args);
res['dur'] = duration;
return res;
}
}

View File

@ -7,15 +7,16 @@
*/
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {ListWrapper} from '@angular/facade/src/collection';
import {Date, DateWrapper} from '@angular/facade/src/lang';
import {MeasureValues, ReflectiveInjector, RegressionSlopeValidator} from 'benchpress/common';
import {MeasureValues, ReflectiveInjector, RegressionSlopeValidator} from '../../index';
import {ListWrapper} from '../../src/facade/collection';
import {Date, DateWrapper} from '../../src/facade/lang';
export function main() {
describe('regression slope validator', () => {
var validator;
var validator: RegressionSlopeValidator;
function createValidator({size, metric}) {
function createValidator({size, metric}: {size: number, metric: string}) {
validator = ReflectiveInjector
.resolveAndCreate([
RegressionSlopeValidator.PROVIDERS,
@ -60,6 +61,6 @@ export function main() {
});
}
function mv(runIndex, time, values) {
function mv(runIndex: number, time: number, values: {[key: string]: number}) {
return new MeasureValues(runIndex, DateWrapper.fromMillis(time), values);
}

View File

@ -7,15 +7,16 @@
*/
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {ListWrapper} from '@angular/facade/src/collection';
import {Date, DateWrapper} from '@angular/facade/src/lang';
import {MeasureValues, ReflectiveInjector, SizeValidator, Validator} from 'benchpress/common';
import {MeasureValues, ReflectiveInjector, SizeValidator, Validator} from '../../index';
import {ListWrapper} from '../../src/facade/collection';
import {Date, DateWrapper} from '../../src/facade/lang';
export function main() {
describe('size validator', () => {
var validator;
var validator: SizeValidator;
function createValidator(size) {
function createValidator(size: number) {
validator =
ReflectiveInjector
.resolveAndCreate(
@ -45,6 +46,6 @@ export function main() {
});
}
function mv(runIndex, time, values) {
function mv(runIndex: number, time: number, values: {[key: string]: number}) {
return new MeasureValues(runIndex, DateWrapper.fromMillis(time), values);
}

View File

@ -7,17 +7,19 @@
*/
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {StringWrapper, isPresent} from '@angular/facade/src/lang';
import {Options, ReflectiveInjector, WebDriverExtension} from 'benchpress/common';
import {Options, ReflectiveInjector, WebDriverExtension} from '../index';
import {StringWrapper, isPresent} from '../src/facade/lang';
export function main() {
function createExtension(ids: any[], caps) {
function createExtension(ids: any[], caps: any) {
return new Promise<any>((res, rej) => {
try {
res(ReflectiveInjector
.resolveAndCreate([
ids.map((id) => { return {provide: id, useValue: new MockExtension(id)}; }),
{provide: Options.CAPABILITIES, useValue: caps}, WebDriverExtension.bindTo(ids)
{provide: Options.CAPABILITIES, useValue: caps},
WebDriverExtension.provideFirstSupported(ids)
])
.get(WebDriverExtension));
} catch (e) {
@ -26,17 +28,18 @@ export function main() {
});
}
describe('WebDriverExtension.bindTo', () => {
describe('WebDriverExtension.provideFirstSupported', () => {
it('should bind the extension that matches the capabilities',
inject([AsyncTestCompleter], (async) => {
it('should provide the extension that matches the capabilities',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension(['m1', 'm2', 'm3'], {'browser': 'm2'}).then((m) => {
expect(m.id).toEqual('m2');
async.done();
});
}));
it('should throw if there is no match', inject([AsyncTestCompleter], (async) => {
it('should throw if there is no match',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension(['m1'], {'browser': 'm2'}).catch((err) => {
expect(isPresent(err)).toBe(true);
async.done();
@ -46,12 +49,7 @@ export function main() {
}
class MockExtension extends WebDriverExtension {
id: string;
constructor(id) {
super();
this.id = id;
}
constructor(public id: string) { super(); }
supports(capabilities: {[key: string]: any}): boolean {
return StringWrapper.equals(capabilities['browser'], this.id);

View File

@ -0,0 +1,408 @@
/**
* @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 {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {ChromeDriverExtension, Options, ReflectiveInjector, WebDriverAdapter, WebDriverExtension} from '../../index';
import {Json, isBlank} from '../../src/facade/lang';
import {TraceEventFactory} from '../trace_event_factory';
export function main() {
describe('chrome driver extension', () => {
var CHROME45_USER_AGENT =
'"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2499.0 Safari/537.36"';
var log: any[];
var extension: ChromeDriverExtension;
var blinkEvents = new TraceEventFactory('blink.console', 'pid0');
var v8Events = new TraceEventFactory('v8', 'pid0');
var v8EventsOtherProcess = new TraceEventFactory('v8', 'pid1');
var chromeTimelineEvents =
new TraceEventFactory('disabled-by-default-devtools.timeline', 'pid0');
var chrome45TimelineEvents = new TraceEventFactory('devtools.timeline', 'pid0');
var chromeTimelineV8Events = new TraceEventFactory('devtools.timeline,v8', 'pid0');
var chromeBlinkTimelineEvents = new TraceEventFactory('blink,devtools.timeline', 'pid0');
var chromeBlinkUserTimingEvents = new TraceEventFactory('blink.user_timing', 'pid0');
var benchmarkEvents = new TraceEventFactory('benchmark', 'pid0');
var normEvents = new TraceEventFactory('timeline', 'pid0');
function createExtension(
perfRecords: any[] = null, userAgent: string = null,
messageMethod = 'Tracing.dataCollected'): WebDriverExtension {
if (isBlank(perfRecords)) {
perfRecords = [];
}
if (isBlank(userAgent)) {
userAgent = CHROME45_USER_AGENT;
}
log = [];
extension = ReflectiveInjector
.resolveAndCreate([
ChromeDriverExtension.PROVIDERS, {
provide: WebDriverAdapter,
useValue: new MockDriverAdapter(log, perfRecords, messageMethod)
},
{provide: Options.USER_AGENT, useValue: userAgent}
])
.get(ChromeDriverExtension);
return extension;
}
it('should force gc via window.gc()',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension().gc().then((_) => {
expect(log).toEqual([['executeScript', 'window.gc()']]);
async.done();
});
}));
it('should mark the timeline via console.time()',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension().timeBegin('someName').then((_) => {
expect(log).toEqual([['executeScript', `console.time('someName');`]]);
async.done();
});
}));
it('should mark the timeline via console.timeEnd()',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension().timeEnd('someName', null).then((_) => {
expect(log).toEqual([['executeScript', `console.timeEnd('someName');`]]);
async.done();
});
}));
it('should mark the timeline via console.time() and console.timeEnd()',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension().timeEnd('name1', 'name2').then((_) => {
expect(log).toEqual(
[['executeScript', `console.timeEnd('name1');console.time('name2');`]]);
async.done();
});
}));
it('should normalize times to ms and forward ph and pid event properties',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([chromeTimelineV8Events.complete('FunctionCall', 1100, 5500, null)])
.readPerfLog()
.then((events) => {
expect(events).toEqual([
normEvents.complete('script', 1.1, 5.5, null),
]);
async.done();
});
}));
it('should normalize "tdur" to "dur"',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var event: any = chromeTimelineV8Events.create('X', 'FunctionCall', 1100, null);
event['tdur'] = 5500;
createExtension([event]).readPerfLog().then((events) => {
expect(events).toEqual([
normEvents.complete('script', 1.1, 5.5, null),
]);
async.done();
});
}));
it('should report FunctionCall events as "script"',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([chromeTimelineV8Events.start('FunctionCall', 0)])
.readPerfLog()
.then((events) => {
expect(events).toEqual([
normEvents.start('script', 0),
]);
async.done();
});
}));
it('should report EvaluateScript events as "script"',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([chromeTimelineV8Events.start('EvaluateScript', 0)])
.readPerfLog()
.then((events) => {
expect(events).toEqual([
normEvents.start('script', 0),
]);
async.done();
});
}));
it('should report minor gc', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([
chromeTimelineV8Events.start('MinorGC', 1000, {'usedHeapSizeBefore': 1000}),
chromeTimelineV8Events.end('MinorGC', 2000, {'usedHeapSizeAfter': 0}),
])
.readPerfLog()
.then((events) => {
expect(events.length).toEqual(2);
expect(events[0]).toEqual(
normEvents.start('gc', 1.0, {'usedHeapSize': 1000, 'majorGc': false}));
expect(events[1]).toEqual(
normEvents.end('gc', 2.0, {'usedHeapSize': 0, 'majorGc': false}));
async.done();
});
}));
it('should report major gc', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension(
[
chromeTimelineV8Events.start('MajorGC', 1000, {'usedHeapSizeBefore': 1000}),
chromeTimelineV8Events.end('MajorGC', 2000, {'usedHeapSizeAfter': 0}),
], )
.readPerfLog()
.then((events) => {
expect(events.length).toEqual(2);
expect(events[0]).toEqual(
normEvents.start('gc', 1.0, {'usedHeapSize': 1000, 'majorGc': true}));
expect(events[1]).toEqual(
normEvents.end('gc', 2.0, {'usedHeapSize': 0, 'majorGc': true}));
async.done();
});
}));
['Layout', 'UpdateLayerTree', 'Paint'].forEach((recordType) => {
it(`should report ${recordType} as "render"`,
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension(
[
chrome45TimelineEvents.start(recordType, 1234),
chrome45TimelineEvents.end(recordType, 2345)
], )
.readPerfLog()
.then((events) => {
expect(events).toEqual([
normEvents.start('render', 1.234),
normEvents.end('render', 2.345),
]);
async.done();
});
}));
});
it(`should report UpdateLayoutTree as "render"`,
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension(
[
chromeBlinkTimelineEvents.start('UpdateLayoutTree', 1234),
chromeBlinkTimelineEvents.end('UpdateLayoutTree', 2345)
], )
.readPerfLog()
.then((events) => {
expect(events).toEqual([
normEvents.start('render', 1.234),
normEvents.end('render', 2.345),
]);
async.done();
});
}));
it('should ignore FunctionCalls from webdriver',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([chromeTimelineV8Events.start(
'FunctionCall', 0, {'data': {'scriptName': 'InjectedScript'}})])
.readPerfLog()
.then((events) => {
expect(events).toEqual([]);
async.done();
});
}));
it('should ignore FunctionCalls with empty scriptName',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension(
[chromeTimelineV8Events.start('FunctionCall', 0, {'data': {'scriptName': ''}})])
.readPerfLog()
.then((events) => {
expect(events).toEqual([]);
async.done();
});
}));
it('should report navigationStart',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([chromeBlinkUserTimingEvents.instant('navigationStart', 1234)])
.readPerfLog()
.then((events) => {
expect(events).toEqual([normEvents.instant('navigationStart', 1.234)]);
async.done();
});
}));
it('should report receivedData', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([chrome45TimelineEvents.instant(
'ResourceReceivedData', 1234, {'data': {'encodedDataLength': 987}})], )
.readPerfLog()
.then((events) => {
expect(events).toEqual(
[normEvents.instant('receivedData', 1.234, {'encodedDataLength': 987})]);
async.done();
});
}));
it('should report sendRequest', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([chrome45TimelineEvents.instant(
'ResourceSendRequest', 1234,
{'data': {'url': 'http://here', 'requestMethod': 'GET'}})], )
.readPerfLog()
.then((events) => {
expect(events).toEqual([normEvents.instant(
'sendRequest', 1.234, {'url': 'http://here', 'method': 'GET'})]);
async.done();
});
}));
describe('readPerfLog (common)', () => {
it('should execute a dummy script before reading them',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
// TODO(tbosch): This seems to be a bug in ChromeDriver:
// Sometimes it does not report the newest events of the performance log
// to the WebDriver client unless a script is executed...
createExtension([]).readPerfLog().then((_) => {
expect(log).toEqual([['executeScript', '1+1'], ['logs', 'performance']]);
async.done();
});
}));
['Rasterize', 'CompositeLayers'].forEach((recordType) => {
it(`should report ${recordType} as "render"`,
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension(
[
chromeTimelineEvents.start(recordType, 1234),
chromeTimelineEvents.end(recordType, 2345)
], )
.readPerfLog()
.then((events) => {
expect(events).toEqual([
normEvents.start('render', 1.234),
normEvents.end('render', 2.345),
]);
async.done();
});
}));
});
describe('frame metrics', () => {
it('should report ImplThreadRenderingStats as frame event',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([benchmarkEvents.instant(
'BenchmarkInstrumentation::ImplThreadRenderingStats', 1100,
{'data': {'frame_count': 1}})])
.readPerfLog()
.then((events) => {
expect(events).toEqual([
normEvents.instant('frame', 1.1),
]);
async.done();
});
}));
it('should not report ImplThreadRenderingStats with zero frames',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([benchmarkEvents.instant(
'BenchmarkInstrumentation::ImplThreadRenderingStats', 1100,
{'data': {'frame_count': 0}})])
.readPerfLog()
.then((events) => {
expect(events).toEqual([]);
async.done();
});
}));
it('should throw when ImplThreadRenderingStats contains more than one frame',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([benchmarkEvents.instant(
'BenchmarkInstrumentation::ImplThreadRenderingStats', 1100,
{'data': {'frame_count': 2}})])
.readPerfLog()
.catch((err): any => {
expect(() => {
throw err;
}).toThrowError('multi-frame render stats not supported');
async.done();
});
}));
});
it('should report begin timestamps',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([blinkEvents.create('S', 'someName', 1000)])
.readPerfLog()
.then((events) => {
expect(events).toEqual([normEvents.markStart('someName', 1.0)]);
async.done();
});
}));
it('should report end timestamps',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([blinkEvents.create('F', 'someName', 1000)])
.readPerfLog()
.then((events) => {
expect(events).toEqual([normEvents.markEnd('someName', 1.0)]);
async.done();
});
}));
it('should throw an error on buffer overflow',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension(
[
chromeTimelineEvents.start('FunctionCall', 1234),
],
CHROME45_USER_AGENT, 'Tracing.bufferUsage')
.readPerfLog()
.catch((err): any => {
expect(() => {
throw err;
}).toThrowError('The DevTools trace buffer filled during the test!');
async.done();
});
}));
it('should match chrome browsers', () => {
expect(createExtension().supports({'browserName': 'chrome'})).toBe(true);
expect(createExtension().supports({'browserName': 'Chrome'})).toBe(true);
});
});
});
}
class MockDriverAdapter extends WebDriverAdapter {
constructor(private _log: any[], private _events: any[], private _messageMethod: string) {
super();
}
executeScript(script: string) {
this._log.push(['executeScript', script]);
return Promise.resolve(null);
}
logs(type: string) {
this._log.push(['logs', type]);
if (type === 'performance') {
return Promise.resolve(this._events.map((event) => {
return {
'message': Json.stringify({'message': {'method': this._messageMethod, 'params': event}})
};
}));
} else {
return null;
}
}
}

View File

@ -7,19 +7,19 @@
*/
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {Json, isBlank, isPresent} from '@angular/facade/src/lang';
import {IOsDriverExtension, ReflectiveInjector, WebDriverAdapter, WebDriverExtension} from 'benchpress/common';
import {IOsDriverExtension, ReflectiveInjector, WebDriverAdapter, WebDriverExtension} from '../../index';
import {Json, isBlank, isPresent} from '../../src/facade/lang';
import {TraceEventFactory} from '../trace_event_factory';
export function main() {
describe('ios driver extension', () => {
var log;
var extension;
var log: any[];
var extension: IOsDriverExtension;
var normEvents = new TraceEventFactory('timeline', 'pid0');
function createExtension(perfRecords = null): WebDriverExtension {
function createExtension(perfRecords: any[] = null): WebDriverExtension {
if (isBlank(perfRecords)) {
perfRecords = [];
}
@ -38,14 +38,16 @@ export function main() {
expect(() => createExtension().gc()).toThrowError('Force GC is not supported on iOS');
});
it('should mark the timeline via console.time()', inject([AsyncTestCompleter], (async) => {
it('should mark the timeline via console.time()',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension().timeBegin('someName').then((_) => {
expect(log).toEqual([['executeScript', `console.time('someName');`]]);
async.done();
});
}));
it('should mark the timeline via console.timeEnd()', inject([AsyncTestCompleter], (async) => {
it('should mark the timeline via console.timeEnd()',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension().timeEnd('someName', null).then((_) => {
expect(log).toEqual([['executeScript', `console.timeEnd('someName');`]]);
async.done();
@ -53,7 +55,7 @@ export function main() {
}));
it('should mark the timeline via console.time() and console.timeEnd()',
inject([AsyncTestCompleter], (async) => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension().timeEnd('name1', 'name2').then((_) => {
expect(log).toEqual(
[['executeScript', `console.timeEnd('name1');console.time('name2');`]]);
@ -64,7 +66,7 @@ export function main() {
describe('readPerfLog', () => {
it('should execute a dummy script before reading them',
inject([AsyncTestCompleter], (async) => {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
// TODO(tbosch): This seems to be a bug in ChromeDriver:
// Sometimes it does not report the newest events of the performance log
// to the WebDriver client unless a script is executed...
@ -74,28 +76,31 @@ export function main() {
});
}));
it('should report FunctionCall records as "script"', inject([AsyncTestCompleter], (async) => {
it('should report FunctionCall records as "script"',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([durationRecord('FunctionCall', 1, 5)]).readPerfLog().then((events) => {
expect(events).toEqual([normEvents.start('script', 1), normEvents.end('script', 5)]);
async.done();
});
}));
it('should ignore FunctionCalls from webdriver', inject([AsyncTestCompleter], (async) => {
it('should ignore FunctionCalls from webdriver',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([internalScriptRecord(1, 5)]).readPerfLog().then((events) => {
expect(events).toEqual([]);
async.done();
});
}));
it('should report begin time', inject([AsyncTestCompleter], (async) => {
it('should report begin time', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([timeBeginRecord('someName', 12)]).readPerfLog().then((events) => {
expect(events).toEqual([normEvents.markStart('someName', 12)]);
async.done();
});
}));
it('should report end timestamps', inject([AsyncTestCompleter], (async) => {
it('should report end timestamps',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([timeEndRecord('someName', 12)]).readPerfLog().then((events) => {
expect(events).toEqual([normEvents.markEnd('someName', 12)]);
async.done();
@ -104,7 +109,8 @@ export function main() {
['RecalculateStyles', 'Layout', 'UpdateLayerTree', 'Paint', 'Rasterize', 'CompositeLayers']
.forEach((recordType) => {
it(`should report ${recordType}`, inject([AsyncTestCompleter], (async) => {
it(`should report ${recordType}`,
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([durationRecord(recordType, 0, 1)])
.readPerfLog()
.then((events) => {
@ -118,7 +124,7 @@ export function main() {
});
it('should walk children', inject([AsyncTestCompleter], (async) => {
it('should walk children', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([durationRecord('FunctionCall', 1, 5, [timeBeginRecord('someName', 2)])])
.readPerfLog()
.then((events) => {
@ -141,22 +147,22 @@ export function main() {
});
}
function timeBeginRecord(name, time) {
function timeBeginRecord(name: string, time: number) {
return {'type': 'Time', 'startTime': time, 'data': {'message': name}};
}
function timeEndRecord(name, time) {
function timeEndRecord(name: string, time: number) {
return {'type': 'TimeEnd', 'startTime': time, 'data': {'message': name}};
}
function durationRecord(type, startTime, endTime, children = null) {
function durationRecord(type: string, startTime: number, endTime: number, children: any[] = null) {
if (isBlank(children)) {
children = [];
}
return {'type': type, 'startTime': startTime, 'endTime': endTime, 'children': children};
}
function internalScriptRecord(startTime, endTime) {
function internalScriptRecord(startTime: number, endTime: number) {
return {
'type': 'FunctionCall',
'startTime': startTime,
@ -168,12 +174,12 @@ function internalScriptRecord(startTime, endTime) {
class MockDriverAdapter extends WebDriverAdapter {
constructor(private _log: any[], private _perfRecords: any[]) { super(); }
executeScript(script) {
executeScript(script: string) {
this._log.push(['executeScript', script]);
return Promise.resolve(null);
}
logs(type) {
logs(type: string) {
this._log.push(['logs', type]);
if (type === 'performance') {
return Promise.resolve(this._perfRecords.map(function(record) {

View File

@ -0,0 +1,26 @@
{
"compilerOptions": {
"module": "commonjs",
"target": "es5",
"lib": ["es6", "dom"],
"noImplicitAny": true,
"sourceMap": true,
"baseUrl": ".",
"paths": {
"@angular/core": ["../../../dist/packages-dist/core"]
},
"experimentalDecorators": true,
"rootDir": ".",
"sourceRoot": ".",
"outDir": "../../../dist/packages-dist/benchpress",
"declaration": true,
"skipLibCheck": true
},
"exclude": ["integrationtest"],
"files": [
"index.ts",
"../../../node_modules/@types/node/index.d.ts",
"../../../node_modules/@types/jasmine/index.d.ts",
"../../../node_modules/zone.js/dist/zone.js.d.ts"
]
}

View File

@ -6,25 +6,14 @@
* found in the LICENSE file at https://angular.io/license
*/
import {NgModule} from '@angular/core';
import {COMMON_DIRECTIVES} from './src/common_directives';
import {COMMON_PIPES} from './src/pipes';
export * from './src/pipes';
export * from './src/directives';
export * from './src/forms-deprecated';
export * from './src/common_directives';
/**
* @module
* @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';
// Note: This does not contain the location providers,
// as they need some platform specific implementations to work.
/**
* The module that includes all the basic Angular directives like {@link NgIf}, ${link NgFor}, ...
*
* @experimental
*/
@NgModule(
{declarations: [COMMON_DIRECTIVES, COMMON_PIPES], exports: [COMMON_DIRECTIVES, COMMON_PIPES]})
export class CommonModule {
}
export {NgClass, NgFor, NgIf, NgPlural, NgPluralCase, NgStyle, NgSwitch, NgSwitchCase, NgSwitchDefault, NgTemplateOutlet} from './src/directives/index';
export {AsyncPipe, DatePipe, I18nPluralPipe, I18nSelectPipe, JsonPipe, LowerCasePipe, CurrencyPipe, DecimalPipe, PercentPipe, SlicePipe, UpperCasePipe} from './src/pipes/index';

View File

@ -1,9 +1,9 @@
{
"name": "@angular/common",
"version": "0.0.0-PLACEHOLDER",
"description": "",
"main": "index.js",
"jsnext:main": "esm/index.js",
"description": "Angular - commonly needed directives and services",
"main": "bundles/common.umd.js",
"module": "index.js",
"typings": "index.d.ts",
"author": "angular",
"license": "MIT",

View File

@ -0,0 +1,13 @@
export default {
entry: '../../../dist/packages-dist/common/testing/index.js',
dest: '../../../dist/packages-dist/common/bundles/common-testing.umd.js',
format: 'umd',
moduleName: 'ng.common.testing',
globals: {
'@angular/core': 'ng.core',
'@angular/common': 'ng.common',
'rxjs/Observable': 'Rx',
'rxjs/Subject': 'Rx'
}
}

View File

@ -1,17 +1,12 @@
export default {
entry: '../../../dist/packages-dist/common/esm/index.js',
dest: '../../../dist/packages-dist/common/esm/common.umd.js',
entry: '../../../dist/packages-dist/common/index.js',
dest: '../../../dist/packages-dist/common/bundles/common.umd.js',
format: 'umd',
moduleName: 'ng.common',
globals: {
'@angular/core': 'ng.core',
'rxjs/Subject': 'Rx',
'rxjs/observable/PromiseObservable': 'Rx', // this is wrong, but this stuff has changed in rxjs b.6 so we need to fix it when we update.
'rxjs/operator/toPromise': 'Rx.Observable.prototype',
'rxjs/Observable': 'Rx'
},
plugins: [
// nodeResolve({ jsnext: true, main: true }),
]
'rxjs/Observable': 'Rx',
'rxjs/Subject': 'Rx'
}
}

View File

@ -1,58 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Type} from '@angular/core';
import {CORE_DIRECTIVES} from './directives';
/**
* A collection of Angular core directives that are likely to be used in each and every Angular
* application. This includes core directives (e.g., NgIf and NgFor), and forms directives (e.g.,
* NgModel).
*
* This collection can be used to quickly enumerate all the built-in directives in the `directives`
* property of the `@Component` decorator.
*
* ### Example
*
* Instead of writing:
*
* ```typescript
* import {NgClass, NgIf, NgFor, NgSwitch, NgSwitchWhen, NgSwitchDefault, NgModel, NgForm} from
* '@angular/common';
* import {OtherDirective} from './myDirectives';
*
* @Component({
* selector: 'my-component',
* templateUrl: 'myComponent.html',
* directives: [NgClass, NgIf, NgFor, NgSwitch, NgSwitchWhen, NgSwitchDefault, NgModel, NgForm,
* OtherDirective]
* })
* export class MyComponent {
* ...
* }
* ```
* one could import all the common directives at once:
*
* ```typescript
* import {COMMON_DIRECTIVES} from '@angular/common';
* import {OtherDirective} from './myDirectives';
*
* @Component({
* selector: 'my-component',
* templateUrl: 'myComponent.html',
* directives: [COMMON_DIRECTIVES, OtherDirective]
* })
* export class MyComponent {
* ...
* }
* ```
*
* @experimental Contains forms which are experimental.
*/
export const COMMON_DIRECTIVES: Type[][] = [CORE_DIRECTIVES];

View File

@ -0,0 +1,30 @@
/**
* @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 {NgModule} from '@angular/core';
import {COMMON_DIRECTIVES} from './directives/index';
import {NgLocaleLocalization, NgLocalization} from './localization';
import {COMMON_PIPES} from './pipes/index';
// Note: This does not contain the location providers,
// as they need some platform specific implementations to work.
/**
* The module that includes all the basic Angular directives like {@link NgIf}, {@link NgFor}, ...
*
* @stable
*/
@NgModule({
declarations: [COMMON_DIRECTIVES, COMMON_PIPES],
exports: [COMMON_DIRECTIVES, COMMON_PIPES],
providers: [
{provide: NgLocalization, useClass: NgLocaleLocalization},
],
})
export class CommonModule {
}

View File

@ -1,21 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
/**
* @module
* @description
* Common directives shipped with Angular.
*/
export {CORE_DIRECTIVES} from './directives/core_directives';
export {NgClass} from './directives/ng_class';
export {NgFor} from './directives/ng_for';
export {NgIf} from './directives/ng_if';
export {NgPlural, NgPluralCase} from './directives/ng_plural';
export {NgStyle} from './directives/ng_style';
export {NgSwitch, NgSwitchCase, NgSwitchDefault} from './directives/ng_switch';
export {NgTemplateOutlet} from './directives/ng_template_outlet';

View File

@ -1,72 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Type} from '../facade/lang';
import {NgClass} from './ng_class';
import {NgFor} from './ng_for';
import {NgIf} from './ng_if';
import {NgPlural, NgPluralCase} from './ng_plural';
import {NgStyle} from './ng_style';
import {NgSwitch, NgSwitchCase, NgSwitchDefault} from './ng_switch';
import {NgTemplateOutlet} from './ng_template_outlet';
/**
* A collection of Angular core directives that are likely to be used in each and every Angular
* application.
*
* This collection can be used to quickly enumerate all the built-in directives in the `directives`
* property of the `@Component` annotation.
*
* ### Example ([live demo](http://plnkr.co/edit/yakGwpCdUkg0qfzX5m8g?p=preview))
*
* Instead of writing:
*
* ```typescript
* import {NgClass, NgIf, NgFor, NgSwitch, NgSwitchWhen, NgSwitchDefault} from '@angular/common';
* import {OtherDirective} from './myDirectives';
*
* @Component({
* selector: 'my-component',
* templateUrl: 'myComponent.html',
* directives: [NgClass, NgIf, NgFor, NgSwitch, NgSwitchWhen, NgSwitchDefault, OtherDirective]
* })
* export class MyComponent {
* ...
* }
* ```
* one could import all the core directives at once:
*
* ```typescript
* import {CORE_DIRECTIVES} from '@angular/common';
* import {OtherDirective} from './myDirectives';
*
* @Component({
* selector: 'my-component',
* templateUrl: 'myComponent.html',
* directives: [CORE_DIRECTIVES, OtherDirective]
* })
* export class MyComponent {
* ...
* }
* ```
*
* @stable
*/
export const CORE_DIRECTIVES: Type[] = [
NgClass,
NgFor,
NgIf,
NgTemplateOutlet,
NgStyle,
NgSwitch,
NgSwitchCase,
NgSwitchDefault,
NgPlural,
NgPluralCase,
];

View File

@ -0,0 +1,47 @@
/**
* @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 {Provider} from '@angular/core';
import {NgClass} from './ng_class';
import {NgFor} from './ng_for';
import {NgIf} from './ng_if';
import {NgPlural, NgPluralCase} from './ng_plural';
import {NgStyle} from './ng_style';
import {NgSwitch, NgSwitchCase, NgSwitchDefault} from './ng_switch';
import {NgTemplateOutlet} from './ng_template_outlet';
export {
NgClass,
NgFor,
NgIf,
NgPlural,
NgPluralCase,
NgStyle,
NgSwitch,
NgSwitchCase,
NgSwitchDefault,
NgTemplateOutlet
};
/**
* A collection of Angular directives that are likely to be used in each and every Angular
* application.
*/
export const COMMON_DIRECTIVES: Provider[] = [
NgClass,
NgFor,
NgIf,
NgTemplateOutlet,
NgStyle,
NgSwitch,
NgSwitchCase,
NgSwitchDefault,
NgPlural,
NgPluralCase,
];

View File

@ -8,70 +8,35 @@
import {CollectionChangeRecord, Directive, DoCheck, ElementRef, Input, IterableDiffer, IterableDiffers, KeyValueChangeRecord, KeyValueDiffer, KeyValueDiffers, Renderer} from '@angular/core';
import {StringMapWrapper, isListLikeIterable} from '../facade/collection';
import {isArray, isPresent, isString} from '../facade/lang';
import {isListLikeIterable} from '../facade/collection';
import {isPresent} from '../facade/lang';
/**
* The `NgClass` directive conditionally adds and removes CSS classes on an HTML element based on
* an expression's evaluation result.
* @ngModule CommonModule
*
* The result of an expression evaluation is interpreted differently depending on type of
* the expression evaluation result:
* - `string` - all the CSS classes listed in a string (space delimited) are added
* - `Array` - all the CSS classes (Array elements) are added
* - `Object` - each key corresponds to a CSS class name while values are interpreted as expressions
* evaluating to `Boolean`. If a given expression evaluates to `true` a corresponding CSS class
* is added - otherwise it is removed.
*
* While the `NgClass` directive can interpret expressions evaluating to `string`, `Array`
* or `Object`, the `Object`-based version is the most often used and has an advantage of keeping
* all the CSS class names in a template.
*
* ### Example ([live demo](http://plnkr.co/edit/a4YdtmWywhJ33uqfpPPn?p=preview)):
* @whatItDoes Adds and removes CSS classes on an HTML element.
*
* @howToUse
* ```
* import {Component} from '@angular/core';
* import {NgClass} from '@angular/common';
* <some-element [ngClass]="'first second'">...</some-element>
*
* @Component({
* selector: 'toggle-button',
* inputs: ['isDisabled'],
* template: `
* <div class="button" [ngClass]="{active: isOn, disabled: isDisabled}"
* (click)="toggle(!isOn)">
* Click me!
* </div>`,
* styles: [`
* .button {
* width: 120px;
* border: medium solid black;
* }
* <some-element [ngClass]="['first', 'second']">...</some-element>
*
* .active {
* background-color: red;
* }
* <some-element [ngClass]="{'first': true, 'second': true, 'third': false}">...</some-element>
*
* .disabled {
* color: gray;
* border: medium solid gray;
* }
* `],
* directives: [NgClass]
* })
* class ToggleButton {
* isOn = false;
* isDisabled = false;
*
* toggle(newState) {
* if (!this.isDisabled) {
* this.isOn = newState;
* }
* }
* }
* <some-element [ngClass]="stringExp|arrayExp|objExp">...</some-element>
* ```
*
* @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.
*
* @stable
*/
@Directive({selector: '[ngClass]'})
@ -79,7 +44,7 @@ export class NgClass implements DoCheck {
private _iterableDiffer: IterableDiffer;
private _keyValueDiffer: KeyValueDiffer;
private _initialClasses: string[] = [];
private _rawClass: string[]|Set<string>;
private _rawClass: string[]|Set<string>|{[klass: string]: any};
constructor(
private _iterableDiffers: IterableDiffers, private _keyValueDiffers: KeyValueDiffers,
@ -87,58 +52,57 @@ export class NgClass implements DoCheck {
@Input('class')
set initialClasses(v: string) {
set klass(v: string) {
this._applyInitialClasses(true);
this._initialClasses = isPresent(v) && isString(v) ? v.split(' ') : [];
this._initialClasses = typeof v === 'string' ? v.split(/\s+/) : [];
this._applyInitialClasses(false);
this._applyClasses(this._rawClass, false);
}
@Input()
set ngClass(v: string|string[]|Set<string>|{[key: string]: any}) {
set ngClass(v: string|string[]|Set<string>|{[klass: string]: any}) {
this._cleanupClasses(this._rawClass);
if (isString(v)) {
v = (<string>v).split(' ');
}
this._rawClass = <string[]|Set<string>>v;
this._iterableDiffer = null;
this._keyValueDiffer = null;
if (isPresent(v)) {
if (isListLikeIterable(v)) {
this._iterableDiffer = this._iterableDiffers.find(v).create(null);
this._rawClass = typeof v === 'string' ? v.split(/\s+/) : v;
if (this._rawClass) {
if (isListLikeIterable(this._rawClass)) {
this._iterableDiffer = this._iterableDiffers.find(this._rawClass).create(null);
} else {
this._keyValueDiffer = this._keyValueDiffers.find(v).create(null);
this._keyValueDiffer = this._keyValueDiffers.find(this._rawClass).create(null);
}
}
}
ngDoCheck(): void {
if (isPresent(this._iterableDiffer)) {
var changes = this._iterableDiffer.diff(this._rawClass);
if (isPresent(changes)) {
if (this._iterableDiffer) {
const changes = this._iterableDiffer.diff(this._rawClass);
if (changes) {
this._applyIterableChanges(changes);
}
}
if (isPresent(this._keyValueDiffer)) {
var changes = this._keyValueDiffer.diff(this._rawClass);
if (isPresent(changes)) {
} else if (this._keyValueDiffer) {
const changes = this._keyValueDiffer.diff(this._rawClass);
if (changes) {
this._applyKeyValueChanges(changes);
}
}
}
private _cleanupClasses(rawClassVal: string[]|Set<string>|{[key: string]: any}): void {
private _cleanupClasses(rawClassVal: string[]|Set<string>|{[klass: string]: any}): void {
this._applyClasses(rawClassVal, true);
this._applyInitialClasses(false);
}
private _applyKeyValueChanges(changes: any): void {
changes.forEachAddedItem(
(record: KeyValueChangeRecord) => { this._toggleClass(record.key, record.currentValue); });
(record: KeyValueChangeRecord) => this._toggleClass(record.key, record.currentValue));
changes.forEachChangedItem(
(record: KeyValueChangeRecord) => { this._toggleClass(record.key, record.currentValue); });
(record: KeyValueChangeRecord) => this._toggleClass(record.key, record.currentValue));
changes.forEachRemovedItem((record: KeyValueChangeRecord) => {
if (record.previousValue) {
this._toggleClass(record.key, false);
@ -148,42 +112,34 @@ export class NgClass implements DoCheck {
private _applyIterableChanges(changes: any): void {
changes.forEachAddedItem(
(record: CollectionChangeRecord) => { this._toggleClass(record.item, true); });
(record: CollectionChangeRecord) => this._toggleClass(record.item, true));
changes.forEachRemovedItem(
(record: CollectionChangeRecord) => { this._toggleClass(record.item, false); });
(record: CollectionChangeRecord) => this._toggleClass(record.item, false));
}
private _applyInitialClasses(isCleanup: boolean) {
this._initialClasses.forEach(className => this._toggleClass(className, !isCleanup));
this._initialClasses.forEach(klass => this._toggleClass(klass, !isCleanup));
}
private _applyClasses(
rawClassVal: string[]|Set<string>|{[key: string]: any}, isCleanup: boolean) {
if (isPresent(rawClassVal)) {
if (isArray(rawClassVal)) {
(<string[]>rawClassVal).forEach(className => this._toggleClass(className, !isCleanup));
} else if (rawClassVal instanceof Set) {
(<Set<string>>rawClassVal).forEach(className => this._toggleClass(className, !isCleanup));
if (rawClassVal) {
if (Array.isArray(rawClassVal) || rawClassVal instanceof Set) {
(<any>rawClassVal).forEach((klass: string) => this._toggleClass(klass, !isCleanup));
} else {
StringMapWrapper.forEach(
<{[k: string]: any}>rawClassVal, (expVal: any, className: string) => {
if (isPresent(expVal)) this._toggleClass(className, !isCleanup);
});
Object.keys(rawClassVal).forEach(klass => {
if (isPresent(rawClassVal[klass])) this._toggleClass(klass, !isCleanup);
});
}
}
}
private _toggleClass(className: string, enabled: boolean): void {
className = className.trim();
if (className.length > 0) {
if (className.indexOf(' ') > -1) {
var classes = className.split(/\s+/g);
for (var i = 0, len = classes.length; i < len; i++) {
this._renderer.setElementClass(this._ngEl.nativeElement, classes[i], enabled);
}
} else {
this._renderer.setElementClass(this._ngEl.nativeElement, className, enabled);
}
private _toggleClass(klass: string, enabled: boolean): void {
klass = klass.trim();
if (klass) {
klass.split(/\s+/g).forEach(
klass => { this._renderer.setElementClass(this._ngEl.nativeElement, klass, enabled); });
}
}
}

View File

@ -8,8 +8,7 @@
import {ChangeDetectorRef, CollectionChangeRecord, DefaultIterableDiffer, Directive, DoCheck, EmbeddedViewRef, Input, IterableDiffer, IterableDiffers, OnChanges, SimpleChanges, TemplateRef, TrackByFn, ViewContainerRef} from '@angular/core';
import {BaseException} from '../facade/exceptions';
import {getTypeNameForDebugging, isBlank, isPresent} from '../facade/lang';
import {getTypeNameForDebugging} from '../facade/lang';
export class NgForRow {
constructor(public $implicit: any, public index: number, public count: number) {}
@ -63,11 +62,22 @@ export class NgForRow {
* elements were deleted and all new elements inserted). This is an expensive operation and should
* be avoided if possible.
*
* To customize the default tracking algorithm, `NgFor` supports `trackBy` option.
* `trackBy` takes a function which has two arguments: `index` and `item`.
* If `trackBy` is given, Angular tracks changes by the return value of the function.
*
* ### Syntax
*
* - `<li *ngFor="let item of items; let i = index">...</li>`
* - `<li template="ngFor let item of items; let i = index">...</li>`
* - `<template ngFor let-item [ngForOf]="items" let-i="index"><li>...</li></template>`
* - `<li *ngFor="let item of items; let i = index; trackBy: trackByFn">...</li>`
* - `<li template="ngFor let item of items; let i = index; trackBy: trackByFn">...</li>`
*
* With `<template>` element:
*
* ```
* <template ngFor let-item [ngForOf]="items" let-i="index" [ngForTrackBy]="trackByFn">
* <li>...</li>
* </template>
* ```
*
* ### Example
*
@ -81,16 +91,16 @@ export class NgFor implements DoCheck, OnChanges {
@Input() ngForOf: any;
@Input() ngForTrackBy: TrackByFn;
private _differ: IterableDiffer;
private _differ: IterableDiffer = null;
constructor(
private _viewContainer: ViewContainerRef, private _templateRef: TemplateRef<NgForRow>,
private _iterableDiffers: IterableDiffers, private _cdr: ChangeDetectorRef) {}
private _viewContainer: ViewContainerRef, private _template: TemplateRef<NgForRow>,
private _differs: IterableDiffers, private _cdr: ChangeDetectorRef) {}
@Input()
set ngForTemplate(value: TemplateRef<NgForRow>) {
if (isPresent(value)) {
this._templateRef = value;
if (value) {
this._template = value;
}
}
@ -98,11 +108,11 @@ export class NgFor implements DoCheck, OnChanges {
if ('ngForOf' in changes) {
// React on ngForOf changes only once all inputs have been initialized
const value = changes['ngForOf'].currentValue;
if (isBlank(this._differ) && isPresent(value)) {
if (!this._differ && value) {
try {
this._differ = this._iterableDiffers.find(value).create(this._cdr, this.ngForTrackBy);
this._differ = this._differs.find(value).create(this._cdr, this.ngForTrackBy);
} catch (e) {
throw new BaseException(
throw new Error(
`Cannot find a differ supporting object '${value}' of type '${getTypeNameForDebugging(value)}'. NgFor only supports binding to Iterables such as Arrays.`);
}
}
@ -110,9 +120,9 @@ export class NgFor implements DoCheck, OnChanges {
}
ngDoCheck() {
if (isPresent(this._differ)) {
if (this._differ) {
const changes = this._differ.diff(this.ngForOf);
if (isPresent(changes)) this._applyChanges(changes);
if (changes) this._applyChanges(changes);
}
}
@ -121,16 +131,16 @@ export class NgFor implements DoCheck, OnChanges {
changes.forEachOperation(
(item: CollectionChangeRecord, adjustedPreviousIndex: number, currentIndex: number) => {
if (item.previousIndex == null) {
let view = this._viewContainer.createEmbeddedView(
this._templateRef, new NgForRow(null, null, null), currentIndex);
let tuple = new RecordViewTuple(item, view);
const view = this._viewContainer.createEmbeddedView(
this._template, new NgForRow(null, null, null), currentIndex);
const tuple = new RecordViewTuple(item, view);
insertTuples.push(tuple);
} else if (currentIndex == null) {
this._viewContainer.remove(adjustedPreviousIndex);
} else {
let view = this._viewContainer.get(adjustedPreviousIndex);
const view = this._viewContainer.get(adjustedPreviousIndex);
this._viewContainer.move(view, currentIndex);
let tuple = new RecordViewTuple(item, <EmbeddedViewRef<NgForRow>>view);
const tuple = new RecordViewTuple(item, <EmbeddedViewRef<NgForRow>>view);
insertTuples.push(tuple);
}
});
@ -140,13 +150,13 @@ export class NgFor implements DoCheck, OnChanges {
}
for (let i = 0, ilen = this._viewContainer.length; i < ilen; i++) {
var viewRef = <EmbeddedViewRef<NgForRow>>this._viewContainer.get(i);
let viewRef = <EmbeddedViewRef<NgForRow>>this._viewContainer.get(i);
viewRef.context.index = i;
viewRef.context.count = ilen;
}
changes.forEachIdentityChange((record: any) => {
var viewRef = <EmbeddedViewRef<NgForRow>>this._viewContainer.get(record.currentIndex);
let viewRef = <EmbeddedViewRef<NgForRow>>this._viewContainer.get(record.currentIndex);
viewRef.context.$implicit = record.item;
});
}

View File

@ -8,10 +8,6 @@
import {Directive, Input, TemplateRef, ViewContainerRef} from '@angular/core';
import {isBlank} from '../facade/lang';
/**
* Removes or recreates a portion of the DOM tree based on an {expression}.
*
@ -38,18 +34,17 @@ import {isBlank} from '../facade/lang';
*/
@Directive({selector: '[ngIf]'})
export class NgIf {
private _prevCondition: boolean = null;
private _hasView: boolean = false;
constructor(private _viewContainer: ViewContainerRef, private _templateRef: TemplateRef<Object>) {
}
constructor(private _viewContainer: ViewContainerRef, private _template: TemplateRef<Object>) {}
@Input()
set ngIf(newCondition: any) {
if (newCondition && (isBlank(this._prevCondition) || !this._prevCondition)) {
this._prevCondition = true;
this._viewContainer.createEmbeddedView(this._templateRef);
} else if (!newCondition && (isBlank(this._prevCondition) || this._prevCondition)) {
this._prevCondition = false;
set ngIf(condition: any) {
if (condition && !this._hasView) {
this._hasView = true;
this._viewContainer.createEmbeddedView(this._template);
} else if (!condition && this._hasView) {
this._hasView = false;
this._viewContainer.clear();
}
}

View File

@ -6,65 +6,43 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Attribute, Directive, Host, Input, OnInit, TemplateRef, ViewContainerRef} from '@angular/core';
import {Attribute, Directive, Host, Input, TemplateRef, ViewContainerRef} from '@angular/core';
import {isPresent} from '../facade/lang';
import {NgLocalization, getPluralCategory} from '../localization';
import {SwitchView} from './ng_switch';
/**
* `ngPlural` is an i18n directive that displays DOM sub-trees that match the switch expression
* value, or failing that, DOM sub-trees that match the switch expression's pluralization category.
* @ngModule CommonModule
*
* To use this directive, you must provide an extension of `NgLocalization` that maps values to
* category names. You then define a container element that sets the `[ngPlural]` attribute to a
* switch expression.
* - Inner elements defined with an `[ngPluralCase]` attribute will display based on their
* expression.
* - If `[ngPluralCase]` is set to a value starting with `=`, it will only display if the value
* matches the switch expression exactly.
* - Otherwise, the view will be treated as a "category match", and will only display if exact
* value matches aren't found and the value maps to its category using the `getPluralCategory`
* function provided.
*
* ```typescript
* class MyLocalization extends NgLocalization {
* getPluralCategory(value: any) {
* if(value < 5) {
* return 'few';
* }
* }
* }
*
* @Component({
* selector: 'app',
* providers: [{provide: NgLocalization, useClass: MyLocalization}]
* })
* @View({
* template: `
* <p>Value = {{value}}</p>
* <button (click)="inc()">Increment</button>
*
* <div [ngPlural]="value">
* <template ngPluralCase="=0">there is nothing</template>
* <template ngPluralCase="=1">there is one</template>
* <template ngPluralCase="few">there are a few</template>
* <template ngPluralCase="other">there is some number</template>
* </div>
* `,
* directives: [NgPlural, NgPluralCase]
* })
* export class App {
* value = 'init';
*
* inc() {
* this.value = this.value === 'init' ? 0 : this.value + 1;
* }
* }
* @whatItDoes Adds / removes DOM sub-trees based on a numeric value. Tailored for pluralization.
*
* @howToUse
* ```
* <some-element [ngPlural]="value">
* <ng-container *ngPluralCase="'=0'">there is nothing</ng-container>
* <ng-container *ngPluralCase="'=1'">there is one</ng-container>
* <ng-container *ngPluralCase="'few'">there are a few</ng-container>
* <ng-container *ngPluralCase="'other'">there are exactly #</ng-container>
* </some-element>
* ```
*
* @description
*
* Displays DOM sub-trees that match the switch expression value, or failing that, DOM sub-trees
* that match the switch expression's pluralization category.
*
* To use this directive you must provide a container element that sets the `[ngPlural]` attribute
* to a switch expression. Inner elements with a `[ngPluralCase]` will display based on their
* expression:
* - if `[ngPluralCase]` is set to a value starting with `=`, it will only display if the value
* matches the switch expression exactly,
* - otherwise, the view will be treated as a "category match", and will only display if exact
* value matches aren't found and the value maps to its category for the defined locale.
*
* See http://cldr.unicode.org/index/cldr-spec/plural-rules
*
* @experimental
*/
@Directive({selector: '[ngPlural]'})
@ -83,29 +61,42 @@ export class NgPlural {
addCase(value: string, switchView: SwitchView): void { this._caseViews[value] = switchView; }
/** @internal */
_updateView(): void {
private _updateView(): void {
this._clearViews();
var key =
getPluralCategory(this._switchValue, Object.keys(this._caseViews), this._localization);
const cases = Object.keys(this._caseViews);
const key = getPluralCategory(this._switchValue, cases, this._localization);
this._activateView(this._caseViews[key]);
}
/** @internal */
_clearViews() {
if (isPresent(this._activeView)) this._activeView.destroy();
private _clearViews() {
if (this._activeView) this._activeView.destroy();
}
/** @internal */
_activateView(view: SwitchView) {
if (!isPresent(view)) return;
this._activeView = view;
this._activeView.create();
private _activateView(view: SwitchView) {
if (view) {
this._activeView = view;
this._activeView.create();
}
}
}
/**
* @ngModule CommonModule
*
* @whatItDoes Creates a view that will be added/removed from the parent {@link NgPlural} when the
* given expression matches the plural expression according to CLDR rules.
*
* @howToUse
* ```
* <some-element [ngPlural]="value">
* <ng-container *ngPluralCase="'=0'">...</ng-container>
* <ng-container *ngPluralCase="'other'">...</ng-container>
* </some-element>
*```
*
* See {@link NgPlural} for more details and example.
*
* @experimental
*/
@Directive({selector: '[ngPluralCase]'})

View File

@ -8,70 +8,32 @@
import {Directive, DoCheck, ElementRef, Input, KeyValueChangeRecord, KeyValueDiffer, KeyValueDiffers, Renderer} from '@angular/core';
import {isBlank, isPresent} from '../facade/lang';
/**
* The `NgStyle` directive changes styles based on a result of expression evaluation.
* @ngModule CommonModule
*
* An expression assigned to the `ngStyle` property must evaluate to an object and the
* corresponding element styles are updated based on changes to this object. Style names to update
* are taken from the object's keys, and values - from the corresponding object's values.
*
* ### Syntax
*
* - `<div [ngStyle]="{'font-style': styleExp}"></div>`
* - `<div [ngStyle]="{'max-width.px': widthExp}"></div>`
* - `<div [ngStyle]="styleExp"></div>` - here the `styleExp` must evaluate to an object
*
* ### Example ([live demo](http://plnkr.co/edit/YamGS6GkUh9GqWNQhCyM?p=preview)):
* @whatItDoes Update an HTML element styles.
*
* @howToUse
* ```
* import {Component} from '@angular/core';
* import {NgStyle} from '@angular/common';
* <some-element [ngStyle]="{'font-style': styleExp}">...</some-element>
*
* @Component({
* selector: 'ngStyle-example',
* template: `
* <h1 [ngStyle]="{'font-style': style, 'font-size': size, 'font-weight': weight}">
* Change style of this text!
* </h1>
* <some-element [ngStyle]="{'max-width.px': widthExp}">...</some-element>
*
* <hr>
*
* <label>Italic: <input type="checkbox" (change)="changeStyle($event)"></label>
* <label>Bold: <input type="checkbox" (change)="changeWeight($event)"></label>
* <label>Size: <input type="text" [value]="size" (change)="size = $event.target.value"></label>
* `,
* directives: [NgStyle]
* })
* export class NgStyleExample {
* style = 'normal';
* weight = 'normal';
* size = '20px';
*
* changeStyle($event: any) {
* this.style = $event.target.checked ? 'italic' : 'normal';
* }
*
* changeWeight($event: any) {
* this.weight = $event.target.checked ? 'bold' : 'normal';
* }
* }
* <some-element [ngStyle]="objExp">...</some-element>
* ```
*
* In this example the `font-style`, `font-size` and `font-weight` styles will be updated
* based on the `style` property's value changes.
* @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'),
* - values are the values assigned to those properties (expressed in the given unit).
*
* @stable
*/
@Directive({selector: '[ngStyle]'})
export class NgStyle implements DoCheck {
/** @internal */
_ngStyle: {[key: string]: string};
/** @internal */
_differ: KeyValueDiffer;
private _ngStyle: {[key: string]: string};
private _differ: KeyValueDiffer;
constructor(
private _differs: KeyValueDiffers, private _ngEl: ElementRef, private _renderer: Renderer) {}
@ -79,34 +41,34 @@ export class NgStyle implements DoCheck {
@Input()
set ngStyle(v: {[key: string]: string}) {
this._ngStyle = v;
if (isBlank(this._differ) && isPresent(v)) {
this._differ = this._differs.find(this._ngStyle).create(null);
if (!this._differ && v) {
this._differ = this._differs.find(v).create(null);
}
}
ngDoCheck() {
if (isPresent(this._differ)) {
var changes = this._differ.diff(this._ngStyle);
if (isPresent(changes)) {
if (this._differ) {
const changes = this._differ.diff(this._ngStyle);
if (changes) {
this._applyChanges(changes);
}
}
}
private _applyChanges(changes: any): void {
changes.forEachRemovedItem(
(record: KeyValueChangeRecord) => { this._setStyle(record.key, null); });
changes.forEachRemovedItem((record: KeyValueChangeRecord) => this._setStyle(record.key, null));
changes.forEachAddedItem(
(record: KeyValueChangeRecord) => { this._setStyle(record.key, record.currentValue); });
(record: KeyValueChangeRecord) => this._setStyle(record.key, record.currentValue));
changes.forEachChangedItem(
(record: KeyValueChangeRecord) => { this._setStyle(record.key, record.currentValue); });
(record: KeyValueChangeRecord) => this._setStyle(record.key, record.currentValue));
}
private _setStyle(name: string, val: string): void {
const nameParts = name.split('.');
const nameToSet = nameParts[0];
const valToSet = isPresent(val) && nameParts.length === 2 ? `${val}${nameParts[1]}` : val;
private _setStyle(nameAndUnit: string, value: string): void {
const [name, unit] = nameAndUnit.split('.');
value = value !== null && value !== void(0) && unit ? `${value}${unit}` : value;
this._renderer.setElementStyle(this._ngEl.nativeElement, nameToSet, valToSet);
this._renderer.setElementStyle(this._ngEl.nativeElement, name, value);
}
}

View File

@ -9,13 +9,9 @@
import {Directive, Host, Input, TemplateRef, ViewContainerRef} from '@angular/core';
import {ListWrapper} from '../facade/collection';
import {isBlank, isPresent, normalizeBlank} from '../facade/lang';
const _CASE_DEFAULT = new Object();
// TODO: remove when fully deprecated
let _warned: boolean = false;
export class SwitchView {
constructor(
private _viewContainerRef: ViewContainerRef, private _templateRef: TemplateRef<Object>) {}
@ -26,62 +22,46 @@ export class SwitchView {
}
/**
* Adds or removes DOM sub-trees when their match expressions match the switch expression.
* @ngModule CommonModule
*
* Elements within `NgSwitch` but without `NgSwitchCase` or `NgSwitchDefault` directives will be
* preserved at the location as specified in the template.
* @whatItDoes Adds / removes DOM sub-trees when the nest match expressions matches the switch
* expression.
*
* `NgSwitch` simply inserts nested elements based on which match expression matches the value
* obtained from the evaluated switch expression. In other words, you define a container element
* (where you place the directive with a switch expression on the
* `[ngSwitch]="..."` attribute), define any inner elements inside of the directive and
* place a `[ngSwitchCase]` attribute per element.
*
* The `ngSwitchCase` property is used to inform `NgSwitch` which element to display when the
* expression is evaluated. If a matching expression is not found via a `ngSwitchCase` property
* then an element with the `ngSwitchDefault` attribute is displayed.
*
* ### Example ([live demo](http://plnkr.co/edit/DQMTII95CbuqWrl3lYAs?p=preview))
*
* ```typescript
* @Component({
* selector: 'app',
* template: `
* <p>Value = {{value}}</p>
* <button (click)="inc()">Increment</button>
*
* <div [ngSwitch]="value">
* <p *ngSwitchCase="'init'">increment to start</p>
* <p *ngSwitchCase="0">0, increment again</p>
* <p *ngSwitchCase="1">1, increment again</p>
* <p *ngSwitchCase="2">2, stop incrementing</p>
* <p *ngSwitchDefault>&gt; 2, STOP!</p>
* </div>
*
* <!-- alternate syntax -->
*
* <p [ngSwitch]="value">
* <template ngSwitchCase="init">increment to start</template>
* <template [ngSwitchCase]="0">0, increment again</template>
* <template [ngSwitchCase]="1">1, increment again</template>
* <template [ngSwitchCase]="2">2, stop incrementing</template>
* <template ngSwitchDefault>&gt; 2, STOP!</template>
* </p>
* `,
* directives: [NgSwitch, NgSwitchCase, NgSwitchDefault]
* })
* export class App {
* value = 'init';
*
* inc() {
* this.value = this.value === 'init' ? 0 : this.value + 1;
* }
* }
*
* bootstrap(App).catch(err => console.error(err));
* @howToUse
* ```
* <container-element [ngSwitch]="switch_expression">
* <some-element *ngSwitchCase="match_expression_1">...</some-element>
* <some-element *ngSwitchCase="match_expression_2">...</some-element>
* <some-other-element *ngSwitchCase="match_expression_3">...</some-other-element>
* <ng-container *ngSwitchCase="match_expression_3">
* <!-- use a ng-container to group multiple root nodes -->
* <inner-element></inner-element>
* <inner-other-element></inner-other-element>
* </ng-container>
* <some-element *ngSwitchDefault>...</p>
* </container-element>
* ```
* @description
*
* @experimental
* `NgSwitch` stamps out nested views when their match expression value matches the value of the
* switch expression.
*
* In other words:
* - you define a container element (where you place the directive with a switch expression on the
* `[ngSwitch]="..."` attribute)
* - you define inner views inside the `NgSwitch` and place a `*ngSwitchCase` attribute on the view
* root elements.
*
* Elements within `NgSwitch` but outside of a `NgSwitchCase` or `NgSwitchDefault` directives will
* be
* preserved at the location.
*
* The `ngSwitchCase` directive informs the parent `NgSwitch` of which view to display when the
* expression is evaluated.
* When no matching expression is found on a `ngSwitchCase` view, the `ngSwitchDefault` view is
* stamped out.
*
* @stable
*/
@Directive({selector: '[ngSwitch]'})
export class NgSwitch {
@ -97,10 +77,10 @@ export class NgSwitch {
// Add the ViewContainers matching the value (with a fallback to default)
this._useDefault = false;
var views = this._valueViews.get(value);
if (isBlank(views)) {
let views = this._valueViews.get(value);
if (!views) {
this._useDefault = true;
views = normalizeBlank(this._valueViews.get(_CASE_DEFAULT));
views = this._valueViews.get(_CASE_DEFAULT) || null;
}
this._activateViews(views);
@ -131,19 +111,16 @@ export class NgSwitch {
}
}
/** @internal */
_emptyAllActiveViews(): void {
var activeContainers = this._activeViews;
private _emptyAllActiveViews(): void {
const activeContainers = this._activeViews;
for (var i = 0; i < activeContainers.length; i++) {
activeContainers[i].destroy();
}
this._activeViews = [];
}
/** @internal */
_activateViews(views: SwitchView[]): void {
// TODO(vicb): assert(this._activeViews.length === 0);
if (isPresent(views)) {
private _activateViews(views: SwitchView[]): void {
if (views) {
for (var i = 0; i < views.length; i++) {
views[i].create();
}
@ -153,19 +130,18 @@ export class NgSwitch {
/** @internal */
_registerView(value: any, view: SwitchView): void {
var views = this._valueViews.get(value);
if (isBlank(views)) {
let views = this._valueViews.get(value);
if (!views) {
views = [];
this._valueViews.set(value, views);
}
views.push(view);
}
/** @internal */
_deregisterView(value: any, view: SwitchView): void {
private _deregisterView(value: any, view: SwitchView): void {
// `_CASE_DEFAULT` is used a marker for non-registered cases
if (value === _CASE_DEFAULT) return;
var views = this._valueViews.get(value);
const views = this._valueViews.get(value);
if (views.length == 1) {
this._valueViews.delete(value);
} else {
@ -175,22 +151,34 @@ export class NgSwitch {
}
/**
* Insert the sub-tree when the `ngSwitchCase` expression evaluates to the same value as the
* enclosing switch expression.
* @ngModule CommonModule
*
* If multiple match expression match the switch expression value, all of them are displayed.
* @whatItDoes Creates a view that will be added/removed from the parent {@link NgSwitch} when the
* given expression evaluate to respectively the same/different value as the switch
* expression.
*
* @howToUse
* ```
* <container-element [ngSwitch]="switch_expression">
* <some-element *ngSwitchCase="match_expression_1">...</some-element>
* </container-element>
*```
* @description
*
* Insert the sub-tree when the expression evaluates to the same value as the enclosing switch
* expression.
*
* If multiple match expressions match the switch expression value, all of them are displayed.
*
* See {@link NgSwitch} for more details and example.
*
* @experimental
* @stable
*/
@Directive({selector: '[ngSwitchCase],[ngSwitchWhen]'})
@Directive({selector: '[ngSwitchCase]'})
export class NgSwitchCase {
// `_CASE_DEFAULT` is used as a marker for a not yet initialized value
/** @internal */
_value: any = _CASE_DEFAULT;
/** @internal */
_view: SwitchView;
private _value: any = _CASE_DEFAULT;
private _view: SwitchView;
private _switch: NgSwitch;
constructor(
@ -205,25 +193,30 @@ export class NgSwitchCase {
this._switch._onCaseValueChanged(this._value, value, this._view);
this._value = value;
}
@Input()
set ngSwitchWhen(value: any) {
if (!_warned) {
_warned = true;
console.warn('*ngSwitchWhen is deprecated and will be removed. Use *ngSwitchCase instead');
}
this._switch._onCaseValueChanged(this._value, value, this._view);
this._value = value;
}
}
/**
* Default case statements are displayed when no match expression matches the switch expression
* value.
* @ngModule CommonModule
* @whatItDoes Creates a view that is added to the parent {@link NgSwitch} when no case expressions
* match the
* switch expression.
*
* @howToUse
* ```
* <container-element [ngSwitch]="switch_expression">
* <some-element *ngSwitchCase="match_expression_1">...</some-element>
* <some-other-element *ngSwitchDefault>...</some-other-element>
* </container-element>
* ```
*
* @description
*
* Insert the sub-tree when no case expressions evaluate to the same value as the enclosing switch
* expression.
*
* See {@link NgSwitch} for more details and example.
*
* @experimental
* @stable
*/
@Directive({selector: '[ngSwitchDefault]'})
export class NgSwitchDefault {

View File

@ -6,24 +6,28 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Directive, EmbeddedViewRef, Input, OnChanges, TemplateRef, ViewContainerRef} from '@angular/core';
import {Directive, EmbeddedViewRef, Input, OnChanges, SimpleChanges, TemplateRef, ViewContainerRef} from '@angular/core';
/**
* Creates and inserts an embedded view based on a prepared `TemplateRef`.
* You can attach a context object to the `EmbeddedViewRef` by setting `[ngOutletContext]`.
* `[ngOutletContext]` should be an object, the object's keys will be the local template variables
* available within the `TemplateRef`.
* @ngModule CommonModule
*
* Note: using the key `$implicit` in the context object will set it's value as default.
*
* ### Syntax
* @whatItDoes Inserts an embedded view from a prepared `TemplateRef`
*
* @howToUse
* ```
* <template [ngTemplateOutlet]="templateRefExpression"
* [ngOutletContext]="objectExpression">
* </template>
* ```
*
* @description
*
* You can attach a context object to the `EmbeddedViewRef` by setting `[ngOutletContext]`.
* `[ngOutletContext]` should be an object, the object's keys will be the local template variables
* available within the `TemplateRef`.
*
* Note: using the key `$implicit` in the context object will set it's value as default.
*
* @experimental
*/
@Directive({selector: '[ngTemplateOutlet]'})
@ -40,7 +44,7 @@ export class NgTemplateOutlet implements OnChanges {
@Input()
set ngTemplateOutlet(templateRef: TemplateRef<Object>) { this._templateRef = templateRef; }
ngOnChanges() {
ngOnChanges(changes: SimpleChanges) {
if (this._viewRef) {
this._viewContainerRef.remove(this._viewContainerRef.indexOf(this._viewRef));
}

View File

@ -1,75 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
/**
* @module
* @description
* This module is used for handling user input, by defining and building a {@link ControlGroup} that
* consists of
* {@link Control} objects, and mapping them onto the DOM. {@link Control} objects can then be used
* to read information
* from the form DOM elements.
*
* Forms providers are not included in default providers; you must import these providers
* explicitly.
*/
import {NgModule, Type} from '@angular/core';
import {FORM_DIRECTIVES} from './forms-deprecated/directives';
import {RadioControlRegistry} from './forms-deprecated/directives/radio_control_value_accessor';
import {FormBuilder} from './forms-deprecated/form_builder';
export {FORM_DIRECTIVES, RadioButtonState} from './forms-deprecated/directives';
export {AbstractControlDirective} from './forms-deprecated/directives/abstract_control_directive';
export {CheckboxControlValueAccessor} from './forms-deprecated/directives/checkbox_value_accessor';
export {ControlContainer} from './forms-deprecated/directives/control_container';
export {ControlValueAccessor, NG_VALUE_ACCESSOR} from './forms-deprecated/directives/control_value_accessor';
export {DefaultValueAccessor} from './forms-deprecated/directives/default_value_accessor';
export {Form} from './forms-deprecated/directives/form_interface';
export {NgControl} from './forms-deprecated/directives/ng_control';
export {NgControlGroup} from './forms-deprecated/directives/ng_control_group';
export {NgControlName} from './forms-deprecated/directives/ng_control_name';
export {NgControlStatus} from './forms-deprecated/directives/ng_control_status';
export {NgForm} from './forms-deprecated/directives/ng_form';
export {NgFormControl} from './forms-deprecated/directives/ng_form_control';
export {NgFormModel} from './forms-deprecated/directives/ng_form_model';
export {NgModel} from './forms-deprecated/directives/ng_model';
export {NgSelectOption, SelectControlValueAccessor} from './forms-deprecated/directives/select_control_value_accessor';
export {MaxLengthValidator, MinLengthValidator, PatternValidator, RequiredValidator, Validator} from './forms-deprecated/directives/validators';
export {FormBuilder} from './forms-deprecated/form_builder';
export {AbstractControl, Control, ControlArray, ControlGroup} from './forms-deprecated/model';
export {NG_ASYNC_VALIDATORS, NG_VALIDATORS, Validators} from './forms-deprecated/validators';
/**
* Shorthand set of providers used for building Angular forms.
*
* ### Example
*
* ```typescript
* bootstrap(MyApp, [FORM_PROVIDERS]);
* ```
*
* @experimental
*/
export const FORM_PROVIDERS: Type[] = [FormBuilder, RadioControlRegistry];
/**
* The ng module for the deprecated forms API.
* @deprecated
*/
@NgModule({
providers: [
FORM_PROVIDERS,
],
declarations: FORM_DIRECTIVES,
exports: FORM_DIRECTIVES
})
export class DeprecatedFormsModule {
}

View File

@ -1,84 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Type} from '@angular/core';
import {CheckboxControlValueAccessor} from './directives/checkbox_value_accessor';
import {DefaultValueAccessor} from './directives/default_value_accessor';
import {NgControlGroup} from './directives/ng_control_group';
import {NgControlName} from './directives/ng_control_name';
import {NgControlStatus} from './directives/ng_control_status';
import {NgForm} from './directives/ng_form';
import {NgFormControl} from './directives/ng_form_control';
import {NgFormModel} from './directives/ng_form_model';
import {NgModel} from './directives/ng_model';
import {NumberValueAccessor} from './directives/number_value_accessor';
import {RadioControlValueAccessor} from './directives/radio_control_value_accessor';
import {NgSelectOption, SelectControlValueAccessor} from './directives/select_control_value_accessor';
import {NgSelectMultipleOption, SelectMultipleControlValueAccessor} from './directives/select_multiple_control_value_accessor';
import {MaxLengthValidator, MinLengthValidator, PatternValidator, RequiredValidator} from './directives/validators';
export {CheckboxControlValueAccessor} from './directives/checkbox_value_accessor';
export {ControlValueAccessor} from './directives/control_value_accessor';
export {DefaultValueAccessor} from './directives/default_value_accessor';
export {NgControl} from './directives/ng_control';
export {NgControlGroup} from './directives/ng_control_group';
export {NgControlName} from './directives/ng_control_name';
export {NgControlStatus} from './directives/ng_control_status';
export {NgForm} from './directives/ng_form';
export {NgFormControl} from './directives/ng_form_control';
export {NgFormModel} from './directives/ng_form_model';
export {NgModel} from './directives/ng_model';
export {NumberValueAccessor} from './directives/number_value_accessor';
export {RadioButtonState, RadioControlValueAccessor} from './directives/radio_control_value_accessor';
export {NgSelectOption, SelectControlValueAccessor} from './directives/select_control_value_accessor';
export {NgSelectMultipleOption, SelectMultipleControlValueAccessor} from './directives/select_multiple_control_value_accessor';
export {MaxLengthValidator, MinLengthValidator, PatternValidator, RequiredValidator} from './directives/validators';
/**
*
* A list of all the form directives used as part of a `@Component` annotation.
*
* This is a shorthand for importing them each individually.
*
* ### Example
*
* ```typescript
* @Component({
* selector: 'my-app',
* directives: [FORM_DIRECTIVES]
* })
* class MyApp {}
* ```
* @experimental
*/
export const FORM_DIRECTIVES: Type[] = [
NgControlName,
NgControlGroup,
NgFormControl,
NgModel,
NgFormModel,
NgForm,
NgSelectOption,
NgSelectMultipleOption,
DefaultValueAccessor,
NumberValueAccessor,
CheckboxControlValueAccessor,
SelectControlValueAccessor,
SelectMultipleControlValueAccessor,
RadioControlValueAccessor,
NgControlStatus,
RequiredValidator,
MinLengthValidator,
MaxLengthValidator,
PatternValidator,
];

View File

@ -1,41 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {unimplemented} from '../../facade/exceptions';
import {isPresent} from '../../facade/lang';
import {AbstractControl} from '../model';
/**
* Base class for control directives.
*
* Only used internally in the forms module.
*
* @experimental
*/
export abstract class AbstractControlDirective {
get control(): AbstractControl { return unimplemented(); }
get value(): any { return isPresent(this.control) ? this.control.value : null; }
get valid(): boolean { return isPresent(this.control) ? this.control.valid : null; }
get errors(): {[key: string]: any} {
return isPresent(this.control) ? this.control.errors : null;
}
get pristine(): boolean { return isPresent(this.control) ? this.control.pristine : null; }
get dirty(): boolean { return isPresent(this.control) ? this.control.dirty : null; }
get touched(): boolean { return isPresent(this.control) ? this.control.touched : null; }
get untouched(): boolean { return isPresent(this.control) ? this.control.untouched : null; }
get path(): string[] { return null; }
}

View File

@ -1,46 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Directive, ElementRef, Renderer, forwardRef} from '@angular/core';
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor';
export const CHECKBOX_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => CheckboxControlValueAccessor),
multi: true
};
/**
* The accessor for writing a value and listening to changes on a checkbox input element.
*
* ### Example
* ```
* <input type="checkbox" ngControl="rememberLogin">
* ```
*
* @experimental
*/
@Directive({
selector:
'input[type=checkbox][ngControl],input[type=checkbox][ngFormControl],input[type=checkbox][ngModel]',
host: {'(change)': 'onChange($event.target.checked)', '(blur)': 'onTouched()'},
providers: [CHECKBOX_VALUE_ACCESSOR]
})
export class CheckboxControlValueAccessor implements ControlValueAccessor {
onChange = (_: any) => {};
onTouched = () => {};
constructor(private _renderer: Renderer, private _elementRef: ElementRef) {}
writeValue(value: any): void {
this._renderer.setElementProperty(this._elementRef.nativeElement, 'checked', value);
}
registerOnChange(fn: (_: any) => {}): void { this.onChange = fn; }
registerOnTouched(fn: () => {}): void { this.onTouched = fn; }
}

View File

@ -1,32 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {AbstractControlDirective} from './abstract_control_directive';
import {Form} from './form_interface';
/**
* A directive that contains multiple {@link NgControl}s.
*
* Only used by the forms module.
*
* @experimental
*/
export class ControlContainer extends AbstractControlDirective {
name: string;
/**
* Get the form to which this container belongs.
*/
get formDirective(): Form { return null; }
/**
* Get the path to this container.
*/
get path(): string[] { return null; }
}

View File

@ -1,44 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {OpaqueToken} from '@angular/core';
/**
* A bridge between a control and a native element.
*
* A `ControlValueAccessor` abstracts the operations of writing a new value to a
* DOM element representing an input control.
*
* Please see {@link DefaultValueAccessor} for more information.
*
* @experimental
*/
export interface ControlValueAccessor {
/**
* Write a new value to the element.
*/
writeValue(obj: any): void;
/**
* Set the function to be called when the control receives a change event.
*/
registerOnChange(fn: any): void;
/**
* Set the function to be called when the control receives a touch event.
*/
registerOnTouched(fn: any): void;
}
/**
* Used to provide a {@link ControlValueAccessor} for form controls.
*
* See {@link DefaultValueAccessor} for how to implement one.
* @experimental
*/
export const NG_VALUE_ACCESSOR: OpaqueToken = new OpaqueToken('NgValueAccessor');

View File

@ -1,54 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Directive, ElementRef, Renderer, forwardRef} from '@angular/core';
import {isBlank} from '../../facade/lang';
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor';
export const DEFAULT_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => DefaultValueAccessor),
multi: true
};
/**
* The default accessor for writing a value and listening to changes that is used by the
* {@link NgModel}, {@link NgFormControl}, and {@link NgControlName} directives.
*
* ### Example
* ```
* <input type="text" ngControl="searchQuery">
* ```
*
* @experimental
*/
@Directive({
selector:
'input:not([type=checkbox])[ngControl],textarea[ngControl],input:not([type=checkbox])[ngFormControl],textarea[ngFormControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]',
// TODO: vsavkin replace the above selector with the one below it once
// https://github.com/angular/angular/issues/3011 is implemented
// selector: '[ngControl],[ngModel],[ngFormControl]',
host: {'(input)': 'onChange($event.target.value)', '(blur)': 'onTouched()'},
providers: [DEFAULT_VALUE_ACCESSOR]
})
export class DefaultValueAccessor implements ControlValueAccessor {
onChange = (_: any) => {};
onTouched = () => {};
constructor(private _renderer: Renderer, private _elementRef: ElementRef) {}
writeValue(value: any): void {
var normalizedValue = isBlank(value) ? '' : value;
this._renderer.setElementProperty(this._elementRef.nativeElement, 'value', normalizedValue);
}
registerOnChange(fn: (_: any) => void): void { this.onChange = fn; }
registerOnTouched(fn: () => void): void { this.onTouched = fn; }
}

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