Compare commits

..

113 Commits

Author SHA1 Message Date
96efb4b165 ci: temporary work-around for Travis issue (#21422)
See
https://github.com/travis-ci/travis-ci/issues/8836#issuecomment-356362524
for more info.

PR Close #21422
2018-01-09 12:25:33 -08:00
7c34807765 build(aio): upgrade to zone.js@0.8.19 (#21349)
This causes a 3.4kb size regressions for polyfills.js. :-(

I filed an issue for this: https://github.com/angular/zone.js/issues/989

-rw-r--r--  1 iminar  eng   73998 Jan  5 17:51 dist/0.5fb611ef423970fd3ba1.chunk.js
-rw-r--r--  1 iminar  eng   14880 Jan  5 17:51 dist/4.c719ac5645940382cdce.chunk.js
-rw-r--r--  1 iminar  eng    1558 Jan  5 17:51 dist/inline.797233300016416206fc.bundle.js
-rw-r--r--  1 iminar  eng  457592 Jan  5 17:51 dist/main.5870135237d5187f1ab6.bundle.js
-rw-r--r--  1 iminar  eng   40684 Jan  5 17:51 dist/polyfills.88f0257676f76560da16.bundle.js
-rw-r--r--  1 iminar  eng   54001 Jan  5 17:51 dist/worker-basic.min.js

PR Close #21349
2018-01-09 10:34:10 -08:00
84f6b148d5 fix(bazel): Give correct module names for ES6 output (#21320)
Fixes #21022

PR Close #21320
2018-01-09 10:31:18 -08:00
39f81b210e build: upgrade Bazel to 0.9.0 (#21335)
Also install the skylark linter for .bzl files.

PR Close #21335
2018-01-09 10:29:01 -08:00
0602aaa06c fix(benchpress): work around missing events from Chrome 63 (#21396)
Chrome 63 can cause the navigationStart event for the first
run to arrive with a different pid than the start of the
benchpress run. This makes the first collected result invalid.

This workaround causes the sampler to ignore runs that have this
condition.

PR Close #21396
2018-01-08 16:14:52 -08:00
a73b0b64fb docs(aio): fix punctuation for clarity (#21325)
PR Close #21325
2018-01-08 16:12:38 -08:00
fda3815395 fix(benchpress): forward compat with selenium_webdriver 3.6.0 (#21399)
This was a local mod in google3 introduced by cl 174212464

PR Close #21399
2018-01-08 13:09:39 -08:00
4f7c13d554 build(core): reduce payload limit back to normal (#21395)
PR Close #21395
2018-01-08 12:13:18 -08:00
4947454344 ci: reformat itegration/_payload-limits.json to be easier to read (#21345)
PR Close #21345
2018-01-08 13:26:08 -05:00
e86ce590fe build: upgrade to @angular/cli@1.6.3 (#21345)
there is a size regression that we are investigating.. :-(

PR Close #21345
2018-01-08 13:26:08 -05:00
1bd03a4081 docs(aio): document the template compiler options (#21333)
PR Close #21333
2018-01-08 13:24:16 -05:00
8b197b24f5 build(core): improve payload size failure message (#21346)
PR Close #21346
2018-01-08 13:15:26 -05:00
8f3ea339f7 build(core): update payload size of hello-world in patch branch (#21343)
PR Close #21343
2018-01-05 15:25:38 -08:00
839d24e427 fix(common): export currencies via getCurrencySymbol (#20983)
PR Close #20983
2018-01-05 14:24:34 -08:00
a1af559e16 build(core): update payload size of hello world (#21340)
PR Close #21340
2018-01-05 14:21:53 -08:00
e2cc4dbfc0 docs(aio): delete duplicated word (#21129)
PR Close #21129
2018-01-05 16:22:40 -05:00
5dd2df6a58 build: force fetch PR in merge script (#21295)
Use `-f` when doing `git fetch` for the PR. Without 
it the `git fetch` will not overwrite what is currently 
fetched locally, in essence doing fast-forward only.
PR Close #21295
2018-01-05 15:02:04 -05:00
52cb79ccb5 build(aio): add @nodoc alias to the @internal tag (#21024)
The `@internal` tag prevents code items from appearing in the docs and the
typings files. You can now use `@nodoc` if you only want it to be excluded
from the docs and not the typings files.

Closes #20990

PR Close #21024
2018-01-05 15:00:19 -05:00
17e85cd9a5 build(aio): fix plunker for custom plunkers (#21291)
PR Close #21291
2018-01-05 14:55:50 -05:00
8dd93f844f docs: remove broken issuestats.com badges (#21334)
PR Close #21334
2018-01-05 14:43:38 -05:00
c809545c77 test(aio): wait for Angular to avoid flake in e2e test (#21047)
PR Close #21047
2018-01-05 14:34:32 -05:00
d3c0425786 docs(router): fix missing export in docs for UrlMatcher (#21095)
Fixes #21042

PR Close #21095
2018-01-04 17:48:45 -05:00
088c1e3286 docs(common): update copyright years (#21232)
PR Close #21232
2018-01-04 17:45:47 -05:00
d79a0ba5b6 docs(aio): add missing imports to interceptor example (#21259)
PR Close #21259
2018-01-04 17:40:41 -05:00
b7307c9517 fix(aio): fix test message's mistake. (#21254)
duplicated message for 1st link. /heroes is 2nd link.

PR Close #21254
2018-01-04 17:38:39 -05:00
cc0b0a4729 fix(aio): do not redirect pages on "next" deployment (#21027)
We redirect non-docs pages in the "archive" deployment back to the stable
deployment. We should not redirect pages in the "next" deployment.

Closes #19505

PR Close #21027
2018-01-04 17:14:07 -05:00
5efb751a09 build(aio): fix example protractor config for Travis (#21309)
Without setting the CHROME_BIN Travis will not use the correct version
of Chrome for running e2e tests.

Closes #20159

PR Close #21309
2018-01-04 17:10:12 -05:00
b9d8ac5b2d fix(aio): don't use Object.keys on NamedNodeMap to prevent SEO errors (#21305)
Apparently Object.keys on NamedNodeMap work differently with googlebot :-(

There are not tests since we don't have a way to write tests for googlebot,
but I did manually verify that after this fix googlebot correctly renders
several of the previously broken pages.

Fixes #21272

PR Close #21305
2018-01-04 14:25:38 -05:00
fc217f552a refactor(aio): use one argument for DocViewer error reporting (#21293)
Pass one argument to `logger.error()` to improve error reporting in
environments that do not handle more than one arguments well (e.g.
Googlebot's web rendering service).

Related to #21272.

PR Close #21293
2018-01-03 17:10:51 -08:00
d138b38bdb docs: add changelog for 5.1.3 2018-01-03 15:54:57 -08:00
4f409954f8 release: cut the 5.1.3 release 2018-01-03 15:53:22 -08:00
00308fcc9f build: update rules_typescript in integration test 2018-01-03 14:12:42 -08:00
a7a7bd3ca0 build: update rules_typescript (#21290)
picks up a bugfix to prevent floating versions on install:
https://github.com/bazelbuild/rules_typescript/compare/0.6.1...0.6.2

PR Close #21290
2018-01-03 13:43:56 -08:00
67630f82b6 docs(aio): fix trailing space breaking lint 2018-01-02 14:12:47 -08:00
8006be8d8c docs(aio): fix trailing space breaking lint 2018-01-02 14:02:43 -08:00
48a1f32222 fix(language-service): ignore null metadatas (#20557)
There can be null metadatas in certain cases, for example with locales.

Fixes #20260

PR Close #20557
2018-01-02 12:49:27 -08:00
521f0d4c7d docs(aio): HttpClientXsrfModule withConfig => withOptions (#21185)
Docummentation suggests use of HttpClientXsrfModule#withConfig but this method looks like it's renamed to #withConfig.
https://angular.io/guide/http#configuring-custom-cookieheader-names
PR Close #21185
2018-01-02 12:49:13 -08:00
941cd102b8 build: force upstream fetch before merge (#21192)
PR Close #21192
2018-01-02 12:48:55 -08:00
66043e09a2 docs(aio): Sort in the api type dropdown (#21030) (#21176)
Change the order of elements in the api type dropdown to be alphabetical order

PR Close #21030

PR Close #21176
2017-12-27 13:17:10 -08:00
12702b20c7 docs(changelog): fix typo in 5.1.1 (#21007)
PR Close #21007
2017-12-22 21:39:23 -08:00
5de91fe93e docs(forms): add text about min() and max() as functions (#21110)
PR Close #21110
2017-12-22 21:36:48 -08:00
d787b55b31 build(common): generate ts declarations for i18n locale files (#21127)
Fixes #21120
PR Close #21127
2017-12-22 21:35:11 -08:00
3e34fa8651 fix(animations): avoid infinite loop with multiple blocked sub triggers (#21119)
This patch fixes animations so that if multiple sub @triggers are used
and are blocked by a parent animation then the engine will not lead
itself into an infinite loop.

PR Close #21119
2017-12-22 09:23:37 -08:00
8c991756fa fix(router): fix wildcard route with lazy loaded module (again) (#18139)
Closes #13848

Description:
We doesn't handle children of wildcard route properly link. It's always an empty array.

Created from #13851

PR Close #18139
2017-12-22 09:20:21 -08:00
fa0e8ef92c fix(common): handle JS floating point errors in percent pipe (#20329)
Fixes #20136
PR Close #20329
2017-12-22 09:03:19 -08:00
41abcc34f4 docs(service-worker): fix word wrap (#21114)
The fix removes space between 'c' and 'aches' in docs

PR Close #21114
2017-12-21 20:12:27 -08:00
0aa6341e31 build: make umd.min.js source map paths relative (#21147)
I'm not quite sure how to test this since we don't have any infrastructure for these kinds of tests.
I did verify the fix manually though.

Fixes #15740

PR Close #21147
2017-12-21 20:11:27 -08:00
43377684d9 build: fix pullapprove (#21140)
Currently it gives a green status if I edit a file I'm an owner of,
even without anyone else's approval.

PR Close #21140
2017-12-21 14:04:30 -08:00
dc53248b15 build: update pullapprove:
- remove ex-team members
- allow author to approve their own change
- move more bazel files under the bazel group
2017-12-21 13:20:16 -08:00
d1f45002d3 fix(animations): renaming issue with DOMAnimation. (#21125)
Closure Compiler renames all properties that are "internal" to the
program. `DOMAnimation` however is external, it is a browser API, so its
fields must not be renamed.

This change marks `DOMAnimation` as external using `declare interface`,
which will cause Closure Compiler to back off and prevent renaming of
any of its fields.

PR Close #21125
2017-12-21 09:45:25 -08:00
6353b77f89 docs: add changelog for 5.1.2 2017-12-20 12:50:50 -08:00
d9c40b7dd5 release: cut the 5.1.2 release 2017-12-20 12:49:12 -08:00
a36dfd453b ci(router): update the public API guard for the router
This fixes a badly applied revert earlier.
2017-12-20 12:03:51 -08:00
ced575fd10 fix(compiler): report an error for recursive module references
Modules that directly or indirectly export or imported themselves
reports an error instead of generating a stack fault.

Fixes: #19979
2017-12-20 10:54:58 -08:00
3b63e168e2 fix(compiler-cli): do not force type checking on .js files
The compiler host would force any file that is in node_modules
into the list of files that needed to be type checked which
captures .js files if `allowJs` is set to `true`. This should
have only forced .d.ts files into the project to enable
generation of factories.

Fixes: #19757
2017-12-20 10:01:30 -08:00
a1d4c2dbf1 fix(compiler-cli): do not emit invalid .metadata.json files
If no metadata is collected the `ngc` would generate file
that contained `[null]` instead of eliding the `.metadata.json`
file.

Fixes: #20479
2017-12-20 09:59:06 -08:00
a33182c4ee fix(service-worker): check for updates on navigation
Currently the Service Worker checks for updates only on SW startup,
an event which happens frequently but also nondeterministically. This
makes it hard for developers to observe the update process or reason
about how updates will be delivered to users. This problem is
exacerbated by the DevTools behavior of keeping the SW alive
indefinitely while opened, effectively preventing the page from
updating at all.

This change causes the SW to additionally check for updates on
navigation requests (app page reloads). This creates deterministic
update behavior, and is much easier for developers to reason about.
It does leave the old update-on-SW-startup behavior in place, as
removing that would be a breaking change.

Fixes #20877
2017-12-20 08:37:20 -08:00
66cc2fabf1 fix(upgrade): replaces get/setAngularLib with get/setAngularJSGlobal
The current names are confusing because Angular should refer to the latest version of the framework.
2017-12-20 08:37:02 -08:00
cf8269ee94 docs(aio): Rename service worker files, update examples, move service worker under Techniques 2017-12-19 11:08:25 -08:00
c7241ca0e6 docs(aio): fix inconsistency in lifecycle hooks table 2017-12-19 10:58:43 -08:00
4a49e19bd7 ci: add router/testing to public API guard 2017-12-19 10:58:43 -08:00
4a3a74b7b0 fix(aio): improve transitions between pages
- Avoid unnecessary animations, style transitions, repositioning on
  initial rendering.
- Better handle transitioning from/to Home page (which is the only page
  with transparent top-menu).
- Better coordinate sidenav and hamburger animations with page
  transitions.
- Improve fade-in/out animations.

Fixes #20996
2017-12-19 10:58:43 -08:00
6aa013cb63 refactor(aio): clean up top-menu CSS
- Clean-up and re-organize top-menu styles.
- Clean-up and merge hamburger styles into top-menu styles.
2017-12-19 10:58:43 -08:00
b9531f90b8 feat(aio): support disabling DocViewer animations via class 2017-12-19 10:58:43 -08:00
f239e8496e build(aio): make zipper work correctly with CLI projects 2017-12-19 10:58:43 -08:00
57bed3fe73 docs(core): move core examples into examples/core/ directory
This allows examples to be found during aio's `yarn serve-and-sync`, which only
looks for examples in `packages/examples/<packageName>/**/*`, where
`packageName` is the name of the package that the modified file belonged to;
e.g. `core`, `common`, etc.).
2017-12-18 12:11:07 -08:00
c011ffae30 test(aio): correct usage of fakeAsync and inject together in test
Corrects a test which wrapped the fakeAsync call in an inject call.  This caused
the test to not actually run.
2017-12-15 07:55:23 -08:00
756dd34519 fix(compiler): make tsx file aot compatible
fixes #20555
2017-12-15 07:54:02 -08:00
267ebf323e fix(common): fix a Closure compilation issue.
Closure Compiler cannot infer that the swtich statement is exhaustive,
which causes it to complain that the method does not always return a
value.

Work around the problem by throwing an exception in the default case,
and using the `: never` type to ensure the code is unreachable.
2017-12-15 07:52:09 -08:00
49c45f336e ci(aio): move e2e tests to non-optional job
This essentially reverts #20178, since the flakes should be gone after
pinning ChromeDriver and Chrome versions to 2.32 and 59 respectively.
2017-12-14 08:56:22 -08:00
71236737ab ci: downgrade Chromium to a version that does not cause flakes
There seems to be some issue that causes Chrome/ChromeDriver to
unexpectedly reload during the aio e2e tests, causing flakes. It is not
clear what exactly is causing the reloading, but to the best of my
knowledge it is something inside Chrome or ChromeDriver.

Pinning Chrome to r494239 (between 62.0.3185.0 and 62.0.3186.0) fixes
the flakes.

Fixes #20159
2017-12-14 08:56:22 -08:00
390837f76e test(aio): disable DocViewer animations during e2e tests 2017-12-14 08:56:22 -08:00
fbcf7dc889 test(aio): fix and clean up e2e tests 2017-12-14 08:56:22 -08:00
5c8c7d8515 build(common): don't generate .d.ts & .metadata.json files for i18n locales
Fixes #20880
2017-12-14 08:55:50 -08:00
99cc591f63 ci: parallelize bazel build and test
The current setup can cause a de-optimization where unit tests can't start running until the slowest build target completes.
2017-12-14 08:55:42 -08:00
e3140ae888 docs: add changelog for 5.1.1 2017-12-13 11:26:01 -08:00
ca815106c9 release: cut the 5.1.1. release 2017-12-13 11:24:54 -08:00
d6da7988c0 fix(compiler): support referencing enums in namespaces (#20947)
Due to an overly agressive assert the compiler would generate
an internal error when referencing an enum declared in
namspace.

Fixes #18170

PR Close #20947
2017-12-12 11:56:41 -08:00
41e1951ffb ci: clean up circleci/config.yml (#20954)
PR Close #20954
2017-12-12 11:56:37 -08:00
c02f97ce4e ci: allow me to approve circleCI changes (#20957)
Removes the root group from the pullapprove settings for .circleci/*
PR Close #20957
2017-12-12 11:56:31 -08:00
be9a7371b8 fix(compiler-cli): merge @fileoverview comments. (#20870)
Previously, this code would unconditionally add a @fileoverview
comment to generated files, and only if the contained any code at all.

However often existing fileoverview comments should be copied from the
file the generated file was originally based off of. This allows users
to e.g. include Closure Compiler directives in their original
`component.ts` file, which will then automaticallly also apply to code
generated from it.

This special cases `@license` comments, as Closure disregards directives
in comments containing `@license`.

PR Close #20870
2017-12-12 11:38:04 -08:00
1f469497da ci: use container version in cache key (#20952)
PR Close #20952
2017-12-11 16:07:34 -08:00
8a5f0f7a64 build: pin ChromeDriver version (#20940)
Since our version of Chromium is also pinned, a new ChromeDriver (that
drops support for our Chromium version) can cause random (and unrelated
to the corresponding changes) errors on CI.
This commit pins the version of ChromeDriver and it should now be
manually upgraded to a vrsion that is compatible with th currently used
Chromium version.

PR Close #20940
2017-12-11 15:53:22 -08:00
8bcb093bfa build: update node version number in .nvmrc (#20832)
PR Close #20832
2017-12-11 12:59:37 -08:00
abc3a1e844 docs: update DEVELOPER.md with the node and yarn info (#20832)
I intentionally removed version numbers so that we don't need to update them in this file -
because we usually forget.

PR Close #20832
2017-12-11 12:59:37 -08:00
9fbf850897 build: remove bazel option --noshow_results (#20943)
I originally added this when I was trying to build `//packages/core`, which is not what users will do often.
This makes it harder for team members to understand what Bazel is doing. I find myself suggesting to turn it off, so it's better to just remove it.
PR Close #20943
2017-12-11 11:18:18 -08:00
0c9f7b032a fix(bazel): don't equate moduleName with fileName (#20895)
Fixes broken material build.
/cc @jelbourn
PR Close #20895
2017-12-11 11:18:13 -08:00
8b21be5da3 build: require bazel 0.8 (#20897)
Users should get an error if they are running an older version of Bazel than we have on CI.
PR Close #20897
2017-12-11 11:18:07 -08:00
0a9a16183f build: new docker image, faster to boot on circleci 2017-12-11 11:18:00 -08:00
28555bc1e7 ci: print the buildifier command when BUILD lint fails (#20882)
PR Close #20882
2017-12-11 11:17:16 -08:00
d09d4971b3 fix(animations): ensure multi-level route leave animations are queryable (#20787)
Closes #19807

PR Close #20787
2017-12-08 13:44:20 -08:00
f8a4d14c8f ci: remove obsolete chromedriverpatch (#18515)
Dart(ium) is not used anymore in Angular so this file should be obsolete

PR Close #18515
2017-12-08 13:44:17 -08:00
d713225128 refactor(common): update i18n locale data to CLDR v32 (#20830)
List of changes between v31.0.1 and v32: http://cldr.unicode.org/index/downloads/cldr-32
PR Close #20830
2017-12-08 10:25:01 -08:00
5d3af4cad4 docs(common): fix mistakes in number pipe example (#20788)
PR Close #20788
2017-12-08 10:24:46 -08:00
a7fe063aa5 ci: add IgorMinar to bazel pullapprove group (#20843)
PR Close #20843
2017-12-08 10:24:41 -08:00
affa54ddf9 build(aio): upgrade to latest @angular/cli (#18428)
PR Close #18428
2017-12-08 10:11:22 -08:00
02782c10ea build(aio): upgrade to latest @angular/material and @angular/cdk (#18428)
PR Close #18428
2017-12-08 10:11:22 -08:00
8e5a3a42d6 build(aio): upgrade to latest @angular/* (#18428)
PR Close #18428
2017-12-08 10:11:22 -08:00
dbef8ff2b0 build(aio): upgrade to latest rxjs (#18428)
PR Close #18428
2017-12-08 10:11:22 -08:00
c0f08be3fb fix(aio): fix embedded ToC and improve ToC, destroying components and scroll timing (#18428)
- Fix embedded ToC:
  Previously, the element was added too late and was never instantiated.

- Improve ToC update timing:
  Previously, the ToC was updated after the entering animation was over, which
  resulted in the ToC being outdated for the duration of the animation.

- Improve destroying components timing:
  Previously, the old embedded components were destroyed as soon as a
  new document was requested. Even if the transition ended up never
  happening (e.g. due to error while preparing the new document), the
  embedded components would have been destroyed and the displayed
  document would not work as expected.
  Now the old embedded components are destroyed only after the new
  document has been fully prepared.

- Improve scroll-to-top timing:
  Previously, the page was scrolled to top after the entering animation was
  over, which resulted in "jumpi-ness". Now the scrolling happens after the
  leaving document has been removed and before the entering document has been
  inserted.

PR Close #18428
2017-12-08 10:11:22 -08:00
f56cbcc1e5 feat(aio): animate the leaving/entering documents (#18428)
This commit adds a simple fade-in/out animation.

Fixes #15629

PR Close #18428
2017-12-08 10:11:22 -08:00
1b86570b60 fix(aio): do not show new document until embedded components are ready (#18428)
Previously, the document was shown as soon as the HTML was received, but before
the embedded components were ready (e.g. downloaded and instantiated). This
caused FOUC (Flash Of Uninstantiated Components).
This commit fixes it by preparing the new document in an off-DOM node and
swapping the nodes when the embedded components are ready.

PR Close #18428
2017-12-08 10:11:22 -08:00
923227dec2 feat(aio): lazy-load embedded components (#18428)
Fixes #16127

PR Close #18428
2017-12-08 10:11:22 -08:00
53b9de300b docs(aio): fix typo for missing quote (#20888)
PR Close #20888
2017-12-08 10:06:46 -08:00
da587cb9ef fix(aio): tsconfig.app.json excludes all testing files (#20779)
Fixes app build error in testing guide which has testing folder at multiple levels,
with files in them referring to files in the root `testing` folder.
Also removed the exclusion of files with `.1` in the name because
all app `.ts` files must be buildable per aio policy.
must build

PR Close #20779
2017-12-08 10:05:51 -08:00
e6a28054d8 fix(animations): properly recover and cleanup DOM when CD failures occur (#20719)
Closes #19093

PR Close #20719
2017-12-07 17:17:47 -08:00
69ed916b42 refactor(animations): instantiate Set-matching code with values in constructor (#20725)
For some reason, prior to this fix, the boolean set matching
code (within `animation_transition_expr.ts`) failed to remain
the same when compiled with closure. This refactor makes sure
that the code stays in tact.

Reproduction Details:
Passes without `ng build --prod`: https://burger.stackblitz.io/
Fails with `ng build --prod`: http://burger.fxck.cz/

Closes #20374

PR Close #20725
2017-12-07 17:17:43 -08:00
c3e8731145 fix(animations): ensure the web-animations driver properly handles empty keyframes (#20648)
Closes #15858

PR Close #20648
2017-12-07 17:17:32 -08:00
501f01e9ac fix(animations): support webkit-based vendor prefixes for prop validations (#19055)
Closes #18921

PR Close #19055
2017-12-07 17:17:27 -08:00
baeec4dbe2 fix(router): NavigatonError and NavigationCancel should be emitted after resetting the URL (#20803)
PR Close #20803
2017-12-07 13:34:40 -08:00
160a154553 fix(compiler-cli): disable checkTypes in emit. (#20828)
Closure Compiler by default will report diagnostics from type checks in
any JavaScript code, including code emitted by the Angular compiler.
Disabling `checkTypes` substantially reduces warning spam for users, and
allows them to run with stricter compiler flags (e.g. treating actual
diagnostics from user code as errors).

Closure Compiler will still type check the code and use types (where
found and correct) for optimizations.

PR Close #20828
2017-12-07 13:34:32 -08:00
9dd60a5fb0 build: upgrade bazel rules to latest (#20768)
Add enough BUILD files to make it possible to
`bazel build packages/core/test`

Also re-format BUILD.bazel files with Buildifier.
Add a CI lint check that they stay formatted.

PR Close #20768
2017-12-07 13:25:47 -08:00
672733608b fix(compiler-cli): Fix swallowed Error messages (#20846)
This commit fixes a bug in which non-formatted errors are silently
dropped.

Internal issue: b/67739418

PR Close #20846
2017-12-06 17:42:19 -08:00
119 changed files with 1125 additions and 1499 deletions

View File

@ -12,8 +12,8 @@
## IMPORTANT
# If you change the `docker_image` version, also change the `cache_key` suffix and the version of
# `com_github_bazelbuild_buildtools` in the `/WORKSPACE` file.
var_1: &docker_image angular/ngcontainer:0.0.8
var_2: &cache_key angular-{{ .Branch }}-{{ checksum "yarn.lock" }}-0.0.8
var_1: &docker_image angular/ngcontainer:0.1.0
var_2: &cache_key angular-{{ .Branch }}-{{ checksum "yarn.lock" }}-0.1.0
# Settings common to each job
anchor_1: &job_defaults
@ -38,7 +38,10 @@ jobs:
# Then we don't need any exclude pattern to avoid checking those files
- run: 'buildifier -mode=check $(find . -type f \( -name BUILD.bazel -or -name BUILD \)) ||
(echo "BUILD files not formatted. Please run ''yarn buildifier''" ; exit 1)'
# Run the skylark linter to check our Bazel rules
- run: 'find . -type f -name "*.bzl" |
xargs java -jar /usr/local/bin/Skylint_deploy.jar ||
(echo -e "\n.bzl files have lint errors. Please run ''yarn skylint''"; exit 1)'
- restore_cache:
key: *cache_key
@ -52,7 +55,7 @@ jobs:
<<: *post_checkout
- restore_cache:
key: *cache_key
- run: bazel info release
- run: bazel run @yarn//:yarn
# Use bazel query so that we explicitly ask for all buildable targets to be built as well

View File

@ -15,7 +15,6 @@
# hansl - Hans Larsen
# IgorMinar - Igor Minar
# jasonaden - Jason Aden
# juleskremer - Jules Kremer
# kara - Kara Erickson
# matsko - Matias Niemelä
# mhevery - Misko Hevery
@ -25,6 +24,7 @@
# tinayuangao - Tina Gao
# vicb - Victor Berchet
# vikerman - Vikram Subramanian
# wardbell - Ward Bell
version: 2
@ -35,14 +35,32 @@ group_defaults:
enabled: true
approve_by_comment:
enabled: false
# see http://docs.pullapprove.com/groups/author_approval/
author_approval:
# If the author is a reviewer on the PR, they will automatically have an "approved" status.
auto: true
groups:
# Require all PRs to have at least one approval from *someone*
all:
users: all
required: 1
# In this group, your self-approval does not count
author_approval:
auto: false
ignored: true
files:
include:
- "*"
root:
conditions:
files:
include:
- "*"
exclude:
- "WORKSPACE"
- "BUILD.bazel"
- ".circleci/*"
- "aio/*"
- "integration/*"
@ -70,6 +88,7 @@ groups:
- "*.bazel"
- "*.bzl"
- "packages/bazel/*"
- "tools/bazel.rc"
users:
- alexeagle #primary
- chuckjaz
@ -85,6 +104,7 @@ groups:
- "*.lock"
- "tools/*"
exclude:
- "tools/bazel.rc"
- "tools/public_api_guard/*"
- "aio/*"
users:
@ -280,7 +300,7 @@ groups:
files:
- "packages/benchpress/*"
users:
# needs primary
- alxhub # primary
# needs secondary
- IgorMinar #fallback
- mhevery #fallback
@ -308,9 +328,8 @@ groups:
- "aio/content/navigation.json"
- "aio/content/license.md"
users:
- juleskremer #primary
- Foxandxss
- stephenfluin
- Foxandxss
- petebacondarwin
- gkalpak
- IgorMinar #fallback
@ -324,7 +343,6 @@ groups:
- "aio/content/navigation.json"
- "aio/content/license.md"
users:
- juleskremer #primary
- stephenfluin
- petebacondarwin
- gkalpak

View File

@ -1,5 +1,7 @@
language: node_js
sudo: false
# Work-around for https://github.com/travis-ci/travis-ci/issues/8836#issuecomment-356362524.
# (Restore `sudo: false` once that is resolved.)
sudo: required
dist: trusty
node_js:
- '8.9.1'

View File

@ -1,17 +1,14 @@
<a name="5.2.0-beta.1"></a>
# [5.2.0-beta.1](https://github.com/angular/angular/compare/5.2.0-beta.0...5.2.0-beta.1) (2017-12-20)
<a name="5.1.3"></a>
## [5.1.3](https://github.com/angular/angular/compare/5.1.2...5.1.3) (2018-01-03)
### Bug Fixes
* **compiler:** generate the correct imports for summary type-check ([d91ff17](https://github.com/angular/angular/commit/d91ff17))
* **forms:** avoid producing an error with hostBindingTypeCheck ([d213a20](https://github.com/angular/angular/commit/d213a20))
### Features
* **compiler:** allow ngIf to use the ngIf expression directly as a guard ([82bcd83](https://github.com/angular/angular/commit/82bcd83))
* **router:** add "paramsInheritanceStrategy" router configuration option ([5efea2f](https://github.com/angular/angular/commit/5efea2f)), closes [#20572](https://github.com/angular/angular/issues/20572)
* **animations:** avoid infinite loop with multiple blocked sub triggers ([#21119](https://github.com/angular/angular/issues/21119)) ([3e34fa8](https://github.com/angular/angular/commit/3e34fa8))
* **animations:** renaming issue with DOMAnimation. ([#21125](https://github.com/angular/angular/issues/21125)) ([d1f4500](https://github.com/angular/angular/commit/d1f4500))
* **common:** handle JS floating point errors in percent pipe ([#20329](https://github.com/angular/angular/issues/20329)) ([fa0e8ef](https://github.com/angular/angular/commit/fa0e8ef)), closes [#20136](https://github.com/angular/angular/issues/20136)
* **language-service:** ignore null metadatas ([#20557](https://github.com/angular/angular/issues/20557)) ([48a1f32](https://github.com/angular/angular/commit/48a1f32)), closes [#20260](https://github.com/angular/angular/issues/20260)
* **router:** fix wildcard route with lazy loaded module (again) ([#18139](https://github.com/angular/angular/issues/18139)) ([8c99175](https://github.com/angular/angular/commit/8c99175)), closes [#13848](https://github.com/angular/angular/issues/13848)
@ -31,20 +28,6 @@
<a name="5.2.0-beta.0"></a>
# [5.2.0-beta.0](https://github.com/angular/angular/compare/5.1.0...5.2.0-beta.0) (2017-12-13)
### Features
* **animations:** re-introduce support for transition matching functions ([#20723](https://github.com/angular/angular/issues/20723)) ([590d93b](https://github.com/angular/angular/commit/590d93b)), closes [#18959](https://github.com/angular/angular/issues/18959)
* **compiler:** add a pseudo $any() function to disable type checking ([#20876](https://github.com/angular/angular/issues/20876)) ([70cd124](https://github.com/angular/angular/commit/70cd124))
* **compiler:** narrow types of expressions used in *ngIf ([#20702](https://github.com/angular/angular/issues/20702)) ([e7d9cb3](https://github.com/angular/angular/commit/e7d9cb3))
* **core:** add source to `StaticInjectorError` message ([#20817](https://github.com/angular/angular/issues/20817)) ([b7738e1](https://github.com/angular/angular/commit/b7738e1)), closes [#19302](https://github.com/angular/angular/issues/19302)
* **forms:** allow nulls on setAsyncValidators ([#20327](https://github.com/angular/angular/issues/20327)) ([d41d2c4](https://github.com/angular/angular/commit/d41d2c4)), closes [#20296](https://github.com/angular/angular/issues/20296)
<a name="5.1.1"></a>
## [5.1.1](https://github.com/angular/angular/compare/5.1.0...5.1.1) (2017-12-13)
@ -60,7 +43,7 @@
* **compiler-cli:** disable checkTypes in emit. ([#20828](https://github.com/angular/angular/issues/20828)) ([160a154](https://github.com/angular/angular/commit/160a154))
* **compiler-cli:** fix swallowed Error messages ([#20846](https://github.com/angular/angular/issues/20846)) ([6727336](https://github.com/angular/angular/commit/6727336))
* **compiler-cli:** merge [@fileoverview](https://github.com/fileoverview) comments. ([#20870](https://github.com/angular/angular/issues/20870)) ([be9a737](https://github.com/angular/angular/commit/be9a737))
* **router:** NavigatonError and NavigationCancel should be emitted after resetting the URL ([#20803](https://github.com/angular/angular/issues/20803)) ([baeec4d](https://github.com/angular/angular/commit/baeec4d))
* **router:** NavigationError and NavigationCancel should be emitted after resetting the URL ([#20803](https://github.com/angular/angular/issues/20803)) ([baeec4d](https://github.com/angular/angular/commit/baeec4d))

View File

@ -1,6 +1,6 @@
The MIT License
Copyright (c) 2014-2017 Google, Inc. http://angular.io
Copyright (c) 2014-2018 Google, Inc. http://angular.io
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -2,8 +2,6 @@
[![CircleCI](https://circleci.com/gh/angular/angular/tree/master.svg?style=shield)](https://circleci.com/gh/angular/angular/tree/master)
[![BrowserStack Status](https://www.browserstack.com/automate/badge.svg?badge_key=LzF3RzBVVGt6VWE2S0hHaC9uYllOZz09LS1BVjNTclBKV0x4eVRlcjA4QVY1M0N3PT0=--eb4ce8c8dc2c1c5b2b5352d473ee12a73ac20e06)](https://www.browserstack.com/automate/public-build/LzF3RzBVVGt6VWE2S0hHaC9uYllOZz09LS1BVjNTclBKV0x4eVRlcjA4QVY1M0N3PT0=--eb4ce8c8dc2c1c5b2b5352d473ee12a73ac20e06)
[![Join the chat at https://gitter.im/angular/angular](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/angular/angular?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![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://www.npmjs.com/@angular/core)

View File

@ -10,13 +10,13 @@ git_repository(
load("@build_bazel_rules_nodejs//:defs.bzl", "check_bazel_version", "node_repositories")
check_bazel_version("0.8.1")
check_bazel_version("0.9.0")
node_repositories(package_json = ["//:package.json"])
git_repository(
name = "build_bazel_rules_typescript",
remote = "https://github.com/bazelbuild/rules_typescript.git",
tag = "0.6.0",
tag = "0.6.2",
)
load("@build_bazel_rules_typescript//:defs.bzl", "ts_repositories")
@ -53,3 +53,11 @@ load("@io_bazel_rules_go//go:def.bzl", "go_rules_dependencies", "go_register_too
go_rules_dependencies()
go_register_toolchains()
# Fetching the Bazel source code allows us to compile the Skylark linter
http_archive(
name = "io_bazel",
url = "https://github.com/bazelbuild/bazel/archive/9755c72b48866ed034bd28aa033e9abd27431b1e.zip",
strip_prefix = "bazel-9755c72b48866ed034bd28aa033e9abd27431b1e",
sha256 = "5b8443fc3481b5fcd9e7f348e1dd93c1397f78b223623c39eb56494c55f41962",
)

View File

@ -130,7 +130,7 @@ function tests() {
it('can get RouterLinks from template', () => {
expect(links.length).toBe(3, 'should have 3 links');
expect(links[0].linkParams).toBe('/dashboard', '1st link should go to Dashboard');
expect(links[1].linkParams).toBe('/heroes', '1st link should go to Heroes');
expect(links[1].linkParams).toBe('/heroes', '2nd link should go to Heroes');
});
it('can click Heroes link in template', () => {

View File

@ -2,7 +2,7 @@
The Angular Ahead-of-Time (AOT) compiler converts your Angular HTML and TypeScript code into efficient JavaScript code during the build phase _before_ the browser downloads and runs that code.
This guide explains how to build with the AOT compiler and how to write Angular metadata that AOT can compile.
This guide explains how to build with the AOT compiler using different compiler options and how to write Angular metadata that AOT can compile.
<div class="l-sub-section">
@ -77,6 +77,174 @@ AOT compiles HTML templates and components into JavaScript files long before the
With no templates to read and no risky client-side HTML or JavaScript evaluation,
there are fewer opportunities for injection attacks.
{@a compiler-options}
## Angular Compiler Options
You can control your app compilation by providing template compiler options in the `tsconfig.json` file along with the options supplied to the TypeScript compiler. The template compiler options are specified as members of
`"angularCompilerOptions"` object as shown below:
```json
{
"compilerOptions": {
"experimentalDecorators": true,
...
},
"angularCompilerOptions": {
"fullTemplateTypeCheck": true,
"preserveWhiteSpace": false,
...
}
}
```
### *skipMetadataEmit*
This option tells the compiler not to produce `.metadata.json` files.
The option is `false` by default.
`.metadata.json` files contain infomration needed by the template compiler from a `.ts`
file that is not included in the `.d.ts` file produced by the TypeScript compiler. This information contains,
for example, the content of annotations (such as a component's template) which TypeScript
emits to the `.js` file but not to the `.d.ts` file.
This option should be set to `true` if using TypeScript's `--outFile` option, as the metadata files
are not valid for this style of TypeScript output. It is not recommeded to use `--outFile` with
Angular. Use a bundler, such as [webpack](https://webpack.js.org/), instead.
This option can also be set to `true` when using factory summaries as the factory summaries
include a copy of the information that is in the `.metadata.json` file.
### *strictMetadataEmit*
This option tells the template compiler to report an error to the `.metadata.json`
file if `"skipMetadataEmit"` is `false` . This option is `false` by default. This should only be used when `"skipMetadataEmit"` is `false` and `"skipTemplateCodeGen"` is `true`.
It is intended to validate the `.metadata.json` files emitted for bundling with an `npm` package. The validation is overly strict and can emit errors for metadata that would never produce an error when used by the template compiler. You can choose to suppress the error emitted by this option for an exported symbol by including `@dynamic` in the comment documenting the symbol.
It is valid for `.metadata.json` files to contain errors. The template compiler reports these errors
if the metadata is used to determine the contents of an annotation. The metadata
collector cannot predict the symbols that are designed to use in an annotation, so it will preemptively
include error nodes in the metadata for the exported symbols. The template compiler can then use the error
nodes to report an error if these symbols are used. If the client of a library intends to use a symbol in an annotation, the template compiler will not normally report
this until the client uses the symbol. This option allows detecting these errors during the build phase of
the library and is used, for example, in producing Angular libraries themselves.
### *skipTemplateCodegen*
This option tells the compiler to suppress emitting `.ngfactory.js` and `.ngstyle.js` files. When set,
this turns off most of the template compiler and disables reporting template diagnostics.
This option can be used to instruct the
template compiler to produce `.metadata.json` files for distribution with an `npm` package while
avoiding the production of `.ngfactory.js` and `.ngstyle.js` files that cannot be distributed to
`npm`.
### *strictInjectionParameters*
When set to `true`, this options tells the compiler to report an error for a parameter supplied
whose injection type cannot be determined. When this value option is not provided or is `false`, constructor parameters of classes marked with `@Injectable` whose type cannot be resolved will
produce a warning.
*Note*: It is recommended to change this option explicitly to `true` as this option will default to `true` in the future.
### *flatModuleOutFile*
When set to `true`, this option tells the template compiler to generate a flat module
index of the given file name and the corresponding flat module metadata. Use this option when creating
flat modules that are packaged similarly to `@angular/core` and `@angular/common`. When this option
is used, the `package.json` for the library should refer
to the generated flat module index instead of the library index file. With this
option only one `.metadata.json` file is produced that contains all the metadata necessary
for symbols exported from the library index. In the generated `.ngfactory.js` files, the flat
module index is used to import symbols that includes both the public API from the library index
as well as shrowded internal symbols.
By default the `.ts` file supplied in the `files` field is assumed to be library index.
If more than one `.ts` file is specified, `libraryIndex` is used to select the file to use.
If more than one `.ts` file is supplied without a `libraryIndex`, an error is produced. A flat module
index `.d.ts` and `.js` will be created with the given `flatModuleOutFile` name in the same
location as the library index `.d.ts` file. For example, if a library uses
`public_api.ts` file as the library index of the module, the `tsconfig.json` `files` field
would be `["public_api.ts"]`. The `flatModuleOutFile` options could then be set to, for
example `"index.js"`, which produces `index.d.ts` and `index.metadata.json` files. The
library's `package.json`'s `module` field would be `"index.js"` and the `typings` field
would be `"index.d.ts"`.
### *flatModuleId*
This option specifies the preferred module id to use for importing a flat module.
References generated by the template compiler will use this module name when importing symbols
from the flat module.
This is only meaningful when `flatModuleOutFile` is also supplied. Otherwise the compiler ignores
this option.
### *generateCodeForLibraries*
This option tells the template compiler to generate factory files (`.ngfactory.js` and `.ngstyle.js`)
for `.d.ts` files with a corresponding `.metadata.json` file. This option defaults to
`true`. When this option is `false`, factory files are generated only for `.ts` files.
This option should be set to `false` when using factory summaries.
### *fullTemplateTypeCheck*
This option tells the compiler to enable the [binding expression validation](#binding-expresion-validation)
phase of the template compiler which uses TypeScript to validate binding expressions.
This option is `false` by default.
*Note*: It is recommended to set this to `true` as this option will default to `true` in the future.
### *annotateForClosureCompiler*
This option tells the compiler to use [Tsickle](https://github.com/angular/tsickle) to annotate the emitted
JavaScript with [JsDoc](http://usejsdoc.org/) comments needed by the
[Closure Compiler](https://github.com/google/closure-compiler). This option defaults to `false`.
### *annotationsAs*
Use this option to modify how the Angular specific annotations are emitted to improve tree-shaking. Non-Angular
annotations and decorators are unnaffected. Default is `static fields`.
value | description
----------------|-------------------------------------------------------------
`decorators` | Leave the Decorators in-place. This makes compilation faster. TypeScript will emit calls to the __decorate helper. Use `--emitDecoratorMetadata` for runtime reflection. However, the resulting code will not properly tree-shake.
`static fields` | Replace decorators with a static field in the class. Allows advanced tree-shakers like [Closure Compiler](https://github.com/google/closure-compiler) to remove unused classes.
### *trace*
This tells the compiler to print extra information while compiling templates.
### *enableLegacyTemplate*
The use of `<template>` element was deprecated starting in Angular 4.0 in favor of using
`<ng-template>` to avoid colliding with the DOM's element of the same name. Setting this option to
`true` enables the use of the deprecated `<template>` element . This option
is `false` by default. This option might be required by some third-party Angular libraries.
### *disableExpressionLowering*
The Angular template compiler transforms code that is used, or could be used, in an annotation
to allow it to be imported from template factory modules. See
[metadata rewriting](#metadata-rewriting) for more information.
Setting this option to `false` disables this rewriting, requiring the rewriting to be
done manually.
### *preserveWhitespaces*
This option tells the compiler whether to remove blank text nodes from compiled templates.
This option is `true` by default.
*Note*: It is recommended to set this explicitly to `false` as it emits smaller template factory modules and might be set to `false` by default in the future.
### *allowEmptyCodegenFiles*
Tells the compiler to generate all the possible generated files even if they are empty. This option is
`false` by default. This is an option used by `bazel` build rules and is needed to simplify
how `bazel` rules track file dependencies. It is not recommended to use this option outside of the `bazel`
rules.
## Angular Metadata and AOT
The Angular **AOT compiler** extracts and interprets **metadata** about the parts of the application that Angular is supposed to manage.
@ -212,6 +380,7 @@ export function serverFactory() {
Beginning in version 5, the compiler automatically performs this rewritting while emitting the `.js` file.
{@a function-calls}
### Limited function calls
The _collector_ can represent a function call or object creation with `new` as long as the syntax is valid. The _collector_ only cares about proper syntax.
@ -411,6 +580,7 @@ The Angular [`RouterModule`](api/router/RouterModule) exports two macro static m
Review the [source code](https://github.com/angular/angular/blob/master/packages/router/src/router_module.ts#L139 "RouterModule.forRoot source code")
for these methods to see how macros can simplify configuration of complex [NgModules](guide/ngmodule).
{@ metadata-rewriting}
### Metadata rewriting
The compiler treats object literals containing the fields `useClass`, `useValue`, `useFactory`, and `data` specially. The compiler converts the expression initializing one of these fields into an exported variable, which replaces the expression. This process of rewriting these expressions removes all the restrictions on what can be in them because
@ -961,7 +1131,155 @@ This error can occur if you use an expression in the `extends` clause of a class
Chuck: After reviewing your PR comment I'm still at a loss. See [comment there](https://github.com/angular/angular/pull/17712#discussion_r132025495).
-->
{@a binding-expresion-validation}
## Phase 3: binding expression validation
In the validation phase, the Angular template compiler uses the TypeScript compiler to validate the
binding expressions in templates. Enable this phase explicity by adding the compiler
option `"fullTemplateTypeCheck"` in the `"angularCompilerOptions"` of the project's `tsconfig.json` (see
[Angular Compiler Options](#compiler-options)).
Template validation produces error messages when a type error is detected in a template binding
expression, similar to how type errors are reported by the TypeScript compiler against code in a `.ts`
file.
For example, consider the following component:
```ts
@Component({
selector: 'my-component',
template: '{{person.addresss.street}}'
})
class MyComponent {
person?: Person;
}
```
This will produce the following error:
```
my.component.ts.MyComponent.html(1,1): : Property 'addresss' does not exist on type 'Person'. Did you mean 'address'?
```
The file name reported in the error message, `my.component.ts.MyComponent.html`, is a synthetic file
generated by the template compiler that holds contents of the `MyComponent` class template.
Compiler never writes this file to disk. The line and column numbers are relative to the template string
in the `@Component` annotation of the class, `MyComponent` in this case. If a component uses
`templateUrl` instead of `template`, the errors are reported in the HTML file refereneced by the
`templateUrl` instead of a synthetic file.
The error location is the beginning of the text node that contains the interpolation expression with
the error. If the error is in an attribute binding such as `[value]="person.address.street"`, the error
location is the location of the attribute that contains the error.
The validation uses the TypeScript type checker and the options supplied to the TypeScript compiler to control
how detailed the type validation is. For example, if the `strictTypeChecks` is specified, the error ```my.component.ts.MyComponent.html(1,1): : Object is possibly 'undefined'``` is reported as well as the above error message.
### Type narrowing
The expression used in an `ngIf` directive is used to narrow type unions in the Angular
template compiler, the same way the `if` expression does in TypeScript. For example, to avoid
`Object is possibly 'undefined'` error in the template above, modify it to only emit the
interpolation if the value of `person` is initialized as shown below:
```ts
@Component({
selector: 'my-component',
template: '<span *ngIf="person"> {{person.addresss.street}} </span>'
})
class MyComponent {
person?: Person;
}
```
Using `*ngIf` allows the TypeScript compiler to infer that the `person` used in the
binding expression will never be `undefined`.
#### Custom `ngIf` like directives
Directives that behave like `*ngIf` can declare that they want the same treatment by including
a static member marker that is a signal to the template compiler to treat them
like `*ngIf`. This static member for `*ngIf` is:
```ts
public static ngIfUseIfTypeGuard: void;
```
This declares that the input property `ngIf` of the `NgIf` directive should be treated as a
guard to the use of its template, implying that the template will only be instantiated if
the `ngIf` input property is true.
### Non-null type assertion operator
Use the [non-null type assertion operator](guide/template-syntax#non-null-assertion-operator)
to suppress the `Object is possibly 'undefined'` error when it is incovienent to use
`*ngIf` or when some constraint in the component ensures that the expression is always
non-null when the binding expression is interpolated.
In the following example, the `person` and `address` properties are always set together,
implying that `address` is always non-null if `person` is non-null. There is no convenient
way to describe this constraint to TypeScript and the template compiler, but the error
is suppressed in the example by using `address!.street`.
```ts
@Component({
selector: 'my-component',
template: '<span *ngIf="person"> {{person.name}} lives on {{address!.street}} </span>'
})
class MyComponent {
person?: Person;
address?: Address;
setData(person: Person, address: Address) {
this.person = person;
this.address = address;
}
}
```
The non-null assertion operator should be used sparingly as refactoring of the component
might break this constraint.
In this example it is recommended to include the checking of `address`
in the `*ngIf`as shown below:
```ts
@Component({
selector: 'my-component',
template: '<span *ngIf="person && address"> {{person.name}} lives on {{address.street}} </span>'
})
class MyComponent {
person?: Person;
address?: Address;
setData(person: Person, address: Address) {
this.person = person;
this.address = address;
}
}
```
### Disabling type checking using `$any()`
Disable checking of a binding expression by surrounding the expression
in a call to the [`$any()` cast pseudo-function](guide/template-syntax).
The compiler treats it as a cast to the `any` type just like in TypeScript when a `<any>`
or `as any` cast is used.
In the following example, the error `Property addresss does not exist` is suppressed
by casting `person` to the `any` type.
```ts
@Component({
selector: 'my-component',
template: '{{$any(person).addresss.street}}'
})
class MyComponent {
person?: Person;
}
```
## Summary
* What the AOT compiler does and why it is important.
@ -970,3 +1288,5 @@ Chuck: After reviewing your PR comment I'm still at a loss. See [comment there](
* Other restrictions on metadata definition.
* Macro-functions and macro-static methods.
* Compiler errors related to metadata.
* Validation of binding expressions

View File

@ -371,7 +371,7 @@ and to
Angular developers may encounter a
<a href="https://en.wikipedia.org/wiki/Cross-origin_resource_sharing" title="Cross-origin resource sharing">
<i>cross-origin resource sharing</i></a> error when making a service request (typically a data service request).
<i>cross-origin resource sharing</i></a> error when making a service request (typically a data service request)
to a server other than the application's own host server.
Browsers forbid such requests unless the server permits them explicitly.

View File

@ -273,6 +273,8 @@ has a single `intercept()` method. Here is a simple interceptor which does nothi
import {Injectable} from '@angular/core';
import {HttpEvent, HttpInterceptor, HttpHandler, HttpRequest} from '@angular/common/http';
import {Observable} from 'rxjs/Observable';
@Injectable()
export class NoopInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
@ -297,6 +299,8 @@ Simply declaring the `NoopInterceptor` above doesn't cause your app to use it. Y
import {NgModule} from '@angular/core';
import {HTTP_INTERCEPTORS} from '@angular/common/http';
import {NoopInterceptor} from 'noop.interceptor.ts';
@NgModule({
providers: [{
provide: HTTP_INTERCEPTORS,
@ -547,12 +551,12 @@ In order to prevent collisions in environments where multiple Angular apps share
### Configuring custom cookie/header names
If your backend service uses different names for the XSRF token cookie or header, use `HttpClientXsrfModule.withConfig()` to override the defaults.
If your backend service uses different names for the XSRF token cookie or header, use `HttpClientXsrfModule.withOptions()` to override the defaults.
```javascript
imports: [
HttpClientModule,
HttpClientXsrfModule.withConfig({
HttpClientXsrfModule.withOptions({
cookieName: 'My-Xsrf-Cookie',
headerName: 'My-Xsrf-Header',
}),

View File

@ -200,8 +200,8 @@ versions are safe to use, so existing tabs continue to run from
cache, but new loads of the app will be served from the network.
* `SAFE_MODE`: the service worker cannot guarantee the safety of
using cached data. Either an unexpected error occurred or all c
ached versions are invalid. All traffic will be served from the
using cached data. Either an unexpected error occurred or all
cached versions are invalid. All traffic will be served from the
network, running as little service worker code as possible.
In both cases, the parenthetical annotation provides the

View File

@ -2,7 +2,7 @@
@description
The MIT License
Copyright (c) 2014-2017 Google, Inc.
Copyright (c) 2014-2018 Google, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -121,7 +121,7 @@ Import the `HeroService` instead.
<code-example path="toh-pt4/src/app/heroes/heroes.component.ts" title="src/app/heroes/heroes.component.ts (import HeroService)" region="hero-service-import">
</code-example>
Replace the the definition of the `heroes` property with a simple declaration.
Replace the definition of the `heroes` property with a simple declaration.
<code-example path="toh-pt4/src/app/heroes/heroes.component.ts" region="heroes">
</code-example>

View File

@ -58,6 +58,7 @@ describe('site App', function() {
expect(page.getScrollTop()).toBeGreaterThan(0);
page.getNavItem(/api/i).click();
browser.waitForAngular();
expect(page.locationPath()).toBe('/api');
expect(page.getScrollTop()).toBe(0);
});
@ -69,6 +70,7 @@ describe('site App', function() {
expect(page.getScrollTop()).toBeGreaterThan(0);
page.getNavItem(/security/i).click();
browser.waitForAngular();
expect(page.locationPath()).toBe('/guide/security');
expect(page.getScrollTop()).toBe(0);
});

View File

@ -84,7 +84,7 @@
"rxjs": "^5.5.2",
"tslib": "^1.7.1",
"web-animations-js": "^2.2.5",
"zone.js": "0.8.16"
"zone.js": "^0.8.19"
},
"devDependencies": {
"@angular/cli": "^1.6.0-rc.0",

View File

@ -4,18 +4,18 @@
"gzip7": {
"inline": 941,
"main": 116124,
"polyfills": 11860
"polyfills": 13102
},
"gzip9": {
"inline": 941,
"main": 115954,
"polyfills": 11858
"polyfills": 13104
},
"uncompressed": {
"inline": 1558,
"main": 456432,
"polyfills": 37070
"polyfills": 40684
}
}
}
}
}

View File

@ -723,14 +723,14 @@ describe('AppComponent', () => {
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
});
it('should redirect to `docs` if deployment mode is `next` and not at a docs page', () => {
it('should not redirect if deployment mode is `next`', () => {
createTestingModule('', 'next');
initializeTest();
expect(TestBed.get(LocationService).replace).toHaveBeenCalledWith('docs');
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
createTestingModule('resources', 'next');
initializeTest();
expect(TestBed.get(LocationService).replace).toHaveBeenCalledWith('docs');
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
createTestingModule('guide/aot-compiler', 'next');
initializeTest();
@ -757,7 +757,7 @@ describe('AppComponent', () => {
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
});
it('should not redirect to `docs` if deployment mode is `stable` and not at a docs page', () => {
it('should not redirect to `docs` if deployment mode is `stable`', () => {
createTestingModule('', 'stable');
initializeTest();
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();

View File

@ -121,9 +121,9 @@ export class AppComponent implements OnInit {
this.documentService.currentDocument.first().subscribe(doc => this.updateHostClassesForDoc(doc));
this.locationService.currentPath.subscribe(path => {
// Redirect to docs if we are in not in stable mode and are not hitting a docs page
// Redirect to docs if we are in archive mode and are not hitting a docs page
// (i.e. we have arrived at a marketing page)
if (this.deployment.mode !== 'stable' && !/^(docs$|api|guide|tutorial)/.test(path)) {
if (this.deployment.mode === 'archive' && !/^(docs$|api|guide|tutorial)/.test(path)) {
this.locationService.replace('docs');
}
if (path === this.currentPath) {

View File

@ -43,15 +43,15 @@ export class ApiListComponent implements OnInit {
// API types
types: Option[] = [
{ value: 'all', title: 'All' },
{ value: 'directive', title: 'Directive' },
{ value: 'pipe', title: 'Pipe'},
{ value: 'decorator', title: 'Decorator' },
{ value: 'class', title: 'Class' },
{ value: 'interface', title: 'Interface' },
{ value: 'function', title: 'Function' },
{ value: 'const', title: 'Const' },
{ value: 'decorator', title: 'Decorator' },
{ value: 'directive', title: 'Directive' },
{ value: 'enum', title: 'Enum' },
{ value: 'type-alias', title: 'Type Alias' },
{ value: 'const', title: 'Const'}
{ value: 'function', title: 'Function' },
{ value: 'interface', title: 'Interface' },
{ value: 'pipe', title: 'Pipe' },
{ value: 'type-alias', title: 'Type Alias' }
];
statuses: Option[] = [

View File

@ -536,7 +536,7 @@ describe('DocViewerComponent', () => {
expect(swapViewsSpy).not.toHaveBeenCalled();
expect(docViewer.nextViewContainer.innerHTML).toBe('');
expect(logger.output.error).toEqual([
['[DocViewer]: Error preparing document \'foo\'.', error],
[`[DocViewer] Error preparing document 'foo': ${error.stack}`],
]);
});
@ -555,7 +555,7 @@ describe('DocViewerComponent', () => {
expect(swapViewsSpy).not.toHaveBeenCalled();
expect(docViewer.nextViewContainer.innerHTML).toBe('');
expect(logger.output.error).toEqual([
['[DocViewer]: Error preparing document \'bar\'.', error],
[`[DocViewer] Error preparing document 'bar': ${error.stack}`],
]);
});
@ -574,7 +574,7 @@ describe('DocViewerComponent', () => {
expect(swapViewsSpy).not.toHaveBeenCalled();
expect(docViewer.nextViewContainer.innerHTML).toBe('');
expect(logger.output.error).toEqual([
['[DocViewer]: Error preparing document \'baz\'.', error],
[`[DocViewer] Error preparing document 'baz': ${error.stack}`],
]);
});
@ -593,7 +593,23 @@ describe('DocViewerComponent', () => {
expect(swapViewsSpy).toHaveBeenCalledTimes(1);
expect(docViewer.nextViewContainer.innerHTML).toBe('');
expect(logger.output.error).toEqual([
['[DocViewer]: Error preparing document \'qux\'.', error],
[`[DocViewer] Error preparing document 'qux': ${error.stack}`],
]);
});
it('when something fails with non-Error', async () => {
const error = 'Typical string error';
swapViewsSpy.and.callFake(() => {
expect(docViewer.nextViewContainer.innerHTML).not.toBe('');
throw error;
});
await doRender('Some content', 'qux');
expect(swapViewsSpy).toHaveBeenCalledTimes(1);
expect(docViewer.nextViewContainer.innerHTML).toBe('');
expect(logger.output.error).toEqual([
[`[DocViewer] Error preparing document 'qux': ${error}`],
]);
});
});

View File

@ -153,8 +153,9 @@ export class DocViewerComponent implements DoCheck, OnDestroy {
.switchMap(() => this.swapViews(addTitleAndToc))
.do(() => this.docRendered.emit())
.catch(err => {
const errorMessage = (err instanceof Error) ? err.stack : err;
this.logger.error(`[DocViewer] Error preparing document '${doc.id}': ${errorMessage}`);
this.nextViewContainer.innerHTML = '';
this.logger.error(`[DocViewer]: Error preparing document '${doc.id}'.`, err);
return this.void$;
});
}

View File

@ -12,7 +12,7 @@
</div>
<p>
Powered by Google ©2010-2017.
Powered by Google ©2010-2018.
Code licensed under an <a href="license" title="License text" >MIT-style License</a>.
Documentation licensed under
<a href="http://creativecommons.org/licenses/by/4.0/">CC BY 4.0</a>.

View File

@ -11,8 +11,9 @@ interface StringMap { [index: string]: string; }
export function getAttrs(el: HTMLElement | ElementRef): StringMap {
const attrs: NamedNodeMap = el instanceof ElementRef ? el.nativeElement.attributes : el.attributes;
const attrMap = {};
Object.keys(attrs).forEach(key =>
attrMap[(attrs[key] as Attr).name.toLowerCase()] = (attrs[key] as Attr).value);
for (const attr of attrs as any /* cast due to https://github.com/Microsoft/TypeScript/issues/2695 */) {
attrMap[attr.name.toLowerCase()] = attr.value;
}
return attrMap;
}

View File

@ -9,7 +9,11 @@ exports.config = {
'./e2e/**/*.e2e-spec.ts'
],
capabilities: {
'browserName': 'chrome'
'browserName': 'chrome',
// For Travis CI only
chromeOptions: {
binary: process.env.CHROME_BIN
}
},
directConnect: true,
baseUrl: 'http://localhost:4200/',

View File

@ -45,7 +45,7 @@ class PlunkerBuilder {
}
_buildCopyrightStrings() {
var copyright = 'Copyright 2017 Google Inc. All Rights Reserved.\n'
var copyright = 'Copyright 2017-2018 Google Inc. All Rights Reserved.\n'
+ 'Use of this source code is governed by an MIT-style license that\n'
+ 'can be found in the LICENSE file at http://angular.io/license';
var pad = '\n\n';
@ -152,6 +152,7 @@ class PlunkerBuilder {
// Matches main.ts or main.1.ts
if (/^main(?:[.-]\w+)?\.ts$/.test(relativeFileName)) {
content = fileTranslator.translate(content, mainTsRules);
relativeFileName = 'main.ts';
}
if (relativeFileName == 'systemjs.config.extras.js') {

View File

@ -1,5 +1,16 @@
/**
* Use this tag to ensure that dgeni does not include this code item
* in the rendered docs.
*
* The `@internal` tag indicates to the compiler not to include the
* item in the public typings file.
* Use the `@nodoc` alias if you only want to hide the item from the
* docs but not from the typings file.
*/
module.exports = function() {
return {
name: 'internal', transforms: function() { return true; }
name: 'internal',
aliases: ['nodoc'],
transforms: function() { return true; }
};
};

View File

@ -9424,10 +9424,10 @@ zip-stream@~0.6.0:
lodash "~3.10.1"
readable-stream "~1.0.26"
zone.js@0.8.16:
version "0.8.16"
resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.8.16.tgz#ac31b6c418f88c0f918ad6acd8a402aca9313abb"
zone.js@^0.8.14:
version "0.8.18"
resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.8.18.tgz#8cecb3977fcd1b3090562ff4570e2847e752b48d"
zone.js@^0.8.19:
version "0.8.19"
resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.8.19.tgz#a4b522cd9e8b7b616a638c297d720d4c7f292f71"

View File

@ -206,7 +206,7 @@ minify() {
base_file=$( basename "${file}" )
if [[ "${base_file}" =~ $regex && "${base_file##*.}" != "map" ]]; then
local out_file=$(dirname "${file}")/${BASH_REMATCH[1]}.min.js
$UGLIFYJS -c --screw-ie8 --comments -o ${out_file} --source-map ${out_file}.map --source-map-include-sources ${file}
$UGLIFYJS -c --screw-ie8 --comments -o ${out_file} --source-map ${out_file}.map --prefix relative --source-map-include-sources ${file}
fi
done
}

View File

@ -7,30 +7,11 @@ Caretaker is responsible for merging PRs into the individual branches and intern
- Draining the queue of PRs ready to be merged. (PRs with [`PR action: merge`](https://github.com/angular/angular/pulls?q=is%3Aopen+is%3Apr+label%3A%22PR+action%3A+merge%22) label)
- Assigining [new issues](https://github.com/angular/angular/issues?q=is%3Aopen+is%3Aissue+no%3Alabel) to individual component authors.
## Setup
### Set `upstream` to fetch PRs into your local repo
Use this conmmands to configure your `git` to fetch PRs into your local repo.
```
git remote add upstream git@github.com:angular/angular.git
git config --add remote.upstream.fetch +refs/pull/*/head:refs/remotes/upstream/pr/*
```
## Merging the PR
A PR needs to have `PR action: merge` and `PR target: *` labels to be considered
ready to merge. Merging is performed by running `merge-pr` with a PR number to merge.
NOTE: before running `merge-pr` ensure that you have synced all of the PRs
locally by running:
```
$ git fetch upstream
```
To merge a PR run:
```
@ -40,6 +21,7 @@ $ ./scripts/github/merge-pr 1234
The `merge-pr` script will:
- Ensure that all approriate labels are on the PR.
- That the current branch (`master` or `?.?.x` patch) mathches the `PR target: *` label.
- Fetches the latest PR code from the `angular/angular` repo.
- It will `cherry-pick` all of the SHAs from the PR into the current branch.
- It will rewrite commit history by automatically adding `Close #1234` and `(#1234)` into the commit message.
@ -53,8 +35,8 @@ $ ./scripts/github/merge-pr 1234
======================
GitHub Merge PR Steps
======================
git cherry-pick upstream/pr/1234~1..upstream/pr/1234
git filter-branch -f --msg-filter "/usr/local/google/home/misko/angular-pr/scripts/github/utils/github.closes 1234" HEAD~1..HEAD
git cherry-pick angular/pr/1234~1..angular/pr/1234
git filter-branch -f --msg-filter "/home/misko/angular/scripts/github/utils/github.closes 1234" HEAD~1..HEAD
```
If the `cherry-pick` command fails than resolve conflicts and use `git cherry-pick --continue` once ready. After the `cherry-pick` is done cut&paste and run the `filter-branch` command to properly rewrite the messages

View File

@ -17,7 +17,7 @@ In such case, we'll update this document accordingly.
The dates are just a guidance and might be adjusted slightly if necessary.
## Tentative Schedule Until December 2017
## Tentative Schedule Until September 2017
<!--
The table below is formatted so that it's easy to read and edit in both markdown and rendered html form.
@ -25,54 +25,43 @@ The table below is formatted so that it's easy to read and edit in both markdown
In order to deal with undesirable line breaks, two special characters are occasionally used:
- non-breaking hyphen: "" http://www.fileformat.info/info/unicode/char/2011/index.htm
- non-breaking space: " " http://www.fileformat.info/info/unicode/char/00a0/index.htm
- non-breaking space: " " http://www.fileformat.info/info/unicode/char/00a0/index.htm
If you see undesirable wrapping issues in the rendered form, please copy&paste the quoted characters and use them in the table below where needed.
-->
Week Of | Stable Release<br>(@latest npm tag) | Beta/RC Release<br>(@next npm tag) | Note
Week Of | Stable Release<br>(@latest npm tag) | Beta/RC Release<br>(@next npm tag) | Note
------------- | ----------------------------------- | ---------------------------------- | ---------------------
20170501 | 4.1.1 | 4.2.0beta.0 |
20170508 | 4.1.2 | 4.2.0beta.1 |
20170515 | 4.1.3 | 4.2.0rc.0 |
20170526 | | 4.2.0rc.1 |
20170601 | | 4.2.0rc.2 |
20170605 | 4.2.0 | | Minor Version Release
*20170609* | 4.2.1 | | *Regression Patch Release*
20170501   | 4.1.1                               | 4.2.0beta.0                       |
20170508   | 4.1.2                               | 4.2.0beta.1                       |
20170515   | 4.1.3                               | 4.2.0rc.0                         |
20170526   |                                    | 4.2.0rc.1                         |
20170601    |                                    | 4.2.0rc.2                         |
20170605   | 4.2.0                               |                                   | Minor Version Release
*20170609*  | 4.2.1                               |                        | *Regression Patch Release*
2017-06-12 | 4.2.2 | |
*2017-06-16* | 4.2.3 | | *Regression Patch Release*
20170619 | 4.2.4 | 4.3.0beta.0 |
20170626 | 4.2.5 | 4.3.0beta.1 |
20170703 | 4.2.6 | 4.3.0rc.0 |
20170710 | 4.3.0 | - | Minor Version Release
20170717 | 4.3.1 | 5.0.0beta.0 |
20170724 | 4.3.2 | 5.0.0beta.1 |
20170731 | 4.3.3 | 5.0.0beta.2 |
20170807 | 4.3.4 | 5.0.0beta.3 |
20170814 | 4.3.5 | 5.0.0beta.4 |
20170821 | 4.3.6 | - |
20170828 | - | 5.0.0beta.5 |
20170904 | - | 5.0.0beta.6 |
20170911 | 4.4.0 | 5.0.0-beta.7 |
20170918 | 4.4.1 | 5.0.0beta.8 |
20170925 | 4.4.2 | 5.0.0rc.0 |
20171002 | 4.4.3 | 5.0.0rc.1 |
20171009 | 4.4.4 | 5.0.0rc.2 |
20171016 | 4.4.5 | 5.0.0rc.3 |
201711-01 | 5.0.0 | | Major Version Release
2017-11-08 | 5.0.1 | 5.1.0.Beta.0 | *Regression Patch Release*
2017-11-16 | 5.0.2 | 5.1.0.Beta.1 | *Regression Patch Release*
2017-11-22 | 5.0.3 | 5.1.0.beta.2 | *Regression Patch Release*
2017-11-30 | 5.0.4 | 5.1.0.rc.0 |
2017-12-01 | 5.0.5 | 5.1.0.rc.1 |
2017-12-06 | 5.1.0 | | Minor Version Release
2017-12-13 | 5.1.1 | 5.2.0.beta.0 |
2017-12-20 | 5.1.2 | |
*2017-06-16*  | 4.2.3 | | *Regression Patch Release*
20170619   | 4.2.4                               | 4.3.0beta.0                       |
20170626   | 4.2.5                               | 4.3.0beta.1                       |
20170703   | 4.2.6                               | 4.3.0rc.0                         |
20170710   | 4.3.0                               | -                        | Minor Version Release
20170717   | 4.3.1                               | 5.0.0beta.0                       |
20170724   | 4.3.2                               | 5.0.0beta.1                       |
20170731   | 4.3.3                               | 5.0.0beta.2                       |
20170807   | 4.3.4                               | 5.0.0beta.3                       |
20170814    | 4.3.5                               | 5.0.0beta.4                       |
20170821   | 4.3.6                               | - |
20170828   | -                               | 5.0.0beta.5                       |
20170904   | -                                | 5.0.0beta.6                       |
20170911   | 4.4.0                               | 5.0.0-beta.7                       |
20170918   | 4.4.1                               | 5.0.0beta.8                       |
20170925   | 4.4.2                               | 5.0.0rc.0                         |
20171002   | 4.4.3                               | 5.0.0rc.1                         |
20171009   | 4.4.4                               | 5.0.0rc.2                         |
20171016  | 4.4.5                               | 5.0.0rc.3                         |
20171023  | 5.0.0                               |                                   | Major Version Release
## Tentative Schedule After December 2017
## Tentative Schedule After September 2017
Date | Stable Release | Compatibility`*`
---------------------- | -------------- | ----------------

View File

@ -1,4 +1,34 @@
{
"cli-hello-world":{"master":{"gzip7":{"inline":847,"main":42533,"polyfills":20207},"gzip9":{"inline":847,"main":42483,"polyfills":20204},"uncompressed":{"inline":1447,"main":154295,"polyfills":61254}}},
"hello_world__closure":{"master":{"gzip7":{"bundle":32793},"gzip9":{"bundle":32758},"uncompressed":{"bundle":100661}}}
"cli-hello-world": {
"master": {
"gzip7": {
"inline": 847,
"main": 41943,
"polyfills": 20207
},
"gzip9": {
"inline": 847,
"main": 41874,
"polyfills": 20204
},
"uncompressed": {
"inline": 1447,
"main": 151849,
"polyfills": 61254
}
}
},
"hello_world__closure": {
"master": {
"gzip7": {
"bundle": 32793
},
"gzip9": {
"bundle": 32758
},
"uncompressed": {
"bundle": 100661
}
}
}
}

View File

@ -14,7 +14,7 @@ node_repositories(package_json = ["//:package.json"])
git_repository(
name = "build_bazel_rules_typescript",
remote = "https://github.com/bazelbuild/rules_typescript.git",
tag = "0.6.0",
tag = "0.6.2",
)
load("@build_bazel_rules_typescript//:defs.bzl", "ts_repositories")

View File

@ -1,6 +1,6 @@
{
"name": "angular-srcs",
"version": "5.2.0-beta.1",
"version": "5.1.3",
"private": true,
"branchPattern": "2.0.*",
"description": "Angular - a web framework for modern web apps",
@ -16,7 +16,10 @@
"url": "https://github.com/angular/angular.git"
},
"scripts": {
"buildifier": "bazel build @com_github_bazelbuild_buildtools//buildifier && find . -type f \\( -name BUILD -or -name BUILD.bazel \\) ! -path \"*/node_modules/*\" | xargs $(bazel info bazel-bin)/external/com_github_bazelbuild_buildtools/buildifier/buildifier",
"preskylint": "bazel build --noshow_progress @io_bazel//src/tools/skylark/java/com/google/devtools/skylark/skylint:Skylint",
"skylint": "find . -type f -name \"*.bzl\" ! -path \"*/node_modules/*\" ! -path \"./dist/*\" | xargs $(bazel info bazel-bin)/external/io_bazel/src/tools/skylark/java/com/google/devtools/skylark/skylint/Skylint",
"prebuildifier": "bazel build --noshow_progress @com_github_bazelbuild_buildtools//buildifier",
"buildifier": "find . -type f \\( -name BUILD -or -name BUILD.bazel \\) ! -path \"*/node_modules/*\" | xargs $(bazel info bazel-bin)/external/com_github_bazelbuild_buildtools/buildifier/buildifier",
"preinstall": "node -e \"if(process.env.npm_execpath.indexOf('yarn') === -1) throw new Error('Please use Yarn instead of NPM to install dependencies. See: https://yarnpkg.com/lang/en/docs/install/')\"",
"postinstall": "yarn update-webdriver",
"update-webdriver": "webdriver-manager update --gecko false $CHROMEDRIVER_VERSION_ARG",

View File

@ -1393,10 +1393,10 @@ export class TransitionAnimationPlayer implements AnimationPlayer {
public markedForDestroy: boolean = false;
readonly queued: boolean = true;
constructor(public namespaceId: string, public triggerName: string, public element: any) {}
get queued() { return this._containsRealPlayer == false; }
setRealPlayer(player: AnimationPlayer) {
if (this._containsRealPlayer) return;
@ -1407,7 +1407,6 @@ export class TransitionAnimationPlayer implements AnimationPlayer {
});
this._queuedCallbacks = {};
this._containsRealPlayer = true;
(this as{queued: boolean}).queued = false;
}
getRealPlayer() { return this._player; }

View File

@ -6,7 +6,15 @@
* found in the LICENSE file at https://angular.io/license
*/
export interface DOMAnimation {
/**
* DOMAnimation represents the Animation Web API.
*
* It is an external API by the browser, and must thus use "declare interface",
* to prevent renaming by Closure Compiler.
*
* @see https://developer.mozilla.org/de/docs/Web/API/Animation
*/
export declare interface DOMAnimation {
cancel(): void;
play(): void;
pause(): void;

View File

@ -115,7 +115,7 @@ export interface AnimationStateMetadata extends AnimationMetadata {
* @experimental Animation support is experimental.
*/
export interface AnimationTransitionMetadata extends AnimationMetadata {
expr: string|((fromState: string, toState: string) => boolean);
expr: string;
animation: AnimationMetadata|AnimationMetadata[];
options: AnimationOptions|null;
}
@ -836,8 +836,7 @@ export function keyframes(steps: AnimationStyleMetadata[]): AnimationKeyframesSe
* @experimental Animation support is experimental.
*/
export function transition(
stateChangeExpr: string | ((fromState: string, toState: string) => boolean),
steps: AnimationMetadata | AnimationMetadata[],
stateChangeExpr: string, steps: AnimationMetadata | AnimationMetadata[],
options: AnimationOptions | null = null): AnimationTransitionMetadata {
return {type: AnimationMetadataType.Transition, expr: stateChangeExpr, animation: steps, options};
}

View File

@ -33,17 +33,17 @@ export class AnimationGroupPlayer implements AnimationPlayer {
} else {
this.players.forEach(player => {
player.onDone(() => {
if (++doneCount >= total) {
if (++doneCount == total) {
this._onFinish();
}
});
player.onDestroy(() => {
if (++destroyCount >= total) {
if (++destroyCount == total) {
this._onDestroy();
}
});
player.onStart(() => {
if (++startCount >= total) {
if (++startCount == total) {
this._onStart();
}
});
@ -67,9 +67,9 @@ export class AnimationGroupPlayer implements AnimationPlayer {
private _onStart() {
if (!this.hasStarted()) {
this._started = true;
this._onStartFns.forEach(fn => fn());
this._onStartFns = [];
this._started = true;
}
}

View File

@ -3,7 +3,10 @@
# Use of this source code is governed by an MIT-style license that can be
# found in the LICENSE file at https://angular.io/license
""" Public API surface is re-exported here.
Users should not load files under "/src"
"""
load("//src:ng_module.bzl", "ng_module")
load("//src:ng_module.bzl", _ng_module = "ng_module")
ng_module = _ng_module

View File

@ -2,6 +2,8 @@
#
# 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
"""Implementation of the ng_module rule.
"""
load(":rules_typescript.bzl",
"tsc_wrapped_tsconfig",
@ -10,20 +12,17 @@ load(":rules_typescript.bzl",
"compile_ts",
"DEPS_ASPECTS",
"ts_providers_dict_to_struct",
"json_marshal",
)
# Calculate the expected output of the template compiler for every source in
# in the library. Most of these will be produced as empty files but it is
# unknown, without parsing, which will be empty.
def _expected_outs(ctx, label):
def _expected_outs(ctx):
devmode_js_files = []
closure_js_files = []
declaration_files = []
summary_files = []
codegen_inputs = ctx.files.srcs
for src in ctx.files.srcs + ctx.files.assets:
if src.short_path.endswith(".ts") and not src.short_path.endswith(".d.ts"):
basename = src.short_path[len(ctx.label.package) + 1:-len(".ts")]
@ -42,6 +41,9 @@ def _expected_outs(ctx, label):
]
summaries = []
else:
continue
closure_js = [f.replace(".js", ".closure.js") for f in devmode_js]
declarations = [f.replace(".js", ".d.ts") for f in devmode_js]
@ -61,7 +63,7 @@ def _expected_outs(ctx, label):
)
def _ngc_tsconfig(ctx, files, srcs, **kwargs):
outs = _expected_outs(ctx, ctx.label)
outs = _expected_outs(ctx)
if "devmode_manifest" in kwargs:
expected_outs = outs.devmode_js + outs.declarations + outs.summaries
else:
@ -79,7 +81,7 @@ def _ngc_tsconfig(ctx, files, srcs, **kwargs):
})
def _collect_summaries_aspect_impl(target, ctx):
results = target.angular.summaries if hasattr(target, "angular") else depset()
results = depset(target.angular.summaries if hasattr(target, "angular") else [])
# If we are visiting empty-srcs ts_library, this is a re-export
srcs = ctx.rule.attr.srcs if hasattr(ctx.rule.attr, "srcs") else []
@ -88,7 +90,7 @@ def _collect_summaries_aspect_impl(target, ctx):
if not srcs:
for dep in ctx.rule.attr.deps:
if (hasattr(dep, "angular")):
results += dep.angular.summaries
results = depset(dep.angular.summaries, transitive = [results])
return struct(collect_summaries_aspect_result = results)
@ -104,10 +106,29 @@ _EXTRA_NODE_OPTIONS_FLAGS = [
]
def ngc_compile_action(ctx, label, inputs, outputs, messages_out, config_file_path,
locale=None, i18n_args=[]):
locale=None, i18n_args=[]):
"""Helper function to create the ngc action.
This is exposed for google3 to wire up i18n replay rules, and is not intended
as part of the public API.
Args:
ctx: skylark context
label: the label of the ng_module being compiled
inputs: passed to the ngc action's inputs
outputs: passed to the ngc action's outputs
messages_out: produced xmb files
config_file_path: path to the tsconfig file
locale: i18n locale, or None
i18n_args: additional command-line arguments to ngc
Returns:
the parameters of the compilation which will be used to replay the ngc action for i18N.
"""
mnemonic = "AngularTemplateCompile"
progress_message = "Compiling Angular templates (ngc) %s" % label
supports_workers = "0"
if locale:
mnemonic = "AngularI18NMerging"
supports_workers = "0"
@ -152,8 +173,6 @@ def ngc_compile_action(ctx, label, inputs, outputs, messages_out, config_file_pa
progress_message = "Extracting Angular 2 messages (ng_xi18n)",
mnemonic = "Angular2MessageExtractor")
# Return the parameters of the compilation which will be used to replay the
# ngc action for i18N.
if not locale and not ctx.attr.no_i18n:
return struct(
label = label,
@ -162,46 +181,68 @@ def ngc_compile_action(ctx, label, inputs, outputs, messages_out, config_file_pa
outputs = outputs,
)
return None
def _compile_action(ctx, inputs, outputs, messages_out, config_file_path):
summaries = depset()
for dep in ctx.attr.deps:
if hasattr(dep, "collect_summaries_aspect_result"):
summaries += dep.collect_summaries_aspect_result
action_inputs = inputs + summaries.to_list() + ctx.files.assets
# print("ASSETS", [a.path for a in ctx.files.assets])
# print("INPUTS", ctx.label, [o.path for o in summaries if o.path.find("core/src") > 0])
# Give the Angular compiler all the user-listed assets
file_inputs = list(ctx.files.assets)
# The compiler only needs to see TypeScript sources from the npm dependencies,
# but may need to look at package.json and ngsummary.json files as well.
if hasattr(ctx.attr, "node_modules"):
action_inputs += [f for f in ctx.files.node_modules
if f.path.endswith(".ts") or f.path.endswith(".json")]
file_inputs += [f for f in ctx.files.node_modules
if f.path.endswith(".ts") or f.path.endswith(".json")]
# If the user supplies a tsconfig.json file, the Angular compiler needs to read it
if hasattr(ctx.attr, "tsconfig") and ctx.file.tsconfig:
action_inputs += [ctx.file.tsconfig]
file_inputs.append(ctx.file.tsconfig)
# Collect the inputs and summary files from our deps
action_inputs = depset(file_inputs,
transitive = [inputs] + [dep.collect_summaries_aspect_result for dep in ctx.attr.deps
if hasattr(dep, "collect_summaries_aspect_result")])
return ngc_compile_action(ctx, ctx.label, action_inputs, outputs, messages_out, config_file_path)
def _prodmode_compile_action(ctx, inputs, outputs, config_file_path):
outs = _expected_outs(ctx, ctx.label)
outs = _expected_outs(ctx)
return _compile_action(ctx, inputs, outputs + outs.closure_js, outs.i18n_messages, config_file_path)
def _devmode_compile_action(ctx, inputs, outputs, config_file_path):
outs = _expected_outs(ctx, ctx.label)
outs = _expected_outs(ctx)
_compile_action(ctx, inputs, outputs + outs.devmode_js + outs.declarations + outs.summaries, None, config_file_path)
def _ts_expected_outs(ctx, label):
# rules_typescript expects a function with two arguments, but our
# implementation doesn't use the label
_ignored = [label]
return _expected_outs(ctx)
def ng_module_impl(ctx, ts_compile_actions):
"""Implementation function for the ng_module rule.
This is exposed so that google3 can have its own entry point that re-uses this
and is not meant as a public API.
Args:
ctx: the skylark rule context
ts_compile_actions: generates all the actions to run an ngc compilation
Returns:
the result of the ng_module rule as a dict, suitable for
conversion by ts_providers_dict_to_struct
"""
providers = ts_compile_actions(
ctx, is_library=True, compile_action=_prodmode_compile_action,
devmode_compile_action=_devmode_compile_action,
tsc_wrapped_tsconfig=_ngc_tsconfig,
outputs = _expected_outs)
outputs = _ts_expected_outs)
#addl_declarations = [_expected_outs(ctx)]
#providers["typescript"]["declarations"] += addl_declarations
#providers["typescript"]["transitive_declarations"] += addl_declarations
outs = _expected_outs(ctx, ctx.label)
outs = _expected_outs(ctx)
providers["angular"] = {
"summaries": _expected_outs(ctx, ctx.label).summaries
"summaries": _expected_outs(ctx).summaries
}
providers["ngc_messages"] = outs.i18n_messages
@ -240,7 +281,7 @@ NG_MODULE_ATTRIBUTES = {
ng_module = rule(
implementation = _ng_module_impl,
attrs = COMMON_ATTRIBUTES + NG_MODULE_ATTRIBUTES + {
attrs = dict(dict(COMMON_ATTRIBUTES, **NG_MODULE_ATTRIBUTES), **{
"tsconfig": attr.label(allow_files = True, single_file = True),
# @// is special syntax for the "main" repository
@ -249,6 +290,6 @@ ng_module = rule(
"node_modules": attr.label(
default = Label("@//:node_modules")
),
},
}),
outputs = COMMON_OUTPUTS,
)

View File

@ -27,6 +27,8 @@ const ALLOW_NON_HERMETIC_READS = true;
// Note: We compile the content of node_modules with plain ngc command line.
const ALL_DEPS_COMPILED_WITH_BAZEL = false;
const NODE_MODULES = 'node_modules/';
export function main(args) {
if (runAsWorker(args)) {
runWorkerLoop(runOneBuild);
@ -175,7 +177,11 @@ export function compile({allowNonHermeticReads, allDepsCompiledWithBazel = true,
ngHost.amdModuleName) {
return ngHost.amdModuleName({ fileName: importedFilePath } as ts.SourceFile);
}
return relativeToRootDirs(importedFilePath, compilerOpts.rootDirs).replace(EXT, '');
const result = relativeToRootDirs(importedFilePath, compilerOpts.rootDirs).replace(EXT, '');
if (result.startsWith(NODE_MODULES)) {
return result.substr(NODE_MODULES.length);
}
return bazelOpts.workspaceName + '/' + result;
};
ngHost.toSummaryFileName = (fileName: string, referringSrcFileName: string) =>
relativeToRootDirs(fileName, compilerOpts.rootDirs).replace(EXT, '');

View File

@ -1,12 +1,26 @@
# Allows different paths for these imports in google3
load("@build_bazel_rules_typescript//internal:build_defs.bzl", "tsc_wrapped_tsconfig")
"""Allows different paths for these imports in google3.
"""
load("@build_bazel_rules_typescript//internal:common/compilation.bzl",
"COMMON_ATTRIBUTES",
"COMMON_OUTPUTS",
"compile_ts",
"DEPS_ASPECTS",
"ts_providers_dict_to_struct",
load("@build_bazel_rules_typescript//internal:build_defs.bzl",
_tsc_wrapped_tsconfig = "tsc_wrapped_tsconfig",
)
load("@build_bazel_rules_typescript//internal:common/json_marshal.bzl", "json_marshal")
load("@build_bazel_rules_typescript//internal:common/compilation.bzl",
_COMMON_ATTRIBUTES = "COMMON_ATTRIBUTES",
_COMMON_OUTPUTS = "COMMON_OUTPUTS",
_compile_ts = "compile_ts",
_DEPS_ASPECTS = "DEPS_ASPECTS",
_ts_providers_dict_to_struct = "ts_providers_dict_to_struct",
)
load("@build_bazel_rules_typescript//internal:common/json_marshal.bzl",
_json_marshal = "json_marshal",
)
tsc_wrapped_tsconfig = _tsc_wrapped_tsconfig
COMMON_ATTRIBUTES = _COMMON_ATTRIBUTES
COMMON_OUTPUTS = _COMMON_OUTPUTS
compile_ts = _compile_ts
DEPS_ASPECTS = _DEPS_ASPECTS
ts_providers_dict_to_struct = _ts_providers_dict_to_struct
json_marshal = _json_marshal

View File

@ -249,6 +249,9 @@ export class PerflogMetric extends Metric {
// not all events have been received, no further processing for now
return null;
}
if (markStartEvent.pid !== markEndEvent.pid) {
result['invalid'] = 1;
}
let gcTimeInScript = 0;
let renderTimeInScript = 0;

View File

@ -63,7 +63,12 @@ export class Sampler {
}
return resultPromise.then((_) => this._driver.waitFor(this._execute))
.then((_) => this._metric.endMeasure(this._prepare === Options.NO_PREPARE))
.then((measureValues) => this._report(lastState, measureValues));
.then((measureValues) => {
if (!!measureValues['invalid']) {
return lastState;
}
return this._report(lastState, measureValues);
});
}
private _report(state: SampleState, metricValues: {[key: string]: any}): Promise<SampleState> {

View File

@ -34,7 +34,9 @@ export class SeleniumWebDriverAdapter extends WebDriverAdapter {
capabilities(): Promise<{[key: string]: any}> {
return this._driver.getCapabilities().then((capsObject: any) => {
const localData: {[key: string]: any} = {};
capsObject.forEach((value: any, key: string) => { localData[key] = value; });
for (const key of capsObject.keys()) {
localData[key] = capsObject.get(key);
}
return localData;
});
}

View File

@ -537,6 +537,24 @@ export function main() {
});
}));
it('should mark a run as invalid if the start and end marks are different',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
const otherProcessEventFactory = new TraceEventFactory('timeline', 'pid1');
const metric = createMetric(
[[
eventFactory.markStart('benchpress0', 0), eventFactory.start('script', 0, null),
eventFactory.end('script', 5, null),
otherProcessEventFactory.start('script', 10, null),
otherProcessEventFactory.end('script', 17, null),
otherProcessEventFactory.markEnd('benchpress0', 20)
]],
null !);
metric.beginMeasure().then((_) => metric.endMeasure(false)).then((data) => {
expect(data['invalid']).toBe(1);
async.done();
});
}));
it('should support scriptTime metric',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
aggregate([

View File

@ -23,12 +23,13 @@ export class MockScriptElement {
export class MockDocument {
mock: MockScriptElement|null;
readonly body: any = this;
createElement(tag: 'script'): HTMLScriptElement {
return new MockScriptElement() as any as HTMLScriptElement;
}
get body(): any { return this; }
appendChild(node: any): void { this.mock = node; }
removeNode(node: any): void {
@ -40,4 +41,4 @@ export class MockDocument {
mockLoad(): void { this.mock !.listeners.load !(null as any); }
mockError(err: Error) { this.mock !.listeners.error !(err); }
}
}

View File

@ -1,7 +1,7 @@
{
"compilerOptions": {
"baseUrl": ".",
"declaration": false,
"declaration": true,
"stripInternal": true,
"experimentalDecorators": true,
"module": "es2015",

View File

@ -14,8 +14,7 @@
export * from './location/index';
export {NgLocaleLocalization, NgLocalization} from './i18n/localization';
export {registerLocaleData} from './i18n/locale_data';
export {Plural, NumberFormatStyle, FormStyle, Time, TranslationWidth, FormatWidth, NumberSymbol, WeekDay, getLocaleDayPeriods, getLocaleDayNames, getLocaleMonthNames, getLocaleId, getLocaleEraNames, getLocaleWeekEndRange, getLocaleFirstDayOfWeek, getLocaleDateFormat, getLocaleDateTimeFormat, getLocaleExtraDayPeriodRules, getLocaleExtraDayPeriods, getLocalePluralCase, getLocaleTimeFormat, getLocaleNumberSymbol, getLocaleNumberFormat, getLocaleCurrencyName, getLocaleCurrencySymbol} from './i18n/locale_data_api';
export {CURRENCIES} from './i18n/currencies';
export {Plural, NumberFormatStyle, FormStyle, Time, TranslationWidth, FormatWidth, NumberSymbol, WeekDay, getCurrencySymbol, getLocaleDayPeriods, getLocaleDayNames, getLocaleMonthNames, getLocaleId, getLocaleEraNames, getLocaleWeekEndRange, getLocaleFirstDayOfWeek, getLocaleDateFormat, getLocaleDateTimeFormat, getLocaleExtraDayPeriodRules, getLocaleExtraDayPeriods, getLocalePluralCase, getLocaleTimeFormat, getLocaleNumberSymbol, getLocaleNumberFormat, getLocaleCurrencyName, getLocaleCurrencySymbol} from './i18n/locale_data_api';
export {parseCookieValue as ɵparseCookieValue} from './cookie';
export {CommonModule, DeprecatedI18NPipesModule} from './common_module';
export {NgClass, NgForOf, NgForOfContext, NgIf, NgIfContext, NgPlural, NgPluralCase, NgStyle, NgSwitch, NgSwitchCase, NgSwitchDefault, NgTemplateOutlet, NgComponentOutlet} from './directives/index';

View File

@ -151,9 +151,6 @@ export class NgIf {
}
}
}
/** @internal */
public static ngIfUseIfTypeGuard: void;
}
/**

View File

@ -9,7 +9,7 @@
// THIS CODE IS GENERATED - DO NOT MODIFY
// See angular/tools/gulp-tasks/cldr/extract.js
/** @experimental */
/** @internal */
export const CURRENCIES: {[code: string]: (string | undefined)[]} = {
'AOA': [, 'Kz'],
'ARS': [, '$'],

View File

@ -46,11 +46,6 @@ export function formatNumber(
num = value;
}
if (style === NumberFormatStyle.Percent) {
num = num * 100;
}
const numStr = Math.abs(num) + '';
const pattern = parseNumberFormat(format, getLocaleNumberSymbol(locale, NumberSymbol.MinusSign));
let formattedText = '';
let isZero = false;
@ -58,7 +53,11 @@ export function formatNumber(
if (!isFinite(num)) {
formattedText = getLocaleNumberSymbol(locale, NumberSymbol.Infinity);
} else {
const parsedNumber = parseNumber(numStr);
let parsedNumber = parseNumber(num);
if (style === NumberFormatStyle.Percent) {
parsedNumber = toPercent(parsedNumber);
}
let minInt = pattern.minInt;
let minFraction = pattern.minFrac;
@ -249,11 +248,35 @@ interface ParsedNumber {
integerLen: number;
}
// Transforms a parsed number into a percentage by multiplying it by 100
function toPercent(parsedNumber: ParsedNumber): ParsedNumber {
// if the number is 0, don't do anything
if (parsedNumber.digits[0] === 0) {
return parsedNumber;
}
// Getting the current number of decimals
const fractionLen = parsedNumber.digits.length - parsedNumber.integerLen;
if (parsedNumber.exponent) {
parsedNumber.exponent += 2;
} else {
if (fractionLen === 0) {
parsedNumber.digits.push(0, 0);
} else if (fractionLen === 1) {
parsedNumber.digits.push(0);
}
parsedNumber.integerLen += 2;
}
return parsedNumber;
}
/**
* Parse a number (as a string)
* Parses a number.
* Significant bits of this parse algorithm came from https://github.com/MikeMcl/big.js/
*/
function parseNumber(numStr: string): ParsedNumber {
function parseNumber(num: number): ParsedNumber {
let numStr = Math.abs(num) + '';
let exponent = 0, digits, integerLen;
let i, j, zeros;
@ -356,12 +379,23 @@ function roundNumber(parsedNumber: ParsedNumber, minFrac: number, maxFrac: numbe
// Pad out with zeros to get the required fraction length
for (; fractionLen < Math.max(0, fractionSize); fractionLen++) digits.push(0);
let dropTrailingZeros = fractionSize !== 0;
// Minimal length = nb of decimals required + current nb of integers
// Any number besides that is optional and can be removed if it's a trailing 0
const minLen = minFrac + parsedNumber.integerLen;
// Do any carrying, e.g. a digit was rounded up to 10
const carry = digits.reduceRight(function(carry, d, i, digits) {
d = d + carry;
digits[i] = d % 10;
return Math.floor(d / 10);
digits[i] = d < 10 ? d : d - 10; // d % 10
if (dropTrailingZeros) {
// Do not keep meaningless fractional trailing zeros (e.g. 15.52000 --> 15.52)
if (digits[i] === 0 && i >= minLen) {
digits.pop();
} else {
dropTrailingZeros = false;
}
}
return d >= 10 ? 1 : 0; // Math.floor(d / 10);
}, 0);
if (carry) {
digits.unshift(carry);

View File

@ -527,12 +527,17 @@ export function findLocaleData(locale: string): any {
/**
* Return the currency symbol for a given currency code, or the code if no symbol available
* (e.g.: $, US$, or USD)
* (e.g.: format narrow = $, format wide = US$, code = USD)
*
* @internal
* @experimental i18n support is experimental.
*/
export function findCurrencySymbol(code: string, format: 'wide' | 'narrow') {
const currency = CURRENCIES[code] || {};
const symbol = currency[0] || code;
return format === 'wide' ? symbol : currency[1] || symbol;
}
export function getCurrencySymbol(code: string, format: 'wide' | 'narrow'): string {
const currency = CURRENCIES[code] || [];
const symbolNarrow = currency[1];
if (format === 'narrow' && typeof symbolNarrow === 'string') {
return symbolNarrow;
}
return currency[0] || code;
}

View File

@ -8,7 +8,7 @@
import {Inject, LOCALE_ID, Pipe, PipeTransform} from '@angular/core';
import {formatNumber} from '../i18n/format_number';
import {NumberFormatStyle, findCurrencySymbol, getLocaleCurrencyName, getLocaleCurrencySymbol} from '../i18n/locale_data_api';
import {NumberFormatStyle, getCurrencySymbol, getLocaleCurrencyName, getLocaleCurrencySymbol} from '../i18n/locale_data_api';
import {invalidPipeArgumentError} from './invalid_pipe_argument_error';
/**
@ -143,7 +143,7 @@ export class CurrencyPipe implements PipeTransform {
let currency = currencyCode || 'USD';
if (display !== 'code') {
currency = findCurrencySymbol(currency, display === 'symbol' ? 'wide' : 'narrow');
currency = getCurrencySymbol(currency, display === 'symbol' ? 'wide' : 'narrow');
}
const {str, error} = formatNumber(value, locale, NumberFormatStyle.Currency, digits, currency);

View File

@ -11,7 +11,7 @@ import localeEn from '../../locales/en';
import localeFr from '../../locales/fr';
import localeFrCA from '../../locales/fr-CA';
import {registerLocaleData} from '../../src/i18n/locale_data';
import {findLocaleData} from '../../src/i18n/locale_data_api';
import {findLocaleData, getCurrencySymbol} from '../../src/i18n/locale_data_api';
export function main() {
describe('locale data api', () => {
@ -51,5 +51,18 @@ export function main() {
expect(findLocaleData('fake-id2')).toEqual(localeFrCA);
});
});
describe('getCurrencySymbolElseCode', () => {
it('should return the correct symbol', () => {
expect(getCurrencySymbol('USD', 'wide')).toEqual('$');
expect(getCurrencySymbol('USD', 'narrow')).toEqual('$');
expect(getCurrencySymbol('AUD', 'wide')).toEqual('A$');
expect(getCurrencySymbol('AUD', 'narrow')).toEqual('$');
expect(getCurrencySymbol('CRC', 'wide')).toEqual('CRC');
expect(getCurrencySymbol('CRC', 'narrow')).toEqual('₡');
expect(getCurrencySymbol('FAKE', 'wide')).toEqual('FAKE');
expect(getCurrencySymbol('FAKE', 'narrow')).toEqual('FAKE');
});
});
});
}

View File

@ -79,6 +79,22 @@ export function main() {
expect(pipe.transform(1.2, '.2')).toEqual('120.00%');
expect(pipe.transform(1.2, '4.2')).toEqual('0,120.00%');
expect(pipe.transform(1.2, '4.2', 'fr')).toEqual('0 120,00 %');
// see issue #20136
expect(pipe.transform(0.12345674, '0.0-10')).toEqual('12.345674%');
expect(pipe.transform(0, '0.0-10')).toEqual('0%');
expect(pipe.transform(0.00, '0.0-10')).toEqual('0%');
expect(pipe.transform(1, '0.0-10')).toEqual('100%');
expect(pipe.transform(0.1, '0.0-10')).toEqual('10%');
expect(pipe.transform(0.12, '0.0-10')).toEqual('12%');
expect(pipe.transform(0.123, '0.0-10')).toEqual('12.3%');
expect(pipe.transform(12.3456, '0.0-10')).toEqual('1,234.56%');
expect(pipe.transform(12.345600, '0.0-10')).toEqual('1,234.56%');
expect(pipe.transform(12.345699999, '0.0-6')).toEqual('1,234.57%');
expect(pipe.transform(12.345699999, '0.4-6')).toEqual('1,234.5700%');
expect(pipe.transform(100, '0.4-6')).toEqual('10,000.0000%');
expect(pipe.transform(100, '0.0-10')).toEqual('10,000%');
expect(pipe.transform(1.5e2)).toEqual('15,000%');
expect(pipe.transform(1e100)).toEqual('1E+102%');
});
it('should not support other objects', () => {
@ -106,6 +122,7 @@ export function main() {
expect(pipe.transform(5.1234, 'CAD', 'symbol-narrow', '5.2-2')).toEqual('$00,005.12');
expect(pipe.transform(5.1234, 'CAD', 'symbol-narrow', '5.2-2', 'fr'))
.toEqual('00 005,12 $');
expect(pipe.transform(5.1234, 'FAKE', 'symbol')).toEqual('FAKE5.12');
});
it('should not support other objects', () => {

View File

@ -57,7 +57,7 @@ export interface CompilerOptions extends ts.CompilerOptions {
// Produce an error if the metadata written for a class would produce an error if used.
strictMetadataEmit?: boolean;
// Don't produce .ngfactory.ts or .ngstyle.ts files
// Don't produce .ngfactory.js or .ngstyle.js files
skipTemplateCodegen?: boolean;
// Always report errors when the type of a parameter supplied whose injection type cannot

View File

@ -48,11 +48,11 @@ describe('ng type checker', () => {
}
function reject(
message: string | RegExp, location: RegExp | null, files: MockFiles,
message: string | RegExp, location: RegExp, files: MockFiles,
overrideOptions: ng.CompilerOptions = {}) {
const diagnostics = compileAndCheck([QUICKSTART, files], overrideOptions);
if (!diagnostics || !diagnostics.length) {
throw new Error('Expected a diagnostic error message');
throw new Error('Expected a diagnostic erorr message');
} else {
const matches: (d: ng.Diagnostic) => boolean = typeof message === 'string' ?
d => ng.isNgDiagnostic(d)&& d.messageText == message :
@ -63,13 +63,11 @@ describe('ng type checker', () => {
`Expected a diagnostics matching ${message}, received\n ${diagnostics.map(d => d.messageText).join('\n ')}`);
}
if (location) {
const span = matchingDiagnostics[0].span;
if (!span) {
throw new Error('Expected a sourceSpan');
}
expect(`${span.start.file.url}@${span.start.line}:${span.start.offset}`).toMatch(location);
const span = matchingDiagnostics[0].span;
if (!span) {
throw new Error('Expected a sourceSpan');
}
expect(`${span.start.file.url}@${span.start.line}:${span.start.offset}`).toMatch(location);
}
}
@ -83,543 +81,6 @@ describe('ng type checker', () => {
});
});
describe('type narrowing', () => {
const a = (files: MockFiles, options: object = {}) => {
accept(files, {fullTemplateTypeCheck: true, ...options});
};
it('should narrow an *ngIf like directive', () => {
a({
'src/app.component.ts': '',
'src/lib.ts': '',
'src/app.module.ts': `
import {NgModule, Component, Directive, HostListener, TemplateRef, Input} from '@angular/core';
export interface Person {
name: string;
}
@Component({
selector: 'comp',
template: '<div *myIf="person"> {{person.name}} </div>'
})
export class MainComp {
person?: Person;
}
export class MyIfContext {
public $implicit: any = null;
public myIf: any = null;
}
@Directive({selector: '[myIf]'})
export class MyIf {
constructor(templateRef: TemplateRef<MyIfContext>) {}
@Input()
set myIf(condition: any) {}
static myIfTypeGuard: <T>(v: T | null | undefined | false) => v is T;
}
@NgModule({
declarations: [MainComp, MyIf],
})
export class MainModule {}`
});
});
it('should narrow a renamed *ngIf like directive', () => {
a({
'src/app.component.ts': '',
'src/lib.ts': '',
'src/app.module.ts': `
import {NgModule, Component, Directive, HostListener, TemplateRef, Input} from '@angular/core';
export interface Person {
name: string;
}
@Component({
selector: 'comp',
template: '<div *my-if="person"> {{person.name}} </div>'
})
export class MainComp {
person?: Person;
}
export class MyIfContext {
public $implicit: any = null;
public myIf: any = null;
}
@Directive({selector: '[my-if]'})
export class MyIf {
constructor(templateRef: TemplateRef<MyIfContext>) {}
@Input('my-if')
set myIf(condition: any) {}
static myIfTypeGuard: <T>(v: T | null | undefined | false) => v is T;
}
@NgModule({
declarations: [MainComp, MyIf],
})
export class MainModule {}`
});
});
it('should narrow a type in a nested *ngIf like directive', () => {
a({
'src/app.component.ts': '',
'src/lib.ts': '',
'src/app.module.ts': `
import {NgModule, Component, Directive, HostListener, TemplateRef, Input} from '@angular/core';
export interface Address {
street: string;
}
export interface Person {
name: string;
address?: Address;
}
@Component({
selector: 'comp',
template: '<div *myIf="person"> {{person.name}} <span *myIf="person.address">{{person.address.street}}</span></div>'
})
export class MainComp {
person?: Person;
}
export class MyIfContext {
public $implicit: any = null;
public myIf: any = null;
}
@Directive({selector: '[myIf]'})
export class MyIf {
constructor(templateRef: TemplateRef<MyIfContext>) {}
@Input()
set myIf(condition: any) {}
static myIfTypeGuard: <T>(v: T | null | undefined | false) => v is T;
}
@NgModule({
declarations: [MainComp, MyIf],
})
export class MainModule {}`
});
});
it('should narrow an *ngIf like directive with UseIf', () => {
a({
'src/app.component.ts': '',
'src/lib.ts': '',
'src/app.module.ts': `
import {NgModule, Component, Directive, HostListener, TemplateRef, Input} from '@angular/core';
export interface Person {
name: string;
}
@Component({
selector: 'comp',
template: '<div *myIf="person"> {{person.name}} </div>'
})
export class MainComp {
person?: Person;
}
export class MyIfContext {
public $implicit: any = null;
public myIf: any = null;
}
@Directive({selector: '[myIf]'})
export class MyIf {
constructor(templateRef: TemplateRef<MyIfContext>) {}
@Input()
set myIf(condition: any) {}
static myIfUseIfTypeGuard: void;
}
@NgModule({
declarations: [MainComp, MyIf],
})
export class MainModule {}`
});
});
it('should narrow a renamed *ngIf like directive with UseIf', () => {
a({
'src/app.component.ts': '',
'src/lib.ts': '',
'src/app.module.ts': `
import {NgModule, Component, Directive, HostListener, TemplateRef, Input} from '@angular/core';
export interface Person {
name: string;
}
@Component({
selector: 'comp',
template: '<div *my-if="person"> {{person.name}} </div>'
})
export class MainComp {
person?: Person;
}
export class MyIfContext {
public $implicit: any = null;
public myIf: any = null;
}
@Directive({selector: '[my-if]'})
export class MyIf {
constructor(templateRef: TemplateRef<MyIfContext>) {}
@Input('my-if')
set myIf(condition: any) {}
static myIfUseIfTypeGuard: void;
}
@NgModule({
declarations: [MainComp, MyIf],
})
export class MainModule {}`
});
});
it('should narrow a type in a nested *ngIf like directive with UseIf', () => {
a({
'src/app.component.ts': '',
'src/lib.ts': '',
'src/app.module.ts': `
import {NgModule, Component, Directive, HostListener, TemplateRef, Input} from '@angular/core';
export interface Address {
street: string;
}
export interface Person {
name: string;
address?: Address;
}
@Component({
selector: 'comp',
template: '<div *myIf="person"> {{person.name}} <span *myIf="person.address">{{person.address.street}}</span></div>'
})
export class MainComp {
person?: Person;
}
export class MyIfContext {
public $implicit: any = null;
public myIf: any = null;
}
@Directive({selector: '[myIf]'})
export class MyIf {
constructor(templateRef: TemplateRef<MyIfContext>) {}
@Input()
set myIf(condition: any) {}
static myIfUseIfTypeGuard: void;
}
@NgModule({
declarations: [MainComp, MyIf],
})
export class MainModule {}`
});
});
it('should narrow an *ngIf like directive with UseIf and &&', () => {
a({
'src/app.component.ts': '',
'src/lib.ts': '',
'src/app.module.ts': `
import {NgModule, Component, Directive, HostListener, TemplateRef, Input} from '@angular/core';
export interface Address {
street: string;
}
export interface Person {
name: string;
}
@Component({
selector: 'comp',
template: '<div *myIf="person && address"> {{person.name}} lives at {{address.street}} </div>'
})
export class MainComp {
person?: Person;
address?: Address;
}
export class MyIfContext {
public $implicit: any = null;
public myIf: any = null;
}
@Directive({selector: '[myIf]'})
export class MyIf {
constructor(templateRef: TemplateRef<MyIfContext>) {}
@Input()
set myIf(condition: any) {}
static myIfUseIfTypeGuard: void;
}
@NgModule({
declarations: [MainComp, MyIf],
})
export class MainModule {}`
});
});
it('should narrow an *ngIf like directive with UseIf and !!', () => {
a({
'src/app.component.ts': '',
'src/lib.ts': '',
'src/app.module.ts': `
import {NgModule, Component, Directive, HostListener, TemplateRef, Input} from '@angular/core';
export interface Person {
name: string;
}
@Component({
selector: 'comp',
template: '<div *myIf="!!person"> {{person.name}} </div>'
})
export class MainComp {
person?: Person;
}
export class MyIfContext {
public $implicit: any = null;
public myIf: any = null;
}
@Directive({selector: '[myIf]'})
export class MyIf {
constructor(templateRef: TemplateRef<MyIfContext>) {}
@Input()
set myIf(condition: any) {}
static myIfUseIfTypeGuard: void;
}
@NgModule({
declarations: [MainComp, MyIf],
})
export class MainModule {}`
});
});
it('should narrow an *ngIf like directive with UseIf and != null', () => {
a({
'src/app.component.ts': '',
'src/lib.ts': '',
'src/app.module.ts': `
import {NgModule, Component, Directive, HostListener, TemplateRef, Input} from '@angular/core';
export interface Person {
name: string;
}
@Component({
selector: 'comp',
template: '<div *myIf="person != null"> {{person.name}} </div>'
})
export class MainComp {
person: Person | null = null;
}
export class MyIfContext {
public $implicit: any = null;
public myIf: any = null;
}
@Directive({selector: '[myIf]'})
export class MyIf {
constructor(templateRef: TemplateRef<MyIfContext>) {}
@Input()
set myIf(condition: any) {}
static myIfUseIfTypeGuard: void;
}
@NgModule({
declarations: [MainComp, MyIf],
})
export class MainModule {}`
});
});
it('should narrow an *ngIf like directive with UseIf and != undefined', () => {
a({
'src/app.component.ts': '',
'src/lib.ts': '',
'src/app.module.ts': `
import {NgModule, Component, Directive, HostListener, TemplateRef, Input} from '@angular/core';
export interface Person {
name: string;
}
@Component({
selector: 'comp',
template: '<div *myIf="person != undefined"> {{person.name}} </div>'
})
export class MainComp {
person?: Person;
}
export class MyIfContext {
public $implicit: any = null;
public myIf: any = null;
}
@Directive({selector: '[myIf]'})
export class MyIf {
constructor(templateRef: TemplateRef<MyIfContext>) {}
@Input()
set myIf(condition: any) {}
static myIfUseIfTypeGuard: void;
}
@NgModule({
declarations: [MainComp, MyIf],
})
export class MainModule {}`
});
});
});
describe('casting $any', () => {
const a = (files: MockFiles, options: object = {}) => {
accept(
{'src/app.component.ts': '', 'src/lib.ts': '', ...files},
{fullTemplateTypeCheck: true, ...options});
};
const r =
(message: string | RegExp, location: RegExp | null, files: MockFiles,
options: object = {}) => {
reject(
message, location, {'src/app.component.ts': '', 'src/lib.ts': '', ...files},
{fullTemplateTypeCheck: true, ...options});
};
it('should allow member access of an expression', () => {
a({
'src/app.module.ts': `
import {NgModule, Component} from '@angular/core';
export interface Person {
name: string;
}
@Component({
selector: 'comp',
template: ' {{$any(person).address}}'
})
export class MainComp {
person: Person;
}
@NgModule({
declarations: [MainComp],
})
export class MainModule {
}`
});
});
it('should allow invalid this.member access', () => {
a({
'src/app.module.ts': `
import {NgModule, Component} from '@angular/core';
@Component({
selector: 'comp',
template: ' {{$any(this).missing}}'
})
export class MainComp { }
@NgModule({
declarations: [MainComp],
})
export class MainModule {
}`
});
});
it('should reject too few parameters to $any', () => {
r(/Invalid call to \$any, expected 1 argument but received none/, null, {
'src/app.module.ts': `
import {NgModule, Component} from '@angular/core';
@Component({
selector: 'comp',
template: ' {{$any().missing}}'
})
export class MainComp { }
@NgModule({
declarations: [MainComp],
})
export class MainModule {
}`
});
});
it('should reject too many parameters to $any', () => {
r(/Invalid call to \$any, expected 1 argument but received 2/, null, {
'src/app.module.ts': `
import {NgModule, Component} from '@angular/core';
export interface Person {
name: string;
}
@Component({
selector: 'comp',
template: ' {{$any(person, 12).missing}}'
})
export class MainComp {
person: Person;
}
@NgModule({
declarations: [MainComp],
})
export class MainModule {
}`
});
});
});
describe('regressions ', () => {
const a = (files: MockFiles, options: object = {}) => {
accept(files, {fullTemplateTypeCheck: true, ...options});

View File

@ -1038,25 +1038,6 @@ describe('Collector', () => {
expect(metadata).toBeUndefined();
});
it('should collect type guards', () => {
const metadata = collectSource(`
import {Directive, Input, TemplateRef} from '@angular/core';
@Directive({selector: '[myIf]'})
export class MyIf {
constructor(private templateRef: TemplateRef) {}
@Input() myIf: any;
static typeGuard: <T>(v: T | null | undefined): v is T;
}
`);
expect((metadata.metadata.MyIf as any).statics.typeGuard)
.not.toBeUndefined('typeGuard was not collected');
});
it('should be able to collect an invalid access expression', () => {
const source = createSource(`
import {Component} from '@angular/core';

View File

@ -12,7 +12,6 @@ import * as path from 'path';
import * as ts from 'typescript';
import * as ng from '../index';
// TEST_TMPDIR is set by bazel.
const tmpdir = process.env.TEST_TMPDIR || os.tmpdir();
function getNgRootDir() {
@ -22,6 +21,7 @@ function getNgRootDir() {
}
export function writeTempFile(name: string, contents: string): string {
// TEST_TMPDIR is set by bazel.
const id = (Math.random() * 1000000).toFixed(0);
const fn = path.join(tmpdir, `tmp.${id}.${name}`);
fs.writeFileSync(fn, contents);
@ -29,12 +29,8 @@ export function writeTempFile(name: string, contents: string): string {
}
export function makeTempDir(): string {
let dir: string;
while (true) {
const id = (Math.random() * 1000000).toFixed(0);
dir = path.join(tmpdir, `tmp.${id}`);
if (!fs.existsSync(dir)) break;
}
const id = (Math.random() * 1000000).toFixed(0);
const dir = path.join(tmpdir, `tmp.${id}`);
fs.mkdirSync(dir);
return dir;
}

View File

@ -218,14 +218,15 @@ export class AotCompiler {
const externalReferenceVars = new Map<any, string>();
externalReferences.forEach((ref, typeIndex) => {
externalReferenceVars.set(ref, `_decl${ngModuleIndex}_${typeIndex}`);
if (this._host.isSourceFile(ref.filePath)) {
externalReferenceVars.set(ref, `_decl${ngModuleIndex}_${typeIndex}`);
}
});
externalReferenceVars.forEach((varName, reference) => {
outputCtx.statements.push(
o.variable(varName)
.set(o.NULL_EXPR.cast(o.DYNAMIC_TYPE))
.toDeclStmt(o.expressionType(outputCtx.importExpr(
reference, /* typeParams */ null, /* useSummaries */ false))));
.toDeclStmt(o.expressionType(outputCtx.importExpr(reference))));
});
if (emitFlags & StubEmitFlags.TypeCheck) {
@ -270,7 +271,7 @@ export class AotCompiler {
const {template: parsedTemplate, pipes: usedPipes} =
this._parseTemplate(compMeta, moduleMeta, directives);
ctx.statements.push(...this._typeCheckCompiler.compileComponent(
componentId, compMeta, parsedTemplate, usedPipes, externalReferenceVars, ctx));
componentId, compMeta, parsedTemplate, usedPipes, externalReferenceVars));
}
emitMessageBundle(analyzeResult: NgAnalyzedModules, locale: string|null): MessageBundle {
@ -514,38 +515,35 @@ export class AotCompiler {
}
private _createOutputContext(genFilePath: string): OutputContext {
const importExpr =
(symbol: StaticSymbol, typeParams: o.Type[] | null = null,
useSummaries: boolean = true) => {
if (!(symbol instanceof StaticSymbol)) {
throw new Error(`Internal error: unknown identifier ${JSON.stringify(symbol)}`);
}
const arity = this._symbolResolver.getTypeArity(symbol) || 0;
const {filePath, name, members} =
this._symbolResolver.getImportAs(symbol, useSummaries) || symbol;
const importModule = this._fileNameToModuleName(filePath, genFilePath);
const importExpr = (symbol: StaticSymbol, typeParams: o.Type[] | null = null) => {
if (!(symbol instanceof StaticSymbol)) {
throw new Error(`Internal error: unknown identifier ${JSON.stringify(symbol)}`);
}
const arity = this._symbolResolver.getTypeArity(symbol) || 0;
const {filePath, name, members} = this._symbolResolver.getImportAs(symbol) || symbol;
const importModule = this._fileNameToModuleName(filePath, genFilePath);
// It should be good enough to compare filePath to genFilePath and if they are equal
// there is a self reference. However, ngfactory files generate to .ts but their
// symbols have .d.ts so a simple compare is insufficient. They should be canonical
// and is tracked by #17705.
const selfReference = this._fileNameToModuleName(genFilePath, genFilePath);
const moduleName = importModule === selfReference ? null : importModule;
// It should be good enough to compare filePath to genFilePath and if they are equal
// there is a self reference. However, ngfactory files generate to .ts but their
// symbols have .d.ts so a simple compare is insufficient. They should be canonical
// and is tracked by #17705.
const selfReference = this._fileNameToModuleName(genFilePath, genFilePath);
const moduleName = importModule === selfReference ? null : importModule;
// If we are in a type expression that refers to a generic type then supply
// the required type parameters. If there were not enough type parameters
// supplied, supply any as the type. Outside a type expression the reference
// should not supply type parameters and be treated as a simple value reference
// to the constructor function itself.
const suppliedTypeParams = typeParams || [];
const missingTypeParamsCount = arity - suppliedTypeParams.length;
const allTypeParams =
suppliedTypeParams.concat(new Array(missingTypeParamsCount).fill(o.DYNAMIC_TYPE));
return members.reduce(
(expr, memberName) => expr.prop(memberName),
<o.Expression>o.importExpr(
new o.ExternalReference(moduleName, name, null), allTypeParams));
};
// If we are in a type expression that refers to a generic type then supply
// the required type parameters. If there were not enough type parameters
// supplied, supply any as the type. Outside a type expression the reference
// should not supply type parameters and be treated as a simple value reference
// to the constructor function itself.
const suppliedTypeParams = typeParams || [];
const missingTypeParamsCount = arity - suppliedTypeParams.length;
const allTypeParams =
suppliedTypeParams.concat(new Array(missingTypeParamsCount).fill(o.DYNAMIC_TYPE));
return members.reduce(
(expr, memberName) => expr.prop(memberName),
<o.Expression>o.importExpr(
new o.ExternalReference(moduleName, name, null), allTypeParams));
};
return {statements: [], genFilePath, importExpr};
}

View File

@ -29,8 +29,6 @@ const IGNORE = {
const USE_VALUE = 'useValue';
const PROVIDE = 'provide';
const REFERENCE_SET = new Set([USE_VALUE, 'useFactory', 'data']);
const TYPEGUARD_POSTFIX = 'TypeGuard';
const USE_IF = 'UseIf';
function shouldIgnore(value: any): boolean {
return value && value.__symbolic == 'ignore';
@ -45,7 +43,6 @@ export class StaticReflector implements CompileReflector {
private propertyCache = new Map<StaticSymbol, {[key: string]: any[]}>();
private parameterCache = new Map<StaticSymbol, any[]>();
private methodCache = new Map<StaticSymbol, {[key: string]: boolean}>();
private staticCache = new Map<StaticSymbol, string[]>();
private conversionMap = new Map<StaticSymbol, (context: StaticSymbol, args: any[]) => any>();
private injectionToken: StaticSymbol;
private opaqueToken: StaticSymbol;
@ -254,18 +251,6 @@ export class StaticReflector implements CompileReflector {
return methodNames;
}
private _staticMembers(type: StaticSymbol): string[] {
let staticMembers = this.staticCache.get(type);
if (!staticMembers) {
const classMetadata = this.getTypeMetadata(type);
const staticMemberData = classMetadata['statics'] || {};
staticMembers = Object.keys(staticMemberData);
this.staticCache.set(type, staticMembers);
}
return staticMembers;
}
private findParentType(type: StaticSymbol, classMetadata: any): StaticSymbol|undefined {
const parentType = this.trySimplify(type, classMetadata['extends']);
if (parentType instanceof StaticSymbol) {
@ -288,30 +273,6 @@ export class StaticReflector implements CompileReflector {
}
}
guards(type: any): {[key: string]: StaticSymbol} {
if (!(type instanceof StaticSymbol)) {
this.reportError(
new Error(`guards received ${JSON.stringify(type)} which is not a StaticSymbol`), type);
return {};
}
const staticMembers = this._staticMembers(type);
const result: {[key: string]: StaticSymbol} = {};
for (let name of staticMembers) {
if (name.endsWith(TYPEGUARD_POSTFIX)) {
let property = name.substr(0, name.length - TYPEGUARD_POSTFIX.length);
let value: any;
if (property.endsWith(USE_IF)) {
property = name.substr(0, property.length - USE_IF.length);
value = USE_IF;
} else {
value = this.getStaticSymbol(type.filePath, type.name, [name]);
}
result[property] = value;
}
}
return result;
}
private _registerDecoratorOrConstructor(type: StaticSymbol, ctor: any): void {
this.conversionMap.set(type, (context: StaticSymbol, args: any[]) => new ctor(...args));
}

View File

@ -98,10 +98,10 @@ export class StaticSymbolResolver {
*
* @param staticSymbol the symbol for which to generate a import symbol
*/
getImportAs(staticSymbol: StaticSymbol, useSummaries: boolean = true): StaticSymbol|null {
getImportAs(staticSymbol: StaticSymbol): StaticSymbol|null {
if (staticSymbol.members.length) {
const baseSymbol = this.getStaticSymbol(staticSymbol.filePath, staticSymbol.name);
const baseImportAs = this.getImportAs(baseSymbol, useSummaries);
const baseImportAs = this.getImportAs(baseSymbol);
return baseImportAs ?
this.getStaticSymbol(baseImportAs.filePath, baseImportAs.name, staticSymbol.members) :
null;
@ -111,14 +111,14 @@ export class StaticSymbolResolver {
const summarizedName = stripSummaryForJitNameSuffix(staticSymbol.name);
const baseSymbol =
this.getStaticSymbol(summarizedFileName, summarizedName, staticSymbol.members);
const baseImportAs = this.getImportAs(baseSymbol, useSummaries);
const baseImportAs = this.getImportAs(baseSymbol);
return baseImportAs ?
this.getStaticSymbol(
summaryForJitFileName(baseImportAs.filePath), summaryForJitName(baseImportAs.name),
baseSymbol.members) :
null;
}
let result = (useSummaries && this.summaryResolver.getImportAs(staticSymbol)) || null;
let result = this.summaryResolver.getImportAs(staticSymbol);
if (!result) {
result = this.importAs.get(staticSymbol) !;
}
@ -481,7 +481,7 @@ export class StaticSymbolResolver {
if (moduleMetadatas) {
let maxVersion = -1;
moduleMetadatas.forEach((md) => {
if (md['version'] > maxVersion) {
if (md && md['version'] > maxVersion) {
maxVersion = md['version'];
moduleMetadata = md;
}

View File

@ -254,7 +254,6 @@ export interface CompileDirectiveSummary extends CompileTypeSummary {
providers: CompileProviderMetadata[];
viewProviders: CompileProviderMetadata[];
queries: CompileQueryMetadata[];
guards: {[key: string]: any};
viewQueries: CompileQueryMetadata[];
entryComponents: CompileEntryComponentMetadata[];
changeDetection: ChangeDetectionStrategy|null;
@ -269,8 +268,8 @@ export interface CompileDirectiveSummary extends CompileTypeSummary {
*/
export class CompileDirectiveMetadata {
static create({isHost, type, isComponent, selector, exportAs, changeDetection, inputs, outputs,
host, providers, viewProviders, queries, guards, viewQueries, entryComponents,
template, componentViewType, rendererType, componentFactory}: {
host, providers, viewProviders, queries, viewQueries, entryComponents, template,
componentViewType, rendererType, componentFactory}: {
isHost: boolean,
type: CompileTypeMetadata,
isComponent: boolean,
@ -283,7 +282,6 @@ export class CompileDirectiveMetadata {
providers: CompileProviderMetadata[],
viewProviders: CompileProviderMetadata[],
queries: CompileQueryMetadata[],
guards: {[key: string]: any};
viewQueries: CompileQueryMetadata[],
entryComponents: CompileEntryComponentMetadata[],
template: CompileTemplateMetadata,
@ -338,7 +336,6 @@ export class CompileDirectiveMetadata {
providers,
viewProviders,
queries,
guards,
viewQueries,
entryComponents,
template,
@ -361,7 +358,6 @@ export class CompileDirectiveMetadata {
providers: CompileProviderMetadata[];
viewProviders: CompileProviderMetadata[];
queries: CompileQueryMetadata[];
guards: {[key: string]: any};
viewQueries: CompileQueryMetadata[];
entryComponents: CompileEntryComponentMetadata[];
@ -371,27 +367,10 @@ export class CompileDirectiveMetadata {
rendererType: StaticSymbol|object|null;
componentFactory: StaticSymbol|object|null;
constructor({isHost,
type,
isComponent,
selector,
exportAs,
changeDetection,
inputs,
outputs,
hostListeners,
hostProperties,
hostAttributes,
providers,
viewProviders,
queries,
guards,
viewQueries,
entryComponents,
template,
componentViewType,
rendererType,
componentFactory}: {
constructor({isHost, type, isComponent, selector, exportAs,
changeDetection, inputs, outputs, hostListeners, hostProperties,
hostAttributes, providers, viewProviders, queries, viewQueries,
entryComponents, template, componentViewType, rendererType, componentFactory}: {
isHost: boolean,
type: CompileTypeMetadata,
isComponent: boolean,
@ -406,7 +385,6 @@ export class CompileDirectiveMetadata {
providers: CompileProviderMetadata[],
viewProviders: CompileProviderMetadata[],
queries: CompileQueryMetadata[],
guards: {[key: string]: any},
viewQueries: CompileQueryMetadata[],
entryComponents: CompileEntryComponentMetadata[],
template: CompileTemplateMetadata|null,
@ -428,7 +406,6 @@ export class CompileDirectiveMetadata {
this.providers = _normalizeArray(providers);
this.viewProviders = _normalizeArray(viewProviders);
this.queries = _normalizeArray(queries);
this.guards = guards;
this.viewQueries = _normalizeArray(viewQueries);
this.entryComponents = _normalizeArray(entryComponents);
this.template = template;
@ -453,7 +430,6 @@ export class CompileDirectiveMetadata {
providers: this.providers,
viewProviders: this.viewProviders,
queries: this.queries,
guards: this.guards,
viewQueries: this.viewQueries,
entryComponents: this.entryComponents,
changeDetection: this.changeDetection,

View File

@ -17,7 +17,6 @@ export abstract class CompileReflector {
abstract annotations(typeOrFunc: /*Type*/ any): any[];
abstract propMetadata(typeOrFunc: /*Type*/ any): {[key: string]: any[]};
abstract hasLifecycleHook(type: any, lcProperty: string): boolean;
abstract guards(typeOrFunc: /* Type */ any): {[key: string]: any};
abstract componentModuleUrl(type: /*Type*/ any, cmpMetadata: Component): string;
abstract resolveExternalReference(ref: o.ExternalReference): any;
}

View File

@ -90,14 +90,6 @@ export class ConvertPropertyBindingResult {
constructor(public stmts: o.Statement[], public currValExpr: o.Expression) {}
}
export enum BindingForm {
// The general form of binding expression, supports all expressions.
General,
// Try to generate a simple binding (no temporaries or statements)
// otherise generate a general binding
TrySimple,
}
/**
* Converts the given expression AST into an executable output AST, assuming the expression
* is used in property binding. The expression has to be preprocessed via
@ -105,8 +97,7 @@ export enum BindingForm {
*/
export function convertPropertyBinding(
localResolver: LocalResolver | null, implicitReceiver: o.Expression,
expressionWithoutBuiltins: cdAst.AST, bindingId: string,
form: BindingForm): ConvertPropertyBindingResult {
expressionWithoutBuiltins: cdAst.AST, bindingId: string): ConvertPropertyBindingResult {
if (!localResolver) {
localResolver = new DefaultLocalResolver();
}
@ -119,11 +110,9 @@ export function convertPropertyBinding(
for (let i = 0; i < visitor.temporaryCount; i++) {
stmts.push(temporaryDeclaration(bindingId, i));
}
} else if (form == BindingForm.TrySimple) {
return new ConvertPropertyBindingResult([], outputExpr);
}
stmts.push(currValExpr.set(outputExpr).toDeclStmt(o.DYNAMIC_TYPE, [o.StmtModifier.Final]));
stmts.push(currValExpr.set(outputExpr).toDeclStmt(null, [o.StmtModifier.Final]));
return new ConvertPropertyBindingResult(stmts, currValExpr);
}
@ -334,27 +323,12 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
}
visitLiteralPrimitive(ast: cdAst.LiteralPrimitive, mode: _Mode): any {
// For literal values of null, undefined, true, or false allow type inteference
// to infer the type.
const type =
ast.value === null || ast.value === undefined || ast.value === true || ast.value === true ?
o.INFERRED_TYPE :
undefined;
return convertToStatementIfNeeded(mode, o.literal(ast.value, type));
return convertToStatementIfNeeded(mode, o.literal(ast.value));
}
private _getLocal(name: string): o.Expression|null { return this._localResolver.getLocal(name); }
visitMethodCall(ast: cdAst.MethodCall, mode: _Mode): any {
if (ast.receiver instanceof cdAst.ImplicitReceiver && ast.name == '$any') {
const args = this.visitAll(ast.args, _Mode.Expression) as any[];
if (args.length != 1) {
throw new Error(
`Invalid call to $any, expected 1 argument but received ${args.length || 'none'}`);
}
return (args[0] as o.Expression).cast(o.DYNAMIC_TYPE);
}
const leftMostSafe = this.leftMostSafeNode(ast);
if (leftMostSafe) {
return this.convertSafeAccess(ast, leftMostSafe, mode);

View File

@ -51,7 +51,6 @@ export interface Directive {
providers?: Provider[];
exportAs?: string;
queries?: {[key: string]: any};
guards?: {[key: string]: any};
}
export const createDirective =
makeMetadataFactory<Directive>('Directive', (dir: Directive = {}) => dir);

View File

@ -44,8 +44,7 @@ export class DirectiveResolver {
const metadata = findLast(typeMetadata, isDirectiveMetadata);
if (metadata) {
const propertyMetadata = this._reflector.propMetadata(type);
const guards = this._reflector.guards(type);
return this._mergeWithPropertyMetadata(metadata, propertyMetadata, guards, type);
return this._mergeWithPropertyMetadata(metadata, propertyMetadata, type);
}
}
@ -57,12 +56,12 @@ export class DirectiveResolver {
}
private _mergeWithPropertyMetadata(
dm: Directive, propertyMetadata: {[key: string]: any[]}, guards: {[key: string]: any},
directiveType: Type): Directive {
dm: Directive, propertyMetadata: {[key: string]: any[]}, directiveType: Type): Directive {
const inputs: string[] = [];
const outputs: string[] = [];
const host: {[key: string]: string} = {};
const queries: {[key: string]: any} = {};
Object.keys(propertyMetadata).forEach((propName: string) => {
const input = findLast(propertyMetadata[propName], (a) => createInput.isTypeOf(a));
if (input) {
@ -106,20 +105,18 @@ export class DirectiveResolver {
queries[propName] = query;
}
});
return this._merge(dm, inputs, outputs, host, queries, guards, directiveType);
return this._merge(dm, inputs, outputs, host, queries, directiveType);
}
private _extractPublicName(def: string) { return splitAtColon(def, [null !, def])[1].trim(); }
private _dedupeBindings(bindings: string[]): string[] {
const names = new Set<string>();
const publicNames = new Set<string>();
const reversedResult: string[] = [];
// go last to first to allow later entries to overwrite previous entries
for (let i = bindings.length - 1; i >= 0; i--) {
const binding = bindings[i];
const name = this._extractPublicName(binding);
publicNames.add(name);
if (!names.has(name)) {
names.add(name);
reversedResult.push(binding);
@ -130,13 +127,14 @@ export class DirectiveResolver {
private _merge(
directive: Directive, inputs: string[], outputs: string[], host: {[key: string]: string},
queries: {[key: string]: any}, guards: {[key: string]: any}, directiveType: Type): Directive {
queries: {[key: string]: any}, directiveType: Type): Directive {
const mergedInputs =
this._dedupeBindings(directive.inputs ? directive.inputs.concat(inputs) : inputs);
const mergedOutputs =
this._dedupeBindings(directive.outputs ? directive.outputs.concat(outputs) : outputs);
const mergedHost = directive.host ? {...directive.host, ...host} : host;
const mergedQueries = directive.queries ? {...directive.queries, ...queries} : queries;
if (createComponent.isTypeOf(directive)) {
const comp = directive as Component;
return createComponent({
@ -168,7 +166,7 @@ export class DirectiveResolver {
host: mergedHost,
exportAs: directive.exportAs,
queries: mergedQueries,
providers: directive.providers, guards
providers: directive.providers
});
}
}

View File

@ -208,7 +208,6 @@ export class CompileMetadataResolver {
providers: [],
viewProviders: [],
queries: [],
guards: {},
viewQueries: [],
componentViewType: hostViewType,
rendererType:
@ -241,7 +240,6 @@ export class CompileMetadataResolver {
providers: metadata.providers,
viewProviders: metadata.viewProviders,
queries: metadata.queries,
guards: metadata.guards,
viewQueries: metadata.viewQueries,
entryComponents: metadata.entryComponents,
componentViewType: metadata.componentViewType,
@ -385,7 +383,6 @@ export class CompileMetadataResolver {
providers: providers || [],
viewProviders: viewProviders || [],
queries: queries || [],
guards: dirMeta.guards || {},
viewQueries: viewQueries || [],
entryComponents: entryComponentMetadata,
componentViewType: nonNormalizedTemplateMetadata ? this.getComponentViewClass(directiveType) :

View File

@ -152,7 +152,7 @@ export function utf8Encode(str: string): string {
export interface OutputContext {
genFilePath: string;
statements: o.Statement[];
importExpr(reference: any, typeParams?: o.Type[]|null, useSummaries?: boolean): o.Expression;
importExpr(reference: any, typeParams?: o.Type[]|null): o.Expression;
}
export function stringify(token: any): string {

View File

@ -10,15 +10,13 @@ import {AotCompilerOptions} from '../aot/compiler_options';
import {StaticReflector} from '../aot/static_reflector';
import {StaticSymbol} from '../aot/static_symbol';
import {CompileDiDependencyMetadata, CompileDirectiveMetadata, CompilePipeSummary} from '../compile_metadata';
import {BindingForm, BuiltinConverter, EventHandlerVars, LocalResolver, convertActionBinding, convertPropertyBinding, convertPropertyBindingBuiltins} from '../compiler_util/expression_converter';
import {BuiltinConverter, EventHandlerVars, LocalResolver, convertActionBinding, convertPropertyBinding, convertPropertyBindingBuiltins} from '../compiler_util/expression_converter';
import {AST, ASTWithSource, Interpolation} from '../expression_parser/ast';
import {Identifiers} from '../identifiers';
import * as o from '../output/output_ast';
import {convertValueToOutputAst} from '../output/value_util';
import {ParseSourceSpan} from '../parse_util';
import {AttrAst, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, DirectiveAst, ElementAst, EmbeddedTemplateAst, NgContentAst, PropertyBindingType, ProviderAst, ProviderAstType, QueryMatch, ReferenceAst, TemplateAst, TemplateAstVisitor, TextAst, VariableAst, templateVisitAll} from '../template_parser/template_ast';
import {OutputContext} from '../util';
/**
* Generates code that is used to type check templates.
@ -36,34 +34,27 @@ export class TypeCheckCompiler {
*/
compileComponent(
componentId: string, component: CompileDirectiveMetadata, template: TemplateAst[],
usedPipes: CompilePipeSummary[], externalReferenceVars: Map<StaticSymbol, string>,
ctx: OutputContext): o.Statement[] {
usedPipes: CompilePipeSummary[],
externalReferenceVars: Map<StaticSymbol, string>): o.Statement[] {
const pipes = new Map<string, StaticSymbol>();
usedPipes.forEach(p => pipes.set(p.name, p.type.reference));
let embeddedViewCount = 0;
const viewBuilderFactory =
(parent: ViewBuilder | null, guards: GuardExpression[]): ViewBuilder => {
const embeddedViewIndex = embeddedViewCount++;
return new ViewBuilder(
this.options, this.reflector, externalReferenceVars, parent, component.type.reference,
component.isHost, embeddedViewIndex, pipes, guards, ctx, viewBuilderFactory);
};
const viewBuilderFactory = (parent: ViewBuilder | null): ViewBuilder => {
const embeddedViewIndex = embeddedViewCount++;
return new ViewBuilder(
this.options, this.reflector, externalReferenceVars, parent, component.type.reference,
component.isHost, embeddedViewIndex, pipes, viewBuilderFactory);
};
const visitor = viewBuilderFactory(null, []);
const visitor = viewBuilderFactory(null);
visitor.visitAll([], template);
return visitor.build(componentId);
}
}
interface GuardExpression {
guard: StaticSymbol;
useIf: boolean;
expression: Expression;
}
interface ViewBuilderFactory {
(parent: ViewBuilder, guards: GuardExpression[]): ViewBuilder;
(parent: ViewBuilder): ViewBuilder;
}
// Note: This is used as key in Map and should therefore be
@ -103,7 +94,6 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
private externalReferenceVars: Map<StaticSymbol, string>, private parent: ViewBuilder|null,
private component: StaticSymbol, private isHostComponent: boolean,
private embeddedViewIndex: number, private pipes: Map<string, StaticSymbol>,
private guards: GuardExpression[], private ctx: OutputContext,
private viewBuilderFactory: ViewBuilderFactory) {}
private getOutputVar(type: o.BuiltinTypeName|StaticSymbol): string {
@ -122,24 +112,6 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
return varName;
}
private getTypeGuardExpressions(ast: EmbeddedTemplateAst): GuardExpression[] {
const result = [...this.guards];
for (let directive of ast.directives) {
for (let input of directive.inputs) {
const guard = directive.directive.guards[input.directiveName];
if (guard) {
const useIf = guard === 'UseIf';
result.push({
guard,
useIf,
expression: {context: this.component, value: input.value} as Expression
});
}
}
}
return result;
}
visitAll(variables: VariableAst[], astNodes: TemplateAst[]) {
this.variables = variables;
templateVisitAll(this, astNodes);
@ -147,7 +119,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
build(componentId: string, targetStatements: o.Statement[] = []): o.Statement[] {
this.children.forEach((child) => child.build(componentId, targetStatements));
let viewStmts: o.Statement[] =
const viewStmts: o.Statement[] =
[o.variable(DYNAMIC_VAR_NAME).set(o.NULL_EXPR).toDeclStmt(o.DYNAMIC_TYPE)];
let bindingCount = 0;
this.updates.forEach((expression) => {
@ -155,8 +127,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
const bindingId = `${bindingCount++}`;
const nameResolver = context === this.component ? this : defaultResolver;
const {stmts, currValExpr} = convertPropertyBinding(
nameResolver, o.variable(this.getOutputVar(context)), value, bindingId,
BindingForm.General);
nameResolver, o.variable(this.getOutputVar(context)), value, bindingId);
stmts.push(new o.ExpressionStatement(currValExpr));
viewStmts.push(...stmts.map(
(stmt: o.Statement) => o.applySourceSpanToStatementIfNeeded(stmt, sourceSpan)));
@ -171,28 +142,6 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
(stmt: o.Statement) => o.applySourceSpanToStatementIfNeeded(stmt, sourceSpan)));
});
if (this.guards.length) {
let guardExpression: o.Expression|undefined = undefined;
for (const guard of this.guards) {
const {context, value} = this.preprocessUpdateExpression(guard.expression);
const bindingId = `${bindingCount++}`;
const nameResolver = context === this.component ? this : defaultResolver;
// We only support support simple expressions and ignore others as they
// are unlikely to affect type narrowing.
const {stmts, currValExpr} = convertPropertyBinding(
nameResolver, o.variable(this.getOutputVar(context)), value, bindingId,
BindingForm.TrySimple);
if (stmts.length == 0) {
const guardClause =
guard.useIf ? currValExpr : this.ctx.importExpr(guard.guard).callFn([currValExpr]);
guardExpression = guardExpression ? guardExpression.and(guardClause) : guardClause;
}
}
if (guardExpression) {
viewStmts = [new o.IfStmt(guardExpression, viewStmts)];
}
}
const viewName = `_View_${componentId}_${this.embeddedViewIndex}`;
const viewFactory = new o.DeclareFunctionStmt(viewName, [], viewStmts);
targetStatements.push(viewFactory);
@ -214,12 +163,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
// for the context in any embedded view.
// We keep this behaivor behind a flag for now.
if (this.options.fullTemplateTypeCheck) {
// Find any applicable type guards. For example, NgIf has a type guard on ngIf
// (see NgIf.ngIfTypeGuard) that can be used to indicate that a template is only
// stamped out if ngIf is truthy so any bindings in the template can assume that,
// if a nullable type is used for ngIf, that expression is not null or undefined.
const guards = this.getTypeGuardExpressions(ast);
const childVisitor = this.viewBuilderFactory(this, guards);
const childVisitor = this.viewBuilderFactory(this);
this.children.push(childVisitor);
childVisitor.visitAll(ast.variables, ast.children);
}

View File

@ -8,7 +8,7 @@
import {CompileDirectiveMetadata, CompilePipeSummary, rendererTypeName, tokenReference, viewClassName} from '../compile_metadata';
import {CompileReflector} from '../compile_reflector';
import {BindingForm, BuiltinConverter, EventHandlerVars, LocalResolver, convertActionBinding, convertPropertyBinding, convertPropertyBindingBuiltins} from '../compiler_util/expression_converter';
import {BuiltinConverter, EventHandlerVars, LocalResolver, convertActionBinding, convertPropertyBinding, convertPropertyBindingBuiltins} from '../compiler_util/expression_converter';
import {ArgumentType, BindingFlags, ChangeDetectionStrategy, NodeFlags, QueryBindingType, QueryValueType, ViewFlags} from '../core';
import {AST, ASTWithSource, Interpolation} from '../expression_parser/ast';
import {Identifiers} from '../identifiers';
@ -859,7 +859,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
const bindingId = `${updateBindingCount++}`;
const nameResolver = context === COMP_VAR ? self : null;
const {stmts, currValExpr} =
convertPropertyBinding(nameResolver, context, value, bindingId, BindingForm.General);
convertPropertyBinding(nameResolver, context, value, bindingId);
updateStmts.push(...stmts.map(
(stmt: o.Statement) => o.applySourceSpanToStatementIfNeeded(stmt, sourceSpan)));
return o.applySourceSpanToExpressionIfNeeded(currValExpr, sourceSpan);

View File

@ -196,25 +196,6 @@ describe('StaticSymbolResolver', () => {
.toBe(symbolCache.get('/test3.d.ts', 'b'));
});
it('should ignore summaries for inputAs if requested', () => {
init(
{
'/test.ts': `
export {a} from './test2';
`
},
[], [{
symbol: symbolCache.get('/test2.d.ts', 'a'),
importAs: symbolCache.get('/test3.d.ts', 'b')
}]);
symbolResolver.getSymbolsOf('/test.ts');
expect(
symbolResolver.getImportAs(symbolCache.get('/test2.d.ts', 'a'), /* useSummaries */ false))
.toBeUndefined();
});
it('should calculate importAs for symbols with members based on importAs for symbols without',
() => {
init(

View File

@ -126,7 +126,6 @@ export function main() {
outputs: [],
host: {},
queries: {},
guards: {},
exportAs: undefined,
providers: undefined
}));
@ -155,7 +154,6 @@ export function main() {
outputs: [],
host: {},
queries: {},
guards: {},
exportAs: undefined,
providers: undefined
}));
@ -166,7 +164,6 @@ export function main() {
outputs: [],
host: {},
queries: {},
guards: {},
exportAs: undefined,
providers: undefined
}));

View File

@ -38,29 +38,28 @@ function createTypeMeta({reference, diDeps}: {reference: any, diDeps?: any[]}):
return {reference: reference, diDeps: diDeps || [], lifecycleHooks: []};
}
function compileDirectiveMetadataCreate(
{isHost, type, isComponent, selector, exportAs, changeDetection, inputs, outputs, host,
providers, viewProviders, queries, guards, viewQueries, entryComponents, template,
componentViewType, rendererType}: {
isHost?: boolean,
type?: CompileTypeMetadata,
isComponent?: boolean,
selector?: string | null,
exportAs?: string | null,
changeDetection?: ChangeDetectionStrategy | null,
inputs?: string[],
outputs?: string[],
host?: {[key: string]: string},
providers?: CompileProviderMetadata[] | null,
viewProviders?: CompileProviderMetadata[] | null,
queries?: CompileQueryMetadata[] | null,
guards?: {[key: string]: any},
viewQueries?: CompileQueryMetadata[],
entryComponents?: CompileEntryComponentMetadata[],
template?: CompileTemplateMetadata,
componentViewType?: StaticSymbol | ProxyClass | null,
rendererType?: StaticSymbol | RendererType2 | null,
}) {
function compileDirectiveMetadataCreate({isHost, type, isComponent, selector, exportAs,
changeDetection, inputs, outputs, host, providers,
viewProviders, queries, viewQueries, entryComponents,
template, componentViewType, rendererType}: {
isHost?: boolean,
type?: CompileTypeMetadata,
isComponent?: boolean,
selector?: string | null,
exportAs?: string | null,
changeDetection?: ChangeDetectionStrategy | null,
inputs?: string[],
outputs?: string[],
host?: {[key: string]: string},
providers?: CompileProviderMetadata[] | null,
viewProviders?: CompileProviderMetadata[] | null,
queries?: CompileQueryMetadata[] | null,
viewQueries?: CompileQueryMetadata[],
entryComponents?: CompileEntryComponentMetadata[],
template?: CompileTemplateMetadata,
componentViewType?: StaticSymbol | ProxyClass | null,
rendererType?: StaticSymbol | RendererType2 | null,
}) {
return CompileDirectiveMetadata.create({
isHost: !!isHost,
type: noUndefined(type) !,
@ -74,7 +73,6 @@ function compileDirectiveMetadataCreate(
providers: providers || [],
viewProviders: viewProviders || [],
queries: queries || [],
guards: guards || {},
viewQueries: viewQueries || [],
entryComponents: entryComponents || [],
template: noUndefined(template) !,
@ -392,7 +390,6 @@ export function main() {
providers: [],
viewProviders: [],
queries: [],
guards: {},
viewQueries: [],
entryComponents: [],
componentViewType: null,

View File

@ -102,8 +102,7 @@ export function createPlatformFactory(
parentPlatformFactory: ((extraProviders?: StaticProvider[]) => PlatformRef) | null,
name: string, providers: StaticProvider[] = []): (extraProviders?: StaticProvider[]) =>
PlatformRef {
const desc = `Platform: ${name}`;
const marker = new InjectionToken(desc);
const marker = new InjectionToken(`Platform: ${name}`);
return (extraProviders: StaticProvider[] = []) => {
let platform = getPlatform();
if (!platform || platform.injector.get(ALLOW_MULTIPLE_PLATFORMS, false)) {
@ -111,9 +110,8 @@ export function createPlatformFactory(
parentPlatformFactory(
providers.concat(extraProviders).concat({provide: marker, useValue: true}));
} else {
const injectedProviders: StaticProvider[] =
providers.concat(extraProviders).concat({provide: marker, useValue: true});
createPlatform(Injector.create({providers: injectedProviders, name: desc}));
createPlatform(Injector.create(
providers.concat(extraProviders).concat({provide: marker, useValue: true})));
}
}
return assertPlatform(marker);
@ -226,12 +224,10 @@ export class PlatformRef {
// pass that as parent to the NgModuleFactory.
const ngZoneOption = options ? options.ngZone : undefined;
const ngZone = getNgZone(ngZoneOption);
const providers: StaticProvider[] = [{provide: NgZone, useValue: ngZone}];
// Attention: Don't use ApplicationRef.run here,
// as we want to be sure that all possible constructor calls are inside `ngZone.run`!
return ngZone.run(() => {
const ngZoneInjector = Injector.create(
{providers: providers, parent: this.injector, name: moduleFactory.moduleType.name});
const ngZoneInjector = Injector.create([{provide: NgZone, useValue: ngZone}], this.injector);
const moduleRef = <InternalNgModuleRef<M>>moduleFactory.create(ngZoneInjector);
const exceptionHandler: ErrorHandler = moduleRef.injector.get(ErrorHandler, null);
if (!exceptionHandler) {

View File

@ -8,12 +8,12 @@
import {Type} from '../type';
import {stringify} from '../util';
import {resolveForwardRef} from './forward_ref';
import {InjectionToken} from './injection_token';
import {Inject, Optional, Self, SkipSelf} from './metadata';
import {ConstructorProvider, ExistingProvider, FactoryProvider, StaticClassProvider, StaticProvider, ValueProvider} from './provider';
export const SOURCE = '__source';
const _THROW_IF_NOT_FOUND = new Object();
export const THROW_IF_NOT_FOUND = _THROW_IF_NOT_FOUND;
@ -64,13 +64,6 @@ export abstract class Injector {
*/
abstract get(token: any, notFoundValue?: any): any;
/**
* @deprecated from v5 use the new signature Injector.create(options)
*/
static create(providers: StaticProvider[], parent?: Injector): Injector;
static create(options: {providers: StaticProvider[], parent?: Injector, name?: string}): Injector;
/**
* Create a new Injector which is configure using `StaticProvider`s.
*
@ -78,14 +71,8 @@ export abstract class Injector {
*
* {@example core/di/ts/provider_spec.ts region='ConstructorProvider'}
*/
static create(
options: StaticProvider[]|{providers: StaticProvider[], parent?: Injector, name?: string},
parent?: Injector): Injector {
if (Array.isArray(options)) {
return new StaticInjector(options, parent);
} else {
return new StaticInjector(options.providers, options.parent, options.name || null);
}
static create(providers: StaticProvider[], parent?: Injector): Injector {
return new StaticInjector(providers, parent);
}
}
@ -116,14 +103,11 @@ const NO_NEW_LINE = 'ɵ';
export class StaticInjector implements Injector {
readonly parent: Injector;
readonly source: string|null;
private _records: Map<any, Record>;
constructor(
providers: StaticProvider[], parent: Injector = NULL_INJECTOR, source: string|null = null) {
constructor(providers: StaticProvider[], parent: Injector = NULL_INJECTOR) {
this.parent = parent;
this.source = source;
const records = this._records = new Map<any, Record>();
records.set(
Injector, <Record>{token: Injector, fn: IDENT, deps: EMPTY, value: this, useNew: false});
@ -138,10 +122,7 @@ export class StaticInjector implements Injector {
return tryResolveToken(token, record, this._records, this.parent, notFoundValue);
} catch (e) {
const tokenPath: any[] = e[NG_TEMP_TOKEN_PATH];
if (token[SOURCE]) {
tokenPath.unshift(token[SOURCE]);
}
e.message = formatError('\n' + e.message, tokenPath, this.source);
e.message = formatError('\n' + e.message, tokenPath);
e[NG_TOKEN_PATH] = tokenPath;
e[NG_TEMP_TOKEN_PATH] = null;
throw e;
@ -355,7 +336,7 @@ function computeDeps(provider: StaticProvider): DependencyRecord[] {
return deps;
}
function formatError(text: string, obj: any, source: string | null = null): string {
function formatError(text: string, obj: any): string {
text = text && text.charAt(0) === '\n' && text.charAt(1) == NO_NEW_LINE ? text.substr(2) : text;
let context = stringify(obj);
if (obj instanceof Array) {
@ -371,7 +352,7 @@ function formatError(text: string, obj: any, source: string | null = null): stri
}
context = `{${parts.join(', ')}}`;
}
return `StaticInjectorError${source ? '(' + source + ')' : ''}[${context}]: ${text.replace(NEW_LINE, '\n ')}`;
return `StaticInjectorError[${context}]: ${text.replace(NEW_LINE, '\n ')}`;
}
function staticError(text: string, obj: any): Error {

View File

@ -71,13 +71,11 @@ export interface ResolvedReflectiveProvider {
}
export class ResolvedReflectiveProvider_ implements ResolvedReflectiveProvider {
readonly resolvedFactory: ResolvedReflectiveFactory;
constructor(
public key: ReflectiveKey, public resolvedFactories: ResolvedReflectiveFactory[],
public multiProvider: boolean) {
this.resolvedFactory = this.resolvedFactories[0];
}
public multiProvider: boolean) {}
get resolvedFactory(): ResolvedReflectiveFactory { return this.resolvedFactories[0]; }
}
/**

View File

@ -66,20 +66,13 @@ export class CodegenComponentFactoryResolver implements ComponentFactoryResolver
}
export class ComponentFactoryBoundToModule<C> extends ComponentFactory<C> {
readonly selector: string;
readonly componentType: Type<any>;
readonly ngContentSelectors: string[];
readonly inputs: {propName: string, templateName: string}[];
readonly outputs: {propName: string, templateName: string}[];
constructor(private factory: ComponentFactory<C>, private ngModule: NgModuleRef<any>) { super(); }
constructor(private factory: ComponentFactory<C>, private ngModule: NgModuleRef<any>) {
super();
this.selector = factory.selector;
this.componentType = factory.componentType;
this.ngContentSelectors = factory.ngContentSelectors;
this.inputs = factory.inputs;
this.outputs = factory.outputs;
}
get selector() { return this.factory.selector; }
get componentType() { return this.factory.componentType; }
get ngContentSelectors() { return this.factory.ngContentSelectors; }
get inputs() { return this.factory.inputs; }
get outputs() { return this.factory.outputs; }
create(
injector: Injector, projectableNodes?: any[][], rootSelectorOrNode?: string|any,

View File

@ -41,9 +41,9 @@ export class QueryList<T>/* implements Iterable<T> */ {
private _results: Array<T> = [];
public readonly changes: Observable<any> = new EventEmitter();
readonly length: number;
readonly first: T;
readonly last: T;
get length(): number { return this._results.length; }
get first(): T { return this._results[0]; }
get last(): T { return this._results[this.length - 1]; }
/**
* See
@ -98,9 +98,6 @@ export class QueryList<T>/* implements Iterable<T> */ {
reset(res: Array<T|any[]>): void {
this._results = flatten(res);
(this as{dirty: boolean}).dirty = false;
(this as{length: number}).length = this._results.length;
(this as{last: T}).last = this._results[this.length - 1];
(this as{first: T}).first = this._results[0];
}
notifyOnChanges(): void { (this.changes as EventEmitter<any>).emit(this); }

View File

@ -13,7 +13,6 @@ export interface PlatformReflectionCapabilities {
isReflectionEnabled(): boolean;
factory(type: Type<any>): Function;
hasLifecycleHook(type: any, lcProperty: string): boolean;
guards(type: any): {[key: string]: any};
/**
* Return a list of annotations/types for constructor parameters

View File

@ -207,8 +207,6 @@ export class ReflectionCapabilities implements PlatformReflectionCapabilities {
return type instanceof Type && lcProperty in type.prototype;
}
guards(type: any): {[key: string]: any} { return {}; }
getter(name: string): GetterFn { return <GetterFn>new Function('o', 'return o.' + name + ';'); }
setter(name: string): SetterFn {

View File

@ -9,7 +9,6 @@
import {resolveForwardRef} from '../di/forward_ref';
import {Injector} from '../di/injector';
import {NgModuleRef} from '../linker/ng_module_factory';
import {stringify} from '../util';
import {DepDef, DepFlags, NgModuleData, NgModuleDefinition, NgModuleProviderDef, NodeFlags} from './types';
import {splitDepsDsl, tokenKey} from './util';
@ -26,7 +25,7 @@ export function moduleProvideDef(
// lowered the expression and then stopped evaluating it,
// i.e. also didn't unwrap it.
value = resolveForwardRef(value);
const depDefs = splitDepsDsl(deps, stringify(token));
const depDefs = splitDepsDsl(deps);
return {
// will bet set by the module definition
index: -1,

View File

@ -12,7 +12,7 @@ import {ElementRef} from '../linker/element_ref';
import {TemplateRef} from '../linker/template_ref';
import {ViewContainerRef} from '../linker/view_container_ref';
import {Renderer as RendererV1, Renderer2} from '../render/api';
import {stringify} from '../util';
import {createChangeDetectorRef, createInjector, createRendererV1} from './refs';
import {BindingDef, BindingFlags, DepDef, DepFlags, NodeDef, NodeFlags, OutputDef, OutputType, ProviderData, QueryValueType, Services, ViewData, ViewFlags, ViewState, asElementData, asProviderData, shouldCallLifecycleInitHook} from './types';
import {calcBindingFlags, checkBinding, dispatchEvent, isComponentView, splitDepsDsl, splitMatchedQueriesDsl, tokenKey, viewParentEl} from './util';
@ -83,7 +83,7 @@ export function _def(
// i.e. also didn't unwrap it.
value = resolveForwardRef(value);
const depDefs = splitDepsDsl(deps, stringify(token));
const depDefs = splitDepsDsl(deps);
return {
// will bet set by the view definition

View File

@ -481,8 +481,6 @@ class NgModuleRef_ implements NgModuleData, InternalNgModuleRef<any> {
/** @internal */
_providers: any[];
readonly injector: Injector = this;
constructor(
private _moduleType: Type<any>, public _parent: Injector,
public _bootstrapComponents: Type<any>[], public _def: NgModuleDefinition) {
@ -498,6 +496,8 @@ class NgModuleRef_ implements NgModuleData, InternalNgModuleRef<any> {
get componentFactoryResolver() { return this.get(ComponentFactoryResolver); }
get injector(): Injector { return this; }
destroy(): void {
if (this._destroyed) {
throw new Error(

View File

@ -649,8 +649,9 @@ class DebugRendererFactory2 implements RendererFactory2 {
class DebugRenderer2 implements Renderer2 {
readonly data: {[key: string]: any};
constructor(private delegate: Renderer2) { this.data = this.delegate.data; }
constructor(private delegate: Renderer2) {}
get data() { return this.delegate.data; }
destroyNode(node: any) {
removeDebugNodeFromIndex(getDebugNode(node) !);

View File

@ -7,10 +7,10 @@
*/
import {WrappedValue, devModeEqual} from '../change_detection/change_detection';
import {SOURCE} from '../di/injector';
import {ViewEncapsulation} from '../metadata/view';
import {RendererType2} from '../render/api';
import {looseIdentical, stringify} from '../util';
import {expressionChangedAfterItHasBeenCheckedError} from './errors';
import {BindingDef, BindingFlags, Definition, DefinitionFactory, DepDef, DepFlags, ElementData, NodeDef, NodeFlags, QueryValueType, Services, ViewData, ViewDefinition, ViewDefinitionFactory, ViewFlags, ViewState, asElementData, asTextData} from './types';
@ -209,7 +209,7 @@ export function splitMatchedQueriesDsl(
return {matchedQueries, references, matchedQueryIds};
}
export function splitDepsDsl(deps: ([DepFlags, any] | any)[], sourceName?: string): DepDef[] {
export function splitDepsDsl(deps: ([DepFlags, any] | any)[]): DepDef[] {
return deps.map(value => {
let token: any;
let flags: DepFlags;
@ -219,9 +219,6 @@ export function splitDepsDsl(deps: ([DepFlags, any] | any)[], sourceName?: strin
flags = DepFlags.None;
token = value;
}
if (token && (typeof token === 'function' || typeof token === 'object') && sourceName) {
Object.defineProperty(token, SOURCE, {value: sourceName, configurable: true});
}
return {flags, token, tokenKey: tokenKey(token)};
});
}

View File

@ -255,45 +255,6 @@ export function main() {
]);
});
it('should allow a transition to use a function to determine what method to run', () => {
let valueToMatch = '';
const transitionFn =
(fromState: string, toState: string) => { return toState == valueToMatch; };
@Component({
selector: 'if-cmp',
template: '<div [@myAnimation]="exp"></div>',
animations: [
trigger('myAnimation', [transition(
transitionFn,
[style({opacity: 0}), animate(1234, style({opacity: 1}))])]),
]
})
class Cmp {
exp: any = '';
}
TestBed.configureTestingModule({declarations: [Cmp]});
const fixture = TestBed.createComponent(Cmp);
const cmp = fixture.componentInstance;
valueToMatch = cmp.exp = 'something';
fixture.detectChanges();
let players = getLog();
expect(players.length).toEqual(1);
let [p1] = players;
expect(p1.totalTime).toEqual(1234);
resetLog();
valueToMatch = 'something-else';
cmp.exp = 'this-wont-match';
fixture.detectChanges();
players = getLog();
expect(players.length).toEqual(0);
});
it('should allow a state value to be `0`', () => {
@Component({
selector: 'if-cmp',

View File

@ -2823,6 +2823,96 @@ export function main() {
expect(child.log).toEqual(['child-start', 'child-done']);
}));
it('should fire and synchronize the start/done callbacks on multiple blocked sub triggers',
fakeAsync(() => {
@Component({
selector: 'cmp',
animations: [
trigger(
'parent1',
[
transition(
'* => go, * => go-again',
[
style({opacity: 0}),
animate('1s', style({opacity: 1})),
]),
]),
trigger(
'parent2',
[
transition(
'* => go, * => go-again',
[
style({lineHeight: '0px'}),
animate('1s', style({lineHeight: '10px'})),
]),
]),
trigger(
'child1',
[
transition(
'* => go, * => go-again',
[
style({width: '0px'}),
animate('1s', style({width: '100px'})),
]),
]),
trigger(
'child2',
[
transition(
'* => go, * => go-again',
[
style({height: '0px'}),
animate('1s', style({height: '100px'})),
]),
]),
],
template: `
<div [@parent1]="parent1Exp" (@parent1.start)="track($event)"
[@parent2]="parent2Exp" (@parent2.start)="track($event)">
<div [@child1]="child1Exp" (@child1.start)="track($event)"
[@child2]="child2Exp" (@child2.start)="track($event)"></div>
</div>
`
})
class Cmp {
public parent1Exp = '';
public parent2Exp = '';
public child1Exp = '';
public child2Exp = '';
public log: string[] = [];
track(event: any) { this.log.push(`${event.triggerName}-${event.phaseName}`); }
}
TestBed.configureTestingModule({declarations: [Cmp]});
const engine = TestBed.get(ɵAnimationEngine);
const fixture = TestBed.createComponent(Cmp);
fixture.detectChanges();
flushMicrotasks();
const cmp = fixture.componentInstance;
cmp.log = [];
cmp.parent1Exp = 'go';
cmp.parent2Exp = 'go';
cmp.child1Exp = 'go';
cmp.child2Exp = 'go';
fixture.detectChanges();
flushMicrotasks();
expect(cmp.log).toEqual(
['parent1-start', 'parent2-start', 'child1-start', 'child2-start']);
cmp.parent1Exp = 'go-again';
cmp.parent2Exp = 'go-again';
cmp.child1Exp = 'go-again';
cmp.child2Exp = 'go-again';
fixture.detectChanges();
flushMicrotasks();
}));
it('should stretch the starting keyframe of a child animation queries are issued by the parent',
() => {
@Component({

View File

@ -147,8 +147,8 @@ export function main() {
expect(() => createAndGetRootNodes(compViewDef(rootElNodes)))
.toThrowError(
'StaticInjectorError(DynamicTestModule)[SomeService -> Dep]: \n' +
' StaticInjectorError(Platform: core)[SomeService -> Dep]: \n' +
'StaticInjectorError[Dep]: \n' +
' StaticInjectorError[Dep]: \n' +
' NullInjectorError: No provider for Dep!');
const nonRootElNodes = [
@ -161,8 +161,8 @@ export function main() {
expect(() => createAndGetRootNodes(compViewDef(nonRootElNodes)))
.toThrowError(
'StaticInjectorError(DynamicTestModule)[SomeService -> Dep]: \n' +
' StaticInjectorError(Platform: core)[SomeService -> Dep]: \n' +
'StaticInjectorError[Dep]: \n' +
' StaticInjectorError[Dep]: \n' +
' NullInjectorError: No provider for Dep!');
});
@ -186,8 +186,8 @@ export function main() {
directiveDef(1, NodeFlags.None, null, 0, SomeService, ['nonExistingDep'])
])))
.toThrowError(
'StaticInjectorError(DynamicTestModule)[nonExistingDep]: \n' +
' StaticInjectorError(Platform: core)[nonExistingDep]: \n' +
'StaticInjectorError[nonExistingDep]: \n' +
' StaticInjectorError[nonExistingDep]: \n' +
' NullInjectorError: No provider for nonExistingDep!');
});

View File

@ -355,12 +355,8 @@ export class TestBed implements Injector {
}
const ngZone = new NgZone({enableLongStackTrace: true});
const providers: StaticProvider[] = [{provide: NgZone, useValue: ngZone}];
const ngZoneInjector = Injector.create({
providers: providers,
parent: this.platform.injector,
name: this._moduleFactory.moduleType.name
});
const ngZoneInjector =
Injector.create([{provide: NgZone, useValue: ngZone}], this.platform.injector);
this._moduleRef = this._moduleFactory.create(ngZoneInjector);
// ApplicationInitStatus.runInitializers() is marked @internal to core. So casting to any
// before accessing it.

View File

@ -135,7 +135,7 @@ export function main() {
name = 'square';
}
const injector = Injector.create({providers: [{provide: Square, deps: []}]});
const injector = Injector.create([{provide: Square, deps: []}]);
const shape: Square = injector.get(Square);
expect(shape.name).toEqual('square');

View File

@ -49,10 +49,10 @@ export const COMPOSITION_BUFFER_MODE = new InjectionToken<boolean>('CompositionE
// https://github.com/angular/angular/issues/3011 is implemented
// selector: '[ngModel],[formControl],[formControlName]',
host: {
'(input)': '$any(this)._handleInput($event.target.value)',
'(input)': '_handleInput($event.target.value)',
'(blur)': 'onTouched()',
'(compositionstart)': '$any(this)._compositionStart()',
'(compositionend)': '$any(this)._compositionEnd($event.target.value)'
'(compositionstart)': '_compositionStart()',
'(compositionend)': '_compositionEnd($event.target.value)'
},
providers: [DEFAULT_VALUE_ACCESSOR]
})

View File

@ -253,7 +253,7 @@ export abstract class AbstractControl {
* Sets the async validators that are active on this control. Calling this
* will overwrite any existing async validators.
*/
setAsyncValidators(newValidator: AsyncValidatorFn|AsyncValidatorFn[]|null): void {
setAsyncValidators(newValidator: AsyncValidatorFn|AsyncValidatorFn[]): void {
this.asyncValidator = coerceToAsyncValidator(newValidator);
}

View File

@ -75,6 +75,8 @@ const EMAIL_REGEXP =
export class Validators {
/**
* Validator that requires controls to have a value greater than a number.
*`min()` exists only as a function, not as a directive. For example,
* `control = new FormControl('', Validators.min(3));`.
*/
static min(min: number): ValidatorFn {
return (control: AbstractControl): ValidationErrors | null => {
@ -90,6 +92,8 @@ export class Validators {
/**
* Validator that requires controls to have a value less than a number.
* `max()` exists only as a function, not as a directive. For example,
* `control = new FormControl('', Validators.max(15));`.
*/
static max(max: number): ValidatorFn {
return (control: AbstractControl): ValidationErrors | null => {

View File

@ -1,5 +1,5 @@
/**
* @license Angular v0.0.0-PLACEHOLDER
* (c) 2010-2017 Google, Inc. https://angular.io/
* (c) 2010-2018 Google, Inc. https://angular.io/
* License: MIT
*/

View File

@ -42,7 +42,6 @@ export class JitReflector implements CompileReflector {
hasLifecycleHook(type: any, lcProperty: string): boolean {
return this.reflectionCapabilities.hasLifecycleHook(type, lcProperty);
}
guards(type: any): {[key: string]: any} { return this.reflectionCapabilities.guards(type); }
resolveExternalReference(ref: ExternalReference): any {
return builtinExternalReferences.get(ref) || ref.runtime;
}

View File

@ -7,12 +7,12 @@
*/
import {isPlatformBrowser} from '@angular/common';
import {APP_INITIALIZER, CUSTOM_ELEMENTS_SCHEMA, Compiler, Component, Directive, ErrorHandler, Inject, Input, LOCALE_ID, NgModule, OnDestroy, PLATFORM_ID, PLATFORM_INITIALIZER, Pipe, Provider, StaticProvider, Type, VERSION, createPlatformFactory} from '@angular/core';
import {APP_INITIALIZER, CUSTOM_ELEMENTS_SCHEMA, Compiler, Component, Directive, ErrorHandler, Inject, Input, LOCALE_ID, NgModule, OnDestroy, PLATFORM_ID, PLATFORM_INITIALIZER, Pipe, Provider, StaticProvider, VERSION, createPlatformFactory, ɵstringify as stringify} from '@angular/core';
import {ApplicationRef, destroyPlatform} from '@angular/core/src/application_ref';
import {Console} from '@angular/core/src/console';
import {ComponentRef} from '@angular/core/src/linker/component_factory';
import {Testability, TestabilityRegistry} from '@angular/core/src/testability/testability';
import {AsyncTestCompleter, Log, afterEach, beforeEach, beforeEachProviders, describe, iit, inject, it} from '@angular/core/testing/src/testing_internal';
import {AsyncTestCompleter, Log, afterEach, beforeEach, beforeEachProviders, ddescribe, describe, iit, inject, it} from '@angular/core/testing/src/testing_internal';
import {BrowserModule} from '@angular/platform-browser';
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
@ -112,11 +112,10 @@ class DummyConsole implements Console {
class TestModule {}
function bootstrap(
cmpType: any, providers: Provider[] = [], platformProviders: StaticProvider[] = [],
imports: Type<any>[] = []): Promise<any> {
function bootstrap(cmpType: any, providers: Provider[] = [], platformProviders: StaticProvider[] = [
]): Promise<any> {
@NgModule({
imports: [BrowserModule, ...imports],
imports: [BrowserModule],
declarations: [cmpType],
bootstrap: [cmpType],
providers: providers,
@ -184,40 +183,6 @@ export function main() {
});
}));
it('should throw if no provider', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
const logger = new MockConsole();
const errorHandler = new ErrorHandler();
errorHandler._console = logger as any;
class IDontExist {}
@Component({selector: 'cmp', template: 'Cmp'})
class CustomCmp {
constructor(iDontExist: IDontExist) {}
}
@Component({
selector: 'hello-app',
template: '<cmp></cmp>',
})
class RootCmp {
}
@NgModule({declarations: [CustomCmp], exports: [CustomCmp]})
class CustomModule {
}
bootstrap(RootCmp, [{provide: ErrorHandler, useValue: errorHandler}], [], [
CustomModule
]).then(null, (e: Error) => {
expect(e.message).toContain(`StaticInjectorError(TestModule)[CustomCmp -> IDontExist]:
StaticInjectorError(Platform: core)[CustomCmp -> IDontExist]:
NullInjectorError: No provider for IDontExist!`);
async.done();
return null;
});
}));
if (getDOM().supportsDOMEvents()) {
it('should forward the error to promise when bootstrap fails',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {

View File

@ -1,6 +1,6 @@
The MIT License
Copyright (c) 2017 Google, Inc. http://angular.io
Copyright (c) 2017-2018 Google, Inc. http://angular.io
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -277,11 +277,11 @@ export type UrlMatchResult = {
* For instance, the following matcher matches html files.
*
* ```
* function htmlFiles(url: UrlSegment[]) {
* return url.length === 1 && url[0].path.endsWith('.html') ? ({consumed: url}) : null;
* export function htmlFiles(url: UrlSegment[]) {
* return url.length === 1 && url[0].path.endsWith('.html') ? ({consumed: url}) : null;
* }
*
* const routes = [{ matcher: htmlFiles, component: HtmlCmp }];
* export const routes = [{ matcher: htmlFiles, component: AnyComponent }];
* ```
*
* @experimental

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