Compare commits

..

281 Commits

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

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

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

BREAKING CHANGE:

Four newly added APIs in 2.2.0-beta:
downgradeComponent, downgradeInjectable, UpgradeComponent, and UpgradeModule
are no longer exported by @angular/upgrade.
Import these from @angular/upgrade/static instead.
2016-10-26 15:14:22 -07:00
7742ec00e7 fix: remove double exports of template_ast 2016-10-26 15:14:00 -07:00
2b5c983c13 docs(reset): change semi-colon to colon in code example
The first code example for the reset function was invalid as it has a semi-colon instead of a colon for the last property in the json object.  Change the semi-colon to a colon.

Closes https://github.com/angular/angular/issues/12531
2016-10-26 14:56:57 -07:00
ef153649b3 fix(compiler-cli): fix types 2016-10-26 14:56:27 -07:00
d321b0ebf5 fix(selectors): use Maps instead of objects 2016-10-26 14:55:59 -07:00
b4265e0685 fix(xsrf): overwrite already set xsrf header 2016-10-26 14:55:24 -07:00
178fb79b5c refactor(compiler): move host properties into DirectiveWrapper
Part of #11683
2016-10-26 14:32:24 -07:00
5a7a58b1e0 refactor(compiler): make arguments in InlineArray optional. 2016-10-26 14:32:24 -07:00
f66ac821a2 refactor(compiler): extract createCheckBindingStmt into compiler_util
Part of #11683
2016-10-26 14:32:24 -07:00
fe299f4dfc refactor(compiler): minor cleanups 2016-10-26 14:32:24 -07:00
4cac650675 refactor(compiler): extract expression evaluation and writing to renderer from view_compiler
This is needed to that `DirectiveWrapper`s can also use them later on.

Part of #11683
2016-10-26 14:32:24 -07:00
cb7643ccea refactor(compiler): introduce ClassBuilder.
Part of #11683
2016-10-26 14:32:23 -07:00
faa3478514 refactor(compiler): set element attributes via one call
This makes the cost of using directives that have host attributes
smaller.

Part of #11683
2016-10-26 14:32:23 -07:00
bc3f4bc816 refactor(compiler): extract BindingParser
Needed so that we can parse directive host bindings independent of templates.

Part of #11683
2016-10-26 14:32:23 -07:00
c9f58cf78c feat(router): export routerLinkActive w/ isActive property 2016-10-26 14:08:22 -07:00
6ccbfd41dd fix(router): preserve resolve data
Closes #12306
2016-10-26 13:53:00 -07:00
7d2554baa1 tests(router): add a test showing how to handle resovle errors 2016-10-26 13:52:59 -07:00
52a853e257 fix(router): change router not to deactivate aux routes when navigating from a componentless routes 2016-10-26 13:52:59 -07:00
8f2fa0f766 fix(router): disallow component routes with named outlets
Closes #11208, #11082
2016-10-26 13:52:59 -07:00
fc60fa790c fix(router): add a test to make sure canDeactivate guards are called for aux routes
Closes #11345
2016-10-26 13:52:58 -07:00
b74185369f fix(router): canDeactivate guards are not triggered for componentless routes
Closes #12375
2016-10-26 13:52:58 -07:00
7221632228 fix(CompilerCli): assert that all pipes and directives are declared by a module 2016-10-25 18:17:18 -07:00
02f1222a8d docs(common): minor corrections/improvements for NgClass (#12327) 2016-10-25 00:12:09 +02:00
c27ce7318f doc(compiler-cli): align example with style guide (#12414)
See The Angular Style Guide, [Section 2.2 - Separate File Names with Dots and Dashes](https://angular.io/docs/ts/latest/guide/style-guide.html#!#02-02)
2016-10-25 00:10:03 +02:00
a838aba756 fix(compiler): walk third party modules (#12453)
fixes #11889
fixes #12428
2016-10-24 22:28:23 +02:00
bfc97ff2cd refactor(i18n): extract Extractor from extract_i18n (#12417)
I put an extractor into your extract so you can extract while you
extract.

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

The refactoring causes no function change.
2016-10-21 15:17:57 -07:00
57051f01ce refactor: remove most facades (#12399) 2016-10-21 15:14:44 -07:00
e319cfefc3 docs(changelog): fix minor typo (#12429) 2016-10-21 14:27:07 -07:00
444014ad96 docs(changelog): add 2.1.1 changelog 2016-10-20 15:49:59 -07:00
867494a060 fix(compiler): don't access view local variables nor pipes in host expressions (#12396)
Fixes #12004
Closes #12071
2016-10-20 15:24:58 -07:00
69ad99dca6 chore(release): cut the 2.2.0-beta.0 release and add changelog 2016-10-20 14:36:46 -07:00
da5fc696bb fix(router): do not update primary route if only secondary outlet is given (#11797) 2016-10-20 10:59:08 -07:00
b44b6ef8f5 fix(router): module loader should start compiling modules when stubbedModules are set (#11742) 2016-10-20 10:58:53 -07:00
0f21a5823b cleanup(router): add a test verifying than NavigationEnd is not emitted after NavigationCancel 2016-10-20 10:56:12 -07:00
5ae6915600 fix(router): fix lazy loading triggered by redirects from wildcard routes
Closes #12183
2016-10-20 10:56:12 -07:00
8b9ab44eee feat(router): add support for ng1/ng2 migration (#12160) 2016-10-20 10:44:44 -07:00
b0a03fcab3 refactor(compiler): introduce directive wrappers to generate less code
- for now only wraps the `@Input` properties and calls
  to `ngOnInit`, `ngDoCheck` and `ngOnChanges` of directives.
- also groups eval sources by NgModule.

Part of #11683
2016-10-20 10:41:43 -07:00
c951822c35 refactor(compiler): don’t use the OfflineCompiler in extract_i18n 2016-10-20 10:41:43 -07:00
acda82c1ed refactor(compiler): remove private exports
All of `@angular/compiler` is private, so we can export
everything we need directly.
2016-10-20 10:41:43 -07:00
a8815d6b08 chore(ci): re-enable browserstack tests in ci 2016-10-20 10:01:51 -07:00
d6791ff0e0 feat(ngUpgrade): add support for AoT compiled upgrade applications
This commit introduces a new API to the ngUpgrade module, which is compatible
with AoT compilation. Primarily, it removes the dependency on reflection
over the Angular 2 metadata by introducing an API where this information
is explicitly defined, in the source code, in a way that is not lost through
AoT compilation.

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

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

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

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

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

Before:

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

After:

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

Fixes #7255
2016-10-19 09:49:02 -07:00
24facdea2d feat(benchmark): add large form benchmark
This benchmark tracks the generated file size for large forms
as well as the time to create and destroy many form fields.
2016-10-19 09:39:16 -07:00
aa2d3372a5 fix(benchmarks): fix method name in targetable spec 2016-10-19 09:39:16 -07:00
bf60418fdc feat(forms): Validator.pattern accepts a RegExp (#12323) 2016-10-19 09:37:54 -07:00
cca4a5c519 fix(compiler): don't redeclare a var in the same scope (#12386)
This is not allowed by Closure Compiler.
2016-10-18 20:28:30 -07:00
6e5f8b59b3 fix(animations): generate aot code for animation trigger output events (#12291)
Closes #11707
Closes #12291
2016-10-18 17:16:51 -07:00
8409b65153 fix(http): make normalizeMethodName optimizer-compatible. (#12370)
`normalizeMethodName` reflectively accessed the RequestMethod enum. With a smart
optimizer, properties from the enum could be removed or renamed, and so user
code just passing in e.g. 'PATCH' might not work. This change fixes the code to
be more explicit and avoids the optimizer issue.
2016-10-18 11:21:54 -07:00
38e2203b24 refactor(core): delete unused reflector code 2016-10-17 23:17:34 -07:00
bd1dcb5f11 fix(core): fix decorator defalut values 2016-10-17 23:17:34 -07:00
3993279527 fix(core): fix property decorators
fixes #12224
2016-10-17 23:17:34 -07:00
bf1e2613b2 refactor(core): cleanup decorators 2016-10-17 23:17:34 -07:00
f7db0668d1 refactor(core): simplify & cleanup reflection 2016-10-17 23:17:34 -07:00
27d76776b8 fix(router): correctly export filter operator in es5 (#12286) 2016-10-17 23:06:19 -07:00
8603d9c269 refactor(http): use Http.request for all http shorthand methods (#12319) 2016-10-17 23:04:25 -07:00
d55f747858 docs(router): attribute notation for string paths (#12205)
Either bind an expression or use the attribute notation.
The mixed way `[routerLink]="/path"` won't work.
Prefer the attribute notation for string-only paths
2016-10-17 22:53:55 -07:00
52de0fa558 docs(CONTRIBUTING.md): fix typo (reproductions --> reproduction) (#12230) 2016-10-17 22:52:44 -07:00
d61ecf0663 docs(NgSwitch): fix mismatched tags in example (#12270) 2016-10-17 22:51:56 -07:00
5a9c5f28b8 docs(CHANGELOG.md): remove incorrect link (#12259) 2016-10-17 22:51:44 -07:00
15fc5dd7ee test(forms): added missing selfOnly tests (#12317) 2016-10-17 22:51:13 -07:00
a5419608e0 docs(ngIf): minor improvements 2016-10-17 22:50:12 -07:00
5f95bf1dd2 refactor(common): remove redundant type 2016-10-17 22:50:12 -07:00
33c8948fd3 refactor(animations): ensure animation data-structures are created only when used
Closes #12250
2016-10-14 15:43:41 -07:00
606e51881a perf(benchmarks): update ng2-switch to match ng2
- use the ~same template layout (text nodes),
- use trackBy

both benchmark now show about the same perfs.
2016-10-12 17:11:46 -07:00
fdf4309b50 perf(common): optimize NgSwitch default case
relates to #11297
2016-10-12 17:11:46 -07:00
af996ef0c4 docs(changelog): fix typo in code name, ouch! 2016-10-12 14:05:48 -07:00
68d2dfdd2a docs(changelog): tweak the change log and group all the 2.1 changes together 2016-10-12 13:54:21 -07:00
07bd4b0630 chore: bump version number and generate CHANGELOG (#12247) 2016-10-12 13:19:31 -07:00
df1718d624 fix(compiler): allow WS as <ng-content> content (#12225) 2016-10-12 07:58:06 -07:00
17e3410d98 Form submit event (#11989)
* feat(forms): ngSubmit event exposes $event from original submit event as local variable

Modify NgForm directive and FormGroup directive to expose the original submit event as $event in the ngSubmit event. Modify docs to reflect changes.

This resolves #10920.

* refactor: code cleanup
2016-10-11 15:49:36 -07:00
5effc330ed feat(upgrade): compilerOptions in bootstrap (#10575) 2016-10-11 15:48:08 -07:00
3df00828d7 docs(router): fix CanActivateChild API docs (#12128)
fixes #12127
2016-10-11 15:47:57 -07:00
8c477b2f45 fix(compiler-cli): don't clone static symbols when simplifying annotation metadata (#12158) 2016-10-11 15:47:44 -07:00
7787771aba refactor(core): cleanup decorators.ts (#12161) 2016-10-11 15:47:20 -07:00
7275e1beb3 refactor(compiler): add optional visit() to TemplateAstVisitor (#12209) 2016-10-11 15:46:11 -07:00
12ba62e5e2 refactor(compiler): expose template parser phases (#12210) 2016-10-11 15:45:27 -07:00
e6e007e2f1 refactor(core): cleanup SpyObject (#12221) 2016-10-11 15:44:48 -07:00
91dd138fa5 docs(animations): document :enter and :leave transition aliases (#12222) 2016-10-11 15:44:38 -07:00
d972d82354 refactor: simplify isPresent(x) ? x : y to x || y (#12166)
Closes #12166
2016-10-10 09:20:58 -07:00
bdcf46f82e refactor(compiler): improve types, misc 2016-10-10 09:20:58 -07:00
79e1c7b807 refactor(upgrade): unify spec code (#12190)
- replace all variable declarations using 'var' by 'const' or 'let'
- replace es5 function declaration by arrow function where applicable
2016-10-10 09:18:33 -07:00
d22eeb70b8 fix(forms): allow optional fields with pattern and minlength validators (#12147) 2016-10-10 09:17:45 -07:00
aa92512ac6 fix(compiler): properly shim :host:before and :host(:before) (#12171)
fixes #12165
2016-10-10 09:15:15 -07:00
f782b08f58 docs: Minor typo fix (#12151) 2016-10-10 09:14:35 -07:00
4202936bbf refactor(compiler): add optional visit() to html AST Visitor (#12135) 2016-10-10 09:13:50 -07:00
e1faca6386 refactor(compiler): template element ast has endSourceSpan (#12138) 2016-10-10 09:12:05 -07:00
f5b0e22d35 docs(public_api): fix missing backtick 2016-10-07 17:23:08 -07:00
00693d70a2 docs: add PUBLIC_API.md 2016-10-07 14:29:16 -07:00
bcef5efffe fix(platform-browser-dynamic): mark platformBrowserDynamic as stable API (#12154)
Everyone building Angular apps need to use this api to bootstrap or AoT compile, so it can't be experimental.
2016-10-07 13:54:06 -07:00
13ecc140e8 fix(compiler): validate @HostBinding name (#12139)
relates to #7500
2016-10-07 13:53:53 -07:00
709a6dea06 refactor(compiler): attribute ast records span of the value (#12132) 2016-10-07 13:53:29 -07:00
16cfb88c00 refactor(compiler): refactor analyzeModules() out of OfflineCompiler (#12137) 2016-10-07 13:52:53 -07:00
efee6f5199 docs(saved-replies): order the replies as shown in github (#12153)
github sorts the replies by reply name.
2016-10-07 13:52:18 -07:00
2aa8aae76d docs(saved-replies): add document with saved replies for our issue tracker 2016-10-07 09:21:20 -07:00
afb4bd9ef6 refactor(NgZone): merge NgZoneImpl and NgZone (#12104) 2016-10-06 15:23:37 -07:00
d641c36a45 fix(compiler): interpolation expressions report the correct offset (#12125) 2016-10-06 15:22:10 -07:00
f4566f8128 fix(http): fix Headers initialization from Headers and Object (#12106) 2016-10-06 15:21:27 -07:00
a67c06708d fix(http): Headers.append should append to the list 2016-10-06 15:21:03 -07:00
d9d57d71dd refactor(http): move one Headers test inside the main describe 2016-10-06 15:21:03 -07:00
e06303a987 fix(router): improve error message (#12102) 2016-10-06 15:19:22 -07:00
40b92ddf21 fix(router): wildcards routes should support lazy loading
Closes #12024
2016-10-06 15:19:09 -07:00
1681e4f57f fix(router): parent resolve should complete before merging resolved data
Closes #12032
2016-10-06 15:19:09 -07:00
71b7654660 fix(compiler-cli): remove peerDependency on @angular/platform-server (#12122)
There is no runtime dependency from the compiler-cli on @angular/platform-server - it was most likely added to package.json by mistake.
2016-10-06 15:16:41 -07:00
eaaec6979c fix(compiler-cli): remove unused parse5 dependency from package.json
This was added in error or is an obsolete dependency. We don't need parse5 for the compiler-cli's runtime.
2016-10-06 15:16:22 -07:00
c587c63591 docs(changelog): fix mentions, backticks and a misplaced line ending (#12109)
* docs(changelog): fix mentions and backticks

`@page` and `@document` were both incorrectly linking to GitHub repositories.
`:enter` and `:leave` in the *Features* section were missing backticks.

* Fix misplaced line ending.
2016-10-06 15:12:41 -07:00
f50c1da4e2 fix(forms): properly validate blank strings with minlength (#12091) 2016-10-06 15:12:09 -07:00
0254ce1f6c refactor(core): simplify Reflector code, add types (#12099) 2016-10-06 15:11:16 -07:00
c9b765f5c0 refactor(compiler): module collector is reusable (#12095) 2016-10-06 15:10:44 -07:00
8c975ed156 refactor(facade): inline StringWrapper (#12051) 2016-10-06 15:10:27 -07:00
bb35fcb562 docs(contributing): remove references to Angular 2
It's just Angular.
2016-10-06 15:07:46 -07:00
57230b70a9 docs(contributing): update the "Submitting an Issue" section 2016-10-06 15:06:37 -07:00
43dc60ce4f docs(contributing): update "got a question or a problem" section
Inspired by: https://github.com/ng-bootstrap/ng-bootstrap#getting-help
2016-10-06 13:58:14 -07:00
230b3b73d8 chore(benchpress): fix the license (#12090)
It's not Apache MIT 2.0, that's a mishmash of Apache 2.0 and MIT
2016-10-06 10:24:01 -07:00
0b7dc2f9ff docs(RouterTestingModule) change modules to imports in example (#12118) 2016-10-06 10:22:39 -07:00
de1f44f51f fix(benchmarks): allow ng2_switch benchmark to be used with AoT. (#12124) 2016-10-06 10:22:08 -07:00
f1cfddf6d6 refactor(benchmarks): add index_aot to support AoT bootstrap. (#12105)
Note: This only make sure it can compile the AoT version, but does not yet use it in e2e tests.
2016-10-06 08:37:37 -07:00
ef621a2f00 docs(changelog): tweak changelog 2016-10-06 06:43:17 -07:00
df9761951b docs(changelog): added changelog for 2.1.0-rc.0 2016-10-05 16:48:22 -07:00
f786c560f1 doc(triage): add info about user pain, frequency and severity labels 2016-10-05 15:58:45 -07:00
c5557de3e7 doc(triage): correct existing incorrect info 2016-10-05 15:58:45 -07:00
ec3a5b54de docs(readme): remove incorrect download count badge
npm doesn't currently support download counts for scoped packages, so there is no replacement right now.
2016-10-05 11:37:28 -07:00
cf269d9ff4 refactor: add license header to JS files & format files (#12081) 2016-10-04 20:39:20 -07:00
5fa5ffb82a refactor(benchmarks): refactor to support AOT bootstrap in G3 (#12075) 2016-10-04 16:27:45 -07:00
4a57dcfd8d fix(forms): properly validate empty strings with patterns (#11450) 2016-10-04 16:14:23 -07:00
43923ffcf5 docs(traige): update triaging doc 2016-10-04 16:13:32 -07:00
50c37d45dc refactor: simplify arrow functions (#12057) 2016-10-04 15:57:37 -07:00
a63359689f fix(ShadowCss): fix attribute selectors in :host and :host-context (#12056)
Fix a regression introduced in #11917 while fixing #6249
2016-10-04 15:40:31 -07:00
43d3a84df3 Revert "refactor: add license header to JS files & format files (#12035)"
This reverts commit 8310c91823.
2016-10-04 14:06:41 -07:00
8310c91823 refactor: add license header to JS files & format files (#12035) 2016-10-04 13:15:49 -07:00
b64b5ece65 refactor(facade): Remove most of StringMapWrapper facade. (#12022)
This change mostly automated by
12012b07a2
with some manual fixes.
2016-10-03 16:46:05 -07:00
ed9c2b6281 fix(Header): preserve case of the first init, set() or append() (#12023)
fixes #11624
2016-10-03 15:27:56 -07:00
1cf5f5fa38 docs(NgModule): Fixed docs for NgModule.entryComponents (#12006)
* docs(NgModule): Corrected the wording of the documentation of `entryComponents`, fixed some minor grammar issues

* docs(NgModule): Remove redundant ComponentFactory mentions

* docs(NgModule): Restore ComponentFactory/ComponentResolver links
2016-10-03 10:19:03 -07:00
a32078f85e docs(DEVELOPER.md): fix typos on "Tests" section (#12029) 2016-10-02 14:19:47 -07:00
decd129a4d refactor(facade): remove DateWrapper (#12027) 2016-10-02 14:12:14 -07:00
c3c9ecb302 text(offline compiler): fix expected output 2016-09-30 17:59:43 -07:00
af520947aa test(AstSerializer): fix serializing void tags 2016-09-30 17:59:43 -07:00
040bf57966 fix(xlif): fix <x> ctype names
fixes #12000
see http://docs.oasis-open.org/xliff/v1.2/os/xliff-core.html#ctype
2016-09-30 17:59:43 -07:00
65a60b7456 style(I18N): Carriage returns in serialized files 2016-09-30 17:59:43 -07:00
756ef09d12 docs(gh): try to improve the issue template (#11891) 2016-09-30 16:40:56 -07:00
9316f95467 fix(ShadowCss): support @page and @document CSS rules (#11878)
fixes #11860
2016-09-30 16:26:24 -07:00
83d94b7504 fix(ShadowCss): support quoted attribute values
fixes #6085
2016-09-30 14:37:41 -07:00
a121136fae refactor(ShadowCss): add missing types 2016-09-30 14:37:41 -07:00
a6bb84e02b fix(ShadowCss): fix :host(tag) and :host-context(tag)
fixes #11972
2016-09-30 14:37:41 -07:00
3898dc488e fix(BrowserAdapter): correctly removes styles on IE
fixes #7916
2016-09-30 11:18:17 -07:00
ca3f9926f9 refactor(BrowserAdapter): cleanup 2016-09-30 11:18:17 -07:00
1c012a035f refactor(CssSelector): misc cleanup 2016-09-30 11:06:24 -07:00
38c5304b7f docs(CssSelector): [name*=value] is not supported
fixes #6042
2016-09-30 11:06:24 -07:00
9a049be67f feat(Parse5): update to the latest version 2.2.1
fixes #6237
2016-09-30 10:46:49 -07:00
2045c9e8ee docs: update docs for ng2_ftl benchmark 2016-09-30 10:42:21 -07:00
6c4ec05a4a fix(ShadowCss): support [attr="value with space"]
fixes #6249
2016-09-30 10:27:35 -07:00
f7bfda31ff refactor(ShadowCss): cleanup 2016-09-30 10:27:35 -07:00
a92b573309 test(DirectiveResolver): test that a prop can have both @Input and @HostBinding 2016-09-30 10:08:52 -07:00
4fd13d71c8 refactor(DirectiveResolver): cleanup 2016-09-30 10:08:52 -07:00
bf7b82b658 fix(UrlSearchParams): change a behavior when a param value is null or undefined (#11990) 2016-09-30 09:57:26 -07:00
c143fee849 refactor(routerLinkActive): optimised routerLinkActive active check code (#11968)
Modify routerLinkActive to optimise performance by removing unnecessary iteration. By replacing Array.reduce with Array.some, the loop will break when it finds an active link. Useful if used on the parent of a large group of routerLinks. Furthermore, if a RouterLink is active it will not check the RouterLinkWithHrefs.
2016-09-30 09:42:54 -07:00
0286956107 refactor(facade): Inline isBlank called with object-type argument (#11992) 2016-09-30 09:26:53 -07:00
e884f4854d feat(animations): provide aliases for :enter and :leave transitions (#11991) 2016-09-30 09:15:56 -07:00
df1822fc2a benchmarks: add ng2_ftl and ng2_switch_ftl benchmarks (#11963)
These benchmarks take the output of AoT
and manually tweaks it to explore possible
future changes to the compiler to produce
this output directly.
2016-09-30 09:09:31 -07:00
42b4b6d21b fix(upgrade): bind optional properties when upgrading from ng1 (#11411)
Previously, optional properties of a directive/component would be wrongly mapped and thus ignored.

Closes #10181
2016-09-29 09:45:28 -07:00
36bc2ff269 docs(forms): Added FormControl initialization information (#11948) 2016-09-28 13:59:08 -07:00
1564042fe8 fix(ngc): allow ReflectorHost passed as argument to CodeGenerator#create (#11951) 2016-09-27 17:12:57 -07:00
41c8c30973 chore(lint): remove unused imports (#11923)
This was done automatically by tslint, which can now fix issues it finds.
The fixer is still pending in PR https://github.com/palantir/tslint/pull/1568
Also I have a local bugfix for https://github.com/palantir/tslint/issues/1569
which causes too many imports to be deleted.
2016-09-27 17:12:25 -07:00
61129fa12d fix(compiler): move detection of unsafe properties for binding to ElementSchemaRegistry (#11378) 2016-09-27 17:10:02 -07:00
3a5b4882bc fix(compiler): Do not embed templateUrl in view factories in non-debug mode. (#11818)
Fixes #11117.
2016-09-27 17:09:44 -07:00
425c1e6042 refactor: remove dead code 2016-09-27 16:13:09 -07:00
58605cf350 refactor(facade): remove useless facades 2016-09-27 16:13:09 -07:00
34b31dea7c docs(upgrade): rename undeclared Ng2 to Ng2Component (#11950) 2016-09-27 16:11:41 -07:00
a241ab7c07 (docs): removing addProvider from UpgradeAdapter (#11934)
The `addProvider` function in the `UpgradeAdapter` was deprecated in this [commit](d21331e902 (diff-77163e956a7842149f583846c1c01651)) and has been removed in final. Given this, the documentation for downgrading ng2 providers for use in ng1 is invalid.
2016-09-27 10:10:45 -07:00
745e10e6d2 docs(router_config): add missing quote (#11925) 2016-09-27 10:10:12 -07:00
33340dbbd1 docs: remove outdated docs (#11875) 2016-09-24 08:23:28 +09:00
52812c08e2 chore(CHANGELOG): fix wrong issue link (#11871) 2016-09-24 07:13:24 +09:00
52f5ae1961 chore(compiler): followup fix for PR#11846 (#11870)
Original PR set [] to any, but any[], is a tighter type and still
works for SNC enabled consumers of the emit.
2016-09-24 07:13:05 +09:00
9be895b6da docs(ExceptionHandler): fix API docs (#11772)
fixes #11769
2016-09-24 07:05:43 +09:00
9f1c82537e ci(travis): increase node's heap size to prevent OOM on travis (#11869) 2016-09-24 06:04:29 +09:00
5ab5cc77bb Fix(http): invalidStateError if response body without content (#11786)
Fix(http): invalidStateError if response body without content
If the responseType has been specified and other than 'text', responseText throw an InvalidStateError exception

See XHR doc => https://xhr.spec.whatwg.org/#the-responsetext-attribute

Unit Test to prevent invalidStateError
2016-09-24 05:44:01 +09:00
f1b6c6efa1 refactor(animations): ensure animation input/outputs are managed within the template parser (#11782)
Closes #11782
Closes #11601
Related #11707
2016-09-24 05:37:04 +09:00
45ad13560b docs(changelog): remove info about an internal change 2016-09-23 12:02:56 -07:00
2045268cec chore(release): v2.1.0-beta.0 2016-09-23 11:41:35 -07:00
fb1076b44a docs(changelog): release notes for 2.1.0-beta.0 2016-09-23 11:37:28 -07:00
6fc46526ae fix(upgrade): allow attribute selectors for components in ng2 which are not part of upgrade (#11808)
fixes #11280
2016-09-24 02:47:16 +09:00
3ef5ede6d6 chore(compiler): emit ([] as any[]) instead of purely []. (#11846)
In SNC mode `[]` has type of never[], so we cast it to any[] to
typecheck correctly see
https://github.com/Microsoft/TypeScript/issues/10479.

This is temporary workaround, until we fully
migrate the framework to TS 2.0 and strictNullChecks.
2016-09-24 02:21:59 +09:00
136621ebc9 docs(Component): API docs for .encapsulation and .interpolation 2016-09-22 11:01:16 -07:00
f23b22a0f4 refactor: misc cleanup 2016-09-22 11:01:16 -07:00
0ca971c5bd refactor(common): cleanup (#11668) 2016-09-22 10:34:00 -07:00
3a6fcee0e6 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-22 10:32:17 -07:00
8972137c29 docs(contributing): remove preview references (#11795) 2016-09-22 10:31:56 -07:00
cc6481077f ci(BrowserStack): add Safari 10 (#11796) 2016-09-22 10:31:38 -07:00
c041b93418 refactor(TemplateParser): clearer error message for on* binding (#11802)
fixes #11756
2016-09-22 10:31:18 -07:00
bc33765913 chore(ISSUE_TEMPLATE): update Angular version field (#11821) 2016-09-22 10:29:12 -07:00
31dce72b7b fix(router): update the router not to reset router state when updating root component (#11799) 2016-09-21 11:37:43 -07:00
212f8dbde7 fix(forms): disable all radios with disable() 2016-09-20 15:00:12 -07:00
44da4984f9 fix(forms): support unbound disabled in ngModel (#11736) 2016-09-20 14:55:47 -07:00
d95344430c chore(zone.js): update to 0.6.25 (#11725) 2016-09-20 14:55:07 -07:00
131626fc61 fix(compiler): Safe property access expressions work in event bindings (#11724) 2016-09-20 14:54:53 -07:00
676bb0fa7d feat(router): update dts files 2016-09-20 14:53:52 -07:00
5a849829c4 feat(router): add router preloader to optimistically preload routes 2016-09-20 14:53:52 -07:00
671f73448c refactor: misc cleanup (#11654) 2016-09-19 17:15:57 -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
796 changed files with 27641 additions and 16917 deletions

View File

@ -1,3 +1,7 @@
<!--
IF YOU DON'T FILL OUT THE FOLLOWING INFORMATION WE MIGHT CLOSE YOUR ISSUE WITHOUT INVESTIGATING
-->
**I'm submitting a ...** (check one with "x")
```
[ ] bug report => search github for a similar issue or PR before submitting
@ -5,14 +9,18 @@
[ ] support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question
```
**Current 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). -->
**Minimal reproduction of the problem with instructions**
<!--
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 -->
@ -20,12 +28,12 @@
**Please tell us about your environment:**
<!-- Operating system, IDE, package manager, HTTP server, ... -->
* **Angular version:** 2.0.0-rc.X
* **Angular version:** 2.0.X
<!-- Check whether this is still an issue in the most recent Angular version -->
* **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 ]
* **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]
* **Node (for AoT issues):** `node --version` =

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="
@ -52,146 +41,11 @@ matrix:
- 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,5 +1,207 @@
<a name="2.2.0-rc.0"></a>
# [2.2.0-rc.0](https://github.com/angular/angular/compare/2.2.0-beta.1...2.2.0-rc.0) (2016-11-02)
### Bug Fixes
* **compiler:** dedupe NgModule declarations, … ([a178bc6](https://github.com/angular/angular/commit/a178bc6))
* **compiler:** dont double bind functions ([e391cac](https://github.com/angular/angular/commit/e391cac))
* **compiler:** Dont throw on empty property bindings ([642c1db](https://github.com/angular/angular/commit/642c1db)), closes [#12583](https://github.com/angular/angular/issues/12583)
* **compiler:** support multiple components in a view container ([6fda972](https://github.com/angular/angular/commit/6fda972))
* **core:** improve error when multiple components match the same element ([e9fd864](https://github.com/angular/angular/commit/e9fd864)), closes [#7067](https://github.com/angular/angular/issues/7067)
* **router:** call data observers when the path changes ([1de04b2](https://github.com/angular/angular/commit/1de04b2))
* **router:** CanDeactivate receives a wrong component ([830a780](https://github.com/angular/angular/commit/830a780)), closes [#12592](https://github.com/angular/angular/issues/12592)
* **router:** rerun resolvers when url changes ([fe47e6b](https://github.com/angular/angular/commit/fe47e6b)), closes [#12603](https://github.com/angular/angular/issues/12603)
* **router:** reset URL to the stable state when a navigation gets canceled ([d509ee0](https://github.com/angular/angular/commit/d509ee0)), closes [#10321](https://github.com/angular/angular/issues/10321)
* **router:** routerLink should not prevent default on non-link elements ([8e221b8](https://github.com/angular/angular/commit/8e221b8))
* **router:** run navigations serially ([091c390](https://github.com/angular/angular/commit/091c390)), closes [#11754](https://github.com/angular/angular/issues/11754)
* **upgrade:** silent bootstrap failures ([fa93fd6](https://github.com/angular/angular/commit/fa93fd6)), closes [#12062](https://github.com/angular/angular/issues/12062)
### Features
* **core:** add the find method to QueryList ([7c16ef9](https://github.com/angular/angular/commit/7c16ef9))
<a name="2.1.2"></a>
# [2.1.2](https://github.com/angular/angular/compare/2.1.1...2.1.2) (2016-10-27)
### Bug Fixes
* **compiler:** don't access view local variables nor pipes in host expressions ([#12396](https://github.com/angular/angular/issues/12396)) ([867494a](https://github.com/angular/angular/commit/867494a)), closes [#12004](https://github.com/angular/angular/issues/12004) [#12071](https://github.com/angular/angular/issues/12071)
* **compiler:** walk third party modules ([#12453](https://github.com/angular/angular/issues/12453)) ([a838aba](https://github.com/angular/angular/commit/a838aba)), closes [#11889](https://github.com/angular/angular/issues/11889) [#12428](https://github.com/angular/angular/issues/12428)
* **compiler:** remove double exports of template_ast ([7742ec0](https://github.com/angular/angular/commit/7742ec0))
* **compiler:** use Maps instead of objects in selector implementation ([d321b0e](https://github.com/angular/angular/commit/d321b0e))
* **compiler-cli:** fix types ([ef15364](https://github.com/angular/angular/commit/ef15364))
* **compiler-cli:** assert that all pipes and directives are declared by a module ([7221632](https://github.com/angular/angular/commit/7221632))
* **http:** overwrite already set xsrf header ([b4265e0](https://github.com/angular/angular/commit/b4265e0))
* **router:** add a test to make sure canDeactivate guards are called for aux routes ([fc60fa7](https://github.com/angular/angular/commit/fc60fa7)), closes [#11345](https://github.com/angular/angular/issues/11345)
* **router:** canDeactivate guards are not triggered for componentless routes ([b741853](https://github.com/angular/angular/commit/b741853)), closes [#12375](https://github.com/angular/angular/issues/12375)
* **router:** change router not to deactivate aux routes when navigating from a componentless routes ([52a853e](https://github.com/angular/angular/commit/52a853e))
* **router:** disallow component routes with named outlets ([8f2fa0f](https://github.com/angular/angular/commit/8f2fa0f)), closes [#11208](https://github.com/angular/angular/issues/11208) [#11082](https://github.com/angular/angular/issues/11082)
* **router:** preserve resolve data ([6ccbfd4](https://github.com/angular/angular/commit/6ccbfd4)), closes [#12306](https://github.com/angular/angular/issues/12306)
<a name="2.2.0-beta.1"></a>
# [2.2.0-beta.1](https://github.com/angular/angular/compare/2.2.0-beta.0...2.2.0-beta.1) (2016-10-27)
### Code Refactoring
* **upgrade:** re-export the new static upgrade APIs on new entry ([a26dd28](https://github.com/angular/angular/commit/a26dd28))
### Features
* **router:** export routerLinkActive w/ isActive property ([c9f58cf](https://github.com/angular/angular/commit/c9f58cf))
### BREAKING CHANGES
* upgrade: Four newly added APIs in 2.2.0-beta:
downgradeComponent, downgradeInjectable, UpgradeComponent, and UpgradeModule are no longer exported by @angular/upgrade.
Import these from @angular/upgrade/static instead.
Note: The 2.2.0-beta.1 release also contains all the changes present in the 2.1.2 release.
# [2.1.1](https://github.com/angular/angular/compare/2.1.0...2.1.1) (2016-10-20)
### Bug Fixes
* **compiler:** generate aot code for animation trigger output events ([#12291](https://github.com/angular/angular/issues/12291)) ([6e5f8b5](https://github.com/angular/angular/commit/6e5f8b5)), closes [#11707](https://github.com/angular/angular/issues/11707)
* **compiler:** don't redeclare a var in the same scope ([#12386](https://github.com/angular/angular/issues/12386)) ([cca4a5c](https://github.com/angular/angular/commit/cca4a5c))
* **core:** fix decorator default values ([bd1dcb5](https://github.com/angular/angular/commit/bd1dcb5))
* **core:** fix property decorators ([3993279](https://github.com/angular/angular/commit/3993279)), closes [#12224](https://github.com/angular/angular/issues/12224)
* **http:** make normalizeMethodName optimizer-compatible. ([#12370](https://github.com/angular/angular/issues/12370)) ([8409b65](https://github.com/angular/angular/commit/8409b65))
* **router:** correctly export filter operator in es5 ([#12286](https://github.com/angular/angular/issues/12286)) ([27d7677](https://github.com/angular/angular/commit/27d7677))
* **router:** do not update primary route if only secondary outlet is given ([#11797](https://github.com/angular/angular/issues/11797)) ([da5fc69](https://github.com/angular/angular/commit/da5fc69))
* **router:** fix lazy loading triggered by redirects from wildcard routes ([5ae6915](https://github.com/angular/angular/commit/5ae6915)), closes [#12183](https://github.com/angular/angular/issues/12183)
* **router:** module loader should start compiling modules when stubbedModules are set ([#11742](https://github.com/angular/angular/issues/11742)) ([b44b6ef](https://github.com/angular/angular/commit/b44b6ef))
### Performance Improvements
* **common:** optimize NgSwitch default case ([fdf4309](https://github.com/angular/angular/commit/fdf4309))
<a name="2.2.0-beta.0"></a>
# [2.2.0-beta.0](https://github.com/angular/angular/compare/2.1.0...2.2.0-beta.0) (2016-10-20)
### Features
* **common:** support narrow forms for month and weekdays in DatePipe ([#12297](https://github.com/angular/angular/issues/12297)) ([f77ab6a](https://github.com/angular/angular/commit/f77ab6a)), closes [#12294](https://github.com/angular/angular/issues/12294)
* **forms:** add hasError and getError to AbstractControlDirective ([#11985](https://github.com/angular/angular/issues/11985)) ([592f40a](https://github.com/angular/angular/commit/592f40a)), closes [#7255](https://github.com/angular/angular/issues/7255)
* **forms:** add ng-pending CSS class during async validation ([#11243](https://github.com/angular/angular/issues/11243)) ([97bc971](https://github.com/angular/angular/commit/97bc971)), closes [#10336](https://github.com/angular/angular/issues/10336)
* **forms:** Added emitEvent to AbstractControl methods ([#11949](https://github.com/angular/angular/issues/11949)) ([b9fc090](https://github.com/angular/angular/commit/b9fc090))
* **forms:** make 'parent' a public property of 'AbstractControl' ([#11855](https://github.com/angular/angular/issues/11855)) ([445e592](https://github.com/angular/angular/commit/445e592))
* **forms:** Validator.pattern accepts a RegExp ([#12323](https://github.com/angular/angular/issues/12323)) ([bf60418](https://github.com/angular/angular/commit/bf60418))
* **upgrade:** add support for AoT compiled upgrade applications ([d6791ff](https://github.com/angular/angular/commit/d6791ff)), closes [#12239](https://github.com/angular/angular/issues/12239)
* **router:** add support for ng1/ng2 migration ([#12160](https://github.com/angular/angular/issues/12160)) ([8b9ab44](https://github.com/angular/angular/commit/8b9ab44))
Note: The 2.2.0-beta.0 release also contains all the changes present in the 2.1.1 release.
<a name="2.1.0"></a>
# [2.1.0 incremental-metamorphosis](https://github.com/angular/angular/compare/2.1.0-rc.0...2.1.0) (2016-10-12)
### Bug Fixes
* **compiler:** allow whitespace as `<ng-content>` content ([#12225](https://github.com/angular/angular/issues/12225)) ([df1718d](https://github.com/angular/angular/commit/df1718d))
* **compiler:** interpolation expressions report the correct offset ([#12125](https://github.com/angular/angular/issues/12125)) ([d641c36](https://github.com/angular/angular/commit/d641c36))
* **compiler:** properly shim `:host:before` and `:host(:before)` ([#12171](https://github.com/angular/angular/issues/12171)) ([aa92512](https://github.com/angular/angular/commit/aa92512)), closes [#12165](https://github.com/angular/angular/issues/12165)
* **compiler:** validate `@HostBinding` name ([#12139](https://github.com/angular/angular/issues/12139)) ([13ecc14](https://github.com/angular/angular/commit/13ecc14))
* **compiler-cli:** don't clone static symbols when simplifying annotation metadata ([#12158](https://github.com/angular/angular/issues/12158)) ([8c477b2](https://github.com/angular/angular/commit/8c477b2))
* **compiler-cli:** remove peerDependency on [@angular](https://github.com/angular)/platform-server ([#12122](https://github.com/angular/angular/issues/12122)) ([71b7654](https://github.com/angular/angular/commit/71b7654))
* **compiler-cli:** remove unused parse5 dependency from package.json ([eaaec69](https://github.com/angular/angular/commit/eaaec69))
* **forms:** allow optional fields with pattern and minlength validators ([#12147](https://github.com/angular/angular/issues/12147)) ([d22eeb7](https://github.com/angular/angular/commit/d22eeb7))
* **forms:** properly validate blank strings with minlength ([#12091](https://github.com/angular/angular/issues/12091)) ([f50c1da](https://github.com/angular/angular/commit/f50c1da))
* **http:** fix Headers initialization from Headers and Object ([#12106](https://github.com/angular/angular/issues/12106)) ([f4566f8](https://github.com/angular/angular/commit/f4566f8))
* **http:** Headers.append should append to the list ([a67c067](https://github.com/angular/angular/commit/a67c067))
* **platform-browser-dynamic:** mark platformBrowserDynamic as stable API ([#12154](https://github.com/angular/angular/issues/12154)) ([bcef5ef](https://github.com/angular/angular/commit/bcef5ef))
* **router:** improve error message ([#12102](https://github.com/angular/angular/issues/12102)) ([e06303a](https://github.com/angular/angular/commit/e06303a))
* **router:** parent resolve should complete before merging resolved data ([1681e4f](https://github.com/angular/angular/commit/1681e4f)), closes [#12032](https://github.com/angular/angular/issues/12032)
* **router:** wildcards routes should support lazy loading ([40b92dd](https://github.com/angular/angular/commit/40b92dd)), closes [#12024](https://github.com/angular/angular/issues/12024)
* **upgrade:** allow compilerOptions in bootstrap ([#10575](https://github.com/angular/angular/issues/10575)) ([5effc33](https://github.com/angular/angular/commit/5effc33))
<a name="2.1.0-rc.0"></a>
# [2.1.0-rc.0](https://github.com/angular/angular/compare/2.1.0-beta.0...2.1.0-rc.0) (2016-10-05)
### Features
* **animations:** provide aliases for `:enter` and `:leave` transitions ([#11991](https://github.com/angular/angular/issues/11991)) ([e884f48](https://github.com/angular/angular/commit/e884f48))
Note: 2.1.0-rc.0 release also contains all the changes present in the 2.0.2 release.
<a name="2.1.0-beta.0"></a>
# [2.1.0-beta.0](https://github.com/angular/angular/compare/2.0.0...2.1.0-beta.0) (2016-09-23)
### Features
* **router:** add router preloader to optimistically preload routes ([5a84982](https://github.com/angular/angular/commit/5a84982))
### Bug Fixes
* **router:** update the router not to reset router state when updating root component ([#11799](https://github.com/angular/angular/issues/11799)) ([31dce72](https://github.com/angular/angular/commit/31dce72))
Note: 2.1.0-beta.0 release also contains all the changes present in the 2.0.1 release.
<a name="2.0.2"></a>
## [2.0.2](https://github.com/angular/angular/compare/2.0.1...2.0.2) (2016-10-05)
### Bug Fixes
* **common:** correctly removes styles on IE ([#11953](https://github.com/angular/angular/pull/11953)), closes [#7916](https://github.com/angular/angular/issues/7916)
* **compiler:** do not embed templateUrl in view factories in non-debug mode. ([#11818](https://github.com/angular/angular/issues/11818)) ([51e1994](https://github.com/angular/angular/commit/51e1994)), closes [#11117](https://github.com/angular/angular/issues/11117)
* **compiler:** move detection of unsafe properties for binding to ElementSchemaRegistry ([#11378](https://github.com/angular/angular/issues/11378)) ([5911c3b](https://github.com/angular/angular/commit/5911c3b))
* **compiler:** fix `:host(tag)` and `:host-context(tag)` ([a6bb84e0](https://github.com/angular/angular/commit/a6bb84e02b7579f8d957ef6ba5b10d83482ed756)), closes [#11972](https://github.com/angular/angular/issues/11972)
* **compiler:** fix attribute selectors in :host and :host-context ([#12056](https://github.com/angular/angular/issues/12056)) ([6f7ed32](https://github.com/angular/angular/commit/6f7ed32)), closes [#11917](https://github.com/angular/angular/issues/11917)
* **compiler:** support `@page` and `@document` CSS rules ([#11878](https://github.com/angular/angular/issues/11878)) ([c99ef49](https://github.com/angular/angular/commit/c99ef49)), closes [#11860](https://github.com/angular/angular/issues/11860)
* **compiler:** support `[attr="value with space"]` ([bd012ef](https://github.com/angular/angular/commit/bd012ef)), closes [#6249](https://github.com/angular/angular/issues/6249)
* **compiler:** support quoted attribute values ([7395400](https://github.com/angular/angular/commit/7395400)), closes [#6085](https://github.com/angular/angular/issues/6085)
* **compiler:** fix `<x>` ctype names ([7578d85](https://github.com/angular/angular/commit/7578d85)), closes [#12000](https://github.com/angular/angular/issues/12000)
* **compiler-cli:** allow ReflectorHost passed as argument to CodeGenerator#create ([#11951](https://github.com/angular/angular/issues/11951)) ([826c98e](https://github.com/angular/angular/commit/826c98e))
* **forms:** properly validate empty strings with patterns ([#11450](https://github.com/angular/angular/issues/11450)) ([e00de0c](https://github.com/angular/angular/commit/e00de0c))
* **http:** preserve case of the first init, `set()` or `append()` ([#12023](https://github.com/angular/angular/issues/12023)) ([adb17fe](https://github.com/angular/angular/commit/adb17fe)), closes [#11624](https://github.com/angular/angular/issues/11624)
* **http:** remove url params if provided value is null or undefined ([#11990](https://github.com/angular/angular/issues/11990)) ([9cc0a4e](https://github.com/angular/angular/commit/9cc0a4e))
* **router:** do not reset the router state when updating the component ([#11867](https://github.com/angular/angular/issues/11867)) ([cf750e1](https://github.com/angular/angular/commit/cf750e1))
* **upgrade:** bind optional properties when upgrading from ng1 ([#11411](https://github.com/angular/angular/issues/11411)) ([0851238](https://github.com/angular/angular/commit/0851238)), closes [#10181](https://github.com/angular/angular/issues/10181)
<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 [#11645](https://github.com/angular/angular/issues/11645)
* **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)
# [2.0.0 proprioception-reinforcement](https://github.com/angular/angular/compare/2.0.0-rc.7...2.0.0) (2016-09-14)
### Bug Fixes
@ -212,7 +414,7 @@
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.
@ -226,11 +428,11 @@ use `Type<any>` in place of `Type`.
* 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>
```
@ -256,7 +458,7 @@ prefix using `animate-` must now be preixed using `bind-animate-`.
```
{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.
@ -268,7 +470,7 @@ prefix using `animate-` must now be preixed using `bind-animate-`.
```
ErrorHandler.handleError(error: any): void;
```
* core: deprecated DynamicComponentLoader was removed; see deprecation notice for migration instructions.
* core: deprecated SystemJsComponentResolver and SystemJsCmpFactoryResolver have been removed.
@ -302,13 +504,13 @@ prefix using `animate-` must now be preixed using `bind-animate-`.
* 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';
```
@ -326,7 +528,7 @@ prefix using `animate-` must now be preixed using `bind-animate-`.
* 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>

View File

@ -1,6 +1,6 @@
# Contributing to Angular 2
# Contributing to Angular
We would love for you to contribute to Angular 2 and help make it even better than it is
We would love for you to contribute to Angular and help make it even better than it is
today! As a contributor, here are the guidelines we would like you to follow:
- [Code of Conduct](#coc)
@ -17,19 +17,27 @@ 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].
Please, do not open issues for the general support questions as we want to keep GitHub issues for bug reports and feature requests. You've got much better chances of getting your question answered on [StackOverflow](stackoverflow.com/questions/tagged/angular) where the questions should be tagged with tag `angular`.
## <a name="issue"></a> Found an Issue?
StackOverflow is a much better place to ask questions since:
- there are thousands of people willing to help on StackOverflow
- questions and answers stay available for public viewing so your question / answer might help someone else
- StackOverflow's voting system assures that the best answers are prominently visible.
To save your and our time we will be systematically closing all the issues that are requests for general support and redirecting people to StackOverflow.
If you would like to chat about the question in real-time, you can reach out via [our gitter channel][gitter].
## <a name="issue"></a> Found a Bug?
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 name="feature"></a> Missing a Feature?
You can *request* a new feature by [submitting an issue](#submit-issue) to our GitHub
Repository. 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.
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
@ -40,24 +48,22 @@ and help you to craft the change so that it is successfully accepted into the pr
## <a name="submit"></a> Submission Guidelines
### <a name="submit-issue"></a> Submitting an Issue
Before you submit an issue, search the archive, maybe your question was already answered.
If your issue appears to be a bug, and hasn't been reported, open a new issue.
Help us to maximize the effort we can spend fixing issues and adding new
features, by not reporting duplicate issues. Providing the following information will increase the
chances of your issue being dealt with quickly:
Before you submit an issue, please search the issue tracker, maybe an issue for your problem already exists and the discussion might inform you of workarounds readily available.
* **Overview of the Issue** - if an error is being thrown a non-minified stack trace helps
* **Angular Version** - what version of Angular is affected (e.g. 2.0.0-alpha.53)
* **Motivation for or Use Case** - explain what are you trying to do and why the current behavior is a bug for you
* **Browsers and Operating System** - is this a problem with all browsers?
* **Reproduce the Error** - provide a live example (using [Plunker][plunker],
[JSFiddle][jsfiddle] or [Runnable][runnable]) or a unambiguous set of steps
* **Related Issues** - has a similar issue been reported before?
* **Suggest a Fix** - if you can't fix the bug yourself, perhaps you can point to what might be
causing the problem (line of code or commit)
We want to fix all the issues as soon as possible, but before fixing a bug we need to reproduce and confirm it. In order to reproduce bugs we will systematically ask you to provide a minimal reproduction scenario using http://plnkr.co. Having a live, reproducible scenario gives us wealth of important information without going back & forth to you with additional questions like:
You can file new issues by providing the above information [here](https://github.com/angular/angular/issues/new).
- version of Angular used
- 3rd-party libraries and their versions
- and most importantly - a use-case that fails
A minimal reproduce scenario using http://plnkr.co/ allows us to quickly confirm a bug (or point out coding problem) as well as confirm that we are fixing the right problem. If plunker is not a suitable way to demostrate the problem (for example for issues related to our npm packaging), please create a standalone git repository demostrating the problem.
We will be insisting on a minimal reproduce scenario in order to save maintainers time and ultimately be able to fix more bugs. Interestingly, from our experience users often find coding problems themselves while preparing a minimal plunk. We understand that sometimes it might be hard to extract essentials bits of code from a larger code-base but we really need to isolate the problem before we can fix it.
Unfortunately we are not able to investigate / fix bugs without a minimal reproduction, so if we don't hear back from you we are going to close an issue that don't have enough info to be reproduced.
You can file new issues by filling out our [new issue form](https://github.com/angular/angular/issues/new).
### <a name="submit-pr"></a> Submitting a Pull Request (PR)
@ -95,7 +101,7 @@ Before you submit your Pull Request (PR) consider the following guidelines:
* In GitHub, send a pull request to `angular:master`.
* If we suggest changes then:
* Make the required updates.
* Re-run the Angular 2 test suites to ensure tests are still passing.
* Re-run the Angular test suites to ensure tests are still passing.
* Rebase your branch and force push to your GitHub repository (this will update your Pull Request):
```shell

View File

@ -114,7 +114,7 @@ You should execute the 3 test suites before submitting a PR to github.
All the tests are executed on our Continuous Integration infrastructure and a PR could only be merged once the tests pass.
- CircleCI fails if your code is not formatted properly,
- Travis CI fails if any of the test suite describe above fails.
- Travis CI fails if any of the test suites described above fails.
## Update the public API tests

View File

@ -4,7 +4,6 @@
[![Issue Stats](http://issuestats.com/github/angular/angular/badge/pr?style=flat)](http://issuestats.com/github/angular/angular)
[![Issue Stats](http://issuestats.com/github/angular/angular/badge/issue?style=flat)](http://issuestats.com/github/angular/angular)
[![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)
*Safari (7+), iOS (7+), Edge (14) and IE mobile (11) are tested on [BrowserStack][browserstack].*
@ -17,7 +16,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
@ -32,7 +30,6 @@ guidelines for [contributing][contributing] and then check out one of our issues
[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

62
SAVED_REPLIES.md Normal file
View File

@ -0,0 +1,62 @@
# Saved Responses for Angular's Issue Tracker
The following are canned responses that the Angular team should use to close issues on our issue tracker that fall into the listed resolution categories.
Since GitHub currently doesn't allow us to have a repository-wide or organization-wide list of [saved replies](https://help.github.com/articles/working-with-saved-replies/), these replies need to be maintained by individual team members. Since the responses can be modified in the future, all responses are versioned to simplify the process of keeping the responses up to date.
## Angular: Already Fixed (v1)
```
Thanks for reporting this issue. Luckily it has already been fixed in one of the recent releases. Please update to the most recent version to resolve the problem.
If after upgrade the problem still exists in your application please open a new issue and provide a plunker reproducing the problem and describing the difference between the expected and current behavior. You can use this plunker template: http://plnkr.co/edit/tpl:AvJOMERrnz94ekVua0u5?p=catalogue
```
## Angular: Don't Understand (v1)
```
I'm sorry but we don't understand the problem you are reporting.
If the problem still exists please open a new issue and provide a plunker reproducing the problem and describing the difference between the expected and current behavior. You can use this plunker template: http://plnkr.co/edit/tpl:AvJOMERrnz94ekVua0u5?p=catalogue
```
## Angular: Duplicate (v1)
```
Thanks for reporting this issue. However this issue is a duplicate of an existing issue #<ISSUE_NUMBER>. Please subscribe to that issue for future updates.
```
## Angular: Insufficient Information Provided (v1)
```
Thanks for reporting this issue. However, you didn't provide sufficient information for us to understand and reproduce the problem. Please check out [our submission guidelines](https://github.com/angular/angular/blob/master/CONTRIBUTING.md#-submitting-an-issue) to understand why we can't act on issues that are lacking important information.
If the problem still persists, please file a new issue and ensure you provide all of the required information when filling out the issue template.
```
## Angular: Issue Outside of Angular (v1)
```
I'm sorry but this issue is not caused by Angular. Please contact the author(s) of project <PROJECT NAME> or file issue on their issue tracker.
```
## Angular: Non-reproducible (v1)
```
I'm sorry but we can't reproduce the problem following the instructions you provided.
If the problem still exists please open a new issue following [our submission guidelines](https://github.com/angular/angular/blob/master/CONTRIBUTING.md#-submitting-an-issue).
```
## Angular: Obsolete (v1)
```
Thanks for reporting this issue. This issue is now obsolete due to changes in the recent releases. Please update to the most recent Angular version.
If the problem still persists, please file a new issue and ensure you provide the version of Angular affected and include the steps to reproduce the problem when filling out the issue template.
```
## Angular: Support Request (v1)
```
Hello, we reviewed this issue and determined that it doesn't fall into the bug report or feature request category. This issue tracker is not suitable for support requests, please repost your issue on [StackOverflow](http://stackoverflow.com/) using tag `angular`.
If you are wondering why we don't resolve support issues via the issue tracker, please [check out this explanation](https://github.com/angular/angular/blob/master/CONTRIBUTING.md#-got-a-question-or-problem).
```

View File

@ -1,7 +1,7 @@
# Triage Process and Github Labels for Angular 2
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
to triage issues on github. The basic idea of the 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.
@ -17,9 +17,9 @@ with it.
* `comp: animations`: `@matsko`
* `comp: benchpress`: `@tbosch`
* `comp: build/ci`: `@IgorMinar` -- All build and CI scripts
* `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
* `comp: core & compiler`: `@tbosch` -- Because core and compiler are very
intertwined, we will be treating them as one.
* `comp: forms`: `@kara`
* `comp: http`: `@jeffbcross`
@ -29,14 +29,14 @@ with it.
* `comp: testing`: `@juliemr`
* `comp: upgrade`: `@mhevery`
* `comp: web-worker`: `@vicb`
* `comp: zone`: `@mhevery`
* `comp: zones`: `@mhevery`
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.
* `comp: documentation`: `@naomiblack`
* `comp: packaging`: `@mhevery`
* `comp: docs`: `@naomiblack`
* `comp: packaging`: `@IgorMinar`
* `comp: performance`: `@tbosch`
* `comp: security`: `@IgorMinar`
@ -53,11 +53,11 @@ What kind of problem is this?
## 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.
It is the caretaker's responsibility to assign `comp: *` to each new
issue as they come in. The reason why we limit the responsibility of the
caretaker to this one label is that it is likely that without domain
knowledge the caretaker could mislabel issues or lack knowledge of
duplicate issues.
## Component's owner Triage Process
@ -68,11 +68,37 @@ 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.
Several owners have adopted the issue categorization based on
[user pain](http://www.lostgarden.com/2008/05/improving-bug-triage-with-user-pain.html)
used by Angular 1. In this system every issue is assigned frequency and
severity based on which the total user pain score is calculated.
Following is the definition of various frequency and severity levels:
1. `freq(score): *` How often does this issue come up? How many developers does this affect?
* low (1) - obscure issue affecting a handful of developers
* moderate (2) - impacts auxiliary usage patterns, only small number of applications are affected
* high (3) - impacts primary usage patterns, affecting most Angular apps
* critical (4) - impacts all Angular apps
1. `severity(score): *` - How bad is the issue?
* inconvenience (1) - causes ugly/boilerplate code in apps
* confusing (2) - unexpected or inconsistent behavior; hard-to-debug
* broken expected use (3) - it's hard or impossible for a developer using Angular to accomplish something that Angular should be able to do
* memory leak (4)
* regression (5) - functionality that used to work no longer works in a new release due to an unintentional change
* security issue (6)
These criteria are then used to calculate a "user pain" score as follows:
`pain = severity × frequency`
### Assigning Issues to Milestones
Any issue that is being worked on must have:
* An `assignee`: The person doing the work.
* An `Assignee`: The person doing the work.
* A `Milestone`: When we expect to complete this work.
We aim to only have at most three milestones open at a time:

View File

@ -1,216 +1,98 @@
// Unique place to configure the browsers which are used in the different CI jobs in Sauce Labs (SL) and BrowserStack (BS).
/**
* @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
*/
// Unique place to configure the browsers which are used in the different CI jobs in Sauce Labs (SL)
// and BrowserStack (BS).
// If the target is set to null, then the browser is not run anywhere during CI.
// If a category becomes empty (e.g. BS and required), then the corresponding job must be commented out in Travis configuration.
// If a category becomes empty (e.g. BS and required), then the corresponding job must be commented
// out in Travis configuration.
var CIconfiguration = {
'Chrome': { unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
'Firefox': { unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
'Chrome': {unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
'Firefox': {unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
// FirefoxBeta and ChromeBeta should be target:'BS' or target:'SL', and required:true
// Currently deactivated due to https://github.com/angular/angular/issues/7560
'ChromeBeta': { unitTest: {target: null, required: true}, e2e: {target: null, required: false}},
'FirefoxBeta': { unitTest: {target: null, required: false}, e2e: {target: null, required: false}},
'ChromeDev': { unitTest: {target: null, required: true}, e2e: {target: null, required: true}},
'FirefoxDev': { unitTest: {target: null, required: true}, e2e: {target: null, required: true}},
'IE9': { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
'IE10': { unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
'IE11': { unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
'Edge': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
'Android4.1': { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
'Android4.2': { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
'Android4.3': { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
'Android4.4': { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
'Android5': { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
'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}},
'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}},
'WindowsPhone': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}}
'ChromeBeta': {unitTest: {target: null, required: true}, e2e: {target: null, required: false}},
'FirefoxBeta': {unitTest: {target: null, required: false}, e2e: {target: null, required: false}},
'ChromeDev': {unitTest: {target: null, required: true}, e2e: {target: null, required: true}},
'FirefoxDev': {unitTest: {target: null, required: true}, e2e: {target: null, required: true}},
'IE9': {unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
'IE10': {unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
'IE11': {unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
'Edge': {unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
'Android4.1': {unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
'Android4.2': {unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
'Android4.3': {unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
'Android4.4': {unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
'Android5': {unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
'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}}
};
var customLaunchers = {
'DartiumWithWebPlatform': {
base: 'Dartium',
flags: ['--enable-experimental-web-platform-features'] },
'ChromeNoSandbox': {
base: 'Chrome',
flags: ['--no-sandbox'] },
'SL_CHROME': {
base: 'SauceLabs',
browserName: 'chrome',
version: '52'
},
'SL_CHROMEBETA': {
base: 'SauceLabs',
browserName: 'chrome',
version: 'beta'
},
'SL_CHROMEDEV': {
base: 'SauceLabs',
browserName: 'chrome',
version: 'dev'
},
'SL_FIREFOX': {
base: 'SauceLabs',
browserName: 'firefox',
version: '46'
},
'SL_FIREFOXBETA': {
base: 'SauceLabs',
browserName: 'firefox',
version: 'beta'
},
'SL_FIREFOXDEV': {
base: 'SauceLabs',
browserName: 'firefox',
version: 'dev'
},
'SL_SAFARI7': {
base: 'SauceLabs',
browserName: 'safari',
platform: 'OS X 10.9',
version: '7.0'
},
'SL_SAFARI8': {
base: 'SauceLabs',
browserName: 'safari',
platform: 'OS X 10.10',
version: '8.0'
},
'SL_SAFARI9': {
base: 'SauceLabs',
browserName: 'safari',
platform: 'OS X 10.11',
version: '9.0'
},
'SL_IOS7': {
base: 'SauceLabs',
browserName: 'iphone',
platform: 'OS X 10.10',
version: '7.1'
},
'SL_IOS8': {
base: 'SauceLabs',
browserName: 'iphone',
platform: 'OS X 10.10',
version: '8.4'
},
'SL_IOS9': {
base: 'SauceLabs',
browserName: 'iphone',
platform: 'OS X 10.10',
version: '9.3'
},
'SL_IE9': {
base: 'SauceLabs',
browserName: 'internet explorer',
platform: 'Windows 2008',
version: '9'
},
'DartiumWithWebPlatform':
{base: 'Dartium', flags: ['--enable-experimental-web-platform-features']},
'ChromeNoSandbox': {base: 'Chrome', flags: ['--no-sandbox']},
'SL_CHROME': {base: 'SauceLabs', browserName: 'chrome', version: '52'},
'SL_CHROMEBETA': {base: 'SauceLabs', browserName: 'chrome', version: 'beta'},
'SL_CHROMEDEV': {base: 'SauceLabs', browserName: 'chrome', version: 'dev'},
'SL_FIREFOX': {base: 'SauceLabs', browserName: 'firefox', version: '46'},
'SL_FIREFOXBETA': {base: 'SauceLabs', browserName: 'firefox', version: 'beta'},
'SL_FIREFOXDEV': {base: 'SauceLabs', browserName: 'firefox', version: 'dev'},
'SL_SAFARI7': {base: 'SauceLabs', browserName: 'safari', platform: 'OS X 10.9', version: '7.0'},
'SL_SAFARI8': {base: 'SauceLabs', browserName: 'safari', platform: 'OS X 10.10', version: '8.0'},
'SL_SAFARI9': {base: 'SauceLabs', browserName: 'safari', 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', platform: 'OS X 10.10', version: '7.1'},
'SL_IOS8': {base: 'SauceLabs', browserName: 'iphone', platform: 'OS X 10.10', version: '8.4'},
'SL_IOS9': {base: 'SauceLabs', browserName: 'iphone', 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', platform: 'Windows 2008', version: '9'},
'SL_IE10': {
base: 'SauceLabs',
browserName: 'internet explorer',
platform: 'Windows 2012',
version: '10'
},
'SL_IE11': {
base: 'SauceLabs',
browserName: 'internet explorer',
platform: 'Windows 8.1',
version: '11'
},
'SL_IE11':
{base: 'SauceLabs', browserName: 'internet explorer', platform: 'Windows 8.1', version: '11'},
'SL_EDGE': {
base: 'SauceLabs',
browserName: 'MicrosoftEdge',
platform: 'Windows 10',
version: '13.10586'
},
'SL_ANDROID4.1': {
base: 'SauceLabs',
browserName: 'android',
platform: 'Linux',
version: '4.1'
},
'SL_ANDROID4.2': {
base: 'SauceLabs',
browserName: 'android',
platform: 'Linux',
version: '4.2'
},
'SL_ANDROID4.3': {
base: 'SauceLabs',
browserName: 'android',
platform: 'Linux',
version: '4.3'
},
'SL_ANDROID4.4': {
base: 'SauceLabs',
browserName: 'android',
platform: 'Linux',
version: '4.4'
},
'SL_ANDROID5': {
base: 'SauceLabs',
browserName: 'android',
platform: 'Linux',
version: '5.1'
},
'SL_ANDROID4.1': {base: 'SauceLabs', browserName: 'android', platform: 'Linux', version: '4.1'},
'SL_ANDROID4.2': {base: 'SauceLabs', browserName: 'android', platform: 'Linux', version: '4.2'},
'SL_ANDROID4.3': {base: 'SauceLabs', browserName: 'android', platform: 'Linux', version: '4.3'},
'SL_ANDROID4.4': {base: 'SauceLabs', browserName: 'android', platform: 'Linux', version: '4.4'},
'SL_ANDROID5': {base: 'SauceLabs', browserName: 'android', platform: 'Linux', version: '5.1'},
'BS_CHROME': {
base: 'BrowserStack',
browser: 'chrome',
os: 'OS X',
os_version: 'Yosemite'
},
'BS_FIREFOX': {
base: 'BrowserStack',
browser: 'firefox',
os: 'Windows',
os_version: '10'
},
'BS_SAFARI7': {
base: 'BrowserStack',
browser: 'safari',
os: 'OS X',
os_version: 'Mavericks'
},
'BS_SAFARI8': {
base: 'BrowserStack',
browser: 'safari',
os: 'OS X',
os_version: 'Yosemite'
},
'BS_SAFARI9': {
base: 'BrowserStack',
browser: 'safari',
os: 'OS X',
os_version: 'El Capitan'
},
'BS_IOS7': {
base: 'BrowserStack',
device: 'iPhone 5S',
os: 'ios',
os_version: '7.0'
},
'BS_IOS8': {
base: 'BrowserStack',
device: 'iPhone 6',
os: 'ios',
os_version: '8.3'
},
'BS_IOS9': {
base: 'BrowserStack',
device: 'iPhone 6S',
os: 'ios',
os_version: '9.1'
},
'BS_IE9': {
base: 'BrowserStack',
browser: 'ie',
browser_version: '9.0',
os: 'Windows',
os_version: '7'
},
'BS_CHROME': {base: 'BrowserStack', browser: 'chrome', os: 'OS X', os_version: 'Yosemite'},
'BS_FIREFOX': {base: 'BrowserStack', browser: 'firefox', os: 'Windows', os_version: '10'},
'BS_SAFARI7': {base: 'BrowserStack', browser: 'safari', os: 'OS X', os_version: 'Mavericks'},
'BS_SAFARI8': {base: 'BrowserStack', browser: 'safari', os: 'OS X', os_version: 'Yosemite'},
'BS_SAFARI9': {base: 'BrowserStack', browser: 'safari', 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', os: 'ios', os_version: '7.0'},
'BS_IOS8': {base: 'BrowserStack', device: 'iPhone 6', os: 'ios', os_version: '8.3'},
'BS_IOS9': {base: 'BrowserStack', device: 'iPhone 6S', 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', browser_version: '9.0', os: 'Windows', os_version: '7'},
'BS_IE10': {
base: 'BrowserStack',
browser: 'ie',
@ -225,58 +107,35 @@ var customLaunchers = {
os: 'Windows',
os_version: '10'
},
'BS_EDGE': {
base: 'BrowserStack',
browser: 'edge',
os: 'Windows',
os_version: '10'
},
'BS_WINDOWSPHONE' : {
base: 'BrowserStack',
device: 'Nokia Lumia 930',
os: 'winphone',
os_version: '8.1'
},
'BS_ANDROID5': {
base: 'BrowserStack',
device: 'Google Nexus 5',
os: 'android',
os_version: '5.0'
},
'BS_ANDROID4.4': {
base: 'BrowserStack',
device: 'HTC One M8',
os: 'android',
os_version: '4.4'
},
'BS_ANDROID4.3': {
base: 'BrowserStack',
device: 'Samsung Galaxy S4',
os: 'android',
os_version: '4.3'
},
'BS_ANDROID4.2': {
base: 'BrowserStack',
device: 'Google Nexus 4',
os: 'android',
os_version: '4.2'
},
'BS_ANDROID4.1': {
base: 'BrowserStack',
device: 'Google Nexus 7',
os: 'android',
os_version: '4.1'
}
'BS_EDGE': {base: 'BrowserStack', browser: 'edge', os: 'Windows', os_version: '10'},
'BS_WINDOWSPHONE':
{base: 'BrowserStack', device: 'Nokia Lumia 930', os: 'winphone', os_version: '8.1'},
'BS_ANDROID5': {base: 'BrowserStack', device: 'Google Nexus 5', os: 'android', os_version: '5.0'},
'BS_ANDROID4.4': {base: 'BrowserStack', device: 'HTC One M8', os: 'android', os_version: '4.4'},
'BS_ANDROID4.3':
{base: 'BrowserStack', device: 'Samsung Galaxy S4', os: 'android', os_version: '4.3'},
'BS_ANDROID4.2':
{base: 'BrowserStack', device: 'Google Nexus 4', os: 'android', os_version: '4.2'},
'BS_ANDROID4.1':
{base: 'BrowserStack', device: 'Google Nexus 7', os: 'android', os_version: '4.1'}
};
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'],
'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', '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),
@ -284,13 +143,20 @@ 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'],
'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', '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)
};
@ -303,11 +169,9 @@ module.exports = {
function buildConfiguration(type, target, required) {
return Object.keys(CIconfiguration)
.filter((item) => {
var conf = CIconfiguration[item][type];
return conf.required === required && conf.target === target;
})
.map((item) => {
return target + '_' + item.toUpperCase();
});
.filter((item) => {
var conf = CIconfiguration[item][type];
return conf.required === required && conf.target === target;
})
.map((item) => target + '_' + item.toUpperCase());
}

View File

@ -67,6 +67,7 @@ if [[ ${BUILD_ALL} == true ]]; then
ln -s ../../../../node_modules/reflect-metadata/Reflect.js .
ln -s ../../../../node_modules/rxjs .
ln -s ../../../../node_modules/angular/angular.js .
ln -s ../../../../node_modules/hammerjs/hammer.js .
cd -
echo "====== Copying files needed for benchmarks ====="
@ -101,7 +102,9 @@ do
DESTDIR=${PWD}/dist/packages-dist/${PACKAGE}
UMD_ES5_PATH=${DESTDIR}/bundles/${PACKAGE}.umd.js
UMD_TESTING_ES5_PATH=${DESTDIR}/bundles/${PACKAGE}-testing.umd.js
UMD_STATIC_ES5_PATH=${DESTDIR}/bundles/${PACKAGE}-static.umd.js
UMD_ES5_MIN_PATH=${DESTDIR}/bundles/${PACKAGE}.umd.min.js
UMD_STATIC_ES5_MIN_PATH=${DESTDIR}/bundles/${PACKAGE}-static.umd.min.js
LICENSE_BANNER=${PWD}/modules/@angular/license-banner.txt
rm -rf ${DESTDIR}
@ -110,6 +113,7 @@ do
$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"
@ -156,6 +160,18 @@ do
cat ${UMD_TESTING_ES5_PATH} >> ${UMD_TESTING_ES5_PATH}.tmp
mv ${UMD_TESTING_ES5_PATH}.tmp ${UMD_TESTING_ES5_PATH}
fi
if [[ -e rollup-static.config.js ]]; then
echo "====== Rollup ${PACKAGE} static"
../../../node_modules/.bin/rollup -c rollup-static.config.js
# create dir because it doesn't exist yet, we should move the src code here and remove this line
mkdir ${DESTDIR}/static
echo "{\"main\": \"../bundles/${PACKAGE}-static.umd.js\"}" > ${DESTDIR}/static/package.json
cat ${LICENSE_BANNER} > ${UMD_STATIC_ES5_PATH}.tmp
cat ${UMD_STATIC_ES5_PATH} >> ${UMD_STATIC_ES5_PATH}.tmp
mv ${UMD_STATIC_ES5_PATH}.tmp ${UMD_STATIC_ES5_PATH}
$UGLIFYJS -c --screw-ie8 --comments -o ${UMD_STATIC_ES5_MIN_PATH} ${UMD_STATIC_ES5_PATH}
fi
) 2>&1 | grep -v "as external dependency"
fi

40
docs/PUBLIC_API.md Normal file
View File

@ -0,0 +1,40 @@
# Supported Public API Surface of Angular
Our SemVer, timed-release cycle and deprecation policy currently applies to these npm packages:
- `@angular/core`
- `@angular/common`
- `@angular/platform-browser`
- `@angular/platform-browser-dynamic`
- `@angular/platform-server`
- `@angular/platform-webworker`
- `@angular/platform-webworker-dynamic`
- `@angular/upgrade`
- `@angular/router`
- `@angular/forms`
- `@angular/http`
One intentional omission from this list is `@angular/compiler`, which is currently considered a low level api and is subject to internal changes. These changes will not affect any applications or libraries using the higher-level apis (the command line interface or JIT compilation via `@angular/platform-browser-dynamic`). Only very specific use-cases require direct access to the compiler API (mostly tooling integration for IDEs, linters, etc). If you are working on this kind of integration, please reach out to us first.
Additionally only the command line usage (not direct use of APIs) of `@angular/compiler-cli` is covered.
Other projects developed by the Angular team like angular-cli, Angular Material, benchpress, will be covered by these or similar guarantees in the future as they mature.
Within the supported packages, we provide guarantees for:
- symbols exported via the main entry point (e.g. `@angular/core`) and testing entry point (e.g. `@angular/core/testing`). This applies to both runtime/JavaScript values and TypeScript types.
- symbols exported via global namespace `ng` (e.g. `ng.core`)
- bundles located in the `bundles/` directory of our npm packages (e.g. `@angular/core/bundles/core.umd.js`)
We explicitly don't consider the following to be our public API surface:
- any file/import paths within our package except for the `/`, `/testing` and `/bundles/*`
- constructors of injectable classes (services and directives) - please use DI to obtain instances of these classes
- any class members or symbols marked as `private` or prefixed with underscore
- extending any of our classes unless the support for this is specifically documented in the API docs
- the contents and API surface of the code generated by Angular's compiler (with one notable exception: the existence and name of `NgModuleFactory` instances exported from generated code is guaranteed)
Our peer dependencies (e.g. typescript, zone.js, or rxjs) are not considered part of our API surface, but they are included in our SemVer policies. We might update the required version of any of these dependencies in minor releases if the update doesn't cause breaking changes for Angular applications. Peer dependency updates that result in non-trivial breaking changes must be deferred to major Angular releases.

View File

@ -1,31 +1,51 @@
/**
* @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
*/
'use strict';
// 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/playground/**/*.ts', 'modules/benchmarks/**/*.ts', 'modules/e2e_util/**/*.ts'];
// clang-format entry points
const srcsToFmt = [
'modules/@angular/**/*.{js,ts}',
'modules/benchmarks/**/*.{js,ts}',
'modules/e2e_util/**/*.{js,ts}',
'modules/playground/**/*.{js,ts}',
'tools/**/*.{js,ts}',
'!tools/public_api_guard/**/*.d.ts',
'./*.{js,ts}',
'!shims_for_IE.js',
];
// Check source code for formatting errors (clang-format)
gulp.task('format:enforce', () => {
const format = require('gulp-clang-format');
const clangFormat = require('clang-format');
return gulp.src(srcsToFmt).pipe(
format.checkFormat('file', clangFormat, {verbose: true, fail: true}));
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');
return gulp.src(srcsToFmt, { base: '.' }).pipe(
format.format('file', clangFormat)).pipe(gulp.dest('.'));
return gulp.src(srcsToFmt, {base: '.'})
.pipe(format.format('file', clangFormat))
.pipe(gulp.dest('.'));
});
const entrypoints = [
@ -38,6 +58,7 @@ const entrypoints = [
//'dist/packages-dist/compiler/index.d.ts',
//'dist/packages-dist/compiler/testing.d.ts',
'dist/packages-dist/upgrade/index.d.ts',
'dist/packages-dist/upgrade/static.d.ts',
'dist/packages-dist/platform-browser/index.d.ts',
'dist/packages-dist/platform-browser/testing/index.d.ts',
'dist/packages-dist/platform-browser-dynamic/index.d.ts',
@ -49,78 +70,103 @@ const entrypoints = [
'dist/packages-dist/http/index.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 = [
'--rootDir', 'dist/packages-dist',
'--stripExportPattern', '^__',
'--allowModuleIdentifiers', 'jasmine',
'--allowModuleIdentifiers', 'protractor',
'--allowModuleIdentifiers', 'angular',
'--onStabilityMissing', 'error'
'--rootDir',
'dist/packages-dist',
'--stripExportPattern',
'^__',
'--allowModuleIdentifiers',
'jasmine',
'--allowModuleIdentifiers',
'protractor',
'--allowModuleIdentifiers',
'angular',
'--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' : ''}`),
['--verifyDir', publicApiDir].concat(publicApiArgs), {stdio: 'inherit'})
.on('close', (errorCode) => {
if (errorCode !== 0) {
done(new Error(
'Public API differs from golden file. Please run `gulp public-api:update`.'));
} else {
done();
}
});
.spawn(
path.join(__dirname, platformScriptPath(`/node_modules/.bin/ts-api-guardian`)),
['--verifyDir', publicApiDir].concat(publicApiArgs), {stdio: 'inherit'})
.on('close', (errorCode) => {
if (errorCode !== 0) {
done(new Error(
'Public API differs from golden file. Please run `gulp public-api:update`.'));
} else {
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' : ''}`),
['--outDir', publicApiDir].concat(publicApiArgs), {stdio: 'inherit'})
.on('close', (errorCode) => done(errorCode));
.spawn(
path.join(__dirname, platformScriptPath(`/node_modules/.bin/ts-api-guardian`)),
['--outDir', publicApiDir].concat(publicApiArgs), {stdio: 'inherit'})
.on('close', done);
});
// Check the coding standards and programming errors
gulp.task('lint', ['format:enforce', 'tools:build'], () => {
const tslint = require('gulp-tslint');
// Built-in rules are at
// https://github.com/palantir/tslint#supported-rules
// https://palantir.github.io/tslint/rules/
const tslintConfig = require('./tslint.json');
return gulp.src(['modules/@angular/**/*.ts', 'modules/benchpress/**/*.ts'])
.pipe(tslint({
tslint: require('tslint').default,
configuration: tslintConfig,
rulesDirectory: 'dist/tools/tslint',
formatter: 'prose'
}))
.pipe(tslint.report({emitError: true}));
return gulp
.src([
// todo(vicb): add .js files when supported
// see https://github.com/palantir/tslint/pull/1515
'./modules/**/*.ts',
'./tools/**/*.ts',
'./*.ts',
// Ignore TypeScript mocks because it's not managed by us
'!./tools/@angular/tsc-wrapped/test/typescript.mocks.ts',
// Ignore generated files due to lack of copyright header
// todo(alfaproject): make generated files lintable
'!**/*.d.ts',
'!**/*.ngfactory.ts',
])
.pipe(tslint({
tslint: require('tslint').default,
configuration: tslintConfig,
formatter: 'prose',
}))
.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, "//"); }
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);
@ -129,47 +175,47 @@ 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', () => {
let connect = require('gulp-connect');
let cors = require('cors');
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()]
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');
return gulp.src('CHANGELOG.md')
.pipe(conventionalChangelog({
preset: 'angular',
releaseCount: 1
}, {
// Conventional Changelog Context
// We have to manually set version number so it doesn't get prefixed with `v`
// See https://github.com/conventional-changelog/conventional-changelog-core/issues/10
currentTag: require('./package.json').version
}))
.pipe(gulp.dest('./'));
.pipe(conventionalChangelog({preset: 'angular', releaseCount: 1}, {
// Conventional Changelog Context
// We have to manually set version number so it doesn't get prefixed with `v`
// See https://github.com/conventional-changelog/conventional-changelog-core/issues/10
currentTag: require('./package.json').version
}))
.pipe(gulp.dest('./'));
});
function tsc(projectPath, done) {
@ -177,8 +223,12 @@ function tsc(projectPath, done) {
childProcess
.spawn(
path.normalize(`${__dirname}/node_modules/.bin/tsc`) + (/^win/.test(os.platform()) ? '.cmd' : ''),
['-p', path.join(__dirname, projectPath)],
{stdio: 'inherit'})
.on('close', (errorCode) => done(errorCode));
path.normalize(platformScriptPath(`${__dirname}/node_modules/.bin/tsc`)),
['-p', path.join(__dirname, projectPath)], {stdio: 'inherit'})
.on('close', done);
}
// returns the script path for the current platform
function platformScriptPath(path) {
return /^win/.test(os.platform()) ? `${path}.cmd` : path;
}

View File

@ -1,3 +1,11 @@
/**
* @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
*/
var browserProvidersConf = require('./browser-providers.conf.js');
var internalAngularReporter = require('./tools/karma/reporter.js');
@ -15,26 +23,27 @@ module.exports = function(config) {
'node_modules/core-js/client/core.js',
// include Angular v1 for upgrade module testing
'node_modules/angular/angular.min.js',
'node_modules/angular/angular.js',
'node_modules/zone.js/dist/zone.js',
'node_modules/zone.js/dist/long-stack-trace-zone.js',
'node_modules/zone.js/dist/proxy.js',
'node_modules/zone.js/dist/sync-test.js',
'node_modules/zone.js/dist/jasmine-patch.js',
'node_modules/zone.js/dist/async-test.js',
'node_modules/zone.js/dist/zone.js', 'node_modules/zone.js/dist/long-stack-trace-zone.js',
'node_modules/zone.js/dist/proxy.js', 'node_modules/zone.js/dist/sync-test.js',
'node_modules/zone.js/dist/jasmine-patch.js', 'node_modules/zone.js/dist/async-test.js',
'node_modules/zone.js/dist/fake-async-test.js',
// Including systemjs because it defines `__eval`, which produces correct stack traces.
'shims_for_IE.js',
'node_modules/systemjs/dist/system.src.js',
'shims_for_IE.js', 'node_modules/systemjs/dist/system.src.js',
{pattern: 'node_modules/rxjs/**', included: false, watched: false, served: true},
'node_modules/reflect-metadata/Reflect.js',
'tools/build/file2modulename.js',
'test-main.js',
{pattern: 'dist/all/empty.*', included: false, watched: false},
{pattern: 'modules/@angular/platform-browser/test/static_assets/**', included: false, watched: false},
{pattern: 'modules/@angular/platform-browser/test/browser/static_assets/**', included: false, watched: false}
'node_modules/reflect-metadata/Reflect.js', 'tools/build/file2modulename.js', 'test-main.js',
{pattern: 'dist/all/empty.*', included: false, watched: false}, {
pattern: 'modules/@angular/platform-browser/test/static_assets/**',
included: false,
watched: false
},
{
pattern: 'modules/@angular/platform-browser/test/browser/static_assets/**',
included: false,
watched: false,
}
],
exclude: [
@ -44,7 +53,7 @@ module.exports = function(config) {
'dist/all/@angular/benchpress/**',
'dist/all/angular1_router.js',
'dist/all/@angular/platform-browser/testing/e2e_util.js',
'dist/examples/**/e2e_test/**'
'dist/examples/**/e2e_test/**',
],
customLaunchers: browserProvidersConf.customLaunchers,
@ -55,11 +64,11 @@ module.exports = function(config) {
'karma-sauce-launcher',
'karma-chrome-launcher',
'karma-sourcemap-loader',
internalAngularReporter
internalAngularReporter,
],
preprocessors: {
'**/*.js': ['sourcemap']
'**/*.js': ['sourcemap'],
},
reporters: ['internal-angular'],
@ -73,7 +82,7 @@ module.exports = function(config) {
'selenium-version': '2.53.0',
'command-timeout': 600,
'idle-timeout': 600,
'max-duration': 5400
'max-duration': 5400,
}
},
@ -82,20 +91,21 @@ module.exports = function(config) {
startTunnel: false,
retryLimit: 3,
timeout: 600,
pollingTimeout: 10000
pollingTimeout: 10000,
},
browsers: ['Chrome'],
port: 9876,
captureTimeout: 60000,
browserDisconnectTimeout : 60000,
browserDisconnectTolerance : 3,
browserNoActivityTimeout : 60000,
browserDisconnectTimeout: 60000,
browserDisconnectTolerance: 3,
browserNoActivityTimeout: 60000,
});
if (process.env.TRAVIS) {
var buildId = 'TRAVIS #' + process.env.TRAVIS_BUILD_NUMBER + ' (' + process.env.TRAVIS_BUILD_ID + ')';
var buildId =
'TRAVIS #' + process.env.TRAVIS_BUILD_NUMBER + ' (' + process.env.TRAVIS_BUILD_ID + ')';
if (process.env.CI_MODE.startsWith('saucelabs')) {
config.sauceLabs.build = buildId;
config.sauceLabs.tunnelIdentifier = process.env.TRAVIS_JOB_NUMBER;

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

@ -5,7 +5,7 @@ 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
License: MIT
# Why?

View File

@ -9,8 +9,6 @@
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');
@ -34,7 +32,7 @@ export class Options {
{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.NOW, useValue: () => new Date()},
{provide: Options.RECEIVED_DATA, useValue: false},
{provide: Options.REQUEST_COUNT, useValue: false},
{provide: Options.CAPTURE_FRAMES, useValue: false},

View File

@ -42,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});
}
}

View File

@ -6,18 +6,15 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Map} from './facade/collection';
import {Date, DateWrapper} from './facade/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

@ -7,7 +7,6 @@
*/
import {Injector, OpaqueToken} from '@angular/core';
import {StringMapWrapper} from '../facade/collection';
import {Metric} from '../metric';
@ -57,8 +56,7 @@ export class MultiMetric extends Metric {
function mergeStringMaps(maps: {[key: string]: string}[]): {[key: string]: string} {
var result: {[key: string]: string} = {};
maps.forEach(
map => { StringMapWrapper.forEach(map, (value, prop) => { result[prop] = value; }); });
maps.forEach(map => { Object.keys(map).forEach(prop => { result[prop] = map[prop]; }); });
return result;
}

View File

@ -9,8 +9,6 @@
import {Inject, Injectable, OpaqueToken} from '@angular/core';
import {Options} from '../common_options';
import {ListWrapper, StringMapWrapper} from '../facade/collection';
import {Math, NumberWrapper, StringWrapper, isBlank, isPresent} from '../facade/lang';
import {Metric} from '../metric';
import {PerfLogEvent, PerfLogFeatures, WebDriverExtension} from '../web_driver_extension';
@ -95,8 +93,9 @@ export class PerflogMetric extends Metric {
res['frameTime.smooth'] = 'percentage of frames that hit 60fps';
}
}
StringMapWrapper.forEach(
this._microMetrics, (desc, name) => { StringMapWrapper.set(res, name, desc); });
for (let name in this._microMetrics) {
res[name] = this._microMetrics[name];
}
return res;
}
@ -126,8 +125,8 @@ export class PerflogMetric extends Metric {
.then((_) => this._endMeasure(restartMeasure))
.then((forceGcMeasureValues) => {
this._captureFrames = originalFrameCaptureValue;
StringMapWrapper.set(measureValues, 'forcedGcTime', forceGcMeasureValues['gcTime']);
StringMapWrapper.set(measureValues, 'forcedGcAmount', forceGcMeasureValues['gcAmount']);
measureValues['forcedGcTime'] = forceGcMeasureValues['gcTime'];
measureValues['forcedGcAmount'] = forceGcMeasureValues['gcAmount'];
return measureValues;
});
});
@ -152,7 +151,7 @@ export class PerflogMetric extends Metric {
return this._driverExtension.readPerfLog().then((events) => {
this._addEvents(events);
var result = this._aggregateEvents(this._remainingEvents, markName);
if (isPresent(result)) {
if (result) {
this._remainingEvents = events;
return result;
}
@ -166,14 +165,14 @@ export class PerflogMetric extends Metric {
private _addEvents(events: PerfLogEvent[]) {
var needSort = false;
events.forEach(event => {
if (StringWrapper.equals(event['ph'], 'X')) {
if (event['ph'] === 'X') {
needSort = true;
var startEvent: PerfLogEvent = {};
var endEvent: PerfLogEvent = {};
StringMapWrapper.forEach(event, (value, prop) => {
(<any>startEvent)[prop] = value;
(<any>endEvent)[prop] = value;
});
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'];
@ -185,7 +184,7 @@ export class PerflogMetric extends Metric {
});
if (needSort) {
// Need to sort because of the ph==='X' events
ListWrapper.sort(this._remainingEvents, (a, b) => {
this._remainingEvents.sort((a, b) => {
var diff = a['ts'] - b['ts'];
return diff > 0 ? 1 : diff < 0 ? -1 : 0;
});
@ -208,7 +207,9 @@ export class PerflogMetric extends Metric {
result['frameTime.worst'] = 0;
result['frameTime.smooth'] = 0;
}
StringMapWrapper.forEach(this._microMetrics, (desc, name) => { result[name] = 0; });
for (let name in this._microMetrics) {
result[name] = 0;
}
if (this._receivedData) {
result['receivedData'] = 0;
}
@ -218,6 +219,24 @@ export class PerflogMetric extends Metric {
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;
@ -228,120 +247,99 @@ export class PerflogMetric extends Metric {
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 (isPresent(microIterationsMatch)) {
if (microIterationsMatch) {
name = microIterationsMatch[1];
microIterations = NumberWrapper.parseInt(microIterationsMatch[2], 10);
microIterations = parseInt(microIterationsMatch[2], 10);
}
if (event === markStartEvent) {
inMeasureRange = true;
} else if (event === markEndEvent) {
inMeasureRange = false;
}
if (!inMeasureRange || event['pid'] !== markStartEvent['pid']) {
return;
}
if (StringWrapper.equals(ph, 'b') && StringWrapper.equals(name, markName)) {
markStartEvent = event;
} else if (StringWrapper.equals(ph, 'e') && StringWrapper.equals(name, markName)) {
markEndEvent = event;
}
let isInstant = StringWrapper.equals(ph, 'I') || StringWrapper.equals(ph, 'i');
if (this._requestCount && StringWrapper.equals(name, 'sendRequest')) {
if (this._requestCount && name === 'sendRequest') {
result['requestCount'] += 1;
} else if (this._receivedData && StringWrapper.equals(name, 'receivedData') && isInstant) {
} else if (this._receivedData && name === 'receivedData' && ph === 'I') {
result['receivedData'] += event['args']['encodedDataLength'];
} else if (StringWrapper.equals(name, 'navigationStart')) {
// We count data + requests since the last navigationStart
// (there might be chrome extensions loaded by selenium before our page, so there
// will likely be more than one navigationStart).
if (this._receivedData) {
result['receivedData'] = 0;
}
if (ph === 'B' && name === _MARK_NAME_FRAME_CAPUTRE) {
if (frameCaptureStartEvent) {
throw new Error('can capture frames only once per benchmark run');
}
if (this._requestCount) {
result['requestCount'] = 0;
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 (isPresent(markStartEvent) && isBlank(markEndEvent) &&
event['pid'] === markStartEvent['pid']) {
if (StringWrapper.equals(ph, 'b') && StringWrapper.equals(name, _MARK_NAME_FRAME_CAPUTRE)) {
if (isPresent(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 (
StringWrapper.equals(ph, 'e') && StringWrapper.equals(name, _MARK_NAME_FRAME_CAPUTRE)) {
if (isBlank(frameCaptureStartEvent)) {
throw new Error('missing start event for frame capture');
}
frameCaptureEndEvent = event;
}
if (isInstant) {
if (isPresent(frameCaptureStartEvent) && isBlank(frameCaptureEndEvent) &&
StringWrapper.equals(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]++;
}
if (StringWrapper.equals(ph, 'B') || StringWrapper.equals(ph, 'b')) {
if (isBlank(intervalStarts[name])) {
intervalStartCount[name] = 1;
intervalStarts[name] = event;
} else {
intervalStartCount[name]++;
}
} else if (
(StringWrapper.equals(ph, 'E') || StringWrapper.equals(ph, 'e')) &&
isPresent(intervalStarts[name])) {
intervalStartCount[name]--;
if (intervalStartCount[name] === 0) {
var startEvent = intervalStarts[name];
var duration = (event['ts'] - startEvent['ts']);
intervalStarts[name] = null;
if (StringWrapper.equals(name, 'gc')) {
result['gcTime'] += duration;
var amount =
(startEvent['args']['usedHeapSize'] - event['args']['usedHeapSize']) / 1000;
result['gcAmount'] += amount;
var majorGc = event['args']['majorGc'];
if (isPresent(majorGc) && majorGc) {
result['majorGcTime'] += duration;
}
if (isPresent(intervalStarts['script'])) {
gcTimeInScript += duration;
}
} else if (StringWrapper.equals(name, 'render')) {
result['renderTime'] += duration;
if (isPresent(intervalStarts['script'])) {
renderTimeInScript += duration;
}
} else if (StringWrapper.equals(name, 'script')) {
result['scriptTime'] += duration;
} else if (isPresent(this._microMetrics[name])) {
(<any>result)[name] += duration / microIterations;
} 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 (!isPresent(markStartEvent) || !isPresent(markEndEvent)) {
// not all events have been received, no further processing for now
return null;
}
if (isPresent(markEndEvent) && isPresent(frameCaptureStartEvent) &&
isBlank(frameCaptureEndEvent)) {
if (frameCaptureStartEvent && !frameCaptureEndEvent) {
throw new Error('missing end event for frame capture');
}
if (this._captureFrames && isBlank(frameCaptureStartEvent)) {
if (this._captureFrames && !frameCaptureStartEvent) {
throw new Error('frame capture requested in benchpress, but no start event was found');
}
if (frameTimes.length > 0) {

View File

@ -6,11 +6,9 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Inject, Injectable, OpaqueToken, Provider} from '@angular/core';
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';
@ -40,17 +38,17 @@ export class UserMetric extends Metric {
reject = rej;
});
let adapter = this._wdAdapter;
let names = StringMapWrapper.keys(this._userMetrics);
let names = Object.keys(this._userMetrics);
function getAndClearValues() {
Promise.all(names.map(name => adapter.executeScript(`return window.${name}`)))
.then((values: any[]) => {
if (values.every(isNumber)) {
if (values.every(v => typeof v === 'number')) {
Promise.all(names.map(name => adapter.executeScript(`delete window.${name}`)))
.then((_: any[]) => {
let map = 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);

View File

@ -7,10 +7,7 @@
*/
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 {print} from '../facade/lang';
import {MeasureValues} from '../measure_values';
import {Reporter} from '../reporter';
import {SampleDescription} from '../sample_description';

View File

@ -9,7 +9,6 @@
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';
@ -39,14 +38,15 @@ export class JsonFileReporter extends Reporter {
sortedProps(this._description.metrics).forEach((metricName) => {
stats[metricName] = formatStats(validSample, metricName);
});
var content = Json.stringify({
'description': this._description,
'stats': stats,
'completeSample': completeSample,
'validSample': validSample,
});
var filePath =
`${this._path}/${this._description.id}_${DateWrapper.toMillis(this._now())}.json`;
var content = JSON.stringify(
{
'description': this._description,
'stats': stats,
'completeSample': completeSample,
'validSample': validSample,
},
null, 2);
var filePath = `${this._path}/${this._description.id}_${this._now().getTime()}.json`;
return this._writeFile(filePath, content);
}
}

View File

@ -6,20 +6,15 @@
* 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);
return n.toFixed(2);
}
export function sortedProps(obj: {[key: string]: any}) {
var props: string[] = [];
StringMapWrapper.forEach(obj, (value, prop) => props.push(prop));
props.sort();
return props;
return Object.keys(obj).sort();
}
export function formatStats(validSamples: MeasureValues[], metricName: string): string {
@ -29,5 +24,5 @@ export function formatStats(validSamples: MeasureValues[], metricName: string):
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)}%`;
}
return isNaN(cv) ? formattedMean : `${formattedMean}+-${Math.floor(cv)}%`;
}

View File

@ -9,7 +9,7 @@
import {Provider, ReflectiveInjector} from '@angular/core';
import {Options} from './common_options';
import {isBlank, isPresent} from './facade/lang';
import {isPresent} from './facade/lang';
import {Metric} from './metric';
import {MultiMetric} from './metric/multi_metric';
import {PerflogMetric} from './metric/perflog_metric';

View File

@ -9,7 +9,6 @@
import {OpaqueToken} from '@angular/core';
import {Options} from './common_options';
import {StringMapWrapper} from './facade/collection';
import {Metric} from './metric';
import {Validator} from './validator';
@ -42,7 +41,7 @@ export class SampleDescription {
public metrics: {[key: string]: any}) {
this.description = {};
descriptions.forEach(description => {
StringMapWrapper.forEach(description, (value, prop) => this.description[prop] = value);
Object.keys(description).forEach(prop => { this.description[prop] = description[prop]; });
});
}

View File

@ -6,10 +6,10 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Inject, Injectable, OpaqueToken} from '@angular/core';
import {Inject, Injectable} from '@angular/core';
import {Options} from './common_options';
import {Date, DateWrapper, isBlank, isPresent} from './facade/lang';
import {isPresent} from './facade/lang';
import {MeasureValues} from './measure_values';
import {Metric} from './metric';
import {Reporter} from './reporter';
@ -49,7 +49,7 @@ export class Sampler {
}
private _iterate(lastState: SampleState): Promise<SampleState> {
var resultPromise: Promise<any>;
var resultPromise: Promise<SampleState>;
if (this._prepare !== Options.NO_PREPARE) {
resultPromise = this._driver.waitFor(this._prepare);
} else {
@ -77,5 +77,5 @@ export class Sampler {
}
export class SampleState {
constructor(public completeSample: any[], public validSample: any[]) {}
constructor(public completeSample: MeasureValues[], public validSample: MeasureValues[]) {}
}

View File

@ -6,8 +6,6 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Math} from './facade/math';
export class Statistic {
static calculateCoefficientOfVariation(sample: number[], mean: number) {
return Statistic.calculateStandardDeviation(sample, mean) / mean * 100;

View File

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

View File

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

View File

@ -9,16 +9,22 @@
import {Injector, OpaqueToken} from '@angular/core';
import {Options} from './common_options';
import {isBlank, isPresent} from './facade/lang';
export type PerfLogEvent = {
cat?: string,
ph?: 'X' | 'B' | 'E' | 'b' | 'e',
[key: string]: any
} & {
ph?: 'X' | 'B' | 'E' | 'I',
ts?: number,
dur?: number,
name?: string,
pid?: string,
args?: {encodedDataLength?: number, usedHeapSize?: number, majorGc?: number}
args?: {
encodedDataLength?: number,
usedHeapSize?: number,
majorGc?: boolean,
url?: string,
method?: string
}
};
/**
@ -43,7 +49,7 @@ export abstract class WebDriverExtension {
delegate = extension;
}
});
if (isBlank(delegate)) {
if (!delegate) {
throw new Error('Could not find a delegate for given capabilities!');
}
return delegate;
@ -64,8 +70,7 @@ export abstract class WebDriverExtension {
* 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}

View File

@ -9,16 +9,12 @@
import {Inject, Injectable} from '@angular/core';
import {Options} from '../common_options';
import {ListWrapper, StringMapWrapper} from '../facade/collection';
import {NumberWrapper, StringWrapper, isBlank, isPresent} from '../facade/lang';
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'
* '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.
@ -35,18 +31,18 @@ export class ChromeDriverExtension extends WebDriverExtension {
}
private _parseChromeVersion(userAgent: string): number {
if (isBlank(userAgent)) {
if (!userAgent) {
return -1;
}
var v = StringWrapper.split(userAgent, /Chrom(e|ium)\//g)[2];
if (isBlank(v)) {
var v = userAgent.split(/Chrom(e|ium)\//g)[2];
if (!v) {
return -1;
}
v = v.split('.')[0];
if (isBlank(v)) {
if (!v) {
return -1;
}
return NumberWrapper.parseInt(v, 10);
return parseInt(v, 10);
}
gc() { return this._driver.executeScript('window.gc()'); }
@ -57,7 +53,7 @@ export class ChromeDriverExtension extends WebDriverExtension {
timeEnd(name: string, restartName: string = null): Promise<any> {
var script = `console.timeEnd('${name}');`;
if (isPresent(restartName)) {
if (restartName) {
script += `console.time('${restartName}');`;
}
return this._driver.executeScript(script);
@ -74,10 +70,10 @@ export class ChromeDriverExtension extends WebDriverExtension {
var events: PerfLogEvent[] = [];
entries.forEach(entry => {
var message = JSON.parse(entry['message'])['message'];
if (StringWrapper.equals(message['method'], 'Tracing.dataCollected')) {
if (message['method'] === 'Tracing.dataCollected') {
events.push(message['params']);
}
if (StringWrapper.equals(message['method'], 'Tracing.bufferUsage')) {
if (message['method'] === 'Tracing.bufferUsage') {
throw new Error('The DevTools trace buffer filled during the test!');
}
});
@ -87,107 +83,64 @@ export class ChromeDriverExtension extends WebDriverExtension {
private _convertPerfRecordsToEvents(
chromeEvents: Array<{[key: string]: any}>, normalizedEvents: PerfLogEvent[] = null) {
if (isBlank(normalizedEvents)) {
if (!normalizedEvents) {
normalizedEvents = [];
}
var majorGCPids = {};
chromeEvents.forEach((event) => {
var categories = this._parseCategories(event['cat']);
var name = event['name'];
if (this._isEvent(categories, name, ['blink.console'])) {
normalizedEvents.push(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) {
normalizedEvents.push(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')) {
normalizedEvents.push(normalizeEvent(event, {'name': 'render'}));
} else if (this._majorChromeVersion < 45) {
var normalizedEvent = this._processAsPreChrome45Event(event, categories, majorGCPids);
if (normalizedEvent != null) normalizedEvents.push(normalizedEvent);
} else {
var normalizedEvent = this._processAsPostChrome44Event(event, categories);
if (normalizedEvent != null) normalizedEvents.push(normalizedEvent);
}
const categories = this._parseCategories(event['cat']);
const normalizedEvent = this._convertEvent(event, categories);
if (normalizedEvent != null) normalizedEvents.push(normalizedEvent);
});
return normalizedEvents;
}
private _processAsPreChrome45Event(
event: {[key: string]: any}, categories: string[], majorGCPids: {[key: string]: any}) {
private _convertEvent(event: {[key: string]: any}, categories: string[]) {
var name = event['name'];
var args = event['args'];
var pid = event['pid'];
var ph = event['ph'];
if (this._isEvent(
categories, name, ['disabled-by-default-devtools.timeline'], 'FunctionCall') &&
(isBlank(args) || isBlank(args['data']) ||
!StringWrapper.equals(args['data']['scriptName'], 'InjectedScript'))) {
return normalizeEvent(event, {'name': 'script'});
} else if (
this._isEvent(
categories, name, ['disabled-by-default-devtools.timeline'], 'RecalculateStyles') ||
this._isEvent(categories, name, ['disabled-by-default-devtools.timeline'], 'Layout') ||
this._isEvent(
categories, name, ['disabled-by-default-devtools.timeline'], 'UpdateLayerTree') ||
this._isEvent(categories, name, ['disabled-by-default-devtools.timeline'], 'Paint')) {
return normalizeEvent(event, {'name': 'render'});
if (this._isEvent(categories, name, ['blink.console'])) {
return normalizeEvent(event, {'name': name});
} else if (this._isEvent(
categories, name, ['disabled-by-default-devtools.timeline'], 'GCEvent')) {
var normArgs: {[key: string]: any} = {
'usedHeapSize': isPresent(args['usedHeapSizeAfter']) ? args['usedHeapSizeAfter'] :
args['usedHeapSizeBefore']
};
if (StringWrapper.equals(ph, 'E')) {
normArgs['majorGc'] = isPresent(majorGCPids[pid]) && majorGCPids[pid];
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'});
}
majorGCPids[pid] = false;
return normalizeEvent(event, {'name': 'gc', 'args': normArgs});
} else if (
this._isEvent(categories, name, ['v8'], 'majorGC') && StringWrapper.equals(ph, 'B')) {
majorGCPids[pid] = true;
}
return null; // nothing useful in this event
}
private _processAsPostChrome44Event(event: {[key: string]: any}, categories: string[]) {
var name = event['name'];
var args = event['args'];
if (this._isEvent(categories, name, ['devtools.timeline', 'v8'], 'MajorGC')) {
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': isPresent(args['usedHeapSizeAfter']) ? args['usedHeapSizeAfter'] :
args['usedHeapSizeBefore']
'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': isPresent(args['usedHeapSizeAfter']) ? args['usedHeapSizeAfter'] :
args['usedHeapSizeBefore']
'usedHeapSize': args['usedHeapSizeAfter'] !== undefined ? args['usedHeapSizeAfter'] :
args['usedHeapSizeBefore']
};
return normalizeEvent(event, {'name': 'gc', 'args': normArgs});
} else if (
this._isEvent(categories, name, ['devtools.timeline'], 'FunctionCall') &&
(isBlank(args) || isBlank(args['data']) ||
(!StringWrapper.equals(args['data']['scriptName'], 'InjectedScript') &&
!StringWrapper.equals(args['data']['scriptName'], '')))) {
(!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')) {
@ -205,7 +158,7 @@ export class ChromeDriverExtension extends WebDriverExtension {
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': name});
return normalizeEvent(event, {'name': 'navigationStart'});
}
return null; // nothing useful in this event
}
@ -216,9 +169,8 @@ export class ChromeDriverExtension extends WebDriverExtension {
eventCategories: string[], eventName: string, expectedCategories: string[],
expectedName: string = null): boolean {
var hasCategories = expectedCategories.reduce(
(value, cat) => { return value && ListWrapper.contains(eventCategories, cat); }, true);
return isBlank(expectedName) ? hasCategories :
hasCategories && StringWrapper.equals(eventName, expectedName);
(value, cat) => value && eventCategories.indexOf(cat) !== -1, true);
return !expectedName ? hasCategories : hasCategories && eventName === expectedName;
}
perfLogFeatures(): PerfLogFeatures {
@ -226,28 +178,31 @@ export class ChromeDriverExtension extends WebDriverExtension {
}
supports(capabilities: {[key: string]: any}): boolean {
return this._majorChromeVersion != -1 &&
StringWrapper.equals(capabilities['browserName'].toLowerCase(), 'chrome');
return this._majorChromeVersion >= 44 && capabilities['browserName'].toLowerCase() === 'chrome';
}
}
function normalizeEvent(
chromeEvent: {[key: string]: any}, data: {[key: string]: any}): PerfLogEvent {
var ph = chromeEvent['ph'];
if (StringWrapper.equals(ph, 'S')) {
ph = 'b';
} else if (StringWrapper.equals(ph, 'F')) {
ph = 'e';
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 (chromeEvent['ph'] === 'X') {
if (ph === 'X') {
var dur = chromeEvent['dur'];
if (isBlank(dur)) {
if (dur === undefined) {
dur = chromeEvent['tdur'];
}
result['dur'] = isBlank(dur) ? 0.0 : dur / 1000;
result['dur'] = !dur ? 0.0 : dur / 1000;
}
for (let prop in data) {
result[prop] = data[prop];
}
StringMapWrapper.forEach(data, (value, prop) => { result[prop] = value; });
return result;
}

View File

@ -8,7 +8,7 @@
import {Injectable} from '@angular/core';
import {StringWrapper, isPresent} from '../facade/lang';
import {isPresent} from '../facade/lang';
import {WebDriverAdapter} from '../web_driver_adapter';
import {PerfLogEvent, PerfLogFeatures, WebDriverExtension} from '../web_driver_extension';
@ -48,6 +48,6 @@ export class FirefoxDriverExtension extends WebDriverExtension {
perfLogFeatures(): PerfLogFeatures { return new PerfLogFeatures({render: true, gc: true}); }
supports(capabilities: {[key: string]: any}): boolean {
return StringWrapper.equals(capabilities['browserName'].toLowerCase(), 'firefox');
return capabilities['browserName'].toLowerCase() === 'firefox';
}
}

View File

@ -8,7 +8,7 @@
import {Injectable} from '@angular/core';
import {StringWrapper, isBlank, isPresent} from '../facade/lang';
import {isBlank, isPresent} from '../facade/lang';
import {WebDriverAdapter} from '../web_driver_adapter';
import {PerfLogEvent, PerfLogFeatures, WebDriverExtension} from '../web_driver_extension';
@ -42,7 +42,7 @@ export class IOsDriverExtension extends WebDriverExtension {
var records: any[] = [];
entries.forEach(entry => {
var message = JSON.parse(entry['message'])['message'];
if (StringWrapper.equals(message['method'], 'Timeline.eventRecorded')) {
if (message['method'] === 'Timeline.eventRecorded') {
records.push(message['params']['record']);
}
});
@ -52,7 +52,7 @@ export class IOsDriverExtension extends WebDriverExtension {
/** @internal */
private _convertPerfRecordsToEvents(records: any[], events: PerfLogEvent[] = null) {
if (isBlank(events)) {
if (!events) {
events = [];
}
records.forEach((record) => {
@ -62,19 +62,16 @@ export class IOsDriverExtension extends WebDriverExtension {
var startTime = record['startTime'];
var endTime = record['endTime'];
if (StringWrapper.equals(type, 'FunctionCall') &&
(isBlank(data) || !StringWrapper.equals(data['scriptName'], 'InjectedScript'))) {
if (type === 'FunctionCall' && (data == null || data['scriptName'] !== 'InjectedScript')) {
events.push(createStartEvent('script', startTime));
endEvent = createEndEvent('script', endTime);
} else if (StringWrapper.equals(type, 'Time')) {
} else if (type === 'Time') {
events.push(createMarkStartEvent(data['message'], startTime));
} else if (StringWrapper.equals(type, 'TimeEnd')) {
} else if (type === 'TimeEnd') {
events.push(createMarkEndEvent(data['message'], startTime));
} else if (
StringWrapper.equals(type, 'RecalculateStyles') || StringWrapper.equals(type, 'Layout') ||
StringWrapper.equals(type, 'UpdateLayerTree') || StringWrapper.equals(type, 'Paint') ||
StringWrapper.equals(type, 'Rasterize') ||
StringWrapper.equals(type, 'CompositeLayers')) {
type === 'RecalculateStyles' || type === 'Layout' || type === 'UpdateLayerTree' ||
type === 'Paint' || type === 'Rasterize' || type === 'CompositeLayers') {
events.push(createStartEvent('render', startTime));
endEvent = createEndEvent('render', endTime);
}
@ -92,12 +89,12 @@ export class IOsDriverExtension extends WebDriverExtension {
perfLogFeatures(): PerfLogFeatures { return new PerfLogFeatures({render: true}); }
supports(capabilities: {[key: string]: any}): boolean {
return StringWrapper.equals(capabilities['browserName'].toLowerCase(), 'safari');
return capabilities['browserName'].toLowerCase() === 'safari';
}
}
function createEvent(
ph: 'X' | 'B' | 'E' | 'b' | 'e', name: string, time: number, args: any = null) {
ph: 'X' | 'B' | 'E' | 'B' | 'E', name: string, time: number, args: any = null) {
var result: PerfLogEvent = {
'cat': 'timeline',
'name': name,
@ -122,9 +119,9 @@ function createEndEvent(name: string, time: number, args: any = null) {
}
function createMarkStartEvent(name: string, time: number) {
return createEvent('b', name, time);
return createEvent('B', name, time);
}
function createMarkEndEvent(name: string, time: number) {
return createEvent('e', name, time);
return createEvent('E', name, time);
}

View File

@ -6,14 +6,14 @@
* 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 {AsyncTestCompleter, describe, expect, inject, it} from '@angular/core/testing/testing_internal';
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)}; }),
ids.map(id => ({provide: id, useValue: new MockMetric(id)})),
MultiMetric.provideWith(ids)
])
.get(MultiMetric);

View File

@ -7,11 +7,10 @@
*/
import {Provider} from '@angular/core';
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {AsyncTestCompleter, beforeEach, describe, expect, inject, it} from '@angular/core/testing/testing_internal';
import {Metric, Options, PerfLogEvent, PerfLogFeatures, PerflogMetric, ReflectiveInjector, WebDriverExtension} from '../../index';
import {StringMapWrapper} from '../../src/facade/collection';
import {isBlank, isPresent} from '../../src/facade/lang';
import {isPresent} from '../../src/facade/lang';
import {TraceEventFactory} from '../trace_event_factory';
export function main() {
@ -28,12 +27,12 @@ export function main() {
requestCount?: boolean
} = {}): Metric {
commandLog = [];
if (isBlank(perfLogFeatures)) {
if (!perfLogFeatures) {
perfLogFeatures =
new PerfLogFeatures({render: true, gc: true, frameCapture: true, userTiming: true});
}
if (isBlank(microMetrics)) {
microMetrics = StringMapWrapper.create();
if (!microMetrics) {
microMetrics = {};
}
var providers: Provider[] = [
Options.DEFAULT_PROVIDERS, PerflogMetric.PROVIDERS,
@ -68,7 +67,7 @@ export function main() {
function sortedKeys(stringMap: {[key: string]: any}) {
var res: string[] = [];
StringMapWrapper.forEach(stringMap, (_, key) => { res.push(key); });
res.push(...Object.keys(stringMap));
res.sort();
return res;
}
@ -171,6 +170,22 @@ export function main() {
});
}));
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 = [
[

View File

@ -7,11 +7,9 @@
*/
import {Provider, ReflectiveInjector} from '@angular/core';
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {AsyncTestCompleter, describe, expect, inject, it} from '@angular/core/testing/testing_internal';
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';
import {Options, PerfLogEvent, PerfLogFeatures, UserMetric, WebDriverAdapter} from '../../index';
export function main() {
var wdAdapter: MockDriverAdapter;
@ -19,12 +17,12 @@ export function main() {
function createMetric(
perfLogs: PerfLogEvent[], perfLogFeatures: PerfLogFeatures,
{userMetrics}: {userMetrics?: {[key: string]: string}} = {}): UserMetric {
if (isBlank(perfLogFeatures)) {
if (!perfLogFeatures) {
perfLogFeatures =
new PerfLogFeatures({render: true, gc: true, frameCapture: true, userTiming: true});
}
if (isBlank(userMetrics)) {
userMetrics = StringMapWrapper.create();
if (!userMetrics) {
userMetrics = {};
}
wdAdapter = new MockDriverAdapter();
var providers: Provider[] = [

View File

@ -7,10 +7,10 @@
*/
import {Provider} from '@angular/core';
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {describe, expect, it} from '@angular/core/testing/testing_internal';
import {ConsoleReporter, MeasureValues, ReflectiveInjector, Reporter, SampleDescription, SampleState} from '../../index';
import {Date, DateWrapper, isBlank, isPresent} from '../../src/facade/lang';
import {ConsoleReporter, MeasureValues, ReflectiveInjector, SampleDescription} from '../../index';
import {isBlank, isPresent} from '../../src/facade/lang';
export function main() {
describe('console reporter', () => {
@ -25,10 +25,10 @@ export function main() {
metrics?: {[key: string]: any}
}) {
log = [];
if (isBlank(descriptions)) {
if (!descriptions) {
descriptions = [];
}
if (isBlank(sampleId)) {
if (sampleId == null) {
sampleId = 'null';
}
var providers: Provider[] = [
@ -90,5 +90,5 @@ export function main() {
}
function mv(runIndex: number, time: number, values: {[key: string]: number}) {
return new MeasureValues(runIndex, DateWrapper.fromMillis(time), values);
return new MeasureValues(runIndex, new Date(time), values);
}

View File

@ -6,10 +6,10 @@
* 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 {AsyncTestCompleter, describe, expect, inject, it} from '@angular/core/testing/testing_internal';
import {JsonFileReporter, MeasureValues, Options, ReflectiveInjector, SampleDescription} from '../../index';
import {DateWrapper, Json, isPresent} from '../../src/facade/lang';
import {isPresent} from '../../src/facade/lang';
export function main() {
describe('file reporter', () => {
@ -27,7 +27,7 @@ export function main() {
useValue: new SampleDescription(sampleId, descriptions, metrics)
},
{provide: JsonFileReporter.PATH, useValue: path},
{provide: Options.NOW, useValue: () => DateWrapper.fromMillis(1234)}, {
{provide: Options.NOW, useValue: () => new Date(1234)}, {
provide: Options.WRITE_FILE,
useValue: (filename: string, content: string) => {
loggedFile = {'filename': filename, 'content': content};
@ -51,7 +51,7 @@ export function main() {
[mv(0, 0, {'a': 3, 'b': 6}), mv(1, 1, {'a': 5, 'b': 9})]);
var regExp = /somePath\/someId_\d+\.json/;
expect(isPresent(loggedFile['filename'].match(regExp))).toBe(true);
var parsedContent = Json.parse(loggedFile['content']);
var parsedContent = JSON.parse(loggedFile['content']);
expect(parsedContent).toEqual({
'description': {
'id': 'someId',
@ -77,5 +77,5 @@ export function main() {
}
function mv(runIndex: number, time: number, values: {[key: string]: number}) {
return new MeasureValues(runIndex, DateWrapper.fromMillis(time), values);
return new MeasureValues(runIndex, new Date(time), values);
}

View File

@ -6,16 +6,15 @@
* 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 {AsyncTestCompleter, describe, expect, inject, it} from '@angular/core/testing/testing_internal';
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)}; }),
ids.map(id => ({provide: id, useValue: new MockReporter(id)})),
MultiReporter.provideWith(ids)
])
.get(MultiReporter);
@ -26,7 +25,7 @@ export function main() {
it('should reportMeasureValues to all',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var mv = new MeasureValues(0, DateWrapper.now(), {});
var mv = new MeasureValues(0, new Date(), {});
createReporters(['m1', 'm2']).then((r) => r.reportMeasureValues(mv)).then((values) => {
expect(values).toEqual([{'id': 'm1', 'values': mv}, {'id': 'm2', 'values': mv}]);
@ -35,9 +34,8 @@ export function main() {
}));
it('should reportSample to call', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var completeSample = [
new MeasureValues(0, DateWrapper.now(), {}), new MeasureValues(1, DateWrapper.now(), {})
];
var completeSample =
[new MeasureValues(0, new Date(), {}), new MeasureValues(1, new Date(), {})];
var validSample = [completeSample[1]];
createReporters(['m1', 'm2'])

View File

@ -6,10 +6,9 @@
* 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 {AsyncTestCompleter, describe, expect, inject, it} from '@angular/core/testing/testing_internal';
import {Injector, Metric, Options, ReflectiveInjector, Runner, SampleDescription, SampleState, Sampler, Validator, WebDriverAdapter} from '../index';
import {isBlank} from '../src/facade/lang';
export function main() {
describe('runner', () => {
@ -17,7 +16,7 @@ export function main() {
var runner: Runner;
function createRunner(defaultProviders: any[] = null): Runner {
if (isBlank(defaultProviders)) {
if (!defaultProviders) {
defaultProviders = [];
}
runner = new Runner([

View File

@ -6,10 +6,10 @@
* 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 {AsyncTestCompleter, describe, expect, inject, it} from '@angular/core/testing/testing_internal';
import {MeasureValues, Metric, Options, ReflectiveInjector, Reporter, Sampler, Validator, WebDriverAdapter} from '../index';
import {Date, DateWrapper, isBlank, isPresent, stringify} from '../src/facade/lang';
import {isBlank, isPresent} from '../src/facade/lang';
export function main() {
var EMPTY_EXECUTE = () => {};
@ -26,10 +26,10 @@ export function main() {
execute?: any
} = {}) {
var time = 1000;
if (isBlank(metric)) {
if (!metric) {
metric = new MockMetric([]);
}
if (isBlank(reporter)) {
if (!reporter) {
reporter = new MockReporter([]);
}
if (isBlank(driver)) {
@ -39,7 +39,7 @@ export function main() {
Options.DEFAULT_PROVIDERS, Sampler.PROVIDERS, {provide: Metric, useValue: metric},
{provide: Reporter, useValue: reporter}, {provide: WebDriverAdapter, useValue: driver},
{provide: Options.EXECUTE, useValue: execute}, {provide: Validator, useValue: validator},
{provide: Options.NOW, useValue: () => DateWrapper.fromMillis(time++)}
{provide: Options.NOW, useValue: () => new Date(time++)}
];
if (isPresent(prepare)) {
providers.push({provide: Options.PREPARE, useValue: prepare});
@ -60,8 +60,8 @@ export function main() {
createSampler({
driver: driver,
validator: createCountingValidator(2),
prepare: () => { return count++; },
execute: () => { return count++; }
prepare: () => count++,
execute: () => count++,
});
sampler.sample().then((_) => {
expect(count).toBe(4);
@ -204,7 +204,7 @@ export function main() {
}
function mv(runIndex: number, time: number, values: {[key: string]: number}) {
return new MeasureValues(runIndex, DateWrapper.fromMillis(time), values);
return new MeasureValues(runIndex, new Date(time), values);
}
function createCountingValidator(
@ -212,7 +212,7 @@ function createCountingValidator(
return new MockValidator(log, (completeSample: MeasureValues[]) => {
count--;
if (count === 0) {
return isPresent(validSample) ? validSample : completeSample;
return validSample || completeSample;
} else {
return null;
}
@ -221,7 +221,7 @@ function createCountingValidator(
function createCountingMetric(log: any[] = []) {
var scriptTime = 0;
return new MockMetric(log, () => { return {'script': scriptTime++}; });
return new MockMetric(log, () => ({'script': scriptTime++}));
}
class MockDriverAdapter extends WebDriverAdapter {

View File

@ -6,7 +6,7 @@
* 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 {describe, expect, it} from '@angular/core/testing/testing_internal';
import {Statistic} from '../src/statistic';
export function main() {

View File

@ -21,16 +21,16 @@ export class TraceEventFactory {
return res;
}
markStart(name: string, time: number) { return this.create('b', name, time); }
markStart(name: string, time: number) { return this.create('B', name, time); }
markEnd(name: string, time: number) { return this.create('e', 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);
return this.create('I', name, time, args);
}
complete(name: string, time: number, duration: number, args: any = null) {

View File

@ -6,11 +6,9 @@
* 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 {describe, expect, it} from '@angular/core/testing/testing_internal';
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', () => {
@ -45,22 +43,20 @@ export function main() {
it('should return the last sampleSize runs when the regression slope is ==0', () => {
createValidator({size: 2, metric: 'script'});
var sample = [mv(0, 0, {'script': 1}), mv(1, 1, {'script': 1}), mv(2, 2, {'script': 1})];
expect(validator.validate(ListWrapper.slice(sample, 0, 2)))
.toEqual(ListWrapper.slice(sample, 0, 2));
expect(validator.validate(sample)).toEqual(ListWrapper.slice(sample, 1, 3));
expect(validator.validate(sample.slice(0, 2))).toEqual(sample.slice(0, 2));
expect(validator.validate(sample)).toEqual(sample.slice(1, 3));
});
it('should return the last sampleSize runs when the regression slope is >0', () => {
createValidator({size: 2, metric: 'script'});
var sample = [mv(0, 0, {'script': 1}), mv(1, 1, {'script': 2}), mv(2, 2, {'script': 3})];
expect(validator.validate(ListWrapper.slice(sample, 0, 2)))
.toEqual(ListWrapper.slice(sample, 0, 2));
expect(validator.validate(sample)).toEqual(ListWrapper.slice(sample, 1, 3));
expect(validator.validate(sample.slice(0, 2))).toEqual(sample.slice(0, 2));
expect(validator.validate(sample)).toEqual(sample.slice(1, 3));
});
});
}
function mv(runIndex: number, time: number, values: {[key: string]: number}) {
return new MeasureValues(runIndex, DateWrapper.fromMillis(time), values);
return new MeasureValues(runIndex, new Date(time), values);
}

View File

@ -6,11 +6,9 @@
* 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 {describe, expect, it} from '@angular/core/testing/testing_internal';
import {MeasureValues, ReflectiveInjector, SizeValidator, Validator} from '../../index';
import {ListWrapper} from '../../src/facade/collection';
import {Date, DateWrapper} from '../../src/facade/lang';
import {MeasureValues, ReflectiveInjector, SizeValidator} from '../../index';
export function main() {
describe('size validator', () => {
@ -38,14 +36,13 @@ export function main() {
it('should return the last sampleSize runs when it has at least the given size', () => {
createValidator(2);
var sample = [mv(0, 0, {'a': 1}), mv(1, 1, {'b': 2}), mv(2, 2, {'c': 3})];
expect(validator.validate(ListWrapper.slice(sample, 0, 2)))
.toEqual(ListWrapper.slice(sample, 0, 2));
expect(validator.validate(sample)).toEqual(ListWrapper.slice(sample, 1, 3));
expect(validator.validate(sample.slice(0, 2))).toEqual(sample.slice(0, 2));
expect(validator.validate(sample)).toEqual(sample.slice(1, 3));
});
});
}
function mv(runIndex: number, time: number, values: {[key: string]: number}) {
return new MeasureValues(runIndex, DateWrapper.fromMillis(time), values);
return new MeasureValues(runIndex, new Date(time), values);
}

View File

@ -6,10 +6,10 @@
* 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 {AsyncTestCompleter, describe, expect, inject, it} from '@angular/core/testing/testing_internal';
import {Options, ReflectiveInjector, WebDriverExtension} from '../index';
import {StringWrapper, isPresent} from '../src/facade/lang';
import {isPresent} from '../src/facade/lang';
export function main() {
function createExtension(ids: any[], caps: any) {
@ -17,7 +17,7 @@ export function main() {
try {
res(ReflectiveInjector
.resolveAndCreate([
ids.map((id) => { return {provide: id, useValue: new MockExtension(id)}; }),
ids.map((id) => ({provide: id, useValue: new MockExtension(id)})),
{provide: Options.CAPABILITIES, useValue: caps},
WebDriverExtension.provideFirstSupported(ids)
])
@ -52,6 +52,6 @@ class MockExtension extends WebDriverExtension {
constructor(public id: string) { super(); }
supports(capabilities: {[key: string]: any}): boolean {
return StringWrapper.equals(capabilities['browser'], this.id);
return capabilities['browser'] === this.id;
}
}

View File

@ -6,16 +6,14 @@
* 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 {AsyncTestCompleter, describe, expect, inject, it} from '@angular/core/testing/testing_internal';
import {ChromeDriverExtension, Options, ReflectiveInjector, WebDriverAdapter, WebDriverExtension} from '../../index';
import {Json, isBlank} from '../../src/facade/lang';
import {isBlank} from '../../src/facade/lang';
import {TraceEventFactory} from '../trace_event_factory';
export function main() {
describe('chrome driver extension', () => {
var CHROME44_USER_AGENT =
'"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.0 Safari/537.36"';
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"';
@ -37,11 +35,11 @@ export function main() {
function createExtension(
perfRecords: any[] = null, userAgent: string = null,
messageMethod = 'Tracing.dataCollected'): WebDriverExtension {
if (isBlank(perfRecords)) {
if (!perfRecords) {
perfRecords = [];
}
if (isBlank(userAgent)) {
userAgent = CHROME44_USER_AGENT;
userAgent = CHROME45_USER_AGENT;
}
log = [];
extension = ReflectiveInjector
@ -89,228 +87,95 @@ export function main() {
});
}));
describe('readPerfLog Chrome44', () => {
it('should normalize times to ms and forward ph and pid event properties',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([chromeTimelineEvents.complete('FunctionCall', 1100, 5500, null)])
.readPerfLog()
.then((events) => {
expect(events).toEqual([
normEvents.complete('script', 1.1, 5.5, null),
]);
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 = chromeTimelineEvents.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 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([chromeTimelineEvents.start('FunctionCall', 0)])
.readPerfLog()
.then((events) => {
expect(events).toEqual([
normEvents.start('script', 0),
]);
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 gc', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([
chromeTimelineEvents.start('GCEvent', 1000, {'usedHeapSizeBefore': 1000}),
chromeTimelineEvents.end('GCEvent', 2000, {'usedHeapSizeAfter': 0}),
])
.readPerfLog()
.then((events) => {
expect(events).toEqual([
normEvents.start('gc', 1.0, {'usedHeapSize': 1000}),
normEvents.end('gc', 2.0, {'usedHeapSize': 0, 'majorGc': false}),
]);
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 ignore major gc from different processes',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([
chromeTimelineEvents.start('GCEvent', 1000, {'usedHeapSizeBefore': 1000}),
v8EventsOtherProcess.start('majorGC', 1100, null),
v8EventsOtherProcess.end('majorGC', 1200, null),
chromeTimelineEvents.end('GCEvent', 2000, {'usedHeapSizeAfter': 0}),
])
.readPerfLog()
.then((events) => {
expect(events).toEqual([
normEvents.start('gc', 1.0, {'usedHeapSize': 1000}),
normEvents.end('gc', 2.0, {'usedHeapSize': 0, 'majorGc': false}),
]);
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([
chromeTimelineEvents.start('GCEvent', 1000, {'usedHeapSizeBefore': 1000}),
v8Events.start('majorGC', 1100, null),
v8Events.end('majorGC', 1200, null),
chromeTimelineEvents.end('GCEvent', 2000, {'usedHeapSizeAfter': 0}),
])
.readPerfLog()
.then((events) => {
expect(events).toEqual([
normEvents.start('gc', 1.0, {'usedHeapSize': 1000}),
normEvents.end('gc', 2.0, {'usedHeapSize': 0, 'majorGc': true}),
]);
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();
});
}));
['RecalculateStyles', 'Layout', 'UpdateLayerTree', 'Paint'].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();
});
}));
});
it('should ignore FunctionCalls from webdriver',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension([chromeTimelineEvents.start(
'FunctionCall', 0, {'data': {'scriptName': 'InjectedScript'}})])
.readPerfLog()
.then((events) => {
expect(events).toEqual([]);
async.done();
});
}));
});
describe('readPerfLog Chrome45', () => {
it('should normalize times to ms and forward ph and pid event properties',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension(
[chromeTimelineV8Events.complete('FunctionCall', 1100, 5500, null)],
CHROME45_USER_AGENT)
.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], CHROME45_USER_AGENT).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)], CHROME45_USER_AGENT)
.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}),
],
CHROME45_USER_AGENT)
.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}),
],
CHROME45_USER_AGENT)
.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)
],
CHROME45_USER_AGENT)
.readPerfLog()
.then((events) => {
expect(events).toEqual([
normEvents.start('render', 1.234),
normEvents.end('render', 2.345),
]);
async.done();
});
}));
});
it(`should report UpdateLayoutTree as "render"`,
['Layout', 'UpdateLayerTree', 'Paint'].forEach((recordType) => {
it(`should report ${recordType} as "render"`,
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension(
[
chromeBlinkTimelineEvents.start('UpdateLayoutTree', 1234),
chromeBlinkTimelineEvents.end('UpdateLayoutTree', 2345)
],
CHROME45_USER_AGENT)
chrome45TimelineEvents.start(recordType, 1234),
chrome45TimelineEvents.end(recordType, 2345)
], )
.readPerfLog()
.then((events) => {
expect(events).toEqual([
@ -320,70 +185,80 @@ export function main() {
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.start('navigationStart', 1234)], CHROME45_USER_AGENT)
.readPerfLog()
.then((events) => {
expect(events).toEqual([normEvents.start('navigationStart', 1.234)]);
async.done();
});
}));
it('should report receivedData', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension(
[chrome45TimelineEvents.instant(
'ResourceReceivedData', 1234, {'data': {'encodedDataLength': 987}})],
CHROME45_USER_AGENT)
.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'}})],
CHROME45_USER_AGENT)
.readPerfLog()
.then((events) => {
expect(events).toEqual([normEvents.instant(
'sendRequest', 1.234, {'url': 'http://here', 'method': 'GET'})]);
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',
@ -404,8 +279,7 @@ export function main() {
[
chromeTimelineEvents.start(recordType, 1234),
chromeTimelineEvents.end(recordType, 2345)
],
CHROME45_USER_AGENT)
], )
.readPerfLog()
.then((events) => {
expect(events).toEqual([
@ -426,7 +300,7 @@ export function main() {
.readPerfLog()
.then((events) => {
expect(events).toEqual([
normEvents.create('i', 'frame', 1.1),
normEvents.instant('frame', 1.1),
]);
async.done();
});
@ -522,11 +396,11 @@ class MockDriverAdapter extends WebDriverAdapter {
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}})
};
}));
return Promise.resolve(this._events.map(
(event) => ({
'message': JSON.stringify(
{'message': {'method': this._messageMethod, 'params': event}}, null, 2)
})));
} else {
return null;
}

View File

@ -6,10 +6,9 @@
* 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 {AsyncTestCompleter, describe, expect, inject, it} from '@angular/core/testing/testing_internal';
import {IOsDriverExtension, ReflectiveInjector, WebDriverAdapter, WebDriverExtension} from '../../index';
import {Json, isBlank, isPresent} from '../../src/facade/lang';
import {TraceEventFactory} from '../trace_event_factory';
export function main() {
@ -20,7 +19,7 @@ export function main() {
var normEvents = new TraceEventFactory('timeline', 'pid0');
function createExtension(perfRecords: any[] = null): WebDriverExtension {
if (isBlank(perfRecords)) {
if (!perfRecords) {
perfRecords = [];
}
log = [];
@ -156,7 +155,7 @@ function timeEndRecord(name: string, time: number) {
}
function durationRecord(type: string, startTime: number, endTime: number, children: any[] = null) {
if (isBlank(children)) {
if (!children) {
children = [];
}
return {'type': type, 'startTime': startTime, 'endTime': endTime, 'children': children};
@ -184,8 +183,9 @@ class MockDriverAdapter extends WebDriverAdapter {
if (type === 'performance') {
return Promise.resolve(this._perfRecords.map(function(record) {
return {
'message': Json.stringify(
{'message': {'method': 'Timeline.eventRecorded', 'params': {'record': record}}})
'message': JSON.stringify(
{'message': {'method': 'Timeline.eventRecorded', 'params': {'record': record}}}, null,
2)
};
}));
} else {

View File

@ -1,3 +1,10 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
export default {
entry: '../../../dist/packages-dist/common/testing/index.js',
@ -10,4 +17,4 @@ export default {
'rxjs/Observable': 'Rx',
'rxjs/Subject': 'Rx'
}
}
};

View File

@ -1,3 +1,10 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
export default {
entry: '../../../dist/packages-dist/common/index.js',
@ -7,6 +14,6 @@ export default {
globals: {
'@angular/core': 'ng.core',
'rxjs/Observable': 'Rx',
'rxjs/Subject': 'Rx'
'rxjs/Subject': 'Rx',
}
}
};

View File

@ -11,8 +11,6 @@ import {CollectionChangeRecord, Directive, DoCheck, ElementRef, Input, IterableD
import {isListLikeIterable} from '../facade/collection';
import {isPresent} from '../facade/lang';
/**
* @ngModule CommonModule
*
@ -31,11 +29,11 @@ import {isPresent} from '../facade/lang';
*
* @description
*
* The CSS classes are updated as follow depending on the type of the expression evaluation:
* - `string` - the CSS classes listed in a string (space delimited) are added,
* - `Array` - the CSS classes (Array elements) are added,
* - `Object` - keys are CSS class names that get added when the expression given in the value
* evaluates to a truthy value, otherwise class are removed.
* The CSS classes are updated as follows, depending on the type of the expression evaluation:
* - `string` - the CSS classes listed in the string (space delimited) are added,
* - `Array` - the CSS classes declared as Array elements are added,
* - `Object` - keys are CSS classes that get added when the expression given in the value
* evaluates to a truthy value, otherwise they are removed.
*
* @stable
*/
@ -50,7 +48,6 @@ export class NgClass implements DoCheck {
private _iterableDiffers: IterableDiffers, private _keyValueDiffers: KeyValueDiffers,
private _ngEl: ElementRef, private _renderer: Renderer) {}
@Input('class')
set klass(v: string) {
this._applyInitialClasses(true);

View File

@ -11,14 +11,14 @@ import {Directive, Input, TemplateRef, ViewContainerRef} from '@angular/core';
/**
* Removes or recreates a portion of the DOM tree based on an {expression}.
*
* If the expression assigned to `ngIf` evaluates to a false value then the element
* If the expression assigned to `ngIf` evaluates to a falsy value then the element
* is removed from the DOM, otherwise a clone of the element is reinserted into the DOM.
*
* ### Example ([live demo](http://plnkr.co/edit/fe0kgemFBtmQOY31b4tw?p=preview)):
*
* ```
* <div *ngIf="errorCount > 0" class="error">
* <!-- Error message displayed when the errorCount property on the current context is greater
* <!-- Error message displayed when the errorCount property in the current context is greater
* than 0. -->
* {{errorCount}} errors detected
* </div>
@ -34,7 +34,7 @@ import {Directive, Input, TemplateRef, ViewContainerRef} from '@angular/core';
*/
@Directive({selector: '[ngIf]'})
export class NgIf {
private _hasView: boolean = false;
private _hasView = false;
constructor(private _viewContainer: ViewContainerRef, private _template: TemplateRef<Object>) {}

View File

@ -61,8 +61,7 @@ export class NgPlural {
addCase(value: string, switchView: SwitchView): void { this._caseViews[value] = switchView; }
/** @internal */
_updateView(): void {
private _updateView(): void {
this._clearViews();
const cases = Object.keys(this._caseViews);
@ -70,13 +69,11 @@ export class NgPlural {
this._activateView(this._caseViews[key]);
}
/** @internal */
_clearViews() {
private _clearViews() {
if (this._activeView) this._activeView.destroy();
}
/** @internal */
_activateView(view: SwitchView) {
private _activateView(view: SwitchView) {
if (view) {
this._activeView = view;
this._activeView.create();
@ -91,10 +88,12 @@ export class NgPlural {
* 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>
* ```
* <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.
*

View File

@ -32,10 +32,8 @@ import {Directive, DoCheck, ElementRef, Input, KeyValueChangeRecord, KeyValueDif
*/
@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) {}
@ -69,7 +67,7 @@ export class NgStyle implements DoCheck {
private _setStyle(nameAndUnit: string, value: string): void {
const [name, unit] = nameAndUnit.split('.');
value = value !== null && value !== void(0) && unit ? `${value}${unit}` : value;
value = value && unit ? `${value}${unit}` : value;
this._renderer.setElementStyle(this._ngEl.nativeElement, name, value);
}

View File

@ -10,7 +10,7 @@ import {Directive, Host, Input, TemplateRef, ViewContainerRef} from '@angular/co
import {ListWrapper} from '../facade/collection';
const _CASE_DEFAULT = new Object();
const _CASE_DEFAULT = {};
export class SwitchView {
constructor(
@ -38,7 +38,7 @@ export class SwitchView {
* <inner-element></inner-element>
* <inner-other-element></inner-other-element>
* </ng-container>
* <some-element *ngSwitchDefault>...</p>
* <some-element *ngSwitchDefault>...</some-element>
* </container-element>
* ```
* @description
@ -53,8 +53,7 @@ export class SwitchView {
* root elements.
*
* Elements within `NgSwitch` but outside of a `NgSwitchCase` or `NgSwitchDefault` directives will
* be
* preserved at the location.
* be preserved at the location.
*
* The `ngSwitchCase` directive informs the parent `NgSwitch` of which view to display when the
* expression is evaluated.
@ -72,18 +71,23 @@ export class NgSwitch {
@Input()
set ngSwitch(value: any) {
// Empty the currently active ViewContainers
this._emptyAllActiveViews();
// Add the ViewContainers matching the value (with a fallback to default)
this._useDefault = false;
// Set of views to display for this value
let views = this._valueViews.get(value);
if (!views) {
this._useDefault = true;
views = this._valueViews.get(_CASE_DEFAULT) || null;
}
this._activateViews(views);
if (views) {
this._useDefault = false;
} else {
// No view to display for the current value -> default case
// Nothing to do if the default case was already active
if (this._useDefault) {
return;
}
this._useDefault = true;
views = this._valueViews.get(_CASE_DEFAULT);
}
this._emptyAllActiveViews();
this._activateViews(views);
this._switchValue = value;
}
@ -111,8 +115,7 @@ export class NgSwitch {
}
}
/** @internal */
_emptyAllActiveViews(): void {
private _emptyAllActiveViews(): void {
const activeContainers = this._activeViews;
for (var i = 0; i < activeContainers.length; i++) {
activeContainers[i].destroy();
@ -120,9 +123,7 @@ export class NgSwitch {
this._activeViews = [];
}
/** @internal */
_activateViews(views: SwitchView[]): void {
// TODO(vicb): assert(this._activeViews.length === 0);
private _activateViews(views?: SwitchView[]): void {
if (views) {
for (var i = 0; i < views.length; i++) {
views[i].create();
@ -141,8 +142,7 @@ export class NgSwitch {
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;
const views = this._valueViews.get(value);
@ -162,10 +162,11 @@ export class NgSwitch {
* expression.
*
* @howToUse
* <container-element [ngSwitch]="switch_expression">
* <some-element *ngSwitchCase="match_expression_1">...</some-element>
* </container-element>
*
* ```
* <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
@ -180,10 +181,8 @@ export class NgSwitch {
@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(
@ -207,10 +206,12 @@ export class NgSwitchCase {
* 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>
* ```
* <container-element [ngSwitch]="switch_expression">
* <some-element *ngSwitchCase="match_expression_1">...</some-element>
* <some-other-element *ngSwitchDefault>...</some-other-element>
* </container-element>
* ```
*
* @description
*

View File

@ -6,7 +6,7 @@
* 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';
/**
* @ngModule CommonModule
@ -44,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

@ -67,7 +67,7 @@ export enum Plural {
Two,
Few,
Many,
Other
Other,
}
/**

View File

@ -49,16 +49,20 @@ export class Location {
_subject: EventEmitter<any> = new EventEmitter();
/** @internal */
_baseHref: string;
/** @internal */
_platformStrategy: LocationStrategy;
constructor(platformStrategy: LocationStrategy) {
this._platformStrategy = platformStrategy;
var browserBaseHref = this._platformStrategy.getBaseHref();
const browserBaseHref = this._platformStrategy.getBaseHref();
this._baseHref = Location.stripTrailingSlash(_stripIndexHtml(browserBaseHref));
this._platformStrategy.onPopState(
(ev) => { this._subject.emit({'url': this.path(true), 'pop': true, 'type': ev.type}); });
this._platformStrategy.onPopState((ev) => {
this._subject.emit({
'url': this.path(true),
'pop': true,
'type': ev.type,
});
});
}
/**

View File

@ -8,7 +8,7 @@
import {ChangeDetectorRef, OnDestroy, Pipe, WrappedValue} from '@angular/core';
import {EventEmitter, Observable} from '../facade/async';
import {isBlank, isPresent, isPromise} from '../facade/lang';
import {isPromise} from '../private_import_core';
import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
interface SubscriptionStrategy {
@ -37,9 +37,8 @@ class PromiseStrategy implements SubscriptionStrategy {
onDestroy(subscription: any): void {}
}
var _promiseStrategy = new PromiseStrategy();
var _observableStrategy = new ObservableStrategy();
var __unused: Promise<any>; // avoid unused import when Promise union types are erased
const _promiseStrategy = new PromiseStrategy();
const _observableStrategy = new ObservableStrategy();
/**
* @ngModule CommonModule
@ -68,30 +67,24 @@ var __unused: Promise<any>; // avoid unused import when Promise union types are
*/
@Pipe({name: 'async', pure: false})
export class AsyncPipe implements OnDestroy {
/** @internal */
_latestValue: Object = null;
/** @internal */
_latestReturnedValue: Object = null;
private _latestValue: Object = null;
private _latestReturnedValue: Object = null;
/** @internal */
_subscription: Object = null;
/** @internal */
_obj: Observable<any>|Promise<any>|EventEmitter<any> = null;
/** @internal */
_ref: ChangeDetectorRef;
private _subscription: Object = null;
private _obj: Observable<any>|Promise<any>|EventEmitter<any> = null;
private _strategy: SubscriptionStrategy = null;
constructor(_ref: ChangeDetectorRef) { this._ref = _ref; }
constructor(private _ref: ChangeDetectorRef) {}
ngOnDestroy(): void {
if (isPresent(this._subscription)) {
if (this._subscription) {
this._dispose();
}
}
transform(obj: Observable<any>|Promise<any>|EventEmitter<any>): any {
if (isBlank(this._obj)) {
if (isPresent(obj)) {
if (!this._obj) {
if (obj) {
this._subscribe(obj);
}
this._latestReturnedValue = this._latestValue;
@ -105,33 +98,32 @@ export class AsyncPipe implements OnDestroy {
if (this._latestValue === this._latestReturnedValue) {
return this._latestReturnedValue;
} else {
this._latestReturnedValue = this._latestValue;
return WrappedValue.wrap(this._latestValue);
}
this._latestReturnedValue = this._latestValue;
return WrappedValue.wrap(this._latestValue);
}
/** @internal */
_subscribe(obj: Observable<any>|Promise<any>|EventEmitter<any>): void {
private _subscribe(obj: Observable<any>|Promise<any>|EventEmitter<any>): void {
this._obj = obj;
this._strategy = this._selectStrategy(obj);
this._subscription = this._strategy.createSubscription(
obj, (value: Object) => this._updateLatestValue(obj, value));
}
/** @internal */
_selectStrategy(obj: Observable<any>|Promise<any>|EventEmitter<any>): any {
private _selectStrategy(obj: Observable<any>|Promise<any>|EventEmitter<any>): any {
if (isPromise(obj)) {
return _promiseStrategy;
} else if ((<any>obj).subscribe) {
return _observableStrategy;
} else {
throw new InvalidPipeArgumentError(AsyncPipe, obj);
}
if ((<any>obj).subscribe) {
return _observableStrategy;
}
throw new InvalidPipeArgumentError(AsyncPipe, obj);
}
/** @internal */
_dispose(): void {
private _dispose(): void {
this._strategy.dispose(this._subscription);
this._latestValue = null;
this._latestReturnedValue = null;
@ -139,8 +131,7 @@ export class AsyncPipe implements OnDestroy {
this._obj = null;
}
/** @internal */
_updateLatestValue(async: any, value: Object) {
private _updateLatestValue(async: any, value: Object) {
if (async === this._obj) {
this._latestValue = value;
this._ref.markForCheck();

View File

@ -7,10 +7,8 @@
*/
import {Inject, LOCALE_ID, Pipe, PipeTransform} from '@angular/core';
import {StringMapWrapper} from '../facade/collection';
import {DateFormatter} from '../facade/intl';
import {DateWrapper, NumberWrapper, isBlank, isDate, isString} from '../facade/lang';
import {NumberWrapper, isBlank, isDate} from '../facade/lang';
import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
@ -35,21 +33,21 @@ import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
* - `'shortTime'`: equivalent to `'jm'` (e.g. `12:05 PM` for `en-US`)
*
*
* | Component | Symbol | Short Form | Long Form | Numeric | 2-digit |
* |-----------|:------:|--------------|-------------------|-----------|-----------|
* | era | G | G (AD) | GGGG (Anno Domini)| - | - |
* | year | y | - | - | y (2015) | yy (15) |
* | month | M | MMM (Sep) | MMMM (September) | M (9) | MM (09) |
* | day | d | - | - | d (3) | dd (03) |
* | weekday | E | EEE (Sun) | EEEE (Sunday) | - | - |
* | hour | j | - | - | j (13) | jj (13) |
* | hour12 | h | - | - | h (1 PM) | hh (01 PM)|
* | hour24 | H | - | - | H (13) | HH (13) |
* | minute | m | - | - | m (5) | mm (05) |
* | second | s | - | - | s (9) | ss (09) |
* | timezone | z | - | z (Pacific Standard Time)| - | - |
* | timezone | Z | Z (GMT-8:00) | - | - | - |
* | timezone | a | a (PM) | - | - | - |
* | Component | Symbol | Narrow | Short Form | Long Form | Numeric | 2-digit |
* |-----------|:------:|--------|--------------|-------------------|-----------|-----------|
* | era | G | G (A) | GGG (AD) | GGGG (Anno Domini)| - | - |
* | year | y | - | - | - | y (2015) | yy (15) |
* | month | M | L (S) | MMM (Sep) | MMMM (September) | M (9) | MM (09) |
* | day | d | - | - | - | d (3) | dd (03) |
* | weekday | E | E (S) | EEE (Sun) | EEEE (Sunday) | - | - |
* | hour | j | - | - | - | j (13) | jj (13) |
* | hour12 | h | - | - | - | h (1 PM) | hh (01 PM)|
* | hour24 | H | - | - | - | H (13) | HH (13) |
* | minute | m | - | - | - | m (5) | mm (05) |
* | second | s | - | - | - | s (9) | ss (09) |
* | timezone | z | - | - | z (Pacific Standard Time)| - | - |
* | timezone | Z | - | Z (GMT-8:00) | - | - | - |
* | timezone | a | - | a (PM) | - | - | - |
*
* In javascript, only the components specified will be respected (not the ordering,
* punctuations, ...) and details of the formatting will be dependent on the locale.
@ -83,7 +81,7 @@ import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
@Pipe({name: 'date', pure: true})
export class DatePipe implements PipeTransform {
/** @internal */
static _ALIASES: {[key: string]: String} = {
static _ALIASES: {[key: string]: string} = {
'medium': 'yMMMdjms',
'short': 'yMdjm',
'fullDate': 'yMMMMEEEEd',
@ -104,23 +102,15 @@ export class DatePipe implements PipeTransform {
}
if (NumberWrapper.isNumeric(value)) {
value = DateWrapper.fromMillis(parseFloat(value));
} else if (isString(value)) {
value = DateWrapper.fromISOString(value);
value = parseFloat(value);
}
if (StringMapWrapper.contains(DatePipe._ALIASES, pattern)) {
pattern = <string>StringMapWrapper.get(DatePipe._ALIASES, pattern);
}
return DateFormatter.format(value, this._locale, pattern);
return DateFormatter.format(
new Date(value), this._locale, DatePipe._ALIASES[pattern] || pattern);
}
private supports(obj: any): boolean {
if (isDate(obj) || NumberWrapper.isNumeric(obj)) {
return true;
}
if (isString(obj) && isDate(DateWrapper.fromISOString(obj))) {
return true;
}
return false;
return isDate(obj) || NumberWrapper.isNumeric(obj) ||
(typeof obj === 'string' && isDate(new Date(obj)));
}
}

View File

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

View File

@ -7,7 +7,7 @@
*/
import {Pipe, PipeTransform} from '@angular/core';
import {isBlank, isStringMap} from '../facade/lang';
import {isBlank} from '../facade/lang';
import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
/**
@ -31,10 +31,10 @@ export class I18nSelectPipe implements PipeTransform {
transform(value: string, mapping: {[key: string]: string}): string {
if (isBlank(value)) return '';
if (!isStringMap(mapping)) {
if (typeof mapping !== 'object' || mapping === null) {
throw new InvalidPipeArgumentError(I18nSelectPipe, mapping);
}
return mapping.hasOwnProperty(value) ? mapping[value] : '';
return mapping[value] || '';
}
}

View File

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

View File

@ -7,7 +7,7 @@
*/
import {Pipe, PipeTransform} from '@angular/core';
import {isBlank, isString} from '../facade/lang';
import {isBlank} from '../facade/lang';
import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
@ -17,7 +17,7 @@ import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
* @howToUse `expression | lowercase`
* @description
*
* Converts value into lowercase string using `String.prototype.toLowerCase()`.
* Converts value into a lowercase string using `String.prototype.toLowerCase()`.
*
* ### Example
*
@ -29,7 +29,7 @@ import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
export class LowerCasePipe implements PipeTransform {
transform(value: string): string {
if (isBlank(value)) return value;
if (!isString(value)) {
if (typeof value !== 'string') {
throw new InvalidPipeArgumentError(LowerCasePipe, value);
}
return value.toLowerCase();

View File

@ -9,21 +9,23 @@
import {Inject, LOCALE_ID, Pipe, PipeTransform, Type} from '@angular/core';
import {NumberFormatStyle, NumberFormatter} from '../facade/intl';
import {NumberWrapper, isBlank, isNumber, isPresent, isString} from '../facade/lang';
import {NumberWrapper, isBlank, isPresent} from '../facade/lang';
import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
const _NUMBER_FORMAT_REGEXP = /^(\d+)?\.((\d+)(\-(\d+))?)?$/;
const _NUMBER_FORMAT_REGEXP = /^(\d+)?\.((\d+)(-(\d+))?)?$/;
function formatNumber(
pipe: Type<any>, locale: string, value: number | string, style: NumberFormatStyle,
digits: string, currency: string = null, currencyAsSymbol: boolean = false): string {
if (isBlank(value)) return null;
// Convert strings to numbers
value = isString(value) && NumberWrapper.isNumeric(value) ? +value : value;
if (!isNumber(value)) {
value = typeof value === 'string' && NumberWrapper.isNumeric(value) ? +value : value;
if (typeof value !== 'number') {
throw new InvalidPipeArgumentError(pipe, value);
}
let minInt: number;
let minFraction: number;
let maxFraction: number;
@ -34,8 +36,8 @@ function formatNumber(
maxFraction = 3;
}
if (isPresent(digits)) {
var parts = digits.match(_NUMBER_FORMAT_REGEXP);
if (digits) {
let parts = digits.match(_NUMBER_FORMAT_REGEXP);
if (parts === null) {
throw new Error(`${digits} is not a valid digit info for number pipes`);
}
@ -49,12 +51,13 @@ function formatNumber(
maxFraction = NumberWrapper.parseIntAutoRadix(parts[5]);
}
}
return NumberFormatter.format(value as number, locale, style, {
minimumIntegerDigits: minInt,
minimumFractionDigits: minFraction,
maximumFractionDigits: maxFraction,
currency: currency,
currencyAsSymbol: currencyAsSymbol
currencyAsSymbol: currencyAsSymbol,
});
}

View File

@ -7,8 +7,7 @@
*/
import {Pipe, PipeTransform} from '@angular/core';
import {ListWrapper} from '../facade/collection';
import {StringWrapper, isArray, isBlank, isString} from '../facade/lang';
import {isBlank} from '../facade/lang';
import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
/**
@ -58,16 +57,15 @@ import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
@Pipe({name: 'slice', pure: false})
export class SlicePipe implements PipeTransform {
transform(value: any, start: number, end: number = null): any {
transform(value: any, start: number, end?: number): any {
if (isBlank(value)) return value;
if (!this.supports(value)) {
throw new InvalidPipeArgumentError(SlicePipe, value);
}
if (isString(value)) {
return StringWrapper.slice(value, start, end);
}
return ListWrapper.slice(value, start, end);
return value.slice(start, end);
}
private supports(obj: any): boolean { return isString(obj) || isArray(obj); }
private supports(obj: any): boolean { return typeof obj === 'string' || Array.isArray(obj); }
}

View File

@ -7,7 +7,7 @@
*/
import {Pipe, PipeTransform} from '@angular/core';
import {isBlank, isString} from '../facade/lang';
import {isBlank} from '../facade/lang';
import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
/**
@ -16,7 +16,7 @@ import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
* @howToUse `expression | uppercase`
* @description
*
* Converts value into lowercase string using `String.prototype.toUpperCase()`.
* Converts value into an uppercase string using `String.prototype.toUpperCase()`.
*
* ### Example
*
@ -28,7 +28,7 @@ import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
export class UpperCasePipe implements PipeTransform {
transform(value: string): string {
if (isBlank(value)) return value;
if (!isString(value)) {
if (typeof value !== 'string') {
throw new InvalidPipeArgumentError(UpperCasePipe, value);
}
return value.toUpperCase();

View File

@ -6,7 +6,6 @@
* found in the LICENSE file at https://angular.io/license
*/
import {global} from './lang';
import {__core_private__ as r} from '@angular/core';
export var Math = global.Math;
export var NaN: any /** TODO #???? */ = typeof NaN;
export const isPromise: typeof r.isPromise = r.isPromise;

View File

@ -8,7 +8,7 @@
import {Component} from '@angular/core';
import {ComponentFixture, TestBed, async} from '@angular/core/testing';
import {beforeEach, ddescribe, describe, expect, iit, inject, it, xdescribe, xit} from '@angular/core/testing/testing_internal';
import {beforeEach, describe, expect, it} from '@angular/core/testing/testing_internal';
export function main() {
describe('binding to CSS class list', () => {

View File

@ -50,25 +50,6 @@ export function main() {
detectChangesAndExpectText('when b');
}));
// TODO(robwormald): deprecate and remove
it('should switch amongst when values using switchCase', async(() => {
const template = '<div>' +
'<ul [ngSwitch]="switchValue">' +
'<template ngSwitchCase="a"><li>when a</li></template>' +
'<template ngSwitchCase="b"><li>when b</li></template>' +
'</ul></div>';
fixture = createTestComponent(template);
detectChangesAndExpectText('');
getComponent().switchValue = 'a';
detectChangesAndExpectText('when a');
getComponent().switchValue = 'b';
detectChangesAndExpectText('when b');
}));
it('should switch amongst when values with fallback to default', async(() => {
const template = '<div>' +
'<ul [ngSwitch]="switchValue">' +
@ -84,6 +65,9 @@ export function main() {
getComponent().switchValue = 'b';
detectChangesAndExpectText('when default');
getComponent().switchValue = 'c';
detectChangesAndExpectText('when default');
}));
it('should support multiple whens with the same value', async(() => {

View File

@ -8,7 +8,7 @@
import {LOCALE_ID} from '@angular/core';
import {TestBed} from '@angular/core/testing';
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {beforeEach, describe, inject, it} from '@angular/core/testing/testing_internal';
import {expect} from '@angular/platform-browser/testing/matchers';
import {NgLocaleLocalization, NgLocalization, getPluralCategory} from '../src/localization';

View File

@ -8,12 +8,11 @@
import {AsyncPipe} from '@angular/common';
import {WrappedValue} from '@angular/core';
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {AsyncTestCompleter, beforeEach, describe, expect, inject, it} from '@angular/core/testing/testing_internal';
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
import {browserDetection} from '@angular/platform-browser/testing/browser_util';
import {EventEmitter} from '../../src/facade/async';
import {isBlank} from '../../src/facade/lang';
import {SpyChangeDetectorRef} from '../spies';
export function main() {
@ -112,7 +111,7 @@ export function main() {
var promise: Promise<any>;
var ref: SpyChangeDetectorRef;
// adds longer timers for passing tests in IE
var timer = (!isBlank(getDOM()) && browserDetection.isIE) ? 50 : 10;
var timer = (getDOM() && browserDetection.isIE) ? 50 : 10;
beforeEach(() => {
promise = new Promise((res, rej) => {

View File

@ -8,15 +8,12 @@
import {DatePipe} from '@angular/common';
import {PipeResolver} from '@angular/compiler/src/pipe_resolver';
import {afterEach, beforeEach, ddescribe, describe, expect, iit, it, xit} from '@angular/core/testing/testing_internal';
import {browserDetection} from '@angular/platform-browser/testing/browser_util';
import {DateWrapper} from '../../src/facade/lang';
export function main() {
describe('DatePipe', () => {
var date: Date;
var pipe: DatePipe;
let date: Date;
let pipe: DatePipe;
// TODO: reactivate the disabled expectations once emulators are fixed in SauceLabs
// In some old versions of Chrome in Android emulators, time formatting returns dates in the
@ -27,7 +24,7 @@ export function main() {
// Tracking issue: https://github.com/angular/angular/issues/11187
beforeEach(() => {
date = DateWrapper.create(2015, 6, 15, 9, 3, 1);
date = new Date(2015, 5, 15, 9, 3, 1);
pipe = new DatePipe('en-US');
});
@ -36,7 +33,9 @@ export function main() {
describe('supports', () => {
it('should support date', () => { expect(() => pipe.transform(date)).not.toThrow(); });
it('should support int', () => { expect(() => pipe.transform(123456789)).not.toThrow(); });
it('should support numeric strings',
() => { expect(() => pipe.transform('123456789')).not.toThrow(); });
@ -61,7 +60,7 @@ export function main() {
expect(pipe.transform(date, 'MMM')).toEqual('Jun');
expect(pipe.transform(date, 'MMMM')).toEqual('June');
expect(pipe.transform(date, 'd')).toEqual('15');
expect(pipe.transform(date, 'E')).toEqual('Mon');
expect(pipe.transform(date, 'EEE')).toEqual('Mon');
expect(pipe.transform(date, 'EEEE')).toEqual('Monday');
if (!browserDetection.isOldChrome) {
expect(pipe.transform(date, 'h')).toEqual('9');
@ -74,6 +73,9 @@ export function main() {
if (!browserDetection.isOldChrome) {
expect(pipe.transform(date, 'HH')).toEqual('09');
}
expect(pipe.transform(date, 'E')).toEqual('M');
expect(pipe.transform(date, 'L')).toEqual('J');
expect(pipe.transform(date, 'm')).toEqual('3');
expect(pipe.transform(date, 's')).toEqual('1');
expect(pipe.transform(date, 'mm')).toEqual('03');
@ -83,13 +85,13 @@ export function main() {
});
it('should format common multi component patterns', () => {
expect(pipe.transform(date, 'E, M/d/y')).toEqual('Mon, 6/15/2015');
expect(pipe.transform(date, 'E, M/d')).toEqual('Mon, 6/15');
expect(pipe.transform(date, 'EEE, M/d/y')).toEqual('Mon, 6/15/2015');
expect(pipe.transform(date, 'EEE, M/d')).toEqual('Mon, 6/15');
expect(pipe.transform(date, 'MMM d')).toEqual('Jun 15');
expect(pipe.transform(date, 'dd/MM/yyyy')).toEqual('15/06/2015');
expect(pipe.transform(date, 'MM/dd/yyyy')).toEqual('06/15/2015');
expect(pipe.transform(date, 'yMEd')).toEqual('20156Mon15');
expect(pipe.transform(date, 'MEd')).toEqual('6Mon15');
expect(pipe.transform(date, 'yMEEEd')).toEqual('20156Mon15');
expect(pipe.transform(date, 'MEEEd')).toEqual('6Mon15');
expect(pipe.transform(date, 'MMMd')).toEqual('Jun15');
expect(pipe.transform(date, 'yMMMMEEEEd')).toEqual('Monday, June 15, 2015');
// IE and Edge can't format a date to minutes and seconds without hours

View File

@ -8,7 +8,7 @@
import {I18nPluralPipe, NgLocalization} from '@angular/common';
import {PipeResolver} from '@angular/compiler/src/pipe_resolver';
import {afterEach, beforeEach, ddescribe, describe, expect, iit, it, xit} from '@angular/core/testing/testing_internal';
import {beforeEach, describe, expect, it} from '@angular/core/testing/testing_internal';
export function main() {
describe('I18nPluralPipe', () => {

View File

@ -8,7 +8,7 @@
import {I18nSelectPipe} from '@angular/common';
import {PipeResolver} from '@angular/compiler/src/pipe_resolver';
import {afterEach, beforeEach, ddescribe, describe, expect, iit, it, xit} from '@angular/core/testing/testing_internal';
import {beforeEach, describe, expect, it} from '@angular/core/testing/testing_internal';
export function main() {
describe('I18nSelectPipe', () => {

View File

@ -11,8 +11,6 @@ import {Component} from '@angular/core';
import {TestBed, async} from '@angular/core/testing';
import {expect} from '@angular/platform-browser/testing/matchers';
import {Json, StringWrapper} from '../../src/facade/lang';
export function main() {
describe('JsonPipe', () => {
var regNewLine = '\n';
@ -20,7 +18,7 @@ export function main() {
var inceptionObjString: string;
var pipe: JsonPipe;
function normalize(obj: string): string { return StringWrapper.replace(obj, regNewLine, ''); }
function normalize(obj: string): string { return obj.replace(regNewLine, ''); }
beforeEach(() => {
inceptionObj = {dream: {dream: {dream: 'Limbo'}}};
@ -48,7 +46,7 @@ export function main() {
it('should return JSON-formatted string similar to Json.stringify', () => {
var dream1 = normalize(pipe.transform(inceptionObj));
var dream2 = normalize(Json.stringify(inceptionObj));
var dream2 = normalize(JSON.stringify(inceptionObj, null, 2));
expect(dream1).toEqual(dream2);
});
});
@ -74,7 +72,6 @@ export function main() {
mutable.push(2);
fixture.detectChanges();
expect(fixture.nativeElement).toHaveText('[\n 1,\n 2\n]');
}));
});
});

View File

@ -7,7 +7,7 @@
*/
import {LowerCasePipe} from '@angular/common';
import {afterEach, beforeEach, ddescribe, describe, expect, iit, it, xit} from '@angular/core/testing/testing_internal';
import {beforeEach, describe, expect, it} from '@angular/core/testing/testing_internal';
export function main() {
describe('LowerCasePipe', () => {

View File

@ -7,7 +7,7 @@
*/
import {CurrencyPipe, DecimalPipe, PercentPipe} from '@angular/common';
import {afterEach, beforeEach, ddescribe, describe, expect, iit, it, xit} from '@angular/core/testing/testing_internal';
import {beforeEach, describe, expect, it} from '@angular/core/testing/testing_internal';
import {browserDetection} from '@angular/platform-browser/testing/browser_util';
export function main() {

View File

@ -9,7 +9,6 @@
import {CommonModule, SlicePipe} from '@angular/common';
import {Component} from '@angular/core';
import {TestBed, async} from '@angular/core/testing';
import {browserDetection} from '@angular/platform-browser/testing/browser_util';
import {expect} from '@angular/platform-browser/testing/matchers';
export function main() {

View File

@ -7,7 +7,7 @@
*/
import {UpperCasePipe} from '@angular/common';
import {afterEach, beforeEach, ddescribe, describe, expect, iit, it, xit} from '@angular/core/testing/testing_internal';
import {beforeEach, describe, expect, it} from '@angular/core/testing/testing_internal';
export function main() {
describe('UpperCasePipe', () => {

View File

@ -7,7 +7,7 @@
*/
import {ChangeDetectorRef} from '@angular/core/src/change_detection/change_detector_ref';
import {SpyObject, proxy} from '@angular/core/testing/testing_internal';
import {SpyObject} from '@angular/core/testing/testing_internal';
export class SpyChangeDetectorRef extends SpyObject {
constructor() {

View File

@ -18,9 +18,7 @@ import {EventEmitter, Injectable} from '@angular/core';
@Injectable()
export class SpyLocation implements Location {
urlChanges: string[] = [];
/** @internal */
private _history: LocationState[] = [new LocationState('', '')];
/** @internal */
private _historyIndex: number = 0;
/** @internal */
_subject: EventEmitter<any> = new EventEmitter();

View File

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

View File

@ -7,6 +7,7 @@
*/
export {CodeGenerator} from './src/codegen';
export {Extractor} from './src/extractor';
export {NodeReflectorHostContext, ReflectorHost, ReflectorHostContext} from './src/reflector_host';
export {StaticReflector, StaticReflectorHost, StaticSymbol} from './src/static_reflector';

View File

@ -0,0 +1,6 @@
# Overview
This folder will be filled with the benchmark sources
so that we can do offline compilation for them.

View File

@ -0,0 +1,18 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Component} from '@angular/core';
@Component({
selector: 'use-third-party',
template: '<third-party-comp [thirdParty]="title"></third-party-comp>' +
'<another-third-party-comp></another-third-party-comp>',
})
export class ComponentUsingThirdParty {
title: string = 'from 3rd party';
}

View File

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

View File

@ -9,4 +9,5 @@
<translationbundle>
<translation id="76e1eccb1b772fa9f294ef9c146ea6d0efa8a2d4">käännä teksti</translation>
<translation id="65cc4ab3b4c438e07c89be2b677d08369fb62da2">tervetuloa</translation>
<translation id="63a85808f03b8181e36a952e0fa38202c2304862">other-3rdP-component</translation>
</translationbundle>

View File

@ -11,9 +11,12 @@ import {FormsModule} from '@angular/forms';
import {BrowserModule} from '@angular/platform-browser';
import {MdButtonModule} from '@angular2-material/button';
import {ThirdpartyModule} from '../third_party_src/module';
import {MultipleComponentsMyComp, NextComp} from './a/multiple_components';
import {AnimateCmp} from './animate';
import {BasicComp} from './basic';
import {ComponentUsingThirdParty} from './comp_using_3rdp';
import {CompWithAnalyzeEntryComponentsProvider, CompWithEntryComponents} from './entry_components';
import {CompConsumingEvents, CompUsingPipes, CompWithProviders, CompWithReferences, DirPublishingEvents, ModuleUsingCustomElements} from './features';
import {CompUsingRootModuleDirectiveAndPipe, SomeDirectiveInRootModule, SomePipeInRootModule, SomeService, someLibModuleWithProviders} from './module_fixtures';
@ -22,35 +25,47 @@ import {CompForChildQuery, CompWithChildQuery, CompWithDirectiveChild, Directive
@NgModule({
declarations: [
SomeDirectiveInRootModule,
SomePipeInRootModule,
AnimateCmp,
BasicComp,
CompConsumingEvents,
CompForChildQuery,
CompWithEntryComponents,
CompUsingPipes,
CompUsingRootModuleDirectiveAndPipe,
CompWithAnalyzeEntryComponentsProvider,
ProjectingComp,
CompWithChildQuery,
CompWithDirectiveChild,
CompWithEntryComponents,
CompWithNgContent,
CompUsingRootModuleDirectiveAndPipe,
CompWithProviders,
CompWithReferences,
CompUsingPipes,
CompConsumingEvents,
DirectiveForQuery,
DirPublishingEvents,
MultipleComponentsMyComp,
DirectiveForQuery,
NextComp,
ProjectingComp,
SomeDirectiveInRootModule,
SomePipeInRootModule,
ComponentUsingThirdParty,
],
imports: [
BrowserModule, FormsModule, someLibModuleWithProviders(), ModuleUsingCustomElements,
MdButtonModule
BrowserModule,
FormsModule,
MdButtonModule,
ModuleUsingCustomElements,
someLibModuleWithProviders(),
ThirdpartyModule,
],
providers: [SomeService],
entryComponents: [
AnimateCmp, BasicComp, CompWithEntryComponents, CompWithAnalyzeEntryComponentsProvider,
ProjectingComp, CompWithChildQuery, CompUsingRootModuleDirectiveAndPipe, CompWithReferences
AnimateCmp,
BasicComp,
CompUsingRootModuleDirectiveAndPipe,
CompWithAnalyzeEntryComponentsProvider,
CompWithChildQuery,
CompWithEntryComponents,
CompWithReferences,
ProjectingComp,
ComponentUsingThirdParty,
]
})
export class MainModule {

View File

@ -43,13 +43,13 @@ describe('template codegen output', () => {
});
it('should be able to create the basic component', () => {
var compFixture = createComponent(BasicComp);
const compFixture = createComponent(BasicComp);
expect(compFixture.componentInstance).toBeTruthy();
});
it('should support ngIf', () => {
var compFixture = createComponent(BasicComp);
var debugElement = compFixture.debugElement;
const compFixture = createComponent(BasicComp);
const debugElement = compFixture.debugElement;
expect(debugElement.children.length).toBe(3);
compFixture.componentInstance.ctxBool = true;
@ -59,8 +59,8 @@ describe('template codegen output', () => {
});
it('should support ngFor', () => {
var compFixture = createComponent(BasicComp);
var debugElement = compFixture.debugElement;
const compFixture = createComponent(BasicComp);
const debugElement = compFixture.debugElement;
expect(debugElement.children.length).toBe(3);
// test NgFor
@ -83,11 +83,9 @@ describe('template codegen output', () => {
});
it('should support i18n for content tags', () => {
const compFixture = createComponent(BasicComp);
const debugElement = compFixture.debugElement;
const containerElement = <any>debugElement.nativeElement;
const pElement = <any>containerElement.children.find((c: any) => c.name == 'p');
const pText = <string>pElement.children.map((c: any) => c.data).join('').trim();
const containerElement = createComponent(BasicComp).nativeElement;
const pElement = containerElement.children.find((c: any) => c.name == 'p');
const pText = pElement.children.map((c: any) => c.data).join('').trim();
expect(pText).toBe('tervetuloa');
});
});

View File

@ -34,27 +34,34 @@ const EXPECTED_XMB = `<?xml version="1.0" encoding="UTF-8" ?>
<!ELEMENT ex (#PCDATA)>
]>
<messagebundle>
<msg id="63a85808f03b8181e36a952e0fa38202c2304862">other-3rdP-component</msg>
<msg id="76e1eccb1b772fa9f294ef9c146ea6d0efa8a2d4" desc="desc" meaning="meaning">translate me</msg>
<msg id="65cc4ab3b4c438e07c89be2b677d08369fb62da2">Welcome</msg>
</messagebundle>`;
</messagebundle>
`;
const EXPECTED_XLIFF = `<?xml version="1.0" encoding="UTF-8" ?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
<file source-language="en" datatype="plaintext" original="ng2.template">
<body>
<trans-unit id="76e1eccb1b772fa9f294ef9c146ea6d0efa8a2d4" datatype="html">
<source>translate me</source>
<target/>
<note priority="1" from="description">desc</note>
<note priority="1" from="meaning">meaning</note>
</trans-unit>
<trans-unit id="65cc4ab3b4c438e07c89be2b677d08369fb62da2" datatype="html">
<source>Welcome</source>
<target/>
</trans-unit>
</body>
</file>
</xliff>`;
<file source-language="en" datatype="plaintext" original="ng2.template">
<body>
<trans-unit id="63a85808f03b8181e36a952e0fa38202c2304862" datatype="html">
<source>other-3rdP-component</source>
<target/>
</trans-unit>
<trans-unit id="76e1eccb1b772fa9f294ef9c146ea6d0efa8a2d4" datatype="html">
<source>translate me</source>
<target/>
<note priority="1" from="description">desc</note>
<note priority="1" from="meaning">meaning</note>
</trans-unit>
<trans-unit id="65cc4ab3b4c438e07c89be2b677d08369fb62da2" datatype="html">
<source>Welcome</source>
<target/>
</trans-unit>
</body>
</file>
</xliff>
`;
describe('template i18n extraction output', () => {
const outDir = '';

View File

@ -7,6 +7,7 @@
*/
import './init';
import {ComponentUsingThirdParty} from '../src/comp_using_3rdp';
import {MainModule} from '../src/module';
import {CompUsingLibModuleDirectiveAndPipe, CompUsingRootModuleDirectiveAndPipe, SOME_TOKEN, ServiceUsingLibModule, SomeLibModule, SomeService} from '../src/module_fixtures';
@ -15,9 +16,9 @@ import {createComponent, createModule} from './util';
describe('NgModule', () => {
it('should support providers', () => {
const moduleRef = createModule();
expect(moduleRef.instance instanceof MainModule).toBe(true);
expect(moduleRef.injector.get(MainModule) instanceof MainModule).toBe(true);
expect(moduleRef.injector.get(SomeService) instanceof SomeService).toBe(true);
expect(moduleRef.instance instanceof MainModule).toEqual(true);
expect(moduleRef.injector.get(MainModule) instanceof MainModule).toEqual(true);
expect(moduleRef.injector.get(SomeService) instanceof SomeService).toEqual(true);
});
it('should support entryComponents components', () => {
@ -26,7 +27,7 @@ describe('NgModule', () => {
CompUsingRootModuleDirectiveAndPipe);
expect(cf.componentType).toBe(CompUsingRootModuleDirectiveAndPipe);
const compRef = cf.create(moduleRef.injector);
expect(compRef.instance instanceof CompUsingRootModuleDirectiveAndPipe).toBe(true);
expect(compRef.instance instanceof CompUsingRootModuleDirectiveAndPipe).toEqual(true);
});
it('should support entryComponents via the ANALYZE_FOR_ENTRY_COMPONENTS provider and function providers in components',
@ -42,12 +43,30 @@ describe('NgModule', () => {
]);
});
describe('third-party modules', () => {
// https://github.com/angular/angular/issues/11889
it('should support third party entryComponents components', () => {
const fixture = createComponent(ComponentUsingThirdParty);
const thirdPComps = fixture.nativeElement.children;
expect(thirdPComps[0].children[0].children[0].data).toEqual('3rdP-component');
expect(thirdPComps[1].children[0].children[0].data).toEqual('other-3rdP-component');
});
// https://github.com/angular/angular/issues/12428
it('should support third party directives', () => {
const fixture = createComponent(ComponentUsingThirdParty);
const debugElement = fixture.debugElement;
fixture.detectChanges();
expect(debugElement.children[0].properties['title']).toEqual('from 3rd party');
});
});
it('should support module directives and pipes', () => {
const compFixture = createComponent(CompUsingRootModuleDirectiveAndPipe);
compFixture.detectChanges();
const debugElement = compFixture.debugElement;
expect(debugElement.children[0].properties['title']).toBe('transformed someValue');
expect(debugElement.children[0].properties['title']).toEqual('transformed someValue');
});
it('should support module directives and pipes on lib modules', () => {
@ -55,10 +74,10 @@ describe('NgModule', () => {
compFixture.detectChanges();
const debugElement = compFixture.debugElement;
expect(debugElement.children[0].properties['title']).toBe('transformed someValue');
expect(debugElement.children[0].properties['title']).toEqual('transformed someValue');
expect(debugElement.injector.get(SomeLibModule) instanceof SomeLibModule).toBe(true);
expect(debugElement.injector.get(SomeLibModule) instanceof SomeLibModule).toEqual(true);
expect(debugElement.injector.get(ServiceUsingLibModule) instanceof ServiceUsingLibModule)
.toBe(true);
.toEqual(true);
});
});

View File

@ -0,0 +1,8 @@
This folder emulates consuming precompiled modules and components.
It is compiled separately from the other sources under `src`
to only generate `*.js` / `*.d.ts` / `*.metadata.json` files,
but no `*.ngfactory.ts` files.
** WARNING **
Do not import components/directives from here directly as we want to test that ngc still compiles
them when they are not imported.

View File

@ -0,0 +1,16 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Component} from '@angular/core';
@Component({
selector: 'third-party-comp',
template: '<div>3rdP-component</div>',
})
export class ThirdPartyComponent {
}

View File

@ -0,0 +1,17 @@
/**
* @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, Input} from '@angular/core';
@Directive({
selector: '[thirdParty]',
host: {'[title]': 'thirdParty'},
})
export class ThirdPartyDirective {
@Input() thirdParty: string;
}

View File

@ -0,0 +1,28 @@
/**
* @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 {ThirdPartyComponent} from './comp';
import {ThirdPartyDirective} from './directive';
import {AnotherThirdPartyModule} from './other_module';
@NgModule({
declarations: [
ThirdPartyComponent,
ThirdPartyDirective,
],
exports: [
AnotherThirdPartyModule,
ThirdPartyComponent,
ThirdPartyDirective,
],
imports: [AnotherThirdPartyModule]
})
export class ThirdpartyModule {
}

View File

@ -0,0 +1,16 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Component} from '@angular/core';
@Component({
selector: 'another-third-party-comp',
template: '<div i18n>other-3rdP-component</div>',
})
export class AnotherThirdpartyComponent {
}

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