Compare commits
113 Commits
manughub-r
...
5.1.x
Author | SHA1 | Date | |
---|---|---|---|
96efb4b165 | |||
7c34807765 | |||
84f6b148d5 | |||
39f81b210e | |||
0602aaa06c | |||
a73b0b64fb | |||
fda3815395 | |||
4f7c13d554 | |||
4947454344 | |||
e86ce590fe | |||
1bd03a4081 | |||
8b197b24f5 | |||
8f3ea339f7 | |||
839d24e427 | |||
a1af559e16 | |||
e2cc4dbfc0 | |||
5dd2df6a58 | |||
52cb79ccb5 | |||
17e85cd9a5 | |||
8dd93f844f | |||
c809545c77 | |||
d3c0425786 | |||
088c1e3286 | |||
d79a0ba5b6 | |||
b7307c9517 | |||
cc0b0a4729 | |||
5efb751a09 | |||
b9d8ac5b2d | |||
fc217f552a | |||
d138b38bdb | |||
4f409954f8 | |||
00308fcc9f | |||
a7a7bd3ca0 | |||
67630f82b6 | |||
8006be8d8c | |||
48a1f32222 | |||
521f0d4c7d | |||
941cd102b8 | |||
66043e09a2 | |||
12702b20c7 | |||
5de91fe93e | |||
d787b55b31 | |||
3e34fa8651 | |||
8c991756fa | |||
fa0e8ef92c | |||
41abcc34f4 | |||
0aa6341e31 | |||
43377684d9 | |||
dc53248b15 | |||
d1f45002d3 | |||
6353b77f89 | |||
d9c40b7dd5 | |||
a36dfd453b | |||
ced575fd10 | |||
3b63e168e2 | |||
a1d4c2dbf1 | |||
a33182c4ee | |||
66cc2fabf1 | |||
cf8269ee94 | |||
c7241ca0e6 | |||
4a49e19bd7 | |||
4a3a74b7b0 | |||
6aa013cb63 | |||
b9531f90b8 | |||
f239e8496e | |||
57bed3fe73 | |||
c011ffae30 | |||
756dd34519 | |||
267ebf323e | |||
49c45f336e | |||
71236737ab | |||
390837f76e | |||
fbcf7dc889 | |||
5c8c7d8515 | |||
99cc591f63 | |||
e3140ae888 | |||
ca815106c9 | |||
d6da7988c0 | |||
41e1951ffb | |||
c02f97ce4e | |||
be9a7371b8 | |||
1f469497da | |||
8a5f0f7a64 | |||
8bcb093bfa | |||
abc3a1e844 | |||
9fbf850897 | |||
0c9f7b032a | |||
8b21be5da3 | |||
0a9a16183f | |||
28555bc1e7 | |||
d09d4971b3 | |||
f8a4d14c8f | |||
d713225128 | |||
5d3af4cad4 | |||
a7fe063aa5 | |||
affa54ddf9 | |||
02782c10ea | |||
8e5a3a42d6 | |||
dbef8ff2b0 | |||
c0f08be3fb | |||
f56cbcc1e5 | |||
1b86570b60 | |||
923227dec2 | |||
53b9de300b | |||
da587cb9ef | |||
e6a28054d8 | |||
69ed916b42 | |||
c3e8731145 | |||
501f01e9ac | |||
baeec4dbe2 | |||
160a154553 | |||
9dd60a5fb0 | |||
672733608b |
@ -12,8 +12,8 @@
|
||||
## IMPORTANT
|
||||
# If you change the `docker_image` version, also change the `cache_key` suffix and the version of
|
||||
# `com_github_bazelbuild_buildtools` in the `/WORKSPACE` file.
|
||||
var_1: &docker_image angular/ngcontainer:0.0.8
|
||||
var_2: &cache_key angular-{{ .Branch }}-{{ checksum "yarn.lock" }}-0.0.8
|
||||
var_1: &docker_image angular/ngcontainer:0.1.0
|
||||
var_2: &cache_key angular-{{ .Branch }}-{{ checksum "yarn.lock" }}-0.1.0
|
||||
|
||||
# Settings common to each job
|
||||
anchor_1: &job_defaults
|
||||
@ -38,7 +38,10 @@ jobs:
|
||||
# Then we don't need any exclude pattern to avoid checking those files
|
||||
- run: 'buildifier -mode=check $(find . -type f \( -name BUILD.bazel -or -name BUILD \)) ||
|
||||
(echo "BUILD files not formatted. Please run ''yarn buildifier''" ; exit 1)'
|
||||
|
||||
# Run the skylark linter to check our Bazel rules
|
||||
- run: 'find . -type f -name "*.bzl" |
|
||||
xargs java -jar /usr/local/bin/Skylint_deploy.jar ||
|
||||
(echo -e "\n.bzl files have lint errors. Please run ''yarn skylint''"; exit 1)'
|
||||
- restore_cache:
|
||||
key: *cache_key
|
||||
|
||||
@ -52,7 +55,7 @@ jobs:
|
||||
<<: *post_checkout
|
||||
- restore_cache:
|
||||
key: *cache_key
|
||||
|
||||
|
||||
- run: bazel info release
|
||||
- run: bazel run @yarn//:yarn
|
||||
# Use bazel query so that we explicitly ask for all buildable targets to be built as well
|
||||
|
@ -15,7 +15,6 @@
|
||||
# hansl - Hans Larsen
|
||||
# IgorMinar - Igor Minar
|
||||
# jasonaden - Jason Aden
|
||||
# juleskremer - Jules Kremer
|
||||
# kara - Kara Erickson
|
||||
# matsko - Matias Niemelä
|
||||
# mhevery - Misko Hevery
|
||||
@ -25,6 +24,7 @@
|
||||
# tinayuangao - Tina Gao
|
||||
# vicb - Victor Berchet
|
||||
# vikerman - Vikram Subramanian
|
||||
# wardbell - Ward Bell
|
||||
|
||||
|
||||
version: 2
|
||||
@ -35,14 +35,32 @@ group_defaults:
|
||||
enabled: true
|
||||
approve_by_comment:
|
||||
enabled: false
|
||||
# see http://docs.pullapprove.com/groups/author_approval/
|
||||
author_approval:
|
||||
# If the author is a reviewer on the PR, they will automatically have an "approved" status.
|
||||
auto: true
|
||||
|
||||
groups:
|
||||
# Require all PRs to have at least one approval from *someone*
|
||||
all:
|
||||
users: all
|
||||
required: 1
|
||||
# In this group, your self-approval does not count
|
||||
author_approval:
|
||||
auto: false
|
||||
ignored: true
|
||||
files:
|
||||
include:
|
||||
- "*"
|
||||
|
||||
root:
|
||||
conditions:
|
||||
files:
|
||||
include:
|
||||
- "*"
|
||||
exclude:
|
||||
- "WORKSPACE"
|
||||
- "BUILD.bazel"
|
||||
- ".circleci/*"
|
||||
- "aio/*"
|
||||
- "integration/*"
|
||||
@ -70,6 +88,7 @@ groups:
|
||||
- "*.bazel"
|
||||
- "*.bzl"
|
||||
- "packages/bazel/*"
|
||||
- "tools/bazel.rc"
|
||||
users:
|
||||
- alexeagle #primary
|
||||
- chuckjaz
|
||||
@ -85,6 +104,7 @@ groups:
|
||||
- "*.lock"
|
||||
- "tools/*"
|
||||
exclude:
|
||||
- "tools/bazel.rc"
|
||||
- "tools/public_api_guard/*"
|
||||
- "aio/*"
|
||||
users:
|
||||
@ -280,7 +300,7 @@ groups:
|
||||
files:
|
||||
- "packages/benchpress/*"
|
||||
users:
|
||||
# needs primary
|
||||
- alxhub # primary
|
||||
# needs secondary
|
||||
- IgorMinar #fallback
|
||||
- mhevery #fallback
|
||||
@ -308,9 +328,8 @@ groups:
|
||||
- "aio/content/navigation.json"
|
||||
- "aio/content/license.md"
|
||||
users:
|
||||
- juleskremer #primary
|
||||
- Foxandxss
|
||||
- stephenfluin
|
||||
- Foxandxss
|
||||
- petebacondarwin
|
||||
- gkalpak
|
||||
- IgorMinar #fallback
|
||||
@ -324,7 +343,6 @@ groups:
|
||||
- "aio/content/navigation.json"
|
||||
- "aio/content/license.md"
|
||||
users:
|
||||
- juleskremer #primary
|
||||
- stephenfluin
|
||||
- petebacondarwin
|
||||
- gkalpak
|
||||
|
@ -1,5 +1,7 @@
|
||||
language: node_js
|
||||
sudo: false
|
||||
# Work-around for https://github.com/travis-ci/travis-ci/issues/8836#issuecomment-356362524.
|
||||
# (Restore `sudo: false` once that is resolved.)
|
||||
sudo: required
|
||||
dist: trusty
|
||||
node_js:
|
||||
- '8.9.1'
|
||||
|
33
CHANGELOG.md
33
CHANGELOG.md
@ -1,17 +1,14 @@
|
||||
<a name="5.2.0-beta.1"></a>
|
||||
# [5.2.0-beta.1](https://github.com/angular/angular/compare/5.2.0-beta.0...5.2.0-beta.1) (2017-12-20)
|
||||
<a name="5.1.3"></a>
|
||||
## [5.1.3](https://github.com/angular/angular/compare/5.1.2...5.1.3) (2018-01-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **compiler:** generate the correct imports for summary type-check ([d91ff17](https://github.com/angular/angular/commit/d91ff17))
|
||||
* **forms:** avoid producing an error with hostBindingTypeCheck ([d213a20](https://github.com/angular/angular/commit/d213a20))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **compiler:** allow ngIf to use the ngIf expression directly as a guard ([82bcd83](https://github.com/angular/angular/commit/82bcd83))
|
||||
* **router:** add "paramsInheritanceStrategy" router configuration option ([5efea2f](https://github.com/angular/angular/commit/5efea2f)), closes [#20572](https://github.com/angular/angular/issues/20572)
|
||||
* **animations:** avoid infinite loop with multiple blocked sub triggers ([#21119](https://github.com/angular/angular/issues/21119)) ([3e34fa8](https://github.com/angular/angular/commit/3e34fa8))
|
||||
* **animations:** renaming issue with DOMAnimation. ([#21125](https://github.com/angular/angular/issues/21125)) ([d1f4500](https://github.com/angular/angular/commit/d1f4500))
|
||||
* **common:** handle JS floating point errors in percent pipe ([#20329](https://github.com/angular/angular/issues/20329)) ([fa0e8ef](https://github.com/angular/angular/commit/fa0e8ef)), closes [#20136](https://github.com/angular/angular/issues/20136)
|
||||
* **language-service:** ignore null metadatas ([#20557](https://github.com/angular/angular/issues/20557)) ([48a1f32](https://github.com/angular/angular/commit/48a1f32)), closes [#20260](https://github.com/angular/angular/issues/20260)
|
||||
* **router:** fix wildcard route with lazy loaded module (again) ([#18139](https://github.com/angular/angular/issues/18139)) ([8c99175](https://github.com/angular/angular/commit/8c99175)), closes [#13848](https://github.com/angular/angular/issues/13848)
|
||||
|
||||
|
||||
|
||||
@ -31,20 +28,6 @@
|
||||
|
||||
|
||||
|
||||
<a name="5.2.0-beta.0"></a>
|
||||
# [5.2.0-beta.0](https://github.com/angular/angular/compare/5.1.0...5.2.0-beta.0) (2017-12-13)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **animations:** re-introduce support for transition matching functions ([#20723](https://github.com/angular/angular/issues/20723)) ([590d93b](https://github.com/angular/angular/commit/590d93b)), closes [#18959](https://github.com/angular/angular/issues/18959)
|
||||
* **compiler:** add a pseudo $any() function to disable type checking ([#20876](https://github.com/angular/angular/issues/20876)) ([70cd124](https://github.com/angular/angular/commit/70cd124))
|
||||
* **compiler:** narrow types of expressions used in *ngIf ([#20702](https://github.com/angular/angular/issues/20702)) ([e7d9cb3](https://github.com/angular/angular/commit/e7d9cb3))
|
||||
* **core:** add source to `StaticInjectorError` message ([#20817](https://github.com/angular/angular/issues/20817)) ([b7738e1](https://github.com/angular/angular/commit/b7738e1)), closes [#19302](https://github.com/angular/angular/issues/19302)
|
||||
* **forms:** allow nulls on setAsyncValidators ([#20327](https://github.com/angular/angular/issues/20327)) ([d41d2c4](https://github.com/angular/angular/commit/d41d2c4)), closes [#20296](https://github.com/angular/angular/issues/20296)
|
||||
|
||||
|
||||
|
||||
<a name="5.1.1"></a>
|
||||
## [5.1.1](https://github.com/angular/angular/compare/5.1.0...5.1.1) (2017-12-13)
|
||||
|
||||
@ -60,7 +43,7 @@
|
||||
* **compiler-cli:** disable checkTypes in emit. ([#20828](https://github.com/angular/angular/issues/20828)) ([160a154](https://github.com/angular/angular/commit/160a154))
|
||||
* **compiler-cli:** fix swallowed Error messages ([#20846](https://github.com/angular/angular/issues/20846)) ([6727336](https://github.com/angular/angular/commit/6727336))
|
||||
* **compiler-cli:** merge [@fileoverview](https://github.com/fileoverview) comments. ([#20870](https://github.com/angular/angular/issues/20870)) ([be9a737](https://github.com/angular/angular/commit/be9a737))
|
||||
* **router:** NavigatonError and NavigationCancel should be emitted after resetting the URL ([#20803](https://github.com/angular/angular/issues/20803)) ([baeec4d](https://github.com/angular/angular/commit/baeec4d))
|
||||
* **router:** NavigationError and NavigationCancel should be emitted after resetting the URL ([#20803](https://github.com/angular/angular/issues/20803)) ([baeec4d](https://github.com/angular/angular/commit/baeec4d))
|
||||
|
||||
|
||||
|
||||
|
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2014-2017 Google, Inc. http://angular.io
|
||||
Copyright (c) 2014-2018 Google, Inc. http://angular.io
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -2,8 +2,6 @@
|
||||
[](https://circleci.com/gh/angular/angular/tree/master)
|
||||
[](https://www.browserstack.com/automate/public-build/LzF3RzBVVGt6VWE2S0hHaC9uYllOZz09LS1BVjNTclBKV0x4eVRlcjA4QVY1M0N3PT0=--eb4ce8c8dc2c1c5b2b5352d473ee12a73ac20e06)
|
||||
[](https://gitter.im/angular/angular?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
[](http://issuestats.com/github/angular/angular)
|
||||
[](http://issuestats.com/github/angular/angular)
|
||||
[](https://www.npmjs.com/@angular/core)
|
||||
|
||||
|
||||
|
12
WORKSPACE
12
WORKSPACE
@ -10,13 +10,13 @@ git_repository(
|
||||
|
||||
load("@build_bazel_rules_nodejs//:defs.bzl", "check_bazel_version", "node_repositories")
|
||||
|
||||
check_bazel_version("0.8.1")
|
||||
check_bazel_version("0.9.0")
|
||||
node_repositories(package_json = ["//:package.json"])
|
||||
|
||||
git_repository(
|
||||
name = "build_bazel_rules_typescript",
|
||||
remote = "https://github.com/bazelbuild/rules_typescript.git",
|
||||
tag = "0.6.0",
|
||||
tag = "0.6.2",
|
||||
)
|
||||
|
||||
load("@build_bazel_rules_typescript//:defs.bzl", "ts_repositories")
|
||||
@ -53,3 +53,11 @@ load("@io_bazel_rules_go//go:def.bzl", "go_rules_dependencies", "go_register_too
|
||||
go_rules_dependencies()
|
||||
|
||||
go_register_toolchains()
|
||||
|
||||
# Fetching the Bazel source code allows us to compile the Skylark linter
|
||||
http_archive(
|
||||
name = "io_bazel",
|
||||
url = "https://github.com/bazelbuild/bazel/archive/9755c72b48866ed034bd28aa033e9abd27431b1e.zip",
|
||||
strip_prefix = "bazel-9755c72b48866ed034bd28aa033e9abd27431b1e",
|
||||
sha256 = "5b8443fc3481b5fcd9e7f348e1dd93c1397f78b223623c39eb56494c55f41962",
|
||||
)
|
||||
|
@ -130,7 +130,7 @@ function tests() {
|
||||
it('can get RouterLinks from template', () => {
|
||||
expect(links.length).toBe(3, 'should have 3 links');
|
||||
expect(links[0].linkParams).toBe('/dashboard', '1st link should go to Dashboard');
|
||||
expect(links[1].linkParams).toBe('/heroes', '1st link should go to Heroes');
|
||||
expect(links[1].linkParams).toBe('/heroes', '2nd link should go to Heroes');
|
||||
});
|
||||
|
||||
it('can click Heroes link in template', () => {
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
The Angular Ahead-of-Time (AOT) compiler converts your Angular HTML and TypeScript code into efficient JavaScript code during the build phase _before_ the browser downloads and runs that code.
|
||||
|
||||
This guide explains how to build with the AOT compiler and how to write Angular metadata that AOT can compile.
|
||||
This guide explains how to build with the AOT compiler using different compiler options and how to write Angular metadata that AOT can compile.
|
||||
|
||||
<div class="l-sub-section">
|
||||
|
||||
@ -77,6 +77,174 @@ AOT compiles HTML templates and components into JavaScript files long before the
|
||||
With no templates to read and no risky client-side HTML or JavaScript evaluation,
|
||||
there are fewer opportunities for injection attacks.
|
||||
|
||||
{@a compiler-options}
|
||||
|
||||
## Angular Compiler Options
|
||||
|
||||
You can control your app compilation by providing template compiler options in the `tsconfig.json` file along with the options supplied to the TypeScript compiler. The template compiler options are specified as members of
|
||||
`"angularCompilerOptions"` object as shown below:
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"experimentalDecorators": true,
|
||||
...
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"fullTemplateTypeCheck": true,
|
||||
"preserveWhiteSpace": false,
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### *skipMetadataEmit*
|
||||
|
||||
This option tells the compiler not to produce `.metadata.json` files.
|
||||
The option is `false` by default.
|
||||
|
||||
`.metadata.json` files contain infomration needed by the template compiler from a `.ts`
|
||||
file that is not included in the `.d.ts` file produced by the TypeScript compiler. This information contains,
|
||||
for example, the content of annotations (such as a component's template) which TypeScript
|
||||
emits to the `.js` file but not to the `.d.ts` file.
|
||||
|
||||
This option should be set to `true` if using TypeScript's `--outFile` option, as the metadata files
|
||||
are not valid for this style of TypeScript output. It is not recommeded to use `--outFile` with
|
||||
Angular. Use a bundler, such as [webpack](https://webpack.js.org/), instead.
|
||||
|
||||
This option can also be set to `true` when using factory summaries as the factory summaries
|
||||
include a copy of the information that is in the `.metadata.json` file.
|
||||
|
||||
### *strictMetadataEmit*
|
||||
|
||||
This option tells the template compiler to report an error to the `.metadata.json`
|
||||
file if `"skipMetadataEmit"` is `false` . This option is `false` by default. This should only be used when `"skipMetadataEmit"` is `false` and `"skipTemplateCodeGen"` is `true`.
|
||||
|
||||
It is intended to validate the `.metadata.json` files emitted for bundling with an `npm` package. The validation is overly strict and can emit errors for metadata that would never produce an error when used by the template compiler. You can choose to suppress the error emitted by this option for an exported symbol by including `@dynamic` in the comment documenting the symbol.
|
||||
|
||||
It is valid for `.metadata.json` files to contain errors. The template compiler reports these errors
|
||||
if the metadata is used to determine the contents of an annotation. The metadata
|
||||
collector cannot predict the symbols that are designed to use in an annotation, so it will preemptively
|
||||
include error nodes in the metadata for the exported symbols. The template compiler can then use the error
|
||||
nodes to report an error if these symbols are used. If the client of a library intends to use a symbol in an annotation, the template compiler will not normally report
|
||||
this until the client uses the symbol. This option allows detecting these errors during the build phase of
|
||||
the library and is used, for example, in producing Angular libraries themselves.
|
||||
|
||||
### *skipTemplateCodegen*
|
||||
|
||||
This option tells the compiler to suppress emitting `.ngfactory.js` and `.ngstyle.js` files. When set,
|
||||
this turns off most of the template compiler and disables reporting template diagnostics.
|
||||
This option can be used to instruct the
|
||||
template compiler to produce `.metadata.json` files for distribution with an `npm` package while
|
||||
avoiding the production of `.ngfactory.js` and `.ngstyle.js` files that cannot be distributed to
|
||||
`npm`.
|
||||
|
||||
### *strictInjectionParameters*
|
||||
|
||||
When set to `true`, this options tells the compiler to report an error for a parameter supplied
|
||||
whose injection type cannot be determined. When this value option is not provided or is `false`, constructor parameters of classes marked with `@Injectable` whose type cannot be resolved will
|
||||
produce a warning.
|
||||
|
||||
*Note*: It is recommended to change this option explicitly to `true` as this option will default to `true` in the future.
|
||||
|
||||
### *flatModuleOutFile*
|
||||
|
||||
When set to `true`, this option tells the template compiler to generate a flat module
|
||||
index of the given file name and the corresponding flat module metadata. Use this option when creating
|
||||
flat modules that are packaged similarly to `@angular/core` and `@angular/common`. When this option
|
||||
is used, the `package.json` for the library should refer
|
||||
to the generated flat module index instead of the library index file. With this
|
||||
option only one `.metadata.json` file is produced that contains all the metadata necessary
|
||||
for symbols exported from the library index. In the generated `.ngfactory.js` files, the flat
|
||||
module index is used to import symbols that includes both the public API from the library index
|
||||
as well as shrowded internal symbols.
|
||||
|
||||
By default the `.ts` file supplied in the `files` field is assumed to be library index.
|
||||
If more than one `.ts` file is specified, `libraryIndex` is used to select the file to use.
|
||||
If more than one `.ts` file is supplied without a `libraryIndex`, an error is produced. A flat module
|
||||
index `.d.ts` and `.js` will be created with the given `flatModuleOutFile` name in the same
|
||||
location as the library index `.d.ts` file. For example, if a library uses
|
||||
`public_api.ts` file as the library index of the module, the `tsconfig.json` `files` field
|
||||
would be `["public_api.ts"]`. The `flatModuleOutFile` options could then be set to, for
|
||||
example `"index.js"`, which produces `index.d.ts` and `index.metadata.json` files. The
|
||||
library's `package.json`'s `module` field would be `"index.js"` and the `typings` field
|
||||
would be `"index.d.ts"`.
|
||||
|
||||
### *flatModuleId*
|
||||
|
||||
This option specifies the preferred module id to use for importing a flat module.
|
||||
References generated by the template compiler will use this module name when importing symbols
|
||||
from the flat module.
|
||||
This is only meaningful when `flatModuleOutFile` is also supplied. Otherwise the compiler ignores
|
||||
this option.
|
||||
|
||||
### *generateCodeForLibraries*
|
||||
|
||||
This option tells the template compiler to generate factory files (`.ngfactory.js` and `.ngstyle.js`)
|
||||
for `.d.ts` files with a corresponding `.metadata.json` file. This option defaults to
|
||||
`true`. When this option is `false`, factory files are generated only for `.ts` files.
|
||||
|
||||
This option should be set to `false` when using factory summaries.
|
||||
|
||||
### *fullTemplateTypeCheck*
|
||||
|
||||
This option tells the compiler to enable the [binding expression validation](#binding-expresion-validation)
|
||||
phase of the template compiler which uses TypeScript to validate binding expressions.
|
||||
|
||||
This option is `false` by default.
|
||||
|
||||
*Note*: It is recommended to set this to `true` as this option will default to `true` in the future.
|
||||
|
||||
### *annotateForClosureCompiler*
|
||||
|
||||
This option tells the compiler to use [Tsickle](https://github.com/angular/tsickle) to annotate the emitted
|
||||
JavaScript with [JsDoc](http://usejsdoc.org/) comments needed by the
|
||||
[Closure Compiler](https://github.com/google/closure-compiler). This option defaults to `false`.
|
||||
|
||||
### *annotationsAs*
|
||||
|
||||
Use this option to modify how the Angular specific annotations are emitted to improve tree-shaking. Non-Angular
|
||||
annotations and decorators are unnaffected. Default is `static fields`.
|
||||
|
||||
value | description
|
||||
----------------|-------------------------------------------------------------
|
||||
`decorators` | Leave the Decorators in-place. This makes compilation faster. TypeScript will emit calls to the __decorate helper. Use `--emitDecoratorMetadata` for runtime reflection. However, the resulting code will not properly tree-shake.
|
||||
`static fields` | Replace decorators with a static field in the class. Allows advanced tree-shakers like [Closure Compiler](https://github.com/google/closure-compiler) to remove unused classes.
|
||||
|
||||
### *trace*
|
||||
|
||||
This tells the compiler to print extra information while compiling templates.
|
||||
|
||||
### *enableLegacyTemplate*
|
||||
|
||||
The use of `<template>` element was deprecated starting in Angular 4.0 in favor of using
|
||||
`<ng-template>` to avoid colliding with the DOM's element of the same name. Setting this option to
|
||||
`true` enables the use of the deprecated `<template>` element . This option
|
||||
is `false` by default. This option might be required by some third-party Angular libraries.
|
||||
|
||||
### *disableExpressionLowering*
|
||||
|
||||
The Angular template compiler transforms code that is used, or could be used, in an annotation
|
||||
to allow it to be imported from template factory modules. See
|
||||
[metadata rewriting](#metadata-rewriting) for more information.
|
||||
|
||||
Setting this option to `false` disables this rewriting, requiring the rewriting to be
|
||||
done manually.
|
||||
|
||||
### *preserveWhitespaces*
|
||||
|
||||
This option tells the compiler whether to remove blank text nodes from compiled templates.
|
||||
This option is `true` by default.
|
||||
|
||||
*Note*: It is recommended to set this explicitly to `false` as it emits smaller template factory modules and might be set to `false` by default in the future.
|
||||
|
||||
### *allowEmptyCodegenFiles*
|
||||
|
||||
Tells the compiler to generate all the possible generated files even if they are empty. This option is
|
||||
`false` by default. This is an option used by `bazel` build rules and is needed to simplify
|
||||
how `bazel` rules track file dependencies. It is not recommended to use this option outside of the `bazel`
|
||||
rules.
|
||||
|
||||
## Angular Metadata and AOT
|
||||
|
||||
The Angular **AOT compiler** extracts and interprets **metadata** about the parts of the application that Angular is supposed to manage.
|
||||
@ -212,6 +380,7 @@ export function serverFactory() {
|
||||
|
||||
Beginning in version 5, the compiler automatically performs this rewritting while emitting the `.js` file.
|
||||
|
||||
{@a function-calls}
|
||||
### Limited function calls
|
||||
|
||||
The _collector_ can represent a function call or object creation with `new` as long as the syntax is valid. The _collector_ only cares about proper syntax.
|
||||
@ -411,6 +580,7 @@ The Angular [`RouterModule`](api/router/RouterModule) exports two macro static m
|
||||
Review the [source code](https://github.com/angular/angular/blob/master/packages/router/src/router_module.ts#L139 "RouterModule.forRoot source code")
|
||||
for these methods to see how macros can simplify configuration of complex [NgModules](guide/ngmodule).
|
||||
|
||||
{@ metadata-rewriting}
|
||||
### Metadata rewriting
|
||||
|
||||
The compiler treats object literals containing the fields `useClass`, `useValue`, `useFactory`, and `data` specially. The compiler converts the expression initializing one of these fields into an exported variable, which replaces the expression. This process of rewriting these expressions removes all the restrictions on what can be in them because
|
||||
@ -961,7 +1131,155 @@ This error can occur if you use an expression in the `extends` clause of a class
|
||||
Chuck: After reviewing your PR comment I'm still at a loss. See [comment there](https://github.com/angular/angular/pull/17712#discussion_r132025495).
|
||||
|
||||
-->
|
||||
{@a binding-expresion-validation}
|
||||
|
||||
## Phase 3: binding expression validation
|
||||
|
||||
In the validation phase, the Angular template compiler uses the TypeScript compiler to validate the
|
||||
binding expressions in templates. Enable this phase explicity by adding the compiler
|
||||
option `"fullTemplateTypeCheck"` in the `"angularCompilerOptions"` of the project's `tsconfig.json` (see
|
||||
[Angular Compiler Options](#compiler-options)).
|
||||
|
||||
Template validation produces error messages when a type error is detected in a template binding
|
||||
expression, similar to how type errors are reported by the TypeScript compiler against code in a `.ts`
|
||||
file.
|
||||
|
||||
For example, consider the following component:
|
||||
|
||||
```ts
|
||||
@Component({
|
||||
selector: 'my-component',
|
||||
template: '{{person.addresss.street}}'
|
||||
})
|
||||
class MyComponent {
|
||||
person?: Person;
|
||||
}
|
||||
```
|
||||
|
||||
This will produce the following error:
|
||||
|
||||
```
|
||||
my.component.ts.MyComponent.html(1,1): : Property 'addresss' does not exist on type 'Person'. Did you mean 'address'?
|
||||
```
|
||||
|
||||
The file name reported in the error message, `my.component.ts.MyComponent.html`, is a synthetic file
|
||||
generated by the template compiler that holds contents of the `MyComponent` class template.
|
||||
Compiler never writes this file to disk. The line and column numbers are relative to the template string
|
||||
in the `@Component` annotation of the class, `MyComponent` in this case. If a component uses
|
||||
`templateUrl` instead of `template`, the errors are reported in the HTML file refereneced by the
|
||||
`templateUrl` instead of a synthetic file.
|
||||
|
||||
The error location is the beginning of the text node that contains the interpolation expression with
|
||||
the error. If the error is in an attribute binding such as `[value]="person.address.street"`, the error
|
||||
location is the location of the attribute that contains the error.
|
||||
|
||||
The validation uses the TypeScript type checker and the options supplied to the TypeScript compiler to control
|
||||
how detailed the type validation is. For example, if the `strictTypeChecks` is specified, the error ```my.component.ts.MyComponent.html(1,1): : Object is possibly 'undefined'``` is reported as well as the above error message.
|
||||
|
||||
### Type narrowing
|
||||
|
||||
The expression used in an `ngIf` directive is used to narrow type unions in the Angular
|
||||
template compiler, the same way the `if` expression does in TypeScript. For example, to avoid
|
||||
`Object is possibly 'undefined'` error in the template above, modify it to only emit the
|
||||
interpolation if the value of `person` is initialized as shown below:
|
||||
|
||||
```ts
|
||||
@Component({
|
||||
selector: 'my-component',
|
||||
template: '<span *ngIf="person"> {{person.addresss.street}} </span>'
|
||||
})
|
||||
class MyComponent {
|
||||
person?: Person;
|
||||
}
|
||||
```
|
||||
|
||||
Using `*ngIf` allows the TypeScript compiler to infer that the `person` used in the
|
||||
binding expression will never be `undefined`.
|
||||
|
||||
#### Custom `ngIf` like directives
|
||||
|
||||
Directives that behave like `*ngIf` can declare that they want the same treatment by including
|
||||
a static member marker that is a signal to the template compiler to treat them
|
||||
like `*ngIf`. This static member for `*ngIf` is:
|
||||
|
||||
```ts
|
||||
public static ngIfUseIfTypeGuard: void;
|
||||
```
|
||||
|
||||
This declares that the input property `ngIf` of the `NgIf` directive should be treated as a
|
||||
guard to the use of its template, implying that the template will only be instantiated if
|
||||
the `ngIf` input property is true.
|
||||
|
||||
|
||||
### Non-null type assertion operator
|
||||
|
||||
Use the [non-null type assertion operator](guide/template-syntax#non-null-assertion-operator)
|
||||
to suppress the `Object is possibly 'undefined'` error when it is incovienent to use
|
||||
`*ngIf` or when some constraint in the component ensures that the expression is always
|
||||
non-null when the binding expression is interpolated.
|
||||
|
||||
In the following example, the `person` and `address` properties are always set together,
|
||||
implying that `address` is always non-null if `person` is non-null. There is no convenient
|
||||
way to describe this constraint to TypeScript and the template compiler, but the error
|
||||
is suppressed in the example by using `address!.street`.
|
||||
|
||||
```ts
|
||||
@Component({
|
||||
selector: 'my-component',
|
||||
template: '<span *ngIf="person"> {{person.name}} lives on {{address!.street}} </span>'
|
||||
})
|
||||
class MyComponent {
|
||||
person?: Person;
|
||||
address?: Address;
|
||||
|
||||
setData(person: Person, address: Address) {
|
||||
this.person = person;
|
||||
this.address = address;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The non-null assertion operator should be used sparingly as refactoring of the component
|
||||
might break this constraint.
|
||||
|
||||
In this example it is recommended to include the checking of `address`
|
||||
in the `*ngIf`as shown below:
|
||||
|
||||
```ts
|
||||
@Component({
|
||||
selector: 'my-component',
|
||||
template: '<span *ngIf="person && address"> {{person.name}} lives on {{address.street}} </span>'
|
||||
})
|
||||
class MyComponent {
|
||||
person?: Person;
|
||||
address?: Address;
|
||||
|
||||
setData(person: Person, address: Address) {
|
||||
this.person = person;
|
||||
this.address = address;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Disabling type checking using `$any()`
|
||||
|
||||
Disable checking of a binding expression by surrounding the expression
|
||||
in a call to the [`$any()` cast pseudo-function](guide/template-syntax).
|
||||
The compiler treats it as a cast to the `any` type just like in TypeScript when a `<any>`
|
||||
or `as any` cast is used.
|
||||
|
||||
In the following example, the error `Property addresss does not exist` is suppressed
|
||||
by casting `person` to the `any` type.
|
||||
|
||||
```ts
|
||||
@Component({
|
||||
selector: 'my-component',
|
||||
template: '{{$any(person).addresss.street}}'
|
||||
})
|
||||
class MyComponent {
|
||||
person?: Person;
|
||||
}
|
||||
```
|
||||
## Summary
|
||||
|
||||
* What the AOT compiler does and why it is important.
|
||||
@ -970,3 +1288,5 @@ Chuck: After reviewing your PR comment I'm still at a loss. See [comment there](
|
||||
* Other restrictions on metadata definition.
|
||||
* Macro-functions and macro-static methods.
|
||||
* Compiler errors related to metadata.
|
||||
* Validation of binding expressions
|
||||
|
||||
|
@ -371,7 +371,7 @@ and to
|
||||
|
||||
Angular developers may encounter a
|
||||
<a href="https://en.wikipedia.org/wiki/Cross-origin_resource_sharing" title="Cross-origin resource sharing">
|
||||
<i>cross-origin resource sharing</i></a> error when making a service request (typically a data service request).
|
||||
<i>cross-origin resource sharing</i></a> error when making a service request (typically a data service request)
|
||||
to a server other than the application's own host server.
|
||||
Browsers forbid such requests unless the server permits them explicitly.
|
||||
|
||||
|
@ -273,6 +273,8 @@ has a single `intercept()` method. Here is a simple interceptor which does nothi
|
||||
import {Injectable} from '@angular/core';
|
||||
import {HttpEvent, HttpInterceptor, HttpHandler, HttpRequest} from '@angular/common/http';
|
||||
|
||||
import {Observable} from 'rxjs/Observable';
|
||||
|
||||
@Injectable()
|
||||
export class NoopInterceptor implements HttpInterceptor {
|
||||
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
||||
@ -297,6 +299,8 @@ Simply declaring the `NoopInterceptor` above doesn't cause your app to use it. Y
|
||||
import {NgModule} from '@angular/core';
|
||||
import {HTTP_INTERCEPTORS} from '@angular/common/http';
|
||||
|
||||
import {NoopInterceptor} from 'noop.interceptor.ts';
|
||||
|
||||
@NgModule({
|
||||
providers: [{
|
||||
provide: HTTP_INTERCEPTORS,
|
||||
@ -547,12 +551,12 @@ In order to prevent collisions in environments where multiple Angular apps share
|
||||
|
||||
### Configuring custom cookie/header names
|
||||
|
||||
If your backend service uses different names for the XSRF token cookie or header, use `HttpClientXsrfModule.withConfig()` to override the defaults.
|
||||
If your backend service uses different names for the XSRF token cookie or header, use `HttpClientXsrfModule.withOptions()` to override the defaults.
|
||||
|
||||
```javascript
|
||||
imports: [
|
||||
HttpClientModule,
|
||||
HttpClientXsrfModule.withConfig({
|
||||
HttpClientXsrfModule.withOptions({
|
||||
cookieName: 'My-Xsrf-Cookie',
|
||||
headerName: 'My-Xsrf-Header',
|
||||
}),
|
||||
|
@ -200,8 +200,8 @@ versions are safe to use, so existing tabs continue to run from
|
||||
cache, but new loads of the app will be served from the network.
|
||||
|
||||
* `SAFE_MODE`: the service worker cannot guarantee the safety of
|
||||
using cached data. Either an unexpected error occurred or all c
|
||||
ached versions are invalid. All traffic will be served from the
|
||||
using cached data. Either an unexpected error occurred or all
|
||||
cached versions are invalid. All traffic will be served from the
|
||||
network, running as little service worker code as possible.
|
||||
|
||||
In both cases, the parenthetical annotation provides the
|
||||
|
@ -2,7 +2,7 @@
|
||||
@description
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2014-2017 Google, Inc.
|
||||
Copyright (c) 2014-2018 Google, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -121,7 +121,7 @@ Import the `HeroService` instead.
|
||||
<code-example path="toh-pt4/src/app/heroes/heroes.component.ts" title="src/app/heroes/heroes.component.ts (import HeroService)" region="hero-service-import">
|
||||
</code-example>
|
||||
|
||||
Replace the the definition of the `heroes` property with a simple declaration.
|
||||
Replace the definition of the `heroes` property with a simple declaration.
|
||||
|
||||
<code-example path="toh-pt4/src/app/heroes/heroes.component.ts" region="heroes">
|
||||
</code-example>
|
||||
|
@ -58,6 +58,7 @@ describe('site App', function() {
|
||||
expect(page.getScrollTop()).toBeGreaterThan(0);
|
||||
|
||||
page.getNavItem(/api/i).click();
|
||||
browser.waitForAngular();
|
||||
expect(page.locationPath()).toBe('/api');
|
||||
expect(page.getScrollTop()).toBe(0);
|
||||
});
|
||||
@ -69,6 +70,7 @@ describe('site App', function() {
|
||||
expect(page.getScrollTop()).toBeGreaterThan(0);
|
||||
|
||||
page.getNavItem(/security/i).click();
|
||||
browser.waitForAngular();
|
||||
expect(page.locationPath()).toBe('/guide/security');
|
||||
expect(page.getScrollTop()).toBe(0);
|
||||
});
|
||||
|
@ -84,7 +84,7 @@
|
||||
"rxjs": "^5.5.2",
|
||||
"tslib": "^1.7.1",
|
||||
"web-animations-js": "^2.2.5",
|
||||
"zone.js": "0.8.16"
|
||||
"zone.js": "^0.8.19"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular/cli": "^1.6.0-rc.0",
|
||||
|
@ -4,18 +4,18 @@
|
||||
"gzip7": {
|
||||
"inline": 941,
|
||||
"main": 116124,
|
||||
"polyfills": 11860
|
||||
"polyfills": 13102
|
||||
},
|
||||
"gzip9": {
|
||||
"inline": 941,
|
||||
"main": 115954,
|
||||
"polyfills": 11858
|
||||
"polyfills": 13104
|
||||
},
|
||||
"uncompressed": {
|
||||
"inline": 1558,
|
||||
"main": 456432,
|
||||
"polyfills": 37070
|
||||
"polyfills": 40684
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -723,14 +723,14 @@ describe('AppComponent', () => {
|
||||
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should redirect to `docs` if deployment mode is `next` and not at a docs page', () => {
|
||||
it('should not redirect if deployment mode is `next`', () => {
|
||||
createTestingModule('', 'next');
|
||||
initializeTest();
|
||||
expect(TestBed.get(LocationService).replace).toHaveBeenCalledWith('docs');
|
||||
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
||||
|
||||
createTestingModule('resources', 'next');
|
||||
initializeTest();
|
||||
expect(TestBed.get(LocationService).replace).toHaveBeenCalledWith('docs');
|
||||
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
||||
|
||||
createTestingModule('guide/aot-compiler', 'next');
|
||||
initializeTest();
|
||||
@ -757,7 +757,7 @@ describe('AppComponent', () => {
|
||||
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not redirect to `docs` if deployment mode is `stable` and not at a docs page', () => {
|
||||
it('should not redirect to `docs` if deployment mode is `stable`', () => {
|
||||
createTestingModule('', 'stable');
|
||||
initializeTest();
|
||||
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
||||
|
@ -121,9 +121,9 @@ export class AppComponent implements OnInit {
|
||||
this.documentService.currentDocument.first().subscribe(doc => this.updateHostClassesForDoc(doc));
|
||||
|
||||
this.locationService.currentPath.subscribe(path => {
|
||||
// Redirect to docs if we are in not in stable mode and are not hitting a docs page
|
||||
// Redirect to docs if we are in archive mode and are not hitting a docs page
|
||||
// (i.e. we have arrived at a marketing page)
|
||||
if (this.deployment.mode !== 'stable' && !/^(docs$|api|guide|tutorial)/.test(path)) {
|
||||
if (this.deployment.mode === 'archive' && !/^(docs$|api|guide|tutorial)/.test(path)) {
|
||||
this.locationService.replace('docs');
|
||||
}
|
||||
if (path === this.currentPath) {
|
||||
|
@ -43,15 +43,15 @@ export class ApiListComponent implements OnInit {
|
||||
// API types
|
||||
types: Option[] = [
|
||||
{ value: 'all', title: 'All' },
|
||||
{ value: 'directive', title: 'Directive' },
|
||||
{ value: 'pipe', title: 'Pipe'},
|
||||
{ value: 'decorator', title: 'Decorator' },
|
||||
{ value: 'class', title: 'Class' },
|
||||
{ value: 'interface', title: 'Interface' },
|
||||
{ value: 'function', title: 'Function' },
|
||||
{ value: 'const', title: 'Const' },
|
||||
{ value: 'decorator', title: 'Decorator' },
|
||||
{ value: 'directive', title: 'Directive' },
|
||||
{ value: 'enum', title: 'Enum' },
|
||||
{ value: 'type-alias', title: 'Type Alias' },
|
||||
{ value: 'const', title: 'Const'}
|
||||
{ value: 'function', title: 'Function' },
|
||||
{ value: 'interface', title: 'Interface' },
|
||||
{ value: 'pipe', title: 'Pipe' },
|
||||
{ value: 'type-alias', title: 'Type Alias' }
|
||||
];
|
||||
|
||||
statuses: Option[] = [
|
||||
|
@ -536,7 +536,7 @@ describe('DocViewerComponent', () => {
|
||||
expect(swapViewsSpy).not.toHaveBeenCalled();
|
||||
expect(docViewer.nextViewContainer.innerHTML).toBe('');
|
||||
expect(logger.output.error).toEqual([
|
||||
['[DocViewer]: Error preparing document \'foo\'.', error],
|
||||
[`[DocViewer] Error preparing document 'foo': ${error.stack}`],
|
||||
]);
|
||||
});
|
||||
|
||||
@ -555,7 +555,7 @@ describe('DocViewerComponent', () => {
|
||||
expect(swapViewsSpy).not.toHaveBeenCalled();
|
||||
expect(docViewer.nextViewContainer.innerHTML).toBe('');
|
||||
expect(logger.output.error).toEqual([
|
||||
['[DocViewer]: Error preparing document \'bar\'.', error],
|
||||
[`[DocViewer] Error preparing document 'bar': ${error.stack}`],
|
||||
]);
|
||||
});
|
||||
|
||||
@ -574,7 +574,7 @@ describe('DocViewerComponent', () => {
|
||||
expect(swapViewsSpy).not.toHaveBeenCalled();
|
||||
expect(docViewer.nextViewContainer.innerHTML).toBe('');
|
||||
expect(logger.output.error).toEqual([
|
||||
['[DocViewer]: Error preparing document \'baz\'.', error],
|
||||
[`[DocViewer] Error preparing document 'baz': ${error.stack}`],
|
||||
]);
|
||||
});
|
||||
|
||||
@ -593,7 +593,23 @@ describe('DocViewerComponent', () => {
|
||||
expect(swapViewsSpy).toHaveBeenCalledTimes(1);
|
||||
expect(docViewer.nextViewContainer.innerHTML).toBe('');
|
||||
expect(logger.output.error).toEqual([
|
||||
['[DocViewer]: Error preparing document \'qux\'.', error],
|
||||
[`[DocViewer] Error preparing document 'qux': ${error.stack}`],
|
||||
]);
|
||||
});
|
||||
|
||||
it('when something fails with non-Error', async () => {
|
||||
const error = 'Typical string error';
|
||||
swapViewsSpy.and.callFake(() => {
|
||||
expect(docViewer.nextViewContainer.innerHTML).not.toBe('');
|
||||
throw error;
|
||||
});
|
||||
|
||||
await doRender('Some content', 'qux');
|
||||
|
||||
expect(swapViewsSpy).toHaveBeenCalledTimes(1);
|
||||
expect(docViewer.nextViewContainer.innerHTML).toBe('');
|
||||
expect(logger.output.error).toEqual([
|
||||
[`[DocViewer] Error preparing document 'qux': ${error}`],
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
@ -153,8 +153,9 @@ export class DocViewerComponent implements DoCheck, OnDestroy {
|
||||
.switchMap(() => this.swapViews(addTitleAndToc))
|
||||
.do(() => this.docRendered.emit())
|
||||
.catch(err => {
|
||||
const errorMessage = (err instanceof Error) ? err.stack : err;
|
||||
this.logger.error(`[DocViewer] Error preparing document '${doc.id}': ${errorMessage}`);
|
||||
this.nextViewContainer.innerHTML = '';
|
||||
this.logger.error(`[DocViewer]: Error preparing document '${doc.id}'.`, err);
|
||||
return this.void$;
|
||||
});
|
||||
}
|
||||
|
@ -12,7 +12,7 @@
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Powered by Google ©2010-2017.
|
||||
Powered by Google ©2010-2018.
|
||||
Code licensed under an <a href="license" title="License text" >MIT-style License</a>.
|
||||
Documentation licensed under
|
||||
<a href="http://creativecommons.org/licenses/by/4.0/">CC BY 4.0</a>.
|
||||
|
@ -11,8 +11,9 @@ interface StringMap { [index: string]: string; }
|
||||
export function getAttrs(el: HTMLElement | ElementRef): StringMap {
|
||||
const attrs: NamedNodeMap = el instanceof ElementRef ? el.nativeElement.attributes : el.attributes;
|
||||
const attrMap = {};
|
||||
Object.keys(attrs).forEach(key =>
|
||||
attrMap[(attrs[key] as Attr).name.toLowerCase()] = (attrs[key] as Attr).value);
|
||||
for (const attr of attrs as any /* cast due to https://github.com/Microsoft/TypeScript/issues/2695 */) {
|
||||
attrMap[attr.name.toLowerCase()] = attr.value;
|
||||
}
|
||||
return attrMap;
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,11 @@ exports.config = {
|
||||
'./e2e/**/*.e2e-spec.ts'
|
||||
],
|
||||
capabilities: {
|
||||
'browserName': 'chrome'
|
||||
'browserName': 'chrome',
|
||||
// For Travis CI only
|
||||
chromeOptions: {
|
||||
binary: process.env.CHROME_BIN
|
||||
}
|
||||
},
|
||||
directConnect: true,
|
||||
baseUrl: 'http://localhost:4200/',
|
||||
|
@ -45,7 +45,7 @@ class PlunkerBuilder {
|
||||
}
|
||||
|
||||
_buildCopyrightStrings() {
|
||||
var copyright = 'Copyright 2017 Google Inc. All Rights Reserved.\n'
|
||||
var copyright = 'Copyright 2017-2018 Google Inc. All Rights Reserved.\n'
|
||||
+ 'Use of this source code is governed by an MIT-style license that\n'
|
||||
+ 'can be found in the LICENSE file at http://angular.io/license';
|
||||
var pad = '\n\n';
|
||||
@ -152,6 +152,7 @@ class PlunkerBuilder {
|
||||
// Matches main.ts or main.1.ts
|
||||
if (/^main(?:[.-]\w+)?\.ts$/.test(relativeFileName)) {
|
||||
content = fileTranslator.translate(content, mainTsRules);
|
||||
relativeFileName = 'main.ts';
|
||||
}
|
||||
|
||||
if (relativeFileName == 'systemjs.config.extras.js') {
|
||||
|
@ -1,5 +1,16 @@
|
||||
/**
|
||||
* Use this tag to ensure that dgeni does not include this code item
|
||||
* in the rendered docs.
|
||||
*
|
||||
* The `@internal` tag indicates to the compiler not to include the
|
||||
* item in the public typings file.
|
||||
* Use the `@nodoc` alias if you only want to hide the item from the
|
||||
* docs but not from the typings file.
|
||||
*/
|
||||
module.exports = function() {
|
||||
return {
|
||||
name: 'internal', transforms: function() { return true; }
|
||||
name: 'internal',
|
||||
aliases: ['nodoc'],
|
||||
transforms: function() { return true; }
|
||||
};
|
||||
};
|
||||
|
@ -9424,10 +9424,10 @@ zip-stream@~0.6.0:
|
||||
lodash "~3.10.1"
|
||||
readable-stream "~1.0.26"
|
||||
|
||||
zone.js@0.8.16:
|
||||
version "0.8.16"
|
||||
resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.8.16.tgz#ac31b6c418f88c0f918ad6acd8a402aca9313abb"
|
||||
|
||||
zone.js@^0.8.14:
|
||||
version "0.8.18"
|
||||
resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.8.18.tgz#8cecb3977fcd1b3090562ff4570e2847e752b48d"
|
||||
|
||||
zone.js@^0.8.19:
|
||||
version "0.8.19"
|
||||
resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.8.19.tgz#a4b522cd9e8b7b616a638c297d720d4c7f292f71"
|
||||
|
2
build.sh
2
build.sh
@ -206,7 +206,7 @@ minify() {
|
||||
base_file=$( basename "${file}" )
|
||||
if [[ "${base_file}" =~ $regex && "${base_file##*.}" != "map" ]]; then
|
||||
local out_file=$(dirname "${file}")/${BASH_REMATCH[1]}.min.js
|
||||
$UGLIFYJS -c --screw-ie8 --comments -o ${out_file} --source-map ${out_file}.map --source-map-include-sources ${file}
|
||||
$UGLIFYJS -c --screw-ie8 --comments -o ${out_file} --source-map ${out_file}.map --prefix relative --source-map-include-sources ${file}
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
@ -7,30 +7,11 @@ Caretaker is responsible for merging PRs into the individual branches and intern
|
||||
- Draining the queue of PRs ready to be merged. (PRs with [`PR action: merge`](https://github.com/angular/angular/pulls?q=is%3Aopen+is%3Apr+label%3A%22PR+action%3A+merge%22) label)
|
||||
- Assigining [new issues](https://github.com/angular/angular/issues?q=is%3Aopen+is%3Aissue+no%3Alabel) to individual component authors.
|
||||
|
||||
## Setup
|
||||
|
||||
### Set `upstream` to fetch PRs into your local repo
|
||||
|
||||
Use this conmmands to configure your `git` to fetch PRs into your local repo.
|
||||
|
||||
```
|
||||
git remote add upstream git@github.com:angular/angular.git
|
||||
git config --add remote.upstream.fetch +refs/pull/*/head:refs/remotes/upstream/pr/*
|
||||
```
|
||||
|
||||
|
||||
## Merging the PR
|
||||
|
||||
A PR needs to have `PR action: merge` and `PR target: *` labels to be considered
|
||||
ready to merge. Merging is performed by running `merge-pr` with a PR number to merge.
|
||||
|
||||
NOTE: before running `merge-pr` ensure that you have synced all of the PRs
|
||||
locally by running:
|
||||
|
||||
```
|
||||
$ git fetch upstream
|
||||
```
|
||||
|
||||
To merge a PR run:
|
||||
|
||||
```
|
||||
@ -40,6 +21,7 @@ $ ./scripts/github/merge-pr 1234
|
||||
The `merge-pr` script will:
|
||||
- Ensure that all approriate labels are on the PR.
|
||||
- That the current branch (`master` or `?.?.x` patch) mathches the `PR target: *` label.
|
||||
- Fetches the latest PR code from the `angular/angular` repo.
|
||||
- It will `cherry-pick` all of the SHAs from the PR into the current branch.
|
||||
- It will rewrite commit history by automatically adding `Close #1234` and `(#1234)` into the commit message.
|
||||
|
||||
@ -53,8 +35,8 @@ $ ./scripts/github/merge-pr 1234
|
||||
======================
|
||||
GitHub Merge PR Steps
|
||||
======================
|
||||
git cherry-pick upstream/pr/1234~1..upstream/pr/1234
|
||||
git filter-branch -f --msg-filter "/usr/local/google/home/misko/angular-pr/scripts/github/utils/github.closes 1234" HEAD~1..HEAD
|
||||
git cherry-pick angular/pr/1234~1..angular/pr/1234
|
||||
git filter-branch -f --msg-filter "/home/misko/angular/scripts/github/utils/github.closes 1234" HEAD~1..HEAD
|
||||
```
|
||||
|
||||
If the `cherry-pick` command fails than resolve conflicts and use `git cherry-pick --continue` once ready. After the `cherry-pick` is done cut&paste and run the `filter-branch` command to properly rewrite the messages
|
||||
|
@ -17,7 +17,7 @@ In such case, we'll update this document accordingly.
|
||||
|
||||
The dates are just a guidance and might be adjusted slightly if necessary.
|
||||
|
||||
## Tentative Schedule Until December 2017
|
||||
## Tentative Schedule Until September 2017
|
||||
|
||||
<!--
|
||||
The table below is formatted so that it's easy to read and edit in both markdown and rendered html form.
|
||||
@ -25,54 +25,43 @@ The table below is formatted so that it's easy to read and edit in both markdown
|
||||
In order to deal with undesirable line breaks, two special characters are occasionally used:
|
||||
|
||||
- non-breaking hyphen: "‑" http://www.fileformat.info/info/unicode/char/2011/index.htm
|
||||
- non-breaking space: " " http://www.fileformat.info/info/unicode/char/00a0/index.htm
|
||||
- non-breaking space: " " http://www.fileformat.info/info/unicode/char/00a0/index.htm
|
||||
|
||||
If you see undesirable wrapping issues in the rendered form, please copy&paste the quoted characters and use them in the table below where needed.
|
||||
-->
|
||||
|
||||
Week Of | Stable Release<br>(@latest npm tag) | Beta/RC Release<br>(@next npm tag) | Note
|
||||
Week Of | Stable Release<br>(@latest npm tag) | Beta/RC Release<br>(@next npm tag) | Note
|
||||
------------- | ----------------------------------- | ---------------------------------- | ---------------------
|
||||
2017‑05‑01 | 4.1.1 | 4.2.0‑beta.0 |
|
||||
2017‑05‑08 | 4.1.2 | 4.2.0‑beta.1 |
|
||||
2017‑05‑15 | 4.1.3 | 4.2.0‑rc.0 |
|
||||
2017‑05‑26 | ‑ | 4.2.0‑rc.1 |
|
||||
2017‑06‑01 | ‑ | 4.2.0‑rc.2 |
|
||||
2017‑06‑05 | 4.2.0 | ‑ | Minor Version Release
|
||||
*2017‑06‑09* | 4.2.1 | ‑ | *Regression Patch Release*
|
||||
2017‑05‑01 | 4.1.1 | 4.2.0‑beta.0 |
|
||||
2017‑05‑08 | 4.1.2 | 4.2.0‑beta.1 |
|
||||
2017‑05‑15 | 4.1.3 | 4.2.0‑rc.0 |
|
||||
2017‑05‑26 | ‑ | 4.2.0‑rc.1 |
|
||||
2017‑06‑01 | ‑ | 4.2.0‑rc.2 |
|
||||
2017‑06‑05 | 4.2.0 | ‑ | Minor Version Release
|
||||
*2017‑06‑09* | 4.2.1 | ‑ | *Regression Patch Release*
|
||||
2017-06-12 | 4.2.2 | ‑ |
|
||||
*2017-06-16* | 4.2.3 | ‑ | *Regression Patch Release*
|
||||
2017‑06‑19 | 4.2.4 | 4.3.0‑beta.0 |
|
||||
2017‑06‑26 | 4.2.5 | 4.3.0‑beta.1 |
|
||||
2017‑07‑03 | 4.2.6 | 4.3.0‑rc.0 |
|
||||
2017‑07‑10 | 4.3.0 | - | Minor Version Release
|
||||
2017‑07‑17 | 4.3.1 | 5.0.0‑beta.0 |
|
||||
2017‑07‑24 | 4.3.2 | 5.0.0‑beta.1 |
|
||||
2017‑07‑31 | 4.3.3 | 5.0.0‑beta.2 |
|
||||
2017‑08‑07 | 4.3.4 | 5.0.0‑beta.3 |
|
||||
2017‑08‑14 | 4.3.5 | 5.0.0‑beta.4 |
|
||||
2017‑08‑21 | 4.3.6 | - |
|
||||
2017‑08‑28 | - | 5.0.0‑beta.5 |
|
||||
2017‑09‑04 | - | 5.0.0‑beta.6 |
|
||||
2017‑09‑11 | 4.4.0 | 5.0.0-beta.7 |
|
||||
2017‑09‑18 | 4.4.1 | 5.0.0‑beta.8 |
|
||||
2017‑09‑25 | 4.4.2 | 5.0.0‑rc.0 |
|
||||
2017‑10‑02 | 4.4.3 | 5.0.0‑rc.1 |
|
||||
2017‑10‑09 | 4.4.4 | 5.0.0‑rc.2 |
|
||||
2017‑10‑16 | 4.4.5 | 5.0.0‑rc.3 |
|
||||
2017‑11-01 | 5.0.0 | ‑ | Major Version Release
|
||||
2017-11-08 | 5.0.1 | 5.1.0.Beta.0 | *Regression Patch Release*
|
||||
2017-11-16 | 5.0.2 | 5.1.0.Beta.1 | *Regression Patch Release*
|
||||
2017-11-22 | 5.0.3 | 5.1.0.beta.2 | *Regression Patch Release*
|
||||
2017-11-30 | 5.0.4 | 5.1.0.rc.0 |
|
||||
2017-12-01 | 5.0.5 | 5.1.0.rc.1 |
|
||||
2017-12-06 | 5.1.0 | | Minor Version Release
|
||||
2017-12-13 | 5.1.1 | 5.2.0.beta.0 |
|
||||
2017-12-20 | 5.1.2 | |
|
||||
*2017-06-16* | 4.2.3 | ‑ | *Regression Patch Release*
|
||||
2017‑06‑19 | 4.2.4 | 4.3.0‑beta.0 |
|
||||
2017‑06‑26 | 4.2.5 | 4.3.0‑beta.1 |
|
||||
2017‑07‑03 | 4.2.6 | 4.3.0‑rc.0 |
|
||||
2017‑07‑10 | 4.3.0 | - | Minor Version Release
|
||||
2017‑07‑17 | 4.3.1 | 5.0.0‑beta.0 |
|
||||
2017‑07‑24 | 4.3.2 | 5.0.0‑beta.1 |
|
||||
2017‑07‑31 | 4.3.3 | 5.0.0‑beta.2 |
|
||||
2017‑08‑07 | 4.3.4 | 5.0.0‑beta.3 |
|
||||
2017‑08‑14 | 4.3.5 | 5.0.0‑beta.4 |
|
||||
2017‑08‑21 | 4.3.6 | - |
|
||||
2017‑08‑28 | - | 5.0.0‑beta.5 |
|
||||
2017‑09‑04 | - | 5.0.0‑beta.6 |
|
||||
2017‑09‑11 | 4.4.0 | 5.0.0-beta.7 |
|
||||
2017‑09‑18 | 4.4.1 | 5.0.0‑beta.8 |
|
||||
2017‑09‑25 | 4.4.2 | 5.0.0‑rc.0 |
|
||||
2017‑10‑02 | 4.4.3 | 5.0.0‑rc.1 |
|
||||
2017‑10‑09 | 4.4.4 | 5.0.0‑rc.2 |
|
||||
2017‑10‑16 | 4.4.5 | 5.0.0‑rc.3 |
|
||||
2017‑10‑23 | 5.0.0 | ‑ | Major Version Release
|
||||
|
||||
|
||||
|
||||
|
||||
## Tentative Schedule After December 2017
|
||||
## Tentative Schedule After September 2017
|
||||
|
||||
Date | Stable Release | Compatibility`*`
|
||||
---------------------- | -------------- | ----------------
|
||||
|
@ -1,4 +1,34 @@
|
||||
{
|
||||
"cli-hello-world":{"master":{"gzip7":{"inline":847,"main":42533,"polyfills":20207},"gzip9":{"inline":847,"main":42483,"polyfills":20204},"uncompressed":{"inline":1447,"main":154295,"polyfills":61254}}},
|
||||
"hello_world__closure":{"master":{"gzip7":{"bundle":32793},"gzip9":{"bundle":32758},"uncompressed":{"bundle":100661}}}
|
||||
"cli-hello-world": {
|
||||
"master": {
|
||||
"gzip7": {
|
||||
"inline": 847,
|
||||
"main": 41943,
|
||||
"polyfills": 20207
|
||||
},
|
||||
"gzip9": {
|
||||
"inline": 847,
|
||||
"main": 41874,
|
||||
"polyfills": 20204
|
||||
},
|
||||
"uncompressed": {
|
||||
"inline": 1447,
|
||||
"main": 151849,
|
||||
"polyfills": 61254
|
||||
}
|
||||
}
|
||||
},
|
||||
"hello_world__closure": {
|
||||
"master": {
|
||||
"gzip7": {
|
||||
"bundle": 32793
|
||||
},
|
||||
"gzip9": {
|
||||
"bundle": 32758
|
||||
},
|
||||
"uncompressed": {
|
||||
"bundle": 100661
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ node_repositories(package_json = ["//:package.json"])
|
||||
git_repository(
|
||||
name = "build_bazel_rules_typescript",
|
||||
remote = "https://github.com/bazelbuild/rules_typescript.git",
|
||||
tag = "0.6.0",
|
||||
tag = "0.6.2",
|
||||
)
|
||||
|
||||
load("@build_bazel_rules_typescript//:defs.bzl", "ts_repositories")
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "angular-srcs",
|
||||
"version": "5.2.0-beta.1",
|
||||
"version": "5.1.3",
|
||||
"private": true,
|
||||
"branchPattern": "2.0.*",
|
||||
"description": "Angular - a web framework for modern web apps",
|
||||
@ -16,7 +16,10 @@
|
||||
"url": "https://github.com/angular/angular.git"
|
||||
},
|
||||
"scripts": {
|
||||
"buildifier": "bazel build @com_github_bazelbuild_buildtools//buildifier && find . -type f \\( -name BUILD -or -name BUILD.bazel \\) ! -path \"*/node_modules/*\" | xargs $(bazel info bazel-bin)/external/com_github_bazelbuild_buildtools/buildifier/buildifier",
|
||||
"preskylint": "bazel build --noshow_progress @io_bazel//src/tools/skylark/java/com/google/devtools/skylark/skylint:Skylint",
|
||||
"skylint": "find . -type f -name \"*.bzl\" ! -path \"*/node_modules/*\" ! -path \"./dist/*\" | xargs $(bazel info bazel-bin)/external/io_bazel/src/tools/skylark/java/com/google/devtools/skylark/skylint/Skylint",
|
||||
"prebuildifier": "bazel build --noshow_progress @com_github_bazelbuild_buildtools//buildifier",
|
||||
"buildifier": "find . -type f \\( -name BUILD -or -name BUILD.bazel \\) ! -path \"*/node_modules/*\" | xargs $(bazel info bazel-bin)/external/com_github_bazelbuild_buildtools/buildifier/buildifier",
|
||||
"preinstall": "node -e \"if(process.env.npm_execpath.indexOf('yarn') === -1) throw new Error('Please use Yarn instead of NPM to install dependencies. See: https://yarnpkg.com/lang/en/docs/install/')\"",
|
||||
"postinstall": "yarn update-webdriver",
|
||||
"update-webdriver": "webdriver-manager update --gecko false $CHROMEDRIVER_VERSION_ARG",
|
||||
|
@ -1393,10 +1393,10 @@ export class TransitionAnimationPlayer implements AnimationPlayer {
|
||||
|
||||
public markedForDestroy: boolean = false;
|
||||
|
||||
readonly queued: boolean = true;
|
||||
|
||||
constructor(public namespaceId: string, public triggerName: string, public element: any) {}
|
||||
|
||||
get queued() { return this._containsRealPlayer == false; }
|
||||
|
||||
setRealPlayer(player: AnimationPlayer) {
|
||||
if (this._containsRealPlayer) return;
|
||||
|
||||
@ -1407,7 +1407,6 @@ export class TransitionAnimationPlayer implements AnimationPlayer {
|
||||
});
|
||||
this._queuedCallbacks = {};
|
||||
this._containsRealPlayer = true;
|
||||
(this as{queued: boolean}).queued = false;
|
||||
}
|
||||
|
||||
getRealPlayer() { return this._player; }
|
||||
|
@ -6,7 +6,15 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
export interface DOMAnimation {
|
||||
/**
|
||||
* DOMAnimation represents the Animation Web API.
|
||||
*
|
||||
* It is an external API by the browser, and must thus use "declare interface",
|
||||
* to prevent renaming by Closure Compiler.
|
||||
*
|
||||
* @see https://developer.mozilla.org/de/docs/Web/API/Animation
|
||||
*/
|
||||
export declare interface DOMAnimation {
|
||||
cancel(): void;
|
||||
play(): void;
|
||||
pause(): void;
|
||||
|
@ -115,7 +115,7 @@ export interface AnimationStateMetadata extends AnimationMetadata {
|
||||
* @experimental Animation support is experimental.
|
||||
*/
|
||||
export interface AnimationTransitionMetadata extends AnimationMetadata {
|
||||
expr: string|((fromState: string, toState: string) => boolean);
|
||||
expr: string;
|
||||
animation: AnimationMetadata|AnimationMetadata[];
|
||||
options: AnimationOptions|null;
|
||||
}
|
||||
@ -836,8 +836,7 @@ export function keyframes(steps: AnimationStyleMetadata[]): AnimationKeyframesSe
|
||||
* @experimental Animation support is experimental.
|
||||
*/
|
||||
export function transition(
|
||||
stateChangeExpr: string | ((fromState: string, toState: string) => boolean),
|
||||
steps: AnimationMetadata | AnimationMetadata[],
|
||||
stateChangeExpr: string, steps: AnimationMetadata | AnimationMetadata[],
|
||||
options: AnimationOptions | null = null): AnimationTransitionMetadata {
|
||||
return {type: AnimationMetadataType.Transition, expr: stateChangeExpr, animation: steps, options};
|
||||
}
|
||||
|
@ -33,17 +33,17 @@ export class AnimationGroupPlayer implements AnimationPlayer {
|
||||
} else {
|
||||
this.players.forEach(player => {
|
||||
player.onDone(() => {
|
||||
if (++doneCount >= total) {
|
||||
if (++doneCount == total) {
|
||||
this._onFinish();
|
||||
}
|
||||
});
|
||||
player.onDestroy(() => {
|
||||
if (++destroyCount >= total) {
|
||||
if (++destroyCount == total) {
|
||||
this._onDestroy();
|
||||
}
|
||||
});
|
||||
player.onStart(() => {
|
||||
if (++startCount >= total) {
|
||||
if (++startCount == total) {
|
||||
this._onStart();
|
||||
}
|
||||
});
|
||||
@ -67,9 +67,9 @@ export class AnimationGroupPlayer implements AnimationPlayer {
|
||||
|
||||
private _onStart() {
|
||||
if (!this.hasStarted()) {
|
||||
this._started = true;
|
||||
this._onStartFns.forEach(fn => fn());
|
||||
this._onStartFns = [];
|
||||
this._started = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,10 @@
|
||||
# Use of this source code is governed by an MIT-style license that can be
|
||||
# found in the LICENSE file at https://angular.io/license
|
||||
""" Public API surface is re-exported here.
|
||||
|
||||
Users should not load files under "/src"
|
||||
"""
|
||||
|
||||
load("//src:ng_module.bzl", "ng_module")
|
||||
load("//src:ng_module.bzl", _ng_module = "ng_module")
|
||||
|
||||
ng_module = _ng_module
|
||||
|
@ -2,6 +2,8 @@
|
||||
#
|
||||
# Use of this source code is governed by an MIT-style license that can be
|
||||
# found in the LICENSE file at https://angular.io/license
|
||||
"""Implementation of the ng_module rule.
|
||||
"""
|
||||
|
||||
load(":rules_typescript.bzl",
|
||||
"tsc_wrapped_tsconfig",
|
||||
@ -10,20 +12,17 @@ load(":rules_typescript.bzl",
|
||||
"compile_ts",
|
||||
"DEPS_ASPECTS",
|
||||
"ts_providers_dict_to_struct",
|
||||
"json_marshal",
|
||||
)
|
||||
|
||||
# Calculate the expected output of the template compiler for every source in
|
||||
# in the library. Most of these will be produced as empty files but it is
|
||||
# unknown, without parsing, which will be empty.
|
||||
def _expected_outs(ctx, label):
|
||||
def _expected_outs(ctx):
|
||||
devmode_js_files = []
|
||||
closure_js_files = []
|
||||
declaration_files = []
|
||||
summary_files = []
|
||||
|
||||
codegen_inputs = ctx.files.srcs
|
||||
|
||||
for src in ctx.files.srcs + ctx.files.assets:
|
||||
if src.short_path.endswith(".ts") and not src.short_path.endswith(".d.ts"):
|
||||
basename = src.short_path[len(ctx.label.package) + 1:-len(".ts")]
|
||||
@ -42,6 +41,9 @@ def _expected_outs(ctx, label):
|
||||
]
|
||||
summaries = []
|
||||
|
||||
else:
|
||||
continue
|
||||
|
||||
closure_js = [f.replace(".js", ".closure.js") for f in devmode_js]
|
||||
declarations = [f.replace(".js", ".d.ts") for f in devmode_js]
|
||||
|
||||
@ -61,7 +63,7 @@ def _expected_outs(ctx, label):
|
||||
)
|
||||
|
||||
def _ngc_tsconfig(ctx, files, srcs, **kwargs):
|
||||
outs = _expected_outs(ctx, ctx.label)
|
||||
outs = _expected_outs(ctx)
|
||||
if "devmode_manifest" in kwargs:
|
||||
expected_outs = outs.devmode_js + outs.declarations + outs.summaries
|
||||
else:
|
||||
@ -79,7 +81,7 @@ def _ngc_tsconfig(ctx, files, srcs, **kwargs):
|
||||
})
|
||||
|
||||
def _collect_summaries_aspect_impl(target, ctx):
|
||||
results = target.angular.summaries if hasattr(target, "angular") else depset()
|
||||
results = depset(target.angular.summaries if hasattr(target, "angular") else [])
|
||||
|
||||
# If we are visiting empty-srcs ts_library, this is a re-export
|
||||
srcs = ctx.rule.attr.srcs if hasattr(ctx.rule.attr, "srcs") else []
|
||||
@ -88,7 +90,7 @@ def _collect_summaries_aspect_impl(target, ctx):
|
||||
if not srcs:
|
||||
for dep in ctx.rule.attr.deps:
|
||||
if (hasattr(dep, "angular")):
|
||||
results += dep.angular.summaries
|
||||
results = depset(dep.angular.summaries, transitive = [results])
|
||||
|
||||
return struct(collect_summaries_aspect_result = results)
|
||||
|
||||
@ -104,10 +106,29 @@ _EXTRA_NODE_OPTIONS_FLAGS = [
|
||||
]
|
||||
|
||||
def ngc_compile_action(ctx, label, inputs, outputs, messages_out, config_file_path,
|
||||
locale=None, i18n_args=[]):
|
||||
locale=None, i18n_args=[]):
|
||||
"""Helper function to create the ngc action.
|
||||
|
||||
This is exposed for google3 to wire up i18n replay rules, and is not intended
|
||||
as part of the public API.
|
||||
|
||||
Args:
|
||||
ctx: skylark context
|
||||
label: the label of the ng_module being compiled
|
||||
inputs: passed to the ngc action's inputs
|
||||
outputs: passed to the ngc action's outputs
|
||||
messages_out: produced xmb files
|
||||
config_file_path: path to the tsconfig file
|
||||
locale: i18n locale, or None
|
||||
i18n_args: additional command-line arguments to ngc
|
||||
|
||||
Returns:
|
||||
the parameters of the compilation which will be used to replay the ngc action for i18N.
|
||||
"""
|
||||
|
||||
mnemonic = "AngularTemplateCompile"
|
||||
progress_message = "Compiling Angular templates (ngc) %s" % label
|
||||
supports_workers = "0"
|
||||
|
||||
if locale:
|
||||
mnemonic = "AngularI18NMerging"
|
||||
supports_workers = "0"
|
||||
@ -152,8 +173,6 @@ def ngc_compile_action(ctx, label, inputs, outputs, messages_out, config_file_pa
|
||||
progress_message = "Extracting Angular 2 messages (ng_xi18n)",
|
||||
mnemonic = "Angular2MessageExtractor")
|
||||
|
||||
# Return the parameters of the compilation which will be used to replay the
|
||||
# ngc action for i18N.
|
||||
if not locale and not ctx.attr.no_i18n:
|
||||
return struct(
|
||||
label = label,
|
||||
@ -162,46 +181,68 @@ def ngc_compile_action(ctx, label, inputs, outputs, messages_out, config_file_pa
|
||||
outputs = outputs,
|
||||
)
|
||||
|
||||
return None
|
||||
|
||||
def _compile_action(ctx, inputs, outputs, messages_out, config_file_path):
|
||||
summaries = depset()
|
||||
for dep in ctx.attr.deps:
|
||||
if hasattr(dep, "collect_summaries_aspect_result"):
|
||||
summaries += dep.collect_summaries_aspect_result
|
||||
|
||||
action_inputs = inputs + summaries.to_list() + ctx.files.assets
|
||||
# print("ASSETS", [a.path for a in ctx.files.assets])
|
||||
# print("INPUTS", ctx.label, [o.path for o in summaries if o.path.find("core/src") > 0])
|
||||
# Give the Angular compiler all the user-listed assets
|
||||
file_inputs = list(ctx.files.assets)
|
||||
|
||||
# The compiler only needs to see TypeScript sources from the npm dependencies,
|
||||
# but may need to look at package.json and ngsummary.json files as well.
|
||||
if hasattr(ctx.attr, "node_modules"):
|
||||
action_inputs += [f for f in ctx.files.node_modules
|
||||
if f.path.endswith(".ts") or f.path.endswith(".json")]
|
||||
file_inputs += [f for f in ctx.files.node_modules
|
||||
if f.path.endswith(".ts") or f.path.endswith(".json")]
|
||||
|
||||
# If the user supplies a tsconfig.json file, the Angular compiler needs to read it
|
||||
if hasattr(ctx.attr, "tsconfig") and ctx.file.tsconfig:
|
||||
action_inputs += [ctx.file.tsconfig]
|
||||
file_inputs.append(ctx.file.tsconfig)
|
||||
|
||||
# Collect the inputs and summary files from our deps
|
||||
action_inputs = depset(file_inputs,
|
||||
transitive = [inputs] + [dep.collect_summaries_aspect_result for dep in ctx.attr.deps
|
||||
if hasattr(dep, "collect_summaries_aspect_result")])
|
||||
|
||||
return ngc_compile_action(ctx, ctx.label, action_inputs, outputs, messages_out, config_file_path)
|
||||
|
||||
|
||||
def _prodmode_compile_action(ctx, inputs, outputs, config_file_path):
|
||||
outs = _expected_outs(ctx, ctx.label)
|
||||
outs = _expected_outs(ctx)
|
||||
return _compile_action(ctx, inputs, outputs + outs.closure_js, outs.i18n_messages, config_file_path)
|
||||
|
||||
def _devmode_compile_action(ctx, inputs, outputs, config_file_path):
|
||||
outs = _expected_outs(ctx, ctx.label)
|
||||
outs = _expected_outs(ctx)
|
||||
_compile_action(ctx, inputs, outputs + outs.devmode_js + outs.declarations + outs.summaries, None, config_file_path)
|
||||
|
||||
def _ts_expected_outs(ctx, label):
|
||||
# rules_typescript expects a function with two arguments, but our
|
||||
# implementation doesn't use the label
|
||||
_ignored = [label]
|
||||
return _expected_outs(ctx)
|
||||
|
||||
def ng_module_impl(ctx, ts_compile_actions):
|
||||
"""Implementation function for the ng_module rule.
|
||||
|
||||
This is exposed so that google3 can have its own entry point that re-uses this
|
||||
and is not meant as a public API.
|
||||
|
||||
Args:
|
||||
ctx: the skylark rule context
|
||||
ts_compile_actions: generates all the actions to run an ngc compilation
|
||||
|
||||
Returns:
|
||||
the result of the ng_module rule as a dict, suitable for
|
||||
conversion by ts_providers_dict_to_struct
|
||||
"""
|
||||
|
||||
providers = ts_compile_actions(
|
||||
ctx, is_library=True, compile_action=_prodmode_compile_action,
|
||||
devmode_compile_action=_devmode_compile_action,
|
||||
tsc_wrapped_tsconfig=_ngc_tsconfig,
|
||||
outputs = _expected_outs)
|
||||
outputs = _ts_expected_outs)
|
||||
|
||||
#addl_declarations = [_expected_outs(ctx)]
|
||||
#providers["typescript"]["declarations"] += addl_declarations
|
||||
#providers["typescript"]["transitive_declarations"] += addl_declarations
|
||||
outs = _expected_outs(ctx, ctx.label)
|
||||
outs = _expected_outs(ctx)
|
||||
providers["angular"] = {
|
||||
"summaries": _expected_outs(ctx, ctx.label).summaries
|
||||
"summaries": _expected_outs(ctx).summaries
|
||||
}
|
||||
providers["ngc_messages"] = outs.i18n_messages
|
||||
|
||||
@ -240,7 +281,7 @@ NG_MODULE_ATTRIBUTES = {
|
||||
|
||||
ng_module = rule(
|
||||
implementation = _ng_module_impl,
|
||||
attrs = COMMON_ATTRIBUTES + NG_MODULE_ATTRIBUTES + {
|
||||
attrs = dict(dict(COMMON_ATTRIBUTES, **NG_MODULE_ATTRIBUTES), **{
|
||||
"tsconfig": attr.label(allow_files = True, single_file = True),
|
||||
|
||||
# @// is special syntax for the "main" repository
|
||||
@ -249,6 +290,6 @@ ng_module = rule(
|
||||
"node_modules": attr.label(
|
||||
default = Label("@//:node_modules")
|
||||
),
|
||||
},
|
||||
}),
|
||||
outputs = COMMON_OUTPUTS,
|
||||
)
|
||||
|
@ -27,6 +27,8 @@ const ALLOW_NON_HERMETIC_READS = true;
|
||||
// Note: We compile the content of node_modules with plain ngc command line.
|
||||
const ALL_DEPS_COMPILED_WITH_BAZEL = false;
|
||||
|
||||
const NODE_MODULES = 'node_modules/';
|
||||
|
||||
export function main(args) {
|
||||
if (runAsWorker(args)) {
|
||||
runWorkerLoop(runOneBuild);
|
||||
@ -175,7 +177,11 @@ export function compile({allowNonHermeticReads, allDepsCompiledWithBazel = true,
|
||||
ngHost.amdModuleName) {
|
||||
return ngHost.amdModuleName({ fileName: importedFilePath } as ts.SourceFile);
|
||||
}
|
||||
return relativeToRootDirs(importedFilePath, compilerOpts.rootDirs).replace(EXT, '');
|
||||
const result = relativeToRootDirs(importedFilePath, compilerOpts.rootDirs).replace(EXT, '');
|
||||
if (result.startsWith(NODE_MODULES)) {
|
||||
return result.substr(NODE_MODULES.length);
|
||||
}
|
||||
return bazelOpts.workspaceName + '/' + result;
|
||||
};
|
||||
ngHost.toSummaryFileName = (fileName: string, referringSrcFileName: string) =>
|
||||
relativeToRootDirs(fileName, compilerOpts.rootDirs).replace(EXT, '');
|
||||
|
@ -1,12 +1,26 @@
|
||||
# Allows different paths for these imports in google3
|
||||
load("@build_bazel_rules_typescript//internal:build_defs.bzl", "tsc_wrapped_tsconfig")
|
||||
"""Allows different paths for these imports in google3.
|
||||
"""
|
||||
|
||||
load("@build_bazel_rules_typescript//internal:common/compilation.bzl",
|
||||
"COMMON_ATTRIBUTES",
|
||||
"COMMON_OUTPUTS",
|
||||
"compile_ts",
|
||||
"DEPS_ASPECTS",
|
||||
"ts_providers_dict_to_struct",
|
||||
load("@build_bazel_rules_typescript//internal:build_defs.bzl",
|
||||
_tsc_wrapped_tsconfig = "tsc_wrapped_tsconfig",
|
||||
)
|
||||
|
||||
load("@build_bazel_rules_typescript//internal:common/json_marshal.bzl", "json_marshal")
|
||||
load("@build_bazel_rules_typescript//internal:common/compilation.bzl",
|
||||
_COMMON_ATTRIBUTES = "COMMON_ATTRIBUTES",
|
||||
_COMMON_OUTPUTS = "COMMON_OUTPUTS",
|
||||
_compile_ts = "compile_ts",
|
||||
_DEPS_ASPECTS = "DEPS_ASPECTS",
|
||||
_ts_providers_dict_to_struct = "ts_providers_dict_to_struct",
|
||||
)
|
||||
|
||||
load("@build_bazel_rules_typescript//internal:common/json_marshal.bzl",
|
||||
_json_marshal = "json_marshal",
|
||||
)
|
||||
|
||||
tsc_wrapped_tsconfig = _tsc_wrapped_tsconfig
|
||||
COMMON_ATTRIBUTES = _COMMON_ATTRIBUTES
|
||||
COMMON_OUTPUTS = _COMMON_OUTPUTS
|
||||
compile_ts = _compile_ts
|
||||
DEPS_ASPECTS = _DEPS_ASPECTS
|
||||
ts_providers_dict_to_struct = _ts_providers_dict_to_struct
|
||||
json_marshal = _json_marshal
|
||||
|
@ -249,6 +249,9 @@ export class PerflogMetric extends Metric {
|
||||
// not all events have been received, no further processing for now
|
||||
return null;
|
||||
}
|
||||
if (markStartEvent.pid !== markEndEvent.pid) {
|
||||
result['invalid'] = 1;
|
||||
}
|
||||
|
||||
let gcTimeInScript = 0;
|
||||
let renderTimeInScript = 0;
|
||||
|
@ -63,7 +63,12 @@ export class Sampler {
|
||||
}
|
||||
return resultPromise.then((_) => this._driver.waitFor(this._execute))
|
||||
.then((_) => this._metric.endMeasure(this._prepare === Options.NO_PREPARE))
|
||||
.then((measureValues) => this._report(lastState, measureValues));
|
||||
.then((measureValues) => {
|
||||
if (!!measureValues['invalid']) {
|
||||
return lastState;
|
||||
}
|
||||
return this._report(lastState, measureValues);
|
||||
});
|
||||
}
|
||||
|
||||
private _report(state: SampleState, metricValues: {[key: string]: any}): Promise<SampleState> {
|
||||
|
@ -34,7 +34,9 @@ export class SeleniumWebDriverAdapter extends WebDriverAdapter {
|
||||
capabilities(): Promise<{[key: string]: any}> {
|
||||
return this._driver.getCapabilities().then((capsObject: any) => {
|
||||
const localData: {[key: string]: any} = {};
|
||||
capsObject.forEach((value: any, key: string) => { localData[key] = value; });
|
||||
for (const key of capsObject.keys()) {
|
||||
localData[key] = capsObject.get(key);
|
||||
}
|
||||
return localData;
|
||||
});
|
||||
}
|
||||
|
@ -537,6 +537,24 @@ export function main() {
|
||||
});
|
||||
}));
|
||||
|
||||
it('should mark a run as invalid if the start and end marks are different',
|
||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
||||
const otherProcessEventFactory = new TraceEventFactory('timeline', 'pid1');
|
||||
const metric = createMetric(
|
||||
[[
|
||||
eventFactory.markStart('benchpress0', 0), eventFactory.start('script', 0, null),
|
||||
eventFactory.end('script', 5, null),
|
||||
otherProcessEventFactory.start('script', 10, null),
|
||||
otherProcessEventFactory.end('script', 17, null),
|
||||
otherProcessEventFactory.markEnd('benchpress0', 20)
|
||||
]],
|
||||
null !);
|
||||
metric.beginMeasure().then((_) => metric.endMeasure(false)).then((data) => {
|
||||
expect(data['invalid']).toBe(1);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should support scriptTime metric',
|
||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
||||
aggregate([
|
||||
|
@ -23,12 +23,13 @@ export class MockScriptElement {
|
||||
|
||||
export class MockDocument {
|
||||
mock: MockScriptElement|null;
|
||||
readonly body: any = this;
|
||||
|
||||
createElement(tag: 'script'): HTMLScriptElement {
|
||||
return new MockScriptElement() as any as HTMLScriptElement;
|
||||
}
|
||||
|
||||
get body(): any { return this; }
|
||||
|
||||
appendChild(node: any): void { this.mock = node; }
|
||||
|
||||
removeNode(node: any): void {
|
||||
@ -40,4 +41,4 @@ export class MockDocument {
|
||||
mockLoad(): void { this.mock !.listeners.load !(null as any); }
|
||||
|
||||
mockError(err: Error) { this.mock !.listeners.error !(err); }
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"declaration": false,
|
||||
"declaration": true,
|
||||
"stripInternal": true,
|
||||
"experimentalDecorators": true,
|
||||
"module": "es2015",
|
||||
|
@ -14,8 +14,7 @@
|
||||
export * from './location/index';
|
||||
export {NgLocaleLocalization, NgLocalization} from './i18n/localization';
|
||||
export {registerLocaleData} from './i18n/locale_data';
|
||||
export {Plural, NumberFormatStyle, FormStyle, Time, TranslationWidth, FormatWidth, NumberSymbol, WeekDay, getLocaleDayPeriods, getLocaleDayNames, getLocaleMonthNames, getLocaleId, getLocaleEraNames, getLocaleWeekEndRange, getLocaleFirstDayOfWeek, getLocaleDateFormat, getLocaleDateTimeFormat, getLocaleExtraDayPeriodRules, getLocaleExtraDayPeriods, getLocalePluralCase, getLocaleTimeFormat, getLocaleNumberSymbol, getLocaleNumberFormat, getLocaleCurrencyName, getLocaleCurrencySymbol} from './i18n/locale_data_api';
|
||||
export {CURRENCIES} from './i18n/currencies';
|
||||
export {Plural, NumberFormatStyle, FormStyle, Time, TranslationWidth, FormatWidth, NumberSymbol, WeekDay, getCurrencySymbol, getLocaleDayPeriods, getLocaleDayNames, getLocaleMonthNames, getLocaleId, getLocaleEraNames, getLocaleWeekEndRange, getLocaleFirstDayOfWeek, getLocaleDateFormat, getLocaleDateTimeFormat, getLocaleExtraDayPeriodRules, getLocaleExtraDayPeriods, getLocalePluralCase, getLocaleTimeFormat, getLocaleNumberSymbol, getLocaleNumberFormat, getLocaleCurrencyName, getLocaleCurrencySymbol} from './i18n/locale_data_api';
|
||||
export {parseCookieValue as ɵparseCookieValue} from './cookie';
|
||||
export {CommonModule, DeprecatedI18NPipesModule} from './common_module';
|
||||
export {NgClass, NgForOf, NgForOfContext, NgIf, NgIfContext, NgPlural, NgPluralCase, NgStyle, NgSwitch, NgSwitchCase, NgSwitchDefault, NgTemplateOutlet, NgComponentOutlet} from './directives/index';
|
||||
|
@ -151,9 +151,6 @@ export class NgIf {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
public static ngIfUseIfTypeGuard: void;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -9,7 +9,7 @@
|
||||
// THIS CODE IS GENERATED - DO NOT MODIFY
|
||||
// See angular/tools/gulp-tasks/cldr/extract.js
|
||||
|
||||
/** @experimental */
|
||||
/** @internal */
|
||||
export const CURRENCIES: {[code: string]: (string | undefined)[]} = {
|
||||
'AOA': [, 'Kz'],
|
||||
'ARS': [, '$'],
|
||||
|
@ -46,11 +46,6 @@ export function formatNumber(
|
||||
num = value;
|
||||
}
|
||||
|
||||
if (style === NumberFormatStyle.Percent) {
|
||||
num = num * 100;
|
||||
}
|
||||
|
||||
const numStr = Math.abs(num) + '';
|
||||
const pattern = parseNumberFormat(format, getLocaleNumberSymbol(locale, NumberSymbol.MinusSign));
|
||||
let formattedText = '';
|
||||
let isZero = false;
|
||||
@ -58,7 +53,11 @@ export function formatNumber(
|
||||
if (!isFinite(num)) {
|
||||
formattedText = getLocaleNumberSymbol(locale, NumberSymbol.Infinity);
|
||||
} else {
|
||||
const parsedNumber = parseNumber(numStr);
|
||||
let parsedNumber = parseNumber(num);
|
||||
|
||||
if (style === NumberFormatStyle.Percent) {
|
||||
parsedNumber = toPercent(parsedNumber);
|
||||
}
|
||||
|
||||
let minInt = pattern.minInt;
|
||||
let minFraction = pattern.minFrac;
|
||||
@ -249,11 +248,35 @@ interface ParsedNumber {
|
||||
integerLen: number;
|
||||
}
|
||||
|
||||
// Transforms a parsed number into a percentage by multiplying it by 100
|
||||
function toPercent(parsedNumber: ParsedNumber): ParsedNumber {
|
||||
// if the number is 0, don't do anything
|
||||
if (parsedNumber.digits[0] === 0) {
|
||||
return parsedNumber;
|
||||
}
|
||||
|
||||
// Getting the current number of decimals
|
||||
const fractionLen = parsedNumber.digits.length - parsedNumber.integerLen;
|
||||
if (parsedNumber.exponent) {
|
||||
parsedNumber.exponent += 2;
|
||||
} else {
|
||||
if (fractionLen === 0) {
|
||||
parsedNumber.digits.push(0, 0);
|
||||
} else if (fractionLen === 1) {
|
||||
parsedNumber.digits.push(0);
|
||||
}
|
||||
parsedNumber.integerLen += 2;
|
||||
}
|
||||
|
||||
return parsedNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a number (as a string)
|
||||
* Parses a number.
|
||||
* Significant bits of this parse algorithm came from https://github.com/MikeMcl/big.js/
|
||||
*/
|
||||
function parseNumber(numStr: string): ParsedNumber {
|
||||
function parseNumber(num: number): ParsedNumber {
|
||||
let numStr = Math.abs(num) + '';
|
||||
let exponent = 0, digits, integerLen;
|
||||
let i, j, zeros;
|
||||
|
||||
@ -356,12 +379,23 @@ function roundNumber(parsedNumber: ParsedNumber, minFrac: number, maxFrac: numbe
|
||||
// Pad out with zeros to get the required fraction length
|
||||
for (; fractionLen < Math.max(0, fractionSize); fractionLen++) digits.push(0);
|
||||
|
||||
|
||||
let dropTrailingZeros = fractionSize !== 0;
|
||||
// Minimal length = nb of decimals required + current nb of integers
|
||||
// Any number besides that is optional and can be removed if it's a trailing 0
|
||||
const minLen = minFrac + parsedNumber.integerLen;
|
||||
// Do any carrying, e.g. a digit was rounded up to 10
|
||||
const carry = digits.reduceRight(function(carry, d, i, digits) {
|
||||
d = d + carry;
|
||||
digits[i] = d % 10;
|
||||
return Math.floor(d / 10);
|
||||
digits[i] = d < 10 ? d : d - 10; // d % 10
|
||||
if (dropTrailingZeros) {
|
||||
// Do not keep meaningless fractional trailing zeros (e.g. 15.52000 --> 15.52)
|
||||
if (digits[i] === 0 && i >= minLen) {
|
||||
digits.pop();
|
||||
} else {
|
||||
dropTrailingZeros = false;
|
||||
}
|
||||
}
|
||||
return d >= 10 ? 1 : 0; // Math.floor(d / 10);
|
||||
}, 0);
|
||||
if (carry) {
|
||||
digits.unshift(carry);
|
||||
|
@ -527,12 +527,17 @@ export function findLocaleData(locale: string): any {
|
||||
|
||||
/**
|
||||
* Return the currency symbol for a given currency code, or the code if no symbol available
|
||||
* (e.g.: $, US$, or USD)
|
||||
* (e.g.: format narrow = $, format wide = US$, code = USD)
|
||||
*
|
||||
* @internal
|
||||
* @experimental i18n support is experimental.
|
||||
*/
|
||||
export function findCurrencySymbol(code: string, format: 'wide' | 'narrow') {
|
||||
const currency = CURRENCIES[code] || {};
|
||||
const symbol = currency[0] || code;
|
||||
return format === 'wide' ? symbol : currency[1] || symbol;
|
||||
}
|
||||
export function getCurrencySymbol(code: string, format: 'wide' | 'narrow'): string {
|
||||
const currency = CURRENCIES[code] || [];
|
||||
const symbolNarrow = currency[1];
|
||||
|
||||
if (format === 'narrow' && typeof symbolNarrow === 'string') {
|
||||
return symbolNarrow;
|
||||
}
|
||||
|
||||
return currency[0] || code;
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
import {Inject, LOCALE_ID, Pipe, PipeTransform} from '@angular/core';
|
||||
import {formatNumber} from '../i18n/format_number';
|
||||
import {NumberFormatStyle, findCurrencySymbol, getLocaleCurrencyName, getLocaleCurrencySymbol} from '../i18n/locale_data_api';
|
||||
import {NumberFormatStyle, getCurrencySymbol, getLocaleCurrencyName, getLocaleCurrencySymbol} from '../i18n/locale_data_api';
|
||||
import {invalidPipeArgumentError} from './invalid_pipe_argument_error';
|
||||
|
||||
/**
|
||||
@ -143,7 +143,7 @@ export class CurrencyPipe implements PipeTransform {
|
||||
|
||||
let currency = currencyCode || 'USD';
|
||||
if (display !== 'code') {
|
||||
currency = findCurrencySymbol(currency, display === 'symbol' ? 'wide' : 'narrow');
|
||||
currency = getCurrencySymbol(currency, display === 'symbol' ? 'wide' : 'narrow');
|
||||
}
|
||||
|
||||
const {str, error} = formatNumber(value, locale, NumberFormatStyle.Currency, digits, currency);
|
||||
|
@ -11,7 +11,7 @@ import localeEn from '../../locales/en';
|
||||
import localeFr from '../../locales/fr';
|
||||
import localeFrCA from '../../locales/fr-CA';
|
||||
import {registerLocaleData} from '../../src/i18n/locale_data';
|
||||
import {findLocaleData} from '../../src/i18n/locale_data_api';
|
||||
import {findLocaleData, getCurrencySymbol} from '../../src/i18n/locale_data_api';
|
||||
|
||||
export function main() {
|
||||
describe('locale data api', () => {
|
||||
@ -51,5 +51,18 @@ export function main() {
|
||||
expect(findLocaleData('fake-id2')).toEqual(localeFrCA);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getCurrencySymbolElseCode', () => {
|
||||
it('should return the correct symbol', () => {
|
||||
expect(getCurrencySymbol('USD', 'wide')).toEqual('$');
|
||||
expect(getCurrencySymbol('USD', 'narrow')).toEqual('$');
|
||||
expect(getCurrencySymbol('AUD', 'wide')).toEqual('A$');
|
||||
expect(getCurrencySymbol('AUD', 'narrow')).toEqual('$');
|
||||
expect(getCurrencySymbol('CRC', 'wide')).toEqual('CRC');
|
||||
expect(getCurrencySymbol('CRC', 'narrow')).toEqual('₡');
|
||||
expect(getCurrencySymbol('FAKE', 'wide')).toEqual('FAKE');
|
||||
expect(getCurrencySymbol('FAKE', 'narrow')).toEqual('FAKE');
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -79,6 +79,22 @@ export function main() {
|
||||
expect(pipe.transform(1.2, '.2')).toEqual('120.00%');
|
||||
expect(pipe.transform(1.2, '4.2')).toEqual('0,120.00%');
|
||||
expect(pipe.transform(1.2, '4.2', 'fr')).toEqual('0 120,00 %');
|
||||
// see issue #20136
|
||||
expect(pipe.transform(0.12345674, '0.0-10')).toEqual('12.345674%');
|
||||
expect(pipe.transform(0, '0.0-10')).toEqual('0%');
|
||||
expect(pipe.transform(0.00, '0.0-10')).toEqual('0%');
|
||||
expect(pipe.transform(1, '0.0-10')).toEqual('100%');
|
||||
expect(pipe.transform(0.1, '0.0-10')).toEqual('10%');
|
||||
expect(pipe.transform(0.12, '0.0-10')).toEqual('12%');
|
||||
expect(pipe.transform(0.123, '0.0-10')).toEqual('12.3%');
|
||||
expect(pipe.transform(12.3456, '0.0-10')).toEqual('1,234.56%');
|
||||
expect(pipe.transform(12.345600, '0.0-10')).toEqual('1,234.56%');
|
||||
expect(pipe.transform(12.345699999, '0.0-6')).toEqual('1,234.57%');
|
||||
expect(pipe.transform(12.345699999, '0.4-6')).toEqual('1,234.5700%');
|
||||
expect(pipe.transform(100, '0.4-6')).toEqual('10,000.0000%');
|
||||
expect(pipe.transform(100, '0.0-10')).toEqual('10,000%');
|
||||
expect(pipe.transform(1.5e2)).toEqual('15,000%');
|
||||
expect(pipe.transform(1e100)).toEqual('1E+102%');
|
||||
});
|
||||
|
||||
it('should not support other objects', () => {
|
||||
@ -106,6 +122,7 @@ export function main() {
|
||||
expect(pipe.transform(5.1234, 'CAD', 'symbol-narrow', '5.2-2')).toEqual('$00,005.12');
|
||||
expect(pipe.transform(5.1234, 'CAD', 'symbol-narrow', '5.2-2', 'fr'))
|
||||
.toEqual('00 005,12 $');
|
||||
expect(pipe.transform(5.1234, 'FAKE', 'symbol')).toEqual('FAKE5.12');
|
||||
});
|
||||
|
||||
it('should not support other objects', () => {
|
||||
|
@ -57,7 +57,7 @@ export interface CompilerOptions extends ts.CompilerOptions {
|
||||
// Produce an error if the metadata written for a class would produce an error if used.
|
||||
strictMetadataEmit?: boolean;
|
||||
|
||||
// Don't produce .ngfactory.ts or .ngstyle.ts files
|
||||
// Don't produce .ngfactory.js or .ngstyle.js files
|
||||
skipTemplateCodegen?: boolean;
|
||||
|
||||
// Always report errors when the type of a parameter supplied whose injection type cannot
|
||||
|
@ -48,11 +48,11 @@ describe('ng type checker', () => {
|
||||
}
|
||||
|
||||
function reject(
|
||||
message: string | RegExp, location: RegExp | null, files: MockFiles,
|
||||
message: string | RegExp, location: RegExp, files: MockFiles,
|
||||
overrideOptions: ng.CompilerOptions = {}) {
|
||||
const diagnostics = compileAndCheck([QUICKSTART, files], overrideOptions);
|
||||
if (!diagnostics || !diagnostics.length) {
|
||||
throw new Error('Expected a diagnostic error message');
|
||||
throw new Error('Expected a diagnostic erorr message');
|
||||
} else {
|
||||
const matches: (d: ng.Diagnostic) => boolean = typeof message === 'string' ?
|
||||
d => ng.isNgDiagnostic(d)&& d.messageText == message :
|
||||
@ -63,13 +63,11 @@ describe('ng type checker', () => {
|
||||
`Expected a diagnostics matching ${message}, received\n ${diagnostics.map(d => d.messageText).join('\n ')}`);
|
||||
}
|
||||
|
||||
if (location) {
|
||||
const span = matchingDiagnostics[0].span;
|
||||
if (!span) {
|
||||
throw new Error('Expected a sourceSpan');
|
||||
}
|
||||
expect(`${span.start.file.url}@${span.start.line}:${span.start.offset}`).toMatch(location);
|
||||
const span = matchingDiagnostics[0].span;
|
||||
if (!span) {
|
||||
throw new Error('Expected a sourceSpan');
|
||||
}
|
||||
expect(`${span.start.file.url}@${span.start.line}:${span.start.offset}`).toMatch(location);
|
||||
}
|
||||
}
|
||||
|
||||
@ -83,543 +81,6 @@ describe('ng type checker', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('type narrowing', () => {
|
||||
const a = (files: MockFiles, options: object = {}) => {
|
||||
accept(files, {fullTemplateTypeCheck: true, ...options});
|
||||
};
|
||||
|
||||
it('should narrow an *ngIf like directive', () => {
|
||||
a({
|
||||
'src/app.component.ts': '',
|
||||
'src/lib.ts': '',
|
||||
'src/app.module.ts': `
|
||||
import {NgModule, Component, Directive, HostListener, TemplateRef, Input} from '@angular/core';
|
||||
|
||||
export interface Person {
|
||||
name: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'comp',
|
||||
template: '<div *myIf="person"> {{person.name}} </div>'
|
||||
})
|
||||
export class MainComp {
|
||||
person?: Person;
|
||||
}
|
||||
|
||||
export class MyIfContext {
|
||||
public $implicit: any = null;
|
||||
public myIf: any = null;
|
||||
}
|
||||
|
||||
@Directive({selector: '[myIf]'})
|
||||
export class MyIf {
|
||||
constructor(templateRef: TemplateRef<MyIfContext>) {}
|
||||
|
||||
@Input()
|
||||
set myIf(condition: any) {}
|
||||
|
||||
static myIfTypeGuard: <T>(v: T | null | undefined | false) => v is T;
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
declarations: [MainComp, MyIf],
|
||||
})
|
||||
export class MainModule {}`
|
||||
});
|
||||
});
|
||||
|
||||
it('should narrow a renamed *ngIf like directive', () => {
|
||||
a({
|
||||
'src/app.component.ts': '',
|
||||
'src/lib.ts': '',
|
||||
'src/app.module.ts': `
|
||||
import {NgModule, Component, Directive, HostListener, TemplateRef, Input} from '@angular/core';
|
||||
|
||||
export interface Person {
|
||||
name: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'comp',
|
||||
template: '<div *my-if="person"> {{person.name}} </div>'
|
||||
})
|
||||
export class MainComp {
|
||||
person?: Person;
|
||||
}
|
||||
|
||||
export class MyIfContext {
|
||||
public $implicit: any = null;
|
||||
public myIf: any = null;
|
||||
}
|
||||
|
||||
@Directive({selector: '[my-if]'})
|
||||
export class MyIf {
|
||||
constructor(templateRef: TemplateRef<MyIfContext>) {}
|
||||
|
||||
@Input('my-if')
|
||||
set myIf(condition: any) {}
|
||||
|
||||
static myIfTypeGuard: <T>(v: T | null | undefined | false) => v is T;
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
declarations: [MainComp, MyIf],
|
||||
})
|
||||
export class MainModule {}`
|
||||
});
|
||||
});
|
||||
|
||||
it('should narrow a type in a nested *ngIf like directive', () => {
|
||||
a({
|
||||
'src/app.component.ts': '',
|
||||
'src/lib.ts': '',
|
||||
'src/app.module.ts': `
|
||||
import {NgModule, Component, Directive, HostListener, TemplateRef, Input} from '@angular/core';
|
||||
|
||||
export interface Address {
|
||||
street: string;
|
||||
}
|
||||
|
||||
export interface Person {
|
||||
name: string;
|
||||
address?: Address;
|
||||
}
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'comp',
|
||||
template: '<div *myIf="person"> {{person.name}} <span *myIf="person.address">{{person.address.street}}</span></div>'
|
||||
})
|
||||
export class MainComp {
|
||||
person?: Person;
|
||||
}
|
||||
|
||||
export class MyIfContext {
|
||||
public $implicit: any = null;
|
||||
public myIf: any = null;
|
||||
}
|
||||
|
||||
@Directive({selector: '[myIf]'})
|
||||
export class MyIf {
|
||||
constructor(templateRef: TemplateRef<MyIfContext>) {}
|
||||
|
||||
@Input()
|
||||
set myIf(condition: any) {}
|
||||
|
||||
static myIfTypeGuard: <T>(v: T | null | undefined | false) => v is T;
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
declarations: [MainComp, MyIf],
|
||||
})
|
||||
export class MainModule {}`
|
||||
});
|
||||
});
|
||||
|
||||
it('should narrow an *ngIf like directive with UseIf', () => {
|
||||
a({
|
||||
'src/app.component.ts': '',
|
||||
'src/lib.ts': '',
|
||||
'src/app.module.ts': `
|
||||
import {NgModule, Component, Directive, HostListener, TemplateRef, Input} from '@angular/core';
|
||||
|
||||
export interface Person {
|
||||
name: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'comp',
|
||||
template: '<div *myIf="person"> {{person.name}} </div>'
|
||||
})
|
||||
export class MainComp {
|
||||
person?: Person;
|
||||
}
|
||||
|
||||
export class MyIfContext {
|
||||
public $implicit: any = null;
|
||||
public myIf: any = null;
|
||||
}
|
||||
|
||||
@Directive({selector: '[myIf]'})
|
||||
export class MyIf {
|
||||
constructor(templateRef: TemplateRef<MyIfContext>) {}
|
||||
|
||||
@Input()
|
||||
set myIf(condition: any) {}
|
||||
|
||||
static myIfUseIfTypeGuard: void;
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
declarations: [MainComp, MyIf],
|
||||
})
|
||||
export class MainModule {}`
|
||||
});
|
||||
});
|
||||
|
||||
it('should narrow a renamed *ngIf like directive with UseIf', () => {
|
||||
a({
|
||||
'src/app.component.ts': '',
|
||||
'src/lib.ts': '',
|
||||
'src/app.module.ts': `
|
||||
import {NgModule, Component, Directive, HostListener, TemplateRef, Input} from '@angular/core';
|
||||
|
||||
export interface Person {
|
||||
name: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'comp',
|
||||
template: '<div *my-if="person"> {{person.name}} </div>'
|
||||
})
|
||||
export class MainComp {
|
||||
person?: Person;
|
||||
}
|
||||
|
||||
export class MyIfContext {
|
||||
public $implicit: any = null;
|
||||
public myIf: any = null;
|
||||
}
|
||||
|
||||
@Directive({selector: '[my-if]'})
|
||||
export class MyIf {
|
||||
constructor(templateRef: TemplateRef<MyIfContext>) {}
|
||||
|
||||
@Input('my-if')
|
||||
set myIf(condition: any) {}
|
||||
|
||||
static myIfUseIfTypeGuard: void;
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
declarations: [MainComp, MyIf],
|
||||
})
|
||||
export class MainModule {}`
|
||||
});
|
||||
});
|
||||
|
||||
it('should narrow a type in a nested *ngIf like directive with UseIf', () => {
|
||||
a({
|
||||
'src/app.component.ts': '',
|
||||
'src/lib.ts': '',
|
||||
'src/app.module.ts': `
|
||||
import {NgModule, Component, Directive, HostListener, TemplateRef, Input} from '@angular/core';
|
||||
|
||||
export interface Address {
|
||||
street: string;
|
||||
}
|
||||
|
||||
export interface Person {
|
||||
name: string;
|
||||
address?: Address;
|
||||
}
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'comp',
|
||||
template: '<div *myIf="person"> {{person.name}} <span *myIf="person.address">{{person.address.street}}</span></div>'
|
||||
})
|
||||
export class MainComp {
|
||||
person?: Person;
|
||||
}
|
||||
|
||||
export class MyIfContext {
|
||||
public $implicit: any = null;
|
||||
public myIf: any = null;
|
||||
}
|
||||
|
||||
@Directive({selector: '[myIf]'})
|
||||
export class MyIf {
|
||||
constructor(templateRef: TemplateRef<MyIfContext>) {}
|
||||
|
||||
@Input()
|
||||
set myIf(condition: any) {}
|
||||
|
||||
static myIfUseIfTypeGuard: void;
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
declarations: [MainComp, MyIf],
|
||||
})
|
||||
export class MainModule {}`
|
||||
});
|
||||
});
|
||||
|
||||
it('should narrow an *ngIf like directive with UseIf and &&', () => {
|
||||
a({
|
||||
'src/app.component.ts': '',
|
||||
'src/lib.ts': '',
|
||||
'src/app.module.ts': `
|
||||
import {NgModule, Component, Directive, HostListener, TemplateRef, Input} from '@angular/core';
|
||||
|
||||
export interface Address {
|
||||
street: string;
|
||||
}
|
||||
|
||||
export interface Person {
|
||||
name: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'comp',
|
||||
template: '<div *myIf="person && address"> {{person.name}} lives at {{address.street}} </div>'
|
||||
})
|
||||
export class MainComp {
|
||||
person?: Person;
|
||||
address?: Address;
|
||||
}
|
||||
|
||||
export class MyIfContext {
|
||||
public $implicit: any = null;
|
||||
public myIf: any = null;
|
||||
}
|
||||
|
||||
@Directive({selector: '[myIf]'})
|
||||
export class MyIf {
|
||||
constructor(templateRef: TemplateRef<MyIfContext>) {}
|
||||
|
||||
@Input()
|
||||
set myIf(condition: any) {}
|
||||
|
||||
static myIfUseIfTypeGuard: void;
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
declarations: [MainComp, MyIf],
|
||||
})
|
||||
export class MainModule {}`
|
||||
});
|
||||
});
|
||||
|
||||
it('should narrow an *ngIf like directive with UseIf and !!', () => {
|
||||
a({
|
||||
'src/app.component.ts': '',
|
||||
'src/lib.ts': '',
|
||||
'src/app.module.ts': `
|
||||
import {NgModule, Component, Directive, HostListener, TemplateRef, Input} from '@angular/core';
|
||||
|
||||
export interface Person {
|
||||
name: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'comp',
|
||||
template: '<div *myIf="!!person"> {{person.name}} </div>'
|
||||
})
|
||||
export class MainComp {
|
||||
person?: Person;
|
||||
}
|
||||
|
||||
export class MyIfContext {
|
||||
public $implicit: any = null;
|
||||
public myIf: any = null;
|
||||
}
|
||||
|
||||
@Directive({selector: '[myIf]'})
|
||||
export class MyIf {
|
||||
constructor(templateRef: TemplateRef<MyIfContext>) {}
|
||||
|
||||
@Input()
|
||||
set myIf(condition: any) {}
|
||||
|
||||
static myIfUseIfTypeGuard: void;
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
declarations: [MainComp, MyIf],
|
||||
})
|
||||
export class MainModule {}`
|
||||
});
|
||||
});
|
||||
|
||||
it('should narrow an *ngIf like directive with UseIf and != null', () => {
|
||||
a({
|
||||
'src/app.component.ts': '',
|
||||
'src/lib.ts': '',
|
||||
'src/app.module.ts': `
|
||||
import {NgModule, Component, Directive, HostListener, TemplateRef, Input} from '@angular/core';
|
||||
|
||||
export interface Person {
|
||||
name: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'comp',
|
||||
template: '<div *myIf="person != null"> {{person.name}} </div>'
|
||||
})
|
||||
export class MainComp {
|
||||
person: Person | null = null;
|
||||
}
|
||||
|
||||
export class MyIfContext {
|
||||
public $implicit: any = null;
|
||||
public myIf: any = null;
|
||||
}
|
||||
|
||||
@Directive({selector: '[myIf]'})
|
||||
export class MyIf {
|
||||
constructor(templateRef: TemplateRef<MyIfContext>) {}
|
||||
|
||||
@Input()
|
||||
set myIf(condition: any) {}
|
||||
|
||||
static myIfUseIfTypeGuard: void;
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
declarations: [MainComp, MyIf],
|
||||
})
|
||||
export class MainModule {}`
|
||||
});
|
||||
});
|
||||
|
||||
it('should narrow an *ngIf like directive with UseIf and != undefined', () => {
|
||||
a({
|
||||
'src/app.component.ts': '',
|
||||
'src/lib.ts': '',
|
||||
'src/app.module.ts': `
|
||||
import {NgModule, Component, Directive, HostListener, TemplateRef, Input} from '@angular/core';
|
||||
|
||||
export interface Person {
|
||||
name: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'comp',
|
||||
template: '<div *myIf="person != undefined"> {{person.name}} </div>'
|
||||
})
|
||||
export class MainComp {
|
||||
person?: Person;
|
||||
}
|
||||
|
||||
export class MyIfContext {
|
||||
public $implicit: any = null;
|
||||
public myIf: any = null;
|
||||
}
|
||||
|
||||
@Directive({selector: '[myIf]'})
|
||||
export class MyIf {
|
||||
constructor(templateRef: TemplateRef<MyIfContext>) {}
|
||||
|
||||
@Input()
|
||||
set myIf(condition: any) {}
|
||||
|
||||
static myIfUseIfTypeGuard: void;
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
declarations: [MainComp, MyIf],
|
||||
})
|
||||
export class MainModule {}`
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('casting $any', () => {
|
||||
const a = (files: MockFiles, options: object = {}) => {
|
||||
accept(
|
||||
{'src/app.component.ts': '', 'src/lib.ts': '', ...files},
|
||||
{fullTemplateTypeCheck: true, ...options});
|
||||
};
|
||||
|
||||
const r =
|
||||
(message: string | RegExp, location: RegExp | null, files: MockFiles,
|
||||
options: object = {}) => {
|
||||
reject(
|
||||
message, location, {'src/app.component.ts': '', 'src/lib.ts': '', ...files},
|
||||
{fullTemplateTypeCheck: true, ...options});
|
||||
};
|
||||
|
||||
it('should allow member access of an expression', () => {
|
||||
a({
|
||||
'src/app.module.ts': `
|
||||
import {NgModule, Component} from '@angular/core';
|
||||
|
||||
export interface Person {
|
||||
name: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'comp',
|
||||
template: ' {{$any(person).address}}'
|
||||
})
|
||||
export class MainComp {
|
||||
person: Person;
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
declarations: [MainComp],
|
||||
})
|
||||
export class MainModule {
|
||||
}`
|
||||
});
|
||||
});
|
||||
|
||||
it('should allow invalid this.member access', () => {
|
||||
a({
|
||||
'src/app.module.ts': `
|
||||
import {NgModule, Component} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'comp',
|
||||
template: ' {{$any(this).missing}}'
|
||||
})
|
||||
export class MainComp { }
|
||||
|
||||
@NgModule({
|
||||
declarations: [MainComp],
|
||||
})
|
||||
export class MainModule {
|
||||
}`
|
||||
});
|
||||
});
|
||||
|
||||
it('should reject too few parameters to $any', () => {
|
||||
r(/Invalid call to \$any, expected 1 argument but received none/, null, {
|
||||
'src/app.module.ts': `
|
||||
import {NgModule, Component} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'comp',
|
||||
template: ' {{$any().missing}}'
|
||||
})
|
||||
export class MainComp { }
|
||||
|
||||
@NgModule({
|
||||
declarations: [MainComp],
|
||||
})
|
||||
export class MainModule {
|
||||
}`
|
||||
});
|
||||
});
|
||||
|
||||
it('should reject too many parameters to $any', () => {
|
||||
r(/Invalid call to \$any, expected 1 argument but received 2/, null, {
|
||||
'src/app.module.ts': `
|
||||
import {NgModule, Component} from '@angular/core';
|
||||
|
||||
export interface Person {
|
||||
name: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'comp',
|
||||
template: ' {{$any(person, 12).missing}}'
|
||||
})
|
||||
export class MainComp {
|
||||
person: Person;
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
declarations: [MainComp],
|
||||
})
|
||||
export class MainModule {
|
||||
}`
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('regressions ', () => {
|
||||
const a = (files: MockFiles, options: object = {}) => {
|
||||
accept(files, {fullTemplateTypeCheck: true, ...options});
|
||||
|
@ -1038,25 +1038,6 @@ describe('Collector', () => {
|
||||
expect(metadata).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should collect type guards', () => {
|
||||
const metadata = collectSource(`
|
||||
import {Directive, Input, TemplateRef} from '@angular/core';
|
||||
|
||||
@Directive({selector: '[myIf]'})
|
||||
export class MyIf {
|
||||
|
||||
constructor(private templateRef: TemplateRef) {}
|
||||
|
||||
@Input() myIf: any;
|
||||
|
||||
static typeGuard: <T>(v: T | null | undefined): v is T;
|
||||
}
|
||||
`);
|
||||
|
||||
expect((metadata.metadata.MyIf as any).statics.typeGuard)
|
||||
.not.toBeUndefined('typeGuard was not collected');
|
||||
});
|
||||
|
||||
it('should be able to collect an invalid access expression', () => {
|
||||
const source = createSource(`
|
||||
import {Component} from '@angular/core';
|
||||
|
@ -12,7 +12,6 @@ import * as path from 'path';
|
||||
import * as ts from 'typescript';
|
||||
import * as ng from '../index';
|
||||
|
||||
// TEST_TMPDIR is set by bazel.
|
||||
const tmpdir = process.env.TEST_TMPDIR || os.tmpdir();
|
||||
|
||||
function getNgRootDir() {
|
||||
@ -22,6 +21,7 @@ function getNgRootDir() {
|
||||
}
|
||||
|
||||
export function writeTempFile(name: string, contents: string): string {
|
||||
// TEST_TMPDIR is set by bazel.
|
||||
const id = (Math.random() * 1000000).toFixed(0);
|
||||
const fn = path.join(tmpdir, `tmp.${id}.${name}`);
|
||||
fs.writeFileSync(fn, contents);
|
||||
@ -29,12 +29,8 @@ export function writeTempFile(name: string, contents: string): string {
|
||||
}
|
||||
|
||||
export function makeTempDir(): string {
|
||||
let dir: string;
|
||||
while (true) {
|
||||
const id = (Math.random() * 1000000).toFixed(0);
|
||||
dir = path.join(tmpdir, `tmp.${id}`);
|
||||
if (!fs.existsSync(dir)) break;
|
||||
}
|
||||
const id = (Math.random() * 1000000).toFixed(0);
|
||||
const dir = path.join(tmpdir, `tmp.${id}`);
|
||||
fs.mkdirSync(dir);
|
||||
return dir;
|
||||
}
|
||||
|
@ -218,14 +218,15 @@ export class AotCompiler {
|
||||
|
||||
const externalReferenceVars = new Map<any, string>();
|
||||
externalReferences.forEach((ref, typeIndex) => {
|
||||
externalReferenceVars.set(ref, `_decl${ngModuleIndex}_${typeIndex}`);
|
||||
if (this._host.isSourceFile(ref.filePath)) {
|
||||
externalReferenceVars.set(ref, `_decl${ngModuleIndex}_${typeIndex}`);
|
||||
}
|
||||
});
|
||||
externalReferenceVars.forEach((varName, reference) => {
|
||||
outputCtx.statements.push(
|
||||
o.variable(varName)
|
||||
.set(o.NULL_EXPR.cast(o.DYNAMIC_TYPE))
|
||||
.toDeclStmt(o.expressionType(outputCtx.importExpr(
|
||||
reference, /* typeParams */ null, /* useSummaries */ false))));
|
||||
.toDeclStmt(o.expressionType(outputCtx.importExpr(reference))));
|
||||
});
|
||||
|
||||
if (emitFlags & StubEmitFlags.TypeCheck) {
|
||||
@ -270,7 +271,7 @@ export class AotCompiler {
|
||||
const {template: parsedTemplate, pipes: usedPipes} =
|
||||
this._parseTemplate(compMeta, moduleMeta, directives);
|
||||
ctx.statements.push(...this._typeCheckCompiler.compileComponent(
|
||||
componentId, compMeta, parsedTemplate, usedPipes, externalReferenceVars, ctx));
|
||||
componentId, compMeta, parsedTemplate, usedPipes, externalReferenceVars));
|
||||
}
|
||||
|
||||
emitMessageBundle(analyzeResult: NgAnalyzedModules, locale: string|null): MessageBundle {
|
||||
@ -514,38 +515,35 @@ export class AotCompiler {
|
||||
}
|
||||
|
||||
private _createOutputContext(genFilePath: string): OutputContext {
|
||||
const importExpr =
|
||||
(symbol: StaticSymbol, typeParams: o.Type[] | null = null,
|
||||
useSummaries: boolean = true) => {
|
||||
if (!(symbol instanceof StaticSymbol)) {
|
||||
throw new Error(`Internal error: unknown identifier ${JSON.stringify(symbol)}`);
|
||||
}
|
||||
const arity = this._symbolResolver.getTypeArity(symbol) || 0;
|
||||
const {filePath, name, members} =
|
||||
this._symbolResolver.getImportAs(symbol, useSummaries) || symbol;
|
||||
const importModule = this._fileNameToModuleName(filePath, genFilePath);
|
||||
const importExpr = (symbol: StaticSymbol, typeParams: o.Type[] | null = null) => {
|
||||
if (!(symbol instanceof StaticSymbol)) {
|
||||
throw new Error(`Internal error: unknown identifier ${JSON.stringify(symbol)}`);
|
||||
}
|
||||
const arity = this._symbolResolver.getTypeArity(symbol) || 0;
|
||||
const {filePath, name, members} = this._symbolResolver.getImportAs(symbol) || symbol;
|
||||
const importModule = this._fileNameToModuleName(filePath, genFilePath);
|
||||
|
||||
// It should be good enough to compare filePath to genFilePath and if they are equal
|
||||
// there is a self reference. However, ngfactory files generate to .ts but their
|
||||
// symbols have .d.ts so a simple compare is insufficient. They should be canonical
|
||||
// and is tracked by #17705.
|
||||
const selfReference = this._fileNameToModuleName(genFilePath, genFilePath);
|
||||
const moduleName = importModule === selfReference ? null : importModule;
|
||||
// It should be good enough to compare filePath to genFilePath and if they are equal
|
||||
// there is a self reference. However, ngfactory files generate to .ts but their
|
||||
// symbols have .d.ts so a simple compare is insufficient. They should be canonical
|
||||
// and is tracked by #17705.
|
||||
const selfReference = this._fileNameToModuleName(genFilePath, genFilePath);
|
||||
const moduleName = importModule === selfReference ? null : importModule;
|
||||
|
||||
// If we are in a type expression that refers to a generic type then supply
|
||||
// the required type parameters. If there were not enough type parameters
|
||||
// supplied, supply any as the type. Outside a type expression the reference
|
||||
// should not supply type parameters and be treated as a simple value reference
|
||||
// to the constructor function itself.
|
||||
const suppliedTypeParams = typeParams || [];
|
||||
const missingTypeParamsCount = arity - suppliedTypeParams.length;
|
||||
const allTypeParams =
|
||||
suppliedTypeParams.concat(new Array(missingTypeParamsCount).fill(o.DYNAMIC_TYPE));
|
||||
return members.reduce(
|
||||
(expr, memberName) => expr.prop(memberName),
|
||||
<o.Expression>o.importExpr(
|
||||
new o.ExternalReference(moduleName, name, null), allTypeParams));
|
||||
};
|
||||
// If we are in a type expression that refers to a generic type then supply
|
||||
// the required type parameters. If there were not enough type parameters
|
||||
// supplied, supply any as the type. Outside a type expression the reference
|
||||
// should not supply type parameters and be treated as a simple value reference
|
||||
// to the constructor function itself.
|
||||
const suppliedTypeParams = typeParams || [];
|
||||
const missingTypeParamsCount = arity - suppliedTypeParams.length;
|
||||
const allTypeParams =
|
||||
suppliedTypeParams.concat(new Array(missingTypeParamsCount).fill(o.DYNAMIC_TYPE));
|
||||
return members.reduce(
|
||||
(expr, memberName) => expr.prop(memberName),
|
||||
<o.Expression>o.importExpr(
|
||||
new o.ExternalReference(moduleName, name, null), allTypeParams));
|
||||
};
|
||||
|
||||
return {statements: [], genFilePath, importExpr};
|
||||
}
|
||||
|
@ -29,8 +29,6 @@ const IGNORE = {
|
||||
const USE_VALUE = 'useValue';
|
||||
const PROVIDE = 'provide';
|
||||
const REFERENCE_SET = new Set([USE_VALUE, 'useFactory', 'data']);
|
||||
const TYPEGUARD_POSTFIX = 'TypeGuard';
|
||||
const USE_IF = 'UseIf';
|
||||
|
||||
function shouldIgnore(value: any): boolean {
|
||||
return value && value.__symbolic == 'ignore';
|
||||
@ -45,7 +43,6 @@ export class StaticReflector implements CompileReflector {
|
||||
private propertyCache = new Map<StaticSymbol, {[key: string]: any[]}>();
|
||||
private parameterCache = new Map<StaticSymbol, any[]>();
|
||||
private methodCache = new Map<StaticSymbol, {[key: string]: boolean}>();
|
||||
private staticCache = new Map<StaticSymbol, string[]>();
|
||||
private conversionMap = new Map<StaticSymbol, (context: StaticSymbol, args: any[]) => any>();
|
||||
private injectionToken: StaticSymbol;
|
||||
private opaqueToken: StaticSymbol;
|
||||
@ -254,18 +251,6 @@ export class StaticReflector implements CompileReflector {
|
||||
return methodNames;
|
||||
}
|
||||
|
||||
private _staticMembers(type: StaticSymbol): string[] {
|
||||
let staticMembers = this.staticCache.get(type);
|
||||
if (!staticMembers) {
|
||||
const classMetadata = this.getTypeMetadata(type);
|
||||
const staticMemberData = classMetadata['statics'] || {};
|
||||
staticMembers = Object.keys(staticMemberData);
|
||||
this.staticCache.set(type, staticMembers);
|
||||
}
|
||||
return staticMembers;
|
||||
}
|
||||
|
||||
|
||||
private findParentType(type: StaticSymbol, classMetadata: any): StaticSymbol|undefined {
|
||||
const parentType = this.trySimplify(type, classMetadata['extends']);
|
||||
if (parentType instanceof StaticSymbol) {
|
||||
@ -288,30 +273,6 @@ export class StaticReflector implements CompileReflector {
|
||||
}
|
||||
}
|
||||
|
||||
guards(type: any): {[key: string]: StaticSymbol} {
|
||||
if (!(type instanceof StaticSymbol)) {
|
||||
this.reportError(
|
||||
new Error(`guards received ${JSON.stringify(type)} which is not a StaticSymbol`), type);
|
||||
return {};
|
||||
}
|
||||
const staticMembers = this._staticMembers(type);
|
||||
const result: {[key: string]: StaticSymbol} = {};
|
||||
for (let name of staticMembers) {
|
||||
if (name.endsWith(TYPEGUARD_POSTFIX)) {
|
||||
let property = name.substr(0, name.length - TYPEGUARD_POSTFIX.length);
|
||||
let value: any;
|
||||
if (property.endsWith(USE_IF)) {
|
||||
property = name.substr(0, property.length - USE_IF.length);
|
||||
value = USE_IF;
|
||||
} else {
|
||||
value = this.getStaticSymbol(type.filePath, type.name, [name]);
|
||||
}
|
||||
result[property] = value;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private _registerDecoratorOrConstructor(type: StaticSymbol, ctor: any): void {
|
||||
this.conversionMap.set(type, (context: StaticSymbol, args: any[]) => new ctor(...args));
|
||||
}
|
||||
|
@ -98,10 +98,10 @@ export class StaticSymbolResolver {
|
||||
*
|
||||
* @param staticSymbol the symbol for which to generate a import symbol
|
||||
*/
|
||||
getImportAs(staticSymbol: StaticSymbol, useSummaries: boolean = true): StaticSymbol|null {
|
||||
getImportAs(staticSymbol: StaticSymbol): StaticSymbol|null {
|
||||
if (staticSymbol.members.length) {
|
||||
const baseSymbol = this.getStaticSymbol(staticSymbol.filePath, staticSymbol.name);
|
||||
const baseImportAs = this.getImportAs(baseSymbol, useSummaries);
|
||||
const baseImportAs = this.getImportAs(baseSymbol);
|
||||
return baseImportAs ?
|
||||
this.getStaticSymbol(baseImportAs.filePath, baseImportAs.name, staticSymbol.members) :
|
||||
null;
|
||||
@ -111,14 +111,14 @@ export class StaticSymbolResolver {
|
||||
const summarizedName = stripSummaryForJitNameSuffix(staticSymbol.name);
|
||||
const baseSymbol =
|
||||
this.getStaticSymbol(summarizedFileName, summarizedName, staticSymbol.members);
|
||||
const baseImportAs = this.getImportAs(baseSymbol, useSummaries);
|
||||
const baseImportAs = this.getImportAs(baseSymbol);
|
||||
return baseImportAs ?
|
||||
this.getStaticSymbol(
|
||||
summaryForJitFileName(baseImportAs.filePath), summaryForJitName(baseImportAs.name),
|
||||
baseSymbol.members) :
|
||||
null;
|
||||
}
|
||||
let result = (useSummaries && this.summaryResolver.getImportAs(staticSymbol)) || null;
|
||||
let result = this.summaryResolver.getImportAs(staticSymbol);
|
||||
if (!result) {
|
||||
result = this.importAs.get(staticSymbol) !;
|
||||
}
|
||||
@ -481,7 +481,7 @@ export class StaticSymbolResolver {
|
||||
if (moduleMetadatas) {
|
||||
let maxVersion = -1;
|
||||
moduleMetadatas.forEach((md) => {
|
||||
if (md['version'] > maxVersion) {
|
||||
if (md && md['version'] > maxVersion) {
|
||||
maxVersion = md['version'];
|
||||
moduleMetadata = md;
|
||||
}
|
||||
|
@ -254,7 +254,6 @@ export interface CompileDirectiveSummary extends CompileTypeSummary {
|
||||
providers: CompileProviderMetadata[];
|
||||
viewProviders: CompileProviderMetadata[];
|
||||
queries: CompileQueryMetadata[];
|
||||
guards: {[key: string]: any};
|
||||
viewQueries: CompileQueryMetadata[];
|
||||
entryComponents: CompileEntryComponentMetadata[];
|
||||
changeDetection: ChangeDetectionStrategy|null;
|
||||
@ -269,8 +268,8 @@ export interface CompileDirectiveSummary extends CompileTypeSummary {
|
||||
*/
|
||||
export class CompileDirectiveMetadata {
|
||||
static create({isHost, type, isComponent, selector, exportAs, changeDetection, inputs, outputs,
|
||||
host, providers, viewProviders, queries, guards, viewQueries, entryComponents,
|
||||
template, componentViewType, rendererType, componentFactory}: {
|
||||
host, providers, viewProviders, queries, viewQueries, entryComponents, template,
|
||||
componentViewType, rendererType, componentFactory}: {
|
||||
isHost: boolean,
|
||||
type: CompileTypeMetadata,
|
||||
isComponent: boolean,
|
||||
@ -283,7 +282,6 @@ export class CompileDirectiveMetadata {
|
||||
providers: CompileProviderMetadata[],
|
||||
viewProviders: CompileProviderMetadata[],
|
||||
queries: CompileQueryMetadata[],
|
||||
guards: {[key: string]: any};
|
||||
viewQueries: CompileQueryMetadata[],
|
||||
entryComponents: CompileEntryComponentMetadata[],
|
||||
template: CompileTemplateMetadata,
|
||||
@ -338,7 +336,6 @@ export class CompileDirectiveMetadata {
|
||||
providers,
|
||||
viewProviders,
|
||||
queries,
|
||||
guards,
|
||||
viewQueries,
|
||||
entryComponents,
|
||||
template,
|
||||
@ -361,7 +358,6 @@ export class CompileDirectiveMetadata {
|
||||
providers: CompileProviderMetadata[];
|
||||
viewProviders: CompileProviderMetadata[];
|
||||
queries: CompileQueryMetadata[];
|
||||
guards: {[key: string]: any};
|
||||
viewQueries: CompileQueryMetadata[];
|
||||
entryComponents: CompileEntryComponentMetadata[];
|
||||
|
||||
@ -371,27 +367,10 @@ export class CompileDirectiveMetadata {
|
||||
rendererType: StaticSymbol|object|null;
|
||||
componentFactory: StaticSymbol|object|null;
|
||||
|
||||
constructor({isHost,
|
||||
type,
|
||||
isComponent,
|
||||
selector,
|
||||
exportAs,
|
||||
changeDetection,
|
||||
inputs,
|
||||
outputs,
|
||||
hostListeners,
|
||||
hostProperties,
|
||||
hostAttributes,
|
||||
providers,
|
||||
viewProviders,
|
||||
queries,
|
||||
guards,
|
||||
viewQueries,
|
||||
entryComponents,
|
||||
template,
|
||||
componentViewType,
|
||||
rendererType,
|
||||
componentFactory}: {
|
||||
constructor({isHost, type, isComponent, selector, exportAs,
|
||||
changeDetection, inputs, outputs, hostListeners, hostProperties,
|
||||
hostAttributes, providers, viewProviders, queries, viewQueries,
|
||||
entryComponents, template, componentViewType, rendererType, componentFactory}: {
|
||||
isHost: boolean,
|
||||
type: CompileTypeMetadata,
|
||||
isComponent: boolean,
|
||||
@ -406,7 +385,6 @@ export class CompileDirectiveMetadata {
|
||||
providers: CompileProviderMetadata[],
|
||||
viewProviders: CompileProviderMetadata[],
|
||||
queries: CompileQueryMetadata[],
|
||||
guards: {[key: string]: any},
|
||||
viewQueries: CompileQueryMetadata[],
|
||||
entryComponents: CompileEntryComponentMetadata[],
|
||||
template: CompileTemplateMetadata|null,
|
||||
@ -428,7 +406,6 @@ export class CompileDirectiveMetadata {
|
||||
this.providers = _normalizeArray(providers);
|
||||
this.viewProviders = _normalizeArray(viewProviders);
|
||||
this.queries = _normalizeArray(queries);
|
||||
this.guards = guards;
|
||||
this.viewQueries = _normalizeArray(viewQueries);
|
||||
this.entryComponents = _normalizeArray(entryComponents);
|
||||
this.template = template;
|
||||
@ -453,7 +430,6 @@ export class CompileDirectiveMetadata {
|
||||
providers: this.providers,
|
||||
viewProviders: this.viewProviders,
|
||||
queries: this.queries,
|
||||
guards: this.guards,
|
||||
viewQueries: this.viewQueries,
|
||||
entryComponents: this.entryComponents,
|
||||
changeDetection: this.changeDetection,
|
||||
|
@ -17,7 +17,6 @@ export abstract class CompileReflector {
|
||||
abstract annotations(typeOrFunc: /*Type*/ any): any[];
|
||||
abstract propMetadata(typeOrFunc: /*Type*/ any): {[key: string]: any[]};
|
||||
abstract hasLifecycleHook(type: any, lcProperty: string): boolean;
|
||||
abstract guards(typeOrFunc: /* Type */ any): {[key: string]: any};
|
||||
abstract componentModuleUrl(type: /*Type*/ any, cmpMetadata: Component): string;
|
||||
abstract resolveExternalReference(ref: o.ExternalReference): any;
|
||||
}
|
||||
|
@ -90,14 +90,6 @@ export class ConvertPropertyBindingResult {
|
||||
constructor(public stmts: o.Statement[], public currValExpr: o.Expression) {}
|
||||
}
|
||||
|
||||
export enum BindingForm {
|
||||
// The general form of binding expression, supports all expressions.
|
||||
General,
|
||||
|
||||
// Try to generate a simple binding (no temporaries or statements)
|
||||
// otherise generate a general binding
|
||||
TrySimple,
|
||||
}
|
||||
/**
|
||||
* Converts the given expression AST into an executable output AST, assuming the expression
|
||||
* is used in property binding. The expression has to be preprocessed via
|
||||
@ -105,8 +97,7 @@ export enum BindingForm {
|
||||
*/
|
||||
export function convertPropertyBinding(
|
||||
localResolver: LocalResolver | null, implicitReceiver: o.Expression,
|
||||
expressionWithoutBuiltins: cdAst.AST, bindingId: string,
|
||||
form: BindingForm): ConvertPropertyBindingResult {
|
||||
expressionWithoutBuiltins: cdAst.AST, bindingId: string): ConvertPropertyBindingResult {
|
||||
if (!localResolver) {
|
||||
localResolver = new DefaultLocalResolver();
|
||||
}
|
||||
@ -119,11 +110,9 @@ export function convertPropertyBinding(
|
||||
for (let i = 0; i < visitor.temporaryCount; i++) {
|
||||
stmts.push(temporaryDeclaration(bindingId, i));
|
||||
}
|
||||
} else if (form == BindingForm.TrySimple) {
|
||||
return new ConvertPropertyBindingResult([], outputExpr);
|
||||
}
|
||||
|
||||
stmts.push(currValExpr.set(outputExpr).toDeclStmt(o.DYNAMIC_TYPE, [o.StmtModifier.Final]));
|
||||
stmts.push(currValExpr.set(outputExpr).toDeclStmt(null, [o.StmtModifier.Final]));
|
||||
return new ConvertPropertyBindingResult(stmts, currValExpr);
|
||||
}
|
||||
|
||||
@ -334,27 +323,12 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
|
||||
}
|
||||
|
||||
visitLiteralPrimitive(ast: cdAst.LiteralPrimitive, mode: _Mode): any {
|
||||
// For literal values of null, undefined, true, or false allow type inteference
|
||||
// to infer the type.
|
||||
const type =
|
||||
ast.value === null || ast.value === undefined || ast.value === true || ast.value === true ?
|
||||
o.INFERRED_TYPE :
|
||||
undefined;
|
||||
return convertToStatementIfNeeded(mode, o.literal(ast.value, type));
|
||||
return convertToStatementIfNeeded(mode, o.literal(ast.value));
|
||||
}
|
||||
|
||||
private _getLocal(name: string): o.Expression|null { return this._localResolver.getLocal(name); }
|
||||
|
||||
visitMethodCall(ast: cdAst.MethodCall, mode: _Mode): any {
|
||||
if (ast.receiver instanceof cdAst.ImplicitReceiver && ast.name == '$any') {
|
||||
const args = this.visitAll(ast.args, _Mode.Expression) as any[];
|
||||
if (args.length != 1) {
|
||||
throw new Error(
|
||||
`Invalid call to $any, expected 1 argument but received ${args.length || 'none'}`);
|
||||
}
|
||||
return (args[0] as o.Expression).cast(o.DYNAMIC_TYPE);
|
||||
}
|
||||
|
||||
const leftMostSafe = this.leftMostSafeNode(ast);
|
||||
if (leftMostSafe) {
|
||||
return this.convertSafeAccess(ast, leftMostSafe, mode);
|
||||
|
@ -51,7 +51,6 @@ export interface Directive {
|
||||
providers?: Provider[];
|
||||
exportAs?: string;
|
||||
queries?: {[key: string]: any};
|
||||
guards?: {[key: string]: any};
|
||||
}
|
||||
export const createDirective =
|
||||
makeMetadataFactory<Directive>('Directive', (dir: Directive = {}) => dir);
|
||||
|
@ -44,8 +44,7 @@ export class DirectiveResolver {
|
||||
const metadata = findLast(typeMetadata, isDirectiveMetadata);
|
||||
if (metadata) {
|
||||
const propertyMetadata = this._reflector.propMetadata(type);
|
||||
const guards = this._reflector.guards(type);
|
||||
return this._mergeWithPropertyMetadata(metadata, propertyMetadata, guards, type);
|
||||
return this._mergeWithPropertyMetadata(metadata, propertyMetadata, type);
|
||||
}
|
||||
}
|
||||
|
||||
@ -57,12 +56,12 @@ export class DirectiveResolver {
|
||||
}
|
||||
|
||||
private _mergeWithPropertyMetadata(
|
||||
dm: Directive, propertyMetadata: {[key: string]: any[]}, guards: {[key: string]: any},
|
||||
directiveType: Type): Directive {
|
||||
dm: Directive, propertyMetadata: {[key: string]: any[]}, directiveType: Type): Directive {
|
||||
const inputs: string[] = [];
|
||||
const outputs: string[] = [];
|
||||
const host: {[key: string]: string} = {};
|
||||
const queries: {[key: string]: any} = {};
|
||||
|
||||
Object.keys(propertyMetadata).forEach((propName: string) => {
|
||||
const input = findLast(propertyMetadata[propName], (a) => createInput.isTypeOf(a));
|
||||
if (input) {
|
||||
@ -106,20 +105,18 @@ export class DirectiveResolver {
|
||||
queries[propName] = query;
|
||||
}
|
||||
});
|
||||
return this._merge(dm, inputs, outputs, host, queries, guards, directiveType);
|
||||
return this._merge(dm, inputs, outputs, host, queries, directiveType);
|
||||
}
|
||||
|
||||
private _extractPublicName(def: string) { return splitAtColon(def, [null !, def])[1].trim(); }
|
||||
|
||||
private _dedupeBindings(bindings: string[]): string[] {
|
||||
const names = new Set<string>();
|
||||
const publicNames = new Set<string>();
|
||||
const reversedResult: string[] = [];
|
||||
// go last to first to allow later entries to overwrite previous entries
|
||||
for (let i = bindings.length - 1; i >= 0; i--) {
|
||||
const binding = bindings[i];
|
||||
const name = this._extractPublicName(binding);
|
||||
publicNames.add(name);
|
||||
if (!names.has(name)) {
|
||||
names.add(name);
|
||||
reversedResult.push(binding);
|
||||
@ -130,13 +127,14 @@ export class DirectiveResolver {
|
||||
|
||||
private _merge(
|
||||
directive: Directive, inputs: string[], outputs: string[], host: {[key: string]: string},
|
||||
queries: {[key: string]: any}, guards: {[key: string]: any}, directiveType: Type): Directive {
|
||||
queries: {[key: string]: any}, directiveType: Type): Directive {
|
||||
const mergedInputs =
|
||||
this._dedupeBindings(directive.inputs ? directive.inputs.concat(inputs) : inputs);
|
||||
const mergedOutputs =
|
||||
this._dedupeBindings(directive.outputs ? directive.outputs.concat(outputs) : outputs);
|
||||
const mergedHost = directive.host ? {...directive.host, ...host} : host;
|
||||
const mergedQueries = directive.queries ? {...directive.queries, ...queries} : queries;
|
||||
|
||||
if (createComponent.isTypeOf(directive)) {
|
||||
const comp = directive as Component;
|
||||
return createComponent({
|
||||
@ -168,7 +166,7 @@ export class DirectiveResolver {
|
||||
host: mergedHost,
|
||||
exportAs: directive.exportAs,
|
||||
queries: mergedQueries,
|
||||
providers: directive.providers, guards
|
||||
providers: directive.providers
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -208,7 +208,6 @@ export class CompileMetadataResolver {
|
||||
providers: [],
|
||||
viewProviders: [],
|
||||
queries: [],
|
||||
guards: {},
|
||||
viewQueries: [],
|
||||
componentViewType: hostViewType,
|
||||
rendererType:
|
||||
@ -241,7 +240,6 @@ export class CompileMetadataResolver {
|
||||
providers: metadata.providers,
|
||||
viewProviders: metadata.viewProviders,
|
||||
queries: metadata.queries,
|
||||
guards: metadata.guards,
|
||||
viewQueries: metadata.viewQueries,
|
||||
entryComponents: metadata.entryComponents,
|
||||
componentViewType: metadata.componentViewType,
|
||||
@ -385,7 +383,6 @@ export class CompileMetadataResolver {
|
||||
providers: providers || [],
|
||||
viewProviders: viewProviders || [],
|
||||
queries: queries || [],
|
||||
guards: dirMeta.guards || {},
|
||||
viewQueries: viewQueries || [],
|
||||
entryComponents: entryComponentMetadata,
|
||||
componentViewType: nonNormalizedTemplateMetadata ? this.getComponentViewClass(directiveType) :
|
||||
|
@ -152,7 +152,7 @@ export function utf8Encode(str: string): string {
|
||||
export interface OutputContext {
|
||||
genFilePath: string;
|
||||
statements: o.Statement[];
|
||||
importExpr(reference: any, typeParams?: o.Type[]|null, useSummaries?: boolean): o.Expression;
|
||||
importExpr(reference: any, typeParams?: o.Type[]|null): o.Expression;
|
||||
}
|
||||
|
||||
export function stringify(token: any): string {
|
||||
|
@ -10,15 +10,13 @@ import {AotCompilerOptions} from '../aot/compiler_options';
|
||||
import {StaticReflector} from '../aot/static_reflector';
|
||||
import {StaticSymbol} from '../aot/static_symbol';
|
||||
import {CompileDiDependencyMetadata, CompileDirectiveMetadata, CompilePipeSummary} from '../compile_metadata';
|
||||
import {BindingForm, BuiltinConverter, EventHandlerVars, LocalResolver, convertActionBinding, convertPropertyBinding, convertPropertyBindingBuiltins} from '../compiler_util/expression_converter';
|
||||
import {BuiltinConverter, EventHandlerVars, LocalResolver, convertActionBinding, convertPropertyBinding, convertPropertyBindingBuiltins} from '../compiler_util/expression_converter';
|
||||
import {AST, ASTWithSource, Interpolation} from '../expression_parser/ast';
|
||||
import {Identifiers} from '../identifiers';
|
||||
import * as o from '../output/output_ast';
|
||||
import {convertValueToOutputAst} from '../output/value_util';
|
||||
import {ParseSourceSpan} from '../parse_util';
|
||||
import {AttrAst, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, DirectiveAst, ElementAst, EmbeddedTemplateAst, NgContentAst, PropertyBindingType, ProviderAst, ProviderAstType, QueryMatch, ReferenceAst, TemplateAst, TemplateAstVisitor, TextAst, VariableAst, templateVisitAll} from '../template_parser/template_ast';
|
||||
import {OutputContext} from '../util';
|
||||
|
||||
|
||||
/**
|
||||
* Generates code that is used to type check templates.
|
||||
@ -36,34 +34,27 @@ export class TypeCheckCompiler {
|
||||
*/
|
||||
compileComponent(
|
||||
componentId: string, component: CompileDirectiveMetadata, template: TemplateAst[],
|
||||
usedPipes: CompilePipeSummary[], externalReferenceVars: Map<StaticSymbol, string>,
|
||||
ctx: OutputContext): o.Statement[] {
|
||||
usedPipes: CompilePipeSummary[],
|
||||
externalReferenceVars: Map<StaticSymbol, string>): o.Statement[] {
|
||||
const pipes = new Map<string, StaticSymbol>();
|
||||
usedPipes.forEach(p => pipes.set(p.name, p.type.reference));
|
||||
let embeddedViewCount = 0;
|
||||
const viewBuilderFactory =
|
||||
(parent: ViewBuilder | null, guards: GuardExpression[]): ViewBuilder => {
|
||||
const embeddedViewIndex = embeddedViewCount++;
|
||||
return new ViewBuilder(
|
||||
this.options, this.reflector, externalReferenceVars, parent, component.type.reference,
|
||||
component.isHost, embeddedViewIndex, pipes, guards, ctx, viewBuilderFactory);
|
||||
};
|
||||
const viewBuilderFactory = (parent: ViewBuilder | null): ViewBuilder => {
|
||||
const embeddedViewIndex = embeddedViewCount++;
|
||||
return new ViewBuilder(
|
||||
this.options, this.reflector, externalReferenceVars, parent, component.type.reference,
|
||||
component.isHost, embeddedViewIndex, pipes, viewBuilderFactory);
|
||||
};
|
||||
|
||||
const visitor = viewBuilderFactory(null, []);
|
||||
const visitor = viewBuilderFactory(null);
|
||||
visitor.visitAll([], template);
|
||||
|
||||
return visitor.build(componentId);
|
||||
}
|
||||
}
|
||||
|
||||
interface GuardExpression {
|
||||
guard: StaticSymbol;
|
||||
useIf: boolean;
|
||||
expression: Expression;
|
||||
}
|
||||
|
||||
interface ViewBuilderFactory {
|
||||
(parent: ViewBuilder, guards: GuardExpression[]): ViewBuilder;
|
||||
(parent: ViewBuilder): ViewBuilder;
|
||||
}
|
||||
|
||||
// Note: This is used as key in Map and should therefore be
|
||||
@ -103,7 +94,6 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
|
||||
private externalReferenceVars: Map<StaticSymbol, string>, private parent: ViewBuilder|null,
|
||||
private component: StaticSymbol, private isHostComponent: boolean,
|
||||
private embeddedViewIndex: number, private pipes: Map<string, StaticSymbol>,
|
||||
private guards: GuardExpression[], private ctx: OutputContext,
|
||||
private viewBuilderFactory: ViewBuilderFactory) {}
|
||||
|
||||
private getOutputVar(type: o.BuiltinTypeName|StaticSymbol): string {
|
||||
@ -122,24 +112,6 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
|
||||
return varName;
|
||||
}
|
||||
|
||||
private getTypeGuardExpressions(ast: EmbeddedTemplateAst): GuardExpression[] {
|
||||
const result = [...this.guards];
|
||||
for (let directive of ast.directives) {
|
||||
for (let input of directive.inputs) {
|
||||
const guard = directive.directive.guards[input.directiveName];
|
||||
if (guard) {
|
||||
const useIf = guard === 'UseIf';
|
||||
result.push({
|
||||
guard,
|
||||
useIf,
|
||||
expression: {context: this.component, value: input.value} as Expression
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
visitAll(variables: VariableAst[], astNodes: TemplateAst[]) {
|
||||
this.variables = variables;
|
||||
templateVisitAll(this, astNodes);
|
||||
@ -147,7 +119,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
|
||||
|
||||
build(componentId: string, targetStatements: o.Statement[] = []): o.Statement[] {
|
||||
this.children.forEach((child) => child.build(componentId, targetStatements));
|
||||
let viewStmts: o.Statement[] =
|
||||
const viewStmts: o.Statement[] =
|
||||
[o.variable(DYNAMIC_VAR_NAME).set(o.NULL_EXPR).toDeclStmt(o.DYNAMIC_TYPE)];
|
||||
let bindingCount = 0;
|
||||
this.updates.forEach((expression) => {
|
||||
@ -155,8 +127,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
|
||||
const bindingId = `${bindingCount++}`;
|
||||
const nameResolver = context === this.component ? this : defaultResolver;
|
||||
const {stmts, currValExpr} = convertPropertyBinding(
|
||||
nameResolver, o.variable(this.getOutputVar(context)), value, bindingId,
|
||||
BindingForm.General);
|
||||
nameResolver, o.variable(this.getOutputVar(context)), value, bindingId);
|
||||
stmts.push(new o.ExpressionStatement(currValExpr));
|
||||
viewStmts.push(...stmts.map(
|
||||
(stmt: o.Statement) => o.applySourceSpanToStatementIfNeeded(stmt, sourceSpan)));
|
||||
@ -171,28 +142,6 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
|
||||
(stmt: o.Statement) => o.applySourceSpanToStatementIfNeeded(stmt, sourceSpan)));
|
||||
});
|
||||
|
||||
if (this.guards.length) {
|
||||
let guardExpression: o.Expression|undefined = undefined;
|
||||
for (const guard of this.guards) {
|
||||
const {context, value} = this.preprocessUpdateExpression(guard.expression);
|
||||
const bindingId = `${bindingCount++}`;
|
||||
const nameResolver = context === this.component ? this : defaultResolver;
|
||||
// We only support support simple expressions and ignore others as they
|
||||
// are unlikely to affect type narrowing.
|
||||
const {stmts, currValExpr} = convertPropertyBinding(
|
||||
nameResolver, o.variable(this.getOutputVar(context)), value, bindingId,
|
||||
BindingForm.TrySimple);
|
||||
if (stmts.length == 0) {
|
||||
const guardClause =
|
||||
guard.useIf ? currValExpr : this.ctx.importExpr(guard.guard).callFn([currValExpr]);
|
||||
guardExpression = guardExpression ? guardExpression.and(guardClause) : guardClause;
|
||||
}
|
||||
}
|
||||
if (guardExpression) {
|
||||
viewStmts = [new o.IfStmt(guardExpression, viewStmts)];
|
||||
}
|
||||
}
|
||||
|
||||
const viewName = `_View_${componentId}_${this.embeddedViewIndex}`;
|
||||
const viewFactory = new o.DeclareFunctionStmt(viewName, [], viewStmts);
|
||||
targetStatements.push(viewFactory);
|
||||
@ -214,12 +163,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
|
||||
// for the context in any embedded view.
|
||||
// We keep this behaivor behind a flag for now.
|
||||
if (this.options.fullTemplateTypeCheck) {
|
||||
// Find any applicable type guards. For example, NgIf has a type guard on ngIf
|
||||
// (see NgIf.ngIfTypeGuard) that can be used to indicate that a template is only
|
||||
// stamped out if ngIf is truthy so any bindings in the template can assume that,
|
||||
// if a nullable type is used for ngIf, that expression is not null or undefined.
|
||||
const guards = this.getTypeGuardExpressions(ast);
|
||||
const childVisitor = this.viewBuilderFactory(this, guards);
|
||||
const childVisitor = this.viewBuilderFactory(this);
|
||||
this.children.push(childVisitor);
|
||||
childVisitor.visitAll(ast.variables, ast.children);
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
import {CompileDirectiveMetadata, CompilePipeSummary, rendererTypeName, tokenReference, viewClassName} from '../compile_metadata';
|
||||
import {CompileReflector} from '../compile_reflector';
|
||||
import {BindingForm, BuiltinConverter, EventHandlerVars, LocalResolver, convertActionBinding, convertPropertyBinding, convertPropertyBindingBuiltins} from '../compiler_util/expression_converter';
|
||||
import {BuiltinConverter, EventHandlerVars, LocalResolver, convertActionBinding, convertPropertyBinding, convertPropertyBindingBuiltins} from '../compiler_util/expression_converter';
|
||||
import {ArgumentType, BindingFlags, ChangeDetectionStrategy, NodeFlags, QueryBindingType, QueryValueType, ViewFlags} from '../core';
|
||||
import {AST, ASTWithSource, Interpolation} from '../expression_parser/ast';
|
||||
import {Identifiers} from '../identifiers';
|
||||
@ -859,7 +859,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
|
||||
const bindingId = `${updateBindingCount++}`;
|
||||
const nameResolver = context === COMP_VAR ? self : null;
|
||||
const {stmts, currValExpr} =
|
||||
convertPropertyBinding(nameResolver, context, value, bindingId, BindingForm.General);
|
||||
convertPropertyBinding(nameResolver, context, value, bindingId);
|
||||
updateStmts.push(...stmts.map(
|
||||
(stmt: o.Statement) => o.applySourceSpanToStatementIfNeeded(stmt, sourceSpan)));
|
||||
return o.applySourceSpanToExpressionIfNeeded(currValExpr, sourceSpan);
|
||||
|
@ -196,25 +196,6 @@ describe('StaticSymbolResolver', () => {
|
||||
.toBe(symbolCache.get('/test3.d.ts', 'b'));
|
||||
});
|
||||
|
||||
it('should ignore summaries for inputAs if requested', () => {
|
||||
init(
|
||||
{
|
||||
'/test.ts': `
|
||||
export {a} from './test2';
|
||||
`
|
||||
},
|
||||
[], [{
|
||||
symbol: symbolCache.get('/test2.d.ts', 'a'),
|
||||
importAs: symbolCache.get('/test3.d.ts', 'b')
|
||||
}]);
|
||||
|
||||
symbolResolver.getSymbolsOf('/test.ts');
|
||||
|
||||
expect(
|
||||
symbolResolver.getImportAs(symbolCache.get('/test2.d.ts', 'a'), /* useSummaries */ false))
|
||||
.toBeUndefined();
|
||||
});
|
||||
|
||||
it('should calculate importAs for symbols with members based on importAs for symbols without',
|
||||
() => {
|
||||
init(
|
||||
|
@ -126,7 +126,6 @@ export function main() {
|
||||
outputs: [],
|
||||
host: {},
|
||||
queries: {},
|
||||
guards: {},
|
||||
exportAs: undefined,
|
||||
providers: undefined
|
||||
}));
|
||||
@ -155,7 +154,6 @@ export function main() {
|
||||
outputs: [],
|
||||
host: {},
|
||||
queries: {},
|
||||
guards: {},
|
||||
exportAs: undefined,
|
||||
providers: undefined
|
||||
}));
|
||||
@ -166,7 +164,6 @@ export function main() {
|
||||
outputs: [],
|
||||
host: {},
|
||||
queries: {},
|
||||
guards: {},
|
||||
exportAs: undefined,
|
||||
providers: undefined
|
||||
}));
|
||||
|
@ -38,29 +38,28 @@ function createTypeMeta({reference, diDeps}: {reference: any, diDeps?: any[]}):
|
||||
return {reference: reference, diDeps: diDeps || [], lifecycleHooks: []};
|
||||
}
|
||||
|
||||
function compileDirectiveMetadataCreate(
|
||||
{isHost, type, isComponent, selector, exportAs, changeDetection, inputs, outputs, host,
|
||||
providers, viewProviders, queries, guards, viewQueries, entryComponents, template,
|
||||
componentViewType, rendererType}: {
|
||||
isHost?: boolean,
|
||||
type?: CompileTypeMetadata,
|
||||
isComponent?: boolean,
|
||||
selector?: string | null,
|
||||
exportAs?: string | null,
|
||||
changeDetection?: ChangeDetectionStrategy | null,
|
||||
inputs?: string[],
|
||||
outputs?: string[],
|
||||
host?: {[key: string]: string},
|
||||
providers?: CompileProviderMetadata[] | null,
|
||||
viewProviders?: CompileProviderMetadata[] | null,
|
||||
queries?: CompileQueryMetadata[] | null,
|
||||
guards?: {[key: string]: any},
|
||||
viewQueries?: CompileQueryMetadata[],
|
||||
entryComponents?: CompileEntryComponentMetadata[],
|
||||
template?: CompileTemplateMetadata,
|
||||
componentViewType?: StaticSymbol | ProxyClass | null,
|
||||
rendererType?: StaticSymbol | RendererType2 | null,
|
||||
}) {
|
||||
function compileDirectiveMetadataCreate({isHost, type, isComponent, selector, exportAs,
|
||||
changeDetection, inputs, outputs, host, providers,
|
||||
viewProviders, queries, viewQueries, entryComponents,
|
||||
template, componentViewType, rendererType}: {
|
||||
isHost?: boolean,
|
||||
type?: CompileTypeMetadata,
|
||||
isComponent?: boolean,
|
||||
selector?: string | null,
|
||||
exportAs?: string | null,
|
||||
changeDetection?: ChangeDetectionStrategy | null,
|
||||
inputs?: string[],
|
||||
outputs?: string[],
|
||||
host?: {[key: string]: string},
|
||||
providers?: CompileProviderMetadata[] | null,
|
||||
viewProviders?: CompileProviderMetadata[] | null,
|
||||
queries?: CompileQueryMetadata[] | null,
|
||||
viewQueries?: CompileQueryMetadata[],
|
||||
entryComponents?: CompileEntryComponentMetadata[],
|
||||
template?: CompileTemplateMetadata,
|
||||
componentViewType?: StaticSymbol | ProxyClass | null,
|
||||
rendererType?: StaticSymbol | RendererType2 | null,
|
||||
}) {
|
||||
return CompileDirectiveMetadata.create({
|
||||
isHost: !!isHost,
|
||||
type: noUndefined(type) !,
|
||||
@ -74,7 +73,6 @@ function compileDirectiveMetadataCreate(
|
||||
providers: providers || [],
|
||||
viewProviders: viewProviders || [],
|
||||
queries: queries || [],
|
||||
guards: guards || {},
|
||||
viewQueries: viewQueries || [],
|
||||
entryComponents: entryComponents || [],
|
||||
template: noUndefined(template) !,
|
||||
@ -392,7 +390,6 @@ export function main() {
|
||||
providers: [],
|
||||
viewProviders: [],
|
||||
queries: [],
|
||||
guards: {},
|
||||
viewQueries: [],
|
||||
entryComponents: [],
|
||||
componentViewType: null,
|
||||
|
@ -102,8 +102,7 @@ export function createPlatformFactory(
|
||||
parentPlatformFactory: ((extraProviders?: StaticProvider[]) => PlatformRef) | null,
|
||||
name: string, providers: StaticProvider[] = []): (extraProviders?: StaticProvider[]) =>
|
||||
PlatformRef {
|
||||
const desc = `Platform: ${name}`;
|
||||
const marker = new InjectionToken(desc);
|
||||
const marker = new InjectionToken(`Platform: ${name}`);
|
||||
return (extraProviders: StaticProvider[] = []) => {
|
||||
let platform = getPlatform();
|
||||
if (!platform || platform.injector.get(ALLOW_MULTIPLE_PLATFORMS, false)) {
|
||||
@ -111,9 +110,8 @@ export function createPlatformFactory(
|
||||
parentPlatformFactory(
|
||||
providers.concat(extraProviders).concat({provide: marker, useValue: true}));
|
||||
} else {
|
||||
const injectedProviders: StaticProvider[] =
|
||||
providers.concat(extraProviders).concat({provide: marker, useValue: true});
|
||||
createPlatform(Injector.create({providers: injectedProviders, name: desc}));
|
||||
createPlatform(Injector.create(
|
||||
providers.concat(extraProviders).concat({provide: marker, useValue: true})));
|
||||
}
|
||||
}
|
||||
return assertPlatform(marker);
|
||||
@ -226,12 +224,10 @@ export class PlatformRef {
|
||||
// pass that as parent to the NgModuleFactory.
|
||||
const ngZoneOption = options ? options.ngZone : undefined;
|
||||
const ngZone = getNgZone(ngZoneOption);
|
||||
const providers: StaticProvider[] = [{provide: NgZone, useValue: ngZone}];
|
||||
// Attention: Don't use ApplicationRef.run here,
|
||||
// as we want to be sure that all possible constructor calls are inside `ngZone.run`!
|
||||
return ngZone.run(() => {
|
||||
const ngZoneInjector = Injector.create(
|
||||
{providers: providers, parent: this.injector, name: moduleFactory.moduleType.name});
|
||||
const ngZoneInjector = Injector.create([{provide: NgZone, useValue: ngZone}], this.injector);
|
||||
const moduleRef = <InternalNgModuleRef<M>>moduleFactory.create(ngZoneInjector);
|
||||
const exceptionHandler: ErrorHandler = moduleRef.injector.get(ErrorHandler, null);
|
||||
if (!exceptionHandler) {
|
||||
|
@ -8,12 +8,12 @@
|
||||
|
||||
import {Type} from '../type';
|
||||
import {stringify} from '../util';
|
||||
|
||||
import {resolveForwardRef} from './forward_ref';
|
||||
import {InjectionToken} from './injection_token';
|
||||
import {Inject, Optional, Self, SkipSelf} from './metadata';
|
||||
import {ConstructorProvider, ExistingProvider, FactoryProvider, StaticClassProvider, StaticProvider, ValueProvider} from './provider';
|
||||
|
||||
export const SOURCE = '__source';
|
||||
const _THROW_IF_NOT_FOUND = new Object();
|
||||
export const THROW_IF_NOT_FOUND = _THROW_IF_NOT_FOUND;
|
||||
|
||||
@ -64,13 +64,6 @@ export abstract class Injector {
|
||||
*/
|
||||
abstract get(token: any, notFoundValue?: any): any;
|
||||
|
||||
/**
|
||||
* @deprecated from v5 use the new signature Injector.create(options)
|
||||
*/
|
||||
static create(providers: StaticProvider[], parent?: Injector): Injector;
|
||||
|
||||
static create(options: {providers: StaticProvider[], parent?: Injector, name?: string}): Injector;
|
||||
|
||||
/**
|
||||
* Create a new Injector which is configure using `StaticProvider`s.
|
||||
*
|
||||
@ -78,14 +71,8 @@ export abstract class Injector {
|
||||
*
|
||||
* {@example core/di/ts/provider_spec.ts region='ConstructorProvider'}
|
||||
*/
|
||||
static create(
|
||||
options: StaticProvider[]|{providers: StaticProvider[], parent?: Injector, name?: string},
|
||||
parent?: Injector): Injector {
|
||||
if (Array.isArray(options)) {
|
||||
return new StaticInjector(options, parent);
|
||||
} else {
|
||||
return new StaticInjector(options.providers, options.parent, options.name || null);
|
||||
}
|
||||
static create(providers: StaticProvider[], parent?: Injector): Injector {
|
||||
return new StaticInjector(providers, parent);
|
||||
}
|
||||
}
|
||||
|
||||
@ -116,14 +103,11 @@ const NO_NEW_LINE = 'ɵ';
|
||||
|
||||
export class StaticInjector implements Injector {
|
||||
readonly parent: Injector;
|
||||
readonly source: string|null;
|
||||
|
||||
private _records: Map<any, Record>;
|
||||
|
||||
constructor(
|
||||
providers: StaticProvider[], parent: Injector = NULL_INJECTOR, source: string|null = null) {
|
||||
constructor(providers: StaticProvider[], parent: Injector = NULL_INJECTOR) {
|
||||
this.parent = parent;
|
||||
this.source = source;
|
||||
const records = this._records = new Map<any, Record>();
|
||||
records.set(
|
||||
Injector, <Record>{token: Injector, fn: IDENT, deps: EMPTY, value: this, useNew: false});
|
||||
@ -138,10 +122,7 @@ export class StaticInjector implements Injector {
|
||||
return tryResolveToken(token, record, this._records, this.parent, notFoundValue);
|
||||
} catch (e) {
|
||||
const tokenPath: any[] = e[NG_TEMP_TOKEN_PATH];
|
||||
if (token[SOURCE]) {
|
||||
tokenPath.unshift(token[SOURCE]);
|
||||
}
|
||||
e.message = formatError('\n' + e.message, tokenPath, this.source);
|
||||
e.message = formatError('\n' + e.message, tokenPath);
|
||||
e[NG_TOKEN_PATH] = tokenPath;
|
||||
e[NG_TEMP_TOKEN_PATH] = null;
|
||||
throw e;
|
||||
@ -355,7 +336,7 @@ function computeDeps(provider: StaticProvider): DependencyRecord[] {
|
||||
return deps;
|
||||
}
|
||||
|
||||
function formatError(text: string, obj: any, source: string | null = null): string {
|
||||
function formatError(text: string, obj: any): string {
|
||||
text = text && text.charAt(0) === '\n' && text.charAt(1) == NO_NEW_LINE ? text.substr(2) : text;
|
||||
let context = stringify(obj);
|
||||
if (obj instanceof Array) {
|
||||
@ -371,7 +352,7 @@ function formatError(text: string, obj: any, source: string | null = null): stri
|
||||
}
|
||||
context = `{${parts.join(', ')}}`;
|
||||
}
|
||||
return `StaticInjectorError${source ? '(' + source + ')' : ''}[${context}]: ${text.replace(NEW_LINE, '\n ')}`;
|
||||
return `StaticInjectorError[${context}]: ${text.replace(NEW_LINE, '\n ')}`;
|
||||
}
|
||||
|
||||
function staticError(text: string, obj: any): Error {
|
||||
|
@ -71,13 +71,11 @@ export interface ResolvedReflectiveProvider {
|
||||
}
|
||||
|
||||
export class ResolvedReflectiveProvider_ implements ResolvedReflectiveProvider {
|
||||
readonly resolvedFactory: ResolvedReflectiveFactory;
|
||||
|
||||
constructor(
|
||||
public key: ReflectiveKey, public resolvedFactories: ResolvedReflectiveFactory[],
|
||||
public multiProvider: boolean) {
|
||||
this.resolvedFactory = this.resolvedFactories[0];
|
||||
}
|
||||
public multiProvider: boolean) {}
|
||||
|
||||
get resolvedFactory(): ResolvedReflectiveFactory { return this.resolvedFactories[0]; }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -66,20 +66,13 @@ export class CodegenComponentFactoryResolver implements ComponentFactoryResolver
|
||||
}
|
||||
|
||||
export class ComponentFactoryBoundToModule<C> extends ComponentFactory<C> {
|
||||
readonly selector: string;
|
||||
readonly componentType: Type<any>;
|
||||
readonly ngContentSelectors: string[];
|
||||
readonly inputs: {propName: string, templateName: string}[];
|
||||
readonly outputs: {propName: string, templateName: string}[];
|
||||
constructor(private factory: ComponentFactory<C>, private ngModule: NgModuleRef<any>) { super(); }
|
||||
|
||||
constructor(private factory: ComponentFactory<C>, private ngModule: NgModuleRef<any>) {
|
||||
super();
|
||||
this.selector = factory.selector;
|
||||
this.componentType = factory.componentType;
|
||||
this.ngContentSelectors = factory.ngContentSelectors;
|
||||
this.inputs = factory.inputs;
|
||||
this.outputs = factory.outputs;
|
||||
}
|
||||
get selector() { return this.factory.selector; }
|
||||
get componentType() { return this.factory.componentType; }
|
||||
get ngContentSelectors() { return this.factory.ngContentSelectors; }
|
||||
get inputs() { return this.factory.inputs; }
|
||||
get outputs() { return this.factory.outputs; }
|
||||
|
||||
create(
|
||||
injector: Injector, projectableNodes?: any[][], rootSelectorOrNode?: string|any,
|
||||
|
@ -41,9 +41,9 @@ export class QueryList<T>/* implements Iterable<T> */ {
|
||||
private _results: Array<T> = [];
|
||||
public readonly changes: Observable<any> = new EventEmitter();
|
||||
|
||||
readonly length: number;
|
||||
readonly first: T;
|
||||
readonly last: T;
|
||||
get length(): number { return this._results.length; }
|
||||
get first(): T { return this._results[0]; }
|
||||
get last(): T { return this._results[this.length - 1]; }
|
||||
|
||||
/**
|
||||
* See
|
||||
@ -98,9 +98,6 @@ export class QueryList<T>/* implements Iterable<T> */ {
|
||||
reset(res: Array<T|any[]>): void {
|
||||
this._results = flatten(res);
|
||||
(this as{dirty: boolean}).dirty = false;
|
||||
(this as{length: number}).length = this._results.length;
|
||||
(this as{last: T}).last = this._results[this.length - 1];
|
||||
(this as{first: T}).first = this._results[0];
|
||||
}
|
||||
|
||||
notifyOnChanges(): void { (this.changes as EventEmitter<any>).emit(this); }
|
||||
|
@ -13,7 +13,6 @@ export interface PlatformReflectionCapabilities {
|
||||
isReflectionEnabled(): boolean;
|
||||
factory(type: Type<any>): Function;
|
||||
hasLifecycleHook(type: any, lcProperty: string): boolean;
|
||||
guards(type: any): {[key: string]: any};
|
||||
|
||||
/**
|
||||
* Return a list of annotations/types for constructor parameters
|
||||
|
@ -207,8 +207,6 @@ export class ReflectionCapabilities implements PlatformReflectionCapabilities {
|
||||
return type instanceof Type && lcProperty in type.prototype;
|
||||
}
|
||||
|
||||
guards(type: any): {[key: string]: any} { return {}; }
|
||||
|
||||
getter(name: string): GetterFn { return <GetterFn>new Function('o', 'return o.' + name + ';'); }
|
||||
|
||||
setter(name: string): SetterFn {
|
||||
|
@ -9,7 +9,6 @@
|
||||
import {resolveForwardRef} from '../di/forward_ref';
|
||||
import {Injector} from '../di/injector';
|
||||
import {NgModuleRef} from '../linker/ng_module_factory';
|
||||
import {stringify} from '../util';
|
||||
|
||||
import {DepDef, DepFlags, NgModuleData, NgModuleDefinition, NgModuleProviderDef, NodeFlags} from './types';
|
||||
import {splitDepsDsl, tokenKey} from './util';
|
||||
@ -26,7 +25,7 @@ export function moduleProvideDef(
|
||||
// lowered the expression and then stopped evaluating it,
|
||||
// i.e. also didn't unwrap it.
|
||||
value = resolveForwardRef(value);
|
||||
const depDefs = splitDepsDsl(deps, stringify(token));
|
||||
const depDefs = splitDepsDsl(deps);
|
||||
return {
|
||||
// will bet set by the module definition
|
||||
index: -1,
|
||||
|
@ -12,7 +12,7 @@ import {ElementRef} from '../linker/element_ref';
|
||||
import {TemplateRef} from '../linker/template_ref';
|
||||
import {ViewContainerRef} from '../linker/view_container_ref';
|
||||
import {Renderer as RendererV1, Renderer2} from '../render/api';
|
||||
import {stringify} from '../util';
|
||||
|
||||
import {createChangeDetectorRef, createInjector, createRendererV1} from './refs';
|
||||
import {BindingDef, BindingFlags, DepDef, DepFlags, NodeDef, NodeFlags, OutputDef, OutputType, ProviderData, QueryValueType, Services, ViewData, ViewFlags, ViewState, asElementData, asProviderData, shouldCallLifecycleInitHook} from './types';
|
||||
import {calcBindingFlags, checkBinding, dispatchEvent, isComponentView, splitDepsDsl, splitMatchedQueriesDsl, tokenKey, viewParentEl} from './util';
|
||||
@ -83,7 +83,7 @@ export function _def(
|
||||
// i.e. also didn't unwrap it.
|
||||
value = resolveForwardRef(value);
|
||||
|
||||
const depDefs = splitDepsDsl(deps, stringify(token));
|
||||
const depDefs = splitDepsDsl(deps);
|
||||
|
||||
return {
|
||||
// will bet set by the view definition
|
||||
|
@ -481,8 +481,6 @@ class NgModuleRef_ implements NgModuleData, InternalNgModuleRef<any> {
|
||||
/** @internal */
|
||||
_providers: any[];
|
||||
|
||||
readonly injector: Injector = this;
|
||||
|
||||
constructor(
|
||||
private _moduleType: Type<any>, public _parent: Injector,
|
||||
public _bootstrapComponents: Type<any>[], public _def: NgModuleDefinition) {
|
||||
@ -498,6 +496,8 @@ class NgModuleRef_ implements NgModuleData, InternalNgModuleRef<any> {
|
||||
|
||||
get componentFactoryResolver() { return this.get(ComponentFactoryResolver); }
|
||||
|
||||
get injector(): Injector { return this; }
|
||||
|
||||
destroy(): void {
|
||||
if (this._destroyed) {
|
||||
throw new Error(
|
||||
|
@ -649,8 +649,9 @@ class DebugRendererFactory2 implements RendererFactory2 {
|
||||
|
||||
|
||||
class DebugRenderer2 implements Renderer2 {
|
||||
readonly data: {[key: string]: any};
|
||||
constructor(private delegate: Renderer2) { this.data = this.delegate.data; }
|
||||
constructor(private delegate: Renderer2) {}
|
||||
|
||||
get data() { return this.delegate.data; }
|
||||
|
||||
destroyNode(node: any) {
|
||||
removeDebugNodeFromIndex(getDebugNode(node) !);
|
||||
|
@ -7,10 +7,10 @@
|
||||
*/
|
||||
|
||||
import {WrappedValue, devModeEqual} from '../change_detection/change_detection';
|
||||
import {SOURCE} from '../di/injector';
|
||||
import {ViewEncapsulation} from '../metadata/view';
|
||||
import {RendererType2} from '../render/api';
|
||||
import {looseIdentical, stringify} from '../util';
|
||||
|
||||
import {expressionChangedAfterItHasBeenCheckedError} from './errors';
|
||||
import {BindingDef, BindingFlags, Definition, DefinitionFactory, DepDef, DepFlags, ElementData, NodeDef, NodeFlags, QueryValueType, Services, ViewData, ViewDefinition, ViewDefinitionFactory, ViewFlags, ViewState, asElementData, asTextData} from './types';
|
||||
|
||||
@ -209,7 +209,7 @@ export function splitMatchedQueriesDsl(
|
||||
return {matchedQueries, references, matchedQueryIds};
|
||||
}
|
||||
|
||||
export function splitDepsDsl(deps: ([DepFlags, any] | any)[], sourceName?: string): DepDef[] {
|
||||
export function splitDepsDsl(deps: ([DepFlags, any] | any)[]): DepDef[] {
|
||||
return deps.map(value => {
|
||||
let token: any;
|
||||
let flags: DepFlags;
|
||||
@ -219,9 +219,6 @@ export function splitDepsDsl(deps: ([DepFlags, any] | any)[], sourceName?: strin
|
||||
flags = DepFlags.None;
|
||||
token = value;
|
||||
}
|
||||
if (token && (typeof token === 'function' || typeof token === 'object') && sourceName) {
|
||||
Object.defineProperty(token, SOURCE, {value: sourceName, configurable: true});
|
||||
}
|
||||
return {flags, token, tokenKey: tokenKey(token)};
|
||||
});
|
||||
}
|
||||
|
@ -255,45 +255,6 @@ export function main() {
|
||||
]);
|
||||
});
|
||||
|
||||
it('should allow a transition to use a function to determine what method to run', () => {
|
||||
let valueToMatch = '';
|
||||
const transitionFn =
|
||||
(fromState: string, toState: string) => { return toState == valueToMatch; };
|
||||
|
||||
@Component({
|
||||
selector: 'if-cmp',
|
||||
template: '<div [@myAnimation]="exp"></div>',
|
||||
animations: [
|
||||
trigger('myAnimation', [transition(
|
||||
transitionFn,
|
||||
[style({opacity: 0}), animate(1234, style({opacity: 1}))])]),
|
||||
]
|
||||
})
|
||||
class Cmp {
|
||||
exp: any = '';
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [Cmp]});
|
||||
|
||||
const fixture = TestBed.createComponent(Cmp);
|
||||
const cmp = fixture.componentInstance;
|
||||
valueToMatch = cmp.exp = 'something';
|
||||
fixture.detectChanges();
|
||||
|
||||
let players = getLog();
|
||||
expect(players.length).toEqual(1);
|
||||
let [p1] = players;
|
||||
expect(p1.totalTime).toEqual(1234);
|
||||
resetLog();
|
||||
|
||||
valueToMatch = 'something-else';
|
||||
cmp.exp = 'this-wont-match';
|
||||
fixture.detectChanges();
|
||||
|
||||
players = getLog();
|
||||
expect(players.length).toEqual(0);
|
||||
});
|
||||
|
||||
it('should allow a state value to be `0`', () => {
|
||||
@Component({
|
||||
selector: 'if-cmp',
|
||||
|
@ -2823,6 +2823,96 @@ export function main() {
|
||||
expect(child.log).toEqual(['child-start', 'child-done']);
|
||||
}));
|
||||
|
||||
it('should fire and synchronize the start/done callbacks on multiple blocked sub triggers',
|
||||
fakeAsync(() => {
|
||||
@Component({
|
||||
selector: 'cmp',
|
||||
animations: [
|
||||
trigger(
|
||||
'parent1',
|
||||
[
|
||||
transition(
|
||||
'* => go, * => go-again',
|
||||
[
|
||||
style({opacity: 0}),
|
||||
animate('1s', style({opacity: 1})),
|
||||
]),
|
||||
]),
|
||||
trigger(
|
||||
'parent2',
|
||||
[
|
||||
transition(
|
||||
'* => go, * => go-again',
|
||||
[
|
||||
style({lineHeight: '0px'}),
|
||||
animate('1s', style({lineHeight: '10px'})),
|
||||
]),
|
||||
]),
|
||||
trigger(
|
||||
'child1',
|
||||
[
|
||||
transition(
|
||||
'* => go, * => go-again',
|
||||
[
|
||||
style({width: '0px'}),
|
||||
animate('1s', style({width: '100px'})),
|
||||
]),
|
||||
]),
|
||||
trigger(
|
||||
'child2',
|
||||
[
|
||||
transition(
|
||||
'* => go, * => go-again',
|
||||
[
|
||||
style({height: '0px'}),
|
||||
animate('1s', style({height: '100px'})),
|
||||
]),
|
||||
]),
|
||||
],
|
||||
template: `
|
||||
<div [@parent1]="parent1Exp" (@parent1.start)="track($event)"
|
||||
[@parent2]="parent2Exp" (@parent2.start)="track($event)">
|
||||
<div [@child1]="child1Exp" (@child1.start)="track($event)"
|
||||
[@child2]="child2Exp" (@child2.start)="track($event)"></div>
|
||||
</div>
|
||||
`
|
||||
})
|
||||
class Cmp {
|
||||
public parent1Exp = '';
|
||||
public parent2Exp = '';
|
||||
public child1Exp = '';
|
||||
public child2Exp = '';
|
||||
public log: string[] = [];
|
||||
|
||||
track(event: any) { this.log.push(`${event.triggerName}-${event.phaseName}`); }
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [Cmp]});
|
||||
const engine = TestBed.get(ɵAnimationEngine);
|
||||
const fixture = TestBed.createComponent(Cmp);
|
||||
fixture.detectChanges();
|
||||
flushMicrotasks();
|
||||
|
||||
const cmp = fixture.componentInstance;
|
||||
cmp.log = [];
|
||||
cmp.parent1Exp = 'go';
|
||||
cmp.parent2Exp = 'go';
|
||||
cmp.child1Exp = 'go';
|
||||
cmp.child2Exp = 'go';
|
||||
fixture.detectChanges();
|
||||
flushMicrotasks();
|
||||
|
||||
expect(cmp.log).toEqual(
|
||||
['parent1-start', 'parent2-start', 'child1-start', 'child2-start']);
|
||||
|
||||
cmp.parent1Exp = 'go-again';
|
||||
cmp.parent2Exp = 'go-again';
|
||||
cmp.child1Exp = 'go-again';
|
||||
cmp.child2Exp = 'go-again';
|
||||
fixture.detectChanges();
|
||||
flushMicrotasks();
|
||||
}));
|
||||
|
||||
it('should stretch the starting keyframe of a child animation queries are issued by the parent',
|
||||
() => {
|
||||
@Component({
|
||||
|
@ -147,8 +147,8 @@ export function main() {
|
||||
|
||||
expect(() => createAndGetRootNodes(compViewDef(rootElNodes)))
|
||||
.toThrowError(
|
||||
'StaticInjectorError(DynamicTestModule)[SomeService -> Dep]: \n' +
|
||||
' StaticInjectorError(Platform: core)[SomeService -> Dep]: \n' +
|
||||
'StaticInjectorError[Dep]: \n' +
|
||||
' StaticInjectorError[Dep]: \n' +
|
||||
' NullInjectorError: No provider for Dep!');
|
||||
|
||||
const nonRootElNodes = [
|
||||
@ -161,8 +161,8 @@ export function main() {
|
||||
|
||||
expect(() => createAndGetRootNodes(compViewDef(nonRootElNodes)))
|
||||
.toThrowError(
|
||||
'StaticInjectorError(DynamicTestModule)[SomeService -> Dep]: \n' +
|
||||
' StaticInjectorError(Platform: core)[SomeService -> Dep]: \n' +
|
||||
'StaticInjectorError[Dep]: \n' +
|
||||
' StaticInjectorError[Dep]: \n' +
|
||||
' NullInjectorError: No provider for Dep!');
|
||||
});
|
||||
|
||||
@ -186,8 +186,8 @@ export function main() {
|
||||
directiveDef(1, NodeFlags.None, null, 0, SomeService, ['nonExistingDep'])
|
||||
])))
|
||||
.toThrowError(
|
||||
'StaticInjectorError(DynamicTestModule)[nonExistingDep]: \n' +
|
||||
' StaticInjectorError(Platform: core)[nonExistingDep]: \n' +
|
||||
'StaticInjectorError[nonExistingDep]: \n' +
|
||||
' StaticInjectorError[nonExistingDep]: \n' +
|
||||
' NullInjectorError: No provider for nonExistingDep!');
|
||||
});
|
||||
|
||||
|
@ -355,12 +355,8 @@ export class TestBed implements Injector {
|
||||
}
|
||||
|
||||
const ngZone = new NgZone({enableLongStackTrace: true});
|
||||
const providers: StaticProvider[] = [{provide: NgZone, useValue: ngZone}];
|
||||
const ngZoneInjector = Injector.create({
|
||||
providers: providers,
|
||||
parent: this.platform.injector,
|
||||
name: this._moduleFactory.moduleType.name
|
||||
});
|
||||
const ngZoneInjector =
|
||||
Injector.create([{provide: NgZone, useValue: ngZone}], this.platform.injector);
|
||||
this._moduleRef = this._moduleFactory.create(ngZoneInjector);
|
||||
// ApplicationInitStatus.runInitializers() is marked @internal to core. So casting to any
|
||||
// before accessing it.
|
||||
|
@ -135,7 +135,7 @@ export function main() {
|
||||
name = 'square';
|
||||
}
|
||||
|
||||
const injector = Injector.create({providers: [{provide: Square, deps: []}]});
|
||||
const injector = Injector.create([{provide: Square, deps: []}]);
|
||||
|
||||
const shape: Square = injector.get(Square);
|
||||
expect(shape.name).toEqual('square');
|
||||
|
@ -49,10 +49,10 @@ export const COMPOSITION_BUFFER_MODE = new InjectionToken<boolean>('CompositionE
|
||||
// https://github.com/angular/angular/issues/3011 is implemented
|
||||
// selector: '[ngModel],[formControl],[formControlName]',
|
||||
host: {
|
||||
'(input)': '$any(this)._handleInput($event.target.value)',
|
||||
'(input)': '_handleInput($event.target.value)',
|
||||
'(blur)': 'onTouched()',
|
||||
'(compositionstart)': '$any(this)._compositionStart()',
|
||||
'(compositionend)': '$any(this)._compositionEnd($event.target.value)'
|
||||
'(compositionstart)': '_compositionStart()',
|
||||
'(compositionend)': '_compositionEnd($event.target.value)'
|
||||
},
|
||||
providers: [DEFAULT_VALUE_ACCESSOR]
|
||||
})
|
||||
|
@ -253,7 +253,7 @@ export abstract class AbstractControl {
|
||||
* Sets the async validators that are active on this control. Calling this
|
||||
* will overwrite any existing async validators.
|
||||
*/
|
||||
setAsyncValidators(newValidator: AsyncValidatorFn|AsyncValidatorFn[]|null): void {
|
||||
setAsyncValidators(newValidator: AsyncValidatorFn|AsyncValidatorFn[]): void {
|
||||
this.asyncValidator = coerceToAsyncValidator(newValidator);
|
||||
}
|
||||
|
||||
|
@ -75,6 +75,8 @@ const EMAIL_REGEXP =
|
||||
export class Validators {
|
||||
/**
|
||||
* Validator that requires controls to have a value greater than a number.
|
||||
*`min()` exists only as a function, not as a directive. For example,
|
||||
* `control = new FormControl('', Validators.min(3));`.
|
||||
*/
|
||||
static min(min: number): ValidatorFn {
|
||||
return (control: AbstractControl): ValidationErrors | null => {
|
||||
@ -90,6 +92,8 @@ export class Validators {
|
||||
|
||||
/**
|
||||
* Validator that requires controls to have a value less than a number.
|
||||
* `max()` exists only as a function, not as a directive. For example,
|
||||
* `control = new FormControl('', Validators.max(15));`.
|
||||
*/
|
||||
static max(max: number): ValidatorFn {
|
||||
return (control: AbstractControl): ValidationErrors | null => {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @license Angular v0.0.0-PLACEHOLDER
|
||||
* (c) 2010-2017 Google, Inc. https://angular.io/
|
||||
* (c) 2010-2018 Google, Inc. https://angular.io/
|
||||
* License: MIT
|
||||
*/
|
||||
|
@ -42,7 +42,6 @@ export class JitReflector implements CompileReflector {
|
||||
hasLifecycleHook(type: any, lcProperty: string): boolean {
|
||||
return this.reflectionCapabilities.hasLifecycleHook(type, lcProperty);
|
||||
}
|
||||
guards(type: any): {[key: string]: any} { return this.reflectionCapabilities.guards(type); }
|
||||
resolveExternalReference(ref: ExternalReference): any {
|
||||
return builtinExternalReferences.get(ref) || ref.runtime;
|
||||
}
|
||||
|
@ -7,12 +7,12 @@
|
||||
*/
|
||||
|
||||
import {isPlatformBrowser} from '@angular/common';
|
||||
import {APP_INITIALIZER, CUSTOM_ELEMENTS_SCHEMA, Compiler, Component, Directive, ErrorHandler, Inject, Input, LOCALE_ID, NgModule, OnDestroy, PLATFORM_ID, PLATFORM_INITIALIZER, Pipe, Provider, StaticProvider, Type, VERSION, createPlatformFactory} from '@angular/core';
|
||||
import {APP_INITIALIZER, CUSTOM_ELEMENTS_SCHEMA, Compiler, Component, Directive, ErrorHandler, Inject, Input, LOCALE_ID, NgModule, OnDestroy, PLATFORM_ID, PLATFORM_INITIALIZER, Pipe, Provider, StaticProvider, VERSION, createPlatformFactory, ɵstringify as stringify} from '@angular/core';
|
||||
import {ApplicationRef, destroyPlatform} from '@angular/core/src/application_ref';
|
||||
import {Console} from '@angular/core/src/console';
|
||||
import {ComponentRef} from '@angular/core/src/linker/component_factory';
|
||||
import {Testability, TestabilityRegistry} from '@angular/core/src/testability/testability';
|
||||
import {AsyncTestCompleter, Log, afterEach, beforeEach, beforeEachProviders, describe, iit, inject, it} from '@angular/core/testing/src/testing_internal';
|
||||
import {AsyncTestCompleter, Log, afterEach, beforeEach, beforeEachProviders, ddescribe, describe, iit, inject, it} from '@angular/core/testing/src/testing_internal';
|
||||
import {BrowserModule} from '@angular/platform-browser';
|
||||
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
|
||||
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
|
||||
@ -112,11 +112,10 @@ class DummyConsole implements Console {
|
||||
|
||||
|
||||
class TestModule {}
|
||||
function bootstrap(
|
||||
cmpType: any, providers: Provider[] = [], platformProviders: StaticProvider[] = [],
|
||||
imports: Type<any>[] = []): Promise<any> {
|
||||
function bootstrap(cmpType: any, providers: Provider[] = [], platformProviders: StaticProvider[] = [
|
||||
]): Promise<any> {
|
||||
@NgModule({
|
||||
imports: [BrowserModule, ...imports],
|
||||
imports: [BrowserModule],
|
||||
declarations: [cmpType],
|
||||
bootstrap: [cmpType],
|
||||
providers: providers,
|
||||
@ -184,40 +183,6 @@ export function main() {
|
||||
});
|
||||
}));
|
||||
|
||||
it('should throw if no provider', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
||||
const logger = new MockConsole();
|
||||
const errorHandler = new ErrorHandler();
|
||||
errorHandler._console = logger as any;
|
||||
|
||||
class IDontExist {}
|
||||
|
||||
@Component({selector: 'cmp', template: 'Cmp'})
|
||||
class CustomCmp {
|
||||
constructor(iDontExist: IDontExist) {}
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'hello-app',
|
||||
template: '<cmp></cmp>',
|
||||
})
|
||||
class RootCmp {
|
||||
}
|
||||
|
||||
@NgModule({declarations: [CustomCmp], exports: [CustomCmp]})
|
||||
class CustomModule {
|
||||
}
|
||||
|
||||
bootstrap(RootCmp, [{provide: ErrorHandler, useValue: errorHandler}], [], [
|
||||
CustomModule
|
||||
]).then(null, (e: Error) => {
|
||||
expect(e.message).toContain(`StaticInjectorError(TestModule)[CustomCmp -> IDontExist]:
|
||||
StaticInjectorError(Platform: core)[CustomCmp -> IDontExist]:
|
||||
NullInjectorError: No provider for IDontExist!`);
|
||||
async.done();
|
||||
return null;
|
||||
});
|
||||
}));
|
||||
|
||||
if (getDOM().supportsDOMEvents()) {
|
||||
it('should forward the error to promise when bootstrap fails',
|
||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
||||
|
@ -1,6 +1,6 @@
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2017 Google, Inc. http://angular.io
|
||||
Copyright (c) 2017-2018 Google, Inc. http://angular.io
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -277,11 +277,11 @@ export type UrlMatchResult = {
|
||||
* For instance, the following matcher matches html files.
|
||||
*
|
||||
* ```
|
||||
* function htmlFiles(url: UrlSegment[]) {
|
||||
* return url.length === 1 && url[0].path.endsWith('.html') ? ({consumed: url}) : null;
|
||||
* export function htmlFiles(url: UrlSegment[]) {
|
||||
* return url.length === 1 && url[0].path.endsWith('.html') ? ({consumed: url}) : null;
|
||||
* }
|
||||
*
|
||||
* const routes = [{ matcher: htmlFiles, component: HtmlCmp }];
|
||||
* export const routes = [{ matcher: htmlFiles, component: AnyComponent }];
|
||||
* ```
|
||||
*
|
||||
* @experimental
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user