Compare commits

...

59 Commits

Author SHA1 Message Date
27a2515c74 ci: mark PRs with rejection as not green 2018-01-30 14:43:32 -08:00
407b5cf408 refactor(ivy): re-introduce QueryPredicate with more focused role (#21857) (#21857)
PR Close #21857

PR Close #21857
2018-01-30 11:52:35 -08:00
4c1743cce3 refactor(ivy): rename QueryPredicate to LQuery (#21857)
PR Close #21857
2018-01-30 11:52:35 -08:00
7305e8b45e refactor(ivy): rename LQuery to LQueries and associated renames (#21857)
PR Close #21857
2018-01-30 11:52:32 -08:00
285dd6be34 feat(ivy): observable QueryList (#21859)
PR Close #21859
2018-01-30 11:43:38 -08:00
b10540a0b5 feat(service-worker): add helper script which will uninstall SW (#21863)
Service Workers can be tricky to work with in production, and often
it becomes necessary to deactivate an existing SW. This is trickier
than one might imagine - as long as clients on the old SW may exist
it is important to serve some script at the old SW URL. This commit
adds safety-worker.js to the published NPM package, which is useful
for that purpose. On install the SW unregisters itself which safely
and gradually allows older clients to update.

PR Close #21863
2018-01-30 11:43:03 -08:00
b62739a989 fix(common): generate closure-locale data file with exported plural functions (#21873)
Fixes #21870
PR Close #21873
2018-01-30 11:42:31 -08:00
bb577c624b ci: unblock master by ignoring date pipe tests while we fix it (#21906)
PR Close #21906
2018-01-30 11:33:46 -08:00
02483a01ad Revert: "refactor(ivy): save check methods separately"
This reverts commit 278889c7b420e530834c457f82a54e33a846a828.
2018-01-29 21:42:37 -08:00
120bdeecdc fix(common): allow HttpInterceptors to inject HttpClient (#19809)
Previously, an interceptor attempting to inject HttpClient directly
would receive a circular dependency error, as HttpClient was
constructed via a factory which injected the interceptor instances.
Users want to inject HttpClient into interceptors to make supporting
requests (ex: to retrieve an authentication token). Currently this is
only possible by injecting the Injector and using it to resolve
HttpClient at request time.

Either HttpClient or the user has to deal specially with the circular
dependency. This change moves that responsibility into HttpClient
itself. By utilizing a new class HttpInterceptingHandler which lazily
loads the set of interceptors at request time, it's possible to inject
HttpClient directly into interceptors as construction of HttpClient no
longer requires the interceptor chain to be constructed.

Fixes #18224.

PR Close #19809
2018-01-29 16:12:32 -08:00
8dff9d84ed refactor(ivy): save check methods separately (#21795)
PR Close #21795
2018-01-29 16:12:02 -08:00
b4cd27979b fix(forms): inserting and removing controls should work in re-bound form arrays (#21822)
Closes #21501

PR Close #21822
2018-01-29 16:11:41 -08:00
11b12670b2 docs: document debugging a Node test in VSCode/Bazel (#21868)
PR Close #21868
2018-01-29 16:11:09 -08:00
dd48df105b perf(ivy): use buildOptimizer in hello_world__render3__rollup integration test (#21744)
PR Close #21744
2018-01-29 11:35:51 -08:00
18174e5564 feat(ivy): support ng-content projection in the ivy compiler (#21764)
PR Close #21764
2018-01-29 11:35:32 -08:00
72265f796f fix(aio): missing plural s in preserveWhiteSpaces example (#21854)
PR Close #21854
2018-01-29 11:35:13 -08:00
6e8bc310f0 docs: change ”it's" to "its" as needed in several docs. (#21867)
Most of them are in content but one is in common and needs special approval.

PR Close #21867
2018-01-29 11:34:46 -08:00
c40ae7f7cf feat(router): add navigationSource and restoredState to NavigationStart event (#21728)
Currently, NavigationStart there is no way to know if an navigation was triggered imperatively or via the location change. These two use cases should be handled differently for a variety of use cases (e.g., scroll position restoration). This PR adds a navigation source field and restored navigation id (passed to navigations triggered by a URL change).

PR Close #21728
2018-01-29 10:22:59 -08:00
5bd93b1f0f build: fix broken build (#21835)
PR Close #21835
2018-01-27 14:19:29 -08:00
a1cc02f0bd build: update to latest bazel rules (#21821)
PR Close #21821
2018-01-27 10:55:44 -08:00
5778bb820a fix(ivy): fix issues found producing "Hello, World" example (#21790)
PR Close #21790
2018-01-27 10:50:13 -08:00
87754ad5ec fix(ivy): emit type type fields (#21789)
PR Close #21789
2018-01-27 10:49:54 -08:00
d364117aa8 fix(ivy): correct errors in template variable specification (#21759)
PR Close #21759
2018-01-27 10:49:30 -08:00
6245637e81 fix(ivy): correct query read logic after merges (#21749)
PR Close #21749
2018-01-27 10:49:09 -08:00
ab69f12e2c refactor(ivy): code review changes (#21638)
PR Close #21638
2018-01-27 10:48:39 -08:00
1278cca883 perf(ivy): removes generation of comments (#21638)
PR Close #21638
2018-01-27 10:48:39 -08:00
ede9cb7c2f Revert: "feat(router): add navigationSource and restoredState to NavigationStart event (#21728)"
This reverts commit 3b7bab7d22. Will be re-merged after fixing integration of minor breaking change.
2018-01-26 16:24:56 -08:00
c3fb820473 fix(aio): don't set noindex metatag in the static index.html (#21816)
This seems to be causing crawling issues for google.

Ref #21665

PR Close #21816
2018-01-26 16:08:30 -08:00
2af19c96f2 fix(core): fix retrieving the binding name when an expression changes (#21814)
fixes #21735
fixes #21788

PR Close #21814
2018-01-26 15:34:47 -08:00
dcca799dbb fix(ivy): call onChanges before onInit (#21793)
PR Close #21793
2018-01-26 14:57:03 -08:00
d3d3f7191a test(ivy): add canonical lifecycle example (#21793)
PR Close #21793
2018-01-26 14:57:03 -08:00
e0b31dbfef build: merge-pr now checks that PR status is green before proceeding (#21810)
Optionally one can use `--force` to override and merge no non-green PR.

PR Close #21810
2018-01-26 14:50:41 -08:00
8df56fe93a build(aio): prevent Windows error on serve-and-sync (#21806)
Running `yarn start` (which watches the `src/` directory) and
`yarn docs-watch` (which cleans up files in `src/generated/api/`) often
results in `ENOTEMPTY` errors.

This commit solves it by ensuring that `yarn docs` has been completed
before running `yarn start`.

PR Close #21806
2018-01-26 14:50:15 -08:00
676d9c2c4b fix(language-service): ensure correct paths are passed to TypeScript (#21812)
The 2.6 version of TypeScript's `resolveModuleName`  started to
require paths passed to be separated by '/' instead of being
able to handle '\'.

`ngc` and `ng` already do this transformation.

Fixes: #21811

PR Close #21812
2018-01-26 14:49:23 -08:00
2b68e8d98a fix(language-service): spell diagnostics correctly (#21812)
PR Close #21812
2018-01-26 14:49:23 -08:00
d964491f2a fix(router): remove @internal tag on ParamInheritanceType (#21773)
This is a more defensive approach to ensure that references to
ParamInheritanceType from the published declarations do not cause
compilation errors when compiling Angular from the published packages.

Fixes #21456

PR Close #21773
2018-01-26 10:28:33 -08:00
e6080527c6 docs: add notes on email used for CLA (#21754)
Closes #20034

PR Close #21754
2018-01-26 10:28:18 -08:00
3b7bab7d22 feat(router): add navigationSource and restoredState to NavigationStart event (#21728)
Currently, NavigationStart there is no way to know if an navigation was triggered imperatively or via the location change. These two use cases should be handled differently for a variety of use cases (e.g., scroll position restoration). This PR adds a navigation source field and restored navigation id (passed to navigations triggered by a URL change).

PR Close #21728
2018-01-26 10:25:32 -08:00
108fa15792 fix(aio): close SideNav on non-sidenav doc on wide screen (#21538)
Partly addresses #21520.

PR Close #21538
2018-01-26 10:25:15 -08:00
1b2271a3b1 fix(aio): fix SideNav height on narrow screens (#21538)
Since we specify `bottom: 0`, specifying the height is unnecessary and
leads to wrong height (unless updated) on narrow screens where the
topbar height is decreased.

Partly addresses #21520.

PR Close #21538
2018-01-26 10:25:15 -08:00
f9381e42de feat(ivy): implement QueryList array-related methods (#21778)
PR Close #21778
2018-01-25 22:19:43 -08:00
bbb8f386f1 feat(ivy): implement template variables (#21760)
PR Close #21760
2018-01-25 22:19:20 -08:00
08aa54e1d9 ci: Add back the CLI integration test with pinning (#21555)
The CLI app is now checked in, rather than generated dynamically with
`ng new`. This loses some assertion power, but gains hermeticity.
It also checks in lock files for all integration tests, avoiding
floating version numbers.

We'll need another place to integration test between changes in
the various repositories - but the angular/angular PR-blocking status
is not the right place to do this.

PR Close #21555
2018-01-25 22:18:55 -08:00
fac4d8d42a build(common): specify explicit locales dir in package.json (#21016)
PR Close #21016
2018-01-25 22:18:35 -08:00
170885c51b fix(forms): allow FormBuilder to create controls with any formState type (#20917)
Align formState type in FormBuilder#control with FormControl#constructor

Fixes #20368

PR Close #20917
2018-01-25 22:17:43 -08:00
5713faa667 build: autosquashes SHAs as part of merge-pr script (#21791)
To support `git checkin --fixup` and `git checkin —squash`
we need to make sure that `merge-pr` squashes the sepecial
commits before they are merged.

For more details see:
https://robots.thoughtbot.com/autosquashing-git-commits

PR Close #21791
2018-01-25 22:12:11 -08:00
23596b3f30 docs(aio): fix missing stylesheet in component-styles example (#21772)
The code in the example was referring to `hero-app.component.css` but this did
not exist.

PR Close #21772
2018-01-25 13:38:12 -08:00
f8fa20d71a docs(aio): fix paths to imported CSS stylesheets (#21772)
The AOT compiler needs relative paths so that it can find
the imported stylesheets.

PR Close #21772
2018-01-25 13:38:12 -08:00
d6d8fe829a build(aio): upgrade CLI version to cope with new Angular 6.0.0-beta.1 release (#21772)
Before version 1.6 of Angular CLI there was a check that prevented use of Angular
compiler CLI with major version 6.

PR Close #21772
2018-01-25 13:38:12 -08:00
5269ce287e feat(ivy): support deep queries through view boundaries (#21700)
PR Close #21700
2018-01-24 22:18:38 -08:00
3e03dbe576 refactor(ivy): flatten hooks and collapse LView hook properties (#21650)
PR Close #21650
2018-01-24 22:14:33 -08:00
33b338120c refactor(ivy): move onDestroys out of cleanup (#21650)
PR Close #21650
2018-01-24 22:14:33 -08:00
811679a583 refactor(ivy): remove unnecessary Comp.r function (#21650)
PR Close #21650
2018-01-24 22:14:33 -08:00
2c33d17609 refactor(ivy): move content and view hooks into TView (#21650)
PR Close #21650
2018-01-24 22:14:32 -08:00
9c99e6a838 refactor(ivy): move init hooks into TView (#21650)
PR Close #21650
2018-01-24 22:14:32 -08:00
98174758ad refactor(ivy): add type and hooks to directive def (#21650)
PR Close #21650
2018-01-24 22:14:32 -08:00
97b928053d fix(ivy): correct onDestroy order for projected components (#21650)
PR Close #21650
2018-01-24 22:14:32 -08:00
1fe55e252c feat(ivy): add afterContentInit and afterContentChecked to render3 (#21650)
PR Close #21650
2018-01-24 22:14:32 -08:00
53ed4b4648 test(ivy): add missing lifecycle tests for projected components (#21650)
PR Close #21650
2018-01-24 22:14:32 -08:00
156 changed files with 33775 additions and 2178 deletions

View File

@ -44,6 +44,7 @@ groups:
all:
users: all
required: 1
rejection_value: -999
# In this group, your self-approval does not count
author_approval:
auto: false

View File

@ -24,9 +24,7 @@ filegroup(
"typescript",
"zone.js",
"tsutils",
"@types/jasmine",
"@types/node",
"@types/source-map",
"@types",
"tsickle",
"hammerjs",
"protobufjs",

View File

@ -72,7 +72,7 @@ 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
that relates to your submission. You don't want to duplicate effort.
1. Please sign our [Contributor License Agreement (CLA)](#cla) before sending PRs.
We cannot accept code without this.
We cannot accept code without this. Make sure you sign with the primary email address of the Git identity that has been granted access to the Angular repository.
1. Fork the angular/angular repo.
1. Make your changes in a new git branch:
@ -259,6 +259,19 @@ changes to be accepted, the CLA must be signed. It's a quick process, we promise
* For corporations we'll need you to
[print, sign and one of scan+email, fax or mail the form][corporate-cla].
<hr>
If you have more than one Git identity, you must make sure that you sign the CLA using the primary email address associated with the ID that has been granted access to the Angular repository. Git identities can be associated with more than one email address, and only one is primary. Here are some links to help you sort out multiple Git identities and email addresses:
* https://help.github.com/articles/setting-your-commit-email-address-in-git/
* https://stackoverflow.com/questions/37245303/what-does-usera-committed-with-userb-13-days-ago-on-github-mean
* https://help.github.com/articles/about-commit-email-addresses/
* https://help.github.com/articles/blocking-command-line-pushes-that-expose-your-personal-email-address/
Note that if you have more than one Git identity, it is important to verify that you are logged in with the same ID with which you signed the CLA, before you commit changes. If not, your PR will fail the CLA check.
<hr>
[angular-group]: https://groups.google.com/forum/#!forum/angular
[coc]: https://github.com/angular/code-of-conduct/blob/master/CODE_OF_CONDUCT.md

View File

@ -5,7 +5,7 @@ load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
git_repository(
name = "build_bazel_rules_nodejs",
remote = "https://github.com/bazelbuild/rules_nodejs.git",
tag = "0.3.1",
commit = "230d39a391226f51c03448f91eb61370e2e58c42",
)
load("@build_bazel_rules_nodejs//:defs.bzl", "check_bazel_version", "node_repositories")
@ -16,7 +16,7 @@ node_repositories(package_json = ["//:package.json"])
git_repository(
name = "build_bazel_rules_typescript",
remote = "https://github.com/bazelbuild/rules_typescript.git",
commit = "c4ea003acd7d42269b81a2d25eb832972cd24912"
commit = "eb3244363e1cb265c84e723b347926f28c29aa35"
)
load("@build_bazel_rules_typescript//:defs.bzl", "ts_setup_workspace")

View File

@ -1,5 +1,6 @@
/* #docregion import */
@import 'hero-details-box.css';
/* The AOT compiler needs the `./` to show that this is local */
@import './hero-details-box.css';
/* #enddocregion import */
/* #docregion host */

View File

@ -5,7 +5,8 @@ import { Hero } from './hero';
@Component({
selector: 'app-hero-team',
template: `
<link rel="stylesheet" href="assets/hero-team.component.css">
<!-- We must use a relative URL so that the AOT compiler can find the stylesheet -->
<link rel="stylesheet" href="../assets/hero-team.component.css">
<h3>Team</h3>
<ul>
<li *ngFor="let member of hero.team">

View File

@ -92,7 +92,7 @@ You can control your app compilation by providing template compiler options in t
},
"angularCompilerOptions": {
"fullTemplateTypeCheck": true,
"preserveWhiteSpace": false,
"preserveWhiteSpaces": false,
...
}
}

View File

@ -14,7 +14,7 @@ You can run the <live-example></live-example> in Stackblitz and download the cod
## Using component styles
For every Angular component you write, you may define not only an HTML template,
but also the CSS styles that go with that template,
but also the CSS styles that go with that template,
specifying any selectors, rules, and media queries that you need.
One way to do this is to set the `styles` property in the component metadata.
@ -42,7 +42,7 @@ This scoping restriction is a ***styling modularity feature***.
* You can use the CSS class names and selectors that make the most sense in the context of each component.
* Class names and selectors are local to the component and don't collide with
* Class names and selectors are local to the component and don't collide with
classes and selectors used elsewhere in the application.
@ -61,7 +61,7 @@ This scoping restriction is a ***styling modularity feature***.
## Special selectors
Component styles have a few special *selectors* from the world of shadow DOM style scoping
(described in the [CSS Scoping Module Level 1](https://www.w3.org/TR/css-scoping-1) page on the
(described in the [CSS Scoping Module Level 1](https://www.w3.org/TR/css-scoping-1) page on the
[W3C](https://www.w3.org) site).
The following sections describe these selectors.
@ -78,7 +78,7 @@ The `:host` selector is the only way to target the host element. You can't reach
the host element from inside the component with other selectors because it's not part of the
component's own template. The host element is in a parent component's template.
Use the *function form* to apply host styles conditionally by
Use the *function form* to apply host styles conditionally by
including another selector inside parentheses after `:host`.
The next example targets the host element again, but only when it also has the `active` CSS class.
@ -104,15 +104,15 @@ if some ancestor element has the CSS class `theme-light`.
### (deprecated) `/deep/`, `>>>`, and `::ng-deep`
Component styles normally apply only to the HTML in the component's own template.
Component styles normally apply only to the HTML in the component's own template.
Use the `/deep/` shadow-piercing descendant combinator to force a style down through the child
component tree into all the child component views.
The `/deep/` combinator works to any depth of nested components, and it applies to both the view
children and content children of the component.
children and content children of the component.
The following example targets all `<h3>` elements, from the host element down
through this component to all of its child elements in the DOM.
The following example targets all `<h3>` elements, from the host element down
through this component to all of its child elements in the DOM.
<code-example path="component-styles/src/app/hero-details.component.css" region="deep" title="src/app/hero-details.component.css" linenums="false">
@ -140,7 +140,7 @@ Until then `::ng-deep` should be preferred for a broader compatibility with the
## Loading component styles
There are several ways to add styles to a component:
There are several ways to add styles to a component:
* By setting `styles` or `styleUrls` metadata.
* Inline in the template HTML.
@ -177,8 +177,8 @@ to a component's `@Component` decorator:
<code-tabs>
<code-pane title="src/app/hero-app.component.ts (CSS in file)" path="component-styles/src/app/hero-app.component.1.ts"></code-pane>
<code-pane title="src/app/hero-app.component.css" path="component-styles/src/app/hero-app.component.1.css"></code-pane>
</code-tabs>
<code-pane title="src/app/hero-app.component.css" path="component-styles/src/app/hero-app.component.css"></code-pane>
</code-tabs>
<div class="alert is-critical">
@ -209,14 +209,14 @@ inside `<style>` tags.
### Template link tags
You can also write `<link>` tags into the component's HTML template.
You can also write `<link>` tags into the component's HTML template.
<code-example path="component-styles/src/app/hero-team.component.ts" region="stylelink" title="src/app/hero-team.component.ts">
</code-example>
<div class="alert is-critical">
The link tag's `href` URL must be relative to the
The link tag's `href` URL must be relative to the
_**application root**_, not relative to the component file.
When building with the CLI, be sure to include the linked style file among the assets to be copied to the server as described in the [CLI documentation](https://github.com/angular/angular-cli/wiki/stories-asset-configuration).
@ -244,7 +244,7 @@ See the [CLI documentation](https://github.com/angular/angular-cli/wiki/stories-
### Non-CSS style files
If you're building with the CLI,
If you're building with the CLI,
you can write style files in [sass](http://sass-lang.com/), [less](http://lesscss.org/), or [stylus](http://stylus-lang.com/) and specify those files in the `@Component.styleUrls` metadata with the appropriate extensions (`.scss`, `.less`, `.styl`) as in the following example:
<code-example>
@ -259,7 +259,7 @@ you can write style files in [sass](http://sass-lang.com/), [less](http://lesscs
The CLI build process runs the pertinent CSS preprocessor.
When generating a component file with `ng generate component`, the CLI emits an empty CSS styles file (`.css`) by default.
You can configure the CLI to default to your preferred CSS preprocessor
You can configure the CLI to default to your preferred CSS preprocessor
as explained in the [CLI documentation](https://github.com/angular/angular-cli/wiki/stories-css-preprocessors
"CSS Preprocessor integration").
@ -281,7 +281,7 @@ component* basis, you can set the *view encapsulation mode* in the component met
Choose from the following modes:
* `Native` view encapsulation uses the browser's native shadow DOM implementation (see
[Shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Shadow_DOM)
[Shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Shadow_DOM)
on the [MDN](https://developer.mozilla.org) site)
to attach a shadow DOM to the component's host element, and then puts the component
view inside that shadow DOM. The component's styles are included within the shadow DOM.
@ -290,18 +290,18 @@ Choose from the following modes:
(and renaming) the CSS code to effectively scope the CSS to the component's view.
For details, see [Appendix 1](guide/component-styles#inspect-generated-css).
* `None` means that Angular does no view encapsulation.
Angular adds the CSS to the global styles.
The scoping rules, isolations, and protections discussed earlier don't apply.
* `None` means that Angular does no view encapsulation.
Angular adds the CSS to the global styles.
The scoping rules, isolations, and protections discussed earlier don't apply.
This is essentially the same as pasting the component's styles into the HTML.
To set the components encapsulation mode, use the `encapsulation` property in the component metadata:
<code-example path="component-styles/src/app/quest-summary.component.ts" region="encapsulation.native" title="src/app/quest-summary.component.ts" linenums="false">
</code-example>
`Native` view encapsulation only works on browsers that have native support
for shadow DOM (see [Shadow DOM v0](http://caniuse.com/#feat=shadowdom) on the
for shadow DOM (see [Shadow DOM v0](http://caniuse.com/#feat=shadowdom) on the
[Can I use](http://caniuse.com) site). The support is still limited,
which is why `Emulated` view encapsulation is the default mode and recommended
in most cases.
@ -331,7 +331,7 @@ There are two kinds of generated attributes:
* An element that would be a shadow DOM host in native encapsulation has a
generated `_nghost` attribute. This is typically the case for component host elements.
* An element within a component's view has a `_ngcontent` attribute
* An element within a component's view has a `_ngcontent` attribute
that identifies to which host's emulated shadow DOM this element belongs.
The exact values of these attributes aren't important. They are automatically
@ -351,5 +351,5 @@ by the generated component styles, which are in the `<head>` section of the DOM:
</code-example>
These styles are post-processed so that each selector is augmented
with `_nghost` or `_ngcontent` attribute selectors.
with `_nghost` or `_ngcontent` attribute selectors.
These extra selectors enable the scoping rules described in this page.

View File

@ -165,7 +165,7 @@ Such [entry components](guide/ngmodule-faq#q-entry-component-defined) can never
While there's no harm in exporting them, there's also no benefit.
* Pure service modules that don't have public (exported) declarations.
For example, there's no point in re-exporting `HttpClientModule` because it doesn't export anything.
It's only purpose is to add http service providers to the application as a whole.
Its only purpose is to add http service providers to the application as a whole.
<hr/>
@ -190,7 +190,7 @@ An NgModule can export a combination of its own declarations, selected imported
Don't bother re-exporting pure service modules.
Pure service modules don't export [declarable](guide/bootstrapping#the-declarations-array) classes that another NgModule could use.
For example, there's no point in re-exporting `HttpClientModule` because it doesn't export anything.
It's only purpose is to add http service providers to the application as a whole.
Its only purpose is to add http service providers to the application as a whole.
<hr/>

View File

@ -297,7 +297,7 @@ These properties include `index` and `odd` and a special property named `$implic
Angular sets them to the current value of the context's `index` and `odd` properties.
* The context property for `let-hero` wasn't specified.
It's intended source is implicit.
Its intended source is implicit.
Angular sets `let-hero` to the value of the context's `$implicit` property
which `NgFor` has initialized with the hero for the current iteration.

View File

@ -588,7 +588,7 @@ and a controller:
You can *upgrade* this component to Angular using the `UpgradeComponent` class.
By creating a new Angular **directive** that extends `UpgradeComponent` and doing a `super` call
inside it's constructor, you have a fully upgraded AngularJS component to be used inside Angular.
inside its constructor, you have a fully upgraded AngularJS component to be used inside Angular.
All that is left is to add it to `AppModule`'s `declarations` array.
<code-example path="upgrade-module/src/app/upgrade-static/hero-detail.component.ts" region="hero-detail-upgrade" title="hero-detail.component.ts">
@ -602,7 +602,7 @@ All that is left is to add it to `AppModule`'s `declarations` array.
Upgraded components are Angular **directives**, instead of **components**, because Angular
is unaware that AngularJS will create elements under it. As far as Angular knows, the upgraded
component is just a directive - a tag - and Angular doesn't have to concern itself with
it's children.
its children.
</div>
@ -784,7 +784,7 @@ compilation can pick it up.
<code-example path="upgrade-module/src/app/ajs-to-a-providers/app.module.ts" region="register" title="app.module.ts">
</code-example>
You can then inject it in Angular using it's class as a type annotation:
You can then inject it in Angular using its class as a type annotation:
<code-example path="upgrade-module/src/app/ajs-to-a-providers/hero-detail.component.ts" title="hero-detail.component.ts">
@ -1260,7 +1260,7 @@ app. Switch to the [ngUpgrade bootstrap](#bootstrapping-hybrid-applications) met
instead.
First, remove the `ng-app` attribute from `index.html`.
Then import `UpgradeModule` in the `AppModule`, and override it's `ngDoBootstrap` method:
Then import `UpgradeModule` in the `AppModule`, and override its `ngDoBootstrap` method:
<code-example path="upgrade-phonecat-2-hybrid/app/app.module.ts" region="upgrademodule" title="app/app.module.ts">
</code-example>
@ -1619,7 +1619,7 @@ instead of the default "push state" strategy.
Now update the `AppModule` to import this `AppRoutingModule` and also the
declare the root `AppComponent` as the bootstrap component.
That tells Angular that it should bootstrap the app with the _root_ `AppComponent` and
insert it's view into the host web page.
insert its view into the host web page.
You must also remove the bootstrap of the AngularJS module from `ngDoBootstrap()` in `app.module.ts`
and the `UpgradeModule` import.
@ -1695,7 +1695,7 @@ module configuration files and not needed in Angular:
The external typings for AngularJS may be uninstalled as well. The only ones
you still need are for Jasmine and Angular polyfills.
The `@angular/upgrade` package and it's mapping in `systemjs.config.js` can also go.
The `@angular/upgrade` package and its mapping in `systemjs.config.js` can also go.
<code-example format="">
npm uninstall @angular/upgrade --save

View File

@ -44,7 +44,8 @@
"docs-lint": "eslint --ignore-path=\"tools/transforms/.eslintignore\" tools/transforms",
"docs-test": "node tools/transforms/test.js",
"tools-test": "./scripts/deploy-to-firebase.test.sh && yarn docs-test && yarn boilerplate:test && jasmine tools/ng-packages-installer/index.spec.js",
"serve-and-sync": "concurrently --kill-others \"yarn docs-watch\" \"yarn start\"",
"preserve-and-sync": "yarn docs",
"serve-and-sync": "concurrently --kill-others \"yarn docs-watch --watch-only\" \"yarn start\"",
"boilerplate:add": "node ./tools/examples/example-boilerplate add",
"boilerplate:remove": "node ./tools/examples/example-boilerplate remove",
"boilerplate:test": "node tools/examples/test.js",

View File

@ -153,122 +153,202 @@ describe('AppComponent', () => {
});
});
describe('SideNav when side-by-side (wide)', () => {
describe('SideNav', () => {
const navigateTo = (path: string) => {
locationService.go(path);
component.updateSideNav();
fixture.detectChanges();
};
beforeEach(() => {
component.onResize(sideBySideBreakPoint + 1); // side-by-side
});
it('should open when nav to a guide page (guide/pipes)', () => {
navigateTo('guide/pipes');
expect(sidenav.opened).toBe(true);
});
it('should open when nav to an api page', () => {
navigateTo('api/a/b/c/d');
expect(sidenav.opened).toBe(true);
});
it('should be closed when nav to a marketing page (features)', () => {
navigateTo('features');
expect(sidenav.opened).toBe(false);
});
describe('when manually closed', () => {
beforeEach(() => {
navigateTo('guide/pipes');
hamburger.click();
fixture.detectChanges();
});
it('should be closed', () => {
expect(sidenav.opened).toBe(false);
});
it('should stay closed when nav from one guide page to another', () => {
navigateTo('guide/bags');
expect(sidenav.opened).toBe(false);
});
it('should stay closed when nav from a guide page to api page', () => {
navigateTo('api');
expect(sidenav.opened).toBe(false);
});
it('should reopen when nav to market page and back to guide page', () => {
navigateTo('features');
navigateTo('guide/bags');
expect(sidenav.opened).toBe(true);
});
});
});
describe('SideNav when NOT side-by-side (narrow)', () => {
const navigateTo = (path: string) => {
locationService.go(path);
component.updateSideNav();
const resizeTo = (width: number) => {
component.onResize(width);
fixture.detectChanges();
};
const toggleSidenav = () => {
hamburger.click();
fixture.detectChanges();
};
beforeEach(() => {
component.onResize(sideBySideBreakPoint - 1); // NOT side-by-side
});
describe('when side-by-side (wide)', () => {
beforeEach(() => resizeTo(sideBySideBreakPoint + 1)); // side-by-side
it('should be closed when nav to a guide page (guide/pipes)', () => {
navigateTo('guide/pipes');
expect(sidenav.opened).toBe(false);
});
it('should be closed when nav to an api page', () => {
navigateTo('api/a/b/c/d');
expect(sidenav.opened).toBe(false);
});
it('should be closed when nav to a marketing page (features)', () => {
navigateTo('features');
expect(sidenav.opened).toBe(false);
});
describe('when manually opened', () => {
beforeEach(() => {
it('should open when navigating to a guide page (guide/pipes)', () => {
navigateTo('guide/pipes');
hamburger.click();
fixture.detectChanges();
});
it('should be open', () => {
expect(sidenav.opened).toBe(true);
});
it('should close when click in gray content area overlay', () => {
const sidenavBackdrop = fixture.debugElement.query(By.css('.mat-drawer-backdrop')).nativeElement;
sidenavBackdrop.click();
fixture.detectChanges();
expect(sidenav.opened).toBe(false);
it('should open when navigating to an api page', () => {
navigateTo('api/a/b/c/d');
expect(sidenav.opened).toBe(true);
});
it('should close when nav to another guide page', () => {
navigateTo('guide/bags');
expect(sidenav.opened).toBe(false);
});
it('should close when nav to api page', () => {
navigateTo('api');
expect(sidenav.opened).toBe(false);
});
it('should close again when nav to market page', () => {
it('should be closed when navigating to a marketing page (features)', () => {
navigateTo('features');
expect(sidenav.opened).toBe(false);
});
describe('when manually closed', () => {
beforeEach(() => {
navigateTo('guide/pipes');
toggleSidenav();
});
it('should be closed', () => {
expect(sidenav.opened).toBe(false);
});
it('should stay closed when navigating from one guide page to another', () => {
navigateTo('guide/bags');
expect(sidenav.opened).toBe(false);
});
it('should stay closed when navigating from a guide page to api page', () => {
navigateTo('api');
expect(sidenav.opened).toBe(false);
});
it('should reopen when navigating to market page and back to guide page', () => {
navigateTo('features');
navigateTo('guide/bags');
expect(sidenav.opened).toBe(true);
});
});
});
describe('when NOT side-by-side (narrow)', () => {
beforeEach(() => resizeTo(sideBySideBreakPoint - 1)); // NOT side-by-side
it('should be closed when navigating to a guide page (guide/pipes)', () => {
navigateTo('guide/pipes');
expect(sidenav.opened).toBe(false);
});
it('should be closed when navigating to an api page', () => {
navigateTo('api/a/b/c/d');
expect(sidenav.opened).toBe(false);
});
it('should be closed when navigating to a marketing page (features)', () => {
navigateTo('features');
expect(sidenav.opened).toBe(false);
});
describe('when manually opened', () => {
beforeEach(() => {
navigateTo('guide/pipes');
toggleSidenav();
});
it('should be open', () => {
expect(sidenav.opened).toBe(true);
});
it('should close when clicking in gray content area overlay', () => {
const sidenavBackdrop = fixture.debugElement.query(By.css('.mat-drawer-backdrop')).nativeElement;
sidenavBackdrop.click();
fixture.detectChanges();
expect(sidenav.opened).toBe(false);
});
it('should close when navigating to another guide page', () => {
navigateTo('guide/bags');
expect(sidenav.opened).toBe(false);
});
it('should close when navigating to api page', () => {
navigateTo('api');
expect(sidenav.opened).toBe(false);
});
it('should close again when navigating to market page', () => {
navigateTo('features');
expect(sidenav.opened).toBe(false);
});
});
});
describe('when changing side-by-side (narrow --> wide)', () => {
const sidenavDocs = ['api/a/b/c/d', 'guide/pipes'];
const nonSidenavDocs = ['features', 'about'];
sidenavDocs.forEach(doc => {
it(`should open when on a sidenav doc (${doc})`, () => {
resizeTo(sideBySideBreakPoint - 1);
navigateTo(doc);
expect(sidenav.opened).toBe(false);
resizeTo(sideBySideBreakPoint + 1);
expect(sidenav.opened).toBe(true);
});
});
nonSidenavDocs.forEach(doc => {
it(`should remain closed when on a non-sidenav doc (${doc})`, () => {
resizeTo(sideBySideBreakPoint - 1);
navigateTo(doc);
expect(sidenav.opened).toBe(false);
resizeTo(sideBySideBreakPoint + 1);
expect(sidenav.opened).toBe(false);
});
});
describe('when manually opened', () => {
sidenavDocs.forEach(doc => {
it(`should remain opened when on a sidenav doc (${doc})`, () => {
resizeTo(sideBySideBreakPoint - 1);
navigateTo(doc);
toggleSidenav();
expect(sidenav.opened).toBe(true);
resizeTo(sideBySideBreakPoint + 1);
expect(sidenav.opened).toBe(true);
});
});
nonSidenavDocs.forEach(doc => {
it(`should close when on a non-sidenav doc (${doc})`, () => {
resizeTo(sideBySideBreakPoint - 1);
navigateTo(doc);
toggleSidenav();
expect(sidenav.opened).toBe(true);
resizeTo(sideBySideBreakPoint + 1);
expect(sidenav.opened).toBe(false);
});
});
});
});
describe('when changing side-by-side (wide --> narrow)', () => {
const sidenavDocs = ['api/a/b/c/d', 'guide/pipes'];
const nonSidenavDocs = ['features', 'about'];
sidenavDocs.forEach(doc => {
it(`should close when on a sidenav doc (${doc})`, () => {
navigateTo(doc);
expect(sidenav.opened).toBe(true);
resizeTo(sideBySideBreakPoint - 1);
expect(sidenav.opened).toBe(false);
});
});
nonSidenavDocs.forEach(doc => {
it(`should remain closed when on a non-sidenav doc (${doc})`, () => {
navigateTo(doc);
expect(sidenav.opened).toBe(false);
resizeTo(sideBySideBreakPoint - 1);
expect(sidenav.opened).toBe(false);
});
});
});
});
@ -387,14 +467,14 @@ describe('AppComponent', () => {
expect(scrollSpy).toHaveBeenCalled();
});
it('should scroll again when nav to the same hash twice in succession', () => {
it('should scroll again when navigating to the same hash twice in succession', () => {
locationService.go('guide/pipes');
locationService.go('guide/pipes#somewhere');
locationService.go('guide/pipes#somewhere');
expect(scrollSpy.calls.count()).toBe(2);
});
it('should scroll when nav to the same path', () => {
it('should scroll when navigating to the same path', () => {
locationService.go('guide/pipes');
scrollSpy.calls.reset();

View File

@ -235,6 +235,14 @@ export class AppComponent implements OnInit {
onResize(width: number) {
this.isSideBySide = width > this.sideBySideWidth;
this.showFloatingToc.next(width > this.showFloatingTocWidth);
if (this.isSideBySide && !this.isSideNavDoc) {
// If this is a non-sidenav doc and the screen is wide enough so that we can display menu
// items in the top-bar, ensure the sidenav is closed.
// (This condition can only be met when the resize event changes the value of `isSideBySide`
// from `false` to `true` while on a non-sidenav doc.)
this.sideNavToggle(false);
}
}
@HostListener('click', ['$event.target', '$event.button', '$event.ctrlKey', '$event.metaKey', '$event.altKey'])

View File

@ -31,14 +31,6 @@
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="translucent">
<!--
Initially tell the Google crawler not to index this page.
If the page loads correctly will remove this tag (in the DocViewer).
Subsequent navigations will update the tag dynamically (i.e. soft 404).
Don't do the same for `robots` in general here, since they might not be able to handle the tag changing dynamically.
-->
<meta name="googlebot" content="noindex">
<!-- Google Analytics -->
<script>
// Note this is a customised version of the GA tracking snippet

View File

@ -35,7 +35,6 @@ mat-sidenav.mat-sidenav.sidenav {
min-width: 260px;
background-color: $offwhite;
box-shadow: 6px 0 6px rgba(0,0,0,0.10);
height: calc(100vh - 64px);
&.collapsed {
top: 56px;

View File

@ -43,7 +43,7 @@
"zone.js": "^0.8.4"
},
"devDependencies": {
"@angular/cli": "1.5.0",
"@angular/cli": "1.6.5",
"@types/angular": "^1.5.16",
"@types/angular-animate": "^1.5.5",
"@types/angular-cookies": "^1.4.2",
@ -66,7 +66,7 @@
"http-server": "^0.9.0",
"jasmine": "~2.8.0",
"jasmine-core": "~2.8.0",
"jasmine-marbles":"^0.2.0",
"jasmine-marbles": "^0.2.0",
"jasmine-spec-reporter": "^4.2.1",
"karma": "^1.3.0",
"karma-chrome-launcher": "^2.0.0",

File diff suppressed because it is too large Load Diff

View File

@ -58,7 +58,7 @@ new as of May 2017 and not very stable yet.
- Test all packages: `bazel test packages/...`
You can use [ibazel] to get a "watch mode" that continuously
keeps the outputs up-to-date as you save sources.
keeps the outputs up-to-date as you save sources.
### Debugging a Node Test
@ -68,6 +68,44 @@ keeps the outputs up-to-date as you save sources.
The process should automatically connect to the debugger.
### Debugging a Node Test in VSCode
First time setup:
- Go to Debug > Add configuration (in the menu bar) to open `launch.json`
- Add the following to the `configurations` array:
```
{
"name": "Attach (inspect)",
"type": "node",
"request": "attach",
"port": 9229,
"address": "localhost",
"restart": false,
"sourceMaps": true,
"localRoot": "${workspaceRoot}",
"remoteRoot": null
},
{
"name": "Attach (no-sm,inspect)",
"type": "node",
"request": "attach",
"port": 9229,
"address": "localhost",
"restart": false,
"sourceMaps": false,
"localRoot": "${workspaceRoot}",
"remoteRoot": null
},
```
The easiest way to debug a test for now is to add a `debugger` statement in the code
and launch the bazel corresponding test (`bazel test <target> --config=debug`).
Bazel will wait on a connection. Go to the debug view (by clicking on the sidebar or
Apple+Shift+D on Mac) and click on the green play icon next to the configuration name
(ie `Attach (inspect)`).
### Debugging a Karma Test
- Run test: `bazel run packages/core/test:test_web`

View File

@ -1,13 +1,9 @@
built/
dist/
vendor/
yarn.lock
.ng-cli/
cli-*/**
*/src/*.d.ts
*/src/*.js
**/*.ngfactory.ts
**/*.ngsummary.json
**/*.ngsummary.ts
*/yarn*
**/.yarn_local_cache*

View File

@ -1,11 +1,24 @@
# Integration tests for Angular
This directory contains end-to-end tests for Angular. Each directory is a self-contained
application that exactly mimics how a user might expect Angular to work, so they allow
high-fidelity reproductions of real-world issues.
This directory contains end-to-end tests for Angular. Each directory is a self-contained application that exactly mimics how a user might expect Angular
to work, so they allow high-fidelity reproductions of real-world issues.
For this to work, we first build the Angular distribution just like we would publish
it to npm, then install the distribution into each app.
For this to work, we first build the Angular distribution just like we would
publish it to npm, then install the distribution into each app.
To test Angular CLI applications, we generate integration tests such as `cli-hello-world`.
This was generated with a current version of the CLI, and the only modification was replacement of `@angular/*` packages with their counterparts coming from `file:../../dist/packages-dist/*`.
When a significant change is released in the CLI, the application should be re-generated from scratch:
```bash
$ cd integration
$ rm -rf cli-hello-world
$ ng new cli-hello-world
# Edit cli-hello-world/package.json to point the @angular packages to dist/packages-dist, and preserve local mods to
# ng build
# ng test
# typescript version
```
## Writing an integration test
@ -29,6 +42,8 @@ you can install the package directly from `file:../../node_modules`.
## Running integration tests
First you must run `build.sh` to create the current distribution.
You can iterate on the tests by keeping the dist folder up-to-date.
See the `package.json` of the test(s) you're debugging, to see which dist/ folders they install from.
Then run the right `tsc --watch` command to keep those dist folders up-to-date, for example:

View File

@ -18,14 +18,14 @@
"hello_world__render3__closure": {
"master": {
"uncompressed": {
"bundle": 7065
"bundle": 8153
}
}
},
"hello_world__render3__rollup": {
"master": {
"uncompressed": {
"bundle": 56550
"bundle": 34304
}
}
}

View File

@ -5,7 +5,7 @@ load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
git_repository(
name = "build_bazel_rules_nodejs",
remote = "https://github.com/bazelbuild/rules_nodejs.git",
tag = "0.3.1",
commit = "230d39a391226f51c03448f91eb61370e2e58c42",
)
load("@build_bazel_rules_nodejs//:defs.bzl", "node_repositories")
@ -14,7 +14,7 @@ node_repositories(package_json = ["//:package.json"])
git_repository(
name = "build_bazel_rules_typescript",
remote = "https://github.com/bazelbuild/rules_typescript.git",
commit = "c4ea003acd7d42269b81a2d25eb832972cd24912"
commit = "eb3244363e1cb265c84e723b347926f28c29aa35"
)
load("@build_bazel_rules_typescript//:defs.bzl", "ts_setup_workspace")

View File

@ -20,7 +20,6 @@
},
"scripts": {
"postinstall": "ngc -p angular.tsconfig.json",
"test": "WORKAROUND https://github.com/bazelbuild/bazel/issues/4242, can't build ...",
"test": "bazel build //src/... --noshow_progress"
"test": "bazel build //... --noshow_progress"
}
}

995
integration/bazel/yarn.lock Normal file
View File

@ -0,0 +1,995 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@angular/animations@file:../../dist/packages-dist/animations":
version "5.2.0-e94fb16a2"
dependencies:
tslib "^1.7.1"
"@angular/bazel@file:../../dist/packages-dist/bazel":
version "5.2.0-e94fb16a2"
dependencies:
"@types/node" "6.0.84"
"@angular/common@file:../../dist/packages-dist/common":
version "5.2.0-e94fb16a2"
dependencies:
tslib "^1.7.1"
"@angular/compiler-cli@file:../../dist/packages-dist/compiler-cli":
version "5.2.0-e94fb16a2"
dependencies:
chokidar "^1.4.2"
minimist "^1.2.0"
reflect-metadata "^0.1.2"
tsickle "^0.26.0"
"@angular/compiler@file:../../dist/packages-dist/compiler":
version "5.2.0-e94fb16a2"
dependencies:
tslib "^1.7.1"
"@angular/core@file:../../dist/packages-dist/core":
version "5.2.0-e94fb16a2"
dependencies:
tslib "^1.7.1"
"@angular/platform-browser@file:../../dist/packages-dist/platform-browser":
version "5.2.0-e94fb16a2"
dependencies:
tslib "^1.7.1"
"@types/node@6.0.84":
version "6.0.84"
resolved "https://registry.yarnpkg.com/@types/node/-/node-6.0.84.tgz#193ffe5a9f42864d425ffd9739d95b753c6a1eab"
"@types/source-map@0.5.1":
version "0.5.1"
resolved "https://registry.yarnpkg.com/@types/source-map/-/source-map-0.5.1.tgz#7e74db5d06ab373a712356eebfaea2fad0ea2367"
abbrev@1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
ajv@^4.9.1:
version "4.11.8"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536"
dependencies:
co "^4.6.0"
json-stable-stringify "^1.0.1"
ansi-regex@^2.0.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
anymatch@^1.3.0:
version "1.3.2"
resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a"
dependencies:
micromatch "^2.1.5"
normalize-path "^2.0.0"
aproba@^1.0.3:
version "1.2.0"
resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
are-we-there-yet@~1.1.2:
version "1.1.4"
resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d"
dependencies:
delegates "^1.0.0"
readable-stream "^2.0.6"
arr-diff@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf"
dependencies:
arr-flatten "^1.0.1"
arr-flatten@^1.0.1:
version "1.1.0"
resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1"
array-unique@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53"
asn1@~0.2.3:
version "0.2.3"
resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86"
assert-plus@1.0.0, assert-plus@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
assert-plus@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234"
async-each@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d"
asynckit@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
aws-sign2@~0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f"
aws4@^1.2.1:
version "1.6.0"
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e"
balanced-match@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
bcrypt-pbkdf@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d"
dependencies:
tweetnacl "^0.14.3"
binary-extensions@^1.0.0:
version "1.11.0"
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205"
block-stream@*:
version "0.0.9"
resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a"
dependencies:
inherits "~2.0.0"
boom@2.x.x:
version "2.10.1"
resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f"
dependencies:
hoek "2.x.x"
brace-expansion@^1.1.7:
version "1.1.8"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292"
dependencies:
balanced-match "^1.0.0"
concat-map "0.0.1"
braces@^1.8.2:
version "1.8.5"
resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7"
dependencies:
expand-range "^1.8.1"
preserve "^0.2.0"
repeat-element "^1.1.2"
caseless@~0.12.0:
version "0.12.0"
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
chokidar@^1.4.2:
version "1.7.0"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468"
dependencies:
anymatch "^1.3.0"
async-each "^1.0.0"
glob-parent "^2.0.0"
inherits "^2.0.1"
is-binary-path "^1.0.0"
is-glob "^2.0.0"
path-is-absolute "^1.0.0"
readdirp "^2.0.0"
optionalDependencies:
fsevents "^1.0.0"
co@^4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
code-point-at@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
combined-stream@^1.0.5, combined-stream@~1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009"
dependencies:
delayed-stream "~1.0.0"
concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
console-control-strings@^1.0.0, console-control-strings@~1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
core-util-is@1.0.2, core-util-is@~1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
cryptiles@2.x.x:
version "2.0.5"
resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8"
dependencies:
boom "2.x.x"
dashdash@^1.12.0:
version "1.14.1"
resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
dependencies:
assert-plus "^1.0.0"
debug@^2.2.0:
version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
dependencies:
ms "2.0.0"
deep-extend@~0.4.0:
version "0.4.2"
resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f"
delayed-stream@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
delegates@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
detect-libc@^1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
ecc-jsbn@~0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505"
dependencies:
jsbn "~0.1.0"
expand-brackets@^0.1.4:
version "0.1.5"
resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b"
dependencies:
is-posix-bracket "^0.1.0"
expand-range@^1.8.1:
version "1.8.2"
resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337"
dependencies:
fill-range "^2.1.0"
extend@~3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444"
extglob@^0.3.1:
version "0.3.2"
resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1"
dependencies:
is-extglob "^1.0.0"
extsprintf@1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
extsprintf@^1.2.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
filename-regex@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26"
fill-range@^2.1.0:
version "2.2.3"
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723"
dependencies:
is-number "^2.1.0"
isobject "^2.0.0"
randomatic "^1.1.3"
repeat-element "^1.1.2"
repeat-string "^1.5.2"
for-in@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
for-own@^0.1.4:
version "0.1.5"
resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce"
dependencies:
for-in "^1.0.1"
forever-agent@~0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
form-data@~2.1.1:
version "2.1.4"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1"
dependencies:
asynckit "^0.4.0"
combined-stream "^1.0.5"
mime-types "^2.1.12"
fs.realpath@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
fsevents@^1.0.0:
version "1.1.3"
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.3.tgz#11f82318f5fe7bb2cd22965a108e9306208216d8"
dependencies:
nan "^2.3.0"
node-pre-gyp "^0.6.39"
fstream-ignore@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105"
dependencies:
fstream "^1.0.0"
inherits "2"
minimatch "^3.0.0"
fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2:
version "1.0.11"
resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171"
dependencies:
graceful-fs "^4.1.2"
inherits "~2.0.0"
mkdirp ">=0.5 0"
rimraf "2"
gauge@~2.7.3:
version "2.7.4"
resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"
dependencies:
aproba "^1.0.3"
console-control-strings "^1.0.0"
has-unicode "^2.0.0"
object-assign "^4.1.0"
signal-exit "^3.0.0"
string-width "^1.0.1"
strip-ansi "^3.0.1"
wide-align "^1.1.0"
getpass@^0.1.1:
version "0.1.7"
resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa"
dependencies:
assert-plus "^1.0.0"
glob-base@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4"
dependencies:
glob-parent "^2.0.0"
is-glob "^2.0.0"
glob-parent@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28"
dependencies:
is-glob "^2.0.0"
glob@^7.0.5:
version "7.1.2"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15"
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
inherits "2"
minimatch "^3.0.4"
once "^1.3.0"
path-is-absolute "^1.0.0"
graceful-fs@^4.1.2:
version "4.1.11"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
har-schema@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e"
har-validator@~4.2.1:
version "4.2.1"
resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a"
dependencies:
ajv "^4.9.1"
har-schema "^1.0.5"
has-unicode@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
hawk@3.1.3, hawk@~3.1.3:
version "3.1.3"
resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4"
dependencies:
boom "2.x.x"
cryptiles "2.x.x"
hoek "2.x.x"
sntp "1.x.x"
hoek@2.x.x:
version "2.16.3"
resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed"
http-signature@~1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf"
dependencies:
assert-plus "^0.2.0"
jsprim "^1.2.2"
sshpk "^1.7.0"
inflight@^1.0.4:
version "1.0.6"
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
dependencies:
once "^1.3.0"
wrappy "1"
inherits@2, inherits@^2.0.1, inherits@~2.0.0, inherits@~2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
ini@~1.3.0:
version "1.3.5"
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
is-binary-path@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898"
dependencies:
binary-extensions "^1.0.0"
is-buffer@^1.1.5:
version "1.1.6"
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
is-dotfile@^1.0.0:
version "1.0.3"
resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1"
is-equal-shallow@^0.1.3:
version "0.1.3"
resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534"
dependencies:
is-primitive "^2.0.0"
is-extendable@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89"
is-extglob@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0"
is-fullwidth-code-point@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb"
dependencies:
number-is-nan "^1.0.0"
is-glob@^2.0.0, is-glob@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863"
dependencies:
is-extglob "^1.0.0"
is-number@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f"
dependencies:
kind-of "^3.0.2"
is-number@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195"
dependencies:
kind-of "^3.0.2"
is-posix-bracket@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4"
is-primitive@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575"
is-typedarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
isarray@1.0.0, isarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
isobject@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89"
dependencies:
isarray "1.0.0"
isstream@~0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
jsbn@~0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
json-schema@0.2.3:
version "0.2.3"
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
json-stable-stringify@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af"
dependencies:
jsonify "~0.0.0"
json-stringify-safe@~5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
jsonify@~0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73"
jsprim@^1.2.2:
version "1.4.1"
resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2"
dependencies:
assert-plus "1.0.0"
extsprintf "1.3.0"
json-schema "0.2.3"
verror "1.10.0"
kind-of@^3.0.2:
version "3.2.2"
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64"
dependencies:
is-buffer "^1.1.5"
kind-of@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57"
dependencies:
is-buffer "^1.1.5"
micromatch@^2.1.5:
version "2.3.11"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565"
dependencies:
arr-diff "^2.0.0"
array-unique "^0.2.1"
braces "^1.8.2"
expand-brackets "^0.1.4"
extglob "^0.3.1"
filename-regex "^2.0.0"
is-extglob "^1.0.0"
is-glob "^2.0.1"
kind-of "^3.0.2"
normalize-path "^2.0.1"
object.omit "^2.0.0"
parse-glob "^3.0.4"
regex-cache "^0.4.2"
mime-db@~1.30.0:
version "1.30.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.30.0.tgz#74c643da2dd9d6a45399963465b26d5ca7d71f01"
mime-types@^2.1.12, mime-types@~2.1.7:
version "2.1.17"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.17.tgz#09d7a393f03e995a79f8af857b70a9e0ab16557a"
dependencies:
mime-db "~1.30.0"
minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
dependencies:
brace-expansion "^1.1.7"
minimist@0.0.8:
version "0.0.8"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
minimist@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
"mkdirp@>=0.5 0", mkdirp@^0.5.1:
version "0.5.1"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
dependencies:
minimist "0.0.8"
ms@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
nan@^2.3.0:
version "2.8.0"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.8.0.tgz#ed715f3fe9de02b57a5e6252d90a96675e1f085a"
node-pre-gyp@^0.6.39:
version "0.6.39"
resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.39.tgz#c00e96860b23c0e1420ac7befc5044e1d78d8649"
dependencies:
detect-libc "^1.0.2"
hawk "3.1.3"
mkdirp "^0.5.1"
nopt "^4.0.1"
npmlog "^4.0.2"
rc "^1.1.7"
request "2.81.0"
rimraf "^2.6.1"
semver "^5.3.0"
tar "^2.2.1"
tar-pack "^3.4.0"
nopt@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d"
dependencies:
abbrev "1"
osenv "^0.1.4"
normalize-path@^2.0.0, normalize-path@^2.0.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9"
dependencies:
remove-trailing-separator "^1.0.1"
npmlog@^4.0.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b"
dependencies:
are-we-there-yet "~1.1.2"
console-control-strings "~1.1.0"
gauge "~2.7.3"
set-blocking "~2.0.0"
number-is-nan@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
oauth-sign@~0.8.1:
version "0.8.2"
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43"
object-assign@^4.1.0:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
object.omit@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa"
dependencies:
for-own "^0.1.4"
is-extendable "^0.1.1"
once@^1.3.0, once@^1.3.3:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
dependencies:
wrappy "1"
os-homedir@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
os-tmpdir@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
osenv@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644"
dependencies:
os-homedir "^1.0.0"
os-tmpdir "^1.0.0"
parse-glob@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c"
dependencies:
glob-base "^0.3.0"
is-dotfile "^1.0.0"
is-extglob "^1.0.0"
is-glob "^2.0.0"
path-is-absolute@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
performance-now@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5"
preserve@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
process-nextick-args@~1.0.6:
version "1.0.7"
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3"
punycode@^1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
qs@~6.4.0:
version "6.4.0"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233"
randomatic@^1.1.3:
version "1.1.7"
resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.7.tgz#c7abe9cc8b87c0baa876b19fde83fd464797e38c"
dependencies:
is-number "^3.0.0"
kind-of "^4.0.0"
rc@^1.1.7:
version "1.2.3"
resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.3.tgz#51575a900f8dd68381c710b4712c2154c3e2035b"
dependencies:
deep-extend "~0.4.0"
ini "~1.3.0"
minimist "^1.2.0"
strip-json-comments "~2.0.1"
readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.4:
version "2.3.3"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c"
dependencies:
core-util-is "~1.0.0"
inherits "~2.0.3"
isarray "~1.0.0"
process-nextick-args "~1.0.6"
safe-buffer "~5.1.1"
string_decoder "~1.0.3"
util-deprecate "~1.0.1"
readdirp@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78"
dependencies:
graceful-fs "^4.1.2"
minimatch "^3.0.2"
readable-stream "^2.0.2"
set-immediate-shim "^1.0.1"
reflect-metadata@^0.1.2:
version "0.1.10"
resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.10.tgz#b4f83704416acad89988c9b15635d47e03b9344a"
regex-cache@^0.4.2:
version "0.4.4"
resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd"
dependencies:
is-equal-shallow "^0.1.3"
remove-trailing-separator@^1.0.1:
version "1.1.0"
resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef"
repeat-element@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a"
repeat-string@^1.5.2:
version "1.6.1"
resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
request@2.81.0:
version "2.81.0"
resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0"
dependencies:
aws-sign2 "~0.6.0"
aws4 "^1.2.1"
caseless "~0.12.0"
combined-stream "~1.0.5"
extend "~3.0.0"
forever-agent "~0.6.1"
form-data "~2.1.1"
har-validator "~4.2.1"
hawk "~3.1.3"
http-signature "~1.1.0"
is-typedarray "~1.0.0"
isstream "~0.1.2"
json-stringify-safe "~5.0.1"
mime-types "~2.1.7"
oauth-sign "~0.8.1"
performance-now "^0.2.0"
qs "~6.4.0"
safe-buffer "^5.0.1"
stringstream "~0.0.4"
tough-cookie "~2.3.0"
tunnel-agent "^0.6.0"
uuid "^3.0.0"
rimraf@2, rimraf@^2.5.1, rimraf@^2.6.1:
version "2.6.2"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36"
dependencies:
glob "^7.0.5"
"rxjs@file:../../node_modules/rxjs":
version "5.5.5"
dependencies:
symbol-observable "1.0.1"
safe-buffer@^5.0.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853"
semver@^5.3.0:
version "5.4.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e"
set-blocking@~2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
set-immediate-shim@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61"
signal-exit@^3.0.0:
version "3.0.2"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
sntp@1.x.x:
version "1.0.9"
resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198"
dependencies:
hoek "2.x.x"
source-map-support@^0.4.2:
version "0.4.18"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f"
dependencies:
source-map "^0.5.6"
source-map@^0.5.6:
version "0.5.7"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
sshpk@^1.7.0:
version "1.13.1"
resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.13.1.tgz#512df6da6287144316dc4c18fe1cf1d940739be3"
dependencies:
asn1 "~0.2.3"
assert-plus "^1.0.0"
dashdash "^1.12.0"
getpass "^0.1.1"
optionalDependencies:
bcrypt-pbkdf "^1.0.0"
ecc-jsbn "~0.1.1"
jsbn "~0.1.0"
tweetnacl "~0.14.0"
string-width@^1.0.1, string-width@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
dependencies:
code-point-at "^1.0.0"
is-fullwidth-code-point "^1.0.0"
strip-ansi "^3.0.0"
string_decoder@~1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab"
dependencies:
safe-buffer "~5.1.0"
stringstream@~0.0.4:
version "0.0.5"
resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878"
strip-ansi@^3.0.0, strip-ansi@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
dependencies:
ansi-regex "^2.0.0"
strip-json-comments@~2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
symbol-observable@1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.1.tgz#8340fc4702c3122df5d22288f88283f513d3fdd4"
tar-pack@^3.4.0:
version "3.4.1"
resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.1.tgz#e1dbc03a9b9d3ba07e896ad027317eb679a10a1f"
dependencies:
debug "^2.2.0"
fstream "^1.0.10"
fstream-ignore "^1.0.5"
once "^1.3.3"
readable-stream "^2.1.4"
rimraf "^2.5.1"
tar "^2.2.1"
uid-number "^0.0.6"
tar@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1"
dependencies:
block-stream "*"
fstream "^1.0.2"
inherits "2"
tough-cookie@~2.3.0:
version "2.3.3"
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.3.tgz#0b618a5565b6dea90bf3425d04d55edc475a7561"
dependencies:
punycode "^1.4.1"
tsickle@^0.26.0:
version "0.26.0"
resolved "https://registry.yarnpkg.com/tsickle/-/tsickle-0.26.0.tgz#40b30a2dd6abcb33b182e37596674bd1cfe4039c"
dependencies:
minimist "^1.2.0"
mkdirp "^0.5.1"
source-map "^0.5.6"
source-map-support "^0.4.2"
tslib@^1.7.1:
version "1.8.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.8.1.tgz#6946af2d1d651a7b1863b531d6e5afa41aa44eac"
tunnel-agent@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
dependencies:
safe-buffer "^5.0.1"
tweetnacl@^0.14.3, tweetnacl@~0.14.0:
version "0.14.5"
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
"typescript@file:../../node_modules/typescript":
version "2.6.2"
uid-number@^0.0.6:
version "0.0.6"
resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81"
util-deprecate@~1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
uuid@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04"
verror@1.10.0:
version "1.10.0"
resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400"
dependencies:
assert-plus "^1.0.0"
core-util-is "1.0.2"
extsprintf "^1.2.0"
wide-align@^1.1.0:
version "1.1.2"
resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710"
dependencies:
string-width "^1.0.2"
wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
"zone.js@file:../../node_modules/zone.js":
version "0.8.17"

View File

@ -0,0 +1,60 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"project": {
"name": "cli-hello-world"
},
"apps": [
{
"root": "src",
"outDir": "dist",
"assets": [
"assets",
"favicon.ico"
],
"index": "index.html",
"main": "main.ts",
"polyfills": "polyfills.ts",
"test": "test.ts",
"tsconfig": "tsconfig.app.json",
"testTsconfig": "tsconfig.spec.json",
"prefix": "app",
"styles": [
"styles.css"
],
"scripts": [],
"environmentSource": "environments/environment.ts",
"environments": {
"dev": "environments/environment.ts",
"prod": "environments/environment.prod.ts"
}
}
],
"e2e": {
"protractor": {
"config": "./protractor.conf.js"
}
},
"lint": [
{
"project": "src/tsconfig.app.json",
"exclude": "**/node_modules/**"
},
{
"project": "src/tsconfig.spec.json",
"exclude": "**/node_modules/**"
},
{
"project": "e2e/tsconfig.e2e.json",
"exclude": "**/node_modules/**"
}
],
"test": {
"karma": {
"config": "./karma.conf.js"
}
},
"defaults": {
"styleExt": "css",
"component": {}
}
}

View File

@ -0,0 +1,13 @@
# Editor configuration, see http://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
max_line_length = off
trim_trailing_whitespace = false

View File

@ -0,0 +1,27 @@
# CliHelloWorld
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 1.6.6.
## Development server
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
## Code scaffolding
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
## Build
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `-prod` flag for a production build.
## Running unit tests
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
## Running end-to-end tests
Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
## Further help
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).

View File

@ -0,0 +1,14 @@
import { AppPage } from './app.po';
describe('cli-hello-world App', () => {
let page: AppPage;
beforeEach(() => {
page = new AppPage();
});
it('should display welcome message', () => {
page.navigateTo();
expect(page.getParagraphText()).toEqual('Welcome to app!');
});
});

View File

@ -0,0 +1,11 @@
import { browser, by, element } from 'protractor';
export class AppPage {
navigateTo() {
return browser.get('/');
}
getParagraphText() {
return element(by.css('app-root h1')).getText();
}
}

View File

@ -0,0 +1,14 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/e2e",
"baseUrl": "./",
"module": "commonjs",
"target": "es5",
"types": [
"jasmine",
"jasminewd2",
"node"
]
}
}

View File

@ -0,0 +1,39 @@
// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html
module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine', '@angular/cli'],
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage-istanbul-reporter'),
require('@angular/cli/plugins/karma')
],
client:{
clearContext: false // leave Jasmine Spec Runner output visible in browser
},
coverageIstanbulReporter: {
reports: [ 'html', 'lcovonly' ],
fixWebpackSourcePaths: true
},
angularCli: {
environment: 'dev'
},
reporters: ['progress', 'kjhtml'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['CustomChrome'],
singleRun: false,
customLaunchers: {
CustomChrome: {
base: 'Chrome',
flags: ['--no-sandbox']
}
}
});
};

View File

@ -0,0 +1,48 @@
{
"name": "cli-hello-world",
"version": "0.0.0",
"license": "MIT",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build --prod --build-optimizer",
"test": "ng test --single-run",
"lint": "ng lint",
"e2e": "ng e2e"
},
"private": true,
"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/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/router": "file:../../dist/packages-dist/router",
"core-js": "^2.4.1",
"rxjs": "^5.5.6",
"zone.js": "^0.8.19"
},
"devDependencies": {
"@angular/cli": "1.6.6",
"@angular/compiler-cli": "file:../../dist/packages-dist/compiler-cli",
"@angular/language-service": "file:../../dist/packages-dist/language-service",
"@types/jasmine": "~2.8.3",
"@types/jasminewd2": "~2.0.2",
"@types/node": "~6.0.60",
"codelyzer": "^4.0.1",
"jasmine-core": "~2.8.0",
"jasmine-spec-reporter": "~4.2.1",
"karma": "~2.0.0",
"karma-chrome-launcher": "~2.2.0",
"karma-coverage-istanbul-reporter": "^1.2.1",
"karma-jasmine": "~1.1.0",
"karma-jasmine-html-reporter": "^0.2.2",
"protractor": "~5.1.2",
"ts-node": "~4.1.0",
"tslint": "~5.9.1",
"typescript": "2.4.2"
}
}

View File

@ -0,0 +1,31 @@
// Protractor configuration file, see link for more information
// https://github.com/angular/protractor/blob/master/lib/config.ts
const { SpecReporter } = require('jasmine-spec-reporter');
exports.config = {
allScriptsTimeout: 11000,
specs: [
'./e2e/**/*.e2e-spec.ts'
],
capabilities: {
'browserName': 'chrome',
chromeOptions: {
args: ['--no-sandbox']
}
},
directConnect: true,
baseUrl: 'http://localhost:4200/',
framework: 'jasmine',
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000,
print: function() {}
},
onPrepare() {
require('ts-node').register({
project: 'e2e/tsconfig.e2e.json'
});
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
}
};

View File

@ -0,0 +1,20 @@
<!--The content below is only a placeholder and can be replaced.-->
<div style="text-align:center">
<h1>
Welcome to {{ title }}!
</h1>
<img width="300" alt="Angular Logo" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNTAgMjUwIj4KICAgIDxwYXRoIGZpbGw9IiNERDAwMzEiIGQ9Ik0xMjUgMzBMMzEuOSA2My4ybDE0LjIgMTIzLjFMMTI1IDIzMGw3OC45LTQzLjcgMTQuMi0xMjMuMXoiIC8+CiAgICA8cGF0aCBmaWxsPSIjQzMwMDJGIiBkPSJNMTI1IDMwdjIyLjItLjFWMjMwbDc4LjktNDMuNyAxNC4yLTEyMy4xTDEyNSAzMHoiIC8+CiAgICA8cGF0aCAgZmlsbD0iI0ZGRkZGRiIgZD0iTTEyNSA1Mi4xTDY2LjggMTgyLjZoMjEuN2wxMS43LTI5LjJoNDkuNGwxMS43IDI5LjJIMTgzTDEyNSA1Mi4xem0xNyA4My4zaC0zNGwxNy00MC45IDE3IDQwLjl6IiAvPgogIDwvc3ZnPg==">
</div>
<h2>Here are some links to help you start: </h2>
<ul>
<li>
<h2><a target="_blank" rel="noopener" href="https://angular.io/tutorial">Tour of Heroes</a></h2>
</li>
<li>
<h2><a target="_blank" rel="noopener" href="https://github.com/angular/angular-cli/wiki">CLI Documentation</a></h2>
</li>
<li>
<h2><a target="_blank" rel="noopener" href="https://blog.angular.io/">Angular blog</a></h2>
</li>
</ul>

View File

@ -0,0 +1,27 @@
import { TestBed, async } from '@angular/core/testing';
import { AppComponent } from './app.component';
describe('AppComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
AppComponent
],
}).compileComponents();
}));
it('should create the app', async(() => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
expect(app).toBeTruthy();
}));
it(`should have as title 'app'`, async(() => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
expect(app.title).toEqual('app');
}));
it('should render title in a h1 tag', async(() => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled = fixture.debugElement.nativeElement;
expect(compiled.querySelector('h1').textContent).toContain('Welcome to app!');
}));
});

View File

@ -0,0 +1,10 @@
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'app';
}

View File

@ -0,0 +1,18 @@
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }

View File

@ -0,0 +1,3 @@
export const environment = {
production: true
};

View File

@ -0,0 +1,8 @@
// The file contents for the current environment will overwrite these during build.
// The build system defaults to the dev environment which uses `environment.ts`, but if you do
// `ng build --env=prod` then `environment.prod.ts` will be used instead.
// The list of which env maps to which file can be found in `.angular-cli.json`.
export const environment = {
production: false
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@ -0,0 +1,14 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>CliHelloWorld</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
<app-root></app-root>
</body>
</html>

View File

@ -0,0 +1,12 @@
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.log(err));

View File

@ -0,0 +1,66 @@
/**
* This file includes polyfills needed by Angular and is loaded before the app.
* You can add your own extra polyfills to this file.
*
* This file is divided into 2 sections:
* 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
* 2. Application imports. Files imported after ZoneJS that should be loaded before your main
* file.
*
* The current setup is for so-called "evergreen" browsers; the last versions of browsers that
* automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
* Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
*
* Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html
*/
/***************************************************************************************************
* BROWSER POLYFILLS
*/
/** IE9, IE10 and IE11 requires all of the following polyfills. **/
// import 'core-js/es6/symbol';
// import 'core-js/es6/object';
// import 'core-js/es6/function';
// import 'core-js/es6/parse-int';
// import 'core-js/es6/parse-float';
// import 'core-js/es6/number';
// import 'core-js/es6/math';
// import 'core-js/es6/string';
// import 'core-js/es6/date';
// import 'core-js/es6/array';
// import 'core-js/es6/regexp';
// import 'core-js/es6/map';
// import 'core-js/es6/weak-map';
// import 'core-js/es6/set';
/** IE10 and IE11 requires the following for NgClass support on SVG elements */
// import 'classlist.js'; // Run `npm install --save classlist.js`.
/** IE10 and IE11 requires the following for the Reflect API. */
// import 'core-js/es6/reflect';
/** Evergreen browsers require these. **/
// Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove.
import 'core-js/es7/reflect';
/**
* Required to support Web Animations `@angular/platform-browser/animations`.
* Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation
**/
// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
/***************************************************************************************************
* Zone JS is required by default for Angular itself.
*/
import 'zone.js/dist/zone'; // Included with Angular CLI.
/***************************************************************************************************
* APPLICATION IMPORTS
*/

View File

@ -0,0 +1 @@
/* You can add global styles to this file, and also import other style files */

View File

@ -0,0 +1,20 @@
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
import 'zone.js/dist/zone-testing';
import { getTestBed } from '@angular/core/testing';
import {
BrowserDynamicTestingModule,
platformBrowserDynamicTesting
} from '@angular/platform-browser-dynamic/testing';
declare const require: any;
// First, initialize the Angular testing environment.
getTestBed().initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting()
);
// Then we find all the tests.
const context = require.context('./', true, /\.spec\.ts$/);
// And load the modules.
context.keys().map(context);

View File

@ -0,0 +1,13 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/app",
"baseUrl": "./",
"module": "es2015",
"types": []
},
"exclude": [
"test.ts",
"**/*.spec.ts"
]
}

View File

@ -0,0 +1,19 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/spec",
"baseUrl": "./",
"module": "commonjs",
"types": [
"jasmine",
"node"
]
},
"files": [
"test.ts"
],
"include": [
"**/*.spec.ts",
"**/*.d.ts"
]
}

View File

@ -0,0 +1,19 @@
{
"compileOnSave": false,
"compilerOptions": {
"outDir": "./dist/out-tsc",
"sourceMap": true,
"declaration": false,
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"target": "es5",
"typeRoots": [
"node_modules/@types"
],
"lib": [
"es2017",
"dom"
]
}
}

View File

@ -0,0 +1,143 @@
{
"rulesDirectory": [
"node_modules/codelyzer"
],
"rules": {
"arrow-return-shorthand": true,
"callable-types": true,
"class-name": true,
"comment-format": [
true,
"check-space"
],
"curly": true,
"deprecation": {
"severity": "warn"
},
"eofline": true,
"forin": true,
"import-blacklist": [
true,
"rxjs",
"rxjs/Rx"
],
"import-spacing": true,
"indent": [
true,
"spaces"
],
"interface-over-type-literal": true,
"label-position": true,
"max-line-length": [
true,
140
],
"member-access": false,
"member-ordering": [
true,
{
"order": [
"static-field",
"instance-field",
"static-method",
"instance-method"
]
}
],
"no-arg": true,
"no-bitwise": true,
"no-console": [
true,
"debug",
"info",
"time",
"timeEnd",
"trace"
],
"no-construct": true,
"no-debugger": true,
"no-duplicate-super": true,
"no-empty": false,
"no-empty-interface": true,
"no-eval": true,
"no-inferrable-types": [
true,
"ignore-params"
],
"no-misused-new": true,
"no-non-null-assertion": true,
"no-shadowed-variable": true,
"no-string-literal": false,
"no-string-throw": true,
"no-switch-case-fall-through": true,
"no-trailing-whitespace": true,
"no-unnecessary-initializer": true,
"no-unused-expression": true,
"no-use-before-declare": true,
"no-var-keyword": true,
"object-literal-sort-keys": false,
"one-line": [
true,
"check-open-brace",
"check-catch",
"check-else",
"check-whitespace"
],
"prefer-const": true,
"quotemark": [
true,
"single"
],
"radix": true,
"semicolon": [
true,
"always"
],
"triple-equals": [
true,
"allow-null-check"
],
"typedef-whitespace": [
true,
{
"call-signature": "nospace",
"index-signature": "nospace",
"parameter": "nospace",
"property-declaration": "nospace",
"variable-declaration": "nospace"
}
],
"unified-signatures": true,
"variable-name": false,
"whitespace": [
true,
"check-branch",
"check-decl",
"check-operator",
"check-separator",
"check-type"
],
"directive-selector": [
true,
"attribute",
"app",
"camelCase"
],
"component-selector": [
true,
"element",
"app",
"kebab-case"
],
"no-output-on-prefix": true,
"use-input-property-decorator": true,
"use-output-property-decorator": true,
"use-host-property-decorator": true,
"no-input-rename": true,
"no-output-rename": true,
"use-life-cycle-interface": true,
"use-pipe-transform-interface": true,
"component-class-suffix": true,
"directive-class-suffix": true
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -14,6 +14,7 @@ export class HelloWorld {
/** @nocollapse */
static ngComponentDef: ComponentDef<HelloWorld> = defineComponent({
type: HelloWorld,
tag: 'hello-world',
template: function (ctx: HelloWorld, cm: boolean) {
if (cm) {

File diff suppressed because it is too large Load Diff

View File

@ -20,15 +20,14 @@
"lite-server": "2.2.2",
"protractor": "file:../../node_modules/protractor",
"rollup": "0.54.0",
"rollup-plugin-angular-optimizer": "0.2.0",
"rollup-plugin-commonjs": "8.2.6",
"rollup-plugin-node-resolve": "3.0.2",
"rollup-plugin-replace": "2.0.0",
"rollup-plugin-typescript2": "0.10.0",
"rollup-plugin-uglify": "2.0.1"
},
"scripts": {
"postinstall": "webdriver-manager update --gecko false --standalone false $CHROMEDRIVER_VERSION_ARG",
"rollup": "rollup -c rollup.config.js",
"rollup": "tsc && rollup -c rollup.config.js",
"test": "yarn run rollup && concurrently \"yarn run serve\" \"yarn run protractor\" --kill-others --success first",
"serve": "lite-server -c e2e/browser.config.json",
"preprotractor": "tsc -p e2e",

View File

@ -1,32 +1,21 @@
import buildOptimizer from 'rollup-plugin-angular-optimizer'
import commonjs from 'rollup-plugin-commonjs';
import nodeResolve from 'rollup-plugin-node-resolve';
import replace from 'rollup-plugin-replace';
import typescript2 from 'rollup-plugin-typescript2';
import uglify from 'rollup-plugin-uglify';
export default {
input: `src/index.ts`,
input: `built/index.js`,
output: {
name: 'hw',
file: `dist/bundle.js`,
format: 'iife',
sourcemap: false
sourcemap: true
},
plugins: [
typescript2({
typescript: require('typescript'),
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}),
replace({
delimiters: ['', ''],
values: {
'/** @class */': '/** @__PURE__ */'
}
}),
buildOptimizer(),
nodeResolve({jsnext: true, module: true}),
commonjs({
include: 'node_modules/rxjs/**',
include: 'node_modules/rxjs/**'
}),
uglify({
mangle: true,

View File

@ -14,6 +14,7 @@ export class HelloWorld {
/** @nocollapse */
static ngComponentDef: ComponentDef<HelloWorld> = defineComponent({
type: HelloWorld,
tag: 'hello-world',
template: function (ctx: HelloWorld, cm: boolean) {
if (cm) {

View File

@ -11,19 +11,15 @@
"strict": true,
"target": "es5",
"noImplicitAny": false,
"sourceMap": false,
"sourceMap": true,
"experimentalDecorators": true,
"outDir": "built",
"rootDir": ".",
"rootDir": "./src",
"declaration": true,
"types": []
"types": [],
"lib": ["es2015", "dom"]
},
"exclude": [
"vendor",
"node_modules",
"built",
"dist",
"e2e"
"files": [
"src/index.ts"
]
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -24,7 +24,8 @@
"scripts": {
"postinstall": "webdriver-manager update --gecko false --standalone false $CHROMEDRIVER_VERSION_ARG",
"closure": "java -jar node_modules/google-closure-compiler/compiler.jar --flagfile closure.conf",
"test": "ngc && yarn run closure && concurrently \"yarn run serve\" \"yarn run protractor\" --kill-others --success first",
"test": "ngc && yarn run closure && concurrently \"yarn run serve\" \"yarn run protractor\" --kill-others --success first && npm run test-locale-folder",
"test-locale-folder": "node test-locale-folder.js",
"serve": "lite-server -c e2e/browser.config.json",
"preprotractor": "tsc -p e2e",
"protractor": "protractor e2e/protractor.config.js"

View File

@ -0,0 +1,14 @@
const fs = require('fs');
const path = require('path');
const packageJson = require('@angular/common/package.json');
const localesFolder = packageJson['locales'];
if (!localesFolder) {
throw new Error(`@angular/common/package.json does not contain 'locales' entry.`)
}
const enLocalePath = `@angular/common/${localesFolder}/en`;
try {
require.resolve(enLocalePath);
} catch (err) {
throw new Error(`@angular/common does not contain 'en' locale in ${enLocalePath}.`)
}

2421
integration/i18n/yarn.lock Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,69 +0,0 @@
#!/usr/bin/env bash
set -e -o pipefail
if [ $# -eq 0 ]
then
echo "Angular cli integration create project"
echo
echo "./ng-cli-create.sh [project-name]"
echo
else
TEMP=`dirname $0`
INTEGRATION_DIR=`(cd $TEMP; pwd)`
PROJECT=$1
PROJECT_DIR=$INTEGRATION_DIR/$PROJECT
NG=$INTEGRATION_DIR/.ng-cli/node_modules/.bin/ng
(
echo "==================="
echo Creating $PROJECT...
echo "==================="
cd $INTEGRATION_DIR
rm -rf $PROJECT
$NG set --global packageManager=yarn
$NG new $PROJECT --skip-install --skip-git
echo "==================="
echo $PROJECT created
echo "==================="
)
# By default `ng new` creates a package.json which uses @angular/* from NPM.
# Instead we want to use them from the current build so we overwrite theme here.
(
echo "==================="
echo Updating $PROJECT bundles
echo "==================="
cd $PROJECT_DIR
sed -i -E 's/ng build/ng build --prod --build-optimizer/g' package.json
sed -i -E 's/ng test/ng test --single-run/g' package.json
sed -i -E 's/"typescript\"\: \".*\"/"typescript": "2.4.2"/g' package.json
yarn add \
file:../../dist/packages-dist/compiler-cli \
file:../../dist/packages-dist/language-service \
--save-dev --skip-integrity-check --emoji
yarn add \
file:../../dist/packages-dist/core \
file:../../dist/packages-dist/common \
file:../../dist/packages-dist/forms \
file:../../dist/packages-dist/http \
--save --skip-integrity-check --emoji
# yarn bug: can not install all of them in a single command and it has to be broken into separate invocations.
yarn add \
file:../../dist/packages-dist/animations \
file:../../dist/packages-dist/compiler \
file:../../dist/packages-dist/platform-browser \
file:../../dist/packages-dist/platform-browser-dynamic \
--save --skip-integrity-check --emoji
yarn install --emoji
echo "==================="
echo $PROJECT created succesfully
echo "==================="
)
fi

View File

@ -19,22 +19,6 @@ rm_cache
mkdir $cache
trap rm_cache EXIT
# cli-hello-world test is disabled because it uses un-pinned dependencies
# TODO(alexeagle): re-enable when it's pinned
# # We need to install `ng` but don't want to do it globally so we place it into `.ng-cli` folder.
# (
# mkdir -p .ng-cli
# cd .ng-cli
# # workaround for https://github.com/yarnpkg/yarn/pull/4464 which causes cli to be installed into the root node_modules
# echo '{"name": "ng-cli"}' > package.json
# yarn init -y
# yarn add @angular/cli@$ANGULAR_CLI_VERSION --cache-folder ../$cache
# )
# ./ng-cli-create.sh cli-hello-world
for testDir in $(ls | grep -v node_modules) ; do
[[ -d "$testDir" ]] || continue
echo "#################################"
@ -42,8 +26,6 @@ for testDir in $(ls | grep -v node_modules) ; do
echo "#################################"
(
cd $testDir
# Workaround for https://github.com/yarnpkg/yarn/issues/2256
rm -f yarn.lock
rm -rf dist
yarn install --cache-folder ../$cache
yarn test || exit 1
@ -52,9 +34,13 @@ for testDir in $(ls | grep -v node_modules) ; do
if [[ $testDir == cli-hello-world ]]; then
yarn build
fi
trackPayloadSize "$testDir" "dist/*.js" true false "${thisDir}/_payload-limits.json"
if [[ -v TRAVIS ]]; then
trackPayloadSize "$testDir" "dist/*.js" true false "${thisDir}/_payload-limits.json"
fi
fi
)
done
trackPayloadSize "umd" "../dist/packages-dist/*/bundles/*.umd.min.js" false false
if [[ -v TRAVIS ]]; then
trackPayloadSize "umd" "../dist/packages-dist/*/bundles/*.umd.min.js" false false
fi

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -16,6 +16,7 @@ export class LargeTableComponent {
/** @nocollapse */
static ngComponentDef: ComponentDef<LargeTableComponent> = defineComponent({
type: LargeTableComponent,
tag: 'largetable',
template: function(ctx: LargeTableComponent, cm: boolean) {
if (cm) {

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {ɵC as C, ɵE as E, ɵT as T, ɵV as V, ɵb as b, ɵb1 as b1, ɵcR as cR, ɵcr as cr, ɵdefineComponent as defineComponent, ɵdetectChanges as _detectChanges, ɵe as e, ɵp as p, ɵs as s, ɵt as t, ɵv as v} from '@angular/core';
import {ɵC as C, ɵE as E, ɵT as T, ɵV as V, ɵb as b, ɵb1 as b1, ɵcR as cR, ɵcr as cr, ɵdefineComponent as defineComponent, ɵdetectChanges as _detectChanges, ɵe as e, ɵp as p, ɵr as r, ɵs as s, ɵt as t, ɵv as v} from '@angular/core';
import {ComponentDef} from '@angular/core/src/render3/interfaces/definition';
import {TreeNode, buildTree, emptyTree} from '../util';
@ -36,6 +36,7 @@ export class TreeComponent {
/** @nocollapse */
static ngComponentDef: ComponentDef<TreeComponent> = defineComponent({
type: TreeComponent,
tag: 'tree',
template: function(ctx: TreeComponent, cm: boolean) {
if (cm) {
@ -58,7 +59,7 @@ export class TreeComponent {
}
p(0, 'data', b(ctx.data.left));
TreeComponent.ngComponentDef.h(1, 0);
TreeComponent.ngComponentDef.r(1, 0);
r(1, 0);
}
v();
}
@ -75,7 +76,7 @@ export class TreeComponent {
}
p(0, 'data', b(ctx.data.right));
TreeComponent.ngComponentDef.h(1, 0);
TreeComponent.ngComponentDef.r(1, 0);
r(1, 0);
}
v();
}
@ -92,6 +93,7 @@ export class TreeFunction {
/** @nocollapse */
static ngComponentDef: ComponentDef<TreeFunction> = defineComponent({
type: TreeFunction,
tag: 'tree',
template: function(ctx: TreeFunction, cm: boolean) {
// bit of a hack

View File

@ -27,7 +27,7 @@ nodejs_binary(
"@build_bazel_rules_typescript//internal:worker_protocol.proto",
],
entry_point = "angular/packages/bazel/src/ngc-wrapped/index.js",
node_modules = "@build_bazel_rules_typescript_deps//:node_modules",
node_modules = "@build_bazel_rules_typescript_tsc_wrapped_deps//:node_modules",
visibility = ["//visibility:public"],
)

View File

@ -6,16 +6,41 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Inject, ModuleWithProviders, NgModule, Optional} from '@angular/core';
import {Injectable, Injector, ModuleWithProviders, NgModule, Optional} from '@angular/core';
import {Observable} from 'rxjs/Observable';
import {HttpBackend, HttpHandler} from './backend';
import {HttpClient} from './client';
import {HTTP_INTERCEPTORS, HttpInterceptor, HttpInterceptorHandler, NoopInterceptor} from './interceptor';
import {JsonpCallbackContext, JsonpClientBackend, JsonpInterceptor} from './jsonp';
import {HttpRequest} from './request';
import {HttpEvent} from './response';
import {BrowserXhr, HttpXhrBackend, XhrFactory} from './xhr';
import {HttpXsrfCookieExtractor, HttpXsrfInterceptor, HttpXsrfTokenExtractor, XSRF_COOKIE_NAME, XSRF_HEADER_NAME} from './xsrf';
/**
* An `HttpHandler` that applies a bunch of `HttpInterceptor`s
* to a request before passing it to the given `HttpBackend`.
*
* The interceptors are loaded lazily from the injector, to allow
* interceptors to themselves inject classes depending indirectly
* on `HttpInterceptingHandler` itself.
*/
@Injectable()
export class HttpInterceptingHandler implements HttpHandler {
private chain: HttpHandler|null = null;
constructor(private backend: HttpBackend, private injector: Injector) {}
handle(req: HttpRequest<any>): Observable<HttpEvent<any>> {
if (this.chain === null) {
const interceptors = this.injector.get(HTTP_INTERCEPTORS, []);
this.chain = interceptors.reduceRight(
(next, interceptor) => new HttpInterceptorHandler(next, interceptor), this.backend);
}
return this.chain.handle(req);
}
}
/**
* Constructs an `HttpHandler` that applies a bunch of `HttpInterceptor`s
@ -118,13 +143,7 @@ export class HttpClientXsrfModule {
],
providers: [
HttpClient,
// HttpHandler is the backend + interceptors and is constructed
// using the interceptingHandler factory function.
{
provide: HttpHandler,
useFactory: interceptingHandler,
deps: [HttpBackend, [new Optional(), new Inject(HTTP_INTERCEPTORS)]],
},
{provide: HttpHandler, useClass: HttpInterceptingHandler},
HttpXhrBackend,
{provide: HttpBackend, useExisting: HttpXhrBackend},
BrowserXhr,

View File

@ -8,7 +8,7 @@
import 'rxjs/add/operator/map';
import {Injector} from '@angular/core';
import {Injectable, Injector} from '@angular/core';
import {TestBed} from '@angular/core/testing';
import {Observable} from 'rxjs/Observable';
@ -47,6 +47,15 @@ class InterceptorB extends TestInterceptor {
constructor() { super('B'); }
}
@Injectable()
class ReentrantInterceptor implements HttpInterceptor {
constructor(private client: HttpClient) {}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(req);
}
}
{
describe('HttpClientModule', () => {
let injector: Injector;
@ -84,5 +93,16 @@ class InterceptorB extends TestInterceptor {
});
injector.get(HttpTestingController).expectOne('/test').flush('ok!');
});
it('allows interceptors to inject HttpClient', (done: DoneFn) => {
TestBed.resetTestingModule();
injector = TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [
{provide: HTTP_INTERCEPTORS, useClass: ReentrantInterceptor, multi: true},
],
});
injector.get(HttpClient).get('/test').subscribe(() => { done(); });
injector.get(HttpTestingController).expectOne('/test').flush('ok!');
});
});
}

File diff suppressed because it is too large Load Diff

View File

@ -11,6 +11,7 @@
"dependencies": {
"tslib": "^1.7.1"
},
"locales": "locales",
"peerDependencies": {
"rxjs": "^5.5.0",
"@angular/core": "0.0.0-PLACEHOLDER"

View File

@ -24,7 +24,7 @@ import {Directive, EmbeddedViewRef, Input, OnChanges, SimpleChange, SimpleChange
* `[ngTemplateOutletContext]` should be an object, the object's keys will be available for binding
* by the local template `let` declarations.
*
* Note: using the key `$implicit` in the context object will set it's value as default.
* Note: using the key `$implicit` in the context object will set its value as default.
*
* ## Example
*

View File

@ -14,6 +14,7 @@ import {LocationStrategy} from './location_strategy';
/** @experimental */
export interface PopStateEvent {
pop?: boolean;
state?: any;
type?: string;
url?: string;
}
@ -56,6 +57,7 @@ export class Location {
this._subject.emit({
'url': this.path(true),
'pop': true,
'state': ev.state,
'type': ev.type,
});
});
@ -103,16 +105,16 @@ export class Location {
* Changes the browsers URL to the normalized version of the given URL, and pushes a
* new item onto the platform's history.
*/
go(path: string, query: string = ''): void {
this._platformStrategy.pushState(null, '', path, query);
go(path: string, query: string = '', state: any = null): void {
this._platformStrategy.pushState(state, '', path, query);
}
/**
* Changes the browsers URL to the normalized version of the given URL, and replaces
* the top item on the platform's history stack.
*/
replaceState(path: string, query: string = ''): void {
this._platformStrategy.replaceState(null, '', path, query);
replaceState(path: string, query: string = '', state: any = null): void {
this._platformStrategy.replaceState(state, '', path, query);
}
/**

View File

@ -58,7 +58,10 @@ export const LOCATION_INITIALIZED = new InjectionToken<Promise<any>>('Location I
*
* @experimental
*/
export interface LocationChangeEvent { type: string; }
export interface LocationChangeEvent {
type: string;
state: any;
}
/**
* @experimental

View File

@ -18,8 +18,8 @@ import localeTh from '@angular/common/locales/th';
import localeAr from '@angular/common/locales/ar';
{
describe('DatePipe', () => {
let date: Date;
let date: Date;
xdescribe('DatePipe', () => {
const isoStringWithoutTime = '2015-01-01';
let pipe: DatePipe;

View File

@ -12,7 +12,7 @@ import {JitReflector} from '@angular/platform-browser-dynamic/src/compiler_refle
import {browserDetection} from '@angular/platform-browser/testing/src/browser_util';
{
describe('DeprecatedDatePipe', () => {
xdescribe('DeprecatedDatePipe', () => {
let date: Date;
const isoStringWithoutTime = '2015-01-01';
let pipe: DeprecatedDatePipe;

View File

@ -19,7 +19,7 @@ import {ISubscription} from 'rxjs/Subscription';
@Injectable()
export class SpyLocation implements Location {
urlChanges: string[] = [];
private _history: LocationState[] = [new LocationState('', '')];
private _history: LocationState[] = [new LocationState('', '', null)];
private _historyIndex: number = 0;
/** @internal */
_subject: EventEmitter<any> = new EventEmitter();
@ -34,6 +34,8 @@ export class SpyLocation implements Location {
path(): string { return this._history[this._historyIndex].path; }
private state(): string { return this._history[this._historyIndex].state; }
isCurrentPathEqualTo(path: string, query: string = ''): boolean {
const givenPath = path.endsWith('/') ? path.substring(0, path.length - 1) : path;
const currPath =
@ -60,13 +62,13 @@ export class SpyLocation implements Location {
return this._baseHref + url;
}
go(path: string, query: string = '') {
go(path: string, query: string = '', state: any = null) {
path = this.prepareExternalUrl(path);
if (this._historyIndex > 0) {
this._history.splice(this._historyIndex + 1);
}
this._history.push(new LocationState(path, query));
this._history.push(new LocationState(path, query, state));
this._historyIndex = this._history.length - 1;
const locationState = this._history[this._historyIndex - 1];
@ -79,7 +81,7 @@ export class SpyLocation implements Location {
this._subject.emit({'url': url, 'pop': false});
}
replaceState(path: string, query: string = '') {
replaceState(path: string, query: string = '', state: any = null) {
path = this.prepareExternalUrl(path);
const history = this._history[this._historyIndex];
@ -89,6 +91,7 @@ export class SpyLocation implements Location {
history.path = path;
history.query = query;
history.state = state;
const url = path + (query.length > 0 ? ('?' + query) : '');
this.urlChanges.push('replace: ' + url);
@ -97,14 +100,14 @@ export class SpyLocation implements Location {
forward() {
if (this._historyIndex < (this._history.length - 1)) {
this._historyIndex++;
this._subject.emit({'url': this.path(), 'pop': true});
this._subject.emit({'url': this.path(), 'state': this.state(), 'pop': true});
}
}
back() {
if (this._historyIndex > 0) {
this._historyIndex--;
this._subject.emit({'url': this.path(), 'pop': true});
this._subject.emit({'url': this.path(), 'state': this.state(), 'pop': true});
}
}
@ -118,10 +121,5 @@ export class SpyLocation implements Location {
}
class LocationState {
path: string;
query: string;
constructor(path: string, query: string) {
this.path = path;
this.query = query;
}
constructor(public path: string, public query: string, public state: any) {}
}

View File

@ -1878,5 +1878,68 @@ describe('ngc transformer command-line', () => {
expect(exitCode).toBe(0, 'Compile failed');
expect(emittedFile('hello-world.js')).toContain('ngComponentDef');
});
it('should emit an injection of a string token', () => {
write('tsconfig.json', `{
"extends": "./tsconfig-base.json",
"files": ["hello-world.ts"],
"angularCompilerOptions": {
"enableIvy": true
}
}`);
write('hello-world.ts', `
import {Component, Inject, NgModule} from '@angular/core';
@Component({
selector: 'hello-world',
template: 'Hello, world!'
})
export class HelloWorldComponent {
constructor (@Inject('test') private test: string) {}
}
@NgModule({
declarations: [HelloWorldComponent],
providers: [
{provide: 'test', useValue: 'test'}
]
})
export class HelloWorldModule {}
`);
const errors: string[] = [];
const exitCode = main(['-p', path.join(basePath, 'tsconfig.json')], msg => errors.push(msg));
expect(exitCode).toBe(0, `Compile failed:\n${errors.join('\n ')}`);
expect(emittedFile('hello-world.js')).toContain('ngComponentDef');
});
it('should emit an example that uses the E() instruction', () => {
write('tsconfig.json', `{
"extends": "./tsconfig-base.json",
"files": ["hello-world.ts"],
"angularCompilerOptions": {
"enableIvy": true
}
}`);
write('hello-world.ts', `
import {Component, NgModule} from '@angular/core';
@Component({
selector: 'hello-world',
template: '<h1><div style="text-align:center"> Hello, {{name}}! </div></h1> '
})
export class HelloWorldComponent {
name = 'World';
}
@NgModule({declarations: [HelloWorldComponent]})
export class HelloWorldModule {}
`);
const errors: string[] = [];
const exitCode = main(['-p', path.join(basePath, 'tsconfig.json')], msg => errors.push(msg));
expect(exitCode).toBe(0, `Compile failed:\n${errors.join('\n ')}`);
expect(emittedFile('hello-world.js')).toContain('ngComponentDef');
});
});
});

View File

@ -27,7 +27,7 @@ class FixupExpression extends o.Expression {
shared: boolean;
visitExpression(visitor: o.ExpressionVisitor, context: any): any {
this.resolved.visitExpression(visitor, context);
return this.resolved.visitExpression(visitor, context);
}
isEquivalent(e: o.Expression): boolean {

View File

@ -66,6 +66,9 @@ export class Identifiers {
static memory: o.ExternalReference = {name: 'ɵm', moduleName: CORE};
static projection: o.ExternalReference = {name: 'ɵP', moduleName: CORE};
static projectionDef: o.ExternalReference = {name: 'ɵpD', moduleName: CORE};
static refreshComponent: o.ExternalReference = {name: 'ɵr', moduleName: CORE};
static directiveLifeCycle: o.ExternalReference = {name: 'ɵl', moduleName: CORE};

View File

@ -15,11 +15,13 @@ import {Identifiers} from '../identifiers';
import * as o from '../output/output_ast';
import {ParseSourceSpan} from '../parse_util';
import {CssSelector} from '../selector';
import {AttrAst, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, DirectiveAst, ElementAst, EmbeddedTemplateAst, NgContentAst, PropertyBindingType, ProviderAst, QueryMatch, ReferenceAst, TemplateAst, TemplateAstVisitor, TextAst, VariableAst, templateVisitAll} from '../template_parser/template_ast';
import {AttrAst, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, DirectiveAst, ElementAst, EmbeddedTemplateAst, NgContentAst, PropertyBindingType, ProviderAst, QueryMatch, RecursiveTemplateAstVisitor, ReferenceAst, TemplateAst, TemplateAstVisitor, TextAst, VariableAst, templateVisitAll} from '../template_parser/template_ast';
import {OutputContext, error} from '../util';
import {Identifiers as R3} from './r3_identifiers';
/** Name of the context parameter passed into a template function */
const CONTEXT_NAME = 'ctx';
@ -32,10 +34,17 @@ const TEMPORARY_NAME = '_t';
/** The prefix reference variables */
const REFERENCE_PREFIX = '_r';
/** The name of the implicit context reference */
const IMPLICIT_REFERENCE = '$implicit';
export function compileDirective(
outputCtx: OutputContext, directive: CompileDirectiveMetadata, reflector: CompileReflector) {
const definitionMapValues: {key: string, quoted: boolean, value: o.Expression}[] = [];
// e.g. 'type: MyDirective`
definitionMapValues.push(
{key: 'type', value: outputCtx.importExpr(directive.type.reference), quoted: false});
// e.g. `factory: () => new MyApp(injectElementRef())`
const templateFactory = createFactory(directive.type, outputCtx, reflector);
definitionMapValues.push({key: 'factory', value: templateFactory, quoted: false});
@ -63,7 +72,11 @@ export function compileComponent(
reflector: CompileReflector) {
const definitionMapValues: {key: string, quoted: boolean, value: o.Expression}[] = [];
// e.g. `tag: 'my-app'
// e.g. `type: MyApp`
definitionMapValues.push(
{key: 'type', value: outputCtx.importExpr(component.type.reference), quoted: false});
// e.g. `tag: 'my-app'`
// This is optional and only included if the first selector of a component has element.
const selector = component.selector && CssSelector.parse(component.selector);
const firstSelector = selector && selector[0];
@ -97,8 +110,8 @@ export function compileComponent(
const templateFunctionExpression =
new TemplateDefinitionBuilder(
outputCtx, outputCtx.constantPool, reflector, CONTEXT_NAME, ROOT_SCOPE.nestedScope(), 0,
templateTypeName, templateName)
.buildTemplateFunction(template);
component.template !.ngContentSelectors, templateTypeName, templateName)
.buildTemplateFunction(template, []);
definitionMapValues.push({key: 'template', value: templateFunctionExpression, quoted: false});
@ -123,13 +136,15 @@ export function compileComponent(
// TODO: Remove these when the things are fully supported
function unknown<T>(arg: o.Expression | o.Statement | TemplateAst): never {
throw new Error(`Builder ${this.constructor.name} is unable to handle ${o.constructor.name} yet`);
throw new Error(
`Builder ${this.constructor.name} is unable to handle ${arg.constructor.name} yet`);
}
function unsupported(feature: string): never {
if (this) {
throw new Error(`Builder ${this.constructor.name} doesn't support ${feature} yet`);
}
throw new Error(`Feature ${feature} is supported yet`);
throw new Error(`Feature ${feature} is not supported yet`);
}
const BINDING_INSTRUCTION_MAP: {[index: number]: o.ExternalReference | undefined} = {
@ -214,16 +229,57 @@ class TemplateDefinitionBuilder implements TemplateAstVisitor, LocalResolver {
private _hostMode: o.Statement[] = [];
private _refreshMode: o.Statement[] = [];
private _postfix: o.Statement[] = [];
private _contentProjections: Map<NgContentAst, NgContentInfo>;
private _projectionDefinitionIndex = 0;
private unsupported = unsupported;
private invalid = invalid;
constructor(
private outputCtx: OutputContext, private constantPool: ConstantPool,
private reflector: CompileReflector, private contextParameter: string,
private bindingScope: BindingScope, private level = 0, private contextName: string|null,
private templateName: string|null) {}
private bindingScope: BindingScope, private level = 0, private ngContentSelectors: string[],
private contextName: string|null, private templateName: string|null) {}
buildTemplateFunction(asts: TemplateAst[], variables: VariableAst[]): o.FunctionExpr {
// Create variable bindings
for (const variable of variables) {
const variableName = variable.name;
const expression =
o.variable(this.contextParameter).prop(variable.value || IMPLICIT_REFERENCE);
const scopedName = this.bindingScope.freshReferenceName();
const declaration = o.variable(scopedName).set(expression).toDeclStmt(o.INFERRED_TYPE, [
o.StmtModifier.Final
]);
// Add the reference to the local scope.
this.bindingScope.set(variableName, scopedName);
// Declare the local variable in binding mode
this._bindingMode.push(declaration);
}
// Collect content projections
if (this.ngContentSelectors && this.ngContentSelectors.length > 0) {
const contentProjections = getContentProjection(asts, this.ngContentSelectors);
this._contentProjections = contentProjections;
if (contentProjections.size > 0) {
const infos: R3CssSelector[] = [];
Array.from(contentProjections.values()).forEach(info => {
if (info.selector) {
infos[info.index - 1] = info.selector;
}
});
const projectionIndex = this._projectionDefinitionIndex = this.allocateDataSlot();
const parameters: o.Expression[] = [o.literal(projectionIndex)];
!infos.some(value => !value) || error(`content project information skipped an index`);
if (infos.length > 1) {
parameters.push(this.outputCtx.constantPool.getConstLiteral(
asLiteral(infos), /* forceShared */ true));
}
this.instruction(this._creationMode, null, R3.projectionDef, ...parameters);
}
}
buildTemplateFunction(asts: TemplateAst[]): o.FunctionExpr {
templateVisitAll(this, asts);
return o.fn(
@ -254,8 +310,16 @@ class TemplateDefinitionBuilder implements TemplateAstVisitor, LocalResolver {
getLocal(name: string): o.Expression|null { return this.bindingScope.get(name); }
// TODO(chuckj): Implement ng-content
visitNgContent = unknown;
visitNgContent(ast: NgContentAst) {
const info = this._contentProjections.get(ast) !;
info || error(`Expected ${ast.sourceSpan} to be included in content projection collection`);
const slot = this.allocateDataSlot();
const parameters = [o.literal(slot), o.literal(this._projectionDefinitionIndex)];
if (info.index !== 0) {
parameters.push(o.literal(info.index));
}
this.instruction(this._creationMode, ast.sourceSpan, R3.projection, ...parameters);
}
private _computeDirectivesArray(directives: DirectiveAst[]) {
const directiveIndexMap = new Map<any, number>();
@ -395,8 +459,9 @@ class TemplateDefinitionBuilder implements TemplateAstVisitor, LocalResolver {
this, implicit, input.value, this.bindingContext(), BindingForm.TrySimple, interpolate);
this._bindingMode.push(...convertedBinding.stmts);
this.instruction(
this._bindingMode, directive.sourceSpan, R3.elementProperty,
o.literal(input.templateName), o.literal(nodeIndex), convertedBinding.currValExpr);
this._bindingMode, directive.sourceSpan, R3.elementProperty, o.literal(nodeIndex),
o.literal(input.templateName),
o.importExpr(R3.bind).callFn([convertedBinding.currValExpr]));
}
// e.g. TodoComponentDef.r(0, 0);
@ -444,8 +509,9 @@ class TemplateDefinitionBuilder implements TemplateAstVisitor, LocalResolver {
// Create the template function
const templateVisitor = new TemplateDefinitionBuilder(
this.outputCtx, this.constantPool, this.reflector, templateContext,
this.bindingScope.nestedScope(), this.level + 1, contextName, templateName);
const templateFunctionExpr = templateVisitor.buildTemplateFunction(ast.children);
this.bindingScope.nestedScope(), this.level + 1, this.ngContentSelectors, contextName,
templateName);
const templateFunctionExpr = templateVisitor.buildTemplateFunction(ast.children, ast.variables);
this._postfix.push(templateFunctionExpr.toDeclStmt(templateName, null));
}
@ -483,7 +549,7 @@ class TemplateDefinitionBuilder implements TemplateAstVisitor, LocalResolver {
private bindingContext() { return `${this._bindingContext++}`; }
private instruction(
statements: o.Statement[], span: ParseSourceSpan, reference: o.ExternalReference,
statements: o.Statement[], span: ParseSourceSpan|null, reference: o.ExternalReference,
...params: o.Expression[]) {
statements.push(o.importExpr(reference, null, span).callFn(params, span).toStmt());
}
@ -542,7 +608,9 @@ function createFactory(
} else if (tokenRef === viewContainerRef) {
args.push(o.importExpr(R3.injectViewContainerRef).callFn([]));
} else {
args.push(o.importExpr(R3.inject).callFn([outputCtx.importExpr(token)]));
const value =
token.identifier != null ? outputCtx.importExpr(tokenRef) : o.literal(tokenRef);
args.push(o.importExpr(R3.inject).callFn([value]));
}
} else {
unsupported('dependency without a token');
@ -563,3 +631,68 @@ function invalid<T>(arg: o.Expression | o.Statement | TemplateAst): never {
function findComponent(directives: DirectiveAst[]): DirectiveAst|undefined {
return directives.filter(directive => directive.directive.isComponent)[0];
}
interface NgContentInfo {
index: number;
selector?: R3CssSelector;
}
class ContentProjectionVisitor extends RecursiveTemplateAstVisitor {
private index = 1;
constructor(
private projectionMap: Map<NgContentAst, NgContentInfo>,
private ngContentSelectors: string[]) {
super();
}
visitNgContent(ast: NgContentAst) {
const selectorText = this.ngContentSelectors[ast.index];
selectorText != null || error(`could not find selector for index ${ast.index} in ${ast}`);
if (!selectorText || selectorText === '*') {
this.projectionMap.set(ast, {index: 0});
} else {
const cssSelectors = CssSelector.parse(selectorText);
this.projectionMap.set(
ast, {index: this.index++, selector: parseSelectorsToR3Selector(cssSelectors)});
}
}
}
function getContentProjection(asts: TemplateAst[], ngContentSelectors: string[]) {
const projectIndexMap = new Map<NgContentAst, NgContentInfo>();
const visitor = new ContentProjectionVisitor(projectIndexMap, ngContentSelectors);
templateVisitAll(visitor, asts);
return projectIndexMap;
}
// These are a copy the CSS types from core/src/render3/interfaces/projection.ts
// They are duplicated here as they cannot be directly referenced from core.
type R3SimpleCssSelector = (string | null)[];
type R3CssSelectorWithNegations =
[R3SimpleCssSelector, null] | [R3SimpleCssSelector, R3SimpleCssSelector];
type R3CssSelector = R3CssSelectorWithNegations[];
function parserSelectorToSimpleSelector(selector: CssSelector): R3SimpleCssSelector {
const classes =
selector.classNames && selector.classNames.length ? ['class', ...selector.classNames] : [];
return [selector.element, ...selector.attrs, ...classes];
}
function parserSelectorToR3Selector(selector: CssSelector): R3CssSelectorWithNegations {
const positive = parserSelectorToSimpleSelector(selector);
const negative = selector.notSelectors && selector.notSelectors.length &&
parserSelectorToSimpleSelector(selector.notSelectors[0]);
return negative ? [positive, negative] : [positive, null];
}
function parseSelectorsToR3Selector(selectors: CssSelector[]): R3CssSelector {
return selectors.map(parserSelectorToR3Selector);
}
function asLiteral(value: any): o.Expression {
if (Array.isArray(value)) {
return o.literalArr(value.map(asLiteral));
}
return o.literal(value, o.INFERRED_TYPE);
}

View File

@ -178,6 +178,7 @@ describe('r3_view_compiler', () => {
// ChildComponent definition should be:
const ChildComponentDefinition = `
static ngComponentDef = IDENT.ɵdefineComponent({
type: ChildComponent,
tag: 'child',
factory: function ChildComponent_Factory() { return new ChildComponent(); },
template: function ChildComponent_Template(ctx: IDENT, cm: IDENT) {
@ -190,6 +191,7 @@ describe('r3_view_compiler', () => {
// SomeDirective definition should be:
const SomeDirectiveDefinition = `
static ngDirectiveDef = IDENT.ɵdefineDirective({
type: SomeDirective,
factory: function SomeDirective_Factory() {return new SomeDirective(); }
});
`;
@ -197,6 +199,7 @@ describe('r3_view_compiler', () => {
// MyComponent definition should be:
const MyComponentDefinition = `
static ngComponentDef = IDENT.ɵdefineComponent({
type: MyComponent,
tag: 'my-component',
factory: function MyComponent_Factory() { return new MyComponent(); },
template: function MyComponent_Template(ctx: IDENT, cm: IDENT) {
@ -253,10 +256,12 @@ describe('r3_view_compiler', () => {
const IfDirectiveDefinition = `
static ngDirectiveDef = IDENT.ɵdefineDirective({
type: IfDirective,
factory: function IfDirective_Factory() { return new IfDirective(IDENT.ɵinjectTemplateRef()); }
});`;
const MyComponentDefinition = `
static ngComponentDef = IDENT.ɵdefineComponent({
type: MyComponent,
tag: 'my-component',
factory: function MyComponent_Factory() { return new MyComponent(); },
template: function MyComponent_Template(ctx: IDENT, cm: IDENT) {
@ -292,6 +297,82 @@ describe('r3_view_compiler', () => {
expectEmit(source, directives, 'Incorrect shared directive constant');
});
it('should support content projection', () => {
const files = {
app: {
'spec.ts': `
import {Component, Directive, NgModule, TemplateRef} from '@angular/core';
@Component({selector: 'simple', template: '<div><ng-content></ng-content></div>'})
export class SimpleComponent {}
@Component({
selector: 'complex',
template: \`
<div id="first"><ng-content select="span[title=toFirst]"></ng-content></div>
<div id="second"><ng-content select="span[title=toSecond]"></ng-content></div>\`
})
export class ComplexComponent { }
@NgModule({declarations: [SimpleComponent, ComplexComponent]})
export class MyModule {}
@Component({
selector: 'my-app',
template: '<simple>content</simple> <complex></complex>'
})
export class MyApp {}
`
}
};
const SimpleComponentDefinition = `
static ngComponentDef = IDENT.ɵdefineComponent({
type: SimpleComponent,
tag: 'simple',
factory: function SimpleComponent_Factory() { return new SimpleComponent(); },
template: function SimpleComponent_Template(ctx: IDENT, cm: IDENT) {
if (cm) {
IDENT.ɵpD(0);
IDENT.ɵE(1, 'div');
IDENT.ɵP(2, 0);
IDENT.ɵe();
}
}
});`;
const ComplexComponentDefinition = `
static ngComponentDef = IDENT.ɵdefineComponent({
type: ComplexComponent,
tag: 'complex',
factory: function ComplexComponent_Factory() { return new ComplexComponent(); },
template: function ComplexComponent_Template(ctx: IDENT, cm: IDENT) {
if (cm) {
IDENT.ɵpD(0, IDENT);
IDENT.ɵE(1, 'div', IDENT);
IDENT.ɵP(2, 0, 1);
IDENT.ɵe();
IDENT.ɵE(3, 'div', IDENT);
IDENT.ɵP(4, 0, 2);
IDENT.ɵe();
}
}
});
`;
const ComplexComponent_ProjectionConst = `
const IDENT = [[[['span', 'title', 'tofirst'], null]], [[['span', 'title', 'tosecond'], null]]];
`;
const result = compile(files, angularFiles);
const source = result.source;
expectEmit(result.source, SimpleComponentDefinition, 'Incorrect SimpleComponent definition');
expectEmit(
result.source, ComplexComponentDefinition, 'Incorrect ComplexComponent definition');
expectEmit(result.source, ComplexComponent_ProjectionConst, 'Incorrect projection const');
});
it('local reference', () => {
const files = {
app: {
@ -309,6 +390,7 @@ describe('r3_view_compiler', () => {
const MyComponentDefinition = `
static ngComponentDef = IDENT.ɵdefineComponent({
type: MyComponent,
tag: 'my-component',
factory: function MyComponent_Factory() { return new MyComponent(); },
template: function MyComponent_Template(ctx: IDENT, cm: IDENT) {
@ -331,6 +413,226 @@ describe('r3_view_compiler', () => {
expectEmit(source, MyComponentDefinition, 'Incorrect MyComponent.ngComponentDef');
expectEmit(source, locals, 'Incorrect locals constant definition');
});
describe('template variables', () => {
const shared = {
shared: {
'for_of.ts': `
import {Directive, Input, SimpleChanges, TemplateRef, ViewContainerRef} from '@angular/core';
export interface ForOfContext {
$implicit: any;
index: number;
even: boolean;
odd: boolean;
}
@Directive({selector: '[forOf]'})
export class ForOfDirective {
private previous: any[];
constructor(private view: ViewContainerRef, private template: TemplateRef<any>) {}
@Input() forOf: any[];
ngOnChanges(simpleChanges: SimpleChanges) {
if ('forOf' in simpleChanges) {
this.update();
}
}
ngDoCheck(): void {
const previous = this.previous;
const current = this.forOf;
if (!previous || previous.length != current.length ||
previous.some((value: any, index: number) => current[index] !== previous[index])) {
this.update();
}
}
private update() {
// TODO(chuckj): Not implemented yet
// this.view.clear();
if (this.forOf) {
const current = this.forOf;
for (let i = 0; i < current.length; i++) {
const context = {$implicit: current[i], index: i, even: i % 2 == 0, odd: i % 2 == 1};
// TODO(chuckj): Not implemented yet
// this.view.createEmbeddedView(this.template, context);
}
this.previous = [...this.forOf];
}
}
}
`
}
};
it('should support a let variable and reference', () => {
const files = {
app: {
...shared,
'spec.ts': `
import {Component, NgModule} from '@angular/core';
import {ForOfDirective} from './shared/for_of';
@Component({
selector: 'my-component',
template: \`<ul><li *for="let item of items">{{item.name}}</li></ul>\`
})
export class MyComponent {
items = [{name: 'one'}, {name: 'two'}];
}
@NgModule({
declarations: [MyComponent, ForOfDirective]
})
export class MyModule {}
`
}
};
// TODO(chuckj): Enforce this when the directives are specified
const ForDirectiveDefinition = `
static ngDirectiveDef = IDENT.ɵdefineDirective({
factory: function ForOfDirective_Factory() {
return new ForOfDirective(IDENT.ɵinjectViewContainerRef(), IDENT.ɵinjectTemplateRef());
},
features: [IDENT.ɵNgOnChangesFeature(NgForOf)],
refresh: function ForOfDirective_Refresh(directiveIndex: IDENT, elementIndex: IDENT) {
IDENT.ɵm<ForOfDirective>(directiveIndex).ngDoCheck();
},
inputs: {forOf: 'forOf'}
});
`;
const MyComponentDefinition = `
static ngComponentDef = IDENT.ɵdefineComponent({
type: MyComponent,
tag: 'my-component',
factory: function MyComponent_Factory() { return new MyComponent(); },
template: function MyComponent_Template(ctx: IDENT, cm: IDENT) {
if (cm) {
IDENT.ɵE(0, 'ul');
IDENT.ɵC(1, IDENT, MyComponent_ForOfDirective_Template_1);
IDENT.ɵe();
}
IDENT.ɵp(1, 'forOf', IDENT.ɵb(ctx.items));
IDENT.ɵcR(1);
ForOfDirective.ngDirectiveDef.r(2, 1);
IDENT.ɵcr();
function MyComponent_ForOfDirective_Template_1(ctx0: IDENT, cm: IDENT) {
if (cm) {
IDENT.ɵE(0, 'li');
IDENT.ɵT(1);
IDENT.ɵe();
}
const IDENT = ctx0.$implicit;
IDENT.ɵt(1, IDENT.ɵb1('', IDENT.name, ''));
}
}
});
`;
const result = compile(files, angularFiles);
const source = result.source;
// TODO(chuckj): Enforce this when the directives are specified
// expectEmit(source, ForDirectiveDefinition, 'Invalid directive definition');
expectEmit(source, MyComponentDefinition, 'Invalid component definition');
});
it('should support accessing parent template variables', () => {
const files = {
app: {
...shared,
'spec.ts': `
import {Component, NgModule} from '@angular/core';
import {ForOfDirective} from './shared/for_of';
@Component({
selector: 'my-component',
template: \`
<ul>
<li *for="let item of items">
<div>{{item.name}}</div>
<ul>
<li *for="let info of item.infos">
{{item.name}}: {{info.description}}
</li>
</ul>
</li>
</ul>\`
})
export class MyComponent {
items: Item[] = [
{name: 'one', infos: [{description: '11'}, {description: '12'}]},
{name: 'two', infos: [{description: '21'}, {description: '22'}]}
];
}
@NgModule({
declarations: [MyComponent, ForOfDirective]
})
export class MyModule {}
`
}
};
const MyComponentDefinition = `
static ngComponentDef = IDENT.ɵdefineComponent({
type: MyComponent,
tag: 'my-component',
factory: function MyComponent_Factory() { return new MyComponent(); },
template: function MyComponent_Template(ctx: IDENT, cm: IDENT) {
if (cm) {
IDENT.ɵE(0, 'ul');
IDENT.ɵC(1, IDENT, MyComponent_ForOfDirective_Template_1);
IDENT.ɵe();
}
IDENT.ɵp(1, 'forOf', IDENT.ɵb(ctx.items));
IDENT.ɵcR(1);
IDENT.r(2, 1);
IDENT.ɵcr();
function MyComponent_ForOfDirective_Template_1(ctx0: IDENT, cm: IDENT) {
if (cm) {
IDENT.ɵE(0, 'li');
IDENT.ɵE(1, 'div');
IDENT.ɵT(2);
IDENT.ɵe();
IDENT.ɵE(3, 'ul');
IDENT.ɵC(4, IDENT, MyComponent_ForOfDirective_ForOfDirective_Template_4);
IDENT.ɵe();
IDENT.ɵe();
}
const IDENT = ctx0.$implicit;
IDENT.ɵp(4, 'forOf', IDENT.ɵb(IDENT.infos));
IDENT.ɵt(2, IDENT.ɵb1('', IDENT.name, ''));
IDENT.ɵcR(4);
IDENT.r(5, 4);
IDENT.ɵcr();
function MyComponent_ForOfDirective_ForOfDirective_Template_4(
ctx1: IDENT, cm: IDENT) {
if (cm) {
IDENT.ɵE(0, 'li');
IDENT.ɵT(1);
IDENT.ɵe();
}
const IDENT = ctx1.$implicit;
IDENT.ɵt(1, IDENT.ɵb2(' ', IDENT.name, ': ', IDENT.description, ' '));
}
}
}
});`;
const result = compile(files, angularFiles);
const source = result.source;
expectEmit(source, MyComponentDefinition, 'Invalid component definition');
});
});
});
});
@ -389,7 +691,7 @@ function expectEmit(source: string, emitted: string, description: string) {
if (!m) {
const contextPieceWidth = contextWidth / 2;
fail(
`${description}: Expected to find ${expected} '${source.substr(0,last)}[<---HERE]${source.substr(last)}'`);
`${description}: Expected to find ${expected} '${source.substr(0,last)}[<---HERE expected "${expected}"]${source.substr(last)}'`);
return;
} else {
last = (m.index || 0) + m[0].length;
@ -401,7 +703,7 @@ function expectEmit(source: string, emitted: string, description: string) {
}
const IDENT_LIKE = /^[a-z][A-Z]/;
const SPECIAL_RE_CHAR = /\/|\(|\)|\||\*|\+|\[|\]|\{|\}/g;
const SPECIAL_RE_CHAR = /\/|\(|\)|\||\*|\+|\[|\]|\{|\}|\$/g;
function r(...pieces: (string | RegExp)[]): RegExp {
let results: string[] = [];
let first = true;

View File

@ -34,5 +34,6 @@ export {
s as ɵs,
t as ɵt,
v as ɵv,
r as ɵr,
} from './render3/index';
// clang-format on

View File

@ -13,8 +13,8 @@ import {ComponentRef as viewEngine_ComponentRef} from '../linker/component_facto
import {EmbeddedViewRef as viewEngine_EmbeddedViewRef} from '../linker/view_ref';
import {assertNotNull} from './assert';
import {NG_HOST_SYMBOL, createError, createLView, directiveCreate, enterView, hostElement, leaveView, locateHostElement, renderComponentOrTemplate} from './instructions';
import {ComponentDef, ComponentType, TypedComponentDef} from './interfaces/definition';
import {NG_HOST_SYMBOL, createError, createLView, createTView, directiveCreate, enterView, hostElement, leaveView, locateHostElement, renderComponentOrTemplate} from './instructions';
import {ComponentDef, ComponentType} from './interfaces/definition';
import {LElementNode} from './interfaces/node';
import {RElement, Renderer3, RendererFactory3, domRendererFactory3} from './interfaces/renderer';
import {notImplemented, stringify} from './util';
@ -166,13 +166,13 @@ export const NULL_INJECTOR: Injector = {
export function renderComponent<T>(
componentType: ComponentType<T>, opts: CreateComponentOptions = {}): T {
const rendererFactory = opts.rendererFactory || domRendererFactory3;
const componentDef = componentType.ngComponentDef as TypedComponentDef<T>;
const componentDef = componentType.ngComponentDef as ComponentDef<T>;
if (componentDef.type != componentType) componentDef.type = componentType;
let component: T;
const hostNode = locateHostElement(rendererFactory, opts.host || componentDef.tag);
const oldView = enterView(
createLView(
-1, rendererFactory.createRenderer(hostNode, componentDef.rendererType), {data: []}),
-1, rendererFactory.createRenderer(hostNode, componentDef.rendererType), createTView()),
null !);
try {
// Create element node at index 0 in data array

View File

@ -13,8 +13,7 @@ import {Type} from '../type';
import {resolveRendererType2} from '../view/util';
import {diPublic} from './di';
import {componentRefresh} from './instructions';
import {ComponentDef, ComponentDefArgs, DirectiveDef, DirectiveDefArgs, TypedDirectiveDef} from './interfaces/definition';
import {ComponentDef, ComponentDefArgs, DirectiveDef, DirectiveDefArgs} from './interfaces/definition';
@ -34,22 +33,26 @@ import {ComponentDef, ComponentDefArgs, DirectiveDef, DirectiveDefArgs, TypedDir
* ```
*/
export function defineComponent<T>(componentDefinition: ComponentDefArgs<T>): ComponentDef<T> {
const type = componentDefinition.type;
const def = <ComponentDef<any>>{
type: type,
diPublic: null,
n: componentDefinition.factory,
tag: (componentDefinition as ComponentDefArgs<T>).tag || null !,
template: (componentDefinition as ComponentDefArgs<T>).template || null !,
r: componentDefinition.refresh || (componentDefinition.template ?
function(d: number, e: number) {
componentRefresh(d, e, componentDefinition.template);
} :
noop),
h: componentDefinition.hostBindings || noop,
inputs: invertObject(componentDefinition.inputs),
outputs: invertObject(componentDefinition.outputs),
methods: invertObject(componentDefinition.methods),
rendererType: resolveRendererType2(componentDefinition.rendererType) || null,
exportAs: componentDefinition.exportAs,
onInit: type.prototype.ngOnInit || null,
doCheck: type.prototype.ngDoCheck || null,
afterContentInit: type.prototype.ngAfterContentInit || null,
afterContentChecked: type.prototype.ngAfterContentChecked || null,
afterViewInit: type.prototype.ngAfterViewInit || null,
afterViewChecked: type.prototype.ngAfterViewChecked || null,
onDestroy: type.prototype.ngOnDestroy || null
};
const feature = componentDefinition.features;
feature && feature.forEach((fn) => fn(def));
@ -96,19 +99,30 @@ export function NgOnChangesFeature<T>(type: Type<T>): (definition: DirectiveDef<
}
});
}
proto.ngDoCheck = (function(delegateDoCheck) {
// If an onInit hook is defined, it will need to wrap the ngOnChanges call
// so the call order is changes-init-check in creation mode. In subsequent
// change detection runs, only the check wrapper will be called.
if (definition.onInit != null) {
definition.onInit = onChangesWrapper(definition.onInit);
}
definition.doCheck = onChangesWrapper(definition.doCheck);
function onChangesWrapper(delegateHook: (() => void) | null) {
return function(this: OnChangesExpando) {
let simpleChanges = this[PRIVATE_PREFIX];
if (simpleChanges != null) {
this.ngOnChanges(simpleChanges);
this[PRIVATE_PREFIX] = null;
}
delegateDoCheck && delegateDoCheck.apply(this);
delegateHook && delegateHook.apply(this);
};
})(proto.ngDoCheck);
}
};
}
export function PublicFeature<T>(definition: DirectiveDef<T>) {
definition.diPublic = diPublic;
}

View File

@ -19,7 +19,7 @@ import {Type} from '../type';
import {assertLessThan} from './assert';
import {assertPreviousIsParent, getPreviousOrParentNode, getRenderer, renderEmbeddedTemplate} from './instructions';
import {ComponentTemplate, DirectiveDef, TypedDirectiveDef} from './interfaces/definition';
import {ComponentTemplate, DirectiveDef} from './interfaces/definition';
import {LInjector} from './interfaces/injector';
import {LContainerNode, LElementNode, LNode, LNodeFlags, LViewNode} from './interfaces/node';
import {QueryReadType} from './interfaces/query';
@ -158,7 +158,7 @@ function createInjectionError(text: string, token: any) {
* @param di The node injector in which a directive will be added
* @param def The definition of the directive to be made public
*/
export function diPublicInInjector(di: LInjector, def: TypedDirectiveDef<any>): void {
export function diPublicInInjector(di: LInjector, def: DirectiveDef<any>): void {
bloomAdd(di, def.type);
}
@ -167,7 +167,7 @@ export function diPublicInInjector(di: LInjector, def: TypedDirectiveDef<any>):
*
* @param def The definition of the directive to be made public
*/
export function diPublic(def: TypedDirectiveDef<any>): void {
export function diPublic(def: DirectiveDef<any>): void {
diPublicInInjector(getOrCreateNodeInjector(), def);
}
@ -291,7 +291,7 @@ export function getOrCreateInjectable<T>(
for (let i = start, ii = start + size; i < ii; i++) {
// Get the definition for the directive at this index and, if it is injectable (diPublic),
// and matches the given token, return the directive instance.
const directiveDef = tData[i] as TypedDirectiveDef<any>;
const directiveDef = tData[i] as DirectiveDef<any>;
if (directiveDef.diPublic && directiveDef.type == token) {
return node.view.data[i];
}
@ -392,7 +392,10 @@ export class ReadFromInjectorFn<T> {
* @returns The ElementRef instance to use
*/
export function getOrCreateElementRef(di: LInjector): viewEngine_ElementRef {
return di.elementRef || (di.elementRef = new ElementRef(di.node.native));
return di.elementRef ||
(di.elementRef = new ElementRef(
((di.node.flags & LNodeFlags.TYPE_MASK) === LNodeFlags.Container) ? null :
di.node.native));
}
export const QUERY_READ_TEMPLATE_REF = <QueryReadType<viewEngine_TemplateRef<any>>>(

View File

@ -0,0 +1,174 @@
/**
* @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 {DirectiveDef} from './interfaces/definition';
import {LNodeFlags} from './interfaces/node';
import {HookData, LView, LifecycleStage, TView} from './interfaces/view';
/** Constants used by lifecycle hooks to determine when and how a hook should be called. */
export const enum LifecycleHook {
ON_INIT = 0b00,
ON_CHECK = 0b01,
/* Mask used to get the type of the lifecycle hook from flags in hook queue */
TYPE_MASK = 0b00000000000000000000000000000001,
/* Shift needed to get directive index from flags in hook queue */
INDX_SHIFT = 1
}
/**
* If this is the first template pass, any ngOnInit or ngDoCheck hooks will be queued into
* TView.initHooks during directiveCreate.
*
* The directive index and hook type are encoded into one number (1st bit: type, remaining bits:
* directive index), then saved in the even indices of the initHooks array. The odd indices
* hold the hook functions themselves.
*
* @param index The index of the directive in LView.data
* @param hooks The static hooks map on the directive def
* @param tView The current TView
*/
export function queueInitHooks(
index: number, onInit: (() => void) | null, doCheck: (() => void) | null, tView: TView): void {
if (tView.firstTemplatePass === true) {
if (onInit != null) {
(tView.initHooks || (tView.initHooks = [])).push(getInitFlags(index), onInit);
}
if (doCheck != null) {
(tView.initHooks || (tView.initHooks = [])).push(getCheckFlags(index), doCheck);
}
}
}
/**
* Loops through the directives on a node and queues all their hooks except ngOnInit
* and ngDoCheck, which are queued separately in directiveCreate.
*/
export function queueLifecycleHooks(flags: number, currentView: LView): void {
const tView = currentView.tView;
if (tView.firstTemplatePass === true) {
const size = (flags & LNodeFlags.SIZE_MASK) >> LNodeFlags.SIZE_SHIFT;
const start = flags >> LNodeFlags.INDX_SHIFT;
// It's necessary to loop through the directives at elementEnd() (rather than processing in
// directiveCreate) so we can preserve the current hook order. Content, view, and destroy
// hooks for projected components and directives must be called *before* their hosts.
for (let i = start, end = start + size; i < end; i++) {
const def = (tView.data[i] as DirectiveDef<any>);
queueContentHooks(def, tView, i);
queueViewHooks(def, tView, i);
queueDestroyHooks(def, tView, i);
}
}
}
/** Queues afterContentInit and afterContentChecked hooks on TView */
function queueContentHooks(def: DirectiveDef<any>, tView: TView, i: number): void {
if (def.afterContentInit != null) {
(tView.contentHooks || (tView.contentHooks = [])).push(getInitFlags(i), def.afterContentInit);
}
if (def.afterContentChecked != null) {
(tView.contentHooks || (tView.contentHooks = [
])).push(getCheckFlags(i), def.afterContentChecked);
}
}
/** Queues afterViewInit and afterViewChecked hooks on TView */
function queueViewHooks(def: DirectiveDef<any>, tView: TView, i: number): void {
if (def.afterViewInit != null) {
(tView.viewHooks || (tView.viewHooks = [])).push(getInitFlags(i), def.afterViewInit);
}
if (def.afterViewChecked != null) {
(tView.viewHooks || (tView.viewHooks = [])).push(getCheckFlags(i), def.afterViewChecked);
}
}
/** Queues onDestroy hooks on TView */
function queueDestroyHooks(def: DirectiveDef<any>, tView: TView, i: number): void {
if (def.onDestroy != null) {
(tView.destroyHooks || (tView.destroyHooks = [])).push(i, def.onDestroy);
}
}
/** Generates flags for init-only hooks */
function getInitFlags(index: number): number {
return index << LifecycleHook.INDX_SHIFT;
}
/** Generates flags for hooks called every change detection run */
function getCheckFlags(index: number): number {
return (index << LifecycleHook.INDX_SHIFT) | LifecycleHook.ON_CHECK;
}
/**
* Calls onInit and doCheck calls if they haven't already been called.
*
* @param currentView The current view
*/
export function executeInitHooks(currentView: LView): void {
const initHooks = currentView.tView.initHooks;
if (currentView.lifecycleStage === LifecycleStage.INIT && initHooks != null) {
executeLifecycleHooks(currentView, initHooks);
currentView.lifecycleStage = LifecycleStage.CONTENT_INIT;
}
}
/**
* Calls all afterContentInit and afterContentChecked hooks for the view, then splices
* out afterContentInit hooks to prep for the next run in update mode.
*
* @param currentView The current view
*/
export function executeContentHooks(currentView: LView): void {
const contentHooks = currentView.tView.contentHooks;
if (currentView.lifecycleStage < LifecycleStage.VIEW_INIT && contentHooks != null) {
executeLifecycleHooks(currentView, contentHooks);
currentView.lifecycleStage = LifecycleStage.VIEW_INIT;
}
}
/**
* Iterates over afterViewInit and afterViewChecked functions and calls them.
*
* @param currentView The current view
*/
export function executeViewHooks(currentView: LView): void {
const viewHooks = currentView.tView.viewHooks;
if (viewHooks != null) {
executeLifecycleHooks(currentView, viewHooks);
}
}
/**
* Calls lifecycle hooks with their contexts, skipping init hooks if it's not
* creation mode.
*
* @param currentView The current view
* @param arr The array in which the hooks are found
*/
function executeLifecycleHooks(currentView: LView, arr: HookData): void {
const data = currentView.data;
const creationMode = currentView.creationMode;
for (let i = 0; i < arr.length; i += 2) {
const flags = arr[i] as number;
const initOnly = (flags & LifecycleHook.TYPE_MASK) === LifecycleHook.ON_INIT;
if (initOnly === false || creationMode) {
(arr[i | 1] as() => void).call(data[flags >> LifecycleHook.INDX_SHIFT]);
}
}
}

View File

@ -24,8 +24,6 @@ export {InjectFlags, QUERY_READ_CONTAINER_REF, QUERY_READ_ELEMENT_REF, QUERY_REA
// clang-format off
export {
LifecycleHook,
NO_CHANGE as NC,
bind as b,
@ -52,7 +50,6 @@ export {
elementStart as E,
elementStyle as s,
lifecycle as l,
listener as L,
memory as m,
@ -68,10 +65,13 @@ export {
export {
QueryList,
query as Q,
queryRefresh as qR,
} from './query';
export {LifecycleHook} from './hooks';
// clang-format on
export {

View File

@ -8,39 +8,22 @@
import './ng_dev_mode';
import {ElementRef} from '../linker/element_ref';
import {TemplateRef} from '../linker/template_ref';
import {ViewContainerRef} from '../linker/view_container_ref';
import {Type} from '../type';
import {assertEqual, assertLessThan, assertNotEqual, assertNotNull} from './assert';
import {LContainer, TContainer} from './interfaces/container';
import {LInjector} from './interfaces/injector';
import {CssSelector, LProjection} from './interfaces/projection';
import {LQuery, QueryReadType} from './interfaces/query';
import {LView, TData, TView} from './interfaces/view';
import {LQueries} from './interfaces/query';
import {LView, LifecycleStage, TData, TView} from './interfaces/view';
import {LContainerNode, LElementNode, LNode, LNodeFlags, LProjectionNode, LTextNode, LViewNode, TNode, TContainerNode, InitialInputData, InitialInputs, PropertyAliases, PropertyAliasValue,} from './interfaces/node';
import {assertNodeType, assertNodeOfPossibleTypes} from './node_assert';
import {appendChild, insertChild, insertView, processProjectedNode, removeView} from './node_manipulation';
import {appendChild, insertChild, insertView, appendProjectedNode, removeView, canInsertNativeNode} from './node_manipulation';
import {isNodeMatchingSelector} from './node_selector_matcher';
import {ComponentDef, ComponentTemplate, ComponentType, DirectiveDef, DirectiveType, TypedDirectiveDef, TypedComponentDef} from './interfaces/definition';
import {RComment, RElement, RText, Renderer3, RendererFactory3, ProceduralRenderer3, ObjectOrientedRenderer3, RendererStyleFlags3} from './interfaces/renderer';
import {ComponentDef, ComponentTemplate, ComponentType, DirectiveDef, DirectiveType} from './interfaces/definition';
import {RElement, RText, Renderer3, RendererFactory3, ProceduralRenderer3, ObjectOrientedRenderer3, RendererStyleFlags3} from './interfaces/renderer';
import {isDifferent, stringify} from './util';
import {executeViewHooks, executeContentHooks, queueLifecycleHooks, queueInitHooks, executeInitHooks} from './hooks';
/**
* Enum used by the lifecycle (l) instruction to determine which lifecycle hook is requesting
* processing.
*/
export const enum LifecycleHook {
ON_INIT = 1,
ON_DESTROY = 2,
ON_CHANGES = 4,
AFTER_VIEW_INIT = 8,
AFTER_VIEW_CHECKED = 16
}
/**
* Directive (D) sets a property on all component instances using this constant as a key and the
* component's host node (LElement) as the value. This is used in methods like detectChanges to
@ -91,9 +74,9 @@ let tData: TData;
/** State of the current view being processed. */
let currentView: LView;
// The initialization has to be after the `let`, otherwise `createLView` can't see `let`.
currentView = createLView(null !, null !, {data: []});
currentView = createLView(null !, null !, createTView());
let currentQuery: LQuery|null;
let currentQueries: LQueries|null;
/**
* This property gets set before entering a template.
@ -112,10 +95,11 @@ let data: any[];
let bindingIndex: number;
/**
* When a view is destroyed, listeners need to be released
* and onDestroy callbacks need to be called. This cleanup array
* stores both listener data (in chunks of 4) and onDestroy data
* (in chunks of 2), as they'll be processed at the same time.
* When a view is destroyed, listeners need to be released and outputs need to be
* unsubscribed. This cleanup array stores both listener data (in chunks of 4)
* and output data (in chunks of 2) for a particular view. Combining the arrays
* saves on memory (70 bytes per array) and on a few bytes of code size (for two
* separate for loops).
*
* If it's a listener being stored:
* 1st index is: event name to remove
@ -123,15 +107,12 @@ let bindingIndex: number;
* 3rd index is: listener function
* 4th index is: useCapture boolean
*
* If it's an onDestroy function:
* 1st index is: onDestroy function
* If it's an output subscription:
* 1st index is: unsubscribe function
* 2nd index is: context for function
*/
let cleanup: any[]|null;
/** Index in the data array at which view hooks begin to be stored. */
let viewHookStartIndex: number|null;
/**
* Swap the current state with a new state.
*
@ -151,7 +132,6 @@ export function enterView(newView: LView, host: LElementNode | LViewNode | null)
tData = newView.tView.data;
creationMode = newView.creationMode;
viewHookStartIndex = newView.viewHookStartIndex;
cleanup = newView.cleanup;
renderer = newView.renderer;
@ -161,6 +141,8 @@ export function enterView(newView: LView, host: LElementNode | LViewNode | null)
}
currentView = newView;
currentQueries = newView.queries;
return oldView !;
}
@ -169,7 +151,10 @@ export function enterView(newView: LView, host: LElementNode | LViewNode | null)
* the direction of traversal (up or down the view tree) a bit clearer.
*/
export function leaveView(newView: LView): void {
executeViewHooks();
executeViewHooks(currentView);
currentView.creationMode = false;
currentView.lifecycleStage = LifecycleStage.INIT;
currentView.tView.firstTemplatePass = false;
enterView(newView, null);
}
@ -189,10 +174,11 @@ export function createLView(
next: null,
bindingStartIndex: null,
creationMode: true,
viewHookStartIndex: null,
template: template,
context: context,
dynamicViewCount: 0,
lifecycleStage: LifecycleStage.INIT,
queries: null,
};
return newView;
@ -208,19 +194,20 @@ export function createLNode(
export function createLNode(
index: null, type: LNodeFlags.View, native: null, lView: LView): LViewNode;
export function createLNode(
index: number, type: LNodeFlags.Container, native: RComment,
index: number, type: LNodeFlags.Container, native: undefined,
lContainer: LContainer): LContainerNode;
export function createLNode(
index: number, type: LNodeFlags.Projection, native: null,
lProjection: LProjection): LProjectionNode;
export function createLNode(
index: number | null, type: LNodeFlags, native: RText | RElement | RComment | null,
index: number | null, type: LNodeFlags, native: RText | RElement | null | undefined,
state?: null | LView | LContainer | LProjection): LElementNode&LTextNode&LViewNode&
LContainerNode&LProjectionNode {
const parent = isParent ? previousOrParentNode :
previousOrParentNode && previousOrParentNode.parent as LNode;
let query = (isParent ? currentQuery : previousOrParentNode && previousOrParentNode.query) ||
parent && parent.query && parent.query.child();
let queries =
(isParent ? currentQueries : previousOrParentNode && previousOrParentNode.queries) ||
parent && parent.queries && parent.queries.child();
const isState = state != null;
const node: LElementNode&LTextNode&LViewNode&LContainerNode&LProjectionNode = {
flags: type,
@ -231,8 +218,9 @@ export function createLNode(
next: null,
nodeInjector: parent ? parent.nodeInjector : null,
data: isState ? state as any : null,
query: query,
tNode: null
queries: queries,
tNode: null,
pNextOrParent: null
};
if ((type & LNodeFlags.ViewOrElement) === LNodeFlags.ViewOrElement && isState) {
@ -255,7 +243,7 @@ export function createLNode(
// Now link ourselves into the tree.
if (isParent) {
currentQuery = null;
currentQueries = null;
if (previousOrParentNode.view === currentView ||
(previousOrParentNode.flags & LNodeFlags.TYPE_MASK) === LNodeFlags.View) {
// We are in the same view, which means we are adding content node to the parent View.
@ -320,7 +308,7 @@ export function renderEmbeddedTemplate<T>(
previousOrParentNode = null !;
let cm: boolean = false;
if (viewNode == null) {
const view = createLView(-1, renderer, {data: []}, template, context);
const view = createLView(-1, renderer, createTView(), template, context);
viewNode = createLNode(null, LNodeFlags.View, null, view);
cm = true;
}
@ -347,14 +335,13 @@ export function renderComponentOrTemplate<T>(
template(componentOrContext !, creationMode);
} else {
// Element was stored at 0 and directive was stored at 1 in renderComponent
// so to refresh the component, r() needs to be called with (1, 0)
(componentOrContext.constructor as ComponentType<T>).ngComponentDef.r(1, 0);
// so to refresh the component, refresh() needs to be called with (1, 0)
componentRefresh(1, 0);
}
} finally {
if (rendererFactory.end) {
rendererFactory.end();
}
hostView.creationMode = false;
leaveView(oldView);
}
}
@ -430,8 +417,6 @@ export function elementStart(
if (hostComponentDef) {
// TODO(mhevery): This assumes that the directives come in correct order, which
// is not guaranteed. Must be refactored to take it into account.
(hostComponentDef as TypedComponentDef<any>).type =
nameOrComponentType as ComponentType<any>;
directiveCreate(++index, hostComponentDef.n(), hostComponentDef, queryName);
}
hack_declareDirectives(index, directiveTypes, localRefs);
@ -459,7 +444,6 @@ function hack_declareDirectives(
// TODO(misko): refactor this to store the `DirectiveDef` in `TView.data`.
const directiveType = directiveTypes[i];
const directiveDef = directiveType.ngDirectiveDef;
(directiveDef as TypedDirectiveDef<any>).type = directiveType;
directiveCreate(
++index, directiveDef.n(), directiveDef, hack_findQueryName(directiveDef, localRefs));
}
@ -494,7 +478,19 @@ function hack_findQueryName(
* @returns TView
*/
function getOrCreateTView(template: ComponentTemplate<any>): TView {
return template.ngPrivateData || (template.ngPrivateData = { data: [] } as never);
return template.ngPrivateData || (template.ngPrivateData = createTView() as never);
}
/** Creates a TView instance */
export function createTView(): TView {
return {
data: [],
firstTemplatePass: true,
initHooks: null,
contentHooks: null,
viewHooks: null,
destroyHooks: null
};
}
function setUpAttributes(native: RElement, attrs: string[]): void {
@ -611,8 +607,9 @@ export function elementEnd() {
previousOrParentNode = previousOrParentNode.parent !;
}
ngDevMode && assertNodeType(previousOrParentNode, LNodeFlags.Element);
const query = previousOrParentNode.query;
query && query.addNode(previousOrParentNode);
const queries = previousOrParentNode.queries;
queries && queries.addNode(previousOrParentNode);
queueLifecycleHooks(previousOrParentNode.flags, currentView);
}
/**
@ -831,23 +828,22 @@ export function text(index: number, value?: any): void {
* @param value Stringified value to write.
*/
export function textBinding<T>(index: number, value: T | NO_CHANGE): void {
// TODO(misko): I don't think index < nodes.length check is needed here.
let existingNode = index < data.length && data[index] as LTextNode;
if (existingNode && existingNode.native) {
ngDevMode && assertDataInRange(index);
let existingNode = data[index] as LTextNode;
ngDevMode && assertNotNull(existingNode, 'existing node');
if (existingNode.native) {
// If DOM node exists and value changed, update textContent
value !== NO_CHANGE &&
((renderer as ProceduralRenderer3).setValue ?
(renderer as ProceduralRenderer3).setValue(existingNode.native, stringify(value)) :
existingNode.native.textContent = stringify(value));
} else if (existingNode) {
} else {
// Node was created but DOM node creation was delayed. Create and append now.
existingNode.native =
((renderer as ProceduralRenderer3).createText ?
(renderer as ProceduralRenderer3).createText(stringify(value)) :
(renderer as ObjectOrientedRenderer3).createTextNode !(stringify(value)));
insertChild(existingNode, currentView);
} else {
text(index, value);
}
}
@ -906,6 +902,11 @@ export function directiveCreate<T>(
if (tNode && tNode.attrs) {
setInputsFromAttrs<T>(instance, directiveDef !.inputs, tNode);
}
// Init hooks are queued now so ngOnInit is called in host components before
// any projected components.
queueInitHooks(index, directiveDef.onInit, directiveDef.doCheck, currentView.tView);
return instance;
}
@ -966,76 +967,6 @@ function generateInitialInputs(
return initialInputData;
}
/**
* Accepts a lifecycle hook type and determines when and how the related lifecycle hook
* callback should run.
*
* For the onInit lifecycle hook, it will return whether or not the ngOnInit() function
* should run. If so, ngOnInit() will be called outside of this function.
*
* e.g. l(LifecycleHook.ON_INIT) && ctx.ngOnInit();
*
* For the onDestroy lifecycle hook, this instruction also accepts an onDestroy
* method that should be stored and called internally when the parent view is being
* cleaned up.
*
* e.g. l(LifecycleHook.ON_DESTROY, ctx, ctx.onDestroy);
*
* @param lifecycle
* @param self
* @param method
*/
export function lifecycle(lifecycle: LifecycleHook.ON_DESTROY, self: any, method: Function): void;
export function lifecycle(
lifecycle: LifecycleHook.AFTER_VIEW_INIT, self: any, method: Function): void;
export function lifecycle(
lifecycle: LifecycleHook.AFTER_VIEW_CHECKED, self: any, method: Function): void;
export function lifecycle(lifecycle: LifecycleHook): boolean;
export function lifecycle(lifecycle: LifecycleHook, self?: any, method?: Function): boolean {
if (lifecycle === LifecycleHook.ON_INIT) {
return creationMode;
} else if (lifecycle === LifecycleHook.ON_DESTROY) {
(cleanup || (currentView.cleanup = cleanup = [])).push(method, self);
} else if (
creationMode && (lifecycle === LifecycleHook.AFTER_VIEW_INIT ||
lifecycle === LifecycleHook.AFTER_VIEW_CHECKED)) {
if (viewHookStartIndex == null) {
currentView.viewHookStartIndex = viewHookStartIndex = data.length;
}
data.push(lifecycle, method, self);
}
return false;
}
/** Iterates over view hook functions and calls them. */
export function executeViewHooks(): void {
if (viewHookStartIndex == null) return;
// Instead of using splice to remove init hooks after their first run (expensive), we
// shift over the AFTER_CHECKED hooks as we call them and truncate once at the end.
let checkIndex = viewHookStartIndex as number;
let writeIndex = checkIndex;
while (checkIndex < data.length) {
// Call lifecycle hook with its context
data[checkIndex + 1].call(data[checkIndex + 2]);
if (data[checkIndex] === LifecycleHook.AFTER_VIEW_CHECKED) {
// We know if the writeIndex falls behind that there is an init that needs to
// be overwritten.
if (writeIndex < checkIndex) {
data[writeIndex] = data[checkIndex];
data[writeIndex + 1] = data[checkIndex + 1];
data[writeIndex + 2] = data[checkIndex + 2];
}
writeIndex += 3;
}
checkIndex += 3;
}
// Truncate once at the writeIndex
data.length = writeIndex;
}
//////////////////////////
//// ViewContainer & View
@ -1057,28 +988,23 @@ export function container(
tagName?: string, attrs?: string[], localRefs?: string[] | null): void {
ngDevMode && assertEqual(currentView.bindingStartIndex, null, 'bindingStartIndex');
// If the direct parent of the container is a view, its views (including its comment)
// will need to be added through insertView() when its parent view is being inserted.
// For now, it is marked "headless" so we know to append its views later.
let comment = renderer.createComment(ngDevMode ? 'container' : '');
let renderParent: LElementNode|null = null;
const currentParent = isParent ? previousOrParentNode : previousOrParentNode.parent !;
ngDevMode && assertNotEqual(currentParent, null, 'currentParent');
if (appendChild(currentParent, comment, currentView)) {
// we are adding to an Element which is either:
// - Not a component (will not be re-projected, just added)
// - View of the Component
renderParent = currentParent as LElementNode;
}
const node = createLNode(index, LNodeFlags.Container, comment, <LContainer>{
const lContainer = <LContainer>{
views: [],
nextIndex: 0, renderParent,
nextIndex: 0,
// If the direct parent of the container is a view, its views will need to be added
// through insertView() when its parent view is being inserted:
renderParent: canInsertNativeNode(currentParent, currentView) ? currentParent : null,
template: template == null ? null : template,
next: null,
parent: currentView,
dynamicViewCount: 0,
});
queries: null
};
const node = createLNode(index, LNodeFlags.Container, undefined, lContainer);
if (node.tNode == null) {
// TODO(misko): implement queryName caching
@ -1093,8 +1019,13 @@ export function container(
isParent = false;
ngDevMode && assertNodeType(previousOrParentNode, LNodeFlags.Container);
const query = previousOrParentNode.query;
query && query.addNode(previousOrParentNode);
const queries = node.queries;
if (queries) {
// check if a given container node matches
queries.addNode(node);
// prepare place for matching nodes from views inserted into a given container
lContainer.queries = queries.container();
}
}
/**
@ -1108,6 +1039,13 @@ export function containerRefreshStart(index: number): void {
ngDevMode && assertNodeType(previousOrParentNode, LNodeFlags.Container);
isParent = true;
(previousOrParentNode as LContainerNode).data.nextIndex = 0;
ngDevMode && assertEqual(
(previousOrParentNode as LContainerNode).native === undefined, true,
'previousOrParentNode.native === undefined');
// We need to execute init hooks here so ngOnInit hooks are called in top level views
// before they are called in embedded views (for backwards compatibility).
executeInitHooks(currentView);
}
/**
@ -1125,6 +1063,7 @@ export function containerRefreshEnd(): void {
}
ngDevMode && assertNodeType(previousOrParentNode, LNodeFlags.Container);
const container = previousOrParentNode as LContainerNode;
container.native = undefined;
ngDevMode && assertNodeType(container, LNodeFlags.Container);
const nextIndex = container.data.nextIndex;
while (nextIndex < container.data.views.length) {
@ -1171,6 +1110,10 @@ export function viewStart(viewBlockId: number): boolean {
// When we create a new LView, we always reset the state of the instructions.
const newView =
createLView(viewBlockId, renderer, getOrCreateEmbeddedTView(viewBlockId, container));
if (lContainer.queries) {
newView.queries = lContainer.queries.enterView(lContainer.nextIndex);
}
enterView(newView, createLNode(null, LNodeFlags.View, null, newView));
lContainer.nextIndex++;
}
@ -1194,7 +1137,7 @@ function getOrCreateEmbeddedTView(viewIndex: number, parent: LContainerNode): TV
ngDevMode && assertNodeType(parent, LNodeFlags.Container);
const tContainer = (parent !.tNode as TContainerNode).data;
if (viewIndex >= tContainer.length || tContainer[viewIndex] == null) {
tContainer[viewIndex] = { data: [] } as TView;
tContainer[viewIndex] = createTView();
}
return tContainer[viewIndex];
}
@ -1215,7 +1158,6 @@ export function viewEnd(): void {
if (viewIdChanged) {
insertView(container, viewNode, containerState.nextIndex - 1);
currentView.creationMode = false;
}
}
leaveView(currentView !.parent !);
@ -1232,29 +1174,29 @@ export function viewEnd(): void {
*
* @param directiveIndex
* @param elementIndex
* @param template
*/
export const componentRefresh:
<T>(directiveIndex: number, elementIndex: number, template: ComponentTemplate<T>) =>
void = function<T>(
directiveIndex: number, elementIndex: number, template: ComponentTemplate<T>) {
ngDevMode && assertDataInRange(elementIndex);
const element = data ![elementIndex] as LElementNode;
ngDevMode && assertNodeOfPossibleTypes(element, LNodeFlags.Element, LNodeFlags.Container);
ngDevMode && assertNotEqual(element.data, null, 'isComponent');
ngDevMode && assertDataInRange(directiveIndex);
const hostView = element.data !;
ngDevMode && assertNotEqual(hostView, null, 'hostView');
const directive = data[directiveIndex];
const oldView = enterView(hostView, element);
try {
template(directive, creationMode);
} finally {
hostView.creationMode = false;
refreshDynamicChildren();
leaveView(oldView);
export function componentRefresh<T>(directiveIndex: number, elementIndex: number): void {
executeInitHooks(currentView);
executeContentHooks(currentView);
const template = (tData[directiveIndex] as ComponentDef<T>).template;
if (template != null) {
ngDevMode && assertDataInRange(elementIndex);
const element = data ![elementIndex] as LElementNode;
ngDevMode && assertNodeType(element, LNodeFlags.Element);
ngDevMode && assertNotEqual(element.data, null, 'isComponent');
ngDevMode && assertDataInRange(directiveIndex);
const directive = data[directiveIndex];
const hostView = element.data !;
ngDevMode && assertNotEqual(hostView, null, 'hostView');
const oldView = enterView(hostView, element);
try {
template(directive, creationMode);
} finally {
refreshDynamicChildren();
leaveView(oldView);
}
}
};
}
/**
* Instruction to distribute projectable nodes among <ng-content> occurrences in a given template.
@ -1309,6 +1251,34 @@ export function projectionDef(index: number, selectors?: CssSelector[]): void {
data[index] = distributedNodes;
}
/**
* Updates the linked list of a projection node, by appending another linked list.
*
* @param projectionNode Projection node whose projected nodes linked list has to be updated
* @param appendedFirst First node of the linked list to append.
* @param appendedLast Last node of the linked list to append.
*/
function appendToProjectionNode(
projectionNode: LProjectionNode,
appendedFirst: LElementNode | LTextNode | LContainerNode | null,
appendedLast: LElementNode | LTextNode | LContainerNode | null) {
// appendedFirst can be null if and only if appendedLast is also null
ngDevMode &&
assertEqual(!appendedFirst === !appendedLast, true, '!appendedFirst === !appendedLast');
if (!appendedLast) {
// nothing to append
return;
}
const projectionNodeData = projectionNode.data;
if (projectionNodeData.tail) {
projectionNodeData.tail.pNextOrParent = appendedFirst;
} else {
projectionNodeData.head = appendedFirst;
}
projectionNodeData.tail = appendedLast;
appendedLast.pNextOrParent = projectionNode;
}
/**
* Inserts previously re-distributed projected nodes. This instruction must be preceded by a call
* to the projectionDef instruction.
@ -1318,8 +1288,7 @@ export function projectionDef(index: number, selectors?: CssSelector[]): void {
* @param selectorIndex - 0 means <ng-content> without any selector
*/
export function projection(nodeIndex: number, localIndex: number, selectorIndex: number = 0): void {
const projectedNodes: LProjection = [];
const node = createLNode(nodeIndex, LNodeFlags.Projection, null, projectedNodes);
const node = createLNode(nodeIndex, LNodeFlags.Projection, null, {head: null, tail: null});
isParent = false; // self closing
const currentParent = node.parent;
@ -1330,18 +1299,27 @@ export function projection(nodeIndex: number, localIndex: number, selectorIndex:
const nodesForSelector =
valueInData<LNode[][]>(componentNode.data !.data !, localIndex)[selectorIndex];
// build the linked list of projected nodes:
for (let i = 0; i < nodesForSelector.length; i++) {
const nodeToProject = nodesForSelector[i];
if ((nodeToProject.flags & LNodeFlags.TYPE_MASK) === LNodeFlags.Projection) {
const previouslyProjectedNodes = (nodeToProject as LProjectionNode).data;
for (let j = 0; j < previouslyProjectedNodes.length; j++) {
processProjectedNode(
projectedNodes, previouslyProjectedNodes[j], currentParent, currentView);
}
const previouslyProjected = (nodeToProject as LProjectionNode).data;
appendToProjectionNode(node, previouslyProjected.head, previouslyProjected.tail);
} else {
processProjectedNode(
projectedNodes, nodeToProject as LElementNode | LTextNode | LContainerNode, currentParent,
currentView);
appendToProjectionNode(
node, nodeToProject as LTextNode | LElementNode | LContainerNode,
nodeToProject as LTextNode | LElementNode | LContainerNode);
}
}
if (canInsertNativeNode(currentParent, currentView)) {
// process each node in the list of projected nodes:
let nodeToProject: LNode|null = node.data.head;
const lastNodeToProject = node.data.tail;
while (nodeToProject) {
appendProjectedNode(
nodeToProject as LTextNode | LElementNode | LContainerNode, currentParent, currentView);
nodeToProject = nodeToProject === lastNodeToProject ? null : nodeToProject.pNextOrParent;
}
}
}
@ -1868,8 +1846,8 @@ function valueInData<T>(data: any[], index: number, value?: T): T {
return value !;
}
export function getCurrentQuery(QueryType: {new (): LQuery}): LQuery {
return currentQuery || (currentQuery = new QueryType());
export function getCurrentQueries(QueryType: {new (): LQueries}): LQueries {
return currentQueries || (currentQueries = new QueryType());
}
export function getPreviousOrParentNode(): LNode {
@ -1895,4 +1873,4 @@ function assertDataInRange(index: number, arr?: any[]) {
function assertDataNext(index: number) {
assertEqual(data.length, index, 'data.length not in sequence');
}
}

View File

@ -8,9 +8,11 @@
import {ComponentTemplate} from './definition';
import {LElementNode, LViewNode} from './node';
import {LQueries} from './query';
import {LView, TView} from './view';
/** The state associated with an LContainer */
export interface LContainer {
/**
@ -67,12 +69,17 @@ export interface LContainer {
*/
readonly template: ComponentTemplate<any>|null;
/**
* A count of dynamic views rendered into this container. If this is non-zero, the `views` array
* will be traversed when refreshing dynamic views on this container.
*/
dynamicViewCount: number;
/**
* Queries active for this container - all the views inserted to / removed from
* this container are reported to queries referenced here.
*/
queries: LQueries|null;
}
/**

View File

@ -27,6 +27,9 @@ export const enum DirectiveDefFlags {ContentQuery = 0b10}
* `DirectiveDef` is a compiled version of the Directive used by the renderer instructions.
*/
export interface DirectiveDef<T> {
/** Token representing the directive. Used by DI. */
type: Type<T>;
/** Function that makes a directive public to the DI system. */
diPublic: ((def: DirectiveDef<any>) => void)|null;
@ -64,42 +67,23 @@ export interface DirectiveDef<T> {
*/
n(): T;
/**
* Refreshes the view of the component. Also calls lifecycle hooks like
* ngAfterViewInit, if they are defined on the component.
*
* NOTE: this property is short (1 char) because it is used in component
* templates which is sensitive to size.
*
* @param directiveIndex index of the directive in the containing template
* @param elementIndex index of an host element for a given directive.
*/
r(directiveIndex: number, elementIndex: number): void;
/**
* Refreshes host bindings on the associated directive. Also calls lifecycle hooks
* like ngOnInit and ngDoCheck, if they are defined on the directive.
*/
// Note: This call must be separate from r() because hooks like ngOnInit need to
// be called breadth-first across a view before processing onInits in children
// (for backwards compatibility). Child template processing thus needs to be
// delayed until all inputs and host bindings in a view have been checked.
h(directiveIndex: number, elementIndex: number): void;
/* The following are lifecycle hooks for this component */
onInit: (() => void)|null;
doCheck: (() => void)|null;
afterContentInit: (() => void)|null;
afterContentChecked: (() => void)|null;
afterViewInit: (() => void)|null;
afterViewChecked: (() => void)|null;
onDestroy: (() => void)|null;
}
export interface ComponentDef<T> extends DirectiveDef<T> {
/**
* Refreshes the view of the component. Also calls lifecycle hooks like
* ngAfterViewInit, if they are defined on the component.
*
* NOTE: this property is short (1 char) because it is used in
* component templates which is sensitive to size.
*
* @param directiveIndex index of the directive in the containing template
* @param elementIndex index of an host element for a given component.
*/
r(directiveIndex: number, elementIndex: number): void;
/**
* The tag name which should be used by the component.
*
@ -122,31 +106,20 @@ export interface ComponentDef<T> extends DirectiveDef<T> {
readonly rendererType: RendererType2|null;
}
/**
* Private: do not export
*/
export interface TypedDirectiveDef<T> extends DirectiveDef<T> { type: DirectiveType<T>; }
/**
* Private: do not export
*/
export interface TypedComponentDef<T> extends ComponentDef<T> { type: ComponentType<T>; }
export interface DirectiveDefArgs<T> {
type: Type<T>;
factory: () => T;
refresh?: (directiveIndex: number, elementIndex: number) => void;
inputs?: {[P in keyof T]?: string};
outputs?: {[P in keyof T]?: string};
methods?: {[P in keyof T]?: string};
features?: DirectiveDefFeature[];
hostBindings?: (directiveIndex: number, elementIndex: number) => void;
exportAs?: string;
}
export interface ComponentDefArgs<T> extends DirectiveDefArgs<T> {
tag: string;
template: ComponentTemplate<T>;
refresh?: (directiveIndex: number, elementIndex: number) => void;
hostBindings?: (directiveIndex: number, elementIndex: number) => void;
features?: ComponentDefFeature[];
rendererType?: RendererType2;
}

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