Compare commits

..

197 Commits

Author SHA1 Message Date
65a40e659b docs: add changelog for 5.0.3 2017-11-22 13:09:12 -08:00
215832d8c6 release: cut the 5.0.3 release 2017-11-22 13:08:11 -08:00
686c4efe6d docs(aio): add ngATL header (#20590)
Fix #20568

PR Close #20590
2017-11-22 15:04:09 -06:00
efce39605b docs(aio): add a French onsite training ressource (#19889)
PR Close #19889
2017-11-22 10:49:12 -06:00
b567f9cc21 docs(aio): add a French onsite training ressource (#19889)
PR Close #19889
2017-11-22 10:49:12 -06:00
4ff60c3562 docs(aio): fix filename (#20569)
PR Close #20569
2017-11-22 10:48:57 -06:00
bc904b19a4 fix(common): return ISubscription from Location.subscribe() (#20429)
Fix #20406

PR Close #20429
2017-11-22 10:48:38 -06:00
135cf226bf ci: Update 1% payload size test (#20524)
PR Close #20524
2017-11-22 10:48:26 -06:00
0550383fc9 build(aio): filter out ambiguous directives from auto code linking (#20512)
Closes #20466

PR Close #20512
2017-11-22 10:48:19 -06:00
07699cbaec build(aio): do not store duplicate metadata aliases (#20512)
Having duplicates was causing the code auto-linking
to ignore `ngForm` directives.

PR Close #20512
2017-11-22 10:48:18 -06:00
e4bb077d27 build(aio): better parsing of selectors as aliases for directives/components (#20512)
PR Close #20512
2017-11-22 10:48:18 -06:00
27e7439c3b docs(aio): add angularfirebase.com to education resources (#20302)
PR Close #20302
2017-11-22 10:48:09 -06:00
66d160215e ci: update pullapprove (#20540)
PR Close #20540
2017-11-22 10:48:02 -06:00
0feba49c4b fix(core): fix #20532, should be able to cancel listener from mixed zone (#20538)
PR Close #20538
2017-11-22 10:47:53 -06:00
9ca6ee9eed fix(benchpress): Allow ignoring navigationStart events in perflog metric. (#20312)
PR Close #20312
2017-11-22 10:46:34 -06:00
a5a82296b7 docs(aio): fix typo in Attribute Directives documentation (#20143)
changed "appHightlight" to "appHighlight"

PR Close #20143
2017-11-22 10:45:41 -06:00
f9f2c20a57 fix(forms): updateOn should check if change occurred (#20358)
Fixes #20259.

PR Close #20358
2017-11-22 10:45:22 -06:00
662422a67e docs: NgModule guide prose for CLI (partial) (#19776)
Also replaces “Angular Module” with “NgModule” wherever that is clarifying.
Continue using “module” when qualified as in “feature module”, “root module”, “routing module”, etc.

PR Close #19776
2017-11-22 10:44:58 -06:00
b53ead4c45 fix(compiler): support event bindings in fullTemplateTypeCheck (#20490)
The type-check block now disables type checking event access instead
of generating a reference to an undefined variable.

PR Close #20490
2017-11-21 10:47:08 -06:00
d0abfa3acc docs: update the triaging doc with the latest process (#20128)
PR Close #20128
2017-11-21 10:43:28 -06:00
3bf36e9492 docs: add description for target labels + add LTS target label (#20128)
PR Close #20128
2017-11-21 10:43:28 -06:00
82aace63ea fix(core): should support event.stopImmediatePropagation (#20469)
PR Close #20469
2017-11-17 18:19:34 -06:00
15795d09cf fix(animations): validate against trigger() names that use @ symbols (#20326)
PR Close #20326
2017-11-17 18:19:28 -06:00
8ddbed8f7b build(aio): tighten up code autolinking (#20468)
Do not match code "words" that are part of a hyphenated
string of characters: e.g. `platform-browser-dynamic` should
not auto-link `browser`.

Do not match code "words" that correspond to pipe names
but are not preceded by a pipe `|` character. E.g. `package.json` should
not auto link `json` to the `JsonPipe`.

Closes #20187

PR Close #20468
2017-11-17 18:19:22 -06:00
81f1d42328 fix(compiler): emit correct type-check-blocks with TemplateRef's (#20463)
The type-check block generated with `"fullTemplateTypeCheck"` was
invalid if the it contained a template ref as would be generated
using the `else` micro-syntax of `NgIf`.

Fixes: #19485

PR Close #20463
2017-11-17 18:19:13 -06:00
3df1542c87 docs(aio): fix a typo to improve readability (#20435)
Remove a comma and space

PR Close #20435
2017-11-17 18:19:06 -06:00
8e1e7faef4 docs(aio): Clearing array with [] (#20369) (#20395)
Convert remaining references to directly use LoggerServices logs.

PR Close #20395
2017-11-17 18:18:59 -06:00
27f8c69d8a docs(aio): Removing reference to LoggerService property (#20369) (#20395)
The reference removed so that calling LoggerService clear() method
behaves as intended in SpyComponent.

PR Close #20395
2017-11-17 18:18:59 -06:00
5d0dd97402 docs(aio): Clearing array with [] (#20369) (#20395)
Clearing array with setting length to 0 replaced with [] for being short
and marginally efficient. For reference: [] is turned into a sequence of
around 15 machine instructions on x64 (if bump pointer allocation succeeds),
whereas a.length=0 is a C++ runtime function call, which requires 10-100x as
many instructions.
Benedikt Meurer

PR Close #20395
2017-11-17 18:18:59 -06:00
814f06289b fix(animations): always fire inner trigger callbacks even if blocked by parent animations (#19753)
Closes #19100

PR Close #19753
2017-11-17 18:17:46 -06:00
b1f8eb14c8 docs: add changelog for 5.0.2 2017-11-16 11:24:02 -08:00
f983d1cc50 release: cut the 5.0.2 release 2017-11-16 11:20:49 -08:00
12857922c5 fix(aio): fix window title on Home page (#20440)
Using `display: none` on the `<h1>` causes `innerText` to not work as expected
and include the icon ligature (`link`) in the title. This caused the window
title on the angular.io Home page to appear as "Angular - link".
This commit fixes it by not generating anchors at all for headings with the
`no-anchor` class.

Fixes #20427

PR Close #20440
2017-11-15 22:26:20 -06:00
dbdf9f76be docs(aio): add missing closing backtick (#20446)
PR Close #20446
2017-11-15 22:26:12 -06:00
d5eaf4de3c Revert "fix(animations): always fire inner trigger callbacks even if blocked by parent animations (#19753)"
This reverts commit bc4b4b5b55.
2017-11-15 22:25:30 -06:00
2d6126ec1b style(core): fix comment format for linter 2017-11-15 11:51:56 -08:00
259f6bf638 style(core): fix max line length to pass linting (#20441)
Accidentally introduced in #19920, where other linting errors (unrelated to the
PR) prevented proper linting.

PR Close #20441
2017-11-15 11:45:02 -08:00
03d549be05 Revert "fix(core): should support event.stopImmediatePropagation"
This reverts commit 5e0eb5e3d94bd7077c4d6657b89bfc8d900f2bc6.
2017-11-15 11:35:52 -08:00
bc4b4b5b55 fix(animations): always fire inner trigger callbacks even if blocked by parent animations (#19753)
Closes #19100

PR Close #19753
2017-11-14 16:00:01 -08:00
00f2055c59 docs(aio): fix wrong copy (#20431)
PR Close #20431
2017-11-14 15:59:57 -08:00
91efc7f70b docs(core): change from deprecated renderer to renderer2 (#19920)
We now show the proper class instead of the deprecated Renderer

Fixes #19806


PR Close #19920
2017-11-14 13:45:04 -08:00
8b1a6b1f24 fix(animations): ensure final state() styles are applied within @.disabled animations (#20267)
Closes #20266

PR Close #20267
2017-11-14 12:13:38 -08:00
b732fb935b fix(router): 'merge' queryParamHandling strategy should be able to remove query params (#19733)
Closes #18463, #17202

PR Close #19733
2017-11-14 12:13:30 -08:00
0e2d962acb ci: tighten package limits (#20364)
PR Close #20364
2017-11-14 12:13:22 -08:00
7acbc19b94 docs(aio): fix broken link in guide/component-interaction (#20411)
add a blank line before line with markdown link
PR Close #20411
2017-11-14 10:03:24 -08:00
c69eda8f60 docs(aio): make it clear we are talking about <a> tags (#20410)
As is, it could be seen as a typo at first glance. Wrapping the "a" in carets and backticks for formatting adds some clarity.

PR Close #20410
2017-11-14 10:03:21 -08:00
210ff78f4d docs(aio): fix typo in filename (packages.json --> package.json) (#20377)
PR Close #20377
2017-11-14 10:03:17 -08:00
96766f7336 docs(aio): fix not found schema (#20347)
Fixes #20338

PR Close #20347
2017-11-14 10:03:14 -08:00
52b50c4b6c docs(aio): fix rxjs import (#20350)
closes #20349

PR Close #20350
2017-11-14 10:02:08 -08:00
398690d47c docs: Dependency Injection guides for CLI (#19892)
PR Close #19892
2017-11-14 10:02:05 -08:00
dc01fb167b docs(aio): update template forms to CLI (#20014)
PR Close #20014
2017-11-14 10:02:02 -08:00
7c26c06495 docs(aio): update reactive-forms to CLI (#20019)
PR Close #20019
2017-11-14 10:01:59 -08:00
82dc7fa628 docs(aio): update displaying-data for CLI (#19574)
PR Close #19574
2017-11-14 10:01:56 -08:00
3101e89cf5 docs(aio): update glossary for CLI (#20017)
PR Close #20017
2017-11-14 10:01:53 -08:00
79c3e1b968 docs(aio): update ajs-quick-reference for CLI (#19552)
PR Close #19552
2017-11-14 10:01:49 -08:00
c96967b235 docs(aio): remove trailing underscore from provide_ (#20356)
_provide_ was already emphasized in the previous paragraph

PR Close #20356
2017-11-14 10:01:06 -08:00
422cd0b665 docs(aio): fix missed grave accent (#20379)
PR Close #20379
2017-11-14 10:01:03 -08:00
eea2039bce docs: AttributeDirectives guide for CLI (#19771)
PR Close #19771
2017-11-14 10:01:00 -08:00
612f508dff refactor(animations): uses a loop instead Array.map() which creates and (#19910)
returns a new array that is discarded.

This pattern will become a compilation error in google3.

PR Close #19910
2017-11-10 13:54:20 -08:00
aa3d75ba83 build: update to google-closure-compiler@20171023.0.1 (#20321)
added externs

remove externs

PR Close #20321
2017-11-10 11:53:21 -08:00
4cc6abbbf8 fix(compiler): recognize @NgModule with a redundant @Injectable (#20320)
The compiler now, again, recognizes `@NgModule()` decorators on
classes with a redundant `@Injectable()` decorator.

Fixes: #19544

PR Close #20320
2017-11-10 11:53:17 -08:00
222758bed3 fix(aio): markdown typo in Tour of Heroes tutorial (#20288)
PR Close #20288
2017-11-10 11:53:13 -08:00
516107fd04 docs(common): update default display value for CurrencyPipe (#20246)
PR Close #20246
2017-11-10 11:53:09 -08:00
bd70aece52 refactor(core): remove prolyfill from error message (#20121)
PR Close #20121
2017-11-10 11:53:03 -08:00
2ca6bdd110 docs(aio): typo fix (#20318)
tutorial part 0 app component template file extention fix

PR Close #20318
2017-11-10 11:12:18 -08:00
2aefac841f docs(aio): empty line between HTML tag and content (#20341)
PR Close #20341
2017-11-10 11:09:35 -08:00
ec496c2fda docs(aio): fix typo (#20103)
PR Close #20103
2017-11-10 11:09:27 -08:00
346dbcf24a docs(aio): show correct path for mock-heroes code (#20323)
PR Close #20323
2017-11-10 11:09:23 -08:00
48843a9f47 docs(aio): Fix typo in tutorial (#20295)
PR Close #20295
2017-11-10 11:09:05 -08:00
8f2fb02048 docs(aio): fix toh-pt3 typos (#20307)
PR Close #20307
2017-11-10 11:08:54 -08:00
89e4262188 docs(aio): fix -mm- to -MM- for month in DatePipe (#20315)
PR Close #20315
2017-11-10 11:08:43 -08:00
424a323316 fix(compiler): show explanatory text in template errors (#20313)
Fixes: #20076

PR Close #20313
2017-11-09 15:48:58 -08:00
28985cb2de test(compiler): do not use a as a content selector
As it might trigger false positive in the RegExp from `_makeScopeMatcher`

closes #20256
2017-11-08 15:53:13 -08:00
5d1cd57787 fix(compiler): fix corner cases in shadow CSS
`cmp:host {}` and `cmp:host some-other-selector {}` were not handled
consistently.

Note those should not match anything but are made equivalent to respectively
`:host(cmp)` and `:host(cmp) some-other-selector` to avoid breaking legacy apps.
2017-11-08 15:53:05 -08:00
9de45fa650 docs: add changelog for 5.0.1 2017-11-08 10:29:46 -08:00
953a0e07d6 release: cut the 5.0.1 version 2017-11-08 10:28:13 -08:00
511e56d633 docs(common): fix mis-ordered lines (#20221) 2017-11-06 11:29:12 -08:00
1f1741c5ad build(aio): upgrade to @anglar/core@5.0.0 and cli@1.5.0
-rw-r--r--  1 iminar  eng   14880 Nov  4 11:54
dist/0.b19e913fbdd6507d346b.chunk.js
-rw-r--r--  1 iminar  eng    1533 Nov  4 11:54
dist/inline.9183bfe0d60f43b6a772.bundle.js
-rw-r--r--  1 iminar  eng  486476 Nov  4 11:54
dist/main.f5445f99490330207c9c.bundle.js
-rw-r--r--  1 iminar  eng   37070 Nov  4 11:54
dist/polyfills.0dfca732c5a075c110d0.bundle.js

Closes #20184
2017-11-06 10:05:23 -08:00
408ffb634e build(aio): remove the build-optimizer flag
it's on by default now.
2017-11-06 10:05:23 -08:00
73d857cb38 build(aio): use aot compiler for development
since it was not turned on by default in the cli we
have to opt in.
2017-11-06 10:05:23 -08:00
3ab0963309 docs(aio): update ToH for CLI (#19811) 2017-11-06 10:02:40 -08:00
da22c48ef1 fix(compiler): report a reasonable error with invalid metadata (#20062)
The compiler would throw an internal exception if an import using
the `ngModule` syntax and the module as not a resolvable symbol.

Fixes: #20049
2017-11-06 10:01:49 -08:00
f80d41f3e5 fix(aio): style correctly on Safari (#20157) 2017-11-06 10:00:57 -08:00
2b7ca4e9f8 ci(aio): move e2e tests to optional job (#20178) 2017-11-06 10:00:23 -08:00
4292540939 docs(aio): fixed case-typo for code (#20196) 2017-11-06 09:59:38 -08:00
708379128f fix(core): should support event.stopImmediatePropagation (#19222) 2017-11-03 15:22:43 -07:00
131368c774 docs(aio): update pipes for CLI (#19553) 2017-11-03 15:21:41 -07:00
94e0ef77ea ci(aio): Add payload size percentage changes check to payload size task (#19908) 2017-11-03 15:20:49 -07:00
e4cd3b0564 test(aio): make e2e tests less flakey
closes #20117
2017-11-03 11:24:04 -07:00
22dc3ad94c build(aio): upgrade protractor to v5.2.0 2017-11-03 11:23:55 -07:00
7077a61614 build(aio): use correct types for e2e tests 2017-11-03 11:23:45 -07:00
9811bef278 docs: Bootstrapping guide prose for CLI (#19777) 2017-11-03 11:13:41 -07:00
3298c4a79f docs: Component Styles guide for CLI (#19791) 2017-11-03 11:12:58 -07:00
5a6efa7a3f fix(platform-browser): support Symbols in custom jasmineToString() method (#19794)
It's illegal to coerce a Symbol to a string, and results in a TypeError:

TypeError: Cannot convert a Symbol value to a string

Previously, the custom jasmineToString() method monkey-patched onto Maps
in platform-browser/testing/src/matchers.ts would coerce keys and values
to strings. A change in a newer version of Jasmine calls this method more
often, resulting in calls against Maps which contain Symbols in some
applications, which causes crashes.

The fix is to explicitly convert keys and values to strings, which does
work on Symbols.
2017-11-03 11:12:09 -07:00
a8c786c8c9 docs: Deployment guide for CLI (#19839) 2017-11-03 11:11:16 -07:00
799cbb932c fix(compiler): don't overwrite missingTranslation's value in JIT (#19952) 2017-11-03 11:09:07 -07:00
e6f16a7629 docs(aio): Fix typo in Architecture Overview. (#20073) 2017-11-03 11:00:44 -07:00
1bb0333c23 docs(aio): Add v4 doc link to navigation (#20089)
Fixes #20090
2017-11-03 10:59:48 -07:00
9fa0ffd8a5 build(aio): make plunker works with rxjs operators (#20124) 2017-11-03 10:48:08 -07:00
678d1cfae1 fix(core): __symbol__ should return __zone_symbol__ without zone.js loaded (#19541) 2017-11-02 16:06:29 -07:00
a897d6842f build: update Windows symlink scripts (#16761)
Fixes packages\upgrade\static\src symlink.

Closes #16760
2017-11-02 16:05:38 -07:00
25843fed53 build(aio): avoid building before running the local PWA tests
When this command is run on CI, `yarn build` has already been run, so
this was unnecessarily building angular.io again (adding ~4mins to the
`aio` job).
When this command is run locally, it is most often about testing a new
`lighthouse` version/config, so you don't need to build angular.io over
and over (and if necessary, one can always run `yarn build` manually).

Closes #19633
2017-11-02 16:04:30 -07:00
762da3b154 build(aio): upgrade lighthouse to v2.5.0 2017-11-02 16:04:19 -07:00
37a740b5b2 build: remove local yarn (#19981)
We use the globally installed yarn now. The local yarn was used in
`check-environment.js` only, which results in the `--integrity` check
always failing (if dependencies were installed with the global yarn).
2017-11-02 15:30:57 -07:00
067e926c08 build(aio): do not fail the initial doc-gen when running docs-watch
Checks that cause the doc-gen to fail were already disabled in `docs-watch`
for the doc-gen that runs when a file is changed.
Now these checks are also disabled for the initial doc-gen run.
closes #20038
2017-11-02 15:06:23 -07:00
bc52e97eba build(aio): do not fail on bad examples when running docs-watch 2017-11-02 15:06:23 -07:00
9b579d85be build(aio): allow render-examples to complete even if examples are broken
By setting `renderExamples.ignoreBrokenExamples = true` the doc-gen will
not fail if there is something wrong with an example. Instead it will
just log a warning.
2017-11-02 15:05:57 -07:00
895d78c0ed docs(aio): fix badly formatted code-examples
closes #19970
2017-11-02 15:05:44 -07:00
803b0f0fb3 build(aio): fail doc-gen if a code-example is badly formatted.
This will catch the problem that was missed in
https://github.com/angular/angular/pull/19845#issuecomment-338626662
2017-11-02 15:05:28 -07:00
86399958dd fix(compiler-cli): don't report emit diagnostics when --noEmitOnError is off (#20063) 2017-11-02 14:53:01 -07:00
d550b6872a docs: fix changelog for v5 (#20097) 2017-11-02 14:42:46 -07:00
92e4c34d01 docs: Add 0 in padding of 'dd' (#20107) 2017-11-02 14:42:34 -07:00
e84695389b docs: AOT guide for CLI #19510 (#19818) 2017-11-02 14:35:35 -07:00
4e48bdff22 docs: BrowserSupport guide for CLI (#19843) 2017-11-02 14:33:44 -07:00
2185e466db docs: Npm Packages guide for CLI (#19850) 2017-11-02 14:28:23 -07:00
6f05dab2fc docs(aio): updated i18n guide and example (#19975) 2017-11-02 14:23:04 -07:00
18197bd56d docs(aio): fix linting for universal (#20086)
PR Close #20086
2017-11-02 00:51:55 +01:00
c75740e585 build(aio): update lockfile for examples (#20084)
Installing dependencies for the docs examples fails, because the
lockfile is out-of-sync with the corresponding `package.json`.
This commit brings the lockfile in sync with `package.json`.

(For reference, this was accidentally broken in #20039.)

PR Close #20084
2017-11-02 00:22:22 +01:00
16d72584cb build(aio): upgrade to @angular/material@2.0.0-beta.12 (#19702)
-rw-r--r--  1 iminar  eng   14880 Nov  1 12:25 dist/0.b19e913fbdd6507d346b.chunk.js
-rw-r--r--  1 iminar  eng    1533 Nov  1 12:25 dist/inline.2826385ad3e299c6d1c1.bundle.js
-rw-r--r--  1 iminar  eng  486476 Nov  1 12:25 dist/main.f0610805f4aad19da4be.bundle.js
-rw-r--r--  1 iminar  eng   37070 Nov  1 12:25 dist/polyfills.0dfca732c5a075c110d0.bundle.js

PR Close #19702
2017-11-01 15:27:00 -07:00
9c9867e840 build(aio): upgrade to @angular/core@5.0.0-rc.9 (#19702)
build fails - material upgrade required

PR Close #19702
2017-11-01 15:26:59 -07:00
55092ace87 revert: build(aio): remove cli patches (#19702)
This reverts commit f0d530b4de38f71c759e42afc8f3d7531eb1b1fb.

cli rc.8 reintroduces the node polyfill which causes size regression,
so I'm putting the patch back in.

-rw-r--r--  1 iminar  eng   14880 Nov  1 12:11 dist/0.b19e913fbdd6507d346b.chunk.js
-rw-r--r--  1 iminar  eng    1533 Nov  1 12:11 dist/inline.25600c3b48de18b97581.bundle.js
-rw-r--r--  1 iminar  eng  486476 Nov  1 12:11 dist/main.d1292a34401056535884.bundle.js
-rw-r--r--  1 iminar  eng   37070 Nov  1 12:11 dist/polyfills.0dfca732c5a075c110d0.bundle.js

PR Close #19702
2017-11-01 15:26:59 -07:00
70edca3cec build(aio): upgrade to @angular/cli@1.5.0-rc.8 (#19702)
-rw-r--r--  1 iminar  eng   14880 Nov  1 11:57 dist/0.b19e913fbdd6507d346b.chunk.js
-rw-r--r--  1 iminar  eng    1533 Nov  1 11:57 dist/inline.3574d1d784c09c507dbd.bundle.js
-rw-r--r--  1 iminar  eng  497812 Nov  1 11:57 dist/main.76bbb69df79eaefef54c.bundle.js
-rw-r--r--  1 iminar  eng   37259 Nov  1 11:57 dist/polyfills.fdb71956ccd13330fb47.bundle.js

PR Close #19702
2017-11-01 15:26:58 -07:00
120ebe8225 build(aio): upgrade to @angular/cli@1.5.0-rc.6 (#19702)
-rw-r--r--  1 iminar  eng   14880 Oct 30 11:29 dist/0.b19e913fbdd6507d346b.chunk.js
-rw-r--r--  1 iminar  eng    1533 Oct 30 11:29 dist/inline.25600c3b48de18b97581.bundle.js
-rw-r--r--  1 iminar  eng  486476 Oct 30 11:29 dist/main.d1292a34401056535884.bundle.js
-rw-r--r--  1 iminar  eng   37070 Oct 30 11:29 dist/polyfills.0dfca732c5a075c110d0.bundle.js

PR Close #19702
2017-11-01 15:26:58 -07:00
7695ad570b ci(aio): decrease payload size limit for main file (#19702)
PR Close #19702
2017-11-01 15:26:58 -07:00
7a708ad387 refactor(aio): rename CustomMdIconRegistry to CustomIconRegistry (#19702)
The change of Angular Material version means that the `md` prefix is
no longer appropriate.

PR Close #19702
2017-11-01 15:26:57 -07:00
71f1ed5795 build(aio): lock zone.js to 0.8.16 (#19702)
Later versions (before 0.8.19) had a size increase.

PR Close #19702
2017-11-01 15:26:57 -07:00
ced5186ca4 style(aio): fix docs linting issues (#19702)
These issues appeared after upgrade of eslint jasmine plugin

PR Close #19702
2017-11-01 15:26:56 -07:00
e48dc270b5 ci(aio): increase payload size limit for polyfills.ts (#19702)
The latest builds have added ~2kB to the size of this file (500 bytes zipped).

PR Close #19702
2017-11-01 15:26:56 -07:00
aa574710c9 build(aio): remove hack to modify CLI version (#19702)
PR Close #19702
2017-11-01 15:26:55 -07:00
d62ef132d2 build(aio): upgrade to Angular@rc.5 and CLI@rc.3 (#19702)
PR Close #19702
2017-11-01 15:26:55 -07:00
428f80e8ae build(aio): revert temporary increase in size limit (#19702)
PR Close #19702
2017-11-01 15:26:55 -07:00
260c9b763c build(aio): fix tests to work with @angular/{material,cdk}@2.0.0-beta.12 (#19702)
PR Close #19702
2017-11-01 15:26:54 -07:00
5f6d71d39a build(aio): remove cli patches (#19702)
PR Close #19702
2017-11-01 15:26:54 -07:00
8133a8d335 build(aio): revert to clean CLI test.ts file (#19702)
The use of `System.import()` in test.ts was causing the webpack build to fail
with a mysterious "Module build failed: Error: TypeScript compilation failed" error,
when running `yarn test`.

PR Close #19702
2017-11-01 15:26:53 -07:00
3e05d62a99 build(aio): temporarily increaze the size limit until the regressions are fixed (#19702)
related issues:
https://github.com/angular/angular/issues/19857
https://github.com/angular/devkit/pull/231

PR Close #19702
2017-11-01 15:26:53 -07:00
db7f2a9ca7 build(aio): disable 'global' support in webpack (#19702)
This will be fixed in CLI once https://github.com/angular/angular-cli/pull/8130 lands.

-rw-r--r--  1 iminar  eng   14942 Oct 20 22:23 dist/0.b19e913fbdd6507d346b.chunk.js
-rw-r--r--  1 iminar  eng    1535 Oct 20 22:23 dist/inline.5d66b81ec9e01af9d28d.bundle.js
-rw-r--r--  1 iminar  eng  528395 Oct 20 22:23 dist/main.e36bb99245ca52ae546f.bundle.js
-rw-r--r--  1 iminar  eng   37205 Oct 20 22:23 dist/polyfills.0dfca732c5a075c110d0.bundle.js

PR Close #19702
2017-11-01 15:26:53 -07:00
59a2fbe74f build(aio): upgrade to build-optimizer@0.0.29 (#19702)
-rw-r--r--  1 iminar  eng   14942 Oct 20 22:16 dist/0.b19e913fbdd6507d346b.chunk.js
-rw-r--r--  1 iminar  eng    1535 Oct 20 22:16 dist/inline.68ebcf831dc9c905804f.bundle.js
-rw-r--r--  1 iminar  eng  541291 Oct 20 22:16 dist/main.5ec6fb5f95fc0433d822.bundle.js
-rw-r--r--  1 iminar  eng   37402 Oct 20 22:16 dist/polyfills.f8409a9eb69060ac1aa6.bundle.js

PR Close #19702
2017-11-01 15:26:52 -07:00
3274e1a79a build(aio): upgrade to @angular/cli@1.5.0-rc.2 (#19702)
-rw-r--r--  1 iminar  eng   84219 Oct 19 21:37 dist/0.0f327734d18211139822.chunk.js
-rw-r--r--  1 iminar  eng   14942 Oct 19 21:37 dist/4.c719ac5645940382cdce.chunk.js
-rw-r--r--  1 iminar  eng    1560 Oct 19 21:37 dist/inline.887757679ff553e20b54.bundle.js
-rw-r--r--  1 iminar  eng  492354 Oct 19 21:37 dist/main.5e5dc9ed980c9f5dc2bd.bundle.js
-rw-r--r--  1 iminar  eng   37402 Oct 19 21:37 dist/polyfills.f8409a9eb69060ac1aa6.bundle.js

PR Close #19702
2017-11-01 15:26:52 -07:00
6979a29d1f build(aio): upgrade to @angular/cli@1.5.0-rc.1 (#19702)
-rw-r--r--  1 iminar  eng   84219 Oct 18 21:05 dist/0.0f327734d18211139822.chunk.js
-rw-r--r--  1 iminar  eng   14942 Oct 18 21:05 dist/4.c719ac5645940382cdce.chunk.js
-rw-r--r--  1 iminar  eng    1560 Oct 18 21:05 dist/inline.887757679ff553e20b54.bundle.js
-rw-r--r--  1 iminar  eng  492354 Oct 18 21:05 dist/main.5e5dc9ed980c9f5dc2bd.bundle.js
-rw-r--r--  1 iminar  eng   37402 Oct 18 21:05 dist/polyfills.f8409a9eb69060ac1aa6.bundle.js

PR Close #19702
2017-11-01 15:26:51 -07:00
9da5ca7ae6 build(aio): upgrade to rxjs@5.5.0 (#19702)
-rw-r--r--  1 iminar  eng   84219 Oct 18 09:13 dist/0.8ef208c27531d5c6af63.chunk.js
-rw-r--r--  1 iminar  eng   14942 Oct 18 09:13 dist/4.c719ac5645940382cdce.chunk.js
-rw-r--r--  1 iminar  eng    1560 Oct 18 09:13 dist/inline.adc367eb50c706f3fd04.bundle.js
-rw-r--r--  1 iminar  eng  492354 Oct 18 09:13 dist/main.b9d9549455c74aff1480.bundle.js
-rw-r--r--  1 iminar  eng   37402 Oct 18 09:13 dist/polyfills.f8409a9eb69060ac1aa6.bundle.js

PR Close #19702
2017-11-01 15:26:51 -07:00
e51ac3671f build(aio): turn off preserveWhitespaces in compiler options (#19702)
-rw-r--r--  1 iminar  eng   14942 Oct 13 16:12 dist/0.b19e913fbdd6507d346b.chunk.js
-rw-r--r--  1 iminar  eng    1535 Oct 13 16:12 dist/inline.eede8140efeab4c45b22.bundle.js
-rw-r--r--  1 iminar  eng  559389 Oct 13 16:12 dist/main.20858f9aa7cf8741b6aa.bundle.js
-rw-r--r--  1 iminar  eng   37402 Oct 13 16:12 dist/polyfills.f8409a9eb69060ac1aa6.bundle.js

PR Close #19702
2017-11-01 15:26:50 -07:00
3393009b69 build(aio): patch @angular/cli to use esm builds of rxjs (#19702)
-rw-r--r--  1 iminar  eng   14942 Oct 13 14:52 dist/0.b19e913fbdd6507d346b.chunk.js
-rw-r--r--  1 iminar  eng    1535 Oct 13 14:52 dist/inline.6ca24f1c3b848103b041.bundle.js
-rw-r--r--  1 iminar  eng  567802 Oct 13 14:52 dist/main.c8183a2c0116782ca366.bundle.js
-rw-r--r--  1 iminar  eng   37402 Oct 13 14:52 dist/polyfills.f8409a9eb69060ac1aa6.bundle.js

PR Close #19702
2017-11-01 15:26:50 -07:00
12e4b5667e build(aio): upgrade to rxjs@5.5.0-beta.7 (#19702)
-rw-r--r--  1 iminar  eng   14942 Oct 13 14:30 dist/0.b19e913fbdd6507d346b.chunk.js
-rw-r--r--  1 iminar  eng    1535 Oct 13 14:30 dist/inline.702d6ff5146ddc373f05.bundle.js
-rw-r--r--  1 iminar  eng  588943 Oct 13 14:30 dist/main.64c96d55a10c56cfd6cd.bundle.js
-rw-r--r--  1 iminar  eng   37402 Oct 13 14:30 dist/polyfills.f8409a9eb69060ac1aa6.bundle.js

PR Close #19702
2017-11-01 15:26:50 -07:00
0f8b83200a build(aio): upgrade to @angular/{material,cdk}@2.0.0-beta.12 (#19702)
-rw-r--r--  1 iminar  eng   14942 Oct 13 13:35 dist/0.b19e913fbdd6507d346b.chunk.js
-rw-r--r--  1 iminar  eng    1535 Oct 13 13:35 dist/inline.f005f1bd6803b72f5961.bundle.js
-rw-r--r--  1 iminar  eng  582527 Oct 13 13:35 dist/main.b9ef1abb785be8de15b8.bundle.js
-rw-r--r--  1 iminar  eng   37402 Oct 13 13:35 dist/polyfills.f8409a9eb69060ac1aa6.bundle.js

PR Close #19702
2017-11-01 15:26:49 -07:00
253e89dfac fix(aio): hand fix the renaming md->mat issues (#19702)
These are changes that the mat-switcher missed and I had to make them by hand.

PR Close #19702
2017-11-01 15:26:49 -07:00
c4772ee002 build(aio): upgrade to @angular/{material,cdk}@2.0.0-beta.11 + md->mat migration (#19702)
all the non-npm changes were made by the angular-material-prefix-updater tool.

the tool missed a few things, which I'll fix in a separate commit to preserve the diff.

-rw-r--r--  1 iminar  eng   14942 Oct 13 13:09 dist/0.b19e913fbdd6507d346b.chunk.js
-rw-r--r--  1 iminar  eng    1535 Oct 13 13:09 dist/inline.0592c25ceb544d6aca3d.bundle.js
-rw-r--r--  1 iminar  eng  578250 Oct 13 13:09 dist/main.45d4edca3facc6d621e7.bundle.js
-rw-r--r--  1 iminar  eng   37402 Oct 13 13:09 dist/polyfills.f8409a9eb69060ac1aa6.bundle.js

PR Close #19702
2017-11-01 15:26:48 -07:00
35ec4af2b1 build(aio): upgrade to @angular/cli@1.5.0-rc.0 and typescript@2.5.3 (#19702)
the size regression has gotten worse:

-rw-r--r--  1 iminar  eng   14942 Oct 13 12:24 dist/0.b19e913fbdd6507d346b.chunk.js
-rw-r--r--  1 iminar  eng    1535 Oct 13 12:24 dist/inline.41e701c562960ede8ef5.bundle.js
-rw-r--r--  1 iminar  eng  865780 Oct 13 12:24 dist/main.6c4c605d461870b9c2d7.bundle.js
-rw-r--r--  1 iminar  eng   37402 Oct 13 12:24 dist/polyfills.f8409a9eb69060ac1aa6.bundle.js

PR Close #19702
2017-11-01 15:26:48 -07:00
19b48429ef build(aio): upgrade to @angular/cli@1.4.7 (#19702)
this causes the size regression to get only worse:

-rw-r--r--  1 iminar  eng   14942 Oct 13 10:37 dist/0.b19e913fbdd6507d346b.chunk.js
-rw-r--r--  1 iminar  eng    1535 Oct 13 10:37 dist/inline.3cc964095cb25e329dc0.bundle.js
-rw-r--r--  1 iminar  eng  846141 Oct 13 10:37 dist/main.5eb64df77b2877327a16.bundle.js
-rw-r--r--  1 iminar  eng   37402 Oct 13 10:37 dist/polyfills.965a9a5ad3e11b17f85e.bundle.js

PR Close #19702
2017-11-01 15:26:47 -07:00
b796419e7e build(aio): update to @angular/core@5.0.0-rc.2 (#19702)
there is a size regression right now because the CLI is out of date:

-rw-r--r--  1 iminar  eng   14942 Oct 13 10:23 dist/0.b19e913fbdd6507d346b.chunk.js
-rw-r--r--  1 iminar  eng    1535 Oct 13 10:23 dist/inline.812a4af83ecce165c71c.bundle.js
-rw-r--r--  1 iminar  eng  643481 Oct 13 10:23 dist/main.74550bb35f9f5a57e78a.bundle.js
-rw-r--r--  1 iminar  eng   37402 Oct 13 10:23 dist/polyfills.965a9a5ad3e11b17f85e.bundle.js

PR Close #19702
2017-11-01 15:26:47 -07:00
a1ec65b1dd docs(aio): fix typo in attribute-directives
Closes #20071
2017-11-01 15:21:40 -07:00
851e1cfcfd docs(aio): update universal for CLI
PR Close #20039
2017-11-01 15:19:33 -07:00
a363be6b5c docs(aio): upgrade to v5 and cli 1.5
PR Close #20077
2017-11-01 14:14:38 -07:00
e1fb65cac4 docs(packaging): fix typo
PR Close #18915
2017-11-01 16:55:41 -04:00
b497e9e6ee fix(docs): Fix 404 on amcdnl image
PR Close #19120
2017-11-01 16:55:36 -04:00
706ba38498 docs: fix link texts
Fixes #19701

PR Close #19709
2017-11-01 16:55:25 -04:00
78052e4984 docs(aio): update AngularJS Quick Reference guide
PR Close #19939
2017-11-01 16:55:17 -04:00
bf861f5539 docs(aio): fix typo
PR Close #20029
2017-11-01 16:55:09 -04:00
d99a5ec494 docs(aio): fix typo
PR Close #20042
2017-11-01 16:55:01 -04:00
d651fc0d6a docs(aio): fix typo
PR Close #20069
2017-11-01 16:54:52 -04:00
5775376bcf docs: add changelog for 5.0.0 2017-11-01 10:50:28 -07:00
896b853519 release: cut the 5.0.0 release 2017-11-01 09:44:19 -07:00
5225fdbc0e build(aio): add i18n boilerplate type (#20004)
PR Close #20004
2017-10-31 01:46:06 -04:00
f5b7f2b9a5 docs: add changelog for 5.0.0-rc.9 2017-10-30 21:09:14 -07:00
509f392ab0 release: cut the 5.0.0-rc.9 release 2017-10-30 21:07:37 -07:00
cf5fce8d5e build: update rollup lint rule from bad merge (#20047)
PR Close #20047
2017-10-30 23:45:06 -04:00
f1248b69e6 refactor: make all rollup config ES5 compatible (#20028)
So they can be required by other Node scripts.

PR Close #20028
2017-10-30 23:28:18 -04:00
4498dddbe3 build: add lint rule for global flags in rollup config (#20028)
We now verify that every imports is part of the globals defined in the files rollup.config.js.

PR Close #20028
2017-10-30 23:28:11 -04:00
812786f44e fix: add missing globals from each rollup configuration (#20028)
PR Close #20028
2017-10-30 23:11:42 -04:00
de24d54517 fix(compiler): report errors properly in G3 in certain conditions (#20041)
Condition: static analysis error, given:
- noResolve:true
- generateCodeForLibraries: false
- CompilerHost.getSourceFile throws on non existent files

All of these are true in G3.
PR Close #20041
2017-10-30 23:07:37 -04:00
c295aeeca2 build: add release as a valid commit message subject (#19955)
PR Close #19955
2017-10-30 21:23:48 -04:00
a8add78fe1 build: temporarily increase the commit msg limit to 120
Right now HEAD and 5.0.x have a branch deviation and therefore
all the commits between both branches are being compared. There
exists a problematic commit which has a commit message that is
longer than 100 commits. This patch will temporarily increase
the limit to 120 so that CI passes. Once master is resumed to
being the primary development branch (once 5.0.0 is out) then
the the msg limit will be set back to 100.
2017-10-30 21:23:43 -04:00
e3a16ed02d fix(compiler): reexport less symbols in .ngfactory.ts files (#19884)
* don't reexport symbols that the user already reexported
* never reexport symbols that are part of arguments of non simple function calls

Fixes #19883

PR Close #19884
2017-10-30 21:19:44 -04:00
fd37f3fbab fix(compiler): always use relative paths to refer to generated code
Previously we generated imports like `@angular/material/index.ngfactory`,
which doesn’t make sense as we don’t ship generated code on npm

Closes #20031
2017-10-30 20:00:48 -04:00
85e95cc32b docs: add changelog for 5.0.0-rc.8 2017-10-27 23:31:35 -07:00
de71ba74bb release: cut the 5.0.0-rc.8 release 2017-10-27 23:31:27 -07:00
a01c877534 docs: ensure examples get rxjs ^5.5.0 (#19985)
This change coincidentally updates other packages that were in `package.json`
because it regenerates `yarn.lock`. This too should be fine.

PR Close #19985
2017-10-27 22:28:21 -07:00
2d508a3ef0 fix(compiler-cli): avoid producing source mappings for host views (#19965)
The host view doesn't map back to user code so the template compiler
produces a blank `url` for them.

PR Close #19965
2017-10-27 22:28:14 -07:00
4285b6c3e3 fix(platform-server): add missing packages to the UMD global rollup config
This adds the proper bindings for calling angular packages from platform-server in the UMD.
This was not a problem for universal apps that dont use UMD.

Fixes 19899
2017-10-27 22:27:43 -07:00
5542517b9c docs: add changelog for 5.0.0-rc.7 2017-10-26 19:03:14 -07:00
fef3539608 release: cut the 5.0.0-rc.7 release 2017-10-26 19:01:34 -07:00
f4d5729cb3 fix(compiler): make watch mode work on windows (#19953)
Fixes #19951
PR Close #19953
2017-10-26 21:52:35 -04:00
d343bf7885 fix(compiler): recover from structural errors in watch mode (#19953)
This also changes the compiler so that we throw less often
on structural changes and produce a meaningful state
in the `ng.Program` in case of errors.

Related to #19951

PR Close #19953
2017-10-26 21:52:25 -04:00
9ce7f0e538 fix(compiler): translate emit diagnostics with noEmitOnError: true. (#19953)
This prevents errors reported against `.ngfactory.ts` files show up
as the result of running `ngc`.

Closes #19935
PR Close #19953
2017-10-26 21:52:16 -04:00
4a23df3909 fix(compiler): don’t store invalid state when using listLazyRoutes (#19953)
Previously, `listLazyRoute` would store invalid information in a compiler
internal cache, which lead to incorrect paths that were used during emit.
This commit fixes this.

PR Close #19953
2017-10-26 21:51:43 -04:00
14016c781f fix(service-worker): fix improper call of Observable.merge (#19962)
Observable.merge was called using .call() as if it were an operator
and not an Observable factory. This removes the .call() and uses
the factory properly.

PR Close #19962
2017-10-26 18:16:20 -04:00
47caebfe86 fix(service-worker): don't block initialization on registration (#19936)
Importing ServiceWorkerModule.register() will schedule registration of
the Service Worker inside an APP_INITIALIZER. Previously, the Promise
returned by navigator.serviceWorker.register() was returned from the
initializer function. This has the unwanted side effect of blocking
initialization until the SW is registered. Even worse, if the SW script
fails to load, this can cause the app initialization to fail.

The solution is to not return the registration promise from the
initializer function, essentially decoupling registration from the rest
of the initialization flow.

This change is not unit testable as there are no mocks/adapters yet for
navigator.serviceWorker. A future integration test should cover this case
with better fidelity.

PR Close #19936
2017-10-26 16:10:17 -04:00
5cfd9c6020 fix(service-worker): listen for messages on the right event source (#19954)
Currently, the SwUpdate service doesn't receive messages from the SW.
This is because it attempts to subscribe to the 'message' event on
ServiceWorkerRegistration, when really messages are emitted by the
ServiceWorkerContainer.

This change moves to listening on ServiceWorkerContainer and changes
the mocks to reflect the way the browser actually works.

PR Close #19954
2017-10-26 16:10:07 -04:00
47bc6f105d docs: add changelog for 5.0.0-rc.6 2017-10-25 14:34:42 -07:00
40fa2593a9 release: cut the 5.0.0-rc.6 release 2017-10-25 14:32:11 -07:00
680bcf7b8a build: update to rxjs@5.5.2 (#19931)
PR Close #19931
2017-10-25 15:32:01 -04:00
ef08330341 fix(compiler): automatically set emitDecoratorMetadata when "annotationsAs": "static fields” (#19927)
This is a workaround for https://github.com/angular/tsickle/issues/635.

Fixes #19916
PR Close #19927
2017-10-25 14:26:28 -04:00
6cc042e2ba fix(compiler-cli): produce correct paths for windows output (#19915)
The path mapping was broken for Windows by fc0b1d5b61.
Fixed the path mapping and put code in place to make such a problem
to sneek by again.

PR Close #19915
2017-10-24 19:21:18 -04:00
9b26455740 fix(compiler-cli): only use error collector when needed. (#19912)
The error collector changes behavior of the metadata resolver
in ways that haven't been fully hardened. This changes limits
its use to the lazy route detection and the language service.

Issue: #19906

PR Close #19912
2017-10-24 19:21:13 -04:00
18bce5987c fix(compiler): don’t type check templates with skipTemplateCodegen (#19909)
This change is needed to prevent users’ builds from breaking.

If a user sets `fullTemlateTypeCheck` to true, we will
continue to check the templates even when `skipTemplateCodegen` is true
as well.

Related to #19906

PR Close #19909
2017-10-24 19:21:03 -04:00
f1108fea76 docs: add changelog for 5.0.0-rc.5 2017-10-23 23:28:28 -07:00
64b3e3e41a release: cut the 5.0.0-rc.5 release 2017-10-23 23:27:15 -07:00
a82f863e24 fix(compiler-cli): report all diagnostic error messages (#19886)
This fixes a problem introduced in 8d45fefc31
which modified how diagnostic error messages are reported for structural
metadata errors causing some of the diagnostics to be lost.

PR Close #19886
2017-10-24 00:57:41 -04:00
146 changed files with 834 additions and 3426 deletions

18
.bazelrc Normal file
View File

@ -0,0 +1,18 @@
# Make compilation fast, by keeping a few copies of the compilers
# running as daemons, and cache SourceFile AST's to reduce parse time.
build --strategy=TypeScriptCompile=worker
build --strategy=AngularTemplateCompile=worker
# Don't create bazel-* symlinks in the WORKSPACE directory.
# These require .gitignore and may scare users.
# Also, it's a workaround for https://github.com/bazelbuild/rules_typescript/issues/12
# which affects the common case of having `tsconfig.json` in the WORKSPACE directory.
#
# Instead, you should run `bazel info bazel-bin` to find out where the outputs went.
build --symlink_prefix=/
# Performance: avoid stat'ing input files
build --watchfs
# Don't print all the .d.ts output locations after builds
build --show_result=0

View File

@ -279,7 +279,7 @@ groups:
files: files:
- "packages/benchpress/*" - "packages/benchpress/*"
users: users:
# needs primary - alxhub #primary
# needs secondary # needs secondary
- IgorMinar #fallback - IgorMinar #fallback
- mhevery #fallback - mhevery #fallback

View File

@ -1,102 +1,3 @@
<a name="5.1.0-rc.1"></a>
# [5.1.0-rc.1](https://github.com/angular/angular/compare/5.1.0-rc.0...5.1.0-rc.1) (2017-12-01)
### Bug Fixes
* **compiler-cli:** propagate ts.SourceFile moduleName into metadata ([f841fbe](https://github.com/angular/angular/commit/f841fbe))
* **service-worker:** allow disabling SW while still using services ([65f4fad](https://github.com/angular/angular/commit/65f4fad))
* **service-worker:** don't crash if SW not supported ([b9a91a5](https://github.com/angular/angular/commit/b9a91a5))
* **service-worker:** send initialization signal from the application ([3fbcde9](https://github.com/angular/angular/commit/3fbcde9))
* **service-worker:** use relative path for ngsw.json ([f582620](https://github.com/angular/angular/commit/f582620))
<a name="5.0.5"></a>
## [5.0.5](https://github.com/angular/angular/compare/5.0.4...5.0.5) (2017-12-01)
### Bug Fixes
* **compiler-cli:** propagate ts.SourceFile moduleName into metadata ([a2ff4ab](https://github.com/angular/angular/commit/a2ff4ab))
* **service-worker:** allow disabling SW while still using services ([f99335b](https://github.com/angular/angular/commit/f99335b))
* **service-worker:** don't crash if SW not supported ([ee37d4b](https://github.com/angular/angular/commit/ee37d4b))
* **service-worker:** send initialization signal from the application ([6bf07b4](https://github.com/angular/angular/commit/6bf07b4))
* **service-worker:** use relative path for ngsw.json ([56c98f7](https://github.com/angular/angular/commit/56c98f7))
<a name="5.1.0-rc.0"></a>
# [5.1.0-rc.0](https://github.com/angular/angular/compare/5.1.0-beta.2...5.1.0-rc.0) (2017-12-01)
### Bug Fixes
* **animations:** ensure multi-level enter animations work ([#19455](https://github.com/angular/angular/issues/19455)) ([dd6237e](https://github.com/angular/angular/commit/dd6237e))
* **animations:** ensure multi-level enter animations work ([#19455](https://github.com/angular/angular/issues/19455)) ([b2a586c](https://github.com/angular/angular/commit/b2a586c))
* **animations:** ensure multi-level leave animations work ([#19455](https://github.com/angular/angular/issues/19455)) ([1366762](https://github.com/angular/angular/commit/1366762))
* **animations:** ensure multi-level leave animations work ([#19455](https://github.com/angular/angular/issues/19455)) ([c2b3792](https://github.com/angular/angular/commit/c2b3792))
* **bazel:** produce named AMD modules for codegen ([#20547](https://github.com/angular/angular/issues/20547)) ([6e83204](https://github.com/angular/angular/commit/6e83204)), closes [#19422](https://github.com/angular/angular/issues/19422)
* **common:** accept falsy values as HTTP bodies ([#19958](https://github.com/angular/angular/issues/19958)) ([15a54df](https://github.com/angular/angular/commit/15a54df)), closes [#19825](https://github.com/angular/angular/issues/19825) [#19195](https://github.com/angular/angular/issues/19195)
* **common:** don't strip XSSI prefix for if error isn't JSON ([#19958](https://github.com/angular/angular/issues/19958)) ([aafa75d](https://github.com/angular/angular/commit/aafa75d))
* **common:** remove useless guard in HttpClient ([#19958](https://github.com/angular/angular/issues/19958)) ([eb01ad5](https://github.com/angular/angular/commit/eb01ad5)), closes [#19223](https://github.com/angular/angular/issues/19223)
* **common:** treat an empty body as null when parsing JSON in HttpClient ([#19958](https://github.com/angular/angular/issues/19958)) ([503be69](https://github.com/angular/angular/commit/503be69)), closes [#18680](https://github.com/angular/angular/issues/18680) [#19413](https://github.com/angular/angular/issues/19413) [#19502](https://github.com/angular/angular/issues/19502) [#19555](https://github.com/angular/angular/issues/19555)
* **compiler:** correctly detect when to serialze summary metadata ([#20668](https://github.com/angular/angular/issues/20668)) ([8bb42df](https://github.com/angular/angular/commit/8bb42df))
* **compiler-cli:** fix memory leak in program creation ([#20692](https://github.com/angular/angular/issues/20692)) ([71e5de6](https://github.com/angular/angular/commit/71e5de6)), closes [#20691](https://github.com/angular/angular/issues/20691)
* **compiler-cli:** normalize sourcepaths for i18n extracted files ([#20417](https://github.com/angular/angular/issues/20417)) ([de78307](https://github.com/angular/angular/commit/de78307)), closes [#20416](https://github.com/angular/angular/issues/20416)
* **core:** should use native addEventListener in ngZone ([#20672](https://github.com/angular/angular/issues/20672)) ([65a2cb8](https://github.com/angular/angular/commit/65a2cb8))
* **language-service:** Allow empty templates ([#20651](https://github.com/angular/angular/issues/20651)) ([3203069](https://github.com/angular/angular/commit/3203069)), closes [#19406](https://github.com/angular/angular/issues/19406)
* **language-service:** Fix crash when no script files are found ([#20550](https://github.com/angular/angular/issues/20550)) ([54bfe14](https://github.com/angular/angular/commit/54bfe14)), closes [#19325](https://github.com/angular/angular/issues/19325)
### Features
* **common:** add locale id parameter to `registerLocaleData` ([#20623](https://github.com/angular/angular/issues/20623)) ([24bf3e2](https://github.com/angular/angular/commit/24bf3e2))
* **compiler-cli:** improve error messages produced during structural errors ([#20459](https://github.com/angular/angular/issues/20459)) ([8ecda94](https://github.com/angular/angular/commit/8ecda94))
<a name="5.0.4"></a>
## [5.0.4](https://github.com/angular/angular/compare/5.0.3...5.0.4) (2017-12-01)
### Bug Fixes
* **animations:** ensure multi-level enter animations work ([#19455](https://github.com/angular/angular/issues/19455)) ([22bbd6e](https://github.com/angular/angular/commit/22bbd6e))
* **animations:** ensure multi-level leave animations work ([#19455](https://github.com/angular/angular/issues/19455)) ([c7b211c](https://github.com/angular/angular/commit/c7b211c))
* **common:** accept falsy values as HTTP bodies ([#19958](https://github.com/angular/angular/issues/19958)) ([66fd1f8](https://github.com/angular/angular/commit/66fd1f8)), closes [#19825](https://github.com/angular/angular/issues/19825) [#19195](https://github.com/angular/angular/issues/19195)
* **common:** don't strip XSSI prefix for if error isn't JSON ([#19958](https://github.com/angular/angular/issues/19958)) ([ead7596](https://github.com/angular/angular/commit/ead7596))
* **common:** remove useless guard in HttpClient ([#19958](https://github.com/angular/angular/issues/19958)) ([e099911](https://github.com/angular/angular/commit/e099911)), closes [#19223](https://github.com/angular/angular/issues/19223)
* **common:** treat an empty body as null when parsing JSON in HttpClient ([#19958](https://github.com/angular/angular/issues/19958)) ([bdaee50](https://github.com/angular/angular/commit/bdaee50)), closes [#18680](https://github.com/angular/angular/issues/18680) [#19413](https://github.com/angular/angular/issues/19413) [#19502](https://github.com/angular/angular/issues/19502) [#19555](https://github.com/angular/angular/issues/19555)
* **compiler-cli:** fix memory leak in program creation ([#20692](https://github.com/angular/angular/issues/20692)) ([38be44d](https://github.com/angular/angular/commit/38be44d)), closes [#20691](https://github.com/angular/angular/issues/20691)
* **compiler-cli:** normalize sourcepaths for i18n extracted files ([#20417](https://github.com/angular/angular/issues/20417)) ([2b0c896](https://github.com/angular/angular/commit/2b0c896)), closes [#20416](https://github.com/angular/angular/issues/20416)
<a name="5.1.0-beta.2"></a>
# [5.1.0-beta.2](https://github.com/angular/angular/compare/5.1.0-beta.1...5.1.0-beta.2) (2017-11-22)
### Bug Fixes
* **animations:** always fire inner trigger callbacks even if blocked by parent animations ([#19753](https://github.com/angular/angular/issues/19753)) ([0e012c9](https://github.com/angular/angular/commit/0e012c9)), closes [#19100](https://github.com/angular/angular/issues/19100)
* **animations:** always fire start and done callbacks in order for noop animations ([#20570](https://github.com/angular/angular/issues/20570)) ([ffb6dbe](https://github.com/angular/angular/commit/ffb6dbe))
* **animations:** validate against trigger() names that use @ symbols ([#20326](https://github.com/angular/angular/issues/20326)) ([1861e41](https://github.com/angular/angular/commit/1861e41))
* **benchpress:** Allow ignoring navigationStart events in perflog metric. ([#20312](https://github.com/angular/angular/issues/20312)) ([717ac5a](https://github.com/angular/angular/commit/717ac5a))
* **common:** return ISubscription from Location.subscribe() ([#20429](https://github.com/angular/angular/issues/20429)) ([437a044](https://github.com/angular/angular/commit/437a044)), closes [#20406](https://github.com/angular/angular/issues/20406)
* **compiler:** emit correct type-check-blocks with TemplateRef's ([#20463](https://github.com/angular/angular/issues/20463)) ([68b53c0](https://github.com/angular/angular/commit/68b53c0))
* **compiler:** support event bindings in `fullTemplateTypeCheck` ([#20490](https://github.com/angular/angular/issues/20490)) ([4ed0439](https://github.com/angular/angular/commit/4ed0439))
* **core:** fix [#20532](https://github.com/angular/angular/issues/20532), should be able to cancel listener from mixed zone ([#20538](https://github.com/angular/angular/issues/20538)) ([a740e4f](https://github.com/angular/angular/commit/a740e4f))
* **core:** should support event.stopImmediatePropagation ([#20469](https://github.com/angular/angular/issues/20469)) ([997336b](https://github.com/angular/angular/commit/997336b))
* **forms:** updateOn should check if change occurred ([#20358](https://github.com/angular/angular/issues/20358)) ([69c53c3](https://github.com/angular/angular/commit/69c53c3)), closes [#20259](https://github.com/angular/angular/issues/20259)
### Features
* **platform-browser-dynamic:** export `JitCompilerFactory` ([#20478](https://github.com/angular/angular/issues/20478)) ([d7a727c](https://github.com/angular/angular/commit/d7a727c)), closes [#20125](https://github.com/angular/angular/issues/20125)
<a name="5.0.3"></a> <a name="5.0.3"></a>
## [5.0.3](https://github.com/angular/angular/compare/5.0.2...5.0.3) (2017-11-22) ## [5.0.3](https://github.com/angular/angular/compare/5.0.2...5.0.3) (2017-11-22)
@ -114,28 +15,6 @@
* **forms:** updateOn should check if change occurred ([#20358](https://github.com/angular/angular/issues/20358)) ([f9f2c20](https://github.com/angular/angular/commit/f9f2c20)), closes [#20259](https://github.com/angular/angular/issues/20259) * **forms:** updateOn should check if change occurred ([#20358](https://github.com/angular/angular/issues/20358)) ([f9f2c20](https://github.com/angular/angular/commit/f9f2c20)), closes [#20259](https://github.com/angular/angular/issues/20259)
<a name="5.1.0-beta.1"></a>
# [5.1.0-beta.1](https://github.com/angular/angular/compare/5.1.0-beta.0...5.1.0-beta.1) (2017-11-16)
### Bug Fixes
* **animations:** always fire inner trigger callbacks even if blocked by parent animations ([#19753](https://github.com/angular/angular/issues/19753)) ([d47b2a6](https://github.com/angular/angular/commit/d47b2a6)), closes [#19100](https://github.com/angular/angular/issues/19100)
* **animations:** ensure final state() styles are applied within @.disabled animations ([#20267](https://github.com/angular/angular/issues/20267)) ([20aafff](https://github.com/angular/angular/commit/20aafff)), closes [#20266](https://github.com/angular/angular/issues/20266)
* **bazel:** adjust mock of tsconfig for ng_module rule unit test ([#20175](https://github.com/angular/angular/issues/20175)) ([c2a24b4](https://github.com/angular/angular/commit/c2a24b4))
* **compiler:** fix corner cases in shadow CSS ([c32f5fd](https://github.com/angular/angular/commit/c32f5fd))
* **compiler:** recognize @NgModule with a redundant @Injectable ([#20320](https://github.com/angular/angular/issues/20320)) ([c33a576](https://github.com/angular/angular/commit/c33a576))
* **compiler:** show explanatory text in template errors ([#20313](https://github.com/angular/angular/issues/20313)) ([3257fcd](https://github.com/angular/angular/commit/3257fcd))
* **core:** ensure init lifecycle events are called ([#20258](https://github.com/angular/angular/issues/20258)) ([24cf8b3](https://github.com/angular/angular/commit/24cf8b3))
* **language-service:** pass compilerOptions.paths to ReflectorHost ([#20222](https://github.com/angular/angular/issues/20222)) ([eb8013e](https://github.com/angular/angular/commit/eb8013e))
* **router:** 'merge' queryParamHandling strategy should be able to remove query params ([#19733](https://github.com/angular/angular/issues/19733)) ([a622e19](https://github.com/angular/angular/commit/a622e19)), closes [#18463](https://github.com/angular/angular/issues/18463) [#17202](https://github.com/angular/angular/issues/17202)
* Update test code to type-check under TS 2.5 ([#20175](https://github.com/angular/angular/issues/20175)) ([5ec1717](https://github.com/angular/angular/commit/5ec1717))
### Features
* **typescript:** support TypeScript 2.5 ([a9f3e2b](https://github.com/angular/angular/commit/a9f3e2b)), closes [#20175](https://github.com/angular/angular/issues/20175)
> Note, if you do `Injector.get(Token)` where `Token` has static members, you'll run into https://github.com/Microsoft/TypeScript/issues/20102 where the returned type is `{}` rather than `Token`. Use `Injector.get<Token>(Token)` to work around.
<a name="5.0.2"></a> <a name="5.0.2"></a>
## [5.0.2](https://github.com/angular/angular/compare/5.0.1...5.0.2) (2017-11-16) ## [5.0.2](https://github.com/angular/angular/compare/5.0.1...5.0.2) (2017-11-16)
@ -150,22 +29,6 @@
* **router:** 'merge' queryParamHandling strategy should be able to remove query params ([#19733](https://github.com/angular/angular/issues/19733)) ([b732fb9](https://github.com/angular/angular/commit/b732fb9)), closes [#18463](https://github.com/angular/angular/issues/18463) [#17202](https://github.com/angular/angular/issues/17202) * **router:** 'merge' queryParamHandling strategy should be able to remove query params ([#19733](https://github.com/angular/angular/issues/19733)) ([b732fb9](https://github.com/angular/angular/commit/b732fb9)), closes [#18463](https://github.com/angular/angular/issues/18463) [#17202](https://github.com/angular/angular/issues/17202)
<a name="5.1.0-beta.0"></a>
# [5.1.0-beta.0](https://github.com/angular/angular/compare/5.0.0-rc.4...5.1.0-beta.0) (2017-11-08)
### Bug Fixes
* **compiler:** don't overwrite missingTranslation's value in JIT ([#19952](https://github.com/angular/angular/issues/19952)) ([799cbb9](https://github.com/angular/angular/commit/799cbb9))
* **compiler:** report a reasonable error with invalid metadata ([#20062](https://github.com/angular/angular/issues/20062)) ([da22c48](https://github.com/angular/angular/commit/da22c48))
* **compiler-cli:** don't report emit diagnostics when `--noEmitOnError` is off ([#20063](https://github.com/angular/angular/issues/20063)) ([8639995](https://github.com/angular/angular/commit/8639995))
* **core:** `__symbol__` should return `__zone_symbol__` without zone.js loaded ([#19541](https://github.com/angular/angular/issues/19541)) ([678d1cf](https://github.com/angular/angular/commit/678d1cf))
* **core:** should support event.stopImmediatePropagation ([#19222](https://github.com/angular/angular/issues/19222)) ([7083791](https://github.com/angular/angular/commit/7083791))
* **platform-browser:** support Symbols in custom `jasmineToString()` method ([#19794](https://github.com/angular/angular/issues/19794)) ([5a6efa7](https://github.com/angular/angular/commit/5a6efa7))
### Features
* **compiler:** introduce `TestBed.overrideTemplateUsingTestingModule` ([a460066](https://github.com/angular/angular/commit/a460066)), closes [#19815](https://github.com/angular/angular/issues/19815)
<a name="5.0.1"></a> <a name="5.0.1"></a>
## [5.0.1](https://github.com/angular/angular/compare/5.0.0...5.0.1) (2017-11-08) ## [5.0.1](https://github.com/angular/angular/compare/5.0.0...5.0.1) (2017-11-08)

View File

@ -69,22 +69,21 @@ You can file new issues by filling out our [new issue form](https://github.com/a
### <a name="submit-pr"></a> Submitting a Pull Request (PR) ### <a name="submit-pr"></a> Submitting a Pull Request (PR)
Before you submit your Pull Request (PR) consider the following guidelines: Before you submit your Pull Request (PR) consider the following guidelines:
1. Search [GitHub](https://github.com/angular/angular/pulls) for an open or closed PR * Search [GitHub](https://github.com/angular/angular/pulls) for an open or closed PR
that relates to your submission. You don't want to duplicate effort. that relates to your submission. You don't want to duplicate effort.
1. Please sign our [Contributor License Agreement (CLA)](#cla) before sending PRs. * Please sign our [Contributor License Agreement (CLA)](#cla) before sending PRs.
We cannot accept code without this. We cannot accept code without this.
1. Fork the angular/angular repo. * Make your changes in a new git branch:
1. Make your changes in a new git branch:
```shell ```shell
git checkout -b my-fix-branch master git checkout -b my-fix-branch master
``` ```
1. Create your patch, **including appropriate test cases**. * Create your patch, **including appropriate test cases**.
1. Follow our [Coding Rules](#rules). * Follow our [Coding Rules](#rules).
1. Run the full Angular test suite, as described in the [developer documentation][dev-doc], * Run the full Angular test suite, as described in the [developer documentation][dev-doc],
and ensure that all tests pass. and ensure that all tests pass.
1. Commit your changes using a descriptive commit message that follows our * Commit your changes using a descriptive commit message that follows our
[commit message conventions](#commit). Adherence to these conventions [commit message conventions](#commit). Adherence to these conventions
is necessary because release notes are automatically generated from these messages. is necessary because release notes are automatically generated from these messages.
@ -93,13 +92,13 @@ Before you submit your Pull Request (PR) consider the following guidelines:
``` ```
Note: the optional commit `-a` command line option will automatically "add" and "rm" edited files. Note: the optional commit `-a` command line option will automatically "add" and "rm" edited files.
1. Push your branch to GitHub: * Push your branch to GitHub:
```shell ```shell
git push origin my-fix-branch git push origin my-fix-branch
``` ```
1. In GitHub, send a pull request to `angular:master`. * In GitHub, send a pull request to `angular:master`.
* If we suggest changes then: * If we suggest changes then:
* Make the required updates. * Make the required updates.
* Re-run the Angular test suites to ensure tests are still passing. * Re-run the Angular test suites to ensure tests are still passing.

View File

@ -5,7 +5,8 @@ load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
git_repository( git_repository(
name = "build_bazel_rules_nodejs", name = "build_bazel_rules_nodejs",
remote = "https://github.com/bazelbuild/rules_nodejs.git", remote = "https://github.com/bazelbuild/rules_nodejs.git",
commit = "0.2.1", # TODO(alexeagle): use the correct tag here.
commit = "2c6243df53fd33fdab283ebdd01582e4eb815db8",
) )
load("@build_bazel_rules_nodejs//:defs.bzl", "node_repositories") load("@build_bazel_rules_nodejs//:defs.bzl", "node_repositories")

View File

@ -6,7 +6,7 @@
<blockquote> <blockquote>
<!-- #docregion built-in, asterisk, ngif --> <!-- #docregion built-in, asterisk, ngif -->
<div *ngIf="hero" class="name">{{hero.name}}</div> <div *ngIf="hero" >{{hero.name}}</div>
<!-- #enddocregion built-in, asterisk, ngif --> <!-- #enddocregion built-in, asterisk, ngif -->
</blockquote> </blockquote>
@ -51,7 +51,7 @@
<p>&lt;ng-template&gt; element</p> <p>&lt;ng-template&gt; element</p>
<!-- #docregion ngif-template --> <!-- #docregion ngif-template -->
<ng-template [ngIf]="hero"> <ng-template [ngIf]="hero">
<div class="name">{{hero.name}}</div> <div>{{hero.name}}</div>
</ng-template> </ng-template>
<!-- #enddocregion ngif-template --> <!-- #enddocregion ngif-template -->

View File

@ -74,8 +74,8 @@ Generate a new project and skeleton application by running the following command
Patience, please. Patience please.
It takes time to set up a new project; most of it is spent installing npm packages. It takes time to set up a new project, most of it spent installing npm packages.
</div> </div>

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 79 KiB

After

Width:  |  Height:  |  Size: 85 KiB

View File

@ -241,12 +241,6 @@
"UI Components": { "UI Components": {
"order": 4, "order": 4,
"resources": { "resources": {
"IgniteUIforAngular": {
"desc": "Ignite UI for Angular is a dependency-free Angular toolkit for building modern web apps.",
"rev": true,
"title": "Ignite UI for Angular",
"url": "https://www.infragistics.com/products/ignite-ui-angular"
},
"DevExtreme": { "DevExtreme": {
"desc": "50+ UI components including data grid, pivot grid, scheduler, charts, editors, maps and other multi-purpose controls for creating highly responsive web applications for touch devices and traditional desktops.", "desc": "50+ UI components including data grid, pivot grid, scheduler, charts, editors, maps and other multi-purpose controls for creating highly responsive web applications for touch devices and traditional desktops.",
"rev": true, "rev": true,

View File

@ -3,7 +3,7 @@
The Tour of Heroes `HeroesComponent` is currently getting and displaying fake data. The Tour of Heroes `HeroesComponent` is currently getting and displaying fake data.
After the refactoring in this tutorial, `HeroesComponent` will be lean and focused on supporting the view. After the refactoring in this tutorial, `HeroesComponent` will be lean and focused on supporting the view.
It will also be easier to unit-test with a mock service. It will also be easier to unit-test with a mock services.
## Why services ## Why services

View File

@ -80,6 +80,8 @@ describe('site App', function() {
}); });
}); });
// TODO(https://github.com/angular/angular/issues/19785): Activate this again
// once it is no more flaky.
describe('google analytics', () => { describe('google analytics', () => {
it('should call ga with initial URL', done => { it('should call ga with initial URL', done => {

View File

@ -29,7 +29,10 @@ export class SitePage {
locationPath() { return browser.executeScript('return document.location.pathname') as promise.Promise<string>; } locationPath() { return browser.executeScript('return document.location.pathname') as promise.Promise<string>; }
navigateTo(pageUrl = '') { navigateTo(pageUrl = '') {
return browser.get('/' + pageUrl); return browser.get('/' + pageUrl)
// We need to tell the index.html not to load the real analytics library
// See the GA snippet in index.html
.then(() => browser.executeScript('sessionStorage.setItem("__e2e__", true);'));
} }
getDocViewerText() { getDocViewerText() {

View File

@ -100,7 +100,7 @@
"cross-spawn": "^5.1.0", "cross-spawn": "^5.1.0",
"css-selector-parser": "^1.3.0", "css-selector-parser": "^1.3.0",
"dgeni": "^0.4.7", "dgeni": "^0.4.7",
"dgeni-packages": "0.22.1", "dgeni-packages": "0.22.0",
"entities": "^1.1.1", "entities": "^1.1.1",
"eslint": "^3.19.0", "eslint": "^3.19.0",
"eslint-plugin-jasmine": "^2.2.0", "eslint-plugin-jasmine": "^2.2.0",

View File

@ -34,13 +34,11 @@
<!-- Google Analytics --> <!-- Google Analytics -->
<script> <script>
// Note this is a customised version of the GA tracking snippet // Note this is a customised version of the GA tracking snippet to aid e2e testing
// See the comments below for more info // See the bit between /**/.../**/
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g; m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;/**/i.sessionStorage.__e2e__||/**/m.parentNode.insertBefore(a,m)
~i.name.indexOf('NG_DEFER_BOOTSTRAP')|| // only load library if not running e2e tests
m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga'); })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
</script> </script>
<!-- End Google Analytics --> <!-- End Google Analytics -->

View File

@ -62,7 +62,7 @@ class ExampleZipper {
let exampleZipName; let exampleZipName;
const exampleType = this._getExampleType(path.join(sourceDirName, relativeDirName)); const exampleType = this._getExampleType(path.join(sourceDirName, relativeDirName));
if (relativeDirName.indexOf('/') !== -1) { // Special example if (relativeDirName.indexOf('/') !== -1) { // Special example
exampleZipName = relativeDirName.split('/').join('-'); exampleZipName = relativeDirName.split('/')[0];
} else { } else {
exampleZipName = jsonFileName.replace(/(plnkr|zipper).json/, relativeDirName); exampleZipName = jsonFileName.replace(/(plnkr|zipper).json/, relativeDirName);
} }

View File

@ -26,13 +26,13 @@
"zone.js": "^0.8.14" "zone.js": "^0.8.14"
}, },
"devDependencies": { "devDependencies": {
"@angular/cli": "1.5.4", "@angular/cli": "1.5.0",
"@angular/compiler-cli": "^5.0.0", "@angular/compiler-cli": "^5.0.0",
"@angular/language-service": "^5.0.0", "@angular/language-service": "^5.0.0",
"@types/jasmine": "~2.5.53", "@types/jasmine": "~2.5.53",
"@types/jasminewd2": "~2.0.2", "@types/jasminewd2": "~2.0.2",
"@types/node": "~6.0.60", "@types/node": "~6.0.60",
"codelyzer": "^4.0.1", "codelyzer": "~3.2.0",
"jasmine-core": "~2.6.2", "jasmine-core": "~2.6.2",
"jasmine-spec-reporter": "~4.1.0", "jasmine-spec-reporter": "~4.1.0",
"karma": "~1.7.0", "karma": "~1.7.0",

View File

@ -2287,9 +2287,9 @@ devtools-timeline-model@1.1.6:
chrome-devtools-frontend "1.0.401423" chrome-devtools-frontend "1.0.401423"
resolve "1.1.7" resolve "1.1.7"
dgeni-packages@0.22.1: dgeni-packages@0.22.0:
version "0.22.1" version "0.22.0"
resolved "https://registry.yarnpkg.com/dgeni-packages/-/dgeni-packages-0.22.1.tgz#c4587a765689c4c9d48ed661517ed2249403bfb2" resolved "https://registry.yarnpkg.com/dgeni-packages/-/dgeni-packages-0.22.0.tgz#7ed07af9074f6547847256c1a65b488a5a17ad03"
dependencies: dependencies:
canonical-path "0.0.2" canonical-path "0.0.2"
catharsis "^0.8.1" catharsis "^0.8.1"

View File

@ -3,7 +3,7 @@ load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
git_repository( git_repository(
name = "build_bazel_rules_nodejs", name = "build_bazel_rules_nodejs",
remote = "https://github.com/bazelbuild/rules_nodejs.git", remote = "https://github.com/bazelbuild/rules_nodejs.git",
tag = "0.2.1", tag = "0.0.2",
) )
load("@build_bazel_rules_nodejs//:defs.bzl", "node_repositories") load("@build_bazel_rules_nodejs//:defs.bzl", "node_repositories")

View File

@ -1,19 +0,0 @@
import { AppPage } from './app.po';
describe('dynamic-compiler App', () => {
let page: AppPage;
beforeEach(() => {
page = new AppPage();
});
it('should display welcome message', () => {
page.navigateTo();
expect(page.getParagraphText()).toEqual('Hello world!');
});
it('should display lazy-loaded component', () => {
page.navigateTo();
expect(page.getLazyLoadedText()).toEqual('Lazy-loaded component!');
});
});

View File

@ -1,16 +0,0 @@
import {browser, by, element, protractor} from 'protractor';
export class AppPage {
navigateTo() {
return browser.get('/');
}
getParagraphText() {
return element(by.css('app-root h1')).getText();
}
getLazyLoadedText() {
const el = element(by.css('app-root lazy-component'));
return browser.wait(protractor.ExpectedConditions.presenceOf(el)).then(() => el.getText(), err => el.getText());
}
}

View File

@ -1,15 +0,0 @@
{
"open": false,
"logLevel": "silent",
"port": 8080,
"server": {
"baseDir": ".",
"routes": {
"/dist": "dist",
"/node_modules": "node_modules"
},
"middleware": {
"0": null
}
}
}

View File

@ -1,16 +0,0 @@
exports.config = {
specs: [
'../dist/e2e/*.e2e-spec.js'
],
capabilities: {
browserName: 'chrome',
chromeOptions: {
args: ['--no-sandbox'],
binary: process.env.CHROME_BIN,
}
},
directConnect: true,
baseUrl: 'http://localhost:8080/',
framework: 'jasmine',
useAllAngular2AppRoots: true
};

View File

@ -1,7 +0,0 @@
{
"compilerOptions": {
"outDir": "../dist/e2e",
"types": ["jasmine"],
"skipLibCheck": true
}
}

View File

@ -1,14 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<app-root></app-root>
<script src="/node_modules/zone.js/dist/zone.js"></script>
<script src="/node_modules/reflect-metadata/Reflect.js"></script>
<script src="/node_modules/systemjs/dist/system.js"></script>
<script src="/dist/bundle.js"></script>
</body>
</html>

View File

@ -1,44 +0,0 @@
{
"name": "dynamic-compiler",
"version": "0.0.0",
"main": "index.js",
"scripts": {
"build": "npm run clean && npm run ngc && npm run rollup && npm run rollup:lazy && npm run es5 && npm run es5:lazy",
"clean": "rm -rf dist",
"es5": "tsc --target es5 --skipLibCheck --allowJs dist/bundle.es2015.js --out dist/bundle.js",
"es5:lazy": "tsc --target es5 --skipLibCheck --allowJs dist/lazy.bundle.es2015.js --out dist/lazy.bundle.js",
"ngc": "ngc -p tsconfig.json",
"rollup": "rollup -f iife -c rollup.config.js -o dist/bundle.es2015.js",
"rollup:lazy": "rollup -f cjs -c rollup.lazy.config.js -o dist/lazy.bundle.es2015.js",
"postinstall": "webdriver-manager update --gecko false",
"preprotractor": "tsc -p e2e",
"protractor": "protractor e2e/protractor.config.js",
"serve": "lite-server -c e2e/browser.config.json",
"test": "npm run build && concurrently \"yarn run serve\" \"yarn run protractor\" --kill-others --success first"
},
"license": "MIT",
"devDependencies": {
"@types/jasmine": "file:../../node_modules/@types/jasmine",
"@angular/compiler-cli": "file:../../dist/packages-dist/compiler-cli",
"concurrently": "3.4.0",
"lite-server": "2.2.2",
"protractor": "file:../../node_modules/protractor",
"rollup": "file:../../node_modules/rollup",
"rollup-plugin-commonjs": "file:../../node_modules/rollup-plugin-commonjs",
"rollup-plugin-node-resolve": "file:../../node_modules/rollup-plugin-node-resolve",
"typescript": "file:../../node_modules/typescript"
},
"dependencies": {
"@angular/animations": "file:../../dist/packages-dist/animations",
"@angular/common": "file:../../dist/packages-dist/common",
"@angular/compiler": "file:../../dist/packages-dist/compiler",
"@angular/core": "file:../../dist/packages-dist/core",
"@angular/platform-browser": "file:../../dist/packages-dist/platform-browser",
"@angular/platform-browser-dynamic": "file:../../dist/packages-dist/platform-browser-dynamic",
"@angular/platform-server": "file:../../dist/packages-dist/platform-server",
"core-js": "file:../../node_modules/core-js",
"rxjs": "file:../../node_modules/rxjs",
"systemjs": "file:../../node_modules/systemjs",
"zone.js": "file:../../node_modules/zone.js"
}
}

View File

@ -1,17 +0,0 @@
import nodeResolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
export default {
entry: 'dist/src/main.js',
sourceMap: true,
treeshake: true,
moduleName: 'main',
plugins: [
commonjs({
include: 'node_modules/**'
}),
nodeResolve({
jsnext: true, main: true, module: true
})
]
};

View File

@ -1,19 +0,0 @@
import nodeResolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
// a real app should make a common bundle for libraries instead of bundling them
// in both the main module & the lazy module, but we don't care about size here
export default {
entry: 'dist/src/lazy.module.js',
sourceMap: true,
treeshake: true,
moduleName: 'lazy',
plugins: [
commonjs({
include: 'node_modules/**'
}),
nodeResolve({
jsnext: true, main: true, module: true
})
]
};

View File

@ -1,27 +0,0 @@
import {AfterViewInit, Compiler, Component, ViewChild, ViewContainerRef} from '@angular/core';
declare var System: any;
@Component({
selector: 'app-root',
template: `
<h1>Hello world!</h1>
<div #vc></div>
`,
})
export class AppComponent implements AfterViewInit {
@ViewChild('vc', {read: ViewContainerRef}) container: ViewContainerRef;
constructor(private compiler: Compiler) {
}
ngAfterViewInit() {
System.import('./dist/lazy.bundle.js').then((module: any) => {
this.compiler.compileModuleAndAllComponentsAsync(module.LazyModule)
.then((compiled) => {
const factory = compiled.componentFactories[0];
this.container.createComponent(factory);
});
});
}
}

View File

@ -1,22 +0,0 @@
import {Compiler, COMPILER_OPTIONS, CompilerFactory, NgModule} from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import {JitCompilerFactory} from '@angular/platform-browser-dynamic';
import { AppComponent } from './app.component';
export function createCompiler(compilerFactory: CompilerFactory) {
return compilerFactory.createCompiler();
}
@NgModule({
imports: [BrowserModule],
bootstrap: [AppComponent],
declarations: [AppComponent],
providers: [
{provide: COMPILER_OPTIONS, useValue: {}, multi: true},
{provide: CompilerFactory, useClass: JitCompilerFactory, deps: [COMPILER_OPTIONS]},
{provide: Compiler, useFactory: createCompiler, deps: [CompilerFactory]}
]
})
export class AppModule {}

View File

@ -1,17 +0,0 @@
import {NgModule} from "@angular/core";
import {Component} from '@angular/core';
@Component({
selector: 'lazy-component',
template: 'Lazy-loaded component!'
})
export class LazyComponent {
constructor() {
}
}
@NgModule({
declarations: [LazyComponent]
})
export class LazyModule {
}

View File

@ -1,8 +0,0 @@
import { enableProdMode } from '@angular/core';
import { platformBrowser } from '@angular/platform-browser';
import { AppModuleNgFactory } from './app.module.ngfactory';
enableProdMode();
platformBrowser().bootstrapModuleFactory(AppModuleNgFactory);

View File

@ -1,28 +0,0 @@
{
"compilerOptions": {
"target": "es2015",
"module": "es2015",
"moduleResolution": "node",
"declaration": false,
"removeComments": true,
"noLib": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"lib": ["es6", "es2015", "dom"],
"sourceMap": true,
"pretty": true,
"allowUnreachableCode": false,
"allowUnusedLabels": false,
"noImplicitAny": true,
"noImplicitReturns": true,
"noImplicitUseStrict": false,
"noFallthroughCasesInSwitch": true,
"outDir": "./dist",
"types": [
]
},
"files": [
"src/main.ts",
"src/lazy.module.ts"
]
}

View File

@ -1,6 +1,6 @@
{ {
"name": "angular-integration", "name": "angular-integration",
"description": "Assert that users with TypeScript 2.4 can type-check an Angular application", "description": "Assert that users with TypeScript 2.2 can type-check an Angular application",
"version": "0.0.0", "version": "0.0.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -18,7 +18,7 @@
"@angular/upgrade": "file:../../dist/packages-dist/upgrade", "@angular/upgrade": "file:../../dist/packages-dist/upgrade",
"@types/jasmine": "2.5.41", "@types/jasmine": "2.5.41",
"rxjs": "file:../../node_modules/rxjs", "rxjs": "file:../../node_modules/rxjs",
"typescript": "2.4.x", "typescript": "file:../../node_modules/typescript",
"zone.js": "file:../../node_modules/zone.js" "zone.js": "file:../../node_modules/zone.js"
}, },
"scripts": { "scripts": {

View File

@ -1,41 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import * as compiler from '@angular/compiler';
import * as compilerTesting from '@angular/compiler/testing';
import * as core from '@angular/core';
import * as coreTesting from '@angular/core/testing';
import * as forms from '@angular/forms';
import * as http from '@angular/http';
import * as httpTesting from '@angular/http/testing';
import * as platformBrowserDynamic from '@angular/platform-browser-dynamic';
import * as platformBrowser from '@angular/platform-browser';
import * as platformBrowserTesting from '@angular/platform-browser/testing';
import * as platformServer from '@angular/platform-server';
import * as platformServerTesting from '@angular/platform-server/testing';
import * as router from '@angular/router';
import * as routerTesting from '@angular/router/testing';
import * as upgrade from '@angular/upgrade';
export default {
compiler,
compilerTesting,
core,
coreTesting,
forms,
http,
httpTesting,
platformBrowser,
platformBrowserTesting,
platformBrowserDynamic,
platformServer,
platformServerTesting,
router,
routerTesting,
upgrade
};

View File

@ -1,27 +0,0 @@
{
"name": "angular-integration",
"description": "Assert that users with TypeScript 2.5 can type-check an Angular application",
"version": "0.0.0",
"license": "MIT",
"dependencies": {
"@angular/animations": "file:../../dist/packages-dist/animations",
"@angular/common": "file:../../dist/packages-dist/common",
"@angular/compiler": "file:../../dist/packages-dist/compiler",
"@angular/compiler-cli": "file:../../dist/packages-dist/compiler-cli",
"@angular/core": "file:../../dist/packages-dist/core",
"@angular/forms": "file:../../dist/packages-dist/forms",
"@angular/http": "file:../../dist/packages-dist/http",
"@angular/platform-browser": "file:../../dist/packages-dist/platform-browser",
"@angular/platform-browser-dynamic": "file:../../dist/packages-dist/platform-browser-dynamic",
"@angular/platform-server": "file:../../dist/packages-dist/platform-server",
"@angular/router": "file:../../dist/packages-dist/router",
"@angular/upgrade": "file:../../dist/packages-dist/upgrade",
"@types/jasmine": "2.5.41",
"rxjs": "file:../../node_modules/rxjs",
"typescript": "2.5.x",
"zone.js": "file:../../node_modules/zone.js"
},
"scripts": {
"test": "tsc"
}
}

View File

@ -1,24 +0,0 @@
{
"compilerOptions": {
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"module": "commonjs",
"moduleResolution": "node",
"outDir": "../../dist/typings_test_ts25/",
"rootDir": ".",
"target": "es5",
"lib": [
"es5",
"dom",
"es2015.collection",
"es2015.iterable",
"es2015.promise"
],
"types": [],
"strictNullChecks": true
},
"files": [
"include-all.ts",
"node_modules/@types/jasmine/index.d.ts"
]
}

View File

@ -1,6 +1,6 @@
{ {
"name": "angular-srcs", "name": "angular-srcs",
"version": "5.1.0-rc.1", "version": "5.0.3",
"private": true, "private": true,
"branchPattern": "2.0.*", "branchPattern": "2.0.*",
"description": "Angular - a web framework for modern web apps", "description": "Angular - a web framework for modern web apps",
@ -32,7 +32,7 @@
"fsevents": "1.1.2" "fsevents": "1.1.2"
}, },
"devDependencies": { "devDependencies": {
"@bazel/typescript": "0.3.2", "@bazel/typescript": "0.2.x",
"@types/angularjs": "1.5.14-alpha", "@types/angularjs": "1.5.14-alpha",
"@types/base64-js": "1.2.5", "@types/base64-js": "1.2.5",
"@types/chokidar": "1.7.3", "@types/chokidar": "1.7.3",
@ -95,10 +95,10 @@
"source-map-support": "0.4.18", "source-map-support": "0.4.18",
"systemjs": "0.18.10", "systemjs": "0.18.10",
"ts-api-guardian": "0.2.2", "ts-api-guardian": "0.2.2",
"tsickle": "0.25.5", "tsickle": "0.24.x",
"tslint": "5.7.0", "tslint": "5.7.0",
"tslint-eslint-rules": "4.1.1", "tslint-eslint-rules": "4.1.1",
"typescript": "2.5.x", "typescript": "2.4.2",
"uglify-js": "2.8.29", "uglify-js": "2.8.29",
"universal-analytics": "0.4.15", "universal-analytics": "0.4.15",
"vlq": "0.2.2", "vlq": "0.2.2",

View File

@ -8,7 +8,7 @@
import {AnimationMetadata, AnimationMetadataType, AnimationOptions, ɵStyleData} from '@angular/animations'; import {AnimationMetadata, AnimationMetadataType, AnimationOptions, ɵStyleData} from '@angular/animations';
import {AnimationDriver} from '../render/animation_driver'; import {AnimationDriver} from '../render/animation_driver';
import {ENTER_CLASSNAME, LEAVE_CLASSNAME, normalizeStyles} from '../util'; import {normalizeStyles} from '../util';
import {Ast} from './animation_ast'; import {Ast} from './animation_ast';
import {buildAnimationAst} from './animation_ast_builder'; import {buildAnimationAst} from './animation_ast_builder';
@ -39,8 +39,7 @@ export class Animation {
const errors: any = []; const errors: any = [];
subInstructions = subInstructions || new ElementInstructionMap(); subInstructions = subInstructions || new ElementInstructionMap();
const result = buildAnimationTimelines( const result = buildAnimationTimelines(
this._driver, element, this._animationAst, ENTER_CLASSNAME, LEAVE_CLASSNAME, start, dest, this._driver, element, this._animationAst, start, dest, options, subInstructions, errors);
options, subInstructions, errors);
if (errors.length) { if (errors.length) {
const errorMessage = `animation building failed:\n${errors.join("\n")}`; const errorMessage = `animation building failed:\n${errors.join("\n")}`;
throw new Error(errorMessage); throw new Error(errorMessage);

View File

@ -60,6 +60,10 @@ export function buildAnimationAst(
return new AnimationAstBuilderVisitor(driver).build(metadata, errors); return new AnimationAstBuilderVisitor(driver).build(metadata, errors);
} }
const LEAVE_TOKEN = ':leave';
const LEAVE_TOKEN_REGEX = new RegExp(LEAVE_TOKEN, 'g');
const ENTER_TOKEN = ':enter';
const ENTER_TOKEN_REGEX = new RegExp(ENTER_TOKEN, 'g');
const ROOT_SELECTOR = ''; const ROOT_SELECTOR = '';
export class AnimationAstBuilderVisitor implements AnimationDslVisitor { export class AnimationAstBuilderVisitor implements AnimationDslVisitor {
@ -474,8 +478,9 @@ function normalizeSelector(selector: string): [string, boolean] {
selector = selector.replace(SELF_TOKEN_REGEX, ''); selector = selector.replace(SELF_TOKEN_REGEX, '');
} }
// the :enter and :leave selectors are filled in at runtime during timeline building selector = selector.replace(ENTER_TOKEN_REGEX, ENTER_SELECTOR)
selector = selector.replace(/@\*/g, NG_TRIGGER_SELECTOR) .replace(LEAVE_TOKEN_REGEX, LEAVE_SELECTOR)
.replace(/@\*/g, NG_TRIGGER_SELECTOR)
.replace(/@\w+/g, match => NG_TRIGGER_SELECTOR + '-' + match.substr(1)) .replace(/@\w+/g, match => NG_TRIGGER_SELECTOR + '-' + match.substr(1))
.replace(/:animating/g, NG_ANIMATING_SELECTOR); .replace(/:animating/g, NG_ANIMATING_SELECTOR);

View File

@ -15,10 +15,6 @@ import {AnimationTimelineInstruction, createTimelineInstruction} from './animati
import {ElementInstructionMap} from './element_instruction_map'; import {ElementInstructionMap} from './element_instruction_map';
const ONE_FRAME_IN_MILLISECONDS = 1; const ONE_FRAME_IN_MILLISECONDS = 1;
const ENTER_TOKEN = ':enter';
const ENTER_TOKEN_REGEX = new RegExp(ENTER_TOKEN, 'g');
const LEAVE_TOKEN = ':leave';
const LEAVE_TOKEN_REGEX = new RegExp(LEAVE_TOKEN, 'g');
/* /*
* The code within this file aims to generate web-animations-compatible keyframes from Angular's * The code within this file aims to generate web-animations-compatible keyframes from Angular's
@ -106,23 +102,19 @@ const LEAVE_TOKEN_REGEX = new RegExp(LEAVE_TOKEN, 'g');
*/ */
export function buildAnimationTimelines( export function buildAnimationTimelines(
driver: AnimationDriver, rootElement: any, ast: Ast<AnimationMetadataType>, driver: AnimationDriver, rootElement: any, ast: Ast<AnimationMetadataType>,
enterClassName: string, leaveClassName: string, startingStyles: ɵStyleData = {}, startingStyles: ɵStyleData = {}, finalStyles: ɵStyleData = {}, options: AnimationOptions,
finalStyles: ɵStyleData = {}, options: AnimationOptions,
subInstructions?: ElementInstructionMap, errors: any[] = []): AnimationTimelineInstruction[] { subInstructions?: ElementInstructionMap, errors: any[] = []): AnimationTimelineInstruction[] {
return new AnimationTimelineBuilderVisitor().buildKeyframes( return new AnimationTimelineBuilderVisitor().buildKeyframes(
driver, rootElement, ast, enterClassName, leaveClassName, startingStyles, finalStyles, driver, rootElement, ast, startingStyles, finalStyles, options, subInstructions, errors);
options, subInstructions, errors);
} }
export class AnimationTimelineBuilderVisitor implements AstVisitor { export class AnimationTimelineBuilderVisitor implements AstVisitor {
buildKeyframes( buildKeyframes(
driver: AnimationDriver, rootElement: any, ast: Ast<AnimationMetadataType>, driver: AnimationDriver, rootElement: any, ast: Ast<AnimationMetadataType>,
enterClassName: string, leaveClassName: string, startingStyles: ɵStyleData, startingStyles: ɵStyleData, finalStyles: ɵStyleData, options: AnimationOptions,
finalStyles: ɵStyleData, options: AnimationOptions, subInstructions?: ElementInstructionMap, subInstructions?: ElementInstructionMap, errors: any[] = []): AnimationTimelineInstruction[] {
errors: any[] = []): AnimationTimelineInstruction[] {
subInstructions = subInstructions || new ElementInstructionMap(); subInstructions = subInstructions || new ElementInstructionMap();
const context = new AnimationTimelineContext( const context = new AnimationTimelineContext(driver, rootElement, subInstructions, errors, []);
driver, rootElement, subInstructions, enterClassName, leaveClassName, errors, []);
context.options = options; context.options = options;
context.currentTimeline.setStyles([startingStyles], null, context.errors, options); context.currentTimeline.setStyles([startingStyles], null, context.errors, options);
@ -453,9 +445,8 @@ export class AnimationTimelineContext {
constructor( constructor(
private _driver: AnimationDriver, public element: any, private _driver: AnimationDriver, public element: any,
public subInstructions: ElementInstructionMap, private _enterClassName: string, public subInstructions: ElementInstructionMap, public errors: any[],
private _leaveClassName: string, public errors: any[], public timelines: TimelineBuilder[], public timelines: TimelineBuilder[], initialTimeline?: TimelineBuilder) {
initialTimeline?: TimelineBuilder) {
this.currentTimeline = initialTimeline || new TimelineBuilder(this._driver, element, 0); this.currentTimeline = initialTimeline || new TimelineBuilder(this._driver, element, 0);
timelines.push(this.currentTimeline); timelines.push(this.currentTimeline);
} }
@ -508,8 +499,8 @@ export class AnimationTimelineContext {
AnimationTimelineContext { AnimationTimelineContext {
const target = element || this.element; const target = element || this.element;
const context = new AnimationTimelineContext( const context = new AnimationTimelineContext(
this._driver, target, this.subInstructions, this._enterClassName, this._leaveClassName, this._driver, target, this.subInstructions, this.errors, this.timelines,
this.errors, this.timelines, this.currentTimeline.fork(target, newTime || 0)); this.currentTimeline.fork(target, newTime || 0));
context.previousNode = this.previousNode; context.previousNode = this.previousNode;
context.currentAnimateTimings = this.currentAnimateTimings; context.currentAnimateTimings = this.currentAnimateTimings;
@ -564,8 +555,6 @@ export class AnimationTimelineContext {
results.push(this.element); results.push(this.element);
} }
if (selector.length > 0) { // if :self is only used then the selector is empty if (selector.length > 0) { // if :self is only used then the selector is empty
selector = selector.replace(ENTER_TOKEN_REGEX, '.' + this._enterClassName);
selector = selector.replace(LEAVE_TOKEN_REGEX, '.' + this._leaveClassName);
const multi = limit != 1; const multi = limit != 1;
let elements = this._driver.query(this.element, selector, multi); let elements = this._driver.query(this.element, selector, multi);
if (limit !== 0) { if (limit !== 0) {

View File

@ -37,8 +37,7 @@ export class AnimationTransitionFactory {
build( build(
driver: AnimationDriver, element: any, currentState: any, nextState: any, driver: AnimationDriver, element: any, currentState: any, nextState: any,
enterClassName: string, leaveClassName: string, currentOptions?: AnimationOptions, currentOptions?: AnimationOptions, nextOptions?: AnimationOptions,
nextOptions?: AnimationOptions,
subInstructions?: ElementInstructionMap): AnimationTransitionInstruction { subInstructions?: ElementInstructionMap): AnimationTransitionInstruction {
const errors: any[] = []; const errors: any[] = [];
@ -56,8 +55,8 @@ export class AnimationTransitionFactory {
const animationOptions = {params: {...transitionAnimationParams, ...nextAnimationParams}}; const animationOptions = {params: {...transitionAnimationParams, ...nextAnimationParams}};
const timelines = buildAnimationTimelines( const timelines = buildAnimationTimelines(
driver, element, this.ast.animation, enterClassName, leaveClassName, currentStateStyles, driver, element, this.ast.animation, currentStateStyles, nextStateStyles, animationOptions,
nextStateStyles, animationOptions, subInstructions, errors); subInstructions, errors);
if (errors.length) { if (errors.length) {
return createTransitionInstruction( return createTransitionInstruction(

View File

@ -13,7 +13,6 @@ import {buildAnimationTimelines} from '../dsl/animation_timeline_builder';
import {AnimationTimelineInstruction} from '../dsl/animation_timeline_instruction'; import {AnimationTimelineInstruction} from '../dsl/animation_timeline_instruction';
import {ElementInstructionMap} from '../dsl/element_instruction_map'; import {ElementInstructionMap} from '../dsl/element_instruction_map';
import {AnimationStyleNormalizer} from '../dsl/style_normalization/animation_style_normalizer'; import {AnimationStyleNormalizer} from '../dsl/style_normalization/animation_style_normalizer';
import {ENTER_CLASSNAME, LEAVE_CLASSNAME} from '../util';
import {AnimationDriver} from './animation_driver'; import {AnimationDriver} from './animation_driver';
import {getOrSetAsInMap, listenOnPlayer, makeAnimationEvent, normalizeKeyframes, optimizeGroupPlayer} from './shared'; import {getOrSetAsInMap, listenOnPlayer, makeAnimationEvent, normalizeKeyframes, optimizeGroupPlayer} from './shared';
@ -56,8 +55,7 @@ export class TimelineAnimationEngine {
if (ast) { if (ast) {
instructions = buildAnimationTimelines( instructions = buildAnimationTimelines(
this._driver, element, ast, ENTER_CLASSNAME, LEAVE_CLASSNAME, {}, {}, options, this._driver, element, ast, {}, {}, options, EMPTY_INSTRUCTION_MAP, errors);
EMPTY_INSTRUCTION_MAP, errors);
instructions.forEach(inst => { instructions.forEach(inst => {
const styles = getOrSetAsInMap(autoStylesMap, inst.element, {}); const styles = getOrSetAsInMap(autoStylesMap, inst.element, {});
inst.postStyleProps.forEach(prop => styles[prop] = null); inst.postStyleProps.forEach(prop => styles[prop] = null);

View File

@ -13,7 +13,7 @@ import {AnimationTransitionInstruction} from '../dsl/animation_transition_instru
import {AnimationTrigger} from '../dsl/animation_trigger'; import {AnimationTrigger} from '../dsl/animation_trigger';
import {ElementInstructionMap} from '../dsl/element_instruction_map'; import {ElementInstructionMap} from '../dsl/element_instruction_map';
import {AnimationStyleNormalizer} from '../dsl/style_normalization/animation_style_normalizer'; import {AnimationStyleNormalizer} from '../dsl/style_normalization/animation_style_normalizer';
import {ENTER_CLASSNAME, LEAVE_CLASSNAME, NG_ANIMATING_CLASSNAME, NG_ANIMATING_SELECTOR, NG_TRIGGER_CLASSNAME, NG_TRIGGER_SELECTOR, copyObj, eraseStyles, iteratorToArray, setStyles} from '../util'; import {ENTER_CLASSNAME, LEAVE_CLASSNAME, NG_ANIMATING_CLASSNAME, NG_ANIMATING_SELECTOR, NG_TRIGGER_CLASSNAME, NG_TRIGGER_SELECTOR, copyObj, eraseStyles, setStyles} from '../util';
import {AnimationDriver} from './animation_driver'; import {AnimationDriver} from './animation_driver';
import {getBodyNode, getOrSetAsInMap, listenOnPlayer, makeAnimationEvent, normalizeKeyframes, optimizeGroupPlayer} from './shared'; import {getBodyNode, getOrSetAsInMap, listenOnPlayer, makeAnimationEvent, normalizeKeyframes, optimizeGroupPlayer} from './shared';
@ -22,8 +22,6 @@ const QUEUED_CLASSNAME = 'ng-animate-queued';
const QUEUED_SELECTOR = '.ng-animate-queued'; const QUEUED_SELECTOR = '.ng-animate-queued';
const DISABLED_CLASSNAME = 'ng-animate-disabled'; const DISABLED_CLASSNAME = 'ng-animate-disabled';
const DISABLED_SELECTOR = '.ng-animate-disabled'; const DISABLED_SELECTOR = '.ng-animate-disabled';
const STAR_CLASSNAME = 'ng-star-inserted';
const STAR_SELECTOR = '.ng-star-inserted';
const EMPTY_PLAYER_ARRAY: TransitionAnimationPlayer[] = []; const EMPTY_PLAYER_ARRAY: TransitionAnimationPlayer[] = [];
const NULL_REMOVAL_STATE: ElementAnimationState = { const NULL_REMOVAL_STATE: ElementAnimationState = {
@ -716,12 +714,10 @@ export class TransitionAnimationEngine {
return () => {}; return () => {};
} }
private _buildInstruction( private _buildInstruction(entry: QueueInstruction, subTimelines: ElementInstructionMap) {
entry: QueueInstruction, subTimelines: ElementInstructionMap, enterClassName: string,
leaveClassName: string) {
return entry.transition.build( return entry.transition.build(
this.driver, entry.element, entry.fromState.value, entry.toState.value, enterClassName, this.driver, entry.element, entry.fromState.value, entry.toState.value,
leaveClassName, entry.fromState.options, entry.toState.options, subTimelines); entry.fromState.options, entry.toState.options, subTimelines);
} }
destroyInnerAnimations(containerElement: any) { destroyInnerAnimations(containerElement: any) {
@ -802,13 +798,6 @@ export class TransitionAnimationEngine {
this.newHostElements.clear(); this.newHostElements.clear();
} }
if (this.totalAnimations && this.collectedEnterElements.length) {
for (let i = 0; i < this.collectedEnterElements.length; i++) {
const elm = this.collectedEnterElements[i];
addClass(elm, STAR_CLASSNAME);
}
}
if (this._namespaceList.length && if (this._namespaceList.length &&
(this.totalQueuedPlayers || this.collectedLeaveElements.length)) { (this.totalQueuedPlayers || this.collectedLeaveElements.length)) {
const cleanupFns: Function[] = []; const cleanupFns: Function[] = [];
@ -873,57 +862,37 @@ export class TransitionAnimationEngine {
}); });
const bodyNode = getBodyNode(); const bodyNode = getBodyNode();
const allTriggerElements = Array.from(this.statesByElement.keys()); const allEnterNodes: any[] = this.collectedEnterElements.length ?
const enterNodeMap = buildRootMap(allTriggerElements, this.collectedEnterElements); this.collectedEnterElements.filter(createIsRootFilterFn(this.collectedEnterElements)) :
[];
// this must occur before the instructions are built below such that // this must occur before the instructions are built below such that
// the :enter queries match the elements (since the timeline queries // the :enter queries match the elements (since the timeline queries
// are fired during instruction building). // are fired during instruction building).
const enterNodeMapIds = new Map<any, string>(); for (let i = 0; i < allEnterNodes.length; i++) {
let i = 0; addClass(allEnterNodes[i], ENTER_CLASSNAME);
enterNodeMap.forEach((nodes, root) => { }
const className = ENTER_CLASSNAME + i++;
enterNodeMapIds.set(root, className);
nodes.forEach(node => addClass(node, className));
});
const allLeaveNodes: any[] = []; const allLeaveNodes: any[] = [];
const mergedLeaveNodes = new Set<any>();
const leaveNodesWithoutAnimations = new Set<any>(); const leaveNodesWithoutAnimations = new Set<any>();
for (let i = 0; i < this.collectedLeaveElements.length; i++) { for (let i = 0; i < this.collectedLeaveElements.length; i++) {
const element = this.collectedLeaveElements[i]; const element = this.collectedLeaveElements[i];
const details = element[REMOVAL_FLAG] as ElementAnimationState; const details = element[REMOVAL_FLAG] as ElementAnimationState;
if (details && details.setForRemoval) { if (details && details.setForRemoval) {
addClass(element, LEAVE_CLASSNAME);
allLeaveNodes.push(element); allLeaveNodes.push(element);
mergedLeaveNodes.add(element); if (!details.hasAnimation) {
if (details.hasAnimation) {
this.driver.query(element, STAR_SELECTOR, true).forEach(elm => mergedLeaveNodes.add(elm));
} else {
leaveNodesWithoutAnimations.add(element); leaveNodesWithoutAnimations.add(element);
} }
} }
} }
const leaveNodeMapIds = new Map<any, string>();
const leaveNodeMap = buildRootMap(allTriggerElements, Array.from(mergedLeaveNodes));
leaveNodeMap.forEach((nodes, root) => {
const className = LEAVE_CLASSNAME + i++;
leaveNodeMapIds.set(root, className);
nodes.forEach(node => addClass(node, className));
});
cleanupFns.push(() => { cleanupFns.push(() => {
enterNodeMap.forEach((nodes, root) => { allEnterNodes.forEach(element => removeClass(element, ENTER_CLASSNAME));
const className = enterNodeMapIds.get(root) !; allLeaveNodes.forEach(element => {
nodes.forEach(node => removeClass(node, className)); removeClass(element, LEAVE_CLASSNAME);
this.processLeaveNode(element);
}); });
leaveNodeMap.forEach((nodes, root) => {
const className = leaveNodeMapIds.get(root) !;
nodes.forEach(node => removeClass(node, className));
});
allLeaveNodes.forEach(element => { this.processLeaveNode(element); });
}); });
const allPlayers: TransitionAnimationPlayer[] = []; const allPlayers: TransitionAnimationPlayer[] = [];
@ -940,10 +909,7 @@ export class TransitionAnimationEngine {
return; return;
} }
const leaveClassName = leaveNodeMapIds.get(element) !; const instruction = this._buildInstruction(entry, subTimelines) !;
const enterClassName = enterNodeMapIds.get(element) !;
const instruction =
this._buildInstruction(entry, subTimelines, enterClassName, leaveClassName) !;
if (instruction.errors && instruction.errors.length) { if (instruction.errors && instruction.errors.length) {
erroneousTransitions.push(instruction); erroneousTransitions.push(instruction);
return; return;
@ -1007,6 +973,18 @@ export class TransitionAnimationEngine {
this.reportError(errors); this.reportError(errors);
} }
// these can only be detected here since we have a map of all the elements
// that have animations attached to them... We use a set here in the event
// multiple enter captures on the same element were caught in different
// renderer namespaces (e.g. when a @trigger was on a host binding that had *ngIf)
const enterNodesWithoutAnimations = new Set<any>();
for (let i = 0; i < allEnterNodes.length; i++) {
const element = allEnterNodes[i];
if (!subTimelines.has(element)) {
enterNodesWithoutAnimations.add(element);
}
}
const allPreviousPlayersMap = new Map<any, TransitionAnimationPlayer[]>(); const allPreviousPlayersMap = new Map<any, TransitionAnimationPlayer[]>();
// this map works to tell which element in the DOM tree is contained by // this map works to tell which element in the DOM tree is contained by
// which animation. Further down below this map will get populated once // which animation. Further down below this map will get populated once
@ -1044,9 +1022,8 @@ export class TransitionAnimationEngine {
}); });
// POST STAGE: fill the * styles // POST STAGE: fill the * styles
const postStylesMap = new Map<any, ɵStyleData>(); const [postStylesMap, allLeaveQueriedNodes] = cloakAndComputeStyles(
const allLeaveQueriedNodes = cloakAndComputeStyles( this.driver, leaveNodesWithoutAnimations, allPostStyleElements, AUTO_STYLE);
postStylesMap, this.driver, leaveNodesWithoutAnimations, allPostStyleElements, AUTO_STYLE);
allLeaveQueriedNodes.forEach(node => { allLeaveQueriedNodes.forEach(node => {
if (replacePostStylesAsPre(node, allPreStyleElements, allPostStyleElements)) { if (replacePostStylesAsPre(node, allPreStyleElements, allPostStyleElements)) {
@ -1055,11 +1032,10 @@ export class TransitionAnimationEngine {
}); });
// PRE STAGE: fill the ! styles // PRE STAGE: fill the ! styles
const preStylesMap = new Map<any, ɵStyleData>(); const [preStylesMap] = allPreStyleElements.size ?
enterNodeMap.forEach((nodes, root) => {
cloakAndComputeStyles( cloakAndComputeStyles(
preStylesMap, this.driver, new Set(nodes), allPreStyleElements, PRE_STYLE); this.driver, enterNodesWithoutAnimations, allPreStyleElements, PRE_STYLE) :
}); [new Map<any, ɵStyleData>()];
replaceNodes.forEach(node => { replaceNodes.forEach(node => {
const post = postStylesMap.get(node); const post = postStylesMap.get(node);
@ -1529,11 +1505,12 @@ function cloakElement(element: any, value?: string) {
} }
function cloakAndComputeStyles( function cloakAndComputeStyles(
valuesMap: Map<any, ɵStyleData>, driver: AnimationDriver, elements: Set<any>, driver: AnimationDriver, elements: Set<any>, elementPropsMap: Map<any, Set<string>>,
elementPropsMap: Map<any, Set<string>>, defaultStyle: string): any[] { defaultStyle: string): [Map<any, ɵStyleData>, any[]] {
const cloakVals: string[] = []; const cloakVals: string[] = [];
elements.forEach(element => cloakVals.push(cloakElement(element))); elements.forEach(element => cloakVals.push(cloakElement(element)));
const valuesMap = new Map<any, ɵStyleData>();
const failedElements: any[] = []; const failedElements: any[] = [];
elementPropsMap.forEach((props: Set<string>, element: any) => { elementPropsMap.forEach((props: Set<string>, element: any) => {
@ -1555,57 +1532,39 @@ function cloakAndComputeStyles(
// an index value for the closure (but instead just the value) // an index value for the closure (but instead just the value)
let i = 0; let i = 0;
elements.forEach(element => cloakElement(element, cloakVals[i++])); elements.forEach(element => cloakElement(element, cloakVals[i++]));
return [valuesMap, failedElements];
return failedElements;
} }
/* /*
Since the Angular renderer code will return a collection of inserted Since the Angular renderer code will return a collection of inserted
nodes in all areas of a DOM tree, it's up to this algorithm to figure nodes in all areas of a DOM tree, it's up to this algorithm to figure
out which nodes are roots for each animation @trigger. out which nodes are roots.
By placing each inserted node into a Set and traversing upwards, it By placing all nodes into a set and traversing upwards to the edge,
is possible to find the @trigger elements and well any direct *star the recursive code can figure out if a clean path from the DOM node
insertion nodes, if a @trigger root is found then the enter element to the edge container is clear. If no other node is detected in the
is placed into the Map[@trigger] spot. set then it is a root element.
This algorithm also keeps track of all nodes along the path so that
if other sibling nodes are also tracked then the lookup process can
skip a lot of steps in between and avoid traversing the entire tree
multiple times to the edge.
*/ */
function buildRootMap(roots: any[], nodes: any[]): Map<any, any[]> { function createIsRootFilterFn(nodes: any): (node: any) => boolean {
const rootMap = new Map<any, any[]>();
roots.forEach(root => rootMap.set(root, []));
if (nodes.length == 0) return rootMap;
const NULL_NODE = 1;
const nodeSet = new Set(nodes); const nodeSet = new Set(nodes);
const localRootMap = new Map<any, any>(); const knownRootContainer = new Set();
let isRoot: (node: any) => boolean;
function getRoot(node: any): any { isRoot = node => {
if (!node) return NULL_NODE; if (!node) return true;
if (nodeSet.has(node.parentNode)) return false;
let root = localRootMap.get(node); if (knownRootContainer.has(node.parentNode)) return true;
if (root) return root; if (isRoot(node.parentNode)) {
knownRootContainer.add(node);
const parent = node.parentNode; return true;
if (rootMap.has(parent)) { // ngIf inside @trigger
root = parent;
} else if (nodeSet.has(parent)) { // ngIf inside ngIf
root = NULL_NODE;
} else { // recurse upwards
root = getRoot(parent);
} }
return false;
localRootMap.set(node, root); };
return root; return isRoot;
}
nodes.forEach(node => {
const root = getRoot(node);
if (root !== NULL_NODE) {
rootMap.get(root) !.push(node);
}
});
return rootMap;
} }
const CLASSES_CACHE_KEY = '$$classes'; const CLASSES_CACHE_KEY = '$$classes';

View File

@ -10,7 +10,6 @@ import {AnimationOptions, animate, state, style, transition} from '@angular/anim
import {AnimationTransitionInstruction} from '@angular/animations/browser/src/dsl/animation_transition_instruction'; import {AnimationTransitionInstruction} from '@angular/animations/browser/src/dsl/animation_transition_instruction';
import {AnimationTrigger} from '@angular/animations/browser/src/dsl/animation_trigger'; import {AnimationTrigger} from '@angular/animations/browser/src/dsl/animation_trigger';
import {ENTER_CLASSNAME, LEAVE_CLASSNAME} from '../../src/util';
import {MockAnimationDriver} from '../../testing'; import {MockAnimationDriver} from '../../testing';
import {makeTrigger} from '../shared'; import {makeTrigger} from '../shared';
@ -229,9 +228,7 @@ function buildTransition(
const trans = trigger.matchTransition(fromState, toState) !; const trans = trigger.matchTransition(fromState, toState) !;
if (trans) { if (trans) {
const driver = new MockAnimationDriver(); const driver = new MockAnimationDriver();
return trans.build( return trans.build(driver, element, fromState, toState, fromOptions, toOptions) !;
driver, element, fromState, toState, ENTER_CLASSNAME, LEAVE_CLASSNAME, fromOptions,
toOptions) !;
} }
return null; return null;
} }

View File

@ -62,8 +62,8 @@ export class NoopAnimationPlayer implements AnimationPlayer {
init(): void {} init(): void {}
play(): void { play(): void {
if (!this.hasStarted()) { if (!this.hasStarted()) {
this._onStart();
this.triggerMicrotask(); this.triggerMicrotask();
this._onStart();
} }
this._started = true; this._started = true;
} }

View File

@ -6,9 +6,9 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {fakeAsync} from '@angular/core/testing'; import {fakeAsync} from '@angular/core/testing';
import {flushMicrotasks} from '../../core/testing/src/fake_async'; import {flushMicrotasks} from '../../core/testing/src/fake_async';
import {NoopAnimationPlayer} from '../src/players/animation_player'; import {NoopAnimationPlayer} from '../src/players/animation_player';
import {scheduleMicroTask} from '../src/util';
export function main() { export function main() {
describe('NoopAnimationPlayer', function() { describe('NoopAnimationPlayer', function() {
@ -61,21 +61,6 @@ export function main() {
player.finish(); player.finish();
expect(log).toEqual(['started', 'done']); expect(log).toEqual(['started', 'done']);
flushMicrotasks();
expect(log).toEqual(['started', 'done']);
}));
it('should fire off start callbacks before triggering the finish callback', fakeAsync(() => {
const log: string[] = [];
const player = new NoopAnimationPlayer();
player.onStart(() => { scheduleMicroTask(() => log.push('started')); });
player.onDone(() => log.push('done'));
expect(log).toEqual([]);
player.play();
expect(log).toEqual([]);
flushMicrotasks(); flushMicrotasks();
expect(log).toEqual(['started', 'done']); expect(log).toEqual(['started', 'done']);
})); }));

View File

@ -6,10 +6,10 @@
"license": "MIT", "license": "MIT",
"peerDependencies": { "peerDependencies": {
"@angular/compiler-cli": "0.0.0-PLACEHOLDER", "@angular/compiler-cli": "0.0.0-PLACEHOLDER",
"typescript": ">=2.4.2 <2.6" "typescript": ">=2.4.2 <2.5"
}, },
"dependencies": { "dependencies": {
"@bazel/typescript": "0.3.2", "@bazel/typescript": "0.2.x",
"@types/node": "6.0.84" "@types/node": "6.0.84"
}, },
"repository": { "repository": {

View File

@ -5,7 +5,8 @@
* Use of this source code is governed by an MIT-style license that can be * 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 * found in the LICENSE file at https://angular.io/license
*/ */
// TODO(tbosch): figure out why we need this as it breaks node code within ngc-wrapped
/// <reference types="node" />
import * as ng from '@angular/compiler-cli'; import * as ng from '@angular/compiler-cli';
import {BazelOptions, CachedFileLoader, CompilerHost, FileCache, FileLoader, UncachedFileLoader, constructManifest, debug, fixUmdModuleDeclarations, parseTsconfig, runAsWorker, runWorkerLoop} from '@bazel/typescript'; import {BazelOptions, CachedFileLoader, CompilerHost, FileCache, FileLoader, UncachedFileLoader, constructManifest, debug, fixUmdModuleDeclarations, parseTsconfig, runAsWorker, runWorkerLoop} from '@bazel/typescript';
import * as fs from 'fs'; import * as fs from 'fs';
@ -164,19 +165,11 @@ export function compile({allowNonHermeticReads, allDepsCompiledWithBazel = true,
} }
return origBazelHostFileExist.call(bazelHost, fileName); return origBazelHostFileExist.call(bazelHost, fileName);
}; };
const origBazelHostShouldNameModule = bazelHost.shouldNameModule.bind(bazelHost);
bazelHost.shouldNameModule = (fileName: string) =>
origBazelHostShouldNameModule(fileName) || NGC_GEN_FILES.test(fileName);
const ngHost = ng.createCompilerHost({options: compilerOpts, tsHost: bazelHost}); const ngHost = ng.createCompilerHost({options: compilerOpts, tsHost: bazelHost});
ngHost.fileNameToModuleName = (importedFilePath: string, containingFilePath: string) => { ngHost.fileNameToModuleName = (importedFilePath: string, containingFilePath: string) =>
if ((compilerOpts.module === ts.ModuleKind.UMD || compilerOpts.module === ts.ModuleKind.AMD) && relativeToRootDirs(importedFilePath, compilerOpts.rootDirs).replace(EXT, '');
ngHost.amdModuleName) {
return ngHost.amdModuleName({ fileName: importedFilePath } as ts.SourceFile);
}
return relativeToRootDirs(importedFilePath, compilerOpts.rootDirs).replace(EXT, '');
};
ngHost.toSummaryFileName = (fileName: string, referringSrcFileName: string) => ngHost.toSummaryFileName = (fileName: string, referringSrcFileName: string) =>
ngHost.fileNameToModuleName(fileName, referringSrcFileName); ngHost.fileNameToModuleName(fileName, referringSrcFileName);
if (allDepsCompiledWithBazel) { if (allDepsCompiledWithBazel) {

View File

@ -64,10 +64,6 @@ export function createTsConfig(options: TsConfigOptions) {
'es5Mode': true, 'es5Mode': true,
'manifest': createManifestPath(options), 'manifest': createManifestPath(options),
'compilationTargetSrc': options.compilationTargetSrc, 'compilationTargetSrc': options.compilationTargetSrc,
// Override this property from the real tsconfig we read
// Because we ask for :empty_tsconfig.json, we get the ES6 version which
// expects to write externs, yet that doesn't work under this fixture.
'tsickleExternsPath': '',
}, },
'files': options.files, 'files': options.files,
'angularCompilerOptions': { 'angularCompilerOptions': {

View File

@ -81,9 +81,7 @@ export class Runner {
{provide: WebDriverAdapter, useValue: adapter} {provide: WebDriverAdapter, useValue: adapter}
]); ]);
// TODO: With TypeScript 2.5 injector.get does not infer correctly the const sampler = injector.get(Sampler);
// return type. Remove 'any' and investigate the issue.
const sampler = injector.get(Sampler) as any;
return sampler.sample(); return sampler.sample();
}); });
} }

View File

@ -17,7 +17,7 @@ export function main() {
ids.map(id => ({provide: id, useValue: new MockMetric(id)})), ids.map(id => ({provide: id, useValue: new MockMetric(id)})),
MultiMetric.provideWith(ids) MultiMetric.provideWith(ids)
]) ])
.get<MultiMetric>(MultiMetric); .get(MultiMetric);
return Promise.resolve(m); return Promise.resolve(m);
} }

View File

@ -34,7 +34,7 @@ export function main() {
} }
} }
]; ];
return Injector.create(providers).get<JsonFileReporter>(JsonFileReporter); return Injector.create(providers).get(JsonFileReporter);
} }
it('should write all data into a file', it('should write all data into a file',

View File

@ -17,7 +17,7 @@ export function main() {
ids.map(id => ({provide: id, useValue: new MockReporter(id)})), ids.map(id => ({provide: id, useValue: new MockReporter(id)})),
MultiReporter.provideWith(ids) MultiReporter.provideWith(ids)
]) ])
.get<MultiReporter>(MultiReporter); .get(MultiReporter);
return Promise.resolve(r); return Promise.resolve(r);
} }

View File

@ -352,11 +352,13 @@ export class HttpClient {
// Figure out the headers. // Figure out the headers.
let headers: HttpHeaders|undefined = undefined; let headers: HttpHeaders|undefined = undefined;
if (!!options.headers !== undefined) {
if (options.headers instanceof HttpHeaders) { if (options.headers instanceof HttpHeaders) {
headers = options.headers; headers = options.headers;
} else { } else {
headers = new HttpHeaders(options.headers); headers = new HttpHeaders(options.headers);
} }
}
// Sort out parameters. // Sort out parameters.
let params: HttpParams|undefined = undefined; let params: HttpParams|undefined = undefined;
@ -369,7 +371,7 @@ export class HttpClient {
} }
// Construct the request. // Construct the request.
req = new HttpRequest(first, url !, (options.body !== undefined ? options.body : null), { req = new HttpRequest(first, url !, options.body || null, {
headers, headers,
params, params,
reportProgress: options.reportProgress, reportProgress: options.reportProgress,

View File

@ -171,7 +171,7 @@ export class HttpRequest<T> {
// the body argument is to use a known no-body method like GET. // the body argument is to use a known no-body method like GET.
if (mightHaveBody(this.method) || !!fourth) { if (mightHaveBody(this.method) || !!fourth) {
// Body is the third argument, options are the fourth. // Body is the third argument, options are the fourth.
this.body = (third !== undefined) ? third as T : null; this.body = third as T || null;
options = fourth; options = fourth;
} else { } else {
// No body required, options are the third argument. The body stays null. // No body required, options are the third argument. The body stays null.

View File

@ -262,7 +262,7 @@ export class HttpResponse<T> extends HttpResponseBase {
body?: T | null, headers?: HttpHeaders; status?: number; statusText?: string; url?: string; body?: T | null, headers?: HttpHeaders; status?: number; statusText?: string; url?: string;
} = {}) { } = {}) {
super(init); super(init);
this.body = init.body !== undefined ? init.body : null; this.body = init.body || null;
} }
readonly type: HttpEventType.Response = HttpEventType.Response; readonly type: HttpEventType.Response = HttpEventType.Response;

View File

@ -180,27 +180,24 @@ export class HttpXhrBackend implements HttpBackend {
// Check whether the body needs to be parsed as JSON (in many cases the browser // Check whether the body needs to be parsed as JSON (in many cases the browser
// will have done that already). // will have done that already).
if (req.responseType === 'json' && typeof body === 'string') { if (ok && req.responseType === 'json' && typeof body === 'string') {
// Save the original body, before attempting XSSI prefix stripping. // Attempt the parse. If it fails, a parse error should be delivered to the user.
const originalBody = body;
body = body.replace(XSSI_PREFIX, ''); body = body.replace(XSSI_PREFIX, '');
try { try {
// Attempt the parse. If it fails, a parse error should be delivered to the user. body = JSON.parse(body);
body = body !== '' ? JSON.parse(body) : null;
} catch (error) { } catch (error) {
// Since the JSON.parse failed, it's reasonable to assume this might not have been a
// JSON response. Restore the original body (including any XSSI prefix) to deliver
// a better error response.
body = originalBody;
// If this was an error request to begin with, leave it as a string, it probably
// just isn't JSON. Otherwise, deliver the parsing error to the user.
if (ok) {
// Even though the response status was 2xx, this is still an error. // Even though the response status was 2xx, this is still an error.
ok = false; ok = false;
// The parse error contains the text of the body that failed to parse. // The parse error contains the text of the body that failed to parse.
body = { error, text: body } as HttpJsonParseError; body = { error, text: body } as HttpJsonParseError;
} }
} else if (!ok && req.responseType === 'json' && typeof body === 'string') {
try {
// Attempt to parse the body as JSON.
body = JSON.parse(body);
} catch (error) {
// Cannot be certain that the body was meant to be parsed as JSON.
// Leave the body as a string.
} }
} }

View File

@ -115,26 +115,6 @@ export function main() {
expect(testReq.request.body).toBe(body); expect(testReq.request.body).toBe(body);
testReq.flush('hello world'); testReq.flush('hello world');
}); });
it('with a json body of false', (done: DoneFn) => {
client.post('/test', false, {observe: 'response', responseType: 'text'}).subscribe(res => {
expect(res.ok).toBeTruthy();
expect(res.status).toBe(200);
done();
});
const testReq = backend.expectOne('/test');
expect(testReq.request.body).toBe(false);
testReq.flush('hello world');
});
it('with a json body of 0', (done: DoneFn) => {
client.post('/test', 0, {observe: 'response', responseType: 'text'}).subscribe(res => {
expect(res.ok).toBeTruthy();
expect(res.status).toBe(200);
done();
});
const testReq = backend.expectOne('/test');
expect(testReq.request.body).toBe(0);
testReq.flush('hello world');
});
it('with an arraybuffer', (done: DoneFn) => { it('with an arraybuffer', (done: DoneFn) => {
const body = new ArrayBuffer(4); const body = new ArrayBuffer(4);
client.post('/test', body, {observe: 'response', responseType: 'text'}).subscribe(res => { client.post('/test', body, {observe: 'response', responseType: 'text'}).subscribe(res => {

View File

@ -40,10 +40,6 @@ export function main() {
expect(resp.ok).toBeTruthy(); expect(resp.ok).toBeTruthy();
expect(resp.url).toBeNull(); expect(resp.url).toBeNull();
}); });
it('accepts a falsy body', () => {
expect(new HttpResponse({body: false}).body).toEqual(false);
expect(new HttpResponse({body: 0}).body).toEqual(0);
});
}); });
it('.ok is determined by status', () => { it('.ok is determined by status', () => {
const good = new HttpResponse({status: 200}); const good = new HttpResponse({status: 200});

View File

@ -25,8 +25,6 @@ const TEST_POST = new HttpRequest('POST', '/test', 'some body', {
responseType: 'text', responseType: 'text',
}); });
const XSSI_PREFIX = ')]}\'\n';
export function main() { export function main() {
describe('XhrBackend', () => { describe('XhrBackend', () => {
let factory: MockXhrFactory = null !; let factory: MockXhrFactory = null !;
@ -94,13 +92,6 @@ export function main() {
const res = events[1] as HttpResponse<{data: string}>; const res = events[1] as HttpResponse<{data: string}>;
expect(res.body !.data).toBe('some data'); expect(res.body !.data).toBe('some data');
}); });
it('handles a blank json response', () => {
const events = trackEvents(backend.handle(TEST_POST.clone({responseType: 'json'})));
factory.mock.mockFlush(200, 'OK', '');
expect(events.length).toBe(2);
const res = events[1] as HttpResponse<{data: string}>;
expect(res.body).toBeNull();
});
it('handles a json error response', () => { it('handles a json error response', () => {
const events = trackEvents(backend.handle(TEST_POST.clone({responseType: 'json'}))); const events = trackEvents(backend.handle(TEST_POST.clone({responseType: 'json'})));
factory.mock.mockFlush(500, 'Error', JSON.stringify({data: 'some data'})); factory.mock.mockFlush(500, 'Error', JSON.stringify({data: 'some data'}));
@ -108,13 +99,6 @@ export function main() {
const res = events[1] as any as HttpErrorResponse; const res = events[1] as any as HttpErrorResponse;
expect(res.error !.data).toBe('some data'); expect(res.error !.data).toBe('some data');
}); });
it('handles a json error response with XSSI prefix', () => {
const events = trackEvents(backend.handle(TEST_POST.clone({responseType: 'json'})));
factory.mock.mockFlush(500, 'Error', XSSI_PREFIX + JSON.stringify({data: 'some data'}));
expect(events.length).toBe(2);
const res = events[1] as any as HttpErrorResponse;
expect(res.error !.data).toBe('some data');
});
it('handles a json string response', () => { it('handles a json string response', () => {
const events = trackEvents(backend.handle(TEST_POST.clone({responseType: 'json'}))); const events = trackEvents(backend.handle(TEST_POST.clone({responseType: 'json'})));
expect(factory.mock.responseType).toEqual('text'); expect(factory.mock.responseType).toEqual('text');
@ -125,7 +109,7 @@ export function main() {
}); });
it('handles a json response with an XSSI prefix', () => { it('handles a json response with an XSSI prefix', () => {
const events = trackEvents(backend.handle(TEST_POST.clone({responseType: 'json'}))); const events = trackEvents(backend.handle(TEST_POST.clone({responseType: 'json'})));
factory.mock.mockFlush(200, 'OK', XSSI_PREFIX + JSON.stringify({data: 'some data'})); factory.mock.mockFlush(200, 'OK', ')]}\'\n' + JSON.stringify({data: 'some data'}));
expect(events.length).toBe(2); expect(events.length).toBe(2);
const res = events[1] as HttpResponse<{data: string}>; const res = events[1] as HttpResponse<{data: string}>;
expect(res.body !.data).toBe('some data'); expect(res.body !.data).toBe('some data');

View File

@ -4895,5 +4895,6 @@ switch (goog.LOCALE) {
} }
if (l) { if (l) {
registerLocaleData(l, goog.LOCALE); l[0] = goog.LOCALE;
registerLocaleData(l);
} }

View File

@ -17,17 +17,9 @@ export const LOCALE_DATA: {[localeId: string]: any} = {};
* *
* @experimental i18n support is experimental. * @experimental i18n support is experimental.
*/ */
// The signature registerLocaleData(data: any, extraData?: any) is deprecated since v5.1 export function registerLocaleData(data: any, extraData?: any) {
export function registerLocaleData(data: any, localeId?: string | any, extraData?: any): void { const localeId = data[LocaleDataIndex.LocaleId].toLowerCase().replace(/_/g, '-');
if (typeof localeId !== 'string') {
extraData = localeId;
localeId = data[LocaleDataIndex.LocaleId];
}
localeId = localeId.toLowerCase().replace(/_/g, '-');
LOCALE_DATA[localeId] = data; LOCALE_DATA[localeId] = data;
if (extraData) { if (extraData) {
LOCALE_DATA[localeId][LocaleDataIndex.ExtraData] = extraData; LOCALE_DATA[localeId][LocaleDataIndex.ExtraData] = extraData;
} }

View File

@ -10,8 +10,8 @@ import localeCaESVALENCIA from '../../locales/ca-ES-VALENCIA';
import localeEn from '../../locales/en'; import localeEn from '../../locales/en';
import localeFr from '../../locales/fr'; import localeFr from '../../locales/fr';
import localeFrCA from '../../locales/fr-CA'; import localeFrCA from '../../locales/fr-CA';
import {registerLocaleData} from '../../src/i18n/locale_data';
import {findLocaleData} from '../../src/i18n/locale_data_api'; import {findLocaleData} from '../../src/i18n/locale_data_api';
import {registerLocaleData} from '../../src/i18n/locale_data';
export function main() { export function main() {
describe('locale data api', () => { describe('locale data api', () => {
@ -20,8 +20,6 @@ export function main() {
registerLocaleData(localeEn); registerLocaleData(localeEn);
registerLocaleData(localeFr); registerLocaleData(localeFr);
registerLocaleData(localeFrCA); registerLocaleData(localeFrCA);
registerLocaleData(localeFr, 'fake-id');
registerLocaleData(localeFrCA, 'fake_Id2');
}); });
describe('findLocaleData', () => { describe('findLocaleData', () => {
@ -44,12 +42,6 @@ export function main() {
expect(findLocaleData('ca-ES-VALENCIA')).toEqual(localeCaESVALENCIA); expect(findLocaleData('ca-ES-VALENCIA')).toEqual(localeCaESVALENCIA);
expect(findLocaleData('CA_es_Valencia')).toEqual(localeCaESVALENCIA); expect(findLocaleData('CA_es_Valencia')).toEqual(localeCaESVALENCIA);
}); });
it(`should find the LOCALE_DATA if the locale id was registered`, () => {
expect(findLocaleData('fake-id')).toEqual(localeFr);
expect(findLocaleData('fake_iD')).toEqual(localeFr);
expect(findLocaleData('fake-id2')).toEqual(localeFrCA);
});
}); });
}); });
} }

View File

@ -42,9 +42,7 @@ export class SpyLocation implements Location {
return currPath == givenPath + (query.length > 0 ? ('?' + query) : ''); return currPath == givenPath + (query.length > 0 ? ('?' + query) : '');
} }
simulateUrlPop(pathname: string) { simulateUrlPop(pathname: string) { this._subject.emit({'url': pathname, 'pop': true}); }
this._subject.emit({'url': pathname, 'pop': true, 'type': 'popstate'});
}
simulateHashChange(pathname: string) { simulateHashChange(pathname: string) {
// Because we don't prevent the native event, the browser will independently update the path // Because we don't prevent the native event, the browser will independently update the path

View File

@ -11,11 +11,11 @@
"dependencies": { "dependencies": {
"reflect-metadata": "^0.1.2", "reflect-metadata": "^0.1.2",
"minimist": "^1.2.0", "minimist": "^1.2.0",
"tsickle": "^0.25.5", "tsickle": "^0.24.0",
"chokidar": "^1.4.2" "chokidar": "^1.4.2"
}, },
"peerDependencies": { "peerDependencies": {
"typescript": ">=2.4.2 <2.6", "typescript": ">=2.4.2 <2.5",
"@angular/compiler": "0.0.0-PLACEHOLDER" "@angular/compiler": "0.0.0-PLACEHOLDER"
}, },
"repository": { "repository": {

View File

@ -20,6 +20,7 @@ import {GENERATED_FILES} from './transformers/util';
import {exitCodeFromResult, performCompilation, readConfiguration, formatDiagnostics, Diagnostics, ParsedConfiguration, PerformCompilationResult, filterErrorsAndWarnings} from './perform_compile'; import {exitCodeFromResult, performCompilation, readConfiguration, formatDiagnostics, Diagnostics, ParsedConfiguration, PerformCompilationResult, filterErrorsAndWarnings} from './perform_compile';
import {performWatchCompilation, createPerformWatchHost} from './perform_watch'; import {performWatchCompilation, createPerformWatchHost} from './perform_watch';
import {isSyntaxError} from '@angular/compiler';
export function main( export function main(
args: string[], consoleError: (s: string) => void = console.error, args: string[], consoleError: (s: string) => void = console.error,

View File

@ -8,8 +8,8 @@
import * as ts from 'typescript'; import * as ts from 'typescript';
import {Evaluator, errorSymbol, recordMapEntry} from './evaluator'; import {Evaluator, errorSymbol} from './evaluator';
import {ClassMetadata, ConstructorMetadata, FunctionMetadata, InterfaceMetadata, METADATA_VERSION, MemberMetadata, MetadataEntry, MetadataError, MetadataMap, MetadataSymbolicBinaryExpression, MetadataSymbolicCallExpression, MetadataSymbolicExpression, MetadataSymbolicIfExpression, MetadataSymbolicIndexExpression, MetadataSymbolicPrefixExpression, MetadataSymbolicReferenceExpression, MetadataSymbolicSelectExpression, MetadataSymbolicSpreadExpression, MetadataValue, MethodMetadata, ModuleExportMetadata, ModuleMetadata, isClassMetadata, isConstructorMetadata, isFunctionMetadata, isMetadataError, isMetadataGlobalReferenceExpression, isMetadataImportDefaultReference, isMetadataImportedSymbolReferenceExpression, isMetadataSymbolicExpression, isMetadataSymbolicReferenceExpression, isMetadataSymbolicSelectExpression, isMethodMetadata} from './schema'; import {ClassMetadata, ConstructorMetadata, FunctionMetadata, InterfaceMetadata, METADATA_VERSION, MemberMetadata, MetadataEntry, MetadataError, MetadataMap, MetadataSymbolicBinaryExpression, MetadataSymbolicCallExpression, MetadataSymbolicExpression, MetadataSymbolicIfExpression, MetadataSymbolicIndexExpression, MetadataSymbolicPrefixExpression, MetadataSymbolicReferenceExpression, MetadataSymbolicSelectExpression, MetadataSymbolicSpreadExpression, MetadataValue, MethodMetadata, ModuleExportMetadata, ModuleMetadata, isClassMetadata, isConstructorMetadata, isFunctionMetadata, isMetadataError, isMetadataGlobalReferenceExpression, isMetadataSymbolicExpression, isMetadataSymbolicReferenceExpression, isMetadataSymbolicSelectExpression, isMethodMetadata} from './schema';
import {Symbols} from './symbols'; import {Symbols} from './symbols';
const isStatic = (node: ts.Node) => ts.getCombinedModifierFlags(node) & ts.ModifierFlags.Static; const isStatic = (node: ts.Node) => ts.getCombinedModifierFlags(node) & ts.ModifierFlags.Static;
@ -76,7 +76,8 @@ export class MetadataCollector {
} }
function recordEntry<T extends MetadataEntry>(entry: T, node: ts.Node): T { function recordEntry<T extends MetadataEntry>(entry: T, node: ts.Node): T {
return recordMapEntry(entry, node, nodeMap, sourceFile); nodeMap.set(entry, node);
return entry;
} }
function errorSym( function errorSym(
@ -115,8 +116,8 @@ export class MetadataCollector {
function classMetadataOf(classDeclaration: ts.ClassDeclaration): ClassMetadata { function classMetadataOf(classDeclaration: ts.ClassDeclaration): ClassMetadata {
const result: ClassMetadata = {__symbolic: 'class'}; const result: ClassMetadata = {__symbolic: 'class'};
function getDecorators(decorators: ReadonlyArray<ts.Decorator>| undefined): function getDecorators(decorators: ts.Decorator[] | undefined): MetadataSymbolicExpression[]|
MetadataSymbolicExpression[]|undefined { undefined {
if (decorators && decorators.length) if (decorators && decorators.length)
return decorators.map(decorator => objFromDecorator(decorator)); return decorators.map(decorator => objFromDecorator(decorator));
return undefined; return undefined;
@ -550,7 +551,6 @@ export class MetadataCollector {
__symbolic: 'module', __symbolic: 'module',
version: this.options.version || METADATA_VERSION, metadata version: this.options.version || METADATA_VERSION, metadata
}; };
if (sourceFile.moduleName) result.importAs = sourceFile.moduleName;
if (exports) result.exports = exports; if (exports) result.exports = exports;
return result; return result;
} }

View File

@ -9,11 +9,10 @@
import * as ts from 'typescript'; import * as ts from 'typescript';
import {CollectorOptions} from './collector'; import {CollectorOptions} from './collector';
import {ClassMetadata, FunctionMetadata, InterfaceMetadata, MetadataEntry, MetadataError, MetadataImportedSymbolReferenceExpression, MetadataSourceLocationInfo, MetadataSymbolicCallExpression, MetadataValue, isMetadataError, isMetadataGlobalReferenceExpression, isMetadataImportDefaultReference, isMetadataImportedSymbolReferenceExpression, isMetadataModuleReferenceExpression, isMetadataSymbolicReferenceExpression, isMetadataSymbolicSpreadExpression} from './schema'; import {MetadataEntry, MetadataError, MetadataImportedSymbolReferenceExpression, MetadataSymbolicCallExpression, MetadataValue, isMetadataError, isMetadataGlobalReferenceExpression, isMetadataModuleReferenceExpression, isMetadataSymbolicReferenceExpression, isMetadataSymbolicSpreadExpression} from './schema';
import {Symbols} from './symbols'; import {Symbols} from './symbols';
// In TypeScript 2.1 the spread element kind was renamed. // In TypeScript 2.1 the spread element kind was renamed.
const spreadElementSyntaxKind: ts.SyntaxKind = const spreadElementSyntaxKind: ts.SyntaxKind =
(ts.SyntaxKind as any).SpreadElement || (ts.SyntaxKind as any).SpreadElementExpression; (ts.SyntaxKind as any).SpreadElement || (ts.SyntaxKind as any).SpreadElementExpression;
@ -39,24 +38,6 @@ function isCallOf(callExpression: ts.CallExpression, ident: string): boolean {
return false; return false;
} }
/* @internal */
export function recordMapEntry<T extends MetadataEntry>(
entry: T, node: ts.Node,
nodeMap: Map<MetadataValue|ClassMetadata|InterfaceMetadata|FunctionMetadata, ts.Node>,
sourceFile?: ts.SourceFile) {
if (!nodeMap.has(entry)) {
nodeMap.set(entry, node);
if (node && (isMetadataImportedSymbolReferenceExpression(entry) ||
isMetadataImportDefaultReference(entry)) &&
entry.line == null) {
const info = sourceInfo(node, sourceFile);
if (info.line != null) entry.line = info.line;
if (info.character != null) entry.character = info.character;
}
}
return entry;
}
/** /**
* ts.forEachChild stops iterating children when the callback return a truthy value. * ts.forEachChild stops iterating children when the callback return a truthy value.
* This method inverts this to implement an `every` style iterator. It will return * This method inverts this to implement an `every` style iterator. It will return
@ -95,23 +76,22 @@ function getSourceFileOfNode(node: ts.Node | undefined): ts.SourceFile {
return <ts.SourceFile>node; return <ts.SourceFile>node;
} }
/* @internal */
export function sourceInfo(
node: ts.Node | undefined, sourceFile: ts.SourceFile | undefined): MetadataSourceLocationInfo {
if (node) {
sourceFile = sourceFile || getSourceFileOfNode(node);
if (sourceFile) {
return ts.getLineAndCharacterOfPosition(sourceFile, node.getStart(sourceFile));
}
}
return {};
}
/* @internal */ /* @internal */
export function errorSymbol( export function errorSymbol(
message: string, node?: ts.Node, context?: {[name: string]: string}, message: string, node?: ts.Node, context?: {[name: string]: string},
sourceFile?: ts.SourceFile): MetadataError { sourceFile?: ts.SourceFile): MetadataError {
const result: MetadataError = {__symbolic: 'error', message, ...sourceInfo(node, sourceFile)}; let result: MetadataError|undefined = undefined;
if (node) {
sourceFile = sourceFile || getSourceFileOfNode(node);
if (sourceFile) {
const {line, character} =
ts.getLineAndCharacterOfPosition(sourceFile, node.getStart(sourceFile));
result = {__symbolic: 'error', message, line, character};
}
}
if (!result) {
result = {__symbolic: 'error', message};
}
if (context) { if (context) {
result.context = context; result.context = context;
} }
@ -262,7 +242,8 @@ export class Evaluator {
} }
entry = newEntry; entry = newEntry;
} }
return recordMapEntry(entry, node, t.nodeMap); t.nodeMap.set(entry, node);
return entry;
} }
function isFoldableError(value: any): value is MetadataError { function isFoldableError(value: any): value is MetadataError {
@ -275,9 +256,6 @@ export class Evaluator {
// Encode as a global reference. StaticReflector will check the reference. // Encode as a global reference. StaticReflector will check the reference.
return recordEntry({__symbolic: 'reference', name}, node); return recordEntry({__symbolic: 'reference', name}, node);
} }
if (reference && isMetadataSymbolicReferenceExpression(reference)) {
return recordEntry({...reference}, node);
}
return reference; return reference;
}; };
@ -650,7 +628,7 @@ export class Evaluator {
return recordEntry({__symbolic: 'if', condition, thenExpression, elseExpression}, node); return recordEntry({__symbolic: 'if', condition, thenExpression, elseExpression}, node);
case ts.SyntaxKind.FunctionExpression: case ts.SyntaxKind.FunctionExpression:
case ts.SyntaxKind.ArrowFunction: case ts.SyntaxKind.ArrowFunction:
return recordEntry(errorSymbol('Lambda not supported', node), node); return recordEntry(errorSymbol('Function call not supported', node), node);
case ts.SyntaxKind.TaggedTemplateExpression: case ts.SyntaxKind.TaggedTemplateExpression:
return recordEntry( return recordEntry(
errorSymbol('Tagged template expressions are not supported in metadata', node), node); errorSymbol('Tagged template expressions are not supported in metadata', node), node);

View File

@ -178,20 +178,7 @@ export function isMetadataSymbolicIfExpression(value: any): value is MetadataSym
return value && value.__symbolic === 'if'; return value && value.__symbolic === 'if';
} }
export interface MetadataSourceLocationInfo { export interface MetadataGlobalReferenceExpression extends MetadataSymbolicExpression {
/**
* The line number of the error in the .ts file the metadata was created for.
*/
line?: number;
/**
* The number of utf8 code-units from the beginning of the file of the error.
*/
character?: number;
}
export interface MetadataGlobalReferenceExpression extends MetadataSymbolicExpression,
MetadataSourceLocationInfo {
__symbolic: 'reference'; __symbolic: 'reference';
name: string; name: string;
arguments?: MetadataValue[]; arguments?: MetadataValue[];
@ -201,8 +188,7 @@ export function isMetadataGlobalReferenceExpression(value: any):
return value && value.name && !value.module && isMetadataSymbolicReferenceExpression(value); return value && value.name && !value.module && isMetadataSymbolicReferenceExpression(value);
} }
export interface MetadataModuleReferenceExpression extends MetadataSymbolicExpression, export interface MetadataModuleReferenceExpression extends MetadataSymbolicExpression {
MetadataSourceLocationInfo {
__symbolic: 'reference'; __symbolic: 'reference';
module: string; module: string;
} }
@ -212,8 +198,7 @@ export function isMetadataModuleReferenceExpression(value: any):
isMetadataSymbolicReferenceExpression(value); isMetadataSymbolicReferenceExpression(value);
} }
export interface MetadataImportedSymbolReferenceExpression extends MetadataSymbolicExpression, export interface MetadataImportedSymbolReferenceExpression extends MetadataSymbolicExpression {
MetadataSourceLocationInfo {
__symbolic: 'reference'; __symbolic: 'reference';
module: string; module: string;
name: string; name: string;
@ -224,8 +209,7 @@ export function isMetadataImportedSymbolReferenceExpression(value: any):
return value && value.module && !!value.name && isMetadataSymbolicReferenceExpression(value); return value && value.module && !!value.name && isMetadataSymbolicReferenceExpression(value);
} }
export interface MetadataImportedDefaultReferenceExpression extends MetadataSymbolicExpression, export interface MetadataImportedDefaultReferenceExpression extends MetadataSymbolicExpression {
MetadataSourceLocationInfo {
__symbolic: 'reference'; __symbolic: 'reference';
module: string; module: string;
default: default:
@ -234,7 +218,7 @@ export interface MetadataImportedDefaultReferenceExpression extends MetadataSymb
} }
export function isMetadataImportDefaultReference(value: any): export function isMetadataImportDefaultReference(value: any):
value is MetadataImportedDefaultReferenceExpression { value is MetadataImportedDefaultReferenceExpression {
return value && value.module && value.default && isMetadataSymbolicReferenceExpression(value); return value.module && value.default && isMetadataSymbolicReferenceExpression(value);
} }
export type MetadataSymbolicReferenceExpression = MetadataGlobalReferenceExpression | export type MetadataSymbolicReferenceExpression = MetadataGlobalReferenceExpression |
@ -264,7 +248,7 @@ export function isMetadataSymbolicSpreadExpression(value: any):
return value && value.__symbolic === 'spread'; return value && value.__symbolic === 'spread';
} }
export interface MetadataError extends MetadataSourceLocationInfo { export interface MetadataError {
__symbolic: 'error'; __symbolic: 'error';
/** /**
@ -275,6 +259,16 @@ export interface MetadataError extends MetadataSourceLocationInfo {
*/ */
message: string; message: string;
/**
* The line number of the error in the .ts file the metadata was created for.
*/
line?: number;
/**
* The number of utf8 code-units from the beginning of the file of the error.
*/
character?: number;
/** /**
* The module of the error (only used in bundled metadata) * The module of the error (only used in bundled metadata)
*/ */
@ -286,7 +280,6 @@ export interface MetadataError extends MetadataSourceLocationInfo {
*/ */
context?: {[name: string]: string}; context?: {[name: string]: string};
} }
export function isMetadataError(value: any): value is MetadataError { export function isMetadataError(value: any): value is MetadataError {
return value && value.__symbolic === 'error'; return value && value.__symbolic === 'error';
} }

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {Position, isSyntaxError, syntaxError} from '@angular/compiler'; import {isSyntaxError, syntaxError} from '@angular/compiler';
import * as fs from 'fs'; import * as fs from 'fs';
import * as path from 'path'; import * as path from 'path';
import * as ts from 'typescript'; import * as ts from 'typescript';
@ -29,77 +29,31 @@ const defaultFormatHost: ts.FormatDiagnosticsHost = {
getNewLine: () => ts.sys.newLine getNewLine: () => ts.sys.newLine
}; };
function displayFileName(fileName: string, host: ts.FormatDiagnosticsHost): string {
return path.relative(host.getCurrentDirectory(), host.getCanonicalFileName(fileName));
}
export function formatDiagnosticPosition(
position: Position, host: ts.FormatDiagnosticsHost = defaultFormatHost): string {
return `${displayFileName(position.fileName, host)}(${position.line + 1},${position.column+1})`;
}
export function flattenDiagnosticMessageChain(
chain: api.DiagnosticMessageChain, host: ts.FormatDiagnosticsHost = defaultFormatHost): string {
let result = chain.messageText;
let indent = 1;
let current = chain.next;
const newLine = host.getNewLine();
while (current) {
result += newLine;
for (let i = 0; i < indent; i++) {
result += ' ';
}
result += current.messageText;
const position = current.position;
if (position) {
result += ` at ${formatDiagnosticPosition(position, host)}`;
}
current = current.next;
indent++;
}
return result;
}
export function formatDiagnostic(
diagnostic: api.Diagnostic, host: ts.FormatDiagnosticsHost = defaultFormatHost) {
let result = '';
const newLine = host.getNewLine();
const span = diagnostic.span;
if (span) {
result += `${formatDiagnosticPosition({
fileName: span.start.file.url,
line: span.start.line,
column: span.start.col
}, host)}: `;
} else if (diagnostic.position) {
result += `${formatDiagnosticPosition(diagnostic.position, host)}: `;
}
if (diagnostic.span && diagnostic.span.details) {
result += `: ${diagnostic.span.details}, ${diagnostic.messageText}${newLine}`;
} else if (diagnostic.chain) {
result += `${flattenDiagnosticMessageChain(diagnostic.chain, host)}.${newLine}`;
} else {
result += `: ${diagnostic.messageText}${newLine}`;
}
return result;
}
export function formatDiagnostics( export function formatDiagnostics(
diags: Diagnostics, host: ts.FormatDiagnosticsHost = defaultFormatHost): string { diags: Diagnostics, tsFormatHost: ts.FormatDiagnosticsHost = defaultFormatHost): string {
if (diags && diags.length) { if (diags && diags.length) {
return diags return diags
.map(diagnostic => { .map(d => {
if (api.isTsDiagnostic(diagnostic)) { if (api.isTsDiagnostic(d)) {
return ts.formatDiagnostics([diagnostic], host); return ts.formatDiagnostics([d], tsFormatHost);
} else { } else {
return formatDiagnostic(diagnostic, host); let res = ts.DiagnosticCategory[d.category];
if (d.span) {
res +=
` at ${d.span.start.file.url}(${d.span.start.line + 1},${d.span.start.col + 1})`;
}
if (d.span && d.span.details) {
res += `: ${d.span.details}, ${d.messageText}\n`;
} else {
res += `: ${d.messageText}\n`;
}
return res;
} }
}) })
.join(''); .join('');
} else { } else
return ''; return '';
} }
}
export interface ParsedConfiguration { export interface ParsedConfiguration {
project: string; project: string;

View File

@ -6,24 +6,16 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {GeneratedFile, ParseSourceSpan, Position} from '@angular/compiler'; import {GeneratedFile, ParseSourceSpan} from '@angular/compiler';
import * as ts from 'typescript'; import * as ts from 'typescript';
export const DEFAULT_ERROR_CODE = 100; export const DEFAULT_ERROR_CODE = 100;
export const UNKNOWN_ERROR_CODE = 500; export const UNKNOWN_ERROR_CODE = 500;
export const SOURCE = 'angular' as 'angular'; export const SOURCE = 'angular' as 'angular';
export interface DiagnosticMessageChain {
messageText: string;
position?: Position;
next?: DiagnosticMessageChain;
}
export interface Diagnostic { export interface Diagnostic {
messageText: string; messageText: string;
span?: ParseSourceSpan; span?: ParseSourceSpan;
position?: Position;
chain?: DiagnosticMessageChain;
category: ts.DiagnosticCategory; category: ts.DiagnosticCategory;
code: number; code: number;
source: 'angular'; source: 'angular';
@ -200,13 +192,6 @@ export interface CompilerHost extends ts.CompilerHost {
* cause a diagnostics diagnostic error or an exception to be thrown. * cause a diagnostics diagnostic error or an exception to be thrown.
*/ */
readResource?(fileName: string): Promise<string>|string; readResource?(fileName: string): Promise<string>|string;
/**
* Produce an AMD module name for the source file. Used in Bazel.
*
* An AMD module can have an arbitrary name, so that it is require'd by name
* rather than by path. See http://requirejs.org/docs/whyamd.html#namedmodules
*/
amdModuleName?(sf: ts.SourceFile): string|undefined;
} }
export enum EmitFlags { export enum EmitFlags {

View File

@ -41,13 +41,6 @@ export interface CodeGenerator {
findGeneratedFileNames(fileName: string): string[]; findGeneratedFileNames(fileName: string): string[];
} }
function assert<T>(condition: T | null | undefined) {
if (!condition) {
// TODO(chuckjaz): do the right thing
}
return condition !;
}
/** /**
* Implements the following hosts based on an api.CompilerHost: * Implements the following hosts based on an api.CompilerHost:
* - ts.CompilerHost to be consumed by a ts.Program * - ts.CompilerHost to be consumed by a ts.Program
@ -120,7 +113,7 @@ export class TsCompilerAotCompilerTypeCheckHostAdapter implements ts.CompilerHos
return sf ? this.metadataProvider.getMetadata(sf) : undefined; return sf ? this.metadataProvider.getMetadata(sf) : undefined;
}, },
fileExists: (filePath) => this.originalFileExists(filePath), fileExists: (filePath) => this.originalFileExists(filePath),
readFile: (filePath) => assert(this.context.readFile(filePath)), readFile: (filePath) => this.context.readFile(filePath),
}; };
} }
@ -303,11 +296,6 @@ export class TsCompilerAotCompilerTypeCheckHostAdapter implements ts.CompilerHos
/* emitSourceMaps */ false); /* emitSourceMaps */ false);
const sf = ts.createSourceFile( const sf = ts.createSourceFile(
genFile.genFileUrl, sourceText, this.options.target || ts.ScriptTarget.Latest); genFile.genFileUrl, sourceText, this.options.target || ts.ScriptTarget.Latest);
if ((this.options.module === ts.ModuleKind.AMD || this.options.module === ts.ModuleKind.UMD) &&
this.context.amdModuleName) {
const moduleName = this.context.amdModuleName(sf);
if (moduleName) sf.moduleName = moduleName;
}
this.generatedSourceFiles.set(genFile.genFileUrl, { this.generatedSourceFiles.set(genFile.genFileUrl, {
sourceFile: sf, sourceFile: sf,
emitCtx: context, externalReferences, emitCtx: context, externalReferences,
@ -433,7 +421,7 @@ export class TsCompilerAotCompilerTypeCheckHostAdapter implements ts.CompilerHos
return summary.text; return summary.text;
} }
if (this.originalFileExists(filePath)) { if (this.originalFileExists(filePath)) {
return assert(this.context.readFile(filePath)); return this.context.readFile(filePath);
} }
return null; return null;
} }
@ -484,7 +472,7 @@ export class TsCompilerAotCompilerTypeCheckHostAdapter implements ts.CompilerHos
if (!this.originalFileExists(filePath)) { if (!this.originalFileExists(filePath)) {
throw syntaxError(`Error: Resource file not found: ${filePath}`); throw syntaxError(`Error: Resource file not found: ${filePath}`);
} }
return assert(this.context.readFile(filePath)); return this.context.readFile(filePath);
} }
private hasBundleIndex(filePath: string): boolean { private hasBundleIndex(filePath: string): boolean {
@ -502,13 +490,13 @@ export class TsCompilerAotCompilerTypeCheckHostAdapter implements ts.CompilerHos
if (this.originalFileExists(packageFile)) { if (this.originalFileExists(packageFile)) {
// Once we see a package.json file, assume false until it we find the bundle index. // Once we see a package.json file, assume false until it we find the bundle index.
result = false; result = false;
const packageContent: any = JSON.parse(assert(this.context.readFile(packageFile))); const packageContent: any = JSON.parse(this.context.readFile(packageFile));
if (packageContent.typings) { if (packageContent.typings) {
const typings = path.normalize(path.join(directory, packageContent.typings)); const typings = path.normalize(path.join(directory, packageContent.typings));
if (DTS.test(typings)) { if (DTS.test(typings)) {
const metadataFile = typings.replace(DTS, '.metadata.json'); const metadataFile = typings.replace(DTS, '.metadata.json');
if (this.originalFileExists(metadataFile)) { if (this.originalFileExists(metadataFile)) {
const metadata = JSON.parse(assert(this.context.readFile(metadataFile))); const metadata = JSON.parse(this.context.readFile(metadataFile));
if (metadata.flatModuleIndexRedirect) { if (metadata.flatModuleIndexRedirect) {
this.flatModuleIndexRedirectNames.add(typings); this.flatModuleIndexRedirectNames.add(typings);
// Note: don't set result = true, // Note: don't set result = true,

View File

@ -112,7 +112,6 @@ function upgradeMetadataWithDtsData(
newMetadata.metadata[prop] = dtsMetadata.metadata[prop]; newMetadata.metadata[prop] = dtsMetadata.metadata[prop];
} }
} }
if (dtsMetadata['importAs']) newMetadata['importAs'] = dtsMetadata['importAs'];
// Only copy exports from exports from metadata prior to version 3. // Only copy exports from exports from metadata prior to version 3.
// Starting with version 3 the collector began collecting exports and // Starting with version 3 the collector began collecting exports and

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {AotCompiler, AotCompilerHost, AotCompilerOptions, EmitterVisitorContext, FormattedMessageChain, GeneratedFile, MessageBundle, NgAnalyzedFile, NgAnalyzedModules, ParseSourceSpan, Position, Serializer, TypeScriptEmitter, Xliff, Xliff2, Xmb, core, createAotCompiler, getParseErrors, isFormattedError, isSyntaxError} from '@angular/compiler'; import {AotCompiler, AotCompilerHost, AotCompilerOptions, EmitterVisitorContext, GeneratedFile, MessageBundle, NgAnalyzedFile, NgAnalyzedModules, ParseSourceSpan, Serializer, TypeScriptEmitter, Xliff, Xliff2, Xmb, core, createAotCompiler, getParseErrors, isSyntaxError} from '@angular/compiler';
import * as fs from 'fs'; import * as fs from 'fs';
import * as path from 'path'; import * as path from 'path';
import * as ts from 'typescript'; import * as ts from 'typescript';
@ -14,13 +14,14 @@ import * as ts from 'typescript';
import {TypeCheckHost, translateDiagnostics} from '../diagnostics/translate_diagnostics'; import {TypeCheckHost, translateDiagnostics} from '../diagnostics/translate_diagnostics';
import {ModuleMetadata, createBundleIndexHost} from '../metadata/index'; import {ModuleMetadata, createBundleIndexHost} from '../metadata/index';
import {CompilerHost, CompilerOptions, CustomTransformers, DEFAULT_ERROR_CODE, Diagnostic, DiagnosticMessageChain, EmitFlags, LazyRoute, LibrarySummary, Program, SOURCE, TsEmitArguments, TsEmitCallback} from './api'; import {CompilerHost, CompilerOptions, CustomTransformers, DEFAULT_ERROR_CODE, Diagnostic, EmitFlags, LazyRoute, LibrarySummary, Program, SOURCE, TsEmitArguments, TsEmitCallback} from './api';
import {CodeGenerator, TsCompilerAotCompilerTypeCheckHostAdapter, getOriginalReferences} from './compiler_host'; import {CodeGenerator, TsCompilerAotCompilerTypeCheckHostAdapter, getOriginalReferences} from './compiler_host';
import {LowerMetadataCache, getExpressionLoweringTransformFactory} from './lower_expressions'; import {LowerMetadataCache, getExpressionLoweringTransformFactory} from './lower_expressions';
import {getAngularEmitterTransformFactory} from './node_emitter_transform'; import {getAngularEmitterTransformFactory} from './node_emitter_transform';
import {GENERATED_FILES, StructureIsReused, createMessageDiagnostic, isInRootDir, ngToTsDiagnostic, tsStructureIsReused} from './util'; import {GENERATED_FILES, StructureIsReused, createMessageDiagnostic, isInRootDir, ngToTsDiagnostic, tsStructureIsReused} from './util';
/** /**
* Maximum number of files that are emitable via calling ts.Program.emit * Maximum number of files that are emitable via calling ts.Program.emit
* passing individual targetSourceFiles. * passing individual targetSourceFiles.
@ -61,7 +62,7 @@ class AngularCompilerProgram implements Program {
constructor( constructor(
private rootNames: string[], private options: CompilerOptions, private host: CompilerHost, private rootNames: string[], private options: CompilerOptions, private host: CompilerHost,
oldProgram?: Program) { private oldProgram?: Program) {
const [major, minor] = ts.version.split('.'); const [major, minor] = ts.version.split('.');
if (Number(major) < 2 || (Number(major) === 2 && Number(minor) < 4)) { if (Number(major) < 2 || (Number(major) === 2 && Number(minor) < 4)) {
throw new Error('The Angular Compiler requires TypeScript >= 2.4.'); throw new Error('The Angular Compiler requires TypeScript >= 2.4.');
@ -377,12 +378,10 @@ class AngularCompilerProgram implements Program {
} }
private get structuralDiagnostics(): Diagnostic[] { private get structuralDiagnostics(): Diagnostic[] {
let diagnostics = this._structuralDiagnostics; if (!this._structuralDiagnostics) {
if (!diagnostics) {
this.initSync(); this.initSync();
diagnostics = (this._structuralDiagnostics = this._structuralDiagnostics || []);
} }
return diagnostics; return this._structuralDiagnostics !;
} }
private get tsProgram(): ts.Program { private get tsProgram(): ts.Program {
@ -431,9 +430,16 @@ class AngularCompilerProgram implements Program {
this.rootNames, this.options, this.host, this.metadataCache, codegen, this.rootNames, this.options, this.host, this.metadataCache, codegen,
this.oldProgramLibrarySummaries); this.oldProgramLibrarySummaries);
const aotOptions = getAotCompilerOptions(this.options); const aotOptions = getAotCompilerOptions(this.options);
const errorCollector = (this.options.collectAllErrors || this.options.fullTemplateTypeCheck) ? this._structuralDiagnostics = [];
(err: any) => this._addStructuralDiagnostics(err) : const errorCollector =
undefined; (this.options.collectAllErrors || this.options.fullTemplateTypeCheck) ? (err: any) => {
this._structuralDiagnostics !.push({
messageText: err.toString(),
category: ts.DiagnosticCategory.Error,
source: SOURCE,
code: DEFAULT_ERROR_CODE
});
} : undefined;
this._compiler = createAotCompiler(this._hostAdapter, aotOptions, errorCollector).compiler; this._compiler = createAotCompiler(this._hostAdapter, aotOptions, errorCollector).compiler;
} }
@ -516,24 +522,31 @@ class AngularCompilerProgram implements Program {
this._hostAdapter.isSourceFile = () => false; this._hostAdapter.isSourceFile = () => false;
this._tsProgram = ts.createProgram(this.rootNames, this.options, this.hostAdapter); this._tsProgram = ts.createProgram(this.rootNames, this.options, this.hostAdapter);
if (isSyntaxError(e)) { if (isSyntaxError(e)) {
this._addStructuralDiagnostics(e); const parserErrors = getParseErrors(e);
return; if (parserErrors && parserErrors.length) {
} this._structuralDiagnostics = [
throw e; ...(this._structuralDiagnostics || []),
} ...parserErrors.map<Diagnostic>(e => ({
messageText: e.contextualMessage(),
private _addStructuralDiagnostics(error: Error) { category: ts.DiagnosticCategory.Error,
const diagnostics = this._structuralDiagnostics || (this._structuralDiagnostics = []); span: e.span,
if (isSyntaxError(error)) { source: SOURCE,
diagnostics.push(...syntaxErrorToDiagnostics(error)); code: DEFAULT_ERROR_CODE
}))
];
} else { } else {
diagnostics.push({ this._structuralDiagnostics = [
messageText: error.toString(), ...(this._structuralDiagnostics || []), {
messageText: e.message,
category: ts.DiagnosticCategory.Error, category: ts.DiagnosticCategory.Error,
source: SOURCE, source: SOURCE,
code: DEFAULT_ERROR_CODE code: DEFAULT_ERROR_CODE
});
} }
];
}
return;
}
throw e;
} }
// Note: this returns a ts.Diagnostic so that we // Note: this returns a ts.Diagnostic so that we
@ -593,8 +606,7 @@ class AngularCompilerProgram implements Program {
private writeFile( private writeFile(
outFileName: string, outData: string, writeByteOrderMark: boolean, outFileName: string, outData: string, writeByteOrderMark: boolean,
onError?: (message: string) => void, genFile?: GeneratedFile, onError?: (message: string) => void, genFile?: GeneratedFile, sourceFiles?: ts.SourceFile[]) {
sourceFiles?: ReadonlyArray<ts.SourceFile>) {
// collect emittedLibrarySummaries // collect emittedLibrarySummaries
let baseFile: ts.SourceFile|undefined; let baseFile: ts.SourceFile|undefined;
if (genFile) { if (genFile) {
@ -641,8 +653,7 @@ class AngularCompilerProgram implements Program {
if (baseFile) { if (baseFile) {
sourceFiles = sourceFiles ? [...sourceFiles, baseFile] : [baseFile]; sourceFiles = sourceFiles ? [...sourceFiles, baseFile] : [baseFile];
} }
// TODO: remove any when TS 2.4 support is removed. this.host.writeFile(outFileName, outData, writeByteOrderMark, onError, sourceFiles);
this.host.writeFile(outFileName, outData, writeByteOrderMark, onError, sourceFiles as any);
} }
} }
@ -790,16 +801,9 @@ export function i18nSerialize(
default: default:
serializer = new Xliff(); serializer = new Xliff();
} }
return bundle.write(
return bundle.write(serializer, getPathNormalizer(options.basePath)); serializer, (sourcePath: string) =>
} options.basePath ? path.relative(options.basePath, sourcePath) : sourcePath);
function getPathNormalizer(basePath?: string) {
// normalize sourcepaths by removing the base path and always using "/" as a separator
return (sourcePath: string) => {
sourcePath = basePath ? path.relative(basePath, sourcePath) : sourcePath;
return sourcePath.split(path.sep).join('/');
};
} }
export function i18nGetExtension(formatName: string): string { export function i18nGetExtension(formatName: string): string {
@ -830,56 +834,3 @@ function mergeEmitResults(emitResults: ts.EmitResult[]): ts.EmitResult {
} }
return {diagnostics, emitSkipped, emittedFiles}; return {diagnostics, emitSkipped, emittedFiles};
} }
function diagnosticSourceOfSpan(span: ParseSourceSpan): ts.SourceFile {
// For diagnostics, TypeScript only uses the fileName and text properties.
// The redundant '()' are here is to avoid having clang-format breaking the line incorrectly.
return ({ fileName: span.start.file.url, text: span.start.file.content } as any);
}
function diagnosticSourceOfFileName(fileName: string, program: ts.Program): ts.SourceFile {
const sourceFile = program.getSourceFile(fileName);
if (sourceFile) return sourceFile;
// If we are reporting diagnostics for a source file that is not in the project then we need
// to fake a source file so the diagnostic formatting routines can emit the file name.
// The redundant '()' are here is to avoid having clang-format breaking the line incorrectly.
return ({ fileName, text: '' } as any);
}
function diagnosticChainFromFormattedDiagnosticChain(chain: FormattedMessageChain):
DiagnosticMessageChain {
return {
messageText: chain.message,
next: chain.next && diagnosticChainFromFormattedDiagnosticChain(chain.next),
position: chain.position
};
}
function syntaxErrorToDiagnostics(error: Error): Diagnostic[] {
const parserErrors = getParseErrors(error);
if (parserErrors && parserErrors.length) {
return parserErrors.map<Diagnostic>(e => ({
messageText: e.contextualMessage(),
file: diagnosticSourceOfSpan(e.span),
start: e.span.start.offset,
length: e.span.end.offset - e.span.start.offset,
category: ts.DiagnosticCategory.Error,
source: SOURCE,
code: DEFAULT_ERROR_CODE
}));
} else {
if (isFormattedError(error)) {
return [{
messageText: error.message,
chain: error.chain && diagnosticChainFromFormattedDiagnosticChain(error.chain),
category: ts.DiagnosticCategory.Error,
source: SOURCE,
code: DEFAULT_ERROR_CODE,
position: error.position
}];
}
}
return [];
}

View File

@ -27,7 +27,7 @@ describe('metadata bundler', () => {
const originalOne = './src/one'; const originalOne = './src/one';
const originalTwo = './src/two/index'; const originalTwo = './src/two/index';
expect(Object.keys(result.metadata.origins !) expect(Object.keys(result.metadata.origins)
.sort() .sort()
.map(name => ({name, value: result.metadata.origins ![name]}))) .map(name => ({name, value: result.metadata.origins ![name]})))
.toEqual([ .toEqual([

View File

@ -45,7 +45,6 @@ describe('Collector', () => {
're-exports.ts', 're-exports.ts',
're-exports-2.ts', 're-exports-2.ts',
'export-as.d.ts', 'export-as.d.ts',
'named-module.d.ts',
'static-field-reference.ts', 'static-field-reference.ts',
'static-method.ts', 'static-method.ts',
'static-method-call.ts', 'static-method-call.ts',
@ -102,12 +101,6 @@ describe('Collector', () => {
}); });
}); });
it('should preserve module names from TypeScript sources', () => {
const sourceFile = program.getSourceFile('named-module.d.ts');
const metadata = collector.getMetadata(sourceFile);
expect(metadata !['importAs']).toEqual('some-named-module');
});
it('should be able to collect a simple component\'s metadata', () => { it('should be able to collect a simple component\'s metadata', () => {
const sourceFile = program.getSourceFile('app/hero-detail.component.ts'); const sourceFile = program.getSourceFile('app/hero-detail.component.ts');
const metadata = collector.getMetadata(sourceFile); const metadata = collector.getMetadata(sourceFile);
@ -119,13 +112,7 @@ describe('Collector', () => {
__symbolic: 'class', __symbolic: 'class',
decorators: [{ decorators: [{
__symbolic: 'call', __symbolic: 'call',
expression: { expression: {__symbolic: 'reference', module: 'angular2/core', name: 'Component'},
__symbolic: 'reference',
module: 'angular2/core',
name: 'Component',
line: 4,
character: 7
},
arguments: [{ arguments: [{
selector: 'my-hero-detail', selector: 'my-hero-detail',
template: ` template: `
@ -145,13 +132,8 @@ describe('Collector', () => {
__symbolic: 'property', __symbolic: 'property',
decorators: [{ decorators: [{
__symbolic: 'call', __symbolic: 'call',
expression: { expression:
__symbolic: 'reference', {__symbolic: 'reference', module: 'angular2/core', name: 'Input'}
module: 'angular2/core',
name: 'Input',
line: 18,
character: 9
}
}] }]
}] }]
} }
@ -171,13 +153,7 @@ describe('Collector', () => {
__symbolic: 'class', __symbolic: 'class',
decorators: [{ decorators: [{
__symbolic: 'call', __symbolic: 'call',
expression: { expression: {__symbolic: 'reference', module: 'angular2/core', name: 'Component'},
__symbolic: 'reference',
module: 'angular2/core',
name: 'Component',
line: 9,
character: 7
},
arguments: [{ arguments: [{
selector: 'my-app', selector: 'my-app',
template: ` template: `
@ -196,52 +172,20 @@ describe('Collector', () => {
__symbolic: 'reference', __symbolic: 'reference',
module: './hero-detail.component', module: './hero-detail.component',
name: 'HeroDetailComponent', name: 'HeroDetailComponent',
line: 22,
character: 21
}, },
{ {__symbolic: 'reference', module: 'angular2/common', name: 'NgFor'}
__symbolic: 'reference',
module: 'angular2/common',
name: 'NgFor',
line: 22,
character: 42
}
], ],
providers: [{ providers: [{__symbolic: 'reference', module: './hero.service', default: true}],
__symbolic: 'reference',
module: './hero.service',
default: true,
line: 23,
character: 20
}],
pipes: [ pipes: [
{ {__symbolic: 'reference', module: 'angular2/common', name: 'LowerCasePipe'},
__symbolic: 'reference', {__symbolic: 'reference', module: 'angular2/common', name: 'UpperCasePipe'}
module: 'angular2/common',
name: 'LowerCasePipe',
line: 24,
character: 16
},
{
__symbolic: 'reference',
module: 'angular2/common',
name: 'UpperCasePipe',
line: 24,
character: 38
}
] ]
}] }]
}], }],
members: { members: {
__ctor__: [{ __ctor__: [{
__symbolic: 'constructor', __symbolic: 'constructor',
parameters: [{ parameters: [{__symbolic: 'reference', module: './hero.service', default: true}]
__symbolic: 'reference',
module: './hero.service',
default: true,
line: 31,
character: 42
}]
}], }],
onSelect: [{__symbolic: 'method'}], onSelect: [{__symbolic: 'method'}],
ngOnInit: [{__symbolic: 'method'}], ngOnInit: [{__symbolic: 'method'}],
@ -292,23 +236,22 @@ describe('Collector', () => {
}); });
it('should record annotations on set and get declarations', () => { it('should record annotations on set and get declarations', () => {
const propertyData = (line: number) => ({ const propertyData = {
name: [{ name: [{
__symbolic: 'property', __symbolic: 'property',
decorators: [{ decorators: [{
__symbolic: 'call', __symbolic: 'call',
expression: expression: {__symbolic: 'reference', module: 'angular2/core', name: 'Input'},
{__symbolic: 'reference', module: 'angular2/core', name: 'Input', line, character: 9},
arguments: ['firstName'] arguments: ['firstName']
}] }]
}] }]
}); };
const caseGetProp = <ClassMetadata>casesMetadata.metadata['GetProp']; const caseGetProp = <ClassMetadata>casesMetadata.metadata['GetProp'];
expect(caseGetProp.members).toEqual(propertyData(11)); expect(caseGetProp.members).toEqual(propertyData);
const caseSetProp = <ClassMetadata>casesMetadata.metadata['SetProp']; const caseSetProp = <ClassMetadata>casesMetadata.metadata['SetProp'];
expect(caseSetProp.members).toEqual(propertyData(19)); expect(caseSetProp.members).toEqual(propertyData);
const caseFullProp = <ClassMetadata>casesMetadata.metadata['FullProp']; const caseFullProp = <ClassMetadata>casesMetadata.metadata['FullProp'];
expect(caseFullProp.members).toEqual(propertyData(27)); expect(caseFullProp.members).toEqual(propertyData);
}); });
it('should record references to parameterized types', () => { it('should record references to parameterized types', () => {
@ -317,13 +260,7 @@ describe('Collector', () => {
__symbolic: 'class', __symbolic: 'class',
decorators: [{ decorators: [{
__symbolic: 'call', __symbolic: 'call',
expression: { expression: {__symbolic: 'reference', module: 'angular2/core', name: 'Injectable'}
__symbolic: 'reference',
module: 'angular2/core',
name: 'Injectable',
line: 40,
character: 7
}
}], }],
members: { members: {
__ctor__: [{ __ctor__: [{
@ -376,7 +313,7 @@ describe('Collector', () => {
const ctor = <ConstructorMetadata>someClass.members !['__ctor__'][0]; const ctor = <ConstructorMetadata>someClass.members !['__ctor__'][0];
const parameters = ctor.parameters; const parameters = ctor.parameters;
expect(parameters).toEqual([ expect(parameters).toEqual([
{__symbolic: 'reference', module: 'angular2/common', name: 'NgFor', line: 6, character: 29} {__symbolic: 'reference', module: 'angular2/common', name: 'NgFor'}
]); ]);
}); });
@ -461,7 +398,7 @@ describe('Collector', () => {
const ctor = <ConstructorMetadata>someClass.members !['__ctor__'][0]; const ctor = <ConstructorMetadata>someClass.members !['__ctor__'][0];
const parameters = ctor.parameters; const parameters = ctor.parameters;
expect(parameters).toEqual([ expect(parameters).toEqual([
{__symbolic: 'reference', module: 'angular2/common', name: 'NgFor', line: 6, character: 29} {__symbolic: 'reference', module: 'angular2/common', name: 'NgFor'}
]); ]);
}); });
@ -490,13 +427,7 @@ describe('Collector', () => {
B: 1, B: 1,
C: 30, C: 30,
D: 40, D: 40,
E: { E: {__symbolic: 'reference', module: './exported-consts', name: 'constValue'}
__symbolic: 'reference',
module: './exported-consts',
name: 'constValue',
line: 5,
character: 75
}
}); });
}); });
@ -526,25 +457,13 @@ describe('Collector', () => {
expect(classData).toBeDefined(); expect(classData).toBeDefined();
expect(classData.decorators).toEqual([{ expect(classData.decorators).toEqual([{
__symbolic: 'call', __symbolic: 'call',
expression: { expression: {__symbolic: 'reference', module: 'angular2/core', name: 'Component'},
__symbolic: 'reference',
module: 'angular2/core',
name: 'Component',
line: 4,
character: 5
},
arguments: [{ arguments: [{
providers: { providers: {
__symbolic: 'call', __symbolic: 'call',
expression: { expression: {
__symbolic: 'select', __symbolic: 'select',
expression: { expression: {__symbolic: 'reference', module: './static-method', name: 'MyModule'},
__symbolic: 'reference',
module: './static-method',
name: 'MyModule',
line: 5,
character: 17
},
member: 'with' member: 'with'
}, },
arguments: ['a'] arguments: ['a']
@ -570,25 +489,13 @@ describe('Collector', () => {
expect(classData).toBeDefined(); expect(classData).toBeDefined();
expect(classData.decorators).toEqual([{ expect(classData.decorators).toEqual([{
__symbolic: 'call', __symbolic: 'call',
expression: { expression: {__symbolic: 'reference', module: 'angular2/core', name: 'Component'},
__symbolic: 'reference',
module: 'angular2/core',
name: 'Component',
line: 4,
character: 5
},
arguments: [{ arguments: [{
providers: [{ providers: [{
provide: 'a', provide: 'a',
useValue: { useValue: {
__symbolic: 'select', __symbolic: 'select',
expression: { expression: {__symbolic: 'reference', module: './static-field', name: 'MyModule'},
__symbolic: 'reference',
module: './static-field',
name: 'MyModule',
line: 5,
character: 45
},
member: 'VALUE' member: 'VALUE'
} }
}] }]
@ -671,20 +578,8 @@ describe('Collector', () => {
const metadata = collector.getMetadata(source) !; const metadata = collector.getMetadata(source) !;
expect(metadata.metadata).toEqual({ expect(metadata.metadata).toEqual({
MyClass: Object({__symbolic: 'class'}), MyClass: Object({__symbolic: 'class'}),
OtherModule: { OtherModule: {__symbolic: 'reference', module: './static-field-reference', name: 'Foo'},
__symbolic: 'reference', MyOtherModule: {__symbolic: 'reference', module: './static-field', name: 'MyModule'}
module: './static-field-reference',
name: 'Foo',
line: 4,
character: 12
},
MyOtherModule: {
__symbolic: 'reference',
module: './static-field',
name: 'MyModule',
line: 4,
character: 25
}
}); });
}); });
@ -703,13 +598,7 @@ describe('Collector', () => {
__symbolic: 'class', __symbolic: 'class',
decorators: [{ decorators: [{
__symbolic: 'call', __symbolic: 'call',
expression: { expression: {__symbolic: 'reference', module: 'angular2/core', name: 'Component'},
__symbolic: 'reference',
module: 'angular2/core',
name: 'Component',
line: 11,
character: 5
},
arguments: [{providers: [{__symbolic: 'reference', name: 'REQUIRED_VALIDATOR'}]}] arguments: [{providers: [{__symbolic: 'reference', name: 'REQUIRED_VALIDATOR'}]}]
}] }]
} }
@ -731,13 +620,7 @@ describe('Collector', () => {
__symbolic: 'class', __symbolic: 'class',
decorators: [{ decorators: [{
__symbolic: 'call', __symbolic: 'call',
expression: { expression: {__symbolic: 'reference', module: 'angular2/core', name: 'Component'},
__symbolic: 'reference',
module: 'angular2/core',
name: 'Component',
line: 11,
character: 5
},
arguments: [{providers: [{__symbolic: 'reference', name: 'REQUIRED_VALIDATOR'}]}] arguments: [{providers: [{__symbolic: 'reference', name: 'REQUIRED_VALIDATOR'}]}]
}] }]
} }
@ -770,13 +653,7 @@ describe('Collector', () => {
__symbolic: 'constructor', __symbolic: 'constructor',
parameterDecorators: [[{ parameterDecorators: [[{
__symbolic: 'call', __symbolic: 'call',
expression: { expression: {__symbolic: 'reference', module: 'angular2/core', name: 'Inject'},
__symbolic: 'reference',
module: 'angular2/core',
name: 'Inject',
line: 6,
character: 19
},
arguments: ['a'] arguments: ['a']
}]], }]],
parameters: [{__symbolic: 'reference', name: 'any'}] parameters: [{__symbolic: 'reference', name: 'any'}]
@ -810,20 +687,13 @@ describe('Collector', () => {
__symbolic: 'reference', __symbolic: 'reference',
module: './external', module: './external',
name: 'external', name: 'external',
line: 0,
character: 68,
} }
}); });
}); });
it('should simplify a redundant template', () => { it('should simplify a redundant template', () => {
e('`${external}`', 'import {external} from "./external";').toEqual({ e('`${external}`', 'import {external} from "./external";')
__symbolic: 'reference', .toEqual({__symbolic: 'reference', module: './external', name: 'external'});
module: './external',
name: 'external',
line: 0,
character: 59
});
}); });
it('should be able to collect complex template with imported references', () => { it('should be able to collect complex template with imported references', () => {
@ -840,18 +710,11 @@ describe('Collector', () => {
__symbolic: 'binop', __symbolic: 'binop',
operator: '+', operator: '+',
left: 'foo:', left: 'foo:',
right: { right: {__symbolic: 'reference', module: './external', name: 'foo'}
__symbolic: 'reference',
module: './external',
name: 'foo',
line: 0,
character: 63
}
}, },
right: ', bar:' right: ', bar:'
}, },
right: right: {__symbolic: 'reference', module: './external', name: 'bar'}
{__symbolic: 'reference', module: './external', name: 'bar', line: 0, character: 75}
}, },
right: ', end' right: ', end'
}); });
@ -878,11 +741,11 @@ describe('Collector', () => {
__ctor__: [{ __ctor__: [{
__symbolic: 'constructor', __symbolic: 'constructor',
parameters: [ parameters: [
{__symbolic: 'reference', module: './foo', name: 'Foo', line: 3, character: 24}, {__symbolic: 'reference', module: './foo', name: 'Foo'},
{__symbolic: 'reference', module: './foo', name: 'Foo', line: 3, character: 24}, {__symbolic: 'reference', module: './foo', name: 'Foo'},
{__symbolic: 'reference', module: './foo', name: 'Foo', line: 3, character: 24}, {__symbolic: 'reference', module: './foo', name: 'Foo'},
{__symbolic: 'reference', module: './foo', name: 'Foo', line: 3, character: 24}, {__symbolic: 'reference', module: './foo', name: 'Foo'},
{__symbolic: 'reference', module: './foo', name: 'Foo', line: 3, character: 24} {__symbolic: 'reference', module: './foo', name: 'Foo'}
] ]
}] }]
}); });
@ -962,9 +825,7 @@ describe('Collector', () => {
extends: { extends: {
__symbolic: 'reference', __symbolic: 'reference',
module: './class-inheritance-parent', module: './class-inheritance-parent',
name: 'ParentClassFromOtherFile', name: 'ParentClassFromOtherFile'
line: 9,
character: 45,
} }
}); });
}); });
@ -1522,10 +1383,6 @@ const FILES: Directory = {
'export-as.d.ts': ` 'export-as.d.ts': `
declare function someFunction(): void; declare function someFunction(): void;
export { someFunction as SomeFunction }; export { someFunction as SomeFunction };
`,
'named-module.d.ts': `
/// <amd-module name="some-named-module" />
export type SomeType = 'a';
`, `,
'local-symbol-ref.ts': ` 'local-symbol-ref.ts': `
import {Component, Validators} from 'angular2/core'; import {Component, Validators} from 'angular2/core';

View File

@ -149,14 +149,12 @@ describe('Evaluator', () => {
const newExpression = program.getSourceFile('newExpression.ts'); const newExpression = program.getSourceFile('newExpression.ts');
expect(evaluator.evaluateNode(findVarInitializer(newExpression, 'someValue'))).toEqual({ expect(evaluator.evaluateNode(findVarInitializer(newExpression, 'someValue'))).toEqual({
__symbolic: 'new', __symbolic: 'new',
expression: expression: {__symbolic: 'reference', name: 'Value', module: './classes'},
{__symbolic: 'reference', name: 'Value', module: './classes', line: 4, character: 33},
arguments: ['name', 12] arguments: ['name', 12]
}); });
expect(evaluator.evaluateNode(findVarInitializer(newExpression, 'complex'))).toEqual({ expect(evaluator.evaluateNode(findVarInitializer(newExpression, 'complex'))).toEqual({
__symbolic: 'new', __symbolic: 'new',
expression: expression: {__symbolic: 'reference', name: 'Value', module: './classes'},
{__symbolic: 'reference', name: 'Value', module: './classes', line: 5, character: 42},
arguments: ['name', 12] arguments: ['name', 12]
}); });
}); });
@ -175,7 +173,8 @@ describe('Evaluator', () => {
const errors = program.getSourceFile('errors.ts'); const errors = program.getSourceFile('errors.ts');
const fDecl = findVar(errors, 'f') !; const fDecl = findVar(errors, 'f') !;
expect(evaluator.evaluateNode(fDecl.initializer !)) expect(evaluator.evaluateNode(fDecl.initializer !))
.toEqual({__symbolic: 'error', message: 'Lambda not supported', line: 1, character: 12}); .toEqual(
{__symbolic: 'error', message: 'Function call not supported', line: 1, character: 12});
const eDecl = findVar(errors, 'e') !; const eDecl = findVar(errors, 'e') !;
expect(evaluator.evaluateNode(eDecl.type !)).toEqual({ expect(evaluator.evaluateNode(eDecl.type !)).toEqual({
__symbolic: 'error', __symbolic: 'error',

View File

@ -102,7 +102,6 @@ export class MockNode implements ts.Node {
export class MockIdentifier extends MockNode implements ts.Identifier { export class MockIdentifier extends MockNode implements ts.Identifier {
public text: string; public text: string;
public escapedText: ts.__String;
// tslint:disable // tslint:disable
public _primaryExpressionBrand: any; public _primaryExpressionBrand: any;
public _memberExpressionBrand: any; public _memberExpressionBrand: any;
@ -138,14 +137,12 @@ export class MockVariableDeclaration extends MockNode implements ts.VariableDecl
} }
export class MockSymbol implements ts.Symbol { export class MockSymbol implements ts.Symbol {
public escapedName: ts.__String;
constructor( constructor(
public name: string, private node: ts.Declaration = MockVariableDeclaration.of(name), public name: string, private node: ts.Declaration = MockVariableDeclaration.of(name),
public flags: ts.SymbolFlags = 0) {} public flags: ts.SymbolFlags = 0) {}
getFlags(): ts.SymbolFlags { return this.flags; } getFlags(): ts.SymbolFlags { return this.flags; }
getName(): string { return this.name; } getName(): string { return this.name; }
getEscapedName(): ts.__String { return this.escapedName; }
getDeclarations(): ts.Declaration[] { return [this.node]; } getDeclarations(): ts.Declaration[] { return [this.node]; }
getDocumentationComment(): ts.SymbolDisplayPart[] { return []; } getDocumentationComment(): ts.SymbolDisplayPart[] { return []; }
// TODO(vicb): removed in TS 2.2 // TODO(vicb): removed in TS 2.2

View File

@ -184,7 +184,8 @@ describe('ngc transformer command-line', () => {
const exitCode = main(['-p', basePath], errorSpy); const exitCode = main(['-p', basePath], errorSpy);
expect(errorSpy).toHaveBeenCalledTimes(1); expect(errorSpy).toHaveBeenCalledTimes(1);
expect(errorSpy.calls.mostRecent().args[0]).toContain('mymodule.ts.MyComp.html'); expect(errorSpy.calls.mostRecent().args[0])
.toContain('Error at ' + path.join(basePath, 'mymodule.ts.MyComp.html'));
expect(errorSpy.calls.mostRecent().args[0]) expect(errorSpy.calls.mostRecent().args[0])
.toContain(`Property 'unknownProp' does not exist on type 'MyComp'`); .toContain(`Property 'unknownProp' does not exist on type 'MyComp'`);
@ -214,7 +215,8 @@ describe('ngc transformer command-line', () => {
const exitCode = main(['-p', basePath], errorSpy); const exitCode = main(['-p', basePath], errorSpy);
expect(errorSpy).toHaveBeenCalledTimes(1); expect(errorSpy).toHaveBeenCalledTimes(1);
expect(errorSpy.calls.mostRecent().args[0]).toContain('my.component.html(1,5):'); expect(errorSpy.calls.mostRecent().args[0])
.toContain('Error at ' + path.join(basePath, 'my.component.html(1,5):'));
expect(errorSpy.calls.mostRecent().args[0]) expect(errorSpy.calls.mostRecent().args[0])
.toContain(`Property 'unknownProp' does not exist on type 'MyComp'`); .toContain(`Property 'unknownProp' does not exist on type 'MyComp'`);
@ -1564,49 +1566,4 @@ describe('ngc transformer command-line', () => {
expect(main(['-p', path.join(basePath, 'src/tsconfig.json')])).toBe(0); expect(main(['-p', path.join(basePath, 'src/tsconfig.json')])).toBe(0);
}); });
}); });
describe('formatted messages', () => {
it('should emit a formatted error message for a structural error', () => {
write('src/tsconfig.json', `{
"extends": "../tsconfig-base.json",
"files": ["test-module.ts"]
}`);
write('src/lib/indirect2.ts', `
declare var f: any;
export const t2 = f\`<p>hello</p>\`;
`);
write('src/lib/indirect1.ts', `
import {t2} from './indirect2';
export const t1 = t2 + ' ';
`);
write('src/lib/test.component.ts', `
import {Component} from '@angular/core';
import {t1} from './indirect1';
@Component({
template: t1,
styleUrls: ['./test.component.css']
})
export class TestComponent {}
`);
write('src/test-module.ts', `
import {NgModule} from '@angular/core';
import {TestComponent} from './lib/test.component';
@NgModule({declarations: [TestComponent]})
export class TestModule {}
`);
const messages: string[] = [];
const exitCode =
main(['-p', path.join(basePath, 'src/tsconfig.json')], message => messages.push(message));
expect(exitCode).toBe(1, 'Compile was expected to fail');
expect(messages[0])
.toEqual(`lib/test.component.ts(6,21): Error during template compile of 'TestComponent'
Tagged template expressions are not supported in metadata in 't1'
't1' references 't2' at lib/indirect1.ts(3,27)
't2' contains the error at lib/indirect2.ts(4,27).
`);
});
});
}); });

View File

@ -119,7 +119,7 @@ describe('perform watch', () => {
const errorFileContent = ` const errorFileContent = `
import {NgModule} from '@angular/core'; import {NgModule} from '@angular/core';
@NgModule((() => (1===1 ? null as any : null as any)) as any) @NgModule(() => (1===1 ? null as any : null as any))
export class MyModule {} export class MyModule {}
`; `;
const indexTsPath = path.resolve(testSupport.basePath, 'src', 'index.ts'); const indexTsPath = path.resolve(testSupport.basePath, 'src', 'index.ts');
@ -143,7 +143,7 @@ describe('perform watch', () => {
const errDiags = host.diagnostics.filter(d => d.category === ts.DiagnosticCategory.Error); const errDiags = host.diagnostics.filter(d => d.category === ts.DiagnosticCategory.Error);
expect(errDiags.length).toBe(1); expect(errDiags.length).toBe(1);
expect(errDiags[0].messageText).toContain('Function expressions are not supported'); expect(errDiags[0].messageText).toContain('Function calls are not supported.');
} }
}); });
}); });

View File

@ -325,7 +325,7 @@ describe('ng program', () => {
'src/main.ts': ` 'src/main.ts': `
import {NgModule} from '@angular/core'; import {NgModule} from '@angular/core';
@NgModule((() => {if (1==1) return null as any;}) as any) @NgModule(() => {if (1==1) return null as any;})
export class SomeClassWithInvalidMetadata {} export class SomeClassWithInvalidMetadata {}
`, `,
}); });
@ -930,7 +930,7 @@ describe('ng program', () => {
const structuralErrors = program.getNgStructuralDiagnostics(); const structuralErrors = program.getNgStructuralDiagnostics();
expect(structuralErrors.length).toBe(1); expect(structuralErrors.length).toBe(1);
expect(structuralErrors[0].messageText).toContain('Function expressions are not supported'); expect(structuralErrors[0].messageText).toContain('Function calls are not supported.');
}); });
it('should not throw on structural errors but collect them (loadNgStructureAsync)', (done) => { it('should not throw on structural errors but collect them (loadNgStructureAsync)', (done) => {
@ -943,7 +943,7 @@ describe('ng program', () => {
program.loadNgStructureAsync().then(() => { program.loadNgStructureAsync().then(() => {
const structuralErrors = program.getNgStructuralDiagnostics(); const structuralErrors = program.getNgStructuralDiagnostics();
expect(structuralErrors.length).toBe(1); expect(structuralErrors.length).toBe(1);
expect(structuralErrors[0].messageText).toContain('Function expressions are not supported'); expect(structuralErrors[0].messageText).toContain('Function calls are not supported.');
done(); done();
}); });
}); });
@ -982,8 +982,7 @@ describe('ng program', () => {
const program = ng.createProgram({rootNames: allRootNames, options, host}); const program = ng.createProgram({rootNames: allRootNames, options, host});
const structuralErrors = program.getNgStructuralDiagnostics(); const structuralErrors = program.getNgStructuralDiagnostics();
expect(structuralErrors.length).toBe(1); expect(structuralErrors.length).toBe(1);
expect(structuralErrors[0].messageText) expect(structuralErrors[0].messageText).toContain('Function calls are not supported.');
.toContain('Function expressions are not supported');
}); });
}); });
}); });

View File

@ -1,60 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {syntaxError} from '../util';
export interface Position {
fileName: string;
line: number;
column: number;
}
export interface FormattedMessageChain {
message: string;
position?: Position;
next?: FormattedMessageChain;
}
export type FormattedError = Error & {
chain: FormattedMessageChain;
position?: Position;
};
const FORMATTED_MESSAGE = 'ngFormattedMessage';
function indentStr(level: number): string {
if (level <= 0) return '';
if (level < 6) return ['', ' ', ' ', ' ', ' ', ' '][level];
const half = indentStr(Math.floor(level / 2));
return half + half + (level % 2 === 1 ? ' ' : '');
}
function formatChain(chain: FormattedMessageChain | undefined, indent: number = 0): string {
if (!chain) return '';
const position = chain.position ?
`${chain.position.fileName}(${chain.position.line+1},${chain.position.column+1})` :
'';
const prefix = position && indent === 0 ? `${position}: ` : '';
const postfix = position && indent !== 0 ? ` at ${position}` : '';
const message = `${prefix}${chain.message}${postfix}`;
return `${indentStr(indent)}${message}${(chain.next && ('\n' + formatChain(chain.next, indent + 2))) || ''}`;
}
export function formattedError(chain: FormattedMessageChain): FormattedError {
const message = formatChain(chain) + '.';
const error = syntaxError(message) as FormattedError;
(error as any)[FORMATTED_MESSAGE] = true;
error.chain = chain;
error.position = chain.position;
return error;
}
export function isFormattedError(error: Error): error is FormattedError {
return !!(error as any)[FORMATTED_MESSAGE];
}

View File

@ -13,7 +13,6 @@ import * as o from '../output/output_ast';
import {SummaryResolver} from '../summary_resolver'; import {SummaryResolver} from '../summary_resolver';
import {syntaxError} from '../util'; import {syntaxError} from '../util';
import {FormattedMessageChain, formattedError} from './formatted_error';
import {StaticSymbol} from './static_symbol'; import {StaticSymbol} from './static_symbol';
import {StaticSymbolResolver} from './static_symbol_resolver'; import {StaticSymbolResolver} from './static_symbol_resolver';
@ -99,17 +98,12 @@ export class StaticReflector implements CompileReflector {
findSymbolDeclaration(symbol: StaticSymbol): StaticSymbol { findSymbolDeclaration(symbol: StaticSymbol): StaticSymbol {
const resolvedSymbol = this.symbolResolver.resolveSymbol(symbol); const resolvedSymbol = this.symbolResolver.resolveSymbol(symbol);
if (resolvedSymbol) { if (resolvedSymbol && resolvedSymbol.metadata instanceof StaticSymbol) {
let resolvedMetadata = resolvedSymbol.metadata;
if (resolvedMetadata && resolvedMetadata.__symbolic === 'resolved') {
resolvedMetadata = resolvedMetadata.symbol;
}
if (resolvedMetadata instanceof StaticSymbol) {
return this.findSymbolDeclaration(resolvedSymbol.metadata); return this.findSymbolDeclaration(resolvedSymbol.metadata);
} } else {
}
return symbol; return symbol;
} }
}
public annotations(type: StaticSymbol): any[] { public annotations(type: StaticSymbol): any[] {
let annotations = this.annotationCache.get(type); let annotations = this.annotationCache.get(type);
@ -136,12 +130,9 @@ export class StaticReflector implements CompileReflector {
(requiredType) => ownAnnotations.some(ann => requiredType.isTypeOf(ann))); (requiredType) => ownAnnotations.some(ann => requiredType.isTypeOf(ann)));
if (!typeHasRequiredAnnotation) { if (!typeHasRequiredAnnotation) {
this.reportError( this.reportError(
formatMetadataError( syntaxError(
metadataError( `Class ${type.name} in ${type.filePath} extends from a ${CompileSummaryKind[summary.type.summaryKind!]} in another compilation unit without duplicating the decorator. ` +
`Class ${type.name} in ${type.filePath} extends from a ${CompileSummaryKind[summary.type.summaryKind!]} in another compilation unit without duplicating the decorator`, `Please add a ${requiredAnnotationTypes.map((type) => type.ngMetadataName).join(' or ')} decorator to the class.`),
/* summary */ undefined,
`Please add a ${requiredAnnotationTypes.map((type) => type.ngMetadataName).join(' or ')} decorator to the class`),
type),
type); type);
} }
} }
@ -343,6 +334,14 @@ export class StaticReflector implements CompileReflector {
return this.symbolResolver.getStaticSymbol(declarationFile, name, members); return this.symbolResolver.getStaticSymbol(declarationFile, name, members);
} }
private reportError(error: Error, context: StaticSymbol, path?: string) {
if (this.errorRecorder) {
this.errorRecorder(error, (context && context.filePath) || path);
} else {
throw error;
}
}
/** /**
* Simplify but discard any errors * Simplify but discard any errors
*/ */
@ -359,7 +358,6 @@ export class StaticReflector implements CompileReflector {
const self = this; const self = this;
let scope = BindingScope.empty; let scope = BindingScope.empty;
const calling = new Map<StaticSymbol, boolean>(); const calling = new Map<StaticSymbol, boolean>();
const rootContext = context;
function simplifyInContext( function simplifyInContext(
context: StaticSymbol, value: any, depth: number, references: number): any { context: StaticSymbol, value: any, depth: number, references: number): any {
@ -368,64 +366,17 @@ export class StaticReflector implements CompileReflector {
return resolvedSymbol ? resolvedSymbol.metadata : null; return resolvedSymbol ? resolvedSymbol.metadata : null;
} }
function simplifyEagerly(value: any): any { function simplifyCall(functionSymbol: StaticSymbol, targetFunction: any, args: any[]) {
return simplifyInContext(context, value, depth, 0);
}
function simplifyLazily(value: any): any {
return simplifyInContext(context, value, depth, references + 1);
}
function simplifyNested(nestedContext: StaticSymbol, value: any): any {
if (nestedContext === context) {
// If the context hasn't changed let the exception propagate unmodified.
return simplifyInContext(nestedContext, value, depth + 1, references);
}
try {
return simplifyInContext(nestedContext, value, depth + 1, references);
} catch (e) {
if (isMetadataError(e)) {
// Propagate the message text up but add a message to the chain that explains how we got
// here.
// e.chain implies e.symbol
const summaryMsg = e.chain ? 'references \'' + e.symbol !.name + '\'' : errorSummary(e);
const summary = `'${nestedContext.name}' ${summaryMsg}`;
const chain = {message: summary, position: e.position, next: e.chain};
// TODO(chuckj): retrieve the position information indirectly from the collectors node
// map if the metadata is from a .ts file.
self.error(
{
message: e.message,
advise: e.advise,
context: e.context, chain,
symbol: nestedContext
},
context);
} else {
// It is probably an internal error.
throw e;
}
}
}
function simplifyCall(
functionSymbol: StaticSymbol, targetFunction: any, args: any[], targetExpression: any) {
if (targetFunction && targetFunction['__symbolic'] == 'function') { if (targetFunction && targetFunction['__symbolic'] == 'function') {
if (calling.get(functionSymbol)) { if (calling.get(functionSymbol)) {
self.error( throw new Error('Recursion not supported');
{
message: 'Recursion is not supported',
summary: `called '${functionSymbol.name}' recursively`,
value: targetFunction
},
functionSymbol);
} }
try { try {
const value = targetFunction['value']; const value = targetFunction['value'];
if (value && (depth != 0 || value.__symbolic != 'error')) { if (value && (depth != 0 || value.__symbolic != 'error')) {
const parameters: string[] = targetFunction['parameters']; const parameters: string[] = targetFunction['parameters'];
const defaults: any[] = targetFunction.defaults; const defaults: any[] = targetFunction.defaults;
args = args.map(arg => simplifyNested(context, arg)) args = args.map(arg => simplifyInContext(context, arg, depth + 1, references))
.map(arg => shouldIgnore(arg) ? undefined : arg); .map(arg => shouldIgnore(arg) ? undefined : arg);
if (defaults && defaults.length > args.length) { if (defaults && defaults.length > args.length) {
args.push(...defaults.slice(args.length).map((value: any) => simplify(value))); args.push(...defaults.slice(args.length).map((value: any) => simplify(value)));
@ -439,7 +390,7 @@ export class StaticReflector implements CompileReflector {
let result: any; let result: any;
try { try {
scope = functionScope.done(); scope = functionScope.done();
result = simplifyNested(functionSymbol, value); result = simplifyInContext(functionSymbol, value, depth + 1, references);
} finally { } finally {
scope = oldScope; scope = oldScope;
} }
@ -456,22 +407,8 @@ export class StaticReflector implements CompileReflector {
// non-angular decorator, and we should just ignore it. // non-angular decorator, and we should just ignore it.
return IGNORE; return IGNORE;
} }
let position: Position|undefined = undefined; return simplify(
if (targetExpression && targetExpression.__symbolic == 'resolved') { {__symbolic: 'error', message: 'Function call not supported', context: functionSymbol});
const line = targetExpression.line;
const character = targetExpression.character;
const fileName = targetExpression.fileName;
if (fileName != null && line != null && character != null) {
position = {fileName, line, column: character};
}
}
self.error(
{
message: FUNCTION_CALL_NOT_SUPPORTED,
context: functionSymbol,
value: targetFunction, position
},
context);
} }
function simplify(expression: any): any { function simplify(expression: any): any {
@ -485,7 +422,7 @@ export class StaticReflector implements CompileReflector {
if (item && item.__symbolic === 'spread') { if (item && item.__symbolic === 'spread') {
// We call with references as 0 because we require the actual value and cannot // We call with references as 0 because we require the actual value and cannot
// tolerate a reference here. // tolerate a reference here.
const spreadArray = simplifyEagerly(item.expression); const spreadArray = simplifyInContext(context, item.expression, depth, 0);
if (Array.isArray(spreadArray)) { if (Array.isArray(spreadArray)) {
for (const spreadItem of spreadArray) { for (const spreadItem of spreadArray) {
result.push(spreadItem); result.push(spreadItem);
@ -511,7 +448,7 @@ export class StaticReflector implements CompileReflector {
const staticSymbol = expression; const staticSymbol = expression;
const declarationValue = resolveReferenceValue(staticSymbol); const declarationValue = resolveReferenceValue(staticSymbol);
if (declarationValue != null) { if (declarationValue != null) {
return simplifyNested(staticSymbol, declarationValue); return simplifyInContext(staticSymbol, declarationValue, depth + 1, references);
} else { } else {
return staticSymbol; return staticSymbol;
} }
@ -588,8 +525,8 @@ export class StaticReflector implements CompileReflector {
} }
return null; return null;
case 'index': case 'index':
let indexTarget = simplifyEagerly(expression['expression']); let indexTarget = simplifyInContext(context, expression['expression'], depth, 0);
let index = simplifyEagerly(expression['index']); let index = simplifyInContext(context, expression['index'], depth, 0);
if (indexTarget && isPrimitive(index)) return indexTarget[index]; if (indexTarget && isPrimitive(index)) return indexTarget[index];
return null; return null;
case 'select': case 'select':
@ -602,41 +539,26 @@ export class StaticReflector implements CompileReflector {
self.getStaticSymbol(selectTarget.filePath, selectTarget.name, members); self.getStaticSymbol(selectTarget.filePath, selectTarget.name, members);
const declarationValue = resolveReferenceValue(selectContext); const declarationValue = resolveReferenceValue(selectContext);
if (declarationValue != null) { if (declarationValue != null) {
return simplifyNested(selectContext, declarationValue); return simplifyInContext(
selectContext, declarationValue, depth + 1, references);
} else { } else {
return selectContext; return selectContext;
} }
} }
if (selectTarget && isPrimitive(member)) if (selectTarget && isPrimitive(member))
return simplifyNested(selectContext, selectTarget[member]); return simplifyInContext(
selectContext, selectTarget[member], depth + 1, references);
return null; return null;
case 'reference': case 'reference':
// Note: This only has to deal with variable references, as symbol references have // Note: This only has to deal with variable references,
// been converted into 'resolved' // as symbol references have been converted into StaticSymbols already
// in the StaticSymbolResolver. // in the StaticSymbolResolver!
const name: string = expression['name']; const name: string = expression['name'];
const localValue = scope.resolve(name); const localValue = scope.resolve(name);
if (localValue != BindingScope.missing) { if (localValue != BindingScope.missing) {
return localValue; return localValue;
} }
break; break;
case 'resolved':
try {
return simplify(expression.symbol);
} catch (e) {
// If an error is reported evaluating the symbol record the position of the
// reference in the error so it can
// be reported in the error message generated from the exception.
if (isMetadataError(e) && expression.fileName != null &&
expression.line != null && expression.character != null) {
e.position = {
fileName: expression.fileName,
line: expression.line,
column: expression.character
};
}
throw e;
}
case 'class': case 'class':
return context; return context;
case 'function': case 'function':
@ -658,34 +580,29 @@ export class StaticReflector implements CompileReflector {
const argExpressions: any[] = expression['arguments'] || []; const argExpressions: any[] = expression['arguments'] || [];
let converter = self.conversionMap.get(staticSymbol); let converter = self.conversionMap.get(staticSymbol);
if (converter) { if (converter) {
const args = argExpressions.map(arg => simplifyNested(context, arg)) const args =
argExpressions
.map(arg => simplifyInContext(context, arg, depth + 1, references))
.map(arg => shouldIgnore(arg) ? undefined : arg); .map(arg => shouldIgnore(arg) ? undefined : arg);
return converter(context, args); return converter(context, args);
} else { } else {
// Determine if the function is one we can simplify. // Determine if the function is one we can simplify.
const targetFunction = resolveReferenceValue(staticSymbol); const targetFunction = resolveReferenceValue(staticSymbol);
return simplifyCall( return simplifyCall(staticSymbol, targetFunction, argExpressions);
staticSymbol, targetFunction, argExpressions, expression['expression']);
} }
} }
return IGNORE; return IGNORE;
case 'error': case 'error':
let message = expression.message; let message = produceErrorMessage(expression);
if (expression['line'] != null) { if (expression['line']) {
self.error( message =
{ `${message} (position ${expression['line']+1}:${expression['character']+1} in the original .ts file)`;
message, self.reportError(
context: expression.context, positionalError(
value: expression, message, context.filePath, expression['line'], expression['character']),
position: {
fileName: expression['fileName'],
line: expression['line'],
column: expression['character']
}
},
context); context);
} else { } else {
self.error({message, context: expression.context}, context); self.reportError(new Error(message), context);
} }
return IGNORE; return IGNORE;
case 'ignore': case 'ignore':
@ -703,7 +620,7 @@ export class StaticReflector implements CompileReflector {
return simplify(value); return simplify(value);
} }
} }
return simplifyLazily(value); return simplifyInContext(context, value, depth, references + 1);
} }
return simplify(value); return simplify(value);
}); });
@ -711,19 +628,29 @@ export class StaticReflector implements CompileReflector {
return IGNORE; return IGNORE;
} }
try {
return simplify(value); return simplify(value);
} catch (e) {
const members = context.members.length ? `.${context.members.join('.')}` : '';
const message =
`${e.message}, resolving symbol ${context.name}${members} in ${context.filePath}`;
if (e.fileName) {
throw positionalError(message, e.fileName, e.line, e.column);
}
throw syntaxError(message);
}
} }
let result: any; const recordedSimplifyInContext = (context: StaticSymbol, value: any) => {
try { try {
result = simplifyInContext(context, value, 0, 0); return simplifyInContext(context, value, 0, 0);
} catch (e) { } catch (e) {
if (this.errorRecorder) {
this.reportError(e, context); this.reportError(e, context);
} else {
throw formatMetadataError(e, context);
}
} }
};
const result = this.errorRecorder ? recordedSimplifyInContext(context, value) :
simplifyInContext(context, value, 0, 0);
if (shouldIgnore(result)) { if (shouldIgnore(result)) {
return undefined; return undefined;
} }
@ -735,166 +662,40 @@ export class StaticReflector implements CompileReflector {
return resolvedSymbol && resolvedSymbol.metadata ? resolvedSymbol.metadata : return resolvedSymbol && resolvedSymbol.metadata ? resolvedSymbol.metadata :
{__symbolic: 'class'}; {__symbolic: 'class'};
} }
private reportError(error: Error, context: StaticSymbol, path?: string) {
if (this.errorRecorder) {
this.errorRecorder(
formatMetadataError(error, context), (context && context.filePath) || path);
} else {
throw error;
}
} }
private error( function expandedMessage(error: any): string {
{message, summary, advise, position, context, value, symbol, chain}: {
message: string,
summary?: string,
advise?: string,
position?: Position,
context?: any,
value?: any,
symbol?: StaticSymbol,
chain?: MetadataMessageChain
},
reportingContext: StaticSymbol) {
this.reportError(
metadataError(message, summary, advise, position, symbol, context, chain),
reportingContext);
}
}
interface Position {
fileName: string;
line: number;
column: number;
}
interface MetadataMessageChain {
message: string;
summary?: string;
position?: Position;
context?: any;
symbol?: StaticSymbol;
next?: MetadataMessageChain;
}
type MetadataError = Error & {
position?: Position;
advise?: string;
summary?: string;
context?: any;
symbol?: StaticSymbol;
chain?: MetadataMessageChain;
};
const METADATA_ERROR = 'ngMetadataError';
function metadataError(
message: string, summary?: string, advise?: string, position?: Position, symbol?: StaticSymbol,
context?: any, chain?: MetadataMessageChain): MetadataError {
const error = syntaxError(message) as MetadataError;
(error as any)[METADATA_ERROR] = true;
if (advise) error.advise = advise;
if (position) error.position = position;
if (summary) error.summary = summary;
if (context) error.context = context;
if (chain) error.chain = chain;
if (symbol) error.symbol = symbol;
return error;
}
function isMetadataError(error: Error): error is MetadataError {
return !!(error as any)[METADATA_ERROR];
}
const REFERENCE_TO_NONEXPORTED_CLASS = 'Reference to non-exported class';
const VARIABLE_NOT_INITIALIZED = 'Variable not initialized';
const DESTRUCTURE_NOT_SUPPORTED = 'Destructuring not supported';
const COULD_NOT_RESOLVE_TYPE = 'Could not resolve type';
const FUNCTION_CALL_NOT_SUPPORTED = 'Function call not supported';
const REFERENCE_TO_LOCAL_SYMBOL = 'Reference to a local symbol';
const LAMBDA_NOT_SUPPORTED = 'Lambda not supported';
function expandedMessage(message: string, context: any): string {
switch (message) {
case REFERENCE_TO_NONEXPORTED_CLASS:
if (context && context.className) {
return `References to a non-exported class are not supported in decorators but ${context.className} was referenced.`;
}
break;
case VARIABLE_NOT_INITIALIZED:
return 'Only initialized variables and constants can be referenced in decorators because the value of this variable is needed by the template compiler';
case DESTRUCTURE_NOT_SUPPORTED:
return 'Referencing an exported destructured variable or constant is not supported in decorators and this value is needed by the template compiler';
case COULD_NOT_RESOLVE_TYPE:
if (context && context.typeName) {
return `Could not resolve type ${context.typeName}`;
}
break;
case FUNCTION_CALL_NOT_SUPPORTED:
if (context && context.name) {
return `Function calls are not supported in decorators but '${context.name}' was called`;
}
return 'Function calls are not supported in decorators';
case REFERENCE_TO_LOCAL_SYMBOL:
if (context && context.name) {
return `Reference to a local (non-exported) symbols are not supported in decorators but '${context.name}' was referenced`;
}
break;
case LAMBDA_NOT_SUPPORTED:
return `Function expressions are not supported in decorators`;
}
return message;
}
function messageAdvise(message: string, context: any): string|undefined {
switch (message) {
case REFERENCE_TO_NONEXPORTED_CLASS:
if (context && context.className) {
return `Consider exporting '${context.className}'`;
}
break;
case DESTRUCTURE_NOT_SUPPORTED:
return 'Consider simplifying to avoid destructuring';
case REFERENCE_TO_LOCAL_SYMBOL:
if (context && context.name) {
return `Consider exporting '${context.name}'`;
}
break;
case LAMBDA_NOT_SUPPORTED:
return `Consider changing the function expression into an exported function`;
}
return undefined;
}
function errorSummary(error: MetadataError): string {
if (error.summary) {
return error.summary;
}
switch (error.message) { switch (error.message) {
case REFERENCE_TO_NONEXPORTED_CLASS: case 'Reference to non-exported class':
if (error.context && error.context.className) { if (error.context && error.context.className) {
return `references non-exported class ${error.context.className}`; return `Reference to a non-exported class ${error.context.className}. Consider exporting the class`;
} }
break; break;
case VARIABLE_NOT_INITIALIZED: case 'Variable not initialized':
return 'is not initialized'; return 'Only initialized variables and constants can be referenced because the value of this variable is needed by the template compiler';
case DESTRUCTURE_NOT_SUPPORTED: case 'Destructuring not supported':
return 'is a destructured variable'; return 'Referencing an exported destructured variable or constant is not supported by the template compiler. Consider simplifying this to avoid destructuring';
case COULD_NOT_RESOLVE_TYPE: case 'Could not resolve type':
return 'could not be resolved'; if (error.context && error.context.typeName) {
case FUNCTION_CALL_NOT_SUPPORTED: return `Could not resolve type ${error.context.typeName}`;
}
break;
case 'Function call not supported':
let prefix =
error.context && error.context.name ? `Calling function '${error.context.name}', f` : 'F';
return prefix +
'unction calls are not supported. Consider replacing the function or lambda with a reference to an exported function';
case 'Reference to a local symbol':
if (error.context && error.context.name) { if (error.context && error.context.name) {
return `calls '${error.context.name}'`; return `Reference to a local (non-exported) symbol '${error.context.name}'. Consider exporting the symbol`;
} }
return `calls a function`; break;
case REFERENCE_TO_LOCAL_SYMBOL:
if (error.context && error.context.name) {
return `references local variable ${error.context.name}`;
} }
return `references a local variable`; return error.message;
} }
return 'contains the error';
function produceErrorMessage(error: any): string {
return `Error encountered resolving symbol values statically. ${expandedMessage(error)}`;
} }
function mapStringMap(input: {[key: string]: any}, transform: (value: any, key: string) => any): function mapStringMap(input: {[key: string]: any}, transform: (value: any, key: string) => any):
@ -950,30 +751,10 @@ class PopulatedScope extends BindingScope {
} }
} }
function formatMetadataMessageChain( function positionalError(message: string, fileName: string, line: number, column: number): Error {
chain: MetadataMessageChain, advise: string | undefined): FormattedMessageChain { const result = syntaxError(message);
const expanded = expandedMessage(chain.message, chain.context); (result as any).fileName = fileName;
const nesting = chain.symbol ? ` in '${chain.symbol.name}'` : ''; (result as any).line = line;
const message = `${expanded}${nesting}`; (result as any).column = column;
const position = chain.position; return result;
const next: FormattedMessageChain|undefined = chain.next ?
formatMetadataMessageChain(chain.next, advise) :
advise ? {message: advise} : undefined;
return {message, position, next};
}
function formatMetadataError(e: Error, context: StaticSymbol): Error {
if (isMetadataError(e)) {
// Produce a formatted version of the and leaving enough information in the original error
// to recover the formatting information to eventually produce a diagnostic error message.
const position = e.position;
const chain: MetadataMessageChain = {
message: `Error during template compile of '${context.name}'`,
position: position,
next: {message: e.message, next: e.chain, context: e.context, symbol: e.symbol}
};
const advise = e.advise || messageAdvise(e.message, e.context);
return formattedError(formatMetadataMessageChain(chain, advise));
}
return e;
} }

View File

@ -146,9 +146,9 @@ export class StaticSymbolResolver {
if (isGeneratedFile(staticSymbol.filePath)) { if (isGeneratedFile(staticSymbol.filePath)) {
return null; return null;
} }
let resolvedSymbol = unwrapResolvedMetadata(this.resolveSymbol(staticSymbol)); let resolvedSymbol = this.resolveSymbol(staticSymbol);
while (resolvedSymbol && resolvedSymbol.metadata instanceof StaticSymbol) { while (resolvedSymbol && resolvedSymbol.metadata instanceof StaticSymbol) {
resolvedSymbol = unwrapResolvedMetadata(this.resolveSymbol(resolvedSymbol.metadata)); resolvedSymbol = this.resolveSymbol(resolvedSymbol.metadata);
} }
return (resolvedSymbol && resolvedSymbol.metadata && resolvedSymbol.metadata.arity) || null; return (resolvedSymbol && resolvedSymbol.metadata && resolvedSymbol.metadata.arity) || null;
} }
@ -204,7 +204,7 @@ export class StaticSymbolResolver {
if (!baseResolvedSymbol) { if (!baseResolvedSymbol) {
return null; return null;
} }
let baseMetadata = unwrapResolvedMetadata(baseResolvedSymbol.metadata); const baseMetadata = baseResolvedSymbol.metadata;
if (baseMetadata instanceof StaticSymbol) { if (baseMetadata instanceof StaticSymbol) {
return new ResolvedStaticSymbol( return new ResolvedStaticSymbol(
staticSymbol, this.getStaticSymbol(baseMetadata.filePath, baseMetadata.name, members)); staticSymbol, this.getStaticSymbol(baseMetadata.filePath, baseMetadata.name, members));
@ -374,19 +374,6 @@ export class StaticSymbolResolver {
return new ResolvedStaticSymbol(sourceSymbol, transformedMeta); return new ResolvedStaticSymbol(sourceSymbol, transformedMeta);
} }
let _originalFileMemo: string|undefined;
const getOriginalName: () => string = () => {
if (!_originalFileMemo) {
// Guess what hte original file name is from the reference. If it has a `.d.ts` extension
// replace it with `.ts`. If it already has `.ts` just leave it in place. If it doesn't have
// .ts or .d.ts, append `.ts'. Also, if it is in `node_modules`, trim the `node_module`
// location as it is not important to finding the file.
_originalFileMemo =
topLevelPath.replace(/((\.ts)|(\.d\.ts)|)$/, '.ts').replace(/^.*node_modules[/\\]/, '');
}
return _originalFileMemo;
};
const self = this; const self = this;
class ReferenceTransformer extends ValueTransformer { class ReferenceTransformer extends ValueTransformer {
@ -410,19 +397,10 @@ export class StaticSymbolResolver {
if (!filePath) { if (!filePath) {
return { return {
__symbolic: 'error', __symbolic: 'error',
message: `Could not resolve ${module} relative to ${sourceSymbol.filePath}.`, message: `Could not resolve ${module} relative to ${sourceSymbol.filePath}.`
line: map.line,
character: map.character,
fileName: getOriginalName()
}; };
} }
return { return self.getStaticSymbol(filePath, name);
__symbolic: 'resolved',
symbol: self.getStaticSymbol(filePath, name),
line: map.line,
character: map.character,
fileName: getOriginalName()
};
} else if (functionParams.indexOf(name) >= 0) { } else if (functionParams.indexOf(name) >= 0) {
// reference to a function parameter // reference to a function parameter
return {__symbolic: 'reference', name: name}; return {__symbolic: 'reference', name: name};
@ -433,17 +411,14 @@ export class StaticSymbolResolver {
// ambient value // ambient value
null; null;
} }
} else if (symbolic === 'error') {
return {...map, fileName: getOriginalName()};
} else { } else {
return super.visitStringMap(map, functionParams); return super.visitStringMap(map, functionParams);
} }
} }
} }
const transformedMeta = visitValue(metadata, new ReferenceTransformer(), []); const transformedMeta = visitValue(metadata, new ReferenceTransformer(), []);
let unwrappedTransformedMeta = unwrapResolvedMetadata(transformedMeta); if (transformedMeta instanceof StaticSymbol) {
if (unwrappedTransformedMeta instanceof StaticSymbol) { return this.createExport(sourceSymbol, transformedMeta);
return this.createExport(sourceSymbol, unwrappedTransformedMeta);
} }
return new ResolvedStaticSymbol(sourceSymbol, transformedMeta); return new ResolvedStaticSymbol(sourceSymbol, transformedMeta);
} }
@ -530,10 +505,3 @@ export class StaticSymbolResolver {
export function unescapeIdentifier(identifier: string): string { export function unescapeIdentifier(identifier: string): string {
return identifier.startsWith('___') ? identifier.substr(1) : identifier; return identifier.startsWith('___') ? identifier.substr(1) : identifier;
} }
export function unwrapResolvedMetadata(metadata: any): any {
if (metadata && metadata.__symbolic === 'resolved') {
return metadata.symbol;
}
return metadata;
}

View File

@ -11,7 +11,7 @@ import {Summary, SummaryResolver} from '../summary_resolver';
import {OutputContext, ValueTransformer, ValueVisitor, visitValue} from '../util'; import {OutputContext, ValueTransformer, ValueVisitor, visitValue} from '../util';
import {StaticSymbol, StaticSymbolCache} from './static_symbol'; import {StaticSymbol, StaticSymbolCache} from './static_symbol';
import {ResolvedStaticSymbol, StaticSymbolResolver, unwrapResolvedMetadata} from './static_symbol_resolver'; import {ResolvedStaticSymbol, StaticSymbolResolver} from './static_symbol_resolver';
import {isLoweredSymbol, ngfactoryFilePath, summaryForJitFileName, summaryForJitName} from './util'; import {isLoweredSymbol, ngfactoryFilePath, summaryForJitFileName, summaryForJitName} from './util';
export function serializeSummaries( export function serializeSummaries(
@ -453,10 +453,10 @@ function isCall(metadata: any): boolean {
} }
function isFunctionCall(metadata: any): boolean { function isFunctionCall(metadata: any): boolean {
return isCall(metadata) && unwrapResolvedMetadata(metadata.expression) instanceof StaticSymbol; return isCall(metadata) && metadata.expression instanceof StaticSymbol;
} }
function isMethodCallOnVariable(metadata: any): boolean { function isMethodCallOnVariable(metadata: any): boolean {
return isCall(metadata) && metadata.expression && metadata.expression.__symbolic === 'select' && return isCall(metadata) && metadata.expression && metadata.expression.__symbolic === 'select' &&
unwrapResolvedMetadata(metadata.expression.expression) instanceof StaticSymbol; metadata.expression.expression instanceof StaticSymbol;
} }

View File

@ -35,7 +35,6 @@ export * from './aot/compiler';
export * from './aot/generated_file'; export * from './aot/generated_file';
export * from './aot/compiler_options'; export * from './aot/compiler_options';
export * from './aot/compiler_host'; export * from './aot/compiler_host';
export * from './aot/formatted_error';
export * from './aot/static_reflector'; export * from './aot/static_reflector';
export * from './aot/static_symbol'; export * from './aot/static_symbol';
export * from './aot/static_symbol_resolver'; export * from './aot/static_symbol_resolver';

View File

@ -42,7 +42,6 @@ export class JitCompiler {
private _compiledDirectiveWrapperCache = new Map<Type, Type>(); private _compiledDirectiveWrapperCache = new Map<Type, Type>();
private _compiledNgModuleCache = new Map<Type, object>(); private _compiledNgModuleCache = new Map<Type, object>();
private _sharedStylesheetCount = 0; private _sharedStylesheetCount = 0;
private _addedAotSummaries = new Set<() => any[]>();
constructor( constructor(
private _metadataResolver: CompileMetadataResolver, private _templateParser: TemplateParser, private _metadataResolver: CompileMetadataResolver, private _templateParser: TemplateParser,
@ -75,25 +74,10 @@ export class JitCompiler {
loadAotSummaries(summaries: () => any[]) { loadAotSummaries(summaries: () => any[]) {
this.clearCache(); this.clearCache();
this._addAotSummaries(summaries); flattenSummaries(summaries).forEach((summary) => {
}
private _addAotSummaries(fn: () => any[]) {
if (this._addedAotSummaries.has(fn)) {
return;
}
this._addedAotSummaries.add(fn);
const summaries = fn();
for (let i = 0; i < summaries.length; i++) {
const entry = summaries[i];
if (typeof entry === 'function') {
this._addAotSummaries(entry);
} else {
const summary = entry as CompileTypeSummary;
this._summaryResolver.addSummary( this._summaryResolver.addSummary(
{symbol: summary.type.reference, metadata: null, type: summary}); {symbol: summary.type.reference, metadata: null, type: summary});
} });
}
} }
hasAotSummary(ref: Type) { return !!this._summaryResolver.resolveSummary(ref); } hasAotSummary(ref: Type) { return !!this._summaryResolver.resolveSummary(ref); }
@ -216,7 +200,6 @@ export class JitCompiler {
} }
clearCache(): void { clearCache(): void {
// Note: don't clear the _addedAotSummaries, as they don't change!
this._metadataResolver.clearCache(); this._metadataResolver.clearCache();
this._compiledTemplateCache.clear(); this._compiledTemplateCache.clear();
this._compiledHostTemplateCache.clear(); this._compiledHostTemplateCache.clear();
@ -352,6 +335,25 @@ function assertComponent(meta: CompileDirectiveMetadata) {
} }
} }
function flattenSummaries(
fn: () => any[], out: CompileTypeSummary[] = [],
seen = new Set<() => any[]>()): CompileTypeSummary[] {
if (seen.has(fn)) {
return out;
}
seen.add(fn);
const summaries = fn();
for (let i = 0; i < summaries.length; i++) {
const entry = summaries[i];
if (typeof entry === 'function') {
flattenSummaries(entry, out, seen);
} else {
out.push(entry);
}
}
return out;
}
function createOutputContext(): OutputContext { function createOutputContext(): OutputContext {
const importExpr = (symbol: any) => const importExpr = (symbol: any) =>
ir.importExpr({name: identifierName(symbol), moduleName: null, runtime: symbol}); ir.importExpr({name: identifierName(symbol), moduleName: null, runtime: symbol});

View File

@ -768,9 +768,9 @@ describe('compiler (unbundled Angular)', () => {
childClassDecorator: '', childClassDecorator: '',
childModuleDecorator: '@NgModule({providers: [Extends]})', childModuleDecorator: '@NgModule({providers: [Extends]})',
})) }))
.toThrowError(`Error during template compile of 'Extends' .toThrowError(
Class Extends in /app/main.ts extends from a Injectable in another compilation unit without duplicating the decorator 'Class Extends in /app/main.ts extends from a Injectable in another compilation unit without duplicating the decorator. ' +
Please add a Injectable or Pipe or Directive or Component or NgModule decorator to the class.`); 'Please add a Injectable or Pipe or Directive or Component or NgModule decorator to the class.');
}); });
}); });
@ -792,9 +792,9 @@ describe('compiler (unbundled Angular)', () => {
childClassDecorator: '', childClassDecorator: '',
childModuleDecorator: '@NgModule({declarations: [Extends]})', childModuleDecorator: '@NgModule({declarations: [Extends]})',
})) }))
.toThrowError(`Error during template compile of 'Extends' .toThrowError(
Class Extends in /app/main.ts extends from a Directive in another compilation unit without duplicating the decorator 'Class Extends in /app/main.ts extends from a Directive in another compilation unit without duplicating the decorator. ' +
Please add a Directive or Component decorator to the class.`); 'Please add a Directive or Component decorator to the class.');
}); });
}); });
@ -816,9 +816,9 @@ describe('compiler (unbundled Angular)', () => {
childClassDecorator: '', childClassDecorator: '',
childModuleDecorator: '@NgModule({declarations: [Extends]})', childModuleDecorator: '@NgModule({declarations: [Extends]})',
})) }))
.toThrowError(`Error during template compile of 'Extends' .toThrowError(
Class Extends in /app/main.ts extends from a Directive in another compilation unit without duplicating the decorator 'Class Extends in /app/main.ts extends from a Directive in another compilation unit without duplicating the decorator. ' +
Please add a Directive or Component decorator to the class.`); 'Please add a Directive or Component decorator to the class.');
}); });
}); });
@ -840,9 +840,9 @@ describe('compiler (unbundled Angular)', () => {
childClassDecorator: '', childClassDecorator: '',
childModuleDecorator: '@NgModule({declarations: [Extends]})', childModuleDecorator: '@NgModule({declarations: [Extends]})',
})) }))
.toThrowError(`Error during template compile of 'Extends' .toThrowError(
Class Extends in /app/main.ts extends from a Pipe in another compilation unit without duplicating the decorator 'Class Extends in /app/main.ts extends from a Pipe in another compilation unit without duplicating the decorator. ' +
Please add a Pipe decorator to the class.`); 'Please add a Pipe decorator to the class.');
}); });
}); });
@ -864,9 +864,9 @@ describe('compiler (unbundled Angular)', () => {
childClassDecorator: '', childClassDecorator: '',
childModuleDecorator: '', childModuleDecorator: '',
})) }))
.toThrowError(`Error during template compile of 'Extends' .toThrowError(
Class Extends in /app/main.ts extends from a NgModule in another compilation unit without duplicating the decorator 'Class Extends in /app/main.ts extends from a NgModule in another compilation unit without duplicating the decorator. ' +
Please add a NgModule decorator to the class.`); 'Please add a NgModule decorator to the class.');
}); });
}); });
} }

View File

@ -107,11 +107,8 @@ describe('StaticReflector', () => {
it('should provide context for errors reported by the collector', () => { it('should provide context for errors reported by the collector', () => {
const SomeClass = reflector.findDeclaration('src/error-reporting', 'SomeClass'); const SomeClass = reflector.findDeclaration('src/error-reporting', 'SomeClass');
expect(() => reflector.annotations(SomeClass)) expect(() => reflector.annotations(SomeClass))
.toThrow(new Error(`Error during template compile of 'SomeClass' .toThrow(new Error(
A reasonable error message in 'Link1' 'Error encountered resolving symbol values statically. A reasonable error message (position 13:34 in the original .ts file), resolving symbol ErrorSym in /tmp/src/error-references.d.ts, resolving symbol Link2 in /tmp/src/error-references.d.ts, resolving symbol Link1 in /tmp/src/error-references.d.ts, resolving symbol SomeClass in /tmp/src/error-reporting.d.ts, resolving symbol SomeClass in /tmp/src/error-reporting.d.ts'));
'Link1' references 'Link2'
'Link2' references 'ErrorSym'
'ErrorSym' contains the error at /tmp/src/error-references.ts(13,34).`));
}); });
it('should simplify primitive into itself', () => { it('should simplify primitive into itself', () => {
@ -333,12 +330,10 @@ describe('StaticReflector', () => {
it('should error on direct recursive calls', () => { it('should error on direct recursive calls', () => {
expect( expect(
() => simplify( () => simplify(
reflector.getStaticSymbol('/tmp/src/function-reference.ts', 'MyComp'), reflector.getStaticSymbol('/tmp/src/function-reference.ts', ''),
reflector.getStaticSymbol('/tmp/src/function-reference.ts', 'recursion'))) reflector.getStaticSymbol('/tmp/src/function-reference.ts', 'recursion')))
.toThrow(new Error(`Error during template compile of 'MyComp' .toThrow(new Error(
Recursion is not supported in 'recursion' 'Recursion not supported, resolving symbol recursive in /tmp/src/function-recursive.d.ts, resolving symbol recursion in /tmp/src/function-reference.ts, resolving symbol in /tmp/src/function-reference.ts'));
'recursion' references 'recursive'
'recursive' called 'recursive' recursively.`));
}); });
it('should throw a SyntaxError without stack trace when the required resource cannot be resolved', it('should throw a SyntaxError without stack trace when the required resource cannot be resolved',
@ -350,8 +345,8 @@ describe('StaticReflector', () => {
message: message:
'Could not resolve ./does-not-exist.component relative to /tmp/src/function-reference.ts' 'Could not resolve ./does-not-exist.component relative to /tmp/src/function-reference.ts'
}))) })))
.toThrowError(`Error during template compile of 'AppModule' .toThrowError(
Could not resolve ./does-not-exist.component relative to /tmp/src/function-reference.ts.`); 'Error encountered resolving symbol values statically. Could not resolve ./does-not-exist.component relative to /tmp/src/function-reference.ts, resolving symbol AppModule in /tmp/src/function-reference.ts');
}); });
it('should record data about the error in the exception', () => { it('should record data about the error in the exception', () => {
@ -366,7 +361,7 @@ describe('StaticReflector', () => {
simplify( simplify(
reflector.getStaticSymbol('/tmp/src/invalid-metadata.ts', ''), classData.decorators[0]); reflector.getStaticSymbol('/tmp/src/invalid-metadata.ts', ''), classData.decorators[0]);
} catch (e) { } catch (e) {
expect(e.position).toBeDefined(); expect(e.fileName).toBe('/tmp/src/invalid-metadata.ts');
threw = true; threw = true;
} }
expect(threw).toBe(true); expect(threw).toBe(true);
@ -375,13 +370,10 @@ describe('StaticReflector', () => {
it('should error on indirect recursive calls', () => { it('should error on indirect recursive calls', () => {
expect( expect(
() => simplify( () => simplify(
reflector.getStaticSymbol('/tmp/src/function-reference.ts', 'MyComp'), reflector.getStaticSymbol('/tmp/src/function-reference.ts', ''),
reflector.getStaticSymbol('/tmp/src/function-reference.ts', 'indirectRecursion'))) reflector.getStaticSymbol('/tmp/src/function-reference.ts', 'indirectRecursion')))
.toThrow(new Error(`Error during template compile of 'MyComp' .toThrow(new Error(
Recursion is not supported in 'indirectRecursion' 'Recursion not supported, resolving symbol indirectRecursion2 in /tmp/src/function-recursive.d.ts, resolving symbol indirectRecursion1 in /tmp/src/function-recursive.d.ts, resolving symbol indirectRecursion in /tmp/src/function-reference.ts, resolving symbol in /tmp/src/function-reference.ts'));
'indirectRecursion' references 'indirectRecursion1'
'indirectRecursion1' references 'indirectRecursion2'
'indirectRecursion2' called 'indirectRecursion1' recursively.`));
}); });
it('should simplify a spread expression', () => { it('should simplify a spread expression', () => {
@ -409,8 +401,7 @@ describe('StaticReflector', () => {
() => reflector.annotations( () => reflector.annotations(
reflector.getStaticSymbol('/tmp/src/invalid-calls.ts', 'MyComponent'))) reflector.getStaticSymbol('/tmp/src/invalid-calls.ts', 'MyComponent')))
.toThrow(new Error( .toThrow(new Error(
`/tmp/src/invalid-calls.ts(8,29): Error during template compile of 'MyComponent' `Error encountered resolving symbol values statically. Calling function 'someFunction', function calls are not supported. Consider replacing the function or lambda with a reference to an exported function, resolving symbol MyComponent in /tmp/src/invalid-calls.ts, resolving symbol MyComponent in /tmp/src/invalid-calls.ts`));
Function calls are not supported in decorators but 'someFunction' was called.`));
}); });
it('should be able to get metadata for a class containing a static method call', () => { it('should be able to get metadata for a class containing a static method call', () => {
@ -971,7 +962,7 @@ describe('StaticReflector', () => {
}); });
// Regression #18170 // Regression #18170
it('should eagerly evaluate enums selects', () => { it('should agressively evaluate enums selects', () => {
const data = Object.create(DEFAULT_TEST_DATA); const data = Object.create(DEFAULT_TEST_DATA);
const file = '/tmp/src/my_component.ts'; const file = '/tmp/src/my_component.ts';
data[file] = ` data[file] = `
@ -1087,228 +1078,6 @@ describe('StaticReflector', () => {
expect(symbolResolver.getKnownModuleName(symbol.filePath)).toBe('a'); expect(symbolResolver.getKnownModuleName(symbol.filePath)).toBe('a');
}); });
}); });
describe('formatted error reporting', () => {
describe('function calls', () => {
const fileName = '/tmp/src/invalid/components.ts';
beforeEach(() => {
const localData = {
'/tmp/src/invalid/function-call.ts': `
import {functionToCall} from 'some-module';
export const CALL_FUNCTION = functionToCall();
`,
'/tmp/src/invalid/indirect.ts': `
import {CALL_FUNCTION} from './function-call';
export const INDIRECT_CALL_FUNCTION = CALL_FUNCTION + 1;
`,
'/tmp/src/invalid/two-levels-indirect.ts': `
import {INDIRECT_CALL_FUNCTION} from './indirect';
export const TWO_LEVELS_INDIRECT_CALL_FUNCTION = INDIRECT_CALL_FUNCTION + 1;
`,
'/tmp/src/invalid/components.ts': `
import {functionToCall} from 'some-module';
import {Component} from '@angular/core';
import {CALL_FUNCTION} from './function-call';
import {INDIRECT_CALL_FUNCTION} from './indirect';
import {TWO_LEVELS_INDIRECT_CALL_FUNCTION} from './two-levels-indirect';
@Component({
value: functionToCall()
})
export class CallImportedFunction {}
@Component({
value: CALL_FUNCTION
})
export class ReferenceCalledFunction {}
@Component({
value: INDIRECT_CALL_FUNCTION
})
export class IndirectReferenceCalledFunction {}
@Component({
value: TWO_LEVELS_INDIRECT_CALL_FUNCTION
})
export class TwoLevelsIndirectReferenceCalledFunction {}
`
};
init({...DEFAULT_TEST_DATA, ...localData});
});
it('should report a formatted error for a direct function call', () => {
expect(() => {
return reflector.annotations(reflector.getStaticSymbol(fileName, 'CallImportedFunction'));
})
.toThrowError(
`/tmp/src/invalid/components.ts(9,18): Error during template compile of 'CallImportedFunction'
Function calls are not supported in decorators but 'functionToCall' was called.`);
});
it('should report a formatted error for a refernce to a function call', () => {
expect(() => {
return reflector.annotations(
reflector.getStaticSymbol(fileName, 'ReferenceCalledFunction'));
})
.toThrowError(
`/tmp/src/invalid/components.ts(14,18): Error during template compile of 'ReferenceCalledFunction'
Function calls are not supported in decorators but 'functionToCall' was called in 'CALL_FUNCTION'
'CALL_FUNCTION' calls 'functionToCall' at /tmp/src/invalid/function-call.ts(3,38).`);
});
it('should report a formatted error for an indirect reference to a function call', () => {
expect(() => {
return reflector.annotations(
reflector.getStaticSymbol(fileName, 'IndirectReferenceCalledFunction'));
})
.toThrowError(
`/tmp/src/invalid/components.ts(19,18): Error during template compile of 'IndirectReferenceCalledFunction'
Function calls are not supported in decorators but 'functionToCall' was called in 'INDIRECT_CALL_FUNCTION'
'INDIRECT_CALL_FUNCTION' references 'CALL_FUNCTION' at /tmp/src/invalid/indirect.ts(4,47)
'CALL_FUNCTION' calls 'functionToCall' at /tmp/src/invalid/function-call.ts(3,38).`);
});
it('should report a formatted error for a double-indirect refernce to a function call', () => {
expect(() => {
return reflector.annotations(
reflector.getStaticSymbol(fileName, 'TwoLevelsIndirectReferenceCalledFunction'));
})
.toThrowError(
`/tmp/src/invalid/components.ts(24,18): Error during template compile of 'TwoLevelsIndirectReferenceCalledFunction'
Function calls are not supported in decorators but 'functionToCall' was called in 'TWO_LEVELS_INDIRECT_CALL_FUNCTION'
'TWO_LEVELS_INDIRECT_CALL_FUNCTION' references 'INDIRECT_CALL_FUNCTION' at /tmp/src/invalid/two-levels-indirect.ts(4,58)
'INDIRECT_CALL_FUNCTION' references 'CALL_FUNCTION' at /tmp/src/invalid/indirect.ts(4,47)
'CALL_FUNCTION' calls 'functionToCall' at /tmp/src/invalid/function-call.ts(3,38).`);
});
});
describe('macro functions', () => {
const fileName = '/tmp/src/invalid/components.ts';
beforeEach(() => {
const localData = {
'/tmp/src/invalid/function-call.ts': `
import {functionToCall} from 'some-module';
export const CALL_FUNCTION = functionToCall();
`,
'/tmp/src/invalid/indirect.ts': `
import {CALL_FUNCTION} from './function-call';
export const INDIRECT_CALL_FUNCTION = CALL_FUNCTION + 1;
`,
'/tmp/src/invalid/macros.ts': `
export function someMacro(value: any) {
return [ { provide: 'key', value: value } ];
}
`,
'/tmp/src/invalid/components.ts': `
import {Component} from '@angular/core';
import {functionToCall} from 'some-module';
import {someMacro} from './macros';
import {CALL_FUNCTION} from './function-call';
import {INDIRECT_CALL_FUNCTION} from './indirect';
@Component({
template: someMacro(functionToCall())
})
export class DirectCall {}
@Component({
template: someMacro(CALL_FUNCTION)
})
export class IndirectCall {}
@Component({
template: someMacro(INDIRECT_CALL_FUNCTION)
})
export class DoubleIndirectCall {}
`
};
init({...DEFAULT_TEST_DATA, ...localData});
});
it('should report a formatted error for a direct function call', () => {
expect(() => {
return reflector.annotations(reflector.getStaticSymbol(fileName, 'DirectCall'));
})
.toThrowError(
`/tmp/src/invalid/components.ts(9,31): Error during template compile of 'DirectCall'
Function calls are not supported in decorators but 'functionToCall' was called.`);
});
it('should report a formatted error for a reference to a function call', () => {
expect(() => {
return reflector.annotations(reflector.getStaticSymbol(fileName, 'IndirectCall'));
})
.toThrowError(
`/tmp/src/invalid/components.ts(14,31): Error during template compile of 'IndirectCall'
Function calls are not supported in decorators but 'functionToCall' was called in 'CALL_FUNCTION'
'CALL_FUNCTION' calls 'functionToCall' at /tmp/src/invalid/function-call.ts(3,38).`);
});
it('should report a formatted error for an indirect refernece to a function call', () => {
expect(() => {
return reflector.annotations(reflector.getStaticSymbol(fileName, 'DoubleIndirectCall'));
})
.toThrowError(
`/tmp/src/invalid/components.ts(19,31): Error during template compile of 'DoubleIndirectCall'
Function calls are not supported in decorators but 'functionToCall' was called in 'INDIRECT_CALL_FUNCTION'
'INDIRECT_CALL_FUNCTION' references 'CALL_FUNCTION' at /tmp/src/invalid/indirect.ts(4,47)
'CALL_FUNCTION' calls 'functionToCall' at /tmp/src/invalid/function-call.ts(3,38).`);
});
});
describe('and give advice', () => {
// If in a reference expression, advice the user to replace with a reference.
const fileName = '/tmp/src/invalid/components.ts';
function collectError(symbol: string): string {
try {
reflector.annotations(reflector.getStaticSymbol(fileName, symbol));
} catch (e) {
return e.message;
}
fail('Expected an exception to be thrown');
return '';
}
function initWith(content: string) {
init({
...DEFAULT_TEST_DATA,
[fileName]: `import {Component} from '@angular/core';\n${content}`
});
}
it('should advise exorting a local', () => {
initWith(`const f: string; @Component({value: f}) export class MyComp {}`);
expect(collectError('MyComp')).toContain(`Consider exporting 'f'`);
});
it('should advise export a class', () => {
initWith('class Foo {} @Component({value: Foo}) export class MyComp {}');
expect(collectError('MyComp')).toContain(`Consider exporting 'Foo'`);
});
it('should advise avoiding destructuring', () => {
initWith(
'export const {foo, bar} = {foo: 1, bar: 2}; @Component({value: foo}) export class MyComp {}');
expect(collectError('MyComp')).toContain(`Consider simplifying to avoid destructuring`);
});
it('should advise converting an arrow function into an exported function', () => {
initWith('@Component({value: () => true}) export class MyComp {}');
expect(collectError('MyComp'))
.toContain(`Consider changing the function expression into an exported function`);
});
it('should advise converting a function expression into an exported function', () => {
initWith('@Component({value: function () { return true; }}) export class MyComp {}');
expect(collectError('MyComp'))
.toContain(`Consider changing the function expression into an exported function`);
});
});
});
}); });
const DEFAULT_TEST_DATA: {[key: string]: any} = { const DEFAULT_TEST_DATA: {[key: string]: any} = {
@ -1698,5 +1467,5 @@ const DEFAULT_TEST_DATA: {[key: string]: any} = {
export class Dep { export class Dep {
@Input f: Forward; @Input f: Forward;
} }
`, `
}; };

View File

@ -234,25 +234,15 @@ describe('StaticSymbolResolver', () => {
}); });
expect(symbolResolver.resolveSymbol(symbolCache.get('/test.ts', 'a')).metadata) expect(symbolResolver.resolveSymbol(symbolCache.get('/test.ts', 'a')).metadata)
.toEqual(symbolCache.get('/test2.ts', 'b')); .toEqual(symbolCache.get('/test2.ts', 'b'));
expect(symbolResolver.resolveSymbol(symbolCache.get('/test.ts', 'x')).metadata).toEqual([{ expect(symbolResolver.resolveSymbol(symbolCache.get('/test.ts', 'x')).metadata).toEqual([
__symbolic: 'resolved', symbolCache.get('/test2.ts', 'y')
symbol: symbolCache.get('/test2.ts', 'y'), ]);
line: 3,
character: 24,
fileName: '/test.ts'
}]);
expect(symbolResolver.resolveSymbol(symbolCache.get('/test.ts', 'simpleFn')).metadata).toEqual({ expect(symbolResolver.resolveSymbol(symbolCache.get('/test.ts', 'simpleFn')).metadata).toEqual({
__symbolic: 'function', __symbolic: 'function',
parameters: ['fnArg'], parameters: ['fnArg'],
value: [ value: [
symbolCache.get('/test.ts', 'a'), { symbolCache.get('/test.ts', 'a'), symbolCache.get('/test2.ts', 'y'),
__symbolic: 'resolved', Object({__symbolic: 'reference', name: 'fnArg'})
symbol: symbolCache.get('/test2.ts', 'y'),
line: 6,
character: 21,
fileName: '/test.ts'
},
{__symbolic: 'reference', name: 'fnArg'}
] ]
}); });
}); });

View File

@ -430,41 +430,5 @@ export function main() {
importAs: symbolCache.get('someFile.ngfactory.d.ts', 'lib_1') importAs: symbolCache.get('someFile.ngfactory.d.ts', 'lib_1')
}]); }]);
}); });
describe('with resolved symbols', () => {
it('should be able to serialize a call', () => {
init();
const serialized = serializeSummaries(
'someFile.ts', createMockOutputContext(), summaryResolver, symbolResolver, [{
symbol: symbolCache.get('/tmp/test.ts', 'main'),
metadata: {
__symbolic: 'call',
expression:
{__symbolic: 'resolved', symbol: symbolCache.get('/tmp/test2.ts', 'ref')}
}
}],
[]);
expect(serialized.json).not.toContain('error');
});
it('should be able to serialize a call to a method', () => {
init();
const serialized = serializeSummaries(
'someFile.ts', createMockOutputContext(), summaryResolver, symbolResolver, [{
symbol: symbolCache.get('/tmp/test.ts', 'main'),
metadata: {
__symbolic: 'call',
expression: {
__symbolic: 'select',
expression:
{__symbolic: 'resolved', symbol: symbolCache.get('/tmp/test2.ts', 'ref')},
name: 'foo'
}
}
}],
[]);
expect(serialized.json).not.toContain('error');
});
});
}); });
} }

View File

@ -20,5 +20,5 @@ export {DirectRenderer as ɵDirectRenderer, RenderDebugInfo as ɵRenderDebugInfo
export {global as ɵglobal, looseIdentical as ɵlooseIdentical, stringify as ɵstringify} from './util'; export {global as ɵglobal, looseIdentical as ɵlooseIdentical, stringify as ɵstringify} from './util';
export {makeDecorator as ɵmakeDecorator} from './util/decorators'; export {makeDecorator as ɵmakeDecorator} from './util/decorators';
export {isObservable as ɵisObservable, isPromise as ɵisPromise} from './util/lang'; export {isObservable as ɵisObservable, isPromise as ɵisPromise} from './util/lang';
export {clearOverrides as ɵclearOverrides, overrideComponentView as ɵoverrideComponentView, overrideProvider as ɵoverrideProvider} from './view/index'; export {clearProviderOverrides as ɵclearProviderOverrides, overrideProvider as ɵoverrideProvider} from './view/index';
export {NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR as ɵNOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR} from './view/provider'; export {NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR as ɵNOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR} from './view/provider';

View File

@ -7,12 +7,11 @@
*/ */
import {Injector} from '../di/injector'; import {Injector} from '../di/injector';
import {ComponentFactory} from '../linker/component_factory';
import {NgModuleFactory, NgModuleRef} from '../linker/ng_module_factory'; import {NgModuleFactory, NgModuleRef} from '../linker/ng_module_factory';
import {Type} from '../type'; import {Type} from '../type';
import {initServicesIfNeeded} from './services'; import {initServicesIfNeeded} from './services';
import {NgModuleDefinitionFactory, ProviderOverride, Services, ViewDefinition} from './types'; import {NgModuleDefinitionFactory, ProviderOverride, Services} from './types';
import {resolveDefinition} from './util'; import {resolveDefinition} from './util';
export function overrideProvider(override: ProviderOverride) { export function overrideProvider(override: ProviderOverride) {
@ -20,14 +19,9 @@ export function overrideProvider(override: ProviderOverride) {
return Services.overrideProvider(override); return Services.overrideProvider(override);
} }
export function overrideComponentView(comp: Type<any>, componentFactory: ComponentFactory<any>) { export function clearProviderOverrides() {
initServicesIfNeeded(); initServicesIfNeeded();
return Services.overrideComponentView(comp, componentFactory); return Services.clearProviderOverrides();
}
export function clearOverrides() {
initServicesIfNeeded();
return Services.clearOverrides();
} }
// Attention: this function is called as top level function. // Attention: this function is called as top level function.

View File

@ -7,7 +7,7 @@
*/ */
export {anchorDef, elementDef} from './element'; export {anchorDef, elementDef} from './element';
export {clearOverrides, createNgModuleFactory, overrideComponentView, overrideProvider} from './entrypoint'; export {clearProviderOverrides, createNgModuleFactory, overrideProvider} from './entrypoint';
export {ngContentDef} from './ng_content'; export {ngContentDef} from './ng_content';
export {moduleDef, moduleProvideDef} from './ng_module'; export {moduleDef, moduleProvideDef} from './ng_module';
export {directiveDef, pipeDef, providerDef} from './provider'; export {directiveDef, pipeDef, providerDef} from './provider';

View File

@ -14,7 +14,7 @@ import {ViewContainerRef} from '../linker/view_container_ref';
import {Renderer as RendererV1, Renderer2} from '../render/api'; import {Renderer as RendererV1, Renderer2} from '../render/api';
import {createChangeDetectorRef, createInjector, createRendererV1} from './refs'; 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 {BindingDef, BindingFlags, DepDef, DepFlags, NodeDef, NodeFlags, OutputDef, OutputType, ProviderData, QueryValueType, Services, ViewData, ViewFlags, ViewState, asElementData, asProviderData} from './types';
import {calcBindingFlags, checkBinding, dispatchEvent, isComponentView, splitDepsDsl, splitMatchedQueriesDsl, tokenKey, viewParentEl} from './util'; import {calcBindingFlags, checkBinding, dispatchEvent, isComponentView, splitDepsDsl, splitMatchedQueriesDsl, tokenKey, viewParentEl} from './util';
const RendererV1TokenKey = tokenKey(RendererV1); const RendererV1TokenKey = tokenKey(RendererV1);
@ -198,8 +198,7 @@ export function checkAndUpdateDirectiveInline(
if (changes) { if (changes) {
directive.ngOnChanges(changes); directive.ngOnChanges(changes);
} }
if ((def.flags & NodeFlags.OnInit) && if ((view.state & ViewState.FirstCheck) && (def.flags & NodeFlags.OnInit)) {
shouldCallLifecycleInitHook(view, ViewState.InitState_CallingOnInit, def.nodeIndex)) {
directive.ngOnInit(); directive.ngOnInit();
} }
if (def.flags & NodeFlags.DoCheck) { if (def.flags & NodeFlags.DoCheck) {
@ -223,8 +222,7 @@ export function checkAndUpdateDirectiveDynamic(
if (changes) { if (changes) {
directive.ngOnChanges(changes); directive.ngOnChanges(changes);
} }
if ((def.flags & NodeFlags.OnInit) && if ((view.state & ViewState.FirstCheck) && (def.flags & NodeFlags.OnInit)) {
shouldCallLifecycleInitHook(view, ViewState.InitState_CallingOnInit, def.nodeIndex)) {
directive.ngOnInit(); directive.ngOnInit();
} }
if (def.flags & NodeFlags.DoCheck) { if (def.flags & NodeFlags.DoCheck) {
@ -449,61 +447,17 @@ function updateProp(
return changes; return changes;
} }
// This function calls the ngAfterContentCheck, ngAfterContentInit,
// ngAfterViewCheck, and ngAfterViewInit lifecycle hooks (depending on the node
// flags in lifecycle). Unlike ngDoCheck, ngOnChanges and ngOnInit, which are
// called during a pre-order traversal of the view tree (that is calling the
// parent hooks before the child hooks) these events are sent in using a
// post-order traversal of the tree (children before parents). This changes the
// meaning of initIndex in the view state. For ngOnInit, initIndex tracks the
// expected nodeIndex which a ngOnInit should be called. When sending
// ngAfterContentInit and ngAfterViewInit it is the expected count of
// ngAfterContentInit or ngAfterViewInit methods that have been called. This
// ensure that dispite being called recursively or after picking up after an
// exception, the ngAfterContentInit or ngAfterViewInit will be called on the
// correct nodes. Consider for example, the following (where E is an element
// and D is a directive)
// Tree: pre-order index post-order index
// E1 0 6
// E2 1 1
// D3 2 0
// E4 3 5
// E5 4 4
// E6 5 2
// E7 6 3
// As can be seen, the post-order index has an unclear relationship to the
// pre-order index (postOrderIndex === preOrderIndex - parentCount +
// childCount). Since number of calls to ngAfterContentInit and ngAfterViewInit
// are stable (will be the same for the same view regardless of exceptions or
// recursion) we just need to count them which will roughly correspond to the
// post-order index (it skips elements and directives that do not have
// lifecycle hooks).
//
// For example, if an exception is raised in the E6.onAfterViewInit() the
// initIndex is left at 3 (by shouldCallLifecycleInitHook() which set it to
// initIndex + 1). When checkAndUpdateView() is called again D3, E2 and E6 will
// not have their ngAfterViewInit() called but, starting with E7, the rest of
// the view will begin getting ngAfterViewInit() called until a check and
// pass is complete.
//
// This algorthim also handles recursion. Consider if E4's ngAfterViewInit()
// indirectly calls E1's ChangeDetectorRef.detectChanges(). The expected
// initIndex is set to 6, the recusive checkAndUpdateView() starts walk again.
// D3, E2, E6, E7, E5 and E4 are skipped, ngAfterViewInit() is called on E1.
// When the recursion returns the initIndex will be 7 so E1 is skipped as it
// has already been called in the recursively called checkAnUpdateView().
export function callLifecycleHooksChildrenFirst(view: ViewData, lifecycles: NodeFlags) { export function callLifecycleHooksChildrenFirst(view: ViewData, lifecycles: NodeFlags) {
if (!(view.def.nodeFlags & lifecycles)) { if (!(view.def.nodeFlags & lifecycles)) {
return; return;
} }
const nodes = view.def.nodes; const nodes = view.def.nodes;
let initIndex = 0;
for (let i = 0; i < nodes.length; i++) { for (let i = 0; i < nodes.length; i++) {
const nodeDef = nodes[i]; const nodeDef = nodes[i];
let parent = nodeDef.parent; let parent = nodeDef.parent;
if (!parent && nodeDef.flags & lifecycles) { if (!parent && nodeDef.flags & lifecycles) {
// matching root node (e.g. a pipe) // matching root node (e.g. a pipe)
callProviderLifecycles(view, i, nodeDef.flags & lifecycles, initIndex++); callProviderLifecycles(view, i, nodeDef.flags & lifecycles);
} }
if ((nodeDef.childFlags & lifecycles) === 0) { if ((nodeDef.childFlags & lifecycles) === 0) {
// no child matches one of the lifecycles // no child matches one of the lifecycles
@ -513,28 +467,25 @@ export function callLifecycleHooksChildrenFirst(view: ViewData, lifecycles: Node
i === parent.nodeIndex + parent.childCount) { i === parent.nodeIndex + parent.childCount) {
// last child of an element // last child of an element
if (parent.directChildFlags & lifecycles) { if (parent.directChildFlags & lifecycles) {
initIndex = callElementProvidersLifecycles(view, parent, lifecycles, initIndex); callElementProvidersLifecycles(view, parent, lifecycles);
} }
parent = parent.parent; parent = parent.parent;
} }
} }
} }
function callElementProvidersLifecycles( function callElementProvidersLifecycles(view: ViewData, elDef: NodeDef, lifecycles: NodeFlags) {
view: ViewData, elDef: NodeDef, lifecycles: NodeFlags, initIndex: number): number {
for (let i = elDef.nodeIndex + 1; i <= elDef.nodeIndex + elDef.childCount; i++) { for (let i = elDef.nodeIndex + 1; i <= elDef.nodeIndex + elDef.childCount; i++) {
const nodeDef = view.def.nodes[i]; const nodeDef = view.def.nodes[i];
if (nodeDef.flags & lifecycles) { if (nodeDef.flags & lifecycles) {
callProviderLifecycles(view, i, nodeDef.flags & lifecycles, initIndex++); callProviderLifecycles(view, i, nodeDef.flags & lifecycles);
} }
// only visit direct children // only visit direct children
i += nodeDef.childCount; i += nodeDef.childCount;
} }
return initIndex;
} }
function callProviderLifecycles( function callProviderLifecycles(view: ViewData, index: number, lifecycles: NodeFlags) {
view: ViewData, index: number, lifecycles: NodeFlags, initIndex: number) {
const providerData = asProviderData(view, index); const providerData = asProviderData(view, index);
if (!providerData) { if (!providerData) {
return; return;
@ -544,15 +495,13 @@ function callProviderLifecycles(
return; return;
} }
Services.setCurrentNode(view, index); Services.setCurrentNode(view, index);
if (lifecycles & NodeFlags.AfterContentInit && if (lifecycles & NodeFlags.AfterContentInit) {
shouldCallLifecycleInitHook(view, ViewState.InitState_CallingAfterContentInit, initIndex)) {
provider.ngAfterContentInit(); provider.ngAfterContentInit();
} }
if (lifecycles & NodeFlags.AfterContentChecked) { if (lifecycles & NodeFlags.AfterContentChecked) {
provider.ngAfterContentChecked(); provider.ngAfterContentChecked();
} }
if (lifecycles & NodeFlags.AfterViewInit && if (lifecycles & NodeFlags.AfterViewInit) {
shouldCallLifecycleInitHook(view, ViewState.InitState_CallingAfterViewInit, initIndex)) {
provider.ngAfterViewInit(); provider.ngAfterViewInit();
} }
if (lifecycles & NodeFlags.AfterViewChecked) { if (lifecycles & NodeFlags.AfterViewChecked) {

View File

@ -10,7 +10,6 @@ import {isDevMode} from '../application_ref';
import {DebugElement, DebugNode, EventListener, getDebugNode, indexDebugNode, removeDebugNodeFromIndex} from '../debug/debug_node'; import {DebugElement, DebugNode, EventListener, getDebugNode, indexDebugNode, removeDebugNodeFromIndex} from '../debug/debug_node';
import {Injector} from '../di'; import {Injector} from '../di';
import {ErrorHandler} from '../error_handler'; import {ErrorHandler} from '../error_handler';
import {ComponentFactory} from '../linker/component_factory';
import {NgModuleRef} from '../linker/ng_module_factory'; import {NgModuleRef} from '../linker/ng_module_factory';
import {Renderer2, RendererFactory2, RendererStyleFlags2, RendererType2} from '../render/api'; import {Renderer2, RendererFactory2, RendererStyleFlags2, RendererType2} from '../render/api';
import {Sanitizer} from '../security'; import {Sanitizer} from '../security';
@ -19,9 +18,9 @@ import {Type} from '../type';
import {isViewDebugError, viewDestroyedError, viewWrappedDebugError} from './errors'; import {isViewDebugError, viewDestroyedError, viewWrappedDebugError} from './errors';
import {resolveDep} from './provider'; import {resolveDep} from './provider';
import {dirtyParentQueries, getQueryValue} from './query'; import {dirtyParentQueries, getQueryValue} from './query';
import {createInjector, createNgModuleRef, getComponentViewDefinitionFactory} from './refs'; import {createInjector, createNgModuleRef} from './refs';
import {ArgumentType, BindingFlags, CheckType, DebugContext, DepDef, ElementData, NgModuleDefinition, NgModuleProviderDef, NodeDef, NodeFlags, NodeLogger, ProviderOverride, RootData, Services, ViewData, ViewDefinition, ViewState, asElementData, asPureExpressionData} from './types'; import {ArgumentType, BindingFlags, CheckType, DebugContext, DepDef, ElementData, NgModuleDefinition, NgModuleProviderDef, NodeDef, NodeFlags, NodeLogger, ProviderOverride, RootData, Services, ViewData, ViewDefinition, ViewState, asElementData, asPureExpressionData} from './types';
import {NOOP, isComponentView, renderNode, resolveDefinition, splitDepsDsl, viewParentEl} from './util'; import {NOOP, isComponentView, renderNode, splitDepsDsl, viewParentEl} from './util';
import {checkAndUpdateNode, checkAndUpdateView, checkNoChangesNode, checkNoChangesView, createComponentView, createEmbeddedView, createRootView, destroyView} from './view'; import {checkAndUpdateNode, checkAndUpdateView, checkNoChangesNode, checkNoChangesView, createComponentView, createEmbeddedView, createRootView, destroyView} from './view';
@ -39,8 +38,7 @@ export function initServicesIfNeeded() {
Services.createComponentView = services.createComponentView; Services.createComponentView = services.createComponentView;
Services.createNgModuleRef = services.createNgModuleRef; Services.createNgModuleRef = services.createNgModuleRef;
Services.overrideProvider = services.overrideProvider; Services.overrideProvider = services.overrideProvider;
Services.overrideComponentView = services.overrideComponentView; Services.clearProviderOverrides = services.clearProviderOverrides;
Services.clearOverrides = services.clearOverrides;
Services.checkAndUpdateView = services.checkAndUpdateView; Services.checkAndUpdateView = services.checkAndUpdateView;
Services.checkNoChangesView = services.checkNoChangesView; Services.checkNoChangesView = services.checkNoChangesView;
Services.destroyView = services.destroyView; Services.destroyView = services.destroyView;
@ -60,8 +58,7 @@ function createProdServices() {
createComponentView: createComponentView, createComponentView: createComponentView,
createNgModuleRef: createNgModuleRef, createNgModuleRef: createNgModuleRef,
overrideProvider: NOOP, overrideProvider: NOOP,
overrideComponentView: NOOP, clearProviderOverrides: NOOP,
clearOverrides: NOOP,
checkAndUpdateView: checkAndUpdateView, checkAndUpdateView: checkAndUpdateView,
checkNoChangesView: checkNoChangesView, checkNoChangesView: checkNoChangesView,
destroyView: destroyView, destroyView: destroyView,
@ -87,8 +84,7 @@ function createDebugServices() {
createComponentView: debugCreateComponentView, createComponentView: debugCreateComponentView,
createNgModuleRef: debugCreateNgModuleRef, createNgModuleRef: debugCreateNgModuleRef,
overrideProvider: debugOverrideProvider, overrideProvider: debugOverrideProvider,
overrideComponentView: debugOverrideComponentView, clearProviderOverrides: debugClearProviderOverrides,
clearOverrides: debugClearOverrides,
checkAndUpdateView: debugCheckAndUpdateView, checkAndUpdateView: debugCheckAndUpdateView,
checkNoChangesView: debugCheckNoChangesView, checkNoChangesView: debugCheckNoChangesView,
destroyView: debugDestroyView, destroyView: debugDestroyView,
@ -143,15 +139,10 @@ function debugCreateEmbeddedView(
function debugCreateComponentView( function debugCreateComponentView(
parentView: ViewData, nodeDef: NodeDef, viewDef: ViewDefinition, hostElement: any): ViewData { parentView: ViewData, nodeDef: NodeDef, viewDef: ViewDefinition, hostElement: any): ViewData {
const overrideComponentView = const defWithOverride = applyProviderOverridesToView(viewDef);
viewDefOverrides.get(nodeDef.element !.componentProvider !.provider !.token);
if (overrideComponentView) {
viewDef = overrideComponentView;
} else {
viewDef = applyProviderOverridesToView(viewDef);
}
return callWithDebugContext( return callWithDebugContext(
DebugAction.create, createComponentView, null, [parentView, nodeDef, viewDef, hostElement]); DebugAction.create, createComponentView, null,
[parentView, nodeDef, defWithOverride, hostElement]);
} }
function debugCreateNgModuleRef( function debugCreateNgModuleRef(
@ -162,21 +153,13 @@ function debugCreateNgModuleRef(
} }
const providerOverrides = new Map<any, ProviderOverride>(); const providerOverrides = new Map<any, ProviderOverride>();
const viewDefOverrides = new Map<any, ViewDefinition>();
function debugOverrideProvider(override: ProviderOverride) { function debugOverrideProvider(override: ProviderOverride) {
providerOverrides.set(override.token, override); providerOverrides.set(override.token, override);
} }
function debugOverrideComponentView(comp: any, compFactory: ComponentFactory<any>) { function debugClearProviderOverrides() {
const hostViewDef = resolveDefinition(getComponentViewDefinitionFactory(compFactory));
const compViewDef = resolveDefinition(hostViewDef.nodes[0].element !.componentView !);
viewDefOverrides.set(comp, compViewDef);
}
function debugClearOverrides() {
providerOverrides.clear(); providerOverrides.clear();
viewDefOverrides.clear();
} }
// Notes about the algorithm: // Notes about the algorithm:

View File

@ -8,7 +8,6 @@
import {Injector} from '../di'; import {Injector} from '../di';
import {ErrorHandler} from '../error_handler'; import {ErrorHandler} from '../error_handler';
import {ComponentFactory} from '../linker/component_factory';
import {NgModuleRef} from '../linker/ng_module_factory'; import {NgModuleRef} from '../linker/ng_module_factory';
import {QueryList} from '../linker/query_list'; import {QueryList} from '../linker/query_list';
import {TemplateRef} from '../linker/template_ref'; import {TemplateRef} from '../linker/template_ref';
@ -17,7 +16,6 @@ import {Renderer2, RendererFactory2, RendererType2} from '../render/api';
import {Sanitizer, SecurityContext} from '../security'; import {Sanitizer, SecurityContext} from '../security';
import {Type} from '../type'; import {Type} from '../type';
// ------------------------------------- // -------------------------------------
// Defs // Defs
// ------------------------------------- // -------------------------------------
@ -354,7 +352,6 @@ export interface ViewData {
state: ViewState; state: ViewState;
oldValues: any[]; oldValues: any[];
disposables: DisposableFn[]|null; disposables: DisposableFn[]|null;
initIndex: number;
} }
/** /**
@ -370,52 +367,8 @@ export const enum ViewState {
CheckProjectedViews = 1 << 6, CheckProjectedViews = 1 << 6,
Destroyed = 1 << 7, Destroyed = 1 << 7,
// InitState Uses 3 bits
InitState_Mask = 7 << 8,
InitState_BeforeInit = 0 << 8,
InitState_CallingOnInit = 1 << 8,
InitState_CallingAfterContentInit = 2 << 8,
InitState_CallingAfterViewInit = 3 << 8,
InitState_AfterInit = 4 << 8,
CatDetectChanges = Attached | ChecksEnabled, CatDetectChanges = Attached | ChecksEnabled,
CatInit = BeforeFirstCheck | CatDetectChanges | InitState_BeforeInit CatInit = BeforeFirstCheck | CatDetectChanges
}
// Called before each cycle of a view's check to detect whether this is in the
// initState for which we need to call ngOnInit, ngAfterContentInit or ngAfterViewInit
// lifecycle methods. Returns true if this check cycle should call lifecycle
// methods.
export function shiftInitState(
view: ViewData, priorInitState: ViewState, newInitState: ViewState): boolean {
// Only update the InitState if we are currently in the prior state.
// For example, only move into CallingInit if we are in BeforeInit. Only
// move into CallingContentInit if we are in CallingInit. Normally this will
// always be true because of how checkCycle is called in checkAndUpdateView.
// However, if checkAndUpdateView is called recursively or if an exception is
// thrown while checkAndUpdateView is running, checkAndUpdateView starts over
// from the beginning. This ensures the state is monotonically increasing,
// terminating in the AfterInit state, which ensures the Init methods are called
// at least once and only once.
const state = view.state;
const initState = state & ViewState.InitState_Mask;
if (initState === priorInitState) {
view.state = (state & ~ViewState.InitState_Mask) | newInitState;
view.initIndex = -1;
return true;
}
return initState === newInitState;
}
// Returns true if the lifecycle init method should be called for the node with
// the given init index.
export function shouldCallLifecycleInitHook(
view: ViewData, initState: ViewState, index: number): boolean {
if ((view.state & ViewState.InitState_Mask) === initState && view.initIndex <= index) {
view.initIndex = index + 1;
return true;
}
return false;
} }
export interface DisposableFn { (): void; } export interface DisposableFn { (): void; }
@ -569,8 +522,7 @@ export interface Services {
moduleType: Type<any>, parent: Injector, bootstrapComponents: Type<any>[], moduleType: Type<any>, parent: Injector, bootstrapComponents: Type<any>[],
def: NgModuleDefinition): NgModuleRef<any>; def: NgModuleDefinition): NgModuleRef<any>;
overrideProvider(override: ProviderOverride): void; overrideProvider(override: ProviderOverride): void;
overrideComponentView(compType: Type<any>, compFactory: ComponentFactory<any>): void; clearProviderOverrides(): void;
clearOverrides(): void;
checkAndUpdateView(view: ViewData): void; checkAndUpdateView(view: ViewData): void;
checkNoChangesView(view: ViewData): void; checkNoChangesView(view: ViewData): void;
destroyView(view: ViewData): void; destroyView(view: ViewData): void;
@ -595,8 +547,7 @@ export const Services: Services = {
createComponentView: undefined !, createComponentView: undefined !,
createNgModuleRef: undefined !, createNgModuleRef: undefined !,
overrideProvider: undefined !, overrideProvider: undefined !,
overrideComponentView: undefined !, clearProviderOverrides: undefined !,
clearOverrides: undefined !,
checkAndUpdateView: undefined !, checkAndUpdateView: undefined !,
checkNoChangesView: undefined !, checkNoChangesView: undefined !,
destroyView: undefined !, destroyView: undefined !,

View File

@ -16,7 +16,7 @@ import {checkAndUpdatePureExpressionDynamic, checkAndUpdatePureExpressionInline,
import {checkAndUpdateQuery, createQuery} from './query'; import {checkAndUpdateQuery, createQuery} from './query';
import {createTemplateData, createViewContainerData} from './refs'; import {createTemplateData, createViewContainerData} from './refs';
import {checkAndUpdateTextDynamic, checkAndUpdateTextInline, createText} from './text'; import {checkAndUpdateTextDynamic, checkAndUpdateTextInline, createText} from './text';
import {ArgumentType, CheckType, ElementData, NodeData, NodeDef, NodeFlags, ProviderData, RootData, Services, ViewData, ViewDefinition, ViewFlags, ViewHandleEventFn, ViewState, ViewUpdateFn, asElementData, asQueryList, asTextData, shiftInitState} from './types'; import {ArgumentType, CheckType, ElementData, NodeData, NodeDef, NodeFlags, ProviderData, RootData, Services, ViewData, ViewDefinition, ViewFlags, ViewHandleEventFn, ViewState, ViewUpdateFn, asElementData, asQueryList, asTextData} from './types';
import {NOOP, checkBindingNoChanges, isComponentView, markParentViewsForCheckProjectedViews, resolveDefinition, tokenKey} from './util'; import {NOOP, checkBindingNoChanges, isComponentView, markParentViewsForCheckProjectedViews, resolveDefinition, tokenKey} from './util';
import {detachProjectedView} from './view_attach'; import {detachProjectedView} from './view_attach';
@ -236,8 +236,7 @@ function createView(
context: null, context: null,
component: null, nodes, component: null, nodes,
state: ViewState.CatInit, root, renderer, state: ViewState.CatInit, root, renderer,
oldValues: new Array(def.bindingCount), disposables, oldValues: new Array(def.bindingCount), disposables
initIndex: -1
}; };
return view; return view;
} }
@ -354,32 +353,29 @@ export function checkAndUpdateView(view: ViewData) {
} else { } else {
view.state &= ~ViewState.FirstCheck; view.state &= ~ViewState.FirstCheck;
} }
shiftInitState(view, ViewState.InitState_BeforeInit, ViewState.InitState_CallingOnInit);
markProjectedViewsForCheck(view); markProjectedViewsForCheck(view);
Services.updateDirectives(view, CheckType.CheckAndUpdate); Services.updateDirectives(view, CheckType.CheckAndUpdate);
execEmbeddedViewsAction(view, ViewAction.CheckAndUpdate); execEmbeddedViewsAction(view, ViewAction.CheckAndUpdate);
execQueriesAction( execQueriesAction(
view, NodeFlags.TypeContentQuery, NodeFlags.DynamicQuery, CheckType.CheckAndUpdate); view, NodeFlags.TypeContentQuery, NodeFlags.DynamicQuery, CheckType.CheckAndUpdate);
let callInit = shiftInitState(
view, ViewState.InitState_CallingOnInit, ViewState.InitState_CallingAfterContentInit);
callLifecycleHooksChildrenFirst( callLifecycleHooksChildrenFirst(
view, NodeFlags.AfterContentChecked | (callInit ? NodeFlags.AfterContentInit : 0)); view, NodeFlags.AfterContentChecked |
(view.state & ViewState.FirstCheck ? NodeFlags.AfterContentInit : 0));
Services.updateRenderer(view, CheckType.CheckAndUpdate); Services.updateRenderer(view, CheckType.CheckAndUpdate);
execComponentViewsAction(view, ViewAction.CheckAndUpdate); execComponentViewsAction(view, ViewAction.CheckAndUpdate);
execQueriesAction( execQueriesAction(
view, NodeFlags.TypeViewQuery, NodeFlags.DynamicQuery, CheckType.CheckAndUpdate); view, NodeFlags.TypeViewQuery, NodeFlags.DynamicQuery, CheckType.CheckAndUpdate);
callInit = shiftInitState(
view, ViewState.InitState_CallingAfterContentInit, ViewState.InitState_CallingAfterViewInit);
callLifecycleHooksChildrenFirst( callLifecycleHooksChildrenFirst(
view, NodeFlags.AfterViewChecked | (callInit ? NodeFlags.AfterViewInit : 0)); view, NodeFlags.AfterViewChecked |
(view.state & ViewState.FirstCheck ? NodeFlags.AfterViewInit : 0));
if (view.def.flags & ViewFlags.OnPush) { if (view.def.flags & ViewFlags.OnPush) {
view.state &= ~ViewState.ChecksEnabled; view.state &= ~ViewState.ChecksEnabled;
} }
view.state &= ~(ViewState.CheckProjectedViews | ViewState.CheckProjectedView); view.state &= ~(ViewState.CheckProjectedViews | ViewState.CheckProjectedView);
shiftInitState(view, ViewState.InitState_CallingAfterViewInit, ViewState.InitState_AfterInit);
} }
export function checkAndUpdateNode( export function checkAndUpdateNode(

View File

@ -31,7 +31,7 @@ import {EventEmitter} from '../event_emitter';
* import {NgIf} from '@angular/common'; * import {NgIf} from '@angular/common';
* *
* @Component({ * @Component({
* selector: 'ng-zone-demo', * selector: 'ng-zone-demo'.
* template: ` * template: `
* <h2>Demo: NgZone</h2> * <h2>Demo: NgZone</h2>
* *
@ -64,9 +64,8 @@ import {EventEmitter} from '../event_emitter';
* this._ngZone.runOutsideAngular(() => { * this._ngZone.runOutsideAngular(() => {
* this._increaseProgress(() => { * this._increaseProgress(() => {
* // reenter the Angular zone and display done * // reenter the Angular zone and display done
* this._ngZone.run(() => { console.log('Outside Done!'); }); * this._ngZone.run(() => {console.log('Outside Done!') });
* }); * }}));
* });
* } * }
* *
* _increaseProgress(doneCallback: () => void) { * _increaseProgress(doneCallback: () => void) {
@ -74,7 +73,7 @@ import {EventEmitter} from '../event_emitter';
* console.log(`Current progress: ${this.progress}%`); * console.log(`Current progress: ${this.progress}%`);
* *
* if (this.progress < 100) { * if (this.progress < 100) {
* window.setTimeout(() => this._increaseProgress(doneCallback), 10); * window.setTimeout(() => this._increaseProgress(doneCallback)), 10)
* } else { * } else {
* doneCallback(); * doneCallback();
* } * }

View File

@ -80,38 +80,6 @@ export function main() {
flushMicrotasks(); flushMicrotasks();
expect(cmp.status).toEqual('done'); expect(cmp.status).toEqual('done');
})); }));
it('should always run .start callbacks before .done callbacks even for noop animations',
fakeAsync(() => {
@Component({
selector: 'cmp',
template: `
<div [@myAnimation]="exp" (@myAnimation.start)="cb('start')" (@myAnimation.done)="cb('done')"></div>
`,
animations: [
trigger(
'myAnimation',
[
transition('* => go', []),
]),
]
})
class Cmp {
exp: any = false;
log: string[] = [];
cb(status: string) { this.log.push(status); }
}
TestBed.configureTestingModule({declarations: [Cmp]});
const fixture = TestBed.createComponent(Cmp);
const cmp = fixture.componentInstance;
cmp.exp = 'go';
fixture.detectChanges();
expect(cmp.log).toEqual([]);
flushMicrotasks();
expect(cmp.log).toEqual(['start', 'done']);
}));
}); });
describe('component fixture integration', () => { describe('component fixture integration', () => {

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